1 /*
2 *
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
7 *
8 * See LICENSING which should be included
9 * along with this file for more details
10 *
11 */
12
13 /* Compiled through itemset.cpp */
14
15 #include "dbgmsgproj.h"
16
GetGraphicsContainerIndex() const17 int bodypart::GetGraphicsContainerIndex() const { return GR_HUMANOID; }
GetArticleMode() const18 int bodypart::GetArticleMode() const { return IsUnique() ? FORCE_THE : 0; }
IsAlive() const19 truth bodypart::IsAlive() const { return MainMaterial->GetBodyFlags() & IS_ALIVE; }
GetSpecialFlags() const20 int bodypart::GetSpecialFlags() const { return SpecialFlags|ST_OTHER_BODYPART; }
GetMaterialColorA(int) const21 col16 bodypart::GetMaterialColorA(int) const { return GetMainMaterial()->GetSkinColor(); }
IsWarm() const22 truth bodypart::IsWarm() const { return MainMaterial->GetBodyFlags() & IS_WARM || IsBurning(); }
IsWarmBlooded() const23 truth bodypart::IsWarmBlooded() const { return MainMaterial->GetBodyFlags() & IS_WARM_BLOODED; }
UseMaterialAttributes() const24 truth bodypart::UseMaterialAttributes() const
25 { return MainMaterial->GetBodyFlags() & USE_MATERIAL_ATTRIBUTES || !Master || Master->AlwaysUseMaterialAttributes(); }
CanRegenerate() const26 truth bodypart::CanRegenerate() const { return MainMaterial->GetBodyFlags() & CAN_REGENERATE; }
GetSquareUnder(int I) const27 square* bodypart::GetSquareUnder(int I) const
28 { return Master ? Slot[0]->GetSquareUnder(I) : Slot[I]->GetSquareUnder(); }
GetLSquareUnder(int I) const29 lsquare* bodypart::GetLSquareUnder(int I) const
30 { return static_cast<lsquare*>(Master ? Slot[0]->GetSquareUnder(I) : Slot[I]->GetSquareUnder()); }
GetExternalBodyArmor() const31 item* bodypart::GetExternalBodyArmor() const { return GetHumanoidMaster()->GetBodyArmor(); }
GetExternalCloak() const32 item* bodypart::GetExternalCloak() const { return GetHumanoidMaster()->GetCloak(); }
GetExternalHelmet() const33 item* bodypart::GetExternalHelmet() const { return GetHumanoidMaster()->GetHelmet(); }
GetExternalBelt() const34 item* bodypart::GetExternalBelt() const { return GetHumanoidMaster()->GetBelt(); }
AllowFluidBe() const35 truth bodypart::AllowFluidBe() const { return !Master || !Master->IsPolymorphed(); }
36
GetBodyPartIndex() const37 int head::GetBodyPartIndex() const { return HEAD_INDEX; }
GetBiteMinDamage() const38 int head::GetBiteMinDamage() const { return int(BiteDamage * 0.75); }
GetBiteMaxDamage() const39 int head::GetBiteMaxDamage() const { return int(BiteDamage * 1.25 + 1); }
40
GetBodyPartIndex() const41 int torso::GetBodyPartIndex() const { return TORSO_INDEX; }
42
GetGraphicsContainerIndex() const43 int normaltorso::GetGraphicsContainerIndex() const { return GR_CHARACTER; }
44
GetMinDamage() const45 int arm::GetMinDamage() const { return int(Damage * 0.75); }
GetMaxDamage() const46 int arm::GetMaxDamage() const { return int(Damage * 1.25 + 1); }
GetBlockValue() const47 double arm::GetBlockValue() const { return GetToHitValue() * GetWielded()->GetBlockModifier() / 10000; }
48
GetBodyPartIndex() const49 int rightarm::GetBodyPartIndex() const { return RIGHT_ARM_INDEX; }
GetSpecialFlags() const50 int rightarm::GetSpecialFlags() const { return SpecialFlags|ST_RIGHT_ARM; }
51
GetBodyPartIndex() const52 int leftarm::GetBodyPartIndex() const { return LEFT_ARM_INDEX; }
GetSpecialFlags() const53 int leftarm::GetSpecialFlags() const { return SpecialFlags|ST_LEFT_ARM; }
54
GetBodyPartIndex() const55 int groin::GetBodyPartIndex() const { return GROIN_INDEX; }
GetSpecialFlags() const56 int groin::GetSpecialFlags() const { return SpecialFlags|ST_GROIN; }
57
GetKickMinDamage() const58 int leg::GetKickMinDamage() const { return int(KickDamage * 0.75); }
GetKickMaxDamage() const59 int leg::GetKickMaxDamage() const { return int(KickDamage * 1.25 + 1); }
60
GetBodyPartIndex() const61 int rightleg::GetBodyPartIndex() const { return RIGHT_LEG_INDEX; }
GetSpecialFlags() const62 int rightleg::GetSpecialFlags() const { return SpecialFlags|ST_RIGHT_LEG; }
63
GetBodyPartIndex() const64 int leftleg::GetBodyPartIndex() const { return LEFT_LEG_INDEX; }
GetSpecialFlags() const65 int leftleg::GetSpecialFlags() const { return SpecialFlags|ST_LEFT_LEG; }
66
GetBitmapPos(int Frame) const67 v2 eddytorso::GetBitmapPos(int Frame) const { return torso::GetBitmapPos(Frame) + v2((Frame&0x6) << 3, 0); }
68
Behead()69 head* corpse::Behead() { return Deceased->Behead(); }
CanBeCloned() const70 truth corpse::CanBeCloned() const { return GetDeceased()->CanBeCloned(); }
GetAttachedGod() const71 int corpse::GetAttachedGod() const { return GetDeceased()->GetTorso()->GetAttachedGod(); }
72
GetBitmapPos(int Frame) const73 v2 ennerhead::GetBitmapPos(int Frame) const
74 { return Frame & 16 ? head::GetBitmapPos(Frame) : head::GetBitmapPos(Frame) + v2(16, 0); }
75
GetAlphaA(int Frame) const76 alpha blinkdogtorso::GetAlphaA(int Frame) const { return (Frame & 31) != 31 ? 255 : 0; }
77
Save(outputfile & SaveFile) const78 void bodypart::Save(outputfile& SaveFile) const
79 {
80 item::Save(SaveFile);
81 SaveFile << BitmapPos << ColorB << ColorC << ColorD << SpecialFlags << WobbleData << HP;
82 SaveFile << OwnerDescription << BloodMaterial << NormalMaterial << Scar << DamageID;
83 }
84
Load(inputfile & SaveFile)85 void bodypart::Load(inputfile& SaveFile)
86 {
87 item::Load(SaveFile);
88 SaveFile >> BitmapPos >> ColorB >> ColorC >> ColorD >> SpecialFlags >> WobbleData >> HP;
89 SaveFile >> OwnerDescription >> BloodMaterial >> NormalMaterial >> Scar >> DamageID;
90 }
91
GetStrengthValue() const92 int bodypart::GetStrengthValue() const
93 {
94 if(!UseMaterialAttributes())
95 return long(GetStrengthModifier()) * Master->GetAttribute(ENDURANCE) / 2000;
96 else
97 return long(GetStrengthModifier()) * GetMainMaterial()->GetStrengthValue() / 2000;
98 }
99
GetTotalResistance(int Type) const100 int head::GetTotalResistance(int Type) const
101 {
102 if(Master)
103 {
104 int Resistance = GetResistance(Type) + Master->GetGlobalResistance(Type);
105
106 if(GetHelmet())
107 Resistance += GetHelmet()->GetResistance(Type);
108
109 if(GetExternalBodyArmor())
110 Resistance += GetExternalBodyArmor()->GetResistance(Type) >> 2;
111
112 return Resistance;
113 }
114 else
115 return GetResistance(Type);
116 }
117
GetTotalResistance(int Type) const118 int normaltorso::GetTotalResistance(int Type) const
119 {
120 if(Master)
121 return GetResistance(Type) + Master->GetGlobalResistance(Type);
122 else
123 return GetResistance(Type);
124 }
125
GetTotalResistance(int Type) const126 int humanoidtorso::GetTotalResistance(int Type) const
127 {
128 if(Master)
129 {
130 int Resistance = GetResistance(Type) + Master->GetGlobalResistance(Type);
131
132 if(GetBodyArmor())
133 Resistance += GetBodyArmor()->GetResistance(Type);
134
135 if(GetBelt())
136 Resistance += GetBelt()->GetResistance(Type);
137
138 return Resistance;
139 }
140 else
141 return GetResistance(Type);
142 }
143
GetTotalResistance(int Type) const144 int arm::GetTotalResistance(int Type) const
145 {
146 if(Master)
147 {
148 int Resistance = GetResistance(Type) + Master->GetGlobalResistance(Type);
149
150 if(GetExternalBodyArmor())
151 Resistance += GetExternalBodyArmor()->GetResistance(Type) >> 1;
152
153 if(GetGauntlet())
154 Resistance += GetGauntlet()->GetResistance(Type);
155
156 return Resistance;
157 }
158 else
159 return GetResistance(Type);
160 }
161
GetTotalResistance(int Type) const162 int groin::GetTotalResistance(int Type) const
163 {
164 if(Master)
165 {
166 int Resistance = GetResistance(Type) + Master->GetGlobalResistance(Type);
167
168 if(GetExternalBodyArmor())
169 Resistance += GetExternalBodyArmor()->GetResistance(Type);
170
171 if(GetHumanoidMaster()->GetBelt())
172 Resistance += GetHumanoidMaster()->GetBelt()->GetResistance(Type);
173
174 return Resistance;
175 }
176 else
177 return GetResistance(Type);
178 }
179
GetTotalResistance(int Type) const180 int leg::GetTotalResistance(int Type) const
181 {
182 if(Master)
183 {
184 int Resistance = GetResistance(Type) + Master->GetGlobalResistance(Type);
185
186 if(GetExternalBodyArmor())
187 Resistance += GetExternalBodyArmor()->GetResistance(Type) >> 1;
188
189 if(GetBoot())
190 Resistance += GetBoot()->GetResistance(Type);
191
192 return Resistance;
193 }
194 else
195 return GetResistance(Type);
196 }
197
Save(outputfile & SaveFile) const198 void head::Save(outputfile& SaveFile) const
199 {
200 bodypart::Save(SaveFile);
201 SaveFile << BaseBiteStrength << BonusBiteStrength;
202 SaveFile << HelmetSlot << AmuletSlot;
203 }
204
Load(inputfile & SaveFile)205 void head::Load(inputfile& SaveFile)
206 {
207 bodypart::Load(SaveFile);
208 SaveFile >> BaseBiteStrength >> BonusBiteStrength;
209 SaveFile >> HelmetSlot >> AmuletSlot;
210 }
211
Save(outputfile & SaveFile) const212 void humanoidtorso::Save(outputfile& SaveFile) const
213 {
214 bodypart::Save(SaveFile);
215 SaveFile << BodyArmorSlot << CloakSlot << BeltSlot;
216 }
217
Load(inputfile & SaveFile)218 void humanoidtorso::Load(inputfile& SaveFile)
219 {
220 bodypart::Load(SaveFile);
221 SaveFile >> BodyArmorSlot >> CloakSlot >> BeltSlot;
222 }
223
Save(outputfile & SaveFile) const224 void arm::Save(outputfile& SaveFile) const
225 {
226 bodypart::Save(SaveFile);
227 SaveFile << BaseUnarmedStrength;
228 SaveFile << StrengthExperience << DexterityExperience;
229 SaveFile << WieldedSlot << GauntletSlot << RingSlot;
230 SaveFile << WieldedGraphicData;
231 }
232
Load(inputfile & SaveFile)233 void arm::Load(inputfile& SaveFile)
234 {
235 bodypart::Load(SaveFile);
236 SaveFile >> BaseUnarmedStrength;
237 SaveFile >> StrengthExperience >> DexterityExperience;
238 SaveFile >> WieldedSlot >> GauntletSlot >> RingSlot;
239 SaveFile >> WieldedGraphicData;
240 }
241
Save(outputfile & SaveFile) const242 void leg::Save(outputfile& SaveFile) const
243 {
244 bodypart::Save(SaveFile);
245 SaveFile << BaseKickStrength << StrengthExperience << AgilityExperience;
246 SaveFile << BootSlot;
247 }
248
Load(inputfile & SaveFile)249 void leg::Load(inputfile& SaveFile)
250 {
251 bodypart::Load(SaveFile);
252 SaveFile >> BaseKickStrength >> StrengthExperience >> AgilityExperience;
253 SaveFile >> BootSlot;
254 }
255
ReceiveDamage(character * Damager,int Damage,int Type,int Direction)256 truth bodypart::ReceiveDamage(character* Damager, int Damage, int Type, int Direction)
257 {DBG1(Damager);
258 if(Master)
259 {
260 if(Type & POISON && !IsAlive())
261 return false;
262
263 int BHP = HP;
264
265 if(HP <= Damage && !CanBeSevered(Type))
266 Damage = GetHP() - 1;
267
268 if(!Damage)
269 return false;
270
271 EditHP(1, -Damage);
272
273 if(Damager!=NULL && (Type & DRAIN) && IsAlive())
274 for(int c = 0; c < Damage; ++c)
275 Damager->HealHitPoint();
276
277 truth WasBadlyHurt = IsBadlyHurt();
278
279 if(HP <= 0)
280 return true;
281
282 if(DamageTypeCanScar(Type) && !(RAND_N(25 + 25 * HP / MaxHP)))
283 GenerateScar(Damage, Type);
284
285 if(Master->IsPlayer())
286 {
287 if(HP == 1 && BHP > 1)
288 {
289 if(IsAlive())
290 ADD_MESSAGE("Your %s bleeds very badly.", GetBodyPartName().CStr());
291 else
292 ADD_MESSAGE("Your %s is in very bad condition.", GetBodyPartName().CStr());
293
294 if(Master->BodyPartIsVital(GetBodyPartIndex()))
295 game::AskForKeyPress(CONST_S("Vital bodypart in serious danger! [press any key to continue]"));
296 }
297 else if(IsBadlyHurt() && !WasBadlyHurt)
298 {
299 if(IsAlive())
300 ADD_MESSAGE("Your %s bleeds.", GetBodyPartName().CStr());
301 else
302 ADD_MESSAGE("Your %s is in bad condition.", GetBodyPartName().CStr());
303
304 if(Master->BodyPartIsVital(GetBodyPartIndex()))
305 game::AskForKeyPress(CONST_S("Vital bodypart in danger! [press any key to continue]"));
306 }
307 }
308
309 SignalPossibleUsabilityChange();
310 }
311 else
312 return item::ReceiveDamage(Damager, Damage, Type, Direction);
313
314 return false;
315 }
316
CanBeSevered(int Type) const317 truth bodypart::CanBeSevered(int Type) const
318 {
319 if((HP == MaxHP && HP != 1 && !Master->IsExtraFragile())
320 || (Type & (POISON|SOUND) && GetBodyPartIndex() != TORSO_INDEX))
321 return false;
322
323 if(!Master->BodyPartIsVital(GetBodyPartIndex()) || Master->IsExtraFragile())
324 return true;
325
326 bodypart* Torso = Master->GetTorso();
327 return Torso->HP != Torso->MaxHP || Torso->HP == 1;
328 }
329
GetUnarmedDamage() const330 double arm::GetUnarmedDamage() const
331 {
332 double WeaponStrength = GetBaseUnarmedStrength() * GetBaseUnarmedStrength();
333 item* Gauntlet = GetGauntlet();
334
335 if(Gauntlet)
336 WeaponStrength += Gauntlet->GetWeaponStrength();
337
338 double Base = sqrt(5e-5 * WeaponStrength);
339
340 if(Gauntlet)
341 Base += Gauntlet->GetDamageBonus();
342
343 double Damage = Base * sqrt(1e-7 * GetAttribute(ARM_STRENGTH))
344 * GetHumanoidMaster()->GetCWeaponSkill(UNARMED)->GetBonus();
345
346 return Damage;
347 }
348
GetUnarmedToHitValue() const349 double arm::GetUnarmedToHitValue() const
350 {
351 double BonusMultiplier = 10.;
352 item* Gauntlet = GetGauntlet();
353
354 if(Gauntlet)
355 BonusMultiplier += Gauntlet->GetTHVBonus();
356
357 return GetAttribute(DEXTERITY)
358 * sqrt(2.5 * Master->GetAttribute(PERCEPTION))
359 * GetHumanoidMaster()->GetCWeaponSkill(UNARMED)->GetBonus()
360 * Master->GetMoveEase()
361 * BonusMultiplier / 5000000;
362 }
363
GetUnarmedAPCost() const364 long arm::GetUnarmedAPCost() const
365 {
366 return long(10000000000. / (APBonus(GetAttribute(DEXTERITY)) * Master->GetMoveEase()
367 * Master->GetCWeaponSkill(UNARMED)->GetBonus()));
368 }
369
CalculateDamage()370 void arm::CalculateDamage()
371 {
372 if(!Master)
373 return;
374
375 if(!IsUsable())
376 Damage = 0;
377 else if(GetWielded())
378 Damage = GetWieldedDamage();
379 else if(PairArmAllowsMelee())
380 Damage = GetUnarmedDamage();
381 else
382 Damage = 0;
383 }
384
CalculateToHitValue()385 void arm::CalculateToHitValue()
386 {
387 if(!Master)
388 return;
389
390 if(GetWielded())
391 ToHitValue = GetWieldedToHitValue();
392 else if(PairArmAllowsMelee())
393 ToHitValue = GetUnarmedToHitValue();
394 else
395 ToHitValue = 0;
396 }
397
CalculateAPCost()398 void arm::CalculateAPCost()
399 {
400 if(!Master)
401 return;
402
403 if(GetWielded())
404 APCost = GetWieldedAPCost();
405 else if(PairArmAllowsMelee())
406 APCost = GetUnarmedAPCost();
407 else return;
408
409 if(APCost < 100)
410 APCost = 100;
411 }
412
PairArmAllowsMelee() const413 truth arm::PairArmAllowsMelee() const
414 {
415 const arm* PairArm = GetPairArm();
416 return !PairArm || !PairArm->IsUsable() || !PairArm->GetWielded()
417 || PairArm->GetWielded()->IsShield(Master);
418 }
419
GetWieldedDamage() const420 double arm::GetWieldedDamage() const
421 {
422 citem* Wielded = GetWielded();
423
424 if(Wielded->IsShield(Master))
425 return 0;
426
427 int HitStrength = GetAttribute(ARM_STRENGTH);
428 int Requirement = Wielded->GetStrengthRequirement();
429
430 if(TwoHandWieldIsActive())
431 {
432 HitStrength += GetPairArm()->GetAttribute(ARM_STRENGTH);
433 Requirement >>= 2;
434 }
435
436 if(HitStrength > Requirement)
437 {
438 /* I have no idea whether this works. It needs to be checked */
439
440 return Wielded->GetBaseDamage() * sqrt(1e-13 * HitStrength)
441 * GetCurrentSWeaponSkillBonus()
442 * GetHumanoidMaster()->GetCWeaponSkill(Wielded->GetWeaponCategory())->GetBonus();
443 }
444 else
445 return 0;
446 }
447
GetWieldedToHitValue() const448 double arm::GetWieldedToHitValue() const
449 {
450 int HitStrength = GetWieldedHitStrength();
451
452 if(HitStrength <= 0)
453 return 0;
454
455 citem* Wielded = GetWielded();
456
457 double Base = 2e-11
458 * Min(HitStrength, 10)
459 * GetHumanoidMaster()->GetCWeaponSkill(Wielded->GetWeaponCategory())->GetBonus()
460 * GetCurrentSWeaponSkillBonus()
461 * Master->GetMoveEase()
462 * (10000. / (1000 + Wielded->GetWeight()) + Wielded->GetTHVBonus());
463 double ThisToHit = GetAttribute(DEXTERITY) * sqrt(2.5 * Master->GetAttribute(PERCEPTION));
464 const arm* PairArm = GetPairArm();
465
466 if(PairArm && PairArm->IsUsable())
467 {
468 citem* PairWielded = PairArm->GetWielded();
469
470 if(!PairWielded)
471 {
472 if(Wielded->IsTwoHanded() && !Wielded->IsShield(Master))
473 return Base * (ThisToHit + PairArm->GetAttribute(DEXTERITY)
474 * sqrt(2.5 * Master->GetAttribute(PERCEPTION))) / 2;
475 }
476 else if(!Wielded->IsShield(Master) && !PairWielded->IsShield(Master))
477 return Base * ThisToHit / (1.0 + (500.0 + PairWielded->GetWeight())
478 / (1000.0 + (Wielded->GetWeight() << 1)));
479 }
480
481 return Base * ThisToHit;
482 }
483
GetWieldedAPCost() const484 long arm::GetWieldedAPCost() const
485 {
486 citem* Wielded = GetWielded();
487
488 if(Wielded->IsShield(Master))
489 return 0;
490
491 int HitStrength = GetWieldedHitStrength();
492
493 if(HitStrength <= 0)
494 return 0;
495
496 return long(1 / (1e-14 * APBonus(GetAttribute(DEXTERITY)) * Master->GetMoveEase()
497 * GetHumanoidMaster()->GetCWeaponSkill(Wielded->GetWeaponCategory())->GetBonus()
498 * (GetCurrentSWeaponSkillBonus() * Min(HitStrength, 10))));
499 }
500
CalculateDamage()501 void head::CalculateDamage()
502 {
503 if(!Master)
504 return;
505
506 if(Master->StateIsActivated(VAMPIRISM))
507 BiteDamage = 7.07e-6 * (GetBaseBiteStrength() + GetBonusBiteStrength()) * GetHumanoidMaster()->GetCWeaponSkill(BITE)->GetBonus();
508 else
509 BiteDamage = 7.07e-6 * GetBaseBiteStrength() * GetHumanoidMaster()->GetCWeaponSkill(BITE)->GetBonus();
510 }
511
CalculateToHitValue()512 void head::CalculateToHitValue()
513 {
514 if(!Master)
515 return;
516
517 BiteToHitValue = Master->GetAttribute(AGILITY) * sqrt(2.5 * Master->GetAttribute(PERCEPTION))
518 * GetHumanoidMaster()->GetCWeaponSkill(KICK)->GetBonus() * Master->GetMoveEase() / 1000000;
519 }
520
CalculateAPCost()521 void head::CalculateAPCost()
522 {
523 if(!Master)
524 return;
525
526 BiteAPCost = Max(long(10000000000. / (APBonus(Master->GetAttribute(AGILITY)) * Master->GetMoveEase()
527 * Master->GetCWeaponSkill(BITE)->GetBonus())), 100L);
528 }
529
CalculateDamage()530 void leg::CalculateDamage()
531 {
532 if(!Master)
533 return;
534
535 double WeaponStrength = GetBaseKickStrength() * GetBaseKickStrength();
536 item* Boot = GetBoot();
537
538 if(Boot)
539 WeaponStrength += Boot->GetWeaponStrength();
540
541 double Base = sqrt(5e-5 * WeaponStrength);
542
543 if(Boot)
544 Base += Boot->GetDamageBonus();
545
546 KickDamage = Base * sqrt(1e-7 * GetAttribute(LEG_STRENGTH))
547 * GetHumanoidMaster()->GetCWeaponSkill(KICK)->GetBonus();
548 }
549
CalculateToHitValue()550 void leg::CalculateToHitValue()
551 {
552 if(!Master)
553 return;
554
555 double BonusMultiplier = 10.;
556 item* Boot = GetBoot();
557
558 if(Boot)
559 BonusMultiplier += Boot->GetTHVBonus();
560
561 KickToHitValue = GetAttribute(AGILITY)
562 * sqrt(2.5 * Master->GetAttribute(PERCEPTION))
563 * GetHumanoidMaster()->GetCWeaponSkill(KICK)->GetBonus()
564 * Master->GetMoveEase()
565 * BonusMultiplier / 10000000;
566 }
567
CalculateAPCost()568 void leg::CalculateAPCost()
569 {
570 if(!Master)
571 return;
572
573 KickAPCost = Max(long(20000000000. / (APBonus(GetAttribute(AGILITY)) * Master->GetMoveEase()
574 * Master->GetCWeaponSkill(KICK)->GetBonus())), 100L);
575 }
576
GetHumanoidMaster() const577 humanoid* bodypart::GetHumanoidMaster() const
578 {
579 return static_cast<humanoid*>(Master);
580 }
581
Save(outputfile & SaveFile) const582 void corpse::Save(outputfile& SaveFile) const
583 {
584 item::Save(SaveFile);
585 SaveFile << Deceased;
586 }
587
Load(inputfile & SaveFile)588 void corpse::Load(inputfile& SaveFile)
589 {
590 item::Load(SaveFile);
591 SaveFile >> Deceased;
592 Deceased->SetMotherEntity(this);
593 Enable();
594 }
595
AddPostFix(festring & String,int) const596 void corpse::AddPostFix(festring& String, int) const
597 {
598 String << " of ";
599 GetDeceased()->AddName(String, INDEFINITE);
600 }
601
GetOfferValue(int Receiver) const602 int corpse::GetOfferValue(int Receiver) const
603 {
604 int OfferValue = 0;
605
606 for(int c = 0; c < GetDeceased()->GetBodyParts(); ++c)
607 {
608 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
609
610 if(BodyPart)
611 OfferValue += BodyPart->GetOfferValue(Receiver);
612 }
613
614 return OfferValue;
615 }
616
GetWeaponStrength() const617 double corpse::GetWeaponStrength() const
618 {
619 return GetFormModifier() * GetDeceased()->GetTorso()->GetMainMaterial()->GetStrengthValue()
620 * sqrt(GetDeceased()->GetTorso()->GetMainMaterial()->GetWeight());
621 }
622
CanBeEatenByAI(ccharacter * Eater) const623 truth corpse::CanBeEatenByAI(ccharacter* Eater) const
624 {
625 for(int c = 0; c < GetDeceased()->GetBodyParts(); ++c)
626 {
627 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
628
629 if(BodyPart && !BodyPart->CanBeEatenByAI(Eater))
630 return false;
631 }
632
633 return true;
634 }
635
GetStrengthValue() const636 int corpse::GetStrengthValue() const
637 {
638 return long(GetStrengthModifier()) * GetDeceased()->GetTorso()->GetMainMaterial()->GetStrengthValue() / 2000;
639 }
640
~corpse()641 corpse::~corpse()
642 {
643 delete Deceased;
644 }
645
GetMaterialColorA(int) const646 col16 corpse::GetMaterialColorA(int) const
647 {
648 return GetDeceased()->GetTorso()->GetMainMaterial()->GetColor();
649 }
650
GetAlphaA(int) const651 alpha corpse::GetAlphaA(int) const
652 {
653 return GetDeceased()->GetTorso()->GetMainMaterial()->GetAlpha();
654 }
655
GetMaterialColorB(int) const656 col16 corpse::GetMaterialColorB(int) const
657 {
658 torso* Torso = GetDeceased()->GetTorso();
659
660 if(Torso->IsAlive())
661 return material::GetDataBase(GetDeceased()->GetBloodMaterial())->Color;
662 else
663 return Torso->GetMainMaterial()->GetColor();
664 }
665
GetAlphaB(int) const666 alpha corpse::GetAlphaB(int) const
667 {
668 torso* Torso = GetDeceased()->GetTorso();
669 return Torso->IsAlive() ? 175 : Torso->GetMainMaterial()->GetAlpha();
670 }
671
GetSparkleFlags() const672 int corpse::GetSparkleFlags() const
673 {
674 torso* Torso = GetDeceased()->GetTorso();
675 material* Material = Torso->GetMainMaterial();
676 return Material->IsSparkling() ? SPARKLING_A|(!Torso->IsAlive() ? SPARKLING_B : 0) : 0;
677 }
678
GetBitmapPos(int) const679 v2 corpse::GetBitmapPos(int) const
680 {
681 if(GetDeceased()->GetSize() < 50)
682 return v2(32, 64);
683 else if(GetDeceased()->GetSize() < 150)
684 return v2(16, 192);
685 else
686 return v2(16, 272);
687 }
688
GetSize() const689 int corpse::GetSize() const
690 {
691 return GetDeceased()->GetSize();
692 }
693
SetDeceased(character * What)694 void corpse::SetDeceased(character* What)
695 {
696 Deceased = What;
697 Deceased->SetMotherEntity(this);
698 SignalVolumeAndWeightChange();
699 SignalEmitationIncrease(Deceased->GetEmitation());
700 UpdatePictures();
701 Enable();
702 }
703
DropEquipment(stack * Stack)704 void head::DropEquipment(stack* Stack)
705 {
706 if(Stack)
707 {
708 if(GetHelmet())
709 GetHelmet()->MoveTo(Stack);
710
711 if(GetAmulet())
712 GetAmulet()->MoveTo(Stack);
713 }
714 else
715 {
716 if(GetHelmet())
717 GetSlot()->AddFriendItem(GetHelmet());
718
719 if(GetAmulet())
720 GetSlot()->AddFriendItem(GetAmulet());
721 }
722 }
723
DropEquipment(stack * Stack)724 void humanoidtorso::DropEquipment(stack* Stack)
725 {
726 if(Stack)
727 {
728 if(GetBodyArmor())
729 GetBodyArmor()->MoveTo(Stack);
730
731 if(GetCloak())
732 GetCloak()->MoveTo(Stack);
733
734 if(GetBelt())
735 GetBelt()->MoveTo(Stack);
736 }
737 else
738 {
739 if(GetBodyArmor())
740 GetSlot()->AddFriendItem(GetBodyArmor());
741
742 if(GetCloak())
743 GetSlot()->AddFriendItem(GetCloak());
744
745 if(GetBelt())
746 GetSlot()->AddFriendItem(GetBelt());
747 }
748 }
749
DropEquipment(stack * Stack)750 void arm::DropEquipment(stack* Stack)
751 {
752 if(Stack)
753 {
754 if(GetWielded())
755 GetWielded()->MoveTo(Stack);
756
757 if(GetGauntlet())
758 GetGauntlet()->MoveTo(Stack);
759
760 if(GetRing())
761 GetRing()->MoveTo(Stack);
762 }
763 else
764 {
765 if(GetWielded())
766 GetSlot()->AddFriendItem(GetWielded());
767
768 if(GetGauntlet())
769 GetSlot()->AddFriendItem(GetGauntlet());
770
771 if(GetRing())
772 GetSlot()->AddFriendItem(GetRing());
773 }
774 }
775
DropEquipment(stack * Stack)776 void leg::DropEquipment(stack* Stack)
777 {
778 if(Stack)
779 {
780 if(GetBoot())
781 GetBoot()->MoveTo(Stack);
782 }
783 else
784 {
785 if(GetBoot())
786 GetSlot()->AddFriendItem(GetBoot());
787 }
788 }
789
~head()790 head::~head()
791 {
792 delete GetHelmet();
793 delete GetAmulet();
794 }
795
~humanoidtorso()796 humanoidtorso::~humanoidtorso()
797 {
798 delete GetBodyArmor();
799 delete GetCloak();
800 delete GetBelt();
801 }
802
~arm()803 arm::~arm()
804 {
805 delete GetWielded();
806 delete GetGauntlet();
807 delete GetRing();
808 }
809
~leg()810 leg::~leg()
811 {
812 delete GetBoot();
813 }
814
GetTruePrice() const815 long corpse::GetTruePrice() const
816 {
817 long Price = 0;
818
819 for(int c = 0; c < GetDeceased()->GetBodyParts(); ++c)
820 {
821 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
822
823 if(BodyPart)
824 Price += BodyPart->GetTruePrice();
825 }
826
827 return Price;
828 }
829
GetMaterial(int I) const830 material* corpse::GetMaterial(int I) const
831 {
832 return GetDeceased()->GetTorso()->GetMaterial(I);
833 }
834
GetSparkleFlags() const835 int bodypart::GetSparkleFlags() const
836 {
837 return (GetMainMaterial()->SkinColorIsSparkling() ? SPARKLING_A : 0)
838 | (Flags >> BODYPART_SPARKLE_SHIFT & (SPARKLING_B|SPARKLING_C|SPARKLING_D));
839 }
840
RaiseTheDead(character * Summoner)841 truth corpse::RaiseTheDead(character* Summoner)
842 {
843 if(Summoner && Summoner->IsPlayer())
844 game::DoEvilDeed(50);
845
846 GetDeceased()->Enable();
847
848 if(GetDeceased()->TryToRiseFromTheDead())
849 {
850 v2 Pos = GetPos();
851 RemoveFromSlot();
852 GetDeceased()->SetMotherEntity(0);
853
854 if(Summoner && GetDeceased()->CanTameWithResurrection(Summoner)
855 && !GetDeceased()->IsPlayer())
856 GetDeceased()->ChangeTeam(Summoner->GetTeam());
857
858 GetDeceased()->PutToOrNear(Pos);
859 GetDeceased()->SignalStepFrom(0);
860 Deceased = 0;
861 SendToHell();
862 return true;
863 }
864 else
865 {
866 GetDeceased()->Disable();
867 return false;
868 }
869 }
870
head()871 head::head()
872 {
873 HelmetSlot.Init(this, HELMET_INDEX);
874 AmuletSlot.Init(this, AMULET_INDEX);
875 }
876
humanoidtorso()877 humanoidtorso::humanoidtorso()
878 {
879 BodyArmorSlot.Init(this, BODY_ARMOR_INDEX);
880 CloakSlot.Init(this, CLOAK_INDEX);
881 BeltSlot.Init(this, BELT_INDEX);
882 }
883
rightarm()884 rightarm::rightarm()
885 {
886 WieldedSlot.Init(this, RIGHT_WIELDED_INDEX);
887 GauntletSlot.Init(this, RIGHT_GAUNTLET_INDEX);
888 RingSlot.Init(this, RIGHT_RING_INDEX);
889 }
890
leftarm()891 leftarm::leftarm()
892 {
893 WieldedSlot.Init(this, LEFT_WIELDED_INDEX);
894 GauntletSlot.Init(this, LEFT_GAUNTLET_INDEX);
895 RingSlot.Init(this, LEFT_RING_INDEX);
896 }
897
rightleg()898 rightleg::rightleg()
899 {
900 BootSlot.Init(this, RIGHT_BOOT_INDEX);
901 }
902
leftleg()903 leftleg::leftleg()
904 {
905 BootSlot.Init(this, LEFT_BOOT_INDEX);
906 }
907
Hit(character * Enemy,v2 HitPos,int Direction,int Flags)908 void arm::Hit(character* Enemy, v2 HitPos, int Direction, int Flags)
909 {
910 long StrExp = 50, DexExp = 50;
911 truth THW = false;
912 item* Wielded = GetWielded();
913
914 if(Wielded)
915 {
916 long Weight = Wielded->GetWeight();
917 StrExp = Limit(15 * Weight / 200L, 75L, 300L);
918 DexExp = Weight ? Limit(75000L / Weight, 75L, 300L) : 300;
919 THW = TwoHandWieldIsActive();
920 }
921
922 switch(Enemy->TakeHit(Master, Wielded ? Wielded : GetGauntlet(), this, HitPos, GetTypeDamage(Enemy),
923 GetToHitValue(), RAND() % 26 - RAND() % 26, Wielded ? WEAPON_ATTACK : UNARMED_ATTACK,
924 Direction, !(RAND() % Master->GetCriticalModifier()), Flags & SADIST_HIT))
925 {
926 case HAS_HIT:
927 case HAS_BLOCKED:
928 case HAS_DIED:
929 case DID_NO_DAMAGE:
930 EditExperience(ARM_STRENGTH, StrExp, 1 << 9);
931
932 if(THW && GetPairArm())
933 GetPairArm()->EditExperience(ARM_STRENGTH, StrExp, 1 << 9);
934
935 case HAS_DODGED:
936 EditExperience(DEXTERITY, DexExp, 1 << 9);
937
938 if(THW && GetPairArm())
939 GetPairArm()->EditExperience(DEXTERITY, DexExp, 1 << 9);
940 }
941 }
942
GetAttribute(int Identifier,truth AllowBonus) const943 int arm::GetAttribute(int Identifier, truth AllowBonus) const
944 {
945 if(Identifier == ARM_STRENGTH)
946 {
947 int Base = !UseMaterialAttributes()
948 ? int(StrengthExperience * EXP_DIVISOR)
949 : GetMainMaterial()->GetStrengthValue();
950
951 if(AllowBonus)
952 Base += StrengthBonus;
953
954 return Max(!IsBadlyHurt() || !AllowBonus ? Base : Base / 3, 1);
955 }
956 else if(Identifier == DEXTERITY)
957 {
958 int Base = !UseMaterialAttributes()
959 ? int(DexterityExperience * EXP_DIVISOR)
960 : GetMainMaterial()->GetFlexibility() << 2;
961
962 if(AllowBonus)
963 Base += DexterityBonus;
964
965 return Max(IsUsable() || !AllowBonus ? Base : Base / 3, 1);
966 }
967 else
968 {
969 ABORT("Illegal arm attribute %d request!", Identifier);
970 return 0xACCA;
971 }
972 }
973
EditAttribute(int Identifier,int Value)974 truth arm::EditAttribute(int Identifier, int Value)
975 {
976 if(!Master)
977 return false;
978
979 if(Identifier == ARM_STRENGTH)
980 {
981 if(!UseMaterialAttributes()
982 && Master->RawEditAttribute(StrengthExperience, Value))
983 {
984 Master->CalculateBattleInfo();
985
986 if(Master->IsPlayerKind())
987 UpdatePictures();
988
989 return true;
990 }
991 }
992 else if(Identifier == DEXTERITY)
993 if(!UseMaterialAttributes()
994 && Master->RawEditAttribute(DexterityExperience, Value))
995 {
996 Master->CalculateBattleInfo();
997 return true;
998 }
999
1000 return false;
1001 }
1002
EditExperience(int Identifier,double Value,double Speed)1003 void arm::EditExperience(int Identifier, double Value, double Speed)
1004 {
1005 if(!Master)
1006 return;
1007
1008 if(Identifier == ARM_STRENGTH)
1009 {
1010 if(!UseMaterialAttributes())
1011 {
1012 int Change = Master->RawEditExperience(StrengthExperience,
1013 Master->GetNaturalExperience(ARM_STRENGTH),
1014 Value, Speed);
1015
1016 if(Change)
1017 {
1018 cchar* Adj = Change > 0 ? "stronger" : "weaker";
1019
1020 if(Master->IsPlayer())
1021 ADD_MESSAGE("Your %s feels %s!", GetBodyPartName().CStr(), Adj);
1022 else if(Master->IsPet() && Master->CanBeSeenByPlayer())
1023 ADD_MESSAGE("Suddenly %s looks %s.", Master->CHAR_NAME(DEFINITE), Adj);
1024
1025 Master->CalculateBattleInfo();
1026
1027 if(Master->IsPlayerKind())
1028 UpdatePictures();
1029 }
1030 }
1031 }
1032 else if(Identifier == DEXTERITY)
1033 {
1034 if(!UseMaterialAttributes())
1035 {
1036 int Change = Master->RawEditExperience(DexterityExperience,
1037 Master->GetNaturalExperience(DEXTERITY),
1038 Value, Speed);
1039
1040 if(Change)
1041 {
1042 cchar* Adj = Change > 0 ? "quite dextrous" : "clumsy";
1043
1044 if(Master->IsPlayer())
1045 ADD_MESSAGE("Your %s feels %s!", GetBodyPartName().CStr(), Adj);
1046 else if(Master->IsPet() && Master->CanBeSeenByPlayer())
1047 ADD_MESSAGE("Suddenly %s looks %s.", Master->CHAR_NAME(DEFINITE), Adj);
1048
1049 Master->CalculateBattleInfo();
1050 }
1051 }
1052 }
1053 else
1054 ABORT("Illegal arm attribute %d experience edit request!", Identifier);
1055 }
1056
GetAttribute(int Identifier,truth AllowBonus) const1057 int leg::GetAttribute(int Identifier, truth AllowBonus) const
1058 {
1059 if(Identifier == LEG_STRENGTH)
1060 {
1061 int Base = !UseMaterialAttributes()
1062 ? int(StrengthExperience * EXP_DIVISOR)
1063 : GetMainMaterial()->GetStrengthValue();
1064
1065 if(AllowBonus)
1066 Base += StrengthBonus;
1067
1068 return Max(!IsBadlyHurt() || !AllowBonus ? Base : Base / 3, 1);
1069 }
1070 else if(Identifier == AGILITY)
1071 {
1072 int Base = !UseMaterialAttributes()
1073 ? int(AgilityExperience * EXP_DIVISOR)
1074 : GetMainMaterial()->GetFlexibility() << 2;
1075
1076 if(AllowBonus)
1077 Base += AgilityBonus;
1078
1079 return Max(IsUsable() || !AllowBonus ? Base : Base / 3, 1);
1080 }
1081 else
1082 {
1083 ABORT("Illegal leg attribute %d request!", Identifier);
1084 return 0xECCE;
1085 }
1086 }
1087
EditAttribute(int Identifier,int Value)1088 truth leg::EditAttribute(int Identifier, int Value)
1089 {
1090 if(!Master)
1091 return false;
1092
1093 if(Identifier == LEG_STRENGTH)
1094 {
1095 if(!UseMaterialAttributes()
1096 && Master->RawEditAttribute(StrengthExperience, Value))
1097 {
1098 Master->CalculateBurdenState();
1099 Master->CalculateBattleInfo();
1100 return true;
1101 }
1102 }
1103 else if(Identifier == AGILITY)
1104 if(!UseMaterialAttributes()
1105 && Master->RawEditAttribute(AgilityExperience, Value))
1106 {
1107 Master->CalculateBattleInfo();
1108 return true;
1109 }
1110
1111 return false;
1112 }
1113
EditExperience(int Identifier,double Value,double Speed)1114 void leg::EditExperience(int Identifier, double Value, double Speed)
1115 {
1116 if(!Master)
1117 return;
1118
1119 if(Identifier == LEG_STRENGTH)
1120 {
1121 if(!UseMaterialAttributes())
1122 {
1123 int Change = Master->RawEditExperience(StrengthExperience,
1124 Master->GetNaturalExperience(LEG_STRENGTH),
1125 Value, Speed);
1126
1127 if(Change)
1128 {
1129 cchar* Adj = Change > 0 ? "stronger" : "weaker";
1130
1131 if(Master->IsPlayer())
1132 ADD_MESSAGE("Your %s feels %s!", GetBodyPartName().CStr(), Adj);
1133 else if(Master->IsPet() && Master->CanBeSeenByPlayer())
1134 ADD_MESSAGE("Suddenly %s looks %s.", Master->CHAR_NAME(DEFINITE), Adj);
1135
1136 Master->CalculateBurdenState();
1137 Master->CalculateBattleInfo();
1138 }
1139 }
1140 }
1141 else if(Identifier == AGILITY)
1142 {
1143 if(!UseMaterialAttributes())
1144 {
1145 int Change = Master->RawEditExperience(AgilityExperience,
1146 Master->GetNaturalExperience(AGILITY),
1147 Value, Speed);
1148
1149 if(Change)
1150 {
1151 cchar* Adj = Change > 0 ? "very agile" : "slower";
1152
1153 if(Master->IsPlayer())
1154 ADD_MESSAGE("Your %s feels %s!", GetBodyPartName().CStr(), Adj);
1155 else if(Master->IsPet() && Master->CanBeSeenByPlayer())
1156 ADD_MESSAGE("Suddenly %s looks %s.", Master->CHAR_NAME(DEFINITE), Adj);
1157
1158 Master->CalculateBattleInfo();
1159 }
1160 }
1161 }
1162 else
1163 ABORT("Illegal leg attribute %d experience edit request!", Identifier);
1164 }
1165
InitSpecialAttributes()1166 void head::InitSpecialAttributes()
1167 {
1168 BaseBiteStrength = Master->GetBaseBiteStrength();
1169 BonusBiteStrength = Master->GetBonusBiteStrength();
1170 }
1171
InitSpecialAttributes()1172 void arm::InitSpecialAttributes()
1173 {
1174 if(!Master->IsHuman() || Master->IsInitializing())
1175 {
1176 StrengthExperience = Master->GetNaturalExperience(ARM_STRENGTH);
1177 DexterityExperience = Master->GetNaturalExperience(DEXTERITY);
1178 }
1179 else
1180 {
1181 StrengthExperience = game::GetAveragePlayerArmStrengthExperience();
1182 DexterityExperience = game::GetAveragePlayerDexterityExperience();
1183 }
1184
1185 LimitRef(StrengthExperience, MIN_EXP, MAX_EXP);
1186 LimitRef(DexterityExperience, MIN_EXP, MAX_EXP);
1187 BaseUnarmedStrength = Master->GetBaseUnarmedStrength();
1188 }
1189
InitSpecialAttributes()1190 void leg::InitSpecialAttributes()
1191 {
1192 if(!Master->IsHuman() || Master->IsInitializing())
1193 {
1194 StrengthExperience = Master->GetNaturalExperience(LEG_STRENGTH);
1195 AgilityExperience = Master->GetNaturalExperience(AGILITY);
1196 }
1197 else
1198 {
1199 StrengthExperience = game::GetAveragePlayerLegStrengthExperience();
1200 AgilityExperience = game::GetAveragePlayerAgilityExperience();
1201 }
1202
1203 LimitRef(StrengthExperience, MIN_EXP, MAX_EXP);
1204 LimitRef(AgilityExperience, MIN_EXP, MAX_EXP);
1205 BaseKickStrength = Master->GetBaseKickStrength();
1206 }
1207
SignalEquipmentAdd(gearslot * Slot)1208 void bodypart::SignalEquipmentAdd(gearslot* Slot)
1209 {
1210 if(Master)
1211 Master->SignalEquipmentAdd(Slot->GetEquipmentIndex());
1212 }
1213
SignalEquipmentRemoval(gearslot * Slot,citem * Item)1214 void bodypart::SignalEquipmentRemoval(gearslot* Slot, citem* Item)
1215 {
1216 if(Master)
1217 Master->SignalEquipmentRemoval(Slot->GetEquipmentIndex(), Item);
1218 }
1219
Mutate()1220 void bodypart::Mutate()
1221 {
1222 GetMainMaterial()->SetVolume(long(GetVolume() * (1.5 - (RAND() & 1023) / 1023.)));
1223 }
1224
Mutate()1225 void arm::Mutate()
1226 {
1227 bodypart::Mutate();
1228 StrengthExperience = StrengthExperience * (1.5 - (RAND() & 1023) / 1023.);
1229 DexterityExperience = DexterityExperience * (1.5 - (RAND() & 1023) / 1023.);
1230 LimitRef(StrengthExperience, MIN_EXP, MAX_EXP);
1231 LimitRef(DexterityExperience, MIN_EXP, MAX_EXP);
1232 }
1233
Mutate()1234 void leg::Mutate()
1235 {
1236 bodypart::Mutate();
1237 StrengthExperience = StrengthExperience * (1.5 - (RAND() & 1023) / 1023.);
1238 AgilityExperience = AgilityExperience * (1.5 - (RAND() & 1023) / 1023.);
1239 LimitRef(StrengthExperience, MIN_EXP, MAX_EXP);
1240 LimitRef(AgilityExperience, MIN_EXP, MAX_EXP);
1241 }
1242
GetPairArm() const1243 arm* rightarm::GetPairArm() const
1244 {
1245 return GetHumanoidMaster() ? GetHumanoidMaster()->GetLeftArm() : 0;
1246 }
1247
GetPairArm() const1248 arm* leftarm::GetPairArm() const
1249 {
1250 return GetHumanoidMaster() ? GetHumanoidMaster()->GetRightArm() : 0;
1251 }
1252
GetCurrentSWeaponSkill() const1253 sweaponskill** rightarm::GetCurrentSWeaponSkill() const
1254 {
1255 return &GetHumanoidMaster()->CurrentRightSWeaponSkill;
1256 }
1257
GetCurrentSWeaponSkill() const1258 sweaponskill** leftarm::GetCurrentSWeaponSkill() const
1259 {
1260 return &GetHumanoidMaster()->CurrentLeftSWeaponSkill;
1261 }
1262
GetMaxAlpha() const1263 alpha bodypart::GetMaxAlpha() const
1264 {
1265 if(Master && (Master->StateIsActivated(INVISIBLE) || !!Master->GhostCopyMaterials()))
1266 return 150;
1267 else
1268 return 255;
1269 }
1270
AddPostFix(festring & String,int) const1271 void bodypart::AddPostFix(festring& String, int) const
1272 {
1273 if(!OwnerDescription.IsEmpty())
1274 String << ' ' << OwnerDescription;
1275 }
1276
CalculateVolumeAndWeight()1277 void corpse::CalculateVolumeAndWeight()
1278 {
1279 Volume = Deceased->GetVolume();
1280 Weight = Deceased->GetWeight();
1281 }
1282
GetEquipment(int I) const1283 item* head::GetEquipment(int I) const
1284 {
1285 switch(I)
1286 {
1287 case 0: return GetHelmet();
1288 case 1: return GetAmulet();
1289 }
1290
1291 return 0;
1292 }
1293
GetEquipment(int I) const1294 item* humanoidtorso::GetEquipment(int I) const
1295 {
1296 switch(I)
1297 {
1298 case 0: return GetBodyArmor();
1299 case 1: return GetCloak();
1300 case 2: return GetBelt();
1301 }
1302
1303 return 0;
1304 }
1305
GetEquipment(int I) const1306 item* arm::GetEquipment(int I) const
1307 {
1308 switch(I)
1309 {
1310 case 0: return GetWielded();
1311 case 1: return GetGauntlet();
1312 case 2: return GetRing();
1313 }
1314
1315 return 0;
1316 }
1317
GetEquipment(int I) const1318 item* leg::GetEquipment(int I) const
1319 {
1320 return !I ? GetBoot() : 0;
1321 }
1322
CalculateVolumeAndWeight()1323 void bodypart::CalculateVolumeAndWeight()
1324 {
1325 item::CalculateVolumeAndWeight();
1326 CarriedWeight = 0;
1327 BodyPartVolume = Volume;
1328
1329 for(int c = 0; c < GetEquipments(); ++c)
1330 {
1331 item* Equipment = GetEquipment(c);
1332
1333 if(Equipment)
1334 {
1335 Volume += Equipment->GetVolume();
1336 CarriedWeight += Equipment->GetWeight();
1337 }
1338 }
1339
1340 Weight += CarriedWeight;
1341 }
1342
CalculateEmitation()1343 void corpse::CalculateEmitation()
1344 {
1345 Emitation = Deceased->GetEmitation();
1346 }
1347
CalculateEmitation()1348 void bodypart::CalculateEmitation()
1349 {
1350 item::CalculateEmitation();
1351
1352 for(int c = 0; c < GetEquipments(); ++c)
1353 {
1354 item* Equipment = GetEquipment(c);
1355
1356 if(Equipment)
1357 game::CombineLights(Emitation, Equipment->GetEmitation());
1358 }
1359 }
1360
CalculateMaxHP(ulong Flags)1361 void bodypart::CalculateMaxHP(ulong Flags)
1362 {
1363 int HPDelta = MaxHP - HP, OldMaxHP = MaxHP;
1364 MaxHP = 0;
1365 int BurnLevel = 0;
1366
1367 if(Master)
1368 {
1369 if(!UseMaterialAttributes())
1370 {
1371 long Endurance = Master->GetAttribute(ENDURANCE);
1372 double DoubleHP = GetBodyPartVolume() * Endurance * Endurance / 200000;
1373
1374 for(size_t c = 0; c < Scar.size(); ++c)
1375 DoubleHP *= (100. - Scar[c].Severity * 4) / 100;
1376
1377 if(MainMaterial)
1378 {
1379 BurnLevel = MainMaterial->GetBurnLevel();
1380 DoubleHP *= 1. * (4 - BurnLevel) / 4;
1381 }
1382
1383 MaxHP = int(DoubleHP);
1384 }
1385 else
1386 {
1387 long SV = GetMainMaterial()->GetStrengthValue();
1388 MaxHP = (GetBodyPartVolume() * SV >> 4) * SV / 250000;
1389 }
1390
1391 if(MaxHP < 1)
1392 MaxHP = 1;
1393
1394 if(Flags & MAY_CHANGE_HPS)
1395 {
1396 if(MaxHP - HPDelta > 1)
1397 HP = MaxHP - HPDelta;
1398 else
1399 HP = 1;
1400 }
1401 else
1402 {
1403 //OldMaxHP - MaxHP;
1404 }
1405
1406 if(Flags & CHECK_USABILITY)
1407 SignalPossibleUsabilityChange();
1408 }
1409 }
1410
SignalVolumeAndWeightChange()1411 void bodypart::SignalVolumeAndWeightChange()
1412 {
1413 item::SignalVolumeAndWeightChange();
1414
1415 if(Master && !Master->IsInitializing())
1416 {
1417 CalculateMaxHP();
1418 Master->CalculateHP();
1419 Master->CalculateMaxHP();
1420 Master->SignalBodyPartVolumeAndWeightChange();
1421 square* SquareUnder = GetSquareUnder();
1422
1423 if(UpdateArmorPictures() && SquareUnder)
1424 SquareUnder->SendNewDrawRequest();
1425 }
1426 }
1427
1428 /*{
1429 for(;;)
1430 {
1431 damageid& D = DamageID.back();
1432 D.
1433 }
1434 }*/
1435
SetHP(int What)1436 void bodypart::SetHP(int What)
1437 {
1438 HP = What;
1439
1440 if(Master)
1441 {
1442 Master->CalculateHP();
1443 SignalPossibleUsabilityChange();
1444 }
1445 }
1446
EditHP(int SrcID,int What)1447 void bodypart::EditHP(int SrcID, int What)
1448 {
1449 HP += What;
1450
1451 if(What < 0)
1452 RemoveDamageIDs(-What);
1453 else
1454 AddDamageID(SrcID, What);
1455
1456 if(Master)
1457 {
1458 Master->CalculateHP();
1459 SignalPossibleUsabilityChange();
1460 }
1461 }
1462
SignalVolumeAndWeightChange()1463 void arm::SignalVolumeAndWeightChange()
1464 {
1465 bodypart::SignalVolumeAndWeightChange();
1466
1467 if(Master && !Master->IsInitializing())
1468 {
1469 GetHumanoidMaster()->EnsureCurrentSWeaponSkillIsCorrect(*GetCurrentSWeaponSkill(), GetWielded());
1470 CalculateAttributeBonuses();
1471 CalculateAttackInfo();
1472 UpdateWieldedPicture();
1473
1474 if(GetSquareUnder())
1475 GetSquareUnder()->SendNewDrawRequest();
1476 }
1477 }
1478
SignalVolumeAndWeightChange()1479 void leg::SignalVolumeAndWeightChange()
1480 {
1481 bodypart::SignalVolumeAndWeightChange();
1482
1483 if(Master && !Master->IsInitializing())
1484 {
1485 CalculateAttributeBonuses();
1486 CalculateAttackInfo();
1487 }
1488 }
1489
SignalVolumeAndWeightChange()1490 void humanoidtorso::SignalVolumeAndWeightChange()
1491 {
1492 bodypart::SignalVolumeAndWeightChange();
1493
1494 if(Master && !Master->IsInitializing())
1495 {
1496 humanoid* HumanoidMaster = GetHumanoidMaster();
1497
1498 if(HumanoidMaster->GetRightArm())
1499 HumanoidMaster->GetRightArm()->CalculateAttributeBonuses();
1500
1501 if(HumanoidMaster->GetLeftArm())
1502 HumanoidMaster->GetLeftArm()->CalculateAttributeBonuses();
1503
1504 if(HumanoidMaster->GetRightLeg())
1505 HumanoidMaster->GetRightLeg()->CalculateAttributeBonuses();
1506
1507 if(HumanoidMaster->GetLeftLeg())
1508 HumanoidMaster->GetLeftLeg()->CalculateAttributeBonuses();
1509 }
1510 }
1511
CalculateAttackInfo()1512 void bodypart::CalculateAttackInfo()
1513 {
1514 CalculateDamage();
1515 CalculateToHitValue();
1516 CalculateAPCost();
1517 }
1518
TwoHandWieldIsActive() const1519 truth arm::TwoHandWieldIsActive() const
1520 {
1521 citem* Wielded = GetWielded();
1522
1523 if(Wielded->IsTwoHanded() && !Wielded->IsShield(Master))
1524 {
1525 arm* PairArm = GetPairArm();
1526 return PairArm && PairArm->IsUsable() && !PairArm->GetWielded();
1527 }
1528 else
1529 return false;
1530 }
1531
GetTimeToDie(int Damage,double ToHitValue,double DodgeValue,truth AttackIsBlockable,truth UseMaxHP) const1532 double bodypart::GetTimeToDie(int Damage, double ToHitValue, double DodgeValue,
1533 truth AttackIsBlockable, truth UseMaxHP) const
1534 {
1535 double Durability;
1536 int TotalResistance = GetTotalResistance(PHYSICAL_DAMAGE);
1537 int Damage3 = (Damage << 1) + Damage;
1538 int Damage5 = (Damage << 2) + Damage;
1539 int TrueDamage = (19 * (Max((Damage3 >> 2) - TotalResistance, 0)
1540 + Max((Damage5 >> 2) + 1 - (TotalResistance >> 1), 0))
1541 + (Max(((Damage3 + (Damage3 >> 1)) >> 2) - TotalResistance, 0)
1542 + Max(((Damage5 + (Damage5 >> 1)) >> 2) + 3 - (TotalResistance >> 1), 0))) / 40;
1543
1544 int HP = UseMaxHP ? GetMaxHP() : GetHP();
1545
1546 if(TrueDamage > 0)
1547 {
1548 double AverageDamage;
1549
1550 if(AttackIsBlockable)
1551 {
1552 blockvector Block;
1553 Master->CreateBlockPossibilityVector(Block, ToHitValue);
1554
1555 if(Block.size())
1556 {
1557 double ChanceForNoBlock = 1.0;
1558 AverageDamage = 0;
1559
1560 for(uint c = 0; c < Block.size(); ++c)
1561 {
1562 ChanceForNoBlock -= Block[c].first;
1563
1564 if(TrueDamage - Block[c].second > 0)
1565 AverageDamage += Block[c].first * (TrueDamage - Block[c].second);
1566 }
1567
1568 AverageDamage += ChanceForNoBlock * TrueDamage;
1569 }
1570 else
1571 AverageDamage = TrueDamage;
1572 }
1573 else
1574 AverageDamage = TrueDamage;
1575
1576 Durability = HP / (AverageDamage * GetRoughChanceToHit(ToHitValue, DodgeValue));
1577
1578 if(Durability < 1)
1579 Durability = 1;
1580
1581 if(Durability > 1000)
1582 Durability = 1000;
1583 }
1584 else
1585 Durability = 1000;
1586
1587 return Durability;
1588 }
1589
GetRoughChanceToHit(double ToHitValue,double DodgeValue) const1590 double bodypart::GetRoughChanceToHit(double ToHitValue, double DodgeValue) const
1591 {
1592 return GLOBAL_WEAK_BODYPART_HIT_MODIFIER * ToHitValue * GetBodyPartVolume()
1593 / ((DodgeValue / ToHitValue + 1) * DodgeValue * Master->GetBodyVolume() * 100);
1594 }
1595
GetRoughChanceToHit(double ToHitValue,double DodgeValue) const1596 double torso::GetRoughChanceToHit(double ToHitValue, double DodgeValue) const
1597 {
1598 return 1 / (DodgeValue / ToHitValue + 1);
1599 }
1600
RandomizePosition()1601 void bodypart::RandomizePosition()
1602 {
1603 SpecialFlags |= 1 + RAND() % 7;
1604 UpdatePictures();
1605 }
1606
GetBlockChance(double EnemyToHitValue) const1607 double arm::GetBlockChance(double EnemyToHitValue) const
1608 {
1609 citem* Wielded = GetWielded();
1610 return Wielded ? Min(1.0 / (1 + EnemyToHitValue / (GetToHitValue() * Wielded->GetBlockModifier()) * 10000), 1.0) : 0;
1611 }
1612
GetBlockCapability() const1613 int arm::GetBlockCapability() const
1614 {
1615 citem* Wielded = GetWielded();
1616
1617 if(!Wielded)
1618 return 0;
1619
1620 int HitStrength = GetWieldedHitStrength();
1621
1622 if(HitStrength <= 0)
1623 return 0;
1624
1625 return Min(HitStrength, 10) * Wielded->GetStrengthValue()
1626 * GetHumanoidMaster()->GetCWeaponSkill(Wielded->GetWeaponCategory())->GetBonus()
1627 * (*GetCurrentSWeaponSkill())->GetBonus() / 10000000;
1628 }
1629
WieldedSkillHit(int Hits)1630 void arm::WieldedSkillHit(int Hits)
1631 {
1632 item* Wielded = GetWielded();
1633
1634 if(Master->GetCWeaponSkill(Wielded->GetWeaponCategory())->AddHit(Hits))
1635 {
1636 CalculateAttackInfo();
1637
1638 if(Master->IsPlayer())
1639 {
1640 int Category = Wielded->GetWeaponCategory();
1641 GetHumanoidMaster()->GetCWeaponSkill(Category)->AddLevelUpMessage(Category);
1642 }
1643 }
1644
1645 if((*GetCurrentSWeaponSkill())->AddHit(Hits))
1646 {
1647 CalculateAttackInfo();
1648
1649 if(Master->IsPlayer())
1650 (*GetCurrentSWeaponSkill())->AddLevelUpMessage(Wielded->CHAR_NAME(UNARTICLED));
1651 }
1652 }
1653
head(const head & Head)1654 head::head(const head& Head) : mybase(Head), BaseBiteStrength(Head.BaseBiteStrength), BonusBiteStrength(Head.BonusBiteStrength)
1655 {
1656 HelmetSlot.Init(this, HELMET_INDEX);
1657 AmuletSlot.Init(this, AMULET_INDEX);
1658 }
1659
humanoidtorso(const humanoidtorso & Torso)1660 humanoidtorso::humanoidtorso(const humanoidtorso& Torso) : mybase(Torso)
1661 {
1662 BodyArmorSlot.Init(this, BODY_ARMOR_INDEX);
1663 CloakSlot.Init(this, CLOAK_INDEX);
1664 BeltSlot.Init(this, BELT_INDEX);
1665 }
1666
arm(const arm & Arm)1667 arm::arm(const arm& Arm)
1668 : mybase(Arm),
1669 StrengthExperience(Arm.StrengthExperience),
1670 DexterityExperience(Arm.DexterityExperience),
1671 BaseUnarmedStrength(Arm.BaseUnarmedStrength)
1672 {
1673 }
1674
rightarm(const rightarm & Arm)1675 rightarm::rightarm(const rightarm& Arm) : mybase(Arm)
1676 {
1677 WieldedSlot.Init(this, RIGHT_WIELDED_INDEX);
1678 GauntletSlot.Init(this, RIGHT_GAUNTLET_INDEX);
1679 RingSlot.Init(this, RIGHT_RING_INDEX);
1680 }
1681
leftarm(const leftarm & Arm)1682 leftarm::leftarm(const leftarm& Arm) : mybase(Arm)
1683 {
1684 WieldedSlot.Init(this, LEFT_WIELDED_INDEX);
1685 GauntletSlot.Init(this, LEFT_GAUNTLET_INDEX);
1686 RingSlot.Init(this, LEFT_RING_INDEX);
1687 }
1688
leg(const leg & Leg)1689 leg::leg(const leg& Leg)
1690 : mybase(Leg),
1691 StrengthExperience(Leg.StrengthExperience),
1692 AgilityExperience(Leg.AgilityExperience),
1693 BaseKickStrength(Leg.BaseKickStrength)
1694 {
1695 }
1696
rightleg(const rightleg & Leg)1697 rightleg::rightleg(const rightleg& Leg) : mybase(Leg)
1698 {
1699 BootSlot.Init(this, RIGHT_BOOT_INDEX);
1700 }
1701
leftleg(const leftleg & Leg)1702 leftleg::leftleg(const leftleg& Leg) : mybase(Leg)
1703 {
1704 BootSlot.Init(this, LEFT_BOOT_INDEX);
1705 }
1706
corpse(const corpse & Corpse)1707 corpse::corpse(const corpse& Corpse) : mybase(Corpse)
1708 {
1709 Deceased = Corpse.Deceased->Duplicate();
1710 Deceased->SetMotherEntity(this);
1711 }
1712
SignalSpoil(material * Material)1713 void bodypart::SignalSpoil(material* Material)
1714 {
1715 if(Master)
1716 Master->SignalSpoil();
1717 else
1718 item::SignalSpoil(Material);
1719 }
1720
SignalSpoil(material *)1721 void corpse::SignalSpoil(material*)
1722 {
1723 GetDeceased()->Disappear(this, "spoil", &item::IsVeryCloseToSpoiling);
1724 }
1725
TestActivationEnergy(int Damage)1726 truth bodypart::TestActivationEnergy(int Damage)
1727 {
1728 // if(MainMaterial)
1729 // {
1730 // int molamola = ((GetMainMaterial()->GetStrengthValue() >> 1)
1731 // + 5 * MainMaterial->GetFireResistance() + GetResistance(FIRE));
1732 // ADD_MESSAGE("%s is being tested (Damage is %d, AE is %d)", CHAR_NAME(DEFINITE), Damage, molamola);
1733 // }
1734 if(Damage <= 0)
1735 return false;
1736
1737 character* Owner = GetMaster();
1738 truth Success = false;
1739
1740 if(Owner)
1741 if(Owner->BodyPartIsVital(GetBodyPartIndex()) || !CanBeBurned())
1742 return Success;
1743
1744 if(MainMaterial)
1745 {
1746 int TestDamage = Damage + MainMaterial->GetTransientThermalEnergy();
1747 GetMainMaterial()->AddToTransientThermalEnergy(Damage);
1748 if((GetMainMaterial()->GetInteractionFlags() & CAN_BURN)
1749 && TestDamage >= ((GetMainMaterial()->GetStrengthValue() >> 1)
1750 + 5 * MainMaterial->GetFireResistance() + GetResistance(FIRE)))
1751 {
1752 if(Owner)
1753 {
1754 if(Owner->IsPlayer())
1755 ADD_MESSAGE("Your %s catches fire!", GetBodyPartName().CStr());
1756 else if(Owner->CanBeSeenByPlayer())
1757 ADD_MESSAGE("The %s of %s catches fire!", GetBodyPartName().CStr(), Owner->CHAR_NAME(DEFINITE));
1758 }
1759 //ADD_MESSAGE("%s catches fire! (TestDamage was %d)", CHAR_NAME(DEFINITE), TestDamage); //CLEANUP
1760 Ignite();
1761 GetMainMaterial()->AddToSteadyStateThermalEnergy(Damage);
1762 Success = true;
1763 }
1764 }
1765 return Success;
1766 }
1767
SignalBurn(material * Material)1768 void bodypart::SignalBurn(material* Material)
1769 {
1770 int BodyPartIndex = GetBodyPartIndex();
1771
1772 if(Master)
1773 {
1774 character* Owner = GetMaster();
1775
1776 if(Owner->IsPlayer())
1777 ADD_MESSAGE("Your %s burns away completely!", GetBodyPartName().CStr());
1778 else if(Owner->CanBeSeenByPlayer())
1779 ADD_MESSAGE("The %s of %s burns away completely!", GetBodyPartName().CStr(), Owner->CHAR_NAME(DEFINITE));
1780
1781 /*GetBodyPart(BodyPartIndex)->*/DropEquipment(!game::IsInWilderness() ? Owner->GetStackUnder() : Owner->GetStack());
1782 /*item* Burnt = */Owner->SevereBodyPart(BodyPartIndex, true);
1783 /* // create lumps of (charred?) flesh... (note, remove 'true' from item* Burnt = SevereBodyPart(BodyPartIndex, true);
1784 if(Burnt)
1785 Burnt->DestroyBodyPart(!game::IsInWilderness() ? GetStackUnder() : GetStack());
1786 */
1787 Owner->SendNewDrawRequest();
1788
1789 if(Owner->IsPlayer())
1790 game::AskForKeyPress(CONST_S("Bodypart destroyed! [press any key to continue]"));
1791 }
1792 else
1793 item::SignalBurn(Material);
1794 }
1795
Extinguish(truth SendMessages)1796 void bodypart::Extinguish(truth SendMessages)
1797 {
1798 if(Master)
1799 {
1800 item::Extinguish(SendMessages); //Master->Extinguish();
1801 Master->UpdatePictures();
1802 }
1803 else
1804 item::Extinguish(SendMessages);
1805 }
1806
SignalBurn(material *)1807 void corpse::SignalBurn(material*)
1808 {
1809 GetDeceased()->Disappear(this, "burn", &item::IsVeryCloseToBurning);
1810 }
1811
AddExtinguishMessage()1812 void bodypart::AddExtinguishMessage()
1813 {
1814 if(Master)
1815 {
1816 character* Owner = GetMaster();
1817
1818 if(Owner->IsPlayer())
1819 ADD_MESSAGE("The flames on your %s die away.", GetBodyPartName().CStr());
1820 else if(Owner->CanBeSeenByPlayer())
1821 ADD_MESSAGE("The flames on the %s of %s die away.", GetBodyPartName().CStr(), Owner->CHAR_NAME(DEFINITE));
1822 }
1823 else
1824 item::AddExtinguishMessage();
1825 }
1826
AddSpecialExtinguishMessageForPF()1827 void bodypart::AddSpecialExtinguishMessageForPF()
1828 {
1829 if(Master)
1830 {
1831 character* Owner = GetMaster();
1832
1833 if(Owner->IsPlayer())
1834 ADD_MESSAGE("Your %s burns even more! But lo', even as it does so, the ashes "
1835 "peel away from your %s and it is made new by some innate virtue!",
1836 CHAR_NAME(UNARTICLED), GetBodyPartName().CStr());
1837 else if(Owner->CanBeSeenByPlayer())
1838 ADD_MESSAGE("The %s of %s burns even more! But lo', even as it does so, the "
1839 "ashes peel away from %s %s and it is made new by some innate virtue!",
1840 GetBodyPartName().CStr(), Owner->CHAR_NAME(DEFINITE),
1841 Owner->GetPossessivePronoun().CStr(), GetBodyPartName().CStr());
1842 }
1843 else
1844 item::AddSpecialExtinguishMessageForPF();
1845 }
1846
Extinguish(truth SendMessages)1847 void corpse::Extinguish(truth SendMessages)
1848 {
1849 GetDeceased()->Extinguish(SendMessages);
1850 }
1851
SignalDisappearance()1852 void corpse::SignalDisappearance()
1853 {
1854 GetDeceased()->Disappear(this, "disappear", &item::IsVeryCloseToDisappearance);
1855 }
1856
CanBePiledWith(citem * Item,ccharacter * Viewer) const1857 truth bodypart::CanBePiledWith(citem* Item, ccharacter* Viewer) const
1858 {
1859 return item::CanBePiledWith(Item, Viewer)
1860 && OwnerDescription == static_cast<const bodypart*>(Item)->OwnerDescription;
1861 }
1862
CanBePiledWith(citem * Item,ccharacter * Viewer) const1863 truth corpse::CanBePiledWith(citem* Item, ccharacter* Viewer) const
1864 {
1865 if(GetType() != Item->GetType()
1866 || GetConfig() != Item->GetConfig()
1867 || GetWeight() != Item->GetWeight()
1868 || Viewer->GetCWeaponSkillLevel(this) != Viewer->GetCWeaponSkillLevel(Item)
1869 || Viewer->GetSWeaponSkillLevel(this) != Viewer->GetSWeaponSkillLevel(Item))
1870 return false;
1871
1872 const corpse* Corpse = static_cast<const corpse*>(Item);
1873
1874 if(Deceased->GetBodyParts() != Corpse->Deceased->GetBodyParts())
1875 return false;
1876
1877 for(int c = 0; c < Deceased->GetBodyParts(); ++c)
1878 {
1879 bodypart* BodyPart1 = Deceased->GetBodyPart(c);
1880 bodypart* BodyPart2 = Corpse->Deceased->GetBodyPart(c);
1881
1882 if(!BodyPart1 && !BodyPart2)
1883 continue;
1884
1885 if(!BodyPart1 || !BodyPart2 || !BodyPart1->CanBePiledWith(BodyPart2, Viewer))
1886 return false;
1887 }
1888
1889 if(Deceased->GetName(UNARTICLED) != Corpse->Deceased->GetName(UNARTICLED))
1890 return false;
1891
1892 return true;
1893 }
1894
Be()1895 void bodypart::Be()
1896 {
1897 if(Master)
1898 {
1899 if(HP < MaxHP && ++SpillBloodCounter >= 4)
1900 {
1901 if(Master->IsEnabled())
1902 {
1903 if(IsBadlyHurt() && !Master->IsPolymorphed() && !(RAND() & 3))
1904 SpillBlood(1);
1905 }
1906 else if(!Master->IsPolymorphed() && !(RAND() & 3))
1907 {
1908 SpillBlood(1);
1909 HP += Max(((MaxHP - HP) >> 2), 1);
1910 }
1911
1912 SpillBloodCounter = 0;
1913 }
1914 // Organics can have an active Be() function, if they are burning...
1915 // they will normally burn completely before they spoil
1916 if(Master->AllowSpoil() || !Master->IsEnabled() || !!IsBurning())
1917 MainMaterial->Be(ItemFlags);
1918
1919 if(Exists() && LifeExpectancy)
1920 {
1921 if(LifeExpectancy == 1)
1922 Master->SignalDisappearance();
1923 else
1924 --LifeExpectancy;
1925 }
1926 }
1927 else
1928 {
1929 if(HP < MaxHP && ++SpillBloodCounter >= 4)
1930 {
1931 if(!(RAND() & 3))
1932 {
1933 SpillBlood(1);
1934 HP += Max(((MaxHP - HP) >> 2), 1);
1935 }
1936
1937 SpillBloodCounter = 0;
1938 }
1939
1940 item::Be();
1941 }
1942 }
1943
SpillBlood(int HowMuch,v2 Pos)1944 void bodypart::SpillBlood(int HowMuch, v2 Pos)
1945 {
1946 if(HowMuch
1947 && (!Master || Master->SpillsBlood())
1948 && (IsAlive() || MainMaterial->IsLiquid())
1949 && !game::IsInWilderness())
1950 GetNearLSquare(Pos)->SpillFluid(0, CreateBlood(long(HowMuch * sqrt(BodyPartVolume) / 2)), false, false);
1951 }
1952
SpillBlood(int HowMuch)1953 void bodypart::SpillBlood(int HowMuch)
1954 {
1955 if(HowMuch
1956 && (!Master || Master->SpillsBlood())
1957 && (IsAlive() || MainMaterial->IsLiquid())
1958 && !game::IsInWilderness())
1959 for(int c = 0; c < GetSquaresUnder(); ++c)
1960 if(GetLSquareUnder(c))
1961 GetLSquareUnder(c)->SpillFluid(0, CreateBlood(long(HowMuch * sqrt(BodyPartVolume) / 2)), false, false);
1962 }
1963
SignalEnchantmentChange()1964 void bodypart::SignalEnchantmentChange()
1965 {
1966 if(Master && !Master->IsInitializing())
1967 {
1968 Master->CalculateAttributeBonuses();
1969 Master->CalculateBattleInfo();
1970 }
1971 }
1972
SignalEquipmentAdd(gearslot * Slot)1973 void arm::SignalEquipmentAdd(gearslot* Slot)
1974 {
1975 int EquipmentIndex = Slot->GetEquipmentIndex();
1976
1977 if(Master && !Master->IsInitializing())
1978 {
1979 item* Equipment = Slot->GetItem();
1980
1981 if(Equipment->IsInCorrectSlot(EquipmentIndex))
1982 ApplyEquipmentAttributeBonuses(Equipment);
1983
1984 if(EquipmentIndex == RIGHT_GAUNTLET_INDEX || EquipmentIndex == LEFT_GAUNTLET_INDEX)
1985 ApplyDexterityPenalty(Equipment);
1986
1987 if(EquipmentIndex == RIGHT_WIELDED_INDEX || EquipmentIndex == LEFT_WIELDED_INDEX)
1988 {
1989 UpdateWieldedPicture();
1990 GetSquareUnder()->SendNewDrawRequest();
1991 }
1992 }
1993
1994 if(Master)
1995 Master->SignalEquipmentAdd(EquipmentIndex);
1996 }
1997
SignalEquipmentRemoval(gearslot * Slot,citem * Item)1998 void arm::SignalEquipmentRemoval(gearslot* Slot, citem* Item)
1999 {
2000 int EquipmentIndex = Slot->GetEquipmentIndex();
2001
2002 if(Master && !Master->IsInitializing())
2003 if(EquipmentIndex == RIGHT_WIELDED_INDEX || EquipmentIndex == LEFT_WIELDED_INDEX)
2004 {
2005 UpdateWieldedPicture();
2006 square* Square = GetSquareUnder();
2007
2008 if(Square)
2009 Square->SendNewDrawRequest();
2010 }
2011
2012 if(Master)
2013 Master->SignalEquipmentRemoval(EquipmentIndex, Item);
2014 }
2015
SignalEquipmentAdd(gearslot * Slot)2016 void leg::SignalEquipmentAdd(gearslot* Slot)
2017 {
2018 int EquipmentIndex = Slot->GetEquipmentIndex();
2019
2020 if(Master && !Master->IsInitializing())
2021 {
2022 item* Equipment = Slot->GetItem();
2023
2024 if(Equipment->IsInCorrectSlot(EquipmentIndex))
2025 ApplyEquipmentAttributeBonuses(Equipment);
2026
2027 if(EquipmentIndex == RIGHT_BOOT_INDEX || EquipmentIndex == LEFT_BOOT_INDEX)
2028 ApplyAgilityPenalty(Equipment);
2029 }
2030
2031 if(Master)
2032 Master->SignalEquipmentAdd(EquipmentIndex);
2033 }
2034
ApplyEquipmentAttributeBonuses(item * Item)2035 void arm::ApplyEquipmentAttributeBonuses(item* Item)
2036 {
2037 if(Item->AffectsArmStrength())
2038 StrengthBonus += Item->GetEnchantment();
2039
2040 if(Item->AffectsDexterity())
2041 DexterityBonus += Item->GetEnchantment();
2042 }
2043
ApplyEquipmentAttributeBonuses(item * Item)2044 void leg::ApplyEquipmentAttributeBonuses(item* Item)
2045 {
2046 if(Item->AffectsLegStrength())
2047 {
2048 StrengthBonus += Item->GetEnchantment();
2049
2050 if(Master)
2051 Master->CalculateBurdenState();
2052 }
2053
2054 if(Item->AffectsAgility())
2055 AgilityBonus += Item->GetEnchantment();
2056 }
2057
CalculateAttributeBonuses()2058 void arm::CalculateAttributeBonuses()
2059 {
2060 StrengthBonus = DexterityBonus = 0;
2061
2062 for(int c = 0; c < GetEquipments(); ++c)
2063 {
2064 item* Equipment = GetEquipment(c);
2065
2066 if(Equipment && Equipment->IsInCorrectSlot())
2067 ApplyEquipmentAttributeBonuses(Equipment);
2068 }
2069
2070 ApplyDexterityPenalty(GetGauntlet());
2071
2072 if(Master)
2073 {
2074 ApplyDexterityPenalty(GetExternalCloak());
2075 ApplyDexterityPenalty(GetExternalBodyArmor());
2076 ApplyStrengthBonus(GetExternalHelmet());
2077 ApplyStrengthBonus(GetExternalCloak());
2078 ApplyStrengthBonus(GetExternalBodyArmor());
2079 ApplyStrengthBonus(GetExternalBelt());
2080 ApplyDexterityBonus(GetExternalHelmet());
2081 ApplyDexterityBonus(GetExternalCloak());
2082 ApplyDexterityBonus(GetExternalBodyArmor());
2083 ApplyDexterityBonus(GetExternalBelt());
2084 }
2085
2086 if(!UseMaterialAttributes())
2087 {
2088 StrengthBonus -= CalculateScarAttributePenalty(GetAttribute(ARM_STRENGTH, false));
2089 DexterityBonus -= CalculateScarAttributePenalty(GetAttribute(DEXTERITY, false));
2090
2091 StrengthBonus -= CalculateBurnAttributePenalty(GetAttribute(ARM_STRENGTH, false));
2092 DexterityBonus -= CalculateBurnAttributePenalty(GetAttribute(DEXTERITY, false));
2093 }
2094 }
2095
CalculateAttributeBonuses()2096 void leg::CalculateAttributeBonuses()
2097 {
2098 StrengthBonus = AgilityBonus = 0;
2099
2100 for(int c = 0; c < GetEquipments(); ++c)
2101 {
2102 item* Equipment = GetEquipment(c);
2103
2104 if(Equipment && Equipment->IsInCorrectSlot())
2105 ApplyEquipmentAttributeBonuses(Equipment);
2106 }
2107
2108 ApplyAgilityPenalty(GetBoot());
2109
2110 if(Master)
2111 {
2112 ApplyAgilityPenalty(GetExternalCloak());
2113 ApplyAgilityPenalty(GetExternalBodyArmor());
2114 ApplyStrengthBonus(GetExternalHelmet());
2115 ApplyStrengthBonus(GetExternalCloak());
2116 ApplyStrengthBonus(GetExternalBodyArmor());
2117 ApplyStrengthBonus(GetExternalBelt());
2118 ApplyAgilityBonus(GetExternalHelmet());
2119 ApplyAgilityBonus(GetExternalCloak());
2120 ApplyAgilityBonus(GetExternalBodyArmor());
2121 ApplyAgilityBonus(GetExternalBelt());
2122 }
2123
2124 if(!UseMaterialAttributes())
2125 {
2126 StrengthBonus -= CalculateScarAttributePenalty(GetAttribute(LEG_STRENGTH, false));
2127 AgilityBonus -= CalculateScarAttributePenalty(GetAttribute(AGILITY, false));
2128
2129 StrengthBonus -= CalculateBurnAttributePenalty(GetAttribute(LEG_STRENGTH, false));
2130 AgilityBonus -= CalculateBurnAttributePenalty(GetAttribute(AGILITY, false));
2131 }
2132 }
2133
SignalEquipmentAdd(gearslot * Slot)2134 void humanoidtorso::SignalEquipmentAdd(gearslot* Slot)
2135 {
2136 if(!Master)
2137 return;
2138
2139 humanoid* Master = GetHumanoidMaster();
2140 int EquipmentIndex = Slot->GetEquipmentIndex();
2141
2142 if(!Master->IsInitializing()
2143 && (EquipmentIndex == CLOAK_INDEX || EquipmentIndex == BODY_ARMOR_INDEX))
2144 {
2145 item* Item = Slot->GetItem();
2146
2147 if(Master->GetRightArm())
2148 Master->GetRightArm()->ApplyDexterityPenalty(Item);
2149
2150 if(Master->GetLeftArm())
2151 Master->GetLeftArm()->ApplyDexterityPenalty(Item);
2152
2153 if(Master->GetRightLeg())
2154 Master->GetRightLeg()->ApplyAgilityPenalty(Item);
2155
2156 if(Master->GetLeftLeg())
2157 Master->GetLeftLeg()->ApplyAgilityPenalty(Item);
2158 }
2159
2160 Master->SignalEquipmentAdd(EquipmentIndex);
2161 }
2162
GetWieldedHitStrength() const2163 int arm::GetWieldedHitStrength() const
2164 {
2165 int HitStrength = GetAttribute(ARM_STRENGTH);
2166 int Requirement = GetWielded()->GetStrengthRequirement();
2167
2168 if(TwoHandWieldIsActive())
2169 {
2170 HitStrength += GetPairArm()->GetAttribute(ARM_STRENGTH);
2171 Requirement >>= 2;
2172 }
2173
2174 return HitStrength - Requirement;
2175 }
2176
ApplyStrengthBonus(item * Item)2177 void arm::ApplyStrengthBonus(item* Item)
2178 {
2179 if(Item && Item->AffectsArmStrength())
2180 StrengthBonus += Item->GetEnchantment() / 2;
2181 }
2182
ApplyDexterityBonus(item * Item)2183 void arm::ApplyDexterityBonus(item* Item)
2184 {
2185 if(Item && Item->AffectsDexterity())
2186 DexterityBonus += Item->GetEnchantment() / 2;
2187 }
2188
ApplyStrengthBonus(item * Item)2189 void leg::ApplyStrengthBonus(item* Item)
2190 {
2191 if(Item && Item->AffectsLegStrength())
2192 StrengthBonus += Item->GetEnchantment() / 2;
2193 }
2194
ApplyAgilityBonus(item * Item)2195 void leg::ApplyAgilityBonus(item* Item)
2196 {
2197 if(Item && Item->AffectsAgility())
2198 AgilityBonus += Item->GetEnchantment() / 2;
2199 }
2200
ApplyDexterityPenalty(item * Item)2201 void arm::ApplyDexterityPenalty(item* Item)
2202 {
2203 if(Item)
2204 DexterityBonus -= Item->GetInElasticityPenalty(GetAttribute(DEXTERITY, false));
2205 }
2206
ApplyAgilityPenalty(item * Item)2207 void leg::ApplyAgilityPenalty(item* Item)
2208 {
2209 if(Item)
2210 AgilityBonus -= Item->GetInElasticityPenalty(GetAttribute(AGILITY, false));
2211 }
2212
GetSpoilLevel() const2213 int corpse::GetSpoilLevel() const
2214 {
2215 int FlyAmount = 0;
2216
2217 for(int c = 0; c < GetDeceased()->GetBodyParts(); ++c)
2218 {
2219 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
2220
2221 if(BodyPart && FlyAmount < BodyPart->GetSpoilLevel())
2222 FlyAmount = BodyPart->GetSpoilLevel();
2223 }
2224
2225 return FlyAmount;
2226 }
2227
SignalSpoilLevelChange(material * Material)2228 void bodypart::SignalSpoilLevelChange(material* Material)
2229 {
2230 if(Master)
2231 Master->SignalSpoilLevelChange();
2232 else
2233 item::SignalSpoilLevelChange(Material);
2234 }
2235
SignalBurnLevelChange()2236 void bodypart::SignalBurnLevelChange()
2237 {
2238 // if(Master)
2239 // Master->SignalBurnLevelChange();
2240 // else
2241 item::SignalBurnLevelChange();
2242 }
2243
SignalBurnLevelTransitionMessage()2244 void bodypart::SignalBurnLevelTransitionMessage()
2245 {
2246 cchar* MoreMsg = MainMaterial->GetBurnLevel() == NOT_BURNT ? "" : " more";
2247
2248 if(Master)
2249 {
2250 if(Master->IsPlayer())
2251 ADD_MESSAGE("Your %s burns%s.", CHAR_NAME(UNARTICLED), MoreMsg);
2252 else if(CanBeSeenByPlayer())
2253 ADD_MESSAGE("The %s of %s burns%s.", CHAR_NAME(UNARTICLED), Master->CHAR_NAME(DEFINITE), MoreMsg);
2254 }
2255 else if(CanBeSeenByPlayer())
2256 ADD_MESSAGE("%s burns%s.", CHAR_NAME(DEFINITE), MoreMsg);
2257 else
2258 item::SignalBurnLevelTransitionMessage();
2259 }
2260
DamageArmor(character * Damager,int Damage,int Type)2261 truth head::DamageArmor(character* Damager, int Damage, int Type)
2262 {
2263 long AV[3] = { 0, 0, 0 }, AVSum = 0;
2264 item* Armor[3];
2265
2266 if((Armor[0] = GetHelmet()))
2267 AVSum += AV[0] = Max(Armor[0]->GetStrengthValue(), 1);
2268
2269 if((Armor[1] = GetExternalBodyArmor()))
2270 AVSum += AV[1] = Max(Armor[1]->GetStrengthValue() >> 2, 1);
2271
2272 if((Armor[2] = GetExternalCloak()))
2273 AVSum += AV[2] = Max(Armor[2]->GetStrengthValue(), 1);
2274
2275 return AVSum ? Armor[femath::WeightedRand(AV, AVSum)]->ReceiveDamage(Damager, Damage, Type) : false;
2276 }
2277
DamageArmor(character * Damager,int Damage,int Type)2278 truth humanoidtorso::DamageArmor(character* Damager, int Damage, int Type)
2279 {
2280 long AV[3] = { 0, 0, 0 }, AVSum = 0;
2281 item* Armor[3];
2282
2283 if((Armor[0] = GetBodyArmor()))
2284 AVSum += AV[0] = Max(Armor[0]->GetStrengthValue(), 1);
2285
2286 if((Armor[1] = GetBelt()))
2287 AVSum += AV[1] = Max(Armor[1]->GetStrengthValue(), 1);
2288
2289 if((Armor[2] = GetCloak()))
2290 AVSum += AV[2] = Max(Armor[2]->GetStrengthValue(), 1);
2291
2292 return AVSum ? Armor[femath::WeightedRand(AV, AVSum)]->ReceiveDamage(Damager, Damage, Type) : false;
2293 }
2294
DamageArmor(character * Damager,int Damage,int Type)2295 truth arm::DamageArmor(character* Damager, int Damage, int Type)
2296 {
2297 long AV[3] = { 0, 0, 0 }, AVSum = 0;
2298 item* Armor[3];
2299
2300 if((Armor[0] = GetGauntlet()))
2301 AVSum += AV[0] = Max(Armor[0]->GetStrengthValue(), 1);
2302
2303 if((Armor[1] = GetExternalBodyArmor()))
2304 AVSum += AV[1] = Max(Armor[1]->GetStrengthValue() >> 1, 1);
2305
2306 if((Armor[2] = GetExternalCloak()))
2307 AVSum += AV[2] = Max(Armor[2]->GetStrengthValue(), 1);
2308
2309 return AVSum ? Armor[femath::WeightedRand(AV, AVSum)]->ReceiveDamage(Damager, Damage, Type) : false;
2310 }
2311
DamageArmor(character * Damager,int Damage,int Type)2312 truth groin::DamageArmor(character* Damager, int Damage, int Type)
2313 {
2314 return Master->GetTorso()->DamageArmor(Damager, Damage, Type);
2315 }
2316
DamageArmor(character * Damager,int Damage,int Type)2317 truth leg::DamageArmor(character* Damager, int Damage, int Type)
2318 {
2319 long AV[3] = { 0, 0, 0 }, AVSum = 0;
2320 item* Armor[3];
2321
2322 if((Armor[0] = GetBoot()))
2323 AVSum += AV[0] = Max(Armor[0]->GetStrengthValue(), 1);
2324
2325 if((Armor[1] = GetExternalBodyArmor()))
2326 AVSum += AV[1] = Max(Armor[1]->GetStrengthValue() >> 1, 1);
2327
2328 if((Armor[2] = GetExternalCloak()))
2329 AVSum += AV[2] = Max(Armor[2]->GetStrengthValue(), 1);
2330
2331 return AVSum ? Armor[femath::WeightedRand(AV, AVSum)]->ReceiveDamage(Damager, Damage, Type) : false;
2332 }
2333
CanBeEatenByAI(ccharacter * Who) const2334 truth bodypart::CanBeEatenByAI(ccharacter* Who) const
2335 {
2336 return item::CanBeEatenByAI(Who) && !(Who->IsPet() && PLAYER->HasHadBodyPart(this));
2337 }
2338
GetConditionColorIndex() const2339 int bodypart::GetConditionColorIndex() const
2340 {
2341 if(HP <= 1 && MaxHP > 1)
2342 return 0;
2343 else if((HP << 1) + HP < MaxHP)
2344 return 1;
2345 else if((HP << 1) + HP < MaxHP << 1)
2346 return 2;
2347 else if(HP < MaxHP)
2348 return 3;
2349 else
2350 return 4;
2351 }
2352
CheckIfWeaponTooHeavy(cchar * WeaponDescription) const2353 truth arm::CheckIfWeaponTooHeavy(cchar* WeaponDescription) const
2354 {
2355 if(!IsUsable())
2356 {
2357 ADD_MESSAGE("%s %s is not usable.", Master->CHAR_POSSESSIVE_PRONOUN, GetBodyPartName().CStr());
2358 return !game::TruthQuestion(CONST_S("Continue anyway? [y/N]"));
2359 }
2360
2361 int HitStrength = GetAttribute(ARM_STRENGTH);
2362 int Requirement = GetWielded()->GetStrengthRequirement();
2363
2364 if(TwoHandWieldIsActive())
2365 {
2366 HitStrength += GetPairArm()->GetAttribute(ARM_STRENGTH);
2367 Requirement >>= 2;
2368
2369 if(HitStrength - Requirement < 10)
2370 {
2371 if(HitStrength <= Requirement)
2372 ADD_MESSAGE("%s cannot use %s. Wielding it with two hands requires %d strength.",
2373 Master->CHAR_DESCRIPTION(DEFINITE), WeaponDescription, (Requirement >> 1) + 1);
2374 else if(HitStrength - Requirement < 4)
2375 ADD_MESSAGE("Using %s even with two hands is extremely difficult for %s.",
2376 WeaponDescription, Master->CHAR_DESCRIPTION(DEFINITE));
2377 else if(HitStrength - Requirement < 7)
2378 ADD_MESSAGE("%s %s much trouble using %s even with two hands.",
2379 Master->CHAR_DESCRIPTION(DEFINITE), Master->IsPlayer() ? "have" : "has", WeaponDescription);
2380 else
2381 ADD_MESSAGE("It is somewhat difficult for %s to use %s even with two hands.",
2382 Master->CHAR_DESCRIPTION(DEFINITE), WeaponDescription);
2383
2384 return !game::TruthQuestion(CONST_S("Continue anyway? [y/N]"));
2385 }
2386 }
2387 else
2388 {
2389 if(HitStrength - Requirement < 10)
2390 {
2391 festring OtherHandInfo;
2392 cchar* HandInfo = "";
2393
2394 if(GetWielded()->IsTwoHanded())
2395 {
2396 if(GetPairArm() && !GetPairArm()->IsUsable())
2397 OtherHandInfo = Master->GetPossessivePronoun() + " other arm is unusable. ";
2398
2399 HandInfo = " with one hand";
2400 }
2401
2402 if(HitStrength <= Requirement)
2403 ADD_MESSAGE("%s%s cannot use %s. Wielding it%s requires %d strength.", OtherHandInfo.CStr(),
2404 Master->GetDescription(DEFINITE).CapitalizeCopy().CStr(),
2405 WeaponDescription, HandInfo, Requirement + 1);
2406 else if(HitStrength - Requirement < 4)
2407 ADD_MESSAGE("%sUsing %s%s is extremely difficult for %s.", OtherHandInfo.CStr(),
2408 WeaponDescription, HandInfo, Master->CHAR_DESCRIPTION(DEFINITE));
2409 else if(HitStrength - Requirement < 7)
2410 ADD_MESSAGE("%s%s %s much trouble using %s%s.", OtherHandInfo.CStr(),
2411 Master->GetDescription(DEFINITE).CapitalizeCopy().CStr(),
2412 Master->IsPlayer() ? "have" : "has", WeaponDescription, HandInfo);
2413 else
2414 ADD_MESSAGE("%sIt is somewhat difficult for %s to use %s%s.", OtherHandInfo.CStr(),
2415 Master->CHAR_DESCRIPTION(DEFINITE), WeaponDescription, HandInfo);
2416 return !game::TruthQuestion(CONST_S("Continue anyway? [y/N]"));
2417 }
2418 }
2419
2420 return false;
2421 }
2422
GetArticleMode() const2423 int corpse::GetArticleMode() const
2424 {
2425 return Deceased->LeftOversAreUnique() ? FORCE_THE : 0;
2426 }
2427
Behead()2428 head* head::Behead()
2429 {
2430 RemoveFromSlot();
2431 return this;
2432 }
2433
EditAllAttributes(int Amount)2434 truth arm::EditAllAttributes(int Amount)
2435 {
2436 LimitRef(StrengthExperience += Amount * EXP_MULTIPLIER, MIN_EXP, MAX_EXP);
2437 LimitRef(DexterityExperience += Amount * EXP_MULTIPLIER, MIN_EXP, MAX_EXP);
2438 return (Amount < 0
2439 && (StrengthExperience != MIN_EXP || DexterityExperience != MIN_EXP))
2440 || (Amount > 0
2441 && (StrengthExperience != MAX_EXP || DexterityExperience != MAX_EXP));
2442 }
2443
EditAllAttributes(int Amount)2444 truth leg::EditAllAttributes(int Amount)
2445 {
2446 LimitRef(StrengthExperience += Amount * EXP_MULTIPLIER, MIN_EXP, MAX_EXP);
2447 LimitRef(AgilityExperience += Amount * EXP_MULTIPLIER, MIN_EXP, MAX_EXP);
2448 return (Amount < 0
2449 && (StrengthExperience != MIN_EXP || AgilityExperience != MIN_EXP))
2450 || (Amount > 0
2451 && (StrengthExperience != MAX_EXP || AgilityExperience != MAX_EXP));
2452 }
2453
2454 #ifdef WIZARD
2455
AddAttackInfo(felist & List) const2456 void arm::AddAttackInfo(felist& List) const
2457 {
2458 if(GetDamage())
2459 {
2460 festring Entry = CONST_S(" ");
2461
2462 if(GetWielded())
2463 {
2464 GetWielded()->AddName(Entry, UNARTICLED);
2465
2466 if(TwoHandWieldIsActive())
2467 Entry << " (b)";
2468 }
2469 else
2470 Entry << "melee attack";
2471
2472 Entry.Resize(50);
2473 Entry << GetMinDamage() << '-' << GetMaxDamage();
2474 Entry.Resize(60);
2475 Entry << int(GetToHitValue());
2476 Entry.Resize(70);
2477 Entry << GetAPCost();
2478 List.AddEntry(Entry, LIGHT_GRAY);
2479 }
2480 }
2481
AddDefenceInfo(felist & List) const2482 void arm::AddDefenceInfo(felist& List) const
2483 {
2484 if(GetWielded())
2485 {
2486 festring Entry = CONST_S(" ");
2487 GetWielded()->AddName(Entry, UNARTICLED);
2488 Entry.Resize(50);
2489 Entry << int(GetBlockValue());
2490 Entry.Resize(70);
2491 Entry << GetBlockCapability();
2492 List.AddEntry(Entry, LIGHT_GRAY);
2493 }
2494 }
2495
2496 #else
2497
AddAttackInfo(felist &) const2498 void arm::AddAttackInfo(felist&) const { }
AddDefenceInfo(felist &) const2499 void arm::AddDefenceInfo(felist&) const { }
2500
2501 #endif
2502
UpdateWieldedPicture()2503 void arm::UpdateWieldedPicture()
2504 {
2505 if(!Master || !Master->PictureUpdatesAreForbidden())
2506 {
2507 truth WasAnimated = MasterIsAnimated();
2508 item* Wielded = GetWielded();
2509
2510 if(Wielded && Master)
2511 {
2512 int SpecialFlags = (IsRightArm() ? 0 : MIRROR)|ST_WIELDED|(Wielded->GetSpecialFlags()&~0x3F);
2513 Wielded->UpdatePictures(WieldedGraphicData,
2514 Master->GetWieldedPosition(),
2515 SpecialFlags,
2516 GetMaxAlpha(),
2517 GR_HUMANOID,
2518 static_cast<bposretriever>(&item::GetWieldedBitmapPos));
2519
2520 if(ShowFluids())
2521 Wielded->CheckFluidGearPictures(Wielded->GetWieldedBitmapPos(0), SpecialFlags, false);
2522 }
2523 else
2524 WieldedGraphicData.Retire();
2525
2526 if(!WasAnimated != !MasterIsAnimated())
2527 SignalAnimationStateChange(WasAnimated);
2528 }
2529 }
2530
DrawWielded(blitdata & BlitData) const2531 void arm::DrawWielded(blitdata& BlitData) const
2532 {
2533 DrawEquipment(WieldedGraphicData, BlitData);
2534
2535 if(ShowFluids() && GetWielded())
2536 GetWielded()->DrawFluidGearPictures(BlitData, IsRightArm() ? 0 : MIRROR);
2537 }
2538
UpdatePictures()2539 void arm::UpdatePictures()
2540 {
2541 bodypart::UpdatePictures();
2542 UpdateWieldedPicture();
2543 }
2544
Draw(blitdata & BlitData) const2545 void bodypart::Draw(blitdata& BlitData) const
2546 {
2547 cint AF = GraphicData.AnimationFrames;
2548 cint F = !(BlitData.CustomData & ALLOW_ANIMATE) || AF == 1 ? 0 : GET_TICK() & (AF - 1);
2549 cbitmap* P = GraphicData.Picture[F];
2550
2551 if(BlitData.CustomData & ALLOW_ALPHA)
2552 P->AlphaPriorityBlit(BlitData);
2553 else
2554 P->MaskedPriorityBlit(BlitData);
2555
2556 if(Fluid && ShowFluids())
2557 DrawFluids(BlitData);
2558
2559 DrawArmor(BlitData);
2560 }
2561
AddAttackInfo(felist & List) const2562 void leg::AddAttackInfo(felist& List) const
2563 {
2564 festring Entry = CONST_S(" kick attack");
2565 Entry.Resize(50);
2566 Entry << GetKickMinDamage() << '-' << GetKickMaxDamage();
2567 Entry.Resize(60);
2568 Entry << int(GetKickToHitValue());
2569 Entry.Resize(70);
2570 Entry << GetKickAPCost();
2571 List.AddEntry(Entry, LIGHT_GRAY);
2572 }
2573
PreProcessForBone()2574 void corpse::PreProcessForBone()
2575 {
2576 item::PreProcessForBone();
2577
2578 if(!Deceased->PreProcessForBone())
2579 {
2580 RemoveFromSlot();
2581 SendToHell();
2582 }
2583 }
2584
PostProcessForBone()2585 void corpse::PostProcessForBone()
2586 {
2587 item::PostProcessForBone();
2588
2589 if(!Deceased->PostProcessForBone())
2590 {
2591 RemoveFromSlot();
2592 SendToHell();
2593 }
2594 }
2595
FinalProcessForBone()2596 void corpse::FinalProcessForBone()
2597 {
2598 item::FinalProcessForBone();
2599 Deceased->FinalProcessForBone();
2600 }
2601
IsRepairable(ccharacter *) const2602 truth bodypart::IsRepairable(ccharacter*) const
2603 {
2604 return !CanRegenerate() && (GetHP() < GetMaxHP() || IsRusted() || IsBurnt());
2605 }
2606
SuckSoul(character * Soul,character * Summoner)2607 truth corpse::SuckSoul(character* Soul, character* Summoner)
2608 {
2609 v2 Pos = Soul->GetPos();
2610
2611 if(Deceased->SuckSoul(Soul))
2612 {
2613 Soul->Remove();
2614 character* Deceased = GetDeceased();
2615
2616 if(RaiseTheDead(Summoner))
2617 {
2618 Soul->SendToHell();
2619 return true;
2620 }
2621 else
2622 {
2623 Deceased->SetSoulID(Soul->GetID());
2624 Soul->PutTo(Pos);
2625 return false;
2626 }
2627 }
2628 else
2629 return false;
2630 }
2631
GetTypeDamage(ccharacter * Enemy) const2632 double arm::GetTypeDamage(ccharacter* Enemy) const
2633 {
2634 double ActualDamage = GetDamage();
2635
2636 if(GetWielded())
2637 {
2638 if(GetWielded()->IsGoodWithPlants() && Enemy->IsPlant())
2639 ActualDamage *= 1.5;
2640 if(GetWielded()->IsGoodWithUndead() && Enemy->IsUndead())
2641 ActualDamage *= 1.5;
2642 if(HasSadistWeapon() && Enemy->IsMasochist())
2643 ActualDamage *= 0.75;
2644 }
2645
2646 return ActualDamage;
2647 }
2648
Draw(blitdata & BlitData) const2649 void largetorso::Draw(blitdata& BlitData) const
2650 {
2651 LargeDraw(BlitData);
2652 }
2653
Draw(blitdata & BlitData) const2654 void largecorpse::Draw(blitdata& BlitData) const
2655 {
2656 LargeDraw(BlitData);
2657 }
2658
SignalStackAdd(stackslot * StackSlot,void (stack::* AddHandler)(item *,truth))2659 void largetorso::SignalStackAdd(stackslot* StackSlot, void (stack::*AddHandler)(item*, truth))
2660 {
2661 if(!Slot[0])
2662 {
2663 Slot[0] = StackSlot;
2664 v2 Pos = GetPos();
2665 level* Level = GetLevel();
2666
2667 for(int c = 1; c < 4; ++c)
2668 (Level->GetLSquare(Pos + game::GetLargeMoveVector(12 + c))->GetStack()->*AddHandler)(this, false);
2669 }
2670 else
2671 for(int c = 1; c < 4; ++c)
2672 if(!Slot[c])
2673 {
2674 Slot[c] = StackSlot;
2675 return;
2676 }
2677 }
2678
GetSquareIndex(v2 Pos) const2679 int largetorso::GetSquareIndex(v2 Pos) const
2680 {
2681 v2 RelativePos = Pos - GetPos();
2682 return RelativePos.X + (RelativePos.Y << 1);
2683 }
2684
SignalStackAdd(stackslot * StackSlot,void (stack::* AddHandler)(item *,truth))2685 void largecorpse::SignalStackAdd(stackslot* StackSlot, void (stack::*AddHandler)(item*, truth))
2686 {
2687 if(!Slot[0])
2688 {
2689 Slot[0] = StackSlot;
2690 v2 Pos = GetPos();
2691 level* Level = GetLevel();
2692
2693 for(int c = 1; c < 4; ++c)
2694 (Level->GetLSquare(Pos + game::GetLargeMoveVector(12 + c))->GetStack()->*AddHandler)(this, false);
2695 }
2696 else
2697 for(int c = 1; c < 4; ++c)
2698 if(!Slot[c])
2699 {
2700 Slot[c] = StackSlot;
2701 return;
2702 }
2703 }
2704
GetSquareIndex(v2 Pos) const2705 int largecorpse::GetSquareIndex(v2 Pos) const
2706 {
2707 v2 RelativePos = Pos - GetPos();
2708 return RelativePos.X + (RelativePos.Y << 1);
2709 }
2710
TryNecromancy(character * Summoner)2711 character* corpse::TryNecromancy(character* Summoner)
2712 {
2713 if(Summoner && Summoner->IsPlayer())
2714 game::DoEvilDeed(50);
2715
2716 character* Zombie = GetDeceased()->CreateZombie();
2717
2718 if(Zombie)
2719 {
2720 v2 Pos = GetPos();
2721 RemoveFromSlot();
2722 Zombie->ChangeTeam(Summoner ? Summoner->GetTeam() : game::GetTeam(MONSTER_TEAM));
2723 Zombie->PutToOrNear(Pos);
2724 Zombie->SignalStepFrom(0);
2725 SendToHell();
2726 return Zombie;
2727 }
2728
2729 return 0;
2730 }
2731
GetArmorToReceiveFluid(truth) const2732 item* head::GetArmorToReceiveFluid(truth) const
2733 {
2734 item* Helmet = GetHelmet();
2735
2736 if(Helmet && Helmet->GetCoverPercentile() > RAND() % 100)
2737 return Helmet;
2738 else
2739 return 0;
2740 }
2741
GetArmorToReceiveFluid(truth) const2742 item* humanoidtorso::GetArmorToReceiveFluid(truth) const
2743 {
2744 item* Cloak = GetCloak();
2745
2746 if(Cloak && !(RAND() % 3))
2747 return Cloak;
2748
2749 item* Belt = GetBelt();
2750
2751 if(Belt && !(RAND() % 10))
2752 return Belt;
2753
2754 item* BodyArmor = GetBodyArmor();
2755 return BodyArmor ? BodyArmor : 0;
2756 }
2757
GetArmorToReceiveFluid(truth) const2758 item* arm::GetArmorToReceiveFluid(truth) const
2759 {
2760 item* Cloak = GetExternalCloak();
2761
2762 if(Cloak && !(RAND() % 3))
2763 return Cloak;
2764
2765 item* Wielded = GetWielded();
2766
2767 if(Wielded && !(RAND() % 3))
2768 return Wielded;
2769
2770 item* Gauntlet = GetGauntlet();
2771
2772 if(Gauntlet && RAND() & 1)
2773 return Gauntlet;
2774
2775 item* BodyArmor = GetExternalBodyArmor();
2776 return BodyArmor ? BodyArmor : 0;
2777 }
2778
GetArmorToReceiveFluid(truth) const2779 item* groin::GetArmorToReceiveFluid(truth) const
2780 {
2781 item* Cloak = GetExternalCloak();
2782
2783 if(Cloak && !(RAND() % 3))
2784 return Cloak;
2785
2786 item* BodyArmor = GetExternalBodyArmor();
2787 return BodyArmor ? BodyArmor : 0;
2788 }
2789
GetArmorToReceiveFluid(truth SteppedOn) const2790 item* leg::GetArmorToReceiveFluid(truth SteppedOn) const
2791 {
2792 if(SteppedOn)
2793 {
2794 item* Boot = GetBoot();
2795 return Boot ? Boot : 0;
2796 }
2797 else
2798 {
2799 item* Cloak = GetExternalCloak();
2800
2801 if(Cloak && !(RAND() % 3))
2802 return Cloak;
2803
2804 item* Boot = GetBoot();
2805
2806 if(Boot && RAND() & 1)
2807 return Boot;
2808
2809 item* BodyArmor = GetExternalBodyArmor();
2810 return BodyArmor ? BodyArmor : 0;
2811 }
2812 }
2813
SpillFluid(character * Spiller,liquid * Liquid,int SquareIndex)2814 void bodypart::SpillFluid(character* Spiller, liquid* Liquid, int SquareIndex)
2815 {
2816 if(Master)
2817 {
2818 item* Armor = GetArmorToReceiveFluid(false);
2819
2820 if(Armor)
2821 Armor->SpillFluid(Spiller, Liquid);
2822 else if(GetMaster())
2823 {
2824 if(Liquid->GetVolume())
2825 AddFluid(Liquid, "", SquareIndex, false);
2826 else
2827 delete Liquid;
2828 }
2829 }
2830 else
2831 item::SpillFluid(Spiller, Liquid, SquareIndex);
2832 }
2833
StayOn(liquid * Liquid)2834 void bodypart::StayOn(liquid* Liquid)
2835 {
2836 item* Armor = GetArmorToReceiveFluid(true);
2837
2838 if(Armor)
2839 Liquid->TouchEffect(Armor, CONST_S(""));
2840 else if(GetMaster())
2841 Liquid->TouchEffect(GetMaster(), GetBodyPartIndex());
2842 }
2843
CreateBlood(long Volume) const2844 liquid* bodypart::CreateBlood(long Volume) const
2845 {
2846 return liquid::Spawn(GetBloodMaterial(), Volume);
2847 }
2848
GetRustDataA() const2849 int corpse::GetRustDataA() const
2850 {
2851 return Deceased->GetTorso()->GetMainMaterial()->GetRustData();
2852 }
2853
GetBurnDataA() const2854 int corpse::GetBurnDataA() const
2855 {
2856 return Deceased->GetTorso()->GetMainMaterial()->GetBurnData();
2857 }
2858
UpdateArmorPicture(graphicdata & GData,item * Armor,int SpecialFlags,v2 (item::* Retriever)(int)const,truth BodyArmor) const2859 void bodypart::UpdateArmorPicture(graphicdata& GData, item* Armor, int SpecialFlags,
2860 v2 (item::*Retriever)(int) const, truth BodyArmor) const
2861 {
2862 if(Armor && Master)
2863 {
2864 Armor->UpdatePictures(GData,
2865 ZERO_V2,
2866 SpecialFlags|Armor->GetSpecialFlags(),
2867 GetMaxAlpha(),
2868 GR_HUMANOID,
2869 static_cast<bposretriever>(Retriever));
2870 Armor->CheckFluidGearPictures((Armor->*Retriever)(0), SpecialFlags, BodyArmor);
2871 }
2872 else
2873 GData.Retire();
2874 }
2875
UpdateArmorPictures()2876 truth playerkindhead::UpdateArmorPictures()
2877 {
2878 UpdateHeadArmorPictures(HelmetGraphicData);
2879 return true;
2880 }
2881
UpdateArmorPictures()2882 truth playerkindtorso::UpdateArmorPictures()
2883 {
2884 UpdateTorsoArmorPictures(TorsoArmorGraphicData,
2885 CloakGraphicData,
2886 BeltGraphicData);
2887 return true;
2888 }
2889
UpdateArmorPictures()2890 truth playerkindrightarm::UpdateArmorPictures()
2891 {
2892 UpdateArmArmorPictures(ArmArmorGraphicData,
2893 GauntletGraphicData,
2894 ST_RIGHT_ARM);
2895 return true;
2896 }
2897
UpdateArmorPictures()2898 truth playerkindleftarm::UpdateArmorPictures()
2899 {
2900 UpdateArmArmorPictures(ArmArmorGraphicData,
2901 GauntletGraphicData,
2902 ST_LEFT_ARM);
2903 return true;
2904 }
2905
UpdateArmorPictures()2906 truth playerkindgroin::UpdateArmorPictures()
2907 {
2908 UpdateGroinArmorPictures(GroinArmorGraphicData);
2909 return true;
2910 }
2911
UpdateArmorPictures()2912 truth playerkindrightleg::UpdateArmorPictures()
2913 {
2914 UpdateLegArmorPictures(LegArmorGraphicData,
2915 BootGraphicData,
2916 ST_RIGHT_LEG);
2917 return true;
2918 }
2919
UpdateArmorPictures()2920 truth playerkindleftleg::UpdateArmorPictures()
2921 {
2922 UpdateLegArmorPictures(LegArmorGraphicData,
2923 BootGraphicData,
2924 ST_LEFT_LEG);
2925 return true;
2926 }
2927
UpdateHeadArmorPictures(graphicdata & HelmetGraphicData) const2928 void head::UpdateHeadArmorPictures(graphicdata& HelmetGraphicData) const
2929 {
2930 if(!Master || !Master->PictureUpdatesAreForbidden())
2931 {
2932 UpdateArmorPicture(HelmetGraphicData,
2933 GetHelmet(),
2934 ST_OTHER_BODYPART,
2935 &item::GetHelmetBitmapPos);
2936 }
2937 }
2938
UpdateTorsoArmorPictures(graphicdata & TorsoArmorGraphicData,graphicdata & CloakGraphicData,graphicdata & BeltGraphicData) const2939 void humanoidtorso::UpdateTorsoArmorPictures(graphicdata& TorsoArmorGraphicData,
2940 graphicdata& CloakGraphicData,
2941 graphicdata& BeltGraphicData) const
2942 {
2943 if(!Master || !Master->PictureUpdatesAreForbidden())
2944 {
2945 UpdateArmorPicture(TorsoArmorGraphicData,
2946 GetBodyArmor(),
2947 ST_OTHER_BODYPART,
2948 &item::GetTorsoArmorBitmapPos,
2949 true);
2950 UpdateArmorPicture(CloakGraphicData,
2951 GetCloak(),
2952 ST_OTHER_BODYPART,
2953 &item::GetCloakBitmapPos);
2954 UpdateArmorPicture(BeltGraphicData,
2955 GetBelt(),
2956 ST_OTHER_BODYPART,
2957 &item::GetBeltBitmapPos);
2958 }
2959 }
2960
UpdateArmArmorPictures(graphicdata & ArmArmorGraphicData,graphicdata & GauntletGraphicData,int SpecialFlags) const2961 void arm::UpdateArmArmorPictures(graphicdata& ArmArmorGraphicData,
2962 graphicdata& GauntletGraphicData,
2963 int SpecialFlags) const
2964 {
2965 if(!Master || !Master->PictureUpdatesAreForbidden())
2966 {
2967 UpdateArmorPicture(ArmArmorGraphicData,
2968 Master ? GetExternalBodyArmor() : 0,
2969 SpecialFlags,
2970 GetAttribute(ARM_STRENGTH, false) >= 20 ?
2971 &item::GetAthleteArmArmorBitmapPos : &item::GetArmArmorBitmapPos,
2972 true);
2973 UpdateArmorPicture(GauntletGraphicData,
2974 GetGauntlet(),
2975 SpecialFlags,
2976 &item::GetGauntletBitmapPos);
2977 }
2978 }
2979
UpdateGroinArmorPictures(graphicdata & GroinArmorGraphicData) const2980 void groin::UpdateGroinArmorPictures(graphicdata& GroinArmorGraphicData) const
2981 {
2982 if(!Master || !Master->PictureUpdatesAreForbidden())
2983 {
2984 UpdateArmorPicture(GroinArmorGraphicData,
2985 Master ? GetExternalBodyArmor() : 0,
2986 ST_GROIN,
2987 &item::GetLegArmorBitmapPos,
2988 true);
2989 }
2990 }
2991
UpdateLegArmorPictures(graphicdata & LegArmorGraphicData,graphicdata & BootGraphicData,int SpecialFlags) const2992 void leg::UpdateLegArmorPictures(graphicdata& LegArmorGraphicData,
2993 graphicdata& BootGraphicData,
2994 int SpecialFlags) const
2995 {
2996 if(!Master || !Master->PictureUpdatesAreForbidden())
2997 {
2998 UpdateArmorPicture(LegArmorGraphicData,
2999 Master ? GetExternalBodyArmor() : 0,
3000 SpecialFlags,
3001 &item::GetLegArmorBitmapPos,
3002 true);
3003 UpdateArmorPicture(BootGraphicData,
3004 GetBoot(),
3005 SpecialFlags,
3006 &item::GetBootBitmapPos);
3007 }
3008 }
3009
DrawEquipment(const graphicdata & GraphicData,blitdata & BlitData) const3010 void bodypart::DrawEquipment(const graphicdata& GraphicData, blitdata& BlitData) const
3011 {
3012 int EAF = GraphicData.AnimationFrames;
3013
3014 if(EAF)
3015 {
3016 int F = !(BlitData.CustomData & ALLOW_ANIMATE) || EAF == 1 ? 0 : GET_TICK() & (EAF - 1);
3017 GraphicData.Picture[F]->AlphaPriorityBlit(BlitData);
3018 }
3019 }
3020
DrawArmor(blitdata & BlitData) const3021 void playerkindhead::DrawArmor(blitdata& BlitData) const
3022 {
3023 DrawEquipment(HelmetGraphicData, BlitData);
3024
3025 if(GetHelmet())
3026 GetHelmet()->DrawFluidGearPictures(BlitData);
3027 }
3028
DrawArmor(blitdata & BlitData) const3029 void playerkindtorso::DrawArmor(blitdata& BlitData) const
3030 {
3031 DrawEquipment(TorsoArmorGraphicData, BlitData);
3032
3033 if(GetBodyArmor())
3034 GetBodyArmor()->DrawFluidGearPictures(BlitData);
3035
3036 DrawEquipment(CloakGraphicData, BlitData);
3037
3038 if(GetCloak())
3039 GetCloak()->DrawFluidGearPictures(BlitData);
3040
3041 DrawEquipment(BeltGraphicData, BlitData);
3042
3043 if(GetBelt())
3044 GetBelt()->DrawFluidGearPictures(BlitData);
3045 }
3046
DrawArmor(blitdata & BlitData) const3047 void playerkindrightarm::DrawArmor(blitdata& BlitData) const
3048 {
3049 DrawEquipment(ArmArmorGraphicData, BlitData);
3050
3051 if(Master && GetExternalBodyArmor())
3052 GetExternalBodyArmor()->DrawFluidBodyArmorPictures(BlitData, ST_RIGHT_ARM);
3053
3054 DrawEquipment(GauntletGraphicData, BlitData);
3055
3056 if(GetGauntlet())
3057 GetGauntlet()->DrawFluidGearPictures(BlitData);
3058 }
3059
DrawArmor(blitdata & BlitData) const3060 void playerkindleftarm::DrawArmor(blitdata& BlitData) const
3061 {
3062 DrawEquipment(ArmArmorGraphicData, BlitData);
3063
3064 if(Master && GetExternalBodyArmor())
3065 GetExternalBodyArmor()->DrawFluidBodyArmorPictures(BlitData, ST_LEFT_ARM);
3066
3067 DrawEquipment(GauntletGraphicData, BlitData);
3068
3069 if(GetGauntlet())
3070 GetGauntlet()->DrawFluidGearPictures(BlitData);
3071 }
3072
DrawArmor(blitdata & BlitData) const3073 void playerkindgroin::DrawArmor(blitdata& BlitData) const
3074 {
3075 DrawEquipment(GroinArmorGraphicData, BlitData);
3076
3077 if(Master && GetExternalBodyArmor())
3078 GetExternalBodyArmor()->DrawFluidBodyArmorPictures(BlitData, ST_GROIN);
3079 }
3080
DrawArmor(blitdata & BlitData) const3081 void playerkindrightleg::DrawArmor(blitdata& BlitData) const
3082 {
3083 DrawEquipment(LegArmorGraphicData, BlitData);
3084
3085 if(Master && GetExternalBodyArmor())
3086 GetExternalBodyArmor()->DrawFluidBodyArmorPictures(BlitData, ST_RIGHT_LEG);
3087
3088 DrawEquipment(BootGraphicData, BlitData);
3089
3090 if(GetBoot())
3091 GetBoot()->DrawFluidGearPictures(BlitData);
3092 }
3093
DrawArmor(blitdata & BlitData) const3094 void playerkindleftleg::DrawArmor(blitdata& BlitData) const
3095 {
3096 DrawEquipment(LegArmorGraphicData, BlitData);
3097
3098 if(Master && GetExternalBodyArmor())
3099 GetExternalBodyArmor()->DrawFluidBodyArmorPictures(BlitData, ST_LEFT_LEG);
3100
3101 DrawEquipment(BootGraphicData, BlitData);
3102
3103 if(GetBoot())
3104 GetBoot()->DrawFluidGearPictures(BlitData);
3105 }
3106
Save(outputfile & SaveFile) const3107 void playerkindhead::Save(outputfile& SaveFile) const
3108 {
3109 head::Save(SaveFile);
3110 SaveFile << HelmetGraphicData;
3111 }
3112
Load(inputfile & SaveFile)3113 void playerkindhead::Load(inputfile& SaveFile)
3114 {
3115 head::Load(SaveFile);
3116 SaveFile >> HelmetGraphicData;
3117 }
3118
Save(outputfile & SaveFile) const3119 void playerkindtorso::Save(outputfile& SaveFile) const
3120 {
3121 humanoidtorso::Save(SaveFile);
3122 SaveFile << TorsoArmorGraphicData << CloakGraphicData << BeltGraphicData;
3123 }
3124
Load(inputfile & SaveFile)3125 void playerkindtorso::Load(inputfile& SaveFile)
3126 {
3127 humanoidtorso::Load(SaveFile);
3128 SaveFile >> TorsoArmorGraphicData >> CloakGraphicData >> BeltGraphicData;
3129 }
3130
Save(outputfile & SaveFile) const3131 void playerkindrightarm::Save(outputfile& SaveFile) const
3132 {
3133 rightarm::Save(SaveFile);
3134 SaveFile << ArmArmorGraphicData << GauntletGraphicData;
3135 }
3136
Load(inputfile & SaveFile)3137 void playerkindrightarm::Load(inputfile& SaveFile)
3138 {
3139 rightarm::Load(SaveFile);
3140 SaveFile >> ArmArmorGraphicData >> GauntletGraphicData;
3141 }
3142
Save(outputfile & SaveFile) const3143 void playerkindleftarm::Save(outputfile& SaveFile) const
3144 {
3145 leftarm::Save(SaveFile);
3146 SaveFile << ArmArmorGraphicData << GauntletGraphicData;
3147 }
3148
Load(inputfile & SaveFile)3149 void playerkindleftarm::Load(inputfile& SaveFile)
3150 {
3151 leftarm::Load(SaveFile);
3152 SaveFile >> ArmArmorGraphicData >> GauntletGraphicData;
3153 }
3154
Save(outputfile & SaveFile) const3155 void playerkindgroin::Save(outputfile& SaveFile) const
3156 {
3157 groin::Save(SaveFile);
3158 SaveFile << GroinArmorGraphicData;
3159 }
3160
Load(inputfile & SaveFile)3161 void playerkindgroin::Load(inputfile& SaveFile)
3162 {
3163 groin::Load(SaveFile);
3164 SaveFile >> GroinArmorGraphicData;
3165 }
3166
Save(outputfile & SaveFile) const3167 void playerkindrightleg::Save(outputfile& SaveFile) const
3168 {
3169 rightleg::Save(SaveFile);
3170 SaveFile << LegArmorGraphicData << BootGraphicData;
3171 }
3172
Load(inputfile & SaveFile)3173 void playerkindrightleg::Load(inputfile& SaveFile)
3174 {
3175 rightleg::Load(SaveFile);
3176 SaveFile >> LegArmorGraphicData >> BootGraphicData;
3177 }
3178
Save(outputfile & SaveFile) const3179 void playerkindleftleg::Save(outputfile& SaveFile) const
3180 {
3181 leftleg::Save(SaveFile);
3182 SaveFile << LegArmorGraphicData << BootGraphicData;
3183 }
3184
Load(inputfile & SaveFile)3185 void playerkindleftleg::Load(inputfile& SaveFile)
3186 {
3187 leftleg::Load(SaveFile);
3188 SaveFile >> LegArmorGraphicData >> BootGraphicData;
3189 }
3190
MasterIsAnimated() const3191 truth bodypart::MasterIsAnimated() const
3192 {
3193 return Master && !Master->IsInitializing() && Master->IsAnimated();
3194 }
3195
UpdatePictures()3196 void bodypart::UpdatePictures()
3197 {
3198 truth WasAnimated = MasterIsAnimated();
3199
3200 item::UpdatePictures();
3201 UpdateArmorPictures();
3202
3203 if(!WasAnimated != !MasterIsAnimated())
3204 SignalAnimationStateChange(WasAnimated);
3205 }
3206
SignalVolumeAndWeightChange()3207 void playerkindtorso::SignalVolumeAndWeightChange()
3208 {
3209 humanoidtorso::SignalVolumeAndWeightChange();
3210
3211 if(Master && !Master->IsInitializing())
3212 Master->UpdatePictures();
3213 }
3214
ReceiveAcid(material * Material,cfestring & LocationName,long Modifier)3215 void bodypart::ReceiveAcid(material* Material, cfestring& LocationName, long Modifier)
3216 {
3217 if(Master && MainMaterial->GetInteractionFlags() & CAN_DISSOLVE)
3218 {
3219 long Tries = Modifier / 1000;
3220 Modifier -= Tries * 1000; //opt%?
3221 int Damage = 0;
3222
3223 for(long c = 0; c < Tries; ++c)
3224 if(!(RAND() % 100))
3225 ++Damage;
3226
3227 if(Modifier && !(RAND() % 100000 / Modifier))
3228 ++Damage;
3229
3230 if(Damage)
3231 {
3232 ulong Minute = game::GetTotalMinutes();
3233 character* Master = this->Master;
3234
3235 if(Master->GetLastAcidMsgMin() != Minute && (Master->CanBeSeenByPlayer() || Master->IsPlayer()))
3236 {
3237 Master->SetLastAcidMsgMin(Minute);
3238 cfestring MName = Material->GetName(false, false);
3239
3240 if(Master->IsPlayer())
3241 {
3242 cchar* TName = LocationName.IsEmpty() ? GetBodyPartName().CStr() : LocationName.CStr();
3243 ADD_MESSAGE("Caustic %s dissolves your %s.", MName.CStr(), TName);
3244 }
3245 else
3246 ADD_MESSAGE("Caustic %s dissolves %s.", MName.CStr(), Master->CHAR_NAME(DEFINITE));
3247 }
3248
3249 Master->ReceiveBodyPartDamage(0, Damage, ACID, GetBodyPartIndex(), YOURSELF, false, false, false);
3250 ulong DeathFlags = Material->IsStuckTo(Master) ? IGNORE_TRAPS : 0;
3251 Master->CheckDeath(CONST_S("dissolved by ") + Material->GetName(), 0, DeathFlags);
3252 }
3253 }
3254 }
3255
ReceiveHeat(material * Material,cfestring & LocationName,long Modifier)3256 void bodypart::ReceiveHeat(material* Material, cfestring& LocationName, long Modifier)
3257 {
3258 if(Master && MainMaterial->GetInteractionFlags() & CAN_BURN)
3259 {
3260 long Tries = Modifier / 1000;
3261 Modifier -= Tries * 1000;
3262 int Damage = 0;
3263
3264 for(long c = 0; c < Tries; ++c)
3265 if(!(RAND() % 100))
3266 ++Damage;
3267
3268 if(Modifier && !(RAND() % 100000 / Modifier))
3269 ++Damage;
3270
3271 if(Damage)
3272 {
3273 ulong Minute = game::GetTotalMinutes();
3274 character* Master = this->Master;
3275
3276 if(Master->GetLastAcidMsgMin() != Minute && (Master->CanBeSeenByPlayer() || Master->IsPlayer()))
3277 {
3278 Master->SetLastAcidMsgMin(Minute); // I don't really think we need to track acid and heat damage messages separately.
3279 cfestring MName = Material->GetName(false, false);
3280
3281 if(Master->IsPlayer())
3282 {
3283 cchar* TName = LocationName.IsEmpty() ? GetBodyPartName().CStr() : LocationName.CStr();
3284 ADD_MESSAGE("Scorching %s burns your %s.", MName.CStr(), TName);
3285 }
3286 else
3287 ADD_MESSAGE("Scorching %s burns %s.", MName.CStr(), Master->CHAR_NAME(DEFINITE));
3288 }
3289
3290 Master->ReceiveBodyPartDamage(0, Damage, FIRE, GetBodyPartIndex(), YOURSELF, false, false, false);
3291 ulong DeathFlags = Material->IsStuckTo(Master) ? IGNORE_TRAPS : 0;
3292 Master->CheckDeath(CONST_S("burnt to death by ") + Material->GetName(), 0, DeathFlags);
3293 }
3294 }
3295 }
3296
TryToRust(long LiquidModifier)3297 void bodypart::TryToRust(long LiquidModifier)
3298 {
3299 if(MainMaterial->TryToRust(LiquidModifier << 4))
3300 {
3301 cchar* MoreMsg = MainMaterial->GetRustLevel() == NOT_RUSTED ? "" : " more";
3302
3303 if(Master)
3304 {
3305 if(Master->IsPlayer())
3306 ADD_MESSAGE("Your %s rusts%s.", CHAR_NAME(UNARTICLED), MoreMsg);
3307 else if(CanBeSeenByPlayer())
3308 ADD_MESSAGE("The %s of %s rusts%s.", CHAR_NAME(UNARTICLED), Master->CHAR_NAME(DEFINITE), MoreMsg);
3309 }
3310 else if(CanBeSeenByPlayer())
3311 ADD_MESSAGE("%s rusts%s.", CHAR_NAME(DEFINITE), MoreMsg);
3312
3313 MainMaterial->SetRustLevel(MainMaterial->GetRustLevel() + 1);
3314 }
3315 }
3316
GetConsumeMaterial(ccharacter * Consumer,materialpredicate Predicate) const3317 material* corpse::GetConsumeMaterial(ccharacter* Consumer, materialpredicate Predicate) const
3318 {
3319 for(int c = GetDeceased()->GetBodyParts() - 1; c; --c)
3320 {
3321 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
3322
3323 if(BodyPart)
3324 {
3325 material* CM = BodyPart->GetConsumeMaterial(Consumer, Predicate);
3326
3327 if(CM)
3328 return CM;
3329 }
3330 }
3331
3332 return GetDeceased()->GetTorso()->GetConsumeMaterial(Consumer, Predicate);
3333 }
3334
Cannibalize()3335 void corpse::Cannibalize()
3336 {
3337 item::Cannibalize();
3338
3339 for(int c = 0; c < GetDeceased()->GetBodyParts(); ++c)
3340 {
3341 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
3342
3343 if(BodyPart)
3344 BodyPart->Cannibalize();
3345 }
3346 }
3347
RemoveMaterial(material * Material)3348 material* bodypart::RemoveMaterial(material* Material)
3349 {
3350 if(Master && GetBodyPartIndex() == TORSO_INDEX)
3351 return Master->GetMotherEntity()->RemoveMaterial(Material); // gum
3352 else
3353 return item::RemoveMaterial(Material);
3354 }
3355
CopyAttributes(const bodypart * BodyPart)3356 void arm::CopyAttributes(const bodypart* BodyPart)
3357 {
3358 const arm* Arm = static_cast<const arm*>(BodyPart);
3359 StrengthExperience = Arm->StrengthExperience;
3360 DexterityExperience = Arm->DexterityExperience;
3361 }
3362
CopyAttributes(const bodypart * BodyPart)3363 void leg::CopyAttributes(const bodypart* BodyPart)
3364 {
3365 const leg* Leg = static_cast<const leg*>(BodyPart);
3366 StrengthExperience = Leg->StrengthExperience;
3367 AgilityExperience = Leg->AgilityExperience;
3368 }
3369
DetectMaterial(const material * Material) const3370 truth corpse::DetectMaterial(const material* Material) const
3371 {
3372 return GetDeceased()->DetectMaterial(Material);
3373 }
3374
DestroyBodyPart(stack * Stack)3375 void bodypart::DestroyBodyPart(stack* Stack)
3376 {
3377 int Lumps = 1 + RAND() % 3;
3378 long LumpVolume = Volume / Lumps >> 2;
3379
3380 if(LumpVolume >= 10)
3381 for(int c = 0; c < Lumps; ++c)
3382 {
3383 item* Lump = GetMainMaterial()->CreateNaturalForm(LumpVolume + RAND() % LumpVolume);
3384 Stack->AddItem(Lump);
3385 }
3386
3387 SendToHell();
3388 }
3389
GetBitmapPos(int Frame) const3390 v2 magicmushroomtorso::GetBitmapPos(int Frame) const
3391 {
3392 v2 BasePos = torso::GetBitmapPos(Frame);
3393 Frame &= 0x3F;
3394
3395 if(!(Frame & 0x30))
3396 {
3397 if(Frame <= 8)
3398 return v2(BasePos.X + 64 - (abs(Frame - 4) << 4), BasePos.Y);
3399 else
3400 return v2(BasePos.X + 64 - (abs(Frame - 12) << 4), BasePos.Y + 16);
3401 }
3402 else
3403 return BasePos;
3404 }
3405
GetBitmapPos(int Frame) const3406 v2 dogtorso::GetBitmapPos(int Frame) const
3407 {
3408 v2 BasePos = torso::GetBitmapPos(Frame);
3409
3410 if(Frame >= GraphicData.AnimationFrames >> 1)
3411 BasePos.X += 32;
3412
3413 return v2(BasePos.X + ((Frame & 4) << 2), BasePos.Y);
3414 }
3415
Draw(blitdata & BlitData) const3416 void dogtorso::Draw(blitdata& BlitData) const
3417 {
3418 cint AF = GraphicData.AnimationFrames >> 1;
3419 int Index = !(BlitData.CustomData & ALLOW_ANIMATE) || AF == 1 ? 0 : GET_TICK() & (AF - 1);
3420
3421 if(GetHP() << 1 <= GetMaxHP())
3422 Index += AF;
3423
3424 cbitmap* P = GraphicData.Picture[Index];
3425
3426 if(BlitData.CustomData & ALLOW_ALPHA)
3427 P->AlphaPriorityBlit(BlitData);
3428 else
3429 P->MaskedPriorityBlit(BlitData);
3430 }
3431
SetLifeExpectancy(int Base,int RandPlus)3432 void corpse::SetLifeExpectancy(int Base, int RandPlus)
3433 {
3434 Deceased->SetLifeExpectancy(Base, RandPlus);
3435 }
3436
Be()3437 void corpse::Be()
3438 {
3439 for(int c = 0; c < Deceased->GetBodyParts(); ++c)
3440 {
3441 bodypart* BodyPart = Deceased->GetBodyPart(c);
3442
3443 if(BodyPart)
3444 BodyPart->Be();
3445 }
3446 }
3447
SetLifeExpectancy(int Base,int RandPlus)3448 void bodypart::SetLifeExpectancy(int Base, int RandPlus)
3449 {
3450 LifeExpectancy = RandPlus > 1 ? Base + RAND_N(RandPlus) : Base;
3451
3452 if(!Master)
3453 Enable();
3454 }
3455
SpecialEatEffect(character * Eater,int Amount)3456 void bodypart::SpecialEatEffect(character* Eater, int Amount)
3457 {
3458 Amount >>= 6;
3459
3460 if(Amount
3461 && (!Master || Master->SpillsBlood())
3462 && (IsAlive() || MainMaterial->IsLiquid())
3463 && !game::IsInWilderness())
3464 {
3465 if(Eater->GetVirtualHead())
3466 Eater->GetVirtualHead()->SpillFluid(Eater, CreateBlood(Amount));
3467
3468 Eater->GetTorso()->SpillFluid(Eater, CreateBlood(Amount));
3469 }
3470 }
3471
IsValuable() const3472 truth corpse::IsValuable() const
3473 {
3474 for(int c = 0; c < Deceased->GetBodyParts(); ++c)
3475 {
3476 bodypart* BodyPart = Deceased->GetBodyPart(c);
3477
3478 if(BodyPart && BodyPart->IsValuable())
3479 return true;
3480 }
3481
3482 return false;
3483 }
3484
Necromancy(character * Necromancer)3485 truth corpse::Necromancy(character* Necromancer)
3486 {
3487 if(Necromancer && Necromancer->IsPlayer())
3488 game::DoEvilDeed(50);
3489
3490 character* Zombie = GetDeceased()->CreateZombie();
3491
3492 if(Zombie)
3493 {
3494 Zombie->ChangeTeam(Necromancer ? Necromancer->GetTeam() : game::GetTeam(MONSTER_TEAM));
3495 Zombie->PutToOrNear(GetPos());
3496 RemoveFromSlot();
3497 SendToHell();
3498
3499 if(Zombie->CanBeSeenByPlayer())
3500 ADD_MESSAGE("%s rises back to cursed undead life.", Zombie->CHAR_DESCRIPTION(INDEFINITE));
3501
3502 Zombie->SignalStepFrom(0);
3503 return true;
3504 }
3505 else
3506 {
3507 if(CanBeSeenByPlayer())
3508 ADD_MESSAGE("%s vibrates for some time.", CHAR_NAME(DEFINITE));
3509
3510 return false;
3511 }
3512 }
3513
GetOutlineAlpha(int Frame) const3514 alpha mysticfrogtorso::GetOutlineAlpha(int Frame) const
3515 {
3516 Frame &= 31;
3517 return Frame * (31 - Frame) >> 1;
3518 }
3519
GetOutlineColor(int Frame) const3520 col16 mysticfrogtorso::GetOutlineColor(int Frame) const
3521 {
3522 switch((Frame&127) >> 5)
3523 {
3524 case 0: return BLUE;
3525 case 1: return GREEN;
3526 case 2: return RED;
3527 case 3: return YELLOW;
3528 }
3529
3530 return TRANSPARENT_COLOR;
3531 }
3532
UpdateFlags()3533 void bodypart::UpdateFlags()
3534 {
3535 if((HP << 1) + HP < MaxHP || (HP == 1 && MaxHP != 1))
3536 Flags |= BADLY_HURT;
3537 else
3538 Flags &= ~BADLY_HURT;
3539
3540 if(Master->BodyPartIsStuck(GetBodyPartIndex()))
3541 Flags |= STUCK;
3542 else
3543 Flags &= ~STUCK;
3544 }
3545
SignalPossibleUsabilityChange()3546 void head::SignalPossibleUsabilityChange()
3547 {
3548 ulong OldFlags = Flags;
3549 UpdateFlags();
3550
3551 if(!Master->IsInitializing() && HP > 0
3552 && Flags & BADLY_HURT && !(OldFlags & BADLY_HURT))
3553 switch(RAND_N(8))
3554 {
3555 case 0:
3556 case 1:
3557 case 2: Master->LoseConsciousness(50 + RAND_N(50)); break;
3558 case 3:
3559 case 4:
3560 case 5: Master->BeginTemporaryState(CONFUSED, 500 + RAND_N(500)); break;
3561 case 6:
3562 if(Master->IsPlayer() && !RAND_N(3))
3563 {
3564 if(RAND_N(5))
3565 {
3566 ADD_MESSAGE("Your memory becomes blurred.");
3567 GetLevel()->Amnesia(25 + RAND_N(50));
3568 Master->EditExperience(INTELLIGENCE, -80, 1 << 13);
3569 game::SendLOSUpdateRequest();
3570 }
3571 else
3572 {
3573 ADD_MESSAGE("A terrible concussion garbles your consciousness.");
3574 Master->BeginTemporaryState(CONFUSED, 5000 + RAND_N(5000));
3575 Master->EditExperience(INTELLIGENCE, -100, 1 << 14);
3576 GetLevel()->BlurMemory();
3577 game::SendLOSUpdateRequest();
3578 }
3579 }
3580 else
3581 Master->EditExperience(INTELLIGENCE, -60, 1 << 12);
3582
3583 break;
3584 case 7:
3585 Master->ForgetRandomThing();
3586 }
3587 }
3588
SignalPossibleUsabilityChange()3589 void arm::SignalPossibleUsabilityChange()
3590 {
3591 ulong OldFlags = Flags;
3592 UpdateFlags();
3593
3594 if(Flags != OldFlags && !Master->IsInitializing())
3595 Master->CalculateBattleInfo();
3596 }
3597
SignalPossibleUsabilityChange()3598 void leg::SignalPossibleUsabilityChange()
3599 {
3600 ulong OldFlags = Flags;
3601 UpdateFlags();
3602
3603 if(Flags != OldFlags && !Master->IsInitializing())
3604 Master->CalculateBattleInfo();
3605 }
3606
IncreaseHP()3607 void bodypart::IncreaseHP()
3608 {
3609 ++HP;
3610 RemoveDamageIDs(1);
3611 SignalPossibleUsabilityChange();
3612 }
3613
FastRestoreHP()3614 void bodypart::FastRestoreHP()
3615 {
3616 HP = MaxHP;
3617 DamageID.clear();
3618 SignalPossibleUsabilityChange();
3619 }
3620
RestoreHP()3621 void bodypart::RestoreHP()
3622 {
3623 HP = MaxHP;
3624 DamageID.clear();
3625 SignalPossibleUsabilityChange();
3626 Master->CalculateHP();
3627 }
3628
SetIsUnique(truth What)3629 void bodypart::SetIsUnique(truth What)
3630 {
3631 if(What)
3632 Flags |= UNIQUE;
3633 else
3634 Flags &= ~UNIQUE;
3635 }
3636
SetIsInfectedByLeprosy(truth What)3637 void bodypart::SetIsInfectedByLeprosy(truth What)
3638 {
3639 MainMaterial->SetIsInfectedByLeprosy(What);
3640 }
3641
SetSparkleFlags(int What)3642 void bodypart::SetSparkleFlags(int What)
3643 {
3644 cint S = SPARKLING_B|SPARKLING_C|SPARKLING_D;
3645 Flags = (Flags & ~(S << BODYPART_SPARKLE_SHIFT)) | ((What & S) << BODYPART_SPARKLE_SHIFT);
3646 }
3647
IsAnimated() const3648 truth arm::IsAnimated() const
3649 {
3650 return (WieldedGraphicData.AnimationFrames > 1) || IsBurning();
3651 }
3652
SignalAnimationStateChange(truth WasAnimated)3653 void bodypart::SignalAnimationStateChange(truth WasAnimated)
3654 {
3655 if(WasAnimated)
3656 {
3657 for(int c = 0; c < GetSquaresUnder(); ++c)
3658 {
3659 square* Square = GetSquareUnder(c);
3660
3661 if(Square)
3662 Square->DecAnimatedEntities();
3663 }
3664 }
3665 else
3666 {
3667 for(int c = 0; c < GetSquaresUnder(); ++c)
3668 {
3669 square* Square = GetSquareUnder(c);
3670
3671 if(Square)
3672 Square->IncAnimatedEntities();
3673 }
3674 }
3675 }
3676
MaterialIsChangeable(ccharacter *) const3677 truth bodypart::MaterialIsChangeable(ccharacter*) const
3678 {
3679 return !Master || !Master->BodyPartIsVital(GetBodyPartIndex()) || UseMaterialAttributes();
3680 }
3681
AddAdjective(festring & String,truth Articled) const3682 truth bodypart::AddAdjective(festring& String, truth Articled) const
3683 {
3684 if(!Master)
3685 {
3686 if(Articled)
3687 String << "a ";
3688
3689 String << "severed ";
3690 return true;
3691 }
3692 else
3693 return false;
3694 }
3695
RemoveRust()3696 void bodypart::RemoveRust()
3697 {
3698 item::RemoveRust();
3699 RestoreHP();
3700 }
3701
RemoveBurns()3702 void bodypart::RemoveBurns()
3703 {
3704 item::RemoveBurns();
3705 RestoreHP();
3706 }
3707
GetFixPrice() const3708 long bodypart::GetFixPrice() const
3709 {
3710 return GetMaxHP() - GetHP() + GetMainMaterial()->GetRustLevel() * 25 + GetMainMaterial()->GetBurnLevel() * 25;
3711 }
3712
IsFixableBySmith(ccharacter *) const3713 truth bodypart::IsFixableBySmith(ccharacter*) const
3714 {
3715 return (GetMainMaterial()->GetCategoryFlags() & IS_METAL
3716 && (GetHP() < GetMaxHP() || IsRusted()));
3717 }
3718
IsFixableByTailor(ccharacter *) const3719 truth bodypart::IsFixableByTailor(ccharacter*) const
3720 {
3721 return (GetMainMaterial()->GetCategoryFlags() & CAN_BE_TAILORED
3722 && GetHP() < GetMaxHP());
3723 }
3724
Fix()3725 item* bodypart::Fix()
3726 {
3727 RestoreHP();
3728 return this;
3729 }
3730
SignalMaterialChange()3731 void bodypart::SignalMaterialChange()
3732 {
3733 if(Master)
3734 RestoreHP();
3735 }
3736
ShowMaterial() const3737 truth bodypart::ShowMaterial() const
3738 {
3739 return MainMaterial->GetConfig() != NormalMaterial;
3740 }
3741
GetMaterialColorD(int Frame) const3742 col16 lobhsetorso::GetMaterialColorD(int Frame) const
3743 {
3744 Frame &= 31;
3745 int Modifier = Frame * (31 - Frame);
3746 return MakeRGB16(220 - (Modifier >> 2), 220 - (Modifier >> 1), 0);
3747 }
3748
IsDestroyable(ccharacter *) const3749 truth bodypart::IsDestroyable(ccharacter*) const
3750 {
3751 return !Master || !Master->BodyPartIsVital(GetBodyPartIndex());
3752 }
3753
DamageTypeCanScar(int Type)3754 truth bodypart::DamageTypeCanScar(int Type)
3755 {
3756 return !(Type == POISON || Type == DRAIN || Type == PSI);
3757 }
3758
GenerateScar(int Damage,int Type)3759 void bodypart::GenerateScar(int Damage, int Type)
3760 {
3761 Scar.push_back(scar());
3762 scar& NewScar = Scar.back();
3763 NewScar.Severity = 1 + RAND_N(1 + 5 * Damage / GetMaxHP());
3764
3765 if(GetMaster()->IsPlayer())
3766 {
3767 int ScarColor = MakeShadeColor(GetMainMaterial()->GetColor());
3768 NewScar.PanelBitmap = igraph::GenerateScarBitmap(GetBodyPartIndex(),
3769 NewScar.Severity,
3770 ScarColor);
3771 ADD_MESSAGE("Your %s is scarred.", CHAR_NAME(UNARTICLED));
3772 }
3773 else
3774 NewScar.PanelBitmap = 0;
3775
3776 CalculateMaxHP();
3777 GetMaster()->CalculateMaxHP();
3778 GetMaster()->CalculateAttributeBonuses();
3779 CalculateAttackInfo();
3780 }
3781
DrawScars(cblitdata & B) const3782 void bodypart::DrawScars(cblitdata& B) const
3783 {
3784 for(size_t c = 0; c < Scar.size(); ++c)
3785 {
3786 if(!Scar[c].PanelBitmap)
3787 {
3788 int ScarColor = MakeShadeColor(GetMainMaterial()->GetColor());
3789 Scar[c].PanelBitmap = igraph::GenerateScarBitmap(GetBodyPartIndex(),
3790 Scar[c].Severity,
3791 ScarColor);
3792 }
3793
3794 Scar[c].PanelBitmap->NormalMaskedBlit(B);
3795 }
3796 }
3797
operator <<(outputfile & SaveFile,const scar & Scar)3798 outputfile& operator<<(outputfile& SaveFile, const scar& Scar)
3799 {
3800 SaveFile << Scar.Severity << Scar.PanelBitmap;
3801 return SaveFile;
3802 }
3803
operator >>(inputfile & SaveFile,scar & Scar)3804 inputfile& operator>>(inputfile& SaveFile, scar& Scar)
3805 {
3806 SaveFile >> Scar.Severity >> Scar.PanelBitmap;
3807 return SaveFile;
3808 }
3809
CalculateScarAttributePenalty(int Attribute) const3810 int bodypart::CalculateScarAttributePenalty(int Attribute) const
3811 {
3812 double DoubleAttribute = Attribute;
3813
3814 for(size_t c = 0; c < Scar.size(); ++c)
3815 DoubleAttribute *= (100. - Scar[c].Severity * 4) / 100;
3816
3817 return Min(Attribute - int(DoubleAttribute), Attribute - 1);
3818 }
3819
CalculateBurnAttributePenalty(int Attribute) const3820 int bodypart::CalculateBurnAttributePenalty(int Attribute) const
3821 {
3822 int BurnLevel = 0;
3823 double DoubleAttribute = Attribute;
3824
3825 if(MainMaterial)
3826 {
3827 BurnLevel = MainMaterial->GetBurnLevel();
3828 DoubleAttribute *= (1. - BurnLevel * 0.05);
3829 }
3830
3831 return BurnLevel ? Min(Attribute - int(DoubleAttribute), Attribute - 1) : 0;
3832 }
3833
~bodypart()3834 bodypart::~bodypart()
3835 {
3836 for(size_t c = 0; c < Scar.size(); ++c)
3837 delete Scar[c].PanelBitmap;
3838 }
3839
bodypart(const bodypart & B)3840 bodypart::bodypart(const bodypart& B)
3841 : mybase(B), OwnerDescription(B.OwnerDescription), Master(B.Master),
3842 CarriedWeight(B.CarriedWeight), BodyPartVolume(B.BodyPartVolume),
3843 BitmapPos(B.BitmapPos), ColorB(B.ColorB), ColorC(B.ColorC), ColorD(B.ColorD),
3844 SpecialFlags(B.SpecialFlags), HP(B.HP), MaxHP(B.MaxHP),
3845 BloodMaterial(B.BloodMaterial), NormalMaterial(B.NormalMaterial),
3846 SpillBloodCounter(B.SpillBloodCounter), WobbleData(B.WobbleData), Scar(B.Scar)
3847 {
3848 for(size_t c = 0; c < Scar.size(); ++c)
3849 if(Scar[c].PanelBitmap)
3850 Scar[c].PanelBitmap = new bitmap(Scar[c].PanelBitmap);
3851 }
3852
3853 /* Amount should be > 0 */
3854
RemoveDamageIDs(int Amount)3855 void bodypart::RemoveDamageIDs(int Amount)
3856 {
3857 /*while(Amount)
3858 {
3859 damageid& D = DamageID.front();
3860 int CurrentAmount = D.Amount;
3861
3862 if(Amount < CurrentAmount)
3863 {
3864 D.Amount -= Amount;
3865 Amount = 0;
3866 }
3867 else
3868 {
3869 DamageID.pop_front();
3870 Amount -= CurrentAmount;
3871 }
3872 }*/
3873 }
3874
3875 /* Amount should be > 0 */
3876
AddDamageID(int SrcID,int Amount)3877 void bodypart::AddDamageID(int SrcID, int Amount)
3878 {
3879 /*damageid D = { SrcID, Amount };
3880 DamageID.push_back(D);*/
3881 }
3882
GetCurrentSWeaponSkillBonus() const3883 int arm::GetCurrentSWeaponSkillBonus() const
3884 {
3885 return (*GetCurrentSWeaponSkill()
3886 ? (*GetCurrentSWeaponSkill())->GetBonus() : 1);
3887 }
3888
GetBitmapPos(int Frame) const3889 v2 battorso::GetBitmapPos(int Frame) const
3890 {
3891 v2 BasePos = torso::GetBitmapPos(Frame);
3892 Frame &= 0xF;
3893 return v2(BasePos.X + ((Frame &~ 3) << 2), BasePos.Y);
3894 }
3895
GetBitmapPos(int Frame) const3896 v2 spidertorso::GetBitmapPos(int Frame) const
3897 {
3898 v2 BasePos = torso::GetBitmapPos(Frame);
3899 Frame &= 0xF;
3900 return v2(BasePos.X + ((Frame &~ 7) << 1), BasePos.Y);
3901 }
3902
GetBitmapPos(int Frame) const3903 v2 snaketorso::GetBitmapPos(int Frame) const
3904 {
3905 v2 BasePos = torso::GetBitmapPos(Frame);
3906
3907 if(Frame<16)
3908 return v2(BasePos.X + ((Frame/2)%2)*TILE_SIZE, BasePos.Y);
3909 else
3910 if(Frame<24)
3911 return v2(BasePos.X + TILE_SIZE, BasePos.Y);
3912 return BasePos;
3913 }
3914
GetBitmapPos(int Frame) const3915 v2 magpietorso::GetBitmapPos(int Frame) const
3916 {
3917 v2 BasePos = torso::GetBitmapPos(Frame);
3918 Frame &= 0xF;
3919
3920 /**
3921 * GetClassAnimationFrames() is the total animation frames per second, so Frame is from 0 to 15 here
3922 * Magpie has 8 pictures, so it will draw the same picture for each 2 frames.
3923 * GetBitmapPos() method will be called only once and stored on the savegame file, therefore there is no need for speed.
3924 * TODO correct?
3925 */
3926 float fPicTot=8.0;
3927 float fDiv = GetClassAnimationFrames()/fPicTot; //each 2 frames
3928 int iPic=Frame/fDiv; DBG3(Frame,fDiv,iPic);
3929 return v2(BasePos.X + iPic*TILE_SIZE, BasePos.Y);
3930 }
3931
HasSadistWeapon() const3932 truth arm::HasSadistWeapon() const
3933 {
3934 item* Wielded = GetWielded();
3935 return Wielded && Wielded->IsSadistWeapon();
3936 }
3937
AddStateDescription(festring & Name,truth Articled) const3938 truth corpse::AddStateDescription(festring& Name, truth Articled) const
3939 {
3940 if(!Spoils())
3941 return false;
3942
3943 truth Hasted = true, Slowed = true;
3944
3945 for(int c = 0; c < GetDeceased()->GetBodyParts(); ++c)
3946 {
3947 bodypart* BodyPart = GetDeceased()->GetBodyPart(c);
3948
3949 if(BodyPart)
3950 {
3951 if(!(BodyPart->ItemFlags & HASTE))
3952 Hasted = false;
3953
3954 if(!(BodyPart->ItemFlags & SLOW))
3955 Slowed = false;
3956 }
3957 }
3958
3959 if((Hasted | Slowed) && Articled)
3960 Name << "a ";
3961
3962 if(Hasted)
3963 Name << "hasted ";
3964
3965 if(Slowed)
3966 Name << "slowed ";
3967
3968 return true;
3969 }
3970