1. You don't need to show the popupmessage when a player spawns every time.
2. Use the coordinates Euphonic used in Uplink for the MI6 and Janus players remaining at the top of the screen. Yours is too close to the top and it's off centered.
Well done on the new gamemode Joe. Hopefully we'll see it on a server's rotation some day once it's out of beta
This pleases me to see a brand new custom gamemode released to the public. Thanks for all of your hard work Joe!Thanks, I hope you will enjoy playing this mode.
+rep
I suggest changing the resurrection timer from digits to a progress bar ("Resurrecting [|||||| ]"), it'll be less wordy and translate better.I would personally prefer to see "Resurrecting:" followed by a seconds countdown. I will create a poll.
Make the top message (Janus 1/3 MI6 0/3 or w/e) thing display all the time (except when waiting for players)---it's nice to have something that immediately shows what gameplay you're playing.I will do this.
Have you considered using objective icons?Are you referring to a token radar icon?
A custom model for the resurrection spots would also help, imo.What do you think the custom model should be?
Gravestone for sure. Here you are.
http://www.mediafire.com/file/zfzb0j4arorjd4d/gravestone.zip (http://www.mediafire.com/file/zfzb0j4arorjd4d/gravestone.zip)
I hope it'll work, just noticed i compiled it as prop_physics, rather should have been just static & dynamic.
But it was allready uploaded and i g2g to work, so no time to do it again right now.
i will do another compile later.
BTW: Is there already a possibility to see which player can be resurrected on that point, displaying the name of the player or something?Unlike in MOHAA Freeze Tag, resurrection entities aren't associated with eliminated players. Instead each side has a resurrection queue and when a side's RE is used the player who has been in their queue for the longest time is resurrected.
(http://www.mediafire.com/conv/e98734746bec2baec2a56b44647ca40a9063cfb8195d96e35df5fa3096b521806g.jpg)
Thanks for making these great looking gravestones, I will include them in the beta 1.02 release.
I will try to make a gravestone radar icon.
Joe, I added in the ability to set an entities' position in Python (players and held weapons will ignore the command for obvious reasons). This will be in the next patch to GE:S.
There is now a screenshot from Beta 1.02 in this topic's first post.
Thanks, when this patch is released I will use this new ability to make resurrection entities appear at player death locations instead of player spawn points.
I've been thinking about this, and you should spawn them at player death points only when the player is killed by another player or themselves, not when it's an environmental death -- that way you prevent them spawning at the bottom of pits.Thanks for the help, I will do this.
def OnCaptureAreaSpawned( self, area ):
areasID = area.GetGroupName()
areasTeam = area.GetTeamNumber()
location = area.GetAbsOrigin()
#TODO remove when REs are moved to player death locations:
#Don't allow a MI6 and Janus RE to be located at the same player spawn point.
if areasTeam == GEGlobal.TEAM_MI6 and location in self.jAreaLocations.values() or areasTeam == GEGlobal.TEAM_JANUS and location in self.mAreaLocations.values():
self.respawnResurrectionEntity(areasID,areasTeam) #Recursive Function Call Loop
return
if location in self.mAreaLocations.values() or location in self.jAreaLocations.values():
GEUtil.Msg("------- Same Team RE Location Overlap -------")
#Deleting the area in this callback function makes GE:S regularly crash:
self.tokenManager.RemoveCaptureArea(areasID)
if area.GetTeamNumber() == GEGlobal.TEAM_MI6: self.mAreaIDs.remove(areasID)
else: self.jAreaIDs.remove(areasID)
areaIDAssociatedWithLocation = self.getREAreaIDAssociatedWithLocation(location,areasTeam)
if not self.multiResurrectionRE.has_key(areaIDAssociatedWithLocation): self.multiResurrectionRE[areaIDAssociatedWithLocation] = 1
self.multiResurrectionRE[areaIDAssociatedWithLocation] += 1
else:
colour = self.getSidesColour(areasTeam)
if areasTeam == GEGlobal.TEAM_MI6: self.mAreaLocations[areasID] = location
else: self.jAreaLocations[areasID] = location
self.radar.AddRadarContact(area,GEGlobal.RADAR_TYPE_OBJECTIVE,True,self.RERadarIcon,colour)
self.radar.SetupObjective(area,areasTeam,"", "",colour,self.REObjectiveIconFadeOutDistance, False)
#TODO remove when REs are moved to player death locations
def getREAreaIDAssociatedWithLocation(self,location,side):
sidesAreaLocations = None
if side == GEGlobal.TEAM_MI6: sidesAreaLocations = self.mAreaLocations
else: sidesAreaLocations = self.jAreaLocations
for areaID in sidesAreaLocations.keys():
if sidesAreaLocations[areaID] == location: return areaID
from . import GEScenario
from GamePlay.Utils.GEPlayerTracker import GEPlayerTracker
from Utils.GETimer import TimerTracker, Timer
from collections import defaultdict
import GEPlayer, GEUtil, GEMPGameRules, GEGlobal
USING_API = GEGlobal.API_VERSION_1_0_0
'''
This mode is based on Mefy's MOHAA Freeze Tag Mode.
I chose to implement this mode by editing the "You Only Live Twice" mode script. So
this script uses lots of code that was created by the author(s) of the YOLT script.
I've also reused code from the "Capture The Key" mode's script.
The gravestones were created by Kraid.
The up and down arrows in the crucifix RE icon were taken from the run icons.
@author: Joe
@version: Crash Bug Demo
'''
class DieAnotherDay( GEScenario ):
ResurrectionTime = 5.0
CompletedResPBRemovalDelay = 1.0
MREModel = "models/gameplay/gravestone.mdl"
JREModel = "models/gameplay/gravestone.mdl"
MRESkin = 0
JRESkin = 1
RERadarIcon = "sprites/hud/radar/RE"
REObjectiveIconFadeOutDistance = 200
COLOR_MI6_RADAR = GEUtil.Color( 94, 171, 231, 255 )
COLOR_JANUS_RADAR = GEUtil.Color( 206, 43, 43, 255 )
JBountyFontColour = GEUtil.CColor( 206, 43, 43, 255 )
MBountyFontColour = GEUtil.CColor( 100, 184, 234, 220 )
#Progress bar positions
MBountyPBX = 0.315
MBountyPBY = 0.03
JBountyPBX = 0.515
JBountyPBY = 0.03
ResurrectionPBX = -1
ResurrectionPBY = 0.6
#-------------------------
TR_ELIMINATED = "eliminated"
TR_SPAWNED = "spawned"
TOKEN_MI6 = 'token_mi6'
TOKEN_JANUS = 'token_janus'
#Progress Bar Indexs
MBountyPBIndex = 0
JBountyPBIndex = 1
ResurrectionPBIndex = 2
def __init__( self ):
super( DieAnotherDay, self ).__init__()
self.radar = None
self.eliminateNewPlayers = False
self.waitingForPlayers = False
self.mBounty = 0
self.jBounty = 0
self.pltracker = GEPlayerTracker( self )
self.bountiesInitialised = False
self.mBountyMaxPlayers = 0
self.jBountyMaxPlayers = 0
self.timerTracker = TimerTracker( self )
self.tokenManager = GEMPGameRules.GetTokenMgr()
#Eliminated player collections
self.mResurrectionQueue = []
self.jResurrectionQueue = []
#Collections related to resurrection area entities
self.mAreaIDs = []
self.jAreaIDs = []
self.mAreaLocations = {}
self.jAreaLocations = {}
self.REResTimers = defaultdict(list)
#TODO remove when REs are moved from spawn points to player death locations:
self.multiResurrectionRE = {}
#Needed because deleting a RE in onCaptureAreaSpawned makes GE:S regularly crash.
#Emptied in onCaptureAreaEntered.
#self.REBin = []
def OnLoadGamePlay( self ):
GEUtil.PrecacheModel( self.MREModel )
GEUtil.PrecacheModel( self.JREModel )
self.radar = GEMPGameRules.GetRadar()
def Cleanup( self ):
super( DieAnotherDay, self ).Cleanup()
self.pltracker = None
def GetPrintName( self ):
return "Die Another Day"
def GetScenarioHelp( self, help_obj ):
#TODO use UI Language Files:
help_obj.SetDescription(
"""-- Version: Crash Bug Demo --
Eliminate your opponents.
To resurrect a team mate: stand next
to one of your team's gravestones.
---------- Credits ---------
Based on Mefy's MOHAA Freeze Tag Mode.
Kraid created the gravestones.
""")
def GetGameDescription( self ):
return "Die Another Day"
def OnPlayerConnect( self, player ):
self.pltracker.SetValue( player, self.TR_SPAWNED, False )
def OnPlayerDisconnect( self, player ):
team = player.GetTeamNumber()
if team != GEGlobal.TEAM_SPECTATOR:
self.decrementTeamsPlayerCount(team)
if self.isEliminatedPlayer(player):
self.deleteNotInUseResurrectionEntityFromTeam(team)
self.removePlayerFromTeamsRQueue(player,team)
else: self.decreaseTeamBounty(team)
if self.bountiesInitialised: self.updateTeamsDisplayedMaxPlayers(team)
def isEliminatedPlayer(self,player):
return self.pltracker.GetValue(player,self.TR_ELIMINATED)
#-------------------------------
def CanPlayerChangeTeam(self,player,oldTeam,newTeam ):
if oldTeam == GEGlobal.TEAM_NONE: return True
elif oldTeam == GEGlobal.TEAM_SPECTATOR and player.IsInitialSpawn(): self.newPlayerWantsToJoinTeam(player,newTeam)
elif oldTeam == GEGlobal.TEAM_SPECTATOR: self.spectatorWantsToJoinTeam(player,newTeam)
elif oldTeam != GEGlobal.TEAM_SPECTATOR and newTeam != GEGlobal.TEAM_SPECTATOR: self.playerWantsToChangeTheirTeam(player,oldTeam,newTeam)
elif newTeam == GEGlobal.TEAM_SPECTATOR:
if self.isEliminatedPlayer(player): self.eliminatedPlayerWantsToBecomeSpectator(player,oldTeam)
else: self.playerWantsToBecomeSpectator(player,oldTeam)
return True
def newPlayerWantsToJoinTeam(self,player,newTeam):
self.incrementTeamsPlayerCount(newTeam)
if self.eliminateNewPlayers:
#TODO use language files
GEUtil.PopupMessage(player, "You Can't Spawn Yet","New players won't spawn until a team mate spawns them, this prevents resurrection rejoins.")
self.eliminatePlayer(player)
self.spawnNewResurrectionEntity(player,newTeam)
self.addPlayerToResurrectionQueue(player,newTeam)
if self.playerNotBot(player): self.tellPlayerWhatTheirResurrectionQueuePositionIs(player,newTeam)
else: self.increaseTeamBounty(newTeam)
if self.bountiesInitialised: self.updateTeamsDisplayedMaxPlayers(newTeam)
def playerWantsToChangeTheirTeam(self,player,oldTeam,newTeam):
self.decrementTeamsPlayerCount(oldTeam)
self.incrementTeamsPlayerCount(newTeam)
if self.isEliminatedPlayer(player):
#Old team
self.deleteNotInUseResurrectionEntityFromTeam(oldTeam)
self.removePlayerFromTeamsRQueue(player,oldTeam)
self.resurrectionQueueUpdateNotify(oldTeam)
#New Team
self.spawnNewResurrectionEntity(player,newTeam)
self.addPlayerToResurrectionQueue(player,newTeam)
if self.playerNotBot(player): self.tellPlayerWhatTheirResurrectionQueuePositionIs(player,newTeam)
else:
self.decreaseTeamBounty(oldTeam)
self.increaseTeamBounty(newTeam)
if self.bountiesInitialised:
self.updateTeamsDisplayedMaxPlayers(oldTeam)
self.updateTeamsDisplayedMaxPlayers(newTeam)
def eliminatedPlayerWantsToBecomeSpectator(self,player,oldTeam):
self.decrementTeamsPlayerCount(oldTeam)
self.deleteNotInUseResurrectionEntityFromTeam(oldTeam)
self.removePlayerFromTeamsRQueue(player,oldTeam)
self.resurrectionQueueUpdateNotify(oldTeam)
#Prevent GE:S spectator view bug from being triggered (this bug will be fixed in the next patch):
self.resurrectPlayer(player)
player.ForceRespawn()
self.eliminatePlayer(player) #Doesn't kill them but does set eliminated? attribute to true.
if self.bountiesInitialised: self.updateTeamsDisplayedMaxPlayers(oldTeam)
def playerWantsToBecomeSpectator(self,player,oldTeam):
self.decrementTeamsPlayerCount(oldTeam)
self.decreaseTeamBounty(oldTeam)
if self.bountiesInitialised: self.updateTeamsDisplayedMaxPlayers(oldTeam)
def spectatorWantsToJoinTeam(self,player,newTeam):
self.incrementTeamsPlayerCount(newTeam)
if self.isEliminatedPlayer(player):
#TODO use language files
GEUtil.PopupMessage(player, "You Can't Spawn Yet","You won't spawn until a team mate spawns you because you were eliminated before you became a spectator.")
self.spawnNewResurrectionEntity(player,newTeam)
self.addPlayerToResurrectionQueue(player,newTeam)
if self.playerNotBot(player): self.tellPlayerWhatTheirResurrectionQueuePositionIs(player,newTeam)
else: self.increaseTeamBounty(newTeam)
if self.bountiesInitialised: self.updateTeamsDisplayedMaxPlayers(newTeam)
#-------------------------------
def incrementTeamsPlayerCount(self,team):
if team == GEGlobal.TEAM_MI6: self.mBountyMaxPlayers += 1
else: self.jBountyMaxPlayers += 1
def decrementTeamsPlayerCount(self,team):
if team == GEGlobal.TEAM_MI6: self.mBountyMaxPlayers -= 1
else: self.jBountyMaxPlayers -= 1
def deleteNotInUseResurrectionEntityFromTeam(self,team):
teamsResurrectionAreaIDs = None
if team == GEGlobal.TEAM_MI6: teamsResurrectionAreaIDs = self.mAreaIDs
else: teamsResurrectionAreaIDs = self.jAreaIDs
for areaID in teamsResurrectionAreaIDs:
if not self.areaInUse(areaID):
self.deleteResurrectionArea(areaID,team)
break
def areaInUse(self,areaID):
return len(self.REResTimers[areaID]) > 0
def deleteResurrectionArea(self,areasID,areasTeam):
if self.multiResurrectionRE.has_key(areasID): del self.multiResurrectionRE[areasID]
if areasTeam == GEGlobal.TEAM_MI6:
self.mAreaIDs.remove(areasID)
del self.mAreaLocations[areasID]
else:
self.jAreaIDs.remove(areasID)
del self.jAreaLocations[areasID]
del self.REResTimers[areasID]
self.tokenManager.RemoveCaptureArea(areasID)
def eliminatePlayer(self,player):
self.pltracker.SetValue(player,self.TR_ELIMINATED,True)
def announceElimination(self,victim,killer):
#Emit "Player Eliminated" event
GEUtil.EmitGameplayEvent( "DieAnotherDay_eliminated", "%i" % victim.GetUserID(), "%i" % killer.GetUserID())
#Tell the other players that a player has been eliminated #TODO use UI Language Files
GEUtil.ClientPrint(None,GEGlobal.HUD_PRINTTALK, "A " + self.getTeamString(victim.GetTeamNumber()) + " player has been eliminated.")
def getTeamString(self,teamNumber):
if(teamNumber == GEGlobal.TEAM_MI6): return "MI6"
elif(teamNumber == GEGlobal.TEAM_JANUS): return "Janus"
else: return "Spectator"
def addPlayerToResurrectionQueue(self,player,team):
if team == GEGlobal.TEAM_MI6: self.mResurrectionQueue.append(player)
else: self.jResurrectionQueue.append(player)
def removePlayerFromTeamsRQueue(self,player,team):
if team == GEGlobal.TEAM_MI6: self.mResurrectionQueue.remove(player)
else: self.jResurrectionQueue.remove(player)
def spawnNewResurrectionEntity(self,victim,team):
#Create a new resurrection area id
newAreasID = str(victim.GetUserID())
#Spawn a new resurrection area
self.spawnResurrectionEntity(newAreasID,team)
#Create entries for the new area in resurrection entity collections
if team == GEGlobal.TEAM_MI6: self.mAreaIDs.append(newAreasID)
else: self.jAreaIDs.append(newAreasID)
#Added to radar in CaptureAreaSpawned()
def respawnResurrectionEntity(self,areaID,team):
self.tokenManager.RemoveCaptureArea(areaID)
self.spawnResurrectionEntity(areaID,team)
def spawnResurrectionEntity(self,areaID,team):
#Get Model Name
modelName = None
skinNumber = None
if team == GEGlobal.TEAM_MI6:
modelName = self.MREModel
skinNumber = self.MRESkin
else:
modelName = self.JREModel
skinNumber = self.JRESkin
#Spawn resurrection entity
self.tokenManager.SetupCaptureArea(areaID,
model=modelName,
skin=skinNumber,
limit=1, location=GEGlobal.SPAWN_PLAYER,
rqd_team=team)
def OnPlayerSpawn(self,player):
if player.GetTeamNumber() != GEGlobal.TEAM_SPECTATOR: self.pltracker.SetValue(player,self.TR_SPAWNED,True)
#TODO Use UI Language Files
if player.IsInitialSpawn(): GEUtil.PopupMessage( player, "Die Another Day", "Eliminate your opponents and resurrect your eliminated team mates." )
def OnRoundBegin( self ):
self.mBounty = 0
self.jBounty = 0
if not self.waitingForPlayers:
for i in range( 32 ):
if not GEPlayer.IsValidPlayerIndex( i ):
continue
self.pltracker.SetValue( GEPlayer.GetMPPlayer( i ), self.TR_ELIMINATED, False )
GEMPGameRules.ResetAllPlayerDeaths()
GEMPGameRules.ResetAllPlayersScores()
def OnRoundEnd( self ):
GEUtil.Msg("One Round End----")
self.eliminateNewPlayers = False
self.radar.DropAllContacts()
self.timerTracker.RemoveTimer(None) #Stop all timers
#Remove all progress bars
self.bountiesInitialised = False
GEUtil.RemoveHudProgressBar( None,self.MBountyPBIndex)
GEUtil.RemoveHudProgressBar( None,self.JBountyPBIndex)
GEUtil.RemoveHudProgressBar( None,self.ResurrectionPBIndex)
#Empty resurrection queues
del self.mResurrectionQueue[:]
del self.jResurrectionQueue[:]
self.deleteAllCaptureAreasAndTheirCollections()
def deleteAllCaptureAreasAndTheirCollections(self):
for areaID in self.mAreaIDs: self.tokenManager.RemoveCaptureArea(areaID)
for areaID in self.jAreaIDs: self.tokenManager.RemoveCaptureArea(areaID)
del self.mAreaIDs[:]
del self.jAreaIDs[:]
self.mAreaLocations.clear()
self.jAreaLocations.clear()
self.REResTimers.clear()
def OnPlayerKilled( self, victim, killer, weapon ):
super( DieAnotherDay, self ).OnPlayerKilled( victim, killer, weapon )
self.InitializePlayerBounty() #if not initialised already
victimsTeam = victim.GetTeamNumber()
#Don't allow players to accidentally/intentionally eliminate their team mates
if killer.GetTeamNumber()!= victimsTeam:
self.eliminatePlayer(victim)
self.announceElimination(victim,killer)
self.decreaseTeamBounty(victimsTeam)
#Get the survivor count for the victim's team.
teamsSurvivors = 0
if victimsTeam == GEGlobal.TEAM_MI6: teamsSurvivors = self.mBounty
else: teamsSurvivors = self.jBounty
#If the victim was the last player alive on their team then don't create a resurrection area because
#the game will be ended by OnThink() when this function has finished.
if teamsSurvivors > 0:
self.eliminateNewPlayers = True
self.spawnNewResurrectionEntity(victim,victimsTeam)
self.addPlayerToResurrectionQueue(victim,victimsTeam)
if self.playerNotBot(victim):
self.tellPlayerWhatTheirResurrectionQueuePositionIs(victim)
elif teamsSurvivors < 0: GEUtil.Msg("ERROR:OnPlayerKilled():teamsSurvivors < 0: = " + str(teamsSurvivors))
def OnCaptureAreaSpawned( self, area ):
areasID = area.GetGroupName()
areasTeam = area.GetTeamNumber()
location = area.GetAbsOrigin()
#TODO remove when REs are moved to player death locations:
#Don't allow a MI6 and Janus RE to be located at the same player spawn point.
if areasTeam == GEGlobal.TEAM_MI6 and location in self.jAreaLocations.values() or areasTeam == GEGlobal.TEAM_JANUS and location in self.mAreaLocations.values():
self.respawnResurrectionEntity(areasID,areasTeam) #Recursive Function Call Loop
return
#TODO modify the following statements when REs are moved to player death locations:
#Deal with the situation of 2 or more RE from the same side being located at the same spawn point (the resurrection function
#is also responsible for dealing with this situation):
if location in self.mAreaLocations.values() or location in self.jAreaLocations.values():
GEUtil.Msg("------- Same Team RE Location Overlap -------")
#Deleting the area in this callback function makes GE:S regularly crash, on Silo when it has 31 bots.
#(it will crash once every 4 - 10 minutes)
self.tokenManager.RemoveCaptureArea(areasID)
if area.GetTeamNumber() == GEGlobal.TEAM_MI6: self.mAreaIDs.remove(areasID)
else: self.jAreaIDs.remove(areasID)
areaIDAssociatedWithLocation = self.getREAreaIDAssociatedWithLocation(location,areasTeam)
if not self.multiResurrectionRE.has_key(areaIDAssociatedWithLocation): self.multiResurrectionRE[areaIDAssociatedWithLocation] = 1
self.multiResurrectionRE[areaIDAssociatedWithLocation] += 1
else:
colour = self.getSidesColour(areasTeam)
if areasTeam == GEGlobal.TEAM_MI6: self.mAreaLocations[areasID] = location
else: self.jAreaLocations[areasID] = location
self.radar.AddRadarContact(area,GEGlobal.RADAR_TYPE_OBJECTIVE,True,self.RERadarIcon,colour)
self.radar.SetupObjective(area,areasTeam,"", "",colour,self.REObjectiveIconFadeOutDistance, False)
#TODO remove when REs are moved to player death locations
def getREAreaIDAssociatedWithLocation(self,location,side):
sidesAreaLocations = None
if side == GEGlobal.TEAM_MI6: sidesAreaLocations = self.mAreaLocations
else: sidesAreaLocations = self.jAreaLocations
for areaID in sidesAreaLocations.keys():
if sidesAreaLocations[areaID] == location: return areaID
def OnCaptureAreaEntered( self, area, player, token ):
if area.GetTeamNumber() == player.GetTeamNumber():
#TODO remove
GEUtil.ClientPrint(None,GEGlobal.HUD_PRINTNOTIFY,"Multi RE entered")
#Create a new resurrection timer and add it to the resurrection timer collection
resurrectionTimer = DieAnotherDay.ResurrectionTimer(self,area,player)
resurrectionTimer.create()
self.REResTimers[area.GetGroupName()].append(resurrectionTimer)
#Create a resurrection progress bar on the player's screen TODO: use language files
GEUtil.InitHudProgressBar(player,self.ResurrectionPBIndex, "Resurrecting:", GEGlobal.HUDPB_SHOWBAR, self.ResurrectionTime, self.ResurrectionPBX, self.ResurrectionPBY, 120, 16,self.getSidesColour(area.GetTeamNumber()))
resurrectionTimer.start()
# def emptyREBin(self):
# if len(self.REBin) != 0:
# for RE in self.REBin:
# areasID = RE.GetGroupName()
# if RE.GetTeamNumber() == GEGlobal.TEAM_MI6: self.mAreaIDs.remove(areasID)
# else: self.jAreaIDs.remove(areasID)
#
# self.tokenManager.RemoveCaptureArea(areasID)
def getSidesColour(self,side):
if side == GEGlobal.TEAM_MI6: return self.COLOR_MI6_RADAR
else: return self.COLOR_JANUS_RADAR
def OnCaptureAreaExited( self, area, player ):
if area.GetTeamNumber() == player.GetTeamNumber():
if self.getREUsersResurrectionTimer(area,player) != None:
self.getREUsersResurrectionTimer(area,player).cancel()
def getREUsersResurrectionTimer(self,area,userP):
for resurrectionTimer in self.REResTimers[area.GetGroupName()]:
if resurrectionTimer.user == userP: return resurrectionTimer
return None
class ResurrectionTimer:
def __init__(self,DADP,areaP,userP):
self.timer = None
self.DAD = DADP
self.area = areaP
self.user = userP
def create(self):
self.timer = self.DAD.timerTracker.CreateTimer(self.area.GetGroupName())
self.timer.SetUpdateCallback(self.TimerTick,1)
self.timer.SetAgeRate(1.0,0)
def start(self):
self.timer.Start(DieAnotherDay.ResurrectionTime,False)
def cancel(self):
self.timer.Stop()
self.removeUsersResurrectionPB()
self.delete()
def delete(self):
self.DAD.timerTracker.RemoveTimer(self.timer.GetName())
self.DAD.REResTimers[self.area.GetGroupName()].remove(self)
def TimerTick( self, timer, update_type ):
if update_type != Timer.UPDATE_STOP:
self.updateUsersResurrectionPB()
if update_type == Timer.UPDATE_FINISH:
self.cancelTimerAreasOtherResTimers()
self.startUsersResurrectionPBsDelayedRemovalTimer(self.area.GetGroupName())
self.resurrectPlayerFromTimersTeam()
self.delete() #Must be called before deleteResurrectionArea()
self.DAD.deleteResurrectionArea(self.area.GetGroupName(),self.area.GetTeamNumber())
def cancelTimerAreasOtherResTimers(self):
for resurrectionTimer in self.DAD.REResTimers[self.area.GetGroupName()]:
if resurrectionTimer != self: resurrectionTimer.cancel()
def removeUsersResurrectionPB(self):
GEUtil.RemoveHudProgressBar(self.user,DieAnotherDay.ResurrectionPBIndex)
def updateUsersResurrectionPB(self):
GEUtil.UpdateHudProgressBar(self.user,DieAnotherDay.ResurrectionPBIndex,int(self.timer.GetCurrentTime()))
def startUsersResurrectionPBsDelayedRemovalTimer(self,timerID):
resPBRemoveTimer = self.DAD.timerTracker.CreateTimer(timerID)
resPBRemoveTimer.SetUpdateCallback(self.DelayedResurrectionPBRemoval,1)
resPBRemoveTimer.SetAgeRate(1.0,0)
resPBRemoveTimer.Start(DieAnotherDay.CompletedResPBRemovalDelay,False)
def DelayedResurrectionPBRemoval(self,timer,update_type ):
if update_type == Timer.UPDATE_FINISH: self.removeUsersResurrectionPB()
def resurrectPlayerFromTimersTeam(self):
areasTeam = self.area.GetTeamNumber()
areasID = self.area.GetGroupName()
#Get team string
teamString = None
if areasTeam == GEGlobal.TEAM_MI6: teamString = "MI6"
else: teamString = "Janus"
#TODO modify when REs are moved from spawn points to death locations:
numberOfPlayersToResurrect = 1
if self.DAD.multiResurrectionRE.has_key(areasID): numberOfPlayersToResurrect = self.DAD.multiResurrectionRE[areasID]
#For each resurrection...
while numberOfPlayersToResurrect > 0:
numberOfPlayersToResurrect -= 1
#TODO remove
if numberOfPlayersToResurrect > 1: GEUtil.Msg("*** Multi Resurrection: " + str(numberOfPlayersToResurrect) + " ***")
#Choose player to be resurrected.
resurrectedPlayer = None
if areasTeam == GEGlobal.TEAM_MI6 and len(self.DAD.mResurrectionQueue) != 0: resurrectedPlayer = self.DAD.mResurrectionQueue.pop(0)
elif areasTeam == GEGlobal.TEAM_JANUS and len(self.DAD.jResurrectionQueue) != 0: resurrectedPlayer = self.DAD.jResurrectionQueue.pop(0)
#If for some reason there is no player to resurrect, don't resurrect anyone.
if resurrectedPlayer != None:
#Resurrect player
self.DAD.resurrectPlayer(resurrectedPlayer)
#Update player bounty
self.DAD.increaseTeamBounty(areasTeam)
#Update resurrection queue progress bars for team mates
self.DAD.resurrectionQueueUpdateNotify(areasTeam)
if self.DAD.playerNotBot(resurrectedPlayer):
#Emit player resurrected event
GEUtil.EmitGameplayEvent("DieAnotherDay_resurrection", "%s" % resurrectedPlayer.GetName(),"%s" % teamString)
#Announce event in console
GEUtil.Msg("A " + teamString + " player has been resurrected: " + resurrectedPlayer.GetName())
#Announce resurrection
GEUtil.ClientPrint(None, GEGlobal.HUD_PRINTTALK,"A " + teamString + " player has been resurrected.")
#If there are now no eliminated players, allow new players to join without needing to be spawned by their team mates.
numberOfMPlayers = GEMPGameRules.GetNumInRoundTeamPlayers(GEGlobal.TEAM_MI6)
numberOfJPlayers = GEMPGameRules.GetNumInRoundTeamPlayers(GEGlobal.TEAM_JANUS)
if numberOfMPlayers == self.DAD.mBounty and numberOfJPlayers == self.DAD.jBounty: self.DAD.eliminateNewPlayers = False
#Only called when a resurrection has taken place.
def DelayedResurrectionPBRemoval( self, timer, update_type ):
timersAreasID = timer.getName()
timersUser = self.resurrectionAreaUserLists[timersAreasID][0]
GEUtil.RemoveHudProgressBar(timersUser,self.ResurrectionPBIndex)
def resurrectionQueueUpdateNotify(self,team):
resurrectionQueue = None
if(team == GEGlobal.TEAM_MI6): resurrectionQueue = self.mResurrectionQueue
else: resurrectionQueue = self.jResurrectionQueue
for player in resurrectionQueue:
if self.playerNotBot(player):
self.tellPlayerWhatTheirResurrectionQueuePositionIs(player)
def tellPlayerWhatTheirResurrectionQueuePositionIs(self,player,team=None):
if team == None: team = player.GetTeamNumber()
queuePosition = None
if team == GEGlobal.TEAM_MI6: queuePosition = self.mResurrectionQueue.index(player)
else: queuePosition = self.jResurrectionQueue.index(player)
#TODO use language files
GEUtil.ClientPrint(player,GEGlobal.HUD_PRINTCONSOLE,"Team mates who will be resurrected before you = ")
GEUtil.PopupMessage(player, "You've Been Eliminated", "Team mates who will be resurrected before you = " + str(queuePosition))
def playerNotBot(self,player):
return player.__class__.__name__ != "CGEBotPlayer"
def resurrectPlayer(self,player):
self.pltracker.SetValue(player,self.TR_ELIMINATED,False)
def OnThink( self ):
if GEMPGameRules.GetNumActivePlayers() < 2:
self.waitingForPlayers = True
return
if self.waitingForPlayers:
self.waitingForPlayers = False
GEUtil.HudMessage( None, "#GES_GP_GETREADY", -1, -1, GEUtil.CColor( 255, 255, 255, 255 ), 2.5 )
GEMPGameRules.EndRound( False )
#Check to see if the round is over!:
#check to see if each team has a player...
inPlayMPlayers = []
inPlayJPlayers = []
for i in range( 32 ):
if not GEPlayer.IsValidPlayerIndex( i ):
continue
player = GEPlayer.GetMPPlayer( i )
if self.IsInPlay( player ):
if player.GetTeamNumber() == GEGlobal.TEAM_MI6:
inPlayMPlayers.append( player )
elif player.GetTeamNumber() == GEGlobal.TEAM_JANUS:
inPlayJPlayers.append( player )
numMI6Players = len(inPlayMPlayers)
numJanusPlayers = len(inPlayJPlayers)
if numMI6Players == 0 and numJanusPlayers == 0: GEMPGameRules.EndRound()
elif numMI6Players == 0 and numJanusPlayers > 0: self.teamWins(GEGlobal.TEAM_JANUS)
elif numMI6Players > 0 and numJanusPlayers == 0: self.teamWins(GEGlobal.TEAM_MI6)
def teamWins(self,teamNumber):
team = GEMPGameRules.GetTeam(teamNumber)
team.IncrementMatchScore( 5 )
GEMPGameRules.SetTeamWinner(team)
GEMPGameRules.EndRound()
def CanPlayerRespawn( self, player ):
if self.isEliminatedPlayer(player):
player.SetScoreBoardColor( GEGlobal.SB_COLOR_ELIMINATED )
return False
player.SetScoreBoardColor( GEGlobal.SB_COLOR_NORMAL )
return True
def InitializePlayerBounty( self ):
if self.mBounty == 0 and self.jBounty == 0:
self.mBountyMaxPlayers = GEMPGameRules.GetNumInRoundTeamPlayers(GEGlobal.TEAM_MI6)
self.jBountyMaxPlayers = GEMPGameRules.GetNumInRoundTeamPlayers(GEGlobal.TEAM_JANUS)
self.mBounty = self.mBountyMaxPlayers
self.jBounty = self.jBountyMaxPlayers
GEUtil.InitHudProgressBar(None,self.MBountyPBIndex,"MI6:",GEGlobal.HUDPB_SHOWVALUE, self.mBountyMaxPlayers, self.MBountyPBX,self.MBountyPBY, 0, 10, self.MBountyFontColour)
GEUtil.InitHudProgressBar(None,self.JBountyPBIndex,"Janus:",GEGlobal.HUDPB_SHOWVALUE, self.jBountyMaxPlayers, self.JBountyPBX,self.JBountyPBY, 0, 10,self.JBountyFontColour)
self.bountiesInitialised = True
def getTeamsPlayerCount(self,team):
if team == GEGlobal.TEAM_MI6: return self.mBountyMaxPlayers
else: return self.jBountyMaxPlayers
def updateTeamsDisplayedMaxPlayers(self,team):
numberOfPlayersInTeam = self.getTeamsPlayerCount(team)
if team == GEGlobal.TEAM_MI6:
GEUtil.InitHudProgressBar(None, self.MBountyPBIndex,"MI6:", GEGlobal.HUDPB_SHOWVALUE,numberOfPlayersInTeam, self.MBountyPBX,self.MBountyPBY, 0, 10, self.MBountyFontColour)
GEUtil.UpdateHudProgressBar(None,self.MBountyPBIndex,self.mBounty)
else:
GEUtil.InitHudProgressBar(None,self.JBountyPBIndex,"Janus:", GEGlobal.HUDPB_SHOWVALUE,numberOfPlayersInTeam, self.JBountyPBX,self.JBountyPBY, 0, 10,self.JBountyFontColour)
GEUtil.UpdateHudProgressBar(None,self.JBountyPBIndex,self.jBounty)
def decreaseTeamBounty(self,team):
if team == GEGlobal.TEAM_JANUS: self.jBounty -= 1
else: self.mBounty -= 1
self.updateDisplayedBounties()
def increaseTeamBounty(self,team):
if team == GEGlobal.TEAM_JANUS: self.jBounty += 1
else: self.mBounty += 1
self.updateDisplayedBounties()
def updateDisplayedBounties(self):
GEUtil.UpdateHudProgressBar(None,self.JBountyPBIndex,self.jBounty)
GEUtil.UpdateHudProgressBar(None,self.MBountyPBIndex,self.mBounty)
def IsInPlay( self, player ):
return player.GetTeamNumber() is not GEGlobal.TEAM_SPECTATOR and self.pltracker.GetValue( player, self.TR_SPAWNED ) and not self.pltracker.GetValue( player, self.TR_ELIMINATED )
def GetTeamPlay(self):
return GEGlobal.TEAMPLAY_ALWAYS
Joe, I'm glad you're working on this promising gamemode, keep it up!
Do you have an estimated date of when this will be finished?
I won't be able to finish this mode until the next GE:S patch is released because it will allow me to move REs to player death locations. I will try to have everything else implemented by the 1st of January.
I will start implementing the long range resurrection ability tomorrow.
I'm going to rent a GE:S server from a dedicated server provider. This dedicated server would be dedicated to running DAD mode and I will only rent it for a month. The purpose of this server will be to promote DAD mode and to provide a server where beta version test events can take place.
Before I release version 2.00 with its addition of the long range resurrection ability, I would like to run a weekend beta test event on my DAD server for Beta 1.02. I'm hoping that some players will attend this event if I announce it in this forum topic.
When I've finished working on this mode's script, I'm hoping that the GE:S developers will be willing to make this mode into an official game mode. If they will be willing to make it into an official mode, then I won't mind if they modify its script.
I'm going to rent a GE:S server from a dedicated server provider. This dedicated server would be dedicated to running DAD mode and I will only rent it for a month. The purpose of this server will be to promote DAD mode and to provide a server where beta version test events can take place.
Before I release version 2.00 with its addition of the long range resurrection ability, I would like to run a weekend beta test event on my DAD server for Beta 1.02. I'm hoping that some players will attend this event if I announce it in this forum topic.
When I've finished working on this mode's script, I'm hoping that the GE:S developers will be willing to make this mode into an official game mode. If they will be willing to make it into an official mode, then I won't mind if they modify its script.
We have a server you can use for a month is you want to save some $. Our token of appropriation. Contact me if want to use it.
Beta 1.03Killermonkey has told me that the next GE:S patch will allow mode scripts to use console commands.
I was going to release Beta 1.03 yesterday but I didn't because I found out that this game doesn't have a kick voting system.
This is a problem for Beta 1.03 because its purpose was going to be to fix two gameplay exploits by allowing players to eliminate their team mates when friendly fire is enabled.
Does anyone have an idea for what an "in use" appearance could be for the gravestones?
It would be good if someone had a good idea which would only involve changing a gravestone's texture or model because I don't think graphical effects like smoke could be spawned with the available scripting functions.
I don't think the idea I've had could be implemented with the available scripting functions: I think it would look good if in use gravestones became surrounded by blue electricity, like the yellow electricity surrounding the car in the image on this web page: http://www.gimpusers.com/tutorials/electrifying-objects-electricity-effect (http://www.gimpusers.com/tutorials/electrifying-objects-electricity-effect)
You could do pulsating rings like I do in Uplink (or increase the amplitude a bit).
My GE:S DAD server is still not working, despite me paying a server provider to setup a GE:S server for me on the 12th of December.
I only intended to rent a DAD server for one month, so I've requested the cancellation of my DAD server on the 1st of January, which is the date when its current billing period ends.
So my GE:S server probably won't be available to play DAD on in its last week.
If you using JestServers, your server might have crashed or is stopped. There's a control panel to reboot it. I run a server and could host your mode if need be.Thanks for the advice, I wasn't using JestServers. I don't think my server was using GE:S server software on the 22nd of December.
Hey Joe, you do a great job.
Development Task | Status | Extra Info |
Implement The Long Range Resurrection Ability. | Done | |
Allow server owners to change the duration of resurrections with a CVAR. | Done | |
Show all players the location of a used RE on their radar. | Done | Server owners will be able to set the duration of this with a CVAR. In MOHAA Freeze Tag, players are told where their enemies' REs have been used. DAD mode is meant to be a recreation of this popular MOHAA mode, this is why I'm implementing this gameplay change. |
Move RE Gravestones To Player Death Locations. | Usable | I still need to create an efficient function (http://forums.geshl2.com/index.php/topic,7617.msg78944.html#msg78944)for working out the location of the ground beneath mid-air players, so gravestones can't yet be spawned beneath players who are killed in mid-air. |
Display MI6 And Janus LRR Ability Lasers. | Done | |
Add A Resurrection Sound Effect To This Mode. | Can't be implemented in the current GE:S version | The GEUtil.StopSound() function can't stop the resurrection sound when resurrections fail. (http://forums.geshl2.com/index.php/topic,7607.0.html) |
Allow Players To Resurrect Multiple Team Mates Simultaneously. | Done | |
Implement a DAD mode bot. | Won't be implemented in this version. | |
Change Elim&Resurrection Messages' Font Colour To Blue & Red. | Done | |
Add A Dutch Translation. | Cancelled | There's no Dutch translation file in the wiki (http://wiki.geshl2.com/) so I don't think the new GE:S version will have it. |
Add Translations To The Official Language Files. | Done | |
Fix The Friendly Fire Gameplay Exploits. | Done | |
Make A Gravestone's HUD Objective Icon Become Yellow When It's Being Used. | Done |
When I've fixed all the bugs I've found and have released it, I want to arrange a Alpha 1.10 public test event for this Sunday. So I will create a forum topic where this event can be discussed.
Hi guys,
I've not been able to afford to buy a modern PC with a secure Windows OS. So I'm stuck with my malicious software infested Windows XP PC, which now has malicious software preventing it from using a graphics driver.
I could obtain a £70 - £120 loan so that I can buy a used Windows 7 PC/ a new Windows OS for my existing PC. But I don't want to have this debt.
So I'm going to ask some experienced GE:S mode developers if they would be interested in taking over the development of this mode. If no one I ask wants to take over the development of this mode, then I will post a message in this forum topic inviting anyone to take over its development.
Why not reinstall XP?
I would be interested in making this mode an official mode if the community supports that.I would like DAD mode to become an official mode because I think servers would be more likely to use it.
Development Task | Status | Extra Info |
Implement The Long Range Resurrection Ability. | Done | |
Allow server owners to change the duration of resurrections with a CVAR. | Done | |
Show all players the location of a used RE on their radar. | Done | Server owners will be able to set the duration of this with a CVAR. In MOHAA Freeze Tag, players are told where their enemies' REs have been used. DAD mode is meant to be a recreation of this popular MOHAA mode, this is why I'm implementing this gameplay change. |
Move RE Gravestones To Player Death Locations. | Usable | I still need to create an efficient function (http://forums.geshl2.com/index.php/topic,7617.msg78944.html#msg78944)for working out the location of the ground beneath mid-air players, so gravestones can't yet be spawned beneath players who are killed in mid-air. |
Display MI6 And Janus LRR Ability Lasers. | Done | |
Add A Resurrection Sound Effect To This Mode. | Can't be implemented in the current GE:S version | The GEUtil.StopSound() function can't stop the resurrection sound when resurrections fail. (http://forums.geshl2.com/index.php/topic,7607.0.html) |
Allow Players To Resurrect Multiple Team Mates Simultaneously. | Done | |
Implement a DAD mode bot. | Won't be implemented in this version. | |
Change Elim&Resurrection Messages' Font Colour To Blue & Red. | Done | |
Add Translations To The Official Language Files. | Done | |
Fix The Friendly Fire Gameplay Exploits. | Done | |
Make A Gravestone's HUD Objective Icon Become Yellow When It's Being Used. | Done |
I would be interested in making this mode an official mode if the community supports that.
LOL that is the funniest thing i have heard all day. In all seriousness.....your joking right killermonkey?
So everything on your computer is good to go right?Yes, so I'm hoping the hacker(s) who interfered with my development of this mode months ago, won't bother to hack my new PC.
...5 months ago.I know I should have finished this mode months ago, so I'm sorry that I've been doing a crap job of developing it.
Traceback (most recent call last):
File "c:\program files (x86)\steam\steamapps\sourcemods\gesource\scripts\python\GamePlay\DieAnotherDay.py", line 217, in OnCaptureAreaEntered
if REArea.GetTeamNumber() == player.GetTeamNumber() and self.REs.REUsable(REArea):
File "c:\program files (x86)\steam\steamapps\sourcemods\gesource\scripts\python\GamePlay\DieAnotherDay.py", line 755, in REUsable
return area in self.REs.values() and not area in self.disabledREs and not area in self.usedREs
RuntimeError: Access violation - no RTTI data!
def REUsable(self,area):
return area in self.REs.values() and not area in self.disabledREs and not area in self.usedREs
class REDict:
def __init__(self,DADP):
self.unusedAreaID = 0
self.DAD = DADP
self.REs = {}
self.REPulseTimers = {}
self.REsWhichNeedToBeMoved = {}
self.disabledREs = []
self.usedREs = []
def flagREAsUsed(self,RE):
self.usedREs.append(RE)
def hasREBeenUsed(self,RE):
return RE in self.usedREs
def getListOfTeamsREs(self,team):
teamsREs = []
for RE in self.REs.values():
if RE.GetTeamNumber() == team: teamsREs.append(RE)
return teamsREs
def cleanup(self):
self.DAD = None
self.REs = None
self.REPulseTimers = None
self.REsWhichNeedToBeMoved = None
self.disabledREs = None
self.usedREs = None
def spawnNewResurrectionEntity(self,victim,team,afterSpawnMoveTo=None):
newAreasID = str(self.unusedAreaID)
self.unusedAreaID += 1
self.spawnResurrectionEntity(newAreasID,team,afterSpawnMoveTo)
def spawnResurrectionEntity(self,areaID,team,afterSpawnMoveTo=None):
skinNumber = 1
if team == GEGlobal.TEAM_MI6: skinNumber = 0
self.DAD.tokenManager.SetupCaptureArea(areaID,
radius = 35,
model="models/gameplay/gravestone.mdl",
limit=1,
#glow_color=self.DAD.getSidesColour(team),
#glow_dist=0,
skin=skinNumber,
rqd_team=team)
if afterSpawnMoveTo != None: self.needsToBeMoved(areaID,afterSpawnMoveTo)
def makeREGlow(self,RE):
self.DAD.tokenManager.SetupCaptureArea(RE.GetGroupName(),glow_dist=350)
def disableREGlow(self,RE):
self.DAD.tokenManager.SetupCaptureArea(RE.GetGroupName(),glow_dist=0)
#
def REUsable(self,area):
return area in self.REs.values() and not area in self.disabledREs and not area in self.usedREs
def newRESpawned(self,area):
self.disabledREs.append(area)
idP = area.GetGroupName()
self.REs[idP] = area
self.REPulseTimers[idP] = DieAnotherDay.REDict.RingPulseTimer(self.DAD,area)
self.disabledREs.remove(area)
def deleteRE(self,RE):
idP = RE.GetGroupName()
del self.REs[idP]
del self.REPulseTimers[idP]
if self.REsWhichNeedToBeMoved.has_key(idP): del self.REsWhichNeedToBeMoved[id]
if RE in self.disabledREs: self.disabledREs.remove(RE)
if RE in self.usedREs: self.usedREs.remove(RE)
self.DAD.tokenManager.RemoveCaptureArea(idP)
def doesREExsist(self,area):
return area in self.REs.values()
def deleteREAfterDelay(self,RE,delay):
timer = DieAnotherDay.ExtCallbackTimer(self.DAD.timerTracker,self.deleteREAfterDelayCallback,RE)
timer.start(delay)
def deleteREAfterDelayCallback(self,timer,update_type,RE):
if update_type == Timer.UPDATE_FINISH: self.deleteRE(RE)
def deleteAll(self):
for REID in self.REs: self.DAD.tokenManager.RemoveCaptureArea(REID)
self.REs = {}
self.REPulseTimers = {}
self.REsWhichNeedToBeMoved = {}
self.disabledREs = []
self.unusedAreaID = 0
def isREDisabled(self,REArea):
return REArea in self.disabledREs
def makeREInvisible(self,RE):
# Make RE Invisible
self.DAD.tokenManager.SetupCaptureArea(RE.GetGroupName(),model="") #glow_dist=0
def afterDelayChangeRERadarIcon(self,RE,icon,colour,delay):
timer = DieAnotherDay.ExtCallbackTimer(self.DAD.timerTracker,self.changeRERadarIconAfterDelayCB,{"REArea":RE,"icon":icon,"colour":colour})
timer.start(delay)
def changeRERadarIconAfterDelayCB(self,timer,update_type,parameters):
if update_type == Timer.UPDATE_FINISH: self.changeRERadarIcon(parameters["REArea"],parameters["icon"],parameters["colour"])
def changeRERadarIcon(self,RE,newIcon,colour):
self.DAD.radar.DropRadarContact(RE)
self.DAD.radar.AddRadarContact(RE,GEGlobal.RADAR_TYPE_OBJECTIVE,True,newIcon,colour)
def getMRELocations(self):
foundLocations = []
for RE in self.REs:
if RE.GetTeamNumber() == GEGlobal.TEAM_MI6: foundLocations.append(RE.GetAbsOrigin())
return foundLocations
def getJRELocations(self):
foundLocations = []
for RE in self.REs:
if RE.GetTeamNumber() == GEGlobal.TEAM_JANUS: foundLocations.append(RE.GetAbsOrigin())
return foundLocations
def needsToBeMoved(self,areasID,moveTo):
self.REsWhichNeedToBeMoved[areasID] = moveTo
def moved(self,RE):
REID = RE.GetGroupName()
if self.REsWhichNeedToBeMoved.has_key(REID): del self.REsWhichNeedToBeMoved[REID]
def getMoveToLocation(self,area):
REID = area.GetGroupName()
if self.REsWhichNeedToBeMoved.has_key(REID): return self.REsWhichNeedToBeMoved[REID]
return None
def isPulsating(self,RE):
return self.REPulseTimers[RE.GetGroupName()].isPulsating()
def startPulsatingRings(self,REArea):
self.REPulseTimers[REArea.GetGroupName()].start()
def stopPulsatingRings(self,idP):
self.REPulseTimers[idP].stop()
def AddAnEntity( ent, array_store ):
array_store.append( GEEntity.EntityHandle( ent ) )
def DoesEntityExist( ent, array_store ):
return ent in array_store
ent_instance == ent_instance: TRUE
ent_instance == GEEntity.EntityHandle( ent_instance ): TRUE
ent_instance == ent_instance.GetUID(): TRUE