bodyparts separated
[k8-i-v-a-n.git] / src / game / bodyparts / bodypart_leg.cpp
blobdb56308cfd57b13c8b70ab1d7f3a6185c8109b72
1 #ifdef HEADER_PHASE
2 ITEM(leg, bodypart)
4 public:
5 leg() : StrengthBonus(0), AgilityBonus(0) { }
6 leg(const leg&);
7 virtual ~leg();
8 virtual void Save(outputfile&) const;
9 virtual void Load(inputfile&);
10 virtual int GetTotalResistance(int) const;
11 void SetBoot(item* What) { BootSlot.PutInItem(What); }
12 item* GetBoot() const { return *BootSlot; }
13 virtual void DropEquipment(stack* = 0);
14 double GetKickToHitValue() const { return KickToHitValue; }
15 double GetKickDamage() const { return KickDamage; }
16 int GetKickMinDamage() const;
17 int GetKickMaxDamage() const;
18 int GetAttribute(int, truth = true) const;
19 truth EditAttribute(int, int);
20 void EditExperience(int, double, double);
21 virtual void InitSpecialAttributes();
22 virtual void Mutate();
23 sLong GetKickAPCost() const { return KickAPCost; }
24 virtual item* GetEquipment(int) const;
25 virtual int GetEquipments() const { return 1; }
26 sLong GetBaseKickStrength() const { return BaseKickStrength; }
27 void SetBaseKickStrength(sLong What) { BaseKickStrength = What; }
28 virtual void CalculateDamage();
29 virtual void CalculateToHitValue();
30 virtual void CalculateAPCost();
31 void ApplyEquipmentAttributeBonuses(item*);
32 virtual void CalculateAttributeBonuses();
33 virtual void SignalEquipmentAdd(gearslot*);
34 void ApplyAgilityPenalty(item*);
35 void ApplyStrengthBonus (item *Item);
36 void ApplyAgilityBonus (item *Item);
37 virtual void SignalVolumeAndWeightChange();
38 virtual truth DamageArmor(character*, int, int);
39 virtual truth EditAllAttributes(int);
40 void AddAttackInfo(felist&) const;
41 virtual item* GetArmorToReceiveFluid(truth) const;
42 virtual void CopyAttributes(const bodypart*);
43 double GetStrengthExperience() const { return StrengthExperience; }
44 double GetAgilityExperience() const { return AgilityExperience; }
45 virtual void SignalPossibleUsabilityChange();
47 protected:
48 void UpdateLegArmorPictures(graphicdata&, graphicdata&, int) const;
49 gearslot BootSlot;
50 double StrengthExperience;
51 double AgilityExperience;
52 int BaseKickStrength;
53 double KickDamage;
54 double KickToHitValue;
55 sLong KickAPCost;
56 int StrengthBonus;
57 int AgilityBonus;
61 #else
65 int leg::GetKickMinDamage() const { return int(KickDamage * 0.75); }
69 int leg::GetKickMaxDamage() const { return int(KickDamage * 1.25 + 1); }
73 int leg::GetTotalResistance(int Type) const
75 if(Master)
77 int Resistance = GetResistance(Type) + Master->GetGlobalResistance(Type);
79 if(GetExternalBodyArmor())
80 Resistance += GetExternalBodyArmor()->GetResistance(Type) >> 1;
82 if(GetBoot())
83 Resistance += GetBoot()->GetResistance(Type);
85 return Resistance;
87 else
88 return GetResistance(Type);
93 void leg::Save(outputfile& SaveFile) const
95 bodypart::Save(SaveFile);
96 SaveFile << BaseKickStrength << StrengthExperience << AgilityExperience;
97 SaveFile << BootSlot;
102 void leg::Load(inputfile& SaveFile)
104 bodypart::Load(SaveFile);
105 SaveFile >> BaseKickStrength >> StrengthExperience >> AgilityExperience;
106 SaveFile >> BootSlot;
111 void leg::CalculateDamage()
113 if(!Master)
114 return;
116 double WeaponStrength = GetBaseKickStrength() * GetBaseKickStrength();
117 item* Boot = GetBoot();
119 if(Boot)
120 WeaponStrength += Boot->GetWeaponStrength();
122 double Base = sqrt(5e-5 * WeaponStrength);
124 if(Boot)
125 Base += Boot->GetDamageBonus();
127 KickDamage = Base * sqrt(1e-7 * GetAttribute(LEG_STRENGTH))
128 * GetHumanoidMaster()->GetCWeaponSkill(KICK)->GetBonus();
133 void leg::CalculateToHitValue()
135 if(!Master)
136 return;
138 double BonusMultiplier = 10.;
139 item* Boot = GetBoot();
141 if(Boot)
142 BonusMultiplier += Boot->GetTHVBonus();
144 KickToHitValue = GetAttribute(AGILITY)
145 * sqrt(2.5 * Master->GetAttribute(PERCEPTION))
146 * GetHumanoidMaster()->GetCWeaponSkill(KICK)->GetBonus()
147 * Master->GetMoveEase()
148 * BonusMultiplier / 10000000;
153 void leg::CalculateAPCost()
155 if(!Master)
156 return;
158 KickAPCost = Max(sLong(20000000000. / (APBonus(GetAttribute(AGILITY)) * Master->GetMoveEase() * Master->GetCWeaponSkill(KICK)->GetBonus())), 100);
163 void leg::DropEquipment(stack* Stack)
165 if(Stack)
167 if(GetBoot())
168 GetBoot()->MoveTo(Stack);
170 else
172 if(GetBoot())
173 GetSlot()->AddFriendItem(GetBoot());
179 leg::~leg()
181 delete GetBoot();
186 int leg::GetAttribute(int Identifier, truth AllowBonus) const
188 if(Identifier == LEG_STRENGTH)
190 int Base = !UseMaterialAttributes()
191 ? int(StrengthExperience * EXP_DIVISOR)
192 : GetMainMaterial()->GetStrengthValue();
194 if(AllowBonus)
195 Base += StrengthBonus;
197 return Max(!IsBadlyHurt() || !AllowBonus ? Base : Base / 3, 1);
199 else if(Identifier == AGILITY)
201 int Base = !UseMaterialAttributes()
202 ? int(AgilityExperience * EXP_DIVISOR)
203 : GetMainMaterial()->GetFlexibility() << 2;
205 if(AllowBonus)
206 Base += AgilityBonus;
208 return Max(IsUsable() || !AllowBonus ? Base : Base / 3, 1);
210 else
212 ABORT("Illegal leg attribute %d request!", Identifier);
213 return 0xECCE;
219 truth leg::EditAttribute(int Identifier, int Value)
221 if(!Master)
222 return false;
224 if(Identifier == LEG_STRENGTH)
226 if(!UseMaterialAttributes()
227 && Master->RawEditAttribute(StrengthExperience, Value))
229 Master->CalculateBurdenState();
230 Master->CalculateBattleInfo();
231 return true;
234 else if(Identifier == AGILITY)
235 if(!UseMaterialAttributes()
236 && Master->RawEditAttribute(AgilityExperience, Value))
238 Master->CalculateBattleInfo();
239 return true;
242 return false;
247 void leg::EditExperience(int Identifier, double Value, double Speed)
249 if(!Master)
250 return;
252 if(Identifier == LEG_STRENGTH)
254 if(!UseMaterialAttributes())
256 int Change = Master->RawEditExperience(StrengthExperience,
257 Master->GetNaturalExperience(LEG_STRENGTH),
258 Value, Speed);
260 if(Change)
262 cchar* Adj = Change > 0 ? "stronger" : "weaker";
264 if(Master->IsPlayer())
265 ADD_MESSAGE("Your %s feels %s!", GetBodyPartName().CStr(), Adj);
266 else if(Master->IsPet() && Master->CanBeSeenByPlayer())
267 ADD_MESSAGE("Suddenly %s looks %s.", Master->CHAR_NAME(DEFINITE), Adj);
269 Master->CalculateBurdenState();
270 Master->CalculateBattleInfo();
274 else if(Identifier == AGILITY)
276 if(!UseMaterialAttributes())
278 int Change = Master->RawEditExperience(AgilityExperience,
279 Master->GetNaturalExperience(AGILITY),
280 Value, Speed);
282 if(Change)
284 cchar* Adj = Change > 0 ? "very agile" : "slower";
286 if(Master->IsPlayer())
287 ADD_MESSAGE("Your %s feels %s!", GetBodyPartName().CStr(), Adj);
288 else if(Master->IsPet() && Master->CanBeSeenByPlayer())
289 ADD_MESSAGE("Suddenly %s looks %s.", Master->CHAR_NAME(DEFINITE), Adj);
291 Master->CalculateBattleInfo();
295 else
296 ABORT("Illegal leg attribute %d experience edit request!", Identifier);
301 void leg::InitSpecialAttributes()
303 if(!Master->IsHuman() || Master->IsInitializing())
305 StrengthExperience = Master->GetNaturalExperience(LEG_STRENGTH);
306 AgilityExperience = Master->GetNaturalExperience(AGILITY);
308 else
310 StrengthExperience = game::GetAveragePlayerLegStrengthExperience();
311 AgilityExperience = game::GetAveragePlayerAgilityExperience();
314 LimitRef(StrengthExperience, MIN_EXP, MAX_EXP);
315 LimitRef(AgilityExperience, MIN_EXP, MAX_EXP);
316 BaseKickStrength = Master->GetBaseKickStrength();
321 void leg::Mutate()
323 bodypart::Mutate();
324 StrengthExperience = StrengthExperience * (1.5 - (RAND() & 1023) / 1023.);
325 AgilityExperience = AgilityExperience * (1.5 - (RAND() & 1023) / 1023.);
326 LimitRef(StrengthExperience, MIN_EXP, MAX_EXP);
327 LimitRef(AgilityExperience, MIN_EXP, MAX_EXP);
332 item* leg::GetEquipment(int I) const
334 return !I ? GetBoot() : 0;
339 void leg::SignalVolumeAndWeightChange()
341 bodypart::SignalVolumeAndWeightChange();
343 if(Master && !Master->IsInitializing())
345 CalculateAttributeBonuses();
346 CalculateAttackInfo();
352 leg::leg(const leg& Leg) : mybase(Leg), StrengthExperience(Leg.StrengthExperience), AgilityExperience(Leg.AgilityExperience), BaseKickStrength(Leg.BaseKickStrength)
358 void leg::SignalEquipmentAdd(gearslot* Slot)
360 int EquipmentIndex = Slot->GetEquipmentIndex();
362 if(Master && !Master->IsInitializing())
364 item* Equipment = Slot->GetItem();
366 if(Equipment->IsInCorrectSlot(EquipmentIndex))
367 ApplyEquipmentAttributeBonuses(Equipment);
369 if(EquipmentIndex == RIGHT_BOOT_INDEX || EquipmentIndex == LEFT_BOOT_INDEX)
370 ApplyAgilityPenalty(Equipment);
373 if(Master)
374 Master->SignalEquipmentAdd(EquipmentIndex);
379 void leg::ApplyEquipmentAttributeBonuses(item* Item)
381 if(Item->AffectsLegStrength())
383 StrengthBonus += Item->GetEnchantment();
385 if(Master)
386 Master->CalculateBurdenState();
389 if(Item->AffectsAgility())
390 AgilityBonus += Item->GetEnchantment();
395 void leg::CalculateAttributeBonuses()
397 StrengthBonus = AgilityBonus = 0;
399 for(int c = 0; c < GetEquipments(); ++c)
401 item* Equipment = GetEquipment(c);
403 if(Equipment && Equipment->IsInCorrectSlot())
404 ApplyEquipmentAttributeBonuses(Equipment);
407 ApplyAgilityPenalty(GetBoot());
409 if(Master)
411 ApplyAgilityPenalty(GetExternalCloak());
412 ApplyAgilityPenalty(GetExternalBodyArmor());
413 /* */
414 ApplyStrengthBonus(GetExternalHelmet());
415 ApplyStrengthBonus(GetExternalCloak());
416 ApplyStrengthBonus(GetExternalBodyArmor());
417 ApplyStrengthBonus(GetExternalBelt());
418 ApplyAgilityBonus(GetExternalHelmet());
419 ApplyAgilityBonus(GetExternalCloak());
420 ApplyAgilityBonus(GetExternalBodyArmor());
421 ApplyAgilityBonus(GetExternalBelt());
424 if(!UseMaterialAttributes())
426 StrengthBonus -= CalculateScarAttributePenalty(GetAttribute(LEG_STRENGTH, false));
427 AgilityBonus -= CalculateScarAttributePenalty(GetAttribute(AGILITY, false)) ;
433 void leg::ApplyAgilityPenalty(item* Item)
435 if(Item)
436 AgilityBonus -= Item->GetInElasticityPenalty(GetAttribute(AGILITY, false));
441 truth leg::DamageArmor(character* Damager, int Damage, int Type)
443 sLong AV[3] = { 0, 0, 0 }, AVSum = 0;
444 item* Armor[3];
446 if((Armor[0] = GetBoot()))
447 AVSum += AV[0] = Max(Armor[0]->GetStrengthValue(), 1);
449 if((Armor[1] = GetExternalBodyArmor()))
450 AVSum += AV[1] = Max(Armor[1]->GetStrengthValue() >> 1, 1);
452 if((Armor[2] = GetExternalCloak()))
453 AVSum += AV[2] = Max(Armor[2]->GetStrengthValue(), 1);
455 return AVSum ? Armor[femath::WeightedRand(AV, AVSum)]->ReceiveDamage(Damager, Damage, Type) : false;
460 truth leg::EditAllAttributes(int Amount)
462 LimitRef(StrengthExperience += Amount * EXP_MULTIPLIER, MIN_EXP, MAX_EXP);
463 LimitRef(AgilityExperience += Amount * EXP_MULTIPLIER, MIN_EXP, MAX_EXP);
464 return (Amount < 0
465 && (StrengthExperience != MIN_EXP || AgilityExperience != MIN_EXP))
466 || (Amount > 0
467 && (StrengthExperience != MAX_EXP || AgilityExperience != MAX_EXP));
472 void leg::AddAttackInfo(felist& List) const
474 festring Entry = CONST_S(" kick attack");
475 Entry.Resize(50);
476 Entry << GetKickMinDamage() << '-' << GetKickMaxDamage();
477 Entry.Resize(60);
478 Entry << int(GetKickToHitValue());
479 Entry.Resize(70);
480 Entry << GetKickAPCost();
481 List.AddEntry(Entry, LIGHT_GRAY);
486 item* leg::GetArmorToReceiveFluid(truth SteppedOn) const
488 if(SteppedOn)
490 item* Boot = GetBoot();
491 return Boot ? Boot : 0;
493 else
495 item* Cloak = GetExternalCloak();
497 if(Cloak && !(RAND() % 3))
498 return Cloak;
500 item* Boot = GetBoot();
502 if(Boot && RAND() & 1)
503 return Boot;
505 item* BodyArmor = GetExternalBodyArmor();
506 return BodyArmor ? BodyArmor : 0;
512 void leg::UpdateLegArmorPictures(graphicdata& LegArmorGraphicData, graphicdata& BootGraphicData, int SpecialFlags) const
514 if(!Master || !Master->PictureUpdatesAreForbidden())
516 UpdateArmorPicture(LegArmorGraphicData,
517 Master ? GetExternalBodyArmor() : 0,
518 SpecialFlags,
519 &item::GetLegArmorBitmapPos,
520 true);
521 UpdateArmorPicture(BootGraphicData,
522 GetBoot(),
523 SpecialFlags,
524 &item::GetBootBitmapPos);
530 void leg::CopyAttributes(const bodypart* BodyPart)
532 const leg* Leg = static_cast<const leg*>(BodyPart);
533 StrengthExperience = Leg->StrengthExperience;
534 AgilityExperience = Leg->AgilityExperience;
539 void leg::SignalPossibleUsabilityChange()
541 feuLong OldFlags = Flags;
542 UpdateFlags();
544 if(Flags != OldFlags && !Master->IsInitializing())
545 Master->CalculateBattleInfo();
550 void leg::ApplyStrengthBonus (item *Item) {
551 if (Item && Item->AffectsLegStrength()) StrengthBonus += Item->GetEnchantment()/2;
556 void leg::ApplyAgilityBonus (item *Item) {
557 if (Item && Item->AffectsAgility()) AgilityBonus += Item->GetEnchantment()/2;
559 #endif