X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fweapons%2Fweapon%2Fdevastator.qc;h=f4ef7ad32c08b320d139348908b42e7c95cb54bb;hb=002be87cfe10ccbfedaf09eec48a1c78b10f8476;hp=7e63e760ec96d4d879a6813e6e436232aef965f2;hpb=9f5143f10e9edfe86851589a1c4b8db0cdd4bdb4;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/weapons/weapon/devastator.qc b/qcsrc/common/weapons/weapon/devastator.qc index 7e63e760e..997f6eb36 100644 --- a/qcsrc/common/weapons/weapon/devastator.qc +++ b/qcsrc/common/weapons/weapon/devastator.qc @@ -1,90 +1,16 @@ #include "devastator.qh" -#ifndef IMPLEMENTATION -CLASS(Devastator, Weapon) -/* ammotype */ ATTRIB(Devastator, ammo_field, .int, ammo_rockets); -/* impulse */ ATTRIB(Devastator, impulse, int, 9); -/* flags */ ATTRIB(Devastator, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH); -/* rating */ ATTRIB(Devastator, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH); -/* color */ ATTRIB(Devastator, wpcolor, vector, '1 1 0'); -/* modelname */ ATTRIB(Devastator, mdl, string, "rl"); -#ifdef GAMEQC -/* model */ ATTRIB(Devastator, m_model, Model, MDL_DEVASTATOR_ITEM); -#endif -/* crosshair */ ATTRIB(Devastator, w_crosshair, string, "gfx/crosshairrocketlauncher"); -/* crosshair */ ATTRIB(Devastator, w_crosshair_size, float, 0.7); -/* wepimg */ ATTRIB(Devastator, model2, string, "weaponrocketlauncher"); -/* refname */ ATTRIB(Devastator, netname, string, "devastator"); -/* wepname */ ATTRIB(Devastator, m_name, string, _("Devastator")); - -#define X(BEGIN, P, END, class, prefix) \ - BEGIN(class) \ - P(class, prefix, ammo, float, NONE) \ - P(class, prefix, animtime, float, NONE) \ - P(class, prefix, damageforcescale, float, NONE) \ - P(class, prefix, damage, float, NONE) \ - P(class, prefix, detonatedelay, float, NONE) \ - P(class, prefix, edgedamage, float, NONE) \ - P(class, prefix, force, float, NONE) \ - P(class, prefix, guidedelay, float, NONE) \ - P(class, prefix, guidegoal, float, NONE) \ - P(class, prefix, guideratedelay, float, NONE) \ - P(class, prefix, guiderate, float, NONE) \ - P(class, prefix, guidestop, float, NONE) \ - P(class, prefix, health, float, NONE) \ - P(class, prefix, lifetime, float, NONE) \ - P(class, prefix, radius, float, NONE) \ - P(class, prefix, refire, float, NONE) \ - P(class, prefix, reload_ammo, float, NONE) \ - P(class, prefix, reload_time, float, NONE) \ - P(class, prefix, remote_damage, float, NONE) \ - P(class, prefix, remote_edgedamage, float, NONE) \ - P(class, prefix, remote_force, float, NONE) \ - P(class, prefix, remote_jump_damage, float, NONE) \ - P(class, prefix, remote_jump_force, float, NONE) \ - P(class, prefix, remote_jump_radius, float, NONE) \ - P(class, prefix, remote_jump_velocity_z_add, float, NONE) \ - P(class, prefix, remote_jump_velocity_z_max, float, NONE) \ - P(class, prefix, remote_jump_velocity_z_min, float, NONE) \ - P(class, prefix, remote_radius, float, NONE) \ - P(class, prefix, speedaccel, float, NONE) \ - P(class, prefix, speedstart, float, NONE) \ - P(class, prefix, speed, float, NONE) \ - 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, Devastator, devastator) -#undef X - -ENDCLASS(Devastator) -REGISTER_WEAPON(DEVASTATOR, devastator, NEW(Devastator)); #ifdef SVQC -.float rl_release[MAX_WEAPONSLOTS]; -.float rl_detonate_later; -#endif -#endif -#ifdef IMPLEMENTATION -#ifdef SVQC -spawnfunc(weapon_devastator) { weapon_defaultspawnfunc(this, WEP_DEVASTATOR); } -spawnfunc(weapon_rocketlauncher) { spawnfunc_weapon_devastator(this); } .entity lastrocket; void W_Devastator_Unregister(entity this) { - if(this.realowner && this.realowner.lastrocket == this) + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { - for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - { - .entity weaponentity = weaponentities[slot]; - if(this.realowner.(weaponentity).lastrocket == this) - this.realowner.(weaponentity).lastrocket = NULL; - } - // this.realowner.rl_release = 1; + .entity weaponentity = weaponentities[slot]; + if(this.realowner.(weaponentity).lastrocket == this) + this.realowner.(weaponentity).lastrocket = NULL; } } @@ -112,19 +38,20 @@ void W_Devastator_Explode(entity this, entity directhitentity) NULL, WEP_CVAR(devastator, force), this.projectiledeathtype, + this.weaponentity_fld, directhitentity ); Weapon thiswep = WEP_DEVASTATOR; - if(PS(this.realowner).m_weapon == thiswep) + .entity weaponentity = this.weaponentity_fld; + if(this.realowner.(weaponentity).m_weapon == thiswep) { - if(this.realowner.(thiswep.ammo_field) < WEP_CVAR(devastator, ammo)) - if(!(this.realowner.items & IT_UNLIMITED_WEAPON_AMMO)) + if(GetResource(this.realowner, thiswep.ammo_type) < WEP_CVAR(devastator, ammo)) + if(!(this.realowner.items & IT_UNLIMITED_AMMO)) { - this.realowner.cnt = WEP_DEVASTATOR.m_id; - int slot = 0; // TODO: unhardcode - ATTACK_FINISHED(this.realowner, slot) = time; - PS(this.realowner).m_switchweapon = w_getbestweapon(this.realowner); + this.realowner.cnt = thiswep.m_id; + ATTACK_FINISHED(this.realowner, weaponentity) = time; + this.realowner.(weaponentity).m_switchweapon = w_getbestweapon(this.realowner, weaponentity); } } delete(this); @@ -144,8 +71,11 @@ void W_Devastator_DoRemoteExplode(entity this, .entity weaponentity) bool handled_as_rocketjump = false; entity head = NULL; + bool allow_rocketjump = WEP_CVAR(devastator, remote_jump); + MUTATOR_CALLHOOK(AllowRocketJumping, allow_rocketjump); + allow_rocketjump = M_ARGV(0, bool); - if(WEP_CVAR(devastator, remote_jump_radius)) + if(allow_rocketjump && WEP_CVAR(devastator, remote_jump_radius)) { head = WarpZone_FindRadius( this.origin, @@ -185,6 +115,7 @@ void W_Devastator_DoRemoteExplode(entity this, .entity weaponentity) head, (WEP_CVAR(devastator, remote_jump_force) ? WEP_CVAR(devastator, remote_jump_force) : 0), this.projectiledeathtype | HITTYPE_BOUNCE, + this.weaponentity_fld, NULL ); break; @@ -204,19 +135,19 @@ void W_Devastator_DoRemoteExplode(entity this, .entity weaponentity) NULL, WEP_CVAR(devastator, remote_force), this.projectiledeathtype | HITTYPE_BOUNCE, + this.weaponentity_fld, NULL ); Weapon thiswep = WEP_DEVASTATOR; - if(PS(this.realowner).m_weapon == thiswep) + if(this.realowner.(weaponentity).m_weapon == thiswep) { - if(this.realowner.(thiswep.ammo_field) < WEP_CVAR(devastator, ammo)) - if(!(this.realowner.items & IT_UNLIMITED_WEAPON_AMMO)) + if(GetResource(this.realowner, thiswep.ammo_type) < WEP_CVAR(devastator, ammo)) + if(!(this.realowner.items & IT_UNLIMITED_AMMO)) { - this.realowner.cnt = WEP_DEVASTATOR.m_id; - int slot = weaponslot(weaponentity); - ATTACK_FINISHED(this.realowner, slot) = time; - PS(this.realowner).m_switchweapon = w_getbestweapon(this.realowner); + this.realowner.cnt = thiswep.m_id; + ATTACK_FINISHED(this.realowner, weaponentity) = time; + this.realowner.(weaponentity).m_switchweapon = w_getbestweapon(this.realowner, weaponentity); } } delete(this); @@ -289,13 +220,11 @@ void W_Devastator_Think(entity this) this.velocity = this.velocity + v_forward * min(WEP_CVAR(devastator, speedaccel) * W_WeaponSpeedFactor(this.realowner) * frametime, velspeed); // laser guided, or remote detonation - if(PS(this.realowner).m_weapon == WEP_DEVASTATOR) + .entity weaponentity = this.weaponentity_fld; + if(this.realowner.(weaponentity).m_weapon == WEP_DEVASTATOR) { - .entity weaponentity = this.weaponentity_fld; - int slot = weaponslot(weaponentity); - if(this == this.realowner.(weaponentity).lastrocket) - if(!this.realowner.rl_release[slot]) + if(!this.realowner.(weaponentity).rl_release) if(!PHYS_INPUT_BUTTON_ATCK2(this)) if(WEP_CVAR(devastator, guiderate)) if(time > this.pushltime) @@ -307,11 +236,19 @@ void W_Devastator_Think(entity this) else f = 1; + vector md = this.realowner.(weaponentity).movedir; + vector vecs = ((md.x > 0) ? md : '0 0 0'); + + vector dv = v_right * -vecs.y + v_up * vecs.z; + + if(!W_DualWielding(this.realowner)) + dv = '0 0 0'; // don't override! + velspeed = vlen(this.velocity); makevectors(this.realowner.v_angle); desireddir = WarpZone_RefSys_TransformVelocity(this.realowner, this, v_forward); - desiredorigin = WarpZone_RefSys_TransformOrigin(this.realowner, this, this.realowner.origin + this.realowner.view_ofs); + desiredorigin = WarpZone_RefSys_TransformOrigin(this.realowner, this, this.realowner.origin + this.realowner.view_ofs + dv); olddir = normalize(this.velocity); // now it gets tricky... we want to move like some curve to approximate the target direction @@ -351,26 +288,26 @@ void W_Devastator_Touch(entity this, entity toucher) W_Devastator_Explode(this, toucher); } -void W_Devastator_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) +void W_Devastator_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force) { - if(this.health <= 0) + if(GetResource(this, RES_HEALTH) <= 0) return; if(!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) // no exceptions return; // g_projectiles_damage says to halt - this.health = this.health - damage; + TakeResource(this, RES_HEALTH, damage); this.angles = vectoangles(this.velocity); - if(this.health <= 0) + if(GetResource(this, RES_HEALTH) <= 0) W_PrepareExplosionByDamage(this, attacker, W_Devastator_Explode_think); } -void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity) +void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity, int fire) { - W_DecreaseAmmo(thiswep, actor, WEP_CVAR(devastator, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR(devastator, ammo), weaponentity); - W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 5, SND_ROCKET_FIRE, CH_WEAPON_A, WEP_CVAR(devastator, damage)); + W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 5, SND_ROCKET_FIRE, CH_WEAPON_A, WEP_CVAR(devastator, damage), thiswep.m_id); Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1); entity missile = WarpZone_RefSys_SpawnSameRefSys(actor); @@ -380,7 +317,7 @@ void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity) if(WEP_CVAR(devastator, detonatedelay) >= 0) missile.spawnshieldtime = time + WEP_CVAR(devastator, detonatedelay); else - missile.spawnshieldtime = -1; + missile.spawnshieldtime = -1; // NOTE: proximity based when rocket jumping missile.pushltime = time + WEP_CVAR(devastator, guidedelay); missile.classname = "rocket"; missile.bot_dodge = true; @@ -388,14 +325,14 @@ void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity) missile.takedamage = DAMAGE_YES; missile.damageforcescale = WEP_CVAR(devastator, damageforcescale); - missile.health = WEP_CVAR(devastator, health); + SetResourceExplicit(missile, RES_HEALTH, WEP_CVAR(devastator, health)); missile.event_damage = W_Devastator_Damage; missile.damagedbycontents = true; IL_PUSH(g_damagedbycontents, missile); set_movetype(missile, MOVETYPE_FLY); PROJECTILE_MAKETRIGGER(missile); - missile.projectiledeathtype = WEP_DEVASTATOR.m_id; + missile.projectiledeathtype = thiswep.m_id; setsize(missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot setorigin(missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point @@ -406,6 +343,7 @@ void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity) setthink(missile, W_Devastator_Think); missile.nextthink = time; missile.cnt = time + WEP_CVAR(devastator, lifetime); + missile.rl_detonate_later = (fire & 2); // allow instant detonation missile.flags = FL_PROJECTILE; IL_PUSH(g_projectiles, missile); IL_PUSH(g_bot_dodge, missile); @@ -422,12 +360,17 @@ void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity) // common properties MUTATOR_CALLHOOK(EditProjectile, actor, missile); + + if (time >= missile.nextthink) + { + getthink(missile)(missile); + } } -METHOD(Devastator, wr_aim, void(entity thiswep, entity actor)) +METHOD(Devastator, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { // aim and decide to fire if appropriate - PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, WEP_CVAR(devastator, speed), 0, WEP_CVAR(devastator, lifetime), false); + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(devastator, speed), 0, WEP_CVAR(devastator, lifetime), false); if(skill >= 2) // skill 0 and 1 bots won't detonate rockets! { // decide whether to detonate rockets @@ -458,7 +401,7 @@ METHOD(Devastator, wr_aim, void(entity thiswep, entity actor)) }); float desirabledamage; desirabledamage = enemydamage; - if(time > actor.invincible_finished && time > actor.spawnshieldtime) + if(time > STAT(INVINCIBLE_FINISHED, actor) && time > actor.spawnshieldtime) desirabledamage = desirabledamage - selfdamage * autocvar_g_balance_selfdamagepercent; if(teamplay && actor.team) desirabledamage = desirabledamage - teamdamage; @@ -495,7 +438,7 @@ METHOD(Devastator, wr_aim, void(entity thiswep, entity actor)) // but don't fire a new shot at the same time! if(desirabledamage >= 0.75 * coredamage) //this should do group damage in rare fortunate events PHYS_INPUT_BUTTON_ATCK2(actor) = true; - if((skill > 6.5) && (selfdamage > actor.health)) + if((skill > 6.5) && (selfdamage > GetResource(actor, RES_HEALTH))) PHYS_INPUT_BUTTON_ATCK2(actor) = false; //if(PHYS_INPUT_BUTTON_ATCK2(actor) == true) // dprint(ftos(desirabledamage),"\n"); @@ -505,25 +448,24 @@ METHOD(Devastator, wr_aim, void(entity thiswep, entity actor)) METHOD(Devastator, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { - if(WEP_CVAR(devastator, reload_ammo) && actor.clip_load < WEP_CVAR(devastator, ammo)) { // forced reload + if(WEP_CVAR(devastator, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR(devastator, ammo)) { // forced reload thiswep.wr_reload(thiswep, actor, weaponentity); } else { - int slot = weaponslot(weaponentity); if(fire & 1) { - if(actor.rl_release[slot] || WEP_CVAR(devastator, guidestop)) + if(actor.(weaponentity).rl_release || WEP_CVAR(devastator, guidestop)) if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(devastator, refire))) { - W_Devastator_Attack(thiswep, actor, weaponentity); + W_Devastator_Attack(thiswep, actor, weaponentity, fire); weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(devastator, animtime), w_ready); - actor.rl_release[slot] = 0; + actor.(weaponentity).rl_release = 0; } } else - actor.rl_release[slot] = 1; + actor.(weaponentity).rl_release = 1; if(fire & 2) - if(PS(actor).m_switchweapon == WEP_DEVASTATOR) + if(actor.(weaponentity).m_switchweapon == thiswep) { bool rockfound = false; IL_EACH(g_projectiles, it.realowner == actor && it.classname == "rocket", @@ -539,24 +481,23 @@ METHOD(Devastator, wr_think, void(entity thiswep, entity actor, .entity weaponen } } } -METHOD(Devastator, wr_setup, void(entity thiswep, entity actor)) +METHOD(Devastator, wr_setup, void(entity thiswep, entity actor, .entity weaponentity)) { - for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - actor.rl_release[slot] = 1; + actor.(weaponentity).rl_release = 1; } -METHOD(Devastator, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Devastator, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { #if 0 // don't switch while guiding a missile - if(ATTACK_FINISHED(actor, slot) <= time || PS(actor).m_weapon != WEP_DEVASTATOR) + if(ATTACK_FINISHED(actor, weaponentity) <= time || PS(actor).m_weapon != WEP_DEVASTATOR) { ammo_amount = false; if(WEP_CVAR(devastator, reload_ammo)) { - if(actor.(thiswep.ammo_field) < WEP_CVAR(devastator, ammo) && actor.(weapon_load[WEP_DEVASTATOR.m_id]) < WEP_CVAR(devastator, ammo)) + if(GetResource(actor, thiswep.ammo_type) < WEP_CVAR(devastator, ammo) && actor.(weaponentity).(weapon_load[WEP_DEVASTATOR.m_id]) < WEP_CVAR(devastator, ammo)) ammo_amount = true; } - else if(actor.(thiswep.ammo_field) < WEP_CVAR(devastator, ammo)) + else if(GetResource(actor, thiswep.ammo_type) < WEP_CVAR(devastator, ammo)) ammo_amount = true; return !ammo_amount; } @@ -564,23 +505,23 @@ METHOD(Devastator, wr_checkammo1, bool(entity thiswep, entity actor)) #if 0 if(actor.rl_release == 0) { - LOG_INFOF("W_Devastator(WR_CHECKAMMO1): %d, %.2f, %d: TRUE\n", actor.rl_release, actor.(thiswep.ammo_field), WEP_CVAR(devastator, ammo)); + LOG_INFOF("W_Devastator(WR_CHECKAMMO1): %d, %.2f, %d: TRUE", actor.rl_release, GetResource(actor, thiswep.ammo_type), WEP_CVAR(devastator, ammo)); return true; } else { - ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(devastator, ammo); - ammo_amount += actor.(weapon_load[WEP_DEVASTATOR.m_id]) >= WEP_CVAR(devastator, ammo); - LOG_INFOF("W_Devastator(WR_CHECKAMMO1): %d, %.2f, %d: %s\n", actor.rl_release, actor.(thiswep.ammo_field), WEP_CVAR(devastator, ammo), (ammo_amount ? "TRUE" : "FALSE")); + ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR(devastator, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_DEVASTATOR.m_id]) >= WEP_CVAR(devastator, ammo); + LOG_INFOF("W_Devastator(WR_CHECKAMMO1): %d, %.2f, %d: %s", actor.rl_release, GetResource(actor, thiswep.ammo_type), WEP_CVAR(devastator, ammo), (ammo_amount ? "TRUE" : "FALSE")); return ammo_amount; } #else - float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(devastator, ammo); - ammo_amount += actor.(weapon_load[WEP_DEVASTATOR.m_id]) >= WEP_CVAR(devastator, ammo); + float ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR(devastator, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[thiswep.m_id]) >= WEP_CVAR(devastator, ammo); return ammo_amount; #endif } -METHOD(Devastator, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Devastator, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { return false; } @@ -590,7 +531,7 @@ METHOD(Devastator, wr_resetplayer, void(entity thiswep, entity actor)) { .entity weaponentity = weaponentities[slot]; actor.(weaponentity).lastrocket = NULL; // stop rocket guiding, no revenge from the grave! - actor.rl_release[slot] = 0; + actor.(weaponentity).rl_release = 0; } } METHOD(Devastator, wr_reload, void(entity thiswep, entity actor, .entity weaponentity)) @@ -622,4 +563,3 @@ METHOD(Devastator, wr_impacteffect, void(entity thiswep, entity actor)) } #endif -#endif