Merge branch 'martin-t/rpc-acc' into 'master'
authorMario <zacjardine@y7mail.com>
Tue, 3 Jul 2018 03:16:23 +0000 (03:16 +0000)
committerMario <zacjardine@y7mail.com>
Tue, 3 Jul 2018 03:16:23 +0000 (03:16 +0000)
Fix RPC accuracy

See merge request xonotic/xonotic-data.pk3dir!535

188 files changed:
.gitlab-ci.yml
.tx/merge-base
_hud_descriptions.cfg
bal-wep-mario.cfg
bal-wep-samual.cfg
bal-wep-xdf.cfg
bal-wep-xonotic.cfg
bal-wep-xpm.cfg
commands.cfg
common.ko.po
effects-high.cfg
effects-low.cfg
effects-med.cfg
effects-normal.cfg
effects-omg.cfg
effects-ultimate.cfg
effects-ultra.cfg
gamemodes-server.cfg
models/items/a_rockets.md3
models/player/gak.iqm_0.txt
models/player/gakmasked.iqm_0.txt
models/player/ignismasked.iqm_0.txt
models/player/seraphinamasked.iqm_0.txt
mutators.cfg
physicsX07.cfg
qcsrc/client/_mod.inc
qcsrc/client/_mod.qh
qcsrc/client/announcer.qc
qcsrc/client/autocvars.qh
qcsrc/client/commands/cl_cmd.qc
qcsrc/client/hud/hud.qh
qcsrc/client/hud/panel/radar.qc
qcsrc/client/hud/panel/scoreboard.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/subs.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/damagetext/sv_damagetext.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/movetypes/movetypes.qc
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/shotgun.qc
qcsrc/common/weapons/weapon/vaporizer.qc
qcsrc/ecs/systems/physics.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
scripts/explosiveammo.shader [new file with mode: 0644]
textures/items/a_rocket_bottom.jpg [deleted file]
textures/items/a_rocket_box.jpg [deleted file]
textures/items/a_rocket_gre.jpg [deleted file]
textures/items/a_rocket_gre_glow.jpg [deleted file]
textures/items/a_rocket_roc.jpg [deleted file]
textures/items/a_rocket_roc_gloss.jpg [deleted file]
textures/items/a_rocket_roc_glow.jpg [deleted file]
textures/items/a_rocket_roc_norm.jpg [deleted file]
textures/items/a_rocket_tag.jpg [deleted file]
textures/items/explosiveammo.tga [new file with mode: 0644]
textures/items/explosiveammo_gloss.tga [new file with mode: 0644]
textures/items/explosiveammo_glow.tga [new file with mode: 0644]
textures/items/explosiveammo_icon_01.tga [new file with mode: 0644]
textures/items/explosiveammo_icon_01_glow.tga [new file with mode: 0644]
textures/items/explosiveammo_icon_02.tga [new file with mode: 0644]
textures/items/explosiveammo_icon_02_glow.tga [new file with mode: 0644]
textures/items/explosiveammo_icon_03.tga [new file with mode: 0644]
textures/items/explosiveammo_icon_03_glow.tga [new file with mode: 0644]
textures/items/explosiveammo_icon_blank.tga [new file with mode: 0644]
textures/items/explosiveammo_norm.tga [new file with mode: 0644]
textures/items/explosiveammo_reflect.tga [new file with mode: 0644]
xonotic-client.cfg
xonotic-server.cfg

index e50392c..153b172 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=b8f4fa5002af1f9f2d5ac3d1809ed188
     - HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
       | tee /dev/stderr
       | grep '^:'
index 9745f61..ca7140d 100644 (file)
@@ -1 +1 @@
-Sun Jun  3 07:24:16 CEST 2018
+Wed Jun 20 07:24:25 CEST 2018
index 9a1654f..30e5a8b 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 89e2e62..d2ff12f 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
index 380d93e..1816f3f 100644 (file)
@@ -322,7 +322,7 @@ 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
index fcf6867..2e0e74a 100644 (file)
@@ -256,7 +256,7 @@ 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
 set g_balance_crylink_secondary_bounces 0
@@ -392,7 +392,7 @@ set g_balance_devastator_guiderate 0
 set g_balance_devastator_guideratedelay 999
 set g_balance_devastator_guidestop 1
 set g_balance_devastator_health 30
-set g_balance_devastator_lifetime 100
+set g_balance_devastator_lifetime 20
 set g_balance_devastator_radius 110
 set g_balance_devastator_refire 0.9
 set g_balance_devastator_reload_ammo 0
index e55e860..5c6ace7 100644 (file)
@@ -256,7 +256,7 @@ 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
@@ -883,7 +883,7 @@ set g_balance_okmachinegun_primary_ammo 1
 set g_balance_okmachinegun_primary_damage 25
 set g_balance_okmachinegun_primary_force 5
 set g_balance_okmachinegun_primary_refire 0.1
-set g_balance_okmachinegun_primary_solidpenetration 13.1
+set g_balance_okmachinegun_primary_solidpenetration 63
 set g_balance_okmachinegun_primary_spread_add 0.012
 set g_balance_okmachinegun_primary_spread_max 0.05
 set g_balance_okmachinegun_primary_spread_min 0
index b16e787..a5438d1 100644 (file)
@@ -256,7 +256,7 @@ 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
index 0e765b8..b2edf84 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 0407c66..4d65b27 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 48c8253..597bb46 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 1
 cl_playerdetailreduction 4
 gl_flashblend 0
 gl_picmip -1
+gl_texturecompression_2d 0
+gl_texturecompression_sky 0
 mod_q3bsp_nolightmaps 0
 r_bloom 1
 r_coronas 1
index b7e9a98..c954958 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 0
 cl_playerdetailreduction 4
 gl_flashblend 1
 gl_picmip 1
+gl_texturecompression_2d 1
+gl_texturecompression_sky 1
 mod_q3bsp_nolightmaps 1
 r_bloom 0
 r_coronas 1
index 66eed5a..4ea20a1 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 0
 cl_playerdetailreduction 4
 gl_flashblend 0
 gl_picmip 0
+gl_texturecompression_2d 0
+gl_texturecompression_sky 1
 mod_q3bsp_nolightmaps 0
 r_bloom 0
 r_coronas 1
index 63dcd13..c421e5b 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 1
 cl_playerdetailreduction 4
 gl_flashblend 0
 gl_picmip 0
+gl_texturecompression_2d 0
+gl_texturecompression_sky 1
 mod_q3bsp_nolightmaps 0
 r_bloom 0
 r_coronas 1
index 9018ee2..7614417 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 0
 cl_playerdetailreduction 4
 gl_flashblend 1
 gl_picmip 1337
+gl_texturecompression_2d 1
+gl_texturecompression_sky 1
 mod_q3bsp_nolightmaps 1
 r_bloom 0
 r_coronas 1
index 0cf3a89..3ce6f55 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 1
 cl_playerdetailreduction 0
 gl_flashblend 0
 gl_picmip -1
+gl_texturecompression_2d 0
+gl_texturecompression_sky 0
 mod_q3bsp_nolightmaps 0
 r_bloom 1
 r_coronas 1
index 5909f3b..d42d7c5 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 1
 cl_playerdetailreduction 0
 gl_flashblend 0
 gl_picmip -1
+gl_texturecompression_2d 0
+gl_texturecompression_sky 0
 mod_q3bsp_nolightmaps 0
 r_bloom 1
 r_coronas 1
index 7319cba..41b5fc5 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 3f1a594..3e9a8f8 100644 (file)
Binary files a/models/items/a_rockets.md3 and b/models/items/a_rockets.md3 differ
index 27b5790..efdb0b2 100644 (file)
@@ -10,3 +10,4 @@ bone_aim1 0.4 spine4
 bone_aim2 0.35 bip01 r hand
 bone_weapon bip01 r hand
 fixbone 1
+hidden 1
index 44843b7..fbc6b67 100644 (file)
@@ -1,4 +1,4 @@
-name Gak Masked
+name Gak
 species alien
 sex Male
 weight 87
index 2610d2b..4a35d90 100644 (file)
@@ -11,3 +11,4 @@ bone_aim2 0.2 upperarm_L
 bone_aim3 0.35 bip01 r hand
 bone_weapon bip01 r hand
 fixbone 1
+hidden 1
index c997d01..76ca617 100644 (file)
@@ -10,3 +10,4 @@ bone_aim1 0.4 spine4
 bone_aim2 0.35 bip01 r hand
 bone_weapon bip01 r hand
 fixbone 1
+hidden 1
index a4c8144..afa1782 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 8ae771f..6135463 100644 (file)
@@ -1,5 +1,5 @@
 g_mod_physics Xonotic
-// current Xonotic physics
+// Xonotic 0.7 physics
 
 sv_gravity 800
 sv_maxspeed 360
index aa20961..ab9184b 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 ecfa4ee..971cc01 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 bcbe724..0195db4 100644 (file)
@@ -129,6 +129,9 @@ void Announcer_Gamestart()
 
 void Announcer_Time()
 {
+       if(intermission)
+               return;
+
        float timeleft;
        if(warmup_stage)
        {
index b6b33c3..8eb3ca1 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 034bb63..1a6a9f8 100644 (file)
@@ -325,7 +325,8 @@ void LocalCommand_hud(int request, int argc)
 
                                case "clickradar":
                                {
-                                       HUD_Radar_Show_Maximized(!hud_panel_radar_mouse, 1);
+                                       if(!isdemo())
+                                               HUD_Radar_Show_Maximized(!hud_panel_radar_mouse, 1);
                                        return;
                                }
                        }
index 950dee1..68d1e6b 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 f0ec01c..bd94520 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 5b8964d..91d9f6f 100644 (file)
@@ -294,8 +294,11 @@ void Cmd_Scoreboard_Help()
 {
        LOG_INFO(_("You can modify the scoreboard using the ^2scoreboard_columns_set command."));
        LOG_INFO(_("Usage:"));
-       LOG_INFO("^2scoreboard_columns_set default");
-       LOG_INFO(_("^2scoreboard_columns_set ^7field1 field2 ..."));
+       LOG_INFO("^2scoreboard_columns_set ^3default");
+       LOG_INFO(_("^2scoreboard_columns_set ^3field1 field2 ..."));
+       LOG_INFO(_("^2scoreboard_columns_set ^7without arguments reads the arguments from the cvar scoreboard_columns"));
+       LOG_INFO(_("  ^5Note: ^7scoreboard_columns_set without arguments is executed on every map start"));
+       LOG_INFO(_("^2scoreboard_columns_set ^3expand_default ^7loads default layout and expands it into the cvar scoreboard_columns so you can edit it"));
        LOG_INFO(_("You can use a ^3|^7 to start the right-aligned fields."));
        LOG_INFO(_("The following field names are recognized (case insensitive):"));
        LOG_INFO("");
@@ -401,8 +404,12 @@ void Cmd_Scoreboard_SetFields(int argc)
 
        if(argc == 3)
        {
-               if(argv(2) == "default")
+               if(argv(2) == "default" || argv(2) == "expand_default")
+               {
+                       if(argv(2) == "expand_default")
+                               cvar_set("scoreboard_columns", SCOREBOARD_DEFAULT_COLUMNS);
                        argc = tokenizebyseparator(strcat("0 1 ", SCOREBOARD_DEFAULT_COLUMNS), " ");
+               }
                else if(argv(2) == "all")
                {
                        string s = "ping pl name |"; // scores without a label
index 4506f69..5d75c7d 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 3de8cef..218df18 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 a95acd5..69c3fa3 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 f23a397..0143d1a 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 8a7d225..7c1ece5 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 d036bd7..2538299 100644 (file)
@@ -491,9 +491,8 @@ vector GetCurrentFov(float fov)
        if(zoomfactor < 1 || zoomfactor > 30)
                zoomfactor = 2.5;
        zoomspeed = autocvar_cl_zoomspeed;
-       if(zoomspeed >= 0)
-       if(zoomspeed < 0.5 || zoomspeed > 16)
-                       zoomspeed = 3.5;
+       if (zoomspeed >= 0 && (zoomspeed < 0.5 || zoomspeed > 16))
+               zoomspeed = 3.5;
 
        zoomdir = button_zoom;
 
@@ -526,7 +525,11 @@ vector GetCurrentFov(float fov)
 
        if(zoomdir) { zoomin_effect = 0; }
 
-       if(camera_active)
+       if (spectatee_status > 0 && STAT(CAMERA_SPECTATOR) == 2)
+       {
+               current_viewzoom = 1;
+       }
+       else if (camera_active)
        {
                current_viewzoom = min(1, current_viewzoom + drawframetime);
        }
@@ -570,10 +573,10 @@ vector GetCurrentFov(float fov)
 
        if(autocvar_cl_velocityzoom_enabled && autocvar_cl_velocityzoom_type) // _type = 0 disables velocity zoom too
        {
-               if(intermission) { curspeed = 0; }
+               if (intermission || (spectatee_status > 0 && STAT(CAMERA_SPECTATOR) == 2))
+                       curspeed = 0;
                else
                {
-
                        makevectors(view_angles);
                        v = pmove_vel;
                        if(csqcplayer)
@@ -2057,7 +2060,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 983b073..41c5d30 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 bbca691..86acdc1 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 ba3d996..9601731 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,8 @@ 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)
+       float hlth = GetResourceAmount(this, RESOURCE_HEALTH);
+       if (hlth < 0 || hlth >= ASSAULT_VALUE_INACTIVE)
                return '-1 0 0';
        return current;
 }
@@ -40,7 +41,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 +62,19 @@ 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)
+       float hlth = GetResourceAmount(this.enemy, RESOURCE_HEALTH);
+       if (hlth < ASSAULT_VALUE_INACTIVE)
        {
-               if(this.enemy.health - this.dmg > 0.5)
+               if (hlth - 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, hlth);
                        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 +101,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 +129,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 +178,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 +325,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 +333,22 @@ 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);
+       float hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       if (hlth <= 0 || hlth >= 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 +356,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 +414,8 @@ 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)
+                       float hlth = GetResourceAmount(it.enemy, RESOURCE_HEALTH);
+                       if (hlth > 0 && hlth < ASSAULT_VALUE_INACTIVE)
                        {
                                found = true;
                                break;
index 561129c..f4aea43 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 c7ade84..3f96b41 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;
@@ -1578,7 +1578,7 @@ void havocbot_goalrating_ctf_carrieritems(entity this, float ratingscale, vector
        {
                // gather health and armor only
                if (it.solid)
-               if (it.health || it.armorvalue)
+               if (GetResourceAmount(it, RESOURCE_HEALTH) || GetResourceAmount(it, RESOURCE_ARMOR))
                if (vdist(it.origin - org, <, sradius))
                {
                        // get the value of the item
@@ -1673,7 +1673,7 @@ void havocbot_role_ctf_carrier(entity this)
                else
                        havocbot_goalrating_ctf_ourbase(this, 50000);
 
-               if(this.health<100)
+               if(GetResourceAmount(this, RESOURCE_HEALTH) < 100)
                        havocbot_goalrating_ctf_carrieritems(this, 1000, this.origin, 1000);
 
                navigation_goalrating_end(this);
@@ -1819,7 +1819,7 @@ void havocbot_role_ctf_offense(entity this)
        }
 
        // About to fail, switch to middlefield
-       if(this.health<50)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) < 50)
        {
                havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
                return;
@@ -2131,7 +2131,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
@@ -2159,7 +2159,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 74a3993..2f9643b 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 12319c2..6190289 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 3faa4a8..24a8220 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 cceff48..7f126ce 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(STAT(FROZEN, it) != 1 && GetResourceAmount(it, RESOURCE_HEALTH) >= 1) ++redalive; break;
+                       case NUM_TEAM_2: ++total_players; if(STAT(FROZEN, it) != 1 && GetResourceAmount(it, RESOURCE_HEALTH) >= 1) ++bluealive; break;
+                       case NUM_TEAM_3: ++total_players; if(STAT(FROZEN, it) != 1 && GetResourceAmount(it, RESOURCE_HEALTH) >= 1) ++yellowalive; break;
+                       case NUM_TEAM_4: ++total_players; if(STAT(FROZEN, it) != 1 && GetResourceAmount(it, RESOURCE_HEALTH) >= 1) ++pinkalive; break;
                }
        });
        FOREACH_CLIENT(IS_REAL_CLIENT(it), {
@@ -139,14 +141,14 @@ float freezetag_CheckWinner()
 entity freezetag_LastPlayerForTeam(entity this)
 {
        entity last_pl = NULL;
-       FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
-               if(it.health >= 1)
-               if(!STAT(FROZEN, it))
-               if(SAME_TEAM(it, this))
-               if(!last_pl)
-                       last_pl = it;
-               else
-                       return NULL;
+       FOREACH_CLIENT(IS_PLAYER(it) && it != this && SAME_TEAM(it, this), {
+               if (!STAT(FROZEN, it) && GetResourceAmount(it, RESOURCE_HEALTH) >= 1)
+               {
+                       if (!last_pl)
+                               last_pl = it;
+                       else
+                               return NULL;
+               }
        });
        return last_pl;
 }
@@ -180,6 +182,7 @@ void freezetag_Add_Score(entity targ, entity attacker)
        // else nothing - got frozen by the game type rules themselves
 }
 
+// to be called when the player is frozen by freezetag (on death, spectator join etc), gives the score
 void freezetag_Freeze(entity targ, entity attacker)
 {
        if(STAT(FROZEN, targ))
@@ -195,14 +198,6 @@ void freezetag_Freeze(entity targ, entity attacker)
        freezetag_Add_Score(targ, attacker);
 }
 
-void freezetag_Unfreeze(entity this)
-{
-       this.freezetag_frozen_time = 0;
-       this.freezetag_frozen_timeout = 0;
-
-       Unfreeze(this);
-}
-
 float freezetag_isEliminated(entity e)
 {
        if(IS_PLAYER(e) && (STAT(FROZEN, e) == 1 || IS_DEAD(e)))
@@ -232,7 +227,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,10 +303,10 @@ 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);
+       Unfreeze(this);
        freezetag_count_alive_players();
 }
 
@@ -340,7 +335,7 @@ MUTATOR_HOOKFUNCTION(ft, PlayerDies)
        if(round_handler_CountdownRunning())
        {
                if(STAT(FROZEN, frag_target))
-                       freezetag_Unfreeze(frag_target);
+                       Unfreeze(frag_target);
                freezetag_count_alive_players();
                return true; // let the player die so that he can respawn whenever he wants
        }
@@ -358,8 +353,8 @@ MUTATOR_HOOKFUNCTION(ft, PlayerDies)
                        freezetag_LastPlayerForTeam_Notify(frag_target);
                }
                else
-                       freezetag_Unfreeze(frag_target); // remove ice
-               frag_target.health = 0; // Unfreeze resets health
+                       Unfreeze(frag_target); // remove ice
+               SetResourceAmountExplicit(frag_target, RESOURCE_HEALTH, 0); // Unfreeze resets health
                frag_target.freezetag_frozen_timeout = -2; // freeze on respawn
                return true;
        }
@@ -427,6 +422,15 @@ MUTATOR_HOOKFUNCTION(ft, GiveFragsForKill, CBC_ORDER_FIRST)
        return true;
 }
 
+MUTATOR_HOOKFUNCTION(ft, Unfreeze)
+{
+       entity targ = M_ARGV(0, entity);
+       targ.freezetag_frozen_time = 0;
+       targ.freezetag_frozen_timeout = 0;
+
+       freezetag_count_alive_players();
+}
+
 MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
 {
        if(game_stopped)
@@ -468,11 +472,11 @@ 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)
                {
-                       freezetag_Unfreeze(player);
+                       Unfreeze(player);
                        freezetag_count_alive_players();
 
                        if(n == -1)
@@ -502,7 +506,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 +568,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;
 }
@@ -577,7 +582,7 @@ void freezetag_Initialize()
 
        freezetag_teams = BITS(bound(2, freezetag_teams, 4));
        GameRules_scoring(freezetag_teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {
-           field(SP_FREEZETAG_REVIVALS, "revivals", 0);
+               field(SP_FREEZETAG_REVIVALS, "revivals", 0);
        });
 
        round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null);
index d6f9860..3dff701 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 8eb88a3..c8bfbf2 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 426b341..487012a 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 a03e5b3..b8d49b1 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 a3374bf..9d12c55 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 80d6a6b..5deef7e 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 d3b6d5c..a00af18 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 ac0596f..a33a430 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 c4f4d32..f0217de 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,23 @@ 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 hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
+       if (hlth <= 0 || hlth >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       if(targ.owner.iscaptured)
+               WaypointSprite_UpdateHealth(targ.owner.sprite, hlth);
+       else
+               WaypointSprite_UpdateBuildFinished(targ.owner.sprite, time + (targ.max_health - hlth) / (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 +486,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 +497,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 +519,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 +541,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 +557,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 +580,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 +595,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 +614,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 +656,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 +905,15 @@ 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);
+       float hlth = GetResourceAmount(this, RESOURCE_HEALTH);
+       WaypointSprite_UpdateHealth(this.sprite, hlth);
        // 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 - hlth / this.max_health), 1);
        // see if the generator is still functional, or dying
-       if (this.health > 0)
+       if (hlth > 0)
        {
-               this.lasthealth = this.health;
+               this.lasthealth = hlth;
        }
        else
        {
@@ -912,6 +929,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 +964,48 @@ 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);
+       float hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       if (hlth <= 0 || hlth >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       WaypointSprite_UpdateHealth(targ.sprite, hlth);
+       targ.frame = 10 * bound(0, (1 - hlth / targ.max_health), 1);
+       targ.lasthealth = hlth;
+       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 +1014,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 +1024,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 +1071,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 +1099,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 +1117,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 +1261,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 +1286,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);
@@ -1972,7 +2010,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;
@@ -1987,7 +2025,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;
@@ -2053,14 +2091,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 31b8f43..3109e7c 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 7c5c12a..4c37464 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 880a932..ee39aa5 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 6a5ffc5..bf515fe 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 73f55e8..7600338 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 d8f6cb1..cb17ac4 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 28e6481..44e3128 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 c19041a..8d40a37 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 41fd05e..39c02a8 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 78e0dd6..f06f39e 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 4747877..cc909e5 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 4877d0f..f9e50dc 100644 (file)
@@ -553,7 +553,7 @@ void InitTrigger(entity this)
 // to mean no restrictions, so use a yaw of 360 instead.
        SetMovedir(this);
        this.solid = SOLID_TRIGGER;
-       SetBrushEntityModel(this);
+       SetBrushEntityModelNoLOD(this);
        set_movetype(this, MOVETYPE_NONE);
        this.modelindex = 0;
        this.model = "";
@@ -565,7 +565,7 @@ void InitSolidBSPTrigger(entity this)
 // to mean no restrictions, so use a yaw of 360 instead.
        SetMovedir(this);
        this.solid = SOLID_BSP;
-       SetBrushEntityModel(this);
+       SetBrushEntityModelNoLOD(this);
        set_movetype(this, MOVETYPE_NONE); // why was this PUSH? -div0
 //     this.modelindex = 0;
        this.model = "";
index ec6a26d..403d956 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 cfcd726..866fd88 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 accfbe8..5447b99 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 9377332..5d7c5b6 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 058e41c..8e3fd73 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 b8b647b..88120a0 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 eeefeae..9981474 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 12277d1..5e2cc05 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 0a52e61..f6c905d 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 297bab8..aaa27d2 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 b4861b9..84355c7 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 4be441d..27f71b5 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 b88d96d..d9eacaa 100644 (file)
@@ -4,7 +4,7 @@ AUTOCVAR(sv_damagetext, int, 2, "<= 0: disabled, >= 1: visible to spectators, >=
 
 REGISTER_MUTATOR(damagetext, true);
 
-#define SV_DAMAGETEXT_DISABLED()        (autocvar_sv_damagetext <= 0 || MUTATOR_IS_ENABLED(mutator_instagib))
+#define SV_DAMAGETEXT_DISABLED()        (autocvar_sv_damagetext <= 0)
 #define SV_DAMAGETEXT_SPECTATORS_ONLY() (autocvar_sv_damagetext >= 1)
 #define SV_DAMAGETEXT_PLAYERS()         (autocvar_sv_damagetext >= 2)
 #define SV_DAMAGETEXT_ALL()             (autocvar_sv_damagetext >= 3)
@@ -16,6 +16,7 @@ MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) {
     const float armor = M_ARGV(3, float);
     const int deathtype = M_ARGV(5, int);
     const float potential_damage = M_ARGV(6, float);
+    if(DEATH_WEAPONOF(deathtype) == WEP_VAPORIZER) return;
     FOREACH_CLIENT(IS_REAL_CLIENT(it), {
         if (
             (SV_DAMAGETEXT_ALL()) ||
index 95f4f32..3f8d087 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 e68c687..443fe24 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 7da7c07..68a3af3 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 a691b86..1fdf5fd 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 540edc6..37dac8f 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 da5dcc2..586deda 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 c786a92..3174fa7 100644 (file)
@@ -36,15 +36,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);
 }
 
@@ -100,7 +100,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 61c302c..ee2a5be 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 b446c92..5619818 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 d0f01a5..115e6ca 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 326a262..dcbb65f 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 b4d1403..a15ef80 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 3fe2808..9ac3e42 100644 (file)
@@ -351,37 +351,50 @@ void _Movetype_LinkEdict_TouchAreaGrid(entity this)  // SV_LinkEdict_TouchAreaGr
     });
 }
 
+bool autocvar__movetype_debug = false;
 void _Movetype_LinkEdict(entity this, bool touch_triggers)  // SV_LinkEdict
 {
-       vector mi, ma;
-       if(this.solid == SOLID_BSP)
+       if(autocvar__movetype_debug)
        {
-               // TODO set the absolute bbox
-               mi = this.mins;
-               ma = this.maxs;
-       }
-       else
-       {
-               mi = this.mins;
-               ma = this.maxs;
-       }
-       mi += this.origin;
-       ma += this.origin;
+               vector mi, ma;
+               if(this.solid == SOLID_BSP)
+               {
+                       // TODO set the absolute bbox
+                       mi = this.mins;
+                       ma = this.maxs;
+               }
+               else
+               {
+                       mi = this.mins;
+                       ma = this.maxs;
+               }
+               mi += this.origin;
+               ma += this.origin;
 
-       if(this.flags & FL_ITEM)
-       {
-               mi -= '15 15 1';
-               ma += '15 15 1';
+               if(this.flags & FL_ITEM)
+               {
+                       mi -= '15 15 1';
+                       ma += '15 15 1';
+               }
+               else
+               {
+                       mi -= '1 1 1';
+                       ma += '1 1 1';
+               }
+
+               this.absmin = mi;
+               this.absmax = ma;
        }
        else
        {
-               mi -= '1 1 1';
-               ma += '1 1 1';
+               setorigin(this, this.origin); // calls SV_LinkEdict
+       #ifdef CSQC
+               // NOTE: CSQC's version of setorigin doesn't expand
+               this.absmin -= '1 1 1';
+               this.absmax += '1 1 1';
+       #endif
        }
 
-       this.absmin = mi;
-       this.absmax = ma;
-
        if(touch_triggers)
                _Movetype_LinkEdict_TouchAreaGrid(this);
 }
@@ -519,6 +532,8 @@ void _Movetype_Physics_Frame(entity this, float movedt)
                case MOVETYPE_FLY:
                case MOVETYPE_FLY_WORLDONLY:
                        _Movetype_Physics_Toss(this, movedt);
+                       if(wasfreed(this))
+                               return;
                        _Movetype_LinkEdict(this, true);
                        break;
                case MOVETYPE_PHYSICS:
index 2b9808a..2f4ebb1 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 a562292..8e33c64 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 ea93618..37813ef 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 f4ed4f1..140b619 100644 (file)
@@ -742,14 +742,14 @@ float Item_GiveAmmoTo(entity item, entity player, int resource_type, float ammom
                {
                        return false;
                }
-               GiveResourceWithLimit(player, resource_type, amount, ammomax);
+               GiveOrTakeResourceWithLimit(player, resource_type, amount, ammomax);
                return true;
        }
        if (g_weapon_stay != 2)
        {
                return false;
        }
-       GiveResourceWithLimit(player, resource_type, amount, min(amount, ammomax));
+       GiveOrTakeResourceWithLimit(player, resource_type, amount, min(amount, ammomax));
        return true;
 }
 
@@ -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 50228a0..9fdb0b0 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 ba7b5d0..ac68003 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;
 }
diff --git