]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into martin-t/okc2
authorMartin Taibr <taibr.martin@gmail.com>
Sun, 29 Oct 2017 00:36:16 +0000 (02:36 +0200)
committerMartin Taibr <taibr.martin@gmail.com>
Sun, 29 Oct 2017 00:36:16 +0000 (02:36 +0200)
93 files changed:
balance-mario.cfg
balance-nexuiz25.cfg
balance-overkill.cfg
balance-samual.cfg
balance-xdf.cfg
balance-xonotic.cfg
balance-xpm.cfg
common.pot
defaultServer.cfg
mutators.cfg
qcsrc/client/hud/panel/ammo.qc
qcsrc/client/hud/panel/weapons.qc
qcsrc/common/ent_cs.qh
qcsrc/common/mutators/mutator/_mod.inc
qcsrc/common/mutators/mutator/_mod.qh
qcsrc/common/mutators/mutator/damagetext/cl_damagetext.qc
qcsrc/common/mutators/mutator/dynamic_handicap/_mod.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/dynamic_handicap/_mod.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/nix/sv_nix.qc
qcsrc/common/mutators/mutator/overkill/hmg.qc
qcsrc/common/mutators/mutator/overkill/hmg.qh
qcsrc/common/mutators/mutator/overkill/rpc.qc
qcsrc/common/mutators/mutator/overkill/rpc.qh
qcsrc/common/notifications/all.inc
qcsrc/common/playerstats.qc
qcsrc/common/playerstats.qh
qcsrc/common/resources.qh [new file with mode: 0644]
qcsrc/common/t_items.qc
qcsrc/common/t_items.qh
qcsrc/common/triggers/func/breakable.qc
qcsrc/common/triggers/func/door.qc
qcsrc/common/weapons/all.qc
qcsrc/common/weapons/weapon.qh
qcsrc/common/weapons/weapon/arc.qc
qcsrc/common/weapons/weapon/arc.qh
qcsrc/common/weapons/weapon/blaster.qh
qcsrc/common/weapons/weapon/crylink.qc
qcsrc/common/weapons/weapon/crylink.qh
qcsrc/common/weapons/weapon/devastator.qc
qcsrc/common/weapons/weapon/devastator.qh
qcsrc/common/weapons/weapon/electro.qc
qcsrc/common/weapons/weapon/electro.qh
qcsrc/common/weapons/weapon/fireball.qh
qcsrc/common/weapons/weapon/hagar.qc
qcsrc/common/weapons/weapon/hagar.qh
qcsrc/common/weapons/weapon/hlac.qc
qcsrc/common/weapons/weapon/hlac.qh
qcsrc/common/weapons/weapon/hook.qh
qcsrc/common/weapons/weapon/machinegun.qc
qcsrc/common/weapons/weapon/machinegun.qh
qcsrc/common/weapons/weapon/minelayer.qc
qcsrc/common/weapons/weapon/minelayer.qh
qcsrc/common/weapons/weapon/mortar.qc
qcsrc/common/weapons/weapon/mortar.qh
qcsrc/common/weapons/weapon/porto.qh
qcsrc/common/weapons/weapon/rifle.qc
qcsrc/common/weapons/weapon/rifle.qh
qcsrc/common/weapons/weapon/seeker.qc
qcsrc/common/weapons/weapon/seeker.qh
qcsrc/common/weapons/weapon/shockwave.qh
qcsrc/common/weapons/weapon/shotgun.qc
qcsrc/common/weapons/weapon/shotgun.qh
qcsrc/common/weapons/weapon/vaporizer.qc
qcsrc/common/weapons/weapon/vaporizer.qh
qcsrc/common/weapons/weapon/vortex.qc
qcsrc/common/weapons/weapon/vortex.qh
qcsrc/ecs/systems/sv_physics.qc
qcsrc/lib/_all.inc
qcsrc/lib/spawnfunc.qh
qcsrc/lib/string.qh
qcsrc/server/_mod.inc
qcsrc/server/_mod.qh
qcsrc/server/anticheat.qc
qcsrc/server/client.qc
qcsrc/server/command/vote.qc
qcsrc/server/g_damage.qc
qcsrc/server/handicap.qc [new file with mode: 0644]
qcsrc/server/handicap.qh [new file with mode: 0644]
qcsrc/server/miscfunctions.qc
qcsrc/server/miscfunctions.qh
qcsrc/server/mutators/events.qh
qcsrc/server/player.qc
qcsrc/server/resources.qc
qcsrc/server/resources.qh
qcsrc/server/scores.qc
qcsrc/server/sv_main.qc
qcsrc/server/weapons/spawning.qc
qcsrc/server/weapons/throwing.qc
qcsrc/server/weapons/weaponsystem.qc
qcsrc/tools/genmod.sh
scripts/ok_nade_counter.shader

index a8f59a8cd75a31c5f5b23b1dc4590007dd7bf8df..28100182ea5fe41b0b1d028b020a93503228c9f5 100644 (file)
@@ -9,6 +9,13 @@ set g_start_ammo_rockets 0
 set g_start_ammo_cells 0
 set g_start_ammo_plasma 0
 set g_start_ammo_fuel 0
+set g_random_start_weapons_count 0
+set g_random_start_weapons "machinegun mortar electro crylink vortex hagar devastator"
+set g_random_start_shells 15
+set g_random_start_bullets 80
+set g_random_start_rockets 40
+set g_random_start_cells 30
+set g_random_start_plasma 30
 set g_warmup_start_health 100 "starting values when being in warmup-stage"
 set g_warmup_start_armor 100 "starting values when being in warmup-stage"
 set g_warmup_start_ammo_shells 30 "starting values when being in warmup-stage"
index 4967fa7e47936208ca64c9e719e5e41fa373b968..37099c1226dfa6ff992a97b74ef1217b91111b31 100644 (file)
@@ -9,6 +9,13 @@ set g_start_ammo_rockets 0
 set g_start_ammo_cells 0
 set g_start_ammo_plasma 0
 set g_start_ammo_fuel 0
+set g_random_start_weapons_count 0
+set g_random_start_weapons "machinegun mortar electro crylink vortex hagar devastator"
+set g_random_start_shells 15
+set g_random_start_bullets 80
+set g_random_start_rockets 15
+set g_random_start_cells 25
+set g_random_start_plasma 25
 set g_warmup_start_health 250 "starting values when being in warmup-stage"
 set g_warmup_start_armor 100 "starting values when being in warmup-stage"
 set g_warmup_start_ammo_shells 50 "starting values when being in warmup-stage"
index 3f025655c8826083e1280112a4550d85100d12d8..3a321ce53d461b2eca19452f5ad420975f9f2c12 100644 (file)
@@ -9,6 +9,13 @@ set g_start_ammo_rockets 0
 set g_start_ammo_cells 0
 set g_start_ammo_plasma 0
 set g_start_ammo_fuel 0
+set g_random_start_weapons_count 0
+set g_random_start_weapons "machinegun mortar electro crylink vortex hagar devastator"
+set g_random_start_shells 15
+set g_random_start_bullets 80
+set g_random_start_rockets 40
+set g_random_start_cells 30
+set g_random_start_plasma 30
 set g_warmup_start_health 100 "starting values when being in warmup-stage"
 set g_warmup_start_armor 100 "starting values when being in warmup-stage"
 set g_warmup_start_ammo_shells 30 "starting values when being in warmup-stage"
index 52fd03dc7e32dcc3223fa5508c0b7b19bd6c1b32..48c68d81be66e77c96cf8f55c417fd4b8565fe0f 100644 (file)
@@ -9,6 +9,13 @@ set g_start_ammo_rockets 0
 set g_start_ammo_cells 0
 set g_start_ammo_plasma 0
 set g_start_ammo_fuel 0
+set g_random_start_weapons_count 0
+set g_random_start_weapons "machinegun mortar electro crylink vortex hagar devastator"
+set g_random_start_shells 15
+set g_random_start_bullets 80
+set g_random_start_rockets 40
+set g_random_start_cells 30
+set g_random_start_plasma 30
 set g_warmup_start_health 100 "starting values when being in warmup-stage"
 set g_warmup_start_armor 100 "starting values when being in warmup-stage"
 set g_warmup_start_ammo_shells 30 "starting values when being in warmup-stage"
index 4d26972067abdcf3fd4a18f1e3db231bd19e4958..562506283c44ad965d5d7d0f641a96a910aa11d3 100644 (file)
@@ -9,6 +9,13 @@ set g_start_ammo_rockets 0
 set g_start_ammo_cells 0
 set g_start_ammo_plasma 0
 set g_start_ammo_fuel 0
+set g_random_start_weapons_count 0
+set g_random_start_weapons "machinegun mortar electro crylink vortex hagar devastator"
+set g_random_start_shells 15
+set g_random_start_bullets 80
+set g_random_start_rockets 40
+set g_random_start_cells 30
+set g_random_start_plasma 30
 set g_warmup_start_health 100 "starting values when being in warmup-stage"
 set g_warmup_start_armor 100 "starting values when being in warmup-stage"
 set g_warmup_start_ammo_shells 30 "starting values when being in warmup-stage"
index fece8cd726072f6b9f0ca81677ce05ffc00815d7..32924a72d2cee7cca9d636330661abe49047f404 100644 (file)
@@ -9,6 +9,13 @@ set g_start_ammo_rockets 0
 set g_start_ammo_cells 0
 set g_start_ammo_plasma 0
 set g_start_ammo_fuel 0
+set g_random_start_weapons_count 0
+set g_random_start_weapons "machinegun mortar electro crylink vortex hagar devastator"
+set g_random_start_shells 15
+set g_random_start_bullets 80
+set g_random_start_rockets 40
+set g_random_start_cells 30
+set g_random_start_plasma 30
 set g_warmup_start_health 100 "starting values when being in warmup-stage"
 set g_warmup_start_armor 100 "starting values when being in warmup-stage"
 set g_warmup_start_ammo_shells 30 "starting values when being in warmup-stage"
index 984972623228b5a3c98c0bf6a035db3d9a7b83d9..6901eda28a8c130622dc43db632f7475965050d3 100644 (file)
@@ -9,6 +9,13 @@ set g_start_ammo_rockets 0
 set g_start_ammo_cells 0
 set g_start_ammo_plasma 0
 set g_start_ammo_fuel 0
+set g_random_start_weapons_count 0
+set g_random_start_weapons "machinegun mortar electro crylink vortex hagar devastator"
+set g_random_start_shells 15
+set g_random_start_bullets 80
+set g_random_start_rockets 40
+set g_random_start_cells 30
+set g_random_start_plasma 30
 set g_warmup_start_health 100 "starting values when being in warmup-stage"
 set g_warmup_start_armor 100 "starting values when being in warmup-stage"
 set g_warmup_start_ammo_shells 30 "starting values when being in warmup-stage"
index 055fa19dc645ea65091b0e6a78d6be596f171352..d0c8c9ce60535857a82023b1090f62e02c11baaf 100644 (file)
@@ -2844,7 +2844,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index 596576a097fb93c6841a9e76ba1927a5909a1e13..47037c069b62ca6aea1538be444c949192e3f721 100644 (file)
@@ -549,3 +549,5 @@ set sv_join_notices_time 15
 set sv_simple_items 1 "allow or forbid client use of simple items"
 
 set sv_showspectators 1 "Show who's spectating who in the player info panel when client has cl_showspectators on. Shouldn't be used on competitive servers, also disable when watching a suspected cheater"
+
+set sv_damagetext 2 "<= 0: disabled, >= 1: visible to spectators, >= 2: visible to attacker, >= 3: all players see everyone's damage"
index 583f3d5975672689f7aeb40348db5043b86b0fcb..de8faa4ff1e01315b737f09350578b1665719bd1 100644 (file)
@@ -468,3 +468,12 @@ set g_bugrigs_steer 1      "steering amount"
 //  running guns
 // ==============
 set g_running_guns 0 "... or wonder, till it drives you mad, what would have followed if you had."
+
+// ==================
+//  dynamic handicap
+// ==================
+set g_dynamic_handicap 0 "Whether to enable dynamic handicap."
+set g_dynamic_handicap_scale 0.2 "The scale of the handicap. Larger values mean more penalties for strong players and more buffs for weak players."
+set g_dynamic_handicap_exponent 1 "The exponent used to calculate handicap. 1 means linear scale. Values more than 1 mean stronger non-linear handicap. Values less than 1 mean weaker non-linear handicap"
+set g_dynamic_handicap_min 0 "The minimum value of the handicap."
+set g_dynamic_handicap_max 0 "The maximum value of the handicap."
index 9e8320452a5e7dcf8db20213e12091dbd9ee1216..0636f3f2e972cfc551eb991b4631732d90aa79ab 100644 (file)
@@ -21,10 +21,10 @@ void DrawNadeProgressBar(vector myPos, vector mySize, float progress, vector col
 
 void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time); // TODO: mutator
 
-void DrawAmmoItem(vector myPos, vector mySize, .int ammoType, bool isCurrent, bool isInfinite)
+void DrawAmmoItem(vector myPos, vector mySize, int ammoType, bool isCurrent, bool isInfinite)
 {
     TC(bool, isCurrent); TC(bool, isInfinite);
-       if(ammoType == ammo_none)
+       if(ammoType == RESOURCE_NONE)
                return;
 
        // Initialize variables
@@ -32,7 +32,7 @@ void DrawAmmoItem(vector myPos, vector mySize, .int ammoType, bool isCurrent, bo
        int ammo;
        if(autocvar__hud_configure)
        {
-               isCurrent = (ammoType == ammo_rockets); // Rockets always current
+               isCurrent = (ammoType == RESOURCE_ROCKETS); // Rockets always current
                ammo = 60;
        }
        else
@@ -184,14 +184,14 @@ void HUD_Ammo()
        {
                if(autocvar__hud_configure)
                {
-                       DrawAmmoItem(pos, ammo_size, ammo_rockets, true, false);
+                       DrawAmmoItem(pos, ammo_size, RESOURCE_ROCKETS, true, false);
                }
                else
                {
                        DrawAmmoItem(
                                pos,
                                ammo_size,
-                               wep.ammo_field,
+                               wep.ammo_type,
                                true,
                                infinite_ammo
                        );
@@ -206,16 +206,16 @@ void HUD_Ammo()
        }
        else
        {
-               .int ammotype;
+               int ammotype;
                row = column = 0;
                for(i = 0; i < AMMO_COUNT; ++i)
                {
-                       ammotype = GetAmmoFieldFromNum(i);
+                       ammotype = GetAmmoTypeFromNum(i);
                        DrawAmmoItem(
                                pos + vec2(column * (ammo_size.x + offset.x), row * (ammo_size.y + offset.y)),
                                ammo_size,
                                ammotype,
-                               (wep.ammo_field == ammotype),
+                               (wep.ammo_type == ammotype),
                                infinite_ammo
                        );
 
index a7c0ade00b473de2f7e49cd3604464f657e1fe59..cebd8f5d65c162b6e3d15d90a5e7a496bbbc0858 100644 (file)
@@ -479,21 +479,21 @@ void HUD_Weapons()
                        }
 
                        // draw ammo status bar
-                       if(!infinite_ammo && autocvar_hud_panel_weapons_ammo && (it.ammo_field != ammo_none))
+                       if(!infinite_ammo && autocvar_hud_panel_weapons_ammo && (it.ammo_type != RESOURCE_NONE))
                        {
                                float ammo_full;
-                               a = getstati(GetAmmoStat(it.ammo_field)); // how much ammo do we have?
+                               a = getstati(GetAmmoStat(it.ammo_type)); // how much ammo do we have?
 
                                if(a > 0)
                                {
-                                       switch(it.ammo_field)
+                                       switch (it.ammo_type)
                                        {
-                                               case ammo_shells:  ammo_full = autocvar_hud_panel_weapons_ammo_full_shells;  break;
-                                               case ammo_nails:   ammo_full = autocvar_hud_panel_weapons_ammo_full_nails;   break;
-                                               case ammo_rockets: ammo_full = autocvar_hud_panel_weapons_ammo_full_rockets; break;
-                                               case ammo_cells:   ammo_full = autocvar_hud_panel_weapons_ammo_full_cells;   break;
-                                               case ammo_plasma:  ammo_full = autocvar_hud_panel_weapons_ammo_full_plasma;  break;
-                                               case ammo_fuel:    ammo_full = autocvar_hud_panel_weapons_ammo_full_fuel;    break;
+                                               case RESOURCE_SHELLS:  ammo_full = autocvar_hud_panel_weapons_ammo_full_shells;  break;
+                                               case RESOURCE_BULLETS: ammo_full = autocvar_hud_panel_weapons_ammo_full_nails;   break;
+                                               case RESOURCE_ROCKETS: ammo_full = autocvar_hud_panel_weapons_ammo_full_rockets; break;
+                                               case RESOURCE_CELLS:   ammo_full = autocvar_hud_panel_weapons_ammo_full_cells;   break;
+                                               case RESOURCE_PLASMA:  ammo_full = autocvar_hud_panel_weapons_ammo_full_plasma;  break;
+                                               case RESOURCE_FUEL:    ammo_full = autocvar_hud_panel_weapons_ammo_full_fuel;    break;
                                                default: ammo_full = 60;
                                        }
 
index 14a758b2615a88f9d8bf825eab629dad3f1877ae..0180fea784793f921036cf52bc4a2a91a1ad0aa1 100644 (file)
@@ -9,8 +9,13 @@ REGISTER_NET_TEMP(CLIENT_ENTCS)
 
 /** True when private information such as origin is available */
 .bool m_entcs_private;
+
 /** True when origin is available */
+// FIXME: it seems sometimes this is false when observing even though observers should be able to know about all players
+// easily reproducible on heart_v2 or The_Yard with bots - might be because they lack waypoints and bots stand still
+// it has happened in matches with players and no bots but much more rarely
 .bool has_origin;
+
 /** True when a recent server sent origin has been received */
 .bool has_sv_origin;
 
index 0d6326fef0712b405f0ad88a856c27a61ef646ab..eeb93ba5e83f7cb9252274e397c994bf9e93a73e 100644 (file)
@@ -9,6 +9,7 @@
 #include <common/mutators/mutator/damagetext/_mod.inc>
 #include <common/mutators/mutator/dodging/_mod.inc>
 #include <common/mutators/mutator/doublejump/_mod.inc>
+#include <common/mutators/mutator/dynamic_handicap/_mod.inc>
 #include <common/mutators/mutator/globalforces/_mod.inc>
 #include <common/mutators/mutator/hook/_mod.inc>
 #include <common/mutators/mutator/instagib/_mod.inc>
index 917dc6557ceb02b2415649bc6d9546e6a400c9c6..956c0d97536fbfeaddc4d4b8b1728ce147d09bc5 100644 (file)
@@ -9,6 +9,7 @@
 #include <common/mutators/mutator/damagetext/_mod.qh>
 #include <common/mutators/mutator/dodging/_mod.qh>
 #include <common/mutators/mutator/doublejump/_mod.qh>
+#include <common/mutators/mutator/dynamic_handicap/_mod.qh>
 #include <common/mutators/mutator/globalforces/_mod.qh>
 #include <common/mutators/mutator/hook/_mod.qh>
 #include <common/mutators/mutator/instagib/_mod.qh>
index bafe8c460733dae6c492706f8a8b6eb0fb405567..0977b62cebe380b5172e0ef03c6d11f38546da54 100644 (file)
@@ -233,9 +233,7 @@ NET_HANDLE(damagetext, bool isNew)
         }
         make_impure(NEW(DamageText, server_entity_index, entcs.origin, false, health, armor, potential_damage, deathtype, friendlyfire));
     } else if (autocvar_cl_damagetext_2d && spectatee_status != -1) {
-        // never show 2d damagetext when observing
-        // on some maps (hearth_v2, The_Yard), sometimes has_origin is false even though observers should know about all players
-        // it happens mostly with bots but occasionally also with players
+        // never show 2d damagetext when observing - might be a bug in .has_origin
 
         // screen coords only
         vector screen_pos = vec2(vid_conwidth * autocvar_cl_damagetext_2d_pos.x, vid_conheight * autocvar_cl_damagetext_2d_pos.y);
diff --git a/qcsrc/common/mutators/mutator/dynamic_handicap/_mod.inc b/qcsrc/common/mutators/mutator/dynamic_handicap/_mod.inc
new file mode 100644 (file)
index 0000000..f4b0a30
--- /dev/null
@@ -0,0 +1,4 @@
+// generated file; do not modify
+#ifdef SVQC
+    #include <common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qc>
+#endif
diff --git a/qcsrc/common/mutators/mutator/dynamic_handicap/_mod.qh b/qcsrc/common/mutators/mutator/dynamic_handicap/_mod.qh
new file mode 100644 (file)
index 0000000..10aeb22
--- /dev/null
@@ -0,0 +1,4 @@
+// generated file; do not modify
+#ifdef SVQC
+    #include <common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qc b/qcsrc/common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qc
new file mode 100644 (file)
index 0000000..d5d3ba4
--- /dev/null
@@ -0,0 +1,116 @@
+#include "sv_dynamic_handicap.qh"
+/// \file
+/// \brief Source file that contains implementation of the Dynamic handicap
+/// mutator.
+/// \author Lyberta
+/// \copyright GNU GPLv2 or any later version.
+
+//======================= Global variables ====================================
+
+int autocvar_g_dynamic_handicap; ///< Whether to enable dynamic handicap.
+/// \brief The scale of the handicap. Larget values mean more penalties for
+/// strong players and more buffs for weak players.
+float autocvar_g_dynamic_handicap_scale;
+/// \brief The exponent used to calculate handicap. 1 means linear scale. Values
+/// more than 1 mean stronger non-linear handicap. Values less than 1 mean
+/// weaker non-linear handicap.
+float autocvar_g_dynamic_handicap_exponent;
+float autocvar_g_dynamic_handicap_min; ///< The minimum value of the handicap.
+float autocvar_g_dynamic_handicap_max; ///< The maximum value of the handicap.
+
+//====================== Forward declarations =================================
+
+/// \brief Clamps the value of the handicap.
+/// \param[in] handicap Value to clamp.
+/// \return Clamped value.
+float DynamicHandicap_ClampHandicap(float handicap);
+
+//========================= Free functions ====================================
+
+/// \brief Updates the handicap of all players.
+/// \return No return.
+void DynamicHandicap_UpdateHandicap()
+{
+       float total_score = 0;
+       float total_players = 0;
+       FOREACH_CLIENT(IS_PLAYER(it),
+       {
+               total_score += PlayerScore_Get(it, SP_SCORE);
+               ++total_players;
+       });
+       float mean_score = total_score / total_players;
+       FOREACH_CLIENT(true,
+       {
+               float score = PlayerScore_Get(it, SP_SCORE);
+               float handicap = fabs((score - mean_score) *
+                       autocvar_g_dynamic_handicap_scale);
+               handicap = handicap ** autocvar_g_dynamic_handicap_exponent;
+               if (score < mean_score)
+               {
+                       handicap = -handicap;
+               }
+               if (handicap >= 0)
+               {
+                       handicap += 1;
+               }
+               else
+               {
+                       handicap = 1 / (fabs(handicap) + 1);
+               }
+               handicap = DynamicHandicap_ClampHandicap(handicap);
+               Handicap_SetForcedHandicap(it, handicap);
+       });
+}
+
+float DynamicHandicap_ClampHandicap(float handicap)
+{
+       if ((autocvar_g_dynamic_handicap_min >= 0) && (handicap <
+               autocvar_g_dynamic_handicap_min))
+       {
+               handicap = autocvar_g_dynamic_handicap_min;
+       }
+       if ((autocvar_g_dynamic_handicap_max > 0) && (handicap >
+               autocvar_g_dynamic_handicap_max))
+       {
+               handicap = autocvar_g_dynamic_handicap_max;
+       }
+       return handicap;
+}
+
+//============================= Hooks ========================================
+
+REGISTER_MUTATOR(dynamic_handicap, autocvar_g_dynamic_handicap);
+
+MUTATOR_HOOKFUNCTION(dynamic_handicap, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":handicap");
+}
+
+MUTATOR_HOOKFUNCTION(dynamic_handicap, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Dynamic handicap");
+}
+
+MUTATOR_HOOKFUNCTION(dynamic_handicap, ClientDisconnect)
+{
+       DynamicHandicap_UpdateHandicap();
+}
+
+MUTATOR_HOOKFUNCTION(dynamic_handicap, PutClientInServer)
+{
+       DynamicHandicap_UpdateHandicap();
+}
+
+MUTATOR_HOOKFUNCTION(dynamic_handicap, MakePlayerObserver)
+{
+       DynamicHandicap_UpdateHandicap();
+}
+
+MUTATOR_HOOKFUNCTION(dynamic_handicap, AddedPlayerScore)
+{
+       if (M_ARGV(0, entity) != SP_SCORE)
+       {
+               return;
+       }
+       DynamicHandicap_UpdateHandicap();
+}
diff --git a/qcsrc/common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qh b/qcsrc/common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 4de24a5898c8b214afb2351ec70b786ee9848434..886740aedcea031e9d31632b17c3a47fb7937fa4 100644 (file)
@@ -142,26 +142,26 @@ void NIX_GiveCurrentWeapon(entity this)
                SetResourceAmount(this, RESOURCE_FUEL, 0);
                if(this.items & IT_UNLIMITED_WEAPON_AMMO)
                {
-                       switch(e.ammo_field)
+                       switch (e.ammo_type)
                        {
-                               case ammo_shells:  SetResourceAmount(this, RESOURCE_SHELLS, autocvar_g_pickup_shells_max);  break;
-                               case ammo_nails:   SetResourceAmount(this, RESOURCE_BULLETS, autocvar_g_pickup_nails_max);   break;
-                               case ammo_rockets: SetResourceAmount(this, RESOURCE_ROCKETS, autocvar_g_pickup_rockets_max); break;
-                               case ammo_cells:   SetResourceAmount(this, RESOURCE_CELLS, autocvar_g_pickup_cells_max);   break;
-                               case ammo_plasma:  SetResourceAmount(this, RESOURCE_PLASMA, autocvar_g_pickup_plasma_max);   break;
-                               case ammo_fuel:    SetResourceAmount(this, RESOURCE_FUEL, autocvar_g_pickup_fuel_max);    break;
+                               case RESOURCE_SHELLS:  SetResourceAmount(this, RESOURCE_SHELLS, autocvar_g_pickup_shells_max);  break;
+                               case RESOURCE_BULLETS: SetResourceAmount(this, RESOURCE_BULLETS, autocvar_g_pickup_nails_max);   break;
+                               case RESOURCE_ROCKETS: SetResourceAmount(this, RESOURCE_ROCKETS, autocvar_g_pickup_rockets_max); break;
+                               case RESOURCE_CELLS:   SetResourceAmount(this, RESOURCE_CELLS, autocvar_g_pickup_cells_max);   break;
+                               case RESOURCE_PLASMA:  SetResourceAmount(this, RESOURCE_PLASMA, autocvar_g_pickup_plasma_max);   break;
+                               case RESOURCE_FUEL:    SetResourceAmount(this, RESOURCE_FUEL, autocvar_g_pickup_fuel_max);    break;
                        }
                }
                else
                {
-                       switch(e.ammo_field)
+                       switch (e.ammo_type)
                        {
-                               case ammo_shells:  SetResourceAmount(this, RESOURCE_SHELLS, autocvar_g_balance_nix_ammo_shells);  break;
-                               case ammo_nails:   SetResourceAmount(this, RESOURCE_BULLETS, autocvar_g_balance_nix_ammo_nails);   break;
-                               case ammo_rockets: SetResourceAmount(this, RESOURCE_ROCKETS, autocvar_g_balance_nix_ammo_rockets); break;
-                               case ammo_cells:   SetResourceAmount(this, RESOURCE_CELLS, autocvar_g_balance_nix_ammo_cells);   break;
-                               case ammo_plasma:  SetResourceAmount(this, RESOURCE_PLASMA, autocvar_g_balance_nix_ammo_plasma);   break;
-                               case ammo_fuel:    SetResourceAmount(this, RESOURCE_FUEL, autocvar_g_balance_nix_ammo_fuel);    break;
+                               case RESOURCE_SHELLS:  SetResourceAmount(this, RESOURCE_SHELLS, autocvar_g_balance_nix_ammo_shells);  break;
+                               case RESOURCE_BULLETS: SetResourceAmount(this, RESOURCE_BULLETS, autocvar_g_balance_nix_ammo_nails);   break;
+                               case RESOURCE_ROCKETS: SetResourceAmount(this, RESOURCE_ROCKETS, autocvar_g_balance_nix_ammo_rockets); break;
+                               case RESOURCE_CELLS:   SetResourceAmount(this, RESOURCE_CELLS, autocvar_g_balance_nix_ammo_cells);   break;
+                               case RESOURCE_PLASMA:  SetResourceAmount(this, RESOURCE_PLASMA, autocvar_g_balance_nix_ammo_plasma);   break;
+                               case RESOURCE_FUEL:    SetResourceAmount(this, RESOURCE_FUEL, autocvar_g_balance_nix_ammo_fuel);    break;
                        }
                }
 
@@ -207,14 +207,14 @@ void NIX_GiveCurrentWeapon(entity this)
 
        if(!(this.items & IT_UNLIMITED_WEAPON_AMMO) && time > this.nix_nextincr)
        {
-               switch(e.ammo_field)
+               switch (e.ammo_type)
                {
-                       case ammo_shells:  GiveResource(this, RESOURCE_SHELLS, autocvar_g_balance_nix_ammoincr_shells);  break;
-                       case ammo_nails:   GiveResource(this, RESOURCE_BULLETS, autocvar_g_balance_nix_ammoincr_nails);   break;
-                       case ammo_rockets: GiveResource(this, RESOURCE_ROCKETS, autocvar_g_balance_nix_ammoincr_rockets); break;
-                       case ammo_cells:   GiveResource(this, RESOURCE_CELLS, autocvar_g_balance_nix_ammoincr_cells);   break;
-                       case ammo_plasma:  GiveResource(this, RESOURCE_PLASMA, autocvar_g_balance_nix_ammoincr_plasma);   break;
-                       case ammo_fuel:    GiveResource(this, RESOURCE_FUEL, autocvar_g_balance_nix_ammoincr_fuel);    break;
+                       case RESOURCE_SHELLS:  GiveResource(this, RESOURCE_SHELLS, autocvar_g_balance_nix_ammoincr_shells);  break;
+                       case RESOURCE_BULLETS: GiveResource(this, RESOURCE_BULLETS, autocvar_g_balance_nix_ammoincr_nails);   break;
+                       case RESOURCE_ROCKETS: GiveResource(this, RESOURCE_ROCKETS, autocvar_g_balance_nix_ammoincr_rockets); break;
+                       case RESOURCE_CELLS:   GiveResource(this, RESOURCE_CELLS, autocvar_g_balance_nix_ammoincr_cells);   break;
+                       case RESOURCE_PLASMA:  GiveResource(this, RESOURCE_PLASMA, autocvar_g_balance_nix_ammoincr_plasma);   break;
+                       case RESOURCE_FUEL:    GiveResource(this, RESOURCE_FUEL, autocvar_g_balance_nix_ammoincr_fuel);    break;
                }
 
                this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
index caf96a67b3fc7e11a7dad4b8a01d2587908e4eee..41327956f383b062deb21356e896170cb57c82f9 100644 (file)
@@ -83,7 +83,7 @@ METHOD(HeavyMachineGun, wr_think, void(entity thiswep, entity actor, .entity wea
 
 METHOD(HeavyMachineGun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float ammo_amount = actor.ammo_nails >= WEP_CVAR(hmg, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(hmg, ammo);
 
     if(autocvar_g_balance_hmg_reload_ammo)
         ammo_amount += actor.(weaponentity).(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
@@ -93,7 +93,7 @@ METHOD(HeavyMachineGun, wr_checkammo1, bool(entity thiswep, entity actor, .entit
 
 METHOD(HeavyMachineGun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float ammo_amount = actor.ammo_nails >= WEP_CVAR(hmg, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(hmg, ammo);
 
     if(autocvar_g_balance_hmg_reload_ammo)
         ammo_amount += actor.(weaponentity).(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
index 99eb4c8091f4d12ab72e674fdb5405be04ca0a95..07b31ea3cd107c6e9af918b749b17d2ac4c0673f 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(HeavyMachineGun, Weapon)
-/* ammotype  */ ATTRIB(HeavyMachineGun, ammo_field, .int, ammo_nails);
+/* ammotype  */ ATTRIB(HeavyMachineGun, ammo_type, int, RESOURCE_BULLETS);
 /* impulse   */ ATTRIB(HeavyMachineGun, impulse, int, 3);
 /* flags     */ ATTRIB(HeavyMachineGun, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_SUPERWEAPON);
 /* rating    */ ATTRIB(HeavyMachineGun, bot_pickupbasevalue, float, 10000);
index e9a5ce2c3fc01b3a39a0ab055234b5f23170b4fd..f901d11593d2951ccf0e542002be2d4230886f85 100644 (file)
@@ -140,7 +140,7 @@ METHOD(RocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, .en
 
 METHOD(RocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(rpc, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(rpc, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_RPC.m_id]) >= WEP_CVAR(rpc, ammo);
     return ammo_amount;
 }
index 417e9a6612883bd69363451566c6392f17dcecb8..560f7f4fa4313cdb68a2b69f1dc0306a696b96e0 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(RocketPropelledChainsaw, Weapon)
-/* ammotype  */ ATTRIB(RocketPropelledChainsaw, ammo_field, .int, ammo_rockets);
+/* ammotype  */ ATTRIB(RocketPropelledChainsaw, ammo_type, int, RESOURCE_ROCKETS);
 /* impulse   */ ATTRIB(RocketPropelledChainsaw, impulse, int, 9);
 /* flags     */ ATTRIB(RocketPropelledChainsaw, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH | WEP_FLAG_SUPERWEAPON);
 /* rating    */ ATTRIB(RocketPropelledChainsaw, bot_pickupbasevalue, float, 10000);
index cba6023bda8b10aadfcf99df8bdc8a47ffe22561..3b5492ac2d0adab12235d3512c13177e179b412b 100644 (file)
     MSG_INFO_NOTIF(WEAPON_CRYLINK_MURDER,                   N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponcrylink",            _("^BG%s%s^K1 felt the strong pull of ^BG%s^K1's Crylink%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_CRYLINK_SUICIDE,                  N_CONSOLE,  2, 1, "s1 s2loc spree_lost", "s1",                      "weaponcrylink",            _("^BG%s^K1 felt the strong pull of their Crylink%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_DEVASTATOR_MURDER_DIRECT,         N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponrocketlauncher",     _("^BG%s%s^K1 ate ^BG%s^K1's rocket%s%s"), "")
-    MSG_INFO_NOTIF(WEAPON_DEVASTATOR_MURDER_SPLASH,         N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponrocketlauncher",     _("^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"), "")
+    MSG_INFO_NOTIF(WEAPON_DEVASTATOR_MURDER_SPLASH,         N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponrocketlauncher",     _("^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_DEVASTATOR_SUICIDE,               N_CONSOLE,  2, 1, "s1 s2loc spree_lost", "s1",                      "weaponrocketlauncher",     _("^BG%s^K1 blew themself up with their Devastator%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_ELECTRO_MURDER_BOLT,              N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponelectro",            _("^BG%s%s^K1 was blasted by ^BG%s^K1's Electro bolt%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_ELECTRO_MURDER_COMBO,             N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponelectro",            _("^BG%s%s^K1 felt the electrifying air of ^BG%s^K1's Electro combo%s%s"), "")
index d8af629624b5e8ea10c22f7cc446681fb8346362..0fcd70dfc08fd8e7afd9bdc2cd2b31c063331c79 100644 (file)
@@ -93,7 +93,6 @@ void PlayerStats_GameReport_AddEvent(string event_id)
        }
 }
 
-// referred to by PS_GR_P_ADDVAL and PS_GR_T_ADDVAL
 float PlayerStats_GameReport_Event(string prefix, string event_id, float value)
 {
        if((prefix == "") || PS_GR_OUT_DB < 0) { return 0; }
@@ -108,7 +107,8 @@ float PlayerStats_GameReport_Event(string prefix, string event_id, float value)
 void PlayerStats_GameReport_Accuracy(entity p)
 {
        #define ACCMAC(suffix, field) \
-               PS_GR_P_ADDVAL(p, sprintf("acc-%s-%s", it.netname, suffix), CS(p).accuracy.(field[i-1]));
+               PlayerStats_GameReport_Event_Player(p, \
+                       sprintf("acc-%s-%s", it.netname, suffix), CS(p).accuracy.(field[i-1]));
        FOREACH(Weapons, it != WEP_Null, {
                ACCMAC("hit", accuracy_hit)
                ACCMAC("fired", accuracy_fired)
@@ -126,7 +126,7 @@ void PlayerStats_GameReport_FinalizePlayer(entity p)
        // add global info!
        if(p.alivetime)
        {
-               PS_GR_P_ADDVAL(p, PLAYERSTATS_ALIVETIME, time - p.alivetime);
+               PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_ALIVETIME, time - p.alivetime);
                p.alivetime = 0;
        }
 
@@ -139,7 +139,7 @@ void PlayerStats_GameReport_FinalizePlayer(entity p)
                db_put(PS_GR_OUT_DB, sprintf("%s:_team", p.playerstats_id), ftos(p.team));
 
        if(stof(db_get(PS_GR_OUT_DB, sprintf("%s:%s", p.playerstats_id, PLAYERSTATS_ALIVETIME))) > 0)
-               PS_GR_P_ADDVAL(p, PLAYERSTATS_JOINS, 1);
+               PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_JOINS, 1);
 
        PlayerStats_GameReport_Accuracy(p);
        anticheat_report_to_playerstats(p);
@@ -149,7 +149,8 @@ void PlayerStats_GameReport_FinalizePlayer(entity p)
                if(CS(p).latency_cnt)
                {
                        float latency = (CS(p).latency_sum / CS(p).latency_cnt);
-                       if(latency) { PS_GR_P_ADDVAL(p, PLAYERSTATS_AVGLATENCY, latency); }
+                       if(latency)
+                               PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_AVGLATENCY, latency);
                }
        }
 
@@ -167,16 +168,16 @@ void PlayerStats_GameReport(float finished)
 
        FOREACH_CLIENT(true, {
                // add personal score rank
-               PS_GR_P_ADDVAL(it, PLAYERSTATS_RANK, it.score_dummyfield);
+               PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_RANK, it.score_dummyfield);
 
                // scoreboard data
                if(it.scoreboard_pos)
                {
                        // scoreboard is valid!
-                       PS_GR_P_ADDVAL(it, PLAYERSTATS_SCOREBOARD_VALID, 1);
+                       PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_SCOREBOARD_VALID, 1);
 
                        // add scoreboard position
-                       PS_GR_P_ADDVAL(it, PLAYERSTATS_SCOREBOARD_POS, it.scoreboard_pos);
+                       PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_SCOREBOARD_POS, it.scoreboard_pos);
 
                        // add scoreboard data
                        PlayerScore_PlayerStats(it);
@@ -184,8 +185,8 @@ void PlayerStats_GameReport(float finished)
                        // if the match ended normally, add winning info
                        if(finished)
                        {
-                               PS_GR_P_ADDVAL(it, PLAYERSTATS_WINS, it.winning);
-                               PS_GR_P_ADDVAL(it, PLAYERSTATS_MATCHES, 1);
+                               PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_WINS, it.winning);
+                               PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_MATCHES, 1);
                        }
                }
 
index 1fafb13978dc9c43c1467ff3accb10089c55b6ad..28f985e27d24a214afc7519a956f70dd79526cef 100644 (file)
@@ -69,8 +69,8 @@ void PlayerStats_GameReport_AddTeam(float t);
 void PlayerStats_GameReport_AddEvent(string event_id);
 
 // call on each event to track, or at player disconnect OR match end for "global stuff"
-#define PS_GR_P_ADDVAL(ent,eventid,val) PlayerStats_GameReport_Event(ent.playerstats_id, eventid, val)
-#define PS_GR_T_ADDVAL(team,eventid,val) PlayerStats_GameReport_Event(sprintf("team#%d", team), eventid, val)
+#define PlayerStats_GameReport_Event_Player(ent, eventid, val) PlayerStats_GameReport_Event(ent.playerstats_id, eventid, val)
+#define PlayerStats_GameReport_Event_Team(team, eventid, val) PlayerStats_GameReport_Event(sprintf("team#%d", team), eventid, val)
 float PlayerStats_GameReport_Event(string prefix, string event_id, float value);
 
 void PlayerStats_GameReport_Accuracy(entity p);
diff --git a/qcsrc/common/resources.qh b/qcsrc/common/resources.qh
new file mode 100644 (file)
index 0000000..a562292
--- /dev/null
@@ -0,0 +1,20 @@
+#pragma once
+
+/// \file
+/// \brief Header file that describes resource types.
+/// \author Lyberta
+/// \copyright GNU GPLv2 or any later version.
+
+/// \brief Describes the available resource types.
+enum
+{
+       RESOURCE_NONE, ///< Indicates the lack of resource. Use with caution.
+       RESOURCE_HEALTH, ///< Health.
+       RESOURCE_ARMOR, ///< Armor.
+       RESOURCE_SHELLS, ///< Shells (used by shotgun).
+       RESOURCE_BULLETS, ///< Bullets (used by machinegun, rifle, HMG)
+       RESOURCE_ROCKETS, ///< Rockets (used by mortar, hagar, devastator, etc).
+       RESOURCE_CELLS, ///< Cells (used by electro, crylink, vortex, etc)
+       RESOURCE_PLASMA, ///< Plasma (unused).
+       RESOURCE_FUEL ///< Fuel (used by jetpack).
+};
index c116b440c42a4686ff8b034f0e3b800e2092c8fd..50ae0c336c51393ee61d7a14e70875588fd1d6e3 100644 (file)
@@ -682,6 +682,51 @@ void Item_ScheduleInitialRespawn(entity e)
        Item_ScheduleRespawnIn(e, max(0, game_starttime - time) + ((e.respawntimestart) ? e.respawntimestart : ITEM_RESPAWNTIME_INITIAL(e)));
 }
 
+void GiveRandomWeapons(entity receiver, int num_weapons, string weapon_names,
+       entity ammo_entity)
+{
+       if (num_weapons == 0)
+       {
+               return;
+       }
+       int num_potential_weapons = tokenize_console(weapon_names);
+       for (int give_attempt = 0; give_attempt < num_weapons; ++give_attempt)
+       {
+               RandomSelection_Init();
+               for (int weapon_index = 0; weapon_index < num_potential_weapons;
+                       ++weapon_index)
+               {
+                       string weapon = argv(weapon_index);
+                       FOREACH(Weapons, it != WEP_Null,
+                       {
+                               // Finding a weapon which player doesn't have.
+                               if (!(receiver.weapons & it.m_wepset) && (it.netname == weapon))
+                               {
+                                       RandomSelection_AddEnt(it, 1, 1);
+                                       break;
+                               }
+                       });
+               }
+               if (RandomSelection_chosen_ent == NULL)
+               {
+                       return;
+               }
+               receiver.weapons |= RandomSelection_chosen_ent.m_wepset;
+               if (RandomSelection_chosen_ent.ammo_type == RESOURCE_NONE)
+               {
+                       continue;
+               }
+               if (GetResourceAmount(receiver,
+                       RandomSelection_chosen_ent.ammo_type) != 0)
+               {
+                       continue;
+               }
+               GiveResource(receiver, RandomSelection_chosen_ent.ammo_type,
+                       GetResourceAmount(ammo_entity,
+                       RandomSelection_chosen_ent.ammo_type));
+       }
+}
+
 float Item_GiveAmmoTo(entity item, entity player, int resource_type, float ammomax)
 {
        float amount = GetResourceAmount(item, resource_type);
@@ -797,8 +842,6 @@ float Item_GiveTo(entity item, entity player)
                player.superweapons_finished = max(player.superweapons_finished, time) + item.superweapons_finished;
        }
 
-LABEL(skip)
-
        // always eat teamed entities
        if(item.team)
                pickedup = true;
@@ -1033,14 +1076,14 @@ float ammo_pickupevalfunc(entity player, entity item)
                        if(!(player.weapons & (it.m_wepset)))
                                continue;
 
-                       switch(it.ammo_field)
+                       switch(it.ammo_type)
                        {
-                               case ammo_shells:  need_shells  = true; break;
-                               case ammo_nails:   need_nails   = true; break;
-                               case ammo_rockets: need_rockets = true; break;
-                               case ammo_cells:   need_cells   = true; break;
-                               case ammo_plasma:  need_plasma  = true; break;
-                               case ammo_fuel:    need_fuel    = true; break;
+                               case RESOURCE_SHELLS:  need_shells  = true; break;
+                               case RESOURCE_BULLETS: need_nails   = true; break;
+                               case RESOURCE_ROCKETS: need_rockets = true; break;
+                               case RESOURCE_CELLS:   need_cells   = true; break;
+                               case RESOURCE_PLASMA:  need_plasma  = true; break;
+                               case RESOURCE_FUEL:    need_fuel    = true; break;
                        }
                });
                rating = item.bot_pickupbasevalue;
index fa78ff4b334ea9ede118f7817c81f02de9c0387d..80385971ab34d40a1ea17dbcc42e73714042aa9a 100644 (file)
@@ -84,6 +84,15 @@ void Item_ScheduleRespawn(entity e);
 
 void Item_ScheduleInitialRespawn(entity e);
 
+/// \brief Give several random weapons and ammo to the entity.
+/// \param[in,out] receiver Entity to give weapons to.
+/// \param[in] num_weapons Number of weapons to give.
+/// \param[in] weapon_names Names of weapons to give separated by spaces.
+/// \param[in] ammo Entity containing the ammo amount for each possible weapon.
+/// \return No return.
+void GiveRandomWeapons(entity receiver, int num_weapons, string weapon_names,
+       entity ammo_entity);
+
 float Item_GiveAmmoTo(entity item, entity player, int resource_type, float ammomax);
 
 float Item_GiveTo(entity item, entity player);
index 79c2feb4eab85b8115a0ddcd00270a26323d7c81..6e0c2b3a3119fd690aa4bc54ef3f2a2009883a47 100644 (file)
@@ -178,7 +178,7 @@ void func_breakable_behave_restore(entity this)
 
 void func_breakable_init_for_player(entity this, entity player)
 {
-       if (this.noise1 && this.state == 0 && clienttype(player) == CLIENTTYPE_REAL)
+       if (this.noise1 && this.state == 0 && IS_REAL_CLIENT(player))
        {
                msg_entity = player;
                soundto (MSG_ONE, this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
index dc0be6ae24a9822b67865e2c4a2cb0c6b0b32c6b..392ab3e5f5f46b883793a34745656298176606b5 100644 (file)
@@ -22,7 +22,7 @@ THINK FUNCTIONS
 */
 
 void door_go_down(entity this);
-void door_go_up(entity this);
+void door_go_up(entity this, entity actor, entity trigger);
 void door_rotating_go_down(entity this);
 void door_rotating_go_up(entity this, entity oth);
 
@@ -59,7 +59,7 @@ void door_blocked(entity this, entity blocker)
                                if (this.state == STATE_DOWN)
                        if (this.classname == "door")
                        {
-                               door_go_up (this);
+                               door_go_up (this, NULL, NULL);
                        } else
                        {
                                door_rotating_go_up(this, blocker);
@@ -123,7 +123,7 @@ void door_go_down(entity this)
        SUB_CalcMove (this, this.pos1, TSPEED_LINEAR, this.speed, door_hit_bottom);
 }
 
-void door_go_up(entity this)
+void door_go_up(entity this, entity actor, entity trigger)
 {
        if (this.state == STATE_UP)
                return;         // already going up
@@ -142,7 +142,7 @@ void door_go_up(entity this)
        string oldmessage;
        oldmessage = this.message;
        this.message = "";
-       SUB_UseTargets(this, NULL, NULL);
+       SUB_UseTargets(this, actor, trigger);
        this.message = oldmessage;
 }
 
@@ -237,7 +237,7 @@ void door_fire(entity this, entity actor, entity trigger)
        entity e = this;
        do {
                if (e.classname == "door") {
-                       door_go_up(e);
+                       door_go_up(e, actor, trigger);
                } else {
                        // if the BIDIR spawnflag (==2) is set and the trigger has set trigger_reverse, reverse the opening direction
                        if ((e.spawnflags & 2) && trigger.trigger_reverse!=0 && e.lip != 666 && e.state == STATE_BOTTOM) {
index 6605f00c26d2a2e48378f519f9a9fc86c314a7cb..e430ec2e78c252dea99cfc5c8fdfcc1a874bce8a 100644 (file)
@@ -210,48 +210,48 @@ void W_RandomWeapons(entity e, int n)
        e.weapons = result;
 }
 
-string GetAmmoPicture(.int ammotype)
+string GetAmmoPicture(int ammotype)
 {
        switch (ammotype)
        {
-               case ammo_shells:  return ITEM_Shells.m_icon;
-               case ammo_nails:   return ITEM_Bullets.m_icon;
-               case ammo_rockets: return ITEM_Rockets.m_icon;
-               case ammo_cells:   return ITEM_Cells.m_icon;
-               case ammo_plasma:  return ITEM_Plasma.m_icon;
-               case ammo_fuel:    return ITEM_JetpackFuel.m_icon;
+               case RESOURCE_SHELLS:  return ITEM_Shells.m_icon;
+               case RESOURCE_BULLETS: return ITEM_Bullets.m_icon;
+               case RESOURCE_ROCKETS: return ITEM_Rockets.m_icon;
+               case RESOURCE_CELLS:   return ITEM_Cells.m_icon;
+               case RESOURCE_PLASMA:  return ITEM_Plasma.m_icon;
+               case RESOURCE_FUEL:    return ITEM_JetpackFuel.m_icon;
                default: return "";  // wtf, no ammo type?
        }
 }
 
 #ifdef CSQC
-       .int GetAmmoFieldFromNum(int i)
+int GetAmmoTypeFromNum(int i)
+{
+       switch (i)
        {
-               switch (i)
-               {
-                       case 0: return ammo_shells;
-                       case 1: return ammo_nails;
-                       case 2: return ammo_rockets;
-                       case 3: return ammo_cells;
-                       case 4: return ammo_plasma;
-                       case 5: return ammo_fuel;
-                       default: return ammo_none;
-               }
+               case 0: return RESOURCE_SHELLS;
+               case 1: return RESOURCE_BULLETS;
+               case 2: return RESOURCE_ROCKETS;
+               case 3: return RESOURCE_CELLS;
+               case 4: return RESOURCE_PLASMA;
+               case 5: return RESOURCE_FUEL;
+               default: return RESOURCE_NONE;
        }
+}
 
-       int GetAmmoStat(.int ammotype)
+int GetAmmoStat(int ammotype)
+{
+       switch (ammotype)
        {
-               switch (ammotype)
-               {
-                       case ammo_shells: return STAT_SHELLS;
-                       case ammo_nails: return STAT_NAILS;
-                       case ammo_rockets: return STAT_ROCKETS;
-                       case ammo_cells: return STAT_CELLS;
-                       case ammo_plasma: return STAT_PLASMA.m_id;
-                       case ammo_fuel: return STAT_FUEL.m_id;
-                       default: return -1;
-               }
+               case RESOURCE_SHELLS: return STAT_SHELLS;
+               case RESOURCE_BULLETS: return STAT_NAILS;
+               case RESOURCE_ROCKETS: return STAT_ROCKETS;
+               case RESOURCE_CELLS: return STAT_CELLS;
+               case RESOURCE_PLASMA: return STAT_PLASMA.m_id;
+               case RESOURCE_FUEL: return STAT_FUEL.m_id;
+               default: return -1;
        }
+}
 #endif
 
 string W_Sound(string w_snd)
index 4be22446bf9dae2f8a314138be4e4b4fd4909426..71d7c3db39f464b975e9258764fa08676984eae5 100644 (file)
@@ -1,5 +1,6 @@
 #pragma once
 
+#include <common/resources.qh>
 #include <common/items/item/pickup.qh>
 #include <common/stats.qh>
 
@@ -59,8 +60,8 @@ CLASS(Weapon, Object)
        ATTRIB(Weapon, m_id, int, 0);
     /** A: WEPSET_id : WEPSET_... */
     ATTRIB(Weapon, weapons, WepSet, '0 0 0');
-    /** M: ammotype  : main ammo field */
-    ATTRIB(Weapon, ammo_field, .int, ammo_none);
+    /** M: ammotype  : main ammo type */
+    ATTRIB(Weapon, ammo_type, int, RESOURCE_NONE);
     /** M: impulse   : weapon impulse */
     ATTRIB(Weapon, impulse, int, -1);
     /** M: flags     : WEPSPAWNFLAG_... combined */
@@ -213,11 +214,11 @@ string W_FixWeaponOrder_AllowIncomplete(entity this, string order);
 string W_FixWeaponOrder_ForceComplete(string order);
 void W_RandomWeapons(entity e, int n);
 
-string GetAmmoPicture(.int ammotype);
+string GetAmmoPicture(int ammotype);
 
 #ifdef CSQC
-.int GetAmmoFieldFromNum(int i);
-int GetAmmoStat(.int ammotype);
+int GetAmmoTypeFromNum(int i);
+int GetAmmoStat(int ammotype);
 #endif
 
 string W_Sound(string w_snd);
index 47b92cc9f3a3819f27b6fff8bbb9be1f5496d664..5b982219e7cc6708dd0ba994b0e5d2501be34797 100644 (file)
@@ -258,8 +258,8 @@ void W_Arc_Beam_Think(entity this)
 
                if(rootammo)
                {
-                       coefficient = min(coefficient, own.(thiswep.ammo_field) / rootammo);
-                       own.(thiswep.ammo_field) = max(0, own.(thiswep.ammo_field) - (rootammo * frametime));
+                       coefficient = min(coefficient, GetResourceAmount(own, thiswep.ammo_type) / rootammo);
+                       SetResourceAmount(own, thiswep.ammo_type, max(0, GetResourceAmount(own, thiswep.ammo_type) - (rootammo * frametime)));
                }
        }
        float heat_speed = burst ? WEP_CVAR(arc, burst_heat) : WEP_CVAR(arc, beam_heat);
@@ -697,19 +697,19 @@ METHOD(Arc, wr_init, void(entity thiswep))
 }
 METHOD(Arc, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    return ((!WEP_CVAR(arc, beam_ammo)) || (actor.(thiswep.ammo_field) > 0));
+    return ((!WEP_CVAR(arc, beam_ammo)) || (GetResourceAmount(actor, thiswep.ammo_type) > 0));
 }
 METHOD(Arc, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
 {
     if(WEP_CVAR(arc, bolt))
     {
-        float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(arc, bolt_ammo);
+        float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(arc, bolt_ammo);
         ammo_amount += actor.(weaponentity).(weapon_load[WEP_ARC.m_id]) >= WEP_CVAR(arc, bolt_ammo);
         return ammo_amount;
     }
     else
         return WEP_CVAR(arc, overheat_max) > 0 &&
-            ((!WEP_CVAR(arc, burst_ammo)) || (actor.(thiswep.ammo_field) > 0));
+            ((!WEP_CVAR(arc, burst_ammo)) || (GetResourceAmount(actor, thiswep.ammo_type) > 0));
 }
 METHOD(Arc, wr_killmessage, Notification(entity thiswep))
 {
index 01c4f2f6a3cf7b8a71c5a5fbdd50e0ded97fe9df..abd9933116b2d86af3506acd6013b3648f6796f9 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Arc, Weapon)
-/* ammotype  */ ATTRIB(Arc, ammo_field, .int, ammo_cells);
+/* ammotype  */ ATTRIB(Arc, ammo_type, int, RESOURCE_CELLS);
 /* impulse   */ ATTRIB(Arc, impulse, int, 3);
 /* flags     */ ATTRIB(Arc, spawnflags, int, WEP_TYPE_HITSCAN);
 /* rating    */ ATTRIB(Arc, bot_pickupbasevalue, float, 8000);
index 990add96bd8f271fe30571b524b148ba38536245..972dcd003f23118654a332337c16904e93ca190d 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Blaster, Weapon)
-/* ammotype  */ //ATTRIB(Blaster, ammo_field, .int, ammo_none);
+/* ammotype  */ //ATTRIB(Blaster, ammo_type, int, RESOURCE_NONE);
 /* impulse   */ ATTRIB(Blaster, impulse, int, 1);
 /* flags     */ ATTRIB(Blaster, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
 /* rating    */ ATTRIB(Blaster, bot_pickupbasevalue, float, 0);
index 82b47037615e1d51cf6808e5ba55cf9fcb7a9493..2e2cb519af644ad83fa9133dc6f711227542b72f 100644 (file)
@@ -582,7 +582,7 @@ METHOD(Crylink, wr_checkammo1, bool(entity thiswep, entity actor, .entity weapon
     if(actor.(weaponentity).crylink_lastgroup && actor.(weaponentity).crylink_waitrelease)
         return true;
 
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(crylink, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(crylink, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_CRYLINK.m_id]) >= WEP_CVAR_PRI(crylink, ammo);
     return ammo_amount;
 }
@@ -592,7 +592,7 @@ METHOD(Crylink, wr_checkammo2, bool(entity thiswep, entity actor, .entity weapon
     if(actor.(weaponentity).crylink_lastgroup && actor.(weaponentity).crylink_waitrelease)
         return true;
 
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(crylink, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(crylink, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_CRYLINK.m_id]) >= WEP_CVAR_SEC(crylink, ammo);
     return ammo_amount;
 }
index 326fdf15bec0aa4d970b2b4f3264776868a23845..e686cfa94cf87cbaf962ba52ecf77fb52a69e520 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Crylink, Weapon)
-/* ammotype  */ ATTRIB(Crylink, ammo_field, .int, ammo_cells);
+/* ammotype  */ ATTRIB(Crylink, ammo_type, int, RESOURCE_CELLS);
 /* impulse   */ ATTRIB(Crylink, impulse, int, 6);
 /* flags     */ ATTRIB(Crylink, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH | WEP_FLAG_CANCLIMB | WEP_FLAG_NODUAL);
 /* rating    */ ATTRIB(Crylink, bot_pickupbasevalue, float, 6000);
index 88d50f80a021eb01dadb77cb867a4bd7a85611fa..f4ef7ad32c08b320d139348908b42e7c95cb54bb 100644 (file)
@@ -47,7 +47,7 @@ void W_Devastator_Explode(entity this, entity directhitentity)
        .entity weaponentity = this.weaponentity_fld;
        if(this.realowner.(weaponentity).m_weapon == thiswep)
        {
-               if(this.realowner.(thiswep.ammo_field) < WEP_CVAR(devastator, ammo))
+               if(GetResourceAmount(this.realowner, thiswep.ammo_type) < WEP_CVAR(devastator, ammo))
                if(!(this.realowner.items & IT_UNLIMITED_WEAPON_AMMO))
                {
                        this.realowner.cnt = WEP_DEVASTATOR.m_id;
@@ -139,7 +139,7 @@ void W_Devastator_DoRemoteExplode(entity this, .entity weaponentity)
        Weapon thiswep = WEP_DEVASTATOR;
        if(this.realowner.(weaponentity).m_weapon == thiswep)
        {
-               if(this.realowner.(thiswep.ammo_field) < WEP_CVAR(devastator, ammo))
+               if(GetResourceAmount(this.realowner, thiswep.ammo_type) < WEP_CVAR(devastator, ammo))
                if(!(this.realowner.items & IT_UNLIMITED_WEAPON_AMMO))
                {
                        this.realowner.cnt = WEP_DEVASTATOR.m_id;
@@ -478,10 +478,10 @@ METHOD(Devastator, wr_checkammo1, bool(entity thiswep, entity actor, .entity wea
         ammo_amount = false;
         if(WEP_CVAR(devastator, reload_ammo))
         {
-            if(actor.(thiswep.ammo_field) < WEP_CVAR(devastator, ammo) && actor.(weaponentity).(weapon_load[WEP_DEVASTATOR.m_id]) < WEP_CVAR(devastator, ammo))
+            if(GetResourceAmount(actor, thiswep.ammo_type) < WEP_CVAR(devastator, ammo) && actor.(weaponentity).(weapon_load[WEP_DEVASTATOR.m_id]) < WEP_CVAR(devastator, ammo))
                 ammo_amount = true;
         }
-        else if(actor.(thiswep.ammo_field) < WEP_CVAR(devastator, ammo))
+        else if(GetResourceAmount(actor, thiswep.ammo_type) < WEP_CVAR(devastator, ammo))
             ammo_amount = true;
         return !ammo_amount;
     }
@@ -489,18 +489,18 @@ METHOD(Devastator, wr_checkammo1, bool(entity thiswep, entity actor, .entity wea
     #if 0
     if(actor.rl_release == 0)
     {
-        LOG_INFOF("W_Devastator(WR_CHECKAMMO1): %d, %.2f, %d: TRUE", actor.rl_release, actor.(thiswep.ammo_field), WEP_CVAR(devastator, ammo));
+        LOG_INFOF("W_Devastator(WR_CHECKAMMO1): %d, %.2f, %d: TRUE", actor.rl_release, GetResourceAmount(actor, thiswep.ammo_type), WEP_CVAR(devastator, ammo));
         return true;
     }
     else
     {
-        ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(devastator, ammo);
+        ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(devastator, ammo);
         ammo_amount += actor.(weaponentity).(weapon_load[WEP_DEVASTATOR.m_id]) >= WEP_CVAR(devastator, ammo);
-        LOG_INFOF("W_Devastator(WR_CHECKAMMO1): %d, %.2f, %d: %s", actor.rl_release, actor.(thiswep.ammo_field), WEP_CVAR(devastator, ammo), (ammo_amount ? "TRUE" : "FALSE"));
+        LOG_INFOF("W_Devastator(WR_CHECKAMMO1): %d, %.2f, %d: %s", actor.rl_release, GetResourceAmount(actor, thiswep.ammo_type), WEP_CVAR(devastator, ammo), (ammo_amount ? "TRUE" : "FALSE"));
         return ammo_amount;
     }
     #else
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(devastator, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(devastator, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_DEVASTATOR.m_id]) >= WEP_CVAR(devastator, ammo);
     return ammo_amount;
     #endif
index dd68ccf58e3f6ad223ecc4b68a79366cebd98c3e..9c419751173120e17ba80911ea9aca37e9b30026 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Devastator, Weapon)
-/* ammotype  */ ATTRIB(Devastator, ammo_field, .int, ammo_rockets);
+/* ammotype  */ ATTRIB(Devastator, ammo_type, int, RESOURCE_ROCKETS);
 /* impulse   */ ATTRIB(Devastator, impulse, int, 9);
 /* flags     */ ATTRIB(Devastator, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH | WEP_FLAG_NODUAL);
 /* rating    */ ATTRIB(Devastator, bot_pickupbasevalue, float, 8000);
index f2fb14614004e9ef2982d5656753514ad7ecf016..8b3946e46e43d77b673b7023c89b3ab4c5afbf6c 100644 (file)
@@ -484,7 +484,7 @@ METHOD(Electro, wr_think, void(entity thiswep, entity actor, .entity weaponentit
 }
 METHOD(Electro, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(electro, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(electro, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_ELECTRO.m_id]) >= WEP_CVAR_PRI(electro, ammo);
     return ammo_amount;
 }
@@ -493,12 +493,12 @@ METHOD(Electro, wr_checkammo2, bool(entity thiswep, entity actor, .entity weapon
     float ammo_amount;
     if(WEP_CVAR(electro, combo_safeammocheck)) // true if you can fire at least one secondary blob AND one primary shot after it, otherwise false.
     {
-        ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(electro, ammo) + WEP_CVAR_PRI(electro, ammo);
+        ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(electro, ammo) + WEP_CVAR_PRI(electro, ammo);
         ammo_amount += actor.(weaponentity).(weapon_load[WEP_ELECTRO.m_id]) >= WEP_CVAR_SEC(electro, ammo) + WEP_CVAR_PRI(electro, ammo);
     }
     else
     {
-        ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(electro, ammo);
+        ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(electro, ammo);
         ammo_amount += actor.(weaponentity).(weapon_load[WEP_ELECTRO.m_id]) >= WEP_CVAR_SEC(electro, ammo);
     }
     return ammo_amount;
index 32b45c6928f2bb7faf1fe94919ef03260f7ce5fe..07c967c49bee20b1bb4d31b2f6c87801e3dac863 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Electro, Weapon)
-/* ammotype  */ ATTRIB(Electro, ammo_field, .int, ammo_cells);
+/* ammotype  */ ATTRIB(Electro, ammo_type, int, RESOURCE_CELLS);
 /* impulse   */ ATTRIB(Electro, impulse, int, 5);
 /* flags     */ ATTRIB(Electro, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
 /* rating    */ ATTRIB(Electro, bot_pickupbasevalue, float, 5000);
index d6d8f017edc9c0027726200f00a89b689f895321..e973d28845cee8ad52c995be9992a5ffd2da3667 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Fireball, Weapon)
-/* ammotype  */ //ATTRIB(Fireball, ammo_field, .int, ammo_none);
+/* ammotype  */ //ATTRIB(Fireball, ammo_type, int, RESOURCE_NONE);
 /* impulse   */ ATTRIB(Fireball, impulse, int, 9);
 /* flags     */ ATTRIB(Fireball, spawnflags, int, WEP_FLAG_SUPERWEAPON | WEP_TYPE_SPLASH | WEP_FLAG_NODUAL);
 /* rating    */ ATTRIB(Fireball, bot_pickupbasevalue, float, 5000);
index 5272e6060a8fdab0c417ab986c96898fe2097f07..be95d5dde2a3650367840715bf865565d1d69256 100644 (file)
@@ -270,7 +270,7 @@ void W_Hagar_Attack2_Load(Weapon thiswep, entity actor, .entity weaponentity)
        else if(autocvar_g_balance_hagar_reload_ammo)
                enough_ammo = actor.(weaponentity).(weapon_load[WEP_HAGAR.m_id]) >= WEP_CVAR_SEC(hagar, ammo);
        else
-               enough_ammo = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(hagar, ammo);
+               enough_ammo = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(hagar, ammo);
 
        bool stopped = loaded || !enough_ammo;
 
@@ -448,13 +448,13 @@ METHOD(Hagar, wr_setup, void(entity thiswep, entity actor, .entity weaponentity)
 }
 METHOD(Hagar, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(hagar, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(hagar, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_HAGAR.m_id]) >= WEP_CVAR_PRI(hagar, ammo);
     return ammo_amount;
 }
 METHOD(Hagar, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(hagar, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(hagar, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_HAGAR.m_id]) >= WEP_CVAR_SEC(hagar, ammo);
     return ammo_amount;
 }
index 7dfd3c6312541e47f4534f3af1cb756a3a5abbc6..24c700cc84d9412bf5362bd6d827656cda909d0f 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Hagar, Weapon)
-/* ammotype  */ ATTRIB(Hagar, ammo_field, .int, ammo_rockets);
+/* ammotype  */ ATTRIB(Hagar, ammo_type, int, RESOURCE_ROCKETS);
 /* impulse   */ ATTRIB(Hagar, impulse, int, 8);
 /* flags     */ ATTRIB(Hagar, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
 /* rating    */ ATTRIB(Hagar, bot_pickupbasevalue, float, 6000);
index 0193270a61e592108213e723afccba610d636e92..2fb16d6e35f0dd9a1c60ffc96a4034c22ff86596 100644 (file)
@@ -189,13 +189,13 @@ METHOD(HLAC, wr_think, void(entity thiswep, entity actor, .entity weaponentity,
 }
 METHOD(HLAC, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(hlac, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(hlac, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_HLAC.m_id]) >= WEP_CVAR_PRI(hlac, ammo);
     return ammo_amount;
 }
 METHOD(HLAC, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(hlac, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(hlac, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_HLAC.m_id]) >= WEP_CVAR_SEC(hlac, ammo);
     return ammo_amount;
 }
index f965abcbf79e62fac163c5f2c52dec2e98fb476e..4664e54d96776a7b02bc3ccdb7d34aa91ebc392c 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(HLAC, Weapon)
-/* ammotype  */ ATTRIB(HLAC, ammo_field, .int, ammo_cells);
+/* ammotype  */ ATTRIB(HLAC, ammo_type, int, RESOURCE_CELLS);
 /* impulse   */ ATTRIB(HLAC, impulse, int, 6);
 /* flags     */ ATTRIB(HLAC, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH);
 /* rating    */ ATTRIB(HLAC, bot_pickupbasevalue, float, 4000);
index f67db3d00d462ac141c52be86adc2d6879b49bdb..4988323fda187803dab6218b45002d4bede7bf90 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Hook, Weapon)
-/* ammotype  */ ATTRIB(Hook, ammo_field, .int, ammo_fuel);
+/* ammotype  */ ATTRIB(Hook, ammo_type, int, RESOURCE_FUEL);
 /* impulse   */ ATTRIB(Hook, impulse, int, 0);
 /* flags     */ ATTRIB(Hook, spawnflags, int, WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
 /* rating    */ ATTRIB(Hook, bot_pickupbasevalue, float, 0);
index c4f3b9bb3b29183bbcd25d0243eefdde0f5bec76..8d96c4b1013ca875a0d581408a335877c83c160a 100644 (file)
@@ -258,9 +258,9 @@ METHOD(MachineGun, wr_checkammo1, bool(entity thiswep, entity actor, .entity wea
 {
     float ammo_amount;
     if(WEP_CVAR(machinegun, mode) == 1)
-        ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(machinegun, sustained_ammo);
+        ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(machinegun, sustained_ammo);
     else
-        ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(machinegun, first_ammo);
+        ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(machinegun, first_ammo);
 
     if(WEP_CVAR(machinegun, reload_ammo))
     {
@@ -275,9 +275,9 @@ METHOD(MachineGun, wr_checkammo2, bool(entity thiswep, entity actor, .entity wea
 {
     float ammo_amount;
     if(WEP_CVAR(machinegun, mode) == 1)
-        ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(machinegun, burst_ammo);
+        ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(machinegun, burst_ammo);
     else
-        ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(machinegun, first_ammo);
+        ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(machinegun, first_ammo);
 
     if(WEP_CVAR(machinegun, reload_ammo))
     {
index 5cd912a2aef278f800a2c86cc2b578ef36037ef6..2f0974971ecc80112eb285e589801f88a074dc71 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(MachineGun, Weapon)
-/* ammotype  */ ATTRIB(MachineGun, ammo_field, .int, ammo_nails);
+/* ammotype  */ ATTRIB(MachineGun, ammo_type, int, RESOURCE_BULLETS);
 /* impulse   */ ATTRIB(MachineGun, impulse, int, 3);
 /* flags     */ ATTRIB(MachineGun, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_PENETRATEWALLS);
 /* rating    */ ATTRIB(MachineGun, bot_pickupbasevalue, float, 7000);
index 463f5109b918187ed45bfe6b41e66f1eb440af76..99b00a814f20ffbdb4d3d62507ba6ccff96f2e80 100644 (file)
@@ -453,7 +453,7 @@ METHOD(MineLayer, wr_think, void(entity thiswep, entity actor, .entity weaponent
     if(autocvar_g_balance_minelayer_reload_ammo && actor.(weaponentity).clip_load < WEP_CVAR(minelayer, ammo)) // forced reload
     {
         // not if we're holding the minelayer without enough ammo, but can detonate existing mines
-        if(!(W_MineLayer_PlacedMines(actor, weaponentity, false) && actor.(thiswep.ammo_field) < WEP_CVAR(minelayer, ammo))) {
+        if(!(W_MineLayer_PlacedMines(actor, weaponentity, false) && GetResourceAmount(actor, thiswep.ammo_type) < WEP_CVAR(minelayer, ammo))) {
             thiswep.wr_reload(thiswep, actor, weaponentity);
         }
     }
@@ -478,7 +478,7 @@ METHOD(MineLayer, wr_checkammo1, bool(entity thiswep, entity actor, .entity weap
     // actually do // don't switch while placing a mine
     //if(ATTACK_FINISHED(actor, slot) <= time || PS(actor).m_weapon != WEP_MINE_LAYER)
     //{
-        float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(minelayer, ammo);
+        float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(minelayer, ammo);
         ammo_amount += actor.(weaponentity).(weapon_load[WEP_MINE_LAYER.m_id]) >= WEP_CVAR(minelayer, ammo);
         return ammo_amount;
     //}
index e867db8d31634764f5f459f8df028f346535b478..f113e6439e3bea5f42d569e36d86482ff9b9ffe2 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(MineLayer, Weapon)
-/* ammotype  */ ATTRIB(MineLayer, ammo_field, .int, ammo_rockets);
+/* ammotype  */ ATTRIB(MineLayer, ammo_type, int, RESOURCE_ROCKETS);
 /* impulse   */ ATTRIB(MineLayer, impulse, int, 4);
 /* flags     */ ATTRIB(MineLayer, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH);
 /* rating    */ ATTRIB(MineLayer, bot_pickupbasevalue, float, 7000);
index 186d1f139d3f52de758e69e0bdd5360c5e4fc7e3..6a3d2e1250a63294e400a4a283e850fef651eb6e 100644 (file)
@@ -325,13 +325,13 @@ METHOD(Mortar, wr_think, void(entity thiswep, entity actor, .entity weaponentity
 }
 METHOD(Mortar, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(mortar, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(mortar, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_MORTAR.m_id]) >= WEP_CVAR_PRI(mortar, ammo);
     return ammo_amount;
 }
 METHOD(Mortar, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(mortar, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(mortar, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_MORTAR.m_id]) >= WEP_CVAR_SEC(mortar, ammo);
     return ammo_amount;
 }
index 58b526b8ec4eddf58e3804ceb4dd5277c9978688..4fc5ec9ad2995644c9a72c1f3d268be874f39edf 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Mortar, Weapon)
-/* ammotype  */ ATTRIB(Mortar, ammo_field, .int, ammo_rockets);
+/* ammotype  */ ATTRIB(Mortar, ammo_type, int, RESOURCE_ROCKETS);
 /* impulse   */ ATTRIB(Mortar, impulse, int, 4);
 /* flags     */ ATTRIB(Mortar, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
 /* rating    */ ATTRIB(Mortar, bot_pickupbasevalue, float, 7000);
index 94c6e165c587f0f095740339c3e8e30d90e23bfe..b46e479aa9f383292498a75e9672cda2013786b4 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(PortoLaunch, Weapon)
-/* ammotype  */ ATTRIB(PortoLaunch, ammo_field, .int, ammo_none);
+/* ammotype  */ ATTRIB(PortoLaunch, ammo_type, int, RESOURCE_NONE);
 /* impulse   */ ATTRIB(PortoLaunch, impulse, int, 0);
 /* flags     */ ATTRIB(PortoLaunch, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_SUPERWEAPON | WEP_FLAG_NODUAL);
 /* rating    */ ATTRIB(PortoLaunch, bot_pickupbasevalue, float, 0);
index 92694e2e2248570b9bcc8ebd878bd8569c23aa83..54784251281c0b488c4867123984548e060ae028 100644 (file)
@@ -150,13 +150,13 @@ METHOD(Rifle, wr_think, void(entity thiswep, entity actor, .entity weaponentity,
 }
 METHOD(Rifle, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(rifle, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(rifle, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_RIFLE.m_id]) >= WEP_CVAR_PRI(rifle, ammo);
     return ammo_amount;
 }
 METHOD(Rifle, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(rifle, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(rifle, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_RIFLE.m_id]) >= WEP_CVAR_SEC(rifle, ammo);
     return ammo_amount;
 }
index ed5496f050f28cb841949a0937ebd4a279c589d6..b1c01b86ff861238a106b1d03a2b8dad77d8e55a 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Rifle, Weapon)
-/* ammotype  */ ATTRIB(Rifle, ammo_field, .int, ammo_nails);
+/* ammotype  */ ATTRIB(Rifle, ammo_type, int, RESOURCE_BULLETS);
 /* impulse   */ ATTRIB(Rifle, impulse, int, 7);
 /* flags     */ ATTRIB(Rifle, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_PENETRATEWALLS);
 /* rating    */ ATTRIB(Rifle, bot_pickupbasevalue, float, 7000);
index 35b48b8ea03159e9a40b448bda4be2103e794a2c..b2df4f0efb54c53e5b951f9c874e3ce651b4b25e 100644 (file)
@@ -348,7 +348,7 @@ void W_Seeker_Vollycontroller_Think(entity this) // TODO: Merge this with W_Seek
 
        Weapon thiswep = WEP_SEEKER;
        .entity weaponentity = this.weaponentity_fld;
-       if((!(this.realowner.items & IT_UNLIMITED_AMMO) && this.realowner.(thiswep.ammo_field) < WEP_CVAR(seeker, missile_ammo)) || (this.cnt <= -1) || (IS_DEAD(this.realowner)) || (this.realowner.(weaponentity).m_switchweapon != WEP_SEEKER))
+       if((!(this.realowner.items & IT_UNLIMITED_AMMO) && GetResourceAmount(this.realowner, thiswep.ammo_type) < WEP_CVAR(seeker, missile_ammo)) || (this.cnt <= -1) || (IS_DEAD(this.realowner)) || (this.realowner.(weaponentity).m_switchweapon != WEP_SEEKER))
        {
                delete(this);
                return;
@@ -589,12 +589,12 @@ METHOD(Seeker, wr_checkammo1, bool(entity thiswep, entity actor, .entity weapone
     float ammo_amount;
     if(WEP_CVAR(seeker, type) == 1)
     {
-        ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(seeker, missile_ammo);
+        ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(seeker, missile_ammo);
         ammo_amount += actor.(weaponentity).(weapon_load[WEP_SEEKER.m_id]) >= WEP_CVAR(seeker, missile_ammo);
     }
     else
     {
-        ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(seeker, tag_ammo);
+        ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(seeker, tag_ammo);
         ammo_amount += actor.(weaponentity).(weapon_load[WEP_SEEKER.m_id]) >= WEP_CVAR(seeker, tag_ammo);
     }
     return ammo_amount;
@@ -604,12 +604,12 @@ METHOD(Seeker, wr_checkammo2, bool(entity thiswep, entity actor, .entity weapone
     float ammo_amount;
     if(WEP_CVAR(seeker, type) == 1)
     {
-        ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(seeker, tag_ammo);
+        ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(seeker, tag_ammo);
         ammo_amount += actor.(weaponentity).(weapon_load[WEP_SEEKER.m_id]) >= WEP_CVAR(seeker, tag_ammo);
     }
     else
     {
-        ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(seeker, flac_ammo);
+        ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(seeker, flac_ammo);
         ammo_amount += actor.(weaponentity).(weapon_load[WEP_SEEKER.m_id]) >= WEP_CVAR(seeker, flac_ammo);
     }
     return ammo_amount;
index 04567d1b9a583083e5cfa3dec19a804eaef7adcb..443d0843d01b3e1fea2bba4ba9d11a4cc182ba4d 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Seeker, Weapon)
-/* ammotype  */ ATTRIB(Seeker, ammo_field, .int, ammo_rockets);
+/* ammotype  */ ATTRIB(Seeker, ammo_type, int, RESOURCE_ROCKETS);
 /* impulse   */ ATTRIB(Seeker, impulse, int, 8);
 /* flags     */ ATTRIB(Seeker, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH);
 /* rating    */ ATTRIB(Seeker, bot_pickupbasevalue, float, 5000);
index f863094c00f54582d8cf7a088adb04f33c5e27a3..89685376dad9a6fd52b6b61f966fdbe2d35ba7ac 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Shockwave, Weapon)
-/* ammotype  */ //ATTRIB(Shockwave, ammo_field, .int, ammo_none);
+/* ammotype  */ //ATTRIB(Shockwave, ammo_type, int, RESOURCE_NONE);
 /* impulse   */ ATTRIB(Shockwave, impulse, int, 2);
 /* flags     */ ATTRIB(Shockwave, spawnflags, int, WEP_TYPE_HITSCAN | WEP_FLAG_CANCLIMB | WEP_TYPE_MELEE_SEC);
 /* rating    */ ATTRIB(Shockwave, bot_pickupbasevalue, float, 3000);
index 3644c1357e3fa2517d7a6de28832c14f2de0c394..e163df4bc61d1958c0ff203bbd8937005abaddef 100644 (file)
@@ -216,7 +216,7 @@ METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, .entity weaponentit
     }
     if(actor.(weaponentity).clip_load >= 0) // we are not currently reloading
     if(WEP_CVAR(shotgun, secondary) == 1)
-    if(((fire & 1) && actor.(thiswep.ammo_field) <= 0 && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || (fire & 2))
+    if(((fire & 1) && GetResourceAmount(actor, thiswep.ammo_type) <= 0 && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || (fire & 2))
     if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(shotgun, refire)))
     {
         // attempt forcing playback of the anim by switching to another anim (that we never play) here...
@@ -225,7 +225,7 @@ METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, .entity weaponentit
 }
 METHOD(Shotgun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(shotgun, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(shotgun, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_SHOTGUN.m_id]) >= WEP_CVAR_PRI(shotgun, ammo);
     return ammo_amount;
 }
@@ -239,7 +239,7 @@ METHOD(Shotgun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weapon
         case 1: return true; // melee does not use ammo
         case 2: // secondary triple shot
         {
-            float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(shotgun, ammo);
+            float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(shotgun, ammo);
             ammo_amount += actor.(weaponentity).(weapon_load[WEP_SHOTGUN.m_id]) >= WEP_CVAR_PRI(shotgun, ammo);
             return ammo_amount;
         }
index 2fd734d554b2ddb6dc43aa11042e41abbd02ae20..cd646a768f456aa2c74c9bdf8dda6f909ef8b305 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Shotgun, Weapon)
-/* ammotype  */ ATTRIB(Shotgun, ammo_field, .int, ammo_shells);
+/* ammotype  */ ATTRIB(Shotgun, ammo_type, int, RESOURCE_SHELLS);
 /* impulse   */ ATTRIB(Shotgun, impulse, int, 2);
 /* flags     */ ATTRIB(Shotgun, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_TYPE_MELEE_SEC);
 /* rating    */ ATTRIB(Shotgun, bot_pickupbasevalue, float, 6000);
index e47f8fa909565a3734188c1f57d376cc1d1a5899..73822b4c50fcbecad3a12f3189253ee4df03054c 100644 (file)
@@ -291,7 +291,7 @@ void W_RocketMinsta_Attack3 (entity actor, .entity weaponentity)
 
 METHOD(Vaporizer, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
 {
-    if(actor.(thiswep.ammo_field) > 0)
+    if(GetResourceAmount(actor, thiswep.ammo_type) > 0)
         PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 1, false);
     else
         PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR_SEC(vaporizer, speed), 0, WEP_CVAR_SEC(vaporizer, lifetime), false); // WEAPONTODO: replace with proper vaporizer cvars
@@ -378,7 +378,7 @@ METHOD(Vaporizer, wr_setup, void(entity thiswep, entity actor, .entity weaponent
 METHOD(Vaporizer, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
 {
     float vaporizer_ammo = ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo));
-    float ammo_amount = actor.(thiswep.ammo_field) >= vaporizer_ammo;
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= vaporizer_ammo;
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_VAPORIZER.m_id]) >= vaporizer_ammo;
     return ammo_amount;
 }
@@ -386,7 +386,7 @@ METHOD(Vaporizer, wr_checkammo2, bool(entity thiswep, entity actor, .entity weap
 {
     if(!WEP_CVAR_SEC(vaporizer, ammo))
         return true;
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(vaporizer, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(vaporizer, ammo);
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_VAPORIZER.m_id]) >= WEP_CVAR_SEC(vaporizer, ammo);
     return ammo_amount;
 }
index f0b144341d538d1f24d39f47a43990b4e1be5e98..0c5c19200a437d67a063ffe58fd43785557bcafc 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Vaporizer, Weapon)
-/* ammotype  */ ATTRIB(Vaporizer, ammo_field, .int, ammo_cells);
+/* ammotype  */ ATTRIB(Vaporizer, ammo_type, int, RESOURCE_CELLS);
 /* impulse   */ ATTRIB(Vaporizer, impulse, int, 7);
 /* flags     */ ATTRIB(Vaporizer, spawnflags, int, WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_FLAG_SUPERWEAPON | WEP_TYPE_HITSCAN | WEP_FLAG_NODUAL);
 /* rating    */ ATTRIB(Vaporizer, bot_pickupbasevalue, float, 10000);
index 454cb8bfba1b3cb53d59bbb7ced9081fc265c5b5..202780e29afc4d982400df3cd2ee3ad98fa43f5b 100644 (file)
@@ -241,11 +241,11 @@ METHOD(Vortex, wr_think, void(entity thiswep, entity actor, .entity weaponentity
                                 }
                                 else
                                 {
-                                    dt = min(dt, (actor.(thiswep.ammo_field) - WEP_CVAR_PRI(vortex, ammo)) / WEP_CVAR_SEC(vortex, ammo));
+                                    dt = min(dt, (GetResourceAmount(actor, thiswep.ammo_type) - WEP_CVAR_PRI(vortex, ammo)) / WEP_CVAR_SEC(vortex, ammo));
                                     dt = max(0, dt);
                                     if(dt > 0)
                                     {
-                                        actor.(thiswep.ammo_field) = max(WEP_CVAR_SEC(vortex, ammo), actor.(thiswep.ammo_field) - WEP_CVAR_SEC(vortex, ammo) * dt);
+                                        SetResourceAmount(actor, thiswep.ammo_type, max(WEP_CVAR_SEC(vortex, ammo), GetResourceAmount(actor, thiswep.ammo_type) - WEP_CVAR_SEC(vortex, ammo) * dt));
                                     }
                                 }
                             }
@@ -277,7 +277,7 @@ METHOD(Vortex, wr_setup, void(entity thiswep, entity actor, .entity weaponentity
 }
 METHOD(Vortex, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(vortex, ammo);
+    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(vortex, ammo);
     ammo_amount += (autocvar_g_balance_vortex_reload_ammo && actor.(weaponentity).(weapon_load[WEP_VORTEX.m_id]) >= WEP_CVAR_PRI(vortex, ammo));
     return ammo_amount;
 }
@@ -286,7 +286,7 @@ METHOD(Vortex, wr_checkammo2, bool(entity thiswep, entity actor, .entity weapone
     if(WEP_CVAR(vortex, secondary))
     {
         // don't allow charging if we don't have enough ammo
-        float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(vortex, ammo);
+        float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(vortex, ammo);
         ammo_amount += actor.(weaponentity).(weapon_load[WEP_VORTEX.m_id]) >= WEP_CVAR_SEC(vortex, ammo);
         return ammo_amount;
     }
index 81ab7e6209d4389d9f8eac7765866623ab51e7c6..5a41b90d8efede1e64457ac4001c09c86ea9b7b1 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(Vortex, Weapon)
-/* ammotype  */ ATTRIB(Vortex, ammo_field, .int, ammo_cells);
+/* ammotype  */ ATTRIB(Vortex, ammo_type, int, RESOURCE_CELLS);
 /* impulse   */ ATTRIB(Vortex, impulse, int, 7);
 /* flags     */ ATTRIB(Vortex, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_NODUAL);
 /* rating    */ ATTRIB(Vortex, bot_pickupbasevalue, float, 8000);
index c20ae8bda2065a58ffd01176ae3ebbe5aa4412f1..6731bdf9433b7e228481237974e79a020334ddfa 100644 (file)
@@ -64,7 +64,9 @@ void sys_phys_spectator_control(entity this)
                            || CS(this).impulse == 15
                            || CS(this).impulse == 18
                            || (CS(this).impulse >= 200 && CS(this).impulse <= 209)
-                          ) { this.spectatorspeed = bound(1, this.spectatorspeed + 0.5, 5); } else if (CS(this).impulse == 11) {
+                          ) {
+                               this.spectatorspeed = bound(1, this.spectatorspeed + 0.5, 5);
+                       } else if (CS(this).impulse == 11) {
                                this.spectatorspeed = maxspeed_mod;
                        } else if (CS(this).impulse == 12
                            || CS(this).impulse == 16
index 9d582091039faa12ac2028efeb9022357be3a631..d44c5e89cdda2acacbd1b615bfbc55dc8bb93b9f 100644 (file)
@@ -241,7 +241,8 @@ void make_safe_for_remove(entity this);
        void SV_OnEntityPreSpawnFunction()
        {
                ENGINE_EVENT();
-               if (_SV_OnEntityPreSpawnFunction) _SV_OnEntityPreSpawnFunction(this);
+               __spawnfunc_expecting = true;
+               __spawnfunc_expect = this;
        }
        #define SV_OnEntityPreSpawnFunction _SV_OnEntityPreSpawnFunction
 
index 4638bca2d490544d8881d0e1507cfe048c7f7607..884714e3596928e9ef334c5d0efd711d21e76cf4 100644 (file)
@@ -36,6 +36,10 @@ noref bool require_spawnfunc_prefix;
 
     #define SPAWNFUNC_INTERNAL_FIELDS(X) \
         X(string, classname, "spawnfunc") \
+        X(string, target, string_null) \
+        X(string, target2, string_null) \
+        X(string, target3, string_null) \
+        X(string, target4, string_null) \
         X(string, targetname, string_null) \
         /**/
 
@@ -57,7 +61,9 @@ noref bool require_spawnfunc_prefix;
         g_map_entities = IL_NEW(); \
         IL_EACH(g_spawn_queue, true, __spawnfunc_spawn(it)); \
     MACRO_END
-
+#ifdef SVQC
+    void _SV_OnEntityPreSpawnFunction(entity this);
+#endif
     void __spawnfunc_spawn(entity prototype)
     {
         entity e = new(clone);
@@ -66,6 +72,12 @@ noref bool require_spawnfunc_prefix;
         #define X(T, fld, def) { e.fld = e.__spawnfunc_##fld; e.__spawnfunc_##fld = def; }
         SPAWNFUNC_INTERNAL_FIELDS(X);
         #undef X
+#ifdef SVQC
+        _SV_OnEntityPreSpawnFunction(e);
+        if (wasfreed(e)) {
+            return;
+        }
+#endif
         e.__spawnfunc_constructor(e);
     }
 
index b05a316c94a2a4d6b438420d000ce7242f506f19..0a3fb085c1d5fb988298073071745b829578cb3d 100644 (file)
@@ -256,6 +256,7 @@ int u8_strsize(string s)
        return l;
 }
 
+//List of Unicode spaces: https://www.cs.tut.fi/~jkorpela/chars/spaces.html
 ERASEABLE
 bool isInvisibleString(string s)
 {
@@ -272,8 +273,26 @@ bool isInvisibleString(string s)
                        case 192:          // charmap space
                                if (!utf8) break;
                                return false;
-                       case 160:          // space in unicode fonts
                        case 0xE000 + 192: // utf8 charmap space
+                       case 0x00A0: // NO-BREAK SPACE
+                       //case 0x1680: // OGHAM SPACE MARK
+                       case 0x180E: // MONGOLIAN VOWEL SEPARATOR
+                       case 0x2000: // EN QUAD
+                       case 0x2001: // EM QUAD
+                       case 0x2002: // EN SPACE
+                       case 0x2003: // EM SPACE
+                       case 0x2004: // THREE-PER-EM SPACE
+                       case 0x2005: // FOUR-PER-EM SPACE
+                       case 0x2006: // SIX-PER-EM SPACE
+                       case 0x2007: // FIGURE SPACE
+                       case 0x2008: // PUNCTUATION SPACE
+                       case 0x2009: // THIN SPACE
+                       case 0x200A: // HAIR SPACE
+                       case 0x200B: // ZERO WIDTH SPACE
+                       case 0x202F: // NARROW NO-BREAK SPACE
+                       case 0x205F: // MEDIUM MATHEMATICAL SPACE
+                       case 0x3000: // IDEOGRAPHIC SPACE
+                       case 0xFEFF: // ZERO WIDTH NO-BREAK SPACE
                                if (utf8) break;
                        default:
                                return false;
index 99115fbdc4fcaa48d2b3b33f8aca6458d530d718..de7e01aa7a862d3f328d0c02a3fdd542e5238ad9 100644 (file)
@@ -10,6 +10,7 @@
 #include <server/g_models.qc>
 #include <server/g_subs.qc>
 #include <server/g_world.qc>
+#include <server/handicap.qc>
 #include <server/impulse.qc>
 #include <server/ipban.qc>
 #include <server/item_key.qc>
index 3a8898670354511f40a1e515d25aeae0d5b28068..67f6aae4db511fd7cb1b91cb1cdb7412c7f017ea 100644 (file)
@@ -10,6 +10,7 @@
 #include <server/g_models.qh>
 #include <server/g_subs.qh>
 #include <server/g_world.qh>
+#include <server/handicap.qh>
 #include <server/impulse.qh>
 #include <server/ipban.qh>
 #include <server/item_key.qh>
index 7173ae5970721388811a5f639476540732851b54..9327a203416598b10e37229d7909f3e34f0eb86d 100644 (file)
@@ -202,9 +202,10 @@ void anticheat_report_to_eventlog(entity this) {
 }
 
 void anticheat_report_to_playerstats(entity this) {
-       PS_GR_P_ADDVAL(this, strcat(PLAYERSTATS_ANTICHEAT, "_time"), servertime - CS(this).anticheat_jointime);
+       PlayerStats_GameReport_Event_Player(this,
+               strcat(PLAYERSTATS_ANTICHEAT, "_time"), servertime - CS(this).anticheat_jointime);
 #define ANTICHEAT_REPORT_ONE(name, f, tmin, mi, ma) \
-       PS_GR_P_ADDVAL(this, strcat(PLAYERSTATS_ANTICHEAT, name), f)
+       PlayerStats_GameReport_Event_Player(this, strcat(PLAYERSTATS_ANTICHEAT, name), f)
        ANTICHEATS(ANTICHEAT_REPORT_ONE);
 #undef ANTICHEAT_REPORT_ONE
 }
index 6a978c6aebe631eef3c51e8016815a7697a24a93..4f7dd14a54da6040d8bc1c93965c515b8a37d049 100644 (file)
@@ -14,6 +14,7 @@
 #include "spawnpoints.qh"
 #include "resources.qh"
 #include "g_damage.qh"
+#include "handicap.qh"
 #include "g_hook.qh"
 #include "command/common.qh"
 #include "cheats.qh"
@@ -219,9 +220,20 @@ void PutObserverInServer(entity this)
     bool mutator_returnvalue = MUTATOR_CALLHOOK(MakePlayerObserver, this);
        PlayerState_detach(this);
 
-       if (IS_PLAYER(this) && this.health >= 1) {
-        // despawn effect
-               Send_Effect(EFFECT_SPAWN_NEUTRAL, this.origin, '0 0 0', 1);
+       if (IS_PLAYER(this))
+       {
+               if(this.health >= 1)
+               {
+                       // despawn effect
+                       Send_Effect(EFFECT_SPAWN_NEUTRAL, this.origin, '0 0 0', 1);
+               }
+
+               // was a player, recount votes and ready status
+               if(IS_REAL_CLIENT(this))
+               {
+                       if (vote_called) { VoteCount(false); }
+                       ReadyCount();
+               }
     }
 
     {
@@ -258,7 +270,7 @@ void PutObserverInServer(entity this)
        if (this.alivetime)
        {
                if (!warmup_stage)
-                       PS_GR_P_ADDVAL(this, PLAYERSTATS_ALIVETIME, time - this.alivetime);
+                       PlayerStats_GameReport_Event_Player(this, PLAYERSTATS_ALIVETIME, time - this.alivetime);
                this.alivetime = 0;
        }
 
@@ -525,7 +537,6 @@ void PutPlayerInServer(entity this)
                this.flags |= FL_NOTARGET;
        this.takedamage = DAMAGE_AIM;
        this.effects = EF_TELEPORT_BIT | EF_RESTARTANIM_BIT;
-       this.dmg = 2; // WTF
 
        if (warmup_stage) {
                this.ammo_shells = warmup_start_ammo_shells;
@@ -547,6 +558,8 @@ void PutPlayerInServer(entity this)
                this.health = start_health;
                this.armorvalue = start_armorvalue;
                this.weapons = start_weapons;
+               GiveRandomWeapons(this, random_start_weapons_count,
+                       autocvar_g_random_start_weapons, random_start_ammo);
        }
        SetSpectatee_status(this, 0);
 
@@ -1204,8 +1217,6 @@ void ClientConnect(entity this)
 
        CS(this).just_joined = true;  // stop spamming the eventlog with additional lines when the client connects
 
-       CS(this).netname_previous = strzone(this.netname);
-
        if(teamplay && IS_PLAYER(this))
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_JOIN_CONNECT_TEAM), this.netname);
        else
@@ -1272,6 +1283,8 @@ void ClientConnect(entity this)
                it.init_for_player(it, this);
        });
 
+       Handicap_Initialize(this);
+
        MUTATOR_CALLHOOK(ClientConnect, this);
 
        if (IS_REAL_CLIENT(this))
@@ -2479,19 +2492,22 @@ void PlayerPreThink (entity this)
                // WORKAROUND: only use dropclient in server frames (frametime set).
                // Never use it in cl_movement frames (frametime zero).
                checkSpectatorBlock(this);
-    }
+       }
 
        zoomstate_set = false;
 
        // Check for nameless players
-       if (isInvisibleString(this.netname)) {
-               this.netname = strzone(sprintf("Player#%d", this.playerid));
-               // stuffcmd(this, strcat("name ", this.netname, "\n")); // maybe?
-       }
-       if (this.netname != CS(this).netname_previous) {
-               if (autocvar_sv_eventlog) {
+       if (this.netname == "" || this.netname != CS(this).netname_previous)
+       {
+               bool assume_unchanged = (CS(this).netname_previous == "");
+               if (isInvisibleString(this.netname))
+               {
+                       this.netname = strzone(sprintf("Player#%d", this.playerid));
+                       assume_unchanged = false;
+                       // stuffcmd(this, strcat("name ", this.netname, "\n")); // maybe?
+               }
+               if (!assume_unchanged && autocvar_sv_eventlog)
                        GameLogEcho(strcat(":name:", ftos(this.playerid), ":", playername(this, false)));
-        }
                if (CS(this).netname_previous) strunzone(CS(this).netname_previous);
                CS(this).netname_previous = strzone(this.netname);
        }
@@ -2650,7 +2666,6 @@ void DrownPlayer(entity this)
                if(this.air_finished < time)
                        PlayerSound(this, playersound_gasp, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND);
                this.air_finished = time + autocvar_g_balance_contents_drowndelay;
-               this.dmg = 2;
        }
        else if (this.air_finished < time)
        {       // drown!
index 1a786cc7fe7891631c567af18cc817345105853c..1a826c6f142daf0164d83a7a27f59b37c09d9820 100644 (file)
@@ -430,7 +430,8 @@ void ReadyRestart_force()
        FOREACH_CLIENT(IS_PLAYER(it), {
                it.alivetime = 0;
                CS(it).killcount = 0;
-               PS_GR_P_ADDVAL(it, PLAYERSTATS_ALIVETIME, -PS_GR_P_ADDVAL(it, PLAYERSTATS_ALIVETIME, 0));
+               float val = PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_ALIVETIME, 0);
+               PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_ALIVETIME, -val);
        });
 
        restart_mapalreadyrestarted = false; // reset this var, needed when cvar sv_ready_restart_repeatable is in use
@@ -649,20 +650,11 @@ float VoteCommand_checkargs(float startpos, float argc)
 
 int VoteCommand_parse(entity caller, string vote_command, string vote_list, float startpos, float argc)
 {
-       string first_command;
+       string first_command = argv(startpos);
+       int missing_chars = argv_start_index(startpos);
 
-       first_command = argv(startpos);
-
-       /*printf("VoteCommand_parse(): Command: '%s', Length: %f.\n",
-           substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos)),
-           strlen(substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos)))
-       );*/
-
-       if (
-           (autocvar_sv_vote_limit > 0)
-           &&
-           (strlen(substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos))) > autocvar_sv_vote_limit)
-          )   return 0;
+       if (autocvar_sv_vote_limit > 0 && strlen(vote_command) > autocvar_sv_vote_limit)
+               return 0;
 
        if (!VoteCommand_checkinlist(first_command, vote_list)) return 0;
 
@@ -678,14 +670,16 @@ int VoteCommand_parse(entity caller, string vote_command, string vote_list, floa
 
                        if (accepted > 0)
                        {
-                               string reason = ((argc > next_token) ? substring(vote_command, argv_start_index(next_token), strlen(vote_command) - argv_start_index(next_token)) : "No reason provided");
-                               string command_arguments;
+                               string reason = "No reason provided";
+                               if(argc > next_token)
+                                       reason = substring(vote_command, argv_start_index(next_token) - missing_chars, -1);
 
-                               if (first_command == "kickban") command_arguments = strcat(ftos(autocvar_g_ban_default_bantime), " ", ftos(autocvar_g_ban_default_masksize), " ~");
-                               else command_arguments = reason;
+                               string command_arguments = reason;
+                               if (first_command == "kickban")
+                                       command_arguments = strcat(ftos(autocvar_g_ban_default_bantime), " ", ftos(autocvar_g_ban_default_masksize), " ~");
 
                                vote_parsed_command = strcat(first_command, " # ", ftos(etof(victim)), " ", command_arguments);
-                               vote_parsed_display = strcat("^1", vote_command, " (^7", victim.netname, "^1): ", reason);
+                               vote_parsed_display = sprintf("^1%s #%d ^7%s^1 %s", first_command, etof(victim), victim.netname, reason);
                        }
                        else { print_to(caller, strcat("vcall: ", GetClientErrorString(accepted, argv(startpos + 1)), ".\n")); return 0; }
 
@@ -798,7 +792,6 @@ void VoteCommand_call(float request, entity caller, float argc, string vote_comm
                                if(parse_error == 0)
                                        print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info.");
                        }
-
                        else  // everything went okay, continue with calling the vote
                        {
                                vote_caller = caller;  // remember who called the vote
@@ -816,10 +809,12 @@ void VoteCommand_call(float request, entity caller, float argc, string vote_comm
                                }
 
                                FOREACH_CLIENT(IS_REAL_CLIENT(it), { ++tmp_playercount; });
-                               if (tmp_playercount > 1)   Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_VOTE_CALL);  // don't announce a "vote now" sound if player is alone
+                               if (tmp_playercount > 1)
+                                       Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_VOTE_CALL);
 
                                bprint("\{1}^2* ^3", OriginalCallerName(), "^2 calls a vote for ", vote_called_display, "\n");
-                               if (autocvar_sv_eventlog)   GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display));
+                               if (autocvar_sv_eventlog)
+                                       GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display));
                                Nagger_VoteChanged();
                                VoteCount(true);  // needed if you are the only one
                        }
@@ -854,7 +849,8 @@ void VoteCommand_master(float request, entity caller, float argc, string vote_co
                                                int parse_error;
                                                vote_command = VoteCommand_extractcommand(vote_command, 3, argc);
 
-                                               if (!caller.vote_master) { print_to(caller, "^1You do not have vote master privelages."); }
+                                               if (!caller.vote_master)
+                                                       print_to(caller, "^1You do not have vote master privileges.");
                                                else if (!VoteCommand_checknasty(vote_command))
                                                {
                                                        print_to(caller, "^1Syntax error in command, see 'vhelp' for more info.");
@@ -864,13 +860,14 @@ void VoteCommand_master(float request, entity caller, float argc, string vote_co
                                                        if(parse_error == 0)
                                                                print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info.");
                                                }
-
                                                else  // everything went okay, proceed with command
                                                {
                                                        localcmd(strcat(vote_parsed_command, "\n"));
                                                        print_to(caller, strcat("Executing command '", vote_parsed_display, "' on server."));
                                                        bprint("\{1}^2* ^3", GetCallerName(caller), "^2 used their ^3master^2 status to do \"^2", vote_parsed_display, "^2\".\n");
-                                                       if (autocvar_sv_eventlog)   GameLogEcho(strcat(":vote:vdo:", ftos(caller.playerid), ":", vote_parsed_display)); }
+                                                       if (autocvar_sv_eventlog)
+                                                               GameLogEcho(strcat(":vote:vdo:", ftos(caller.playerid), ":", vote_parsed_display));
+                                               }
 
                                                return;
                                        }
@@ -886,13 +883,14 @@ void VoteCommand_master(float request, entity caller, float argc, string vote_co
                                                {
                                                        print_to(caller, strcat("Rejected vote master login from ", GetCallerName(caller)));
                                                }
-
                                                else  // everything went okay, proceed with giving this player master privilages
                                                {
                                                        caller.vote_master = true;
                                                        print_to(caller, strcat("Accepted vote master login from ", GetCallerName(caller)));
                                                        bprint("\{1}^2* ^3", GetCallerName(caller), "^2 logged in as ^3master^2\n");
-                                                       if (autocvar_sv_eventlog)   GameLogEcho(strcat(":vote:vlogin:", ftos(caller.playerid))); }
+                                                       if (autocvar_sv_eventlog)
+                                                               GameLogEcho(strcat(":vote:vlogin:", ftos(caller.playerid)));
+                                               }
 
                                                return;
                                        }
@@ -912,7 +910,6 @@ void VoteCommand_master(float request, entity caller, float argc, string vote_co
                                                {
                                                        print_to(caller, "^1You can not call a vote while a timeout is active.");
                                                }
-
                                                else  // everything went okay, continue with creating vote
                                                {
                                                        vote_caller = caller;
@@ -926,7 +923,8 @@ void VoteCommand_master(float request, entity caller, float argc, string vote_co
                                                        caller.vote_waittime = time + autocvar_sv_vote_wait;
 
                                                        bprint("\{1}^2* ^3", OriginalCallerName(), "^2 calls a vote to become ^3master^2.\n");
-                                                       if (autocvar_sv_eventlog)   GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display));
+                                                       if (autocvar_sv_eventlog)
+                                                               GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display));
                                                        Nagger_VoteChanged();
                                                        VoteCount(true);  // needed if you are the only one
                                                }
@@ -972,7 +970,9 @@ void VoteCommand_no(float request, entity caller)  // CLIENT ONLY
                                print_to(caller, "^1You rejected the vote.");
                                caller.vote_selection = VOTE_SELECT_REJECT;
                                msg_entity = caller;
-                               if (!autocvar_sv_vote_singlecount)   VoteCount(false); }
+                               if (!autocvar_sv_vote_singlecount)
+                                       VoteCount(false);
+                       }
 
                        return;
                }
@@ -1042,13 +1042,14 @@ void VoteCommand_yes(float request, entity caller)  // CLIENT ONLY
                        {
                                print_to(caller, "^1You have already voted.");
                        }
-
                        else  // everything went okay, continue changing vote
                        {
                                print_to(caller, "^1You accepted the vote.");
                                caller.vote_selection = VOTE_SELECT_ACCEPT;
                                msg_entity = caller;
-                               if (!autocvar_sv_vote_singlecount)   VoteCount(false); }
+                               if (!autocvar_sv_vote_singlecount)
+                                       VoteCount(false);
+                       }
 
                        return;
                }
index 02704629612f32eaec198bca03857447a7ba337f..adaa8c36984525277e41f8c52607bc4ad9e74b04 100644 (file)
@@ -55,7 +55,7 @@ void GiveFrags (entity attacker, entity targ, float f, int deathtype)
                // regular frag
                GameRules_scoring_add(attacker, KILLS, 1);
                if(targ.playerid)
-                       PS_GR_P_ADDVAL(attacker, sprintf("kills-%d", targ.playerid), 1);
+                       PlayerStats_GameReport_Event_Player(attacker, sprintf("kills-%d", targ.playerid), 1);
        }
 
        GameRules_scoring_add(targ, DEATHS, 1);
@@ -167,60 +167,42 @@ void Obituary_SpecialDeath(
        string s1, string s2, string s3,
        float f1, float f2, float f3)
 {
-       if(DEATH_ISSPECIAL(deathtype))
+       if(!DEATH_ISSPECIAL(deathtype))
        {
-               entity deathent = Deathtypes_from(deathtype - DT_FIRST);
-               if (!deathent) { backtrace("Obituary_SpecialDeath: Could not find deathtype entity!\n"); return; }
+               backtrace("Obituary_SpecialDeath called without a special deathtype?\n");
+               return;
+       }
 
-               if(g_cts && deathtype == DEATH_KILL.m_id)
-                       return; // TODO: somehow put this in CTS gamemode file!
+       entity deathent = Deathtypes_from(deathtype - DT_FIRST);
+       if (!deathent)
+       {
+               backtrace("Obituary_SpecialDeath: Could not find deathtype entity!\n");
+               return;
+       }
 
-               if(murder)
-               {
-                       if(deathent.death_msgmurder)
-                       {
-                               Send_Notification_WOCOVA(
-                                       NOTIF_ONE,
-                                       notif_target,
-                                       MSG_MULTI,
-                                       deathent.death_msgmurder,
-                                       s1, s2, s3, "",
-                                       f1, f2, f3, 0
-                               );
-                               Send_Notification_WOCOVA(
-                                       NOTIF_ALL_EXCEPT,
-                                       notif_target,
-                                       MSG_INFO,
-                                       deathent.death_msgmurder.nent_msginfo,
-                                       s1, s2, s3, "",
-                                       f1, f2, f3, 0
-                               );
-                       }
-               }
-               else
-               {
-                       if(deathent.death_msgself)
-                       {
-                               Send_Notification_WOCOVA(
-                                       NOTIF_ONE,
-                                       notif_target,
-                                       MSG_MULTI,
-                                       deathent.death_msgself,
-                                       s1, s2, s3, "",
-                                       f1, f2, f3, 0
-                               );
-                               Send_Notification_WOCOVA(
-                                       NOTIF_ALL_EXCEPT,
-                                       notif_target,
-                                       MSG_INFO,
-                                       deathent.death_msgself.nent_msginfo,
-                                       s1, s2, s3, "",
-                                       f1, f2, f3, 0
-                               );
-                       }
-               }
+       if(g_cts && deathtype == DEATH_KILL.m_id)
+               return; // TODO: somehow put this in CTS gamemode file!
+
+       Notification death_message = (murder) ? deathent.death_msgmurder : deathent.death_msgself;
+       if(death_message)
+       {
+               Send_Notification_WOCOVA(
+                       NOTIF_ONE,
+                       notif_target,
+                       MSG_MULTI,
+                       death_message,
+                       s1, s2, s3, "",
+                       f1, f2, f3, 0
+               );
+               Send_Notification_WOCOVA(
+                       NOTIF_ALL_EXCEPT,
+                       notif_target,
+                       MSG_INFO,
+                       death_message.nent_msginfo,
+                       s1, s2, s3, "",
+                       f1, f2, f3, 0
+               );
        }
-       else { backtrace("Obituary_SpecialDeath called without a special deathtype?\n"); return; }
 }
 
 float Obituary_WeaponDeath(
@@ -231,44 +213,43 @@ float Obituary_WeaponDeath(
        float f1, float f2)
 {
        Weapon death_weapon = DEATH_WEAPONOF(deathtype);
-       if (death_weapon != WEP_Null)
-       {
-               w_deathtype = deathtype;
-               Notification death_message = ((murder) ? death_weapon.wr_killmessage(death_weapon) : death_weapon.wr_suicidemessage(death_weapon));
-               w_deathtype = false;
+       if (death_weapon == WEP_Null)
+               return false;
 
-               if (death_message)
-               {
-                       Send_Notification_WOCOVA(
-                               NOTIF_ONE,
-                               notif_target,
-                               MSG_MULTI,
-                               death_message,
-                               s1, s2, s3, "",
-                               f1, f2, 0, 0
-                       );
-                       // send the info part to everyone
-                       Send_Notification_WOCOVA(
-                               NOTIF_ALL_EXCEPT,
-                               notif_target,
-                               MSG_INFO,
-                               death_message.nent_msginfo,
-                               s1, s2, s3, "",
-                               f1, f2, 0, 0
-                       );
-               }
-               else
-               {
-                       LOG_TRACEF(
-                               "Obituary_WeaponDeath(): ^1Deathtype ^7(%d)^1 has no notification for weapon %d!\n",
-                               deathtype,
-                               death_weapon
-                       );
-               }
+       w_deathtype = deathtype;
+       Notification death_message = ((murder) ? death_weapon.wr_killmessage(death_weapon) : death_weapon.wr_suicidemessage(death_weapon));
+       w_deathtype = false;
 
-               return true;
+       if (death_message)
+       {
+               Send_Notification_WOCOVA(
+                       NOTIF_ONE,
+                       notif_target,
+                       MSG_MULTI,
+                       death_message,
+                       s1, s2, s3, "",
+                       f1, f2, 0, 0
+               );
+               // send the info part to everyone
+               Send_Notification_WOCOVA(
+                       NOTIF_ALL_EXCEPT,
+                       notif_target,
+                       MSG_INFO,
+                       death_message.nent_msginfo,
+                       s1, s2, s3, "",
+                       f1, f2, 0, 0
+               );
        }
-       return false;
+       else
+       {
+               LOG_TRACEF(
+                       "Obituary_WeaponDeath(): ^1Deathtype ^7(%d)^1 has no notification for weapon %d!\n",
+                       deathtype,
+                       death_weapon
+               );
+       }
+
+       return true;
 }
 
 bool frag_centermessage_override(entity attacker, entity targ, int deathtype, int kill_count_to_attacker, int kill_count_to_target)
@@ -383,7 +364,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
                                case counta: \
                                { \
                                        Send_Notification(NOTIF_ONE, attacker, MSG_ANNCE, ANNCE_KILLSTREAK_##countb); \
-                                       PS_GR_P_ADDVAL(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
+                                       PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
                                        break; \
                                }
                        switch(CS(attacker).killcount)
@@ -397,8 +378,8 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
                        {
                                checkrules_firstblood = true;
                                notif_firstblood = true; // modify the current messages so that they too show firstblood information
-                               PS_GR_P_ADDVAL(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
-                               PS_GR_P_ADDVAL(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
+                               PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
+                               PlayerStats_GameReport_Event_Player(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
 
                                // tell spree_inf and spree_cen that this is a first-blood and first-victim event
                                kill_count_to_attacker = -1;
@@ -513,7 +494,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
                if(GameRules_scoring_add(targ, SCORE, 0) == -5)
                {
                        Send_Notification(NOTIF_ONE, targ, MSG_ANNCE, ANNCE_ACHIEVEMENT_BOTLIKE);
-                       PS_GR_P_ADDVAL(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
+                       PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
                }
        }
 
diff --git a/qcsrc/server/handicap.qc b/qcsrc/server/handicap.qc
new file mode 100644 (file)
index 0000000..d0dfc4d
--- /dev/null
@@ -0,0 +1,41 @@
+#include "handicap.qh"
+
+/// \file
+/// \brief Source file that contains implementation of the handicap system.
+/// \author Lyberta
+/// \copyright GNU GPLv2 or any later version.
+
+#include <common/state.qh>
+#include "client.qh"
+
+.float m_handicap; ///< Holds the handicap value.
+
+void Handicap_Initialize(entity player)
+{
+       CS(player).m_handicap = 1;
+}
+
+float Handicap_GetVoluntaryHandicap(entity player)
+{
+       return bound(1.0, CS(player).cvar_cl_handicap, 10.0);
+}
+
+float Handicap_GetForcedHandicap(entity player)
+{
+       return CS(player).m_handicap;
+}
+
+void Handicap_SetForcedHandicap(entity player, float value)
+{
+       if (value <= 0)
+       {
+               error("Handicap_SetForcedHandicap: Invalid handicap value.");
+       }
+       CS(player).m_handicap = value;
+}
+
+float Handicap_GetTotalHandicap(entity player)
+{
+       return Handicap_GetForcedHandicap(player) * Handicap_GetVoluntaryHandicap(
+               player);
+}
diff --git a/qcsrc/server/handicap.qh b/qcsrc/server/handicap.qh
new file mode 100644 (file)
index 0000000..fa45a0e
--- /dev/null
@@ -0,0 +1,40 @@
+#pragma once
+
+/// \file
+/// \brief Header file that describes the handicap system.
+/// \author Lyberta
+/// \copyright GNU GPLv2 or any later version.
+
+// Handicap is used to make the game harder for strong players and easier for
+// weak players. Values greater than 1 make the game harder and values less than
+// 1 make the game easier. Right now handicap only affects damage. There are 2
+// types of handicap: voluntary and forced. Voluntary handicap can be set via
+// cl_handicap cvar. For obvious reasons, it can't be less than 1. Forced
+// handicap can be set by server mutators. The total handicap is the product of
+// voluntary and forced handicap.
+
+/// \brief Initializes handicap to its default value.
+/// \param[in,out] player Player to initialize.
+/// \return No return.
+void Handicap_Initialize(entity player);
+
+/// \brief Returns the voluntary handicap of the player.
+/// \param[in] player Player to check.
+/// \return Voluntary handicap of the player.
+float Handicap_GetVoluntaryHandicap(entity player);
+
+/// \brief Returns the forced handicap of the player.
+/// \param[in] player Player to check.
+/// \return Forced handicap of the player.
+float Handicap_GetForcedHandicap(entity player);
+
+/// \brief Sets the forced handicap of the player.
+/// \param[in] player Player to alter.
+/// \param[in] value Handicap value to set.
+/// \return No return.
+void Handicap_SetForcedHandicap(entity player, float value);
+
+/// \brief Returns the total handicap of the player.
+/// \param[in] player Player to check.
+/// \return Total handicap of the player.
+float Handicap_GetTotalHandicap(entity player);
index 554da5f804bbaa2b35a633053b5c3a9c1bd55fa3..ab837c8945b873c0982d13834693c4a1a0f1fe9e 100644 (file)
@@ -7,6 +7,7 @@
 #include "ipban.qh"
 #include "mutators/_mod.qh"
 #include "../common/t_items.qh"
+#include "resources.qh"
 #include "weapons/accuracy.qh"
 #include "weapons/csqcprojectile.qh"
 #include "weapons/selection.qh"
@@ -199,14 +200,14 @@ string NearestLocation(vector p)
 string AmmoNameFromWeaponentity(entity wpn)
 {
        string ammoitems = "batteries";
-       switch((wpn.m_weapon).ammo_field)
+       switch ((wpn.m_weapon).ammo_type)
        {
-               case ammo_shells:  ammoitems = ITEM_Shells.m_name;      break;
-               case ammo_nails:   ammoitems = ITEM_Bullets.m_name;     break;
-               case ammo_rockets: ammoitems = ITEM_Rockets.m_name;     break;
-               case ammo_cells:   ammoitems = ITEM_Cells.m_name;       break;
-               case ammo_plasma:  ammoitems = ITEM_Plasma.m_name;      break;
-               case ammo_fuel:    ammoitems = ITEM_JetpackFuel.m_name; break;
+               case RESOURCE_SHELLS:  ammoitems = ITEM_Shells.m_name;      break;
+               case RESOURCE_BULLETS: ammoitems = ITEM_Bullets.m_name;     break;
+               case RESOURCE_ROCKETS: ammoitems = ITEM_Rockets.m_name;     break;
+               case RESOURCE_CELLS:   ammoitems = ITEM_Cells.m_name;       break;
+               case RESOURCE_PLASMA:  ammoitems = ITEM_Plasma.m_name;      break;
+               case RESOURCE_FUEL:    ammoitems = ITEM_JetpackFuel.m_name; break;
        }
        return ammoitems;
 }
@@ -525,6 +526,10 @@ void readplayerstartcvars()
        start_ammo_rockets = 0;
        start_ammo_cells = 0;
        start_ammo_plasma = 0;
+       if (random_start_ammo == NULL)
+       {
+               random_start_ammo = spawn();
+       }
        start_health = cvar("g_balance_health_start");
        start_armorvalue = cvar("g_balance_armor_start");
 
@@ -643,6 +648,17 @@ void readplayerstartcvars()
                start_ammo_cells = cvar("g_start_ammo_cells");
                start_ammo_plasma = cvar("g_start_ammo_plasma");
                start_ammo_fuel = cvar("g_start_ammo_fuel");
+               random_start_weapons_count = cvar("g_random_start_weapons_count");
+               SetResourceAmount(random_start_ammo, RESOURCE_SHELLS, cvar(
+                       "g_random_start_shells"));
+               SetResourceAmount(random_start_ammo, RESOURCE_BULLETS, cvar(
+                       "g_random_start_bullets"));
+               SetResourceAmount(random_start_ammo, RESOURCE_ROCKETS, 
+                       cvar("g_random_start_rockets"));
+               SetResourceAmount(random_start_ammo, RESOURCE_CELLS, cvar(
+                       "g_random_start_cells"));
+               SetResourceAmount(random_start_ammo, RESOURCE_PLASMA, cvar(
+                       "g_random_start_plasma"));
        }
 
        if (warmup_stage)
@@ -711,6 +727,16 @@ void readplayerstartcvars()
        start_ammo_cells = max(0, start_ammo_cells);
        start_ammo_plasma = max(0, start_ammo_plasma);
        start_ammo_fuel = max(0, start_ammo_fuel);
+       SetResourceAmount(random_start_ammo, RESOURCE_SHELLS, max(0,
+               GetResourceAmount(random_start_ammo, RESOURCE_SHELLS)));
+       SetResourceAmount(random_start_ammo, RESOURCE_BULLETS, max(0,
+               GetResourceAmount(random_start_ammo, RESOURCE_BULLETS)));
+       SetResourceAmount(random_start_ammo, RESOURCE_ROCKETS, max(0,
+               GetResourceAmount(random_start_ammo, RESOURCE_ROCKETS)));
+       SetResourceAmount(random_start_ammo, RESOURCE_CELLS, max(0,
+               GetResourceAmount(random_start_ammo, RESOURCE_CELLS)));
+       SetResourceAmount(random_start_ammo, RESOURCE_PLASMA, max(0,
+               GetResourceAmount(random_start_ammo, RESOURCE_PLASMA)));
 
        warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
        warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
index 1c01a573797713c4fe39345da3f895e60717aad9..1dd3526dd48c435eaa00ade8bc1a0047b767079a 100644 (file)
@@ -188,6 +188,13 @@ float start_ammo_rockets;
 float start_ammo_cells;
 float start_ammo_plasma;
 float start_ammo_fuel;
+/// \brief Number of random start weapons to give to players.
+int random_start_weapons_count;
+/// \brief Holds a list of possible random start weapons.
+string autocvar_g_random_start_weapons;
+/// \brief Entity that contains amount of ammo to give with random start
+/// weapons.
+entity random_start_ammo;
 float start_health;
 float start_armorvalue;
 WepSet warmup_start_weapons;
index 0110bdf1bd66c989a61f88e8e7840d7e088bcd38..e0c4198cc7adbea3354f350544950a5cf8ac7397 100644 (file)
@@ -871,6 +871,13 @@ MUTATOR_HOOKABLE(WantWeapon, EV_WantWeapon);
     /**/
 MUTATOR_HOOKABLE(AddPlayerScore, EV_AddPlayerScore);
 
+#define EV_AddedPlayerScore(i, o) \
+    /** score field */  i(entity, MUTATOR_ARGV_0_entity) \
+    /** score */        i(float, MUTATOR_ARGV_1_float) \
+    /** player */       i(entity, MUTATOR_ARGV_2_entity) \
+    /**/
+MUTATOR_HOOKABLE(AddedPlayerScore, EV_AddPlayerScore);
+
 #define EV_GetPlayerStatus(i, o) \
     /** player */    i(entity, MUTATOR_ARGV_0_entity) \
     /**/
index dd061526265c12501deb2add452d694b5b7752be..ac2dcb1ede667f10ab90dd9953895faeff3c1437 100644 (file)
@@ -4,6 +4,7 @@
 #include "bot/api.qh"
 #include "cheats.qh"
 #include "g_damage.qh"
+#include "handicap.qh"
 #include "g_subs.qh"
 #include "miscfunctions.qh"
 #include "portals.qh"
@@ -317,9 +318,11 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
 
        if(!DEATH_ISSPECIAL(deathtype))
        {
-               damage *= bound(1.0, CS(this).cvar_cl_handicap, 10.0);
-               if(this != attacker && IS_PLAYER(attacker))
-                       damage /= bound(1.0, CS(attacker).cvar_cl_handicap, 10.0);
+               damage *= Handicap_GetTotalHandicap(this);
+               if (this != attacker && IS_PLAYER(attacker))
+               {
+                       damage /= Handicap_GetTotalHandicap(attacker);
+               }
        }
 
        if (time < this.spawnshieldtime && autocvar_g_spawnshield_blockdamage < 1)
@@ -514,7 +517,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
 
                if(this.alivetime)
                {
-                       PS_GR_P_ADDVAL(this, PLAYERSTATS_ALIVETIME, time - this.alivetime);
+                       PlayerStats_GameReport_Event_Player(this, PLAYERSTATS_ALIVETIME, time - this.alivetime);
                        this.alivetime = 0;
                }
 
index edf4ff16238ee591537546037eba9eff8fe14750..a2a1358b97856196366b7dc95c909c620f2152ec 100644 (file)
@@ -1,4 +1,5 @@
 #include "resources.qh"
+
 /// \file
 /// \brief Source file that contains implementation of the resource system.
 /// \author Lyberta
index ce8e1e8e5daaa3f023cfe169f814a5aa5c8ba89c..6ff3cea67917973eab045526b76d0c6d97b05890 100644 (file)
@@ -1,25 +1,15 @@
 #pragma once
+
 /// \file
 /// \brief Header file that describes the resource system.
 /// \author Lyberta
 /// \copyright GNU GPLv2 or any later version.
 
+#include <common/resources.qh>
+
 /// \brief Unconditional maximum amount of resources the entity can have.
 const int RESOURCE_AMOUNT_HARD_LIMIT = 999;
 
-/// \brief Describes the available resource types.
-enum
-{
-       RESOURCE_HEALTH = 1, ///< Health.
-       RESOURCE_ARMOR, ///< Armor.
-       RESOURCE_SHELLS, ///< Shells (used by shotgun).
-       RESOURCE_BULLETS, ///< Bullets (used by machinegun and rifle)
-       RESOURCE_ROCKETS, ///< Rockets (used by mortar, hagar, devastator, etc).
-       RESOURCE_CELLS, ///< Cells (used by electro, crylink, vortex, etc)
-       RESOURCE_PLASMA, ///< Plasma (unused).
-       RESOURCE_FUEL ///< Fuel (used by jetpack).
-};
-
 // ============================ Public API ====================================
 
 /// \brief Returns the maximum amount of the given resource.
index 11bc60238252bb071cbade6518384a3ac8cbb47c..32fe3c6aaa2dd178f3af6cff5d89606688e3209f 100644 (file)
@@ -347,8 +347,10 @@ float PlayerScore_Add(entity player, PlayerScoreField scorefield, float score)
        if(scores_label(scorefield) != "")
                s.SendFlags |= (2 ** (scorefield.m_id % 16));
        if(!warmup_stage)
-               PS_GR_P_ADDVAL(s.owner, strcat(PLAYERSTATS_TOTAL, scores_label(scorefield)), score);
-       return (s.(scores(scorefield)) += score);
+               PlayerStats_GameReport_Event_Player(s.owner, strcat(PLAYERSTATS_TOTAL, scores_label(scorefield)), score);
+       s.(scores(scorefield)) += score;
+       MUTATOR_CALLHOOK(AddedPlayerScore, scorefield, score, player);
+       return s.(scores(scorefield));
 }
 
 float PlayerTeamScore_Add(entity player, PlayerScoreField pscorefield, float tscorefield, float score)
@@ -906,10 +908,10 @@ void PlayerScore_PlayerStats(entity p)
 {
        entity s = CS(p).scorekeeper;
        FOREACH(Scores, true, {
-               if(s.(scores(it)) != 0)
-                       if(scores_label(it) != "")
-                               PS_GR_P_ADDVAL(s.owner, strcat(PLAYERSTATS_SCOREBOARD, scores_label(it)), s.(scores(it)));
-    });
+               if(s.(scores(it)) != 0 && scores_label(it) != "")
+                       PlayerStats_GameReport_Event_Player(s.owner,
+                               strcat(PLAYERSTATS_SCOREBOARD, scores_label(it)), s.(scores(it)));
+       });
 }
 
 void PlayerScore_TeamStats()
@@ -922,9 +924,9 @@ void PlayerScore_TeamStats()
                if(!sk)
                        continue;
                for(i = 0; i < MAX_TEAMSCORE; ++i)
-                       if(sk.(teamscores(i)) != 0)
-                               if(teamscores_label(i) != "")
-                                       // the +1 is important here!
-                                       PS_GR_T_ADDVAL(t+1, strcat(PLAYERSTATS_SCOREBOARD, teamscores_label(i)), sk.(teamscores(i)));
+                       if(sk.(teamscores(i)) != 0 && teamscores_label(i) != "")
+                               // the +1 is important here!
+                               PlayerStats_GameReport_Event_Team(t+1,
+                                       strcat(PLAYERSTATS_SCOREBOARD, teamscores_label(i)), sk.(teamscores(i)));
        }
 }
index 68e7b375b507a09051f3607114f60d14cd9da0f2..97299ffeffa7e4a7c114ad53bf7885ca7585ed79 100644 (file)
@@ -88,7 +88,6 @@ void CreatureFrame_Liquids(entity this)
                        this.dmgtime = 0;
                }
                this.air_finished = time + 12;
-               this.dmg = 2;
        }
 }
 
@@ -320,8 +319,6 @@ bool expr_evaluate(string s)
 
 void SV_OnEntityPreSpawnFunction(entity this)
 {
-       __spawnfunc_expecting = true;
-       __spawnfunc_expect = this;
        if (this)
        if (this.gametypefilter != "")
        if (!isGametypeInFilter(MapInfo_LoadedGametype, teamplay, have_team_spawns, this.gametypefilter))
@@ -363,7 +360,6 @@ void SV_OnEntityPreSpawnFunction(entity this)
        return;
 LABEL(cleanup)
     builtin_remove(this);
-    __spawnfunc_expecting = false;
 }
 
 void WarpZone_PostInitialize_Callback()
index 62b11ea45d62e47e3bc9c3d7244b05837e39c737..d5b78aa1cd064424b267ca3cfc2ce7c782714d09 100644 (file)
@@ -1,6 +1,7 @@
 #include "spawning.qh"
 
 #include "weaponsystem.qh"
+#include "../resources.qh"
 #include "../mutators/_mod.qh"
 #include <common/t_items.qh>
 #include <common/weapons/_all.qh>
@@ -101,16 +102,16 @@ void weapon_defaultspawnfunc(entity this, Weapon e)
                        this.superweapons_finished = autocvar_g_balance_superweapons_time;
 
        // if we don't already have ammo, give us some ammo
-       if (!this.(wpn.ammo_field))
+       if ((wpn.ammo_type != RESOURCE_NONE) && !GetResourceAmount(this, wpn.ammo_type))
        {
-               switch (wpn.ammo_field)
+               switch (wpn.ammo_type)
                {
-                       case ammo_shells:  this.ammo_shells  = cvar("g_pickup_shells_weapon");  break;
-                       case ammo_nails:   this.ammo_nails   = cvar("g_pickup_nails_weapon");   break;
-                       case ammo_rockets: this.ammo_rockets = cvar("g_pickup_rockets_weapon"); break;
-                       case ammo_cells:   this.ammo_cells   = cvar("g_pickup_cells_weapon");   break;
-                       case ammo_plasma:  this.ammo_plasma  = cvar("g_pickup_plasma_weapon");  break;
-                       case ammo_fuel:    this.ammo_fuel    = cvar("g_pickup_fuel_weapon");    break;
+                       case RESOURCE_SHELLS:  SetResourceAmount(this, wpn.ammo_type, cvar("g_pickup_shells_weapon"));  break;
+                       case RESOURCE_BULLETS: SetResourceAmount(this, wpn.ammo_type, cvar("g_pickup_nails_weapon"));   break;
+                       case RESOURCE_ROCKETS: SetResourceAmount(this, wpn.ammo_type, cvar("g_pickup_rockets_weapon")); break;
+                       case RESOURCE_CELLS:   SetResourceAmount(this, wpn.ammo_type, cvar("g_pickup_cells_weapon"));   break;
+                       case RESOURCE_PLASMA:  SetResourceAmount(this, wpn.ammo_type, cvar("g_pickup_plasma_weapon"));  break;
+                       case RESOURCE_FUEL:    SetResourceAmount(this, wpn.ammo_type, cvar("g_pickup_fuel_weapon"));    break;
                }
        }
 
index 4b7d45b964157127f682e1de6048aa1bc3c358cd..52bf4a60788509039e72818a421099eb0c9aa907 100644 (file)
@@ -1,6 +1,7 @@
 #include "throwing.qh"
 
 #include "weaponsystem.qh"
+#include "../resources.qh"
 #include "../mutators/_mod.qh"
 #include <common/t_items.qh>
 #include "../g_damage.qh"
@@ -37,7 +38,7 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto
        float thisammo;
        string s;
        Weapon info = Weapons_from(wpn);
-       var .int ammotype = info.ammo_field;
+       int ammotype = info.ammo_type;
 
        entity wep = new(droppedweapon);
 
@@ -88,7 +89,7 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto
        wep.pickup_anyway = true; // these are ALWAYS pickable
 
        //wa = W_AmmoItemCode(wpn);
-       if(ammotype == ammo_none)
+       if(ammotype == RESOURCE_NONE)
        {
                return "";
        }
@@ -102,11 +103,10 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto
                        int i = own.(weaponentity).m_weapon.m_id;
                        if(own.(weaponentity).(weapon_load[i]) > 0)
                        {
-                               own.(ammotype) += own.(weaponentity).(weapon_load[i]);
+                               GiveResource(own, ammotype, own.(weaponentity).(weapon_load[i]));
                                own.(weaponentity).(weapon_load[i]) = -1; // schedule the weapon for reloading
                        }
-
-                       wep.(ammotype) = 0;
+                       SetResourceAmount(wep, ammotype, 0);
                }
                else if(doreduce)
                {
@@ -114,22 +114,23 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto
                        int i = own.(weaponentity).m_weapon.m_id;
                        if(own.(weaponentity).(weapon_load[i]) > 0)
                        {
-                               own.(ammotype) += own.(weaponentity).(weapon_load[i]);
+                               GiveResource(own, ammotype, own.(weaponentity).(weapon_load[i]));
                                own.(weaponentity).(weapon_load[i]) = -1; // schedule the weapon for reloading
                        }
 
-                       thisammo = min(own.(ammotype), wep.(ammotype));
-                       wep.(ammotype) = thisammo;
-                       own.(ammotype) -= thisammo;
+                       float ownderammo = GetResourceAmount(own, ammotype);
+                       thisammo = min(ownderammo, GetResourceAmount(wep, ammotype));
+                       SetResourceAmount(wep, ammotype, thisammo);
+                       SetResourceAmount(own, ammotype, ownderammo - thisammo);
 
-                       switch(ammotype)
+                       switch (ammotype)
                        {
-                               case ammo_shells:  s = sprintf("%s and %d shells", s, thisammo);  break;
-                               case ammo_nails:   s = sprintf("%s and %d nails", s, thisammo);   break;
-                               case ammo_rockets: s = sprintf("%s and %d rockets", s, thisammo); break;
-                               case ammo_cells:   s = sprintf("%s and %d cells", s, thisammo);   break;
-                               case ammo_plasma:  s = sprintf("%s and %d plasma", s, thisammo);  break;
-                               case ammo_fuel:    s = sprintf("%s and %d fuel", s, thisammo);    break;
+                               case RESOURCE_SHELLS:  s = sprintf("%s and %d shells", s, thisammo);  break;
+                               case RESOURCE_BULLETS: s = sprintf("%s and %d nails", s, thisammo);   break;
+                               case RESOURCE_ROCKETS: s = sprintf("%s and %d rockets", s, thisammo); break;
+                               case RESOURCE_CELLS:   s = sprintf("%s and %d cells", s, thisammo);   break;
+                               case RESOURCE_PLASMA:  s = sprintf("%s and %d plasma", s, thisammo);  break;
+                               case RESOURCE_FUEL:    s = sprintf("%s and %d fuel", s, thisammo);    break;
                        }
 
                        s = substring(s, 5, -1);
@@ -155,7 +156,7 @@ bool W_IsWeaponThrowable(entity this, int w)
                // start weapons that take no ammo can't be dropped (this prevents dropping the laser, as long as it continues to use no ammo)
                if(start_items & IT_UNLIMITED_WEAPON_AMMO)
                        return false;
-               if((Weapons_from(w)).ammo_field == ammo_none)
+               if((Weapons_from(w)).ammo_type == RESOURCE_NONE)
                        return false;
        }
        return true;
index f8949b15601919e1b863084a1e5653ab3f94d9c2..2f6fcb68d7213cbafc508343d377da932944ad0a 100644 (file)
@@ -5,6 +5,7 @@
 #include "../command/common.qh"
 #include "../mutators/_mod.qh"
 #include "../round_handler.qh"
+#include "../resources.qh"
 #include <common/t_items.qh>
 #include <common/animdecide.qh>
 #include <common/constants.qh>
@@ -668,21 +669,22 @@ void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use, .entity weaponenti
                w_ent.clip_load -= ammo_use;
                w_ent.(weapon_load[w_ent.m_weapon.m_id]) = w_ent.clip_load;
        }
-       else if (wep.ammo_field != ammo_none)
+       else if (wep.ammo_type != RESOURCE_NONE)
        {
-               actor.(wep.ammo_field) -= ammo_use;
-               if (actor.(wep.ammo_field) < 0)
+               float ammo = GetResourceAmount(actor, wep.ammo_type);
+               if (ammo < ammo_use)
                {
                        backtrace(sprintf(
                                "W_DecreaseAmmo(%.2f): '%s' subtracted too much %s from '%s', resulting with '%.2f' left... "
                                "Please notify Samual immediately with a copy of this backtrace!\n",
                                ammo_use,
                                wep.netname,
-                               GetAmmoPicture(wep.ammo_field),
+                               GetAmmoPicture(wep.ammo_type),
                                actor.netname,
-                               actor.(wep.ammo_field)
+                               ammo
                                             ));
                }
+               SetResourceAmount(actor, wep.ammo_type, ammo - ammo_use);
        }
 }
 
@@ -702,16 +704,17 @@ void W_ReloadedAndReady(Weapon thiswep, entity actor, .entity weaponentity, int
        w_ent.clip_load = w_ent.old_clip_load;  // restore the ammo counter, in case we still had ammo in the weapon before reloading
 
        // if the gun uses no ammo, max out weapon load, else decrease ammo as we increase weapon load
-       if (!w_ent.reload_ammo_min || (actor.items & IT_UNLIMITED_WEAPON_AMMO) || wpn.ammo_field == ammo_none)
+       if (!w_ent.reload_ammo_min || (actor.items & IT_UNLIMITED_WEAPON_AMMO) || wpn.ammo_type == RESOURCE_NONE)
        {
                w_ent.clip_load = w_ent.reload_ammo_amount;
        }
        else
        {
                // make sure we don't add more ammo than we have
-               float load = min(w_ent.reload_ammo_amount - w_ent.clip_load, actor.(wpn.ammo_field));
+               float ammo = GetResourceAmount(actor, wpn.ammo_type);
+               float load = min(w_ent.reload_ammo_amount - w_ent.clip_load, ammo);
                w_ent.clip_load += load;
-               actor.(wpn.ammo_field) -= load;
+               SetResourceAmount(actor, wpn.ammo_type, ammo - load);
        }
        w_ent.(weapon_load[w_ent.m_weapon.m_id]) = w_ent.clip_load;
 
@@ -754,9 +757,9 @@ void W_Reload(entity actor, .entity weaponentity, float sent_ammo_min, Sound sen
        if (this.clip_load >= this.reload_ammo_amount) return;
 
        // no ammo, so nothing to load
-       if (e.ammo_field != ammo_none)
+       if (e.ammo_type != RESOURCE_NONE)
        {
-               if (!actor.(e.ammo_field) && this.reload_ammo_min)
+               if (!GetResourceAmount(actor, e.ammo_type) && this.reload_ammo_min)
                {
                        if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
                        {
index 1c0eadcbe30b293c69a95134a2fc4e85a09c0e50..a8ac4a0e85a7533dbc78ff08ba450e8935322d9e 100755 (executable)
@@ -13,10 +13,14 @@ function hash() {
 function genmod() {
     # use context to work around cmake issue #12619
     CTX="${PWD#$ROOT}/"
-    oldHashC=$(hash ${MOD}.inc)
-    oldTimeC=$(stat -c "%Y" ${MOD}.inc)
-    oldHashH=$(hash ${MOD}.qh)
-    oldTimeH=$(stat -c "%Y" ${MOD}.qh)
+    if [ -f ${MOD}.inc ]; then
+        oldHashC=$(hash ${MOD}.inc)
+        oldTimeC=$(stat -c "%Y" ${MOD}.inc)
+    fi
+    if [ -f ${MOD}.qh ]; then
+        oldHashH=$(hash ${MOD}.qh)
+        oldTimeH=$(stat -c "%Y" ${MOD}.qh)
+    fi
     echo '// generated file; do not modify' > ${MOD}.inc
     echo '// generated file; do not modify' > ${MOD}.qh
     for f in $(ls | sort -k 1,1 -t .); do
index a538eafbb59c29b0ee036b4a1813626abb52c2f1..bfd9808fbb13e2029972cb4c36e36114e55a1f75 100644 (file)
@@ -2,6 +2,7 @@ models/ok_nade_counter/ok_nade_counter_01
 {
        dpnoshadow
        deformVertexes autosprite
+       nopicmip
        {
                map "models/ok_nade_counter/ok_nade_counter_01"
                blendfunc add
@@ -11,6 +12,7 @@ models/ok_nade_counter/ok_nade_counter_02
 {
        dpnoshadow
        deformVertexes autosprite
+       nopicmip
        {
                map "models/ok_nade_counter/ok_nade_counter_02"
                blendfunc add
@@ -20,6 +22,7 @@ models/ok_nade_counter/ok_nade_counter_03
 {
        dpnoshadow
        deformVertexes autosprite
+       nopicmip
        {
                map "models/ok_nade_counter/ok_nade_counter_03"
                blendfunc add
@@ -29,6 +32,7 @@ models/ok_nade_counter/ok_nade_counter_04
 {
        dpnoshadow
        deformVertexes autosprite
+       nopicmip
        {
                map "models/ok_nade_counter/ok_nade_counter_04"
                blendfunc add
@@ -38,6 +42,7 @@ models/ok_nade_counter/ok_nade_counter_05
 {
        dpnoshadow
        deformVertexes autosprite
+       nopicmip
        {
                map "models/ok_nade_counter/ok_nade_counter_05"
                blendfunc add
@@ -47,6 +52,7 @@ models/ok_nade_counter/ok_nade_counter_06
 {
        dpnoshadow
        deformVertexes autosprite
+       nopicmip
        {
                map "models/ok_nade_counter/ok_nade_counter_06"
                blendfunc add
@@ -56,6 +62,7 @@ models/ok_nade_counter/ok_nade_counter_07
 {
        dpnoshadow
        deformVertexes autosprite
+       nopicmip
        {
                map "models/ok_nade_counter/ok_nade_counter_07"
                blendfunc add
@@ -65,6 +72,7 @@ models/ok_nade_counter/ok_nade_counter_08
 {
        dpnoshadow
        deformVertexes autosprite
+       nopicmip
        {
                map "models/ok_nade_counter/ok_nade_counter_08"
                blendfunc add
@@ -74,6 +82,7 @@ models/ok_nade_counter/ok_nade_counter_09
 {
        dpnoshadow
        deformVertexes autosprite
+       nopicmip
        {
                map "models/ok_nade_counter/ok_nade_counter_09"
                blendfunc add