Merge branch 'master' into terencehill/bot_ai
authorterencehill <piuntn@gmail.com>
Wed, 20 Jun 2018 10:07:20 +0000 (12:07 +0200)
committerterencehill <piuntn@gmail.com>
Wed, 20 Jun 2018 10:07:20 +0000 (12:07 +0200)
# Conflicts:
# qcsrc/common/gamemodes/gamemode/ctf/ctf.qc

144 files changed:
.gitlab-ci.yml
.tx/merge-base
_hud_descriptions.cfg
bal-wep-mario.cfg
commands.cfg
common.ko.po
gamemodes-server.cfg
mutators.cfg
qcsrc/client/_mod.inc
qcsrc/client/_mod.qh
qcsrc/client/announcer.qc
qcsrc/client/autocvars.qh
qcsrc/client/hud/hud.qh
qcsrc/client/hud/panel/radar.qc
qcsrc/client/hud/panel/weapons.qc
qcsrc/client/main.qc
qcsrc/client/main.qh
qcsrc/client/miscfunctions.qh
qcsrc/client/resources.qc [new file with mode: 0644]
qcsrc/client/resources.qh [new file with mode: 0644]
qcsrc/client/shownames.qc
qcsrc/client/view.qc
qcsrc/common/debug.qh
qcsrc/common/ent_cs.qc
qcsrc/common/gamemodes/gamemode/assault/assault.qc
qcsrc/common/gamemodes/gamemode/clanarena/clanarena.qc
qcsrc/common/gamemodes/gamemode/ctf/ctf.qc
qcsrc/common/gamemodes/gamemode/ctf/ctf.qh
qcsrc/common/gamemodes/gamemode/cts/cts.qc
qcsrc/common/gamemodes/gamemode/domination/domination.qc
qcsrc/common/gamemodes/gamemode/freezetag/freezetag.qc
qcsrc/common/gamemodes/gamemode/invasion/invasion.qc
qcsrc/common/gamemodes/gamemode/keepaway/keepaway.qc
qcsrc/common/gamemodes/gamemode/nexball/nexball.qc
qcsrc/common/gamemodes/gamemode/onslaught/cl_controlpoint.qc
qcsrc/common/gamemodes/gamemode/onslaught/cl_generator.qc
qcsrc/common/gamemodes/gamemode/onslaught/onslaught.qc
qcsrc/common/gamemodes/gamemode/onslaught/sv_controlpoint.qc
qcsrc/common/gamemodes/gamemode/onslaught/sv_generator.qc
qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc
qcsrc/common/items/item.qh
qcsrc/common/items/item/ammo.qh
qcsrc/common/items/item/armor.qh
qcsrc/common/items/item/health.qh
qcsrc/common/items/item/jetpack.qh
qcsrc/common/mapobjects/func/breakable.qc
qcsrc/common/mapobjects/func/button.qc
qcsrc/common/mapobjects/func/door.qc
qcsrc/common/mapobjects/func/door_rotating.qc
qcsrc/common/mapobjects/func/door_secret.qc
qcsrc/common/mapobjects/platforms.qc
qcsrc/common/mapobjects/teleporters.qc
qcsrc/common/mapobjects/trigger/heal.qc
qcsrc/common/mapobjects/trigger/multi.qc
qcsrc/common/mapobjects/trigger/secret.qc
qcsrc/common/mapobjects/trigger/swamp.qc
qcsrc/common/monsters/monster/mage.qc
qcsrc/common/monsters/monster/shambler.qc
qcsrc/common/monsters/monster/spider.qc
qcsrc/common/monsters/monster/wyvern.qc
qcsrc/common/monsters/monster/zombie.qc
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/mutators/mutator/buffs/sv_buffs.qc
qcsrc/common/mutators/mutator/instagib/items.qh
qcsrc/common/mutators/mutator/invincibleproj/sv_invincibleproj.qc
qcsrc/common/mutators/mutator/nades/nades.qc
qcsrc/common/mutators/mutator/nades/net.qc
qcsrc/common/mutators/mutator/new_toys/sv_new_toys.qc
qcsrc/common/mutators/mutator/nix/sv_nix.qc
qcsrc/common/mutators/mutator/overkill/okrpc.qc
qcsrc/common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qc
qcsrc/common/mutators/mutator/vampire/sv_vampire.qc
qcsrc/common/mutators/mutator/vampirehook/sv_vampirehook.qc
qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc
qcsrc/common/notifications/all.inc
qcsrc/common/physics/player.qc
qcsrc/common/resources.qh
qcsrc/common/state.qc
qcsrc/common/t_items.qc
qcsrc/common/t_items.qh
qcsrc/common/turrets/cl_turrets.qc
qcsrc/common/turrets/sv_turrets.qc
qcsrc/common/turrets/turret/ewheel.qc
qcsrc/common/turrets/turret/hk_weapon.qc
qcsrc/common/turrets/turret/walker.qc
qcsrc/common/vehicles/sv_vehicles.qc
qcsrc/common/vehicles/sv_vehicles.qh
qcsrc/common/vehicles/vehicle/bumblebee.qc
qcsrc/common/vehicles/vehicle/racer.qc
qcsrc/common/vehicles/vehicle/raptor.qc
qcsrc/common/vehicles/vehicle/raptor_weapons.qc
qcsrc/common/vehicles/vehicle/spiderbot.qc
qcsrc/common/weapons/weapon/arc.qc
qcsrc/common/weapons/weapon/devastator.qc
qcsrc/common/weapons/weapon/electro.qc
qcsrc/common/weapons/weapon/fireball.qc
qcsrc/common/weapons/weapon/hagar.qc
qcsrc/common/weapons/weapon/hook.qc
qcsrc/common/weapons/weapon/machinegun.qc
qcsrc/common/weapons/weapon/minelayer.qc
qcsrc/common/weapons/weapon/mortar.qc
qcsrc/common/weapons/weapon/seeker.qc
qcsrc/common/weapons/weapon/vaporizer.qc
qcsrc/ecs/systems/sv_physics.qc
qcsrc/lib/csqcmodel/cl_player.qc
qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc
qcsrc/menu/xonotic/keybinder.qc
qcsrc/server/_mod.inc
qcsrc/server/_mod.qh
qcsrc/server/bot/default/bot.qc
qcsrc/server/bot/default/havocbot/havocbot.qc
qcsrc/server/bot/default/havocbot/roles.qc
qcsrc/server/bot/default/navigation.qc
qcsrc/server/bot/default/scripting.qc
qcsrc/server/cheats.qc
qcsrc/server/client.qc
qcsrc/server/command/common.qc
qcsrc/server/command/sv_cmd.qc
qcsrc/server/compat/quake3.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_damage.qh
qcsrc/server/g_hook.qc
qcsrc/server/g_world.qc
qcsrc/server/mapvoting.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/events.qh
qcsrc/server/player.qc
qcsrc/server/player.qh
qcsrc/server/playerdemo.qc [deleted file]
qcsrc/server/playerdemo.qh [deleted file]
qcsrc/server/portals.qc
qcsrc/server/resources.qc
qcsrc/server/resources.qh
qcsrc/server/scores.qc
qcsrc/server/spawnpoints.qc
qcsrc/server/teamplay.qc
qcsrc/server/tests.qc
qcsrc/server/weapons/accuracy.qc
qcsrc/server/weapons/weaponsystem.qc
ruleset-XDF.cfg
ruleset-XPM.cfg
xonotic-client.cfg
xonotic-server.cfg

index e50392ca6a8e1c49df20f3465838b7a6052041c0..8243f0d9ba5af67ff036301b93dfb84e9510ca87 100644 (file)
@@ -29,7 +29,7 @@ test_sv_game:
     - wget -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints
     - wget -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache
     - make
-    - EXPECT=033546d32426e6409458fb39d0130f56
+    - EXPECT=de6a7d95ce65fb6c66558a93a9fb994f
     - HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
       | tee /dev/stderr
       | grep '^:'
index 9745f61361ea974460edaf8e9c90a96700d78cb1..ca7140deb4f39043ced90c760624d498c0f1b2a1 100644 (file)
@@ -1 +1 @@
-Sun Jun  3 07:24:16 CEST 2018
+Wed Jun 20 07:24:25 CEST 2018
index 9a1654f83abd1a177f392a12fd6d785ce883a706..30e5a8bee9a8756fe9fafe883306260e1e4025aa 100644 (file)
@@ -62,7 +62,7 @@ seta hud_panel_weapons_label "" "1 = show number of weapon, 2 = show bound key o
 seta hud_panel_weapons_label_scale "" "scale of the weapon text label"
 seta hud_panel_weapons_accuracy "" "show accuracy color as the weapon icon background; colors can be configured with accuracy_color* cvars"
 seta hud_panel_weapons_ammo "" "show ammo as a status bar"
-seta hud_panel_weapons_onlyowned "" "show only owned weapons"
+seta hud_panel_weapons_onlyowned "" "show only owned weapons, set it to 2 to show only the held weapon"
 seta hud_panel_weapons_noncurrent_alpha "" "alpha of noncurrent weapons"
 seta hud_panel_weapons_noncurrent_scale "" "scale of noncurrent weapons, relative to the current weapon"
 seta hud_panel_weapons_selection_radius "" "number of weapons that get partially highlighted on each side of the currently selected weapon"
index 9ed423c1c9b692443efe369e24fb8c8c76c67f85..d2ff12f6bc81cf2e13051600315fd4fb78f9c2ca 100644 (file)
@@ -256,13 +256,13 @@ set g_balance_crylink_primary_spread 0.08
 set g_balance_crylink_reload_ammo 0
 set g_balance_crylink_reload_time 2
 set g_balance_crylink_secondary 1
-set g_balance_crylink_secondary_ammo 2
+set g_balance_crylink_secondary_ammo 3
 set g_balance_crylink_secondary_animtime 0.2
 set g_balance_crylink_secondary_bouncedamagefactor 0.5
 set g_balance_crylink_secondary_bounces 0
-set g_balance_crylink_secondary_damage 8
-set g_balance_crylink_secondary_edgedamage 4
-set g_balance_crylink_secondary_force -200
+set g_balance_crylink_secondary_damage 50
+set g_balance_crylink_secondary_edgedamage 15
+set g_balance_crylink_secondary_force -400
 set g_balance_crylink_secondary_joindelay 0
 set g_balance_crylink_secondary_joinexplode 0
 set g_balance_crylink_secondary_joinexplode_damage 0
@@ -275,11 +275,11 @@ set g_balance_crylink_secondary_middle_fadetime 5
 set g_balance_crylink_secondary_middle_lifetime 5
 set g_balance_crylink_secondary_other_fadetime 5
 set g_balance_crylink_secondary_other_lifetime 5
-set g_balance_crylink_secondary_radius 100
-set g_balance_crylink_secondary_refire 0.7
-set g_balance_crylink_secondary_shots 5
+set g_balance_crylink_secondary_radius 70
+set g_balance_crylink_secondary_refire 0.8
+set g_balance_crylink_secondary_shots 1
 set g_balance_crylink_secondary_speed 3000
-set g_balance_crylink_secondary_spread 0.01
+set g_balance_crylink_secondary_spread 0
 set g_balance_crylink_secondary_spreadtype 1
 set g_balance_crylink_switchdelay_drop 0.2
 set g_balance_crylink_switchdelay_raise 0.2
@@ -459,7 +459,7 @@ set g_balance_vaporizer_switchdelay_raise 0.2
 set g_balance_vaporizer_weaponreplace ""
 set g_balance_vaporizer_weaponstart 0
 set g_balance_vaporizer_weaponstartoverride -1
-set g_balance_vaporizer_weaponthrowable 0
+set g_balance_vaporizer_weaponthrowable 1
 // }}}
 // {{{ #13: Grappling Hook
 set g_balance_hook_primary_ammo 5
@@ -753,7 +753,7 @@ set g_balance_arc_beam_heat 0
 set g_balance_arc_burst_heat 5
 set g_balance_arc_beam_maxangle 10
 set g_balance_arc_beam_nonplayerdamage 80
-set g_balance_arc_beam_range 1500
+set g_balance_arc_beam_range 1250
 set g_balance_arc_beam_refire 0.25
 set g_balance_arc_beam_returnspeed 8
 set g_balance_arc_beam_tightness 0.5
index 0e765b8a136cd83be6d5d0743421ac6b382f5fbf..b2edf84788332b7da31d681a318c19d6fd2e807d 100644 (file)
@@ -212,7 +212,6 @@ alias lockteams            "qc_cmd_sv     lockteams            ${* ?}" // Disabl
 alias make_mapinfo         "qc_cmd_sv     make_mapinfo         ${* ?}" // Automatically rebuild mapinfo files
 alias moveplayer           "qc_cmd_sv     moveplayer           ${* ?}" // Change the team/status of a player
 alias nospectators         "qc_cmd_sv     nospectators         ${* ?}" // Automatically remove spectators from a match
-alias playerdemo           "qc_cmd_sv     playerdemo           ${* ?}" // Control the ability to save demos of players
 alias printstats           "qc_cmd_sv     printstats           ${* ?}" // Dump eventlog player stats and other score information
 alias radarmap             "qc_cmd_sv     radarmap             ${* ?}" // Generate a radar image of the map
 alias reducematchtime      "qc_cmd_sv     reducematchtime      ${* ?}" // Decrease the timelimit value incrementally
index 0407c66068c4c65e014e05626a10c912e5e84130..4d65b27123a4b82371ab71c2651b0b7184ef1083 100644 (file)
@@ -4,9 +4,10 @@
 #
 # Translators:
 # Jisoo Lim <liminj0719@gmail.com>, 2017
-# Kyf Lee (coughingmouse) <coughingmouse@gmail.com>, 2016
-# Kyf Lee (coughingmouse) <coughingmouse@gmail.com>, 2016-2017
-# Kyf Lee (coughingmouse) <coughingmouse@gmail.com>, 2016-2017
+# Kyf Lee <coughingmouse@gmail.com>, 2016
+# Kyf Lee <coughingmouse@gmail.com>, 2016-2017
+# Kyf Lee <coughingmouse@gmail.com>, 2016-2017
+# Kyf Lee <coughingmouse@gmail.com>, 2016
 msgid ""
 msgstr ""
 "Project-Id-Version: Xonotic\n"
index 7319cba4e8d1d1d286261036a5da4b215e26364c..41b5fc5dbe745dd85c02b81e6ad2b3ac6d2a574f 100644 (file)
@@ -478,7 +478,7 @@ seta g_nexball_tackling 1 "Allow ball theft?"
 set g_onslaught 0 "Onslaught: take control points towards the enemy generator and then destroy it"
 set g_onslaught_point_limit 1 "Onslaught point limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
 set g_onslaught_warmup 5
-set g_onslaught_round_timelimit 280
+set g_onslaught_round_timelimit 500
 set g_onslaught_teleport_radius 200 "Allows teleporting from a control point to another"
 set g_onslaught_teleport_wait 5 "Time before player can teleport again"
 set g_onslaught_spawn_choose 1 "Allow players to choose the control point to be spawned at"
index a4c8144fc209b51b36863d5735b19522ca633408..afa17824980e02ddc6be90760b998ec8bfd8d1c5 100644 (file)
@@ -294,7 +294,7 @@ set g_campcheck_distance 1800
 // ==========
 set g_new_toys 0 "Mutator 'New Toys': enable extra fun guns"
 set g_new_toys_autoreplace 2 "0: never replace, 1: always auto replace guns by available new toys, 2: randomly auto replace guns by available new toys"
-set g_new_toys_use_pickupsound 1 "play the 'new toys, new toys!' roflsound when picking up a new toys weapon"
+set g_new_toys_use_pickupsound 0 "play the 'new toys, new toys!' roflsound when picking up a new toys weapon"
 
 
 // =======
index aa20961a2b1a60d8037567f340518922df69ebac..ab9184b9b9efccf44caaaa393a6bace1bf0f6e8e 100644 (file)
@@ -6,6 +6,7 @@
 #include <client/mapvoting.qc>
 #include <client/miscfunctions.qc>
 #include <client/player_skeleton.qc>
+#include <client/resources.qc>
 #include <client/shownames.qc>
 #include <client/teamradar.qc>
 #include <client/view.qc>
index ecfa4ee1a6751d0d97c68e4b8f646befab9d2bba..971cc01de6afaf6e3a002942cfac832a15b9d165 100644 (file)
@@ -6,6 +6,7 @@
 #include <client/mapvoting.qh>
 #include <client/miscfunctions.qh>
 #include <client/player_skeleton.qh>
+#include <client/resources.qh>
 #include <client/shownames.qh>
 #include <client/teamradar.qh>
 #include <client/view.qh>
index bcbe7244692eb85bb4c6c28fcf8e8c0b111fc252..0195db43a432e17e1e472155995451a8f703160d 100644 (file)
@@ -129,6 +129,9 @@ void Announcer_Gamestart()
 
 void Announcer_Time()
 {
+       if(intermission)
+               return;
+
        float timeleft;
        if(warmup_stage)
        {
index b6b33c3b1766670b0f8350b37236fa37bbb23da1..8eb3ca1dcb1a623111fc2a7a095d31ff946ebdc0 100644 (file)
@@ -344,7 +344,7 @@ float autocvar_hud_panel_weapons_complainbubble_padding;
 float autocvar_hud_panel_weapons_complainbubble_time;
 int autocvar_hud_panel_weapons_label;
 float autocvar_hud_panel_weapons_label_scale = 0.5;
-bool autocvar_hud_panel_weapons_onlyowned;
+int autocvar_hud_panel_weapons_onlyowned;
 float autocvar_hud_panel_weapons_noncurrent_alpha = 1;
 float autocvar_hud_panel_weapons_noncurrent_scale = 1;
 float autocvar_hud_panel_weapons_selection_radius = 0;
index 950dee17ad5ec77799cab431c5bc3229f13d58af..68d1e6bffabb1c327a75d5068b91a7cfd072683e 100644 (file)
@@ -86,8 +86,8 @@ const float BORDER_MULTIPLIER = 4;
 float scoreboard_bottom;
 int weapon_accuracy[Weapons_MAX];
 
-int complain_weapon;
-float complain_weapon_type;
+entity complain_weapon;
+int complain_weapon_type;
 float complain_weapon_time;
 
 PlayerScoreField ps_primary, ps_secondary;
index f0ec01c9e7b1847e68734896348da82b7658ad0f..bd94520d4e4292972e51277c0f27d6fc7fd7cd75 100644 (file)
@@ -6,6 +6,7 @@
 #include <common/ent_cs.qh>
 #include <common/mapinfo.qh>
 #include <client/mapvoting.qh>
+#include <client/resources.qh>
 #include <client/teamradar.qh>
 #include <common/mutators/mutator/waypoints/all.qh>
 
@@ -352,7 +353,7 @@ void HUD_Radar()
 
        IL_EACH(g_radaricons, it.teamradar_icon, {
                if ( hud_panel_radar_mouse )
-               if ( it.health >= 0 )
+               if ( GetResourceAmount(it, RESOURCE_HEALTH) >= 0 )
                if ( it.team == myteam + 1 || gametype == MAPINFO_TYPE_RACE || !teamplay )
                {
                        vector coord = teamradar_texcoord_to_2dcoord(teamradar_3dcoord_to_texcoord(it.origin));
index 4506f69a0c591b603d41ca4fa5f6a497581c071f..5d75c7dd2a4182fe19d9a4ec67d2940a3d877174 100644 (file)
@@ -108,7 +108,14 @@ void HUD_Weapons()
        }
 
        if(!autocvar_hud_panel_weapons_complainbubble || autocvar__hud_configure || time - complain_weapon_time >= when + fadetime)
-               complain_weapon = 0;
+               complain_weapon = NULL;
+
+       entity wepent = viewmodels[0]; // TODO: unhardcode
+
+       if (wepent.switchweapon == WEP_Null)
+               panel_switchweapon = NULL;
+       else if (!panel_switchweapon)
+               panel_switchweapon = wepent.switchweapon;
 
        if(autocvar__hud_configure)
        {
@@ -159,10 +166,18 @@ void HUD_Weapons()
 
                // do we own this weapon?
                weapon_count = 0;
-               for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
-                       if((weapons_stat & WepSet_FromWeapon(weaponorder[i])) || (weaponorder[i].m_id == complain_weapon))
-                               ++weapon_count;
-
+               if (autocvar_hud_panel_weapons_onlyowned >= 2) // only current
+               {
+                       for (i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
+                               if (weaponorder[i] == panel_switchweapon || weaponorder[i] == complain_weapon)
+                                       ++weapon_count;
+               }
+               else
+               {
+                       for (i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
+                               if ((weapons_stat & WepSet_FromWeapon(weaponorder[i])) || weaponorder[i] == complain_weapon)
+                                       ++weapon_count;
+               }
 
                // might as well commit suicide now, no reason to live ;)
                if (weapon_count == 0)
@@ -373,13 +388,6 @@ void HUD_Weapons()
                switch_speed = frametime * autocvar_hud_panel_weapons_selection_speed;
        vector radius_size = weapon_size * (autocvar_hud_panel_weapons_selection_radius + 1);
 
-       entity wepent = viewmodels[0]; // TODO: unhardcode
-
-       if(wepent.switchweapon == WEP_Null)
-               panel_switchweapon = NULL;
-       else if(!panel_switchweapon)
-               panel_switchweapon = wepent.switchweapon;
-
        // draw background behind currently selected weapon
        // do it earlier to make sure bg is drawn behind every weapon icons while it's moving
        if(panel_switchweapon)
@@ -395,10 +403,18 @@ void HUD_Weapons()
                if(!it || weapon_id < 0) { continue; }
 
                // skip this weapon if we don't own it (and onlyowned is enabled)-- or if weapons_complainbubble is showing for this weapon
-               if(autocvar_hud_panel_weapons_onlyowned)
+               if (autocvar_hud_panel_weapons_onlyowned)
                {
-                       if (!((weapons_stat & WepSet_FromWeapon(it)) || (it.m_id == complain_weapon)))
-                               continue;
+                       if (autocvar_hud_panel_weapons_onlyowned >= 2) // only current
+                       {
+                               if (!(it == panel_switchweapon || it == complain_weapon))
+                                       continue;
+                       }
+                       else
+                       {
+                               if (!((weapons_stat & WepSet_FromWeapon(it)) || (it == complain_weapon)))
+                                       continue;
+                       }
                }
                else
                {
@@ -518,7 +534,7 @@ void HUD_Weapons()
                }
 
                // draw the complain message
-               if(it.m_id == complain_weapon)
+               if(it == complain_weapon)
                {
                        if(fadetime)
                                a = ((complain_weapon_time + when > time) ? 1 : bound(0, (complain_weapon_time + when + fadetime - time) / fadetime, 1));
index 3de8cefeb661084515be0ebe365d88f73888ede5..218df18a474fc47746e8a928f77e164ecece995f 100644 (file)
@@ -1216,7 +1216,8 @@ NET_HANDLE(TE_CSQC_PINGPLREPORT, bool isNew)
 
 NET_HANDLE(TE_CSQC_WEAPONCOMPLAIN, bool isNew)
 {
-       complain_weapon = ReadByte();
+       int weapon_id = ReadByte();
+       complain_weapon = Weapons_from(weapon_id);
        complain_weapon_type = ReadByte();
        return = true;
 
@@ -1225,9 +1226,9 @@ NET_HANDLE(TE_CSQC_WEAPONCOMPLAIN, bool isNew)
 
        switch(complain_weapon_type)
        {
-               case 0: Local_Notification(MSG_MULTI, ITEM_WEAPON_NOAMMO, complain_weapon); break;
-               case 1: Local_Notification(MSG_MULTI, ITEM_WEAPON_DONTHAVE, complain_weapon); break;
-               default: Local_Notification(MSG_MULTI, ITEM_WEAPON_UNAVAILABLE, complain_weapon); break;
+               case 0: Local_Notification(MSG_MULTI, ITEM_WEAPON_NOAMMO, weapon_id); break;
+               case 1: Local_Notification(MSG_MULTI, ITEM_WEAPON_DONTHAVE, weapon_id); break;
+               default: Local_Notification(MSG_MULTI, ITEM_WEAPON_UNAVAILABLE, weapon_id); break;
        }
 }
 
index a95acd5739672b5fe096b1e2891220ab92fe3f40..69c3fa3d2b300eb4f54f6fd2a9bf4b8e68db62bf 100644 (file)
@@ -114,7 +114,6 @@ const int MAX_SPECTATORS = 7;
 int spectatorlist[MAX_SPECTATORS];
 
 int framecount;
-.float health;
 
 float GetSpeedUnitFactor(int speed_unit);
 string GetSpeedUnit(int speed_unit);
index f23a3976b55c6fcaba36a0ec2d5301f80ab0ba8f..0143d1a0134ac1720a49273a0bb87b408156ab54 100644 (file)
@@ -34,7 +34,7 @@ float PreviewExists(string name);
 vector Rotate(vector v, float a);
 
 
-#define IS_DEAD(s) (((s).classname == "csqcmodel") ? (s).csqcmodel_isdead : ((s).health <= 0))
+#define IS_DEAD(s) (((s).classname == "csqcmodel") ? (s).csqcmodel_isdead : (GetResourceAmount((s), RESOURCE_HEALTH) <= 0))
 
 
 // decolorizes and team colors the player name when needed
diff --git a/qcsrc/client/resources.qc b/qcsrc/client/resources.qc
new file mode 100644 (file)
index 0000000..285ebad
--- /dev/null
@@ -0,0 +1,87 @@
+#include "resources.qh"
+#include <common/items/item/ammo.qh>
+
+/// \file
+/// \brief Source file that contains implementation of the resource system.
+/// \copyright GNU GPLv2 or any later version.
+
+float GetResourceAmount(entity e, int resource_type)
+{
+       .float resource_field = GetResourceField(resource_type);
+       return e.(resource_field);
+}
+
+bool SetResourceAmountExplicit(entity e, int resource_type, float amount)
+{
+       .float resource_field = GetResourceField(resource_type);
+       if (e.(resource_field) != amount)
+       {
+               e.(resource_field) = amount;
+               return true;
+       }
+       return false;
+}
+
+void SetResourceAmount(entity e, int resource_type, float amount)
+{
+       SetResourceAmountExplicit(e, resource_type, amount);
+}
+
+void TakeResource(entity receiver, int resource_type, float amount)
+{
+       if (amount == 0)
+       {
+               return;
+       }
+       SetResourceAmount(receiver, resource_type,
+               GetResourceAmount(receiver, resource_type) - amount);
+}
+
+void TakeResourceWithLimit(entity receiver, int resource_type, float amount,
+       float limit)
+{
+       if (amount == 0)
+       {
+               return;
+       }
+       float current_amount = GetResourceAmount(receiver, resource_type);
+       if (current_amount - amount < limit)
+       {
+               amount = limit + current_amount;
+       }
+       TakeResource(receiver, resource_type, amount);
+}
+
+int GetResourceType(.float resource_field)
+{
+       switch (resource_field)
+       {
+               case health: { return RESOURCE_HEALTH; }
+               case armorvalue: { return RESOURCE_ARMOR; }
+               case ammo_shells: { return RESOURCE_SHELLS; }
+               case ammo_nails: { return RESOURCE_BULLETS; }
+               case ammo_rockets: { return RESOURCE_ROCKETS; }
+               case ammo_cells: { return RESOURCE_CELLS; }
+               case ammo_plasma: { return RESOURCE_PLASMA; }
+               case ammo_fuel: { return RESOURCE_FUEL; }
+       }
+       error("GetResourceType: Invalid field.");
+       return 0;
+}
+
+.float GetResourceField(int resource_type)
+{
+       switch (resource_type)
+       {
+               case RESOURCE_HEALTH: { return health; }
+               case RESOURCE_ARMOR: { return armorvalue; }
+               case RESOURCE_SHELLS: { return ammo_shells; }
+               case RESOURCE_BULLETS: { return ammo_nails; }
+               case RESOURCE_ROCKETS: { return ammo_rockets; }
+               case RESOURCE_CELLS: { return ammo_cells; }
+               case RESOURCE_PLASMA: { return ammo_plasma; }
+               case RESOURCE_FUEL: { return ammo_fuel; }
+       }
+       error("GetResourceField: Invalid resource type.");
+       return health;
+}
diff --git a/qcsrc/client/resources.qh b/qcsrc/client/resources.qh
new file mode 100644 (file)
index 0000000..3aaa8aa
--- /dev/null
@@ -0,0 +1,61 @@
+#pragma once
+
+/// \file
+/// \brief Header file that describes the resource system.
+/// \copyright GNU GPLv2 or any later version.
+
+#include <common/resources.qh>
+
+// ============================ Public API ====================================
+
+/// \brief Returns the current amount of resource the given entity has.
+/// \param[in] e Entity to check.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \return Current amount of resource the given entity has.
+float GetResourceAmount(entity e, int resource_type);
+
+/// \brief Sets the resource amount of an entity without calling any hooks.
+/// \param[in,out] e Entity to adjust.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to set.
+/// \return Boolean for whether the ammo amount was changed
+bool SetResourceAmountExplicit(entity e, int resource_type, float amount);
+
+/// \brief Sets the current amount of resource the given entity will have.
+/// \param[in,out] e Entity to adjust.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to set.
+/// \return No return.
+void SetResourceAmount(entity e, int resource_type, float amount);
+
+/// \brief Takes an entity some resource.
+/// \param[in,out] receiver Entity to take resource from.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to take.
+/// \return No return.
+void TakeResource(entity receiver, int resource_type, float amount);
+
+/// \brief Takes an entity some resource but not less than a limit.
+/// \param[in,out] receiver Entity to take resource from.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to take.
+/// \param[in] limit Limit of resources to take.
+/// \return No return.
+void TakeResourceWithLimit(entity receiver, int resource_type, float amount,
+       float limit);
+
+// ===================== Legacy and/or internal API ===========================
+
+/// \brief Converts an entity field to resource type.
+/// \param[in] resource_field Entity field to convert.
+/// \return Resource type (a RESOURCE_* constant).
+int GetResourceType(.float resource_field);
+
+/// \brief Converts resource type (a RESOURCE_* constant) to entity field.
+/// \param[in] resource_type Type of the resource.
+/// \return Entity field for that resource.
+.float GetResourceField(int resource_type);
+
+/// \brief Legacy fields for the resources. To be removed.
+.float health;
+.float armorvalue;
index 8a7d225bff7bdc319260e5e0648a2aaff9b7aa08..7c1ece5a3dc395c0afea7f4f2bfdfd8ab8519d4f 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "autocvars.qh"
 #include "miscfunctions.qh"
+#include "resources.qh"
 #include "hud/_mod.qh"
 
 #include <common/ent_cs.qh>
@@ -157,10 +158,10 @@ void Draw_ShowNames(entity this)
                                        this.healthvalue / autocvar_hud_panel_healtharmor_maxhealth, false, 1, '1 0 0', a,
                                        DRAWFLAG_NORMAL);
                        }
-                       if (this.armorvalue > 0)
+                       if (GetResourceAmount(this, RESOURCE_ARMOR) > 0)
                        {
                                HUD_Panel_DrawProgressBar(pos + eX * 0.5 * mySize.x, sz, "nametag_statusbar",
-                                       this.armorvalue / autocvar_hud_panel_healtharmor_maxarmor, false, 0, '0 1 0', a,
+                                       GetResourceAmount(this, RESOURCE_ARMOR) / autocvar_hud_panel_healtharmor_maxarmor, false, 0, '0 1 0', a,
                                        DRAWFLAG_NORMAL);
                        }
                }
@@ -193,13 +194,13 @@ void Draw_ShowNames_All()
                if (entcs.m_entcs_private)
                {
                        it.healthvalue = entcs.healthvalue;
-                       it.armorvalue = entcs.armorvalue;
+                       SetResourceAmountExplicit(it, RESOURCE_ARMOR, GetResourceAmount(entcs, RESOURCE_ARMOR));
                        it.sameteam = true;
                }
                else
                {
                        it.healthvalue = 0;
-                       it.armorvalue = 0;
+                       SetResourceAmountExplicit(it, RESOURCE_ARMOR, 0);
                        it.sameteam = false;
                }
                bool dead = entcs_IsDead(i) || entcs_IsSpectating(i);
index d036bd75df1b95e2552c59741658461796131d43..4d355fb2a177fd5fe102c19ff5b7783381abf227 100644 (file)
@@ -2057,7 +2057,7 @@ void CSQC_UpdateView(entity this, float w, float h)
 
        IL_EACH(g_drawables, it.draw, it.draw(it));
 
-       addentities(MASK_NORMAL | MASK_ENGINE | MASK_ENGINEVIEWMODELS);
+       addentities(MASK_NORMAL | MASK_ENGINE | MASK_ENGINEVIEWMODELS); // TODO: .health is used in cl_deathfade (a feature we have turned off currently)
        renderscene();
 
        // now switch to 2D drawing mode by calling a 2D drawing function
index 983b073b406c8cfb93de92a31002d5dd1359fa56..41c5d3017eada07992e8ba6ae102827da85525d4 100644 (file)
@@ -1,5 +1,9 @@
 #pragma once
 
+#ifdef CSQC
+#include <client/resources.qh>
+#endif
+
 
 // This includes some functions useful for debugging.
 // Some more bot-specific ones are in server/pathlib/debug.qc.
@@ -403,7 +407,7 @@ CLASS(DebugText3d, Object)
                CONSTRUCT(DebugText3d);
                this.origin = pos;
                this.message = strzone(msg);
-               this.health = align;
+               SetResourceAmount(this, RESOURCE_HEALTH, align);
                this.hit_time = time;
                this.fade_rate = fade_rate_;
                this.velocity = vel;
@@ -425,7 +429,7 @@ CLASS(DebugText3d, Object)
 
                int size = 8;
                vector screen_pos = project_3d_to_2d(this.origin) + since_created * this.velocity;
-               float align = this.health;
+               float align = GetResourceAmount(this, RESOURCE_HEALTH);
                if (align > 0)
                        screen_pos.x -= stringwidth(this.message, true, size * '1 1 0') * min(1, align);
                if (screen_pos.z < 0) return; // behind camera
index bbca691add0423059b1e6e86ee729725776fce17..86acdc154064ac6d0bc80258e7fca234d369740c 100644 (file)
@@ -1,5 +1,9 @@
 #include "ent_cs.qh"
 #include <common/gamemodes/_mod.qh>
+#include <common/resources.qh>
+#ifdef SVQC
+#include <server/resources.qh>
+#endif
 
 REGISTRY(EntCSProps, BITS(16) - 1)
 #define EntCSProps_from(i) _EntCSProps_from(i, NULL)
@@ -34,6 +38,26 @@ STATIC_INIT(RegisterEntCSProps_renumber) { FOREACH(EntCSProps, true, it.m_id = i
        }
 #endif
 
+#ifdef SVQC
+#define ENTCS_PROP_RESOURCE(id, ispublic, checkprop, setprop, svsend, clreceive) \
+       bool id##_check(entity ent, entity player) { return (GetResourceAmount(ent, checkprop) != GetResourceAmount(player, checkprop)); } \
+       void id##_set(entity ent, entity player) { SetResourceAmountExplicit(ent, checkprop, GetResourceAmount(player, checkprop)); } \
+       void id##_send(int chan, entity ent) { LAMBDA(svsend); } \
+       REGISTER(EntCSProps, ENTCS_PROP, id, m_id, new_pure(entcs_prop)) { \
+               this.m_public = ispublic; \
+               this.m_check = id##_check; \
+               this.m_set = id##_set; \
+               this.m_send = id##_send; \
+       }
+#elif defined(CSQC)
+#define ENTCS_PROP_RESOURCE(id, ispublic, checkprop, setprop, svsend, clreceive) \
+       void id##_receive(entity ent) { LAMBDA(clreceive); } \
+       REGISTER(EntCSProps, ENTCS_PROP, id, m_id, new_pure(entcs_prop)) { \
+               this.m_public = ispublic; \
+               this.m_receive = id##_receive; \
+       }
+#endif
+
 #define ENTCS_SET_NORMAL(var, x) MACRO_BEGIN \
        var = x; \
 MACRO_END
@@ -53,13 +77,13 @@ ENTCS_PROP(ANGLES, false, angles_y, ENTCS_SET_NORMAL,
        { WriteByte(chan, ent.angles.y / 360 * 256); },
        { vector v = '0 0 0'; v.y = ReadByte() / 256 * 360; ent.angles = v; })
 
-ENTCS_PROP(HEALTH, false, health, ENTCS_SET_NORMAL,
-       { WriteByte(chan, bound(0, ent.health / 10, 255));  /* FIXME: use a better scale? */ },
+ENTCS_PROP_RESOURCE(HEALTH, false, RESOURCE_HEALTH, ENTCS_SET_NORMAL,
+       { WriteByte(chan, bound(0, GetResourceAmount(ent, RESOURCE_HEALTH) / 10, 255));  /* FIXME: use a better scale? */ },
        { ent.healthvalue = ReadByte() * 10; })
 
-ENTCS_PROP(ARMOR, false, armorvalue, ENTCS_SET_NORMAL,
-       { WriteByte(chan, bound(0, ent.armorvalue / 10, 255));  /* FIXME: use a better scale? */ },
-       { ent.armorvalue = ReadByte() * 10; })
+ENTCS_PROP_RESOURCE(ARMOR, false, RESOURCE_ARMOR, ENTCS_SET_NORMAL,
+       { WriteByte(chan, bound(0, GetResourceAmount(ent, RESOURCE_ARMOR) / 10, 255));  /* FIXME: use a better scale? */ },
+       { SetResourceAmountExplicit(ent, RESOURCE_ARMOR, ReadByte() * 10); })
 
 ENTCS_PROP(NAME, true, netname, ENTCS_SET_MUTABLE_STRING,
        { WriteString(chan, ent.netname); },
index 1a9fff10cb4b1c54ce1f4bb7930365dffe9f7940..82af283d634e04be984f8a5e046fac2d22894b55 100644 (file)
@@ -19,7 +19,7 @@ STATIC_INIT(g_assault)
 void assault_objective_use(entity this, entity actor, entity trigger)
 {
        // activate objective
-       this.health = 100;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 100);
        //print("^2Activated objective ", this.targetname, "=", etos(this), "\n");
        //print("Activator is ", actor.classname, "\n");
 
@@ -31,7 +31,7 @@ void assault_objective_use(entity this, entity actor, entity trigger)
 
 vector target_objective_spawn_evalfunc(entity this, entity player, entity spot, vector current)
 {
-       if(this.health < 0 || this.health >= ASSAULT_VALUE_INACTIVE)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) < 0 || GetResourceAmount(this, RESOURCE_HEALTH) >= ASSAULT_VALUE_INACTIVE)
                return '-1 0 0';
        return current;
 }
@@ -40,7 +40,7 @@ vector target_objective_spawn_evalfunc(entity this, entity player, entity spot,
 // and when a new round starts
 void assault_objective_reset(entity this)
 {
-       this.health = ASSAULT_VALUE_INACTIVE;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, ASSAULT_VALUE_INACTIVE);
 }
 
 // decrease the health of targeted objectives
@@ -61,18 +61,18 @@ void assault_objective_decrease_use(entity this, entity actor, entity trigger)
        else
                return; // already activated! cannot activate again!
 
-       if(this.enemy.health < ASSAULT_VALUE_INACTIVE)
+       if(GetResourceAmount(this.enemy, RESOURCE_HEALTH) < ASSAULT_VALUE_INACTIVE)
        {
-               if(this.enemy.health - this.dmg > 0.5)
+               if(GetResourceAmount(this.enemy, RESOURCE_HEALTH) - this.dmg > 0.5)
                {
                        GameRules_scoring_add_team(actor, SCORE, this.dmg);
-                       this.enemy.health = this.enemy.health - this.dmg;
+                       TakeResource(this.enemy, RESOURCE_HEALTH, this.dmg);
                }
                else
                {
-                       GameRules_scoring_add_team(actor, SCORE, this.enemy.health);
+                       GameRules_scoring_add_team(actor, SCORE, GetResourceAmount(this.enemy, RESOURCE_HEALTH));
                        GameRules_scoring_add_team(actor, ASSAULT_OBJECTIVES, 1);
-                       this.enemy.health = -1;
+                       SetResourceAmountExplicit(this.enemy, RESOURCE_HEALTH, -1);
 
                        if(this.enemy.message)
                                FOREACH_CLIENT(IS_PLAYER(it), { centerprint(it, this.enemy.message); });
@@ -99,7 +99,7 @@ void assault_setenemytoobjective(entity this)
 
 bool assault_decreaser_sprite_visible(entity this, entity player, entity view)
 {
-       if(this.assault_decreaser.enemy.health >= ASSAULT_VALUE_INACTIVE)
+       if(GetResourceAmount(this.assault_decreaser.enemy, RESOURCE_HEALTH) >= ASSAULT_VALUE_INACTIVE)
                return false;
 
        return true;
@@ -127,7 +127,7 @@ void target_objective_decrease_activate(entity this)
                {
                        WaypointSprite_UpdateSprites(spr, WP_AssaultDefend, WP_AssaultDestroy, WP_AssaultDestroy);
                        WaypointSprite_UpdateMaxHealth(spr, it.max_health);
-                       WaypointSprite_UpdateHealth(spr, it.health);
+                       WaypointSprite_UpdateHealth(spr, GetResourceAmount(it, RESOURCE_HEALTH));
                        it.sprite = spr;
                }
                else
@@ -176,7 +176,7 @@ void assault_roundstart_use_this(entity this)
 
 void assault_wall_think(entity this)
 {
-       if(this.enemy.health < 0)
+       if(GetResourceAmount(this.enemy, RESOURCE_HEALTH) < 0)
        {
                this.model = "";
                this.solid = SOLID_NOT;
@@ -323,7 +323,7 @@ spawnfunc(target_objective_decrease)
                this.dmg = 101;
 
        this.use = assault_objective_decrease_use;
-       this.health = ASSAULT_VALUE_INACTIVE;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, ASSAULT_VALUE_INACTIVE);
        this.max_health = ASSAULT_VALUE_INACTIVE;
        this.enemy = NULL;
 
@@ -331,6 +331,21 @@ spawnfunc(target_objective_decrease)
 }
 
 // destructible walls that can be used to trigger target_objective_decrease
+bool destructible_heal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       if(targ.sprite)
+       {
+               WaypointSprite_UpdateHealth(targ.sprite, GetResourceAmount(targ, RESOURCE_HEALTH));
+       }
+       func_breakable_colormod(targ);
+       return true;
+}
+
 spawnfunc(func_breakable);
 spawnfunc(func_assault_destructible)
 {
@@ -338,6 +353,7 @@ spawnfunc(func_assault_destructible)
 
        this.spawnflags = 3;
        this.classname = "func_assault_destructible";
+       this.event_heal = destructible_heal;
        IL_PUSH(g_assault_destructibles, this);
 
        if(assault_attacker_team == NUM_TEAM_1)
@@ -395,7 +411,7 @@ void havocbot_goalrating_ast_targets(entity this, float ratingscale)
                entity destr = it;
                IL_EACH(g_assault_objectivedecreasers, it.targetname == destr.target,
                {
-                       if(it.enemy.health > 0 && it.enemy.health < ASSAULT_VALUE_INACTIVE)
+                       if(GetResourceAmount(it.enemy, RESOURCE_HEALTH) > 0 && GetResourceAmount(it.enemy, RESOURCE_HEALTH) < ASSAULT_VALUE_INACTIVE)
                        {
                                found = true;
                                break;
index 561129c7db70619c5636ed09f062ee0cc44dcadf..f4aea4357ddfc3fecd65e3feabafda49890c72e1 100644 (file)
@@ -96,7 +96,7 @@ float CA_CheckWinner()
 
 void CA_RoundStart()
 {
-    allowed_to_spawn = boolean(warmup_stage);
+       allowed_to_spawn = boolean(warmup_stage);
 }
 
 bool CA_CheckTeams()
@@ -164,7 +164,7 @@ entity CA_SpectateNext(entity player, entity start)
 
 MUTATOR_HOOKFUNCTION(ca, PlayerSpawn)
 {
-    entity player = M_ARGV(0, entity);
+       entity player = M_ARGV(0, entity);
 
        player.caplayer = 1;
        if (!warmup_stage)
@@ -220,7 +220,7 @@ MUTATOR_HOOKFUNCTION(ca, reset_map_players)
 
 MUTATOR_HOOKFUNCTION(ca, ClientConnect)
 {
-    entity player = M_ARGV(0, entity);
+       entity player = M_ARGV(0, entity);
 
        TRANSMUTE(Observer, player);
        return true;
@@ -253,8 +253,7 @@ entity ca_LastPlayerForTeam(entity this)
 
 void ca_LastPlayerForTeam_Notify(entity this)
 {
-       if (round_handler_IsActive())
-       if (round_handler_IsRoundStarted())
+       if (!warmup_stage && round_handler_IsActive() && round_handler_IsRoundStarted())
        {
                entity pl = ca_LastPlayerForTeam(this);
                if (pl)
@@ -275,15 +274,17 @@ MUTATOR_HOOKFUNCTION(ca, PlayerDies)
        }
        frag_target.respawn_flags |= RESPAWN_FORCE;
        if (!warmup_stage)
+       {
                eliminatedPlayers.SendFlags |= 1;
-       if(IS_BOT_CLIENT(frag_target))
-               bot_clear(frag_target);
+               if (IS_BOT_CLIENT(frag_target))
+                       bot_clear(frag_target);
+       }
        return true;
 }
 
 MUTATOR_HOOKFUNCTION(ca, ClientDisconnect)
 {
-    entity player = M_ARGV(0, entity);
+       entity player = M_ARGV(0, entity);
 
        if (player.caplayer == 1)
                ca_LastPlayerForTeam_Notify(player);
@@ -292,7 +293,7 @@ MUTATOR_HOOKFUNCTION(ca, ClientDisconnect)
 
 MUTATOR_HOOKFUNCTION(ca, MakePlayerObserver)
 {
-    entity player = M_ARGV(0, entity);
+       entity player = M_ARGV(0, entity);
 
        if (!IS_DEAD(player))
                ca_LastPlayerForTeam_Notify(player);
@@ -352,7 +353,7 @@ MUTATOR_HOOKFUNCTION(ca, Damage_Calculate)
 
 MUTATOR_HOOKFUNCTION(ca, FilterItem)
 {
-    entity item = M_ARGV(0, entity);
+       entity item = M_ARGV(0, entity);
 
        if (autocvar_g_powerups <= 0)
        if (item.flags & FL_POWERUP)
@@ -396,8 +397,8 @@ MUTATOR_HOOKFUNCTION(ca, Scores_CountFragsRemaining)
 
 MUTATOR_HOOKFUNCTION(ca, SpectateSet)
 {
-    entity client = M_ARGV(0, entity);
-    entity targ = M_ARGV(1, entity);
+       entity client = M_ARGV(0, entity);
+       entity targ = M_ARGV(1, entity);
 
        if (!autocvar_g_ca_spectate_enemies && client.caplayer)
        if (DIFF_TEAM(targ, client))
@@ -406,7 +407,7 @@ MUTATOR_HOOKFUNCTION(ca, SpectateSet)
 
 MUTATOR_HOOKFUNCTION(ca, SpectateNext)
 {
-    entity client = M_ARGV(0, entity);
+       entity client = M_ARGV(0, entity);
 
        if (!autocvar_g_ca_spectate_enemies && client.caplayer)
        {
@@ -418,9 +419,9 @@ MUTATOR_HOOKFUNCTION(ca, SpectateNext)
 
 MUTATOR_HOOKFUNCTION(ca, SpectatePrev)
 {
-    entity client = M_ARGV(0, entity);
-    entity targ = M_ARGV(1, entity);
-    entity first = M_ARGV(2, entity);
+       entity client = M_ARGV(0, entity);
+       entity targ = M_ARGV(1, entity);
+       entity first = M_ARGV(2, entity);
 
        if (!autocvar_g_ca_spectate_enemies && client.caplayer)
        {
@@ -453,7 +454,7 @@ MUTATOR_HOOKFUNCTION(ca, Bot_FixCount, CBC_ORDER_EXCLUSIVE)
 
 MUTATOR_HOOKFUNCTION(ca, ClientCommand_Spectate)
 {
-    entity player = M_ARGV(0, entity);
+       entity player = M_ARGV(0, entity);
 
        if (player.caplayer)
        {
index 92f64080e6d24e8be680e7e9ecd72dc555b4c337..25412be2a664fb6c4d17d22e067b49b05f691ea2 100644 (file)
@@ -147,7 +147,7 @@ void ctf_FlagcarrierWaypoints(entity player)
 {
        WaypointSprite_Spawn(WP_FlagCarrier, 0, 0, player, FLAG_WAYPOINT_OFFSET, NULL, player.team, player, wps_flagcarrier, true, RADARICON_FLAG);
        WaypointSprite_UpdateMaxHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id) * 2);
-       WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
+       WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(GetResourceAmount(player, RESOURCE_HEALTH), GetResourceAmount(player, RESOURCE_ARMOR), autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
        WaypointSprite_UpdateTeamRadar(player.wps_flagcarrier, RADARICON_FLAGCARRIER, WPCOLOR_FLAGCARRIER(player.team));
 
        if(player.flagcarried && CTF_SAMETEAM(player, player.flagcarried))
@@ -343,7 +343,7 @@ void ctf_Handle_Drop(entity flag, entity player, int droptype)
        set_movetype(flag, MOVETYPE_TOSS);
        flag.takedamage = DAMAGE_YES;
        flag.angles = '0 0 0';
-       flag.health = flag.max_flag_health;
+       SetResourceAmountExplicit(flag, RESOURCE_HEALTH, flag.max_flag_health);
        flag.ctf_droptime = time;
        flag.ctf_dropper = player;
        flag.ctf_status = FLAG_DROPPED;
@@ -366,7 +366,7 @@ void ctf_Handle_Drop(entity flag, entity player, int droptype)
        if(autocvar_g_ctf_flag_return_time || (autocvar_g_ctf_flag_return_damage && autocvar_g_ctf_flag_health))
        {
                WaypointSprite_UpdateMaxHealth(flag.wps_flagdropped, flag.max_flag_health);
-               WaypointSprite_UpdateHealth(flag.wps_flagdropped, flag.health);
+               WaypointSprite_UpdateHealth(flag.wps_flagdropped, GetResourceAmount(flag, RESOURCE_HEALTH));
        }
 
        player.throw_antispam = time + autocvar_g_ctf_pass_wait;
@@ -680,7 +680,7 @@ void ctf_Handle_Pickup(entity flag, entity player, int pickuptype)
        switch(pickuptype)
        {
                case PICKUP_BASE: flag.ctf_pickuptime = time; break; // used for timing runs
-               case PICKUP_DROPPED: flag.health = flag.max_flag_health; break; // reset health/return timelimit
+               case PICKUP_DROPPED: SetResourceAmountExplicit(flag, RESOURCE_HEALTH, flag.max_flag_health); break; // reset health/return timelimit
                default: break;
        }
 
@@ -762,9 +762,9 @@ void ctf_CheckFlagReturn(entity flag, int returntype)
 {
        if((flag.ctf_status == FLAG_DROPPED) || (flag.ctf_status == FLAG_PASSING))
        {
-               if(flag.wps_flagdropped) { WaypointSprite_UpdateHealth(flag.wps_flagdropped, flag.health); }
+               if(flag.wps_flagdropped) { WaypointSprite_UpdateHealth(flag.wps_flagdropped, GetResourceAmount(flag, RESOURCE_HEALTH)); }
 
-               if((flag.health <= 0) || (time >= flag.ctf_droptime + autocvar_g_ctf_flag_return_time))
+               if((GetResourceAmount(flag, RESOURCE_HEALTH) <= 0) || (time >= flag.ctf_droptime + autocvar_g_ctf_flag_return_time))
                {
                        switch(returntype)
                        {
@@ -875,7 +875,7 @@ void ctf_FlagDamage(entity this, entity inflictor, entity attacker, float damage
                        this.ctf_flagdamaged_byworld = true;
                else
                {
-                       this.health = 0;
+                       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0);
                        ctf_CheckFlagReturn(this, RETURN_NEEDKILL);
                }
                return;
@@ -883,7 +883,7 @@ void ctf_FlagDamage(entity this, entity inflictor, entity attacker, float damage
        if(autocvar_g_ctf_flag_return_damage)
        {
                // reduce health and check if it should be returned
-               this.health = this.health - damage;
+               TakeResource(this, RESOURCE_HEALTH, damage);
                ctf_CheckFlagReturn(this, RETURN_DAMAGE);
                return;
        }
@@ -946,20 +946,20 @@ void ctf_FlagThink(entity this)
                        {
                                if((vdist(this.origin - this.ctf_spawnorigin, <=, autocvar_g_ctf_flag_return_dropped)) || (autocvar_g_ctf_flag_return_dropped == -1))
                                {
-                                       this.health = 0;
+                                       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0);
                                        ctf_CheckFlagReturn(this, RETURN_DROPPED);
                                        return;
                                }
                        }
                        if(this.ctf_flagdamaged_byworld)
                        {
-                               this.health -= ((this.max_flag_health / autocvar_g_ctf_flag_return_damage_delay) * FLAG_THINKRATE);
+                               TakeResource(this, RESOURCE_HEALTH, ((this.max_flag_health / autocvar_g_ctf_flag_return_damage_delay) * FLAG_THINKRATE));
                                ctf_CheckFlagReturn(this, RETURN_NEEDKILL);
                                return;
                        }
                        else if(autocvar_g_ctf_flag_return_time)
                        {
-                               this.health -= ((this.max_flag_health / autocvar_g_ctf_flag_return_time) * FLAG_THINKRATE);
+                               TakeResource(this, RESOURCE_HEALTH, ((this.max_flag_health / autocvar_g_ctf_flag_return_time) * FLAG_THINKRATE));
                                ctf_CheckFlagReturn(this, RETURN_TIMEOUT);
                                return;
                        }
@@ -970,7 +970,7 @@ void ctf_FlagThink(entity this)
                {
                        if(this.speedrunning && ctf_captimerecord && (time >= this.ctf_pickuptime + ctf_captimerecord))
                        {
-                               this.health = 0;
+                               SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0);
                                ctf_CheckFlagReturn(this, RETURN_SPEEDRUN);
 
                                CS(this.owner).impulse = CHIMPULSE_SPEEDRUN.impulse; // move the player back to the waypoint they set
@@ -1039,7 +1039,7 @@ METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher))
        {
                if(!autocvar_g_ctf_flag_return_damage_delay)
                {
-                       flag.health = 0;
+                       SetResourceAmountExplicit(flag, RESOURCE_HEALTH, 0);
                        ctf_CheckFlagReturn(flag, RETURN_NEEDKILL);
                }
                if(!flag.ctf_flagdamaged_byworld) { return; }
@@ -1163,7 +1163,7 @@ void ctf_RespawnFlag(entity flag)
 
        set_movetype(flag, ((flag.noalign) ? MOVETYPE_NONE : MOVETYPE_TOSS));
        flag.takedamage = DAMAGE_NO;
-       flag.health = flag.max_flag_health;
+       SetResourceAmountExplicit(flag, RESOURCE_HEALTH, flag.max_flag_health);
        flag.solid = SOLID_TRIGGER;
        flag.velocity = '0 0 0';
        flag.angles = flag.mangle;
@@ -1250,7 +1250,7 @@ void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag e
        flag.takedamage = DAMAGE_NO;
        flag.damageforcescale = autocvar_g_ctf_flag_damageforcescale;
        flag.max_flag_health = ((autocvar_g_ctf_flag_return_damage && autocvar_g_ctf_flag_health) ? autocvar_g_ctf_flag_health : 100);
-       flag.health = flag.max_flag_health;
+       SetResourceAmountExplicit(flag, RESOURCE_HEALTH, flag.max_flag_health);
        flag.event_damage = ctf_FlagDamage;
        flag.pushable = true;
        flag.teleportable = TELEPORT_NORMAL;
@@ -2167,7 +2167,7 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerPreThink)
 
        // update the health of the flag carrier waypointsprite
        if(player.wps_flagcarrier)
-               WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
+               WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(GetResourceAmount(player, RESOURCE_HEALTH), GetResourceAmount(player, RESOURCE_ARMOR), autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
 }
 
 MUTATOR_HOOKFUNCTION(ctf, Damage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc
@@ -2195,7 +2195,7 @@ MUTATOR_HOOKFUNCTION(ctf, Damage_Calculate) // for changing damage and force val
        }
        else if(frag_target.flagcarried && !IS_DEAD(frag_target) && CTF_DIFFTEAM(frag_target, frag_attacker)) // if the target is a flagcarrier
        {
-               if(autocvar_g_ctf_flagcarrier_auto_helpme_damage > ('1 0 0' * healtharmor_maxdamage(frag_target.health, frag_target.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id)))
+               if(autocvar_g_ctf_flagcarrier_auto_helpme_damage > ('1 0 0' * healtharmor_maxdamage(GetResourceAmount(frag_target, RESOURCE_HEALTH), GetResourceAmount(frag_target, RESOURCE_ARMOR), autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id)))
                if(time > frag_target.wps_helpme_time + autocvar_g_ctf_flagcarrier_auto_helpme_time)
                {
                        frag_target.wps_helpme_time = time;
index 74a3993e35d3cff947e5f0f3e936682864475db8..2f9643b4a411df5af8e3b3b86e33198913f0c24b 100644 (file)
@@ -51,7 +51,8 @@ const float VEHICLE_FLAG_SCALE = 1.0;
 
 // waypoint colors
 #define WPCOLOR_ENEMYFC(t) ((t) ? colormapPaletteColor(t - 1, false) * 0.75 : '1 1 1')
-#define WPCOLOR_FLAGCARRIER(t) (WP_FlagCarrier.m_color)
+#define WPCOLOR_FLAGCARRIER(t) ((t) ? colormapPaletteColor(t - 1, false) * 0.75 : '1 1 1')
+//#define WPCOLOR_FLAGCARRIER(t) (WP_FlagCarrier.m_color)
 #define WPCOLOR_DROPPEDFLAG(t) ((t) ? ('0.25 0.25 0.25' + colormapPaletteColor(t - 1, false)) * 0.5 : '1 1 1')
 
 // sounds
index 12319c26cd66a01f505e76669e855668a7e85bfb..6190289347279b30c5d47d08c5da06c851fc1fbb 100644 (file)
@@ -74,7 +74,7 @@ void CTS_ClientKill(entity e) // silent version of ClientKill, used when player
     setthink(e.killindicator, KillIndicator_Think);
     e.killindicator.nextthink = time + (e.lip) * 0.05;
     e.killindicator.cnt = ceil(autocvar_g_cts_finish_kill_delay);
-    e.killindicator.health = 1; // this is used to indicate that it should be silent
+    e.killindicator.count = 1; // this is used to indicate that it should be silent
     e.lip = 0;
 }
 
@@ -386,7 +386,7 @@ MUTATOR_HOOKFUNCTION(cts, ClientKill)
 
        M_ARGV(1, float) = 0; // kill delay
 
-       if(player.killindicator && player.killindicator.health == 1) // player.killindicator.health == 1 means that the kill indicator was spawned by CTS_ClientKill
+       if(player.killindicator && player.killindicator.count == 1) // player.killindicator.count == 1 means that the kill indicator was spawned by CTS_ClientKill
        {
                delete(player.killindicator);
                player.killindicator = NULL;
index 067d5c0bfeff347a7877e5d75f9b66fb2ead7c2a..7575f946470a024630c1e8dd9fc5e8dfc68cfe6e 100644 (file)
@@ -188,9 +188,9 @@ void dompointthink(entity this)
 
 void dompointtouch(entity this, entity toucher)
 {
-       if (!IS_PLAYER(toucher))
+       if(!IS_PLAYER(toucher))
                return;
-       if (toucher.health < 1)
+       if(GetResourceAmount(toucher, RESOURCE_HEALTH) < 1)
                return;
 
        if(round_handler_IsActive() && !round_handler_IsRoundStarted())
index 50e3a815f4a8213a98a0cb7076d72371cd8a28a8..9205e8975457fa4160cc3df75d27cc782fd15cb7 100644 (file)
@@ -2,6 +2,8 @@
 
 // TODO: sv_freezetag
 #ifdef SVQC
+#include <server/resources.qh>
+
 float autocvar_g_freezetag_frozen_maxtime;
 float autocvar_g_freezetag_revive_clearspeed;
 float autocvar_g_freezetag_round_timelimit;
@@ -15,10 +17,10 @@ void freezetag_count_alive_players()
        FOREACH_CLIENT(IS_PLAYER(it), {
                switch(it.team)
                {
-                       case NUM_TEAM_1: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++redalive; break;
-                       case NUM_TEAM_2: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++bluealive; break;
-                       case NUM_TEAM_3: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++yellowalive; break;
-                       case NUM_TEAM_4: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++pinkalive; break;
+                       case NUM_TEAM_1: ++total_players; if(GetResourceAmount(it, RESOURCE_HEALTH) >= 1 && STAT(FROZEN, it) != 1) ++redalive; break;
+                       case NUM_TEAM_2: ++total_players; if(GetResourceAmount(it, RESOURCE_HEALTH) >= 1 && STAT(FROZEN, it) != 1) ++bluealive; break;
+                       case NUM_TEAM_3: ++total_players; if(GetResourceAmount(it, RESOURCE_HEALTH) >= 1 && STAT(FROZEN, it) != 1) ++yellowalive; break;
+                       case NUM_TEAM_4: ++total_players; if(GetResourceAmount(it, RESOURCE_HEALTH) >= 1 && STAT(FROZEN, it) != 1) ++pinkalive; break;
                }
        });
        FOREACH_CLIENT(IS_REAL_CLIENT(it), {
@@ -140,7 +142,7 @@ entity freezetag_LastPlayerForTeam(entity this)
 {
        entity last_pl = NULL;
        FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
-               if(it.health >= 1)
+               if(GetResourceAmount(it, RESOURCE_HEALTH) >= 1)
                if(!STAT(FROZEN, it))
                if(SAME_TEAM(it, this))
                if(!last_pl)
@@ -232,7 +234,7 @@ void havocbot_goalrating_freeplayers(entity this, float ratingscale, vector org,
                {
                        // If teamate is not frozen still seek them out as fight better
                        // in a group.
-                       t = 0.2 * 150 / (this.health + this.armorvalue);
+                       t = 0.2 * 150 / (GetResourceAmount(this, RESOURCE_HEALTH) + GetResourceAmount(this, RESOURCE_ARMOR));
                        navigation_routerating(this, it, t * ratingscale, 2000);
                }
        });
@@ -308,7 +310,7 @@ void havocbot_role_ft_freeing(entity this)
 
 void ft_RemovePlayer(entity this)
 {
-       this.health = 0; // neccessary to update correctly alive stats
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0); // neccessary to update correctly alive stats
        if(!STAT(FROZEN, this))
                freezetag_LastPlayerForTeam_Notify(this);
        freezetag_Unfreeze(this);
@@ -359,7 +361,7 @@ MUTATOR_HOOKFUNCTION(ft, PlayerDies)
                }
                else
                        freezetag_Unfreeze(frag_target); // remove ice
-               frag_target.health = 0; // Unfreeze resets health
+               SetResourceAmountExplicit(frag_target, RESOURCE_HEALTH, 0); // Unfreeze resets health
                frag_target.freezetag_frozen_timeout = -2; // freeze on respawn
                return true;
        }
@@ -468,7 +470,7 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
        if(n && STAT(FROZEN, player) == 1) // OK, there is at least one teammate reviving us
        {
                STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
-               player.health = max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health));
+               SetResourceAmountExplicit(player, RESOURCE_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health)));
 
                if(STAT(REVIVE_PROGRESS, player) >= 1)
                {
@@ -502,7 +504,7 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
        else if(!n && STAT(FROZEN, player) == 1) // only if no teammate is nearby will we reset
        {
                STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) - frametime * autocvar_g_freezetag_revive_clearspeed, 1);
-               player.health = max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health));
+               SetResourceAmountExplicit(player, RESOURCE_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health)));
        }
        else if(!n && !STAT(FROZEN, player))
        {
@@ -564,7 +566,8 @@ MUTATOR_HOOKFUNCTION(ft, FragCenterMessage)
                return; // target was already frozen, so this is just pushing them off the cliff
 
        Send_Notification(NOTIF_ONE, frag_attacker, MSG_CHOICE, CHOICE_FRAG_FREEZE, frag_target.netname, kill_count_to_attacker, (IS_BOT_CLIENT(frag_target) ? -1 : CS(frag_target).ping));
-       Send_Notification(NOTIF_ONE, frag_target, MSG_CHOICE, CHOICE_FRAGGED_FREEZE, frag_attacker.netname, kill_count_to_target, frag_attacker.health, frag_attacker.armorvalue, (IS_BOT_CLIENT(frag_attacker) ? -1 : CS(frag_attacker).ping));
+       Send_Notification(NOTIF_ONE, frag_target, MSG_CHOICE, CHOICE_FRAGGED_FREEZE, frag_attacker.netname, kill_count_to_target, 
+                                                                               GetResourceAmount(frag_attacker, RESOURCE_HEALTH), GetResourceAmount(frag_attacker, RESOURCE_ARMOR), (IS_BOT_CLIENT(frag_attacker) ? -1 : CS(frag_attacker).ping));
 
        return true;
 }
index d6f9860c9874f17c1665edeed78d78d48570bd3a..3dff701959ef82c11f8f7e205daa3abfeb6af14b 100644 (file)
@@ -290,7 +290,7 @@ bool Invasion_CheckWinner()
 
        float total_alive_monsters = 0, supermonster_count = 0, red_alive = 0, blue_alive = 0, yellow_alive = 0, pink_alive = 0;
 
-       IL_EACH(g_monsters, it.health > 0,
+       IL_EACH(g_monsters, GetResourceAmount(it, RESOURCE_HEALTH) > 0,
        {
                if((get_monsterinfo(it.monsterid)).spawnflags & MON_FLAG_SUPERMONSTER)
                        ++supermonster_count;
index ac4c5a67523331da2fcd5c7afc6e06c9a9004026..fc2793bcabdfa7c445fbb5c525a02051dcc5cf8c 100644 (file)
@@ -222,7 +222,7 @@ void havocbot_goalrating_ball(entity this, float ratingscale, vector org)
        // If ball is carried by player then hunt them down.
        if (ball_owner)
        {
-               t = (this.health + this.armorvalue) / (ball_owner.health + ball_owner.armorvalue);
+               t = (GetResourceAmount(this, RESOURCE_HEALTH) + GetResourceAmount(this, RESOURCE_ARMOR)) / (GetResourceAmount(ball_owner, RESOURCE_HEALTH) + GetResourceAmount(ball_owner, RESOURCE_ARMOR));
                navigation_routerating(this, ball_owner, t * ratingscale, 2000);
        }
        else // Ball has been dropped so collect.
index 426b341a63a077b1316305a435d0975241b490ea..487012aa50902e7a834fdd708a7c0e45bb2928cc 100644 (file)
@@ -308,7 +308,7 @@ void football_touch(entity this, entity toucher)
        }
        if (!IS_PLAYER(toucher))
                return;
-       if(toucher.health < 1)
+       if(GetResourceAmount(toucher, RESOURCE_HEALTH) < 1)
                return;
        if(!this.cnt)
                this.nextthink = time + autocvar_g_nexball_delay_idle;
@@ -348,7 +348,7 @@ void basketball_touch(entity this, entity toucher)
        }
        if(!this.cnt && IS_PLAYER(toucher) && !STAT(FROZEN, toucher) && !IS_DEAD(toucher) && (toucher != this.nb_dropper || time > this.nb_droptime + autocvar_g_nexball_delay_collect))
        {
-               if(toucher.health <= 0)
+               if(GetResourceAmount(toucher, RESOURCE_HEALTH) < 1)
                        return;
                LogNB("caught", toucher);
                GiveBall(toucher, this);
index a03e5b3353f8b6156eac2d8012ff5e0af9d2c96a..b8d49b10f2edce3580b517f2556a95f35fd092f7 100644 (file)
@@ -30,7 +30,7 @@ void cpicon_draw(entity this)
        this.cp_bob_spd = this.cp_bob_spd + 1.875 * frametime;
        this.colormod = '1 1 1' * (2 - bound(0, (this.pain_finished - time) / 10, 1));
 
-       if(!this.iscaptured) this.alpha = this.health / this.max_health;
+       if(!this.iscaptured) this.alpha = GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health;
 
        if(this.iscaptured)
        {
@@ -165,14 +165,14 @@ NET_HANDLE(ENT_CLIENT_CONTROLPOINT_ICON, bool isnew)
                this.origin = ReadVector();
                setorigin(this, this.origin);
 
-               this.health = ReadByte();
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, ReadByte());
                this.max_health = ReadByte();
                this.count = ReadByte();
                this.team = ReadByte();
                this.iscaptured = ReadByte();
 
                if(!this.count)
-                       this.count = (this.health - this.max_health) * frametime;
+                       this.count = (GetResourceAmount(this, RESOURCE_HEALTH) - this.max_health) * frametime;
 
                cpicon_changeteam(this);
                cpicon_construct(this, isnew);
@@ -189,9 +189,9 @@ NET_HANDLE(ENT_CLIENT_CONTROLPOINT_ICON, bool isnew)
 
                _tmp = ReadByte();
 
-               if(_tmp != this.health)
+               if(_tmp != GetResourceAmount(this, RESOURCE_HEALTH))
                        cpicon_damage(this, _tmp);
 
-               this.health = _tmp;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, _tmp);
        }
 }
index a3374bf91e804f4db0ae4993eb107349d3c72411..9d12c5548e6d4eafd4abdb336b6aa7208274bda3 100644 (file)
@@ -48,10 +48,10 @@ void generator_draw(entity this)
        if(time < this.move_time)
                return;
 
-       if(this.health > 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) > 0)
        {
                // damaged fx (less probable the more damaged is the generator)
-               if(random() < 0.9 - this.health / this.max_health)
+               if(random() < 0.9 - GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health)
                if(random() < 0.01)
                {
                        pointparticles(EFFECT_ELECTRO_BALLEXPLODE, this.origin + randompos('-50 -50 -20', '50 50 50'), '0 0 0', 1);
@@ -195,7 +195,7 @@ NET_HANDLE(ENT_CLIENT_GENERATOR, bool isnew)
                this.origin = ReadVector();
                setorigin(this, this.origin);
 
-               this.health = ReadByte();
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, ReadByte());
                this.max_health = ReadByte();
                this.count = ReadByte();
                this.team = ReadByte();
@@ -219,9 +219,9 @@ NET_HANDLE(ENT_CLIENT_GENERATOR, bool isnew)
 
                _tmp = ReadByte();
 
-               if(_tmp != this.health)
+               if(_tmp != GetResourceAmount(this, RESOURCE_HEALTH))
                        generator_damage(this, _tmp);
 
-               this.health = _tmp;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, _tmp);
        }
 }
index 80d6a6be29fa146940ccf242cfddb9c90413e2ea..5deef7ec22e01351ebf2f8b3796cd4c47b39f3d6 100644 (file)
@@ -36,7 +36,7 @@ MUTATOR_HOOKFUNCTION(cl_ons, WantEventchase)
        entity gen = NULL;
        if(ons_roundlost)
        {
-               IL_EACH(g_onsgenerators, it.health <= 0,
+               IL_EACH(g_onsgenerators, GetResourceAmount(it, RESOURCE_HEALTH) <= 0,
                {
                        gen = it;
                        break;
index d3b6d5c7f4c09f62d510db50b61c79685f1847b0..a00af18ff83119b0c991312fefdf3c8f981f0ec2 100644 (file)
@@ -12,7 +12,7 @@ bool cpicon_send(entity this, entity to, int sf)
        {
                WriteVector(MSG_ENTITY, this.origin);
 
-               WriteByte(MSG_ENTITY, this.health);
+               WriteByte(MSG_ENTITY, GetResourceAmount(this, RESOURCE_HEALTH));
                WriteByte(MSG_ENTITY, this.max_health);
                WriteByte(MSG_ENTITY, this.count);
                WriteByte(MSG_ENTITY, this.team);
@@ -23,10 +23,10 @@ bool cpicon_send(entity this, entity to, int sf)
        {
                WriteByte(MSG_ENTITY, this.team);
 
-               if(this.health <= 0)
+               if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                        WriteByte(MSG_ENTITY, 0);
                else
-                       WriteByte(MSG_ENTITY, ceil((this.health / this.max_health) * 255));
+                       WriteByte(MSG_ENTITY, ceil((GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health) * 255));
        }
 
        return true;
index ac0596f2e2a5abfb3c9c21603b2a29652a31994d..a33a4301249c1dd67ef06ddf6b0dd445570d893e 100644 (file)
@@ -8,7 +8,7 @@ bool generator_send(entity this, entity to, int sf)
        {
                WriteVector(MSG_ENTITY, this.origin);
 
-               WriteByte(MSG_ENTITY, this.health);
+               WriteByte(MSG_ENTITY, GetResourceAmount(this, RESOURCE_HEALTH));
                WriteByte(MSG_ENTITY, this.max_health);
                WriteByte(MSG_ENTITY, this.count);
                WriteByte(MSG_ENTITY, this.team);
@@ -18,10 +18,10 @@ bool generator_send(entity this, entity to, int sf)
        {
                WriteByte(MSG_ENTITY, this.team);
 
-               if(this.health <= 0)
+               if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                        WriteByte(MSG_ENTITY, 0);
                else
-                       WriteByte(MSG_ENTITY, ceil((this.health / this.max_health) * 255));
+                       WriteByte(MSG_ENTITY, ceil((GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health) * 255));
        }
 
        return true;
index 85d4bef62840c98dd80b008f035012e44a08132b..7258a190ea77730cd2482ba388340c1fe4787b7e 100644 (file)
@@ -400,11 +400,11 @@ void ons_ControlPoint_Icon_Damage(entity this, entity inflictor, entity attacker
                ons_notification_time[this.team] = time;
        }
 
-       this.health = this.health - damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
        if(this.owner.iscaptured)
-               WaypointSprite_UpdateHealth(this.owner.sprite, this.health);
+               WaypointSprite_UpdateHealth(this.owner.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
        else
-               WaypointSprite_UpdateBuildFinished(this.owner.sprite, time + (this.max_health - this.health) / (this.count / ONS_CP_THINKRATE));
+               WaypointSprite_UpdateBuildFinished(this.owner.sprite, time + (this.max_health - GetResourceAmount(this, RESOURCE_HEALTH)) / (this.count / ONS_CP_THINKRATE));
        this.pain_finished = time + 1;
        // particles on every hit
        pointparticles(EFFECT_SPARKS, hitloc, force*-1, 1);
@@ -414,7 +414,7 @@ void ons_ControlPoint_Icon_Damage(entity this, entity inflictor, entity attacker
        else
                sound(this, CH_TRIGGER, SND_ONS_HIT2, VOL_BASE+0.3, ATTEN_NORM);
 
-       if (this.health < 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) < 0)
        {
                sound(this, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
                pointparticles(EFFECT_ROCKET_EXPLODE, this.origin, '0 0 0', 1);
@@ -447,6 +447,21 @@ void ons_ControlPoint_Icon_Damage(entity this, entity inflictor, entity attacker
        this.SendFlags |= CPSF_STATUS;
 }
 
+bool ons_ControlPoint_Icon_Heal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       if(targ.owner.iscaptured)
+               WaypointSprite_UpdateHealth(targ.owner.sprite, GetResourceAmount(targ, RESOURCE_HEALTH));
+       else
+               WaypointSprite_UpdateBuildFinished(targ.owner.sprite, time + (targ.max_health - GetResourceAmount(targ, RESOURCE_HEALTH)) / (targ.count / ONS_CP_THINKRATE));
+       targ.SendFlags |= CPSF_STATUS;
+       return true;
+}
+
 void ons_ControlPoint_Icon_Think(entity this)
 {
        this.nextthink = time + ONS_CP_THINKRATE;
@@ -469,9 +484,9 @@ void ons_ControlPoint_Icon_Think(entity this)
                _friendly_count = _friendly_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
                _enemy_count = _enemy_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
 
-               this.health = bound(0, this.health + (_friendly_count - _enemy_count), this.max_health);
+               GiveResourceWithLimit(this, RESOURCE_HEALTH, (_friendly_count - _enemy_count), this.max_health);
                this.SendFlags |= CPSF_STATUS;
-               if(this.health <= 0)
+               if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                {
                        ons_ControlPoint_Icon_Damage(this, this, this, 1, 0, DMG_NOWEP, this.origin, '0 0 0');
                        return;
@@ -480,12 +495,10 @@ void ons_ControlPoint_Icon_Think(entity this)
 
        if (time > this.pain_finished + 5)
        {
-               if(this.health < this.max_health)
+               if(GetResourceAmount(this, RESOURCE_HEALTH) < this.max_health)
                {
-                       this.health = this.health + this.count;
-                       if (this.health >= this.max_health)
-                               this.health = this.max_health;
-                       WaypointSprite_UpdateHealth(this.owner.sprite, this.health);
+                       GiveResourceWithLimit(this, RESOURCE_HEALTH, this.count, this.max_health);
+                       WaypointSprite_UpdateHealth(this.owner.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
                }
        }
 
@@ -504,7 +517,7 @@ void ons_ControlPoint_Icon_Think(entity this)
        }
 
        // damaged fx
-       if(random() < 0.6 - this.health / this.max_health)
+       if(random() < 0.6 - GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health)
        {
                Send_Effect(EFFECT_ELECTRIC_SPARKS, this.origin + randompos('-10 -10 -20', '10 10 20'), '0 0 0', 1);
 
@@ -526,13 +539,13 @@ void ons_ControlPoint_Icon_BuildThink(entity this)
        if(!a)
                return;
 
-       this.health = this.health + this.count;
+       GiveResource(this, RESOURCE_HEALTH, this.count);
 
        this.SendFlags |= CPSF_STATUS;
 
-       if (this.health >= this.max_health)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) >= this.max_health)
        {
-               this.health = this.max_health;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
                this.count = autocvar_g_onslaught_cp_regen * ONS_CP_THINKRATE; // slow repair rate from now on
                setthink(this, ons_ControlPoint_Icon_Think);
                sound(this, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILT, VOL_BASE, ATTEN_NORM);
@@ -542,7 +555,7 @@ void ons_ControlPoint_Icon_BuildThink(entity this)
                Send_Effect(EFFECT_CAP(this.owner.team), this.owner.origin, '0 0 0', 1);
 
                WaypointSprite_UpdateMaxHealth(this.owner.sprite, this.max_health);
-               WaypointSprite_UpdateHealth(this.owner.sprite, this.health);
+               WaypointSprite_UpdateHealth(this.owner.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
 
                if(IS_PLAYER(this.owner.ons_toucher))
                {
@@ -565,7 +578,7 @@ void ons_ControlPoint_Icon_BuildThink(entity this)
        if(this.owner.model != MDL_ONS_CP_PAD2.model_str())
                setmodel_fixsize(this.owner, MDL_ONS_CP_PAD2);
 
-       if(random() < 0.9 - this.health / this.max_health)
+       if(random() < 0.9 - GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health)
                Send_Effect(EFFECT_RAGE, this.origin + 10 * randomvec(), '0 0 -1', 1);
 }
 
@@ -580,15 +593,16 @@ void ons_ControlPoint_Icon_Spawn(entity cp, entity player)
 
        e.owner = cp;
        e.max_health = autocvar_g_onslaught_cp_health;
-       e.health = autocvar_g_onslaught_cp_buildhealth;
+       SetResourceAmountExplicit(e, RESOURCE_HEALTH, autocvar_g_onslaught_cp_buildhealth);
        e.solid = SOLID_NOT;
        e.takedamage = DAMAGE_AIM;
        e.bot_attack = true;
        IL_PUSH(g_bot_targets, e);
        e.event_damage = ons_ControlPoint_Icon_Damage;
+       e.event_heal = ons_ControlPoint_Icon_Heal;
        e.team = player.team;
        e.colormap = 1024 + (e.team - 1) * 17;
-       e.count = (e.max_health - e.health) * ONS_CP_THINKRATE / autocvar_g_onslaught_cp_buildtime; // how long it takes to build
+       e.count = (e.max_health - GetResourceAmount(e, RESOURCE_HEALTH)) * ONS_CP_THINKRATE / autocvar_g_onslaught_cp_buildtime; // how long it takes to build
 
        sound(e, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILD, VOL_BASE, ATTEN_NORM);
 
@@ -598,7 +612,7 @@ void ons_ControlPoint_Icon_Spawn(entity cp, entity player)
 
        Send_Effect(EFFECT_FLAG_TOUCH(player.team), e.origin, '0 0 0', 1);
 
-       WaypointSprite_UpdateBuildFinished(cp.sprite, time + (e.max_health - e.health) / (e.count / ONS_CP_THINKRATE));
+       WaypointSprite_UpdateBuildFinished(cp.sprite, time + (e.max_health - GetResourceAmount(e, RESOURCE_HEALTH)) / (e.count / ONS_CP_THINKRATE));
        WaypointSprite_UpdateRule(cp.sprite,cp.team,SPRITERULE_TEAMPLAY);
        cp.sprite.SendFlags |= 16;
 
@@ -640,7 +654,7 @@ void ons_ControlPoint_UpdateSprite(entity e)
                        else
                        {
                                WaypointSprite_UpdateMaxHealth(e.sprite, e.goalentity.max_health);
-                               WaypointSprite_UpdateHealth(e.sprite, e.goalentity.health);
+                               WaypointSprite_UpdateHealth(e.sprite, GetResourceAmount(e.goalentity, RESOURCE_HEALTH));
                        }
                }
                if(e.lastshielded)
@@ -889,14 +903,14 @@ void ons_GeneratorDamage(entity this, entity inflictor, entity attacker, float d
                        play2team(this.team, SND(ONS_GENERATOR_UNDERATTACK));
                }
        }
-       this.health = this.health - damage;
-       WaypointSprite_UpdateHealth(this.sprite, this.health);
+       TakeResource(this, RESOURCE_HEALTH, damage);
+       WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
        // choose an animation frame based on health
-       this.frame = 10 * bound(0, (1 - this.health / this.max_health), 1);
+       this.frame = 10 * bound(0, (1 - GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health), 1);
        // see if the generator is still functional, or dying
-       if (this.health > 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) > 0)
        {
-               this.lasthealth = this.health;
+               this.lasthealth = GetResourceAmount(this, RESOURCE_HEALTH);
        }
        else
        {
@@ -912,6 +926,7 @@ void ons_GeneratorDamage(entity this, entity inflictor, entity attacker, float d
                this.isshielded = false;
                this.takedamage = DAMAGE_NO; // can't be hurt anymore
                this.event_damage = func_null; // won't do anything if hurt
+               this.event_heal = func_null;
                this.count = 0; // reset counter
                setthink(this, func_null);
                this.nextthink = 0;
@@ -946,31 +961,46 @@ void ons_GeneratorDamage(entity this, entity inflictor, entity attacker, float d
        this.SendFlags |= GSF_STATUS;
 }
 
+bool ons_GeneratorHeal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       WaypointSprite_UpdateHealth(targ.sprite, GetResourceAmount(targ, RESOURCE_HEALTH));
+       targ.frame = 10 * bound(0, (1 - GetResourceAmount(targ, RESOURCE_HEALTH) / targ.max_health), 1);
+       targ.lasthealth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       targ.SendFlags |= GSF_STATUS;
+       return true;
+}
+
 void ons_GeneratorThink(entity this)
 {
        this.nextthink = time + GEN_THINKRATE;
-       if (!game_stopped)
+
+       if (game_stopped || this.isshielded || time < this.wait)
+               return;
+
+       this.wait = time + 5;
+       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it),
        {
-               if(!this.isshielded && this.wait < time)
+               if (SAME_TEAM(it, this))
                {
-                       this.wait = time + 5;
-                       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
-                               if(SAME_TEAM(it, this))
-                               {
-                                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_ONS_NOTSHIELDED_TEAM);
-                                       soundto(MSG_ONE, it, CHAN_AUTO, SND(KH_ALARM), VOL_BASE, ATTEN_NONE);    // FIXME: unique sound?
-                               }
-                               else
-                                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_TEAM_NUM(this.team, CENTER_ONS_NOTSHIELDED));
-                       });
+                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_ONS_NOTSHIELDED_TEAM);
+                       msg_entity = it;
+                       soundto(MSG_ONE, this, CHAN_AUTO, SND(KH_ALARM), VOL_BASE, ATTEN_NONE); // FIXME: unique sound?
                }
-       }
+               else
+                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_TEAM_NUM(this.team, CENTER_ONS_NOTSHIELDED));
+       });
 }
 
 void ons_GeneratorReset(entity this)
 {
        this.team = this.team_saved;
-       this.lasthealth = this.max_health = this.health = autocvar_g_onslaught_gen_health;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, autocvar_g_onslaught_gen_health);
+       this.lasthealth = this.max_health = autocvar_g_onslaught_gen_health;
        this.takedamage = DAMAGE_AIM;
        this.bot_attack = true;
        if(!IL_CONTAINS(g_bot_targets, this))
@@ -979,6 +1009,7 @@ void ons_GeneratorReset(entity this)
        this.islinked = true;
        this.isshielded = true;
        this.event_damage = ons_GeneratorDamage;
+       this.event_heal = ons_GeneratorHeal;
        setthink(this, ons_GeneratorThink);
        this.nextthink = time + GEN_THINKRATE;
 
@@ -988,7 +1019,7 @@ void ons_GeneratorReset(entity this)
        this.SendFlags |= GSF_STATUS;
 
        WaypointSprite_UpdateMaxHealth(this.sprite, this.max_health);
-       WaypointSprite_UpdateHealth(this.sprite, this.health);
+       WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
        WaypointSprite_UpdateRule(this.sprite,this.team,SPRITERULE_TEAMPLAY);
 
        onslaught_updatelinks();
@@ -1035,11 +1066,13 @@ void ons_GeneratorSetup(entity gen) // called when spawning a generator entity o
        gen.team_saved = teamnumber;
        IL_PUSH(g_saved_team, gen);
        set_movetype(gen, MOVETYPE_NONE);
-       gen.lasthealth = gen.max_health = gen.health = autocvar_g_onslaught_gen_health;
+       gen.lasthealth = gen.max_health = autocvar_g_onslaught_gen_health;
+       SetResourceAmountExplicit(gen, RESOURCE_HEALTH, autocvar_g_onslaught_gen_health);
        gen.takedamage = DAMAGE_AIM;
        gen.bot_attack = true;
        IL_PUSH(g_bot_targets, gen);
        gen.event_damage = ons_GeneratorDamage;
+       gen.event_heal = ons_GeneratorHeal;
        gen.reset = ons_GeneratorReset;
        setthink(gen, ons_GeneratorThink);
        gen.nextthink = time + GEN_THINKRATE;
@@ -1061,7 +1094,7 @@ void ons_GeneratorSetup(entity gen) // called when spawning a generator entity o
        WaypointSprite_SpawnFixed(WP_Null, gen.origin + CPGEN_WAYPOINT_OFFSET, gen, sprite, RADARICON_NONE);
        WaypointSprite_UpdateRule(gen.sprite, gen.team, SPRITERULE_TEAMPLAY);
        WaypointSprite_UpdateMaxHealth(gen.sprite, gen.max_health);
-       WaypointSprite_UpdateHealth(gen.sprite, gen.health);
+       WaypointSprite_UpdateHealth(gen.sprite, GetResourceAmount(gen, RESOURCE_HEALTH));
 
        InitializeEntity(gen, ons_DelayedGeneratorSetup, INITPRIO_SETLOCATION);
 }
@@ -1079,10 +1112,10 @@ void Onslaught_count_generators()
        for(e = ons_worldgeneratorlist; e; e = e.ons_worldgeneratornext)
        {
                ++total_generators;
-               redowned += (e.team == NUM_TEAM_1 && e.health > 0);
-               blueowned += (e.team == NUM_TEAM_2 && e.health > 0);
-               yellowowned += (e.team == NUM_TEAM_3 && e.health > 0);
-               pinkowned += (e.team == NUM_TEAM_4 && e.health > 0);
+               redowned += (e.team == NUM_TEAM_1 && GetResourceAmount(e, RESOURCE_HEALTH) > 0);
+               blueowned += (e.team == NUM_TEAM_2 && GetResourceAmount(e, RESOURCE_HEALTH) > 0);
+               yellowowned += (e.team == NUM_TEAM_3 && GetResourceAmount(e, RESOURCE_HEALTH) > 0);
+               pinkowned += (e.team == NUM_TEAM_4 && GetResourceAmount(e, RESOURCE_HEALTH) > 0);
        }
 }
 
@@ -1223,7 +1256,7 @@ void havocbot_goalrating_ons_offenseitems(entity this, float ratingscale, vector
        bool needarmor = false, needweapons = false;
 
        // Needs armor/health?
-       if(this.health<100)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) < 100)
                needarmor = true;
 
        // Needs weapons?
@@ -1248,7 +1281,7 @@ void havocbot_goalrating_ons_offenseitems(entity this, float ratingscale, vector
        {
                // gather health and armor only
                if (it.solid)
-               if ( ((it.health || it.armorvalue) && needarmor) || (STAT(WEAPONS, it) && needweapons ) )
+               if ( ((GetResourceAmount(it, RESOURCE_HEALTH) || GetResourceAmount(it, RESOURCE_ARMOR)) && needarmor) || (STAT(WEAPONS, it) && needweapons ) )
                if (vdist(it.origin - org, <, sradius))
                {
                        int t = it.bot_pickupevalfunc(this, it);
@@ -1949,7 +1982,7 @@ MUTATOR_HOOKFUNCTION(ons, SV_ParseClientCommand)
                        {
                                entity source_point = ons_Nearest_ControlPoint(player, player.origin, autocvar_g_onslaught_teleport_radius);
 
-                               if ( !source_point && player.health > 0 )
+                               if ( !source_point && GetResourceAmount(player, RESOURCE_HEALTH) > 0 )
                                {
                                        sprint(player, "\nYou need to be next to a control point\n");
                                        return true;
@@ -1964,7 +1997,7 @@ MUTATOR_HOOKFUNCTION(ons, SV_ParseClientCommand)
                                        return true;
                                }
 
-                               if ( player.health <= 0 )
+                               if ( GetResourceAmount(player, RESOURCE_HEALTH) <= 0 )
                                {
                                        player.ons_spawn_by = closest_target;
                                        player.respawn_flags = player.respawn_flags | RESPAWN_FORCE;
@@ -2030,14 +2063,14 @@ MUTATOR_HOOKFUNCTION(ons, SendWaypoint)
                {
                        entity wp_owner = wp.owner;
                        entity e = WaypointSprite_getviewentity(to);
-                       if(SAME_TEAM(e, wp_owner) && wp_owner.goalentity.health >= wp_owner.goalentity.max_health) { wp_flag |= 2; }
+                       if(SAME_TEAM(e, wp_owner) && GetResourceAmount(wp_owner.goalentity, RESOURCE_HEALTH) >= wp_owner.goalentity.max_health) { wp_flag |= 2; }
                        if(!ons_ControlPoint_Attackable(wp_owner, e.team)) { wp_flag |= 2; }
                }
                if(wp.owner.classname == "onslaught_generator")
                {
                        entity wp_owner = wp.owner;
-                       if(wp_owner.isshielded && wp_owner.health >= wp_owner.max_health) { wp_flag |= 2; }
-                       if(wp_owner.health <= 0) { wp_flag |= 2; }
+                       if(wp_owner.isshielded && GetResourceAmount(wp_owner, RESOURCE_HEALTH) >= wp_owner.max_health) { wp_flag |= 2; }
+                       if(GetResourceAmount(wp_owner, RESOURCE_HEALTH) <= 0) { wp_flag |= 2; }
                }
        }
 
index 31b8f43cb17fe6041ec7c6155278db7aaad5823c..3109e7c92f93c66adc8c0f5d274bef901bf019e3 100644 (file)
@@ -72,7 +72,8 @@ const int IT_PICKUPMASK                       = IT_UNLIMITED_AMMO | IT_JETPACK | IT_FU
 enum
 {
        ITEM_FLAG_NORMAL = BIT(0), ///< Item is usable during normal gameplay.
-       ITEM_FLAG_MUTATORBLOCKED = BIT(1)
+       ITEM_FLAG_MUTATORBLOCKED = BIT(1),
+    ITEM_FLAG_RESOURCE = BIT(2) ///< Item is is a resource, not a held item.
 };
 
 #define ITEM_HANDLE(signal, ...) __Item_Send_##signal(__VA_ARGS__)
index 7c5c12af7284268c1b14c2eb4db1d464bf89b52c..4c37464ad83c8de28d6a6f706d8f264ff26727f9 100644 (file)
@@ -1,10 +1,13 @@
 #pragma once
 
 #include "pickup.qh"
+#include <common/items/all.qh>
 #ifdef SVQC
     #include <common/t_items.qh>
+    #include <server/resources.qh>
 #endif
 
+#if 1
 .int ammo_none;
 .int ammo_shells;
 .int ammo_nails;
 .int ammo_plasma;
 .int ammo_fuel;
 #endif
+#endif
+
+#ifdef GAMEQC
+.int spawnflags;
+#endif
 
 #ifdef SVQC
 PROPERTY(float, g_pickup_ammo_anyway);
@@ -40,8 +48,8 @@ MODEL(Bullets_ITEM, Item_Model("a_bullets.mdl"));
 PROPERTY(int, g_pickup_nails);
 void ammo_bullets_init(Pickup this, entity item)
 {
-    if(!item.ammo_nails)
-        item.ammo_nails = g_pickup_nails;
+    if(!GetResourceAmount(item, RESOURCE_BULLETS))
+        SetResourceAmountExplicit(item, RESOURCE_BULLETS, g_pickup_nails);
 }
 #endif
 
@@ -51,7 +59,7 @@ ENDCLASS(Bullets)
 REGISTER_ITEM(Bullets, Bullets) {
     this.m_canonical_spawnfunc = "item_bullets";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model    =   MDL_Bullets_ITEM;
 #endif
     this.netname    =   "bullets";
@@ -74,14 +82,14 @@ MODEL(Cells_ITEM, Item_Model("a_cells.md3"));
 PROPERTY(int, g_pickup_cells);
 void ammo_cells_init(Pickup this, entity item)
 {
-    if(!item.ammo_cells)
-        item.ammo_cells = g_pickup_cells;
+    if(!GetResourceAmount(item, RESOURCE_CELLS))
+        SetResourceAmountExplicit(item, RESOURCE_CELLS, g_pickup_cells);
 }
 #endif
 REGISTER_ITEM(Cells, Ammo) {
     this.m_canonical_spawnfunc = "item_cells";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model    =   MDL_Cells_ITEM;
 #endif
     this.netname    =   "cells";
@@ -104,14 +112,14 @@ MODEL(Plasma_ITEM, Item_Model("a_cells.md3"));
 PROPERTY(int, g_pickup_plasma);
 void ammo_plasma_init(Pickup this, entity item)
 {
-    if(!item.ammo_plasma)
-        item.ammo_plasma = g_pickup_plasma;
+    if(!GetResourceAmount(item, RESOURCE_PLASMA))
+        SetResourceAmountExplicit(item, RESOURCE_PLASMA, g_pickup_plasma);
 }
 #endif
 REGISTER_ITEM(Plasma, Ammo) {
     this.m_canonical_spawnfunc = "item_plasma";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model    =   MDL_Plasma_ITEM;
 #endif
     this.netname    =   "plasma";
@@ -134,14 +142,14 @@ MODEL(Rockets_ITEM, Item_Model("a_rockets.md3"));
 PROPERTY(int, g_pickup_rockets);
 void ammo_rockets_init(Pickup this, entity item)
 {
-    if(!item.ammo_rockets)
-        item.ammo_rockets = g_pickup_rockets;
+    if(!GetResourceAmount(item, RESOURCE_ROCKETS))
+        SetResourceAmountExplicit(item, RESOURCE_ROCKETS, g_pickup_rockets);
 }
 #endif
 REGISTER_ITEM(Rockets, Ammo) {
     this.m_canonical_spawnfunc = "item_rockets";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model    =   MDL_Rockets_ITEM;
 #endif
     this.netname    =   "rockets";
@@ -164,8 +172,8 @@ MODEL(Shells_ITEM, Item_Model("a_shells.md3"));
 PROPERTY(int, g_pickup_shells);
 void ammo_shells_init(Pickup this, entity item)
 {
-    if(!item.ammo_shells)
-        item.ammo_shells = g_pickup_shells;
+    if(!GetResourceAmount(item, RESOURCE_SHELLS))
+        SetResourceAmountExplicit(item, RESOURCE_SHELLS, g_pickup_shells);
 }
 #endif
 
@@ -175,7 +183,7 @@ ENDCLASS(Shells)
 REGISTER_ITEM(Shells, Shells) {
     this.m_canonical_spawnfunc = "item_shells";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model    =   MDL_Shells_ITEM;
 #endif
     this.netname    =   "shells";
index 880a932d7c27db58ceb0cfc4943f36059a296483..ee39aa59242111771347d38005fe0d3c89113e4c 100644 (file)
@@ -26,15 +26,15 @@ void item_armorsmall_init(Pickup this, entity item)
 {
     if(!item.max_armorvalue)
         item.max_armorvalue = g_pickup_armorsmall_max;
-    if(!item.armorvalue)
-        item.armorvalue = g_pickup_armorsmall;
+    if(!GetResourceAmount(item, RESOURCE_ARMOR))
+        SetResourceAmountExplicit(item, RESOURCE_ARMOR, g_pickup_armorsmall);
 }
 #endif
 
 REGISTER_ITEM(ArmorSmall, Armor) {
     this.m_canonical_spawnfunc = "item_armor_small";
 #ifdef GAMEQC
-    this.spawnflags = ITEM_FLAG_NORMAL;
+    this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_ArmorSmall_ITEM;
     this.m_sound                =   SND_ArmorSmall;
 #endif
@@ -64,15 +64,15 @@ void item_armormedium_init(Pickup this, entity item)
 {
     if(!item.max_armorvalue)
         item.max_armorvalue = g_pickup_armormedium_max;
-    if(!item.armorvalue)
-        item.armorvalue = g_pickup_armormedium;
+    if(!GetResourceAmount(item, RESOURCE_ARMOR))
+        SetResourceAmountExplicit(item, RESOURCE_ARMOR, g_pickup_armormedium);
 }
 #endif
 
 REGISTER_ITEM(ArmorMedium, Armor) {
     this.m_canonical_spawnfunc = "item_armor_medium";
 #ifdef GAMEQC
-    this.spawnflags = ITEM_FLAG_NORMAL;
+    this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_ArmorMedium_ITEM;
     this.m_sound                =   SND_ArmorMedium;
 #endif
@@ -102,15 +102,15 @@ void item_armorbig_init(Pickup this, entity item)
 {
     if(!item.max_armorvalue)
         item.max_armorvalue = g_pickup_armorbig_max;
-    if(!item.armorvalue)
-        item.armorvalue = g_pickup_armorbig;
+    if(!GetResourceAmount(item, RESOURCE_ARMOR))
+        SetResourceAmountExplicit(item, RESOURCE_ARMOR, g_pickup_armorbig);
 }
 #endif
 
 REGISTER_ITEM(ArmorBig, Armor) {
     this.m_canonical_spawnfunc = "item_armor_big";
 #ifdef GAMEQC
-    this.spawnflags = ITEM_FLAG_NORMAL;
+    this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_ArmorBig_ITEM;
     this.m_sound                =   SND_ArmorBig;
 #endif
@@ -142,15 +142,15 @@ void item_armormega_init(Pickup this, entity item)
 {
     if(!item.max_armorvalue)
         item.max_armorvalue = g_pickup_armormega_max;
-    if(!item.armorvalue)
-        item.armorvalue = g_pickup_armormega;
+    if(!GetResourceAmount(item, RESOURCE_ARMOR))
+        SetResourceAmountExplicit(item, RESOURCE_ARMOR, g_pickup_armormega);
 }
 #endif
 
 REGISTER_ITEM(ArmorMega, Armor) {
     this.m_canonical_spawnfunc = "item_armor_mega";
 #ifdef GAMEQC
-    this.spawnflags = ITEM_FLAG_NORMAL;
+    this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_ArmorMega_ITEM;
     this.m_sound                =   SND_ArmorMega;
 #endif
index 6a5ffc5ca478677cdece01528f17c5509ab333cf..bf515fe4dd7f7c167d31c7f85b6eb3bc9e409fb3 100644 (file)
@@ -26,15 +26,15 @@ void item_healthsmall_init(Pickup this, entity item)
 {
     if(!item.max_health)
         item.max_health = g_pickup_healthsmall_max;
-    if(!item.health)
-        item.health = g_pickup_healthsmall;
+    if(!GetResourceAmount(item, RESOURCE_HEALTH))
+        SetResourceAmountExplicit(item, RESOURCE_HEALTH, g_pickup_healthsmall);
 }
 #endif
 
 REGISTER_ITEM(HealthSmall, Health) {
     this.m_canonical_spawnfunc = "item_health_small";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_HealthSmall_ITEM;
     this.m_sound                =   SND_HealthSmall;
 #endif
@@ -64,15 +64,15 @@ void item_healthmedium_init(Pickup this, entity item)
 {
     if(!item.max_health)
         item.max_health = g_pickup_healthmedium_max;
-    if(!item.health)
-        item.health = g_pickup_healthmedium;
+    if(!GetResourceAmount(item, RESOURCE_HEALTH))
+        SetResourceAmountExplicit(item, RESOURCE_HEALTH, g_pickup_healthmedium);
 }
 #endif
 
 REGISTER_ITEM(HealthMedium, Health) {
     this.m_canonical_spawnfunc = "item_health_medium";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_HealthMedium_ITEM;
     this.m_sound                =   SND_HealthMedium;
 #endif
@@ -102,15 +102,15 @@ void item_healthbig_init(Pickup this, entity item)
 {
     if(!item.max_health)
         item.max_health = g_pickup_healthbig_max;
-    if(!item.health)
-        item.health = g_pickup_healthbig;
+    if(!GetResourceAmount(item, RESOURCE_HEALTH))
+        SetResourceAmountExplicit(item, RESOURCE_HEALTH, g_pickup_healthbig);
 }
 #endif
 
 REGISTER_ITEM(HealthBig, Health) {
     this.m_canonical_spawnfunc = "item_health_big";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_HealthBig_ITEM;
     this.m_sound                =   SND_HealthBig;
 #endif
@@ -142,15 +142,15 @@ void item_healthmega_init(Pickup this, entity item)
 {
     if(!item.max_health)
         item.max_health = g_pickup_healthmega_max;
-    if(!item.health)
-        item.health = g_pickup_healthmega;
+    if(!GetResourceAmount(item, RESOURCE_HEALTH))
+        SetResourceAmountExplicit(item, RESOURCE_HEALTH, g_pickup_healthmega);
 }
 #endif
 
 REGISTER_ITEM(HealthMega, Health) {
     this.m_canonical_spawnfunc = "item_health_mega";
 #ifdef GAMEQC
-    this.spawnflags = ITEM_FLAG_NORMAL;
+    this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_HealthMega_ITEM;
     this.m_sound                =   SND_HealthMega;
 #endif
index 73f55e83f5a225a82605e5320f3de8291bf26c03..760033861a7db8377342bc6ff7dbd6bef1901b4b 100644 (file)
@@ -19,8 +19,8 @@ MODEL(Jetpack_ITEM, Item_Model("g_jetpack.md3"));
 PROPERTY(int, g_pickup_fuel_jetpack);
 void powerup_jetpack_init(Pickup this, entity item)
 {
-    if(!item.ammo_fuel)
-        item.ammo_fuel = g_pickup_fuel_jetpack;
+    if(!GetResourceAmount(item, RESOURCE_FUEL))
+        SetResourceAmountExplicit(item, RESOURCE_FUEL, g_pickup_fuel_jetpack);
 }
 #endif
 
@@ -35,10 +35,10 @@ REGISTER_ITEM(Jetpack, Powerup) {
     this.m_itemid               =   IT_JETPACK;
 #endif
     this.netname                =   "jetpack";
-    this.m_name                 =   "Jet pack";
+    this.m_name                 =   "Jetpack";
     this.m_icon                 =   "jetpack";
     this.m_color                =   '0.5 0.5 0.5';
-    this.m_waypoint             =   _("Jet Pack");
+    this.m_waypoint             =   _("Jetpack");
     this.m_waypointblink        =   2;
 #ifdef SVQC
     this.m_botvalue             =   3000;
@@ -57,14 +57,14 @@ MODEL(JetpackFuel_ITEM, Item_Model("g_fuel.md3"));
 PROPERTY(int, g_pickup_fuel);
 void ammo_fuel_init(Pickup this, entity item)
 {
-    if(!item.ammo_fuel)
-        item.ammo_fuel = g_pickup_fuel;
+    if(!GetResourceAmount(item, RESOURCE_FUEL))
+        SetResourceAmountExplicit(item, RESOURCE_FUEL, g_pickup_fuel);
 }
 #endif
 REGISTER_ITEM(JetpackFuel, Ammo) {
     this.m_canonical_spawnfunc = "item_fuel";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model    =   MDL_JetpackFuel_ITEM;
 #endif
     this.netname    =   "fuel";
index d8f6cb1384e72952d7034ae40317a77a130d5bb5..cb17ac442cb4244aa71b708e6c7c27deaf220bb4 100644 (file)
@@ -83,7 +83,7 @@ void func_breakable_colormod(entity this)
        float h;
        if (!(this.spawnflags & BREAKABLE_INDICATE_DAMAGE))
                return;
-       h = this.health / this.max_health;
+       h = GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health;
        if(h < 0.25)
                this.colormod = '1 0 0';
        else if(h <= 0.75)
@@ -129,7 +129,7 @@ void func_breakable_look_restore(entity this)
 
 void func_breakable_behave_destroyed(entity this)
 {
-       this.health = this.max_health;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
        this.takedamage = DAMAGE_NO;
        if(this.bot_attack)
                IL_REMOVE(g_bot_targets, this);
@@ -141,6 +141,11 @@ void func_breakable_behave_destroyed(entity this)
        func_breakable_colormod(this);
        if (this.noise1)
                stopsound (this, CH_TRIGGER_SINGLE);
+
+       IL_EACH(g_projectiles, it.classname == "grapplinghook" && it.aiment == this,
+       {
+               RemoveHook(it);
+       });
 }
 
 void func_breakable_think(entity this)
@@ -152,11 +157,11 @@ void func_breakable_think(entity this)
 void func_breakable_destroy(entity this, entity actor, entity trigger);
 void func_breakable_behave_restore(entity this)
 {
-       this.health = this.max_health;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
        if(this.sprite)
        {
                WaypointSprite_UpdateMaxHealth(this.sprite, this.max_health);
-               WaypointSprite_UpdateHealth(this.sprite, this.health);
+               WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
        }
        if(!(this.spawnflags & BREAKABLE_NODAMAGE))
        {
@@ -200,6 +205,16 @@ void func_breakable_restore(entity this, entity actor, entity trigger)
 
 void func_breakable_restore_self(entity this)
 {
+       // TODO: use a clipgroup for all func_breakables so they don't collide with eachother
+       float oldhit = this.dphitcontentsmask;
+       this.dphitcontentsmask = DPCONTENTS_BODY; // we really only care about when players are standing inside, obey the mapper in other cases!
+       tracebox(this.origin, this.mins, this.maxs, this.origin, MOVE_NORMAL, this);
+       this.dphitcontentsmask = oldhit;
+       if(trace_startsolid || trace_fraction < 1)
+       {
+               this.nextthink = time + 5; // retry every 5 seconds until the area becomes clear
+               return;
+       }
        func_breakable_restore(this, NULL, NULL);
 }
 
@@ -257,15 +272,15 @@ void func_breakable_damage(entity this, entity inflictor, entity attacker, float
                if(attacker.team == this.team)
                        return;
        this.pain_finished = time;
-       this.health = this.health - damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
        if(this.sprite)
        {
                WaypointSprite_Ping(this.sprite);
-               WaypointSprite_UpdateHealth(this.sprite, this.health);
+               WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
        }
        func_breakable_colormod(this);
 
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
        {
                debrisforce = force;
 
@@ -300,9 +315,9 @@ void func_breakable_reset(entity this)
 spawnfunc(func_breakable)
 {
        float n, i;
-       if(!this.health)
-               this.health = 100;
-       this.max_health = this.health;
+       if(!GetResourceAmount(this, RESOURCE_HEALTH))
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, 100);
+       this.max_health = GetResourceAmount(this, RESOURCE_HEALTH);
 
        // yes, I know, MOVETYPE_NONE is not available here, not that one would want it here anyway
        if(!this.debrismovetype) this.debrismovetype = MOVETYPE_BOUNCE;
index 28e6481c880886c18d240fc3cc55719eb80668d6..44e31284336aae99eb35f580dff390b5db98797b 100644 (file)
@@ -27,7 +27,7 @@ void button_return(entity this)
        this.state = STATE_DOWN;
        SUB_CalcMove (this, this.pos1, TSPEED_LINEAR, this.speed, button_done);
        this.frame = 0;                 // use normal textures
-       if (this.health)
+       if (GetResourceAmount(this, RESOURCE_HEALTH))
                this.takedamage = DAMAGE_YES;   // can be shot again
 }
 
@@ -40,7 +40,7 @@ void button_blocked(entity this, entity blocker)
 
 void button_fire(entity this)
 {
-       this.health = this.max_health;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
        this.takedamage = DAMAGE_NO;    // will be reset upon return
 
        if (this.state == STATE_UP || this.state == STATE_TOP)
@@ -55,14 +55,14 @@ void button_fire(entity this)
 
 void button_reset(entity this)
 {
-       this.health = this.max_health;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
        setorigin(this, this.pos1);
        this.frame = 0;                 // use normal textures
        this.state = STATE_BOTTOM;
        this.velocity = '0 0 0';
        setthink(this, func_null);
        this.nextthink = 0;
-       if (this.health)
+       if (GetResourceAmount(this, RESOURCE_HEALTH))
                this.takedamage = DAMAGE_YES;   // can be shot again
 }
 
@@ -96,7 +96,7 @@ void button_damage(entity this, entity inflictor, entity attacker, float damage,
                        return;
        if (this.spawnflags & BUTTON_DONTACCUMULATEDMG)
        {
-               if (this.health <= damage)
+               if (GetResourceAmount(this, RESOURCE_HEALTH) <= damage)
                {
                        this.enemy = attacker;
                        button_fire(this);
@@ -104,8 +104,8 @@ void button_damage(entity this, entity inflictor, entity attacker, float damage,
        }
        else
        {
-               this.health = this.health - damage;
-               if (this.health <= 0)
+               TakeResource(this, RESOURCE_HEALTH, damage);
+               if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                {
                        this.enemy = attacker;
                        button_fire(this);
@@ -138,9 +138,9 @@ spawnfunc(func_button)
 
 //     if (this.health == 0) // all buttons are now shootable
 //             this.health = 10;
-       if (this.health)
+       if (GetResourceAmount(this, RESOURCE_HEALTH))
        {
-               this.max_health = this.health;
+               this.max_health = GetResourceAmount(this, RESOURCE_HEALTH);
                this.event_damage = button_damage;
                this.takedamage = DAMAGE_YES;
        }
index c19041aa0b1b7ad2269597caa1ea93040a26afa6..8d40a377be081fbc583f3adef2486a129530d694 100644 (file)
@@ -113,7 +113,7 @@ void door_go_down(entity this)
        if (this.max_health)
        {
                this.takedamage = DAMAGE_YES;
-               this.health = this.max_health;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
        }
 
        this.state = STATE_DOWN;
@@ -265,7 +265,7 @@ void door_damage(entity this, entity inflictor, entity attacker, float damage, i
        if(this.spawnflags & NOSPLASH)
                if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
                        return;
-       this.health = this.health - damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
 
        if (this.itemkeys)
        {
@@ -273,10 +273,10 @@ void door_damage(entity this, entity inflictor, entity attacker, float damage, i
                return;
        }
 
-       if (this.health <= 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
        {
-               this.owner.health = this.owner.max_health;
-               this.owner.takedamage = DAMAGE_NO;      // wil be reset upon return
+               SetResourceAmountExplicit(this.owner, RESOURCE_HEALTH, this.owner.max_health);
+               this.owner.takedamage = DAMAGE_NO;      // will be reset upon return
                door_use(this.owner, NULL, NULL);
        }
 }
@@ -357,7 +357,7 @@ Spawned if a door lacks a real activator
 
 void door_trigger_touch(entity this, entity toucher)
 {
-       if (toucher.health < 1)
+       if (GetResourceAmount(toucher, RESOURCE_HEALTH) < 1)
 #ifdef SVQC
                if (!((toucher.iscreature || (toucher.flags & FL_PROJECTILE)) && !IS_DEAD(toucher)))
 #elif defined(CSQC)
@@ -441,7 +441,7 @@ void LinkDoors(entity this)
        {
                this.owner = this.enemy = this;
 
-               if (this.health)
+               if (GetResourceAmount(this, RESOURCE_HEALTH))
                        return;
                IFTARGETED
                        return;
@@ -474,8 +474,8 @@ void LinkDoors(entity this)
        cmaxs = this.absmax;
        for(t = this; ; t = t.enemy)
        {
-               if(t.health && !this.health)
-                       this.health = t.health;
+               if(GetResourceAmount(t, RESOURCE_HEALTH) && !GetResourceAmount(this, RESOURCE_HEALTH))
+                       SetResourceAmountExplicit(this, RESOURCE_HEALTH, GetResourceAmount(t, RESOURCE_HEALTH));
                if((t.targetname != "") && (this.targetname == ""))
                        this.targetname = t.targetname;
                if((t.message != "") && (this.message == ""))
@@ -499,7 +499,7 @@ void LinkDoors(entity this)
        // distribute health, targetname, message
        for(t = this; t; t = t.enemy)
        {
-               t.health = this.health;
+               SetResourceAmountExplicit(t, RESOURCE_HEALTH, GetResourceAmount(this, RESOURCE_HEALTH));
                t.targetname = this.targetname;
                t.message = this.message;
                if(t.enemy == this)
@@ -509,7 +509,7 @@ void LinkDoors(entity this)
        // shootable, or triggered doors just needed the owner/enemy links,
        // they don't spawn a field
 
-       if (this.health)
+       if (GetResourceAmount(this, RESOURCE_HEALTH))
                return;
        IFTARGETED
                return;
@@ -630,7 +630,7 @@ void door_reset(entity this)
 // common code for func_door and func_door_rotating spawnfuncs
 void door_init_shared(entity this)
 {
-       this.max_health = this.health;
+       this.max_health = GetResourceAmount(this, RESOURCE_HEALTH);
 
        // unlock sound
        if(this.noise == "")
@@ -683,7 +683,7 @@ void door_init_shared(entity this)
 
        this.state = STATE_BOTTOM;
 
-       if (this.health)
+       if (GetResourceAmount(this, RESOURCE_HEALTH))
        {
                //this.canteamdamage = true; // TODO
                this.takedamage = DAMAGE_YES;
index 41fd05e574af53295a71c6b105c3a76f3ac78e52..39c02a8669881528f5a57d792c921fe03530c890 100644 (file)
@@ -58,7 +58,7 @@ void door_rotating_go_down(entity this)
        if (this.max_health)
        {
                this.takedamage = DAMAGE_YES;
-               this.health = this.max_health;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
        }
 
        this.state = STATE_DOWN;
index 78e0dd64e9cafc275eb55c1a6d1302cdcde2cdd5..f06f39e91126e963fa507e139a19304bfbcb6453 100644 (file)
@@ -13,7 +13,7 @@ void fd_secret_use(entity this, entity actor, entity trigger)
        float temp;
        string message_save;
 
-       this.health = 10000;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 10000);
        if(!this.bot_attack)
                IL_PUSH(g_bot_targets, this);
        this.bot_attack = true;
@@ -122,7 +122,7 @@ void fd_secret_done(entity this)
 {
        if (this.spawnflags&DOOR_SECRET_YES_SHOOT)
        {
-               this.health = 10000;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, 10000);
                this.takedamage = DAMAGE_YES;
                //this.th_pain = fd_secret_use;
        }
@@ -168,7 +168,7 @@ void secret_reset(entity this)
 {
        if (this.spawnflags & DOOR_SECRET_YES_SHOOT)
        {
-               this.health = 10000;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, 10000);
                this.takedamage = DAMAGE_YES;
        }
        setorigin(this, this.oldorigin);
@@ -253,7 +253,7 @@ spawnfunc(func_door_secret)
        if (this.spawnflags & DOOR_SECRET_YES_SHOOT)
        {
                //this.canteamdamage = true; // TODO
-               this.health = 10000;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, 10000);
                this.takedamage = DAMAGE_YES;
                this.event_damage = fd_secret_damage;
        }
index 4747877314a3ac52f78c30c06233ec3f63dcf170..cc909e5c5600fa0def2e10ab424282b6b0cb64f9 100644 (file)
@@ -93,7 +93,7 @@ void plat_center_touch(entity this, entity toucher)
        if (!toucher.iscreature)
                return;
 
-       if (toucher.health <= 0)
+       if (GetResourceAmount(toucher, RESOURCE_HEALTH) <= 0)
                return;
 #elif defined(CSQC)
        if (!IS_PLAYER(toucher))
@@ -114,7 +114,7 @@ void plat_outside_touch(entity this, entity toucher)
        if (!toucher.iscreature)
                return;
 
-       if (toucher.health <= 0)
+       if (GetResourceAmount(toucher, RESOURCE_HEALTH) <= 0)
                return;
 #elif defined(CSQC)
        if (!IS_PLAYER(toucher))
index ec6a26d18338949336ed54656a11dc7b93c234d2..403d956c59b22552521ec569d243f2d198db90ff 100644 (file)
@@ -44,12 +44,12 @@ void tdeath(entity player, entity teleporter, entity telefragger, vector telefra
 {
        TDEATHLOOP(player.origin)
        {
-               if (IS_PLAYER(player) && player.health >= 1)
+               if (IS_PLAYER(player) && GetResourceAmount(player, RESOURCE_HEALTH) >= 1)
                {
                        if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
                        {
                                if(IS_PLAYER(head))
-                                       if(head.health >= 1)
+                                       if(GetResourceAmount(head, RESOURCE_HEALTH) >= 1)
                                                ++tdeath_hit;
                                Damage (head, teleporter, telefragger, 10000, DEATH_TELEFRAG.m_id, DMG_NOWEP, head.origin, '0 0 0');
                        }
index cfcd726fcdb8e02c4a8997cf1477b0556f1c54dd..866fd88a569ddd4e67488ba23ba0a72e8ac5715f 100644 (file)
@@ -18,14 +18,9 @@ void trigger_heal_touch(entity this, entity toucher)
                                toucher.triggerhealtime = time + this.delay;
 
                        bool playthesound = (this.spawnflags & HEAL_SOUND_ALWAYS);
-                       if (toucher.health < this.max_health)
-                       {
-                               playthesound = true;
-                               toucher.health = min(toucher.health + this.health, this.max_health);
-                               toucher.pauserothealth_finished = max(toucher.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
-                       }
+                       bool healed = Heal(toucher, this, GetResourceAmount(this, RESOURCE_HEALTH), this.max_health);
 
-                       if(playthesound)
+                       if(playthesound || healed)
                                _sound (toucher, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
                }
        }
@@ -41,8 +36,8 @@ void trigger_heal_init(entity this)
        this.active = ACTIVE_ACTIVE;
        if(!this.delay)
                this.delay = 1;
-       if(!this.health)
-               this.health = 10;
+       if(!GetResourceAmount(this, RESOURCE_HEALTH))
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, 10); // TODO: use a special field for this, it doesn't have actual health!
        if(!this.max_health)
                this.max_health = 200; // max health topoff for field
        if(this.noise == "")
index accfbe8ac47b057d745a4542cb214ae10a66acbd..5447b992c373e1c1694b7e5bacb926cd8953f2e9 100644 (file)
@@ -7,7 +7,7 @@ void multi_wait(entity this)
 {
        if (this.max_health)
        {
-               this.health = this.max_health;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
                this.takedamage = DAMAGE_YES;
                this.solid = SOLID_BBOX;
        }
@@ -120,8 +120,8 @@ void multi_eventdamage(entity this, entity inflictor, entity attacker, float dam
        if(this.team)
                if(((this.spawnflags & INVERT_TEAMS) == 0) == (this.team != attacker.team))
                        return;
-       this.health = this.health - damage;
-       if (this.health <= 0)
+       TakeResource(this, RESOURCE_HEALTH, damage);
+       if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
        {
                this.enemy = attacker;
                this.goalentity = inflictor;
@@ -135,7 +135,7 @@ void multi_reset(entity this)
                settouch(this, multi_touch);
        if (this.max_health)
        {
-               this.health = this.max_health;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
                this.takedamage = DAMAGE_YES;
                this.solid = SOLID_BBOX;
        }
@@ -181,12 +181,12 @@ spawnfunc(trigger_multiple)
        this.team_saved = this.team;
        IL_PUSH(g_saved_team, this);
 
-       if (this.health)
+       if (GetResourceAmount(this, RESOURCE_HEALTH))
        {
                if (this.spawnflags & SPAWNFLAG_NOTOUCH)
                        objerror (this, "health and notouch don't make sense\n");
                this.canteamdamage = true;
-               this.max_health = this.health;
+               this.max_health = GetResourceAmount(this, RESOURCE_HEALTH);
                this.event_damage = multi_eventdamage;
                this.takedamage = DAMAGE_YES;
                this.solid = SOLID_BBOX;
index 9377332e2fb138299e1f3af53b653d57e55163d6..5d7c5b6f464a2c921fa6605cbab669de62b034af 100644 (file)
@@ -73,7 +73,7 @@ spawnfunc(trigger_secret)
        this.targetname = "";
 
        // you can't just shoot a room to find it, can you?
-       this.health = 0;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0);
 
        // a secret can not be delayed
        this.delay = 0;
index 058e41ca278e0cad04833d247dc3c2ba6621265f..8e3fd739de5694b34dd563a999707de4544fc45f 100644 (file)
@@ -18,6 +18,7 @@
 
 .float swamp_interval; //Hurt players in swamp with this interval
 .float swamp_slowdown; //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?)
+.float swamp_lifetime;  // holds the points remaining until slug dies (not quite health!) 
 .entity swampslug;
 
 #ifdef SVQC
@@ -40,10 +41,10 @@ void swampslug_think(entity this);
 void swampslug_think(entity this)
 {
        //Slowly kill the slug
-       this.health = this.health - 1;
+       this.swamp_lifetime -= 1;
 
        //Slug dead? then remove curses.
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
        {
                this.owner.in_swamp = 0;
                delete(this);
@@ -76,7 +77,7 @@ void swamp_touch(entity this, entity toucher)
                // If not attach one.
                //centerprint(toucher,"Entering swamp!\n");
                toucher.swampslug = spawn();
-               toucher.swampslug.health = 2;
+               toucher.swampslug.swamp_lifetime = 2;
                setthink(toucher.swampslug, swampslug_think);
                toucher.swampslug.nextthink = time;
                toucher.swampslug.owner = toucher;
@@ -90,7 +91,7 @@ void swamp_touch(entity this, entity toucher)
        //toucher.in_swamp = 1;
 
        //Revitalize players swampslug
-       toucher.swampslug.health = 2;
+       toucher.swampslug.swamp_lifetime = 2;
 }
 
 REGISTER_NET_LINKED(ENT_CLIENT_SWAMP)
index b8b647bef36946b5ce6cce47fb5e22241bd52236..88120a0ea7550acbb93cd46e9b94022165b18ba2 100644 (file)
@@ -87,20 +87,20 @@ bool M_Mage_Defend_Heal_Check(entity this, entity targ)
 {
        if(targ == NULL)
                return false;
-       if(targ.health <= 0)
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0)
                return false;
        if(DIFF_TEAM(targ, this) && targ != this.monster_follow)
                return false;
        if(STAT(FROZEN, targ))
                return false;
        if(!IS_PLAYER(targ))
-               return (IS_MONSTER(targ) && targ.health < targ.max_health);
+               return (IS_MONSTER(targ) && GetResourceAmount(targ, RESOURCE_HEALTH) < targ.max_health);
        if(targ.items & ITEM_Shield.m_itemid)
                return false;
 
        switch(this.skin)
        {
-               case 0: return (targ.health < autocvar_g_balance_health_regenstable);
+               case 0: return (GetResourceAmount(targ, RESOURCE_HEALTH) < autocvar_g_balance_health_regenstable);
                case 1:
                {
                        return ((GetResourceAmount(targ, RESOURCE_CELLS) && GetResourceAmount(targ, RESOURCE_CELLS) < g_pickup_cells_max)
@@ -110,8 +110,8 @@ bool M_Mage_Defend_Heal_Check(entity this, entity targ)
                                ||  (GetResourceAmount(targ, RESOURCE_SHELLS) && GetResourceAmount(targ, RESOURCE_SHELLS) < g_pickup_shells_max)
                                        );
                }
-               case 2: return (targ.armorvalue < autocvar_g_balance_armor_regenstable);
-               case 3: return (targ.health > 0);
+               case 2: return (GetResourceAmount(targ, RESOURCE_ARMOR) < autocvar_g_balance_armor_regenstable);
+               case 3: return (GetResourceAmount(targ, RESOURCE_HEALTH) > 0);
        }
 
        return false;
@@ -144,7 +144,7 @@ void M_Mage_Attack_Spike_Touch(entity this, entity toucher)
 // copied from W_Seeker_Think
 void M_Mage_Attack_Spike_Think(entity this)
 {
-       if (time > this.ltime || (this.enemy && this.enemy.health <= 0) || this.owner.health <= 0) {
+       if (time > this.ltime || (this.enemy && GetResourceAmount(this.enemy, RESOURCE_HEALTH) <= 0) || GetResourceAmount(this.owner, RESOURCE_HEALTH) <= 0) {
                this.projectiledeathtype |= HITTYPE_SPLASH;
                M_Mage_Attack_Spike_Explode(this, NULL);
        }
@@ -234,29 +234,32 @@ void M_Mage_Defend_Heal(entity this)
                        switch(this.skin)
                        {
                                case 0:
-                                       if(it.health < autocvar_g_balance_health_regenstable) it.health = bound(0, it.health + (autocvar_g_monster_mage_heal_allies), autocvar_g_balance_health_regenstable);
+                               {
+                                       Heal(it, this, autocvar_g_monster_mage_heal_allies, autocvar_g_balance_health_regenstable);
                                        fx = EFFECT_HEALING;
                                        break;
+                               }
                                case 1:
                                {
-                                       float tmpfld;
-                                       tmpfld = GetResourceAmount(it, RESOURCE_CELLS); if(tmpfld) SetResourceAmount(it, RESOURCE_CELLS, bound(tmpfld, tmpfld + 1, g_pickup_cells_max));
-                                       tmpfld = GetResourceAmount(it, RESOURCE_PLASMA); if(tmpfld) SetResourceAmount(it, RESOURCE_PLASMA, bound(tmpfld, tmpfld + 1, g_pickup_plasma_max));
-                                       tmpfld = GetResourceAmount(it, RESOURCE_ROCKETS); if(tmpfld) SetResourceAmount(it, RESOURCE_ROCKETS, bound(tmpfld, tmpfld + 1, g_pickup_rockets_max));
-                                       tmpfld = GetResourceAmount(it, RESOURCE_SHELLS); if(tmpfld) SetResourceAmount(it, RESOURCE_SHELLS, bound(tmpfld, tmpfld + 2, g_pickup_shells_max));
-                                       tmpfld = GetResourceAmount(it, RESOURCE_BULLETS); if(tmpfld) SetResourceAmount(it, RESOURCE_BULLETS, bound(tmpfld, tmpfld + 5, g_pickup_nails_max));
+                                       if(GetResourceAmount(this, RESOURCE_CELLS)) GiveResourceWithLimit(it, RESOURCE_CELLS, 1, g_pickup_cells_max);
+                                       if(GetResourceAmount(this, RESOURCE_PLASMA)) GiveResourceWithLimit(it, RESOURCE_PLASMA, 1, g_pickup_plasma_max);
+                                       if(GetResourceAmount(this, RESOURCE_ROCKETS)) GiveResourceWithLimit(it, RESOURCE_ROCKETS, 1, g_pickup_rockets_max);
+                                       if(GetResourceAmount(this, RESOURCE_SHELLS)) GiveResourceWithLimit(it, RESOURCE_SHELLS, 2, g_pickup_shells_max);
+                                       if(GetResourceAmount(this, RESOURCE_BULLETS)) GiveResourceWithLimit(it, RESOURCE_BULLETS, 5, g_pickup_nails_max);
+                                       // TODO: fuel?
                                        fx = EFFECT_AMMO_REGEN;
                                        break;
                                }
                                case 2:
-                                       if(it.armorvalue < autocvar_g_balance_armor_regenstable)
+                                       if(GetResourceAmount(it, RESOURCE_ARMOR) < autocvar_g_balance_armor_regenstable)
                                        {
-                                               it.armorvalue = bound(0, it.armorvalue + (autocvar_g_monster_mage_heal_allies), autocvar_g_balance_armor_regenstable);
+                                               GiveResourceWithLimit(it, RESOURCE_ARMOR, autocvar_g_monster_mage_heal_allies, autocvar_g_balance_armor_regenstable);
                                                fx = EFFECT_ARMOR_REPAIR;
                                        }
                                        break;
                                case 3:
-                                       it.health = bound(0, it.health - ((it == this)  ? (autocvar_g_monster_mage_heal_self) : (autocvar_g_monster_mage_heal_allies)), autocvar_g_balance_health_regenstable);
+                                       float hp = ((it == this) ? autocvar_g_monster_mage_heal_self : autocvar_g_monster_mage_heal_allies);
+                                       TakeResource(it, RESOURCE_HEALTH, hp); // TODO: use regular damage functions? needs a way to bypass friendly fire checks
                                        fx = EFFECT_RAGE;
                                        break;
                        }
@@ -266,9 +269,9 @@ void M_Mage_Defend_Heal(entity this)
                else
                {
                        Send_Effect(EFFECT_HEALING, it.origin, '0 0 0', 1);
-                       it.health = bound(0, it.health + (autocvar_g_monster_mage_heal_allies), it.max_health);
+                       Heal(it, this, autocvar_g_monster_mage_heal_allies, RESOURCE_LIMIT_NONE);
                        if(!(it.spawnflags & MONSTERFLAG_INVINCIBLE) && it.sprite)
-                               WaypointSprite_UpdateHealth(it.sprite, it.health);
+                               WaypointSprite_UpdateHealth(it.sprite, GetResourceAmount(it, RESOURCE_HEALTH));
                }
        });
 
@@ -322,14 +325,14 @@ void M_Mage_Attack_Teleport(entity this, entity targ)
 void M_Mage_Defend_Shield_Remove(entity this)
 {
        this.effects &= ~(EF_ADDITIVE | EF_BLUE);
-       this.armorvalue = autocvar_g_monsters_armor_blockpercent;
+       SetResourceAmountExplicit(this, RESOURCE_ARMOR, autocvar_g_monsters_armor_blockpercent);
 }
 
 void M_Mage_Defend_Shield(entity this)
 {
        this.effects |= (EF_ADDITIVE | EF_BLUE);
        this.mage_shield_delay = time + (autocvar_g_monster_mage_shield_delay);
-       this.armorvalue = (autocvar_g_monster_mage_shield_blockpercent);
+       SetResourceAmountExplicit(this, RESOURCE_ARMOR, autocvar_g_monster_mage_shield_blockpercent);
        this.mage_shield_time = time + (autocvar_g_monster_mage_shield_time);
        setanim(this, this.anim_shoot, true, true, true);
        this.attack_finished_single[0] = time + 1;
@@ -416,16 +419,16 @@ METHOD(Mage, mr_think, bool(Mage thismon, entity actor))
        });
     }
 
-    if(actor.health < (autocvar_g_monster_mage_heal_minhealth) || need_help)
+    if(GetResourceAmount(actor, RESOURCE_HEALTH) < (autocvar_g_monster_mage_heal_minhealth) || need_help)
     if(time >= actor.attack_finished_single[0])
     if(random() < 0.5)
         M_Mage_Defend_Heal(actor);
 
-    if(time >= actor.mage_shield_time && actor.armorvalue)
+    if(time >= actor.mage_shield_time && GetResourceAmount(actor, RESOURCE_ARMOR))
         M_Mage_Defend_Shield_Remove(actor);
 
     if(actor.enemy)
-    if(actor.health < actor.max_health)
+    if(GetResourceAmount(actor, RESOURCE_HEALTH) < actor.max_health)
     if(time >= actor.mage_shield_delay)
     if(random() < 0.5)
         M_Mage_Defend_Shield(actor);
@@ -466,7 +469,7 @@ METHOD(Mage, mr_anim, bool(Mage this, entity actor))
 METHOD(Mage, mr_setup, bool(Mage this, entity actor))
 {
     TC(Mage, this);
-    if(!actor.health) actor.health = (autocvar_g_monster_mage_health);
+    if(!GetResourceAmount(this, RESOURCE_HEALTH)) SetResourceAmountExplicit(actor, RESOURCE_HEALTH, autocvar_g_monster_mage_health);
     if(!actor.speed) { actor.speed = (autocvar_g_monster_mage_speed_walk); }
     if(!actor.speed2) { actor.speed2 = (autocvar_g_monster_mage_speed_run); }
     if(!actor.stopspeed) { actor.stopspeed = (autocvar_g_monster_mage_speed_stop); }
index eeefeae8ca51119bc5aa1775e525c2fba3d288cf..9981474f9bc7ad92a696dc9f8792d01a88cb0d15 100644 (file)
@@ -85,15 +85,15 @@ void M_Shambler_Attack_Lightning_Explode_use(entity this, entity actor, entity t
 
 void M_Shambler_Attack_Lightning_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if (this.health <= 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        if (!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) // no exceptions
                return; // g_projectiles_damage says to halt
 
-       this.health = this.health - damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
 
-       if (this.health <= 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_PrepareExplosionByDamage(this, attacker, adaptor_think2use);
 }
 
@@ -136,7 +136,7 @@ void M_Shambler_Attack_Lightning(entity this)
        settouch(gren, M_Shambler_Attack_Lightning_Touch);
 
        gren.takedamage = DAMAGE_YES;
-       gren.health = 50;
+       SetResourceAmountExplicit(gren, RESOURCE_HEALTH, 50);
        gren.damageforcescale = 0;
        gren.event_damage = M_Shambler_Attack_Lightning_Damage;
        gren.damagedbycontents = true;
@@ -246,7 +246,7 @@ METHOD(Shambler, mr_anim, bool(Shambler this, entity actor))
 METHOD(Shambler, mr_setup, bool(Shambler this, entity actor))
 {
     TC(Shambler, this);
-    if(!actor.health) actor.health = (autocvar_g_monster_shambler_health);
+    if(!GetResourceAmount(this, RESOURCE_HEALTH)) SetResourceAmountExplicit(actor, RESOURCE_HEALTH, autocvar_g_monster_shambler_health);
     if(!actor.attack_range) actor.attack_range = 150;
     if(!actor.speed) { actor.speed = (autocvar_g_monster_shambler_speed_walk); }
     if(!actor.speed2) { actor.speed2 = (autocvar_g_monster_shambler_speed_run); }
index 12277d1d640f4c5ed99d860bf9424225e8100409..5e2cc0513851594d70a64167656be7196135500d 100644 (file)
@@ -103,7 +103,7 @@ void M_Spider_Attack_Web_Explode(entity this)
                Send_Effect(EFFECT_ELECTRO_IMPACT, this.origin, '0 0 0', 1);
                RadiusDamage(this, this.realowner, 0, 0, 25, NULL, NULL, 25, this.projectiledeathtype, DMG_NOWEP, NULL);
 
-               FOREACH_ENTITY_RADIUS(this.origin, 25, it != this && it.takedamage && !IS_DEAD(it) && it.health > 0 && it.monsterid != MON_SPIDER.monsterid,
+               FOREACH_ENTITY_RADIUS(this.origin, 25, it != this && it.takedamage && !IS_DEAD(it) && GetResourceAmount(it, RESOURCE_HEALTH) > 0 && it.monsterid != MON_SPIDER.monsterid,
                {
                        it.spider_slowness = time + (autocvar_g_monster_spider_attack_web_damagetime);
                });
@@ -151,7 +151,7 @@ void M_Spider_Attack_Web(entity this)
        setsize(proj, '-4 -4 -4', '4 4 4');
        proj.takedamage = DAMAGE_NO;
        proj.damageforcescale = 0;
-       proj.health = 500;
+       SetResourceAmountExplicit(proj, RESOURCE_HEALTH, 500);
        proj.event_damage = func_null;
        proj.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, proj);
@@ -227,7 +227,7 @@ METHOD(Spider, mr_anim, bool(Spider this, entity actor))
 METHOD(Spider, mr_setup, bool(Spider this, entity actor))
 {
     TC(Spider, this);
-    if(!actor.health) actor.health = (autocvar_g_monster_spider_health);
+    if(!GetResourceAmount(this, RESOURCE_HEALTH)) SetResourceAmountExplicit(actor, RESOURCE_HEALTH, autocvar_g_monster_spider_health);
     if(!actor.speed) { actor.speed = (autocvar_g_monster_spider_speed_walk); }
     if(!actor.speed2) { actor.speed2 = (autocvar_g_monster_spider_speed_run); }
     if(!actor.stopspeed) { actor.stopspeed = (autocvar_g_monster_spider_speed_stop); }
index 0a52e61090e553a140817abc3536a9429a0fd425..f6c905d6d1893bcd4d1d3f134e28d62799da3ae7 100644 (file)
@@ -152,7 +152,7 @@ METHOD(Wyvern, mr_anim, bool(Wyvern this, entity actor))
 METHOD(Wyvern, mr_setup, bool(Wyvern this, entity actor))
 {
     TC(Wyvern, this);
-    if(!actor.health) actor.health = (autocvar_g_monster_wyvern_health);
+    if(!GetResourceAmount(this, RESOURCE_HEALTH)) SetResourceAmountExplicit(actor, RESOURCE_HEALTH, autocvar_g_monster_wyvern_health);
     if(!actor.speed) { actor.speed = (autocvar_g_monster_wyvern_speed_walk); }
     if(!actor.speed2) { actor.speed2 = (autocvar_g_monster_wyvern_speed_run); }
     if(!actor.stopspeed) { actor.stopspeed = (autocvar_g_monster_wyvern_speed_stop); }
index 297bab87ddeac5409cc962be2776fdeec6fcc263..aaa27d21b2894ed7e86a6fe021993c041b164db4 100644 (file)
@@ -51,7 +51,7 @@ const float zombie_anim_spawn                         = 30;
 
 void M_Zombie_Attack_Leap_Touch(entity this, entity toucher)
 {
-       if (this.health <= 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        vector angles_face;
@@ -74,16 +74,16 @@ void M_Zombie_Attack_Leap_Touch(entity this, entity toucher)
 
 void M_Zombie_Defend_Block_End(entity this)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        setanim(this, this.anim_blockend, false, true, true);
-       this.armorvalue = autocvar_g_monsters_armor_blockpercent;
+       SetResourceAmountExplicit(this, RESOURCE_ARMOR, autocvar_g_monsters_armor_blockpercent);
 }
 
 bool M_Zombie_Defend_Block(entity this)
 {
-       this.armorvalue = 0.9;
+       SetResourceAmountExplicit(this, RESOURCE_ARMOR, 0.9);
        this.state = MONSTER_ATTACK_MELEE; // freeze monster
        this.attack_finished_single[0] = time + 2.1;
        this.anim_finished = this.attack_finished_single[0];
@@ -100,7 +100,7 @@ bool M_Zombie_Attack(int attack_type, entity actor, entity targ, .entity weapone
        {
                case MONSTER_ATTACK_MELEE:
                {
-                       if(random() < 0.3 && actor.health < 75 && actor.enemy.health > 10)
+                       if(random() < 0.3 && GetResourceAmount(actor, RESOURCE_HEALTH) < 75 && GetResourceAmount(actor.enemy, RESOURCE_HEALTH) > 10)
                                return M_Zombie_Defend_Block(actor);
 
                        float anim_chance = random();
@@ -148,7 +148,7 @@ METHOD(Zombie, mr_pain, float(Zombie this, entity actor, float damage_take, enti
 METHOD(Zombie, mr_death, bool(Zombie this, entity actor))
 {
     TC(Zombie, this);
-    actor.armorvalue = autocvar_g_monsters_armor_blockpercent;
+    SetResourceAmountExplicit(actor, RESOURCE_ARMOR, autocvar_g_monsters_armor_blockpercent);
 
     setanim(actor, ((random() > 0.5) ? actor.anim_die1 : actor.anim_die2), false, true, true);
     return true;
@@ -180,7 +180,7 @@ METHOD(Zombie, mr_anim, bool(Zombie this, entity actor))
 METHOD(Zombie, mr_setup, bool(Zombie this, entity actor))
 {
     TC(Zombie, this);
-    if(!actor.health) actor.health = (autocvar_g_monster_zombie_health);
+    if(!GetResourceAmount(actor, RESOURCE_HEALTH)) SetResourceAmountExplicit(actor, RESOURCE_HEALTH, autocvar_g_monster_zombie_health);
     if(!actor.speed) { actor.speed = (autocvar_g_monster_zombie_speed_walk); }
     if(!actor.speed2) { actor.speed2 = (autocvar_g_monster_zombie_speed_run); }
     if(!actor.stopspeed) { actor.stopspeed = (autocvar_g_monster_zombie_speed_stop); }
index b4861b917dd39e068cb816fc3253f89f9b7acf4a..84355c7f3530ffddcf3dccde86781d487c7fd717 100644 (file)
@@ -84,7 +84,7 @@ bool Monster_ValidTarget(entity this, entity targ)
        || (game_stopped)
        || (targ.items & IT_INVISIBILITY)
        || (IS_SPEC(targ) || IS_OBSERVER(targ)) // don't attack spectators
-       || (!IS_VEHICLE(targ) && (IS_DEAD(targ) || IS_DEAD(this) || targ.health <= 0 || this.health <= 0))
+       || (!IS_VEHICLE(targ) && (IS_DEAD(targ) || IS_DEAD(this) || GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(this, RESOURCE_HEALTH) <= 0))
        || (this.monster_follow == targ || targ.monster_follow == this)
        || (!IS_VEHICLE(targ) && (targ.flags & FL_NOTARGET))
        || (!autocvar_g_monsters_typefrag && PHYS_INPUT_BUTTON_CHAT(targ))
@@ -375,7 +375,7 @@ bool Monster_Attack_Leap_Check(entity this, vector vel)
                return false; // already attacking
        if(!IS_ONGROUND(this))
                return false; // not on the ground
-       if(this.health <= 0 || IS_DEAD(this))
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0 || IS_DEAD(this))
                return false; // called when dead?
        if(time < this.attack_finished_single[0])
                return false; // still attacking
@@ -486,7 +486,7 @@ void Monster_Miniboss_Check(entity this)
        // g_monsters_miniboss_chance cvar or spawnflags 64 causes a monster to be a miniboss
        if ((this.spawnflags & MONSTERFLAG_MINIBOSS) || (chance < autocvar_g_monsters_miniboss_chance))
        {
-               this.health += autocvar_g_monsters_miniboss_healthboost;
+               GiveResource(this, RESOURCE_HEALTH, autocvar_g_monsters_miniboss_healthboost);
                this.effects |= EF_RED;
                if(!this.weapon)
                        this.weapon = WEP_VORTEX.m_id;
@@ -527,10 +527,11 @@ void Monster_Dead_Fade(entity this)
                        this.pos2 = this.angles;
                }
                this.event_damage = func_null;
+               this.event_heal = func_null;
                this.takedamage = DAMAGE_NO;
                setorigin(this, this.pos1);
                this.angles = this.pos2;
-               this.health = this.max_health;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
                setmodel(this, MDL_Null);
        }
        else
@@ -559,7 +560,7 @@ vector Monster_Move_Target(entity this, entity targ)
 
                // cases where the enemy may have changed their state (don't need to check everything here)
                if((!this.enemy)
-                       || (IS_DEAD(this.enemy) || this.enemy.health < 1)
+                       || (IS_DEAD(this.enemy) || GetResourceAmount(this.enemy, RESOURCE_HEALTH) < 1)
                        || (STAT(FROZEN, this.enemy))
                        || (this.enemy.flags & FL_NOTARGET)
                        || (this.enemy.alpha < 0.5 && this.enemy.alpha != 0)
@@ -896,7 +897,7 @@ void Monster_Reset(entity this)
 
        Unfreeze(this); // remove any icy remains
 
-       this.health = this.max_health;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
        this.velocity = '0 0 0';
        this.enemy = NULL;
        this.goalentity = NULL;
@@ -906,11 +907,11 @@ void Monster_Reset(entity this)
 
 void Monster_Dead_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       this.health -= damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
 
        Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, this, attacker);
 
-       if(this.health <= -50) // 100 health until gone?
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= -50) // 100 health until gone?
        {
                Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, this, attacker);
 
@@ -932,7 +933,7 @@ void Monster_Dead(entity this, entity attacker, float gibbed)
        if(STAT(FROZEN, this))
        {
                Unfreeze(this); // remove any icy remains
-               this.health = 0; // reset by Unfreeze
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0); // reset by Unfreeze (TODO)
        }
 
        monster_dropitem(this, attacker);
@@ -956,6 +957,7 @@ void Monster_Dead(entity this, entity attacker, float gibbed)
                _setmodel(this, this.mdl_dead);
 
        this.event_damage       = ((gibbed) ? func_null : Monster_Dead_Damage);
+       this.event_heal         = func_null;
        this.solid                      = SOLID_CORPSE;
        this.takedamage         = DAMAGE_AIM;
        this.deadflag           = DEAD_DEAD;
@@ -1000,7 +1002,7 @@ void Monster_Damage(entity this, entity inflictor, entity attacker, float damage
        if(deathtype == DEATH_FALL.m_id && this.draggedby != NULL)
                return;
 
-       vector v = healtharmor_applydamage(100, this.armorvalue / 100, deathtype, damage);
+       vector v = healtharmor_applydamage(100, GetResourceAmount(this, RESOURCE_ARMOR) / 100, deathtype, damage);
        float take = v.x;
        //float save = v.y;
 
@@ -1009,12 +1011,12 @@ void Monster_Damage(entity this, entity inflictor, entity attacker, float damage
 
        if(take)
        {
-               this.health -= take;
+               TakeResource(this, RESOURCE_HEALTH, take);
                Monster_Sound(this, monstersound_pain, 1.2, true, CH_PAIN);
        }
 
        if(this.sprite)
-               WaypointSprite_UpdateHealth(this.sprite, this.health);
+               WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
 
        this.dmg_time = time;
 
@@ -1032,7 +1034,7 @@ void Monster_Damage(entity this, entity inflictor, entity attacker, float damage
                        Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, this, attacker);
        }
 
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
        {
                if(deathtype == DEATH_KILL.m_id)
                        this.candrop = false; // killed by mobkill command
@@ -1041,13 +1043,13 @@ void Monster_Damage(entity this, entity inflictor, entity attacker, float damage
                SUB_UseTargets(this, attacker, this.enemy);
                this.target2 = this.oldtarget2; // reset to original target on death, incase we respawn
 
-               Monster_Dead(this, attacker, (this.health <= -100 || deathtype == DEATH_KILL.m_id));
+               Monster_Dead(this, attacker, (GetResourceAmount(this, RESOURCE_HEALTH) <= -100 || deathtype == DEATH_KILL.m_id));
 
                WaypointSprite_Kill(this.sprite);
 
                MUTATOR_CALLHOOK(MonsterDies, this, attacker, deathtype);
 
-               if(this.health <= -100 || deathtype == DEATH_KILL.m_id) // check if we're already gibbed
+               if(GetResourceAmount(this, RESOURCE_HEALTH) <= -100 || deathtype == DEATH_KILL.m_id) // check if we're already gibbed
                {
                        Violence_GibSplash(this, 1, 0.5, attacker);
 
@@ -1057,6 +1059,18 @@ void Monster_Damage(entity this, entity inflictor, entity attacker, float damage
        }
 }
 
+bool Monster_Heal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       if(targ.sprite)
+               WaypointSprite_UpdateHealth(targ.sprite, GetResourceAmount(targ, RESOURCE_HEALTH));
+       return true;
+}
+
 // don't check for enemies, just keep walking in a straight line
 void Monster_Move_2D(entity this, float mspeed, bool allow_jumpoff)
 {
@@ -1150,11 +1164,11 @@ void Monster_Frozen_Think(entity this)
        if(STAT(FROZEN, this) == 2)
        {
                STAT(REVIVE_PROGRESS, this) = bound(0, STAT(REVIVE_PROGRESS, this) + this.ticrate * this.revive_speed, 1);
-               this.health = max(1, STAT(REVIVE_PROGRESS, this) * this.max_health);
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, max(1, STAT(REVIVE_PROGRESS, this) * this.max_health));
                this.iceblock.alpha = bound(0.2, 1 - STAT(REVIVE_PROGRESS, this), 1);
 
                if(!(this.spawnflags & MONSTERFLAG_INVINCIBLE) && this.sprite)
-                       WaypointSprite_UpdateHealth(this.sprite, this.health);
+                       WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
 
                if(STAT(REVIVE_PROGRESS, this) >= 1)
                        Unfreeze(this);
@@ -1162,15 +1176,15 @@ void Monster_Frozen_Think(entity this)
        else if(STAT(FROZEN, this) == 3)
        {
                STAT(REVIVE_PROGRESS, this) = bound(0, STAT(REVIVE_PROGRESS, this) - this.ticrate * this.revive_speed, 1);
-               this.health = max(0, autocvar_g_nades_ice_health + (this.max_health-autocvar_g_nades_ice_health) * STAT(REVIVE_PROGRESS, this) );
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, max(0, autocvar_g_nades_ice_health + (this.max_health-autocvar_g_nades_ice_health) * STAT(REVIVE_PROGRESS, this)));
 
                if(!(this.spawnflags & MONSTERFLAG_INVINCIBLE) && this.sprite)
-                       WaypointSprite_UpdateHealth(this.sprite, this.health);
+                       WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
 
-               if(this.health < 1)
+               if(GetResourceAmount(this, RESOURCE_HEALTH) < 1)
                {
                        Unfreeze(this);
-                       this.health = 0;
+                       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0);
                        if(this.event_damage)
                                this.event_damage(this, this, this.frozen_by, 1, DEATH_NADE_ICE_FREEZE.m_id, DMG_NOWEP, this.origin, '0 0 0');
                }
@@ -1210,7 +1224,7 @@ void Monster_Think(entity this)
 
        if(this.monster_lifetime && time >= this.monster_lifetime)
        {
-               Damage(this, this, this, this.health + this.max_health, DEATH_KILL.m_id, DMG_NOWEP, this.origin, this.origin);
+               Damage(this, this, this, GetResourceAmount(this, RESOURCE_HEALTH) + this.max_health, DEATH_KILL.m_id, DMG_NOWEP, this.origin, this.origin);
                return;
        }
 
@@ -1242,8 +1256,8 @@ bool Monster_Spawn_Setup(entity this)
        mon.mr_setup(mon, this);
 
        // ensure some basic needs are met
-       if(!this.health) { this.health = 100; }
-       if(!this.armorvalue) { this.armorvalue = bound(0.2, 0.5 * MONSTER_SKILLMOD(this), 0.9); }
+       if(!GetResourceAmount(this, RESOURCE_HEALTH)) { SetResourceAmountExplicit(this, RESOURCE_HEALTH, 100); }
+       if(!GetResourceAmount(this, RESOURCE_ARMOR)) { SetResourceAmountExplicit(this, RESOURCE_ARMOR, bound(0.2, 0.5 * MONSTER_SKILLMOD(this), 0.9)); }
        if(!this.target_range) { this.target_range = autocvar_g_monsters_target_range; }
        if(!this.respawntime) { this.respawntime = autocvar_g_monsters_respawn_delay; }
        if(!this.monster_moveflags) { this.monster_moveflags = MONSTER_MOVE_WANDER; }
@@ -1253,13 +1267,13 @@ bool Monster_Spawn_Setup(entity this)
        if(!(this.spawnflags & MONSTERFLAG_RESPAWNED))
        {
                Monster_Miniboss_Check(this);
-               this.health *= MONSTER_SKILLMOD(this);
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, GetResourceAmount(this, RESOURCE_HEALTH) * MONSTER_SKILLMOD(this));
 
                if(!this.skin)
                        this.skin = rint(random() * 4);
        }
 
-       this.max_health = this.health;
+       this.max_health = GetResourceAmount(this, RESOURCE_HEALTH);
        this.pain_finished = this.nextthink;
 
        if(IS_PLAYER(this.monster_follow))
@@ -1288,7 +1302,7 @@ bool Monster_Spawn_Setup(entity this)
                if(!(this.spawnflags & MONSTERFLAG_INVINCIBLE))
                {
                        WaypointSprite_UpdateMaxHealth(this.sprite, this.max_health);
-                       WaypointSprite_UpdateHealth(this.sprite, this.health);
+                       WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
                }
        }
 
@@ -1353,6 +1367,7 @@ bool Monster_Spawn(entity this, bool check_appear, int mon_id)
        this.damagedbycontents  = true;
        this.monsterid                  = mon_id;
        this.event_damage               = Monster_Damage;
+       this.event_heal                 = Monster_Heal;
        settouch(this, Monster_Touch);
        this.use                                = Monster_Use;
        this.solid                              = SOLID_BBOX;
index 4be441dc1096106c0b4db2c1836880d0596e14e9..27f71b56c24ee02f88798ed51e214c15a5b05127 100644 (file)
@@ -544,7 +544,7 @@ MUTATOR_HOOKFUNCTION(buffs, Damage_Calculate)
                float amount = bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal,
                        GetResourceAmount(frag_target, RESOURCE_HEALTH));
                GiveResourceWithLimit(frag_attacker, RESOURCE_HEALTH, amount, g_pickup_healthsmall_max);
-               if (frag_target.armorvalue)
+               if (GetResourceAmount(frag_target, RESOURCE_ARMOR))
                {
                        amount = bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal,
                                GetResourceAmount(frag_target, RESOURCE_ARMOR));
index 95f4f3210c6a97c2650ff61317efb5018b509cdf..3f8d087166353715a224acd0d7bbf4383cdb2154 100644 (file)
@@ -18,8 +18,8 @@ SOUND(VaporizerCells, Item_Sound("itempickup"));
 int autocvar_g_instagib_ammo_drop;
 void ammo_vaporizercells_init(Pickup this, entity item)
 {
-    if(!item.ammo_cells)
-        item.ammo_cells = autocvar_g_instagib_ammo_drop;
+    if(!GetResourceAmount(item, RESOURCE_CELLS))
+        SetResourceAmountExplicit(item, RESOURCE_CELLS, autocvar_g_instagib_ammo_drop);
 }
 #endif
 REGISTER_ITEM(VaporizerCells, Ammo) {
index e68c687bdeb65058bac0c887c5f8aab8967bd560..443fe2478139a9527df39ab979f13a85805f09f8 100644 (file)
@@ -7,10 +7,10 @@ MUTATOR_HOOKFUNCTION(invincibleprojectiles, EditProjectile)
 {
        entity proj = M_ARGV(1, entity);
 
-       if(proj.health)
+       if(GetResourceAmount(proj, RESOURCE_HEALTH))
        {
                // disable health which in effect disables damage calculations
-               proj.health = 0;
+               SetResourceAmountExplicit(proj, RESOURCE_HEALTH, 0);
        }
 }
 
index 7da7c0709b3161da40140a82ba44a8795af6ad2d..68a3af3baf76d5ae65f46819004a865c91ce604e 100644 (file)
@@ -978,7 +978,7 @@ void toss_nade(entity e, bool set_owner, vector _velocity, float _time)
        settouch(_nade, nade_touch);
        _nade.spawnshieldtime = time + 0.1; // prevent instantly picking up again
        SetResourceAmount(_nade, RESOURCE_HEALTH, autocvar_g_nades_nade_health);
-       _nade.max_health = _nade.health;
+       _nade.max_health = GetResourceAmount(_nade, RESOURCE_HEALTH);
        _nade.takedamage = DAMAGE_AIM;
        _nade.event_damage = nade_damage;
        setcefc(_nade, func_null);
index a691b866f789b448c8cfdf0d699cb2de892e9f85..1fdf5fd7aad1a5e2ef0e85c68d326da0fb6845bc 100644 (file)
@@ -32,7 +32,7 @@ void orb_setup(entity e)
 
        e.draw = orb_draw;
        IL_PUSH(g_drawables, e);
-       e.health = 255;
+       SetResourceAmountExplicit(e, RESOURCE_HEALTH, 255);
        set_movetype(e, MOVETYPE_NONE);
        e.solid = SOLID_NOT;
        e.drawmask = MASK_NORMAL;
index 540edc69d9c6578c7ef4277a9f35b1a2f37cfb4b..37dac8f93123d0624d78e44f90e918e828c659d8 100644 (file)
@@ -108,7 +108,7 @@ REGISTER_MUTATOR(nt, expr_evaluate(cvar_string("g_new_toys")) && !MUTATOR_IS_ENA
 .string new_toys;
 
 float autocvar_g_new_toys_autoreplace;
-bool autocvar_g_new_toys_use_pickupsound = true;
+bool autocvar_g_new_toys_use_pickupsound = false;
 const float NT_AUTOREPLACE_NEVER = 0;
 const float NT_AUTOREPLACE_ALWAYS = 1;
 const float NT_AUTOREPLACE_RANDOM = 2;
index da5dcc234e32b4df646150465d7dee849f3193ae..586deda3efbb4aa6fcc5dc6d00de5bad6d5184c5 100644 (file)
@@ -130,7 +130,7 @@ void NIX_GiveCurrentWeapon(entity this)
        }
 
        // get weapon info
-       entity e = Weapons_from(nix_weapon);
+       entity wpn = Weapons_from(nix_weapon);
 
        if(nix_nextchange != this.nix_lastchange_id) // this shall only be called once per round!
        {
@@ -142,7 +142,7 @@ void NIX_GiveCurrentWeapon(entity this)
                SetResourceAmount(this, RESOURCE_FUEL, 0);
                if(this.items & IT_UNLIMITED_WEAPON_AMMO)
                {
-                       switch (e.ammo_type)
+                       switch (wpn.ammo_type)
                        {
                                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;
@@ -154,7 +154,7 @@ void NIX_GiveCurrentWeapon(entity this)
                }
                else
                {
-                       switch (e.ammo_type)
+                       switch (wpn.ammo_type)
                        {
                                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;
@@ -171,15 +171,15 @@ void NIX_GiveCurrentWeapon(entity this)
                else
                        Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
 
-               e.wr_resetplayer(e, this);
+               wpn.wr_resetplayer(wpn, this);
 
                // all weapons must be fully loaded when we spawn
-               if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
+               if (wpn.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
                {
-                       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+                       for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                        {
                                .entity weaponentity = weaponentities[slot];
-                               this.(weaponentity).(weapon_load[nix_weapon]) = e.reloading_ammo;
+                               this.(weaponentity).(weapon_load[nix_weapon]) = wpn.reloading_ammo;
                        }
                }
 
@@ -195,7 +195,7 @@ void NIX_GiveCurrentWeapon(entity this)
 
        if(!(this.items & IT_UNLIMITED_WEAPON_AMMO) && time > this.nix_nextincr)
        {
-               switch (e.ammo_type)
+               switch (wpn.ammo_type)
                {
                        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;
@@ -211,20 +211,19 @@ void NIX_GiveCurrentWeapon(entity this)
        STAT(WEAPONS, this) = '0 0 0';
        if(g_nix_with_blaster)
                STAT(WEAPONS, this) |= WEPSET(BLASTER);
-       STAT(WEAPONS, this) |= e.m_wepset;
+       STAT(WEAPONS, this) |= wpn.m_wepset;
 
-    Weapon w = Weapons_from(nix_weapon);
-    for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-    {
-       .entity weaponentity = weaponentities[slot];
-       if(this.(weaponentity).m_weapon == WEP_Null && slot != 0)
-               continue;
+       for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+       {
+               .entity weaponentity = weaponentities[slot];
+               if (this.(weaponentity).m_weapon == WEP_Null && slot != 0)
+                       continue;
 
-               if(this.(weaponentity).m_switchweapon != w)
-               if(!client_hasweapon(this, this.(weaponentity).m_switchweapon, weaponentity, true, false))
+               if (this.(weaponentity).m_switchweapon != wpn)
+               if (!client_hasweapon(this, this.(weaponentity).m_switchweapon, weaponentity, true, false))
                {
-                       if(client_hasweapon(this, w, weaponentity, true, false))
-                               W_SwitchWeapon(this, w, weaponentity);
+                       if (client_hasweapon(this, wpn, weaponentity, true, false))
+                               W_SwitchWeapon(this, wpn, weaponentity);
                }
        }
 }
index c06ca5b78cf3923816cf9950b4afb53172eb3967..37d82e22ef72d9f1579d4056349bcf39f61d012a 100644 (file)
@@ -28,15 +28,15 @@ void W_OverkillRocketPropelledChainsaw_Touch (entity this, entity toucher)
 
 void W_OverkillRocketPropelledChainsaw_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if (this.health <= 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        if (!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) // no exceptions
                return; // g_projectiles_damage says to halt
 
-       this.health = this.health - damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
 
-       if (this.health <= 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_PrepareExplosionByDamage(this, attacker, W_OverkillRocketPropelledChainsaw_Explode_think);
 }
 
@@ -78,7 +78,7 @@ void W_OverkillRocketPropelledChainsaw_Attack (Weapon thiswep, entity actor, .en
 
        missile.takedamage = DAMAGE_YES;
        missile.damageforcescale = WEP_CVAR_PRI(okrpc, damageforcescale);
-       missile.health = WEP_CVAR_PRI(okrpc, health);
+       SetResourceAmountExplicit(missile, RESOURCE_HEALTH, WEP_CVAR_PRI(okrpc, health));
        missile.event_damage = W_OverkillRocketPropelledChainsaw_Damage;
        missile.damagedbycontents = true;
        IL_PUSH(g_damagedbycontents, missile);
index 61c302c3e7e0fa74bdd67d0a81a67ea00012efe1..ee2a5be7f504d11c376bd85b31ec28b505b7eeec 100644 (file)
@@ -91,7 +91,7 @@ MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerSpawn)
 
                        if (PHYS_INPUT_BUTTON_CHAT(it)) continue;
                        if (!SAME_TEAM(player, it)) continue;
-                       if (autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health && it.health < autocvar_g_balance_health_regenstable) continue;
+                       if (autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health && GetResourceAmount(it, RESOURCE_HEALTH) < autocvar_g_balance_health_regenstable) continue;
                        if (IS_DEAD(it)) continue;
                        if (time < it.msnt_timer) continue;
                        if (time < it.spawnshieldtime) continue;
index b446c927052e0fc824a07708f03a9633f4c4fdad..56198186f1492b1e27648ca7abe6491b6c0f4ce8 100644 (file)
@@ -14,7 +14,7 @@ MUTATOR_HOOKFUNCTION(vampire, PlayerDamage_SplitHealthArmor)
        if(!IS_DEAD(frag_target))
        {
                GiveResource(frag_attacker, RESOURCE_HEALTH,
-                       bound(0, damage_take, frag_target.health));
+                       bound(0, damage_take, GetResourceAmount(frag_target, RESOURCE_HEALTH)));
        }
 }
 
index d0f01a576a278e8cd7f78327b4b8d66e356ef260..115e6ca9109341fcaa4c61974eaafe416b342f15 100644 (file)
@@ -21,18 +21,16 @@ MUTATOR_HOOKFUNCTION(vh, GrappleHookThink)
        if(!STAT(FROZEN, thehook.aiment))
        if(time >= game_starttime)
        if(DIFF_TEAM(thehook.owner, thehook.aiment) || autocvar_g_vampirehook_teamheal)
-       if(thehook.aiment.health > 0)
+       if(GetResourceAmount(thehook.aiment, RESOURCE_HEALTH) > 0)
        if(autocvar_g_vampirehook_damage)
        {
                thehook.last_dmg = time + autocvar_g_vampirehook_damagerate;
                thehook.owner.damage_dealt += autocvar_g_vampirehook_damage;
                Damage(dmgent, thehook, thehook.owner, autocvar_g_vampirehook_damage, WEP_HOOK.m_id, DMG_NOWEP, thehook.origin, '0 0 0');
-               if(SAME_TEAM(thehook.owner, thehook.aiment))
-                       thehook.aiment.health = min(thehook.aiment.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
-               else
-                       thehook.owner.health = min(thehook.owner.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
+               entity targ = ((SAME_TEAM(thehook.owner, thehook.aiment)) ? thehook.aiment : thehook.owner);
+               Heal(targ, thehook.owner, autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
 
                if(dmgent == thehook.owner)
-                       dmgent.health -= autocvar_g_vampirehook_damage; // FIXME: friendly fire?!
+                       TakeResource(dmgent, RESOURCE_HEALTH, autocvar_g_vampirehook_damage); // FIXME: friendly fire?!
        }
 }
index 326a26219b34e8008fe275f5b6d22076c958454a..dcbb65f65cd29472659141b93617b7a8182c2075 100644 (file)
@@ -34,7 +34,7 @@ bool WaypointSprite_SendEntity(entity this, entity to, float sendflags)
     {
         if (this.max_health)
         {
-            WriteByte(MSG_ENTITY, (this.health / this.max_health) * 191.0);
+            WriteByte(MSG_ENTITY, (GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health) * 191.0);
         }
         else
         {
@@ -134,7 +134,7 @@ void Ent_WaypointSprite(entity this, bool isnew)
         int t = ReadByte();
         if (t < 192)
         {
-            this.health = t / 191.0;
+            SetResourceAmountExplicit(this, RESOURCE_HEALTH, t / 191.0);
             this.build_finished = 0;
         }
         else
@@ -142,7 +142,7 @@ void Ent_WaypointSprite(entity this, bool isnew)
             t = (t - 192) * 256 + ReadByte();
             this.build_started = servertime;
             if (this.build_finished)
-                this.build_starthealth = bound(0, this.health, 1);
+                this.build_starthealth = bound(0, GetResourceAmount(this, RESOURCE_HEALTH), 1);
             else
                 this.build_starthealth = 0;
             this.build_finished = servertime + t / 32;
@@ -150,7 +150,7 @@ void Ent_WaypointSprite(entity this, bool isnew)
     }
     else
     {
-        this.health = -1;
+        SetResourceAmountExplicit(this, RESOURCE_HEALTH, -1);
         this.build_finished = 0;
     }
 
@@ -654,14 +654,14 @@ void Draw_WaypointSprite(entity this)
         if (time < this.build_finished + 0.25)
         {
             if (time < this.build_started)
-                this.health = this.build_starthealth;
+                SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.build_starthealth);
             else if (time < this.build_finished)
-                this.health = (time - this.build_started) / (this.build_finished - this.build_started) * (1 - this.build_starthealth) + this.build_starthealth;
+                SetResourceAmountExplicit(this, RESOURCE_HEALTH, (time - this.build_started) / (this.build_finished - this.build_started) * (1 - this.build_starthealth) + this.build_starthealth);
             else
-                this.health = 1;
+                SetResourceAmountExplicit(this, RESOURCE_HEALTH, 1);
         }
         else
-            this.health = -1;
+            SetResourceAmountExplicit(this, RESOURCE_HEALTH, -1);
     }
 
     o = drawspritearrow(o, ang, rgb, a, SPRITE_ARROW_SCALE * t);
@@ -709,7 +709,7 @@ void Draw_WaypointSprite(entity this)
     }
 
     draw_beginBoldFont();
-    if (this.health >= 0)
+    if (GetResourceAmount(this, RESOURCE_HEALTH) >= 0)
     {
         float align = 0, marg;
         if (this.build_finished)
@@ -726,7 +726,7 @@ void Draw_WaypointSprite(entity this)
         drawhealthbar(
                 o,
                 0,
-                this.health,
+                GetResourceAmount(this, RESOURCE_HEALTH),
                 '0 0 0',
                 '0 0 0',
                 SPRITE_HEALTHBAR_WIDTH * t,
@@ -831,9 +831,9 @@ void WaypointSprite_UpdateSprites(entity e, entity _m1, entity _m2, entity _m3)
 void WaypointSprite_UpdateHealth(entity e, float f)
 {
     f = bound(0, f, e.max_health);
-    if (f != e.health || e.pain_finished)
+    if (f != GetResourceAmount(e, RESOURCE_HEALTH) || e.pain_finished)
     {
-        e.health = f;
+        SetResourceAmountExplicit(e, RESOURCE_HEALTH, f);
         e.pain_finished = 0;
         e.SendFlags |= 0x80;
     }
@@ -1160,10 +1160,10 @@ entity WaypointSprite_AttachCarrier(
 {
     WaypointSprite_Kill(carrier.waypointsprite_attached); // FC overrides attached
     entity e = WaypointSprite_Spawn(spr, 0, 0, carrier, '0 0 64', NULL, carrier.team, carrier, waypointsprite_attachedforcarrier, false, icon);
-    if (carrier.health)
+    if (GetResourceAmount(carrier, RESOURCE_HEALTH))
     {
         WaypointSprite_UpdateMaxHealth(e, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id) * 2);
-        WaypointSprite_UpdateHealth(e, '1 0 0' * healtharmor_maxdamage(carrier.health, carrier.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
+        WaypointSprite_UpdateHealth(e, '1 0 0' * healtharmor_maxdamage(GetResourceAmount(carrier, RESOURCE_HEALTH), GetResourceAmount(carrier, RESOURCE_ARMOR), autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
     }
     return e;
 }
index b4d14034def463e93ce6747dc98bcb9bdac73c61..a15ef80d1e7f8feece7b0dc8f7927e3962d50db0 100644 (file)
     MSG_CENTER_NOTIF(ITEM_BUFF_DROP,                    N_ENABLE,    0, 1, "item_buffname",                      CPID_ITEM, "item_centime 0", _("^BGYou dropped the %s^BG buff!"), "")
     MSG_CENTER_NOTIF(ITEM_BUFF_GOT,                     N_ENABLE,    0, 1, "item_buffname",                      CPID_ITEM, "item_centime 0", _("^BGYou got the %s^BG buff!"), "")
     MSG_CENTER_NOTIF(ITEM_FUELREGEN_GOT,                N_ENABLE,    0, 0, "",                                   CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1Fuel regenerator"), "")
-    MSG_CENTER_NOTIF(ITEM_JETPACK_GOT,                  N_ENABLE,    0, 0, "",                                   CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1Jet pack"), "")
+    MSG_CENTER_NOTIF(ITEM_JETPACK_GOT,                  N_ENABLE,    0, 0, "",                                   CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1Jetpack"), "")
     MSG_CENTER_NOTIF(ITEM_WEAPON_DONTHAVE,              N_ENABLE,    0, 1, "item_wepname",                       CPID_ITEM, "item_centime 0", _("^BGYou do not have the ^F1%s"), "")
     MSG_CENTER_NOTIF(ITEM_WEAPON_DROP,                  N_ENABLE,    1, 1, "item_wepname item_wepammo",          CPID_ITEM, "item_centime 0", _("^BGYou dropped the ^F1%s^BG%s"), "")
     MSG_CENTER_NOTIF(ITEM_WEAPON_GOT,                   N_ENABLE,    0, 1, "item_wepname",                       CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1%s"), "")
index 2b9808a5540fd95733660635f89e108f52deb41f..2f4ebb1ff002c9c37278901d70a4838bb0e043e1 100644 (file)
@@ -792,7 +792,7 @@ void PM_jetpack(entity this, float maxspd_mod, float dt)
 
 #ifdef SVQC
                if (!(ITEMS_STAT(this) & IT_UNLIMITED_WEAPON_AMMO))
-                       this.ammo_fuel -= PHYS_JETPACK_FUEL(this) * dt * fvel * f;
+                       TakeResource(this, RESOURCE_FUEL, PHYS_JETPACK_FUEL(this) * dt * fvel * f);
 
                ITEMS_STAT(this) |= IT_USING_JETPACK;
 
index a562292b40a5c5bcd7f00d779f647c2a3bb87357..8e33c649b3bf5e68e09b5050252f53f48002e8b7 100644 (file)
@@ -5,6 +5,10 @@
 /// \author Lyberta
 /// \copyright GNU GPLv2 or any later version.
 
+/// \brief Unconditional maximum amount of resources the entity can have.
+const int RESOURCE_AMOUNT_HARD_LIMIT = 999;
+const int RESOURCE_LIMIT_NONE = -1;
+
 /// \brief Describes the available resource types.
 enum
 {
index ea936185b95ee2b1227a58be5664a7e2ecfda30c..37813ef716c0bd5f393bc45a1f2fad39036e7b0b 100644 (file)
@@ -31,7 +31,6 @@ void PlayerScore_Attach(entity this);
 void ClientData_Attach(entity this);
 void accuracy_init(entity this);
 void entcs_attach(entity this);
-void playerdemo_init(entity this);
 void anticheat_init(entity this);
 void W_HitPlotOpen(entity this);
 void bot_clientconnect(entity this);
@@ -51,7 +50,6 @@ void ClientState_attach(entity this)
        ClientData_Attach(this);
        accuracy_init(this);
        entcs_attach(this);
-       playerdemo_init(this);
        anticheat_init(this);
        W_HitPlotOpen(this);
 
@@ -61,7 +59,6 @@ void ClientState_attach(entity this)
 void bot_clientdisconnect(entity this);
 void W_HitPlotClose(entity this);
 void anticheat_report_to_eventlog(entity this);
-void playerdemo_shutdown(entity this);
 void entcs_detach(entity this);
 void accuracy_free(entity this);
 void ClientData_Detach(entity this);
@@ -81,6 +78,5 @@ void ClientState_detach(entity this)
     bot_clientdisconnect(this);
 
     anticheat_report_to_eventlog(this);
-    playerdemo_shutdown(this);
     entcs_detach(this);
 }
index f4ed4f1bf423e83e62be4463a76e0ab9a72aaac6..68fa7ef578ee302b29fd3697e22f89b5a2b6d856 100644 (file)
@@ -824,7 +824,8 @@ float Item_GiveTo(entity item, entity player)
        {
                pickedup = true;
                player.items |= its;
-               Send_Notification(NOTIF_ONE, player, MSG_INFO, INFO_ITEM_WEAPON_GOT, item.netname);
+               // TODO: we probably want to show a message in the console, but not this one!
+               //Send_Notification(NOTIF_ONE, player, MSG_INFO, INFO_ITEM_WEAPON_GOT, item.netname);
        }
 
        if (item.strength_finished)
@@ -1070,12 +1071,12 @@ float ammo_pickupevalfunc(entity player, entity item)
        if(item.itemdef.instanceOfWeaponPickup)
        {
                entity ammo = NULL;
-               if(item.ammo_shells)       { need_shells  = true; ammo = ITEM_Shells;      }
-               else if(item.ammo_nails)   { need_nails   = true; ammo = ITEM_Bullets;     }
-               else if(item.ammo_rockets) { need_rockets = true; ammo = ITEM_Rockets;     }
-               else if(item.ammo_cells)   { need_cells   = true; ammo = ITEM_Cells;       }
-               else if(item.ammo_plasma)  { need_plasma  = true; ammo = ITEM_Plasma;      }
-               else if(item.ammo_fuel)    { need_fuel    = true; ammo = ITEM_JetpackFuel; }
+               if(GetResourceAmount(item, RESOURCE_SHELLS))       { need_shells  = true; ammo = ITEM_Shells;      }
+               else if(GetResourceAmount(item, RESOURCE_BULLETS))   { need_nails   = true; ammo = ITEM_Bullets;     }
+               else if(GetResourceAmount(item, RESOURCE_ROCKETS)) { need_rockets = true; ammo = ITEM_Rockets;     }
+               else if(GetResourceAmount(item, RESOURCE_CELLS))   { need_cells   = true; ammo = ITEM_Cells;       }
+               else if(GetResourceAmount(item, RESOURCE_PLASMA))  { need_plasma  = true; ammo = ITEM_Plasma;      }
+               else if(GetResourceAmount(item, RESOURCE_FUEL))    { need_fuel    = true; ammo = ITEM_JetpackFuel; }
 
                if(!ammo)
                        return 0;
@@ -1103,23 +1104,23 @@ float ammo_pickupevalfunc(entity player, entity item)
 
        float noammorating = 0.5;
 
-       if ((need_shells) && (item.ammo_shells) && (GetResourceAmount(player, RESOURCE_SHELLS) < g_pickup_shells_max))
-               c = item.ammo_shells / max(noammorating, GetResourceAmount(player, RESOURCE_SHELLS));
+       if ((need_shells) && GetResourceAmount(item, RESOURCE_SHELLS) && (GetResourceAmount(player, RESOURCE_SHELLS) < g_pickup_shells_max))
+               c = GetResourceAmount(item, RESOURCE_SHELLS) / max(noammorating, GetResourceAmount(player, RESOURCE_SHELLS));
 
-       if ((need_nails) && (item.ammo_nails) && (GetResourceAmount(player, RESOURCE_BULLETS) < g_pickup_nails_max))
-               c = item.ammo_nails / max(noammorating, GetResourceAmount(player, RESOURCE_BULLETS));
+       if ((need_nails) && GetResourceAmount(item, RESOURCE_BULLETS) && (GetResourceAmount(player, RESOURCE_BULLETS) < g_pickup_nails_max))
+               c = GetResourceAmount(item, RESOURCE_BULLETS) / max(noammorating, GetResourceAmount(player, RESOURCE_BULLETS));
 
-       if ((need_rockets) && (item.ammo_rockets) && (GetResourceAmount(player, RESOURCE_ROCKETS) < g_pickup_rockets_max))
-               c = item.ammo_rockets / max(noammorating, GetResourceAmount(player, RESOURCE_ROCKETS));
+       if ((need_rockets) && GetResourceAmount(item, RESOURCE_ROCKETS) && (GetResourceAmount(player, RESOURCE_ROCKETS) < g_pickup_rockets_max))
+               c = GetResourceAmount(item, RESOURCE_ROCKETS) / max(noammorating, GetResourceAmount(player, RESOURCE_ROCKETS));
 
-       if ((need_cells) && (item.ammo_cells) && (GetResourceAmount(player, RESOURCE_CELLS) < g_pickup_cells_max))
-               c = item.ammo_cells / max(noammorating, GetResourceAmount(player, RESOURCE_CELLS));
+       if ((need_cells) && GetResourceAmount(item, RESOURCE_CELLS) && (GetResourceAmount(player, RESOURCE_CELLS) < g_pickup_cells_max))
+               c = GetResourceAmount(item, RESOURCE_CELLS) / max(noammorating, GetResourceAmount(player, RESOURCE_CELLS));
 
-       if ((need_plasma) && (item.ammo_plasma) && (GetResourceAmount(player, RESOURCE_PLASMA) < g_pickup_plasma_max))
-               c = item.ammo_plasma / max(noammorating, GetResourceAmount(player, RESOURCE_PLASMA));
+       if ((need_plasma) && GetResourceAmount(item, RESOURCE_PLASMA) && (GetResourceAmount(player, RESOURCE_PLASMA) < g_pickup_plasma_max))
+               c = GetResourceAmount(item, RESOURCE_PLASMA) / max(noammorating, GetResourceAmount(player, RESOURCE_PLASMA));
 
-       if ((need_fuel) && (item.ammo_fuel) && (GetResourceAmount(player, RESOURCE_FUEL) < g_pickup_fuel_max))
-               c = item.ammo_fuel / max(noammorating, GetResourceAmount(player, RESOURCE_FUEL));
+       if ((need_fuel) && GetResourceAmount(item, RESOURCE_FUEL) && (GetResourceAmount(player, RESOURCE_FUEL) < g_pickup_fuel_max))
+               c = GetResourceAmount(item, RESOURCE_FUEL) / max(noammorating, GetResourceAmount(player, RESOURCE_FUEL));
 
        rating *= min(c, 2);
        if(wpn)
@@ -1132,8 +1133,8 @@ float healtharmor_pickupevalfunc(entity player, entity item)
        float c = 0;
        float rating = item.bot_pickupbasevalue;
 
-       float itemarmor = item.armorvalue;
-       float itemhealth = item.health;
+       float itemarmor = GetResourceAmount(item, RESOURCE_ARMOR);
+       float itemhealth = GetResourceAmount(item, RESOURCE_HEALTH);
 
        if(item.item_group)
        {
@@ -1141,11 +1142,11 @@ float healtharmor_pickupevalfunc(entity player, entity item)
                itemhealth *= min(4, item.item_group_count);
        }
 
-       if (itemarmor && (player.armorvalue < item.max_armorvalue))
-               c = itemarmor / max(1, player.armorvalue * 2/3 + player.health * 1/3);
+       if (itemarmor && (GetResourceAmount(player, RESOURCE_ARMOR) < item.max_armorvalue))
+               c = itemarmor / max(1, GetResourceAmount(player, RESOURCE_ARMOR) * 2/3 + GetResourceAmount(player, RESOURCE_HEALTH) * 1/3);
 
-       if (itemhealth && (player.health < item.max_health))
-               c = itemhealth / max(1, player.health);
+       if (itemhealth && (GetResourceAmount(player, RESOURCE_HEALTH) < item.max_health))
+               c = itemhealth / max(1, GetResourceAmount(player, RESOURCE_HEALTH));
 
        rating *= min(2, c);
        return rating;
@@ -1334,7 +1335,7 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
                if(def.instanceOfPowerup)
                        this.ItemStatus |= ITS_ANIMATE1;
 
-               if(this.armorvalue || this.health)
+               if(GetResourceAmount(this, RESOURCE_ARMOR) || GetResourceAmount(this, RESOURCE_HEALTH))
                        this.ItemStatus |= ITS_ANIMATE2;
        }
 
@@ -1554,14 +1555,14 @@ spawnfunc(target_items)
                this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, this.superweapons_finished * boolean(this.items & IT_SUPERWEAPON), "superweapons");
                this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, boolean(this.items & ITEM_Jetpack.m_itemid), "jetpack");
                this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, boolean(this.items & ITEM_JetpackRegen.m_itemid), "fuel_regen");
-               if(this.ammo_shells != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_shells), "shells");
-               if(this.ammo_nails != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_nails), "nails");
-               if(this.ammo_rockets != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_rockets), "rockets");
-               if(this.ammo_cells != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_cells), "cells");
-               if(this.ammo_plasma != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_plasma), "plasma");
-               if(this.ammo_fuel != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_fuel), "fuel");
-               if(this.health != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.health), "health");
-               if(this.armorvalue != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.armorvalue), "armor");
+               if(GetResourceAmount(this, RESOURCE_SHELLS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_SHELLS)), "shells");
+               if(GetResourceAmount(this, RESOURCE_BULLETS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_BULLETS)), "nails");
+               if(GetResourceAmount(this, RESOURCE_ROCKETS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_ROCKETS)), "rockets");
+               if(GetResourceAmount(this, RESOURCE_CELLS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_CELLS)), "cells");
+               if(GetResourceAmount(this, RESOURCE_PLASMA) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_PLASMA)), "plasma");
+               if(GetResourceAmount(this, RESOURCE_FUEL) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_FUEL)), "fuel");
+               if(GetResourceAmount(this, RESOURCE_HEALTH) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_HEALTH)), "health");
+               if(GetResourceAmount(this, RESOURCE_ARMOR) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_ARMOR)), "armor");
                FOREACH(Buffs, it != BUFF_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(BUFFS, this) & (it.m_itemid)), it.m_name));
                FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(WEAPONS, this) & (it.m_wepset)), it.netname));
        }
@@ -1661,6 +1662,31 @@ void GiveRot(entity e, float v0, float v1, .float rotfield, float rottime, .floa
        else if(v0 > v1)
                e.(regenfield) = max(e.(regenfield), time + regentime);
 }
+bool GiveResourceValue(entity e, int resource_type, int op, int val)
+{
+       int v0 = GetResourceAmount(e, resource_type);
+       switch (op)
+       {
+               case OP_SET:
+                       SetResourceAmount(e, resource_type, val);
+                       break;
+               case OP_MIN:
+                       SetResourceAmount(e, resource_type, max(v0, val)); // min 100 cells = at least 100 cells
+                       break;
+               case OP_MAX:
+                       SetResourceAmount(e, resource_type, min(v0, val));
+                       break;
+               case OP_PLUS:
+                       SetResourceAmount(e, resource_type, v0 + val);
+                       break;
+               case OP_MINUS:
+                       SetResourceAmount(e, resource_type, v0 - val);
+                       break;
+       }
+       int v1 = GetResourceAmount(e, resource_type);
+       return v0 != v1;
+}
+
 float GiveItems(entity e, float beginarg, float endarg)
 {
        float got, i, val, op;
@@ -1693,14 +1719,14 @@ float GiveItems(entity e, float beginarg, float endarg)
        PREGIVE(e, strength_finished);
        PREGIVE(e, invincible_finished);
        PREGIVE(e, superweapons_finished);
-       PREGIVE(e, ammo_nails);
-       PREGIVE(e, ammo_cells);
-       PREGIVE(e, ammo_plasma);
-       PREGIVE(e, ammo_shells);
-       PREGIVE(e, ammo_rockets);
-       PREGIVE(e, ammo_fuel);
-       PREGIVE(e, armorvalue);
-       PREGIVE(e, health);
+       PREGIVE_RESOURCE(e, RESOURCE_BULLETS);
+       PREGIVE_RESOURCE(e, RESOURCE_CELLS);
+       PREGIVE_RESOURCE(e, RESOURCE_PLASMA);
+       PREGIVE_RESOURCE(e, RESOURCE_SHELLS);
+       PREGIVE_RESOURCE(e, RESOURCE_ROCKETS);
+       PREGIVE_RESOURCE(e, RESOURCE_FUEL);
+       PREGIVE_RESOURCE(e, RESOURCE_ARMOR);
+       PREGIVE_RESOURCE(e, RESOURCE_HEALTH);
 
        for(i = beginarg; i < endarg; ++i)
        {
@@ -1737,19 +1763,19 @@ float GiveItems(entity e, float beginarg, float endarg)
                                got += GiveBit(e, items, IT_UNLIMITED_AMMO, op, val);
                        case "all":
                                got += GiveBit(e, items, ITEM_Jetpack.m_itemid, op, val);
-                               got += GiveValue(e, health, op, val);
-                               got += GiveValue(e, armorvalue, op, val);
+                               got += GiveResourceValue(e, RESOURCE_HEALTH, op, val);
+                               got += GiveResourceValue(e, RESOURCE_ARMOR, op, val);
                        case "allweapons":
                                FOREACH(Weapons, it != WEP_Null && !(it.spawnflags & WEP_FLAG_MUTATORBLOCKED), got += GiveWeapon(e, it.m_id, op, val));
                        //case "allbuffs": // all buffs makes a player god, do not want!
                                //FOREACH(Buffs, it != BUFF_Null, got += GiveBuff(e, it.m_itemid, op, val));
                        case "allammo":
-                               got += GiveValue(e, ammo_cells, op, val);
-                               got += GiveValue(e, ammo_plasma, op, val);
-                               got += GiveValue(e, ammo_shells, op, val);
-                               got += GiveValue(e, ammo_nails, op, val);
-                               got += GiveValue(e, ammo_rockets, op, val);
-                               got += GiveValue(e, ammo_fuel, op, val);
+                               got += GiveResourceValue(e, RESOURCE_CELLS, op, val);
+                               got += GiveResourceValue(e, RESOURCE_PLASMA, op, val);
+                               got += GiveResourceValue(e, RESOURCE_SHELLS, op, val);
+                               got += GiveResourceValue(e, RESOURCE_BULLETS, op, val);
+                               got += GiveResourceValue(e, RESOURCE_ROCKETS, op, val);
+                               got += GiveResourceValue(e, RESOURCE_FUEL, op, val);
                                break;
                        case "unlimited_ammo":
                                got += GiveBit(e, items, IT_UNLIMITED_AMMO, op, val);
@@ -1776,29 +1802,29 @@ float GiveItems(entity e, float beginarg, float endarg)
                                got += GiveValue(e, superweapons_finished, op, val);
                                break;
                        case "cells":
-                               got += GiveValue(e, ammo_cells, op, val);
+                               got += GiveResourceValue(e, RESOURCE_CELLS, op, val);
                                break;
                        case "plasma":
-                               got += GiveValue(e, ammo_plasma, op, val);
+                               got += GiveResourceValue(e, RESOURCE_PLASMA, op, val);
                                break;
                        case "shells":
-                               got += GiveValue(e, ammo_shells, op, val);
+                               got += GiveResourceValue(e, RESOURCE_SHELLS, op, val);
                                break;
                        case "nails":
                        case "bullets":
-                               got += GiveValue(e, ammo_nails, op, val);
+                               got += GiveResourceValue(e, RESOURCE_BULLETS, op, val);
                                break;
                        case "rockets":
-                               got += GiveValue(e, ammo_rockets, op, val);
+                               got += GiveResourceValue(e, RESOURCE_ROCKETS, op, val);
                                break;
                        case "health":
-                               got += GiveValue(e, health, op, val);
+                               got += GiveResourceValue(e, RESOURCE_HEALTH, op, val);
                                break;
                        case "armor":
-                               got += GiveValue(e, armorvalue, op, val);
+                               got += GiveResourceValue(e, RESOURCE_ARMOR, op, val);
                                break;
                        case "fuel":
-                               got += GiveValue(e, ammo_fuel, op, val);
+                               got += GiveResourceValue(e, RESOURCE_FUEL, op, val);
                                break;
                        default:
                                FOREACH(Buffs, it != BUFF_Null && Buff_UndeprecateName(cmd) == it.m_name,
@@ -1829,14 +1855,14 @@ float GiveItems(entity e, float beginarg, float endarg)
        POSTGIVE_VALUE(e, strength_finished, 1, SND_POWERUP, SND_POWEROFF);
        POSTGIVE_VALUE(e, invincible_finished, 1, SND_Shield, SND_POWEROFF);
        //POSTGIVE_VALUE(e, superweapons_finished, 1, SND_Null, SND_Null);
-       POSTGIVE_VALUE(e, ammo_nails, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_VALUE(e, ammo_cells, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_VALUE(e, ammo_plasma, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_VALUE(e, ammo_shells, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_VALUE(e, ammo_rockets, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_VALUE_ROT(e, ammo_fuel, 1, pauserotfuel_finished, autocvar_g_balance_pause_fuel_rot, pauseregen_finished, autocvar_g_balance_pause_fuel_regen, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_VALUE_ROT(e, armorvalue, 1, pauserotarmor_finished, autocvar_g_balance_pause_armor_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_ARMOR25, SND_Null);
-       POSTGIVE_VALUE_ROT(e, health, 1, pauserothealth_finished, autocvar_g_balance_pause_health_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_MEGAHEALTH, SND_Null);
+       POSTGIVE_RESOURCE(e, RESOURCE_BULLETS, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE(e, RESOURCE_CELLS, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE(e, RESOURCE_PLASMA, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE(e, RESOURCE_SHELLS, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE(e, RESOURCE_ROCKETS, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE_ROT(e, RESOURCE_FUEL, 1, pauserotfuel_finished, autocvar_g_balance_pause_fuel_rot, pauseregen_finished, autocvar_g_balance_pause_fuel_regen, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE_ROT(e, RESOURCE_ARMOR, 1, pauserotarmor_finished, autocvar_g_balance_pause_armor_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_ARMOR25, SND_Null);
+       POSTGIVE_RESOURCE_ROT(e, RESOURCE_HEALTH, 1, pauserothealth_finished, autocvar_g_balance_pause_health_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_MEGAHEALTH, SND_Null);
 
        if(e.superweapons_finished <= 0)
                if(STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS)
index 50228a0a8f02c94a2f79b6a8c1f13d7b741e7b2b..9fdb0b0925798580c57106a7eb598c24e3a5ad41 100644 (file)
@@ -128,8 +128,11 @@ spawnfunc(target_items);
 
 #define PREGIVE_WEAPONS(e) WepSet save_weapons; save_weapons = STAT(WEAPONS, e)
 #define PREGIVE(e,f) float save_##f; save_##f = (e).f
+#define PREGIVE_RESOURCE(e,f) float save_##f = GetResourceAmount((e), (f))
 #define POSTGIVE_WEAPON(e,b,snd_incr,snd_decr) GiveSound((e), !!(save_weapons & WepSet_FromWeapon(b)), !!(STAT(WEAPONS, e) & WepSet_FromWeapon(b)), 0, snd_incr, snd_decr)
 #define POSTGIVE_BIT(e,f,b,snd_incr,snd_decr) GiveSound((e), save_##f & (b), (e).f & (b), 0, snd_incr, snd_decr)
+#define POSTGIVE_RESOURCE(e,f,t,snd_incr,snd_decr) GiveSound((e), save_##f, GetResourceAmount((e), (f)), t, snd_incr, snd_decr)
+#define POSTGIVE_RESOURCE_ROT(e,f,t,rotfield,rottime,regenfield,regentime,snd_incr,snd_decr) GiveRot((e),save_##f,GetResourceAmount((e),(f)),rotfield,rottime,regenfield,regentime);GiveSound((e),save_##f,GetResourceAmount((e),(f)),t,snd_incr,snd_decr)
 #define POSTGIVE_VALUE(e,f,t,snd_incr,snd_decr) GiveSound((e), save_##f, (e).f, t, snd_incr, snd_decr)
 #define POSTGIVE_VALUE_ROT(e,f,t,rotfield,rottime,regenfield,regentime,snd_incr,snd_decr) GiveRot((e), save_##f, (e).f, rotfield, rottime, regenfield, regentime); GiveSound((e), save_##f, (e).f, t, snd_incr, snd_decr)
 
index ba7b5d01bb5ba25c87ce00d1ad83b55b1f81923e..ac68003a6cde83c1a6b652959af1f349240654e1 100644 (file)
@@ -37,7 +37,7 @@ void turret_draw(entity this)
 
        this.tur_head.angles += dt * this.tur_head.avelocity;
 
-       if (this.health < 127)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) < 127)
        {
                dt = random();
 
@@ -45,11 +45,11 @@ void turret_draw(entity this)
                        te_spark(this.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
        }
 
-       if(this.health < 85)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) < 85)
        if(dt < 0.01)
                pointparticles(EFFECT_SMOKE_LARGE, (this.origin + (randomvec() * 80)), '0 0 0', 1);
 
-       if(this.health < 32)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) < 32)
        if(dt < 0.015)
                pointparticles(EFFECT_SMOKE_SMALL, (this.origin + (randomvec() * 80)), '0 0 0', 1);
 
@@ -180,7 +180,7 @@ void turret_draw2d(entity this)
        drawhealthbar(
                        o,
                        0,
-                       this.health / 255,
+                       GetResourceAmount(this, RESOURCE_HEALTH) / 255,
                        '0 0 0',
                        '0 0 0',
                        0.5 * SPRITE_HEALTHBAR_WIDTH * t,
@@ -221,7 +221,7 @@ void turret_construct(entity this, bool isnew)
        set_movetype(this.tur_head, MOVETYPE_NOCLIP);
        set_movetype(this, MOVETYPE_NOCLIP);
        this.tur_head.angles                    = this.angles;
-       this.health                                             = 255;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 255);
        this.solid                                              = SOLID_BBOX;
        this.tur_head.solid                             = SOLID_NOT;
        set_movetype(this, MOVETYPE_NOCLIP);
@@ -422,13 +422,15 @@ NET_HANDLE(ENT_CLIENT_TURRET, bool isnew)
                }
 
                _tmp = ReadByte();
-               if(_tmp == 0 && this.health != 0)
+               float myhp = GetResourceAmount(this, RESOURCE_HEALTH);
+               if(_tmp == 0 && myhp != 0)
                        turret_die(this);
-               else if(this.health && this.health != _tmp)
+               else if(myhp && myhp > _tmp)
                        this.helpme = servertime + 10;
+               else if(myhp && myhp < _tmp)
+                       this.helpme = 0; // we're being healed, don't spam help me waypoints
 
-               this.health = _tmp;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, _tmp);
        }
-       //this.enemy.health = this.health / 255;
        return true;
 }
index 06f8bab9c92a1543b953245fe22af8a1ff3dde62..b68aca16feddd93b6ea01b555b49aa6b17d2c53a 100644 (file)
@@ -182,9 +182,10 @@ void turret_die(entity this)
        this.tur_head.solid      = this.solid;
 
        this.event_damage                 = func_null;
+       this.event_heal = func_null;
        this.takedamage                  = DAMAGE_NO;
 
-       this.health                      = 0;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0);
 
 // Go boom
        //RadiusDamage (this,this, min(this.ammo,50),min(this.ammo,50) * 0.25,250,NULL,min(this.ammo,50)*5,DEATH_TURRET,NULL);
@@ -230,7 +231,7 @@ void turret_damage(entity this, entity inflictor, entity attacker, float damage,
                        return;
        }
 
-       this.health -= damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
 
        // thorw head slightly off aim when hit?
        if (this.damage_flags & TFL_DMG_HEADSHAKE)
@@ -244,10 +245,12 @@ void turret_damage(entity this, entity inflictor, entity attacker, float damage,
        if (this.turret_flags & TUR_FLAG_MOVE)
                this.velocity = this.velocity + vforce;
 
-       if (this.health <= 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
        {
                this.event_damage                 = func_null;
                this.tur_head.event_damage = func_null;
+               this.event_heal = func_null;
+               this.tur_head.event_heal = func_null;
                this.takedamage                  = DAMAGE_NO;
                this.nextthink = time;
                setthink(this, turret_die);
@@ -256,6 +259,17 @@ void turret_damage(entity this, entity inflictor, entity attacker, float damage,
        this.SendFlags  |= TNSF_STATUS;
 }
 
+bool turret_heal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       targ.SendFlags |= TNSF_STATUS;
+       return true;
+}
+
 void turret_think(entity this);
 void turret_respawn(entity this)
 {
@@ -268,10 +282,11 @@ void turret_respawn(entity this)
        this.solid                                      = SOLID_BBOX;
        this.takedamage                         = DAMAGE_AIM;
        this.event_damage                       = turret_damage;
+       this.event_heal                         = turret_heal;
        this.avelocity                          = '0 0 0';
        this.tur_head.avelocity         = this.avelocity;
        this.tur_head.angles            = this.idle_aim;
-       this.health                                     = this.max_health;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
        this.enemy                                      = NULL;
        this.volly_counter                      = this.shot_volly;
        this.ammo                                       = this.ammo_max;
@@ -350,10 +365,10 @@ bool turret_send(entity this, entity to, float sf)
        {
                WriteByte(MSG_ENTITY, this.team);
 
-               if(this.health <= 0)
+               if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                        WriteByte(MSG_ENTITY, 0);
                else
-                       WriteByte(MSG_ENTITY, ceil((this.health / this.max_health) * 255));
+                       WriteByte(MSG_ENTITY, ceil((GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health) * 255));
        }
 
        return true;
@@ -384,7 +399,7 @@ void load_unit_settings(entity ent, bool is_reload)
                ent.tur_head.angles = '0 0 0';
        }
 
-       ent.health       = cvar(strcat(sbase,"_health")) * ent.turret_scale_health;
+       SetResourceAmountExplicit(ent, RESOURCE_HEALTH, cvar(strcat(sbase,"_health")) * ent.turret_scale_health);
        ent.respawntime = cvar(strcat(sbase,"_respawntime")) * ent.turret_scale_respawn;
 
        ent.shot_dmg             = cvar(strcat(sbase,"_shot_dmg")) * ent.turret_scale_damage;
@@ -451,9 +466,9 @@ void turret_projectile_touch(entity this, entity toucher)
 void turret_projectile_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector vforce)
 {
        this.velocity  += vforce;
-       this.health     -= damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
        //this.realowner = attacker; // Dont change realowner, it does not make much sense for turrets
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_PrepareExplosionByDamage(this, this.owner, turret_projectile_explode);
 }
 
@@ -483,7 +498,7 @@ entity turret_projectile(entity actor, Sound _snd, float _size, float _health, f
        PROJECTILE_MAKETRIGGER(proj);
        if(_health)
        {
-               proj.health              = _health;
+               SetResourceAmountExplicit(proj, RESOURCE_HEALTH, _health);
                proj.takedamage  = DAMAGE_YES;
                proj.event_damage  = turret_projectile_damage;
        }
@@ -720,7 +735,7 @@ float turret_validate_target(entity e_turret, entity e_target, float validate_fl
                if (e_target.vehicle_health <= 0)
                        return -6;
        }
-       else if (e_target.health <= 0)
+       else if (GetResourceAmount(e_target, RESOURCE_HEALTH) <= 0)
                return -6;
        else if(STAT(FROZEN, e_target) > 0)
                return -6;
@@ -1292,7 +1307,7 @@ bool turret_initialize(entity this, Turret tur)
 
        if(!this.team || !teamplay)             { this.team = FLOAT_MAX; }
        if(!this.ticrate)                               { this.ticrate = ((this.turret_flags & TUR_FLAG_SUPPORT) ? 0.2 : 0.1); }
-       if(!this.health)                                { this.health = 1000; }
+       if(!GetResourceAmount(this, RESOURCE_HEALTH)) { SetResourceAmountExplicit(this, RESOURCE_HEALTH, 1000); }
        if(!this.shot_refire)                   { this.shot_refire = 1; }
        if(!this.tur_shotorg)                   { this.tur_shotorg = '50 0 50'; }
        if(!this.turret_flags)                  { this.turret_flags = TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER; }
@@ -1349,7 +1364,7 @@ bool turret_initialize(entity this, Turret tur)
        this.effects                            = EF_NODRAW;
        this.netname                            = tur.turret_name;
        this.ticrate                            = bound(sys_frametime, this.ticrate, 60);
-       this.max_health                         = this.health;
+       this.max_health                         = GetResourceAmount(this, RESOURCE_HEALTH);
        this.target_validate_flags      = this.target_select_flags;
        this.ammo                                       = this.ammo_max;
        this.ammo_recharge                 *= this.ticrate;
@@ -1360,6 +1375,7 @@ bool turret_initialize(entity this, Turret tur)
        this.idle_aim                           = '0 0 0';
        this.turret_firecheckfunc       = turret_firecheck;
        this.event_damage                       = turret_damage;
+       this.event_heal                         = turret_heal;
        this.use                                        = turret_use;
        this.bot_attack                         = true;
        this.nextthink                          = time + 1;
index 9a9001c42d39a99c14434ae662ef4602e3835536..c0a0b177ee2d179afb99aeb774203521daf5eeeb 100644 (file)
@@ -228,17 +228,17 @@ void ewheel_draw(entity this)
     setorigin(this, this.origin + this.velocity * dt);
     this.tur_head.angles += dt * this.tur_head.avelocity;
 
-    if (this.health < 127)
+    if(GetResourceAmount(this, RESOURCE_HEALTH) < 127)
     if(random() < 0.05)
         te_spark(this.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
 }
 
-        METHOD(EWheel, tr_setup, void(EWheel this, entity it))
-        {
-            it.gravity         = 1;
-            set_movetype(it, MOVETYPE_BOUNCE);
-            it.move_time               = time;
-            it.draw                    = ewheel_draw;
-        }
+METHOD(EWheel, tr_setup, void(EWheel this, entity it))
+{
+    it.gravity         = 1;
+    set_movetype(it, MOVETYPE_BOUNCE);
+    it.move_time               = time;
+    it.draw                    = ewheel_draw;
+}
 
 #endif // CSQC
index 3141b3d10f8c579fc596f9adc45d30b3b8ccea76..b68bfb77307a5f3ed243779deb9b3b717eacfad9 100644 (file)
@@ -58,7 +58,7 @@ void turret_hk_missile_think(entity this)
     //if (this.cnt < time)
     // turret_hk_missile_explode();
 
-    if (IS_DEAD(this.enemy))
+    if (IS_DEAD(this.enemy) || IS_SPEC(this.enemy) || IS_OBSERVER(this.enemy))
         this.enemy = NULL;
 
     // Pick the closest valid target.
@@ -251,7 +251,7 @@ bool hk_is_valid_target(entity this, entity proj, entity targ)
         return false;
 
     // Cant touch this
-    if ((targ.takedamage == DAMAGE_NO) || (targ.health < 0))
+    if ((targ.takedamage == DAMAGE_NO) || (GetResourceAmount(targ, RESOURCE_HEALTH) < 0))
         return false;
 
     // player
index 93b9483defa5fc06cc1f91ff0dfba51d840934c8..6aa0865e69d1e4fac73d93ab9177f72278071985 100644 (file)
@@ -86,10 +86,10 @@ void walker_rocket_touch(entity this, entity toucher)
 
 void walker_rocket_damage(entity this, entity inflictor, entity attacker, float damage, float deathtype, .entity weaponentity, vector hitloc, vector vforce)
 {
-    this.health = this.health - damage;
+    TakeResource(this, RESOURCE_HEALTH, damage);
     this.velocity = this.velocity + vforce;
 
-    if (this.health <= 0)
+    if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
         W_PrepareExplosionByDamage(this, this.owner, walker_rocket_explode);
 }
 
@@ -218,7 +218,7 @@ void walker_fire_rocket(entity this, vector org)
     rocket.bot_dodgerating     = 50;
     rocket.takedamage           = DAMAGE_YES;
     rocket.damageforcescale   = 2;
-    rocket.health                       = 25;
+    SetResourceAmountExplicit(rocket, RESOURCE_HEALTH, 25);
     rocket.tur_shotorg         = randomvec() * 512;
     rocket.cnt                         = time + 1;
     rocket.enemy                         = this.enemy;
@@ -629,17 +629,17 @@ void walker_draw(entity this)
     setorigin(this, this.origin + this.velocity * dt);
     this.tur_head.angles += dt * this.tur_head.avelocity;
 
-    if (this.health < 127)
+    if(GetResourceAmount(this, RESOURCE_HEALTH) < 127)
     if(random() < 0.15)
         te_spark(this.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
 }
 
-        METHOD(WalkerTurret, tr_setup, void(WalkerTurret this, entity it))
-        {
-            it.gravity         = 1;
-            set_movetype(it, MOVETYPE_BOUNCE);
-            it.move_time               = time;
-            it.draw                    = walker_draw;
-        }
+METHOD(WalkerTurret, tr_setup, void(WalkerTurret this, entity it))
+{
+    it.gravity         = 1;
+    set_movetype(it, MOVETYPE_BOUNCE);
+    it.move_time               = time;
+    it.draw                    = walker_draw;
+}
 
 #endif // CSQC
index 0eaf69eac6eab5ffbbf057538603fb3a2d406d84..df0f5d91693946c7230fb95d37f0dfb6b773aecd 100644 (file)
@@ -205,9 +205,9 @@ void vehicles_projectile_damage(entity this, entity inflictor, entity attacker,
        if(inflictor.owner == this.owner)
                return;
 
-       this.health -= damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
        this.velocity += force;
-       if(this.health < 1)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) < 1)
        {
                this.takedamage = DAMAGE_NO;
                this.event_damage = func_null;
@@ -282,7 +282,7 @@ entity vehicles_projectile(entity this, string _mzlfx, Sound _mzlsound,
        {
                proj.takedamage    = DAMAGE_AIM;
                proj.event_damage        = vehicles_projectile_damage;
-               proj.health                = _health;
+               SetResourceAmountExplicit(proj, RESOURCE_HEALTH, _health);
        }
        else
                proj.flags |= FL_NOTARGET;
@@ -727,6 +727,20 @@ void vehicles_damage(entity this, entity inflictor, entity attacker, float damag
        }
 }
 
+bool vehicles_heal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
+       //if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+       if(targ.vehicle_health <= 0 || targ.vehicle_health >= true_limit)
+               return false;
+
+       targ.vehicle_health = min(targ.vehicle_health + amount, true_limit);
+       //GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       //if(targ.owner)
+               //targ.owner.vehicle_health = (targ.vehicle_health / targ.max_health) * 100;
+       return true;
+}
+
 bool vehicles_crushable(entity e)
 {
        if(IS_PLAYER(e) && time >= e.vehicle_enter_delay)
@@ -1005,6 +1019,7 @@ void vehicles_enter(entity pl, entity veh)
        setsize(pl, STAT(PL_MIN, pl), STAT(PL_MAX, pl));
 
        veh.event_damage        = vehicles_damage;
+       veh.event_heal          = vehicles_heal;
        veh.nextthink           = 0;
        pl.items &= ~IT_USING_JETPACK;
        pl.angles                       = veh.angles;
@@ -1118,6 +1133,7 @@ void vehicles_spawn(entity this)
        this.owner                              = NULL;
        settouch(this, vehicles_touch);
        this.event_damage               = vehicles_damage;
+       this.event_heal                 = vehicles_heal;
        this.reset                              = vehicles_reset;
        this.iscreature                 = true;
        this.teleportable               = false; // no teleporting for vehicles, too buggy
@@ -1230,6 +1246,7 @@ bool vehicle_initialize(entity this, Vehicle info, bool nodrop)
        this.vehicleid                          = info.vehicleid;
        this.PlayerPhysplug                     = info.PlayerPhysplug;
        this.event_damage                       = func_null;
+       this.event_heal                         = func_null;
        settouch(this, vehicles_touch);
        setthink(this, vehicles_spawn);
        this.nextthink                          = time;
index d0f63c96a3d77258d25ff5d80ed98208b6ddd677..0cc9da56ea11a57779850fc85f1bdd53ca0864e1 100644 (file)
@@ -45,14 +45,14 @@ float autocvar_g_vehicles_weapon_damagerate = 2;
 .entity gunner1;
 .entity gunner2;
 
-.float vehicle_health = _STAT(VEHICLESTAT_HEALTH);  /// If ent is player this is 0..100 indicating precentage of health left on vehicle. If ent is vehile, this is the real health value.
-.float vehicle_energy = _STAT(VEHICLESTAT_ENERGY);  /// If ent is player this is 0..100 indicating precentage of energy left on vehicle. If ent is vehile, this is the real energy value.
-.float vehicle_shield = _STAT(VEHICLESTAT_SHIELD);  /// If ent is player this is 0..100 indicating precentage of shield left on vehicle. If ent is vehile, this is the real shield value.
+.float vehicle_health = _STAT(VEHICLESTAT_HEALTH);  /// If ent is player this is 0..100 indicating precentage of health left on vehicle. If ent is vehicle, this is the real health value.
+.float vehicle_energy = _STAT(VEHICLESTAT_ENERGY);  /// If ent is player this is 0..100 indicating precentage of energy left on vehicle. If ent is vehicle, this is the real energy value.
+.float vehicle_shield = _STAT(VEHICLESTAT_SHIELD);  /// If ent is player this is 0..100 indicating precentage of shield left on vehicle. If ent is vehicle, this is the real shield value.
 
-.float vehicle_ammo1 = _STAT(VEHICLESTAT_AMMO1);   /// If ent is player this is 0..100 indicating percentage of primary ammo left UNLESS value is already stored in vehicle_energy. If ent is vehile, this is the real ammo1 value.
-.float vehicle_reload1 = _STAT(VEHICLESTAT_RELOAD1); /// If ent is player this is 0..100 indicating percentage of primary reload status. If ent is vehile, this is the real reload1 value.
-.float vehicle_ammo2 = _STAT(VEHICLESTAT_AMMO2);   /// If ent is player this is 0..100 indicating percentage of secondary ammo left. If ent is vehile, this is the real ammo2 value.
-.float vehicle_reload2 = _STAT(VEHICLESTAT_RELOAD2); /// If ent is player this is 0..100 indicating percentage of secondary reload status. If ent is vehile, this is the real reload2 value.
+.float vehicle_ammo1 = _STAT(VEHICLESTAT_AMMO1);   /// If ent is player this is 0..100 indicating percentage of primary ammo left UNLESS value is already stored in vehicle_energy. If ent is vehicle, this is the real ammo1 value.
+.float vehicle_reload1 = _STAT(VEHICLESTAT_RELOAD1); /// If ent is player this is 0..100 indicating percentage of primary reload status. If ent is vehicle, this is the real reload1 value.
+.float vehicle_ammo2 = _STAT(VEHICLESTAT_AMMO2);   /// If ent is player this is 0..100 indicating percentage of secondary ammo left. If ent is vehicle, this is the real ammo2 value.
+.float vehicle_reload2 = _STAT(VEHICLESTAT_RELOAD2); /// If ent is player this is 0..100 indicating percentage of secondary reload status. If ent is vehicle, this is the real reload2 value.
 
 .float sound_nexttime;
 const float VOL_VEHICLEENGINE = 1;
@@ -79,7 +79,6 @@ const int MAX_AXH = 4;
 .float  lock_strength;
 .float  lock_time;
 .float  lock_soundtime;
-const float    DAMAGE_TARGETDRONE = 10;
 
 // vehicle functions
 .void(int _spawnflag) vehicle_spawn;  /// Vehicles custom fucntion to be efecuted when vehicle (re)spawns
@@ -87,7 +86,7 @@ const float   DAMAGE_TARGETDRONE = 10;
 .void(entity this, int exit_flags) vehicle_exit;
 .bool(entity this, entity player) vehicle_enter;
 const int VHEF_NORMAL = 0;  /// User pressed exit key
-const int VHEF_EJECT  = 1;  /// User pressed exit key 3 times fast (not implemented) or vehile is dying
+const int VHEF_EJECT  = 1;  /// User pressed exit key 3 times fast (not implemented) or vehicle is dying
 const int VHEF_RELEASE = 2;  /// Release ownership, client possibly allready dissconnected / went spec / changed team / used "kill" (not implemented)
 
 float  force_fromtag_power;
index 4e842a865c76b31f91eea2b698da3930ea6d8e85..c340d947035617492da6d224bbede286baf8e7be 100644 (file)
@@ -544,36 +544,27 @@ bool bumblebee_pilot_frame(entity this, float dt)
                        else
                        {
                                if(!IS_DEAD(trace_ent))
+                               {
                                        if((teamplay && trace_ent.team == this.team) || !teamplay)
                                        {
+                                               if(autocvar_g_vehicle_bumblebee_healgun_hps)
+                                               {
+                                                       float hplimit = ((IS_PLAYER(trace_ent)) ? autocvar_g_vehicle_bumblebee_healgun_hmax : RESOURCE_LIMIT_NONE);
+                                                       Heal(trace_ent, this, autocvar_g_vehicle_bumblebee_healgun_hps * dt, hplimit);
+                                               }
 
                                                if(IS_VEHICLE(trace_ent))
                                                {
                                                        if(autocvar_g_vehicle_bumblebee_healgun_sps && trace_ent.vehicle_health <= trace_ent.max_health)
                                                                trace_ent.vehicle_shield = min(trace_ent.vehicle_shield + autocvar_g_vehicle_bumblebee_healgun_sps * dt, trace_ent.tur_head.max_health);
-
-                                                       if(autocvar_g_vehicle_bumblebee_healgun_hps)
-                                                               trace_ent.vehicle_health = min(trace_ent.vehicle_health + autocvar_g_vehicle_bumblebee_healgun_hps * dt, trace_ent.max_health);
                                                }
                                                else if(IS_CLIENT(trace_ent))
                                                {
-                                                       if(trace_ent.health <= autocvar_g_vehicle_bumblebee_healgun_hmax && autocvar_g_vehicle_bumblebee_healgun_hps)
-                                                               trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * dt, autocvar_g_vehicle_bumblebee_healgun_hmax);
-
-                                                       if(trace_ent.armorvalue <= autocvar_g_vehicle_bumblebee_healgun_amax && autocvar_g_vehicle_bumblebee_healgun_aps)
-                                                               trace_ent.armorvalue = min(trace_ent.armorvalue + autocvar_g_vehicle_bumblebee_healgun_aps * dt, autocvar_g_vehicle_bumblebee_healgun_amax);
-
-                                                       trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * dt, autocvar_g_vehicle_bumblebee_healgun_hmax);
-                                               }
-                                               else if(IS_TURRET(trace_ent))
-                                               {
-                                                       if(trace_ent.health  <= trace_ent.max_health && autocvar_g_vehicle_bumblebee_healgun_hps)
-                                                               trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * dt, trace_ent.max_health);
-                                                       //else ..hmmm what? ammo?
-
-                                                       trace_ent.SendFlags |= TNSF_STATUS;
+                                                       if(GetResourceAmount(trace_ent, RESOURCE_ARMOR) <= autocvar_g_vehicle_bumblebee_healgun_amax && autocvar_g_vehicle_bumblebee_healgun_aps)
+                                                               GiveResourceWithLimit(trace_ent, RESOURCE_ARMOR, autocvar_g_vehicle_bumblebee_healgun_aps * dt, autocvar_g_vehicle_bumblebee_healgun_amax);
                                                }
                                        }
+                               }
                        }
                }
 
@@ -803,7 +794,7 @@ METHOD(Bumblebee, vr_death, void(Bumblebee thisveh, entity instance))
 
     Send_Effect(EFFECT_EXPLOSION_MEDIUM, findbetterlocation(instance.origin, 16), '0 0 0', 1);
 
-    instance.health                    = 0;
+    SetResourceAmountExplicit(instance, RESOURCE_HEALTH, 0);
     instance.event_damage      = func_null;
     instance.solid                     = SOLID_NOT;
     instance.takedamage                = DAMAGE_NO;
index 93ed6d31d531ac6b06baa424090d54718f8d2219..18e13bcbbe68d3f23bc558dad7b0e0f9427c4d2b 100644 (file)
@@ -566,7 +566,7 @@ METHOD(Racer, vr_death, void(Racer thisveh, entity instance))
 {
 #ifdef SVQC
     setSendEntity(instance, func_null); // stop networking this racer (for now)
-    instance.health                    = 0;
+    SetResourceAmountExplicit(instance, RESOURCE_HEALTH, 0);
     instance.event_damage      = func_null;
     instance.solid                     = SOLID_CORPSE;
     instance.takedamage                = DAMAGE_NO;
index bf3e4436205c22d91ee0c7a17a25faaf1108a034..f44dcc578464e7a2e485c5da437a286bd721bc87 100644 (file)
@@ -609,7 +609,7 @@ METHOD(Raptor, vr_enter, void(Raptor thisveh, entity instance))
 }
 METHOD(Raptor, vr_death, void(Raptor thisveh, entity instance))
 {
-    instance.health                            = 0;
+       SetResourceAmountExplicit(instance, RESOURCE_HEALTH, 0);
     instance.event_damage              = func_null;
     instance.solid                             = SOLID_CORPSE;
     instance.takedamage                        = DAMAGE_NO;
index 37c4fc391f78c16455127716451e4ace115eeb9f..53475d6cfd382e6efe95ae50ae09642b6fe04a89 100644 (file)
@@ -74,7 +74,7 @@ METHOD(RaptorFlare, wr_think, void(entity thiswep, entity actor, .entity weapone
             _flare.solid = SOLID_CORPSE;
             _flare.takedamage = DAMAGE_YES;
             _flare.event_damage = raptor_flare_damage;
-            _flare.health = 20;
+            SetResourceAmountExplicit(_flare, RESOURCE_HEALTH, 20);
             _flare.tur_impacttime = time + autocvar_g_vehicle_raptor_flare_lifetime;
             settouch(_flare, raptor_flare_touch);
         }
@@ -191,8 +191,8 @@ void raptor_flare_touch(entity this, entity toucher)
 
 void raptor_flare_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-    this.health -= damage;
-    if(this.health <= 0)
+    TakeResource(this, RESOURCE_HEALTH, damage);
+    if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
         delete(this);
 }
 
index 994a642d73ebac110dd657f7eba910d32aa28fa8..09d0eb2af9175c6012b0a903677483e2e7c6d0cc 100644 (file)
@@ -540,7 +540,7 @@ METHOD(Spiderbot, vr_think, void(Spiderbot thisveh, entity instance))
 }
 METHOD(Spiderbot, vr_death, void(Spiderbot thisveh, entity instance))
 {
-    instance.health                            = 0;
+       SetResourceAmountExplicit(instance, RESOURCE_HEALTH, 0);
     instance.event_damage              = func_null;
     instance.takedamage                        = DAMAGE_NO;
     settouch(instance, func_null);
index e5d4f2eb23253dccbe414e522d0bc5ec84e8c1f0..c7066e6fbd34720e16d0852f305c6fa36d426323 100644 (file)
@@ -1,6 +1,8 @@
 #include "arc.qh"
 
 #ifdef SVQC
+#include <common/gamemodes/gamemode/onslaught/sv_onslaught.qh>
+#include <common/gamemodes/gamemode/onslaught/sv_generator.qh>
 
 bool W_Arc_Beam_Send(entity this, entity to, int sf)
 {
@@ -102,16 +104,16 @@ void W_Arc_Bolt_Explode_use(entity this, entity actor, entity trigger)
 
 void W_Arc_Bolt_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        if(!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1))
                return; // g_projectiles_damage says to halt
 
-       this.health = this.health - damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
        this.angles = vectoangles(this.velocity);
 
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_PrepareExplosionByDamage(this, attacker, getthink(this));
 }
 
@@ -138,7 +140,7 @@ void W_Arc_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity)
        missile.bot_dodgerating = WEP_CVAR(arc, bolt_damage);
 
        missile.takedamage = DAMAGE_YES;
-       missile.health = WEP_CVAR(arc, bolt_health);
+       SetResourceAmountExplicit(missile, RESOURCE_HEALTH, WEP_CVAR(arc, bolt_health));
        missile.damageforcescale = WEP_CVAR(arc, bolt_damageforcescale);
        missile.event_damage = W_Arc_Bolt_Damage;
        missile.damagedbycontents = true;
@@ -189,11 +191,9 @@ void W_Arc_Beam_Think(entity this)
        if(
                !IS_PLAYER(own)
                ||
-               (!thiswep.wr_checkammo1(thiswep, own, weaponentity) && !(own.items & IT_UNLIMITED_WEAPON_AMMO))
-               ||
                IS_DEAD(own)
                ||
-               forbidWeaponUse(own)
+               !weapon_prepareattack_check(thiswep, own, weaponentity, this.beam_bursting, -1)
                ||
                own.(weaponentity).m_switchweapon != WEP_ARC
                ||
@@ -408,7 +408,7 @@ void W_Arc_Beam_Think(entity this)
                beam_endpos = WarpZone_TransformOrigin(WarpZone_trace_transform, beam_endpos);
                new_dir = WarpZone_TransformVelocity(WarpZone_trace_transform, new_dir);
 
-               float is_player = (
+               bool is_player = (
                        IS_PLAYER(trace_ent)
                        ||
                        trace_ent.classname == "body"
@@ -416,65 +416,42 @@ void W_Arc_Beam_Think(entity this)
                        IS_MONSTER(trace_ent)
                );
 
-               if(trace_ent && trace_ent.takedamage && (is_player || WEP_CVAR(arc, beam_nonplayerdamage)))
+               if(trace_ent)
                {
-                       // calculate our own hit origin as trace_endpos tends to jump around annoyingly (to player origin?)
-                       // NO. trace_endpos should be just fine. If not,
-                       // that's an engine bug that needs proper debugging.
-                       vector hitorigin = trace_endpos;
-
-                       float falloff = ExponentialFalloff(
-                               WEP_CVAR(arc, beam_falloff_mindist),
-                               WEP_CVAR(arc, beam_falloff_maxdist),
-                               WEP_CVAR(arc, beam_falloff_halflifedist),
-                               vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, hitorigin) - w_shotorg)
-                       );
-
-                       if(is_player && SAME_TEAM(own, trace_ent))
+                       if(SAME_TEAM(own, trace_ent))
                        {
-                               float roothealth, rootarmor;
-                               if(burst)
-                               {
-                                       roothealth = WEP_CVAR(arc, burst_healing_hps);
-                                       rootarmor = WEP_CVAR(arc, burst_healing_aps);
-                               }
-                               else
+                               float roothealth = ((burst) ? WEP_CVAR(arc, burst_healing_hps) : WEP_CVAR(arc, beam_healing_hps));
+                               float rootarmor = ((burst) ? WEP_CVAR(arc, burst_healing_aps) : WEP_CVAR(arc, beam_healing_aps));
+                               float hplimit = ((IS_PLAYER(trace_ent)) ? WEP_CVAR(arc, beam_healing_hmax) : RESOURCE_LIMIT_NONE);
+                               Heal(trace_ent, own, (roothealth * coefficient), hplimit);
+                               if(IS_PLAYER(trace_ent) && rootarmor)
                                {
-                                       roothealth = WEP_CVAR(arc, beam_healing_hps);
-                                       rootarmor = WEP_CVAR(arc, beam_healing_aps);
+                                       if(GetResourceAmount(trace_ent, RESOURCE_ARMOR) <= WEP_CVAR(arc, beam_healing_amax))
+                                       {
+                                               GiveResourceWithLimit(trace_ent, RESOURCE_ARMOR, (rootarmor * coefficient), WEP_CVAR(arc, beam_healing_amax));
+                                               trace_ent.pauserotarmor_finished = max(
+                                                       trace_ent.pauserotarmor_finished,
+                                                       time + autocvar_g_balance_pause_armor_rot
+                                               );
+                                       }
                                }
-
-                               if(trace_ent.health <= WEP_CVAR(arc, beam_healing_hmax) && roothealth)
-                               {
-                                       trace_ent.health = min(
-                                               trace_ent.health + (roothealth * coefficient),
-                                               WEP_CVAR(arc, beam_healing_hmax)
-                                       );
-                               }
-                               if(trace_ent.armorvalue <= WEP_CVAR(arc, beam_healing_amax) && rootarmor)
-                               {
-                                       trace_ent.armorvalue = min(
-                                               trace_ent.armorvalue + (rootarmor * coefficient),
-                                               WEP_CVAR(arc, beam_healing_amax)
-                                       );
-                               }
-
-                               // stop rot, set visual effect
                                if(roothealth || rootarmor)
-                               {
-                                       trace_ent.pauserothealth_finished = max(
-                                               trace_ent.pauserothealth_finished,
-                                               time + autocvar_g_balance_pause_health_rot
-                                       );
-                                       trace_ent.pauserotarmor_finished = max(
-                                               trace_ent.pauserotarmor_finished,
-                                               time + autocvar_g_balance_pause_armor_rot
-                                       );
                                        new_beam_type = ARC_BT_HEAL;
-                               }
                        }
-                       else
+                       else if(trace_ent.takedamage && (is_player || WEP_CVAR(arc, beam_nonplayerdamage)))
                        {
+                               // calculate our own hit origin as trace_endpos tends to jump around annoyingly (to player origin?)
+                               // NO. trace_endpos should be just fine. If not,
+                               // that's an engine bug that needs proper debugging.
+                               vector hitorigin = trace_endpos;
+
+                               float falloff = ExponentialFalloff(
+                                       WEP_CVAR(arc, beam_falloff_mindist),
+                                       WEP_CVAR(arc, beam_falloff_maxdist),
+                                       WEP_CVAR(arc, beam_falloff_halflifedist),
+                                       vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, hitorigin) - w_shotorg)
+                               );
+
                                float rootdamage;
                                if(is_player)
                                {
index c53e110fddb07a699988578d09067db6e73a462c..ab97e3d7f0b6c5c16ba538092b3ece2bd2aeb4df 100644 (file)
@@ -289,20 +289,20 @@ void W_Devastator_Touch(entity this, entity toucher)
 
 void W_Devastator_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        if(!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) // no exceptions
                return; // g_projectiles_damage says to halt
 
-       this.health = this.health - damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
        this.angles = vectoangles(this.velocity);
 
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_PrepareExplosionByDamage(this, attacker, W_Devastator_Explode_think);
 }
 
-void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity)
+void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        W_DecreaseAmmo(thiswep, actor, WEP_CVAR(devastator, ammo), weaponentity);
 
@@ -324,7 +324,7 @@ void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity)
 
        missile.takedamage = DAMAGE_YES;
        missile.damageforcescale = WEP_CVAR(devastator, damageforcescale);
-       missile.health = WEP_CVAR(devastator, health);
+       SetResourceAmountExplicit(missile, RESOURCE_HEALTH, WEP_CVAR(devastator, health));
        missile.event_damage = W_Devastator_Damage;
        missile.damagedbycontents = true;
        IL_PUSH(g_damagedbycontents, missile);
@@ -342,6 +342,7 @@ void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        setthink(missile, W_Devastator_Think);
        missile.nextthink = time;
        missile.cnt = time + WEP_CVAR(devastator, lifetime);
+       missile.rl_detonate_later = (fire & 2); // allow instant detonation
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
        IL_PUSH(g_bot_dodge, missile);
@@ -358,6 +359,11 @@ void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity)
 
        // common properties
        MUTATOR_CALLHOOK(EditProjectile, actor, missile);
+
+       if (time >= missile.nextthink)
+       {
+               getthink(missile)(missile);
+       }
 }
 
 METHOD(Devastator, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
@@ -431,7 +437,7 @@ METHOD(Devastator, wr_aim, void(entity thiswep, entity actor, .entity weaponenti
         // but don't fire a new shot at the same time!
         if(desirabledamage >= 0.75 * coredamage) //this should do group damage in rare fortunate events
             PHYS_INPUT_BUTTON_ATCK2(actor) = true;
-        if((skill > 6.5) && (selfdamage > actor.health))
+        if((skill > 6.5) && (selfdamage > GetResourceAmount(actor, RESOURCE_HEALTH)))
             PHYS_INPUT_BUTTON_ATCK2(actor) = false;
         //if(PHYS_INPUT_BUTTON_ATCK2(actor) == true)
         //     dprint(ftos(desirabledamage),"\n");
@@ -449,7 +455,7 @@ METHOD(Devastator, wr_think, void(entity thiswep, entity actor, .entity weaponen
             if(actor.(weaponentity).rl_release || WEP_CVAR(devastator, guidestop))
             if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(devastator, refire)))
             {
-                W_Devastator_Attack(thiswep, actor, weaponentity);
+                W_Devastator_Attack(thiswep, actor, weaponentity, fire);
                 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(devastator, animtime), w_ready);
                 actor.(weaponentity).rl_release = 0;
             }
index 2276b6042ac1f45893aa0d2451c6d3b43f1f9ee5..89738289f2b84b0205020e9ae0b4f33eeca05afb 100644 (file)
@@ -258,7 +258,7 @@ void W_Electro_Orb_Stick(entity this, entity to)
 
        newproj.takedamage = this.takedamage;
        newproj.damageforcescale = this.damageforcescale;
-       newproj.health = this.health;
+       SetResourceAmountExplicit(newproj, RESOURCE_HEALTH, GetResourceAmount(this, RESOURCE_HEALTH));
        newproj.event_damage = this.event_damage;
        newproj.spawnshieldtime = this.spawnshieldtime;
        newproj.damagedbycontents = true;
@@ -300,7 +300,7 @@ void W_Electro_Orb_Touch(entity this, entity toucher)
 
 void W_Electro_Orb_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        // note: combos are usually triggered by W_Electro_TriggerCombo, not damage
@@ -309,8