renamed alot of types; hope this will not break the game
[k8-i-v-a-n.git] / src / game / human.cpp
blob9b397da67058fa7d30f176456594739ba2b14e54
1 /*
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
8 * See LICENSING which should be included
9 * along with this file for more details
13 /* Compiled through charsset.cpp */
15 cint humanoid::DrawOrder[] = { TORSO_INDEX, GROIN_INDEX, RIGHT_LEG_INDEX, LEFT_LEG_INDEX, RIGHT_ARM_INDEX, LEFT_ARM_INDEX, HEAD_INDEX };
17 truth humanoid::BodyPartIsVital(int I) const { return I == TORSO_INDEX || I == HEAD_INDEX || I == GROIN_INDEX; }
18 truth humanoid::BodyPartCanBeSevered(int I) const { return I != TORSO_INDEX && I != GROIN_INDEX; }
19 int humanoid::OpenMultiplier() const { return HasAUsableArm() ? 1 : 3; }
20 int humanoid::CloseMultiplier() const { return HasAUsableArm() ? 1 : 2; }
21 int humanoid::GetCarryingStrength() const { return Max(GetAttribute(LEG_STRENGTH), 1) + CarryingBonus; }
22 void humanoid::CalculateBodyParts() { BodyParts = HUMANOID_BODYPARTS; }
23 void humanoid::CalculateAllowedWeaponSkillCategories() { AllowedWeaponSkillCategories = WEAPON_SKILL_CATEGORIES; }
25 v2 farmer::GetHeadBitmapPos() const { return v2(96, (4 + (RAND() & 1)) << 4); }
26 v2 farmer::GetRightArmBitmapPos() const { return v2(64, (RAND() & 1) << 4); }
28 void guard::SetWayPoints(const fearray<packv2>& What) { ArrayToVector(What, WayPoints); }
30 cchar* oree::FirstPersonBiteVerb() const { return "vomit acidous blood at"; }
31 cchar* oree::FirstPersonCriticalBiteVerb() const { return "vomit very acidous blood at"; }
32 cchar* oree::ThirdPersonBiteVerb() const { return "vomits acidous blood at"; }
33 cchar* oree::ThirdPersonCriticalBiteVerb() const { return "vomits very acidous blood at"; }
34 cchar* oree::BiteNoun() const { return "liquid"; }
36 truth skeleton::BodyPartIsVital(int I) const { return I == GROIN_INDEX || I == TORSO_INDEX; }
38 truth communist::ShowClassDescription() const { return GetAssignedName() != "Ivan"; }
40 v2 housewife::GetHeadBitmapPos() const { return v2(112, (RAND() % 6) << 4); }
42 truth zombie::BodyPartIsVital(int I) const { return I == GROIN_INDEX || I == TORSO_INDEX; }
43 festring zombie::GetZombieDescription() const { return Description; }
45 truth angel::BodyPartIsVital(int I) const { return I == TORSO_INDEX || I == HEAD_INDEX; }
47 truth genie::BodyPartIsVital(int I) const { return I == TORSO_INDEX || I == HEAD_INDEX; }
49 material* golem::CreateBodyPartMaterial(int, sLong Volume) const { return MAKE_MATERIAL(GetConfig(), Volume); }
51 truth sumowrestler::EquipmentIsAllowed(int I) const { return I == BELT_INDEX; }
53 truth ennerbeast::Hit(character* Enemy, v2, int, int)
55 if(CheckIfTooScaredToHit(Enemy))
56 return false;
58 if(RAND() & 1)
59 ADD_MESSAGE("%s yells: UGH UGHAaaa!", CHAR_DESCRIPTION(DEFINITE));
60 else
61 ADD_MESSAGE("%s yells: Uga Ugar Ugade Ugat!", CHAR_DESCRIPTION(DEFINITE));
63 rect Rect;
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));
71 if(ScreamStrength)
73 character* Char = GetNearSquare(x, y)->GetCharacter();
75 if(Char && Char != this)
77 msgsystem::EnterBigMessageMode();
79 if(Char->IsPlayer())
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);
93 EditNP(-100);
94 EditAP(-1000000 / GetCWeaponSkill(BITE)->GetBonus());
95 EditStamina(-1000, false);
96 return true;
99 void skeleton::CreateCorpse(lsquare* Square)
101 if(GetHead())
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());
112 SendToHell();
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);
131 break;
134 if(GetLeftWielded())
135 for(std::list<sweaponskill*>::iterator i = SWeaponSkill.begin(); i != SWeaponSkill.end(); ++i)
136 if((*i)->IsSkillOf(GetLeftWielded()))
138 SetCurrentLeftSWeaponSkill(*i);
139 break;
143 truth golem::MoveRandomly()
145 if(!(RAND() % 500))
147 Engrave(CONST_S("Golem Needs Master"));
148 EditAP(-1000);
149 return true;
151 else
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))
163 return;
165 if(FollowLeader(GetLeader()))
166 return;
168 if(MoveRandomly())
169 return;
171 EditAP(-1000);
174 item* humanoid::GetMainWielded() const
176 if(GetMainArm())
177 if(GetMainArm()->GetWielded())
178 return GetMainArm()->GetWielded();
179 else
180 if(GetSecondaryArm())
181 return GetSecondaryArm()->GetWielded();
182 else
183 return 0;
184 else
185 if(GetSecondaryArm())
186 return GetSecondaryArm()->GetWielded();
187 else
188 return 0;
191 item* humanoid::GetSecondaryWielded() const
193 if(GetMainArm() && GetMainArm()->GetWielded() && GetSecondaryArm())
194 return GetSecondaryArm()->GetWielded();
195 else
196 return 0;
199 truth humanoid::Hit(character* Enemy, v2 HitPos, int Direction, int Flags)
201 if(CheckIfTooScaredToHit(Enemy))
202 return false;
204 if(IsPlayer())
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]")))
207 return false;
209 else if(GetAttribute(WISDOM) >= Enemy->GetAttackWisdomLimit())
210 return false;
212 if(GetBurdenState() == OVER_LOADED)
214 if(IsPlayer())
215 ADD_MESSAGE("You cannot fight while carrying so much.");
217 return false;
220 int c, AttackStyles;
222 for(c = 0, AttackStyles = 0; c < 8; ++c)
223 if(GetAttackStyle() & (1 << c))
224 ++AttackStyles;
226 int Chosen = RAND() % AttackStyles;
228 for(c = 0, AttackStyles = 0; c < 8; ++c)
229 if(GetAttackStyle() & (1 << c) && AttackStyles++ == Chosen)
231 Chosen = 1 << c;
232 break;
235 switch(Chosen)
237 case USE_ARMS:
238 if(CanAttackWithAnArm() && (!(Flags & SADIST_HIT) || HasSadistWeapon()))
240 msgsystem::EnterBigMessageMode();
241 Hostility(Enemy);
242 sLong FirstAPCost = 0, SecondAPCost = 0;
243 arm* FirstArm, * SecondArm;
245 if(RAND() & 1)
247 FirstArm = GetRightArm();
248 SecondArm = GetLeftArm();
250 else
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());
276 EditNP(-50);
277 EditAP(-Max(FirstAPCost, SecondAPCost));
278 EditStamina(-10000 / Strength, false);
279 msgsystem::LeaveBigMessageMode();
280 return true;
282 case USE_LEGS:
283 if(HasTwoUsableLegs())
285 msgsystem::EnterBigMessageMode();
286 Hostility(Enemy);
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();
293 return true;
295 case USE_HEAD:
296 if(GetHead())
298 msgsystem::EnterBigMessageMode();
299 Hostility(Enemy);
300 Bite(Enemy, HitPos, Direction, Flags & SADIST_HIT);
301 msgsystem::LeaveBigMessageMode();
302 return true;
304 default:
305 if(IsPlayer())
306 ADD_MESSAGE("You are currently quite unable to damage anything.");
308 return false;
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");
320 Buffer.Resize(30);
321 Buffer << CurrentRightSWeaponSkill->GetLevel();
322 Buffer.Resize(40);
323 Buffer << CurrentRightSWeaponSkill->GetHits() / 100;
324 Buffer.Resize(50);
326 if(CurrentRightSWeaponSkill->GetLevel() != 20)
327 Buffer << (CurrentRightSWeaponSkill->GetLevelMap(CurrentRightSWeaponSkill->GetLevel() + 1) - CurrentRightSWeaponSkill->GetHits()) / 100;
328 else
329 Buffer << '-';
331 Buffer.Resize(60);
332 int Bonus = CurrentRightSWeaponSkill->GetBonus();
333 Buffer << '+' << (Bonus - 1000) / 10;
335 if(Bonus %= 10)
336 Buffer << '.' << Bonus;
338 Buffer << '%';
339 List.AddEntry(Buffer, WHITE);
340 Something = true;
343 if(CurrentLeftSWeaponSkill && CurrentLeftSWeaponSkill->GetHits() / 100)
345 if(!Something)
346 List.AddEntry(CONST_S(""), LIGHT_GRAY);
348 festring Buffer = CONST_S("left accustomization");
349 Buffer.Resize(30);
350 Buffer << CurrentLeftSWeaponSkill->GetLevel();
351 Buffer.Resize(40);
352 Buffer << CurrentLeftSWeaponSkill->GetHits() / 100;
353 Buffer.Resize(50);
355 if(CurrentLeftSWeaponSkill->GetLevel() != 20)
356 Buffer << (CurrentLeftSWeaponSkill->GetLevelMap(CurrentLeftSWeaponSkill->GetLevel() + 1) - CurrentLeftSWeaponSkill->GetHits()) / 100;
357 else
358 Buffer << '-';
360 Buffer.Resize(60);
361 int Bonus = CurrentLeftSWeaponSkill->GetBonus();
362 Buffer << '+' << (Bonus - 1000) / 10;
364 if(Bonus %= 10)
365 Buffer << '.' << Bonus;
367 Buffer << '%';
368 List.AddEntry(Buffer, WHITE);
369 Something = true;
372 return Something;
375 void priest::BeTalkedTo () {
376 if (GetRelation(PLAYER) == HOSTILE) {
377 ADD_MESSAGE("\"Sinner! My hands shall pour Dinive Wrath upon thee!\"");
378 return;
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));
385 if (OldBodyPart) {
386 HasOld = true;
387 sLong Price = GetConfig() == VALPURUS ? 50 : 10;
388 if (PLAYER->GetMoney() >= Price) {
389 if (!OldBodyPart->CanRegenerate())
390 ADD_MESSAGE("\"Sorry, I cannot put back bodyparts made of %s, not even your severed %s.\"", OldBodyPart->GetMainMaterial()->GetName(false, false).CStr(), PLAYER->GetBodyPartName(c).CStr());
391 else {
392 ADD_MESSAGE("\"I could put your old %s back in exchange for %d gold.\"", PLAYER->GetBodyPartName(c).CStr(), Price);
393 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
394 OldBodyPart->SetHP(1);
395 PLAYER->SetMoney(PLAYER->GetMoney()-Price);
396 SetMoney(GetMoney()+Price);
397 OldBodyPart->RemoveFromSlot();
398 PLAYER->AttachBodyPart(OldBodyPart);
399 return;
402 } else {
403 ADD_MESSAGE("\"Your %s is severed. Help yourself and get %dgp and I'll help you too.\"", PLAYER->GetBodyPartName(c).CStr(), Price);
407 sLong Price = GetConfig() == VALPURUS ? 100 : 20;
408 if (PLAYER->GetMoney() >= Price) {
409 if (HasOld)
410 ADD_MESSAGE("\"I could still summon up a new one for %d gold.\"", Price);
411 else
412 ADD_MESSAGE("\"Since you don't seem to have your original %s with you, I could summon up a new one for %d gold.\"", PLAYER->GetBodyPartName(c).CStr(), Price);
413 if (game::TruthQuestion(CONST_S("Agreed? [y/N]"))) {
414 PLAYER->SetMoney(PLAYER->GetMoney()-Price);
415 SetMoney(GetMoney()+Price);
416 PLAYER->CreateBodyPart(c);
417 PLAYER->GetBodyPart(c)->SetHP(1);
418 return;
420 } else if (!HasOld) {
421 ADD_MESSAGE("\"You don't have your original %s with you. I could create you a new one, but my Divine Employer is not a communist and you need %dgp first.\"", PLAYER->GetBodyPartName(c).CStr(), Price);
425 if (PLAYER->TemporaryStateIsActivated(POISONED)) {
426 sLong Price = GetConfig() == VALPURUS ? 25 : 5;
427 if (PLAYER->GetMoney() >= Price) {
428 ADD_MESSAGE("\"You seem to be rather ill. I could give you a small dose of antidote for %d gold pieces.\"", Price);
429 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
430 ADD_MESSAGE("You feel better.");
431 PLAYER->DeActivateTemporaryState(POISONED);
432 PLAYER->SetMoney(PLAYER->GetMoney()-Price);
433 SetMoney(GetMoney()+Price);
434 return;
436 } else {
437 ADD_MESSAGE("\"You seem to be rather ill. Get %d gold pieces and I'll fix that.\"", Price);
440 if (PLAYER->TemporaryStateIsActivated(LEPROSY)) {
441 sLong Price = GetConfig() == VALPURUS ? 100 : 20;
442 if (PLAYER->GetMoney() >= Price) {
443 ADD_MESSAGE("\"You seem to have contracted the vile disease of leprosy. I could give you a small dose of medicince for %d gold pieces.\"", Price);
444 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
445 ADD_MESSAGE("You feel better.");
446 PLAYER->DeActivateTemporaryState(LEPROSY);
447 PLAYER->SetMoney(PLAYER->GetMoney()-Price);
448 SetMoney(GetMoney()+Price);
449 return;
451 } else {
452 ADD_MESSAGE("\"You seem to be falling apart. Get %d gold pieces and I'll fix that.\"", Price);
455 if (PLAYER->TemporaryStateIsActivated(LYCANTHROPY)) {
456 sLong Price = GetConfig() == VALPURUS ? 100 : 20;
457 if (PLAYER->GetMoney() >= Price) {
458 ADD_MESSAGE("\"You seem to be turning into a werewolf quite frequently. Well, everyone has right to little secret habits, but if you wish to donate %dgp to %s, maybe I could pray %s to remove the canine blood from your veins, just so you don't scare our blessed youth.\"", Price, GetMasterGod()->GetName(), GetMasterGod()->GetObjectPronoun());
459 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
460 ADD_MESSAGE("You feel better.");
461 PLAYER->DeActivateTemporaryState(LYCANTHROPY);
462 PLAYER->SetMoney(PLAYER->GetMoney()-Price);
463 SetMoney(GetMoney()+Price);
464 return;
466 } else {
467 ADD_MESSAGE("\"You seem to be lycanthropic. I might be able to do something for that but I need %dgp for the ritual materials first.\"", Price);
470 humanoid::BeTalkedTo();
474 void skeleton::BeTalkedTo()
476 if(GetHead())
477 humanoid::BeTalkedTo();
478 else
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();)
491 if(*i != this)
493 character* Char = *i++;
494 Char->ChangeTeam(PLAYER->GetTeam());
496 else
497 ++i;
499 ChangeTeam(PLAYER->GetTeam());
501 else if(GetTeam() != PLAYER->GetTeam() && !(RAND() % 5))
502 ADD_MESSAGE("\"You weak. Learn killing and come back.\"");
503 else
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));
511 else
512 character::BeTalkedTo();
515 void slave::BeTalkedTo()
517 if(GetRelation(PLAYER) == HOSTILE)
519 ADD_MESSAGE("\"Yikes!\"");
520 return;
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());
538 RemoveHomeData();
541 else
542 ADD_MESSAGE("\"Don't touch me! Master doesn't want people to touch sale items. I'm worth 50 gold pieces, you know!\"");
544 return;
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!\"");
551 else
552 character::BeTalkedTo();
554 else
555 ADD_MESSAGE("\"I'm free! Rejoice!\"");
558 void slave::GetAICommand()
560 SeekLeader(GetLeader());
562 if(CheckForEnemies(true, true, true))
563 return;
565 if(CheckForUsefulItemsOnGround())
566 return;
568 if(FollowLeader(GetLeader()))
569 return;
571 if(CheckForDoors())
572 return;
574 if(!GetHomeRoom() || !GetHomeRoom()->MasterIsActive())
576 RemoveHomeData();
578 if(MoveRandomly())
579 return;
581 else if(MoveTowardsHomePos())
582 return;
584 EditAP(-1000);
587 void librarian::BeTalkedTo()
589 if(GetRelation(PLAYER) == HOSTILE)
591 ADD_MESSAGE("\"The pen is mightier than the sword! Fall, unlearned one!\"");
592 return;
595 static sLong Said;
597 switch(RandomizeReply(Said, 12))
599 case 0:
600 if(game::GetPetrus() && !game::GetStoryState())
601 ADD_MESSAGE("\"Thou shouldst visit Petrus if thou art in need of further adventures.\"");
602 else
603 ADD_MESSAGE("\"They say a wand of polymorph hath dozens of uses.\"");
605 break;
606 case 1:
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.\"");
609 else
610 ADD_MESSAGE("\"Thou shalt remember: Scientia est potentia.\"");
612 break;
613 case 2:
614 if(game::GetPetrus() && game::GetStoryState() == 1)
615 ADD_MESSAGE("\"Elpuri the Dark Frog abhors light and resides in a level of eternal darkness.\"");
616 else
617 ADD_MESSAGE("\"Shh! Thou shalt be silent in the library.\"");
619 break;
620 case 3:
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.\"");
623 else
624 ADD_MESSAGE("\"Dost thou not smell all the knowledge floating around here?\"");
626 break;
627 case 4:
628 ADD_MESSAGE("\"It is said that Loricatus, the god of smithing, can upgrade thy weapons' materials.\"");
629 break;
630 case 5:
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.\"");
633 else
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.\"");
636 break;
637 case 6:
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.\"");
639 break;
640 case 7:
641 ADD_MESSAGE("\"They say thou shouldst keep all the artifacts thou findst. They shall make thee famous after thy retirement.\"");
642 break;
643 case 8:
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.\"");
645 break;
646 case 9:
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.\"");
649 else
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.\"");
652 break;
653 case 10:
654 ADD_MESSAGE("\"If a man cannot choose, he ceases to be a man.\"");
655 break;
656 case 11:
657 ADD_MESSAGE("%s sighs: \"The censorship laws in this town are really too strict...\"", CHAR_DESCRIPTION(DEFINITE));
658 break;
662 truth communist::MoveRandomly()
664 switch(RAND() % 1000)
666 case 0:
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."));
671 return true;
672 case 1:
673 if(CanBeSeenByPlayer())
674 ADD_MESSAGE("%s engraves something to the ground.", CHAR_NAME(UNARTICLED));
676 Engrave(CONST_S("Proletarians of all countries, unite!"));
677 return true;
678 case 2:
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."));
683 return true;
684 default:
685 return character::MoveRandomly();
689 void zombie::BeTalkedTo()
691 if(GetRelation(PLAYER) == HOSTILE && PLAYER->GetAttribute(INTELLIGENCE) > 5)
693 if(RAND() % 5)
695 if(GetHead())
696 ADD_MESSAGE("\"Need brain!!\"");
697 else
698 ADD_MESSAGE("\"Need head with brain!!\"");
700 else
701 ADD_MESSAGE("\"Redrum! Redrum! Redrum!\"");
703 else
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));
723 armor* Equipment;
724 meleeweapon* Weapon;
726 switch(GetMasterGod()->GetBasicAlignment())
728 case GOOD:
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);
747 break;
748 case NEUTRAL:
749 Equipment = cloak::Spawn(0, SpecialFlags|NO_MATERIALS);
750 Equipment->InitMaterials(MAKE_MATERIAL(ANGEL_HAIR), !(SpecialFlags & NO_PIC_UPDATE));
751 Equipment->SetEnchantment(1);
752 SetCloak(Equipment);
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);
764 SetEndurance(40);
765 break;
766 case EVIL:
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)
796 if(!IsPlayer())
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());
806 else if(RAND() & 1)
807 ADD_MESSAGE("%s shouts: \"For %s!\"", CHAR_DESCRIPTION(DEFINITE), GetMasterGod()->GetName());
808 else
809 ADD_MESSAGE("%s screams: \"%s, here I come!\"", CHAR_DESCRIPTION(DEFINITE), GetMasterGod()->GetName());
811 if(KamikazeWeapon[RAND_N(KamikazeWeapon.size())]->Apply(this))
812 return true;
816 return humanoid::Hit(Enemy, HitPos, Direction, Flags);
819 void kamikazedwarf::GetAICommand()
821 if(GetHomeRoom())
822 StandIdleAI();
823 else
825 if(!RAND_N(50))
827 SingRandomSong();
828 return;
831 character::GetAICommand();
836 void axethrowerdwarf::CreateInitialEquipment (int SpecialFlags) {
837 SetRightWielded(meleeweapon::Spawn(AXE, SpecialFlags));
838 SetLeftWielded(meleeweapon::Spawn(AXE, SpecialFlags));
839 for (int k = 0; k < 6; ++k) GetStack()->AddItem(meleeweapon::Spawn(AXE));
840 GetStack()->AddItem(lantern::Spawn());
841 GetCWeaponSkill(AXES)->AddHit(GetWSkillHits());
842 GetCurrentRightSWeaponSkill()->AddHit(GetWSkillHits());
846 void axethrowerdwarf::GetAICommand () {
847 if (CheckThrowItemOpportunity()) return;
848 character::GetAICommand();
852 v2 axethrowerdwarf::GetDrawDisplacement (int j) const {
853 static v2 DrawDisplacement[] = { v2(0, 0), v2(0, 1), v2(0, -1), v2(0, -1), v2(0, -1), v2(0, 0), v2(0, 0) };
854 return DrawDisplacement[j];
858 col16 axethrowerdwarf::GetTorsoMainColor () const {
859 return GetMasterGod()->GetColor();
863 col16 axethrowerdwarf::GetGauntletColor () const {
864 return GetMasterGod()->GetColor();
868 col16 axethrowerdwarf::GetLegMainColor () const {
869 return GetMasterGod()->GetColor();
873 truth humanoid::CheckThrowItemOpportunity () {
874 if(!HasAUsableArm()) return false;
875 return character::CheckThrowItemOpportunity();
879 int humanoid::GetSize() const
881 int Size = 0;
883 if(GetHead())
884 Size += GetHead()->GetSize();
886 if(GetTorso())
887 Size += GetTorso()->GetSize();
889 leg* RightLeg = GetRightLeg();
890 leg* LeftLeg = GetLeftLeg();
892 if(LeftLeg && RightLeg)
893 Size += Max(LeftLeg->GetSize(), RightLeg->GetSize());
894 else if(LeftLeg)
895 Size += LeftLeg->GetSize();
896 else if(RightLeg)
897 Size += RightLeg->GetSize();
899 return Size;
902 sLong humanoid::GetBodyPartSize(int I, int TotalSize) const
904 switch(I)
906 case HEAD_INDEX: return 20;
907 case TORSO_INDEX: return ((TotalSize - 20) << 1) / 5;
908 case RIGHT_ARM_INDEX:
909 case LEFT_ARM_INDEX: return (TotalSize - 20) * 3 / 5;
910 case GROIN_INDEX: return (TotalSize - 20) / 3;
911 case RIGHT_LEG_INDEX:
912 case LEFT_LEG_INDEX: return (TotalSize - 20) * 3 / 5;
915 ABORT("Illegal humanoid bodypart size request!");
916 return 0;
919 sLong humanoid::GetBodyPartVolume(int I) const
921 switch(I)
923 case HEAD_INDEX: return 4000;
924 case TORSO_INDEX: return (GetTotalVolume() - 4000) * 13 / 30;
925 case RIGHT_ARM_INDEX:
926 case LEFT_ARM_INDEX: return (GetTotalVolume() - 4000) / 10;
927 case GROIN_INDEX: return (GetTotalVolume() - 4000) / 10;
928 case RIGHT_LEG_INDEX:
929 case LEFT_LEG_INDEX: return ((GetTotalVolume() - 4000) << 1) / 15;
932 ABORT("Illegal humanoid bodypart volume request!");
933 return 0;
936 bodypart* humanoid::MakeBodyPart(int I) const
938 switch(I)
940 case TORSO_INDEX: return humanoidtorso::Spawn(0, NO_MATERIALS);
941 case HEAD_INDEX: return head::Spawn(0, NO_MATERIALS);
942 case RIGHT_ARM_INDEX: return rightarm::Spawn(0, NO_MATERIALS);
943 case LEFT_ARM_INDEX: return leftarm::Spawn(0, NO_MATERIALS);
944 case GROIN_INDEX: return groin::Spawn(0, NO_MATERIALS);
945 case RIGHT_LEG_INDEX: return rightleg::Spawn(0, NO_MATERIALS);
946 case LEFT_LEG_INDEX: return leftleg::Spawn(0, NO_MATERIALS);
949 ABORT("Weird bodypart to make for a humanoid. It must be your fault!");
950 return 0;
953 truth humanoid::ReceiveDamage(character* Damager, int Damage, int Type, int TargetFlags, int Direction, truth Divide, truth PenetrateArmor, truth Critical, truth ShowMsg)
955 int ChooseFrom[MAX_BODYPARTS], BodyParts = 0;
957 if(TargetFlags & RIGHT_ARM && GetRightArm())
958 ChooseFrom[BodyParts++] = 2;
960 if(TargetFlags & LEFT_ARM && GetLeftArm())
961 ChooseFrom[BodyParts++] = 3;
963 if(TargetFlags & RIGHT_LEG && GetRightLeg())
964 ChooseFrom[BodyParts++] = 5;
966 if(TargetFlags & LEFT_LEG && GetLeftLeg())
967 ChooseFrom[BodyParts++] = 6;
969 if(TargetFlags & HEAD && GetHead())
970 ChooseFrom[BodyParts++] = 1;
972 if(TargetFlags & TORSO && GetTorso())
973 ChooseFrom[BodyParts++] = 0;
975 if(TargetFlags & GROIN && GetGroin())
976 ChooseFrom[BodyParts++] = 4;
978 if(!BodyParts)
979 return false;
981 truth Affected = false;
983 if(Divide)
985 int c;
986 sLong TotalVolume = 0;
988 for(c = 0; c < BodyParts; ++c)
989 TotalVolume += GetBodyPart(ChooseFrom[c])->GetBodyPartVolume();
991 for(c = 0; c < BodyParts; ++c)
992 if(ReceiveBodyPartDamage(Damager, sLong(Damage) * GetBodyPart(ChooseFrom[c])->GetBodyPartVolume() / TotalVolume, Type, ChooseFrom[c], Direction, PenetrateArmor, Critical, false))
993 Affected = true;
995 else
997 sLong Possibility[MAX_BODYPARTS], PossibilitySum = 0;
998 int Index = 0;
1000 for(int c = 0; c < BodyParts; ++c)
1001 PossibilitySum += Possibility[Index++] = GetBodyPart(ChooseFrom[c])->GetBodyPartVolume();
1003 Index = femath::WeightedRand(Possibility, PossibilitySum);
1004 Affected = ReceiveBodyPartDamage(Damager, Damage, Type, ChooseFrom[Index], Direction, PenetrateArmor, Critical, false);
1007 if(!Affected && ShowMsg)
1009 if(IsPlayer())
1010 ADD_MESSAGE("You are not hurt.");
1011 else if(CanBeSeenByPlayer())
1012 ADD_MESSAGE("%s is not hurt.", GetPersonalPronoun().CStr());
1015 if(DamageTypeAffectsInventory(Type))
1017 for(int c = 0; c < GetEquipments(); ++c)
1019 item* Equipment = GetEquipment(c);
1021 if(Equipment)
1022 Equipment->ReceiveDamage(Damager, Damage, Type);
1025 GetStack()->ReceiveDamage(Damager, Damage, Type);
1028 return Affected;
1031 arm* humanoid::GetMainArm() const
1033 return GetRightArm() ? GetRightArm() : GetLeftArm();
1036 arm* humanoid::GetSecondaryArm() const
1038 return GetRightArm() ? GetLeftArm() : 0;
1041 cchar* humanoid::GetEquipmentName(int I) const // convert to array
1043 switch(I)
1045 case HELMET_INDEX: return "helmet";
1046 case AMULET_INDEX: return "amulet";
1047 case CLOAK_INDEX: return "cloak";
1048 case BODY_ARMOR_INDEX: return "body armor";
1049 case BELT_INDEX: return "belt";
1050 case RIGHT_WIELDED_INDEX: return "right hand wielded";
1051 case LEFT_WIELDED_INDEX: return "left hand wielded";
1052 case RIGHT_RING_INDEX: return "right ring";
1053 case LEFT_RING_INDEX: return "left ring";
1054 case RIGHT_GAUNTLET_INDEX: return "right gauntlet";
1055 case LEFT_GAUNTLET_INDEX: return "left gauntlet";
1056 case RIGHT_BOOT_INDEX: return "right boot";
1057 case LEFT_BOOT_INDEX: return "left boot";
1060 return "forbidden piece of cloth";
1063 sorter humanoid::EquipmentSorter(int I) const
1065 switch(I)
1067 case HELMET_INDEX: return &item::IsHelmet;
1068 case AMULET_INDEX: return &item::IsAmulet;
1069 case CLOAK_INDEX: return &item::IsCloak;
1070 case BODY_ARMOR_INDEX: return &item::IsBodyArmor;
1071 case BELT_INDEX: return &item::IsBelt;
1072 case RIGHT_WIELDED_INDEX:
1073 case LEFT_WIELDED_INDEX: return 0;
1074 case RIGHT_RING_INDEX:
1075 case LEFT_RING_INDEX: return &item::IsRing;
1076 case RIGHT_GAUNTLET_INDEX:
1077 case LEFT_GAUNTLET_INDEX: return &item::IsGauntlet;
1078 case RIGHT_BOOT_INDEX:
1079 case LEFT_BOOT_INDEX: return &item::IsBoot;
1082 return 0;
1085 bodypart* humanoid::GetBodyPartOfEquipment(int I) const
1087 switch(I)
1089 case HELMET_INDEX:
1090 case AMULET_INDEX:
1091 return GetHead();
1092 case CLOAK_INDEX:
1093 case BODY_ARMOR_INDEX:
1094 case BELT_INDEX:
1095 return GetTorso();
1096 case RIGHT_WIELDED_INDEX:
1097 case RIGHT_RING_INDEX:
1098 case RIGHT_GAUNTLET_INDEX:
1099 return GetRightArm();
1100 case LEFT_WIELDED_INDEX:
1101 case LEFT_RING_INDEX:
1102 case LEFT_GAUNTLET_INDEX:
1103 return GetLeftArm();
1104 case RIGHT_BOOT_INDEX:
1105 return GetRightLeg();
1106 case LEFT_BOOT_INDEX:
1107 return GetLeftLeg();
1110 return 0;
1113 item* humanoid::GetEquipment(int I) const
1115 switch(I)
1117 case HELMET_INDEX: return GetHelmet();
1118 case AMULET_INDEX: return GetAmulet();
1119 case CLOAK_INDEX: return GetCloak();
1120 case BODY_ARMOR_INDEX: return GetBodyArmor();
1121 case BELT_INDEX: return GetBelt();
1122 case RIGHT_WIELDED_INDEX: return GetRightWielded();
1123 case LEFT_WIELDED_INDEX: return GetLeftWielded();
1124 case RIGHT_RING_INDEX: return GetRightRing();
1125 case LEFT_RING_INDEX: return GetLeftRing();
1126 case RIGHT_GAUNTLET_INDEX: return GetRightGauntlet();
1127 case LEFT_GAUNTLET_INDEX: return GetLeftGauntlet();
1128 case RIGHT_BOOT_INDEX: return GetRightBoot();
1129 case LEFT_BOOT_INDEX: return GetLeftBoot();
1132 return 0;
1135 void humanoid::SetEquipment(int I, item* What)
1137 switch(I)
1139 case HELMET_INDEX: SetHelmet(What); break;
1140 case AMULET_INDEX: SetAmulet(What); break;
1141 case CLOAK_INDEX: SetCloak(What); break;
1142 case BODY_ARMOR_INDEX: SetBodyArmor(What); break;
1143 case BELT_INDEX: SetBelt(What); break;
1144 case RIGHT_WIELDED_INDEX: SetRightWielded(What); break;
1145 case LEFT_WIELDED_INDEX: SetLeftWielded(What); break;
1146 case RIGHT_RING_INDEX: SetRightRing(What); break;
1147 case LEFT_RING_INDEX: SetLeftRing(What); break;
1148 case RIGHT_GAUNTLET_INDEX: SetRightGauntlet(What); break;
1149 case LEFT_GAUNTLET_INDEX: SetLeftGauntlet(What); break;
1150 case RIGHT_BOOT_INDEX: SetRightBoot(What); break;
1151 case LEFT_BOOT_INDEX: SetLeftBoot(What); break;
1155 void humanoid::SwitchToDig(item* DigItem, v2 Square)
1157 dig* Dig = dig::Spawn(this);
1159 if(GetRightArm())
1161 item* Item = GetRightArm()->GetWielded();
1163 if(Item && Item != DigItem)
1165 Dig->SetRightBackupID(GetRightArm()->GetWielded()->GetID());
1166 GetRightArm()->GetWielded()->MoveTo(GetStack());
1170 if(GetLeftArm())
1172 item* Item = GetLeftArm()->GetWielded();
1174 if(Item && Item != DigItem)
1176 Dig->SetLeftBackupID(GetLeftArm()->GetWielded()->GetID());
1177 GetLeftArm()->GetWielded()->MoveTo(GetStack());
1181 if(GetMainWielded() != DigItem)
1183 Dig->SetMoveDigger(true);
1184 DigItem->RemoveFromSlot();
1186 if(GetMainArm() && GetMainArm()->IsUsable())
1187 GetMainArm()->SetWielded(DigItem);
1188 else
1189 GetSecondaryArm()->SetWielded(DigItem);
1191 else
1192 Dig->SetMoveDigger(false);
1194 Dig->SetSquareDug(Square);
1195 SetAction(Dig);
1198 truth humanoid::CheckKick() const
1200 if(!CanKick())
1202 if(IsPlayer())
1203 ADD_MESSAGE("This race can't kick.");
1205 return false;
1208 if(GetUsableLegs() < 2)
1210 if(IsPlayer())
1211 ADD_MESSAGE("How are you going to do that with %s?", GetUsableLegs() ? "only one usable leg" : "no usable legs");
1213 return false;
1215 else
1216 return true;
1219 int humanoid::GetUsableLegs() const
1221 int Legs = 0;
1223 if(RightLegIsUsable())
1224 ++Legs;
1226 if(LeftLegIsUsable())
1227 ++Legs;
1229 return Legs;
1232 int humanoid::GetUsableArms() const
1234 int Arms = 0;
1236 if(RightArmIsUsable())
1237 ++Arms;
1239 if(LeftArmIsUsable())
1240 ++Arms;
1242 return Arms;
1245 truth humanoid::CheckThrow() const
1247 if(!character::CheckThrow())
1248 return false;
1250 if(HasAUsableArm())
1251 return true;
1252 else
1254 ADD_MESSAGE("You don't have a usable arm to do that!");
1255 return false;
1259 truth humanoid::CheckOffer() const
1261 if(HasAUsableArm())
1262 return true;
1263 else
1265 ADD_MESSAGE("You need a usable arm to offer.");
1266 return false;
1270 v2 humanoid::GetEquipmentPanelPos(int I) const // convert to array
1272 switch(I)
1274 case HELMET_INDEX: return v2(34, -22);
1275 case AMULET_INDEX: return v2(14, -22);
1276 case CLOAK_INDEX: return v2(-6, -22);
1277 case BODY_ARMOR_INDEX: return v2(54, -22);
1278 case BELT_INDEX: return v2(24, 70);
1279 case RIGHT_WIELDED_INDEX: return v2(-14, 4);
1280 case LEFT_WIELDED_INDEX: return v2(62, 4);
1281 case RIGHT_RING_INDEX: return v2(-14, 44);
1282 case LEFT_RING_INDEX: return v2(62, 44);
1283 case RIGHT_GAUNTLET_INDEX: return v2(-14, 24);
1284 case LEFT_GAUNTLET_INDEX: return v2(62, 24);
1285 case RIGHT_BOOT_INDEX: return v2(4, 70);
1286 case LEFT_BOOT_INDEX: return v2(44, 70);
1289 return v2(24, 12);
1292 void humanoid::DrawSilhouette(truth AnimationDraw) const
1294 int c;
1295 blitdata B1 = { DOUBLE_BUFFER,
1296 { 0, 0 },
1297 { 0, 0 },
1298 { TILE_SIZE, TILE_SIZE },
1299 { ivanconfig::GetContrastLuminance() },
1300 TRANSPARENT_COLOR,
1301 ALLOW_ANIMATE };
1303 v2 Where(RES.X - SILHOUETTE_SIZE.X - 39, 53);
1304 cint Equipments = GetEquipments();
1306 if(CanUseEquipment())
1307 for(c = 0; c < Equipments; ++c)
1308 if(GetBodyPartOfEquipment(c) && EquipmentIsAllowed(c))
1310 v2 Pos = Where + GetEquipmentPanelPos(c);
1312 if(!AnimationDraw)
1313 DOUBLE_BUFFER->DrawRectangle(Pos + v2(-1, -1), Pos + TILE_V2, DARK_GRAY);
1315 item* Equipment = GetEquipment(c);
1317 if(Equipment && (!AnimationDraw || Equipment->IsAnimated()))
1319 igraph::BlitBackGround(Pos, TILE_V2);
1320 B1.Dest = Pos;
1322 if(Equipment->AllowAlphaEverywhere())
1323 B1.CustomData |= ALLOW_ALPHA;
1325 Equipment->Draw(B1);
1326 B1.CustomData &= ~ALLOW_ALPHA;
1330 if(!AnimationDraw)
1332 blitdata B2 = { DOUBLE_BUFFER,
1333 { 0, 0 },
1334 { Where.X + 8, Where.Y },
1335 { SILHOUETTE_SIZE.X, SILHOUETTE_SIZE.Y },
1336 { 0 },
1338 0 };
1340 for(int c = 0; c < BodyParts; ++c)
1342 bodypart* BodyPart = GetBodyPart(c);
1344 if(BodyPart)
1346 int Type = BodyPart->IsUsable() ? SILHOUETTE_NORMAL : SILHOUETTE_INTER_LACED;
1347 bitmap* Cache = igraph::GetSilhouetteCache(c, BodyPart->GetConditionColorIndex(), Type);
1348 Cache->NormalMaskedBlit(B2);
1349 BodyPart->DrawScars(B2);
1355 int humanoid::GetGlobalResistance(int Type) const
1357 int Resistance = GetResistance(Type);
1359 if(GetCloak())
1360 Resistance += GetCloak()->GetResistance(Type);
1362 if(!(Type & PHYSICAL_DAMAGE))
1364 if(GetAmulet())
1365 Resistance += GetAmulet()->GetResistance(Type);
1367 if(GetRightRing())
1368 Resistance += GetRightRing()->GetResistance(Type);
1370 if(GetLeftRing())
1371 Resistance += GetLeftRing()->GetResistance(Type);
1374 return Resistance;
1377 truth humanoid::TryToRiseFromTheDead()
1379 int c;
1381 for(c = 0; c < BodyParts; ++c)
1382 if(!GetBodyPart(c))
1384 bodypart* BodyPart = SearchForOriginalBodyPart(c);
1386 if(BodyPart)
1388 BodyPart->RemoveFromSlot();
1389 AttachBodyPart(BodyPart);
1390 BodyPart->SetHP(1);
1394 for(c = 0; c < BodyParts; ++c)
1396 bodypart* BodyPart = GetBodyPart(c);
1398 if(BodyPartIsVital(c) && !BodyPart)
1399 if(!HandleNoBodyPart(c))
1400 return false;
1402 if(BodyPart)
1404 BodyPart->ResetSpoiling();
1406 if(BodyPart->CanRegenerate() || BodyPart->GetHP() < 1)
1407 BodyPart->SetHP(1);
1411 ResetStates();
1412 return true;
1415 truth humanoid::HandleNoBodyPart(int I)
1417 switch(I)
1419 case HEAD_INDEX:
1420 if(CanBeSeenByPlayer())
1421 ADD_MESSAGE("The headless body of %s vibrates violently.", CHAR_NAME(DEFINITE));
1423 return false;
1424 case GROIN_INDEX:
1425 if(CanBeSeenByPlayer())
1426 ADD_MESSAGE("The groinless body of %s vibrates violently.", CHAR_NAME(DEFINITE));
1428 return false;
1429 case TORSO_INDEX:
1430 ABORT("The corpse does not have a torso.");
1431 default:
1432 return true;
1436 v2 humanoid::GetBodyPartBitmapPos(int I, truth) const
1438 switch(I)
1440 case TORSO_INDEX: return GetTorsoBitmapPos();
1441 case HEAD_INDEX: return GetHeadBitmapPos();
1442 case RIGHT_ARM_INDEX: return GetRightArmBitmapPos();
1443 case LEFT_ARM_INDEX: return GetLeftArmBitmapPos();
1444 case GROIN_INDEX: return GetGroinBitmapPos();
1445 case RIGHT_LEG_INDEX: return GetRightLegBitmapPos();
1446 case LEFT_LEG_INDEX: return GetLeftLegBitmapPos();
1449 ABORT("Weird bodypart BitmapPos request for a humanoid!");
1450 return v2();
1453 col16 humanoid::GetBodyPartColorB(int I, truth) const
1455 switch(I)
1457 case TORSO_INDEX: return GetTorsoMainColor();
1458 case HEAD_INDEX: return GetCapColor();
1459 case RIGHT_ARM_INDEX:
1460 case LEFT_ARM_INDEX: return GetArmMainColor();
1461 case GROIN_INDEX:
1462 case RIGHT_LEG_INDEX:
1463 case LEFT_LEG_INDEX: return GetLegMainColor();
1466 ABORT("Weird bodypart col B request for a humanoid!");
1467 return 0;
1470 col16 humanoid::GetBodyPartColorC(int I, truth) const
1472 switch(I)
1474 case TORSO_INDEX: return GetBeltColor();
1475 case HEAD_INDEX: return GetHairColor();
1476 case RIGHT_ARM_INDEX:
1477 case LEFT_ARM_INDEX: return GetGauntletColor();
1478 case GROIN_INDEX:
1479 case RIGHT_LEG_INDEX:
1480 case LEFT_LEG_INDEX: return GetBootColor();
1483 ABORT("Weird bodypart col C request for a humanoid!");
1484 return 0;
1487 col16 humanoid::GetBodyPartColorD(int I, truth) const
1489 switch(I)
1491 case TORSO_INDEX: return GetTorsoSpecialColor();
1492 case HEAD_INDEX: return GetEyeColor();
1493 case RIGHT_ARM_INDEX:
1494 case LEFT_ARM_INDEX: return GetArmSpecialColor();
1495 case GROIN_INDEX:
1496 case RIGHT_LEG_INDEX:
1497 case LEFT_LEG_INDEX: return GetLegSpecialColor();
1500 ABORT("Weird bodypart col D request for a humanoid!");
1501 return 0;
1504 int humanoid::GetBodyPartSparkleFlags(int I) const
1506 truth Sparkling = false;
1507 int SparkleFlags = GetNaturalSparkleFlags() & SKIN_COLOR ? SPARKLING_A : 0;
1509 switch(I)
1511 case TORSO_INDEX: Sparkling = GetNaturalSparkleFlags() & TORSO_MAIN_COLOR; break;
1512 case HEAD_INDEX: Sparkling = GetNaturalSparkleFlags() & CAP_COLOR; break;
1513 case RIGHT_ARM_INDEX:
1514 case LEFT_ARM_INDEX: Sparkling = GetNaturalSparkleFlags() & ARM_MAIN_COLOR; break;
1515 case GROIN_INDEX:
1516 case RIGHT_LEG_INDEX:
1517 case LEFT_LEG_INDEX: Sparkling = GetNaturalSparkleFlags() & LEG_MAIN_COLOR; break;
1520 SparkleFlags |= Sparkling ? SPARKLING_B : 0;
1521 Sparkling = false;
1523 switch(I)
1525 case TORSO_INDEX: Sparkling = GetNaturalSparkleFlags() & BELT_COLOR; break;
1526 case HEAD_INDEX: Sparkling = GetNaturalSparkleFlags() & HAIR_COLOR; break;
1527 case RIGHT_ARM_INDEX:
1528 case LEFT_ARM_INDEX: Sparkling = GetNaturalSparkleFlags() & GAUNTLET_COLOR; break;
1529 case GROIN_INDEX:
1530 case RIGHT_LEG_INDEX:
1531 case LEFT_LEG_INDEX: Sparkling = GetNaturalSparkleFlags() & BOOT_COLOR; break;
1534 SparkleFlags |= Sparkling ? SPARKLING_C : 0;
1535 Sparkling = false;
1537 switch(I)
1539 case TORSO_INDEX: Sparkling = GetNaturalSparkleFlags() & TORSO_SPECIAL_COLOR; break;
1540 case HEAD_INDEX: Sparkling = GetNaturalSparkleFlags() & EYE_COLOR; break;
1541 case RIGHT_ARM_INDEX:
1542 case LEFT_ARM_INDEX: Sparkling = GetNaturalSparkleFlags() & ARM_SPECIAL_COLOR; break;
1543 case GROIN_INDEX:
1544 case RIGHT_LEG_INDEX:
1545 case LEFT_LEG_INDEX: Sparkling = GetNaturalSparkleFlags() & LEG_SPECIAL_COLOR; break;
1548 SparkleFlags |= Sparkling ? SPARKLING_D : 0;
1549 return SparkleFlags;
1552 playerkind::playerkind() : SoulID(0), IsBonePlayer(false), IsClone(false)
1556 shopkeeper::shopkeeper()
1558 if(!game::IsLoading())
1559 Money = GetMoney() + RAND() % 2001;
1562 void humanoid::Bite(character* Enemy, v2 HitPos, int Direction, truth ForceHit)
1564 /* This function ought not to be called without a head */
1566 EditNP(-50);
1567 EditAP(-GetHead()->GetBiteAPCost());
1568 EditExperience(AGILITY, 150, 1 << 9);
1569 EditStamina(-1000, false);
1570 Enemy->TakeHit(this, 0, GetHead(), HitPos, GetHead()->GetBiteDamage(), GetHead()->GetBiteToHitValue(), RAND() % 26 - RAND() % 26, BITE_ATTACK, Direction, !(RAND() % GetCriticalModifier()), ForceHit);
1573 void humanoid::Kick(lsquare* Square, int Direction, truth ForceHit)
1575 leg* KickLeg = RAND_2 ? GetRightLeg() : GetLeftLeg();
1576 EditNP(-50);
1577 EditAP(-KickLeg->GetKickAPCost());
1578 EditStamina(-10000 / GetAttribute(LEG_STRENGTH), false);
1580 if(Square->BeKicked(this, 0, KickLeg, KickLeg->GetKickDamage(), KickLeg->GetKickToHitValue(), RAND() % 26 - RAND() % 26, Direction, !(RAND() % GetCriticalModifier()), ForceHit))
1582 KickLeg->EditExperience(LEG_STRENGTH, 75, 1 << 9);
1583 KickLeg->EditExperience(AGILITY, 75, 1 << 9);
1587 /* Returns the average number of APs required to kill Enemy */
1589 double humanoid::GetTimeToKill(ccharacter* Enemy, truth UseMaxHP) const
1591 double Effectivity = 0;
1592 int AttackStyles = 0;
1594 if(IsUsingArms())
1596 arm* RightArm = GetRightArm();
1598 if(RightArm)
1600 double Damage = RightArm->GetDamage();
1602 if(Damage)
1603 Effectivity += 1 / (Enemy->GetTimeToDie(this, int(Damage) + 1, RightArm->GetToHitValue(), AttackIsBlockable(GetRightWielded() ? WEAPON_ATTACK : UNARMED_ATTACK), UseMaxHP) * RightArm->GetAPCost());
1606 arm* LeftArm = GetLeftArm();
1608 if(LeftArm)
1610 double Damage = LeftArm->GetDamage();
1612 if(Damage)
1613 Effectivity += 1 / (Enemy->GetTimeToDie(this, int(Damage) + 1, LeftArm->GetToHitValue(), AttackIsBlockable(GetLeftWielded() ? WEAPON_ATTACK : UNARMED_ATTACK), UseMaxHP) * LeftArm->GetAPCost());
1616 ++AttackStyles;
1619 if(IsUsingLegs())
1621 leg* RightLeg = GetRightLeg();
1622 leg* LeftLeg = GetLeftLeg();
1623 double TimeToDie = Enemy->GetTimeToDie(this, int(RightLeg->GetKickDamage()) + 1, RightLeg->GetKickToHitValue(), AttackIsBlockable(KICK_ATTACK), UseMaxHP) * RightLeg->GetKickAPCost()
1624 + Enemy->GetTimeToDie(this, int(LeftLeg->GetKickDamage()) + 1, LeftLeg->GetKickToHitValue(), AttackIsBlockable(KICK_ATTACK), UseMaxHP) * LeftLeg->GetKickAPCost();
1625 Effectivity += 2 / TimeToDie;
1626 ++AttackStyles;
1629 if(IsUsingHead())
1631 head* Head = GetHead();
1632 Effectivity += 1 / (Enemy->GetTimeToDie(this, int(Head->GetBiteDamage()) + 1, Head->GetBiteToHitValue(), AttackIsBlockable(BITE_ATTACK), UseMaxHP) * Head->GetBiteAPCost());
1633 ++AttackStyles;
1636 if(StateIsActivated(HASTE))
1637 Effectivity *= 2;
1639 if(StateIsActivated(SLOW))
1640 Effectivity /= 2;
1642 return AttackStyles ? AttackStyles / Effectivity : 10000000;
1645 int humanoid::GetAttribute(int Identifier, truth AllowBonus) const
1647 if(Identifier < BASE_ATTRIBUTES)
1648 return character::GetAttribute(Identifier, AllowBonus);
1649 else
1651 int Attrib = 0;
1653 if(Identifier == ARM_STRENGTH || Identifier == DEXTERITY)
1655 arm* RightArm = GetRightArm();
1657 if(RightArm)
1658 Attrib += RightArm->GetAttribute(Identifier, AllowBonus);
1660 arm* LeftArm = GetLeftArm();
1662 if(LeftArm)
1663 Attrib += LeftArm->GetAttribute(Identifier, AllowBonus);
1665 else if(Identifier == LEG_STRENGTH || Identifier == AGILITY)
1667 leg* RightLeg = GetRightLeg();
1669 if(RightLeg)
1670 Attrib += RightLeg->GetAttribute(Identifier, AllowBonus);
1672 leg* LeftLeg = GetLeftLeg();
1674 if(LeftLeg)
1675 Attrib += LeftLeg->GetAttribute(Identifier, AllowBonus);
1677 else
1679 ABORT("Illegal humanoid attribute %d request!", Identifier);
1680 return 0xEBBA;
1683 return Attrib >> 1;
1687 truth humanoid::EditAttribute(int Identifier, int Value)
1689 if(Identifier < BASE_ATTRIBUTES)
1690 return character::EditAttribute(Identifier, Value);
1691 else if(Identifier == ARM_STRENGTH || Identifier == DEXTERITY)
1693 truth Success = false;
1695 if(GetRightArm() && GetRightArm()->EditAttribute(Identifier, Value))
1696 Success = true;
1698 if(GetLeftArm() && GetLeftArm()->EditAttribute(Identifier, Value))
1699 Success = true;
1701 return Success;
1703 else if(Identifier == LEG_STRENGTH || Identifier == AGILITY)
1705 truth Success = false;
1707 if(GetRightLeg() && GetRightLeg()->EditAttribute(Identifier, Value))
1708 Success = true;
1710 if(GetLeftLeg() && GetLeftLeg()->EditAttribute(Identifier, Value))
1711 Success = true;
1713 return Success;
1715 else
1717 ABORT("Illegal humanoid attribute %d edit request!", Identifier);
1718 return false;
1722 void humanoid::EditExperience(int Identifier, double Value, double Speed)
1724 if(!AllowExperience())
1725 return;
1727 if(Identifier < BASE_ATTRIBUTES)
1728 character::EditExperience(Identifier, Value, Speed);
1729 else if(Identifier == ARM_STRENGTH || Identifier == DEXTERITY)
1731 if(GetRightArm())
1732 GetRightArm()->EditExperience(Identifier, Value, Speed);
1734 if(GetLeftArm())
1735 GetLeftArm()->EditExperience(Identifier, Value, Speed);
1737 else if(Identifier == LEG_STRENGTH || Identifier == AGILITY)
1739 if(GetRightLeg())
1740 GetRightLeg()->EditExperience(Identifier, Value, Speed);
1742 if(GetLeftLeg())
1743 GetLeftLeg()->EditExperience(Identifier, Value, Speed);
1745 else
1746 ABORT("Illegal humanoid attribute %d experience edit request!", Identifier);
1749 int humanoid::DrawStats(truth AnimationDraw) const
1751 DrawSilhouette(AnimationDraw);
1753 if(AnimationDraw)
1754 return 15;
1756 int PanelPosX = RES.X - 96, PanelPosY = 15;
1757 PrintAttribute("AStr", ARM_STRENGTH, PanelPosX, PanelPosY++);
1758 PrintAttribute("LStr", LEG_STRENGTH, PanelPosX, PanelPosY++);
1759 PrintAttribute("Dex", DEXTERITY, PanelPosX, PanelPosY++);
1760 PrintAttribute("Agi", AGILITY, PanelPosX, PanelPosY++);
1761 return PanelPosY;
1764 int humanoid::GetRandomStepperBodyPart() const
1766 int Possible = 0, PossibleArray[3];
1768 if(GetRightLeg())
1769 PossibleArray[Possible++] = RIGHT_LEG_INDEX;
1771 if(GetLeftLeg())
1772 PossibleArray[Possible++] = LEFT_LEG_INDEX;
1774 if(Possible)
1775 return PossibleArray[RAND_N(Possible)];
1777 if(GetRightArm())
1778 PossibleArray[Possible++] = RIGHT_ARM_INDEX;
1780 if(GetLeftArm())
1781 PossibleArray[Possible++] = LEFT_ARM_INDEX;
1783 if(Possible)
1784 return PossibleArray[RAND_N(Possible)];
1786 if(GetHead())
1787 PossibleArray[Possible++] = HEAD_INDEX;
1789 if(GetGroin())
1790 PossibleArray[Possible++] = GROIN_INDEX;
1792 PossibleArray[Possible++] = TORSO_INDEX;
1793 return PossibleArray[RAND_N(Possible)];
1796 int humanoid::CheckForBlock(character* Enemy, item* Weapon, double ToHitValue, int Damage, int Success, int Type)
1798 if(GetAction())
1799 return Damage;
1801 if(GetRightWielded())
1802 Damage = CheckForBlockWithArm(Enemy, Weapon, GetRightArm(), ToHitValue, Damage, Success, Type);
1804 if(Damage && GetLeftWielded() && (!Weapon || Weapon->Exists()))
1805 Damage = CheckForBlockWithArm(Enemy, Weapon, GetLeftArm(), ToHitValue, Damage, Success, Type);
1807 return Damage;
1810 truth humanoid::CanWield() const
1812 return CanUseEquipment(RIGHT_WIELDED_INDEX) || CanUseEquipment(LEFT_WIELDED_INDEX);
1815 /* return true if still in balance */
1817 truth humanoid::CheckBalance(double KickDamage)
1819 return !CanMove()
1820 || IsStuck()
1821 || !KickDamage
1822 || (GetUsableLegs() != 1
1823 && !IsFlying()
1824 && KickDamage * 5 < RAND() % GetSize());
1827 sLong humanoid::GetMoveAPRequirement(int Difficulty) const
1829 if(IsFlying())
1830 return (!StateIsActivated(PANIC) ? 10000000 : 8000000) * Difficulty / (APBonus(GetAttribute(AGILITY)) * GetMoveEase());
1832 switch(GetUsableLegs())
1834 case 0:
1835 return (!StateIsActivated(PANIC) ? 20000000 : 16000000) * Difficulty / (APBonus(GetAttribute(AGILITY)) * GetMoveEase());
1836 case 1:
1837 return (!StateIsActivated(PANIC) ? 13333333 : 10666667) * Difficulty / (APBonus(GetAttribute(AGILITY)) * GetMoveEase());
1838 case 2:
1839 return (!StateIsActivated(PANIC) ? 10000000 : 8000000) * Difficulty / (APBonus(GetAttribute(AGILITY)) * GetMoveEase());
1842 ABORT("A %d legged humanoid invaded the dungeon!", GetUsableLegs());
1843 return 0;
1846 void hunter::CreateBodyParts(int SpecialFlags)
1848 for(int c = 0; c < BodyParts; ++c)
1849 if(c != LEFT_ARM_INDEX)
1850 CreateBodyPart(c, SpecialFlags);
1851 else
1852 SetBodyPart(LEFT_ARM_INDEX, 0);
1855 truth humanoid::EquipmentEasilyRecognized(int I) const
1857 if(GetRelation(PLAYER) != HOSTILE)
1858 return true;
1860 switch(I)
1862 case AMULET_INDEX:
1863 case RIGHT_RING_INDEX:
1864 case LEFT_RING_INDEX:
1865 case BELT_INDEX:
1866 return false;
1869 return true;
1872 void humanoid::SignalEquipmentAdd(int EquipmentIndex)
1874 character::SignalEquipmentAdd(EquipmentIndex);
1876 if(EquipmentIndex == RIGHT_WIELDED_INDEX)
1877 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill, GetRightWielded());
1878 else if(EquipmentIndex == LEFT_WIELDED_INDEX)
1879 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill, GetLeftWielded());
1881 if(!IsInitializing())
1882 CalculateBattleInfo();
1885 void humanoid::SignalEquipmentRemoval(int EquipmentIndex, citem* Item)
1887 character::SignalEquipmentRemoval(EquipmentIndex, Item);
1889 if(EquipmentIndex == RIGHT_WIELDED_INDEX)
1890 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill, 0);
1891 else if(EquipmentIndex == LEFT_WIELDED_INDEX)
1892 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill, 0);
1894 if(!IsInitializing())
1895 CalculateBattleInfo();
1898 void humanoid::SWeaponSkillTick()
1900 for(std::list<sweaponskill*>::iterator i = SWeaponSkill.begin(); i != SWeaponSkill.end();)
1902 if((*i)->Tick() && IsPlayer())
1904 item* Item = SearchForItem(*i);
1906 if(Item)
1907 (*i)->AddLevelDownMessage(Item->CHAR_NAME(UNARTICLED));
1910 if(!(*i)->GetHits() && *i != GetCurrentRightSWeaponSkill() && *i != GetCurrentLeftSWeaponSkill())
1912 std::list<sweaponskill*>::iterator Dirt = i++;
1913 SWeaponSkill.erase(Dirt);
1915 else
1916 ++i;
1920 void angel::GetAICommand()
1922 if((LastHealed || game::GetTick() - LastHealed > 10000) && AttachBodyPartsOfFriendsNear())
1923 return;
1925 humanoid::GetAICommand();
1928 /* Returns true if the angel finds somebody near to heal else false */
1930 truth angel::AttachBodyPartsOfFriendsNear()
1932 character* HurtOne = 0;
1933 bodypart* SeveredOne = 0;
1935 for(int d = 0; d < GetNeighbourSquares(); ++d)
1937 square* Square = GetNeighbourSquare(d);
1939 if(Square)
1941 character* Char = Square->GetCharacter();
1943 if(Char && (!HurtOne || Char->IsPlayer()) && GetRelation(Char) == FRIEND && !Char->HasAllBodyParts())
1945 bodypart* BodyPart = Char->FindRandomOwnBodyPart(false);
1947 if(BodyPart)
1949 HurtOne = Char;
1950 SeveredOne = BodyPart;
1956 if(HurtOne)
1958 if(HurtOne->IsPlayer())
1959 ADD_MESSAGE("%s puts your %s back to its place.", CHAR_DESCRIPTION(DEFINITE), SeveredOne->GetBodyPartName().CStr());
1960 else if(CanBeSeenByPlayer())
1961 ADD_MESSAGE("%s helps %s by putting %s %s in its old place.", CHAR_DESCRIPTION(DEFINITE), HurtOne->CHAR_DESCRIPTION(DEFINITE), HurtOne->GetPossessivePronoun().CStr(), SeveredOne->GetBodyPartName().CStr());
1963 SeveredOne->SetHP(1);
1964 SeveredOne->RemoveFromSlot();
1965 HurtOne->AttachBodyPart(SeveredOne);
1966 LastHealed = game::GetTick();
1967 DexterityAction(10);
1968 return true;
1970 else
1971 return false;
1974 void humanoid::DrawBodyParts(blitdata& BlitData) const
1976 bitmap* TileBuffer = igraph::GetTileBuffer();
1977 bitmap* RealBitmap = BlitData.Bitmap;
1978 blitdata B = { TileBuffer,
1979 { BlitData.Dest.X, BlitData.Dest.Y },
1980 { 0, 0 },
1981 { TILE_SIZE, TILE_SIZE },
1982 { 0 },
1983 TRANSPARENT_COLOR,
1984 BlitData.CustomData };
1986 RealBitmap->NormalBlit(B);
1987 TileBuffer->FillPriority(0);
1988 B.Src.X = B.Src.Y = 0;
1989 B.Luminance = BlitData.Luminance;
1991 for(int c = 0; c < BodyParts; ++c)
1993 bodypart* BodyPart = GetBodyPart(DrawOrder[c]);
1995 if(BodyPart)
1997 B.Dest = GetDrawDisplacement(c);
1998 BodyPart->Draw(B);
2002 B.Dest.X = B.Dest.Y = 0;
2003 arm* LeftArm = GetLeftArm();
2005 if(LeftArm)
2006 LeftArm->DrawWielded(B);
2008 arm* RightArm = GetRightArm();
2010 if(RightArm)
2011 RightArm->DrawWielded(B);
2013 TileBuffer->FastBlit(RealBitmap, BlitData.Dest);
2016 v2 kamikazedwarf::GetDrawDisplacement(int I) const
2018 static v2 DrawDisplacement[] = { v2(0, 0), v2(0, 1), v2(0, -1), v2(0, -1), v2(0, -1), v2(0, 0), v2(0, 0) };
2019 return DrawDisplacement[I];
2022 col16 angel::GetTorsoMainColor() const
2024 return GetMasterGod()->GetColor();
2027 col16 angel::GetArmMainColor() const
2029 return GetMasterGod()->GetColor();
2032 col16 kamikazedwarf::GetTorsoMainColor() const
2034 return GetMasterGod()->GetColor();
2037 col16 kamikazedwarf::GetGauntletColor() const
2039 return GetMasterGod()->GetColor();
2042 col16 kamikazedwarf::GetLegMainColor() const
2044 return GetMasterGod()->GetColor();
2047 col16 housewife::GetHairColor() const
2049 static col16 HouseWifeHairColor[] = { MakeRGB16(48, 40, 8), MakeRGB16(60, 48, 24), MakeRGB16(200, 0, 0) };
2050 return HouseWifeHairColor[RAND() % 3];
2053 int angel::GetAttribute(int Identifier, truth AllowBonus) const // temporary until wings are bodyparts
2055 if(Identifier == LEG_STRENGTH)
2056 return GetDefaultLegStrength();
2057 else if(Identifier == AGILITY)
2058 return GetDefaultAgility();
2059 else
2060 return humanoid::GetAttribute(Identifier, AllowBonus);
2063 int genie::GetAttribute(int Identifier, truth AllowBonus) const // temporary until someone invents a better way of doing this
2065 if(Identifier == LEG_STRENGTH)
2066 return GetDefaultLegStrength();
2067 else if(Identifier == AGILITY)
2068 return GetDefaultAgility();
2069 else
2070 return humanoid::GetAttribute(Identifier, AllowBonus);
2073 truth humanoid::CanUseStethoscope(truth PrintReason) const
2075 if(!GetUsableArms())
2077 if(PrintReason)
2078 ADD_MESSAGE("You need a usable arm to use a stethoscope.");
2080 return false;
2083 if(!GetHead())
2085 if(PrintReason)
2086 ADD_MESSAGE("You need a head to use stethoscope.");
2088 return false;
2091 return true;
2094 truth humanoid::IsUsingArms() const
2096 return GetAttackStyle() & USE_ARMS && CanAttackWithAnArm();
2099 truth humanoid::IsUsingLegs() const
2101 return (GetAttackStyle() & USE_LEGS
2102 || (GetAttackStyle() & USE_ARMS && !CanAttackWithAnArm()))
2103 && HasTwoUsableLegs();
2106 truth humanoid::IsUsingHead() const
2108 return (GetAttackStyle() & USE_HEAD
2109 || ((GetAttackStyle() & USE_LEGS
2110 || (GetAttackStyle() & USE_ARMS && !CanAttackWithAnArm()))
2111 && !HasTwoUsableLegs()))
2112 && GetHead();
2115 void humanoid::CalculateBattleInfo()
2117 CalculateDodgeValue();
2118 doforbodyparts()(this, &bodypart::CalculateAttackInfo);
2121 item* skeleton::SevereBodyPart(int BodyPartIndex, truth ForceDisappearance, stack* EquipmentDropStack)
2123 if(BodyPartIndex == RIGHT_ARM_INDEX)
2124 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill, 0);
2125 else if(BodyPartIndex == LEFT_ARM_INDEX)
2126 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill, 0);
2128 item* BodyPart = GetBodyPart(BodyPartIndex);
2129 item* Bone = 0;
2131 if(!ForceDisappearance)
2133 if(BodyPartIndex == HEAD_INDEX)
2134 Bone = skull::Spawn(0, NO_MATERIALS);
2135 else
2136 Bone = bone::Spawn(0, NO_MATERIALS);
2138 Bone->InitMaterials(BodyPart->GetMainMaterial());
2139 BodyPart->DropEquipment(EquipmentDropStack);
2140 BodyPart->RemoveFromSlot();
2141 BodyPart->SetMainMaterial(0, NO_PIC_UPDATE|NO_SIGNALS);
2143 else
2145 BodyPart->DropEquipment(EquipmentDropStack);
2146 BodyPart->RemoveFromSlot();
2149 BodyPart->SendToHell();
2150 CalculateAttributeBonuses();
2151 CalculateBattleInfo();
2152 SignalPossibleTransparencyChange();
2153 RemoveTraps(BodyPartIndex);
2154 return Bone;
2157 void zombie::CreateBodyParts(int SpecialFlags)
2159 bool Anyway = false;
2160 if(GetConfig() == ZOMBIE_OF_KHAZ_ZADM)
2162 Anyway = true;
2163 } // Khaz-Zadm needs his hands...
2165 for(int c = 0; c < BodyParts; ++c)
2166 if(Anyway || BodyPartIsVital(c) || RAND_N(3) || (c == HEAD_INDEX && !RAND_N(3)))
2168 bodypart* BodyPart = CreateBodyPart(c, SpecialFlags|NO_PIC_UPDATE);
2169 BodyPart->GetMainMaterial()->SetSpoilCounter(2000 + RAND_N(1000));
2173 void humanoid::AddSpecialEquipmentInfo(festring& String, int I) const
2175 if((I == RIGHT_WIELDED_INDEX && GetRightArm()->TwoHandWieldIsActive()) || (I == LEFT_WIELDED_INDEX && GetLeftArm()->TwoHandWieldIsActive()))
2176 String << " (in both hands)";
2179 /* Yes, this is evil. */
2181 #define INSTANTIATE(name) if(DataBase->name.IsValid() && (Item = DataBase->name.Instantiate(SpecialFlags))) Set##name(Item);
2183 void humanoid::CreateInitialEquipment(int SpecialFlags)
2185 character::CreateInitialEquipment(SpecialFlags);
2186 item* Item;
2188 INSTANTIATE(Helmet);
2189 INSTANTIATE(Amulet);
2190 INSTANTIATE(Cloak);
2191 INSTANTIATE(BodyArmor);
2192 INSTANTIATE(Belt);
2193 INSTANTIATE(RightWielded);
2194 INSTANTIATE(LeftWielded);
2195 INSTANTIATE(RightRing);
2196 INSTANTIATE(LeftRing);
2197 INSTANTIATE(RightGauntlet);
2198 INSTANTIATE(LeftGauntlet);
2199 INSTANTIATE(RightBoot);
2200 INSTANTIATE(LeftBoot);
2202 if(CurrentRightSWeaponSkill)
2203 CurrentRightSWeaponSkill->AddHit(GetRightSWeaponSkillHits() * 100);
2205 if(CurrentLeftSWeaponSkill)
2206 CurrentLeftSWeaponSkill->AddHit(GetLeftSWeaponSkillHits() * 100);
2209 festring humanoid::GetBodyPartName(int I, truth Articled) const
2211 festring Article;
2213 if(Articled)
2214 Article << 'a';
2216 switch(I)
2218 case HEAD_INDEX: return Article + "head";
2219 case TORSO_INDEX: return Article + "torso";
2220 case RIGHT_ARM_INDEX: return Article + "right arm";
2221 case LEFT_ARM_INDEX: return Article + "left arm";
2222 case GROIN_INDEX: return Article + "groin";
2223 case RIGHT_LEG_INDEX: return Article + "right leg";
2224 case LEFT_LEG_INDEX: return Article + "left leg";
2227 ABORT("Illegal humanoid bodypart name request!");
2228 return "";
2231 void humanoid::CreateBlockPossibilityVector(blockvector& Vector, double ToHitValue) const
2233 double RightBlockChance = 0;
2234 int RightBlockCapability = 0;
2235 double LeftBlockChance = 0;
2236 int LeftBlockCapability = 0;
2237 arm* RightArm = GetRightArm();
2238 arm* LeftArm = GetLeftArm();
2240 if(RightArm)
2242 RightBlockChance = RightArm->GetBlockChance(ToHitValue);
2243 RightBlockCapability = RightArm->GetBlockCapability();
2246 if(LeftArm)
2248 LeftBlockChance = LeftArm->GetBlockChance(ToHitValue);
2249 LeftBlockCapability = LeftArm->GetBlockCapability();
2252 /* Double block */
2254 if(RightBlockCapability + LeftBlockCapability)
2255 Vector.push_back(std::make_pair(RightBlockChance * LeftBlockChance, RightBlockCapability + LeftBlockCapability));
2257 /* Right block */
2259 if(RightBlockCapability)
2260 Vector.push_back(std::make_pair(RightBlockChance * (1 - LeftBlockChance), RightBlockCapability));
2262 /* Left block */
2264 if(LeftBlockCapability)
2265 Vector.push_back(std::make_pair(LeftBlockChance * (1 - RightBlockChance), LeftBlockCapability));
2268 item* humanoid::SevereBodyPart(int BodyPartIndex, truth ForceDisappearance, stack* EquipmentDropStack)
2270 if(BodyPartIndex == RIGHT_ARM_INDEX)
2271 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill, 0);
2272 else if(BodyPartIndex == LEFT_ARM_INDEX)
2273 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill, 0);
2275 return character::SevereBodyPart(BodyPartIndex, ForceDisappearance, EquipmentDropStack);
2278 humanoid::humanoid(const humanoid& Humanoid) : mybase(Humanoid), CurrentRightSWeaponSkill(0), CurrentLeftSWeaponSkill(0)
2280 SWeaponSkill.resize(Humanoid.SWeaponSkill.size());
2281 std::list<sweaponskill*>::iterator i1 = SWeaponSkill.begin();
2282 std::list<sweaponskill*>::const_iterator i2 = Humanoid.SWeaponSkill.begin();
2284 for(; i1 != SWeaponSkill.end(); ++i1, ++i2)
2285 *i1 = new sweaponskill(**i2);
2288 cfestring& humanoid::GetDeathMessage() const
2290 static festring HeadlessDeathMsg = CONST_S("@Dd dies without a sound.");
2291 return GetHead() || character::GetDeathMessage() != "@Dd dies screaming." ? character::GetDeathMessage() : HeadlessDeathMsg;
2294 int humanoid::GetSWeaponSkillLevel(citem* Item) const
2296 std::list<sweaponskill*>::const_iterator i;
2298 for(i = SWeaponSkill.begin(); i != SWeaponSkill.end(); ++i)
2299 if((*i)->IsSkillOf(Item))
2300 return (*i)->GetLevel();
2302 for(idholder* I = Item->GetCloneMotherID(); I; I = I->Next)
2303 for(i = SWeaponSkill.begin(); i != SWeaponSkill.end(); ++i)
2304 if((*i)->IsSkillOfCloneMother(Item, I->ID))
2305 return (*i)->GetLevel();
2307 return 0;
2310 truth humanoid::UseMaterialAttributes() const
2312 return combinebodypartpredicates()(this, &bodypart::UseMaterialAttributes, 0);
2315 col24 angel::GetBaseEmitation() const
2317 switch(GetMasterGod()->GetBasicAlignment())
2319 case GOOD: return MakeRGB24(150, 150, 150);
2320 case NEUTRAL: return MakeRGB24(120, 120, 150);
2321 case EVIL: return MakeRGB24(150, 110, 110);
2324 return 0;
2327 void bananagrower::BeTalkedTo()
2329 static sLong Said;
2331 if(GetRelation(PLAYER) == HOSTILE)
2332 ProcessAndAddMessage(GetHostileReplies()[RandomizeReply(Said, GetHostileReplies().Size)]);
2333 else if(!game::TweraifIsFree())
2335 if(GetRelation(PLAYER) != HOSTILE
2336 && Profession.Find("president", 0) != festring::NPos && !(RAND() % 7))
2337 ADD_MESSAGE("\"I'm glad Petrus spared my life even though I was the president.\"");
2339 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said, 6)]);
2341 else
2342 ProcessAndAddMessage(GetFriendlyReplies()[6 + RandomizeReply(Said, 3)]);
2345 void bananagrower::RandomizeProfession()
2347 switch(RAND_N(12))
2349 case 0:
2350 Profession = CONST_S("the president of Tweraif");
2351 break;
2352 case 1:
2353 Profession = CONST_S("a diplomat");
2354 break;
2355 case 2:
2356 Profession = CONST_S("a teacher");
2357 break;
2358 case 3:
2359 Profession = CONST_S("a philosopher");
2360 break;
2361 case 4:
2362 Profession = CONST_S("a journalist");
2363 break;
2364 case 5:
2365 Profession = CONST_S("an alchemist");
2366 break;
2367 case 6:
2368 Profession = CONST_S("a renown mathematician");
2369 break;
2370 case 7:
2371 Profession = CONST_S("a priest of Silva");
2372 break;
2373 case 8:
2374 case 9:
2375 case 10:
2376 case 11:
2377 Profession = CONST_S("a professor of ");
2378 AddRandomScienceName(Profession);
2379 break;
2383 void bananagrower::PostConstruct()
2385 Stamina = MaxStamina / 5;
2386 RandomizeProfession();
2387 HasDroppedBananas = FeedingSumo = false;
2390 void bananagrower::Save(outputfile& SaveFile) const
2392 humanoid::Save(SaveFile);
2393 SaveFile << Profession << HasDroppedBananas << FeedingSumo;
2396 void bananagrower::Load(inputfile& SaveFile)
2398 humanoid::Load(SaveFile);
2399 SaveFile >> Profession >> HasDroppedBananas >> FeedingSumo;
2402 void smith::BeTalkedTo()
2404 if(GetRelation(PLAYER) == HOSTILE)
2406 ADD_MESSAGE("\"You talkin' to me? You talkin' to me? You talkin' to me? Then who the hell else are you talkin' to? You talkin' to me? Well I'm the only one here. Who do you think you're talking to? Oh yeah? Huh? Ok.\"");
2407 return;
2410 if(!GetMainWielded() || !GetMainWielded()->CanBeUsedBySmith())
2412 ADD_MESSAGE("\"Sorry, I need an intact hammer to practise the art of smithing.\"");
2413 return;
2416 if(PLAYER->PossessesItem(&item::IsFixableBySmith))
2418 item* Item = PLAYER->SelectFromPossessions(CONST_S("\"What do you want me to fix?\""), &item::IsFixableBySmith);
2420 if(!Item)
2421 return;
2423 if(!(Item->GetMainMaterial()->GetCategoryFlags() & IS_METAL))
2425 ADD_MESSAGE("\"I only fix items made of metal.\"");
2426 return;
2429 /** update messages */
2431 sLong FixPrice = Item->GetFixPrice();
2433 if(PLAYER->GetMoney() < FixPrice)
2435 ADD_MESSAGE("\"Getting that fixed costs you %d gold pieces. Get the money and we'll talk.\"", FixPrice);
2436 return;
2439 ADD_MESSAGE("\"I can fix your %s, but it'll cost you %d gold pieces.\"", Item->CHAR_NAME(UNARTICLED), FixPrice);
2441 if(game::TruthQuestion(CONST_S("Do you accept this deal? [y/N]")))
2443 Item->RemoveRust();
2444 Item->Fix();
2445 PLAYER->EditMoney(-FixPrice);
2446 ADD_MESSAGE("%s fixes %s in no time.", CHAR_NAME(DEFINITE), Item->CHAR_NAME(DEFINITE));
2449 else
2450 ADD_MESSAGE("\"Come back when you have some weapons or armor I can fix.\"");
2453 void humanoid::CalculateDodgeValue()
2455 DodgeValue = 0.05 * GetMoveEase() * GetAttribute(AGILITY) / sqrt(GetSize());
2457 if(IsFlying())
2458 DodgeValue *= 2;
2459 else
2461 if(!HasAUsableLeg())
2462 DodgeValue *= 0.50;
2463 if(!HasTwoUsableLegs())
2464 DodgeValue *= 0.75;
2467 if(DodgeValue < 1)
2468 DodgeValue = 1;
2471 truth humanoid::CheckZap()
2473 if(!GetUsableArms())
2475 ADD_MESSAGE("You need at least one usable arm to zap.");
2476 return false;
2478 else
2479 return character::CheckZap();
2482 void bananagrower::GetAICommand()
2484 if(game::TweraifIsFree())
2486 humanoid::GetAICommand();
2487 return;
2490 if(CheckForEnemies(false, false, true, true))
2491 return;
2493 if(!IsEnabled())
2494 return;
2496 cv2 BananaTarget = FeedingSumo ? SUMO_ROOM_POS + v2(1, 2) : v2(45, 45);
2498 if(GetPos() == BananaTarget)
2500 itemvector ItemVector;
2501 GetStack()->FillItemVector(ItemVector);
2502 int BananasDropped = 0;
2503 uInt c;
2505 for(c = 0; c < ItemVector.size(); ++c)
2506 if(ItemVector[c]->IsBanana())
2508 ItemVector[c]->MoveTo(GetStackUnder());
2509 ++BananasDropped;
2512 if(BananasDropped)
2514 if(CanBeSeenByPlayer())
2515 ADD_MESSAGE("%s drops %s.", CHAR_NAME(DEFINITE), BananasDropped == 1 ? "a banana" : "some bananas");
2517 return;
2520 ItemVector.clear();
2521 GetStackUnder()->FillItemVector(ItemVector);
2522 int PeelsPickedUp = 0;
2524 for(c = 0; c < ItemVector.size(); ++c)
2525 if(ItemVector[c]->IsBananaPeel())
2527 ItemVector[c]->MoveTo(GetStack());
2528 ++PeelsPickedUp;
2531 if(PeelsPickedUp)
2533 if(CanBeSeenByPlayer())
2534 ADD_MESSAGE("%s picks up %s.", CHAR_NAME(DEFINITE), PeelsPickedUp == 1 ? "a banana peel" : "some banana peels");
2536 return;
2539 HasDroppedBananas = true;
2542 if(!HasDroppedBananas)
2544 SetGoingTo(BananaTarget);
2546 if(MoveTowardsTarget(true))
2547 return;
2549 else if(GetPos().X == 54)
2551 if(CanBeSeenByPlayer())
2552 ADD_MESSAGE("%s leaves the town to gather more bananas.", CHAR_NAME(DEFINITE));
2554 GetStack()->Clean();
2555 character* Sumo = game::GetSumo();
2556 FeedingSumo = Sumo && Sumo->GetNP() < (SATIATED_LEVEL + BLOATED_LEVEL) >> 1 && !(RAND() % 15);
2557 int Bananas = FeedingSumo ? 3 : 10;
2559 for(int c = 0; c < Bananas; ++c)
2560 GetStack()->AddItem(banana::Spawn());
2562 v2 Where = GetLevel()->GetNearestFreeSquare(this, v2(0, 45));
2564 if(Where == ERROR_V2)
2565 Where = GetLevel()->GetRandomSquare(this, NOT_IN_ROOM); // this is odd but at least it doesn't crash
2567 Move(Where, true);
2568 RandomizeProfession();
2569 RestoreBodyParts();
2570 RestoreHP();
2571 Stamina = MaxStamina / 5;
2572 ResetStates();
2573 TemporaryState = 0;
2575 if(CanBeSeenByPlayer())
2576 ADD_MESSAGE("%s enters the town.", CHAR_NAME(INDEFINITE));
2578 HasDroppedBananas = false;
2580 else
2582 SetGoingTo(v2(54, 45));
2584 if(MoveTowardsTarget(true))
2585 return;
2588 EditAP(-1000);
2591 truth humanoid::CheckTalk()
2593 if(!character::CheckTalk())
2594 return false;
2596 if(!GetHead())
2598 ADD_MESSAGE("You need a head to talk.");
2599 return false;
2602 return true;
2605 truth angel::CanCreateBodyPart(int I) const
2607 return I == TORSO_INDEX || I == HEAD_INDEX || I == RIGHT_ARM_INDEX || I == LEFT_ARM_INDEX;
2610 truth genie::CanCreateBodyPart(int I) const
2612 return I == TORSO_INDEX || I == HEAD_INDEX || I == RIGHT_ARM_INDEX || I == LEFT_ARM_INDEX;
2615 truth bananagrower::HandleCharacterBlockingTheWay(character* Char, v2 Pos, int Dir)
2617 return Char->GetPos() == v2(45, 45) && (Displace(Char, true) || Hit(Char, Pos, Dir));
2620 festring& bananagrower::ProcessMessage(festring& Msg) const
2622 character::ProcessMessage(Msg);
2623 SEARCH_N_REPLACE(Msg, "@pd", GetProfession());
2624 SEARCH_N_REPLACE(Msg, "@Pd", GetProfession().CapitalizeCopy());
2625 return Msg;
2628 void elder::CreateBodyParts(int SpecialFlags)
2630 for(int c = 0; c < BodyParts; ++c)
2631 if(c != LEFT_LEG_INDEX)
2632 CreateBodyPart(c, SpecialFlags);
2633 else
2634 SetBodyPart(LEFT_LEG_INDEX, 0);
2637 /*void encourager::GetAICommand()
2639 if(CheckForEnemies(true, true, true))
2640 return;
2642 if(CheckForUsefulItemsOnGround())
2643 return;
2645 if(CheckForDoors())
2646 return;
2648 if(game::GetTick() - LastHit > 200)
2650 static int NotDiagonal[] = { 1, 3, 4, 6 };
2652 for(int d = 0; d < 4; ++d)
2654 square* Square = GetNeighbourSquare(NotDiagonal[d]);
2656 if(Square)
2658 character* Char = Square->GetCharacter();
2660 if(Char && Char->IsBananaGrower() && Hit(Char, Square->GetPos(), NotDiagonal[d], true))
2662 LastHit = game::GetTick();
2663 TerminateGoingTo();
2664 return;
2670 if(MoveTowardsHomePos())
2671 return;
2673 EditAP(-1000);
2676 /*void encourager::Save(outputfile& SaveFile) const
2678 humanoid::Save(SaveFile);
2679 SaveFile << LastHit;
2682 void encourager::Load(inputfile& SaveFile)
2684 humanoid::Load(SaveFile);
2685 SaveFile >> LastHit;
2688 sLong skeleton::GetBodyPartVolume(int I) const
2690 switch(I)
2692 case HEAD_INDEX: return 600;
2693 case TORSO_INDEX: return (GetTotalVolume() - 600) * 13 / 30;
2694 case RIGHT_ARM_INDEX:
2695 case LEFT_ARM_INDEX: return (GetTotalVolume() - 600) / 10;
2696 case GROIN_INDEX: return (GetTotalVolume() - 600) / 10;
2697 case RIGHT_LEG_INDEX:
2698 case LEFT_LEG_INDEX: return ((GetTotalVolume() - 600) << 1) / 15;
2701 ABORT("Illegal humanoid bodypart volume request!");
2702 return 0;
2705 truth humanoid::CheckIfEquipmentIsNotUsable(int I) const
2707 return (I == RIGHT_WIELDED_INDEX && GetRightArm()->CheckIfWeaponTooHeavy("this item"))
2708 || (I == LEFT_WIELDED_INDEX && GetLeftArm()->CheckIfWeaponTooHeavy("this item"))
2709 || (I == RIGHT_WIELDED_INDEX && GetLeftWielded() && GetLeftWielded()->IsTwoHanded() && GetLeftArm()->CheckIfWeaponTooHeavy(festring(GetPossessivePronoun() + " other wielded item").CStr()))
2710 || (I == LEFT_WIELDED_INDEX && GetRightWielded() && GetRightWielded()->IsTwoHanded() && GetRightArm()->CheckIfWeaponTooHeavy(festring(GetPossessivePronoun() + " other wielded item").CStr()));
2713 int mistress::TakeHit(character* Enemy, item* Weapon, bodypart* EnemyBodyPart, v2 HitPos, double Damage, double ToHitValue, int Success, int Type, int Direction, truth Critical, truth ForceHit)
2715 int Return = humanoid::TakeHit(Enemy, Weapon, EnemyBodyPart, HitPos, Damage, ToHitValue, Success, Type, Direction, Critical, ForceHit);
2717 if(Return == HAS_HIT && Critical)
2719 if(IsPlayer())
2720 ADD_MESSAGE("Aahhh. The pain feels unbelievably good.");
2721 else if(CanBeSeenByPlayer())
2722 ADD_MESSAGE("%s screams: \"Oh the delightful pain!\"", CHAR_NAME(DEFINITE));
2723 else
2724 ADD_MESSAGE("You hear someone screaming: \"Oh the delightful pain!\"");
2727 return Return;
2730 truth petrusswife::SpecialEnemySightedReaction(character* Char)
2732 item* Weapon = Char->GetMainWielded();
2734 if(Weapon && Weapon->IsWeapon(Char) && !(RAND() % 20))
2735 ADD_MESSAGE("%s screams: \"Oh my Frog, %s's got %s %s!\"", CHAR_DESCRIPTION(DEFINITE), Char->CHAR_PERSONAL_PRONOUN_THIRD_PERSON_VIEW, Weapon->GetArticle(), Weapon->GetNameSingular().CStr());
2737 return false;
2740 truth housewife::SpecialEnemySightedReaction(character* Char)
2742 item* Weapon = Char->GetMainWielded();
2744 if(Weapon && Weapon->IsWeapon(Char) && !(RAND() % 5))
2745 ADD_MESSAGE("%s screams: \"Oh my Frog, %s's got %s %s!\"", CHAR_DESCRIPTION(DEFINITE), Char->CHAR_PERSONAL_PRONOUN_THIRD_PERSON_VIEW, Weapon->GetArticle(), Weapon->GetNameSingular().CStr());
2747 return false;
2750 void guard::Save(outputfile& SaveFile) const
2752 humanoid::Save(SaveFile);
2753 SaveFile << WayPoints << NextWayPoint;
2756 void guard::Load(inputfile& SaveFile)
2758 humanoid::Load(SaveFile);
2759 SaveFile >> WayPoints >> NextWayPoint;
2762 void guard::GetAICommand()
2764 if(GetConfig() == MASTER && HP << 1 < MaxHP && (GetPos() - v2(30, 17)).GetLengthSquare() > 9)
2766 if(CanBeSeenByPlayer())
2767 ADD_MESSAGE("%s disappears.", CHAR_NAME(DEFINITE));
2769 GetLevel()->GetLSquare(30, 16)->KickAnyoneStandingHereAway();
2770 Move(v2(30, 16), true);
2771 EditAP(-1000);
2772 return;
2775 if(WayPoints.size() && !IsGoingSomeWhere())
2777 if(GetPos() == WayPoints[NextWayPoint]) {
2778 if(NextWayPoint < WayPoints.size() - 1) ++NextWayPoint; else NextWayPoint = 0;
2781 GoingTo = WayPoints[NextWayPoint];
2784 SeekLeader(GetLeader());
2786 if(CheckForEnemies(true, true, true))
2787 return;
2789 if(CheckForUsefulItemsOnGround())
2790 return;
2792 if(FollowLeader(GetLeader()))
2793 return;
2795 if(CheckForDoors())
2796 return;
2798 if(MoveTowardsHomePos())
2799 return;
2801 if(CheckSadism())
2802 return;
2804 if(CheckForBeverage())
2805 return;
2807 EditAP(-1000);
2810 truth mistress::ReceiveDamage(character* Damager, int Damage, int Type, int TargetFlags, int Direction, truth Divide, truth PenetrateArmor, truth Critical, truth ShowMsg)
2812 truth Success = humanoid::ReceiveDamage(Damager, Damage, Type, TargetFlags, Direction, Divide, PenetrateArmor, Critical, ShowMsg);
2814 if(Type & SOUND && Success && !(RAND() & 7))
2816 if(IsPlayer())
2817 ADD_MESSAGE("Aahhh. The pain feels unbelievably good.");
2818 else if(CanBeSeenByPlayer())
2819 ADD_MESSAGE("%s screams: \"Oh the delightful pain!\"", CHAR_NAME(DEFINITE));
2820 else
2821 ADD_MESSAGE("You hear someone screaming: \"Oh the delightful pain!\"");
2824 return Success;
2827 void humanoid::AddSpecialStethoscopeInfo(felist& Info) const
2829 Info.AddEntry(CONST_S("Arm strength: ") + GetAttribute(ARM_STRENGTH), LIGHT_GRAY);
2830 Info.AddEntry(CONST_S("Leg strength: ") + GetAttribute(LEG_STRENGTH), LIGHT_GRAY);
2831 Info.AddEntry(CONST_S("Dexterity: ") + GetAttribute(DEXTERITY), LIGHT_GRAY);
2832 Info.AddEntry(CONST_S("Agility: ") + GetAttribute(AGILITY), LIGHT_GRAY);
2835 item* humanoid::GetPairEquipment(int I) const
2837 switch(I)
2839 case RIGHT_WIELDED_INDEX: return GetLeftWielded();
2840 case LEFT_WIELDED_INDEX: return GetRightWielded();
2841 case RIGHT_GAUNTLET_INDEX: return GetLeftGauntlet();
2842 case LEFT_GAUNTLET_INDEX: return GetRightGauntlet();
2843 case RIGHT_BOOT_INDEX: return GetLeftBoot();
2844 case LEFT_BOOT_INDEX: return GetRightBoot();
2847 return 0;
2850 cfestring& humanoid::GetStandVerb() const
2852 if(ForceCustomStandVerb())
2853 return DataBase->StandVerb;
2855 static festring HasntFeet = CONST_S("crawling");
2856 static festring Hovering = CONST_S("hovering");
2857 static festring Swimming = CONST_S("swimming");
2859 if(StateIsActivated(LEVITATION))
2860 return Hovering;
2862 if(IsSwimming())
2863 return Swimming;
2865 return HasAUsableLeg() ? DataBase->StandVerb : HasntFeet;
2868 void darkmage::GetAICommand()
2870 SeekLeader(GetLeader());
2872 if(FollowLeader(GetLeader()))
2873 return;
2875 character* NearestEnemy = 0;
2876 sLong NearestEnemyDistance = 0x7FFFFFFF;
2877 character* RandomFriend = 0;
2878 charactervector Friend;
2879 v2 Pos = GetPos();
2881 for(int c = 0; c < game::GetTeams(); ++c)
2883 if(GetTeam()->GetRelation(game::GetTeam(c)) == HOSTILE)
2885 for(std::list<character*>::const_iterator i = game::GetTeam(c)->GetMember().begin(); i != game::GetTeam(c)->GetMember().end(); ++i)
2886 if((*i)->IsEnabled())
2888 sLong ThisDistance = Max<sLong>(abs((*i)->GetPos().X - Pos.X), abs((*i)->GetPos().Y - Pos.Y));
2890 if((ThisDistance < NearestEnemyDistance || (ThisDistance == NearestEnemyDistance && !(RAND() % 3))) && (*i)->CanBeSeenBy(this))
2892 NearestEnemy = *i;
2893 NearestEnemyDistance = ThisDistance;
2897 else if(GetTeam()->GetRelation(game::GetTeam(c)) == FRIEND)
2899 for(std::list<character*>::const_iterator i = game::GetTeam(c)->GetMember().begin(); i != game::GetTeam(c)->GetMember().end(); ++i)
2900 if((*i)->IsEnabled() && (*i)->CanBeSeenBy(this))
2901 Friend.push_back(*i);
2905 if(NearestEnemy && NearestEnemy->GetPos().IsAdjacent(Pos))
2907 if(NearestEnemy->IsSmall()
2908 && GetAttribute(WISDOM) < NearestEnemy->GetAttackWisdomLimit()
2909 && !(RAND() % 5)
2910 && Hit(NearestEnemy, NearestEnemy->GetPos(), game::GetDirectionForVector(NearestEnemy->GetPos() - GetPos())))
2911 return;
2912 else if((GetConfig() == ARCH_MAGE && RAND() & 1)
2913 || (GetConfig() == ELDER && !(RAND() & 3)))
2915 if(CanBeSeenByPlayer())
2916 ADD_MESSAGE("%s invokes a spell and disappears.", CHAR_NAME(DEFINITE));
2918 TeleportRandomly(true);
2919 EditAP(-GetSpellAPCost());
2920 return;
2924 if(NearestEnemy && ((GetConfig() != APPRENTICE && NearestEnemyDistance < 10) || StateIsActivated(PANIC)) && RAND() & 3)
2926 SetGoingTo((Pos << 1) - NearestEnemy->GetPos());
2928 if(MoveTowardsTarget(true))
2929 return;
2932 if(Friend.size() && !(RAND() & 3))
2934 RandomFriend = Friend[RAND() % Friend.size()];
2935 NearestEnemy = 0;
2938 beamdata Beam
2940 this,
2941 CONST_S("killed by the spells of ") + GetName(INDEFINITE),
2942 YOURSELF,
2946 if(NearestEnemy)
2948 lsquare* Square = NearestEnemy->GetLSquareUnder();
2949 EditAP(-GetSpellAPCost());
2951 if(CanBeSeenByPlayer())
2952 ADD_MESSAGE("%s invokes a spell!", CHAR_NAME(DEFINITE));
2954 switch(GetConfig())
2956 case APPRENTICE:
2957 Square->DrawLightning(v2(8, 8), WHITE, YOURSELF);
2958 Square->Lightning(Beam);
2959 break;
2960 case BATTLE_MAGE:
2961 if(RAND() % 20)
2963 Square->DrawLightning(v2(8, 8), WHITE, YOURSELF);
2964 Square->Lightning(Beam);
2966 else
2968 Square->DrawParticles(RED);
2969 Square->LowerEnchantment(Beam);
2972 break;
2973 case ELDER:
2974 switch(RAND() % 20)
2976 case 0:
2977 case 1:
2978 case 2: Square->DrawParticles(RED); Square->Strike(Beam); break;
2979 case 3: Square->DrawParticles(RED); Square->FireBall(Beam); break;
2980 case 4:
2981 case 5:
2982 case 6: Square->DrawParticles(RED); Square->Slow(Beam); break;
2983 case 7: Square->DrawParticles(RED); Square->Teleport(Beam); break;
2984 case 8:
2985 case 9:
2986 case 10: Square->DrawParticles(RED); Square->LowerEnchantment(Beam); break;
2987 default: Square->DrawLightning(v2(8, 8), WHITE, YOURSELF); Square->Lightning(Beam); break;
2990 break;
2991 case ARCH_MAGE:
2992 switch(RAND() % 20)
2994 case 0:
2995 case 1:
2996 case 2: Square->DrawParticles(RED); Square->FireBall(Beam); break;
2997 case 3:
2999 character* Char = NearestEnemy->DuplicateToNearestSquare(this, CHANGE_TEAM|MIRROR|(1000 << LE_BASE_SHIFT)|(1000 << LE_RAND_SHIFT));
3001 if(Char)
3003 if(Char->CanBeSeenByPlayer())
3004 ADD_MESSAGE("%s materializes!", Char->CHAR_NAME(INDEFINITE));
3006 break;
3009 case 4:
3010 case 5: Square->DrawParticles(RED); Square->Slow(Beam); break;
3011 case 6: Square->DrawParticles(RED); Square->Teleport(Beam); break;
3012 case 7:
3013 case 8:
3014 case 9: Square->DrawParticles(RED); Square->LowerEnchantment(Beam); break;
3015 case 10:
3017 golem* Golem = golem::Spawn(RAND() % 3 ? ARCANITE : OCTIRON);
3018 v2 Where = GetLevel()->GetNearestFreeSquare(Golem, Square->GetPos());
3020 if(Where == ERROR_V2)
3022 if(CanBeSeenByPlayer())
3023 ADD_MESSAGE("Nothing happens.");
3025 delete Golem;
3027 else
3029 Golem->SetGenerationDanger(GetGenerationDanger());
3030 Golem->SetTeam(GetTeam());
3031 Golem->PutTo(Where);
3033 if(Golem->CanBeSeenByPlayer())
3034 ADD_MESSAGE("Suddenly %s materializes!", Golem->CHAR_NAME(INDEFINITE));
3036 Golem->GetLSquareUnder()->DrawParticles(RED);
3039 break;
3041 default: Square->DrawParticles(RED); Square->Strike(Beam); break;
3044 break;
3047 if(CanBeSeenByPlayer())
3048 NearestEnemy->DeActivateVoluntaryAction(CONST_S("The spell of ") + GetName(DEFINITE) + CONST_S(" interrupts you."));
3049 else
3050 NearestEnemy->DeActivateVoluntaryAction(CONST_S("The spell interrupts you."));
3052 return;
3055 if(RandomFriend)
3057 lsquare* Square = RandomFriend->GetLSquareUnder();
3058 EditAP(-GetSpellAPCost());
3059 Square->DrawParticles(RED);
3061 switch(GetConfig())
3063 case APPRENTICE:
3064 case BATTLE_MAGE:
3065 Square->Haste(Beam);
3066 break;
3067 case ARCH_MAGE:
3068 if(!(RAND() & 31))
3070 RandomFriend->DuplicateToNearestSquare(this, CHANGE_TEAM);
3071 return;
3073 case ELDER:
3074 if(RAND() & 1)
3075 Square->Invisibility(Beam);
3076 else
3077 Square->Haste(Beam);
3079 break;
3082 return;
3085 if(CheckForDoors())
3086 return;
3088 if(CheckSadism())
3089 return;
3091 if(MoveRandomly())
3092 return;
3094 EditAP(-1000);
3097 void zombie::GetAICommand()
3099 if(!GetHead())
3101 for(stackiterator i = GetLSquareUnder()->GetStack()->GetBottom(); i.HasItem(); ++i)
3103 head* Head = i->Behead();
3105 if(Head)
3107 if(CanBeSeenByPlayer())
3108 ADD_MESSAGE("%s takes %s and attaches it to its torso.", CHAR_NAME(DEFINITE), Head->CHAR_NAME(INDEFINITE));
3110 Head->RemoveFromSlot();
3111 AttachBodyPart(Head);
3112 Head->SetHP(1);
3113 DexterityAction(10);
3114 return;
3119 humanoid::GetAICommand();
3122 head* humanoid::Behead()
3124 head* Head = GetHead();
3126 if(Head)
3127 SevereBodyPart(HEAD_INDEX);
3129 return Head;
3132 truth communist::BoundToUse(citem* Item, int I) const
3134 return Item && Item->IsGorovitsFamilyRelic() && Item->IsInCorrectSlot(I);
3137 festring werewolfwolf::GetKillName() const
3139 if(GetPolymorphBackup() && GetPolymorphBackup()->GetType() == werewolfhuman::ProtoType.GetIndex())
3140 return GetName(INDEFINITE);
3142 return humanoid::GetKillName();
3145 int humanoid::GetRandomApplyBodyPart() const
3147 if(RightArmIsUsable())
3149 if(LeftArmIsUsable())
3150 return RAND_2 ? RIGHT_ARM_INDEX : LEFT_ARM_INDEX;
3151 else
3152 return RIGHT_ARM_INDEX;
3154 else if(LeftArmIsUsable())
3155 return LEFT_ARM_INDEX;
3157 if(GetHead())
3158 return HEAD_INDEX;
3160 return TORSO_INDEX;
3163 void golem::BeTalkedTo()
3165 static sLong Said;
3167 if(GetRelation(PLAYER) == HOSTILE)
3168 Engrave(GetHostileReplies()[RandomizeReply(Said, GetHostileReplies().Size)]);
3169 else
3170 Engrave(GetFriendlyReplies()[RandomizeReply(Said, GetFriendlyReplies().Size)]);
3172 if(CanBeSeenByPlayer())
3173 ADD_MESSAGE("%s engraves something.", CHAR_NAME(DEFINITE));
3176 #ifdef WIZARD
3178 void humanoid::AddAttributeInfo(festring& Entry) const
3180 Entry.Resize(45);
3181 Entry << GetAttribute(ARM_STRENGTH);
3182 Entry.Resize(48);
3183 Entry << GetAttribute(LEG_STRENGTH);
3184 Entry.Resize(51);
3185 Entry << GetAttribute(DEXTERITY);
3186 Entry.Resize(54);
3187 Entry << GetAttribute(AGILITY);
3188 character::AddAttributeInfo(Entry);
3191 void humanoid::AddAttackInfo(felist& List) const
3193 if(GetAttackStyle() & USE_ARMS)
3195 if(GetRightArm())
3196 GetRightArm()->AddAttackInfo(List);
3198 if(GetLeftArm())
3199 GetLeftArm()->AddAttackInfo(List);
3202 festring Entry;
3204 if(IsUsingLegs())
3206 GetRightLeg()->AddAttackInfo(List);
3207 GetLeftLeg()->AddAttackInfo(List);
3210 if(IsUsingHead())
3212 Entry = CONST_S(" bite attack");
3213 Entry.Resize(50);
3214 Entry << GetHead()->GetBiteMinDamage() << '-' << GetHead()->GetBiteMaxDamage();
3215 Entry.Resize(60);
3216 Entry << int(GetHead()->GetBiteToHitValue());
3217 Entry.Resize(70);
3218 Entry << GetHead()->GetBiteAPCost();
3219 List.AddEntry(Entry, LIGHT_GRAY);
3223 void humanoid::AddDefenceInfo(felist& List) const
3225 character::AddDefenceInfo(List);
3227 if(GetRightArm())
3228 GetRightArm()->AddDefenceInfo(List);
3230 if(GetLeftArm())
3231 GetLeftArm()->AddDefenceInfo(List);
3234 void humanoid::DetachBodyPart()
3236 int ToBeDetached;
3238 switch(game::KeyQuestion(CONST_S("What limb? (l)eft arm, (r)ight arm, (L)eft leg, (R)ight leg, (h)ead?"), KEY_ESC, 5, 'l','r','L','R', 'h'))
3240 case 'l':
3241 ToBeDetached = LEFT_ARM_INDEX;
3242 break;
3243 case 'r':
3244 ToBeDetached = RIGHT_ARM_INDEX;
3245 break;
3246 case 'L':
3247 ToBeDetached = LEFT_LEG_INDEX;
3248 break;
3249 case 'R':
3250 ToBeDetached = RIGHT_LEG_INDEX;
3251 break;
3252 case 'h':
3253 ToBeDetached = HEAD_INDEX;
3254 break;
3255 default:
3256 return;
3259 if(GetBodyPart(ToBeDetached))
3261 item* ToDrop = SevereBodyPart(ToBeDetached);
3262 SendNewDrawRequest();
3264 if(ToDrop)
3266 GetStack()->AddItem(ToDrop);
3267 ToDrop->DropEquipment();
3270 ADD_MESSAGE("Bodypart detached!");
3272 else
3273 ADD_MESSAGE("That bodypart has already been detached.");
3275 CheckDeath(CONST_S("removed one of his vital bodyparts"), 0);
3278 #else
3280 void humanoid::AddAttributeInfo(festring&) const { }
3281 void humanoid::AddAttackInfo(felist&) const { }
3282 void humanoid::AddDefenceInfo(felist&) const { }
3283 void humanoid::DetachBodyPart() { }
3285 #endif
3287 truth ennerbeast::MustBeRemovedFromBone() const
3289 return !IsEnabled() || GetTeam()->GetID() != MONSTER_TEAM || GetDungeon()->GetIndex() != ELPURI_CAVE || GetLevel()->GetIndex() != ENNER_BEAST_LEVEL;
3292 truth communist::MustBeRemovedFromBone() const
3294 return !IsEnabled() || GetTeam()->GetID() != IVAN_TEAM || GetDungeon()->GetIndex() != ELPURI_CAVE|| GetLevel()->GetIndex() != IVAN_LEVEL;
3297 truth humanoid::PreProcessForBone()
3299 for(std::list<sweaponskill*>::iterator i = SWeaponSkill.begin(); i != SWeaponSkill.end(); ++i)
3300 (*i)->PreProcessForBone();
3302 return character::PreProcessForBone();
3305 void humanoid::FinalProcessForBone()
3307 character::FinalProcessForBone();
3309 for(std::list<sweaponskill*>::iterator i = SWeaponSkill.begin(); i != SWeaponSkill.end();)
3311 boneidmap::iterator BI = game::GetBoneItemIDMap().find(-(*i)->GetID());
3313 if(BI == game::GetBoneItemIDMap().end())
3315 std::list<sweaponskill*>::iterator Dirt = i++;
3316 SWeaponSkill.erase(Dirt);
3318 else
3320 (*i)->SetID(BI->second);
3321 ++i;
3326 void angel::FinalProcessForBone()
3328 humanoid::FinalProcessForBone();
3329 LastHealed = 0;
3332 /*void encourager::FinalProcessForBone()
3334 humanoid::FinalProcessForBone();
3335 LastHit = 0;
3338 void playerkind::Save(outputfile& SaveFile) const
3340 humanoid::Save(SaveFile);
3341 SaveFile << SoulID << HairColor << EyeColor << Talent << Weakness << IsBonePlayer << IsClone;
3344 void playerkind::Load(inputfile& SaveFile)
3346 humanoid::Load(SaveFile);
3347 SaveFile >> SoulID >> HairColor >> EyeColor >> Talent >> Weakness >> IsBonePlayer >> IsClone;
3350 void playerkind::SetSoulID(uLong What)
3352 SoulID = What;
3354 if(GetPolymorphBackup())
3355 GetPolymorphBackup()->SetSoulID(What);
3358 truth playerkind::SuckSoul(character* Soul)
3360 if(Soul->GetID() == SoulID)
3362 SoulID = 0;
3363 return true;
3366 return false;
3369 truth playerkind::TryToRiseFromTheDead()
3371 if(humanoid::TryToRiseFromTheDead())
3373 if(IsEnabled() && SoulID)
3375 ADD_MESSAGE("The soulless body of %s wobbles for a moment.", CHAR_NAME(DEFINITE));
3376 return false;
3379 return true;
3381 else
3382 return false;
3385 void playerkind::FinalProcessForBone()
3387 humanoid::FinalProcessForBone();
3388 IsBonePlayer = true;
3390 if(SoulID)
3392 boneidmap::iterator BI = game::GetBoneCharacterIDMap().find(SoulID);
3394 if(BI != game::GetBoneCharacterIDMap().end())
3395 SoulID = BI->second;
3396 else
3397 SoulID = 0;
3401 playerkind::playerkind(const playerkind& Char) : mybase(Char), SoulID(Char.SoulID), HairColor(Char.HairColor), EyeColor(Char.EyeColor), Talent(Char.Talent), Weakness(Char.Weakness), IsBonePlayer(Char.IsBonePlayer), IsClone(true)
3405 void playerkind::BeTalkedTo()
3407 if(IsClone && IsBonePlayer)
3409 if(GetRelation(PLAYER) == HOSTILE)
3411 ADD_MESSAGE("Oh no, you too! Why does everyone bully me!");
3412 return;
3415 static sLong Said;
3417 switch(RandomizeReply(Said, 4))
3419 case 0:
3420 ADD_MESSAGE("\"I'd like to write a memoir, but alas I doubt anyone would believe it.\"");
3421 break;
3422 case 1:
3423 ADD_MESSAGE("\"Then that damned clone appeared, took all my equipment and claimed I was his slave...\"");
3424 break;
3425 case 2:
3426 ADD_MESSAGE("\"The level was a catastrophe for the party, but luckily you saved the day.\"");
3427 break;
3428 case 3:
3429 ADD_MESSAGE("\"Oh, how I hate bananas. I Hate Them! I HATE THEM SO MUCH!!!\"");
3430 break;
3433 else if(IsClone)
3435 if(GetRelation(PLAYER) == HOSTILE)
3437 ADD_MESSAGE("%s seems extremely irritated. \"Vanish, you foul mirror image!\"", CHAR_DESCRIPTION(DEFINITE));
3438 return;
3441 static sLong Said;
3443 switch(RandomizeReply(Said, 4))
3445 case 0:
3446 ADD_MESSAGE("\"Hey, those clothes are mine! Give them back!\"");
3447 break;
3448 case 1:
3449 ADD_MESSAGE("\"What, you summoned me? What a coincidence, I remember summoning you, too.\"");
3450 break;
3451 case 2:
3452 ADD_MESSAGE("\"I'm leading this party, not you, Mr. copy guy!\"");
3453 break;
3454 case 3:
3455 ADD_MESSAGE("\"Oh, how I hate bananas. I Hate Them! I HATE THEM SO MUCH!!!\"");
3456 break;
3459 else
3461 if(GetRelation(PLAYER) == HOSTILE)
3463 ADD_MESSAGE("Let's finish what my ghost failed to do!");
3464 return;
3467 static sLong Said;
3469 switch(RandomizeReply(Said, 4))
3471 case 0:
3472 ADD_MESSAGE("\"What was it like? Death, you mean? Well, just like New Attnam. Very hot and whips everywhere.\"");
3473 break;
3474 case 1:
3475 ADD_MESSAGE("\"Stop it already! I *don't* want to know how my corpse smelled!\"");
3476 break;
3477 case 2:
3478 ADD_MESSAGE("\"I'm sorry about that ghost thing. That YASD was just a bit too much to handle, so I lost myself.\"");
3479 break;
3480 case 3:
3481 ADD_MESSAGE("\"Oh, how I hate bananas. I Hate Them! I HATE THEM SO MUCH!!!\"");
3482 break;
3487 void humanoid::EnsureCurrentSWeaponSkillIsCorrect(sweaponskill*& Skill, citem* Wielded)
3489 if(Wielded)
3491 if(!Skill || !Skill->IsSkillOf(Wielded))
3493 if(Skill)
3494 EnsureCurrentSWeaponSkillIsCorrect(Skill, 0);
3496 std::list<sweaponskill*>::iterator i;
3498 for(i = SWeaponSkill.begin(); i != SWeaponSkill.end(); ++i)
3499 if((*i)->IsSkillOf(Wielded))
3501 Skill = *i;
3502 return;
3505 for(idholder* I = Wielded->GetCloneMotherID(); I; I = I->Next)
3506 for(i = SWeaponSkill.begin(); i != SWeaponSkill.end(); ++i)
3507 if((*i)->IsSkillOfCloneMother(Wielded, I->ID))
3509 Skill = new sweaponskill(**i);
3510 Skill->SetID(Wielded->GetID());
3511 SWeaponSkill.push_back(Skill);
3512 return;
3515 Skill = new sweaponskill(Wielded);
3516 SWeaponSkill.push_back(Skill);
3519 else if(Skill)
3521 if(!Skill->GetHits() && (CurrentRightSWeaponSkill != Skill || CurrentLeftSWeaponSkill != Skill))
3522 for(std::list<sweaponskill*>::iterator i = SWeaponSkill.begin(); i != SWeaponSkill.end(); ++i)
3523 if(*i == Skill)
3525 delete *i;
3526 SWeaponSkill.erase(i);
3527 break;
3530 Skill = 0;
3534 humanoid::~humanoid()
3536 for(std::list<sweaponskill*>::iterator i = SWeaponSkill.begin(); i != SWeaponSkill.end(); ++i)
3537 delete *i;
3540 truth guard::MoveTowardsHomePos()
3542 if(GetConfig() == MASTER && GetPos() != v2(30, 16))
3544 if(CanBeSeenByPlayer())
3545 ADD_MESSAGE("%s disappears.", CHAR_NAME(DEFINITE));
3547 GetLevel()->GetLSquare(30, 16)->KickAnyoneStandingHereAway();
3548 Move(v2(30, 16), true);
3550 if(CanBeSeenByPlayer())
3551 ADD_MESSAGE("%s appears.", CHAR_NAME(DEFINITE));
3553 EditAP(-1000);
3554 return true;
3556 else
3557 return humanoid::MoveTowardsHomePos();
3560 bodypart* ennerbeast::MakeBodyPart(int I) const
3562 if(I == HEAD_INDEX)
3563 return ennerhead::Spawn(0, NO_MATERIALS);
3564 else
3565 return humanoid::MakeBodyPart(I);
3568 int humanoid::GetSumOfAttributes() const
3570 return character::GetSumOfAttributes() + GetAttribute(LEG_STRENGTH) + GetAttribute(DEXTERITY) ;
3573 truth humanoid::CheckConsume(cfestring& Verb) const
3575 if(!HasHead())
3577 if(IsPlayer())
3578 ADD_MESSAGE("You need a head to %s.", Verb.CStr());
3580 return false;
3583 return character::CheckConsume(Verb);
3586 truth humanoid::CanConsume(material* Material) const
3588 return character::CanConsume(Material) && HasHead();
3591 void femaleslave::BeTalkedTo()
3593 static sLong Said;
3595 if(GetConfig() != NEW_ATTNAM || GetRelation(PLAYER) == HOSTILE)
3596 humanoid::BeTalkedTo();
3597 else if(!game::TweraifIsFree())
3598 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said, 4)]);
3599 else
3600 ProcessAndAddMessage(GetFriendlyReplies()[4 + RandomizeReply(Said, 3)]);
3603 void necromancer::GetAICommand()
3605 SeekLeader(GetLeader());
3607 if(FollowLeader(GetLeader()))
3608 return;
3610 character* NearestEnemy = 0;
3611 sLong NearestEnemyDistance = 0x7FFFFFFF;
3612 v2 Pos = GetPos();
3614 for(int c = 0; c < game::GetTeams(); ++c)
3615 if(GetTeam()->GetRelation(game::GetTeam(c)) == HOSTILE)
3617 for(std::list<character*>::const_iterator i = game::GetTeam(c)->GetMember().begin(); i != game::GetTeam(c)->GetMember().end(); ++i)
3618 if((*i)->IsEnabled())
3620 sLong ThisDistance = Max<sLong>(abs((*i)->GetPos().X - Pos.X), abs((*i)->GetPos().Y - Pos.Y));
3622 if((ThisDistance < NearestEnemyDistance || (ThisDistance == NearestEnemyDistance && !(RAND() % 3))) && (*i)->CanBeSeenBy(this))
3624 NearestEnemy = *i;
3625 NearestEnemyDistance = ThisDistance;
3630 if(NearestEnemy && NearestEnemy->GetPos().IsAdjacent(Pos))
3632 if(GetConfig() == MASTER_NECROMANCER && !(RAND() & 3))
3634 if(CanBeSeenByPlayer())
3635 ADD_MESSAGE("%s invokes a spell and disappears.", CHAR_NAME(DEFINITE));
3637 TeleportRandomly(true);
3638 EditAP(-GetSpellAPCost());
3639 return;
3641 else if(NearestEnemy->IsSmall()
3642 && GetAttribute(WISDOM) < NearestEnemy->GetAttackWisdomLimit()
3643 && !(RAND() & 3)
3644 && Hit(NearestEnemy, NearestEnemy->GetPos(), game::GetDirectionForVector(NearestEnemy->GetPos() - GetPos())))
3645 return;
3648 if(!NearestEnemy)
3650 if(!RAND_N(3) && TryToRaiseZombie())
3651 return;
3653 else
3655 if(!RAND_N(6) && TryToRaiseZombie())
3656 return;
3659 if(NearestEnemy && !(RAND() % (GetConfig() == APPRENTICE_NECROMANCER ? 3 : 2)))
3661 lsquare* Square = NearestEnemy->GetLSquareUnder();
3662 EditAP(-GetSpellAPCost());
3664 if(CanBeSeenByPlayer())
3665 ADD_MESSAGE("%s invokes a spell!", CHAR_NAME(DEFINITE));
3667 truth Interrupt = false;
3669 switch(GetConfig())
3671 case APPRENTICE_NECROMANCER:
3672 RaiseSkeleton();
3673 break;
3674 case MASTER_NECROMANCER:
3675 if(RAND() % 5)
3676 RaiseSkeleton();
3677 else
3679 Square->DrawLightning(v2(8, 8), WHITE, YOURSELF);
3681 beamdata Beam
3683 this,
3684 CONST_S("killed by the spells of ") + GetName(INDEFINITE),
3685 YOURSELF,
3689 Square->Lightning(Beam);
3690 Interrupt = true;
3693 break;
3696 if(Interrupt) {
3697 if(CanBeSeenByPlayer())
3698 NearestEnemy->DeActivateVoluntaryAction(CONST_S("The spell of ") + GetName(DEFINITE) + CONST_S(" interrupts you."));
3699 else
3700 NearestEnemy->DeActivateVoluntaryAction(CONST_S("The spell interrupts you."));
3702 return;
3705 if(NearestEnemy && (NearestEnemyDistance < 10 || StateIsActivated(PANIC)) && RAND() & 3)
3707 SetGoingTo((Pos << 1) - NearestEnemy->GetPos());
3709 if(MoveTowardsTarget(true))
3710 return;
3713 if(CheckForDoors())
3714 return;
3716 if(CheckSadism())
3717 return;
3719 if(MoveRandomly())
3720 return;
3722 EditAP(-1000);
3725 truth necromancer::TryToRaiseZombie()
3727 for(int c = 0; c < game::GetTeams(); ++c)
3728 for(std::list<character*>::const_iterator i = game::GetTeam(c)->GetMember().begin();
3729 i != game::GetTeam(c)->GetMember().end(); ++i)
3730 if(!(*i)->IsEnabled() && (*i)->GetMotherEntity()
3731 && (*i)->GetMotherEntity()->Exists()
3732 && (GetConfig() == MASTER_NECROMANCER
3733 || (*i)->GetMotherEntity()->GetSquareUnderEntity()->CanBeSeenBy(this)))
3735 character* Zombie = (*i)->GetMotherEntity()->TryNecromancy(this);
3737 if(Zombie)
3739 if(Zombie->CanBeSeenByPlayer())
3740 ADD_MESSAGE("%s calls %s back to cursed undead life.", CHAR_DESCRIPTION(DEFINITE), Zombie->CHAR_NAME(INDEFINITE));
3741 else if(CanBeSeenByPlayer())
3742 ADD_MESSAGE("%s casts a spell, but you notice no effect.", CHAR_NAME(DEFINITE));
3744 EditAP(-GetSpellAPCost());
3745 return true;
3749 return false;
3752 void necromancer::RaiseSkeleton()
3754 /* Gum solution */
3756 const database* WarLordDataBase;
3757 databasecreator<character>::FindDataBase(WarLordDataBase, &skeleton::ProtoType, WAR_LORD);
3758 skeleton* Skeleton;
3760 if(GetConfig() == MASTER_NECROMANCER && !(WarLordDataBase->Flags & HAS_BEEN_GENERATED) && !(RAND() % 250))
3762 Skeleton = skeleton::Spawn(WAR_LORD);
3763 Skeleton->SetTeam(GetTeam());
3764 Skeleton->PutNear(GetPos());
3765 Skeleton->SignalGeneration();
3767 if(Skeleton->CanBeSeenByPlayer())
3768 ADD_MESSAGE("The whole area trembles terribly as %s emerges from the ground.", Skeleton->CHAR_NAME(DEFINITE));
3769 else if(CanBeSeenByPlayer())
3770 ADD_MESSAGE("%s casts a powerful spell which makes the whole area tremble.", CHAR_NAME(DEFINITE));
3771 else
3772 ADD_MESSAGE("You feel the presence of an ancient evil being awakened from its long slumber. You shiver.");
3774 else
3776 Skeleton = skeleton::Spawn(GetConfig() == APPRENTICE_NECROMANCER ? 0 : WARRIOR, NO_EQUIPMENT);
3777 Skeleton->SetTeam(GetTeam());
3778 Skeleton->PutNear(GetPos());
3780 if(Skeleton->CanBeSeenByPlayer())
3781 ADD_MESSAGE("The ground shakes and %s emerges from it.", Skeleton->CHAR_NAME(INDEFINITE));
3782 else if(CanBeSeenByPlayer())
3783 ADD_MESSAGE("%s casts a spell, but you notice no effect.", CHAR_NAME(DEFINITE));
3786 Skeleton->SetGenerationDanger(GetGenerationDanger());
3787 EditAP(-GetSpellAPCost());
3790 void humanoid::StayOn(liquid* Liquid)
3792 if(IsFlying())
3793 return;
3795 truth Standing = false;
3797 if(GetRightLeg())
3799 GetRightLeg()->StayOn(Liquid);
3800 Standing = true;
3803 if(IsEnabled() && GetLeftLeg())
3805 GetLeftLeg()->StayOn(Liquid);
3806 Standing = true;
3809 if(!Standing)
3811 bodypart* BodyPart[MAX_BODYPARTS];
3812 int Index = 0;
3814 for(int c = 0; c < BodyParts; ++c)
3815 if(GetBodyPart(c))
3816 BodyPart[Index++] = GetBodyPart(c);
3818 BodyPart[RAND() % Index]->StayOn(Liquid);
3822 bodypart* playerkind::MakeBodyPart(int I) const
3824 switch(I)
3826 case TORSO_INDEX: return playerkindtorso::Spawn(0, NO_MATERIALS);
3827 case HEAD_INDEX: return playerkindhead::Spawn(0, NO_MATERIALS);
3828 case RIGHT_ARM_INDEX: return playerkindrightarm::Spawn(0, NO_MATERIALS);
3829 case LEFT_ARM_INDEX: return playerkindleftarm::Spawn(0, NO_MATERIALS);
3830 case GROIN_INDEX: return playerkindgroin::Spawn(0, NO_MATERIALS);
3831 case RIGHT_LEG_INDEX: return playerkindrightleg::Spawn(0, NO_MATERIALS);
3832 case LEFT_LEG_INDEX: return playerkindleftleg::Spawn(0, NO_MATERIALS);
3835 ABORT("Weird bodypart to make for a playerkind. It must be your fault!");
3836 return 0;
3839 truth golem::AddAdjective(festring& String, truth Articled) const
3841 int TotalRustLevel = sumbodypartproperties()(this, &bodypart::GetMainMaterialRustLevel);
3843 if(!TotalRustLevel)
3844 return humanoid::AddAdjective(String, Articled);
3845 else
3847 if(Articled)
3848 String << "a ";
3850 if(TotalRustLevel <= GetBodyParts())
3851 String << "slightly rusted ";
3852 else if(TotalRustLevel <= GetBodyParts() << 1)
3853 String << "rusted ";
3854 else
3855 String << "very rusted ";
3857 String << GetAdjective() << ' ';
3858 return true;
3862 void oree::Bite(character* Enemy, v2 HitPos, int, truth)
3864 if(IsPlayer())
3865 ADD_MESSAGE("You vomit acidous blood at %s.", Enemy->CHAR_DESCRIPTION(DEFINITE));
3866 else if(Enemy->IsPlayer() || CanBeSeenByPlayer() || Enemy->CanBeSeenByPlayer())
3867 ADD_MESSAGE("%s vomits acidous blood at %s.", CHAR_DESCRIPTION(DEFINITE), Enemy->CHAR_DESCRIPTION(DEFINITE));
3869 Vomit(HitPos, 500 + RAND() % 500, false);
3872 void sumowrestler::GetAICommand()
3874 EditNP(-25);
3876 SeekLeader(GetLeader());
3878 if(CheckForEnemies(true, true, true))
3879 return;
3881 if(CheckForUsefulItemsOnGround())
3882 return;
3884 if(CheckForFood(4))
3885 return;
3887 if(FollowLeader(GetLeader()))
3888 return;
3890 if(CheckForDoors())
3891 return;
3893 if(MoveTowardsHomePos())
3894 return;
3896 EditAP(-1000);
3899 void sumowrestler::BeTalkedTo()
3901 static sLong Said;
3903 if(GetRelation(PLAYER) == HOSTILE)
3904 ProcessAndAddMessage(GetHostileReplies()[RandomizeReply(Said, GetHostileReplies().Size)]);
3905 else if(!game::TweraifIsFree())
3906 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said, 6)]);
3907 else
3908 ProcessAndAddMessage(GetFriendlyReplies()[6 + RandomizeReply(Said, 3)]);
3911 character* tourist::GetLeader() const
3913 character* Guide = game::GetTeam(TOURIST_GUIDE_TEAM)->GetLeader();
3914 return Guide && Guide->GetRelation(this) != HOSTILE ? Guide : GetTeam()->GetLeader();
3917 void elder::GetAICommand()
3919 /* Select a place to guide the tourists to */
3921 if(!(RAND() % 10))
3922 SetGoingTo(GetLevel()->GetRandomSquare());
3924 humanoid::GetAICommand();
3927 void tourist::GetAICommand()
3929 if(game::IsSumoWrestling() && !(RAND() % 10))
3931 if(GetConfig() == HUSBAND)
3933 if(RAND() & 1)
3934 ADD_MESSAGE("%s shouts: \"Show that skinny wimp what you've got, Huang!\"", CHAR_DESCRIPTION(DEFINITE));
3935 else
3936 ADD_MESSAGE("%s screams: \"Go for it, Huang!\"", CHAR_DESCRIPTION(DEFINITE));
3938 else if(GetConfig() == WIFE)
3940 if(RAND() & 1)
3941 ADD_MESSAGE("%s encourages you: \"Knock him out, %s!\"", CHAR_DESCRIPTION(DEFINITE), game::GetPlayerName().CStr());
3942 else
3943 ADD_MESSAGE("%s cheers you: \"A handsome guy like you can't lose to that banana ball!\"", CHAR_DESCRIPTION(DEFINITE));
3945 else if(GetConfig() == CHILD)
3947 if(RAND() & 1)
3948 ADD_MESSAGE("%s yells: \"More blood on the ring!!!\"", CHAR_DESCRIPTION(DEFINITE));
3949 else
3950 ADD_MESSAGE("%s cries: \"Kill him, Pong!!!\"", CHAR_DESCRIPTION(DEFINITE));
3954 humanoid::GetAICommand();
3958 ///////////////////////////////////////////////////////////////////////////////
3959 character* humanoid::CreateZombie() const
3961 if(!TorsoIsAlive())
3962 return 0;
3964 humanoid* Zombie = zombie::Spawn();
3965 int c;
3967 for(c = 0; c < BodyParts; ++c)
3969 bodypart* BodyPart = GetBodyPart(c);
3971 if(!BodyPart)
3973 BodyPart = SearchForOriginalBodyPart(c);
3975 if(BodyPart)
3977 BodyPart->RemoveFromSlot();
3978 BodyPart->SendToHell();
3982 if(BodyPart)
3984 bodypart* ZombieBodyPart = Zombie->GetBodyPart(c);
3986 if(!ZombieBodyPart)
3987 ZombieBodyPart = Zombie->CreateBodyPart(c);
3989 material* M = BodyPart->GetMainMaterial()->Duplicate();
3990 M->SetSpoilCounter(2000 + RAND() % 1000);
3991 M->SetSkinColor(Zombie->GetSkinColor());
3992 ZombieBodyPart->ChangeMainMaterial(M);
3993 ZombieBodyPart->CopyAttributes(BodyPart);
3995 else if(!Zombie->BodyPartIsVital(c))
3997 bodypart* ZombieBodyPart = Zombie->GetBodyPart(c);
3999 if(ZombieBodyPart)
4001 ZombieBodyPart->RemoveFromSlot();
4002 ZombieBodyPart->SendToHell();
4007 for(c = 0; c < Zombie->AllowedWeaponSkillCategories; ++c)
4008 Zombie->CWeaponSkill[c] = CWeaponSkill[c];
4010 Zombie->SWeaponSkill.resize(SWeaponSkill.size());
4011 std::list<sweaponskill*>::iterator i1 = Zombie->SWeaponSkill.begin();
4012 std::list<sweaponskill*>::const_iterator i2 = SWeaponSkill.begin();
4014 for(; i2 != SWeaponSkill.end(); ++i1, ++i2)
4015 *i1 = new sweaponskill(**i2);
4017 memcpy(Zombie->BaseExperience,
4018 BaseExperience,
4019 BASE_ATTRIBUTES * sizeof(*BaseExperience));
4020 Zombie->CalculateAll();
4021 Zombie->RestoreHP();
4022 Zombie->RestoreStamina();
4023 static_cast<zombie*>(Zombie)->SetDescription(GetZombieDescription());
4024 Zombie->GenerationDanger = GenerationDanger;
4025 return Zombie;
4028 void zombie::AddPostFix(festring& String, int Case) const
4030 if(!Description.IsEmpty())
4031 String << Description;
4032 else
4033 humanoid::AddPostFix(String, Case);
4036 void zombie::Save(outputfile& SaveFile) const
4038 humanoid::Save(SaveFile);
4039 SaveFile << Description;
4042 void zombie::Load(inputfile& SaveFile)
4044 humanoid::Load(SaveFile);
4045 SaveFile >> Description;
4048 int darkknight::ModifyBodyPartHitPreference(int I, int Modifier) const
4050 return IsLimbIndex(I) ? Modifier << 1 : Modifier;
4053 int darkknight::ModifyBodyPartToHitChance(int I, int Chance) const
4055 return IsLimbIndex(I) ? Chance << 1 : Chance;
4058 void darkknight::SpecialBodyPartSeverReaction()
4060 if(!IsPlayer())
4062 if(IsUsingHead())
4063 ADD_MESSAGE("%s screams: \"I'll do you for that! I'll bite your legs off!\"", CHAR_DESCRIPTION(DEFINITE));
4064 else if(!(RAND() % 5))
4065 switch(RAND() % 3)
4067 case 0:
4068 ADD_MESSAGE("%s states calmly: \"'Tis but a scratch.\"", CHAR_DESCRIPTION(DEFINITE)); break;
4069 case 1:
4070 ADD_MESSAGE("%s states calmly: \"Just a flesh wound.\"", CHAR_DESCRIPTION(DEFINITE)); break;
4071 case 2:
4072 ADD_MESSAGE("%s shouts: \"I'm invincible!\"", CHAR_DESCRIPTION(DEFINITE)); break;
4077 void humanoid::LeprosyHandler()
4079 if(IsImmuneToLeprosy())
4081 return;
4084 if(!RAND_N(1000 * GetAttribute(ENDURANCE)))
4085 DropRandomNonVitalBodypart();
4087 if(!game::IsInWilderness())
4089 for(int d = 0; d < GetNeighbourSquares(); ++d)
4091 lsquare* Square = GetNeighbourLSquare(d);
4093 if(Square && Square->GetCharacter())
4094 Square->GetCharacter()->TryToInfectWithLeprosy(this);
4098 character::LeprosyHandler();
4101 void humanoid::DropRandomNonVitalBodypart()
4103 int BodyPartIndexToDrop = GetRandomNonVitalBodyPart();
4105 if(BodyPartIndexToDrop != NONE_INDEX)
4106 DropBodyPart(BodyPartIndexToDrop);
4109 void humanoid::DropBodyPart(int Index)
4111 if(!GetBodyPart(Index)->IsAlive())
4112 return;
4114 festring NameOfDropped = GetBodyPart(Index)->GetBodyPartName();
4115 item* Dropped = SevereBodyPart(Index);
4117 if(Dropped)
4119 GetStack()->AddItem(Dropped);
4120 Dropped->DropEquipment();
4122 if(IsPlayer())
4124 ADD_MESSAGE("You feel very ill. Your %s snaps off.", NameOfDropped.CStr());
4125 game::AskForEscPress(CONST_S("Bodypart severed!"));
4126 DeActivateVoluntaryAction();
4128 else if(CanBeSeenByPlayer())
4129 ADD_MESSAGE("Suddenly %s's %s snaps off.", CHAR_NAME(DEFINITE), NameOfDropped.CStr());
4131 else
4133 if(IsPlayer())
4135 ADD_MESSAGE("You feel very ill. Your %s disappears.", NameOfDropped.CStr());
4136 game::AskForEscPress(CONST_S("Bodypart destroyed!"));
4137 DeActivateVoluntaryAction();
4139 else if(CanBeSeenByPlayer())
4140 ADD_MESSAGE("Suddenly %s's %s disappears.", CHAR_NAME(DEFINITE), NameOfDropped.CStr());
4144 void humanoid::DuplicateEquipment(character* Receiver, uLong Flags)
4146 character::DuplicateEquipment(Receiver, Flags);
4147 EnsureCurrentSWeaponSkillIsCorrect(CurrentRightSWeaponSkill, GetRightWielded());
4148 EnsureCurrentSWeaponSkillIsCorrect(CurrentLeftSWeaponSkill, GetLeftWielded());
4151 truth character::CanHear() const
4153 return DataBase->CanHear && HasHead();
4156 col16 veterankamikazedwarf::GetTorsoMainColor() const
4158 return GetMasterGod()->GetEliteColor();
4161 col16 veterankamikazedwarf::GetGauntletColor() const
4163 return GetMasterGod()->GetEliteColor();
4166 col16 veterankamikazedwarf::GetLegMainColor() const
4168 return GetMasterGod()->GetEliteColor();
4171 col16 archangel::GetTorsoMainColor() const
4173 return GetMasterGod()->GetEliteColor();
4176 col16 archangel::GetArmMainColor() const
4178 return GetMasterGod()->GetEliteColor();
4181 void archangel::CreateInitialEquipment(int SpecialFlags)
4183 humanoid::CreateInitialEquipment(SpecialFlags);
4184 GetStack()->AddItem(holybook::Spawn(GetConfig(), SpecialFlags));
4185 armor* Equipment;
4186 meleeweapon* Weapon;
4188 switch(GetMasterGod()->GetBasicAlignment())
4190 case GOOD:
4191 Weapon = flamingsword::Spawn(0, SpecialFlags|NO_MATERIALS);
4192 Weapon->InitMaterials(MAKE_MATERIAL(DIAMOND), MAKE_MATERIAL(ADAMANT), !(SpecialFlags & NO_PIC_UPDATE));
4193 Weapon->SetEnchantment(4);
4194 SetRightWielded(Weapon);
4195 Equipment = shield::Spawn(0, SpecialFlags|NO_MATERIALS);
4196 Equipment->InitMaterials(MAKE_MATERIAL(DIAMOND), !(SpecialFlags & NO_PIC_UPDATE));
4197 Equipment->SetEnchantment(4);
4198 SetLeftWielded(Equipment);
4199 GetCWeaponSkill(LARGE_SWORDS)->AddHit(200000);
4200 GetCWeaponSkill(SHIELDS)->AddHit(500000);
4201 GetCurrentRightSWeaponSkill()->AddHit(200000);
4202 GetCurrentLeftSWeaponSkill()->AddHit(200000);
4203 GetRightArm()->SetDexterity(70);
4204 GetLeftArm()->SetDexterity(70);
4205 break;
4206 case NEUTRAL:
4207 Weapon = meleeweapon::Spawn(WAR_HAMMER, SpecialFlags|NO_MATERIALS);
4208 Weapon->InitMaterials(MAKE_MATERIAL(SAPPHIRE), MAKE_MATERIAL(OCTIRON), !(SpecialFlags & NO_PIC_UPDATE));
4209 Weapon->SetEnchantment(4);
4210 SetRightWielded(Weapon);
4211 GetCWeaponSkill(BLUNT_WEAPONS)->AddHit(500000);
4212 GetCurrentRightSWeaponSkill()->AddHit(200000);
4213 SetEndurance(70);
4214 break;
4215 case EVIL:
4216 Weapon = meleeweapon::Spawn(HALBERD, SpecialFlags|NO_MATERIALS);
4217 Weapon->InitMaterials(MAKE_MATERIAL(RUBY), MAKE_MATERIAL(OCTIRON), !(SpecialFlags & NO_PIC_UPDATE));
4218 Weapon->SetEnchantment(4);
4219 SetLeftWielded(Weapon);
4220 GetCWeaponSkill(POLE_ARMS)->AddHit(500000);
4221 GetCurrentLeftSWeaponSkill()->AddHit(500000);
4222 GetRightArm()->SetStrength(70);
4223 GetLeftArm()->SetStrength(70);
4227 void zombie::PostConstruct()
4229 if(!RAND_N(3))
4230 GainIntrinsic(LEPROSY);
4233 void orc::PostConstruct()
4235 if(!RAND_N(25))
4236 GainIntrinsic(LEPROSY);
4239 truth mistress::AllowEquipment(citem* Item, int EquipmentIndex) const
4241 return ((EquipmentIndex != RIGHT_WIELDED_INDEX
4242 && EquipmentIndex != LEFT_WIELDED_INDEX)
4243 || Item->IsWhip());
4246 int humanoid::GetAttributeAverage() const
4248 return GetSumOfAttributes() / 9;
4251 void golem::CreateCorpse(lsquare* Square)
4253 material* Material = GetTorso()->GetMainMaterial();
4255 if(Material->IsSolid())
4256 Square->AddItem(Material->CreateNaturalForm(ItemVolume));
4258 SendToHell();
4261 golem::golem()
4263 if(!game::IsLoading())
4264 ItemVolume = 50 + RAND_N(100);
4267 void golem::Save(outputfile& SaveFile) const
4269 humanoid::Save(SaveFile);
4270 SaveFile << ItemVolume;
4273 void golem::Load(inputfile& SaveFile)
4275 humanoid::Load(SaveFile);
4276 SaveFile >> ItemVolume;
4279 truth humanoid::CanVomit() const
4281 return HasHead() && character::CanVomit();
4284 truth humanoid::CheckApply() const
4286 if(!character::CheckApply())
4287 return false;
4289 if(!HasAUsableArm())
4291 ADD_MESSAGE("You need a usable arm to apply.");
4292 return false;
4295 return true;
4298 int darkmage::GetSpellAPCost() const
4300 switch(GetConfig())
4302 case APPRENTICE: return 4000;
4303 case BATTLE_MAGE: return 2000;
4304 case ELDER: return 1000;
4305 case ARCH_MAGE: return 500;
4308 return 4000;
4311 int necromancer::GetSpellAPCost() const
4313 switch(GetConfig())
4315 case APPRENTICE_NECROMANCER: return 2000;
4316 case MASTER_NECROMANCER: return 1000;
4319 return 4000;
4322 /* Horrible repeating. Sorry */
4324 void tailor::BeTalkedTo()
4326 if(GetRelation(PLAYER) == HOSTILE)
4328 ADD_MESSAGE("\"You talkin' to me? You talkin' to me? You talkin' to me? Then who the hell else are you talkin' to? You talkin' to me? Well I'm the only one here. Who do you think you're talking to? Oh yeah? Huh? Ok.\"");
4329 return;
4332 if(PLAYER->PossessesItem(&item::IsFixableByTailor))
4334 item* Item = PLAYER->SelectFromPossessions(CONST_S("\"What do you want me to fix?\""), &item::IsFixableByTailor);
4336 if(!Item)
4337 return;
4339 if(!(Item->GetMainMaterial()->GetCategoryFlags() & CAN_BE_TAILORED))
4341 ADD_MESSAGE("\"I can't work on %s.\"", Item->GetMainMaterial()->GetName(false, false).CStr());
4342 return;
4345 /** update messages */
4347 sLong FixPrice = Item->GetFixPrice();
4349 if(PLAYER->GetMoney() < FixPrice)
4351 ADD_MESSAGE("\"Getting that fixed costs you %d gold pieces. Get the money and we'll talk.\"", FixPrice);
4352 return;
4355 ADD_MESSAGE("\"I can fix your %s, but it'll cost you %d gold pieces.\"", Item->CHAR_NAME(UNARTICLED), FixPrice);
4357 if(game::TruthQuestion(CONST_S("Do you accept this deal? [y/N]")))
4359 Item->Fix();
4360 PLAYER->EditMoney(-FixPrice);
4361 ADD_MESSAGE("%s fixes %s in no time.", CHAR_NAME(DEFINITE), Item->CHAR_NAME(DEFINITE));
4364 else
4365 ADD_MESSAGE("\"Come back when you have some weapons or armor I can fix.\"");
4368 void veterankamikazedwarf::PostConstruct()
4370 kamikazedwarf::PostConstruct();
4371 ivantime Time;
4372 game::GetTime(Time);
4373 int Modifier = Time.Day - KAMIKAZE_INVISIBILITY_DAY_MIN;
4375 if(Time.Day >= KAMIKAZE_INVISIBILITY_DAY_MAX
4376 || (Modifier > 0
4377 && RAND_N(KAMIKAZE_INVISIBILITY_DAY_MAX - KAMIKAZE_INVISIBILITY_DAY_MIN) < Modifier))
4378 GainIntrinsic(INVISIBLE);
4381 truth humanoid::IsTransparent() const
4383 return character::IsTransparent() || !(GetRightLeg() || GetLeftLeg());
4386 void humanoid::ModifySituationDanger(double& Danger) const
4388 character::ModifySituationDanger(Danger);
4390 switch(GetUsableArms())
4392 case 0: Danger *= 10;
4393 case 1: Danger *= 2;
4396 switch(GetUsableLegs())
4398 case 0: Danger *= 10;
4399 case 1: Danger *= 2;
4403 void oree::GetAICommand()
4405 if(!RAND_N(50))
4406 CallForMonsters();
4408 humanoid::GetAICommand();
4411 void oree::CallForMonsters()
4413 if(GetDungeon()->GetIndex() != ELPURI_CAVE || GetLevel()->GetIndex() != OREE_LAIR)
4414 return;
4416 character* ToBeCalled = 0;
4418 switch(RAND_N(6))
4420 case 0:
4421 ToBeCalled = darkknight::Spawn(ELITE);
4422 break;
4423 case 1:
4424 ToBeCalled = frog::Spawn(RAND_2 ? GREATER_DARK : GIANT_DARK);
4425 break;
4426 case 2:
4427 ToBeCalled = frog::Spawn(DARK);
4428 break;
4429 case 3:
4430 ToBeCalled = darkmage::Spawn(RAND_2 ? APPRENTICE : BATTLE_MAGE);
4431 break;
4432 case 4:
4433 ToBeCalled = darkmage::Spawn(RAND_2 ? APPRENTICE : ELDER);
4434 break;
4435 case 5:
4436 ToBeCalled = necromancer::Spawn(RAND_2 ? APPRENTICE_NECROMANCER : MASTER_NECROMANCER);
4437 break;
4440 v2 TryToCreate;
4442 for(int c = 0; c < 100; ++c)
4444 TryToCreate = game::GetMonsterPortal()->GetPos() + game::GetMoveVector(RAND() % DIRECTION_COMMAND_KEYS);
4446 if(GetArea()->IsValidPos(TryToCreate) && ToBeCalled->CanMoveOn(GetNearLSquare(TryToCreate)) && ToBeCalled->IsFreeForMe(GetNearLSquare(TryToCreate)))
4448 ToBeCalled->SetTeam(game::GetTeam(MONSTER_TEAM));
4449 ToBeCalled->PutTo(TryToCreate);
4450 return;
4454 delete ToBeCalled;
4457 int humanoid::RandomizeTryToUnStickBodyPart(uLong PossibleBodyParts) const
4459 int Possible = 0, PossibleArray[3];
4461 if(RightArmIsUsable() && 1 << RIGHT_ARM_INDEX & PossibleBodyParts)
4462 PossibleArray[Possible++] = RIGHT_ARM_INDEX;
4464 if(LeftArmIsUsable() && 1 << LEFT_ARM_INDEX & PossibleBodyParts)
4465 PossibleArray[Possible++] = LEFT_ARM_INDEX;
4467 if(Possible)
4468 return PossibleArray[RAND_N(Possible)];
4470 if(RightLegIsUsable() && 1 << RIGHT_LEG_INDEX & PossibleBodyParts)
4471 PossibleArray[Possible++] = RIGHT_LEG_INDEX;
4473 if(LeftLegIsUsable() && 1 << LEFT_LEG_INDEX & PossibleBodyParts)
4474 PossibleArray[Possible++] = LEFT_LEG_INDEX;
4476 if(Possible)
4477 return PossibleArray[RAND_N(Possible)];
4479 if(GetHead() && 1 << HEAD_INDEX & PossibleBodyParts)
4480 return HEAD_INDEX;
4482 if(GetGroin() && 1 << GROIN_INDEX & PossibleBodyParts)
4483 PossibleArray[Possible++] = GROIN_INDEX;
4485 if(1 << TORSO_INDEX & PossibleBodyParts)
4486 PossibleArray[Possible++] = TORSO_INDEX;
4488 return Possible ? PossibleArray[RAND_N(Possible)] : NONE_INDEX;
4491 truth humanoid::HasAUsableArm() const
4493 arm* R = GetRightArm(), * L = GetLeftArm();
4494 return (R && R->IsUsable()) || (L && L->IsUsable());
4497 truth humanoid::HasAUsableLeg() const
4499 leg* R = GetRightLeg(), * L = GetLeftLeg();
4500 return (R && R->IsUsable()) || (L && L->IsUsable());
4503 truth humanoid::HasTwoUsableLegs() const
4505 leg* R = GetRightLeg(), * L = GetLeftLeg();
4506 return R && R->IsUsable() && L && L->IsUsable();
4509 truth humanoid::CanAttackWithAnArm() const
4511 arm* R = GetRightArm();
4513 if(R && R->GetDamage())
4514 return true;
4516 arm* L = GetLeftArm();
4517 return L && L->GetDamage();
4520 truth humanoid::RightArmIsUsable() const
4522 arm* A = GetRightArm();
4523 return A && A->IsUsable();
4526 truth humanoid::LeftArmIsUsable() const
4528 arm* A = GetLeftArm();
4529 return A && A->IsUsable();
4532 truth humanoid::RightLegIsUsable() const
4534 leg* L = GetRightLeg();
4535 return L && L->IsUsable();
4538 truth humanoid::LeftLegIsUsable() const
4540 leg* L = GetLeftLeg();
4541 return L && L->IsUsable();
4544 truth humanoid::AllowUnconsciousness() const
4546 return (DataBase->AllowUnconsciousness && TorsoIsAlive()
4547 && BodyPartIsVital(HEAD_INDEX));
4550 truth humanoid::CanChokeOnWeb(web* Web) const
4552 return CanChoke() && Web->IsStuckToBodyPart(HEAD_INDEX);
4555 truth humanoid::BrainsHurt() const
4557 head* Head = GetHead();
4558 return !Head || Head->IsBadlyHurt();
4561 void playerkind::PostConstruct()
4563 int R = 0, G = 0, B = 0;
4565 switch(RAND_N(4))
4567 case 0: R = 195; G = 165; B = 40; break;
4568 case 1: R = 130; G = 30; B = 0; break;
4569 case 2: R = 30; G = 30; B = 15; break;
4570 case 3: R = 50; G = 30; B = 5; break;
4573 HairColor = MakeRGB16(R + RAND_N(41), G + RAND_N(41), B + RAND_N(41));
4575 switch(RAND_N(4))
4577 case 0: R = 25; G = 0; B = 70; break;
4578 case 1: R = 5; G = 0; B = 50; break;
4579 case 2: R = 10; G = 10; B = 10; break;
4580 case 3: R = 60; G = 20; B = 0; break;
4583 EyeColor = MakeRGB16(R + RAND_N(41), G + RAND_N(41), B + RAND_N(41));
4584 Talent = RAND_N(TALENTS);
4585 Weakness = RAND_N(TALENTS);
4588 v2 playerkind::GetHeadBitmapPos() const
4590 int Sum = GetAttribute(INTELLIGENCE, false) + GetAttribute(WISDOM, false);
4592 if(Sum >= 60)
4593 return v2(96, 480);
4594 else if(Sum >= 40)
4595 return v2(96, 464);
4596 else
4597 return v2(96, 416);
4600 v2 playerkind::GetRightArmBitmapPos() const
4602 if(GetRightArm()->GetAttribute(ARM_STRENGTH, false) >= 20)
4603 return v2(64, 448);
4604 else
4605 return v2(64, 416);
4608 v2 playerkind::GetLeftArmBitmapPos() const
4610 if(GetLeftArm()->GetAttribute(ARM_STRENGTH, false) >= 20)
4611 return v2(64, 448);
4612 else
4613 return v2(64, 416);
4616 int playerkind::GetNaturalSparkleFlags() const
4618 return GetAttribute(CHARISMA) >= 30 ? SKIN_COLOR : 0;
4621 void slave::PostConstruct()
4623 Talent = TALENT_STRONG;
4624 Weakness = TALENT_CLEVER;
4627 cint TalentOfAttribute[ATTRIBUTES] = { TALENT_HEALTHY, TALENT_FAST_N_ACCURATE, TALENT_CLEVER, TALENT_CLEVER, TALENT_CLEVER, TALENT_CLEVER, TALENT_CLEVER, TALENT_STRONG, TALENT_STRONG, TALENT_FAST_N_ACCURATE, TALENT_FAST_N_ACCURATE };
4628 const double TalentBonusOfAttribute[ATTRIBUTES] = { 1.1, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25 };
4630 double playerkind::GetNaturalExperience(int Identifier) const
4632 double NE = DataBase->NaturalExperience[Identifier];
4634 if(Talent == TalentOfAttribute[Identifier])
4635 NE *= TalentBonusOfAttribute[Identifier];
4637 if(Weakness == TalentOfAttribute[Identifier])
4638 NE /= TalentBonusOfAttribute[Identifier];
4640 return NE;
4643 cchar* humanoid::GetRunDescriptionLine(int I) const
4645 if(!GetRunDescriptionLineOne().IsEmpty())
4646 return !I ? GetRunDescriptionLineOne().CStr() : GetRunDescriptionLineTwo().CStr();
4648 if(IsFlying())
4649 return !I ? "Flying" : "very fast";
4651 if(IsSwimming())
4653 if(!GetRightArm() && !GetLeftArm() && !GetRightLeg() && !GetLeftLeg())
4654 return !I ? "Floating" : "ahead fast";
4655 else
4656 return !I ? "Swimming" : "very fast";
4659 if(!GetRightLeg() && !GetLeftLeg())
4660 return !I ? "Rolling" : "very fast";
4662 if(!GetRightLeg() || !GetLeftLeg())
4663 return !I ? "Hopping" : "very fast";
4665 return !I ? "Running" : "";
4668 cchar* humanoid::GetNormalDeathMessage() const
4670 if(BodyPartIsVital(HEAD_INDEX) && (!GetHead() || GetHead()->GetHP() <= 0))
4671 return "beheaded @k";
4672 else if(BodyPartIsVital(GROIN_INDEX) && (!GetGroin() || GetGroin()->GetHP() <= 0))
4673 return "killed @bkp dirty attack below the belt";
4674 else
4675 return "killed @k";
4678 void kamikazedwarf::SingRandomSong()
4680 festring Song;
4681 festring God = GetMasterGod()->GetName();
4682 festring Bodypart;
4684 switch(RAND_N(9))
4686 case 0:
4688 switch(RAND_N(3))
4690 case 0:
4691 Bodypart = "palm";
4692 break;
4694 case 1:
4695 Bodypart = "forehead";
4696 break;
4698 default:
4699 Bodypart = "tongue";
4700 break;
4702 Song = festring("On the ") + Bodypart + festring(" of ") + God + " everybody fears everything";
4703 break;
4704 case 1:
4706 festring Title = GetMasterGod()->GetSex() == MALE ? "King" : "Queen";
4707 Song = festring("Joy to the world, ") + God
4708 + " is come! Let all above Valpurus receive her " + Title;
4709 break;
4711 case 2:
4712 Song = festring("Hark the herald angels sing. Glory to ") + God + "!";
4713 break;
4714 case 3:
4715 Song = festring("O ") + God
4716 + ", You are so big, So absolutely huge, Gosh, "
4717 "we're all really impressed down here, I can tell You.";
4718 break;
4719 case 4:
4720 Song = festring("Forgive us, O ") + God
4721 + " for this, our dreadful toadying and barefaced flattery";
4722 break;
4723 case 5:
4724 Song = festring("But you, ") + God
4725 + ", are so strong and, well, just so super fantastic. Amen.";
4726 break;
4727 case 6:
4728 Song = festring("O ") + God + ", please don't burn us";
4729 break;
4730 case 7:
4731 Song = festring("O ") + God + ", please don't grill or toast your flock";
4732 break;
4733 case 8:
4734 Song = festring("O ") + God + ", please don't simmer us in stock";
4735 break;
4738 EditAP(-1000);
4740 if(CanBeSeenByPlayer())
4741 ADD_MESSAGE("%s sings: \"%s\"",
4742 CHAR_DESCRIPTION(DEFINITE), Song.CStr());
4743 else
4744 ADD_MESSAGE("You hear someone sing: \"%s\"", Song.CStr());
4747 void humanoid::ApplySpecialAttributeBonuses()
4749 if(GetHead())
4751 AttributeBonus[CHARISMA] -= GetHead()->
4752 CalculateScarAttributePenalty(GetAttribute(CHARISMA, false));
4754 else
4755 AttributeBonus[CHARISMA] -= GetAttribute(CHARISMA, false) - 1;
4758 void siren::GetAICommand()
4760 if(TryToSing())
4761 return;
4763 humanoid::GetAICommand();
4766 truth siren::TryToSing()
4768 truth Success=false;
4769 for(int d = 0; d < GetNeighbourSquares(); ++d)
4771 lsquare* Square = GetNeighbourLSquare(d);
4773 if(Square && Square->GetCharacter())
4775 Success = true;
4776 Square->GetCharacter()->ReceiveSirenSong(this);
4779 if(Success)
4780 EditAP(-2000);
4782 return Success;
4785 truth humanoid::MindWormCanPenetrateSkull(mindworm* Worm) const
4787 if(GetHelmet())
4789 if(RAND_N(102) > GetHelmet()->GetCoverPercentile())
4791 return RAND_2;
4795 return RAND_2;
4798 truth humanoid::HasSadistWeapon() const
4800 arm* Right = GetRightArm(), * Left = GetLeftArm();
4801 return (Right && Right->HasSadistWeapon()) || (Left && Left->HasSadistWeapon());
4804 truth humanoid::HasSadistAttackMode() const
4806 return HasSadistWeapon() || IsUsingLegs();
4809 void petrusswife::Save(outputfile& SaveFile) const
4811 humanoid::Save(SaveFile);
4812 SaveFile << GiftTotal;
4815 void petrusswife::Load(inputfile& SaveFile)
4817 humanoid::Load(SaveFile);
4818 SaveFile >> GiftTotal;
4821 void petrusswife::BeTalkedTo()
4823 itemvector Item;
4825 if(!PLAYER->SelectFromPossessions(Item, CONST_S("Do you have something to give me?"), 0, &item::IsLuxuryItem)
4826 || Item.empty())
4827 humanoid::BeTalkedTo();
4829 int Accepted = 0;
4830 truth RefusedSomething = false;
4832 for(unsigned int c = 0; c < Item.size(); ++c)
4833 if(!MakesBurdened(GetCarriedWeight() + Item[c]->GetWeight()))
4835 ++Accepted;
4836 GiftTotal += Item[c]->GetTruePrice();
4837 Item[c]->RemoveFromSlot();
4838 GetStack()->AddItem(Item[c]);
4840 else
4842 RefusedSomething = true;
4843 break;
4846 if(Accepted)
4847 ADD_MESSAGE("\"I thank you for your little gift%s.\"", Accepted == 1 ? "" : "s");
4849 if(RefusedSomething)
4850 ADD_MESSAGE("\"Unfortunately I cannot carry any more of your gifts. I'm a delicate woman, you see.\"");
4853 void guard::BeTalkedTo()
4855 itemvector Item;
4857 if(!PLAYER->SelectFromPossessions(Item, CONST_S("Do you have something to give me?"), 0, &item::IsBeverage)
4858 || Item.empty())
4859 humanoid::BeTalkedTo();
4861 for(unsigned int c = 0; c < Item.size(); ++c)
4863 Item[c]->RemoveFromSlot();
4864 GetStack()->AddItem(Item[c]);
4869 void denim::GetAICommand () {
4870 int Enemies = 0;
4871 for (int c = 0; c < game::GetTeams(); ++c) {
4872 if (GetTeam()->GetRelation(game::GetTeam(c)) == HOSTILE) Enemies += game::GetTeam(c)->GetEnabledMembers();
4874 StandIdleAI();
4878 v2 wisefarmer::GetHeadBitmapPos () const { return v2(96, (4 + (RAND() & 1)) << 4); }
4879 v2 wisefarmer::GetRightArmBitmapPos () const { return v2(64, (RAND() & 1) << 4); }
4881 void wisefarmer::GetAICommand () {
4882 int Enemies = 0;
4883 for (int c = 0; c < game::GetTeams(); ++c) {
4884 if (GetTeam()->GetRelation(game::GetTeam(c)) == HOSTILE) Enemies += game::GetTeam(c)->GetEnabledMembers();
4886 StandIdleAI();
4890 void raven::GetAICommand () {
4891 int Enemies = 0;
4892 for (int c = 0; c < game::GetTeams(); ++c) {
4893 if (GetTeam()->GetRelation(game::GetTeam(c)) == HOSTILE) Enemies += game::GetTeam(c)->GetEnabledMembers();
4895 StandIdleAI();
4899 void vulcan::GetAICommand () {
4900 int Enemies = 0;
4901 for (int c = 0; c < game::GetTeams(); ++c) {
4902 if (GetTeam()->GetRelation(game::GetTeam(c)) == HOSTILE) Enemies += game::GetTeam(c)->GetEnabledMembers();
4904 StandIdleAI();
4908 truth rogue::IsRetreating () const {
4909 if (humanoid::IsRetreating()) return true;
4910 for (stackiterator i = GetStack()->GetBottom(); i.HasItem(); ++i) if ((*i)->GetSparkleFlags()) return true;
4911 return false;
4915 void rogue::GetAICommand () {
4916 if (!IsRetreating()) {
4917 character *Char = GetRandomNeighbour();
4918 if (Char) {
4919 itemvector Sparkling;
4920 for (stackiterator i = Char->GetStack()->GetBottom(); i.HasItem(); ++i) {
4921 if ((*i)->GetSparkleFlags() && !MakesBurdened((*i)->GetWeight())) Sparkling.push_back(*i);
4923 if (!Sparkling.empty()) {
4924 item *ToSteal = Sparkling[RAND() % Sparkling.size()];
4925 ToSteal->RemoveFromSlot();
4926 GetStack()->AddItem(ToSteal);
4927 if (Char->IsPlayer()) ADD_MESSAGE("%s steals your %s.", CHAR_NAME(DEFINITE), ToSteal->CHAR_NAME(UNARTICLED));
4928 EditAP(-500);
4929 return;
4933 humanoid::GetAICommand();
4937 void assassin::BeTalkedTo () {
4938 if (GetRelation(PLAYER) == HOSTILE) {
4939 if (PLAYER->GetMoney() >= 1500) {
4940 ADD_MESSAGE("%s talks: \"If you shell out 1500 gold pieces I'll join your side\"", CHAR_DESCRIPTION(DEFINITE));
4941 if (game::TruthQuestion(CONST_S("Do you want to bribe him? [y/N]"))) {
4942 PLAYER->SetMoney(PLAYER->GetMoney()-1500);
4943 ChangeTeam(PLAYER->GetTeam());
4944 RemoveHomeData();
4946 } else {
4947 ADD_MESSAGE("\"Trying to reason me with diplomancy won't work on me.\"");
4953 ///////////////////////////////////////////////////////////////////////////////
4954 petrus::petrus () : LastHealed(0) {
4955 game::SetPetrus(this);
4959 petrus::~petrus () {
4960 game::SetPetrus(0);
4964 void petrus::FinalProcessForBone () {
4965 humanoid::FinalProcessForBone();
4966 LastHealed = 0;
4970 truth petrus::HealFully (character *ToBeHealed) {
4971 truth DidSomething = false;
4972 for (int c = 0; c < ToBeHealed->GetBodyParts(); ++c) {
4973 if (!ToBeHealed->GetBodyPart(c)) {
4974 bodypart* BodyPart = 0;
4975 for (std::list<uLong>::const_iterator i = ToBeHealed->GetOriginalBodyPartID(c).begin(); i != ToBeHealed->GetOriginalBodyPartID(c).end(); ++i) {
4976 BodyPart = static_cast<bodypart *>(ToBeHealed->SearchForItem(*i));
4977 if (BodyPart) break;
4979 if (!BodyPart || !BodyPart->CanRegenerate()) continue;
4980 BodyPart->RemoveFromSlot();
4981 ToBeHealed->AttachBodyPart(BodyPart);
4982 BodyPart->RestoreHP();
4983 DidSomething = true;
4984 if (ToBeHealed->IsPlayer())
4985 ADD_MESSAGE("%s attaches your old %s back and heals it.", CHAR_NAME(DEFINITE), BodyPart->GetBodyPartName().CStr());
4986 else if (CanBeSeenByPlayer())
4987 ADD_MESSAGE("%s attaches the old %s of %s back and heals it.", CHAR_NAME(DEFINITE), BodyPart->GetBodyPartName().CStr(), ToBeHealed->CHAR_DESCRIPTION(DEFINITE));
4990 if (ToBeHealed->IsInBadCondition()) {
4991 ToBeHealed->RestoreLivingHP();
4992 DidSomething = true;
4993 if (ToBeHealed->IsPlayer())
4994 ADD_MESSAGE("%s heals you fully.", CHAR_DESCRIPTION(DEFINITE));
4995 else if (CanBeSeenByPlayer())
4996 ADD_MESSAGE("%s heals %s fully.", CHAR_DESCRIPTION(DEFINITE), ToBeHealed->CHAR_DESCRIPTION(DEFINITE));
4998 if (ToBeHealed->TemporaryStateIsActivated(POISONED)) {
4999 ToBeHealed->DeActivateTemporaryState(POISONED);
5000 DidSomething = true;
5001 if (ToBeHealed->IsPlayer())
5002 ADD_MESSAGE("%s removes the foul poison in your body.", CHAR_DESCRIPTION(DEFINITE));
5003 else if (CanBeSeenByPlayer())
5004 ADD_MESSAGE("%s removes the foul poison in %s's body.", CHAR_DESCRIPTION(DEFINITE), ToBeHealed->CHAR_DESCRIPTION(DEFINITE));
5006 if (DidSomething) {
5007 LastHealed = game::GetTick();
5008 DexterityAction(10);
5009 return true;
5011 return false;
5015 void petrus::Save (outputfile &SaveFile) const {
5016 humanoid::Save(SaveFile);
5017 SaveFile << LastHealed;
5021 void petrus::Load (inputfile &SaveFile) {
5022 humanoid::Load(SaveFile);
5023 SaveFile >> LastHealed;
5024 game::SetPetrus(this);
5028 void petrus::GetAICommand () {
5029 int Enemies = 0;
5030 for (int c = 0; c < game::GetTeams(); ++c) {
5031 if (GetTeam()->GetRelation(game::GetTeam(c)) == HOSTILE) Enemies += game::GetTeam(c)->GetEnabledMembers();
5034 if (Enemies && !RAND_N(250 / Min(Enemies, 50))) {
5035 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s shouts a magnificent prayer to Valpurus.", CHAR_NAME(DEFINITE));
5036 angel *Angel = angel::Spawn(VALPURUS);
5037 Angel->SetLifeExpectancy(10000, 0);
5038 v2 Where = GetLevel()->GetNearestFreeSquare(Angel, GetPos());
5039 if (Where == ERROR_V2) Where = GetLevel()->GetRandomSquare(Angel);
5040 Angel->SetTeam(GetTeam());
5041 Angel->PutTo(Where);
5042 if (Angel->CanBeSeenByPlayer()) ADD_MESSAGE("%s materializes.", Angel->CHAR_NAME(INDEFINITE));
5043 EditAP(-1000);
5044 return;
5047 if (HP << 1 < MaxHP && (GetPos() - v2(28, 20)).GetLengthSquare() > 400 && !RAND_N(10)) {
5048 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s disappears.", CHAR_NAME(DEFINITE));
5049 GetLevel()->GetLSquare(28, 20)->KickAnyoneStandingHereAway();
5050 Move(v2(28, 20), true);
5051 EditAP(-1000);
5052 return;
5055 if (!LastHealed || game::GetTick()-LastHealed > 16384) {
5056 for (int d = 0; d < GetNeighbourSquares(); ++d) {
5057 square *Square = GetNeighbourSquare(d);
5058 if (Square) {
5059 character *Char = Square->GetCharacter();
5060 if (Char && GetRelation(Char) == FRIEND && HealFully(Char)) return;
5065 StandIdleAI();
5069 void petrus::CreateCorpse (lsquare *Square) {
5070 if (game::GetStoryState() == 2) game::GetTeam(ATTNAM_TEAM)->SetRelation(game::GetTeam(PLAYER_TEAM), FRIEND);
5071 Square->AddItem(leftnutofpetrus::Spawn());
5072 SendToHell();
5076 void petrus::BeTalkedTo () {
5077 if (GetRelation(PLAYER) == HOSTILE) {
5078 ADD_MESSAGE("Heretic! Dev/null is a place not worthy to receive thee!");
5079 return;
5082 if (PLAYER->HasGoldenEagleShirt()) {
5083 ADD_MESSAGE("Petrus smiles. \"Thou hast defeated Oree! Mayst thou be blessed by Valpurus for the rest of thy life! And thou possess the Shirt of the Golden Eagle, the symbol of Our status! Return it now, please.\"");
5084 if (game::TruthQuestion(CONST_S("Will you give the Shirt of the Golden Eagle to Petrus? [y/n]"), REQUIRES_ANSWER)) {
5085 game::TextScreen(CONST_S(
5086 "The Holy Shirt is returned to its old owner and you kneel down to receive your reward.\n"
5087 "Petrus taps your shoulder with the Justifier and raises you to nobility."));
5088 if (true || game::TruthQuestion(CONST_S("Do you want to become a duke? [y/n]"), REQUIRES_ANSWER)) {
5089 game::TextScreen(CONST_S(
5090 "Later you receive a small dukedom in the middle of tundra\n"
5091 "where you rule with justice till the end of your content life.\n\n"
5092 "You are victorious!"));
5093 game::GetCurrentArea()->SendNewDrawRequest();
5094 game::DrawEverything();
5095 PLAYER->ShowAdventureInfo();
5096 festring Msg = CONST_S("retrieved the Shirt of the Golden Eagle and was raised to nobility");
5097 AddScoreEntry(Msg, 4, false);
5098 game::End(Msg);
5099 } else {
5100 GetArea()->SendNewDrawRequest();
5102 return;
5104 ADD_MESSAGE("Petrus's face turns red. \"I see. Thy greed hath overcome thy wisdom. Then, we shall fight for the shiny shirt. May Valpurus bless him who is better.\"");
5105 /* And now we actually make his face change color ;-) */
5106 GetHead()->GetMainMaterial()->SetSkinColor(MakeRGB16(255, 75, 50));
5107 GetHead()->UpdatePictures();
5108 SendNewDrawRequest();
5109 game::AskForEscPress(CONST_S("You are attacked!"));
5110 PLAYER->GetTeam()->Hostility(GetTeam());
5111 game::SetStoryState(2);
5112 return;
5115 if (PLAYER->HasHeadOfElpuri()) {
5116 game::TextScreen(CONST_S(
5117 "You have slain Elpuri, and Petrus grants you the freedom you desire.\n"
5118 "You spend the next months in Attnam as an honored hero."));
5119 if (true || game::TruthQuestion(CONST_S("Do you want to sail beyond the sunset? [y/n]"), REQUIRES_ANSWER)) {
5120 game::TextScreen(CONST_S(
5121 "When the sea finally melts, you board the first ship,\n"
5122 "leaving your past forever behind.\n\n"
5123 "You are victorious!"));
5124 game::GetCurrentArea()->SendNewDrawRequest();
5125 game::DrawEverything();
5126 PLAYER->ShowAdventureInfo();
5127 festring Msg = CONST_S("defeated Elpuri and continued to further adventures");
5128 AddScoreEntry(Msg, 2, false);
5129 game::End(Msg);
5130 } else {
5131 GetArea()->SendNewDrawRequest();
5133 return;
5136 if (!game::GetStoryState()) {
5137 if (PLAYER->RemoveEncryptedScroll()) {
5138 game::TextScreen(CONST_S(
5139 "You kneel down and bow before the high priest and hand him the encrypted scroll.\n"
5140 "Petrus raises his arm, the scroll glows yellow, and lo! The letters are clear and\n"
5141 "readable. Petrus asks you to voice them aloud. The first two thousand words praise\n"
5142 "Valpurus the Creator and all His manifestations and are followed by a canticle of\n"
5143 "Saint Petrus the Lion-Hearted lasting roughly three thousand words. Finally there\n"
5144 "are some sentences actually concerning your mission:\n\n"
5145 "\"Alas, I fear dirty tongues have spread lies to my Lord's ears. I assure all tales\n"
5146 "of treasures here in New Attnam are but mythic legends. There is nothing of value here.\n"
5147 "The taxes are already an unbearable burden and I can't possibly pay more. However I do\n"
5148 "not question the wisdom of the government's decisions. I will contribute what I can:\n"
5149 "the ostriches will deliver an extra 10000 bananas to the capital and additionally the\n"
5150 "slave that brought the message will henceforth be at Your disposal. I am certain this\n"
5151 "satisfies the crown's needs.\"\n\n"
5152 "\"Yours sincerely,\n"
5153 "Richel Decos, the viceroy of New Attnam\""));
5154 game::TextScreen(CONST_S(
5155 "You almost expected the last bit. Petrus seems to be deep in his thoughts and you\n"
5156 "wonder what shape your destiny is taking in his mind. Suddenly he seems to return\n"
5157 "to this reality and talks to you.\n\n"
5158 "\"Oh, thou art still here. We were just discussing telepathically with Sir Galladon.\n"
5159 "We started doubting Decos's alleged poverty a while back when he bought a couple of\n"
5160 "medium-sized castles nearby. Thy brethren from New Attnam have also told Us about\n"
5161 "vast riches seized from them. Our law says all such stolen valuables belong to\n"
5162 "the Cathedral's treasury, so this is a severe claim. However, proof is needed,\n"
5163 "and even if such was provided, We couldn't send soldiers over the snow fields\n"
5164 "ere spring.\""));
5165 if (game::GetLiberator()) {
5166 //TODO: do something?
5167 game::TextScreen(CONST_S(
5168 "\"Thy brethren from New Attnam have also told Us that Decos dies while sleeping.\n"
5169 "While We are sad to hear this, We hope that We shall not be forced to send our\n"
5170 "soldiers to New Attnam. We are sure that Our people there will work even better now.\""));
5172 game::TextScreen(CONST_S(
5173 "\"However, since thou now servest Us, We ought to find thee something to do. Sir\n"
5174 "Galladon hath told Us his agents witnessed thou leaving the dreaded underwater tunnel.\n"
5175 "This means thou most likely hast defeated genetrix vesana and art a talented warrior.\n"
5176 "We happen to have a task perfect for such a person. An evil dark frog named Elpuri who\n"
5177 "hates Valpurus and Attnam more than anything hath taken control over an abandoned mine\n"
5178 "nearby. It is pestering our fine city in many ways and reconnaissance has reported an\n"
5179 "army of monsters gathering in the cave. Our guards are not trained to fight underground\n"
5180 "and We dare not send them. To make things worse, someone hath recently stolen Us the\n"
5181 "greatest armor in existence - the Shirt of the Golden Eagle. Elpuri cannot wear\n"
5182 "it but he who can is now nearly immortal.\"\n\n"
5183 "\"We have marked the location of the gloomy cave on thy world map. We want you to dive\n"
5184 "into it and slay the vile frog. Bring Us its head and We reward thee with freedom.\n"
5185 "Shouldst thou also find the Shirt, We'll knight thee. Good luck, and return when\n"
5186 "thou hast succeeded.\""));
5187 game::LoadWorldMap();
5188 v2 ElpuriCavePos = game::GetWorldMap()->GetEntryPos(0, ELPURI_CAVE);
5189 game::GetWorldMap()->GetWSquare(ElpuriCavePos)->ChangeOWTerrain(elpuricave::Spawn());
5190 game::GetWorldMap()->RevealEnvironment(ElpuriCavePos, 1);
5191 game::SaveWorldMap();
5192 GetArea()->SendNewDrawRequest();
5193 ADD_MESSAGE("\"And by the way, visit the librarian. He might have advice for thee.\"");
5194 game::SetStoryState(1);
5195 } else {
5196 ADD_MESSAGE("\"Yes, citizen? We are quite busy now, thou shalt not disturb Us without proper cause.\"");
5198 return;
5200 /* StoryState == 1 */
5201 ADD_MESSAGE("Petrus says: \"Bring me the head of Elpuri and we'll talk.\"");
5205 truth petrus::MoveTowardsHomePos () {
5206 if (GetPos() != v2(28, 20)) {
5207 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s disappears.", CHAR_NAME(DEFINITE));
5208 GetLevel()->GetLSquare(28, 20)->KickAnyoneStandingHereAway();
5209 Move(v2(28, 20), true);
5210 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s appears.", CHAR_NAME(DEFINITE));
5211 EditAP(-1000);
5212 return true;
5214 return false;
5218 ///////////////////////////////////////////////////////////////////////////////
5219 void raven::BeTalkedTo () {
5220 if (GetRelation(PLAYER) == HOSTILE) {
5221 ADD_MESSAGE("I bet you are with those filthy Attnamanese bastards!");
5222 return;
5224 if (!game::GetRingOfThieves()) {
5225 if (PLAYER->RemoveRingOfThieves()) {
5226 game::TextScreen(CONST_S(
5227 "You hand over the Ring of Thieves, Raven's eyes glow in amazement.\n"
5228 "\"May Cleptia bless this mighty warrior, whom vanquished Vulcan-Loki!\n"
5229 "Retrieving the ring is no easy task, Vulcan is a powerful adversary.\n"
5230 "The importance of the Ring of Thieves is great. It is used to channel\n"
5231 "Cleptia's power to help Mondedr avoid it's enemies, including Petrus.\n"
5232 "Without it we would have been raided by every nation that hates us.\n"
5233 "Not a mere mortal like Vulcan-Loki could channel the ring's power for\n"
5234 "himself so he decided to contract a deal with Oree to assist him.\n"
5235 "To reward your efforts I will give you the artifact whip, Gleipnir.\"\n\n"
5236 "\"I pray to Cleptia that you will use it well..\"\n\n"""));
5237 game::GetGod(CLEPTIA)->AdjustRelation(500);
5238 game::GetGod(NEFAS)->AdjustRelation(50);
5239 game::GetGod(SCABIES)->AdjustRelation(50);
5240 game::GetGod(INFUSCOR)->AdjustRelation(50);
5241 game::GetGod(CRUENTUS)->AdjustRelation(50);
5242 game::GetGod(MORTIFER)->AdjustRelation(50);
5243 meleeweapon *Weapon = whipofthievery::Spawn();
5244 Weapon->InitMaterials(MAKE_MATERIAL(SPIDER_SILK), MAKE_MATERIAL(EBONY_WOOD), true);
5245 PLAYER->GetGiftStack()->AddItem(Weapon);
5246 GetArea()->SendNewDrawRequest();
5247 ADD_MESSAGE("A whip materializes near your feet.");
5248 game::SetRingOfThieves(1);
5249 } else {
5250 ADD_MESSAGE("\"Mondedr's most important artifact, the Ring of Thieves, has been stolen by Vulcan-Loki; residing at the deepest floor of the underground temple, he awaits Oree to receive it and reward him with incredible power.\"");
5252 } else {
5253 /* StoryState == 100 */
5254 ADD_MESSAGE("\"I must thank you again, I hope you make good use of that whip.\"");
5259 ///////////////////////////////////////////////////////////////////////////////
5260 void mysteryman::BeTalkedTo () {
5261 if (GetRelation(PLAYER) == HOSTILE) {
5262 ADD_MESSAGE("This is why the government doesn't mess with me, fool!");
5263 return;
5265 if (!game::GetMondedrPass()) {
5266 if (PLAYER->RemoveMondedrPass()) {
5267 game::TextScreen(CONST_S(
5268 "You hand over the mondedr pass,\n"
5269 "the man quickly snatches it and starts reading it right away.\n"
5270 "The man scans the text very quickly, his eyes run around a hundred laps per second.\n"
5271 "His eyes come to a halt.\n"
5272 "\"I have revealed the location of Mondedr.\" He hands you a map.\n"
5273 "\"It is a good thing I was born in this world, no? You owe me nothing, the \n"
5274 "the amount of information in the sheet of paper is what repays it.\"\n\n"""));
5275 game::LoadWorldMap();
5276 v2 MondedrPos = game::GetWorldMap()->GetEntryPos(0, MONDEDR);
5277 game::GetWorldMap()->GetWSquare(MondedrPos)->ChangeOWTerrain(mondedr::Spawn());
5278 game::GetWorldMap()->RevealEnvironment(MondedrPos, 1);
5279 game::SaveWorldMap();
5280 GetArea()->SendNewDrawRequest();
5281 ADD_MESSAGE("\"And by the way, the government always watches you.\"");
5282 game::SetMondedrPass(1);
5283 } else {
5284 ADD_MESSAGE("\"Shoo, come back if you have a sheet of paper they call 'Mondedr Pass'\"");
5286 } else {
5287 /* StoryState == 100 */
5288 ADD_MESSAGE("The man says: \"I don't have anymore business with you, shoo.\"");
5293 ///////////////////////////////////////////////////////////////////////////////
5294 void imperialist::BeTalkedTo () {
5295 decosadshirt *Shirt = static_cast<decosadshirt *>(PLAYER->SearchForItem(this, &item::IsDecosAdShirt));
5296 if (Shirt) {
5297 uLong Reward = Shirt->GetEquippedTicks()/500;
5298 if (Reward) {
5299 ADD_MESSAGE("%s smiles. \"I see you have advertised our company diligently. Here's %dgp as a token of my gratitude.\"", CHAR_NAME(DEFINITE), Reward);
5300 PLAYER->EditMoney(Reward);
5301 Shirt->SetEquippedTicks(0);
5302 } else if (!(RAND()%5)) {
5303 ADD_MESSAGE("\"Come back when you've worn the shirt for some time and I'll reward you generously!\"");
5305 return;
5307 static sLong Said;
5308 if (GetRelation(PLAYER) == HOSTILE)
5309 ProcessAndAddMessage(GetHostileReplies()[RandomizeReply(Said, GetHostileReplies().Size)]);
5310 else if (!game::PlayerIsSumoChampion())
5311 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said, GetFriendlyReplies().Size)]);
5312 else
5313 ProcessAndAddMessage(GetFriendlyReplies()[RandomizeReply(Said, GetFriendlyReplies().Size-1)]);
5317 void imperialist::DisplayStethoscopeInfo (character *) const {
5318 ADD_MESSAGE("You hear coins clinking inside.");
5322 void imperialist::CreateCorpse (lsquare *Square) {
5323 if (!game::GetLiberator()) {
5324 game::SetLiberator(1);
5325 ADD_MESSAGE("You liberate citizens of New Attnam!");
5327 imperialistsysbase::CreateCorpse(Square);
5331 ///////////////////////////////////////////////////////////////////////////////
5332 exiledpriest::exiledpriest () :
5333 exiledpriestsysbase(),
5334 mAtHome(false)
5339 exiledpriest::~exiledpriest () {
5343 void exiledpriest::Save (outputfile &saveFile) const {
5344 priest::Save(saveFile);
5345 saveFile << mAtHome;
5349 void exiledpriest::Load (inputfile &saveFile) {
5350 priest::Load(saveFile);
5351 saveFile >> mAtHome;
5355 void exiledpriest::healBodyParts () {
5356 for (int c = 0; c < PLAYER->GetBodyParts(); ++c) {
5357 if (!PLAYER->GetBodyPart(c) && PLAYER->CanCreateBodyPart(c)) {
5358 truth HasOld = false;
5359 for (std::list<uLong>::const_iterator i = PLAYER->GetOriginalBodyPartID(c).begin(); i != PLAYER->GetOriginalBodyPartID(c).end(); ++i) {
5360 bodypart *OldBodyPart = static_cast<bodypart *>(PLAYER->SearchForItem(*i));
5361 if (OldBodyPart) {
5362 HasOld = true;
5363 if (!OldBodyPart->CanRegenerate())
5364 ADD_MESSAGE("\"Sorry, I cannot put back bodyparts made of %s, not even your severed %s.\"", OldBodyPart->GetMainMaterial()->GetName(false, false).CStr(), PLAYER->GetBodyPartName(c).CStr());
5365 else {
5366 ADD_MESSAGE("\"I will put your old %s back.\"", PLAYER->GetBodyPartName(c).CStr());
5367 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5368 OldBodyPart->SetHP(1);
5369 OldBodyPart->RemoveFromSlot();
5370 PLAYER->AttachBodyPart(OldBodyPart);
5371 healBodyParts(); //FIXME
5372 return;
5377 if (HasOld)
5378 ADD_MESSAGE("\"I could summon up a new %s.\"", PLAYER->GetBodyPartName(c).CStr());
5379 else
5380 ADD_MESSAGE("\"Since you don't seem to have your original %s with you, I could summon up a new one.\"", PLAYER->GetBodyPartName(c).CStr());
5381 if (game::TruthQuestion(CONST_S("Agreed? [y/N]"))) {
5382 PLAYER->CreateBodyPart(c);
5383 PLAYER->GetBodyPart(c)->SetHP(1);
5384 healBodyParts(); //FIXME
5385 return;
5392 void exiledpriest::healDeseases () {
5393 if (PLAYER->TemporaryStateIsActivated(POISONED)) {
5394 ADD_MESSAGE("\"You seem to be rather ill. I could give you a small dose of antidote.\"");
5395 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5396 ADD_MESSAGE("You feel better.");
5397 PLAYER->DeActivateTemporaryState(POISONED);
5400 if (PLAYER->TemporaryStateIsActivated(PARASITIZED)) {
5401 ADD_MESSAGE("\"You seem to have something inside you. I could give you a small dose of antidote.\"");
5402 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5403 ADD_MESSAGE("You feel better.");
5404 PLAYER->DeActivateTemporaryState(PARASITIZED);
5407 if (PLAYER->TemporaryStateIsActivated(LEPROSY)) {
5408 ADD_MESSAGE("\"You seem to have contracted the vile disease of leprosy. I could give you a small dose of medicince.\"");
5409 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5410 ADD_MESSAGE("You feel better.");
5411 PLAYER->DeActivateTemporaryState(LEPROSY);
5414 if (PLAYER->TemporaryStateIsActivated(LYCANTHROPY)) {
5415 ADD_MESSAGE("\"You seem to be turning into a werewolf quite frequently. Well, everyone has right to little secret habits, but I could pray %s to remove the canine blood from your veins, just so you don't scare our blessed youth.\"", GetMasterGod()->GetName());
5416 if (game::TruthQuestion(CONST_S("Do you agree? [y/N]"))) {
5417 ADD_MESSAGE("You feel better.");
5418 PLAYER->DeActivateTemporaryState(LYCANTHROPY);
5424 void exiledpriest::healAll () {
5425 healBodyParts();
5426 healDeseases();
5430 //FIXME: GENDER!
5431 void exiledpriest::BeTalkedTo () {
5432 if (GetRelation(PLAYER) != HOSTILE && game::GetLiberator()) {
5433 if (!mAtHome) {
5434 ADD_MESSAGE(
5435 "Priestess says: "
5436 "\"Let %s bless you! I can return to my temple now! "
5437 "Get this things and remember how kind %s is!\"",
5438 GetMasterGod()->GetName(), GetMasterGod()->GetName());
5439 //GetMasterGod()->GetObjectPronoun());
5440 mAtHome = true;
5441 //GetGiftStack()
5443 potion *bottle = potion::Spawn(0, NO_MATERIALS);
5444 bottle->InitMaterials(MAKE_MATERIAL(GLASS), MAKE_MATERIAL(HEALING_LIQUID));
5445 PLAYER->GetStack()->AddItem(bottle);
5446 ADD_MESSAGE("Priestess gives %s to you.", bottle->CHAR_DESCRIPTION(DEFINITE));
5449 potion *bottle = potion::Spawn(0, NO_MATERIALS);
5450 bottle->InitMaterials(MAKE_MATERIAL(GLASS), MAKE_MATERIAL(ANTIDOTE_LIQUID));
5451 PLAYER->GetStack()->AddItem(bottle);
5452 ADD_MESSAGE("Priestess gives %s to you.", bottle->CHAR_DESCRIPTION(DEFINITE));
5454 if (RAND_N(100) >= 90) {
5455 potion *bottle = potion::Spawn(0, NO_MATERIALS);
5456 bottle->InitMaterials(MAKE_MATERIAL(GLASS), MAKE_MATERIAL(VODKA));
5457 PLAYER->GetStack()->AddItem(bottle);
5458 ADD_MESSAGE("Priestess gives %s to you.", bottle->CHAR_DESCRIPTION(DEFINITE));
5461 ADD_MESSAGE("I will heal you for free.");
5462 healAll();
5463 return;
5465 priest::BeTalkedTo();
5469 truth exiledpriest::MoveTowardsHomePos () {
5470 if (!mAtHome) return false;
5471 v2 homePos(12, 10);
5472 if (GetPos() != homePos) {
5473 SetGoingTo(homePos);
5474 return MoveTowardsTarget(false) || (!GetPos().IsAdjacent(homePos) && MoveRandomly());
5476 return false;
5480 void exiledpriest::GetAICommand () {
5481 priest::GetAICommand();