3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
8 * See LICENSING which should be included
9 * along with this file for more details
13 /* Compiled through godset.cpp */
15 godprototype::godprototype (godspawner Spawner
, cchar
* ClassID
) : Spawner(Spawner
), ClassID(ClassID
) { Index
= protocontainer
<god
>::Add(this); }
17 god::god() : Relation(0), LastPray(-1), Timer(0), Known(false) { }
18 int god::GetBasicAlignment() const { return NEUTRAL
; }
20 cchar
*god::GetPersonalPronoun () const { return (GetSex() == MALE
? "He" : "She"); }
21 cchar
*god::GetObjectPronoun () const { return (GetSex() == MALE
? "Him" : "Her"); }
27 if (Relation
>= -RAND_N(500)) {
28 ADD_MESSAGE("You feel %s is pleased.", GetName());
30 if (!TryToAttachBodyPart(PLAYER
) && !TryToHardenBodyPart(PLAYER
)) PrayGoodEffect();
34 game::ApplyDivineAlignmentBonuses(this, 10, true);
35 PLAYER
->EditExperience(WISDOM
, 200, 1<<10);
37 if (Relation
> 250 && !(RAND()%20)) {
38 character
*Angel
= CreateAngel(PLAYER
->GetTeam(), 10000);
39 if (Angel
) ADD_MESSAGE("%s seems to be very friendly towards you.", Angel
->CHAR_DESCRIPTION(DEFINITE
));
40 } else if (Relation
> 100 && !(RAND()%20)) {
41 sLong Category
= RAND()&ANY_CATEGORY
;
42 if (!Category
) Category
= ANY_CATEGORY
;
43 item
*Gift
= protosystem::BalancedCreateItem(0, Relation
/2, Relation
*2, Category
, 0, 0, GetType());
46 Gift
->CalculateEnchantment();
47 PLAYER
->GetStack()->AddItem(Gift
);
49 if (Gift
->IsBroken()) Gift
= Gift
->Fix();
50 if (Relation
== 1000) Gift
->EditEnchantment(3);
51 else if (Relation
>= 500) Gift
->EditEnchantment(2);
52 else Gift
->EditEnchantment(1);
54 ADD_MESSAGE("You notice %s in your inventory which you don't recall picking up anywhere.", Gift
->CHAR_NAME(INDEFINITE
));
58 ADD_MESSAGE("You feel %s is displeased today.", GetName());
62 game::ApplyDivineAlignmentBonuses(this, 10, false);
63 PLAYER
->EditExperience(WISDOM
, -50, 1<<10);
66 if (Relation
> RAND_N(500) && Timer
< RAND_N(500000)) {
67 ADD_MESSAGE("You feel %s is displeased, but tries to help you anyway.", GetName());
68 if (!TryToAttachBodyPart(PLAYER
) && !TryToHardenBodyPart(PLAYER
)) PrayGoodEffect();
71 game::ApplyDivineAlignmentBonuses(this, 15, false);
72 PLAYER
->EditExperience(WISDOM
, -50, 1<<10);
74 ADD_MESSAGE("You feel %s is angry.", GetName());
78 game::ApplyDivineAlignmentBonuses(this, 20, false);
79 PLAYER
->EditExperience(WISDOM
, -100, 1<<11);
80 if (Relation
< -250 && !(RAND()%5)) {
81 character
* Angel
= CreateAngel(game::GetTeam(4), 10000);
82 if (Angel
) ADD_MESSAGE("%s seems to be hostile.", Angel
->CHAR_DESCRIPTION(DEFINITE
));
89 festring
god::GetCompleteDescription () const {
90 festring
Desc(game::GetAlignment(GetAlignment()));
95 if (game::WizardModeIsActive()) {
96 Desc
<< "Timer: " << Timer
<< " Relation: " << Relation
;
103 int Hour
= LastPray
/2000;
106 int Min
= LastPray
%2000*60/2000;
107 Desc
<< "last prayed ";
109 Desc
<< "over a week ago.";
111 if (Day
> 1) Desc
<< Day
<< " days, ";
112 else if (Day
) Desc
<< "one day, ";
113 if (Hour
> 1) Desc
<< Hour
<< " hours, ";
114 else if (Hour
) Desc
<< "one hour, ";
115 if (Day
|| Hour
) Desc
<< "and " << Min
<< " minutes ago.";
116 else Desc
<< Min
<< " minutes ago.";
119 Desc
<< "never prayed to this god.";
125 void god::AdjustRelation (god
*Competitor
, int Multiplier
, truth Good
) {
126 int Adjustment
= (Multiplier
<<1)-abs(GetAlignment()-Competitor
->GetAlignment())*Multiplier
;
127 if (!Good
&& Adjustment
> 0) Adjustment
= -Adjustment
;
128 AdjustRelation(Adjustment
);
132 void god::AdjustRelation (int Amount
) {
134 Amount
= Amount
*100/(100+PLAYER
->GetAttribute(WISDOM
));
136 Amount
= Amount
*(100+PLAYER
->GetAttribute(WISDOM
))/100;
141 if (Relation
< -1000) Relation
= -1000;
142 if (Relation
> 1000) Relation
= 1000;
146 void god::AdjustTimer (sLong Amount
) {
148 if (Timer
< 0) Timer
= 0;
149 if (Timer
> 1000000000) Timer
= 1000000000;
153 truth
god::PlayerVomitedOnAltar (liquid
*Liquid
) {
154 if (PLAYER
->GetVirtualHead()) {
155 ADD_MESSAGE("The vomit drops on the altar, but then suddenly gravity changes its direction. The vomit lands on your face.");
156 PLAYER
->GetVirtualHead()->SpillFluid(0, Liquid
);
157 PLAYER
->ReceiveDamage(0, 1+(RAND()&1), ACID
, HEAD
);
159 ADD_MESSAGE("The vomit drops on the altar, but then suddenly gravity changes its direction. The vomit lands all over you.");
160 PLAYER
->SpillFluid(0, Liquid
);
161 PLAYER
->ReceiveDamage(0, 1+(RAND()&1), ACID
);
164 AdjustRelation(-200);
165 PLAYER
->CheckDeath(CONST_S("killed by a flying lump of vomit"), 0);
168 character
*Angel
= CreateAngel(game::GetTeam(4), 10000);
169 if (Angel
) ADD_MESSAGE("%s seems to be hostile.", Angel
->CHAR_DESCRIPTION(DEFINITE
));
176 character
*god::CreateAngel (team
*Team
, int LifeBase
) {
178 for (int c
= 0; c
< 100; ++c
) {
179 TryToCreate
= PLAYER
->GetPos()+game::GetMoveVector(RAND()%DIRECTION_COMMAND_KEYS
);
180 if (game::GetCurrentArea()->IsValidPos(TryToCreate
)) {
183 if (LifeBase
&& GetType() != VALPURUS
&& (!(RAND()%5) || abs(Relation
) == 1000)) {
184 Angel
= archangel::Spawn(GetType());
185 Angel
->SetLifeExpectancy(LifeBase
/10, 0);
187 Angel
= angel::Spawn(GetType());
188 if (LifeBase
) Angel
->SetLifeExpectancy(LifeBase
, 0);
191 lsquare
*Square
= game::GetCurrentLevel()->GetLSquare(TryToCreate
);
193 if (Angel
->CanMoveOn(Square
) && Angel
->IsFreeForMe(Square
)) {
194 Angel
->SetTeam(Team
);
195 Angel
->SetGenerationDanger(ANGEL_GENERATION_DANGER
);
196 Angel
->PutTo(TryToCreate
);
197 ADD_MESSAGE("Suddenly %s appears!", Angel
->CHAR_DESCRIPTION(INDEFINITE
));
209 void god::PrintRelation () const {
210 cchar
*VerbalRelation
;
211 int rel
= GetRelation();
213 if (rel
>= 1000) VerbalRelation
= "greets you as a Champion of the Cause!";
214 else if (rel
> 750) VerbalRelation
= "is extremely pleased.";
215 else if (rel
> 250) VerbalRelation
= "is very pleased.";
216 else if (rel
> 50) VerbalRelation
= "is pleased.";
217 else if (rel
> -50) VerbalRelation
= "is content.";
218 else if (rel
> -250) VerbalRelation
= "is angry.";
219 else if (rel
> -750) VerbalRelation
= "is very angry.";
220 else if (rel
>= -1000) VerbalRelation
= "is extremely angry.";
221 else VerbalRelation
= "hates you more than any other mortal.";
223 ADD_MESSAGE("%s %s", GetName(), VerbalRelation
);
227 truth
god::ReceiveOffer (item
*Sacrifice
) {
228 if (Sacrifice
->SpecialOfferEffect(GetType())) return true;
230 int OfferValue
= Sacrifice
->GetOfferValue(GetType());
233 if (!Sacrifice
->IsDestroyable(PLAYER
)) {
234 ADD_MESSAGE("%s is too important for you to be sacrificed.", Sacrifice
->CHAR_NAME(DEFINITE
));
238 AdjustRelation(OfferValue
);
240 game::ApplyDivineAlignmentBonuses(this, (OfferValue
>= 0 ? OfferValue
: -OfferValue
)/5, true);
242 if (OfferValue
> 0) {
243 PLAYER
->EditExperience(WISDOM
, 150, 1<<7);
245 PLAYER
->EditExperience(WISDOM
, -100, 1<<7);
248 if (OfferValue
> 0) {
249 if (Sacrifice
->GetAttachedGod() == GetType()) {
250 ADD_MESSAGE("%s appreciates your generous offer truly.", GetName());
252 ADD_MESSAGE("%s thanks you for your gift.", GetName());
255 ADD_MESSAGE("%s seems not to appreciate your gift at all.", GetName());
259 int RandModifier
= Sacrifice
->GetAttachedGod() == GetType() ? 50 : 100;
261 if (OfferValue
> 0 && Relation
> 250 && !(RAND()%RandModifier
)) {
262 character
*Angel
= CreateAngel(PLAYER
->GetTeam());
263 if (Angel
) ADD_MESSAGE("%s seems to be very friendly towards you.", Angel
->CHAR_DESCRIPTION(DEFINITE
));
269 ADD_MESSAGE("Nothing happens.");
274 god
*godprototype::SpawnAndLoad (inputfile
&SaveFile
) const {
275 god
*God
= Spawner();
281 truth
god::LikesMaterial (const materialdatabase
*MDB
, ccharacter
*) const {
282 return (MDB
->AttachedGod
== GetType());
286 struct materialsorter
{
287 materialsorter(citem
* Item
) : Item(Item
) {}
288 truth
operator () (cmaterial
*M1
, cmaterial
*M2
) const { return (M1
->GetHardenModifier(Item
) > M2
->GetHardenModifier(Item
)); }
293 truth
god::TryToAttachBodyPart (character
*Char
) {
294 msgsystem::EnterBigMessageMode();
296 if (!Char
->HasAllBodyParts()) {
297 bodypart
*BodyPart
= Char
->FindRandomOwnBodyPart(true);
299 if (BodyPart
&& LikesMaterial(BodyPart
->GetMainMaterial()->GetDataBase(), Char
)) {
300 BodyPart
->RemoveFromSlot();
301 Char
->AttachBodyPart(BodyPart
);
302 ADD_MESSAGE("%s attaches your old %s back.", GetName(), BodyPart
->GetBodyPartName().CStr());
305 materialvector MaterialVector
;
306 protosystem::CreateEveryMaterial(MaterialVector
, this, Char
);
307 std::sort(MaterialVector
.begin(), MaterialVector
.end(), materialsorter(0));
309 for (uInt c
= 0; c
< MaterialVector
.size(); ++c
) {
310 if (ForceGiveBodyPart() ||
311 ((MaterialVector
[c
]->GetCommonFlags()&CAN_BE_WISHED
) &&
312 !RAND_N(6000/(GetRelation()+2000)) &&
313 !RAND_N(Max(MaterialVector
[c
]->GetIntelligenceRequirement()-10, 1))))
315 BodyPart
= Char
->GenerateRandomBodyPart();
316 BodyPart
->ChangeMainMaterial(MaterialVector
[c
]->SpawnMore());
317 Char
->UpdatePictures();
320 if (!MaterialVector
[c
]->IsSameAs(Char
->GetTorso()->GetMainMaterial())) {
321 MadeOf
<< " made of ";
322 MaterialVector
[c
]->AddName(MadeOf
, false, false);
325 ADD_MESSAGE("%s gives you a new %s%s.", GetName(), BodyPart
->GetBodyPartName().CStr(), MadeOf
.CStr());
330 for (uInt c
= 0; c
< MaterialVector
.size(); ++c
) delete MaterialVector
[c
];
334 if (MutatesBodyParts()) {
336 ADD_MESSAGE("It seems somehow different.");
339 truth Heal
= !BodyPart
->CanRegenerate() || HealRegeneratingBodyParts();
340 BodyPart
->SetHP(Heal
? BodyPart
->GetMaxHP() : 1);
341 msgsystem::LeaveBigMessageMode();
346 msgsystem::LeaveBigMessageMode();
351 truth
god::TryToHardenBodyPart (character
*Char
) {
352 bodypart
*PossibleBodyPart
[MAX_BODYPARTS
];
355 for (uInt c
= 1; c
< uInt(Char
->GetBodyParts()); ++c
) { // annoying :(
356 bodypart
*BodyPart
= Char
->GetBodyPart(c
);
357 if (BodyPart
&& LikesMaterial(BodyPart
->GetMainMaterial()->GetDataBase(), Char
)) {
358 PossibleBodyPart
[Index
++] = BodyPart
;
362 if (Index
== 0) return false;
364 bodypart
*BodyPart
= PossibleBodyPart
[RAND_N(Index
)];
365 material
*OldMaterial
= BodyPart
->GetMainMaterial();
366 int OldModifier
= OldMaterial
->GetHardenModifier(BodyPart
);
368 materialvector MaterialVector
;
369 protosystem::CreateEveryMaterial(MaterialVector
, this, Char
);
370 std::sort(MaterialVector
.begin(), MaterialVector
.end(), materialsorter(BodyPart
));
371 truth Changed
= false;
373 for (uInt c
= 0; c
< MaterialVector
.size(); ++c
) {
374 if (MaterialVector
[c
]->GetCommonFlags()&CAN_BE_WISHED
) {
375 material
*Material
= MaterialVector
[c
];
376 if (Material
->GetHardenModifier(BodyPart
) > OldModifier
&&
377 !RAND_N(12000/(GetRelation()+2000)) &&
378 !RAND_N(Max(Material
->GetIntelligenceRequirement()-15, 1)))
380 BodyPart
->ChangeMainMaterial(Material
->SpawnMore());
381 ADD_MESSAGE("%s changes your %s to %s.", GetName(), BodyPart
->GetBodyPartName().CStr(), Material
->GetName(false, false).CStr());
388 for (uInt c
= 0; c
< MaterialVector
.size(); ++c
) delete MaterialVector
[c
];
394 void god::SignalRandomAltarGeneration (const std::vector
<v2
> &RoomSquare
) {
395 int Times
= 1+femath::LoopRoll(50, 4);
397 for (int c
= 0; c
< Times
; ++c
) {
398 sLong Category
= RAND()&ANY_CATEGORY
;
399 if (!Category
) Category
= ANY_CATEGORY
;
401 sLong MaxPrice
= 250+femath::LoopRoll(95, 500)*10;
402 item
*Item
= protosystem::BalancedCreateItem(0, 0, MaxPrice
, Category
, 0, 0, GetType());
405 Item
->CalculateEnchantment();
406 game::GetCurrentLevel()->GetLSquare(RoomSquare
[RAND_N(RoomSquare
.size())])->AddItem(Item
);
412 void god::Save (outputfile
&SaveFile
) const {
413 SaveFile
<< (uShort
)GetType();
414 SaveFile
<< Relation
<< Timer
<< Known
<< LastPray
;
418 void god::Load (inputfile
&SaveFile
) {
419 SaveFile
>> Relation
>> Timer
>> Known
>> LastPray
;
423 void god::ApplyDivineTick () {
424 if (Timer
> 0) --Timer
;
425 if (LastPray
> -1 && LastPray
< 336000) ++LastPray
;