X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fmutators%2Fmutator%2Fbuffs%2Fbuffs.qc;h=15b725ee4b18d2bcd934728a6e0b2c2c8b233496;hb=42e255d014f2c6a1871177ea511f630624cdfb57;hp=08f1aa3b504f60b93beb10ff6a6c28a25cd1b29e;hpb=7f64f637f43db3555fbe00e2424c68474de7bcc0;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/mutators/mutator/buffs/buffs.qc b/qcsrc/common/mutators/mutator/buffs/buffs.qc index 08f1aa3b5..15b725ee4 100644 --- a/qcsrc/common/mutators/mutator/buffs/buffs.qc +++ b/qcsrc/common/mutators/mutator/buffs/buffs.qc @@ -19,6 +19,9 @@ float autocvar_g_buffs_medic_survive_health; float autocvar_g_buffs_medic_rot; float autocvar_g_buffs_medic_max; float autocvar_g_buffs_medic_regen; +float autocvar_g_buffs_medic_heal_amount = 15; +float autocvar_g_buffs_medic_heal_delay = 1; +float autocvar_g_buffs_medic_heal_range = 400; float autocvar_g_buffs_vengeance_damage_multiplier; float autocvar_g_buffs_bash_force; float autocvar_g_buffs_bash_force_self; @@ -33,7 +36,6 @@ float autocvar_g_buffs_speed_damage_take; float autocvar_g_buffs_speed_regen; float autocvar_g_buffs_vampire_damage_steal; float autocvar_g_buffs_invisible_alpha; -float autocvar_g_buffs_flight_gravity; float autocvar_g_buffs_jump_height; float autocvar_g_buffs_inferno_burntime_factor; float autocvar_g_buffs_inferno_burntime_min_time; @@ -42,14 +44,17 @@ float autocvar_g_buffs_inferno_burntime_target_time; float autocvar_g_buffs_inferno_damagemultiplier; float autocvar_g_buffs_swapper_range; float autocvar_g_buffs_magnet_range_item; +float autocvar_g_buffs_magnet_range_buff = 200; +float autocvar_g_buffs_luck_chance = 0.15; +float autocvar_g_buffs_luck_damagemultiplier = 3; // ammo .float buff_ammo_prev_infitems; .int buff_ammo_prev_clipload; // invisible .float buff_invisible_prev_alpha; -// flight -.float buff_flight_prev_gravity; +// medic +.float buff_medic_healtime; // disability .float buff_disability_time; .float buff_disability_effect_time; @@ -73,32 +78,20 @@ const vector BUFF_MAX = ('16 16 20'); #ifdef IMPLEMENTATION -#include "../../../triggers/target/music.qh" -#include "../../../gamemodes/all.qh" +#include +#include -.float buff_time; -void buffs_DelayedInit(); +.float buff_time = _STAT(BUFF_TIME); +void buffs_DelayedInit(entity this); REGISTER_MUTATOR(buffs, cvar("g_buffs")) { MUTATOR_ONADD { - addstat(STAT_BUFFS, AS_INT, buffs); - addstat(STAT_BUFF_TIME, AS_FLOAT, buff_time); - InitializeEntity(world, buffs_DelayedInit, INITPRIO_FINDTARGET); } } -entity buff_FirstFromFlags(int _buffs) -{ - if (flags) - { - FOREACH(Buffs, it.m_itemid & _buffs, LAMBDA(return it)); - } - return BUFF_Null; -} - bool buffs_BuffModel_Customize() {SELFPARAM(); entity player, myowner; @@ -194,37 +187,39 @@ void buff_SetCooldown(float cd) self.buff_active = !cd; } -void buff_Respawn(entity ent) -{SELFPARAM(); +void buff_Respawn(entity this) +{ if(gameover) { return; } - vector oldbufforigin = ent.origin; + vector oldbufforigin = this.origin; + this.velocity = '0 0 200'; - if(!MoveToRandomMapLocation(ent, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, ((autocvar_g_buffs_random_location_attempts > 0) ? autocvar_g_buffs_random_location_attempts : 10), 1024, 256)) + if(!MoveToRandomMapLocation(this, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, + ((autocvar_g_buffs_random_location_attempts > 0) ? autocvar_g_buffs_random_location_attempts : 10), 1024, 256)) { entity spot = SelectSpawnPoint(true); - setorigin(ent, spot.origin + '0 0 200'); - ent.angles = spot.angles; + setorigin(this, spot.origin); + this.velocity = ((randomvec() * 100) + '0 0 200'); + this.angles = spot.angles; } - tracebox(ent.origin, ent.mins * 1.5, self.maxs * 1.5, ent.origin, MOVE_NOMONSTERS, ent); + tracebox(this.origin, this.mins * 1.5, this.maxs * 1.5, this.origin, MOVE_NOMONSTERS, this); - setorigin(ent, trace_endpos); // attempt to unstick + setorigin(this, trace_endpos); // attempt to unstick - ent.movetype = MOVETYPE_TOSS; + this.movetype = MOVETYPE_TOSS; - makevectors(ent.angles); - ent.velocity = '0 0 200'; - ent.angles = '0 0 0'; + makevectors(this.angles); + this.angles = '0 0 0'; if(autocvar_g_buffs_random_lifetime > 0) - ent.lifetime = time + autocvar_g_buffs_random_lifetime; + this.lifetime = time + autocvar_g_buffs_random_lifetime; - Send_Effect(EFFECT_ELECTRO_COMBO, oldbufforigin + ((ent.mins + ent.maxs) * 0.5), '0 0 0', 1); - Send_Effect(EFFECT_ELECTRO_COMBO, CENTER_OR_VIEWOFS(ent), '0 0 0', 1); + Send_Effect(EFFECT_ELECTRO_COMBO, oldbufforigin + ((this.mins + this.maxs) * 0.5), '0 0 0', 1); + Send_Effect(EFFECT_ELECTRO_COMBO, CENTER_OR_VIEWOFS(this), '0 0 0', 1); - WaypointSprite_Ping(ent.buff_waypoint); + WaypointSprite_Ping(this.buff_waypoint); - sound(ent, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere) + sound(this, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere) } void buff_Touch() @@ -238,7 +233,7 @@ void buff_Touch() } if((self.team && DIFF_TEAM(other, self)) - || (other.frozen) + || (STAT(FROZEN, other)) || (other.vehicle) || (!self.buff_active) ) @@ -335,7 +330,7 @@ void buff_Think() } if(!self.buff_active && !self.buff_activetime) - if(!self.owner || self.owner.frozen || self.owner.deadflag != DEAD_NO || !self.owner.iscreature || !(self.owner.buffs & self.buffs)) + if(!self.owner || STAT(FROZEN, self.owner) || IS_DEAD(self.owner) || !self.owner.iscreature || !(self.owner.buffs & self.buffs)) { buff_SetCooldown(autocvar_g_buffs_cooldown_respawn + frametime); self.owner = world; @@ -381,17 +376,17 @@ void buff_Waypoint_Reset() if(self.buff_activetime) { buff_Waypoint_Spawn(self); } } -void buff_Reset() -{SELFPARAM(); +void buff_Reset(entity this) +{ if(autocvar_g_buffs_randomize) - buff_NewType(self, self.buffs); - self.owner = world; + buff_NewType(this, this.buffs); + this.owner = world; buff_SetCooldown(autocvar_g_buffs_cooldown_activate); buff_Waypoint_Reset(); - self.buff_activetime_updated = false; + this.buff_activetime_updated = false; - if(autocvar_g_buffs_random_location || (self.spawnflags & 64)) - buff_Respawn(self); + if(autocvar_g_buffs_random_location || (this.spawnflags & 64)) + buff_Respawn(this); } float buff_Customize() @@ -491,6 +486,20 @@ void buff_Vengeance_DelayedDamage() return; } +// note: only really useful in teamplay +void buff_Medic_Heal(entity this) +{ + FOREACH_CLIENT(IS_PLAYER(it) && it != this && vdist(it.origin - this.origin, <=, autocvar_g_buffs_medic_heal_range), + { + if(SAME_TEAM(it, this)) + if(it.health < autocvar_g_balance_health_regenstable) + { + Send_Effect(EFFECT_HEALING, it.origin, '0 0 0', 1); + it.health = bound(0, it.health + autocvar_g_buffs_medic_heal_amount, autocvar_g_balance_health_regenstable); + } + }); +} + float buff_Inferno_CalculateTime(float x, float offset_x, float offset_y, float intersect_x, float intersect_y, float base) { return offset_y + (intersect_y - offset_y) * logn(((x - offset_x) * ((base - 1) / intersect_x)) + 1, base); @@ -546,11 +555,10 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_Calculate) if(frag_target.buffs & BUFF_BASH.m_itemid) if(frag_attacker != frag_target) - if(vlen(frag_force)) frag_force = '0 0 0'; if(frag_attacker.buffs & BUFF_BASH.m_itemid) - if(vlen(frag_force)) + if(frag_force) if(frag_attacker == frag_target) frag_force *= autocvar_g_buffs_bash_force_self; else @@ -560,18 +568,23 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_Calculate) if(frag_target != frag_attacker) frag_target.buff_disability_time = time + autocvar_g_buffs_disability_slowtime; - if(frag_attacker.buffs & BUFF_MEDIC.m_itemid) - if(DEATH_WEAPONOF(frag_deathtype) != WEP_ARC) - if(SAME_TEAM(frag_attacker, frag_target)) - if(frag_attacker != frag_target) + if(frag_target.buffs & BUFF_INFERNO.m_itemid) { - frag_target.health = min(g_pickup_healthmega_max, frag_target.health + frag_damage); - frag_damage = 0; + if(frag_deathtype == DEATH_FIRE.m_id) + frag_damage = 0; + if(frag_deathtype == DEATH_LAVA.m_id) + frag_damage *= 0.5; // TODO: cvarize? } + if(frag_attacker.buffs & BUFF_LUCK.m_itemid) + if(frag_attacker != frag_target) + if(autocvar_g_buffs_luck_damagemultiplier > 0) + if(random() <= autocvar_g_buffs_luck_chance) + frag_damage *= autocvar_g_buffs_luck_damagemultiplier; + if(frag_attacker.buffs & BUFF_INFERNO.m_itemid) if(frag_target != frag_attacker) { - float time = buff_Inferno_CalculateTime( + float btime = buff_Inferno_CalculateTime( frag_damage, 0, autocvar_g_buffs_inferno_burntime_min_time, @@ -579,18 +592,17 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_Calculate) autocvar_g_buffs_inferno_burntime_target_time, autocvar_g_buffs_inferno_burntime_factor ); - Fire_AddDamage(frag_target, frag_attacker, (frag_damage * autocvar_g_buffs_inferno_damagemultiplier) * time, time, DEATH_BUFF.m_id); + Fire_AddDamage(frag_target, frag_attacker, (frag_damage * autocvar_g_buffs_inferno_damagemultiplier), btime, DEATH_BUFF.m_id); } // this... is ridiculous (TODO: fix!) if(frag_attacker.buffs & BUFF_VAMPIRE.m_itemid) if(!frag_target.vehicle) - if(DEATH_WEAPONOF(frag_deathtype) != WEP_ARC) if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype)) - if(frag_target.deadflag == DEAD_NO) + if(!IS_DEAD(frag_target)) if(IS_PLAYER(frag_target) || IS_MONSTER(frag_target)) if(frag_attacker != frag_target) - if(!frag_target.frozen) + if(!STAT(FROZEN, frag_target)) if(frag_target.takedamage) if(DIFF_TEAM(frag_attacker, frag_target)) { @@ -658,17 +670,17 @@ MUTATOR_HOOKFUNCTION(buffs, MonsterMove) } MUTATOR_HOOKFUNCTION(buffs, PlayerDies) -{SELFPARAM(); - if(self.buffs) +{ + if(frag_target.buffs) { - int buffid = buff_FirstFromFlags(self.buffs).m_id; - Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, buffid); - self.buffs = 0; + int buffid = buff_FirstFromFlags(frag_target.buffs).m_id; + Send_Notification(NOTIF_ALL_EXCEPT, frag_target, MSG_INFO, INFO_ITEM_BUFF_LOST, frag_target.netname, buffid); + frag_target.buffs = 0; - if(self.buff_model) + if(frag_target.buff_model) { - remove(self.buff_model); - self.buff_model = world; + remove(frag_target.buff_model); + frag_target.buff_model = world; } } return false; @@ -698,15 +710,18 @@ MUTATOR_HOOKFUNCTION(buffs, ForbidThrowCurrentWeapon) { float best_distance = autocvar_g_buffs_swapper_range; entity closest = world; - entity player; - FOR_EACH_PLAYER(player) - if(DIFF_TEAM(self, player)) - if(player.deadflag == DEAD_NO && !player.frozen && !player.vehicle) - if(vlen(self.origin - player.origin) <= best_distance) - { - best_distance = vlen(self.origin - player.origin); - closest = player; - } + FOREACH_CLIENT(IS_PLAYER(it), LAMBDA( + if(!IS_DEAD(it) && !STAT(FROZEN, it) && !it.vehicle) + if(DIFF_TEAM(it, self)) + { + float test = vlen2(self.origin - it.origin); + if(test <= best_distance * best_distance) + { + best_distance = sqrt(test); + closest = it; + } + } + )); if(closest) { @@ -740,7 +755,7 @@ MUTATOR_HOOKFUNCTION(buffs, ForbidThrowCurrentWeapon) // set pusher so self gets the kill if they fall into void closest.pusher = self; closest.pushltime = time + autocvar_g_maxpushtime; - closest.istypefrag = closest.BUTTON_CHAT; + closest.istypefrag = PHYS_INPUT_BUTTON_CHAT(closest); Send_Effect(EFFECT_ELECTRO_COMBO, their_org, '0 0 0', 1); Send_Effect(EFFECT_ELECTRO_COMBO, my_org, '0 0 0', 1); @@ -770,8 +785,8 @@ bool buffs_RemovePlayer(entity player) return false; } -MUTATOR_HOOKFUNCTION(buffs, MakePlayerObserver) { return buffs_RemovePlayer(self); } -MUTATOR_HOOKFUNCTION(buffs, ClientDisconnect) { return buffs_RemovePlayer(self); } +MUTATOR_HOOKFUNCTION(buffs, MakePlayerObserver) { SELFPARAM(); return buffs_RemovePlayer(self); } +MUTATOR_HOOKFUNCTION(buffs, ClientDisconnect) { SELFPARAM(); return buffs_RemovePlayer(self); } MUTATOR_HOOKFUNCTION(buffs, CustomizeWaypoint) {SELFPARAM(); @@ -788,11 +803,6 @@ MUTATOR_HOOKFUNCTION(buffs, CustomizeWaypoint) MUTATOR_HOOKFUNCTION(buffs, OnEntityPreSpawn, CBC_ORDER_LAST) {SELFPARAM(); - if (self.classname == "item_flight" && cvar("g_buffs") && cvar("g_buffs_flight")) - { - buff_Init_Compat(self, BUFF_FLIGHT); - return true; - } if(autocvar_g_buffs_replace_powerups) switch(self.classname) { @@ -831,7 +841,7 @@ MUTATOR_HOOKFUNCTION(buffs, WeaponSpeedFactor) MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink) {SELFPARAM(); - if(gameover || self.deadflag != DEAD_NO) { return false; } + if(gameover || IS_DEAD(self)) { return false; } if(time < self.buff_disability_time) if(time >= self.buff_disability_effect_time) @@ -849,7 +859,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink) if(time >= self.buff_time) buff_lost = 2; - if(self.frozen) { buff_lost = 1; } + if(STAT(FROZEN, self)) { buff_lost = 1; } if(buff_lost) { @@ -868,27 +878,43 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink) if(self.buffs & BUFF_MAGNET.m_itemid) { - vector pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_item; - for(other = world; (other = findflags(other, flags, FL_ITEM)); ) - if(boxesoverlap(self.absmin - pickup_size, self.absmax + pickup_size, other.absmin, other.absmax)) + vector pickup_size; + FOREACH_ENTITY_FLAGS(flags, FL_ITEM, { - setself(other); - other = this; - if(self.touch) - self.touch(); - other = self; - setself(this); - } + if(it.buffs) + pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_buff; + else + pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_item; + + if(boxesoverlap(self.absmin - pickup_size, self.absmax + pickup_size, it.absmin, it.absmax)) + { + if(it.touch) + { + entity oldother = other; + other = self; + WITHSELF(it, it.touch()); + + other = oldother; + } + } + }); } if(self.buffs & BUFF_AMMO.m_itemid) if(self.clip_size) - self.clip_load = self.(weapon_load[self.switchweapon]) = self.clip_size; + self.clip_load = self.(weapon_load[PS(self).m_switchweapon.m_id]) = self.clip_size; if((self.buffs & BUFF_INVISIBLE.m_itemid) && (self.oldbuffs & BUFF_INVISIBLE.m_itemid)) if(self.alpha != autocvar_g_buffs_invisible_alpha) self.alpha = autocvar_g_buffs_invisible_alpha; // powerups reset alpha, so we must enforce this (TODO) + if(self.buffs & BUFF_MEDIC.m_itemid) + if(time >= self.buff_medic_healtime) + { + buff_Medic_Heal(self); + self.buff_medic_healtime = time + autocvar_g_buffs_medic_heal_delay; + } + #define BUFF_ONADD(b) if ( (self.buffs & (b).m_itemid) && !(self.oldbuffs & (b).m_itemid)) #define BUFF_ONREM(b) if (!(self.buffs & (b).m_itemid) && (self.oldbuffs & (b).m_itemid)) @@ -905,7 +931,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink) if(self.clip_load) self.buff_ammo_prev_clipload = self.clip_load; - self.clip_load = self.(weapon_load[self.switchweapon]) = self.clip_size; + self.clip_load = self.(weapon_load[PS(self).m_switchweapon.m_id]) = self.clip_size; } BUFF_ONREM(BUFF_AMMO) @@ -931,15 +957,6 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink) BUFF_ONREM(BUFF_INVISIBLE) self.alpha = self.buff_invisible_prev_alpha; - BUFF_ONADD(BUFF_FLIGHT) - { - self.buff_flight_prev_gravity = self.gravity; - self.gravity = autocvar_g_buffs_flight_gravity; - } - - BUFF_ONREM(BUFF_FLIGHT) - self.gravity = self.buff_flight_prev_gravity; - self.oldbuffs = self.buffs; if(self.buffs) { @@ -985,7 +1002,7 @@ MUTATOR_HOOKFUNCTION(buffs, VehicleEnter) { vh_vehicle.buffs = vh_player.buffs; vh_player.buffs = 0; - vh_vehicle.buff_time = vh_player.buff_time - time; + vh_vehicle.buff_time = max(0, vh_player.buff_time - time); vh_player.buff_time = 0; return false; } @@ -1014,11 +1031,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerRegen) return false; } -MUTATOR_HOOKFUNCTION(buffs, GetCvars) -{ - GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_buffs_autoreplace, "cl_buffs_autoreplace"); - return false; -} +REPLICATE(cvar_cl_buffs_autoreplace, bool, "cl_buffs_autoreplace"); MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsString) { @@ -1032,7 +1045,7 @@ MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsPrettyString) return false; } -void buffs_DelayedInit() +void buffs_DelayedInit(entity this) { if(autocvar_g_buffs_spawn_count > 0) if(find(world, classname, "item_buff") == world)