X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fweapons%2Fweapon%2Felectro.qc;h=3a70920e07839ed32bee603e7ec368c640b9bac2;hb=5ab697b0184201b9fb2fe49fb33699cbde5d7f18;hp=21a2f9b0128723b4d719acc46d3d20f852e2a569;hpb=3e6e644488b54b638078fb88b88c643e103ac8e1;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/weapons/weapon/electro.qc b/qcsrc/common/weapons/weapon/electro.qc index 21a2f9b01..3a70920e0 100644 --- a/qcsrc/common/weapons/weapon/electro.qc +++ b/qcsrc/common/weapons/weapon/electro.qc @@ -10,6 +10,13 @@ void W_Electro_TriggerCombo(vector org, float rad, entity own) { if(e.classname == "electro_orb") { + // check if the ball we are exploding is not owned by an + // independent player which is not the player who shot the ball + if(IS_INDEPENDENT_PLAYER(e.realowner) && own != e.realowner) + { + e = e.chain; + continue; + } // do we allow thruwall triggering? if(WEP_CVAR(electro, combo_comboradius_thruwall)) { @@ -35,16 +42,10 @@ void W_Electro_TriggerCombo(vector org, float rad, entity own) setthink(e, W_Electro_ExplodeCombo); // delay combo chains, looks cooler - e.nextthink = - ( - time - + - (WEP_CVAR(electro, combo_speed) ? - (vlen(e.WarpZone_findradius_dist) / WEP_CVAR(electro, combo_speed)) - : - 0 - ) - ); + float delay = 0; + if (WEP_CVAR(electro, combo_speed)) + delay = vlen(e.WarpZone_findradius_dist) / WEP_CVAR(electro, combo_speed); + e.nextthink = time + delay; } e = e.chain; } @@ -55,6 +56,7 @@ void W_Electro_ExplodeCombo(entity this) W_Electro_TriggerCombo(this.origin, WEP_CVAR(electro, combo_comboradius), this.realowner); this.event_damage = func_null; + this.velocity = this.movedir; // particle fx and decals need .velocity RadiusDamage( this, @@ -84,6 +86,7 @@ void W_Electro_Explode(entity this, entity directhitentity) this.event_damage = func_null; this.takedamage = DAMAGE_NO; + this.velocity = this.movedir; // particle fx and decals need .velocity if(this.move_movetype == MOVETYPE_BOUNCE || this.classname == "electro_orb") // TODO: classname is more reliable anyway? { @@ -134,7 +137,7 @@ void W_Electro_TouchExplode(entity this, entity toucher) } -void sys_phys_update_single(entity this); +//void sys_phys_update_single(entity this); void W_Electro_Bolt_Think(entity this) { @@ -155,6 +158,13 @@ void W_Electro_Bolt_Think(entity this) { if(e.classname == "electro_orb") { + // check if the ball we are exploding is not owned by an + // independent player which is not the player who shot the ball + if(IS_INDEPENDENT_PLAYER(e.realowner) && this.realowner != e.realowner) + { + e = e.chain; + continue; + } bool explode; if (this.owner == e.owner) { @@ -181,17 +191,10 @@ void W_Electro_Bolt_Think(entity this) // (the bolt and orb should explode together because they interacted together) // while keeping the chaining delay. setthink(e, W_Electro_ExplodeCombo); - e.nextthink = - ( - time - + - (WEP_CVAR_PRI(electro, midaircombo_speed) ? - (vlen(e.WarpZone_findradius_dist) / WEP_CVAR_PRI(electro, midaircombo_speed)) - : - 0 - ) - ); - + float delay = 0; + if (WEP_CVAR_PRI(electro, midaircombo_speed)) + delay = vlen(e.WarpZone_findradius_dist) / WEP_CVAR_PRI(electro, midaircombo_speed); + e.nextthink = time + delay; ++found; } @@ -261,6 +264,37 @@ void W_Electro_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity) // proj.com_phys_vel = proj.velocity; } +void W_Electro_Orb_Follow_Think(entity this) +{ + if (time > this.death_time) + { + adaptor_think2use_hittype_splash(this); + return; + } + if (this.move_movetype == MOVETYPE_FOLLOW) + { + int lost = LostMovetypeFollow(this); + if (lost == 2) + { + // FIXME if player disconnected, it isn't possible to drop the orb at player's origin + // see comment in LostMovetypeFollow implementation + delete(this); + return; + } + if (lost) + { + // drop the orb at the corpse's location + PROJECTILE_MAKETRIGGER(this); + set_movetype(this, MOVETYPE_TOSS); + + setthink(this, adaptor_think2use_hittype_splash); + this.nextthink = this.death_time; + return; + } + } + this.nextthink = time; +} + void W_Electro_Orb_Stick(entity this, entity to) { entity newproj = spawn(); @@ -271,10 +305,13 @@ void W_Electro_Orb_Stick(entity this, entity to) newproj.owner = this.owner; newproj.realowner = this.realowner; - setsize(newproj, this.mins, this.maxs); setorigin(newproj, this.origin); setmodel(newproj, MDL_PROJECTILE_ELECTRO); + setsize(newproj, this.mins, this.maxs); newproj.angles = vectoangles(-trace_plane_normal); // face against the surface + newproj.traileffectnum = _particleeffectnum(EFFECT_TR_NEXUIZPLASMA.eent_eff_name); + + newproj.movedir = -trace_plane_normal; newproj.takedamage = this.takedamage; newproj.damageforcescale = this.damageforcescale; @@ -289,24 +326,36 @@ void W_Electro_Orb_Stick(entity this, entity to) newproj.weaponentity_fld = this.weaponentity_fld; settouch(newproj, func_null); - setthink(newproj, getthink(this)); - newproj.nextthink = this.nextthink; + if(WEP_CVAR_SEC(electro, stick_lifetime) > 0){ + newproj.death_time = time + WEP_CVAR_SEC(electro, stick_lifetime); + }else{ + newproj.death_time = this.death_time; + } newproj.use = this.use; newproj.flags = this.flags; IL_PUSH(g_projectiles, newproj); IL_PUSH(g_bot_dodge, newproj); // check if limits are enabled (we can tell by checking if the original orb is listed) and push it to the list if so - if(IL_CONTAINS(g_rubble, this)) + if(LimitedElectroBallRubbleList && IL_CONTAINS(LimitedElectroBallRubbleList, this)) { - newproj.creationtime = this.creationtime; - IL_PUSH(g_rubble, newproj); + ReplaceOldListedChildRubble(LimitedElectroBallRubbleList, newproj, this); } delete(this); if(to) + { SetMovetypeFollow(newproj, to); + + setthink(newproj, W_Electro_Orb_Follow_Think); + newproj.nextthink = time; + } + else + { + setthink(newproj, adaptor_think2use_hittype_splash); + newproj.nextthink = newproj.death_time; + } } void W_Electro_Orb_Touch(entity this, entity toucher) @@ -320,8 +369,13 @@ void W_Electro_Orb_Touch(entity this, entity toucher) spamsound(this, CH_SHOTS, SND_ELECTRO_BOUNCE, VOL_BASE, ATTEN_NORM); this.projectiledeathtype |= HITTYPE_BOUNCE; - if(WEP_CVAR_SEC(electro, stick)) - W_Electro_Orb_Stick(this, toucher); + if(WEP_CVAR_SEC(electro, stick)){ + if(WEP_CVAR_SEC(electro, stick_lifetime) == 0){ + W_Electro_Explode(this, toucher); + } else { + W_Electro_Orb_Stick(this, toucher); + } + } } } @@ -347,17 +401,11 @@ void W_Electro_Orb_Damage(entity this, entity inflictor, entity attacker, float this.realowner = inflictor.realowner; this.classname = "electro_orb_chain"; setthink(this, W_Electro_ExplodeCombo); - this.nextthink = time + - ( - // bound the length, inflictor may be in a galaxy far far away (warpzones) - min( - WEP_CVAR(electro, combo_radius), - vlen(this.origin - inflictor.origin) - ) - / - // delay combo chains, looks cooler - WEP_CVAR(electro, combo_speed) - ); + // delay combo chains, looks cooler + // bound the length, inflictor may be in a galaxy far far away (warpzones) + float len = min(WEP_CVAR(electro, combo_radius), vlen(this.origin - inflictor.origin)); + float delay = len / WEP_CVAR(electro, combo_speed); + this.nextthink = time + delay; } else { @@ -395,6 +443,7 @@ void W_Electro_Attack_Orb(Weapon thiswep, entity actor, .entity weaponentity) proj.bot_dodge = true; proj.bot_dodgerating = WEP_CVAR_SEC(electro, damage); proj.nextthink = time + WEP_CVAR_SEC(electro, lifetime); + proj.death_time = time + WEP_CVAR_SEC(electro, lifetime); PROJECTILE_MAKETRIGGER(proj); proj.projectiledeathtype = thiswep.m_id | HITTYPE_SECONDARY; proj.weaponentity_fld = weaponentity; @@ -423,8 +472,10 @@ void W_Electro_Attack_Orb(Weapon thiswep, entity actor, .entity weaponentity) if(WEP_CVAR_SEC(electro, limit) > 0) { - RubbleNew(proj); - RubbleLimit("electro_orb", WEP_CVAR_SEC(electro, limit), adaptor_think2use_hittype_splash); + if (!LimitedElectroBallRubbleList) + LimitedElectroBallRubbleList = IL_NEW(); + ListNewChildRubble(LimitedElectroBallRubbleList, proj); + LimitedChildrenRubble(LimitedElectroBallRubbleList, "electro_orb", WEP_CVAR_SEC(electro, limit), adaptor_think2use_hittype_splash, actor); } CSQCProjectile(proj, true, PROJECTILE_ELECTRO, false); // no culling, it has sound @@ -440,10 +491,10 @@ void W_Electro_CheckAttack(Weapon thiswep, entity actor, .entity weaponentity, i { W_Electro_Attack_Orb(thiswep, actor, weaponentity); actor.(weaponentity).electro_count -= 1; + actor.(weaponentity).electro_secondarytime = time; weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack); return; } - // WEAPONTODO: when the player releases the button, cut down the length of refire2? w_ready(thiswep, actor, weaponentity, fire); } @@ -496,21 +547,22 @@ METHOD(Electro, wr_think, void(entity thiswep, entity actor, .entity weaponentit if(fire & 1) { + if(time >= actor.(weaponentity).electro_secondarytime + WEP_CVAR_SEC(electro, refire2) * W_WeaponRateFactor(actor)) if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) { - W_Electro_Attack_Bolt(thiswep, actor, weaponentity); - weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); + W_Electro_Attack_Bolt(thiswep, actor, weaponentity); + weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); } } else if(fire & 2) { - if(time >= actor.(weaponentity).electro_secondarytime) - if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(electro, refire))) + if(time >= actor.(weaponentity).electro_secondarytime + WEP_CVAR_SEC(electro, refire) * W_WeaponRateFactor(actor)) + if(weapon_prepareattack(thiswep, actor, weaponentity, true, -1)) { W_Electro_Attack_Orb(thiswep, actor, weaponentity); actor.(weaponentity).electro_count = WEP_CVAR_SEC(electro, count); + actor.(weaponentity).electro_secondarytime = time; weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack); - actor.(weaponentity).electro_secondarytime = time + WEP_CVAR_SEC(electro, refire2) * W_WeaponRateFactor(actor); } } } @@ -535,14 +587,6 @@ METHOD(Electro, wr_checkammo2, bool(entity thiswep, entity actor, .entity weapon } return ammo_amount; } -METHOD(Electro, wr_resetplayer, void(entity thiswep, entity actor)) -{ - for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - { - .entity weaponentity = weaponentities[slot]; - actor.(weaponentity).electro_secondarytime = time; - } -} METHOD(Electro, wr_reload, void(entity thiswep, entity actor, .entity weaponentity)) { W_Reload(actor, weaponentity, min(WEP_CVAR_PRI(electro, ammo), WEP_CVAR_SEC(electro, ammo)), SND_RELOAD);