void CItemSpawn::GenerateItem(CResourceDef *pDef) { ADDTOCALLSTACK("CitemSpawn:GenerateItem"); RESOURCE_ID_BASE rid = pDef->GetResourceID(); ITEMID_TYPE id = static_cast<ITEMID_TYPE>(rid.GetResIndex()); CItemContainer *pCont = dynamic_cast<CItemContainer *>(GetParent()); BYTE iCount = pCont ? static_cast<unsigned char>(pCont->ContentCount(rid)) : GetCount(); if ( iCount >= GetAmount() ) return; CItem *pItem = CreateTemplate(id); if ( pItem == NULL ) return; WORD iAmountPile = static_cast<WORD>(minimum(USHRT_MAX,m_itSpawnItem.m_pile)); if ( iAmountPile > 1 ) { CItemBase *pItemDef = pItem->Item_GetDef(); ASSERT(pItemDef); if ( pItemDef->IsStackableType() ) pItem->SetAmount(Calc_GetRandVal(iAmountPile) + 1); } pItem->SetAttr(m_Attr & (ATTR_OWNED | ATTR_MOVE_ALWAYS)); pItem->SetDecayTime(g_Cfg.m_iDecay_Item); // it will decay eventually to be replaced later pItem->MoveNearObj(this, m_itSpawnItem.m_DistMax); AddObj(pItem->GetUID()); }
CCharBase *CItemSpawn::SetTrackID() { ADDTOCALLSTACK("CitemSpawn:SetTrackID"); SetAttr(ATTR_INVIS); // Indicate to GM's that it is invis. if (GetHue() == 0) SetHue(HUE_RED_DARK); if ( !IsType(IT_SPAWN_CHAR) ) { SetDispID(ITEMID_WorldGem_lg); return NULL; } CCharBase *pCharDef = NULL; RESOURCE_ID_BASE rid = m_itSpawnChar.m_CharID; if ( rid.GetResType() == RES_CHARDEF ) { CREID_TYPE id = static_cast<CREID_TYPE>(rid.GetResIndex()); pCharDef = CCharBase::FindCharBase(id); } if ( pCharDef ) // They must want it to look like this. SetDispID(pCharDef ? pCharDef->m_trackID : ITEMID_TRACK_WISP); return pCharDef; }
CResourceDef * CItemSpawn::FixDef() { ADDTOCALLSTACK("CitemSpawn:FixDef"); // Get a proper RESOURCE_ID from the id provided. // RETURN: true = ok. RESOURCE_ID_BASE rid = ( IsType(IT_SPAWN_ITEM) ? m_itSpawnItem.m_ItemID : m_itSpawnChar.m_CharID ); if ( rid.GetResType() != RES_UNKNOWN ) { return STATIC_CAST <CResourceDef *>(g_Cfg.ResourceGetDef(rid)); } // No type info here !? if ( IsType(IT_SPAWN_ITEM)) { ITEMID_TYPE id = static_cast<ITEMID_TYPE>(rid.GetResIndex()); if ( id < ITEMID_TEMPLATE ) { return( TryItem( id ) ); } else { // try a template. rid = RESOURCE_ID( RES_TEMPLATE, id ); CResourceDef * pDef = g_Cfg.ResourceGetDef(rid); if ( pDef ) { m_itSpawnItem.m_ItemID = rid; return( STATIC_CAST <CResourceDef *>( pDef )); } //if fails return( TryItem( id ) ); } } else { CREID_TYPE id = static_cast<CREID_TYPE>(rid.GetResIndex()); if ( id < SPAWNTYPE_START ) { return( TryChar( id )); } else { // try a spawn group. rid = RESOURCE_ID( RES_SPAWN, id ); CResourceDef * pDef = g_Cfg.ResourceGetDef(rid); if ( pDef ) { m_itSpawnChar.m_CharID = rid; return( STATIC_CAST <CResourceDef *>( pDef )); } //if fails return( TryChar( id )); } } }
void CItem::Spawn_GenerateChar( CResourceDef * pDef ) { if ( ! IsTopLevel()) return; // creatures can only be top level. if ( m_itSpawnChar.m_current >= GetAmount()) return; int iComplexity = GetTopSector()->GetCharComplexity(); if ( iComplexity > g_Cfg.m_iMaxCharComplexity ) { DEBUG_MSG(( "Spawn uid=0%lx too complex (%d>%d)\n", GetUID(), iComplexity, g_Cfg.m_iMaxCharComplexity )); return; } int iDistMax = m_itSpawnChar.m_DistMax; RESOURCE_ID_BASE rid = pDef->GetResourceID(); if ( rid.GetResType() == RES_SPAWN ) { const CRandGroupDef * pSpawnGroup = STATIC_CAST <const CRandGroupDef *>(pDef); ASSERT(pSpawnGroup); int i = pSpawnGroup->GetRandMemberIndex(); if ( i >= 0 ) { rid = pSpawnGroup->GetMemberID(i); } } CREID_TYPE id; if ( rid.GetResType() == RES_CHARDEF || rid.GetResType() == RES_UNKNOWN ) { id = (CREID_TYPE) rid.GetResIndex(); } else { return; } CChar * pChar = CChar::CreateNPC( id ); if ( pChar == NULL ) return; ASSERT(pChar->m_pNPC); m_itSpawnChar.m_current ++; pChar->Memory_AddObjTypes( this, MEMORY_ISPAWNED ); // Move to spot "near" the spawn item. pChar->MoveNearObj( this, iDistMax ); if ( iDistMax ) { pChar->m_ptHome = GetTopPoint(); pChar->m_pNPC->m_Home_Dist_Wander = iDistMax; } pChar->Update(); }
void CItemSpawn::GenerateChar(CResourceDef *pDef) { ADDTOCALLSTACK("CitemSpawn:GenerateChar"); RESOURCE_ID_BASE rid = pDef->GetResourceID(); if ( rid.GetResType() == RES_SPAWN ) { const CRandGroupDef *pSpawnGroup = static_cast<const CRandGroupDef *>(pDef); ASSERT(pSpawnGroup); size_t i = pSpawnGroup->GetRandMemberIndex(); if ( i != pSpawnGroup->BadMemberIndex() ) rid = pSpawnGroup->GetMemberID(i); } if ( (rid.GetResType() != RES_CHARDEF) && (rid.GetResType() != RES_UNKNOWN) ) return; CPointMap pt = GetTopPoint(); CRegionBase *pRegion = pt.GetRegion(REGION_TYPE_AREA); if ( !pRegion ) return; CChar *pChar = CChar::CreateBasic(static_cast<CREID_TYPE>(rid.GetResIndex())); if ( !pChar ) return; pChar->NPC_LoadScript(true); pChar->StatFlag_Set(STATF_Spawned); // Try placing the char near the spawn if ( !pChar->MoveNearObj(this, m_itSpawnChar.m_DistMax) || !pChar->CanSeeLOS(pt) ) { // If this fails, try placing the char over the spawn if ( !pChar->MoveTo(pt) ) { DEBUG_ERR(("Spawn UID:0%lx is unable to place a character inside the world.\n", static_cast<DWORD>(GetUID()))); pChar->Delete(); return; } } AddObj(pChar->GetUID()); pChar->NPC_CreateTrigger(); // removed from NPC_LoadScript() and triggered after char placement and attachment to the spawnitem pChar->Update(); size_t iCount = GetTopSector()->GetCharComplexity(); if ( iCount > g_Cfg.m_iMaxCharComplexity ) g_Log.Event(LOGL_WARN, "%" FMTSIZE_T " chars at %s. Sector too complex!\n", iCount, GetTopSector()->GetBasePoint().WriteUsed()); }
TRIGRET_TYPE CContainer::OnContTriggerForLoop( CScript &s, CTextConsole * pSrc, CScriptTriggerArgs * pArgs, CGString * pResult, CScriptLineContext & StartContext, CScriptLineContext & EndContext, RESOURCE_ID_BASE rid, DWORD dwArg, int iDecendLevels ) { ADDTOCALLSTACK("CContainer::OnContTriggerForLoop"); if ( rid.GetResIndex() != 0 ) { CItem* pItem = GetContentHead(); CItem * pItemNext; for ( ; pItem!=NULL; pItem=pItemNext) { pItemNext = pItem->GetNext(); if ( pItem->IsResourceMatch( rid, dwArg )) { s.SeekContext( StartContext ); TRIGRET_TYPE iRet = pItem->OnTriggerRun( s, TRIGRUN_SECTION_TRUE, pSrc, pArgs, pResult ); if ( iRet == TRIGRET_BREAK ) { EndContext = StartContext; break; } if (( iRet != TRIGRET_ENDIF ) && ( iRet != TRIGRET_CONTINUE )) return( iRet ); if ( iRet == TRIGRET_CONTINUE ) EndContext = StartContext; else EndContext = s.GetContext(); } if ( iDecendLevels <= 0 ) continue; CItemContainer * pCont = dynamic_cast <CItemContainer*>(pItem); if ( pCont != NULL ) { if ( pCont->IsSearchable()) { CContainer * pContBase = dynamic_cast <CContainer *> (pCont); TRIGRET_TYPE iRet = pContBase->OnContTriggerForLoop( s, pSrc, pArgs, pResult, StartContext, EndContext, rid, dwArg, iDecendLevels-1 ); if ( iRet != TRIGRET_ENDIF ) { return( iRet ); } // Since the previous call has already found the EndContext, set it. EndContext = s.GetContext(); } } } } if ( EndContext.m_lOffset <= StartContext.m_lOffset ) { CScriptObj * pScript = dynamic_cast <CScriptObj *> (this); TRIGRET_TYPE iRet = pScript->OnTriggerRun( s, TRIGRUN_SECTION_FALSE, pSrc, pArgs, pResult ); if ( iRet != TRIGRET_ENDIF ) return( iRet ); } else s.SeekContext( EndContext ); return( TRIGRET_ENDIF ); }
void CItemSpawn::GenerateChar(CResourceDef *pDef) { ADDTOCALLSTACK("CitemSpawn:GenerateChar"); if ( !IsTopLevel() ) return; RESOURCE_ID_BASE rid = pDef->GetResourceID(); if ( rid.GetResType() == RES_SPAWN ) { const CRandGroupDef *pSpawnGroup = static_cast<const CRandGroupDef *>(pDef); ASSERT(pSpawnGroup); size_t i = pSpawnGroup->GetRandMemberIndex(); if ( i != pSpawnGroup->BadMemberIndex() ) rid = pSpawnGroup->GetMemberID(i); } if ( (rid.GetResType() != RES_CHARDEF) && (rid.GetResType() != RES_UNKNOWN) ) return; CChar *pChar = CChar::CreateBasic(static_cast<CREID_TYPE>(rid.GetResIndex())); if ( !pChar ) return; CPointMap pt = GetTopPoint(); pChar->NPC_LoadScript(true); pChar->StatFlag_Set(STATF_Spawned); pChar->MoveTo(pt); // Check if the NPC can spawn in this region CRegionBase *pRegion = GetTopPoint().GetRegion(REGION_TYPE_AREA); if ( !pRegion || (pRegion->IsGuarded() && pChar->Noto_IsEvil()) ) { pChar->Delete(); return; } AddObj(pChar->GetUID()); pChar->NPC_CreateTrigger(); // removed from NPC_LoadScript() and triggered after char placement and attachment to the spawnitem pChar->Update(); size_t iCount = GetTopSector()->GetCharComplexity(); if ( iCount > g_Cfg.m_iMaxCharComplexity ) g_Log.Event(LOGL_WARN, "%d chars at %s. Sector too complex!\n", iCount, GetTopSector()->GetBasePoint().WriteUsed()); }
void CItemSpawn::GenerateItem(CResourceDef * pDef) { ADDTOCALLSTACK("CitemSpawn:GenerateItem"); RESOURCE_ID_BASE rid = pDef->GetResourceID(); ITEMID_TYPE id = static_cast<ITEMID_TYPE>(rid.GetResIndex()); int iDistMax = m_itSpawnItem.m_DistMax; int iAmountPile = m_itSpawnItem.m_pile; int iCount = 0; CItemContainer * pCont = dynamic_cast <CItemContainer *>( GetParent()); if ( pCont != NULL ) iCount = pCont->ContentCount( rid ); else iCount = GetCount(); if ( iCount >= GetAmount()) return; CItem * pItem = CreateTemplate( id ); if ( pItem == NULL ) return; pItem->SetAttr( m_Attr & ( ATTR_OWNED | ATTR_MOVE_ALWAYS )); if ( iAmountPile > 1 ) { CItemBase * pItemDef = pItem->Item_GetDef(); ASSERT(pItemDef); if ( pItemDef->IsStackableType()) { if ( iAmountPile == 0 || iAmountPile > GetAmount()) iAmountPile = GetAmount(); pItem->SetAmount( Calc_GetRandVal(iAmountPile) + 1 ); } } pItem->SetDecayTime( g_Cfg.m_iDecay_Item ); // It will decay eventually to be replaced later. pItem->MoveNearObj( this, iDistMax ); AddObj(pItem->GetUID()); pItem->m_uidSpawnItem = GetUID(); }
CResourceDef *CItemSpawn::FixDef() { ADDTOCALLSTACK("CitemSpawn:FixDef"); RESOURCE_ID_BASE rid = (IsType(IT_SPAWN_ITEM) ? m_itSpawnItem.m_ItemID : m_itSpawnChar.m_CharID); if ( rid.GetResType() != RES_UNKNOWN ) return static_cast<CResourceDef *>(g_Cfg.ResourceGetDef(rid)); // No type info here !? if ( IsType(IT_SPAWN_CHAR) ) { CREID_TYPE id = static_cast<CREID_TYPE>(rid.GetResIndex()); if ( id < SPAWNTYPE_START ) return TryChar(id); // try a spawn group. rid = RESOURCE_ID(RES_SPAWN, id); CResourceDef *pDef = g_Cfg.ResourceGetDef(rid); if ( pDef ) { m_itSpawnChar.m_CharID = rid; return pDef; } return TryChar(id); } else { ITEMID_TYPE id = static_cast<ITEMID_TYPE>(rid.GetResIndex()); if ( id < ITEMID_TEMPLATE ) return TryItem(id); // try a template. rid = RESOURCE_ID(RES_TEMPLATE, id); CResourceDef *pDef = g_Cfg.ResourceGetDef(rid); if ( pDef ) { m_itSpawnItem.m_ItemID = rid; return pDef; } return TryItem(id); } }
LPCTSTR CResourceBase::ResourceGetName( RESOURCE_ID_BASE rid ) const { ADDTOCALLSTACK("CResourceBase::ResourceGetName"); // Get a portable name for the resource id type. CResourceDef * pResourceDef = dynamic_cast <CResourceDef *>( ResourceGetDef( rid )); if ( pResourceDef ) return( pResourceDef->GetResourceName()); TCHAR * pszTmp = Str_GetTemp(); ASSERT(pszTmp); if ( ! rid.IsValidUID()) { sprintf( pszTmp, "%ld", static_cast<long>(rid.GetPrivateUID()) ); } else { sprintf( pszTmp, "0%x", rid.GetResIndex() ); } return( pszTmp ); }
CCharBase * CItem::Spawn_SetTrackID() { if ( ! IsType(IT_SPAWN_CHAR)) return NULL; CCharBase * pCharDef = NULL; RESOURCE_ID_BASE rid = m_itSpawnChar.m_CharID; if ( rid.GetResType() == RES_CHARDEF ) { CREID_TYPE id = (CREID_TYPE) rid.GetResIndex(); pCharDef = CCharBase::FindCharBase( id ); } if ( pCharDef ) SetAttr( ATTR_INVIS ); if ( IsAttr(ATTR_INVIS)) // They must want it to look like this. { SetDispID( ( pCharDef == NULL ) ? ITEMID_TRACK_WISP : pCharDef->m_trackID ); if ( GetHue() == 0 ) SetHue( HUE_RED_DARK ); // Indicate to GM's that it is invis. } return( pCharDef ); }
bool CResourceBase::ResourceLock( CResourceLock & s, RESOURCE_ID_BASE rid ) { ADDTOCALLSTACK("CResourceBase::ResourceLock"); // Lock a referenced resource object. if ( ! rid.IsValidUID()) return( false ); CResourceLink * pResourceLink = dynamic_cast <CResourceLink *>( ResourceGetDef( rid )); if ( pResourceLink ) { return( pResourceLink->ResourceLock(s)); } return( false ); }
int CContainer::ContentConsume( RESOURCE_ID_BASE rid, int amount, bool fTest, DWORD dwArg ) { ADDTOCALLSTACK("CContainer::ContentConsume"); // ARGS: // dwArg = a hack for ores. // RETURN: // 0 = all consumed ok. // # = number left to be consumed. (still required) if ( rid.GetResIndex() == 0 ) return( amount ); // from skills menus. CItem * pItemNext; for ( CItem* pItem=GetContentHead(); pItem!=NULL; pItem=pItemNext) { pItemNext = pItem->GetNext(); if ( pItem->IsResourceMatch( rid, dwArg )) { amount -= pItem->ConsumeAmount( amount, fTest ); if ( amount <= 0 ) break; } CItemContainer * pCont = dynamic_cast <CItemContainer*> (pItem); if ( pCont != NULL ) // this is a sub-container. { if ( rid == RESOURCE_ID(RES_TYPEDEF,IT_GOLD)) { if ( pCont->IsType(IT_CONTAINER_LOCKED)) continue; } else { if ( ! pCont->IsSearchable()) continue; } amount = pCont->ContentConsume( rid, amount, fTest, dwArg ); if ( amount <= 0 ) break; } } return( amount ); }
TRIGRET_TYPE CClient::Dialog_OnButton( RESOURCE_ID_BASE rid, DWORD dwButtonID, CObjBase * pObj, CDialogResponseArgs * pArgs ) { ADDTOCALLSTACK("CClient::Dialog_OnButton"); // one of the gump dialog buttons was pressed. if ( !pObj ) // object is gone ? return TRIGRET_ENDIF; CResourceLock s; if ( !g_Cfg.ResourceLock(s, RESOURCE_ID(RES_DIALOG, rid.GetResIndex(), RES_DIALOG_BUTTON)) ) return TRIGRET_ENDIF; INT64 piCmd[3]; while ( s.ReadKeyParse()) { if ( ! s.IsKeyHead( "ON", 2 )) continue; size_t iArgs = Str_ParseCmds( s.GetArgStr(), piCmd, COUNTOF(piCmd) ); if ( iArgs == 0 ) continue; if ( iArgs == 1 ) { // single button value if ( (DWORD)piCmd[0] != dwButtonID ) continue; } else { // range of button values if ( dwButtonID < (DWORD)piCmd[0] || dwButtonID > (DWORD)piCmd[1] ) continue; } pArgs->m_iN1 = dwButtonID; return pObj->OnTriggerRunVal( s, TRIGRUN_SECTION_TRUE, m_pChar, pArgs ); } return( TRIGRET_ENDIF ); }
size_t CClient::Cmd_Skill_Menu_Build( RESOURCE_ID_BASE rid, int iSelect, CMenuItem *item, size_t iMaxSize, bool &fShowMenu, bool &fLimitReached ) { ADDTOCALLSTACK("CClient::Cmd_Skill_Menu_Build"); // Build the skill menu for the curent active skill. // Only list the things we have skill and ingrediants to make. // // ARGS: // m_Targ_UID = the object used to get us here. // rid = which menu ? // iSelect = -2 = Just a test of the whole menu., // iSelect = -1 = 1st setup. // iSelect = 0 = cancel // iSelect = x = execute the selection. // fShowMenu = whether or not menus can be shown // item = pointer to entries list // iMaxSize = maximum number of entries // // RETURN: number of entries in menu // m_tmMenu.m_Item = the menu entries. ASSERT(m_pChar); if ( rid.GetResType() != RES_SKILLMENU ) return 0; // Find section. CResourceLock s; if ( !g_Cfg.ResourceLock(s, rid) ) return 0; // Get title line if ( !s.ReadKey() ) return 0; if ( iSelect == 0 ) // cancelled { while ( s.ReadKeyParse() ) { if ( !s.IsKey("ON") || (*s.GetArgStr() != '@') ) continue; if ( strcmpi(s.GetArgStr(), "@Cancel") ) continue; if ( m_pChar->OnTriggerRunVal(s, TRIGRUN_SECTION_TRUE, m_pChar, NULL) == TRIGRET_RET_TRUE ) return 0; break; } return 1; } if ( iSelect < 0 ) { item[0].m_sText = s.GetKey(); if ( iSelect == -1 ) m_tmMenu.m_ResourceID = rid; } bool fSkip = false; // skip this if we lack resources or skill. int iOnCount = 0; size_t iShowCount = 0; CScriptTriggerArgs Args; while ( s.ReadKeyParse()) { if ( s.IsKeyHead("ON", 2) ) { if ( *s.GetArgStr() == '@' ) { fSkip = true; continue; } // a new option to look at. fSkip = false; iOnCount++; if ( iSelect < 0 ) // building up the list. { if ( iSelect < -1 && iShowCount >= 1 ) // just a test. so we are done. return 1; iShowCount++; if ( !item[iSelect == -2 ? 0 : iShowCount].ParseLine(s.GetArgRaw(), NULL, m_pChar) ) { // remove if the item is invalid. iShowCount--; fSkip = true; continue; } if ( iSelect == -1 ) m_tmMenu.m_Item[iShowCount] = iOnCount; if ( iShowCount >= (iMaxSize - 1) ) break; } else { if ( iOnCount > iSelect ) // we are done. break; } continue; } if ( fSkip ) // we have decided we cant do this option. continue; if ( iSelect > 0 && iOnCount != iSelect ) // only interested in the selected option continue; // Check for a skill / non-consumables required. if ( s.IsKey("TEST") ) { m_pChar->ParseText(s.GetArgRaw(), m_pChar); CResourceQtyArray skills(s.GetArgStr()); if ( !skills.IsResourceMatchAll(m_pChar) ) { iShowCount--; fSkip = true; } continue; } if ( s.IsKey("TESTIF") ) { m_pChar->ParseText(s.GetArgRaw(), m_pChar); if ( !s.GetArgVal() ) { iShowCount--; fSkip = true; } continue; } // select to execute any entries here ? if ( iOnCount == iSelect ) { // Execute command from script TRIGRET_TYPE tRet = m_pChar->OnTriggerRunVal(s, TRIGRUN_SINGLE_EXEC, m_pChar, &Args); if ( tRet != TRIGRET_RET_DEFAULT ) return tRet == TRIGRET_RET_TRUE ? 0 : 1; iShowCount++; // we are good. but continue til the end } else { ASSERT(iSelect < 0); if ( s.IsKey("SKILLMENU") ) { static int sm_iReentrant = 0; if ( sm_iReentrant > 1024 ) { if ( g_Cfg.m_wDebugFlags & DEBUGF_SCRIPTS ) g_Log.EventDebug("SCRIPT: Too many skill menus (circular menus?) to continue searching in menu '%s'\n", g_Cfg.ResourceGetDef(rid)->GetResourceName()); fLimitReached = true; } else { // Test if there is anything in this skillmenu we can do. ++sm_iReentrant; if ( !Cmd_Skill_Menu_Build(g_Cfg.ResourceGetIDType(RES_SKILLMENU, s.GetArgStr()), -2, *&item, iMaxSize, fShowMenu, fLimitReached) ) { iShowCount--; fSkip = true; } else fShowMenu = true; --sm_iReentrant; } continue; } if ( s.IsKey("MAKEITEM") ) { // test if i can make this item using m_Targ_UID. // There should ALWAYS be a valid id here. if ( !m_pChar->Skill_MakeItem(static_cast<ITEMID_TYPE>(g_Cfg.ResourceGetIndexType(RES_ITEMDEF, s.GetArgStr())), m_Targ_UID, SKTRIG_SELECT) ) { iShowCount--; fSkip = true; } continue; } } } return iShowCount; }
bool CClient::Cmd_Skill_Menu( RESOURCE_ID_BASE rid, int iSelect ) { ADDTOCALLSTACK("CClient::Cmd_Skill_Menu"); // Build the skill menu for the curent active skill. // Only list the things we have skill and ingrediants to make. // // ARGS: // m_Targ_UID = the object used to get us here. // rid = which menu ? // iSelect = -2 = Just a test of the whole menu., // iSelect = -1 = 1st setup. // iSelect = 0 = cancel // iSelect = x = execute the selection. // // RETURN: false = fail/cancel the skill. // m_tmMenu.m_Item = the menu entries. ASSERT(m_pChar); if ( rid.GetResType() != RES_SKILLMENU ) return false; bool fShowMenu = false; bool fLimitReached = false; if ( iSelect == 0 ) // menu cancelled return (Cmd_Skill_Menu_Build(rid, iSelect, NULL, 0, fShowMenu, fLimitReached) > 0); CMenuItem item[minimum(COUNTOF(m_tmMenu.m_Item), MAX_MENU_ITEMS)]; size_t iShowCount = Cmd_Skill_Menu_Build(rid, iSelect, item, COUNTOF(item), fShowMenu, fLimitReached); if ( iSelect < -1 ) // just a test return iShowCount ? true : false; if ( iSelect > 0 ) // seems our resources disappeared. { if ( iShowCount <= 0 ) SysMessageDefault(DEFMSG_CANT_MAKE); return iShowCount > 0 ? true : false; } if ( iShowCount <= 0 ) { SysMessageDefault(DEFMSG_CANT_MAKE_RES); return false; } if ( iShowCount == 1 && fShowMenu && !fLimitReached ) { static int sm_iReentrant = 0; if ( sm_iReentrant < 12 ) { sm_iReentrant++; // If there is just one menu then select it. bool fSuccess = Cmd_Skill_Menu(rid, m_tmMenu.m_Item[1]); sm_iReentrant--; return fSuccess; } if ( g_Cfg.m_wDebugFlags & DEBUGF_SCRIPTS ) g_Log.EventDebug("SCRIPT: Too many empty skill menus to continue seeking through menu '%s'\n", g_Cfg.ResourceGetDef(rid)->GetResourceName()); } ASSERT(iShowCount < COUNTOF(item)); addItemMenu(CLIMODE_MENU_SKILL, item, iShowCount); return true; }
void CItem::Spawn_GenerateItem( CResourceDef * pDef ) { // Count how many items are here already. // This could be in a container. RESOURCE_ID_BASE rid = pDef->GetResourceID(); ITEMID_TYPE id = (ITEMID_TYPE) rid.GetResIndex(); int iDistMax = m_itSpawnItem.m_DistMax; int iAmountPile = m_itSpawnItem.m_pile; int iCount = 0; CItemContainer * pCont = dynamic_cast <CItemContainer *>( GetParent()); if ( pCont != NULL ) { iCount = pCont->ContentCount( rid ); } else { // If is equipped this will produce the item where you are standing. CPointMap pt = GetTopLevelObj()->GetTopPoint(); CWorldSearch AreaItems( pt, iDistMax ); while (true) { CItem * pItem = AreaItems.GetItem(); if ( pItem == NULL ) break; if ( pItem->IsType(IT_SPAWN_ITEM)) continue; if ( pItem->IsAttr( ATTR_INVIS )) continue; if ( pItem->GetID() != id ) continue; // if ( pItem->m_uidLink != GetUID()) continue; iCount += pItem->GetAmount(); } } if ( iCount >= GetAmount()) return; CItem * pItem = CreateTemplate( id ); if ( pItem == NULL ) return; pItem->SetAttr( m_Attr & ( ATTR_OWNED | ATTR_MOVE_ALWAYS )); if ( iAmountPile > 1 ) { CItemBase * pItemDef = pItem->Item_GetDef(); ASSERT(pItemDef); if ( pItemDef->IsStackableType()) { if ( iAmountPile == 0 || iAmountPile > GetAmount()) iAmountPile = GetAmount(); pItem->SetAmount( Calc_GetRandVal(iAmountPile) + 1 ); } } // pItem->m_uidLink = GetUID(); // This might be dangerous ? pItem->SetDecayTime( g_Cfg.m_iDecay_Item ); // It will decay eventually to be replaced later. pItem->MoveNearObj( this, iDistMax ); }
CResourceDef * CItem::Spawn_FixDef() { // Get a proper RESOURCE_ID from the id provided. // RETURN: true = ok. RESOURCE_ID_BASE rid; if ( IsType(IT_SPAWN_ITEM)) { rid = m_itSpawnItem.m_ItemID; } else { ASSERT( IsType(IT_SPAWN_CHAR) ); rid = m_itSpawnChar.m_CharID; } if ( rid.GetResType() != RES_UNKNOWN ) { return STATIC_CAST <CResourceDef *>( g_Cfg.ResourceGetDef(rid)); } // No type info here !? if ( IsType(IT_SPAWN_ITEM)) { ITEMID_TYPE id = (ITEMID_TYPE) rid.GetResIndex(); if ( id < ITEMID_TEMPLATE ) { why_not_try_this_item: CItemBase * pItemDef = CItemBase::FindItemBase( id ); if ( pItemDef ) { m_itSpawnItem.m_ItemID = RESOURCE_ID( RES_ITEMDEF, id ); return( pItemDef ); } } else { // try a template. rid = RESOURCE_ID( RES_TEMPLATE, id ); CResourceDef * pDef = g_Cfg.ResourceGetDef(rid); if ( pDef ) { m_itSpawnItem.m_ItemID = rid; return( STATIC_CAST <CResourceDef *>( pDef )); } goto why_not_try_this_item; } } else { CREID_TYPE id = (CREID_TYPE) rid.GetResIndex(); if ( id < SPAWNTYPE_START ) { why_not_try_this_char: CCharBase * pCharDef = CCharBase::FindCharBase( id ); if ( pCharDef ) { m_itSpawnChar.m_CharID = RESOURCE_ID( RES_CHARDEF, id ); return( pCharDef ); } } else { // try a spawn group. rid = RESOURCE_ID( RES_SPAWN, id ); CResourceDef * pDef = g_Cfg.ResourceGetDef(rid); if ( pDef ) { m_itSpawnChar.m_CharID = rid; return( STATIC_CAST <CResourceDef *>( pDef )); } goto why_not_try_this_char; } } return( NULL ); }
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; }
void CItemSpawn::GenerateChar(CResourceDef * pDef) { ADDTOCALLSTACK("CitemSpawn:GenerateChar"); if ( !IsTopLevel() || ( m_itSpawnChar.m_current >= GetAmount() ) || ( GetTopSector()->GetCharComplexity() > g_Cfg.m_iMaxCharComplexity )) return; int iDistMax = m_itSpawnChar.m_DistMax; RESOURCE_ID_BASE rid = pDef->GetResourceID(); if ( rid.GetResType() == RES_SPAWN ) { const CRandGroupDef * pSpawnGroup = STATIC_CAST <const CRandGroupDef *>(pDef); ASSERT(pSpawnGroup); size_t i = pSpawnGroup->GetRandMemberIndex(); if ( i != pSpawnGroup->BadMemberIndex() ) { rid = pSpawnGroup->GetMemberID(i); } } if (( rid.GetResType() != RES_CHARDEF ) && ( rid.GetResType() != RES_UNKNOWN )) return; CREID_TYPE id = static_cast<CREID_TYPE>(rid.GetResIndex()); bool isBadPlaceToSpawn = false; CChar * pChar = CChar::CreateBasic(id); if( pChar == NULL ) { return; } pChar->NPC_LoadScript(true); AddObj(pChar->GetUID()); pChar->m_uidSpawnItem = GetUID(); // SpawnItem for this char pChar->StatFlag_Set( STATF_Spawned ); pChar->MoveTo(GetTopPoint()); pChar->NPC_CreateTrigger(); //Removed from NPC_LoadScript() and triggered after char placement if( pChar->GetRegion() == NULL ) { isBadPlaceToSpawn = true; } else if( pChar->GetRegion()->IsGuarded() && pChar->Noto_IsEvil() ) { isBadPlaceToSpawn = true; } // Deny definitely known a bad place to spawn (like red NPCs in guarded areas) // Usually caused by wide range near the edge of the towns if( isBadPlaceToSpawn ) { pChar->Delete(); //m_itSpawnChar.m_current--; return; } ASSERT(pChar->m_pNPC); if ( iDistMax ) { pChar->m_ptHome = GetTopPoint(); pChar->m_pNPC->m_Home_Dist_Wander = static_cast<WORD>(iDistMax); } pChar->Update(); }