From 0cd9c0a195837f223442a3cb8b6a00ef0b343cf0 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 1 Feb 2013 22:58:40 +1100 Subject: [PATCH] Moving Assault to the mutator API --- qcsrc/server/{ => attic}/assault.qc | 0 .../{ => attic}/bot/havocbot/role_assault.qc | 0 qcsrc/server/autocvars.qh | 1 - qcsrc/server/bot/havocbot/havocbot.qc | 1 - qcsrc/server/bot/havocbot/roles.qc | 2 - qcsrc/server/cl_client.qc | 7 - qcsrc/server/mutators/base.qh | 4 + qcsrc/server/mutators/gamemode_assault.qc | 646 ++++++++++++++++++ qcsrc/server/mutators/gamemode_assault.qh | 31 + qcsrc/server/mutators/mutators.qh | 1 + qcsrc/server/progs.src | 4 +- qcsrc/server/scores_rules.qc | 11 - qcsrc/server/teamplay.qc | 2 +- qcsrc/server/tturrets/system/system_main.qc | 7 +- qcsrc/server/vehicles/vehicles.qc | 5 +- 15 files changed, 691 insertions(+), 31 deletions(-) rename qcsrc/server/{ => attic}/assault.qc (100%) rename qcsrc/server/{ => attic}/bot/havocbot/role_assault.qc (100%) create mode 100644 qcsrc/server/mutators/gamemode_assault.qc create mode 100644 qcsrc/server/mutators/gamemode_assault.qh diff --git a/qcsrc/server/assault.qc b/qcsrc/server/attic/assault.qc similarity index 100% rename from qcsrc/server/assault.qc rename to qcsrc/server/attic/assault.qc diff --git a/qcsrc/server/bot/havocbot/role_assault.qc b/qcsrc/server/attic/bot/havocbot/role_assault.qc similarity index 100% rename from qcsrc/server/bot/havocbot/role_assault.qc rename to qcsrc/server/attic/bot/havocbot/role_assault.qc diff --git a/qcsrc/server/autocvars.qh b/qcsrc/server/autocvars.qh index c8db3db8a..45e5d35fb 100644 --- a/qcsrc/server/autocvars.qh +++ b/qcsrc/server/autocvars.qh @@ -76,7 +76,6 @@ float autocvar_g_arena_point_leadlimit; float autocvar_g_arena_point_limit; float autocvar_g_arena_roundbased; float autocvar_g_arena_warmup; -float autocvar_g_assault; float autocvar_g_balance_armor_blockpercent; float autocvar_g_balance_armor_limit; float autocvar_g_balance_armor_regen; diff --git a/qcsrc/server/bot/havocbot/havocbot.qc b/qcsrc/server/bot/havocbot/havocbot.qc index 1b9178b17..0b8bac733 100644 --- a/qcsrc/server/bot/havocbot/havocbot.qc +++ b/qcsrc/server/bot/havocbot/havocbot.qc @@ -1,7 +1,6 @@ #include "havocbot.qh" #include "role_onslaught.qc" #include "role_keyhunt.qc" -#include "role_assault.qc" #include "roles.qc" void havocbot_ai() diff --git a/qcsrc/server/bot/havocbot/roles.qc b/qcsrc/server/bot/havocbot/roles.qc index ad3bb2367..ce7fb8194 100644 --- a/qcsrc/server/bot/havocbot/roles.qc +++ b/qcsrc/server/bot/havocbot/roles.qc @@ -303,8 +303,6 @@ void havocbot_chooserole() havocbot_chooserole_race(); else if (g_onslaught) havocbot_chooserole_ons(); - else if (g_assault) - havocbot_chooserole_ast(); else // assume anything else is deathmatch havocbot_chooserole_dm(); } diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index 165460eeb..6c05b534d 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -866,13 +866,6 @@ void PutClientInServer (void) //stuffcmd(self, "chase_active 0"); //stuffcmd(self, "set viewsize $tmpviewsize \n"); - if(g_assault) { - if(self.team == assault_attacker_team) - centerprint(self, "You are attacking!"); - else - centerprint(self, "You are defending!"); - } - target_voicescript_clear(self); // reset fields the weapons may use diff --git a/qcsrc/server/mutators/base.qh b/qcsrc/server/mutators/base.qh index d90d564b5..ce90ef457 100644 --- a/qcsrc/server/mutators/base.qh +++ b/qcsrc/server/mutators/base.qh @@ -235,6 +235,10 @@ MUTATOR_HOOKABLE(HelpMePing); // INPUT entity self; // the player who pressed impulse 33 +MUTATOR_HOOKABLE(VehicleSpawn); + // called when a vehicle initializes + // return TRUE to remove the vehicle + MUTATOR_HOOKABLE(VehicleEnter); // called when a player enters a vehicle // allows mutators to set special settings in this event diff --git a/qcsrc/server/mutators/gamemode_assault.qc b/qcsrc/server/mutators/gamemode_assault.qc new file mode 100644 index 000000000..7b55be478 --- /dev/null +++ b/qcsrc/server/mutators/gamemode_assault.qc @@ -0,0 +1,646 @@ +// random functions +void assault_objective_use() +{ + // activate objective + self.health = 100; + //print("^2Activated objective ", self.targetname, "=", etos(self), "\n"); + //print("Activator is ", activator.classname, "\n"); + + entity oldself; + oldself = self; + + for(self = world; (self = find(self, target, oldself.targetname)); ) + { + if(self.classname == "target_objective_decrease") + target_objective_decrease_activate(); + } + + self = oldself; +} + +vector target_objective_spawn_evalfunc(entity player, entity spot, vector current) +{ + if(self.health < 0 || self.health >= ASSAULT_VALUE_INACTIVE) + return '-1 0 0'; + return current; +} + +// reset this objective. Used when spawning an objective +// and when a new round starts +void assault_objective_reset() +{ + self.health = ASSAULT_VALUE_INACTIVE; +} + +// decrease the health of targeted objectives +void assault_objective_decrease_use() +{ + if(activator.team != assault_attacker_team) + { + // wrong team triggered decrease + return; + } + + if(other.assault_sprite) + { + WaypointSprite_Disown(other.assault_sprite, waypointsprite_deadlifetime); + if(other.classname == "func_assault_destructible") + other.sprite = world; + } + else + return; // already activated! cannot activate again! + + if(self.enemy.health < ASSAULT_VALUE_INACTIVE) + { + if(self.enemy.health - self.dmg > 0.5) + { + PlayerTeamScore_Add(activator, SP_SCORE, ST_SCORE, self.dmg); + self.enemy.health = self.enemy.health - self.dmg; + } + else + { + PlayerTeamScore_Add(activator, SP_SCORE, ST_SCORE, self.enemy.health); + PlayerTeamScore_Add(activator, SP_ASSAULT_OBJECTIVES, ST_ASSAULT_OBJECTIVES, 1); + self.enemy.health = -1; + + entity oldself, oldactivator; + + oldself = self; + self = oldself.enemy; + if(self.message) + { + entity player; + string s; + FOR_EACH_PLAYER(player) + { + s = strcat(self.message, "\n"); + centerprint(player, s); + } + } + + oldactivator = activator; + activator = oldself; + SUB_UseTargets(); + activator = oldactivator; + self = oldself; + } + } +} + +void assault_setenemytoobjective() +{ + entity objective; + for(objective = world; (objective = find(objective, targetname, self.target)); ) + { + if(objective.classname == "target_objective") + { + if(self.enemy == world) + self.enemy = objective; + else + objerror("more than one objective as target - fix the map!"); + break; + } + } + + if(self.enemy == world) + objerror("no objective as target - fix the map!"); +} + +float assault_decreaser_sprite_visible(entity e) +{ + entity decreaser; + + decreaser = self.assault_decreaser; + + if(decreaser.enemy.health >= ASSAULT_VALUE_INACTIVE) + return FALSE; + + return TRUE; +} + +void target_objective_decrease_activate() +{ + entity ent, spr; + self.owner = world; + for(ent = world; (ent = find(ent, target, self.targetname)); ) + { + if(ent.assault_sprite != world) + { + WaypointSprite_Disown(ent.assault_sprite, waypointsprite_deadlifetime); + if(ent.classname == "func_assault_destructible") + ent.sprite = world; + } + + spr = WaypointSprite_SpawnFixed("", 0.5 * (ent.absmin + ent.absmax), ent, assault_sprite, RADARICON_OBJECTIVE, '1 0.5 0'); + spr.assault_decreaser = self; + spr.waypointsprite_visible_for_player = assault_decreaser_sprite_visible; + spr.classname = "sprite_waypoint"; + WaypointSprite_UpdateRule(spr, assault_attacker_team, SPRITERULE_TEAMPLAY); + if(ent.classname == "func_assault_destructible") + { + WaypointSprite_UpdateSprites(spr, "as-defend", "as-destroy", "as-destroy"); + WaypointSprite_UpdateMaxHealth(spr, ent.max_health); + WaypointSprite_UpdateHealth(spr, ent.health); + ent.sprite = spr; + } + else + WaypointSprite_UpdateSprites(spr, "as-defend", "as-push", "as-push"); + } +} + +void target_objective_decrease_findtarget() +{ + assault_setenemytoobjective(); +} + +void target_assault_roundend_reset() +{ + //print("round end reset\n"); + self.cnt = self.cnt + 1; // up round counter + self.winning = 0; // up round +} + +void target_assault_roundend_use() +{ + self.winning = 1; // round has been won by attackers +} + +void assault_roundstart_use() +{ + activator = self; + SUB_UseTargets(); + +#ifdef TTURRETS_ENABLED + entity ent, oldself; + + //(Re)spawn all turrets + oldself = self; + ent = find(world, classname, "turret_main"); + while(ent) { + // Swap turret teams + if(ent.team == COLOR_TEAM1) + ent.team = COLOR_TEAM2; + else + ent.team = COLOR_TEAM1; + + self = ent; + + // Dubbles as teamchange + turret_stdproc_respawn(); + + ent = find(ent, classname, "turret_main"); + } + self = oldself; +#endif +} + +void assault_wall_think() +{ + if(self.enemy.health < 0) + { + self.model = ""; + self.solid = SOLID_NOT; + } + else + { + self.model = self.mdl; + self.solid = SOLID_BSP; + } + + self.nextthink = time + 0.2; +} + +// trigger new round +// reset objectives, toggle spawnpoints, reset triggers, ... +void vehicles_clearrturn(); +void vehicles_spawn(); +void assault_new_round() +{ + entity oldself; + //bprint("ASSAULT: new round\n"); + + oldself = self; + // Eject players from vehicles + FOR_EACH_PLAYER(self) + { + if(self.vehicle) + vehicles_exit(VHEF_RELESE); + } + + self = findchainflags(vehicle_flags, VHF_ISVEHICLE); + while(self) + { + vehicles_clearrturn(); + vehicles_spawn(); + self = self.chain; + } + + self = oldself; + + // up round counter + self.winning = self.winning + 1; + + // swap attacker/defender roles + if(assault_attacker_team == COLOR_TEAM1) { + assault_attacker_team = COLOR_TEAM2; + } else { + assault_attacker_team = COLOR_TEAM1; + } + + + entity ent; + for(ent = world; (ent = nextent(ent)); ) + { + if(clienttype(ent) == CLIENTTYPE_NOTACLIENT) + { + if(ent.team_saved == COLOR_TEAM1) + ent.team_saved = COLOR_TEAM2; + else if(ent.team_saved == COLOR_TEAM2) + ent.team_saved = COLOR_TEAM1; + } + } + + // reset the level with a countdown + cvar_set("timelimit", ftos(ceil(time - game_starttime) / 60)); + ReadyRestart_force(); // sets game_starttime +} + +// spawnfuncs +void spawnfunc_info_player_attacker() +{ + if not(g_assault) + { + remove(self); + return; + } + self.team = COLOR_TEAM1; // red, gets swapped every round + spawnfunc_info_player_deathmatch(); +} + +void spawnfunc_info_player_defender() +{ + if not(g_assault) + { + remove(self); + return; + } + self.team = COLOR_TEAM2; // blue, gets swapped every round + spawnfunc_info_player_deathmatch(); +} + +void spawnfunc_target_objective() +{ + if not(g_assault) + { + remove(self); + return; + } + self.classname = "target_objective"; + self.use = assault_objective_use; + assault_objective_reset(); + self.reset = assault_objective_reset; + self.spawn_evalfunc = target_objective_spawn_evalfunc; +} + +void spawnfunc_target_objective_decrease() +{ + if not(g_assault) + { + remove(self); + return; + } + + self.classname = "target_objective_decrease"; + + if(!self.dmg) + self.dmg = 101; + + self.use = assault_objective_decrease_use; + self.health = ASSAULT_VALUE_INACTIVE; + self.max_health = ASSAULT_VALUE_INACTIVE; + self.enemy = world; + + InitializeEntity(self, target_objective_decrease_findtarget, INITPRIO_FINDTARGET); +} + +// destructible walls that can be used to trigger target_objective_decrease +void spawnfunc_func_assault_destructible() +{ + if not(g_assault) + { + remove(self); + return; + } + self.spawnflags = 3; + self.classname = "func_assault_destructible"; + + if(assault_attacker_team == COLOR_TEAM1) + self.team = COLOR_TEAM2; + else + self.team = COLOR_TEAM1; + + spawnfunc_func_breakable(); +} + +void spawnfunc_func_assault_wall() +{ + if not(g_assault) + { + remove(self); + return; + } + self.classname = "func_assault_wall"; + self.mdl = self.model; + setmodel(self, self.mdl); + self.solid = SOLID_BSP; + self.think = assault_wall_think; + self.nextthink = time; + InitializeEntity(self, assault_setenemytoobjective, INITPRIO_FINDTARGET); +} + +void spawnfunc_target_assault_roundend() +{ + if not(g_assault) + { + remove(self); + return; + } + self.winning = 0; // round not yet won by attackers + self.classname = "target_assault_roundend"; + self.use = target_assault_roundend_use; + self.cnt = 0; // first round + self.reset = target_assault_roundend_reset; +} + +void spawnfunc_target_assault_roundstart() +{ + if not(g_assault) + { + remove(self); + return; + } + assault_attacker_team = COLOR_TEAM1; + self.classname = "target_assault_roundstart"; + self.use = assault_roundstart_use; + self.reset2 = assault_roundstart_use; + InitializeEntity(self, assault_roundstart_use, INITPRIO_FINDTARGET); +} + +// legacy bot code +void havocbot_goalrating_ast_targets(float ratingscale) +{ + entity ad, best, wp, tod; + float radius, found, bestvalue; + vector p; + + ad = findchain(classname, "func_assault_destructible"); + + for (; ad; ad = ad.chain) + { + if (ad.target == "") + continue; + + if not(ad.bot_attack) + continue; + + found = FALSE; + for(tod = world; (tod = find(tod, targetname, ad.target)); ) + { + if(tod.classname == "target_objective_decrease") + { + if(tod.enemy.health > 0 && tod.enemy.health < ASSAULT_VALUE_INACTIVE) + { + // dprint(etos(ad),"\n"); + found = TRUE; + break; + } + } + } + + if(!found) + { + /// dprint("target not found\n"); + continue; + } + /// dprint("target #", etos(ad), " found\n"); + + + p = 0.5 * (ad.absmin + ad.absmax); + // dprint(vtos(ad.origin), " ", vtos(ad.absmin), " ", vtos(ad.absmax),"\n"); + // te_knightspike(p); + // te_lightning2(world, '0 0 0', p); + + // Find and rate waypoints around it + found = FALSE; + best = world; + bestvalue = 99999999999; + for(radius=0; radius<1500 && !found; radius+=500) + { + for(wp=findradius(p, radius); wp; wp=wp.chain) + { + if(!(wp.wpflags & WAYPOINTFLAG_GENERATED)) + if(wp.classname=="waypoint") + if(checkpvs(wp.origin, ad)) + { + found = TRUE; + if(wp.cnt self.havocbot_role_timeout) + { + havocbot_ast_reset_role(self); + return; + } + + if(self.havocbot_attack_time>time) + return; + + if (self.bot_strategytime < time) + { + navigation_goalrating_start(); + havocbot_goalrating_enemyplayers(20000, self.origin, 650); + havocbot_goalrating_ast_targets(20000); + havocbot_goalrating_items(15000, self.origin, 10000); + navigation_goalrating_end(); + + self.bot_strategytime = time + autocvar_bot_ai_strategyinterval; + } +} + +void havocbot_role_ast_defense() +{ + if(self.deadflag != DEAD_NO) + { + self.havocbot_attack_time = 0; + havocbot_ast_reset_role(self); + return; + } + + // Set the role timeout if necessary + if (!self.havocbot_role_timeout) + self.havocbot_role_timeout = time + 120; + + if (time > self.havocbot_role_timeout) + { + havocbot_ast_reset_role(self); + return; + } + + if(self.havocbot_attack_time>time) + return; + + if (self.bot_strategytime < time) + { + navigation_goalrating_start(); + havocbot_goalrating_enemyplayers(20000, self.origin, 3000); + havocbot_goalrating_ast_targets(20000); + havocbot_goalrating_items(15000, self.origin, 10000); + navigation_goalrating_end(); + + self.bot_strategytime = time + autocvar_bot_ai_strategyinterval; + } +} + +void havocbot_role_ast_setrole(entity bot, float role) +{ + switch(role) + { + case HAVOCBOT_AST_ROLE_DEFENSE: + bot.havocbot_role = havocbot_role_ast_defense; + bot.havocbot_role_flags = HAVOCBOT_AST_ROLE_DEFENSE; + bot.havocbot_role_timeout = 0; + break; + case HAVOCBOT_AST_ROLE_OFFENSE: + bot.havocbot_role = havocbot_role_ast_offense; + bot.havocbot_role_flags = HAVOCBOT_AST_ROLE_OFFENSE; + bot.havocbot_role_timeout = 0; + break; + } +} + +void havocbot_ast_reset_role(entity bot) +{ + if(self.deadflag != DEAD_NO) + return; + + if(bot.team == assault_attacker_team) + havocbot_role_ast_setrole(bot, HAVOCBOT_AST_ROLE_OFFENSE); + else + havocbot_role_ast_setrole(bot, HAVOCBOT_AST_ROLE_DEFENSE); +} + +void havocbot_chooserole_ast() +{ + havocbot_ast_reset_role(self); +} + +// mutator hooks +MUTATOR_HOOKFUNCTION(assault_PlayerSpawn) +{ + if(self.team == assault_attacker_team) + centerprint(self, "You are attacking!"); + else + centerprint(self, "You are defending!"); + + return FALSE; +} + +MUTATOR_HOOKFUNCTION(assault_TurretSpawn) +{ + if not (self.team) + self.team = 14; + + return FALSE; +} + +MUTATOR_HOOKFUNCTION(assault_VehicleSpawn) +{ + self.nextthink = time + 0.5; + + return FALSE; +} + +MUTATOR_HOOKFUNCTION(assault_BotRoles) +{ + havocbot_chooserole_ast(); + return TRUE; +} + +// scoreboard setup +void assault_ScoreRules() +{ + ScoreRules_basics(2, SFL_SORT_PRIO_SECONDARY, SFL_SORT_PRIO_SECONDARY, TRUE); + ScoreInfo_SetLabel_TeamScore( ST_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY); + ScoreInfo_SetLabel_PlayerScore(SP_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY); + ScoreRules_basics_end(); +} + +MUTATOR_DEFINITION(gamemode_assault) +{ + MUTATOR_HOOK(PlayerSpawn, assault_PlayerSpawn, CBC_ORDER_ANY); + MUTATOR_HOOK(TurretSpawn, assault_TurretSpawn, CBC_ORDER_ANY); + MUTATOR_HOOK(VehicleSpawn, assault_VehicleSpawn, CBC_ORDER_ANY); + MUTATOR_HOOK(HavocBot_ChooseRule, assault_BotRoles, 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."); + assault_ScoreRules(); + } + + MUTATOR_ONROLLBACK_OR_REMOVE + { + // we actually cannot roll back assault_Initialize here + // BUT: we don't need to! If this gets called, adding always + // succeeds. + } + + MUTATOR_ONREMOVE + { + print("This is a game type and it cannot be removed at runtime."); + return -1; + } + + return 0; +} diff --git a/qcsrc/server/mutators/gamemode_assault.qh b/qcsrc/server/mutators/gamemode_assault.qh new file mode 100644 index 000000000..9aecf87f2 --- /dev/null +++ b/qcsrc/server/mutators/gamemode_assault.qh @@ -0,0 +1,31 @@ +// sprites +.entity assault_decreaser; +.entity assault_sprite; + +// legacy bot defs +#define HAVOCBOT_AST_ROLE_NONE 0 +#define HAVOCBOT_AST_ROLE_DEFENSE 2 +#define HAVOCBOT_AST_ROLE_OFFENSE 4 + +.float havocbot_role_flags; +.float havocbot_attack_time; + +.void() havocbot_role; +.void() havocbot_previous_role; + +void() havocbot_role_ast_defense; +void() havocbot_role_ast_offense; +.entity havocbot_ast_target; + +void(entity bot) havocbot_ast_reset_role; + +void(float ratingscale, vector org, float sradius) havocbot_goalrating_items; +void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers; + +// scoreboard stuff +#define ST_ASSAULT_OBJECTIVES 1 +#define SP_ASSAULT_OBJECTIVES 4 + +// predefined spawnfuncs +void spawnfunc_func_breakable(); +void target_objective_decrease_activate(); \ No newline at end of file diff --git a/qcsrc/server/mutators/mutators.qh b/qcsrc/server/mutators/mutators.qh index 7fcfd9883..7d75706d7 100644 --- a/qcsrc/server/mutators/mutators.qh +++ b/qcsrc/server/mutators/mutators.qh @@ -1,3 +1,4 @@ +MUTATOR_DECLARATION(gamemode_assault); MUTATOR_DECLARATION(gamemode_keyhunt); MUTATOR_DECLARATION(gamemode_freezetag); MUTATOR_DECLARATION(gamemode_keepaway); diff --git a/qcsrc/server/progs.src b/qcsrc/server/progs.src index 36936e386..271248923 100644 --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@ -29,6 +29,7 @@ defs.qh // Should rename this, it has fields and globals mutators/base.qh mutators/mutators.qh +mutators/gamemode_assault.qh mutators/gamemode_ctf.qh mutators/gamemode_keyhunt.qh // TODO fix this mutators/gamemode_keepaway.qh @@ -166,7 +167,7 @@ command/getreplies.qc command/cmd.qc command/sv_cmd.qc -assault.qc +//assault.qc ipban.qc @@ -207,6 +208,7 @@ playerstats.qc ../common/explosion_equation.qc mutators/base.qc +mutators/gamemode_assault.qc mutators/gamemode_ctf.qc mutators/gamemode_freezetag.qc mutators/gamemode_keyhunt.qc diff --git a/qcsrc/server/scores_rules.qc b/qcsrc/server/scores_rules.qc index c4021fc39..66ba48145 100644 --- a/qcsrc/server/scores_rules.qc +++ b/qcsrc/server/scores_rules.qc @@ -125,17 +125,6 @@ void ScoreRules_race() ScoreRules_basics_end(); } -// Assault stuff -#define ST_ASSAULT_OBJECTIVES 1 -#define SP_ASSAULT_OBJECTIVES 4 -void ScoreRules_assault() -{ - ScoreRules_basics(2, SFL_SORT_PRIO_SECONDARY, SFL_SORT_PRIO_SECONDARY, TRUE); - ScoreInfo_SetLabel_TeamScore( ST_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY); - ScoreInfo_SetLabel_PlayerScore(SP_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY); - ScoreRules_basics_end(); -} - // Nexball stuff #define ST_NEXBALL_GOALS 1 #define SP_NEXBALL_GOALS 4 diff --git a/qcsrc/server/teamplay.qc b/qcsrc/server/teamplay.qc index b8f2f3ac8..f2aaf258b 100644 --- a/qcsrc/server/teamplay.qc +++ b/qcsrc/server/teamplay.qc @@ -203,7 +203,7 @@ void InitGameplayMode() if(g_assault) { ActivateTeamplay(); - ScoreRules_assault(); + MUTATOR_ADD(gamemode_assault); have_team_spawns = -1; // request team spawns } diff --git a/qcsrc/server/tturrets/system/system_main.qc b/qcsrc/server/tturrets/system/system_main.qc index dd58b3cee..726aa7be4 100644 --- a/qcsrc/server/tturrets/system/system_main.qc +++ b/qcsrc/server/tturrets/system/system_main.qc @@ -1060,12 +1060,7 @@ float turret_stdproc_init (string cvar_base_name, string base, string head, floa self.effects = EF_NODRAW; // Handle turret teams. - if (autocvar_g_assault != 0) - { - if not (self.team) - self.team = 14; // Assume turrets are on the defending side if not explicitly set otehrwize - } - else if not (teamplay) + if not (teamplay) self.team = MAX_SHOT_DISTANCE; // Group all turrets into the same team, so they dont kill eachother. else if(g_onslaught && self.targetname) { diff --git a/qcsrc/server/vehicles/vehicles.qc b/qcsrc/server/vehicles/vehicles.qc index 5e377079e..9627340fa 100644 --- a/qcsrc/server/vehicles/vehicles.qc +++ b/qcsrc/server/vehicles/vehicles.qc @@ -1275,7 +1275,7 @@ float vehicle_initialize(string net_name, self.vehicle_respawntime = _respawntime; self.vehicle_spawn = spawnproc; self.effects = EF_NODRAW; - if(g_assault || !autocvar_g_vehicles_delayspawn) + if(!autocvar_g_vehicles_delayspawn) self.nextthink = time + 0.5; else self.nextthink = time + _respawntime + (random() * autocvar_g_vehicles_delayspawn_jitter); @@ -1315,6 +1315,9 @@ float vehicle_initialize(string net_name, self.pos1 = self.origin; self.pos2 = self.angles; self.tur_head.team = self.team; + + if(MUTATOR_CALLHOOK(VehicleSpawn)) + return FALSE; return TRUE; } -- 2.39.2