int CContainer::ResourceConsume( const CResourceQtyArray * pResources, int iReplicationQty, bool fTest, DWORD dwArg ) { ADDTOCALLSTACK("CContainer::ResourceConsume"); // Consume or test all the required resources. // ARGS: // pResources = the resources i need to make 1 replication of this end product. // RETURN: // how many whole objects can be made. <= iReplicationQty if ( iReplicationQty <= 0 ) iReplicationQty = 1; if ( ! fTest && iReplicationQty > 1 ) { // Test what the max number we can really make is first ! // All resources must be consumed with the same number. iReplicationQty = ResourceConsume( pResources, iReplicationQty, true, dwArg ); } int iQtyMin = INT_MAX; for ( size_t i = 0; i < pResources->GetCount(); i++ ) { int iResQty = static_cast<int>(pResources->GetAt(i).GetResQty()); if (iResQty <= 0) // not sure why this would be true continue; int iQtyTotal = ( iResQty * iReplicationQty ); RESOURCE_ID rid = pResources->GetAt(i).GetResourceID(); if ( rid.GetResType() == RES_SKILL ) { CChar * pChar = dynamic_cast <CChar *> (this); if ( !pChar ) continue; if ( pChar->Skill_GetBase(static_cast<SKILL_TYPE>(rid.GetResIndex())) < iResQty ) return 0; continue; } int iQtyCur = iQtyTotal - ContentConsume( rid, iQtyTotal, fTest, dwArg ); iQtyCur /= iResQty; if ( iQtyCur < iQtyMin ) iQtyMin = iQtyCur; } if ( iQtyMin == INT_MAX ) // it has no resources ? So i guess we can make it from nothing ? return( iReplicationQty ); return( iQtyMin ); }
bool CChar::NPC_OnHirePay( CChar * pCharSrc, CItemMemory * pMemory, CItem * pGold ) { ADDTOCALLSTACK("CChar::NPC_OnHirePay"); if ( !m_pNPC || !pCharSrc || !pMemory ) return false; CCharBase * pCharDef = Char_GetDef(); if ( IsStatFlag( STATF_Pet )) { if ( ! pMemory->IsMemoryTypes(MEMORY_IPET|MEMORY_FRIEND)) { Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_EMPLOYED ) ); return false; } } else { unsigned int iWage = pCharDef->GetHireDayWage(); if ( iWage <= 0 ) { Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_NOT_FOR_HIRE ) ); return false; } if ( pGold->GetAmount() < iWage ) { Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_NOT_ENOUGH ) ); return false; } // NOTO_TYPE ? if ( pMemory->IsMemoryTypes( MEMORY_FIGHT|MEMORY_HARMEDBY|MEMORY_IRRITATEDBY )) { Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_NOT_WORK ) ); return false; } // Put all my loot cash away. ContentConsume( RESOURCE_ID(RES_TYPEDEF,IT_GOLD), INT_MAX, false, 0 ); // Mark all my stuff ATTR_OWNED - i won't give it away. ContentAttrMod( ATTR_OWNED, true ); NPC_PetSetOwner( pCharSrc ); } pMemory->m_itEqMemory.m_Action = NPC_MEM_ACT_NONE; NPC_OnHirePayMore( pGold, true ); return true; }
size_t CContainer::ResourceConsumePart( const CResourceQtyArray * pResources, int iReplicationQty, int iDamagePercent, bool fTest, DWORD dwArg ) { ADDTOCALLSTACK("CContainer::ResourceConsumePart"); // Consume just some of the resources. // ARGS: // pResources = the resources i need to make 1 replication of this end product. // iDamagePercent = 0-100 // RETURN: // BadIndex = all needed items where present. // index of the item we did not have. if ( iDamagePercent <= 0 ) return pResources->BadIndex(); size_t iMissing = pResources->BadIndex(); size_t iQtyRes = pResources->GetCount(); for ( size_t i = 0; i < iQtyRes; i++ ) { int iResQty = static_cast<int>(pResources->GetAt(i).GetResQty()); if (iResQty <= 0) // not sure why this would be true continue; int iQtyTotal = ( iResQty * iReplicationQty ); if ( iQtyTotal <= 0 ) continue; iQtyTotal = IMULDIV( iQtyTotal, iDamagePercent, 100 ); if ( iQtyTotal <= 0 ) continue; RESOURCE_ID rid = pResources->GetAt(i).GetResourceID(); int iRet = ContentConsume( rid, iQtyTotal, fTest, dwArg ); if ( iRet ) { iMissing = i; } } return( iMissing ); }
bool CChar::Use_Train_ArcheryButte( CItem * pButte, bool fSetup ) { ADDTOCALLSTACK("CChar::Use_Train_ArcheryButte"); // IT_ARCHERY_BUTTE ASSERT(pButte); ITEMID_TYPE AmmoID; if ( GetDist(pButte) < 2 ) // if we are standing right next to the butte, retrieve the arrows/bolts { if ( pButte->m_itArcheryButte.m_AmmoCount == 0 ) { SysMessageDefault(DEFMSG_ITEMUSE_ARCHB_EMPTY); return true; } AmmoID = pButte->m_itArcheryButte.m_AmmoType; CItemBase *pAmmoDef = CItemBase::FindItemBase(AmmoID); if ( pAmmoDef ) { TCHAR *pszMsg = Str_GetTemp(); sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_REM), pAmmoDef->GetName(), (pButte->m_itArcheryButte.m_AmmoCount == 1) ? "" : g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_REMS)); Emote(pszMsg); CItem *pRemovedAmmo = CItem::CreateBase(AmmoID); ASSERT(pRemovedAmmo); pRemovedAmmo->SetAmount(pButte->m_itArcheryButte.m_AmmoCount); ItemBounce(pRemovedAmmo); } // Clear the target pButte->m_itArcheryButte.m_AmmoType = ITEMID_NOTHING; pButte->m_itArcheryButte.m_AmmoCount = 0; return true; } SKILL_TYPE skill = Fight_GetWeaponSkill(); if ( !g_Cfg.IsSkillFlag(skill, SKF_RANGED) ) { SysMessageDefault(DEFMSG_ITEMUSE_ARCHB_WS); return true; } if ( Skill_GetBase(skill) > g_Cfg.m_iSkillPracticeMax ) { SysMessageDefault(DEFMSG_ITEMUSE_ARCHB_SKILL); return true; } // Make sure we have some ammo CItem *pWeapon = m_uidWeapon.ItemFind(); ASSERT(pWeapon); const CItemBase *pWeaponDef = pWeapon->Item_GetDef(); // Determine ammo type CVarDefCont *pVarAmmoType = pWeapon->GetDefKey("AMMOTYPE", true); RESOURCE_ID_BASE rid; LPCTSTR t_Str; if ( pVarAmmoType ) { t_Str = pVarAmmoType->GetValStr(); rid = static_cast<RESOURCE_ID_BASE>(g_Cfg.ResourceGetID(RES_ITEMDEF, t_Str)); } else { rid = pWeaponDef->m_ttWeaponBow.m_idAmmo; } AmmoID = static_cast<ITEMID_TYPE>(rid.GetResIndex()); // If there is a different ammo type on the butte currently, tell us to remove the current type first if ( (pButte->m_itArcheryButte.m_AmmoType != ITEMID_NOTHING) && (pButte->m_itArcheryButte.m_AmmoType != AmmoID) ) { SysMessageDefault(DEFMSG_ITEMUSE_ARCHB_X); return true; } // We need to be correctly aligned with the target before we can use it // For the south facing butte, we need to have the same X value and a Y > 2 // For the east facing butte, we need to have the same Y value and an X > 2 if ( !pButte->IsTopLevel() ) { badalign: SysMessageDefault(DEFMSG_ITEMUSE_ARCHB_P); return true; } int targDistX = GetTopPoint().m_x - pButte->GetTopPoint().m_x; int targDistY = GetTopPoint().m_y - pButte->GetTopPoint().m_y; if ( (pButte->GetID() == ITEMID_ARCHERYBUTTE_S) || (pButte->GetID() == ITEMID_MONGBATTARGET_S) ) { if ( !(targDistX == 0 && targDistY > 2) ) goto badalign; } else { if ( !(targDistY == 0 && targDistX > 2) ) goto badalign; } if ( !CanSeeLOS(pButte, LOS_NB_WINDOWS) ) //we should be able to shoot through a window { SysMessageDefault(DEFMSG_ITEMUSE_ARCHB_BLOCK); return true; } if ( fSetup ) { if ( Skill_GetActive() == NPCACT_TRAINING ) return true; UpdateAnimate(ANIM_ATTACK_WEAPON); m_Act_TargPrv = m_uidWeapon; m_Act_Targ = pButte->GetUID(); Skill_Start(NPCACT_TRAINING); return true; } CVarDefCont *pCont = pWeapon->GetDefKey("AMMOCONT",true); if ( m_pPlayer && AmmoID ) { int iFound = 1; if ( pCont ) { //check for UID CGrayUID uidCont = static_cast<DWORD>(pCont->GetValNum()); CItemContainer *pNewCont = dynamic_cast<CItemContainer*>(uidCont.ItemFind()); if ( !pNewCont ) //if no UID, check for ITEMID_TYPE { t_Str = pCont->GetValStr(); RESOURCE_ID_BASE rContid = static_cast<RESOURCE_ID_BASE>(g_Cfg.ResourceGetID(RES_ITEMDEF, t_Str)); ITEMID_TYPE ContID = static_cast<ITEMID_TYPE>(rContid.GetResIndex()); if ( ContID ) pNewCont = dynamic_cast<CItemContainer*>(ContentFind(rContid)); } if ( pNewCont ) iFound = pNewCont->ContentConsume(RESOURCE_ID(RES_ITEMDEF, AmmoID)); else iFound = ContentConsume(RESOURCE_ID(RES_ITEMDEF, AmmoID)); } else iFound = ContentConsume(RESOURCE_ID(RES_ITEMDEF, AmmoID)); if ( iFound ) { SysMessageDefault(DEFMSG_ITEMUSE_ARCHB_NOAMMO); return(true); } } // OK...go ahead and fire at the target // Check the skill bool fSuccess = Skill_UseQuick(skill, Calc_GetRandLLVal(40)); // determine animation parameters CVarDefCont *pVarAnim = pWeapon->GetDefKey("AMMOANIM", true); CVarDefCont *pVarAnimColor = pWeapon->GetDefKey("AMMOANIMHUE", true); CVarDefCont *pVarAnimRender = pWeapon->GetDefKey("AMMOANIMRENDER", true); ITEMID_TYPE AmmoAnim; DWORD AmmoHue; DWORD AmmoRender; if ( pVarAnim ) { t_Str = pVarAnim->GetValStr(); rid = static_cast<RESOURCE_ID_BASE>(g_Cfg.ResourceGetID(RES_ITEMDEF, t_Str)); AmmoAnim = static_cast<ITEMID_TYPE>(rid.GetResIndex()); } else AmmoAnim = static_cast<ITEMID_TYPE>(pWeaponDef->m_ttWeaponBow.m_idAmmoX.GetResIndex()); AmmoHue = pVarAnimColor ? static_cast<DWORD>(pVarAnimColor->GetValNum()) : 0; AmmoRender = pVarAnimRender ? static_cast<DWORD>(pVarAnimRender->GetValNum()) : 0; pButte->Effect(EFFECT_BOLT, AmmoAnim, this, 16, 0, false, AmmoHue, AmmoRender); pButte->Sound(0x224); // Did we destroy the ammo? const CItemBase *pAmmoDef = NULL; if ( AmmoID ) pAmmoDef = CItemBase::FindItemBase(AmmoID); if ( !fSuccess ) { // Small chance of destroying the ammo if ( pAmmoDef && !Calc_GetRandVal(10) ) { TCHAR *pszMsg = Str_GetTemp(); sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_DEST), pAmmoDef->GetName()); Emote(pszMsg, NULL, true); return true; } static LPCTSTR const sm_Txt_ArcheryButte_Failure[] = { g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_MISS_1), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_MISS_2), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_MISS_3), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_MISS_4) }; Emote(sm_Txt_ArcheryButte_Failure[Calc_GetRandVal(COUNTOF(sm_Txt_ArcheryButte_Failure))]); } else { // Very small chance of destroying another arrow if ( pAmmoDef && !Calc_GetRandVal(50) && pButte->m_itArcheryButte.m_AmmoCount ) { TCHAR *pszMsg = Str_GetTemp(); sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_SPLIT), pAmmoDef->GetName()); Emote(pszMsg, NULL, true); return true; } static LPCTSTR const sm_Txt_ArcheryButte_Success[] = { g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_HIT_1), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_HIT_2), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_HIT_3), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_HIT_4) }; Emote(sm_Txt_ArcheryButte_Success[Calc_GetRandVal(COUNTOF(sm_Txt_ArcheryButte_Success))]); } // Update the target if ( AmmoID ) { pButte->m_itArcheryButte.m_AmmoType = AmmoID; pButte->m_itArcheryButte.m_AmmoCount++; } return true; }
int CContainer::ContentCount( RESOURCE_ID_BASE rid, DWORD dwArg ) { ADDTOCALLSTACK("CContainer::ContentCount"); // Calculate total (gold or other items) in this recursed container return( INT_MAX - ContentConsume( rid, INT_MAX, true, dwArg )); }