3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
8 * See LICENSING which should be included
9 * along with this file for more details
13 /* Compiled through charsset.cpp */
15 cint
humanoid::DrawOrder
[] = { TORSO_INDEX
, GROIN_INDEX
, RIGHT_LEG_INDEX
, LEFT_LEG_INDEX
, RIGHT_ARM_INDEX
, LEFT_ARM_INDEX
, HEAD_INDEX
};
17 truth
humanoid::BodyPartIsVital(int I
) const { return I
== TORSO_INDEX
|| I
== HEAD_INDEX
|| I
== GROIN_INDEX
; }
18 truth
humanoid::BodyPartCanBeSevered(int I
) const { return I
!= TORSO_INDEX
&& I
!= GROIN_INDEX
; }
19 int humanoid::OpenMultiplier() const { return HasAUsableArm() ? 1 : 3; }
20 int humanoid::CloseMultiplier() const { return HasAUsableArm() ? 1 : 2; }
21 int humanoid::GetCarryingStrength() const { return Max(GetAttribute(LEG_STRENGTH
), 1) + CarryingBonus
; }
22 void humanoid::CalculateBodyParts() { BodyParts
= HUMANOID_BODYPARTS
; }
23 void humanoid::CalculateAllowedWeaponSkillCategories() { AllowedWeaponSkillCategories
= WEAPON_SKILL_CATEGORIES
; }
25 v2
farmer::GetHeadBitmapPos() const { return v2(96, (4 + (RAND() & 1)) << 4); }
26 v2
farmer::GetRightArmBitmapPos() const { return v2(64, (RAND() & 1) << 4); }
28 void guard::SetWayPoints(const fearray
<packv2
>& What
) { ArrayToVector(What
, WayPoints
); }
30 cchar
* oree::FirstPersonBiteVerb() const { return "vomit acidous blood at"; }
31 cchar
* oree::FirstPersonCriticalBiteVerb() const { return "vomit very acidous blood at"; }
32 cchar
* oree::ThirdPersonBiteVerb() const { return "vomits acidous blood at"; }
33 cchar
* oree::ThirdPersonCriticalBiteVerb() const { return "vomits very acidous blood at"; }
34 cchar
* oree::BiteNoun() const { return "liquid"; }
36 truth
skeleton::BodyPartIsVital(int I
) const { return I
== GROIN_INDEX
|| I
== TORSO_INDEX
; }
38 truth
communist::ShowClassDescription() const { return GetAssignedName() != "Ivan"; }
40 v2
housewife::GetHeadBitmapPos() const { return v2(112, (RAND() % 6) << 4); }
42 truth
zombie::BodyPartIsVital(int I
) const { return I
== GROIN_INDEX
|| I
== TORSO_INDEX
; }
43 festring
zombie::GetZombieDescription() const { return Description
; }
45 truth
angel::BodyPartIsVital(int I
) const { return I
== TORSO_INDEX
|| I
== HEAD_INDEX
; }
47 truth
genie::BodyPartIsVital(int I
) const { return I
== TORSO_INDEX
|| I
== HEAD_INDEX
; }
49 material
* golem::CreateBodyPartMaterial(int, sLong Volume
) const { return MAKE_MATERIAL(GetConfig(), Volume
); }
51 truth
sumowrestler::EquipmentIsAllowed(int I
) const { return I
== BELT_INDEX
; }
53 truth
ennerbeast::Hit(character
* Enemy
, v2
, int, int)
55 if(CheckIfTooScaredToHit(Enemy
))
59 ADD_MESSAGE("%s yells: UGH UGHAaaa!", CHAR_DESCRIPTION(DEFINITE
));
61 ADD_MESSAGE("%s yells: Uga Ugar Ugade Ugat!", CHAR_DESCRIPTION(DEFINITE
));
64 femath::CalculateEnvironmentRectangle(Rect
, GetLevel()->GetBorder(), GetPos(), 30);
66 for(int x
= Rect
.X1
; x
<= Rect
.X2
; ++x
)
67 for(int y
= Rect
.Y1
; y
<= Rect
.Y2
; ++y
)
69 int ScreamStrength
= int(70 / (hypot(GetPos().X
- x
, GetPos().Y
- y
) + 1));
73 character
* Char
= GetNearSquare(x
, y
)->GetCharacter();
75 if(Char
&& Char
!= this)
77 msgsystem::EnterBigMessageMode();
80 ADD_MESSAGE("You are hit by the horrible waves of high sound.");
81 else if(Char
->CanBeSeenByPlayer())
82 ADD_MESSAGE("%s is hit by the horrible waves of high sound.", Char
->CHAR_NAME(DEFINITE
));
84 Char
->ReceiveDamage(this, ScreamStrength
, SOUND
, ALL
, YOURSELF
, true);
85 Char
->CheckDeath(CONST_S("killed @bkp scream"), this);
86 msgsystem::LeaveBigMessageMode();
89 GetNearLSquare(x
, y
)->GetStack()->ReceiveDamage(this, ScreamStrength
, SOUND
);
94 EditAP(-1000000 / GetCWeaponSkill(BITE
)->GetBonus());
95 EditStamina(-1000, false);
99 void skeleton::CreateCorpse(lsquare
* Square
)
103 item
* Skull
= SevereBodyPart(HEAD_INDEX
, false, Square
->GetStack());
104 Square
->AddItem(Skull
);
107 int Amount
= 2 + (RAND() & 3);
109 for(int c
= 0; c
< Amount
; ++c
)
110 Square
->AddItem(bone::Spawn());
115 void humanoid::Save(outputfile
& SaveFile
) const
117 character::Save(SaveFile
);
118 SaveFile
<< SWeaponSkill
;
121 void humanoid::Load(inputfile
& SaveFile
)
123 character::Load(SaveFile
);
124 SaveFile
>> SWeaponSkill
;
126 if(GetRightWielded())
127 for(std::list
<sweaponskill
*>::iterator i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
128 if((*i
)->IsSkillOf(GetRightWielded()))
130 SetCurrentRightSWeaponSkill(*i
);
135 for(std::list
<sweaponskill
*>::iterator i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
136 if((*i
)->IsSkillOf(GetLeftWielded()))
138 SetCurrentLeftSWeaponSkill(*i
);
143 truth
golem::MoveRandomly()
147 Engrave(CONST_S("Golem Needs Master"));
152 return character::MoveRandomly();
155 void ennerbeast::GetAICommand()
157 SeekLeader(GetLeader());
159 if(StateIsActivated(PANIC
) || !(RAND() % 3))
160 Hit(0, ZERO_V2
, YOURSELF
);
162 if(CheckForEnemies(false, false, true))
165 if(FollowLeader(GetLeader()))
174 item
* humanoid::GetMainWielded() const
177 if(GetMainArm()->GetWielded())
178 return GetMainArm()->GetWielded();
180 if(GetSecondaryArm())
181 return GetSecondaryArm()->GetWielded();
185 if(GetSecondaryArm())
186 return GetSecondaryArm()->GetWielded();
191 item
* humanoid::GetSecondaryWielded() const
193 if(GetMainArm() && GetMainArm()->GetWielded() && GetSecondaryArm())
194 return GetSecondaryArm()->GetWielded();
199 truth
humanoid::Hit(character
* Enemy
, v2 HitPos
, int Direction
, int Flags
)
201 if(CheckIfTooScaredToHit(Enemy
))
206 if(!(Enemy
->IsMasochist() && GetRelation(Enemy
) == FRIEND
) && GetRelation(Enemy
) != HOSTILE
&& !game::TruthQuestion(CONST_S("This might cause a hostile reaction. Are you sure? [y/N]")))
209 else if(GetAttribute(WISDOM
) >= Enemy
->GetAttackWisdomLimit())
212 if(GetBurdenState() == OVER_LOADED
)
215 ADD_MESSAGE("You cannot fight while carrying so much.");
222 for(c
= 0, AttackStyles
= 0; c
< 8; ++c
)
223 if(GetAttackStyle() & (1 << c
))
226 int Chosen
= RAND() % AttackStyles
;
228 for(c
= 0, AttackStyles
= 0; c
< 8; ++c
)
229 if(GetAttackStyle() & (1 << c
) && AttackStyles
++ == Chosen
)
238 if(CanAttackWithAnArm() && (!(Flags
& SADIST_HIT
) || HasSadistWeapon()))
240 msgsystem::EnterBigMessageMode();
242 sLong FirstAPCost
= 0, SecondAPCost
= 0;
243 arm
* FirstArm
, * SecondArm
;
247 FirstArm
= GetRightArm();
248 SecondArm
= GetLeftArm();
252 FirstArm
= GetLeftArm();
253 SecondArm
= GetRightArm();
256 int Strength
= Max(GetAttribute(ARM_STRENGTH
), 1);
258 if(FirstArm
&& FirstArm
->GetDamage() && (!(Flags
& SADIST_HIT
) || FirstArm
->HasSadistWeapon()))
260 FirstAPCost
= FirstArm
->GetAPCost();
261 FirstArm
->Hit(Enemy
, HitPos
, Direction
, Flags
);
263 if(StateIsActivated(LEPROSY
) && !RAND_N(25 * GetAttribute(ENDURANCE
)))
264 DropBodyPart(FirstArm
->GetBodyPartIndex());
267 if(!GetAction() && IsEnabled() && Enemy
->IsEnabled() && SecondArm
&& SecondArm
->GetDamage() && (!(Flags
& SADIST_HIT
) || SecondArm
->HasSadistWeapon()))
269 SecondAPCost
= SecondArm
->GetAPCost();
270 SecondArm
->Hit(Enemy
, HitPos
, Direction
, Flags
);
272 if(StateIsActivated(LEPROSY
) && !RAND_N(25 * GetAttribute(ENDURANCE
)))
273 DropBodyPart(SecondArm
->GetBodyPartIndex());
277 EditAP(-Max(FirstAPCost
, SecondAPCost
));
278 EditStamina(-10000 / Strength
, false);
279 msgsystem::LeaveBigMessageMode();
283 if(HasTwoUsableLegs())
285 msgsystem::EnterBigMessageMode();
287 Kick(GetNearLSquare(HitPos
), Direction
, Flags
& SADIST_HIT
);
289 if(StateIsActivated(LEPROSY
) && !RAND_N(25 * GetAttribute(ENDURANCE
)))
290 DropBodyPart(RAND_2
? RIGHT_LEG_INDEX
: LEFT_LEG_INDEX
);
292 msgsystem::LeaveBigMessageMode();
298 msgsystem::EnterBigMessageMode();
300 Bite(Enemy
, HitPos
, Direction
, Flags
& SADIST_HIT
);
301 msgsystem::LeaveBigMessageMode();
306 ADD_MESSAGE("You are currently quite unable to damage anything.");
312 truth
humanoid::AddSpecialSkillInfo(felist
& List
) const
314 truth Something
= false;
316 if(CurrentRightSWeaponSkill
&& CurrentRightSWeaponSkill
->GetHits() / 100)
318 List
.AddEntry(CONST_S(""), LIGHT_GRAY
);
319 festring Buffer
= CONST_S("right accustomization");
321 Buffer
<< CurrentRightSWeaponSkill
->GetLevel();
323 Buffer
<< CurrentRightSWeaponSkill
->GetHits() / 100;
326 if(CurrentRightSWeaponSkill
->GetLevel() != 20)
327 Buffer
<< (CurrentRightSWeaponSkill
->GetLevelMap(CurrentRightSWeaponSkill
->GetLevel() + 1) - CurrentRightSWeaponSkill
->GetHits()) / 100;
332 int Bonus
= CurrentRightSWeaponSkill
->GetBonus();
333 Buffer
<< '+' << (Bonus
- 1000) / 10;
336 Buffer
<< '.' << Bonus
;
339 List
.AddEntry(Buffer
, WHITE
);
343 if(CurrentLeftSWeaponSkill
&& CurrentLeftSWeaponSkill
->GetHits() / 100)
346 List
.AddEntry(CONST_S(""), LIGHT_GRAY
);
348 festring Buffer
= CONST_S("left accustomization");
350 Buffer
<< CurrentLeftSWeaponSkill
->GetLevel();
352 Buffer
<< CurrentLeftSWeaponSkill
->GetHits() / 100;
355 if(CurrentLeftSWeaponSkill
->GetLevel() != 20)
356 Buffer
<< (CurrentLeftSWeaponSkill
->GetLevelMap(CurrentLeftSWeaponSkill
->GetLevel() + 1) - CurrentLeftSWeaponSkill
->GetHits()) / 100;
361 int Bonus
= CurrentLeftSWeaponSkill
->GetBonus();
362 Buffer
<< '+' << (Bonus
- 1000) / 10;
365 Buffer
<< '.' << Bonus
;
368 List
.AddEntry(Buffer
, WHITE
);
375 void priest::BeTalkedTo () {
376 if (GetRelation(PLAYER
) == HOSTILE
) {
377 ADD_MESSAGE("\"Sinner! My hands shall pour Dinive Wrath upon thee!\"");
380 for (int c
= 0; c
< PLAYER
->GetBodyParts(); ++c
) {
381 if (!PLAYER
->GetBodyPart(c
) && PLAYER
->CanCreateBodyPart(c
)) {
382 truth HasOld
= false;
383 for (std::list
<uLong
>::const_iterator i
= PLAYER
->GetOriginalBodyPartID(c
).begin(); i
!= PLAYER
->GetOriginalBodyPartID(c
).end(); ++i
) {
384 bodypart
*OldBodyPart
= static_cast<bodypart
*>(PLAYER
->SearchForItem(*i
));
387 sLong Price
= GetConfig() == VALPURUS
? 50 : 10;
388 if (PLAYER
->GetMoney() >= Price
) {
389 if (!OldBodyPart
->CanRegenerate())
390 ADD_MESSAGE("\"Sorry, I cannot put back bodyparts made of %s, not even your severed %s.\"", OldBodyPart
->GetMainMaterial()->GetName(false, false).CStr(), PLAYER
->GetBodyPartName(c
).CStr());
392 ADD_MESSAGE("\"I could put your old %s back in exchange for %d gold.\"", PLAYER
->GetBodyPartName(c
).CStr(), Price
);
393 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
394 OldBodyPart
->SetHP(1);
395 PLAYER
->SetMoney(PLAYER
->GetMoney()-Price
);
396 SetMoney(GetMoney()+Price
);
397 OldBodyPart
->RemoveFromSlot();
398 PLAYER
->AttachBodyPart(OldBodyPart
);
403 ADD_MESSAGE("\"Your %s is severed. Help yourself and get %dgp and I'll help you too.\"", PLAYER
->GetBodyPartName(c
).CStr(), Price
);
407 sLong Price
= GetConfig() == VALPURUS
? 100 : 20;
408 if (PLAYER
->GetMoney() >= Price
) {
410 ADD_MESSAGE("\"I could still summon up a new one for %d gold.\"", Price
);
412 ADD_MESSAGE("\"Since you don't seem to have your original %s with you, I could summon up a new one for %d gold.\"", PLAYER
->GetBodyPartName(c
).CStr(), Price
);
413 if (game::TruthQuestion(CONST_S("Agreed? [y/N]"))) {
414 PLAYER
->SetMoney(PLAYER
->GetMoney()-Price
);
415 SetMoney(GetMoney()+Price
);
416 PLAYER
->CreateBodyPart(c
);
417 PLAYER
->GetBodyPart(c
)->SetHP(1);
420 } else if (!HasOld
) {
421 ADD_MESSAGE("\"You don't have your original %s with you. I could create you a new one, but my Divine Employer is not a communist and you need %dgp first.\"", PLAYER
->GetBodyPartName(c
).CStr(), Price
);
425 if (PLAYER
->TemporaryStateIsActivated(POISONED
)) {
426 sLong Price
= GetConfig() == VALPURUS
? 25 : 5;
427 if (PLAYER
->GetMoney() >= Price
) {
428 ADD_MESSAGE("\"You seem to be rather ill. I could give you a small dose of antidote for %d gold pieces.\"", Price
);
429 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
430 ADD_MESSAGE("You feel better.");
431 PLAYER
->DeActivateTemporaryState(POISONED
);
432 PLAYER
->SetMoney(PLAYER
->GetMoney()-Price
);
433 SetMoney(GetMoney()+Price
);
437 ADD_MESSAGE("\"You seem to be rather ill. Get %d gold pieces and I'll fix that.\"", Price
);
440 if (PLAYER
->TemporaryStateIsActivated(LEPROSY
)) {
441 sLong Price
= GetConfig() == VALPURUS
? 100 : 20;
442 if (PLAYER
->GetMoney() >= Price
) {
443 ADD_MESSAGE("\"You seem to have contracted the vile disease of leprosy. I could give you a small dose of medicince for %d gold pieces.\"", Price
);
444 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
445 ADD_MESSAGE("You feel better.");
446 PLAYER
->DeActivateTemporaryState(LEPROSY
);
447 PLAYER
->SetMoney(PLAYER
->GetMoney()-Price
);
448 SetMoney(GetMoney()+Price
);
452 ADD_MESSAGE("\"You seem to be falling apart. Get %d gold pieces and I'll fix that.\"", Price
);
455 if (PLAYER
->TemporaryStateIsActivated(LYCANTHROPY
)) {
456 sLong Price
= GetConfig() == VALPURUS
? 100 : 20;
457 if (PLAYER
->GetMoney() >= Price
) {
458 ADD_MESSAGE("\"You seem to be turning into a werewolf quite frequently. Well, everyone has right to little secret habits, but if you wish to donate %dgp to %s, maybe I could pray %s to remove the canine blood from your veins, just so you don't scare our blessed youth.\"", Price
, GetMasterGod()->GetName(), GetMasterGod()->GetObjectPronoun());
459 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
460 ADD_MESSAGE("You feel better.");
461 PLAYER
->DeActivateTemporaryState(LYCANTHROPY
);
462 PLAYER
->SetMoney(PLAYER
->GetMoney()-Price
);
463 SetMoney(GetMoney()+Price
);
467 ADD_MESSAGE("\"You seem to be lycanthropic. I might be able to do something for that but I need %dgp for the ritual materials first.\"", Price
);
470 humanoid::BeTalkedTo();
474 void skeleton::BeTalkedTo()
477 humanoid::BeTalkedTo();
479 ADD_MESSAGE("The headless %s remains silent.", PLAYER
->CHAR_DESCRIPTION(UNARTICLED
));
482 void communist::BeTalkedTo()
484 if(GetRelation(PLAYER
) != HOSTILE
485 && GetTeam() != PLAYER
->GetTeam()
486 && PLAYER
->GetRelativeDanger(this, true) > 0.1)
488 ADD_MESSAGE("%s seems to be very friendly. \"%s make good communist. %s go with %s!\"", CHAR_DESCRIPTION(DEFINITE
), PLAYER
->GetAssignedName().CStr(), CHAR_NAME(UNARTICLED
), PLAYER
->GetAssignedName().CStr());
490 for(std::list
<character
*>::const_iterator i
= GetTeam()->GetMember().begin(); i
!= GetTeam()->GetMember().end();)
493 character
* Char
= *i
++;
494 Char
->ChangeTeam(PLAYER
->GetTeam());
499 ChangeTeam(PLAYER
->GetTeam());
501 else if(GetTeam() != PLAYER
->GetTeam() && !(RAND() % 5))
502 ADD_MESSAGE("\"You weak. Learn killing and come back.\"");
504 character::BeTalkedTo();
507 void hunter::BeTalkedTo()
509 if(GetRelation(PLAYER
) != HOSTILE
&& GetMainWielded() && !(RAND() % 10))
510 ADD_MESSAGE("\"This is my %s. There are many like it but this one is mine. My %s is my best friend.\"", GetMainWielded()->CHAR_NAME(UNARTICLED
), GetMainWielded()->CHAR_NAME(UNARTICLED
));
512 character::BeTalkedTo();
515 void slave::BeTalkedTo()
517 if(GetRelation(PLAYER
) == HOSTILE
)
519 ADD_MESSAGE("\"Yikes!\"");
523 room
* Room
= GetHomeRoom();
525 if(Room
&& Room
->MasterIsActive())
527 character
* Master
= Room
->GetMaster();
529 if(PLAYER
->GetMoney() >= 50)
531 ADD_MESSAGE("%s talks: \"Do you want to buy me? 50 gold pieces. I work very hard.\"", CHAR_DESCRIPTION(DEFINITE
));
533 if(game::TruthQuestion(CONST_S("Do you want to buy him? [y/N]")))
535 PLAYER
->SetMoney(PLAYER
->GetMoney() - 50);
536 Master
->SetMoney(Master
->GetMoney() + 50);
537 ChangeTeam(PLAYER
->GetTeam());
542 ADD_MESSAGE("\"Don't touch me! Master doesn't want people to touch sale items. I'm worth 50 gold pieces, you know!\"");
547 if(GetTeam() == PLAYER
->GetTeam())
549 if((PLAYER
->GetMainWielded() && PLAYER
->GetMainWielded()->IsWhip()) || (PLAYER
->GetSecondaryWielded() && PLAYER
->GetSecondaryWielded()->IsWhip()))
550 ADD_MESSAGE("\"Don't hit me! I work! I obey! I don't think!\"");
552 character::BeTalkedTo();
555 ADD_MESSAGE("\"I'm free! Rejoice!\"");
558 void slave::GetAICommand()
560 SeekLeader(GetLeader());
562 if(CheckForEnemies(true, true, true))
565 if(CheckForUsefulItemsOnGround())
568 if(FollowLeader(GetLeader()))
574 if(!GetHomeRoom() || !GetHomeRoom()->MasterIsActive())
581 else if(MoveTowardsHomePos())
587 void librarian::BeTalkedTo()
589 if(GetRelation(PLAYER
) == HOSTILE
)
591 ADD_MESSAGE("\"The pen is mightier than the sword! Fall, unlearned one!\"");
597 switch(RandomizeReply(Said
, 12))
600 if(game::GetPetrus() && !game::GetStoryState())
601 ADD_MESSAGE("\"Thou shouldst visit Petrus if thou art in need of further adventures.\"");
603 ADD_MESSAGE("\"They say a wand of polymorph hath dozens of uses.\"");
607 if(game::GetPetrus() && game::GetStoryState() == 1)
608 ADD_MESSAGE("\"Thou art going to fight Elpuri? Beware! It is a powerful enemy. Other monsters are very vulnerable if surrounded by thy party, but not that beast, for it may slay a horde of thy friends at once with its horrendous tail attack.\"");
610 ADD_MESSAGE("\"Thou shalt remember: Scientia est potentia.\"");
614 if(game::GetPetrus() && game::GetStoryState() == 1)
615 ADD_MESSAGE("\"Elpuri the Dark Frog abhors light and resides in a level of eternal darkness.\"");
617 ADD_MESSAGE("\"Shh! Thou shalt be silent in the library.\"");
621 if(game::GetPetrus() && game::GetStoryState() == 1)
622 ADD_MESSAGE("\"Elpuri's attacks are so strong that they may shatter many of thy precious items.\"");
624 ADD_MESSAGE("\"Dost thou not smell all the knowledge floating around here?\"");
628 ADD_MESSAGE("\"It is said that Loricatus, the god of smithing, can upgrade thy weapons' materials.\"");
631 if(game::GetPetrus() && game::GetStoryState() == 1)
632 ADD_MESSAGE("\"The Shirt of the Golden Eagle is a legendary artifact. Thou canst not find a better armor.\"");
634 ADD_MESSAGE("\"In this book they talk about Mortifer, the great chaos god. He hates us mortals more than anything and will respond only to Champions of Evil.\"");
638 ADD_MESSAGE("\"Attnam is traditionally ruled by the high priest of the Great Frog. He holds the Shirt of the Golden Eagle and has always killed his predecessor.\"");
641 ADD_MESSAGE("\"They say thou shouldst keep all the artifacts thou findst. They shall make thee famous after thy retirement.\"");
644 ADD_MESSAGE("\"If thou wilt ever encounter an enner beast, know this: It is a horrible foe. It may shatter thy items and armor with its scream that penetrates iron and stone. Thou shouldst not engage it in melee but rather kill it from afar.\"");
647 if(game::GetPetrus() && game::GetStoryState() == 1)
648 ADD_MESSAGE("\"Thou art not alone in thy attempt to defeat Elpuri. A brave adventurer called Ivan also diveth into its cave not long ago.\"");
650 ADD_MESSAGE("\"It is said that chaotic gods offer great power to their followers. But thou must remember: unlike lawfuls, they shall not help thee when things go bad.\"");
654 ADD_MESSAGE("\"If a man cannot choose, he ceases to be a man.\"");
657 ADD_MESSAGE("%s sighs: \"The censorship laws in this town are really too strict...\"", CHAR_DESCRIPTION(DEFINITE
));
662 truth
communist::MoveRandomly()
664 switch(RAND() % 1000)
667 if(CanBeSeenByPlayer())
668 ADD_MESSAGE("%s engraves something to the ground.", CHAR_NAME(UNARTICLED
));
670 Engrave(CONST_S("The bourgeois is a bourgeois -- for the benefit of the working class."));
673 if(CanBeSeenByPlayer())
674 ADD_MESSAGE("%s engraves something to the ground.", CHAR_NAME(UNARTICLED
));
676 Engrave(CONST_S("Proletarians of all countries, unite!"));
679 if(CanBeSeenByPlayer())
680 ADD_MESSAGE("%s engraves something to the ground.", CHAR_NAME(UNARTICLED
));
682 Engrave(CONST_S("Capital is therefore not only personal; it is a social power."));
685 return character::MoveRandomly();
689 void zombie::BeTalkedTo()
691 if(GetRelation(PLAYER
) == HOSTILE
&& PLAYER
->GetAttribute(INTELLIGENCE
) > 5)
696 ADD_MESSAGE("\"Need brain!!\"");
698 ADD_MESSAGE("\"Need head with brain!!\"");
701 ADD_MESSAGE("\"Redrum! Redrum! Redrum!\"");
704 ADD_MESSAGE("\"Need brain but you too stoopid!\"");
707 void angel::Save(outputfile
& SaveFile
) const
709 humanoid::Save(SaveFile
);
710 SaveFile
<< LastHealed
;
713 void angel::Load(inputfile
& SaveFile
)
715 humanoid::Load(SaveFile
);
716 SaveFile
>> LastHealed
;
719 void angel::CreateInitialEquipment(int SpecialFlags
)
721 humanoid::CreateInitialEquipment(SpecialFlags
);
722 GetStack()->AddItem(holybook::Spawn(GetConfig(), SpecialFlags
));
726 switch(GetMasterGod()->GetBasicAlignment())
729 Equipment
= bodyarmor::Spawn(PLATE_MAIL
, SpecialFlags
|NO_MATERIALS
);
730 Equipment
->InitMaterials(MAKE_MATERIAL(ANGEL_HAIR
), !(SpecialFlags
& NO_PIC_UPDATE
));
731 Equipment
->SetEnchantment(1);
732 SetBodyArmor(Equipment
);
733 Weapon
= meleeweapon::Spawn(LONG_SWORD
, SpecialFlags
|NO_MATERIALS
);
734 Weapon
->InitMaterials(MAKE_MATERIAL(MITHRIL
), MAKE_MATERIAL(MITHRIL
), !(SpecialFlags
& NO_PIC_UPDATE
));
735 Weapon
->SetEnchantment(2);
736 SetRightWielded(Weapon
);
737 Equipment
= shield::Spawn(0, SpecialFlags
|NO_MATERIALS
);
738 Equipment
->InitMaterials(MAKE_MATERIAL(MITHRIL
), !(SpecialFlags
& NO_PIC_UPDATE
));
739 Equipment
->SetEnchantment(2);
740 SetLeftWielded(Equipment
);
741 GetCWeaponSkill(LARGE_SWORDS
)->AddHit(20000);
742 GetCWeaponSkill(SHIELDS
)->AddHit(50000);
743 GetCurrentRightSWeaponSkill()->AddHit(20000);
744 GetCurrentLeftSWeaponSkill()->AddHit(20000);
745 GetRightArm()->SetDexterity(40);
746 GetLeftArm()->SetDexterity(40);
749 Equipment
= cloak::Spawn(0, SpecialFlags
|NO_MATERIALS
);
750 Equipment
->InitMaterials(MAKE_MATERIAL(ANGEL_HAIR
), !(SpecialFlags
& NO_PIC_UPDATE
));
751 Equipment
->SetEnchantment(1);
753 Weapon
= meleeweapon::Spawn(WAR_HAMMER
, SpecialFlags
|NO_MATERIALS
);
754 Weapon
->InitMaterials(MAKE_MATERIAL(MITHRIL
), MAKE_MATERIAL(TEAK_WOOD
), !(SpecialFlags
& NO_PIC_UPDATE
));
755 Weapon
->SetEnchantment(2);
756 SetRightWielded(Weapon
);
757 Weapon
= meleeweapon::Spawn(WAR_HAMMER
, SpecialFlags
|NO_MATERIALS
);
758 Weapon
->InitMaterials(MAKE_MATERIAL(MITHRIL
), MAKE_MATERIAL(TEAK_WOOD
), !(SpecialFlags
& NO_PIC_UPDATE
));
759 Weapon
->SetEnchantment(2);
760 SetLeftWielded(Weapon
);
761 GetCWeaponSkill(BLUNT_WEAPONS
)->AddHit(50000);
762 GetCurrentRightSWeaponSkill()->AddHit(20000);
763 GetCurrentLeftSWeaponSkill()->AddHit(20000);
767 Weapon
= meleeweapon::Spawn(HALBERD
, SpecialFlags
|NO_MATERIALS
);
768 Weapon
->InitMaterials(MAKE_MATERIAL(MITHRIL
), MAKE_MATERIAL(EBONY_WOOD
), !(SpecialFlags
& NO_PIC_UPDATE
));
769 Weapon
->SetEnchantment(2);
770 SetRightWielded(Weapon
);
771 Equipment
= gauntlet::Spawn(0, SpecialFlags
|NO_MATERIALS
);
772 Equipment
->InitMaterials(MAKE_MATERIAL(ANGEL_HAIR
), !(SpecialFlags
& NO_PIC_UPDATE
));
773 Equipment
->SetEnchantment(1);
774 SetRightGauntlet(Equipment
);
775 Equipment
= gauntlet::Spawn(0, SpecialFlags
|NO_MATERIALS
);
776 Equipment
->InitMaterials(MAKE_MATERIAL(ANGEL_HAIR
), !(SpecialFlags
& NO_PIC_UPDATE
));
777 Equipment
->SetEnchantment(1);
778 SetLeftGauntlet(Equipment
);
779 GetCWeaponSkill(POLE_ARMS
)->AddHit(100000);
780 GetCurrentRightSWeaponSkill()->AddHit(100000);
781 GetRightArm()->SetStrength(40);
782 GetLeftArm()->SetStrength(40);
786 void kamikazedwarf::CreateInitialEquipment(int SpecialFlags
)
788 humanoid::CreateInitialEquipment(SpecialFlags
);
789 SetRightWielded(holybook::Spawn(GetConfig(), SpecialFlags
));
790 GetCWeaponSkill(UNCATEGORIZED
)->AddHit(GetWSkillHits());
791 GetCurrentRightSWeaponSkill()->AddHit(GetWSkillHits());
794 truth
kamikazedwarf::Hit(character
* Enemy
, v2 HitPos
, int Direction
, int Flags
)
798 itemvector KamikazeWeapon
;
799 sortdata
SortData(KamikazeWeapon
, this, false, &item::IsKamikazeWeapon
);
800 SortAllItems(SortData
);
802 if(!KamikazeWeapon
.empty())
804 if(IsElite() && RAND() & 1)
805 ADD_MESSAGE("%s shouts: \"This time I won't fail, O Great %s!\"", CHAR_DESCRIPTION(DEFINITE
), GetMasterGod()->GetName());
807 ADD_MESSAGE("%s shouts: \"For %s!\"", CHAR_DESCRIPTION(DEFINITE
), GetMasterGod()->GetName());
809 ADD_MESSAGE("%s screams: \"%s, here I come!\"", CHAR_DESCRIPTION(DEFINITE
), GetMasterGod()->GetName());
811 if(KamikazeWeapon
[RAND_N(KamikazeWeapon
.size())]->Apply(this))
816 return humanoid::Hit(Enemy
, HitPos
, Direction
, Flags
);
819 void kamikazedwarf::GetAICommand()
831 character::GetAICommand();
836 void axethrowerdwarf::CreateInitialEquipment (int SpecialFlags
) {
837 SetRightWielded(meleeweapon::Spawn(AXE
, SpecialFlags
));
838 SetLeftWielded(meleeweapon::Spawn(AXE
, SpecialFlags
));
839 for (int k
= 0; k
< 6; ++k
) GetStack()->AddItem(meleeweapon::Spawn(AXE
));
840 GetStack()->AddItem(lantern::Spawn());
841 GetCWeaponSkill(AXES
)->AddHit(GetWSkillHits());
842 GetCurrentRightSWeaponSkill()->AddHit(GetWSkillHits());
846 void axethrowerdwarf::GetAICommand () {
847 if (CheckThrowItemOpportunity()) return;
848 character::GetAICommand();
852 v2
axethrowerdwarf::GetDrawDisplacement (int j
) const {
853 static v2 DrawDisplacement
[] = { v2(0, 0), v2(0, 1), v2(0, -1), v2(0, -1), v2(0, -1), v2(0, 0), v2(0, 0) };
854 return DrawDisplacement
[j
];
858 col16
axethrowerdwarf::GetTorsoMainColor () const {
859 return GetMasterGod()->GetColor();
863 col16
axethrowerdwarf::GetGauntletColor () const {
864 return GetMasterGod()->GetColor();
868 col16
axethrowerdwarf::GetLegMainColor () const {
869 return GetMasterGod()->GetColor();
873 truth
humanoid::CheckThrowItemOpportunity () {
874 if(!HasAUsableArm()) return false;
875 return character::CheckThrowItemOpportunity();
879 int humanoid::GetSize() const
884 Size
+= GetHead()->GetSize();
887 Size
+= GetTorso()->GetSize();
889 leg
* RightLeg
= GetRightLeg();
890 leg
* LeftLeg
= GetLeftLeg();
892 if(LeftLeg
&& RightLeg
)
893 Size
+= Max(LeftLeg
->GetSize(), RightLeg
->GetSize());
895 Size
+= LeftLeg
->GetSize();
897 Size
+= RightLeg
->GetSize();
902 sLong
humanoid::GetBodyPartSize(int I
, int TotalSize
) const
906 case HEAD_INDEX
: return 20;
907 case TORSO_INDEX
: return ((TotalSize
- 20) << 1) / 5;
908 case RIGHT_ARM_INDEX
:
909 case LEFT_ARM_INDEX
: return (TotalSize
- 20) * 3 / 5;
910 case GROIN_INDEX
: return (TotalSize
- 20) / 3;
911 case RIGHT_LEG_INDEX
:
912 case LEFT_LEG_INDEX
: return (TotalSize
- 20) * 3 / 5;
915 ABORT("Illegal humanoid bodypart size request!");
919 sLong
humanoid::GetBodyPartVolume(int I
) const
923 case HEAD_INDEX
: return 4000;
924 case TORSO_INDEX
: return (GetTotalVolume() - 4000) * 13 / 30;
925 case RIGHT_ARM_INDEX
:
926 case LEFT_ARM_INDEX
: return (GetTotalVolume() - 4000) / 10;
927 case GROIN_INDEX
: return (GetTotalVolume() - 4000) / 10;
928 case RIGHT_LEG_INDEX
:
929 case LEFT_LEG_INDEX
: return ((GetTotalVolume() - 4000) << 1) / 15;
932 ABORT("Illegal humanoid bodypart volume request!");
936 bodypart
* humanoid::MakeBodyPart(int I
) const
940 case TORSO_INDEX
: return humanoidtorso::Spawn(0, NO_MATERIALS
);
941 case HEAD_INDEX
: return head::Spawn(0, NO_MATERIALS
);
942 case RIGHT_ARM_INDEX
: return rightarm::Spawn(0, NO_MATERIALS
);
943 case LEFT_ARM_INDEX
: return leftarm::Spawn(0, NO_MATERIALS
);
944 case GROIN_INDEX
: return groin::Spawn(0, NO_MATERIALS
);
945 case RIGHT_LEG_INDEX
: return rightleg::Spawn(0, NO_MATERIALS
);
946 case LEFT_LEG_INDEX
: return leftleg::Spawn(0, NO_MATERIALS
);
949 ABORT("Weird bodypart to make for a humanoid. It must be your fault!");
953 truth
humanoid::ReceiveDamage(character
* Damager
, int Damage
, int Type
, int TargetFlags
, int Direction
, truth Divide
, truth PenetrateArmor
, truth Critical
, truth ShowMsg
)
955 int ChooseFrom
[MAX_BODYPARTS
], BodyParts
= 0;
957 if(TargetFlags
& RIGHT_ARM
&& GetRightArm())
958 ChooseFrom
[BodyParts
++] = 2;
960 if(TargetFlags
& LEFT_ARM
&& GetLeftArm())
961 ChooseFrom
[BodyParts
++] = 3;
963 if(TargetFlags
& RIGHT_LEG
&& GetRightLeg())
964 ChooseFrom
[BodyParts
++] = 5;
966 if(TargetFlags
& LEFT_LEG
&& GetLeftLeg())
967 ChooseFrom
[BodyParts
++] = 6;
969 if(TargetFlags
& HEAD
&& GetHead())
970 ChooseFrom
[BodyParts
++] = 1;
972 if(TargetFlags
& TORSO
&& GetTorso())
973 ChooseFrom
[BodyParts
++] = 0;
975 if(TargetFlags
& GROIN
&& GetGroin())
976 ChooseFrom
[BodyParts
++] = 4;
981 truth Affected
= false;
986 sLong TotalVolume
= 0;
988 for(c
= 0; c
< BodyParts
; ++c
)
989 TotalVolume
+= GetBodyPart(ChooseFrom
[c
])->GetBodyPartVolume();
991 for(c
= 0; c
< BodyParts
; ++c
)
992 if(ReceiveBodyPartDamage(Damager
, sLong(Damage
) * GetBodyPart(ChooseFrom
[c
])->GetBodyPartVolume() / TotalVolume
, Type
, ChooseFrom
[c
], Direction
, PenetrateArmor
, Critical
, false))
997 sLong Possibility
[MAX_BODYPARTS
], PossibilitySum
= 0;
1000 for(int c
= 0; c
< BodyParts
; ++c
)
1001 PossibilitySum
+= Possibility
[Index
++] = GetBodyPart(ChooseFrom
[c
])->GetBodyPartVolume();
1003 Index
= femath::WeightedRand(Possibility
, PossibilitySum
);
1004 Affected
= ReceiveBodyPartDamage(Damager
, Damage
, Type
, ChooseFrom
[Index
], Direction
, PenetrateArmor
, Critical
, false);
1007 if(!Affected
&& ShowMsg
)
1010 ADD_MESSAGE("You are not hurt.");
1011 else if(CanBeSeenByPlayer())
1012 ADD_MESSAGE("%s is not hurt.", GetPersonalPronoun().CStr());
1015 if(DamageTypeAffectsInventory(Type
))
1017 for(int c
= 0; c
< GetEquipments(); ++c
)
1019 item
* Equipment
= GetEquipment(c
);
1022 Equipment
->ReceiveDamage(Damager
, Damage
, Type
);
1025 GetStack()->ReceiveDamage(Damager
, Damage
, Type
);
1031 arm
* humanoid::GetMainArm() const
1033 return GetRightArm() ? GetRightArm() : GetLeftArm();
1036 arm
* humanoid::GetSecondaryArm() const
1038 return GetRightArm() ? GetLeftArm() : 0;
1041 cchar
* humanoid::GetEquipmentName(int I
) const // convert to array
1045 case HELMET_INDEX
: return "helmet";
1046 case AMULET_INDEX
: return "amulet";
1047 case CLOAK_INDEX
: return "cloak";
1048 case BODY_ARMOR_INDEX
: return "body armor";
1049 case BELT_INDEX
: return "belt";
1050 case RIGHT_WIELDED_INDEX
: return "right hand wielded";
1051 case LEFT_WIELDED_INDEX
: return "left hand wielded";
1052 case RIGHT_RING_INDEX
: return "right ring";
1053 case LEFT_RING_INDEX
: return "left ring";
1054 case RIGHT_GAUNTLET_INDEX
: return "right gauntlet";
1055 case LEFT_GAUNTLET_INDEX
: return "left gauntlet";
1056 case RIGHT_BOOT_INDEX
: return "right boot";
1057 case LEFT_BOOT_INDEX
: return "left boot";
1060 return "forbidden piece of cloth";
1063 sorter
humanoid::EquipmentSorter(int I
) const
1067 case HELMET_INDEX
: return &item::IsHelmet
;
1068 case AMULET_INDEX
: return &item::IsAmulet
;
1069 case CLOAK_INDEX
: return &item::IsCloak
;
1070 case BODY_ARMOR_INDEX
: return &item::IsBodyArmor
;
1071 case BELT_INDEX
: return &item::IsBelt
;
1072 case RIGHT_WIELDED_INDEX
:
1073 case LEFT_WIELDED_INDEX
: return 0;
1074 case RIGHT_RING_INDEX
:
1075 case LEFT_RING_INDEX
: return &item::IsRing
;
1076 case RIGHT_GAUNTLET_INDEX
:
1077 case LEFT_GAUNTLET_INDEX
: return &item::IsGauntlet
;
1078 case RIGHT_BOOT_INDEX
:
1079 case LEFT_BOOT_INDEX
: return &item::IsBoot
;
1085 bodypart
* humanoid::GetBodyPartOfEquipment(int I
) const
1093 case BODY_ARMOR_INDEX
:
1096 case RIGHT_WIELDED_INDEX
:
1097 case RIGHT_RING_INDEX
:
1098 case RIGHT_GAUNTLET_INDEX
:
1099 return GetRightArm();
1100 case LEFT_WIELDED_INDEX
:
1101 case LEFT_RING_INDEX
:
1102 case LEFT_GAUNTLET_INDEX
:
1103 return GetLeftArm();
1104 case RIGHT_BOOT_INDEX
:
1105 return GetRightLeg();
1106 case LEFT_BOOT_INDEX
:
1107 return GetLeftLeg();
1113 item
* humanoid::GetEquipment(int I
) const
1117 case HELMET_INDEX
: return GetHelmet();
1118 case AMULET_INDEX
: return GetAmulet();
1119 case CLOAK_INDEX
: return GetCloak();
1120 case BODY_ARMOR_INDEX
: return GetBodyArmor();
1121 case BELT_INDEX
: return GetBelt();
1122 case RIGHT_WIELDED_INDEX
: return GetRightWielded();
1123 case LEFT_WIELDED_INDEX
: return GetLeftWielded();
1124 case RIGHT_RING_INDEX
: return GetRightRing();
1125 case LEFT_RING_INDEX
: return GetLeftRing();
1126 case RIGHT_GAUNTLET_INDEX
: return GetRightGauntlet();
1127 case LEFT_GAUNTLET_INDEX
: return GetLeftGauntlet();
1128 case RIGHT_BOOT_INDEX
: return GetRightBoot();
1129 case LEFT_BOOT_INDEX
: return GetLeftBoot();
1135 void humanoid::SetEquipment(int I
, item
* What
)
1139 case HELMET_INDEX
: SetHelmet(What
); break;
1140 case AMULET_INDEX
: SetAmulet(What
); break;
1141 case CLOAK_INDEX
: SetCloak(What
); break;
1142 case BODY_ARMOR_INDEX
: SetBodyArmor(What
); break;
1143 case BELT_INDEX
: SetBelt(What
); break;
1144 case RIGHT_WIELDED_INDEX
: SetRightWielded(What
); break;
1145 case LEFT_WIELDED_INDEX
: SetLeftWielded(What
); break;
1146 case RIGHT_RING_INDEX
: SetRightRing(What
); break;
1147 case LEFT_RING_INDEX
: SetLeftRing(What
); break;
1148 case RIGHT_GAUNTLET_INDEX
: SetRightGauntlet(What
); break;
1149 case LEFT_GAUNTLET_INDEX
: SetLeftGauntlet(What
); break;
1150 case RIGHT_BOOT_INDEX
: SetRightBoot(What
); break;
1151 case LEFT_BOOT_INDEX
: SetLeftBoot(What
); break;
1155 void humanoid::SwitchToDig(item
* DigItem
, v2 Square
)
1157 dig
* Dig
= dig::Spawn(this);
1161 item
* Item
= GetRightArm()->GetWielded();
1163 if(Item
&& Item
!= DigItem
)
1165 Dig
->SetRightBackupID(GetRightArm()->GetWielded()->GetID());
1166 GetRightArm()->GetWielded()->MoveTo(GetStack());
1172 item
* Item
= GetLeftArm()->GetWielded();
1174 if(Item
&& Item
!= DigItem
)
1176 Dig
->SetLeftBackupID(GetLeftArm()->GetWielded()->GetID());
1177 GetLeftArm()->GetWielded()->MoveTo(GetStack());
1181 if(GetMainWielded() != DigItem
)
1183 Dig
->SetMoveDigger(true);
1184 DigItem
->RemoveFromSlot();
1186 if(GetMainArm() && GetMainArm()->IsUsable())
1187 GetMainArm()->SetWielded(DigItem
);
1189 GetSecondaryArm()->SetWielded(DigItem
);
1192 Dig
->SetMoveDigger(false);
1194 Dig
->SetSquareDug(Square
);
1198 truth
humanoid::CheckKick() const
1203 ADD_MESSAGE("This race can't kick.");
1208 if(GetUsableLegs() < 2)
1211 ADD_MESSAGE("How are you going to do that with %s?", GetUsableLegs() ? "only one usable leg" : "no usable legs");
1219 int humanoid::GetUsableLegs() const
1223 if(RightLegIsUsable())
1226 if(LeftLegIsUsable())
1232 int humanoid::GetUsableArms() const
1236 if(RightArmIsUsable())
1239 if(LeftArmIsUsable())
1245 truth
humanoid::CheckThrow() const
1247 if(!character::CheckThrow())
1254 ADD_MESSAGE("You don't have a usable arm to do that!");
1259 truth
humanoid::CheckOffer() const
1265 ADD_MESSAGE("You need a usable arm to offer.");
1270 v2
humanoid::GetEquipmentPanelPos(int I
) const // convert to array
1274 case HELMET_INDEX
: return v2(34, -22);
1275 case AMULET_INDEX
: return v2(14, -22);
1276 case CLOAK_INDEX
: return v2(-6, -22);
1277 case BODY_ARMOR_INDEX
: return v2(54, -22);
1278 case BELT_INDEX
: return v2(24, 70);
1279 case RIGHT_WIELDED_INDEX
: return v2(-14, 4);
1280 case LEFT_WIELDED_INDEX
: return v2(62, 4);
1281 case RIGHT_RING_INDEX
: return v2(-14, 44);
1282 case LEFT_RING_INDEX
: return v2(62, 44);
1283 case RIGHT_GAUNTLET_INDEX
: return v2(-14, 24);
1284 case LEFT_GAUNTLET_INDEX
: return v2(62, 24);
1285 case RIGHT_BOOT_INDEX
: return v2(4, 70);
1286 case LEFT_BOOT_INDEX
: return v2(44, 70);
1292 void humanoid::DrawSilhouette(truth AnimationDraw
) const
1295 blitdata B1
= { DOUBLE_BUFFER
,
1298 { TILE_SIZE
, TILE_SIZE
},
1299 { ivanconfig::GetContrastLuminance() },
1303 v2
Where(RES
.X
- SILHOUETTE_SIZE
.X
- 39, 53);
1304 cint Equipments
= GetEquipments();
1306 if(CanUseEquipment())
1307 for(c
= 0; c
< Equipments
; ++c
)
1308 if(GetBodyPartOfEquipment(c
) && EquipmentIsAllowed(c
))
1310 v2 Pos
= Where
+ GetEquipmentPanelPos(c
);
1313 DOUBLE_BUFFER
->DrawRectangle(Pos
+ v2(-1, -1), Pos
+ TILE_V2
, DARK_GRAY
);
1315 item
* Equipment
= GetEquipment(c
);
1317 if(Equipment
&& (!AnimationDraw
|| Equipment
->IsAnimated()))
1319 igraph::BlitBackGround(Pos
, TILE_V2
);
1322 if(Equipment
->AllowAlphaEverywhere())
1323 B1
.CustomData
|= ALLOW_ALPHA
;
1325 Equipment
->Draw(B1
);
1326 B1
.CustomData
&= ~ALLOW_ALPHA
;
1332 blitdata B2
= { DOUBLE_BUFFER
,
1334 { Where
.X
+ 8, Where
.Y
},
1335 { SILHOUETTE_SIZE
.X
, SILHOUETTE_SIZE
.Y
},
1340 for(int c
= 0; c
< BodyParts
; ++c
)
1342 bodypart
* BodyPart
= GetBodyPart(c
);
1346 int Type
= BodyPart
->IsUsable() ? SILHOUETTE_NORMAL
: SILHOUETTE_INTER_LACED
;
1347 bitmap
* Cache
= igraph::GetSilhouetteCache(c
, BodyPart
->GetConditionColorIndex(), Type
);
1348 Cache
->NormalMaskedBlit(B2
);
1349 BodyPart
->DrawScars(B2
);
1355 int humanoid::GetGlobalResistance(int Type
) const
1357 int Resistance
= GetResistance(Type
);
1360 Resistance
+= GetCloak()->GetResistance(Type
);
1362 if(!(Type
& PHYSICAL_DAMAGE
))
1365 Resistance
+= GetAmulet()->GetResistance(Type
);
1368 Resistance
+= GetRightRing()->GetResistance(Type
);
1371 Resistance
+= GetLeftRing()->GetResistance(Type
);
1377 truth
humanoid::TryToRiseFromTheDead()
1381 for(c
= 0; c
< BodyParts
; ++c
)
1384 bodypart
* BodyPart
= SearchForOriginalBodyPart(c
);
1388 BodyPart
->RemoveFromSlot();
1389 AttachBodyPart(BodyPart
);
1394 for(c
= 0; c
< BodyParts
; ++c
)
1396 bodypart
* BodyPart
= GetBodyPart(c
);
1398 if(BodyPartIsVital(c
) && !BodyPart
)
1399 if(!HandleNoBodyPart(c
))
1404 BodyPart
->ResetSpoiling();
1406 if(BodyPart
->CanRegenerate() || BodyPart
->GetHP() < 1)
1415 truth
humanoid::HandleNoBodyPart(int I
)
1420 if(CanBeSeenByPlayer())
1421 ADD_MESSAGE("The headless body of %s vibrates violently.", CHAR_NAME(DEFINITE
));
1425 if(CanBeSeenByPlayer())
1426 ADD_MESSAGE("The groinless body of %s vibrates violently.", CHAR_NAME(DEFINITE
));
1430 ABORT("The corpse does not have a torso.");
1436 v2
humanoid::GetBodyPartBitmapPos(int I
, truth
) const
1440 case TORSO_INDEX
: return GetTorsoBitmapPos();
1441 case HEAD_INDEX
: return GetHeadBitmapPos();
1442 case RIGHT_ARM_INDEX
: return GetRightArmBitmapPos();
1443 case LEFT_ARM_INDEX
: return GetLeftArmBitmapPos();
1444 case GROIN_INDEX
: return GetGroinBitmapPos();
1445 case RIGHT_LEG_INDEX
: return GetRightLegBitmapPos();
1446 case LEFT_LEG_INDEX
: return GetLeftLegBitmapPos();
1449 ABORT("Weird bodypart BitmapPos request for a humanoid!");
1453 col16
humanoid::GetBodyPartColorB(int I
, truth
) const
1457 case TORSO_INDEX
: return GetTorsoMainColor();
1458 case HEAD_INDEX
: return GetCapColor();
1459 case RIGHT_ARM_INDEX
:
1460 case LEFT_ARM_INDEX
: return GetArmMainColor();
1462 case RIGHT_LEG_INDEX
:
1463 case LEFT_LEG_INDEX
: return GetLegMainColor();
1466 ABORT("Weird bodypart col B request for a humanoid!");
1470 col16
humanoid::GetBodyPartColorC(int I
, truth
) const
1474 case TORSO_INDEX
: return GetBeltColor();
1475 case HEAD_INDEX
: return GetHairColor();
1476 case RIGHT_ARM_INDEX
:
1477 case LEFT_ARM_INDEX
: return GetGauntletColor();
1479 case RIGHT_LEG_INDEX
:
1480 case LEFT_LEG_INDEX
: return GetBootColor();
1483 ABORT("Weird bodypart col C request for a humanoid!");
1487 col16
humanoid::GetBodyPartColorD(int I
, truth
) const
1491 case TORSO_INDEX
: return GetTorsoSpecialColor();
1492 case HEAD_INDEX
: return GetEyeColor();
1493 case RIGHT_ARM_INDEX
:
1494 case LEFT_ARM_INDEX
: return GetArmSpecialColor();
1496 case RIGHT_LEG_INDEX
:
1497 case LEFT_LEG_INDEX
: return GetLegSpecialColor();
1500 ABORT("Weird bodypart col D request for a humanoid!");
1504 int humanoid::GetBodyPartSparkleFlags(int I
) const
1506 truth Sparkling
= false;
1507 int SparkleFlags
= GetNaturalSparkleFlags() & SKIN_COLOR
? SPARKLING_A
: 0;
1511 case TORSO_INDEX
: Sparkling
= GetNaturalSparkleFlags() & TORSO_MAIN_COLOR
; break;
1512 case HEAD_INDEX
: Sparkling
= GetNaturalSparkleFlags() & CAP_COLOR
; break;
1513 case RIGHT_ARM_INDEX
:
1514 case LEFT_ARM_INDEX
: Sparkling
= GetNaturalSparkleFlags() & ARM_MAIN_COLOR
; break;
1516 case RIGHT_LEG_INDEX
:
1517 case LEFT_LEG_INDEX
: Sparkling
= GetNaturalSparkleFlags() & LEG_MAIN_COLOR
; break;
1520 SparkleFlags
|= Sparkling
? SPARKLING_B
: 0;
1525 case TORSO_INDEX
: Sparkling
= GetNaturalSparkleFlags() & BELT_COLOR
; break;
1526 case HEAD_INDEX
: Sparkling
= GetNaturalSparkleFlags() & HAIR_COLOR
; break;
1527 case RIGHT_ARM_INDEX
:
1528 case LEFT_ARM_INDEX
: Sparkling
= GetNaturalSparkleFlags() & GAUNTLET_COLOR
; break;
1530 case RIGHT_LEG_INDEX
:
1531 case LEFT_LEG_INDEX
: Sparkling
= GetNaturalSparkleFlags() & BOOT_COLOR
; break;
1534 SparkleFlags
|= Sparkling
? SPARKLING_C
: 0;
1539 case TORSO_INDEX
: Sparkling
= GetNaturalSparkleFlags() & TORSO_SPECIAL_COLOR
; break;
1540 case HEAD_INDEX
: Sparkling
= GetNaturalSparkleFlags() & EYE_COLOR
; break;
1541 case RIGHT_ARM_INDEX
:
1542 case LEFT_ARM_INDEX
: Sparkling
= GetNaturalSparkleFlags() & ARM_SPECIAL_COLOR
; break;
1544 case RIGHT_LEG_INDEX
:
1545 case LEFT_LEG_INDEX
: Sparkling
= GetNaturalSparkleFlags() & LEG_SPECIAL_COLOR
; break;
1548 SparkleFlags
|= Sparkling
? SPARKLING_D
: 0;
1549 return SparkleFlags
;
1552 playerkind::playerkind() : SoulID(0), IsBonePlayer(false), IsClone(false)
1556 shopkeeper::shopkeeper()
1558 if(!game::IsLoading())
1559 Money
= GetMoney() + RAND() % 2001;
1562 void humanoid::Bite(character
* Enemy
, v2 HitPos
, int Direction
, truth ForceHit
)
1564 /* This function ought not to be called without a head */
1567 EditAP(-GetHead()->GetBiteAPCost());
1568 EditExperience(AGILITY
, 150, 1 << 9);
1569 EditStamina(-1000, false);
1570 Enemy
->TakeHit(this, 0, GetHead(), HitPos
, GetHead()->GetBiteDamage(), GetHead()->GetBiteToHitValue(), RAND() % 26 - RAND() % 26, BITE_ATTACK
, Direction
, !(RAND() % GetCriticalModifier()), ForceHit
);
1573 void humanoid::Kick(lsquare
* Square
, int Direction
, truth ForceHit
)
1575 leg
* KickLeg
= RAND_2
? GetRightLeg() : GetLeftLeg();
1577 EditAP(-KickLeg
->GetKickAPCost());
1578 EditStamina(-10000 / GetAttribute(LEG_STRENGTH
), false);
1580 if(Square
->BeKicked(this, 0, KickLeg
, KickLeg
->GetKickDamage(), KickLeg
->GetKickToHitValue(), RAND() % 26 - RAND() % 26, Direction
, !(RAND() % GetCriticalModifier()), ForceHit
))
1582 KickLeg
->EditExperience(LEG_STRENGTH
, 75, 1 << 9);
1583 KickLeg
->EditExperience(AGILITY
, 75, 1 << 9);
1587 /* Returns the average number of APs required to kill Enemy */
1589 double humanoid::GetTimeToKill(ccharacter
* Enemy
, truth UseMaxHP
) const
1591 double Effectivity
= 0;
1592 int AttackStyles
= 0;
1596 arm
* RightArm
= GetRightArm();
1600 double Damage
= RightArm
->GetDamage();
1603 Effectivity
+= 1 / (Enemy
->GetTimeToDie(this, int(Damage
) + 1, RightArm
->GetToHitValue(), AttackIsBlockable(GetRightWielded() ? WEAPON_ATTACK
: UNARMED_ATTACK
), UseMaxHP
) * RightArm
->GetAPCost());
1606 arm
* LeftArm
= GetLeftArm();
1610 double Damage
= LeftArm
->GetDamage();
1613 Effectivity
+= 1 / (Enemy
->GetTimeToDie(this, int(Damage
) + 1, LeftArm
->GetToHitValue(), AttackIsBlockable(GetLeftWielded() ? WEAPON_ATTACK
: UNARMED_ATTACK
), UseMaxHP
) * LeftArm
->GetAPCost());
1621 leg
* RightLeg
= GetRightLeg();
1622 leg
* LeftLeg
= GetLeftLeg();
1623 double TimeToDie
= Enemy
->GetTimeToDie(this, int(RightLeg
->GetKickDamage()) + 1, RightLeg
->GetKickToHitValue(), AttackIsBlockable(KICK_ATTACK
), UseMaxHP
) * RightLeg
->GetKickAPCost()
1624 + Enemy
->GetTimeToDie(this, int(LeftLeg
->GetKickDamage()) + 1, LeftLeg
->GetKickToHitValue(), AttackIsBlockable(KICK_ATTACK
), UseMaxHP
) * LeftLeg
->GetKickAPCost();
1625 Effectivity
+= 2 / TimeToDie
;
1631 head
* Head
= GetHead();
1632 Effectivity
+= 1 / (Enemy
->GetTimeToDie(this, int(Head
->GetBiteDamage()) + 1, Head
->GetBiteToHitValue(), AttackIsBlockable(BITE_ATTACK
), UseMaxHP
) * Head
->GetBiteAPCost());
1636 if(StateIsActivated(HASTE
))
1639 if(StateIsActivated(SLOW
))
1642 return AttackStyles
? AttackStyles
/ Effectivity
: 10000000;
1645 int humanoid::GetAttribute(int Identifier
, truth AllowBonus
) const
1647 if(Identifier
< BASE_ATTRIBUTES
)
1648 return character::GetAttribute(Identifier
, AllowBonus
);
1653 if(Identifier
== ARM_STRENGTH
|| Identifier
== DEXTERITY
)
1655 arm
* RightArm
= GetRightArm();
1658 Attrib
+= RightArm
->GetAttribute(Identifier
, AllowBonus
);
1660 arm
* LeftArm
= GetLeftArm();
1663 Attrib
+= LeftArm
->GetAttribute(Identifier
, AllowBonus
);
1665 else if(Identifier
== LEG_STRENGTH
|| Identifier
== AGILITY
)
1667 leg
* RightLeg
= GetRightLeg();
1670 Attrib
+= RightLeg
->GetAttribute(Identifier
, AllowBonus
);
1672 leg
* LeftLeg
= GetLeftLeg();
1675 Attrib
+= LeftLeg
->GetAttribute(Identifier
, AllowBonus
);
1679 ABORT("Illegal humanoid attribute %d request!", Identifier
);
1687 truth
humanoid::EditAttribute(int Identifier
, int Value
)
1689 if(Identifier
< BASE_ATTRIBUTES
)
1690 return character::EditAttribute(Identifier
, Value
);
1691 else if(Identifier
== ARM_STRENGTH
|| Identifier
== DEXTERITY
)
1693 truth Success
= false;
1695 if(GetRightArm() && GetRightArm()->EditAttribute(Identifier
, Value
))
1698 if(GetLeftArm() && GetLeftArm()->EditAttribute(Identifier
, Value
))
1703 else if(Identifier
== LEG_STRENGTH
|| Identifier
== AGILITY
)
1705 truth Success
= false;
1707 if(GetRightLeg() && GetRightLeg()->EditAttribute(Identifier
, Value
))
1710 if(GetLeftLeg() && GetLeftLeg()->EditAttribute(Identifier
, Value
))
1717 ABORT("Illegal humanoid attribute %d edit request!", Identifier
);
1722 void humanoid::EditExperience(int Identifier
, double Value
, double Speed
)
1724 if(!AllowExperience())
1727 if(Identifier
< BASE_ATTRIBUTES
)
1728 character::EditExperience(Identifier
, Value
, Speed
);
1729 else if(Identifier
== ARM_STRENGTH
|| Identifier
== DEXTERITY
)
1732 GetRightArm()->EditExperience(Identifier
, Value
, Speed
);
1735 GetLeftArm()->EditExperience(Identifier
, Value
, Speed
);
1737 else if(Identifier
== LEG_STRENGTH
|| Identifier
== AGILITY
)
1740 GetRightLeg()->EditExperience(Identifier
, Value
, Speed
);
1743 GetLeftLeg()->EditExperience(Identifier
, Value
, Speed
);
1746 ABORT("Illegal humanoid attribute %d experience edit request!", Identifier
);
1749 int humanoid::DrawStats(truth AnimationDraw
) const
1751 DrawSilhouette(AnimationDraw
);
1756 int PanelPosX
= RES
.X
- 96, PanelPosY
= 15;
1757 PrintAttribute("AStr", ARM_STRENGTH
, PanelPosX
, PanelPosY
++);
1758 PrintAttribute("LStr", LEG_STRENGTH
, PanelPosX
, PanelPosY
++);
1759 PrintAttribute("Dex", DEXTERITY
, PanelPosX
, PanelPosY
++);
1760 PrintAttribute("Agi", AGILITY
, PanelPosX
, PanelPosY
++);
1764 int humanoid::GetRandomStepperBodyPart() const
1766 int Possible
= 0, PossibleArray
[3];
1769 PossibleArray
[Possible
++] = RIGHT_LEG_INDEX
;
1772 PossibleArray
[Possible
++] = LEFT_LEG_INDEX
;
1775 return PossibleArray
[RAND_N(Possible
)];
1778 PossibleArray
[Possible
++] = RIGHT_ARM_INDEX
;
1781 PossibleArray
[Possible
++] = LEFT_ARM_INDEX
;
1784 return PossibleArray
[RAND_N(Possible
)];
1787 PossibleArray
[Possible
++] = HEAD_INDEX
;
1790 PossibleArray
[Possible
++] = GROIN_INDEX
;
1792 PossibleArray
[Possible
++] = TORSO_INDEX
;
1793 return PossibleArray
[RAND_N(Possible
)];
1796 int humanoid::CheckForBlock(character
* Enemy
, item
* Weapon
, double ToHitValue
, int Damage
, int Success
, int Type
)
1801 if(GetRightWielded())
1802 Damage
= CheckForBlockWithArm(Enemy
, Weapon
, GetRightArm(), ToHitValue
, Damage
, Success
, Type
);
1804 if(Damage
&& GetLeftWielded() && (!Weapon
|| Weapon
->Exists()))
1805 Damage
= CheckForBlockWithArm(Enemy
, Weapon
, GetLeftArm(), ToHitValue
, Damage
, Success
, Type
);
1810 truth
humanoid::CanWield() const
1812 return CanUseEquipment(RIGHT_WIELDED_INDEX
) || CanUseEquipment(LEFT_WIELDED_INDEX
);
1815 /* return true if still in balance */
1817 truth
humanoid::CheckBalance(double KickDamage
)
1822 || (GetUsableLegs() != 1
1824 && KickDamage
* 5 < RAND() % GetSize());
1827 sLong
humanoid::GetMoveAPRequirement(int Difficulty
) const
1830 return (!StateIsActivated(PANIC
) ? 10000000 : 8000000) * Difficulty
/ (APBonus(GetAttribute(AGILITY
)) * GetMoveEase());
1832 switch(GetUsableLegs())
1835 return (!StateIsActivated(PANIC
) ? 20000000 : 16000000) * Difficulty
/ (APBonus(GetAttribute(AGILITY
)) * GetMoveEase());
1837 return (!StateIsActivated(PANIC
) ? 13333333 : 10666667) * Difficulty
/ (APBonus(GetAttribute(AGILITY
)) * GetMoveEase());
1839 return (!StateIsActivated(PANIC
) ? 10000000 : 8000000) * Difficulty
/ (APBonus(GetAttribute(AGILITY
)) * GetMoveEase());
1842 ABORT("A %d legged humanoid invaded the dungeon!", GetUsableLegs());
1846 void hunter::CreateBodyParts(int SpecialFlags
)
1848 for(int c
= 0; c
< BodyParts
; ++c
)
1849 if(c
!= LEFT_ARM_INDEX
)
1850 CreateBodyPart(c
, SpecialFlags
);
1852 SetBodyPart(LEFT_ARM_INDEX
, 0);
1855 truth
humanoid::EquipmentEasilyRecognized(int I
) const
1857 if(GetRelation(PLAYER
) != HOSTILE
)
1863 case RIGHT_RING_INDEX
:
1864 case LEFT_RING_INDEX
:
1872 void humanoid::SignalEquipmentAdd(int EquipmentIndex
)
1874 character::SignalEquipmentAdd(EquipmentIndex
);
1876 if(EquipmentIndex
== RIGHT_WIELDED_INDEX
)
1877 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill
, GetRightWielded());
1878 else if(EquipmentIndex
== LEFT_WIELDED_INDEX
)
1879 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill
, GetLeftWielded());
1881 if(!IsInitializing())
1882 CalculateBattleInfo();
1885 void humanoid::SignalEquipmentRemoval(int EquipmentIndex
, citem
* Item
)
1887 character::SignalEquipmentRemoval(EquipmentIndex
, Item
);
1889 if(EquipmentIndex
== RIGHT_WIELDED_INDEX
)
1890 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill
, 0);
1891 else if(EquipmentIndex
== LEFT_WIELDED_INDEX
)
1892 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill
, 0);
1894 if(!IsInitializing())
1895 CalculateBattleInfo();
1898 void humanoid::SWeaponSkillTick()
1900 for(std::list
<sweaponskill
*>::iterator i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end();)
1902 if((*i
)->Tick() && IsPlayer())
1904 item
* Item
= SearchForItem(*i
);
1907 (*i
)->AddLevelDownMessage(Item
->CHAR_NAME(UNARTICLED
));
1910 if(!(*i
)->GetHits() && *i
!= GetCurrentRightSWeaponSkill() && *i
!= GetCurrentLeftSWeaponSkill())
1912 std::list
<sweaponskill
*>::iterator Dirt
= i
++;
1913 SWeaponSkill
.erase(Dirt
);
1920 void angel::GetAICommand()
1922 if((LastHealed
|| game::GetTick() - LastHealed
> 10000) && AttachBodyPartsOfFriendsNear())
1925 humanoid::GetAICommand();
1928 /* Returns true if the angel finds somebody near to heal else false */
1930 truth
angel::AttachBodyPartsOfFriendsNear()
1932 character
* HurtOne
= 0;
1933 bodypart
* SeveredOne
= 0;
1935 for(int d
= 0; d
< GetNeighbourSquares(); ++d
)
1937 square
* Square
= GetNeighbourSquare(d
);
1941 character
* Char
= Square
->GetCharacter();
1943 if(Char
&& (!HurtOne
|| Char
->IsPlayer()) && GetRelation(Char
) == FRIEND
&& !Char
->HasAllBodyParts())
1945 bodypart
* BodyPart
= Char
->FindRandomOwnBodyPart(false);
1950 SeveredOne
= BodyPart
;
1958 if(HurtOne
->IsPlayer())
1959 ADD_MESSAGE("%s puts your %s back to its place.", CHAR_DESCRIPTION(DEFINITE
), SeveredOne
->GetBodyPartName().CStr());
1960 else if(CanBeSeenByPlayer())
1961 ADD_MESSAGE("%s helps %s by putting %s %s in its old place.", CHAR_DESCRIPTION(DEFINITE
), HurtOne
->CHAR_DESCRIPTION(DEFINITE
), HurtOne
->GetPossessivePronoun().CStr(), SeveredOne
->GetBodyPartName().CStr());
1963 SeveredOne
->SetHP(1);
1964 SeveredOne
->RemoveFromSlot();
1965 HurtOne
->AttachBodyPart(SeveredOne
);
1966 LastHealed
= game::GetTick();
1967 DexterityAction(10);
1974 void humanoid::DrawBodyParts(blitdata
& BlitData
) const
1976 bitmap
* TileBuffer
= igraph::GetTileBuffer();
1977 bitmap
* RealBitmap
= BlitData
.Bitmap
;
1978 blitdata B
= { TileBuffer
,
1979 { BlitData
.Dest
.X
, BlitData
.Dest
.Y
},
1981 { TILE_SIZE
, TILE_SIZE
},
1984 BlitData
.CustomData
};
1986 RealBitmap
->NormalBlit(B
);
1987 TileBuffer
->FillPriority(0);
1988 B
.Src
.X
= B
.Src
.Y
= 0;
1989 B
.Luminance
= BlitData
.Luminance
;
1991 for(int c
= 0; c
< BodyParts
; ++c
)
1993 bodypart
* BodyPart
= GetBodyPart(DrawOrder
[c
]);
1997 B
.Dest
= GetDrawDisplacement(c
);
2002 B
.Dest
.X
= B
.Dest
.Y
= 0;
2003 arm
* LeftArm
= GetLeftArm();
2006 LeftArm
->DrawWielded(B
);
2008 arm
* RightArm
= GetRightArm();
2011 RightArm
->DrawWielded(B
);
2013 TileBuffer
->FastBlit(RealBitmap
, BlitData
.Dest
);
2016 v2
kamikazedwarf::GetDrawDisplacement(int I
) const
2018 static v2 DrawDisplacement
[] = { v2(0, 0), v2(0, 1), v2(0, -1), v2(0, -1), v2(0, -1), v2(0, 0), v2(0, 0) };
2019 return DrawDisplacement
[I
];
2022 col16
angel::GetTorsoMainColor() const
2024 return GetMasterGod()->GetColor();
2027 col16
angel::GetArmMainColor() const
2029 return GetMasterGod()->GetColor();
2032 col16
kamikazedwarf::GetTorsoMainColor() const
2034 return GetMasterGod()->GetColor();
2037 col16
kamikazedwarf::GetGauntletColor() const
2039 return GetMasterGod()->GetColor();
2042 col16
kamikazedwarf::GetLegMainColor() const
2044 return GetMasterGod()->GetColor();
2047 col16
housewife::GetHairColor() const
2049 static col16 HouseWifeHairColor
[] = { MakeRGB16(48, 40, 8), MakeRGB16(60, 48, 24), MakeRGB16(200, 0, 0) };
2050 return HouseWifeHairColor
[RAND() % 3];
2053 int angel::GetAttribute(int Identifier
, truth AllowBonus
) const // temporary until wings are bodyparts
2055 if(Identifier
== LEG_STRENGTH
)
2056 return GetDefaultLegStrength();
2057 else if(Identifier
== AGILITY
)
2058 return GetDefaultAgility();
2060 return humanoid::GetAttribute(Identifier
, AllowBonus
);
2063 int genie::GetAttribute(int Identifier
, truth AllowBonus
) const // temporary until someone invents a better way of doing this
2065 if(Identifier
== LEG_STRENGTH
)
2066 return GetDefaultLegStrength();
2067 else if(Identifier
== AGILITY
)
2068 return GetDefaultAgility();
2070 return humanoid::GetAttribute(Identifier
, AllowBonus
);
2073 truth
humanoid::CanUseStethoscope(truth PrintReason
) const
2075 if(!GetUsableArms())
2078 ADD_MESSAGE("You need a usable arm to use a stethoscope.");
2086 ADD_MESSAGE("You need a head to use stethoscope.");
2094 truth
humanoid::IsUsingArms() const
2096 return GetAttackStyle() & USE_ARMS
&& CanAttackWithAnArm();
2099 truth
humanoid::IsUsingLegs() const
2101 return (GetAttackStyle() & USE_LEGS
2102 || (GetAttackStyle() & USE_ARMS
&& !CanAttackWithAnArm()))
2103 && HasTwoUsableLegs();
2106 truth
humanoid::IsUsingHead() const
2108 return (GetAttackStyle() & USE_HEAD
2109 || ((GetAttackStyle() & USE_LEGS
2110 || (GetAttackStyle() & USE_ARMS
&& !CanAttackWithAnArm()))
2111 && !HasTwoUsableLegs()))
2115 void humanoid::CalculateBattleInfo()
2117 CalculateDodgeValue();
2118 doforbodyparts()(this, &bodypart::CalculateAttackInfo
);
2121 item
* skeleton::SevereBodyPart(int BodyPartIndex
, truth ForceDisappearance
, stack
* EquipmentDropStack
)
2123 if(BodyPartIndex
== RIGHT_ARM_INDEX
)
2124 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill
, 0);
2125 else if(BodyPartIndex
== LEFT_ARM_INDEX
)
2126 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill
, 0);
2128 item
* BodyPart
= GetBodyPart(BodyPartIndex
);
2131 if(!ForceDisappearance
)
2133 if(BodyPartIndex
== HEAD_INDEX
)
2134 Bone
= skull::Spawn(0, NO_MATERIALS
);
2136 Bone
= bone::Spawn(0, NO_MATERIALS
);
2138 Bone
->InitMaterials(BodyPart
->GetMainMaterial());
2139 BodyPart
->DropEquipment(EquipmentDropStack
);
2140 BodyPart
->RemoveFromSlot();
2141 BodyPart
->SetMainMaterial(0, NO_PIC_UPDATE
|NO_SIGNALS
);
2145 BodyPart
->DropEquipment(EquipmentDropStack
);
2146 BodyPart
->RemoveFromSlot();
2149 BodyPart
->SendToHell();
2150 CalculateAttributeBonuses();
2151 CalculateBattleInfo();
2152 SignalPossibleTransparencyChange();
2153 RemoveTraps(BodyPartIndex
);
2157 void zombie::CreateBodyParts(int SpecialFlags
)
2159 bool Anyway
= false;
2160 if(GetConfig() == ZOMBIE_OF_KHAZ_ZADM
)
2163 } // Khaz-Zadm needs his hands...
2165 for(int c
= 0; c
< BodyParts
; ++c
)
2166 if(Anyway
|| BodyPartIsVital(c
) || RAND_N(3) || (c
== HEAD_INDEX
&& !RAND_N(3)))
2168 bodypart
* BodyPart
= CreateBodyPart(c
, SpecialFlags
|NO_PIC_UPDATE
);
2169 BodyPart
->GetMainMaterial()->SetSpoilCounter(2000 + RAND_N(1000));
2173 void humanoid::AddSpecialEquipmentInfo(festring
& String
, int I
) const
2175 if((I
== RIGHT_WIELDED_INDEX
&& GetRightArm()->TwoHandWieldIsActive()) || (I
== LEFT_WIELDED_INDEX
&& GetLeftArm()->TwoHandWieldIsActive()))
2176 String
<< " (in both hands)";
2179 /* Yes, this is evil. */
2181 #define INSTANTIATE(name) if(DataBase->name.IsValid() && (Item = DataBase->name.Instantiate(SpecialFlags))) Set##name(Item);
2183 void humanoid::CreateInitialEquipment(int SpecialFlags
)
2185 character::CreateInitialEquipment(SpecialFlags
);
2188 INSTANTIATE(Helmet
);
2189 INSTANTIATE(Amulet
);
2191 INSTANTIATE(BodyArmor
);
2193 INSTANTIATE(RightWielded
);
2194 INSTANTIATE(LeftWielded
);
2195 INSTANTIATE(RightRing
);
2196 INSTANTIATE(LeftRing
);
2197 INSTANTIATE(RightGauntlet
);
2198 INSTANTIATE(LeftGauntlet
);
2199 INSTANTIATE(RightBoot
);
2200 INSTANTIATE(LeftBoot
);
2202 if(CurrentRightSWeaponSkill
)
2203 CurrentRightSWeaponSkill
->AddHit(GetRightSWeaponSkillHits() * 100);
2205 if(CurrentLeftSWeaponSkill
)
2206 CurrentLeftSWeaponSkill
->AddHit(GetLeftSWeaponSkillHits() * 100);
2209 festring
humanoid::GetBodyPartName(int I
, truth Articled
) const
2218 case HEAD_INDEX
: return Article
+ "head";
2219 case TORSO_INDEX
: return Article
+ "torso";
2220 case RIGHT_ARM_INDEX
: return Article
+ "right arm";
2221 case LEFT_ARM_INDEX
: return Article
+ "left arm";
2222 case GROIN_INDEX
: return Article
+ "groin";
2223 case RIGHT_LEG_INDEX
: return Article
+ "right leg";
2224 case LEFT_LEG_INDEX
: return Article
+ "left leg";
2227 ABORT("Illegal humanoid bodypart name request!");
2231 void humanoid::CreateBlockPossibilityVector(blockvector
& Vector
, double ToHitValue
) const
2233 double RightBlockChance
= 0;
2234 int RightBlockCapability
= 0;
2235 double LeftBlockChance
= 0;
2236 int LeftBlockCapability
= 0;
2237 arm
* RightArm
= GetRightArm();
2238 arm
* LeftArm
= GetLeftArm();
2242 RightBlockChance
= RightArm
->GetBlockChance(ToHitValue
);
2243 RightBlockCapability
= RightArm
->GetBlockCapability();
2248 LeftBlockChance
= LeftArm
->GetBlockChance(ToHitValue
);
2249 LeftBlockCapability
= LeftArm
->GetBlockCapability();
2254 if(RightBlockCapability
+ LeftBlockCapability
)
2255 Vector
.push_back(std::make_pair(RightBlockChance
* LeftBlockChance
, RightBlockCapability
+ LeftBlockCapability
));
2259 if(RightBlockCapability
)
2260 Vector
.push_back(std::make_pair(RightBlockChance
* (1 - LeftBlockChance
), RightBlockCapability
));
2264 if(LeftBlockCapability
)
2265 Vector
.push_back(std::make_pair(LeftBlockChance
* (1 - RightBlockChance
), LeftBlockCapability
));
2268 item
* humanoid::SevereBodyPart(int BodyPartIndex
, truth ForceDisappearance
, stack
* EquipmentDropStack
)
2270 if(BodyPartIndex
== RIGHT_ARM_INDEX
)
2271 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill
, 0);
2272 else if(BodyPartIndex
== LEFT_ARM_INDEX
)
2273 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill
, 0);
2275 return character::SevereBodyPart(BodyPartIndex
, ForceDisappearance
, EquipmentDropStack
);
2278 humanoid::humanoid(const humanoid
& Humanoid
) : mybase(Humanoid
), CurrentRightSWeaponSkill(0), CurrentLeftSWeaponSkill(0)
2280 SWeaponSkill
.resize(Humanoid
.SWeaponSkill
.size());
2281 std::list
<sweaponskill
*>::iterator i1
= SWeaponSkill
.begin();
2282 std::list
<sweaponskill
*>::const_iterator i2
= Humanoid
.SWeaponSkill
.begin();
2284 for(; i1
!= SWeaponSkill
.end(); ++i1
, ++i2
)
2285 *i1
= new sweaponskill(**i2
);
2288 cfestring
& humanoid::GetDeathMessage() const
2290 static festring HeadlessDeathMsg
= CONST_S("@Dd dies without a sound.");
2291 return GetHead() || character::GetDeathMessage() != "@Dd dies screaming." ? character::GetDeathMessage() : HeadlessDeathMsg
;
2294 int humanoid::GetSWeaponSkillLevel(citem
* Item
) const
2296 std::list
<sweaponskill
*>::const_iterator i
;
2298 for(i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
2299 if((*i
)->IsSkillOf(Item
))
2300 return (*i
)->GetLevel();
2302 for(idholder
* I
= Item
->GetCloneMotherID(); I
; I
= I
->Next
)
2303 for(i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
2304 if((*i
)->IsSkillOfCloneMother(Item
, I
->ID
))
2305 return (*i
)->GetLevel();
2310 truth
humanoid::UseMaterialAttributes() const
2312 return combinebodypartpredicates()(this, &bodypart::UseMaterialAttributes
, 0);
2315 col24
angel::GetBaseEmitation() const
2317 switch(GetMasterGod()->GetBasicAlignment())
2319 case GOOD
: return MakeRGB24(150, 150, 150);
2320 case NEUTRAL
: return MakeRGB24(120, 120, 150);
2321 case EVIL
: return MakeRGB24(150, 110, 110);
2327 void bananagrower::BeTalkedTo()
2331 if(GetRelation(PLAYER
) == HOSTILE
)
2332 ProcessAndAddMessage(GetHostileReplies()[RandomizeReply(Said
, GetHostileReplies().Size
)]);
2333 else if(!game::TweraifIsFree())
2335 if(GetRelation(PLAYER
) != HOSTILE
2336 && Profession
.Find("president", 0) != festring::NPos
&& !(RAND() % 7))
2337 ADD_MESSAGE("\"I'm glad Petrus spared my life even though I was the president.\"");
2339 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said
, 6)]);
2342 ProcessAndAddMessage(GetFriendlyReplies()[6 + RandomizeReply(Said
, 3)]);
2345 void bananagrower::RandomizeProfession()
2350 Profession
= CONST_S("the president of Tweraif");
2353 Profession
= CONST_S("a diplomat");
2356 Profession
= CONST_S("a teacher");
2359 Profession
= CONST_S("a philosopher");
2362 Profession
= CONST_S("a journalist");
2365 Profession
= CONST_S("an alchemist");
2368 Profession
= CONST_S("a renown mathematician");
2371 Profession
= CONST_S("a priest of Silva");
2377 Profession
= CONST_S("a professor of ");
2378 AddRandomScienceName(Profession
);
2383 void bananagrower::PostConstruct()
2385 Stamina
= MaxStamina
/ 5;
2386 RandomizeProfession();
2387 HasDroppedBananas
= FeedingSumo
= false;
2390 void bananagrower::Save(outputfile
& SaveFile
) const
2392 humanoid::Save(SaveFile
);
2393 SaveFile
<< Profession
<< HasDroppedBananas
<< FeedingSumo
;
2396 void bananagrower::Load(inputfile
& SaveFile
)
2398 humanoid::Load(SaveFile
);
2399 SaveFile
>> Profession
>> HasDroppedBananas
>> FeedingSumo
;
2402 void smith::BeTalkedTo()
2404 if(GetRelation(PLAYER
) == HOSTILE
)
2406 ADD_MESSAGE("\"You talkin' to me? You talkin' to me? You talkin' to me? Then who the hell else are you talkin' to? You talkin' to me? Well I'm the only one here. Who do you think you're talking to? Oh yeah? Huh? Ok.\"");
2410 if(!GetMainWielded() || !GetMainWielded()->CanBeUsedBySmith())
2412 ADD_MESSAGE("\"Sorry, I need an intact hammer to practise the art of smithing.\"");
2416 if(PLAYER
->PossessesItem(&item::IsFixableBySmith
))
2418 item
* Item
= PLAYER
->SelectFromPossessions(CONST_S("\"What do you want me to fix?\""), &item::IsFixableBySmith
);
2423 if(!(Item
->GetMainMaterial()->GetCategoryFlags() & IS_METAL
))
2425 ADD_MESSAGE("\"I only fix items made of metal.\"");
2429 /** update messages */
2431 sLong FixPrice
= Item
->GetFixPrice();
2433 if(PLAYER
->GetMoney() < FixPrice
)
2435 ADD_MESSAGE("\"Getting that fixed costs you %d gold pieces. Get the money and we'll talk.\"", FixPrice
);
2439 ADD_MESSAGE("\"I can fix your %s, but it'll cost you %d gold pieces.\"", Item
->CHAR_NAME(UNARTICLED
), FixPrice
);
2441 if(game::TruthQuestion(CONST_S("Do you accept this deal? [y/N]")))
2445 PLAYER
->EditMoney(-FixPrice
);
2446 ADD_MESSAGE("%s fixes %s in no time.", CHAR_NAME(DEFINITE
), Item
->CHAR_NAME(DEFINITE
));
2450 ADD_MESSAGE("\"Come back when you have some weapons or armor I can fix.\"");
2453 void humanoid::CalculateDodgeValue()
2455 DodgeValue
= 0.05 * GetMoveEase() * GetAttribute(AGILITY
) / sqrt(GetSize());
2461 if(!HasAUsableLeg())
2463 if(!HasTwoUsableLegs())
2471 truth
humanoid::CheckZap()
2473 if(!GetUsableArms())
2475 ADD_MESSAGE("You need at least one usable arm to zap.");
2479 return character::CheckZap();
2482 void bananagrower::GetAICommand()
2484 if(game::TweraifIsFree())
2486 humanoid::GetAICommand();
2490 if(CheckForEnemies(false, false, true, true))
2496 cv2 BananaTarget
= FeedingSumo
? SUMO_ROOM_POS
+ v2(1, 2) : v2(45, 45);
2498 if(GetPos() == BananaTarget
)
2500 itemvector ItemVector
;
2501 GetStack()->FillItemVector(ItemVector
);
2502 int BananasDropped
= 0;
2505 for(c
= 0; c
< ItemVector
.size(); ++c
)
2506 if(ItemVector
[c
]->IsBanana())
2508 ItemVector
[c
]->MoveTo(GetStackUnder());
2514 if(CanBeSeenByPlayer())
2515 ADD_MESSAGE("%s drops %s.", CHAR_NAME(DEFINITE
), BananasDropped
== 1 ? "a banana" : "some bananas");
2521 GetStackUnder()->FillItemVector(ItemVector
);
2522 int PeelsPickedUp
= 0;
2524 for(c
= 0; c
< ItemVector
.size(); ++c
)
2525 if(ItemVector
[c
]->IsBananaPeel())
2527 ItemVector
[c
]->MoveTo(GetStack());
2533 if(CanBeSeenByPlayer())
2534 ADD_MESSAGE("%s picks up %s.", CHAR_NAME(DEFINITE
), PeelsPickedUp
== 1 ? "a banana peel" : "some banana peels");
2539 HasDroppedBananas
= true;
2542 if(!HasDroppedBananas
)
2544 SetGoingTo(BananaTarget
);
2546 if(MoveTowardsTarget(true))
2549 else if(GetPos().X
== 54)
2551 if(CanBeSeenByPlayer())
2552 ADD_MESSAGE("%s leaves the town to gather more bananas.", CHAR_NAME(DEFINITE
));
2554 GetStack()->Clean();
2555 character
* Sumo
= game::GetSumo();
2556 FeedingSumo
= Sumo
&& Sumo
->GetNP() < (SATIATED_LEVEL
+ BLOATED_LEVEL
) >> 1 && !(RAND() % 15);
2557 int Bananas
= FeedingSumo
? 3 : 10;
2559 for(int c
= 0; c
< Bananas
; ++c
)
2560 GetStack()->AddItem(banana::Spawn());
2562 v2 Where
= GetLevel()->GetNearestFreeSquare(this, v2(0, 45));
2564 if(Where
== ERROR_V2
)
2565 Where
= GetLevel()->GetRandomSquare(this, NOT_IN_ROOM
); // this is odd but at least it doesn't crash
2568 RandomizeProfession();
2571 Stamina
= MaxStamina
/ 5;
2575 if(CanBeSeenByPlayer())
2576 ADD_MESSAGE("%s enters the town.", CHAR_NAME(INDEFINITE
));
2578 HasDroppedBananas
= false;
2582 SetGoingTo(v2(54, 45));
2584 if(MoveTowardsTarget(true))
2591 truth
humanoid::CheckTalk()
2593 if(!character::CheckTalk())
2598 ADD_MESSAGE("You need a head to talk.");
2605 truth
angel::CanCreateBodyPart(int I
) const
2607 return I
== TORSO_INDEX
|| I
== HEAD_INDEX
|| I
== RIGHT_ARM_INDEX
|| I
== LEFT_ARM_INDEX
;
2610 truth
genie::CanCreateBodyPart(int I
) const
2612 return I
== TORSO_INDEX
|| I
== HEAD_INDEX
|| I
== RIGHT_ARM_INDEX
|| I
== LEFT_ARM_INDEX
;
2615 truth
bananagrower::HandleCharacterBlockingTheWay(character
* Char
, v2 Pos
, int Dir
)
2617 return Char
->GetPos() == v2(45, 45) && (Displace(Char
, true) || Hit(Char
, Pos
, Dir
));
2620 festring
& bananagrower::ProcessMessage(festring
& Msg
) const
2622 character::ProcessMessage(Msg
);
2623 SEARCH_N_REPLACE(Msg
, "@pd", GetProfession());
2624 SEARCH_N_REPLACE(Msg
, "@Pd", GetProfession().CapitalizeCopy());
2628 void elder::CreateBodyParts(int SpecialFlags
)
2630 for(int c
= 0; c
< BodyParts
; ++c
)
2631 if(c
!= LEFT_LEG_INDEX
)
2632 CreateBodyPart(c
, SpecialFlags
);
2634 SetBodyPart(LEFT_LEG_INDEX
, 0);
2637 /*void encourager::GetAICommand()
2639 if(CheckForEnemies(true, true, true))
2642 if(CheckForUsefulItemsOnGround())
2648 if(game::GetTick() - LastHit > 200)
2650 static int NotDiagonal[] = { 1, 3, 4, 6 };
2652 for(int d = 0; d < 4; ++d)
2654 square* Square = GetNeighbourSquare(NotDiagonal[d]);
2658 character* Char = Square->GetCharacter();
2660 if(Char && Char->IsBananaGrower() && Hit(Char, Square->GetPos(), NotDiagonal[d], true))
2662 LastHit = game::GetTick();
2670 if(MoveTowardsHomePos())
2676 /*void encourager::Save(outputfile& SaveFile) const
2678 humanoid::Save(SaveFile);
2679 SaveFile << LastHit;
2682 void encourager::Load(inputfile& SaveFile)
2684 humanoid::Load(SaveFile);
2685 SaveFile >> LastHit;
2688 sLong
skeleton::GetBodyPartVolume(int I
) const
2692 case HEAD_INDEX
: return 600;
2693 case TORSO_INDEX
: return (GetTotalVolume() - 600) * 13 / 30;
2694 case RIGHT_ARM_INDEX
:
2695 case LEFT_ARM_INDEX
: return (GetTotalVolume() - 600) / 10;
2696 case GROIN_INDEX
: return (GetTotalVolume() - 600) / 10;
2697 case RIGHT_LEG_INDEX
:
2698 case LEFT_LEG_INDEX
: return ((GetTotalVolume() - 600) << 1) / 15;
2701 ABORT("Illegal humanoid bodypart volume request!");
2705 truth
humanoid::CheckIfEquipmentIsNotUsable(int I
) const
2707 return (I
== RIGHT_WIELDED_INDEX
&& GetRightArm()->CheckIfWeaponTooHeavy("this item"))
2708 || (I
== LEFT_WIELDED_INDEX
&& GetLeftArm()->CheckIfWeaponTooHeavy("this item"))
2709 || (I
== RIGHT_WIELDED_INDEX
&& GetLeftWielded() && GetLeftWielded()->IsTwoHanded() && GetLeftArm()->CheckIfWeaponTooHeavy(festring(GetPossessivePronoun() + " other wielded item").CStr()))
2710 || (I
== LEFT_WIELDED_INDEX
&& GetRightWielded() && GetRightWielded()->IsTwoHanded() && GetRightArm()->CheckIfWeaponTooHeavy(festring(GetPossessivePronoun() + " other wielded item").CStr()));
2713 int mistress::TakeHit(character
* Enemy
, item
* Weapon
, bodypart
* EnemyBodyPart
, v2 HitPos
, double Damage
, double ToHitValue
, int Success
, int Type
, int Direction
, truth Critical
, truth ForceHit
)
2715 int Return
= humanoid::TakeHit(Enemy
, Weapon
, EnemyBodyPart
, HitPos
, Damage
, ToHitValue
, Success
, Type
, Direction
, Critical
, ForceHit
);
2717 if(Return
== HAS_HIT
&& Critical
)
2720 ADD_MESSAGE("Aahhh. The pain feels unbelievably good.");
2721 else if(CanBeSeenByPlayer())
2722 ADD_MESSAGE("%s screams: \"Oh the delightful pain!\"", CHAR_NAME(DEFINITE
));
2724 ADD_MESSAGE("You hear someone screaming: \"Oh the delightful pain!\"");
2730 truth
petrusswife::SpecialEnemySightedReaction(character
* Char
)
2732 item
* Weapon
= Char
->GetMainWielded();
2734 if(Weapon
&& Weapon
->IsWeapon(Char
) && !(RAND() % 20))
2735 ADD_MESSAGE("%s screams: \"Oh my Frog, %s's got %s %s!\"", CHAR_DESCRIPTION(DEFINITE
), Char
->CHAR_PERSONAL_PRONOUN_THIRD_PERSON_VIEW
, Weapon
->GetArticle(), Weapon
->GetNameSingular().CStr());
2740 truth
housewife::SpecialEnemySightedReaction(character
* Char
)
2742 item
* Weapon
= Char
->GetMainWielded();
2744 if(Weapon
&& Weapon
->IsWeapon(Char
) && !(RAND() % 5))
2745 ADD_MESSAGE("%s screams: \"Oh my Frog, %s's got %s %s!\"", CHAR_DESCRIPTION(DEFINITE
), Char
->CHAR_PERSONAL_PRONOUN_THIRD_PERSON_VIEW
, Weapon
->GetArticle(), Weapon
->GetNameSingular().CStr());
2750 void guard::Save(outputfile
& SaveFile
) const
2752 humanoid::Save(SaveFile
);
2753 SaveFile
<< WayPoints
<< NextWayPoint
;
2756 void guard::Load(inputfile
& SaveFile
)
2758 humanoid::Load(SaveFile
);
2759 SaveFile
>> WayPoints
>> NextWayPoint
;
2762 void guard::GetAICommand()
2764 if(GetConfig() == MASTER
&& HP
<< 1 < MaxHP
&& (GetPos() - v2(30, 17)).GetLengthSquare() > 9)
2766 if(CanBeSeenByPlayer())
2767 ADD_MESSAGE("%s disappears.", CHAR_NAME(DEFINITE
));
2769 GetLevel()->GetLSquare(30, 16)->KickAnyoneStandingHereAway();
2770 Move(v2(30, 16), true);
2775 if(WayPoints
.size() && !IsGoingSomeWhere())
2777 if(GetPos() == WayPoints
[NextWayPoint
]) {
2778 if(NextWayPoint
< WayPoints
.size() - 1) ++NextWayPoint
; else NextWayPoint
= 0;
2781 GoingTo
= WayPoints
[NextWayPoint
];
2784 SeekLeader(GetLeader());
2786 if(CheckForEnemies(true, true, true))
2789 if(CheckForUsefulItemsOnGround())
2792 if(FollowLeader(GetLeader()))
2798 if(MoveTowardsHomePos())
2804 if(CheckForBeverage())
2810 truth
mistress::ReceiveDamage(character
* Damager
, int Damage
, int Type
, int TargetFlags
, int Direction
, truth Divide
, truth PenetrateArmor
, truth Critical
, truth ShowMsg
)
2812 truth Success
= humanoid::ReceiveDamage(Damager
, Damage
, Type
, TargetFlags
, Direction
, Divide
, PenetrateArmor
, Critical
, ShowMsg
);
2814 if(Type
& SOUND
&& Success
&& !(RAND() & 7))
2817 ADD_MESSAGE("Aahhh. The pain feels unbelievably good.");
2818 else if(CanBeSeenByPlayer())
2819 ADD_MESSAGE("%s screams: \"Oh the delightful pain!\"", CHAR_NAME(DEFINITE
));
2821 ADD_MESSAGE("You hear someone screaming: \"Oh the delightful pain!\"");
2827 void humanoid::AddSpecialStethoscopeInfo(felist
& Info
) const
2829 Info
.AddEntry(CONST_S("Arm strength: ") + GetAttribute(ARM_STRENGTH
), LIGHT_GRAY
);
2830 Info
.AddEntry(CONST_S("Leg strength: ") + GetAttribute(LEG_STRENGTH
), LIGHT_GRAY
);
2831 Info
.AddEntry(CONST_S("Dexterity: ") + GetAttribute(DEXTERITY
), LIGHT_GRAY
);
2832 Info
.AddEntry(CONST_S("Agility: ") + GetAttribute(AGILITY
), LIGHT_GRAY
);
2835 item
* humanoid::GetPairEquipment(int I
) const
2839 case RIGHT_WIELDED_INDEX
: return GetLeftWielded();
2840 case LEFT_WIELDED_INDEX
: return GetRightWielded();
2841 case RIGHT_GAUNTLET_INDEX
: return GetLeftGauntlet();
2842 case LEFT_GAUNTLET_INDEX
: return GetRightGauntlet();
2843 case RIGHT_BOOT_INDEX
: return GetLeftBoot();
2844 case LEFT_BOOT_INDEX
: return GetRightBoot();
2850 cfestring
& humanoid::GetStandVerb() const
2852 if(ForceCustomStandVerb())
2853 return DataBase
->StandVerb
;
2855 static festring HasntFeet
= CONST_S("crawling");
2856 static festring Hovering
= CONST_S("hovering");
2857 static festring Swimming
= CONST_S("swimming");
2859 if(StateIsActivated(LEVITATION
))
2865 return HasAUsableLeg() ? DataBase
->StandVerb
: HasntFeet
;
2868 void darkmage::GetAICommand()
2870 SeekLeader(GetLeader());
2872 if(FollowLeader(GetLeader()))
2875 character
* NearestEnemy
= 0;
2876 sLong NearestEnemyDistance
= 0x7FFFFFFF;
2877 character
* RandomFriend
= 0;
2878 charactervector Friend
;
2881 for(int c
= 0; c
< game::GetTeams(); ++c
)
2883 if(GetTeam()->GetRelation(game::GetTeam(c
)) == HOSTILE
)
2885 for(std::list
<character
*>::const_iterator i
= game::GetTeam(c
)->GetMember().begin(); i
!= game::GetTeam(c
)->GetMember().end(); ++i
)
2886 if((*i
)->IsEnabled())
2888 sLong ThisDistance
= Max
<sLong
>(abs((*i
)->GetPos().X
- Pos
.X
), abs((*i
)->GetPos().Y
- Pos
.Y
));
2890 if((ThisDistance
< NearestEnemyDistance
|| (ThisDistance
== NearestEnemyDistance
&& !(RAND() % 3))) && (*i
)->CanBeSeenBy(this))
2893 NearestEnemyDistance
= ThisDistance
;
2897 else if(GetTeam()->GetRelation(game::GetTeam(c
)) == FRIEND
)
2899 for(std::list
<character
*>::const_iterator i
= game::GetTeam(c
)->GetMember().begin(); i
!= game::GetTeam(c
)->GetMember().end(); ++i
)
2900 if((*i
)->IsEnabled() && (*i
)->CanBeSeenBy(this))
2901 Friend
.push_back(*i
);
2905 if(NearestEnemy
&& NearestEnemy
->GetPos().IsAdjacent(Pos
))
2907 if(NearestEnemy
->IsSmall()
2908 && GetAttribute(WISDOM
) < NearestEnemy
->GetAttackWisdomLimit()
2910 && Hit(NearestEnemy
, NearestEnemy
->GetPos(), game::GetDirectionForVector(NearestEnemy
->GetPos() - GetPos())))
2912 else if((GetConfig() == ARCH_MAGE
&& RAND() & 1)
2913 || (GetConfig() == ELDER
&& !(RAND() & 3)))
2915 if(CanBeSeenByPlayer())
2916 ADD_MESSAGE("%s invokes a spell and disappears.", CHAR_NAME(DEFINITE
));
2918 TeleportRandomly(true);
2919 EditAP(-GetSpellAPCost());
2924 if(NearestEnemy
&& ((GetConfig() != APPRENTICE
&& NearestEnemyDistance
< 10) || StateIsActivated(PANIC
)) && RAND() & 3)
2926 SetGoingTo((Pos
<< 1) - NearestEnemy
->GetPos());
2928 if(MoveTowardsTarget(true))
2932 if(Friend
.size() && !(RAND() & 3))
2934 RandomFriend
= Friend
[RAND() % Friend
.size()];
2941 CONST_S("killed by the spells of ") + GetName(INDEFINITE
),
2948 lsquare
* Square
= NearestEnemy
->GetLSquareUnder();
2949 EditAP(-GetSpellAPCost());
2951 if(CanBeSeenByPlayer())
2952 ADD_MESSAGE("%s invokes a spell!", CHAR_NAME(DEFINITE
));
2957 Square
->DrawLightning(v2(8, 8), WHITE
, YOURSELF
);
2958 Square
->Lightning(Beam
);
2963 Square
->DrawLightning(v2(8, 8), WHITE
, YOURSELF
);
2964 Square
->Lightning(Beam
);
2968 Square
->DrawParticles(RED
);
2969 Square
->LowerEnchantment(Beam
);
2978 case 2: Square
->DrawParticles(RED
); Square
->Strike(Beam
); break;
2979 case 3: Square
->DrawParticles(RED
); Square
->FireBall(Beam
); break;
2982 case 6: Square
->DrawParticles(RED
); Square
->Slow(Beam
); break;
2983 case 7: Square
->DrawParticles(RED
); Square
->Teleport(Beam
); break;
2986 case 10: Square
->DrawParticles(RED
); Square
->LowerEnchantment(Beam
); break;
2987 default: Square
->DrawLightning(v2(8, 8), WHITE
, YOURSELF
); Square
->Lightning(Beam
); break;
2996 case 2: Square
->DrawParticles(RED
); Square
->FireBall(Beam
); break;
2999 character
* Char
= NearestEnemy
->DuplicateToNearestSquare(this, CHANGE_TEAM
|MIRROR
|(1000 << LE_BASE_SHIFT
)|(1000 << LE_RAND_SHIFT
));
3003 if(Char
->CanBeSeenByPlayer())
3004 ADD_MESSAGE("%s materializes!", Char
->CHAR_NAME(INDEFINITE
));
3010 case 5: Square
->DrawParticles(RED
); Square
->Slow(Beam
); break;
3011 case 6: Square
->DrawParticles(RED
); Square
->Teleport(Beam
); break;
3014 case 9: Square
->DrawParticles(RED
); Square
->LowerEnchantment(Beam
); break;
3017 golem
* Golem
= golem::Spawn(RAND() % 3 ? ARCANITE
: OCTIRON
);
3018 v2 Where
= GetLevel()->GetNearestFreeSquare(Golem
, Square
->GetPos());
3020 if(Where
== ERROR_V2
)
3022 if(CanBeSeenByPlayer())
3023 ADD_MESSAGE("Nothing happens.");
3029 Golem
->SetGenerationDanger(GetGenerationDanger());
3030 Golem
->SetTeam(GetTeam());
3031 Golem
->PutTo(Where
);
3033 if(Golem
->CanBeSeenByPlayer())
3034 ADD_MESSAGE("Suddenly %s materializes!", Golem
->CHAR_NAME(INDEFINITE
));
3036 Golem
->GetLSquareUnder()->DrawParticles(RED
);
3041 default: Square
->DrawParticles(RED
); Square
->Strike(Beam
); break;
3047 if(CanBeSeenByPlayer())
3048 NearestEnemy
->DeActivateVoluntaryAction(CONST_S("The spell of ") + GetName(DEFINITE
) + CONST_S(" interrupts you."));
3050 NearestEnemy
->DeActivateVoluntaryAction(CONST_S("The spell interrupts you."));
3057 lsquare
* Square
= RandomFriend
->GetLSquareUnder();
3058 EditAP(-GetSpellAPCost());
3059 Square
->DrawParticles(RED
);
3065 Square
->Haste(Beam
);
3070 RandomFriend
->DuplicateToNearestSquare(this, CHANGE_TEAM
);
3075 Square
->Invisibility(Beam
);
3077 Square
->Haste(Beam
);
3097 void zombie::GetAICommand()
3101 for(stackiterator i
= GetLSquareUnder()->GetStack()->GetBottom(); i
.HasItem(); ++i
)
3103 head
* Head
= i
->Behead();
3107 if(CanBeSeenByPlayer())
3108 ADD_MESSAGE("%s takes %s and attaches it to its torso.", CHAR_NAME(DEFINITE
), Head
->CHAR_NAME(INDEFINITE
));
3110 Head
->RemoveFromSlot();
3111 AttachBodyPart(Head
);
3113 DexterityAction(10);
3119 humanoid::GetAICommand();
3122 head
* humanoid::Behead()
3124 head
* Head
= GetHead();
3127 SevereBodyPart(HEAD_INDEX
);
3132 truth
communist::BoundToUse(citem
* Item
, int I
) const
3134 return Item
&& Item
->IsGorovitsFamilyRelic() && Item
->IsInCorrectSlot(I
);
3137 festring
werewolfwolf::GetKillName() const
3139 if(GetPolymorphBackup() && GetPolymorphBackup()->GetType() == werewolfhuman::ProtoType
.GetIndex())
3140 return GetName(INDEFINITE
);
3142 return humanoid::GetKillName();
3145 int humanoid::GetRandomApplyBodyPart() const
3147 if(RightArmIsUsable())
3149 if(LeftArmIsUsable())
3150 return RAND_2
? RIGHT_ARM_INDEX
: LEFT_ARM_INDEX
;
3152 return RIGHT_ARM_INDEX
;
3154 else if(LeftArmIsUsable())
3155 return LEFT_ARM_INDEX
;
3163 void golem::BeTalkedTo()
3167 if(GetRelation(PLAYER
) == HOSTILE
)
3168 Engrave(GetHostileReplies()[RandomizeReply(Said
, GetHostileReplies().Size
)]);
3170 Engrave(GetFriendlyReplies()[RandomizeReply(Said
, GetFriendlyReplies().Size
)]);
3172 if(CanBeSeenByPlayer())
3173 ADD_MESSAGE("%s engraves something.", CHAR_NAME(DEFINITE
));
3178 void humanoid::AddAttributeInfo(festring
& Entry
) const
3181 Entry
<< GetAttribute(ARM_STRENGTH
);
3183 Entry
<< GetAttribute(LEG_STRENGTH
);
3185 Entry
<< GetAttribute(DEXTERITY
);
3187 Entry
<< GetAttribute(AGILITY
);
3188 character::AddAttributeInfo(Entry
);
3191 void humanoid::AddAttackInfo(felist
& List
) const
3193 if(GetAttackStyle() & USE_ARMS
)
3196 GetRightArm()->AddAttackInfo(List
);
3199 GetLeftArm()->AddAttackInfo(List
);
3206 GetRightLeg()->AddAttackInfo(List
);
3207 GetLeftLeg()->AddAttackInfo(List
);
3212 Entry
= CONST_S(" bite attack");
3214 Entry
<< GetHead()->GetBiteMinDamage() << '-' << GetHead()->GetBiteMaxDamage();
3216 Entry
<< int(GetHead()->GetBiteToHitValue());
3218 Entry
<< GetHead()->GetBiteAPCost();
3219 List
.AddEntry(Entry
, LIGHT_GRAY
);
3223 void humanoid::AddDefenceInfo(felist
& List
) const
3225 character::AddDefenceInfo(List
);
3228 GetRightArm()->AddDefenceInfo(List
);
3231 GetLeftArm()->AddDefenceInfo(List
);
3234 void humanoid::DetachBodyPart()
3238 switch(game::KeyQuestion(CONST_S("What limb? (l)eft arm, (r)ight arm, (L)eft leg, (R)ight leg, (h)ead?"), KEY_ESC
, 5, 'l','r','L','R', 'h'))
3241 ToBeDetached
= LEFT_ARM_INDEX
;
3244 ToBeDetached
= RIGHT_ARM_INDEX
;
3247 ToBeDetached
= LEFT_LEG_INDEX
;
3250 ToBeDetached
= RIGHT_LEG_INDEX
;
3253 ToBeDetached
= HEAD_INDEX
;
3259 if(GetBodyPart(ToBeDetached
))
3261 item
* ToDrop
= SevereBodyPart(ToBeDetached
);
3262 SendNewDrawRequest();
3266 GetStack()->AddItem(ToDrop
);
3267 ToDrop
->DropEquipment();
3270 ADD_MESSAGE("Bodypart detached!");
3273 ADD_MESSAGE("That bodypart has already been detached.");
3275 CheckDeath(CONST_S("removed one of his vital bodyparts"), 0);
3280 void humanoid::AddAttributeInfo(festring
&) const { }
3281 void humanoid::AddAttackInfo(felist
&) const { }
3282 void humanoid::AddDefenceInfo(felist
&) const { }
3283 void humanoid::DetachBodyPart() { }
3287 truth
ennerbeast::MustBeRemovedFromBone() const
3289 return !IsEnabled() || GetTeam()->GetID() != MONSTER_TEAM
|| GetDungeon()->GetIndex() != ELPURI_CAVE
|| GetLevel()->GetIndex() != ENNER_BEAST_LEVEL
;
3292 truth
communist::MustBeRemovedFromBone() const
3294 return !IsEnabled() || GetTeam()->GetID() != IVAN_TEAM
|| GetDungeon()->GetIndex() != ELPURI_CAVE
|| GetLevel()->GetIndex() != IVAN_LEVEL
;
3297 truth
humanoid::PreProcessForBone()
3299 for(std::list
<sweaponskill
*>::iterator i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
3300 (*i
)->PreProcessForBone();
3302 return character::PreProcessForBone();
3305 void humanoid::FinalProcessForBone()
3307 character::FinalProcessForBone();
3309 for(std::list
<sweaponskill
*>::iterator i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end();)
3311 boneidmap::iterator BI
= game::GetBoneItemIDMap().find(-(*i
)->GetID());
3313 if(BI
== game::GetBoneItemIDMap().end())
3315 std::list
<sweaponskill
*>::iterator Dirt
= i
++;
3316 SWeaponSkill
.erase(Dirt
);
3320 (*i
)->SetID(BI
->second
);
3326 void angel::FinalProcessForBone()
3328 humanoid::FinalProcessForBone();
3332 /*void encourager::FinalProcessForBone()
3334 humanoid::FinalProcessForBone();
3338 void playerkind::Save(outputfile
& SaveFile
) const
3340 humanoid::Save(SaveFile
);
3341 SaveFile
<< SoulID
<< HairColor
<< EyeColor
<< Talent
<< Weakness
<< IsBonePlayer
<< IsClone
;
3344 void playerkind::Load(inputfile
& SaveFile
)
3346 humanoid::Load(SaveFile
);
3347 SaveFile
>> SoulID
>> HairColor
>> EyeColor
>> Talent
>> Weakness
>> IsBonePlayer
>> IsClone
;
3350 void playerkind::SetSoulID(uLong What
)
3354 if(GetPolymorphBackup())
3355 GetPolymorphBackup()->SetSoulID(What
);
3358 truth
playerkind::SuckSoul(character
* Soul
)
3360 if(Soul
->GetID() == SoulID
)
3369 truth
playerkind::TryToRiseFromTheDead()
3371 if(humanoid::TryToRiseFromTheDead())
3373 if(IsEnabled() && SoulID
)
3375 ADD_MESSAGE("The soulless body of %s wobbles for a moment.", CHAR_NAME(DEFINITE
));
3385 void playerkind::FinalProcessForBone()
3387 humanoid::FinalProcessForBone();
3388 IsBonePlayer
= true;
3392 boneidmap::iterator BI
= game::GetBoneCharacterIDMap().find(SoulID
);
3394 if(BI
!= game::GetBoneCharacterIDMap().end())
3395 SoulID
= BI
->second
;
3401 playerkind::playerkind(const playerkind
& Char
) : mybase(Char
), SoulID(Char
.SoulID
), HairColor(Char
.HairColor
), EyeColor(Char
.EyeColor
), Talent(Char
.Talent
), Weakness(Char
.Weakness
), IsBonePlayer(Char
.IsBonePlayer
), IsClone(true)
3405 void playerkind::BeTalkedTo()
3407 if(IsClone
&& IsBonePlayer
)
3409 if(GetRelation(PLAYER
) == HOSTILE
)
3411 ADD_MESSAGE("Oh no, you too! Why does everyone bully me!");
3417 switch(RandomizeReply(Said
, 4))
3420 ADD_MESSAGE("\"I'd like to write a memoir, but alas I doubt anyone would believe it.\"");
3423 ADD_MESSAGE("\"Then that damned clone appeared, took all my equipment and claimed I was his slave...\"");
3426 ADD_MESSAGE("\"The level was a catastrophe for the party, but luckily you saved the day.\"");
3429 ADD_MESSAGE("\"Oh, how I hate bananas. I Hate Them! I HATE THEM SO MUCH!!!\"");
3435 if(GetRelation(PLAYER
) == HOSTILE
)
3437 ADD_MESSAGE("%s seems extremely irritated. \"Vanish, you foul mirror image!\"", CHAR_DESCRIPTION(DEFINITE
));
3443 switch(RandomizeReply(Said
, 4))
3446 ADD_MESSAGE("\"Hey, those clothes are mine! Give them back!\"");
3449 ADD_MESSAGE("\"What, you summoned me? What a coincidence, I remember summoning you, too.\"");
3452 ADD_MESSAGE("\"I'm leading this party, not you, Mr. copy guy!\"");
3455 ADD_MESSAGE("\"Oh, how I hate bananas. I Hate Them! I HATE THEM SO MUCH!!!\"");
3461 if(GetRelation(PLAYER
) == HOSTILE
)
3463 ADD_MESSAGE("Let's finish what my ghost failed to do!");
3469 switch(RandomizeReply(Said
, 4))
3472 ADD_MESSAGE("\"What was it like? Death, you mean? Well, just like New Attnam. Very hot and whips everywhere.\"");
3475 ADD_MESSAGE("\"Stop it already! I *don't* want to know how my corpse smelled!\"");
3478 ADD_MESSAGE("\"I'm sorry about that ghost thing. That YASD was just a bit too much to handle, so I lost myself.\"");
3481 ADD_MESSAGE("\"Oh, how I hate bananas. I Hate Them! I HATE THEM SO MUCH!!!\"");
3487 void humanoid::EnsureCurrentSWeaponSkillIsCorrect(sweaponskill
*& Skill
, citem
* Wielded
)
3491 if(!Skill
|| !Skill
->IsSkillOf(Wielded
))
3494 EnsureCurrentSWeaponSkillIsCorrect(Skill
, 0);
3496 std::list
<sweaponskill
*>::iterator i
;
3498 for(i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
3499 if((*i
)->IsSkillOf(Wielded
))
3505 for(idholder
* I
= Wielded
->GetCloneMotherID(); I
; I
= I
->Next
)
3506 for(i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
3507 if((*i
)->IsSkillOfCloneMother(Wielded
, I
->ID
))
3509 Skill
= new sweaponskill(**i
);
3510 Skill
->SetID(Wielded
->GetID());
3511 SWeaponSkill
.push_back(Skill
);
3515 Skill
= new sweaponskill(Wielded
);
3516 SWeaponSkill
.push_back(Skill
);
3521 if(!Skill
->GetHits() && (CurrentRightSWeaponSkill
!= Skill
|| CurrentLeftSWeaponSkill
!= Skill
))
3522 for(std::list
<sweaponskill
*>::iterator i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
3526 SWeaponSkill
.erase(i
);
3534 humanoid::~humanoid()
3536 for(std::list
<sweaponskill
*>::iterator i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
3540 truth
guard::MoveTowardsHomePos()
3542 if(GetConfig() == MASTER
&& GetPos() != v2(30, 16))
3544 if(CanBeSeenByPlayer())
3545 ADD_MESSAGE("%s disappears.", CHAR_NAME(DEFINITE
));
3547 GetLevel()->GetLSquare(30, 16)->KickAnyoneStandingHereAway();
3548 Move(v2(30, 16), true);
3550 if(CanBeSeenByPlayer())
3551 ADD_MESSAGE("%s appears.", CHAR_NAME(DEFINITE
));
3557 return humanoid::MoveTowardsHomePos();
3560 bodypart
* ennerbeast::MakeBodyPart(int I
) const
3563 return ennerhead::Spawn(0, NO_MATERIALS
);
3565 return humanoid::MakeBodyPart(I
);
3568 int humanoid::GetSumOfAttributes() const
3570 return character::GetSumOfAttributes() + GetAttribute(LEG_STRENGTH
) + GetAttribute(DEXTERITY
) ;
3573 truth
humanoid::CheckConsume(cfestring
& Verb
) const
3578 ADD_MESSAGE("You need a head to %s.", Verb
.CStr());
3583 return character::CheckConsume(Verb
);
3586 truth
humanoid::CanConsume(material
* Material
) const
3588 return character::CanConsume(Material
) && HasHead();
3591 void femaleslave::BeTalkedTo()
3595 if(GetConfig() != NEW_ATTNAM
|| GetRelation(PLAYER
) == HOSTILE
)
3596 humanoid::BeTalkedTo();
3597 else if(!game::TweraifIsFree())
3598 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said
, 4)]);
3600 ProcessAndAddMessage(GetFriendlyReplies()[4 + RandomizeReply(Said
, 3)]);
3603 void necromancer::GetAICommand()
3605 SeekLeader(GetLeader());
3607 if(FollowLeader(GetLeader()))
3610 character
* NearestEnemy
= 0;
3611 sLong NearestEnemyDistance
= 0x7FFFFFFF;
3614 for(int c
= 0; c
< game::GetTeams(); ++c
)
3615 if(GetTeam()->GetRelation(game::GetTeam(c
)) == HOSTILE
)
3617 for(std::list
<character
*>::const_iterator i
= game::GetTeam(c
)->GetMember().begin(); i
!= game::GetTeam(c
)->GetMember().end(); ++i
)
3618 if((*i
)->IsEnabled())
3620 sLong ThisDistance
= Max
<sLong
>(abs((*i
)->GetPos().X
- Pos
.X
), abs((*i
)->GetPos().Y
- Pos
.Y
));
3622 if((ThisDistance
< NearestEnemyDistance
|| (ThisDistance
== NearestEnemyDistance
&& !(RAND() % 3))) && (*i
)->CanBeSeenBy(this))
3625 NearestEnemyDistance
= ThisDistance
;
3630 if(NearestEnemy
&& NearestEnemy
->GetPos().IsAdjacent(Pos
))
3632 if(GetConfig() == MASTER_NECROMANCER
&& !(RAND() & 3))
3634 if(CanBeSeenByPlayer())
3635 ADD_MESSAGE("%s invokes a spell and disappears.", CHAR_NAME(DEFINITE
));
3637 TeleportRandomly(true);
3638 EditAP(-GetSpellAPCost());
3641 else if(NearestEnemy
->IsSmall()
3642 && GetAttribute(WISDOM
) < NearestEnemy
->GetAttackWisdomLimit()
3644 && Hit(NearestEnemy
, NearestEnemy
->GetPos(), game::GetDirectionForVector(NearestEnemy
->GetPos() - GetPos())))
3650 if(!RAND_N(3) && TryToRaiseZombie())
3655 if(!RAND_N(6) && TryToRaiseZombie())
3659 if(NearestEnemy
&& !(RAND() % (GetConfig() == APPRENTICE_NECROMANCER
? 3 : 2)))
3661 lsquare
* Square
= NearestEnemy
->GetLSquareUnder();
3662 EditAP(-GetSpellAPCost());
3664 if(CanBeSeenByPlayer())
3665 ADD_MESSAGE("%s invokes a spell!", CHAR_NAME(DEFINITE
));
3667 truth Interrupt
= false;
3671 case APPRENTICE_NECROMANCER
:
3674 case MASTER_NECROMANCER
:
3679 Square
->DrawLightning(v2(8, 8), WHITE
, YOURSELF
);
3684 CONST_S("killed by the spells of ") + GetName(INDEFINITE
),
3689 Square
->Lightning(Beam
);
3697 if(CanBeSeenByPlayer())
3698 NearestEnemy
->DeActivateVoluntaryAction(CONST_S("The spell of ") + GetName(DEFINITE
) + CONST_S(" interrupts you."));
3700 NearestEnemy
->DeActivateVoluntaryAction(CONST_S("The spell interrupts you."));
3705 if(NearestEnemy
&& (NearestEnemyDistance
< 10 || StateIsActivated(PANIC
)) && RAND() & 3)
3707 SetGoingTo((Pos
<< 1) - NearestEnemy
->GetPos());
3709 if(MoveTowardsTarget(true))
3725 truth
necromancer::TryToRaiseZombie()
3727 for(int c
= 0; c
< game::GetTeams(); ++c
)
3728 for(std::list
<character
*>::const_iterator i
= game::GetTeam(c
)->GetMember().begin();
3729 i
!= game::GetTeam(c
)->GetMember().end(); ++i
)
3730 if(!(*i
)->IsEnabled() && (*i
)->GetMotherEntity()
3731 && (*i
)->GetMotherEntity()->Exists()
3732 && (GetConfig() == MASTER_NECROMANCER
3733 || (*i
)->GetMotherEntity()->GetSquareUnderEntity()->CanBeSeenBy(this)))
3735 character
* Zombie
= (*i
)->GetMotherEntity()->TryNecromancy(this);
3739 if(Zombie
->CanBeSeenByPlayer())
3740 ADD_MESSAGE("%s calls %s back to cursed undead life.", CHAR_DESCRIPTION(DEFINITE
), Zombie
->CHAR_NAME(INDEFINITE
));
3741 else if(CanBeSeenByPlayer())
3742 ADD_MESSAGE("%s casts a spell, but you notice no effect.", CHAR_NAME(DEFINITE
));
3744 EditAP(-GetSpellAPCost());
3752 void necromancer::RaiseSkeleton()
3756 const database
* WarLordDataBase
;
3757 databasecreator
<character
>::FindDataBase(WarLordDataBase
, &skeleton::ProtoType
, WAR_LORD
);
3760 if(GetConfig() == MASTER_NECROMANCER
&& !(WarLordDataBase
->Flags
& HAS_BEEN_GENERATED
) && !(RAND() % 250))
3762 Skeleton
= skeleton::Spawn(WAR_LORD
);
3763 Skeleton
->SetTeam(GetTeam());
3764 Skeleton
->PutNear(GetPos());
3765 Skeleton
->SignalGeneration();
3767 if(Skeleton
->CanBeSeenByPlayer())
3768 ADD_MESSAGE("The whole area trembles terribly as %s emerges from the ground.", Skeleton
->CHAR_NAME(DEFINITE
));
3769 else if(CanBeSeenByPlayer())
3770 ADD_MESSAGE("%s casts a powerful spell which makes the whole area tremble.", CHAR_NAME(DEFINITE
));
3772 ADD_MESSAGE("You feel the presence of an ancient evil being awakened from its long slumber. You shiver.");
3776 Skeleton
= skeleton::Spawn(GetConfig() == APPRENTICE_NECROMANCER
? 0 : WARRIOR
, NO_EQUIPMENT
);
3777 Skeleton
->SetTeam(GetTeam());
3778 Skeleton
->PutNear(GetPos());
3780 if(Skeleton
->CanBeSeenByPlayer())
3781 ADD_MESSAGE("The ground shakes and %s emerges from it.", Skeleton
->CHAR_NAME(INDEFINITE
));
3782 else if(CanBeSeenByPlayer())
3783 ADD_MESSAGE("%s casts a spell, but you notice no effect.", CHAR_NAME(DEFINITE
));
3786 Skeleton
->SetGenerationDanger(GetGenerationDanger());
3787 EditAP(-GetSpellAPCost());
3790 void humanoid::StayOn(liquid
* Liquid
)
3795 truth Standing
= false;
3799 GetRightLeg()->StayOn(Liquid
);
3803 if(IsEnabled() && GetLeftLeg())
3805 GetLeftLeg()->StayOn(Liquid
);
3811 bodypart
* BodyPart
[MAX_BODYPARTS
];
3814 for(int c
= 0; c
< BodyParts
; ++c
)
3816 BodyPart
[Index
++] = GetBodyPart(c
);
3818 BodyPart
[RAND() % Index
]->StayOn(Liquid
);
3822 bodypart
* playerkind::MakeBodyPart(int I
) const
3826 case TORSO_INDEX
: return playerkindtorso::Spawn(0, NO_MATERIALS
);
3827 case HEAD_INDEX
: return playerkindhead::Spawn(0, NO_MATERIALS
);
3828 case RIGHT_ARM_INDEX
: return playerkindrightarm::Spawn(0, NO_MATERIALS
);
3829 case LEFT_ARM_INDEX
: return playerkindleftarm::Spawn(0, NO_MATERIALS
);
3830 case GROIN_INDEX
: return playerkindgroin::Spawn(0, NO_MATERIALS
);
3831 case RIGHT_LEG_INDEX
: return playerkindrightleg::Spawn(0, NO_MATERIALS
);
3832 case LEFT_LEG_INDEX
: return playerkindleftleg::Spawn(0, NO_MATERIALS
);
3835 ABORT("Weird bodypart to make for a playerkind. It must be your fault!");
3839 truth
golem::AddAdjective(festring
& String
, truth Articled
) const
3841 int TotalRustLevel
= sumbodypartproperties()(this, &bodypart::GetMainMaterialRustLevel
);
3844 return humanoid::AddAdjective(String
, Articled
);
3850 if(TotalRustLevel
<= GetBodyParts())
3851 String
<< "slightly rusted ";
3852 else if(TotalRustLevel
<= GetBodyParts() << 1)
3853 String
<< "rusted ";
3855 String
<< "very rusted ";
3857 String
<< GetAdjective() << ' ';
3862 void oree::Bite(character
* Enemy
, v2 HitPos
, int, truth
)
3865 ADD_MESSAGE("You vomit acidous blood at %s.", Enemy
->CHAR_DESCRIPTION(DEFINITE
));
3866 else if(Enemy
->IsPlayer() || CanBeSeenByPlayer() || Enemy
->CanBeSeenByPlayer())
3867 ADD_MESSAGE("%s vomits acidous blood at %s.", CHAR_DESCRIPTION(DEFINITE
), Enemy
->CHAR_DESCRIPTION(DEFINITE
));
3869 Vomit(HitPos
, 500 + RAND() % 500, false);
3872 void sumowrestler::GetAICommand()
3876 SeekLeader(GetLeader());
3878 if(CheckForEnemies(true, true, true))
3881 if(CheckForUsefulItemsOnGround())
3887 if(FollowLeader(GetLeader()))
3893 if(MoveTowardsHomePos())
3899 void sumowrestler::BeTalkedTo()
3903 if(GetRelation(PLAYER
) == HOSTILE
)
3904 ProcessAndAddMessage(GetHostileReplies()[RandomizeReply(Said
, GetHostileReplies().Size
)]);
3905 else if(!game::TweraifIsFree())
3906 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said
, 6)]);
3908 ProcessAndAddMessage(GetFriendlyReplies()[6 + RandomizeReply(Said
, 3)]);
3911 character
* tourist::GetLeader() const
3913 character
* Guide
= game::GetTeam(TOURIST_GUIDE_TEAM
)->GetLeader();
3914 return Guide
&& Guide
->GetRelation(this) != HOSTILE
? Guide
: GetTeam()->GetLeader();
3917 void elder::GetAICommand()
3919 /* Select a place to guide the tourists to */
3922 SetGoingTo(GetLevel()->GetRandomSquare());
3924 humanoid::GetAICommand();
3927 void tourist::GetAICommand()
3929 if(game::IsSumoWrestling() && !(RAND() % 10))
3931 if(GetConfig() == HUSBAND
)
3934 ADD_MESSAGE("%s shouts: \"Show that skinny wimp what you've got, Huang!\"", CHAR_DESCRIPTION(DEFINITE
));
3936 ADD_MESSAGE("%s screams: \"Go for it, Huang!\"", CHAR_DESCRIPTION(DEFINITE
));
3938 else if(GetConfig() == WIFE
)
3941 ADD_MESSAGE("%s encourages you: \"Knock him out, %s!\"", CHAR_DESCRIPTION(DEFINITE
), game::GetPlayerName().CStr());
3943 ADD_MESSAGE("%s cheers you: \"A handsome guy like you can't lose to that banana ball!\"", CHAR_DESCRIPTION(DEFINITE
));
3945 else if(GetConfig() == CHILD
)
3948 ADD_MESSAGE("%s yells: \"More blood on the ring!!!\"", CHAR_DESCRIPTION(DEFINITE
));
3950 ADD_MESSAGE("%s cries: \"Kill him, Pong!!!\"", CHAR_DESCRIPTION(DEFINITE
));
3954 humanoid::GetAICommand();
3958 ///////////////////////////////////////////////////////////////////////////////
3959 character
* humanoid::CreateZombie() const
3964 humanoid
* Zombie
= zombie::Spawn();
3967 for(c
= 0; c
< BodyParts
; ++c
)
3969 bodypart
* BodyPart
= GetBodyPart(c
);
3973 BodyPart
= SearchForOriginalBodyPart(c
);
3977 BodyPart
->RemoveFromSlot();
3978 BodyPart
->SendToHell();
3984 bodypart
* ZombieBodyPart
= Zombie
->GetBodyPart(c
);
3987 ZombieBodyPart
= Zombie
->CreateBodyPart(c
);
3989 material
* M
= BodyPart
->GetMainMaterial()->Duplicate();
3990 M
->SetSpoilCounter(2000 + RAND() % 1000);
3991 M
->SetSkinColor(Zombie
->GetSkinColor());
3992 ZombieBodyPart
->ChangeMainMaterial(M
);
3993 ZombieBodyPart
->CopyAttributes(BodyPart
);
3995 else if(!Zombie
->BodyPartIsVital(c
))
3997 bodypart
* ZombieBodyPart
= Zombie
->GetBodyPart(c
);
4001 ZombieBodyPart
->RemoveFromSlot();
4002 ZombieBodyPart
->SendToHell();
4007 for(c
= 0; c
< Zombie
->AllowedWeaponSkillCategories
; ++c
)
4008 Zombie
->CWeaponSkill
[c
] = CWeaponSkill
[c
];
4010 Zombie
->SWeaponSkill
.resize(SWeaponSkill
.size());
4011 std::list
<sweaponskill
*>::iterator i1
= Zombie
->SWeaponSkill
.begin();
4012 std::list
<sweaponskill
*>::const_iterator i2
= SWeaponSkill
.begin();
4014 for(; i2
!= SWeaponSkill
.end(); ++i1
, ++i2
)
4015 *i1
= new sweaponskill(**i2
);
4017 memcpy(Zombie
->BaseExperience
,
4019 BASE_ATTRIBUTES
* sizeof(*BaseExperience
));
4020 Zombie
->CalculateAll();
4021 Zombie
->RestoreHP();
4022 Zombie
->RestoreStamina();
4023 static_cast<zombie
*>(Zombie
)->SetDescription(GetZombieDescription());
4024 Zombie
->GenerationDanger
= GenerationDanger
;
4028 void zombie::AddPostFix(festring
& String
, int Case
) const
4030 if(!Description
.IsEmpty())
4031 String
<< Description
;
4033 humanoid::AddPostFix(String
, Case
);
4036 void zombie::Save(outputfile
& SaveFile
) const
4038 humanoid::Save(SaveFile
);
4039 SaveFile
<< Description
;
4042 void zombie::Load(inputfile
& SaveFile
)
4044 humanoid::Load(SaveFile
);
4045 SaveFile
>> Description
;
4048 int darkknight::ModifyBodyPartHitPreference(int I
, int Modifier
) const
4050 return IsLimbIndex(I
) ? Modifier
<< 1 : Modifier
;
4053 int darkknight::ModifyBodyPartToHitChance(int I
, int Chance
) const
4055 return IsLimbIndex(I
) ? Chance
<< 1 : Chance
;
4058 void darkknight::SpecialBodyPartSeverReaction()
4063 ADD_MESSAGE("%s screams: \"I'll do you for that! I'll bite your legs off!\"", CHAR_DESCRIPTION(DEFINITE
));
4064 else if(!(RAND() % 5))
4068 ADD_MESSAGE("%s states calmly: \"'Tis but a scratch.\"", CHAR_DESCRIPTION(DEFINITE
)); break;
4070 ADD_MESSAGE("%s states calmly: \"Just a flesh wound.\"", CHAR_DESCRIPTION(DEFINITE
)); break;
4072 ADD_MESSAGE("%s shouts: \"I'm invincible!\"", CHAR_DESCRIPTION(DEFINITE
)); break;
4077 void humanoid::LeprosyHandler()
4079 if(IsImmuneToLeprosy())
4084 if(!RAND_N(1000 * GetAttribute(ENDURANCE
)))
4085 DropRandomNonVitalBodypart();
4087 if(!game::IsInWilderness())
4089 for(int d
= 0; d
< GetNeighbourSquares(); ++d
)
4091 lsquare
* Square
= GetNeighbourLSquare(d
);
4093 if(Square
&& Square
->GetCharacter())
4094 Square
->GetCharacter()->TryToInfectWithLeprosy(this);
4098 character::LeprosyHandler();
4101 void humanoid::DropRandomNonVitalBodypart()
4103 int BodyPartIndexToDrop
= GetRandomNonVitalBodyPart();
4105 if(BodyPartIndexToDrop
!= NONE_INDEX
)
4106 DropBodyPart(BodyPartIndexToDrop
);
4109 void humanoid::DropBodyPart(int Index
)
4111 if(!GetBodyPart(Index
)->IsAlive())
4114 festring NameOfDropped
= GetBodyPart(Index
)->GetBodyPartName();
4115 item
* Dropped
= SevereBodyPart(Index
);
4119 GetStack()->AddItem(Dropped
);
4120 Dropped
->DropEquipment();
4124 ADD_MESSAGE("You feel very ill. Your %s snaps off.", NameOfDropped
.CStr());
4125 game::AskForEscPress(CONST_S("Bodypart severed!"));
4126 DeActivateVoluntaryAction();
4128 else if(CanBeSeenByPlayer())
4129 ADD_MESSAGE("Suddenly %s's %s snaps off.", CHAR_NAME(DEFINITE
), NameOfDropped
.CStr());
4135 ADD_MESSAGE("You feel very ill. Your %s disappears.", NameOfDropped
.CStr());
4136 game::AskForEscPress(CONST_S("Bodypart destroyed!"));
4137 DeActivateVoluntaryAction();
4139 else if(CanBeSeenByPlayer())
4140 ADD_MESSAGE("Suddenly %s's %s disappears.", CHAR_NAME(DEFINITE
), NameOfDropped
.CStr());
4144 void humanoid::DuplicateEquipment(character
* Receiver
, uLong Flags
)
4146 character::DuplicateEquipment(Receiver
, Flags
);
4147 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill
, GetRightWielded());
4148 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill
, GetLeftWielded());
4151 truth
character::CanHear() const
4153 return DataBase
->CanHear
&& HasHead();
4156 col16
veterankamikazedwarf::GetTorsoMainColor() const
4158 return GetMasterGod()->GetEliteColor();
4161 col16
veterankamikazedwarf::GetGauntletColor() const
4163 return GetMasterGod()->GetEliteColor();
4166 col16
veterankamikazedwarf::GetLegMainColor() const
4168 return GetMasterGod()->GetEliteColor();
4171 col16
archangel::GetTorsoMainColor() const
4173 return GetMasterGod()->GetEliteColor();
4176 col16
archangel::GetArmMainColor() const
4178 return GetMasterGod()->GetEliteColor();
4181 void archangel::CreateInitialEquipment(int SpecialFlags
)
4183 humanoid::CreateInitialEquipment(SpecialFlags
);
4184 GetStack()->AddItem(holybook::Spawn(GetConfig(), SpecialFlags
));
4186 meleeweapon
* Weapon
;
4188 switch(GetMasterGod()->GetBasicAlignment())
4191 Weapon
= flamingsword::Spawn(0, SpecialFlags
|NO_MATERIALS
);
4192 Weapon
->InitMaterials(MAKE_MATERIAL(DIAMOND
), MAKE_MATERIAL(ADAMANT
), !(SpecialFlags
& NO_PIC_UPDATE
));
4193 Weapon
->SetEnchantment(4);
4194 SetRightWielded(Weapon
);
4195 Equipment
= shield::Spawn(0, SpecialFlags
|NO_MATERIALS
);
4196 Equipment
->InitMaterials(MAKE_MATERIAL(DIAMOND
), !(SpecialFlags
& NO_PIC_UPDATE
));
4197 Equipment
->SetEnchantment(4);
4198 SetLeftWielded(Equipment
);
4199 GetCWeaponSkill(LARGE_SWORDS
)->AddHit(200000);
4200 GetCWeaponSkill(SHIELDS
)->AddHit(500000);
4201 GetCurrentRightSWeaponSkill()->AddHit(200000);
4202 GetCurrentLeftSWeaponSkill()->AddHit(200000);
4203 GetRightArm()->SetDexterity(70);
4204 GetLeftArm()->SetDexterity(70);
4207 Weapon
= meleeweapon::Spawn(WAR_HAMMER
, SpecialFlags
|NO_MATERIALS
);
4208 Weapon
->InitMaterials(MAKE_MATERIAL(SAPPHIRE
), MAKE_MATERIAL(OCTIRON
), !(SpecialFlags
& NO_PIC_UPDATE
));
4209 Weapon
->SetEnchantment(4);
4210 SetRightWielded(Weapon
);
4211 GetCWeaponSkill(BLUNT_WEAPONS
)->AddHit(500000);
4212 GetCurrentRightSWeaponSkill()->AddHit(200000);
4216 Weapon
= meleeweapon::Spawn(HALBERD
, SpecialFlags
|NO_MATERIALS
);
4217 Weapon
->InitMaterials(MAKE_MATERIAL(RUBY
), MAKE_MATERIAL(OCTIRON
), !(SpecialFlags
& NO_PIC_UPDATE
));
4218 Weapon
->SetEnchantment(4);
4219 SetLeftWielded(Weapon
);
4220 GetCWeaponSkill(POLE_ARMS
)->AddHit(500000);
4221 GetCurrentLeftSWeaponSkill()->AddHit(500000);
4222 GetRightArm()->SetStrength(70);
4223 GetLeftArm()->SetStrength(70);
4227 void zombie::PostConstruct()
4230 GainIntrinsic(LEPROSY
);
4233 void orc::PostConstruct()
4236 GainIntrinsic(LEPROSY
);
4239 truth
mistress::AllowEquipment(citem
* Item
, int EquipmentIndex
) const
4241 return ((EquipmentIndex
!= RIGHT_WIELDED_INDEX
4242 && EquipmentIndex
!= LEFT_WIELDED_INDEX
)
4246 int humanoid::GetAttributeAverage() const
4248 return GetSumOfAttributes() / 9;
4251 void golem::CreateCorpse(lsquare
* Square
)
4253 material
* Material
= GetTorso()->GetMainMaterial();
4255 if(Material
->IsSolid())
4256 Square
->AddItem(Material
->CreateNaturalForm(ItemVolume
));
4263 if(!game::IsLoading())
4264 ItemVolume
= 50 + RAND_N(100);
4267 void golem::Save(outputfile
& SaveFile
) const
4269 humanoid::Save(SaveFile
);
4270 SaveFile
<< ItemVolume
;
4273 void golem::Load(inputfile
& SaveFile
)
4275 humanoid::Load(SaveFile
);
4276 SaveFile
>> ItemVolume
;
4279 truth
humanoid::CanVomit() const
4281 return HasHead() && character::CanVomit();
4284 truth
humanoid::CheckApply() const
4286 if(!character::CheckApply())
4289 if(!HasAUsableArm())
4291 ADD_MESSAGE("You need a usable arm to apply.");
4298 int darkmage::GetSpellAPCost() const
4302 case APPRENTICE
: return 4000;
4303 case BATTLE_MAGE
: return 2000;
4304 case ELDER
: return 1000;
4305 case ARCH_MAGE
: return 500;
4311 int necromancer::GetSpellAPCost() const
4315 case APPRENTICE_NECROMANCER
: return 2000;
4316 case MASTER_NECROMANCER
: return 1000;
4322 /* Horrible repeating. Sorry */
4324 void tailor::BeTalkedTo()
4326 if(GetRelation(PLAYER
) == HOSTILE
)
4328 ADD_MESSAGE("\"You talkin' to me? You talkin' to me? You talkin' to me? Then who the hell else are you talkin' to? You talkin' to me? Well I'm the only one here. Who do you think you're talking to? Oh yeah? Huh? Ok.\"");
4332 if(PLAYER
->PossessesItem(&item::IsFixableByTailor
))
4334 item
* Item
= PLAYER
->SelectFromPossessions(CONST_S("\"What do you want me to fix?\""), &item::IsFixableByTailor
);
4339 if(!(Item
->GetMainMaterial()->GetCategoryFlags() & CAN_BE_TAILORED
))
4341 ADD_MESSAGE("\"I can't work on %s.\"", Item
->GetMainMaterial()->GetName(false, false).CStr());
4345 /** update messages */
4347 sLong FixPrice
= Item
->GetFixPrice();
4349 if(PLAYER
->GetMoney() < FixPrice
)
4351 ADD_MESSAGE("\"Getting that fixed costs you %d gold pieces. Get the money and we'll talk.\"", FixPrice
);
4355 ADD_MESSAGE("\"I can fix your %s, but it'll cost you %d gold pieces.\"", Item
->CHAR_NAME(UNARTICLED
), FixPrice
);
4357 if(game::TruthQuestion(CONST_S("Do you accept this deal? [y/N]")))
4360 PLAYER
->EditMoney(-FixPrice
);
4361 ADD_MESSAGE("%s fixes %s in no time.", CHAR_NAME(DEFINITE
), Item
->CHAR_NAME(DEFINITE
));
4365 ADD_MESSAGE("\"Come back when you have some weapons or armor I can fix.\"");
4368 void veterankamikazedwarf::PostConstruct()
4370 kamikazedwarf::PostConstruct();
4372 game::GetTime(Time
);
4373 int Modifier
= Time
.Day
- KAMIKAZE_INVISIBILITY_DAY_MIN
;
4375 if(Time
.Day
>= KAMIKAZE_INVISIBILITY_DAY_MAX
4377 && RAND_N(KAMIKAZE_INVISIBILITY_DAY_MAX
- KAMIKAZE_INVISIBILITY_DAY_MIN
) < Modifier
))
4378 GainIntrinsic(INVISIBLE
);
4381 truth
humanoid::IsTransparent() const
4383 return character::IsTransparent() || !(GetRightLeg() || GetLeftLeg());
4386 void humanoid::ModifySituationDanger(double& Danger
) const
4388 character::ModifySituationDanger(Danger
);
4390 switch(GetUsableArms())
4392 case 0: Danger
*= 10;
4393 case 1: Danger
*= 2;
4396 switch(GetUsableLegs())
4398 case 0: Danger
*= 10;
4399 case 1: Danger
*= 2;
4403 void oree::GetAICommand()
4408 humanoid::GetAICommand();
4411 void oree::CallForMonsters()
4413 if(GetDungeon()->GetIndex() != ELPURI_CAVE
|| GetLevel()->GetIndex() != OREE_LAIR
)
4416 character
* ToBeCalled
= 0;
4421 ToBeCalled
= darkknight::Spawn(ELITE
);
4424 ToBeCalled
= frog::Spawn(RAND_2
? GREATER_DARK
: GIANT_DARK
);
4427 ToBeCalled
= frog::Spawn(DARK
);
4430 ToBeCalled
= darkmage::Spawn(RAND_2
? APPRENTICE
: BATTLE_MAGE
);
4433 ToBeCalled
= darkmage::Spawn(RAND_2
? APPRENTICE
: ELDER
);
4436 ToBeCalled
= necromancer::Spawn(RAND_2
? APPRENTICE_NECROMANCER
: MASTER_NECROMANCER
);
4442 for(int c
= 0; c
< 100; ++c
)
4444 TryToCreate
= game::GetMonsterPortal()->GetPos() + game::GetMoveVector(RAND() % DIRECTION_COMMAND_KEYS
);
4446 if(GetArea()->IsValidPos(TryToCreate
) && ToBeCalled
->CanMoveOn(GetNearLSquare(TryToCreate
)) && ToBeCalled
->IsFreeForMe(GetNearLSquare(TryToCreate
)))
4448 ToBeCalled
->SetTeam(game::GetTeam(MONSTER_TEAM
));
4449 ToBeCalled
->PutTo(TryToCreate
);
4457 int humanoid::RandomizeTryToUnStickBodyPart(uLong PossibleBodyParts
) const
4459 int Possible
= 0, PossibleArray
[3];
4461 if(RightArmIsUsable() && 1 << RIGHT_ARM_INDEX
& PossibleBodyParts
)
4462 PossibleArray
[Possible
++] = RIGHT_ARM_INDEX
;
4464 if(LeftArmIsUsable() && 1 << LEFT_ARM_INDEX
& PossibleBodyParts
)
4465 PossibleArray
[Possible
++] = LEFT_ARM_INDEX
;
4468 return PossibleArray
[RAND_N(Possible
)];
4470 if(RightLegIsUsable() && 1 << RIGHT_LEG_INDEX
& PossibleBodyParts
)
4471 PossibleArray
[Possible
++] = RIGHT_LEG_INDEX
;
4473 if(LeftLegIsUsable() && 1 << LEFT_LEG_INDEX
& PossibleBodyParts
)
4474 PossibleArray
[Possible
++] = LEFT_LEG_INDEX
;
4477 return PossibleArray
[RAND_N(Possible
)];
4479 if(GetHead() && 1 << HEAD_INDEX
& PossibleBodyParts
)
4482 if(GetGroin() && 1 << GROIN_INDEX
& PossibleBodyParts
)
4483 PossibleArray
[Possible
++] = GROIN_INDEX
;
4485 if(1 << TORSO_INDEX
& PossibleBodyParts
)
4486 PossibleArray
[Possible
++] = TORSO_INDEX
;
4488 return Possible
? PossibleArray
[RAND_N(Possible
)] : NONE_INDEX
;
4491 truth
humanoid::HasAUsableArm() const
4493 arm
* R
= GetRightArm(), * L
= GetLeftArm();
4494 return (R
&& R
->IsUsable()) || (L
&& L
->IsUsable());
4497 truth
humanoid::HasAUsableLeg() const
4499 leg
* R
= GetRightLeg(), * L
= GetLeftLeg();
4500 return (R
&& R
->IsUsable()) || (L
&& L
->IsUsable());
4503 truth
humanoid::HasTwoUsableLegs() const
4505 leg
* R
= GetRightLeg(), * L
= GetLeftLeg();
4506 return R
&& R
->IsUsable() && L
&& L
->IsUsable();
4509 truth
humanoid::CanAttackWithAnArm() const
4511 arm
* R
= GetRightArm();
4513 if(R
&& R
->GetDamage())
4516 arm
* L
= GetLeftArm();
4517 return L
&& L
->GetDamage();
4520 truth
humanoid::RightArmIsUsable() const
4522 arm
* A
= GetRightArm();
4523 return A
&& A
->IsUsable();
4526 truth
humanoid::LeftArmIsUsable() const
4528 arm
* A
= GetLeftArm();
4529 return A
&& A
->IsUsable();
4532 truth
humanoid::RightLegIsUsable() const
4534 leg
* L
= GetRightLeg();
4535 return L
&& L
->IsUsable();
4538 truth
humanoid::LeftLegIsUsable() const
4540 leg
* L
= GetLeftLeg();
4541 return L
&& L
->IsUsable();
4544 truth
humanoid::AllowUnconsciousness() const
4546 return (DataBase
->AllowUnconsciousness
&& TorsoIsAlive()
4547 && BodyPartIsVital(HEAD_INDEX
));
4550 truth
humanoid::CanChokeOnWeb(web
* Web
) const
4552 return CanChoke() && Web
->IsStuckToBodyPart(HEAD_INDEX
);
4555 truth
humanoid::BrainsHurt() const
4557 head
* Head
= GetHead();
4558 return !Head
|| Head
->IsBadlyHurt();
4561 void playerkind::PostConstruct()
4563 int R
= 0, G
= 0, B
= 0;
4567 case 0: R
= 195; G
= 165; B
= 40; break;
4568 case 1: R
= 130; G
= 30; B
= 0; break;
4569 case 2: R
= 30; G
= 30; B
= 15; break;
4570 case 3: R
= 50; G
= 30; B
= 5; break;
4573 HairColor
= MakeRGB16(R
+ RAND_N(41), G
+ RAND_N(41), B
+ RAND_N(41));
4577 case 0: R
= 25; G
= 0; B
= 70; break;
4578 case 1: R
= 5; G
= 0; B
= 50; break;
4579 case 2: R
= 10; G
= 10; B
= 10; break;
4580 case 3: R
= 60; G
= 20; B
= 0; break;
4583 EyeColor
= MakeRGB16(R
+ RAND_N(41), G
+ RAND_N(41), B
+ RAND_N(41));
4584 Talent
= RAND_N(TALENTS
);
4585 Weakness
= RAND_N(TALENTS
);
4588 v2
playerkind::GetHeadBitmapPos() const
4590 int Sum
= GetAttribute(INTELLIGENCE
, false) + GetAttribute(WISDOM
, false);
4600 v2
playerkind::GetRightArmBitmapPos() const
4602 if(GetRightArm()->GetAttribute(ARM_STRENGTH
, false) >= 20)
4608 v2
playerkind::GetLeftArmBitmapPos() const
4610 if(GetLeftArm()->GetAttribute(ARM_STRENGTH
, false) >= 20)
4616 int playerkind::GetNaturalSparkleFlags() const
4618 return GetAttribute(CHARISMA
) >= 30 ? SKIN_COLOR
: 0;
4621 void slave::PostConstruct()
4623 Talent
= TALENT_STRONG
;
4624 Weakness
= TALENT_CLEVER
;
4627 cint TalentOfAttribute
[ATTRIBUTES
] = { TALENT_HEALTHY
, TALENT_FAST_N_ACCURATE
, TALENT_CLEVER
, TALENT_CLEVER
, TALENT_CLEVER
, TALENT_CLEVER
, TALENT_CLEVER
, TALENT_STRONG
, TALENT_STRONG
, TALENT_FAST_N_ACCURATE
, TALENT_FAST_N_ACCURATE
};
4628 const double TalentBonusOfAttribute
[ATTRIBUTES
] = { 1.1, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25 };
4630 double playerkind::GetNaturalExperience(int Identifier
) const
4632 double NE
= DataBase
->NaturalExperience
[Identifier
];
4634 if(Talent
== TalentOfAttribute
[Identifier
])
4635 NE
*= TalentBonusOfAttribute
[Identifier
];
4637 if(Weakness
== TalentOfAttribute
[Identifier
])
4638 NE
/= TalentBonusOfAttribute
[Identifier
];
4643 cchar
* humanoid::GetRunDescriptionLine(int I
) const
4645 if(!GetRunDescriptionLineOne().IsEmpty())
4646 return !I
? GetRunDescriptionLineOne().CStr() : GetRunDescriptionLineTwo().CStr();
4649 return !I
? "Flying" : "very fast";
4653 if(!GetRightArm() && !GetLeftArm() && !GetRightLeg() && !GetLeftLeg())
4654 return !I
? "Floating" : "ahead fast";
4656 return !I
? "Swimming" : "very fast";
4659 if(!GetRightLeg() && !GetLeftLeg())
4660 return !I
? "Rolling" : "very fast";
4662 if(!GetRightLeg() || !GetLeftLeg())
4663 return !I
? "Hopping" : "very fast";
4665 return !I
? "Running" : "";
4668 cchar
* humanoid::GetNormalDeathMessage() const
4670 if(BodyPartIsVital(HEAD_INDEX
) && (!GetHead() || GetHead()->GetHP() <= 0))
4671 return "beheaded @k";
4672 else if(BodyPartIsVital(GROIN_INDEX
) && (!GetGroin() || GetGroin()->GetHP() <= 0))
4673 return "killed @bkp dirty attack below the belt";
4678 void kamikazedwarf::SingRandomSong()
4681 festring God
= GetMasterGod()->GetName();
4695 Bodypart
= "forehead";
4699 Bodypart
= "tongue";
4702 Song
= festring("On the ") + Bodypart
+ festring(" of ") + God
+ " everybody fears everything";
4706 festring Title
= GetMasterGod()->GetSex() == MALE
? "King" : "Queen";
4707 Song
= festring("Joy to the world, ") + God
4708 + " is come! Let all above Valpurus receive her " + Title
;
4712 Song
= festring("Hark the herald angels sing. Glory to ") + God
+ "!";
4715 Song
= festring("O ") + God
4716 + ", You are so big, So absolutely huge, Gosh, "
4717 "we're all really impressed down here, I can tell You.";
4720 Song
= festring("Forgive us, O ") + God
4721 + " for this, our dreadful toadying and barefaced flattery";
4724 Song
= festring("But you, ") + God
4725 + ", are so strong and, well, just so super fantastic. Amen.";
4728 Song
= festring("O ") + God
+ ", please don't burn us";
4731 Song
= festring("O ") + God
+ ", please don't grill or toast your flock";
4734 Song
= festring("O ") + God
+ ", please don't simmer us in stock";
4740 if(CanBeSeenByPlayer())
4741 ADD_MESSAGE("%s sings: \"%s\"",
4742 CHAR_DESCRIPTION(DEFINITE
), Song
.CStr());
4744 ADD_MESSAGE("You hear someone sing: \"%s\"", Song
.CStr());
4747 void humanoid::ApplySpecialAttributeBonuses()
4751 AttributeBonus
[CHARISMA
] -= GetHead()->
4752 CalculateScarAttributePenalty(GetAttribute(CHARISMA
, false));
4755 AttributeBonus
[CHARISMA
] -= GetAttribute(CHARISMA
, false) - 1;
4758 void siren::GetAICommand()
4763 humanoid::GetAICommand();
4766 truth
siren::TryToSing()
4768 truth Success
=false;
4769 for(int d
= 0; d
< GetNeighbourSquares(); ++d
)
4771 lsquare
* Square
= GetNeighbourLSquare(d
);
4773 if(Square
&& Square
->GetCharacter())
4776 Square
->GetCharacter()->ReceiveSirenSong(this);
4785 truth
humanoid::MindWormCanPenetrateSkull(mindworm
* Worm
) const
4789 if(RAND_N(102) > GetHelmet()->GetCoverPercentile())
4798 truth
humanoid::HasSadistWeapon() const
4800 arm
* Right
= GetRightArm(), * Left
= GetLeftArm();
4801 return (Right
&& Right
->HasSadistWeapon()) || (Left
&& Left
->HasSadistWeapon());
4804 truth
humanoid::HasSadistAttackMode() const
4806 return HasSadistWeapon() || IsUsingLegs();
4809 void petrusswife::Save(outputfile
& SaveFile
) const
4811 humanoid::Save(SaveFile
);
4812 SaveFile
<< GiftTotal
;
4815 void petrusswife::Load(inputfile
& SaveFile
)
4817 humanoid::Load(SaveFile
);
4818 SaveFile
>> GiftTotal
;
4821 void petrusswife::BeTalkedTo()
4825 if(!PLAYER
->SelectFromPossessions(Item
, CONST_S("Do you have something to give me?"), 0, &item::IsLuxuryItem
)
4827 humanoid::BeTalkedTo();
4830 truth RefusedSomething
= false;
4832 for(unsigned int c
= 0; c
< Item
.size(); ++c
)
4833 if(!MakesBurdened(GetCarriedWeight() + Item
[c
]->GetWeight()))
4836 GiftTotal
+= Item
[c
]->GetTruePrice();
4837 Item
[c
]->RemoveFromSlot();
4838 GetStack()->AddItem(Item
[c
]);
4842 RefusedSomething
= true;
4847 ADD_MESSAGE("\"I thank you for your little gift%s.\"", Accepted
== 1 ? "" : "s");
4849 if(RefusedSomething
)
4850 ADD_MESSAGE("\"Unfortunately I cannot carry any more of your gifts. I'm a delicate woman, you see.\"");
4853 void guard::BeTalkedTo()
4857 if(!PLAYER
->SelectFromPossessions(Item
, CONST_S("Do you have something to give me?"), 0, &item::IsBeverage
)
4859 humanoid::BeTalkedTo();
4861 for(unsigned int c
= 0; c
< Item
.size(); ++c
)
4863 Item
[c
]->RemoveFromSlot();
4864 GetStack()->AddItem(Item
[c
]);
4869 void denim::GetAICommand () {
4871 for (int c
= 0; c
< game::GetTeams(); ++c
) {
4872 if (GetTeam()->GetRelation(game::GetTeam(c
)) == HOSTILE
) Enemies
+= game::GetTeam(c
)->GetEnabledMembers();
4878 v2
wisefarmer::GetHeadBitmapPos () const { return v2(96, (4 + (RAND() & 1)) << 4); }
4879 v2
wisefarmer::GetRightArmBitmapPos () const { return v2(64, (RAND() & 1) << 4); }
4881 void wisefarmer::GetAICommand () {
4883 for (int c
= 0; c
< game::GetTeams(); ++c
) {
4884 if (GetTeam()->GetRelation(game::GetTeam(c
)) == HOSTILE
) Enemies
+= game::GetTeam(c
)->GetEnabledMembers();
4890 void raven::GetAICommand () {
4892 for (int c
= 0; c
< game::GetTeams(); ++c
) {
4893 if (GetTeam()->GetRelation(game::GetTeam(c
)) == HOSTILE
) Enemies
+= game::GetTeam(c
)->GetEnabledMembers();
4899 void vulcan::GetAICommand () {
4901 for (int c
= 0; c
< game::GetTeams(); ++c
) {
4902 if (GetTeam()->GetRelation(game::GetTeam(c
)) == HOSTILE
) Enemies
+= game::GetTeam(c
)->GetEnabledMembers();
4908 truth
rogue::IsRetreating () const {
4909 if (humanoid::IsRetreating()) return true;
4910 for (stackiterator i
= GetStack()->GetBottom(); i
.HasItem(); ++i
) if ((*i
)->GetSparkleFlags()) return true;
4915 void rogue::GetAICommand () {
4916 if (!IsRetreating()) {
4917 character
*Char
= GetRandomNeighbour();
4919 itemvector Sparkling
;
4920 for (stackiterator i
= Char
->GetStack()->GetBottom(); i
.HasItem(); ++i
) {
4921 if ((*i
)->GetSparkleFlags() && !MakesBurdened((*i
)->GetWeight())) Sparkling
.push_back(*i
);
4923 if (!Sparkling
.empty()) {
4924 item
*ToSteal
= Sparkling
[RAND() % Sparkling
.size()];
4925 ToSteal
->RemoveFromSlot();
4926 GetStack()->AddItem(ToSteal
);
4927 if (Char
->IsPlayer()) ADD_MESSAGE("%s steals your %s.", CHAR_NAME(DEFINITE
), ToSteal
->CHAR_NAME(UNARTICLED
));
4933 humanoid::GetAICommand();
4937 void assassin::BeTalkedTo () {
4938 if (GetRelation(PLAYER
) == HOSTILE
) {
4939 if (PLAYER
->GetMoney() >= 1500) {
4940 ADD_MESSAGE("%s talks: \"If you shell out 1500 gold pieces I'll join your side\"", CHAR_DESCRIPTION(DEFINITE
));
4941 if (game::TruthQuestion(CONST_S("Do you want to bribe him? [y/N]"))) {
4942 PLAYER
->SetMoney(PLAYER
->GetMoney()-1500);
4943 ChangeTeam(PLAYER
->GetTeam());
4947 ADD_MESSAGE("\"Trying to reason me with diplomancy won't work on me.\"");
4953 ///////////////////////////////////////////////////////////////////////////////
4954 petrus::petrus () : LastHealed(0) {
4955 game::SetPetrus(this);
4959 petrus::~petrus () {
4964 void petrus::FinalProcessForBone () {
4965 humanoid::FinalProcessForBone();
4970 truth
petrus::HealFully (character
*ToBeHealed
) {
4971 truth DidSomething
= false;
4972 for (int c
= 0; c
< ToBeHealed
->GetBodyParts(); ++c
) {
4973 if (!ToBeHealed
->GetBodyPart(c
)) {
4974 bodypart
* BodyPart
= 0;
4975 for (std::list
<uLong
>::const_iterator i
= ToBeHealed
->GetOriginalBodyPartID(c
).begin(); i
!= ToBeHealed
->GetOriginalBodyPartID(c
).end(); ++i
) {
4976 BodyPart
= static_cast<bodypart
*>(ToBeHealed
->SearchForItem(*i
));
4977 if (BodyPart
) break;
4979 if (!BodyPart
|| !BodyPart
->CanRegenerate()) continue;
4980 BodyPart
->RemoveFromSlot();
4981 ToBeHealed
->AttachBodyPart(BodyPart
);
4982 BodyPart
->RestoreHP();
4983 DidSomething
= true;
4984 if (ToBeHealed
->IsPlayer())
4985 ADD_MESSAGE("%s attaches your old %s back and heals it.", CHAR_NAME(DEFINITE
), BodyPart
->GetBodyPartName().CStr());
4986 else if (CanBeSeenByPlayer())
4987 ADD_MESSAGE("%s attaches the old %s of %s back and heals it.", CHAR_NAME(DEFINITE
), BodyPart
->GetBodyPartName().CStr(), ToBeHealed
->CHAR_DESCRIPTION(DEFINITE
));
4990 if (ToBeHealed
->IsInBadCondition()) {
4991 ToBeHealed
->RestoreLivingHP();
4992 DidSomething
= true;
4993 if (ToBeHealed
->IsPlayer())
4994 ADD_MESSAGE("%s heals you fully.", CHAR_DESCRIPTION(DEFINITE
));
4995 else if (CanBeSeenByPlayer())
4996 ADD_MESSAGE("%s heals %s fully.", CHAR_DESCRIPTION(DEFINITE
), ToBeHealed
->CHAR_DESCRIPTION(DEFINITE
));
4998 if (ToBeHealed
->TemporaryStateIsActivated(POISONED
)) {
4999 ToBeHealed
->DeActivateTemporaryState(POISONED
);
5000 DidSomething
= true;
5001 if (ToBeHealed
->IsPlayer())
5002 ADD_MESSAGE("%s removes the foul poison in your body.", CHAR_DESCRIPTION(DEFINITE
));
5003 else if (CanBeSeenByPlayer())
5004 ADD_MESSAGE("%s removes the foul poison in %s's body.", CHAR_DESCRIPTION(DEFINITE
), ToBeHealed
->CHAR_DESCRIPTION(DEFINITE
));
5007 LastHealed
= game::GetTick();
5008 DexterityAction(10);
5015 void petrus::Save (outputfile
&SaveFile
) const {
5016 humanoid::Save(SaveFile
);
5017 SaveFile
<< LastHealed
;
5021 void petrus::Load (inputfile
&SaveFile
) {
5022 humanoid::Load(SaveFile
);
5023 SaveFile
>> LastHealed
;
5024 game::SetPetrus(this);
5028 void petrus::GetAICommand () {
5030 for (int c
= 0; c
< game::GetTeams(); ++c
) {
5031 if (GetTeam()->GetRelation(game::GetTeam(c
)) == HOSTILE
) Enemies
+= game::GetTeam(c
)->GetEnabledMembers();
5034 if (Enemies
&& !RAND_N(250 / Min(Enemies
, 50))) {
5035 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s shouts a magnificent prayer to Valpurus.", CHAR_NAME(DEFINITE
));
5036 angel
*Angel
= angel::Spawn(VALPURUS
);
5037 Angel
->SetLifeExpectancy(10000, 0);
5038 v2 Where
= GetLevel()->GetNearestFreeSquare(Angel
, GetPos());
5039 if (Where
== ERROR_V2
) Where
= GetLevel()->GetRandomSquare(Angel
);
5040 Angel
->SetTeam(GetTeam());
5041 Angel
->PutTo(Where
);
5042 if (Angel
->CanBeSeenByPlayer()) ADD_MESSAGE("%s materializes.", Angel
->CHAR_NAME(INDEFINITE
));
5047 if (HP
<< 1 < MaxHP
&& (GetPos() - v2(28, 20)).GetLengthSquare() > 400 && !RAND_N(10)) {
5048 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s disappears.", CHAR_NAME(DEFINITE
));
5049 GetLevel()->GetLSquare(28, 20)->KickAnyoneStandingHereAway();
5050 Move(v2(28, 20), true);
5055 if (!LastHealed
|| game::GetTick()-LastHealed
> 16384) {
5056 for (int d
= 0; d
< GetNeighbourSquares(); ++d
) {
5057 square
*Square
= GetNeighbourSquare(d
);
5059 character
*Char
= Square
->GetCharacter();
5060 if (Char
&& GetRelation(Char
) == FRIEND
&& HealFully(Char
)) return;
5069 void petrus::CreateCorpse (lsquare
*Square
) {
5070 if (game::GetStoryState() == 2) game::GetTeam(ATTNAM_TEAM
)->SetRelation(game::GetTeam(PLAYER_TEAM
), FRIEND
);
5071 Square
->AddItem(leftnutofpetrus::Spawn());
5076 void petrus::BeTalkedTo () {
5077 if (GetRelation(PLAYER
) == HOSTILE
) {
5078 ADD_MESSAGE("Heretic! Dev/null is a place not worthy to receive thee!");
5082 if (PLAYER
->HasGoldenEagleShirt()) {
5083 ADD_MESSAGE("Petrus smiles. \"Thou hast defeated Oree! Mayst thou be blessed by Valpurus for the rest of thy life! And thou possess the Shirt of the Golden Eagle, the symbol of Our status! Return it now, please.\"");
5084 if (game::TruthQuestion(CONST_S("Will you give the Shirt of the Golden Eagle to Petrus? [y/n]"), REQUIRES_ANSWER
)) {
5085 game::TextScreen(CONST_S(
5086 "The Holy Shirt is returned to its old owner and you kneel down to receive your reward.\n"
5087 "Petrus taps your shoulder with the Justifier and raises you to nobility."));
5088 if (true || game::TruthQuestion(CONST_S("Do you want to become a duke? [y/n]"), REQUIRES_ANSWER
)) {
5089 game::TextScreen(CONST_S(
5090 "Later you receive a small dukedom in the middle of tundra\n"
5091 "where you rule with justice till the end of your content life.\n\n"
5092 "You are victorious!"));
5093 game::GetCurrentArea()->SendNewDrawRequest();
5094 game::DrawEverything();
5095 PLAYER
->ShowAdventureInfo();
5096 festring Msg
= CONST_S("retrieved the Shirt of the Golden Eagle and was raised to nobility");
5097 AddScoreEntry(Msg
, 4, false);
5100 GetArea()->SendNewDrawRequest();
5104 ADD_MESSAGE("Petrus's face turns red. \"I see. Thy greed hath overcome thy wisdom. Then, we shall fight for the shiny shirt. May Valpurus bless him who is better.\"");
5105 /* And now we actually make his face change color ;-) */
5106 GetHead()->GetMainMaterial()->SetSkinColor(MakeRGB16(255, 75, 50));
5107 GetHead()->UpdatePictures();
5108 SendNewDrawRequest();
5109 game::AskForEscPress(CONST_S("You are attacked!"));
5110 PLAYER
->GetTeam()->Hostility(GetTeam());
5111 game::SetStoryState(2);
5115 if (PLAYER
->HasHeadOfElpuri()) {
5116 game::TextScreen(CONST_S(
5117 "You have slain Elpuri, and Petrus grants you the freedom you desire.\n"
5118 "You spend the next months in Attnam as an honored hero."));
5119 if (true || game::TruthQuestion(CONST_S("Do you want to sail beyond the sunset? [y/n]"), REQUIRES_ANSWER
)) {
5120 game::TextScreen(CONST_S(
5121 "When the sea finally melts, you board the first ship,\n"
5122 "leaving your past forever behind.\n\n"
5123 "You are victorious!"));
5124 game::GetCurrentArea()->SendNewDrawRequest();
5125 game::DrawEverything();
5126 PLAYER
->ShowAdventureInfo();
5127 festring Msg
= CONST_S("defeated Elpuri and continued to further adventures");
5128 AddScoreEntry(Msg
, 2, false);
5131 GetArea()->SendNewDrawRequest();
5136 if (!game::GetStoryState()) {
5137 if (PLAYER
->RemoveEncryptedScroll()) {
5138 game::TextScreen(CONST_S(
5139 "You kneel down and bow before the high priest and hand him the encrypted scroll.\n"
5140 "Petrus raises his arm, the scroll glows yellow, and lo! The letters are clear and\n"
5141 "readable. Petrus asks you to voice them aloud. The first two thousand words praise\n"
5142 "Valpurus the Creator and all His manifestations and are followed by a canticle of\n"
5143 "Saint Petrus the Lion-Hearted lasting roughly three thousand words. Finally there\n"
5144 "are some sentences actually concerning your mission:\n\n"
5145 "\"Alas, I fear dirty tongues have spread lies to my Lord's ears. I assure all tales\n"
5146 "of treasures here in New Attnam are but mythic legends. There is nothing of value here.\n"
5147 "The taxes are already an unbearable burden and I can't possibly pay more. However I do\n"
5148 "not question the wisdom of the government's decisions. I will contribute what I can:\n"
5149 "the ostriches will deliver an extra 10000 bananas to the capital and additionally the\n"
5150 "slave that brought the message will henceforth be at Your disposal. I am certain this\n"
5151 "satisfies the crown's needs.\"\n\n"
5152 "\"Yours sincerely,\n"
5153 "Richel Decos, the viceroy of New Attnam\""));
5154 game::TextScreen(CONST_S(
5155 "You almost expected the last bit. Petrus seems to be deep in his thoughts and you\n"
5156 "wonder what shape your destiny is taking in his mind. Suddenly he seems to return\n"
5157 "to this reality and talks to you.\n\n"
5158 "\"Oh, thou art still here. We were just discussing telepathically with Sir Galladon.\n"
5159 "We started doubting Decos's alleged poverty a while back when he bought a couple of\n"
5160 "medium-sized castles nearby. Thy brethren from New Attnam have also told Us about\n"
5161 "vast riches seized from them. Our law says all such stolen valuables belong to\n"
5162 "the Cathedral's treasury, so this is a severe claim. However, proof is needed,\n"
5163 "and even if such was provided, We couldn't send soldiers over the snow fields\n"
5165 if (game::GetLiberator()) {
5166 //TODO: do something?
5167 game::TextScreen(CONST_S(
5168 "\"Thy brethren from New Attnam have also told Us that Decos dies while sleeping.\n"
5169 "While We are sad to hear this, We hope that We shall not be forced to send our\n"
5170 "soldiers to New Attnam. We are sure that Our people there will work even better now.\""));
5172 game::TextScreen(CONST_S(
5173 "\"However, since thou now servest Us, We ought to find thee something to do. Sir\n"
5174 "Galladon hath told Us his agents witnessed thou leaving the dreaded underwater tunnel.\n"
5175 "This means thou most likely hast defeated genetrix vesana and art a talented warrior.\n"
5176 "We happen to have a task perfect for such a person. An evil dark frog named Elpuri who\n"
5177 "hates Valpurus and Attnam more than anything hath taken control over an abandoned mine\n"
5178 "nearby. It is pestering our fine city in many ways and reconnaissance has reported an\n"
5179 "army of monsters gathering in the cave. Our guards are not trained to fight underground\n"
5180 "and We dare not send them. To make things worse, someone hath recently stolen Us the\n"
5181 "greatest armor in existence - the Shirt of the Golden Eagle. Elpuri cannot wear\n"
5182 "it but he who can is now nearly immortal.\"\n\n"
5183 "\"We have marked the location of the gloomy cave on thy world map. We want you to dive\n"
5184 "into it and slay the vile frog. Bring Us its head and We reward thee with freedom.\n"
5185 "Shouldst thou also find the Shirt, We'll knight thee. Good luck, and return when\n"
5186 "thou hast succeeded.\""));
5187 game::LoadWorldMap();
5188 v2 ElpuriCavePos
= game::GetWorldMap()->GetEntryPos(0, ELPURI_CAVE
);
5189 game::GetWorldMap()->GetWSquare(ElpuriCavePos
)->ChangeOWTerrain(elpuricave::Spawn());
5190 game::GetWorldMap()->RevealEnvironment(ElpuriCavePos
, 1);
5191 game::SaveWorldMap();
5192 GetArea()->SendNewDrawRequest();
5193 ADD_MESSAGE("\"And by the way, visit the librarian. He might have advice for thee.\"");
5194 game::SetStoryState(1);
5196 ADD_MESSAGE("\"Yes, citizen? We are quite busy now, thou shalt not disturb Us without proper cause.\"");
5200 /* StoryState == 1 */
5201 ADD_MESSAGE("Petrus says: \"Bring me the head of Elpuri and we'll talk.\"");
5205 truth
petrus::MoveTowardsHomePos () {
5206 if (GetPos() != v2(28, 20)) {
5207 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s disappears.", CHAR_NAME(DEFINITE
));
5208 GetLevel()->GetLSquare(28, 20)->KickAnyoneStandingHereAway();
5209 Move(v2(28, 20), true);
5210 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s appears.", CHAR_NAME(DEFINITE
));
5218 ///////////////////////////////////////////////////////////////////////////////
5219 void raven::BeTalkedTo () {
5220 if (GetRelation(PLAYER
) == HOSTILE
) {
5221 ADD_MESSAGE("I bet you are with those filthy Attnamanese bastards!");
5224 if (!game::GetRingOfThieves()) {
5225 if (PLAYER
->RemoveRingOfThieves()) {
5226 game::TextScreen(CONST_S(
5227 "You hand over the Ring of Thieves, Raven's eyes glow in amazement.\n"
5228 "\"May Cleptia bless this mighty warrior, whom vanquished Vulcan-Loki!\n"
5229 "Retrieving the ring is no easy task, Vulcan is a powerful adversary.\n"
5230 "The importance of the Ring of Thieves is great. It is used to channel\n"
5231 "Cleptia's power to help Mondedr avoid it's enemies, including Petrus.\n"
5232 "Without it we would have been raided by every nation that hates us.\n"
5233 "Not a mere mortal like Vulcan-Loki could channel the ring's power for\n"
5234 "himself so he decided to contract a deal with Oree to assist him.\n"
5235 "To reward your efforts I will give you the artifact whip, Gleipnir.\"\n\n"
5236 "\"I pray to Cleptia that you will use it well..\"\n\n"""));
5237 game::GetGod(CLEPTIA
)->AdjustRelation(500);
5238 game::GetGod(NEFAS
)->AdjustRelation(50);
5239 game::GetGod(SCABIES
)->AdjustRelation(50);
5240 game::GetGod(INFUSCOR
)->AdjustRelation(50);
5241 game::GetGod(CRUENTUS
)->AdjustRelation(50);
5242 game::GetGod(MORTIFER
)->AdjustRelation(50);
5243 meleeweapon
*Weapon
= whipofthievery::Spawn();
5244 Weapon
->InitMaterials(MAKE_MATERIAL(SPIDER_SILK
), MAKE_MATERIAL(EBONY_WOOD
), true);
5245 PLAYER
->GetGiftStack()->AddItem(Weapon
);
5246 GetArea()->SendNewDrawRequest();
5247 ADD_MESSAGE("A whip materializes near your feet.");
5248 game::SetRingOfThieves(1);
5250 ADD_MESSAGE("\"Mondedr's most important artifact, the Ring of Thieves, has been stolen by Vulcan-Loki; residing at the deepest floor of the underground temple, he awaits Oree to receive it and reward him with incredible power.\"");
5253 /* StoryState == 100 */
5254 ADD_MESSAGE("\"I must thank you again, I hope you make good use of that whip.\"");
5259 ///////////////////////////////////////////////////////////////////////////////
5260 void mysteryman::BeTalkedTo () {
5261 if (GetRelation(PLAYER
) == HOSTILE
) {
5262 ADD_MESSAGE("This is why the government doesn't mess with me, fool!");
5265 if (!game::GetMondedrPass()) {
5266 if (PLAYER
->RemoveMondedrPass()) {
5267 game::TextScreen(CONST_S(
5268 "You hand over the mondedr pass,\n"
5269 "the man quickly snatches it and starts reading it right away.\n"
5270 "The man scans the text very quickly, his eyes run around a hundred laps per second.\n"
5271 "His eyes come to a halt.\n"
5272 "\"I have revealed the location of Mondedr.\" He hands you a map.\n"
5273 "\"It is a good thing I was born in this world, no? You owe me nothing, the \n"
5274 "the amount of information in the sheet of paper is what repays it.\"\n\n"""));
5275 game::LoadWorldMap();
5276 v2 MondedrPos
= game::GetWorldMap()->GetEntryPos(0, MONDEDR
);
5277 game::GetWorldMap()->GetWSquare(MondedrPos
)->ChangeOWTerrain(mondedr::Spawn());
5278 game::GetWorldMap()->RevealEnvironment(MondedrPos
, 1);
5279 game::SaveWorldMap();
5280 GetArea()->SendNewDrawRequest();
5281 ADD_MESSAGE("\"And by the way, the government always watches you.\"");
5282 game::SetMondedrPass(1);
5284 ADD_MESSAGE("\"Shoo, come back if you have a sheet of paper they call 'Mondedr Pass'\"");
5287 /* StoryState == 100 */
5288 ADD_MESSAGE("The man says: \"I don't have anymore business with you, shoo.\"");
5293 ///////////////////////////////////////////////////////////////////////////////
5294 void imperialist::BeTalkedTo () {
5295 decosadshirt
*Shirt
= static_cast<decosadshirt
*>(PLAYER
->SearchForItem(this, &item::IsDecosAdShirt
));
5297 uLong Reward
= Shirt
->GetEquippedTicks()/500;
5299 ADD_MESSAGE("%s smiles. \"I see you have advertised our company diligently. Here's %dgp as a token of my gratitude.\"", CHAR_NAME(DEFINITE
), Reward
);
5300 PLAYER
->EditMoney(Reward
);
5301 Shirt
->SetEquippedTicks(0);
5302 } else if (!(RAND()%5)) {
5303 ADD_MESSAGE("\"Come back when you've worn the shirt for some time and I'll reward you generously!\"");
5308 if (GetRelation(PLAYER
) == HOSTILE
)
5309 ProcessAndAddMessage(GetHostileReplies()[RandomizeReply(Said
, GetHostileReplies().Size
)]);
5310 else if (!game::PlayerIsSumoChampion())
5311 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said
, GetFriendlyReplies().Size
)]);
5313 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said
, GetFriendlyReplies().Size
-1)]);
5317 void imperialist::DisplayStethoscopeInfo (character
*) const {
5318 ADD_MESSAGE("You hear coins clinking inside.");
5322 void imperialist::CreateCorpse (lsquare
*Square
) {
5323 if (!game::GetLiberator()) {
5324 game::SetLiberator(1);
5325 ADD_MESSAGE("You liberate citizens of New Attnam!");
5327 imperialistsysbase::CreateCorpse(Square
);
5331 ///////////////////////////////////////////////////////////////////////////////
5332 exiledpriest::exiledpriest () :
5333 exiledpriestsysbase(),
5339 exiledpriest::~exiledpriest () {
5343 void exiledpriest::Save (outputfile
&saveFile
) const {
5344 priest::Save(saveFile
);
5345 saveFile
<< mAtHome
;
5349 void exiledpriest::Load (inputfile
&saveFile
) {
5350 priest::Load(saveFile
);
5351 saveFile
>> mAtHome
;
5355 void exiledpriest::healBodyParts () {
5356 for (int c
= 0; c
< PLAYER
->GetBodyParts(); ++c
) {
5357 if (!PLAYER
->GetBodyPart(c
) && PLAYER
->CanCreateBodyPart(c
)) {
5358 truth HasOld
= false;
5359 for (std::list
<uLong
>::const_iterator i
= PLAYER
->GetOriginalBodyPartID(c
).begin(); i
!= PLAYER
->GetOriginalBodyPartID(c
).end(); ++i
) {
5360 bodypart
*OldBodyPart
= static_cast<bodypart
*>(PLAYER
->SearchForItem(*i
));
5363 if (!OldBodyPart
->CanRegenerate())
5364 ADD_MESSAGE("\"Sorry, I cannot put back bodyparts made of %s, not even your severed %s.\"", OldBodyPart
->GetMainMaterial()->GetName(false, false).CStr(), PLAYER
->GetBodyPartName(c
).CStr());
5366 ADD_MESSAGE("\"I will put your old %s back.\"", PLAYER
->GetBodyPartName(c
).CStr());
5367 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5368 OldBodyPart
->SetHP(1);
5369 OldBodyPart
->RemoveFromSlot();
5370 PLAYER
->AttachBodyPart(OldBodyPart
);
5371 healBodyParts(); //FIXME
5378 ADD_MESSAGE("\"I could summon up a new %s.\"", PLAYER
->GetBodyPartName(c
).CStr());
5380 ADD_MESSAGE("\"Since you don't seem to have your original %s with you, I could summon up a new one.\"", PLAYER
->GetBodyPartName(c
).CStr());
5381 if (game::TruthQuestion(CONST_S("Agreed? [y/N]"))) {
5382 PLAYER
->CreateBodyPart(c
);
5383 PLAYER
->GetBodyPart(c
)->SetHP(1);
5384 healBodyParts(); //FIXME
5392 void exiledpriest::healDeseases () {
5393 if (PLAYER
->TemporaryStateIsActivated(POISONED
)) {
5394 ADD_MESSAGE("\"You seem to be rather ill. I could give you a small dose of antidote.\"");
5395 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5396 ADD_MESSAGE("You feel better.");
5397 PLAYER
->DeActivateTemporaryState(POISONED
);
5400 if (PLAYER
->TemporaryStateIsActivated(PARASITIZED
)) {
5401 ADD_MESSAGE("\"You seem to have something inside you. I could give you a small dose of antidote.\"");
5402 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5403 ADD_MESSAGE("You feel better.");
5404 PLAYER
->DeActivateTemporaryState(PARASITIZED
);
5407 if (PLAYER
->TemporaryStateIsActivated(LEPROSY
)) {
5408 ADD_MESSAGE("\"You seem to have contracted the vile disease of leprosy. I could give you a small dose of medicince.\"");
5409 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5410 ADD_MESSAGE("You feel better.");
5411 PLAYER
->DeActivateTemporaryState(LEPROSY
);
5414 if (PLAYER
->TemporaryStateIsActivated(LYCANTHROPY
)) {
5415 ADD_MESSAGE("\"You seem to be turning into a werewolf quite frequently. Well, everyone has right to little secret habits, but I could pray %s to remove the canine blood from your veins, just so you don't scare our blessed youth.\"", GetMasterGod()->GetName());
5416 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5417 ADD_MESSAGE("You feel better.");
5418 PLAYER
->DeActivateTemporaryState(LYCANTHROPY
);
5424 void exiledpriest::healAll () {
5431 void exiledpriest::BeTalkedTo () {
5432 if (GetRelation(PLAYER
) != HOSTILE
&& game::GetLiberator()) {
5436 "\"Let %s bless you! I can return to my temple now! "
5437 "Get this things and remember how kind %s is!\"",
5438 GetMasterGod()->GetName(), GetMasterGod()->GetName());
5439 //GetMasterGod()->GetObjectPronoun());
5443 potion
*bottle
= potion::Spawn(0, NO_MATERIALS
);
5444 bottle
->InitMaterials(MAKE_MATERIAL(GLASS
), MAKE_MATERIAL(HEALING_LIQUID
));
5445 PLAYER
->GetStack()->AddItem(bottle
);
5446 ADD_MESSAGE("Priestess gives %s to you.", bottle
->CHAR_DESCRIPTION(DEFINITE
));
5449 potion
*bottle
= potion::Spawn(0, NO_MATERIALS
);
5450 bottle
->InitMaterials(MAKE_MATERIAL(GLASS
), MAKE_MATERIAL(ANTIDOTE_LIQUID
));
5451 PLAYER
->GetStack()->AddItem(bottle
);
5452 ADD_MESSAGE("Priestess gives %s to you.", bottle
->CHAR_DESCRIPTION(DEFINITE
));
5454 if (RAND_N(100) >= 90) {
5455 potion
*bottle
= potion::Spawn(0, NO_MATERIALS
);
5456 bottle
->InitMaterials(MAKE_MATERIAL(GLASS
), MAKE_MATERIAL(VODKA
));
5457 PLAYER
->GetStack()->AddItem(bottle
);
5458 ADD_MESSAGE("Priestess gives %s to you.", bottle
->CHAR_DESCRIPTION(DEFINITE
));
5461 ADD_MESSAGE("I will heal you for free.");
5465 priest::BeTalkedTo();
5469 truth
exiledpriest::MoveTowardsHomePos () {
5470 if (!mAtHome
) return false;
5472 if (GetPos() != homePos
) {
5473 SetGoingTo(homePos
);
5474 return MoveTowardsTarget(false) || (!GetPos().IsAdjacent(homePos
) && MoveRandomly());
5480 void exiledpriest::GetAICommand () {
5481 priest::GetAICommand();