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, long 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 long 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 long 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 %ld 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 %ldgp and I'll help you too.\"", PLAYER
->GetBodyPartName(c
).CStr(), Price
);
407 long Price
= GetConfig() == VALPURUS
? 100 : 20;
408 if (PLAYER
->GetMoney() >= Price
) {
410 ADD_MESSAGE("\"I could still summon up a new one for %ld 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 %ld 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 %ldgp first.\"", PLAYER
->GetBodyPartName(c
).CStr(), Price
);
425 if (PLAYER
->TemporaryStateIsActivated(POISONED
)) {
426 long 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 %ld 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 %ld gold pieces and I'll fix that.\"", Price
);
440 if (PLAYER
->TemporaryStateIsActivated(LEPROSY
)) {
441 long 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 %ld 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 %ld gold pieces and I'll fix that.\"", Price
);
455 if (PLAYER
->TemporaryStateIsActivated(LYCANTHROPY
)) {
456 long 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 %ldgp 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 %ldgp 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();
835 int humanoid::GetSize() const
840 Size
+= GetHead()->GetSize();
843 Size
+= GetTorso()->GetSize();
845 leg
* RightLeg
= GetRightLeg();
846 leg
* LeftLeg
= GetLeftLeg();
848 if(LeftLeg
&& RightLeg
)
849 Size
+= Max(LeftLeg
->GetSize(), RightLeg
->GetSize());
851 Size
+= LeftLeg
->GetSize();
853 Size
+= RightLeg
->GetSize();
858 long humanoid::GetBodyPartSize(int I
, int TotalSize
) const
862 case HEAD_INDEX
: return 20;
863 case TORSO_INDEX
: return ((TotalSize
- 20) << 1) / 5;
864 case RIGHT_ARM_INDEX
:
865 case LEFT_ARM_INDEX
: return (TotalSize
- 20) * 3 / 5;
866 case GROIN_INDEX
: return (TotalSize
- 20) / 3;
867 case RIGHT_LEG_INDEX
:
868 case LEFT_LEG_INDEX
: return (TotalSize
- 20) * 3 / 5;
871 ABORT("Illegal humanoid bodypart size request!");
875 long humanoid::GetBodyPartVolume(int I
) const
879 case HEAD_INDEX
: return 4000;
880 case TORSO_INDEX
: return (GetTotalVolume() - 4000) * 13 / 30;
881 case RIGHT_ARM_INDEX
:
882 case LEFT_ARM_INDEX
: return (GetTotalVolume() - 4000) / 10;
883 case GROIN_INDEX
: return (GetTotalVolume() - 4000) / 10;
884 case RIGHT_LEG_INDEX
:
885 case LEFT_LEG_INDEX
: return ((GetTotalVolume() - 4000) << 1) / 15;
888 ABORT("Illegal humanoid bodypart volume request!");
892 bodypart
* humanoid::MakeBodyPart(int I
) const
896 case TORSO_INDEX
: return humanoidtorso::Spawn(0, NO_MATERIALS
);
897 case HEAD_INDEX
: return head::Spawn(0, NO_MATERIALS
);
898 case RIGHT_ARM_INDEX
: return rightarm::Spawn(0, NO_MATERIALS
);
899 case LEFT_ARM_INDEX
: return leftarm::Spawn(0, NO_MATERIALS
);
900 case GROIN_INDEX
: return groin::Spawn(0, NO_MATERIALS
);
901 case RIGHT_LEG_INDEX
: return rightleg::Spawn(0, NO_MATERIALS
);
902 case LEFT_LEG_INDEX
: return leftleg::Spawn(0, NO_MATERIALS
);
905 ABORT("Weird bodypart to make for a humanoid. It must be your fault!");
909 truth
humanoid::ReceiveDamage(character
* Damager
, int Damage
, int Type
, int TargetFlags
, int Direction
, truth Divide
, truth PenetrateArmor
, truth Critical
, truth ShowMsg
)
911 int ChooseFrom
[MAX_BODYPARTS
], BodyParts
= 0;
913 if(TargetFlags
& RIGHT_ARM
&& GetRightArm())
914 ChooseFrom
[BodyParts
++] = 2;
916 if(TargetFlags
& LEFT_ARM
&& GetLeftArm())
917 ChooseFrom
[BodyParts
++] = 3;
919 if(TargetFlags
& RIGHT_LEG
&& GetRightLeg())
920 ChooseFrom
[BodyParts
++] = 5;
922 if(TargetFlags
& LEFT_LEG
&& GetLeftLeg())
923 ChooseFrom
[BodyParts
++] = 6;
925 if(TargetFlags
& HEAD
&& GetHead())
926 ChooseFrom
[BodyParts
++] = 1;
928 if(TargetFlags
& TORSO
&& GetTorso())
929 ChooseFrom
[BodyParts
++] = 0;
931 if(TargetFlags
& GROIN
&& GetGroin())
932 ChooseFrom
[BodyParts
++] = 4;
937 truth Affected
= false;
942 long TotalVolume
= 0;
944 for(c
= 0; c
< BodyParts
; ++c
)
945 TotalVolume
+= GetBodyPart(ChooseFrom
[c
])->GetBodyPartVolume();
947 for(c
= 0; c
< BodyParts
; ++c
)
948 if(ReceiveBodyPartDamage(Damager
, long(Damage
) * GetBodyPart(ChooseFrom
[c
])->GetBodyPartVolume() / TotalVolume
, Type
, ChooseFrom
[c
], Direction
, PenetrateArmor
, Critical
, false))
953 long Possibility
[MAX_BODYPARTS
], PossibilitySum
= 0;
956 for(int c
= 0; c
< BodyParts
; ++c
)
957 PossibilitySum
+= Possibility
[Index
++] = GetBodyPart(ChooseFrom
[c
])->GetBodyPartVolume();
959 Index
= femath::WeightedRand(Possibility
, PossibilitySum
);
960 Affected
= ReceiveBodyPartDamage(Damager
, Damage
, Type
, ChooseFrom
[Index
], Direction
, PenetrateArmor
, Critical
, false);
963 if(!Affected
&& ShowMsg
)
966 ADD_MESSAGE("You are not hurt.");
967 else if(CanBeSeenByPlayer())
968 ADD_MESSAGE("%s is not hurt.", GetPersonalPronoun().CStr());
971 if(DamageTypeAffectsInventory(Type
))
973 for(int c
= 0; c
< GetEquipments(); ++c
)
975 item
* Equipment
= GetEquipment(c
);
978 Equipment
->ReceiveDamage(Damager
, Damage
, Type
);
981 GetStack()->ReceiveDamage(Damager
, Damage
, Type
);
987 arm
* humanoid::GetMainArm() const
989 return GetRightArm() ? GetRightArm() : GetLeftArm();
992 arm
* humanoid::GetSecondaryArm() const
994 return GetRightArm() ? GetLeftArm() : 0;
997 cchar
* humanoid::GetEquipmentName(int I
) const // convert to array
1001 case HELMET_INDEX
: return "helmet";
1002 case AMULET_INDEX
: return "amulet";
1003 case CLOAK_INDEX
: return "cloak";
1004 case BODY_ARMOR_INDEX
: return "body armor";
1005 case BELT_INDEX
: return "belt";
1006 case RIGHT_WIELDED_INDEX
: return "right hand wielded";
1007 case LEFT_WIELDED_INDEX
: return "left hand wielded";
1008 case RIGHT_RING_INDEX
: return "right ring";
1009 case LEFT_RING_INDEX
: return "left ring";
1010 case RIGHT_GAUNTLET_INDEX
: return "right gauntlet";
1011 case LEFT_GAUNTLET_INDEX
: return "left gauntlet";
1012 case RIGHT_BOOT_INDEX
: return "right boot";
1013 case LEFT_BOOT_INDEX
: return "left boot";
1016 return "forbidden piece of cloth";
1019 sorter
humanoid::EquipmentSorter(int I
) const
1023 case HELMET_INDEX
: return &item::IsHelmet
;
1024 case AMULET_INDEX
: return &item::IsAmulet
;
1025 case CLOAK_INDEX
: return &item::IsCloak
;
1026 case BODY_ARMOR_INDEX
: return &item::IsBodyArmor
;
1027 case BELT_INDEX
: return &item::IsBelt
;
1028 case RIGHT_WIELDED_INDEX
:
1029 case LEFT_WIELDED_INDEX
: return 0;
1030 case RIGHT_RING_INDEX
:
1031 case LEFT_RING_INDEX
: return &item::IsRing
;
1032 case RIGHT_GAUNTLET_INDEX
:
1033 case LEFT_GAUNTLET_INDEX
: return &item::IsGauntlet
;
1034 case RIGHT_BOOT_INDEX
:
1035 case LEFT_BOOT_INDEX
: return &item::IsBoot
;
1041 bodypart
* humanoid::GetBodyPartOfEquipment(int I
) const
1049 case BODY_ARMOR_INDEX
:
1052 case RIGHT_WIELDED_INDEX
:
1053 case RIGHT_RING_INDEX
:
1054 case RIGHT_GAUNTLET_INDEX
:
1055 return GetRightArm();
1056 case LEFT_WIELDED_INDEX
:
1057 case LEFT_RING_INDEX
:
1058 case LEFT_GAUNTLET_INDEX
:
1059 return GetLeftArm();
1060 case RIGHT_BOOT_INDEX
:
1061 return GetRightLeg();
1062 case LEFT_BOOT_INDEX
:
1063 return GetLeftLeg();
1069 item
* humanoid::GetEquipment(int I
) const
1073 case HELMET_INDEX
: return GetHelmet();
1074 case AMULET_INDEX
: return GetAmulet();
1075 case CLOAK_INDEX
: return GetCloak();
1076 case BODY_ARMOR_INDEX
: return GetBodyArmor();
1077 case BELT_INDEX
: return GetBelt();
1078 case RIGHT_WIELDED_INDEX
: return GetRightWielded();
1079 case LEFT_WIELDED_INDEX
: return GetLeftWielded();
1080 case RIGHT_RING_INDEX
: return GetRightRing();
1081 case LEFT_RING_INDEX
: return GetLeftRing();
1082 case RIGHT_GAUNTLET_INDEX
: return GetRightGauntlet();
1083 case LEFT_GAUNTLET_INDEX
: return GetLeftGauntlet();
1084 case RIGHT_BOOT_INDEX
: return GetRightBoot();
1085 case LEFT_BOOT_INDEX
: return GetLeftBoot();
1091 void humanoid::SetEquipment(int I
, item
* What
)
1095 case HELMET_INDEX
: SetHelmet(What
); break;
1096 case AMULET_INDEX
: SetAmulet(What
); break;
1097 case CLOAK_INDEX
: SetCloak(What
); break;
1098 case BODY_ARMOR_INDEX
: SetBodyArmor(What
); break;
1099 case BELT_INDEX
: SetBelt(What
); break;
1100 case RIGHT_WIELDED_INDEX
: SetRightWielded(What
); break;
1101 case LEFT_WIELDED_INDEX
: SetLeftWielded(What
); break;
1102 case RIGHT_RING_INDEX
: SetRightRing(What
); break;
1103 case LEFT_RING_INDEX
: SetLeftRing(What
); break;
1104 case RIGHT_GAUNTLET_INDEX
: SetRightGauntlet(What
); break;
1105 case LEFT_GAUNTLET_INDEX
: SetLeftGauntlet(What
); break;
1106 case RIGHT_BOOT_INDEX
: SetRightBoot(What
); break;
1107 case LEFT_BOOT_INDEX
: SetLeftBoot(What
); break;
1111 void humanoid::SwitchToDig(item
* DigItem
, v2 Square
)
1113 dig
* Dig
= dig::Spawn(this);
1117 item
* Item
= GetRightArm()->GetWielded();
1119 if(Item
&& Item
!= DigItem
)
1121 Dig
->SetRightBackupID(GetRightArm()->GetWielded()->GetID());
1122 GetRightArm()->GetWielded()->MoveTo(GetStack());
1128 item
* Item
= GetLeftArm()->GetWielded();
1130 if(Item
&& Item
!= DigItem
)
1132 Dig
->SetLeftBackupID(GetLeftArm()->GetWielded()->GetID());
1133 GetLeftArm()->GetWielded()->MoveTo(GetStack());
1137 if(GetMainWielded() != DigItem
)
1139 Dig
->SetMoveDigger(true);
1140 DigItem
->RemoveFromSlot();
1142 if(GetMainArm() && GetMainArm()->IsUsable())
1143 GetMainArm()->SetWielded(DigItem
);
1145 GetSecondaryArm()->SetWielded(DigItem
);
1148 Dig
->SetMoveDigger(false);
1150 Dig
->SetSquareDug(Square
);
1154 truth
humanoid::CheckKick() const
1159 ADD_MESSAGE("This race can't kick.");
1164 if(GetUsableLegs() < 2)
1167 ADD_MESSAGE("How are you going to do that with %s?", GetUsableLegs() ? "only one usable leg" : "no usable legs");
1175 int humanoid::GetUsableLegs() const
1179 if(RightLegIsUsable())
1182 if(LeftLegIsUsable())
1188 int humanoid::GetUsableArms() const
1192 if(RightArmIsUsable())
1195 if(LeftArmIsUsable())
1201 truth
humanoid::CheckThrow() const
1203 if(!character::CheckThrow())
1210 ADD_MESSAGE("You don't have a usable arm to do that!");
1215 truth
humanoid::CheckOffer() const
1221 ADD_MESSAGE("You need a usable arm to offer.");
1226 v2
humanoid::GetEquipmentPanelPos(int I
) const // convert to array
1230 case HELMET_INDEX
: return v2(34, -22);
1231 case AMULET_INDEX
: return v2(14, -22);
1232 case CLOAK_INDEX
: return v2(-6, -22);
1233 case BODY_ARMOR_INDEX
: return v2(54, -22);
1234 case BELT_INDEX
: return v2(24, 70);
1235 case RIGHT_WIELDED_INDEX
: return v2(-14, 4);
1236 case LEFT_WIELDED_INDEX
: return v2(62, 4);
1237 case RIGHT_RING_INDEX
: return v2(-14, 44);
1238 case LEFT_RING_INDEX
: return v2(62, 44);
1239 case RIGHT_GAUNTLET_INDEX
: return v2(-14, 24);
1240 case LEFT_GAUNTLET_INDEX
: return v2(62, 24);
1241 case RIGHT_BOOT_INDEX
: return v2(4, 70);
1242 case LEFT_BOOT_INDEX
: return v2(44, 70);
1248 void humanoid::DrawSilhouette(truth AnimationDraw
) const
1251 blitdata B1
= { DOUBLE_BUFFER
,
1254 { TILE_SIZE
, TILE_SIZE
},
1255 { ivanconfig::GetContrastLuminance() },
1259 v2
Where(RES
.X
- SILHOUETTE_SIZE
.X
- 39, 53);
1260 cint Equipments
= GetEquipments();
1262 if(CanUseEquipment())
1263 for(c
= 0; c
< Equipments
; ++c
)
1264 if(GetBodyPartOfEquipment(c
) && EquipmentIsAllowed(c
))
1266 v2 Pos
= Where
+ GetEquipmentPanelPos(c
);
1269 DOUBLE_BUFFER
->DrawRectangle(Pos
+ v2(-1, -1), Pos
+ TILE_V2
, DARK_GRAY
);
1271 item
* Equipment
= GetEquipment(c
);
1273 if(Equipment
&& (!AnimationDraw
|| Equipment
->IsAnimated()))
1275 igraph::BlitBackGround(Pos
, TILE_V2
);
1278 if(Equipment
->AllowAlphaEverywhere())
1279 B1
.CustomData
|= ALLOW_ALPHA
;
1281 Equipment
->Draw(B1
);
1282 B1
.CustomData
&= ~ALLOW_ALPHA
;
1288 blitdata B2
= { DOUBLE_BUFFER
,
1290 { Where
.X
+ 8, Where
.Y
},
1291 { SILHOUETTE_SIZE
.X
, SILHOUETTE_SIZE
.Y
},
1296 for(int c
= 0; c
< BodyParts
; ++c
)
1298 bodypart
* BodyPart
= GetBodyPart(c
);
1302 int Type
= BodyPart
->IsUsable() ? SILHOUETTE_NORMAL
: SILHOUETTE_INTER_LACED
;
1303 bitmap
* Cache
= igraph::GetSilhouetteCache(c
, BodyPart
->GetConditionColorIndex(), Type
);
1304 Cache
->NormalMaskedBlit(B2
);
1305 BodyPart
->DrawScars(B2
);
1311 int humanoid::GetGlobalResistance(int Type
) const
1313 int Resistance
= GetResistance(Type
);
1316 Resistance
+= GetCloak()->GetResistance(Type
);
1318 if(!(Type
& PHYSICAL_DAMAGE
))
1321 Resistance
+= GetAmulet()->GetResistance(Type
);
1324 Resistance
+= GetRightRing()->GetResistance(Type
);
1327 Resistance
+= GetLeftRing()->GetResistance(Type
);
1333 truth
humanoid::TryToRiseFromTheDead()
1337 for(c
= 0; c
< BodyParts
; ++c
)
1340 bodypart
* BodyPart
= SearchForOriginalBodyPart(c
);
1344 BodyPart
->RemoveFromSlot();
1345 AttachBodyPart(BodyPart
);
1350 for(c
= 0; c
< BodyParts
; ++c
)
1352 bodypart
* BodyPart
= GetBodyPart(c
);
1354 if(BodyPartIsVital(c
) && !BodyPart
)
1355 if(!HandleNoBodyPart(c
))
1360 BodyPart
->ResetSpoiling();
1362 if(BodyPart
->CanRegenerate() || BodyPart
->GetHP() < 1)
1371 truth
humanoid::HandleNoBodyPart(int I
)
1376 if(CanBeSeenByPlayer())
1377 ADD_MESSAGE("The headless body of %s vibrates violently.", CHAR_NAME(DEFINITE
));
1381 if(CanBeSeenByPlayer())
1382 ADD_MESSAGE("The groinless body of %s vibrates violently.", CHAR_NAME(DEFINITE
));
1386 ABORT("The corpse does not have a torso.");
1392 v2
humanoid::GetBodyPartBitmapPos(int I
, truth
) const
1396 case TORSO_INDEX
: return GetTorsoBitmapPos();
1397 case HEAD_INDEX
: return GetHeadBitmapPos();
1398 case RIGHT_ARM_INDEX
: return GetRightArmBitmapPos();
1399 case LEFT_ARM_INDEX
: return GetLeftArmBitmapPos();
1400 case GROIN_INDEX
: return GetGroinBitmapPos();
1401 case RIGHT_LEG_INDEX
: return GetRightLegBitmapPos();
1402 case LEFT_LEG_INDEX
: return GetLeftLegBitmapPos();
1405 ABORT("Weird bodypart BitmapPos request for a humanoid!");
1409 col16
humanoid::GetBodyPartColorB(int I
, truth
) const
1413 case TORSO_INDEX
: return GetTorsoMainColor();
1414 case HEAD_INDEX
: return GetCapColor();
1415 case RIGHT_ARM_INDEX
:
1416 case LEFT_ARM_INDEX
: return GetArmMainColor();
1418 case RIGHT_LEG_INDEX
:
1419 case LEFT_LEG_INDEX
: return GetLegMainColor();
1422 ABORT("Weird bodypart col B request for a humanoid!");
1426 col16
humanoid::GetBodyPartColorC(int I
, truth
) const
1430 case TORSO_INDEX
: return GetBeltColor();
1431 case HEAD_INDEX
: return GetHairColor();
1432 case RIGHT_ARM_INDEX
:
1433 case LEFT_ARM_INDEX
: return GetGauntletColor();
1435 case RIGHT_LEG_INDEX
:
1436 case LEFT_LEG_INDEX
: return GetBootColor();
1439 ABORT("Weird bodypart col C request for a humanoid!");
1443 col16
humanoid::GetBodyPartColorD(int I
, truth
) const
1447 case TORSO_INDEX
: return GetTorsoSpecialColor();
1448 case HEAD_INDEX
: return GetEyeColor();
1449 case RIGHT_ARM_INDEX
:
1450 case LEFT_ARM_INDEX
: return GetArmSpecialColor();
1452 case RIGHT_LEG_INDEX
:
1453 case LEFT_LEG_INDEX
: return GetLegSpecialColor();
1456 ABORT("Weird bodypart col D request for a humanoid!");
1460 int humanoid::GetBodyPartSparkleFlags(int I
) const
1462 truth Sparkling
= false;
1463 int SparkleFlags
= GetNaturalSparkleFlags() & SKIN_COLOR
? SPARKLING_A
: 0;
1467 case TORSO_INDEX
: Sparkling
= GetNaturalSparkleFlags() & TORSO_MAIN_COLOR
; break;
1468 case HEAD_INDEX
: Sparkling
= GetNaturalSparkleFlags() & CAP_COLOR
; break;
1469 case RIGHT_ARM_INDEX
:
1470 case LEFT_ARM_INDEX
: Sparkling
= GetNaturalSparkleFlags() & ARM_MAIN_COLOR
; break;
1472 case RIGHT_LEG_INDEX
:
1473 case LEFT_LEG_INDEX
: Sparkling
= GetNaturalSparkleFlags() & LEG_MAIN_COLOR
; break;
1476 SparkleFlags
|= Sparkling
? SPARKLING_B
: 0;
1481 case TORSO_INDEX
: Sparkling
= GetNaturalSparkleFlags() & BELT_COLOR
; break;
1482 case HEAD_INDEX
: Sparkling
= GetNaturalSparkleFlags() & HAIR_COLOR
; break;
1483 case RIGHT_ARM_INDEX
:
1484 case LEFT_ARM_INDEX
: Sparkling
= GetNaturalSparkleFlags() & GAUNTLET_COLOR
; break;
1486 case RIGHT_LEG_INDEX
:
1487 case LEFT_LEG_INDEX
: Sparkling
= GetNaturalSparkleFlags() & BOOT_COLOR
; break;
1490 SparkleFlags
|= Sparkling
? SPARKLING_C
: 0;
1495 case TORSO_INDEX
: Sparkling
= GetNaturalSparkleFlags() & TORSO_SPECIAL_COLOR
; break;
1496 case HEAD_INDEX
: Sparkling
= GetNaturalSparkleFlags() & EYE_COLOR
; break;
1497 case RIGHT_ARM_INDEX
:
1498 case LEFT_ARM_INDEX
: Sparkling
= GetNaturalSparkleFlags() & ARM_SPECIAL_COLOR
; break;
1500 case RIGHT_LEG_INDEX
:
1501 case LEFT_LEG_INDEX
: Sparkling
= GetNaturalSparkleFlags() & LEG_SPECIAL_COLOR
; break;
1504 SparkleFlags
|= Sparkling
? SPARKLING_D
: 0;
1505 return SparkleFlags
;
1508 playerkind::playerkind() : SoulID(0), IsBonePlayer(false), IsClone(false)
1512 shopkeeper::shopkeeper()
1514 if(!game::IsLoading())
1515 Money
= GetMoney() + RAND() % 2001;
1518 void humanoid::Bite(character
* Enemy
, v2 HitPos
, int Direction
, truth ForceHit
)
1520 /* This function ought not to be called without a head */
1523 EditAP(-GetHead()->GetBiteAPCost());
1524 EditExperience(AGILITY
, 150, 1 << 9);
1525 EditStamina(-1000, false);
1526 Enemy
->TakeHit(this, 0, GetHead(), HitPos
, GetHead()->GetBiteDamage(), GetHead()->GetBiteToHitValue(), RAND() % 26 - RAND() % 26, BITE_ATTACK
, Direction
, !(RAND() % GetCriticalModifier()), ForceHit
);
1529 void humanoid::Kick(lsquare
* Square
, int Direction
, truth ForceHit
)
1531 leg
* KickLeg
= RAND_2
? GetRightLeg() : GetLeftLeg();
1533 EditAP(-KickLeg
->GetKickAPCost());
1534 EditStamina(-10000 / GetAttribute(LEG_STRENGTH
), false);
1536 if(Square
->BeKicked(this, 0, KickLeg
, KickLeg
->GetKickDamage(), KickLeg
->GetKickToHitValue(), RAND() % 26 - RAND() % 26, Direction
, !(RAND() % GetCriticalModifier()), ForceHit
))
1538 KickLeg
->EditExperience(LEG_STRENGTH
, 75, 1 << 9);
1539 KickLeg
->EditExperience(AGILITY
, 75, 1 << 9);
1543 /* Returns the average number of APs required to kill Enemy */
1545 double humanoid::GetTimeToKill(ccharacter
* Enemy
, truth UseMaxHP
) const
1547 double Effectivity
= 0;
1548 int AttackStyles
= 0;
1552 arm
* RightArm
= GetRightArm();
1556 double Damage
= RightArm
->GetDamage();
1559 Effectivity
+= 1 / (Enemy
->GetTimeToDie(this, int(Damage
) + 1, RightArm
->GetToHitValue(), AttackIsBlockable(GetRightWielded() ? WEAPON_ATTACK
: UNARMED_ATTACK
), UseMaxHP
) * RightArm
->GetAPCost());
1562 arm
* LeftArm
= GetLeftArm();
1566 double Damage
= LeftArm
->GetDamage();
1569 Effectivity
+= 1 / (Enemy
->GetTimeToDie(this, int(Damage
) + 1, LeftArm
->GetToHitValue(), AttackIsBlockable(GetLeftWielded() ? WEAPON_ATTACK
: UNARMED_ATTACK
), UseMaxHP
) * LeftArm
->GetAPCost());
1577 leg
* RightLeg
= GetRightLeg();
1578 leg
* LeftLeg
= GetLeftLeg();
1579 double TimeToDie
= Enemy
->GetTimeToDie(this, int(RightLeg
->GetKickDamage()) + 1, RightLeg
->GetKickToHitValue(), AttackIsBlockable(KICK_ATTACK
), UseMaxHP
) * RightLeg
->GetKickAPCost()
1580 + Enemy
->GetTimeToDie(this, int(LeftLeg
->GetKickDamage()) + 1, LeftLeg
->GetKickToHitValue(), AttackIsBlockable(KICK_ATTACK
), UseMaxHP
) * LeftLeg
->GetKickAPCost();
1581 Effectivity
+= 2 / TimeToDie
;
1587 head
* Head
= GetHead();
1588 Effectivity
+= 1 / (Enemy
->GetTimeToDie(this, int(Head
->GetBiteDamage()) + 1, Head
->GetBiteToHitValue(), AttackIsBlockable(BITE_ATTACK
), UseMaxHP
) * Head
->GetBiteAPCost());
1592 if(StateIsActivated(HASTE
))
1595 if(StateIsActivated(SLOW
))
1598 return AttackStyles
? AttackStyles
/ Effectivity
: 10000000;
1601 int humanoid::GetAttribute(int Identifier
, truth AllowBonus
) const
1603 if(Identifier
< BASE_ATTRIBUTES
)
1604 return character::GetAttribute(Identifier
, AllowBonus
);
1609 if(Identifier
== ARM_STRENGTH
|| Identifier
== DEXTERITY
)
1611 arm
* RightArm
= GetRightArm();
1614 Attrib
+= RightArm
->GetAttribute(Identifier
, AllowBonus
);
1616 arm
* LeftArm
= GetLeftArm();
1619 Attrib
+= LeftArm
->GetAttribute(Identifier
, AllowBonus
);
1621 else if(Identifier
== LEG_STRENGTH
|| Identifier
== AGILITY
)
1623 leg
* RightLeg
= GetRightLeg();
1626 Attrib
+= RightLeg
->GetAttribute(Identifier
, AllowBonus
);
1628 leg
* LeftLeg
= GetLeftLeg();
1631 Attrib
+= LeftLeg
->GetAttribute(Identifier
, AllowBonus
);
1635 ABORT("Illegal humanoid attribute %d request!", Identifier
);
1643 truth
humanoid::EditAttribute(int Identifier
, int Value
)
1645 if(Identifier
< BASE_ATTRIBUTES
)
1646 return character::EditAttribute(Identifier
, Value
);
1647 else if(Identifier
== ARM_STRENGTH
|| Identifier
== DEXTERITY
)
1649 truth Success
= false;
1651 if(GetRightArm() && GetRightArm()->EditAttribute(Identifier
, Value
))
1654 if(GetLeftArm() && GetLeftArm()->EditAttribute(Identifier
, Value
))
1659 else if(Identifier
== LEG_STRENGTH
|| Identifier
== AGILITY
)
1661 truth Success
= false;
1663 if(GetRightLeg() && GetRightLeg()->EditAttribute(Identifier
, Value
))
1666 if(GetLeftLeg() && GetLeftLeg()->EditAttribute(Identifier
, Value
))
1673 ABORT("Illegal humanoid attribute %d edit request!", Identifier
);
1678 void humanoid::EditExperience(int Identifier
, double Value
, double Speed
)
1680 if(!AllowExperience())
1683 if(Identifier
< BASE_ATTRIBUTES
)
1684 character::EditExperience(Identifier
, Value
, Speed
);
1685 else if(Identifier
== ARM_STRENGTH
|| Identifier
== DEXTERITY
)
1688 GetRightArm()->EditExperience(Identifier
, Value
, Speed
);
1691 GetLeftArm()->EditExperience(Identifier
, Value
, Speed
);
1693 else if(Identifier
== LEG_STRENGTH
|| Identifier
== AGILITY
)
1696 GetRightLeg()->EditExperience(Identifier
, Value
, Speed
);
1699 GetLeftLeg()->EditExperience(Identifier
, Value
, Speed
);
1702 ABORT("Illegal humanoid attribute %d experience edit request!", Identifier
);
1705 int humanoid::DrawStats(truth AnimationDraw
) const
1707 DrawSilhouette(AnimationDraw
);
1712 int PanelPosX
= RES
.X
- 96, PanelPosY
= 15;
1713 PrintAttribute("AStr", ARM_STRENGTH
, PanelPosX
, PanelPosY
++);
1714 PrintAttribute("LStr", LEG_STRENGTH
, PanelPosX
, PanelPosY
++);
1715 PrintAttribute("Dex", DEXTERITY
, PanelPosX
, PanelPosY
++);
1716 PrintAttribute("Agi", AGILITY
, PanelPosX
, PanelPosY
++);
1720 int humanoid::GetRandomStepperBodyPart() const
1722 int Possible
= 0, PossibleArray
[3];
1725 PossibleArray
[Possible
++] = RIGHT_LEG_INDEX
;
1728 PossibleArray
[Possible
++] = LEFT_LEG_INDEX
;
1731 return PossibleArray
[RAND_N(Possible
)];
1734 PossibleArray
[Possible
++] = RIGHT_ARM_INDEX
;
1737 PossibleArray
[Possible
++] = LEFT_ARM_INDEX
;
1740 return PossibleArray
[RAND_N(Possible
)];
1743 PossibleArray
[Possible
++] = HEAD_INDEX
;
1746 PossibleArray
[Possible
++] = GROIN_INDEX
;
1748 PossibleArray
[Possible
++] = TORSO_INDEX
;
1749 return PossibleArray
[RAND_N(Possible
)];
1752 int humanoid::CheckForBlock(character
* Enemy
, item
* Weapon
, double ToHitValue
, int Damage
, int Success
, int Type
)
1757 if(GetRightWielded())
1758 Damage
= CheckForBlockWithArm(Enemy
, Weapon
, GetRightArm(), ToHitValue
, Damage
, Success
, Type
);
1760 if(Damage
&& GetLeftWielded() && (!Weapon
|| Weapon
->Exists()))
1761 Damage
= CheckForBlockWithArm(Enemy
, Weapon
, GetLeftArm(), ToHitValue
, Damage
, Success
, Type
);
1766 truth
humanoid::CanWield() const
1768 return CanUseEquipment(RIGHT_WIELDED_INDEX
) || CanUseEquipment(LEFT_WIELDED_INDEX
);
1771 /* return true if still in balance */
1773 truth
humanoid::CheckBalance(double KickDamage
)
1778 || (GetUsableLegs() != 1
1780 && KickDamage
* 5 < RAND() % GetSize());
1783 long humanoid::GetMoveAPRequirement(int Difficulty
) const
1786 return (!StateIsActivated(PANIC
) ? 10000000 : 8000000) * Difficulty
/ (APBonus(GetAttribute(AGILITY
)) * GetMoveEase());
1788 switch(GetUsableLegs())
1791 return (!StateIsActivated(PANIC
) ? 20000000 : 16000000) * Difficulty
/ (APBonus(GetAttribute(AGILITY
)) * GetMoveEase());
1793 return (!StateIsActivated(PANIC
) ? 13333333 : 10666667) * Difficulty
/ (APBonus(GetAttribute(AGILITY
)) * GetMoveEase());
1795 return (!StateIsActivated(PANIC
) ? 10000000 : 8000000) * Difficulty
/ (APBonus(GetAttribute(AGILITY
)) * GetMoveEase());
1798 ABORT("A %d legged humanoid invaded the dungeon!", GetUsableLegs());
1802 void hunter::CreateBodyParts(int SpecialFlags
)
1804 for(int c
= 0; c
< BodyParts
; ++c
)
1805 if(c
!= LEFT_ARM_INDEX
)
1806 CreateBodyPart(c
, SpecialFlags
);
1808 SetBodyPart(LEFT_ARM_INDEX
, 0);
1811 truth
humanoid::EquipmentEasilyRecognized(int I
) const
1813 if(GetRelation(PLAYER
) != HOSTILE
)
1819 case RIGHT_RING_INDEX
:
1820 case LEFT_RING_INDEX
:
1828 void humanoid::SignalEquipmentAdd(int EquipmentIndex
)
1830 character::SignalEquipmentAdd(EquipmentIndex
);
1832 if(EquipmentIndex
== RIGHT_WIELDED_INDEX
)
1833 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill
, GetRightWielded());
1834 else if(EquipmentIndex
== LEFT_WIELDED_INDEX
)
1835 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill
, GetLeftWielded());
1837 if(!IsInitializing())
1838 CalculateBattleInfo();
1841 void humanoid::SignalEquipmentRemoval(int EquipmentIndex
, citem
* Item
)
1843 character::SignalEquipmentRemoval(EquipmentIndex
, Item
);
1845 if(EquipmentIndex
== RIGHT_WIELDED_INDEX
)
1846 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill
, 0);
1847 else if(EquipmentIndex
== LEFT_WIELDED_INDEX
)
1848 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill
, 0);
1850 if(!IsInitializing())
1851 CalculateBattleInfo();
1854 void humanoid::SWeaponSkillTick()
1856 for(std::list
<sweaponskill
*>::iterator i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end();)
1858 if((*i
)->Tick() && IsPlayer())
1860 item
* Item
= SearchForItem(*i
);
1863 (*i
)->AddLevelDownMessage(Item
->CHAR_NAME(UNARTICLED
));
1866 if(!(*i
)->GetHits() && *i
!= GetCurrentRightSWeaponSkill() && *i
!= GetCurrentLeftSWeaponSkill())
1868 std::list
<sweaponskill
*>::iterator Dirt
= i
++;
1869 SWeaponSkill
.erase(Dirt
);
1876 void angel::GetAICommand()
1878 if((LastHealed
|| game::GetTick() - LastHealed
> 10000) && AttachBodyPartsOfFriendsNear())
1881 humanoid::GetAICommand();
1884 /* Returns true if the angel finds somebody near to heal else false */
1886 truth
angel::AttachBodyPartsOfFriendsNear()
1888 character
* HurtOne
= 0;
1889 bodypart
* SeveredOne
= 0;
1891 for(int d
= 0; d
< GetNeighbourSquares(); ++d
)
1893 square
* Square
= GetNeighbourSquare(d
);
1897 character
* Char
= Square
->GetCharacter();
1899 if(Char
&& (!HurtOne
|| Char
->IsPlayer()) && GetRelation(Char
) == FRIEND
&& !Char
->HasAllBodyParts())
1901 bodypart
* BodyPart
= Char
->FindRandomOwnBodyPart(false);
1906 SeveredOne
= BodyPart
;
1914 if(HurtOne
->IsPlayer())
1915 ADD_MESSAGE("%s puts your %s back to its place.", CHAR_DESCRIPTION(DEFINITE
), SeveredOne
->GetBodyPartName().CStr());
1916 else if(CanBeSeenByPlayer())
1917 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());
1919 SeveredOne
->SetHP(1);
1920 SeveredOne
->RemoveFromSlot();
1921 HurtOne
->AttachBodyPart(SeveredOne
);
1922 LastHealed
= game::GetTick();
1923 DexterityAction(10);
1930 void humanoid::DrawBodyParts(blitdata
& BlitData
) const
1932 bitmap
* TileBuffer
= igraph::GetTileBuffer();
1933 bitmap
* RealBitmap
= BlitData
.Bitmap
;
1934 blitdata B
= { TileBuffer
,
1935 { BlitData
.Dest
.X
, BlitData
.Dest
.Y
},
1937 { TILE_SIZE
, TILE_SIZE
},
1940 BlitData
.CustomData
};
1942 RealBitmap
->NormalBlit(B
);
1943 TileBuffer
->FillPriority(0);
1944 B
.Src
.X
= B
.Src
.Y
= 0;
1945 B
.Luminance
= BlitData
.Luminance
;
1947 for(int c
= 0; c
< BodyParts
; ++c
)
1949 bodypart
* BodyPart
= GetBodyPart(DrawOrder
[c
]);
1953 B
.Dest
= GetDrawDisplacement(c
);
1958 B
.Dest
.X
= B
.Dest
.Y
= 0;
1959 arm
* LeftArm
= GetLeftArm();
1962 LeftArm
->DrawWielded(B
);
1964 arm
* RightArm
= GetRightArm();
1967 RightArm
->DrawWielded(B
);
1969 TileBuffer
->FastBlit(RealBitmap
, BlitData
.Dest
);
1972 v2
kamikazedwarf::GetDrawDisplacement(int I
) const
1974 static v2 DrawDisplacement
[] = { v2(0, 0), v2(0, 1), v2(0, -1), v2(0, -1), v2(0, -1), v2(0, 0), v2(0, 0) };
1975 return DrawDisplacement
[I
];
1978 col16
angel::GetTorsoMainColor() const
1980 return GetMasterGod()->GetColor();
1983 col16
angel::GetArmMainColor() const
1985 return GetMasterGod()->GetColor();
1988 col16
kamikazedwarf::GetTorsoMainColor() const
1990 return GetMasterGod()->GetColor();
1993 col16
kamikazedwarf::GetGauntletColor() const
1995 return GetMasterGod()->GetColor();
1998 col16
kamikazedwarf::GetLegMainColor() const
2000 return GetMasterGod()->GetColor();
2003 col16
housewife::GetHairColor() const
2005 static col16 HouseWifeHairColor
[] = { MakeRGB16(48, 40, 8), MakeRGB16(60, 48, 24), MakeRGB16(200, 0, 0) };
2006 return HouseWifeHairColor
[RAND() % 3];
2009 int angel::GetAttribute(int Identifier
, truth AllowBonus
) const // temporary until wings are bodyparts
2011 if(Identifier
== LEG_STRENGTH
)
2012 return GetDefaultLegStrength();
2013 else if(Identifier
== AGILITY
)
2014 return GetDefaultAgility();
2016 return humanoid::GetAttribute(Identifier
, AllowBonus
);
2019 int genie::GetAttribute(int Identifier
, truth AllowBonus
) const // temporary until someone invents a better way of doing this
2021 if(Identifier
== LEG_STRENGTH
)
2022 return GetDefaultLegStrength();
2023 else if(Identifier
== AGILITY
)
2024 return GetDefaultAgility();
2026 return humanoid::GetAttribute(Identifier
, AllowBonus
);
2029 truth
humanoid::CanUseStethoscope(truth PrintReason
) const
2031 if(!GetUsableArms())
2034 ADD_MESSAGE("You need a usable arm to use a stethoscope.");
2042 ADD_MESSAGE("You need a head to use stethoscope.");
2050 truth
humanoid::IsUsingArms() const
2052 return GetAttackStyle() & USE_ARMS
&& CanAttackWithAnArm();
2055 truth
humanoid::IsUsingLegs() const
2057 return (GetAttackStyle() & USE_LEGS
2058 || (GetAttackStyle() & USE_ARMS
&& !CanAttackWithAnArm()))
2059 && HasTwoUsableLegs();
2062 truth
humanoid::IsUsingHead() const
2064 return (GetAttackStyle() & USE_HEAD
2065 || ((GetAttackStyle() & USE_LEGS
2066 || (GetAttackStyle() & USE_ARMS
&& !CanAttackWithAnArm()))
2067 && !HasTwoUsableLegs()))
2071 void humanoid::CalculateBattleInfo()
2073 CalculateDodgeValue();
2074 doforbodyparts()(this, &bodypart::CalculateAttackInfo
);
2077 item
* skeleton::SevereBodyPart(int BodyPartIndex
, truth ForceDisappearance
, stack
* EquipmentDropStack
)
2079 if(BodyPartIndex
== RIGHT_ARM_INDEX
)
2080 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill
, 0);
2081 else if(BodyPartIndex
== LEFT_ARM_INDEX
)
2082 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill
, 0);
2084 item
* BodyPart
= GetBodyPart(BodyPartIndex
);
2087 if(!ForceDisappearance
)
2089 if(BodyPartIndex
== HEAD_INDEX
)
2090 Bone
= skull::Spawn(0, NO_MATERIALS
);
2092 Bone
= bone::Spawn(0, NO_MATERIALS
);
2094 Bone
->InitMaterials(BodyPart
->GetMainMaterial());
2095 BodyPart
->DropEquipment(EquipmentDropStack
);
2096 BodyPart
->RemoveFromSlot();
2097 BodyPart
->SetMainMaterial(0, NO_PIC_UPDATE
|NO_SIGNALS
);
2101 BodyPart
->DropEquipment(EquipmentDropStack
);
2102 BodyPart
->RemoveFromSlot();
2105 BodyPart
->SendToHell();
2106 CalculateAttributeBonuses();
2107 CalculateBattleInfo();
2108 SignalPossibleTransparencyChange();
2109 RemoveTraps(BodyPartIndex
);
2113 void zombie::CreateBodyParts(int SpecialFlags
)
2115 bool Anyway
= false;
2116 if(GetConfig() == ZOMBIE_OF_KHAZ_ZADM
)
2119 } // Khaz-Zadm needs his hands...
2121 for(int c
= 0; c
< BodyParts
; ++c
)
2122 if(Anyway
|| BodyPartIsVital(c
) || RAND_N(3) || (c
== HEAD_INDEX
&& !RAND_N(3)))
2124 bodypart
* BodyPart
= CreateBodyPart(c
, SpecialFlags
|NO_PIC_UPDATE
);
2125 BodyPart
->GetMainMaterial()->SetSpoilCounter(2000 + RAND_N(1000));
2129 void humanoid::AddSpecialEquipmentInfo(festring
& String
, int I
) const
2131 if((I
== RIGHT_WIELDED_INDEX
&& GetRightArm()->TwoHandWieldIsActive()) || (I
== LEFT_WIELDED_INDEX
&& GetLeftArm()->TwoHandWieldIsActive()))
2132 String
<< " (in both hands)";
2135 /* Yes, this is evil. */
2137 #define INSTANTIATE(name) if(DataBase->name.IsValid() && (Item = DataBase->name.Instantiate(SpecialFlags))) Set##name(Item);
2139 void humanoid::CreateInitialEquipment(int SpecialFlags
)
2141 character::CreateInitialEquipment(SpecialFlags
);
2144 INSTANTIATE(Helmet
);
2145 INSTANTIATE(Amulet
);
2147 INSTANTIATE(BodyArmor
);
2149 INSTANTIATE(RightWielded
);
2150 INSTANTIATE(LeftWielded
);
2151 INSTANTIATE(RightRing
);
2152 INSTANTIATE(LeftRing
);
2153 INSTANTIATE(RightGauntlet
);
2154 INSTANTIATE(LeftGauntlet
);
2155 INSTANTIATE(RightBoot
);
2156 INSTANTIATE(LeftBoot
);
2158 if(CurrentRightSWeaponSkill
)
2159 CurrentRightSWeaponSkill
->AddHit(GetRightSWeaponSkillHits() * 100);
2161 if(CurrentLeftSWeaponSkill
)
2162 CurrentLeftSWeaponSkill
->AddHit(GetLeftSWeaponSkillHits() * 100);
2165 festring
humanoid::GetBodyPartName(int I
, truth Articled
) const
2174 case HEAD_INDEX
: return Article
+ "head";
2175 case TORSO_INDEX
: return Article
+ "torso";
2176 case RIGHT_ARM_INDEX
: return Article
+ "right arm";
2177 case LEFT_ARM_INDEX
: return Article
+ "left arm";
2178 case GROIN_INDEX
: return Article
+ "groin";
2179 case RIGHT_LEG_INDEX
: return Article
+ "right leg";
2180 case LEFT_LEG_INDEX
: return Article
+ "left leg";
2183 ABORT("Illegal humanoid bodypart name request!");
2187 void humanoid::CreateBlockPossibilityVector(blockvector
& Vector
, double ToHitValue
) const
2189 double RightBlockChance
= 0;
2190 int RightBlockCapability
= 0;
2191 double LeftBlockChance
= 0;
2192 int LeftBlockCapability
= 0;
2193 arm
* RightArm
= GetRightArm();
2194 arm
* LeftArm
= GetLeftArm();
2198 RightBlockChance
= RightArm
->GetBlockChance(ToHitValue
);
2199 RightBlockCapability
= RightArm
->GetBlockCapability();
2204 LeftBlockChance
= LeftArm
->GetBlockChance(ToHitValue
);
2205 LeftBlockCapability
= LeftArm
->GetBlockCapability();
2210 if(RightBlockCapability
+ LeftBlockCapability
)
2211 Vector
.push_back(std::make_pair(RightBlockChance
* LeftBlockChance
, RightBlockCapability
+ LeftBlockCapability
));
2215 if(RightBlockCapability
)
2216 Vector
.push_back(std::make_pair(RightBlockChance
* (1 - LeftBlockChance
), RightBlockCapability
));
2220 if(LeftBlockCapability
)
2221 Vector
.push_back(std::make_pair(LeftBlockChance
* (1 - RightBlockChance
), LeftBlockCapability
));
2224 item
* humanoid::SevereBodyPart(int BodyPartIndex
, truth ForceDisappearance
, stack
* EquipmentDropStack
)
2226 if(BodyPartIndex
== RIGHT_ARM_INDEX
)
2227 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill
, 0);
2228 else if(BodyPartIndex
== LEFT_ARM_INDEX
)
2229 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill
, 0);
2231 return character::SevereBodyPart(BodyPartIndex
, ForceDisappearance
, EquipmentDropStack
);
2234 humanoid::humanoid(const humanoid
& Humanoid
) : mybase(Humanoid
), CurrentRightSWeaponSkill(0), CurrentLeftSWeaponSkill(0)
2236 SWeaponSkill
.resize(Humanoid
.SWeaponSkill
.size());
2237 std::list
<sweaponskill
*>::iterator i1
= SWeaponSkill
.begin();
2238 std::list
<sweaponskill
*>::const_iterator i2
= Humanoid
.SWeaponSkill
.begin();
2240 for(; i1
!= SWeaponSkill
.end(); ++i1
, ++i2
)
2241 *i1
= new sweaponskill(**i2
);
2244 cfestring
& humanoid::GetDeathMessage() const
2246 static festring HeadlessDeathMsg
= CONST_S("@Dd dies without a sound.");
2247 return GetHead() || character::GetDeathMessage() != "@Dd dies screaming." ? character::GetDeathMessage() : HeadlessDeathMsg
;
2250 int humanoid::GetSWeaponSkillLevel(citem
* Item
) const
2252 std::list
<sweaponskill
*>::const_iterator i
;
2254 for(i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
2255 if((*i
)->IsSkillOf(Item
))
2256 return (*i
)->GetLevel();
2258 for(idholder
* I
= Item
->GetCloneMotherID(); I
; I
= I
->Next
)
2259 for(i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
2260 if((*i
)->IsSkillOfCloneMother(Item
, I
->ID
))
2261 return (*i
)->GetLevel();
2266 truth
humanoid::UseMaterialAttributes() const
2268 return combinebodypartpredicates()(this, &bodypart::UseMaterialAttributes
, 0);
2271 col24
angel::GetBaseEmitation() const
2273 switch(GetMasterGod()->GetBasicAlignment())
2275 case GOOD
: return MakeRGB24(150, 150, 150);
2276 case NEUTRAL
: return MakeRGB24(120, 120, 150);
2277 case EVIL
: return MakeRGB24(150, 110, 110);
2283 void bananagrower::BeTalkedTo()
2287 if(GetRelation(PLAYER
) == HOSTILE
)
2288 ProcessAndAddMessage(GetHostileReplies()[RandomizeReply(Said
, GetHostileReplies().Size
)]);
2289 else if(!game::TweraifIsFree())
2291 if(GetRelation(PLAYER
) != HOSTILE
2292 && Profession
.Find("president", 0) != festring::NPos
&& !(RAND() % 7))
2293 ADD_MESSAGE("\"I'm glad Petrus spared my life even though I was the president.\"");
2295 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said
, 6)]);
2298 ProcessAndAddMessage(GetFriendlyReplies()[6 + RandomizeReply(Said
, 3)]);
2301 void bananagrower::RandomizeProfession()
2306 Profession
= CONST_S("the president of Tweraif");
2309 Profession
= CONST_S("a diplomat");
2312 Profession
= CONST_S("a teacher");
2315 Profession
= CONST_S("a philosopher");
2318 Profession
= CONST_S("a journalist");
2321 Profession
= CONST_S("an alchemist");
2324 Profession
= CONST_S("a renown mathematician");
2327 Profession
= CONST_S("a priest of Silva");
2333 Profession
= CONST_S("a professor of ");
2334 AddRandomScienceName(Profession
);
2339 void bananagrower::PostConstruct()
2341 Stamina
= MaxStamina
/ 5;
2342 RandomizeProfession();
2343 HasDroppedBananas
= FeedingSumo
= false;
2346 void bananagrower::Save(outputfile
& SaveFile
) const
2348 humanoid::Save(SaveFile
);
2349 SaveFile
<< Profession
<< HasDroppedBananas
<< FeedingSumo
;
2352 void bananagrower::Load(inputfile
& SaveFile
)
2354 humanoid::Load(SaveFile
);
2355 SaveFile
>> Profession
>> HasDroppedBananas
>> FeedingSumo
;
2358 void smith::BeTalkedTo()
2360 if(GetRelation(PLAYER
) == HOSTILE
)
2362 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.\"");
2366 if(!GetMainWielded() || !GetMainWielded()->CanBeUsedBySmith())
2368 ADD_MESSAGE("\"Sorry, I need an intact hammer to practise the art of smithing.\"");
2372 if(PLAYER
->PossessesItem(&item::IsFixableBySmith
))
2374 item
* Item
= PLAYER
->SelectFromPossessions(CONST_S("\"What do you want me to fix?\""), &item::IsFixableBySmith
);
2379 if(!(Item
->GetMainMaterial()->GetCategoryFlags() & IS_METAL
))
2381 ADD_MESSAGE("\"I only fix items made of metal.\"");
2385 /** update messages */
2387 long FixPrice
= Item
->GetFixPrice();
2389 if(PLAYER
->GetMoney() < FixPrice
)
2391 ADD_MESSAGE("\"Getting that fixed costs you %ld gold pieces. Get the money and we'll talk.\"", FixPrice
);
2395 ADD_MESSAGE("\"I can fix your %s, but it'll cost you %ld gold pieces.\"", Item
->CHAR_NAME(UNARTICLED
), FixPrice
);
2397 if(game::TruthQuestion(CONST_S("Do you accept this deal? [y/N]")))
2401 PLAYER
->EditMoney(-FixPrice
);
2402 ADD_MESSAGE("%s fixes %s in no time.", CHAR_NAME(DEFINITE
), Item
->CHAR_NAME(DEFINITE
));
2406 ADD_MESSAGE("\"Come back when you have some weapons or armor I can fix.\"");
2409 void humanoid::CalculateDodgeValue()
2411 DodgeValue
= 0.05 * GetMoveEase() * GetAttribute(AGILITY
) / sqrt(GetSize());
2417 if(!HasAUsableLeg())
2419 if(!HasTwoUsableLegs())
2427 truth
humanoid::CheckZap()
2429 if(!GetUsableArms())
2431 ADD_MESSAGE("You need at least one usable arm to zap.");
2435 return character::CheckZap();
2438 void bananagrower::GetAICommand()
2440 if(game::TweraifIsFree())
2442 humanoid::GetAICommand();
2446 if(CheckForEnemies(false, false, true, true))
2452 cv2 BananaTarget
= FeedingSumo
? SUMO_ROOM_POS
+ v2(1, 2) : v2(45, 45);
2454 if(GetPos() == BananaTarget
)
2456 itemvector ItemVector
;
2457 GetStack()->FillItemVector(ItemVector
);
2458 int BananasDropped
= 0;
2461 for(c
= 0; c
< ItemVector
.size(); ++c
)
2462 if(ItemVector
[c
]->IsBanana())
2464 ItemVector
[c
]->MoveTo(GetStackUnder());
2470 if(CanBeSeenByPlayer())
2471 ADD_MESSAGE("%s drops %s.", CHAR_NAME(DEFINITE
), BananasDropped
== 1 ? "a banana" : "some bananas");
2477 GetStackUnder()->FillItemVector(ItemVector
);
2478 int PeelsPickedUp
= 0;
2480 for(c
= 0; c
< ItemVector
.size(); ++c
)
2481 if(ItemVector
[c
]->IsBananaPeel())
2483 ItemVector
[c
]->MoveTo(GetStack());
2489 if(CanBeSeenByPlayer())
2490 ADD_MESSAGE("%s picks up %s.", CHAR_NAME(DEFINITE
), PeelsPickedUp
== 1 ? "a banana peel" : "some banana peels");
2495 HasDroppedBananas
= true;
2498 if(!HasDroppedBananas
)
2500 SetGoingTo(BananaTarget
);
2502 if(MoveTowardsTarget(true))
2505 else if(GetPos().X
== 54)
2507 if(CanBeSeenByPlayer())
2508 ADD_MESSAGE("%s leaves the town to gather more bananas.", CHAR_NAME(DEFINITE
));
2510 GetStack()->Clean();
2511 character
* Sumo
= game::GetSumo();
2512 FeedingSumo
= Sumo
&& Sumo
->GetNP() < (SATIATED_LEVEL
+ BLOATED_LEVEL
) >> 1 && !(RAND() % 15);
2513 int Bananas
= FeedingSumo
? 3 : 10;
2515 for(int c
= 0; c
< Bananas
; ++c
)
2516 GetStack()->AddItem(banana::Spawn());
2518 v2 Where
= GetLevel()->GetNearestFreeSquare(this, v2(0, 45));
2520 if(Where
== ERROR_V2
)
2521 Where
= GetLevel()->GetRandomSquare(this, NOT_IN_ROOM
); // this is odd but at least it doesn't crash
2524 RandomizeProfession();
2527 Stamina
= MaxStamina
/ 5;
2531 if(CanBeSeenByPlayer())
2532 ADD_MESSAGE("%s enters the town.", CHAR_NAME(INDEFINITE
));
2534 HasDroppedBananas
= false;
2538 SetGoingTo(v2(54, 45));
2540 if(MoveTowardsTarget(true))
2547 truth
humanoid::CheckTalk()
2549 if(!character::CheckTalk())
2554 ADD_MESSAGE("You need a head to talk.");
2561 truth
angel::CanCreateBodyPart(int I
) const
2563 return I
== TORSO_INDEX
|| I
== HEAD_INDEX
|| I
== RIGHT_ARM_INDEX
|| I
== LEFT_ARM_INDEX
;
2566 truth
genie::CanCreateBodyPart(int I
) const
2568 return I
== TORSO_INDEX
|| I
== HEAD_INDEX
|| I
== RIGHT_ARM_INDEX
|| I
== LEFT_ARM_INDEX
;
2571 truth
bananagrower::HandleCharacterBlockingTheWay(character
* Char
, v2 Pos
, int Dir
)
2573 return Char
->GetPos() == v2(45, 45) && (Displace(Char
, true) || Hit(Char
, Pos
, Dir
));
2576 festring
& bananagrower::ProcessMessage(festring
& Msg
) const
2578 character::ProcessMessage(Msg
);
2579 SEARCH_N_REPLACE(Msg
, "@pd", GetProfession());
2580 SEARCH_N_REPLACE(Msg
, "@Pd", GetProfession().CapitalizeCopy());
2584 void elder::CreateBodyParts(int SpecialFlags
)
2586 for(int c
= 0; c
< BodyParts
; ++c
)
2587 if(c
!= LEFT_LEG_INDEX
)
2588 CreateBodyPart(c
, SpecialFlags
);
2590 SetBodyPart(LEFT_LEG_INDEX
, 0);
2593 /*void encourager::GetAICommand()
2595 if(CheckForEnemies(true, true, true))
2598 if(CheckForUsefulItemsOnGround())
2604 if(game::GetTick() - LastHit > 200)
2606 static int NotDiagonal[] = { 1, 3, 4, 6 };
2608 for(int d = 0; d < 4; ++d)
2610 square* Square = GetNeighbourSquare(NotDiagonal[d]);
2614 character* Char = Square->GetCharacter();
2616 if(Char && Char->IsBananaGrower() && Hit(Char, Square->GetPos(), NotDiagonal[d], true))
2618 LastHit = game::GetTick();
2626 if(MoveTowardsHomePos())
2632 /*void encourager::Save(outputfile& SaveFile) const
2634 humanoid::Save(SaveFile);
2635 SaveFile << LastHit;
2638 void encourager::Load(inputfile& SaveFile)
2640 humanoid::Load(SaveFile);
2641 SaveFile >> LastHit;
2644 long skeleton::GetBodyPartVolume(int I
) const
2648 case HEAD_INDEX
: return 600;
2649 case TORSO_INDEX
: return (GetTotalVolume() - 600) * 13 / 30;
2650 case RIGHT_ARM_INDEX
:
2651 case LEFT_ARM_INDEX
: return (GetTotalVolume() - 600) / 10;
2652 case GROIN_INDEX
: return (GetTotalVolume() - 600) / 10;
2653 case RIGHT_LEG_INDEX
:
2654 case LEFT_LEG_INDEX
: return ((GetTotalVolume() - 600) << 1) / 15;
2657 ABORT("Illegal humanoid bodypart volume request!");
2661 truth
humanoid::CheckIfEquipmentIsNotUsable(int I
) const
2663 return (I
== RIGHT_WIELDED_INDEX
&& GetRightArm()->CheckIfWeaponTooHeavy("this item"))
2664 || (I
== LEFT_WIELDED_INDEX
&& GetLeftArm()->CheckIfWeaponTooHeavy("this item"))
2665 || (I
== RIGHT_WIELDED_INDEX
&& GetLeftWielded() && GetLeftWielded()->IsTwoHanded() && GetLeftArm()->CheckIfWeaponTooHeavy(festring(GetPossessivePronoun() + " other wielded item").CStr()))
2666 || (I
== LEFT_WIELDED_INDEX
&& GetRightWielded() && GetRightWielded()->IsTwoHanded() && GetRightArm()->CheckIfWeaponTooHeavy(festring(GetPossessivePronoun() + " other wielded item").CStr()));
2669 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
)
2671 int Return
= humanoid::TakeHit(Enemy
, Weapon
, EnemyBodyPart
, HitPos
, Damage
, ToHitValue
, Success
, Type
, Direction
, Critical
, ForceHit
);
2673 if(Return
== HAS_HIT
&& Critical
)
2676 ADD_MESSAGE("Aahhh. The pain feels unbelievably good.");
2677 else if(CanBeSeenByPlayer())
2678 ADD_MESSAGE("%s screams: \"Oh the delightful pain!\"", CHAR_NAME(DEFINITE
));
2680 ADD_MESSAGE("You hear someone screaming: \"Oh the delightful pain!\"");
2686 truth
petrusswife::SpecialEnemySightedReaction(character
* Char
)
2688 item
* Weapon
= Char
->GetMainWielded();
2690 if(Weapon
&& Weapon
->IsWeapon(Char
) && !(RAND() % 20))
2691 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());
2696 truth
housewife::SpecialEnemySightedReaction(character
* Char
)
2698 item
* Weapon
= Char
->GetMainWielded();
2700 if(Weapon
&& Weapon
->IsWeapon(Char
) && !(RAND() % 5))
2701 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());
2706 void guard::Save(outputfile
& SaveFile
) const
2708 humanoid::Save(SaveFile
);
2709 SaveFile
<< WayPoints
<< NextWayPoint
;
2712 void guard::Load(inputfile
& SaveFile
)
2714 humanoid::Load(SaveFile
);
2715 SaveFile
>> WayPoints
>> NextWayPoint
;
2718 void guard::GetAICommand()
2720 if(GetConfig() == MASTER
&& HP
<< 1 < MaxHP
&& (GetPos() - v2(30, 17)).GetLengthSquare() > 9)
2722 if(CanBeSeenByPlayer())
2723 ADD_MESSAGE("%s disappears.", CHAR_NAME(DEFINITE
));
2725 GetLevel()->GetLSquare(30, 16)->KickAnyoneStandingHereAway();
2726 Move(v2(30, 16), true);
2731 if(WayPoints
.size() && !IsGoingSomeWhere())
2733 if(GetPos() == WayPoints
[NextWayPoint
]) {
2734 if(NextWayPoint
< WayPoints
.size() - 1) ++NextWayPoint
; else NextWayPoint
= 0;
2737 GoingTo
= WayPoints
[NextWayPoint
];
2740 SeekLeader(GetLeader());
2742 if(CheckForEnemies(true, true, true))
2745 if(CheckForUsefulItemsOnGround())
2748 if(FollowLeader(GetLeader()))
2754 if(MoveTowardsHomePos())
2760 if(CheckForBeverage())
2766 truth
mistress::ReceiveDamage(character
* Damager
, int Damage
, int Type
, int TargetFlags
, int Direction
, truth Divide
, truth PenetrateArmor
, truth Critical
, truth ShowMsg
)
2768 truth Success
= humanoid::ReceiveDamage(Damager
, Damage
, Type
, TargetFlags
, Direction
, Divide
, PenetrateArmor
, Critical
, ShowMsg
);
2770 if(Type
& SOUND
&& Success
&& !(RAND() & 7))
2773 ADD_MESSAGE("Aahhh. The pain feels unbelievably good.");
2774 else if(CanBeSeenByPlayer())
2775 ADD_MESSAGE("%s screams: \"Oh the delightful pain!\"", CHAR_NAME(DEFINITE
));
2777 ADD_MESSAGE("You hear someone screaming: \"Oh the delightful pain!\"");
2783 void humanoid::AddSpecialStethoscopeInfo(felist
& Info
) const
2785 Info
.AddEntry(CONST_S("Arm strength: ") + GetAttribute(ARM_STRENGTH
), LIGHT_GRAY
);
2786 Info
.AddEntry(CONST_S("Leg strength: ") + GetAttribute(LEG_STRENGTH
), LIGHT_GRAY
);
2787 Info
.AddEntry(CONST_S("Dexterity: ") + GetAttribute(DEXTERITY
), LIGHT_GRAY
);
2788 Info
.AddEntry(CONST_S("Agility: ") + GetAttribute(AGILITY
), LIGHT_GRAY
);
2791 item
* humanoid::GetPairEquipment(int I
) const
2795 case RIGHT_WIELDED_INDEX
: return GetLeftWielded();
2796 case LEFT_WIELDED_INDEX
: return GetRightWielded();
2797 case RIGHT_GAUNTLET_INDEX
: return GetLeftGauntlet();
2798 case LEFT_GAUNTLET_INDEX
: return GetRightGauntlet();
2799 case RIGHT_BOOT_INDEX
: return GetLeftBoot();
2800 case LEFT_BOOT_INDEX
: return GetRightBoot();
2806 cfestring
& humanoid::GetStandVerb() const
2808 if(ForceCustomStandVerb())
2809 return DataBase
->StandVerb
;
2811 static festring HasntFeet
= CONST_S("crawling");
2812 static festring Hovering
= CONST_S("hovering");
2813 static festring Swimming
= CONST_S("swimming");
2815 if(StateIsActivated(LEVITATION
))
2821 return HasAUsableLeg() ? DataBase
->StandVerb
: HasntFeet
;
2824 void darkmage::GetAICommand()
2826 SeekLeader(GetLeader());
2828 if(FollowLeader(GetLeader()))
2831 character
* NearestEnemy
= 0;
2832 long NearestEnemyDistance
= 0x7FFFFFFF;
2833 character
* RandomFriend
= 0;
2834 charactervector Friend
;
2837 for(int c
= 0; c
< game::GetTeams(); ++c
)
2839 if(GetTeam()->GetRelation(game::GetTeam(c
)) == HOSTILE
)
2841 for(std::list
<character
*>::const_iterator i
= game::GetTeam(c
)->GetMember().begin(); i
!= game::GetTeam(c
)->GetMember().end(); ++i
)
2842 if((*i
)->IsEnabled())
2844 long ThisDistance
= Max
<long>(abs((*i
)->GetPos().X
- Pos
.X
), abs((*i
)->GetPos().Y
- Pos
.Y
));
2846 if((ThisDistance
< NearestEnemyDistance
|| (ThisDistance
== NearestEnemyDistance
&& !(RAND() % 3))) && (*i
)->CanBeSeenBy(this))
2849 NearestEnemyDistance
= ThisDistance
;
2853 else if(GetTeam()->GetRelation(game::GetTeam(c
)) == FRIEND
)
2855 for(std::list
<character
*>::const_iterator i
= game::GetTeam(c
)->GetMember().begin(); i
!= game::GetTeam(c
)->GetMember().end(); ++i
)
2856 if((*i
)->IsEnabled() && (*i
)->CanBeSeenBy(this))
2857 Friend
.push_back(*i
);
2861 if(NearestEnemy
&& NearestEnemy
->GetPos().IsAdjacent(Pos
))
2863 if(NearestEnemy
->IsSmall()
2864 && GetAttribute(WISDOM
) < NearestEnemy
->GetAttackWisdomLimit()
2866 && Hit(NearestEnemy
, NearestEnemy
->GetPos(), game::GetDirectionForVector(NearestEnemy
->GetPos() - GetPos())))
2868 else if((GetConfig() == ARCH_MAGE
&& RAND() & 1)
2869 || (GetConfig() == ELDER
&& !(RAND() & 3)))
2871 if(CanBeSeenByPlayer())
2872 ADD_MESSAGE("%s invokes a spell and disappears.", CHAR_NAME(DEFINITE
));
2874 TeleportRandomly(true);
2875 EditAP(-GetSpellAPCost());
2880 if(NearestEnemy
&& ((GetConfig() != APPRENTICE
&& NearestEnemyDistance
< 10) || StateIsActivated(PANIC
)) && RAND() & 3)
2882 SetGoingTo((Pos
<< 1) - NearestEnemy
->GetPos());
2884 if(MoveTowardsTarget(true))
2888 if(Friend
.size() && !(RAND() & 3))
2890 RandomFriend
= Friend
[RAND() % Friend
.size()];
2897 CONST_S("killed by the spells of ") + GetName(INDEFINITE
),
2904 lsquare
* Square
= NearestEnemy
->GetLSquareUnder();
2905 EditAP(-GetSpellAPCost());
2907 if(CanBeSeenByPlayer())
2908 ADD_MESSAGE("%s invokes a spell!", CHAR_NAME(DEFINITE
));
2913 Square
->DrawLightning(v2(8, 8), WHITE
, YOURSELF
);
2914 Square
->Lightning(Beam
);
2919 Square
->DrawLightning(v2(8, 8), WHITE
, YOURSELF
);
2920 Square
->Lightning(Beam
);
2924 Square
->DrawParticles(RED
);
2925 Square
->LowerEnchantment(Beam
);
2934 case 2: Square
->DrawParticles(RED
); Square
->Strike(Beam
); break;
2935 case 3: Square
->DrawParticles(RED
); Square
->FireBall(Beam
); break;
2938 case 6: Square
->DrawParticles(RED
); Square
->Slow(Beam
); break;
2939 case 7: Square
->DrawParticles(RED
); Square
->Teleport(Beam
); break;
2942 case 10: Square
->DrawParticles(RED
); Square
->LowerEnchantment(Beam
); break;
2943 default: Square
->DrawLightning(v2(8, 8), WHITE
, YOURSELF
); Square
->Lightning(Beam
); break;
2952 case 2: Square
->DrawParticles(RED
); Square
->FireBall(Beam
); break;
2955 character
* Char
= NearestEnemy
->DuplicateToNearestSquare(this, CHANGE_TEAM
|MIRROR
|(1000 << LE_BASE_SHIFT
)|(1000 << LE_RAND_SHIFT
));
2959 if(Char
->CanBeSeenByPlayer())
2960 ADD_MESSAGE("%s materializes!", Char
->CHAR_NAME(INDEFINITE
));
2966 case 5: Square
->DrawParticles(RED
); Square
->Slow(Beam
); break;
2967 case 6: Square
->DrawParticles(RED
); Square
->Teleport(Beam
); break;
2970 case 9: Square
->DrawParticles(RED
); Square
->LowerEnchantment(Beam
); break;
2973 golem
* Golem
= golem::Spawn(RAND() % 3 ? ARCANITE
: OCTIRON
);
2974 v2 Where
= GetLevel()->GetNearestFreeSquare(Golem
, Square
->GetPos());
2976 if(Where
== ERROR_V2
)
2978 if(CanBeSeenByPlayer())
2979 ADD_MESSAGE("Nothing happens.");
2985 Golem
->SetGenerationDanger(GetGenerationDanger());
2986 Golem
->SetTeam(GetTeam());
2987 Golem
->PutTo(Where
);
2989 if(Golem
->CanBeSeenByPlayer())
2990 ADD_MESSAGE("Suddenly %s materializes!", Golem
->CHAR_NAME(INDEFINITE
));
2992 Golem
->GetLSquareUnder()->DrawParticles(RED
);
2997 default: Square
->DrawParticles(RED
); Square
->Strike(Beam
); break;
3003 if(CanBeSeenByPlayer())
3004 NearestEnemy
->DeActivateVoluntaryAction(CONST_S("The spell of ") + GetName(DEFINITE
) + CONST_S(" interrupts you."));
3006 NearestEnemy
->DeActivateVoluntaryAction(CONST_S("The spell interrupts you."));
3013 lsquare
* Square
= RandomFriend
->GetLSquareUnder();
3014 EditAP(-GetSpellAPCost());
3015 Square
->DrawParticles(RED
);
3021 Square
->Haste(Beam
);
3026 RandomFriend
->DuplicateToNearestSquare(this, CHANGE_TEAM
);
3031 Square
->Invisibility(Beam
);
3033 Square
->Haste(Beam
);
3053 void zombie::GetAICommand()
3057 for(stackiterator i
= GetLSquareUnder()->GetStack()->GetBottom(); i
.HasItem(); ++i
)
3059 head
* Head
= i
->Behead();
3063 if(CanBeSeenByPlayer())
3064 ADD_MESSAGE("%s takes %s and attaches it to its torso.", CHAR_NAME(DEFINITE
), Head
->CHAR_NAME(INDEFINITE
));
3066 Head
->RemoveFromSlot();
3067 AttachBodyPart(Head
);
3069 DexterityAction(10);
3075 humanoid::GetAICommand();
3078 head
* humanoid::Behead()
3080 head
* Head
= GetHead();
3083 SevereBodyPart(HEAD_INDEX
);
3088 truth
communist::BoundToUse(citem
* Item
, int I
) const
3090 return Item
&& Item
->IsGorovitsFamilyRelic() && Item
->IsInCorrectSlot(I
);
3093 festring
werewolfwolf::GetKillName() const
3095 if(GetPolymorphBackup() && GetPolymorphBackup()->GetType() == werewolfhuman::ProtoType
.GetIndex())
3096 return GetName(INDEFINITE
);
3098 return humanoid::GetKillName();
3101 int humanoid::GetRandomApplyBodyPart() const
3103 if(RightArmIsUsable())
3105 if(LeftArmIsUsable())
3106 return RAND_2
? RIGHT_ARM_INDEX
: LEFT_ARM_INDEX
;
3108 return RIGHT_ARM_INDEX
;
3110 else if(LeftArmIsUsable())
3111 return LEFT_ARM_INDEX
;
3119 void golem::BeTalkedTo()
3123 if(GetRelation(PLAYER
) == HOSTILE
)
3124 Engrave(GetHostileReplies()[RandomizeReply(Said
, GetHostileReplies().Size
)]);
3126 Engrave(GetFriendlyReplies()[RandomizeReply(Said
, GetFriendlyReplies().Size
)]);
3128 if(CanBeSeenByPlayer())
3129 ADD_MESSAGE("%s engraves something.", CHAR_NAME(DEFINITE
));
3134 void humanoid::AddAttributeInfo(festring
& Entry
) const
3137 Entry
<< GetAttribute(ARM_STRENGTH
);
3139 Entry
<< GetAttribute(LEG_STRENGTH
);
3141 Entry
<< GetAttribute(DEXTERITY
);
3143 Entry
<< GetAttribute(AGILITY
);
3144 character::AddAttributeInfo(Entry
);
3147 void humanoid::AddAttackInfo(felist
& List
) const
3149 if(GetAttackStyle() & USE_ARMS
)
3152 GetRightArm()->AddAttackInfo(List
);
3155 GetLeftArm()->AddAttackInfo(List
);
3162 GetRightLeg()->AddAttackInfo(List
);
3163 GetLeftLeg()->AddAttackInfo(List
);
3168 Entry
= CONST_S(" bite attack");
3170 Entry
<< GetHead()->GetBiteMinDamage() << '-' << GetHead()->GetBiteMaxDamage();
3172 Entry
<< int(GetHead()->GetBiteToHitValue());
3174 Entry
<< GetHead()->GetBiteAPCost();
3175 List
.AddEntry(Entry
, LIGHT_GRAY
);
3179 void humanoid::AddDefenceInfo(felist
& List
) const
3181 character::AddDefenceInfo(List
);
3184 GetRightArm()->AddDefenceInfo(List
);
3187 GetLeftArm()->AddDefenceInfo(List
);
3190 void humanoid::DetachBodyPart()
3194 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'))
3197 ToBeDetached
= LEFT_ARM_INDEX
;
3200 ToBeDetached
= RIGHT_ARM_INDEX
;
3203 ToBeDetached
= LEFT_LEG_INDEX
;
3206 ToBeDetached
= RIGHT_LEG_INDEX
;
3209 ToBeDetached
= HEAD_INDEX
;
3215 if(GetBodyPart(ToBeDetached
))
3217 item
* ToDrop
= SevereBodyPart(ToBeDetached
);
3218 SendNewDrawRequest();
3222 GetStack()->AddItem(ToDrop
);
3223 ToDrop
->DropEquipment();
3226 ADD_MESSAGE("Bodypart detached!");
3229 ADD_MESSAGE("That bodypart has already been detached.");
3231 CheckDeath(CONST_S("removed one of his vital bodyparts"), 0);
3236 void humanoid::AddAttributeInfo(festring
&) const { }
3237 void humanoid::AddAttackInfo(felist
&) const { }
3238 void humanoid::AddDefenceInfo(felist
&) const { }
3239 void humanoid::DetachBodyPart() { }
3243 truth
ennerbeast::MustBeRemovedFromBone() const
3245 return !IsEnabled() || GetTeam()->GetID() != MONSTER_TEAM
|| GetDungeon()->GetIndex() != ELPURI_CAVE
|| GetLevel()->GetIndex() != ENNER_BEAST_LEVEL
;
3248 truth
communist::MustBeRemovedFromBone() const
3250 return !IsEnabled() || GetTeam()->GetID() != IVAN_TEAM
|| GetDungeon()->GetIndex() != ELPURI_CAVE
|| GetLevel()->GetIndex() != IVAN_LEVEL
;
3253 truth
humanoid::PreProcessForBone()
3255 for(std::list
<sweaponskill
*>::iterator i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
3256 (*i
)->PreProcessForBone();
3258 return character::PreProcessForBone();
3261 void humanoid::FinalProcessForBone()
3263 character::FinalProcessForBone();
3265 for(std::list
<sweaponskill
*>::iterator i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end();)
3267 boneidmap::iterator BI
= game::GetBoneItemIDMap().find(-(*i
)->GetID());
3269 if(BI
== game::GetBoneItemIDMap().end())
3271 std::list
<sweaponskill
*>::iterator Dirt
= i
++;
3272 SWeaponSkill
.erase(Dirt
);
3276 (*i
)->SetID(BI
->second
);
3282 void angel::FinalProcessForBone()
3284 humanoid::FinalProcessForBone();
3288 /*void encourager::FinalProcessForBone()
3290 humanoid::FinalProcessForBone();
3294 void playerkind::Save(outputfile
& SaveFile
) const
3296 humanoid::Save(SaveFile
);
3297 SaveFile
<< SoulID
<< HairColor
<< EyeColor
<< Talent
<< Weakness
<< IsBonePlayer
<< IsClone
;
3300 void playerkind::Load(inputfile
& SaveFile
)
3302 humanoid::Load(SaveFile
);
3303 SaveFile
>> SoulID
>> HairColor
>> EyeColor
>> Talent
>> Weakness
>> IsBonePlayer
>> IsClone
;
3306 void playerkind::SetSoulID(ulong What
)
3310 if(GetPolymorphBackup())
3311 GetPolymorphBackup()->SetSoulID(What
);
3314 truth
playerkind::SuckSoul(character
* Soul
)
3316 if(Soul
->GetID() == SoulID
)
3325 truth
playerkind::TryToRiseFromTheDead()
3327 if(humanoid::TryToRiseFromTheDead())
3329 if(IsEnabled() && SoulID
)
3331 ADD_MESSAGE("The soulless body of %s wobbles for a moment.", CHAR_NAME(DEFINITE
));
3341 void playerkind::FinalProcessForBone()
3343 humanoid::FinalProcessForBone();
3344 IsBonePlayer
= true;
3348 boneidmap::iterator BI
= game::GetBoneCharacterIDMap().find(SoulID
);
3350 if(BI
!= game::GetBoneCharacterIDMap().end())
3351 SoulID
= BI
->second
;
3357 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)
3361 void playerkind::BeTalkedTo()
3363 if(IsClone
&& IsBonePlayer
)
3365 if(GetRelation(PLAYER
) == HOSTILE
)
3367 ADD_MESSAGE("Oh no, you too! Why does everyone bully me!");
3373 switch(RandomizeReply(Said
, 4))
3376 ADD_MESSAGE("\"I'd like to write a memoir, but alas I doubt anyone would believe it.\"");
3379 ADD_MESSAGE("\"Then that damned clone appeared, took all my equipment and claimed I was his slave...\"");
3382 ADD_MESSAGE("\"The level was a catastrophe for the party, but luckily you saved the day.\"");
3385 ADD_MESSAGE("\"Oh, how I hate bananas. I Hate Them! I HATE THEM SO MUCH!!!\"");
3391 if(GetRelation(PLAYER
) == HOSTILE
)
3393 ADD_MESSAGE("%s seems extremely irritated. \"Vanish, you foul mirror image!\"", CHAR_DESCRIPTION(DEFINITE
));
3399 switch(RandomizeReply(Said
, 4))
3402 ADD_MESSAGE("\"Hey, those clothes are mine! Give them back!\"");
3405 ADD_MESSAGE("\"What, you summoned me? What a coincidence, I remember summoning you, too.\"");
3408 ADD_MESSAGE("\"I'm leading this party, not you, Mr. copy guy!\"");
3411 ADD_MESSAGE("\"Oh, how I hate bananas. I Hate Them! I HATE THEM SO MUCH!!!\"");
3417 if(GetRelation(PLAYER
) == HOSTILE
)
3419 ADD_MESSAGE("Let's finish what my ghost failed to do!");
3425 switch(RandomizeReply(Said
, 4))
3428 ADD_MESSAGE("\"What was it like? Death, you mean? Well, just like New Attnam. Very hot and whips everywhere.\"");
3431 ADD_MESSAGE("\"Stop it already! I *don't* want to know how my corpse smelled!\"");
3434 ADD_MESSAGE("\"I'm sorry about that ghost thing. That YASD was just a bit too much to handle, so I lost myself.\"");
3437 ADD_MESSAGE("\"Oh, how I hate bananas. I Hate Them! I HATE THEM SO MUCH!!!\"");
3443 void humanoid::EnsureCurrentSWeaponSkillIsCorrect(sweaponskill
*& Skill
, citem
* Wielded
)
3447 if(!Skill
|| !Skill
->IsSkillOf(Wielded
))
3450 EnsureCurrentSWeaponSkillIsCorrect(Skill
, 0);
3452 std::list
<sweaponskill
*>::iterator i
;
3454 for(i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
3455 if((*i
)->IsSkillOf(Wielded
))
3461 for(idholder
* I
= Wielded
->GetCloneMotherID(); I
; I
= I
->Next
)
3462 for(i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
3463 if((*i
)->IsSkillOfCloneMother(Wielded
, I
->ID
))
3465 Skill
= new sweaponskill(**i
);
3466 Skill
->SetID(Wielded
->GetID());
3467 SWeaponSkill
.push_back(Skill
);
3471 Skill
= new sweaponskill(Wielded
);
3472 SWeaponSkill
.push_back(Skill
);
3477 if(!Skill
->GetHits() && (CurrentRightSWeaponSkill
!= Skill
|| CurrentLeftSWeaponSkill
!= Skill
))
3478 for(std::list
<sweaponskill
*>::iterator i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
3482 SWeaponSkill
.erase(i
);
3490 humanoid::~humanoid()
3492 for(std::list
<sweaponskill
*>::iterator i
= SWeaponSkill
.begin(); i
!= SWeaponSkill
.end(); ++i
)
3496 truth
guard::MoveTowardsHomePos()
3498 if(GetConfig() == MASTER
&& GetPos() != v2(30, 16))
3500 if(CanBeSeenByPlayer())
3501 ADD_MESSAGE("%s disappears.", CHAR_NAME(DEFINITE
));
3503 GetLevel()->GetLSquare(30, 16)->KickAnyoneStandingHereAway();
3504 Move(v2(30, 16), true);
3506 if(CanBeSeenByPlayer())
3507 ADD_MESSAGE("%s appears.", CHAR_NAME(DEFINITE
));
3513 return humanoid::MoveTowardsHomePos();
3516 bodypart
* ennerbeast::MakeBodyPart(int I
) const
3519 return ennerhead::Spawn(0, NO_MATERIALS
);
3521 return humanoid::MakeBodyPart(I
);
3524 int humanoid::GetSumOfAttributes() const
3526 return character::GetSumOfAttributes() + GetAttribute(LEG_STRENGTH
) + GetAttribute(DEXTERITY
) ;
3529 truth
humanoid::CheckConsume(cfestring
& Verb
) const
3534 ADD_MESSAGE("You need a head to %s.", Verb
.CStr());
3539 return character::CheckConsume(Verb
);
3542 truth
humanoid::CanConsume(material
* Material
) const
3544 return character::CanConsume(Material
) && HasHead();
3547 void femaleslave::BeTalkedTo()
3551 if(GetConfig() != NEW_ATTNAM
|| GetRelation(PLAYER
) == HOSTILE
)
3552 humanoid::BeTalkedTo();
3553 else if(!game::TweraifIsFree())
3554 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said
, 4)]);
3556 ProcessAndAddMessage(GetFriendlyReplies()[4 + RandomizeReply(Said
, 3)]);
3559 void necromancer::GetAICommand()
3561 SeekLeader(GetLeader());
3563 if(FollowLeader(GetLeader()))
3566 character
* NearestEnemy
= 0;
3567 long NearestEnemyDistance
= 0x7FFFFFFF;
3570 for(int c
= 0; c
< game::GetTeams(); ++c
)
3571 if(GetTeam()->GetRelation(game::GetTeam(c
)) == HOSTILE
)
3573 for(std::list
<character
*>::const_iterator i
= game::GetTeam(c
)->GetMember().begin(); i
!= game::GetTeam(c
)->GetMember().end(); ++i
)
3574 if((*i
)->IsEnabled())
3576 long ThisDistance
= Max
<long>(abs((*i
)->GetPos().X
- Pos
.X
), abs((*i
)->GetPos().Y
- Pos
.Y
));
3578 if((ThisDistance
< NearestEnemyDistance
|| (ThisDistance
== NearestEnemyDistance
&& !(RAND() % 3))) && (*i
)->CanBeSeenBy(this))
3581 NearestEnemyDistance
= ThisDistance
;
3586 if(NearestEnemy
&& NearestEnemy
->GetPos().IsAdjacent(Pos
))
3588 if(GetConfig() == MASTER_NECROMANCER
&& !(RAND() & 3))
3590 if(CanBeSeenByPlayer())
3591 ADD_MESSAGE("%s invokes a spell and disappears.", CHAR_NAME(DEFINITE
));
3593 TeleportRandomly(true);
3594 EditAP(-GetSpellAPCost());
3597 else if(NearestEnemy
->IsSmall()
3598 && GetAttribute(WISDOM
) < NearestEnemy
->GetAttackWisdomLimit()
3600 && Hit(NearestEnemy
, NearestEnemy
->GetPos(), game::GetDirectionForVector(NearestEnemy
->GetPos() - GetPos())))
3606 if(!RAND_N(3) && TryToRaiseZombie())
3611 if(!RAND_N(6) && TryToRaiseZombie())
3615 if(NearestEnemy
&& !(RAND() % (GetConfig() == APPRENTICE_NECROMANCER
? 3 : 2)))
3617 lsquare
* Square
= NearestEnemy
->GetLSquareUnder();
3618 EditAP(-GetSpellAPCost());
3620 if(CanBeSeenByPlayer())
3621 ADD_MESSAGE("%s invokes a spell!", CHAR_NAME(DEFINITE
));
3623 truth Interrupt
= false;
3627 case APPRENTICE_NECROMANCER
:
3630 case MASTER_NECROMANCER
:
3635 Square
->DrawLightning(v2(8, 8), WHITE
, YOURSELF
);
3640 CONST_S("killed by the spells of ") + GetName(INDEFINITE
),
3645 Square
->Lightning(Beam
);
3653 if(CanBeSeenByPlayer())
3654 NearestEnemy
->DeActivateVoluntaryAction(CONST_S("The spell of ") + GetName(DEFINITE
) + CONST_S(" interrupts you."));
3656 NearestEnemy
->DeActivateVoluntaryAction(CONST_S("The spell interrupts you."));
3661 if(NearestEnemy
&& (NearestEnemyDistance
< 10 || StateIsActivated(PANIC
)) && RAND() & 3)
3663 SetGoingTo((Pos
<< 1) - NearestEnemy
->GetPos());
3665 if(MoveTowardsTarget(true))
3681 truth
necromancer::TryToRaiseZombie()
3683 for(int c
= 0; c
< game::GetTeams(); ++c
)
3684 for(std::list
<character
*>::const_iterator i
= game::GetTeam(c
)->GetMember().begin();
3685 i
!= game::GetTeam(c
)->GetMember().end(); ++i
)
3686 if(!(*i
)->IsEnabled() && (*i
)->GetMotherEntity()
3687 && (*i
)->GetMotherEntity()->Exists()
3688 && (GetConfig() == MASTER_NECROMANCER
3689 || (*i
)->GetMotherEntity()->GetSquareUnderEntity()->CanBeSeenBy(this)))
3691 character
* Zombie
= (*i
)->GetMotherEntity()->TryNecromancy(this);
3695 if(Zombie
->CanBeSeenByPlayer())
3696 ADD_MESSAGE("%s calls %s back to cursed undead life.", CHAR_DESCRIPTION(DEFINITE
), Zombie
->CHAR_NAME(INDEFINITE
));
3697 else if(CanBeSeenByPlayer())
3698 ADD_MESSAGE("%s casts a spell, but you notice no effect.", CHAR_NAME(DEFINITE
));
3700 EditAP(-GetSpellAPCost());
3708 void necromancer::RaiseSkeleton()
3712 const database
* WarLordDataBase
;
3713 databasecreator
<character
>::FindDataBase(WarLordDataBase
, &skeleton::ProtoType
, WAR_LORD
);
3716 if(GetConfig() == MASTER_NECROMANCER
&& !(WarLordDataBase
->Flags
& HAS_BEEN_GENERATED
) && !(RAND() % 250))
3718 Skeleton
= skeleton::Spawn(WAR_LORD
);
3719 Skeleton
->SetTeam(GetTeam());
3720 Skeleton
->PutNear(GetPos());
3721 Skeleton
->SignalGeneration();
3723 if(Skeleton
->CanBeSeenByPlayer())
3724 ADD_MESSAGE("The whole area trembles terribly as %s emerges from the ground.", Skeleton
->CHAR_NAME(DEFINITE
));
3725 else if(CanBeSeenByPlayer())
3726 ADD_MESSAGE("%s casts a powerful spell which makes the whole area tremble.", CHAR_NAME(DEFINITE
));
3728 ADD_MESSAGE("You feel the presence of an ancient evil being awakened from its long slumber. You shiver.");
3732 Skeleton
= skeleton::Spawn(GetConfig() == APPRENTICE_NECROMANCER
? 0 : WARRIOR
, NO_EQUIPMENT
);
3733 Skeleton
->SetTeam(GetTeam());
3734 Skeleton
->PutNear(GetPos());
3736 if(Skeleton
->CanBeSeenByPlayer())
3737 ADD_MESSAGE("The ground shakes and %s emerges from it.", Skeleton
->CHAR_NAME(INDEFINITE
));
3738 else if(CanBeSeenByPlayer())
3739 ADD_MESSAGE("%s casts a spell, but you notice no effect.", CHAR_NAME(DEFINITE
));
3742 Skeleton
->SetGenerationDanger(GetGenerationDanger());
3743 EditAP(-GetSpellAPCost());
3746 void humanoid::StayOn(liquid
* Liquid
)
3751 truth Standing
= false;
3755 GetRightLeg()->StayOn(Liquid
);
3759 if(IsEnabled() && GetLeftLeg())
3761 GetLeftLeg()->StayOn(Liquid
);
3767 bodypart
* BodyPart
[MAX_BODYPARTS
];
3770 for(int c
= 0; c
< BodyParts
; ++c
)
3772 BodyPart
[Index
++] = GetBodyPart(c
);
3774 BodyPart
[RAND() % Index
]->StayOn(Liquid
);
3778 bodypart
* playerkind::MakeBodyPart(int I
) const
3782 case TORSO_INDEX
: return playerkindtorso::Spawn(0, NO_MATERIALS
);
3783 case HEAD_INDEX
: return playerkindhead::Spawn(0, NO_MATERIALS
);
3784 case RIGHT_ARM_INDEX
: return playerkindrightarm::Spawn(0, NO_MATERIALS
);
3785 case LEFT_ARM_INDEX
: return playerkindleftarm::Spawn(0, NO_MATERIALS
);
3786 case GROIN_INDEX
: return playerkindgroin::Spawn(0, NO_MATERIALS
);
3787 case RIGHT_LEG_INDEX
: return playerkindrightleg::Spawn(0, NO_MATERIALS
);
3788 case LEFT_LEG_INDEX
: return playerkindleftleg::Spawn(0, NO_MATERIALS
);
3791 ABORT("Weird bodypart to make for a playerkind. It must be your fault!");
3795 truth
golem::AddAdjective(festring
& String
, truth Articled
) const
3797 int TotalRustLevel
= sumbodypartproperties()(this, &bodypart::GetMainMaterialRustLevel
);
3800 return humanoid::AddAdjective(String
, Articled
);
3806 if(TotalRustLevel
<= GetBodyParts())
3807 String
<< "slightly rusted ";
3808 else if(TotalRustLevel
<= GetBodyParts() << 1)
3809 String
<< "rusted ";
3811 String
<< "very rusted ";
3813 String
<< GetAdjective() << ' ';
3818 void oree::Bite(character
* Enemy
, v2 HitPos
, int, truth
)
3821 ADD_MESSAGE("You vomit acidous blood at %s.", Enemy
->CHAR_DESCRIPTION(DEFINITE
));
3822 else if(Enemy
->IsPlayer() || CanBeSeenByPlayer() || Enemy
->CanBeSeenByPlayer())
3823 ADD_MESSAGE("%s vomits acidous blood at %s.", CHAR_DESCRIPTION(DEFINITE
), Enemy
->CHAR_DESCRIPTION(DEFINITE
));
3825 Vomit(HitPos
, 500 + RAND() % 500, false);
3828 void sumowrestler::GetAICommand()
3832 SeekLeader(GetLeader());
3834 if(CheckForEnemies(true, true, true))
3837 if(CheckForUsefulItemsOnGround())
3843 if(FollowLeader(GetLeader()))
3849 if(MoveTowardsHomePos())
3855 void sumowrestler::BeTalkedTo()
3859 if(GetRelation(PLAYER
) == HOSTILE
)
3860 ProcessAndAddMessage(GetHostileReplies()[RandomizeReply(Said
, GetHostileReplies().Size
)]);
3861 else if(!game::TweraifIsFree())
3862 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said
, 6)]);
3864 ProcessAndAddMessage(GetFriendlyReplies()[6 + RandomizeReply(Said
, 3)]);
3867 character
* tourist::GetLeader() const
3869 character
* Guide
= game::GetTeam(TOURIST_GUIDE_TEAM
)->GetLeader();
3870 return Guide
&& Guide
->GetRelation(this) != HOSTILE
? Guide
: GetTeam()->GetLeader();
3873 void elder::GetAICommand()
3875 /* Select a place to guide the tourists to */
3878 SetGoingTo(GetLevel()->GetRandomSquare());
3880 humanoid::GetAICommand();
3883 void tourist::GetAICommand()
3885 if(game::IsSumoWrestling() && !(RAND() % 10))
3887 if(GetConfig() == HUSBAND
)
3890 ADD_MESSAGE("%s shouts: \"Show that skinny wimp what you've got, Huang!\"", CHAR_DESCRIPTION(DEFINITE
));
3892 ADD_MESSAGE("%s screams: \"Go for it, Huang!\"", CHAR_DESCRIPTION(DEFINITE
));
3894 else if(GetConfig() == WIFE
)
3897 ADD_MESSAGE("%s encourages you: \"Knock him out, %s!\"", CHAR_DESCRIPTION(DEFINITE
), game::GetPlayerName().CStr());
3899 ADD_MESSAGE("%s cheers you: \"A handsome guy like you can't lose to that banana ball!\"", CHAR_DESCRIPTION(DEFINITE
));
3901 else if(GetConfig() == CHILD
)
3904 ADD_MESSAGE("%s yells: \"More blood on the ring!!!\"", CHAR_DESCRIPTION(DEFINITE
));
3906 ADD_MESSAGE("%s cries: \"Kill him, Pong!!!\"", CHAR_DESCRIPTION(DEFINITE
));
3910 humanoid::GetAICommand();
3914 ///////////////////////////////////////////////////////////////////////////////
3915 character
* humanoid::CreateZombie() const
3920 humanoid
* Zombie
= zombie::Spawn();
3923 for(c
= 0; c
< BodyParts
; ++c
)
3925 bodypart
* BodyPart
= GetBodyPart(c
);
3929 BodyPart
= SearchForOriginalBodyPart(c
);
3933 BodyPart
->RemoveFromSlot();
3934 BodyPart
->SendToHell();
3940 bodypart
* ZombieBodyPart
= Zombie
->GetBodyPart(c
);
3943 ZombieBodyPart
= Zombie
->CreateBodyPart(c
);
3945 material
* M
= BodyPart
->GetMainMaterial()->Duplicate();
3946 M
->SetSpoilCounter(2000 + RAND() % 1000);
3947 M
->SetSkinColor(Zombie
->GetSkinColor());
3948 ZombieBodyPart
->ChangeMainMaterial(M
);
3949 ZombieBodyPart
->CopyAttributes(BodyPart
);
3951 else if(!Zombie
->BodyPartIsVital(c
))
3953 bodypart
* ZombieBodyPart
= Zombie
->GetBodyPart(c
);
3957 ZombieBodyPart
->RemoveFromSlot();
3958 ZombieBodyPart
->SendToHell();
3963 for(c
= 0; c
< Zombie
->AllowedWeaponSkillCategories
; ++c
)
3964 Zombie
->CWeaponSkill
[c
] = CWeaponSkill
[c
];
3966 Zombie
->SWeaponSkill
.resize(SWeaponSkill
.size());
3967 std::list
<sweaponskill
*>::iterator i1
= Zombie
->SWeaponSkill
.begin();
3968 std::list
<sweaponskill
*>::const_iterator i2
= SWeaponSkill
.begin();
3970 for(; i2
!= SWeaponSkill
.end(); ++i1
, ++i2
)
3971 *i1
= new sweaponskill(**i2
);
3973 memcpy(Zombie
->BaseExperience
,
3975 BASE_ATTRIBUTES
* sizeof(*BaseExperience
));
3976 Zombie
->CalculateAll();
3977 Zombie
->RestoreHP();
3978 Zombie
->RestoreStamina();
3979 static_cast<zombie
*>(Zombie
)->SetDescription(GetZombieDescription());
3980 Zombie
->GenerationDanger
= GenerationDanger
;
3984 void zombie::AddPostFix(festring
& String
, int Case
) const
3986 if(!Description
.IsEmpty())
3987 String
<< Description
;
3989 humanoid::AddPostFix(String
, Case
);
3992 void zombie::Save(outputfile
& SaveFile
) const
3994 humanoid::Save(SaveFile
);
3995 SaveFile
<< Description
;
3998 void zombie::Load(inputfile
& SaveFile
)
4000 humanoid::Load(SaveFile
);
4001 SaveFile
>> Description
;
4004 int darkknight::ModifyBodyPartHitPreference(int I
, int Modifier
) const
4006 return IsLimbIndex(I
) ? Modifier
<< 1 : Modifier
;
4009 int darkknight::ModifyBodyPartToHitChance(int I
, int Chance
) const
4011 return IsLimbIndex(I
) ? Chance
<< 1 : Chance
;
4014 void darkknight::SpecialBodyPartSeverReaction()
4019 ADD_MESSAGE("%s screams: \"I'll do you for that! I'll bite your legs off!\"", CHAR_DESCRIPTION(DEFINITE
));
4020 else if(!(RAND() % 5))
4024 ADD_MESSAGE("%s states calmly: \"'Tis but a scratch.\"", CHAR_DESCRIPTION(DEFINITE
)); break;
4026 ADD_MESSAGE("%s states calmly: \"Just a flesh wound.\"", CHAR_DESCRIPTION(DEFINITE
)); break;
4028 ADD_MESSAGE("%s shouts: \"I'm invincible!\"", CHAR_DESCRIPTION(DEFINITE
)); break;
4033 void humanoid::LeprosyHandler()
4035 if(IsImmuneToLeprosy())
4040 if(!RAND_N(1000 * GetAttribute(ENDURANCE
)))
4041 DropRandomNonVitalBodypart();
4043 if(!game::IsInWilderness())
4045 for(int d
= 0; d
< GetNeighbourSquares(); ++d
)
4047 lsquare
* Square
= GetNeighbourLSquare(d
);
4049 if(Square
&& Square
->GetCharacter())
4050 Square
->GetCharacter()->TryToInfectWithLeprosy(this);
4054 character::LeprosyHandler();
4057 void humanoid::DropRandomNonVitalBodypart()
4059 int BodyPartIndexToDrop
= GetRandomNonVitalBodyPart();
4061 if(BodyPartIndexToDrop
!= NONE_INDEX
)
4062 DropBodyPart(BodyPartIndexToDrop
);
4065 void humanoid::DropBodyPart(int Index
)
4067 if(!GetBodyPart(Index
)->IsAlive())
4070 festring NameOfDropped
= GetBodyPart(Index
)->GetBodyPartName();
4071 item
* Dropped
= SevereBodyPart(Index
);
4075 GetStack()->AddItem(Dropped
);
4076 Dropped
->DropEquipment();
4080 ADD_MESSAGE("You feel very ill. Your %s snaps off.", NameOfDropped
.CStr());
4081 game::AskForEscPress(CONST_S("Bodypart severed!"));
4082 DeActivateVoluntaryAction();
4084 else if(CanBeSeenByPlayer())
4085 ADD_MESSAGE("Suddenly %s's %s snaps off.", CHAR_NAME(DEFINITE
), NameOfDropped
.CStr());
4091 ADD_MESSAGE("You feel very ill. Your %s disappears.", NameOfDropped
.CStr());
4092 game::AskForEscPress(CONST_S("Bodypart destroyed!"));
4093 DeActivateVoluntaryAction();
4095 else if(CanBeSeenByPlayer())
4096 ADD_MESSAGE("Suddenly %s's %s disappears.", CHAR_NAME(DEFINITE
), NameOfDropped
.CStr());
4100 void humanoid::DuplicateEquipment(character
* Receiver
, ulong Flags
)
4102 character::DuplicateEquipment(Receiver
, Flags
);
4103 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill
, GetRightWielded());
4104 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill
, GetLeftWielded());
4107 truth
character::CanHear() const
4109 return DataBase
->CanHear
&& HasHead();
4112 col16
veterankamikazedwarf::GetTorsoMainColor() const
4114 return GetMasterGod()->GetEliteColor();
4117 col16
veterankamikazedwarf::GetGauntletColor() const
4119 return GetMasterGod()->GetEliteColor();
4122 col16
veterankamikazedwarf::GetLegMainColor() const
4124 return GetMasterGod()->GetEliteColor();
4127 col16
archangel::GetTorsoMainColor() const
4129 return GetMasterGod()->GetEliteColor();
4132 col16
archangel::GetArmMainColor() const
4134 return GetMasterGod()->GetEliteColor();
4137 void archangel::CreateInitialEquipment(int SpecialFlags
)
4139 humanoid::CreateInitialEquipment(SpecialFlags
);
4140 GetStack()->AddItem(holybook::Spawn(GetConfig(), SpecialFlags
));
4142 meleeweapon
* Weapon
;
4144 switch(GetMasterGod()->GetBasicAlignment())
4147 Weapon
= flamingsword::Spawn(0, SpecialFlags
|NO_MATERIALS
);
4148 Weapon
->InitMaterials(MAKE_MATERIAL(DIAMOND
), MAKE_MATERIAL(ADAMANT
), !(SpecialFlags
& NO_PIC_UPDATE
));
4149 Weapon
->SetEnchantment(4);
4150 SetRightWielded(Weapon
);
4151 Equipment
= shield::Spawn(0, SpecialFlags
|NO_MATERIALS
);
4152 Equipment
->InitMaterials(MAKE_MATERIAL(DIAMOND
), !(SpecialFlags
& NO_PIC_UPDATE
));
4153 Equipment
->SetEnchantment(4);
4154 SetLeftWielded(Equipment
);
4155 GetCWeaponSkill(LARGE_SWORDS
)->AddHit(200000);
4156 GetCWeaponSkill(SHIELDS
)->AddHit(500000);
4157 GetCurrentRightSWeaponSkill()->AddHit(200000);
4158 GetCurrentLeftSWeaponSkill()->AddHit(200000);
4159 GetRightArm()->SetDexterity(70);
4160 GetLeftArm()->SetDexterity(70);
4163 Weapon
= meleeweapon::Spawn(WAR_HAMMER
, SpecialFlags
|NO_MATERIALS
);
4164 Weapon
->InitMaterials(MAKE_MATERIAL(SAPPHIRE
), MAKE_MATERIAL(OCTIRON
), !(SpecialFlags
& NO_PIC_UPDATE
));
4165 Weapon
->SetEnchantment(4);
4166 SetRightWielded(Weapon
);
4167 GetCWeaponSkill(BLUNT_WEAPONS
)->AddHit(500000);
4168 GetCurrentRightSWeaponSkill()->AddHit(200000);
4172 Weapon
= meleeweapon::Spawn(HALBERD
, SpecialFlags
|NO_MATERIALS
);
4173 Weapon
->InitMaterials(MAKE_MATERIAL(RUBY
), MAKE_MATERIAL(OCTIRON
), !(SpecialFlags
& NO_PIC_UPDATE
));
4174 Weapon
->SetEnchantment(4);
4175 SetLeftWielded(Weapon
);
4176 GetCWeaponSkill(POLE_ARMS
)->AddHit(500000);
4177 GetCurrentLeftSWeaponSkill()->AddHit(500000);
4178 GetRightArm()->SetStrength(70);
4179 GetLeftArm()->SetStrength(70);
4183 void zombie::PostConstruct()
4186 GainIntrinsic(LEPROSY
);
4189 void orc::PostConstruct()
4192 GainIntrinsic(LEPROSY
);
4195 truth
mistress::AllowEquipment(citem
* Item
, int EquipmentIndex
) const
4197 return ((EquipmentIndex
!= RIGHT_WIELDED_INDEX
4198 && EquipmentIndex
!= LEFT_WIELDED_INDEX
)
4202 int humanoid::GetAttributeAverage() const
4204 return GetSumOfAttributes() / 9;
4207 void golem::CreateCorpse(lsquare
* Square
)
4209 material
* Material
= GetTorso()->GetMainMaterial();
4211 if(Material
->IsSolid())
4212 Square
->AddItem(Material
->CreateNaturalForm(ItemVolume
));
4219 if(!game::IsLoading())
4220 ItemVolume
= 50 + RAND_N(100);
4223 void golem::Save(outputfile
& SaveFile
) const
4225 humanoid::Save(SaveFile
);
4226 SaveFile
<< ItemVolume
;
4229 void golem::Load(inputfile
& SaveFile
)
4231 humanoid::Load(SaveFile
);
4232 SaveFile
>> ItemVolume
;
4235 truth
humanoid::CanVomit() const
4237 return HasHead() && character::CanVomit();
4240 truth
humanoid::CheckApply() const
4242 if(!character::CheckApply())
4245 if(!HasAUsableArm())
4247 ADD_MESSAGE("You need a usable arm to apply.");
4254 int darkmage::GetSpellAPCost() const
4258 case APPRENTICE
: return 4000;
4259 case BATTLE_MAGE
: return 2000;
4260 case ELDER
: return 1000;
4261 case ARCH_MAGE
: return 500;
4267 int necromancer::GetSpellAPCost() const
4271 case APPRENTICE_NECROMANCER
: return 2000;
4272 case MASTER_NECROMANCER
: return 1000;
4278 /* Horrible repeating. Sorry */
4280 void tailor::BeTalkedTo()
4282 if(GetRelation(PLAYER
) == HOSTILE
)
4284 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.\"");
4288 if(PLAYER
->PossessesItem(&item::IsFixableByTailor
))
4290 item
* Item
= PLAYER
->SelectFromPossessions(CONST_S("\"What do you want me to fix?\""), &item::IsFixableByTailor
);
4295 if(!(Item
->GetMainMaterial()->GetCategoryFlags() & CAN_BE_TAILORED
))
4297 ADD_MESSAGE("\"I can't work on %s.\"", Item
->GetMainMaterial()->GetName(false, false).CStr());
4301 /** update messages */
4303 long FixPrice
= Item
->GetFixPrice();
4305 if(PLAYER
->GetMoney() < FixPrice
)
4307 ADD_MESSAGE("\"Getting that fixed costs you %ld gold pieces. Get the money and we'll talk.\"", FixPrice
);
4311 ADD_MESSAGE("\"I can fix your %s, but it'll cost you %ld gold pieces.\"", Item
->CHAR_NAME(UNARTICLED
), FixPrice
);
4313 if(game::TruthQuestion(CONST_S("Do you accept this deal? [y/N]")))
4316 PLAYER
->EditMoney(-FixPrice
);
4317 ADD_MESSAGE("%s fixes %s in no time.", CHAR_NAME(DEFINITE
), Item
->CHAR_NAME(DEFINITE
));
4321 ADD_MESSAGE("\"Come back when you have some weapons or armor I can fix.\"");
4324 void veterankamikazedwarf::PostConstruct()
4326 kamikazedwarf::PostConstruct();
4328 game::GetTime(Time
);
4329 int Modifier
= Time
.Day
- KAMIKAZE_INVISIBILITY_DAY_MIN
;
4331 if(Time
.Day
>= KAMIKAZE_INVISIBILITY_DAY_MAX
4333 && RAND_N(KAMIKAZE_INVISIBILITY_DAY_MAX
- KAMIKAZE_INVISIBILITY_DAY_MIN
) < Modifier
))
4334 GainIntrinsic(INVISIBLE
);
4337 truth
humanoid::IsTransparent() const
4339 return character::IsTransparent() || !(GetRightLeg() || GetLeftLeg());
4342 void humanoid::ModifySituationDanger(double& Danger
) const
4344 character::ModifySituationDanger(Danger
);
4346 switch(GetUsableArms())
4348 case 0: Danger
*= 10;
4349 case 1: Danger
*= 2;
4352 switch(GetUsableLegs())
4354 case 0: Danger
*= 10;
4355 case 1: Danger
*= 2;
4359 void oree::GetAICommand()
4364 humanoid::GetAICommand();
4367 void oree::CallForMonsters()
4369 if(GetDungeon()->GetIndex() != ELPURI_CAVE
|| GetLevel()->GetIndex() != OREE_LAIR
)
4372 character
* ToBeCalled
= 0;
4377 ToBeCalled
= darkknight::Spawn(ELITE
);
4380 ToBeCalled
= frog::Spawn(RAND_2
? GREATER_DARK
: GIANT_DARK
);
4383 ToBeCalled
= frog::Spawn(DARK
);
4386 ToBeCalled
= darkmage::Spawn(RAND_2
? APPRENTICE
: BATTLE_MAGE
);
4389 ToBeCalled
= darkmage::Spawn(RAND_2
? APPRENTICE
: ELDER
);
4392 ToBeCalled
= necromancer::Spawn(RAND_2
? APPRENTICE_NECROMANCER
: MASTER_NECROMANCER
);
4398 for(int c
= 0; c
< 100; ++c
)
4400 TryToCreate
= game::GetMonsterPortal()->GetPos() + game::GetMoveVector(RAND() % DIRECTION_COMMAND_KEYS
);
4402 if(GetArea()->IsValidPos(TryToCreate
) && ToBeCalled
->CanMoveOn(GetNearLSquare(TryToCreate
)) && ToBeCalled
->IsFreeForMe(GetNearLSquare(TryToCreate
)))
4404 ToBeCalled
->SetTeam(game::GetTeam(MONSTER_TEAM
));
4405 ToBeCalled
->PutTo(TryToCreate
);
4413 int humanoid::RandomizeTryToUnStickBodyPart(ulong PossibleBodyParts
) const
4415 int Possible
= 0, PossibleArray
[3];
4417 if(RightArmIsUsable() && 1 << RIGHT_ARM_INDEX
& PossibleBodyParts
)
4418 PossibleArray
[Possible
++] = RIGHT_ARM_INDEX
;
4420 if(LeftArmIsUsable() && 1 << LEFT_ARM_INDEX
& PossibleBodyParts
)
4421 PossibleArray
[Possible
++] = LEFT_ARM_INDEX
;
4424 return PossibleArray
[RAND_N(Possible
)];
4426 if(RightLegIsUsable() && 1 << RIGHT_LEG_INDEX
& PossibleBodyParts
)
4427 PossibleArray
[Possible
++] = RIGHT_LEG_INDEX
;
4429 if(LeftLegIsUsable() && 1 << LEFT_LEG_INDEX
& PossibleBodyParts
)
4430 PossibleArray
[Possible
++] = LEFT_LEG_INDEX
;
4433 return PossibleArray
[RAND_N(Possible
)];
4435 if(GetHead() && 1 << HEAD_INDEX
& PossibleBodyParts
)
4438 if(GetGroin() && 1 << GROIN_INDEX
& PossibleBodyParts
)
4439 PossibleArray
[Possible
++] = GROIN_INDEX
;
4441 if(1 << TORSO_INDEX
& PossibleBodyParts
)
4442 PossibleArray
[Possible
++] = TORSO_INDEX
;
4444 return Possible
? PossibleArray
[RAND_N(Possible
)] : NONE_INDEX
;
4447 truth
humanoid::HasAUsableArm() const
4449 arm
* R
= GetRightArm(), * L
= GetLeftArm();
4450 return (R
&& R
->IsUsable()) || (L
&& L
->IsUsable());
4453 truth
humanoid::HasAUsableLeg() const
4455 leg
* R
= GetRightLeg(), * L
= GetLeftLeg();
4456 return (R
&& R
->IsUsable()) || (L
&& L
->IsUsable());
4459 truth
humanoid::HasTwoUsableLegs() const
4461 leg
* R
= GetRightLeg(), * L
= GetLeftLeg();
4462 return R
&& R
->IsUsable() && L
&& L
->IsUsable();
4465 truth
humanoid::CanAttackWithAnArm() const
4467 arm
* R
= GetRightArm();
4469 if(R
&& R
->GetDamage())
4472 arm
* L
= GetLeftArm();
4473 return L
&& L
->GetDamage();
4476 truth
humanoid::RightArmIsUsable() const
4478 arm
* A
= GetRightArm();
4479 return A
&& A
->IsUsable();
4482 truth
humanoid::LeftArmIsUsable() const
4484 arm
* A
= GetLeftArm();
4485 return A
&& A
->IsUsable();
4488 truth
humanoid::RightLegIsUsable() const
4490 leg
* L
= GetRightLeg();
4491 return L
&& L
->IsUsable();
4494 truth
humanoid::LeftLegIsUsable() const
4496 leg
* L
= GetLeftLeg();
4497 return L
&& L
->IsUsable();
4500 truth
humanoid::AllowUnconsciousness() const
4502 return (DataBase
->AllowUnconsciousness
&& TorsoIsAlive()
4503 && BodyPartIsVital(HEAD_INDEX
));
4506 truth
humanoid::CanChokeOnWeb(web
* Web
) const
4508 return CanChoke() && Web
->IsStuckToBodyPart(HEAD_INDEX
);
4511 truth
humanoid::BrainsHurt() const
4513 head
* Head
= GetHead();
4514 return !Head
|| Head
->IsBadlyHurt();
4517 void playerkind::PostConstruct()
4519 int R
= 0, G
= 0, B
= 0;
4523 case 0: R
= 195; G
= 165; B
= 40; break;
4524 case 1: R
= 130; G
= 30; B
= 0; break;
4525 case 2: R
= 30; G
= 30; B
= 15; break;
4526 case 3: R
= 50; G
= 30; B
= 5; break;
4529 HairColor
= MakeRGB16(R
+ RAND_N(41), G
+ RAND_N(41), B
+ RAND_N(41));
4533 case 0: R
= 25; G
= 0; B
= 70; break;
4534 case 1: R
= 5; G
= 0; B
= 50; break;
4535 case 2: R
= 10; G
= 10; B
= 10; break;
4536 case 3: R
= 60; G
= 20; B
= 0; break;
4539 EyeColor
= MakeRGB16(R
+ RAND_N(41), G
+ RAND_N(41), B
+ RAND_N(41));
4540 Talent
= RAND_N(TALENTS
);
4541 Weakness
= RAND_N(TALENTS
);
4544 v2
playerkind::GetHeadBitmapPos() const
4546 int Sum
= GetAttribute(INTELLIGENCE
, false) + GetAttribute(WISDOM
, false);
4556 v2
playerkind::GetRightArmBitmapPos() const
4558 if(GetRightArm()->GetAttribute(ARM_STRENGTH
, false) >= 20)
4564 v2
playerkind::GetLeftArmBitmapPos() const
4566 if(GetLeftArm()->GetAttribute(ARM_STRENGTH
, false) >= 20)
4572 int playerkind::GetNaturalSparkleFlags() const
4574 return GetAttribute(CHARISMA
) >= 30 ? SKIN_COLOR
: 0;
4577 void slave::PostConstruct()
4579 Talent
= TALENT_STRONG
;
4580 Weakness
= TALENT_CLEVER
;
4583 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
};
4584 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 };
4586 double playerkind::GetNaturalExperience(int Identifier
) const
4588 double NE
= DataBase
->NaturalExperience
[Identifier
];
4590 if(Talent
== TalentOfAttribute
[Identifier
])
4591 NE
*= TalentBonusOfAttribute
[Identifier
];
4593 if(Weakness
== TalentOfAttribute
[Identifier
])
4594 NE
/= TalentBonusOfAttribute
[Identifier
];
4599 cchar
* humanoid::GetRunDescriptionLine(int I
) const
4601 if(!GetRunDescriptionLineOne().IsEmpty())
4602 return !I
? GetRunDescriptionLineOne().CStr() : GetRunDescriptionLineTwo().CStr();
4605 return !I
? "Flying" : "very fast";
4609 if(!GetRightArm() && !GetLeftArm() && !GetRightLeg() && !GetLeftLeg())
4610 return !I
? "Floating" : "ahead fast";
4612 return !I
? "Swimming" : "very fast";
4615 if(!GetRightLeg() && !GetLeftLeg())
4616 return !I
? "Rolling" : "very fast";
4618 if(!GetRightLeg() || !GetLeftLeg())
4619 return !I
? "Hopping" : "very fast";
4621 return !I
? "Running" : "";
4624 cchar
* humanoid::GetNormalDeathMessage() const
4626 if(BodyPartIsVital(HEAD_INDEX
) && (!GetHead() || GetHead()->GetHP() <= 0))
4627 return "beheaded @k";
4628 else if(BodyPartIsVital(GROIN_INDEX
) && (!GetGroin() || GetGroin()->GetHP() <= 0))
4629 return "killed @bkp dirty attack below the belt";
4634 void kamikazedwarf::SingRandomSong()
4637 festring God
= GetMasterGod()->GetName();
4651 Bodypart
= "forehead";
4655 Bodypart
= "tongue";
4658 Song
= festring("On the ") + Bodypart
+ festring(" of ") + God
+ " everybody fears everything";
4662 festring Title
= GetMasterGod()->GetSex() == MALE
? "King" : "Queen";
4663 Song
= festring("Joy to the world, ") + God
4664 + " is come! Let all above Valpurus receive her " + Title
;
4668 Song
= festring("Hark the herald angels sing. Glory to ") + God
+ "!";
4671 Song
= festring("O ") + God
4672 + ", You are so big, So absolutely huge, Gosh, "
4673 "we're all really impressed down here, I can tell You.";
4676 Song
= festring("Forgive us, O ") + God
4677 + " for this, our dreadful toadying and barefaced flattery";
4680 Song
= festring("But you, ") + God
4681 + ", are so strong and, well, just so super fantastic. Amen.";
4684 Song
= festring("O ") + God
+ ", please don't burn us";
4687 Song
= festring("O ") + God
+ ", please don't grill or toast your flock";
4690 Song
= festring("O ") + God
+ ", please don't simmer us in stock";
4696 if(CanBeSeenByPlayer())
4697 ADD_MESSAGE("%s sings: \"%s\"",
4698 CHAR_DESCRIPTION(DEFINITE
), Song
.CStr());
4700 ADD_MESSAGE("You hear someone sing: \"%s\"", Song
.CStr());
4703 void humanoid::ApplySpecialAttributeBonuses()
4707 AttributeBonus
[CHARISMA
] -= GetHead()->
4708 CalculateScarAttributePenalty(GetAttribute(CHARISMA
, false));
4711 AttributeBonus
[CHARISMA
] -= GetAttribute(CHARISMA
, false) - 1;
4714 void siren::GetAICommand()
4719 humanoid::GetAICommand();
4722 truth
siren::TryToSing()
4724 truth Success
=false;
4725 for(int d
= 0; d
< GetNeighbourSquares(); ++d
)
4727 lsquare
* Square
= GetNeighbourLSquare(d
);
4729 if(Square
&& Square
->GetCharacter())
4732 Square
->GetCharacter()->ReceiveSirenSong(this);
4741 truth
humanoid::MindWormCanPenetrateSkull(mindworm
* Worm
) const
4745 if(RAND_N(102) > GetHelmet()->GetCoverPercentile())
4754 truth
humanoid::HasSadistWeapon() const
4756 arm
* Right
= GetRightArm(), * Left
= GetLeftArm();
4757 return (Right
&& Right
->HasSadistWeapon()) || (Left
&& Left
->HasSadistWeapon());
4760 truth
humanoid::HasSadistAttackMode() const
4762 return HasSadistWeapon() || IsUsingLegs();
4765 void petrusswife::Save(outputfile
& SaveFile
) const
4767 humanoid::Save(SaveFile
);
4768 SaveFile
<< GiftTotal
;
4771 void petrusswife::Load(inputfile
& SaveFile
)
4773 humanoid::Load(SaveFile
);
4774 SaveFile
>> GiftTotal
;
4777 void petrusswife::BeTalkedTo()
4781 if(!PLAYER
->SelectFromPossessions(Item
, CONST_S("Do you have something to give me?"), 0, &item::IsLuxuryItem
)
4783 humanoid::BeTalkedTo();
4786 truth RefusedSomething
= false;
4788 for(unsigned int c
= 0; c
< Item
.size(); ++c
)
4789 if(!MakesBurdened(GetCarriedWeight() + Item
[c
]->GetWeight()))
4792 GiftTotal
+= Item
[c
]->GetTruePrice();
4793 Item
[c
]->RemoveFromSlot();
4794 GetStack()->AddItem(Item
[c
]);
4798 RefusedSomething
= true;
4803 ADD_MESSAGE("\"I thank you for your little gift%s.\"", Accepted
== 1 ? "" : "s");
4805 if(RefusedSomething
)
4806 ADD_MESSAGE("\"Unfortunately I cannot carry any more of your gifts. I'm a delicate woman, you see.\"");
4809 void guard::BeTalkedTo()
4813 if(!PLAYER
->SelectFromPossessions(Item
, CONST_S("Do you have something to give me?"), 0, &item::IsBeverage
)
4815 humanoid::BeTalkedTo();
4817 for(unsigned int c
= 0; c
< Item
.size(); ++c
)
4819 Item
[c
]->RemoveFromSlot();
4820 GetStack()->AddItem(Item
[c
]);
4825 void denim::GetAICommand () {
4827 for (int c
= 0; c
< game::GetTeams(); ++c
) {
4828 if (GetTeam()->GetRelation(game::GetTeam(c
)) == HOSTILE
) Enemies
+= game::GetTeam(c
)->GetEnabledMembers();
4834 v2
wisefarmer::GetHeadBitmapPos () const { return v2(96, (4 + (RAND() & 1)) << 4); }
4835 v2
wisefarmer::GetRightArmBitmapPos () const { return v2(64, (RAND() & 1) << 4); }
4837 void wisefarmer::GetAICommand () {
4839 for (int c
= 0; c
< game::GetTeams(); ++c
) {
4840 if (GetTeam()->GetRelation(game::GetTeam(c
)) == HOSTILE
) Enemies
+= game::GetTeam(c
)->GetEnabledMembers();
4846 void raven::GetAICommand () {
4848 for (int c
= 0; c
< game::GetTeams(); ++c
) {
4849 if (GetTeam()->GetRelation(game::GetTeam(c
)) == HOSTILE
) Enemies
+= game::GetTeam(c
)->GetEnabledMembers();
4855 void vulcan::GetAICommand () {
4857 for (int c
= 0; c
< game::GetTeams(); ++c
) {
4858 if (GetTeam()->GetRelation(game::GetTeam(c
)) == HOSTILE
) Enemies
+= game::GetTeam(c
)->GetEnabledMembers();
4864 truth
rogue::IsRetreating () const {
4865 if (humanoid::IsRetreating()) return true;
4866 for (stackiterator i
= GetStack()->GetBottom(); i
.HasItem(); ++i
) if ((*i
)->GetSparkleFlags()) return true;
4871 void rogue::GetAICommand () {
4872 if (!IsRetreating()) {
4873 character
*Char
= GetRandomNeighbour();
4875 itemvector Sparkling
;
4876 for (stackiterator i
= Char
->GetStack()->GetBottom(); i
.HasItem(); ++i
) {
4877 if ((*i
)->GetSparkleFlags() && !MakesBurdened((*i
)->GetWeight())) Sparkling
.push_back(*i
);
4879 if (!Sparkling
.empty()) {
4880 item
*ToSteal
= Sparkling
[RAND() % Sparkling
.size()];
4881 ToSteal
->RemoveFromSlot();
4882 GetStack()->AddItem(ToSteal
);
4883 if (Char
->IsPlayer()) ADD_MESSAGE("%s steals your %s.", CHAR_NAME(DEFINITE
), ToSteal
->CHAR_NAME(UNARTICLED
));
4889 humanoid::GetAICommand();
4893 void assassin::BeTalkedTo () {
4894 if (GetRelation(PLAYER
) == HOSTILE
) {
4895 if (PLAYER
->GetMoney() >= 1500) {
4896 ADD_MESSAGE("%s talks: \"If you shell out 1500 gold pieces I'll join your side\"", CHAR_DESCRIPTION(DEFINITE
));
4897 if (game::TruthQuestion(CONST_S("Do you want to bribe him? [y/N]"))) {
4898 PLAYER
->SetMoney(PLAYER
->GetMoney()-1500);
4899 ChangeTeam(PLAYER
->GetTeam());
4903 ADD_MESSAGE("\"Trying to reason me with diplomancy won't work on me.\"");
4909 ///////////////////////////////////////////////////////////////////////////////
4910 petrus::petrus () : LastHealed(0) {
4911 game::SetPetrus(this);
4915 petrus::~petrus () {
4920 void petrus::FinalProcessForBone () {
4921 humanoid::FinalProcessForBone();
4926 truth
petrus::HealFully (character
*ToBeHealed
) {
4927 truth DidSomething
= false;
4928 for (int c
= 0; c
< ToBeHealed
->GetBodyParts(); ++c
) {
4929 if (!ToBeHealed
->GetBodyPart(c
)) {
4930 bodypart
* BodyPart
= 0;
4931 for (std::list
<ulong
>::const_iterator i
= ToBeHealed
->GetOriginalBodyPartID(c
).begin(); i
!= ToBeHealed
->GetOriginalBodyPartID(c
).end(); ++i
) {
4932 BodyPart
= static_cast<bodypart
*>(ToBeHealed
->SearchForItem(*i
));
4933 if (BodyPart
) break;
4935 if (!BodyPart
|| !BodyPart
->CanRegenerate()) continue;
4936 BodyPart
->RemoveFromSlot();
4937 ToBeHealed
->AttachBodyPart(BodyPart
);
4938 BodyPart
->RestoreHP();
4939 DidSomething
= true;
4940 if (ToBeHealed
->IsPlayer())
4941 ADD_MESSAGE("%s attaches your old %s back and heals it.", CHAR_NAME(DEFINITE
), BodyPart
->GetBodyPartName().CStr());
4942 else if (CanBeSeenByPlayer())
4943 ADD_MESSAGE("%s attaches the old %s of %s back and heals it.", CHAR_NAME(DEFINITE
), BodyPart
->GetBodyPartName().CStr(), ToBeHealed
->CHAR_DESCRIPTION(DEFINITE
));
4946 if (ToBeHealed
->IsInBadCondition()) {
4947 ToBeHealed
->RestoreLivingHP();
4948 DidSomething
= true;
4949 if (ToBeHealed
->IsPlayer())
4950 ADD_MESSAGE("%s heals you fully.", CHAR_DESCRIPTION(DEFINITE
));
4951 else if (CanBeSeenByPlayer())
4952 ADD_MESSAGE("%s heals %s fully.", CHAR_DESCRIPTION(DEFINITE
), ToBeHealed
->CHAR_DESCRIPTION(DEFINITE
));
4954 if (ToBeHealed
->TemporaryStateIsActivated(POISONED
)) {
4955 ToBeHealed
->DeActivateTemporaryState(POISONED
);
4956 DidSomething
= true;
4957 if (ToBeHealed
->IsPlayer())
4958 ADD_MESSAGE("%s removes the foul poison in your body.", CHAR_DESCRIPTION(DEFINITE
));
4959 else if (CanBeSeenByPlayer())
4960 ADD_MESSAGE("%s removes the foul poison in %s's body.", CHAR_DESCRIPTION(DEFINITE
), ToBeHealed
->CHAR_DESCRIPTION(DEFINITE
));
4963 LastHealed
= game::GetTick();
4964 DexterityAction(10);
4971 void petrus::Save (outputfile
&SaveFile
) const {
4972 humanoid::Save(SaveFile
);
4973 SaveFile
<< LastHealed
;
4977 void petrus::Load (inputfile
&SaveFile
) {
4978 humanoid::Load(SaveFile
);
4979 SaveFile
>> LastHealed
;
4980 game::SetPetrus(this);
4984 void petrus::GetAICommand () {
4986 for (int c
= 0; c
< game::GetTeams(); ++c
) {
4987 if (GetTeam()->GetRelation(game::GetTeam(c
)) == HOSTILE
) Enemies
+= game::GetTeam(c
)->GetEnabledMembers();
4990 if (Enemies
&& !RAND_N(250 / Min(Enemies
, 50))) {
4991 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s shouts a magnificent prayer to Valpurus.", CHAR_NAME(DEFINITE
));
4992 angel
*Angel
= angel::Spawn(VALPURUS
);
4993 Angel
->SetLifeExpectancy(10000, 0);
4994 v2 Where
= GetLevel()->GetNearestFreeSquare(Angel
, GetPos());
4995 if (Where
== ERROR_V2
) Where
= GetLevel()->GetRandomSquare(Angel
);
4996 Angel
->SetTeam(GetTeam());
4997 Angel
->PutTo(Where
);
4998 if (Angel
->CanBeSeenByPlayer()) ADD_MESSAGE("%s materializes.", Angel
->CHAR_NAME(INDEFINITE
));
5003 if (HP
<< 1 < MaxHP
&& (GetPos() - v2(28, 20)).GetLengthSquare() > 400 && !RAND_N(10)) {
5004 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s disappears.", CHAR_NAME(DEFINITE
));
5005 GetLevel()->GetLSquare(28, 20)->KickAnyoneStandingHereAway();
5006 Move(v2(28, 20), true);
5011 if (!LastHealed
|| game::GetTick()-LastHealed
> 16384) {
5012 for (int d
= 0; d
< GetNeighbourSquares(); ++d
) {
5013 square
*Square
= GetNeighbourSquare(d
);
5015 character
*Char
= Square
->GetCharacter();
5016 if (Char
&& GetRelation(Char
) == FRIEND
&& HealFully(Char
)) return;
5025 void petrus::CreateCorpse (lsquare
*Square
) {
5026 if (game::GetStoryState() == 2) game::GetTeam(ATTNAM_TEAM
)->SetRelation(game::GetTeam(PLAYER_TEAM
), FRIEND
);
5027 Square
->AddItem(leftnutofpetrus::Spawn());
5032 void petrus::BeTalkedTo () {
5033 if (GetRelation(PLAYER
) == HOSTILE
) {
5034 ADD_MESSAGE("Heretic! Dev/null is a place not worthy to receive thee!");
5038 if (PLAYER
->HasGoldenEagleShirt()) {
5039 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.\"");
5040 if (game::TruthQuestion(CONST_S("Will you give the Shirt of the Golden Eagle to Petrus? [y/n]"), REQUIRES_ANSWER
)) {
5041 game::TextScreen(CONST_S(
5042 "The Holy Shirt is returned to its old owner and you kneel down to receive your reward.\n"
5043 "Petrus taps your shoulder with the Justifier and raises you to nobility."));
5044 if (true || game::TruthQuestion(CONST_S("Do you want to become a duke? [y/n]"), REQUIRES_ANSWER
)) {
5045 game::TextScreen(CONST_S(
5046 "Later you receive a small dukedom in the middle of tundra\n"
5047 "where you rule with justice till the end of your content life.\n\n"
5048 "You are victorious!"));
5049 game::GetCurrentArea()->SendNewDrawRequest();
5050 game::DrawEverything();
5051 PLAYER
->ShowAdventureInfo();
5052 festring Msg
= CONST_S("retrieved the Shirt of the Golden Eagle and was raised to nobility");
5053 AddScoreEntry(Msg
, 4, false);
5056 GetArea()->SendNewDrawRequest();
5060 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.\"");
5061 /* And now we actually make his face change color ;-) */
5062 GetHead()->GetMainMaterial()->SetSkinColor(MakeRGB16(255, 75, 50));
5063 GetHead()->UpdatePictures();
5064 SendNewDrawRequest();
5065 game::AskForEscPress(CONST_S("You are attacked!"));
5066 PLAYER
->GetTeam()->Hostility(GetTeam());
5067 game::SetStoryState(2);
5071 if (PLAYER
->HasHeadOfElpuri()) {
5072 game::TextScreen(CONST_S(
5073 "You have slain Elpuri, and Petrus grants you the freedom you desire.\n"
5074 "You spend the next months in Attnam as an honored hero."));
5075 if (true || game::TruthQuestion(CONST_S("Do you want to sail beyond the sunset? [y/n]"), REQUIRES_ANSWER
)) {
5076 game::TextScreen(CONST_S(
5077 "When the sea finally melts, you board the first ship,\n"
5078 "leaving your past forever behind.\n\n"
5079 "You are victorious!"));
5080 game::GetCurrentArea()->SendNewDrawRequest();
5081 game::DrawEverything();
5082 PLAYER
->ShowAdventureInfo();
5083 festring Msg
= CONST_S("defeated Elpuri and continued to further adventures");
5084 AddScoreEntry(Msg
, 2, false);
5087 GetArea()->SendNewDrawRequest();
5092 if (!game::GetStoryState()) {
5093 if (PLAYER
->RemoveEncryptedScroll()) {
5094 game::TextScreen(CONST_S(
5095 "You kneel down and bow before the high priest and hand him the encrypted scroll.\n"
5096 "Petrus raises his arm, the scroll glows yellow, and lo! The letters are clear and\n"
5097 "readable. Petrus asks you to voice them aloud. The first two thousand words praise\n"
5098 "Valpurus the Creator and all His manifestations and are followed by a canticle of\n"
5099 "Saint Petrus the Lion-Hearted lasting roughly three thousand words. Finally there\n"
5100 "are some sentences actually concerning your mission:\n\n"
5101 "\"Alas, I fear dirty tongues have spread lies to my Lord's ears. I assure all tales\n"
5102 "of treasures here in New Attnam are but mythic legends. There is nothing of value here.\n"
5103 "The taxes are already an unbearable burden and I can't possibly pay more. However I do\n"
5104 "not question the wisdom of the government's decisions. I will contribute what I can:\n"
5105 "the ostriches will deliver an extra 10000 bananas to the capital and additionally the\n"
5106 "slave that brought the message will henceforth be at Your disposal. I am certain this\n"
5107 "satisfies the crown's needs.\"\n\n"
5108 "\"Yours sincerely,\n"
5109 "Richel Decos, the viceroy of New Attnam\""));
5110 game::TextScreen(CONST_S(
5111 "You almost expected the last bit. Petrus seems to be deep in his thoughts and you\n"
5112 "wonder what shape your destiny is taking in his mind. Suddenly he seems to return\n"
5113 "to this reality and talks to you.\n\n"
5114 "\"Oh, thou art still here. We were just discussing telepathically with Sir Galladon.\n"
5115 "We started doubting Decos's alleged poverty a while back when he bought a couple of\n"
5116 "medium-sized castles nearby. Thy brethren from New Attnam have also told Us about\n"
5117 "vast riches seized from them. Our law says all such stolen valuables belong to\n"
5118 "the Cathedral's treasury, so this is a severe claim. However, proof is needed,\n"
5119 "and even if such was provided, We couldn't send soldiers over the snow fields\n"
5121 if (game::GetLiberator()) {
5122 //TODO: do something?
5123 game::TextScreen(CONST_S(
5124 "\"Thy brethren from New Attnam have also told Us that Decos dies while sleeping.\n"
5125 "While We are sad to hear this, We hope that We shall not be forced to send our\n"
5126 "soldiers to New Attnam. We are sure that Our people there will work even better now.\""));
5128 game::TextScreen(CONST_S(
5129 "\"However, since thou now servest Us, We ought to find thee something to do. Sir\n"
5130 "Galladon hath told Us his agents witnessed thou leaving the dreaded underwater tunnel.\n"
5131 "This means thou most likely hast defeated genetrix vesana and art a talented warrior.\n"
5132 "We happen to have a task perfect for such a person. An evil dark frog named Elpuri who\n"
5133 "hates Valpurus and Attnam more than anything hath taken control over an abandoned mine\n"
5134 "nearby. It is pestering our fine city in many ways and reconnaissance has reported an\n"
5135 "army of monsters gathering in the cave. Our guards are not trained to fight underground\n"
5136 "and We dare not send them. To make things worse, someone hath recently stolen Us the\n"
5137 "greatest armor in existence - the Shirt of the Golden Eagle. Elpuri cannot wear\n"
5138 "it but he who can is now nearly immortal.\"\n\n"
5139 "\"We have marked the location of the gloomy cave on thy world map. We want you to dive\n"
5140 "into it and slay the vile frog. Bring Us its head and We reward thee with freedom.\n"
5141 "Shouldst thou also find the Shirt, We'll knight thee. Good luck, and return when\n"
5142 "thou hast succeeded.\""));
5143 game::LoadWorldMap();
5144 v2 ElpuriCavePos
= game::GetWorldMap()->GetEntryPos(0, ELPURI_CAVE
);
5145 game::GetWorldMap()->GetWSquare(ElpuriCavePos
)->ChangeOWTerrain(elpuricave::Spawn());
5146 game::GetWorldMap()->RevealEnvironment(ElpuriCavePos
, 1);
5147 game::SaveWorldMap();
5148 GetArea()->SendNewDrawRequest();
5149 ADD_MESSAGE("\"And by the way, visit the librarian. He might have advice for thee.\"");
5150 game::SetStoryState(1);
5152 ADD_MESSAGE("\"Yes, citizen? We are quite busy now, thou shalt not disturb Us without proper cause.\"");
5156 /* StoryState == 1 */
5157 ADD_MESSAGE("Petrus says: \"Bring me the head of Elpuri and we'll talk.\"");
5161 truth
petrus::MoveTowardsHomePos () {
5162 if (GetPos() != v2(28, 20)) {
5163 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s disappears.", CHAR_NAME(DEFINITE
));
5164 GetLevel()->GetLSquare(28, 20)->KickAnyoneStandingHereAway();
5165 Move(v2(28, 20), true);
5166 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s appears.", CHAR_NAME(DEFINITE
));
5174 ///////////////////////////////////////////////////////////////////////////////
5175 void raven::BeTalkedTo () {
5176 if (GetRelation(PLAYER
) == HOSTILE
) {
5177 ADD_MESSAGE("I bet you are with those filthy Attnamanese bastards!");
5180 if (!game::GetRingOfThieves()) {
5181 if (PLAYER
->RemoveRingOfThieves()) {
5182 game::TextScreen(CONST_S(
5183 "You hand over the Ring of Thieves, Raven's eyes glow in amazement.\n"
5184 "\"May Cleptia bless this mighty warrior, whom vanquished Vulcan-Loki!\n"
5185 "Retrieving the ring is no easy task, Vulcan is a powerful adversary.\n"
5186 "The importance of the Ring of Thieves is great. It is used to channel\n"
5187 "Cleptia's power to help Mondedr avoid it's enemies, including Petrus.\n"
5188 "Without it we would have been raided by every nation that hates us.\n"
5189 "Not a mere mortal like Vulcan-Loki could channel the ring's power for\n"
5190 "himself so he decided to contract a deal with Oree to assist him.\n"
5191 "To reward your efforts I will give you the artifact whip, Gleipnir.\"\n\n"
5192 "\"I pray to Cleptia that you will use it well..\"\n\n"""));
5193 game::GetGod(CLEPTIA
)->AdjustRelation(500);
5194 game::GetGod(NEFAS
)->AdjustRelation(50);
5195 game::GetGod(SCABIES
)->AdjustRelation(50);
5196 game::GetGod(INFUSCOR
)->AdjustRelation(50);
5197 game::GetGod(CRUENTUS
)->AdjustRelation(50);
5198 game::GetGod(MORTIFER
)->AdjustRelation(50);
5199 meleeweapon
*Weapon
= whipofthievery::Spawn();
5200 Weapon
->InitMaterials(MAKE_MATERIAL(SPIDER_SILK
), MAKE_MATERIAL(EBONY_WOOD
), true);
5201 PLAYER
->GetGiftStack()->AddItem(Weapon
);
5202 GetArea()->SendNewDrawRequest();
5203 ADD_MESSAGE("A whip materializes near your feet.");
5204 game::SetRingOfThieves(1);
5206 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.\"");
5209 /* StoryState == 100 */
5210 ADD_MESSAGE("\"I must thank you again, I hope you make good use of that whip.\"");
5215 ///////////////////////////////////////////////////////////////////////////////
5216 void mysteryman::BeTalkedTo () {
5217 if (GetRelation(PLAYER
) == HOSTILE
) {
5218 ADD_MESSAGE("This is why the government doesn't mess with me, fool!");
5221 if (!game::GetMondedrPass()) {
5222 if (PLAYER
->RemoveMondedrPass()) {
5223 game::TextScreen(CONST_S(
5224 "You hand over the mondedr pass,\n"
5225 "the man quickly snatches it and starts reading it right away.\n"
5226 "The man scans the text very quickly, his eyes run around a hundred laps per second.\n"
5227 "His eyes come to a halt.\n"
5228 "\"I have revealed the location of Mondedr.\" He hands you a map.\n"
5229 "\"It is a good thing I was born in this world, no? You owe me nothing, the \n"
5230 "the amount of information in the sheet of paper is what repays it.\"\n\n"""));
5231 game::LoadWorldMap();
5232 v2 MondedrPos
= game::GetWorldMap()->GetEntryPos(0, MONDEDR
);
5233 game::GetWorldMap()->GetWSquare(MondedrPos
)->ChangeOWTerrain(mondedr::Spawn());
5234 game::GetWorldMap()->RevealEnvironment(MondedrPos
, 1);
5235 game::SaveWorldMap();
5236 GetArea()->SendNewDrawRequest();
5237 ADD_MESSAGE("\"And by the way, the government always watches you.\"");
5238 game::SetMondedrPass(1);
5240 ADD_MESSAGE("\"Shoo, come back if you have a sheet of paper they call 'Mondedr Pass'\"");
5243 /* StoryState == 100 */
5244 ADD_MESSAGE("The man says: \"I don't have anymore business with you, shoo.\"");
5249 ///////////////////////////////////////////////////////////////////////////////
5250 void imperialist::BeTalkedTo () {
5251 decosadshirt
*Shirt
= static_cast<decosadshirt
*>(PLAYER
->SearchForItem(this, &item::IsDecosAdShirt
));
5253 ulong Reward
= Shirt
->GetEquippedTicks()/500;
5255 ADD_MESSAGE("%s smiles. \"I see you have advertised our company diligently. Here's %ldgp as a token of my gratitude.\"", CHAR_NAME(DEFINITE
), Reward
);
5256 PLAYER
->EditMoney(Reward
);
5257 Shirt
->SetEquippedTicks(0);
5258 } else if (!(RAND()%5)) {
5259 ADD_MESSAGE("\"Come back when you've worn the shirt for some time and I'll reward you generously!\"");
5264 if (GetRelation(PLAYER
) == HOSTILE
)
5265 ProcessAndAddMessage(GetHostileReplies()[RandomizeReply(Said
, GetHostileReplies().Size
)]);
5266 else if (!game::PlayerIsSumoChampion())
5267 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said
, GetFriendlyReplies().Size
)]);
5269 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said
, GetFriendlyReplies().Size
-1)]);
5273 void imperialist::DisplayStethoscopeInfo (character
*) const {
5274 ADD_MESSAGE("You hear coins clinking inside.");
5278 void imperialist::CreateCorpse (lsquare
*Square
) {
5279 if (!game::GetLiberator()) {
5280 game::SetLiberator(1);
5281 ADD_MESSAGE("You liberate citizens of New Attnam!");
5283 imperialistsysbase::CreateCorpse(Square
);
5287 ///////////////////////////////////////////////////////////////////////////////
5288 exiledpriest::exiledpriest () :
5289 exiledpriestsysbase(),
5295 exiledpriest::~exiledpriest () {
5299 void exiledpriest::Save (outputfile
&saveFile
) const {
5300 priest::Save(saveFile
);
5301 saveFile
<< mAtHome
;
5305 void exiledpriest::Load (inputfile
&saveFile
) {
5306 priest::Load(saveFile
);
5307 saveFile
>> mAtHome
;
5311 void exiledpriest::healBodyParts () {
5312 for (int c
= 0; c
< PLAYER
->GetBodyParts(); ++c
) {
5313 if (!PLAYER
->GetBodyPart(c
) && PLAYER
->CanCreateBodyPart(c
)) {
5314 truth HasOld
= false;
5315 for (std::list
<ulong
>::const_iterator i
= PLAYER
->GetOriginalBodyPartID(c
).begin(); i
!= PLAYER
->GetOriginalBodyPartID(c
).end(); ++i
) {
5316 bodypart
*OldBodyPart
= static_cast<bodypart
*>(PLAYER
->SearchForItem(*i
));
5319 if (!OldBodyPart
->CanRegenerate())
5320 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());
5322 ADD_MESSAGE("\"I will put your old %s back.\"", PLAYER
->GetBodyPartName(c
).CStr());
5323 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5324 OldBodyPart
->SetHP(1);
5325 OldBodyPart
->RemoveFromSlot();
5326 PLAYER
->AttachBodyPart(OldBodyPart
);
5327 healBodyParts(); //FIXME
5334 ADD_MESSAGE("\"I could summon up a new %s.\"", PLAYER
->GetBodyPartName(c
).CStr());
5336 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());
5337 if (game::TruthQuestion(CONST_S("Agreed? [y/N]"))) {
5338 PLAYER
->CreateBodyPart(c
);
5339 PLAYER
->GetBodyPart(c
)->SetHP(1);
5340 healBodyParts(); //FIXME
5348 void exiledpriest::healDeseases () {
5349 if (PLAYER
->TemporaryStateIsActivated(POISONED
)) {
5350 ADD_MESSAGE("\"You seem to be rather ill. I could give you a small dose of antidote.\"");
5351 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5352 ADD_MESSAGE("You feel better.");
5353 PLAYER
->DeActivateTemporaryState(POISONED
);
5356 if (PLAYER
->TemporaryStateIsActivated(PARASITIZED
)) {
5357 ADD_MESSAGE("\"You seem to have something inside you. I could give you a small dose of antidote.\"");
5358 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5359 ADD_MESSAGE("You feel better.");
5360 PLAYER
->DeActivateTemporaryState(PARASITIZED
);
5363 if (PLAYER
->TemporaryStateIsActivated(LEPROSY
)) {
5364 ADD_MESSAGE("\"You seem to have contracted the vile disease of leprosy. I could give you a small dose of medicince.\"");
5365 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5366 ADD_MESSAGE("You feel better.");
5367 PLAYER
->DeActivateTemporaryState(LEPROSY
);
5370 if (PLAYER
->TemporaryStateIsActivated(LYCANTHROPY
)) {
5371 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());
5372 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5373 ADD_MESSAGE("You feel better.");
5374 PLAYER
->DeActivateTemporaryState(LYCANTHROPY
);
5380 void exiledpriest::healAll () {
5387 void exiledpriest::BeTalkedTo () {
5388 if (GetRelation(PLAYER
) != HOSTILE
&& game::GetLiberator()) {
5392 "\"Let %s bless you! I can return to my temple now! "
5393 "Get this things and remember how kind %s is!\"",
5394 GetMasterGod()->GetName(), GetMasterGod()->GetName());
5395 //GetMasterGod()->GetObjectPronoun());
5399 potion
*bottle
= potion::Spawn(0, NO_MATERIALS
);
5400 bottle
->InitMaterials(MAKE_MATERIAL(GLASS
), MAKE_MATERIAL(HEALING_LIQUID
));
5401 PLAYER
->GetStack()->AddItem(bottle
);
5402 ADD_MESSAGE("Priestess gives %s to you.", bottle
->CHAR_DESCRIPTION(DEFINITE
));
5405 potion
*bottle
= potion::Spawn(0, NO_MATERIALS
);
5406 bottle
->InitMaterials(MAKE_MATERIAL(GLASS
), MAKE_MATERIAL(ANTIDOTE_LIQUID
));
5407 PLAYER
->GetStack()->AddItem(bottle
);
5408 ADD_MESSAGE("Priestess gives %s to you.", bottle
->CHAR_DESCRIPTION(DEFINITE
));
5410 if (RAND_N(100) >= 90) {
5411 potion
*bottle
= potion::Spawn(0, NO_MATERIALS
);
5412 bottle
->InitMaterials(MAKE_MATERIAL(GLASS
), MAKE_MATERIAL(VODKA
));
5413 PLAYER
->GetStack()->AddItem(bottle
);
5414 ADD_MESSAGE("Priestess gives %s to you.", bottle
->CHAR_DESCRIPTION(DEFINITE
));
5417 ADD_MESSAGE("I will heal you for free.");
5421 priest::BeTalkedTo();
5425 truth
exiledpriest::MoveTowardsHomePos () {
5426 if (!mAtHome
) return false;
5428 if (GetPos() != homePos
) {
5429 SetGoingTo(homePos
);
5430 return MoveTowardsTarget(false) || (!GetPos().IsAdjacent(homePos
) && MoveRandomly());
5436 void exiledpriest::GetAICommand () {
5437 priest::GetAICommand();