#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 "w_network.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; int fireEvent; int altfireEvent; void inven_c::getServerState(void) { // Clip. curWeapon()->setClip(owner->edict->client->ps.gunClip); // Ammo pool. weapon_c *weaponToFill=&weapons[curWeaponSlot]; int type = weaponToFill->getWeaponInfo()->getAmmoType(0); ammo[type]=owner->edict->client->ps.gunAmmo; } void inven_c::setServerState(void) { // Clip. owner->edict->client->ps.gunClip=curWeapon()->getClip(); // Ammo pool. owner->edict->client->ps.gunAmmo=getCurAmmo(); } inven_c::inven_c(void) { canHandleInput = 1; setCurWeapon(0); setReadiedWeapon(0); setWInfo(1); setDroppingWeapon(-1); model = 0; readyModel = 0; memset(&gunEnd, 0, sizeof(Matrix4)); // Should really be gunEnd.Zero() wAnim.setHandsInUse(2); wAnim.setWeaponLifted(0); wAnim.setTransition(1); wAnim.setBloody(0); wAnim.setHandSide(0); wAnim.setDown(0); wAnim.setFirstShot(1); wAnim.setInZoom(0); wAnim.setInZoomView(0); wAnim.setInteresting(0); wAnim.setRezoom(0); wAnim.setKnifeStatus(0); wAnim.setDisguise(0); wAnim.setlastShootTime(0); nextCommand = PWC_NOCOMMAND; clientOverrideCmd=0; newInstRxd=0; rulesWeaponsUseAmmo=-1; rulesDropWeapons=-1; rulesNonDroppableWeaponTypes=(1<setOwner(this); } else { clientRICBuffer=new clientRICBuf; clientRICBuffer->setOwner(this); } int i; if(isClient) { // Client always has all the weapons available. for(i=SFW_KNIFE;iedict->s.origin, owner->edict->client->ps.viewoffset, worldSpot); #else Matrix4 etow,null2world; Vect3 NullPos; vec3_t pos; gunEnd.GetRow(3, NullPos); VectorAdd(owner->s.origin, owner->client->ps.viewoffset, pos); EntToWorldMatrix(pos,owner->client->ps.viewangles,etow); null2world.Concat(gunEnd,etow); Vect3 curPos(0,0,0); null2world.XFormPoint(NullPos,curPos); worldSpot[0] = NullPos.x(); worldSpot[1] = NullPos.y(); worldSpot[2] = NullPos.z(); #endif */ } void inven_c::initNewWeapon(void) { if(!isClient) { owner->edict->client->ps.gunType=curWeaponID; owner->edict->client->ps.gunClip=curWeapon()->getClip(); owner->edict->client->ps.gunAmmo=getCurAmmo(); } SetVWeapGhoul(owner, getViewModelName()); if(!wAnim.disguised()) idle(); if(rulesDoWeaponsUseAmmo()) { if(!isClient) curWeapon()->getWeaponInfo()->turnOffAmmoParts(*owner,curWeapon()->getClip(),true); else curWeapon()->getWeaponInfo()->turnOffAmmoParts(*owner,owner->edict->client->ps.gunClip,true); } } int inven_c::addWeaponType(int weapon, int fullClip) { int i; // See if there already is one in our inventory. for(i = 0; i < MAXWEAPONS; i++) { if(weapons[i].getType() == weapon) { return 0; } } // Ok, don't have one, so add it to the correct slot. static int weaponBinds[]= { SFW_KNIFE, SFW_PISTOL1, SFW_PISTOL2, SFW_SHOTGUN, SFW_SNIPER, SFW_MACHINEPISTOL, SFW_ASSAULTRIFLE, SFW_MACHINEGUN, SFW_AUTOSHOTGUN, SFW_ROCKET, SFW_FLAMEGUN, SFW_MICROWAVEPULSE, SFW_HURTHAND, SFW_THROWHAND, SFW_NUM_WEAPONS }; i=0; while(weaponBinds[i]!=SFW_NUM_WEAPONS) { if(weaponBinds[i]==weapon) { if(!rulesDoWeaponsUseAmmo()) fullClip=0; weapons[i].setType(weapon, fullClip); addWeaponToOwnList(weapon); return(1); } i++; } return(0); } int inven_c::getEncumbrance(void) { int encumbrance=0; for(int i=0; igetSlotsNeeded(); return(encumbrance); } int inven_c::getEncumbranceByType(int weapon) { return(weapInfo[weapon]->getSlotsNeeded()); } int inven_c::addItem(int type, int amount, int maxAmount/*= -1*/) { bool bWasEmpty = items.getCurSlot()?(items.getCurSlot()->getSlotType()==SFE_EMPTYSLOT):true; int nRet = items.addItemType(type, amount, maxAmount); if(bWasEmpty && !!nRet) items.setNextCommand(PEC_ITEMNEXT); return nRet; } void inven_c::readyNextWeapon(void) { if(nextSelectSlot == -1) return; readiedWeaponID = weapons[nextSelectSlot].getType(); setReadiedWeapon(nextSelectSlot); setReadiedWInfo(readiedWeapon()->getWeaponInfo()->getType()); readiedWeaponSlot = nextSelectSlot; ReadyVWeapGhoulServer(owner, getReadyModelName()); // Needed to 'kick-start' the new inst to the client straight-away. idleReadied(); // Needed by client. owner->edict->client->ps.gunType=readiedWeaponID; owner->edict->client->ps.gunClip=readiedWeapon()->getClip(); owner->edict->client->ps.gunAmmo=getReadiedAmmo(); } void inven_c::SelectRediedWeapon(void) { SetReadiedVWeapGhoulServer(owner,""); curWeaponID = readiedWeaponID; setCurWeapon(readiedWeaponSlot); setWInfo(readiedWeapon()->getWeaponInfo()->getType()); selectedWeaponSlot = readiedWeaponSlot; readiedWeaponID=0; } void inven_c::selectNULLWeapon(void) { if(!isClient) { owner->edict->client->ps.gun=0; owner->edict->client->ps.gunType=0; owner->edict->client->ps.gunClip=0; owner->edict->client->ps.gunAmmo=0; } setCurWeapon(0); setReadiedWeapon(0); setWInfo(1); model = 0; readyModel = 0; selectedWeaponSlot = -1; wAnim.clearFireLoop(); nextSelectSlot = 0; curWeaponID = 0; readiedWeaponID = 0; readiedWeaponType = 0; pendingChange = 0; wAnim.setAnimType(WANIM_NORMAL); wAnim.setSeqName("unused viewmodel"); } void inven_c::SelectPendingWeapon(void) { if(nextSelectSlot == -1)return; curWeaponID = weapons[nextSelectSlot].getType(); setCurWeapon(nextSelectSlot); setWInfo(curWeapon()->getWeaponInfo()->getType()); selectedWeaponSlot = nextSelectSlot; initNewWeapon(); } int inven_c::selectWeapon(int weapon) { int i; for(i = 0; i < MAXSELECTABLEWEAPONS; i++) { if(weapons[i].getType() == weapon) { curWeaponID = weapon; setCurWeapon(i); setWInfo(weapons[i].getWeaponInfo()->getType()); selectedWeaponSlot = i; initNewWeapon(); return 1; } } return 0; } void inven_c::selectWeaponSlot(int weaponNum) { curWeaponID = weapons[weaponNum].getType(); setCurWeapon(weaponNum); setWInfo(curWeaponID); selectedWeaponSlot = weaponNum; initNewWeapon(); } void inven_c::selectBestWeapon(void) { selectWeaponSlot(getBestSlot(!strcmp(rulesGetBestWeaponMode(),"safe"))); } void inven_c::takeOutWeapon(int type) { for(int i=0; i= ammoMaxes[type]) { // NO PICK UP!!! return 0; } if(curClip+amount>ammoMaxes[type]) amount=ammoMaxes[type] - curClip; weapons[10].setClip(curClip+amount); return 1; } if(ammo[type] >= ammoMaxes[type]) { // NO PICK UP!!! return 0; } if(ammo[type] + amount > ammoMaxes[type]) amount = ammoMaxes[type] - ammo[type]; ammo[type] += amount; return 1; } int ammoMinPickup[] = { 0, //AMMO_NONE = 0, 1, //AMMO_KNIFE, 4, //AMMO_44, 5, //AMMO_9MM, 2, //AMMO_SHELLS, 15, //AMMO_556, 1, //AMMO_ROCKET, 5, //AMMO_MWAVE, 5, //AMMO_FTHROWER, 5, //AMMO_SLUG, 8, //special 9mm machine pistol ammo AMMO_MACHPIS9MM }; int ammoMaxPickup[] = { 0, //AMMO_NONE = 0, 1, //AMMO_KNIFE, 9, //AMMO_44, 8, //AMMO_9MM, 4, //AMMO_SHELLS, 20, //AMMO_556, 3, //AMMO_ROCKET, 10, //AMMO_MWAVE, 10, //AMMO_FTHROWER, 10, //AMMO_SLUG, 15, //special 9mm machine pistol ammo AMMO_MACHPIS9MM }; int inven_c::addAmmoByGunType(int type, int amount) { // Default to one, I guess. int ammoType = weapInfo[type]->getAmmoType(0); int addedAmount; if(amount) { addedAmount = amount; } else if(type == SFW_MACHINEPISTOL) { ammoType = AMMO_MACHPIS9MM; // special amount for machine pistol 9mm addedAmount = ClientServerRand(ammoMinPickup[ammoType],ammoMaxPickup[ammoType]); return addAmmoType(AMMO_9MM, addedAmount); } else { addedAmount = ClientServerRand(ammoMinPickup[ammoType],ammoMaxPickup[ammoType]); } return addAmmoType(ammoType, addedAmount); } int inven_c::stripAmmoFromGun(int type, int amount) { // For single player // Default to one, I guess. int ammoType = weapInfo[type]->getAmmoType(0); return addAmmoType(ammoType, amount); } void inven_c::clearInv(bool ctf_remove) { int i; for(i=0; igetSlotType() != SFE_CTFFLAG)) { items.clearSlot(i); } } armor=0; nextCommand=PWC_NOCOMMAND; } void inven_c::removeSpecificItem(int type) { int i; for(i=0; igetSlotType() == type) { items.clearSlot(i); } } } void inven_c::handlePlayerDeath(void) { if(isClient) return; deactivateInventory(); if(curWeaponID!=SFW_EMPTYSLOT) { // This will stop weapons that are looping their firing sequences. idle(); // Shut down current. curInfo()->shutdownWeapon(*owner); } // Drop current weapon(s)? PWC_DROP can only be set if: // a) rulesCanDropWeapons() returns non-zero or // b) removeCurrentWeapon() has been called. if(rulesCanDropWeapons()||(nextCommand==PWC_DROP)) { if(curWeaponID!=SFW_EMPTYSLOT) { // Ensure we drop any weapon we are in the process of dropping or losing. if((nextCommand==PWC_DROP)||(nextCommand==PWC_LOSE)) setDroppingWeapon(curWeaponSlot); // Ensure we drop current weapon if we haven't already started dropping it. if(!droppingWeapon()) setDroppingWeapon(curWeaponSlot); // Actually drop it. if(!(rulesGetNonDroppableWeaponTypes()&(1<getType()))) pisv.WeaponDrop(this->owner->edict,droppingWeapon()->getType(), droppingWeapon()->getClip()); removeWeaponFromOwnList(droppingWeapon()->getType()); droppingWeapon()->setType(SFW_EMPTYSLOT); setDroppingWeapon(-1); } // In realistic DM, we need to drop any special weapons in our inventory. if(rulesCanDropInvenOnDeath()) { dropAllWeapons(); } } } void inven_c::dropAllWeapons(void) { if(isClient) return; for(int i = 0; i < MAXSELECTABLEWEAPONS; i++) { if(weapons[i].getType()!=SFW_EMPTYSLOT) { if(!(rulesGetNonDroppableWeaponTypes()&(1<owner->edict,weapons[i].getType(), weapons[i].getClip()); removeWeaponFromOwnList(weapons[i].getType()); weapons[i].setType(SFW_EMPTYSLOT); } } } int inven_c::removeCurrentWeapon(void) { if(isClient) return(0); nextCommand = PWC_DROP; return(1); } int inven_c::countWeapons(void) { int i; int val = 0; for(i = 0; i < MAXSELECTABLEWEAPONS; i++) { if(weapons[i].getType() != SFW_EMPTYSLOT)val++; } return(val); } void inven_c::deactivateCurrentWeapon(void) { curInfo()->shutdownWeapon(*owner); } void inven_c::deactivateInventory(void) { items.deactivate(*owner); } int inven_c::refillCurClip(int curSlot, int ignoreSingle, int noFillForSingle) { weapon_c *weaponToFill = &weapons[curSlot]; int type = weaponToFill->getWeaponInfo()->getAmmoType(0); if(type == AMMO_NONE)return 0; if(ammo[type] == 0)return 0; if(weaponToFill->getWeaponInfo()->isSingleReload() && (!ignoreSingle) && rulesDoWeaponsReload()) { if(weaponToFill->getClip() >= weaponToFill->getWeaponInfo()->getClipSize()) { // Already full. return 0; } if(noFillForSingle) { // Strangeness with shotgun. return 1; } if(ammo[type]) { ammo[type] --; weaponToFill->setClip(weaponToFill->getClip() + 1); } } else { if(rulesDoReloadEmptiesWeapon()) { // Clip simulator for realistic stuff. if(ammo[type] > weaponToFill->getWeaponInfo()->getClipSize()) { ammo[type] -= weaponToFill->getWeaponInfo()->getClipSize(); weaponToFill->setClip(weaponToFill->getWeaponInfo()->getClipSize()); } else { weaponToFill->setClip(ammo[type]); ammo[type] = 0; } } else if(ammo[type] > weaponToFill->getWeaponInfo()->getClipSize() - weaponToFill->getClip()) { ammo[type] -= weaponToFill->getWeaponInfo()->getClipSize() - weaponToFill->getClip(); weaponToFill->setClip(weaponToFill->getWeaponInfo()->getClipSize()); } else { weaponToFill->setClip(weaponToFill->getClip() + ammo[type]); ammo[type] = 0; } } return 1; } int inven_c::adjustDamageByArmor(int initDamage, float penetrate, float absorb) { if(!armor) { return initDamage; } // Take absorbtion into account. initDamage -= (initDamage * absorb); if(penetrate) { int extraDmg = initDamage * 2; if(armor > extraDmg) { armor -= extraDmg; extraDmg = 0; } else { extraDmg -= armor; armor = 0; } // So it just does well against armor, that's all. return extraDmg * .5; } else { if(armor > initDamage) { armor -= initDamage; initDamage = 0; } else { initDamage -= armor; armor = 0; } return initDamage; } return 0; } void inven_c::becomeDisguised(void) { if(!isClient) serverRICBuffer->AddRIC(RIC_HIDEWEAPONFORDISGUISE,""); if(wAnim.disguised()) { // 'Tis a toggle. wAnim.setDisguise(0); } else { wAnim.setDisguise(1); putAway(); // In case we pull it right back out. nextSelectSlot = selectedWeaponSlot; } } //------------------------------------------------------------------------------------------------------------------------ // ANIM FUNCS //------------------------------------------------------------------------------------------------------------------------ int inven_c::fire(void) { char *fireSeq; if((fireSeq = curInfo()->getFireSeq(*owner)) == NULL) return 0; if((!curWeapon()->handleAmmo(*owner, 0))) { if((!isClient)&&isClientPredicting()) pisv.clearFireEvent(owner->edict); if(isClient) fireEvent=1; return 1; } // If ammo is okay, initiate the firing seq. setInputStatus(0); wAnim.setAnimType(WANIM_FIRE); if(!isClient) { if(isClientPredicting()) { if((curWeaponID==SFW_ASSAULTRIFLE)||(curWeaponID==SFW_MACHINEPISTOL)) RunVWeapAnim(owner, fireSeq, getCurWeapon()->getWeaponInfo()->getLoopType()); else RunVWeapAnim(owner, fireSeq, getCurWeapon()->getWeaponInfo()->getLoopType(),pisv.getFireEvent(owner->edict)); pisv.clearFireEvent(owner->edict); } else { RunVWeapAnim(owner, fireSeq, getCurWeapon()->getWeaponInfo()->getLoopType()); } } else { RunVWeapAnim(owner, fireSeq, getCurWeapon()->getWeaponInfo()->getLoopType()); fireEvent=1; } return 1; } int inven_c::altFire(void) { if(!curInfo()->hasAltFire()) { // Well, not everything can do this. return 0; } char *altFireSeq; if((altFireSeq = curInfo()->getAltFireSeq(*owner)) == NULL) return 0; if(!curWeapon()->handleAmmo(*owner, 1)) { if((!isClient)&&isClientPredicting()) pisv.clearAltfireEvent(owner->edict); if(isClient) altfireEvent=1; return 1; } // If ammo is okay, initiate the altfiring seq. setInputStatus(0); wAnim.setAnimType(WANIM_ALTFIRE); if(!isClient) { if(isClientPredicting()) { if(curWeaponID==SFW_ROCKET) RunVWeapAnim(owner, altFireSeq, IGhoulInst::Hold); else RunVWeapAnim(owner, altFireSeq, IGhoulInst::Hold,pisv.getAltfireEvent(owner->edict)); pisv.clearAltfireEvent(owner->edict); } else { RunVWeapAnim(owner, altFireSeq, IGhoulInst::Hold); } } else { RunVWeapAnim(owner, altFireSeq, IGhoulInst::Hold); altfireEvent=1; } return 1; } int inven_c::clientReload(void) { fireEvent=0; altfireEvent=0; char *reloadSeq; if((reloadSeq = curInfo()->getReloadSeq(*owner)) == NULL) return 0; // Reloading recenters the weapon. wAnim.clearFireLoop(); if(curInfo()->testReloadAtInit(*owner)) { if(!refillCurClip(curWeaponSlot)) { dryfire(); if(!curWeapon()->getClip()) { // Totally out of ammo, so do nothing and wait for server to // change our weapon. ; } return 0; } } if(rulesDoWeaponsReload()) { if(!isClient) pisv.ShowReload(owner->edict); setInputStatus(0); wAnim.setAnimType(WANIM_RELOAD); RunVWeapAnim(owner, reloadSeq, IGhoulInst::Hold); } else idle(); return 1; } int inven_c::reload(void) { if(isClient) { // Client always told to do this via clientReload(). return 0; } pisv.clearFireEvent(owner->edict); pisv.clearAltfireEvent(owner->edict); char *reloadSeq; if((curWeapon()->getClip() == curInfo()->getClipSize()) && (!rulesDoReloadEmptiesWeapon())) { // Already full.... return 0; } if((reloadSeq = curInfo()->getReloadSeq(*owner)) == NULL) return 0; // Reloading recenters the weapon. wAnim.clearFireLoop(); if(curInfo()->testReloadAtInit(*owner)) { if(!refillCurClip(curWeaponSlot)) { dryfire(); if(!curWeapon()->getClip()) { // Totally out of ammo, so change weapons (if possible). addCommand("weaponbestsafe",true); if(getWeaponNum(nextCommand)!=-1) return 0; } // Tell client to reload. owner->edict->client->ps.gunReload++; return 0; } } if(rulesDoWeaponsReload()) { if(!isClient) pisv.ShowReload(owner->edict); setInputStatus(0); wAnim.setAnimType(WANIM_RELOAD); RunVWeapAnim(owner, reloadSeq, IGhoulInst::Hold); } else idle(); // Tell client to reload. owner->edict->client->ps.gunReload++; return 1; } int inven_c::putAway(void) { curInfo()->shutdownWeapon(*owner); char *putAwaySeq; if((putAwaySeq = curInfo()->getPutAwaySeq(*owner)) == NULL) { SelectPendingWeapon(); takeOut(); return 0; } if((!isClient)&&isClientPredicting()) readyNextWeapon(); setInputStatus(0); wAnim.setAnimType(WANIM_PUTAWAY); RunVWeapAnim(owner, putAwaySeq, IGhoulInst::Hold); return 1; } int inven_c::takeOut(void) { // Ensure no weapon fires on taking new weapon out. if(!isClient) { pisv.clearFireEvent(getOwner()->edict); pisv.clearAltfireEvent(getOwner()->edict); } else { fireEvent=0; altfireEvent=0; } if(isClient) newInstRxd=0; char *takeOutSeq; if((takeOutSeq = curInfo()->getTakeOutSeq(*owner)) == NULL) { idle(); return 0; } setInputStatus(0); wAnim.setAnimType(WANIM_NORMAL); RunVWeapAnim(owner, takeOutSeq, IGhoulInst::Hold); return 1; } int inven_c::idle(void) { char *idleSeq; if((idleSeq = curInfo()->getIdleSeq(*owner)) == NULL) return 0; setInputStatus(1); wAnim.setAnimType(WANIM_NORMAL); RunVWeapAnim(owner, idleSeq, IGhoulInst::Hold); return 1; } void inven_c::idleReadied(void) { char *idleSeq; if((idleSeq = weapInfo[readiedWeaponType]->getIdleSeq(*owner)) == NULL) return; setInputStatus(1); wAnim.setAnimType(WANIM_NORMAL); RunReadiedVWeapAnim(owner, idleSeq, IGhoulInst::Hold); } int inven_c::dryfire(void) { char *dryfireSeq; if((dryfireSeq = curInfo()->getDryfireSeq(*owner)) == NULL) { idle(); return 1; } setInputStatus(0); wAnim.setAnimType(WANIM_NORMAL); RunVWeapAnim(owner, dryfireSeq, IGhoulInst::Hold); return 1; } int inven_c::loseWeapon(void) { curInfo()->shutdownWeapon(*owner); // Drop what we're holding. setDroppingWeapon(curWeaponSlot); if(!isClient) pisv.WeaponDrop(this->owner->edict,droppingWeapon()->getType(), droppingWeapon()->getClip()); if(!isClient) { removeWeaponFromOwnList(droppingWeapon()->getType()); droppingWeapon()->setType(SFW_EMPTYSLOT); } setDroppingWeapon(-1); // Select 'hand-pain' weapon. SelectPendingWeapon(); // Make sure client is ready for next weapon when it comes down the wire. if(isClient) newInstRxd=0; // Play the takeout sequence for this weapon. On the server ONLY, this ends // with the issue of a PWC_NEXTWEAP. char *takeOutSeq = curInfo()->getTakeOutSeq(*owner); setInputStatus(0); wAnim.setAnimType(WANIM_LOSE); RunVWeapAnim(owner, takeOutSeq, IGhoulInst::Hold); // So we know we are now empty handed. curWeaponID=0; return 1; } static int weaponPrioritySafe[]= { SFW_MICROWAVEPULSE, SFW_MACHINEGUN, SFW_ASSAULTRIFLE, SFW_MACHINEPISTOL, SFW_SHOTGUN, SFW_PISTOL2, SFW_PISTOL1, SFW_SNIPER, SFW_KNIFE, SFW_ROCKET, SFW_AUTOSHOTGUN, SFW_FLAMEGUN, SFW_EMPTYSLOT }; static int weaponPriorityUnsafe[]= { SFW_MICROWAVEPULSE, SFW_ROCKET, SFW_AUTOSHOTGUN, SFW_FLAMEGUN, SFW_MACHINEGUN, SFW_ASSAULTRIFLE, SFW_MACHINEPISTOL, SFW_SHOTGUN, SFW_PISTOL2, SFW_PISTOL1, SFW_SNIPER, SFW_KNIFE, SFW_EMPTYSLOT }; static int weaponUnsafeList[]= { SFW_ROCKET, SFW_AUTOSHOTGUN, SFW_FLAMEGUN, SFW_EMPTYSLOT }; int inven_c::getBestSlot(int safe) { int curTest = 0; int returnWeap = -1; int *weaponPriority; qboolean unsafe=false; // Okay, here's the scoop. If the "safe" param is >= 2, then we've got a // pickup situation. In that case, the pickups act like a "safe best" // weapon pick, except if there is an unsafe weapon up, don't override it. if (safe >= 2) { // Check if the current weapon is unsafe first. while((weaponUnsafeList[curTest] != SFW_EMPTYSLOT) && (!unsafe)) { if (getCurWeaponType() == weaponUnsafeList[curTest]) { unsafe=true; } curTest++; } if (unsafe) { // Return the current weapon... return getCurSlot(); } else { // Otherwise act like a safe weapon. curTest = 0; while((weaponPrioritySafe[curTest] != SFW_EMPTYSLOT) && (returnWeap == -1)) { for(int i = 0; (i < MAXSELECTABLEWEAPONS) && (returnWeap == -1); i++) { if(weapons[i].canSelect(*owner)) { if(weapons[i].getType() == weaponPrioritySafe[curTest]) { returnWeap = i; } } } curTest++; } } } else { weaponPriority=(safe)?weaponPrioritySafe:weaponPriorityUnsafe; while((weaponPriority[curTest] != SFW_EMPTYSLOT) && (returnWeap == -1)) { for(int i = 0; (i < MAXSELECTABLEWEAPONS) && (returnWeap == -1); i++) { if(weapons[i].canSelect(*owner)) { if(weapons[i].getType() == weaponPriority[curTest]) { returnWeap = i; } } } curTest++; } } return returnWeap; } int inven_c::getBestWeaponType(void) { if (!strcmp(rulesGetBestWeaponMode(),"safe")) { // The mode is for the unusual safe selection. return(weapons[getBestSlot(2)].getType()); } else { // Go for non-safe weaponry normally. return(weapons[getBestSlot(0)].getType()); } } int inven_c::getClipMaxByType(int weapon) { return(weapInfo[weapon]->getClipSize()); } int inven_c::getWeaponNum(int cmd) { if(!isClient) { // No point finding a new-weap if we have no weapons. if(!(weaponsOwned&((1<=MAXSELECTABLEWEAPONS)?0:selectedWeaponSlot; returnWeap=startWeap; if(cmd == PWC_WEAPNEXT) { do { returnWeap++; if(returnWeap >= MAXSELECTABLEWEAPONS) { returnWeap = 0; } }while((!weapons[returnWeap].canSelect(*owner,rulesCanSelectWithNoAmmo()))&&(returnWeap != startWeap)); } else if(cmd == PWC_WEAPPREV) { do { returnWeap--; if(returnWeap <= -1) { returnWeap = MAXSELECTABLEWEAPONS - 1; } }while((!weapons[returnWeap].canSelect(*owner,rulesCanSelectWithNoAmmo()))&&(returnWeap != startWeap)); } else if(cmd == PWC_WEAPONBEST_SAFE) { returnWeap = getBestSlot(1); } else if(cmd == PWC_WEAPONBEST_UNSAFE) { returnWeap = getBestSlot(0); } else if(cmd == PWC_LOSE) { returnWeap=MAXSELECTABLEWEAPONS; } else if(cmd == PWC_DROP) { returnWeap=MAXSELECTABLEWEAPONS+1; } else { // Then must be a raw weapon number. returnWeap = cmd - PWC_WEAPSELECTFIRST; if(!weapons[returnWeap].canSelect(*owner,1)) { returnWeap = -1; } } // New weapon same as old? if((startWeap==selectedWeaponSlot)&&(returnWeap==startWeap)) { // Ok, no change. returnWeap = -1; } return returnWeap; } int inven_c::checkCommandInput(void) { if(nextCommand == PWC_NOCOMMAND) return 0; int retVal=0; if(nextCommand == PWC_RELOAD) { // This will only happen on the server. if(rulesDoWeaponsReload()&&reload()) retVal=1; } else if((nextCommand >= PWC_WEAPNEXT)&&(nextCommand < PWC_WEAPSELECTFIRST + MAXSELECTABLEWEAPONS)) { if(isClient&&(!clientOverrideCmd)) { idle(); return(0); } else { if(isClient) clientOverrideCmd=0; int weaponNum=getWeaponNum(nextCommand); if(curWeaponID) { // Ok, we currently have a weapon out... if(weaponNum!=-1) { // ...and we have a valid next weapon so proceed. nextSelectSlot = weaponNum; switch(nextCommand) { case PWC_LOSE: case PWC_DROP: if(rulesGetNonDroppableWeaponTypes()&(1<attack)||(owner->altattack)) { wAnim.setDisguise(0); } else { // Swap stuff around properly. if((nextCommand >= PWC_WEAPNEXT)&&(nextCommand < PWC_WEAPSELECTFIRST + MAXSELECTABLEWEAPONS)) { switch(nextCommand) { case PWC_LOSE: case PWC_DROP: break; default: int weaponNum=getWeaponNum(nextCommand); if(weaponNum != -1) nextSelectSlot = weaponNum; break; } nextCommand=PWC_NOCOMMAND; } } } if(owner->cinematicFreeze) { // Clear out input to make everything behave. owner->altattack = 0; owner->attack = 0; owner->leanLeft = 0; owner->leanRight = 0; owner->weap3 = 0; owner->weap4 = 0; } curInfo()->testInput(*owner); // Always return during cinematics. if(owner->cinematicFreeze) return; // Active sequences (e.g. fire) may prevent command input. if(!isClient) { // Server always wants to return if this is the case... if(!canHandleInput) return; } else { // Client may need to overide current predicted sequence (e.g. fire) if // instructed to do so by server. if((!clientOverrideCmd)&&(!canHandleInput)) return; } if(checkCommandInput()) { // Check for inventory command input. return; } if(!model) return; // Check for attack. qboolean doAttack=false; if((!isClient)&&(!isClientPredicting())) { if(owner->attack) doAttack=true; } else { if((isClient&&(owner->attack))||((!isClient)&&(pisv.getFireEvent(owner->edict)))) doAttack=true; } if(doAttack) { if(fire()) return; } // Check for altattack. qboolean doAltAttack=false; if((!isClient)&&(!isClientPredicting())) { if(owner->altattack) doAltAttack=true; } else { if((isClient&&(owner->altattack))||((!isClient)&&(pisv.getAltfireEvent(owner->edict)))) doAltAttack=true; } if(doAltAttack) { if(altFire()) return; } } void inven_c::handleModelChange() { if(wAnim.disguised()) { // Can't get out our new weapon until we are no longer being sneaky. return; } if(isClient) { // Client side version... if(((IGhoul *)picl.GetGhoul())->FindClientInst(owner->edict->client->ps.gunUUID)) { // We need this test because of the latency involved in receiving new // ghoul instances from server. I.e. we want to be sure that we have // the new instance from the server before proceeding to create a new // PRIVATE client view weapon (by cloning the server owned instance). // In the event that the new instance has not been recieved yet, the // weapon code will remain in a 'supended' state as long as the member // variable 'pendingChange' is non zero. if(!owner->edict->client->ps.gun->GetUserData()) { if(pendingChange) { // The new weapon has been selected (and the previous one // put away), so take out the new weapon. SelectPendingWeapon(); takeOut(); pendingChange = 0; if(droppingWeapon()) setDroppingWeapon(-1); } else if(newInstRxd==0) { // We have just gotten a new weapon instance from the server, so // issue a command to select this weapon. if(owner->edict->client->ps.gunTypeedict->client->ps.gunType) break; } weapon_c *weaponToFill = &weapons[i]; int type = weaponToFill->getWeaponInfo()->getAmmoType(0); ammo[type]=owner->edict->client->ps.gunAmmo; weaponToFill->setClip(owner->edict->client->ps.gunClip); nextCommand=PWC_WEAPSELECTFIRST+i; } else { // Special "throw weapon away" animation. nextCommand=PWC_LOSE+(owner->edict->client->ps.gunType-SFW_HURTHAND); } clientOverrideCmd=1; newInstRxd=1; if(model) idle(); } } } } else { // Server side version... if(pendingChange) { if(isClientPredicting()) SelectRediedWeapon(); else SelectPendingWeapon(); takeOut(); pendingChange = 0; if(droppingWeapon()) { if(!isClient) pisv.WeaponDrop(this->owner->edict,droppingWeapon()->getType(), droppingWeapon()->getClip()); removeWeaponFromOwnList(droppingWeapon()->getType()); droppingWeapon()->setType(SFW_EMPTYSLOT); setDroppingWeapon(-1); } } } } void inven_c::frameUpdate(void) { if(isClient) { fireEvent=0; altfireEvent=0; if(owner->doReload) { owner->doReload=0; clientReload(); } getServerState(); } handleModelChange(); handleInput(); sharedEdict_t *saved=owner; sharedEdict_t sh; sh.inv=(inven_c *)this; if(model) { if(!isClient) model->ServerUpdate(*(pisv.levelTime) + .001); else model->ServerUpdate(*(picl.levelTime) + .001); } sh.inv->setOwner(saved); if((!isClient)&&(!readiedWeaponID)) setServerState(); items.frameUpdate(*owner); } int inven_c::addCommand(char *string,qboolean internal) { char *s=picom.Cmd_Args(); if(!isClient) { // Server... if(getInputStatus()<0) { // Don't want any crappy messages popping up as chat, just 'cos the // system isn't ready to accept inventory commands. return 1; } // Sometimes we want to prevent sources outside of the player.dll from // executing weapon select commands (e.g. arsenal). int denied=((!internal)&&(!rulesCanFreelySelectWeapon()))?-1:0; if (stricmp (string, "reload") == 0) { nextCommand = PWC_RELOAD; } else if (stricmp (string, "weapprev") == 0) { if(denied) return 1; nextCommand = PWC_WEAPPREV; } else if (stricmp (string, "weapnext") == 0) { if(denied) return 1; nextCommand = PWC_WEAPNEXT; } else if (stricmp (string, "weaponselect") == 0) { if(denied) return 1; if(s[0]) nextCommand = PWC_WEAPSELECTFIRST + atoi(s)-1; } else if (stricmp (string, "weapondrop") == 0) { if(rulesCanDropWeapons()) { nextCommand = PWC_DROP; } else { // Command weapondrop is valid but not allowed to drop weapons. // So we don't want anything printed as an unrecognised command. return 1; } } else if (stricmp (string, "weaponlose") == 0) { if(rulesCanDropWeapons()) { nextCommand = PWC_LOSE; } else { // Command weaponloose is valid but not allowed to drop weapons. // So we don't want anything printed as an unrecognised command. return 1; } } else if (stricmp (string, "weaponbestsafe") == 0) { if(denied) return 1; nextCommand = PWC_WEAPONBEST_SAFE; } else if (stricmp (string, "weaponbestunsafe") == 0) { if(denied) return 1; nextCommand = PWC_WEAPONBEST_UNSAFE; } else if (stricmp (string, "itemuse") == 0) { if(s[0]) { // Try to use named item (shortcut key). int i=items.getSlotNumFromName(s); if(i>=0) { // Ok, use specified item. items.setNextCommand(PEC_USEITEMFIRST+i); } else if(i==-2) { // Named item doesn't exist (no such item type). return 0; } } else { // Use currently selected item. items.setNextCommand(PEC_USEITEM); } } else if (stricmp (string, "itemnext") == 0) { items.setNextCommand(PEC_ITEMNEXT); } else if (stricmp (string, "itemprev") == 0) { items.setNextCommand(PEC_ITEMPREV); } else if (stricmp (string, "itemdrop") == 0) { items.setNextCommand(PEC_DROP); } else { return 0; } } else { // Client... (does nowt). return 0; } return 1; } /* List of weapons (with ammo) Knife - aknife Pistol1 - a9mm Pistol2 - a9mm (possibly a44) Mpistol - a9mm Assault - a556 Sniper - a556 Slugger - Shells Shotgun - Shells Machinegun - a556 Flamegun - Fuel Rocket - Rockets Mpg - Battery Items Flashpak C4 Armor Neural Claymore goggles Ammo aknife a9mm a556 a44 Shells Rockets Battery Fuel */ char *weaponList[] = { "nothing", "knife", "pistol2", "pistol1", "mpistol", "assault", "sniper", "slugger", "shotgun", "machinegun", "rocket", "mpg", "flamegun", 0 }; //AMMO_NONE = 0, //AMMO_KNIFE, //AMMO_44, //AMMO_9MM, //AMMO_SHELLS, //AMMO_556, //AMMO_ROCKET, //AMMO_MWAVE, //AMMO_FTHROWER, //AMMO_SLUG, char *ammoList[] = { "nothing", "aknife", "a44", "a9mm", "shells", "a556", "rockets", "battery", "fuel", "slug", 0 }; //armor is a special case, I suppose char *itemList[] = { "nothing", "fpak", // "neural", "c4", "goggles", "claymore", "medkit", "grenade", 0 }; #define ORDERLISTSIZE 12 int weaponOrder[] = { SFW_KNIFE, SFW_PISTOL1, SFW_PISTOL2, SFW_SHOTGUN, SFW_SNIPER, SFW_MACHINEPISTOL, SFW_ASSAULTRIFLE, SFW_MACHINEGUN, SFW_AUTOSHOTGUN, SFW_ROCKET, SFW_MICROWAVEPULSE, SFW_FLAMEGUN, }; //health parm is the health extracted from the menu as we don't have access to the game-side health edict field int inven_c::extractInvFromMenu(int *weaponsAvailable, int *health) { char *curSpot; char *curTokSpot; char token[256]; char temp[256]; int value; int weaponsToAdd = 0; char buffer[1024]; if(isClient) { return 0; // None of this for you!! } //assume curSpot is somewhere decent curSpot = pisv.CvarInfo(CVAR_WEAPON | CVAR_ITEM | CVAR_AMMO | CVAR_MISC); if(!curSpot || (!strcmp(curSpot, ""))) { // if there is nothing, plug in the defaults return 0; } while(*curSpot) { curTokSpot = token; if(*curSpot == '\\') { curSpot++; } while(*curSpot && (*curSpot != '\\')) { *curTokSpot++ = *curSpot++; } *curTokSpot = 0; assert(*curSpot); if(*curSpot == '\\') { curSpot++; } curTokSpot = temp; while((*curSpot) && (*curSpot != '\\')) { *curTokSpot++ = *curSpot++; } *curTokSpot = 0; value = atoi(temp); // okay, we have the two tokens... let's do stuff with them now... char *testString; int curCheck; int found = 0; // look for weapons curCheck = 0; do { testString = weaponList[curCheck]; if(!stricmp(token, testString)) { // hey, I have one of these! Cool! if(value) {// add the weapon //addWeaponType(curCheck); weaponsToAdd |= (1<getAmmoType(0) < MAXAMMOS); assert(weapons[i].getWeaponInfo()->getAmmoType(0) > -1); if(includeClipAmmo) { //end of level needs this - within level does not ammo[weapons[i].getWeaponInfo()->getAmmoType(0)] += weapons[i].getClip(); } sprintf(buffer, "set %s 1 w;", weaponList[curWeapType]); pisv.AddCommand(buffer); } } // now list what ammo is currently being carried for(i = 1; i < MAXAMMOS; i++) { sprintf(buffer, "set %s %d a;", ammoList[i], ammo[i]); pisv.AddCommand(buffer); } // now list what items, and their amounts, are being carried for(i = 0; i < MAXITEMS; i++) { itemSlot_c *curSlot = items.getSlot(i); if(curSlot->getSlotType() != SFE_EMPTYSLOT) { sprintf(buffer, "set %s %d i;", itemList[curSlot->getSlotType()], curSlot->getSlotCount()); pisv.AddCommand(buffer); } } // write out armor too, I suppose sprintf(buffer, "set armor %d i;", armor); pisv.AddCommand(buffer); // write out health too, I suppose sprintf(buffer, "set health %d m;", health); pisv.AddCommand(buffer); } int inven_c::extractInvFromString(int *weaponsAvailable,char *invString) { char *curSpot; char *curTokSpot; char token[256]; char temp[256]; int value; int weaponsToAdd = 0; if(isClient) { // None of this for you Mr Client side!! return 0; } curSpot = invString; if(!curSpot || (!strcmp(curSpot, ""))) { // If there is nothing, do nothing. return 0; } while(*curSpot) { curTokSpot = token; if(*curSpot == '\\') { curSpot++; } while(*curSpot && (*curSpot != '\\')) { *curTokSpot++ = *curSpot++; } *curTokSpot = 0; if(*curSpot == '\\') { curSpot++; } curTokSpot = temp; while((*curSpot) && (*curSpot != '\\')) { *curTokSpot++ = *curSpot++; } *curTokSpot = 0; value = atoi(temp); // Okay, we have the two tokens... let's do stuff with them now... char *testString; int curCheck; int found = 0; // Look for weapons. curCheck = 0; do { testString = weaponList[curCheck]; if(!stricmp(token, testString)) { // Hey, I have one of these! Cool! if(value) { // Add the weapon. weaponsToAdd |= (1<getAmmoType(0) < MAXAMMOS); assert(weapons[i].getWeaponInfo()->getAmmoType(0) > -1); ammo[weapons[i].getWeaponInfo()->getAmmoType(0)] += weapons[i].getClip(); sprintf(buffer, "%s\\1\\", weaponList[curWeapType]); strcat(string,buffer); //FIXME } } } if(xtractAmmo) { // Now list what ammo is currently being carried. for(int i = 1; i < MAXAMMOS; i++) { sprintf(buffer, "%s\\%d\\", ammoList[i], ammo[i]); strcat(string,buffer);//FIXME } } if(xtractItems) { // Now list what items, and their amounts, are being carried. for(int i = 0; i < MAXITEMS; i++) { itemSlot_c *curSlot = items.getSlot(i); if(curSlot->getSlotType() != SFE_EMPTYSLOT) { sprintf(buffer, "%s\\%d\\", itemList[curSlot->getSlotType()], curSlot->getSlotCount()); strcat(string,buffer);//FIXME } } } if(xtractArmor) { // Write out armor too, I suppose. sprintf(buffer, "armor\\%d\\", armor); strcat(string,buffer);//FIXME } } void inven_c::stockWeapons(void) { // Go through all your possessions and ensure that they are filled with tasty ammo. for(int i = 0; i < MAXSELECTABLEWEAPONS; i++) { if(weapons[i].getType() != SFW_EMPTYSLOT) refillCurClip(i, 1, 0); } } void inven_c::setBloodyWeapon(int isBloody) { if(!wAnim.getBloody()) { if(!isClient) serverRICBuffer->AddRIC(RIC_SETBLOODYWEAPON,"i",isBloody); curInfo()->setBloody(owner); wAnim.setBloody(1); } } int inven_c::rulesDoWeaponsUseAmmo(void) { return(rulesWeaponsUseAmmo); } void inven_c::rulesSetWeaponsUseAmmo(int useAmmo) { if(!isClient) serverRICBuffer->AddRIC(RIC_RULESSETWEAPONSUSEAMMO,"i",useAmmo); rulesWeaponsUseAmmo=useAmmo; } int inven_c::rulesCanDropWeapons(void) { return(rulesDropWeapons); } void inven_c::rulesSetDropWeapons(int dropWeapons) { rulesDropWeapons=dropWeapons; } int inven_c::rulesGetNonDroppableWeaponTypes(void) { return(rulesNonDroppableWeaponTypes); } void inven_c::rulesSetNonDroppableWeaponTypes(int nonDropMask) { rulesNonDroppableWeaponTypes=(nonDropMask|(1<AddRIC(RIC_RULESSETWEAPONSRELOAD,"i",weaponsReload); rulesWeaponsReload=weaponsReload; } int inven_c::rulesIsWeaponReloadAutomatic(void) { return(rulesWeaponReloadAutomatic); } void inven_c::rulesSetWeaponReloadAutomatic(int reloadAutomatic) { if(!isClient) serverRICBuffer->AddRIC(RIC_RULESSETWEAPONRELOADAUTOMATIC,"i",reloadAutomatic); rulesWeaponReloadAutomatic=reloadAutomatic; } int inven_c::rulesDoReloadEmptiesWeapon(void) { return(rulesReloadEmptiesWeapon); } void inven_c::rulesSetReloadEmptiesWeapon(int reloadEmptiesWeapon) { if(!isClient) serverRICBuffer->AddRIC(RIC_RULESSETRELOADEMPTIESWEAPON,"i",reloadEmptiesWeapon); rulesReloadEmptiesWeapon=reloadEmptiesWeapon; } char *inven_c::rulesGetBestWeaponMode(void) { return(rulesBestWeaponMode); } void inven_c::rulesSetBestWeaponMode(char *bestWeaponMode) { int len=strlen(bestWeaponMode); len=(len<5)?len:4; memcpy(rulesBestWeaponMode,bestWeaponMode,len); rulesBestWeaponMode[len]=0; } int inven_c::rulesCanDropInvenOnDeath(void) { return(rulesDropInvenOnDeath); } void inven_c::rulesSetDropInvenOnDeath(int dropInvenOnDeath) { rulesDropInvenOnDeath=dropInvenOnDeath; } int inven_c::rulesCanSelectWithNoAmmo(void) { return(rulesSelectWithNoAmmo); } void inven_c::rulesSetSelectWithNoAmmo(int selectWithNoAmmo) { rulesSelectWithNoAmmo=selectWithNoAmmo; } int inven_c::rulesCanFreelySelectWeapon(void) { return(rulesFreelySelectWeapon); } void inven_c::rulesSetFreelySelectWeapon(int freelySelectWeapon) { rulesFreelySelectWeapon=freelySelectWeapon; } weaponInfo_c *inven_c::curInfo(void) { return weapInfo[curWeaponType]; } weaponInfo_c *inven_c::readiedInfo(void) { return weapInfo[readiedWeaponType]; } weapon_c *inven_c::curWeapon(void) { return &weapons[curWeaponSlot]; } weapon_c *inven_c::readiedWeapon(void) { return &weapons[readiedWeaponSlot]; } void inven_c::clientClearRICs(void) { clientRICBuffer->ClearRICs(); } void inven_c::clientReadRICs(void) { clientRICBuffer->ReadRICs(); } void inven_c::clientProcessRICs(void) { clientRICBuffer->ProcessRICs(); } void inven_c::serverClearRICs(void) { serverRICBuffer->ClearRICs(); } void inven_c::serverWriteRICs(void) { serverRICBuffer->WriteRICs(); } inven_c *W_NewInv(void) { return(new inven_c); } void W_KillInv(inven_c *inven) { delete(inven); } void RefreshWeapon(inven_c *inven) { if(isClient) return; // Set object to NULL to force a reload. inven->getCurWeapon()->getWeaponInfo()->setGhoulObj(NULL); // Reload weapon. inven->initNewWeapon(); // Hack for sniper rifle. I don't care anymore thankyou. IGhoulInst *gun=inven->getViewModel(); if(gun) gun->SetAllPartsOnOff(inven->scopeIsActive()?false:true); } inven_c::inven_c(inven_c *orig) { int i; nextCommand = orig->nextCommand; clientOverrideCmd = orig->clientOverrideCmd; newInstRxd = orig->newInstRxd; nextSelectSlot = orig->nextSelectSlot; curWeaponID = orig->curWeaponID; curWeaponType = orig->curWeaponType; curWeaponSlot = orig->curWeaponSlot; readiedWeaponID = orig->readiedWeaponID; readiedWeaponType = orig->readiedWeaponType; readiedWeaponSlot = orig->readiedWeaponSlot; droppingSlot = orig->droppingSlot; for(i = 0; i < MAXWEAPONS; i++) { weapons[i] = orig->weapons[i]; } rulesWeaponsUseAmmo = orig->rulesWeaponsUseAmmo; rulesDropWeapons = orig->rulesDropWeapons; rulesNonDroppableWeaponTypes = orig->rulesNonDroppableWeaponTypes; rulesWeaponsReload = orig->rulesWeaponsReload; rulesReloadEmptiesWeapon = orig->rulesReloadEmptiesWeapon; rulesWeaponReloadAutomatic = orig->rulesWeaponReloadAutomatic; rulesDropInvenOnDeath = orig->rulesDropInvenOnDeath; rulesSelectWithNoAmmo = orig->rulesSelectWithNoAmmo; for(i = 0; i < 5; i++) { rulesBestWeaponMode[i] = orig->rulesBestWeaponMode[i]; } rulesFreelySelectWeapon = orig->rulesFreelySelectWeapon; for(i = 0; i < MAXAMMOS; i++) { ammo[i] = orig->ammo[i]; } canHandleInput = orig->canHandleInput; model = NULL; // This is always recreated from scratch readyModel = NULL; selectedWeaponSlot = orig->selectedWeaponSlot; armor = orig->armor; weaponsOwned = orig->weaponsOwned; pendingChange = orig->pendingChange; clientPredicting = orig->clientPredicting; gunEnd = orig->gunEnd; owner = NULL; items = orig->items; wAnim = orig->wAnim; clientRICBuffer = NULL; serverRICBuffer = NULL; } void inven_c::Evaluate(inven_c *orig) { int i; nextCommand = orig->nextCommand; clientOverrideCmd = orig->clientOverrideCmd; newInstRxd = orig->newInstRxd; nextSelectSlot = orig->nextSelectSlot; curWeaponID = orig->curWeaponID; curWeaponType = orig->curWeaponType; curWeaponSlot = orig->curWeaponSlot; readiedWeaponID = orig->readiedWeaponID; readiedWeaponType = orig->readiedWeaponType; readiedWeaponSlot = orig->readiedWeaponSlot; droppingSlot = orig->droppingSlot; for(i = 0; i < MAXWEAPONS; i++) { weapons[i] = orig->weapons[i]; } rulesWeaponsUseAmmo = orig->rulesWeaponsUseAmmo; rulesDropWeapons = orig->rulesDropWeapons; rulesNonDroppableWeaponTypes = orig->rulesNonDroppableWeaponTypes; rulesWeaponsReload = orig->rulesWeaponsReload; rulesReloadEmptiesWeapon = orig->rulesReloadEmptiesWeapon; rulesWeaponReloadAutomatic = orig->rulesWeaponReloadAutomatic; rulesDropInvenOnDeath = orig->rulesDropInvenOnDeath; rulesSelectWithNoAmmo = orig->rulesSelectWithNoAmmo; for(i = 0; i < 5; i++) { rulesBestWeaponMode[i] = orig->rulesBestWeaponMode[i]; } rulesFreelySelectWeapon = orig->rulesFreelySelectWeapon; for(i = 0; i < MAXAMMOS; i++) { ammo[i] = orig->ammo[i]; } canHandleInput = orig->canHandleInput; model = NULL; // This is always recreated from scratch readyModel = NULL; selectedWeaponSlot = orig->selectedWeaponSlot; armor = orig->armor; weaponsOwned = orig->weaponsOwned; pendingChange = orig->pendingChange; clientPredicting = orig->clientPredicting; gunEnd = orig->gunEnd; owner = NULL; items = orig->items; wAnim = orig->wAnim; } void inven_c::NetRead(sizebuf_t *net_message_ptr) { char loaded[sizeof(inven_c)]; picl.ReadDataSizebuf(net_message_ptr, (byte *)(loaded + INVEN_SAVE_START), sizeof(inven_c) - INVEN_SAVE_START); Evaluate((inven_c *)loaded); clientPredicting=0; // FIXME: check for other fields that need to be cleared out (so that the // system will settle back into a stable state). model=0; readyModel=0; } void inven_c::NetWrite(int clientnum) { inven_c *tosend; byte *save_start; tosend = new inven_c(this); save_start = (byte *)this; pisv.ReliableWriteDataToClient(save_start + INVEN_SAVE_START, sizeof(*this) - INVEN_SAVE_START, clientnum); delete tosend; } void inven_c::Read(void) { char loaded[sizeof(inven_c)]; pisv.ReadFromSavegame('INVN', loaded + INVEN_SAVE_START, sizeof(inven_c) - INVEN_SAVE_START); Evaluate((inven_c *)loaded); } void inven_c::Write(void) { inven_c *savable; byte *save_start; savable = new inven_c(this); save_start = (byte *)savable; pisv.AppendToSavegame('INVN', save_start + INVEN_SAVE_START, sizeof(*this) - INVEN_SAVE_START); delete savable; } // end