save and bone files now can be compressed with ZLib (wow!)
[k8-i-v-a-n.git] / src / game / command.cpp
blob73c3286cb06f690af203a2a87178c7969cf532f1
1 /* *
2 * Iter Vehemens ad Necem (IVAN)
3 * Copyright (C) Timo Kiviluoto
4 * Released under the GNU General
5 * Public License
7 * See LICENSING which should be included
8 * along with this file for more details
11 #include <string.h>
12 #include <stdio.h>
14 #include "fesave.h"
15 #include "command.h"
16 #include "char.h"
17 #include "message.h"
18 #include "game.h"
19 #include "stack.h"
20 #include "room.h"
21 #include "god.h"
22 #include "felist.h"
23 #include "iconf.h"
24 #include "bitmap.h"
25 #include "actions.h"
26 #include "miscitem.h"
27 #include "worldmap.h"
28 #include "wsquare.h"
29 #include "wterras.h"
30 #include "materia.h"
31 #include "database.h"
32 #include "team.h"
34 #ifdef WIZARD
35 #include "proto.h"
36 #endif
39 /* k8 */
40 /* SLOOOOWWW! */
41 static void cstrTrim (char *buf) {
42 char *p = buf, *t;
43 while (*p && *((unsigned char *)(p)) <= ' ') p++;
44 if (!p[0]) { buf[0] = '\0'; return; } /* empty line */
45 if (p > buf) { t = buf; while (*p) *t++ = *p++; }
46 p = buf+strlen(buf)-1;
47 while (p >= buf && *((unsigned char *)(p)) <= ' ') p--;
48 if (p < buf) { buf[0] = '\0'; return; } /* empty line */
49 *(++p) = '\0';
53 command::command(truth (*LinkedFunction)(character *), cchar *Description, char Key1, char Key2, truth UsableInWilderness, truth WizardModeFunction) :
54 LinkedFunction(LinkedFunction),
55 Description(Description),
56 Key1(Key1), Key2(Key2),
57 UsableInWilderness(UsableInWilderness),
58 WizardModeFunction(WizardModeFunction)
63 char command::GetKey () const { return !ivanconfig::GetUseAlternativeKeys() ? Key1 : Key2; }
66 static const char *adirNames[9] = {
67 "dir-left-up",
68 "dir-up",
69 "dir-right-up",
70 "dir-left",
71 "dir-right",
72 "dir-left-down",
73 "dir-down",
74 "dir-right-down",
75 "dir-none"
79 /* k8 */
80 void commandsystem::ConfigureKeys () {
81 command *cmd;
82 char buf[512];
83 festring fname;
84 #ifdef LOCAL_SAVES
85 fname << ivanconfig::GetMyDir();
86 #else
87 fname << getenv("HOME");
88 #endif
89 fname << "/.keys.rc";
90 FILE *fl = fopen(fname.CStr(), "r");
91 if (!fl) return;
92 while (fgets(buf, 510, fl)) {
93 cstrTrim(buf);
94 char k1 = 0, k2 = 0, i1;
95 if (buf[0] == '=') {
96 i1 = 1;
97 } else if (buf[2] != '=') {
98 if (buf[1] != '=') continue;
99 i1 = 2;
100 k1 = buf[0];
101 } else {
102 i1 = 3;
103 k1 = buf[0];
104 k2 = buf[1];
106 for (int f = 1; (cmd = commandsystem::GetCommand(f)) != 0; f++) {
107 if (!strcmp(buf+i1, cmd->GetDescription())) cmd->SetKeys(k1, k2);
109 for (int f = 0; f <= 8; f++) if (!strcmp(buf+i1, adirNames[f])) game::SetAbnormalMoveKey(f, k1);
111 fclose(fl);
115 void commandsystem::SaveKeys (truth forced) {
116 command *cmd;
117 festring fname;
118 int isWizard = 0;
119 #ifdef LOCAL_SAVES
120 fname << ivanconfig::GetMyDir();
121 #else
122 fname << getenv("HOME");
123 #endif
124 fname << "/.keys.rc";
125 if (!forced) {
126 if (inputfile::fileExists(fname)) return;
128 FILE *fl = fopen(fname.CStr(), "w");
129 if (!fl) return;
130 for (; isWizard < 2; isWizard++) {
131 fputs(isWizard ? "\n# wizard actions\n" : "# actions\n", fl);
132 for (int f = 1; (cmd = commandsystem::GetCommand(f)) != 0; f++) {
133 if (cmd->IsWizardModeFunction()) {
134 if (!isWizard) continue;
135 } else {
136 if (isWizard) continue;
138 cchar *dsc = cmd->GetDescription();
139 char k1 = cmd->GetKey1(), k2 = cmd->GetKey2();
140 if (!dsc || !dsc[0]) continue;
141 if (k1 && k2 && k1 != k2) fprintf(fl, "%c%c", k1, k2);
142 else if (k1) fprintf(fl, "%c", k1);
143 else if (k2) fprintf(fl, "%c", k2);
144 fprintf(fl, "=%s\n", dsc);
147 fputs("\n# alternate movement\n", fl);
148 for (int f = 0; f <= 8; f++) {
149 char ch = game::GetAbnormalMoveKey(f);
150 if (ch) fputc(ch, fl);
151 fprintf(fl, "=%s\n", adirNames[f]);
153 fclose(fl);
155 /* k8 */
158 command *commandsystem::Command[] = {
160 /* Sort according to description */
161 new command(&Apply, "apply", 'a', 'a', false),
162 new command(&Talk, "chat", 'C', 'C', false),
163 new command(&Close, "close", 'c', 'c', false),
164 new command(&Dip, "dip", '!', '!', false),
165 new command(&Dump, "dump potion/can contents", 'U', 'U', false),
166 new command(&Drink, "drink", 'D', 'D', true),
167 new command(&Drop, "drop", 'd', 'd', true),
168 new command(&Eat, "eat", 'e', 'e', true),
169 new command(&WhatToEngrave, "engrave", 'G', 'G', false),
170 new command(&EquipmentScreen, "equipment menu", 'E', 'E', true),
171 new command(&Go, "go", 'g', 'g', false),
172 new command(&GoDown, "go down/enter area", '>', '>', true),
173 new command(&GoUp, "go up", '<', '<', true),
174 new command(&IssueCommand, "issue command(s) to team member(s)", 'I', 'I', false),
175 new command(&Kick, "kick", 'k', 'K', false),
176 new command(&Look, "look", 'l', 'L', true),
177 new command(&AssignName, "name", 'n', 'n', false),
178 new command(&Offer, "offer", 'O', 'f', false),
179 new command(&Open, "open", 'o', 'O', false),
180 new command(&PickUp, "pick up", ',', ',', false),
181 new command(&Pray, "pray", 'p', 'p', false),
182 new command(&Quit, "quit", 'Q', 'Q', true),
183 new command(&Read, "read", 'r', 'r', false),
184 new command(&Rest, "rest/heal", 'h', 'h', true),
185 new command(&Save, "save game", 'S', 'S', true),
186 new command(&ScrollMessagesDown, "scroll messages down", '+', '+', true),
187 new command(&ScrollMessagesUp, "scroll messages up", '-', '-', true),
188 new command(&ShowConfigScreen, "show config screen", '\\', '\\', true),
189 new command(&ShowInventory, "show inventory", 'i', 'i', true),
190 new command(&ShowKeyLayout, "show key layout", '?', '?', true),
191 new command(&DrawMessageHistory, "show message history", 'M', 'M', true),
192 new command(&ShowWeaponSkills, "show weapon skills", '@', '@', true),
193 new command(&Search, "search", 's', 's', false),
194 new command(&Sit, "sit", '_', '_', false),
195 new command(&Throw, "throw", 't', 't', false),
196 new command(&ToggleRunning, "toggle running", 'u', 'U', true),
197 new command(&ForceVomit, "vomit", 'V', 'V', false),
198 new command(&NOP, "wait", '.', '.', true),
199 new command(&WieldInRightArm, "wield in right arm", 'w', 'w', true),
200 new command(&WieldInLeftArm, "wield in left arm", 'W', 'W', true),
201 new command(&Burn, "burn", 'B', 'B', false),
202 #ifdef WIZARD
203 new command(&WizardMode, "wizard mode activation", 'X', 'X', true),
204 #endif
205 new command(&Zap, "zap", 'z', 'z', false),
206 #ifdef WIZARD
207 /* Sort according to key */
208 new command(&RaiseStats, "raise stats", '1', '1', true, true),
209 new command(&LowerStats, "lower stats", '2', '2', true, true),
210 new command(&SeeWholeMap, "see whole map", '3', '3', true, true),
211 new command(&WalkThroughWalls, "toggle walk through walls mode", '4', '4', true, true),
212 new command(&RaiseGodRelations, "raise your relations to the gods", '5', '5', true, true),
213 new command(&LowerGodRelations, "lower your relations to the gods", '6', '6', true, true),
214 new command(&WizardWish, "wish something", '=', '=', true, true),
215 new command(&GainDivineKnowledge, "gain knowledge of all gods", '\"', '\"', true, true),
216 new command(&GainAllItems, "gain all items", '$', '$', true, true),
217 new command(&SecretKnowledge, "reveal secret knowledge", '*', '*', true, true),
218 new command(&DetachBodyPart, "detach a limb", '0', '0', true, true),
219 new command(&SummonMonster, "summon monster", '&', '&', false, true),
220 new command(&LevelTeleport, "level teleport", '|', '|', false, true),
221 new command(&Possess, "possess creature", '{', '{', false, true),
222 new command(&Polymorph, "polymorph", '[', '[', true, true),
223 new command(&GetScroll, "get scroll", 'R', 'R', true, true),
224 new command(&OpenMondedr, "open Mondedr", 'm', 'm', true, true),
225 new command(&ShowCoords, "show current coordinates", '(', '(', true, true),
226 new command(&WizardHeal, "wizard healing", 'H', 'H', true, true),
227 #endif
232 truth commandsystem::GoUp (character *Char) {
233 if (!Char->TryToUnStickTraps(ZERO_V2)) return false;
234 /*if(!game::IsInWilderness() && game::WizardModeIsActive() && game::GetCurrentLevelIndex() >= 1)
235 if(game::TryTravel(game::GetCurrentDungeonIndex(), game::GetCurrentLevelIndex() - 1, RANDOM, true))
236 return true;*/
237 oterrain *Terrain = Char->GetSquareUnder()->GetOTerrain();
238 if (!Terrain) {
239 if (game::IsInWilderness()) {
240 if (!Char->IsFlying()) ADD_MESSAGE("You jump into the air. For some reason you don't get too far above.");
241 else ADD_MESSAGE("You fly around for some time.");
242 } else ADD_MESSAGE("You can't go up.");
243 return false;
245 if (Terrain->Enter(true)) {
246 Char->EditExperience(LEG_STRENGTH, 150, 1<<6);
247 Char->EditNP(-20);
248 Char->EditAP(-100000/APBonus(Char->GetAttribute(AGILITY)));
249 return true;
251 return false;
255 truth commandsystem::GoDown (character *Char) {
256 if (!Char->TryToUnStickTraps(ZERO_V2)) return false;
257 /*if(!game::IsInWilderness() && game::WizardModeIsActive() && game::GetCurrentLevelIndex() < game::GetLevels() - 1)
258 if(game::TryTravel(game::GetCurrentDungeonIndex(), game::GetCurrentLevelIndex() + 1, RANDOM, true))
259 return true;*/
260 oterrain *Terrain = Char->GetSquareUnder()->GetOTerrain();
261 if (!Terrain) {
262 if (game::IsInWilderness()) ADD_MESSAGE("There seems to be nothing of interest here.");
263 else ADD_MESSAGE("You can't go down.");
264 return false;
266 if (Terrain->Enter(false)) {
267 Char->EditExperience(AGILITY, 150, 1<<6);
268 Char->EditNP(-10);
269 Char->EditAP(-100000/APBonus(Char->GetAttribute(AGILITY)));
270 return true;
272 return false;
276 truth commandsystem::Open (character *Char) {
277 if (Char->CanOpen()) {
278 int Key;
279 truth OpenableItems = Char->GetStack()->SortedItems(Char, &item::IsOpenable);
281 if (OpenableItems) {
282 Key = game::AskForKeyPress(CONST_S("What do you wish to open? [press a direction key, space or i]"));
283 } else {
284 Key = game::AskForKeyPress(CONST_S("What do you wish to open? [press a direction key or space]"));
287 if (OpenableItems && (Key == 'i' || Key == 'I')) {
288 item *Item = Char->GetStack()->DrawContents(Char, CONST_S("What do you want to open?"), 0, &item::IsOpenable);
289 return Item && Item->Open(Char);
291 v2 DirVect = game::GetDirectionVectorForKey(Key);
292 if (DirVect != ERROR_V2 && Char->GetArea()->IsValidPos(Char->GetPos()+DirVect)) return Char->GetNearLSquare(Char->GetPos()+DirVect)->Open(Char);
293 } else {
294 ADD_MESSAGE("This monster type cannot open anything.");
296 return false;
300 truth commandsystem::Close (character *Char) {
301 if (Char->CanOpen()) {
302 int Dir = game::DirectionQuestion(CONST_S("What do you wish to close? [press a direction key]"), false);
303 if (Dir != DIR_ERROR && Char->GetArea()->IsValidPos(Char->GetPos()+game::GetMoveVector(Dir)))
304 return Char->GetNearLSquare(Char->GetPos()+game::GetMoveVector(Dir))->Close(Char);
305 } else {
306 ADD_MESSAGE("This monster type cannot close anything.");
308 return false;
312 truth commandsystem::Drop (character *Char) {
313 if (!Char->GetStack()->GetItems()) {
314 ADD_MESSAGE("You have nothing to drop!");
315 return false;
317 truth Success = false;
318 stack::SetSelected(0);
319 for (;;) {
320 itemvector ToDrop;
321 game::DrawEverythingNoBlit();
322 Char->GetStack()->DrawContents(ToDrop, Char, CONST_S("What do you want to drop?"), REMEMBER_SELECTED);
323 if (ToDrop.empty()) break;
324 if (game::IsInWilderness()) {
325 for (uInt c = 0; c < ToDrop.size(); ++c) {
326 if (game::TruthQuestion(CONST_S("Are you sure? You will never see ")+ToDrop[c]->CHAR_NAME(DEFINITE)+" again! [y/N]")) {
327 ADD_MESSAGE("You drop %s.", ToDrop[c]->CHAR_NAME(DEFINITE));
328 ToDrop[c]->RemoveFromSlot();
329 ToDrop[c]->SendToHell();
332 } else if (!Char->GetRoom() || Char->GetRoom()->DropItem(Char, ToDrop[0], ToDrop.size())) {
333 ADD_MESSAGE("%s dropped.", ToDrop[0]->GetName(INDEFINITE, ToDrop.size()).CStr());
334 for (uInt c = 0; c < ToDrop.size(); ++c) ToDrop[c]->MoveTo(Char->GetStackUnder());
335 Success = true;
338 if (Success) {
339 Char->DexterityAction(2);
340 return true;
342 return false;
346 truth commandsystem::Eat (character *Char) {
347 if (!Char->CheckConsume(CONST_S("eat"))) return false;
348 lsquare *Square = Char->GetLSquareUnder();
349 if (!game::IsInWilderness() && Square->GetOLTerrain() && Square->GetOLTerrain()->HasEatEffect()) {
350 if (Square->GetOLTerrain()->Eat(Char)) return true;
352 return Consume(Char, "eat", &item::IsEatable);
356 truth commandsystem::Drink (character *Char) {
357 if (!Char->CheckConsume(CONST_S("drink"))) return false;
358 lsquare *Square = Char->GetLSquareUnder();
359 if (!game::IsInWilderness() && Square->GetOLTerrain() && Square->GetOLTerrain()->HasDrinkEffect()) {
360 if (Square->GetOLTerrain()->Drink(Char)) return true;
362 return Consume(Char, "drink", &item::IsDrinkable);
366 truth commandsystem::Consume (character* Char, cchar *ConsumeVerb, sorter Sorter) {
367 lsquare *Square = Char->GetLSquareUnder();
368 stack *Inventory = Char->GetStack();
369 stack *StackUnder = Square->GetStack();
370 if ((game::IsInWilderness() || !StackUnder->SortedItems(Char, Sorter)) && !Inventory->SortedItems(Char, Sorter)) {
371 ADD_MESSAGE("You have nothing to %s!", ConsumeVerb);
372 return false;
374 itemvector Item;
375 festring Question = CONST_S("What do you wish to ")+ConsumeVerb+'?';
376 if (!game::IsInWilderness() && StackUnder->SortedItems(Char, Sorter))
377 Inventory->DrawContents(Item, StackUnder, Char, Question, CONST_S("Items in your inventory"), CONST_S("Items on the ground"), CONST_S(""), 0, NO_MULTI_SELECT, Sorter);
378 else
379 Inventory->DrawContents(Item, Char, Question, NO_MULTI_SELECT, Sorter);
380 return !Item.empty() ? Char->ConsumeItem(Item[0], ConsumeVerb+CONST_S("ing")) : false;
384 truth commandsystem::ShowInventory (character *Char) {
385 festring Title("Your inventory (total weight: ");
386 Title << Char->GetStack()->GetWeight();
387 Title << "g)";
388 Char->GetStack()->DrawContents(Char, Title, NO_SELECT);
389 return false;
393 truth commandsystem::PickUp (character *Char) {
394 if (!Char->GetStackUnder()->GetVisibleItems(Char)) {
395 ADD_MESSAGE("There is nothing here to pick up!");
396 return false;
398 itemvectorvector PileVector;
399 Char->GetStackUnder()->Pile(PileVector, Char, CENTER);
400 for (int c = 0; c < 4; ++c) {
401 stack *Stack = Char->GetLSquareUnder()->GetStackOfAdjacentSquare(c);
402 if (Stack) Stack->Pile(PileVector, Char, 3-c);
404 if (PileVector.size() == 1) {
405 if (PileVector[0][0]->CanBePickedUp()) {
406 int Amount = PileVector[0].size();
407 if (Amount > 1) Amount = game::ScrollBarQuestion(CONST_S("How many ")+PileVector[0][0]->GetName(PLURAL)+'?', Amount, 1, 0, Amount, 0, WHITE, LIGHT_GRAY, DARK_GRAY);
408 if (!Amount) return false;
409 if ((!PileVector[0][0]->GetRoom() ||
410 PileVector[0][0]->GetRoom()->PickupItem(Char, PileVector[0][0], Amount)) &&
411 PileVector[0][0]->CheckPickUpEffect(Char)) {
412 if (PileVector[0][0]->IsCorpse() && ivanconfig::GetConfirmCorpses()) {
413 //if (!game::TruthQuestion(CONST_S("Do you really want to pick up the corpse? [y/N]"))) return false;
414 itemvector ToPickup;
415 game::DrawEverythingNoBlit();
416 Char->GetStackUnder()->DrawContents(ToPickup, Char, CONST_S("Do you really want to pick up the corpse?"), REMEMBER_SELECTED);
417 if (ToPickup.empty()) return false;
419 for (int c = 0; c < Amount; ++c) PileVector[0][c]->MoveTo(Char->GetStack());
420 ADD_MESSAGE("%s picked up.", PileVector[0][0]->GetName(INDEFINITE, Amount).CStr());
421 Char->DexterityAction(2);
422 return true;
424 return false;
425 } else {
426 ADD_MESSAGE("%s too large to pick up!", PileVector[0].size() == 1 ? "It is" : "They are");
427 return false;
430 truth Success = false;
431 stack::SetSelected(0);
432 for (;;) {
433 itemvector ToPickup;
434 game::DrawEverythingNoBlit();
435 Char->GetStackUnder()->DrawContents(ToPickup, Char, CONST_S("What do you want to pick up?"), REMEMBER_SELECTED);
436 if (ToPickup.empty()) break;
437 if (ToPickup[0]->CanBePickedUp()) {
438 if ((!ToPickup[0]->GetRoom() || ToPickup[0]->GetRoom()->PickupItem(Char, ToPickup[0], ToPickup.size())) &&
439 ToPickup[0]->CheckPickUpEffect(Char)) {
440 for (uInt c = 0; c < ToPickup.size(); ++c) ToPickup[c]->MoveTo(Char->GetStack());
441 ADD_MESSAGE("%s picked up.", ToPickup[0]->GetName(INDEFINITE, ToPickup.size()).CStr());
442 Success = true;
444 } else ADD_MESSAGE("%s too large to pick up!", ToPickup.size() == 1 ? "It is" : "They are");
446 if (Success) {
447 Char->DexterityAction(2);
448 return true;
450 return false;
454 truth commandsystem::Quit (character *Char) {
455 if (game::TruthQuestion(CONST_S("Your quest is not yet compeleted! Really quit? [y/N]"))) {
456 Char->ShowAdventureInfo();
457 festring Msg = CONST_S("cowardly quit the game");
458 Char->AddScoreEntry(Msg, 0.75);
459 game::End(Msg, !game::WizardModeIsActive() || game::TruthQuestion(CONST_S("Remove saves? [y/N]")));
460 return true;
462 return false;
466 truth commandsystem::Talk (character *Char) {
467 if (!Char->CheckTalk()) return false;
468 character *ToTalk = 0;
469 int Characters = 0;
470 for (int d = 0; d < 8; ++d) {
471 lsquare *Square = Char->GetNaturalNeighbourLSquare(d);
472 if (Square) {
473 character *Dude = Square->GetCharacter();
474 if (Dude) {
475 ToTalk = Dude;
476 ++Characters;
480 if (!Characters) {
481 ADD_MESSAGE("Find yourself someone to talk to first!");
482 return false;
484 if (Characters == 1) return ToTalk->ChatMenu();
485 int Dir = game::DirectionQuestion(CONST_S("To whom do you wish to talk to? [press a direction key]"), false, true);
486 if (Dir == DIR_ERROR || !Char->GetArea()->IsValidPos(Char->GetPos()+game::GetMoveVector(Dir))) return false;
487 character *Dude = Char->GetNearSquare(Char->GetPos()+game::GetMoveVector(Dir))->GetCharacter();
488 if (Dude == Char) {
489 ADD_MESSAGE("You talk to yourself for some time.");
490 Char->EditExperience(WISDOM, -50, 1<<7);
491 Char->EditAP(-1000);
492 return true;
494 if (Dude) return Dude->ChatMenu();
495 ADD_MESSAGE("You get no response.");
496 return false;
500 truth commandsystem::NOP (character *Char) {
501 Char->EditExperience(DEXTERITY, -25, 1<<3);
502 Char->EditExperience(AGILITY, -25, 1<<3);
503 Char->EditAP(-Char->GetStateAPGain(1000));
504 return true;
508 truth commandsystem::Save (character *) {
509 if (game::TruthQuestion(CONST_S("Do you truly wish to save and flee? [y/N]"))) {
510 game::Save();
511 if (game::WizardModeIsActive()) {
512 if (!game::TruthQuestion(CONST_S("Do you want to exit, cheater? [y/N]"))) return false;
514 game::End("", false);
515 return true;
517 return false;
521 truth commandsystem::Read (character *Char) {
522 if (!Char->CanRead() && !game::GetSeeWholeMapCheatMode()) {
523 ADD_MESSAGE("You can't read.");
524 return false;
526 if (!Char->GetStack()->SortedItems(Char, &item::IsReadable)) {
527 ADD_MESSAGE("You have nothing to read!");
528 return false;
530 if (Char->GetLSquareUnder()->IsDark() && !game::GetSeeWholeMapCheatMode()) {
531 ADD_MESSAGE("It is too dark to read.");
532 return false;
534 item *Item = Char->GetStack()->DrawContents(Char, CONST_S("What do you want to read?"), 0, &item::IsReadable);
535 if (Item) {
536 if (ivanconfig::GetConfirmScrollReading() && Item->IsScroll()) {
537 if (!game::TruthQuestion(festring("Do you really want to read ")+Item->CHAR_NAME(DEFINITE)+"? [y/n]")) return false;
539 return Char->ReadItem(Item);
541 return false;
545 truth commandsystem::Dip (character *Char) {
546 if (!Char->GetStack()->SortedItems(Char, &item::IsDippable) && !Char->EquipsSomething(&item::IsDippable)) {
547 ADD_MESSAGE("You have nothing to dip!");
548 return false;
550 truth HasDipDestination = Char->PossessesItem(&item::IsDipDestination);
551 truth DipDestinationNear = false;
552 for (int d = 0; d < 9; ++d) {
553 lsquare *Square = Char->GetNaturalNeighbourLSquare(d);
554 if (Square && Square->IsDipDestination()) DipDestinationNear = true;
556 if (!HasDipDestination && !DipDestinationNear) {
557 ADD_MESSAGE("There is nothing to dip anything into.");
558 return false;
560 item *Item = Char->SelectFromPossessions(CONST_S("What do you want to dip?"), &item::IsDippable);
561 if (Item) {
562 if (!HasDipDestination || (DipDestinationNear && game::TruthQuestion(CONST_S("Do you wish to dip in a nearby square? [y/N]")))) {
563 int Dir = game::DirectionQuestion(CONST_S("Where do you want to dip ")+Item->GetName(DEFINITE)+"? [press a direction key or '.']", false, true);
564 v2 Pos = Char->GetPos()+game::GetMoveVector(Dir);
565 if (Dir == DIR_ERROR || !Char->GetArea()->IsValidPos(Pos) || !Char->GetNearLSquare(Pos)->IsDipDestination()) return false;
566 return Char->GetNearLSquare(Pos)->DipInto(Item, Char);
568 item *DipTo = Char->SelectFromPossessions(CONST_S("Into what do you wish to dip it?"), &item::IsDipDestination);
569 if (DipTo) {
570 if (Item == DipTo) {
571 ADD_MESSAGE("Very funny...");
572 return false;
574 //fprintf(stderr, "BSM: %p\n", DipTo->GetSecondaryMaterial());
575 Item->DipInto(DipTo->CreateDipLiquid(), Char);
576 //fprintf(stderr, "ASM: %p\n", DipTo->GetSecondaryMaterial());
577 if (!game::IsInWilderness() && !DipTo->GetSecondaryMaterial()) {
578 // container is empty
579 if ((DipTo->IsBottle() && ivanconfig::GetAutoDropBottles()) ||
580 (DipTo->IsCan() && ivanconfig::GetAutoDropCans())) {
581 // drop this item
582 if (!Char->GetRoom() || Char->GetRoom()->DropItem(Char, DipTo, 1)) {
583 ADD_MESSAGE("%s dropped.", DipTo->GetName(INDEFINITE, 1).CStr());
584 DipTo->MoveTo(Char->GetStackUnder());
585 Char->DexterityAction(2);
589 return true;
592 return false;
596 truth commandsystem::ShowKeyLayout (character *) {
597 felist List(CONST_S("Keyboard Layout"));
598 List.AddDescription(CONST_S(""));
599 List.AddDescription(CONST_S("Key Description"));
600 festring Buffer;
601 for (int c = 1; GetCommand(c); ++c) {
602 if (!GetCommand(c)->IsWizardModeFunction()) {
603 Buffer.Empty();
604 Buffer << GetCommand(c)->GetKey();
605 Buffer.Resize(10);
606 List.AddEntry(Buffer+GetCommand(c)->GetDescription(), LIGHT_GRAY);
609 if (game::WizardModeIsActive()) {
610 List.AddEntry(CONST_S(""), WHITE);
611 List.AddEntry(CONST_S("Wizard mode functions:"), WHITE);
612 List.AddEntry(CONST_S(""), WHITE);
613 for (int c = 1; GetCommand(c); ++c) {
614 if (GetCommand(c)->IsWizardModeFunction()) {
615 Buffer.Empty();
616 Buffer << GetCommand(c)->GetKey();
617 Buffer.Resize(10);
618 List.AddEntry(Buffer+GetCommand(c)->GetDescription(), LIGHT_GRAY);
622 game::SetStandardListAttributes(List);
623 List.Draw();
624 return false;
628 truth commandsystem::Look (character *Char) {
629 festring Msg;
630 if (!game::IsInWilderness()) Char->GetLevel()->AddSpecialCursors();
631 if (!game::IsInWilderness())
632 Msg = CONST_S("Direction keys move cursor, ESC exits, 'i' examines items, 'c' examines a character.");
633 else
634 Msg = CONST_S("Direction keys move cursor, ESC exits, 'c' examines a character.");
635 game::PositionQuestion(Msg, Char->GetPos(), &game::LookHandler, &game::LookKeyHandler, ivanconfig::GetLookZoom());
636 game::RemoveSpecialCursors();
637 return false;
641 truth commandsystem::WhatToEngrave (character *Char) {
642 if (!Char->CanRead()) {
643 ADD_MESSAGE("You can't even read.");
644 return false;
646 Char->GetNearLSquare(Char->GetPos())->Engrave(game::StringQuestion(CONST_S("What do you want to engrave here?"), WHITE, 0, 80, true));
647 return false;
651 truth commandsystem::Pray (character *Char) {
652 felist Panthenon(CONST_S("To Whom you want to address your prayers?"));
653 Panthenon.SetEntryDrawer(game::GodEntryDrawer);
654 int Known[GODS];
655 int Index = 0;
656 int DivineMaster = Char->GetLSquareUnder()->GetDivineMaster();
657 if (DivineMaster == ATHEIST) {
658 ADD_MESSAGE("Somehow you feel that no god will help you here.");
659 return false;
661 if (!DivineMaster) {
662 for (int c = 1; c <= GODS; ++c) {
663 if (game::GetGod(c)->IsKnown()) {
664 Panthenon.AddEntry(game::GetGod(c)->GetCompleteDescription(), LIGHT_GRAY, 20, c);
665 Known[Index++] = c;
668 } else if (game::GetGod(DivineMaster)->IsKnown()) {
669 Panthenon.AddEntry(game::GetGod(DivineMaster)->GetCompleteDescription(), LIGHT_GRAY, 20, DivineMaster);
670 Known[0] = DivineMaster;
671 } else {
672 ADD_MESSAGE("Somehow you feel that no deity you know can hear your prayers from this place.");
673 return false;
675 game::SetStandardListAttributes(Panthenon);
676 Panthenon.AddFlags(SELECTABLE);
677 int Select = Panthenon.Draw();
678 if (Select == LIST_WAS_EMPTY) {
679 ADD_MESSAGE("You do not know any gods.");
680 return false;
682 if (Select & FELIST_ERROR_BIT) return false;
683 if (Char->GetLSquareUnder()->GetDivineMaster()) {
684 if (!Select) {
685 if (game::TruthQuestion(CONST_S("Do you really wish to pray to ")+game::GetGod(Char->GetLSquareUnder()->GetDivineMaster())->GetName()+"? [y/N]"))
686 game::GetGod(Char->GetLSquareUnder()->GetDivineMaster())->Pray();
687 else
688 return false;
689 } else return false;
690 } else {
691 if (game::TruthQuestion(CONST_S("Do you really wish to pray to ")+game::GetGod(Known[Select])->GetName()+"? [y/N]")) {
692 if (Char->StateIsActivated(CONFUSED) && !(RAND() & 7)) {
693 int Index;
694 for (Index = 1+RAND()%GODS; Index == Known[Select]; Index = 1+RAND()%GODS);
695 if (game::GetGod(Index)->IsKnown())
696 ADD_MESSAGE("You feel something went wrong in the rituals. You have accidentally prayed to %s!", game::GetGod(Index)->GetName());
697 else
698 ADD_MESSAGE("Your rituals were seriously incorrect. You have accidentally prayed to an unknown god, but have no idea how!");
699 game::GetGod(Index)->Pray();
700 } else {
701 game::GetGod(Known[Select])->Pray();
703 } else {
704 return false;
707 Char->EditAP(-1000);
708 return true;
712 truth commandsystem::Kick (character *Char) {
713 /** No multi-tile support */
714 if (!Char->CheckKick()) return false;
715 if (Char->GetBurdenState() == OVER_LOADED) {
716 ADD_MESSAGE("You try to kick, but you collapse under your load.");
717 Char->EditAP(-100000/APBonus(Char->GetAttribute(AGILITY)));
718 return true;
720 int Dir = game::DirectionQuestion(CONST_S("In what direction do you wish to kick? [press a direction key]"), false);
721 if (Dir == DIR_ERROR || !Char->GetArea()->IsValidPos(Char->GetPos()+game::GetMoveVector(Dir))) return false;
722 lsquare *Square = Char->GetNearLSquare(Char->GetPos()+game::GetMoveVector(Dir));
723 if (!Square->CheckKick(Char)) return false;
724 character *Enemy = Square->GetCharacter();
725 if (Enemy && !(Enemy->IsMasochist() && Char->GetRelation(Enemy) == FRIEND) && Char->GetRelation(Enemy) != HOSTILE) {
726 if (!game::TruthQuestion(CONST_S("This might cause a hostile reaction. Are you sure? [y/N]"))) return false;
728 game::ClearEventData();
729 game::mActor = Square->GetCharacter();
730 game::mSecondActor = Char;
731 if (game::RunOnCharEvent(Char, CONST_S("before_kick"))) { game::ClearEventData(); return game::mResult != 0; }
732 game::ClearEventData();
733 game::mActor = Char;
734 game::mSecondActor = Square->GetCharacter();
735 if (game::RunOnCharEvent(Square->GetCharacter(), CONST_S("before_kicked_by"))) { game::ClearEventData(); return game::mResult != 0; }
736 game::ClearEventData();
737 Char->Hostility(Square->GetCharacter());
738 Char->Kick(Square, Dir);
739 return true;
743 truth commandsystem::Offer (character *Char) {
744 if (!Char->CheckOffer()) return false;
745 lsquare *Square = Char->GetLSquareUnder();
746 if (Square->GetOLTerrain() && Square->GetOLTerrain()->AcceptsOffers()) {
747 if (!Char->GetStack()->GetItems()) {
748 ADD_MESSAGE("You have nothing to offer!");
749 return false;
751 item *Item = Char->GetStack()->DrawContents(Char, CONST_S("What do you want to offer?"));
752 if (Item) {
753 if (game::GetGod(Square->GetDivineMaster())->ReceiveOffer(Item)) {
754 Item->RemoveFromSlot();
755 Item->SendToHell();
756 Char->DexterityAction(5); /** C **/
757 return true;
759 return false;
761 return false;
763 ADD_MESSAGE("There isn't any altar here!");
764 return false;
768 truth commandsystem::DrawMessageHistory (character *) {
769 msgsystem::DrawMessageHistory();
770 return false;
774 truth commandsystem::Throw (character *Char) {
775 if (!Char->CheckThrow()) return false;
776 if (!Char->GetStack()->GetItems()) {
777 ADD_MESSAGE("You have nothing to throw!");
778 return false;
780 item *Item = Char->GetStack()->DrawContents(Char, CONST_S("What do you want to throw?"));
781 if (Item) {
782 int Answer = game::DirectionQuestion(CONST_S("In what direction do you wish to throw? [press a direction key]"), false);
783 if (Answer == DIR_ERROR) return false;
784 Char->ThrowItem(Answer, Item);
785 Char->EditExperience(ARM_STRENGTH, 75, 1 << 8);
786 Char->EditExperience(DEXTERITY, 75, 1 << 8);
787 Char->EditExperience(PERCEPTION, 75, 1 << 8);
788 Char->EditNP(-50);
789 Char->DexterityAction(5);
790 return true;
792 return false;
796 truth commandsystem::Apply (character *Char) {
797 if (!Char->CanApply()) {
798 ADD_MESSAGE("This monster type cannot apply.");
799 return false;
801 if (!Char->CheckApply()) return false;
802 if (!Char->PossessesItem(&item::IsAppliable)) {
803 ADD_MESSAGE("You have nothing to apply!");
804 return false;
806 item *Item = Char->SelectFromPossessions(CONST_S("What do you want to apply?"), &item::IsAppliable);
807 return Item && Item->Apply(Char);
811 truth commandsystem::ForceVomit (character *Char) {
812 if (Char->CanForceVomit()) {
813 int Dir = game::DirectionQuestion(CONST_S("Where do you wish to vomit? [press a direction key]"), false, true);
814 if (Dir != DIR_ERROR) {
815 v2 VomitPos = Char->GetPos()+game::GetMoveVector(Dir);
816 if (Char->GetArea()->IsValidPos(VomitPos)) {
817 ccharacter *Other = Char->GetArea()->GetSquare(VomitPos)->GetCharacter();
818 if (Other && Other->GetTeam() != Char->GetTeam() &&
819 Other->GetRelation(Char) != HOSTILE &&
820 Other->CanBeSeenBy(Char) &&
821 !game::TruthQuestion("Do you really want to vomit at "+Other->GetObjectPronoun()+"? [y/N]")) return false;
822 ADD_MESSAGE("%s", Char->GetForceVomitMessage().CStr());
823 Char->Vomit(Char->GetPos() + game::GetMoveVector(Dir), 500 + RAND() % 500, false);
824 Char->EditAP(-1000);
825 return true;
828 } else ADD_MESSAGE("You can't vomit.");
830 return false;
834 truth commandsystem::Zap (character *Char) {
835 if (!Char->CheckZap()) return false;
836 if (!Char->PossessesItem(&item::IsZappable)) {
837 ADD_MESSAGE("You have nothing to zap with, %s.", game::Insult());
838 return false;
840 item *Item = Char->SelectFromPossessions(CONST_S("What do you want to zap with?"), &item::IsZappable);
841 if (Item) {
842 int Answer = game::DirectionQuestion(CONST_S("In what direction do you wish to zap? [press a direction key or '.']"), false, true);
843 if (Answer == DIR_ERROR) return false;
844 if (Item->Zap(Char, Char->GetPos(), Answer)) {
845 Char->EditAP(-100000/APBonus(Char->GetAttribute(PERCEPTION)));
846 return true;
848 return false;
850 return false;
854 truth commandsystem::Rest (character *Char) {
855 if (Char->StateIsActivated(PANIC)) {
856 ADD_MESSAGE("You are too scared to rest.");
857 return false;
859 truth Error = false;
860 if (Char->GetHP() == Char->GetMaxHP()) {
861 ADD_MESSAGE("You HP is already at its maximum.");
862 Error = true;
863 } else if (!Char->CanHeal()) {
864 ADD_MESSAGE("You cannot heal.");
865 Error = true;
867 if (Error) {
868 sLong MinutesToRest = game::NumberQuestion(CONST_S("How many minutes to wait?"), WHITE, true);
869 if (MinutesToRest > 0) {
870 oterrain *Terrain = Char->GetSquareUnder()->GetOTerrain();
871 if (Terrain) Terrain->ShowRestMessage(Char);
872 rest *Rest = rest::Spawn(Char);
873 Rest->SetMinToStop(game::GetTotalMinutes()+MinutesToRest);
874 Rest->SetGoalHP(0);
875 Char->SetAction(Rest);
876 return true;
878 return false;
880 sLong HPToRest = game::ScrollBarQuestion(CONST_S("How many hit points you desire?"), Char->GetMaxHP(), 1, 0, Char->GetMaxHP(), 0, WHITE, LIGHT_GRAY, DARK_GRAY);
881 if (HPToRest <= Char->GetHP()) {
882 if (HPToRest != 0) ADD_MESSAGE("Your HP is already %d.", Char->GetHP());
883 return false;
885 oterrain *Terrain = Char->GetSquareUnder()->GetOTerrain();
886 if (Terrain) Terrain->ShowRestMessage(Char);
887 rest *Rest = rest::Spawn(Char);
888 Rest->SetMinToStop(0);
889 Rest->SetGoalHP(HPToRest);
890 Char->SetAction(Rest);
891 return true;
895 truth commandsystem::Sit (character *Char) {
896 lsquare *Square = Char->GetLSquareUnder();
897 return (Square->GetOLTerrain() && Square->GetOLTerrain()->SitOn(Char)) || Square->GetGLTerrain()->SitOn(Char);
901 truth commandsystem::Go (character *Char) {
902 int Dir = game::DirectionQuestion(CONST_S("In what direction do you want to go? [press a direction key]"), false);
903 if (Dir == DIR_ERROR) return false;
904 go *Go = go::Spawn(Char);
905 Go->SetDirection(Dir);
906 Go->SetPrevWasTurn(false);
908 int OKDirectionsCounter = 0;
909 for (int d = 0; d < Char->GetNeighbourSquares(); ++d) {
910 lsquare *Square = Char->GetNeighbourLSquare(d);
911 if (Square && Char->CanMoveOn(Square)) ++OKDirectionsCounter;
913 Go->SetIsWalkingInOpen(OKDirectionsCounter > 2);
915 Char->SetAction(Go);
916 Char->EditAP(Char->GetStateAPGain(100)); // gum solution
917 Char->GoOn(Go, true);
918 return truth(Char->GetAction());
922 truth commandsystem::ShowConfigScreen (character *) {
923 ivanconfig::Show();
924 return false;
928 truth commandsystem::AssignName (character *) {
929 game::NameQuestion();
930 return false;
934 truth commandsystem::EquipmentScreen (character *Char) {
935 return Char->EquipmentScreen(Char->GetStack(), 0);
939 truth commandsystem::ScrollMessagesDown (character *) {
940 msgsystem::ScrollDown();
941 return false;
945 truth commandsystem::ScrollMessagesUp (character *) {
946 msgsystem::ScrollUp();
947 return false;
951 truth commandsystem::ShowWeaponSkills (character *Char) {
952 felist List(CONST_S("Your experience in weapon categories"));
953 List.AddDescription(CONST_S(""));
954 List.AddDescription(CONST_S("Category name Level Points Needed Battle bonus"));
955 truth Something = false;
956 festring Buffer;
957 for (int c = 0; c < Char->GetAllowedWeaponSkillCategories(); ++c) {
958 cweaponskill *Skill = Char->GetCWeaponSkill(c);
959 if (Skill->GetHits()/100 || (Char->IsUsingWeaponOfCategory(c))) {
960 Buffer = Skill->GetName(c);
961 Buffer.Resize(30);
962 Buffer << Skill->GetLevel();
963 Buffer.Resize(40);
964 Buffer << Skill->GetHits()/100;
965 Buffer.Resize(50);
966 if (Skill->GetLevel() != 20) Buffer << (Skill->GetLevelMap(Skill->GetLevel()+1)-Skill->GetHits())/100;
967 else Buffer << '-';
968 Buffer.Resize(60);
969 Buffer << '+' << (Skill->GetBonus()-1000)/10;
970 if (Skill->GetBonus() % 10) Buffer << '.' << Skill->GetBonus()%10;
971 Buffer << '%';
972 List.AddEntry(Buffer, Char->IsUsingWeaponOfCategory(c) ? WHITE : LIGHT_GRAY);
973 Something = true;
976 if (Char->AddSpecialSkillInfo(List)) Something = true;
977 if (Something) {
978 game::SetStandardListAttributes(List);
979 List.Draw();
980 } else {
981 ADD_MESSAGE("You are not experienced in any weapon skill yet!");
983 return false;
987 truth commandsystem::WieldInRightArm (character *Char) {
988 if (!Char->CanUseEquipment()) ADD_MESSAGE("You cannot wield anything.");
989 else if (Char->TryToChangeEquipment(Char->GetStack(), 0, RIGHT_WIELDED_INDEX)) {
990 Char->DexterityAction(5);
991 return true;
993 return false;
997 truth commandsystem::WieldInLeftArm (character *Char) {
998 if (!Char->CanUseEquipment()) ADD_MESSAGE("You cannot wield anything.");
999 else if (Char->TryToChangeEquipment(Char->GetStack(), 0, LEFT_WIELDED_INDEX)) {
1000 Char->DexterityAction(5);
1001 return true;
1003 return false;
1007 truth commandsystem::Search (character *Char) {
1008 Char->Search(Char->GetAttribute(PERCEPTION) << 2);
1009 return true;
1013 #ifdef WIZARD
1014 truth commandsystem::WizardMode (character *Char) {
1015 if (!game::WizardModeIsActive()) {
1016 if (game::TruthQuestion(CONST_S("Do you want to cheat, cheater? This action cannot be undone. [y/N]"))) {
1017 game::ActivateWizardMode();
1018 ADD_MESSAGE("Wizard mode activated.");
1019 if (!game::IsInWilderness()) game::LoadWorldMap();
1020 v2 ElpuriCavePos = game::GetWorldMap()->GetEntryPos(0, ELPURI_CAVE);
1021 game::GetWorldMap()->GetWSquare(ElpuriCavePos)->ChangeOWTerrain(elpuricave::Spawn());
1022 game::GetWorldMap()->RevealEnvironment(ElpuriCavePos, 1);
1023 if (game::IsInWilderness()) game::GetWorldMap()->SendNewDrawRequest(); else game::SaveWorldMap();
1024 game::Save();
1025 game::Save(game::GetAutoSaveFileName());
1027 return false;
1029 // wizard mode
1030 if (game::GetPlayerName() == "_k8_" && game::TruthQuestion(CONST_S("Do you want to uncheat, cheater? [y/N]"))) {
1031 game::DeactivateWizardMode();
1032 ADD_MESSAGE("You are the ordinary mortal again.");
1033 } else {
1034 if (PLAYER->GetVirtualHead()) {
1035 ADD_MESSAGE("spillfluid.");
1036 //PLAYER->GetVirtualHead()->SpillFluid(0, liquid::Spawn(GetBloodMaterial(), 1000));
1037 PLAYER->GetVirtualHead()->SpillBlood(1000);
1040 return false;
1044 truth commandsystem::RaiseStats (character *Char) {
1045 Char->EditAllAttributes(1);
1046 return false;
1050 truth commandsystem::LowerStats (character *Char) {
1051 Char->EditAllAttributes(-1);
1052 return false;
1056 truth commandsystem::GainAllItems (character *Char) {
1057 itemvectorvector AllItems;
1058 protosystem::CreateEveryItem(AllItems);
1059 stack *Stack = game::IsInWilderness() ? Char->GetStack() : Char->GetStackUnder();
1060 for (uInt c = 0; c < AllItems.size(); ++c) Stack->AddItem(AllItems[c][0]);
1061 return false;
1065 truth commandsystem::SeeWholeMap (character *) {
1066 game::SeeWholeMap();
1067 return false;
1071 truth commandsystem::WalkThroughWalls (character *) {
1072 game::GoThroughWalls();
1073 return false;
1077 truth commandsystem::RaiseGodRelations (character *) {
1078 for (int c = 1; c <= GODS; ++c) game::GetGod(c)->AdjustRelation(50);
1079 return false;
1083 truth commandsystem::LowerGodRelations (character *) {
1084 for (int c = 1; c <= GODS; ++c) game::GetGod(c)->AdjustRelation(-50);
1085 return false;
1089 truth commandsystem::GainDivineKnowledge (character *) {
1090 for (int c = 1; c <= GODS; ++c) game::LearnAbout(game::GetGod(c));
1091 return false;
1095 truth commandsystem::SecretKnowledge (character *Char) {
1096 felist List(CONST_S("Knowledge of the ancients"));
1097 List.AddEntry(CONST_S("Character attributes"), LIGHT_GRAY);
1098 List.AddEntry(CONST_S("Character attack info"), LIGHT_GRAY);
1099 List.AddEntry(CONST_S("Character defence info"), LIGHT_GRAY);
1100 List.AddEntry(CONST_S("Character danger values"), LIGHT_GRAY);
1101 List.AddEntry(CONST_S("Item attack info"), LIGHT_GRAY);
1102 List.AddEntry(CONST_S("Miscellaneous item info"), LIGHT_GRAY);
1103 List.AddEntry(CONST_S("Material info"), LIGHT_GRAY);
1104 game::SetStandardListAttributes(List);
1105 List.AddFlags(SELECTABLE);
1106 uInt c, Chosen = List.Draw();
1107 festring Entry;
1108 if (Chosen & FELIST_ERROR_BIT) return false;
1109 List.Empty();
1110 List.RemoveFlags(SELECTABLE);
1111 if (Chosen < 4) {
1112 charactervector &Character = game::GetCharacterDrawVector();
1113 int TeamSize = 0;
1114 for (std::list<character*>::const_iterator i = Char->GetTeam()->GetMember().begin(); i != Char->GetTeam()->GetMember().end(); ++i) {
1115 if ((*i)->IsEnabled()) {
1116 Character.push_back(*i);
1117 ++TeamSize;
1120 protosystem::CreateEveryCharacter(Character);
1121 List.SetEntryDrawer(game::CharacterEntryDrawer);
1122 switch (Chosen) {
1123 case 0:
1124 List.AddDescription(CONST_S(" AS LS DX AG EN PE IN WI CH MA"));
1125 for (c = 0; c < Character.size(); ++c) {
1126 Entry.Empty();
1127 Character[c]->AddName(Entry, UNARTICLED);
1128 Character[c]->AddAttributeInfo(Entry);
1129 List.AddEntry(Entry, LIGHT_GRAY, 0, c);
1131 List.SetPageLength(15);
1132 break;
1133 case 1:
1134 List.AddDescription(CONST_S(" BD THV APC"));
1135 for (c = 0; c < Character.size(); ++c) {
1136 Entry.Empty();
1137 Character[c]->AddName(Entry, UNARTICLED);
1138 List.AddEntry(Entry, LIGHT_GRAY, 0, c);
1139 Character[c]->AddAttackInfo(List);
1141 List.SetPageLength(20);
1142 break;
1143 case 2:
1144 List.AddDescription(CONST_S(" DV/BV HP AV/BS"));
1145 for (c = 0; c < Character.size(); ++c) {
1146 Entry.Empty();
1147 Character[c]->AddName(Entry, UNARTICLED);
1148 Entry.Resize(47);
1149 Entry << int(Character[c]->GetDodgeValue());
1150 Entry.Resize(57);
1151 Entry << Character[c]->GetMaxHP();
1152 List.AddEntry(Entry, LIGHT_GRAY, 0, c);
1153 Character[c]->AddDefenceInfo(List);
1155 List.SetPageLength(25);
1156 break;
1157 case 3:
1158 List.AddDescription(CONST_S(" Danger NGM EGM"));
1159 for (c = 0; c < Character.size(); ++c) {
1160 Entry.Empty();
1161 Character[c]->AddName(Entry, UNARTICLED);
1162 Entry.Resize(47);
1163 Entry << int(Character[c]->GetRelativeDanger(Char, true) * 1000);
1164 Entry.Resize(57);
1165 const dangerid& DI = game::GetDangerMap().find(configid(Character[c]->GetType(), Character[c]->GetConfig()))->second;
1166 Entry << int(DI.NakedDanger * 1000);
1167 Entry.Resize(67);
1168 Entry << int(DI.EquippedDanger * 1000);
1169 List.AddEntry(Entry, LIGHT_GRAY, 0, c);
1171 List.SetPageLength(15);
1172 break;
1174 List.Draw();
1175 for (c = TeamSize; c < Character.size(); ++c) delete Character[c];
1176 game::ClearCharacterDrawVector();
1177 } else if (Chosen < 6) {
1178 itemvectorvector &Item = game::GetItemDrawVector();
1179 protosystem::CreateEveryItem(Item);
1180 List.SetEntryDrawer(game::ItemEntryDrawer);
1181 List.SetPageLength(20);
1182 switch (Chosen) {
1183 case 4:
1184 List.AddDescription(CONST_S(" Weight Size SR DAM"));
1185 for (c = 0; c < Item.size(); ++c) {
1186 Entry.Empty();
1187 Item[c][0]->AddName(Entry, UNARTICLED);
1188 List.AddEntry(Entry, LIGHT_GRAY, 0, c, true);
1189 Item[c][0]->AddAttackInfo(List);
1191 break;
1192 case 5:
1193 List.AddDescription(CONST_S(" \177 OV NV"));
1194 for (c = 0; c < Item.size(); ++c) {
1195 Entry.Empty();
1196 Item[c][0]->AddName(Entry, UNARTICLED);
1197 List.AddEntry(Entry, LIGHT_GRAY, 0, c, true);
1198 Item[c][0]->AddMiscellaneousInfo(List);
1200 break;
1202 List.Draw();
1203 for (c = 0; c < Item.size(); ++c) delete Item[c][0];
1204 game::ClearItemDrawVector();
1205 } else if (Chosen < 7) {
1206 std::vector<material *> Material;
1207 protosystem::CreateEveryMaterial(Material);
1208 List.SetPageLength(30);
1209 List.AddDescription(CONST_S(" Strength Flexibility Density"));
1210 for (c = 0; c < Material.size(); ++c) {
1211 Entry.Empty();
1212 Material[c]->AddName(Entry, false, false);
1213 Entry.Resize(40);
1214 Entry << Material[c]->GetStrengthValue();
1215 Entry.Resize(55);
1216 Entry << int(Material[c]->GetFlexibility());
1217 Entry.Resize(70);
1218 Entry << int(Material[c]->GetDensity());
1219 List.AddEntry(Entry, Material[c]->GetColor());
1221 List.Draw();
1222 for (c = 0; c < Material.size(); ++c) delete Material[c];
1224 List.PrintToFile(game::GetHomeDir()+"secret"+Chosen+".txt");
1225 ADD_MESSAGE("Info written also to %ssecret%d.txt.", game::GetHomeDir().CStr(), Chosen);
1226 return false;
1230 truth commandsystem::DetachBodyPart (character *Char) {
1231 Char->DetachBodyPart();
1232 return false;
1236 truth commandsystem::SummonMonster (character *Char) {
1237 character *Summoned = 0;
1239 while (!Summoned) {
1240 festring Temp = game::DefaultQuestion(CONST_S("Summon which monster?"), game::GetDefaultSummonMonster());
1242 if (Temp == "none") return false;
1243 Summoned = protosystem::CreateMonster(Temp);
1245 Summoned->SetTeam(game::GetTeam(MONSTER_TEAM));
1246 Summoned->PutNear(Char->GetPos());
1247 return false;
1251 truth commandsystem::LevelTeleport (character *) {
1252 sLong Level = game::NumberQuestion(CONST_S("To which level?"), WHITE);
1253 if (Level <= 0 || Level > game::GetLevels()) {
1254 ADD_MESSAGE("There is no level %d in this dungeon, %s!", Level, game::Insult());
1255 return false;
1257 if (Level == game::GetCurrentLevelIndex()+1) {
1258 ADD_MESSAGE("You are already here, %s!", game::Insult());
1259 return false;
1261 return game::TryTravel(game::GetCurrentDungeonIndex(), Level-1, RANDOM, true);
1265 truth commandsystem::Possess (character *Char) {
1266 int Dir = game::DirectionQuestion(CONST_S("Choose creature to possess. [press a direction key]"), false);
1267 if (Dir == DIR_ERROR || !Char->GetArea()->IsValidPos(Char->GetPos() + game::GetMoveVector(Dir))) return false;
1268 character *ToPossess = Char->GetNearLSquare(Char->GetPos() + game::GetMoveVector(Dir))->GetCharacter();
1269 if (ToPossess) {
1270 Char->RemoveFlags(C_PLAYER);
1271 game::SetPlayer(ToPossess);
1272 } else {
1273 ADD_MESSAGE("There's no one to possess, %s!", game::Insult());
1275 return true; // The old player's turn must end
1279 truth commandsystem::Polymorph (character *Char) {
1280 character *NewForm;
1281 if (!Char->GetNewFormForPolymorphWithControl(NewForm)) return true;
1282 Char->Polymorph(NewForm, game::NumberQuestion(CONST_S("For how long?"), WHITE));
1283 return true;
1287 truth commandsystem::GetScroll (character *Char) {
1288 for (;;) {
1289 int sel = game::ListSelector(-1, CONST_S("Select scroll to add"),
1290 "Scroll of Wishing",
1291 "Scroll of Charging",
1292 "Scroll of Repair",
1293 "Scroll of Change Material",
1294 "Scroll of Enchant Weapon",
1295 "Scroll of Enchant Armor",
1296 "Scroll of Taming",
1297 "Scroll of Teleportation",
1298 "Scroll of Detect Material",
1299 "Scroll of Harden Material",
1300 "Scroll of Golem Creation",
1301 NULL
1303 if (sel < 0) break;
1304 festring sname;
1305 sLong amount = game::NumberQuestion(CONST_S("How many scrolls do you want?"), WHITE, true);
1306 if (amount < 1) amount = 1;
1307 for (sLong f = amount; f > 0; --f) {
1308 switch (sel) {
1309 case 0: sname = "Wishing"; Char->GetStack()->AddItem(scrollofwishing::Spawn()); break;
1310 case 1: sname = "Charging"; Char->GetStack()->AddItem(scrollofcharging::Spawn()); break;
1311 case 2: sname = "Repair"; Char->GetStack()->AddItem(scrollofrepair::Spawn()); break;
1312 case 3: sname = "Change Material"; Char->GetStack()->AddItem(scrollofchangematerial::Spawn()); break;
1313 case 4: sname = "Enchant Weapon"; Char->GetStack()->AddItem(scrollofenchantweapon::Spawn()); break;
1314 case 5: sname = "Enchant Armor"; Char->GetStack()->AddItem(scrollofenchantarmor::Spawn()); break;
1315 case 6: sname = "Taming"; Char->GetStack()->AddItem(scrolloftaming::Spawn()); break;
1316 case 7: sname = "Teleportation"; Char->GetStack()->AddItem(scrollofteleportation::Spawn()); break;
1317 case 8: sname = "Detect Material"; Char->GetStack()->AddItem(scrollofdetectmaterial::Spawn()); break;
1318 case 9: sname = "Harden Material"; Char->GetStack()->AddItem(scrollofhardenmaterial::Spawn()); break;
1319 case 10: sname = "Golem Creation"; Char->GetStack()->AddItem(scrollofgolemcreation::Spawn()); break;
1320 default: sel = 666; break;
1323 if (sel != 666) {
1324 if (amount == 1) {
1325 ADD_MESSAGE("Got Scroll of %s.", sname.CStr());
1326 } else {
1327 ADD_MESSAGE("Got %d Scrolls of %s.", amount, sname.CStr());
1329 break;
1332 return false;
1336 truth commandsystem::WizardWish (character *Char) {
1337 if (!game::Wish(PLAYER, "%s appears from nothing!", "Two %s appear from nothing!", true)) {
1338 ADD_MESSAGE("You changed your mind, didn't you, %s?", game::Insult());
1340 return false;
1344 truth commandsystem::OpenMondedr (character *Char) {
1345 if (!game::GetMondedrPass()) {
1346 if (!game::IsInWilderness()) game::LoadWorldMap();
1347 v2 MondedrPos = game::GetWorldMap()->GetEntryPos(0, MONDEDR);
1348 game::GetWorldMap()->GetWSquare(MondedrPos)->ChangeOWTerrain(mondedr::Spawn());
1349 game::GetWorldMap()->RevealEnvironment(MondedrPos, 1);
1350 if (game::IsInWilderness()) game::GetWorldMap()->SendNewDrawRequest(); else game::SaveWorldMap();
1351 game::SetMondedrPass(1);
1352 game::Save();
1353 game::Save(game::GetAutoSaveFileName());
1354 ADD_MESSAGE("Mondedr opened.");
1355 } else {
1356 ADD_MESSAGE("Mondedr already opened.");
1358 return false;
1362 truth commandsystem::ShowCoords (character *Char) {
1363 v2 xy = Char->GetPos();
1364 ADD_MESSAGE("Coordinates: X=%d; Y=%d", xy.X, xy.Y);
1365 return false;
1370 static void dbp (character *Char, int idx) {
1371 if (Char->GetBodyPart(idx)) {
1372 festring NameOfDropped = Char->GetBodyPart(idx)->GetBodyPartName();
1373 item *dropped = Char->SevereBodyPart(idx);
1374 if (dropped) {
1375 //Char->GetStack()->AddItem(dropped);
1376 dropped->DropEquipment();
1377 dropped->SendToHell();
1378 ADD_MESSAGE("Suddenly, %s snaps off.", NameOfDropped.CStr());
1385 truth commandsystem::WizardHeal (character *Char) {
1387 truth newbp = game::TruthQuestion(CONST_S("Do you want completely new body? [y/N]"));
1388 if (newbp) {
1389 dbp(Char, LEFT_ARM_INDEX);
1390 //dbp(Char, RIGHT_ARM_INDEX);
1391 //dbp(Char, LEFT_LEG_INDEX);
1392 //dbp(Char, RIGHT_LEG_INDEX);
1393 //dbp(Char, HEAD_INDEX);
1394 //dbp(Char, TORSO_INDEX);
1397 for (int c = 0; c < Char->GetBodyParts(); ++c) {
1398 if (Char->GetBodyPart(c)) {
1399 Char->GetBodyPart(c)->RemoveAllFluids();
1400 } else if (Char->CanCreateBodyPart(c)) {
1401 const std::list<feuLong> &obp = Char->GetOriginalBodyPartID(c);
1403 for (std::list<feuLong>::const_iterator i = obp.begin(); i != obp.end(); ++i) {
1404 bodypart *OldBodyPart = static_cast<bodypart *>(PLAYER->SearchForItem(*i));
1406 if (OldBodyPart && OldBodyPart->CanRegenerate()) {
1407 OldBodyPart->RemoveAllFluids();
1408 OldBodyPart->SetHP(1);
1409 OldBodyPart->RemoveFromSlot();
1410 Char->AttachBodyPart(OldBodyPart);
1411 break;
1412 } else {
1413 Char->CreateBodyPart(c);
1414 Char->GetBodyPart(c)->SetHP(1);
1415 break;
1421 if (Char->TemporaryStateIsActivated(POISONED)) Char->DeActivateTemporaryState(POISONED);
1422 if (Char->TemporaryStateIsActivated(PARASITIZED)) Char->DeActivateTemporaryState(PARASITIZED);
1423 if (Char->TemporaryStateIsActivated(LEPROSY)) Char->DeActivateTemporaryState(LEPROSY);
1424 if (Char->TemporaryStateIsActivated(LYCANTHROPY)) Char->DeActivateTemporaryState(LYCANTHROPY);
1425 if (Char->TemporaryStateIsActivated(VAMPIRISM)) Char->DeActivateTemporaryState(VAMPIRISM);
1427 ADD_MESSAGE("Wizard healing...");
1428 return false;
1430 #endif
1433 truth commandsystem::ToggleRunning (character *Char) {
1434 if (game::PlayerIsRunning() && PLAYER->StateIsActivated(PANIC) && PLAYER->GetTirednessState() != FAINTING) {
1435 ADD_MESSAGE("You are too scared to move at normal pace.");
1436 return false;
1438 if (!Char->CanMove()) {
1439 ADD_MESSAGE("Well, well, aren't we funny today, eh?");
1440 return false;
1442 game::SetPlayerIsRunning(!game::PlayerIsRunning());
1443 return false;
1447 truth commandsystem::Burn (character *Char) {
1448 if (!Char->PossessesItem(&item::IsFlaming)) {
1449 ADD_MESSAGE("You have no flaming items, %s.", game::Insult());
1450 return false;
1452 item *Item = Char->SelectFromPossessions(CONST_S("What do you want to use?"), &item::IsFlaming);
1453 if (Item) {
1454 int Answer = game::DirectionQuestion(CONST_S("In what direction do you wish to burn? [press a direction key]"), false);
1455 if (Answer == DIR_ERROR) return false;
1456 if (Item->Burn(Char, Char->GetPos(), Answer)) {
1457 //FIXME: AP
1458 Char->EditExperience(AGILITY, 150, 1<<6);
1459 Char->EditNP(-10);
1460 Char->EditAP(-100000/APBonus(Char->GetAttribute(AGILITY)));
1461 return true;
1463 return false;
1465 return false;
1469 //FIXME: check for actor in that direction
1470 //FIXME: made actor/room owner hostile when containing material is acid, etc
1471 //FIXME: ÓÐÏÓÏ ×ÙÌÉÔØ ÔÏÞÎÏ ÎÁ ÐÏÌ ÉÌÉ ÎÁ ÍÏÎÓÔÒÉËÁ (ÚÁ×ÉÓÉÔ ÏÔ ÌÏ×ËÏÓÔÉ?)
1472 truth commandsystem::Dump (character *Char) {
1473 if (!Char->GetStack()->SortedItems(Char, &item::IsDumpable) && !Char->EquipsSomething(&item::IsDumpable)) {
1474 ADD_MESSAGE("You have nothing to dump!");
1475 return false;
1477 item *Item = Char->SelectFromPossessions(CONST_S("What do you want to dump?"), &item::IsDumpable);
1478 if (Item) {
1479 int Dir = game::DirectionQuestion(CONST_S("In what direction do you wish to dump it? [press a direction key or '.']"), false, true);
1480 if (Dir == DIR_ERROR) return false;
1481 v2 Pos = Char->GetPos()+game::GetMoveVector(Dir);
1482 return Item->DumpTo(Char, Pos);
1484 return false;
1488 truth commandsystem::IssueCommand (character *Char) {
1489 if (!Char->CheckTalk()) return false;
1490 return game::CommandQuestion();