X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fmutators%2Fmutator_buffs.qc;h=6fda5d39f1dfa484d9b60f6d1f3cd077138c4049;hp=c71fe60ea9bf3076107fa829438df4957af09db6;hb=ec0035789475e48a58a22df279c7cb1099454afd;hpb=71775fe6ad624b08f0aad2b7116c48f35198478c diff --git a/qcsrc/server/mutators/mutator_buffs.qc b/qcsrc/server/mutators/mutator_buffs.qc index c71fe60ea9..6fda5d39f1 100644 --- a/qcsrc/server/mutators/mutator_buffs.qc +++ b/qcsrc/server/mutators/mutator_buffs.qc @@ -8,7 +8,7 @@ float buffs_BuffModel_Customize() same_team = (SAME_TEAM(player, myowner) || SAME_TEAM(player, myowner)); if(myowner.alpha <= 0.5 && !same_team && myowner.alpha != 0) - return FALSE; + return false; if(player == myowner || (IS_SPEC(other) && other.enemy == myowner)) { @@ -21,24 +21,55 @@ float buffs_BuffModel_Customize() self.effects = EF_FULLBRIGHT | EF_LOWPRECISION; self.alpha = 1; } - return TRUE; + return true; +} + +void buffs_BuffModel_Spawn(entity player) +{ + player.buff_model = spawn(); + setmodel(player.buff_model, BUFF_MODEL); + setsize(player.buff_model, '0 0 -40', '0 0 40'); + setattachment(player.buff_model, player, ""); + setorigin(player.buff_model, '0 0 1' * (player.buff_model.maxs.z * 1)); + player.buff_model.owner = player; + player.buff_model.scale = 0.7; + player.buff_model.pflags = PFLAGS_FULLDYNAMIC; + player.buff_model.light_lev = 200; + player.buff_model.customizeentityforclient = buffs_BuffModel_Customize; +} + +vector buff_GlowColor(entity buff) +{ + //if(buff.team) { return Team_ColorRGB(buff.team); } + return buff.color; +} + +void buff_Effect(entity player, string eff) +{ + if(!autocvar_g_buffs_effects) { return; } + + if(time >= self.buff_effect_delay) + { + pointparticles(particleeffectnum(eff), player.origin + ((player.mins + player.maxs) * 0.5), '0 0 0', 1); + self.buff_effect_delay = time + 0.05; // prevent spam + } } // buff item float buff_Waypoint_visible_for_player(entity plr) { if(!self.owner.buff_active && !self.owner.buff_activetime) - return FALSE; + return false; if(plr.buffs) { if(plr.cvar_cl_buffs_autoreplace) { if(plr.buffs == self.owner.buffs) - return FALSE; + return false; } else - return FALSE; + return false; } return WaypointSprite_visible_for_player(plr); @@ -46,7 +77,7 @@ float buff_Waypoint_visible_for_player(entity plr) void buff_Waypoint_Spawn(entity e) { - WaypointSprite_Spawn(Buff_Sprite(e.buffs), 0, autocvar_g_buffs_waypoint_distance, e, '0 0 1' * e.maxs_z, world, e.team, e, buff_waypoint, TRUE, RADARICON_POWERUP, e.glowmod); + WaypointSprite_Spawn(Buff_Sprite(e.buffs), 0, autocvar_g_buffs_waypoint_distance, e, '0 0 1' * e.maxs.z, world, e.team, e, buff_waypoint, true, RADARICON_POWERUP, e.glowmod); WaypointSprite_UpdateTeamRadar(e.buff_waypoint, RADARICON_POWERUP, e.glowmod); e.buff_waypoint.waypointsprite_visible_for_player = buff_Waypoint_visible_for_player; } @@ -66,22 +97,22 @@ void buff_SetCooldown(float cd) void buff_Respawn(entity ent) { if(gameover) { return; } - + vector oldbufforigin = ent.origin; - + 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)) { - entity spot = SelectSpawnPoint(TRUE); + entity spot = SelectSpawnPoint(true); setorigin(ent, ((spot.origin + '0 0 200') + (randomvec() * 300))); ent.angles = spot.angles; } - + tracebox(ent.origin, ent.mins * 1.5, self.maxs * 1.5, ent.origin, MOVE_NOMONSTERS, ent); - + setorigin(ent, trace_endpos); // attempt to unstick - + ent.movetype = MOVETYPE_TOSS; - + makevectors(ent.angles); ent.velocity = '0 0 200'; ent.angles = '0 0 0'; @@ -90,9 +121,9 @@ void buff_Respawn(entity ent) pointparticles(particleeffectnum("electro_combo"), oldbufforigin + ((ent.mins + ent.maxs) * 0.5), '0 0 0', 1); pointparticles(particleeffectnum("electro_combo"), CENTER_OR_VIEWOFS(ent), '0 0 0', 1); - + WaypointSprite_Ping(ent.buff_waypoint); - + sound(ent, CH_TRIGGER, "keepaway/respawn.wav", VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere) } @@ -107,7 +138,7 @@ void buff_Touch() } if((self.team && DIFF_TEAM(other, self)) - || (other.freezetag_frozen) + || (other.frozen) || (other.vehicle) || (!IS_PLAYER(other)) || (!self.buff_active) @@ -129,11 +160,11 @@ void buff_Touch() } else { return; } // do nothing } - + self.owner = other; - self.buff_active = FALSE; + self.buff_active = false; self.lifetime = 0; - + Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_BUFF_GOT, self.buffs); Send_Notification(NOTIF_ALL_EXCEPT, other, MSG_INFO, INFO_ITEM_BUFF, other.netname, self.buffs); @@ -145,15 +176,15 @@ void buff_Touch() float buff_Available(float buffid) { if(buffid == BUFF_AMMO && ((start_items & IT_UNLIMITED_WEAPON_AMMO) || (start_items & IT_UNLIMITED_AMMO) || (cvar("g_melee_only")))) - return FALSE; + return false; if(buffid == BUFF_VAMPIRE && cvar("g_vampire")) - return FALSE; + return false; if(!cvar(strcat("g_buffs_", Buff_Name(buffid)))) - return FALSE; + return false; - return TRUE; + return true; } void buff_NewType(entity ent, float cb) @@ -174,10 +205,10 @@ void buff_Think() if(self.buffs != self.oldbuffs) { self.color = Buff_Color(self.buffs); - self.glowmod = ((self.team) ? Team_ColorRGB(self.team) + '0.1 0.1 0.1' : self.color); + self.glowmod = buff_GlowColor(self); self.skin = Buff_Skin(self.buffs); - - setmodel(self, "models/relics/relic.md3"); + + setmodel(self, BUFF_MODEL); if(self.buff_waypoint) { @@ -196,21 +227,21 @@ void buff_Think() if(!self.buff_activetime_updated) { buff_SetCooldown(self.buff_activetime); - self.buff_activetime_updated = TRUE; + self.buff_activetime_updated = true; } if(!self.buff_active && !self.buff_activetime) - if(!self.owner || self.owner.freezetag_frozen || self.owner.deadflag != DEAD_NO || !self.owner.iscreature || !(self.owner.buffs & self.buffs)) + if(!self.owner || self.owner.frozen || self.owner.deadflag != DEAD_NO || !self.owner.iscreature || !(self.owner.buffs & self.buffs)) { buff_SetCooldown(autocvar_g_buffs_cooldown_respawn + frametime); self.owner = world; if(autocvar_g_buffs_randomize) buff_NewType(self, self.buffs); - + if(autocvar_g_buffs_random_location || (self.spawnflags & 1)) buff_Respawn(self); } - + if(self.buff_activetime) if(!gameover) if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime) @@ -219,33 +250,22 @@ void buff_Think() if(!self.buff_activetime) { - self.buff_active = TRUE; + self.buff_active = true; sound(self, CH_TRIGGER, "misc/strength_respawn.wav", VOL_BASE, ATTN_NORM); pointparticles(particleeffectnum("item_respawn"), CENTER_OR_VIEWOFS(self), '0 0 0', 1); } } - if(!self.buff_active) + if(self.buff_active) { - self.alpha = 0.3; - self.effects &= ~(EF_FULLBRIGHT); - self.pflags = 0; - } - else - { - self.alpha = 1; - self.effects |= EF_FULLBRIGHT; - self.light_lev = 220 + 36 * sin(time); - self.pflags = PFLAGS_FULLDYNAMIC; - if(self.team && !self.buff_waypoint) buff_Waypoint_Spawn(self); - + if(self.lifetime) if(time >= self.lifetime) buff_Respawn(self); } - + self.nextthink = time; //self.angles_y = time * 110.1; } @@ -264,23 +284,42 @@ void buff_Reset() self.owner = world; buff_SetCooldown(autocvar_g_buffs_cooldown_activate); buff_Waypoint_Reset(); - self.buff_activetime_updated = FALSE; - + self.buff_activetime_updated = false; + if(autocvar_g_buffs_random_location || (self.spawnflags & 1)) buff_Respawn(self); } +float buff_Customize() +{ + entity player = WaypointSprite_getviewentity(other); + if(!self.buff_active || (self.team && DIFF_TEAM(player, self))) + { + self.alpha = 0.3; + if(self.effects & EF_FULLBRIGHT) { self.effects &= ~(EF_FULLBRIGHT); } + self.pflags = 0; + } + else + { + self.alpha = 1; + if(!(self.effects & EF_FULLBRIGHT)) { self.effects |= EF_FULLBRIGHT; } + self.light_lev = 220 + 36 * sin(time); + self.pflags = PFLAGS_FULLDYNAMIC; + } + return true; +} + void buff_Init(entity ent) { if(!cvar("g_buffs")) { remove(self); return; } - + if(!teamplay && self.team) { self.team = 0; } entity oldself = self; self = ent; if(!self.buffs || buff_Available(self.buffs)) buff_NewType(self, 0); - + self.classname = "item_buff"; self.solid = SOLID_TRIGGER; self.flags = FL_ITEM; @@ -294,22 +333,23 @@ void buff_Init(entity ent) self.skin = Buff_Skin(self.buffs); self.effects = EF_FULLBRIGHT | EF_STARDUST | EF_NOSHADOW; self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY; + self.customizeentityforclient = buff_Customize; //self.gravity = 100; self.color = Buff_Color(self.buffs); - self.glowmod = ((self.team) ? Team_ColorRGB(self.team) + '0.1 0.1 0.1' : self.color); + self.glowmod = buff_GlowColor(self); buff_SetCooldown(autocvar_g_buffs_cooldown_activate + game_starttime); self.buff_active = !self.buff_activetime; self.pflags = PFLAGS_FULLDYNAMIC; - + if(self.noalign) self.movetype = MOVETYPE_NONE; // reset by random location - setmodel(self, "models/relics/relic.md3"); + setmodel(self, BUFF_MODEL); setsize(self, BUFF_MIN, BUFF_MAX); - + if(cvar("g_buffs_random_location") || (self.spawnflags & 1)) buff_Respawn(self); - + self = oldself; } @@ -330,37 +370,42 @@ void buff_SpawnReplacement(entity ent, entity old) setorigin(ent, old.origin); ent.angles = old.angles; ent.noalign = old.noalign; - + buff_Init(ent); } +void buff_Vengeance_DelayedDamage() +{ + if(self.enemy) + Damage(self.enemy, self.owner, self.owner, self.dmg, DEATH_BUFF, self.enemy.origin, '0 0 0'); + + remove(self); + return; +} + +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); +} + // mutator hooks MUTATOR_HOOKFUNCTION(buffs_PlayerDamage_SplitHealthArmor) { - if(frag_deathtype == DEATH_BUFF_VENGEANCE) { return FALSE; } // oh no you don't + if(frag_deathtype == DEATH_BUFF) { return false; } if(frag_target.buffs & BUFF_RESISTANCE) { vector v = healtharmor_applydamage(50, autocvar_g_buffs_resistance_blockpercent, frag_deathtype, frag_damage); - damage_take = v_x; - damage_save = v_y; + damage_take = v.x; + damage_save = v.y; } - return FALSE; -} - -void buff_Vengeance_DelayedDamage() -{ - if(self.enemy) - Damage(self.enemy, self.owner, self.owner, self.dmg, DEATH_BUFF_VENGEANCE, self.enemy.origin, '0 0 0'); - - remove(self); - return; + return false; } MUTATOR_HOOKFUNCTION(buffs_PlayerDamage_Calculate) { - if(frag_deathtype == DEATH_BUFF_VENGEANCE) { return FALSE; } // oh no you don't + if(frag_deathtype == DEATH_BUFF) { return false; } if(frag_target.buffs & BUFF_SPEED) if(frag_target != frag_attacker) @@ -371,9 +416,8 @@ MUTATOR_HOOKFUNCTION(buffs_PlayerDamage_Calculate) if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype)) if(frag_attacker) if(random() <= autocvar_g_buffs_medic_survive_chance) - if(frag_target.health - autocvar_g_buffs_medic_survive_health > 0) // not if the final result would be less than 0, medic must get health - frag_damage = frag_target.health - autocvar_g_buffs_medic_survive_health; - + frag_damage = max(5, frag_target.health - autocvar_g_buffs_medic_survive_health); + if(frag_target.buffs & BUFF_VENGEANCE) if(frag_attacker) if(frag_attacker != frag_target) @@ -392,19 +436,20 @@ MUTATOR_HOOKFUNCTION(buffs_PlayerDamage_Calculate) if(frag_attacker != frag_target) if(vlen(frag_force)) frag_force = '0 0 0'; - + if(frag_attacker.buffs & BUFF_BASH) if(vlen(frag_force)) if(frag_attacker == frag_target) frag_force *= autocvar_g_buffs_bash_force_self; else frag_force *= autocvar_g_buffs_bash_force; - + if(frag_attacker.buffs & BUFF_DISABILITY) if(frag_target != frag_attacker) - frag_target.buff_disability_time = time + autocvar_g_buffs_disability_time; + frag_target.buff_disability_time = time + autocvar_g_buffs_disability_slowtime; if(frag_attacker.buffs & BUFF_MEDIC) + if(DEATH_WEAPONOF(frag_deathtype) != WEP_ARC) if(SAME_TEAM(frag_attacker, frag_target)) if(frag_attacker != frag_target) { @@ -412,19 +457,33 @@ MUTATOR_HOOKFUNCTION(buffs_PlayerDamage_Calculate) frag_damage = 0; } + if(frag_attacker.buffs & BUFF_INFERNO) + if(frag_target != frag_attacker) { + float time = buff_Inferno_CalculateTime( + frag_damage, + 0, + autocvar_g_buffs_inferno_burntime_min_time, + autocvar_g_buffs_inferno_burntime_target_damage, + 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); + } + // this... is ridiculous (TODO: fix!) if(frag_attacker.buffs & BUFF_VAMPIRE) 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_PLAYER(frag_target) || (frag_target.flags & FL_MONSTER)) if(frag_attacker != frag_target) - if(!frag_target.freezetag_frozen) + if(!frag_target.frozen) if(frag_target.takedamage) if(DIFF_TEAM(frag_attacker, frag_target)) frag_attacker.health = bound(0, frag_attacker.health + bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal, frag_target.health), g_pickup_healthsmall_max); - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_PlayerSpawn) @@ -433,7 +492,7 @@ MUTATOR_HOOKFUNCTION(buffs_PlayerSpawn) // reset timers here to prevent them continuing after re-spawn self.buff_disability_time = 0; self.buff_disability_effect_time = 0; - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_PlayerPhysics) @@ -443,14 +502,14 @@ MUTATOR_HOOKFUNCTION(buffs_PlayerPhysics) self.stat_sv_maxspeed *= autocvar_g_buffs_speed_speed; self.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_speed_speed; } - + if(time < self.buff_disability_time) { self.stat_sv_maxspeed *= autocvar_g_buffs_disability_speed; self.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_disability_speed; } - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_PlayerJump) @@ -459,7 +518,7 @@ MUTATOR_HOOKFUNCTION(buffs_PlayerJump) player_jumpheight = autocvar_g_buffs_jump_height; self.stat_jumpheight = player_jumpheight; - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_MonsterMove) @@ -470,7 +529,7 @@ MUTATOR_HOOKFUNCTION(buffs_MonsterMove) monster_speed_run *= autocvar_g_buffs_disability_speed; } - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_PlayerDies) @@ -479,19 +538,19 @@ MUTATOR_HOOKFUNCTION(buffs_PlayerDies) { Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, self.buffs); self.buffs = 0; - + if(self.buff_model) { remove(self.buff_model); self.buff_model = world; } } - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_PlayerUseKey) { - if(MUTATOR_RETURNVALUE || gameover) { return FALSE; } + if(MUTATOR_RETURNVALUE || gameover) { return false; } if(self.buffs) { Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_BUFF_DROP, self.buffs); @@ -499,9 +558,79 @@ MUTATOR_HOOKFUNCTION(buffs_PlayerUseKey) self.buffs = 0; sound(self, CH_TRIGGER, "relics/relic_effect.wav", VOL_BASE, ATTN_NORM); - return TRUE; + return true; } - return FALSE; + return false; +} + +MUTATOR_HOOKFUNCTION(buffs_PlayerThrowKey) +{ + if(MUTATOR_RETURNVALUE || gameover) { return false; } + + if(self.buffs & BUFF_SWAPPER) + { + 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; + } + + if(closest) + { + vector my_org, my_vel, my_ang, their_org, their_vel, their_ang; + + my_org = self.origin; + my_vel = self.velocity; + my_ang = self.angles; + their_org = closest.origin; + their_vel = closest.velocity; + their_ang = closest.angles; + + if(closest.ballcarried) + if(g_keepaway) { ka_DropEvent(closest); } + else { DropBall(closest.ballcarried, closest.origin, closest.velocity);} + if(closest.flagcarried) { ctf_Handle_Throw(closest, world, DROP_THROW); } + if(closest.nade) { toss_nade(closest, '0 0 0', time + 0.05); } + + MUTATOR_CALLHOOK(PortalTeleport); // initiate flag dropper + + setorigin(self, their_org); + setorigin(closest, my_org); + + closest.velocity = my_vel; + closest.angles = my_ang; + closest.fixangle = true; + closest.oldorigin = my_org; + closest.oldvelocity = my_vel; + self.velocity = their_vel; + self.angles = their_ang; + self.fixangle = true; + self.oldorigin = their_org; + self.oldvelocity = their_vel; + + // 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; + + pointparticles(particleeffectnum("electro_combo"), their_org, '0 0 0', 1); + pointparticles(particleeffectnum("electro_combo"), my_org, '0 0 0', 1); + + sound(self, CH_TRIGGER, "keepaway/respawn.wav", VOL_BASE, ATTEN_NORM); + sound(closest, CH_TRIGGER, "keepaway/respawn.wav", VOL_BASE, ATTEN_NORM); + + // TODO: add a counter to handle how many times one can teleport, and a delay to prevent spam + self.buffs = 0; + return true; + } + } + return false; } MUTATOR_HOOKFUNCTION(buffs_RemovePlayer) @@ -511,12 +640,12 @@ MUTATOR_HOOKFUNCTION(buffs_RemovePlayer) remove(self.buff_model); self.buff_model = world; } - + // also reset timers here to prevent them continuing after spectating self.buff_disability_time = 0; self.buff_disability_effect_time = 0; - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_CustomizeWaypoint) @@ -527,9 +656,9 @@ MUTATOR_HOOKFUNCTION(buffs_CustomizeWaypoint) // but only apply this to real players, not to spectators if((self.owner.flags & FL_CLIENT) && (self.owner.buffs & BUFF_INVISIBLE) && (e == other)) if(DIFF_TEAM(self.owner, e)) - return TRUE; + return true; - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_OnEntityPreSpawn) @@ -542,118 +671,136 @@ MUTATOR_HOOKFUNCTION(buffs_OnEntityPreSpawn) { entity e = spawn(); buff_SpawnReplacement(e, self); - return TRUE; + return true; } } - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_WeaponRate) { if(self.buffs & BUFF_SPEED) weapon_rate *= autocvar_g_buffs_speed_rate; - + if(time < self.buff_disability_time) weapon_rate *= autocvar_g_buffs_disability_rate; - - return FALSE; + + return false; +} + +MUTATOR_HOOKFUNCTION(buffs_WeaponSpeed) +{ + if(self.buffs & BUFF_SPEED) + ret_float *= autocvar_g_buffs_speed_weaponspeed; + + if(time < self.buff_disability_time) + ret_float *= autocvar_g_buffs_disability_weaponspeed; + + return false; } MUTATOR_HOOKFUNCTION(buffs_PlayerThink) { - if(gameover || self.deadflag != DEAD_NO) { return FALSE; } - + if(gameover || self.deadflag != DEAD_NO) { return false; } + if(time < self.buff_disability_time) if(time >= self.buff_disability_effect_time) { pointparticles(particleeffectnum("smoking"), self.origin + ((self.mins + self.maxs) * 0.5), '0 0 0', 1); self.buff_disability_effect_time = time + 0.5; } - - if(self.freezetag_frozen) + + // handle buff lost status + // 1: notify everyone else + // 2: notify carrier as well + int buff_lost = 0; + + if(self.buff_time) + if(time >= self.buff_time) + buff_lost = 2; + + if(self.frozen) { buff_lost = 1; } + + if(buff_lost) { if(self.buffs) { Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, self.buffs); + if(buff_lost >= 2) + { + Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_BUFF_DROP, self.buffs); // TODO: special timeout message? + sound(self, CH_TRIGGER, "relics/relic_effect.wav", VOL_BASE, ATTN_NORM); + } self.buffs = 0; } } - + if((self.buffs & BUFF_INVISIBLE) && (self.oldbuffs & BUFF_INVISIBLE)) if(self.alpha != autocvar_g_buffs_invisible_alpha) - self.alpha = autocvar_g_buffs_invisible_alpha; + self.alpha = autocvar_g_buffs_invisible_alpha; // powerups reset alpha, so we must enforce this (TODO) + +#define BUFF_ONADD(b) if((self.buffs & (b)) && !(self.oldbuffs & (b))) +#define BUFF_ONREM(b) if(!(self.buffs & (b)) && (self.oldbuffs & (b))) if(self.buffs != self.oldbuffs) { - if(self.oldbuffs & BUFF_AMMO) - { - if(self.buff_ammo_prev_infitems) - self.items |= IT_UNLIMITED_WEAPON_AMMO; - else - self.items &= ~IT_UNLIMITED_WEAPON_AMMO; - } - else if(self.buffs & BUFF_AMMO) + if(self.buffs && Buff_Timer(self.buffs)) + self.buff_time = time + Buff_Timer(self.buffs); + else + self.buff_time = 0; + + BUFF_ONADD(BUFF_AMMO) { self.buff_ammo_prev_infitems = (self.items & IT_UNLIMITED_WEAPON_AMMO); self.items |= IT_UNLIMITED_WEAPON_AMMO; - if(!self.ammo_shells) { self.ammo_shells = 20; } - if(!self.ammo_cells) { self.ammo_cells = 20; } - if(!self.ammo_rockets) { self.ammo_rockets = 20; } - if(!self.ammo_nails) { self.ammo_nails = 20; } - if(!self.ammo_fuel) { self.ammo_fuel = 20; } } - - if(self.oldbuffs & BUFF_INVISIBLE) + + BUFF_ONREM(BUFF_AMMO) { - if(time < self.strength_finished && g_minstagib) - self.alpha = autocvar_g_minstagib_invis_alpha; + if(self.buff_ammo_prev_infitems) + self.items |= IT_UNLIMITED_WEAPON_AMMO; else - self.alpha = self.buff_invisible_prev_alpha; + self.items &= ~IT_UNLIMITED_WEAPON_AMMO; } - else if(self.buffs & BUFF_INVISIBLE) + + BUFF_ONADD(BUFF_INVISIBLE) { - if(time < self.strength_finished && g_minstagib) - self.buff_invisible_prev_alpha = default_player_alpha; + if(time < self.strength_finished && g_instagib) + self.alpha = autocvar_g_instagib_invis_alpha; else - self.buff_invisible_prev_alpha = self.alpha; + self.alpha = self.buff_invisible_prev_alpha; self.alpha = autocvar_g_buffs_invisible_alpha; } - - if(self.oldbuffs & BUFF_FLIGHT) - self.gravity = self.buff_flight_prev_gravity; - else if(self.buffs & BUFF_FLIGHT) + + 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) { if(!self.buff_model) - { - self.buff_model = spawn(); - setmodel(self.buff_model, "models/relics/relic.md3"); - setsize(self.buff_model, '0 0 -40', '0 0 40'); - setattachment(self.buff_model, self, ""); - setorigin(self.buff_model, '0 0 1' * (self.buff_model.maxs_z * 1)); - self.buff_model.owner = self; - self.buff_model.scale = 0.7; - self.buff_model.pflags = PFLAGS_FULLDYNAMIC; - self.buff_model.light_lev = 200; - self.buff_model.customizeentityforclient = buffs_BuffModel_Customize; - } + buffs_BuffModel_Spawn(self); + self.buff_model.color = Buff_Color(self.buffs); - self.buff_model.glowmod = ((self.buff_model.team) ? Team_ColorRGB(self.buff_model.team) + '0.1 0.1 0.1' : self.buff_model.color); + self.buff_model.glowmod = buff_GlowColor(self.buff_model); self.buff_model.skin = Buff_Skin(self.buffs); - + self.effects |= EF_NOSHADOW; } else { remove(self.buff_model); self.buff_model = world; - + self.effects &= ~(EF_NOSHADOW); } } @@ -663,31 +810,33 @@ MUTATOR_HOOKFUNCTION(buffs_PlayerThink) self.buff_model.effects = self.effects; self.buff_model.effects |= EF_LOWPRECISION; self.buff_model.effects = self.buff_model.effects & EFMASK_CHEAP; // eat performance - + self.buff_model.alpha = self.alpha; } - return FALSE; +#undef BUFF_ONADD +#undef BUFF_ONREM + return false; } MUTATOR_HOOKFUNCTION(buffs_SpectateCopy) { self.buffs = other.buffs; - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_VehicleEnter) { vh_vehicle.buffs = vh_player.buffs; vh_player.buffs = 0; - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_VehicleExit) { vh_player.buffs = vh_vehicle.buffs; vh_vehicle.buffs = 0; - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_PlayerRegen) @@ -698,29 +847,29 @@ MUTATOR_HOOKFUNCTION(buffs_PlayerRegen) regen_mod_limit = regen_mod_max = autocvar_g_buffs_medic_max; regen_mod_regen = autocvar_g_buffs_medic_regen; } - + if(self.buffs & BUFF_SPEED) regen_mod_regen = autocvar_g_buffs_speed_regen; - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_GetCvars) { GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_buffs_autoreplace, "cl_buffs_autoreplace"); - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_BuildMutatorsString) { ret_string = strcat(ret_string, ":Buffs"); - return FALSE; + return false; } MUTATOR_HOOKFUNCTION(buffs_BuildMutatorsPrettyString) { ret_string = strcat(ret_string, ", Buffs"); - return FALSE; + return false; } void buffs_DelayedInit() @@ -741,7 +890,7 @@ void buffs_DelayedInit() void buffs_Initialize() { - precache_model("models/relics/relic.md3"); + precache_model(BUFF_MODEL); precache_sound("misc/strength_respawn.wav"); precache_sound("misc/shield_respawn.wav"); precache_sound("relics/relic_effect.wav"); @@ -749,8 +898,9 @@ void buffs_Initialize() precache_sound("keepaway/respawn.wav"); addstat(STAT_BUFFS, AS_INT, buffs); + addstat(STAT_BUFF_TIME, AS_FLOAT, buff_time); addstat(STAT_MOVEVARS_JUMPVELOCITY, AS_FLOAT, stat_jumpheight); - + InitializeEntity(world, buffs_DelayedInit, INITPRIO_FINDTARGET); } @@ -767,12 +917,14 @@ MUTATOR_DEFINITION(mutator_buffs) MUTATOR_HOOK(VehicleExit, buffs_VehicleExit, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerRegen, buffs_PlayerRegen, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerDies, buffs_PlayerDies, CBC_ORDER_ANY); - MUTATOR_HOOK(PlayerUseKey, buffs_PlayerUseKey, CBC_ORDER_ANY); + MUTATOR_HOOK(PlayerUseKey, buffs_PlayerUseKey, CBC_ORDER_FIRST); + MUTATOR_HOOK(ForbidThrowCurrentWeapon, buffs_PlayerThrowKey, CBC_ORDER_ANY); MUTATOR_HOOK(MakePlayerObserver, buffs_RemovePlayer, CBC_ORDER_ANY); MUTATOR_HOOK(ClientDisconnect, buffs_RemovePlayer, CBC_ORDER_ANY); MUTATOR_HOOK(OnEntityPreSpawn, buffs_OnEntityPreSpawn, CBC_ORDER_ANY); MUTATOR_HOOK(CustomizeWaypoint, buffs_CustomizeWaypoint, CBC_ORDER_ANY); MUTATOR_HOOK(WeaponRateFactor, buffs_WeaponRate, CBC_ORDER_ANY); + MUTATOR_HOOK(WeaponSpeedFactor, buffs_WeaponSpeed, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerPreThink, buffs_PlayerThink, CBC_ORDER_ANY); MUTATOR_HOOK(GetCvars, buffs_GetCvars, CBC_ORDER_ANY); MUTATOR_HOOK(BuildMutatorsString, buffs_BuildMutatorsString, CBC_ORDER_ANY); @@ -783,5 +935,5 @@ MUTATOR_DEFINITION(mutator_buffs) buffs_Initialize(); } - return FALSE; + return false; }