diff --git a/Changelog.txt b/Changelog.txt index f6cebea5d..2fed73343 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3915,12 +3915,38 @@ Added: 'H' shortcut for variables to get the value as hexadecimal. 13-10-2024, Jhobean - Added: @PetRelease trigger work like @petdesert and return 1 to prevent the pet from being released. +26-10-2024, canerksk +- Fixed: Memory OnTick link char if not, the skill will not fail. + If the memory owner is not present, skills do not fail when taking damage, but if the memory owner is alive, skills fail when taking damage. + +- Fixed: The entity was jumping frames in flooded pet commands (come, guard) + +08-11-2024 +- Fixed: ITEMMEMORYEQUIP is not triggered in many default memories. + Previously, many memories did not have morex information, but now for some reason many memories have morex information and for this reason the trigger was not triggered in almost most of the memories, the morex query was removed. Also, the slang did not represent the memory item. + 27-11-2024, canerksk +- Added: All skills that have a distance query have been adjusted to take the RANGE values ​​of that skill. + All skills to be used in RANGE; + BLACKSMITHING + MINING // It was added before. + FISHING // It was added before. + LUMBERJACKING // It was added before. + PEACEMAKING + ENTICEMENT + PROVOCATION + COOKING + TAMING + THROWING + SNOOPING + STEALING + Also added BREATH.MAXDIST to Breath. If this property is not given, the default is 14 distance. - Added: Added NOREJOIN tag for corpses, If the NOREJOIN tag is one, the player cannot come back to life on that corpse. That is, the player comes back to life but not on the corpse. This tag does not prevent the player from coming back to life, it just prevents them from respawning on that corpse. The player always comes back to life, but not on that corpse. - -27-11-2024, canerksk - Fixed: If you are around an entity that you own and you are trying to open a bank next to a bank, the "bank" command is perceived as a pet command and the bank does not open. There is no problem when you type "bank" after mounting the mount, but "bank" does not work when you dismount. (Issue #1331) 27-11-2024, Gladie - Fixed: Redeeding t_multi_addon outside of housing system. Before it was only looking for owner of the multi, but in our case we need to know uid of the redeeding char. +======= +02-11-2024, raydie +- Added: Add LAYER_SPELL_Explosion for use delayed explosion spell. Now if set Duration to spell explosion, these duration is the delay to execute the explosion (From UOGuide, explosion spell: 2 second delay between targetting and explosion) diff --git a/src/game/chars/CChar.cpp b/src/game/chars/CChar.cpp index c1b95127a..fad039269 100644 --- a/src/game/chars/CChar.cpp +++ b/src/game/chars/CChar.cpp @@ -2510,7 +2510,7 @@ bool CChar::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, bo } case CHC_BREATH: { - if( !strnicmp(ptcKey, "BREATH.DAM", 10) ) + if (!strnicmp(ptcKey, "BREATH.MAXDIST", 14) || !strnicmp(ptcKey, "BREATH.DAM", 10)) { CVarDefCont * pVar = GetDefKey(ptcKey, true); sVal.FormatLLVal(pVar ? pVar->GetValNum() : 0); @@ -3808,7 +3808,7 @@ bool CChar::r_LoadVal( CScript & s ) break; case CHC_BREATH: { - if ( !strnicmp(ptcKey, "BREATH.DAM", 10) || !strnicmp(ptcKey, "BREATH.HUE", 10) || !strnicmp(ptcKey, "BREATH.ANIM", 11) || !strnicmp(ptcKey, "BREATH.TYPE", 11) || !strnicmp(ptcKey, "BREATH.DAMTYPE", 14)) + if ( !strnicmp(ptcKey, "BREATH.MAXDIST", 14) || !strnicmp(ptcKey, "BREATH.DAM", 10) || !strnicmp(ptcKey, "BREATH.HUE", 10) || !strnicmp(ptcKey, "BREATH.ANIM", 11) || !strnicmp(ptcKey, "BREATH.TYPE", 11) || !strnicmp(ptcKey, "BREATH.DAMTYPE", 14)) { SetDefNum(s.GetKey(), s.GetArgLLVal()); return true; diff --git a/src/game/chars/CCharAct.cpp b/src/game/chars/CCharAct.cpp index b4c427f1a..d6bf5d4e1 100644 --- a/src/game/chars/CCharAct.cpp +++ b/src/game/chars/CCharAct.cpp @@ -280,11 +280,14 @@ void CChar::LayerAdd( CItem * pItem, LAYER_TYPE layer ) return; } - if (!pItem->IsTypeSpellable() && !pItem->m_itSpell.m_spell && !pItem->IsType(IT_WAND)) // can this item have a spell effect ? If so we do not send - { + //if (!pItem->IsTypeSpellable() && !pItem->m_itSpell.m_spell && !pItem->IsType(IT_WAND)) // can this item have a spell effect ? If so we do not send + // Since most of the memories came with a morex information by default, almost no memory was triggered. + if (!(pItem->IsTypeSpellable() || pItem->IsType(IT_WAND))) + { if ((IsTrigUsed(TRIGGER_MEMORYEQUIP)) || (IsTrigUsed(TRIGGER_ITEMMEMORYEQUIP))) { - CScriptTriggerArgs pArgs; + //CScriptTriggerArgs pArgs; + CScriptTriggerArgs pArgs(pItem); // added "argo" argument pArgs.m_iN1 = layer; if (pItem->OnTrigger(ITRIG_MemoryEquip, this, &pArgs) == TRIGRET_RET_TRUE) { diff --git a/src/game/chars/CCharNPCPet.cpp b/src/game/chars/CCharNPCPet.cpp index 91e65ff6a..0b9ef724c 100644 --- a/src/game/chars/CCharNPCPet.cpp +++ b/src/game/chars/CCharNPCPet.cpp @@ -173,14 +173,20 @@ bool CChar::NPC_OnHearPetCmd( lpctstr pszCmd, CChar *pSrc, bool fAllPets ) break; case PC_GUARD_ME: - m_Act_UID = pSrc->GetUID(); - Skill_Start(NPCACT_GUARD_TARG); + if ((m_Act_UID != pSrc->GetUID()) || (Skill_GetActive() != NPCACT_GUARD_TARG)) // When you do all guard flood, the mount jumps one frame. + { + m_Act_UID = pSrc->GetUID(); + Skill_Start(NPCACT_GUARD_TARG); + } break; case PC_COME: case PC_FOLLOW_ME: - m_Act_UID = pSrc->GetUID(); - Skill_Start(NPCACT_FOLLOW_TARG); + if ((m_Act_UID != pSrc->GetUID()) || (Skill_GetActive() != NPCACT_FOLLOW_TARG)) // When you do all come flood, the mount jumps one frame. + { + m_Act_UID = pSrc->GetUID(); + Skill_Start(NPCACT_FOLLOW_TARG); + } break; case PC_FOLLOW: diff --git a/src/game/chars/CCharSkill.cpp b/src/game/chars/CCharSkill.cpp index fe11e036f..4a344e817 100644 --- a/src/game/chars/CCharSkill.cpp +++ b/src/game/chars/CCharSkill.cpp @@ -1078,10 +1078,21 @@ bool CChar::Skill_Mining_Smelt( CItem * pItemOre, CItem * pItemTarg ) return true; } - if ( pItemTarg != nullptr && pItemTarg->IsTopLevel() && pItemTarg->IsType( IT_FORGE )) - m_Act_p = pItemTarg->GetTopPoint(); - else - m_Act_p = CWorldMap::FindItemTypeNearby( GetTopPoint(), IT_FORGE, 3, false ); + if (pItemTarg != nullptr && pItemTarg->IsTopLevel() && pItemTarg->IsType(IT_FORGE)) + { + m_Act_p = pItemTarg->GetTopPoint(); + } + else + { + CSkillDef *pSkillDef = g_Cfg.GetSkillDef(SKILL_BLACKSMITHING); + int iMaxRange = pSkillDef->m_Range; + if (!iMaxRange) + { + g_Log.EventError("Blacksmith skill doesn't have a value for RANGE, defaulting to 3\n"); + iMaxRange = 3; + } + m_Act_p = CWorldMap::FindItemTypeNearby(GetTopPoint(), IT_FORGE, iMaxRange, false); + } if ( !m_Act_p.IsValidPoint() || !CanTouch(m_Act_p)) { @@ -1405,7 +1416,7 @@ int CChar::Skill_Mining( SKTRIG_TYPE stage ) const CSkillDef *pSkillDef = g_Cfg.GetSkillDef(SKILL_MINING); const int iTargRange = GetTopPoint().GetDist(m_Act_p); int iMaxRange = pSkillDef->m_Range; - if ( !iMaxRange ) + if (!iMaxRange) { g_Log.EventError("Mining skill doesn't have a value for RANGE, defaulting to 2\n"); iMaxRange = 2; @@ -1501,7 +1512,7 @@ int CChar::Skill_Fishing( SKTRIG_TYPE stage ) CSkillDef *pSkillDef = g_Cfg.GetSkillDef(SKILL_FISHING); int iTargRange = GetTopPoint().GetDist(m_Act_p); int iMaxRange = pSkillDef->m_Range; - if ( !iMaxRange ) + if (!iMaxRange) { g_Log.EventError("Fishing skill doesn't have a value for RANGE, defaulting to 4\n"); iMaxRange = 4; @@ -1603,7 +1614,7 @@ int CChar::Skill_Lumberjack( SKTRIG_TYPE stage ) CSkillDef *pSkillDef = g_Cfg.GetSkillDef(SKILL_LUMBERJACKING); int iTargRange = GetTopPoint().GetDist(m_Act_p); int iMaxRange = pSkillDef->m_Range; - if ( !pSkillDef->m_Range ) + if (!iMaxRange) { g_Log.EventError("Lumberjacking skill doesn't have a value for RANGE, defaulting to 2\n"); iMaxRange = 2; @@ -1825,7 +1836,15 @@ int CChar::Skill_Peacemaking( SKTRIG_TYPE stage ) { int peace = Skill_GetAdjusted(SKILL_PEACEMAKING); int iRadius = ( peace / 100 ) + 2; // 2..12 - auto Area = CWorldSearchHolder::GetInstance(GetTopPoint(), iRadius); + + CSkillDef *pSkillDef = g_Cfg.GetSkillDef(SKILL_PEACEMAKING); + int iMaxRadius = pSkillDef->m_Range; + if (!iMaxRadius) + { + //g_Log.EventError("Peacemaking skill doesn't have a value for RANGE, defaulting to (Peacemaking skill level / 100 + 2) \n"); + iMaxRadius = iRadius; + } + auto Area = CWorldSearchHolder::GetInstance(GetTopPoint(), iMaxRadius); for (;;) { CChar *pChar = Area->GetChar(); @@ -1951,9 +1970,15 @@ int CChar::Skill_Enticement( SKTRIG_TYPE stage ) SysMessagef("%s %s.", pChar->GetName(), g_Cfg.GetDefaultMsg(DEFMSG_ENTICEMENT_BATTLE)); return -SKTRIG_ABORT; } - + CSkillDef *pSkillDef = g_Cfg.GetSkillDef(SKILL_ENTICEMENT); + int iMaxRange = pSkillDef->m_Range; + if (!iMaxRange) + { + //g_Log.EventError("Enticement skill doesn't have a value for RANGE, defaulting 3\n"); + iMaxRange = 3; + } pChar->m_Act_p = GetTopPoint(); - pChar->NPC_WalkToPoint( ( pChar->m_Act_p.GetDist(pChar->GetTopPoint()) > 3) ); + pChar->NPC_WalkToPoint((pChar->m_Act_p.GetDist(pChar->GetTopPoint()) > iMaxRange)); return 0; } @@ -1969,6 +1994,9 @@ int CChar::Skill_Provocation(SKTRIG_TYPE stage) // m_Act_Prv_UID = provoke this person // m_Act_UID = against this person. + CSkillDef *pSkillDef = g_Cfg.GetSkillDef(SKILL_PROVOCATION); + int iMaxRange = pSkillDef->m_Range; + if ( stage == SKTRIG_ABORT ) return -SKTRIG_ABORT; @@ -2070,8 +2098,14 @@ int CChar::Skill_Provocation(SKTRIG_TYPE stage) pCharProv->Memory_AddObjTypes(this, MEMORY_AGGREIVED|MEMORY_IRRITATEDBY); + if (!iMaxRange) + { + //g_Log.EventError("Provocation skill doesn't have a value for RANGE, defaulting to UO_MAP_VIEW_SIGHT(14) \n"); + iMaxRange = UO_MAP_VIEW_SIGHT; + } + // If out of range we might get attacked ourself. - if ( (pCharProv->GetTopDist3D(pCharTarg) > UO_MAP_VIEW_SIGHT) || (pCharProv->GetTopDist3D(this) > UO_MAP_VIEW_SIGHT) ) + if ((pCharProv->GetTopDist3D(pCharTarg) > iMaxRange) || (pCharProv->GetTopDist3D(this) > iMaxRange)) { // Check that only "evil" monsters attack provoker back if ( pCharProv->Noto_IsEvil() ) @@ -2183,7 +2217,13 @@ int CChar::Skill_Cooking( SKTRIG_TYPE stage ) // m_Act_p = the heat source // m_Act_UID = the skill tool - int iMaxDist = 3; + CSkillDef *pSkillDef = g_Cfg.GetSkillDef(SKILL_COOKING); + int iMaxDist = pSkillDef->m_Range; + if (!iMaxDist) + { + g_Log.EventError("Cooking skill doesn't have a value for RANGE, defaulting to 3\n"); + iMaxDist = 3; + } if ( stage == SKTRIG_START ) { @@ -2239,10 +2279,13 @@ int CChar::Skill_Taming( SKTRIG_TYPE stage ) } CSkillDef* pSkillDef = g_Cfg.GetSkillDef(SKILL_TAMING); - if (pSkillDef->m_Range <= 0) - pSkillDef->m_Range = 10; - - if ( GetTopDist3D(pChar) > pSkillDef->m_Range) + int iMaxRange = pSkillDef->m_Range; + if (!iMaxRange) + { + g_Log.EventError("Taming skill doesn't have a value for RANGE, defaulting to 10\n"); + iMaxRange = 10; + } + if (GetTopDist3D(pChar) > iMaxRange) { SysMessageDefault( DEFMSG_TAMING_REACH ); return -SKTRIG_QTY; @@ -3237,8 +3280,16 @@ int CChar::Skill_Act_Breath( SKTRIG_TYPE stage ) return -SKTRIG_QTY; const CPointMap& pntMe = GetTopPoint(); - if ( pntMe.GetDist( m_Act_p ) > UO_MAP_VIEW_SIGHT ) - m_Act_p.StepLinePath( pntMe, UO_MAP_VIEW_SIGHT ); + + int iMaxDist = (int)(GetDefNum("BREATH.MAXDIST", true)); + if (!iMaxDist) + { + //g_Log.EventError("Breath skill doesn't have a value for RANGE, defaulting to UO_MAP_VIEW_SIGHT(14) \n"); + iMaxDist = UO_MAP_VIEW_SIGHT; + } + + if (pntMe.GetDist(m_Act_p) > iMaxDist) + m_Act_p.StepLinePath(pntMe, iMaxDist); int iDamage = (int)(GetDefNum("BREATH.DAM", true)); @@ -3319,8 +3370,17 @@ int CChar::Skill_Act_Throwing( SKTRIG_TYPE stage ) return -SKTRIG_QTY; const CPointMap pntMe(GetTopPoint()); - if ( pntMe.GetDist( m_Act_p ) > UO_MAP_VIEW_SIGHT ) - m_Act_p.StepLinePath( pntMe, UO_MAP_VIEW_SIGHT ); + + CSkillDef *pSkillDef = g_Cfg.GetSkillDef(SKILL_THROWING); + int iMaxRange = pSkillDef->m_Range; + if (!iMaxRange) + { + //g_Log.EventError("Throwing skill doesn't have a value for RANGE, defaulting to UO_MAP_VIEW_SIGHT(14) \n"); + iMaxRange = UO_MAP_VIEW_SIGHT; + } + + if (pntMe.GetDist(m_Act_p) > iMaxRange) + m_Act_p.StepLinePath(pntMe, iMaxRange); SoundChar( CRESND_GETHIT ); @@ -4055,7 +4115,15 @@ int CChar::Skill_Snooping(SKTRIG_TYPE stage) if (!IsTakeCrime(pCont, &pCharMark) || pCharMark == nullptr) return 0; // Not a crime really. - if (GetTopDist3D(pCharMark) > 1) + CSkillDef *pSkillDef = g_Cfg.GetSkillDef(SKILL_SNOOPING); + int iMaxRange = pSkillDef->m_Range; + if (!iMaxRange) + { + g_Log.EventError("Snooping skill doesn't have a value for RANGE, defaulting to 1\n"); + iMaxRange = 1; + } + + if (GetTopDist3D(pCharMark) > iMaxRange) { SysMessageDefault(DEFMSG_SNOOPING_REACH); return (-SKTRIG_QTY); @@ -4207,7 +4275,14 @@ int CChar::Skill_Stealing(SKTRIG_TYPE stage) bool fGround = false; if (pCharMark != nullptr) { - if (GetTopDist3D(pCharMark) > 2) + CSkillDef *pSkillDef = g_Cfg.GetSkillDef(SKILL_STEALING); + int iMaxRange = pSkillDef->m_Range; + if (!iMaxRange) + { + g_Log.EventError("Stealing skill doesn't have a value for RANGE, defaulting to 2\n"); + iMaxRange = 2; + } + if (GetTopDist3D(pCharMark) > iMaxRange) { SysMessageDefault(DEFMSG_STEALING_MARK); return -SKTRIG_QTY; diff --git a/src/game/chars/CCharSpell.cpp b/src/game/chars/CCharSpell.cpp index d68bf7da3..7e724034a 100644 --- a/src/game/chars/CCharSpell.cpp +++ b/src/game/chars/CCharSpell.cpp @@ -1894,6 +1894,14 @@ bool CChar::Spell_Equip_OnTick( CItem * pItem ) break; } + case SPELL_Explosion: + { + iEffect = iLevel; + iDmgType = DAMAGE_MAGIC | DAMAGE_FIRE; + Effect(EFFECT_OBJ, ITEMID_FX_EXPLODE_3, pItem->m_uidLink.CharFind(), 10, 16); + } + break; + case SPELL_Strangle: { /* @@ -1982,13 +1990,23 @@ bool CChar::Spell_Equip_OnTick( CItem * pItem ) iDmgType = (DAMAGE_TYPE)(ResGetIndex((dword)Args.m_VarsLocal.GetKeyNum("DamageType"))); if (iDmgType > 0 && iEffect > 0) // This is necessary if we have a spell that is harmful but does no damage periodically. { - OnTakeDamage(iEffect, pItem->m_uidLink.CharFind(), iDmgType, - (iDmgType & (DAMAGE_HIT_BLUNT | DAMAGE_HIT_PIERCE | DAMAGE_HIT_SLASH)) ? 100 : 0, - (iDmgType & DAMAGE_FIRE) ? 100 : 0, - (iDmgType & DAMAGE_COLD) ? 100 : 0, - (iDmgType & DAMAGE_POISON) ? 100 : 0, - (iDmgType & DAMAGE_ENERGY) ? 100 : 0, - spell); + // + CChar *pLinkedChar = pItem->m_uidLink.CharFind(); + if (pLinkedChar == nullptr) + { + // pLinkedChar = this; // If it is not alive or deleted, should it be like it is self-damaging? Note: Under the OnTakeDamage() + Skill_Fail(); // If the memory does not belong to a creature, or if the creature is dead or deleted, skills do not take effect on damage taken. + } + + OnTakeDamage(iEffect, + pLinkedChar, + iDmgType, + (iDmgType & (DAMAGE_HIT_BLUNT | DAMAGE_HIT_PIERCE | DAMAGE_HIT_SLASH)) ? 100 : 0, + (iDmgType & DAMAGE_FIRE) ? 100 : 0, + (iDmgType & DAMAGE_COLD) ? 100 : 0, + (iDmgType & DAMAGE_POISON) ? 100 : 0, + (iDmgType & DAMAGE_ENERGY) ? 100 : 0, + spell); } } else if (pSpellDef->IsSpellType(SPELLFLAG_HEAL)) @@ -2037,6 +2055,10 @@ CItem * CChar::Spell_Effect_Create( SPELL_TYPE spell, LAYER_TYPE layer, int iEff if ( layer == LAYER_SPELL_STATS && spell != pSpellPrev->m_itSpell.m_spell && IsSetMagicFlags(MAGICF_STACKSTATS) ) continue; + // If spell is explosion and there's already an explosion timer, dont remove it + if ( spell == SPELL_Explosion && layer == LAYER_SPELL_Explosion ) + continue; + pSpellPrev->Delete(); break; } @@ -2045,15 +2067,16 @@ CItem * CChar::Spell_Effect_Create( SPELL_TYPE spell, LAYER_TYPE layer, int iEff CItem *pSpell = CItem::CreateBase(pSpellDef ? pSpellDef->m_idSpell : ITEMID_RHAND_POINT_NW); ASSERT(pSpell); - switch ( layer ) - { - case LAYER_FLAG_Criminal: pSpell->SetName("Criminal Timer"); break; - case LAYER_FLAG_PotionUsed: pSpell->SetName("Potion Cooldown"); break; - case LAYER_FLAG_Drunk: pSpell->SetName("Drunk Effect"); break; - case LAYER_FLAG_Hallucination: pSpell->SetName("Hallucination Effect"); break; - case LAYER_FLAG_Murders: pSpell->SetName("Murder Decay"); break; - default: break; - } + switch ( layer ) + { + case LAYER_FLAG_Criminal: pSpell->SetName("Criminal Timer"); break; + case LAYER_FLAG_PotionUsed: pSpell->SetName("Potion Cooldown"); break; + case LAYER_FLAG_Drunk: pSpell->SetName("Drunk Effect"); break; + case LAYER_FLAG_Hallucination: pSpell->SetName("Hallucination Effect"); break; + case LAYER_FLAG_Murders: pSpell->SetName("Murder Decay"); break; + case LAYER_SPELL_Explosion: pSpell->SetName("Explosion Timer"); break; + default: break; + } g_World.m_uidNew = pSpell->GetUID(); pSpell->SetAttr(pSpellDef ? ATTR_NEWBIE|ATTR_MAGIC : ATTR_NEWBIE); @@ -3901,6 +3924,12 @@ bool CChar::OnSpellEffect( SPELL_TYPE spell, CChar * pCharSrc, int iSkillLevel, } break; + case SPELL_Explosion: + // if not a potion and have duration, create effect + if (!fPotion && iDuration > 0) + Spell_Effect_Create( SPELL_Explosion, LAYER_SPELL_Explosion, iEffect, iDuration, pCharSrc ); + break; + case SPELL_Invis: Spell_Effect_Create( spell, fPotion ? LAYER_FLAG_Potion : LAYER_SPELL_Invis, iEffect, iDuration, pCharSrc ); break; diff --git a/src/game/clients/CClientUse.cpp b/src/game/clients/CClientUse.cpp index 2b13591ab..2e536abee 100644 --- a/src/game/clients/CClientUse.cpp +++ b/src/game/clients/CClientUse.cpp @@ -158,6 +158,7 @@ bool CClient::Cmd_Use_Item( CItem *pItem, bool fTestTouch, bool fScript ) case IT_SHAFT: case IT_FEATHER: + case IT_FLETCHING: return Skill_Menu(SKILL_BOWCRAFT, "sm_bolts", pItem->GetID()); case IT_FISH_POLE: // Just be near water ? @@ -185,7 +186,7 @@ bool CClient::Cmd_Use_Item( CItem *pItem, bool fTestTouch, bool fScript ) } else // I have the key but i need to use it to unlock the container. { - SysMessageDefault(DEFMSG_LOCK_HAS_KEY); + SysMessageDefault(DEFMSG_LOCK_HAS_KEY); return false; } break; @@ -194,7 +195,7 @@ bool CClient::Cmd_Use_Item( CItem *pItem, bool fTestTouch, bool fScript ) SysMessageDefault(DEFMSG_ITEMUSE_LOCKED); if ( !m_pChar->GetPackSafe()->ContentFindKeyFor(pItem) ) // I don't have the hold key { - + SysMessageDefault(DEFMSG_LOCK_HOLD_NO_KEY); if ( !IsPriv(PRIV_GM) ) return false; @@ -225,7 +226,7 @@ bool CClient::Cmd_Use_Item( CItem *pItem, bool fTestTouch, bool fScript ) if ( m_pChar->CheckCorpseCrime(pCorpseItem, true, true) ) SysMessageDefault(DEFMSG_LOOT_CRIMINAL_ACT); } - + return true; } @@ -849,7 +850,7 @@ int CClient::Cmd_Skill_Menu_Build( const CResourceID& rid, int iSelect, CMenuIte { if ( (iSelect < -1) && (iShowCount >= 1) ) // just a test. so we are done. return 1; - + CMenuItem miTest; if ( !miTest.ParseLine(s.GetArgRaw(), nullptr, m_pChar) ) { @@ -1150,7 +1151,7 @@ bool CClient::Cmd_Skill_Tracking( uint track_sel, bool fExec ) When the Tracking skill starts and the Effect property is defined on the Tracking skill use it instead of the hardcoded formula for the maximum distance. */ - + if (m_pChar->m_Act_Effect >= 0) m_pChar->m_atTracking.m_dwDistMax = (dword)m_pChar->m_Act_Effect; else //This is default Sphere maximum tracking distance. diff --git a/src/game/items/item_types.h b/src/game/items/item_types.h index 64000b465..438e0569c 100644 --- a/src/game/items/item_types.h +++ b/src/game/items/item_types.h @@ -173,7 +173,7 @@ enum IT_TYPE : int32_t // double click type action. IT_TRAIN_DUMMY, // 156 IT_TRAIN_PICKPOCKET, // 157 IT_BEDROLL, // 158 - IT_UNUSED_159, // 159 + IT_FLETCHING, // 159 IT_HIDE, // 160 = hides are cured to make leather. IT_CLOTH_BOLT, // 161 = must be cut up to make cloth squares. IT_BOARD, // 162 = logs are plained into decent lumber @@ -214,7 +214,7 @@ enum IT_TYPE : int32_t // double click type action. IT_PILOT, // 197 = ship's pilot (PacketWheelMove) IT_ROPE, // 198 = t_rope (working like t_ship_plank but without id changes) IT_WEAPON_WHIP, // 199 - + // New SphereX hardcoded types starting from 300 IT_SPAWN_CHAMPION = 300,// 300 = t_spawn_champion IT_MULTI_ADDON, // 301 = t_multi_addon diff --git a/src/game/uo_files/uofiles_enums.h b/src/game/uo_files/uofiles_enums.h index 2653cd8d6..fe233958c 100644 --- a/src/game/uo_files/uofiles_enums.h +++ b/src/game/uo_files/uofiles_enums.h @@ -654,9 +654,10 @@ enum LAYER_TYPE : unsigned char // defined by UO. Only one item can be in a slot //Individual Spell Layers LAYER_SPELL_Mana_Drain, + LAYER_SPELL_Explosion, - LAYER_STORAGE, //80 New Storage layer, can equip t_container and t_container_locked. - LAYER_STABLE, //81 New stable layer, now stabled pets will be stored in this layer of the player instead of npc's itself. + LAYER_STORAGE, // New Storage layer, can equip t_container and t_container_locked. + LAYER_STABLE, // New stable layer, now stabled pets will be stored in this layer of the player instead of npc's itself. LAYER_QTY };