]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Moving Assault to the mutator API
authorMario <mario.mario@y7mail.com>
Fri, 1 Feb 2013 11:58:40 +0000 (22:58 +1100)
committerMario <mario.mario@y7mail.com>
Fri, 1 Feb 2013 11:58:40 +0000 (22:58 +1100)
17 files changed:
qcsrc/server/assault.qc [deleted file]
qcsrc/server/attic/assault.qc [new file with mode: 0644]
qcsrc/server/attic/bot/havocbot/role_assault.qc [new file with mode: 0644]
qcsrc/server/autocvars.qh
qcsrc/server/bot/havocbot/havocbot.qc
qcsrc/server/bot/havocbot/role_assault.qc [deleted file]
qcsrc/server/bot/havocbot/roles.qc
qcsrc/server/cl_client.qc
qcsrc/server/mutators/base.qh
qcsrc/server/mutators/gamemode_assault.qc [new file with mode: 0644]
qcsrc/server/mutators/gamemode_assault.qh [new file with mode: 0644]
qcsrc/server/mutators/mutators.qh
qcsrc/server/progs.src
qcsrc/server/scores_rules.qc
qcsrc/server/teamplay.qc
qcsrc/server/tturrets/system/system_main.qc
qcsrc/server/vehicles/vehicles.qc

diff --git a/qcsrc/server/assault.qc b/qcsrc/server/assault.qc
deleted file mode 100644 (file)
index 2562dca..0000000
+++ /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("<placeholder>", 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 (file)
index 0000000..2562dca
--- /dev/null
@@ -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("<placeholder>", 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 (file)
index 0000000..4456802
--- /dev/null
@@ -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<bestvalue)
+                                       {
+                                               best = wp;
+                                               bestvalue = wp.cnt;
+                                       }
+                               }
+                       }
+               }
+
+               if(best)
+               {
+               ///     dprint("waypoints around target were found\n");
+               //      te_lightning2(world, '0 0 0', best.origin);
+               //      te_knightspike(best.origin);
+
+                       navigation_routerating(best, ratingscale, 4000);
+                       best.cnt += 1;
+
+                       self.havocbot_attack_time = 0;
+
+                       if(checkpvs(self.view_ofs,ad))
+                       if(checkpvs(self.view_ofs,best))
+                       {
+                       //      dprint("increasing attack time for this target\n");
+                               self.havocbot_attack_time = time + 2;
+                       }
+               }
+       }
+}
+
+void havocbot_role_ast_offense()
+{
+       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, 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);
+}
index c8db3db8a409c5749a6b1c4fef7e086cdb5d22dd..45e5d35fba71d805eea9c3116af1f5b642b503bd 100644 (file)
@@ -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;
index 1b9178b1774b7632c2359463a9fd777833771326..0b8bac7333ee49ce8807733056a810a888c6fdfd 100644 (file)
@@ -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 (file)
index 4456802..0000000
+++ /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<bestvalue)
-                                       {
-                                               best = wp;
-                                               bestvalue = wp.cnt;
-                                       }
-                               }
-                       }
-               }
-
-               if(best)
-               {
-               ///     dprint("waypoints around target were found\n");
-               //      te_lightning2(world, '0 0 0', best.origin);
-               //      te_knightspike(best.origin);
-
-                       navigation_routerating(best, ratingscale, 4000);
-                       best.cnt += 1;
-
-                       self.havocbot_attack_time = 0;
-
-                       if(checkpvs(self.view_ofs,ad))
-                       if(checkpvs(self.view_ofs,best))
-                       {
-                       //      dprint("increasing attack time for this target\n");
-                               self.havocbot_attack_time = time + 2;
-                       }
-               }
-       }
-}
-
-void havocbot_role_ast_offense()
-{
-       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, 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);
-}
index ad3bb2367418f611d13bb67725c70cd416d7831f..ce7fb8194a0268b3394f4260d02397e55613518e 100644 (file)
@@ -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();
 }
index 165460eeb2ae3ad678729611f873f927c7f65cb9..6c05b534d18cae4fcb64c40d8c756d74be5fce9e 100644 (file)
@@ -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
index d90d564b501447acb3e3ef1def71530be1a521ee..ce90ef457eb1fbd3db4c22e60cc7c2360fed502a 100644 (file)
@@ -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 (file)
index 0000000..7b55be4
--- /dev/null
@@ -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("<placeholder>", 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<bestvalue)
+                                       {
+                                               best = wp;
+                                               bestvalue = wp.cnt;
+                                       }
+                               }
+                       }
+               }
+
+               if(best)
+               {
+               ///     dprint("waypoints around target were found\n");
+               //      te_lightning2(world, '0 0 0', best.origin);
+               //      te_knightspike(best.origin);
+
+                       navigation_routerating(best, ratingscale, 4000);
+                       best.cnt += 1;
+
+                       self.havocbot_attack_time = 0;
+
+                       if(checkpvs(self.view_ofs,ad))
+                       if(checkpvs(self.view_ofs,best))
+                       {
+                       //      dprint("increasing attack time for this target\n");
+                               self.havocbot_attack_time = time + 2;
+                       }
+               }
+       }
+}
+
+void havocbot_role_ast_offense()
+{
+       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, 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 (file)
index 0000000..9aecf87
--- /dev/null
@@ -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
index 7fcfd9883bb9195f24b7f513ffc1e8189d03c014..7d75706d7a699deadfc36406586fa880cd10e8ca 100644 (file)
@@ -1,3 +1,4 @@
+MUTATOR_DECLARATION(gamemode_assault);
 MUTATOR_DECLARATION(gamemode_keyhunt);
 MUTATOR_DECLARATION(gamemode_freezetag);
 MUTATOR_DECLARATION(gamemode_keepaway);
index 36936e38642e597bad39ca5b3d56621450a9dbe1..27124892343be9bd2886949d9338fabc72f3fc7a 100644 (file)
@@ -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
index c4021fc397ea3d2cf28c67e004bb9afdde68e1aa..66ba48145338425295501e0a232fbe002d9307b1 100644 (file)
@@ -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
index b8f2f3ac8746ea4e02daae0936833d2086954699..f2aaf258bfffd3850382b4f2000b7d8c0ed09069 100644 (file)
@@ -203,7 +203,7 @@ void InitGameplayMode()
        if(g_assault)
        {
                ActivateTeamplay();
-               ScoreRules_assault();
+               MUTATOR_ADD(gamemode_assault);
                have_team_spawns = -1; // request team spawns
        }
 
index dd58b3cee2860e0c031dc131a47eab165c846967..726aa7be44c9df5f6963e79a5af55ac820a038bc 100644 (file)
@@ -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)
        {
index 5e377079e01dd2fc0b1377fde2a884a17e50656a..9627340faad9437de829f316697111eeaf1ede44 100644 (file)
@@ -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;
 }