From: Mario Date: Fri, 1 Feb 2013 11:58:40 +0000 (+1100) Subject: Moving Assault to the mutator API X-Git-Tag: xonotic-v0.7.0~59^2~3 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=0cd9c0a195837f223442a3cb8b6a00ef0b343cf0;p=xonotic%2Fxonotic-data.pk3dir.git Moving Assault to the mutator API --- diff --git a/qcsrc/server/assault.qc b/qcsrc/server/assault.qc deleted file mode 100644 index 2562dca3d..000000000 --- a/qcsrc/server/assault.qc +++ /dev/null @@ -1,376 +0,0 @@ -void spawnfunc_func_breakable(); -void target_objective_decrease_activate(); -.entity assault_decreaser; -.entity assault_sprite; - -void spawnfunc_info_player_attacker() { - if(!g_assault) - { - remove(self); - return; - } - self.team = COLOR_TEAM1; // red, gets swapped every round - spawnfunc_info_player_deathmatch(); -} - -void spawnfunc_info_player_defender() { - if(!g_assault) - { - remove(self); - return; - } - self.team = COLOR_TEAM2; // blue, gets swapped every round - spawnfunc_info_player_deathmatch(); -} - -// reset this objective. Used when spawning an objective -// and when a new round starts -void assault_objective_reset() { - self.health = ASSAULT_VALUE_INACTIVE; -} - -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; -} - -void spawnfunc_target_objective() { - if(!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; -} - - -// 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 spawnfunc_target_objective_decrease() { - if(!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(!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 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; -} - -void spawnfunc_func_assault_wall() { - if(!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 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 spawnfunc_target_assault_roundend() { - if(!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 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 spawnfunc_target_assault_roundstart() { - if(!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); -} - -// 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 -} diff --git a/qcsrc/server/attic/assault.qc b/qcsrc/server/attic/assault.qc new file mode 100644 index 000000000..2562dca3d --- /dev/null +++ b/qcsrc/server/attic/assault.qc @@ -0,0 +1,376 @@ +void spawnfunc_func_breakable(); +void target_objective_decrease_activate(); +.entity assault_decreaser; +.entity assault_sprite; + +void spawnfunc_info_player_attacker() { + if(!g_assault) + { + remove(self); + return; + } + self.team = COLOR_TEAM1; // red, gets swapped every round + spawnfunc_info_player_deathmatch(); +} + +void spawnfunc_info_player_defender() { + if(!g_assault) + { + remove(self); + return; + } + self.team = COLOR_TEAM2; // blue, gets swapped every round + spawnfunc_info_player_deathmatch(); +} + +// reset this objective. Used when spawning an objective +// and when a new round starts +void assault_objective_reset() { + self.health = ASSAULT_VALUE_INACTIVE; +} + +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; +} + +void spawnfunc_target_objective() { + if(!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; +} + + +// 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 spawnfunc_target_objective_decrease() { + if(!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(!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 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; +} + +void spawnfunc_func_assault_wall() { + if(!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 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 spawnfunc_target_assault_roundend() { + if(!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 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 spawnfunc_target_assault_roundstart() { + if(!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); +} + +// 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 +} diff --git a/qcsrc/server/attic/bot/havocbot/role_assault.qc b/qcsrc/server/attic/bot/havocbot/role_assault.qc new file mode 100644 index 000000000..4456802d5 --- /dev/null +++ b/qcsrc/server/attic/bot/havocbot/role_assault.qc @@ -0,0 +1,205 @@ +#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; + +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); +} 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/role_assault.qc b/qcsrc/server/bot/havocbot/role_assault.qc deleted file mode 100644 index 4456802d5..000000000 --- a/qcsrc/server/bot/havocbot/role_assault.qc +++ /dev/null @@ -1,205 +0,0 @@ -#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; - -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); -} 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; }