]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Mario/event_heal
authorMario <mario@smbclan.net>
Sun, 17 Jun 2018 22:29:23 +0000 (08:29 +1000)
committerMario <mario@smbclan.net>
Sun, 17 Jun 2018 22:29:23 +0000 (08:29 +1000)
17 files changed:
qcsrc/common/gamemodes/gamemode/assault/assault.qc
qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc
qcsrc/common/mapobjects/trigger/heal.qc
qcsrc/common/monsters/monster/mage.qc
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/mutators/mutator/vampirehook/sv_vampirehook.qc
qcsrc/common/turrets/cl_turrets.qc
qcsrc/common/turrets/sv_turrets.qc
qcsrc/common/vehicles/sv_vehicles.qc
qcsrc/common/vehicles/vehicle/bumblebee.qc
qcsrc/common/weapons/weapon/arc.qc
qcsrc/server/client.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_damage.qh
qcsrc/server/player.qc
qcsrc/server/player.qh

index 97a7b4df28d0a77c03c3e0c04d489d7c244d5543..b9b5c361ce737596a410bf66c02d89419f57211d 100644 (file)
@@ -331,6 +331,21 @@ spawnfunc(target_objective_decrease)
 }
 
 // destructible walls that can be used to trigger target_objective_decrease
+bool destructible_heal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit >= 0) ? limit : targ.max_health);
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       if(targ.sprite)
+       {
+               WaypointSprite_UpdateHealth(targ.sprite, GetResourceAmount(targ, RESOURCE_HEALTH));
+       }
+       func_breakable_colormod(targ);
+       return true;
+}
+
 spawnfunc(func_breakable);
 spawnfunc(func_assault_destructible)
 {
@@ -338,6 +353,7 @@ spawnfunc(func_assault_destructible)
 
        this.spawnflags = 3;
        this.classname = "func_assault_destructible";
+       this.event_heal = destructible_heal;
        IL_PUSH(g_assault_destructibles, this);
 
        if(assault_attacker_team == NUM_TEAM_1)
index 15aedc732d15c95283baf0c1f58cad87efc20022..90ab772342e537a5a961bf910c5f30dff2463b1f 100644 (file)
@@ -447,6 +447,21 @@ void ons_ControlPoint_Icon_Damage(entity this, entity inflictor, entity attacker
        this.SendFlags |= CPSF_STATUS;
 }
 
+bool ons_ControlPoint_Icon_Heal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit >= 0) ? limit : targ.max_health);
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       if(targ.owner.iscaptured)
+               WaypointSprite_UpdateHealth(targ.owner.sprite, GetResourceAmount(targ, RESOURCE_HEALTH));
+       else
+               WaypointSprite_UpdateBuildFinished(targ.owner.sprite, time + (targ.max_health - GetResourceAmount(targ, RESOURCE_HEALTH)) / (targ.count / ONS_CP_THINKRATE));
+       targ.SendFlags |= CPSF_STATUS;
+       return true;
+}
+
 void ons_ControlPoint_Icon_Think(entity this)
 {
        this.nextthink = time + ONS_CP_THINKRATE;
@@ -584,6 +599,7 @@ void ons_ControlPoint_Icon_Spawn(entity cp, entity player)
        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 - GetResourceAmount(e, RESOURCE_HEALTH)) * ONS_CP_THINKRATE / autocvar_g_onslaught_cp_buildtime; // how long it takes to build
@@ -910,6 +926,7 @@ void ons_GeneratorDamage(entity this, entity inflictor, entity attacker, float d
                this.isshielded = false;
                this.takedamage = DAMAGE_NO; // can't be hurt anymore
                this.event_damage = func_null; // won't do anything if hurt
+               this.event_heal = func_null;
                this.count = 0; // reset counter
                setthink(this, func_null);
                this.nextthink = 0;
@@ -944,6 +961,20 @@ 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 >= 0) ? limit : targ.max_health);
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       WaypointSprite_UpdateHealth(targ.sprite, GetResourceAmount(targ, RESOURCE_HEALTH));
+       targ.frame = 10 * bound(0, (1 - GetResourceAmount(targ, RESOURCE_HEALTH) / targ.max_health), 1);
+       targ.lasthealth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       targ.SendFlags |= GSF_STATUS;
+       return true;
+}
+
 void ons_GeneratorThink(entity this)
 {
        this.nextthink = time + GEN_THINKRATE;
@@ -978,6 +1009,7 @@ void ons_GeneratorReset(entity this)
        this.islinked = true;
        this.isshielded = true;
        this.event_damage = ons_GeneratorDamage;
+       this.event_heal = ons_GeneratorHeal;
        setthink(this, ons_GeneratorThink);
        this.nextthink = time + GEN_THINKRATE;
 
@@ -1040,6 +1072,7 @@ void ons_GeneratorSetup(entity gen) // called when spawning a generator entity o
        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;
index 61f27a0219184340edfeca6bd40a3f7d6ac46156..fb20ebdbadbbd45c45edd73e0b3e93723cb2580c 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 (GetResourceAmount(toucher, RESOURCE_HEALTH) < this.max_health)
-                       {
-                               playthesound = true;
-                               GiveResourceWithLimit(toucher, RESOURCE_HEALTH, GetResourceAmount(this, RESOURCE_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);
                }
        }
index b26328a54593fc325c9b940a6eb21c5fb4062c28..a49430fbc88f58a1cbdc55e8dbc56ee96c2a284f 100644 (file)
@@ -234,9 +234,11 @@ void M_Mage_Defend_Heal(entity this)
                        switch(this.skin)
                        {
                                case 0:
-                                       GiveResourceWithLimit(it, RESOURCE_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:
                                {
                                        if(GetResourceAmount(this, RESOURCE_CELLS)) GiveResourceWithLimit(it, RESOURCE_CELLS, 1, g_pickup_cells_max);
@@ -267,7 +269,7 @@ void M_Mage_Defend_Heal(entity this)
                else
                {
                        Send_Effect(EFFECT_HEALING, it.origin, '0 0 0', 1);
-                       GiveResourceWithLimit(it, RESOURCE_HEALTH, autocvar_g_monster_mage_heal_allies, it.max_health);
+                       Heal(it, this, autocvar_g_monster_mage_heal_allies, -1);
                        if(!(it.spawnflags & MONSTERFLAG_INVINCIBLE) && it.sprite)
                                WaypointSprite_UpdateHealth(it.sprite, GetResourceAmount(it, RESOURCE_HEALTH));
                }
index 63f4418dec6cc4b7dae80cd7244fcdeaea254c22..810732b10ac62a4b55da2efbe40371eeec4df0ff 100644 (file)
@@ -527,6 +527,7 @@ 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;
@@ -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;
@@ -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 >= 0) ? 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)
 {
@@ -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 319b518665fff22505ba0afaf5256187257b443c..115e6ca9109341fcaa4c61974eaafe416b342f15 100644 (file)
@@ -27,10 +27,8 @@ MUTATOR_HOOKFUNCTION(vh, GrappleHookThink)
                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))
-                       GiveResourceWithLimit(thehook.aiment, RESOURCE_HEALTH, autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
-               else
-                       GiveResourceWithLimit(thehook.owner, RESOURCE_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)
                        TakeResource(dmgent, RESOURCE_HEALTH, autocvar_g_vampirehook_damage); // FIXME: friendly fire?!
index fb27cd12137fef8e36cd30dfb09f133077c3cf6c..ac68003a6cde83c1a6b652959af1f349240654e1 100644 (file)
@@ -425,8 +425,10 @@ NET_HANDLE(ENT_CLIENT_TURRET, bool isnew)
                float myhp = GetResourceAmount(this, RESOURCE_HEALTH);
                if(_tmp == 0 && myhp != 0)
                        turret_die(this);
-               else if(myhp && myhp != _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
 
                SetResourceAmountExplicit(this, RESOURCE_HEALTH, _tmp);
        }
index a02ce07aca2454367cacbc86cea4242fb6bf05b5..db33ca7cb4def2ddb22f2e64c3d314ce2cdd543e 100644 (file)
@@ -182,6 +182,7 @@ void turret_die(entity this)
        this.tur_head.solid      = this.solid;
 
        this.event_damage                 = func_null;
+       this.event_heal = func_null;
        this.takedamage                  = DAMAGE_NO;
 
        SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0);
@@ -248,6 +249,8 @@ void turret_damage(entity this, entity inflictor, entity attacker, float damage,
        {
                this.event_damage                 = func_null;
                this.tur_head.event_damage = func_null;
+               this.event_heal = func_null;
+               this.tur_head.event_heal = func_null;
                this.takedamage                  = DAMAGE_NO;
                this.nextthink = time;
                setthink(this, turret_die);
@@ -256,6 +259,17 @@ void turret_damage(entity this, entity inflictor, entity attacker, float damage,
        this.SendFlags  |= TNSF_STATUS;
 }
 
+bool turret_heal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit >= 0) ? limit : targ.max_health);
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       targ.SendFlags |= TNSF_STATUS;
+       return true;
+}
+
 void turret_think(entity this);
 void turret_respawn(entity this)
 {
@@ -268,6 +282,7 @@ void turret_respawn(entity this)
        this.solid                                      = SOLID_BBOX;
        this.takedamage                         = DAMAGE_AIM;
        this.event_damage                       = turret_damage;
+       this.event_heal                         = turret_heal;
        this.avelocity                          = '0 0 0';
        this.tur_head.avelocity         = this.avelocity;
        this.tur_head.angles            = this.idle_aim;
@@ -1360,6 +1375,7 @@ bool turret_initialize(entity this, Turret tur)
        this.idle_aim                           = '0 0 0';
        this.turret_firecheckfunc       = turret_firecheck;
        this.event_damage                       = turret_damage;
+       this.event_heal                         = turret_heal;
        this.use                                        = turret_use;
        this.bot_attack                         = true;
        this.nextthink                          = time + 1;
index 6c34741cc710733fe7886c837dddf7859b5aacc8..5284664e96b8da4551495d8618655a1d533d1727 100644 (file)
@@ -727,6 +727,20 @@ void vehicles_damage(entity this, entity inflictor, entity attacker, float damag
        }
 }
 
+bool vehicles_heal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit >= 0) ? limit : targ.max_health);
+       //if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+       if(targ.vehicle_health <= 0 || targ.vehicle_health >= true_limit)
+               return false;
+
+       targ.vehicle_health = min(targ.vehicle_health + amount, true_limit);
+       //GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       //if(targ.owner)
+               //targ.owner.vehicle_health = (targ.vehicle_health / targ.max_health) * 100;
+       return true;
+}
+
 bool vehicles_crushable(entity e)
 {
        if(IS_PLAYER(e) && time >= e.vehicle_enter_delay)
@@ -1005,6 +1019,7 @@ void vehicles_enter(entity pl, entity veh)
        setsize(pl, STAT(PL_MIN, pl), STAT(PL_MAX, pl));
 
        veh.event_damage        = vehicles_damage;
+       veh.event_heal          = vehicles_heal;
        veh.nextthink           = 0;
        pl.items &= ~IT_USING_JETPACK;
        pl.angles                       = veh.angles;
@@ -1118,6 +1133,7 @@ void vehicles_spawn(entity this)
        this.owner                              = NULL;
        settouch(this, vehicles_touch);
        this.event_damage               = vehicles_damage;
+       this.event_heal                 = vehicles_heal;
        this.reset                              = vehicles_reset;
        this.iscreature                 = true;
        this.teleportable               = false; // no teleporting for vehicles, too buggy
@@ -1230,6 +1246,7 @@ bool vehicle_initialize(entity this, Vehicle info, bool nodrop)
        this.vehicleid                          = info.vehicleid;
        this.PlayerPhysplug                     = info.PlayerPhysplug;
        this.event_damage                       = func_null;
+       this.event_heal                         = func_null;
        settouch(this, vehicles_touch);
        setthink(this, vehicles_spawn);
        this.nextthink                          = time;
index da21a4bcb42d5e599fc5fdf4aae1a4fbbb49b172..32a5a2aded881324acc4c6f50350ecf3c58b39db 100644 (file)
@@ -544,36 +544,27 @@ bool bumblebee_pilot_frame(entity this, float dt)
                        else
                        {
                                if(!IS_DEAD(trace_ent))
+                               {
                                        if((teamplay && trace_ent.team == this.team) || !teamplay)
                                        {
+                                               if(autocvar_g_vehicle_bumblebee_healgun_hps)
+                                               {
+                                                       float hplimit = ((IS_PLAYER(trace_ent)) ? autocvar_g_vehicle_bumblebee_healgun_hmax : -1);
+                                                       Heal(trace_ent, this, autocvar_g_vehicle_bumblebee_healgun_hps * dt, hplimit);
+                                               }
 
                                                if(IS_VEHICLE(trace_ent))
                                                {
                                                        if(autocvar_g_vehicle_bumblebee_healgun_sps && trace_ent.vehicle_health <= trace_ent.max_health)
                                                                trace_ent.vehicle_shield = min(trace_ent.vehicle_shield + autocvar_g_vehicle_bumblebee_healgun_sps * dt, trace_ent.tur_head.max_health);
-
-                                                       if(autocvar_g_vehicle_bumblebee_healgun_hps)
-                                                               trace_ent.vehicle_health = min(trace_ent.vehicle_health + autocvar_g_vehicle_bumblebee_healgun_hps * dt, trace_ent.max_health);
                                                }
                                                else if(IS_CLIENT(trace_ent))
                                                {
-                                                       if(GetResourceAmount(trace_ent, RESOURCE_HEALTH) <= autocvar_g_vehicle_bumblebee_healgun_hmax && autocvar_g_vehicle_bumblebee_healgun_hps)
-                                                               GiveResourceWithLimit(trace_ent, RESOURCE_HEALTH, autocvar_g_vehicle_bumblebee_healgun_hps * dt, autocvar_g_vehicle_bumblebee_healgun_hmax);
-
                                                        if(GetResourceAmount(trace_ent, RESOURCE_ARMOR) <= autocvar_g_vehicle_bumblebee_healgun_amax && autocvar_g_vehicle_bumblebee_healgun_aps)
                                                                GiveResourceWithLimit(trace_ent, RESOURCE_ARMOR, autocvar_g_vehicle_bumblebee_healgun_aps * dt, autocvar_g_vehicle_bumblebee_healgun_amax);
-
-                                                       GiveResourceWithLimit(trace_ent, RESOURCE_HEALTH, autocvar_g_vehicle_bumblebee_healgun_hps * dt, autocvar_g_vehicle_bumblebee_healgun_hmax);
-                                               }
-                                               else if(IS_TURRET(trace_ent))
-                                               {
-                                                       if(GetResourceAmount(trace_ent, RESOURCE_HEALTH) <= trace_ent.max_health && autocvar_g_vehicle_bumblebee_healgun_hps)
-                                                               GiveResourceWithLimit(trace_ent, RESOURCE_HEALTH, autocvar_g_vehicle_bumblebee_healgun_hps * dt, trace_ent.max_health);
-                                                       //else ..hmmm what? ammo?
-
-                                                       trace_ent.SendFlags |= TNSF_STATUS;
                                                }
                                        }
+                               }
                        }
                }
 
index d6604623d2615ae31467d9592e0d7037c8557c6e..fc4b92a55b82b1427b00efa1c9137b5dc0c786de 100644 (file)
@@ -410,7 +410,7 @@ void W_Arc_Beam_Think(entity this)
                beam_endpos = WarpZone_TransformOrigin(WarpZone_trace_transform, beam_endpos);
                new_dir = WarpZone_TransformVelocity(WarpZone_trace_transform, new_dir);
 
-               float is_player = (
+               bool is_player = (
                        IS_PLAYER(trace_ent)
                        ||
                        trace_ent.classname == "body"
@@ -418,129 +418,42 @@ void W_Arc_Beam_Think(entity this)
                        IS_MONSTER(trace_ent)
                );
 
-               // TODO: takedamage flag for things that can be healed?
-               if(trace_ent && (trace_ent.takedamage || trace_ent.classname == "onslaught_generator" || trace_ent.classname == "onslaught_controlpoint_icon") && (is_player || WEP_CVAR(arc, beam_nonplayerdamage)))
+               if(trace_ent)
                {
-                       // calculate our own hit origin as trace_endpos tends to jump around annoyingly (to player origin?)
-                       // NO. trace_endpos should be just fine. If not,
-                       // that's an engine bug that needs proper debugging.
-                       vector hitorigin = trace_endpos;
-
-                       float falloff = ExponentialFalloff(
-                               WEP_CVAR(arc, beam_falloff_mindist),
-                               WEP_CVAR(arc, beam_falloff_maxdist),
-                               WEP_CVAR(arc, beam_falloff_halflifedist),
-                               vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, hitorigin) - w_shotorg)
-                       );
-
-                       // TODO: api or event for things that can be healed
-                       if(IS_VEHICLE(trace_ent) && SAME_TEAM(own, trace_ent))
+                       if(SAME_TEAM(own, trace_ent))
                        {
                                float roothealth = ((burst) ? WEP_CVAR(arc, burst_healing_hps) : WEP_CVAR(arc, beam_healing_hps));
-                               // not handling shield, since it's not exactly a defensive stat
-
-                               if(trace_ent.vehicle_health <= trace_ent.max_health && roothealth)
+                               float rootarmor = ((burst) ? WEP_CVAR(arc, burst_healing_aps) : WEP_CVAR(arc, beam_healing_aps));
+                               float hplimit = ((IS_PLAYER(trace_ent)) ? WEP_CVAR(arc, beam_healing_hmax) : -1);
+                               Heal(trace_ent, own, (roothealth * coefficient), hplimit);
+                               if(IS_PLAYER(trace_ent) && rootarmor)
                                {
-                                       trace_ent.vehicle_health = min(
-                                                       trace_ent.vehicle_health + (roothealth * coefficient),
-                                                       trace_ent.max_health
-                                               );
-                                       if(trace_ent.owner)
-                                               trace_ent.owner.vehicle_health = (trace_ent.vehicle_health / trace_ent.max_health) * 100;
-                                       new_beam_type = ARC_BT_HEAL;
-                               }
-                       }
-                       else if(trace_ent.classname == "onslaught_generator" && SAME_TEAM(own, trace_ent))
-                       {
-                               float roothealth = ((burst) ? WEP_CVAR(arc, burst_healing_hps) : WEP_CVAR(arc, beam_healing_hps));
-                               if(roothealth)
-                               {
-                                       if(GetResourceAmount(trace_ent, RESOURCE_HEALTH) <= trace_ent.max_health)
+                                       if(GetResourceAmount(trace_ent, RESOURCE_ARMOR) <= WEP_CVAR(arc, beam_healing_amax))
                                        {
-                                               GiveResourceWithLimit(trace_ent, RESOURCE_HEALTH, (roothealth * coefficient), trace_ent.max_health);
-                                               WaypointSprite_UpdateHealth(trace_ent.sprite, GetResourceAmount(trace_ent, RESOURCE_HEALTH));
-                                               trace_ent.frame = 10 * bound(0, (1 - GetResourceAmount(trace_ent, RESOURCE_HEALTH) / trace_ent.max_health), 1);
-                                               trace_ent.lasthealth = GetResourceAmount(trace_ent, RESOURCE_HEALTH);
-                                               trace_ent.SendFlags |= GSF_STATUS;
-                                       }
-                                       new_beam_type = ARC_BT_HEAL;
-                               }
-                       }
-                       else if(trace_ent.classname == "onslaught_controlpoint_icon" && SAME_TEAM(own, trace_ent))
-                       {
-                               float roothealth = ((burst) ? WEP_CVAR(arc, burst_healing_hps) : WEP_CVAR(arc, beam_healing_hps));
-                               if(roothealth)
-                               {
-                                       if(GetResourceAmount(trace_ent, RESOURCE_HEALTH) <= trace_ent.max_health)
-                                       {
-                                               GiveResourceWithLimit(trace_ent, RESOURCE_HEALTH, (roothealth * coefficient), trace_ent.max_health);
-                                               if(trace_ent.owner.iscaptured)
-                                                       WaypointSprite_UpdateHealth(trace_ent.owner.sprite, GetResourceAmount(trace_ent, RESOURCE_HEALTH));
-                                               else
-                                                       WaypointSprite_UpdateBuildFinished(trace_ent.owner.sprite, time + (trace_ent.max_health - GetResourceAmount(trace_ent, RESOURCE_HEALTH)) / (trace_ent.count / ONS_CP_THINKRATE));
-                                       }
-                                       new_beam_type = ARC_BT_HEAL;
-                               }
-                       }
-                       else if(trace_ent.classname == "func_assault_destructible" && SAME_TEAM(own, trace_ent))
-                       {
-                               float roothealth = ((burst) ? WEP_CVAR(arc, burst_healing_hps) : WEP_CVAR(arc, beam_healing_hps));
-
-                               if(roothealth)
-                               {
-                                       if(GetResourceAmount(trace_ent, RESOURCE_HEALTH) <= trace_ent.max_health)
-                                       {
-                                               GiveResourceWithLimit(trace_ent, RESOURCE_HEALTH, (roothealth * coefficient), trace_ent.max_health);
-                                               if(trace_ent.sprite)
-                                               {
-                                                       WaypointSprite_UpdateHealth(trace_ent.sprite, GetResourceAmount(trace_ent, RESOURCE_HEALTH));
-                                               }
-                                               func_breakable_colormod(trace_ent);
+                                               GiveResourceWithLimit(trace_ent, RESOURCE_ARMOR, (rootarmor * coefficient), WEP_CVAR(arc, beam_healing_amax));
+                                               trace_ent.pauserotarmor_finished = max(
+                                                       trace_ent.pauserotarmor_finished,
+                                                       time + autocvar_g_balance_pause_armor_rot
+                                               );
                                        }
-                                       new_beam_type = ARC_BT_HEAL;
-                               }
-                       }
-                       else if(is_player && SAME_TEAM(own, trace_ent))
-                       {
-                               float roothealth, rootarmor;
-                               float maxhp;
-                               if(burst)
-                               {
-                                       roothealth = WEP_CVAR(arc, burst_healing_hps);
-                                       rootarmor = WEP_CVAR(arc, burst_healing_aps);
-                               }
-                               else
-                               {
-                                       roothealth = WEP_CVAR(arc, beam_healing_hps);
-                                       rootarmor = WEP_CVAR(arc, beam_healing_aps);
-                               }
-                               maxhp = ((IS_MONSTER(trace_ent)) ? trace_ent.max_health : WEP_CVAR(arc, beam_healing_hmax));
-
-                               if(GetResourceAmount(trace_ent, RESOURCE_HEALTH) <= maxhp && roothealth)
-                               {
-                                       GiveResourceWithLimit(trace_ent, RESOURCE_HEALTH, (roothealth * coefficient), maxhp);
-                               }
-                               if(GetResourceAmount(trace_ent, RESOURCE_ARMOR) <= WEP_CVAR(arc, beam_healing_amax) && rootarmor && !IS_MONSTER(trace_ent))
-                               {
-                                       GiveResourceWithLimit(trace_ent, RESOURCE_ARMOR, (rootarmor * coefficient), WEP_CVAR(arc, beam_healing_amax));
                                }
-
-                               // stop rot, set visual effect
                                if(roothealth || rootarmor)
-                               {
-                                       trace_ent.pauserothealth_finished = max(
-                                               trace_ent.pauserothealth_finished,
-                                               time + autocvar_g_balance_pause_health_rot
-                                       );
-                                       trace_ent.pauserotarmor_finished = max(
-                                               trace_ent.pauserotarmor_finished,
-                                               time + autocvar_g_balance_pause_armor_rot
-                                       );
                                        new_beam_type = ARC_BT_HEAL;
-                               }
                        }
-                       else
+                       else if(trace_ent.takedamage && (is_player || WEP_CVAR(arc, beam_nonplayerdamage)))
                        {
+                               // calculate our own hit origin as trace_endpos tends to jump around annoyingly (to player origin?)
+                               // NO. trace_endpos should be just fine. If not,
+                               // that's an engine bug that needs proper debugging.
+                               vector hitorigin = trace_endpos;
+
+                               float falloff = ExponentialFalloff(
+                                       WEP_CVAR(arc, beam_falloff_mindist),
+                                       WEP_CVAR(arc, beam_falloff_maxdist),
+                                       WEP_CVAR(arc, beam_falloff_halflifedist),
+                                       vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, hitorigin) - w_shotorg)
+                               );
+
                                float rootdamage;
                                if(is_player)
                                {
index 0c740545c08d3593af6c5fe8f098125bf0544f2d..42d72edf415e00183eb1236bef310a6361f8461b 100644 (file)
@@ -380,6 +380,7 @@ void PutObserverInServer(entity this)
        this.oldvelocity = this.velocity;
        this.fire_endtime = -1;
        this.event_damage = func_null;
+       this.event_heal = func_null;
 
        for(int slot = 0; slot < MAX_AXH; ++slot)
        {
@@ -674,6 +675,7 @@ void PutPlayerInServer(entity this)
        STAT(HUD, this) = HUD_NORMAL;
 
        this.event_damage = PlayerDamage;
+       this.event_heal = PlayerHeal;
 
        if(!this.bot_attack)
                IL_PUSH(g_bot_targets, this);
index 1db5dd0c5b637244ef97e3a68271975bd393b8d0..4c23aaeb3b956f6706b8dcea57db48f1c4231f01 100644 (file)
@@ -36,6 +36,8 @@ float server_is_dedicated;
 
 .void(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force) event_damage;
 
+.bool(entity targ, entity inflictor, float amount, float limit) event_heal;
+
 //.string      wad;
 //.string      map;
 
index 2efe1475a69aa9cef99b6a7fe37e98cdca5173f9..cc0c71be5d56e32a1ad721a1e8fe1a9726645a43 100644 (file)
@@ -1061,6 +1061,20 @@ float RadiusDamage (entity inflictor, entity attacker, float coredamage, float e
        return RadiusDamageForSource (inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, cantbe, mustbe, false, forceintensity, deathtype, weaponentity, directhitentity);
 }
 
+bool Heal(entity targ, entity inflictor, float amount, float limit)
+{
+       if(game_stopped || (IS_CLIENT(targ) && CS(targ).killcount == FRAGS_SPECTATOR) || STAT(FROZEN, targ) || IS_DEAD(targ))
+               return false;
+
+       bool healed = false;
+       if(targ.event_heal)
+               healed = targ.event_heal(targ, inflictor, amount, limit);
+       // TODO: additional handling? what if the healing kills them? should this abort if healing would do so etc
+       // TODO: healing fx!
+       // TODO: armor healing?
+       return healed;
+}
+
 float Fire_IsBurning(entity e)
 {
        return (time < e.fire_endtime);
index 9ab817853b0754a5ead77fccd73ff8cd16624eb0..e752f1057e15340c8f62d4a4eeeae01d3d241c0c 100644 (file)
@@ -96,6 +96,10 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in
 
 float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity);
 
+// Calls .event_heal on the target so that they can handle healing themselves
+// a limit of -1 should be handled by the entity as its max health (if applicable)
+bool Heal(entity targ, entity inflictor, float amount, float limit);
+
 .float fire_damagepersec;
 .float fire_endtime;
 .float fire_deathtype;
index 4e39cf6b779297478ec2d3ed55170e2e13cfc90c..cc58cdc6d7ca7e2bc493b9c2bd1518a3aaa3bbe2 100644 (file)
@@ -74,6 +74,7 @@ void CopyBody(entity this, float keepvelocity)
        clone.effects = this.effects;
        clone.glowmod = this.glowmod;
        clone.event_damage = this.event_damage;
+       clone.event_heal = this.event_heal;
        clone.anim_state = this.anim_state;
        clone.anim_time = this.anim_time;
        clone.anim_lower_action = this.anim_lower_action;
@@ -629,6 +630,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
 
                // set damage function to corpse damage
                this.event_damage = PlayerCorpseDamage;
+               this.event_heal = func_null;
                // call the corpse damage function just in case it wants to gib
                this.event_damage(this, inflictor, attacker, excess, deathtype, weaponentity, hitloc, force);
 
@@ -664,6 +666,15 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
        }
 }
 
+bool PlayerHeal(entity targ, entity inflictor, float amount, float limit)
+{
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, limit);
+       return true;
+}
+
 bool MoveToTeam(entity client, int team_colour, int type)
 {
        int lockteams_backup = lockteams;  // backup any team lock
index 5e6642e0471a78220a1af579a705e7b50d74b76b..8c9bac9b62aaa8e94ea4a594e33f6b680f67d74c 100644 (file)
@@ -39,4 +39,6 @@ bool MoveToTeam(entity client, float team_colour, float type);
 
 void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force);
 
+bool PlayerHeal(entity targ, entity inflictor, float amount, float limit);
+
 int Say(entity source, float teamsay, entity privatesay, string msgin, float floodcontrol);