#include "q_shared.h" #include "..\ghoul\ighoul.h" #include "w_public.h" #include "w_types.h" #include "w_weapons.h" #include "w_utils.h" #include "player.h" #include "../gamecpp/game.h" extern player_com_import_t picom; extern player_cl_import_t picl; extern player_sv_import_t pisv; extern int isClient; extern int fireEvent; extern int altfireEvent; // noiserad does NOT belong here... attackInfoExtra_t attacks[] = { //ammo noiseRad waver waverMax kickamount AttackID {AMMO_NONE, 0.0, 0.0, 0.0, 0.0, ATK_NOTHING}, //SFW_EMPTYSLOT {AMMO_KNIFE, 0.0, 0.0, 0.0, 0.0, ATK_KNIFE}, //SFW_KNIFE, {AMMO_KNIFE, 0.0, 0.0, 0.0, 0.0, ATK_KNIFE_ALT}, //SFW_KNIFE, {AMMO_44, 900.0, 0.2, 0.8, 5.0, ATK_PISTOL2}, //SFW_PISTOL2, {AMMO_9MM, 600.0, 0.3, 1.5, 1.0, ATK_PISTOL1}, //SFW_PISTOL1, {AMMO_9MM, 10.0, 0.6, 3.5, 0.0, ATK_MACHINEPISTOL}, //SFW_MACHINEPISTOL, {AMMO_556, 800.0, 0.4, 1.8, 0.0, ATK_ASSAULTRIFLE}, //SFW_ASSAULTRIFLE, {AMMO_556, 0.0, 0.0, 0.0, 2.0, ATK_SNIPER}, //SFW_SNIPER, ->sniper rifle {AMMO_NONE, 0.0, 0.0, 0.0, 0.0, ATK_SNIPER_ALT}, //SFW_SNIPER, ->sniper rifle {AMMO_SLUG, 1200.0, 1.5, 1.5, 4.0, ATK_AUTOSHOTGUN}, //SFW_AUTOSHOTGUN, ->shotgun {AMMO_SLUG, 0.0, 0.0, 0.0, 4.0, ATK_AUTOSHOTGUN_ALT}, //SFW_AUTOSHOTGUN, ->shotgun {AMMO_SHELLS, 1200.0, 0.0, 0.0, 5.0, ATK_SHOTGUN}, //SFW_SHOTGUN, ->shotgun {AMMO_556, 1500.0, 0.1, 0.4, 0.0, ATK_MACHINEGUN}, //SFW_MACHINEGUN, -> machinegun {AMMO_556, 500.0, 0.0, 0.0, 0.0, ATK_MACHINEGUN_ALT}, //SFW_MACHINEGUN, -> machinegun {AMMO_ROCKET, 0.0, 0.0, 0.0, 0.0, ATK_ROCKET}, //SFW_ROCKET, -> rocketlauncher {AMMO_ROCKET, 0.0, 0.0, 0.0, 0.0, ATK_ROCKET_ALT}, //SFW_ROCKET, -> rocketlauncher {AMMO_MWAVE, 0.0, 0.0, 0.0, 0.0, ATK_MICROWAVE}, //SFW_MICROWAVEPULSE, {AMMO_MWAVE, 0.0, 0.0, 0.0, 0.0, ATK_MICROWAVE_ALT}, //SFW_MICROWAVEPULSE, {AMMO_FTHROWER, 0.0, 0.0, 0.0, 0.0, ATK_FLAMEGUN}, //SFW_FLAMETHROWER, {AMMO_FTHROWER, 0.0, 0.0, 0.0, 0.0, ATK_FLAMEGUN_ALT}, //SFW_FLAMETHROWER, }; WeapSoundCallBack theWeapSoundCallback; GunFireCallBack theGunFireCallback; AltfireCallBack theAltfireCallback; EOSCallBack theEOSCallback; KnifeCleanCallBack theKnifeCleanCallback; MinimiReloadCallBack theMinimiReloadCallback; EffectCallBack theEffectCallback; weaponInfoExtra_t extraInfo[] = { // name slotsNeeded clipsize attack1 attack2 {"", 0, -1, &attacks[0], &attacks[0]}, //SFW_EMPTYSLOT {"Knife", 0, 0, &attacks[1], &attacks[2]}, //SFW_KNIFE, {"Pistol2", 1, 9, &attacks[3], &attacks[0]}, //SFW_PISTOL2, {"Pistol1", 1, 18, &attacks[4], &attacks[0]}, //SFW_PISTOL1, {"MPistol", 2, 32, &attacks[5], &attacks[0]}, //SFW_MACHINEPISTOL, {"Assaultrifle", 2, 40, &attacks[6], &attacks[0]}, //SFW_ASSAULTRIFLE, {"SniperRifle", 2, 6, &attacks[7], &attacks[8]}, //SFW_SNIPER, ->sniper rifle {"Autoshotgun", 2, 10, &attacks[9], &attacks[10]}, //SFW_AUTOSHOTGUN, ->shotgun {"Shotgun", 2, 8, &attacks[11], &attacks[0]}, //SFW_SHOTGUN, ->shotgun {"Machinegun", 2, 40, &attacks[12], &attacks[13]}, //SFW_MACHINEGUN, -> machinegun {"Rocket", 3, 4, &attacks[14], &attacks[15]}, //SFW_ROCKET, -> rocketlauncher {"MPG", 3, 30, &attacks[16], &attacks[17]}, //SFW_MICROWAVEPULSE, {"Flamegun", 3, 60, &attacks[18], &attacks[19]}, //SFW_FLAMETHROWER, {"Hurthand", 0, 0, &attacks[0], &attacks[0]}, //SFW_HURTHAND, {"Throwhand", 0, 0, &attacks[0], &attacks[0]}, //SFW_THROWHAND, }; weaponInfo_c noweap(&extraInfo[0]); knifeInfo knife(&extraInfo[1]); pistol2Info eagle(&extraInfo[2]); pistol1Info glock(&extraInfo[3]); machinePistolInfo ingram(&extraInfo[4]); assaultRifleInfo hk53(&extraInfo[5]); sniperInfo sig(&extraInfo[6]); autoshotgunInfo jhammer(&extraInfo[7]); shotgunInfo spas(&extraInfo[8]); machinegunInfo minimi(&extraInfo[9]); rocketInfo m202a2(&extraInfo[10]); microInfo micro(&extraInfo[11]); flamegunInfo fthrow(&extraInfo[12]); hurthandInfo hhand(&extraInfo[13]); throwhandInfo thand(&extraInfo[14]); weaponInfo_c *weapInfo[SFW_NUM_WEAPONS] = { &noweap, &knife, &eagle, &glock, &ingram, &hk53, &sig, &jhammer, &spas, &minimi, &m202a2, µ, &fthrow, &hhand, &thand, }; weaponInfo_c::weaponInfo_c(weaponInfoExtra_t *w) { clip = w->clipsize; slotsNeeded = w->slotsNeeded; ammoType[0] = w->a1->ammoType; ammoType[1] = w->a2->ammoType; noiseRad[0] = w->a1->noiseRad; noiseRad[1] = w->a2->noiseRad; waver[0] = w->a1->waver; waver[1] = w->a2->waver; waverMax[0] = w->a1->waverMax; waverMax[1] = w->a2->waverMax; kick[0] = w->a1->kickAmount; kick[1] = w->a2->kickAmount; strcpy(modelName, w->name); atkID[0] = w->a1->id; atkID[1] = w->a2->id; soundToken = NULL_GhoulID; } int weaponInfo_c::useAmmo1(sharedEdict_t &ent, int *skipIdle) { weapon_c *weap = inven(ent)->getCurWeapon(); if(getAmmoType(0) == AMMO_NONE) return 1; if(!inven(ent)->rulesDoWeaponsUseAmmo()) return 1; if(!weap->getClip()) { if(inven(ent)->rulesIsWeaponReloadAutomatic()) inven(ent)->reload(); else inven(ent)->dryfire(); return 0; } weap->setClip(weap->getClip() - 1); return 1; } int weaponInfo_c::useAmmo2(sharedEdict_t &ent, int *skipIdle) { weapon_c *weap = inven(ent)->getCurWeapon(); if(getAmmoType(1) == AMMO_NONE) return 1; if(!inven(ent)->rulesDoWeaponsUseAmmo()) return 1; if(!weap->getClip()) { if(inven(ent)->rulesIsWeaponReloadAutomatic()) inven(ent)->reload(); else inven(ent)->dryfire(); return 0; } weap->setClip(weap->getClip() - 1); return 1; } int weaponInfo_c::checkReloadAtEOS(sharedEdict_t &ent) { if((wAnim(ent)->getAnimType() == WANIM_FIRE)||(wAnim(ent)->getAnimType() == WANIM_ALTFIRE)) { if(!inven(ent)->rulesDoWeaponsUseAmmo()) return 0; if(!inven(ent)->getCurClip()) { if(inven(ent)->rulesIsWeaponReloadAutomatic()) { inven(ent)->reload(); return 1; } else { return 0; } } } return 0; } void weaponInfo_c::precacheResources() { if(getAtkID(0) != ATK_NOTHING) { pisv.CacheAttack((int)getAtkID(0)); } if(getAtkID(1) != ATK_NOTHING) { pisv.CacheAttack((int)getAtkID(1)); } } //------------------------------------------------------------------------ weapon_c::weapon_c(void) { curClip = 0; cannotFire = 0; type = SFW_EMPTYSLOT; } weapon_c::weapon_c(weaponInfo_c *wInfo) { curClip = getWeaponInfo()->getClipSize(); cannotFire = 0; type = SFW_EMPTYSLOT; } void weapon_c::setType(int newType, int startWithFullClip) { type = newType; if(startWithFullClip == -1) { curClip = getWeaponInfo()->getClipSize(); } else if(startWithFullClip) { curClip = startWithFullClip; } else { curClip = 0; } } int weapon_c::handleAmmo(sharedEdict_t &ent, int mode, int *skipIdle) { return((mode) ? getWeaponInfo()->useAmmo2(ent, skipIdle) : getWeaponInfo()->useAmmo1(ent, skipIdle)); } weaponInfo_c *weapon_c::getWeaponInfo(void) { return weapInfo[type]; } int weapon_c::canSelect(sharedEdict_t &ent,int withNoAmmo) { if(type == SFW_EMPTYSLOT) return 0; if(isClient) { // Client is always able to select any weapon. return(1); } if(!withNoAmmo) { if((curClip == 0)&&(inven(ent)->rulesDoWeaponsUseAmmo())) { if((inven(ent)->hasAmmo(weapInfo[type]->getAmmoType(0)) == 0)&&(!weapInfo[type]->canSelectWithNoAmmo())) return 0; } } return(1); } //--------------------------------------------------------------------------------------------- // // wrapper funcs // //--------------------------------------------------------------------------------------------- void Fire(sharedEdict_t &sh, edict_t &ent, inven_c &inven) { if(!inven.getCurWeapon()->getWeaponInfo()->atMomentOfFire(sh)) return; if(wAnim(sh)->getAnimType() != WANIM_FIRE) return; if(!isClient) pisv.FireHelper(sh, ent, inven); else picl.FireHelper(sh, ent, inven); sh.weaponkick_angles[PITCH]=-(inven.getCurWeapon()->getWeaponInfo()->getKick(0)); } void Altfire(sharedEdict_t &sh, edict_t &ent, inven_c &inven) { if(!inven.getCurWeapon()->getWeaponInfo()->atMomentOfFire(sh)) return; if(wAnim(sh)->getAnimType() != WANIM_ALTFIRE) return; if(!isClient) pisv.AltfireHelper(sh, ent, inven); else picl.AltfireHelper(sh, ent, inven); sh.weaponkick_angles[PITCH]=-(inven.getCurWeapon()->getWeaponInfo()->getKick(1)); } void EOS(sharedEdict_t &ent, inven_c &inven) { if(inven.getCurWeapon()->getWeaponInfo()->handleEOS(ent)) { // Special end of sequence stuff handled by weapon specific EOS. return; } if(inven.getCurWeapon()->getWeaponInfo()->checkReloadAtEOS(ent)) { // Do we need to reload now? return; } switch(wAnim(ent)->getAnimType()) { case WANIM_NORMAL: case WANIM_RELOAD: inven.idle(); break; case WANIM_FIRE: if(!(inven.pendingCommand())) { qboolean doAttack=false; if(!isClient) { if(!inven.isClientPredicting()) { if(ent.attack) doAttack=true; } else { if((inven.getCurWeaponID()==SFW_FLAMEGUN)|| (inven.getCurWeaponID()==SFW_KNIFE)|| (inven.getCurWeaponID()==SFW_MICROWAVEPULSE)) { // Yuck!! Sigh!! if(ent.attack) doAttack=true; } else { if(pisv.getFireEvent(inven.getOwner()->edict)) doAttack=true; } } } else { if(ent.attack) doAttack=true; } if(doAttack) { inven.getAnimInfo()->incFireLoop(); int skipIdle = 0; if(!inven.getCurWeapon()->handleAmmo(ent, 0, &skipIdle)) { if(!skipIdle) { inven.idle(); } return; } if(!isClient) { if(inven.isClientPredicting()) { if((inven.getCurWeaponID()==SFW_FLAMEGUN)|| (inven.getCurWeaponID()==SFW_KNIFE)|| (inven.getCurWeaponID()==SFW_ASSAULTRIFLE)|| (inven.getCurWeaponID()==SFW_MACHINEPISTOL)|| (inven.getCurWeaponID()==SFW_MICROWAVEPULSE)) { // Yuck!! Sigh!! RunVWeapAnim(&ent, inven.getCurWeapon()->getWeaponInfo()->getFireSeq(ent), inven.getCurWeapon()->getWeaponInfo()->getLoopType()); } else { RunVWeapAnim(&ent, inven.getCurWeapon()->getWeaponInfo()->getFireSeq(ent), inven.getCurWeapon()->getWeaponInfo()->getLoopType(), pisv.getFireEvent(inven.getOwner()->edict)); } pisv.clearFireEvent(inven.getOwner()->edict); } else { RunVWeapAnim(&ent, inven.getCurWeapon()->getWeaponInfo()->getFireSeq(ent), inven.getCurWeapon()->getWeaponInfo()->getLoopType()); } } else { RunVWeapAnim(&ent, inven.getCurWeapon()->getWeaponInfo()->getFireSeq(ent), inven.getCurWeapon()->getWeaponInfo()->getLoopType()); fireEvent=1; } // Some weapons don't just loop their anim. inven.getCurWeapon()->getWeaponInfo()->handleFireLoop(ent); return; } } inven.getAnimInfo()->clearFireLoop(); inven.idle(); break; case WANIM_ALTFIRE: if(!inven.pendingCommand()) { qboolean doAltAttack=false; if(!isClient) { if(!inven.isClientPredicting()) { if(ent.altattack) doAltAttack=true; } else { if(pisv.getAltfireEvent(inven.getOwner()->edict)) doAltAttack=true; } } else { if(ent.altattack) doAltAttack=true; } if(doAltAttack) { inven.getAnimInfo()->incFireLoop(); int skipIdle = 0; if(!inven.getCurWeapon()->handleAmmo(ent, 1, &skipIdle)) { if(!skipIdle) { inven.idle(); } return; } if(!isClient) { if(inven.isClientPredicting()) { if(inven.getCurWeaponID()==SFW_ROCKET) { // Yuck!! Sigh!! RunVWeapAnim(&ent, inven.getCurWeapon()->getWeaponInfo()->getAltFireSeq(ent), IGhoulInst::Hold); } else { RunVWeapAnim(&ent, inven.getCurWeapon()->getWeaponInfo()->getAltFireSeq(ent), IGhoulInst::Hold, pisv.getAltfireEvent(inven.getOwner()->edict)); } pisv.clearAltfireEvent(inven.getOwner()->edict); } else { RunVWeapAnim(&ent, inven.getCurWeapon()->getWeaponInfo()->getAltFireSeq(ent), IGhoulInst::Hold); } } else { RunVWeapAnim(&ent, inven.getCurWeapon()->getWeaponInfo()->getAltFireSeq(ent), IGhoulInst::Hold); altfireEvent=1; } // Some weapons don't just loop their anim! inven.getCurWeapon()->getWeaponInfo()->handleAltfireLoop(ent); return; } } inven.getAnimInfo()->clearFireLoop(); inven.idle(); break; case WANIM_PUTAWAY: // Set new weapon to take out. inven.setPendingChange(); break; case WANIM_LOSE: inven.idle(); break; } } //------------------------------------------------------------------------ bool WeapSoundCallBack::Execute(IGhoulInst *me,void *user,float now,const void *data) { inven_c *inv = (inven_c *)user; sharedEdict_t *ent = inv->getOwner(); if(isClient) picl.WeapSoundHelper(data); return true; } bool GunFireCallBack::Execute(IGhoulInst *me,void *user,float now,const void *data) { inven_c *inv = (inven_c *)user; sharedEdict_t *ent = inv->getOwner(); Fire(*ent, *ent->edict, *inv); if (data && *((char *)data)=='1') { // Use ammo during this fire. if (!inv->getCurWeapon()->getWeaponInfo()->useAmmo1(*ent)) { EOS(*ent, *inv); } } return true; } bool AltfireCallBack::Execute(IGhoulInst *me,void *user,float now,const void *data) { inven_c *inv = (inven_c *)user; sharedEdict_t *ent = inv->getOwner(); Altfire(*ent, *ent->edict, *inv); return true; } bool EOSCallBack::Execute(IGhoulInst *me,void *user,float now,const void *data) { inven_c *inv = (inven_c *)user; sharedEdict_t *ent = inv->getOwner(); EOS(*ent, *inv); return true; } bool KnifeCleanCallBack::Execute(IGhoulInst *me,void *user,float now,const void *data) { inven_c *inv = (inven_c *)user; sharedEdict_t *ent = inv->getOwner(); inv->getCurWeapon()->getWeaponInfo()->handleSpecialNotes((char *)data, *ent); return true; } bool MinimiReloadCallBack::Execute(IGhoulInst *me,void *user,float now,const void *data) { inven_c *inv = (inven_c *)user; sharedEdict_t *ent = inv->getOwner(); inv->getCurWeapon()->getWeaponInfo()->handleSpecialNotes((char *)data, *ent); return true; } bool EffectCallBack::Execute(IGhoulInst *me,void *user,float now,const void *data) { inven_c *inv = (inven_c *)user; sharedEdict_t *ent = inv->getOwner(); if(isClient) picl.WeaponEffectHelper(data); return true; } class EffectPrecacheCallBack: public IGhoulCallBack { public:virtual bool Execute(IGhoulInst *me,void *user,float now,const void *data) { char effectstr[256], *effectname; strcpy(effectstr, (char *)data); effectname = strtok(effectstr, " "); pisv.EffectIndex(effectname); return true; } }; EffectPrecacheCallBack effectPrecacher; //------------------------------------------------------------------------ class SoundPrecacheCallBack: public IGhoulCallBack { public:virtual bool Execute(IGhoulInst *me,void *user,float now,const void *data) { char buffer[256], soundname[256], *soundtok, *numtok; int i,c; strcpy(soundname, (char *)data); soundtok = strtok(soundname, " "); numtok = strtok(NULL, " "); if (!numtok) { c=0; } else { c=atoi(numtok); } if (c>0) { for (i=1; i<=c; i++) { picom.Com_Sprintf(buffer, sizeof(buffer), "%s%d.wav", soundtok, i); pisv.SoundIndex(buffer); } } else { picom.Com_Sprintf(buffer, sizeof(buffer), "%s.wav", soundtok); pisv.SoundIndex(buffer); } return true; } }; SoundPrecacheCallBack soundPrecacher; //------------------------------------------------------------------------ void W_UncacheViewWeaponModels(void) { int i; for(i = 0; i < SFW_NUM_WEAPONS; i++) { if(weapInfo[i]->getGhoulObj()) { weapInfo[i]->setGhoulObj(NULL); } } } void W_PrecacheViewWeaponModels(int types) { // types is a bitflag of all the weapon types that should be precached char buffer[256]; for(int i = SFW_EMPTYSLOT + 1; i < SFW_NUM_WEAPONS; i++) { if(!(types & (1<getGhoulObj())continue;//only need to precache if this weapon isn't already loaded, of course obj = ((IGhoul *)pisv.GetGhoul())->NewObj(); if(!obj) { // This is real bad - should not happen right? assert(obj); continue; } picom.RegisterGSQSequences(buffer, extraInfo[i].name, obj); obj->RegisterEverything(); obj->PreCache(picom.ghl_specular->value>0.0f); // Precache all the weapon sounds. GhoulID id = obj->FindNoteToken("sound"); if(id) { obj->FireAllNoteCallBacks(&soundPrecacher,id); } // Precache all effect calls. id = obj->FindNoteToken("effect"); if(id) { obj->FireAllNoteCallBacks(&effectPrecacher,id); } // Precache all other resources. weapInfo[i]->setGhoulObj(obj); weapInfo[i]->precacheResources(); } }