Files
DoomRTX/neo/prey/Prey/game_itemcabinet.cpp
T
2026-05-05 15:01:01 -07:00

418 lines
9.8 KiB
C++

#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef EV_GiveItems("<giveItems>", "e");
/***********************************************************************
hhItemCabinet
***********************************************************************/
const idEventDef EV_EnableItemClip( "<enableItemClip>" );
CLASS_DECLARATION( hhAnimatedEntity, hhItemCabinet )
EVENT( EV_Activate, hhItemCabinet::Event_Activate )
EVENT( EV_EnableItemClip, hhItemCabinet::Event_EnableItemClip )
EVENT( EV_Broadcast_AppendFxToList, hhItemCabinet::Event_AppendFxToIdleList )
EVENT( EV_PostSpawn, hhItemCabinet::Event_PostSpawn ) //rww
END_CLASS
/*
================
hhItemCabinet::hhItemCabinet
================
*/
hhItemCabinet::hhItemCabinet() {
}
/*
================
hhItemCabinet::Spawn
================
*/
void hhItemCabinet::Spawn() {
animDoneTime = 0;
GetPhysics()->SetContents( CONTENTS_BODY );
ResetItemList();
InitBoneInfo();
if (!gameLocal.isClient) {
PostEventMS(&EV_PostSpawn, 0);
}
StartSound( "snd_idle", SND_CHANNEL_IDLE );
}
/*
================
hhItemCabinet::Event_PostSpawn
================
*/
void hhItemCabinet::Event_PostSpawn(void) {
SpawnIdleFX();
}
/*
================
hhItemCabinet::~hhItemCabinet
================
*/
hhItemCabinet::~hhItemCabinet() {
for( int i = 0; i < CABINET_MAX_ITEMS; i++) {
SAFE_REMOVE( itemList[i] );
}
hhUtils::RemoveContents< idEntityPtr<idEntityFx> >( idleFxList, true );
StopSound( SND_CHANNEL_IDLE );
}
/*
================
hhItemCabinet::InitBoneInfo
================
*/
void hhItemCabinet::InitBoneInfo() {
boneList[0] = idStr( spawnArgs.GetString("bone_shelfTop") );
boneList[1] = idStr(spawnArgs.GetString("bone_shelfMiddle") );
boneList[2] = idStr(spawnArgs.GetString("bone_shelfBottom") );
}
void hhItemCabinet::Save(idSaveGame *savefile) const {
savefile->WriteInt( animDoneTime );
int num = idleFxList.Num();
savefile->WriteInt( num );
for( int i = 0; i < num; i++ ) {
idleFxList[i].Save( savefile );
}
for( int i = 0; i < CABINET_MAX_ITEMS; i++ ) {
itemList[i].Save( savefile );
}
for( int i = 0; i < CABINET_MAX_ITEMS; i++ ) {
savefile->WriteString( boneList[i] );
}
}
void hhItemCabinet::Restore( idRestoreGame *savefile ) {
savefile->ReadInt( animDoneTime );
int num;
savefile->ReadInt( num );
idleFxList.Clear();
idleFxList.SetNum( num );
for( int i = 0; i < num; i++ ) {
idleFxList[i].Restore( savefile );
}
for( int i = 0; i < CABINET_MAX_ITEMS; i++ ) {
itemList[i].Restore( savefile );
}
for( int i = 0; i < CABINET_MAX_ITEMS; i++ ) {
savefile->ReadString( boneList[i] );
}
}
/*
================
hhItemCabinet::PlayAnim
================
*/
void hhItemCabinet::PlayAnim( const char* pAnimName, int iBlendTime ) {
PlayAnim( GetAnimator()->GetAnim(pAnimName), iBlendTime );
}
/*
================
hhItemCabinet::PlayAnim
================
*/
void hhItemCabinet::PlayAnim( int pAnim, int iBlendTime ) {
int iAnimLength = 0;
if( pAnim ) {
animator.ClearAllAnims( gameLocal.GetTime(), 0 );
animator.PlayAnim( ANIMCHANNEL_ALL, pAnim, gameLocal.GetTime(), iBlendTime );
iAnimLength = GetAnimator()->GetAnim( pAnim )->Length();
}
animDoneTime = gameLocal.GetTime() + iAnimLength;
}
/*
================
hhItemCabinet::SpawnIdleFX
================
*/
void hhItemCabinet::SpawnIdleFX() {
hhUtils::RemoveContents< idEntityPtr<idEntityFx> >( idleFxList, true );
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_idle"), spawnArgs.GetString("bone_idleRight"), NULL, &EV_Broadcast_AppendFxToList );
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_idle"), spawnArgs.GetString("bone_idleLeft"), NULL, &EV_Broadcast_AppendFxToList );
}
//=============================================================================
//
// hhItemCabinet::SpawnDefaultItems
//
//=============================================================================
bool hhItemCabinet::SpawnDefaultItems() {
idList<idStr> items;
if ( spawnArgs.GetString( "items", NULL ) ) {
hhUtils::SplitString( idStr(spawnArgs.GetString( "items" )), items );
int slot = 0;
for( int i = 0; i < items.Num(); i++ ) {
AddItem( items[i], slot );
if ( ++slot >= CABINET_MAX_ITEMS ) {
return true;
}
}
return true;
}
return false; // No default items
}
/*
================
hhItemCabinet::SpawnItems
================
*/
void hhItemCabinet::SpawnItems() {
int i;
idStr defaultName;
int numAmmo;
idList<idStr> weaponNames;
idList<int> weaponIndexes;
idList<bool> validWeapon;
idList<float> ammoPercent;
idList<idStr> ammoTypes;
idList<idStr> itemNames;
float total;
bool bAutomatic = true;
if ( !bAutomatic ) { // Items were placed by a designer, so don't automatically add any items
return;
}
// This is the heart of the DDA system:
// list all available weapons that can have ammo in the cabinet and how much ammo the player has
hhPlayer *player = static_cast<hhPlayer *>(gameLocal.GetLocalPlayer());
// Build lists of all valid weapon names, ammo types and ammo names
// Note that all these must line up -- so the first weapon corresponds with the first ammo type and the first item name
hhUtils::SplitString( idStr(spawnArgs.GetString( "weaponNames" )), weaponNames );
hhUtils::SplitString( idStr(spawnArgs.GetString( "ammoTypes" )), ammoTypes );
hhUtils::SplitString( idStr(spawnArgs.GetString( "itemNames" )), itemNames );
numAmmo = weaponNames.Num();
weaponIndexes.SetNum( numAmmo );
validWeapon.SetNum( numAmmo );
ammoPercent.SetNum( numAmmo );
for( i = 0; i < weaponNames.Num(); i++ ) {
weaponIndexes[i] = player->GetWeaponNum( weaponNames[i].c_str() );
}
// compute percentages of each ammo compared to the max allowed
for( i = 0; i < numAmmo; i++ ) {
validWeapon[i] = false;
if ( player->inventory.weapons & (1 << weaponIndexes[i] ) ) {
int ammoIndex = player->inventory.AmmoIndexForAmmoClass( ammoTypes[i].c_str() );
ammoPercent[i] = 1.0f - player->inventory.AmmoPercentage( player, ammoIndex );
if ( ammoPercent[i] == 0.0f ) { // Give full ammo weapons a slight chance
ammoPercent[i] = 0.01f;
}
validWeapon[i] = true;
}
}
// for each slot in the cabinet:
for( int slot = 0; slot < numAmmo; slot++ ) {
if ( gameLocal.random.RandomFloat() < spawnArgs.GetFloat( "emptyChance", "0.15" ) ) { // Chance the slot is empty
continue;
}
// re-compute the total of all percentages
total = 0;
for( i = 0; i < numAmmo; i++ ) {
if ( validWeapon[i] ) {
total += ammoPercent[i];
}
}
// random number from 0 - total
float random = gameLocal.random.RandomFloat() * total;
// calculate which ammo that number is associated with and add that item to the cabinet
for( i = 0; i < numAmmo; i++ ) {
if ( validWeapon[i] ) {
if ( random <= ammoPercent[i] ) { // This is the ammo we want
AddItem( itemNames[i], slot ); // Add the item
ammoPercent[i] *= spawnArgs.GetFloat( "repeatReduce", "0.5" ); // reduce this item's chance of being chosen for the next slot
break; // No need to check further, go to the next slot
}
random -= ammoPercent[i]; // Not the item, so remove this percent and check the next value
}
}
}
}
/*
================
hhItemCabinet::ResetItemList
================
*/
void hhItemCabinet::ResetItemList() {
for( int i = 0; i < CABINET_MAX_ITEMS; i++ ) {
SAFE_REMOVE( itemList[i] );
}
}
/*
================
hhItemCabinet::AddItem
================
*/
void hhItemCabinet::AddItem( idStr itemName, int slot ) {
idDict Args;
hhItem* item = NULL;
if ( slot < 0 || slot >= CABINET_MAX_ITEMS ) {
return;
}
Args.SetBool( "spin", 0 );
Args.SetFloat( "triggersize", 48.0f );
Args.SetFloat( "respawn", 0.0f );
Args.SetBool( "enablePickup", false );
item = static_cast<hhItem *>( gameLocal.SpawnObject( itemName.c_str(), &Args ) );
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_shelf"), boneList[slot] );
// Check if the item should be rotated
bool bRotated = false;
for ( int i = 0; i < spawnArgs.GetInt( "numRotated" ); i++ ) {
if ( !idStr::Icmp( spawnArgs.GetString( va("rotate%d", i) ), itemName.c_str() ) ) {
bRotated = true;
}
}
if( item ) {
const char *boneName = boneList[ slot ];
idVec3 boneOffset;
idMat3 boneAxis;
this->GetJointWorldTransform( boneName, boneOffset, boneAxis );
if ( bRotated ) {
item->SetOrigin( boneOffset + GetAxis()[1] * -14 + GetAxis()[2] * 8 );
item->SetAxis( idMat3( idVec3( 1, 0, 0 ), idVec3( 0, 0, -1), idVec3( 0, 1, 0 ) ) * GetAxis() );
} else {
item->MoveToJoint( this, boneName );
item->SetAxis( GetAxis() );
}
item->BindToJoint( this, boneName, false );
itemList[ slot ] = item;
return;
}
}
/*
===============
hhItemCabinet::HandleSingleGuiCommand
===============
*/
bool hhItemCabinet::HandleSingleGuiCommand( idEntity *entityGui, idLexer *src ) {
idToken token;
if( !src->ReadToken(&token) ) {
return false;
}
if( token == ";" ) {
return false;
}
if( token.Icmp("openCabinet") == 0 ) {
Event_Activate( NULL );
return true;
}
src->UnreadToken( &token );
return false;
}
/*
================
hhItemCabinet::Event_AppendFxToIdleList
================
*/
void hhItemCabinet::Event_AppendFxToIdleList( hhEntityFx* fx ) {
idleFxList.Append( fx );
}
/*
================
hhItemCabinet::Event_Activate
================
*/
void hhItemCabinet::Event_Activate( idEntity* pActivator ) {
if( gameLocal.GetTime() < animDoneTime ) {
return;
}
if ( !SpawnDefaultItems() ) {
SpawnItems();
}
PlayAnim( "open", 0 );
StartSound( "snd_open", SND_CHANNEL_ANY );
PostEventMS( &EV_EnableItemClip, animDoneTime - gameLocal.GetTime() );
ActivateTargets(pActivator);
StartSound( "snd_idle_open", SND_CHANNEL_IDLE );
}
/*
================
hhItemCabinet::Event_EnableItemClip
================
*/
void hhItemCabinet::Event_EnableItemClip() {
for( int i = 0; i < CABINET_MAX_ITEMS; i++ ) {
if( !itemList[i].IsValid() ) {
continue;
}
itemList[i]->EnablePickup();
itemList[i] = NULL;
}
}