//------------------------------------------------------------------------- /* Copyright (C) 1996, 2003 - 3D Realms Entertainment Copyright (C) 2000, 2003 - Matt Saettler (EDuke Enhancements) Copyright (C) 2020 - Christoph Oelckers This file is part of Enhanced Duke Nukem 3D version 1.5 - Atomic Edition Duke Nukem 3D is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Original Source: 1996 - Todd Replogle Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms EDuke enhancements integrated: 04/13/2003 - Matt Saettler Note: EDuke source was in transition. Changes are in-progress in the source as it is released. */ //------------------------------------------------------------------------- #include "ns.h" #include "global.h" #include "gamevar.h" #include "names_d.h" #include "dukeactor.h" BEGIN_DUKE_NS int operateTripbomb(int snum); //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void DoFire(player_struct* p, int snum) { int i; if (aplWeaponWorksLike(p->curr_weapon, snum) != KNEE_WEAPON) { p->ammo_amount[p->curr_weapon]--; } if (aplWeaponFireSound(p->curr_weapon, snum)) { S_PlayActorSound(aplWeaponFireSound(p->curr_weapon, snum), p->GetActor()); } SetGameVarID(g_iWeaponVarID, p->curr_weapon, p->GetActor(), snum); SetGameVarID(g_iWorksLikeVarID, aplWeaponWorksLike(p->curr_weapon, snum), p->GetActor(), snum); fi.shoot(p->GetActor(), aplWeaponShoots(p->curr_weapon, snum)); for (i = 1; i < aplWeaponShotsPerBurst(p->curr_weapon, snum); i++) { fi.shoot(p->GetActor(), aplWeaponShoots(p->curr_weapon, snum)); if (aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_AMMOPERSHOT) { p->ammo_amount[p->curr_weapon]--; } } if (!(aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_NOVISIBLE)) { // make them visible if not set... lastvisinc = PlayClock + 32; p->visibility = 0; } if ( //!(aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_CHECKATRELOAD) && aplWeaponReload(p->curr_weapon, snum) > aplWeaponTotalTime(p->curr_weapon, snum) && p->ammo_amount[p->curr_weapon] > 0 && (aplWeaponClip(p->curr_weapon, snum)) && ((p->ammo_amount[p->curr_weapon] % (aplWeaponClip(p->curr_weapon, snum))) == 0) ) { // do clip check... p->kickback_pic = aplWeaponTotalTime(p->curr_weapon, snum); // is same as p->kickback_pic.... } if (aplWeaponWorksLike(p->curr_weapon, snum) != KNEE_WEAPON) { checkavailweapon(p); } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void DoSpawn(player_struct *p, int snum) { if(!aplWeaponSpawn(p->curr_weapon, snum)) return; auto j = spawn(p->GetActor(), aplWeaponSpawn(p->curr_weapon, snum)); if (!j) return; if((aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_SPAWNTYPE2 ) ) { // like shotgun shells j->add_int_ang(1024); ssp(j,CLIPMASK0); j->add_int_ang(1024); // p->kickback_pic++; } else if((aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_SPAWNTYPE3 ) ) { // like chaingun shells j->set_int_ang((j->int_ang() + 1024) & 2047); j->spr.xvel += 32; j->add_int_z(3<<8); ssp(j,CLIPMASK0); } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void fireweapon_ww(int snum) { auto p = &ps[snum]; auto pact = p->GetActor(); p->crack_time = CRACK_TIME; if (p->holster_weapon == 1) { if (p->last_pissed_time <= (26 * 218) && p->weapon_pos == -9) { p->holster_weapon = 0; p->oweapon_pos = p->weapon_pos = 10; FTA(74, p); } } else { SetGameVarID(g_iReturnVarID, 0, p->GetActor(), snum); SetGameVarID(g_iWeaponVarID, p->curr_weapon, p->GetActor(), snum); SetGameVarID(g_iWorksLikeVarID, aplWeaponWorksLike(p->curr_weapon, snum), p->GetActor(), snum); OnEvent(EVENT_FIRE, snum, p->GetActor(), -1); if (GetGameVarID(g_iReturnVarID, p->GetActor(), snum).value() == 0) { switch (aplWeaponWorksLike(p->curr_weapon, snum)) { case HANDBOMB_WEAPON: p->hbomb_hold_delay = 0; if (p->ammo_amount[p->curr_weapon] > 0) { p->kickback_pic = 1; if (aplWeaponInitialSound(p->curr_weapon, snum)) { S_PlayActorSound(aplWeaponInitialSound(p->curr_weapon, snum), pact); } } break; case HANDREMOTE_WEAPON: p->hbomb_hold_delay = 0; p->kickback_pic = 1; if (aplWeaponInitialSound(p->curr_weapon, snum)) { S_PlayActorSound(aplWeaponInitialSound(p->curr_weapon, snum), pact); } break; case PISTOL_WEAPON: if (p->ammo_amount[p->curr_weapon] > 0) { //p->ammo_amount[p->curr_weapon]--; p->kickback_pic = 1; if (aplWeaponInitialSound(p->curr_weapon, snum)) { S_PlayActorSound(aplWeaponInitialSound(p->curr_weapon, snum), pact); } } break; case CHAINGUN_WEAPON: if (p->ammo_amount[p->curr_weapon] > 0) { p->kickback_pic = 1; if (aplWeaponInitialSound(p->curr_weapon, snum)) { S_PlayActorSound(aplWeaponInitialSound(p->curr_weapon, snum), pact); } } break; case SHOTGUN_WEAPON: if (p->ammo_amount[p->curr_weapon] > 0 && p->random_club_frame == 0) { p->kickback_pic = 1; if (aplWeaponInitialSound(p->curr_weapon, snum)) { S_PlayActorSound(aplWeaponInitialSound(p->curr_weapon, snum), pact); } } break; case TRIPBOMB_WEAPON: if (operateTripbomb(snum)) { p->kickback_pic = 1; if (aplWeaponInitialSound(p->curr_weapon, snum)) { S_PlayActorSound(aplWeaponInitialSound(p->curr_weapon, snum), pact); } } break; case SHRINKER_WEAPON: if (p->ammo_amount[p->curr_weapon] > 0) { p->kickback_pic = 1; if (aplWeaponInitialSound(p->curr_weapon, snum)) { S_PlayActorSound(aplWeaponInitialSound(p->curr_weapon, snum), pact); } } break; case GROW_WEAPON: if (p->ammo_amount[p->curr_weapon] > 0) { p->kickback_pic = 1; if (aplWeaponInitialSound(p->curr_weapon, snum)) { S_PlayActorSound(aplWeaponInitialSound(p->curr_weapon, snum), pact); } } break; case FREEZE_WEAPON: if (p->ammo_amount[p->curr_weapon] > 0) { p->kickback_pic = 1; if (aplWeaponInitialSound(p->curr_weapon, snum)) { S_PlayActorSound(aplWeaponInitialSound(p->curr_weapon, snum), pact); } } break; case DEVISTATOR_WEAPON: if (p->ammo_amount[p->curr_weapon] > 0) { p->kickback_pic = 1; p->hbomb_hold_delay = !p->hbomb_hold_delay; if (aplWeaponInitialSound(p->curr_weapon, snum)) { S_PlayActorSound(aplWeaponInitialSound(p->curr_weapon, snum), pact); } } break; case RPG_WEAPON: if (p->ammo_amount[RPG_WEAPON] > 0) { p->kickback_pic = 1; if (aplWeaponInitialSound(p->curr_weapon, snum)) { S_PlayActorSound(aplWeaponInitialSound(p->curr_weapon, snum), pact); } } break; case KNEE_WEAPON: if (p->quick_kick == 0) { p->kickback_pic = 1; if (aplWeaponInitialSound(p->curr_weapon, snum)) { S_PlayActorSound(aplWeaponInitialSound(p->curr_weapon, snum), pact); } } break; } } } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void operateweapon_ww(int snum, ESyncBits actions) { auto p = &ps[snum]; auto pact = p->GetActor(); int i, k; // already firing... if (aplWeaponWorksLike(p->curr_weapon, snum) == HANDBOMB_WEAPON) { if (aplWeaponHoldDelay(p->curr_weapon, snum) // there is a hold delay && (p->kickback_pic == aplWeaponFireDelay(p->curr_weapon, snum)) // and we are 'at' hold && (actions & SB_FIRE) // and 'fire' button is still down ) // just hold here... { p->rapid_fire_hold = 1; return; } p->kickback_pic++; if (p->kickback_pic == aplWeaponHoldDelay(p->curr_weapon, snum)) { p->ammo_amount[p->curr_weapon]--; if (p->on_ground && (actions & SB_CROUCH)) { k = 15; i = MulScale(p->horizon.sum().asq16(), 20, 16); } else { k = 140; i = -512 - MulScale(p->horizon.sum().asq16(), 20, 16); } auto j = EGS(p->cursector, p->player_int_pos().X + p->angle.ang.Cos() * (1 << 8), p->player_int_pos().Y + p->angle.ang.Sin() * (1 << 8), p->player_int_pos().Z, HEAVYHBOMB, -16, 9, 9, p->angle.ang.Buildang(), (k + (p->hbomb_hold_delay << 5)), i, p->GetActor(), 1); if (j) { { int lGrenadeLifetime = GetGameVar("GRENADE_LIFETIME", NAM_GRENADE_LIFETIME, nullptr, snum).value(); int lGrenadeLifetimeVar = GetGameVar("GRENADE_LIFETIME_VAR", NAM_GRENADE_LIFETIME_VAR, nullptr, snum).value(); // set timer. blows up when at zero.... j->spr.extra = lGrenadeLifetime + MulScale(krand(), lGrenadeLifetimeVar, 14) - lGrenadeLifetimeVar; } if (k == 15) { j->spr.yvel = 3; j->spr.pos.Z += 8; } k = hits(p->GetActor()); if (k < 512) { j->add_int_ang(1024); j->spr.zvel /= 3; j->spr.xvel /= 3; } p->hbomb_on = 1; } } else if (p->kickback_pic < aplWeaponHoldDelay(p->curr_weapon, snum) && (actions & SB_CROUCH)) { p->hbomb_hold_delay++; } else if (p->kickback_pic > aplWeaponTotalTime(p->curr_weapon, snum)) { p->okickback_pic = p->kickback_pic = 0; // don't change to remote when in NAM: grenades are timed checkavailweapon(p); } } else if (aplWeaponWorksLike(p->curr_weapon, snum) == HANDREMOTE_WEAPON) { p->kickback_pic++; if (p->kickback_pic == aplWeaponFireDelay(p->curr_weapon, snum)) { if (aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_BOMB_TRIGGER) { p->hbomb_on = 0; } if (aplWeaponShoots(p->curr_weapon, snum) != 0) { if (!(aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_NOVISIBLE)) { // make them visible if not set... lastvisinc = PlayClock + 32; p->visibility = 0; } SetGameVarID(g_iWeaponVarID, p->curr_weapon, p->GetActor(), snum); SetGameVarID(g_iWorksLikeVarID, aplWeaponWorksLike(p->curr_weapon, snum), p->GetActor(), snum); fi.shoot(p->GetActor(), aplWeaponShoots(p->curr_weapon, snum)); } } if (p->kickback_pic >= aplWeaponTotalTime(p->curr_weapon, snum)) { p->okickback_pic = p->kickback_pic = 0; /// WHAT THE HELL DOES THIS DO....????????????? if (p->ammo_amount[TRIPBOMB_WEAPON] > 0) fi.addweapon(p, TRIPBOMB_WEAPON); else checkavailweapon(p); } } else { // the basic weapon... p->kickback_pic++; if (aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_CHECKATRELOAD) { if (p->kickback_pic == aplWeaponReload(p->curr_weapon, snum)) { checkavailweapon(p); } } if (aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_STANDSTILL && p->kickback_pic < (aplWeaponFireDelay(p->curr_weapon, snum) + 1)) { p->pos.Z = p->opos.Z; p->vel.Z = 0; } if (p->kickback_pic == aplWeaponSound2Time(p->curr_weapon, snum)) { if (aplWeaponSound2Sound(p->curr_weapon, snum)) { S_PlayActorSound(aplWeaponSound2Sound(p->curr_weapon, snum), pact); } } if (p->kickback_pic == aplWeaponSpawnTime(p->curr_weapon, snum)) { DoSpawn(p, snum); } if (p->kickback_pic == aplWeaponFireDelay(p->curr_weapon, snum)) { DoFire(p, snum); } if (p->kickback_pic > aplWeaponFireDelay(p->curr_weapon, snum) && p->kickback_pic < aplWeaponTotalTime(p->curr_weapon, snum)) { if (aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_AUTOMATIC) { // an 'automatic' if ((actions & SB_FIRE) == 0) { p->kickback_pic = aplWeaponTotalTime(p->curr_weapon, snum); } if (aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_FIREEVERYTHIRD) { if (((p->kickback_pic) % 3) == 0) { DoFire(p, snum); DoSpawn(p, snum); } } if (aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_FIREEVERYOTHER) { // fire every other... DoFire(p, snum); DoSpawn(p, snum); } } // 'automatic } else if (p->kickback_pic >= aplWeaponTotalTime(p->curr_weapon, snum)) { if ( //!(aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_CHECKATRELOAD) && aplWeaponReload(p->curr_weapon, snum) > aplWeaponTotalTime(p->curr_weapon, snum) && p->ammo_amount[p->curr_weapon] > 0 && (aplWeaponClip(p->curr_weapon, snum)) && ((p->ammo_amount[p->curr_weapon] % (aplWeaponClip(p->curr_weapon, snum))) == 0) ) { // reload in progress... int timer = aplWeaponReload(p->curr_weapon, snum) - aplWeaponTotalTime(p->curr_weapon, snum); // time for 'reload' if (p->kickback_pic == (aplWeaponTotalTime(p->curr_weapon, snum) + 1)) { // eject shortly after 'total time' S_PlayActorSound(EJECT_CLIP, pact); } else if (p->kickback_pic == (aplWeaponReload(p->curr_weapon, snum) - (timer / 3))) { // insert occurs 2/3 of way through reload delay S_PlayActorSound(INSERT_CLIP, pact); } if (p->kickback_pic >= (aplWeaponReload(p->curr_weapon, snum))) { p->okickback_pic = p->kickback_pic = 0; } } else { if (aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_AUTOMATIC) { // an 'automatic' if (actions & SB_FIRE) { // we are an AUTOMATIC. Fire again... if (aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_RANDOMRESTART) { p->kickback_pic = 1 + (krand() & 3); } else { p->kickback_pic = 1; } } else { p->okickback_pic = p->kickback_pic = 0; } } else { // not 'automatic' and >totaltime p->okickback_pic = p->kickback_pic = 0; } } } } // process the event ourselves if no handler provided. } END_DUKE_NS