Пример #1
0
int CResource::Calc_StealingItem( CChar * pCharThief, CItem * pItem, CChar * pCharMark )
{
	// Chance to steal and retrieve the item successfully.
	// weight of the item
	//  heavier items should be more difficult.
	//	thiefs skill/ dex
	//  marks skill/dex
	//  marks war mode ?
	// NOTE:
	//  Items on the ground can always be stolen. chance of being seen is another matter.
	// RETURN:
	//  0-100 percent chance to hit on a d100 roll.
	//  0-100 percent difficulty against my SKILL_STEALING skill.

	ASSERT(pCharThief);
	ASSERT(pCharMark);

	int iDexMark = pCharMark->Stat_GetAdjusted(STAT_DEX);
	int iSkillMark = pCharMark->Skill_GetAdjusted( SKILL_STEALING );
	int iWeightItem = pItem->GetWeight();
	int iDifficulty = iDexMark/2 + (iSkillMark/5) + Calc_GetRandVal(iDexMark/2) +
		IMULDIV( iWeightItem, 4, WEIGHT_UNITS );
	if ( pItem->IsItemEquipped())
	{
		// This is REALLY HARD to do.
		iDifficulty += iDexMark/2 + pCharMark->Stat_GetAdjusted(STAT_INT);
	}
	if ( pCharThief->IsStatFlag( STATF_War )) // all keyed up.
	{
		iDifficulty += Calc_GetRandVal( iDexMark/2 );
	}

	return( iDifficulty );
}
Пример #2
0
bool CItemMulti::Ship_SetMoveDir( DIR_TYPE dir )
{
	// Set the direction we will move next time we get a tick.
	int iSpeed = 1;
	if ( m_itShip.m_DirMove == dir && m_itShip.m_fSail )
	{
		if ( m_itShip.m_DirFace == m_itShip.m_DirMove &&
			m_itShip.m_fSail == 1 )
		{
			iSpeed = 2;
		}
		else return( false );
	}

	if ( ! IsAttr(ATTR_MAGIC ))	// make sound.
	{
		if ( ! Calc_GetRandVal(10))
		{
			Sound( Calc_GetRandVal(2)?0x12:0x13 );
		}
	}

	m_itShip.m_DirMove = dir;
	m_itShip.m_fSail = iSpeed;
	GetTopSector()->SetSectorWakeStatus();	// may get here b4 my client does.
	SetTimeout(( m_itShip.m_fSail == 1 ) ? 1*TICK_PER_SEC : (TICK_PER_SEC/5));
	return( true );
}
Пример #3
0
void CItem::Spawn_OnTick( bool fExec )
{
	int iMinutes;
	if ( m_itSpawnChar.m_TimeHiMin <= 0 )
	{
		iMinutes = Calc_GetRandVal(30) + 1;
	}
	else
	{
		iMinutes = min( m_itSpawnChar.m_TimeHiMin, m_itSpawnChar.m_TimeLoMin ) + Calc_GetRandVal( 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 )
		return;

	CResourceDef * pDef = Spawn_FixDef();
	if ( pDef == NULL )
	{
		RESOURCE_ID_BASE rid;
		if ( IsType(IT_SPAWN_ITEM))
		{
			rid = m_itSpawnItem.m_ItemID;
		}
		else
		{
			rid = 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))
	{
		Spawn_GenerateItem(pDef);
	}
	else
	{
		Spawn_GenerateChar(pDef);
	}
}
Пример #4
0
int CResource::Calc_DropStamWhileMoving( CChar * pChar, int iWeightLoadPercent )
{
	// I am now running/walking.
	// Should my stam drop ?
	// ARGS:
	//  iWeightLoadPercent = 0-100 percent of the weight i can carry.
	// RETURN:
	//  Stamina penalty
	//  -1 = can't move
	//  

	ASSERT(pChar);

	if ( pChar->IsStatFlag( STATF_DEAD ) )
		return 0;
	
	if ( pChar->IsStatFlag( STATF_Fly ))	// i'm running ?
	{
		iWeightLoadPercent += m_iStamRunningPenalty;
	}

	// Chance to drop in Stam given a weight
	int iChanceForStamLoss = Calc_GetSCurve( iWeightLoadPercent - m_iStaminaLossAtWeight, 10 );

	int iRoll = Calc_GetRandVal(1000);
	if ( iRoll <= iChanceForStamLoss )
		return 1;

	return( 0 );
}
Пример #5
0
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());
}
Пример #6
0
bool CResource::Calc_CrimeSeen( CChar * pCharThief, CChar * pCharViewer, SKILL_TYPE SkillToSee, bool fBonus )
{
	// Chance to steal without being seen by a specific person
	//	weight of the item
	//	distance from crime. (0=i am the mark)
	//	Thiefs skill/ dex
	//  viewers skill

	if ( SkillToSee == SKILL_NONE )	// takes no skill.
		return( true );

	ASSERT(pCharViewer);
	ASSERT(pCharThief);

	if ( pCharViewer->IsPriv(PRIV_GM) || pCharThief->IsPriv(PRIV_GM))
	{
		if ( pCharViewer->GetPrivLevel() < pCharThief->GetPrivLevel())
			return( false );	// never seen
		if ( pCharViewer->GetPrivLevel() > pCharThief->GetPrivLevel())
			return( true );	// always seen.
	}

	int iChanceToSee = ( pCharViewer->Stat_GetAdjusted(STAT_DEX) + pCharViewer->Stat_GetAdjusted(STAT_INT)) * 50;
	if ( SkillToSee != SKILL_NONE )
	{
		// Snooping or stealing.
		iChanceToSee = 1000+(pCharViewer->Skill_GetBase(SkillToSee) - pCharThief->Skill_GetBase(SkillToSee));
	}
	else
	{
		iChanceToSee += 400;
	}

	// the targets chance of seeing.
	if ( fBonus )
	{
		// Up by 30 % if it's me.
		iChanceToSee += iChanceToSee/3;
		if ( iChanceToSee < 50 ) // always atleast 5% chance.
			iChanceToSee=50;
	}
	else
	{
		// the bystanders chance of seeing.
		if ( iChanceToSee < 10 ) // always atleast 1% chance.
			iChanceToSee=10;
	}

	if ( Calc_GetRandVal(1000) > iChanceToSee )
		return( false );

	return( true );
}
Пример #7
0
WEATHER_TYPE CSector::GetWeatherCalc() const
{
	ADDTOCALLSTACK("CSector::GetWeatherCalc");

	// There is no weather in dungeons (or when the Sphere.ini setting prevents weather)
	if ( IsInDungeon() || g_Cfg.m_fNoWeather )
		return( WEATHER_DRY );

	// Rain chance also controls the chance of snow. If it isn't possible to rain then it cannot snow either
	int iPercentRoll = Calc_GetRandVal( 100 );
	if ( iPercentRoll < GetRainChance() )
	{
		// It is precipitating... but is it rain or snow?
		if ( GetColdChance() && Calc_GetRandVal(100) <= GetColdChance()) // Should it actually snow here?
			return WEATHER_SNOW;
		return WEATHER_RAIN;
	}
	// It is not precipitating, but is it cloudy or dry?
	if ( ( iPercentRoll / 2) < GetRainChance() )
		return WEATHER_CLOUDY;
	return( WEATHER_DRY );
}
Пример #8
0
bool CChar::NPC_OnHireHear( CChar * pCharSrc )
{
	ADDTOCALLSTACK("CChar::NPC_OnHireHear");
	if ( !m_pNPC )
		return false;

	CCharBase * pCharDef = Char_GetDef();
	unsigned int iWage = pCharDef->GetHireDayWage();
	if ( ! iWage )
	{
		Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_NOT_FOR_HIRE ) );
		return false;
	}

	CItemMemory * pMemory = Memory_FindObj( pCharSrc );
	if ( pMemory )
	{
		if ( pMemory->IsMemoryTypes(MEMORY_IPET|MEMORY_FRIEND))
		{
			// Next gold i get goes toward hire.
			pMemory->m_itEqMemory.m_Action = NPC_MEM_ACT_SPEAK_HIRE;
			NPC_OnHirePayMore( NULL, false );
			return true;
		}
		if ( pMemory->IsMemoryTypes( MEMORY_FIGHT|MEMORY_HARMEDBY|MEMORY_IRRITATEDBY ))
		{
			Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_NOT_WORK ) );
			return false;
		}
	}
	if ( IsStatFlag( STATF_Pet ))
	{
		Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_EMPLOYED ) );
		return false;
	}

	TCHAR *pszMsg = Str_GetTemp();
	sprintf(pszMsg, Calc_GetRandVal(2) ?
		g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_HIRE_AMNT ) :
		g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_HIRE_RATE ), iWage );
	Speak(pszMsg);

	pMemory = Memory_AddObjTypes( pCharSrc, MEMORY_SPEAK );
	if ( pMemory )
		pMemory->m_itEqMemory.m_Action = NPC_MEM_ACT_SPEAK_HIRE;
	return true;
}
Пример #9
0
bool CResource::Calc_SkillCheck( int iSkillLevel, int iDifficulty )
{
	// Chance to complete skill check given skill x and difficulty y
	// ARGS:
	//  iSkillLevel = 0-1000
	//  difficulty = 0-100
	// RETURN:
	//  true = success check.

	if ( iDifficulty < 0 || iSkillLevel < 0 )	// auto failure.
		return( false );

	int iChanceForSuccess = Calc_GetSCurve( iSkillLevel - ( iDifficulty * 10 ), SKILL_VARIANCE );
	int iRoll = Calc_GetRandVal(1000);

	return( iRoll <= iChanceForSuccess );
}
Пример #10
0
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();
}
Пример #11
0
bool CChar::Use_BedRoll( CItem * pItem )
{
	ADDTOCALLSTACK("CChar::Use_BedRoll");
	// IT_BEDROLL

	ASSERT(pItem);
	switch ( pItem->GetDispID() )
	{
		case ITEMID_BEDROLL_C:
			if ( !pItem->IsTopLevel() )
			{
			putonground:
				SysMessageDefault(DEFMSG_ITEMUSE_BEDROLL);
				return true;
			}
			pItem->SetID(Calc_GetRandVal(2) ? ITEMID_BEDROLL_O_EW : ITEMID_BEDROLL_O_NS);
			pItem->Update();
			return true;
		case ITEMID_BEDROLL_C_NS:
			if ( !pItem->IsTopLevel() )
				goto putonground;
			pItem->SetID(ITEMID_BEDROLL_O_NS);
			pItem->Update();
			return true;
		case ITEMID_BEDROLL_C_EW:
			if ( !pItem->IsTopLevel() )
				goto putonground;
			pItem->SetID(ITEMID_BEDROLL_O_EW);
			pItem->Update();
			return true;
		case ITEMID_BEDROLL_O_EW:
		case ITEMID_BEDROLL_O_NS:
			pItem->SetID(ITEMID_BEDROLL_C);
			pItem->Update();
			return true;
		default:
			return false;
	}
}
Пример #12
0
int CChar::Do_Use_Item(CItem *pItem, bool fLink)
{
	ADDTOCALLSTACK("CChar::Do_Use_Item");
	if (!pItem)
		return false;

	if (m_pNPC && (IsTrigUsed(TRIGGER_DCLICK) ||
	               IsTrigUsed(TRIGGER_ITEMDCLICK)))        // for players, DClick was called before this function
	{
		if (pItem->OnTrigger(ITRIG_DCLICK, this) == TRIGRET_RET_TRUE)
			return false;
	}

	CItemSpawn *pSpawn = static_cast<CItemSpawn *>(pItem->m_uidSpawnItem.ItemFind());
	if (pSpawn)
		pSpawn->DelObj(pItem->GetUID());    // remove this item from it's spawn when DClicks it

	int fAction = true;
	switch(pItem->GetType()) {
		case IT_ITEM_STONE: {
			// Give them this item
			if (pItem->m_itItemStone.m_wAmount == USHRT_MAX) {
				SysMessageDefault(DEFMSG_MSG_IT_IS_DEAD);
				return true;
			}
			if (pItem->m_itItemStone.m_wRegenTime) {
				if (pItem->IsTimerSet()) {
					SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_MSG_STONEREG_TIME), pItem->GetTimerDiff() / TICK_PER_SEC);
					return true;
				}
				pItem->SetTimeout(pItem->m_itItemStone.m_wRegenTime * TICK_PER_SEC);
			}
			ItemBounce(CItem::CreateTemplate(pItem->m_itItemStone.m_ItemID, GetPackSafe(), this));
			if (pItem->m_itItemStone.m_wAmount != 0) {
				pItem->m_itItemStone.m_wAmount--;
				if (pItem->m_itItemStone.m_wAmount == 0)
					pItem->m_itItemStone.m_wAmount = USHRT_MAX;
			}
			return true;
		}

		case IT_SEED:
			return Use_Seed(pItem, NULL);

		case IT_BEDROLL:
			return Use_BedRoll(pItem);

		case IT_KINDLING:
			return Use_Kindling(pItem);

		case IT_SPINWHEEL: {
			if (fLink)
				return false;

			// Just make them spin
			pItem->SetAnim(static_cast<ITEMID_TYPE>(pItem->GetID() + 1), 2 * TICK_PER_SEC);
			SysMessageDefault(DEFMSG_ITEMUSE_SPINWHEEL);
			return true;
		}

		case IT_TRAIN_DUMMY: {
			if (fLink)
				return false;

			Use_Train_Dummy(pItem, true);
			return true;
		}

		case IT_TRAIN_PICKPOCKET: {
			if (fLink)
				return false;

			Use_Train_PickPocketDip(pItem, true);
			return true;
		}

		case IT_ARCHERY_BUTTE: {
			if (fLink)
				return false;

			Use_Train_ArcheryButte(pItem, true);
			return true;
		}

		case IT_LOOM: {
			if (fLink)
				return false;

			SysMessageDefault(DEFMSG_ITEMUSE_LOOM);
			return true;
		}

		case IT_BEE_HIVE: {
			if (fLink)
				return false;

			// Get honey from it
			ITEMID_TYPE id = ITEMID_NOTHING;
			if (!pItem->m_itBeeHive.m_honeycount)
				SysMessageDefault(DEFMSG_ITEMUSE_BEEHIVE);
			else {
				switch(Calc_GetRandVal(3)) {
					case 1:
						id = ITEMID_JAR_HONEY;
						break;
					case 2:
						id = ITEMID_BEE_WAX;
						break;
				}
			}
			if (id) {
				ItemBounce(CItem::CreateScript(id, this));
				pItem->m_itBeeHive.m_honeycount--;
			}
			else {
				SysMessageDefault(DEFMSG_ITEMUSE_BEEHIVE_STING);
				OnTakeDamage(Calc_GetRandVal(5), this, DAMAGE_POISON | DAMAGE_GENERAL);
			}
			pItem->SetTimeout(15 * 60 * TICK_PER_SEC);
			return true;
		}

		case IT_MUSICAL: {
			if (!Skill_Wait(SKILL_MUSICIANSHIP)) {
				m_Act_Targ = pItem->GetUID();
				Skill_Start(SKILL_MUSICIANSHIP);
			}
			break;
		}

		case IT_CROPS:
		case IT_FOLIAGE: {
			// Pick cotton/hay/etc
			fAction = pItem->Plant_Use(this);
			break;
		}

		case IT_FIGURINE: {
			// Create the creature here
			if (Use_Figurine(pItem) != NULL)
				pItem->Delete();
			return true;
		}

		case IT_TRAP:
		case IT_TRAP_ACTIVE: {
			// Activate the trap (plus any linked traps)
			int iDmg = pItem->Use_Trap();
			if (CanTouch(pItem->GetTopLevelObj()->GetTopPoint()))
				OnTakeDamage(iDmg, NULL, DAMAGE_HIT_BLUNT | DAMAGE_GENERAL);
			break;
		}

		case IT_SWITCH: {
			// Switches can be linked to gates and doors and such.
			// Flip the switch graphic.
			pItem->SetSwitchState();
			break;
		}

		case IT_PORT_LOCKED:
			if (!fLink && !IsPriv(PRIV_GM)) {
				SysMessageDefault(DEFMSG_ITEMUSE_PORT_LOCKED);
				return true;
			}
		case IT_PORTCULIS:
			// Open a metal gate vertically
			pItem->Use_Portculis();
			break;

		case IT_DOOR_LOCKED:
			if (!ContentFindKeyFor(pItem)) {
				SysMessageDefault(DEFMSG_MSG_KEY_DOORLOCKED);
				if (!pItem->IsTopLevel())
					return false;
				if (pItem->IsAttr(ATTR_MAGIC))    // show it's magic face
				{
					ITEMID_TYPE id = (GetDispID() & DOOR_NORTHSOUTH) ? ITEMID_DOOR_MAGIC_SI_NS
					                                                 : ITEMID_DOOR_MAGIC_SI_EW;
					CItem *pFace = CItem::CreateBase(id);
					ASSERT(pFace);
					pFace->MoveToDecay(pItem->GetTopPoint(), 4 * TICK_PER_SEC);
				}
				if (!IsPriv(PRIV_GM))
					return true;
			}
		case IT_DOOR_OPEN:
		case IT_DOOR: {
			bool fOpen = pItem->Use_DoorNew(fLink);
			if (fLink || !fOpen)    // don't link if we are just closing the door
				return true;
		}
			break;

		case IT_SHIP_PLANK: {
			// Close the plank if I'm inside the ship
			if (m_pArea->IsFlag(REGION_FLAG_SHIP) && m_pArea->GetResourceID() == pItem->m_uidLink) {
				if (pItem->m_itShipPlank.m_itSideType == IT_SHIP_SIDE_LOCKED && !ContentFindKeyFor(pItem)) {
					SysMessageDefault(DEFMSG_ITEMUSE_SHIPSIDE);
					return true;
				}
				return pItem->Ship_Plank(false);
			}
			else if (pItem->IsTopLevel()) {
				// Teleport to plank if I'm outside the ship
				CPointMap pntTarg = pItem->GetTopPoint();
				pntTarg.m_z++;
				Spell_Teleport(pntTarg, true, false, false);
			}
			return true;
		}

		case IT_SHIP_SIDE_LOCKED:
			if (!ContentFindKeyFor(pItem)) {
				SysMessageDefault(DEFMSG_ITEMUSE_SHIPSIDE);
				return true;
			}
		case IT_SHIP_SIDE:
			// Open the plank
			pItem->Ship_Plank(true);
			return true;

		case IT_GRAIN:
		case IT_GRASS:
		case IT_GARBAGE:
		case IT_FRUIT:
		case IT_FOOD:
		case IT_FOOD_RAW:
		case IT_MEAT_RAW: {
			if (fLink)
				return false;

			Use_Eat(pItem);
			return true;
		}

		case IT_POTION:
		case IT_DRINK:
		case IT_PITCHER:
		case IT_WATER_WASH:
		case IT_BOOZE: {
			if (fLink)
				return false;

			Use_Drink(pItem);
			return true;
		}

		case IT_LIGHT_OUT:        // can the light be lit?
		case IT_LIGHT_LIT:        // can the light be doused?
			fAction = pItem->Use_Light();
			break;

		case IT_CLOTHING:
		case IT_ARMOR:
		case IT_ARMOR_LEATHER:
		case IT_SHIELD:
		case IT_WEAPON_MACE_CROOK:
		case IT_WEAPON_MACE_PICK:
		case IT_WEAPON_MACE_SMITH:
		case IT_WEAPON_MACE_SHARP:
		case IT_WEAPON_SWORD:
		case IT_WEAPON_FENCE:
		case IT_WEAPON_BOW:
		case IT_WEAPON_AXE:
		case IT_WEAPON_XBOW:
		case IT_WEAPON_MACE_STAFF:
		case IT_JEWELRY:
		case IT_WEAPON_THROWING: {
			if (fLink)
				return false;

			return ItemEquip(pItem);
		}

		case IT_WEB: {
			if (fLink)
				return false;

			Use_Item_Web(pItem);
			return true;
		}

		case IT_SPY_GLASS: {
			if (fLink)
				return false;

			// Spyglass will tell you the moon phases
			static LPCTSTR const sm_sPhases[8] =
					{
							g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M1),
							g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M2),
							g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M3),
							g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M4),
							g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M5),
							g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M6),
							g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M7),
							g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M8)
					};
			SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_TR), sm_sPhases[g_World.GetMoonPhase(false)]);
			SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_FE), sm_sPhases[g_World.GetMoonPhase(true)]);

			if (m_pArea && m_pArea->IsFlag(REGION_FLAG_SHIP))
				ObjMessage(pItem->Use_SpyGlass(this), this);
			return true;
		}

		case IT_SEXTANT: {
			if (fLink)
				return false;

			if ((GetTopPoint().m_map <= 1) && (GetTopPoint().m_x > UO_SIZE_X_REAL))    // dungeons and T2A lands
				ObjMessage(g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SEXTANT_T2A), this);
			else {
				TCHAR *pszMsg = Str_GetTemp();
				sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SEXTANT), m_pArea->GetName(),
				        pItem->Use_Sextant(GetTopPoint()));
				ObjMessage(pszMsg, this);
			}
			return true;
		}

		default:
			fAction = false;
	}
	return fAction | MASK_RETURN_FOLLOW_LINKS;
}
Пример #13
0
bool CClient::r_Verb(CScript &s, CTextConsole *pSrc) // Execute command from script
{
	ADDTOCALLSTACK("CClient::r_Verb");
	EXC_TRY("Verb");
	// NOTE: This can be called directly from a RES_WEBPAGE script.
	//  So do not assume we are a game client !
	// NOTE: Mostly called from CChar::r_Verb
	// NOTE: Little security here so watch out for dangerous scripts !

	ASSERT(pSrc);
	LPCTSTR pszKey = s.GetKey();

	// Old ver
	if ( s.IsKeyHead("SET", 3) && !g_Cfg.m_Functions.ContainsKey(pszKey) )
	{
		PLEVEL_TYPE ilevel = g_Cfg.GetPrivCommandLevel("SET");
		if ( ilevel > GetPrivLevel() )
			return false;

		ASSERT(m_pChar);
		addTargetVerb(pszKey + 3, s.GetArgRaw());
		return true;
	}

	if ( (toupper(pszKey[0]) == 'X') && !g_Cfg.m_Functions.ContainsKey(pszKey) )
	{
		PLEVEL_TYPE ilevel = g_Cfg.GetPrivCommandLevel("SET");
		if ( ilevel > GetPrivLevel() )
			return false;

		// Target this command verb on some other object.
		ASSERT(m_pChar);
		addTargetVerb(pszKey + 1, s.GetArgRaw());
		return true;
	}

	int index = FindTableSorted(s.GetKey(), sm_szVerbKeys, COUNTOF(sm_szVerbKeys) - 1);
	switch ( index )
	{
		case CV_ADD:
		{
			if ( s.HasArgs() )
			{
				TCHAR *ppArgs[2];
				size_t iArgQty = Str_ParseCmds(s.GetArgStr(), ppArgs, COUNTOF(ppArgs));

				if ( !IsValidGameObjDef(static_cast<LPCTSTR>(ppArgs[0])) )
				{
					g_Log.EventWarn("Invalid ADD argument '%s'\n", ppArgs[0]);
					SysMessageDefault(DEFMSG_CMD_INVALID);
					return true;
				}

				RESOURCE_ID rid = g_Cfg.ResourceGetID(RES_QTY, const_cast<LPCTSTR &>(ppArgs[0]));
				m_tmAdd.m_id = rid.GetResIndex();
				m_tmAdd.m_amount = (iArgQty > 1) ? static_cast<WORD>(maximum(ATOI(ppArgs[1]), 1)) : 1;

				if ( (rid.GetResType() == RES_CHARDEF) || (rid.GetResType() == RES_SPAWN) )
				{
					m_Targ_PrvUID.InitUID();
					return addTargetChars(CLIMODE_TARG_ADDCHAR, static_cast<CREID_TYPE>(m_tmAdd.m_id), false);
				}
				else
					return addTargetItems(CLIMODE_TARG_ADDITEM, static_cast<ITEMID_TYPE>(m_tmAdd.m_id));
				break;
			}

			if ( IsValidDef("d_add") )
				Dialog_Setup(CLIMODE_DIALOG, g_Cfg.ResourceGetIDType(RES_DIALOG, "d_add"), 0, m_pChar);
			else
				Menu_Setup(g_Cfg.ResourceGetIDType(RES_MENU, "MENU_ADDITEM"));
			break;
		}
		case CV_ADDBUFF:
		{
			TCHAR *ppArgs[11];
			Str_ParseCmds(s.GetArgStr(), ppArgs, COUNTOF(ppArgs));

			int iArgs[4];
			for ( int i = 0; i < 4; ++i )
			{
				if ( !IsStrNumeric(ppArgs[i]) )
				{
					DEBUG_ERR(("Invalid AddBuff argument number %u\n", i + 1));
					return true;
				}
				iArgs[i] = Exp_GetVal(ppArgs[i]);
			}
			if ( (iArgs[0] < 0) || (iArgs[0] > USHRT_MAX) )
			{
				DEBUG_ERR(("Invalid AddBuff icon ID\n"));
				break;
			}

			LPCTSTR pszArgs[7];
			size_t iArgQty = 0;
			for ( int i = 0; i < 7; ++i )
			{
				pszArgs[i] = ppArgs[i + 4];
				if ( pszArgs[i] != NULL )
					++iArgQty;
			}

			addBuff(static_cast<BUFF_ICONS>(iArgs[0]), static_cast<DWORD>(iArgs[1]), static_cast<DWORD>(iArgs[2]), static_cast<WORD>(iArgs[3]), pszArgs, iArgQty);
			break;
		}
		case CV_REMOVEBUFF:
		{
			BUFF_ICONS IconId = static_cast<BUFF_ICONS>(s.GetArgVal());
			if ( (IconId < 0) || (IconId > USHRT_MAX) )
			{
				DEBUG_ERR(("Invalid RemoveBuff icon ID\n"));
				break;
			}
			removeBuff(IconId);
			break;
		}
		case CV_ADDCLILOC:
		{
			// Add cliloc in @ClientTooltip trigger
			TCHAR *ppArgs[256];
			size_t iArgQty = Str_ParseCmds(s.GetArgRaw(), ppArgs, COUNTOF(ppArgs), ",");
			DWORD dwClilocId = static_cast<DWORD>(Exp_GetLLVal(ppArgs[0]));

			CGString sVal;
			for ( size_t i = 1; i < iArgQty; ++i )
			{
				if ( sVal.GetLength() )
					sVal += "\t";
				sVal += !strcmp(ppArgs[i], "NULL") ? " " : ppArgs[i];
			}

			if ( g_Cfg.m_wDebugFlags & DEBUGF_SCRIPTS )
				g_Log.EventDebug("SCRIPT: addcliloc(%lu,'%s')\n", dwClilocId, static_cast<LPCTSTR>(sVal));
			m_TooltipData.Add(new CClientTooltip(dwClilocId, sVal));
			break;
		}
		case CV_ADDCONTEXTENTRY:
		{
			TCHAR *ppArgs[20];
			if ( Str_ParseCmds(s.GetArgRaw(), ppArgs, COUNTOF(ppArgs), ",") > 4 )
			{
				DEBUG_ERR(("Bad AddContextEntry usage: Function takes maximum of 4 arguments!\n"));
				return true;
			}
			if ( !m_pPopupPacket )
			{
				DEBUG_ERR(("Bad AddContextEntry usage: Not used under a @ContextMenuRequest/@itemContextMenuRequest trigger!\n"));
				return true;
			}

			for ( int i = 0; i < 4; ++i )
			{
				if ( (i > 1) && IsStrEmpty(ppArgs[i]) )
					continue;

				if ( !IsStrNumeric(ppArgs[i]) )
				{
					DEBUG_ERR(("Bad AddContextEntry usage: Argument %d must be a number!\n", i + 1));
					return true;
				}
			}

			int iTextEntry = Exp_GetVal(ppArgs[0]);
			if ( iTextEntry < 100 )
			{
				DEBUG_ERR(("Bad AddContextEntry usage: TextEntry < 100 is reserved for server usage!\n"));
				return true;
			}
			m_pPopupPacket->addOption(static_cast<WORD>(iTextEntry), static_cast<DWORD>(Exp_GetLLVal(ppArgs[1])), static_cast<WORD>(Exp_GetLLVal(ppArgs[2])), static_cast<WORD>(Exp_GetLLVal(ppArgs[3])));
			break;
		}
		case CV_ARROWQUEST:
		{
			INT64 piVal[3];
			Str_ParseCmds(s.GetArgRaw(), piVal, COUNTOF(piVal));
			addArrowQuest(static_cast<WORD>(piVal[0]), static_cast<WORD>(piVal[1]), static_cast<DWORD>(piVal[2]));
			break;
		}
		case CV_BADSPAWN:
		{
			// Loop the world searching for bad spawns
			bool fFound = false;
			CItem *pItem = NULL;
			CSector *pSector = NULL;
			CResourceDef *pSpawnDef = NULL;
			for ( int m = 0; (m < 256) && !fFound; ++m )
			{
				if ( !g_MapList.m_maps[m] )
					continue;

				for ( int s = 0; (s < g_MapList.GetSectorQty(m)) && !fFound; ++s )
				{
					pSector = g_World.GetSector(m, s);
					if ( !pSector )
						continue;

					for ( pItem = static_cast<CItem *>(pSector->m_Items_Timer.GetHead()); (pItem != NULL) && !fFound; pItem = pItem->GetNext() )
					{
						if ( pItem->IsType(IT_SPAWN_ITEM) || pItem->IsType(IT_SPAWN_CHAR) )
						{
							pSpawnDef = static_cast<CItemSpawn *>(pItem)->FixDef();
							if ( !pSpawnDef )
							{
								RESOURCE_ID_BASE rid = pItem->IsType(IT_SPAWN_ITEM) ? pItem->m_itSpawnItem.m_ItemID : pItem->m_itSpawnChar.m_CharID;
								CPointMap pt = pItem->GetTopPoint();
								m_pChar->Spell_Teleport(pt, true, false);
								m_pChar->m_Act_Targ = pItem->GetUID();
								SysMessagef("Bad spawn (0%lx, id=%s). Set as ACT", static_cast<DWORD>(pItem->GetUID()), g_Cfg.ResourceGetName(rid));
								fFound = true;
							}
						}
					}
				}
			}
			if ( !fFound )
				SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_NO_BAD_SPAWNS));
			break;
		}
		case CV_BANKSELF:
		{
			addBankOpen(m_pChar, LAYER_BANKBOX);
			break;
		}
		case CV_CAST:
		{
			SPELL_TYPE spell = static_cast<SPELL_TYPE>(g_Cfg.ResourceGetIndexType(RES_SPELL, s.GetArgStr()));
			const CSpellDef *pSpellDef = g_Cfg.GetSpellDef(spell);
			if ( !pSpellDef )
				return true;

			CObjBase *pObjSrc = dynamic_cast<CObjBase *>(pSrc);
			if ( IsSetMagicFlags(MAGICF_PRECAST) && !pSpellDef->IsSpellType(SPELLFLAG_NOPRECAST) )
			{
				int iSkill;
				if ( !pSpellDef->GetPrimarySkill(&iSkill, NULL) )
					return true;

				m_tmSkillMagery.m_Spell = spell;	// m_atMagery.m_Spell
				m_pChar->m_atMagery.m_Spell = spell;
				if ( pObjSrc )
				{
					m_Targ_UID = pObjSrc->GetUID();	// default target.
					m_Targ_PrvUID = pObjSrc->GetUID();
				}
				else
				{
					m_Targ_UID.ClearUID();
					m_Targ_PrvUID.ClearUID();
				}
				m_pChar->Skill_Start(static_cast<SKILL_TYPE>(iSkill));
				break;
			}
			else
				Cmd_Skill_Magery(spell, pObjSrc);
			break;
		}
		case CV_CHANGEFACE:		// open 'face selection' dialog (enhanced clients only)
		{
			addGumpDialog(CLIMODE_DIALOG, NULL, 0, NULL, 0, 0, 0, m_pChar, CLIMODE_DIALOG_FACESELECTION);
			break;
		}
		case CV_CHARLIST:		// usually just a gm command
		{
			if ( !PacketChangeCharacter::CanSendTo(m_NetState) )
				break;
			new PacketChangeCharacter(this);
			CharDisconnect();	// since there is no undoing this in the client.
			SetTargMode(CLIMODE_SETUP_CHARLIST);
			break;
		}
		case CV_CTAGLIST:
		{
			if ( !strcmpi(s.GetArgStr(), "log") )
				pSrc = &g_Serv;
			m_TagDefs.DumpKeys(pSrc, "CTAG.");
			break;
		}
		case CV_CLEARCTAGS:
		{
			if ( s.HasArgs() )
			{
				LPCTSTR pszArgs = s.GetArgStr();
				SKIP_SEPARATORS(pszArgs);
				m_TagDefs.ClearKeys(pszArgs);
			}
			else
				m_TagDefs.ClearKeys();
			break;
		}
		case CV_CLOSEPAPERDOLL:
		{
			const CChar *pChar = s.HasArgs() ? static_cast<CGrayUID>(s.GetArgVal()).CharFind() : m_pChar;
			if ( pChar )
				closeUIWindow(pChar, 0x1);
			break;
		}
		case CV_CLOSEPROFILE:
		{
			const CChar *pChar = s.HasArgs() ? static_cast<CGrayUID>(s.GetArgVal()).CharFind() : m_pChar;
			if ( pChar )
				closeUIWindow(pChar, 0x8);
			break;
		}
		case CV_CLOSESTATUS:
		{
			const CChar *pChar = s.HasArgs() ? static_cast<CGrayUID>(s.GetArgVal()).CharFind() : m_pChar;
			if ( pChar )
				closeUIWindow(pChar, 0x2);
			break;
		}
		case CV_CODEXOFWISDOM:
		{
			INT64 piArgs[2];
			size_t iArgQty = Str_ParseCmds(s.GetArgStr(), piArgs, COUNTOF(piArgs));
			if ( iArgQty < 1 )
			{
				SysMessage("Usage: CODEXOFWISDOM TopicID [ForceOpen]");
				break;
			}

			addCodexOfWisdom(static_cast<DWORD>(piArgs[0]), static_cast<bool>(piArgs[1]));
			break;
		}
		case CV_DYE:
		{
			const CObjBase *pObj = s.HasArgs() ? static_cast<CGrayUID>(s.GetArgVal()).ObjFind() : NULL;
			if ( pObj )
				addDyeOption(pObj);
			break;
		}
		case CV_EVERBTARG:
		{
			m_Prompt_Text = s.GetArgStr();
			addPromptConsole(CLIMODE_PROMPT_TARG_VERB, m_Targ_Text.IsEmpty() ? "Enter the verb" : "Enter the text", m_Targ_UID);
			break;
		}
		case CV_EXTRACT:
		{
			// sort of like EXPORT but for statics.
			// Opposite of the "UNEXTRACT" command
			TCHAR *ppArgs[2];
			size_t iArgQty = Str_ParseCmds(s.GetArgStr(), ppArgs, COUNTOF(ppArgs));
			if ( iArgQty < 2 )
			{
				SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_EXTRACT_USAGE));
				break;
			}

			m_Targ_Text = ppArgs[0];				// point at the options (if any)
			m_tmTile.m_ptFirst.InitPoint();			// clear this first
			m_tmTile.m_Code = CV_EXTRACT;			// set extract code
			m_tmTile.m_id = Exp_GetVal(ppArgs[1]);	// extract id
			addTarget(CLIMODE_TARG_TILE, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_EXTRACT_AREA), true);
			break;
		}
		case CV_UNEXTRACT:
		{
			// Create item from script.
			// Opposite of the "EXTRACT" command
			TCHAR *ppArgs[2];
			size_t iArgQty = Str_ParseCmds(s.GetArgStr(), ppArgs, COUNTOF(ppArgs));
			if ( iArgQty < 2 )
			{
				SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_UNEXTRACT_USAGE));
				break;
			}

			m_Targ_Text = ppArgs[0];				// point at the options (if any)
			m_tmTile.m_ptFirst.InitPoint();			// clear this first
			m_tmTile.m_Code = CV_UNEXTRACT;			// set extract code
			m_tmTile.m_id = Exp_GetVal(ppArgs[1]);	// extract id
			addTarget(CLIMODE_TARG_UNEXTRACT, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_MULTI_POS), true);
			break;
		}
		case CV_GMPAGE:
		{
			m_Targ_Text = s.GetArgStr();
			if ( !m_Targ_Text.IsEmpty() && !strnicmp(m_Targ_Text, "ADD ", 4) )
			{
				Cmd_GM_Page(m_Targ_Text + 4);
				break;
			}
			addPromptConsole(CLIMODE_PROMPT_GM_PAGE_TEXT, g_Cfg.GetDefaultMsg(DEFMSG_GMPAGE_PROMPT));
			break;
		}
		case CV_GOTARG:		// go to my (preselected) target.
		{
			ASSERT(m_pChar);
			CObjBase *pObj = m_Targ_UID.ObjFind();
			if ( pObj )
			{
				CPointMap pt = pObj->GetTopLevelObj()->GetTopPoint();
				m_pChar->m_dirFace = m_pChar->GetDir(pObj, m_pChar->m_dirFace);
				m_pChar->Spell_Teleport(pt, true, false);
			}
			break;
		}
		case CV_INFO:
		{
			// We could also get ground tile info.
			addTarget(CLIMODE_TARG_OBJ_INFO, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_ITEM_INFO), true, false);
			break;
		}
		case CV_INFORMATION:
		{
			SysMessage(g_Serv.GetStatusString(0x22));
			SysMessage(g_Serv.GetStatusString(0x24));
			break;
		}
		case CV_LAST:	// fake previous target
		{
			if ( GetTargMode() >= CLIMODE_MOUSE_TYPE )
			{
				ASSERT(m_pChar);
				CObjBase *pObj = m_pChar->m_Act_Targ.ObjFind();
				if ( pObj )
				{
					Event_Target(GetTargMode(), pObj->GetUID(), pObj->GetTopPoint());
					addTargetCancel();
				}
				break;
			}
			return false;
		}
		case CV_LINK:	// link doors
		{
			m_Targ_UID.InitUID();
			addTarget(CLIMODE_TARG_LINK, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_LINK_ITEM));
			break;
		}
		case CV_MAPWAYPOINT:
		{
			INT64 piVal[2];
			size_t iArgQty = Str_ParseCmds(s.GetArgRaw(), piVal, COUNTOF(piVal));
			if ( iArgQty < 2 )
			{
				SysMessage("Usage: MAPWAYPOINT uid type");
				break;
			}
			CObjBase *pObj = static_cast<CGrayUID>(piVal[0]).ObjFind();
			addMapWaypoint(pObj, static_cast<MAPWAYPOINT_TYPE>(piVal[1]));
			break;
		}
		case CV_MENU:
		{
			Menu_Setup(g_Cfg.ResourceGetIDType(RES_MENU, s.GetArgStr()));
			break;
		}
		case CV_MIDILIST:
		{
			INT64 piMidi[64];
			size_t iArgQty = Str_ParseCmds(s.GetArgStr(), piMidi, COUNTOF(piMidi));
			if ( iArgQty > 0 )
				addMusic(static_cast<MIDI_TYPE>(piMidi[Calc_GetRandVal(iArgQty)]));
			break;
		}
		case CV_NUDGE:
		{
			if ( !s.HasArgs() )
			{
				SysMessage("Usage: NUDGE dx dy dz");
				break;
			}
			m_Targ_Text = s.GetArgRaw();
			m_tmTile.m_ptFirst.InitPoint();		// clear this first
			m_tmTile.m_Code = CV_NUDGE;
			addTarget(CLIMODE_TARG_TILE, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_NUDGE_AREA), true);
			break;
		}
		case CV_NUKE:
		{
			m_Targ_Text = s.GetArgRaw();
			m_tmTile.m_ptFirst.InitPoint();		// clear this first
			m_tmTile.m_Code = CV_NUKE;			// set nuke code
			addTarget(CLIMODE_TARG_TILE, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_NUKE_AREA), true);
			break;
		}
		case CV_NUKECHAR:
		{
			m_Targ_Text = s.GetArgRaw();
			m_tmTile.m_ptFirst.InitPoint();		// clear this first
			m_tmTile.m_Code = CV_NUKECHAR;		// set nuke code
			addTarget(CLIMODE_TARG_TILE, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_NUKE_CHAR_AREA), true);
			break;
		}
		case CV_OPENPAPERDOLL:
		{
			const CChar *pChar = s.HasArgs() ? static_cast<CGrayUID>(s.GetArgVal()).CharFind() : m_pChar;
			if ( pChar )
				addCharPaperdoll(pChar);
			break;
		}
		case CV_OPENTRADEWINDOW:
		{
			TCHAR *ppArgs[2];
			Str_ParseCmds(s.GetArgStr(), ppArgs, COUNTOF(ppArgs));

			CChar *pChar = ppArgs[0] ? static_cast<CGrayUID>(Exp_GetLLVal(ppArgs[0])).CharFind() : NULL;
			if ( pChar )
			{
				CItem *pItem = ppArgs[1] ? static_cast<CGrayUID>(Exp_GetLLVal(ppArgs[1])).ItemFind() : NULL;
				Cmd_SecureTrade(pChar, pItem);
			}
			break;
		}
		case CV_PAGE:
			Cmd_GM_PageCmd(s.GetArgStr());
			break;
		case CV_REPAIR:
			addTarget(CLIMODE_TARG_REPAIR, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_ITEM_REPAIR));
			break;
		case CV_FLUSH:
#ifndef _MTNETWORK
			g_NetworkOut.flush(this);
#else
			g_NetworkManager.flush(m_NetState);
#endif
			break;
		case CV_RESEND:
			addReSync();
			break;
		case CV_SAVE:
			g_World.Save(s.GetArgVal() != 0);
			break;
		case CV_SCROLL:
			// put a scroll up.
			addScrollResource(s.GetArgStr(), SCROLL_TYPE_UPDATES);
			break;
		case CV_SENDPACKET:
			SendPacket(s.GetArgStr());
			break;
		case CV_SELF:		// fake self target
			if ( GetTargMode() >= CLIMODE_MOUSE_TYPE )
			{
				ASSERT(m_pChar);
				Event_Target(GetTargMode(), m_pChar->GetUID(), m_pChar->GetTopPoint());
				addTargetCancel();
				break;
			}
			return false;
		case CV_SHOWSKILLS:
			addSkillWindow(static_cast<SKILL_TYPE>(g_Cfg.m_iMaxSkill));		// reload the real skills
			break;
		case CV_SKILLMENU:
			Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, s.GetArgStr()));
			break;
		case CV_SKILLSELECT:
			Event_Skill_Use(g_Cfg.FindSkillKey(s.GetArgStr()));
			break;
		case CV_SUMMON:
		{
			ASSERT(m_pChar);
			const CSpellDef *pSpellDef = g_Cfg.GetSpellDef(SPELL_Summon);
			if ( !pSpellDef )
				return false;

			m_pChar->m_Act_Targ = m_pChar->GetUID();
			m_pChar->m_Act_TargPrv = m_pChar->GetUID();

			if ( pSpellDef->IsSpellType(SPELLFLAG_TARG_OBJ|SPELLFLAG_TARG_XYZ) )
			{
				m_tmSkillMagery.m_Spell = SPELL_Summon;
				m_tmSkillMagery.m_SummonID = static_cast<CREID_TYPE>(g_Cfg.ResourceGetIndexType(RES_CHARDEF, s.GetArgStr()));

				LPCTSTR pszPrompt = g_Cfg.GetDefaultMsg(DEFMSG_SELECT_MAGIC_TARGET);
				if ( !pSpellDef->m_sTargetPrompt.IsEmpty() )
					pszPrompt = pSpellDef->m_sTargetPrompt;

				int iSpellTimeout = static_cast<int>(GetDefNum("SPELLTIMEOUT"));
				if ( !iSpellTimeout )
					iSpellTimeout = g_Cfg.m_iSpellTimeout * TICK_PER_SEC;

				addTarget(CLIMODE_TARG_SKILL_MAGERY, pszPrompt, pSpellDef->IsSpellType(SPELLFLAG_TARG_XYZ), pSpellDef->IsSpellType(SPELLFLAG_HARM), iSpellTimeout);
				break;
			}
			else
			{
				m_pChar->m_atMagery.m_Spell = SPELL_Summon;
				m_pChar->m_atMagery.m_SummonID = static_cast<CREID_TYPE>(g_Cfg.ResourceGetIndexType(RES_CHARDEF, s.GetArgStr()));

				if ( IsSetMagicFlags(MAGICF_PRECAST) && !pSpellDef->IsSpellType(SPELLFLAG_NOPRECAST) )
				{
					m_pChar->Spell_CastDone();
					break;
				}
				else
				{
					int iSkill;
					if ( !pSpellDef->GetPrimarySkill(&iSkill, NULL) )
						return false;

					m_pChar->Skill_Start(static_cast<SKILL_TYPE>(iSkill));
				}
			}
			break;
		}
		case CV_SMSG:
		case CV_SYSMESSAGE:
			SysMessage(s.GetArgStr());
			break;
		case CV_SYSMESSAGEF:	// there is still an issue with numbers not resolving properly when %i,%d,or other numeric format code is in use
		{
			TCHAR *ppArgs[4];
			size_t iArgQty = Str_ParseCmds(s.GetArgRaw(), ppArgs, COUNTOF(ppArgs));
			if ( iArgQty < 2 )
			{
				g_Log.EventError("SysMessagef with less than 1 args for the given text\n");
				return false;
			}
			if ( iArgQty > 4 )
			{
				g_Log.EventError("Too many arguments given to SysMessagef (max = text + 3\n");
				return false;
			}
			if ( *ppArgs[0] == '"' )	// skip quotes
				++ppArgs[0];
			for ( TCHAR *pEnd = ppArgs[0] + strlen(ppArgs[0]) - 1; pEnd >= ppArgs[0]; --pEnd )
			{
				if ( *pEnd == '"' )		// skip quotes
				{
					*pEnd = '\0';
					break;
				}
			}
			SysMessagef(ppArgs[0], ppArgs[1], ppArgs[2] ? ppArgs[2] : 0, ppArgs[3] ? ppArgs[3] : 0);
			break;
		}
		case CV_SMSGU:
		case CV_SYSMESSAGEUA:
		{
			TCHAR *ppArgs[5];
			size_t iArgQty = Str_ParseCmds(s.GetArgRaw(), ppArgs, COUNTOF(ppArgs));
			if ( iArgQty > 4 )
			{
				// Font and mode are actually ignored here, but they never made a difference anyway.. I'd like to keep the syntax similar to SAYUA
				NCHAR szBuffer[MAX_TALK_BUFFER];
				CvtSystemToNUNICODE(szBuffer, COUNTOF(szBuffer), ppArgs[4], -1);

				addBarkUNICODE(szBuffer, NULL, static_cast<HUE_TYPE>(Exp_GetLLVal(ppArgs[0])), TALKMODE_SYSTEM, FONT_NORMAL, ppArgs[3]);
			}
			break;
		}
		case CV_SMSGL:
		case CV_SYSMESSAGELOC:
		{
			TCHAR *ppArgs[256];
			size_t iArgQty = Str_ParseCmds(s.GetArgRaw(), ppArgs, COUNTOF(ppArgs), ",");
			if ( iArgQty > 1 )
			{
				HUE_TYPE hue = HUE_TEXT_DEF;
				if ( ATOI(ppArgs[0]) > 0 )
					hue = static_cast<HUE_TYPE>(Exp_GetLLVal(ppArgs[0]));

				DWORD dwClilocId = static_cast<DWORD>(Exp_GetLLVal(ppArgs[1]));

				CGString sVal;
				for ( size_t i = 2; i < iArgQty; ++i )
				{
					if ( sVal.GetLength() )
						sVal += "\t";
					sVal += !strcmp(ppArgs[i], "NULL") ? " " : ppArgs[i];
				}

				addBarkLocalized(dwClilocId, NULL, hue, TALKMODE_SYSTEM, FONT_NORMAL, sVal.GetPtr());
			}
			break;
		}
		case CV_SMSGLEX:
		case CV_SYSMESSAGELOCEX:
		{
			TCHAR *ppArgs[256];
			size_t iArgQty = Str_ParseCmds(s.GetArgRaw(), ppArgs, COUNTOF(ppArgs), ",");
			if ( iArgQty > 2 )
			{
				HUE_TYPE hue = HUE_TEXT_DEF;
				AFFIX_TYPE affix = AFFIX_APPEND;
				if ( ATOI(ppArgs[0]) > 0 )
					hue = static_cast<HUE_TYPE>(Exp_GetLLVal(ppArgs[0]));

				DWORD dwClilocId = static_cast<DWORD>(Exp_GetLLVal(ppArgs[1]));

				if ( ppArgs[2] )
					affix = static_cast<AFFIX_TYPE>(Exp_GetLLVal(ppArgs[2]));

				CGString sVal;
				for ( size_t i = 4; i < iArgQty; ++i )
				{
					if ( sVal.GetLength() )
						sVal += "\t";
					sVal += !strcmp(ppArgs[i], "NULL") ? " " : ppArgs[i];
				}

				addBarkLocalizedEx(dwClilocId, NULL, hue, TALKMODE_SYSTEM, FONT_NORMAL, affix, ppArgs[3], sVal.GetPtr());
			}
			break;
		}
		case CV_TELE:
			Cmd_Skill_Magery(SPELL_Teleport, dynamic_cast<CObjBase *>(pSrc));
			break;
		case CV_TILE:
			if ( !s.HasArgs() )
			{
				SysMessage("Usage: TILE z-height item1 item2 itemX");
				break;
			}
			m_Targ_Text = s.GetArgStr();	// point at the options
			m_tmTile.m_ptFirst.InitPoint();	// clear this first
			m_tmTile.m_Code = CV_TILE;
			addTarget(CLIMODE_TARG_TILE, "Pick 1st corner:", true);
			break;
		case CV_VERSION:
			SysMessage(g_szServerDescription);
			break;
		case CV_WEBLINK:
			addWebLaunch(s.GetArgStr());
			break;
		default:
			if ( r_LoadVal(s) )
			{
				CGString sVal;
				if ( r_WriteVal(s.GetKey(), sVal, pSrc) )
					return true;
			}
			return CScriptObj::r_Verb(s, pSrc);		// used in the case of web pages to access server level things
	}
	return true;
	EXC_CATCH;

	EXC_DEBUG_START;
	EXC_ADD_SCRIPTSRC;
	EXC_DEBUG_END;
	return false;
}
Пример #14
0
int CResource::Calc_CombatChanceToHit( CChar * pChar, SKILL_TYPE skill, CChar * pCharTarg, CItem * pWeapon )
{
	// AGRS:
	//  pChar = the attacker.
	//  pWeapon = NULL = wrestling.
	//
	// RETURN:
	//  0-100 percent chance to hit on a d100 roll.
	// ??? OR ???
	//  0-100 percent difficulty against my SKILL_* combat skill 
	//
	// NOTE: 
	// There should be size panlties of large creatures vs. small creatures in melee combat.

	// Chance to hit a target: (bow or melee)
	// Target speed (DEX) subtract out STAM lost?
	// Target Surprised ? (war mode) 
	// vs. 
	// Attackers Weapon skill
	// Attackers TACTICS
	// Attackers STAM/DEX
	// Size diff.
	//
	// NOTE: 
	//  How does this translate to experiencce in my combat skills ?

	// What is our chance of hitting our target?
	// This will be compared to our current weapon skill level.
	// There should always be a bit of a chance. (even if we suck)
	// Adjust the value for our experience curve level.
	// RETURN:
	//  0-100 difficulty.

	if ( pCharTarg == NULL )
	{
		return( Calc_GetRandVal(31)); // must be a training dummy
	}

	if ( pChar->m_pNPC &&
		pChar->m_pNPC->m_Brain == NPCBRAIN_GUARD &&
		m_fGuardsInstantKill )
	{
		return( 0 );
	}

	// Frozen targets should be easy.
	if ( pCharTarg->IsStatFlag( STATF_Sleeping | STATF_Freeze | STATF_Stone ))
	{
		return( Calc_GetRandVal(10));
	}

	int iSkillVal = pChar->Skill_GetAdjusted( skill );

	// Offensive value mostly based on your skill and TACTICS.
	// 0 - 1000
	int iSkillAttack = ( iSkillVal + pChar->Skill_GetAdjusted( SKILL_TACTICS )) / 2;
	// int iSkillAttack = ( iSkillVal * 3 + pChar->Skill_GetAdjusted( SKILL_TACTICS )) / 4;

	// Defensive value mostly based on your tactics value and random DEX,
	// 0 - 1000
	int iSkillDefend = pCharTarg->Skill_GetAdjusted( SKILL_TACTICS );

	// Make it easier to hit people havin a bow or crossbow due to the fact that its
	// not a very "mobile" weapon, nor is it fast to change position while in
	// a fight etc. Just use 90% of the statvalue when defending so its easier
	// to hit than defend == more fun in combat.
	int iStam = pCharTarg->Stat_GetVal(STAT_DEX);
	if ( pCharTarg->Skill_GetActive() == SKILL_ARCHERY &&
		skill != SKILL_ARCHERY )
		// The defender uses ranged weapon and the attacker is not.
		// Make just a bit easier to hit.
		iSkillDefend = ( iSkillDefend + iStam*9 ) / 2;
	else
		// The defender is using a nonranged, or they both use bows.
		iSkillDefend = ( iSkillDefend + iStam*10 ) / 2;

	int iDiff = ( iSkillAttack - iSkillDefend ) / 5;

	iDiff = ( iSkillVal - iDiff ) / 10;
	if ( iDiff < 0 )
		iDiff = 0;	// just means it's very easy.
	else if ( iDiff > 100 )
		iDiff = 100;	// just means it's very hard.

	return( Calc_GetRandVal(iDiff));	// always need to have some chance. );
}
Пример #15
0
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);
	WORD iMaxSkill = pSkillTag ? static_cast<WORD>(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
	{
		static const SOUND_TYPE sm_TrainingDummySounds[] = { 0x3A4, 0x3A6, 0x3A9, 0x3AE, 0x3B4, 0x3B6 };
		pItem->Sound(sm_TrainingDummySounds[Calc_GetRandVal(COUNTOF(sm_TrainingDummySounds))]);
		pItem->SetAnim(static_cast<ITEMID_TYPE>(pItem->GetID() + 1), 3 * TICK_PER_SEC);
		Skill_UseQuick(skill, Calc_GetRandLLVal(40));
	}
	return true;
}
Пример #16
0
CPointMap CItemContainer::GetRandContainerLoc() const
{
	ADDTOCALLSTACK("CItemContainer::GetRandContainerLoc");
	// Max/Min Container Sizes.

	static const struct // we can probably get this from MUL file some place.
	{
		GUMP_TYPE m_gump;
		WORD m_minx;
		WORD m_miny;
		WORD m_maxx;
		WORD m_maxy;
	} sm_ContSize[] =
	{
		{ GUMP_RESERVED, 40, 50, 100, 100 },		// default.
		{ GUMP_CORPSE, 20, 85, 80, 185 },
		{ GUMP_PACK, 44, 65, 142, 150 },			// Open backpack
		{ GUMP_BAG, 29, 34, 93, 119 },				// Leather Bag
		{ GUMP_BARREL, 33, 36, 98, 139 },			// Barrel
		{ GUMP_BASKET_SQ, 19, 47, 138, 114 },		// Square picknick Basket
		{ GUMP_BOX_WOOD, 16, 51, 140, 115 },		// small wood box with a lock
		{ GUMP_BASKET_RO, 33, 36,  98, 134 },		// Round Basket
		{ GUMP_CHEST_GO_SI, 18, 105, 118, 169 },	// Gold and Silver Chest.
		{ GUMP_BOX_WOOD_OR, 16, 51, 140, 115 },		// Small wood box (ornate)(no lock)
		{ GUMP_CRATE, 20, 10, 126, 91 },			// Wood Crate
		{ GUMP_DRAWER_DK, 16, 17, 110, 85 },
		{ GUMP_CHEST_WO_GO, 18, 105, 118, 169 },	// Wood with gold trim.
		{ GUMP_CHEST_SI, 18, 105, 118, 169 },		// silver chest.
		{ GUMP_BOX_GO_LO, 16, 51, 140, 115 },		// Gold/Brass box with a lock.
		{ GUMP_SHIP_HOLD, 46, 74, 152, 175 },
		{ GUMP_BOOK_SHELF, 76, 12, 96, 59 },
		{ GUMP_CABINET_DK, 24, 96, 91, 143 },
		{ GUMP_CABINET_LT, 24, 96, 91, 143 },
		{ GUMP_DRAWER_LT, 16, 17, 110, 85 },
		{ GUMP_GIFT_BOX, 35, 10, 155, 85 },
		{ GUMP_ARMOIRE_RED, 10, 10, 150, 95 },
		{ GUMP_ARMOIRE_MAPLE, 10, 10, 150, 95 },
		{ GUMP_ARMOIRE_CHERRY, 10, 10, 150, 95 },
		{ GUMP_BASKET_TALL, 10, 10, 116, 71 },
		{ GUMP_CHEST_WOOD_PLAIN, 10, 10, 150, 95 },
		{ GUMP_CHEST_WOOD_GILDED, 10, 10, 150, 95 },
		{ GUMP_CHEST_WOOD_ORNATE, 10, 10, 150, 95 },
		{ GUMP_TALL_CABINET, 10, 10, 150, 95 },
		{ GUMP_CHEST_WOOD_FINISH, 10, 10, 150, 95 },
		{ GUMP_HEART_SHAPED, 56, 30, 102, 74},
		{ GUMP_SECURE_TRADE, 1, 1, 66, 26 },
		{ GUMP_GAME_BOARD,	 4, 10, 220, 185 },		// Chess or checker board.
		{ GUMP_GAME_BACKGAM, 4, 10, 220, 185 },
	};

	// ??? pItemDef->m_ttContainer.m_dwMinXY to m_dwMaxXY
	// Get a random location in the container.

	CItemBase * pItemDef = Item_GetDef();
	GUMP_TYPE gump = pItemDef->IsTypeContainer();

	// check for custom values in TDATA3/TDATA4
	if ( pItemDef->m_ttContainer.m_dwMaxXY )
	{
		int tmp_MinX = (pItemDef->m_ttContainer.m_dwMinXY & 0xFFFF0000) >> 16;
		int tmp_MinY = (pItemDef->m_ttContainer.m_dwMinXY & 0xFFFF);
		int tmp_MaxX = (pItemDef->m_ttContainer.m_dwMaxXY & 0xFFFF0000) >> 16;
		int tmp_MaxY = (pItemDef->m_ttContainer.m_dwMaxXY & 0xFFFF);
		DEBUG_WARN(("Custom container gump id %d for 0%x\n", gump, GetDispID()));
		return( CPointMap(
			static_cast<WORD>(tmp_MinX + Calc_GetRandVal(tmp_MaxX - tmp_MinX)),
			static_cast<WORD>(tmp_MinY + Calc_GetRandVal(tmp_MaxY - tmp_MinY)),
			0 ));
	}
Пример #17
0
bool CItemMulti::r_Verb( CScript & s, CTextConsole * pSrc ) // Execute command from script
{
	LOCKDATA;
	EXC_TRY(("r_Verb('%s %s',%x)", s.GetKey(), s.GetArgStr(), pSrc));
	// Speaking in this ships region.
	// return: true = command for the ship.

	//"One (direction*)", " (Direction*), one" Moves ship one tile in desired direction and stops.
	//"Slow (direction*)" Moves ship slowly in desired direction (see below for possible directions).

	int iCmd = FindTableSorted( s.GetKey(), sm_szVerbKeys, COUNTOF( sm_szVerbKeys )-1 );
	if ( iCmd < 0 )
	{
		return( CItem::r_Verb( s, pSrc ));
	}

	if ( ! pSrc )
		return( false );

	switch ( iCmd )
	{
	case SHV_MULTICREATE:
		{
			CGrayUID	uid( s.GetArgVal() );
			CChar *	pSrc	= uid.CharFind();
			Multi_Create( pSrc, 0 );
		}
		return true;
	}

	if ( IsAttr(ATTR_MOVE_NEVER) || ! IsTopLevel() )
		return false;

	CChar * pChar = pSrc->GetChar();

	// Only key holders can command the ship ???
	// if ( pChar && pChar->ContentFindKeyFor( pItem ))

	// Find the tiller man object.
	CItem * pTiller = Multi_GetSign();
	ASSERT( pTiller );

	// Get current facing dir.
	DIR_TYPE DirFace = sm_Ship_FaceDir[ Ship_GetFaceOffset() ];
	int DirMoveChange;
	LPCTSTR pszSpeak = NULL;

	switch ( iCmd )
	{
	case SHV_SHIPSTOP:
		// "Furl sail"
		// "Stop" Stops current ship movement.
		if ( ! m_itShip.m_fSail )
			return( false );
		Ship_Stop();
		break;
	case SHV_SHIPFACE:
		// Face this direction. do not change the direction of movement.
		if ( ! s.HasArgs())
			return( false );
		return Ship_Face( GetDirStr( s.GetArgStr()));

	case SHV_SHIPMOVE:
		// Move one space in this direction.
		// Does NOT protect against exploits !
		if ( ! s.HasArgs())
			return( false );
		m_itShip.m_DirMove = GetDirStr( s.GetArgStr());
		return Ship_Move( (DIR_TYPE) m_itShip.m_DirMove );

	case SHV_SHIPGATE:
		// Move the whole ship and contents to another place.
		if ( ! s.HasArgs())
			return( false );
		{
			CPointMap ptdelta = g_Cfg.GetRegionPoint( s.GetArgStr());
			if ( ! ptdelta.IsValidPoint())
				return( false );
			ptdelta -= GetTopPoint();
			return Ship_MoveDelta( ptdelta );
		}
		break;
	case SHV_SHIPTURNLEFT:
		// "Port",
		// "Turn Left",
		DirMoveChange = -2;
doturn:
		if ( m_itShip.m_fAnchored )
		{
anchored:
			pszSpeak = "The anchor is down <SEX Sir/Mam>!";
			break;
		}
		m_itShip.m_DirMove = GetDirTurn( DirFace, DirMoveChange );
		Ship_Face( (DIR_TYPE) m_itShip.m_DirMove );
		break;
	case SHV_SHIPTURNRIGHT:
		// "Turn Right",
		// "Starboard",	// Turn Right
		DirMoveChange = 2;
		goto doturn;
	case SHV_SHIPDRIFTLEFT: 
		// "Left",
		// "Drift Left",
		DirMoveChange = -2;
dodirmovechange:
		if ( m_itShip.m_fAnchored )
			goto anchored;
		if ( ! Ship_SetMoveDir( GetDirTurn( DirFace, DirMoveChange )))
			return( false );
		break;
	case SHV_SHIPDRIFTRIGHT: 
		// "Right",
		// "Drift Right",
		DirMoveChange = 2;
		goto dodirmovechange;
	case SHV_SHIPBACK: 
		// "Back",			// Move ship backwards
		// "Backward",		// Move ship backwards
		// "Backwards",	// Move ship backwards
		DirMoveChange = 4;
		goto dodirmovechange;
	case SHV_SHIPFORE:
		// "Forward"
		// "Foreward",		// Moves ship forward.
		// "Unfurl sail",	// Moves ship forward.
		DirMoveChange = 0;
		goto dodirmovechange;
	case SHV_SHIPFORELEFT: // "Forward left",
		DirMoveChange = -1;
		goto dodirmovechange;
	case SHV_SHIPFORERIGHT: // "forward right",
		DirMoveChange = 1;
		goto dodirmovechange;
	case SHV_SHIPBACKLEFT:
		// "backward left",
		// "back left",
		DirMoveChange = -3;
		goto dodirmovechange;
	case SHV_SHIPBACKRIGHT:
		// "backward right",
		// "back right",
		DirMoveChange = 3;
		goto dodirmovechange;
	case SHV_SHIPANCHORRAISE: // "Raise Anchor",
		if ( ! m_itShip.m_fAnchored )
		{
			pszSpeak = "The anchor is already up <SEX Sir/Mam>";
			break;
		}
		m_itShip.m_fAnchored = false;
		break;
	case SHV_SHIPANCHORDROP: // "Drop Anchor",
		if ( m_itShip.m_fAnchored )
		{
			pszSpeak = "The anchor is already down <SEX Sir/Mam>";
			break;
		}
		m_itShip.m_fAnchored = true;
		Ship_Stop();
		break;
	case SHV_SHIPTURN:
		//	"Turn around",	// Turns ship around and proceeds.
		// "Come about",	// Turns ship around and proceeds.
		DirMoveChange = 4;
		goto doturn;
	case SHV_SHIPUP: // "Up"
		{
			if ( ! IsAttr(ATTR_MAGIC ))
				return( false );

			CPointMap pt;
			pt.m_z = PLAYER_HEIGHT;
			if ( Ship_MoveDelta( pt ))
			{
				pszSpeak = "As you command <SEX Sir/Mam>";
			}
			else
			{
				pszSpeak = "Can't do that <SEX Sir/Mam>";
			}
		}
		break;
	case SHV_SHIPDOWN: // "Down"
		{
			if ( ! IsAttr(ATTR_MAGIC ))
				return( false );
			CPointMap pt;
			pt.m_z = -PLAYER_HEIGHT;
			if ( Ship_MoveDelta( pt ))
			{
				pszSpeak = "As you command <SEX Sir/Mam>";
			}
			else
			{
				pszSpeak = "Can't do that <SEX Sir/Mam>";
			}
		}
		break;
	case SHV_SHIPLAND: // "Land"
		{
			if ( ! IsAttr(ATTR_MAGIC ))
				return( false );
			signed char zold = GetTopZ();
			CPointMap pt = GetTopPoint();
			pt.m_z = zold;
			SetTopZ( -UO_SIZE_Z );	// bottom of the world where i won't get in the way.
			WORD wBlockFlags = CAN_I_WATER;
			signed char z = g_World.GetHeightPoint( pt, wBlockFlags );
			SetTopZ( zold );	// restore z for now.
			pt.InitPoint();
			pt.m_z = z - zold;
			if ( pt.m_z )
			{
				Ship_MoveDelta( pt );
				pszSpeak = "As you command <SEX Sir/Mam>";
			}
			else
			{
				pszSpeak = "We have landed <SEX Sir/Mam>";
			}
		}
		break;
	default:
		return( false );
	}

	if ( pChar )
	{
		if ( pszSpeak == NULL )
		{
			static LPCTSTR const sm_pszAye[] =
			{
				"Aye",
				"Aye Cap'n",
				"Aye <SEX Sir/Mam>",
			};
			pszSpeak = sm_pszAye[ Calc_GetRandVal( COUNTOF( sm_pszAye )) ];
		}

		TCHAR szText[ MAX_TALK_BUFFER ];
		strcpy( szText, pszSpeak );
		pChar->ParseText( szText, &g_Serv );
		pTiller->Speak( szText, 0, TALKMODE_SAY, FONT_NORMAL );
	}
	return false;
	EXC_CATCH("CItemMulti");
	return true;
}
Пример #18
0
bool CClient::r_Verb( CScript & s, CTextConsole * pSrc ) // Execute command from script
{
	ADDTOCALLSTACK("CClient::r_Verb");
	EXC_TRY("Verb");
	// NOTE: This can be called directly from a RES_WEBPAGE script.
	//  So do not assume we are a game client !
	// NOTE: Mostly called from CChar::r_Verb
	// NOTE: Little security here so watch out for dangerous scripts !

	ASSERT(pSrc);
	LPCTSTR pszKey = s.GetKey();

	// Old ver
	if ( s.IsKeyHead( "SET", 3 ) && ( g_Cfg.m_Functions.ContainsKey( pszKey ) == false ) )
	{
		PLEVEL_TYPE ilevel = g_Cfg.GetPrivCommandLevel( "SET" );
		if ( ilevel > GetPrivLevel() )
			return( false );

		ASSERT( m_pChar );
		addTargetVerb( pszKey+3, s.GetArgRaw());
		return( true );
	}

	if ( toupper( pszKey[0] ) == 'X' && ( g_Cfg.m_Functions.ContainsKey( pszKey ) == false ) )
	{
		PLEVEL_TYPE ilevel = g_Cfg.GetPrivCommandLevel( "SET" );
		if ( ilevel > GetPrivLevel() )
			return( false );

		// Target this command verb on some other object.
		ASSERT( m_pChar );
		addTargetVerb( pszKey+1, s.GetArgRaw());
		return( true );
	}

	int index = FindTableSorted( s.GetKey(), sm_szVerbKeys, COUNTOF(sm_szVerbKeys)-1 );
	switch (index)
	{
		case CV_ADD:
			if ( s.HasArgs())
			{
				// FindItemName ???
				TCHAR * pszArgs = s.GetArgStr();
				if ( !IsValidGameObjDef( static_cast<LPCTSTR>(pszArgs) ) )
				{
					g_Log.EventWarn("Invalid ADD argument '%s'\n", pszArgs);
					SysMessageDefault( DEFMSG_CMD_INVALID );
					return true;
				}

				RESOURCE_ID rid = g_Cfg.ResourceGetID( RES_QTY, const_cast<LPCTSTR &>(reinterpret_cast<LPTSTR &>(pszArgs)));
				if (( rid.GetResType() == RES_CHARDEF ) || ( rid.GetResType() == RES_SPAWN ))
				{
					m_Targ_PrvUID.InitUID();
					return Cmd_CreateChar(static_cast<CREID_TYPE>(rid.GetResIndex()), SPELL_Summon, false );
				}

				ITEMID_TYPE id = static_cast<ITEMID_TYPE>(rid.GetResIndex());
				return Cmd_CreateItem( id );
			}
			else
			{
				if ( IsValidDef( "d_add" ) )
					Dialog_Setup( CLIMODE_DIALOG, g_Cfg.ResourceGetIDType(RES_DIALOG, "d_add"), 0, this->GetChar() );
				else
					Menu_Setup( g_Cfg.ResourceGetIDType( RES_MENU, "MENU_ADDITEM"));	
			}
			break;
		case CV_ADDBUFF:
			{
				TCHAR * ppArgs[11];
				Str_ParseCmds( s.GetArgStr(), ppArgs, COUNTOF(ppArgs));

				int iArgs[4];
				for ( int idx = 0; idx < 4; ++idx )
				{
					if ( !IsStrNumeric(ppArgs[idx]))
					{
						DEBUG_ERR(("Invalid AddBuff argument number %u\n", idx+1));
						return true;
					}
					iArgs[idx] = Exp_GetVal( ppArgs[idx] );
				}
				if (iArgs[0] < BI_START || iArgs[0] > BI_QTY/* || iArgs[0] == 0x3EB || iArgs[0] == 0x3EC*/) {	// 0x3eb and 0x3ec among some others does not exists now, which doesn't mean they won't fill them and, since nothing happens when wrong id is sent, we can let them be sent.
					DEBUG_ERR(("Invalid AddBuff icon ID\n"));
					break;
				}

				LPCTSTR Args[7];
				size_t ArgsCount = 0;
				for ( int i = 0; i < 7; ++i )
				{
					Args[i] = ppArgs[i + 4];
					if ( Args[i] != NULL )
						ArgsCount++;
				}

				addBuff(static_cast<BUFF_ICONS>(iArgs[0]), iArgs[1], iArgs[2], static_cast<WORD>(iArgs[3]), Args, ArgsCount);
			}
			break;
		case CV_REMOVEBUFF:
			{
				BUFF_ICONS IconId = static_cast<BUFF_ICONS>(s.GetArgVal());
				if (IconId < BI_START || IconId > BI_QTY/* || IconId == 0x3EB || IconId == 0x3EC*/) {
					DEBUG_ERR(("Invalid RemoveBuff icon ID\n"));
					break;
				}
				removeBuff(IconId);
			}
			break;
		case CV_ADDCLILOC:
			// Add cliloc in @ClientTooltip trigger
			{
				TCHAR * ppLocArgs[256];
				size_t qty = Str_ParseCmds(s.GetArgRaw(), ppLocArgs, COUNTOF(ppLocArgs), ",");
				DWORD clilocid = Exp_GetVal(ppLocArgs[0]);

				CGString LocArgs;
				for ( size_t y = 1 ; y < qty; y++ )
				{
					if ( LocArgs.GetLength() )
						LocArgs += "\t";
					LocArgs += ( !strcmp(ppLocArgs[y], "NULL") ? " " : ppLocArgs[y] );
				}

				if ( g_Cfg.m_wDebugFlags & DEBUGF_SCRIPTS )
					g_Log.EventDebug("SCRIPT: addcliloc(%lu,'%s')\n", clilocid, static_cast<LPCTSTR>(LocArgs));
				this->m_TooltipData.Add(new CClientTooltip(clilocid, LocArgs));
			}
			break;
		case CV_ADDCONTEXTENTRY:
			{
				TCHAR * ppLocArgs[20];
				if ( Str_ParseCmds(s.GetArgRaw(), ppLocArgs, COUNTOF(ppLocArgs), ",") > 4 )
				{
					DEBUG_ERR(("Bad AddContextEntry usage: Function takes maximum of 4 arguments!\n"));
					return true;
				}

				if (m_pPopupPacket == NULL)
				{
					DEBUG_ERR(("Bad AddContextEntry usage: Not used under a @ContextMenuRequest/@itemContextMenuRequest trigger!\n"));
					return true;
				}

				for ( int i = 0; i < 4; i++ )
				{
					if ( i > 1 && IsStrEmpty(ppLocArgs[i]) )
						continue;

					if ( !IsStrNumeric(ppLocArgs[i]) )
					{
						DEBUG_ERR(("Bad AddContextEntry usage: Argument %d must be a number!\n", i+1));
						return true;
					}
				}

				int entrytag = Exp_GetVal(ppLocArgs[0]);
				if ( entrytag < 100 )
				{
					DEBUG_ERR(("Bad AddContextEntry usage: TextEntry < 100 is reserved for server usage!\n"));
					return true;
				}
				m_pPopupPacket->addOption(static_cast<WORD>(entrytag), static_cast<DWORD>(Exp_GetVal(ppLocArgs[1])), static_cast<WORD>(Exp_GetVal(ppLocArgs[2])), static_cast<WORD>(Exp_GetVal(ppLocArgs[3])));
			}
			break;
		case CV_ARROWQUEST:
			{
				INT64 piVal[3];
				Str_ParseCmds( s.GetArgRaw(), piVal, COUNTOF(piVal));
				addArrowQuest( static_cast<int>(piVal[0]), static_cast<int>(piVal[1]), static_cast<int>(piVal[2]) );
#ifdef _ALPHASPHERE
				// todo: should use a proper container for these, since the arrows are lost
				// when the client logs out, and also newer clients support multiple
				// arrows
				if ( piVal[0] && piVal[1] && m_pChar )
				{
					m_pChar->SetKeyNum("ARROWQUEST_X", piVal[0]);
					m_pChar->SetKeyNum("ARROWQUEST_Y", piVal[1]);
				} else {
					m_pChar->DeleteKey("ARROWQUEST_X");
					m_pChar->DeleteKey("ARROWQUEST_Y");
				}
#endif
			}
			break;
		case CV_BADSPAWN:
			{
				//	Loop the world searching for bad spawns
				bool fFound = false;
				for ( int m = 0; m < 256 && !fFound; m++ )
				{
					if ( !g_MapList.m_maps[m] ) continue;

					for ( int d = 0; d < g_MapList.GetSectorQty(m) && !fFound; d++ )
					{
						CSector	*pSector = g_World.GetSector(m, d);
						if ( !pSector ) continue;

						CItem	*pNext;
						CItem	*pItem = STATIC_CAST <CItem*>(pSector->m_Items_Inert.GetHead());
						for ( ; pItem != NULL && !fFound; pItem = pNext )
						{
							pNext = pItem->GetNext();

							if ( pItem->IsType(IT_SPAWN_ITEM) || pItem->IsType(IT_SPAWN_CHAR) )
							{
								CItemSpawn *pSpawn = static_cast<CItemSpawn*>(pItem);
								CResourceDef	*pDef = pSpawn->FixDef();
								if ( !pDef )
								{
									RESOURCE_ID_BASE	rid = ( pItem->IsType(IT_SPAWN_ITEM) ? pItem->m_itSpawnItem.m_ItemID : pItem->m_itSpawnChar.m_CharID);

									CPointMap	pt = pItem->GetTopPoint();
									m_pChar->Spell_Teleport(pt, true, false);
									m_pChar->m_Act_Targ = pItem->GetUID();
									SysMessagef("Bad spawn (0%lx, id=%s). Set as ACT", (DWORD)pItem->GetUID(), g_Cfg.ResourceGetName(rid));
									fFound = true;
								}
							}
						}
					}
				}
				if ( ! fFound )
					SysMessage(g_Cfg.GetDefaultMsg( DEFMSG_NO_BAD_SPAWNS ));
			}
			break;
		case CV_BANKSELF: // open my own bank
			addBankOpen( m_pChar, static_cast<LAYER_TYPE>(s.GetArgVal()));
			break;
		case CV_CAST:
			{
				SPELL_TYPE spell = static_cast<SPELL_TYPE>(g_Cfg.ResourceGetIndexType(RES_SPELL, s.GetArgStr()));
				const CSpellDef * pSpellDef = g_Cfg.GetSpellDef(spell);
				if (pSpellDef == NULL)
					return true;

				CObjBase * pObjSrc = dynamic_cast<CObjBase *>(pSrc);

				if ( IsSetMagicFlags( MAGICF_PRECAST ) && !pSpellDef->IsSpellType( SPELLFLAG_NOPRECAST ) )
				{
					int skill;
					if (!pSpellDef->GetPrimarySkill(&skill, NULL))
						return true;

					m_tmSkillMagery.m_Spell = spell;	// m_atMagery.m_Spell
					m_pChar->m_atMagery.m_Spell = spell;
					if (pObjSrc != NULL)
					{
						m_Targ_UID = pObjSrc->GetUID();	// default target.
						m_Targ_PrvUID = pObjSrc->GetUID();
					}
					else
					{
						m_Targ_UID.ClearUID();
						m_Targ_PrvUID.ClearUID();
					}
					m_pChar->Skill_Start(static_cast<SKILL_TYPE>(skill));
					break;
				}
				else
					Cmd_Skill_Magery(spell, pObjSrc);
			}
			break;

		case CV_CHARLIST:
			{
				// usually just a gm command
				new PacketChangeCharacter(this);

				CharDisconnect();	// since there is no undoing this in the client.
				SetTargMode( CLIMODE_SETUP_CHARLIST );
			}
			break;

		case CV_CTAGLIST:
			if ( ! strcmpi( s.GetArgStr(), "log" ))
				pSrc = &g_Serv;
			m_TagDefs.DumpKeys(pSrc, "CTAG.");
			break;

		case CV_CLEARCTAGS:
			{
				if ( s.HasArgs() )
				{
					LPCTSTR pszArgs = s.GetArgStr();
					SKIP_SEPARATORS(pszArgs);
					m_TagDefs.ClearKeys(pszArgs);
				}
				else
				{
					m_TagDefs.ClearKeys();
				}
			} break;

		case CV_CLOSEPAPERDOLL:
			{
				CChar *pChar = m_pChar;
				if ( s.HasArgs() )
				{
					CGrayUID uid = s.GetArgVal();
					pChar = uid.CharFind();
				}
				if ( pChar )
					closeUIWindow(pChar, 0x01);
			}
			break;

		case CV_CLOSEPROFILE:
			{
				CChar *pChar = m_pChar;
				if ( s.HasArgs() )
				{
					CGrayUID uid = s.GetArgVal();
					pChar = uid.CharFind();
				}
				if ( pChar )
					closeUIWindow(pChar, 0x08);
			}
			break;

		case CV_CLOSESTATUS:
			{
				CChar *pChar = m_pChar;
				if ( s.HasArgs() )
				{
					CGrayUID uid = s.GetArgVal();
					pChar = uid.CharFind();
				}
				if ( pChar )
					closeUIWindow(pChar, 0x02);
			}
			break;

		case CV_DYE:
			if ( s.HasArgs() )
			{
				CGrayUID uid(s.GetArgVal());
				CObjBase *pObj = uid.ObjFind();
				if ( pObj )
					addDyeOption(pObj);
			}
			break;

		case CV_EVERBTARG:
			m_Prompt_Text = s.GetArgStr();
			addPromptConsole( CLIMODE_PROMPT_TARG_VERB, m_Targ_Text.IsEmpty() ? "Enter the verb" : "Enter the text",  m_Targ_UID );
			break;

		case CV_EXTRACT:
			// sort of like EXPORT but for statics.
			// Opposite of the "UNEXTRACT" command

			if ( ! s.HasArgs())
			{
				SysMessage( g_Cfg.GetDefaultMsg( DEFMSG_EXTRACT_USAGE ) );
			}
			else
			{
				TCHAR * ppArgs[2];
				Str_ParseCmds( s.GetArgStr(), ppArgs, COUNTOF( ppArgs ));

				m_Targ_Text = ppArgs[0]; // Point at the options, if any
				m_tmTile.m_ptFirst.InitPoint(); // Clear this first
				m_tmTile.m_Code = CV_EXTRACT;	// set extract code.
				m_tmTile.m_id = Exp_GetVal(ppArgs[1]);	// extract id.
				addTarget( CLIMODE_TARG_TILE, g_Cfg.GetDefaultMsg( DEFMSG_SELECT_EXTRACT_AREA ), true );
			}
			break;

		case CV_UNEXTRACT:
			// Create item from script.
			// Opposite of the "EXTRACT" command
			if ( ! s.HasArgs())
			{
				SysMessage( g_Cfg.GetDefaultMsg( DEFMSG_UNEXTRACT_USAGE ) );
			}
			else
			{
				TCHAR * ppArgs[2];
				Str_ParseCmds( s.GetArgStr(), ppArgs, COUNTOF( ppArgs ));

				m_Targ_Text = ppArgs[0]; // Point at the options, if any
				m_tmTile.m_ptFirst.InitPoint(); // Clear this first
				m_tmTile.m_Code = CV_UNEXTRACT;	// set extract code.
				m_tmTile.m_id = Exp_GetVal(ppArgs[1]);	// extract id.

				addTarget( CLIMODE_TARG_UNEXTRACT, g_Cfg.GetDefaultMsg( DEFMSG_SELECT_MULTI_POS ), true );
			}
			break;

		case CV_GMPAGE:
			m_Targ_Text = s.GetArgStr();
			if ( !m_Targ_Text.IsEmpty() && !strnicmp( m_Targ_Text, "ADD ", 4 ) )
			{
				Cmd_GM_Page( m_Targ_Text + 4 );
				break;
			}
			addPromptConsole( CLIMODE_PROMPT_GM_PAGE_TEXT, g_Cfg.GetDefaultMsg( DEFMSG_GMPAGE_PROMPT ) );
			break;
		case CV_GOTARG: // go to my (preselected) target.
			{
				ASSERT(m_pChar);
				CObjBase * pObj = m_Targ_UID.ObjFind();
				if ( pObj != NULL )
				{
					CPointMap po = pObj->GetTopLevelObj()->GetTopPoint();
					CPointMap pnt = po;
					pnt.MoveN( DIR_W, 3 );
					DWORD wBlockFlags = m_pChar->GetMoveBlockFlags();
					pnt.m_z = g_World.GetHeightPoint2( pnt, wBlockFlags );	// ??? Get Area
					m_pChar->m_dirFace = pnt.GetDir( po, m_pChar->m_dirFace ); // Face the player
					m_pChar->Spell_Teleport( pnt, true, false );
				}
			}
			break;
		case CV_INFO:
			// We could also get ground tile info.
			addTarget( CLIMODE_TARG_OBJ_INFO, g_Cfg.GetDefaultMsg( DEFMSG_SELECT_ITEM_INFO ), true, false );
			break;
		case CV_INFORMATION:
			SysMessage( g_Serv.GetStatusString( 0x22 ));
			SysMessage( g_Serv.GetStatusString( 0x24 ));
			break;
		case CV_LAST:
			// Fake Previous target.
			if ( GetTargMode() >= CLIMODE_MOUSE_TYPE )
			{
				ASSERT(m_pChar);
				CObjBase * pObj = m_pChar->m_Act_Targ.ObjFind();
				if ( pObj != NULL )
				{
					Event_Target(GetTargMode(), pObj->GetUID(), pObj->GetUnkPoint());
					addTargetCancel();
				}
				break;
			}
			return( false );
		case CV_LINK:	// link doors
			m_Targ_UID.InitUID();
			addTarget( CLIMODE_TARG_LINK, g_Cfg.GetDefaultMsg( DEFMSG_SELECT_LINK_ITEM ) );
			break;

		case CV_MENU:
			Menu_Setup( g_Cfg.ResourceGetIDType( RES_MENU, s.GetArgStr()));
			break;
		case CV_MIDILIST:
			{
				INT64 piMidi[64];
				size_t iQty = Str_ParseCmds( s.GetArgStr(), piMidi, COUNTOF(piMidi));
				if ( iQty > 0 )
				{
					addMusic( static_cast<MIDI_TYPE>(piMidi[ Calc_GetRandVal( iQty ) ]) );
				}
			}
			break;
		case CV_NUDGE:
			if ( ! s.HasArgs())
			{
				SysMessage( "Usage: NUDGE dx dy dz" );
			}
			else
			{
				m_Targ_Text = s.GetArgRaw();
				m_tmTile.m_ptFirst.InitPoint(); // Clear this first
				m_tmTile.m_Code = CV_NUDGE;
				addTarget( CLIMODE_TARG_TILE, g_Cfg.GetDefaultMsg( DEFMSG_SELECT_NUDGE_AREA ), true );
			}
			break;

		case CV_NUKE:
			m_Targ_Text = s.GetArgRaw();
			m_tmTile.m_ptFirst.InitPoint(); // Clear this first
			m_tmTile.m_Code = CV_NUKE;	// set nuke code.
			addTarget( CLIMODE_TARG_TILE, g_Cfg.GetDefaultMsg( DEFMSG_SELECT_NUKE_AREA ), true );
			break;
		case CV_NUKECHAR:
			m_Targ_Text = s.GetArgRaw();
			m_tmTile.m_ptFirst.InitPoint(); // Clear this first
			m_tmTile.m_Code = CV_NUKECHAR;	// set nuke code.
			addTarget( CLIMODE_TARG_TILE, g_Cfg.GetDefaultMsg( DEFMSG_SELECT_NUKE_CHAR_AREA ), true );
			break;

		case CV_OPENPAPERDOLL:
		{
			CChar *pChar = m_pChar;
			if ( s.HasArgs() )
			{
				CGrayUID uid = s.GetArgVal();
				pChar = uid.CharFind();
			}
			if ( pChar )
				addCharPaperdoll(pChar);
		}
		break;

		case CV_PAGE:
			Cmd_GM_PageCmd( s.GetArgStr());
			break;
		case CV_REPAIR:
			addTarget( CLIMODE_TARG_REPAIR, g_Cfg.GetDefaultMsg( DEFMSG_SELECT_ITEM_REPAIR ) );
			break;
		case CV_FLUSH:
#ifndef _MTNETWORK
			g_NetworkOut.flush(this);
#else
			g_NetworkManager.flush(GetNetState());
#endif
			break;
		case CV_RESEND:
			addReSync();
			break;
		case CV_SAVE:
			g_World.Save(s.GetArgVal() != 0);
			break;
		case CV_SCROLL:
			// put a scroll up.
			addScrollResource( s.GetArgStr(), SCROLL_TYPE_UPDATES );
			break;
		case CV_SENDPACKET:
			SendPacket( s.GetArgStr() );
			break;
		case CV_SELF:
			// Fake self target.
			if ( GetTargMode() >= CLIMODE_MOUSE_TYPE )
			{
				ASSERT(m_pChar);
				Event_Target(GetTargMode(), m_pChar->GetUID(), m_pChar->GetTopPoint());
				addTargetCancel();
				break;
			}
			return( false );
		case CV_SHOWSKILLS:
			addSkillWindow(static_cast<SKILL_TYPE>(g_Cfg.m_iMaxSkill)); // Reload the real skills
			break;
		case CV_SKILLMENU:				// Just put up another menu.
			Cmd_Skill_Menu( g_Cfg.ResourceGetIDType( RES_SKILLMENU, s.GetArgStr()));
			break;
		case CV_SKILLSELECT:
			Event_Skill_Use( g_Cfg.FindSkillKey( s.GetArgStr() ) );
			break;
		case CV_SUMMON:	// from the spell skill script.
			// m_Targ_PrvUID should already be set.
			return Cmd_CreateChar(static_cast<CREID_TYPE>(g_Cfg.ResourceGetIndexType( RES_CHARDEF, s.GetArgStr())), SPELL_Summon, true );
		case CV_SMSG:
		case CV_SYSMESSAGE:
			SysMessage( s.GetArgStr() );
			break;
		case CV_SYSMESSAGEF: //There is still an issue with numbers not resolving properly when %i,%d,or other numeric format code is in use
			{
				TCHAR * pszArgs[4];
				size_t iArgQty = Str_ParseCmds( s.GetArgRaw(), pszArgs, COUNTOF(pszArgs) );
				if ( iArgQty < 2 )
				{
					g_Log.EventError("SysMessagef with less than 1 args for the given text\n");
					return false;
				}
				if ( iArgQty > 4 )
				{
					g_Log.EventError("Too many arguments given to SysMessagef (max = text + 3\n");
					return false;
				}
				//strip quotes if any
				if ( *pszArgs[0] == '"' )
					pszArgs[0]++;
				for (TCHAR * pEnd = pszArgs[0] + strlen( pszArgs[0] ) - 1; pEnd >= pszArgs[0]; pEnd-- )
				{
					if ( *pEnd == '"' )
					{
						*pEnd = '\0';
						break;
					}
				}
				SysMessagef( pszArgs[0], pszArgs[1], pszArgs[2] ? pszArgs[2] : 0, pszArgs[3] ? pszArgs[3] : 0);
			}break;
		case CV_SMSGU:
		case CV_SYSMESSAGEUA:
			{
				TCHAR * pszArgs[5];
				size_t iArgQty = Str_ParseCmds( s.GetArgRaw(), pszArgs, COUNTOF(pszArgs) );
				if ( iArgQty > 4 )
				{
					// Font and mode are actually ignored here, but they never made a difference
					// anyway.. I'd like to keep the syntax similar to SAYUA
			 		NCHAR szBuffer[ MAX_TALK_BUFFER ];
					CvtSystemToNUNICODE( szBuffer, COUNTOF(szBuffer), pszArgs[4], -1 );

					addBarkUNICODE( szBuffer, NULL, static_cast<HUE_TYPE>(Exp_GetVal(pszArgs[0])), TALKMODE_SYSTEM, FONT_NORMAL, pszArgs[3] );
				}
			}
			break;
		case CV_SMSGL:
		case CV_SYSMESSAGELOC:
			{
				TCHAR * ppArgs[256];
				size_t iArgQty = Str_ParseCmds( s.GetArgRaw(), ppArgs, COUNTOF(ppArgs), "," );
				if ( iArgQty > 1 )
				{
					int hue = -1;
					if ( ppArgs[0] )
						hue = Exp_GetVal( ppArgs[0] );
					int iClilocId = Exp_GetVal( ppArgs[1] );

					if ( hue == -1 )	hue = HUE_TEXT_DEF;

					CGString CArgs;
					for ( size_t i = 2; i < iArgQty; i++ )
					{
						if ( CArgs.GetLength() )
							CArgs += "\t";
						CArgs += ( !strcmp(ppArgs[i], "NULL") ? " " : ppArgs[i] );
					}

					addBarkLocalized(iClilocId, NULL, static_cast<HUE_TYPE>(hue), TALKMODE_SYSTEM, FONT_NORMAL, CArgs.GetPtr());
				}
			}
			break;
		case CV_SMSGLEX:
		case CV_SYSMESSAGELOCEX:
			{
				TCHAR * ppArgs[256];
				size_t iArgQty = Str_ParseCmds( s.GetArgRaw(), ppArgs, COUNTOF(ppArgs), "," );
				if ( iArgQty > 2 )
				{
					int hue = -1;
					int affix = 0;
					if ( ppArgs[0] )
						hue = Exp_GetVal( ppArgs[0] );
					int iClilocId = Exp_GetVal( ppArgs[1] );
					if ( ppArgs[2] )
						affix = Exp_GetVal( ppArgs[2] );

					if ( hue == -1 )	hue = HUE_TEXT_DEF;

					CGString CArgs;
					for ( size_t i = 4; i < iArgQty; i++ )
					{
						if ( CArgs.GetLength() )
							CArgs += "\t";
						CArgs += ( !strcmp(ppArgs[i], "NULL") ? " " : ppArgs[i] );
					}

					addBarkLocalizedEx( iClilocId, NULL, static_cast<HUE_TYPE>(hue), TALKMODE_SYSTEM, FONT_NORMAL, static_cast<AFFIX_TYPE>(affix), ppArgs[3], CArgs.GetPtr() );
				}
			}
			break;
		case CV_TELE:
			Cmd_Skill_Magery(SPELL_Teleport, dynamic_cast<CObjBase *>(pSrc));
			break;
		case CV_TILE:
			if ( ! s.HasArgs())
			{
				SysMessage( "Usage: TILE z-height item1 item2 itemX" );
			}
			else
			{
				m_Targ_Text = s.GetArgStr(); // Point at the options
				m_tmTile.m_ptFirst.InitPoint(); // Clear this first
				m_tmTile.m_Code = CV_TILE;
				addTarget( CLIMODE_TARG_TILE, "Pick 1st corner:", true );
			}
			break;
		case CV_VERSION:	// "SHOW VERSION"
			SysMessage(g_szServerDescription);
			break;
		case CV_WEBLINK:
			addWebLaunch( s.GetArgStr());
			break;
		default:
			if ( r_LoadVal( s ))
			{
				CGString sVal;
				if ( r_WriteVal( s.GetKey(), sVal, pSrc ))
				{
					// if ( !s.IsKeyHead( "CTAG.", 5 ) && !s.IsKeyHead( "CTAG0.", 6 ) ) // We don't want output related to ctag
					//	SysMessagef( "%s = %s", (LPCTSTR) s.GetKey(), (LPCTSTR) sVal );	// feedback on what we just did.

					return( true );
				}
			}
			return( CScriptObj::r_Verb( s, pSrc ));	// used in the case of web pages to access server level things..
	}
	return true;
	EXC_CATCH;

	EXC_DEBUG_START;
	EXC_ADD_SCRIPTSRC;
	EXC_DEBUG_END;
	return false;
}
Пример #19
0
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 );
}
Пример #20
0
bool CSector::OnTick()
{
	ADDTOCALLSTACK("CSector::OnTick");
	/*Ticking sectors from CWorld
    * Timer is automatically updated at the end with a 30 seconds default delay
    * Any return before it will threat this CSector as Sleep and will make it
    * not tick again until a new player enters (WARNING: even if there are
    * players already inside).
    */

	EXC_TRY("Tick");

	//	do not tick sectors on maps not supported by server
	if ( !g_MapList.m_maps[m_map] )
		return true;

    EXC_SET_BLOCK("light change");
	// Check for light change before putting the sector to sleep, since in other case the
	// world light levels will be shitty
	bool fEnvironChange = false;
	bool fLightChange = false;

	// check for local light level change ?
	byte bLightPrv = m_Env.m_Light;
	m_Env.m_Light = GetLightCalc( false );
	if ( m_Env.m_Light != bLightPrv )
	{
		fEnvironChange = true;
		fLightChange = true;
	}

	EXC_SET_BLOCK("sector sleeping?");
    bool fCanSleep = CanSleep(true);
    int64 iCurTime = CServerTime::GetCurrentTime().GetTimeRaw();

	// Put the sector to sleep if no clients been here in a while.
	if (fCanSleep && (g_Cfg._iSectorSleepDelay > 0))
	{
        if (!IsSleeping())
        {
            GoSleep();
        }
		return true;
	}


	EXC_SET_BLOCK("sound effects");
	// random weather noises and effects.
	SOUND_TYPE sound = 0;
	bool fWeatherChange = false;
	int iRegionPeriodic = 0;

	WEATHER_TYPE weatherprv = m_Env.m_Weather;
	if ( ! Calc_GetRandVal( 30 ))	// change less often
	{
		m_Env.m_Weather = GetWeatherCalc();
		if ( weatherprv != m_Env.m_Weather )
		{
			fWeatherChange = true;
			fEnvironChange = true;
		}
	}

	// Random area noises. Only do if clients about.
	if ( GetClientsNumber() > 0 )
	{
		iRegionPeriodic = 2;

		static const SOUND_TYPE sm_SfxRain[] = { 0x10, 0x11 };
		static const SOUND_TYPE sm_SfxWind[] = { 0x14, 0x15, 0x16 };
		static const SOUND_TYPE sm_SfxThunder[] = { 0x28, 0x29 , 0x206 };

		// Lightning ?	// wind, rain,
		switch ( GetWeather() )
		{
			case WEATHER_CLOUDY:
				break;

			case WEATHER_SNOW:
				if ( ! Calc_GetRandVal(5) )
					sound = sm_SfxWind[ Calc_GetRandVal( CountOf( sm_SfxWind )) ];
				break;

			case WEATHER_RAIN:
				{
					int iVal = Calc_GetRandVal(30);
					if ( iVal < 5 )
					{
						// Mess up the light levels for a sec..
						LightFlash();
						sound = sm_SfxThunder[ Calc_GetRandVal( CountOf( sm_SfxThunder )) ];
					}
					else if ( iVal < 10 )
						sound = sm_SfxRain[ Calc_GetRandVal( CountOf( sm_SfxRain )) ];
					else if ( iVal < 15 )
						sound = sm_SfxWind[ Calc_GetRandVal( CountOf( sm_SfxWind )) ];
				}
				break;

			default:
				break;
		}
	}

    // Check environ changes and inform clients of it.
	ProfileTask charactersTask(PROFILE_CHARS);

	CChar * pCharNext = nullptr;
	CChar * pChar = static_cast <CChar*>( m_Chars_Active.GetHead());
	for ( ; pChar != nullptr; pChar = pCharNext )
	{
		EXC_TRYSUB("TickChar");

		pCharNext = pChar->GetNext();

		if (( fEnvironChange ) && ( IsTrigUsed(TRIGGER_ENVIRONCHANGE) ))
			pChar->OnTrigger(CTRIG_EnvironChange, pChar);

		if ( pChar->IsClient())
		{
			CClient * pClient = pChar->GetClient();
			ASSERT( pClient );
			if ( sound )
				pClient->addSound(sound, pChar);

			if ( fLightChange && ! pChar->IsStatFlag( STATF_DEAD | STATF_NIGHTSIGHT ))
				pClient->addLight();

			if ( fWeatherChange )
				pClient->addWeather(GetWeather());

			if ( iRegionPeriodic && pChar->m_pArea )
			{
				if ( ( iRegionPeriodic == 2 ) && IsTrigUsed(TRIGGER_REGPERIODIC))
				{
					pChar->m_pArea->OnRegionTrigger( pChar, RTRIG_REGPERIODIC );
					--iRegionPeriodic;
				}
				if ( IsTrigUsed(TRIGGER_CLIPERIODIC) )
					pChar->m_pArea->OnRegionTrigger( pChar, RTRIG_CLIPERIODIC );
			}
		}

		EXC_CATCHSUB("Sector");

		EXC_DEBUGSUB_START;
		CPointMap pt = GetBasePoint();
		g_Log.EventDebug("#0 char 0%x '%s'\n", (dword)(pChar->GetUID()), pChar->GetName());
		g_Log.EventDebug("#0 sector #%d [%d,%d,%d,%d]\n", GetIndex(),  pt.m_x, pt.m_y, pt.m_z, pt.m_map);
		EXC_DEBUGSUB_END;
	}

	ProfileTask overheadTask(PROFILE_OVERHEAD);

	EXC_SET_BLOCK("check map cache");
	if (fCanSleep && m_iMapBlockCacheTime < iCurTime)     // Only if the sector can sleep.
	{
		// delete the static CServerMapBlock items that have not been used recently.
		m_iMapBlockCacheTime = CServerTime::GetCurrentTime().GetTimeRaw() + g_Cfg.m_iMapCacheTime ;
		CheckMapBlockCache();
	}
	EXC_CATCH;

    SetTimeoutS(30);  // Sector is Awake, make it tick after 30 seconds.

	EXC_DEBUG_START;
	CPointMap pt = GetBasePoint();
	g_Log.EventError("#4 sector #%d [%hd,%hd,%hhd,%hhu]\n", GetIndex(), pt.m_x, pt.m_y, pt.m_z, pt.m_map);
	EXC_DEBUG_END;
    return true;
}
Пример #21
0
bool CScriptObj::r_WriteVal( LPCTSTR pszKey, CGString &sVal, CTextConsole * pSrc )
{
	EXC_TRY(("r_WriteVal('%s',,%x)", pszKey, pSrc));
	CScriptObj * pRef;
	if ( r_GetRef( pszKey, pRef ))
	{
		if ( pRef == NULL )	// good command but bad link.
		{
			sVal = "0";
			return true;
		}
		if ( pszKey[0] == '\0' )	// we where just testing the ref.
		{
			CObjBase *	pObj	= dynamic_cast <CObjBase *> (pRef);
			if ( pObj )
				sVal.FormatHex( (DWORD) pObj->GetUID() );
			else
				sVal.FormatVal( 1 );
			return( true );
		}
		return pRef->r_WriteVal( pszKey, sVal, pSrc );
	}

	int i = FindTableHeadSorted( pszKey, sm_szLoadKeys, COUNTOF( sm_szLoadKeys )-1 );
	if ( i < 0 )
	{
		// <dSOMEVAL> same as <eval <SOMEVAL>> to get dec from the val
		if (( *pszKey == 'd' ) || ( *pszKey == 'D' ))
		{
			LPCTSTR arg = pszKey + 1;
			if ( r_WriteVal(arg, sVal, pSrc) )
			{
				if ( !IsStrNumericDec(sVal) ) // dValue dec -> hex fix
				{
					sVal.FormatVal(ahextoi(sVal));
				}
				return true;
			}
		}
		// <r>, <r15>, <r3,15> are shortcuts to rand(), rand(15) and rand(3,15)
		else if (( *pszKey == 'r' ) || ( *pszKey == 'R' ))
		{
			char	*zTemp = Str_GetTemp();
			strcpy(zTemp, pszKey+1);

			if (( *zTemp ) &&  (( *zTemp < '0' ) || ( *zTemp > '9' )) )
				goto badcmd;

			TCHAR	*ppCmd[2];
			int		qty = Str_ParseCmds(zTemp, ppCmd, COUNTOF(ppCmd));
			int		min = 0, max = 1000;

			if ( qty == 1 ) max = atoi(ppCmd[0]);
			else if ( qty == 2 )
			{
				min = g_Exp.GetVal(ppCmd[0]);
				max = g_Exp.GetVal(ppCmd[1]);
			}

			if ( min > max )
			{
				int a = min;
				min = max;
				max = a;
			}
			if ( min == max )
				sVal.FormatVal(min);
			else
				sVal.FormatVal(min + Calc_GetRandVal(max - min));

			return true;
		}
badcmd:
		return false;	// Bad command.
	}

	pszKey += strlen( sm_szLoadKeys[i] );
	SKIP_SEPERATORS(pszKey);
	bool	fZero	= false;

	switch ( i )
	{
	case SSC_LISTCOL:
		// Set the alternating color.
		sVal = (CWebPageDef::sm_iListIndex&1) ? "bgcolor=\"#E8E8E8\"" : "";
		return( true );
	case SSC_OBJ:
		if ( !g_World.m_uidObj.ObjFind() ) g_World.m_uidObj = 0;
		sVal.FormatHex((DWORD)g_World.m_uidObj);
		return true;
	case SSC_NEW:
		if ( !g_World.m_uidNew.ObjFind() ) g_World.m_uidNew = 0;
		sVal.FormatHex((DWORD)g_World.m_uidNew);
		return true;
	case SSC_SRC:
		if ( pSrc == NULL )
			pRef	= NULL;
		else
		{
			pRef = pSrc->GetChar();	// if it can be converted .
			if ( ! pRef )
				pRef = dynamic_cast <CScriptObj*> (pSrc);	// if it can be converted .
		}
		if ( ! pRef )
		{
			sVal.FormatVal( 0 );
			return true;
		}
		if ( !*pszKey )
		{
			CObjBase * pObj = dynamic_cast <CObjBase*> (pRef);	// if it can be converted .
			sVal.FormatHex( pObj ? (DWORD) pObj->GetUID() : 0 );
			return true;
		}
		return pRef->r_WriteVal( pszKey, sVal, pSrc );
	case SSC_VAR0:
		fZero	= true;
	case SSC_VAR:
		// "VAR." = get/set a system wide variable.
		{
			CVarDefBase * pVar = g_Exp.m_VarGlobals.GetKey(pszKey);
			if ( pVar )
				sVal	= pVar->GetValStr();
			else if ( fZero )
				sVal	= "0";
		}
		return true;
	case SSC_DEF0:
		fZero	= true;
	case SSC_DEF:
		{
			CVarDefBase * pVar = g_Exp.m_VarDefs.GetKey(pszKey);
			if ( pVar )
				sVal	= pVar->GetValStr();
			else if ( fZero )
				sVal	= "0";
		}
		return( true );
	case SSC_EVAL:
		sVal.FormatVal( Exp_GetVal( pszKey ));
		return( true );
	case SSC_FVAL:
		{
		int	iVal		= Exp_GetVal( pszKey );
		sVal.Format( "%i.%i", iVal/10, abs(iVal%10) );
		return true;
		}
	case SSC_HVAL:
		sVal.FormatHex( Exp_GetVal( pszKey ));
		return( true );
	case SSC_QVAL:
		{	// Do a switch ? type statement <QVAL conditional ? option1 : option2>
			TCHAR * ppCmds[3];
			ppCmds[0] = const_cast<TCHAR*>(pszKey);
			Str_Parse( ppCmds[0], &(ppCmds[1]), "?" );
			Str_Parse( ppCmds[1], &(ppCmds[2]), ":" );
			sVal = ppCmds[ Exp_GetVal( ppCmds[0] ) ? 1 : 2 ];
			if ( sVal.IsEmpty())
				sVal = " ";
		}
		return( true );
	case SSC_ISEMPTY:
		sVal.FormatVal( IsStrEmpty( pszKey ) );
		return true;
	case SSC_ISNUM:
		GETNONWHITESPACE( pszKey );
		sVal.FormatVal( IsStrNumeric( pszKey ) );
		return true;
	case SSC_StrRev:
		{
			GETNONWHITESPACE( pszKey );
			sVal = pszKey;
			sVal.Reverse();
			return true;
		}
	case SSC_StrPos:
		{
			GETNONWHITESPACE( pszKey );
			int	iPos	= Exp_GetVal( pszKey );
			TCHAR	ch;
			if ( isdigit( *pszKey) && isdigit( *(pszKey+1) ) )
				ch	= (TCHAR) Exp_GetVal( pszKey );
			else
			{
				ch	= *pszKey;
				pszKey++;
			}
			
			GETNONWHITESPACE( pszKey );
			int	iLen	= strlen( pszKey );
			if ( iPos < 0 )
				iPos	= iLen + iPos;
			if ( iPos < 0 )
				iPos	= 0;
			else if ( iPos > iLen )
				iPos	= iLen;

			TCHAR *	pszPos	= strchr( pszKey + iPos, ch );
			if ( !pszPos )
				sVal.FormatVal( -1 );
			else
				sVal.FormatVal( pszPos - pszKey );
		}
		return true;
	case SSC_StrSub:
		{
			int	iPos	= Exp_GetVal( pszKey );
			int	iCnt	= Exp_GetVal( pszKey );
			SKIP_ARGSEP( pszKey );
			GETNONWHITESPACE( pszKey );

			int	iLen	= strlen( pszKey );
			if ( iPos < 0 ) iPos += iLen;
			if ( iPos > iLen || iPos < 0 ) iPos = 0;

			if ( iPos + iCnt > iLen || iCnt == 0 )
				iCnt = iLen - iPos;

			TCHAR	*buf = Str_GetTemp();
			strncpy( buf, pszKey + iPos, iCnt );
			buf[iCnt] = '\0';
			sVal = buf;
		}
		return true;
	case SSC_StrArg:
		{
			TCHAR	*buf = Str_GetTemp();
			GETNONWHITESPACE( pszKey );
			if ( *pszKey == '"' )
				pszKey++;
			int	i	= 0;
			while ( *pszKey && !isspace( *pszKey ) && *pszKey != ',' )
			{
				buf[i]	= *pszKey;
				pszKey++;
				i++;
			}
			buf[i]	= '\0';
			sVal	= buf;
		}
		return true;
	case SSC_StrEat:
		{
			GETNONWHITESPACE( pszKey );
			while ( *pszKey && !isspace( *pszKey ) && *pszKey != ',' )
				pszKey++;
			SKIP_ARGSEP( pszKey );
			sVal	= pszKey;
		}
		return true;
	case SSC_ASC:
		{
			TCHAR	*buf = Str_GetTemp();
			REMOVE_QUOTES( pszKey );
			sVal.FormatHex( *pszKey );
			sprintf( buf, sVal );
			while ( *(++pszKey) )
			{
				if ( *pszKey == '"' ) break;
				sVal.FormatHex( *pszKey );
				strcat( buf, " " );
				strcat( buf, sVal );
			}
			sVal	= buf;
		}
		return true;

	case SSC_READFILE:
		{
			if ( !IsSetOF( OF_FileCommands ) ) 
				return false;

			TCHAR	*rfArgs[1];
			FILE	*rfFD;
			TCHAR	*buf = Str_GetTemp();

			int line;

			rfArgs[0] = const_cast<TCHAR*>(pszKey);
			Str_Parse( rfArgs[0], &(rfArgs[1]), " " );

			// Remove other junk
			Str_Parse( rfArgs[1], NULL, " " );

			line = atoi( rfArgs[1] );

			sVal = "";
			if ( rfFD = fopen( rfArgs[0], "r" ))
			{
				if ( line == -1 )	// First line of the file
					fgets(buf, SCRIPT_MAX_LINE_LEN, rfFD );
				else if ( line == 0 )
				{
					// Last line of the file
					while ( ! feof( rfFD ) )
						fgets(buf, SCRIPT_MAX_LINE_LEN, rfFD );
				}					
				else
				{
					// Line "line" of the file
					int x;
					for ( x = 1; x <= line; x++ )
					{
						if ( feof(rfFD) )
						{
							buf[0] = 0;
							break;
						}
						fgets(buf, SCRIPT_MAX_LINE_LEN, rfFD );
					}
				}
				sVal = buf;
				fclose(rfFD);
			}
		}
		return true;
	case SSC_FILELINES:
		{
			if ( !IsSetOF( OF_FileCommands ) )
				return false;
			
			TCHAR	*buf = Str_GetTemp();
			FILE	*flFD;
			int		x(0);
			GETNONWHITESPACE( pszKey );
			if ( flFD = fopen( pszKey, "r" ) )
			{
				while ( ! feof(flFD) )
				{
					fgets(buf, SCRIPT_MAX_LINE_LEN, flFD );
					x++;
				}
				fclose(flFD);
			}
			sVal.FormatVal(x);
		}
		return true;
	case SSC_SYSCMD:
	case SSC_SYSSPAWN:
		{
			if ( !IsSetOF(OF_FileCommands) )
				return false;

			GETNONWHITESPACE(pszKey);
			TCHAR	*buf = Str_GetTemp();
			TCHAR	*Arg_ppCmd[10];		// limit to 9 arguments
			strcpy(buf, pszKey);
			int iQty = Str_ParseCmds(buf, Arg_ppCmd, COUNTOF(Arg_ppCmd));
			if ( iQty < 1 )
				return false;

#ifdef WIN32
			_spawnl(
				( i == SSC_SYSCMD ) ? _P_WAIT : _P_NOWAIT,
				Arg_ppCmd[0],
				Arg_ppCmd[0],
				Arg_ppCmd[1],
				Arg_ppCmd[2],
				Arg_ppCmd[3],
				Arg_ppCmd[4],
				Arg_ppCmd[5],
				Arg_ppCmd[6],
				Arg_ppCmd[7],
				Arg_ppCmd[8],
				Arg_ppCmd[9],
				NULL
			);
#else
			g_Log.EventError("sysspawn/syscmd is not available on unix builds." DEBUG_CR);
#endif
			return true;
		}

	default:
		StringFunction( i, pszKey, sVal );
		return true;
	}
	EXC_CATCH("CScriptObj");
	return false;
}
Пример #22
0
TRIGRET_TYPE CScriptObj::OnTriggerRun( CScript &s, TRIGRUN_TYPE trigrun, CTextConsole * pSrc, CScriptTriggerArgs * pArgs, CGString * pResult )
{
	// ARGS:
	//	TRIGRUN_SECTION_SINGLE = just this 1 line.
	// RETURN:
	//  TRIGRET_RET_FALSE = 0 = return and continue processing.
	//  TRIGRET_RET_TRUE = 1 = return and handled. (halt further processing)
	//  TRIGRET_RET_DEFAULT = 2 = if process returns nothing specifically.

	// CScriptFileContext set g_Log.m_pObjectContext is the current context (we assume)
	// DEBUGCHECK( this == g_Log.m_pObjectContext );

	static LPCTSTR const m_ExcKeys[] =
	{
		"parsing",
		"parsing IF statement",
		"parsing begin/loop cycle",
		"foritem",
		"forchar",
		"forclients",
		"forobjs",
		"forplayers",
		"for",
		"while",
		"forcharlayer/memorytype",
		"forcont",
		"forcontid/type",
		"dorand/doswitch",
		"return",
		"CALLing a subfunction",
		"VERBing a value",
	};

	#ifdef WIN32
		EXC_TRY(("OnTriggerRun(%x,%i,%x,%x,%x)", s.GetKey(), trigrun, pSrc, pArgs, pResult));
	#else
		EXC_TRY(("OnTriggerRun(??,%i,%x,%x,%x)", trigrun, pSrc, pArgs, pResult));
	#endif
	
	bool fSectionFalse = (trigrun == TRIGRUN_SECTION_FALSE || trigrun == TRIGRUN_SINGLE_FALSE);
	if ( trigrun == TRIGRUN_SECTION_EXEC || trigrun == TRIGRUN_SINGLE_EXEC )	// header was already read in.
		goto jump_in;

	EXC_SET(m_ExcKeys[0]);
	while ( s.ReadKeyParse())
	{
		// Hit the end of the next trigger.
		if ( s.IsKeyHead( "ON", 2 ))	// done with this section.
			break;

jump_in:
		SK_TYPE iCmd = (SK_TYPE) FindTableSorted( s.GetKey(), sm_szScriptKeys, COUNTOF( sm_szScriptKeys )-1 );
		TRIGRET_TYPE iRet;

		switch ( iCmd )
		{
		case SK_ENDIF:
		case SK_END:
		case SK_ENDDO:
		case SK_ENDFOR:
		case SK_ENDRAND:
		case SK_ENDSWITCH:
		case SK_ENDWHILE:
			return( TRIGRET_ENDIF );

		case SK_ELIF:
		case SK_ELSEIF:
			return( TRIGRET_ELSEIF );

		case SK_ELSE:
			return( TRIGRET_ELSE );
		}

		if ( fSectionFalse )
		{
			// Ignoring this whole section. don't bother parsing it.
			switch ( iCmd )
			{
			case SK_IF:
				EXC_SET(m_ExcKeys[1]);
				do
				{
					iRet = OnTriggerRun( s, TRIGRUN_SECTION_FALSE, pSrc, pArgs, pResult );
				} while ( iRet == TRIGRET_ELSEIF || iRet == TRIGRET_ELSE );
				break;
			case SK_WHILE:
			case SK_FOR:
			case SK_FORCHARLAYER:
			case SK_FORCHARMEMORYTYPE:
			case SK_FORCHAR:
			case SK_FORCLIENTS:
			case SK_FORCONT:
			case SK_FORCONTID:
			case SK_FORCONTTYPE:
			case SK_FORITEM:
			case SK_FOROBJ:
			case SK_FORPLAYERS:
			case SK_DORAND:
			case SK_DOSWITCH:
			case SK_BEGIN:
				EXC_SET(m_ExcKeys[2]);
				iRet = OnTriggerRun( s, TRIGRUN_SECTION_FALSE, pSrc, pArgs, pResult );
				break;
			}
			if ( trigrun >= TRIGRUN_SINGLE_EXEC )
				return( TRIGRET_RET_DEFAULT );
			continue;	// just ignore it.
		}

		switch ( iCmd )
		{
		case SK_FORITEM:	EXC_SET(m_ExcKeys[3]); iRet = OnTriggerForLoop( s, 1, pSrc, pArgs, pResult );			break;
		case SK_FORCHAR:	EXC_SET(m_ExcKeys[4]); iRet = OnTriggerForLoop( s, 2, pSrc, pArgs, pResult );			break;
		case SK_FORCLIENTS:	EXC_SET(m_ExcKeys[5]); iRet = OnTriggerForLoop( s, 0x12, pSrc, pArgs, pResult );		break;
		case SK_FOROBJ:		EXC_SET(m_ExcKeys[6]); iRet = OnTriggerForLoop( s, 3, pSrc, pArgs, pResult );			break;
		case SK_FORPLAYERS:	EXC_SET(m_ExcKeys[7]); iRet = OnTriggerForLoop( s, 0x22, pSrc, pArgs, pResult );		break;
		case SK_FOR:		EXC_SET(m_ExcKeys[8]); iRet = OnTriggerForLoop( s, 4, pSrc, pArgs, pResult );			break;
		case SK_WHILE:		EXC_SET(m_ExcKeys[9]); iRet = OnTriggerForLoop( s, 8, pSrc, pArgs, pResult );			break;
		case SK_FORCHARLAYER:
		case SK_FORCHARMEMORYTYPE:
			{
				EXC_SET(m_ExcKeys[10]);
				CChar * pCharThis = dynamic_cast <CChar *> (this);
				if ( pCharThis )
				{
					if ( s.HasArgs() )
					{
						if ( iCmd == SK_FORCHARLAYER )
							iRet = pCharThis->OnCharTrigForLayerLoop( s, pSrc, pArgs, pResult, (LAYER_TYPE) s.GetArgVal() );
						else
							iRet = pCharThis->OnCharTrigForMemTypeLoop( s, pSrc, pArgs, pResult, s.GetArgVal() );
						break;
					}
				}
			}
		case SK_FORCONT:
			{
				EXC_SET(m_ExcKeys[11]);
				if ( s.HasArgs() )
				{
					TCHAR * ppArgs[2];
					TCHAR * tempPoint;
					TCHAR 	*porigValue = Str_GetTemp();
					
					int iArgQty = Str_ParseCmds( (TCHAR*) s.GetArgRaw(), ppArgs, COUNTOF(ppArgs), " \t," );
					
					if ( iArgQty >= 1 )
					{
						strcpy(porigValue, ppArgs[0]);
						tempPoint = porigValue;
						ParseText( tempPoint, pSrc, 0, pArgs );
						
						CGrayUID pCurUid = (DWORD) Exp_GetVal(tempPoint);
						if ( pCurUid.IsValidUID() )
						{
							CObjBase * pObj = pCurUid.ObjFind();
							if ( pObj && pObj->IsContainer() )
							{
								CContainer * pContThis = dynamic_cast <CContainer *> (pObj);
								
								CScriptLineContext StartContext = s.GetContext();
								CScriptLineContext EndContext = StartContext;
								iRet = pContThis->OnGenericContTriggerForLoop( s, pSrc, pArgs, pResult, StartContext, EndContext, ppArgs[1] != NULL ? Exp_GetVal(ppArgs[1]) : 255 );
								break;
							}
						}
					}
				}
			}
		case SK_FORCONTID:
		case SK_FORCONTTYPE:
			{
				EXC_SET(m_ExcKeys[12]);
				CContainer * pCont = dynamic_cast <CContainer *> (this);
				if ( pCont )
				{
					if ( s.HasArgs() )
					{
						LPCTSTR pszKey = s.GetArgRaw();
						SKIP_SEPERATORS(pszKey);
					
						TCHAR * ppArgs[2];
						Str_ParseCmds( (TCHAR*) pszKey, ppArgs, COUNTOF(ppArgs), " \t," );

						CScriptLineContext StartContext = s.GetContext();
						CScriptLineContext EndContext = StartContext;
#ifdef _WIN32
						iRet = pCont->OnContTriggerForLoop( s, pSrc, pArgs, pResult, StartContext, EndContext, g_Cfg.ResourceGetID( ( iCmd == SK_FORCONTID ) ? RES_ITEMDEF : RES_TYPEDEF, ppArgs[0] ), 0, ppArgs[1] != NULL ? Exp_GetVal( ppArgs[1] ) : 255 );
#else
						iRet = pCont->OnContTriggerForLoop( s, pSrc, pArgs, pResult, StartContext, EndContext, g_Cfg.ResourceGetID( ( iCmd == SK_FORCONTID ) ? RES_ITEMDEF : RES_TYPEDEF, (const char*&) ppArgs[0] ), 0, ppArgs[1] != NULL ? Exp_GetVal( ppArgs[1] ) : 255 );
#endif
						break;
					}
				}
			}
		default:
			// Parse out any variables in it. (may act like a verb sometimes?)
			EXC_SET(m_ExcKeys[0]);
			ParseText( s.GetArgRaw(), pSrc, 0, pArgs );
		}

		switch ( iCmd )
		{
		case SK_FORITEM:
		case SK_FORCHAR:
		case SK_FORCHARLAYER:
		case SK_FORCHARMEMORYTYPE:
		case SK_FORCLIENTS:
		case SK_FORCONT:
		case SK_FORCONTID:
		case SK_FORCONTTYPE:
		case SK_FOROBJ:
		case SK_FORPLAYERS:
		case SK_FOR:
		case SK_WHILE:
			if ( iRet != TRIGRET_ENDIF )
			{
				if ( iRet > TRIGRET_RET_DEFAULT )
				{
					DEBUG_MSG(( "WARNING: Trigger Bad For Ret %d '%s','%s'\n", iRet, s.GetKey(), s.GetArgStr()));
				}
				return( iRet );
			}
			break;
		case SK_DORAND:	// Do a random line in here.
		case SK_DOSWITCH:
			{
			EXC_SET(m_ExcKeys[13]);
			int iVal = s.GetArgVal();
			if ( iCmd == SK_DORAND )
				iVal = Calc_GetRandVal(iVal);
			for ( ;true; iVal-- )
			{
				iRet = OnTriggerRun( s, (!iVal) ? TRIGRUN_SINGLE_TRUE : TRIGRUN_SINGLE_FALSE, pSrc, pArgs, pResult );
				if ( iRet == TRIGRET_RET_DEFAULT )
					continue;
				if ( iRet == TRIGRET_ENDIF )
					break;
				if ( iRet > TRIGRET_RET_DEFAULT )
				{
					DEBUG_MSG(( "WARNING: Trigger Bad Ret %d '%s','%s'\n", iRet, s.GetKey(), s.GetArgStr()));
				}
				return( iRet );
			}
			}
			break;
		case SK_RETURN:		// Process the trigger.
			EXC_SET(m_ExcKeys[14]);
			if ( pResult )
			{
				pResult->Copy( s.GetArgStr() );
				return (TRIGRET_TYPE) 1;
			}
			return ( (TRIGRET_TYPE) s.GetArgVal() );
		case SK_IF:
			{
				EXC_SET(m_ExcKeys[1]);
				bool fTrigger = s.GetArgVal() ? true : false;
				bool fBeenTrue = false;
				while (true)
				{
					iRet = OnTriggerRun( s, fTrigger ? TRIGRUN_SECTION_TRUE : TRIGRUN_SECTION_FALSE, pSrc, pArgs, pResult );
					if ( iRet < TRIGRET_ENDIF )
						return( iRet );
					if ( iRet == TRIGRET_ENDIF )
						break;
					fBeenTrue |= fTrigger;
					if ( fBeenTrue )
						fTrigger = false;
					else if ( iRet == TRIGRET_ELSE )
						fTrigger = true;
					else if ( iRet == TRIGRET_ELSEIF )
					{
						ParseText( s.GetArgStr(), pSrc, 0, pArgs );
						fTrigger = s.GetArgVal() ? true : false;
					}
				}
			}
			break;

		case SK_BEGIN:
			// Do this block here.
			{
				EXC_SET(m_ExcKeys[2]);
				iRet = OnTriggerRun( s, TRIGRUN_SECTION_TRUE, pSrc, pArgs, pResult );
				if ( iRet != TRIGRET_ENDIF )
				{
					if ( iRet > TRIGRET_RET_DEFAULT )
					{
						DEBUG_MSG(( "WARNING: Trigger Bad Ret %d '%s','%s'\n", iRet, s.GetKey(), s.GetArgStr()));
					}
					return( iRet );
				}
			}
			break;

		default:
			if ( IsSetEF( EF_Scripts_Parse_Verbs ) )
			{
				EXC_SET(m_ExcKeys[0]);
				ParseText( s.GetKeyBuffer(), pSrc, 0, pArgs );
			}
			EXC_SET(m_ExcKeys[0]);
			if ( pArgs && pArgs->r_Verb( s, pSrc ) )
				;
			else
			{
				bool	fRes;
				if ( !strcmpi( (char *)s.GetKey(), "call" ) )
				{
					EXC_SET(m_ExcKeys[15]);
					LPCTSTR	pszArgs	= strchr( s.GetArgRaw(), ' ' );
					if ( pszArgs )
						GETNONWHITESPACE( pszArgs );
					if ( !pszArgs || !*pszArgs )
					{
						fRes	= this->r_Call( s.GetArgRaw(), pSrc, pArgs );
					}
					else
					{
						CScriptTriggerArgs	Args( pszArgs );
						if ( pArgs )
							Args.m_VarsLocal	= pArgs->m_VarsLocal;
						fRes	= this->r_Call( s.GetArgRaw(), pSrc, &Args );
						if ( pArgs )
							pArgs->m_VarsLocal	= Args.m_VarsLocal;
					}
				}
				else
				{
					EXC_SET(m_ExcKeys[16]);
					fRes	= r_Verb( s, pSrc );
				}

				if ( !fRes  )
				{
					DEBUG_MSG(( "WARNING: Trigger Bad Verb '%s','%s'\n", s.GetKey(), s.GetArgStr()));
				}
			}
			break;
		}

		if ( trigrun >= TRIGRUN_SINGLE_EXEC )
			return( TRIGRET_RET_DEFAULT );
	}
	EXC_CATCH("running trigger line");
	return( TRIGRET_RET_DEFAULT );
}
Пример #23
0
BYTE CSector::GetLightCalc( bool fQuickSet ) const
{
	ADDTOCALLSTACK("CSector::GetLightCalc");
	// What is the light level default here in this sector.

	if ( g_Cfg.m_bAllowLightOverride && IsLightOverriden() )
		return m_Env.m_Light;

	if ( IsInDungeon() )
		return static_cast<unsigned char>(g_Cfg.m_iLightDungeon);

	int localtime = GetLocalTime();

	if ( !g_Cfg.m_bAllowLightOverride )
	{
		//	Normalize time:
		//	convert	0=midnight	.. (23*60)+59=midnight
		//	to		0=day		.. 12*60=night
		if ( localtime < 12*60 )
			localtime = 12*60 - localtime;
		else
			localtime -= 12*60;

		//	0...	y	...lightnight
		//	0...	x	...12*60
		int iTargLight = ((localtime * ( g_Cfg.m_iLightNight - g_Cfg.m_iLightDay ))/(12*60) + g_Cfg.m_iLightDay);

		if ( iTargLight < LIGHT_BRIGHT ) iTargLight = LIGHT_BRIGHT;
		if ( iTargLight > LIGHT_DARK ) iTargLight = LIGHT_DARK;

		return static_cast<unsigned char>(iTargLight);
	}

	int hour = ( localtime / ( 60)) % 24;
	bool fNight = ( hour < 6 || hour > 12+8 );	// Is it night or day ?
	int iTargLight = (fNight) ? g_Cfg.m_iLightNight : g_Cfg.m_iLightDay;	// Target light level.

	// Check for clouds...if it is cloudy, then we don't even need to check for the effects of the moons...
	if ( GetWeather())
	{
		// Clouds of some sort...
		if (fNight)
			iTargLight += ( Calc_GetRandVal( 2 ) + 1 );	// 1-2 light levels darker if cloudy at night
		else
			iTargLight += ( Calc_GetRandVal( 4 ) + 1 );	// 1-4 light levels darker if cloudy during the day.
	}

	if ( fNight )
	{
		// Factor in the effects of the moons
		// Trammel
		unsigned int iTrammelPhase = g_World.GetMoonPhase( false );
		// Check to see if Trammel is up here...

		if ( IsMoonVisible( iTrammelPhase, localtime ))
		{
static const BYTE sm_TrammelPhaseBrightness[] =
{
	0, // New Moon
	TRAMMEL_FULL_BRIGHTNESS / 4,	// Crescent Moon
	TRAMMEL_FULL_BRIGHTNESS / 2, 	// Quarter Moon
	( TRAMMEL_FULL_BRIGHTNESS * 3) / 4, // Gibbous Moon
	TRAMMEL_FULL_BRIGHTNESS,		// Full Moon
	( TRAMMEL_FULL_BRIGHTNESS * 3) / 4, // Gibbous Moon
	TRAMMEL_FULL_BRIGHTNESS / 2, 	// Quarter Moon
	TRAMMEL_FULL_BRIGHTNESS / 4		// Crescent Moon
};
			ASSERT( iTrammelPhase < COUNTOF(sm_TrammelPhaseBrightness));
			iTargLight -= sm_TrammelPhaseBrightness[iTrammelPhase];
		}

		// Felucca
		unsigned int iFeluccaPhase = g_World.GetMoonPhase( true );
		if ( IsMoonVisible( iFeluccaPhase, localtime ))
		{
static const BYTE sm_FeluccaPhaseBrightness[] =
{
	0, // New Moon
	FELUCCA_FULL_BRIGHTNESS / 4,	// Crescent Moon
	FELUCCA_FULL_BRIGHTNESS / 2, 	// Quarter Moon
	( FELUCCA_FULL_BRIGHTNESS * 3) / 4, // Gibbous Moon
	FELUCCA_FULL_BRIGHTNESS,		// Full Moon
	( FELUCCA_FULL_BRIGHTNESS * 3) / 4, // Gibbous Moon
	FELUCCA_FULL_BRIGHTNESS / 2, 	// Quarter Moon
	FELUCCA_FULL_BRIGHTNESS / 4		// Crescent Moon
};
			ASSERT( iFeluccaPhase < COUNTOF(sm_FeluccaPhaseBrightness));
			iTargLight -= sm_FeluccaPhaseBrightness[iFeluccaPhase];
		}
	}

	if ( iTargLight < LIGHT_BRIGHT ) iTargLight = LIGHT_BRIGHT;
	if ( iTargLight > LIGHT_DARK ) iTargLight = LIGHT_DARK;

	if ( fQuickSet || m_Env.m_Light == iTargLight )		// Initializing the sector
		return static_cast<unsigned char>(iTargLight);

	// Gradual transition to global light level.
	if ( m_Env.m_Light > iTargLight )
		return( m_Env.m_Light - 1 );
	else
		return( m_Env.m_Light + 1 );
}
Пример #24
0
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;
}
Пример #25
0
void CSector::OnTick(int iPulseCount)
{
	ADDTOCALLSTACK_INTENSIVE("CSector::OnTick");
	// CWorld gives OnTick() to all CSectors.

	EXC_TRY("Tick");
	EXC_SET("light change");

	//	do not tick sectors on maps not supported by server
	if ( !g_MapList.m_maps[m_map] ) return;

	// Check for light change before putting the sector to sleep, since in other case the
	// world light levels will be shitty
	bool fEnvironChange = false;
	bool fLightChange = false;
	bool fSleeping = false;

	if ( ! ( iPulseCount & 0x7f ))	// 30 seconds or so.
	{
		// check for local light level change ?
		BYTE blightprv = m_Env.m_Light;
		m_Env.m_Light = GetLightCalc( false );
		if ( m_Env.m_Light != blightprv )
		{
			fEnvironChange = true;
			fLightChange = true;
		}
	}

	EXC_SET("sector sleeping?");
	size_t clients = m_Chars_Active.HasClients();

	if ( clients <= 0 ) // having no clients inside
	{
		// Put the sector to sleep if no clients been here in a while.
		fSleeping = IsSectorSleeping();
		if ( fSleeping )
		{
			if ( !g_Cfg.m_iSectorSleepMask )
				return;
			if (( iPulseCount & g_Cfg.m_iSectorSleepMask ) != ( GetIndex() & g_Cfg.m_iSectorSleepMask ))
				return;
		}
	}

	EXC_SET("sound effects");
	// random weather noises and effects.
	SOUND_TYPE sound = 0;
	bool fWeatherChange = false;
	int iRegionPeriodic = 0;

	if ( ! ( iPulseCount & 0x7f ))	// 30 seconds or so.
	{
		// Only do this every x minutes or so (TICK_PER_SEC)
		// check for local weather change ?
		WEATHER_TYPE weatherprv = m_Env.m_Weather;
		if ( ! Calc_GetRandVal( 30 ))	// change less often
		{
			m_Env.m_Weather = GetWeatherCalc();
			if ( weatherprv != m_Env.m_Weather )
			{
				fWeatherChange = true;
				fEnvironChange = true;
			}
		}

		// Random area noises. Only do if clients about.
		if ( clients > 0 )
		{
			iRegionPeriodic = 2;

			static const SOUND_TYPE sm_SfxRain[] = { 0x10, 0x11 };
			static const SOUND_TYPE sm_SfxWind[] = { 0x14, 0x15, 0x16 };
			static const SOUND_TYPE sm_SfxThunder[] = { 0x28, 0x29 , 0x206 };

			// Lightning ?	// wind, rain,
			switch ( GetWeather() )
			{
				case WEATHER_CLOUDY:
					break;

				case WEATHER_SNOW:
					if ( ! Calc_GetRandVal(5) )
						sound = sm_SfxWind[ Calc_GetRandVal( COUNTOF( sm_SfxWind )) ];
					break;

				case WEATHER_RAIN:
					{
						int iVal = Calc_GetRandVal(30);
						if ( iVal < 5 )
						{
							// Mess up the light levels for a sec..
							LightFlash();
							sound = sm_SfxThunder[ Calc_GetRandVal( COUNTOF( sm_SfxThunder )) ];
						}
						else if ( iVal < 10 )
							sound = sm_SfxRain[ Calc_GetRandVal( COUNTOF( sm_SfxRain )) ];
						else if ( iVal < 15 )
							sound = sm_SfxWind[ Calc_GetRandVal( COUNTOF( sm_SfxWind )) ];
					}
					break;

				default:
					break;
			}
		}
	}

	// regen all creatures and do AI

	ProfileTask charactersTask(PROFILE_CHARS);

	//pChar = STATIC_CAST <CChar*>( m_Chars_Active.GetHead());
	CChar * pCharNext = NULL;
	CChar * pChar = dynamic_cast <CChar*>( m_Chars_Active.GetHead());
	for ( ; pChar != NULL; pChar = pCharNext )
	{
		EXC_TRYSUB("TickChar");

		pCharNext = pChar->GetNext();
		if (( fEnvironChange ) && ( IsTrigUsed(TRIGGER_ENVIRONCHANGE) ))
			pChar->OnTrigger(CTRIG_EnvironChange, pChar);

		if ( pChar->IsClient())
		{
			CClient * pClient = pChar->GetClient();
			ASSERT( pClient );
			if ( sound )
				pClient->addSound(sound, pChar);

			if ( fLightChange && ! pChar->IsStatFlag( STATF_DEAD | STATF_NightSight ))
				pClient->addLight();

			if ( fWeatherChange )
				pClient->addWeather(GetWeather());

			if ( iRegionPeriodic && pChar->m_pArea )
			{
				if (( iRegionPeriodic == 2 )&&( IsTrigUsed(TRIGGER_REGPERIODIC) ))
				{
					pChar->m_pArea->OnRegionTrigger( pChar, RTRIG_REGPERIODIC );
					iRegionPeriodic--;
				}
				if ( IsTrigUsed(TRIGGER_CLIPERIODIC) )
					pChar->m_pArea->OnRegionTrigger( pChar, RTRIG_CLIPERIODIC );
			}
		}
		// Can only die on your own tick.
		if ( !pChar->OnTick() )
			pChar->Delete();

		EXC_CATCHSUB("Sector");

		EXC_DEBUGSUB_START;
		CPointMap pt = GetBasePoint();
		g_Log.EventDebug("char 0%lx '%s'\n", static_cast<DWORD>(pChar->GetUID()), pChar->GetName());
		g_Log.EventDebug("sector #%d [%d,%d,%d,%d]\n", GetIndex(),  pt.m_x, pt.m_y, pt.m_z, pt.m_map);
		EXC_DEBUGSUB_END;
	}

	// decay items on ground = time out spells / gates etc.. etc..
	// No need to check these so often !

	ProfileTask itemsTask(PROFILE_ITEMS);

	CItem * pItemNext = NULL;
	CItem * pItem = dynamic_cast <CItem*>( m_Items_Timer.GetHead());
	for ( ; pItem != NULL; pItem = pItemNext )
	{
		EXC_TRYSUB("TickItem");
		pItemNext = pItem->GetNext();

		EXC_SETSUB("TimerExpired");
		if ( pItem->IsTimerExpired() )
		{
			EXC_SETSUB("ItemTick");
			if ( !pItem->OnTick() )
			{
				EXC_SETSUB("ItemDelete");
				pItem->Delete();
			}
			else
			{
				EXC_SETSUB("TimerExpired2");
				if ( pItem->IsTimerExpired() )	// forgot to clear the timer.? strange.
				{
					EXC_SETSUB("SetTimeout");
					pItem->SetTimeout(-1);
				}
			}
		}

		EXC_SETSUB("UpdateFlags");
		pItem->OnTickStatusUpdate();

#ifdef _WIN32
		EXC_CATCHSUB("Sector");

		EXC_DEBUGSUB_START;
		CPointMap pt = GetBasePoint();
		g_Log.EventError("item 0%lx '%s' [timer=%lld, type=%lld]\n", static_cast<DWORD>(pItem->GetUID()), pItem->GetName(), pItem->GetTimerAdjusted(), static_cast<int>(pItem->GetType()));
		g_Log.EventError("sector #%d [%d,%d,%d,%d]\n", GetIndex(),  pt.m_x, pt.m_y, pt.m_z, pt.m_map);
		
		EXC_DEBUGSUB_END;
#else
		}
#ifndef _DEBUG
		catch ( const CGrayError& e )
Пример #26
0
bool CChar::Use_Item_Web( CItem * pItemWeb )
{
	ADDTOCALLSTACK("CChar::Use_Item_Web");
	// IT_WEB
	// IT_EQ_STUCK
	// Try to break out of the web.
	// Or just try to damage it.
	//
	// RETURN: true = held in place.
	//  false = walk thru it.

	if ( GetDispID() == CREID_GIANT_SPIDER || !pItemWeb || !pItemWeb->IsTopLevel() || IsStatFlag(STATF_DEAD|STATF_Insubstantial) || IsPriv(PRIV_GM) )
		return false;	// just walk through it

	// Try to break it.
	int iStr = pItemWeb->m_itWeb.m_Hits_Cur;
	if ( iStr == 0 )
		iStr = pItemWeb->m_itWeb.m_Hits_Cur = 60 + Calc_GetRandVal(250);

	// Since broken webs become spider silk, we should get out of here now if we aren't in a web.
	CItem *pFlag = LayerFind(LAYER_FLAG_Stuck);
	if ( CanMove(pItemWeb, false) )
	{
		if ( pFlag )
			pFlag->Delete();
		return false;
	}

	if ( pFlag )
	{
		if ( pFlag->IsTimerSet() )	// don't allow me to try to damage it too often
			return true;
	}

	int iDmg = pItemWeb->OnTakeDamage(Stat_GetAdjusted(STAT_STR), this);
	switch ( iDmg )
	{
		case 0:			// damage blocked
		case 1:			// web survived
		default:		// unknown
			if ( GetTopPoint() == pItemWeb->GetTopPoint() )		// is character still stuck on the web?
				break;

		case 2:			// web turned into silk
		case INT_MAX:	// web destroyed
			if ( pFlag )
				pFlag->Delete();
			return false;
	}

	// Stuck in it still.
	if ( !pFlag )
	{
		if ( iDmg < 0 )
			return false;

		// First time message.
		pFlag = CItem::CreateBase(ITEMID_WEB1_1);
		ASSERT(pFlag);
		pFlag->SetAttr(ATTR_DECAY);
		pFlag->SetType(IT_EQ_STUCK);
		pFlag->m_uidLink = pItemWeb->GetUID();
		pFlag->SetTimeout(pItemWeb->GetTimerDAdjusted());
		LayerAdd(pFlag, LAYER_FLAG_Stuck);
	}
	else
	{
		if ( iDmg < 0 )
		{
			pFlag->Delete();
			return false;
		}
		SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SWEB_STUCK), pItemWeb->GetName());
	}

	return true;
}
Пример #27
0
bool CChar::Use_Repair( CItem * pItemArmor )
{
	ADDTOCALLSTACK("CChar::Use_Repair");
	// Attempt to repair the item.
	// If it is repairable.

	if ( !pItemArmor || !pItemArmor->Armor_IsRepairable() )
	{
		SysMessageDefault(DEFMSG_REPAIR_NOT);
		return false;
	}

	if ( pItemArmor->IsItemEquipped() )
	{
		SysMessageDefault(DEFMSG_REPAIR_WORN);
		return false;
	}
	if ( !CanUse(pItemArmor, true) )
	{
		SysMessageDefault(DEFMSG_REPAIR_REACH);
		return false;
	}

	// Quickly use arms lore skill, but don't gain any skill until later on
	int iArmsLoreDiff = Calc_GetRandVal(30);
	if ( !Skill_UseQuick(SKILL_ARMSLORE, iArmsLoreDiff, false) )
	{
		// apply arms lore skillgain for failure
		Skill_Experience(SKILL_ARMSLORE, -iArmsLoreDiff);
		SysMessageDefault(DEFMSG_REPAIR_UNK);
		return false;
	}

	if ( pItemArmor->m_itArmor.m_Hits_Cur >= pItemArmor->m_itArmor.m_Hits_Max )
	{
		SysMessageDefault(DEFMSG_REPAIR_FULL);
		return false;
	}

	m_Act_p = g_World.FindItemTypeNearby(GetTopPoint(), IT_ANVIL, 2, false);
	if ( !m_Act_p.IsValidPoint() )
	{
		SysMessageDefault(DEFMSG_REPAIR_ANVIL);
		return false;
	}

	CItemBase *pItemDef = pItemArmor->Item_GetDef();
	ASSERT(pItemDef);

	// Use up some raw materials to repair.
	int iTotalHits = pItemArmor->m_itArmor.m_Hits_Max;
	int iDamageHits = pItemArmor->m_itArmor.m_Hits_Max - pItemArmor->m_itArmor.m_Hits_Cur;
	int iDamagePercent = IMULDIV(100, iDamageHits, iTotalHits);

	size_t iMissing = ResourceConsumePart(&(pItemDef->m_BaseResources), 1, iDamagePercent / 2, true);
	if ( iMissing != pItemDef->m_BaseResources.BadIndex() )
	{
		// Need this to repair.
		const CResourceDef *pCompDef = g_Cfg.ResourceGetDef(pItemDef->m_BaseResources.GetAt(iMissing).GetResourceID());
		SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_REPAIR_LACK_1), pCompDef ? pCompDef->GetName() : g_Cfg.GetDefaultMsg(DEFMSG_REPAIR_LACK_2));
		return false;
	}

	UpdateDir(m_Act_p);
	UpdateAnimate(ANIM_ATTACK_1H_SLASH);

	// quarter the skill to make it.
	// + more damaged items should be harder to repair.
	// higher the percentage damage the closer to the skills to make it.

	size_t iRes = pItemDef->m_SkillMake.FindResourceType(RES_SKILL);
	if ( iRes == pItemDef->m_SkillMake.BadIndex() )
		return false;

	CResourceQty RetMainSkill = pItemDef->m_SkillMake[iRes];
	int iSkillLevel = static_cast<int>(RetMainSkill.GetResQty()) / 10;
	int iDifficulty = IMULDIV(iSkillLevel, iDamagePercent, 100);
	if ( iDifficulty < iSkillLevel / 4 )
		iDifficulty = iSkillLevel / 4;

	// apply arms lore skillgain now
	LPCTSTR pszText;
	Skill_Experience(SKILL_ARMSLORE, iArmsLoreDiff);
	bool fSuccess = Skill_UseQuick(static_cast<SKILL_TYPE>(RetMainSkill.GetResIndex()), iDifficulty);
	if ( fSuccess )
	{
		pItemArmor->m_itArmor.m_Hits_Cur = static_cast<WORD>(iTotalHits);
		pszText = g_Cfg.GetDefaultMsg(DEFMSG_REPAIR_1);
	}
	else
	{
		/*****************************
		// not sure if this is working!
		******************************/
		// Failure
		if ( !Calc_GetRandVal(6) )
		{
			pszText = g_Cfg.GetDefaultMsg(DEFMSG_REPAIR_2);
			pItemArmor->m_itArmor.m_Hits_Max--;
			pItemArmor->m_itArmor.m_Hits_Cur--;
		}
		else if ( !Calc_GetRandVal(3) )
		{
			pszText = g_Cfg.GetDefaultMsg(DEFMSG_REPAIR_3);
			pItemArmor->m_itArmor.m_Hits_Cur--;
		}
		else
			pszText = g_Cfg.GetDefaultMsg( DEFMSG_REPAIR_4 );

		iDamagePercent = Calc_GetRandVal(iDamagePercent);	// some random amount
	}

	ResourceConsumePart(&(pItemDef->m_BaseResources), 1, iDamagePercent / 2, false);
	if ( pItemArmor->m_itArmor.m_Hits_Cur <= 0 )
		pszText = g_Cfg.GetDefaultMsg(DEFMSG_REPAIR_5);

	TCHAR *pszMsg = Str_GetTemp();
	sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_REPAIR_MSG), pszText, pItemArmor->GetName());
	Emote(pszMsg);

	if ( pItemArmor->m_itArmor.m_Hits_Cur <= 0 )
		pItemArmor->Delete();
	else
		pItemArmor->UpdatePropertyFlag(AUTOTOOLTIP_FLAG_DURABILITY);

	return fSuccess;
}
Пример #28
0
void CChar::Use_Drink( CItem * pItem )
{
	ADDTOCALLSTACK("CChar::Use_Drink");
	// IT_POTION:
	// IT_DRINK:
	// IT_PITCHER:
	// IT_WATER_WASH:
	// IT_BOOZE:

	if ( !CanMove(pItem) )
	{
		SysMessageDefault(DEFMSG_DRINK_CANTMOVE);
		return;
	}

	const CItemBase *pItemDef = pItem->Item_GetDef();
	ITEMID_TYPE idbottle = static_cast<ITEMID_TYPE>(RES_GET_INDEX(pItemDef->m_ttDrink.m_idEmpty));

	if ( pItem->IsType(IT_BOOZE) )
	{
		// Beer wine and liquor. vary strength of effect.
		int iAlcohol = Calc_GetRandVal(4);

		CItem *pDrunkLayer = LayerFind(LAYER_FLAG_Drunk);
		if ( !pDrunkLayer )
			pDrunkLayer = Spell_Effect_Create(SPELL_Liquor, LAYER_FLAG_Drunk, 0, 5 * TICK_PER_SEC, this);

		pDrunkLayer->m_itSpell.m_spellcharges += iAlcohol;
		if ( pDrunkLayer->m_itSpell.m_spellcharges > 60 )
			pDrunkLayer->m_itSpell.m_spellcharges = 60;
	}

	if ( pItem->IsType(IT_POTION) )
	{
		// Time limit on using potions.
		if ( LayerFind(LAYER_FLAG_PotionUsed) )
		{
			SysMessageDefault(DEFMSG_DRINK_POTION_DELAY);
			return;
		}

		// Convey the effect of the potion.
		int iSkillQuality = pItem->m_itPotion.m_skillquality;
		if ( g_Cfg.m_iFeatureAOS & FEATURE_AOS_UPDATE_B )
		{
			int iEnhance = static_cast<int>(GetDefNum("EnhancePotions", false));
			if ( iEnhance )
				iSkillQuality += IMULDIV(iSkillQuality, iEnhance, 100);
		}

		OnSpellEffect(static_cast<SPELL_TYPE>(RES_GET_INDEX(pItem->m_itPotion.m_Type)), this, iSkillQuality, pItem);

		// Give me the marker that i've used a potion.
		Spell_Effect_Create(SPELL_NONE, LAYER_FLAG_PotionUsed, iSkillQuality, 15 * TICK_PER_SEC, this);
	}

	if ( pItem->IsType(IT_DRINK) && IsSetOF(OF_DrinkIsFood) )
	{
		short iRestore = 0;
		if ( pItem->m_itDrink.m_foodval )
			iRestore = static_cast<short>(pItem->m_itDrink.m_foodval);
		else
			iRestore = static_cast<short>(pItem->Item_GetDef()->GetVolume());

		if ( iRestore < 1 )
			iRestore = 1;

		if ( Stat_GetVal(STAT_FOOD) >= Stat_GetMax(STAT_FOOD) )
		{
			SysMessageDefault(DEFMSG_DRINK_FULL);
			return;
		}

		Stat_SetVal(STAT_FOOD, Stat_GetVal(STAT_FOOD) + iRestore);
		if ( pItem->m_itFood.m_poison_skill )
			SetPoison(pItem->m_itFood.m_poison_skill * 10, 1 + (pItem->m_itFood.m_poison_skill / 50), this);
	}

	//Sound(sm_DrinkSounds[Calc_GetRandVal(COUNTOF(sm_DrinkSounds))]);
	UpdateAnimate(ANIM_EAT);
	pItem->ConsumeAmount();

	// Create the empty bottle ?
	if ( idbottle != ITEMID_NOTHING )
		ItemBounce(CItem::CreateScript(idbottle, this), false);
}
Пример #29
0
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;
}
Пример #30
0
CItem* CContainer::ContentFindRandom() const
{
	ADDTOCALLSTACK("CContainer::ContentFindRandom");
	// returns Pointer of random item, NULL if player carrying none
	return( dynamic_cast <CItem*> ( GetAt( Calc_GetRandVal( GetCount()))));
}