Esempio n. 1
0
int CChar::NPC_GetTrainMax( const CChar * pStudent, SKILL_TYPE Skill ) const
{
	ADDTOCALLSTACK("CChar::NPC_GetTrainMax");
	// What is the max I can train to ?
	int iMax;
	int iMaxAllowed;

	CVarDefCont * pValue = GetKey("OVERRIDE.TRAINSKILLMAXPERCENT",true);
	if ( pValue ) 
	{
		iMax = static_cast<int>(IMULDIV( pValue->GetValNum(), Skill_GetBase(Skill), 100 ));
	} else {
		iMax = IMULDIV( g_Cfg.m_iTrainSkillPercent, Skill_GetBase(Skill), 100 );
	}

	pValue = GetKey("OVERRIDE.TRAINSKILLMAX",true);
	if ( pValue ) 
	{
		iMaxAllowed = static_cast<int>(pValue->GetValNum());
	} else {
		iMaxAllowed = g_Cfg.m_iTrainSkillMax;
	}
	
	if ( iMax > iMaxAllowed )
		return minimum(iMaxAllowed, pStudent->Skill_GetMax(Skill));

	// Is this more that the student can take ?
	return minimum(iMax, pStudent->Skill_GetMax(Skill));
}
Esempio n. 2
0
int CValueCurveDef::GetLinear( int iSkillPercent ) const
{
	ADDTOCALLSTACK("CValueCurveDef::GetLinear");
	//
	// ARGS:
	//  iSkillPercent = 0 - 1000 = 0 to 100.0 percent
	//  m_Rate[3] = the 3 advance rate control numbers, 100,50,0 skill levels
	//		Acts as line segments.
	// RETURN:
	//  raw chance value.

	size_t iSegSize;
	size_t iLoIdx;

	size_t iQty = m_aiValues.GetCount();
	switch (iQty)
	{
	case 0:
		return( 0 );	// no values defined !
	case 1:
		return( m_aiValues[0] );
	case 2:
		iLoIdx = 0;
		iSegSize = 1000;
		break;
	case 3:
		// Do this the fastest.
		if ( iSkillPercent >= 500 )
		{
			iLoIdx = 1;
			iSkillPercent -= 500;
		}
		else
		{
			iLoIdx = 0;
		}
		iSegSize = 500;
		break;
	default:
		// More
		iLoIdx = IMULDIV( iSkillPercent, iQty, 1000 );
		iQty--;
		if ( iLoIdx >= iQty )
			iLoIdx = iQty - 1;
		iSegSize = 1000 / iQty;
		iSkillPercent -= ( iLoIdx * iSegSize );
		break;
	}

	int iLoVal = m_aiValues[iLoIdx];
	int iHiVal = m_aiValues[iLoIdx + 1];
	int iChance = iLoVal + IMULDIV( iHiVal - iLoVal, static_cast<int>(iSkillPercent), static_cast<int>(iSegSize) );

	if ( iChance <= 0 )
		return 0; // less than no chance ?

	return( iChance );
}
Esempio n. 3
0
int CPointBase::StepLinePath( const CPointBase & ptSrc, int iSteps )
{
	ADDTOCALLSTACK("CPointBase::StepLinePath");
	// Take x steps toward this point.
	int dx = m_x - ptSrc.m_x;
	int dy = m_y - ptSrc.m_y;
	int iDist2D = GetDist( ptSrc );
	if ( ! iDist2D )
		return 0;

	m_x = static_cast<short>(ptSrc.m_x + IMULDIV( iSteps, dx, iDist2D ));
	m_y = static_cast<short>(ptSrc.m_y + IMULDIV( iSteps, dy, iDist2D ));
	return( iDist2D );
}
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 );
}
int CResource::Calc_CombatAttackSpeed( CChar * pChar, CItem * pWeapon )
{
	// Combat: Speed of the attack
	// based on dex and weight of the weapon.
	// ? my tactics ?
	// ? my skill with weapon ?
	// ? How much weight i'm carrying ?
	// RETURN: 
	//  Time in tenths of a sec. (for entire swing, not just time to hit)

	ASSERT(pChar);

	if ( pWeapon != NULL )
	{
		CItemBase * pItemDef = dynamic_cast <CItemBase *> (pWeapon->Base_GetDef());
		if ( pItemDef )
		{
			BYTE speed = pItemDef->GetSpeed();
			if ( speed )
			{
				int iWaitTime = (TICK_PER_SEC * g_Cfg.m_iSpeedScaleFactor) / ( ( pChar->Stat_GetAdjusted(STAT_DEX) + 100 ) * speed );
				return (iWaitTime > 5 ? iWaitTime : 5);
			}
		}
	}
	if ( pChar->m_pNPC &&
		pChar->m_pNPC->m_Brain == NPCBRAIN_GUARD &&
		m_fGuardsInstantKill )
		return( 1 );

	// Base speed is just your DEX range=40 to 0
	int iWaitTime = IMULDIV( 100 - pChar->Stat_GetAdjusted(STAT_DEX), 40, 100 );
	if ( iWaitTime < 5 )	// no-one needs to be this fast.
		iWaitTime = 5;
	else
		iWaitTime += 5;

	// Speed of the weapon as well effected by strength (minor).

	if ( pWeapon != NULL )
	{
		DEBUG_CHECK( pWeapon->IsItemEquipped());
		int iWeaponWait = (pWeapon->GetWeight() * 10 ) / ( 4 * WEIGHT_UNITS );	// tenths of a stone.
		if ( pWeapon->GetEquipLayer() == LAYER_HAND2 )	// 2 handed is slower
		{
			iWeaponWait += iWaitTime/2;
		}
		iWaitTime += iWeaponWait;
	}
	else
	{
		iWaitTime += 2;
	}

	return( iWaitTime );
}
Esempio n. 6
0
INT64 Calc_GetRandLLVal( INT64 iqty )
{
	if ( iqty <= 0 )
		return( 0 );
	if ( iqty >= LLONG_MAX )
	{
		return( IMULDIV( g_World.m_Rand.genrand64_int64(), (DWORD) iqty, LLONG_MAX )) ;
	}
	return( g_World.m_Rand.genrand64_int64() % iqty );
}
Esempio n. 7
0
int Calc_GetRandVal( int iqty )
{
	if ( iqty <= 0 )
		return( 0 );
	if ( iqty >= INT_MAX )
	{
		return( IMULDIV( g_World.m_Rand.randInt(), (DWORD) iqty, INT_MAX )) ;
	}
	return( g_World.m_Rand.randInt() % iqty );
}
Esempio n. 8
0
bool CChar::NPC_CheckHirelingStatus()
{
	ADDTOCALLSTACK("CChar::NPC_CheckHirelingStatus");
	//  Am i happy at the moment ?
	//  If not then free myself.
	//
	// RETURN:
	//  true = happy.

	if ( ! IsStatFlag( STATF_Pet ))
		return( true );

	CCharBase * pCharDef = Char_GetDef();
	int iFoodConsumeRate = g_Cfg.m_iRegenRate[STAT_FOOD];

	unsigned int iWage = pCharDef->GetHireDayWage();
	if ( ! iWage || ! iFoodConsumeRate )
		return( true );

	// I am hired for money not for food.
	unsigned int iPeriodWage = IMULDIV( iWage, iFoodConsumeRate, 24 * 60 * g_Cfg.m_iGameMinuteLength );
	if ( iPeriodWage <= 0 )
		iPeriodWage = 1;

	CItemContainer * pBank = GetBank();
	if ( pBank->m_itEqBankBox.m_Check_Amount > iPeriodWage )
	{
		pBank->m_itEqBankBox.m_Check_Amount -= iPeriodWage;
	}
	else
	{
		TCHAR* pszMsg = Str_GetTemp();
		sprintf(pszMsg, g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_WAGE_COST ), iWage);
		Speak(pszMsg);

		CChar * pOwner = NPC_PetGetOwner();
		if ( pOwner )
		{
			Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_HIRE_TIMEUP ) );

			CItem * pMemory = Memory_AddObjTypes( pOwner, MEMORY_SPEAK );
			if ( pMemory )
				pMemory->m_itEqMemory.m_Action = NPC_MEM_ACT_SPEAK_HIRE;

			NPC_PetDesert();
			return false;
		}

		// Some sort of strange bug to get here.
		Memory_ClearTypes( MEMORY_IPET );
		StatFlag_Clear( STATF_Pet );
	}

	return( true );
}
Esempio n. 9
0
LONG CItemVendable::GetVendorPrice( int iConvertFactor )
{
	ADDTOCALLSTACK("CItemVendable::GetVendorPrice");
	// Player is buying/selling from a vendor.
	// ASSUME this item is on the vendor !
	// Consider: (if not on a player vendor)
	//  Quality of the item.
	//  rareity of the item.
	// ARGS:
	// iConvertFactor will consider:
	//  Vendors Karma.
	//  Players Karma
	// -100 = reduce price by 100%   (player selling to vendor?)
	//    0 = base price
	// +100 = increase price by 100% (vendor selling to player?)

	INT64 lPrice = m_price;
	if ( lPrice <= 0 )	// set on player vendor.
	{
		if ( lPrice == 0 )	// set a new randomized price for the item
		{
			CItemBase * pItemDef;
			if ( IsType( IT_DEED ))
			{
				// Deeds just represent the item they are deeding.
				pItemDef = CItemBase::FindItemBase(static_cast<ITEMID_TYPE>(RES_GET_INDEX(m_itDeed.m_Type)));
				if ( pItemDef == NULL )
					return( 1 );
			}
			else
			{
				pItemDef = Item_GetDef();
			}
			lPrice = pItemDef->GetMakeValue(GetQuality());
			m_price = static_cast<long>(-lPrice);
		}
		else
		{
			lPrice = -lPrice;
		}
	}

	lPrice += IMULDIV( lPrice, maximum(iConvertFactor, -100), 100 );
	if (lPrice > LONG_MAX)
		return LONG_MAX;
	else if (lPrice <= 0)
		return 0;
	
	return static_cast<long>(lPrice);
}
Esempio n. 10
0
void CSector::SetDefaultWeatherChance()
{
	ADDTOCALLSTACK("CSector::SetDefaultWeatherChance");
	CPointMap pt = GetBasePoint();
	BYTE iPercent = static_cast<BYTE>(IMULDIV( pt.m_y, 100, g_MapList.GetY(pt.m_map) ));	// 100 = south
	if ( iPercent < 50 )
	{
		// Anywhere north of the Britain Moongate is a good candidate for snow
		m_ColdChance = 1 + ( 49 - iPercent ) * 2;
		m_RainChance = 15;
	}
	else
	{
		// warmer down south
		m_ColdChance = 1;
		// rain more likely down south.
		m_RainChance = 15 + ( iPercent - 50 ) / 10;
	}
}
Esempio n. 11
0
size_t CContainer::ResourceConsumePart( const CResourceQtyArray * pResources, int iReplicationQty, int iDamagePercent, bool fTest, DWORD dwArg )
{
	ADDTOCALLSTACK("CContainer::ResourceConsumePart");
	// Consume just some of the resources.
	// ARGS:
	//	pResources = the resources i need to make 1 replication of this end product.
	//  iDamagePercent = 0-100
	// RETURN:
	//  BadIndex = all needed items where present.
	// index of the item we did not have.

	if ( iDamagePercent <= 0 )
		return pResources->BadIndex();

	size_t iMissing = pResources->BadIndex();

	size_t iQtyRes = pResources->GetCount();
	for ( size_t i = 0; i < iQtyRes; i++ )
	{
		int iResQty = static_cast<int>(pResources->GetAt(i).GetResQty());
		if (iResQty <= 0) // not sure why this would be true
			continue;

		int iQtyTotal = ( iResQty * iReplicationQty );
		if ( iQtyTotal <= 0 )
			continue;
		iQtyTotal = IMULDIV( iQtyTotal, iDamagePercent, 100 );
		if ( iQtyTotal <= 0 )
			continue;

		RESOURCE_ID rid = pResources->GetAt(i).GetResourceID();
		int iRet = ContentConsume( rid, iQtyTotal, fTest, dwArg );
		if ( iRet )
		{
			iMissing = i;
		}
	}

	return( iMissing );
}
Esempio n. 12
0
int Calc_GetBellCurve( int iValDiff, int iVariance )
{
	// Produce a log curve.
	//
	// 50+
	//	 |
	//	 |
	//	 |
	// 25|  +
	//	 |
	//	 |	   +
	//	 |		  +
	//	0 --+--+--+--+------
	//    iVar				iValDiff
	//
	// ARGS:
	//  iValDiff = Given a value relative to 0
	//		0 = 50.0% chance.
	//  iVariance = the 25.0% point of the bell curve
	// RETURN:
	//  (0-100.0) % chance at this iValDiff.
	//  Chance gets smaller as Diff gets bigger.
	// EXAMPLE:
	//  if ( iValDiff == iVariance ) return( 250 )
	//  if ( iValDiff == 0 ) return( 500 );
	//

	if ( iVariance <= 0 )	// this really should not happen but just in case.
		return( 500 );
	if ( iValDiff < 0 ) iValDiff = -iValDiff;

	int iChance = 500;
	while ( iValDiff > iVariance && iChance )
	{
		iValDiff -= iVariance;
		iChance /= 2;	// chance is halved for each Variance period.
	}

	return( iChance - IMULDIV( iChance/2, iValDiff, iVariance ));
}
Esempio n. 13
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);
}
Esempio n. 14
0
bool CChar::Use_Eat( CItem * pItemFood, short iQty )
{
	ADDTOCALLSTACK("CChar::Use_Eat");
	// What we can eat should depend on body type.
	// How much we can eat should depend on body size and current fullness.
	//
	// ??? monsters should be able to eat corpses / raw meat
	// IT_FOOD or IT_FOOD_RAW
	// NOTE: Some foods like apples are stackable !

	if ( !CanMove(pItemFood) )
	{
		SysMessageDefault(DEFMSG_FOOD_CANTMOVE);
		return false;
	}

	if ( Stat_GetMax(STAT_FOOD) == 0 )
	{
		SysMessageDefault(DEFMSG_FOOD_CANTEAT);
		return false;
	}

	// Is this edible by me ?
	if ( !Food_CanEat(pItemFood) )
	{
		SysMessageDefault(DEFMSG_FOOD_RCANTEAT);
		return false;
	}

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

	Use_EatQty(pItemFood, iQty);

	LPCTSTR pMsg;
	int index = IMULDIV(Stat_GetVal(STAT_FOOD), 5, Stat_GetMax(STAT_FOOD));
	switch ( index )
	{
		case 0:
			pMsg = g_Cfg.GetDefaultMsg(DEFMSG_FOOD_FULL_1);
			break;
		case 1:
			pMsg = g_Cfg.GetDefaultMsg(DEFMSG_FOOD_FULL_2);
			break;
		case 2:
			pMsg = g_Cfg.GetDefaultMsg(DEFMSG_FOOD_FULL_3);
			break;
		case 3:
			pMsg = g_Cfg.GetDefaultMsg(DEFMSG_FOOD_FULL_4);
			break;
		case 4:
			pMsg = g_Cfg.GetDefaultMsg(DEFMSG_FOOD_FULL_5);
			break;
		case 5:
		default:
			pMsg = g_Cfg.GetDefaultMsg(DEFMSG_FOOD_FULL_6);
			break;
	}
	SysMessage(pMsg);
	return true;
}
Esempio n. 15
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;
}
Esempio n. 16
0
int CResource::Calc_CombatAttackSpeed( CChar * pChar, CItem * pWeapon )
{
    ADDTOCALLSTACK("CResource::Calc_CombatAttackSpeed");
    // Calculate the swing speed value on chars
    // RETURN:
    //  Time in tenths of a sec. (for entire swing, not just time to hit)

    ASSERT(pChar);
    if ( pChar->m_pNPC && pChar->m_pNPC->m_Brain == NPCBRAIN_GUARD && m_fGuardsInstantKill )
        return 1;

    int iSwingSpeedIncrease = static_cast<int>(pChar->GetDefNum("INCREASESWINGSPEED", true));
    int iBaseSpeed = 50;	// Base speed = Wrestling speed.
    if ( pWeapon )			// If we have a weapon, base speed should match weapon's value.
        iBaseSpeed = pWeapon->GetSpeed();

    switch ( g_Cfg.m_iCombatSpeedEra )
    {
    case 0:	// OLD (55r and lower) formula using DEX and: a)Speed if set on weapon or b)calculating delay from weapon's weight if speed not set (taking in count if weapon is 2h)
    {
        if ( pWeapon )
        {
            if (iBaseSpeed)
            {
                int iWaitTime = (TICK_PER_SEC * g_Cfg.m_iSpeedScaleFactor) / ((pChar->Stat_GetAdjusted(STAT_DEX) + 100) * iBaseSpeed);
                return ( iWaitTime < 5 ? 5 : iWaitTime ); // Never less than 5 tenths, even removing the '5' limit it should never be less than 0 or CChar will get SetTimeout(-1) and stop attack.
            }
        }

        // Base speed is just your DEX range=40 to 0
        int iWaitTime = IMULDIV(100 - pChar->Stat_GetAdjusted(STAT_DEX), 40, 100);
        if (iWaitTime < 5)	// no-one needs to be this fast.
            iWaitTime = 5;
        else
            iWaitTime += 5;

        // Speed of the weapon as well effected by strength (minor).

        if ( pWeapon )
        {
            int iWeaponWait = (pWeapon->GetWeight() * 10) / (4 * WEIGHT_UNITS);	// tenths of a stone.
            if (pWeapon->GetEquipLayer() == LAYER_HAND2)	// 2 handed is slower
            {
                iWeaponWait += iWaitTime / 2;
            }
            iWaitTime += iWeaponWait;
        }
        else
            iWaitTime += 2;
        return iWaitTime;
    }

    case 1:
    {
        // AOS formula		(default m_iSpeedScaleFactor = 40000)
        int iSwingSpeed = (pChar->Stat_GetVal(STAT_DEX) + 100) * iBaseSpeed;
        iSwingSpeed = maximum(1, iSwingSpeed * (100 + iSwingSpeedIncrease) / 100);
        iSwingSpeed = ((g_Cfg.m_iSpeedScaleFactor * TICK_PER_SEC) / iSwingSpeed) / 2;
        if ( iSwingSpeed < 12 )		//1.25
            iSwingSpeed = 12;
        return iSwingSpeed;
    }

    default:
    case 2:
    {
        // SE formula		(default m_iSpeedScaleFactor = 80000)
        int iSwingSpeed = maximum(1, iBaseSpeed * (100 + iSwingSpeedIncrease) / 100);
        iSwingSpeed = (g_Cfg.m_iSpeedScaleFactor / ((pChar->Stat_GetVal(STAT_DEX) + 100) * iSwingSpeed)) - 2;	// get speed in ticks of 0.25s each
        if ( iSwingSpeed < 5 )
            iSwingSpeed = 5;
        iSwingSpeed = (iSwingSpeed * TICK_PER_SEC) / 4;		// convert 0.25s ticks into ms
        return iSwingSpeed;
    }

    case 3:
    {
        // ML formula		(doesn't use m_iSpeedScaleFactor and it's only compatible with ML speed format eg. 0.25 ~ 5.00 instead 0 ~ 50)
        int iSwingSpeed = ((iBaseSpeed * 4) - (pChar->Stat_GetVal(STAT_DEX) / 30)) * (100 / (100 + iSwingSpeedIncrease));	// get speed in ticks of 0.25s each
        if ( iSwingSpeed < 5 )
            iSwingSpeed = 5;
        iSwingSpeed = (iSwingSpeed * TICK_PER_SEC) / 4;		// convert 0.25s ticks into ms
        return iSwingSpeed;
    }
    }
}