void CItemSpawn::OnTick(bool fExec) { ADDTOCALLSTACK("CitemSpawn:OnTick"); INT64 iMinutes; if ( m_itSpawnChar.m_TimeHiMin <= 0 ) iMinutes = Calc_GetRandLLVal(30) + 1; else iMinutes = minimum(m_itSpawnChar.m_TimeHiMin, m_itSpawnChar.m_TimeLoMin) + Calc_GetRandLLVal(abs(m_itSpawnChar.m_TimeHiMin - m_itSpawnChar.m_TimeLoMin)); if ( iMinutes <= 0 ) iMinutes = 1; if ( !fExec || IsTimerExpired() ) SetTimeout(iMinutes * 60 * TICK_PER_SEC); // set time to check again. if ( !fExec || m_currentSpawned >= GetAmount() ) return; CResourceDef *pDef = FixDef(); if ( !pDef ) { RESOURCE_ID_BASE rid = IsType(IT_SPAWN_ITEM) ? m_itSpawnItem.m_ItemID : m_itSpawnChar.m_CharID; DEBUG_ERR(("Bad Spawn point uid=0%lx, id=%s\n", (DWORD)GetUID(), g_Cfg.ResourceGetName(rid))); return; } if ( IsType(IT_SPAWN_ITEM) ) GenerateItem(pDef); else GenerateChar(pDef); }
bool CChar::Use_Kindling( CItem * pKindling ) { ADDTOCALLSTACK("CChar::Use_Kindling"); ASSERT(pKindling); if ( !pKindling->IsTopLevel() ) { SysMessageDefault(DEFMSG_ITEMUSE_KINDLING_CONT); return false; } if ( !Skill_UseQuick(SKILL_CAMPING, Calc_GetRandLLVal(30)) ) { SysMessageDefault(DEFMSG_ITEMUSE_KINDLING_FAIL); return false; } pKindling->SetID(ITEMID_CAMPFIRE); pKindling->SetAttr(ATTR_MOVE_NEVER|ATTR_CAN_DECAY); pKindling->SetTimeout((4 + pKindling->GetAmount()) * 60 * TICK_PER_SEC); pKindling->SetAmount(1); // all kindling is set to one fire pKindling->m_itLight.m_pattern = LIGHT_LARGE; pKindling->Update(); pKindling->Sound(0x226); return true; }
bool CChar::Use_Train_PickPocketDip( CItem *pItem, bool fSetup ) { ADDTOCALLSTACK("CChar::Use_Train_PickPocketDip"); // IT_TRAIN_PICKPOCKET // Train dummy. ASSERT(pItem); if ( Skill_GetBase(SKILL_STEALING) > g_Cfg.m_iSkillPracticeMax ) { SysMessageDefault(DEFMSG_ITEMUSE_PDUMMY_SKILL); return true; } if ( !pItem->IsTopLevel() ) { badpickpocket: SysMessageDefault(DEFMSG_ITEMUSE_PDUMMY_P); return true; } int dx = GetTopPoint().m_x - pItem->GetTopPoint().m_x; int dy = GetTopPoint().m_y - pItem->GetTopPoint().m_y; bool fNS = (pItem->GetDispID() == ITEMID_PICKPOCKET_NS || pItem->GetDispID() == ITEMID_PICKPOCKET_NS2); if ( fNS ) { if ( !(!dx && abs(dy) < 2) ) goto badpickpocket; } else { if ( !(!dy && abs(dx) < 2) ) goto badpickpocket; } if ( fSetup ) { if ( Skill_GetActive() == NPCACT_TRAINING ) return true; m_Act_TargPrv = m_uidWeapon; m_Act_Targ = pItem->GetUID(); Skill_Start(NPCACT_TRAINING); } else if ( !Skill_UseQuick(SKILL_STEALING, Calc_GetRandLLVal(40)) ) { pItem->Sound(0x041); pItem->SetAnim(fNS ? ITEMID_PICKPOCKET_NS_FX : ITEMID_PICKPOCKET_EW_FX, 3 * TICK_PER_SEC); UpdateAnimate(ANIM_ATTACK_WEAPON); } else { SysMessageDefault(DEFMSG_ITEMUSE_PDUMMY_OK); //pItem->Sound(0x033); } return true; }
bool CClient::Cmd_Skill_Tracking( WORD track_sel, bool bExec ) { ADDTOCALLSTACK("CClient::Cmd_Skill_Tracking"); // look around for stuff. ASSERT(m_pChar); if ( track_sel == USHRT_MAX ) { // Unlike others skills, Tracking is used during menu setup m_pChar->Skill_Cleanup(); // clean up current skill CMenuItem item[6]; item[0].m_sText = g_Cfg.GetDefaultMsg(DEFMSG_TRACKING_SKILLMENU_TITLE); item[1].m_id = ITEMID_TRACK_HORSE; item[1].m_color = 0; item[1].m_sText = g_Cfg.GetDefaultMsg(DEFMSG_TRACKING_SKILLMENU_ANIMALS); item[2].m_id = ITEMID_TRACK_OGRE; item[2].m_color = 0; item[2].m_sText = g_Cfg.GetDefaultMsg(DEFMSG_TRACKING_SKILLMENU_MONSTERS); item[3].m_id = ITEMID_TRACK_MAN; item[3].m_color = 0; item[3].m_sText = g_Cfg.GetDefaultMsg(DEFMSG_TRACKING_SKILLMENU_NPCS); item[4].m_id = ITEMID_TRACK_WOMAN; item[4].m_color = 0; item[4].m_sText = g_Cfg.GetDefaultMsg(DEFMSG_TRACKING_SKILLMENU_PLAYERS); m_tmMenu.m_Item[0] = 0; addItemMenu(CLIMODE_MENU_SKILL_TRACK_SETUP, item, 4); return true; } if ( track_sel > 0 ) // Not Cancelled { ASSERT(track_sel < COUNTOF(m_tmMenu.m_Item)); if ( bExec ) { // Tracking menu got us here. Start tracking the selected creature. m_pChar->SetTimeout(1 * TICK_PER_SEC); m_pChar->m_Act_Targ = static_cast<CGrayUID>(m_tmMenu.m_Item[track_sel]); m_pChar->Skill_Start(SKILL_TRACKING); return true; } static const NPCBRAIN_TYPE sm_Track_Brain[] = { NPCBRAIN_QTY, // not used here NPCBRAIN_ANIMAL, NPCBRAIN_MONSTER, NPCBRAIN_HUMAN, NPCBRAIN_NONE // players }; if ( track_sel >= COUNTOF(sm_Track_Brain) ) track_sel = COUNTOF(sm_Track_Brain) - 1; NPCBRAIN_TYPE track_type = sm_Track_Brain[track_sel]; CMenuItem item[minimum(MAX_MENU_ITEMS, COUNTOF(m_tmMenu.m_Item))]; size_t count = 0; item[0].m_sText = g_Cfg.GetDefaultMsg(DEFMSG_TRACKING_SKILLMENU_TITLE); m_tmMenu.m_Item[0] = track_sel; CWorldSearch AreaChars(m_pChar->GetTopPoint(), m_pChar->Skill_GetBase(SKILL_TRACKING) / 10 + 10); for (;;) { CChar *pChar = AreaChars.GetChar(); if ( !pChar ) break; if ( pChar == m_pChar ) continue; if ( pChar->GetNPCBrain() != track_type ) continue; if ( pChar->IsStatFlag(STATF_DEAD) ) // can't track ghosts continue; if ( pChar->m_pPlayer ) { // Prevent track hidden GMs if ( pChar->IsStatFlag(STATF_Insubstantial) && (pChar->GetPrivLevel() > GetPrivLevel()) ) continue; // Check action difficulty when trying to track players int tracking = m_pChar->Skill_GetBase(SKILL_TRACKING); int detectHidden = m_pChar->Skill_GetBase(SKILL_DETECTINGHIDDEN); if ( (g_Cfg.m_iRacialFlags & RACIALF_ELF_DIFFTRACK) && pChar->IsElf() ) tracking /= 2; // elves are more difficult to track (Difficult to Track racial trait) int hiding = pChar->Skill_GetBase(SKILL_HIDING); int stealth = pChar->Skill_GetBase(SKILL_STEALTH); int divisor = maximum(hiding + stealth, 1); int chance; if ( g_Cfg.m_iFeatureSE & FEATURE_SE_UPDATE ) chance = 50 * (tracking * 2 + detectHidden) / divisor; else chance = 50 * (tracking + detectHidden + 10 * Calc_GetRandVal(20)) / divisor; if ( Calc_GetRandVal(100) > chance ) continue; } CCharBase *pCharDef = pChar->Char_GetDef(); if ( !pCharDef ) continue; count++; item[count].m_id = static_cast<WORD>(pCharDef->m_trackID); item[count].m_color = 0; item[count].m_sText = pChar->GetName(); m_tmMenu.m_Item[count] = pChar->GetUID(); if ( count >= COUNTOF(item) - 1 ) break; } // Some credit for trying if ( count > 0 ) { m_pChar->Skill_UseQuick(SKILL_TRACKING, 20 + Calc_GetRandLLVal(30)); ASSERT(count < COUNTOF(item)); addItemMenu(CLIMODE_MENU_SKILL_TRACK, item, count); return true; } else { // Tracking failed or cancelled m_pChar->Skill_UseQuick(SKILL_TRACKING, 10 + Calc_GetRandLLVal(30)); static LPCTSTR const sm_Track_FailMsg[] = { g_Cfg.GetDefaultMsg(DEFMSG_TRACKING_FAIL_ANIMAL), g_Cfg.GetDefaultMsg(DEFMSG_TRACKING_FAIL_MONSTER), g_Cfg.GetDefaultMsg(DEFMSG_TRACKING_FAIL_PEOPLE), g_Cfg.GetDefaultMsg(DEFMSG_TRACKING_FAIL_PEOPLE) }; if ( sm_Track_FailMsg[track_sel - 1] ) SysMessage(sm_Track_FailMsg[track_sel - 1]); } } return false; }
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; }
bool CChar::Use_Train_Dummy( CItem * pItem, bool fSetup ) { ADDTOCALLSTACK("CChar::Use_Train_Dummy"); // IT_TRAIN_DUMMY // Dummy animation timer prevents over dclicking. ASSERT(pItem); SKILL_TYPE skill = Fight_GetWeaponSkill(); if ( g_Cfg.IsSkillFlag(skill, SKF_RANGED) ) // do not allow archery training on dummys { SysMessageDefault(DEFMSG_ITEMUSE_TDUMMY_ARCH); return false; } char skilltag[32]; sprintf(skilltag, "OVERRIDE.PracticeMax.SKILL_%d", skill &~0xD2000000); CVarDefCont *pSkillTag = pItem->GetKey(skilltag, true); int iMaxSkill = pSkillTag ? static_cast<int>(pSkillTag->GetValNum()) : g_Cfg.m_iSkillPracticeMax; if ( Skill_GetBase(skill) > iMaxSkill ) { SysMessageDefault(DEFMSG_ITEMUSE_TDUMMY_SKILL); return false; } if ( !pItem->IsTopLevel() ) { baddumy: SysMessageDefault(DEFMSG_ITEMUSE_TDUMMY_P); return false ; } // Check location int dx = GetTopPoint().m_x - pItem->GetTopPoint().m_x; int dy = GetTopPoint().m_y - pItem->GetTopPoint().m_y; if ( pItem->GetDispID() == ITEMID_DUMMY1 ) { if ( !(!dx && abs(dy) < 2) ) goto baddumy; } else { if ( !(!dy && abs(dx) < 2) ) goto baddumy; } if ( fSetup ) { if ( Skill_GetActive() == NPCACT_TRAINING ) return true; UpdateAnimate(ANIM_ATTACK_WEAPON); m_Act_TargPrv = m_uidWeapon; m_Act_Targ = pItem->GetUID(); Skill_Start(NPCACT_TRAINING); } else { pItem->SetAnim(static_cast<ITEMID_TYPE>(pItem->GetID() + 1), 3 * TICK_PER_SEC); pItem->Sound(0x033); Skill_UseQuick(skill, Calc_GetRandLLVal(40)); } return true; }
bool CChar::Use_Key( CItem * pKey, CItem * pItemTarg ) { ADDTOCALLSTACK("CChar::Use_Key"); ASSERT(pKey); ASSERT(pKey->IsType(IT_KEY)); if ( !pItemTarg ) { SysMessageDefault(DEFMSG_MSG_KEY_TARG); return false; } if ( pKey != pItemTarg && pItemTarg->IsType(IT_KEY) ) { // We are trying to copy a key ? if ( !CanUse(pItemTarg, true) ) { SysMessageDefault(DEFMSG_MSG_KEY_TARG_REACH); return false; } if ( !pKey->m_itKey.m_lockUID && !pItemTarg->m_itKey.m_lockUID ) { SysMessageDefault(DEFMSG_MSG_KEY_BLANKS); return false; } if ( pItemTarg->m_itKey.m_lockUID && pKey->m_itKey.m_lockUID ) { SysMessageDefault(DEFMSG_MSG_KEY_NOTBLANKS); return false; } // Need tinkering tools ??? if ( !Skill_UseQuick(SKILL_TINKERING, 30 + Calc_GetRandLLVal(40)) ) { SysMessageDefault(DEFMSG_MSG_KEY_FAILC); return false; } if ( pItemTarg->m_itKey.m_lockUID ) pKey->m_itKey.m_lockUID = pItemTarg->m_itKey.m_lockUID; else pItemTarg->m_itKey.m_lockUID = pKey->m_itKey.m_lockUID; return true; } if ( !pKey->m_itKey.m_lockUID ) { SysMessageDefault(DEFMSG_MSG_KEY_ISBLANK); return false; } if ( pKey == pItemTarg ) // rename the key { if ( IsClient() ) GetClient()->addPromptConsole(CLIMODE_PROMPT_NAME_KEY, g_Cfg.GetDefaultMsg(DEFMSG_MSG_KEY_SETNAME), pKey->GetUID()); return false; } if ( !CanUse(pItemTarg, false) ) { SysMessageDefault(DEFMSG_MSG_KEY_CANTREACH); return false; } if ( m_pArea->GetResourceID() == pKey->m_itKey.m_lockUID ) { if ( Use_MultiLockDown(pItemTarg) ) return true; } if ( !pItemTarg->m_itContainer.m_lockUID ) // or m_itContainer.m_lockUID { SysMessageDefault(DEFMSG_MSG_KEY_NOLOCK); return false; } if ( !pKey->IsKeyLockFit(pItemTarg->m_itContainer.m_lockUID) ) // or m_itKey { SysMessageDefault(DEFMSG_MSG_KEY_WRONGLOCK); return false; } return Use_KeyChange(pItemTarg); }
llong CExpression::GetSingle( lpctstr & pszArgs ) { ADDTOCALLSTACK("CExpression::GetSingle"); // Parse just a single expression without any operators or ranges. ASSERT(pszArgs); GETNONWHITESPACE( pszArgs ); lpctstr orig = pszArgs; if (pszArgs[0]=='.') ++pszArgs; if ( pszArgs[0] == '0' ) // leading '0' = hex value. { // A hex value. if ( pszArgs[1] == '.' ) // leading 0. means it really is decimal. { pszArgs += 2; goto try_dec; } lpctstr pStart = pszArgs; ullong val = 0; while (true) { tchar ch = *pszArgs; if ( IsDigit(ch) ) ch -= '0'; else { ch = static_cast<tchar>(tolower(ch)); if ( ch > 'f' || ch < 'a' ) { if ( ch == '.' && pStart[0] != '0' ) // ok i'm confused. it must be decimal. { pszArgs = pStart; goto try_dec; } break; } ch -= 'a' - 10; } val *= 0x10; val += ch; ++pszArgs; } return (llong)val; } else if ( pszArgs[0] == '.' || IsDigit(pszArgs[0]) ) { // A decminal number try_dec: llong iVal = 0; for ( ; ; ++pszArgs ) { if ( *pszArgs == '.' ) continue; // just skip this. if ( ! IsDigit(*pszArgs) ) break; iVal *= 10; iVal += *pszArgs - '0'; } return iVal; } else if ( ! _ISCSYMF(pszArgs[0]) ) { #pragma region maths // some sort of math op ? switch ( pszArgs[0] ) { case '{': ++pszArgs; return GetRangeNumber( pszArgs ); case '[': case '(': // Parse out a sub expression. ++pszArgs; return GetVal( pszArgs ); case '+': ++pszArgs; break; case '-': ++pszArgs; return -GetSingle( pszArgs ); case '~': // Bitwise not. ++pszArgs; return ~GetSingle( pszArgs ); case '!': // boolean not. ++pszArgs; if ( pszArgs[0] == '=' ) // odd condition such as (!=x) which is always true of course. { ++pszArgs; // so just skip it. and compare it to 0 return GetSingle( pszArgs ); } return !GetSingle( pszArgs ); case ';': // seperate field. case ',': // seperate field. case '\0': return 0; } #pragma endregion maths } else #pragma region intrinsics { // Symbol or intrinsinc function ? INTRINSIC_TYPE iIntrinsic = (INTRINSIC_TYPE) FindTableHeadSorted( pszArgs, sm_IntrinsicFunctions, CountOf(sm_IntrinsicFunctions)-1 ); if ( iIntrinsic >= 0 ) { size_t iLen = strlen(sm_IntrinsicFunctions[iIntrinsic]); if ( pszArgs[iLen] == '(' ) { pszArgs += (iLen + 1); tchar * pszArgsNext; Str_Parse( const_cast<tchar*>(pszArgs), &(pszArgsNext), ")" ); tchar * ppCmd[5]; llong iResult; size_t iCount = 0; switch ( iIntrinsic ) { case INTRINSIC_ID: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = RES_GET_INDEX( GetVal(pszArgs) ); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_MAX: { iCount = Str_ParseCmds( const_cast<tchar*>(pszArgs), ppCmd, 2, "," ); if ( iCount < 2 ) iResult = 0; else { const int64 iVal1 = GetVal(ppCmd[0]), iVal2 = GetVal(ppCmd[1]); iResult = maximum(iVal1, iVal2); } } break; case INTRINSIC_MIN: { iCount = Str_ParseCmds( const_cast<tchar*>(pszArgs), ppCmd, 2, "," ); if ( iCount < 2 ) iResult = 0; else { const int64 iVal1 = GetVal(ppCmd[0]), iVal2 = GetVal(ppCmd[1]); iResult = minimum(iVal1, iVal2); } } break; case INTRINSIC_LOGARITHM: { iCount = 0; iResult = 0; if ( pszArgs && *pszArgs ) { llong iArgument = GetVal(pszArgs); if ( iArgument <= 0 ) { DEBUG_ERR(( "Exp_GetVal: (x)Log(%" PRId64 ") is %s\n", iArgument, (!iArgument) ? "infinite" : "undefined" )); } else { iCount = 1; if ( strchr(pszArgs, ',') ) { ++iCount; SKIP_ARGSEP(pszArgs); if ( !strcmpi(pszArgs, "e") ) { iResult = (llong)log( (double)iArgument ); } else if ( !strcmpi(pszArgs, "pi") ) { iResult = (llong)(log( (double)iArgument ) / log( M_PI ) ); } else { llong iBase = GetVal(pszArgs); if ( iBase <= 0 ) { DEBUG_ERR(( "Exp_GetVal: (%" PRId64 ")Log(%" PRId64 ") is %s\n", iBase, iArgument, (!iBase ? "infinite" : "undefined") )); iCount = 0; } else iResult = (llong)(log( (double)iArgument ) / log( (double)iBase )); } } else iResult = (llong)log10( (double)iArgument ); } } } break; case INTRINSIC_NAPIERPOW: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = (llong)exp( (double)GetVal( pszArgs ) ); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_SQRT: { iCount = 0; iResult = 0; if ( pszArgs && *pszArgs ) { llong iTosquare = GetVal(pszArgs); if (iTosquare >= 0) { ++iCount; iResult = (llong)sqrt( (double)iTosquare ); } else DEBUG_ERR(( "Exp_GetVal: Sqrt of negative number (%" PRId64 ") is impossible\n", iTosquare )); } } break; case INTRINSIC_SIN: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = (llong)sin( (double)GetVal( pszArgs ) ); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_ARCSIN: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = (llong)asin( (double)GetVal( pszArgs ) ); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_COS: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = (llong)cos( (double)GetVal( pszArgs ) ); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_ARCCOS: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = (llong)acos( (double)GetVal( pszArgs ) ); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_TAN: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = (llong)tan( (double)GetVal( pszArgs ) ); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_ARCTAN: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = (llong)atan( (double)GetVal( pszArgs ) ); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_StrIndexOf: { iCount = Str_ParseCmds( const_cast<tchar*>(pszArgs), ppCmd, 3, "," ); if ( iCount < 2 ) iResult = -1; else iResult = Str_IndexOf( ppCmd[0] , ppCmd[1] , (iCount==3)?(int)GetVal(ppCmd[2]):0 ); } break; case INTRINSIC_STRMATCH: { iCount = Str_ParseCmds( const_cast<tchar*>(pszArgs), ppCmd, 2, "," ); if ( iCount < 2 ) iResult = 0; else iResult = (Str_Match( ppCmd[0], ppCmd[1] ) == MATCH_VALID ) ? 1 : 0; } break; case INTRINSIC_STRREGEX: { iCount = Str_ParseCmds( const_cast<tchar*>(pszArgs), ppCmd, 2, "," ); if ( iCount < 2 ) iResult = 0; else { tchar * tLastError = Str_GetTemp(); iResult = Str_RegExMatch( ppCmd[0], ppCmd[1], tLastError ); if ( iResult == -1 ) { DEBUG_ERR(( "STRREGEX bad function usage. Error: %s\n", tLastError )); } } } break; case INTRINSIC_RANDBELL: { iCount = Str_ParseCmds( const_cast<tchar*>(pszArgs), ppCmd, 2, "," ); if ( iCount < 2 ) iResult = 0; else iResult = Calc_GetBellCurve( (int)GetVal( ppCmd[0] ), (int)GetVal( ppCmd[1] ) ); } break; case INTRINSIC_STRASCII: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = pszArgs[0]; } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_RAND: { iCount = Str_ParseCmds( const_cast<tchar*>(pszArgs), ppCmd, 2, "," ); if ( iCount <= 0 ) iResult = 0; else { int64 val1 = GetVal( ppCmd[0] ); if ( iCount == 2 ) { int64 val2 = GetVal( ppCmd[1] ); iResult = Calc_GetRandLLVal2( val1, val2 ); } else iResult = Calc_GetRandLLVal(val1); } } break; case INTRINSIC_STRCMP: { iCount = Str_ParseCmds( const_cast<tchar*>(pszArgs), ppCmd, 2, "," ); if ( iCount < 2 ) iResult = 1; else iResult = strcmp(ppCmd[0], ppCmd[1]); } break; case INTRINSIC_STRCMPI: { iCount = Str_ParseCmds( const_cast<tchar*>(pszArgs), ppCmd, 2, "," ); if ( iCount < 2 ) iResult = 1; else iResult = strcmpi(ppCmd[0], ppCmd[1]); } break; case INTRINSIC_STRLEN: { iCount = 1; iResult = strlen(pszArgs); } break; case INTRINSIC_ISOBSCENE: { iCount = 1; iResult = g_Cfg.IsObscene( pszArgs ); } break; case INTRINSIC_ISNUMBER: { iCount = 1; { GETNONWHITESPACE( pszArgs ); if (*pszArgs == '-') ++pszArgs; iResult = IsStrNumeric( pszArgs ); } } break; case INTRINSIC_QVAL: { iCount = Str_ParseCmds( const_cast<tchar*>(pszArgs), ppCmd, 5, "," ); if ( iCount < 3 ) iResult = 0; else { llong a1 = GetSingle(ppCmd[0]); llong a2 = GetSingle(ppCmd[1]); if ( a1 < a2 ) iResult = GetSingle(ppCmd[2]); else if ( a1 == a2 ) iResult = ( iCount < 4 ) ? 0 : GetSingle(ppCmd[3]); else iResult = ( iCount < 5 ) ? 0 : GetSingle(ppCmd[4]); } } break; case INTRINSIC_ABS: { iCount = 1; iResult = llabs(GetVal(pszArgs)); } break; default: iCount = 0; iResult = 0; break; } pszArgs = pszArgsNext; if ( !iCount ) { DEBUG_ERR(( "Bad intrinsic function usage: Missing arguments\n" )); return 0; } else return iResult; } } // Must be a symbol of some sort ? lpctstr ptcArgsOriginal = pszArgs; llong llVal; if ( m_VarGlobals.GetParseVal_Advance( pszArgs, &llVal ) ) // VAR. return llVal; if ( m_VarResDefs.GetParseVal( ptcArgsOriginal, &llVal ) ) // RESDEF. return llVal; if ( m_VarDefs.GetParseVal( ptcArgsOriginal, &llVal ) ) // DEF. return llVal; } #pragma endregion intrinsics // hard end ! Error of some sort. tchar szTag[ EXPRESSION_MAX_KEY_LEN ]; size_t i = GetIdentifierString( szTag, pszArgs ); pszArgs += i; // skip it. if ( strlen(orig) > 1) DEBUG_ERR(("Undefined symbol '%s' ['%s']\n", szTag, orig)); else DEBUG_ERR(("Undefined symbol '%s'\n", szTag)); return 0; }
INT64 CExpression::GetSingle( LPCTSTR & pszArgs ) { ADDTOCALLSTACK("CExpression::GetSingle"); // Parse just a single expression without any operators or ranges. ASSERT(pszArgs); GETNONWHITESPACE( pszArgs ); LPCTSTR orig = pszArgs; if (pszArgs[0]=='.') pszArgs++; if ( pszArgs[0] == '0' ) // leading '0' = hex value. { // A hex value. if ( pszArgs[1] == '.' ) // leading 0. means it really is decimal. { pszArgs += 2; goto try_dec; } LPCTSTR pStart = pszArgs; ULONGLONG val = 0; for (;;) { TCHAR ch = *pszArgs; if ( IsDigit( ch )) ch -= '0'; else { ch = static_cast<TCHAR>(tolower(ch)); if ( ch > 'f' || ch <'a' ) { if ( ch == '.' && pStart[0] != '0' ) // ok i'm confused. it must be decimal. { pszArgs = pStart; goto try_dec; } break; } ch -= 'a' - 10; } val *= 0x10; val += ch; pszArgs ++; } return( (INT64)val ); } else if ( pszArgs[0] == '.' || IsDigit(pszArgs[0])) { // A decminal number try_dec: INT64 iVal = 0; for ( ; ; pszArgs++ ) { if ( *pszArgs == '.' ) continue; // just skip this. if ( ! IsDigit( *pszArgs )) break; iVal *= 10; iVal += *pszArgs - '0'; } return( iVal ); } else if ( ! _ISCSYMF(pszArgs[0])) { #pragma region maths // some sort of math op ? switch ( pszArgs[0] ) { case '{': pszArgs ++; return( GetRange( pszArgs )); case '[': case '(': // Parse out a sub expression. pszArgs ++; return(GetVal( pszArgs )); case '+': pszArgs++; break; case '-': pszArgs++; return( -GetSingle( pszArgs )); case '~': // Bitwise not. pszArgs++; return( ~GetSingle( pszArgs )); case '!': // boolean not. pszArgs++; if ( pszArgs[0] == '=' ) // odd condition such as (!=x) which is always true of course. { pszArgs++; // so just skip it. and compare it to 0 return( GetSingle( pszArgs )); } return( !GetSingle( pszArgs )); case ';': // seperate field. case ',': // seperate field. case '\0': return( 0 ); } #pragma endregion maths } else #pragma region intrinsics { // Symbol or intrinsinc function ? INTRINSIC_TYPE iIntrinsic = (INTRINSIC_TYPE) FindTableHeadSorted( pszArgs, sm_IntrinsicFunctions, COUNTOF(sm_IntrinsicFunctions)-1 ); if ( iIntrinsic >= 0 ) { size_t iLen = strlen(sm_IntrinsicFunctions[iIntrinsic]); if ( pszArgs[iLen] == '(' ) { pszArgs += (iLen + 1); TCHAR * pszArgsNext; Str_Parse( const_cast<TCHAR*>(pszArgs), &(pszArgsNext), ")" ); TCHAR * ppCmd[5]; INT64 iResult; size_t iCount = 0; switch ( iIntrinsic ) { case INTRINSIC_ID: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = RES_GET_INDEX( GetVal( pszArgs )); // RES_GET_INDEX } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_LOGARITHM: { iCount = 0; iResult = 0; if ( pszArgs && *pszArgs ) { int iArgument = static_cast<long>(GetVal(pszArgs)); if ( iArgument <= 0 ) { DEBUG_ERR(( "Exp_GetVal: (x)Log(%d) is %s\n", iArgument, (!iArgument) ? "infinite" : "undefined" )); } else { iCount = 1; if ( strchr(pszArgs, ',') ) { iCount++; SKIP_ARGSEP(pszArgs); if ( !strcmpi(pszArgs, "e") ) { iResult = static_cast<INT64>(log(static_cast<double>(iArgument))); } else if ( !strcmpi(pszArgs, "pi") ) { iResult = static_cast<INT64>(log(static_cast<double>(iArgument)) / log(M_PI)); } else { INT64 iBase = GetVal(pszArgs); if ( iBase <= 0 ) { DEBUG_ERR(( "Exp_GetVal: (%lld)Log(%d) is %s\n", iBase, iArgument, (!iBase) ? "infinite" : "undefined" )); iCount = 0; } else { iResult = static_cast<INT64>(log(static_cast<double>(iArgument)) / log(static_cast<double>(iBase))); } } } else { iResult = static_cast<INT64>(log10(static_cast<double>(iArgument))); } } } } break; case INTRINSIC_NAPIERPOW: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = static_cast<INT64>(exp(static_cast<double>(GetVal(pszArgs)))); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_SQRT: { iCount = 0; iResult = 0; if ( pszArgs && *pszArgs ) { int iTosquare = static_cast<long>(GetVal(pszArgs)); if (iTosquare >= 0) { iCount++; iResult = static_cast<INT64>(sqrt(static_cast<double>(iTosquare))); } else { DEBUG_ERR(( "Exp_GetVal: Sqrt of negative number (%d) is impossible\n", iTosquare )); } } } break; case INTRINSIC_SIN: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = static_cast<INT64>(sin(static_cast<double>(GetVal(pszArgs)))); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_ARCSIN: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = static_cast<INT64>(asin(static_cast<double>(GetVal(pszArgs)))); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_COS: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = static_cast<INT64>(cos(static_cast<double>(GetVal(pszArgs)))); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_ARCCOS: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = static_cast<INT64>(acos(static_cast<double>(GetVal(pszArgs)))); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_TAN: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = static_cast<INT64>(tan(static_cast<double>(GetVal(pszArgs)))); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_ARCTAN: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = static_cast<INT64>(atan(static_cast<double>(GetVal(pszArgs)))); } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_StrIndexOf: { iCount = Str_ParseCmds( const_cast<TCHAR*>(pszArgs), ppCmd, 3, "," ); if ( iCount < 2 ) iResult = -1; else iResult = Str_IndexOf(ppCmd[0],ppCmd[1],(iCount==3)?static_cast<long>(GetVal(ppCmd[2])):0); } break; case INTRINSIC_STRMATCH: { iCount = Str_ParseCmds( const_cast<TCHAR*>(pszArgs), ppCmd, 2, "," ); if ( iCount < 2 ) iResult = 0; else iResult = (Str_Match( ppCmd[0], ppCmd[1] ) == MATCH_VALID ) ? 1 : 0; } break; case INTRINSIC_STRREGEX: { iCount = Str_ParseCmds( const_cast<TCHAR*>(pszArgs), ppCmd, 2, "," ); if ( iCount < 2 ) iResult = 0; else { TCHAR * tLastError = Str_GetTemp(); iResult = Str_RegExMatch( ppCmd[0], ppCmd[1], tLastError ); if ( iResult == -1 ) { DEBUG_ERR(( "STRREGEX bad function usage. Error: %s\n", tLastError )); } } } break; case INTRINSIC_RANDBELL: { iCount = Str_ParseCmds( const_cast<TCHAR*>(pszArgs), ppCmd, 2, "," ); if ( iCount < 2 ) iResult = 0; else iResult = Calc_GetBellCurve( static_cast<long>(GetVal( ppCmd[0] )), static_cast<long>(GetVal( ppCmd[1] ))); } break; case INTRINSIC_STRASCII: { if ( pszArgs && *pszArgs ) { iCount = 1; iResult = pszArgs[0]; } else { iCount = 0; iResult = 0; } } break; case INTRINSIC_RAND: { iCount = Str_ParseCmds( const_cast<TCHAR*>(pszArgs), ppCmd, 2, "," ); if ( iCount <= 0 ) iResult = 0; else { INT64 val1 = GetVal( ppCmd[0] ); if ( iCount == 2 ) { INT64 val2 = GetVal( ppCmd[1] ); iResult = Calc_GetRandLLVal2( val1, val2 ); } else iResult = Calc_GetRandLLVal(val1); } } break; case INTRINSIC_STRCMP: { iCount = Str_ParseCmds( const_cast<TCHAR*>(pszArgs), ppCmd, 2, "," ); if ( iCount < 2 ) iResult = 1; else iResult = strcmp(ppCmd[0], ppCmd[1]); } break; case INTRINSIC_STRCMPI: { iCount = Str_ParseCmds( const_cast<TCHAR*>(pszArgs), ppCmd, 2, "," ); if ( iCount < 2 ) iResult = 1; else iResult = strcmpi(ppCmd[0], ppCmd[1]); } break; case INTRINSIC_STRLEN: { iCount = 1; iResult = strlen(pszArgs); } break; case INTRINSIC_ISOBSCENE: { iCount = 1; iResult = g_Cfg.IsObscene( pszArgs ); } break; case INTRINSIC_ISNUMBER: { iCount = 1; { char z[64]; LTOA(atol(pszArgs), z, 10); iResult = strcmp(pszArgs, z) ? 0 : 1; } } break; case INTRINSIC_QVAL: { iCount = Str_ParseCmds( const_cast<TCHAR*>(pszArgs), ppCmd, 5, "," ); if ( iCount < 3 ) iResult = 0; else { INT64 a1 = GetSingle(ppCmd[0]); INT64 a2 = GetSingle(ppCmd[1]); if ( a1 < a2 ) iResult = GetSingle(ppCmd[2]); else if ( a1 == a2 ) iResult = ( iCount < 4 ) ? 0 : GetSingle(ppCmd[3]); else iResult = ( iCount < 5 ) ? 0 : GetSingle(ppCmd[4]); } } break; case INTRINSIC_ABS: { iCount = 1; iResult = llabs(GetVal(pszArgs)); } break; default: iCount = 0; iResult = 0; break; } pszArgs = pszArgsNext; if ( ! iCount ) { DEBUG_ERR(( "Bad intrinsic function usage: Missing arguments\n" )); return 0; } else { return iResult; } } } // Must be a symbol of some sort ? long long lVal; if ( m_VarGlobals.GetParseVal( pszArgs, &lVal ) ) return(lVal); if ( m_VarDefs.GetParseVal( pszArgs, &lVal ) ) return(lVal); } #pragma endregion intrinsics // hard end ! Error of some sort. TCHAR szTag[ EXPRESSION_MAX_KEY_LEN ]; size_t i = GetIdentifierString( szTag, pszArgs ); pszArgs += i; // skip it. if (strlen(orig)> 1) DEBUG_ERR(("Undefined symbol '%s' ['%s']\n", szTag, orig)); else DEBUG_ERR(("Undefined symbol '%s'\n", szTag)); return( 0 ); }