6 bodypart() : Master(0) { }
7 bodypart(const bodypart
&);
9 virtual void Save(outputfile
&) const;
10 virtual void Load(inputfile
&);
11 virtual int GetGraphicsContainerIndex() const;
12 character
* GetMaster() const { return Master
; }
13 humanoid
* GetHumanoidMaster() const;
14 void SetMaster(character
* What
) { Master
= What
; }
15 virtual int GetStrengthValue() const;
16 int GetMaxHP() const { return MaxHP
; }
18 int GetHP() const { return HP
; }
19 void EditHP(int, int);
21 virtual int GetTotalResistance(int) const { return 0; }
22 virtual truth
ReceiveDamage(character
*, int, int, int);
23 cfestring
& GetOwnerDescription() const { return OwnerDescription
; }
24 void SetOwnerDescription(cfestring
& What
) { OwnerDescription
= What
; }
25 truth
IsUnique() const { return Flags
& UNIQUE
; }
26 void SetIsUnique(truth
);
27 virtual void DropEquipment(stack
* = 0) { }
28 virtual void InitSpecialAttributes() { }
29 virtual void SignalEquipmentAdd(gearslot
*);
30 virtual void SignalEquipmentRemoval(gearslot
*, citem
*);
31 virtual void Mutate();
32 sLong
GetBodyPartVolume() const { return BodyPartVolume
; }
33 sLong
GetCarriedWeight() const { return CarriedWeight
; }
34 virtual item
* GetEquipment(int) const { return 0; }
35 virtual int GetEquipments() const { return 0; }
36 virtual void CalculateVolumeAndWeight();
37 virtual void CalculateEmitation();
38 void CalculateMaxHP(feuLong
= MAY_CHANGE_HPS
|CHECK_USABILITY
);
39 virtual void SignalVolumeAndWeightChange();
42 virtual void CalculateDamage() { }
43 virtual void CalculateToHitValue() { }
44 virtual void CalculateAPCost() { }
45 void CalculateAttackInfo();
46 double GetTimeToDie(int, double, double, truth
, truth
) const;
47 virtual double GetRoughChanceToHit(double, double) const;
48 cfestring
& GetBodyPartName() const { return GetNameSingular(); }
49 void RandomizePosition();
50 void ResetPosition() { SpecialFlags
&= ~0x7; }
51 virtual void SignalSpoil(material
*);
52 virtual truth
CanBePiledWith(citem
*, ccharacter
*) const;
53 truth
IsAlive() const;
55 void SpillBlood(int, v2
);
57 int GetConditionColorIndex() const;
58 void SetBitmapPos(v2 What
) { BitmapPos
= What
; }
59 void SetSpecialFlags(int What
) { SpecialFlags
= What
; }
60 void SetWobbleData(int What
) { WobbleData
= What
; }
61 void SetMaterialColorB(col16 What
) { ColorB
= What
; }
62 void SetMaterialColorC(col16 What
) { ColorC
= What
; }
63 void SetMaterialColorD(col16 What
) { ColorD
= What
; }
64 virtual void SignalEnchantmentChange();
65 virtual void CalculateAttributeBonuses() { }
66 virtual void SignalSpoilLevelChange(material
*);
67 virtual truth
CanBeEatenByAI(ccharacter
*) const;
68 virtual truth
DamageArmor(character
*, int, int) { return false; }
69 truth
CanBeSevered(int) const;
70 virtual truth
EditAllAttributes(int) { return false; }
71 virtual void Draw(blitdata
&) const;
72 void SetSparkleFlags(int);
73 virtual int GetSpecialFlags() const;
74 virtual truth
IsRepairable(ccharacter
*) const;
76 truth
UseMaterialAttributes() const;
77 truth
CanRegenerate() const;
78 truth
CanHaveParasite() const;
79 virtual square
* GetSquareUnder(int = 0) const;
80 virtual lsquare
* GetLSquareUnder(int = 0) const;
81 virtual item
* GetArmorToReceiveFluid(truth
) const { return 0; }
82 virtual void SpillFluid(character
*, liquid
*, int = 0);
84 void SetBloodMaterial(int What
) { BloodMaterial
= What
; }
85 int GetBloodMaterial() const { return BloodMaterial
; }
86 liquid
* CreateBlood(sLong
) const;
87 virtual truth
UpdateArmorPictures() { return false; }
88 virtual void DrawArmor(blitdata
&) const { }
89 virtual void UpdatePictures();
90 item
*GetExternalBodyArmor () const;
91 item
*GetExternalCloak () const;
92 item
*GetExternalHelmet () const;
93 item
*GetExternalBelt () const;
94 virtual void ReceiveAcid(material
*, cfestring
&, sLong
);
95 virtual truth
ShowFluids() const { return false; }
96 virtual void TryToRust(sLong
);
97 virtual truth
AllowFluidBe() const;
98 virtual material
* RemoveMaterial(material
*);
99 virtual void CopyAttributes(const bodypart
*) { }
100 virtual void DestroyBodyPart(stack
*);
101 virtual void SetLifeExpectancy(int, int);
102 virtual void SpecialEatEffect(character
*, int);
103 virtual character
* GetBodyPartMaster() const { return Master
; }
104 virtual truth
AllowFluids() const { return true; }
105 truth
IsBadlyHurt() const { return Flags
& BADLY_HURT
; }
106 truth
IsStuck() const { return Flags
& STUCK
; }
107 truth
IsUsable() const { return !(Flags
& (BADLY_HURT
|STUCK
)); }
108 virtual void SignalPossibleUsabilityChange() { UpdateFlags(); }
109 void SetIsInfectedByLeprosy(truth
);
110 virtual int GetSparkleFlags() const;
111 virtual truth
MaterialIsChangeable(ccharacter
*) const;
112 virtual void RemoveRust();
114 virtual sLong
GetFixPrice() const;
115 virtual truth
IsFixableBySmith(ccharacter
*) const;
116 virtual truth
IsFixableByTailor(ccharacter
*) const;
117 virtual void SignalMaterialChange();
118 void SetNormalMaterial(int What
) { NormalMaterial
= What
; }
119 virtual truth
IsBroken() const { return HP
< MaxHP
; }
120 virtual truth
IsDestroyable(ccharacter
*) const;
121 void DrawScars(cblitdata
&) const;
122 static truth
DamageTypeCanScar(int);
123 void GenerateScar(int, int);
124 int CalculateScarAttributePenalty(int) const;
125 virtual truth
IsBodyPart () const { return true; }
128 virtual alpha
GetMaxAlpha() const;
129 virtual void GenerateMaterials() { }
130 virtual void AddPostFix(festring
&, int) const;
131 virtual truth
ShowMaterial() const;
132 virtual int GetArticleMode() const;
133 virtual col16
GetMaterialColorA(int) const;
134 virtual col16
GetMaterialColorB(int) const { return ColorB
; }
135 virtual col16
GetMaterialColorC(int) const { return ColorC
; }
136 virtual col16
GetMaterialColorD(int) const { return ColorD
; }
137 virtual v2
GetBitmapPos(int) const { return BitmapPos
; }
138 virtual int GetWobbleData() const { return WobbleData
; }
139 void UpdateArmorPicture(graphicdata
&, item
*, int, v2 (item::*)(int) const, truth
= false) const;
140 void DrawEquipment(const graphicdata
&, blitdata
&) const;
142 truth
MasterIsAnimated() const;
143 void SignalAnimationStateChange(truth
);
144 virtual truth
AddAdjective(festring
&, truth
) const;
145 void RemoveDamageIDs(int);
146 void AddDamageID(int, int);
147 festring OwnerDescription
;
150 sLong BodyPartVolume
;
159 short NormalMaterial
;
160 uChar SpillBloodCounter
;
162 std::vector
<scar
> Scar
;
163 std::deque
<damageid
> DamageID
;
171 int bodypart::GetGraphicsContainerIndex() const { return GR_HUMANOID
; }
175 int bodypart::GetArticleMode() const { return IsUnique() ? FORCE_THE
: 0; }
179 truth
bodypart::IsAlive() const { return MainMaterial
->GetBodyFlags() & IS_ALIVE
; }
183 int bodypart::GetSpecialFlags() const { return SpecialFlags
|ST_OTHER_BODYPART
; }
187 col16
bodypart::GetMaterialColorA(int) const { return GetMainMaterial()->GetSkinColor(); }
191 truth
bodypart::IsWarm() const { return MainMaterial
->GetBodyFlags() & IS_WARM
; }
195 truth
bodypart::UseMaterialAttributes() const { return MainMaterial
->GetBodyFlags() & USE_MATERIAL_ATTRIBUTES
|| !Master
|| Master
->AlwaysUseMaterialAttributes(); }
199 truth
bodypart::CanRegenerate() const { return MainMaterial
->GetBodyFlags() & CAN_REGENERATE
; }
203 truth
bodypart::CanHaveParasite() const { return MainMaterial
->GetBodyFlags() & CAN_HAVE_PARASITE
; }
207 square
* bodypart::GetSquareUnder(int I
) const { return Master
? Slot
[0]->GetSquareUnder(I
) : Slot
[I
]->GetSquareUnder(); }
211 lsquare
* bodypart::GetLSquareUnder(int I
) const { return static_cast<lsquare
*>(Master
? Slot
[0]->GetSquareUnder(I
) : Slot
[I
]->GetSquareUnder()); }
215 item
* bodypart::GetExternalBodyArmor() const { return GetHumanoidMaster()->GetBodyArmor(); }
219 item
* bodypart::GetExternalCloak() const { return GetHumanoidMaster()->GetCloak(); }
223 truth
bodypart::AllowFluidBe() const { return !Master
|| !Master
->IsPolymorphed(); }
227 item
*bodypart::GetExternalHelmet () const { return GetHumanoidMaster()->GetHelmet(); }
231 item
*bodypart::GetExternalBelt () const { return GetHumanoidMaster()->GetBelt(); }
235 void bodypart::Save(outputfile
& SaveFile
) const
237 item::Save(SaveFile
);
238 SaveFile
<< BitmapPos
<< ColorB
<< ColorC
<< ColorD
<< SpecialFlags
<< WobbleData
<< HP
;
239 SaveFile
<< OwnerDescription
<< BloodMaterial
<< NormalMaterial
<< Scar
<< DamageID
;
244 void bodypart::Load(inputfile
& SaveFile
)
246 item::Load(SaveFile
);
247 SaveFile
>> BitmapPos
>> ColorB
>> ColorC
>> ColorD
>> SpecialFlags
>> WobbleData
>> HP
;
248 SaveFile
>> OwnerDescription
>> BloodMaterial
>> NormalMaterial
>> Scar
>> DamageID
;
253 int bodypart::GetStrengthValue() const
255 if(!UseMaterialAttributes())
256 return sLong(GetStrengthModifier()) * Master
->GetAttribute(ENDURANCE
) / 2000;
258 return sLong(GetStrengthModifier()) * GetMainMaterial()->GetStrengthValue() / 2000;
263 truth
bodypart::ReceiveDamage(character
* Damager
, int Damage
, int Type
, int)
267 if(Type
& POISON
&& !IsAlive())
272 if(HP
<= Damage
&& !CanBeSevered(Type
))
273 Damage
= GetHP() - 1;
280 if(Type
& DRAIN
&& IsAlive())
281 for(int c
= 0; c
< Damage
; ++c
)
282 Damager
->HealHitPoint();
284 truth WasBadlyHurt
= IsBadlyHurt();
289 if(DamageTypeCanScar(Type
) && !(RAND_N(25 + 25 * HP
/ MaxHP
)))
290 GenerateScar(Damage
, Type
);
292 if (Master
->IsPlayer()) {
293 if (HP
== 1 && BHP
> 1) {
294 if (IsAlive()) ADD_MESSAGE("Your %s bleeds very badly.", GetBodyPartName().CStr());
295 else ADD_MESSAGE("Your %s is in very bad condition.", GetBodyPartName().CStr());
296 if (Master
->BodyPartIsVital(GetBodyPartIndex())) game::AskForEscPress(CONST_S("Vital bodypart in serious danger!"));
297 } else if (IsBadlyHurt() && !WasBadlyHurt
) {
298 if (IsAlive()) ADD_MESSAGE("Your %s bleeds.", GetBodyPartName().CStr());
299 else ADD_MESSAGE("Your %s is in bad condition.", GetBodyPartName().CStr());
300 if (Master
->BodyPartIsVital(GetBodyPartIndex())) game::AskForEscPress(CONST_S("Vital bodypart in danger!"));
303 SignalPossibleUsabilityChange();
311 truth
bodypart::CanBeSevered(int Type
) const
313 if((HP
== MaxHP
&& HP
!= 1 && !Master
->IsExtraFragile())
314 || (Type
& (POISON
|SOUND
) && GetBodyPartIndex() != TORSO_INDEX
))
317 if(!Master
->BodyPartIsVital(GetBodyPartIndex()) || Master
->IsExtraFragile())
320 bodypart
* Torso
= Master
->GetTorso();
321 return Torso
->HP
!= Torso
->MaxHP
|| Torso
->HP
== 1;
326 humanoid
* bodypart::GetHumanoidMaster() const
328 return static_cast<humanoid
*>(Master
);
333 int bodypart::GetSparkleFlags() const
335 return (GetMainMaterial()->SkinColorIsSparkling() ? SPARKLING_A
: 0)
336 | (Flags
>> BODYPART_SPARKLE_SHIFT
& (SPARKLING_B
|SPARKLING_C
|SPARKLING_D
));
341 void bodypart::SignalEquipmentAdd(gearslot
* Slot
)
344 Master
->SignalEquipmentAdd(Slot
->GetEquipmentIndex());
349 void bodypart::SignalEquipmentRemoval(gearslot
* Slot
, citem
* Item
)
352 Master
->SignalEquipmentRemoval(Slot
->GetEquipmentIndex(), Item
);
357 void bodypart::Mutate()
359 GetMainMaterial()->SetVolume(sLong(GetVolume() * (1.5 - (RAND() & 1023) / 1023.)));
364 alpha
bodypart::GetMaxAlpha() const
366 if(Master
&& Master
->StateIsActivated(INVISIBLE
))
374 void bodypart::AddPostFix(festring
& String
, int) const
376 if(!OwnerDescription
.IsEmpty())
377 String
<< ' ' << OwnerDescription
;
382 void bodypart::CalculateVolumeAndWeight()
384 item::CalculateVolumeAndWeight();
386 BodyPartVolume
= Volume
;
388 for(int c
= 0; c
< GetEquipments(); ++c
)
390 item
* Equipment
= GetEquipment(c
);
394 Volume
+= Equipment
->GetVolume();
395 CarriedWeight
+= Equipment
->GetWeight();
399 Weight
+= CarriedWeight
;
404 void bodypart::CalculateEmitation()
406 item::CalculateEmitation();
408 for(int c
= 0; c
< GetEquipments(); ++c
)
410 item
* Equipment
= GetEquipment(c
);
413 game::CombineLights(Emitation
, Equipment
->GetEmitation());
419 void bodypart::CalculateMaxHP(feuLong Flags
)
421 int HPDelta
= MaxHP
- HP
/*k8, OldMaxHP = MaxHP*/;
426 if(!UseMaterialAttributes())
428 sLong Endurance
= Master
->GetAttribute(ENDURANCE
);
429 double DoubleHP
= GetBodyPartVolume() * Endurance
* Endurance
/ 200000;
431 for(unsigned int c
= 0; c
< Scar
.size(); ++c
)
432 DoubleHP
*= (100. - Scar
[c
].Severity
* 4) / 100;
434 MaxHP
= int(DoubleHP
);
438 sLong SV
= GetMainMaterial()->GetStrengthValue();
439 MaxHP
= (GetBodyPartVolume() * SV
>> 4) * SV
/ 250000;
445 if(Flags
& MAY_CHANGE_HPS
)
447 if(MaxHP
- HPDelta
> 1)
448 HP
= MaxHP
- HPDelta
;
457 if(Flags
& CHECK_USABILITY
)
458 SignalPossibleUsabilityChange();
464 void bodypart::SignalVolumeAndWeightChange()
466 item::SignalVolumeAndWeightChange();
468 if(Master
&& !Master
->IsInitializing())
471 Master
->CalculateHP();
472 Master
->CalculateMaxHP();
473 Master
->SignalBodyPartVolumeAndWeightChange();
474 square
* SquareUnder
= GetSquareUnder();
476 if(UpdateArmorPictures() && SquareUnder
)
477 SquareUnder
->SendNewDrawRequest();
483 void bodypart::SetHP(int What
)
489 Master
->CalculateHP();
490 SignalPossibleUsabilityChange();
496 void bodypart::EditHP(int SrcID
, int What
)
501 RemoveDamageIDs(-What
);
503 AddDamageID(SrcID
, What
);
507 Master
->CalculateHP();
508 SignalPossibleUsabilityChange();
514 void bodypart::CalculateAttackInfo()
517 CalculateToHitValue();
523 double bodypart::GetTimeToDie(int Damage
, double ToHitValue
, double DodgeValue
, truth AttackIsBlockable
, truth UseMaxHP
) const
526 int TotalResistance
= GetTotalResistance(PHYSICAL_DAMAGE
);
527 int Damage3
= (Damage
<< 1) + Damage
;
528 int Damage5
= (Damage
<< 2) + Damage
;
529 int TrueDamage
= (19 * (Max((Damage3
>> 2) - TotalResistance
, 0)
530 + Max((Damage5
>> 2) + 1 - (TotalResistance
>> 1), 0))
531 + (Max(((Damage3
+ (Damage3
>> 1)) >> 2) - TotalResistance
, 0)
532 + Max(((Damage5
+ (Damage5
>> 1)) >> 2) + 3 - (TotalResistance
>> 1), 0))) / 40;
534 int HP
= UseMaxHP
? GetMaxHP() : GetHP();
538 double AverageDamage
;
540 if(AttackIsBlockable
)
543 Master
->CreateBlockPossibilityVector(Block
, ToHitValue
);
547 double ChanceForNoBlock
= 1.0;
550 for(uInt c
= 0; c
< Block
.size(); ++c
)
552 ChanceForNoBlock
-= Block
[c
].first
;
554 if(TrueDamage
- Block
[c
].second
> 0)
555 AverageDamage
+= Block
[c
].first
* (TrueDamage
- Block
[c
].second
);
558 AverageDamage
+= ChanceForNoBlock
* TrueDamage
;
561 AverageDamage
= TrueDamage
;
564 AverageDamage
= TrueDamage
;
566 Durability
= HP
/ (AverageDamage
* GetRoughChanceToHit(ToHitValue
, DodgeValue
));
571 if(Durability
> 1000)
582 double bodypart::GetRoughChanceToHit(double ToHitValue
, double DodgeValue
) const
584 return GLOBAL_WEAK_BODYPART_HIT_MODIFIER
* ToHitValue
* GetBodyPartVolume() / ((DodgeValue
/ ToHitValue
+ 1) * DodgeValue
* Master
->GetBodyVolume() * 100);
589 void bodypart::RandomizePosition()
591 SpecialFlags
|= 1 + RAND() % 7;
597 void bodypart::SignalSpoil(material
* Material
)
600 Master
->SignalSpoil();
602 item::SignalSpoil(Material
);
607 truth
bodypart::CanBePiledWith(citem
* Item
, ccharacter
* Viewer
) const
609 return item::CanBePiledWith(Item
, Viewer
)
610 && OwnerDescription
== static_cast<const bodypart
*>(Item
)->OwnerDescription
;
619 if(HP
< MaxHP
&& ++SpillBloodCounter
>= 4)
621 if(Master
->IsEnabled())
623 if(IsBadlyHurt() && !Master
->IsPolymorphed() && !(RAND() & 3))
626 else if(!Master
->IsPolymorphed() && !(RAND() & 3))
629 HP
+= Max(((MaxHP
- HP
) >> 2), 1);
632 SpillBloodCounter
= 0;
635 if(Master
->AllowSpoil() || !Master
->IsEnabled())
636 MainMaterial
->Be(ItemFlags
);
638 if (Exists() && LifeExpectancy
) {
639 if (LifeExpectancy
== 1) Master
->SignalDisappearance(); else --LifeExpectancy
;
644 if(HP
< MaxHP
&& ++SpillBloodCounter
>= 4)
649 HP
+= Max(((MaxHP
- HP
) >> 2), 1);
652 SpillBloodCounter
= 0;
661 void bodypart::SpillBlood(int HowMuch
, v2 Pos
)
663 if(HowMuch
&& (!Master
|| Master
->SpillsBlood()) && (IsAlive() || MainMaterial
->IsLiquid()) && !game::IsInWilderness())
664 GetNearLSquare(Pos
)->SpillFluid(0, CreateBlood(sLong(HowMuch
* sqrt(BodyPartVolume
) / 2)), false, false);
669 void bodypart::SpillBlood(int HowMuch
)
671 if(HowMuch
&& (!Master
|| Master
->SpillsBlood()) && (IsAlive() || MainMaterial
->IsLiquid()) && !game::IsInWilderness())
672 for(int c
= 0; c
< GetSquaresUnder(); ++c
)
673 if(GetLSquareUnder(c
))
674 GetLSquareUnder(c
)->SpillFluid(0, CreateBlood(sLong(HowMuch
* sqrt(BodyPartVolume
) / 2)), false, false);
679 void bodypart::SignalEnchantmentChange()
681 if(Master
&& !Master
->IsInitializing())
683 Master
->CalculateAttributeBonuses();
684 Master
->CalculateBattleInfo();
690 void bodypart::SignalSpoilLevelChange(material
* Material
)
693 Master
->SignalSpoilLevelChange();
695 item::SignalSpoilLevelChange(Material
);
700 truth
bodypart::CanBeEatenByAI(ccharacter
* Who
) const
702 return item::CanBeEatenByAI(Who
) && !(Who
->IsPet() && PLAYER
->HasHadBodyPart(this));
707 int bodypart::GetConditionColorIndex() const
709 if(HP
<= 1 && MaxHP
> 1)
711 else if((HP
<< 1) + HP
< MaxHP
)
713 else if((HP
<< 1) + HP
< MaxHP
<< 1)
723 void bodypart::Draw(blitdata
& BlitData
) const
725 cint AF
= GraphicData
.AnimationFrames
;
726 cint F
= !(BlitData
.CustomData
& ALLOW_ANIMATE
) || AF
== 1 ? 0 : GET_TICK() & (AF
- 1);
727 cbitmap
* P
= GraphicData
.Picture
[F
];
729 if(BlitData
.CustomData
& ALLOW_ALPHA
)
730 P
->AlphaPriorityBlit(BlitData
);
732 P
->MaskedPriorityBlit(BlitData
);
734 if(Fluid
&& ShowFluids())
735 DrawFluids(BlitData
);
742 truth
bodypart::IsRepairable(ccharacter
*) const
744 return !CanRegenerate() && (GetHP() < GetMaxHP() || IsRusted());
749 void bodypart::SpillFluid(character
* Spiller
, liquid
* Liquid
, int SquareIndex
)
753 item
* Armor
= GetArmorToReceiveFluid(false);
756 Armor
->SpillFluid(Spiller
, Liquid
);
759 if(Liquid
->GetVolume())
760 AddFluid(Liquid
, "", SquareIndex
, false);
766 item::SpillFluid(Spiller
, Liquid
, SquareIndex
);
771 void bodypart::StayOn(liquid
* Liquid
)
773 item
* Armor
= GetArmorToReceiveFluid(true);
776 Liquid
->TouchEffect(Armor
, CONST_S(""));
778 Liquid
->TouchEffect(GetMaster(), GetBodyPartIndex());
783 liquid
* bodypart::CreateBlood(sLong Volume
) const
785 return liquid::Spawn(GetBloodMaterial(), Volume
);
790 void bodypart::UpdateArmorPicture(graphicdata
& GData
, item
* Armor
, int SpecialFlags
, v2 (item::*Retriever
)(int) const, truth BodyArmor
) const
794 Armor
->UpdatePictures(GData
,
796 SpecialFlags
|Armor
->GetSpecialFlags(),
799 static_cast<bposretriever
>(Retriever
));
800 Armor
->CheckFluidGearPictures((Armor
->*Retriever
)(0), SpecialFlags
, BodyArmor
);
808 void bodypart::DrawEquipment(const graphicdata
& GraphicData
, blitdata
& BlitData
) const
810 int EAF
= GraphicData
.AnimationFrames
;
814 int F
= !(BlitData
.CustomData
& ALLOW_ANIMATE
) || EAF
== 1 ? 0 : GET_TICK() & (EAF
- 1);
815 GraphicData
.Picture
[F
]->AlphaPriorityBlit(BlitData
);
821 truth
bodypart::MasterIsAnimated() const
823 return Master
&& !Master
->IsInitializing() && Master
->IsAnimated();
828 void bodypart::UpdatePictures()
830 truth WasAnimated
= MasterIsAnimated();
832 item::UpdatePictures();
833 UpdateArmorPictures();
835 if(!WasAnimated
!= !MasterIsAnimated())
836 SignalAnimationStateChange(WasAnimated
);
841 void bodypart::ReceiveAcid (material
*Material
, cfestring
&LocationName
, sLong Modifier
) {
842 if (Master
&& MainMaterial
->GetInteractionFlags() & CAN_DISSOLVE
) {
843 sLong Tries
= Modifier
/1000;
844 Modifier
-= Tries
*1000; //opt%?
846 for (sLong c
= 0; c
< Tries
; ++c
) if (!(RAND() % 100)) ++Damage
;
847 if (Modifier
&& !(RAND()%100000/Modifier
)) ++Damage
;
849 feuLong Minute
= game::GetTotalMinutes();
850 character
*Master
= this->Master
;
851 if (Master
->GetLastAcidMsgMin() != Minute
&& (Master
->CanBeSeenByPlayer() || Master
->IsPlayer())) {
852 Master
->SetLastAcidMsgMin(Minute
);
853 cchar
*MName
= Material
->GetName(false, false).CStr();
854 if (Master
->IsPlayer()) {
855 cchar
*TName
= LocationName
.IsEmpty() ? GetBodyPartName().CStr() : LocationName
.CStr();
856 ADD_MESSAGE("Acidous %s dissolves your %s.", MName
, TName
);
858 ADD_MESSAGE("Acidous %s dissolves %s.", MName
, Master
->CHAR_NAME(DEFINITE
));
861 Master
->ReceiveBodyPartDamage(0, Damage
, ACID
, GetBodyPartIndex(), YOURSELF
, false, false, false);
862 feuLong DeathFlags
= Material
->IsStuckTo(Master
) ? IGNORE_TRAPS
: 0;
863 Master
->CheckDeath(CONST_S("dissolved by ")+Material
->GetName(), 0, DeathFlags
);
870 void bodypart::TryToRust(sLong LiquidModifier
)
872 if(MainMaterial
->TryToRust(LiquidModifier
<< 4))
874 cchar
* MoreMsg
= MainMaterial
->GetRustLevel() == NOT_RUSTED
? "" : " more";
878 if(Master
->IsPlayer())
879 ADD_MESSAGE("Your %s rusts%s.", CHAR_NAME(UNARTICLED
), MoreMsg
);
880 else if(CanBeSeenByPlayer())
881 ADD_MESSAGE("The %s of %s rusts%s.", CHAR_NAME(UNARTICLED
), Master
->CHAR_NAME(DEFINITE
), MoreMsg
);
883 else if(CanBeSeenByPlayer())
884 ADD_MESSAGE("%s rusts%s.", CHAR_NAME(DEFINITE
), MoreMsg
);
886 MainMaterial
->SetRustLevel(MainMaterial
->GetRustLevel() + 1);
892 material
* bodypart::RemoveMaterial(material
* Material
)
894 if(Master
&& GetBodyPartIndex() == TORSO_INDEX
)
895 return Master
->GetMotherEntity()->RemoveMaterial(Material
); // gum
897 return item::RemoveMaterial(Material
);
902 void bodypart::DestroyBodyPart(stack
* Stack
)
904 int Lumps
= 1 + RAND() % 3;
905 sLong LumpVolume
= Volume
/ Lumps
>> 2;
908 for(int c
= 0; c
< Lumps
; ++c
)
910 item
* Lump
= GetMainMaterial()->CreateNaturalForm(LumpVolume
+ RAND() % LumpVolume
);
911 Stack
->AddItem(Lump
);
919 void bodypart::SetLifeExpectancy(int Base
, int RandPlus
)
921 LifeExpectancy
= RandPlus
> 1 ? Base
+ RAND_N(RandPlus
) : Base
;
929 void bodypart::SpecialEatEffect(character
* Eater
, int Amount
)
933 if(Amount
&& (!Master
|| Master
->SpillsBlood()) && (IsAlive() || MainMaterial
->IsLiquid()) && !game::IsInWilderness())
935 if(Eater
->GetVirtualHead())
936 Eater
->GetVirtualHead()->SpillFluid(Eater
, CreateBlood(Amount
));
938 Eater
->GetTorso()->SpillFluid(Eater
, CreateBlood(Amount
));
944 void bodypart::UpdateFlags()
946 if((HP
<< 1) + HP
< MaxHP
|| (HP
== 1 && MaxHP
!= 1))
949 Flags
&= ~BADLY_HURT
;
951 if(Master
->BodyPartIsStuck(GetBodyPartIndex()))
959 void bodypart::IncreaseHP()
963 SignalPossibleUsabilityChange();
968 void bodypart::FastRestoreHP()
972 SignalPossibleUsabilityChange();
977 void bodypart::RestoreHP()
981 SignalPossibleUsabilityChange();
982 Master
->CalculateHP();
987 void bodypart::SetIsUnique(truth What
)
997 void bodypart::SetIsInfectedByLeprosy(truth What
)
999 MainMaterial
->SetIsInfectedByLeprosy(What
);
1004 void bodypart::SetSparkleFlags(int What
)
1006 cint S
= SPARKLING_B
|SPARKLING_C
|SPARKLING_D
;
1007 Flags
= (Flags
& ~(S
<< BODYPART_SPARKLE_SHIFT
)) | ((What
& S
) << BODYPART_SPARKLE_SHIFT
);
1012 void bodypart::SignalAnimationStateChange(truth WasAnimated
)
1016 for(int c
= 0; c
< GetSquaresUnder(); ++c
)
1018 square
* Square
= GetSquareUnder(c
);
1021 Square
->DecAnimatedEntities();
1026 for(int c
= 0; c
< GetSquaresUnder(); ++c
)
1028 square
* Square
= GetSquareUnder(c
);
1031 Square
->IncAnimatedEntities();
1038 truth
bodypart::MaterialIsChangeable(ccharacter
*) const
1040 return !Master
|| !Master
->BodyPartIsVital(GetBodyPartIndex()) || UseMaterialAttributes();
1045 truth
bodypart::AddAdjective(festring
& String
, truth Articled
) const
1052 String
<< "severed ";
1061 void bodypart::RemoveRust()
1069 sLong
bodypart::GetFixPrice() const
1071 return GetMaxHP() - GetHP() + GetMainMaterial()->GetRustLevel() * 25;
1076 truth
bodypart::IsFixableBySmith(ccharacter
*) const
1078 return (GetMainMaterial()->GetCategoryFlags() & IS_METAL
1079 && (GetHP() < GetMaxHP() || IsRusted()));
1084 truth
bodypart::IsFixableByTailor(ccharacter
*) const
1086 return (GetMainMaterial()->GetCategoryFlags() & CAN_BE_TAILORED
1087 && GetHP() < GetMaxHP());
1092 item
* bodypart::Fix()
1100 void bodypart::SignalMaterialChange()
1108 truth
bodypart::ShowMaterial() const
1110 return MainMaterial
->GetConfig() != NormalMaterial
;
1115 truth
bodypart::IsDestroyable(ccharacter
*) const
1117 return !Master
|| !Master
->BodyPartIsVital(GetBodyPartIndex());
1122 truth
bodypart::DamageTypeCanScar(int Type
)
1124 return !(Type
== POISON
|| Type
== DRAIN
);
1129 void bodypart::GenerateScar(int Damage
, int Type
)
1131 Scar
.push_back(scar());
1132 scar
& NewScar
= Scar
.back();
1133 NewScar
.Severity
= 1 + RAND_N(1 + 5 * Damage
/ GetMaxHP());
1135 if(GetMaster()->IsPlayer())
1137 int ScarColor
= MakeShadeColor(GetMainMaterial()->GetColor());
1138 NewScar
.PanelBitmap
= igraph::GenerateScarBitmap(GetBodyPartIndex(),
1141 ADD_MESSAGE("Your %s is scarred.", CHAR_NAME(UNARTICLED
));
1144 NewScar
.PanelBitmap
= 0;
1147 GetMaster()->CalculateMaxHP();
1148 GetMaster()->CalculateAttributeBonuses();
1149 CalculateAttackInfo();
1154 void bodypart::DrawScars(cblitdata
& B
) const
1156 for(unsigned int c
= 0; c
< Scar
.size(); ++c
)
1158 if(!Scar
[c
].PanelBitmap
)
1160 int ScarColor
= MakeShadeColor(GetMainMaterial()->GetColor());
1161 Scar
[c
].PanelBitmap
= igraph::GenerateScarBitmap(GetBodyPartIndex(),
1166 Scar
[c
].PanelBitmap
->NormalMaskedBlit(B
);
1172 int bodypart::CalculateScarAttributePenalty(int Attribute
) const
1174 double DoubleAttribute
= Attribute
;
1176 for(unsigned int c
= 0; c
< Scar
.size(); ++c
)
1177 DoubleAttribute
*= (100. - Scar
[c
].Severity
* 4) / 100;
1179 return Min(Attribute
- int(DoubleAttribute
), Attribute
- 1);
1184 bodypart::~bodypart()
1186 for(unsigned int c
= 0; c
< Scar
.size(); ++c
)
1187 delete Scar
[c
].PanelBitmap
;
1192 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
)
1194 for(unsigned int c
= 0; c
< Scar
.size(); ++c
)
1195 if(Scar
[c
].PanelBitmap
)
1196 Scar
[c
].PanelBitmap
= new bitmap(Scar
[c
].PanelBitmap
);
1201 void bodypart::RemoveDamageIDs(int Amount
)
1205 damageid& D = DamageID.front();
1206 int CurrentAmount = D.Amount;
1208 if(Amount < CurrentAmount)
1215 DamageID.pop_front();
1216 Amount -= CurrentAmount;
1223 void bodypart::AddDamageID(int SrcID
, int Amount
)
1225 /*damageid D = { SrcID, Amount };
1226 DamageID.push_back(D);*/