//------------------------------------------------------------------------ int CScriptBind_Weapon::SetAmmoCount(IFunctionHandler *pH) { CWeapon *pWeapon = GetWeapon(pH); if (!pWeapon) return pH->EndFunction(); IFireMode* pFireMode = GetRequestedFireMode(pWeapon, pH); if (pFireMode) { if (pH->GetParamType(2) != svtNumber) return pH->EndFunction(); const char *ammoName = 0; if (pH->GetParamType(1) == svtString) pH->GetParam(1, ammoName); IEntityClass* pAmmoType = pFireMode->GetAmmoType(); if (ammoName) pAmmoType = gEnv->pEntitySystem->GetClassRegistry()->FindClass(ammoName); int ammo = 0; pH->GetParam(2, ammo); pWeapon->SetAmmoCount(pAmmoType, ammo); } return pH->EndFunction(); }
void CGameStateRecorder::OnRecordedGameplayEvent(IEntity *pEntity, const GameplayEvent &event, int currentFrame, bool bRecording) { EntityId id; m_currentFrame = currentFrame; int demo_forceGameState = 0; if(!bRecording) { ICVar *pVar = gEnv->pConsole->GetCVar( "demo_force_game_state" ); if(pVar) demo_forceGameState = pVar->GetIVal(); } if(!pEntity || !(id = pEntity->GetId())) return; if(m_IgnoredEvents.size()) if(event.event == m_IgnoredEvents[0]) { m_IgnoredEvents.erase(m_IgnoredEvents.begin()); return; } TGameStates::iterator itActor = m_GameStates.find(id); if(itActor == m_GameStates.end()) { m_GameStates.insert(std::make_pair(id,SActorGameState())); itActor = m_GameStates.find(id); } if(itActor == m_GameStates.end()) { GameWarning("TimeDemo:GameState: actor %s not found in records",pEntity->GetName()); return; } SActorGameState& gstate = itActor->second; switch(event.event) { case eGE_HealthChanged: { gstate.health = event.value; if(!m_bRecording) { CActor *pActor = (CActor*)(gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(id)); if(pActor) { if(m_bLogWarning) { if(CHECK_MISMATCH(pActor->GetHealth(), gstate.health,10)) { if(!gstate.bHealthDifferent) { GameWarning("TimeDemo:GameState: Frame %d - Actor %s - HEALTH mismatch (%d, %d)",m_currentFrame,pEntity->GetName(), static_cast<int>(pActor->GetHealth()), static_cast<int>(gstate.health)); gstate.bHealthDifferent = true; } } else gstate.bHealthDifferent = false; } if( demo_forceGameState) pActor->SetHealth(gstate.health); } } } break; case eGE_WeaponFireModeChanged: { TItemName sel = (event.description); if(sel) { TItemContainer& Items = gstate.Items; TItemContainer::iterator iti = Items.find(sel); uint8 recFireModeIdx = uint8(event.value); if(iti != Items.end()) iti->second.fireMode = recFireModeIdx; CActor *pActor = (CActor*)(gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(id)); if(pActor && pActor->GetInventory()) { IItem* pItem = pActor->GetInventory()->GetItemByName(sel); CWeapon* pWeapon; if(pItem && (pWeapon = (CWeapon*)(pItem->GetIWeapon()))) { int fireModeIdx = pWeapon->GetCurrentFireMode(); if(m_bLogWarning) { CheckDifference(recFireModeIdx,fireModeIdx,"TimeDemo:GameState: Frame %d - Actor %s - FIRE MODE mismatch for weapon %s (rec:%d, cur:%d)",pEntity,pItem->GetEntity() ? pItem->GetEntity()->GetName() : "(null)"); } if(demo_forceGameState==2 && fireModeIdx!= recFireModeIdx) pWeapon->SetCurrentFireMode(recFireModeIdx); } } } } break; case eGE_WeaponReload: { const char* ammoType = event.description; TAmmoContainer& ammoMags = gstate.AmmoMags; TAmmoContainer::iterator it = ammoMags.find(ammoType); if(it!=ammoMags.end()) { it->second -= (uint16)event.value; CActor *pActor = (CActor*)(gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(id)); if(pActor) { CInventory* pInventory = (CInventory*)(pActor->GetInventory()); if(pInventory) { { IEntityClass* pAmmoClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(ammoType); if(pAmmoClass) { if(m_bLogWarning) CheckDifference(it->second,pInventory->GetAmmoCount(pAmmoClass),"TimeDemo:GameState: Frame %d - Actor %s - WEAPON RELOAD, ammo count mismatch for ammo class %s (rec:%d, cur:%d)",pEntity,ammoType); if(demo_forceGameState == 2) pInventory->SetAmmoCount(pAmmoClass,it->second); } } } } } } break; case eGE_ItemSelected: { TItemName itemName = event.description; gstate.itemSelected = itemName; if(itemName) { if( !bRecording && (event.value > 0 || demo_forceGameState==2)) // EVENT.VALUE > 0 means initialization { CActor *pActor = (CActor*)(gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(id)); if(pActor && pActor->GetInventory()) { IItem* pItem = pActor->GetInventory()->GetItemByName(itemName); if(pItem) pActor->SelectItem(pItem->GetEntityId(),false); } } } if(m_bLogWarning) { CActor *pActor = (CActor*)(gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(id)); if(pActor) { IItem* pItem = pActor->GetCurrentItem(); const char* curItemName= pItem && pItem->GetEntity() ? pItem->GetEntity()->GetName(): NULL; CheckDifferenceString(itemName,curItemName,"TimeDemo:GameState: Frame %d - Actor %s - SELECTED ITEM mismatch (rec:%s, cur:%s)",pEntity); } } break; } break; case eGE_ItemExchanged: { // prevent unwanted record/play mismatch error with current item during item exchanging // two unneeded game events are sent (selecting fists) m_IgnoredEvents.push_back(eGE_ItemSelected); m_IgnoredEvents.push_back(eGE_ItemSelected); } break; case eGE_ItemPickedUp: { TItemName sel = (TItemName)event.description; // gstate.itemSelected = sel; TItemContainer& Items = gstate.Items; TItemContainer::iterator it = Items.find(sel); if(it == Items.end()) { Items.insert(std::make_pair(sel,SItemProperties())); it = Items.find(sel); } if(it != Items.end()) { it->second.count++; CActor *pActor = (CActor*)(gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(id)); if(pActor && !m_bRecording) { CInventory* pInventory = (CInventory*)(pActor->GetInventory()); if(pInventory) { // just check if the item is the inventory if(m_bLogWarning && !pInventory->GetItemByName(sel)) GameWarning("TimeDemo:GameState: Frame %d - Actor %s - Recorded PICKED UP ITEM class '%s' not found in current inventory",m_currentFrame,pEntity->GetName(),sel); if(demo_forceGameState == 2) { IEntity* pItemEntity = gEnv->pEntitySystem->FindEntityByName(sel); if(pItemEntity) pInventory->AddItem(pItemEntity->GetId()); else GameWarning("TimeDemo:GameState: Frame %d - Actor %s - PICKED UP ITEM entity %s not found in level",m_currentFrame,pEntity->GetName(),sel); } } } } else if(m_bLogWarning) { if(!sel) sel = "(null)"; GameWarning("TimeDemo:GameState: Frame %d - Actor %s - PICKED UP ITEM %s not found in recorded inventory",m_currentFrame,pEntity->GetName(),sel); } } break; case eGE_AmmoPickedUp: { uint16 ammoCount = (uint16)(event.value); TItemName sel = (TItemName)event.description; TAmmoContainer& Ammo = gstate.AmmoMags; TAmmoContainer::iterator it = Ammo.find(sel); if(it == Ammo.end()) Ammo.insert(std::make_pair(sel,ammoCount)); else it->second = ammoCount; if( !m_bRecording) { CActor *pActor = (CActor*)(gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(id)); if(pActor) { CInventory* pInventory = (CInventory*)(pActor->GetInventory()); if(pInventory) { IEntityClass* pClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(sel); if(m_bLogWarning) CheckDifference(ammoCount,pInventory->GetAmmoCount(pClass),"TimeDemo:GameState: Frame %d - Actor %s - AMMO PICKEDUP: count mismatch for ammo class %s (rec:%d, cur:%d)", pEntity,sel); if(demo_forceGameState == 2) pInventory->SetAmmoCount(pClass,ammoCount); } } } } break; case eGE_AccessoryPickedUp: { TItemName sel = (TItemName)event.description; // gstate.itemSelected = sel; TAccessoryContainer& Accessories = gstate.Accessories; TAccessoryContainer::iterator it = Accessories.find(sel); if(it == Accessories.end()) { Accessories.insert(std::make_pair(sel,1)); } else it->second++; CActor *pActor = (CActor*)(gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(id)); if(pActor) { CInventory* pInventory = (CInventory*)(pActor->GetInventory()); if(pInventory) { IEntityClass* pClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(sel); if(m_bLogWarning && !pInventory->HasAccessory(pClass)) GameWarning("TimeDemo:GameState: Frame %d - Actor %s - ACCESSORY PICKEDUP %s not found in current inventory", m_currentFrame, pEntity->GetName(),sel ? sel:"(null)"); if(demo_forceGameState == 2 && pClass) pInventory->AddAccessory(pClass);// doesn't actually add it if it's there already } } } break; case eGE_ItemDropped: { TItemName sel = (TItemName)event.description; //gstate.itemSelected = sel; TItemContainer& Items = gstate.Items; TItemContainer::iterator it = Items.find(sel); if(it != Items.end()) { it->second.count--; if(it->second.count<=0) Items.erase(it); if(demo_forceGameState == 2) { CActor *pActor = (CActor*)(gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(id)); if(pActor) { CInventory* pInventory = (CInventory*)(pActor->GetInventory()); if(pInventory) { IEntityClass* pClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(sel); if(pClass) { EntityId itemId = pInventory->GetItemByClass(pClass); if(itemId) pInventory->RemoveItem(itemId); } } } } } else GameWarning("TimeDemo:GameState: Frame %d - Actor %s - ITEM DROPPED, wrong item selected (%s)",m_currentFrame,pEntity->GetName(),sel); } break; case eGE_AmmoCount: { TItemContainer& Items = gstate.Items; TItemName itemClassDesc = event.description; TItemContainer::iterator it = Items.find(itemClassDesc); if(it != Items.end()) { SItemProperties& item = it->second; const char* ammoClassDesc = (const char*)(event.extra); if(ammoClassDesc) { string szAmmoClassDesc(ammoClassDesc); bool bAmmoMag = IsAmmoGrenade(ammoClassDesc); TAmmoContainer& itemAmmo = bAmmoMag ? gstate.AmmoMags : item.Ammo; if(itemAmmo.find(szAmmoClassDesc)==itemAmmo.end()) itemAmmo.insert(std::make_pair(szAmmoClassDesc,int(event.value))); else itemAmmo[szAmmoClassDesc] = (uint16)event.value; if(!bRecording && (m_bLogWarning || demo_forceGameState==2)) { CActor *pActor = (CActor*)(gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(id)); if(pActor) { CInventory* pInventory = (CInventory*)(pActor->GetInventory()); if(pInventory) { IItem* pItem = pInventory->GetItemByName(itemClassDesc); if(pItem) { CWeapon* pWeapon = (CWeapon*)(pItem->GetIWeapon()); if(pWeapon) { IEntityClass* pAmmoClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(ammoClassDesc); if(pAmmoClass) { if(m_bLogWarning) { int curAmmoCount = (bAmmoMag ? pInventory->GetAmmoCount(pAmmoClass) : pWeapon->GetAmmoCount(pAmmoClass)); CheckDifference( int(event.value),curAmmoCount,"TimeDemo:GameState: Frame %d - Actor %s - AMMO COUNT mismatch for ammo class %s (rec:%d, cur:%d)",pEntity,ammoClassDesc); } if(demo_forceGameState==2) pWeapon->SetAmmoCount(pAmmoClass,int(event.value)); } } } } } } } else GameWarning("TimeDemo:GameState: Frame %d - Actor %s - AMMO COUNT null ammoClass descriptor",m_currentFrame,pEntity->GetName()); } else GameWarning("TimeDemo:GameState: Frame %d - Actor %s - AMMO COUNT wrong item selected (%s)",m_currentFrame,pEntity->GetName(),itemClassDesc); } break; case eGE_AttachedAccessory: { // always force attachment of accessory to the current weapon // kind of a workaround, the HUD weapon modifier menu is spawned during timedemo playback // but it doesn't use recorded input events if(!bRecording) { CActor *pActor = (CActor*)(gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(id)); if(pActor) { CInventory* pInventory = (CInventory*)(pActor->GetInventory()); if(pInventory) { const char* sel = event.description; IEntityClass* pClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(sel); if(!sel) sel = "(null)"; if(!pInventory->HasAccessory(pClass)) { if(m_bLogWarning) GameWarning("TimeDemo:GameState: Frame %d - Actor %s - ATTACHED ACCESSORY %s not found in current inventory", m_currentFrame,pEntity->GetName(),sel); } else { CItem* pCurrentItem = (CItem*)(pActor->GetCurrentItem()); if(pCurrentItem) pCurrentItem->SwitchAccessory(sel); } } } } } break; case eGE_EntityGrabbed: { if(demo_forceGameState==2) { TItemName itemName = event.description; if(itemName) { IEntity * pGrabbedEntity = gEnv->pEntitySystem->FindEntityByName(itemName); if(pGrabbedEntity) { CActor *pActor = (CActor*)(gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(id)); if(pActor) { IItem* pItem = GetItemOfName(pActor,itemName); if(!pItem) { // it's a pickable entity, won't end up in the inventory //(otherwise it would be managed by eGE_ItemPickedUp) COffHand* pOffHand = static_cast<COffHand*>(pActor->GetWeaponByClass(CItem::sOffHandClass)); if(pOffHand && !pOffHand->GetPreHeldEntityId()) pOffHand->ForcePickUp(pGrabbedEntity->GetId()); } } } } } } break; default: break; } }