X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fweapons%2Fweapon%2Farc.qc;h=1eaf4062d462d6860df66d0001b719e4ec0eeb27;hb=83aad9e1a69d8e924df17cdbad05b015c6c6f0fc;hp=4a15cc6c7f1a90bc0af1fd2bfccd8cafda7db1d5;hpb=f203a8239ab58e776da8df7bce46be73d2d655a4;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/weapons/weapon/arc.qc b/qcsrc/common/weapons/weapon/arc.qc index 4a15cc6c7..1eaf4062d 100644 --- a/qcsrc/common/weapons/weapon/arc.qc +++ b/qcsrc/common/weapons/weapon/arc.qc @@ -14,47 +14,65 @@ CLASS(Arc, Weapon) /* wepimg */ ATTRIB(Arc, model2, string, "weaponarc"); /* refname */ ATTRIB(Arc, netname, string, "arc"); /* wepname */ ATTRIB(Arc, m_name, string, _("Arc")); + +#define X(BEGIN, P, END, class, prefix) \ + BEGIN(class) \ + P(class, prefix, bolt, float, NONE) \ + P(class, prefix, bolt_ammo, float, NONE) \ + P(class, prefix, bolt_damageforcescale, float, NONE) \ + P(class, prefix, bolt_damage, float, NONE) \ + P(class, prefix, bolt_edgedamage, float, NONE) \ + P(class, prefix, bolt_force, float, NONE) \ + P(class, prefix, bolt_health, float, NONE) \ + P(class, prefix, bolt_lifetime, float, NONE) \ + P(class, prefix, bolt_radius, float, NONE) \ + P(class, prefix, bolt_refire, float, NONE) \ + P(class, prefix, bolt_speed, float, NONE) \ + P(class, prefix, bolt_spread, float, NONE) \ + P(class, prefix, beam_ammo, float, NONE) \ + P(class, prefix, beam_animtime, float, NONE) \ + P(class, prefix, beam_botaimlifetime, float, NONE) \ + P(class, prefix, beam_botaimspeed, float, NONE) \ + P(class, prefix, beam_damage, float, NONE) \ + P(class, prefix, beam_degreespersegment, float, NONE) \ + P(class, prefix, beam_distancepersegment, float, NONE) \ + P(class, prefix, beam_falloff_halflifedist, float, NONE) \ + P(class, prefix, beam_falloff_maxdist, float, NONE) \ + P(class, prefix, beam_falloff_mindist, float, NONE) \ + P(class, prefix, beam_force, float, NONE) \ + P(class, prefix, beam_healing_amax, float, NONE) \ + P(class, prefix, beam_healing_aps, float, NONE) \ + P(class, prefix, beam_healing_hmax, float, NONE) \ + P(class, prefix, beam_healing_hps, float, NONE) \ + P(class, prefix, beam_heat, float, NONE) /* heat increase per second (primary) */ \ + P(class, prefix, beam_maxangle, float, NONE) \ + P(class, prefix, beam_nonplayerdamage, float, NONE) \ + P(class, prefix, beam_range, float, NONE) \ + P(class, prefix, beam_refire, float, NONE) \ + P(class, prefix, beam_returnspeed, float, NONE) \ + P(class, prefix, beam_tightness, float, NONE) \ + P(class, prefix, burst_ammo, float, NONE) \ + P(class, prefix, burst_damage, float, NONE) \ + P(class, prefix, burst_healing_aps, float, NONE) \ + P(class, prefix, burst_healing_hps, float, NONE) \ + P(class, prefix, burst_heat, float, NONE) /* heat increase per second (secondary) */ \ + P(class, prefix, cooldown, float, NONE) /* heat decrease per second when resting */ \ + P(class, prefix, cooldown_release, float, NONE) /* delay weapon re-use when releasing button */ \ + P(class, prefix, overheat_max, float, NONE) /* maximum heat before jamming */ \ + P(class, prefix, overheat_min, float, NONE) /* minimum heat to wait for cooldown */ \ + P(class, prefix, switchdelay_drop, float, NONE) \ + P(class, prefix, switchdelay_raise, float, NONE) \ + P(class, prefix, weaponreplace, string, NONE) \ + P(class, prefix, weaponstartoverride, float, NONE) \ + P(class, prefix, weaponstart, float, NONE) \ + P(class, prefix, weaponthrowable, float, NONE) \ + END() + W_PROPS(X, Arc, arc) +#undef X + ENDCLASS(Arc) -REGISTER_WEAPON(ARC, NEW(Arc)); - -#define ARC_SETTINGS(w_cvar,w_prop) ARC_SETTINGS_LIST(w_cvar, w_prop, ARC, arc) -#define ARC_SETTINGS_LIST(w_cvar,w_prop,id,sn) \ - w_cvar(id, sn, NONE, beam_ammo) \ - w_cvar(id, sn, NONE, beam_animtime) \ - w_cvar(id, sn, NONE, beam_botaimspeed) \ - w_cvar(id, sn, NONE, beam_botaimlifetime) \ - w_cvar(id, sn, NONE, beam_damage) \ - w_cvar(id, sn, NONE, beam_degreespersegment) \ - w_cvar(id, sn, NONE, beam_distancepersegment) \ - w_cvar(id, sn, NONE, beam_falloff_halflifedist) \ - w_cvar(id, sn, NONE, beam_falloff_maxdist) \ - w_cvar(id, sn, NONE, beam_falloff_mindist) \ - w_cvar(id, sn, NONE, beam_force) \ - w_cvar(id, sn, NONE, beam_healing_amax) \ - w_cvar(id, sn, NONE, beam_healing_aps) \ - w_cvar(id, sn, NONE, beam_healing_hmax) \ - w_cvar(id, sn, NONE, beam_healing_hps) \ - w_cvar(id, sn, NONE, beam_maxangle) \ - w_cvar(id, sn, NONE, beam_nonplayerdamage) \ - w_cvar(id, sn, NONE, beam_range) \ - w_cvar(id, sn, NONE, beam_refire) \ - w_cvar(id, sn, NONE, beam_returnspeed) \ - w_cvar(id, sn, NONE, beam_tightness) \ - w_cvar(id, sn, NONE, burst_ammo) \ - w_cvar(id, sn, NONE, burst_damage) \ - w_cvar(id, sn, NONE, burst_healing_aps) \ - w_cvar(id, sn, NONE, burst_healing_hps) \ - w_cvar(id, sn, NONE, overheat_max)/* maximum heat before jamming */ \ - w_cvar(id, sn, NONE, overheat_min)/* minimum heat to wait for cooldown */ \ - w_cvar(id, sn, NONE, beam_heat) /* heat increase per second (primary) */ \ - w_cvar(id, sn, NONE, burst_heat) /* heat increase per second (secondary) */ \ - w_cvar(id, sn, NONE, cooldown) /* heat decrease per second when resting */ \ - w_prop(id, sn, float, switchdelay_raise, switchdelay_raise) \ - w_prop(id, sn, float, switchdelay_drop, switchdelay_drop) \ - w_prop(id, sn, string, weaponreplace, weaponreplace) \ - w_prop(id, sn, float, weaponstart, weaponstart) \ - w_prop(id, sn, float, weaponstartoverride, weaponstartoverride) \ - w_prop(id, sn, float, weaponthrowable, weaponthrowable) +REGISTER_WEAPON(ARC, arc, NEW(Arc)); + #ifndef MENUQC const float ARC_MAX_SEGMENTS = 20; @@ -82,7 +100,6 @@ const int ARC_SF_BEAMTYPE = BIT(4); const int ARC_SF_LOCALMASK = ARC_SF_START | ARC_SF_WANTDIR | ARC_SF_BEAMDIR; #endif #ifdef SVQC -ARC_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP) .entity arc_beam; .bool arc_BUTTON_ATCK_prev; // for better animation control .float beam_prev; @@ -137,7 +154,7 @@ bool W_Arc_Beam_Send(entity this, entity to, int sf) // - The owner client has no use for beam start position or directions, // it always figures this information out for itself with csqc code. // - Spectating the owner also truncates this information. - float drawlocal = ((to == self.owner) || ((to.enemy == self.owner) && IS_SPEC(to))); + float drawlocal = ((to == this.owner) || ((to.enemy == this.owner) && IS_SPEC(to))); if(drawlocal) { sf &= ~ARC_SF_LOCALMASK; } WriteByte(MSG_ENTITY, sf); @@ -152,28 +169,29 @@ bool W_Arc_Beam_Send(entity this, entity to, int sf) WriteByte(MSG_ENTITY, WEP_CVAR(arc, beam_tightness) * 10); WriteByte(MSG_ENTITY, drawlocal); + WriteByte(MSG_ENTITY, etof(this.owner)); } if(sf & ARC_SF_START) // starting location { - WriteCoord(MSG_ENTITY, self.beam_start.x); - WriteCoord(MSG_ENTITY, self.beam_start.y); - WriteCoord(MSG_ENTITY, self.beam_start.z); + WriteCoord(MSG_ENTITY, this.beam_start.x); + WriteCoord(MSG_ENTITY, this.beam_start.y); + WriteCoord(MSG_ENTITY, this.beam_start.z); } if(sf & ARC_SF_WANTDIR) // want/aim direction { - WriteCoord(MSG_ENTITY, self.beam_wantdir.x); - WriteCoord(MSG_ENTITY, self.beam_wantdir.y); - WriteCoord(MSG_ENTITY, self.beam_wantdir.z); + WriteCoord(MSG_ENTITY, this.beam_wantdir.x); + WriteCoord(MSG_ENTITY, this.beam_wantdir.y); + WriteCoord(MSG_ENTITY, this.beam_wantdir.z); } if(sf & ARC_SF_BEAMDIR) // beam direction { - WriteCoord(MSG_ENTITY, self.beam_dir.x); - WriteCoord(MSG_ENTITY, self.beam_dir.y); - WriteCoord(MSG_ENTITY, self.beam_dir.z); + WriteCoord(MSG_ENTITY, this.beam_dir.x); + WriteCoord(MSG_ENTITY, this.beam_dir.y); + WriteCoord(MSG_ENTITY, this.beam_dir.z); } if(sf & ARC_SF_BEAMTYPE) // beam type { - WriteByte(MSG_ENTITY, self.beam_type); + WriteByte(MSG_ENTITY, this.beam_type); } return true; @@ -213,82 +231,160 @@ void Arc_Player_SetHeat(entity player) //dprint("Heat: ",ftos(player.arc_heat_percent*100),"%\n"); } -void W_Arc_Beam_Think() -{SELFPARAM(); - if(self != self.owner.arc_beam) +void W_Arc_Bolt_Explode(entity this, entity directhitentity) +{ + this.event_damage = func_null; + RadiusDamage(this, this.realowner, WEP_CVAR(arc, bolt_damage), WEP_CVAR(arc, bolt_edgedamage), WEP_CVAR(arc, bolt_radius), NULL, NULL, WEP_CVAR(arc, bolt_force), this.projectiledeathtype, directhitentity); + + remove(this); +} + +void W_Arc_Bolt_Explode_use(entity this, entity actor, entity trigger) +{ + W_Arc_Bolt_Explode(this, trigger); +} + +void W_Arc_Bolt_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) +{ + if(this.health <= 0) + return; + + if(!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) + return; // g_projectiles_damage says to halt + + this.health = this.health - damage; + this.angles = vectoangles(this.velocity); + + if(this.health <= 0) + W_PrepareExplosionByDamage(this, attacker, getthink(this)); +} + +void W_Arc_Bolt_Touch(entity this, entity toucher) +{ + PROJECTILE_TOUCH(this, toucher); + this.use(this, NULL, toucher); +} + +void W_Arc_Attack_Bolt(Weapon thiswep, entity actor) +{ + entity missile; + + W_DecreaseAmmo(thiswep, actor, WEP_CVAR(arc, bolt_ammo)); + + W_SetupShot(actor, false, 2, SND_LASERGUN_FIRE, CH_WEAPON_A, WEP_CVAR(arc, bolt_damage)); + + Send_Effect(EFFECT_ARC_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1); + + missile = new(missile); + missile.owner = missile.realowner = actor; + missile.bot_dodge = true; + missile.bot_dodgerating = WEP_CVAR(arc, bolt_damage); + + missile.takedamage = DAMAGE_YES; + missile.health = WEP_CVAR(arc, bolt_health); + missile.damageforcescale = WEP_CVAR(arc, bolt_damageforcescale); + missile.event_damage = W_Arc_Bolt_Damage; + missile.damagedbycontents = true; + + settouch(missile, W_Arc_Bolt_Touch); + missile.use = W_Arc_Bolt_Explode_use; + setthink(missile, adaptor_think2use_hittype_splash); + missile.nextthink = time + WEP_CVAR(arc, bolt_lifetime); + PROJECTILE_MAKETRIGGER(missile); + missile.projectiledeathtype = WEP_ARC.m_id | HITTYPE_SECONDARY; + setorigin(missile, w_shotorg); + setsize(missile, '0 0 0', '0 0 0'); + + set_movetype(missile, MOVETYPE_FLY); + W_SetupProjVelocity_PRE(missile, arc, bolt_); + + missile.angles = vectoangles(missile.velocity); + missile.flags = FL_PROJECTILE; + missile.missile_flags = MIF_SPLASH; + + CSQCProjectile(missile, true, PROJECTILE_ARC_BOLT, true); + + MUTATOR_CALLHOOK(EditProjectile, actor, missile); +} + +void W_Arc_Beam_Think(entity this) +{ + if(this != this.owner.arc_beam) { - remove(self); + remove(this); return; } float burst = 0; - if( self.owner.BUTTON_ATCK2 || self.beam_bursting) + if( (PHYS_INPUT_BUTTON_ATCK2(this.owner) && !WEP_CVAR(arc, bolt)) || this.beam_bursting) { - if(!self.beam_bursting) - self.beam_bursting = true; + if(!this.beam_bursting) + this.beam_bursting = true; burst = ARC_BT_BURSTMASK; } + Weapon thiswep = WEP_ARC; + if( - !IS_PLAYER(self.owner) + !IS_PLAYER(this.owner) || - (self.owner.WEP_AMMO(ARC) <= 0 && !(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)) + (this.owner.(thiswep.ammo_field) <= 0 && !(this.owner.items & IT_UNLIMITED_WEAPON_AMMO)) || - self.owner.deadflag != DEAD_NO + IS_DEAD(this.owner) || - (!self.owner.BUTTON_ATCK && !burst ) + forbidWeaponUse(this.owner) || - self.owner.frozen + (!PHYS_INPUT_BUTTON_ATCK(this.owner) && !burst ) || - self.owner.vehicle + this.owner.vehicle || - (WEP_CVAR(arc, overheat_max) > 0 && self.beam_heat >= WEP_CVAR(arc, overheat_max)) + (WEP_CVAR(arc, overheat_max) > 0 && this.beam_heat >= WEP_CVAR(arc, overheat_max)) ) { if ( WEP_CVAR(arc, cooldown) > 0 ) { float cooldown_speed = 0; - if ( self.beam_heat > WEP_CVAR(arc, overheat_min) && WEP_CVAR(arc, cooldown) > 0 ) + if ( this.beam_heat > WEP_CVAR(arc, overheat_min) && WEP_CVAR(arc, cooldown) > 0 ) { cooldown_speed = WEP_CVAR(arc, cooldown); } else if ( !burst ) { - cooldown_speed = self.beam_heat / WEP_CVAR(arc, beam_refire); + cooldown_speed = this.beam_heat / WEP_CVAR(arc, beam_refire); } if ( cooldown_speed ) { - self.owner.arc_overheat = time + self.beam_heat / cooldown_speed; - self.owner.arc_cooldown = cooldown_speed; + if ( WEP_CVAR(arc, cooldown_release) || (WEP_CVAR(arc, overheat_max) > 0 && this.beam_heat >= WEP_CVAR(arc, overheat_max)) ) + this.owner.arc_overheat = time + this.beam_heat / cooldown_speed; + this.owner.arc_cooldown = cooldown_speed; } - if ( WEP_CVAR(arc, overheat_max) > 0 && self.beam_heat >= WEP_CVAR(arc, overheat_max) ) + if ( WEP_CVAR(arc, overheat_max) > 0 && this.beam_heat >= WEP_CVAR(arc, overheat_max) ) { Send_Effect(EFFECT_ARC_OVERHEAT, - self.beam_start, self.beam_wantdir, 1 ); - sound(self, CH_WEAPON_A, SND_ARC_STOP, VOL_BASE, ATTN_NORM); + this.beam_start, this.beam_wantdir, 1 ); + sound(this, CH_WEAPON_A, SND_ARC_STOP, VOL_BASE, ATTN_NORM); } } - if(self == self.owner.arc_beam) { self.owner.arc_beam = world; } - setself(self.owner); + if(this == this.owner.arc_beam) { this.owner.arc_beam = NULL; } + entity own = this.owner; Weapon w = WEP_ARC; - if(!w.wr_checkammo1(w) && !w.wr_checkammo2(w)) - if(!(self.items & IT_UNLIMITED_WEAPON_AMMO)) + if(!w.wr_checkammo1(w, own) && !w.wr_checkammo2(w, own)) + if(!(own.items & IT_UNLIMITED_WEAPON_AMMO)) { // note: this doesn't force the switch - W_SwitchToOtherWeapon(self); + W_SwitchToOtherWeapon(own); } - setself(this); - remove(self); + remove(this); return; } // decrease ammo float coefficient = frametime; - if(!(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)) + if(!(this.owner.items & IT_UNLIMITED_WEAPON_AMMO)) { float rootammo; if(burst) @@ -298,64 +394,64 @@ void W_Arc_Beam_Think() if(rootammo) { - coefficient = min(coefficient, self.owner.WEP_AMMO(ARC) / rootammo); - self.owner.WEP_AMMO(ARC) = max(0, self.owner.WEP_AMMO(ARC) - (rootammo * frametime)); + coefficient = min(coefficient, this.owner.(thiswep.ammo_field) / rootammo); + this.owner.(thiswep.ammo_field) = max(0, this.owner.(thiswep.ammo_field) - (rootammo * frametime)); } } float heat_speed = burst ? WEP_CVAR(arc, burst_heat) : WEP_CVAR(arc, beam_heat); - self.beam_heat = min( WEP_CVAR(arc, overheat_max), self.beam_heat + heat_speed*frametime ); + this.beam_heat = min( WEP_CVAR(arc, overheat_max), this.beam_heat + heat_speed*frametime ); - makevectors(self.owner.v_angle); + makevectors(this.owner.v_angle); W_SetupShot_Range( - self.owner, + this.owner, true, 0, - "", + SND_Null, 0, WEP_CVAR(arc, beam_damage) * coefficient, WEP_CVAR(arc, beam_range) ); // After teleport, "lock" the beam until the teleport is confirmed. - if (time < self.beam_teleporttime + ANTILAG_LATENCY(self.owner)) { - w_shotdir = self.beam_dir; + if (time < this.beam_teleporttime + ANTILAG_LATENCY(this.owner)) { + w_shotdir = this.beam_dir; } // network information: shot origin and want/aim direction - if(self.beam_start != w_shotorg) + if(this.beam_start != w_shotorg) { - self.SendFlags |= ARC_SF_START; - self.beam_start = w_shotorg; + this.SendFlags |= ARC_SF_START; + this.beam_start = w_shotorg; } - if(self.beam_wantdir != w_shotdir) + if(this.beam_wantdir != w_shotdir) { - self.SendFlags |= ARC_SF_WANTDIR; - self.beam_wantdir = w_shotdir; + this.SendFlags |= ARC_SF_WANTDIR; + this.beam_wantdir = w_shotdir; } - if(!self.beam_initialized) + if(!this.beam_initialized) { - self.beam_dir = w_shotdir; - self.beam_initialized = true; + this.beam_dir = w_shotdir; + this.beam_initialized = true; } // WEAPONTODO: Detect player velocity so that the beam curves when moving too - // idea: blend together self.beam_dir with the inverted direction the player is moving in + // idea: blend together this.beam_dir with the inverted direction the player is moving in // might have to make some special accomodation so that it only uses view_right and view_up // note that if we do this, it'll always be corrected to a maximum angle by beam_maxangle handling float segments; - if(self.beam_dir != w_shotdir) + if(this.beam_dir != w_shotdir) { // calculate how much we're going to move the end of the beam to the want position // WEAPONTODO (server and client): // blendfactor never actually becomes 0 in this situation, which is a problem - // regarding precision... this means that self.beam_dir and w_shotdir approach + // regarding precision... this means that this.beam_dir and w_shotdir approach // eachother, however they never actually become the same value with this method. // Perhaps we should do some form of rounding/snapping? - float angle = vlen(w_shotdir - self.beam_dir) * RAD2DEG; + float angle = vlen(w_shotdir - this.beam_dir) * RAD2DEG; if(angle && (angle > WEP_CVAR(arc, beam_maxangle))) { // if the angle is greater than maxangle, force the blendfactor to make this the maximum factor @@ -364,7 +460,7 @@ void W_Arc_Beam_Think() (1 - (WEP_CVAR(arc, beam_returnspeed) * frametime)), min(WEP_CVAR(arc, beam_maxangle) / angle, 1) ); - self.beam_dir = normalize((w_shotdir * (1 - blendfactor)) + (self.beam_dir * blendfactor)); + this.beam_dir = normalize((w_shotdir * (1 - blendfactor)) + (this.beam_dir * blendfactor)); } else { @@ -374,11 +470,11 @@ void W_Arc_Beam_Think() (1 - (WEP_CVAR(arc, beam_returnspeed) * frametime)), 1 ); - self.beam_dir = normalize((w_shotdir * (1 - blendfactor)) + (self.beam_dir * blendfactor)); + this.beam_dir = normalize((w_shotdir * (1 - blendfactor)) + (this.beam_dir * blendfactor)); } // network information: beam direction - self.SendFlags |= ARC_SF_BEAMDIR; + this.SendFlags |= ARC_SF_BEAMDIR; // calculate how many segments are needed float max_allowed_segments; @@ -411,7 +507,7 @@ void W_Arc_Beam_Think() } else { segments = 1; } - vector beam_endpos = (w_shotorg + (self.beam_dir * WEP_CVAR(arc, beam_range))); + vector beam_endpos = (w_shotorg + (this.beam_dir * WEP_CVAR(arc, beam_range))); vector beam_controlpoint = w_shotorg + w_shotdir * (WEP_CVAR(arc, beam_range) * (1 - WEP_CVAR(arc, beam_tightness))); float i; @@ -433,12 +529,12 @@ void W_Arc_Beam_Think() vector new_dir = normalize(new_origin - last_origin); WarpZone_traceline_antilag( - self.owner, + this.owner, last_origin, new_origin, MOVE_NORMAL, - self.owner, - ANTILAG_LATENCY(self.owner) + this.owner, + ANTILAG_LATENCY(this.owner) ); // Do all the transforms for warpzones right now, as we already @@ -472,7 +568,7 @@ void W_Arc_Beam_Think() vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, hitorigin) - w_shotorg) ); - if(is_player && SAME_TEAM(self.owner, trace_ent)) + if(is_player && SAME_TEAM(this.owner, trace_ent)) { float roothealth, rootarmor; if(burst) @@ -528,10 +624,10 @@ void W_Arc_Beam_Think() else { rootdamage = WEP_CVAR(arc, beam_nonplayerdamage); } - if(accuracy_isgooddamage(self.owner, trace_ent)) + if(accuracy_isgooddamage(this.owner, trace_ent)) { accuracy_add( - self.owner, + this.owner, WEP_ARC.m_id, 0, rootdamage * coefficient * falloff @@ -540,8 +636,8 @@ void W_Arc_Beam_Think() Damage( trace_ent, - self.owner, - self.owner, + this.owner, + this.owner, rootdamage * coefficient * falloff, WEP_ARC.m_id, hitorigin, @@ -566,198 +662,237 @@ void W_Arc_Beam_Think() new_beam_type |= burst; // network information: beam type - if(new_beam_type != self.beam_type) + if(new_beam_type != this.beam_type) { - self.SendFlags |= ARC_SF_BEAMTYPE; - self.beam_type = new_beam_type; + this.SendFlags |= ARC_SF_BEAMTYPE; + this.beam_type = new_beam_type; } - self.owner.beam_prev = time; - self.nextthink = time; + this.owner.beam_prev = time; + this.nextthink = time; } -void W_Arc_Beam(float burst) -{SELFPARAM(); +void W_Arc_Beam(float burst, entity actor) +{ // only play fire sound if 1 sec has passed since player let go the fire button - if(time - self.beam_prev > 1) - sound(self, CH_WEAPON_A, SND_ARC_FIRE, VOL_BASE, ATTN_NORM); + if(time - actor.beam_prev > 1) + sound(actor, CH_WEAPON_A, SND_ARC_FIRE, VOL_BASE, ATTN_NORM); - entity beam = self.arc_beam = new(W_Arc_Beam); + entity beam = actor.arc_beam = new(W_Arc_Beam); beam.solid = SOLID_NOT; - beam.think = W_Arc_Beam_Think; - beam.owner = self; - beam.movetype = MOVETYPE_NONE; + setthink(beam, W_Arc_Beam_Think); + beam.owner = actor; + set_movetype(beam, MOVETYPE_NONE); beam.bot_dodge = true; beam.bot_dodgerating = WEP_CVAR(arc, beam_damage); beam.beam_bursting = burst; Net_LinkEntity(beam, false, 0, W_Arc_Beam_Send); - WITH(entity, self, beam, beam.think()); + getthink(beam)(beam); } +void Arc_Smoke(entity actor) +{ + makevectors(actor.v_angle); + W_SetupShot_Range(actor,true,0,SND_Null,0,0,0); -void Arc_Smoke() -{SELFPARAM(); - makevectors(self.v_angle); - W_SetupShot_Range(self,true,0,"",0,0,0); - - vector smoke_origin = w_shotorg + self.velocity*frametime; - if ( self.arc_overheat > time ) + vector smoke_origin = w_shotorg + actor.velocity*frametime; + if ( actor.arc_overheat > time ) { - if ( random() < self.arc_heat_percent ) + if ( random() < actor.arc_heat_percent ) Send_Effect(EFFECT_ARC_SMOKE, smoke_origin, '0 0 0', 1 ); - if ( self.BUTTON_ATCK || self.BUTTON_ATCK2 ) + if ( PHYS_INPUT_BUTTON_ATCK(actor) || PHYS_INPUT_BUTTON_ATCK2(actor) ) { Send_Effect(EFFECT_ARC_OVERHEAT_FIRE, smoke_origin, w_shotdir, 1 ); - if ( !self.arc_smoke_sound ) + if ( !actor.arc_smoke_sound ) { - self.arc_smoke_sound = 1; - sound(self, CH_SHOTS_SINGLE, SND_ARC_LOOP_OVERHEAT, VOL_BASE, ATTN_NORM); + actor.arc_smoke_sound = 1; + sound(actor, CH_SHOTS_SINGLE, SND_ARC_LOOP_OVERHEAT, VOL_BASE, ATTN_NORM); } } } - else if ( self.arc_beam && WEP_CVAR(arc, overheat_max) > 0 && - self.arc_beam.beam_heat > WEP_CVAR(arc, overheat_min) ) + else if ( actor.arc_beam && WEP_CVAR(arc, overheat_max) > 0 && + actor.arc_beam.beam_heat > WEP_CVAR(arc, overheat_min) ) { - if ( random() < (self.arc_beam.beam_heat-WEP_CVAR(arc, overheat_min)) / + if ( random() < (actor.arc_beam.beam_heat-WEP_CVAR(arc, overheat_min)) / ( WEP_CVAR(arc, overheat_max)-WEP_CVAR(arc, overheat_min) ) ) Send_Effect(EFFECT_ARC_SMOKE, smoke_origin, '0 0 0', 1 ); } - if ( self.arc_smoke_sound && ( self.arc_overheat <= time || - !( self.BUTTON_ATCK || self.BUTTON_ATCK2 ) ) || self.switchweapon != WEP_ARC.m_id ) + if ( actor.arc_smoke_sound && ( actor.arc_overheat <= time || + !( PHYS_INPUT_BUTTON_ATCK(actor) || PHYS_INPUT_BUTTON_ATCK2(actor) ) ) || PS(actor).m_switchweapon != WEP_ARC ) { - self.arc_smoke_sound = 0; - sound(self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM); + actor.arc_smoke_sound = 0; + sound(actor, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM); } } - METHOD(Arc, wr_aim, void(entity thiswep)) - { - SELFPARAM(); - if(WEP_CVAR(arc, beam_botaimspeed)) - { - self.BUTTON_ATCK = bot_aim( - WEP_CVAR(arc, beam_botaimspeed), - 0, - WEP_CVAR(arc, beam_botaimlifetime), - false - ); - } - else - { - self.BUTTON_ATCK = bot_aim( - 1000000, - 0, - 0.001, - false - ); - } - } - METHOD(Arc, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) - { - Arc_Player_SetHeat(actor); - Arc_Smoke(); - - if (time >= actor.arc_overheat) - if ((fire & 1) || (fire & 2) || actor.arc_beam.beam_bursting) - { - - if(actor.arc_BUTTON_ATCK_prev) - { - #if 0 - if(actor.animstate_startframe == actor.anim_shoot.x && actor.animstate_numframes == actor.anim_shoot.y) - weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, autocvar_g_balance_arc_primary_animtime, w_ready); - else - #endif - weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, WEP_CVAR(arc, beam_animtime), w_ready); - } - - if((!actor.arc_beam) || wasfreed(actor.arc_beam)) - { - if(weapon_prepareattack(thiswep, actor, weaponentity, boolean(fire & 2), 0)) - { - W_Arc_Beam(boolean(fire & 2)); - - if(!actor.arc_BUTTON_ATCK_prev) - { - weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready); - actor.arc_BUTTON_ATCK_prev = true; - } - } - } - - return; - } - - if(actor.arc_BUTTON_ATCK_prev) - { - sound(actor, CH_WEAPON_A, SND_ARC_STOP, VOL_BASE, ATTN_NORM); - weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready); - int slot = weaponslot(weaponentity); - ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(arc, beam_refire) * W_WeaponRateFactor(); - } - actor.arc_BUTTON_ATCK_prev = false; - - #if 0 - if(fire & 2) - if(weapon_prepareattack(thiswep, actor, weaponentity, true, autocvar_g_balance_arc_secondary_refire)) - { - W_Arc_Attack2(); - actor.arc_count = autocvar_g_balance_arc_secondary_count; - weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, autocvar_g_balance_arc_secondary_animtime, w_arc_checkattack); - actor.arc_secondarytime = time + autocvar_g_balance_arc_secondary_refire2 * W_WeaponRateFactor(); - } - #endif - } - METHOD(Arc, wr_init, void(entity thiswep)) - { - if(!arc_shotorigin[0]) - { - arc_shotorigin[0] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC.m_id), false, false, 1); - arc_shotorigin[1] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC.m_id), false, false, 2); - arc_shotorigin[2] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC.m_id), false, false, 3); - arc_shotorigin[3] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC.m_id), false, false, 4); - } - ARC_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP); - } - METHOD(Arc, wr_checkammo1, bool(entity thiswep)) - { - SELFPARAM(); - return ((!WEP_CVAR(arc, beam_ammo)) || (self.WEP_AMMO(ARC) > 0)); - } - METHOD(Arc, wr_checkammo2, bool(entity thiswep)) - { - SELFPARAM(); - return WEP_CVAR(arc, overheat_max) > 0 && - ((!WEP_CVAR(arc, burst_ammo)) || (self.WEP_AMMO(ARC) > 0)); - } - METHOD(Arc, wr_config, void(entity thiswep)) - { - ARC_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS); - } - METHOD(Arc, wr_killmessage, int(entity thiswep)) - { - return WEAPON_ARC_MURDER; - } - METHOD(Arc, wr_drop, void(entity thiswep)) - { - weapon_dropevent_item.arc_overheat = self.arc_overheat; - weapon_dropevent_item.arc_cooldown = self.arc_cooldown; - self.arc_overheat = 0; - self.arc_cooldown = 0; - } - METHOD(Arc, wr_pickup, void(entity thiswep)) - { - if ( !client_hasweapon(self, thiswep, false, false) && - weapon_dropevent_item.arc_overheat > time ) - { - self.arc_overheat = weapon_dropevent_item.arc_overheat; - self.arc_cooldown = weapon_dropevent_item.arc_cooldown; - } - } +METHOD(Arc, wr_aim, void(entity thiswep, entity actor)) +{ + if(WEP_CVAR(arc, beam_botaimspeed)) + { + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim( + actor, + WEP_CVAR(arc, beam_botaimspeed), + 0, + WEP_CVAR(arc, beam_botaimlifetime), + false + ); + } + else + { + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim( + actor, + 1000000, + 0, + 0.001, + false + ); + } +} +METHOD(Arc, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) +{ + Arc_Player_SetHeat(actor); + Arc_Smoke(actor); + + bool beam_fire2 = ((fire & 2) && !WEP_CVAR(arc, bolt)); + + if (time >= actor.arc_overheat) + if ((fire & 1) || beam_fire2 || actor.arc_beam.beam_bursting) + { + + if(actor.arc_BUTTON_ATCK_prev) + { + #if 0 + if(actor.animstate_startframe == actor.anim_shoot.x && actor.animstate_numframes == actor.anim_shoot.y) + weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, autocvar_g_balance_arc_primary_animtime, w_ready); + else + #endif + weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, WEP_CVAR(arc, beam_animtime), w_ready); + } + + if((!actor.arc_beam) || wasfreed(actor.arc_beam)) + { + if(weapon_prepareattack(thiswep, actor, weaponentity, boolean(beam_fire2), 0)) + { + W_Arc_Beam(boolean(beam_fire2), actor); + + if(!actor.arc_BUTTON_ATCK_prev) + { + weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready); + actor.arc_BUTTON_ATCK_prev = true; + } + } + } + + return; + } + else if(fire & 2) + { + if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(arc, bolt_refire))) + { + W_Arc_Attack_Bolt(thiswep, actor); + weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, bolt_refire), w_ready); + } + } + + if(actor.arc_BUTTON_ATCK_prev) + { + sound(actor, CH_WEAPON_A, SND_ARC_STOP, VOL_BASE, ATTN_NORM); + weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready); + int slot = weaponslot(weaponentity); + ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(arc, beam_refire) * W_WeaponRateFactor(actor); + } + actor.arc_BUTTON_ATCK_prev = false; + + #if 0 + if(fire & 2) + if(weapon_prepareattack(thiswep, actor, weaponentity, true, autocvar_g_balance_arc_secondary_refire)) + { + W_Arc_Attack2(); + actor.arc_count = autocvar_g_balance_arc_secondary_count; + weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, autocvar_g_balance_arc_secondary_animtime, w_arc_checkattack); + actor.arc_secondarytime = time + autocvar_g_balance_arc_secondary_refire2 * W_WeaponRateFactor(actor); + } + #endif +} +METHOD(Arc, wr_init, void(entity thiswep)) +{ + if(!arc_shotorigin[0]) + { + arc_shotorigin[0] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC.m_id), false, false, 1); + arc_shotorigin[1] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC.m_id), false, false, 2); + arc_shotorigin[2] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC.m_id), false, false, 3); + arc_shotorigin[3] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC.m_id), false, false, 4); + } +} +METHOD(Arc, wr_checkammo1, bool(entity thiswep, entity actor)) +{ + return ((!WEP_CVAR(arc, beam_ammo)) || (actor.(thiswep.ammo_field) > 0)); +} +METHOD(Arc, wr_checkammo2, bool(entity thiswep, entity actor)) +{ + if(WEP_CVAR(arc, bolt)) + { + float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(arc, bolt_ammo); + ammo_amount += actor.(weapon_load[WEP_ARC.m_id]) >= WEP_CVAR(arc, bolt_ammo); + return ammo_amount; + } + else + return WEP_CVAR(arc, overheat_max) > 0 && + ((!WEP_CVAR(arc, burst_ammo)) || (actor.(thiswep.ammo_field) > 0)); +} +METHOD(Arc, wr_killmessage, Notification(entity thiswep)) +{ + if(w_deathtype & HITTYPE_SECONDARY) + return WEAPON_ARC_MURDER_SPRAY; + else + return WEAPON_ARC_MURDER; +} +METHOD(Arc, wr_drop, void(entity thiswep, entity actor)) +{ + weapon_dropevent_item.arc_overheat = actor.arc_overheat; + weapon_dropevent_item.arc_cooldown = actor.arc_cooldown; + actor.arc_overheat = 0; + actor.arc_cooldown = 0; + actor.arc_BUTTON_ATCK_prev = false; +} +METHOD(Arc, wr_pickup, void(entity thiswep, entity actor)) +{ + if ( !client_hasweapon(actor, thiswep, false, false) && + weapon_dropevent_item.arc_overheat > time ) + { + actor.arc_overheat = weapon_dropevent_item.arc_overheat; + actor.arc_cooldown = weapon_dropevent_item.arc_cooldown; + } +} +METHOD(Arc, wr_resetplayer, void(entity thiswep, entity actor)) +{ + actor.arc_overheat = 0; + actor.arc_cooldown = 0; + actor.arc_BUTTON_ATCK_prev = false; +} +METHOD(Arc, wr_playerdeath, void(entity thiswep, entity actor)) +{ + actor.arc_overheat = 0; + actor.arc_cooldown = 0; + actor.arc_BUTTON_ATCK_prev = false; +} #endif #ifdef CSQC +bool autocvar_cl_arcbeam_teamcolor = true; + +METHOD(Arc, wr_impacteffect, void(entity thiswep, entity actor)) +{ + if(w_deathtype & HITTYPE_SECONDARY) + { + vector org2; + org2 = w_org + w_backoff * 6; + pointparticles(EFFECT_ARC_BOLT_EXPLODE, org2, w_backoff * 1000, 1); + if(!w_issilent) { sound(actor, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTN_NORM); } + } +} + void Draw_ArcBeam_callback(vector start, vector hit, vector end) { entity beam = Draw_ArcBeam_callback_entity; @@ -841,23 +976,23 @@ void Draw_ArcBeam_callback(vector start, vector hit, vector end) void Reset_ArcBeam() { entity e; - for (e = world; (e = findfloat(e, beam_usevieworigin, 1)); ) { + for (e = NULL; (e = findfloat(e, beam_usevieworigin, 1)); ) { e.beam_initialized = false; } - for (e = world; (e = findfloat(e, beam_usevieworigin, 2)); ) { + for (e = NULL; (e = findfloat(e, beam_usevieworigin, 2)); ) { e.beam_initialized = false; } } void Draw_ArcBeam(entity this) { - float dt = time - self.move_time; - self.move_time = time; + float dt = time - this.move_time; + this.move_time = time; if(dt <= 0) { return; } - if(!self.beam_usevieworigin) + if(!this.beam_usevieworigin) { - InterpolateOrigin_Do(self); + InterpolateOrigin_Do(this); } // origin = beam starting origin @@ -866,10 +1001,10 @@ void Draw_ArcBeam(entity this) vector start_pos; vector wantdir; //= view_forward; - vector beamdir; //= self.beam_dir; + vector beamdir; //= this.beam_dir; float segments; - if(self.beam_usevieworigin) + if(this.beam_usevieworigin) { // WEAPONTODO: // Currently we have to replicate nearly the same method of figuring @@ -884,99 +1019,99 @@ void Draw_ArcBeam(entity this) vector up = v_up; // decide upon start position - if(self.beam_usevieworigin == 2) + if(this.beam_usevieworigin == 2) { start_pos = warpzone_save_view_origin; } else - { start_pos = self.origin; } + { start_pos = this.origin; } // trace forward with an estimation WarpZone_TraceLine( start_pos, - start_pos + forward * self.beam_range, + start_pos + forward * this.beam_range, MOVE_NOMONSTERS, - self + this ); // untransform in case our trace went through a warpzone vector end_pos = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos); // un-adjust trueaim if shotend is too close - if(vlen(end_pos - start_pos) < g_trueaim_minrange) + if(vdist(end_pos - start_pos, <, g_trueaim_minrange)) end_pos = start_pos + (forward * g_trueaim_minrange); // move shot origin to the actual gun muzzle origin vector origin_offset = - right * -self.beam_shotorigin.y - + up * self.beam_shotorigin.z; + right * -this.beam_shotorigin.y + + up * this.beam_shotorigin.z; start_pos = start_pos + origin_offset; // Move it also forward, but only as far as possible without hitting anything. Don't poke into walls! - traceline(start_pos, start_pos + forward * self.beam_shotorigin.x, MOVE_NORMAL, self); + traceline(start_pos, start_pos + forward * this.beam_shotorigin.x, MOVE_NORMAL, this); start_pos = trace_endpos; // calculate the aim direction now wantdir = normalize(end_pos - start_pos); - if(!self.beam_initialized) + if(!this.beam_initialized) { - self.beam_dir = wantdir; - self.beam_initialized = true; + this.beam_dir = wantdir; + this.beam_initialized = true; } - if(self.beam_dir != wantdir) + if(this.beam_dir != wantdir) { // calculate how much we're going to move the end of the beam to the want position // WEAPONTODO (server and client): // blendfactor never actually becomes 0 in this situation, which is a problem - // regarding precision... this means that self.beam_dir and w_shotdir approach + // regarding precision... this means that this.beam_dir and w_shotdir approach // eachother, however they never actually become the same value with this method. // Perhaps we should do some form of rounding/snapping? - float angle = vlen(wantdir - self.beam_dir) * RAD2DEG; - if(angle && (angle > self.beam_maxangle)) + float angle = vlen(wantdir - this.beam_dir) * RAD2DEG; + if(angle && (angle > this.beam_maxangle)) { // if the angle is greater than maxangle, force the blendfactor to make this the maximum factor float blendfactor = bound( 0, - (1 - (self.beam_returnspeed * frametime)), - min(self.beam_maxangle / angle, 1) + (1 - (this.beam_returnspeed * frametime)), + min(this.beam_maxangle / angle, 1) ); - self.beam_dir = normalize((wantdir * (1 - blendfactor)) + (self.beam_dir * blendfactor)); + this.beam_dir = normalize((wantdir * (1 - blendfactor)) + (this.beam_dir * blendfactor)); } else { // the radius is not too far yet, no worries :D float blendfactor = bound( 0, - (1 - (self.beam_returnspeed * frametime)), + (1 - (this.beam_returnspeed * frametime)), 1 ); - self.beam_dir = normalize((wantdir * (1 - blendfactor)) + (self.beam_dir * blendfactor)); + this.beam_dir = normalize((wantdir * (1 - blendfactor)) + (this.beam_dir * blendfactor)); } // calculate how many segments are needed float max_allowed_segments; - if(self.beam_distancepersegment) + if(this.beam_distancepersegment) { max_allowed_segments = min( ARC_MAX_SEGMENTS, - 1 + (vlen(wantdir / self.beam_distancepersegment)) + 1 + (vlen(wantdir / this.beam_distancepersegment)) ); } else { max_allowed_segments = ARC_MAX_SEGMENTS; } - if(self.beam_degreespersegment) + if(this.beam_degreespersegment) { segments = bound( 1, ( min( angle, - self.beam_maxangle + this.beam_maxangle ) / - self.beam_degreespersegment + this.beam_degreespersegment ), max_allowed_segments ); @@ -986,17 +1121,17 @@ void Draw_ArcBeam(entity this) else { segments = 1; } // set the beam direction which the rest of the code will refer to - beamdir = self.beam_dir; + beamdir = this.beam_dir; - // finally, set self.angles to the proper direction so that muzzle attachment points in proper direction - self.angles = fixedvectoangles2(forward, up); // TODO(Samual): is this == warpzone_save_view_angles? + // finally, set this.angles to the proper direction so that muzzle attachment points in proper direction + this.angles = fixedvectoangles2(forward, up); // TODO(Samual): is this == warpzone_save_view_angles? } else { // set the values from the provided info from the networked entity - start_pos = self.origin; - wantdir = self.v_angle; - beamdir = self.angles; + start_pos = this.origin; + wantdir = this.v_angle; + beamdir = this.angles; if(beamdir != wantdir) { @@ -1005,26 +1140,26 @@ void Draw_ArcBeam(entity this) // calculate how many segments are needed float max_allowed_segments; - if(self.beam_distancepersegment) + if(this.beam_distancepersegment) { max_allowed_segments = min( ARC_MAX_SEGMENTS, - 1 + (vlen(wantdir / self.beam_distancepersegment)) + 1 + (vlen(wantdir / this.beam_distancepersegment)) ); } else { max_allowed_segments = ARC_MAX_SEGMENTS; } - if(self.beam_degreespersegment) + if(this.beam_degreespersegment) { segments = bound( 1, ( min( angle, - self.beam_maxangle + this.beam_maxangle ) / - self.beam_degreespersegment + this.beam_degreespersegment ), max_allowed_segments ); @@ -1034,13 +1169,13 @@ void Draw_ArcBeam(entity this) else { segments = 1; } } - setorigin(self, start_pos); - self.beam_muzzleentity.angles_z = random() * 360; // WEAPONTODO: use avelocity instead? + setorigin(this, start_pos); + this.beam_muzzleentity.angles_z = random() * 360; // WEAPONTODO: use avelocity instead? - vector beam_endpos = (start_pos + (beamdir * self.beam_range)); - vector beam_controlpoint = start_pos + wantdir * (self.beam_range * (1 - self.beam_tightness)); + vector beam_endpos = (start_pos + (beamdir * this.beam_range)); + vector beam_controlpoint = start_pos + wantdir * (this.beam_range * (1 - this.beam_tightness)); - Draw_ArcBeam_callback_entity = self; + Draw_ArcBeam_callback_entity = this; Draw_ArcBeam_callback_last_thickness = 0; Draw_ArcBeam_callback_last_top = start_pos; Draw_ArcBeam_callback_last_bottom = start_pos; @@ -1069,8 +1204,8 @@ void Draw_ArcBeam(entity this) '0 0 0', new_origin, MOVE_NORMAL, - world, - world, + NULL, + NULL, Draw_ArcBeam_callback ); @@ -1088,64 +1223,64 @@ void Draw_ArcBeam(entity this) } // visual effects for startpoint and endpoint - if(self.beam_hiteffect) + if(this.beam_hiteffect) { // FIXME we really should do this on the server so it actually // matches gameplay. What this client side stuff is doing is no // more than guesswork. if((trace_ent || trace_fraction < 1) && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)) pointparticles( - self.beam_hiteffect, + this.beam_hiteffect, last_origin, beamdir * -1, frametime * 2 ); } - if(self.beam_hitlight[0]) + if(this.beam_hitlight[0]) { adddynamiclight( last_origin, - self.beam_hitlight[0], + this.beam_hitlight[0], vec3( - self.beam_hitlight[1], - self.beam_hitlight[2], - self.beam_hitlight[3] + this.beam_hitlight[1], + this.beam_hitlight[2], + this.beam_hitlight[3] ) ); } - if(self.beam_muzzleeffect) + if(this.beam_muzzleeffect) { pointparticles( - self.beam_muzzleeffect, + this.beam_muzzleeffect, original_start_pos + wantdir * 20, wantdir * 1000, frametime * 0.1 ); } - if(self.beam_muzzlelight[0]) + if(this.beam_muzzlelight[0]) { adddynamiclight( original_start_pos + wantdir * 20, - self.beam_muzzlelight[0], + this.beam_muzzlelight[0], vec3( - self.beam_muzzlelight[1], - self.beam_muzzlelight[2], - self.beam_muzzlelight[3] + this.beam_muzzlelight[1], + this.beam_muzzlelight[2], + this.beam_muzzlelight[3] ) ); } // cleanup - Draw_ArcBeam_callback_entity = world; + Draw_ArcBeam_callback_entity = NULL; Draw_ArcBeam_callback_last_thickness = 0; Draw_ArcBeam_callback_last_top = '0 0 0'; Draw_ArcBeam_callback_last_bottom = '0 0 0'; } -void Remove_ArcBeam() -{SELFPARAM(); - remove(self.beam_muzzleentity); - sound(self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM); +void Remove_ArcBeam(entity this) +{ + remove(this.beam_muzzleentity); + sound(this, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM); } NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew) @@ -1155,306 +1290,310 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew) if(isnew) { - int gunalign = W_GetGunAlignment(world); + int gunalign = W_GetGunAlignment(NULL); - self.beam_shotorigin = arc_shotorigin[gunalign]; + this.beam_shotorigin = arc_shotorigin[gunalign]; // set other main attributes of the beam - self.draw = Draw_ArcBeam; - self.entremove = Remove_ArcBeam; - self.move_time = time; - loopsound(self, CH_SHOTS_SINGLE, SND(ARC_LOOP), VOL_BASE, ATTEN_NORM); + this.draw = Draw_ArcBeam; + this.entremove = Remove_ArcBeam; + this.move_time = time; + loopsound(this, CH_SHOTS_SINGLE, SND(ARC_LOOP), VOL_BASE, ATTEN_NORM); flash = spawn(); - flash.owner = self; + flash.owner = this; flash.effects = EF_ADDITIVE | EF_FULLBRIGHT; flash.drawmask = MASK_NORMAL; flash.solid = SOLID_NOT; flash.avelocity_z = 5000; - setattachment(flash, self, ""); + setattachment(flash, this, ""); setorigin(flash, '0 0 0'); - self.beam_muzzleentity = flash; + this.beam_muzzleentity = flash; } else { - flash = self.beam_muzzleentity; + flash = this.beam_muzzleentity; } if(sf & ARC_SF_SETTINGS) // settings information { - self.beam_degreespersegment = ReadShort(); - self.beam_distancepersegment = ReadShort(); - self.beam_maxangle = ReadShort(); - self.beam_range = ReadCoord(); - self.beam_returnspeed = ReadShort(); - self.beam_tightness = (ReadByte() / 10); + this.beam_degreespersegment = ReadShort(); + this.beam_distancepersegment = ReadShort(); + this.beam_maxangle = ReadShort(); + this.beam_range = ReadCoord(); + this.beam_returnspeed = ReadShort(); + this.beam_tightness = (ReadByte() / 10); if(ReadByte()) { if(autocvar_chase_active) - { self.beam_usevieworigin = 1; } + { this.beam_usevieworigin = 1; } else // use view origin - { self.beam_usevieworigin = 2; } + { this.beam_usevieworigin = 2; } } else { - self.beam_usevieworigin = 0; + this.beam_usevieworigin = 0; } + + this.sv_entnum = ReadByte(); } - if(!self.beam_usevieworigin) + if(!this.beam_usevieworigin) { - // self.iflags = IFLAG_ORIGIN | IFLAG_ANGLES | IFLAG_V_ANGLE; // why doesn't this work? - self.iflags = IFLAG_ORIGIN; + // this.iflags = IFLAG_ORIGIN | IFLAG_ANGLES | IFLAG_V_ANGLE; // why doesn't this work? + this.iflags = IFLAG_ORIGIN; - InterpolateOrigin_Undo(self); + InterpolateOrigin_Undo(this); } if(sf & ARC_SF_START) // starting location { - self.origin_x = ReadCoord(); - self.origin_y = ReadCoord(); - self.origin_z = ReadCoord(); + this.origin_x = ReadCoord(); + this.origin_y = ReadCoord(); + this.origin_z = ReadCoord(); } - else if(self.beam_usevieworigin) // infer the location from player location + else if(this.beam_usevieworigin) // infer the location from player location { - if(self.beam_usevieworigin == 2) + if(this.beam_usevieworigin == 2) { // use view origin - self.origin = view_origin; + this.origin = view_origin; } else { // use player origin so that third person display still works - self.origin = entcs_receiver(player_localnum).origin + ('0 0 1' * getstati(STAT_VIEWHEIGHT)); + this.origin = entcs_receiver(player_localnum).origin + ('0 0 1' * STAT(VIEWHEIGHT)); } } - setorigin(self, self.origin); + setorigin(this, this.origin); if(sf & ARC_SF_WANTDIR) // want/aim direction { - self.v_angle_x = ReadCoord(); - self.v_angle_y = ReadCoord(); - self.v_angle_z = ReadCoord(); + this.v_angle_x = ReadCoord(); + this.v_angle_y = ReadCoord(); + this.v_angle_z = ReadCoord(); } if(sf & ARC_SF_BEAMDIR) // beam direction { - self.angles_x = ReadCoord(); - self.angles_y = ReadCoord(); - self.angles_z = ReadCoord(); + this.angles_x = ReadCoord(); + this.angles_y = ReadCoord(); + this.angles_z = ReadCoord(); } if(sf & ARC_SF_BEAMTYPE) // beam type { - self.beam_type = ReadByte(); - switch(self.beam_type) + this.beam_type = ReadByte(); + + vector beamcolor = ((autocvar_cl_arcbeam_teamcolor) ? colormapPaletteColor(stof(getplayerkeyvalue(this.sv_entnum - 1, "colors")) & 0x0F, true) : '1 1 1'); + switch(this.beam_type) { case ARC_BT_MISS: { - self.beam_color = '1 1 1'; - self.beam_alpha = 0.5; - self.beam_thickness = 8; - self.beam_traileffect = (EFFECT_ARC_BEAM); - self.beam_hiteffect = (EFFECT_ARC_LIGHTNING); - self.beam_hitlight[0] = 0; - self.beam_hitlight[1] = 1; - self.beam_hitlight[2] = 1; - self.beam_hitlight[3] = 1; - self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); - self.beam_muzzlelight[0] = 0; - self.beam_muzzlelight[1] = 1; - self.beam_muzzlelight[2] = 1; - self.beam_muzzlelight[3] = 1; - if(self.beam_muzzleeffect) + this.beam_color = beamcolor; + this.beam_alpha = 0.5; + this.beam_thickness = 8; + this.beam_traileffect = (EFFECT_ARC_BEAM); + this.beam_hiteffect = (EFFECT_ARC_LIGHTNING); + this.beam_hitlight[0] = 0; + this.beam_hitlight[1] = 1; + this.beam_hitlight[2] = 1; + this.beam_hitlight[3] = 1; + this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); + this.beam_muzzlelight[0] = 0; + this.beam_muzzlelight[1] = 1; + this.beam_muzzlelight[2] = 1; + this.beam_muzzlelight[3] = 1; + if(this.beam_muzzleeffect) { setmodel(flash, MDL_ARC_MUZZLEFLASH); - flash.alpha = self.beam_alpha; - flash.colormod = self.beam_color; + flash.alpha = this.beam_alpha; + flash.colormod = this.beam_color; flash.scale = 0.5; } break; } case ARC_BT_WALL: // grenadelauncher_muzzleflash healray_muzzleflash { - self.beam_color = '1 1 1'; - self.beam_alpha = 0.5; - self.beam_thickness = 8; - self.beam_traileffect = (EFFECT_ARC_BEAM); - self.beam_hiteffect = (EFFECT_ARC_LIGHTNING); - self.beam_hitlight[0] = 0; - self.beam_hitlight[1] = 1; - self.beam_hitlight[2] = 1; - self.beam_hitlight[3] = 1; - self.beam_muzzleeffect = NULL; // (EFFECT_GRENADE_MUZZLEFLASH); - self.beam_muzzlelight[0] = 0; - self.beam_muzzlelight[1] = 1; - self.beam_muzzlelight[2] = 1; - self.beam_muzzlelight[3] = 1; - self.beam_image = "particles/lgbeam"; - if(self.beam_muzzleeffect) + this.beam_color = beamcolor; + this.beam_alpha = 0.5; + this.beam_thickness = 8; + this.beam_traileffect = (EFFECT_ARC_BEAM); + this.beam_hiteffect = (EFFECT_ARC_LIGHTNING); + this.beam_hitlight[0] = 0; + this.beam_hitlight[1] = 1; + this.beam_hitlight[2] = 1; + this.beam_hitlight[3] = 1; + this.beam_muzzleeffect = NULL; // (EFFECT_GRENADE_MUZZLEFLASH); + this.beam_muzzlelight[0] = 0; + this.beam_muzzlelight[1] = 1; + this.beam_muzzlelight[2] = 1; + this.beam_muzzlelight[3] = 1; + this.beam_image = "particles/lgbeam"; + if(this.beam_muzzleeffect) { setmodel(flash, MDL_ARC_MUZZLEFLASH); - flash.alpha = self.beam_alpha; - flash.colormod = self.beam_color; + flash.alpha = this.beam_alpha; + flash.colormod = this.beam_color; flash.scale = 0.5; } break; } case ARC_BT_HEAL: { - self.beam_color = '1 1 1'; - self.beam_alpha = 0.5; - self.beam_thickness = 8; - self.beam_traileffect = (EFFECT_ARC_BEAM_HEAL); - self.beam_hiteffect = (EFFECT_ARC_BEAM_HEAL_IMPACT); - self.beam_hitlight[0] = 0; - self.beam_hitlight[1] = 1; - self.beam_hitlight[2] = 1; - self.beam_hitlight[3] = 1; - self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); - self.beam_muzzlelight[0] = 0; - self.beam_muzzlelight[1] = 1; - self.beam_muzzlelight[2] = 1; - self.beam_muzzlelight[3] = 1; - self.beam_image = "particles/lgbeam"; - if(self.beam_muzzleeffect) + this.beam_color = beamcolor; + this.beam_alpha = 0.5; + this.beam_thickness = 8; + this.beam_traileffect = (EFFECT_ARC_BEAM_HEAL); + this.beam_hiteffect = (EFFECT_ARC_BEAM_HEAL_IMPACT); + this.beam_hitlight[0] = 0; + this.beam_hitlight[1] = 1; + this.beam_hitlight[2] = 1; + this.beam_hitlight[3] = 1; + this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); + this.beam_muzzlelight[0] = 0; + this.beam_muzzlelight[1] = 1; + this.beam_muzzlelight[2] = 1; + this.beam_muzzlelight[3] = 1; + this.beam_image = "particles/lgbeam"; + if(this.beam_muzzleeffect) { setmodel(flash, MDL_ARC_MUZZLEFLASH); - flash.alpha = self.beam_alpha; - flash.colormod = self.beam_color; + flash.alpha = this.beam_alpha; + flash.colormod = this.beam_color; flash.scale = 0.5; } break; } case ARC_BT_HIT: { - self.beam_color = '1 1 1'; - self.beam_alpha = 0.5; - self.beam_thickness = 8; - self.beam_traileffect = (EFFECT_ARC_BEAM); - self.beam_hiteffect = (EFFECT_ARC_LIGHTNING); - self.beam_hitlight[0] = 20; - self.beam_hitlight[1] = 1; - self.beam_hitlight[2] = 0; - self.beam_hitlight[3] = 0; - self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); - self.beam_muzzlelight[0] = 50; - self.beam_muzzlelight[1] = 1; - self.beam_muzzlelight[2] = 0; - self.beam_muzzlelight[3] = 0; - self.beam_image = "particles/lgbeam"; - if(self.beam_muzzleeffect) + this.beam_color = beamcolor; + this.beam_alpha = 0.5; + this.beam_thickness = 8; + this.beam_traileffect = (EFFECT_ARC_BEAM); + this.beam_hiteffect = (EFFECT_ARC_LIGHTNING); + this.beam_hitlight[0] = 20; + this.beam_hitlight[1] = 1; + this.beam_hitlight[2] = 0; + this.beam_hitlight[3] = 0; + this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); + this.beam_muzzlelight[0] = 50; + this.beam_muzzlelight[1] = 1; + this.beam_muzzlelight[2] = 0; + this.beam_muzzlelight[3] = 0; + this.beam_image = "particles/lgbeam"; + if(this.beam_muzzleeffect) { setmodel(flash, MDL_ARC_MUZZLEFLASH); - flash.alpha = self.beam_alpha; - flash.colormod = self.beam_color; + flash.alpha = this.beam_alpha; + flash.colormod = this.beam_color; flash.scale = 0.5; } break; } case ARC_BT_BURST_MISS: { - self.beam_color = '1 1 1'; - self.beam_alpha = 0.5; - self.beam_thickness = 14; - self.beam_traileffect = (EFFECT_ARC_BEAM); - self.beam_hiteffect = (EFFECT_ARC_LIGHTNING); - self.beam_hitlight[0] = 0; - self.beam_hitlight[1] = 1; - self.beam_hitlight[2] = 1; - self.beam_hitlight[3] = 1; - self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); - self.beam_muzzlelight[0] = 0; - self.beam_muzzlelight[1] = 1; - self.beam_muzzlelight[2] = 1; - self.beam_muzzlelight[3] = 1; - self.beam_image = "particles/lgbeam"; - if(self.beam_muzzleeffect) + this.beam_color = beamcolor; + this.beam_alpha = 0.5; + this.beam_thickness = 14; + this.beam_traileffect = (EFFECT_ARC_BEAM); + this.beam_hiteffect = (EFFECT_ARC_LIGHTNING); + this.beam_hitlight[0] = 0; + this.beam_hitlight[1] = 1; + this.beam_hitlight[2] = 1; + this.beam_hitlight[3] = 1; + this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); + this.beam_muzzlelight[0] = 0; + this.beam_muzzlelight[1] = 1; + this.beam_muzzlelight[2] = 1; + this.beam_muzzlelight[3] = 1; + this.beam_image = "particles/lgbeam"; + if(this.beam_muzzleeffect) { setmodel(flash, MDL_ARC_MUZZLEFLASH); - flash.alpha = self.beam_alpha; - flash.colormod = self.beam_color; + flash.alpha = this.beam_alpha; + flash.colormod = this.beam_color; flash.scale = 0.5; } break; } case ARC_BT_BURST_WALL: { - self.beam_color = '1 1 1'; - self.beam_alpha = 0.5; - self.beam_thickness = 14; - self.beam_traileffect = (EFFECT_ARC_BEAM); - self.beam_hiteffect = (EFFECT_ARC_LIGHTNING); - self.beam_hitlight[0] = 0; - self.beam_hitlight[1] = 1; - self.beam_hitlight[2] = 1; - self.beam_hitlight[3] = 1; - self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); - self.beam_muzzlelight[0] = 0; - self.beam_muzzlelight[1] = 1; - self.beam_muzzlelight[2] = 1; - self.beam_muzzlelight[3] = 1; - self.beam_image = "particles/lgbeam"; - if(self.beam_muzzleeffect) + this.beam_color = beamcolor; + this.beam_alpha = 0.5; + this.beam_thickness = 14; + this.beam_traileffect = (EFFECT_ARC_BEAM); + this.beam_hiteffect = (EFFECT_ARC_LIGHTNING); + this.beam_hitlight[0] = 0; + this.beam_hitlight[1] = 1; + this.beam_hitlight[2] = 1; + this.beam_hitlight[3] = 1; + this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); + this.beam_muzzlelight[0] = 0; + this.beam_muzzlelight[1] = 1; + this.beam_muzzlelight[2] = 1; + this.beam_muzzlelight[3] = 1; + this.beam_image = "particles/lgbeam"; + if(this.beam_muzzleeffect) { setmodel(flash, MDL_ARC_MUZZLEFLASH); - flash.alpha = self.beam_alpha; - flash.colormod = self.beam_color; + flash.alpha = this.beam_alpha; + flash.colormod = this.beam_color; flash.scale = 0.5; } break; } case ARC_BT_BURST_HEAL: { - self.beam_color = '1 1 1'; - self.beam_alpha = 0.5; - self.beam_thickness = 14; - self.beam_traileffect = (EFFECT_ARC_BEAM_HEAL); - self.beam_hiteffect = (EFFECT_ARC_BEAM_HEAL_IMPACT2); - self.beam_hitlight[0] = 0; - self.beam_hitlight[1] = 1; - self.beam_hitlight[2] = 1; - self.beam_hitlight[3] = 1; - self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); - self.beam_muzzlelight[0] = 0; - self.beam_muzzlelight[1] = 1; - self.beam_muzzlelight[2] = 1; - self.beam_muzzlelight[3] = 1; - self.beam_image = "particles/lgbeam"; - if(self.beam_muzzleeffect) + this.beam_color = beamcolor; + this.beam_alpha = 0.5; + this.beam_thickness = 14; + this.beam_traileffect = (EFFECT_ARC_BEAM_HEAL); + this.beam_hiteffect = (EFFECT_ARC_BEAM_HEAL_IMPACT2); + this.beam_hitlight[0] = 0; + this.beam_hitlight[1] = 1; + this.beam_hitlight[2] = 1; + this.beam_hitlight[3] = 1; + this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); + this.beam_muzzlelight[0] = 0; + this.beam_muzzlelight[1] = 1; + this.beam_muzzlelight[2] = 1; + this.beam_muzzlelight[3] = 1; + this.beam_image = "particles/lgbeam"; + if(this.beam_muzzleeffect) { setmodel(flash, MDL_ARC_MUZZLEFLASH); - flash.alpha = self.beam_alpha; - flash.colormod = self.beam_color; + flash.alpha = this.beam_alpha; + flash.colormod = this.beam_color; flash.scale = 0.5; } break; } case ARC_BT_BURST_HIT: { - self.beam_color = '1 1 1'; - self.beam_alpha = 0.5; - self.beam_thickness = 14; - self.beam_traileffect = (EFFECT_ARC_BEAM); - self.beam_hiteffect = (EFFECT_ARC_LIGHTNING); - self.beam_hitlight[0] = 0; - self.beam_hitlight[1] = 1; - self.beam_hitlight[2] = 1; - self.beam_hitlight[3] = 1; - self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); - self.beam_muzzlelight[0] = 0; - self.beam_muzzlelight[1] = 1; - self.beam_muzzlelight[2] = 1; - self.beam_muzzlelight[3] = 1; - self.beam_image = "particles/lgbeam"; - if(self.beam_muzzleeffect) + this.beam_color = beamcolor; + this.beam_alpha = 0.5; + this.beam_thickness = 14; + this.beam_traileffect = (EFFECT_ARC_BEAM); + this.beam_hiteffect = (EFFECT_ARC_LIGHTNING); + this.beam_hitlight[0] = 0; + this.beam_hitlight[1] = 1; + this.beam_hitlight[2] = 1; + this.beam_hitlight[3] = 1; + this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); + this.beam_muzzlelight[0] = 0; + this.beam_muzzlelight[1] = 1; + this.beam_muzzlelight[2] = 1; + this.beam_muzzlelight[3] = 1; + this.beam_image = "particles/lgbeam"; + if(this.beam_muzzleeffect) { setmodel(flash, MDL_ARC_MUZZLEFLASH); - flash.alpha = self.beam_alpha; - flash.colormod = self.beam_color; + flash.alpha = this.beam_alpha; + flash.colormod = this.beam_color; flash.scale = 0.5; } break; @@ -1463,26 +1602,26 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew) // shouldn't be possible, but lets make it colorful if it does :D default: { - self.beam_color = randomvec(); - self.beam_alpha = 1; - self.beam_thickness = 8; - self.beam_traileffect = NULL; - self.beam_hiteffect = NULL; - self.beam_hitlight[0] = 0; - self.beam_hitlight[1] = 1; - self.beam_hitlight[2] = 1; - self.beam_hitlight[3] = 1; - self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); - self.beam_muzzlelight[0] = 0; - self.beam_muzzlelight[1] = 1; - self.beam_muzzlelight[2] = 1; - self.beam_muzzlelight[3] = 1; - self.beam_image = "particles/lgbeam"; - if(self.beam_muzzleeffect) + this.beam_color = randomvec(); + this.beam_alpha = 1; + this.beam_thickness = 8; + this.beam_traileffect = NULL; + this.beam_hiteffect = NULL; + this.beam_hitlight[0] = 0; + this.beam_hitlight[1] = 1; + this.beam_hitlight[2] = 1; + this.beam_hitlight[3] = 1; + this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH); + this.beam_muzzlelight[0] = 0; + this.beam_muzzlelight[1] = 1; + this.beam_muzzlelight[2] = 1; + this.beam_muzzlelight[3] = 1; + this.beam_image = "particles/lgbeam"; + if(this.beam_muzzleeffect) { setmodel(flash, MDL_ARC_MUZZLEFLASH); - flash.alpha = self.beam_alpha; - flash.colormod = self.beam_color; + flash.alpha = this.beam_alpha; + flash.colormod = this.beam_color; flash.scale = 0.5; } break; @@ -1490,7 +1629,7 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew) } } - if(!self.beam_usevieworigin) + if(!this.beam_usevieworigin) { InterpolateOrigin_Note(this); }