X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fweapons%2Fweapon%2Farc.qc;h=6ac3e9274d9b88df0648c2474b551d1a8f5e165d;hb=9f70bdba9a6fb2c06324be13504341da967f7028;hp=ba36d8fc98c9c05eaeb82d1983b13e7ef6f35faa;hpb=068324d293df795dbc41de75f38256b8c6c35607;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/weapons/weapon/arc.qc b/qcsrc/common/weapons/weapon/arc.qc index ba36d8fc9..6ac3e9274 100644 --- a/qcsrc/common/weapons/weapon/arc.qc +++ b/qcsrc/common/weapons/weapon/arc.qc @@ -17,6 +17,18 @@ CLASS(Arc, Weapon) #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) \ @@ -45,6 +57,7 @@ CLASS(Arc, Weapon) 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) \ @@ -156,6 +169,7 @@ 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 { @@ -217,6 +231,77 @@ void Arc_Player_SetHeat(entity player) //dprint("Heat: ",ftos(player.arc_heat_percent*100),"%\n"); } +void W_Arc_Bolt_Explode() +{SELFPARAM(); + self.event_damage = func_null; + RadiusDamage(self, self.realowner, WEP_CVAR(arc, bolt_damage), WEP_CVAR(arc, bolt_edgedamage), WEP_CVAR(arc, bolt_radius), world, world, WEP_CVAR(arc, bolt_force), self.projectiledeathtype, other); + + remove(self); +} + +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) + WITH(entity, self, this, W_PrepareExplosionByDamage(attacker, this.think)); +} + +void W_Arc_Bolt_Touch() +{SELFPARAM(); + PROJECTILE_TOUCH; + self.use(); +} + +void W_Arc_Attack_Bolt(Weapon thiswep) +{SELFPARAM(); + entity missile; + + W_DecreaseAmmo(thiswep, self, WEP_CVAR(arc, bolt_ammo)); + + W_SetupShot(self, 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 = self; + 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; + + missile.touch = W_Arc_Bolt_Touch; + missile.use = W_Arc_Bolt_Explode; + missile.think = 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'); + + missile.movetype = 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, self, missile); +} + void W_Arc_Beam_Think() {SELFPARAM(); if(self != self.owner.arc_beam) @@ -227,7 +312,7 @@ void W_Arc_Beam_Think() float burst = 0; - if( self.owner.BUTTON_ATCK2 || self.beam_bursting) + if( (PHYS_INPUT_BUTTON_ATCK2(self.owner) && !WEP_CVAR(arc, bolt)) || self.beam_bursting) { if(!self.beam_bursting) self.beam_bursting = true; @@ -243,7 +328,9 @@ void W_Arc_Beam_Think() || IS_DEAD(self.owner) || - (!self.owner.BUTTON_ATCK && !burst ) + gameover + || + (!PHYS_INPUT_BUTTON_ATCK(self.owner) && !burst ) || STAT(FROZEN, self.owner) || @@ -266,7 +353,8 @@ void W_Arc_Beam_Think() if ( cooldown_speed ) { - self.owner.arc_overheat = time + self.beam_heat / cooldown_speed; + if ( WEP_CVAR(arc, cooldown_release) || (WEP_CVAR(arc, overheat_max) > 0 && self.beam_heat >= WEP_CVAR(arc, overheat_max)) ) + self.owner.arc_overheat = time + self.beam_heat / cooldown_speed; self.owner.arc_cooldown = cooldown_speed; } @@ -612,7 +700,7 @@ void Arc_Smoke() { if ( random() < self.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(self) || PHYS_INPUT_BUTTON_ATCK2(self) ) { Send_Effect(EFFECT_ARC_OVERHEAT_FIRE, smoke_origin, w_shotdir, 1 ); if ( !self.arc_smoke_sound ) @@ -631,134 +719,167 @@ void Arc_Smoke() } if ( self.arc_smoke_sound && ( self.arc_overheat <= time || - !( self.BUTTON_ATCK || self.BUTTON_ATCK2 ) ) || PS(self).m_switchweapon != WEP_ARC ) + !( PHYS_INPUT_BUTTON_ATCK(self) || PHYS_INPUT_BUTTON_ATCK2(self) ) ) || PS(self).m_switchweapon != WEP_ARC ) { self.arc_smoke_sound = 0; sound(self, 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); - } - } - METHOD(Arc, wr_checkammo1, bool(entity thiswep)) - { - SELFPARAM(); - return ((!WEP_CVAR(arc, beam_ammo)) || (self.(thiswep.ammo_field) > 0)); - } - METHOD(Arc, wr_checkammo2, bool(entity thiswep)) - { - SELFPARAM(); - return WEP_CVAR(arc, overheat_max) > 0 && - ((!WEP_CVAR(arc, burst_ammo)) || (self.(thiswep.ammo_field) > 0)); - } - 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)) +{ + SELFPARAM(); + if(WEP_CVAR(arc, beam_botaimspeed)) + { + PHYS_INPUT_BUTTON_ATCK(self) = bot_aim( + WEP_CVAR(arc, beam_botaimspeed), + 0, + WEP_CVAR(arc, beam_botaimlifetime), + false + ); + } + else + { + PHYS_INPUT_BUTTON_ATCK(self) = 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(); + + 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)); + + 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); + 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.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); + } +} +METHOD(Arc, wr_checkammo1, bool(entity thiswep)) +{ + SELFPARAM(); + return ((!WEP_CVAR(arc, beam_ammo)) || (self.(thiswep.ammo_field) > 0)); +} +METHOD(Arc, wr_checkammo2, bool(entity thiswep)) +{ + SELFPARAM(); + if(WEP_CVAR(arc, bolt)) + { + float ammo_amount = self.(thiswep.ammo_field) >= WEP_CVAR(arc, bolt_ammo); + ammo_amount += self.(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)) || (self.(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)) +{ + 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; + } +} #endif #ifdef CSQC +bool autocvar_cl_arcbeam_teamcolor = true; + +METHOD(Arc, wr_impacteffect, void(entity thiswep)) +{ + 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(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTN_NORM); } + } +} + void Draw_ArcBeam_callback(vector start, vector hit, vector end) { entity beam = Draw_ArcBeam_callback_entity; @@ -1202,6 +1323,8 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew) { self.beam_usevieworigin = 0; } + + self.sv_entnum = ReadByte(); } if(!self.beam_usevieworigin) @@ -1251,11 +1374,13 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew) if(sf & ARC_SF_BEAMTYPE) // beam type { self.beam_type = ReadByte(); + + vector beamcolor = ((autocvar_cl_arcbeam_teamcolor) ? colormapPaletteColor(stof(getplayerkeyvalue(self.sv_entnum - 1, "colors")) & 0x0F, true) : '1 1 1'); switch(self.beam_type) { case ARC_BT_MISS: { - self.beam_color = '1 1 1'; + self.beam_color = beamcolor; self.beam_alpha = 0.5; self.beam_thickness = 8; self.beam_traileffect = (EFFECT_ARC_BEAM); @@ -1280,7 +1405,7 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew) } case ARC_BT_WALL: // grenadelauncher_muzzleflash healray_muzzleflash { - self.beam_color = '1 1 1'; + self.beam_color = beamcolor; self.beam_alpha = 0.5; self.beam_thickness = 8; self.beam_traileffect = (EFFECT_ARC_BEAM); @@ -1306,7 +1431,7 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew) } case ARC_BT_HEAL: { - self.beam_color = '1 1 1'; + self.beam_color = beamcolor; self.beam_alpha = 0.5; self.beam_thickness = 8; self.beam_traileffect = (EFFECT_ARC_BEAM_HEAL); @@ -1332,7 +1457,7 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew) } case ARC_BT_HIT: { - self.beam_color = '1 1 1'; + self.beam_color = beamcolor; self.beam_alpha = 0.5; self.beam_thickness = 8; self.beam_traileffect = (EFFECT_ARC_BEAM); @@ -1358,7 +1483,7 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew) } case ARC_BT_BURST_MISS: { - self.beam_color = '1 1 1'; + self.beam_color = beamcolor; self.beam_alpha = 0.5; self.beam_thickness = 14; self.beam_traileffect = (EFFECT_ARC_BEAM); @@ -1384,7 +1509,7 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew) } case ARC_BT_BURST_WALL: { - self.beam_color = '1 1 1'; + self.beam_color = beamcolor; self.beam_alpha = 0.5; self.beam_thickness = 14; self.beam_traileffect = (EFFECT_ARC_BEAM); @@ -1410,7 +1535,7 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew) } case ARC_BT_BURST_HEAL: { - self.beam_color = '1 1 1'; + self.beam_color = beamcolor; self.beam_alpha = 0.5; self.beam_thickness = 14; self.beam_traileffect = (EFFECT_ARC_BEAM_HEAL); @@ -1436,7 +1561,7 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew) } case ARC_BT_BURST_HIT: { - self.beam_color = '1 1 1'; + self.beam_color = beamcolor; self.beam_alpha = 0.5; self.beam_thickness = 14; self.beam_traileffect = (EFFECT_ARC_BEAM);