save and bone files now can be compressed with ZLib (wow!)
[k8-i-v-a-n.git] / src / game / bodypart.cpp
blob162d9941b33436cc3f23f7cc9692bf7524d6aa1b
1 /*
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
8 * See LICENSING which should be included
9 * along with this file for more details
13 /* Compiled through itemset.cpp */
15 int bodypart::GetGraphicsContainerIndex() const { return GR_HUMANOID; }
16 int bodypart::GetArticleMode() const { return IsUnique() ? FORCE_THE : 0; }
17 truth bodypart::IsAlive() const { return MainMaterial->GetBodyFlags() & IS_ALIVE; }
18 int bodypart::GetSpecialFlags() const { return SpecialFlags|ST_OTHER_BODYPART; }
19 col16 bodypart::GetMaterialColorA(int) const { return GetMainMaterial()->GetSkinColor(); }
20 truth bodypart::IsWarm() const { return MainMaterial->GetBodyFlags() & IS_WARM; }
21 truth bodypart::UseMaterialAttributes() const { return MainMaterial->GetBodyFlags() & USE_MATERIAL_ATTRIBUTES || !Master || Master->AlwaysUseMaterialAttributes(); }
22 truth bodypart::CanRegenerate() const { return MainMaterial->GetBodyFlags() & CAN_REGENERATE; }
23 truth bodypart::CanHaveParasite() const { return MainMaterial->GetBodyFlags() & CAN_HAVE_PARASITE; }
24 square* bodypart::GetSquareUnder(int I) const { return Master ? Slot[0]->GetSquareUnder(I) : Slot[I]->GetSquareUnder(); }
25 lsquare* bodypart::GetLSquareUnder(int I) const { return static_cast<lsquare*>(Master ? Slot[0]->GetSquareUnder(I) : Slot[I]->GetSquareUnder()); }
26 item* bodypart::GetExternalBodyArmor() const { return GetHumanoidMaster()->GetBodyArmor(); }
27 item* bodypart::GetExternalCloak() const { return GetHumanoidMaster()->GetCloak(); }
28 truth bodypart::AllowFluidBe() const { return !Master || !Master->IsPolymorphed(); }
30 /* */
31 item *bodypart::GetExternalHelmet () const { return GetHumanoidMaster()->GetHelmet(); }
32 item *bodypart::GetExternalBelt () const { return GetHumanoidMaster()->GetBelt(); }
34 int head::GetBodyPartIndex() const { return HEAD_INDEX; }
35 int head::GetBiteMinDamage() const { return int(BiteDamage * 0.75); }
36 int head::GetBiteMaxDamage() const { return int(BiteDamage * 1.25 + 1); }
38 int torso::GetBodyPartIndex() const { return TORSO_INDEX; }
40 int normaltorso::GetGraphicsContainerIndex() const { return GR_CHARACTER; }
42 int arm::GetMinDamage() const { return int(Damage * 0.75); }
43 int arm::GetMaxDamage() const { return int(Damage * 1.25 + 1); }
44 double arm::GetBlockValue() const { return GetToHitValue() * GetWielded()->GetBlockModifier() / 10000; }
46 int rightarm::GetBodyPartIndex() const { return RIGHT_ARM_INDEX; }
47 int rightarm::GetSpecialFlags() const { return SpecialFlags|ST_RIGHT_ARM; }
49 int leftarm::GetBodyPartIndex() const { return LEFT_ARM_INDEX; }
50 int leftarm::GetSpecialFlags() const { return SpecialFlags|ST_LEFT_ARM; }
52 int groin::GetBodyPartIndex() const { return GROIN_INDEX; }
53 int groin::GetSpecialFlags() const { return SpecialFlags|ST_GROIN; }
55 int leg::GetKickMinDamage() const { return int(KickDamage * 0.75); }
56 int leg::GetKickMaxDamage() const { return int(KickDamage * 1.25 + 1); }
58 int rightleg::GetBodyPartIndex() const { return RIGHT_LEG_INDEX; }
59 int rightleg::GetSpecialFlags() const { return SpecialFlags|ST_RIGHT_LEG; }
61 int leftleg::GetBodyPartIndex() const { return LEFT_LEG_INDEX; }
62 int leftleg::GetSpecialFlags() const { return SpecialFlags|ST_LEFT_LEG; }
64 v2 eddytorso::GetBitmapPos(int Frame) const { return torso::GetBitmapPos(Frame) + v2((Frame&0x6) << 3, 0); }
66 head* corpse::Behead() { return Deceased->Behead(); }
67 truth corpse::CanBeCloned() const { return GetDeceased()->CanBeCloned(); }
68 int corpse::GetAttachedGod() const { return GetDeceased()->GetTorso()->GetAttachedGod(); }
70 v2 ennerhead::GetBitmapPos(int Frame) const { return Frame & 16 ? head::GetBitmapPos(Frame) : head::GetBitmapPos(Frame) + v2(16, 0); }
72 alpha blinkdogtorso::GetAlphaA(int Frame) const { return (Frame & 31) != 31 ? 255 : 0; }
74 void bodypart::Save(outputfile& SaveFile) const
76 item::Save(SaveFile);
77 SaveFile << BitmapPos << ColorB << ColorC << ColorD << SpecialFlags << WobbleData << HP;
78 SaveFile << OwnerDescription << BloodMaterial << NormalMaterial << Scar << DamageID;
81 void bodypart::Load(inputfile& SaveFile)
83 item::Load(SaveFile);
84 SaveFile >> BitmapPos >> ColorB >> ColorC >> ColorD >> SpecialFlags >> WobbleData >> HP;
85 SaveFile >> OwnerDescription >> BloodMaterial >> NormalMaterial >> Scar >> DamageID;
88 int bodypart::GetStrengthValue() const
90 if(!UseMaterialAttributes())
91 return sLong(GetStrengthModifier()) * Master->GetAttribute(ENDURANCE) / 2000;
92 else
93 return sLong(GetStrengthModifier()) * GetMainMaterial()->GetStrengthValue() / 2000;
96 int head::GetTotalResistance(int Type) const
98 if(Master)
100 int Resistance = GetResistance(Type) + Master->GetGlobalResistance(Type);
102 if(GetHelmet())
103 Resistance += GetHelmet()->GetResistance(Type);
105 if(GetExternalBodyArmor())
106 Resistance += GetExternalBodyArmor()->GetResistance(Type) >> 2;
108 return Resistance;
110 else
111 return GetResistance(Type);
114 int normaltorso::GetTotalResistance(int Type) const
116 if(Master)
117 return GetResistance(Type) + Master->GetGlobalResistance(Type);
118 else
119 return GetResistance(Type);
122 int humanoidtorso::GetTotalResistance(int Type) const
124 if(Master)
126 int Resistance = GetResistance(Type) + Master->GetGlobalResistance(Type);
128 if(GetBodyArmor())
129 Resistance += GetBodyArmor()->GetResistance(Type);
131 if(GetBelt())
132 Resistance += GetBelt()->GetResistance(Type);
134 return Resistance;
136 else
137 return GetResistance(Type);
140 int arm::GetTotalResistance(int Type) const
142 if(Master)
144 int Resistance = GetResistance(Type) + Master->GetGlobalResistance(Type);
146 if(GetExternalBodyArmor())
147 Resistance += GetExternalBodyArmor()->GetResistance(Type) >> 1;
149 if(GetGauntlet())
150 Resistance += GetGauntlet()->GetResistance(Type);
152 return Resistance;
154 else
155 return GetResistance(Type);
158 int groin::GetTotalResistance(int Type) const
160 if(Master)
162 int Resistance = GetResistance(Type) + Master->GetGlobalResistance(Type);
164 if(GetExternalBodyArmor())
165 Resistance += GetExternalBodyArmor()->GetResistance(Type);
167 if(GetHumanoidMaster()->GetBelt())
168 Resistance += GetHumanoidMaster()->GetBelt()->GetResistance(Type);
170 return Resistance;
172 else
173 return GetResistance(Type);
176 int leg::GetTotalResistance(int Type) const
178 if(Master)
180 int Resistance = GetResistance(Type) + Master->GetGlobalResistance(Type);
182 if(GetExternalBodyArmor())
183 Resistance += GetExternalBodyArmor()->GetResistance(Type) >> 1;
185 if(GetBoot())
186 Resistance += GetBoot()->GetResistance(Type);
188 return Resistance;
190 else
191 return GetResistance(Type);
194 void head::Save(outputfile& SaveFile) const
196 bodypart::Save(SaveFile);
197 SaveFile << (int)BaseBiteStrength;
198 SaveFile << HelmetSlot << AmuletSlot;
201 void head::Load(inputfile& SaveFile)
203 bodypart::Load(SaveFile);
204 SaveFile >> (int&)BaseBiteStrength;
205 SaveFile >> HelmetSlot >> AmuletSlot;
208 void humanoidtorso::Save(outputfile& SaveFile) const
210 bodypart::Save(SaveFile);
211 SaveFile << BodyArmorSlot << CloakSlot << BeltSlot;
214 void humanoidtorso::Load(inputfile& SaveFile)
216 bodypart::Load(SaveFile);
217 SaveFile >> BodyArmorSlot >> CloakSlot >> BeltSlot;
220 void arm::Save(outputfile& SaveFile) const
222 bodypart::Save(SaveFile);
223 SaveFile << (int)BaseUnarmedStrength;
224 SaveFile << StrengthExperience << DexterityExperience;
225 SaveFile << WieldedSlot << GauntletSlot << RingSlot;
226 SaveFile << WieldedGraphicData;
229 void arm::Load(inputfile& SaveFile)
231 bodypart::Load(SaveFile);
232 SaveFile >> (int&)BaseUnarmedStrength;
233 SaveFile >> StrengthExperience >> DexterityExperience;
234 SaveFile >> WieldedSlot >> GauntletSlot >> RingSlot;
235 SaveFile >> WieldedGraphicData;
238 void leg::Save(outputfile& SaveFile) const
240 bodypart::Save(SaveFile);
241 SaveFile << BaseKickStrength << StrengthExperience << AgilityExperience;
242 SaveFile << BootSlot;
245 void leg::Load(inputfile& SaveFile)
247 bodypart::Load(SaveFile);
248 SaveFile >> BaseKickStrength >> StrengthExperience >> AgilityExperience;
249 SaveFile >> BootSlot;
252 truth bodypart::ReceiveDamage(character* Damager, int Damage, int Type, int)
254 if(Master)
256 if(Type & POISON && !IsAlive())
257 return false;
259 int BHP = HP;
261 if(HP <= Damage && !CanBeSevered(Type))
262 Damage = GetHP() - 1;
264 if(!Damage)
265 return false;
267 EditHP(1, -Damage);
269 if(Type & DRAIN && IsAlive())
270 for(int c = 0; c < Damage; ++c)
271 Damager->HealHitPoint();
273 truth WasBadlyHurt = IsBadlyHurt();
275 if(HP <= 0)
276 return true;
278 if(DamageTypeCanScar(Type) && !(RAND_N(25 + 25 * HP / MaxHP)))
279 GenerateScar(Damage, Type);
281 if (Master->IsPlayer()) {
282 if (HP == 1 && BHP > 1) {
283 if (IsAlive()) ADD_MESSAGE("Your %s bleeds very badly.", GetBodyPartName().CStr());
284 else ADD_MESSAGE("Your %s is in very bad condition.", GetBodyPartName().CStr());
285 if (Master->BodyPartIsVital(GetBodyPartIndex())) game::AskForEscPress(CONST_S("Vital bodypart in serious danger!"));
286 } else if (IsBadlyHurt() && !WasBadlyHurt) {
287 if (IsAlive()) ADD_MESSAGE("Your %s bleeds.", GetBodyPartName().CStr());
288 else ADD_MESSAGE("Your %s is in bad condition.", GetBodyPartName().CStr());
289 if (Master->BodyPartIsVital(GetBodyPartIndex())) game::AskForEscPress(CONST_S("Vital bodypart in danger!"));
292 SignalPossibleUsabilityChange();
295 return false;
298 truth bodypart::CanBeSevered(int Type) const
300 if((HP == MaxHP && HP != 1 && !Master->IsExtraFragile())
301 || (Type & (POISON|SOUND) && GetBodyPartIndex() != TORSO_INDEX))
302 return false;
304 if(!Master->BodyPartIsVital(GetBodyPartIndex()) || Master->IsExtraFragile())
305 return true;
307 bodypart* Torso = Master->GetTorso();
308 return Torso->HP != Torso->MaxHP || Torso->HP == 1;
311 double arm::GetUnarmedDamage() const
313 double WeaponStrength = GetBaseUnarmedStrength() * GetBaseUnarmedStrength();
314 item* Gauntlet = GetGauntlet();
316 if(Gauntlet)
317 WeaponStrength += Gauntlet->GetWeaponStrength();
319 double Base = sqrt(5e-5 * WeaponStrength);
321 if(Gauntlet)
322 Base += Gauntlet->GetDamageBonus();
324 double Damage = Base * sqrt(1e-7 * GetAttribute(ARM_STRENGTH))
325 * GetHumanoidMaster()->GetCWeaponSkill(UNARMED)->GetBonus();
327 return Damage;
330 double arm::GetUnarmedToHitValue() const
332 double BonusMultiplier = 10.;
333 item* Gauntlet = GetGauntlet();
335 if(Gauntlet)
336 BonusMultiplier += Gauntlet->GetTHVBonus();
338 return GetAttribute(DEXTERITY)
339 * sqrt(2.5 * Master->GetAttribute(PERCEPTION))
340 * GetHumanoidMaster()->GetCWeaponSkill(UNARMED)->GetBonus()
341 * Master->GetMoveEase()
342 * BonusMultiplier / 5000000;
345 sLong arm::GetUnarmedAPCost() const
347 return sLong(10000000000. / (APBonus(GetAttribute(DEXTERITY)) * Master->GetMoveEase() * Master->GetCWeaponSkill(UNARMED)->GetBonus()));
350 void arm::CalculateDamage()
352 if(!Master)
353 return;
355 if(!IsUsable())
356 Damage = 0;
357 else if(GetWielded())
358 Damage = GetWieldedDamage();
359 else if(PairArmAllowsMelee())
360 Damage = GetUnarmedDamage();
361 else
362 Damage = 0;
365 void arm::CalculateToHitValue()
367 if(!Master)
368 return;
370 if(GetWielded())
371 ToHitValue = GetWieldedToHitValue();
372 else if(PairArmAllowsMelee())
373 ToHitValue = GetUnarmedToHitValue();
374 else
375 ToHitValue = 0;
378 void arm::CalculateAPCost()
380 if(!Master)
381 return;
383 if(GetWielded())
384 APCost = GetWieldedAPCost();
385 else if(PairArmAllowsMelee())
386 APCost = GetUnarmedAPCost();
387 else return;
389 if(APCost < 100)
390 APCost = 100;
393 truth arm::PairArmAllowsMelee() const
395 const arm* PairArm = GetPairArm();
396 return !PairArm || !PairArm->IsUsable() || !PairArm->GetWielded()
397 || PairArm->GetWielded()->IsShield(Master);
400 double arm::GetWieldedDamage() const
402 citem* Wielded = GetWielded();
404 if(Wielded->IsShield(Master))
405 return 0;
407 int HitStrength = GetAttribute(ARM_STRENGTH);
408 int Requirement = Wielded->GetStrengthRequirement();
410 if(TwoHandWieldIsActive())
412 HitStrength += GetPairArm()->GetAttribute(ARM_STRENGTH);
413 Requirement >>= 2;
416 if(HitStrength > Requirement)
418 /* I have no idea whether this works. It needs to be checked */
420 return Wielded->GetBaseDamage() * sqrt(1e-13 * HitStrength)
421 * GetCurrentSWeaponSkillBonus()
422 * GetHumanoidMaster()->GetCWeaponSkill(Wielded->GetWeaponCategory())->GetBonus();
424 else
425 return 0;
428 double arm::GetWieldedToHitValue() const
430 int HitStrength = GetWieldedHitStrength();
432 if(HitStrength <= 0)
433 return 0;
435 citem* Wielded = GetWielded();
437 double Base = 2e-11
438 * Min(HitStrength, 10)
439 * GetHumanoidMaster()->GetCWeaponSkill(Wielded->GetWeaponCategory())->GetBonus()
440 * GetCurrentSWeaponSkillBonus()
441 * Master->GetMoveEase()
442 * (10000. / (1000 + Wielded->GetWeight()) + Wielded->GetTHVBonus());
443 double ThisToHit = GetAttribute(DEXTERITY) * sqrt(2.5 * Master->GetAttribute(PERCEPTION));
444 const arm* PairArm = GetPairArm();
446 if(PairArm && PairArm->IsUsable())
448 citem* PairWielded = PairArm->GetWielded();
450 if(!PairWielded)
452 if(Wielded->IsTwoHanded() && !Wielded->IsShield(Master))
453 return Base * (ThisToHit + PairArm->GetAttribute(DEXTERITY)
454 * sqrt(2.5 * Master->GetAttribute(PERCEPTION))) / 2;
456 else if(!Wielded->IsShield(Master) && !PairWielded->IsShield(Master))
457 return Base * ThisToHit / (1.0 + (500.0 + PairWielded->GetWeight())
458 / (1000.0 + (Wielded->GetWeight() << 1)));
461 return Base * ThisToHit;
464 sLong arm::GetWieldedAPCost() const
466 citem* Wielded = GetWielded();
468 if(Wielded->IsShield(Master))
469 return 0;
471 int HitStrength = GetWieldedHitStrength();
473 if(HitStrength <= 0)
474 return 0;
476 return sLong(1 / (1e-14 * APBonus(GetAttribute(DEXTERITY)) * Master->GetMoveEase() * GetHumanoidMaster()->GetCWeaponSkill(Wielded->GetWeaponCategory())->GetBonus() * (GetCurrentSWeaponSkillBonus() * Min(HitStrength, 10))));
479 void head::CalculateDamage()
481 if(!Master)
482 return;
484 BiteDamage = 7.07e-6 * GetBaseBiteStrength() * GetHumanoidMaster()->GetCWeaponSkill(BITE)->GetBonus();
487 void head::CalculateToHitValue()
489 if(!Master)
490 return;
492 BiteToHitValue = Master->GetAttribute(AGILITY) * sqrt(2.5 * Master->GetAttribute(PERCEPTION)) * GetHumanoidMaster()->GetCWeaponSkill(KICK)->GetBonus() * Master->GetMoveEase() / 1000000;
495 void head::CalculateAPCost()
497 if(!Master)
498 return;
500 BiteAPCost = Max(sLong(10000000000. / (APBonus(Master->GetAttribute(AGILITY)) * Master->GetMoveEase() * Master->GetCWeaponSkill(BITE)->GetBonus())), 100);
503 void leg::CalculateDamage()
505 if(!Master)
506 return;
508 double WeaponStrength = GetBaseKickStrength() * GetBaseKickStrength();
509 item* Boot = GetBoot();
511 if(Boot)
512 WeaponStrength += Boot->GetWeaponStrength();
514 double Base = sqrt(5e-5 * WeaponStrength);
516 if(Boot)
517 Base += Boot->GetDamageBonus();
519 KickDamage = Base * sqrt(1e-7 * GetAttribute(LEG_STRENGTH))
520 * GetHumanoidMaster()->GetCWeaponSkill(KICK)->GetBonus();
523 void leg::CalculateToHitValue()
525 if(!Master)
526 return;
528 double BonusMultiplier = 10.;
529 item* Boot = GetBoot();
531 if(Boot)
532 BonusMultiplier += Boot->GetTHVBonus();
534 KickToHitValue = GetAttribute(AGILITY)
535 * sqrt(2.5 * Master->GetAttribute(PERCEPTION))
536 * GetHumanoidMaster()->GetCWeaponSkill(KICK)->GetBonus()
537 * Master->GetMoveEase()
538 * BonusMultiplier / 10000000;
541 void leg::CalculateAPCost()
543 if(!Master)
544 return;
546 KickAPCost = Max(sLong(20000000000. / (APBonus(GetAttribute(AGILITY)) * Master->GetMoveEase() * Master->GetCWeaponSkill(KICK)->GetBonus())), 100);
549 humanoid* bodypart::GetHumanoidMaster() const
551 return static_cast<humanoid*>(Master);
554 void corpse::Save(outputfile& SaveFile) const
556 item::Save(SaveFile);
557 SaveFile << Deceased;
560 void corpse::Load(inputfile& SaveFile)
562 item::Load(SaveFile);
563 SaveFile >> Deceased;
564 Deceased->SetMotherEntity(this);
565 Enable();
568 void corpse::AddPostFix(festring& String, int) const
570 String << " of ";
571 GetDeceased()->AddName(String, INDEFINITE);
574 int corpse::GetOfferValue(int Receiver) const
576 int OfferValue = 0;
578 for(int c = 0; c < GetDeceased()->GetBodyParts(); ++c)
580 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
582 if(BodyPart)
583 OfferValue += BodyPart->GetOfferValue(Receiver);
586 return OfferValue;
589 double corpse::GetWeaponStrength() const
591 return GetFormModifier() * GetDeceased()->GetTorso()->GetMainMaterial()->GetStrengthValue() * sqrt(GetDeceased()->GetTorso()->GetMainMaterial()->GetWeight());
594 truth corpse::CanBeEatenByAI(ccharacter* Eater) const
596 for(int c = 0; c < GetDeceased()->GetBodyParts(); ++c)
598 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
600 if(BodyPart && !BodyPart->CanBeEatenByAI(Eater))
601 return false;
604 return true;
607 int corpse::GetStrengthValue() const
609 return sLong(GetStrengthModifier()) * GetDeceased()->GetTorso()->GetMainMaterial()->GetStrengthValue() / 2000;
612 corpse::~corpse()
614 delete Deceased;
617 col16 corpse::GetMaterialColorA(int) const
619 return GetDeceased()->GetTorso()->GetMainMaterial()->GetColor();
622 alpha corpse::GetAlphaA(int) const
624 return GetDeceased()->GetTorso()->GetMainMaterial()->GetAlpha();
627 col16 corpse::GetMaterialColorB(int) const
629 torso* Torso = GetDeceased()->GetTorso();
630 return Torso->IsAlive() ? material::GetDataBase(GetDeceased()->GetBloodMaterial())->Color : Torso->GetMainMaterial()->GetColor();
633 alpha corpse::GetAlphaB(int) const
635 torso* Torso = GetDeceased()->GetTorso();
636 return Torso->IsAlive() ? 175 : Torso->GetMainMaterial()->GetAlpha();
639 int corpse::GetSparkleFlags() const
641 torso* Torso = GetDeceased()->GetTorso();
642 material* Material = Torso->GetMainMaterial();
643 return Material->IsSparkling() ? SPARKLING_A|(!Torso->IsAlive() ? SPARKLING_B : 0) : 0;
646 v2 corpse::GetBitmapPos(int) const
648 if(GetDeceased()->GetSize() < 50)
649 return v2(32, 64);
650 else if(GetDeceased()->GetSize() < 150)
651 return v2(16, 192);
652 else
653 return v2(16, 272);
656 int corpse::GetSize() const
658 return GetDeceased()->GetSize();
661 void corpse::SetDeceased(character* What)
663 Deceased = What;
664 Deceased->SetMotherEntity(this);
665 SignalVolumeAndWeightChange();
666 SignalEmitationIncrease(Deceased->GetEmitation());
667 UpdatePictures();
668 Enable();
671 void head::DropEquipment(stack* Stack)
673 if(Stack)
675 if(GetHelmet())
676 GetHelmet()->MoveTo(Stack);
678 if(GetAmulet())
679 GetAmulet()->MoveTo(Stack);
681 else
683 if(GetHelmet())
684 GetSlot()->AddFriendItem(GetHelmet());
686 if(GetAmulet())
687 GetSlot()->AddFriendItem(GetAmulet());
691 void humanoidtorso::DropEquipment(stack* Stack)
693 if(Stack)
695 if(GetBodyArmor())
696 GetBodyArmor()->MoveTo(Stack);
698 if(GetCloak())
699 GetCloak()->MoveTo(Stack);
701 if(GetBelt())
702 GetBelt()->MoveTo(Stack);
704 else
706 if(GetBodyArmor())
707 GetSlot()->AddFriendItem(GetBodyArmor());
709 if(GetCloak())
710 GetSlot()->AddFriendItem(GetCloak());
712 if(GetBelt())
713 GetSlot()->AddFriendItem(GetBelt());
717 void arm::DropEquipment(stack* Stack)
719 if(Stack)
721 if(GetWielded())
722 GetWielded()->MoveTo(Stack);
724 if(GetGauntlet())
725 GetGauntlet()->MoveTo(Stack);
727 if(GetRing())
728 GetRing()->MoveTo(Stack);
730 else
732 if(GetWielded())
733 GetSlot()->AddFriendItem(GetWielded());
735 if(GetGauntlet())
736 GetSlot()->AddFriendItem(GetGauntlet());
738 if(GetRing())
739 GetSlot()->AddFriendItem(GetRing());
743 void leg::DropEquipment(stack* Stack)
745 if(Stack)
747 if(GetBoot())
748 GetBoot()->MoveTo(Stack);
750 else
752 if(GetBoot())
753 GetSlot()->AddFriendItem(GetBoot());
757 head::~head()
759 delete GetHelmet();
760 delete GetAmulet();
763 humanoidtorso::~humanoidtorso()
765 delete GetBodyArmor();
766 delete GetCloak();
767 delete GetBelt();
770 arm::~arm()
772 delete GetWielded();
773 delete GetGauntlet();
774 delete GetRing();
777 leg::~leg()
779 delete GetBoot();
782 truth corpse::IsDestroyable(ccharacter* Char) const
784 for(int c = 0; c < GetDeceased()->GetBodyParts(); ++c)
786 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
788 if(BodyPart && !BodyPart->IsDestroyable(Char))
789 return false;
792 return true;
795 sLong corpse::GetTruePrice() const
797 sLong Price = 0;
799 for(int c = 0; c < GetDeceased()->GetBodyParts(); ++c)
801 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
803 if(BodyPart)
804 Price += BodyPart->GetTruePrice();
807 return Price;
810 material* corpse::GetMaterial(int I) const
812 return GetDeceased()->GetTorso()->GetMaterial(I);
815 int bodypart::GetSparkleFlags() const
817 return (GetMainMaterial()->SkinColorIsSparkling() ? SPARKLING_A : 0)
818 | (Flags >> BODYPART_SPARKLE_SHIFT & (SPARKLING_B|SPARKLING_C|SPARKLING_D));
821 truth corpse::RaiseTheDead(character* Summoner)
823 if(Summoner && Summoner->IsPlayer())
824 game::DoEvilDeed(50);
826 GetDeceased()->Enable();
828 if(GetDeceased()->TryToRiseFromTheDead())
830 v2 Pos = GetPos();
831 RemoveFromSlot();
832 GetDeceased()->SetMotherEntity(0);
834 if(Summoner && GetDeceased()->IsCharmable() && !GetDeceased()->IsPlayer())
835 GetDeceased()->ChangeTeam(Summoner->GetTeam());
837 GetDeceased()->PutToOrNear(Pos);
838 GetDeceased()->SignalStepFrom(0);
839 Deceased = 0;
840 SendToHell();
841 return true;
843 else
845 GetDeceased()->Disable();
846 return false;
850 head::head()
852 HelmetSlot.Init(this, HELMET_INDEX);
853 AmuletSlot.Init(this, AMULET_INDEX);
856 humanoidtorso::humanoidtorso()
858 BodyArmorSlot.Init(this, BODY_ARMOR_INDEX);
859 CloakSlot.Init(this, CLOAK_INDEX);
860 BeltSlot.Init(this, BELT_INDEX);
863 rightarm::rightarm()
865 WieldedSlot.Init(this, RIGHT_WIELDED_INDEX);
866 GauntletSlot.Init(this, RIGHT_GAUNTLET_INDEX);
867 RingSlot.Init(this, RIGHT_RING_INDEX);
870 leftarm::leftarm()
872 WieldedSlot.Init(this, LEFT_WIELDED_INDEX);
873 GauntletSlot.Init(this, LEFT_GAUNTLET_INDEX);
874 RingSlot.Init(this, LEFT_RING_INDEX);
877 rightleg::rightleg()
879 BootSlot.Init(this, RIGHT_BOOT_INDEX);
882 leftleg::leftleg()
884 BootSlot.Init(this, LEFT_BOOT_INDEX);
887 void arm::Hit(character* Enemy, v2 HitPos, int Direction, int Flags)
889 sLong StrExp = 50, DexExp = 50;
890 truth THW = false;
891 item* Wielded = GetWielded();
893 if(Wielded)
895 sLong Weight = Wielded->GetWeight();
896 StrExp = Limit(15 * Weight / 200, 75, 300);
897 DexExp = Weight ? Limit(75000 / Weight, 75, 300) : 300;
898 THW = TwoHandWieldIsActive();
901 switch(Enemy->TakeHit(Master, Wielded ? Wielded : GetGauntlet(), this, HitPos, GetTypeDamage(Enemy), GetToHitValue(), RAND() % 26 - RAND() % 26, Wielded ? WEAPON_ATTACK : UNARMED_ATTACK, Direction, !(RAND() % Master->GetCriticalModifier()), Flags & SADIST_HIT))
903 case HAS_HIT:
904 case HAS_BLOCKED:
905 case HAS_DIED:
906 case DID_NO_DAMAGE:
907 EditExperience(ARM_STRENGTH, StrExp, 1 << 9);
909 if(THW && GetPairArm())
910 GetPairArm()->EditExperience(ARM_STRENGTH, StrExp, 1 << 9);
912 case HAS_DODGED:
913 EditExperience(DEXTERITY, DexExp, 1 << 9);
915 if(THW && GetPairArm())
916 GetPairArm()->EditExperience(DEXTERITY, DexExp, 1 << 9);
920 int arm::GetAttribute(int Identifier, truth AllowBonus) const
922 if(Identifier == ARM_STRENGTH)
924 int Base = !UseMaterialAttributes()
925 ? int(StrengthExperience * EXP_DIVISOR)
926 : GetMainMaterial()->GetStrengthValue();
928 if(AllowBonus)
929 Base += StrengthBonus;
931 return Max(!IsBadlyHurt() || !AllowBonus ? Base : Base / 3, 1);
933 else if(Identifier == DEXTERITY)
935 int Base = !UseMaterialAttributes()
936 ? int(DexterityExperience * EXP_DIVISOR)
937 : GetMainMaterial()->GetFlexibility() << 2;
939 if(AllowBonus)
940 Base += DexterityBonus;
942 return Max(IsUsable() || !AllowBonus ? Base : Base / 3, 1);
944 else
946 ABORT("Illegal arm attribute %d request!", Identifier);
947 return 0xACCA;
951 truth arm::EditAttribute(int Identifier, int Value)
953 if(!Master)
954 return false;
956 if(Identifier == ARM_STRENGTH)
958 if(!UseMaterialAttributes()
959 && Master->RawEditAttribute(StrengthExperience, Value))
961 Master->CalculateBattleInfo();
963 if(Master->IsPlayerKind())
964 UpdatePictures();
966 return true;
969 else if(Identifier == DEXTERITY)
970 if(!UseMaterialAttributes()
971 && Master->RawEditAttribute(DexterityExperience, Value))
973 Master->CalculateBattleInfo();
974 return true;
977 return false;
980 void arm::EditExperience(int Identifier, double Value, double Speed)
982 if(!Master)
983 return;
985 if(Identifier == ARM_STRENGTH)
987 if(!UseMaterialAttributes())
989 int Change = Master->RawEditExperience(StrengthExperience,
990 Master->GetNaturalExperience(ARM_STRENGTH),
991 Value, Speed);
993 if(Change)
995 cchar* Adj = Change > 0 ? "stronger" : "weaker";
997 if(Master->IsPlayer())
998 ADD_MESSAGE("Your %s feels %s!", GetBodyPartName().CStr(), Adj);
999 else if(Master->IsPet() && Master->CanBeSeenByPlayer())
1000 ADD_MESSAGE("Suddenly %s looks %s.", Master->CHAR_NAME(DEFINITE), Adj);
1002 Master->CalculateBattleInfo();
1004 if(Master->IsPlayerKind())
1005 UpdatePictures();
1009 else if(Identifier == DEXTERITY)
1011 if(!UseMaterialAttributes())
1013 int Change = Master->RawEditExperience(DexterityExperience,
1014 Master->GetNaturalExperience(DEXTERITY),
1015 Value, Speed);
1017 if(Change)
1019 cchar* Adj = Change > 0 ? "quite dextrous" : "clumsy";
1021 if(Master->IsPlayer())
1022 ADD_MESSAGE("Your %s feels %s!", GetBodyPartName().CStr(), Adj);
1023 else if(Master->IsPet() && Master->CanBeSeenByPlayer())
1024 ADD_MESSAGE("Suddenly %s looks %s.", Master->CHAR_NAME(DEFINITE), Adj);
1026 Master->CalculateBattleInfo();
1030 else
1031 ABORT("Illegal arm attribute %d experience edit request!", Identifier);
1034 int leg::GetAttribute(int Identifier, truth AllowBonus) const
1036 if(Identifier == LEG_STRENGTH)
1038 int Base = !UseMaterialAttributes()
1039 ? int(StrengthExperience * EXP_DIVISOR)
1040 : GetMainMaterial()->GetStrengthValue();
1042 if(AllowBonus)
1043 Base += StrengthBonus;
1045 return Max(!IsBadlyHurt() || !AllowBonus ? Base : Base / 3, 1);
1047 else if(Identifier == AGILITY)
1049 int Base = !UseMaterialAttributes()
1050 ? int(AgilityExperience * EXP_DIVISOR)
1051 : GetMainMaterial()->GetFlexibility() << 2;
1053 if(AllowBonus)
1054 Base += AgilityBonus;
1056 return Max(IsUsable() || !AllowBonus ? Base : Base / 3, 1);
1058 else
1060 ABORT("Illegal leg attribute %d request!", Identifier);
1061 return 0xECCE;
1065 truth leg::EditAttribute(int Identifier, int Value)
1067 if(!Master)
1068 return false;
1070 if(Identifier == LEG_STRENGTH)
1072 if(!UseMaterialAttributes()
1073 && Master->RawEditAttribute(StrengthExperience, Value))
1075 Master->CalculateBurdenState();
1076 Master->CalculateBattleInfo();
1077 return true;
1080 else if(Identifier == AGILITY)
1081 if(!UseMaterialAttributes()
1082 && Master->RawEditAttribute(AgilityExperience, Value))
1084 Master->CalculateBattleInfo();
1085 return true;
1088 return false;
1091 void leg::EditExperience(int Identifier, double Value, double Speed)
1093 if(!Master)
1094 return;
1096 if(Identifier == LEG_STRENGTH)
1098 if(!UseMaterialAttributes())
1100 int Change = Master->RawEditExperience(StrengthExperience,
1101 Master->GetNaturalExperience(LEG_STRENGTH),
1102 Value, Speed);
1104 if(Change)
1106 cchar* Adj = Change > 0 ? "stronger" : "weaker";
1108 if(Master->IsPlayer())
1109 ADD_MESSAGE("Your %s feels %s!", GetBodyPartName().CStr(), Adj);
1110 else if(Master->IsPet() && Master->CanBeSeenByPlayer())
1111 ADD_MESSAGE("Suddenly %s looks %s.", Master->CHAR_NAME(DEFINITE), Adj);
1113 Master->CalculateBurdenState();
1114 Master->CalculateBattleInfo();
1118 else if(Identifier == AGILITY)
1120 if(!UseMaterialAttributes())
1122 int Change = Master->RawEditExperience(AgilityExperience,
1123 Master->GetNaturalExperience(AGILITY),
1124 Value, Speed);
1126 if(Change)
1128 cchar* Adj = Change > 0 ? "very agile" : "slower";
1130 if(Master->IsPlayer())
1131 ADD_MESSAGE("Your %s feels %s!", GetBodyPartName().CStr(), Adj);
1132 else if(Master->IsPet() && Master->CanBeSeenByPlayer())
1133 ADD_MESSAGE("Suddenly %s looks %s.", Master->CHAR_NAME(DEFINITE), Adj);
1135 Master->CalculateBattleInfo();
1139 else
1140 ABORT("Illegal leg attribute %d experience edit request!", Identifier);
1143 void head::InitSpecialAttributes()
1145 BaseBiteStrength = Master->GetBaseBiteStrength();
1148 void arm::InitSpecialAttributes()
1150 if(!Master->IsHuman() || Master->IsInitializing())
1152 StrengthExperience = Master->GetNaturalExperience(ARM_STRENGTH);
1153 DexterityExperience = Master->GetNaturalExperience(DEXTERITY);
1155 else
1157 StrengthExperience = game::GetAveragePlayerArmStrengthExperience();
1158 DexterityExperience = game::GetAveragePlayerDexterityExperience();
1161 LimitRef(StrengthExperience, MIN_EXP, MAX_EXP);
1162 LimitRef(DexterityExperience, MIN_EXP, MAX_EXP);
1163 BaseUnarmedStrength = Master->GetBaseUnarmedStrength();
1166 void leg::InitSpecialAttributes()
1168 if(!Master->IsHuman() || Master->IsInitializing())
1170 StrengthExperience = Master->GetNaturalExperience(LEG_STRENGTH);
1171 AgilityExperience = Master->GetNaturalExperience(AGILITY);
1173 else
1175 StrengthExperience = game::GetAveragePlayerLegStrengthExperience();
1176 AgilityExperience = game::GetAveragePlayerAgilityExperience();
1179 LimitRef(StrengthExperience, MIN_EXP, MAX_EXP);
1180 LimitRef(AgilityExperience, MIN_EXP, MAX_EXP);
1181 BaseKickStrength = Master->GetBaseKickStrength();
1184 void bodypart::SignalEquipmentAdd(gearslot* Slot)
1186 if(Master)
1187 Master->SignalEquipmentAdd(Slot->GetEquipmentIndex());
1190 void bodypart::SignalEquipmentRemoval(gearslot* Slot, citem* Item)
1192 if(Master)
1193 Master->SignalEquipmentRemoval(Slot->GetEquipmentIndex(), Item);
1196 void bodypart::Mutate()
1198 GetMainMaterial()->SetVolume(sLong(GetVolume() * (1.5 - (RAND() & 1023) / 1023.)));
1201 void arm::Mutate()
1203 bodypart::Mutate();
1204 StrengthExperience = StrengthExperience * (1.5 - (RAND() & 1023) / 1023.);
1205 DexterityExperience = DexterityExperience * (1.5 - (RAND() & 1023) / 1023.);
1206 LimitRef(StrengthExperience, MIN_EXP, MAX_EXP);
1207 LimitRef(DexterityExperience, MIN_EXP, MAX_EXP);
1210 void leg::Mutate()
1212 bodypart::Mutate();
1213 StrengthExperience = StrengthExperience * (1.5 - (RAND() & 1023) / 1023.);
1214 AgilityExperience = AgilityExperience * (1.5 - (RAND() & 1023) / 1023.);
1215 LimitRef(StrengthExperience, MIN_EXP, MAX_EXP);
1216 LimitRef(AgilityExperience, MIN_EXP, MAX_EXP);
1219 arm* rightarm::GetPairArm() const
1221 return GetHumanoidMaster() ? GetHumanoidMaster()->GetLeftArm() : 0;
1224 arm* leftarm::GetPairArm() const
1226 return GetHumanoidMaster() ? GetHumanoidMaster()->GetRightArm() : 0;
1229 sweaponskill** rightarm::GetCurrentSWeaponSkill() const
1231 return &GetHumanoidMaster()->CurrentRightSWeaponSkill;
1234 sweaponskill** leftarm::GetCurrentSWeaponSkill() const
1236 return &GetHumanoidMaster()->CurrentLeftSWeaponSkill;
1239 alpha bodypart::GetMaxAlpha() const
1241 if(Master && Master->StateIsActivated(INVISIBLE))
1242 return 150;
1243 else
1244 return 255;
1247 void bodypart::AddPostFix(festring& String, int) const
1249 if(!OwnerDescription.IsEmpty())
1250 String << ' ' << OwnerDescription;
1253 void corpse::CalculateVolumeAndWeight()
1255 Volume = Deceased->GetVolume();
1256 Weight = Deceased->GetWeight();
1259 item* head::GetEquipment(int I) const
1261 switch(I)
1263 case 0: return GetHelmet();
1264 case 1: return GetAmulet();
1267 return 0;
1270 item* humanoidtorso::GetEquipment(int I) const
1272 switch(I)
1274 case 0: return GetBodyArmor();
1275 case 1: return GetCloak();
1276 case 2: return GetBelt();
1279 return 0;
1282 item* arm::GetEquipment(int I) const
1284 switch(I)
1286 case 0: return GetWielded();
1287 case 1: return GetGauntlet();
1288 case 2: return GetRing();
1291 return 0;
1294 item* leg::GetEquipment(int I) const
1296 return !I ? GetBoot() : 0;
1299 void bodypart::CalculateVolumeAndWeight()
1301 item::CalculateVolumeAndWeight();
1302 CarriedWeight = 0;
1303 BodyPartVolume = Volume;
1305 for(int c = 0; c < GetEquipments(); ++c)
1307 item* Equipment = GetEquipment(c);
1309 if(Equipment)
1311 Volume += Equipment->GetVolume();
1312 CarriedWeight += Equipment->GetWeight();
1316 Weight += CarriedWeight;
1319 void corpse::CalculateEmitation()
1321 Emitation = Deceased->GetEmitation();
1324 void bodypart::CalculateEmitation()
1326 item::CalculateEmitation();
1328 for(int c = 0; c < GetEquipments(); ++c)
1330 item* Equipment = GetEquipment(c);
1332 if(Equipment)
1333 game::CombineLights(Emitation, Equipment->GetEmitation());
1337 void bodypart::CalculateMaxHP(feuLong Flags)
1339 int HPDelta = MaxHP - HP/*k8, OldMaxHP = MaxHP*/;
1340 MaxHP = 0;
1342 if(Master)
1344 if(!UseMaterialAttributes())
1346 sLong Endurance = Master->GetAttribute(ENDURANCE);
1347 double DoubleHP = GetBodyPartVolume() * Endurance * Endurance / 200000;
1349 for(unsigned int c = 0; c < Scar.size(); ++c)
1350 DoubleHP *= (100. - Scar[c].Severity * 4) / 100;
1352 MaxHP = int(DoubleHP);
1354 else
1356 sLong SV = GetMainMaterial()->GetStrengthValue();
1357 MaxHP = (GetBodyPartVolume() * SV >> 4) * SV / 250000;
1360 if(MaxHP < 1)
1361 MaxHP = 1;
1363 if(Flags & MAY_CHANGE_HPS)
1365 if(MaxHP - HPDelta > 1)
1366 HP = MaxHP - HPDelta;
1367 else
1368 HP = 1;
1370 else
1372 //OldMaxHP - MaxHP;
1375 if(Flags & CHECK_USABILITY)
1376 SignalPossibleUsabilityChange();
1380 void bodypart::SignalVolumeAndWeightChange()
1382 item::SignalVolumeAndWeightChange();
1384 if(Master && !Master->IsInitializing())
1386 CalculateMaxHP();
1387 Master->CalculateHP();
1388 Master->CalculateMaxHP();
1389 Master->SignalBodyPartVolumeAndWeightChange();
1390 square* SquareUnder = GetSquareUnder();
1392 if(UpdateArmorPictures() && SquareUnder)
1393 SquareUnder->SendNewDrawRequest();
1398 for(;;)
1400 damageid& D = DamageID.back();
1405 void bodypart::SetHP(int What)
1407 HP = What;
1409 if(Master)
1411 Master->CalculateHP();
1412 SignalPossibleUsabilityChange();
1416 void bodypart::EditHP(int SrcID, int What)
1418 HP += What;
1420 if(What < 0)
1421 RemoveDamageIDs(-What);
1422 else
1423 AddDamageID(SrcID, What);
1425 if(Master)
1427 Master->CalculateHP();
1428 SignalPossibleUsabilityChange();
1432 void arm::SignalVolumeAndWeightChange()
1434 bodypart::SignalVolumeAndWeightChange();
1436 if(Master && !Master->IsInitializing())
1438 GetHumanoidMaster()->EnsureCurrentSWeaponSkillIsCorrect(*GetCurrentSWeaponSkill(), GetWielded());
1439 CalculateAttributeBonuses();
1440 CalculateAttackInfo();
1441 UpdateWieldedPicture();
1443 if(GetSquareUnder())
1444 GetSquareUnder()->SendNewDrawRequest();
1448 void leg::SignalVolumeAndWeightChange()
1450 bodypart::SignalVolumeAndWeightChange();
1452 if(Master && !Master->IsInitializing())
1454 CalculateAttributeBonuses();
1455 CalculateAttackInfo();
1459 void humanoidtorso::SignalVolumeAndWeightChange()
1461 bodypart::SignalVolumeAndWeightChange();
1463 if(Master && !Master->IsInitializing())
1465 humanoid* HumanoidMaster = GetHumanoidMaster();
1467 if(HumanoidMaster->GetRightArm())
1468 HumanoidMaster->GetRightArm()->CalculateAttributeBonuses();
1470 if(HumanoidMaster->GetLeftArm())
1471 HumanoidMaster->GetLeftArm()->CalculateAttributeBonuses();
1473 if(HumanoidMaster->GetRightLeg())
1474 HumanoidMaster->GetRightLeg()->CalculateAttributeBonuses();
1476 if(HumanoidMaster->GetLeftLeg())
1477 HumanoidMaster->GetLeftLeg()->CalculateAttributeBonuses();
1481 void bodypart::CalculateAttackInfo()
1483 CalculateDamage();
1484 CalculateToHitValue();
1485 CalculateAPCost();
1488 truth arm::TwoHandWieldIsActive() const
1490 citem* Wielded = GetWielded();
1492 if(Wielded->IsTwoHanded() && !Wielded->IsShield(Master))
1494 arm* PairArm = GetPairArm();
1495 return PairArm && PairArm->IsUsable() && !PairArm->GetWielded();
1497 else
1498 return false;
1501 double bodypart::GetTimeToDie(int Damage, double ToHitValue, double DodgeValue, truth AttackIsBlockable, truth UseMaxHP) const
1503 double Durability;
1504 int TotalResistance = GetTotalResistance(PHYSICAL_DAMAGE);
1505 int Damage3 = (Damage << 1) + Damage;
1506 int Damage5 = (Damage << 2) + Damage;
1507 int TrueDamage = (19 * (Max((Damage3 >> 2) - TotalResistance, 0)
1508 + Max((Damage5 >> 2) + 1 - (TotalResistance >> 1), 0))
1509 + (Max(((Damage3 + (Damage3 >> 1)) >> 2) - TotalResistance, 0)
1510 + Max(((Damage5 + (Damage5 >> 1)) >> 2) + 3 - (TotalResistance >> 1), 0))) / 40;
1512 int HP = UseMaxHP ? GetMaxHP() : GetHP();
1514 if(TrueDamage > 0)
1516 double AverageDamage;
1518 if(AttackIsBlockable)
1520 blockvector Block;
1521 Master->CreateBlockPossibilityVector(Block, ToHitValue);
1523 if(Block.size())
1525 double ChanceForNoBlock = 1.0;
1526 AverageDamage = 0;
1528 for(uInt c = 0; c < Block.size(); ++c)
1530 ChanceForNoBlock -= Block[c].first;
1532 if(TrueDamage - Block[c].second > 0)
1533 AverageDamage += Block[c].first * (TrueDamage - Block[c].second);
1536 AverageDamage += ChanceForNoBlock * TrueDamage;
1538 else
1539 AverageDamage = TrueDamage;
1541 else
1542 AverageDamage = TrueDamage;
1544 Durability = HP / (AverageDamage * GetRoughChanceToHit(ToHitValue, DodgeValue));
1546 if(Durability < 1)
1547 Durability = 1;
1549 if(Durability > 1000)
1550 Durability = 1000;
1552 else
1553 Durability = 1000;
1555 return Durability;
1558 double bodypart::GetRoughChanceToHit(double ToHitValue, double DodgeValue) const
1560 return GLOBAL_WEAK_BODYPART_HIT_MODIFIER * ToHitValue * GetBodyPartVolume() / ((DodgeValue / ToHitValue + 1) * DodgeValue * Master->GetBodyVolume() * 100);
1563 double torso::GetRoughChanceToHit(double ToHitValue, double DodgeValue) const
1565 return 1 / (DodgeValue / ToHitValue + 1);
1568 void bodypart::RandomizePosition()
1570 SpecialFlags |= 1 + RAND() % 7;
1571 UpdatePictures();
1574 double arm::GetBlockChance(double EnemyToHitValue) const
1576 citem* Wielded = GetWielded();
1577 return Wielded ? Min(1.0 / (1 + EnemyToHitValue / (GetToHitValue() * Wielded->GetBlockModifier()) * 10000), 1.0) : 0;
1580 int arm::GetBlockCapability() const
1582 citem* Wielded = GetWielded();
1584 if(!Wielded)
1585 return 0;
1587 int HitStrength = GetWieldedHitStrength();
1589 if(HitStrength <= 0)
1590 return 0;
1592 return Min(HitStrength, 10) * Wielded->GetStrengthValue() * GetHumanoidMaster()->GetCWeaponSkill(Wielded->GetWeaponCategory())->GetBonus() * (*GetCurrentSWeaponSkill())->GetBonus() / 10000000;
1595 void arm::WieldedSkillHit(int Hits)
1597 item* Wielded = GetWielded();
1599 if(Master->GetCWeaponSkill(Wielded->GetWeaponCategory())->AddHit(Hits))
1601 CalculateAttackInfo();
1603 if(Master->IsPlayer())
1605 int Category = Wielded->GetWeaponCategory();
1606 GetHumanoidMaster()->GetCWeaponSkill(Category)->AddLevelUpMessage(Category);
1610 if((*GetCurrentSWeaponSkill())->AddHit(Hits))
1612 CalculateAttackInfo();
1614 if(Master->IsPlayer())
1615 (*GetCurrentSWeaponSkill())->AddLevelUpMessage(Wielded->CHAR_NAME(UNARTICLED));
1619 head::head(const head& Head) : mybase(Head), BaseBiteStrength(Head.BaseBiteStrength)
1621 HelmetSlot.Init(this, HELMET_INDEX);
1622 AmuletSlot.Init(this, AMULET_INDEX);
1625 humanoidtorso::humanoidtorso(const humanoidtorso& Torso) : mybase(Torso)
1627 BodyArmorSlot.Init(this, BODY_ARMOR_INDEX);
1628 CloakSlot.Init(this, CLOAK_INDEX);
1629 BeltSlot.Init(this, BELT_INDEX);
1632 arm::arm(const arm& Arm) : mybase(Arm), StrengthExperience(Arm.StrengthExperience), DexterityExperience(Arm.DexterityExperience), BaseUnarmedStrength(Arm.BaseUnarmedStrength)
1636 rightarm::rightarm(const rightarm& Arm) : mybase(Arm)
1638 WieldedSlot.Init(this, RIGHT_WIELDED_INDEX);
1639 GauntletSlot.Init(this, RIGHT_GAUNTLET_INDEX);
1640 RingSlot.Init(this, RIGHT_RING_INDEX);
1643 leftarm::leftarm(const leftarm& Arm) : mybase(Arm)
1645 WieldedSlot.Init(this, LEFT_WIELDED_INDEX);
1646 GauntletSlot.Init(this, LEFT_GAUNTLET_INDEX);
1647 RingSlot.Init(this, LEFT_RING_INDEX);
1650 leg::leg(const leg& Leg) : mybase(Leg), StrengthExperience(Leg.StrengthExperience), AgilityExperience(Leg.AgilityExperience), BaseKickStrength(Leg.BaseKickStrength)
1654 rightleg::rightleg(const rightleg& Leg) : mybase(Leg)
1656 BootSlot.Init(this, RIGHT_BOOT_INDEX);
1659 leftleg::leftleg(const leftleg& Leg) : mybase(Leg)
1661 BootSlot.Init(this, LEFT_BOOT_INDEX);
1664 corpse::corpse(const corpse& Corpse) : mybase(Corpse)
1666 Deceased = Corpse.Deceased->Duplicate();
1667 Deceased->SetMotherEntity(this);
1670 void bodypart::SignalSpoil(material* Material)
1672 if(Master)
1673 Master->SignalSpoil();
1674 else
1675 item::SignalSpoil(Material);
1678 void corpse::SignalSpoil(material*)
1680 GetDeceased()->Disappear(this, "spoil", &item::IsVeryCloseToSpoiling);
1683 void corpse::SignalDisappearance()
1685 GetDeceased()->Disappear(this, "disappear", &item::IsVeryCloseToDisappearance);
1688 truth bodypart::CanBePiledWith(citem* Item, ccharacter* Viewer) const
1690 return item::CanBePiledWith(Item, Viewer)
1691 && OwnerDescription == static_cast<const bodypart*>(Item)->OwnerDescription;
1694 truth corpse::CanBePiledWith(citem* Item, ccharacter* Viewer) const
1696 if(GetType() != Item->GetType()
1697 || GetConfig() != Item->GetConfig()
1698 || GetWeight() != Item->GetWeight()
1699 || Viewer->GetCWeaponSkillLevel(this) != Viewer->GetCWeaponSkillLevel(Item)
1700 || Viewer->GetSWeaponSkillLevel(this) != Viewer->GetSWeaponSkillLevel(Item))
1701 return false;
1703 const corpse* Corpse = static_cast<const corpse*>(Item);
1705 if(Deceased->GetBodyParts() != Corpse->Deceased->GetBodyParts())
1706 return false;
1708 for(int c = 0; c < Deceased->GetBodyParts(); ++c)
1710 bodypart* BodyPart1 = Deceased->GetBodyPart(c);
1711 bodypart* BodyPart2 = Corpse->Deceased->GetBodyPart(c);
1713 if(!BodyPart1 && !BodyPart2)
1714 continue;
1716 if(!BodyPart1 || !BodyPart2 || !BodyPart1->CanBePiledWith(BodyPart2, Viewer))
1717 return false;
1720 if(Deceased->GetName(UNARTICLED) != Corpse->Deceased->GetName(UNARTICLED))
1721 return false;
1723 return true;
1726 void bodypart::Be()
1728 if(Master)
1730 if(HP < MaxHP && ++SpillBloodCounter >= 4)
1732 if(Master->IsEnabled())
1734 if(IsBadlyHurt() && !Master->IsPolymorphed() && !(RAND() & 3))
1735 SpillBlood(1);
1737 else if(!Master->IsPolymorphed() && !(RAND() & 3))
1739 SpillBlood(1);
1740 HP += Max(((MaxHP - HP) >> 2), 1);
1743 SpillBloodCounter = 0;
1746 if(Master->AllowSpoil() || !Master->IsEnabled())
1747 MainMaterial->Be(ItemFlags);
1749 if (Exists() && LifeExpectancy) {
1750 if (LifeExpectancy == 1) Master->SignalDisappearance(); else --LifeExpectancy;
1753 else
1755 if(HP < MaxHP && ++SpillBloodCounter >= 4)
1757 if(!(RAND() & 3))
1759 SpillBlood(1);
1760 HP += Max(((MaxHP - HP) >> 2), 1);
1763 SpillBloodCounter = 0;
1766 item::Be();
1770 void bodypart::SpillBlood(int HowMuch, v2 Pos)
1772 if(HowMuch && (!Master || Master->SpillsBlood()) && (IsAlive() || MainMaterial->IsLiquid()) && !game::IsInWilderness())
1773 GetNearLSquare(Pos)->SpillFluid(0, CreateBlood(sLong(HowMuch * sqrt(BodyPartVolume) / 2)), false, false);
1776 void bodypart::SpillBlood(int HowMuch)
1778 if(HowMuch && (!Master || Master->SpillsBlood()) && (IsAlive() || MainMaterial->IsLiquid()) && !game::IsInWilderness())
1779 for(int c = 0; c < GetSquaresUnder(); ++c)
1780 if(GetLSquareUnder(c))
1781 GetLSquareUnder(c)->SpillFluid(0, CreateBlood(sLong(HowMuch * sqrt(BodyPartVolume) / 2)), false, false);
1784 void bodypart::SignalEnchantmentChange()
1786 if(Master && !Master->IsInitializing())
1788 Master->CalculateAttributeBonuses();
1789 Master->CalculateBattleInfo();
1793 void arm::SignalEquipmentAdd(gearslot* Slot)
1795 int EquipmentIndex = Slot->GetEquipmentIndex();
1797 if(Master && !Master->IsInitializing())
1799 item* Equipment = Slot->GetItem();
1801 if(Equipment->IsInCorrectSlot(EquipmentIndex))
1802 ApplyEquipmentAttributeBonuses(Equipment);
1804 if(EquipmentIndex == RIGHT_GAUNTLET_INDEX || EquipmentIndex == LEFT_GAUNTLET_INDEX)
1805 ApplyDexterityPenalty(Equipment);
1807 if(EquipmentIndex == RIGHT_WIELDED_INDEX || EquipmentIndex == LEFT_WIELDED_INDEX)
1809 UpdateWieldedPicture();
1810 GetSquareUnder()->SendNewDrawRequest();
1814 if(Master)
1815 Master->SignalEquipmentAdd(EquipmentIndex);
1818 void arm::SignalEquipmentRemoval(gearslot* Slot, citem* Item)
1820 int EquipmentIndex = Slot->GetEquipmentIndex();
1822 if(Master && !Master->IsInitializing())
1823 if(EquipmentIndex == RIGHT_WIELDED_INDEX || EquipmentIndex == LEFT_WIELDED_INDEX)
1825 UpdateWieldedPicture();
1826 square* Square = GetSquareUnder();
1828 if(Square)
1829 Square->SendNewDrawRequest();
1832 if(Master)
1833 Master->SignalEquipmentRemoval(EquipmentIndex, Item);
1836 void leg::SignalEquipmentAdd(gearslot* Slot)
1838 int EquipmentIndex = Slot->GetEquipmentIndex();
1840 if(Master && !Master->IsInitializing())
1842 item* Equipment = Slot->GetItem();
1844 if(Equipment->IsInCorrectSlot(EquipmentIndex))
1845 ApplyEquipmentAttributeBonuses(Equipment);
1847 if(EquipmentIndex == RIGHT_BOOT_INDEX || EquipmentIndex == LEFT_BOOT_INDEX)
1848 ApplyAgilityPenalty(Equipment);
1851 if(Master)
1852 Master->SignalEquipmentAdd(EquipmentIndex);
1855 void arm::ApplyEquipmentAttributeBonuses(item* Item)
1857 if(Item->AffectsArmStrength())
1858 StrengthBonus += Item->GetEnchantment();
1860 if(Item->AffectsDexterity())
1861 DexterityBonus += Item->GetEnchantment();
1864 void leg::ApplyEquipmentAttributeBonuses(item* Item)
1866 if(Item->AffectsLegStrength())
1868 StrengthBonus += Item->GetEnchantment();
1870 if(Master)
1871 Master->CalculateBurdenState();
1874 if(Item->AffectsAgility())
1875 AgilityBonus += Item->GetEnchantment();
1878 void arm::CalculateAttributeBonuses()
1880 StrengthBonus = DexterityBonus = 0;
1882 for(int c = 0; c < GetEquipments(); ++c)
1884 item* Equipment = GetEquipment(c);
1886 if(Equipment && Equipment->IsInCorrectSlot())
1887 ApplyEquipmentAttributeBonuses(Equipment);
1890 ApplyDexterityPenalty(GetGauntlet());
1892 if(Master)
1894 ApplyDexterityPenalty(GetExternalCloak());
1895 ApplyDexterityPenalty(GetExternalBodyArmor());
1896 /* */
1897 ApplyStrengthBonus(GetExternalHelmet());
1898 ApplyStrengthBonus(GetExternalCloak());
1899 ApplyStrengthBonus(GetExternalBodyArmor());
1900 ApplyStrengthBonus(GetExternalBelt());
1901 ApplyDexterityBonus(GetExternalHelmet());
1902 ApplyDexterityBonus(GetExternalCloak());
1903 ApplyDexterityBonus(GetExternalBodyArmor());
1904 ApplyDexterityBonus(GetExternalBelt());
1907 if(!UseMaterialAttributes())
1909 StrengthBonus -= CalculateScarAttributePenalty(GetAttribute(ARM_STRENGTH, false));
1910 DexterityBonus -= CalculateScarAttributePenalty(GetAttribute(DEXTERITY, false)) ;
1914 void leg::CalculateAttributeBonuses()
1916 StrengthBonus = AgilityBonus = 0;
1918 for(int c = 0; c < GetEquipments(); ++c)
1920 item* Equipment = GetEquipment(c);
1922 if(Equipment && Equipment->IsInCorrectSlot())
1923 ApplyEquipmentAttributeBonuses(Equipment);
1926 ApplyAgilityPenalty(GetBoot());
1928 if(Master)
1930 ApplyAgilityPenalty(GetExternalCloak());
1931 ApplyAgilityPenalty(GetExternalBodyArmor());
1932 /* */
1933 ApplyStrengthBonus(GetExternalHelmet());
1934 ApplyStrengthBonus(GetExternalCloak());
1935 ApplyStrengthBonus(GetExternalBodyArmor());
1936 ApplyStrengthBonus(GetExternalBelt());
1937 ApplyAgilityBonus(GetExternalHelmet());
1938 ApplyAgilityBonus(GetExternalCloak());
1939 ApplyAgilityBonus(GetExternalBodyArmor());
1940 ApplyAgilityBonus(GetExternalBelt());
1943 if(!UseMaterialAttributes())
1945 StrengthBonus -= CalculateScarAttributePenalty(GetAttribute(LEG_STRENGTH, false));
1946 AgilityBonus -= CalculateScarAttributePenalty(GetAttribute(AGILITY, false)) ;
1950 void humanoidtorso::SignalEquipmentAdd(gearslot* Slot)
1952 if(!Master)
1953 return;
1955 humanoid* Master = GetHumanoidMaster();
1956 int EquipmentIndex = Slot->GetEquipmentIndex();
1958 if(!Master->IsInitializing()
1959 && (EquipmentIndex == CLOAK_INDEX || EquipmentIndex == BODY_ARMOR_INDEX))
1961 item* Item = Slot->GetItem();
1963 if(Master->GetRightArm())
1964 Master->GetRightArm()->ApplyDexterityPenalty(Item);
1966 if(Master->GetLeftArm())
1967 Master->GetLeftArm()->ApplyDexterityPenalty(Item);
1969 if(Master->GetRightLeg())
1970 Master->GetRightLeg()->ApplyAgilityPenalty(Item);
1972 if(Master->GetLeftLeg())
1973 Master->GetLeftLeg()->ApplyAgilityPenalty(Item);
1976 Master->SignalEquipmentAdd(EquipmentIndex);
1979 int arm::GetWieldedHitStrength() const
1981 int HitStrength = GetAttribute(ARM_STRENGTH);
1982 int Requirement = GetWielded()->GetStrengthRequirement();
1984 if(TwoHandWieldIsActive())
1986 HitStrength += GetPairArm()->GetAttribute(ARM_STRENGTH);
1987 Requirement >>= 2;
1990 return HitStrength - Requirement;
1993 void arm::ApplyDexterityPenalty(item* Item)
1995 if(Item)
1996 DexterityBonus -= Item->GetInElasticityPenalty(GetAttribute(DEXTERITY, false));
1999 void leg::ApplyAgilityPenalty(item* Item)
2001 if(Item)
2002 AgilityBonus -= Item->GetInElasticityPenalty(GetAttribute(AGILITY, false));
2005 int corpse::GetSpoilLevel() const
2007 int FlyAmount = 0;
2009 for(int c = 0; c < GetDeceased()->GetBodyParts(); ++c)
2011 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
2013 if(BodyPart && FlyAmount < BodyPart->GetSpoilLevel())
2014 FlyAmount = BodyPart->GetSpoilLevel();
2017 return FlyAmount;
2020 void bodypart::SignalSpoilLevelChange(material* Material)
2022 if(Master)
2023 Master->SignalSpoilLevelChange();
2024 else
2025 item::SignalSpoilLevelChange(Material);
2028 truth head::DamageArmor(character* Damager, int Damage, int Type)
2030 sLong AV[3] = { 0, 0, 0 }, AVSum = 0;
2031 item* Armor[3];
2033 if((Armor[0] = GetHelmet()))
2034 AVSum += AV[0] = Max(Armor[0]->GetStrengthValue(), 1);
2036 if((Armor[1] = GetExternalBodyArmor()))
2037 AVSum += AV[1] = Max(Armor[1]->GetStrengthValue() >> 2, 1);
2039 if((Armor[2] = GetExternalCloak()))
2040 AVSum += AV[2] = Max(Armor[2]->GetStrengthValue(), 1);
2042 return AVSum ? Armor[femath::WeightedRand(AV, AVSum)]->ReceiveDamage(Damager, Damage, Type) : false;
2045 truth humanoidtorso::DamageArmor(character* Damager, int Damage, int Type)
2047 sLong AV[3] = { 0, 0, 0 }, AVSum = 0;
2048 item* Armor[3];
2050 if((Armor[0] = GetBodyArmor()))
2051 AVSum += AV[0] = Max(Armor[0]->GetStrengthValue(), 1);
2053 if((Armor[1] = GetBelt()))
2054 AVSum += AV[1] = Max(Armor[1]->GetStrengthValue(), 1);
2056 if((Armor[2] = GetCloak()))
2057 AVSum += AV[2] = Max(Armor[2]->GetStrengthValue(), 1);
2059 return AVSum ? Armor[femath::WeightedRand(AV, AVSum)]->ReceiveDamage(Damager, Damage, Type) : false;
2062 truth arm::DamageArmor(character* Damager, int Damage, int Type)
2064 sLong AV[3] = { 0, 0, 0 }, AVSum = 0;
2065 item* Armor[3];
2067 if((Armor[0] = GetGauntlet()))
2068 AVSum += AV[0] = Max(Armor[0]->GetStrengthValue(), 1);
2070 if((Armor[1] = GetExternalBodyArmor()))
2071 AVSum += AV[1] = Max(Armor[1]->GetStrengthValue() >> 1, 1);
2073 if((Armor[2] = GetExternalCloak()))
2074 AVSum += AV[2] = Max(Armor[2]->GetStrengthValue(), 1);
2076 return AVSum ? Armor[femath::WeightedRand(AV, AVSum)]->ReceiveDamage(Damager, Damage, Type) : false;
2079 truth groin::DamageArmor(character* Damager, int Damage, int Type)
2081 return Master->GetTorso()->DamageArmor(Damager, Damage, Type);
2084 truth leg::DamageArmor(character* Damager, int Damage, int Type)
2086 sLong AV[3] = { 0, 0, 0 }, AVSum = 0;
2087 item* Armor[3];
2089 if((Armor[0] = GetBoot()))
2090 AVSum += AV[0] = Max(Armor[0]->GetStrengthValue(), 1);
2092 if((Armor[1] = GetExternalBodyArmor()))
2093 AVSum += AV[1] = Max(Armor[1]->GetStrengthValue() >> 1, 1);
2095 if((Armor[2] = GetExternalCloak()))
2096 AVSum += AV[2] = Max(Armor[2]->GetStrengthValue(), 1);
2098 return AVSum ? Armor[femath::WeightedRand(AV, AVSum)]->ReceiveDamage(Damager, Damage, Type) : false;
2101 truth bodypart::CanBeEatenByAI(ccharacter* Who) const
2103 return item::CanBeEatenByAI(Who) && !(Who->IsPet() && PLAYER->HasHadBodyPart(this));
2106 int bodypart::GetConditionColorIndex() const
2108 if(HP <= 1 && MaxHP > 1)
2109 return 0;
2110 else if((HP << 1) + HP < MaxHP)
2111 return 1;
2112 else if((HP << 1) + HP < MaxHP << 1)
2113 return 2;
2114 else if(HP < MaxHP)
2115 return 3;
2116 else
2117 return 4;
2120 truth arm::CheckIfWeaponTooHeavy(cchar* WeaponDescription) const
2122 if(!IsUsable())
2124 ADD_MESSAGE("%s %s is not usable.", Master->CHAR_POSSESSIVE_PRONOUN, GetBodyPartName().CStr());
2125 return !game::TruthQuestion(CONST_S("Continue anyway? [y/N]"));
2128 int HitStrength = GetAttribute(ARM_STRENGTH);
2129 int Requirement = GetWielded()->GetStrengthRequirement();
2131 if(TwoHandWieldIsActive())
2133 HitStrength += GetPairArm()->GetAttribute(ARM_STRENGTH);
2134 Requirement >>= 2;
2136 if(HitStrength - Requirement < 10)
2138 if(HitStrength <= Requirement)
2139 ADD_MESSAGE("%s cannot use %s. Wielding it with two hands requires %d strength.", Master->CHAR_DESCRIPTION(DEFINITE), WeaponDescription, (Requirement >> 1) + 1);
2140 else if(HitStrength - Requirement < 4)
2141 ADD_MESSAGE("Using %s even with two hands is extremely difficult for %s.", WeaponDescription, Master->CHAR_DESCRIPTION(DEFINITE));
2142 else if(HitStrength - Requirement < 7)
2143 ADD_MESSAGE("%s %s much trouble using %s even with two hands.", Master->CHAR_DESCRIPTION(DEFINITE), Master->IsPlayer() ? "have" : "has", WeaponDescription);
2144 else
2145 ADD_MESSAGE("It is somewhat difficult for %s to use %s even with two hands.", Master->CHAR_DESCRIPTION(DEFINITE), WeaponDescription);
2147 return !game::TruthQuestion(CONST_S("Continue anyway? [y/N]"));
2150 else
2152 if(HitStrength - Requirement < 10)
2154 festring OtherHandInfo;
2155 cchar* HandInfo = "";
2157 if(GetWielded()->IsTwoHanded())
2159 if(GetPairArm() && !GetPairArm()->IsUsable())
2160 OtherHandInfo = Master->GetPossessivePronoun() + " other arm is unusable. ";
2162 HandInfo = " with one hand";
2165 if(HitStrength <= Requirement)
2166 ADD_MESSAGE("%s%s cannot use %s. Wielding it%s requires %d strength.", OtherHandInfo.CStr(), Master->GetDescription(DEFINITE).CapitalizeCopy().CStr(), WeaponDescription, HandInfo, Requirement + 1);
2167 else if(HitStrength - Requirement < 4)
2168 ADD_MESSAGE("%sUsing %s%s is extremely difficult for %s.", OtherHandInfo.CStr(), WeaponDescription, HandInfo, Master->CHAR_DESCRIPTION(DEFINITE));
2169 else if(HitStrength - Requirement < 7)
2170 ADD_MESSAGE("%s%s %s much trouble using %s%s.", OtherHandInfo.CStr(), Master->GetDescription(DEFINITE).CapitalizeCopy().CStr(), Master->IsPlayer() ? "have" : "has", WeaponDescription, HandInfo);
2171 else
2172 ADD_MESSAGE("%sIt is somewhat difficult for %s to use %s%s.", OtherHandInfo.CStr(), Master->CHAR_DESCRIPTION(DEFINITE), WeaponDescription, HandInfo);
2174 return !game::TruthQuestion(CONST_S("Continue anyway? [y/N]"));
2178 return false;
2181 int corpse::GetArticleMode() const
2183 return Deceased->LeftOversAreUnique() ? FORCE_THE : 0;
2186 head* head::Behead()
2188 RemoveFromSlot();
2189 return this;
2192 truth arm::EditAllAttributes(int Amount)
2194 LimitRef(StrengthExperience += Amount * EXP_MULTIPLIER, MIN_EXP, MAX_EXP);
2195 LimitRef(DexterityExperience += Amount * EXP_MULTIPLIER, MIN_EXP, MAX_EXP);
2196 return (Amount < 0
2197 && (StrengthExperience != MIN_EXP || DexterityExperience != MIN_EXP))
2198 || (Amount > 0
2199 && (StrengthExperience != MAX_EXP || DexterityExperience != MAX_EXP));
2202 truth leg::EditAllAttributes(int Amount)
2204 LimitRef(StrengthExperience += Amount * EXP_MULTIPLIER, MIN_EXP, MAX_EXP);
2205 LimitRef(AgilityExperience += Amount * EXP_MULTIPLIER, MIN_EXP, MAX_EXP);
2206 return (Amount < 0
2207 && (StrengthExperience != MIN_EXP || AgilityExperience != MIN_EXP))
2208 || (Amount > 0
2209 && (StrengthExperience != MAX_EXP || AgilityExperience != MAX_EXP));
2212 #ifdef WIZARD
2214 void arm::AddAttackInfo(felist& List) const
2216 if(GetDamage())
2218 festring Entry = CONST_S(" ");
2220 if(GetWielded())
2222 GetWielded()->AddName(Entry, UNARTICLED);
2224 if(TwoHandWieldIsActive())
2225 Entry << " (b)";
2227 else
2228 Entry << "melee attack";
2230 Entry.Resize(50);
2231 Entry << GetMinDamage() << '-' << GetMaxDamage();
2232 Entry.Resize(60);
2233 Entry << int(GetToHitValue());
2234 Entry.Resize(70);
2235 Entry << GetAPCost();
2236 List.AddEntry(Entry, LIGHT_GRAY);
2240 void arm::AddDefenceInfo(felist& List) const
2242 if(GetWielded())
2244 festring Entry = CONST_S(" ");
2245 GetWielded()->AddName(Entry, UNARTICLED);
2246 Entry.Resize(50);
2247 Entry << int(GetBlockValue());
2248 Entry.Resize(70);
2249 Entry << GetBlockCapability();
2250 List.AddEntry(Entry, LIGHT_GRAY);
2254 #else
2256 void arm::AddAttackInfo(felist&) const { }
2257 void arm::AddDefenceInfo(felist&) const { }
2259 #endif
2261 void arm::UpdateWieldedPicture()
2263 if(!Master || !Master->PictureUpdatesAreForbidden())
2265 truth WasAnimated = MasterIsAnimated();
2266 item* Wielded = GetWielded();
2268 if(Wielded && Master)
2270 int SpecialFlags = (IsRightArm() ? 0 : MIRROR)|ST_WIELDED|(Wielded->GetSpecialFlags()&~0x3F);
2271 Wielded->UpdatePictures(WieldedGraphicData,
2272 Master->GetWieldedPosition(),
2273 SpecialFlags,
2274 GetMaxAlpha(),
2275 GR_HUMANOID,
2276 static_cast<bposretriever>(&item::GetWieldedBitmapPos));
2278 if(ShowFluids())
2279 Wielded->CheckFluidGearPictures(Wielded->GetWieldedBitmapPos(0), SpecialFlags, false);
2281 else
2282 WieldedGraphicData.Retire();
2284 if(!WasAnimated != !MasterIsAnimated())
2285 SignalAnimationStateChange(WasAnimated);
2289 void arm::DrawWielded(blitdata& BlitData) const
2291 DrawEquipment(WieldedGraphicData, BlitData);
2293 if(ShowFluids() && GetWielded())
2294 GetWielded()->DrawFluidGearPictures(BlitData, IsRightArm() ? 0 : MIRROR);
2297 void arm::UpdatePictures()
2299 bodypart::UpdatePictures();
2300 UpdateWieldedPicture();
2303 void bodypart::Draw(blitdata& BlitData) const
2305 cint AF = GraphicData.AnimationFrames;
2306 cint F = !(BlitData.CustomData & ALLOW_ANIMATE) || AF == 1 ? 0 : GET_TICK() & (AF - 1);
2307 cbitmap* P = GraphicData.Picture[F];
2309 if(BlitData.CustomData & ALLOW_ALPHA)
2310 P->AlphaPriorityBlit(BlitData);
2311 else
2312 P->MaskedPriorityBlit(BlitData);
2314 if(Fluid && ShowFluids())
2315 DrawFluids(BlitData);
2317 DrawArmor(BlitData);
2320 void leg::AddAttackInfo(felist& List) const
2322 festring Entry = CONST_S(" kick attack");
2323 Entry.Resize(50);
2324 Entry << GetKickMinDamage() << '-' << GetKickMaxDamage();
2325 Entry.Resize(60);
2326 Entry << int(GetKickToHitValue());
2327 Entry.Resize(70);
2328 Entry << GetKickAPCost();
2329 List.AddEntry(Entry, LIGHT_GRAY);
2332 void corpse::PreProcessForBone()
2334 item::PreProcessForBone();
2336 if(!Deceased->PreProcessForBone())
2338 RemoveFromSlot();
2339 SendToHell();
2343 void corpse::PostProcessForBone()
2345 item::PostProcessForBone();
2347 if(!Deceased->PostProcessForBone())
2349 RemoveFromSlot();
2350 SendToHell();
2354 void corpse::FinalProcessForBone()
2356 item::FinalProcessForBone();
2357 Deceased->FinalProcessForBone();
2360 truth bodypart::IsRepairable(ccharacter*) const
2362 return !CanRegenerate() && (GetHP() < GetMaxHP() || IsRusted());
2365 truth corpse::SuckSoul(character* Soul, character* Summoner)
2367 v2 Pos = Soul->GetPos();
2369 if(Deceased->SuckSoul(Soul))
2371 Soul->Remove();
2372 character* Deceased = GetDeceased();
2374 if(RaiseTheDead(Summoner))
2376 Soul->SendToHell();
2377 return true;
2379 else
2381 Deceased->SetSoulID(Soul->GetID());
2382 Soul->PutTo(Pos);
2383 return false;
2386 else
2387 return false;
2390 double arm::GetTypeDamage(ccharacter* Enemy) const
2392 if(!GetWielded() || !GetWielded()->IsGoodWithPlants() || !Enemy->IsPlant())
2393 return Damage;
2394 else
2395 return Damage * 1.5;
2398 void largetorso::Draw(blitdata& BlitData) const
2400 LargeDraw(BlitData);
2403 void largecorpse::Draw(blitdata& BlitData) const
2405 LargeDraw(BlitData);
2408 void largetorso::SignalStackAdd(stackslot* StackSlot, void (stack::*AddHandler)(item*, truth))
2410 if(!Slot[0])
2412 Slot[0] = StackSlot;
2413 v2 Pos = GetPos();
2414 level* Level = GetLevel();
2416 for(int c = 1; c < 4; ++c)
2417 (Level->GetLSquare(Pos + game::GetLargeMoveVector(12 + c))->GetStack()->*AddHandler)(this, false);
2419 else
2420 for(int c = 1; c < 4; ++c)
2421 if(!Slot[c])
2423 Slot[c] = StackSlot;
2424 return;
2428 int largetorso::GetSquareIndex(v2 Pos) const
2430 v2 RelativePos = Pos - GetPos();
2431 return RelativePos.X + (RelativePos.Y << 1);
2434 void largecorpse::SignalStackAdd(stackslot* StackSlot, void (stack::*AddHandler)(item*, truth))
2436 if(!Slot[0])
2438 Slot[0] = StackSlot;
2439 v2 Pos = GetPos();
2440 level* Level = GetLevel();
2442 for(int c = 1; c < 4; ++c)
2443 (Level->GetLSquare(Pos + game::GetLargeMoveVector(12 + c))->GetStack()->*AddHandler)(this, false);
2445 else
2446 for(int c = 1; c < 4; ++c)
2447 if(!Slot[c])
2449 Slot[c] = StackSlot;
2450 return;
2454 int largecorpse::GetSquareIndex(v2 Pos) const
2456 v2 RelativePos = Pos - GetPos();
2457 return RelativePos.X + (RelativePos.Y << 1);
2460 character* corpse::TryNecromancy(character* Summoner)
2462 if(Summoner && Summoner->IsPlayer())
2463 game::DoEvilDeed(50);
2465 character* Zombie = GetDeceased()->CreateZombie();
2467 if(Zombie)
2469 v2 Pos = GetPos();
2470 RemoveFromSlot();
2471 Zombie->ChangeTeam(Summoner ? Summoner->GetTeam() : game::GetTeam(MONSTER_TEAM));
2472 Zombie->PutToOrNear(Pos);
2473 Zombie->SignalStepFrom(0);
2474 SendToHell();
2475 return Zombie;
2478 return 0;
2481 item* head::GetArmorToReceiveFluid(truth) const
2483 item* Helmet = GetHelmet();
2485 if(Helmet && Helmet->GetCoverPercentile() > RAND() % 100)
2486 return Helmet;
2487 else
2488 return 0;
2491 item* humanoidtorso::GetArmorToReceiveFluid(truth) const
2493 item* Cloak = GetCloak();
2495 if(Cloak && !(RAND() % 3))
2496 return Cloak;
2498 item* Belt = GetBelt();
2500 if(Belt && !(RAND() % 10))
2501 return Belt;
2503 item* BodyArmor = GetBodyArmor();
2504 return BodyArmor ? BodyArmor : 0;
2507 item* arm::GetArmorToReceiveFluid(truth) const
2509 item* Cloak = GetExternalCloak();
2511 if(Cloak && !(RAND() % 3))
2512 return Cloak;
2514 item* Wielded = GetWielded();
2516 if(Wielded && !(RAND() % 3))
2517 return Wielded;
2519 item* Gauntlet = GetGauntlet();
2521 if(Gauntlet && RAND() & 1)
2522 return Gauntlet;
2524 item* BodyArmor = GetExternalBodyArmor();
2525 return BodyArmor ? BodyArmor : 0;
2528 item* groin::GetArmorToReceiveFluid(truth) const
2530 item* Cloak = GetExternalCloak();
2532 if(Cloak && !(RAND() % 3))
2533 return Cloak;
2535 item* BodyArmor = GetExternalBodyArmor();
2536 return BodyArmor ? BodyArmor : 0;
2539 item* leg::GetArmorToReceiveFluid(truth SteppedOn) const
2541 if(SteppedOn)
2543 item* Boot = GetBoot();
2544 return Boot ? Boot : 0;
2546 else
2548 item* Cloak = GetExternalCloak();
2550 if(Cloak && !(RAND() % 3))
2551 return Cloak;
2553 item* Boot = GetBoot();
2555 if(Boot && RAND() & 1)
2556 return Boot;
2558 item* BodyArmor = GetExternalBodyArmor();
2559 return BodyArmor ? BodyArmor : 0;
2563 void bodypart::SpillFluid(character* Spiller, liquid* Liquid, int SquareIndex)
2565 if(Master)
2567 item* Armor = GetArmorToReceiveFluid(false);
2569 if(Armor)
2570 Armor->SpillFluid(Spiller, Liquid);
2571 else if(GetMaster())
2573 if(Liquid->GetVolume())
2574 AddFluid(Liquid, "", SquareIndex, false);
2575 else
2576 delete Liquid;
2579 else
2580 item::SpillFluid(Spiller, Liquid, SquareIndex);
2583 void bodypart::StayOn(liquid* Liquid)
2585 item* Armor = GetArmorToReceiveFluid(true);
2587 if(Armor)
2588 Liquid->TouchEffect(Armor, CONST_S(""));
2589 else if(GetMaster())
2590 Liquid->TouchEffect(GetMaster(), GetBodyPartIndex());
2593 liquid* bodypart::CreateBlood(sLong Volume) const
2595 return liquid::Spawn(GetBloodMaterial(), Volume);
2598 int corpse::GetRustDataA() const
2600 return Deceased->GetTorso()->GetMainMaterial()->GetRustData();
2603 void bodypart::UpdateArmorPicture(graphicdata& GData, item* Armor, int SpecialFlags, v2 (item::*Retriever)(int) const, truth BodyArmor) const
2605 if(Armor && Master)
2607 Armor->UpdatePictures(GData,
2608 ZERO_V2,
2609 SpecialFlags|Armor->GetSpecialFlags(),
2610 GetMaxAlpha(),
2611 GR_HUMANOID,
2612 static_cast<bposretriever>(Retriever));
2613 Armor->CheckFluidGearPictures((Armor->*Retriever)(0), SpecialFlags, BodyArmor);
2615 else
2616 GData.Retire();
2619 truth playerkindhead::UpdateArmorPictures()
2621 UpdateHeadArmorPictures(HelmetGraphicData);
2622 return true;
2625 truth playerkindtorso::UpdateArmorPictures()
2627 UpdateTorsoArmorPictures(TorsoArmorGraphicData,
2628 CloakGraphicData,
2629 BeltGraphicData);
2630 return true;
2633 truth playerkindrightarm::UpdateArmorPictures()
2635 UpdateArmArmorPictures(ArmArmorGraphicData,
2636 GauntletGraphicData,
2637 ST_RIGHT_ARM);
2638 return true;
2641 truth playerkindleftarm::UpdateArmorPictures()
2643 UpdateArmArmorPictures(ArmArmorGraphicData,
2644 GauntletGraphicData,
2645 ST_LEFT_ARM);
2646 return true;
2649 truth playerkindgroin::UpdateArmorPictures()
2651 UpdateGroinArmorPictures(GroinArmorGraphicData);
2652 return true;
2655 truth playerkindrightleg::UpdateArmorPictures()
2657 UpdateLegArmorPictures(LegArmorGraphicData,
2658 BootGraphicData,
2659 ST_RIGHT_LEG);
2660 return true;
2663 truth playerkindleftleg::UpdateArmorPictures()
2665 UpdateLegArmorPictures(LegArmorGraphicData,
2666 BootGraphicData,
2667 ST_LEFT_LEG);
2668 return true;
2671 void head::UpdateHeadArmorPictures(graphicdata& HelmetGraphicData) const
2673 if(!Master || !Master->PictureUpdatesAreForbidden())
2675 UpdateArmorPicture(HelmetGraphicData,
2676 GetHelmet(),
2677 ST_OTHER_BODYPART,
2678 &item::GetHelmetBitmapPos);
2682 void humanoidtorso::UpdateTorsoArmorPictures(graphicdata& TorsoArmorGraphicData, graphicdata& CloakGraphicData, graphicdata& BeltGraphicData) const
2684 if(!Master || !Master->PictureUpdatesAreForbidden())
2686 UpdateArmorPicture(TorsoArmorGraphicData,
2687 GetBodyArmor(),
2688 ST_OTHER_BODYPART,
2689 &item::GetTorsoArmorBitmapPos,
2690 true);
2691 UpdateArmorPicture(CloakGraphicData,
2692 GetCloak(),
2693 ST_OTHER_BODYPART,
2694 &item::GetCloakBitmapPos);
2695 UpdateArmorPicture(BeltGraphicData,
2696 GetBelt(),
2697 ST_OTHER_BODYPART,
2698 &item::GetBeltBitmapPos);
2702 void arm::UpdateArmArmorPictures(graphicdata& ArmArmorGraphicData, graphicdata& GauntletGraphicData, int SpecialFlags) const
2704 if(!Master || !Master->PictureUpdatesAreForbidden())
2706 UpdateArmorPicture(ArmArmorGraphicData,
2707 Master ? GetExternalBodyArmor() : 0,
2708 SpecialFlags,
2709 GetAttribute(ARM_STRENGTH, false) >= 20 ? &item::GetAthleteArmArmorBitmapPos : &item::GetArmArmorBitmapPos,
2710 true);
2711 UpdateArmorPicture(GauntletGraphicData,
2712 GetGauntlet(),
2713 SpecialFlags,
2714 &item::GetGauntletBitmapPos);
2718 void groin::UpdateGroinArmorPictures(graphicdata& GroinArmorGraphicData) const
2720 if(!Master || !Master->PictureUpdatesAreForbidden())
2722 UpdateArmorPicture(GroinArmorGraphicData,
2723 Master ? GetExternalBodyArmor() : 0,
2724 ST_GROIN,
2725 &item::GetLegArmorBitmapPos,
2726 true);
2730 void leg::UpdateLegArmorPictures(graphicdata& LegArmorGraphicData, graphicdata& BootGraphicData, int SpecialFlags) const
2732 if(!Master || !Master->PictureUpdatesAreForbidden())
2734 UpdateArmorPicture(LegArmorGraphicData,
2735 Master ? GetExternalBodyArmor() : 0,
2736 SpecialFlags,
2737 &item::GetLegArmorBitmapPos,
2738 true);
2739 UpdateArmorPicture(BootGraphicData,
2740 GetBoot(),
2741 SpecialFlags,
2742 &item::GetBootBitmapPos);
2746 void bodypart::DrawEquipment(const graphicdata& GraphicData, blitdata& BlitData) const
2748 int EAF = GraphicData.AnimationFrames;
2750 if(EAF)
2752 int F = !(BlitData.CustomData & ALLOW_ANIMATE) || EAF == 1 ? 0 : GET_TICK() & (EAF - 1);
2753 GraphicData.Picture[F]->AlphaPriorityBlit(BlitData);
2757 void playerkindhead::DrawArmor(blitdata& BlitData) const
2759 DrawEquipment(HelmetGraphicData, BlitData);
2761 if(GetHelmet())
2762 GetHelmet()->DrawFluidGearPictures(BlitData);
2765 void playerkindtorso::DrawArmor(blitdata& BlitData) const
2767 DrawEquipment(TorsoArmorGraphicData, BlitData);
2769 if(GetBodyArmor())
2770 GetBodyArmor()->DrawFluidGearPictures(BlitData);
2772 DrawEquipment(CloakGraphicData, BlitData);
2774 if(GetCloak())
2775 GetCloak()->DrawFluidGearPictures(BlitData);
2777 DrawEquipment(BeltGraphicData, BlitData);
2779 if(GetBelt())
2780 GetBelt()->DrawFluidGearPictures(BlitData);
2783 void playerkindrightarm::DrawArmor(blitdata& BlitData) const
2785 DrawEquipment(ArmArmorGraphicData, BlitData);
2787 if(Master && GetExternalBodyArmor())
2788 GetExternalBodyArmor()->DrawFluidBodyArmorPictures(BlitData, ST_RIGHT_ARM);
2790 DrawEquipment(GauntletGraphicData, BlitData);
2792 if(GetGauntlet())
2793 GetGauntlet()->DrawFluidGearPictures(BlitData);
2796 void playerkindleftarm::DrawArmor(blitdata& BlitData) const
2798 DrawEquipment(ArmArmorGraphicData, BlitData);
2800 if(Master && GetExternalBodyArmor())
2801 GetExternalBodyArmor()->DrawFluidBodyArmorPictures(BlitData, ST_LEFT_ARM);
2803 DrawEquipment(GauntletGraphicData, BlitData);
2805 if(GetGauntlet())
2806 GetGauntlet()->DrawFluidGearPictures(BlitData);
2809 void playerkindgroin::DrawArmor(blitdata& BlitData) const
2811 DrawEquipment(GroinArmorGraphicData, BlitData);
2813 if(Master && GetExternalBodyArmor())
2814 GetExternalBodyArmor()->DrawFluidBodyArmorPictures(BlitData, ST_GROIN);
2817 void playerkindrightleg::DrawArmor(blitdata& BlitData) const
2819 DrawEquipment(LegArmorGraphicData, BlitData);
2821 if(Master && GetExternalBodyArmor())
2822 GetExternalBodyArmor()->DrawFluidBodyArmorPictures(BlitData, ST_RIGHT_LEG);
2824 DrawEquipment(BootGraphicData, BlitData);
2826 if(GetBoot())
2827 GetBoot()->DrawFluidGearPictures(BlitData);
2830 void playerkindleftleg::DrawArmor(blitdata& BlitData) const
2832 DrawEquipment(LegArmorGraphicData, BlitData);
2834 if(Master && GetExternalBodyArmor())
2835 GetExternalBodyArmor()->DrawFluidBodyArmorPictures(BlitData, ST_LEFT_LEG);
2837 DrawEquipment(BootGraphicData, BlitData);
2839 if(GetBoot())
2840 GetBoot()->DrawFluidGearPictures(BlitData);
2843 void playerkindhead::Save(outputfile& SaveFile) const
2845 head::Save(SaveFile);
2846 SaveFile << HelmetGraphicData;
2849 void playerkindhead::Load(inputfile& SaveFile)
2851 head::Load(SaveFile);
2852 SaveFile >> HelmetGraphicData;
2855 void playerkindtorso::Save(outputfile& SaveFile) const
2857 humanoidtorso::Save(SaveFile);
2858 SaveFile << TorsoArmorGraphicData << CloakGraphicData << BeltGraphicData;
2861 void playerkindtorso::Load(inputfile& SaveFile)
2863 humanoidtorso::Load(SaveFile);
2864 SaveFile >> TorsoArmorGraphicData >> CloakGraphicData >> BeltGraphicData;
2867 void playerkindrightarm::Save(outputfile& SaveFile) const
2869 rightarm::Save(SaveFile);
2870 SaveFile << ArmArmorGraphicData << GauntletGraphicData;
2873 void playerkindrightarm::Load(inputfile& SaveFile)
2875 rightarm::Load(SaveFile);
2876 SaveFile >> ArmArmorGraphicData >> GauntletGraphicData;
2879 void playerkindleftarm::Save(outputfile& SaveFile) const
2881 leftarm::Save(SaveFile);
2882 SaveFile << ArmArmorGraphicData << GauntletGraphicData;
2885 void playerkindleftarm::Load(inputfile& SaveFile)
2887 leftarm::Load(SaveFile);
2888 SaveFile >> ArmArmorGraphicData >> GauntletGraphicData;
2891 void playerkindgroin::Save(outputfile& SaveFile) const
2893 groin::Save(SaveFile);
2894 SaveFile << GroinArmorGraphicData;
2897 void playerkindgroin::Load(inputfile& SaveFile)
2899 groin::Load(SaveFile);
2900 SaveFile >> GroinArmorGraphicData;
2903 void playerkindrightleg::Save(outputfile& SaveFile) const
2905 rightleg::Save(SaveFile);
2906 SaveFile << LegArmorGraphicData << BootGraphicData;
2909 void playerkindrightleg::Load(inputfile& SaveFile)
2911 rightleg::Load(SaveFile);
2912 SaveFile >> LegArmorGraphicData >> BootGraphicData;
2915 void playerkindleftleg::Save(outputfile& SaveFile) const
2917 leftleg::Save(SaveFile);
2918 SaveFile << LegArmorGraphicData << BootGraphicData;
2921 void playerkindleftleg::Load(inputfile& SaveFile)
2923 leftleg::Load(SaveFile);
2924 SaveFile >> LegArmorGraphicData >> BootGraphicData;
2927 truth bodypart::MasterIsAnimated() const
2929 return Master && !Master->IsInitializing() && Master->IsAnimated();
2932 void bodypart::UpdatePictures()
2934 truth WasAnimated = MasterIsAnimated();
2936 item::UpdatePictures();
2937 UpdateArmorPictures();
2939 if(!WasAnimated != !MasterIsAnimated())
2940 SignalAnimationStateChange(WasAnimated);
2943 void playerkindtorso::SignalVolumeAndWeightChange()
2945 humanoidtorso::SignalVolumeAndWeightChange();
2947 if(Master && !Master->IsInitializing())
2948 Master->UpdatePictures();
2952 void bodypart::ReceiveAcid (material *Material, cfestring &LocationName, sLong Modifier) {
2953 if (Master && MainMaterial->GetInteractionFlags() & CAN_DISSOLVE) {
2954 sLong Tries = Modifier/1000;
2955 Modifier -= Tries*1000; //opt%?
2956 int Damage = 0;
2957 for (sLong c = 0; c < Tries; ++c) if (!(RAND() % 100)) ++Damage;
2958 if (Modifier && !(RAND()%100000/Modifier)) ++Damage;
2959 if (Damage) {
2960 feuLong Minute = game::GetTotalMinutes();
2961 character *Master = this->Master;
2962 if (Master->GetLastAcidMsgMin() != Minute && (Master->CanBeSeenByPlayer() || Master->IsPlayer())) {
2963 Master->SetLastAcidMsgMin(Minute);
2964 cchar *MName = Material->GetName(false, false).CStr();
2965 if (Master->IsPlayer()) {
2966 cchar *TName = LocationName.IsEmpty() ? GetBodyPartName().CStr() : LocationName.CStr();
2967 ADD_MESSAGE("Acidous %s dissolves your %s.", MName, TName);
2968 } else {
2969 ADD_MESSAGE("Acidous %s dissolves %s.", MName, Master->CHAR_NAME(DEFINITE));
2972 Master->ReceiveBodyPartDamage(0, Damage, ACID, GetBodyPartIndex(), YOURSELF, false, false, false);
2973 feuLong DeathFlags = Material->IsStuckTo(Master) ? IGNORE_TRAPS : 0;
2974 Master->CheckDeath(CONST_S("dissolved by ")+Material->GetName(), 0, DeathFlags);
2979 void bodypart::TryToRust(sLong LiquidModifier)
2981 if(MainMaterial->TryToRust(LiquidModifier << 4))
2983 cchar* MoreMsg = MainMaterial->GetRustLevel() == NOT_RUSTED ? "" : " more";
2985 if(Master)
2987 if(Master->IsPlayer())
2988 ADD_MESSAGE("Your %s rusts%s.", CHAR_NAME(UNARTICLED), MoreMsg);
2989 else if(CanBeSeenByPlayer())
2990 ADD_MESSAGE("The %s of %s rusts%s.", CHAR_NAME(UNARTICLED), Master->CHAR_NAME(DEFINITE), MoreMsg);
2992 else if(CanBeSeenByPlayer())
2993 ADD_MESSAGE("%s rusts%s.", CHAR_NAME(DEFINITE), MoreMsg);
2995 MainMaterial->SetRustLevel(MainMaterial->GetRustLevel() + 1);
2999 material* corpse::GetConsumeMaterial(ccharacter* Consumer, materialpredicate Predicate) const
3001 for(int c = GetDeceased()->GetBodyParts() - 1; c; --c)
3003 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
3005 if(BodyPart)
3007 material* CM = BodyPart->GetConsumeMaterial(Consumer, Predicate);
3009 if(CM)
3010 return CM;
3014 return GetDeceased()->GetTorso()->GetConsumeMaterial(Consumer, Predicate);
3017 void corpse::Cannibalize()
3019 item::Cannibalize();
3021 for(int c = 0; c < GetDeceased()->GetBodyParts(); ++c)
3023 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
3025 if(BodyPart)
3026 BodyPart->Cannibalize();
3030 material* bodypart::RemoveMaterial(material* Material)
3032 if(Master && GetBodyPartIndex() == TORSO_INDEX)
3033 return Master->GetMotherEntity()->RemoveMaterial(Material); // gum
3034 else
3035 return item::RemoveMaterial(Material);
3038 void arm::CopyAttributes(const bodypart* BodyPart)
3040 const arm* Arm = static_cast<const arm*>(BodyPart);
3041 StrengthExperience = Arm->StrengthExperience;
3042 DexterityExperience = Arm->DexterityExperience;
3045 void leg::CopyAttributes(const bodypart* BodyPart)
3047 const leg* Leg = static_cast<const leg*>(BodyPart);
3048 StrengthExperience = Leg->StrengthExperience;
3049 AgilityExperience = Leg->AgilityExperience;
3052 truth corpse::DetectMaterial(const material* Material) const
3054 return GetDeceased()->DetectMaterial(Material);
3057 void bodypart::DestroyBodyPart(stack* Stack)
3059 int Lumps = 1 + RAND() % 3;
3060 sLong LumpVolume = Volume / Lumps >> 2;
3062 if(LumpVolume >= 10)
3063 for(int c = 0; c < Lumps; ++c)
3065 item* Lump = GetMainMaterial()->CreateNaturalForm(LumpVolume + RAND() % LumpVolume);
3066 Stack->AddItem(Lump);
3069 SendToHell();
3072 v2 magicmushroomtorso::GetBitmapPos(int Frame) const
3074 v2 BasePos = torso::GetBitmapPos(Frame);
3075 Frame &= 0x3F;
3077 if(!(Frame & 0x30))
3079 if(Frame <= 8)
3080 return v2(BasePos.X + 64 - (abs(Frame - 4) << 4), BasePos.Y);
3081 else
3082 return v2(BasePos.X + 64 - (abs(Frame - 12) << 4), BasePos.Y + 16);
3084 else
3085 return BasePos;
3088 v2 dogtorso::GetBitmapPos(int Frame) const
3090 v2 BasePos = torso::GetBitmapPos(Frame);
3092 if(Frame >= GraphicData.AnimationFrames >> 1)
3093 BasePos.X += 32;
3095 return v2(BasePos.X + ((Frame & 4) << 2), BasePos.Y);
3098 void dogtorso::Draw(blitdata& BlitData) const
3100 cint AF = GraphicData.AnimationFrames >> 1;
3101 int Index = !(BlitData.CustomData & ALLOW_ANIMATE) || AF == 1 ? 0 : GET_TICK() & (AF - 1);
3103 if(GetHP() << 1 <= GetMaxHP())
3104 Index += AF;
3106 cbitmap* P = GraphicData.Picture[Index];
3108 if(BlitData.CustomData & ALLOW_ALPHA)
3109 P->AlphaPriorityBlit(BlitData);
3110 else
3111 P->MaskedPriorityBlit(BlitData);
3114 void corpse::SetLifeExpectancy(int Base, int RandPlus)
3116 Deceased->SetLifeExpectancy(Base, RandPlus);
3119 void corpse::Be()
3121 for(int c = 0; c < Deceased->GetBodyParts(); ++c)
3123 bodypart* BodyPart = Deceased->GetBodyPart(c);
3125 if(BodyPart)
3126 BodyPart->Be();
3130 void bodypart::SetLifeExpectancy(int Base, int RandPlus)
3132 LifeExpectancy = RandPlus > 1 ? Base + RAND_N(RandPlus) : Base;
3134 if(!Master)
3135 Enable();
3138 void bodypart::SpecialEatEffect(character* Eater, int Amount)
3140 Amount >>= 6;
3142 if(Amount && (!Master || Master->SpillsBlood()) && (IsAlive() || MainMaterial->IsLiquid()) && !game::IsInWilderness())
3144 if(Eater->GetVirtualHead())
3145 Eater->GetVirtualHead()->SpillFluid(Eater, CreateBlood(Amount));
3147 Eater->GetTorso()->SpillFluid(Eater, CreateBlood(Amount));
3151 truth corpse::IsValuable() const
3153 for(int c = 0; c < Deceased->GetBodyParts(); ++c)
3155 bodypart* BodyPart = Deceased->GetBodyPart(c);
3157 if(BodyPart && BodyPart->IsValuable())
3158 return true;
3161 return false;
3164 truth corpse::Necromancy(character* Necromancer)
3166 if(Necromancer && Necromancer->IsPlayer())
3167 game::DoEvilDeed(50);
3169 character* Zombie = GetDeceased()->CreateZombie();
3171 if(Zombie)
3173 Zombie->ChangeTeam(Necromancer ? Necromancer->GetTeam() : game::GetTeam(MONSTER_TEAM));
3174 Zombie->PutToOrNear(GetPos());
3175 RemoveFromSlot();
3176 SendToHell();
3178 if(Zombie->CanBeSeenByPlayer())
3179 ADD_MESSAGE("%s rises back to cursed undead life.", Zombie->CHAR_DESCRIPTION(INDEFINITE));
3181 Zombie->SignalStepFrom(0);
3182 return true;
3184 else
3186 if(CanBeSeenByPlayer())
3187 ADD_MESSAGE("%s vibrates for some time.", CHAR_NAME(DEFINITE));
3189 return false;
3193 alpha mysticfrogtorso::GetOutlineAlpha(int Frame) const
3195 Frame &= 31;
3196 return Frame * (31 - Frame) >> 1;
3199 col16 mysticfrogtorso::GetOutlineColor(int Frame) const
3201 switch((Frame&127) >> 5)
3203 case 0: return BLUE;
3204 case 1: return GREEN;
3205 case 2: return RED;
3206 case 3: return YELLOW;
3209 return TRANSPARENT_COLOR;
3212 void bodypart::UpdateFlags()
3214 if((HP << 1) + HP < MaxHP || (HP == 1 && MaxHP != 1))
3215 Flags |= BADLY_HURT;
3216 else
3217 Flags &= ~BADLY_HURT;
3219 if(Master->BodyPartIsStuck(GetBodyPartIndex()))
3220 Flags |= STUCK;
3221 else
3222 Flags &= ~STUCK;
3225 void head::SignalPossibleUsabilityChange()
3227 feuLong OldFlags = Flags;
3228 UpdateFlags();
3230 if(!Master->IsInitializing() && HP > 0
3231 && Flags & BADLY_HURT && !(OldFlags & BADLY_HURT))
3232 switch(RAND_N(8))
3234 case 0:
3235 case 1:
3236 case 2: Master->LoseConsciousness(50 + RAND_N(50)); break;
3237 case 3:
3238 case 4:
3239 case 5: Master->BeginTemporaryState(CONFUSED, 500 + RAND_N(500)); break;
3240 case 6:
3241 if(Master->IsPlayer() && !RAND_N(3))
3243 if(RAND_N(5))
3245 ADD_MESSAGE("Your memory becomes blurred.");
3246 GetLevel()->Amnesia(25 + RAND_N(50));
3247 Master->EditExperience(INTELLIGENCE, -80, 1 << 13);
3248 game::SendLOSUpdateRequest();
3250 else
3252 ADD_MESSAGE("A terrible concussion garbles your consciousness.");
3253 Master->BeginTemporaryState(CONFUSED, 5000 + RAND_N(5000));
3254 Master->EditExperience(INTELLIGENCE, -100, 1 << 14);
3255 GetLevel()->BlurMemory();
3256 game::SendLOSUpdateRequest();
3259 else
3260 Master->EditExperience(INTELLIGENCE, -60, 1 << 12);
3262 break;
3263 case 7:
3264 Master->ForgetRandomThing();
3268 void arm::SignalPossibleUsabilityChange()
3270 feuLong OldFlags = Flags;
3271 UpdateFlags();
3273 if(Flags != OldFlags && !Master->IsInitializing())
3274 Master->CalculateBattleInfo();
3277 void leg::SignalPossibleUsabilityChange()
3279 feuLong OldFlags = Flags;
3280 UpdateFlags();
3282 if(Flags != OldFlags && !Master->IsInitializing())
3283 Master->CalculateBattleInfo();
3286 void bodypart::IncreaseHP()
3288 ++HP;
3289 RemoveDamageIDs(1);
3290 SignalPossibleUsabilityChange();
3293 void bodypart::FastRestoreHP()
3295 HP = MaxHP;
3296 DamageID.clear();
3297 SignalPossibleUsabilityChange();
3300 void bodypart::RestoreHP()
3302 HP = MaxHP;
3303 DamageID.clear();
3304 SignalPossibleUsabilityChange();
3305 Master->CalculateHP();
3308 void bodypart::SetIsUnique(truth What)
3310 if(What)
3311 Flags |= UNIQUE;
3312 else
3313 Flags &= ~UNIQUE;
3316 void bodypart::SetIsInfectedByLeprosy(truth What)
3318 MainMaterial->SetIsInfectedByLeprosy(What);
3321 void bodypart::SetSparkleFlags(int What)
3323 cint S = SPARKLING_B|SPARKLING_C|SPARKLING_D;
3324 Flags = (Flags & ~(S << BODYPART_SPARKLE_SHIFT)) | ((What & S) << BODYPART_SPARKLE_SHIFT);
3327 truth arm::IsAnimated() const
3329 return WieldedGraphicData.AnimationFrames > 1;
3332 void bodypart::SignalAnimationStateChange(truth WasAnimated)
3334 if(WasAnimated)
3336 for(int c = 0; c < GetSquaresUnder(); ++c)
3338 square* Square = GetSquareUnder(c);
3340 if(Square)
3341 Square->DecAnimatedEntities();
3344 else
3346 for(int c = 0; c < GetSquaresUnder(); ++c)
3348 square* Square = GetSquareUnder(c);
3350 if(Square)
3351 Square->IncAnimatedEntities();
3356 truth bodypart::MaterialIsChangeable(ccharacter*) const
3358 return !Master || !Master->BodyPartIsVital(GetBodyPartIndex()) || UseMaterialAttributes();
3361 truth bodypart::AddAdjective(festring& String, truth Articled) const
3363 if(!Master)
3365 if(Articled)
3366 String << "a ";
3368 String << "severed ";
3369 return true;
3371 else
3372 return false;
3375 void bodypart::RemoveRust()
3377 item::RemoveRust();
3378 RestoreHP();
3381 sLong bodypart::GetFixPrice() const
3383 return GetMaxHP() - GetHP() + GetMainMaterial()->GetRustLevel() * 25;
3386 truth bodypart::IsFixableBySmith(ccharacter*) const
3388 return (GetMainMaterial()->GetCategoryFlags() & IS_METAL
3389 && (GetHP() < GetMaxHP() || IsRusted()));
3392 truth bodypart::IsFixableByTailor(ccharacter*) const
3394 return (GetMainMaterial()->GetCategoryFlags() & CAN_BE_TAILORED
3395 && GetHP() < GetMaxHP());
3398 item* bodypart::Fix()
3400 RestoreHP();
3401 return this;
3404 void bodypart::SignalMaterialChange()
3406 if(Master)
3407 RestoreHP();
3410 truth bodypart::ShowMaterial() const
3412 return MainMaterial->GetConfig() != NormalMaterial;
3415 col16 lobhsetorso::GetMaterialColorD(int Frame) const
3417 Frame &= 31;
3418 int Modifier = Frame * (31 - Frame);
3419 return MakeRGB16(220 - (Modifier >> 2), 220 - (Modifier >> 1), 0);
3422 truth bodypart::IsDestroyable(ccharacter*) const
3424 return !Master || !Master->BodyPartIsVital(GetBodyPartIndex());
3427 truth bodypart::DamageTypeCanScar(int Type)
3429 return !(Type == POISON || Type == DRAIN);
3432 void bodypart::GenerateScar(int Damage, int Type)
3434 Scar.push_back(scar());
3435 scar& NewScar = Scar.back();
3436 NewScar.Severity = 1 + RAND_N(1 + 5 * Damage / GetMaxHP());
3438 if(GetMaster()->IsPlayer())
3440 int ScarColor = MakeShadeColor(GetMainMaterial()->GetColor());
3441 NewScar.PanelBitmap = igraph::GenerateScarBitmap(GetBodyPartIndex(),
3442 NewScar.Severity,
3443 ScarColor);
3444 ADD_MESSAGE("Your %s is scarred.", CHAR_NAME(UNARTICLED));
3446 else
3447 NewScar.PanelBitmap = 0;
3449 CalculateMaxHP();
3450 GetMaster()->CalculateMaxHP();
3451 GetMaster()->CalculateAttributeBonuses();
3452 CalculateAttackInfo();
3455 void bodypart::DrawScars(cblitdata& B) const
3457 for(unsigned int c = 0; c < Scar.size(); ++c)
3459 if(!Scar[c].PanelBitmap)
3461 int ScarColor = MakeShadeColor(GetMainMaterial()->GetColor());
3462 Scar[c].PanelBitmap = igraph::GenerateScarBitmap(GetBodyPartIndex(),
3463 Scar[c].Severity,
3464 ScarColor);
3467 Scar[c].PanelBitmap->NormalMaskedBlit(B);
3471 outputfile& operator<<(outputfile& SaveFile, const scar& Scar)
3473 SaveFile << Scar.Severity << Scar.PanelBitmap;
3474 return SaveFile;
3477 inputfile& operator>>(inputfile& SaveFile, scar& Scar)
3479 SaveFile >> Scar.Severity >> Scar.PanelBitmap;
3480 return SaveFile;
3483 int bodypart::CalculateScarAttributePenalty(int Attribute) const
3485 double DoubleAttribute = Attribute;
3487 for(unsigned int c = 0; c < Scar.size(); ++c)
3488 DoubleAttribute *= (100. - Scar[c].Severity * 4) / 100;
3490 return Min(Attribute - int(DoubleAttribute), Attribute - 1);
3493 bodypart::~bodypart()
3495 for(unsigned int c = 0; c < Scar.size(); ++c)
3496 delete Scar[c].PanelBitmap;
3499 bodypart::bodypart(const bodypart& B) : mybase(B), OwnerDescription(B.OwnerDescription), Master(B.Master), CarriedWeight(B.CarriedWeight), BodyPartVolume(B.BodyPartVolume), BitmapPos(B.BitmapPos), ColorB(B.ColorB), ColorC(B.ColorC), ColorD(B.ColorD), SpecialFlags(B.SpecialFlags), HP(B.HP), MaxHP(B.MaxHP), BloodMaterial(B.BloodMaterial), NormalMaterial(B.NormalMaterial), SpillBloodCounter(B.SpillBloodCounter), WobbleData(B.WobbleData), Scar(B.Scar)
3501 for(unsigned int c = 0; c < Scar.size(); ++c)
3502 if(Scar[c].PanelBitmap)
3503 Scar[c].PanelBitmap = new bitmap(Scar[c].PanelBitmap);
3506 /* Amount should be > 0 */
3508 void bodypart::RemoveDamageIDs(int Amount)
3510 /*while(Amount)
3512 damageid& D = DamageID.front();
3513 int CurrentAmount = D.Amount;
3515 if(Amount < CurrentAmount)
3517 D.Amount -= Amount;
3518 Amount = 0;
3520 else
3522 DamageID.pop_front();
3523 Amount -= CurrentAmount;
3528 /* Amount should be > 0 */
3530 void bodypart::AddDamageID(int SrcID, int Amount)
3532 /*damageid D = { SrcID, Amount };
3533 DamageID.push_back(D);*/
3536 int arm::GetCurrentSWeaponSkillBonus() const
3538 return (*GetCurrentSWeaponSkill()
3539 ? (*GetCurrentSWeaponSkill())->GetBonus() : 1);
3542 v2 battorso::GetBitmapPos(int Frame) const
3544 v2 BasePos = torso::GetBitmapPos(Frame);
3545 Frame &= 0xF;
3546 return v2(BasePos.X + ((Frame &~ 3) << 2), BasePos.Y);
3549 v2 spidertorso::GetBitmapPos(int Frame) const
3551 v2 BasePos = torso::GetBitmapPos(Frame);
3552 Frame &= 0xF;
3553 return v2(BasePos.X + ((Frame &~ 7) << 1), BasePos.Y);
3556 truth arm::HasSadistWeapon() const
3558 item* Wielded = GetWielded();
3559 return Wielded && Wielded->IsSadistWeapon();
3562 truth corpse::AddStateDescription(festring& Name, truth Articled) const
3564 if(!Spoils())
3565 return false;
3567 truth Hasted = true, Slowed = true;
3569 for(int c = 0; c < GetDeceased()->GetBodyParts(); ++c)
3571 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
3573 if(BodyPart)
3575 if(!(BodyPart->ItemFlags & HASTE))
3576 Hasted = false;
3578 if(!(BodyPart->ItemFlags & SLOW))
3579 Slowed = false;
3583 if((Hasted | Slowed) && Articled)
3584 Name << "a ";
3586 if(Hasted)
3587 Name << "hasted ";
3589 if(Slowed)
3590 Name << "slowed ";
3592 return true;
3596 void arm::ApplyStrengthBonus (item *Item) {
3597 if (Item && Item->AffectsArmStrength()) StrengthBonus += Item->GetEnchantment()/2;
3600 void arm::ApplyDexterityBonus (item *Item) {
3601 if (Item && Item->AffectsDexterity()) DexterityBonus += Item->GetEnchantment()/2;
3604 void leg::ApplyStrengthBonus (item *Item) {
3605 if (Item && Item->AffectsLegStrength()) StrengthBonus += Item->GetEnchantment()/2;
3608 void leg::ApplyAgilityBonus (item *Item) {
3609 if (Item && Item->AffectsAgility()) AgilityBonus += Item->GetEnchantment()/2;