From eee42ae3d8ba448f0a657071defef437edeada0d Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 7 Feb 2013 04:36:42 +1100 Subject: [PATCH] Cleanup RTS mode a bit --- qcsrc/server/monsters/lib/monsters.qc | 32 ++++-- qcsrc/server/mutators/base.qh | 5 + qcsrc/server/mutators/gamemode_rts.qc | 144 ++++++++++++++++++++++---- qcsrc/server/teamplay.qc | 2 + 4 files changed, 155 insertions(+), 28 deletions(-) diff --git a/qcsrc/server/monsters/lib/monsters.qc b/qcsrc/server/monsters/lib/monsters.qc index e6f53a681..b0b113227 100644 --- a/qcsrc/server/monsters/lib/monsters.qc +++ b/qcsrc/server/monsters/lib/monsters.qc @@ -210,15 +210,29 @@ void Monster_CheckMinibossFlag () } } +float Monster_CanRespawn(entity ent) +{ + other = ent; + if(MUTATOR_CALLHOOK(MonsterRespawn)) + return TRUE; // enabled by a mutator + + if(ent.spawnflags & MONSTERFLAG_NORESPAWN) + return FALSE; + + if not(autocvar_g_monsters_respawn) + return FALSE; + + return TRUE; +} + void Monster_Fade () { - if not(self.spawnflags & MONSTERFLAG_NORESPAWN) - if(autocvar_g_monsters_respawn) + if(Monster_CanRespawn(self)) { self.monster_respawned = TRUE; setmodel(self, ""); self.think = self.monster_spawnfunc; - self.nextthink = time + autocvar_g_monsters_respawn_delay; + self.nextthink = time + self.respawntime; setorigin(self, self.pos1); self.angles = self.pos2; self.health = 0; @@ -338,6 +352,11 @@ vector monster_pickmovetarget(entity targ) self.monster_movestate = MONSTER_MOVE_ENEMY; return self.enemy.origin; } + if(targ) + { + self.monster_movestate = MONSTER_MOVE_WANDER; + return targ.origin; + } switch(self.monster_moveflags) { @@ -350,8 +369,6 @@ vector monster_pickmovetarget(entity targ) case MONSTER_MOVE_WANDER: { self.monster_movestate = MONSTER_MOVE_WANDER; - if(targ) - return targ.origin; self.angles_y = random() * 500; makevectors(self.angles); @@ -464,7 +481,7 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_ if(time >= self.last_trace) { - if(self.monster_movestate == MONSTER_MOVE_WANDER && (self.goalentity.classname != "td_waypoint" || self.goalentity != self.sprite)) + if(self.monster_movestate == MONSTER_MOVE_WANDER && self.goalentity.classname != "td_waypoint") self.last_trace = time + 2; else self.last_trace = time + 0.5; @@ -734,6 +751,9 @@ float monster_initialize(string net_name, self.pos1 = self.origin; self.pos2 = self.angles; + if not(self.respawntime) + self.respawntime = autocvar_g_monsters_respawn_delay; + if not(self.monster_moveflags) self.monster_moveflags = MONSTER_MOVE_WANDER; diff --git a/qcsrc/server/mutators/base.qh b/qcsrc/server/mutators/base.qh index 43e807b6f..abef8e8d6 100644 --- a/qcsrc/server/mutators/base.qh +++ b/qcsrc/server/mutators/base.qh @@ -144,6 +144,11 @@ MUTATOR_HOOKABLE(MonsterDies); // INPUT: entity frag_attacker; +MUTATOR_HOOKABLE(MonsterRespawn); + // called when a monster wants to respawn + // INPUT: + entity other; + MUTATOR_HOOKABLE(MonsterDropItem); // called when a monster is dropping loot // INPUT, OUTPUT: diff --git a/qcsrc/server/mutators/gamemode_rts.qc b/qcsrc/server/mutators/gamemode_rts.qc index 7cbf32f6f..dd7b686fc 100644 --- a/qcsrc/server/mutators/gamemode_rts.qc +++ b/qcsrc/server/mutators/gamemode_rts.qc @@ -6,8 +6,10 @@ .float last_click; MUTATOR_HOOKFUNCTION(rts_PlayerSpawn) { + self.effects |= EF_NODRAW; self.oldorigin = self.origin; self.last_click = time; + self.takedamage = DAMAGE_NO; self.flags |= FL_NOTARGET; self.movetype = MOVETYPE_FLY; stuffcmd(self, "settemp cl_prydoncursor 1\n"); @@ -29,33 +31,41 @@ MUTATOR_HOOKFUNCTION(rts_SetStartItems) MUTATOR_HOOKFUNCTION(rts_PlayerThink) { + if(self.classname != "player") + return FALSE; // dont do any checks for spectators entity head, wp = world; - if(self.cursor_trace_ent == world && self.BUTTON_ATCK) + if(self.cursor_trace_ent == world && self.BUTTON_ATCK && time >= self.last_click) { FOR_EACH_MONSTER(head) { - if(head.waypointsprite_attachedforcarrier) - WaypointSprite_Kill(head.waypointsprite_attachedforcarrier); + if(head.owner != self) continue; + + if(head.goalentity) + { + remove(head.goalentity); + head.goalentity = world; + } head.selected = FALSE; - if(head.owner == self) + if(!self.enemy && !self.goalentity) head.owner = world; } } if(self.cursor_trace_ent.flags & FL_MONSTER && self.BUTTON_ATCK && time >= self.last_click) { - if(self.cursor_trace_ent.selected) + if(self.cursor_trace_ent.owner != self && self.cursor_trace_ent.owner != world) + return FALSE; // someone else owns it + else if(self.cursor_trace_ent.team != self.team) + return FALSE; // not our team + else if(self.cursor_trace_ent.selected) { - WaypointSprite_Kill(self.cursor_trace_ent.waypointsprite_attachedforcarrier); self.cursor_trace_ent.selected = FALSE; self.cursor_trace_ent.owner = world; self.last_click = time + 0.5; // prevent spamming } else { - WaypointSprite_Spawn("Selected", 0, 0, self.cursor_trace_ent, '0 0 64' + ('0 0 1' * self.cursor_trace_ent.maxs_z), world, 0, self.cursor_trace_ent, waypointsprite_attachedforcarrier, FALSE, RADARICON_FLAGCARRIER, BALL_SPRITECOLOR); - self.cursor_trace_ent.owner = self; self.cursor_trace_ent.selected = TRUE; self.last_click = time + 0.5; // prevent spamming @@ -71,7 +81,6 @@ MUTATOR_HOOKFUNCTION(rts_PlayerThink) { wp = spawn(); setorigin(wp, self.cursor_trace_endpos); - WaypointSprite_SpawnFixed("Moving Here", wp.origin + '0 0 40', wp, sprite, RADARICON_HERE, '1 0.5 0'); } } @@ -81,19 +90,17 @@ MUTATOR_HOOKFUNCTION(rts_PlayerThink) if(head.goalentity) { - if(head.goalentity.sprite) - WaypointSprite_Kill(head.goalentity.sprite); remove(head.goalentity); head.goalentity = world; } - if(head.sprite) - WaypointSprite_Kill(head.sprite); - - if(self.cursor_trace_ent) + if(self.cursor_trace_ent && self.cursor_trace_ent.team != self.team) head.enemy = self.cursor_trace_ent; else + { head.goalentity = wp; + head.enemy = world; + } } } @@ -102,34 +109,105 @@ MUTATOR_HOOKFUNCTION(rts_PlayerThink) MUTATOR_HOOKFUNCTION(rts_MonsterSpawn) { + self.respawntime = time + 5; // default to 5 seconds for now self.effects |= EF_SELECTABLE; + self.monster_moveflags = MONSTER_MOVE_NOMOVE; - if(self.sprite) - WaypointSprite_Kill(self.sprite); // no waypoint names in rts...? + WaypointSprite_Kill(self.sprite); + self.sprite = world; return FALSE; } MUTATOR_HOOKFUNCTION(rts_MonsterThink) { + vector color; + if(self.team) + color = TeamColor(self.team); + else + color = '1 1 1'; + + monster_speed_run = 100; + monster_speed_walk = 100; + if(self.selected) - self.colormod = '1 1 1' * 4; + self.colormod = color * 4; else - self.colormod = '1 1 1'; + { + self.colormod = color; + if(self.goalentity) + { + remove(self.goalentity); + self.goalentity = world; + } + } + + if(self.goalentity) + self.enemy = world; // don't ignore our owner's commands + + if(!self.sprite) + { + WaypointSprite_Spawn(self.netname, 0, 0, self, '0 0 1' * self.sprite_height, world, self.team, self, sprite, FALSE, RADARICON_DANGER, ((teamplay) ? TeamColor(self.team) : '1 0 0')); + WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health); + WaypointSprite_UpdateHealth(self.sprite, self.health); + } + + if(!self.selected) + if(self.owner) + if(!self.goalentity && !self.enemy) + self.owner = world; + + if(self.enemy.team == self.team) + self.enemy = world; // no same team fighting + + self.last_trace = time; // realtime moving? return FALSE; } MUTATOR_HOOKFUNCTION(rts_MonsterDies) { - if(self.waypointsprite_attachedforcarrier) - WaypointSprite_Kill(self.waypointsprite_attachedforcarrier); - + float otherteam = ((self.team == COLOR_TEAM1) ? COLOR_TEAM2 : COLOR_TEAM1); + + TeamScore_AddToTeam(otherteam, ST_SCORE, 1); + + self.effects &~= EF_SELECTABLE; self.selected = FALSE; return FALSE; } +MUTATOR_HOOKFUNCTION(rts_MonsterRespawn) +{ + if(other.team) + return TRUE; + + return FALSE; // if no team is set, don't respawn +} + +MUTATOR_HOOKFUNCTION(rts_MonsterTarget) +{ + // don't search for enemies, they are given to us + return TRUE; +} + +MUTATOR_HOOKFUNCTION(rts_MonsterBossFlag) +{ + // no minibosses in RTS + return TRUE; +} + +MUTATOR_HOOKFUNCTION(rts_PlayerDamage) +{ + if(frag_target.classname == "player") + frag_damage = 0; // don't damage the invincible players... + + if((frag_target.flags & FL_MONSTER) && frag_target.goalentity) + frag_target.enemy = world; // don't attack the attacker, we're probably pulling back + + return FALSE; +} + MUTATOR_HOOKFUNCTION(rts_PlayerPhysics) { self.origin_z = self.oldorigin_z; @@ -138,6 +216,22 @@ MUTATOR_HOOKFUNCTION(rts_PlayerPhysics) return FALSE; } +void rts_ScoreRules() +{ + ScoreRules_basics(2, SFL_SORT_PRIO_PRIMARY, 0, TRUE); + ScoreRules_basics_end(); +} + +void rts_DelayedInit() +{ + rts_ScoreRules(); +} + +void rts_Initialize() +{ + InitializeEntity(world, rts_DelayedInit, INITPRIO_GAMETYPE); +} + MUTATOR_DEFINITION(gamemode_rts) { MUTATOR_HOOK(PlayerPhysics, rts_PlayerPhysics, CBC_ORDER_ANY); @@ -147,13 +241,19 @@ MUTATOR_DEFINITION(gamemode_rts) MUTATOR_HOOK(MonsterSpawn, rts_MonsterSpawn, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerPreThink, rts_PlayerThink, CBC_ORDER_ANY); MUTATOR_HOOK(MonsterMove, rts_MonsterThink, CBC_ORDER_ANY); + MUTATOR_HOOK(MonsterFindTarget, rts_MonsterTarget, CBC_ORDER_ANY); MUTATOR_HOOK(MonsterDies, rts_MonsterDies, CBC_ORDER_ANY); + MUTATOR_HOOK(MonsterRespawn, rts_MonsterRespawn, CBC_ORDER_ANY); + MUTATOR_HOOK(MonsterCheckBossFlag, rts_MonsterBossFlag, CBC_ORDER_ANY); + MUTATOR_HOOK(PlayerDamage_Calculate, rts_PlayerDamage, CBC_ORDER_ANY); MUTATOR_ONADD { if(time > 1) // game loads at time 1 error("This is a game type and it cannot be added at runtime."); cvar_settemp("g_monsters", "1"); + + rts_Initialize(); } MUTATOR_ONREMOVE diff --git a/qcsrc/server/teamplay.qc b/qcsrc/server/teamplay.qc index 3581f6bd1..564171c0c 100644 --- a/qcsrc/server/teamplay.qc +++ b/qcsrc/server/teamplay.qc @@ -155,9 +155,11 @@ void InitGameplayMode() if(g_rts) { + ActivateTeamplay(); fraglimit_override = 0; leadlimit_override = 0; MUTATOR_ADD(gamemode_rts); + have_team_spawns = -1; // request team spawns } if(g_runematch) -- 2.39.2