]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge remote-tracking branch 'origin/master' into Mario/assault_mutator
authorSamual Lenks <samual@xonotic.org>
Tue, 7 May 2013 05:42:27 +0000 (01:42 -0400)
committerSamual Lenks <samual@xonotic.org>
Tue, 7 May 2013 05:42:27 +0000 (01:42 -0400)
Conflicts:
qcsrc/server/cl_client.qc
qcsrc/server/mutators/mutators.qh
qcsrc/server/progs.src

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 7a5662c..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 = NUM_TEAM_1; // red, gets swapped every round
-       spawnfunc_info_player_deathmatch();
-}
-
-void spawnfunc_info_player_defender() {
-       if(!g_assault)
-       {
-               remove(self);
-               return;
-       }
-       self.team = NUM_TEAM_2; // 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 == NUM_TEAM_1) {
-               self.team = NUM_TEAM_2;
-       } else {
-               self.team = NUM_TEAM_1;
-       }
-       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 == NUM_TEAM_1)
-                       ent.team = NUM_TEAM_2;
-               else
-                       ent.team = NUM_TEAM_1;
-
-               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 = NUM_TEAM_1;
-       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 == NUM_TEAM_1) {
-               assault_attacker_team = NUM_TEAM_2;
-       } else {
-               assault_attacker_team = NUM_TEAM_1;
-       }
-
-
-       entity ent;
-       for(ent = world; (ent = nextent(ent)); )
-       {
-               if(clienttype(ent) == CLIENTTYPE_NOTACLIENT)
-               {
-                       if(ent.team_saved == NUM_TEAM_1)
-                               ent.team_saved = NUM_TEAM_2;
-                       else if(ent.team_saved == NUM_TEAM_2)
-                               ent.team_saved = NUM_TEAM_1;
-               }
-       }
-
-       // 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..7a5662c
--- /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 = NUM_TEAM_1; // red, gets swapped every round
+       spawnfunc_info_player_deathmatch();
+}
+
+void spawnfunc_info_player_defender() {
+       if(!g_assault)
+       {
+               remove(self);
+               return;
+       }
+       self.team = NUM_TEAM_2; // 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 == NUM_TEAM_1) {
+               self.team = NUM_TEAM_2;
+       } else {
+               self.team = NUM_TEAM_1;
+       }
+       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 == NUM_TEAM_1)
+                       ent.team = NUM_TEAM_2;
+               else
+                       ent.team = NUM_TEAM_1;
+
+               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 = NUM_TEAM_1;
+       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 == NUM_TEAM_1) {
+               assault_attacker_team = NUM_TEAM_2;
+       } else {
+               assault_attacker_team = NUM_TEAM_1;
+       }
+
+
+       entity ent;
+       for(ent = world; (ent = nextent(ent)); )
+       {
+               if(clienttype(ent) == CLIENTTYPE_NOTACLIENT)
+               {
+                       if(ent.team_saved == NUM_TEAM_1)
+                               ent.team_saved = NUM_TEAM_2;
+                       else if(ent.team_saved == NUM_TEAM_2)
+                               ent.team_saved = NUM_TEAM_1;
+               }
+       }
+
+       // 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 bfc362caff91a1e9f630248669fce9d41bba8d50..efb9f8c17a240cfdd5869f6a074a7cb15fd2383b 100644 (file)
@@ -77,7 +77,6 @@ float autocvar_g_arena_point_limit;
 float autocvar_g_arena_roundbased;
 float autocvar_g_arena_round_timelimit;
 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 a3078c4e43588bc64bbbeef1c2a09e490a4af928..a54874786cf6df38f2f87cbf267ba88970d5fc79 100644 (file)
@@ -277,8 +277,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 2f9c0d8312fae7091b9570070db75e7b405a71c8..075280c264e2094c8ecd40785ad946c00736dec2 100644 (file)
@@ -808,14 +808,7 @@ void PutClientInServer (void)
 
                //stuffcmd(self, "chase_active 0");
                //stuffcmd(self, "set viewsize $tmpviewsize \n");
-
-               if(g_assault) {
-                       if(self.team == assault_attacker_team)
-                               Send_Notification(NOTIF_TEAM, self, MSG_CENTER, CENTER_ASSAULT_ATTACKING);
-                       else
-                               Send_Notification(NOTIF_TEAM, self, MSG_CENTER, CENTER_ASSAULT_DEFENDING);
-               }
-
+               
                target_voicescript_clear(self);
 
                // reset fields the weapons may use
index d705f5d5e9fb9674c7cae4f91400d0a2cbdb60cb..311d156304c9dbd0c99835d8ab928515e8ddc6aa 100644 (file)
@@ -248,6 +248,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..bf25947
--- /dev/null
@@ -0,0 +1,614 @@
+// 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);
+}
+
+// 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_ast_reset_role(self);
+       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 9c139f0e97d5042acdc076b7c03409fb135b2034..dab42bd65d8c39287701a4c3cffb3daf808f9609 100644 (file)
@@ -1,3 +1,4 @@
+MUTATOR_DECLARATION(gamemode_assault);
 MUTATOR_DECLARATION(gamemode_arena);
 MUTATOR_DECLARATION(gamemode_ca);
 MUTATOR_DECLARATION(gamemode_keyhunt);
index 28736e6cdb279f2ff0ee8762b8520f18cc7018ba..b3cc22ddaa7a785c9a44472025a74e1b0cde3cb3 100644 (file)
@@ -35,6 +35,7 @@ defs.qh               // Should rename this, it has fields and globals
 
 mutators/base.qh
 mutators/mutators.qh
+mutators/gamemode_assault.qh
 mutators/gamemode_arena.qh
 mutators/gamemode_ca.qh
 mutators/gamemode_ctf.qh
@@ -177,7 +178,7 @@ command/getreplies.qc
 command/cmd.qc
 command/sv_cmd.qc
 
-assault.qc
+//assault.qc
 
 ipban.qc
 
@@ -220,6 +221,7 @@ round_handler.qc
 ../common/explosion_equation.qc
 
 mutators/base.qc
+mutators/gamemode_assault.qc
 mutators/gamemode_arena.qc
 mutators/gamemode_ca.qc
 mutators/gamemode_ctf.qc
index 3f39f455c56c6f70d0813564e229b9d8d83c87aa..d60f4563c1cfdbf937982c9046ed66cc2f264423 100644 (file)
@@ -93,17 +93,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 3d7970297fd6f010923d73b020bb4fa13220fa1d..16236dd16ba7d93fb52210553efe8d0ca89a5078 100644 (file)
@@ -149,7 +149,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 a79fcc62a4e2df25044e7d4a55e7647ecf4273f4..1b1ae3f647628626c24440d0b020ac8654909be1 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;
 }