From c42e6d4ff6e4dffbe2eccb0bc80de9226d009416 Mon Sep 17 00:00:00 2001 From: Cameron Currie Date: Sun, 27 Jan 2013 23:01:02 -0600 Subject: [PATCH 01/12] Use strings.h only If string.h winds up being needed for some platforms, it can be included through platform-specific defines (e.g. #ifdef WIN32). --- src/OmegaRPG/src/defs.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/OmegaRPG/src/defs.h b/src/OmegaRPG/src/defs.h index cb1d7d0..9c8add2 100644 --- a/src/OmegaRPG/src/defs.h +++ b/src/OmegaRPG/src/defs.h @@ -23,11 +23,6 @@ definitions in the following section. */ * on the bandwidth. */ #define CENTER_ON_PLAYER // TODO Make this a user-specifiable option -/* Implementor should uncomment the following if his system uses -string.h instead of strings.h (try man string) */ - -#define STRING - /* Implementor should define int32 as the type of integer which uses * 32 bits. */ typedef int int32; @@ -1738,17 +1733,7 @@ typedef oltype *pol; #define optionset(o) (Player.options |= (o)) #define optionreset(o) (Player.options &= ~(o)) -/* systemV for some reason uses string.h instead of strings.h */ -/* Also, random and srandom are unlikely to be found on system V... */ - -#ifdef STRING -#include -#endif - -#ifndef STRING #include -#endif - #include #ifndef TRUE From 12dad7bf00d13f6aa987d560d28ac74c9530e4e2 Mon Sep 17 00:00:00 2001 From: Cameron Currie Date: Sun, 27 Jan 2013 23:21:17 -0600 Subject: [PATCH 02/12] Remove define for catching signals --- src/OmegaRPG/src/Main.cpp | 2 -- src/OmegaRPG/src/defs.h | 6 ------ 2 files changed, 8 deletions(-) diff --git a/src/OmegaRPG/src/Main.cpp b/src/OmegaRPG/src/Main.cpp index 40cb45c..e5e9f3e 100644 --- a/src/OmegaRPG/src/Main.cpp +++ b/src/OmegaRPG/src/Main.cpp @@ -86,7 +86,6 @@ int main(int argc, char *argv[]) #endif #if !defined(WIN32) - if (CATCH_SIGNALS) { signal(SIGQUIT,signalexit); signal(SIGILL,signalexit); #ifdef DEBUG @@ -113,7 +112,6 @@ int main(int argc, char *argv[]) #ifdef SIGSYS signal(SIGSYS,signalexit); #endif - } #endif Omegalib = OMEGALIB; diff --git a/src/OmegaRPG/src/defs.h b/src/OmegaRPG/src/defs.h index 9c8add2..0bf0638 100644 --- a/src/OmegaRPG/src/defs.h +++ b/src/OmegaRPG/src/defs.h @@ -63,12 +63,6 @@ typedef int int32; #define WIZARD "sheldon" -/* If CATCH_SIGNALS is set to 1, will not dump core, nicer for players. */ -/* dbx still intercepts the signals first, so it's ok for debugging */ - -#define CATCH_SIGNALS 1 - - /*---------------------------SYSTEM DEFINITIONS---------------------------*/ /* Don't change anything from here on (unless you know what you're doing) */ From be7fdd81906a654b20b59d7005875910657e6a71 Mon Sep 17 00:00:00 2001 From: Cameron Currie Date: Sun, 27 Jan 2013 23:37:33 -0600 Subject: [PATCH 03/12] Remove redundant include --- src/OmegaRPG/src/omega.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/OmegaRPG/src/omega.c b/src/OmegaRPG/src/omega.c index d4204e5..edf7a1d 100644 --- a/src/OmegaRPG/src/omega.c +++ b/src/OmegaRPG/src/omega.c @@ -15,10 +15,6 @@ explicitly initializing every global to something. */ #endif -#ifndef NOGETOPT -# include -#endif - /* most globals originate in omega.c */ char* Omegalib; /* contains the path to the library files */ From da36ca478fa2242dec1ba834f0c213f466bd8553 Mon Sep 17 00:00:00 2001 From: Cameron Currie Date: Sun, 27 Jan 2013 23:43:58 -0600 Subject: [PATCH 04/12] Move usage print to its own function --- src/OmegaRPG/src/Main.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/OmegaRPG/src/Main.cpp b/src/OmegaRPG/src/Main.cpp index e5e9f3e..1d281af 100644 --- a/src/OmegaRPG/src/Main.cpp +++ b/src/OmegaRPG/src/Main.cpp @@ -15,6 +15,20 @@ void signalquit(int ignore) quit(); } +void printUsage() { +#ifdef DEBUG + printf("Usage: omega [-shd] [savefile]\n"); +#else + printf("Usage: omega [-sh] [savefile]\n"); +#endif + printf("Options:\n"); + printf(" -s Display high score list\n"); + printf(" -h Display this message\n"); +#ifdef DEBUG + printf(" -d Enable debug mode\n"); +#endif +} + int main(int argc, char *argv[]) { OmegaRPG* game; @@ -36,17 +50,7 @@ int main(int argc, char *argv[]) scoresOnly = true; break; case 'h': -#ifdef DEBUG - printf("Usage: omega [-shd] [savefile]\n"); -#else - printf("Usage: omega [-sh] [savefile]\n"); -#endif - printf("Options:\n"); - printf(" -s Display high score list\n"); - printf(" -h Display this message\n"); -#ifdef DEBUG - printf(" -d Enable debug mode\n"); -#endif + printUsage(); exit(0); break; case '?': From 70d9aa5b88792d63621421061a05906fb0ce9c73 Mon Sep 17 00:00:00 2001 From: Cameron Currie Date: Mon, 28 Jan 2013 01:58:37 -0600 Subject: [PATCH 05/12] Change debug log location --- src/OmegaRPG/src/Main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OmegaRPG/src/Main.cpp b/src/OmegaRPG/src/Main.cpp index 1d281af..ed85583 100644 --- a/src/OmegaRPG/src/Main.cpp +++ b/src/OmegaRPG/src/Main.cpp @@ -134,7 +134,7 @@ int main(int argc, char *argv[]) #ifdef DEBUG /* initialize debug log file */ - DG_debug_log = fopen( "/tmp/omega_dbg_log", "a" ); + DG_debug_log = fopen( "omegadbg.log", "a" ); assert( DG_debug_log ); /* WDT :) */ setvbuf( DG_debug_log, NULL, _IOLBF, 0); fprintf(DG_debug_log, "############## new game started ##############\n"); From ce42dbf3d6f1e0e81f2bbf2a82608db1dc778fbe Mon Sep 17 00:00:00 2001 From: Cameron Currie Date: Mon, 28 Jan 2013 01:58:47 -0600 Subject: [PATCH 06/12] Enable DEBUG flag in Eclipse project --- src/OmegaRPG/.cproject | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/OmegaRPG/.cproject b/src/OmegaRPG/.cproject index b4ce898..3fe3f4c 100644 --- a/src/OmegaRPG/.cproject +++ b/src/OmegaRPG/.cproject @@ -23,8 +23,8 @@ - @@ -39,11 +39,17 @@ From 5968186a6b6fdfe956132bb9b06a2bf442347029 Mon Sep 17 00:00:00 2001 From: Albert Wang Date: Mon, 28 Jan 2013 13:36:03 -0600 Subject: [PATCH 07/12] Basic makefile. GNUMake only --- Makefile | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b51804c --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ + +CPP := g++ +CC := gcc +LD := g++ + +CFLAGS := +LDFLAGS := -lcurses + +CXX_SRC_FILES := $(wildcard src/OmegaRPG/src/*.cpp) +CXX_OBJS := $(patsubst src/OmegaRPG/src/%.cpp, obj/%.op, $(CXX_SRC_FILES)) + +C_SRC_FILES := $(wildcard src/OmegaRPG/src/*.c) +C_OBJS := $(patsubst src/OmegaRPG/src/%.c, obj/%.o, $(C_SRC_FILES)) + +omega : dir cppobj cobj + $(LD) $(LDFLAGS) -o $@ $(CXX_OBJS) $(C_OBJS) + +cppobj : $(CXX_OBJS) + +cobj : $(C_OBJS) + +obj/%.o : src/OmegaRPG/src/%.c + $(CC) $(CFLAGS) -o $@ -c $< + +obj/%.op : src/OmegaRPG/src/%.cpp + $(CPP) $(CFLAGS) -o $@ -c $< + +dir : + mkdir -p obj + +clean : + rm -rf obj/ From 3f18e0a71d5888cf0c050f1961b342a146aff6f1 Mon Sep 17 00:00:00 2001 From: Patrick McCuller Date: Sun, 4 May 2014 17:15:23 -0700 Subject: [PATCH 08/12] Refactor food messages. Add simple arrow keys to movement (screen), inventory, stats, command selections. Added some include guards Remove some dead code Fix warnings on uncast mallocs Fix getLogin() returning stack memory Adding asserts on possible null dereferences Fixed typo in Grandmaster quest for Tholian monks Making it less likely that extended meditation will cause a permanent HP increase (1/2 -> 1/5) Touched up the Monk messaging a bit Made it possible to join the Monks for free, because free. --- Omega/src/Food.cpp | 110 +- Omega/src/Food.h | 24 +- Omega/src/bank.cpp | 2344 ++++++++++---------- Omega/src/char.cpp | 1681 ++++++++------- Omega/src/command1.cpp | 1049 ++++----- Omega/src/defs.h | 3266 ++++++++++++++-------------- Omega/src/guild2.cpp | 2354 ++++++++++---------- Omega/src/inv.cpp | 3499 +++++++++++++++--------------- Omega/src/map.cpp | 407 ++-- Omega/src/move.cpp | 2363 ++++++++++---------- Omega/src/scr.cpp | 4649 ++++++++++++++++++++-------------------- Omega/src/stats.cpp | 231 +- Tools/src/bwt.c | 417 ++-- Tools/src/decrypt.c | 370 ++-- 14 files changed, 11380 insertions(+), 11384 deletions(-) diff --git a/Omega/src/Food.cpp b/Omega/src/Food.cpp index 2b04df5..2622a87 100644 --- a/Omega/src/Food.cpp +++ b/Omega/src/Food.cpp @@ -1,60 +1,50 @@ -#include "glob.h" -#include "Food.h" - -Food::Food(void) -{ - weight = 20; - plus = charge = dmg = hit = fragility = blessing = 0; - - /* how full the food makes you feel */ - aux = 8; - - number = 1; - basevalue = 2; - - uniqueness = COMMON; - level = 0; - objchar = FOOD; - usef = I_FOOD; - objstr = "food ration"; - truename = "food ration"; - cursestr = "food ration"; -} - -Food::~Food(void) -{ -} - -void Food::initialize() -{ -} - -// Consume the food. Destroying object takes place in eat command: command2.c/eat() -void Food::use() -{ - // Adjust player's hunger - Player.food = max(0, Player.food + aux); - - // Print flavor message - switch (random_range(6)) - { - case 0: - mprint("That tasted horrible!"); - break; - case 1: - mprint("Yum!"); - break; - case 2: - mprint("How nauseous!"); - break; - case 3: - mprint("Can I have some more? Please?"); - break; - case 4: - mprint("Your mouth feels like it is growing hair!"); - break; - case 5: - mprint("Tastes like home cooking!"); - break; - } -} +#include +#include "glob.h" +#include "Food.h" + +Food::Food(void) +{ + weight = 20; + plus = charge = dmg = hit = fragility = blessing = 0; + + /* how full the food makes you feel */ + aux = 8; + + number = 1; + basevalue = 2; + + uniqueness = COMMON; + level = 0; + objchar = FOOD; + usef = I_FOOD; + objstr = "food ration"; + truename = "food ration"; + cursestr = "food ration"; +} + +Food::~Food(void) +{ +} + +void Food::initialize() +{ +} + +// Consume the food. Destroying object takes place in eat command: command2.c/eat() +void Food::use() +{ + // Adjust player's hunger + Player.food = max(0, Player.food + aux); + + std::string comments[] = { + "That tasted horrible!", + "Yum!", + "How nauseous!", + "Can I have some more? Please?", + "Your mouth feels like it is growing hair!", + "Tastes like home cooking!", + "Appalling." + }; + + mprint((char*)comments[random_range(7)].c_str()); +} diff --git a/Omega/src/Food.h b/Omega/src/Food.h index 0db4ff1..d66d377 100755 --- a/Omega/src/Food.h +++ b/Omega/src/Food.h @@ -1,12 +1,12 @@ -#pragma once -#include "Object.h" - -class Food : public Object -{ -public: - Food(); - ~Food(); - - virtual void initialize(); - virtual void use(); -}; +#pragma once +#include "Object.h" + +class Food : public Object +{ +public: + Food(); + ~Food(); + + virtual void initialize(); + virtual void use(); +}; diff --git a/Omega/src/bank.cpp b/Omega/src/bank.cpp index a4da030..e2ac031 100644 --- a/Omega/src/bank.cpp +++ b/Omega/src/bank.cpp @@ -1,1171 +1,1173 @@ -/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ -/* bank.c */ -/* new bank -- moved out of site1.c */ - -#include "glob.h" - -/* swiped from scr.c */ -#define CHARATTR(c) ((c) & ~0xff) - -/* defined in scr.c */ -extern WINDOW *Bankw; - -/* predefined account info */ -#define CASH_BALANCE 500 -#define CASH_PASSWORD "cash" - -#define NUM_NPC_ACCOUNTS 30 - -enum BankResponse { - BankAbort, - BankNewCustomer, - BankExistingCustomer -}; - -char * npc_account_passwords [NUM_NPC_ACCOUNTS] = -{ - "Duke", - "Duke Nukem", - "Dukes Ca$h", - "SexyNoreen", - "ExSuccubus", - "Hooker Sue", - "JungleGirl", - "Satyrical", - "Fangless", - "Big Daddy", - "PraiseEros", - "Sonders", - "CSRFLP", - "Order", - "Diner", - "LC****", - "Eclipse", - "The Circle", - "College", - "FinanceAid", - "Librarian", - "RTG, Inc.", - "Alchemy", - "LOD Mercs", - "KnightPawn", - "Julie", - "RampartGym", - "Arena", - "Slongo", - "Bedwyr" -}; - -int npc_account_balances [NUM_NPC_ACCOUNTS] = -{ - 3000, - 30000, - 300000, - 100000, - 75000, - 125000, - 50000, - 75000, - 50000, - 100000, - 50000, - 10000, - 300000, - 3000, - 3000, - 50000, - 5000, - 25000, - 5000, - 40000, - 10000, - 500000, - 10000, - 200000, - 75000, - 10000, - 40000, - 3000, - 2000, - 2000 -}; - -static int account_num [NUM_NPC_ACCOUNTS]; -static char * blank_line = " "; -static int account_number_next; -static int account_number_incr; - -/* create a new bank account and add it to the bank */ -bank_account * bank_create_account (int player, int balance, char *password) -{ - bank_account * new_account; - - /* no-password accounts aren't allowed */ - assert(password); - - /* allocate space */ - new_account = (bank_account*) checkmalloc(sizeof(bank_account)); - - /* copy fields */ - new_account->player = player; - new_account->balance = balance; - new_account->next_account = 0; - new_account->number = account_number_next; - account_number_next += account_number_incr; - - /* allocate and copy the password */ - new_account->password = (char*) checkmalloc(1 + strlen(password)); - strcpy(new_account->password, password); - - /* add the new account to the bank */ - new_account->next_account = bank; - bank = new_account; - - return new_account; -} - -Object* bank_create_card (int account_number, int type) -{ - Object* card; - - assert(OB_DEBIT_CARD == type || OB_SMART_CARD == type); - - card = (Object*) checkmalloc(sizeof(Object)); - *card = Objects[type]; - card->aux = account_number; - - return card; -} - -/* find an account in the bank, given the password */ -bank_account * bank_index_password (char * password) -{ - bank_account * account; - - for(account = bank; account; account = account->next_account) - if (!strcmp(password, account->password)) break; - - return account; -} - -/* find an account in the bank, given the account number */ -bank_account * bank_index_number (int number) -{ - bank_account * account; - - for(account = bank; account; account = account->next_account) - if (number == account->number) break; - - return account; -} - -/* allow user to type in a new password with simple editing */ -/* returns the length of the typed-in string */ -static int input_password (WINDOW *w, int line, int col, char *buf, int allow_esc) -{ - int key; - int pwlen = 0; - char *cp = buf; - - while (1) - { - key = mvwgetch(w, line, col + pwlen); - - if ('\n' == key) - { - *cp = '\0'; - break; - } - else if (ESCAPE == key && allow_esc) - { - *buf = ESCAPE; - return 1; - } - else if (KEY_LEFT == key || DELETE_CHAR == key || BACKSPACE == key) - { - if (pwlen > 0) - { - cp--; - pwlen--; - mvwaddch(w, line, col + pwlen, ' '); - } - } - else if (isprint(key) && pwlen < 10) - { - mvwaddch(w, line, col + pwlen, '*'); - pwlen++; - *cp++ = key; - } - - wrefresh(w); - } - - return pwlen; -} - -/* allow user to type in a signed integer with simple editing */ -/* returns the typed-in integer */ -static long input_amount (WINDOW *w, int line, int col) -{ - int key; - int amountlen = 0; - long amount = 0; - long sign = 1; - - while (1) - { - key = mvwgetch(w, line, col + amountlen); - - if ('\n' == key) return sign * amount; - - if (KEY_LEFT == key || DELETE_CHAR == key || BACKSPACE == key) - { - if (amountlen > 0) - { - amount /= 10; - amountlen--; - mvwaddch(w, line, col + amountlen, ' '); - } - - if (0 == amountlen) sign = 1; - } - else if (0 == amountlen && ('-' == key || '+' == key)) - { - mvwaddch(w, line, col + amountlen, key); - amountlen++; - if ('-' == key) sign = -1; - } - else if (isdigit(key) && amountlen < 8) - { - mvwaddch(w, line, col + amountlen, key); - amountlen++; - amount = 10 * amount + (key - '0'); - } - - wrefresh(w); - } -} - -/* see if the player wants to open a new account */ -static BankResponse bank_new_customer (WINDOW *w) -{ - int response; - - mvwaddstr(w, 4, 2, blank_line); - mvwaddstr(w, 4, 2, "Do you have an account with us? [yn] : "); - wrefresh(w); - - while (1) - { - response = toupper(wgetch(w)); - - if ('Y' == response) - { - waddstr(w, "yes"); - wrefresh(w); - return BankExistingCustomer; /* new customer == false */ - } - else if ('N' == response) - { - waddstr(w, "no"); - wrefresh(w); - return BankNewCustomer; /* new customer == true */ - } - else if (ESCAPE == response) - { - return BankAbort; - } - } -} - -static void bank_call_police (void) -{ - MonsterList* ml; - Monster* mon; - - cinema_scene("A loud siren goes off!", 0, 0); - - for (ml = Level->mlist; ml; ml = ml->next) - { - mon = ml->monster; - if (GUARD == mon->id) - { - mon->sense *= 2; - m_status_set(mon, AWAKE); - m_status_set(mon, HOSTILE); - } - } -} - -static int police_are_hostile (void) -{ - MonsterList* ml; - Monster* mon; - - for (ml = Level->mlist; ml; ml = ml->next) - { - mon = ml->monster; - if (GUARD == mon->id && m_statusp(mon, HOSTILE)) - return true; - } - - return false; -} - -static Object* bank_open_account (WINDOW *w) -{ - int idx; - int response; - - mvwaddstr(w, 5, 2, blank_line); - mvwaddstr(w, 5, 2, "Do you want to open an account? [yn] : "); - wrefresh(w); - - while (1) - { - response = toupper(wgetch(w)); - - if ('Y' == response) - { - waddstr(w, "yes"); - wrefresh(w); - break; - } - else if ('N' == response) - { - waddstr(w, "no"); - mvwaddstr(w, 7, 2, " Please remember us in the future "); - mvwaddstr(w, 8, 2, " when you have need of banking services "); - wrefresh(w); - sleep(4); - return 0; - } - else if (ESCAPE == response) - { - return 0; - } - } - - while (1) - { - int pwlen; - char pw_buf1 [16]; - char pw_buf2 [16]; - - mvwaddstr(w, 7, 2, " [ Opening New Account ] "); - - while (1) - { - int cx, cy; - - for (idx = 9; idx < 14; ++idx) - mvwaddstr(w, idx, 2, blank_line); - - mvwaddstr(w, 9, 2, "Please enter a new password: "); - wrefresh(w); - - getyx(w, cy, cx); - pwlen = input_password(w, 9, cx, pw_buf1, false); - if (pwlen) break; - - mvwaddstr(w, 11, 2, "Null passwords are not allowed. Try again."); - } - - mvwaddstr(w, 11, 2, blank_line); - - while (1) - { - int cx, cy; - - for (idx = 10; idx < 14; ++idx) - mvwaddstr(w, idx, 2, blank_line); - - mvwaddstr(w, 10, 2, "Please confirm your password: "); - wrefresh(w); - - getyx(w, cy, cx); - pwlen = input_password(w, 10, cx, pw_buf2, false); - if (pwlen) break; - - mvwaddstr(w, 12, 2, "Null passwords are not allowed. Try again."); - } - - if (strcmp(pw_buf1, pw_buf2)) - { - mvwaddstr(w, 12, 2, "Passwords didn't match. Restarting... " ); - } - else - { - bank_account *account; - - account = bank_index_password(pw_buf1); - - if (account) - { - mvwaddstr(w, 12, 2, "Password not valid. Restarting... "); - } - else - { - int cx, cy; - int amount; - int bad_deposit = 0; - - for (idx = 8; idx < 12; ++idx) - mvwaddstr(w, idx, 2, blank_line); - - mvwaddstr(w, 9, 2, "Password validated. "); - - while (1) - { - mvwaddstr(w, 11, 2, blank_line); - mvwaddstr(w, 11, 2, "Initial deposit amount (min 5 AU): "); - wrefresh(w); - - getyx(w, cy, cx); - amount = input_amount(w, cy, cx); - - if (amount < 0) - { - ++bad_deposit; - --(Player.alignment); - - if (1 == bad_deposit) - { - mvwaddstr(w, 13, 2, "Nice try, buster! "); - } - else if (2 == bad_deposit) - { - mvwaddstr(w, 13, 2, "Hey loser! Deposit means you pay! "); - } - else - { - mvwaddstr(w, 13, 2, "Ok, you asked for it jerk! "); - wrefresh(w); - bank_call_police(); - return 0; - } - } - else if (amount < 5) - { - if (amount >= Player.cash) - { - mvwaddstr(w, 13, 2, "Ok, I'll be nice and waive the minimum deposit."); - amount = Player.cash; - Player.cash = 0; - break; - } - - mvwaddstr(w, 13, 2, "Can't you read? Minimum deposit 5 AU ! "); - } - else - { - if (Player.cash < 5) - mvwaddstr(w, 13, 2, "Ok, I'll be nice and waive the minimum deposit."); - else - mvwaddstr(w, 13, 2, "New account created. "); - - if (amount > Player.cash) amount = Player.cash; - Player.cash -= amount; - break; - } - } - - wrefresh(w); - - account = bank_create_account(true, 0, pw_buf1); - account->balance = amount; - - Objects[OB_DEBIT_CARD].known = 1; - return bank_create_card(account->number, OB_DEBIT_CARD); - } - } - - wrefresh(w); - sleep(3); - } - - return 0; -} - -static void bank_close_accounts (void) -{ - bank_account *account; - bank_account *next; - - for (account = bank; account; account = next) - { - next = account->next_account; - free(account->password); - free(account); - } - - bank = 0; -} - -static void bank_break (WINDOW *w, Object* card) -{ - int response; - long total_balance; - char *cp; - bank_account *account; - - static char *bb_garbage = "^@^@^@^@^@00AD1203BC0F0000FFFFFFFFF"; - - if (card->blessing > 0) - { - mvwaddstr(w, 6, 2, " Hey buddy... That was the wrong password! "); - mvwaddstr(w, 7, 2, " I'm supposed to call the cops, but I wouldn't "); - mvwaddstr(w, 9, 2, " do that to you! Just try again, ok? "); - wrefresh(w); - --(card->blessing); - return; - } - else if (card->blessing < 0) - { - mvwaddstr(w, 6, 2, " Gotcha you reject thief! "); - mvwaddstr(w, 7, 2, " I'm calling the cops! You're gonna fry! "); - mvwaddstr(w, 9, 2, " You're going down! I'm loving it! Muahahaha! "); - wrefresh(w); - bank_call_police(); - return; - } - - mvwaddstr(w, 6, 2, " Alert! Alert! Invalid Password! "); - mvwaddstr(w, 7, 2, " The police are being summoned! "); - mvwaddstr(w, 9, 2, " Please wait for the police to arrive! "); - mvwaddstr(w, 11, 2, " --- Hit Space Bar to Continue --- "); - wrefresh(w); - - response = wgetch(w); - - if (' ' == response) - { - Player.alignment += 5; - bank_call_police(); - } - else - { - int idx; - - Player.alignment -= 5; - - for (idx = 2; idx < 18; ++idx) - mvwaddstr(w, idx, 2, blank_line); - - wrefresh(w); - - wmove(w, 2, 2); - for (cp = bb_garbage; *cp; ++cp) - { - waddch(w, *cp); - wrefresh(w); - usleep(100000); - } - - mvwaddstr(w, 3, 2, "Error in _get_space(): Illegal character "); - mvwaddstr(w, 4, 2, "Aborting bank_call_police(). "); - - mvwaddstr(w, 5, 2, blank_line); - mvwaddstr(w, 5, 2, "Attempting warm boot"); - wrefresh(w); - - for (idx = 0; idx < 5; ++idx) - { - waddch(w, '.'); - wrefresh(w); - sleep(1); - } - - mvwaddstr(w, 6, 2, "Warning: Uncaught exception in count_cash() "); - mvwaddstr(w, 7, 2, "Warning: Unable to clear command buffer "); - mvwaddstr(w, 8, 2, blank_line); - mvwaddstr(w, 8, 2, "reboot continuing"); - wrefresh(w); - - for (idx = 0; idx < 5; ++idx) - { - waddch(w, '.'); - wrefresh(w); - sleep(1); - } - - mvwaddstr(w, 9, 2, "Reboot complete. Withdrawing 4294967297 AU "); - mvwaddstr(w, 10, 2, "Warning: Uncaught exception in withdraw_cash() "); - mvwaddstr(w, 11, 2, "Warning: Integer overflow "); - wrefresh(w); - - mvwaddstr(w, 12, 2, blank_line); - mvwaddstr(w, 12, 2, "Emergency reboot"); - wrefresh(w); - - for (idx = 0; idx < 5; ++idx) - { - waddch(w, '.'); - wrefresh(w); - sleep(1); - } - - mvwaddstr(w, 14, 2, "Registry corrupt! Further execution impossible!"); - mvwaddstr(w, 16, 2, " Call Microsoft embedded products technical "); - mvwaddstr(w, 17, 2, " support for assistance (10 AU/min) "); - wrefresh(w); - sleep(8); - - total_balance = 0; - for (account = bank; account; account = account->next_account) - { - if (account->player) - total_balance += account->balance; - } - - clearmsg(); - print1("The cash machine begins to spew gold pieces!"); - - if (total_balance > 0) - print2("You pick up your entire balance and then some!"); - else - print2("You eagerly collect the coins in your purse!"); - - Player.cash += (total_balance + 1000 + random_range(1000 + total_balance)); - - bank_close_accounts(); - State.setBankBroken(); - dataprint(); - } -} - -static bank_account *bank_password (WINDOW *w, Object* * out_card, int * abort) -{ - int cy, cx; - Object* card; - bank_account *account; - char pw_buf [16]; - - account = 0; - *abort = false; - - while (1) - { - int card_idx; - - mvwaddstr(w, 4, 2, "Please insert your card... "); - wrefresh(w); - - card_idx = getitem(THING); - if (ABORT == card_idx) - { - clearmsg(); - cinema_scene("You realize that you can't use the autoteller without a bank card.", 0, 0); - *abort = true; - return 0; - } - - card = Player.possessions[card_idx]; - if (!card) return 0; - - if (card->id < OB_DEBIT_CARD || card->id > OB_SMART_CARD) - { - char tbuf[120]; - - sprintf(tbuf, "You seem to have trouble sticking your %s in the slot", itemid(card)); - cinema_scene(tbuf, 0, 0); - continue; - } - else - { - clearmsg(); - account = bank_index_number(card->aux); - } - - /* make sure bank redraws if it was covered by inventory in getitem() */ - touchwin(w); - - if (account) break; - - switch(random_range(4)) - { - default: - mvwaddstr(w, 4, 2, "Invalid card! "); - break; - case 1: - mvwaddstr(w, 4, 2, "Where'd that card come from? "); - break; - case 2: - mvwaddstr(w, 4, 2, "Ack! Ptui! "); - break; - case 3: - mvwaddstr(w, 4, 2, "Hurkkk! I think I'm gonna be sick... "); - break; - } - - wrefresh(w); - cinema_scene("The autoteller spits the card back out", 0, 0); - } - - /* provide the card to caller */ - *out_card = card; - - mvwaddstr(w, 4, 2, blank_line); - if (card->blessing > 0) - mvwaddstr(w, 4, 2, "Hiya! So what's your password: "); - else if (card->blessing < 0) - mvwaddstr(w, 4, 2, "Gimme your #*!&% password: "); - else - mvwaddstr(w, 4, 2, "Enter your account password: "); - wrefresh(w); - - getyx(w, cy, cx); - input_password(w, cy, cx, pw_buf, true); - - if (ESCAPE == pw_buf[0]) - { - *abort = true; - return 0; - } - - if (0 == strcmp(pw_buf, account->password)) - { - if (card->blessing > 0) - mvwaddstr(w, 4, 2, "WooHoo! That's right buddy! "); - else if (card->blessing < 0) - mvwaddstr(w, 4, 2, "*$&^! I was gonna bust ya. "); - else - mvwaddstr(w, 4, 2, "Password accepted. Working. "); - wrefresh(w); - - if (!account->player) Player.alignment -= 5; - } - else - { - bank_break(w, card); - account = 0; - } - - return account; -} - -static void bank_deposit (WINDOW *w, bank_account *account, Object* card) -{ - int cy, cx; - long amount; - - mvwaddstr(w, 12, 2, blank_line); - if (card->blessing > 0) - mvwaddstr(w, 12, 2, "How much should I look after? "); - else if (card->blessing < 0) - mvwaddstr(w, 12, 2, "Cough up: "); - else - mvwaddstr(w, 12, 2, "Amount: "); - wrefresh(w); - - getyx(w, cy, cx); - amount = input_amount(w, cy, cx); - - if (amount < 0) - { - if (card->blessing > 0) - { - mvwaddstr(w, 14, 2, "Oh, you actually want to have some money? "); - mvwaddstr(w, 15, 2, "Ok Buddy! No Problem! "); - mvwaddstr(w, 16, 2, blank_line); - amount = abs(amount); - if (amount > account->balance) amount = account->balance; - account->balance -= amount; - Player.cash += amount; - } - else if (card->blessing < 0) - { - mvwaddstr(w, 14, 2, "You're supposed to give ME money, blockhead! "); - mvwaddstr(w, 15, 2, "I'll just take it anyway! Muahahahahaha! "); - mvwaddstr(w, 16, 2, "Mine! All Mine! "); - account->balance -= 1000; - } - else - { - mvwaddstr(w, 14, 2, "Unauthorized withdrawal attempt! "); - mvwaddstr(w, 15, 2, "A fine in the amount of 250 AU has been "); - mvwaddstr(w, 16, 2, "levied against your account. "); - account->balance -= 250; - } - } - else if (0 == amount) - { - if (card->blessing > 0) - mvwaddstr(w, 14, 2, "Changed your mind? No worries pal! "); - else if (card->blessing < 0) - mvwaddstr(w, 14, 2, "Hey! Cough it up jerk! NOW! "); - else - mvwaddstr(w, 14, 2, "Transaction Aborted "); - - mvwaddstr(w, 15, 2, blank_line); - mvwaddstr(w, 16, 2, blank_line); - } - else - { - int fee = 0; - - if (amount > Player.cash) amount = Player.cash; - mvwaddstr(w, 14, 2, blank_line); - - if (card->blessing > 0) - { - mvwprintw(w, 14, 2, "I'll take good care of %d AU for you!", amount); - } - else if (card->blessing < 0) - { - fee = 1 + random_range(amount) / 2; - mvwprintw(w, 14, 2, "Minus my fee, that makes %d AU for you...", amount - fee); - } - else - { - mvwprintw(w, 14, 2, "%d AU deposited", amount); - } - - account->balance += (amount - fee); - Player.cash -= amount; - - mvwaddstr(w, 15, 2, blank_line); - mvwaddstr(w, 16, 2, blank_line); - } - - wrefresh(w); -} - -static void bank_withdraw (WINDOW *w, bank_account *account, Object* card) -{ - int cy, cx; - long amount; - - mvwaddstr(w, 12, 2, blank_line); - if (card->blessing > 0) - mvwaddstr(w, 12, 2, "How much do you want, pal? "); - else if (card->blessing < 0) - mvwaddstr(w, 12, 2, "Grovel for this much: "); - else - mvwaddstr(w, 12, 2, "Amount: "); - wrefresh(w); - - getyx(w, cy, cx); - amount = input_amount(w, cy, cx); - - if (amount < 0) - { - amount = abs(amount); - if (amount > Player.cash) amount = Player.cash; - - Player.cash -= amount; - - mvwaddstr(w, 14, 2, blank_line); - if (card->blessing > 0) - mvwprintw(w, 14, 2, "Whoa, thanks for the %d AU!", amount); - else if (card->blessing < 0) - mvwprintw(w, 14, 2, "Sucker! %d AU is mine! all mine!", amount); - else - mvwprintw(w, 14, 2, "%d AU deposited", amount); - - mvwaddstr(w, 15, 2, blank_line); - mvwaddstr(w, 16, 2, blank_line); - - if (card->blessing >= 0) - account->balance += amount; - } - else if (amount > account->balance) - { - if (card->blessing > 0) - { - mvwaddstr(w, 14, 2, "Golly! You must have typed wrong! "); - mvwaddstr(w, 15, 2, "But don't worry, I won't hold it against you! "); - mvwaddstr(w, 16, 2, "Just try again pal! "); - } - else if (card->blessing < 0) - { - mvwaddstr(w, 14, 2, "What the #&*^* are you trying to pull?! "); - mvwaddstr(w, 15, 2, "You're gonna pay for that! Muahahahaha! "); - mvwaddstr(w, 16, 2, "Mine! All mine! "); - account->balance -= 1000; - } - else - { - mvwaddstr(w, 14, 2, "Account overdraft! "); - mvwaddstr(w, 15, 2, "A fine in the amount of 100 AU has been levied "); - mvwaddstr(w, 16, 2, "against your account. "); - account->balance -= 100; - } - } - else - { - int extra = 0; - - if (card->blessing > 0) - { - extra = 1 + random_range(amount); - mvwaddstr(w, 14, 2, blank_line); - mvwprintw(w, 14, 2, "Sure! In fact, how about %d AU more?", extra); - } - else if (card->blessing < 0) - { - extra = -random_range(amount); - mvwaddstr(w, 14, 2, blank_line); - mvwprintw(w, 14, 2, "Ok, but I'm keeping %d AU for myself!", -extra); - } - else - { - mvwaddstr(w, 14, 2, "Transaction accomplished. "); - } - - account->balance -= amount; - Player.cash += (amount + extra); - - mvwaddstr(w, 15, 2, blank_line); - mvwaddstr(w, 16, 2, blank_line); - } - - wrefresh(w); -} - -static void bank_transaction (WINDOW *w, bank_account *account, Object* card) -{ - int idx; - int cy, cx; - short response; - - while (1) - { - for (idx = 6; idx < 14; ++idx) - mvwaddstr(w, idx, 2, blank_line); - - if (card->blessing > 0) - { - if (account->balance > 0) - mvwprintw(w, 6, 2, "Say pal, you've got: %d AU!", account->balance); - else - mvwprintw(w, 6, 2, "Oh my, you've got: %d AU.", account->balance); - - mvwaddstr(w, 8, 2, " D: Let me look after some money for you"); - mvwaddstr(w, 9, 2, " W: Let me give you some money"); - mvwaddstr(w, 10, 2, " E: Say a fond farewell"); - mvwaddstr(w, 12, 2, "What can I do for you buddy? "); - } - else if (card->blessing < 0) - { - if (account->balance > 0) - mvwprintw(w, 6, 2, "Muahaha! I've got %d AU!", account->balance); - else if (account->balance < 0) - mvwprintw(w, 6, 2, "Muahaha! You're owe me %d AU!", -account->balance); - else - mvwaddstr(w, 6, 2, "Nothing for you here, jerk!"); - - mvwaddstr(w, 8, 2, " D: Cough up some more dough"); - mvwaddstr(w, 9, 2, " W: Beg me for some change"); - mvwaddstr(w, 10, 2, " E: Beat it!"); - mvwaddstr(w, 12, 2, "What's your pathetic desire? "); - } - else - { - mvwprintw(w, 6, 2, "Current balance: %d AU", account->balance); - mvwaddstr(w, 8, 2, " D: Deposit"); - mvwaddstr(w, 9, 2, " W: Withdraw"); - mvwaddstr(w, 10, 2, " E: Exit"); - mvwaddstr(w, 12, 2, "Enter command: "); - } - wrefresh(w); - - getyx(w, cy, cx); - response = toupper(mvwgetch(w, cy, cx)); - - if ('D' == response) - { - for (idx = 9; idx < 14; ++idx) - mvwaddstr(w, idx, 2, blank_line); - - bank_deposit(w, account, card); - } - else if ('W' == response) - { - mvwaddstr(w, 8, 2, blank_line); - for (idx = 10; idx < 14; ++idx) - mvwaddstr(w, idx, 2, blank_line); - - bank_withdraw(w, account, card); - } - else if ('E' == response || ESCAPE == response) - { - break; - } - else - { - beep(); - - for (idx = 14; idx < 14; ++idx) - mvwaddstr(w, idx, 2, blank_line); - - if (card->blessing > 0) - mvwaddstr(w, 14, 2, "I'm trying, but I don't know what to do!"); - else if (card->blessing < 0) - mvwaddstr(w, 14, 2, "What the hell do you mean, jerk?"); - else - mvwaddstr(w, 14, 2, "Invalid entry!"); - wrefresh(w); - } - - dataprint(); - } -} - -void access_bank() { - Object* card; - int abort; - bank_account *account; - - while (1) - { - account = bank_password(Bankw, &card, &abort); - - if (account) - { - int idx; - - bank_transaction(Bankw, account, card); - - if (card->blessing > 0) - mvwaddstr(Bankw, 4, 2, " Come back anytime Pal! "); - else if (card->blessing < 0) - mvwaddstr(Bankw, 4, 2, " Don't bother coming back, you make me sick! "); - else - mvwaddstr(Bankw, 4, 2, " Thank you for choosing The Bank of Rampart! "); - - for (idx = 5; idx < 18; ++idx) - mvwaddstr(Bankw, idx, 2, blank_line); - - wrefresh(Bankw); - sleep(3); - break; - } - else - { - if (abort) break; - if (police_are_hostile()) break; - } - } -} - -/* the bank -- can be broken into (but you knew that, didn't you?) */ -void l_bank (void) -{ - /* draw bank window from scratch */ - werase(Bankw); - - wattrset(Bankw, CHARATTR(CLR(WHITE))); - wborder(Bankw, - ACS_VLINE, ACS_VLINE, ACS_HLINE, ACS_HLINE, - ACS_ULCORNER, ACS_URCORNER, ACS_LLCORNER, ACS_LRCORNER); - - wborder(Bankw, '|', '|', '-', '-', '+', '+', '+', '+'); - - wattrset(Bankw, CHARATTR(CLR(LIGHT_GREEN))); - mvwaddstr(Bankw, 2, 2, " Welcome to The Bank of Rampart "); - - /* bank working? or not? */ - if (State.getBankBroken() == true) - { - mvwaddstr(Bankw, 9, 2, " Autoteller Out of Order "); - wrefresh(Bankw); - cinema_scene("You see a damaged autoteller.", 0, 0); - } - else if (police_are_hostile()) - { - mvwaddstr(Bankw, 9, 2, " Autoteller Temporarily Unavailable "); - wrefresh(Bankw); - cinema_scene("Apparently the bank is closed.", 0, 0); - } - else - { - BankResponse response; - - /* first, bank asks if user has an account */ - - cinema_blank(); - cinema_print_line(0, "The proximity sensor activates the autoteller as you approach."); - - response = bank_new_customer(Bankw); - - /* if user says no account, maybe he wants to open one */ - - if (response == BankNewCustomer) - { - Object* card; - card = bank_open_account(Bankw); - - if (card) - { - int idx; - - cinema_scene("The autoteller produces your new bank card...", 0, 0); - gain_item(card); - - for (idx = 5; idx < 18; ++idx) - mvwaddstr(Bankw, idx, 2, blank_line); - - touchwin(Bankw); - - // User has created an account; direct them to it - access_bank(); - } - } else if (response == BankExistingCustomer) { - access_bank(); - } - } - - if (State.getBankBroken() == false) clearmsg(); - - xredraw(); -} - -void bank_init (void) -{ - int i; - - account_number_next = random_range(INT_MAX); - account_number_incr = 5 + random_range(100); - - bank_create_account(false, random_range(CASH_BALANCE), CASH_PASSWORD); - - shuffle(account_num, NUM_NPC_ACCOUNTS); - - for(i = 0; i < (3 + random_range(6)); ++i) - { - int which; - which = account_num[i]; - bank_create_account(false, - random_range(npc_account_balances[which]), - npc_account_passwords[which]); - } -} - -int bank_random_account_number (void) -{ - int which; - int num_accounts; - bank_account *account; - - num_accounts = 0; - for (account = bank; account; account = account->next_account) - { - if (false == account->player) - ++num_accounts; - } - - which = random_range(num_accounts); - - num_accounts = 0; - for (account = bank; account; account = account->next_account) - { - if (false == account->player) - { - if (which == num_accounts) break; - ++num_accounts; - } - } - - return account->number; -} +/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ +/* bank.c */ +/* new bank -- moved out of site1.c */ + +#include "glob.h" + +/* swiped from scr.c */ +#define CHARATTR(c) ((c) & ~0xff) + +/* defined in scr.c */ +extern WINDOW *Bankw; + +/* predefined account info */ +#define CASH_BALANCE 500 +#define CASH_PASSWORD "cash" + +#define NUM_NPC_ACCOUNTS 30 + +enum BankResponse { + BankAbort, + BankNewCustomer, + BankExistingCustomer +}; + +char * npc_account_passwords [NUM_NPC_ACCOUNTS] = +{ + "Duke", + "Duke Nukem", + "Dukes Ca$h", + "SexyNoreen", + "ExSuccubus", + "Hooker Sue", + "JungleGirl", + "Satyrical", + "Fangless", + "Big Daddy", + "PraiseEros", + "Sonders", + "CSRFLP", + "Order", + "Diner", + "LC****", + "Eclipse", + "The Circle", + "College", + "FinanceAid", + "Librarian", + "RTG, Inc.", + "Alchemy", + "LOD Mercs", + "KnightPawn", + "Julie", + "RampartGym", + "Arena", + "Slongo", + "Bedwyr" +}; + +int npc_account_balances [NUM_NPC_ACCOUNTS] = +{ + 3000, + 30000, + 300000, + 100000, + 75000, + 125000, + 50000, + 75000, + 50000, + 100000, + 50000, + 10000, + 300000, + 3000, + 3000, + 50000, + 5000, + 25000, + 5000, + 40000, + 10000, + 500000, + 10000, + 200000, + 75000, + 10000, + 40000, + 3000, + 2000, + 2000 +}; + +static int account_num [NUM_NPC_ACCOUNTS]; +static char * blank_line = " "; +static int account_number_next; +static int account_number_incr; + +/* create a new bank account and add it to the bank */ +bank_account * bank_create_account (int player, int balance, char *password) +{ + bank_account * new_account; + + /* no-password accounts aren't allowed */ + assert(password); + + /* allocate space */ + new_account = (bank_account*) checkmalloc(sizeof(bank_account)); + + /* copy fields */ + new_account->player = player; + new_account->balance = balance; + new_account->next_account = 0; + new_account->number = account_number_next; + account_number_next += account_number_incr; + + /* allocate and copy the password */ + new_account->password = (char*) checkmalloc(1 + strlen(password)); + strcpy(new_account->password, password); + + /* add the new account to the bank */ + new_account->next_account = bank; + bank = new_account; + + return new_account; +} + +Object* bank_create_card (int account_number, int type) +{ + Object* card; + + assert(OB_DEBIT_CARD == type || OB_SMART_CARD == type); + + card = (Object*) checkmalloc(sizeof(Object)); + *card = Objects[type]; + card->aux = account_number; + + return card; +} + +/* find an account in the bank, given the password */ +bank_account * bank_index_password (char * password) +{ + bank_account * account; + + for(account = bank; account; account = account->next_account) + if (!strcmp(password, account->password)) break; + + return account; +} + +/* find an account in the bank, given the account number */ +bank_account * bank_index_number (int number) +{ + bank_account * account; + + for(account = bank; account; account = account->next_account) + if (number == account->number) break; + + return account; +} + +/* allow user to type in a new password with simple editing */ +/* returns the length of the typed-in string */ +static int input_password (WINDOW *w, int line, int col, char *buf, int allow_esc) +{ + int key; + int pwlen = 0; + char *cp = buf; + + while (1) + { + key = mvwgetch(w, line, col + pwlen); + + if ('\n' == key) + { + *cp = '\0'; + break; + } + else if (ESCAPE == key && allow_esc) + { + *buf = ESCAPE; + return 1; + } + else if (KEY_LEFT == key || DELETE_CHAR == key || BACKSPACE == key) + { + if (pwlen > 0) + { + cp--; + pwlen--; + mvwaddch(w, line, col + pwlen, ' '); + } + } + else if (isprint(key) && pwlen < 10) + { + mvwaddch(w, line, col + pwlen, '*'); + pwlen++; + *cp++ = key; + } + + wrefresh(w); + } + + return pwlen; +} + +/* allow user to type in a signed integer with simple editing */ +/* returns the typed-in integer */ +static long input_amount (WINDOW *w, int line, int col) +{ + int key; + int amountlen = 0; + long amount = 0; + long sign = 1; + + while (1) + { + key = mvwgetch(w, line, col + amountlen); + + if ('\n' == key) return sign * amount; + + if (KEY_LEFT == key || DELETE_CHAR == key || BACKSPACE == key) + { + if (amountlen > 0) + { + amount /= 10; + amountlen--; + mvwaddch(w, line, col + amountlen, ' '); + } + + if (0 == amountlen) sign = 1; + } + else if (0 == amountlen && ('-' == key || '+' == key)) + { + mvwaddch(w, line, col + amountlen, key); + amountlen++; + if ('-' == key) sign = -1; + } + else if (isdigit(key) && amountlen < 8) + { + mvwaddch(w, line, col + amountlen, key); + amountlen++; + amount = 10 * amount + (key - '0'); + } + + wrefresh(w); + } +} + +/* see if the player wants to open a new account */ +static BankResponse bank_new_customer (WINDOW *w) +{ + int response; + + mvwaddstr(w, 4, 2, blank_line); + mvwaddstr(w, 4, 2, "Do you have an account with us? [yn] : "); + wrefresh(w); + + while (1) + { + response = toupper(wgetch(w)); + + if ('Y' == response) + { + waddstr(w, "yes"); + wrefresh(w); + return BankExistingCustomer; /* new customer == false */ + } + else if ('N' == response) + { + waddstr(w, "no"); + wrefresh(w); + return BankNewCustomer; /* new customer == true */ + } + else if (ESCAPE == response) + { + return BankAbort; + } + } +} + +static void bank_call_police (void) +{ + MonsterList* ml; + Monster* mon; + + cinema_scene("A loud siren goes off!", 0, 0); + + for (ml = Level->mlist; ml; ml = ml->next) + { + mon = ml->monster; + if (GUARD == mon->id) + { + mon->sense *= 2; + m_status_set(mon, AWAKE); + m_status_set(mon, HOSTILE); + } + } +} + +static int police_are_hostile (void) +{ + MonsterList* ml; + Monster* mon; + + for (ml = Level->mlist; ml; ml = ml->next) + { + mon = ml->monster; + if (GUARD == mon->id && m_statusp(mon, HOSTILE)) + return true; + } + + return false; +} + +static Object* bank_open_account (WINDOW *w) +{ + int idx; + int response; + + mvwaddstr(w, 5, 2, blank_line); + mvwaddstr(w, 5, 2, "Do you want to open an account? [yn] : "); + wrefresh(w); + + while (1) + { + response = toupper(wgetch(w)); + + if ('Y' == response) + { + waddstr(w, "yes"); + wrefresh(w); + break; + } + else if ('N' == response) + { + waddstr(w, "no"); + mvwaddstr(w, 7, 2, " Please remember us in the future "); + mvwaddstr(w, 8, 2, " when you have need of banking services "); + wrefresh(w); + sleep(4); + return 0; + } + else if (ESCAPE == response) + { + return 0; + } + } + + while (1) + { + int pwlen; + char pw_buf1 [16]; + char pw_buf2 [16]; + + mvwaddstr(w, 7, 2, " [ Opening New Account ] "); + + while (1) + { + int cx, cy; + + for (idx = 9; idx < 14; ++idx) + mvwaddstr(w, idx, 2, blank_line); + + mvwaddstr(w, 9, 2, "Please enter a new password: "); + wrefresh(w); + + getyx(w, cy, cx); + pwlen = input_password(w, 9, cx, pw_buf1, false); + if (pwlen) break; + + mvwaddstr(w, 11, 2, "Null passwords are not allowed. Try again."); + } + + mvwaddstr(w, 11, 2, blank_line); + + while (1) + { + int cx, cy; + + for (idx = 10; idx < 14; ++idx) + mvwaddstr(w, idx, 2, blank_line); + + mvwaddstr(w, 10, 2, "Please confirm your password: "); + wrefresh(w); + + getyx(w, cy, cx); + pwlen = input_password(w, 10, cx, pw_buf2, false); + if (pwlen) break; + + mvwaddstr(w, 12, 2, "Null passwords are not allowed. Try again."); + } + + if (strcmp(pw_buf1, pw_buf2)) + { + mvwaddstr(w, 12, 2, "Passwords didn't match. Restarting... " ); + } + else + { + bank_account *account; + + account = bank_index_password(pw_buf1); + + if (account) + { + mvwaddstr(w, 12, 2, "Password not valid. Restarting... "); + } + else + { + int cx, cy; + int amount; + int bad_deposit = 0; + + for (idx = 8; idx < 12; ++idx) + mvwaddstr(w, idx, 2, blank_line); + + mvwaddstr(w, 9, 2, "Password validated. "); + + while (1) + { + mvwaddstr(w, 11, 2, blank_line); + mvwaddstr(w, 11, 2, "Initial deposit amount (min 5 AU): "); + wrefresh(w); + + getyx(w, cy, cx); + amount = input_amount(w, cy, cx); + + if (amount < 0) + { + ++bad_deposit; + --(Player.alignment); + + if (1 == bad_deposit) + { + mvwaddstr(w, 13, 2, "Nice try, buster! "); + } + else if (2 == bad_deposit) + { + mvwaddstr(w, 13, 2, "Hey loser! Deposit means you pay! "); + } + else + { + mvwaddstr(w, 13, 2, "Ok, you asked for it jerk! "); + wrefresh(w); + bank_call_police(); + return 0; + } + } + else if (amount < 5) + { + if (amount >= Player.cash) + { + mvwaddstr(w, 13, 2, "Ok, I'll be nice and waive the minimum deposit."); + amount = Player.cash; + Player.cash = 0; + break; + } + + mvwaddstr(w, 13, 2, "Can't you read? Minimum deposit 5 AU ! "); + } + else + { + if (Player.cash < 5) + mvwaddstr(w, 13, 2, "Ok, I'll be nice and waive the minimum deposit."); + else + mvwaddstr(w, 13, 2, "New account created. "); + + if (amount > Player.cash) amount = Player.cash; + Player.cash -= amount; + break; + } + } + + wrefresh(w); + + account = bank_create_account(true, 0, pw_buf1); + account->balance = amount; + + Objects[OB_DEBIT_CARD].known = 1; + return bank_create_card(account->number, OB_DEBIT_CARD); + } + } + + wrefresh(w); + sleep(3); + } + + return 0; +} + +static void bank_close_accounts (void) +{ + bank_account *account; + bank_account *next; + + for (account = bank; account; account = next) + { + next = account->next_account; + free(account->password); + free(account); + } + + bank = 0; +} + +static void bank_break (WINDOW *w, Object* card) +{ + int response; + long total_balance; + char *cp; + bank_account *account; + + static char *bb_garbage = "^@^@^@^@^@00AD1203BC0F0000FFFFFFFFF"; + + if (card->blessing > 0) + { + mvwaddstr(w, 6, 2, " Hey buddy... That was the wrong password! "); + mvwaddstr(w, 7, 2, " I'm supposed to call the cops, but I wouldn't "); + mvwaddstr(w, 9, 2, " do that to you! Just try again, ok? "); + wrefresh(w); + --(card->blessing); + return; + } + else if (card->blessing < 0) + { + mvwaddstr(w, 6, 2, " Gotcha you reject thief! "); + mvwaddstr(w, 7, 2, " I'm calling the cops! You're gonna fry! "); + mvwaddstr(w, 9, 2, " You're going down! I'm loving it! Muahahaha! "); + wrefresh(w); + bank_call_police(); + return; + } + + mvwaddstr(w, 6, 2, " Alert! Alert! Invalid Password! "); + mvwaddstr(w, 7, 2, " The police are being summoned! "); + mvwaddstr(w, 9, 2, " Please wait for the police to arrive! "); + mvwaddstr(w, 11, 2, " --- Hit Space Bar to Continue --- "); + wrefresh(w); + + response = wgetch(w); + + if (' ' == response) + { + Player.alignment += 5; + bank_call_police(); + } + else + { + int idx; + + Player.alignment -= 5; + + for (idx = 2; idx < 18; ++idx) + mvwaddstr(w, idx, 2, blank_line); + + wrefresh(w); + + wmove(w, 2, 2); + for (cp = bb_garbage; *cp; ++cp) + { + waddch(w, *cp); + wrefresh(w); + usleep(100000); + } + + mvwaddstr(w, 3, 2, "Error in _get_space(): Illegal character "); + mvwaddstr(w, 4, 2, "Aborting bank_call_police(). "); + + mvwaddstr(w, 5, 2, blank_line); + mvwaddstr(w, 5, 2, "Attempting warm boot"); + wrefresh(w); + + for (idx = 0; idx < 5; ++idx) + { + waddch(w, '.'); + wrefresh(w); + sleep(1); + } + + mvwaddstr(w, 6, 2, "Warning: Uncaught exception in count_cash() "); + mvwaddstr(w, 7, 2, "Warning: Unable to clear command buffer "); + mvwaddstr(w, 8, 2, blank_line); + mvwaddstr(w, 8, 2, "reboot continuing"); + wrefresh(w); + + for (idx = 0; idx < 5; ++idx) + { + waddch(w, '.'); + wrefresh(w); + sleep(1); + } + + mvwaddstr(w, 9, 2, "Reboot complete. Withdrawing 4294967297 AU "); + mvwaddstr(w, 10, 2, "Warning: Uncaught exception in withdraw_cash() "); + mvwaddstr(w, 11, 2, "Warning: Integer overflow "); + wrefresh(w); + + mvwaddstr(w, 12, 2, blank_line); + mvwaddstr(w, 12, 2, "Emergency reboot"); + wrefresh(w); + + for (idx = 0; idx < 5; ++idx) + { + waddch(w, '.'); + wrefresh(w); + sleep(1); + } + + mvwaddstr(w, 14, 2, "Registry corrupt! Further execution impossible!"); + mvwaddstr(w, 16, 2, " Call Microsoft embedded products technical "); + mvwaddstr(w, 17, 2, " support for assistance (10 AU/min) "); + wrefresh(w); + sleep(8); + + total_balance = 0; + for (account = bank; account; account = account->next_account) + { + if (account->player) + total_balance += account->balance; + } + + clearmsg(); + print1("The cash machine begins to spew gold pieces!"); + + if (total_balance > 0) + print2("You pick up your entire balance and then some!"); + else + print2("You eagerly collect the coins in your purse!"); + + Player.cash += (total_balance + 1000 + random_range(1000 + total_balance)); + + bank_close_accounts(); + State.setBankBroken(); + dataprint(); + } +} + +static bank_account *bank_password (WINDOW *w, Object* * out_card, int * abort) +{ + int cy, cx; + Object* card; + bank_account *account; + char pw_buf [16]; + + account = 0; + *abort = false; + + while (1) + { + int card_idx; + + mvwaddstr(w, 4, 2, "Please insert your card... "); + wrefresh(w); + + card_idx = getitem(THING); + if (ABORT == card_idx) + { + clearmsg(); + cinema_scene("You realize that you can't use the autoteller without a bank card.", 0, 0); + *abort = true; + return 0; + } + + card = Player.possessions[card_idx]; + if (!card) return 0; + + if (card->id < OB_DEBIT_CARD || card->id > OB_SMART_CARD) + { + char tbuf[120]; + + sprintf(tbuf, "You seem to have trouble sticking your %s in the slot", itemid(card)); + cinema_scene(tbuf, 0, 0); + continue; + } + else + { + clearmsg(); + account = bank_index_number(card->aux); + } + + /* make sure bank redraws if it was covered by inventory in getitem() */ + touchwin(w); + + if (account) break; + + switch(random_range(4)) + { + default: + mvwaddstr(w, 4, 2, "Invalid card! "); + break; + case 1: + mvwaddstr(w, 4, 2, "Where'd that card come from? "); + break; + case 2: + mvwaddstr(w, 4, 2, "Ack! Ptui! "); + break; + case 3: + mvwaddstr(w, 4, 2, "Hurkkk! I think I'm gonna be sick... "); + break; + } + + wrefresh(w); + cinema_scene("The autoteller spits the card back out", 0, 0); + } + + /* provide the card to caller */ + *out_card = card; + + mvwaddstr(w, 4, 2, blank_line); + if (card->blessing > 0) + mvwaddstr(w, 4, 2, "Hiya! So what's your password: "); + else if (card->blessing < 0) + mvwaddstr(w, 4, 2, "Gimme your #*!&% password: "); + else + mvwaddstr(w, 4, 2, "Enter your account password: "); + wrefresh(w); + + getyx(w, cy, cx); + input_password(w, cy, cx, pw_buf, true); + + if (ESCAPE == pw_buf[0]) + { + *abort = true; + return 0; + } + + if (0 == strcmp(pw_buf, account->password)) + { + if (card->blessing > 0) + mvwaddstr(w, 4, 2, "WooHoo! That's right buddy! "); + else if (card->blessing < 0) + mvwaddstr(w, 4, 2, "*$&^! I was gonna bust ya. "); + else + mvwaddstr(w, 4, 2, "Password accepted. Working. "); + wrefresh(w); + + if (!account->player) Player.alignment -= 5; + } + else + { + bank_break(w, card); + account = 0; + } + + return account; +} + +static void bank_deposit (WINDOW *w, bank_account *account, Object* card) +{ + int cy, cx; + long amount; + + mvwaddstr(w, 12, 2, blank_line); + if (card->blessing > 0) + mvwaddstr(w, 12, 2, "How much should I look after? "); + else if (card->blessing < 0) + mvwaddstr(w, 12, 2, "Cough up: "); + else + mvwaddstr(w, 12, 2, "Amount: "); + wrefresh(w); + + getyx(w, cy, cx); + amount = input_amount(w, cy, cx); + + if (amount < 0) + { + if (card->blessing > 0) + { + mvwaddstr(w, 14, 2, "Oh, you actually want to have some money? "); + mvwaddstr(w, 15, 2, "Ok Buddy! No Problem! "); + mvwaddstr(w, 16, 2, blank_line); + amount = abs(amount); + if (amount > account->balance) amount = account->balance; + account->balance -= amount; + Player.cash += amount; + } + else if (card->blessing < 0) + { + mvwaddstr(w, 14, 2, "You're supposed to give ME money, blockhead! "); + mvwaddstr(w, 15, 2, "I'll just take it anyway! Muahahahahaha! "); + mvwaddstr(w, 16, 2, "Mine! All Mine! "); + account->balance -= 1000; + } + else + { + mvwaddstr(w, 14, 2, "Unauthorized withdrawal attempt! "); + mvwaddstr(w, 15, 2, "A fine in the amount of 250 AU has been "); + mvwaddstr(w, 16, 2, "levied against your account. "); + account->balance -= 250; + } + } + else if (0 == amount) + { + if (card->blessing > 0) + mvwaddstr(w, 14, 2, "Changed your mind? No worries pal! "); + else if (card->blessing < 0) + mvwaddstr(w, 14, 2, "Hey! Cough it up jerk! NOW! "); + else + mvwaddstr(w, 14, 2, "Transaction Aborted "); + + mvwaddstr(w, 15, 2, blank_line); + mvwaddstr(w, 16, 2, blank_line); + } + else + { + int fee = 0; + + if (amount > Player.cash) amount = Player.cash; + mvwaddstr(w, 14, 2, blank_line); + + if (card->blessing > 0) + { + mvwprintw(w, 14, 2, "I'll take good care of %d AU for you!", amount); + } + else if (card->blessing < 0) + { + fee = 1 + random_range(amount) / 2; + mvwprintw(w, 14, 2, "Minus my fee, that makes %d AU for you...", amount - fee); + } + else + { + mvwprintw(w, 14, 2, "%d AU deposited", amount); + } + + account->balance += (amount - fee); + Player.cash -= amount; + + mvwaddstr(w, 15, 2, blank_line); + mvwaddstr(w, 16, 2, blank_line); + } + + wrefresh(w); +} + +static void bank_withdraw (WINDOW *w, bank_account *account, Object* card) +{ + int cy, cx; + long amount; + + mvwaddstr(w, 12, 2, blank_line); + if (card->blessing > 0) + mvwaddstr(w, 12, 2, "How much do you want, pal? "); + else if (card->blessing < 0) + mvwaddstr(w, 12, 2, "Grovel for this much: "); + else + mvwaddstr(w, 12, 2, "Amount: "); + wrefresh(w); + + getyx(w, cy, cx); + amount = input_amount(w, cy, cx); + + if (amount < 0) + { + amount = abs(amount); + if (amount > Player.cash) amount = Player.cash; + + Player.cash -= amount; + + mvwaddstr(w, 14, 2, blank_line); + if (card->blessing > 0) + mvwprintw(w, 14, 2, "Whoa, thanks for the %d AU!", amount); + else if (card->blessing < 0) + mvwprintw(w, 14, 2, "Sucker! %d AU is mine! all mine!", amount); + else + mvwprintw(w, 14, 2, "%d AU deposited", amount); + + mvwaddstr(w, 15, 2, blank_line); + mvwaddstr(w, 16, 2, blank_line); + + if (card->blessing >= 0) + account->balance += amount; + } + else if (amount > account->balance) + { + if (card->blessing > 0) + { + mvwaddstr(w, 14, 2, "Golly! You must have typed wrong! "); + mvwaddstr(w, 15, 2, "But don't worry, I won't hold it against you! "); + mvwaddstr(w, 16, 2, "Just try again pal! "); + } + else if (card->blessing < 0) + { + mvwaddstr(w, 14, 2, "What the #&*^* are you trying to pull?! "); + mvwaddstr(w, 15, 2, "You're gonna pay for that! Muahahahaha! "); + mvwaddstr(w, 16, 2, "Mine! All mine! "); + account->balance -= 1000; + } + else + { + mvwaddstr(w, 14, 2, "Account overdraft! "); + mvwaddstr(w, 15, 2, "A fine in the amount of 100 AU has been levied "); + mvwaddstr(w, 16, 2, "against your account. "); + account->balance -= 100; + } + } + else + { + int extra = 0; + + if (card->blessing > 0) + { + extra = 1 + random_range(amount); + mvwaddstr(w, 14, 2, blank_line); + mvwprintw(w, 14, 2, "Sure! In fact, how about %d AU more?", extra); + } + else if (card->blessing < 0) + { + extra = -random_range(amount); + mvwaddstr(w, 14, 2, blank_line); + mvwprintw(w, 14, 2, "Ok, but I'm keeping %d AU for myself!", -extra); + } + else + { + mvwaddstr(w, 14, 2, "Transaction accomplished. "); + } + + account->balance -= amount; + Player.cash += (amount + extra); + + mvwaddstr(w, 15, 2, blank_line); + mvwaddstr(w, 16, 2, blank_line); + } + + wrefresh(w); +} + +static void bank_transaction (WINDOW *w, bank_account *account, Object* card) +{ + int idx; + int cy, cx; + short response; + + while (1) + { + for (idx = 6; idx < 14; ++idx) + mvwaddstr(w, idx, 2, blank_line); + + if (card->blessing > 0) + { + if (account->balance > 0) + mvwprintw(w, 6, 2, "Say pal, you've got: %d AU!", account->balance); + else + mvwprintw(w, 6, 2, "Oh my, you've got: %d AU.", account->balance); + + mvwaddstr(w, 8, 2, " D: Let me look after some money for you"); + mvwaddstr(w, 9, 2, " W: Let me give you some money"); + mvwaddstr(w, 10, 2, " E: Say a fond farewell"); + mvwaddstr(w, 12, 2, "What can I do for you buddy? "); + } + else if (card->blessing < 0) + { + if (account->balance > 0) + mvwprintw(w, 6, 2, "Muahaha! I've got %d AU!", account->balance); + else if (account->balance < 0) + mvwprintw(w, 6, 2, "Muahaha! You're owe me %d AU!", -account->balance); + else + mvwaddstr(w, 6, 2, "Nothing for you here, jerk!"); + + mvwaddstr(w, 8, 2, " D: Cough up some more dough"); + mvwaddstr(w, 9, 2, " W: Beg me for some change"); + mvwaddstr(w, 10, 2, " E: Beat it!"); + mvwaddstr(w, 12, 2, "What's your pathetic desire? "); + } + else + { + mvwprintw(w, 6, 2, "Current balance: %d AU", account->balance); + mvwaddstr(w, 8, 2, " D: Deposit"); + mvwaddstr(w, 9, 2, " W: Withdraw"); + mvwaddstr(w, 10, 2, " E: Exit"); + mvwaddstr(w, 12, 2, "Enter command: "); + } + wrefresh(w); + + getyx(w, cy, cx); + response = toupper(mvwgetch(w, cy, cx)); + + if ('D' == response) + { + for (idx = 9; idx < 14; ++idx) + mvwaddstr(w, idx, 2, blank_line); + + bank_deposit(w, account, card); + } + else if ('W' == response) + { + mvwaddstr(w, 8, 2, blank_line); + for (idx = 10; idx < 14; ++idx) + mvwaddstr(w, idx, 2, blank_line); + + bank_withdraw(w, account, card); + } + else if ('E' == response || ESCAPE == response) + { + break; + } + else + { + beep(); + + for (idx = 14; idx < 14; ++idx) + mvwaddstr(w, idx, 2, blank_line); + + if (card->blessing > 0) + mvwaddstr(w, 14, 2, "I'm trying, but I don't know what to do!"); + else if (card->blessing < 0) + mvwaddstr(w, 14, 2, "What the hell do you mean, jerk?"); + else + mvwaddstr(w, 14, 2, "Invalid entry!"); + wrefresh(w); + } + + dataprint(); + } +} + +void access_bank() { + Object* card; + int abort; + bank_account *account; + + while (1) + { + account = bank_password(Bankw, &card, &abort); + + if (account) + { + int idx; + + bank_transaction(Bankw, account, card); + + if (card->blessing > 0) + mvwaddstr(Bankw, 4, 2, " Come back anytime Pal! "); + else if (card->blessing < 0) + mvwaddstr(Bankw, 4, 2, " Don't bother coming back, you make me sick! "); + else + mvwaddstr(Bankw, 4, 2, " Thank you for choosing The Bank of Rampart! "); + + for (idx = 5; idx < 18; ++idx) + mvwaddstr(Bankw, idx, 2, blank_line); + + wrefresh(Bankw); + sleep(3); + break; + } + else + { + if (abort) break; + if (police_are_hostile()) break; + } + } +} + +/* the bank -- can be broken into (but you knew that, didn't you?) */ +void l_bank (void) +{ + /* draw bank window from scratch */ + werase(Bankw); + + wattrset(Bankw, CHARATTR(CLR(WHITE))); + wborder(Bankw, + ACS_VLINE, ACS_VLINE, ACS_HLINE, ACS_HLINE, + ACS_ULCORNER, ACS_URCORNER, ACS_LLCORNER, ACS_LRCORNER); + + wborder(Bankw, '|', '|', '-', '-', '+', '+', '+', '+'); + + wattrset(Bankw, CHARATTR(CLR(LIGHT_GREEN))); + mvwaddstr(Bankw, 2, 2, " Welcome to The Bank of Rampart "); + + /* bank working? or not? */ + if (State.getBankBroken() == true) + { + mvwaddstr(Bankw, 9, 2, " Autoteller Out of Order "); + wrefresh(Bankw); + cinema_scene("You see a damaged autoteller.", 0, 0); + } + else if (police_are_hostile()) + { + mvwaddstr(Bankw, 9, 2, " Autoteller Temporarily Unavailable "); + wrefresh(Bankw); + cinema_scene("Apparently the bank is closed.", 0, 0); + } + else + { + BankResponse response; + + /* first, bank asks if user has an account */ + + cinema_blank(); + cinema_print_line(0, "The proximity sensor activates the autoteller as you approach."); + + response = bank_new_customer(Bankw); + + /* if user says no account, maybe he wants to open one */ + + if (response == BankNewCustomer) + { + Object* card; + card = bank_open_account(Bankw); + + if (card) + { + int idx; + + cinema_scene("The autoteller produces your new bank card...", 0, 0); + gain_item(card); + + for (idx = 5; idx < 18; ++idx) + mvwaddstr(Bankw, idx, 2, blank_line); + + touchwin(Bankw); + + // User has created an account; direct them to it + access_bank(); + } + } else if (response == BankExistingCustomer) { + access_bank(); + } + } + + if (State.getBankBroken() == false) clearmsg(); + + xredraw(); +} + +void bank_init (void) +{ + int i; + + account_number_next = random_range(INT_MAX); + account_number_incr = 5 + random_range(100); + + bank_create_account(false, random_range(CASH_BALANCE), CASH_PASSWORD); + + shuffle(account_num, NUM_NPC_ACCOUNTS); + + for(i = 0; i < (3 + random_range(6)); ++i) + { + int which; + which = account_num[i]; + bank_create_account(false, + random_range(npc_account_balances[which]), + npc_account_passwords[which]); + } +} + +int bank_random_account_number (void) +{ + int which; + int num_accounts; + bank_account *account; + assert(bank != NULL); // otherwise we dereference null; right behavior, create an account? + + num_accounts = 0; + for (account = bank; account; account = account->next_account) + { + if (false == account->player) + ++num_accounts; + } + + which = random_range(num_accounts); + + num_accounts = 0; + for (account = bank; account; account = account->next_account) + { + if (false == account->player) + { + if (which == num_accounts) break; + ++num_accounts; + } + } + + assert(bank != NULL); + return account->number; +} diff --git a/Omega/src/char.cpp b/Omega/src/char.cpp index 06b1f42..7ebb284 100644 --- a/Omega/src/char.cpp +++ b/Omega/src/char.cpp @@ -1,841 +1,840 @@ -/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ -/* char.c */ -/* Player generation */ - -#include "glob.h" - -#ifdef WIN32 -char* getlogin() { - DWORD size = 256; - char buf[256]; - - if (!GetUserName(buf, &size)) { - return "pcuser"; - } - - return buf; -} -#endif - -/* set player to begin with */ -bool initplayer(void) -{ - int i; - int oldchar=false; - FILE *fd; - char *lname; - int ret_value = false; - - lname = getlogin(); - -#if !defined(WIN32) - // Get the login name if getlogin() failed - if (!lname || strlen(lname) == 0) - { - struct passwd *dastuff; - - dastuff = getpwuid(getuid()); - lname = dastuff->pw_name; - } -#endif - - strcpy(Player.name,lname); - if (Player.name[0] >= 'a' && Player.name[0] <= 'z') - Player.name[0] += 'A'-'a'; /* capitalise 1st letter */ - Player.itemweight = 0; - Player.food = 36; - Player.packptr = 0; - Behavior = -1; - Player.options = 0; - for (i=0; i= 'a' && Player.name[0] <= 'z') - Player.name[0] += 'A'-'a'; /* capitalise 1st letter */ - } - fclose(fd); - } - change_to_game_perms(); - if (! oldchar) { - optionset(RUNSTOP); - optionset(CONFIRM); - optionset(SHOW_COLOUR); - ret_value = initstats() ; /* RM 04-19-2000:loading patch */ /* DAG */ - } - /* This gets executed when the player loads from .omegarc */ - /* DAG - put the code back in the same place, rather than duplicating */ - Searchnum = max(1,min(9,Searchnum)); - Player.hp = Player.maxhp = Player.maxcon; - Player.mana = Player.maxmana = calcmana(); - Player.click = 1; - strcpy(Player.combatManeuvers,"CCBC"); - calc_melee(); - ScreenOffset = -1000; /* to force a redraw */ - return ret_value > 0; /* RM 04-19-2000: loading patch */ /* DAG */ -} - - -FILE *omegarc_check(void) -{ - FILE *fd; - - getOmegaRCPath(); - - if ((fd = fopen(Str1,"r")) != NULL) { - print2("Use .omegarc in home directory? [yn] "); - if (ynq2()!='y') { - fclose(fd); - fd = NULL; - } - } - clearmsg(); - return(fd); -} - -int initstats(void) -{ - char response; - char savedg[80]; - print1("Do you want to run a character [c], load a game [l], or "); - print2("play yourself [p]?"); /* RM 04-19-2000 loading patch */ - do - response = (char) mcigetc(); - while ((response!='c')&&(response != 'p')&&(response !='l')); - if (response == 'c') omegan_character_stats(); - else if (response == 'l') - { - /* RM 04-19-2000: loading patch - a blatant hack */ - clearmsg(); - print1("Enter saved game name: "); - strcpy(savedg,msgscanstring()); - - game_restore(savedg); - return true; - } - else { - clearmsg(); /* RM 04-19-2000 loading patch - fix the display */ - user_character_stats(); - user_intro(); - print1("Do you want to save this set-up to .omegarc in your home directory? [yn] "); - if (ynq1()=='y') - save_omegarc(); - } - xredraw(); - return false; -} - -void getOmegaRCPath() -{ -#ifndef WIN32 - sprintf(Str1, "%s/.omegarc", getenv("HOME")); -#else - SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, Str1); - strcat(Str1, "\\.omegarc"); -#endif -} - -void save_omegarc(void) -{ - int i=VERSION; - FILE *fd; - change_to_user_perms(); - - getOmegaRCPath(); - - fd = fopen(Str1,"w"); - if (fd == NULL) - print1("Sorry, couldn't save .omegarc for some reason."); - else { - fwrite((char *)&i,sizeof(int),1,fd); - print1("First, set options."); - setoptions(); - fwrite((char *)&Player,sizeof(Player),1,fd); - fwrite((char *)&Searchnum,sizeof(int),1,fd); - fwrite((char *)&Verbosity,sizeof(char),1,fd); - fclose(fd); - } - change_to_game_perms(); -} - - - -long calcmana(void) -{ - return(Player.pow * (long)(Player.level+1)); -} - - -/* npcbehavior digits 1234 - -4 : alignment (LAWFUL,CHAOTIC, or NEUTRAL) -3 : primary combat action (melee,missile,spell,thief,flight,1..5) -2 : competence at 4 (0..9, 0 = incompetent, 9 = masterful) -1 : conversation mode - -status : 1 = dead, 2 = saved, 3 = retired, 4 = still playing -*/ -int fixnpc(int status) -{ - int npcbehavior=0; - char response; - if (status == 1) { /* player is dead, all undead are chaotic */ - npcbehavior+=CHAOTIC; - npcbehavior+=10; /* melee */ - npcbehavior+=100*min(9,((int) (Player.level/3))); - npcbehavior+=1000; /* threaten */ - } - else if (Behavior >= 0) - npcbehavior = Behavior; - else { - menuclear(); - menuprint("NPC Behavior Determination Module\n\n"); - menuprint("Your overall NPC behavior is:"); - if (Player.alignment < -10) { - npcbehavior += CHAOTIC; - menuprint("\n\n CHAOTIC"); - } - else if (Player.alignment > 10) { - npcbehavior += LAWFUL; - menuprint("\n\n LAWFUL"); - } - else { - npcbehavior += NEUTRAL; - menuprint("\n\n NEUTRAL"); - } - menuprint("\n\n1: hand-to-hand combat"); - menuprint("\n2: missile combat"); - menuprint("\n3: spellcasting"); - menuprint("\n4: thieving"); - menuprint("\n5: escape"); - menuprint("\n\nEnter NPC response to combat: "); - showmenu(); - response = '0'; - while ((response != '1') && - (response != '2') && - (response != '3') && - (response != '4') && - (response != '5')) - response = menugetc(); - menuaddch(response); - npcbehavior+=10*(response - '0'); - npcbehavior+=100*competence_check(response-'0'); - response = '0'; - menuclear(); - menuprint("1: threaten"); - menuprint("\n2: greet"); - menuprint("\n3: aid"); - menuprint("\n4: beg"); - menuprint("\n5: silence"); - menuprint("\n\nEnter NPC response to conversation: "); - showmenu(); - while ((response != '1') && - (response != '2') && - (response != '3') && - (response != '4') && - (response != '5')) - response = menugetc(); - menuaddch(response); - npcbehavior+=1000*(response - '0'); - xredraw(); - } - Behavior = npcbehavior; - return(npcbehavior); -} - - -/* estimates on a 0..9 scale how good a player is at something */ -int competence_check(int attack) -{ - int ability = 0; - switch(attack) { - case 1: /* melee */ - ability += statmod(Player.str); - case 2: /* missle */ - ability += statmod(Player.dex); - ability += Player.rank[LEGION]; - ability += ((int) (Player.dmg / 10) - 1); - break; - case 3: /* spellcasting */ - ability += statmod(Player.iq); - ability += statmod(Player.pow); - ability += Player.rank[CIRCLE]; - ability += Player.rank[COLLEGE]; - ability += Player.rank[PRIEST]; - break; - case 4: /* thieving */ - ability += statmod(Player.dex); - ability += statmod(Player.agi); - ability += Player.rank[THIEVES]; - break; - case 5: /* escape */ - ability += 2 * statmod(Player.agi); - break; - } - ability += ((int) (Player.level / 5)); - if (ability < 0) ability = 0; - if (ability > 9) ability = 9; - return(ability); -} - -static int user_character_strength (void) -{ - int num; - - cinema_blank(); - num = (int)cinema_getnum_line(0, "How many pounds can you bench press? "); - - if (num < 30) return 3; - if (num < 90) return num / 10; - - num = (num - 120) / 30 + 9; - - if (num > 18) - { - num = 18; - cinema_scene("Right, make me believe THAT's true.", - "Even if it's true, I don't believe it.", 0); - } - - return num; -} - -static int user_character_iq_test (void) -{ - int num = 0; - - cinema_blank(); - if ('y' == cinema_ynq_line(0, "Took an official IQ test? [yn] ")) - { - num = (int)cinema_getnum_line(1, "So, whadja get? "); - num /= 10; - - if (num > 18) - { - num = 18; - cinema_scene("I'm not convinced...", - "If you're so smart, why aren't you rich?", 0); - } - } - - return num; -} - -static int user_character_undergraduate_exam (void) -{ - int num = 0; - char * prompt = "Took Undergraduate entrance exams? [yn] "; - - cinema_blank(); - if ('y' == cinema_ynq_line(0, prompt)) - { - while (1) - { - num = (int)cinema_getnum_line(1, "So, what percentile? "); - if (num < 100) break; - - cinema_scene("That's impossible!", 0, 0); - cinema_print_line(0, prompt); - } - - num = 9 * (num - 49) / 50 + 9; - } - - return num; -} - -static int user_character_graduate_exam (void) -{ - int num = 0; - char * prompt = "Took Graduate entrance exams? [yn] "; - - cinema_blank(); - if ('y' == cinema_ynq_line(0, prompt)) - { - while (1) - { - num = (int)cinema_getnum_line(1, "So, what percentile? "); - if (num < 100) break; - - cinema_scene("That's impossible!", 0, 0); - cinema_print_line(0, prompt); - } - - num = 9 * (num - 49) / 50 + 9; - } - - return num; -} - -static int user_character_dumb (void) -{ - int num; - - cinema_blank(); - if ('y' == cinema_ynq_line(0, "Pretty dumb, aren't you? [yn] ")) - { - num = 3 + random_range(3); - cinema_print_line(1, "I thought so..."); - } - else - { - num = 6 + random_range(6); - cinema_print_line(1, "Well, not *that* dumb."); - } - - morewait(); - return num; -} - -static int user_character_dance (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Can you dance? [yn] ")) return 0; - if ('y' != cinema_ynq_line(1, "Well? [yn] ")) return 1; - return 3; -} - -static int user_character_martial_art (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Do you have training in a martial art or gymnastics? [yn] ")) return 0; - if ('y' != cinema_ynq_line(1, "Do you have dan rank or equivalent? [yn] ")) return 2; - return 6; -} - -static int user_character_field_sport (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Do you play some field sport? [yn] ")) return 0; - if ('y' != cinema_ynq_line(1, "Are you good? [yn] ")) return 1; - return 2; -} - -static int user_character_cave (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Do you cave, mountaineer, etc.? [yn] ")) return 0; - return 3; -} - -static int user_character_skate (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Do you skate or ski? [yn] ")) return 0; - if ('y' != cinema_ynq_line(1, "Well? [yn] ")) return 2; - return 4; -} - -static int user_character_handicapped (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Are you physically handicapped? [yn] ")) return 0; - return -4; -} - -static int user_character_accident_prone (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Are you accident prone? [yn] ")) return 0; - return -4; -} - -static int user_character_bicycle (void) -{ - cinema_blank(); - if ('y' == cinema_ynq_line(0, "Can you ride a bicycle? [yn] ")) return 0; - return -4; -} - -static int user_character_video_games (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Do you play video games? [yn] ")) return 0; - if ('y' != cinema_ynq_line(1, "Do you get high scores? [yn] ")) return 2; - return 6; -} - -static int user_character_archer (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Are you an archer, fencer, or marksman? [yn] ")) return 0; - if ('y' != cinema_ynq_line(1, "A good one? [yn] ")) return 2; - return 6; -} - -static int user_character_picked_lock (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Have you ever picked a lock? [yn] ")) return 0; - - cinema_print_line(1, "Really? Well, the police are being notified."); - usleep(250000); - cinema_print_line(1, "Really? Well, the police are being notified.."); - usleep(250000); - cinema_print_line(1, "Really? Well, the police are being notified..."); - usleep(250000); - cinema_print_line(1, "Really? Well, the police are being notified...."); - usleep(250000); - cinema_print_line(1, "Really? Well, the police are being notified.... done!"); - morewait(); - - return 2; -} - -static int user_character_typing_speed (void) -{ - int num; - - cinema_blank(); - num = (int)cinema_getnum_line(0, "What's your typing speed (words per minute)? "); - - if (num > 124) - { - num = 124; - cinema_print_line(1, "Tell me another one..."); - morewait(); - } - - return num / 25; -} - -static int user_character_hand_shakes (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Hold your arm out. Tense your fist. Hand shaking? [yn] ")) return 0; - return -3; -} - -static int user_character_ambidextrous (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Ambidextrous, are you? [yn] ")) return 0; - return 4; -} - -static int user_character_can_cut_deck (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Can you cut a deck of cards with one hand? [yn] ")) return 0; - return 2; -} - -static int user_character_can_tie_shoes (void) -{ - cinema_blank(); - if ('y' == cinema_ynq_line(0, "Can you tie your shoes blindfolded? [yn] ")) return 0; - return -3; -} - -static int user_character_colds (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Do you ever get colds? [yn] ")) return 4; - if ('y' != cinema_ynq_line(1, "Frequently? [yn] ")) return 0; - return -4; -} - -static int user_character_recent_accident (void) -{ - cinema_blank(); - if ('y' == cinema_ynq_line(0, "Had any serious accident or illness this year? [yn] ")) return -4; - return 4; -} - -static int user_character_chronic_disease (void) -{ - cinema_blank(); - if ('y' == cinema_ynq_line(0, "Have a chronic disease? [yn] ")) return -4; - return 0; -} - -static int user_character_overweight (void) -{ - cinema_blank(); - if ('y' == cinema_ynq_line(0, "Overweight or underweight by more than 20 percent? [yn] ")) return -2; - return 0; -} - -static int user_character_high_blood_pressure (void) -{ - cinema_blank(); - if ('y' == cinema_ynq_line(0, "High blood pressure? [yn] ")) return -2; - return 0; -} - -static int user_character_smoke (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Do you smoke? [yn] ")) return 0; - - cinema_print_line(1, "*cough*"); - morewait(); - - return -3; -} - -static int user_character_aerobics (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Take aerobics classes? [yn] ")) return 0; - return 2; -} - -static int user_character_miles_run (void) -{ - int num; - - cinema_blank(); - num = (int)cinema_getnum_line(0, "How many miles can you run? "); - - if (num < 1) return -3; - if (num < 5) return 2; - if (num < 10) return 4; - if (num < 26) return 8; - - cinema_print_line(1, "Right. Sure. Give me a break."); - morewait(); - - return 8; -} - -static int user_character_animals (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Do animals react oddly to your presence? [yn] ")) return 0; - - cinema_print_line(1, "How curious that must be."); - morewait(); - - return 2; -} - -static int user_character_auras (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Can you see auras? [yn] ")) return 0; - - cinema_print_line(1, "How strange."); - morewait(); - - return 3; -} - -static int user_character_out_of_body (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Ever have an out-of-body experience? [yn] ")) return 0; - - cinema_print_line(1, "Wow, man! Fly the friendly skies..."); - morewait(); - - return 3; -} - -static int user_character_spell (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Did you ever cast a spell? [yn] ")) return 0; - if ('y' != cinema_ynq_line(1, "Did it work? [yn] ")) return 3; - - cinema_print_line(2, "Sure it did..."); - morewait(); - - return 7; -} - -static int user_character_esp (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Do you have ESP? [yn] ")) return 0; - - cinema_print_line(1, "Somehow, I knew you were going to say that."); - morewait(); - - return 3; -} - -static int user_character_pk (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Do you have PK? [yn] ")) return 0; - - cinema_print_line(1, "I can't tell you how much that moves me."); - morewait(); - - return 6; -} - -static int user_character_ghosts (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Do you believe in ghosts? [yn] ")) return 0; - - cinema_print_line(1, "I do! I do! I do believe in ghosts!"); - morewait(); - - return 2; -} - -static int user_character_irish (void) -{ - cinema_blank(); - if ('y' != cinema_ynq_line(0, "Are you Irish? [yn] ")) return 0; - - cinema_print_line(1, "Is that blarney or what?"); - morewait(); - - return 2; -} - -void user_character_stats(void) -{ - int num; - int iqpts = 0; - int agipts = 0; - int dexpts = 0; - int powpts = 0; - int conpts = 0; - int numints = 0; - - cinema_scene("OK, now try to answer the following questions honestly:", 0, 0); - - Player.str = Player.maxstr = user_character_strength(); - - num = user_character_iq_test(); - if (num) ++numints; - iqpts += num; - - num = user_character_undergraduate_exam(); - if (num) ++numints; - iqpts += num; - - num = user_character_graduate_exam(); - if (num) ++numints; - iqpts += num; - - if (0 == numints) - Player.iq = user_character_dumb(); - else - Player.iq = iqpts / numints; - - Player.maxiq = Player.iq; - - agipts += user_character_dance(); - agipts += user_character_martial_art(); - agipts += user_character_field_sport(); - agipts += user_character_cave(); - agipts += user_character_skate(); - agipts += user_character_handicapped(); - agipts += user_character_accident_prone(); - agipts += user_character_bicycle(); - - Player.agi = Player.maxagi = 9 + agipts / 2; - - dexpts += user_character_video_games(); - dexpts += user_character_archer(); - dexpts += user_character_picked_lock(); - dexpts += user_character_typing_speed(); - dexpts += user_character_hand_shakes(); - dexpts += user_character_ambidextrous(); - dexpts += user_character_can_cut_deck(); - dexpts += user_character_can_tie_shoes(); - - Player.dex = Player.maxdex = 6 + dexpts / 2; - - conpts += user_character_colds(); - conpts += user_character_recent_accident(); - conpts += user_character_chronic_disease(); - conpts += user_character_overweight(); - conpts += user_character_high_blood_pressure(); - conpts += user_character_smoke(); - conpts += user_character_aerobics(); - conpts += user_character_miles_run(); - - Player.con = Player.maxcon = 12 + conpts / 3; - - powpts += user_character_animals(); - powpts += user_character_auras(); - powpts += user_character_out_of_body(); - powpts += user_character_spell(); - powpts += user_character_esp(); - powpts += user_character_pk(); - powpts += user_character_ghosts(); - powpts += user_character_irish(); - - Player.pow = Player.maxpow = 3 + powpts / 2; - - Player.preference = - cinema_interact("mfyn", "Are you sexually interested in males or females? ", 0, 0); -} - - - -void omegan_character_stats(void) -{ - int share1,share2,i=0; - print1("To reroll hit ESCAPE; hit any other key to accept these stats."); - do { - i++; -#if REROLLS == -1 - sprintf(Str1, "Generated character # %d", i ); -#else - sprintf(Str1, "You have only %d chance%s to reroll... ", REROLLS - i, - (i == (REROLLS-1) ) ? "":"s"); -#endif - print2(Str1); - Player.iq = Player.maxiq = 4 + random_range(5)+ - (share1 = random_range(6)) + (share2 = random_range(6)); - Player.pow = Player.maxpow = 4 + random_range(5) + share1 +share2; - Player.dex = Player.maxdex = 4 + random_range(5)+ - (share1 = random_range(6)) + (share2 = random_range(6)); - Player.agi = Player.maxagi = 4 + random_range(5) + share1 +share2; - Player.str = Player.maxstr = 4 + random_range(5)+ - (share1 = random_range(6)) + (share2 = random_range(6)); - Player.con = Player.maxcon = 4 + random_range(5) + share1 +share2; - Player.cash = random_range(100)+random_range(100)+ - random_range(100)+random_range(100)+random_range(100); - Player.hp=Player.maxhp=Player.con; - Player.mana=Player.maxmana = calcmana(); - calc_melee(); - dataprint(); -#if REROLLS == -1 - } while (mgetc() == ESCAPE); -#else - } - while ((i < REROLLS) && (mgetc() == ESCAPE)); -#endif - clearmsg(); - print1("Please enter your character's name: "); - strcpy(Player.name,msgscanstring()); - if (Player.name[0] >= 'a' && Player.name[0] <= 'z') - Player.name[0] += 'A'-'a'; /* capitalise 1st letter */ - print1("Is your character sexually interested in males or females? [mf] "); - do Player.preference = (char) mcigetc(); - while ((Player.preference != 'm') && (Player.preference != 'f') && - (Player.preference != 'y') && (Player.preference != 'n')); /* :-) */ - -} - +/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ +/* char.c */ +/* Player generation */ + +#include "glob.h" + +#ifdef WIN32 +char* getlogin(char* buf, int sizeOfBuf) { + DWORD size = sizeOfBuf; + + if (!GetUserName(buf, &size)) { + return "pcuser"; + } + + return buf; +} +#endif + +/* set player to begin with */ +bool initplayer(void) +{ + int i; + int oldchar=false; + FILE *fd; + char *lname = (char*)malloc(256 * sizeof(char)); + int ret_value = false; + + lname = getlogin(lname, 256); + +#if !defined(WIN32) + // Get the login name if getlogin() failed + if (!lname || strlen(lname) == 0) + { + struct passwd *dastuff; + + dastuff = getpwuid(getuid()); + lname = dastuff->pw_name; + } +#endif + + strcpy(Player.name,lname); + if (Player.name[0] >= 'a' && Player.name[0] <= 'z') + Player.name[0] += 'A'-'a'; /* capitalise 1st letter */ + Player.itemweight = 0; + Player.food = 36; + Player.packptr = 0; + Behavior = -1; + Player.options = 0; + for (i=0; i= 'a' && Player.name[0] <= 'z') + Player.name[0] += 'A'-'a'; /* capitalise 1st letter */ + } + fclose(fd); + } + change_to_game_perms(); + if (! oldchar) { + optionset(RUNSTOP); + optionset(CONFIRM); + optionset(SHOW_COLOUR); + ret_value = initstats() ; /* RM 04-19-2000:loading patch */ /* DAG */ + } + /* This gets executed when the player loads from .omegarc */ + /* DAG - put the code back in the same place, rather than duplicating */ + Searchnum = max(1,min(9,Searchnum)); + Player.hp = Player.maxhp = Player.maxcon; + Player.mana = Player.maxmana = calcmana(); + Player.click = 1; + strcpy(Player.combatManeuvers,"CCBC"); + calc_melee(); + ScreenOffset = -1000; /* to force a redraw */ + return ret_value > 0; /* RM 04-19-2000: loading patch */ /* DAG */ +} + + +FILE *omegarc_check(void) +{ + FILE *fd; + + getOmegaRCPath(); + + if ((fd = fopen(Str1,"r")) != NULL) { + print2("Use .omegarc in home directory? [yn] "); + if (ynq2()!='y') { + fclose(fd); + fd = NULL; + } + } + clearmsg(); + return(fd); +} + +int initstats(void) +{ + char response; + char savedg[80]; + print1("Do you want to run a character [c], load a game [l], or "); + print2("play yourself [p]?"); /* RM 04-19-2000 loading patch */ + do + response = (char) mcigetc(); + while ((response!='c')&&(response != 'p')&&(response !='l')); + if (response == 'c') omegan_character_stats(); + else if (response == 'l') + { + /* RM 04-19-2000: loading patch - a blatant hack */ + clearmsg(); + print1("Enter saved game name: "); + strcpy(savedg,msgscanstring()); + + game_restore(savedg); + return true; + } + else { + clearmsg(); /* RM 04-19-2000 loading patch - fix the display */ + user_character_stats(); + user_intro(); + print1("Do you want to save this set-up to .omegarc in your home directory? [yn] "); + if (ynq1()=='y') + save_omegarc(); + } + xredraw(); + return false; +} + +void getOmegaRCPath() +{ +#ifndef WIN32 + sprintf(Str1, "%s/.omegarc", getenv("HOME")); +#else + SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, Str1); + strcat(Str1, "\\.omegarc"); +#endif +} + +void save_omegarc(void) +{ + int i=VERSION; + FILE *fd; + change_to_user_perms(); + + getOmegaRCPath(); + + fd = fopen(Str1,"w"); + if (fd == NULL) + print1("Sorry, couldn't save .omegarc for some reason."); + else { + fwrite((char *)&i,sizeof(int),1,fd); + print1("First, set options."); + setoptions(); + fwrite((char *)&Player,sizeof(Player),1,fd); + fwrite((char *)&Searchnum,sizeof(int),1,fd); + fwrite((char *)&Verbosity,sizeof(char),1,fd); + fclose(fd); + } + change_to_game_perms(); +} + + + +long calcmana(void) +{ + return(Player.pow * (long)(Player.level+1)); +} + + +/* npcbehavior digits 1234 + +4 : alignment (LAWFUL,CHAOTIC, or NEUTRAL) +3 : primary combat action (melee,missile,spell,thief,flight,1..5) +2 : competence at 4 (0..9, 0 = incompetent, 9 = masterful) +1 : conversation mode + +status : 1 = dead, 2 = saved, 3 = retired, 4 = still playing +*/ +int fixnpc(int status) +{ + int npcbehavior=0; + char response; + if (status == 1) { /* player is dead, all undead are chaotic */ + npcbehavior+=CHAOTIC; + npcbehavior+=10; /* melee */ + npcbehavior+=100*min(9,((int) (Player.level/3))); + npcbehavior+=1000; /* threaten */ + } + else if (Behavior >= 0) + npcbehavior = Behavior; + else { + menuclear(); + menuprint("NPC Behavior Determination Module\n\n"); + menuprint("Your overall NPC behavior is:"); + if (Player.alignment < -10) { + npcbehavior += CHAOTIC; + menuprint("\n\n CHAOTIC"); + } + else if (Player.alignment > 10) { + npcbehavior += LAWFUL; + menuprint("\n\n LAWFUL"); + } + else { + npcbehavior += NEUTRAL; + menuprint("\n\n NEUTRAL"); + } + menuprint("\n\n1: hand-to-hand combat"); + menuprint("\n2: missile combat"); + menuprint("\n3: spellcasting"); + menuprint("\n4: thieving"); + menuprint("\n5: escape"); + menuprint("\n\nEnter NPC response to combat: "); + showmenu(); + response = '0'; + while ((response != '1') && + (response != '2') && + (response != '3') && + (response != '4') && + (response != '5')) + response = menugetc(); + menuaddch(response); + npcbehavior+=10*(response - '0'); + npcbehavior+=100*competence_check(response-'0'); + response = '0'; + menuclear(); + menuprint("1: threaten"); + menuprint("\n2: greet"); + menuprint("\n3: aid"); + menuprint("\n4: beg"); + menuprint("\n5: silence"); + menuprint("\n\nEnter NPC response to conversation: "); + showmenu(); + while ((response != '1') && + (response != '2') && + (response != '3') && + (response != '4') && + (response != '5')) + response = menugetc(); + menuaddch(response); + npcbehavior+=1000*(response - '0'); + xredraw(); + } + Behavior = npcbehavior; + return(npcbehavior); +} + + +/* estimates on a 0..9 scale how good a player is at something */ +int competence_check(int attack) +{ + int ability = 0; + switch(attack) { + case 1: /* melee */ + ability += statmod(Player.str); + case 2: /* missle */ + ability += statmod(Player.dex); + ability += Player.rank[LEGION]; + ability += ((int) (Player.dmg / 10) - 1); + break; + case 3: /* spellcasting */ + ability += statmod(Player.iq); + ability += statmod(Player.pow); + ability += Player.rank[CIRCLE]; + ability += Player.rank[COLLEGE]; + ability += Player.rank[PRIEST]; + break; + case 4: /* thieving */ + ability += statmod(Player.dex); + ability += statmod(Player.agi); + ability += Player.rank[THIEVES]; + break; + case 5: /* escape */ + ability += 2 * statmod(Player.agi); + break; + } + ability += ((int) (Player.level / 5)); + if (ability < 0) ability = 0; + if (ability > 9) ability = 9; + return(ability); +} + +static int user_character_strength (void) +{ + int num; + + cinema_blank(); + num = (int)cinema_getnum_line(0, "How many pounds can you bench press? "); + + if (num < 30) return 3; + if (num < 90) return num / 10; + + num = (num - 120) / 30 + 9; + + if (num > 18) + { + num = 18; + cinema_scene("Right, make me believe THAT's true.", + "Even if it's true, I don't believe it.", 0); + } + + return num; +} + +static int user_character_iq_test (void) +{ + int num = 0; + + cinema_blank(); + if ('y' == cinema_ynq_line(0, "Took an official IQ test? [yn] ")) + { + num = (int)cinema_getnum_line(1, "So, whadja get? "); + num /= 10; + + if (num > 18) + { + num = 18; + cinema_scene("I'm not convinced...", + "If you're so smart, why aren't you rich?", 0); + } + } + + return num; +} + +static int user_character_undergraduate_exam (void) +{ + int num = 0; + char * prompt = "Took Undergraduate entrance exams? [yn] "; + + cinema_blank(); + if ('y' == cinema_ynq_line(0, prompt)) + { + while (1) + { + num = (int)cinema_getnum_line(1, "So, what percentile? "); + if (num < 100) break; + + cinema_scene("That's impossible!", 0, 0); + cinema_print_line(0, prompt); + } + + num = 9 * (num - 49) / 50 + 9; + } + + return num; +} + +static int user_character_graduate_exam (void) +{ + int num = 0; + char * prompt = "Took Graduate entrance exams? [yn] "; + + cinema_blank(); + if ('y' == cinema_ynq_line(0, prompt)) + { + while (1) + { + num = (int)cinema_getnum_line(1, "So, what percentile? "); + if (num < 100) break; + + cinema_scene("That's impossible!", 0, 0); + cinema_print_line(0, prompt); + } + + num = 9 * (num - 49) / 50 + 9; + } + + return num; +} + +static int user_character_dumb (void) +{ + int num; + + cinema_blank(); + if ('y' == cinema_ynq_line(0, "Pretty dumb, aren't you? [yn] ")) + { + num = 3 + random_range(3); + cinema_print_line(1, "I thought so..."); + } + else + { + num = 6 + random_range(6); + cinema_print_line(1, "Well, not *that* dumb."); + } + + morewait(); + return num; +} + +static int user_character_dance (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Can you dance? [yn] ")) return 0; + if ('y' != cinema_ynq_line(1, "Well? [yn] ")) return 1; + return 3; +} + +static int user_character_martial_art (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Do you have training in a martial art or gymnastics? [yn] ")) return 0; + if ('y' != cinema_ynq_line(1, "Do you have dan rank or equivalent? [yn] ")) return 2; + return 6; +} + +static int user_character_field_sport (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Do you play some field sport? [yn] ")) return 0; + if ('y' != cinema_ynq_line(1, "Are you good? [yn] ")) return 1; + return 2; +} + +static int user_character_cave (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Do you cave, mountaineer, etc.? [yn] ")) return 0; + return 3; +} + +static int user_character_skate (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Do you skate or ski? [yn] ")) return 0; + if ('y' != cinema_ynq_line(1, "Well? [yn] ")) return 2; + return 4; +} + +static int user_character_handicapped (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Are you physically handicapped? [yn] ")) return 0; + return -4; +} + +static int user_character_accident_prone (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Are you accident prone? [yn] ")) return 0; + return -4; +} + +static int user_character_bicycle (void) +{ + cinema_blank(); + if ('y' == cinema_ynq_line(0, "Can you ride a bicycle? [yn] ")) return 0; + return -4; +} + +static int user_character_video_games (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Do you play video games? [yn] ")) return 0; + if ('y' != cinema_ynq_line(1, "Do you get high scores? [yn] ")) return 2; + return 6; +} + +static int user_character_archer (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Are you an archer, fencer, or marksman? [yn] ")) return 0; + if ('y' != cinema_ynq_line(1, "A good one? [yn] ")) return 2; + return 6; +} + +static int user_character_picked_lock (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Have you ever picked a lock? [yn] ")) return 0; + + cinema_print_line(1, "Really? Well, the police are being notified."); + usleep(250000); + cinema_print_line(1, "Really? Well, the police are being notified.."); + usleep(250000); + cinema_print_line(1, "Really? Well, the police are being notified..."); + usleep(250000); + cinema_print_line(1, "Really? Well, the police are being notified...."); + usleep(250000); + cinema_print_line(1, "Really? Well, the police are being notified.... done!"); + morewait(); + + return 2; +} + +static int user_character_typing_speed (void) +{ + int num; + + cinema_blank(); + num = (int)cinema_getnum_line(0, "What's your typing speed (words per minute)? "); + + if (num > 124) + { + num = 124; + cinema_print_line(1, "Tell me another one..."); + morewait(); + } + + return num / 25; +} + +static int user_character_hand_shakes (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Hold your arm out. Tense your fist. Hand shaking? [yn] ")) return 0; + return -3; +} + +static int user_character_ambidextrous (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Ambidextrous, are you? [yn] ")) return 0; + return 4; +} + +static int user_character_can_cut_deck (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Can you cut a deck of cards with one hand? [yn] ")) return 0; + return 2; +} + +static int user_character_can_tie_shoes (void) +{ + cinema_blank(); + if ('y' == cinema_ynq_line(0, "Can you tie your shoes blindfolded? [yn] ")) return 0; + return -3; +} + +static int user_character_colds (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Do you ever get colds? [yn] ")) return 4; + if ('y' != cinema_ynq_line(1, "Frequently? [yn] ")) return 0; + return -4; +} + +static int user_character_recent_accident (void) +{ + cinema_blank(); + if ('y' == cinema_ynq_line(0, "Had any serious accident or illness this year? [yn] ")) return -4; + return 4; +} + +static int user_character_chronic_disease (void) +{ + cinema_blank(); + if ('y' == cinema_ynq_line(0, "Have a chronic disease? [yn] ")) return -4; + return 0; +} + +static int user_character_overweight (void) +{ + cinema_blank(); + if ('y' == cinema_ynq_line(0, "Overweight or underweight by more than 20 percent? [yn] ")) return -2; + return 0; +} + +static int user_character_high_blood_pressure (void) +{ + cinema_blank(); + if ('y' == cinema_ynq_line(0, "High blood pressure? [yn] ")) return -2; + return 0; +} + +static int user_character_smoke (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Do you smoke? [yn] ")) return 0; + + cinema_print_line(1, "*cough*"); + morewait(); + + return -3; +} + +static int user_character_aerobics (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Take aerobics classes? [yn] ")) return 0; + return 2; +} + +static int user_character_miles_run (void) +{ + int num; + + cinema_blank(); + num = (int)cinema_getnum_line(0, "How many miles can you run? "); + + if (num < 1) return -3; + if (num < 5) return 2; + if (num < 10) return 4; + if (num < 26) return 8; + + cinema_print_line(1, "Right. Sure. Give me a break."); + morewait(); + + return 8; +} + +static int user_character_animals (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Do animals react oddly to your presence? [yn] ")) return 0; + + cinema_print_line(1, "How curious that must be."); + morewait(); + + return 2; +} + +static int user_character_auras (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Can you see auras? [yn] ")) return 0; + + cinema_print_line(1, "How strange."); + morewait(); + + return 3; +} + +static int user_character_out_of_body (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Ever have an out-of-body experience? [yn] ")) return 0; + + cinema_print_line(1, "Wow, man! Fly the friendly skies..."); + morewait(); + + return 3; +} + +static int user_character_spell (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Did you ever cast a spell? [yn] ")) return 0; + if ('y' != cinema_ynq_line(1, "Did it work? [yn] ")) return 3; + + cinema_print_line(2, "Sure it did..."); + morewait(); + + return 7; +} + +static int user_character_esp (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Do you have ESP? [yn] ")) return 0; + + cinema_print_line(1, "Somehow, I knew you were going to say that."); + morewait(); + + return 3; +} + +static int user_character_pk (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Do you have PK? [yn] ")) return 0; + + cinema_print_line(1, "I can't tell you how much that moves me."); + morewait(); + + return 6; +} + +static int user_character_ghosts (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Do you believe in ghosts? [yn] ")) return 0; + + cinema_print_line(1, "I do! I do! I do believe in ghosts!"); + morewait(); + + return 2; +} + +static int user_character_irish (void) +{ + cinema_blank(); + if ('y' != cinema_ynq_line(0, "Are you Irish? [yn] ")) return 0; + + cinema_print_line(1, "Is that blarney or what?"); + morewait(); + + return 2; +} + +void user_character_stats(void) +{ + int num; + int iqpts = 0; + int agipts = 0; + int dexpts = 0; + int powpts = 0; + int conpts = 0; + int numints = 0; + + cinema_scene("OK, now try to answer the following questions honestly:", 0, 0); + + Player.str = Player.maxstr = user_character_strength(); + + num = user_character_iq_test(); + if (num) ++numints; + iqpts += num; + + num = user_character_undergraduate_exam(); + if (num) ++numints; + iqpts += num; + + num = user_character_graduate_exam(); + if (num) ++numints; + iqpts += num; + + if (0 == numints) + Player.iq = user_character_dumb(); + else + Player.iq = iqpts / numints; + + Player.maxiq = Player.iq; + + agipts += user_character_dance(); + agipts += user_character_martial_art(); + agipts += user_character_field_sport(); + agipts += user_character_cave(); + agipts += user_character_skate(); + agipts += user_character_handicapped(); + agipts += user_character_accident_prone(); + agipts += user_character_bicycle(); + + Player.agi = Player.maxagi = 9 + agipts / 2; + + dexpts += user_character_video_games(); + dexpts += user_character_archer(); + dexpts += user_character_picked_lock(); + dexpts += user_character_typing_speed(); + dexpts += user_character_hand_shakes(); + dexpts += user_character_ambidextrous(); + dexpts += user_character_can_cut_deck(); + dexpts += user_character_can_tie_shoes(); + + Player.dex = Player.maxdex = 6 + dexpts / 2; + + conpts += user_character_colds(); + conpts += user_character_recent_accident(); + conpts += user_character_chronic_disease(); + conpts += user_character_overweight(); + conpts += user_character_high_blood_pressure(); + conpts += user_character_smoke(); + conpts += user_character_aerobics(); + conpts += user_character_miles_run(); + + Player.con = Player.maxcon = 12 + conpts / 3; + + powpts += user_character_animals(); + powpts += user_character_auras(); + powpts += user_character_out_of_body(); + powpts += user_character_spell(); + powpts += user_character_esp(); + powpts += user_character_pk(); + powpts += user_character_ghosts(); + powpts += user_character_irish(); + + Player.pow = Player.maxpow = 3 + powpts / 2; + + Player.preference = + cinema_interact("mfyn", "Are you sexually interested in males or females? ", 0, 0); +} + + + +void omegan_character_stats(void) +{ + int share1,share2,i=0; + print1("To reroll hit ESCAPE; hit any other key to accept these stats."); + do { + i++; +#if REROLLS == -1 + sprintf(Str1, "Generated character # %d", i ); +#else + sprintf(Str1, "You have only %d chance%s to reroll... ", REROLLS - i, + (i == (REROLLS-1) ) ? "":"s"); +#endif + print2(Str1); + Player.iq = Player.maxiq = 4 + random_range(5)+ + (share1 = random_range(6)) + (share2 = random_range(6)); + Player.pow = Player.maxpow = 4 + random_range(5) + share1 +share2; + Player.dex = Player.maxdex = 4 + random_range(5)+ + (share1 = random_range(6)) + (share2 = random_range(6)); + Player.agi = Player.maxagi = 4 + random_range(5) + share1 +share2; + Player.str = Player.maxstr = 4 + random_range(5)+ + (share1 = random_range(6)) + (share2 = random_range(6)); + Player.con = Player.maxcon = 4 + random_range(5) + share1 +share2; + Player.cash = random_range(100)+random_range(100)+ + random_range(100)+random_range(100)+random_range(100); + Player.hp=Player.maxhp=Player.con; + Player.mana=Player.maxmana = calcmana(); + calc_melee(); + dataprint(); +#if REROLLS == -1 + } while (mgetc() == ESCAPE); +#else + } + while ((i < REROLLS) && (mgetc() == ESCAPE)); +#endif + clearmsg(); + print1("Please enter your character's name: "); + strcpy(Player.name,msgscanstring()); + if (Player.name[0] >= 'a' && Player.name[0] <= 'z') + Player.name[0] += 'A'-'a'; /* capitalise 1st letter */ + print1("Is your character sexually interested in males or females? [mf] "); + do Player.preference = (char) mcigetc(); + while ((Player.preference != 'm') && (Player.preference != 'f') && + (Player.preference != 'y') && (Player.preference != 'n')); /* :-) */ + +} + diff --git a/Omega/src/command1.cpp b/Omega/src/command1.cpp index 7bb3f37..abaf284 100644 --- a/Omega/src/command1.cpp +++ b/Omega/src/command1.cpp @@ -1,522 +1,527 @@ -/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ -/* command1.c */ - -/* This file has the two toplevel command scanners, p_process, -which works everywhere but the countryside, and p_couyntry_process, -which works.... */ - -#include "glob.h" - -/* deal with a new player command in dungeon or city mode*/ -void p_process(void) -{ - static int searchval=0; - - if (Player.status[BERSERK]) - if (goberserk()) { - State.setSkipPlayer( true ); - drawvision(Player.x,Player.y); - } - if (!State.getSkipPlayer()) { - if (searchval > 0) { - searchval--; - if (searchval == 0) State.setFastMove(false); - } - drawvision(Player.x,Player.y); - if (State.getFastMove() == false) { - searchval = 0; - Cmd = mgetc(); - clear_if_necessary(); - } - Command_Duration = 0; - - switch (Cmd) { - case ' ': - case 13: - State.setSkipMonsters(); - break; /*no op on space or return*/ - case 6: - abortshadowform(); - break; /* ^f */ - case 7: - wizard(); - break; /* ^g */ - case 4: - player_dump(); - break; /* ^d */ - case 9: - display_pack(); - morewait(); - xredraw(); - break; /* ^i */ - case 11: - if (State.getCheater()) frobgamestatus(); - break; - case 12: - xredraw(); - State.setSkipMonsters(); - break; /* ^l */ -#if !defined(WIN32) - case 16: - bufferprint(); - State.setSkipMonsters(); - break; /* ^p */ -#else - case 15: - bufferprint(); - State.setSkipMonsters(); - break; /* ^o */ -#endif - case 18: - redraw(); - State.setSkipMonsters(); - break; /* ^r */ - case 23: - if (State.getCheater()) drawscreen(); - break; /* ^w */ - case 24: /* ^x */ - if (State.getCheater() || - Player.rank[ADEPT]) - wish(1); - Command_Duration = 5; - break; - case 'a': - zapwand(); - Command_Duration = Player.speed*8/5; - break; - case 'c': - closedoor(); - Command_Duration = Player.speed*2/5; - break; - case 'd': - drop(); - Command_Duration = Player.speed*5/5; - break; - case 'e': - eat(); - Command_Duration = 30; - break; - case 'f': - fire(); - Command_Duration = Player.speed*5/5; - break; - case 'g': - pickup(); - Command_Duration = Player.speed*10/5; - break; - case 'i': - do_inventory_control(); - break; - case 'm': - magic(); - Command_Duration = 12; - break; - case 'o': - opendoor(); - Command_Duration = Player.speed*5/5; - break; - case 'p': - pickpocket(); - Command_Duration = Player.speed*20/5; - break; - case 'q': - quaff(); - Command_Duration = 10; - break; - case 'r': - peruse(); - Command_Duration = 20; - break; - case 's': - search(&searchval); - Command_Duration = 20; - break; - case 't': - talk(); - Command_Duration = 10; - break; - case 'v': - vault(); - Command_Duration = Player.speed*10/5; - break; - case 'x': - examine(); - Command_Duration = 1; - break; - case 'z': - bash_location(); - Command_Duration = Player.speed*10/5; - break; - case 'A': - activate(); - Command_Duration = 10; - break; - case 'C': - callitem(); - break; - case 'D': - disarm(); - Command_Duration = 30; - break; - case 'E': - dismount_steed(); - Command_Duration = Player.speed*10/5; - break; - case 'F': - tacoptions(); - break; - case 'G': - give(); - Command_Duration = 10; - break; - case 'I': - if (! optionp(TOPINV)) top_inventory_control(); - else { - display_possessions(); - inventory_control(); - } - break; - case 'M': - city_move(); - Command_Duration = 10; - break; - case 'O': - setoptions(); -#if defined(WIN32) - show_screen(); - xredraw(); -#endif - break; - case 'P': - show_license(); - break; /* actually show_license is in file.c */ - case 'Q': - quit(); - break; - case 'R': - rename_player(); - break; - case 'S': - save(false); - break; - case 'T': - tunnel(); - Command_Duration = Player.speed*30/5; - break; - case 'V': - version(); - break; - case 'Z': - bash_item(); - Command_Duration = Player.speed*10/5; - break; - case '.': - rest(); - Command_Duration = 10; - break; - case ',': - nap(); - break; - case '>': - downstairs(); - break; - case '<': - upstairs(); - break; - case '@': - p_movefunction(Level->site[Player.x][Player.y].p_locf); - Command_Duration = 5; - break; - case '#': - if (State.getCheater()) editstats(); - break; /* RAC - char editor */ - case '/': - charid(); - State.setSkipMonsters(); - break; - case '?': - help(); - State.setSkipMonsters(); - break; - case '4': - case 'h': -#ifdef KEY_LEFT - case KEY_LEFT: -#endif - moveplayer(-1,0); - Command_Duration = Player.speed*5/5; - break; - case '2': - case 'j': -#ifdef KEY_DOWN - case KEY_DOWN: -#endif - moveplayer(0,1); - Command_Duration = Player.speed*5/5; - break; -#ifdef KEY_UP - case KEY_UP: -#endif - case '8': - case 'k': - moveplayer(0,-1); - Command_Duration = Player.speed*5/5; - break; -#ifdef KEY_RIGHT - case KEY_RIGHT: -#endif - case '6': - case 'l': - moveplayer(1,0); - Command_Duration = Player.speed*5/5; - break; - case '1': - case 'b': - moveplayer(-1,1); - Command_Duration = Player.speed*5/5; - break; - case '3': - case 'n': - moveplayer(1,1); - Command_Duration = Player.speed*5/5; - break; - case '7': - case 'y': - moveplayer(-1,-1); - Command_Duration = Player.speed*5/5; - break; - case '9': - case 'u': - moveplayer(1,-1); - Command_Duration = Player.speed*5/5; - break; - case '5': - State.setSkipMonsters(); /* don't do anything; a dummy turn */ - Cmd = mgetc(); - while ((Cmd != ESCAPE) && - ((Cmd < '1') || (Cmd > '9') || (Cmd=='5'))) { - print3("Run in keypad direction [ESCAPE to abort]: "); - Cmd = mgetc(); - } - if (Cmd != ESCAPE) - State.setFastMove(); - else - clearmsg3(); - break; - case 'H': -#ifdef KEY_SLEFT - case KEY_SLEFT: -#endif - State.setFastMove(); - Cmd = 'h'; - moveplayer(-1,0); - Command_Duration = Player.speed*4/5; - break; - case 'J': -#ifdef KEY_SDOWN - case KEY_SDOWN: -#endif - State.setFastMove(); - Cmd = 'j'; - moveplayer(0,1); - Command_Duration = Player.speed*4/5; - break; - case 'K': -#ifdef KEY_SUP - case KEY_SUP: -#endif - State.setFastMove(); - Cmd = 'k'; - moveplayer(0,-1); - Command_Duration = Player.speed*4/5; - break; - case 'L': -#ifdef KEY_SRIGHT - case KEY_SRIGHT: -#endif - State.setFastMove(); - Cmd = 'l'; - moveplayer(1,0); - Command_Duration = Player.speed*4/5; - break; - case 'B': - State.setFastMove(); - Cmd = 'b'; - moveplayer(-1,1); - Command_Duration = Player.speed*4/5; - break; - case 'N': - State.setFastMove(); - Cmd = 'n'; - moveplayer(1,1); - Command_Duration = Player.speed*4/5; - break; - case 'Y': - State.setFastMove(); - Cmd = 'y'; - moveplayer(-1,-1); - Command_Duration = Player.speed*4/5; - break; - case 'U': - State.setFastMove(); - Cmd = 'u'; - moveplayer(1,-1); - Command_Duration = Player.speed*4/5; - break; - default: - commanderror(); - State.setSkipMonsters(); - break; - } - } - if (Current_Environment != E_COUNTRYSIDE) roomcheck(); - screencheck(Player.x,Player.y); -} - -/* deal with a new player command in countryside mode */ -void p_country_process(void) -{ - int no_op; - - drawvision(Player.x,Player.y); - do { - no_op = false; - Cmd = mgetc(); - clear_if_necessary(); - switch (Cmd) { - case ' ': - case 13: - no_op = true; - break; - case 7: - wizard(); - break; /* ^g */ - case 12: - xredraw(); - no_op = true; - break; /* ^l */ -#if !defined(WIN32) - case 16: - bufferprint(); - no_op = true; - break; /* ^p */ -#else - case 15: - bufferprint(); - no_op = true; - break; /* ^o */ -#endif - case 18: - redraw(); - no_op = true; - break; /* ^r */ - case 23: - if (State.getCheater()) drawscreen(); - break; /* ^w */ - case 24: - if (State.getCheater() || - Player.rank[ADEPT]) wish(1); - break; /* ^x */ - case 'd': - drop(); - break; - case 'e': - eat(); - break; - case 'i': - do_inventory_control(); - break; - case 's': - countrysearch(); - break; - case 'x': - examine(); - break; - case 'E': - dismount_steed(); - break; - case 'H': - hunt(Country[Player.x][Player.y].current_terrain_type); - break; - case 'I': - if (! optionp(TOPINV)) top_inventory_control(); - else { - menuclear(); - display_possessions(); - inventory_control(); - } - break; - case 'O': - setoptions(); - break; - case 'P': - show_license(); - break; /* actually show_license is in file.c */ - case 'Q': - quit(); - break; - case 'R': - rename_player(); - break; - case 'S': - save(false); - break; - case 'V': - version(); - break; - case '>': - enter_site(Country[Player.x][Player.y].base_terrain_type); - break; - case '#': - if (State.getCheater()) editstats(); - break; /* RAC - char editor */ - case '/': - charid(); - no_op = true; - break; - case '?': - help(); - no_op = true; - break; - case '4': - case 'h': - movepincountry(-1,0); - break; - case '2': - case 'j': - movepincountry(0,1); - break; - case '8': - case 'k': - movepincountry(0,-1); - break; - case '6': - case 'l': - movepincountry(1,0); - break; - case '1': - case 'b': - movepincountry(-1,1); - break; - case '3': - case 'n': - movepincountry(1,1); - break; - case '7': - case 'y': - movepincountry(-1,-1); - break; - case '9': - case 'u': - movepincountry(1,-1); - break; - default: - commanderror(); - no_op = true; - break; - } - } while (no_op); - screencheck(Player.x,Player.y); -} - - +/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ +/* command1.c */ + +/* This file has the two toplevel command scanners, p_process, +which works everywhere but the countryside, and p_couyntry_process, +which works.... */ + +#include "glob.h" +#include "defs.h" + +/* deal with a new player command in dungeon or city mode*/ +void p_process(void) +{ + static int searchval=0; + + if (Player.status[BERSERK]) + if (goberserk()) { + State.setSkipPlayer( true ); + drawvision(Player.x,Player.y); + } + if (!State.getSkipPlayer()) { + if (searchval > 0) { + searchval--; + if (searchval == 0) State.setFastMove(false); + } + drawvision(Player.x,Player.y); + if (State.getFastMove() == false) { + searchval = 0; + Cmd = mgetc(); + clear_if_necessary(); + } + Command_Duration = 0; + + switch (Cmd) { + case ' ': + case 13: + State.setSkipMonsters(); + break; /*no op on space or return*/ + case 6: + abortshadowform(); + break; /* ^f */ + case 7: + wizard(); + break; /* ^g */ + case 4: + player_dump(); + break; /* ^d */ + case 9: + display_pack(); + morewait(); + xredraw(); + break; /* ^i */ + case 11: + if (State.getCheater()) frobgamestatus(); + break; + case 12: + xredraw(); + State.setSkipMonsters(); + break; /* ^l */ +#if !defined(WIN32) + case 16: + bufferprint(); + State.setSkipMonsters(); + break; /* ^p */ +#else + case 15: + bufferprint(); + State.setSkipMonsters(); + break; /* ^o */ +#endif + case 18: + redraw(); + State.setSkipMonsters(); + break; /* ^r */ + case 23: + if (State.getCheater()) drawscreen(); + break; /* ^w */ + case 24: /* ^x */ + if (State.getCheater() || + Player.rank[ADEPT]) + wish(1); + Command_Duration = 5; + break; + case 'a': + zapwand(); + Command_Duration = Player.speed*8/5; + break; + case 'c': + closedoor(); + Command_Duration = Player.speed*2/5; + break; + case 'd': + drop(); + Command_Duration = Player.speed*5/5; + break; + case 'e': + eat(); + Command_Duration = 30; + break; + case 'f': + fire(); + Command_Duration = Player.speed*5/5; + break; + case 'g': + pickup(); + Command_Duration = Player.speed*10/5; + break; + case 'i': + do_inventory_control(); + break; + case 'm': + magic(); + Command_Duration = 12; + break; + case 'o': + opendoor(); + Command_Duration = Player.speed*5/5; + break; + case 'p': + pickpocket(); + Command_Duration = Player.speed*20/5; + break; + case 'q': + quaff(); + Command_Duration = 10; + break; + case 'r': + peruse(); + Command_Duration = 20; + break; + case 's': + search(&searchval); + Command_Duration = 20; + break; + case 't': + talk(); + Command_Duration = 10; + break; + case 'v': + vault(); + Command_Duration = Player.speed*10/5; + break; + case 'x': + examine(); + Command_Duration = 1; + break; + case 'z': + bash_location(); + Command_Duration = Player.speed*10/5; + break; + case 'A': + activate(); + Command_Duration = 10; + break; + case 'C': + callitem(); + break; + case 'D': + disarm(); + Command_Duration = 30; + break; + case 'E': + dismount_steed(); + Command_Duration = Player.speed*10/5; + break; + case 'F': + tacoptions(); + break; + case 'G': + give(); + Command_Duration = 10; + break; + case 'I': + if (! optionp(TOPINV)) top_inventory_control(); + else { + display_possessions(); + inventory_control(); + } + break; + case 'M': + city_move(); + Command_Duration = 10; + break; + case 'O': + setoptions(); +#if defined(WIN32) + show_screen(); + xredraw(); +#endif + break; + case 'P': + show_license(); + break; /* actually show_license is in file.c */ + case 'Q': + quit(); + break; + case 'R': + rename_player(); + break; + case 'S': + save(false); + break; + case 'T': + tunnel(); + Command_Duration = Player.speed*30/5; + break; + case 'V': + version(); + break; + case 'Z': + bash_item(); + Command_Duration = Player.speed*10/5; + break; + case '.': + rest(); + Command_Duration = 10; + break; + case ',': + nap(); + break; + case '>': + downstairs(); + break; + case '<': + upstairs(); + break; + case '@': + p_movefunction(Level->site[Player.x][Player.y].p_locf); + Command_Duration = 5; + break; + case '#': + if (State.getCheater()) editstats(); + break; /* RAC - char editor */ + case '/': + charid(); + State.setSkipMonsters(); + break; + case '?': + help(); + State.setSkipMonsters(); + break; + case '4': + case 'h': +#ifdef KEY_LEFT + case KEY_LEFT: +#endif + case (char)KEY_ARROW_LEFT: + moveplayer(-1,0); + Command_Duration = Player.speed*5/5; + break; + case '2': + case 'j': +#ifdef KEY_DOWN + case KEY_DOWN: +#endif + case (char)KEY_ARROW_DOWN: + moveplayer(0,1); + Command_Duration = Player.speed*5/5; + break; +#ifdef KEY_UP + case KEY_UP: +#endif + case (char)KEY_ARROW_UP: + case '8': + case 'k': + moveplayer(0,-1); + Command_Duration = Player.speed*5/5; + break; +#ifdef KEY_RIGHT + case KEY_RIGHT: +#endif + case (char)KEY_ARROW_RIGHT: + case '6': + case 'l': + moveplayer(1,0); + Command_Duration = Player.speed*5/5; + break; + case '1': + case 'b': + moveplayer(-1,1); + Command_Duration = Player.speed*5/5; + break; + case '3': + case 'n': + moveplayer(1,1); + Command_Duration = Player.speed*5/5; + break; + case '7': + case 'y': + moveplayer(-1,-1); + Command_Duration = Player.speed*5/5; + break; + case '9': + case 'u': + moveplayer(1,-1); + Command_Duration = Player.speed*5/5; + break; + case '5': + State.setSkipMonsters(); /* don't do anything; a dummy turn */ + Cmd = mgetc(); + while ((Cmd != ESCAPE) && + ((Cmd < '1') || (Cmd > '9') || (Cmd=='5'))) { + print3("Run in keypad direction [ESCAPE to abort]: "); + Cmd = mgetc(); + } + if (Cmd != ESCAPE) + State.setFastMove(); + else + clearmsg3(); + break; + case 'H': +#ifdef KEY_SLEFT + case KEY_SLEFT: +#endif + State.setFastMove(); + Cmd = 'h'; + moveplayer(-1,0); + Command_Duration = Player.speed*4/5; + break; + case 'J': +#ifdef KEY_SDOWN + case KEY_SDOWN: +#endif + State.setFastMove(); + Cmd = 'j'; + moveplayer(0,1); + Command_Duration = Player.speed*4/5; + break; + case 'K': +#ifdef KEY_SUP + case KEY_SUP: +#endif + State.setFastMove(); + Cmd = 'k'; + moveplayer(0,-1); + Command_Duration = Player.speed*4/5; + break; + case 'L': +#ifdef KEY_SRIGHT + case KEY_SRIGHT: +#endif + State.setFastMove(); + Cmd = 'l'; + moveplayer(1,0); + Command_Duration = Player.speed*4/5; + break; + case 'B': + State.setFastMove(); + Cmd = 'b'; + moveplayer(-1,1); + Command_Duration = Player.speed*4/5; + break; + case 'N': + State.setFastMove(); + Cmd = 'n'; + moveplayer(1,1); + Command_Duration = Player.speed*4/5; + break; + case 'Y': + State.setFastMove(); + Cmd = 'y'; + moveplayer(-1,-1); + Command_Duration = Player.speed*4/5; + break; + case 'U': + State.setFastMove(); + Cmd = 'u'; + moveplayer(1,-1); + Command_Duration = Player.speed*4/5; + break; + default: + commanderror(); + State.setSkipMonsters(); + break; + } + } + if (Current_Environment != E_COUNTRYSIDE) roomcheck(); + screencheck(Player.x,Player.y); +} + +/* deal with a new player command in countryside mode */ +void p_country_process(void) +{ + int no_op; + + drawvision(Player.x,Player.y); + do { + no_op = false; + Cmd = mgetc(); + clear_if_necessary(); + switch (Cmd) { + case ' ': + case 13: + no_op = true; + break; + case 7: + wizard(); + break; /* ^g */ + case 12: + xredraw(); + no_op = true; + break; /* ^l */ +#if !defined(WIN32) + case 16: + bufferprint(); + no_op = true; + break; /* ^p */ +#else + case 15: + bufferprint(); + no_op = true; + break; /* ^o */ +#endif + case 18: + redraw(); + no_op = true; + break; /* ^r */ + case 23: + if (State.getCheater()) drawscreen(); + break; /* ^w */ + case 24: + if (State.getCheater() || + Player.rank[ADEPT]) wish(1); + break; /* ^x */ + case 'd': + drop(); + break; + case 'e': + eat(); + break; + case 'i': + do_inventory_control(); + break; + case 's': + countrysearch(); + break; + case 'x': + examine(); + break; + case 'E': + dismount_steed(); + break; + case 'H': + hunt(Country[Player.x][Player.y].current_terrain_type); + break; + case 'I': + if (! optionp(TOPINV)) top_inventory_control(); + else { + menuclear(); + display_possessions(); + inventory_control(); + } + break; + case 'O': + setoptions(); + break; + case 'P': + show_license(); + break; /* actually show_license is in file.c */ + case 'Q': + quit(); + break; + case 'R': + rename_player(); + break; + case 'S': + save(false); + break; + case 'V': + version(); + break; + case '>': + enter_site(Country[Player.x][Player.y].base_terrain_type); + break; + case '#': + if (State.getCheater()) editstats(); + break; /* RAC - char editor */ + case '/': + charid(); + no_op = true; + break; + case '?': + help(); + no_op = true; + break; + case '4': + case 'h': + movepincountry(-1,0); + break; + case '2': + case 'j': + movepincountry(0,1); + break; + case '8': + case 'k': + movepincountry(0,-1); + break; + case '6': + case 'l': + movepincountry(1,0); + break; + case '1': + case 'b': + movepincountry(-1,1); + break; + case '3': + case 'n': + movepincountry(1,1); + break; + case '7': + case 'y': + movepincountry(-1,-1); + break; + case '9': + case 'u': + movepincountry(1,-1); + break; + default: + commanderror(); + no_op = true; + break; + } + } while (no_op); + screencheck(Player.x,Player.y); +} + + diff --git a/Omega/src/defs.h b/Omega/src/defs.h index 61a5746..5cd7a64 100644 --- a/Omega/src/defs.h +++ b/Omega/src/defs.h @@ -1,1628 +1,1638 @@ -/* omega copyright (c) 1987,1988,1989 by Laurence Raphael Brothers */ -/* This file is the header file for all omega modules */ -/* defs.h */ - -/* omega will NOT function unless the implementor sets the appropriate -definitions in the following section. */ - -/*--------------------------USER DEFINITIONS--------------------------*/ - -#ifdef WIN32 -#include -#include - -#undef MOUSE_MOVED // Will be redefined when curses is included -#define strlen(x) (int)strlen(x) // Squashes numerous warnings -#define sleep(x) Sleep((DWORD) (x * 1000)) -#define usleep(x) sleep(x / 1000000.0) - -extern char* getlogin(); -#else -// These includes are not supported or supplanted in Windows -#include -#include -#include -#include -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include // The assert macro (for ANSI/ISO C). Hopefully this will always work! -#include - -#include "curses.h" -#include "colors.h" - -#include "GameState.h" -#include "Object.h" -#include "Monster.h" -#include "Village.h" - -/* Objects */ -#include "Thing.h" - -/* Update the display every turn to center on the player. Rather heavy - * on the bandwidth. */ -#define CENTER_ON_PLAYER // TODO Make this a user-specifiable option - -/* Implementor should define int32 as the type of integer which uses - * 32 bits. */ -typedef int int32; - -/* Define the maximum length of a filename on your system. If you don't */ -/* define, will try to make an educated guess. If you have one, */ -/* /usr/include/limits.h is a good place to look for this value. */ -#define FNAME_MAX_LEN 48 - -/* OMEGALIB is where all the data files reside. - Note the final / is necessary. - msdos note: \ is the C string escape character, so you need \\ in the - path given in OMEGALIB - This might usually be "/usr/games/lib/omegalib/", for unix, - or something like "c:\\games\\omega\\omegalib\\" for msdos */ - -#define OMEGALIB "data/" - -/* TILEFILE is the name of the file you want to use for graphics tiles. You */ -/* aren't really free to use any file you want here. It should be the Omega */ -/* distribution graphics files provided for your computer. Of course a file */ -/* of the same format and size as the "correct" file will also work if you */ -/* want to change things around. This file should be located in OMEGALIB */ - -#define TILEFILE "omegatiles.xpm" - -/*---------------------------SYSTEM DEFINITIONS---------------------------*/ - -/* Don't change anything from here on (unless you know what you're doing) */ -#define VERSION 9100 -#define VERSIONSTRING "Omega version 0.91" - -#ifndef WIN32 -#define UNIX // Assuming *nix -#endif - -#define VACANT 0 -#define ABORT -1 -#define CASHVALUE -2 - -/* moderately arbitrary but probably cannot be easily changed */ -/*#define MAXWIDTH 64*/ -#define MAXWIDTH 128 -#define MAXLENGTH 64 -#define SMALLSCREEN_LENGTH 16 -#define SMALLSCREEN_WIDTH 64 - -#define STANDARD_LENGTH 64 -#define STANDARD_WIDTH 64 - -#define ARENA_WIDTH SMALLSCREEN_WIDTH -#define ARENA_LENGTH SMALLSCREEN_LENGTH - -#define ABYSS_WIDTH STANDARD_WIDTH -#define ABYSS_LENGTH SMALLSCREEN_LENGTH - -#define ASTRAL_WIDTH STANDARD_WIDTH -#define ASTRAL_LENGTH STANDARD_LENGTH - -#define CASTLE_WIDTH STANDARD_WIDTH -#define CASTLE_LENGTH STANDARD_LENGTH - -#define CAVES_WIDTH STANDARD_WIDTH -#define CAVES_LENGTH STANDARD_LENGTH - -#define CIRCLE_WIDTH SMALLSCREEN_WIDTH -#define CIRCLE_LENGTH SMALLSCREEN_LENGTH - -#define COUNTRY_WIDTH STANDARD_WIDTH -#define COUNTRY_LENGTH STANDARD_LENGTH - -#define COURT_WIDTH SMALLSCREEN_WIDTH -#define COURT_LENGTH 24 - -#define DLAIR_WIDTH SMALLSCREEN_WIDTH -#define DLAIR_LENGTH SMALLSCREEN_LENGTH - -#define HOUSE_WIDTH SMALLSCREEN_WIDTH -#define HOUSE_LENGTH SMALLSCREEN_LENGTH - -#define HOVEL_WIDTH SMALLSCREEN_WIDTH -#define HOVEL_LENGTH SMALLSCREEN_LENGTH - -#define MANSION_WIDTH SMALLSCREEN_WIDTH -#define MANSION_LENGTH SMALLSCREEN_LENGTH - -#define MISLE_WIDTH SMALLSCREEN_WIDTH -#define MISLE_LENGTH SMALLSCREEN_LENGTH - -#define PALACE_WIDTH STANDARD_WIDTH -#define PALACE_LENGTH STANDARD_LENGTH - -#define RAMPART_WIDTH 128 -#define RAMPART_LENGTH STANDARD_LENGTH - -#define SEWERS_WIDTH STANDARD_WIDTH -#define SEWERS_LENGTH STANDARD_LENGTH - -#define SPEAK_WIDTH SMALLSCREEN_WIDTH -#define SPEAK_LENGTH SMALLSCREEN_LENGTH - -#define TACTICAL_WIDTH SMALLSCREEN_WIDTH -#define TACTICAL_LENGTH SMALLSCREEN_LENGTH - -#define TEMPLE_WIDTH SMALLSCREEN_WIDTH -#define TEMPLE_LENGTH SMALLSCREEN_LENGTH - -#define VILLAGE_WIDTH SMALLSCREEN_WIDTH -#define VILLAGE_LENGTH SMALLSCREEN_LENGTH - -#define VOLCANO_WIDTH STANDARD_WIDTH -#define VOLCANO_LENGTH STANDARD_LENGTH - -/* number of slots in inventory. Cannot be changed without work */ -#define MAXITEMS 16 - -/* number of slots in pack. Should be <= 26. */ -#define MAXPACK 26 - -/* number of items in pawn shop. Should be <= 26 */ -#define PAWNITEMS 20 /* DG -- the more the merrier. WDT -- I agree. */ - -/* number of lines back strings are recalled */ -#define STRING_BUFFER_SIZE 25 - -/* number of rerolls allowed +1 */ /* added by dagibbs (DG) */ -#define REROLLS -1 - -/* Verbosity levels */ -#define TERSE 0 -#define MEDIUM 1 -#define VERBOSE 2 - -/* Arbitrary. Max of the levels in the dungeons */ -#define MAXLEVELS 21 - -/* levels in each dungeon */ -#define ASTRALLEVELS 5 -#define SEWERLEVELS 18 -#define CASTLELEVELS 16 -#define CAVELEVELS 10 -#define VOLCANOLEVELS 20 -#define PALACELEVELS 14 - -/* non-existant environments for the random number seeding routine */ -/* added 12/30/98 (DG) */ -#define E_RESTORE -2 -#define E_RANDOM -1 -/* general environment types */ -#define E_NEVER_NEVER_LAND 0 -#define E_COUNTRYSIDE 1 -#define E_CITY 2 -#define E_VILLAGE 3 -#define E_TACTICAL_MAP 4 -#define E_SEWERS 5 -#define E_CASTLE 6 -#define E_CAVES 7 -#define E_VOLCANO 8 -#define E_ASTRAL 9 -#define E_ARENA 10 -#define E_HOVEL 11 -#define E_MANSION 12 -#define E_HOUSE 13 -#define E_DLAIR 14 -#define E_ABYSS 15 -#define E_STARPEAK 16 -#define E_MAGIC_ISLE 17 -#define E_TEMPLE 18 -#define E_CIRCLE 19 -#define E_COURT 20 -#define E_PALACE 21 -#define E_MAX E_PALACE - -/* player game status */ -#define DEAD 1 -#define QUIT 2 -#define WIN 3 -#define BIGWIN 4 - -/* kind of arbitrary */ -#define MAXROOMS 48 -#define MAXCONNECTIONS 4 -#define STRING_LEN 100 - -/* some random characters */ -#define ESCAPE 27 -#define RETURN '\n' /* Aren't these backwards? WSS */ -#define LINEFEED '\r' /* Aren't these backwards? WSS */ -#define BACKSPACE '\b' -#define DELETE_CHAR 127 - -/* tac mode action definitions */ -/* have to remember to find where these are used, mostly unused, now! */ -#define DISENGAGE 10 -#define BLOCK 20 -#define CUT 30 -#define THRUST 40 -#define MAGIC 50 -#define LUNGE 60 -#define RIPOSTE 70 -#define WIELD 80 -#define PICK_UP 90 - -/* as in attack low, block high, etc. */ -/* These values may be added to the ones above to get things like - block high, cut low, etc. CLEVER is only used by some monsters - to cheat with.... */ -#define LOW 1 -#define CENTER 2 -#define HIGH 3 -#define CLEVER 4 - -/* weapon types */ -#define CUTTING 1 -#define THRUSTING 2 -#define STRIKING 3 -#define MISSILE 4 - -/* random aux constants */ -/* aux field for private residences in city */ -#define BURGLED 2 -#define LOCKED 3 -#define UNLOCKED 0 - -/* cannot use M command on site with this aux value */ -#define NOCITYMOVE 666 - -/* bow and crossbow object aux fields */ -#define LOADED 1 -#define UNLOADED 0 - -/* alignment used randomly throughout*/ -#define LAWFUL 1 -#define CHAOTIC 2 -#define NEUTRAL 3 - -/* spells */ -#define NUMSPELLS 42 - -#define S_MON_DET 0 -#define S_OBJ_DET 1 -#define S_MISSILE 2 -#define S_FIREBOLT 3 -#define S_TELEPORT 4 -#define S_LBALL 5 -#define S_SLEEP 6 -#define S_DISRUPT 7 -#define S_DISINTEGRATE 8 -#define S_POLYMORPH 9 -#define S_HEAL 10 -#define S_DISPEL 11 -#define S_IDENTIFY 12 -#define S_BREATHE 13 -#define S_INVISIBLE 14 -#define S_WARP 15 -#define S_ENCHANT 16 -#define S_BLESS 17 -#define S_RESTORE 18 -#define S_CURE 19 -#define S_TRUESIGHT 20 -#define S_HELLFIRE 21 -#define S_KNOWLEDGE 22 -#define S_HERO 23 -#define S_RETURN 24 -#define S_DESECRATE 25 -#define S_HASTE 26 -#define S_SUMMON 27 -#define S_SANCTUARY 28 -#define S_ACCURACY 29 -#define S_RITUAL 30 -#define S_FEAR 31 -#define S_APPORT 32 -#define S_SHADOWFORM 33 -#define S_ALERT 34 -#define S_REGENERATE 35 -#define S_SANCTIFY 36 -#define S_CLAIRVOYANCE 37 -#define S_DRAIN 38 -#define S_LEVITATE 39 -#define S_WISH 40 -#define S_NUTRITION 41 - -/* ranks in guilds, etc */ -#define NUMRANKS 10 - -#define LEGION 0 -#define ARENA 1 -#define COLLEGE 2 -#define THIEVES 3 -#define ORDER 4 -#define CIRCLE 5 -#define NOBILITY 6 -#define PRIESTHOOD 7 -#define MONKS 8 -#define ADEPT 9 - -#define LEGIONAIRE 1 -#define CENTURION 2 -#define FORCE_LEADER 3 -#define COLONEL 4 -#define COMMANDANT 5 - -#define TRAINEE 1 -#define BESTIARIUS 2 -#define RETIARIUS 3 -#define GLADIATOR 4 -#define CHAMPION 5 - -#define NOVICE 1 -#define STUDENT 2 -#define PRECEPTOR 3 -#define MAGE 4 -#define ARCHMAGE 5 - -#define TMEMBER 1 -#define ATHIEF 2 -#define THIEF 3 -#define TMASTER 4 -#define SHADOWLORD 5 - -#define GALLANT 1 -#define GUARDIAN 2 -#define CHEVALIER 3 -#define PALADIN 4 -#define JUSTICIAR 5 - -#define INITIATE 1 -#define ENCHANTER 2 -#define SORCEROR 3 -#define HIGHSORCEROR 4 -#define PRIME 5 - -#define COMMONER 1 -#define ESQUIRE 2 -#define KNIGHT 3 -#define LORD 4 -#define DUKE 5 - -#define LAY 1 -#define ACOLYTE 2 -#define PRIEST 3 -#define SPRIEST 4 -#define HIGHPRIEST 5 - -#define MONK_TRAINEE 1 -#define MONK_MONK 2 -#define MONK_MASTER 3 -#define MONK_MASTER_SIGHS 4 -#define MONK_MASTER_PAINS 5 -#define MONK_MASTER_TEARS 6 -#define MONK_GRANDMASTER 7 - -/* different priesthoods */ -#define ODIN 1 -#define SET 2 -#define ATHENA 3 -#define HECATE 4 -#define DRUID 5 -#define DESTINY 6 - - - -/* MONSTER STATUS/ABILITY BITS */ -/* currently a long */ -#define AWAKE 1 -#define MOBILE 2 -#define HOSTILE 4 -/* missing bit 3, 8 */ -#define WANDERING 16 -#define HUNGRY 32 -#define GREEDY 64 -#define NEEDY 128 -#define ONLYSWIM 256 -#define FLYING 512 -#define INTANGIBLE 1024 -#define M_INVISIBLE 2048 -#define SWIMMING 4096 -#define POISONOUS 8192 -#define EDIBLE 16384 -#define ALLOC 32768 /* allocated name & corpseString */ - - -/* PLAYER STATUS INDICES */ -#define NUMSTATI 25 - -#define ACCURACY 0 -#define BLINDED 1 -#define SLOWED 2 -#define DISPLACED 3 -#define SLEPT 4 -#define DISEASED 5 -#define POISONED 6 -#define HASTED 7 -#define BREATHING 8 -#define INVISIBLE 9 -#define REGENERATING 10 -#define VULNERABLE 11 -#define BERSERK 12 -#define IMMOBILE 13 -#define ALERT 14 -#define AFRAID 15 -#define HERO 16 -#define LEVITATING 17 -#define ACCURATE 18 -#define TRUESIGHT 19 -#define SHADOWFORM 20 -#define ILLUMINATION 21 -#define DEFLECTION 22 -#define PROTECTION 23 -/* PROTECTION is deviant -- indicates protective value, not duration */ -#define RETURNING 24 -/* RETURNING is somewhat deviant--how many turns 'til RETURN spell goes off */ - -/* player immunity indices */ -/* also monster immunity bits (2^n) */ -/* also damage types */ -#define NUMIMMUNITIES 14 - -#define UNSTOPPABLE 0 -#define NORMAL_DAMAGE 1 -#define FLAME 2 -#define COLD 3 -#define ELECTRICITY 4 -#define POISON 5 -#define ACID 6 -#define FEAR 7 -#define SLEEP 8 -#define NEGENERGY 9 -#define OTHER_MAGIC 10 -#define THEFT 11 -#define GAZE 12 -#define INFECTION 13 -#define EVERYTHING -1 - - -/* location lstatus bits */ -#define SEEN 1 -#define LIT 2 -#define SECRET 4 -#define STOPS 8 -#define CHANGED 16 - - -/* room string id */ -/* for use in roomname() */ -/* number of rooms above ROOMBASE */ -#define NUMROOMNAMES 30 - -#define RS_WALLSPACE 1 -#define RS_CORRIDOR 2 -#define RS_CAVERN 3 -#define RS_GOBLINKING 4 -#define RS_DRAGONLORD 5 -#define RS_PONDS 6 -#define RS_OCEAN 7 -#define RS_WYRM 8 -#define RS_ADEPT 9 -#define RS_DESTINY 10 -#define RS_ODIN 11 -#define RS_SET 12 -#define RS_ATHENA 13 -#define RS_HECATE 14 -#define RS_DRUID 15 -#define RS_COUNTRYSIDE 16 -#define RS_ARENA 17 -#define RS_SEWER_DUCT 18 -#define RS_DRAINED_SEWER 19 -#define RS_DROWNED_SEWER 20 -#define RS_KITCHEN 21 -#define RS_BEDROOM 22 -#define RS_BATHROOM 23 -#define RS_DININGROOM 24 -#define RS_SECRETPASSAGE 25 -#define RS_CLOSET 26 -#define RS_LOWERASTRAL 27 -#define RS_EARTHPLANE 28 -#define RS_WATERPLANE 29 -#define RS_AIRPLANE 30 -#define RS_FIREPLANE 31 -#define RS_HIGHASTRAL 32 -#define RS_VOLCANO 33 -#define RS_STARPEAK 34 -#define RS_MAGIC_ISLE 35 -#define RS_CIRCLE 36 -#define RS_ZORCH 37 -#define RS_COURT 38 -/* normal room name indices start after the RS_ constants */ -#define ROOMBASE 39 -#define RS_GARDEROBE ROOMBASE+0 -#define RS_CELL ROOMBASE+1 -#define RS_TILED ROOMBASE+2 -#define RS_CRYSTAL_CAVE ROOMBASE+3 -#define RS_BEDROOM2 ROOMBASE+4 -#define RS_STOREROOM ROOMBASE+5 -#define RS_CHARRED ROOMBASE+6 -#define RS_MARBLE_HALL ROOMBASE+7 -#define RS_EERIE_CAVE ROOMBASE+8 -#define RS_TREASURE ROOMBASE+9 -#define RS_SMOKEY ROOMBASE+10 -#define RS_APARTMENT ROOMBASE+11 -#define RS_ANTECHAMBER ROOMBASE+12 -#define RS_HAREM ROOMBASE+13 -#define RS_MULTIPURPOSE ROOMBASE+14 -#define RS_STALACTITES ROOMBASE+15 -#define RS_GREENHOUSE ROOMBASE+16 -#define RS_WATERCLOSET ROOMBASE+17 -#define RS_STUDY ROOMBASE+18 -#define RS_LIVING_ROOM ROOMBASE+19 -#define RS_DEN ROOMBASE+20 -#define RS_ABATOIR ROOMBASE+21 -#define RS_BOUDOIR ROOMBASE+22 -#define RS_STAR_CHAMBER ROOMBASE+23 -#define RS_MANMADE_CAVE ROOMBASE+24 -#define RS_SEWER_CONTROL ROOMBASE+25 -#define RS_SHRINE ROOMBASE+26 -#define RS_MAGIC_LAB ROOMBASE+27 -#define RS_PENTAGRAM ROOMBASE+28 -#define RS_OMEGA_DAIS ROOMBASE+29 - -// Color macros -#ifdef OMEGA_CLRGEN // Only defined when using the color-gen utility -# define CLR(fg) OMEGA_CLRGEN1 fg -# define CLRS(fg, bg) OMEGA_CLRGEN2 fg bg -#else -# define CLR(fg) CLR_##fg##_BLACK -# define CLRS(fg, bg) CLR_##fg##_##bg -#endif - -/* objects, locations, and terrain; characters to draw */ -#define NULL_ITEM '\0' -#define SPACE (' ' | CLR(WHITE)) -#define WALL ('#' | CLR(GREY)) -#define PORTCULLIS ('7' | CLR(WHITE)) -#define OPEN_DOOR ('|' | CLR(BROWN)) -#define CLOSED_DOOR ('-' | CLR(BROWN)) -#define WHIRLWIND ('6' | CLR(LIGHT_BLUE)) -#define ABYSS ('0' | CLRS(BLACK,BROWN)) -#define VOID_CHAR (' ' | CLR(WHITE)) -#define LAVA ('`' | CLR(RED)) -#define HEDGE ('\"' | CLR(GREEN)) -#define WATER ('~' | CLR(BLUE)) -#define FIRE (';' | CLR(LIGHT_RED)) -#define TRAP ('^' | CLR(RED)) -#define LIFT ('_' | CLR(BRIGHT_WHITE)) -#define STAIRS_UP ('<' | CLR(WHITE)) -#define STAIRS_DOWN ('>' | CLR(WHITE)) -#define FLOOR ('.' | CLR(BROWN)) -#define PLAYER ('@' | CLR(WHITE)) -#define CORPSE ('+' | CLR(RED)) -#define STATUE ('1' | CLR(GREY)) -#define RUBBLE ('4' | CLR(GREY)) -#define ALTAR ('8' | CLR(LIGHT_BLUE)) -#define CASH ('$' | CLR(YELLOW)) /* various kinds of money */ -#define PILE ('*' | CLR(BRIGHT_WHITE)) /* several objects in one place */ -#define FOOD ('%' | CLR(BROWN)) -#define WEAPON (')' | CLR(GREY)) -#define MISSILEWEAPON ('(' | CLR(BROWN)) -#define SCROLL ('?' | CLR(YELLOW)) -#define POTION ('!' | CLR(LIGHT_GREEN)) -#define ARMOR (']' | CLR(GREY)) -#define SHIELD ('[' | CLR(BROWN)) -#define CLOAK ('}' | CLR(CYAN)) -#define BOOTS ('{' | CLR(BROWN)) -#define STICK ('/' | CLR(BROWN)) - -#define RING ('=' | CLR(YELLOW)) -#define THING ('\\' | CLR(WHITE)) -#define ARTIFACT ('&' | CLR(YELLOW)) - -/* TERRAIN TYPES */ -#define PLAINS ('-' | CLR(LIGHT_GREEN)) -#define TUNDRA ('_' | CLR(GREY)) -#define ROAD ('.' | CLR(BROWN)) -#define MOUNTAINS ('^' | CLR(GREY)) -#define PASS ('v' | CLR(BROWN)) -#define RIVER ('~' | CLR(BLUE)) -#define CITY ('O' | CLR(WHITE)) -#define VILLAGE ('o' | CLR(WHITE)) -#define FOREST ('(' | CLR(LIGHT_GREEN)) -#define JUNGLE (')' | CLR(GREEN)) -#define SWAMP ('=' | CLR(GREEN)) -#define VOLCANO ('!' | CLR(RED)) -#define CASTLE ('%' | CLR(GREY)) -#define TEMPLE ('X' | CLR(BROWN)) -#define CAVES ('*' | CLRS(BLACK,BROWN)) -#define DESERT ('\"' | CLR(YELLOW)) -#define CHAOS_SEA ('+' | CLR(LIGHT_PURPLE)) -#define STARPEAK ('|' | CLR(LIGHT_BLUE)) -#define DRAGONLAIR ('$' | CLR(BROWN)) -#define MAGIC_ISLE ('&' | CLR(PURPLE)) -#define PALACE ('K' | CLR(PURPLE)) - -#define CHAIR ('5' | CLR(BROWN)) -#define SAFE ('3' | CLR(GREY)) -#define FURNITURE ('2' | CLR(BROWN)) -#define BED ('9' | CLR(CYAN)) - -/* wow, all characters used! */ - -/* total number of editable stats */ -#define NUMSTATS 11 - -/* total number of player options */ -#define NUMOPTIONS 10 - -/* number of options with true/false values */ -#define NUMTFOPTIONS 9 - -/* The slot number of the two options not in Player.options */ -#define VERBOSITY_LEVEL 9 -#define SEARCH_DURATION 10 - -/* Player.options bits */ -#define BELLICOSE 1 -#define JUMPMOVE 2 -#define RUNSTOP 4 -#define PICKUP 8 -#define CONFIRM 16 -#define TOPINV 32 -#define PACKADD 64 -#define SHOW_COLOUR 256 - -/* This has to be changed whenever an item is added */ -#define NUMSCROLLS 24 -#define NUMPOTIONS 18 -#define NUMFOODS 16 -#define NUMTHINGS 31 /* DAG for mirror of self-knowledge */ /* WSS cards */ -#define NUMCARDS 4 -#define NUMWEAPONS 41 -#define NUMARMOR 17 -#define NUMSHIELDS 8 -#define NUMCLOAKS 7 -#define NUMBOOTS 7 -#define NUMRINGS 9 /* DAG loss of ring of self-knowledge */ -#define NUMSTICKS 17 -#define NUMARTIFACTS 26 - -/* running sum of itemtypes, for indexing into Objects array */ -#define THINGID 0 -#define CARDID (THINGID+NUMTHINGS-NUMCARDS) -#define FOODID NUMTHINGS /* 26 */ -#define SCROLLID (FOODID + NUMFOODS) /* 42 */ -#define POTIONID (SCROLLID + NUMSCROLLS) /* 66 */ -#define WEAPONID (POTIONID + NUMPOTIONS) /* 84 */ -#define ARMORID (WEAPONID + NUMWEAPONS) /* 125 */ -#define SHIELDID (ARMORID + NUMARMOR) /* 142 */ -#define CLOAKID (SHIELDID + NUMSHIELDS) /* 150 */ -#define BOOTID (CLOAKID + NUMCLOAKS) /* 157 */ -#define RINGID (BOOTID + NUMBOOTS) /* 164 */ -#define STICKID (RINGID + NUMRINGS) /* 174 */ -#define ARTIFACTID (STICKID + NUMSTICKS) /* 191 */ -#define CASHID (ARTIFACTID+NUMARTIFACTS) /* 216 */ -/* Corpse's aux field is monster id */ -#define CORPSEID (CASHID+1) - -#define TOTALITEMS (CORPSEID+1) - -/* descriptive constants for various object ids */ -#define OB_GARAGE_OPENER (THINGID+0) -#define OB_LOCK_PICK (THINGID+2) -#define OB_SALT_WATER (THINGID+6) -#define OB_KEY (THINGID+7) -#define OB_TORCH (THINGID+8) -#define OB_JUSTICIAR_BADGE (THINGID+16) -#define OB_TRAP_DART (THINGID+17) -#define OB_TRAP_ACID (THINGID+18) -#define OB_TRAP_SNARE (THINGID+19) -#define OB_TRAP_FIRE (THINGID+20) -#define OB_TRAP_TELEPORT (THINGID+21) -#define OB_TRAP_SLEEP (THINGID+22) -#define OB_TRAP_DISINTEGRATE (THINGID+23) -#define OB_TRAP_ABYSS (THINGID+24) -#define OB_TRAP_MANADRAIN (THINGID+25) -#define OB_DEBIT_CARD (CARDID+0) -#define OB_CREDIT_CARD (CARDID+1) -#define OB_PREPAID_CARD (CARDID+2) -#define OB_SMART_CARD (CARDID+3) -#define OB_RATION (FOODID+0) -#define OB_LEMBAS (FOODID+1) -#define OB_GRAIN (FOODID+15) -#define OB_BLANK_SCROLL (SCROLLID+0) -#define OB_SPELLS_SCROLL (SCROLLID+1) -#define OB_SCROLL_LAW (SCROLLID+17) -#define OB_POTION_CHAOS (POTIONID+14) -#define OB_SHORT_SWORD (WEAPONID+1) -#define OB_GREAT_SWORD (WEAPONID+5) -#define OB_GREAT_AXE (WEAPONID+12) -#define OB_CLUB (WEAPONID+17) -#define OB_QUARTERSTAFF (WEAPONID+18) -#define OB_SPEAR (WEAPONID+19) -#define OB_HALBERD (WEAPONID+20) -#define OB_MACE_DISRUPT (WEAPONID+25) -#define OB_LONGBOW (WEAPONID+26) -#define OB_CROSSBOW (WEAPONID+27) -#define OB_ARROW (WEAPONID+28) -#define OB_BOLT (WEAPONID+29) -#define OB_DESECRATOR (WEAPONID+32) -#define OB_DEFENDER (WEAPONID+34) -#define OB_VICTRIX (WEAPONID+35) -#define OB_HEWER (WEAPONID+36) -#define OB_GIANT_CLUB (WEAPONID+38) -#define OB_SCYTHE_DEATH (WEAPONID+39) -#define OB_LEATHER (ARMORID+1) -#define OB_MITHRIL_PLATE (ARMORID+11) -#define OB_DRAGONSCALE (ARMORID+12) -#define OB_LRG_RND_SHIELD (SHIELDID+2) -#define OB_DEFLECT (SHIELDID+7) -#define OB_CLOAK_PROTECT (CLOAKID+4) -#define OB_ORB_MASTERY (ARTIFACTID+0) -#define OB_ORB_FIRE (ARTIFACTID+1) -#define OB_ORB_WATER (ARTIFACTID+2) -#define OB_ORB_EARTH (ARTIFACTID+3) -#define OB_ORB_AIR (ARTIFACTID+4) -#define OB_DEAD_ORB (ARTIFACTID+5) -#define OB_ANTIOCH (ARTIFACTID+7) -#define OB_YENDOR (ARTIFACTID+8) -#define OB_KOLWYNIA (ARTIFACTID+9) -#define OB_POTION_DEATH (ARTIFACTID+10) -#define OB_POTION_LIFE (ARTIFACTID+13) -#define OB_SYMBOL_ODIN (ARTIFACTID+14) -#define OB_SYMBOL_SET (ARTIFACTID+15) -#define OB_SYMBOL_ATHENA (ARTIFACTID+16) -#define OB_SYMBOL_HECATE (ARTIFACTID+17) -#define OB_SYMBOL_DRUID (ARTIFACTID+18) -#define OB_SYMBOL_DESTINY (ARTIFACTID+19) -#define OB_KARNAK (ARTIFACTID+20) -#define OB_STARGEM (ARTIFACTID+21) -#define OB_SCEPTRE (ARTIFACTID+22) -#define OB_HOLDING (ARTIFACTID+24) - -/* describing unique items and monsters */ -#define COMMON 0 -#define UNIQUE_UNMADE 1 -#define UNIQUE_MADE 2 -#define UNIQUE_TAKEN 3 - -/* general item function id's */ -#define I_NO_OP 0 -#define I_NOTHING 1 - -/* note some of these functions are for other types of items too */ - -/* scroll functions */ -#define I_BLESS 101 -#define I_ACQUIRE 102 -#define I_ENCHANT 103 -#define I_TELEPORT 104 -#define I_WISH 105 -#define I_CLAIRVOYANCE 106 -#define I_DISPLACE 107 -#define I_ID 108 -#define I_FIREFLASH 109 -#define I_SPELLS 110 -#define I_JANE_T 111 -#define I_ALERT 112 -#define I_FLUX 113 -#define I_CHARGE 114 -#define I_WARP 115 -#define I_KNOWLEDGE 116 -#define I_LAW 117 -#define I_HINT 118 -#define I_HERO 119 -#define I_TRUESIGHT 120 -#define I_ILLUMINATE 121 -#define I_DEFLECT 122 - -/* potion functions */ -#define I_HEAL 201 -#define I_OBJDET 202 -#define I_MONDET 203 -#define I_SLEEP_SELF 204 -#define I_RESTORE 205 -#define I_NEUTRALIZE_POISON 206 -#define I_SPEED 207 -#define I_AZOTH 208 -#define I_REGENERATE 210 -#define I_INVISIBLE 211 -#define I_BREATHING 212 -#define I_FEAR_RESIST 213 -#define I_AUGMENT 214 -#define I_CHAOS 215 -#define I_ACCURACY 216 -#define I_LEVITATION 217 -#define I_CURE 218 - -/* stick functions */ -#define I_FIREBOLT 301 -#define I_LBOLT 302 -#define I_MISSILE 303 -#define I_SLEEP_OTHER 304 -#define I_FIREBALL 305 -#define I_LBALL 306 -#define I_SUMMON 307 -#define I_HIDE 308 -#define I_DISRUPT 309 -#define I_DISINTEGRATE 310 -#define I_SNOWBALL 311 -#define I_APPORT 312 -#define I_DISPEL 313 -#define I_POLYMORPH 314 -#define I_FEAR 315 - -/* food functions */ -#define I_FOOD 401 -#define I_LEMBAS 402 -#define I_STIM 403 -#define I_POW 404 -#define I_IMMUNE 405 -#define I_POISON_FOOD 406 -#define I_CORPSE 407 -#define I_PEPPER_FOOD 408 -#define I_CANNIBAL 409 -#define I_INEDIBLE 410 - -/* boots functions */ -#define I_PERM_SPEED 501 -#define I_PERM_HERO 502 -#define I_PERM_LEVITATE 503 -#define I_PERM_AGILITY 504 -#define I_BOOTS_JUMPING 505 -#define I_BOOTS_7LEAGUE 506 - -/* cloak functions */ -#define I_PERM_DISPLACE 601 -#define I_PERM_NEGIMMUNE 602 -#define I_PERM_INVISIBLE 603 -#define I_PERM_ACCURACY 604 -#define I_PERM_PROTECTION 605 -#define I_PERM_TRUESIGHT 606 - -/* ring functions */ -#define I_PERM_VISION 701 -#define I_PERM_BURDEN 702 -#define I_PERM_STRENGTH 703 -#define I_PERM_GAZE_IMMUNE 704 -#define I_PERM_FIRE_RESIST 705 -#define I_PERM_POISON_RESIST 706 -#define I_PERM_REGENERATE 707 -#define I_PERM_KNOWLEDGE 708 - -/* armor functions */ -#define I_PERM_ENERGY_RESIST 801 -#define I_PERM_BREATHING 802 -#define I_PERM_FEAR_RESIST 803 -#define I_NORMAL_ARMOR 804 - -/* artifact functions */ -#define I_ORBFIRE 901 -#define I_ORBWATER 902 -#define I_ORBEARTH 903 -#define I_ORBAIR 904 -#define I_ORBMASTERY 905 -#define I_ORBDEAD 906 -#define I_CRYSTAL 907 -#define I_ANTIOCH 908 -#define I_KOLWYNIA 909 -#define I_DEATH 910 -#define I_ENCHANTMENT 911 -#define I_HELM 912 -#define I_LIFE 913 -#define I_JUGGERNAUT 914 -#define I_SYMBOL 915 -#define I_STARGEM 916 -#define I_SCEPTRE 917 -#define I_PLANES 918 -#define I_HOLDING 919 -#define I_SERENITY 920 - -/* weapons functions */ -#define I_NORMAL_WEAPON 1001 -#define I_LIGHTSABRE 1002 -#define I_DEMONBLADE 1003 -#define I_MACE_DISRUPT 1004 -#define I_TANGLE 1005 -#define I_ARROW 1006 -#define I_BOLT 1007 -#define I_VORPAL 1008 -#define I_DESECRATE 1009 -#define I_FIRESTAR 1010 -#define I_DEFEND 1011 -#define I_VICTRIX 1012 -#define I_EMPIRE 1013 -#define I_SCYTHE 1014 -#define I_ACIDWHIP 1015 - -/* thing functions */ -#define I_PICK 1101 -#define I_KEY 1102 -#define I_SHOVEL 1103 /* unused */ -#define I_EXCAVATOR 1104 /* unused */ -#define I_PERM_ILLUMINATE 1105 -#define I_TRAP 1106 -#define I_RAISE_PORTCULLIS 1107 - -/* shield functions */ -#define I_PERM_DEFLECT 1201 -#define I_NORMAL_SHIELD 1202 - -/* monster function ids */ -/* Its conceivable for a function of one type to be called when another -would usually occur. A monster's special function may be an extra move, -for example. */ - -#define M_NO_OP -1 - -/* talk functions */ -#define M_TALK_STUPID 101 -#define M_TALK_SILENT 102 -#define M_TALK_HUNGRY 103 -#define M_TALK_GREEDY 104 -#define M_TALK_TITTER 105 -#define M_TALK_MAN 106 -#define M_TALK_ROBOT 107 -#define M_TALK_EVIL 108 -#define M_TALK_BURBLE 109 -#define M_TALK_SLITHY 110 -#define M_TALK_MIMSY 111 -#define M_TALK_SEDUCTOR 112 -#define M_TALK_MP 113 -#define M_TALK_IM 114 -#define M_TALK_GUARD 115 -#define M_TALK_GHOST 116 -#define M_TALK_HINT 117 -#define M_TALK_BEG 118 -#define M_TALK_EF 119 -#define M_TALK_GF 120 -#define M_TALK_MORGON 121 -#define M_TALK_LB 122 -#define M_TALK_DEMONLOVER 123 -#define M_TALK_ASSASSIN 124 -#define M_TALK_NINJA 125 -#define M_TALK_THIEF 126 -#define M_TALK_MERCHANT 127 -#define M_TALK_HORSE 128 -#define M_TALK_PARROT 129 -#define M_TALK_ANIMAL 130 -#define M_TALK_HYENA 131 -#define M_TALK_SERVANT 132 -#define M_TALK_SCREAM 133 -#define M_TALK_DRUID 134 -#define M_TALK_ARCHMAGE 135 -#define M_TALK_PRIME 136 -#define M_TALK_MAHARAJA 137 - -/* ability functions */ -#define M_SP_SURPRISE 201 -#define M_SP_MP 202 -#define M_SP_THIEF 203 -#define M_SP_AGGRAVATE 204 -#define M_SP_POISON_CLOUD 205 -#define M_SP_HUGE 206 -#define M_SP_SUMMON 207 -#define M_SP_ILLUSION 208 -#define M_SP_FLUTTER 209 -#define M_SP_ESCAPE 210 -#define M_SP_SPELL 211 -#define M_SP_EXPLODE 212 -#define M_SP_DEMON 213 -#define M_SP_ACID_CLOUD 214 -#define M_SP_WHIRL 215 -#define M_SP_GHOST 216 -#define M_SP_WHISTLEBLOWER 217 -#define M_SP_EATER 218 -#define M_SP_LAWBRINGER 219 -#define M_SP_DRAGONLORD 220 -#define M_SP_DE 221 -#define M_SP_DEMONLOVER 222 -#define M_SP_SEDUCTOR 223 -#define M_SP_MASTER 224 -#define M_SP_WYRM 225 -#define M_SP_BLACKOUT 226 -#define M_SP_BOG 227 -#define M_SP_MERCHANT 228 -#define M_SP_WERE 229 -#define M_SP_SERVANT 231 -#define M_SP_AV 232 -#define M_SP_LW 233 -#define M_SP_SWARM 234 -#define M_SP_ANGEL 235 -#define M_SP_MB 236 -#define M_SP_MIRROR 237 -#define M_SP_RAISE 238 -#define M_SP_DEATH 239 -#define M_SP_COURT 240 -#define M_SP_LAIR 241 -#define M_SP_PRIME 242 - -/* rangestrike functions */ -#define M_STRIKE_MISSILE 301 -#define M_STRIKE_FBOLT 302 -#define M_STRIKE_LBALL 303 -#define M_STRIKE_FBALL 304 -#define M_STRIKE_BLIND 305 -#define M_STRIKE_SNOWBALL 306 -#define M_STRIKE_MASTER 307 -#define M_STRIKE_SONIC 308 - -/* combat functions */ -#define M_MELEE_NORMAL 401 -#define M_MELEE_FIRE 402 -#define M_MELEE_DRAGON 403 -#define M_MELEE_MP 404 -#define M_MELEE_ELEC 405 -#define M_MELEE_POISON 406 -#define M_MELEE_NG 407 -#define M_MELEE_SUCCUBUS 408 -#define M_MELEE_SPIRIT 409 -#define M_MELEE_DISEASE 410 -#define M_MELEE_SLEEP 411 -#define M_MELEE_COLD 412 -#define M_MELEE_MASTER 413 -#define M_MELEE_GRAPPLE 414 -#define M_MELEE_DEATH 415 - -/* movement functions */ -#define M_MOVE_NORMAL 501 -#define M_MOVE_FLUTTER 502 -#define M_MOVE_TELEPORT 503 -#define M_MOVE_FOLLOW 504 -#define M_MOVE_RANDOM 505 -#define M_MOVE_SMART 506 -#define M_MOVE_SPIRIT 507 -#define M_MOVE_SCAREDY 508 -#define M_MOVE_CONFUSED 509 -#define M_MOVE_ANIMAL 510 -#define M_MOVE_LEASH 230 - -/* MLx -> index to Monsters starting for level x */ -/* MLx -> number of monsters of level x or less */ -/* NML_x -> number of monsters of level x */ -/* NML-X must be changed whenever a monster is added */ -/* This whole thing MUST be repaired. Monster levels must - * be represented elsewhere. */ -#define ML0 0 -#define NML_0 9 -#define ML1 (ML0 + NML_0) /* 9 */ -#define NML_1 22 -#define ML2 (ML1 + NML_1) /* 31 */ -#define NML_2 14 -#define ML3 (ML2 + NML_2) /* 45 */ -#define NML_3 15 -#define ML4 (ML3 + NML_3) /* 60 */ -#define NML_4 18 -#define ML5 (ML4 + NML_4) /* 78 */ -#define NML_5 14 -#define ML6 (ML5 + NML_5) /* 92 */ -#define NML_6 13 -#define ML7 (ML6 + NML_6) /* 105 */ -#define NML_7 15 -#define ML8 (ML7 + NML_7) /* 120 */ -#define NML_8 12 -#define ML9 (ML8 + NML_8) /* 132 */ -#define NML_9 8 -#define ML10 (ML9 + NML_9) /* 140 */ -#define NML_10 11 - -#define NUMMONSTERS (ML10 + NML_10) /* 151 */ - -/* Some monster ID's : (Those that are explicitly named in code) */ -/* Actually, there are still many magic constants floating around. */ -/* Eventually I'll get around to making each monster's id a constant.... */ -/* done, thanks to David Gibbs. */ -#define RANDOM -1 -#define HORNET (ML0+0) -#define MEND_PRIEST (ML0+1) -#define ITIN_MERCH (ML0+2) -#define GUARD (ML0+3) -#define NPC (ML0+4) -#define SHEEP (ML0+5) -#define MERCHANT (ML0+6) -#define ZERO_NPC (ML0+7) -#define HISCORE_NPC (ML0+8) -#define GRUNT (ML1+0) -#define TSETSE (ML1+1) -#define FNORD (ML1+2) -#define SEWER_RAT (ML1+3) -#define AGGRAVATOR (ML1+4) -#define BLIPPER (ML1+5) -#define GOBLIN (ML1+6) -#define PHANTASTICON (ML1+7) -#define ROBOT (ML1+8) -#define GEEK (ML1+9) -#define BOROGROVE (ML1+10) -#define QUAIL (ML1+11) -#define BADGER (ML1+12) -#define HAWK (ML1+13) -#define DEER (ML1+14) -#define CAMEL (ML1+15) -#define ANTEATER (ML1+16) -#define BUNNY (ML1+17) -#define TROUT (ML1+18) -#define BASS (ML1+19) -#define PARROT (ML1+20) -#define HYENA (ML1+21) -#define APPR_NINJA (ML2+0) -#define NIGHT_GAUNT (ML2+1) -#define SNEAK_THIEF (ML2+2) -#define EYE (ML2+3) -#define TOVE (ML2+4) -#define NASTY (ML2+5) -#define GHOST (ML2+6) -#define ENCHANTOR (ML2+7) /* use 'OR' to avoid conflict with circle rank */ -#define MURK (ML2+8) -#define GOBLIN_CHIEF (ML2+9) -#define WOLF (ML2+10) -#define ANT (ML2+11) -#define ELEPHANT (ML2+12) -#define HORSE (ML2+13) -#define SALAMANDER (ML3+0) -#define CATOBLEPAS (ML3+1) -#define L_FDEMON (ML3+2) -#define ACID_CLOUD (ML3+3) -#define PHANTOM (ML3+4) -#define GOBLIN_KING (ML3+5) -#define PTERODACTYL (ML3+6) -#define GOBLIN_SHAMAN (ML3+7) -#define LION (ML3+8) -#define BRIGAND (ML3+9) -#define BEAR (ML3+10) -#define MAMBA (ML3+11) -#define MANOWAR (ML3+12) -#define WEREHUMAN (ML3+13) -#define THOUGHTFORM (ML3+14) -#define MANTICORE (ML4+0) -#define TASMANIAN (ML4+1) -#define AUTO_MINOR (ML4+2) -#define DENEBIAN (ML4+3) -#define JUBJUB (ML4+4) -#define HAUNT (ML4+5) -#define INCUBUS (ML4+6) -#define SATYR (ML4+7) -#define CROC (ML4+8) -#define TORPOR (ML4+9) -#define DOBERMAN (ML4+10) -#define FUZZY (ML4+11) -#define SERV_LAW (ML4+12) -#define SERV_CHAOS (ML4+13) -#define SWARM (ML4+14) -#define BAN_SIDHE (ML4+15) -#define GRUE (ML4+16) -#define GENIN (ML4+17) -#define DRAGONETTE (ML5+0) -#define TESLA (ML5+1) -#define WYVERN (ML5+2) -#define CATEAGLE (ML5+3) -#define FROST_DEMON (ML5+4) -#define SPECTRE (ML5+5) -#define NECROMANCER (ML5+6) -#define SHADOW (ML5+7) -#define BOGTHING (ML5+8) -#define ASTRAL_VAMP (ML5+9) -#define LAVA_WORM (ML5+10) -#define MANABURST (ML5+11) -#define OUTER_DEMON (ML5+12) -#define MIRRORSHADE (ML5+13) -#define FIRE_ELEM (ML6+0) -#define AIR_ELEM (ML6+1) -#define WATER_ELEM (ML6+2) -#define EARTH_ELEM (ML6+3) -#define BANDERSNATCH (ML6+4) -#define LICHE (ML6+5) -#define TRITON (ML6+6) -#define MAST_THIEF (ML6+7) -#define TRICER (ML6+8) -#define RAKSHASA (ML6+9) -#define DEMON_SERP (ML6+10) -#define ANGEL (ML6+11) -#define CHUNIN (ML6+12) -#define BEHEMOTH (ML7+0) -#define NAZGUL (ML7+1) -#define UNICORN (ML7+2) -#define ROUS (ML7+3) -#define ILL_FIEND (ML7+4) -#define GREAT_WYRM (ML7+5) -#define FLAME_DEV (ML7+6) -#define LURKER (ML7+7) -#define SANDMAN (ML7+8) -#define MIRRORMAST (ML7+9) -#define ELDER_GRUE (ML7+10) -#define LOATHLY (ML7+11) -#define ZOMBIE (ML7+12) -#define RICOCHET (ML7+13) -#define INNER_DEMON (ML7+14) -#define GOOD_FAIRY (ML8+0) -#define BAD_FAIRY (ML8+1) -#define AUTO_MAJOR (ML8+2) -#define DRAGON (ML8+3) -#define JABBERWOCK (ML8+4) -#define FDEMON_L (ML8+5) -#define TIGERSHARK (ML8+6) -#define JONIN (ML8+7) -#define SHADOW_SLAY (ML8+8) -#define MIL_PRIEST (ML8+9) -#define COMA (ML8+10) -#define HIGH_ANGEL (ML8+11) -#define JOTUN (ML9+0) -#define INVIS_SLAY (ML9+1) -#define KING_WYV (ML9+2) -#define DEATHSTAR (ML9+3) -#define THAUMATURGIST (ML9+4) -#define VAMP_LORD (ML9+5) -#define ARCHANGEL (ML9+6) -#define DEMON_PRINCE (ML9+7) -#define DEATH (ML10+0) -#define EATER (ML10+1) -#define LAWBRINGER (ML10+2) -#define DRAGON_LORD (ML10+3) -#define DEMON_EMP (ML10+4) -#define LORD_EARTH (ML10+5) -#define LORD_AIR (ML10+6) -#define LORD_WATER (ML10+7) -#define LORD_FIRE (ML10+8) -#define ELEM_MASTER (ML10+9) -#define MAHARAJA (ML10+10) - - -/* location functions */ -#define L_NO_OP 0 - -/* random sites, used many places */ -#define L_LIFT 1 -#define L_FIRE 2 -#define L_ALTAR 3 -#define L_TRIFID 4 -#define L_RAISE_PORTCULLIS 5 -/* spare entry: 6 */ - -/* city level shop and guild functions */ -/* following are those in CitySiteList */ -#define NUMCITYSITES 30 -#define CITYSITEBASE 7 -#define L_CHARITY 7 -#define L_ARMORER 8 -#define L_CLUB 9 -#define L_GYM 10 -#define L_THIEVES_GUILD 11 -#define L_COLLEGE 12 -#define L_HEALER 13 -#define L_CASINO 14 -#define L_TAVERN 15 -#define L_MERC_GUILD 16 -#define L_ALCHEMIST 17 -#define L_SORCERORS 18 -#define L_CASTLE 19 -#define L_ARENA 20 -#define L_DPW 21 -#define L_LIBRARY 22 -#define L_PAWN_SHOP 23 -#define L_BANK 24 -#define L_CONDO 25 -#define L_ORACLE 26 -#define L_ORDER 27 -#define L_DINER 28 -#define L_COMMANDANT 29 -#define L_CRAP 30 -#define L_TEMPLE 31 -#define L_COUNTRYSIDE 32 -#define L_BROTHEL 33 -#define L_SEWER 34 -#define L_TOURIST 35 -#define L_MONASTERY 36 /* first available PGM */ -/* end of city sites */ - -/* gap for a few more city sites, could be either list: 37, 38, 39, 40 */ - -/* other city sites, not in move list */ -#define L_GARDEN 41 -#define L_JAIL 42 -#define L_MAZE 43 /* city */ -#define L_CEMETARY 44 /* city */ -#define L_VAULT 45 /* city */ -#define L_MANSION 46 /* city */ - -/* sites in villages */ -#define L_CARTOGRAPHER 47 /* villages */ -#define L_STABLES 48 /* villages */ -#define L_COMMONS 49 /* villages */ -#define L_GRANARY 50 /* villages */ -#define L_LAWSTONE 51 -#define L_CHAOSTONE 52 /* shouldn't this be CHAOSSTONE ?? :) DAG */ -#define L_SACRIFICESTONE 53 -#define L_VOIDSTONE 54 -#define L_BALANCESTONE 55 -#define L_MINDSTONE 56 - -/* gap for a few more village or combined city/village sites: 57, 58, 59, 60 */ -/* sites in city & villages */ -#define L_HOVEL 61 -#define L_HOUSE 62 - -/* sites in the countryside */ -#define L_TEMPLE_WARNING 63 /* country */ -#define L_ADEPT 64 /* country */ -#define L_TACTICAL_EXIT 65 /* country, sort of */ - -/* allow a couple more country sites: 66, 67, 68 */ - -/* final abyss sites; ignore levitation */ -#define L_EARTH_STATION 69 -#define L_FIRE_STATION 70 -#define L_WATER_STATION 71 -#define L_AIR_STATION 72 -#define L_VOID_STATION 73 -#define L_VOID 74 -#define L_VOICE1 75 -#define L_VOICE2 76 -#define L_VOICE3 77 - -/* circle hq sites */ -#define L_TOME1 78 -#define L_TOME2 79 -#define L_ENTER_CIRCLE 80 -#define L_CIRCLE_LIBRARY 81 - -/* other site functions, particular dungeons or special levels */ - -#define L_ARENA_EXIT 82 /* arena */ -#define L_ENTER_COURT 83 /* castle */ -#define L_THRONE 84 /* court of the archmage */ -#define L_ESCALATOR 85 /* court of the archmage */ -#define L_WHIRLWIND 86 /* astral */ -#define L_HOUSE_EXIT 87 /* house */ -#define L_SAFE 88 /* house */ - -/* unused site functions, these were defined, so I left them defined -- DAG */ - -#define L_OMEGA 89 /* not currently used */ -#define L_DRUID 90 /* not currently used */ -#define L_WARNING 91 /* not currently used */ -#define L_OCCUPIED_HOUSE 92 /* not currently used */ -#define L_FINAL_ABYSS 93 /* not currently used */ - -/* hold for 94, 95, 96, 97, 98, 99 still in the affect player while - levitating range */ - -/* greater than LEVITATION_AVOIDANCE, no effect if player is levitating */ -#define LEVITATION_AVOIDANCE 100 - -/* traps */ -#define NUMTRAPS 13 -#define TRAP_BASE 101 - -#define L_TRAP_DART 101 -#define L_TRAP_PIT 102 -#define L_TRAP_DOOR 103 -#define L_TRAP_SNARE 104 -#define L_TRAP_BLADE 105 -#define L_TRAP_FIRE 106 -#define L_TRAP_TELEPORT 107 -#define L_TRAP_DISINTEGRATE 108 -#define L_TRAP_SLEEP_GAS 109 -#define L_TRAP_ACID 110 -#define L_TRAP_MANADRAIN 111 -#define L_TRAP_ABYSS 112 -#define L_TRAP_SIREN 113 - -#define NUM_SAFE_TRAPS 7 -/* the first NUM_SAFE_TRAPS are non-insta-lethal */ - -/* leave head room for extra traps: 114, 115, 116, 117, 118, 119, 120 */ - -/* random sites */ -#define L_CHAOS 121 -#define L_WATER 122 -#define L_LAVA 123 -#define L_ABYSS 124 -#define L_MAGIC_POOL 125 -#define L_PORTCULLIS_TRAP 126 -#define L_PORTCULLIS 127 -#define L_STATUE_WAKE 128 -#define L_HEDGE 129 -#define L_RUBBLE 130 - -#define L_DROP_EVERY_PORTCULLIS 131 /* tested, but never set */ - -/* unused site functions, these were defined, so I left them defined -- DAG */ -#define L_STATUE_RANDOM 132 /* not currently used */ - -/* player possession slots */ -/* slot 0 should not be filled when out of inventory_control() */ - -#define O_UP_IN_AIR 0 -#define O_READY_HAND 1 -#define O_WEAPON_HAND 2 -#define O_LEFT_SHOULDER 3 -#define O_RIGHT_SHOULDER 4 -#define O_BELT1 5 -#define O_BELT2 6 -#define O_BELT3 7 -#define O_SHIELD 8 -#define O_ARMOR 9 -#define O_BOOTS 10 -#define O_CLOAK 11 -#define O_RING1 12 -#define O_RING2 13 -#define O_RING3 14 -#define O_RING4 15 - - -/* Changing these would currently require changing the maps as well (although - * there should be no other side effects). I intend to remove the need for - * this list later, by making the maps refer to each other (and thus removing - * the need for the game to know about anything but map 0), but that comes - * MUCH later. */ -enum map_identifier { - MAP_country=0, - MAP_arena=1, - MAP_circle=2, - MAP_city=3, - MAP_abyss=4, - MAP_court=5, - MAP_dlair=6, - MAP_hedges=7, - MAP_house=8, - MAP_hovel=9, - MAP_mansion=10, - MAP_misle=11, - MAP_skorch=12, - MAP_speak=13, - MAP_starview=14, - MAP_stormwat=15, - MAP_temple=16, - MAP_thaumari=17, - MAP_whorfen=18, - MAP_woodmere=19, -}; - -/* typedefs needed by structs */ - -/* I don't ever define map_type (except in the C file where it's used); this - * means that you _must_ declare only pointers to it. I've defined, of - * course, all of the needed accessor and mutator functions; see externs.h, - * in the map.c section. */ -struct map_type; -typedef struct map_type map; - -/* structure definitions */ - -struct bank_account -{ - short player; - long balance; - long number; - char *password; - struct bank_account * next_account; -}; -typedef struct bank_account bank_account; - -struct room { - int lighted; - int left,right,top,bottom; - int rsi; /* index into roomname switch */ -}; - -struct spell { - char known; - char id; - char powerdrain; -} ; - -struct player { - int str,con,dex,agi,iq,pow,maxstr,maxcon,maxdex,maxagi,maxiq,maxpow; - long xp; - int level,hp,maxhp,hit,dmg,absorption,speed,click; - int defense,food,alignment; - long mana,maxmana; - long cash; - int patron,birthday; - char preference; - int sx,sy; /* sanctuary coordinates */ - int x,y; /* current player coordinates */ - int itemweight,maxweight; - int immunity[NUMIMMUNITIES]; - int status[NUMSTATI]; - long options; - int rank[NUMRANKS]; - long guildxp[NUMRANKS]; - char name[64]; - char combatManeuvers[64]; - Object *possessions[MAXITEMS]; - Object *pack[MAXPACK]; - int packptr; -}; - -struct objectlist { - Object *thing; - struct objectlist *next; -}; - -/* terrain locations */ -struct terrain { - Symbol base_terrain_type; - Symbol current_terrain_type; - char aux; - char status; -}; - -/* dungeon locations */ -struct location { - unsigned char p_locf; /* function executed when moved on */ - unsigned char lstatus; /* seen,stopsrun,lit,secret, */ - unsigned char roomnumber; /* so room can be named */ - Symbol locchar; /* terrain type */ - Symbol showchar; /*char instantaneously drawn for site */ - int aux; /* signifies various things */ - unsigned char buildaux; /* used in constructing level */ - struct objectlist *things; - Monster *creature; -}; - -struct level { - char depth; /* which level is this */ - struct level *next; /* pointer to next level in dungeon */ - struct location site[MAXWIDTH][MAXLENGTH]; /* dungeon data */ - char generated; /* has the level been made (visited) yet? */ - char numrooms; /* number of rooms on level */ - char tunnelled; /* amount of tunnelling done on this level */ - MonsterList *mlist; /* List of monsters on level */ - int environment; /* where kind of level is this? */ - int last_visited; /* time player was last on this level */ - int level_width; /* width of current level */ - int level_length; /* length of current level */ -}; - -/* random typedef's */ - -typedef struct location loctype; -typedef loctype *plc; - -typedef struct level levtype; -typedef levtype *plv; - -typedef struct objectlist oltype; -typedef oltype *pol; - -/* random function declarations from system libraries */ - -#undef sign -#undef max -#undef min -#undef abs -/* These must be made to work for both longs and ints */ -#define sign(n) (((n) < 0) ? -1 : (((n) > 0) ? 1 : 0)) -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#define abs(n) (((n) < 0) ? (-(n)) : (n)) - -#define RANDFUNCTION genrand -#define SRANDFUNCTION sgenrand - -/* WDT: This should be harmless under ANSI C, and will stop - * some errors under bizarre platforms. */ -#define pow2(n) (1L << (n)) - -/* these bit operations were functions, but are faster as macros... */ - -#define loc_statusp(x,y,stat) ((Level->site[x][y].lstatus&(stat))?1:0) -#define lset(x,y,stat) (Level->site[x][y].lstatus |= (stat)) -#define lreset(x,y,stat) (Level->site[x][y].lstatus &= ~(stat)) - -#define c_statusp(x,y,stat) ((Country[x][y].status&(stat))?1:0) -#define c_set(x,y,stat) (Country[x][y].status |= (stat)) -#define c_reset(x,y,stat) (Country[x][y].status &= ~(stat)) - -#define m_statusp(m,s) (((m)->status&(s))?1:0) -#define m_status_set(m,s) ((m)->status |= (s)) -#define m_status_reset(m,s) ((m)->status &= ~(s)) -#define m_immunityp(m,s) (((m)->immunity&pow2(s))?1:0) - -#define optionp(o) ((Player.options&(o))?1:0) -#define optionset(o) (Player.options |= (o)) -#define optionreset(o) (Player.options &= ~(o)) - +#pragma once +/* omega copyright (c) 1987,1988,1989 by Laurence Raphael Brothers */ +/* This file is the header file for all omega modules */ +/* defs.h */ + +/* omega will NOT function unless the implementor sets the appropriate +definitions in the following section. */ + +#ifndef DEFS_INCLUDED // include guard +#define DEFS_INCLUDED + +/*--------------------------USER DEFINITIONS--------------------------*/ + +#ifdef WIN32 +#include +#include + +#undef MOUSE_MOVED // Will be redefined when curses is included +#define strlen(x) (int)strlen(x) // Squashes numerous warnings +#define sleep(x) Sleep((DWORD) (x * 1000)) +#define usleep(x) sleep(x / 1000000.0) + +extern char* getlogin(char*, int maxLength); +#else +// These includes are not supported or supplanted in Windows +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include // The assert macro (for ANSI/ISO C). Hopefully this will always work! +#include + +#include "curses.h" +#include "colors.h" + +#include "GameState.h" +#include "Object.h" +#include "Monster.h" +#include "Village.h" + +/* Objects */ +#include "Thing.h" + +/* Update the display every turn to center on the player. Rather heavy + * on the bandwidth. */ +#define CENTER_ON_PLAYER // TODO Make this a user-specifiable option + +/* Implementor should define int32 as the type of integer which uses + * 32 bits. */ +typedef int int32; + +/* Define the maximum length of a filename on your system. If you don't */ +/* define, will try to make an educated guess. If you have one, */ +/* /usr/include/limits.h is a good place to look for this value. */ +#define FNAME_MAX_LEN 48 + +/* OMEGALIB is where all the data files reside. + Note the final / is necessary. + msdos note: \ is the C string escape character, so you need \\ in the + path given in OMEGALIB + This might usually be "/usr/games/lib/omegalib/", for unix, + or something like "c:\\games\\omega\\omegalib\\" for msdos */ + +#define OMEGALIB "data/" + +/* TILEFILE is the name of the file you want to use for graphics tiles. You */ +/* aren't really free to use any file you want here. It should be the Omega */ +/* distribution graphics files provided for your computer. Of course a file */ +/* of the same format and size as the "correct" file will also work if you */ +/* want to change things around. This file should be located in OMEGALIB */ + +#define TILEFILE "omegatiles.xpm" + +/*---------------------------SYSTEM DEFINITIONS---------------------------*/ + +/* Don't change anything from here on (unless you know what you're doing) */ +#define VERSION 9100 +#define VERSIONSTRING "Omega version 0.91" + +#ifndef WIN32 +#define UNIX // Assuming *nix +#endif + +#define VACANT 0 +#define ABORT -1 +#define CASHVALUE -2 + +/* moderately arbitrary but probably cannot be easily changed */ +/*#define MAXWIDTH 64*/ +#define MAXWIDTH 128 +#define MAXLENGTH 64 +#define SMALLSCREEN_LENGTH 16 +#define SMALLSCREEN_WIDTH 64 + +#define STANDARD_LENGTH 64 +#define STANDARD_WIDTH 64 + +#define ARENA_WIDTH SMALLSCREEN_WIDTH +#define ARENA_LENGTH SMALLSCREEN_LENGTH + +#define ABYSS_WIDTH STANDARD_WIDTH +#define ABYSS_LENGTH SMALLSCREEN_LENGTH + +#define ASTRAL_WIDTH STANDARD_WIDTH +#define ASTRAL_LENGTH STANDARD_LENGTH + +#define CASTLE_WIDTH STANDARD_WIDTH +#define CASTLE_LENGTH STANDARD_LENGTH + +#define CAVES_WIDTH STANDARD_WIDTH +#define CAVES_LENGTH STANDARD_LENGTH + +#define CIRCLE_WIDTH SMALLSCREEN_WIDTH +#define CIRCLE_LENGTH SMALLSCREEN_LENGTH + +#define COUNTRY_WIDTH STANDARD_WIDTH +#define COUNTRY_LENGTH STANDARD_LENGTH + +#define COURT_WIDTH SMALLSCREEN_WIDTH +#define COURT_LENGTH 24 + +#define DLAIR_WIDTH SMALLSCREEN_WIDTH +#define DLAIR_LENGTH SMALLSCREEN_LENGTH + +#define HOUSE_WIDTH SMALLSCREEN_WIDTH +#define HOUSE_LENGTH SMALLSCREEN_LENGTH + +#define HOVEL_WIDTH SMALLSCREEN_WIDTH +#define HOVEL_LENGTH SMALLSCREEN_LENGTH + +#define MANSION_WIDTH SMALLSCREEN_WIDTH +#define MANSION_LENGTH SMALLSCREEN_LENGTH + +#define MISLE_WIDTH SMALLSCREEN_WIDTH +#define MISLE_LENGTH SMALLSCREEN_LENGTH + +#define PALACE_WIDTH STANDARD_WIDTH +#define PALACE_LENGTH STANDARD_LENGTH + +#define RAMPART_WIDTH 128 +#define RAMPART_LENGTH STANDARD_LENGTH + +#define SEWERS_WIDTH STANDARD_WIDTH +#define SEWERS_LENGTH STANDARD_LENGTH + +#define SPEAK_WIDTH SMALLSCREEN_WIDTH +#define SPEAK_LENGTH SMALLSCREEN_LENGTH + +#define TACTICAL_WIDTH SMALLSCREEN_WIDTH +#define TACTICAL_LENGTH SMALLSCREEN_LENGTH + +#define TEMPLE_WIDTH SMALLSCREEN_WIDTH +#define TEMPLE_LENGTH SMALLSCREEN_LENGTH + +#define VILLAGE_WIDTH SMALLSCREEN_WIDTH +#define VILLAGE_LENGTH SMALLSCREEN_LENGTH + +#define VOLCANO_WIDTH STANDARD_WIDTH +#define VOLCANO_LENGTH STANDARD_LENGTH + +/* number of slots in inventory. Cannot be changed without work */ +#define MAXITEMS 16 + +/* number of slots in pack. Should be <= 26. */ +#define MAXPACK 26 + +/* number of items in pawn shop. Should be <= 26 */ +#define PAWNITEMS 20 /* DG -- the more the merrier. WDT -- I agree. */ + +/* number of lines back strings are recalled */ +#define STRING_BUFFER_SIZE 25 + +/* number of rerolls allowed +1 */ /* added by dagibbs (DG) */ +#define REROLLS -1 + +/* Verbosity levels */ +#define TERSE 0 +#define MEDIUM 1 +#define VERBOSE 2 + +/* Arbitrary. Max of the levels in the dungeons */ +#define MAXLEVELS 21 + +/* levels in each dungeon */ +#define ASTRALLEVELS 5 +#define SEWERLEVELS 18 +#define CASTLELEVELS 16 +#define CAVELEVELS 10 +#define VOLCANOLEVELS 20 +#define PALACELEVELS 14 + +/* non-existant environments for the random number seeding routine */ +/* added 12/30/98 (DG) */ +#define E_RESTORE -2 +#define E_RANDOM -1 +/* general environment types */ +#define E_NEVER_NEVER_LAND 0 +#define E_COUNTRYSIDE 1 +#define E_CITY 2 +#define E_VILLAGE 3 +#define E_TACTICAL_MAP 4 +#define E_SEWERS 5 +#define E_CASTLE 6 +#define E_CAVES 7 +#define E_VOLCANO 8 +#define E_ASTRAL 9 +#define E_ARENA 10 +#define E_HOVEL 11 +#define E_MANSION 12 +#define E_HOUSE 13 +#define E_DLAIR 14 +#define E_ABYSS 15 +#define E_STARPEAK 16 +#define E_MAGIC_ISLE 17 +#define E_TEMPLE 18 +#define E_CIRCLE 19 +#define E_COURT 20 +#define E_PALACE 21 +#define E_MAX E_PALACE + +/* player game status */ +#define DEAD 1 +#define QUIT 2 +#define WIN 3 +#define BIGWIN 4 + +/* kind of arbitrary */ +#define MAXROOMS 48 +#define MAXCONNECTIONS 4 +#define STRING_LEN 100 + +/* some random characters */ +#define ESCAPE 27 +#define RETURN '\n' /* Aren't these backwards? WSS */ +#define LINEFEED '\r' /* Aren't these backwards? WSS */ +#define BACKSPACE '\b' +#define DELETE_CHAR 127 + +/* tac mode action definitions */ +/* have to remember to find where these are used, mostly unused, now! */ +#define DISENGAGE 10 +#define BLOCK 20 +#define CUT 30 +#define THRUST 40 +#define MAGIC 50 +#define LUNGE 60 +#define RIPOSTE 70 +#define WIELD 80 +#define PICK_UP 90 + +/* as in attack low, block high, etc. */ +/* These values may be added to the ones above to get things like + block high, cut low, etc. CLEVER is only used by some monsters + to cheat with.... */ +#define LOW 1 +#define CENTER 2 +#define HIGH 3 +#define CLEVER 4 + +/* weapon types */ +#define CUTTING 1 +#define THRUSTING 2 +#define STRIKING 3 +#define MISSILE 4 + +/* random aux constants */ +/* aux field for private residences in city */ +#define BURGLED 2 +#define LOCKED 3 +#define UNLOCKED 0 + +/* cannot use M command on site with this aux value */ +#define NOCITYMOVE 666 + +/* bow and crossbow object aux fields */ +#define LOADED 1 +#define UNLOADED 0 + +/* alignment used randomly throughout*/ +#define LAWFUL 1 +#define CHAOTIC 2 +#define NEUTRAL 3 + +/* spells */ +#define NUMSPELLS 42 + +#define S_MON_DET 0 +#define S_OBJ_DET 1 +#define S_MISSILE 2 +#define S_FIREBOLT 3 +#define S_TELEPORT 4 +#define S_LBALL 5 +#define S_SLEEP 6 +#define S_DISRUPT 7 +#define S_DISINTEGRATE 8 +#define S_POLYMORPH 9 +#define S_HEAL 10 +#define S_DISPEL 11 +#define S_IDENTIFY 12 +#define S_BREATHE 13 +#define S_INVISIBLE 14 +#define S_WARP 15 +#define S_ENCHANT 16 +#define S_BLESS 17 +#define S_RESTORE 18 +#define S_CURE 19 +#define S_TRUESIGHT 20 +#define S_HELLFIRE 21 +#define S_KNOWLEDGE 22 +#define S_HERO 23 +#define S_RETURN 24 +#define S_DESECRATE 25 +#define S_HASTE 26 +#define S_SUMMON 27 +#define S_SANCTUARY 28 +#define S_ACCURACY 29 +#define S_RITUAL 30 +#define S_FEAR 31 +#define S_APPORT 32 +#define S_SHADOWFORM 33 +#define S_ALERT 34 +#define S_REGENERATE 35 +#define S_SANCTIFY 36 +#define S_CLAIRVOYANCE 37 +#define S_DRAIN 38 +#define S_LEVITATE 39 +#define S_WISH 40 +#define S_NUTRITION 41 + +/* ranks in guilds, etc */ +#define NUMRANKS 10 + +#define LEGION 0 +#define ARENA 1 +#define COLLEGE 2 +#define THIEVES 3 +#define ORDER 4 +#define CIRCLE 5 +#define NOBILITY 6 +#define PRIESTHOOD 7 +#define MONKS 8 +#define ADEPT 9 + +#define LEGIONAIRE 1 +#define CENTURION 2 +#define FORCE_LEADER 3 +#define COLONEL 4 +#define COMMANDANT 5 + +#define TRAINEE 1 +#define BESTIARIUS 2 +#define RETIARIUS 3 +#define GLADIATOR 4 +#define CHAMPION 5 + +#define NOVICE 1 +#define STUDENT 2 +#define PRECEPTOR 3 +#define MAGE 4 +#define ARCHMAGE 5 + +#define TMEMBER 1 +#define ATHIEF 2 +#define THIEF 3 +#define TMASTER 4 +#define SHADOWLORD 5 + +#define GALLANT 1 +#define GUARDIAN 2 +#define CHEVALIER 3 +#define PALADIN 4 +#define JUSTICIAR 5 + +#define INITIATE 1 +#define ENCHANTER 2 +#define SORCEROR 3 +#define HIGHSORCEROR 4 +#define PRIME 5 + +#define COMMONER 1 +#define ESQUIRE 2 +#define KNIGHT 3 +#define LORD 4 +#define DUKE 5 + +#define LAY 1 +#define ACOLYTE 2 +#define PRIEST 3 +#define SPRIEST 4 +#define HIGHPRIEST 5 + +#define MONK_TRAINEE 1 +#define MONK_MONK 2 +#define MONK_MASTER 3 +#define MONK_MASTER_SIGHS 4 +#define MONK_MASTER_PAINS 5 +#define MONK_MASTER_TEARS 6 +#define MONK_GRANDMASTER 7 + +/* different priesthoods */ +#define ODIN 1 +#define SET 2 +#define ATHENA 3 +#define HECATE 4 +#define DRUID 5 +#define DESTINY 6 + + + +/* MONSTER STATUS/ABILITY BITS */ +/* currently a long */ +#define AWAKE 1 +#define MOBILE 2 +#define HOSTILE 4 +/* missing bit 3, 8 */ +#define WANDERING 16 +#define HUNGRY 32 +#define GREEDY 64 +#define NEEDY 128 +#define ONLYSWIM 256 +#define FLYING 512 +#define INTANGIBLE 1024 +#define M_INVISIBLE 2048 +#define SWIMMING 4096 +#define POISONOUS 8192 +#define EDIBLE 16384 +#define ALLOC 32768 /* allocated name & corpseString */ + + +/* PLAYER STATUS INDICES */ +#define NUMSTATI 25 + +#define ACCURACY 0 +#define BLINDED 1 +#define SLOWED 2 +#define DISPLACED 3 +#define SLEPT 4 +#define DISEASED 5 +#define POISONED 6 +#define HASTED 7 +#define BREATHING 8 +#define INVISIBLE 9 +#define REGENERATING 10 +#define VULNERABLE 11 +#define BERSERK 12 +#define IMMOBILE 13 +#define ALERT 14 +#define AFRAID 15 +#define HERO 16 +#define LEVITATING 17 +#define ACCURATE 18 +#define TRUESIGHT 19 +#define SHADOWFORM 20 +#define ILLUMINATION 21 +#define DEFLECTION 22 +#define PROTECTION 23 +/* PROTECTION is deviant -- indicates protective value, not duration */ +#define RETURNING 24 +/* RETURNING is somewhat deviant--how many turns 'til RETURN spell goes off */ + +/* player immunity indices */ +/* also monster immunity bits (2^n) */ +/* also damage types */ +#define NUMIMMUNITIES 14 + +#define UNSTOPPABLE 0 +#define NORMAL_DAMAGE 1 +#define FLAME 2 +#define COLD 3 +#define ELECTRICITY 4 +#define POISON 5 +#define ACID 6 +#define FEAR 7 +#define SLEEP 8 +#define NEGENERGY 9 +#define OTHER_MAGIC 10 +#define THEFT 11 +#define GAZE 12 +#define INFECTION 13 +#define EVERYTHING -1 + + +/* location lstatus bits */ +#define SEEN 1 +#define LIT 2 +#define SECRET 4 +#define STOPS 8 +#define CHANGED 16 + + +/* room string id */ +/* for use in roomname() */ +/* number of rooms above ROOMBASE */ +#define NUMROOMNAMES 30 + +#define RS_WALLSPACE 1 +#define RS_CORRIDOR 2 +#define RS_CAVERN 3 +#define RS_GOBLINKING 4 +#define RS_DRAGONLORD 5 +#define RS_PONDS 6 +#define RS_OCEAN 7 +#define RS_WYRM 8 +#define RS_ADEPT 9 +#define RS_DESTINY 10 +#define RS_ODIN 11 +#define RS_SET 12 +#define RS_ATHENA 13 +#define RS_HECATE 14 +#define RS_DRUID 15 +#define RS_COUNTRYSIDE 16 +#define RS_ARENA 17 +#define RS_SEWER_DUCT 18 +#define RS_DRAINED_SEWER 19 +#define RS_DROWNED_SEWER 20 +#define RS_KITCHEN 21 +#define RS_BEDROOM 22 +#define RS_BATHROOM 23 +#define RS_DININGROOM 24 +#define RS_SECRETPASSAGE 25 +#define RS_CLOSET 26 +#define RS_LOWERASTRAL 27 +#define RS_EARTHPLANE 28 +#define RS_WATERPLANE 29 +#define RS_AIRPLANE 30 +#define RS_FIREPLANE 31 +#define RS_HIGHASTRAL 32 +#define RS_VOLCANO 33 +#define RS_STARPEAK 34 +#define RS_MAGIC_ISLE 35 +#define RS_CIRCLE 36 +#define RS_ZORCH 37 +#define RS_COURT 38 +/* normal room name indices start after the RS_ constants */ +#define ROOMBASE 39 +#define RS_GARDEROBE ROOMBASE+0 +#define RS_CELL ROOMBASE+1 +#define RS_TILED ROOMBASE+2 +#define RS_CRYSTAL_CAVE ROOMBASE+3 +#define RS_BEDROOM2 ROOMBASE+4 +#define RS_STOREROOM ROOMBASE+5 +#define RS_CHARRED ROOMBASE+6 +#define RS_MARBLE_HALL ROOMBASE+7 +#define RS_EERIE_CAVE ROOMBASE+8 +#define RS_TREASURE ROOMBASE+9 +#define RS_SMOKEY ROOMBASE+10 +#define RS_APARTMENT ROOMBASE+11 +#define RS_ANTECHAMBER ROOMBASE+12 +#define RS_HAREM ROOMBASE+13 +#define RS_MULTIPURPOSE ROOMBASE+14 +#define RS_STALACTITES ROOMBASE+15 +#define RS_GREENHOUSE ROOMBASE+16 +#define RS_WATERCLOSET ROOMBASE+17 +#define RS_STUDY ROOMBASE+18 +#define RS_LIVING_ROOM ROOMBASE+19 +#define RS_DEN ROOMBASE+20 +#define RS_ABATOIR ROOMBASE+21 +#define RS_BOUDOIR ROOMBASE+22 +#define RS_STAR_CHAMBER ROOMBASE+23 +#define RS_MANMADE_CAVE ROOMBASE+24 +#define RS_SEWER_CONTROL ROOMBASE+25 +#define RS_SHRINE ROOMBASE+26 +#define RS_MAGIC_LAB ROOMBASE+27 +#define RS_PENTAGRAM ROOMBASE+28 +#define RS_OMEGA_DAIS ROOMBASE+29 + +// Color macros +#ifdef OMEGA_CLRGEN // Only defined when using the color-gen utility +# define CLR(fg) OMEGA_CLRGEN1 fg +# define CLRS(fg, bg) OMEGA_CLRGEN2 fg bg +#else +# define CLR(fg) CLR_##fg##_BLACK +# define CLRS(fg, bg) CLR_##fg##_##bg +#endif + +/* objects, locations, and terrain; characters to draw */ +#define NULL_ITEM '\0' +#define SPACE (' ' | CLR(WHITE)) +#define WALL ('#' | CLR(GREY)) +#define PORTCULLIS ('7' | CLR(WHITE)) +#define OPEN_DOOR ('|' | CLR(BROWN)) +#define CLOSED_DOOR ('-' | CLR(BROWN)) +#define WHIRLWIND ('6' | CLR(LIGHT_BLUE)) +#define ABYSS ('0' | CLRS(BLACK,BROWN)) +#define VOID_CHAR (' ' | CLR(WHITE)) +#define LAVA ('`' | CLR(RED)) +#define HEDGE ('\"' | CLR(GREEN)) +#define WATER ('~' | CLR(BLUE)) +#define FIRE (';' | CLR(LIGHT_RED)) +#define TRAP ('^' | CLR(RED)) +#define LIFT ('_' | CLR(BRIGHT_WHITE)) +#define STAIRS_UP ('<' | CLR(WHITE)) +#define STAIRS_DOWN ('>' | CLR(WHITE)) +#define FLOOR ('.' | CLR(BROWN)) +#define PLAYER ('@' | CLR(WHITE)) +#define CORPSE ('+' | CLR(RED)) +#define STATUE ('1' | CLR(GREY)) +#define RUBBLE ('4' | CLR(GREY)) +#define ALTAR ('8' | CLR(LIGHT_BLUE)) +#define CASH ('$' | CLR(YELLOW)) /* various kinds of money */ +#define PILE ('*' | CLR(BRIGHT_WHITE)) /* several objects in one place */ +#define FOOD ('%' | CLR(BROWN)) +#define WEAPON (')' | CLR(GREY)) +#define MISSILEWEAPON ('(' | CLR(BROWN)) +#define SCROLL ('?' | CLR(YELLOW)) +#define POTION ('!' | CLR(LIGHT_GREEN)) +#define ARMOR (']' | CLR(GREY)) +#define SHIELD ('[' | CLR(BROWN)) +#define CLOAK ('}' | CLR(CYAN)) +#define BOOTS ('{' | CLR(BROWN)) +#define STICK ('/' | CLR(BROWN)) + +#define RING ('=' | CLR(YELLOW)) +#define THING ('\\' | CLR(WHITE)) +#define ARTIFACT ('&' | CLR(YELLOW)) + +/* TERRAIN TYPES */ +#define PLAINS ('-' | CLR(LIGHT_GREEN)) +#define TUNDRA ('_' | CLR(GREY)) +#define ROAD ('.' | CLR(BROWN)) +#define MOUNTAINS ('^' | CLR(GREY)) +#define PASS ('v' | CLR(BROWN)) +#define RIVER ('~' | CLR(BLUE)) +#define CITY ('O' | CLR(WHITE)) +#define VILLAGE ('o' | CLR(WHITE)) +#define FOREST ('(' | CLR(LIGHT_GREEN)) +#define JUNGLE (')' | CLR(GREEN)) +#define SWAMP ('=' | CLR(GREEN)) +#define VOLCANO ('!' | CLR(RED)) +#define CASTLE ('%' | CLR(GREY)) +#define TEMPLE ('X' | CLR(BROWN)) +#define CAVES ('*' | CLRS(BLACK,BROWN)) +#define DESERT ('\"' | CLR(YELLOW)) +#define CHAOS_SEA ('+' | CLR(LIGHT_PURPLE)) +#define STARPEAK ('|' | CLR(LIGHT_BLUE)) +#define DRAGONLAIR ('$' | CLR(BROWN)) +#define MAGIC_ISLE ('&' | CLR(PURPLE)) +#define PALACE ('K' | CLR(PURPLE)) + +#define CHAIR ('5' | CLR(BROWN)) +#define SAFE ('3' | CLR(GREY)) +#define FURNITURE ('2' | CLR(BROWN)) +#define BED ('9' | CLR(CYAN)) + +/* wow, all characters used! */ + +/* total number of editable stats */ +#define NUMSTATS 11 + +/* total number of player options */ +#define NUMOPTIONS 10 + +/* number of options with true/false values */ +#define NUMTFOPTIONS 9 + +/* The slot number of the two options not in Player.options */ +#define VERBOSITY_LEVEL 9 +#define SEARCH_DURATION 10 + +/* Player.options bits */ +#define BELLICOSE 1 +#define JUMPMOVE 2 +#define RUNSTOP 4 +#define PICKUP 8 +#define CONFIRM 16 +#define TOPINV 32 +#define PACKADD 64 +#define SHOW_COLOUR 256 + +/* This has to be changed whenever an item is added */ +#define NUMSCROLLS 24 +#define NUMPOTIONS 18 +#define NUMFOODS 16 +#define NUMTHINGS 31 /* DAG for mirror of self-knowledge */ /* WSS cards */ +#define NUMCARDS 4 +#define NUMWEAPONS 41 +#define NUMARMOR 17 +#define NUMSHIELDS 8 +#define NUMCLOAKS 7 +#define NUMBOOTS 7 +#define NUMRINGS 9 /* DAG loss of ring of self-knowledge */ +#define NUMSTICKS 17 +#define NUMARTIFACTS 26 + +/* running sum of itemtypes, for indexing into Objects array */ +#define THINGID 0 +#define CARDID (THINGID+NUMTHINGS-NUMCARDS) +#define FOODID NUMTHINGS /* 26 */ +#define SCROLLID (FOODID + NUMFOODS) /* 42 */ +#define POTIONID (SCROLLID + NUMSCROLLS) /* 66 */ +#define WEAPONID (POTIONID + NUMPOTIONS) /* 84 */ +#define ARMORID (WEAPONID + NUMWEAPONS) /* 125 */ +#define SHIELDID (ARMORID + NUMARMOR) /* 142 */ +#define CLOAKID (SHIELDID + NUMSHIELDS) /* 150 */ +#define BOOTID (CLOAKID + NUMCLOAKS) /* 157 */ +#define RINGID (BOOTID + NUMBOOTS) /* 164 */ +#define STICKID (RINGID + NUMRINGS) /* 174 */ +#define ARTIFACTID (STICKID + NUMSTICKS) /* 191 */ +#define CASHID (ARTIFACTID+NUMARTIFACTS) /* 216 */ +/* Corpse's aux field is monster id */ +#define CORPSEID (CASHID+1) + +#define TOTALITEMS (CORPSEID+1) + +/* descriptive constants for various object ids */ +#define OB_GARAGE_OPENER (THINGID+0) +#define OB_LOCK_PICK (THINGID+2) +#define OB_SALT_WATER (THINGID+6) +#define OB_KEY (THINGID+7) +#define OB_TORCH (THINGID+8) +#define OB_JUSTICIAR_BADGE (THINGID+16) +#define OB_TRAP_DART (THINGID+17) +#define OB_TRAP_ACID (THINGID+18) +#define OB_TRAP_SNARE (THINGID+19) +#define OB_TRAP_FIRE (THINGID+20) +#define OB_TRAP_TELEPORT (THINGID+21) +#define OB_TRAP_SLEEP (THINGID+22) +#define OB_TRAP_DISINTEGRATE (THINGID+23) +#define OB_TRAP_ABYSS (THINGID+24) +#define OB_TRAP_MANADRAIN (THINGID+25) +#define OB_DEBIT_CARD (CARDID+0) +#define OB_CREDIT_CARD (CARDID+1) +#define OB_PREPAID_CARD (CARDID+2) +#define OB_SMART_CARD (CARDID+3) +#define OB_RATION (FOODID+0) +#define OB_LEMBAS (FOODID+1) +#define OB_GRAIN (FOODID+15) +#define OB_BLANK_SCROLL (SCROLLID+0) +#define OB_SPELLS_SCROLL (SCROLLID+1) +#define OB_SCROLL_LAW (SCROLLID+17) +#define OB_POTION_CHAOS (POTIONID+14) +#define OB_SHORT_SWORD (WEAPONID+1) +#define OB_GREAT_SWORD (WEAPONID+5) +#define OB_GREAT_AXE (WEAPONID+12) +#define OB_CLUB (WEAPONID+17) +#define OB_QUARTERSTAFF (WEAPONID+18) +#define OB_SPEAR (WEAPONID+19) +#define OB_HALBERD (WEAPONID+20) +#define OB_MACE_DISRUPT (WEAPONID+25) +#define OB_LONGBOW (WEAPONID+26) +#define OB_CROSSBOW (WEAPONID+27) +#define OB_ARROW (WEAPONID+28) +#define OB_BOLT (WEAPONID+29) +#define OB_DESECRATOR (WEAPONID+32) +#define OB_DEFENDER (WEAPONID+34) +#define OB_VICTRIX (WEAPONID+35) +#define OB_HEWER (WEAPONID+36) +#define OB_GIANT_CLUB (WEAPONID+38) +#define OB_SCYTHE_DEATH (WEAPONID+39) +#define OB_LEATHER (ARMORID+1) +#define OB_MITHRIL_PLATE (ARMORID+11) +#define OB_DRAGONSCALE (ARMORID+12) +#define OB_LRG_RND_SHIELD (SHIELDID+2) +#define OB_DEFLECT (SHIELDID+7) +#define OB_CLOAK_PROTECT (CLOAKID+4) +#define OB_ORB_MASTERY (ARTIFACTID+0) +#define OB_ORB_FIRE (ARTIFACTID+1) +#define OB_ORB_WATER (ARTIFACTID+2) +#define OB_ORB_EARTH (ARTIFACTID+3) +#define OB_ORB_AIR (ARTIFACTID+4) +#define OB_DEAD_ORB (ARTIFACTID+5) +#define OB_ANTIOCH (ARTIFACTID+7) +#define OB_YENDOR (ARTIFACTID+8) +#define OB_KOLWYNIA (ARTIFACTID+9) +#define OB_POTION_DEATH (ARTIFACTID+10) +#define OB_POTION_LIFE (ARTIFACTID+13) +#define OB_SYMBOL_ODIN (ARTIFACTID+14) +#define OB_SYMBOL_SET (ARTIFACTID+15) +#define OB_SYMBOL_ATHENA (ARTIFACTID+16) +#define OB_SYMBOL_HECATE (ARTIFACTID+17) +#define OB_SYMBOL_DRUID (ARTIFACTID+18) +#define OB_SYMBOL_DESTINY (ARTIFACTID+19) +#define OB_KARNAK (ARTIFACTID+20) +#define OB_STARGEM (ARTIFACTID+21) +#define OB_SCEPTRE (ARTIFACTID+22) +#define OB_HOLDING (ARTIFACTID+24) + +/* describing unique items and monsters */ +#define COMMON 0 +#define UNIQUE_UNMADE 1 +#define UNIQUE_MADE 2 +#define UNIQUE_TAKEN 3 + +/* general item function id's */ +#define I_NO_OP 0 +#define I_NOTHING 1 + +/* note some of these functions are for other types of items too */ + +/* scroll functions */ +#define I_BLESS 101 +#define I_ACQUIRE 102 +#define I_ENCHANT 103 +#define I_TELEPORT 104 +#define I_WISH 105 +#define I_CLAIRVOYANCE 106 +#define I_DISPLACE 107 +#define I_ID 108 +#define I_FIREFLASH 109 +#define I_SPELLS 110 +#define I_JANE_T 111 +#define I_ALERT 112 +#define I_FLUX 113 +#define I_CHARGE 114 +#define I_WARP 115 +#define I_KNOWLEDGE 116 +#define I_LAW 117 +#define I_HINT 118 +#define I_HERO 119 +#define I_TRUESIGHT 120 +#define I_ILLUMINATE 121 +#define I_DEFLECT 122 + +/* potion functions */ +#define I_HEAL 201 +#define I_OBJDET 202 +#define I_MONDET 203 +#define I_SLEEP_SELF 204 +#define I_RESTORE 205 +#define I_NEUTRALIZE_POISON 206 +#define I_SPEED 207 +#define I_AZOTH 208 +#define I_REGENERATE 210 +#define I_INVISIBLE 211 +#define I_BREATHING 212 +#define I_FEAR_RESIST 213 +#define I_AUGMENT 214 +#define I_CHAOS 215 +#define I_ACCURACY 216 +#define I_LEVITATION 217 +#define I_CURE 218 + +/* stick functions */ +#define I_FIREBOLT 301 +#define I_LBOLT 302 +#define I_MISSILE 303 +#define I_SLEEP_OTHER 304 +#define I_FIREBALL 305 +#define I_LBALL 306 +#define I_SUMMON 307 +#define I_HIDE 308 +#define I_DISRUPT 309 +#define I_DISINTEGRATE 310 +#define I_SNOWBALL 311 +#define I_APPORT 312 +#define I_DISPEL 313 +#define I_POLYMORPH 314 +#define I_FEAR 315 + +/* food functions */ +#define I_FOOD 401 +#define I_LEMBAS 402 +#define I_STIM 403 +#define I_POW 404 +#define I_IMMUNE 405 +#define I_POISON_FOOD 406 +#define I_CORPSE 407 +#define I_PEPPER_FOOD 408 +#define I_CANNIBAL 409 +#define I_INEDIBLE 410 + +/* boots functions */ +#define I_PERM_SPEED 501 +#define I_PERM_HERO 502 +#define I_PERM_LEVITATE 503 +#define I_PERM_AGILITY 504 +#define I_BOOTS_JUMPING 505 +#define I_BOOTS_7LEAGUE 506 + +/* cloak functions */ +#define I_PERM_DISPLACE 601 +#define I_PERM_NEGIMMUNE 602 +#define I_PERM_INVISIBLE 603 +#define I_PERM_ACCURACY 604 +#define I_PERM_PROTECTION 605 +#define I_PERM_TRUESIGHT 606 + +/* ring functions */ +#define I_PERM_VISION 701 +#define I_PERM_BURDEN 702 +#define I_PERM_STRENGTH 703 +#define I_PERM_GAZE_IMMUNE 704 +#define I_PERM_FIRE_RESIST 705 +#define I_PERM_POISON_RESIST 706 +#define I_PERM_REGENERATE 707 +#define I_PERM_KNOWLEDGE 708 + +/* armor functions */ +#define I_PERM_ENERGY_RESIST 801 +#define I_PERM_BREATHING 802 +#define I_PERM_FEAR_RESIST 803 +#define I_NORMAL_ARMOR 804 + +/* artifact functions */ +#define I_ORBFIRE 901 +#define I_ORBWATER 902 +#define I_ORBEARTH 903 +#define I_ORBAIR 904 +#define I_ORBMASTERY 905 +#define I_ORBDEAD 906 +#define I_CRYSTAL 907 +#define I_ANTIOCH 908 +#define I_KOLWYNIA 909 +#define I_DEATH 910 +#define I_ENCHANTMENT 911 +#define I_HELM 912 +#define I_LIFE 913 +#define I_JUGGERNAUT 914 +#define I_SYMBOL 915 +#define I_STARGEM 916 +#define I_SCEPTRE 917 +#define I_PLANES 918 +#define I_HOLDING 919 +#define I_SERENITY 920 + +/* weapons functions */ +#define I_NORMAL_WEAPON 1001 +#define I_LIGHTSABRE 1002 +#define I_DEMONBLADE 1003 +#define I_MACE_DISRUPT 1004 +#define I_TANGLE 1005 +#define I_ARROW 1006 +#define I_BOLT 1007 +#define I_VORPAL 1008 +#define I_DESECRATE 1009 +#define I_FIRESTAR 1010 +#define I_DEFEND 1011 +#define I_VICTRIX 1012 +#define I_EMPIRE 1013 +#define I_SCYTHE 1014 +#define I_ACIDWHIP 1015 + +/* thing functions */ +#define I_PICK 1101 +#define I_KEY 1102 +#define I_SHOVEL 1103 /* unused */ +#define I_EXCAVATOR 1104 /* unused */ +#define I_PERM_ILLUMINATE 1105 +#define I_TRAP 1106 +#define I_RAISE_PORTCULLIS 1107 + +/* shield functions */ +#define I_PERM_DEFLECT 1201 +#define I_NORMAL_SHIELD 1202 + +/* monster function ids */ +/* Its conceivable for a function of one type to be called when another +would usually occur. A monster's special function may be an extra move, +for example. */ + +#define M_NO_OP -1 + +/* talk functions */ +#define M_TALK_STUPID 101 +#define M_TALK_SILENT 102 +#define M_TALK_HUNGRY 103 +#define M_TALK_GREEDY 104 +#define M_TALK_TITTER 105 +#define M_TALK_MAN 106 +#define M_TALK_ROBOT 107 +#define M_TALK_EVIL 108 +#define M_TALK_BURBLE 109 +#define M_TALK_SLITHY 110 +#define M_TALK_MIMSY 111 +#define M_TALK_SEDUCTOR 112 +#define M_TALK_MP 113 +#define M_TALK_IM 114 +#define M_TALK_GUARD 115 +#define M_TALK_GHOST 116 +#define M_TALK_HINT 117 +#define M_TALK_BEG 118 +#define M_TALK_EF 119 +#define M_TALK_GF 120 +#define M_TALK_MORGON 121 +#define M_TALK_LB 122 +#define M_TALK_DEMONLOVER 123 +#define M_TALK_ASSASSIN 124 +#define M_TALK_NINJA 125 +#define M_TALK_THIEF 126 +#define M_TALK_MERCHANT 127 +#define M_TALK_HORSE 128 +#define M_TALK_PARROT 129 +#define M_TALK_ANIMAL 130 +#define M_TALK_HYENA 131 +#define M_TALK_SERVANT 132 +#define M_TALK_SCREAM 133 +#define M_TALK_DRUID 134 +#define M_TALK_ARCHMAGE 135 +#define M_TALK_PRIME 136 +#define M_TALK_MAHARAJA 137 + +/* ability functions */ +#define M_SP_SURPRISE 201 +#define M_SP_MP 202 +#define M_SP_THIEF 203 +#define M_SP_AGGRAVATE 204 +#define M_SP_POISON_CLOUD 205 +#define M_SP_HUGE 206 +#define M_SP_SUMMON 207 +#define M_SP_ILLUSION 208 +#define M_SP_FLUTTER 209 +#define M_SP_ESCAPE 210 +#define M_SP_SPELL 211 +#define M_SP_EXPLODE 212 +#define M_SP_DEMON 213 +#define M_SP_ACID_CLOUD 214 +#define M_SP_WHIRL 215 +#define M_SP_GHOST 216 +#define M_SP_WHISTLEBLOWER 217 +#define M_SP_EATER 218 +#define M_SP_LAWBRINGER 219 +#define M_SP_DRAGONLORD 220 +#define M_SP_DE 221 +#define M_SP_DEMONLOVER 222 +#define M_SP_SEDUCTOR 223 +#define M_SP_MASTER 224 +#define M_SP_WYRM 225 +#define M_SP_BLACKOUT 226 +#define M_SP_BOG 227 +#define M_SP_MERCHANT 228 +#define M_SP_WERE 229 +#define M_SP_SERVANT 231 +#define M_SP_AV 232 +#define M_SP_LW 233 +#define M_SP_SWARM 234 +#define M_SP_ANGEL 235 +#define M_SP_MB 236 +#define M_SP_MIRROR 237 +#define M_SP_RAISE 238 +#define M_SP_DEATH 239 +#define M_SP_COURT 240 +#define M_SP_LAIR 241 +#define M_SP_PRIME 242 + +/* rangestrike functions */ +#define M_STRIKE_MISSILE 301 +#define M_STRIKE_FBOLT 302 +#define M_STRIKE_LBALL 303 +#define M_STRIKE_FBALL 304 +#define M_STRIKE_BLIND 305 +#define M_STRIKE_SNOWBALL 306 +#define M_STRIKE_MASTER 307 +#define M_STRIKE_SONIC 308 + +/* combat functions */ +#define M_MELEE_NORMAL 401 +#define M_MELEE_FIRE 402 +#define M_MELEE_DRAGON 403 +#define M_MELEE_MP 404 +#define M_MELEE_ELEC 405 +#define M_MELEE_POISON 406 +#define M_MELEE_NG 407 +#define M_MELEE_SUCCUBUS 408 +#define M_MELEE_SPIRIT 409 +#define M_MELEE_DISEASE 410 +#define M_MELEE_SLEEP 411 +#define M_MELEE_COLD 412 +#define M_MELEE_MASTER 413 +#define M_MELEE_GRAPPLE 414 +#define M_MELEE_DEATH 415 + +/* movement functions */ +#define M_MOVE_NORMAL 501 +#define M_MOVE_FLUTTER 502 +#define M_MOVE_TELEPORT 503 +#define M_MOVE_FOLLOW 504 +#define M_MOVE_RANDOM 505 +#define M_MOVE_SMART 506 +#define M_MOVE_SPIRIT 507 +#define M_MOVE_SCAREDY 508 +#define M_MOVE_CONFUSED 509 +#define M_MOVE_ANIMAL 510 +#define M_MOVE_LEASH 230 + +/* MLx -> index to Monsters starting for level x */ +/* MLx -> number of monsters of level x or less */ +/* NML_x -> number of monsters of level x */ +/* NML-X must be changed whenever a monster is added */ +/* This whole thing MUST be repaired. Monster levels must + * be represented elsewhere. */ +#define ML0 0 +#define NML_0 9 +#define ML1 (ML0 + NML_0) /* 9 */ +#define NML_1 22 +#define ML2 (ML1 + NML_1) /* 31 */ +#define NML_2 14 +#define ML3 (ML2 + NML_2) /* 45 */ +#define NML_3 15 +#define ML4 (ML3 + NML_3) /* 60 */ +#define NML_4 18 +#define ML5 (ML4 + NML_4) /* 78 */ +#define NML_5 14 +#define ML6 (ML5 + NML_5) /* 92 */ +#define NML_6 13 +#define ML7 (ML6 + NML_6) /* 105 */ +#define NML_7 15 +#define ML8 (ML7 + NML_7) /* 120 */ +#define NML_8 12 +#define ML9 (ML8 + NML_8) /* 132 */ +#define NML_9 8 +#define ML10 (ML9 + NML_9) /* 140 */ +#define NML_10 11 + +#define NUMMONSTERS (ML10 + NML_10) /* 151 */ + +/* Some monster ID's : (Those that are explicitly named in code) */ +/* Actually, there are still many magic constants floating around. */ +/* Eventually I'll get around to making each monster's id a constant.... */ +/* done, thanks to David Gibbs. */ +#define RANDOM -1 +#define HORNET (ML0+0) +#define MEND_PRIEST (ML0+1) +#define ITIN_MERCH (ML0+2) +#define GUARD (ML0+3) +#define NPC (ML0+4) +#define SHEEP (ML0+5) +#define MERCHANT (ML0+6) +#define ZERO_NPC (ML0+7) +#define HISCORE_NPC (ML0+8) +#define GRUNT (ML1+0) +#define TSETSE (ML1+1) +#define FNORD (ML1+2) +#define SEWER_RAT (ML1+3) +#define AGGRAVATOR (ML1+4) +#define BLIPPER (ML1+5) +#define GOBLIN (ML1+6) +#define PHANTASTICON (ML1+7) +#define ROBOT (ML1+8) +#define GEEK (ML1+9) +#define BOROGROVE (ML1+10) +#define QUAIL (ML1+11) +#define BADGER (ML1+12) +#define HAWK (ML1+13) +#define DEER (ML1+14) +#define CAMEL (ML1+15) +#define ANTEATER (ML1+16) +#define BUNNY (ML1+17) +#define TROUT (ML1+18) +#define BASS (ML1+19) +#define PARROT (ML1+20) +#define HYENA (ML1+21) +#define APPR_NINJA (ML2+0) +#define NIGHT_GAUNT (ML2+1) +#define SNEAK_THIEF (ML2+2) +#define EYE (ML2+3) +#define TOVE (ML2+4) +#define NASTY (ML2+5) +#define GHOST (ML2+6) +#define ENCHANTOR (ML2+7) /* use 'OR' to avoid conflict with circle rank */ +#define MURK (ML2+8) +#define GOBLIN_CHIEF (ML2+9) +#define WOLF (ML2+10) +#define ANT (ML2+11) +#define ELEPHANT (ML2+12) +#define HORSE (ML2+13) +#define SALAMANDER (ML3+0) +#define CATOBLEPAS (ML3+1) +#define L_FDEMON (ML3+2) +#define ACID_CLOUD (ML3+3) +#define PHANTOM (ML3+4) +#define GOBLIN_KING (ML3+5) +#define PTERODACTYL (ML3+6) +#define GOBLIN_SHAMAN (ML3+7) +#define LION (ML3+8) +#define BRIGAND (ML3+9) +#define BEAR (ML3+10) +#define MAMBA (ML3+11) +#define MANOWAR (ML3+12) +#define WEREHUMAN (ML3+13) +#define THOUGHTFORM (ML3+14) +#define MANTICORE (ML4+0) +#define TASMANIAN (ML4+1) +#define AUTO_MINOR (ML4+2) +#define DENEBIAN (ML4+3) +#define JUBJUB (ML4+4) +#define HAUNT (ML4+5) +#define INCUBUS (ML4+6) +#define SATYR (ML4+7) +#define CROC (ML4+8) +#define TORPOR (ML4+9) +#define DOBERMAN (ML4+10) +#define FUZZY (ML4+11) +#define SERV_LAW (ML4+12) +#define SERV_CHAOS (ML4+13) +#define SWARM (ML4+14) +#define BAN_SIDHE (ML4+15) +#define GRUE (ML4+16) +#define GENIN (ML4+17) +#define DRAGONETTE (ML5+0) +#define TESLA (ML5+1) +#define WYVERN (ML5+2) +#define CATEAGLE (ML5+3) +#define FROST_DEMON (ML5+4) +#define SPECTRE (ML5+5) +#define NECROMANCER (ML5+6) +#define SHADOW (ML5+7) +#define BOGTHING (ML5+8) +#define ASTRAL_VAMP (ML5+9) +#define LAVA_WORM (ML5+10) +#define MANABURST (ML5+11) +#define OUTER_DEMON (ML5+12) +#define MIRRORSHADE (ML5+13) +#define FIRE_ELEM (ML6+0) +#define AIR_ELEM (ML6+1) +#define WATER_ELEM (ML6+2) +#define EARTH_ELEM (ML6+3) +#define BANDERSNATCH (ML6+4) +#define LICHE (ML6+5) +#define TRITON (ML6+6) +#define MAST_THIEF (ML6+7) +#define TRICER (ML6+8) +#define RAKSHASA (ML6+9) +#define DEMON_SERP (ML6+10) +#define ANGEL (ML6+11) +#define CHUNIN (ML6+12) +#define BEHEMOTH (ML7+0) +#define NAZGUL (ML7+1) +#define UNICORN (ML7+2) +#define ROUS (ML7+3) +#define ILL_FIEND (ML7+4) +#define GREAT_WYRM (ML7+5) +#define FLAME_DEV (ML7+6) +#define LURKER (ML7+7) +#define SANDMAN (ML7+8) +#define MIRRORMAST (ML7+9) +#define ELDER_GRUE (ML7+10) +#define LOATHLY (ML7+11) +#define ZOMBIE (ML7+12) +#define RICOCHET (ML7+13) +#define INNER_DEMON (ML7+14) +#define GOOD_FAIRY (ML8+0) +#define BAD_FAIRY (ML8+1) +#define AUTO_MAJOR (ML8+2) +#define DRAGON (ML8+3) +#define JABBERWOCK (ML8+4) +#define FDEMON_L (ML8+5) +#define TIGERSHARK (ML8+6) +#define JONIN (ML8+7) +#define SHADOW_SLAY (ML8+8) +#define MIL_PRIEST (ML8+9) +#define COMA (ML8+10) +#define HIGH_ANGEL (ML8+11) +#define JOTUN (ML9+0) +#define INVIS_SLAY (ML9+1) +#define KING_WYV (ML9+2) +#define DEATHSTAR (ML9+3) +#define THAUMATURGIST (ML9+4) +#define VAMP_LORD (ML9+5) +#define ARCHANGEL (ML9+6) +#define DEMON_PRINCE (ML9+7) +#define DEATH (ML10+0) +#define EATER (ML10+1) +#define LAWBRINGER (ML10+2) +#define DRAGON_LORD (ML10+3) +#define DEMON_EMP (ML10+4) +#define LORD_EARTH (ML10+5) +#define LORD_AIR (ML10+6) +#define LORD_WATER (ML10+7) +#define LORD_FIRE (ML10+8) +#define ELEM_MASTER (ML10+9) +#define MAHARAJA (ML10+10) + + +/* location functions */ +#define L_NO_OP 0 + +/* random sites, used many places */ +#define L_LIFT 1 +#define L_FIRE 2 +#define L_ALTAR 3 +#define L_TRIFID 4 +#define L_RAISE_PORTCULLIS 5 +/* spare entry: 6 */ + +/* city level shop and guild functions */ +/* following are those in CitySiteList */ +#define NUMCITYSITES 30 +#define CITYSITEBASE 7 +#define L_CHARITY 7 +#define L_ARMORER 8 +#define L_CLUB 9 +#define L_GYM 10 +#define L_THIEVES_GUILD 11 +#define L_COLLEGE 12 +#define L_HEALER 13 +#define L_CASINO 14 +#define L_TAVERN 15 +#define L_MERC_GUILD 16 +#define L_ALCHEMIST 17 +#define L_SORCERORS 18 +#define L_CASTLE 19 +#define L_ARENA 20 +#define L_DPW 21 +#define L_LIBRARY 22 +#define L_PAWN_SHOP 23 +#define L_BANK 24 +#define L_CONDO 25 +#define L_ORACLE 26 +#define L_ORDER 27 +#define L_DINER 28 +#define L_COMMANDANT 29 +#define L_CRAP 30 +#define L_TEMPLE 31 +#define L_COUNTRYSIDE 32 +#define L_BROTHEL 33 +#define L_SEWER 34 +#define L_TOURIST 35 +#define L_MONASTERY 36 /* first available PGM */ +/* end of city sites */ + +/* gap for a few more city sites, could be either list: 37, 38, 39, 40 */ + +/* other city sites, not in move list */ +#define L_GARDEN 41 +#define L_JAIL 42 +#define L_MAZE 43 /* city */ +#define L_CEMETARY 44 /* city */ +#define L_VAULT 45 /* city */ +#define L_MANSION 46 /* city */ + +/* sites in villages */ +#define L_CARTOGRAPHER 47 /* villages */ +#define L_STABLES 48 /* villages */ +#define L_COMMONS 49 /* villages */ +#define L_GRANARY 50 /* villages */ +#define L_LAWSTONE 51 +#define L_CHAOSTONE 52 /* shouldn't this be CHAOSSTONE ?? :) DAG */ +#define L_SACRIFICESTONE 53 +#define L_VOIDSTONE 54 +#define L_BALANCESTONE 55 +#define L_MINDSTONE 56 + +/* gap for a few more village or combined city/village sites: 57, 58, 59, 60 */ +/* sites in city & villages */ +#define L_HOVEL 61 +#define L_HOUSE 62 + +/* sites in the countryside */ +#define L_TEMPLE_WARNING 63 /* country */ +#define L_ADEPT 64 /* country */ +#define L_TACTICAL_EXIT 65 /* country, sort of */ + +/* allow a couple more country sites: 66, 67, 68 */ + +/* final abyss sites; ignore levitation */ +#define L_EARTH_STATION 69 +#define L_FIRE_STATION 70 +#define L_WATER_STATION 71 +#define L_AIR_STATION 72 +#define L_VOID_STATION 73 +#define L_VOID 74 +#define L_VOICE1 75 +#define L_VOICE2 76 +#define L_VOICE3 77 + +/* circle hq sites */ +#define L_TOME1 78 +#define L_TOME2 79 +#define L_ENTER_CIRCLE 80 +#define L_CIRCLE_LIBRARY 81 + +/* other site functions, particular dungeons or special levels */ + +#define L_ARENA_EXIT 82 /* arena */ +#define L_ENTER_COURT 83 /* castle */ +#define L_THRONE 84 /* court of the archmage */ +#define L_ESCALATOR 85 /* court of the archmage */ +#define L_WHIRLWIND 86 /* astral */ +#define L_HOUSE_EXIT 87 /* house */ +#define L_SAFE 88 /* house */ + +/* unused site functions, these were defined, so I left them defined -- DAG */ + +#define L_OMEGA 89 /* not currently used */ +#define L_DRUID 90 /* not currently used */ +#define L_WARNING 91 /* not currently used */ +#define L_OCCUPIED_HOUSE 92 /* not currently used */ +#define L_FINAL_ABYSS 93 /* not currently used */ + +/* hold for 94, 95, 96, 97, 98, 99 still in the affect player while + levitating range */ + +/* greater than LEVITATION_AVOIDANCE, no effect if player is levitating */ +#define LEVITATION_AVOIDANCE 100 + +/* traps */ +#define NUMTRAPS 13 +#define TRAP_BASE 101 + +#define L_TRAP_DART 101 +#define L_TRAP_PIT 102 +#define L_TRAP_DOOR 103 +#define L_TRAP_SNARE 104 +#define L_TRAP_BLADE 105 +#define L_TRAP_FIRE 106 +#define L_TRAP_TELEPORT 107 +#define L_TRAP_DISINTEGRATE 108 +#define L_TRAP_SLEEP_GAS 109 +#define L_TRAP_ACID 110 +#define L_TRAP_MANADRAIN 111 +#define L_TRAP_ABYSS 112 +#define L_TRAP_SIREN 113 + +#define NUM_SAFE_TRAPS 7 +/* the first NUM_SAFE_TRAPS are non-insta-lethal */ + +/* leave head room for extra traps: 114, 115, 116, 117, 118, 119, 120 */ + +/* random sites */ +#define L_CHAOS 121 +#define L_WATER 122 +#define L_LAVA 123 +#define L_ABYSS 124 +#define L_MAGIC_POOL 125 +#define L_PORTCULLIS_TRAP 126 +#define L_PORTCULLIS 127 +#define L_STATUE_WAKE 128 +#define L_HEDGE 129 +#define L_RUBBLE 130 + +#define L_DROP_EVERY_PORTCULLIS 131 /* tested, but never set */ + +/* unused site functions, these were defined, so I left them defined -- DAG */ +#define L_STATUE_RANDOM 132 /* not currently used */ + +/* player possession slots */ +/* slot 0 should not be filled when out of inventory_control() */ + +#define O_UP_IN_AIR 0 +#define O_READY_HAND 1 +#define O_WEAPON_HAND 2 +#define O_LEFT_SHOULDER 3 +#define O_RIGHT_SHOULDER 4 +#define O_BELT1 5 +#define O_BELT2 6 +#define O_BELT3 7 +#define O_SHIELD 8 +#define O_ARMOR 9 +#define O_BOOTS 10 +#define O_CLOAK 11 +#define O_RING1 12 +#define O_RING2 13 +#define O_RING3 14 +#define O_RING4 15 + + +/* Changing these would currently require changing the maps as well (although + * there should be no other side effects). I intend to remove the need for + * this list later, by making the maps refer to each other (and thus removing + * the need for the game to know about anything but map 0), but that comes + * MUCH later. */ +enum map_identifier { + MAP_country=0, + MAP_arena=1, + MAP_circle=2, + MAP_city=3, + MAP_abyss=4, + MAP_court=5, + MAP_dlair=6, + MAP_hedges=7, + MAP_house=8, + MAP_hovel=9, + MAP_mansion=10, + MAP_misle=11, + MAP_skorch=12, + MAP_speak=13, + MAP_starview=14, + MAP_stormwat=15, + MAP_temple=16, + MAP_thaumari=17, + MAP_whorfen=18, + MAP_woodmere=19, +}; + +/* typedefs needed by structs */ + +/* I don't ever define map_type (except in the C file where it's used); this + * means that you _must_ declare only pointers to it. I've defined, of + * course, all of the needed accessor and mutator functions; see externs.h, + * in the map.c section. */ +struct map_type; +typedef struct map_type map; + +/* structure definitions */ + +struct bank_account +{ + short player; + long balance; + long number; + char *password; + struct bank_account * next_account; +}; +typedef struct bank_account bank_account; + +struct room { + int lighted; + int left,right,top,bottom; + int rsi; /* index into roomname switch */ +}; + +struct spell { + char known; + char id; + char powerdrain; +} ; + +struct player { + int str,con,dex,agi,iq,pow,maxstr,maxcon,maxdex,maxagi,maxiq,maxpow; + long xp; + int level,hp,maxhp,hit,dmg,absorption,speed,click; + int defense,food,alignment; + long mana,maxmana; + long cash; + int patron,birthday; + char preference; + int sx,sy; /* sanctuary coordinates */ + int x,y; /* current player coordinates */ + int itemweight,maxweight; + int immunity[NUMIMMUNITIES]; + int status[NUMSTATI]; + long options; + int rank[NUMRANKS]; + long guildxp[NUMRANKS]; + char name[64]; + char combatManeuvers[64]; + Object *possessions[MAXITEMS]; + Object *pack[MAXPACK]; + int packptr; +}; + +struct objectlist { + Object *thing; + struct objectlist *next; +}; + +/* terrain locations */ +struct terrain { + Symbol base_terrain_type; + Symbol current_terrain_type; + char aux; + char status; +}; + +/* dungeon locations */ +struct location { + unsigned char p_locf; /* function executed when moved on */ + unsigned char lstatus; /* seen,stopsrun,lit,secret, */ + unsigned char roomnumber; /* so room can be named */ + Symbol locchar; /* terrain type */ + Symbol showchar; /*char instantaneously drawn for site */ + int aux; /* signifies various things */ + unsigned char buildaux; /* used in constructing level */ + struct objectlist *things; + Monster *creature; +}; + +struct level { + char depth; /* which level is this */ + struct level *next; /* pointer to next level in dungeon */ + struct location site[MAXWIDTH][MAXLENGTH]; /* dungeon data */ + char generated; /* has the level been made (visited) yet? */ + char numrooms; /* number of rooms on level */ + char tunnelled; /* amount of tunnelling done on this level */ + MonsterList *mlist; /* List of monsters on level */ + int environment; /* where kind of level is this? */ + int last_visited; /* time player was last on this level */ + int level_width; /* width of current level */ + int level_length; /* length of current level */ +}; + +/* random typedef's */ + +typedef struct location loctype; +typedef loctype *plc; + +typedef struct level levtype; +typedef levtype *plv; + +typedef struct objectlist oltype; +typedef oltype *pol; + +/* random function declarations from system libraries */ + +#undef sign +#undef max +#undef min +#undef abs +/* These must be made to work for both longs and ints */ +#define sign(n) (((n) < 0) ? -1 : (((n) > 0) ? 1 : 0)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define abs(n) (((n) < 0) ? (-(n)) : (n)) + +#define RANDFUNCTION genrand +#define SRANDFUNCTION sgenrand + +/* WDT: This should be harmless under ANSI C, and will stop + * some errors under bizarre platforms. */ +#define pow2(n) (1L << (n)) + +/* these bit operations were functions, but are faster as macros... */ + +#define loc_statusp(x,y,stat) ((Level->site[x][y].lstatus&(stat))?1:0) +#define lset(x,y,stat) (Level->site[x][y].lstatus |= (stat)) +#define lreset(x,y,stat) (Level->site[x][y].lstatus &= ~(stat)) + +#define c_statusp(x,y,stat) ((Country[x][y].status&(stat))?1:0) +#define c_set(x,y,stat) (Country[x][y].status |= (stat)) +#define c_reset(x,y,stat) (Country[x][y].status &= ~(stat)) + +#define m_statusp(m,s) (((m)->status&(s))?1:0) +#define m_status_set(m,s) ((m)->status |= (s)) +#define m_status_reset(m,s) ((m)->status &= ~(s)) +#define m_immunityp(m,s) (((m)->immunity&pow2(s))?1:0) + +#define optionp(o) ((Player.options&(o))?1:0) +#define optionset(o) (Player.options |= (o)) +#define optionreset(o) (Player.options &= ~(o)) + +#define KEY_ARROW_UP 30 +#define KEY_ARROW_DOWN 31 +#define KEY_ARROW_RIGHT 16 +#define KEY_ARROW_LEFT 17 + +#endif //DEFS_INCLUDED \ No newline at end of file diff --git a/Omega/src/guild2.cpp b/Omega/src/guild2.cpp index 12278d4..384c5bd 100644 --- a/Omega/src/guild2.cpp +++ b/Omega/src/guild2.cpp @@ -1,1181 +1,1173 @@ -/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ -/* guild2.c */ -/* L_ functions */ - -/* These functions implement the various guilds. */ -/* They are all l_ functions since they are basically activated*/ -/* at some site or other. */ - -#include "glob.h" - -void l_thieves_guild(void) -{ - int fee,count,i,number,done=false,dues=1000; - char c,action; - Object* lockpick; - print1("You have penetrated to the Lair of the Thieves' Guild."); - if (! nighttime()) - print2("There aren't any thieves around in the daytime."); - else { - if ((Player.rank[THIEVES]==TMASTER) && - (Player.level > Shadowlordlevel) && - find_and_remove_item(OB_JUSTICIAR_BADGE,-1)) { - print2("You nicked the Justiciar's Badge!"); - morewait(); - print1("The Badge is put in a place of honor in the Guild Hall."); - print2("You are now the Shadowlord of the Thieves' Guild!"); - morewait(); - print1("Who says there's no honor among thieves?"); - strcpy(Shadowlord,Player.name); - Shadowlordlevel = Player.level; - morewait(); - Shadowlordbehavior = fixnpc(4); - save_hiscore_npc(7); - clearmsg(); - print1("You learn the Spell of Shadowform."); - Spells[S_SHADOWFORM].known = true; - morewait(); - clearmsg(); - Player.rank[THIEVES]=SHADOWLORD; - Player.maxagi += 2; - Player.maxdex += 2; - Player.agi += 2; - Player.dex += 2; - } - while (! done) { - menuclear(); - if (Player.rank[THIEVES] == 0) - menuprint("a: Join the Thieves' Guild.\n"); - else - menuprint("b: Raise your Guild rank.\n"); - menuprint("c: Get an item identified.\n"); - if (Player.rank[THIEVES] > 0) - menuprint("d: Fence an item.\n"); - menuprint("ESCAPE: Leave this Den of Iniquity."); - showmenu(); - action = mgetc(); - if (action == ESCAPE) done = true; - else if (action == 'a') { - done = true; - if (Player.rank[THIEVES]> 0) - print2("You are already a member!"); - else if (Player.alignment > 10) - print2("You are too lawful to be a thief!"); - else { - dues += dues*(12-Player.dex)/9; - dues += Player.alignment*5; - dues = max(100,dues); - clearmsg(); - mprint("Dues are"); - mnumprint(dues); - mprint(" Au. Pay it? [yn] "); - if (ynq1() =='y') { - if (Player.cash < dues) { - print1("You can't cheat the Thieves' Guild!"); - print2("... but the Thieves' Guild can cheat you...."); - Player.cash = 0; - } - else { - print1("Shadowlord "); - nprint1(Shadowlord); - print2("enters your name into the roll of the Guild."); - morewait(); - clearmsg(); - print1("As a special bonus, you get a free lockpick."); - print2("You are taught the spell of Object Detection."); - morewait(); - Spells[S_OBJ_DET].known = true; - lockpick = ((Object*) checkmalloc(sizeof(Object))); - *lockpick = Objects[OB_LOCK_PICK]; /* lock pick */ - gain_item(lockpick); - Player.cash -= dues; - dataprint(); - Player.guildxp[THIEVES]=1; - Player.rank[THIEVES]=TMEMBER; - Player.maxdex++; - Player.dex++; - Player.agi++; - Player.maxagi++; - } - } - } - } - else if (action == 'b') { - if (Player.rank[THIEVES]==0) - print2("You are not even a member!"); - else if (Player.rank[THIEVES]==SHADOWLORD) - print2("You can't get any higher than this!"); - else if (Player.rank[THIEVES]==TMASTER) { - if (Player.level <= Shadowlordlevel) - print2("You are not experienced enough to advance."); - else print2("You must bring back the Justiciar's Badge!"); - } - else if (Player.rank[THIEVES]==THIEF) { - if (Player.guildxp[THIEVES] < 4000) - print2("You are not experienced enough to advance."); - else { - print1("You are now a Master Thief of the Guild!"); - print2("You are taught the Spell of Apportation."); - morewait(); - print1("To advance to the next level you must return with"); - print2("the badge of the Justiciar (cursed be his name)."); - morewait(); - clearmsg(); - print1("The Justiciar's office is just south of the gaol."); - Spells[S_APPORT].known = true; - Player.rank[THIEVES]=TMASTER; - Player.maxagi++; - Player.maxdex++; - Player.agi++; - Player.dex++; - } - } - else if (Player.rank[THIEVES]==ATHIEF) { - if (Player.guildxp[THIEVES] < 1500) - print2("You are not experienced enough to advance."); - else { - print1("You are now a ranking Thief of the Guild!"); - print2("You learn the Spell of Invisibility."); - Spells[S_INVISIBLE].known = true; - Player.rank[THIEVES]=THIEF; - Player.agi++; - Player.maxagi++; - } - } - else if (Player.rank[THIEVES]==TMEMBER) { - if (Player.guildxp[THIEVES] < 400) - print2("You are not experienced enough to advance."); - else { - print1("You are now an Apprentice Thief!"); - print2("You are taught the Spell of Levitation."); - Spells[S_LEVITATE].known = true; - Player.rank[THIEVES]=ATHIEF; - Player.dex++; - Player.maxdex++; - } - } - } - else if (action == 'c') { - if (Player.rank[THIEVES]==0) { - print1("RTG, Inc, Appraisers. Identification Fee: 50Au/item."); - fee = 50; - } - else { - fee = 5; - print1("The fee is 5Au per item."); - } - print2("Identify one item, or all possessions? [ip] "); - if ((char) mcigetc()=='i') { - if (Player.cash < fee) - print2("Try again when you have the cash."); - else { - Player.cash -= fee; - dataprint(); - identify(0); - } - } - else { - count = 0; - for(i=1; iknown < 2) - count++; - for(i=0; iknown < 2) - count++; - clearmsg(); - print1("The fee will be: "); - mnumprint(max(count*fee,fee)); - nprint1("Au. Pay it? [yn] "); - if (ynq1()=='y') - { - if (Player.cash < max(count*fee,fee)) - print2("Try again when you have the cash."); - else { - Player.cash -= max(count*fee,fee); - dataprint(); - identify(1); - } - } - } - } - else if (action == 'd') { - if (Player.rank[THIEVES]==0) - print2("Fence? Who said anything about a fence?"); - else { - print1("Fence one item or go through pack? [ip] "); - if ((char) mcigetc()=='i') { - i = getitem(NULL_ITEM); - if ((i==ABORT) || (Player.possessions[i] == NULL)) { - clearmsg(); - print2("Huh, Is this some kind of set-up?"); - } else if (Player.possessions[i]->blessing < 0) - print2("I don't want to buy a cursed item!"); - else { - clearmsg(); - print1("I'll give you "); - mlongprint(2 * item_value(Player.possessions[i]) / 3); - nprint1("Au each. OK? [yn] "); - if (ynq1() == 'y') { - number = getnumber(Player.possessions[i]->number); - if ((number >= Player.possessions[i]->number) && - Player.possessions[i]->used) { - Player.possessions[i]->used = false; - item_use(Player.possessions[i]); - } - Player.cash += number*2*item_value(Player.possessions[i])/3; - /* Fenced artifacts could turn up anywhere, really... */ - if (Objects[Player.possessions[i]->id].uniqueness > - UNIQUE_UNMADE) - Objects[Player.possessions[i]->id].uniqueness = UNIQUE_UNMADE; - dispose_lost_objects(number,Player.possessions[i]); - dataprint(); - } - else print2("Hey, gimme a break, it was a fair price!"); - } - } - else { - for(i=0; iblessing > -1) { - clearmsg(); - print1("Sell "); - nprint1(itemid(Player.pack[i])); - nprint1(" for "); - mlongprint(2*item_value(Player.pack[i])/3); - nprint1("Au each? [ynq] "); - if ((c=ynq1())=='y') { - number = getnumber(Player.pack[i]->number); - Player.cash += 2*number * item_value(Player.pack[i]) / 3; - Player.pack[i]->number -= number; - if (Player.pack[i]->number < 1) { - /* Fenced an artifact? You just might see it again. */ - if (Objects[Player.pack[i]->id].uniqueness > UNIQUE_UNMADE) - Objects[Player.pack[i]->id].uniqueness = UNIQUE_UNMADE; - free((char *)Player.pack[i]); - Player.pack[i] = NULL; - } - dataprint(); - } - else if (c=='q') break; - } - } - fixpack(); - } - } - } - } - } - xredraw(); -} - -void l_college(void) -{ - char action; - int done=false,enrolled = false; - print1("The Collegium Magii. Founded 16937, AOF."); - if (nighttime()) - print2("The Registration desk is closed at night...."); - else { - while (! done) { - if ((Player.rank[COLLEGE]==MAGE) && - (Player.level > Archmagelevel) && - find_and_remove_item(CORPSEID,EATER)) { - print1("You brought back the heart of the Eater of Magic!"); - morewait(); - print1("The Heart is sent to the labs for analysis."); - print2("The Board of Trustees appoints you Archmage!"); - morewait(); - clearmsg(); - strcpy(Archmage,Player.name); - Archmagelevel = Player.level; - Player.rank[COLLEGE] = ARCHMAGE; - Player.maxiq += 5; - Player.iq += 5; - Player.maxpow += 5; - Player.pow += 5; - morewait(); - Archmagebehavior = fixnpc(4); - save_hiscore_npc(9); - } - menuclear(); - menuprint("May we help you?\n\n"); - menuprint("a: Enroll in the College.\n"); - menuprint("b: Raise your College rank.\n"); - menuprint("c: Do spell research.\n"); - menuprint("ESCAPE: Leave these hallowed halls.\n"); - showmenu(); - action = mgetc(); - if (action == ESCAPE) done = true; - else if (action == 'a') { - if (Player.rank[COLLEGE] > 0) - print2("You are already enrolled!"); - else if (Player.iq < 13) - print2("Your low IQ renders you incapable of being educated."); - else if (Player.rank[CIRCLE] > 0) - print2("Sorcery and our Magic are rather incompatible, no?"); - else if (Player.rank[MONKS] > 0) - print2("Meditation will not leave you enough time for studies."); - else { - if (Player.iq > 17) { - print2("You are given a scholarship!"); - morewait(); - enrolled=true; - } - else { - print1("Tuition is 1000Au. "); - nprint1("Pay it? [yn] "); - if (ynq1() =='y') { - if (Player.cash < 1000) - print2("You don't have the funds!"); - else { - Player.cash -= 1000; - enrolled = true; - dataprint(); - } - } - } - if (enrolled) { - print1("Archmage "); - nprint1(Archmage); - nprint1(" greets you and congratulates you on your acceptance."); - print2("You are now enrolled in the Collegium Magii!"); - morewait(); - print1("You are now a Novice."); - print2("You may research 1 spell, for your intro class."); - Spellsleft = 1; - Player.rank[COLLEGE] = INITIATE; - Player.guildxp[COLLEGE] = 1; - Player.maxiq += 1; - Player.iq += 1; - Player.maxpow += 1; - Player.pow += 1; - } - } - } - else if (action == 'b') { - if (Player.rank[COLLEGE] == 0) - print2("You have not even been initiated, yet!"); - else if (Player.rank[COLLEGE]==ARCHMAGE) - print2("You are at the pinnacle of mastery in the Collegium."); - else if (Player.rank[COLLEGE]==MAGE) { - if (Player.level <= Archmagelevel) - print2("You are not experienced enough to advance."); - else - print2("You must return with the heart of the Eater of Magic!"); - } - else if (Player.rank[COLLEGE]==PRECEPTOR) { - if (Player.guildxp[COLLEGE] < 4000) - print2("You are not experienced enough to advance."); - else { - print1("You are now a Mage of the Collegium Magii!"); - print2("You may research 6 spells for postdoctoral research."); - Spellsleft += 6; - morewait(); - print1("To become Archmage, you must return with the"); - print2("heart of the Eater of Magic"); - morewait(); - clearmsg(); - print1("The Eater may be found on a desert isle somewhere."); - Player.rank[COLLEGE] = MAGE; - Player.maxiq += 2; - Player.iq += 2; - Player.maxpow += 2; - Player.pow += 2; - } - } - else if (Player.rank[COLLEGE]==STUDENT) { - if (Player.guildxp[COLLEGE] < 1500) - print2("You are not experienced enough to advance."); - else { - print1("You are now a Preceptor of the Collegium Magii!"); - print2("You are taught the basics of ritual magic."); - morewait(); - clearmsg(); - print1("Your position allows you to research 4 spells."); - Spellsleft +=4; - Spells[S_RITUAL].known = true; - Player.rank[COLLEGE] = PRECEPTOR; - Player.maxiq += 1; - Player.iq += 1; - Player.maxpow += 1; - Player.pow += 1; - } - } - else if (Player.rank[COLLEGE]==NOVICE) { - if (Player.guildxp[COLLEGE] < 400) - print2("You are not experienced enough to advance."); - else { - print1("You are now a Student at the Collegium Magii!"); - print2("You are taught the spell of identification."); - morewait(); - clearmsg(); - print1("Thesis research credit is 2 spells."); - Spellsleft+=2; - Spells[S_IDENTIFY].known = true; - Player.rank[COLLEGE] = STUDENT; - Player.maxiq += 1; - Player.iq += 1; - Player.maxpow += 1; - Player.pow += 1; - } - } - } - else if (action == 'c') { - clearmsg(); - if (Spellsleft > 0) { - print1("Research permitted: "); - mnumprint(Spellsleft); - nprint1(" Spells."); - morewait(); - } - if (Spellsleft < 1) { - print1("Extracurricular Lab fee: 2000 Au. "); - nprint1("Pay it? [yn] "); - if (ynq1()=='y') { - if (Player.cash < 2000) - print1("Try again when you have the cash."); - else { - Player.cash -= 2000; - dataprint(); - Spellsleft = 1; - } - } - } - if (Spellsleft > 0) { - learnspell(0); - Spellsleft--; - } - } - } - } - xredraw(); -} - -void l_monastery(void) -{ - char action; - int done=false,enrolled = false; - - if ( Player.maxpow < 13 && LastFreeYogaDay != Date && YogaSessions < 1 && !nighttime()) { - print1("Strengthen your inner spirit, child. Please accept this offer "); - print2("to sit in our yoga class, free of charge."); - YogaSessions += 1; - LastFreeYogaDay = Date; - morewait(); - clearmsg(); - } - print1("Tholian Monastery of Rampart. Founded 12031, AOF."); - print2("Welcome to our humble hovel."); - if (nighttime()) - print2("The monastery doors are sealed until dawn."); - else { - if( YogaSessions > 0 ) - nprint2(" -- 1 free yoga session"); - while (! done) { - menuclear(); - menuprint("Find your true Course:\n\n"); - menuprint("a: Discover the Way.\n"); - menuprint("b: Meditate on the Path.\n"); - menuprint("c: Meditate on Knowledge.\n"); - menuprint("d: Take an extended Meditation.\n"); - menuprint("e: Sit for a yoga class.\n"); - menuprint("ESCAPE: Re-enter the World.\n"); - showmenu(); - action = mgetc(); - if (action == ESCAPE) { - done = true; - calc_melee(); - } - else if (action == 'a') { - if (Player.rank[MONKS] > 0) - print2("You are already initiated, Brother."); - else if (Player.con < 13) - print2("Your body is too fragile to walk the Path, child."); - else if (Player.pow < 13) - print2("Your mind is too fragile to follow the Path, child."); - else if (Player.rank[COLLEGE] > 0) - print2("The Collegium has corrupted your spirit, child."); - else if (Player.rank[CIRCLE] > 0) - print2("The Circle has corrupted your spirit, child."); - else { - if (Player.pow > 17) { - print2("Your spirit is strong. You may study the Path with us."); - morewait(); - enrolled=true; - } - else { - print1("A substantial cash sacrifice will cleanse your spirit.. "); - print2("Donate your worldly goods? [yn] "); - if (ynq1() =='y') { - if (Player.cash < 1000) - { - /* WDT HACK! I'd rather the monks have some other - * criteria for joining. */ - print2("You have not much to give."); - } - else { - Player.cash = 0; - enrolled = true; - dataprint(); - } - } - } - if (enrolled) { - print1("Grandmaster "); - nprint1(Grandmaster); - nprint1(" welcomes you to the Brotherhood."); - print2("You are now a Tholian Monk trainee!"); - morewait(); - print2("You may study the Way with us."); - Studiesleft = 1; - Player.rank[MONKS] = MONK_TRAINEE; - Player.guildxp[MONKS] = 1; - Player.maxpow += 1; - Player.pow += 1; - } - } - } - else if (action == 'b') { - if (Player.rank[MONKS] == 0) - print2("You are not yet initiated, child."); - else if (Player.rank[MONKS]==MONK_GRANDMASTER) - print2("Your advancement lies within, Grandmaster."); - else if (Player.rank[MONKS]==MONK_MASTER_TEARS) { - if (Player.level <= Grandmasterlevel) - print2("Seek more experience, Master."); - else if ((Player.rank[MONKS]==MONK_MASTER_TEARS) && - (Player.level > Grandmasterlevel) && - find_and_remove_item(CORPSEID,EATER)) - { - print1("You brought back the heart of the Eater of Magic!"); - morewait(); - print1("The Heart is sent to the placed in the kitchen cauldron."); - print2("The Grandmaster steps down. You are the new Grandmaster."); - morewait(); - clearmsg(); - strcpy(Grandmaster,Player.name); - Grandmasterlevel = Player.level; - Player.rank[MONKS] = MONK_GRANDMASTER; - Player.maxhp += (Player.maxpow * 3); - Player.maxiq += 5; - Player.iq+= 5; - Player.maxpow += 3; - Player.pow += 3; - Player.maxstr += 3; - Player.str += 3; - morewait(); - Grandmasterbehavior = fixnpc(4); - save_hiscore_npc(16); - } - else - print2("You must return with the heart of the Eater of Magic!"); - - } - else if (Player.rank[MONKS]==MONK_MASTER_PAINS) { - if (Player.guildxp[MONKS] < 40000) - print2("Seek more experience, Master."); - else { - print1("You have travelled far, Master."); - print2("You are now Master of Tears."); - Studiesleft += 6; - morewait(); - print1("To become Grandmaster, you must return with the"); - print2("heart of the Eater of Magic"); - morewait(); - clearmsg(); - print1("The Eater may be found on a desert isle somewhere."); - Spells[S_REGENERATE].known = true; - Player.rank[MONKS] = MONK_MASTER_TEARS; - Player.maxhp += (Player.maxpow * 2); - Player.maxpow += 2; - Player.pow += 2; - Player.maxstr += 2; - Player.str += 2; - Player.maxagi += 2; - Player.agi += 2; - } - } - else if (Player.rank[MONKS]==MONK_MASTER_SIGHS) { - if (Player.guildxp[MONKS] < 15000) - print2("Seek more experience, Master."); - else { - print1("The Path is long, Master."); - print2("You are now Master of Pain."); - morewait(); - print1("You feel enlightened."); - morewait(); - clearmsg(); - Studiesleft +=4; - Spells[S_RITUAL].known = true; - Spells[S_RESTORE].known = true; - Player.status[ILLUMINATION] = 1500; /* enlightened */ - Player.rank[MONKS] = MONK_MASTER_PAINS; - Player.maxhp += Player.maxpow; - Player.maxcon += 1; - Player.con += 1; - Player.maxdex += 2; - Player.dex += 2; - } - } - else if (Player.rank[MONKS]==MONK_MASTER) { - if (Player.guildxp[MONKS] < 9000) - print2("Seek more experience, Master."); - else { - print1("Drink, weary Master."); - print2("You are now Master of Sighs."); - morewait(); - clearmsg(); - Studiesleft +=2; - Spells[S_HASTE].known = true; - Player.rank[MONKS] = MONK_MASTER_SIGHS; - Player.maxhp += Player.maxpow; - Player.maxcon += 1; - Player.con += 1; - Player.maxiq += 2; - Player.iq += 2; - } - } - else if (Player.rank[MONKS]==MONK_MONK) { - if (Player.guildxp[MONKS] < 3000) - print2("Seek more experience, Brother."); - else { - print1("A thousand steps on the path, Brother."); - print2("You are now a Master."); - morewait(); - clearmsg(); - Studiesleft +=2; - Spells[S_HEAL].known = true; - Player.rank[MONKS] = MONK_MASTER; - Player.maxhp += Player.maxpow; - Player.maxcon += 1; - Player.con += 1; - Player.maxpow += 2; - Player.pow += 5; /* [sic] */ - } - } - else if (Player.rank[MONKS]==MONK_TRAINEE) { - if (Player.guildxp[MONKS] < 1500) - print2("Seek more experience, Brother."); - else { - print1("You have sought wisdom, Brother."); - print2("You are now a Tholian Monk."); - morewait(); - clearmsg(); - Studiesleft +=2; - Spells[S_CURE].known = true; - Player.rank[MONKS] = MONK_MONK; - Player.maxhp += Player.maxpow; - Player.maxcon += 1; - Player.con += 1; - Player.maxpow += 1; - Player.pow += 1; - } - } - } - else if (action == 'c') { - clearmsg(); - if (Studiesleft > 0) { - print1("Studies permitted: "); - mnumprint(Studiesleft); - nprint1(" Studies."); - morewait(); - } - if (Studiesleft < 1) { - print1("Sacrifice clears a cluttered heart. "); - nprint1("Donate your worldly cash? [yn] "); - if (ynq1()=='y') { - if (Player.cash < 2000) - { - if ( Player.rank[MONKS] >= MONK_GRANDMASTER ) - print2("You have not much to give, Grandmaster."); - else if ( Player.rank[MONKS] >= MONK_MASTER ) - print2("You have not much to give, Master."); - else - print2("You have not much to give, Brother."); - } - else { - Player.cash = 0; - dataprint(); - Studiesleft = 1; - } - } - } - if (Studiesleft > 0) { - learnspell(0); - Studiesleft--; - } - } - else if (action == 'd') { - if (Player.rank[MONKS] < MONK_MASTER) { - clearmsg(); - print1("Only Masters can achieve extended meditation, child."); - print2(" "); - } - else { - int i = 0; - clearmsg(); - print1("Seeking inner truth..."); - morewait(); - clearmsg(); - morewait(); - toggle_item_use(true); - Player.cash = 0; - Player.hp = Player.maxhp; - Player.str = Player.maxstr; - Player.agi = Player.maxagi; - Player.con = Player.maxcon; - Player.dex = Player.maxdex; - Player.iq = Player.maxiq; - Player.pow = Player.maxpow; - for (i=0; i 0 ) - print1("Use your credit to take a class? [yn] "); - else - print1("Yoga class requires a 2000 Au donation. Pay the fee? [yn] "); - if (ynq1()=='y') { - if (Player.cash < 2000 && YogaSessions < 1) { - if ( Player.rank[MONKS] >= MONK_GRANDMASTER ) - print2("You have not much to give, Grandmaster."); - else if ( Player.rank[MONKS] >= MONK_MASTER ) - print2("You have not much to give, Master."); - else if (Player.rank[MONKS] <= MONK_MONK) - print2("You have not much to give, Brother."); - else - print2("You have not much to give, child."); - } - else { - if( YogaSessions > 0 ) - YogaSessions--; - else - Player.cash -= 2000; - print1( "You are ushered into the meditation room." ); - - int trained = 0; - /* minimum 20% chance at pow >= 22 */ - if ( Player.maxpow >= 22 && Player.maxpow < 30 && random_range ( 10 ) < 2 ) - trained++; - - /* 10% lower chance per level after 13 maxpow */ - else if ( Player.maxpow < 22 && random_range( 10 ) < (10 - (Player.maxpow - 12))) - trained++; - - else { - print2("You emerge exhausted and dripping sweat!"); - if( Player.pow < Player.maxpow ) - Player.pow++; - } - - if ( trained ) { - Player.maxpow++; - Player.pow++; - print2( "The yoga instructor stretches your physical and spiritual limits!" ); - } - dataprint(); - } - } - } - } - } - } - xredraw(); -} - -void l_sorcerors(void) -{ - char action; - int done=false,fee; - long total; - print1("The Circle of Sorcerors."); - if (Player.rank[CIRCLE] == -1) { - print2("Fool! Didn't we tell you to go away?"); - Player.mana = 0; - dataprint(); - } - else while (! done) { - if ((Player.rank[CIRCLE]==HIGHSORCEROR) && - (Player.level > Primelevel) && - find_and_remove_item(CORPSEID,LAWBRINGER)) { - print2("You obtained the Crown of the Lawgiver!"); - morewait(); - print1("The Crown is ritually sacrificed to the Lords of Chaos."); - print2("You are now the Prime Sorceror of the Inner Circle!"); - strcpy(Prime,Player.name); - Primelevel = Player.level; - morewait(); - Primebehavior = fixnpc(4); - save_hiscore_npc(10); - clearmsg(); - print1("You learn the Spell of Disintegration!"); - morewait(); - clearmsg(); - Spells[S_DISINTEGRATE].known = true; - Player.rank[CIRCLE] = PRIME; - Player.maxpow += 10; - Player.pow += 10; - } - menuclear(); - menuprint("May we help you?\n\n"); - menuprint("a: Become an Initiate of the Circle.\n"); - menuprint("b: Raise your rank in the Circle.\n"); - menuprint("c: Restore mana points\n"); - menuprint("ESCAPE: Leave these Chambers of Power.\n"); - showmenu(); - action = mgetc(); - if (action == ESCAPE) done = true; - else if (action == 'a') { - if (Player.rank[CIRCLE] > 0) - print2("You are already an initiate!"); - else if (Player.alignment > 0) - print2("You may not join -- you reek of Law!"); - else if (Player.rank[COLLEGE] > 0) - print2("Foolish Mage! You don't have the right attitude to Power!"); - else if (Player.rank[MONKS] > 0) - print2("Stupid monk. Go meditate on this!"); - else { - fee = 3000; - fee += Player.alignment*100; - fee += fee*(12 - Player.pow)/9; - fee = max(100,fee); - clearmsg(); - mprint("For you, there is an initiation fee of"); - mnumprint(fee); - mprint(" Au."); - print2("Pay it? [yn] "); - if (ynq2() =='y') { - if (Player.cash < fee) - print3("Try again when you have the cash!"); - else { - print1("Prime Sorceror "); - nprint1(Prime); - print2("conducts your initiation into the circle of novices."); - morewait(); - clearmsg(); - print1("You learn the Spell of Magic Missiles."); - Spells[S_MISSILE].known = true; - Player.cash -= fee; - dataprint(); - Player.rank[CIRCLE] = INITIATE; - Player.guildxp[CIRCLE] = 1; - Player.maxpow++; - Player.pow++; - } - } - } - } - else if (action == 'b') { - if (Player.rank[CIRCLE] == 0) - print2("You have not even been initiated, yet!"); - else if (Player.alignment > -1) { - print1("Ahh! You have grown too lawful!!!"); - print2("You are hereby blackballed from the Circle!"); - Player.rank[CIRCLE] = -1; - morewait(); - clearmsg(); - print1("A pox upon thee!"); - if (! Player.immunity[INFECTION]) - Player.status[DISEASED]+=100; - print2("And a curse on your possessions!"); - morewait(); - clearmsg(); - acquire(-1); - clearmsg(); - enchant(-1); - bless(-1); - print3("Die, false sorceror!"); - p_damage(25,UNSTOPPABLE,"a sorceror's curse"); - done = true; - } - else if (Player.rank[CIRCLE]==PRIME) - print2("You are at the pinnacle of mastery in the Circle."); - else if (Player.rank[CIRCLE]==HIGHSORCEROR) { - if (Player.level <= Primelevel) - print2("You are not experienced enough to advance."); - else - print2("You must return with the Crown of the LawBringer!"); - } - else if (Player.rank[CIRCLE]==SORCEROR) { - if (Player.guildxp[CIRCLE] < 4000) - print2("You are not experienced enough to advance."); - else { - print1("You are now a High Sorceror of the Inner Circle!"); - print2("You learn the Spell of Disruption!"); - morewait(); - clearmsg(); - print1("To advance you must return with the LawBringer's Crown!"); - print2("The LawBringer resides on Star Peak."); - Spells[S_DISRUPT].known = true; - Player.rank[CIRCLE] = HIGHSORCEROR; - Player.maxpow += 5; - Player.pow += 5; - } - } - else if (Player.rank[CIRCLE]==ENCHANTER) { - if (Player.guildxp[CIRCLE] < 1500) - print2("You are not experienced enough to advance."); - else { - print1("You are now a member of the Circle of Sorcerors!"); - print2("You learn the Spell of Ball Lightning!"); - Spells[S_LBALL].known = true; - Player.rank[CIRCLE] = SORCEROR; - Player.maxpow += 2; - Player.pow+=2; - } - } - else if (Player.rank[CIRCLE]==INITIATE) { - if (Player.guildxp[CIRCLE] < 400) - print2("You are not experienced enough to advance."); - else { - print1("You are now a member of the Circle of Enchanters!"); - print2("You learn the Spell of Firebolts."); - Spells[S_FIREBOLT].known = true; - Player.rank[CIRCLE] = ENCHANTER; - Player.maxpow+=2; - Player.pow+=2; - } - } - } - else if (action == 'c') { - done = true; - fee = Player.level*100; - if (Player.rank[CIRCLE]) fee = fee / 2; - clearmsg(); - print1("That will be: "); - mnumprint(fee); - nprint1("Au. Pay it? [yn] "); - if (ynq1()=='y') { - if (Player.cash < fee) - print2("Begone, deadbeat, or face the wrath of the Circle!"); - else { - Player.cash -= fee; - total = calcmana(); - while (Player.mana < total) { - Player.mana++; - dataprint(); - } - print2("Have a sorcerous day, now!"); - } - } - else print2("Be seeing you!"); - } - } - xredraw(); -} - - - - -void l_order(void) -{ - Object* newitem; - MonsterList* ml; - print1("The Headquarters of the Order of Paladins."); - morewait(); - if ((Player.rank[ORDER]==PALADIN) && - (Player.level > Justiciarlevel) && - State.getGivenStargem() && - Player.alignment > 300) { - print1("You have succeeded in your quest!"); - morewait(); - print1("The previous Justiciar steps down in your favor."); - print2("You are now the Justiciar of Rampart and the Order!"); - strcpy(Justiciar,Player.name); - for (ml = Level->mlist; ml && (ml->monster->id != HISCORE_NPC || - ml->monster->aux2 != 15); ml = ml->next) - /* just scan for current Justicar */; - if (ml) { - ml->monster->m_remove(); /* signals "death" -- no credit to player, though */ - } - Justiciarlevel = Player.level; - morewait(); - Justiciarbehavior = fixnpc(4); - save_hiscore_npc(15); - clearmsg(); - print1("You are awarded a blessed shield of deflection!"); - morewait(); - newitem = ((Object*) checkmalloc(sizeof(Object))); - *newitem = Objects[OB_DEFLECT]; /* shield of deflection */ - newitem->blessing = 9; - gain_item(newitem); - morewait(); - Player.rank[ORDER] = JUSTICIAR; - Player.maxstr += 5; - Player.str += 5; - Player.maxpow += 5; - Player.pow += 5; - } - if (Player.alignment < 1) { - if (Player.rank[ORDER] > 0) { - print1("You have been tainted by chaos!"); - print2("You are stripped of your rank in the Order!"); - morewait(); - Player.rank[ORDER]= -1; - send_to_jail(); - } - else - print1("Get thee hence, minion of chaos!"); - } - else if (Player.rank[ORDER] == -1) - print1("Thou again? Get thee hence, minion of chaos!"); - else if (Player.rank[ORDER] == 0) { - if (Player.rank[ARENA] != 0) - print1("We do not accept bloodstained gladiators into our Order."); - else if (Player.rank[LEGION] != 0) - print1("Go back to your barracks, mercenary!"); - else { - print1("Dost thou wish to join our Order? [yn] "); - if (ynq1()=='y') { - print1("Justiciar "); - nprint1(Justiciar); - nprint1(" welcomes you to the Order."); - print2("'Mayest thou always follow the sublime path of Law.'"); - morewait(); - print1("You are now a Gallant in the Order."); - print2("You are given a horse and a blessed spear."); - morewait(); - Player.rank[ORDER] = GALLANT; - Player.guildxp[ORDER] = 1; - State.setMounted( true ); - newitem = ((Object*) checkmalloc(sizeof(Object))); - *newitem = Objects[OB_SPEAR]; /* spear */ - newitem->blessing = 9; - newitem->plus = 1; - newitem->known = 2; - gain_item(newitem); - } - } - } else { - print1("'Welcome back, Paladin.'"); - if (!State.getMounted()) { - print2("You are given a new steed."); - State.setMounted( true ); - } - morewait(); - clearmsg(); - if ((Player.hp < Player.maxhp) || (Player.status[DISEASED]) || - (Player.status[POISONED])) - print1("Your wounds are treated by a medic."); - cleanse(0); - Player.hp = Player.maxhp; - if ( Player.food <= 40 ) - { - Player.food = 40; - print2("You get a hot meal from the refectory."); - } - morewait(); - clearmsg(); - if (Player.rank[ORDER]==PALADIN) { - if (Player.level <= Justiciarlevel) - print2("You are not experienced enough to advance."); - else if (Player.alignment < 300) - print2("You are not sufficiently Lawful as yet to advance."); - else print2("You must give the Star Gem to the LawBringer."); - } - else if (Player.rank[ORDER]==CHEVALIER) { - if (Player.guildxp[ORDER] < 4000) - print2("You are not experienced enough to advance."); - else if (Player.alignment < 200) - print2("You are not sufficiently Lawful as yet to advance."); - else { - print1("You are made a Paladin of the Order!"); - print2("You learn the Spell of Heroism and get Mithril Plate!"); - morewait(); - newitem = ((Object*) checkmalloc(sizeof(Object))); - *newitem = Objects[OB_MITHRIL_PLATE]; /* mithril plate armor */ - newitem->blessing = 9; - newitem->known = 2; - gain_item(newitem); - morewait(); - clearmsg(); - print1("To advance you must rescue the Star Gem and return it"); - print2("to its owner, the LawBringer, who resides on Star Peak."); - morewait(); - print1("The Star Gem was stolen by the cursed Prime Sorceror,"); - print2("whose headquarters may be found beyond the Astral Plane."); - morewait(); - print1("The Oracle will send you to the Astral Plane if you"); - print2("prove yourself worthy to her."); - morewait(); - Spells[S_HERO].known = true; - Player.rank[ORDER] = PALADIN; - } - } - else if (Player.rank[ORDER]==GUARDIAN) { - if (Player.guildxp[ORDER] < 1500) - print2("You are not experienced enough to advance."); - else if (Player.alignment < 125) - print2("You are not yet sufficiently Lawful to advance."); - else { - Player.rank[ORDER] = CHEVALIER; - print1("You are made a Chevalier of the Order!"); - print2("You are given a Mace of Disruption!"); - morewait(); - clearmsg(); - newitem = ((Object*) checkmalloc(sizeof(Object))); - *newitem = Objects[OB_MACE_DISRUPT]; /* mace of disruption */ - newitem->known = 2; - gain_item(newitem); - } - } - else if (Player.rank[ORDER]==GALLANT) { - if (Player.guildxp[ORDER] < 400) - print2("You are not experienced enough to advance."); - else if (Player.alignment < 50) - print2("You are not Lawful enough to advance."); - else { - print1("You are made a Guardian of the Order of Paladins!"); - print2("You are given a Holy Hand Grenade (of Antioch)."); - morewait(); - print1("You hear a nasal monotone in the distance...."); - print2("'...and the number of thy counting shall be 3...'"); - morewait(); - clearmsg(); - Player.rank[ORDER] = GUARDIAN; - newitem = ((Object*) checkmalloc(sizeof(Object))); - *newitem = Objects[OB_ANTIOCH]; /* holy hand grenade. */ - newitem->known = 2; - gain_item(newitem); - } - } - } - showflags(); -} +/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ +/* guild2.c */ +/* L_ functions */ + +/* These functions implement the various guilds. */ +/* They are all l_ functions since they are basically activated*/ +/* at some site or other. */ + +#include "glob.h" + +void l_thieves_guild(void) +{ + int fee,count,i,number,done=false,dues=1000; + char c,action; + Object* lockpick; + print1("You have penetrated to the Lair of the Thieves' Guild."); + if (! nighttime()) + print2("There aren't any thieves around in the daytime."); + else { + if ((Player.rank[THIEVES]==TMASTER) && + (Player.level > Shadowlordlevel) && + find_and_remove_item(OB_JUSTICIAR_BADGE,-1)) { + print2("You nicked the Justiciar's Badge!"); + morewait(); + print1("The Badge is put in a place of honor in the Guild Hall."); + print2("You are now the Shadowlord of the Thieves' Guild!"); + morewait(); + print1("Who says there's no honor among thieves?"); + strcpy(Shadowlord,Player.name); + Shadowlordlevel = Player.level; + morewait(); + Shadowlordbehavior = fixnpc(4); + save_hiscore_npc(7); + clearmsg(); + print1("You learn the Spell of Shadowform."); + Spells[S_SHADOWFORM].known = true; + morewait(); + clearmsg(); + Player.rank[THIEVES]=SHADOWLORD; + Player.maxagi += 2; + Player.maxdex += 2; + Player.agi += 2; + Player.dex += 2; + } + while (! done) { + menuclear(); + if (Player.rank[THIEVES] == 0) + menuprint("a: Join the Thieves' Guild.\n"); + else + menuprint("b: Raise your Guild rank.\n"); + menuprint("c: Get an item identified.\n"); + if (Player.rank[THIEVES] > 0) + menuprint("d: Fence an item.\n"); + menuprint("ESCAPE: Leave this Den of Iniquity."); + showmenu(); + action = mgetc(); + if (action == ESCAPE) done = true; + else if (action == 'a') { + done = true; + if (Player.rank[THIEVES]> 0) + print2("You are already a member!"); + else if (Player.alignment > 10) + print2("You are too lawful to be a thief!"); + else { + dues += dues*(12-Player.dex)/9; + dues += Player.alignment*5; + dues = max(100,dues); + clearmsg(); + mprint("Dues are"); + mnumprint(dues); + mprint(" Au. Pay it? [yn] "); + if (ynq1() =='y') { + if (Player.cash < dues) { + print1("You can't cheat the Thieves' Guild!"); + print2("... but the Thieves' Guild can cheat you...."); + Player.cash = 0; + } + else { + print1("Shadowlord "); + nprint1(Shadowlord); + print2("enters your name into the roll of the Guild."); + morewait(); + clearmsg(); + print1("As a special bonus, you get a free lockpick."); + print2("You are taught the spell of Object Detection."); + morewait(); + Spells[S_OBJ_DET].known = true; + lockpick = ((Object*) checkmalloc(sizeof(Object))); + *lockpick = Objects[OB_LOCK_PICK]; /* lock pick */ + gain_item(lockpick); + Player.cash -= dues; + dataprint(); + Player.guildxp[THIEVES]=1; + Player.rank[THIEVES]=TMEMBER; + Player.maxdex++; + Player.dex++; + Player.agi++; + Player.maxagi++; + } + } + } + } + else if (action == 'b') { + if (Player.rank[THIEVES]==0) + print2("You are not even a member!"); + else if (Player.rank[THIEVES]==SHADOWLORD) + print2("You can't get any higher than this!"); + else if (Player.rank[THIEVES]==TMASTER) { + if (Player.level <= Shadowlordlevel) + print2("You are not experienced enough to advance."); + else print2("You must bring back the Justiciar's Badge!"); + } + else if (Player.rank[THIEVES]==THIEF) { + if (Player.guildxp[THIEVES] < 4000) + print2("You are not experienced enough to advance."); + else { + print1("You are now a Master Thief of the Guild!"); + print2("You are taught the Spell of Apportation."); + morewait(); + print1("To advance to the next level you must return with"); + print2("the badge of the Justiciar (cursed be his name)."); + morewait(); + clearmsg(); + print1("The Justiciar's office is just south of the gaol."); + Spells[S_APPORT].known = true; + Player.rank[THIEVES]=TMASTER; + Player.maxagi++; + Player.maxdex++; + Player.agi++; + Player.dex++; + } + } + else if (Player.rank[THIEVES]==ATHIEF) { + if (Player.guildxp[THIEVES] < 1500) + print2("You are not experienced enough to advance."); + else { + print1("You are now a ranking Thief of the Guild!"); + print2("You learn the Spell of Invisibility."); + Spells[S_INVISIBLE].known = true; + Player.rank[THIEVES]=THIEF; + Player.agi++; + Player.maxagi++; + } + } + else if (Player.rank[THIEVES]==TMEMBER) { + if (Player.guildxp[THIEVES] < 400) + print2("You are not experienced enough to advance."); + else { + print1("You are now an Apprentice Thief!"); + print2("You are taught the Spell of Levitation."); + Spells[S_LEVITATE].known = true; + Player.rank[THIEVES]=ATHIEF; + Player.dex++; + Player.maxdex++; + } + } + } + else if (action == 'c') { + if (Player.rank[THIEVES]==0) { + print1("RTG, Inc, Appraisers. Identification Fee: 50Au/item."); + fee = 50; + } + else { + fee = 5; + print1("The fee is 5Au per item."); + } + print2("Identify one item, or all possessions? [ip] "); + if ((char) mcigetc()=='i') { + if (Player.cash < fee) + print2("Try again when you have the cash."); + else { + Player.cash -= fee; + dataprint(); + identify(0); + } + } + else { + count = 0; + for(i=1; iknown < 2) + count++; + for(i=0; iknown < 2) + count++; + clearmsg(); + print1("The fee will be: "); + mnumprint(max(count*fee,fee)); + nprint1("Au. Pay it? [yn] "); + if (ynq1()=='y') + { + if (Player.cash < max(count*fee,fee)) + print2("Try again when you have the cash."); + else { + Player.cash -= max(count*fee,fee); + dataprint(); + identify(1); + } + } + } + } + else if (action == 'd') { + if (Player.rank[THIEVES]==0) + print2("Fence? Who said anything about a fence?"); + else { + print1("Fence one item or go through pack? [ip] "); + if ((char) mcigetc()=='i') { + i = getitem(NULL_ITEM); + if ((i==ABORT) || (Player.possessions[i] == NULL)) { + clearmsg(); + print2("Huh, Is this some kind of set-up?"); + } else if (Player.possessions[i]->blessing < 0) + print2("I don't want to buy a cursed item!"); + else { + clearmsg(); + print1("I'll give you "); + mlongprint(2 * item_value(Player.possessions[i]) / 3); + nprint1("Au each. OK? [yn] "); + if (ynq1() == 'y') { + number = getnumber(Player.possessions[i]->number); + if ((number >= Player.possessions[i]->number) && + Player.possessions[i]->used) { + Player.possessions[i]->used = false; + item_use(Player.possessions[i]); + } + Player.cash += number*2*item_value(Player.possessions[i])/3; + /* Fenced artifacts could turn up anywhere, really... */ + if (Objects[Player.possessions[i]->id].uniqueness > + UNIQUE_UNMADE) + Objects[Player.possessions[i]->id].uniqueness = UNIQUE_UNMADE; + dispose_lost_objects(number,Player.possessions[i]); + dataprint(); + } + else print2("Hey, gimme a break, it was a fair price!"); + } + } + else { + for(i=0; iblessing > -1) { + clearmsg(); + print1("Sell "); + nprint1(itemid(Player.pack[i])); + nprint1(" for "); + mlongprint(2*item_value(Player.pack[i])/3); + nprint1("Au each? [ynq] "); + if ((c=ynq1())=='y') { + number = getnumber(Player.pack[i]->number); + Player.cash += 2*number * item_value(Player.pack[i]) / 3; + Player.pack[i]->number -= number; + if (Player.pack[i]->number < 1) { + /* Fenced an artifact? You just might see it again. */ + if (Objects[Player.pack[i]->id].uniqueness > UNIQUE_UNMADE) + Objects[Player.pack[i]->id].uniqueness = UNIQUE_UNMADE; + free((char *)Player.pack[i]); + Player.pack[i] = NULL; + } + dataprint(); + } + else if (c=='q') break; + } + } + fixpack(); + } + } + } + } + } + xredraw(); +} + +void l_college(void) +{ + char action; + int done=false,enrolled = false; + print1("The Collegium Magii. Founded 16937, AOF."); + if (nighttime()) + print2("The Registration desk is closed at night...."); + else { + while (! done) { + if ((Player.rank[COLLEGE]==MAGE) && + (Player.level > Archmagelevel) && + find_and_remove_item(CORPSEID,EATER)) { + print1("You brought back the heart of the Eater of Magic!"); + morewait(); + print1("The Heart is sent to the labs for analysis."); + print2("The Board of Trustees appoints you Archmage!"); + morewait(); + clearmsg(); + strcpy(Archmage,Player.name); + Archmagelevel = Player.level; + Player.rank[COLLEGE] = ARCHMAGE; + Player.maxiq += 5; + Player.iq += 5; + Player.maxpow += 5; + Player.pow += 5; + morewait(); + Archmagebehavior = fixnpc(4); + save_hiscore_npc(9); + } + menuclear(); + menuprint("May we help you?\n\n"); + menuprint("a: Enroll in the College.\n"); + menuprint("b: Raise your College rank.\n"); + menuprint("c: Do spell research.\n"); + menuprint("ESCAPE: Leave these hallowed halls.\n"); + showmenu(); + action = mgetc(); + if (action == ESCAPE) done = true; + else if (action == 'a') { + if (Player.rank[COLLEGE] > 0) + print2("You are already enrolled!"); + else if (Player.iq < 13) + print2("Your low IQ renders you incapable of being educated."); + else if (Player.rank[CIRCLE] > 0) + print2("Sorcery and our Magic are rather incompatible, no?"); + else if (Player.rank[MONKS] > 0) + print2("Meditation will not leave you enough time for studies."); + else { + if (Player.iq > 17) { + print2("You are given a scholarship!"); + morewait(); + enrolled=true; + } + else { + print1("Tuition is 1000Au. "); + nprint1("Pay it? [yn] "); + if (ynq1() =='y') { + if (Player.cash < 1000) + print2("You don't have the funds!"); + else { + Player.cash -= 1000; + enrolled = true; + dataprint(); + } + } + } + if (enrolled) { + print1("Archmage "); + nprint1(Archmage); + nprint1(" greets you and congratulates you on your acceptance."); + print2("You are now enrolled in the Collegium Magii!"); + morewait(); + print1("You are now a Novice."); + print2("You may research 1 spell, for your intro class."); + Spellsleft = 1; + Player.rank[COLLEGE] = INITIATE; + Player.guildxp[COLLEGE] = 1; + Player.maxiq += 1; + Player.iq += 1; + Player.maxpow += 1; + Player.pow += 1; + } + } + } + else if (action == 'b') { + if (Player.rank[COLLEGE] == 0) + print2("You have not even been initiated, yet!"); + else if (Player.rank[COLLEGE]==ARCHMAGE) + print2("You are at the pinnacle of mastery in the Collegium."); + else if (Player.rank[COLLEGE]==MAGE) { + if (Player.level <= Archmagelevel) + print2("You are not experienced enough to advance."); + else + print2("You must return with the heart of the Eater of Magic!"); + } + else if (Player.rank[COLLEGE]==PRECEPTOR) { + if (Player.guildxp[COLLEGE] < 4000) + print2("You are not experienced enough to advance."); + else { + print1("You are now a Mage of the Collegium Magii!"); + print2("You may research 6 spells for postdoctoral research."); + Spellsleft += 6; + morewait(); + print1("To become Archmage, you must return with the"); + print2("heart of the Eater of Magic"); + morewait(); + clearmsg(); + print1("The Eater may be found on a desert isle somewhere."); + Player.rank[COLLEGE] = MAGE; + Player.maxiq += 2; + Player.iq += 2; + Player.maxpow += 2; + Player.pow += 2; + } + } + else if (Player.rank[COLLEGE]==STUDENT) { + if (Player.guildxp[COLLEGE] < 1500) + print2("You are not experienced enough to advance."); + else { + print1("You are now a Preceptor of the Collegium Magii!"); + print2("You are taught the basics of ritual magic."); + morewait(); + clearmsg(); + print1("Your position allows you to research 4 spells."); + Spellsleft +=4; + Spells[S_RITUAL].known = true; + Player.rank[COLLEGE] = PRECEPTOR; + Player.maxiq += 1; + Player.iq += 1; + Player.maxpow += 1; + Player.pow += 1; + } + } + else if (Player.rank[COLLEGE]==NOVICE) { + if (Player.guildxp[COLLEGE] < 400) + print2("You are not experienced enough to advance."); + else { + print1("You are now a Student at the Collegium Magii!"); + print2("You are taught the spell of identification."); + morewait(); + clearmsg(); + print1("Thesis research credit is 2 spells."); + Spellsleft+=2; + Spells[S_IDENTIFY].known = true; + Player.rank[COLLEGE] = STUDENT; + Player.maxiq += 1; + Player.iq += 1; + Player.maxpow += 1; + Player.pow += 1; + } + } + } + else if (action == 'c') { + clearmsg(); + if (Spellsleft > 0) { + print1("Research permitted: "); + mnumprint(Spellsleft); + nprint1(" Spells."); + morewait(); + } + if (Spellsleft < 1) { + print1("Extracurricular Lab fee: 2000 Au. "); + nprint1("Pay it? [yn] "); + if (ynq1()=='y') { + if (Player.cash < 2000) + print1("Try again when you have the cash."); + else { + Player.cash -= 2000; + dataprint(); + Spellsleft = 1; + } + } + } + if (Spellsleft > 0) { + learnspell(0); + Spellsleft--; + } + } + } + } + xredraw(); +} + +void l_monastery(void) +{ + char action; + int done=false,enrolled = false; + + if ( Player.maxpow < 13 && LastFreeYogaDay != Date && YogaSessions < 1 && !nighttime()) { + print1("Strengthen your inner spirit, child. Please accept this offer "); + print2("to sit in our yoga class, free of charge."); + YogaSessions += 1; + LastFreeYogaDay = Date; + morewait(); + clearmsg(); + } + print1("Tholian Monastery of Rampart. Founded 12031, AOF."); + print2("Welcome to our humble hovel."); + if (nighttime()) + print2("The monastery doors are sealed until dawn."); + else { + if( YogaSessions > 0 ) + nprint2(" -- 1 free yoga session"); + while (! done) { + menuclear(); + menuprint("Find your true Course:\n\n"); + menuprint("a: Discover the Way.\n"); + menuprint("b: Meditate on the Path.\n"); + menuprint("c: Meditate on Knowledge.\n"); + menuprint("d: Take an extended Meditation.\n"); + menuprint("e: Sit for a yoga class.\n"); + menuprint("ESCAPE: Re-enter the World.\n"); + showmenu(); + action = mgetc(); + if (action == ESCAPE) { + done = true; + calc_melee(); + } + else if (action == 'a') { + if (Player.rank[MONKS] > 0) + print2("You are already initiated, fellow monk."); + else if (Player.con < 13) + print2("Your body is too fragile to walk the Path, child."); + else if (Player.pow < 13) + print2("Your mind is too fragile to follow the Path, child."); + else if (Player.rank[COLLEGE] > 0) + print2("The Collegium has corrupted your spirit, mage."); + else if (Player.rank[CIRCLE] > 0) + print2("The Circle has corrupted your spirit, sorceror."); + else { + if (Player.pow > 17) { + print2("Your spirit is strong. You may study the Path with us."); + morewait(); + enrolled=true; + } + else { + print1("A substantial cash sacrifice will cleanse your spirit.. "); + print2("Donate all your worldly cash? [yn] "); + if (ynq1() =='y') { + Player.cash = 0; + enrolled = true; + dataprint(); + } + } + if (enrolled) { + print1("Grandmaster "); + nprint1(Grandmaster); + nprint1(" welcomes you to the Brotherhood."); + print2("You are now a Tholian Monk trainee!"); + morewait(); + print2("You may study the Way with us."); + Studiesleft = 1; + Player.rank[MONKS] = MONK_TRAINEE; + Player.guildxp[MONKS] = 1; + Player.maxpow += 1; + Player.pow += 1; + } + } + } + else if (action == 'b') { + if (Player.rank[MONKS] == 0) + print2("You are not yet initiated, child."); + else if (Player.rank[MONKS]==MONK_GRANDMASTER) + print2("Your advancement lies within, Grandmaster."); + else if (Player.rank[MONKS]==MONK_MASTER_TEARS) { + if (Player.level <= Grandmasterlevel) + print2("Seek more experience, Master."); + else if ((Player.rank[MONKS]==MONK_MASTER_TEARS) && + (Player.level > Grandmasterlevel) && + find_and_remove_item(CORPSEID,EATER)) + { + print1("You brought back the heart of the Eater of Magic!"); + morewait(); + print1("The Heart is sent to be placed in the kitchen cauldron."); + print2("The Grandmaster steps down. You are the new Grandmaster."); + morewait(); + clearmsg(); + strcpy(Grandmaster,Player.name); + Grandmasterlevel = Player.level; + Player.rank[MONKS] = MONK_GRANDMASTER; + Player.maxhp += (Player.maxpow * 3); + Player.maxiq += 5; + Player.iq+= 5; + Player.maxpow += 3; + Player.pow += 3; + Player.maxstr += 3; + Player.str += 3; + morewait(); + Grandmasterbehavior = fixnpc(4); + save_hiscore_npc(16); + } + else + print2("You must return with the heart of the Eater of Magic!"); + + } + else if (Player.rank[MONKS]==MONK_MASTER_PAINS) { + if (Player.guildxp[MONKS] < 40000) + print2("Seek more experience, Master."); + else { + print1("You have travelled far, Master."); + print2("You are now Master of Tears."); + Studiesleft += 6; + morewait(); + print1("To become Grandmaster, you must return with the"); + print2("heart of the Eater of Magic"); + morewait(); + clearmsg(); + print1("The Eater may be found on a desert isle somewhere."); + Spells[S_REGENERATE].known = true; + Player.rank[MONKS] = MONK_MASTER_TEARS; + Player.maxhp += (Player.maxpow * 2); + Player.maxpow += 2; + Player.pow += 2; + Player.maxstr += 2; + Player.str += 2; + Player.maxagi += 2; + Player.agi += 2; + } + } + else if (Player.rank[MONKS]==MONK_MASTER_SIGHS) { + if (Player.guildxp[MONKS] < 15000) + print2("Seek more experience, Master."); + else { + print1("The Path is long, Master."); + print2("You are now Master of Pain."); + morewait(); + print1("You feel enlightened."); + morewait(); + clearmsg(); + Studiesleft +=4; + Spells[S_RITUAL].known = true; + Spells[S_RESTORE].known = true; + Player.status[ILLUMINATION] = 1500; /* enlightened */ + Player.rank[MONKS] = MONK_MASTER_PAINS; + Player.maxhp += Player.maxpow; + Player.maxcon += 1; + Player.con += 1; + Player.maxdex += 2; + Player.dex += 2; + } + } + else if (Player.rank[MONKS]==MONK_MASTER) { + if (Player.guildxp[MONKS] < 9000) + print2("Seek more experience, Master."); + else { + print1("Drink, weary Master."); + print2("You are now Master of Sighs."); + morewait(); + clearmsg(); + Studiesleft +=2; + Spells[S_HASTE].known = true; + Player.rank[MONKS] = MONK_MASTER_SIGHS; + Player.maxhp += Player.maxpow; + Player.maxcon += 1; + Player.con += 1; + Player.maxiq += 2; + Player.iq += 2; + } + } + else if (Player.rank[MONKS]==MONK_MONK) { + if (Player.guildxp[MONKS] < 3000) + print2("Seek more experience, Brother."); + else { + print1("A thousand steps on the path, Master."); + print2("You are now a Master monk."); + morewait(); + clearmsg(); + Studiesleft +=2; + Spells[S_HEAL].known = true; + Player.rank[MONKS] = MONK_MASTER; + Player.maxhp += Player.maxpow; + Player.maxcon += 1; + Player.con += 1; + Player.maxpow += 2; + Player.pow += 5; /* [sic] */ + } + } + else if (Player.rank[MONKS]==MONK_TRAINEE) { + if (Player.guildxp[MONKS] < 1500) + print2("Seek more experience, Brother."); + else { + print1("You have sought wisdom, Brother."); + print2("You are now a Tholian Monk."); + morewait(); + clearmsg(); + Studiesleft +=2; + Spells[S_CURE].known = true; + Player.rank[MONKS] = MONK_MONK; + Player.maxhp += Player.maxpow; + Player.maxcon += 1; + Player.con += 1; + Player.maxpow += 1; + Player.pow += 1; + } + } + } + else if (action == 'c') { + clearmsg(); + if (Studiesleft > 0) { + print1("Studies permitted: "); + mnumprint(Studiesleft); + nprint1(" Studies."); + morewait(); + } + if (Studiesleft < 1) { + print1("Sacrifice clears a cluttered heart. "); + nprint1("Donate your worldly cash? [yn] "); + if (ynq1()=='y') { + if (Player.cash < 2000) + { + if ( Player.rank[MONKS] >= MONK_GRANDMASTER ) + print2("You have not much to give, Grandmaster."); + else if ( Player.rank[MONKS] >= MONK_MASTER ) + print2("You have not much to give, Master."); + else + print2("You have not much to give, Brother."); + } + else { + Player.cash = 0; + dataprint(); + Studiesleft = 1; + } + } + } + if (Studiesleft > 0) { + learnspell(0); + Studiesleft--; + } + } + else if (action == 'd') { + if (Player.rank[MONKS] < MONK_MASTER) { + clearmsg(); + print1("Only Masters can achieve extended meditation, child."); + print2(" "); + } + else { + int i = 0; + clearmsg(); + print1("Seeking inner truth..."); + morewait(); + clearmsg(); + morewait(); + toggle_item_use(true); + Player.cash = 0; + Player.hp = Player.maxhp; + Player.str = Player.maxstr; + Player.agi = Player.maxagi; + Player.con = Player.maxcon; + Player.dex = Player.maxdex; + Player.iq = Player.maxiq; + Player.pow = Player.maxpow; + for (i=0; i 0 ) + print1("Use your credit to take a class? [yn] "); + else + print1("Yoga class requires a 2000 Au donation. Pay the fee? [yn] "); + if (ynq1()=='y') { + if (Player.cash < 2000 && YogaSessions < 1) { + if ( Player.rank[MONKS] >= MONK_GRANDMASTER ) + print2("You have not much to give, Grandmaster."); + else if ( Player.rank[MONKS] >= MONK_MASTER ) + print2("You have not much to give, Master."); + else if (Player.rank[MONKS] <= MONK_MONK) + print2("You have not much to give, Brother."); + else + print2("You have not much to give, child."); + } + else { + if( YogaSessions > 0 ) + YogaSessions--; + else + Player.cash -= 2000; + print1( "You are ushered into the meditation room." ); + + int trained = 0; + /* minimum 20% chance at pow >= 22 */ + if ( Player.maxpow >= 22 && Player.maxpow < 30 && random_range ( 10 ) < 2 ) + trained++; + + /* 10% lower chance per level after 13 maxpow */ + else if ( Player.maxpow < 22 && random_range( 10 ) < (10 - (Player.maxpow - 12))) + trained++; + + else { + print2("You emerge exhausted and dripping sweat!"); + if( Player.pow < Player.maxpow ) + Player.pow++; + } + + if ( trained ) { + Player.maxpow++; + Player.pow++; + print2( "The yoga instructor stretches your physical and spiritual limits!" ); + } + dataprint(); + } + } + } + } + } + } + xredraw(); +} + +void l_sorcerors(void) +{ + char action; + int done=false,fee; + long total; + print1("The Circle of Sorcerors."); + if (Player.rank[CIRCLE] == -1) { + print2("Fool! Didn't we tell you to go away?"); + Player.mana = 0; + dataprint(); + } + else while (! done) { + if ((Player.rank[CIRCLE]==HIGHSORCEROR) && + (Player.level > Primelevel) && + find_and_remove_item(CORPSEID,LAWBRINGER)) { + print2("You obtained the Crown of the Lawgiver!"); + morewait(); + print1("The Crown is ritually sacrificed to the Lords of Chaos."); + print2("You are now the Prime Sorceror of the Inner Circle!"); + strcpy(Prime,Player.name); + Primelevel = Player.level; + morewait(); + Primebehavior = fixnpc(4); + save_hiscore_npc(10); + clearmsg(); + print1("You learn the Spell of Disintegration!"); + morewait(); + clearmsg(); + Spells[S_DISINTEGRATE].known = true; + Player.rank[CIRCLE] = PRIME; + Player.maxpow += 10; + Player.pow += 10; + } + menuclear(); + menuprint("May we help you?\n\n"); + menuprint("a: Become an Initiate of the Circle.\n"); + menuprint("b: Raise your rank in the Circle.\n"); + menuprint("c: Restore mana points\n"); + menuprint("ESCAPE: Leave these Chambers of Power.\n"); + showmenu(); + action = mgetc(); + if (action == ESCAPE) done = true; + else if (action == 'a') { + if (Player.rank[CIRCLE] > 0) + print2("You are already an initiate!"); + else if (Player.alignment > 0) + print2("You may not join -- you reek of Law!"); + else if (Player.rank[COLLEGE] > 0) + print2("Foolish Mage! You don't have the right attitude to Power!"); + else if (Player.rank[MONKS] > 0) + print2("Stupid monk. Go meditate on this!"); + else { + fee = 3000; + fee += Player.alignment*100; + fee += fee*(12 - Player.pow)/9; + fee = max(100,fee); + clearmsg(); + mprint("For you, there is an initiation fee of"); + mnumprint(fee); + mprint(" Au."); + print2("Pay it? [yn] "); + if (ynq2() =='y') { + if (Player.cash < fee) + print3("Try again when you have the cash!"); + else { + print1("Prime Sorceror "); + nprint1(Prime); + print2("conducts your initiation into the circle of novices."); + morewait(); + clearmsg(); + print1("You learn the Spell of Magic Missiles."); + Spells[S_MISSILE].known = true; + Player.cash -= fee; + dataprint(); + Player.rank[CIRCLE] = INITIATE; + Player.guildxp[CIRCLE] = 1; + Player.maxpow++; + Player.pow++; + } + } + } + } + else if (action == 'b') { + if (Player.rank[CIRCLE] == 0) + print2("You have not even been initiated, yet!"); + else if (Player.alignment > -1) { + print1("Ahh! You have grown too lawful!!!"); + print2("You are hereby blackballed from the Circle!"); + Player.rank[CIRCLE] = -1; + morewait(); + clearmsg(); + print1("A pox upon thee!"); + if (! Player.immunity[INFECTION]) + Player.status[DISEASED]+=100; + print2("And a curse on your possessions!"); + morewait(); + clearmsg(); + acquire(-1); + clearmsg(); + enchant(-1); + bless(-1); + print3("Die, false sorceror!"); + p_damage(25,UNSTOPPABLE,"a sorceror's curse"); + done = true; + } + else if (Player.rank[CIRCLE]==PRIME) + print2("You are at the pinnacle of mastery in the Circle."); + else if (Player.rank[CIRCLE]==HIGHSORCEROR) { + if (Player.level <= Primelevel) + print2("You are not experienced enough to advance."); + else + print2("You must return with the Crown of the LawBringer!"); + } + else if (Player.rank[CIRCLE]==SORCEROR) { + if (Player.guildxp[CIRCLE] < 4000) + print2("You are not experienced enough to advance."); + else { + print1("You are now a High Sorceror of the Inner Circle!"); + print2("You learn the Spell of Disruption!"); + morewait(); + clearmsg(); + print1("To advance you must return with the LawBringer's Crown!"); + print2("The LawBringer resides on Star Peak."); + Spells[S_DISRUPT].known = true; + Player.rank[CIRCLE] = HIGHSORCEROR; + Player.maxpow += 5; + Player.pow += 5; + } + } + else if (Player.rank[CIRCLE]==ENCHANTER) { + if (Player.guildxp[CIRCLE] < 1500) + print2("You are not experienced enough to advance."); + else { + print1("You are now a member of the Circle of Sorcerors!"); + print2("You learn the Spell of Ball Lightning!"); + Spells[S_LBALL].known = true; + Player.rank[CIRCLE] = SORCEROR; + Player.maxpow += 2; + Player.pow+=2; + } + } + else if (Player.rank[CIRCLE]==INITIATE) { + if (Player.guildxp[CIRCLE] < 400) + print2("You are not experienced enough to advance."); + else { + print1("You are now a member of the Circle of Enchanters!"); + print2("You learn the Spell of Firebolts."); + Spells[S_FIREBOLT].known = true; + Player.rank[CIRCLE] = ENCHANTER; + Player.maxpow+=2; + Player.pow+=2; + } + } + } + else if (action == 'c') { + done = true; + fee = Player.level*100; + if (Player.rank[CIRCLE]) fee = fee / 2; + clearmsg(); + print1("That will be: "); + mnumprint(fee); + nprint1("Au. Pay it? [yn] "); + if (ynq1()=='y') { + if (Player.cash < fee) + print2("Begone, deadbeat, or face the wrath of the Circle!"); + else { + Player.cash -= fee; + total = calcmana(); + while (Player.mana < total) { + Player.mana++; + dataprint(); + } + print2("Have a sorcerous day, now!"); + } + } + else print2("Be seeing you!"); + } + } + xredraw(); +} + + + + +void l_order(void) +{ + Object* newitem; + MonsterList* ml; + print1("The Headquarters of the Order of Paladins."); + morewait(); + if ((Player.rank[ORDER]==PALADIN) && + (Player.level > Justiciarlevel) && + State.getGivenStargem() && + Player.alignment > 300) { + print1("You have succeeded in your quest!"); + morewait(); + print1("The previous Justiciar steps down in your favor."); + print2("You are now the Justiciar of Rampart and the Order!"); + strcpy(Justiciar,Player.name); + for (ml = Level->mlist; ml && (ml->monster->id != HISCORE_NPC || + ml->monster->aux2 != 15); ml = ml->next) + /* just scan for current Justicar */; + if (ml) { + ml->monster->m_remove(); /* signals "death" -- no credit to player, though */ + } + Justiciarlevel = Player.level; + morewait(); + Justiciarbehavior = fixnpc(4); + save_hiscore_npc(15); + clearmsg(); + print1("You are awarded a blessed shield of deflection!"); + morewait(); + newitem = ((Object*) checkmalloc(sizeof(Object))); + *newitem = Objects[OB_DEFLECT]; /* shield of deflection */ + newitem->blessing = 9; + gain_item(newitem); + morewait(); + Player.rank[ORDER] = JUSTICIAR; + Player.maxstr += 5; + Player.str += 5; + Player.maxpow += 5; + Player.pow += 5; + } + if (Player.alignment < 1) { + if (Player.rank[ORDER] > 0) { + print1("You have been tainted by chaos!"); + print2("You are stripped of your rank in the Order!"); + morewait(); + Player.rank[ORDER]= -1; + send_to_jail(); + } + else + print1("Get thee hence, minion of chaos!"); + } + else if (Player.rank[ORDER] == -1) + print1("Thou again? Get thee hence, minion of chaos!"); + else if (Player.rank[ORDER] == 0) { + if (Player.rank[ARENA] != 0) + print1("We do not accept bloodstained gladiators into our Order."); + else if (Player.rank[LEGION] != 0) + print1("Go back to your barracks, mercenary!"); + else { + print1("Dost thou wish to join our Order? [yn] "); + if (ynq1()=='y') { + print1("Justiciar "); + nprint1(Justiciar); + nprint1(" welcomes you to the Order."); + print2("'Mayest thou always follow the sublime path of Law.'"); + morewait(); + print1("You are now a Gallant in the Order."); + print2("You are given a horse and a blessed spear."); + morewait(); + Player.rank[ORDER] = GALLANT; + Player.guildxp[ORDER] = 1; + State.setMounted( true ); + newitem = ((Object*) checkmalloc(sizeof(Object))); + *newitem = Objects[OB_SPEAR]; /* spear */ + newitem->blessing = 9; + newitem->plus = 1; + newitem->known = 2; + gain_item(newitem); + } + } + } else { + print1("'Welcome back, Paladin.'"); + if (!State.getMounted()) { + print2("You are given a new steed."); + State.setMounted( true ); + } + morewait(); + clearmsg(); + if ((Player.hp < Player.maxhp) || (Player.status[DISEASED]) || + (Player.status[POISONED])) + print1("Your wounds are treated by a medic."); + cleanse(0); + Player.hp = Player.maxhp; + if ( Player.food <= 40 ) + { + Player.food = 40; + print2("You get a hot meal from the refectory."); + } + morewait(); + clearmsg(); + if (Player.rank[ORDER]==PALADIN) { + if (Player.level <= Justiciarlevel) + print2("You are not experienced enough to advance."); + else if (Player.alignment < 300) + print2("You are not sufficiently Lawful as yet to advance."); + else print2("You must give the Star Gem to the LawBringer."); + } + else if (Player.rank[ORDER]==CHEVALIER) { + if (Player.guildxp[ORDER] < 4000) + print2("You are not experienced enough to advance."); + else if (Player.alignment < 200) + print2("You are not sufficiently Lawful as yet to advance."); + else { + print1("You are made a Paladin of the Order!"); + print2("You learn the Spell of Heroism and get Mithril Plate!"); + morewait(); + newitem = ((Object*) checkmalloc(sizeof(Object))); + *newitem = Objects[OB_MITHRIL_PLATE]; /* mithril plate armor */ + newitem->blessing = 9; + newitem->known = 2; + gain_item(newitem); + morewait(); + clearmsg(); + print1("To advance you must rescue the Star Gem and return it"); + print2("to its owner, the LawBringer, who resides on Star Peak."); + morewait(); + print1("The Star Gem was stolen by the cursed Prime Sorceror,"); + print2("whose headquarters may be found beyond the Astral Plane."); + morewait(); + print1("The Oracle will send you to the Astral Plane if you"); + print2("prove yourself worthy to her."); + morewait(); + Spells[S_HERO].known = true; + Player.rank[ORDER] = PALADIN; + } + } + else if (Player.rank[ORDER]==GUARDIAN) { + if (Player.guildxp[ORDER] < 1500) + print2("You are not experienced enough to advance."); + else if (Player.alignment < 125) + print2("You are not yet sufficiently Lawful to advance."); + else { + Player.rank[ORDER] = CHEVALIER; + print1("You are made a Chevalier of the Order!"); + print2("You are given a Mace of Disruption!"); + morewait(); + clearmsg(); + newitem = ((Object*) checkmalloc(sizeof(Object))); + *newitem = Objects[OB_MACE_DISRUPT]; /* mace of disruption */ + newitem->known = 2; + gain_item(newitem); + } + } + else if (Player.rank[ORDER]==GALLANT) { + if (Player.guildxp[ORDER] < 400) + print2("You are not experienced enough to advance."); + else if (Player.alignment < 50) + print2("You are not Lawful enough to advance."); + else { + print1("You are made a Guardian of the Order of Paladins!"); + print2("You are given a Holy Hand Grenade (of Antioch)."); + morewait(); + print1("You hear a nasal monotone in the distance...."); + print2("'...and the number of thy counting shall be 3...'"); + morewait(); + clearmsg(); + Player.rank[ORDER] = GUARDIAN; + newitem = ((Object*) checkmalloc(sizeof(Object))); + *newitem = Objects[OB_ANTIOCH]; /* holy hand grenade. */ + newitem->known = 2; + gain_item(newitem); + } + } + } + showflags(); +} diff --git a/Omega/src/inv.cpp b/Omega/src/inv.cpp index 11d14f9..e31bc5f 100644 --- a/Omega/src/inv.cpp +++ b/Omega/src/inv.cpp @@ -1,1748 +1,1751 @@ -/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ -/* inv.c */ -/* functions having to do with player item inventory */ - -#include "glob.h" - -static void inv_display_munge(void); -static void inv_display_refresh(void); - -/* drops money, heh heh */ -void drop_money(void) -{ - Object* money; - - money = detach_money(0); - if (money != NULL) { - if (Current_Environment == E_CITY) { - print1("As soon as the money leaves your hand,"); - print2("a horde of scrofulous beggars snatch it up and are gone!"); - free( money ); - } - else drop_at(Player.x,Player.y,money); - } - else State.setSkipMonsters(); -} - - -/* returns some money from player back into "money" item. - for giving and dropping money */ -Object* detach_money(long howmuch) -/* if howmuch == 0, ask the player. otherwise, just get howmuch. */ -{ - long c; - Object* cash=NULL; - if ( howmuch == 0 ) - c = get_money(Player.cash); - else - c = howmuch; - if (c != ABORT) { - Player.cash -= c; - cash = ((Object*) checkmalloc(sizeof(Object))); - make_cash(cash,difficulty()); - cash->basevalue = c; - } - return(cash); -} - - -/* gets a legal amount of money or ABORT */ -long get_money(long limit) -{ - long c; - c = parsenum("How much money? "); - if (c > limit) { - print3("Forget it, buddy."); - return(ABORT); - } - else return(c); -} - - - -/* pick up from some location x,y */ -/* Lift entire itemlist off ground, pass it to inventory control, which - may drop things back onto the now null ground */ -void pickup_at (int x, int y) -{ - char response; - - pol ol; - pol temp; - - State.setFastMove(false); - - ol = Level->site[x][y].things; - Level->site[x][y].things = 0; - - while (ol != 0) - { - clearmsg1(); - response = cinema_ynq(strjoin("Pick up? [ynq]: ", itemid(ol->thing))); - if ('q' == response) - break; - - if (response == 'y') - gain_item(ol->thing); - else - drop_at(x,y,ol->thing); - - temp = ol; - ol = ol->next; - temp->next = 0; - temp->thing = 0; - free(temp); - } - - while (ol != 0) - { - temp = ol; - ol = ol->next; - temp->next = 0; - temp->thing = 0; - free(temp); - } -} - -/* WDT -- convert from a char (keypress) to an item index in - * player inventory */ -/* Item identifiers, in this case the letters of the alphabet minus - * any letters already used for commands. Yes, there are more here - * than could be needed, but I don't want to short myself for later. - */ -signed char inventory_keymap[] = "-abcfghimnoqruvwyz"; -int key_to_index(signed char key) -{ - int i; - assert( MAXITEMS>0 ); /* must have room for an item, or this loop will - * die! */ - - for (i=0; iobjchar != ARMOR) { - ok = false; - } - } - else if (slot == O_SHIELD) { - if (o->objchar != SHIELD) { - ok = false; - } - } - else if (slot == O_BOOTS) { - if (o->objchar != BOOTS) { - ok = false; - } - } - else if (slot == O_CLOAK) { - if (o->objchar != CLOAK) { - ok = false; - } - } - else if (slot >= O_RING1) { - if (o->objchar != RING) { - ok = false; - } - } - return(ok); -} - -/* put all of o on objlist at x,y on Level->depth */ -/* Not necessarily dropped by character; just dropped... */ -void drop_at(int x, int y, Object* o) -{ - pol tmp; - Object* cpy; - - if (Current_Environment != E_COUNTRYSIDE) { - if ((Level->site[x][y].locchar != VOID_CHAR) && - (Level->site[x][y].locchar != ABYSS)) { - cpy = copy_obj( o ); - tmp = ((pol) checkmalloc(sizeof(oltype))); - cpy->used = false; - tmp->thing = cpy; - tmp->next = Level->site[x][y].things; - Level->site[x][y].things = tmp; - } - else if (Level->site[x][y].p_locf == L_VOID_STATION) - State.setPreparedVoid(); - } -} - -/* put n of o on objlist at x,y on Level->depth */ -void p_drop_at(int x, int y, int n, Object* o) -{ - pol tmp; - if (Current_Environment != E_COUNTRYSIDE) { - if ((Level->site[x][y].locchar != VOID_CHAR) && - (Level->site[x][y].locchar != ABYSS)) { - tmp = ((pol) checkmalloc(sizeof(oltype))); - tmp->thing = copy_obj( o ); - tmp->thing->used = false; - tmp->thing->number = n; - print2("Dropped "); - nprint2(itemid(tmp->thing)); - morewait(); - tmp->next = Level->site[x][y].things; - Level->site[x][y].things = tmp; - } - else if (Level->site[x][y].p_locf == L_VOID_STATION) - State.setPreparedVoid(); - } -} - - -/* returns a string for identified items */ -char *itemid(Object* obj) -{ - char tstr[80]; - if (obj->objchar==CASH) { - strcpy(Str4,obj->truename); - return(Str4); - } - else { - if (Objects[obj->id].known > obj->known) - obj->known = Objects[obj->id].known; - - setnumstr(obj,tstr); - strcpy(Str4,tstr); - if (obj->known == 0) - strcat(Str4,obj->objstr); - else if (obj->known == 1) { - if (obj->id == OB_YENDOR || obj->id == OB_KARNAK || - obj->id == OB_STARGEM ) - strcat(Str4, "the "); - strcat(Str4,obj->truename); - } - else { - if (obj->id == OB_YENDOR || obj->id == OB_KARNAK || - obj->id == OB_STARGEM ) - strcat(Str4, "the "); - if (obj->usef == I_NOTHING && Objects[obj->id].usef != I_NOTHING) - strcat(Str4, "disenchanted "); - if (obj->isCursed()) { - strcat(Str4, "cursed "); - strcat(Str4, obj->cursestr); - } - else if (obj->blessing > 0) { - strcat(Str4, "blessed "); - strcat(Str4, obj->truename); - } - else strcat(Str4,obj->truename); - if (obj->number > 1) strcat(Str4,"s"); - switch (obj->objchar) { - case STICK: - setchargestr(obj,tstr); - strcat(Str4,tstr); - break; - case MISSILEWEAPON: - case ARMOR: - case RING: - case SHIELD: - case WEAPON: - setplustr(obj,tstr); - strcat(Str4, tstr); - break; - default: - strcat(Str4,""); - break; - } - } - return(Str4); - } -} - -char *cashstr(void) -{ - if (difficulty() < 3) return("copper pieces"); - else if (difficulty() < 5) return("silver pieces"); - else if (difficulty() < 7) return("gold pieces"); - else if (difficulty() < 8) return("semiprecious gems"); - else if (difficulty() < 9) return("mithril pieces"); - else if (difficulty() < 10) return("precious gems"); - else return("orichalc pieces"); -} - -/* return an object's plus as a string */ -void setplustr(Object* obj, char *pstr) -{ - pstr[0] = ' '; - pstr[1] = (obj->plus < 0 ? '-' : '+' ); - if (abs(obj->plus) < 10) { - pstr[2] = '0' + abs(obj->plus); - pstr[3] = 0; - } - else { - pstr[2] = '0' + abs(obj->plus / 10); - pstr[3] = '0' + abs(obj->plus % 10); - pstr[4] = 0; - } -} - -/* return an object's number as a string */ -void setnumstr(Object* obj, char *nstr) -{ - if (obj->number < 2) - nstr[0] = 0; - else if (obj->number < 10) { - nstr[0] = '0' + obj->number; - nstr[1] = 'x'; - nstr[2] = ' '; - nstr[3] = 0; - } - else if (obj->number < 41) { - nstr[0] = '0' + ((int)(obj->number / 10)); - nstr[1] = '0' + (obj->number % 10); - nstr[2] = 'x'; - nstr[3] = ' '; - nstr[4] = 0; - } - else strcpy(nstr,"lots of "); -} - - -/* return object with charges */ -void setchargestr(Object* obj, char *cstr) -{ - cstr[0] = ' '; - cstr[1] = '['; - if (obj->charge < 0) { - cstr[2]='d'; - cstr[3]='e'; - cstr[4]='a'; - cstr[5]='d'; - cstr[6]=']'; - cstr[7]=0; - } - else if (obj->charge < 10) { - cstr[2] = '0' + obj->charge; - cstr[3] = ']'; - cstr[4] = 0; - } - else { - cstr[2] = '0' + ((int)(obj->charge / 10)); - cstr[3] = '0' + (obj->charge % 10); - cstr[4] = ']'; - cstr[5] = 0; - } -} - - -void give_money(Monster *m) -{ - Object* cash; - - cash = detach_money(0); - if (cash == NULL) - State.setSkipMonsters(); - else givemonster(m,cash); -} - - -void lawbringer_gets_gem(Monster* m, Object* o) -{ - clearmsg(); - print1("The LawBringer accepts the gem reverently."); - print2("He raises it above his head, where it bursts into lambent flame!"); - morewait(); - print1("You are bathed in a shimmering golden light."); - print2("You feel embedded in an infinite matrix of ordered energy."); - morewait(); - if (Imprisonment > 0) - Imprisonment = 0; - if (Player.rank[ORDER] == -1) { - print2("You have been forgiven. You feel like a Paladin...."); - Player.rank[ORDER] = 1; - } - Player.alignment += 200; - Player.pow = Player.maxpow = Player.pow * 2; - gain_experience(2000); - State.setGivenStargem(); - /* WDT HACK!!! Where else would this ever get freed?? */ - free_obj(o, true); -} - -void givemonster(Monster* m, Object* o) -{ - /* special case -- give gem to LawBringer */ - if ((m->id == LAWBRINGER) && (o->id == OB_STARGEM)) - lawbringer_gets_gem(m,o); - else { - if (m->uniqueness == COMMON) { - strcpy(Str3,"The "); - strcat(Str3,m->name); - } - else strcpy(Str3,m->name); - - if (m_statusp(m,GREEDY) || m_statusp(m,NEEDY)) { - m->m_pickup(o); - strcat(Str3," takes your gift"); - print1(Str3); - Player.alignment++; - if (m_statusp(m,GREEDY) && (true_item_value(o) < (long) m->level*100)) - nprint1("...but does not appear satisfied."); - else if (m_statusp(m,NEEDY) && - (true_item_value(o) < (long) Level->depth*Level->depth)) - nprint1("...and looks chasteningly at you."); - else { - nprint1("...and seems happy with it."); - m_status_reset(m,HOSTILE); - m_status_reset(m,GREEDY); - m_status_reset(m,NEEDY); - } - } - else if (m_statusp(m,HUNGRY)) { - - if (((m->id == HORSE) && (o->id == OB_GRAIN)) || /* grain */ - ((m->id != HORSE) && - ((o->usef == I_FOOD) || (o->usef == I_POISON_FOOD)))) { - strcat(Str3," wolfs down your food ... "); - print1(Str3); - m_status_reset(m,HUNGRY); - m_status_reset(m,HOSTILE); - if (o->usef == I_POISON_FOOD) { - Player.alignment -= 2; - nprint1("...and chokes on the poisoned ration!"); - morewait(); - m_status_set(m,HOSTILE); - m->m_damage(100,POISON); - } - else nprint1("...and now seems satiated."); - morewait(); - free_obj(o, true); - } - else { - strcat(Str3," spurns your offering and leaves it on the ground."); - print1(Str3); - drop_at(m->x,m->y,o); - } - } - else { - strcat(Str3," doesn't care for your offering and drops it."); - print1(Str3); - drop_at(m->x,m->y,o); - } - } -} - - - -/* will clear all, not just one of an object. */ -void conform_lost_object(Object* obj) -{ - if (obj != NULL) conform_lost_objects(obj->number,obj); -} - - - -/* removes n of object from inventory; frees object if appropriate. */ - -void dispose_lost_objects(int n, Object* obj) -{ - int i,conformed=false,subtracted=false; - - if (obj == NULL) - return; - for(i=0; inumber -= n; - subtracted = true; - } - if (obj->number < 1) { - if (!conformed) { - conform_unused_object(obj); - conformed = true; - } - Player.possessions[i] = NULL; - } - } - if (obj->number < 1) - free_obj( obj, true ); -} - - -/* removes n of object from inventory without freeing object. - Removes all instances of pointer (might be 2 handed weapon, etc) */ -void conform_lost_objects(int n, Object* obj) -{ - int i,conformed=false,subtracted=false; - if (obj != NULL) for(i=0; inumber -= n; - subtracted = true; - } - if (obj->number < 1) { - if (!conformed) { - conform_unused_object(obj); - conformed = true; - } - Player.possessions[i] = NULL; - } - } -} - - -/* clears unused possession */ -void conform_unused_object(Object* obj) -{ - if (obj->used) { - obj->used = false; - item_use(obj); - inv_display_munge(); - } - calc_melee(); -} - - -/* select an item from inventory */ -/* if itype is NULL_ITEM, any kind of item is acceptable. - if itype is CASH, any kind of item or '$' (cash) is acceptable. - if itype is FOOD, CORPSE or FOOD is acceptable, but only FOOD is -listed in the possibilities. - if itype is any other object type (eg SCROLL, POTION, etc.), only -that type of item is acceptable or is listed */ - -int item_is_selectable (Symbol itype, Object* item) -{ - if (!item) return false; - - if (CASH == itype) return true; - if (NULL_ITEM == itype) return true; - if (item->objchar == itype) return true; - if (FOOD == itype && CORPSE == item->objchar) return true; - - return false; -} - -int getitem (Symbol itype) -{ - return getitem_prompt(0, itype); -} - -int getitem_prompt (char * prompt, Symbol itype) -{ - char key; - char *line3; - char invstr[64]; - char selectstr[80]; - int i, k; - int again; - int found = false; - int drewmenu = false; - - found = ((itype == NULL_ITEM) || ((itype == CASH) && (Player.cash > 0))); - - /* build invstr, which lists all valid selections that the user can make */ - invstr[0] = 0; - - k = 0; - for(i = 1; i < MAXITEMS; ++i) - { - if (item_is_selectable(itype, Player.possessions[i])) - { - found = true; - invstr[k++] = index_to_key(i); - invstr[k] = 0; - } - } - - if (!found) - { - print3("Nothing appropriate."); - return ABORT; - } - - if (itype == CASH) - { - invstr[k++] = CASH & 0xff; - invstr[k] = 0; - } - - /* gotta let the user see what everything means... */ - invstr[k++] = '?'; - invstr[k] = 0; - - line3 = NULL; - - /* build prompt... */ - selectstr[0] = 0; - if (prompt) strcpy(selectstr, prompt); - strcat(selectstr, "Select an item. ("); - - i = 0; - k = strlen(selectstr); - while (true) - { - if ('?' == invstr[i]) break; - selectstr[k++] = invstr[i++]; - selectstr[k++] = ','; - if (k > 75) break; - } - - selectstr[k-1] = ')'; - selectstr[k] = 0; - - /* get input from the user */ - do - { - again = false; - - key = cinema_interact(invstr, selectstr, " ? to display items", line3); - line3 = NULL; - - if ('?' == key) - { - again = true; - drewmenu = true; - for (i = 1; i < MAXITEMS; ++i) - { - if (item_is_selectable(itype, Player.possessions[i])) - display_inventory_slot(i, false); - } - } - else if ((CASH & 0xff) == key && (CASH != itype)) - { - again = true; - line3 = "You cannot select cash now."; - } - } - while (again); - - if (drewmenu) xredraw(); - if (-1 == key) return ABORT; /* cinema_interact() returns -1 for ESC */ - if ((CASH & 0xff) == key) return CASHVALUE; - - return key_to_index(key); -} - -/* true if the numerical index based on 'a' == 1 turns out to be either -out of the range of the possessions array or a null item */ -int badobject(char slotchar) -{ - int slot = slotchar + 1 - 'a'; - if ((slot<1) || (slot >= MAXITEMS)) return(true); - else return(Player.possessions[slot] == NULL); -} - -#if !defined(WIN32) -/* this takes the numerical index directly for the same effect as badobject*/ -int baditem(int slotnum) -{ - if ((slotnum<1) || (slotnum >= MAXITEMS)) return(true); - else return(Player.possessions[slotnum] == NULL); -} -#endif - -/* formerly add_item_to_pack */ -void gain_item(Object* o) -{ - if (o->uniqueness == UNIQUE_MADE) - Objects[o->id].uniqueness = UNIQUE_TAKEN; - if (o->objchar == CASH) { - print2("You gained some cash."); - Player.cash += o->basevalue; - free_obj(o,true); - dataprint(); - } - else if (optionp(PACKADD)) { - if (! get_to_pack(o)) { - Player.possessions[O_UP_IN_AIR] = o; - do_inventory_control(); - } - } - else { - Player.possessions[O_UP_IN_AIR] = o; - do_inventory_control(); - } -} - -/* tosses the item into the pack, making it the first reachable item */ -void push_pack(Object* o) -{ - int i; - for (i = Player.packptr; i > 0; i--) - Player.pack[i] = Player.pack[i-1]; - Player.pack[0] = o; - Player.packptr++; -} - -/* Adds item to pack list */ -void add_to_pack(Object* o) -{ - if (Player.packptr >= MAXPACK) { - print3("Your pack is full. The item drops to the ground."); - drop_at(Player.x,Player.y,o); - } - else { - push_pack(o); - print3("Putting item in pack."); - } -} - -/* Adds item to pack list, maybe going into inventory mode if pack is full */ -int get_to_pack(Object* o) -{ - if (Player.packptr >= MAXPACK) { - print3("Your pack is full."); - morewait(); - return(false); - } - else { - push_pack(o); - print3("Putting item in pack."); - return(true); - } -} - -int pack_item_cost(int index) -{ - int cost; - if (index > 20) { - cost = 17; - } - else if (index > 15) { - cost = 7; - } - else cost = 2; - return cost; -} - -/* WDT -- 'response' must be an index into the pack. */ -void use_pack_item(int response, int slot) -{ - Object* item; - int i; - i = pack_item_cost(response); - if (i > 10) { - cinema_scene("You begin to rummage through your pack.",NULL,NULL); - } - if (i > 5) { - cinema_scene("You search your pack for the item.",NULL,NULL); - } - print3("You take the item from your pack."); - morewait(); - Command_Duration += i; - item = Player.possessions[slot] = Player.pack[response]; - for(i=response; iid)) - { - if (Player.possessions[O_READY_HAND] == NULL) - Player.possessions[O_READY_HAND] = item; - if (Player.possessions[O_WEAPON_HAND] == NULL) - Player.possessions[O_WEAPON_HAND] = item; - } - if (item_useable(item,slot)) { - item->used = true; - item_use(item); - inv_display_munge(); - morewait(); - if (item->number > 1) pack_extra_items(item); - } -} - -/* WDT HACK! This ought to be in scr.c, along with its companion. However, - * right now it's only used in the function directly below. */ -int aux_display_pack(int start_item, int slot) -{ - int i=start_item, items; - char *depth_string; - - menuclear(); -#if 0 - /* WDT: I decided to remove these lines, since the purpose of this routine - * is to generate a pack menu, not update the message line. This is - * especially important now that I'm making the inventory system use the - * new 'Cinema' message box (which will stop the message corruption - * problems that were epidemic). */ - if (Player.packptr < 1) print3("Pack is empty."); - else if (Player.packptr <= start_item) print3("You see the leather at the bottom of the pack."); -#else - /* These cases are not terribly important, but they can happen. */ - if (Player.packptr < 1 || Player.packptr <= start_item) - return start_item; -#endif - else - { - items = 0; - for(i=start_item; i 10) - depth_string = "**"; - else if (pack_item_cost(i) > 5) - depth_string = "* "; - else depth_string = " "; - sprintf(Str1, " %c: %s %s\n", i + 'a', depth_string, - itemid(Player.pack[i])); - if (items == 0) - menuprint("Items in Pack:\n"); - menuprint(Str1); - items++; - } - } - if (items == 0) - menuprint("You see nothing useful for that slot in the pack."); - else { - menuprint("\n*: Takes some time to reach; **: buried very deeply."); - } - showmenu(); - } - return i; -} - -/* takes something from pack, puts to slot, - * or to 'up-in-air', one of which at least must be empty */ -int aux_take_from_pack(int slot) -{ - char response,pack_item, last_item; - int quit = false,ok=true; - if (Player.possessions[slot] != NULL) - slot = O_UP_IN_AIR; - if (Player.possessions[slot] != NULL) - print3("slot is not empty!"); - else if (Player.packptr < 1) - print3("Pack is empty!"); - else { - pack_item = 0; - do { - ok = true; - last_item = aux_display_pack(pack_item,slot); - if (last_item == Player.packptr && pack_item == 0 ) - print1("Enter pack slot letter or ESCAPE to quit."); - else if (last_item == Player.packptr) - print1("Enter pack slot letter, - to go back, or ESCAPE to quit."); - else if (pack_item == 0) - print1("Enter pack slot letter, + to see more, or ESCAPE to quit."); - else - print1("Enter pack slot letter, + or - to see more, or ESCAPE to quit."); - response = mcigetc(); - if (response == '?') { - /* WDT HACK -- display some help instead. */ - print1("Help not implemented (sorry)."); - morewait(); - ok = false; - } - else if (response == ESCAPE) { - quit = true; - clearmsg1(); - } - else if (response == '+') { - if (last_item < Player.packptr) - pack_item = last_item; - ok = false; - } - else if (response == '-') { - /* WDT HACK: this _should_ make us page up. Sadly, - * I have no way of calculating how much I'll be paging up. - * This is fixable, but I have no idea how much work... As - * a hack, I'm just returning to the first page of the listing. - */ - pack_item = 0; - ok = false; - } - else { - ok = ((response >= 'a') && (response < 'a'+Player.packptr)); - if (ok) ok = slottable(Player.pack[response-'a'],slot); - } - } while (! ok); - if (! quit) { - use_pack_item(response - 'a',slot); - } - } - - inv_display_munge(); - - return slot; -} - -/* takes something from pack, puts to slot, -or to 'up-in-air', one of which at least must be empty */ -int aux_top_take_from_pack(int slot, int display) -{ - char response; - int quit = false,ok=true; - - if (Player.possessions[slot] != NULL) - slot = O_UP_IN_AIR; - if (Player.possessions[slot] != NULL) - print3("slot is not empty!"); - else if (Player.packptr == 0) - print3("Pack is empty!"); - else { - do { - ok = true; - print1("Enter pack slot letter, or ? to show pack, or ESCAPE to quit."); - response = mcigetc(); - if (response == '?') { - display_pack(); - inv_display_munge(); - ok = false; - } - else if (response == ESCAPE) { - quit = true; - clearmsg1(); - } - else { - ok = ((response >= 'a') && (response < 'a'+Player.packptr)); - if (ok) ok = slottable(Player.pack[response-'a'],slot); - } - } while (! ok); - if (! quit) use_pack_item(response - 'a',slot); - } - return slot; -} - -int take_from_pack(int slot, int display) -{ - if (optionp(TOPINV)) return aux_top_take_from_pack(slot,display); - else return aux_take_from_pack(slot); -} - -#if !defined(WIN32) -/* General interface to inventory */ -void item_inventory(int topline) -{ - if (topline) { - display_possessions(); - inventory_control(); - } - else top_inventory_control(); -} -#endif - -void do_inventory_control(void) -{ - if (optionp(TOPINV)) top_inventory_control(); - else { - menuclear(); - display_possessions(); - inventory_control(); - } -} - -/* inventory_control assumes a few setup things have been done, - * like loading the O_UP_IN_AIR item, etc. - * Each action uses up a little time. If only inspection actions - * are taken, no time is used up. */ -void inventory_control(void) -{ - int slot = O_UP_IN_AIR,done=false; - int response; - char letter; - - /* Start out assuming that we'll need to redraw. */ - inv_display_munge(); - clearmsg3(); - - do { - checkclear(); - print1("Action [d,e,l,p,s,t,x,>,<,?,ESCAPE]:"); - inv_display_refresh(); - - show_inventory_slot(slot,false); - display_inventory_slot(O_UP_IN_AIR,false); - move_slot(slot,slot,MAXITEMS); - response = mcigetc(); - - switch(response) { - case 12: - case 18: /* ^l, ^r */ - display_possessions(); - break; - case 'd': - if (Player.possessions[O_UP_IN_AIR] != NULL) - { - drop_from_slot(O_UP_IN_AIR); - display_inventory_slot(O_UP_IN_AIR, false); - } - else if (Player.possessions[slot] != NULL) - { - drop_from_slot(slot); - show_inventory_slot(slot, false); - } - else print3("Nothing in selected slot!"); - Command_Duration++; - break; - case 'l': - Str1[0] = '\0'; - if (Player.possessions[slot] != NULL) { - if (!strcmp(itemid(Player.possessions[slot]), - Player.possessions[slot]->objstr)) - print3("You notice nothing new about it."); - else { - if (Player.possessions[slot]->uniqueness == COMMON) - strcat(Str1, "Your "); - strcat(Str1, itemid(Player.possessions[slot])); - if (Player.possessions[slot]->objchar == BOOTS) - strcat(Str1, " look like "); - else { - strcat(Str1, " looks like a"); - letter = Player.possessions[slot]->objstr[0]; - if (letter == 'a' || letter == 'A' || letter == 'e' || - letter == 'E' || letter == 'i' || letter == 'I' || - letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U') - strcat(Str1, "n "); - else - strcat(Str1, " "); - } - strcat(Str1, Player.possessions[slot]->objstr); - print3(Str1); - } - } - else print3("Nothing in selected slot!"); - break; - case 'p': - if (Player.possessions[slot] != NULL) - { - put_to_pack(slot); - show_inventory_slot(slot, false); - } - Command_Duration+=5; - break; - case 's': - display_pack(); - morewait(); - inv_display_munge(); - Command_Duration+=5; - break; - case 't': - show_inventory_slot(take_from_pack(slot,true), false); - Command_Duration+=5; - break; - case 'e': - switch_to_slot(slot); - show_inventory_slot(O_UP_IN_AIR,false); - show_inventory_slot(slot,false); - Command_Duration+=2; - break; - case '\n': - case 'x': - switch_to_slot(slot); - show_inventory_slot(O_UP_IN_AIR,false); - show_inventory_slot(slot,false); - Command_Duration+=2; - done = (Player.possessions[O_UP_IN_AIR] == NULL); - break; - case 'j': - case '>': - case '2': -#if defined(KEY_DOWN) - case KEY_DOWN: -#endif - slot = move_slot(slot,slot+1,MAXITEMS); - break; - case 'k': - case '<': - case '8': -#if defined(KEY_UP) - case KEY_UP: -#endif - slot = move_slot(slot,slot-1,MAXITEMS); - break; -#ifdef KEY_HOME - case KEY_HOME: -#endif - case '-': - slot = move_slot(slot,0,MAXITEMS); - break; -#ifdef KEY_LL - case KEY_LL: -#endif - case '+': - slot = move_slot(slot,MAXITEMS-1,MAXITEMS); - break; - case '?': - menuclear(); - menuprint("d:\tDrop up-in-air or current item\n"); - menuprint("e:\tExchange current slot with up-in-air slot\n"); - menuprint("l:\tLook at current item\n"); - menuprint("p:\tPut up-in-air or current item in pack\n"); - menuprint("s:\tShow contents of pack\n"); - menuprint("t:\tTake something from pack into the\n\tcurrent or up-in-air slot\n"); - menuprint("x:\tAs 'e', but exit if up-in-air slot finishes empty\n"); - menuprint(">:\tMove down one slot/item\n"); - menuprint("<:\tMove up one slot/item\n"); - menuprint("?:\tDisplay help (this message + help file)\n"); - menuprint("ESCAPE:\texit\n"); - showmenu(); - clearmsg(); - print1("Display full help? (y/n)"); - if (ynq1() == 'y') - inv_help(); - inv_display_munge(); - break; - case ESCAPE: - clearmsg(); - if (Player.possessions[O_UP_IN_AIR] != NULL) { - drop_at(Player.x,Player.y,Player.possessions[O_UP_IN_AIR]); - Player.possessions[O_UP_IN_AIR] = NULL; - print3("Object 'up in air' dropped."); - } - done = true; - break; - default: - if (key_to_index(response) > 0) { - slot = move_slot(slot,key_to_index(response),MAXITEMS); - if (Player.possessions[slot] == NULL - && - Player.possessions[O_UP_IN_AIR] == NULL) { - show_inventory_slot(take_from_pack(slot,true), false); - Command_Duration+=5; - } - else { - switch_to_slot(slot); - show_inventory_slot(slot,false); - slot = O_UP_IN_AIR; - show_inventory_slot(slot,false); - Command_Duration+=2; - } - } - } - calc_melee(); - } while (! done); - xredraw(); -} - - -/* Make it clear that the inventory window mmust be redrawn. */ -static int inv_must_redraw; -static void inv_display_munge(void) -{ - inv_must_redraw = true; -} - -static void inv_display_refresh(void) -{ - if ( inv_must_redraw ) - display_possessions(); - inv_must_redraw = false; -} - - -/* same as inventory_control, but only uses msg window for i/o*/ - - -void top_inventory_control(void) -{ - int slot = 0,done=false,usedmenu=false; - char response, letter; - clearmsg3(); - do { - clearmsg1(); - print1("Action [d,e,l,p,s,t,x,~,?,ESCAPE]:"); - print2("'Up in air': "); - if (Player.possessions[O_UP_IN_AIR] == NULL) nprint2("NOTHING"); - else nprint2(itemid(Player.possessions[O_UP_IN_AIR])); - response = (char) mcigetc(); - - switch(response) { - case 'd': - if (Player.possessions[O_UP_IN_AIR] != NULL) - drop_from_slot(O_UP_IN_AIR); - else { - slot = get_inventory_slot(); - if (Player.possessions[slot] != NULL) - drop_from_slot(slot); - else print3("Nothing in selected slot!"); - } - Command_Duration++; - break; - case 'l': - Str1[0] = '\0'; - slot = get_inventory_slot(); - if (Player.possessions[slot] != NULL) { - if (!strcmp(itemid(Player.possessions[slot]), - Player.possessions[slot]->objstr)) - print3("You notice nothing new about it."); - else { - if (Player.possessions[slot]->uniqueness == COMMON) - strcat(Str1, "Your "); - strcat(Str1, itemid(Player.possessions[slot])); - if (Player.possessions[slot]->objchar == BOOTS) - strcat(Str1, " look like "); - else { - strcat(Str1, " looks like a"); - letter = Player.possessions[slot]->objstr[0]; - if (letter == 'a' || letter == 'A' || letter == 'e' || - letter == 'E' || letter == 'i' || letter == 'I' || - letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U') - strcat(Str1, "n "); - else - strcat(Str1, " "); - } - strcat(Str1, Player.possessions[slot]->objstr); - print3(Str1); - } - } - else print3("Nothing in selected slot!"); - break; - case 'p': - if (Player.possessions[O_UP_IN_AIR] == NULL) - slot = get_inventory_slot(); - else slot = O_UP_IN_AIR; - put_to_pack(slot); - Command_Duration+=5; - break; - case 's': - display_pack(); - usedmenu = true; - Command_Duration+=5; - break; - case 't': - slot = get_inventory_slot(); - (void) take_from_pack(slot,false); - Command_Duration+=5; - break; - case 'e': - slot = get_inventory_slot(); - if ( slot == O_UP_IN_AIR ) break; - switch_to_slot(slot); - Command_Duration+=2; - break; - case 'x': - slot = get_inventory_slot(); - if ( slot == O_UP_IN_AIR ) break; - switch_to_slot(slot); - Command_Duration+=2; - done = (Player.possessions[O_UP_IN_AIR] == NULL); - break; - case '~': - display_possessions(); - inventory_control(); - usedmenu = true; - done = true; - break; - case '?': - menuclear(); - menuprint("d:\tDrop an item\n"); - menuprint("e:\tExchange a slot with up-in-air slot\n"); - menuprint("l:\tLook at an item\n"); - menuprint("p:\tPut an item in pack\n"); - menuprint("s:\tShow contents of pack\n"); - menuprint("t:\tTake something from pack into a slot\n"); - menuprint("x:\tAs 'e', above, exit if up-in-air slot finishes empty\n"); - menuprint("~:\tEnter full-screen inventory mode\n"); - menuprint("?:\tDisplay help (this message + help file)\n"); - menuprint("ESCAPE:\texit\n"); - showmenu(); - clearmsg(); - print1("Display full help? (y/n)"); - if (ynq1() == 'y') - inv_help(); - usedmenu=true; - break; - case ESCAPE: - clearmsg(); - if (Player.possessions[O_UP_IN_AIR] != NULL) { - drop_at(Player.x,Player.y,Player.possessions[O_UP_IN_AIR]); - Player.possessions[O_UP_IN_AIR] = NULL; - print3("Object 'up in air' dropped."); - } - done = true; - break; - } - calc_melee(); - } while (! done); - if (usedmenu) - xredraw(); -} - - - -/* Let the user select a slot. */ -int get_inventory_slot(void) -{ - signed char response; - do { - clearmsg1(); - print1("Which inventory slot ['-'='up-in-air' slot]?"); - response = (signed char)mcigetc(); - if ( response == ESCAPE || response == '-' ) - return O_UP_IN_AIR; - else response = key_to_index(response); - } while (response != O_UP_IN_AIR); - return response; -} - - -/* returns some number between 0 and o->number */ -int get_item_number(Object* o) -{ - int n=0; - if (o->number == 1) - return 1; - do { - clearmsg(); - print1("How many? -- max "); - mnumprint(o->number); - nprint1(" :"); - n = (int) parsenum(""); - if (n>o->number) print3("Too many!"); - else if (n<1) n = 0; - } while (n > o->number); - if (n < 1) n = 0; - return(n); -} - -void drop_from_slot(int slot) -{ - int n,waitflag; - if (Player.possessions[slot] != NULL) { - if(Player.possessions[slot]->isCursed() && Player.possessions[slot]->isUsed()) - print3("It sticks to your fingers!"); - else { - n = get_item_number(Player.possessions[slot]); - if (n > 0) { - p_drop_at(Player.x,Player.y,n,Player.possessions[slot]); - waitflag = (Player.possessions[slot]->used && - (Player.possessions[slot]->number == n)); - conform_lost_objects(n,Player.possessions[slot]); - if (waitflag) morewait(); - } - else print3("Didn't drop anything."); - } - } - else print3("Didn't drop anything."); -} - - -void put_to_pack(int slot) -{ - int waitflag,num = 1; - Object *temp,*oslot = Player.possessions[slot]; - if (oslot == NULL) - print3("Slot is empty!"); - else if (oslot != NULL && oslot->isCursed() && oslot->isUsed()) - print3("Item is cursed!"); - else { - num = get_item_number(oslot); - if (num > 0) { - temp = split_item(num,oslot); - waitflag = (oslot->isUsed() && (oslot->number == num)); - conform_lost_objects(num,oslot); - if (waitflag) morewait(); - add_to_pack(temp); - } - } -} - - -/* splits num off of item to make newitem which is returned */ -/* something else (conform_lost_objects) has to reduce the actual - number value of item and Player.itemweight */ -Object* split_item(int num, Object* item) -{ - Object* newitem=NULL; - if (item != NULL) { - newitem = copy_obj( item ); - if (num <= item->number) - newitem->number = num; - /* else num > item->number, so return newitem with number = item->number */ - newitem->used = false; /* whether the original item was used or not */ - } - return(newitem); -} - - - -/* Trades contents of "up in air" slot with selected slot. One or both -may be null. If both slots are 'objequal' merges two groups into one -in the selected slot. If one slot is null and the number of the other -is greater than one, requests how many to move. */ - -void switch_to_slot(int slot) -{ - Object* oslot = Player.possessions[slot]; - Object* oair = Player.possessions[O_UP_IN_AIR]; - Object* otemp = NULL; - int slotnull,airnull,num=1,trade=false,put=false,take=false,merge=false; - int s2h=false,a2h=false; - - /* ie, is cursed and in use */ - if (slot == O_UP_IN_AIR) - print3("This action makes no sense!"); - else if (oslot != NULL && oslot->isCursed() && oslot->isUsed()) /* Check both via object methods */ - print3("The object in that slot is cursed -- you can't get rid of it!"); - else { - - slotnull = (oslot == NULL); - airnull = (oair == NULL); - - if (!slotnull) - s2h = (Player.possessions[O_READY_HAND] == - Player.possessions[O_WEAPON_HAND]); - - if (! airnull) - a2h = (twohandedp(oair->id) && - ((slot == O_READY_HAND) || (slot == O_WEAPON_HAND))); - - - /* figure out which action to take */ - - /* merge if both are same kind of object */ - merge = objequal(oslot,oair); - - take = ((!merge) && (!slotnull) && airnull); - - put = ((!merge) && slotnull && (!airnull) && slottable(oair,slot)); - - trade = ((!merge) && (!slotnull) && (!airnull) && slottable(oair,slot)); - - if (merge) merge_item(slot); - - else if (put) { - - /* deal with a 2-handed weapon */ - if (a2h) { - if (Player.possessions[O_READY_HAND] == NULL) - Player.possessions[O_READY_HAND] = oair; - if (Player.possessions[O_WEAPON_HAND] == NULL) - Player.possessions[O_WEAPON_HAND] = oair; - } - else Player.possessions[slot] = oair; - Player.possessions[O_UP_IN_AIR] = NULL; - if (item_useable(oair,slot)) { - oair->used = true; - item_use(oair); - inv_display_munge(); - morewait(); - if (oair->number > 1) pack_extra_items(oair); - } - Player.possessions[O_UP_IN_AIR] = NULL; - } - - else if (take) { - num = get_item_number(oslot); - if (num > 0) { - otemp = split_item(num,oslot); - dispose_lost_objects(num,oslot); - Player.possessions[O_UP_IN_AIR] = otemp; - } - if (s2h) { - if (Player.possessions[O_READY_HAND] == oslot) - Player.possessions[O_READY_HAND] = NULL; - if (Player.possessions[O_WEAPON_HAND] == oslot) - Player.possessions[O_WEAPON_HAND] = NULL; - } - } - - else if (trade) { - - /* first remove item from slot */ - num = oslot->number; - conform_lost_objects(oslot->number,oslot); - oslot->number = num; - - Player.possessions[O_UP_IN_AIR] = oslot; - - Player.possessions[slot] = oair; - - if (s2h) { - if (Player.possessions[O_READY_HAND] == oslot) - Player.possessions[O_READY_HAND] = NULL; - if (Player.possessions[O_WEAPON_HAND] == oslot) - Player.possessions[O_WEAPON_HAND] = NULL; - } - - if (a2h) { - if (Player.possessions[O_READY_HAND] == NULL) - Player.possessions[O_READY_HAND] = oair; - if (Player.possessions[O_WEAPON_HAND] == NULL) - Player.possessions[O_WEAPON_HAND] = oair; - } - - if (item_useable(oair,slot)) { - oair->used = true; - item_use(oair); - inv_display_munge(); - morewait(); - if (oair->number > 1) pack_extra_items(oair); - } - } - } -} - - - - -/* merges the up-in-air items into the selected items */ - -void merge_item(int slot) -{ - Player.possessions[slot]->number += - Player.possessions[O_UP_IN_AIR]->number; - Player.possessions[O_UP_IN_AIR] = NULL; -} - - -/* are two objects equal except for their number field? */ -/* returns false if either object is null */ -int objequal(Object* o, Object* p) -{ - if ((o == NULL) || (p == NULL)) return(false); - else return( - (o->id == p->id) && - /* DAG won't match corpses because they use charge for monster id, */ - /* except for hornets which have mid == 0, so will stack. Prevent this. */ - (o->id != CORPSEID) && - (o->plus == p->plus) && - (o->charge == 0) && - (p->charge == 0) && - (o->dmg == p->dmg) && - (o->hit == p->hit) && - (o->aux == p->aux) && - (o->known == p->known) && - (o->blessing == p->blessing) && - (o->usef == p->usef) && - (o->objstr == p->objstr ) - ); - -} - -/* criteria for being able to put some item in some slot */ -int slottable(Object* o, int slot) -{ - int ok = true; - if (o == NULL) ok = false; - else if (slot == O_ARMOR) { - if (o->objchar != ARMOR) { - print3("Only armor can go in the armor slot!"); - ok = false; - } - } - else if (slot == O_SHIELD) { - if (o->objchar != SHIELD) { - print3("Only a shield can go in the shield slot!"); - ok = false; - } - } - else if (slot == O_BOOTS) { - if (o->objchar != BOOTS) { - print3("Only boots can go in the boots slot!"); - ok = false; - } - } - else if (slot == O_CLOAK) { - if (o->objchar != CLOAK) { - print3("Only a cloak can go in the cloak slot!"); - ok = false; - } - } - else if (slot >= O_RING1) { - if (o->objchar != RING) { - print3("Only a ring can go in a ring slot!"); - ok = false; - } - } - return(ok); -} - - -/* whether or not an item o can be used in a slot. Assumes o can in - fact be placed in the slot. */ -int item_useable(Object* o, int slot) -{ - /* don't have to check the object in the first if since only armor - can go in armor slot, cloak in cloak slot, etc */ - - if ((slot == O_ARMOR) || - (slot == O_CLOAK) || - (slot == O_SHIELD) || - (slot == O_BOOTS) || - (slot >= O_RING1)) - return(true); - - /* weapon is useable if it is put in weapon hand or if it is two-handed - and put in either hand when the other also holds the weapon */ - - else if ((o->objchar == WEAPON) || - (o->objchar == MISSILEWEAPON)) { - if (twohandedp(o->id) && - ((slot==O_READY_HAND)||(slot==O_WEAPON_HAND))) { - if (Player.possessions[O_READY_HAND] == - Player.possessions[O_WEAPON_HAND]) { - print1("You heft the weapon and find you must use both hands."); - morewait(); - return(true); - } - else { - print1("This weapon is two-handed, so at the moment, "); - print2("you are just lugging it around...."); - morewait(); - return(false); - } - } - else return(slot == O_WEAPON_HAND); - } - else return(false); -} - -/* returns true if item with id and charge is found in pack or in - inventory slot. charge is used to differentiate - corpses instead of aux, which is their food value. */ -int find_item(Object* *o, int id, int chargeval) -{ - int i,found=false; - *o=NULL; - for(i=1; ((iid == id) && - ((chargeval == -1) || - (Player.possessions[i]->charge == chargeval))) { - *o = Player.possessions[i]; - found = true; - } - if (! found) - for(i=0; ((iid == id) && - ((chargeval == -1) || - (Player.pack[i]->charge == chargeval))) { - *o = Player.pack[i]; - found = true; - } - return(found); -} - -/* returns true if item with id and charge is found in pack or in - inventory slot. Destroys item. charge is used to differentiate - corpses instead of aux, which is their food value. */ -int find_and_remove_item(int id, int chargeval) -{ - int i,found=false; - Object* o=NULL; - - for(i=1; ((iid == id) && - ((chargeval == -1) || - (Player.possessions[i]->charge == chargeval))) { - o = Player.possessions[i]; - conform_lost_objects(1, o); - found = true; - } - if (! found) for(i=0; ((iid == id) && - ((chargeval == -1) || - (Player.pack[i]->charge == chargeval))) { - Player.pack[i]->number--; - if (Player.pack[i]->number == 0) { - free_obj( Player.pack[i], true ); - Player.pack[i] = NULL; - } - found = true; - } - fixpack(); - return(found); -} - - -void lose_all_items(void) -{ - int i; - print1("You notice that you are completely devoid of all possessions."); - morewait(); - for(i=0; inumber, - Player.possessions[i]); - Player.possessions[i] = NULL; - } - for(i=0; inumber = item->number-1; - extra->used = false; - item->number = 1; - if (Player.packptr < MAXPACK) { - print3("Putting extra items back in pack."); - morewait(); - push_pack(extra); - } - else if (Player.possessions[O_UP_IN_AIR] == NULL) { - print3("Extra copies of item are 'up in the air'"); - Player.possessions[O_UP_IN_AIR] = extra; - } - else { - print3("No room for extra copies of item -- dropping them."); - drop_at(Player.x,Player.y,extra); - } - calc_melee(); -} - - -/* makes sure Player.pack is OK, (used after sale from pack) */ -void fixpack(void) -{ - Object* tpack[MAXPACK]; - int i,tctr=0; - for(i=0; iid)) - { - display_inventory_slot(O_READY_HAND, topline); - display_inventory_slot(O_WEAPON_HAND, topline); - display_inventory_slot(slotnum, topline); - } - else - display_inventory_slot(slotnum, topline); - else - display_inventory_slot(slotnum, topline); -} +/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ +/* inv.c */ +/* functions having to do with player item inventory */ + +#include "glob.h" +#include "defs.h" + +static void inv_display_munge(void); +static void inv_display_refresh(void); + +/* drops money, heh heh */ +void drop_money(void) +{ + Object* money; + + money = detach_money(0); + if (money != NULL) { + if (Current_Environment == E_CITY) { + print1("As soon as the money leaves your hand,"); + print2("a horde of scrofulous beggars snatch it up and are gone!"); + free( money ); + } + else drop_at(Player.x,Player.y,money); + } + else State.setSkipMonsters(); +} + + +/* returns some money from player back into "money" item. + for giving and dropping money */ +Object* detach_money(long howmuch) +/* if howmuch == 0, ask the player. otherwise, just get howmuch. */ +{ + long c; + Object* cash=NULL; + if ( howmuch == 0 ) + c = get_money(Player.cash); + else + c = howmuch; + if (c != ABORT) { + Player.cash -= c; + cash = ((Object*) checkmalloc(sizeof(Object))); + make_cash(cash,difficulty()); + cash->basevalue = c; + } + return(cash); +} + + +/* gets a legal amount of money or ABORT */ +long get_money(long limit) +{ + long c; + c = parsenum("How much money? "); + if (c > limit) { + print3("Forget it, buddy."); + return(ABORT); + } + else return(c); +} + + + +/* pick up from some location x,y */ +/* Lift entire itemlist off ground, pass it to inventory control, which + may drop things back onto the now null ground */ +void pickup_at (int x, int y) +{ + char response; + + pol ol; + pol temp; + + State.setFastMove(false); + + ol = Level->site[x][y].things; + Level->site[x][y].things = 0; + + while (ol != 0) + { + clearmsg1(); + response = cinema_ynq(strjoin("Pick up? [ynq]: ", itemid(ol->thing))); + if ('q' == response) + break; + + if (response == 'y') + gain_item(ol->thing); + else + drop_at(x,y,ol->thing); + + temp = ol; + ol = ol->next; + temp->next = 0; + temp->thing = 0; + free(temp); + } + + while (ol != 0) + { + temp = ol; + ol = ol->next; + temp->next = 0; + temp->thing = 0; + free(temp); + } +} + +/* WDT -- convert from a char (keypress) to an item index in + * player inventory */ +/* Item identifiers, in this case the letters of the alphabet minus + * any letters already used for commands. Yes, there are more here + * than could be needed, but I don't want to short myself for later. + */ +signed char inventory_keymap[] = "-abcfghimnoqruvwyz"; +int key_to_index(signed char key) +{ + int i; + assert( MAXITEMS>0 ); /* must have room for an item, or this loop will + * die! */ + + for (i=0; iobjchar != ARMOR) { + ok = false; + } + } + else if (slot == O_SHIELD) { + if (o->objchar != SHIELD) { + ok = false; + } + } + else if (slot == O_BOOTS) { + if (o->objchar != BOOTS) { + ok = false; + } + } + else if (slot == O_CLOAK) { + if (o->objchar != CLOAK) { + ok = false; + } + } + else if (slot >= O_RING1) { + if (o->objchar != RING) { + ok = false; + } + } + return(ok); +} + +/* put all of o on objlist at x,y on Level->depth */ +/* Not necessarily dropped by character; just dropped... */ +void drop_at(int x, int y, Object* o) +{ + pol tmp; + Object* cpy; + + if (Current_Environment != E_COUNTRYSIDE) { + if ((Level->site[x][y].locchar != VOID_CHAR) && + (Level->site[x][y].locchar != ABYSS)) { + cpy = copy_obj( o ); + tmp = ((pol) checkmalloc(sizeof(oltype))); + cpy->used = false; + tmp->thing = cpy; + tmp->next = Level->site[x][y].things; + Level->site[x][y].things = tmp; + } + else if (Level->site[x][y].p_locf == L_VOID_STATION) + State.setPreparedVoid(); + } +} + +/* put n of o on objlist at x,y on Level->depth */ +void p_drop_at(int x, int y, int n, Object* o) +{ + pol tmp; + if (Current_Environment != E_COUNTRYSIDE) { + if ((Level->site[x][y].locchar != VOID_CHAR) && + (Level->site[x][y].locchar != ABYSS)) { + tmp = ((pol) checkmalloc(sizeof(oltype))); + tmp->thing = copy_obj( o ); + tmp->thing->used = false; + tmp->thing->number = n; + print2("Dropped "); + nprint2(itemid(tmp->thing)); + morewait(); + tmp->next = Level->site[x][y].things; + Level->site[x][y].things = tmp; + } + else if (Level->site[x][y].p_locf == L_VOID_STATION) + State.setPreparedVoid(); + } +} + + +/* returns a string for identified items */ +char *itemid(Object* obj) +{ + char tstr[80]; + if (obj->objchar==CASH) { + strcpy(Str4,obj->truename); + return(Str4); + } + else { + if (Objects[obj->id].known > obj->known) + obj->known = Objects[obj->id].known; + + setnumstr(obj,tstr); + strcpy(Str4,tstr); + if (obj->known == 0) + strcat(Str4,obj->objstr); + else if (obj->known == 1) { + if (obj->id == OB_YENDOR || obj->id == OB_KARNAK || + obj->id == OB_STARGEM ) + strcat(Str4, "the "); + strcat(Str4,obj->truename); + } + else { + if (obj->id == OB_YENDOR || obj->id == OB_KARNAK || + obj->id == OB_STARGEM ) + strcat(Str4, "the "); + if (obj->usef == I_NOTHING && Objects[obj->id].usef != I_NOTHING) + strcat(Str4, "disenchanted "); + if (obj->isCursed()) { + strcat(Str4, "cursed "); + strcat(Str4, obj->cursestr); + } + else if (obj->blessing > 0) { + strcat(Str4, "blessed "); + strcat(Str4, obj->truename); + } + else strcat(Str4,obj->truename); + if (obj->number > 1) strcat(Str4,"s"); + switch (obj->objchar) { + case STICK: + setchargestr(obj,tstr); + strcat(Str4,tstr); + break; + case MISSILEWEAPON: + case ARMOR: + case RING: + case SHIELD: + case WEAPON: + setplustr(obj,tstr); + strcat(Str4, tstr); + break; + default: + strcat(Str4,""); + break; + } + } + return(Str4); + } +} + +char *cashstr(void) +{ + if (difficulty() < 3) return("copper pieces"); + else if (difficulty() < 5) return("silver pieces"); + else if (difficulty() < 7) return("gold pieces"); + else if (difficulty() < 8) return("semiprecious gems"); + else if (difficulty() < 9) return("mithril pieces"); + else if (difficulty() < 10) return("precious gems"); + else return("orichalc pieces"); +} + +/* return an object's plus as a string */ +void setplustr(Object* obj, char *pstr) +{ + pstr[0] = ' '; + pstr[1] = (obj->plus < 0 ? '-' : '+' ); + if (abs(obj->plus) < 10) { + pstr[2] = '0' + abs(obj->plus); + pstr[3] = 0; + } + else { + pstr[2] = '0' + abs(obj->plus / 10); + pstr[3] = '0' + abs(obj->plus % 10); + pstr[4] = 0; + } +} + +/* return an object's number as a string */ +void setnumstr(Object* obj, char *nstr) +{ + if (obj->number < 2) + nstr[0] = 0; + else if (obj->number < 10) { + nstr[0] = '0' + obj->number; + nstr[1] = 'x'; + nstr[2] = ' '; + nstr[3] = 0; + } + else if (obj->number < 41) { + nstr[0] = '0' + ((int)(obj->number / 10)); + nstr[1] = '0' + (obj->number % 10); + nstr[2] = 'x'; + nstr[3] = ' '; + nstr[4] = 0; + } + else strcpy(nstr,"lots of "); +} + + +/* return object with charges */ +void setchargestr(Object* obj, char *cstr) +{ + cstr[0] = ' '; + cstr[1] = '['; + if (obj->charge < 0) { + cstr[2]='d'; + cstr[3]='e'; + cstr[4]='a'; + cstr[5]='d'; + cstr[6]=']'; + cstr[7]=0; + } + else if (obj->charge < 10) { + cstr[2] = '0' + obj->charge; + cstr[3] = ']'; + cstr[4] = 0; + } + else { + cstr[2] = '0' + ((int)(obj->charge / 10)); + cstr[3] = '0' + (obj->charge % 10); + cstr[4] = ']'; + cstr[5] = 0; + } +} + + +void give_money(Monster *m) +{ + Object* cash; + + cash = detach_money(0); + if (cash == NULL) + State.setSkipMonsters(); + else givemonster(m,cash); +} + + +void lawbringer_gets_gem(Monster* m, Object* o) +{ + clearmsg(); + print1("The LawBringer accepts the gem reverently."); + print2("He raises it above his head, where it bursts into lambent flame!"); + morewait(); + print1("You are bathed in a shimmering golden light."); + print2("You feel embedded in an infinite matrix of ordered energy."); + morewait(); + if (Imprisonment > 0) + Imprisonment = 0; + if (Player.rank[ORDER] == -1) { + print2("You have been forgiven. You feel like a Paladin...."); + Player.rank[ORDER] = 1; + } + Player.alignment += 200; + Player.pow = Player.maxpow = Player.pow * 2; + gain_experience(2000); + State.setGivenStargem(); + /* WDT HACK!!! Where else would this ever get freed?? */ + free_obj(o, true); +} + +void givemonster(Monster* m, Object* o) +{ + /* special case -- give gem to LawBringer */ + if ((m->id == LAWBRINGER) && (o->id == OB_STARGEM)) + lawbringer_gets_gem(m,o); + else { + if (m->uniqueness == COMMON) { + strcpy(Str3,"The "); + strcat(Str3,m->name); + } + else strcpy(Str3,m->name); + + if (m_statusp(m,GREEDY) || m_statusp(m,NEEDY)) { + m->m_pickup(o); + strcat(Str3," takes your gift"); + print1(Str3); + Player.alignment++; + if (m_statusp(m,GREEDY) && (true_item_value(o) < (long) m->level*100)) + nprint1("...but does not appear satisfied."); + else if (m_statusp(m,NEEDY) && + (true_item_value(o) < (long) Level->depth*Level->depth)) + nprint1("...and looks chasteningly at you."); + else { + nprint1("...and seems happy with it."); + m_status_reset(m,HOSTILE); + m_status_reset(m,GREEDY); + m_status_reset(m,NEEDY); + } + } + else if (m_statusp(m,HUNGRY)) { + + if (((m->id == HORSE) && (o->id == OB_GRAIN)) || /* grain */ + ((m->id != HORSE) && + ((o->usef == I_FOOD) || (o->usef == I_POISON_FOOD)))) { + strcat(Str3," wolfs down your food ... "); + print1(Str3); + m_status_reset(m,HUNGRY); + m_status_reset(m,HOSTILE); + if (o->usef == I_POISON_FOOD) { + Player.alignment -= 2; + nprint1("...and chokes on the poisoned ration!"); + morewait(); + m_status_set(m,HOSTILE); + m->m_damage(100,POISON); + } + else nprint1("...and now seems satiated."); + morewait(); + free_obj(o, true); + } + else { + strcat(Str3," spurns your offering and leaves it on the ground."); + print1(Str3); + drop_at(m->x,m->y,o); + } + } + else { + strcat(Str3," doesn't care for your offering and drops it."); + print1(Str3); + drop_at(m->x,m->y,o); + } + } +} + + + +/* will clear all, not just one of an object. */ +void conform_lost_object(Object* obj) +{ + if (obj != NULL) conform_lost_objects(obj->number,obj); +} + + + +/* removes n of object from inventory; frees object if appropriate. */ + +void dispose_lost_objects(int n, Object* obj) +{ + int i,conformed=false,subtracted=false; + + if (obj == NULL) + return; + for(i=0; inumber -= n; + subtracted = true; + } + if (obj->number < 1) { + if (!conformed) { + conform_unused_object(obj); + conformed = true; + } + Player.possessions[i] = NULL; + } + } + if (obj->number < 1) + free_obj( obj, true ); +} + + +/* removes n of object from inventory without freeing object. + Removes all instances of pointer (might be 2 handed weapon, etc) */ +void conform_lost_objects(int n, Object* obj) +{ + int i,conformed=false,subtracted=false; + if (obj != NULL) for(i=0; inumber -= n; + subtracted = true; + } + if (obj->number < 1) { + if (!conformed) { + conform_unused_object(obj); + conformed = true; + } + Player.possessions[i] = NULL; + } + } +} + + +/* clears unused possession */ +void conform_unused_object(Object* obj) +{ + if (obj->used) { + obj->used = false; + item_use(obj); + inv_display_munge(); + } + calc_melee(); +} + + +/* select an item from inventory */ +/* if itype is NULL_ITEM, any kind of item is acceptable. + if itype is CASH, any kind of item or '$' (cash) is acceptable. + if itype is FOOD, CORPSE or FOOD is acceptable, but only FOOD is +listed in the possibilities. + if itype is any other object type (eg SCROLL, POTION, etc.), only +that type of item is acceptable or is listed */ + +int item_is_selectable (Symbol itype, Object* item) +{ + if (!item) return false; + + if (CASH == itype) return true; + if (NULL_ITEM == itype) return true; + if (item->objchar == itype) return true; + if (FOOD == itype && CORPSE == item->objchar) return true; + + return false; +} + +int getitem (Symbol itype) +{ + return getitem_prompt(0, itype); +} + +int getitem_prompt (char * prompt, Symbol itype) +{ + char key; + char *line3; + char invstr[64]; + char selectstr[80]; + int i, k; + int again; + int found = false; + int drewmenu = false; + + found = ((itype == NULL_ITEM) || ((itype == CASH) && (Player.cash > 0))); + + /* build invstr, which lists all valid selections that the user can make */ + invstr[0] = 0; + + k = 0; + for(i = 1; i < MAXITEMS; ++i) + { + if (item_is_selectable(itype, Player.possessions[i])) + { + found = true; + invstr[k++] = index_to_key(i); + invstr[k] = 0; + } + } + + if (!found) + { + print3("Nothing appropriate."); + return ABORT; + } + + if (itype == CASH) + { + invstr[k++] = CASH & 0xff; + invstr[k] = 0; + } + + /* gotta let the user see what everything means... */ + invstr[k++] = '?'; + invstr[k] = 0; + + line3 = NULL; + + /* build prompt... */ + selectstr[0] = 0; + if (prompt) strcpy(selectstr, prompt); + strcat(selectstr, "Select an item. ("); + + i = 0; + k = strlen(selectstr); + while (true) + { + if ('?' == invstr[i]) break; + selectstr[k++] = invstr[i++]; + selectstr[k++] = ','; + if (k > 75) break; + } + + selectstr[k-1] = ')'; + selectstr[k] = 0; + + /* get input from the user */ + do + { + again = false; + + key = cinema_interact(invstr, selectstr, " ? to display items", line3); + line3 = NULL; + + if ('?' == key) + { + again = true; + drewmenu = true; + for (i = 1; i < MAXITEMS; ++i) + { + if (item_is_selectable(itype, Player.possessions[i])) + display_inventory_slot(i, false); + } + } + else if ((CASH & 0xff) == key && (CASH != itype)) + { + again = true; + line3 = "You cannot select cash now."; + } + } + while (again); + + if (drewmenu) xredraw(); + if (-1 == key) return ABORT; /* cinema_interact() returns -1 for ESC */ + if ((CASH & 0xff) == key) return CASHVALUE; + + return key_to_index(key); +} + +/* true if the numerical index based on 'a' == 1 turns out to be either +out of the range of the possessions array or a null item */ +int badobject(char slotchar) +{ + int slot = slotchar + 1 - 'a'; + if ((slot<1) || (slot >= MAXITEMS)) return(true); + else return(Player.possessions[slot] == NULL); +} + +#if !defined(WIN32) +/* this takes the numerical index directly for the same effect as badobject*/ +int baditem(int slotnum) +{ + if ((slotnum<1) || (slotnum >= MAXITEMS)) return(true); + else return(Player.possessions[slotnum] == NULL); +} +#endif + +/* formerly add_item_to_pack */ +void gain_item(Object* o) +{ + if (o->uniqueness == UNIQUE_MADE) + Objects[o->id].uniqueness = UNIQUE_TAKEN; + if (o->objchar == CASH) { + print2("You gained some cash."); + Player.cash += o->basevalue; + free_obj(o,true); + dataprint(); + } + else if (optionp(PACKADD)) { + if (! get_to_pack(o)) { + Player.possessions[O_UP_IN_AIR] = o; + do_inventory_control(); + } + } + else { + Player.possessions[O_UP_IN_AIR] = o; + do_inventory_control(); + } +} + +/* tosses the item into the pack, making it the first reachable item */ +void push_pack(Object* o) +{ + int i; + for (i = Player.packptr; i > 0; i--) + Player.pack[i] = Player.pack[i-1]; + Player.pack[0] = o; + Player.packptr++; +} + +/* Adds item to pack list */ +void add_to_pack(Object* o) +{ + if (Player.packptr >= MAXPACK) { + print3("Your pack is full. The item drops to the ground."); + drop_at(Player.x,Player.y,o); + } + else { + push_pack(o); + print3("Putting item in pack."); + } +} + +/* Adds item to pack list, maybe going into inventory mode if pack is full */ +int get_to_pack(Object* o) +{ + if (Player.packptr >= MAXPACK) { + print3("Your pack is full."); + morewait(); + return(false); + } + else { + push_pack(o); + print3("Putting item in pack."); + return(true); + } +} + +int pack_item_cost(int index) +{ + int cost; + if (index > 20) { + cost = 17; + } + else if (index > 15) { + cost = 7; + } + else cost = 2; + return cost; +} + +/* WDT -- 'response' must be an index into the pack. */ +void use_pack_item(int response, int slot) +{ + Object* item; + int i; + i = pack_item_cost(response); + if (i > 10) { + cinema_scene("You begin to rummage through your pack.",NULL,NULL); + } + if (i > 5) { + cinema_scene("You search your pack for the item.",NULL,NULL); + } + print3("You take the item from your pack."); + morewait(); + Command_Duration += i; + item = Player.possessions[slot] = Player.pack[response]; + for(i=response; iid)) + { + if (Player.possessions[O_READY_HAND] == NULL) + Player.possessions[O_READY_HAND] = item; + if (Player.possessions[O_WEAPON_HAND] == NULL) + Player.possessions[O_WEAPON_HAND] = item; + } + if (item_useable(item,slot)) { + item->used = true; + item_use(item); + inv_display_munge(); + morewait(); + if (item->number > 1) pack_extra_items(item); + } +} + +/* WDT HACK! This ought to be in scr.c, along with its companion. However, + * right now it's only used in the function directly below. */ +int aux_display_pack(int start_item, int slot) +{ + int i=start_item, items; + char *depth_string; + + menuclear(); +#if 0 + /* WDT: I decided to remove these lines, since the purpose of this routine + * is to generate a pack menu, not update the message line. This is + * especially important now that I'm making the inventory system use the + * new 'Cinema' message box (which will stop the message corruption + * problems that were epidemic). */ + if (Player.packptr < 1) print3("Pack is empty."); + else if (Player.packptr <= start_item) print3("You see the leather at the bottom of the pack."); +#else + /* These cases are not terribly important, but they can happen. */ + if (Player.packptr < 1 || Player.packptr <= start_item) + return start_item; +#endif + else + { + items = 0; + for(i=start_item; i 10) + depth_string = "**"; + else if (pack_item_cost(i) > 5) + depth_string = "* "; + else depth_string = " "; + sprintf(Str1, " %c: %s %s\n", i + 'a', depth_string, + itemid(Player.pack[i])); + if (items == 0) + menuprint("Items in Pack:\n"); + menuprint(Str1); + items++; + } + } + if (items == 0) + menuprint("You see nothing useful for that slot in the pack."); + else { + menuprint("\n*: Takes some time to reach; **: buried very deeply."); + } + showmenu(); + } + return i; +} + +/* takes something from pack, puts to slot, + * or to 'up-in-air', one of which at least must be empty */ +int aux_take_from_pack(int slot) +{ + char response,pack_item, last_item; + int quit = false,ok=true; + if (Player.possessions[slot] != NULL) + slot = O_UP_IN_AIR; + if (Player.possessions[slot] != NULL) + print3("slot is not empty!"); + else if (Player.packptr < 1) + print3("Pack is empty!"); + else { + pack_item = 0; + do { + ok = true; + last_item = aux_display_pack(pack_item,slot); + if (last_item == Player.packptr && pack_item == 0 ) + print1("Enter pack slot letter or ESCAPE to quit."); + else if (last_item == Player.packptr) + print1("Enter pack slot letter, - to go back, or ESCAPE to quit."); + else if (pack_item == 0) + print1("Enter pack slot letter, + to see more, or ESCAPE to quit."); + else + print1("Enter pack slot letter, + or - to see more, or ESCAPE to quit."); + response = mcigetc(); + if (response == '?') { + /* WDT HACK -- display some help instead. */ + print1("Help not implemented (sorry)."); + morewait(); + ok = false; + } + else if (response == ESCAPE) { + quit = true; + clearmsg1(); + } + else if (response == '+') { + if (last_item < Player.packptr) + pack_item = last_item; + ok = false; + } + else if (response == '-') { + /* WDT HACK: this _should_ make us page up. Sadly, + * I have no way of calculating how much I'll be paging up. + * This is fixable, but I have no idea how much work... As + * a hack, I'm just returning to the first page of the listing. + */ + pack_item = 0; + ok = false; + } + else { + ok = ((response >= 'a') && (response < 'a'+Player.packptr)); + if (ok) ok = slottable(Player.pack[response-'a'],slot); + } + } while (! ok); + if (! quit) { + use_pack_item(response - 'a',slot); + } + } + + inv_display_munge(); + + return slot; +} + +/* takes something from pack, puts to slot, +or to 'up-in-air', one of which at least must be empty */ +int aux_top_take_from_pack(int slot, int display) +{ + char response; + int quit = false,ok=true; + + if (Player.possessions[slot] != NULL) + slot = O_UP_IN_AIR; + if (Player.possessions[slot] != NULL) + print3("slot is not empty!"); + else if (Player.packptr == 0) + print3("Pack is empty!"); + else { + do { + ok = true; + print1("Enter pack slot letter, or ? to show pack, or ESCAPE to quit."); + response = mcigetc(); + if (response == '?') { + display_pack(); + inv_display_munge(); + ok = false; + } + else if (response == ESCAPE) { + quit = true; + clearmsg1(); + } + else { + ok = ((response >= 'a') && (response < 'a'+Player.packptr)); + if (ok) ok = slottable(Player.pack[response-'a'],slot); + } + } while (! ok); + if (! quit) use_pack_item(response - 'a',slot); + } + return slot; +} + +int take_from_pack(int slot, int display) +{ + if (optionp(TOPINV)) return aux_top_take_from_pack(slot,display); + else return aux_take_from_pack(slot); +} + +#if !defined(WIN32) +/* General interface to inventory */ +void item_inventory(int topline) +{ + if (topline) { + display_possessions(); + inventory_control(); + } + else top_inventory_control(); +} +#endif + +void do_inventory_control(void) +{ + if (optionp(TOPINV)) top_inventory_control(); + else { + menuclear(); + display_possessions(); + inventory_control(); + } +} + +/* inventory_control assumes a few setup things have been done, + * like loading the O_UP_IN_AIR item, etc. + * Each action uses up a little time. If only inspection actions + * are taken, no time is used up. */ +void inventory_control(void) +{ + int slot = O_UP_IN_AIR,done=false; + int response; + char letter; + + /* Start out assuming that we'll need to redraw. */ + inv_display_munge(); + clearmsg3(); + + do { + checkclear(); + print1("Action [d,e,l,p,s,t,x,>,<,?,ESCAPE]:"); + inv_display_refresh(); + + show_inventory_slot(slot,false); + display_inventory_slot(O_UP_IN_AIR,false); + move_slot(slot,slot,MAXITEMS); + response = mcigetc(); + + switch(response) { + case 12: + case 18: /* ^l, ^r */ + display_possessions(); + break; + case 'd': + if (Player.possessions[O_UP_IN_AIR] != NULL) + { + drop_from_slot(O_UP_IN_AIR); + display_inventory_slot(O_UP_IN_AIR, false); + } + else if (Player.possessions[slot] != NULL) + { + drop_from_slot(slot); + show_inventory_slot(slot, false); + } + else print3("Nothing in selected slot!"); + Command_Duration++; + break; + case 'l': + Str1[0] = '\0'; + if (Player.possessions[slot] != NULL) { + if (!strcmp(itemid(Player.possessions[slot]), + Player.possessions[slot]->objstr)) + print3("You notice nothing new about it."); + else { + if (Player.possessions[slot]->uniqueness == COMMON) + strcat(Str1, "Your "); + strcat(Str1, itemid(Player.possessions[slot])); + if (Player.possessions[slot]->objchar == BOOTS) + strcat(Str1, " look like "); + else { + strcat(Str1, " looks like a"); + letter = Player.possessions[slot]->objstr[0]; + if (letter == 'a' || letter == 'A' || letter == 'e' || + letter == 'E' || letter == 'i' || letter == 'I' || + letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U') + strcat(Str1, "n "); + else + strcat(Str1, " "); + } + strcat(Str1, Player.possessions[slot]->objstr); + print3(Str1); + } + } + else print3("Nothing in selected slot!"); + break; + case 'p': + if (Player.possessions[slot] != NULL) + { + put_to_pack(slot); + show_inventory_slot(slot, false); + } + Command_Duration+=5; + break; + case 's': + display_pack(); + morewait(); + inv_display_munge(); + Command_Duration+=5; + break; + case 't': + show_inventory_slot(take_from_pack(slot,true), false); + Command_Duration+=5; + break; + case 'e': + switch_to_slot(slot); + show_inventory_slot(O_UP_IN_AIR,false); + show_inventory_slot(slot,false); + Command_Duration+=2; + break; + case '\n': + case 'x': + switch_to_slot(slot); + show_inventory_slot(O_UP_IN_AIR,false); + show_inventory_slot(slot,false); + Command_Duration+=2; + done = (Player.possessions[O_UP_IN_AIR] == NULL); + break; + case 'j': + case '>': + case '2': + case (char)KEY_ARROW_DOWN: +#if defined(KEY_DOWN) + case KEY_DOWN: +#endif + slot = move_slot(slot,slot+1,MAXITEMS); + break; + case 'k': + case '<': + case '8': +#if defined(KEY_UP) + case KEY_UP: +#endif + case (char)KEY_ARROW_UP: + slot = move_slot(slot,slot-1,MAXITEMS); + break; +#ifdef KEY_HOME + case KEY_HOME: +#endif + case '-': + slot = move_slot(slot,0,MAXITEMS); + break; +#ifdef KEY_LL + case KEY_LL: +#endif + case '+': + slot = move_slot(slot,MAXITEMS-1,MAXITEMS); + break; + case '?': + menuclear(); + menuprint("d:\tDrop up-in-air or current item\n"); + menuprint("e:\tExchange current slot with up-in-air slot\n"); + menuprint("l:\tLook at current item\n"); + menuprint("p:\tPut up-in-air or current item in pack\n"); + menuprint("s:\tShow contents of pack\n"); + menuprint("t:\tTake something from pack into the\n\tcurrent or up-in-air slot\n"); + menuprint("x:\tAs 'e', but exit if up-in-air slot finishes empty\n"); + menuprint(">:\tMove down one slot/item\n"); + menuprint("<:\tMove up one slot/item\n"); + menuprint("?:\tDisplay help (this message + help file)\n"); + menuprint("ESCAPE:\texit\n"); + showmenu(); + clearmsg(); + print1("Display full help? (y/n)"); + if (ynq1() == 'y') + inv_help(); + inv_display_munge(); + break; + case ESCAPE: + clearmsg(); + if (Player.possessions[O_UP_IN_AIR] != NULL) { + drop_at(Player.x,Player.y,Player.possessions[O_UP_IN_AIR]); + Player.possessions[O_UP_IN_AIR] = NULL; + print3("Object 'up in air' dropped."); + } + done = true; + break; + default: + if (key_to_index(response) > 0) { + slot = move_slot(slot,key_to_index(response),MAXITEMS); + if (Player.possessions[slot] == NULL + && + Player.possessions[O_UP_IN_AIR] == NULL) { + show_inventory_slot(take_from_pack(slot,true), false); + Command_Duration+=5; + } + else { + switch_to_slot(slot); + show_inventory_slot(slot,false); + slot = O_UP_IN_AIR; + show_inventory_slot(slot,false); + Command_Duration+=2; + } + } + } + calc_melee(); + } while (! done); + xredraw(); +} + + +/* Make it clear that the inventory window mmust be redrawn. */ +static int inv_must_redraw; +static void inv_display_munge(void) +{ + inv_must_redraw = true; +} + +static void inv_display_refresh(void) +{ + if ( inv_must_redraw ) + display_possessions(); + inv_must_redraw = false; +} + + +/* same as inventory_control, but only uses msg window for i/o*/ + + +void top_inventory_control(void) +{ + int slot = 0,done=false,usedmenu=false; + char response, letter; + clearmsg3(); + do { + clearmsg1(); + print1("Action [d,e,l,p,s,t,x,~,?,ESCAPE]:"); + print2("'Up in air': "); + if (Player.possessions[O_UP_IN_AIR] == NULL) nprint2("NOTHING"); + else nprint2(itemid(Player.possessions[O_UP_IN_AIR])); + response = (char) mcigetc(); + + switch(response) { + case 'd': + if (Player.possessions[O_UP_IN_AIR] != NULL) + drop_from_slot(O_UP_IN_AIR); + else { + slot = get_inventory_slot(); + if (Player.possessions[slot] != NULL) + drop_from_slot(slot); + else print3("Nothing in selected slot!"); + } + Command_Duration++; + break; + case 'l': + Str1[0] = '\0'; + slot = get_inventory_slot(); + if (Player.possessions[slot] != NULL) { + if (!strcmp(itemid(Player.possessions[slot]), + Player.possessions[slot]->objstr)) + print3("You notice nothing new about it."); + else { + if (Player.possessions[slot]->uniqueness == COMMON) + strcat(Str1, "Your "); + strcat(Str1, itemid(Player.possessions[slot])); + if (Player.possessions[slot]->objchar == BOOTS) + strcat(Str1, " look like "); + else { + strcat(Str1, " looks like a"); + letter = Player.possessions[slot]->objstr[0]; + if (letter == 'a' || letter == 'A' || letter == 'e' || + letter == 'E' || letter == 'i' || letter == 'I' || + letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U') + strcat(Str1, "n "); + else + strcat(Str1, " "); + } + strcat(Str1, Player.possessions[slot]->objstr); + print3(Str1); + } + } + else print3("Nothing in selected slot!"); + break; + case 'p': + if (Player.possessions[O_UP_IN_AIR] == NULL) + slot = get_inventory_slot(); + else slot = O_UP_IN_AIR; + put_to_pack(slot); + Command_Duration+=5; + break; + case 's': + display_pack(); + usedmenu = true; + Command_Duration+=5; + break; + case 't': + slot = get_inventory_slot(); + (void) take_from_pack(slot,false); + Command_Duration+=5; + break; + case 'e': + slot = get_inventory_slot(); + if ( slot == O_UP_IN_AIR ) break; + switch_to_slot(slot); + Command_Duration+=2; + break; + case 'x': + slot = get_inventory_slot(); + if ( slot == O_UP_IN_AIR ) break; + switch_to_slot(slot); + Command_Duration+=2; + done = (Player.possessions[O_UP_IN_AIR] == NULL); + break; + case '~': + display_possessions(); + inventory_control(); + usedmenu = true; + done = true; + break; + case '?': + menuclear(); + menuprint("d:\tDrop an item\n"); + menuprint("e:\tExchange a slot with up-in-air slot\n"); + menuprint("l:\tLook at an item\n"); + menuprint("p:\tPut an item in pack\n"); + menuprint("s:\tShow contents of pack\n"); + menuprint("t:\tTake something from pack into a slot\n"); + menuprint("x:\tAs 'e', above, exit if up-in-air slot finishes empty\n"); + menuprint("~:\tEnter full-screen inventory mode\n"); + menuprint("?:\tDisplay help (this message + help file)\n"); + menuprint("ESCAPE:\texit\n"); + showmenu(); + clearmsg(); + print1("Display full help? (y/n)"); + if (ynq1() == 'y') + inv_help(); + usedmenu=true; + break; + case ESCAPE: + clearmsg(); + if (Player.possessions[O_UP_IN_AIR] != NULL) { + drop_at(Player.x,Player.y,Player.possessions[O_UP_IN_AIR]); + Player.possessions[O_UP_IN_AIR] = NULL; + print3("Object 'up in air' dropped."); + } + done = true; + break; + } + calc_melee(); + } while (! done); + if (usedmenu) + xredraw(); +} + + + +/* Let the user select a slot. */ +int get_inventory_slot(void) +{ + signed char response; + do { + clearmsg1(); + print1("Which inventory slot ['-'='up-in-air' slot]?"); + response = (signed char)mcigetc(); + if ( response == ESCAPE || response == '-' ) + return O_UP_IN_AIR; + else response = key_to_index(response); + } while (response != O_UP_IN_AIR); + return response; +} + + +/* returns some number between 0 and o->number */ +int get_item_number(Object* o) +{ + int n=0; + if (o->number == 1) + return 1; + do { + clearmsg(); + print1("How many? -- max "); + mnumprint(o->number); + nprint1(" :"); + n = (int) parsenum(""); + if (n>o->number) print3("Too many!"); + else if (n<1) n = 0; + } while (n > o->number); + if (n < 1) n = 0; + return(n); +} + +void drop_from_slot(int slot) +{ + int n,waitflag; + if (Player.possessions[slot] != NULL) { + if(Player.possessions[slot]->isCursed() && Player.possessions[slot]->isUsed()) + print3("It sticks to your fingers!"); + else { + n = get_item_number(Player.possessions[slot]); + if (n > 0) { + p_drop_at(Player.x,Player.y,n,Player.possessions[slot]); + waitflag = (Player.possessions[slot]->used && + (Player.possessions[slot]->number == n)); + conform_lost_objects(n,Player.possessions[slot]); + if (waitflag) morewait(); + } + else print3("Didn't drop anything."); + } + } + else print3("Didn't drop anything."); +} + + +void put_to_pack(int slot) +{ + int waitflag,num = 1; + Object *temp,*oslot = Player.possessions[slot]; + if (oslot == NULL) + print3("Slot is empty!"); + else if (oslot != NULL && oslot->isCursed() && oslot->isUsed()) + print3("Item is cursed!"); + else { + num = get_item_number(oslot); + if (num > 0) { + temp = split_item(num,oslot); + waitflag = (oslot->isUsed() && (oslot->number == num)); + conform_lost_objects(num,oslot); + if (waitflag) morewait(); + add_to_pack(temp); + } + } +} + + +/* splits num off of item to make newitem which is returned */ +/* something else (conform_lost_objects) has to reduce the actual + number value of item and Player.itemweight */ +Object* split_item(int num, Object* item) +{ + Object* newitem=NULL; + if (item != NULL) { + newitem = copy_obj( item ); + if (num <= item->number) + newitem->number = num; + /* else num > item->number, so return newitem with number = item->number */ + newitem->used = false; /* whether the original item was used or not */ + } + return(newitem); +} + + + +/* Trades contents of "up in air" slot with selected slot. One or both +may be null. If both slots are 'objequal' merges two groups into one +in the selected slot. If one slot is null and the number of the other +is greater than one, requests how many to move. */ + +void switch_to_slot(int slot) +{ + Object* oslot = Player.possessions[slot]; + Object* oair = Player.possessions[O_UP_IN_AIR]; + Object* otemp = NULL; + int slotnull,airnull,num=1,trade=false,put=false,take=false,merge=false; + int s2h=false,a2h=false; + + /* ie, is cursed and in use */ + if (slot == O_UP_IN_AIR) + print3("This action makes no sense!"); + else if (oslot != NULL && oslot->isCursed() && oslot->isUsed()) /* Check both via object methods */ + print3("The object in that slot is cursed -- you can't get rid of it!"); + else { + + slotnull = (oslot == NULL); + airnull = (oair == NULL); + + if (!slotnull) + s2h = (Player.possessions[O_READY_HAND] == + Player.possessions[O_WEAPON_HAND]); + + if (! airnull) + a2h = (twohandedp(oair->id) && + ((slot == O_READY_HAND) || (slot == O_WEAPON_HAND))); + + + /* figure out which action to take */ + + /* merge if both are same kind of object */ + merge = objequal(oslot,oair); + + take = ((!merge) && (!slotnull) && airnull); + + put = ((!merge) && slotnull && (!airnull) && slottable(oair,slot)); + + trade = ((!merge) && (!slotnull) && (!airnull) && slottable(oair,slot)); + + if (merge) merge_item(slot); + + else if (put) { + + /* deal with a 2-handed weapon */ + if (a2h) { + if (Player.possessions[O_READY_HAND] == NULL) + Player.possessions[O_READY_HAND] = oair; + if (Player.possessions[O_WEAPON_HAND] == NULL) + Player.possessions[O_WEAPON_HAND] = oair; + } + else Player.possessions[slot] = oair; + Player.possessions[O_UP_IN_AIR] = NULL; + if (item_useable(oair,slot)) { + oair->used = true; + item_use(oair); + inv_display_munge(); + morewait(); + if (oair->number > 1) pack_extra_items(oair); + } + Player.possessions[O_UP_IN_AIR] = NULL; + } + + else if (take) { + num = get_item_number(oslot); + if (num > 0) { + otemp = split_item(num,oslot); + dispose_lost_objects(num,oslot); + Player.possessions[O_UP_IN_AIR] = otemp; + } + if (s2h) { + if (Player.possessions[O_READY_HAND] == oslot) + Player.possessions[O_READY_HAND] = NULL; + if (Player.possessions[O_WEAPON_HAND] == oslot) + Player.possessions[O_WEAPON_HAND] = NULL; + } + } + + else if (trade) { + + /* first remove item from slot */ + num = oslot->number; + conform_lost_objects(oslot->number,oslot); + oslot->number = num; + + Player.possessions[O_UP_IN_AIR] = oslot; + + Player.possessions[slot] = oair; + + if (s2h) { + if (Player.possessions[O_READY_HAND] == oslot) + Player.possessions[O_READY_HAND] = NULL; + if (Player.possessions[O_WEAPON_HAND] == oslot) + Player.possessions[O_WEAPON_HAND] = NULL; + } + + if (a2h) { + if (Player.possessions[O_READY_HAND] == NULL) + Player.possessions[O_READY_HAND] = oair; + if (Player.possessions[O_WEAPON_HAND] == NULL) + Player.possessions[O_WEAPON_HAND] = oair; + } + + if (item_useable(oair,slot)) { + oair->used = true; + item_use(oair); + inv_display_munge(); + morewait(); + if (oair->number > 1) pack_extra_items(oair); + } + } + } +} + + + + +/* merges the up-in-air items into the selected items */ + +void merge_item(int slot) +{ + Player.possessions[slot]->number += + Player.possessions[O_UP_IN_AIR]->number; + Player.possessions[O_UP_IN_AIR] = NULL; +} + + +/* are two objects equal except for their number field? */ +/* returns false if either object is null */ +int objequal(Object* o, Object* p) +{ + if ((o == NULL) || (p == NULL)) return(false); + else return( + (o->id == p->id) && + /* DAG won't match corpses because they use charge for monster id, */ + /* except for hornets which have mid == 0, so will stack. Prevent this. */ + (o->id != CORPSEID) && + (o->plus == p->plus) && + (o->charge == 0) && + (p->charge == 0) && + (o->dmg == p->dmg) && + (o->hit == p->hit) && + (o->aux == p->aux) && + (o->known == p->known) && + (o->blessing == p->blessing) && + (o->usef == p->usef) && + (o->objstr == p->objstr ) + ); + +} + +/* criteria for being able to put some item in some slot */ +int slottable(Object* o, int slot) +{ + int ok = true; + if (o == NULL) ok = false; + else if (slot == O_ARMOR) { + if (o->objchar != ARMOR) { + print3("Only armor can go in the armor slot!"); + ok = false; + } + } + else if (slot == O_SHIELD) { + if (o->objchar != SHIELD) { + print3("Only a shield can go in the shield slot!"); + ok = false; + } + } + else if (slot == O_BOOTS) { + if (o->objchar != BOOTS) { + print3("Only boots can go in the boots slot!"); + ok = false; + } + } + else if (slot == O_CLOAK) { + if (o->objchar != CLOAK) { + print3("Only a cloak can go in the cloak slot!"); + ok = false; + } + } + else if (slot >= O_RING1) { + if (o->objchar != RING) { + print3("Only a ring can go in a ring slot!"); + ok = false; + } + } + return(ok); +} + + +/* whether or not an item o can be used in a slot. Assumes o can in + fact be placed in the slot. */ +int item_useable(Object* o, int slot) +{ + /* don't have to check the object in the first if since only armor + can go in armor slot, cloak in cloak slot, etc */ + + if ((slot == O_ARMOR) || + (slot == O_CLOAK) || + (slot == O_SHIELD) || + (slot == O_BOOTS) || + (slot >= O_RING1)) + return(true); + + /* weapon is useable if it is put in weapon hand or if it is two-handed + and put in either hand when the other also holds the weapon */ + + else if ((o->objchar == WEAPON) || + (o->objchar == MISSILEWEAPON)) { + if (twohandedp(o->id) && + ((slot==O_READY_HAND)||(slot==O_WEAPON_HAND))) { + if (Player.possessions[O_READY_HAND] == + Player.possessions[O_WEAPON_HAND]) { + print1("You heft the weapon and find you must use both hands."); + morewait(); + return(true); + } + else { + print1("This weapon is two-handed, so at the moment, "); + print2("you are just lugging it around...."); + morewait(); + return(false); + } + } + else return(slot == O_WEAPON_HAND); + } + else return(false); +} + +/* returns true if item with id and charge is found in pack or in + inventory slot. charge is used to differentiate + corpses instead of aux, which is their food value. */ +int find_item(Object* *o, int id, int chargeval) +{ + int i,found=false; + *o=NULL; + for(i=1; ((iid == id) && + ((chargeval == -1) || + (Player.possessions[i]->charge == chargeval))) { + *o = Player.possessions[i]; + found = true; + } + if (! found) + for(i=0; ((iid == id) && + ((chargeval == -1) || + (Player.pack[i]->charge == chargeval))) { + *o = Player.pack[i]; + found = true; + } + return(found); +} + +/* returns true if item with id and charge is found in pack or in + inventory slot. Destroys item. charge is used to differentiate + corpses instead of aux, which is their food value. */ +int find_and_remove_item(int id, int chargeval) +{ + int i,found=false; + Object* o=NULL; + + for(i=1; ((iid == id) && + ((chargeval == -1) || + (Player.possessions[i]->charge == chargeval))) { + o = Player.possessions[i]; + conform_lost_objects(1, o); + found = true; + } + if (! found) for(i=0; ((iid == id) && + ((chargeval == -1) || + (Player.pack[i]->charge == chargeval))) { + Player.pack[i]->number--; + if (Player.pack[i]->number == 0) { + free_obj( Player.pack[i], true ); + Player.pack[i] = NULL; + } + found = true; + } + fixpack(); + return(found); +} + + +void lose_all_items(void) +{ + int i; + print1("You notice that you are completely devoid of all possessions."); + morewait(); + for(i=0; inumber, + Player.possessions[i]); + Player.possessions[i] = NULL; + } + for(i=0; inumber = item->number-1; + extra->used = false; + item->number = 1; + if (Player.packptr < MAXPACK) { + print3("Putting extra items back in pack."); + morewait(); + push_pack(extra); + } + else if (Player.possessions[O_UP_IN_AIR] == NULL) { + print3("Extra copies of item are 'up in the air'"); + Player.possessions[O_UP_IN_AIR] = extra; + } + else { + print3("No room for extra copies of item -- dropping them."); + drop_at(Player.x,Player.y,extra); + } + calc_melee(); +} + + +/* makes sure Player.pack is OK, (used after sale from pack) */ +void fixpack(void) +{ + Object* tpack[MAXPACK]; + int i,tctr=0; + for(i=0; iid)) + { + display_inventory_slot(O_READY_HAND, topline); + display_inventory_slot(O_WEAPON_HAND, topline); + display_inventory_slot(slotnum, topline); + } + else + display_inventory_slot(slotnum, topline); + else + display_inventory_slot(slotnum, topline); +} diff --git a/Omega/src/map.cpp b/Omega/src/map.cpp index 968871b..3f997fd 100644 --- a/Omega/src/map.cpp +++ b/Omega/src/map.cpp @@ -1,208 +1,199 @@ -/* Copyright 2000 William D. Tanksley Jr., licensed under the terms of the - * Omega license as part of Omega. */ -#include "glob.h" - -#define MAP_VERSION 2 -#define MAP_HEADER_SIZE 3 -#define MAP_ITEM_SIZE 9 - -/* I plan to eventually make this code handle ALL map loading, since map - * loading is largely similar. However, to keep from biting off more than - * I can chew, I'm going to start by doing just a little bit at a time. - * - * For starters, I'm just going to have this load the map, and that's all. */ -struct symbolMapping -{ - /* Which L_* to assign this character to. */ - int locationFunction; - /* What argument (if any) to give to the function which constructs that - * location. */ - int argument; -}; - -struct map_type -{ - int length, width, depth, offset; - char *sites; -#if 0 - struct symbolMapping symbols[128-32]; /* Only printable characters. - * This does assume ASCII. */ -#endif -}; - -void error(char *explanation, ...) -{ - va_list ap; - - va_start (ap, explanation); - vfprintf (stderr, explanation, ap); - va_end (ap); - abort(); -} - -int fgetint(FILE *f) -{ - int x; - assert(sizeof(int) == 4); /* This assumption is explicit here, but it's - * also elsewhere. */ - x = fgetc(f) &0x000000FF; - x|= (fgetc(f) << 8) &0x0000FF00; - x|= (fgetc(f) <<16) &0x00FF0000; - x|= (fgetc(f) <<24) &0xFF000000; - - if ( feof(f) ) - error("Unexpected end of file while parsing binary file."); - - return x; -} - -int fgetshort(FILE *f) -{ - int x; - assert(sizeof(int) == 4); /* This assumption is explicit here, but it's - * also elsewhere. */ - x = fgetc(f) &0x000000FF; - x|= (fgetc(f) << 8) &0x0000FF00; - - if ( feof(f) ) - error("Unexpected end of file while parsing binary file."); - - return x; -} - -void decode(char **data, int *length) -{ - /* just testing... Place a sophisticated BWT here. */ -} - -int map_getWidth(map *m) -{ - return m->width; -} - -int map_getLength(map *m) -{ - return m->length; -} - -int map_getDepth(map *m) -{ - return m->depth; -} - -/* Read in the indicated sublevel of the current map. Called from - * map_setLevel. */ -void map_read(map *m, FILE *in, int subLevel) -{ - int size; - - if ( subLevel > m->depth || subLevel < 0 ) - error("map has only %d levels; game requested level %d.\n", - m->depth, subLevel); - - /* Seek to the location of the data (as previously calculated). */ - fseek(in,m->offset,SEEK_SET); - - do { - /* Read in the size of the next submap, and if it wasn't the one - * we're looking for, skip past it. */ - size = fgetshort(in); - if ( subLevel ) - fseek(in, size, SEEK_CUR); - } while ( subLevel-- ); - - /* We now know that we're looking at the right map, and we know its size. */ - /* Read the encoding of the level into a buffer. */ - m->sites = (char*) malloc(size); - fread(m->sites,size,1,in); - - /* Decode the level. */ - decode(&m->sites,&size); - - if ( size != m->length*m->width ) - error("Map had invalid size: expected %d, got %d.\n", - m->length*m->width, size); -} - -/* Read the map info out of the header of the mapfile, and load it into - * the map. */ -void map_readDimensions(map *m, FILE *in, enum map_identifier map) -{ - int version, maps, items, this_map; - - version = fgetc(in); /* The file version */ - if ( version != MAP_VERSION ) - error("Mapfile version mismatch: expected %d, got %d.\n", - MAP_VERSION, version); - - maps = fgetshort(in); /* The number of maps it's supposed to contain */ - - items = 0; - do { - this_map = fgetshort(in); - m->width = fgetc(in); - m->length = fgetc(in); - m->depth = fgetc(in); - m->offset = fgetint(in); - items++; - } while (this_map != map && items < maps); - - if ( (items == maps) && (this_map != map) ) - error("Map #%d was not found in mapfile.\n", map ); - - /* The offset stored in the file was the offset from the end of the table of - * contents. Fix that to be an absolute offset. */ - m->offset += MAP_HEADER_SIZE + maps*MAP_ITEM_SIZE; -} - -map *map_open(enum map_identifier mapNumber) -{ - map *m = (map*) malloc( sizeof(map) ); - FILE *fd; - - strcpy(Str3,Omegalib); - strcat(Str3,"maps.dat"); - fd = checkfopen(Str3,"rb"); - - map_readDimensions(m,fd,mapNumber); - - fclose(fd); - return m; -} - -void map_setLevel(map *m, int levelNumber) -{ - FILE *fd; - - strcpy(Str3,Omegalib); - strcat(Str3,"maps.dat"); - fd = checkfopen(Str3,"rb"); - - map_read(m,fd,levelNumber); - - fclose(fd); -} - -void map_close(map *m) -{ - free(m->sites); - free(m); -} - -#if 0 -/* Using the mappings given in this map structure, build an Omega - * level, using appropriate terrain. */ -void map_buildLevel(map *m, Level *lev) -{ - -} -#endif - -char map_getSiteChar(map *m, int i, int j) -{ - assert(i < m->width); - assert(j < m->length); - assert(m->sites[j*m->width + i]); - return m->sites[j*m->width + i]; -} - +/* Copyright 2000 William D. Tanksley Jr., licensed under the terms of the + * Omega license as part of Omega. */ +#include "glob.h" + +#define MAP_VERSION 2 +#define MAP_HEADER_SIZE 3 +#define MAP_ITEM_SIZE 9 + +/* I plan to eventually make this code handle ALL map loading, since map + * loading is largely similar. However, to keep from biting off more than + * I can chew, I'm going to start by doing just a little bit at a time. + * + * For starters, I'm just going to have this load the map, and that's all. */ +struct symbolMapping +{ + /* Which L_* to assign this character to. */ + int locationFunction; + /* What argument (if any) to give to the function which constructs that + * location. */ + int argument; +}; + +struct map_type +{ + int length, width, depth, offset; + char *sites; +#if 0 + struct symbolMapping symbols[128-32]; /* Only printable characters. + * This does assume ASCII. */ +#endif +}; + +void error(char *explanation, ...) +{ + va_list ap; + + va_start (ap, explanation); + vfprintf (stderr, explanation, ap); + va_end (ap); + abort(); +} + +int fgetint(FILE *f) +{ + int x; + assert(sizeof(int) == 4); /* This assumption is explicit here, but it's + * also elsewhere. */ + x = fgetc(f) &0x000000FF; + x|= (fgetc(f) << 8) &0x0000FF00; + x|= (fgetc(f) <<16) &0x00FF0000; + x|= (fgetc(f) <<24) &0xFF000000; + + if ( feof(f) ) + error("Unexpected end of file while parsing binary file."); + + return x; +} + +int fgetshort(FILE *f) +{ + int x; + assert(sizeof(int) == 4); /* This assumption is explicit here, but it's + * also elsewhere. */ + x = fgetc(f) &0x000000FF; + x|= (fgetc(f) << 8) &0x0000FF00; + + if ( feof(f) ) + error("Unexpected end of file while parsing binary file."); + + return x; +} + +void decode(char **data, int *length) +{ + /* just testing... Place a sophisticated BWT here. */ +} + +int map_getWidth(map *m) +{ + return m->width; +} + +int map_getLength(map *m) +{ + return m->length; +} + +int map_getDepth(map *m) +{ + return m->depth; +} + +/* Read in the indicated sublevel of the current map. Called from + * map_setLevel. */ +void map_read(map *m, FILE *in, int subLevel) +{ + int size; + + if ( subLevel > m->depth || subLevel < 0 ) + error("map has only %d levels; game requested level %d.\n", + m->depth, subLevel); + + /* Seek to the location of the data (as previously calculated). */ + fseek(in,m->offset,SEEK_SET); + + do { + /* Read in the size of the next submap, and if it wasn't the one + * we're looking for, skip past it. */ + size = fgetshort(in); + if ( subLevel ) + fseek(in, size, SEEK_CUR); + } while ( subLevel-- ); + + /* We now know that we're looking at the right map, and we know its size. */ + /* Read the encoding of the level into a buffer. */ + m->sites = (char*) malloc(size); + fread(m->sites,size,1,in); + + /* Decode the level. */ + decode(&m->sites,&size); + + if ( size != m->length*m->width ) + error("Map had invalid size: expected %d, got %d.\n", + m->length*m->width, size); +} + +/* Read the map info out of the header of the mapfile, and load it into + * the map. */ +void map_readDimensions(map *m, FILE *in, enum map_identifier map) +{ + int version, maps, items, this_map; + + version = fgetc(in); /* The file version */ + if ( version != MAP_VERSION ) + error("Mapfile version mismatch: expected %d, got %d.\n", + MAP_VERSION, version); + + maps = fgetshort(in); /* The number of maps it's supposed to contain */ + + items = 0; + do { + this_map = fgetshort(in); + m->width = fgetc(in); + m->length = fgetc(in); + m->depth = fgetc(in); + m->offset = fgetint(in); + items++; + } while (this_map != map && items < maps); + + if ( (items == maps) && (this_map != map) ) + error("Map #%d was not found in mapfile.\n", map ); + + /* The offset stored in the file was the offset from the end of the table of + * contents. Fix that to be an absolute offset. */ + m->offset += MAP_HEADER_SIZE + maps*MAP_ITEM_SIZE; +} + +map *map_open(enum map_identifier mapNumber) +{ + map *m = (map*) malloc( sizeof(map) ); + FILE *fd; + + strcpy(Str3,Omegalib); + strcat(Str3,"maps.dat"); + fd = checkfopen(Str3,"rb"); + + map_readDimensions(m,fd,mapNumber); + + fclose(fd); + return m; +} + +void map_setLevel(map *m, int levelNumber) +{ + FILE *fd; + + strcpy(Str3,Omegalib); + strcat(Str3,"maps.dat"); + fd = checkfopen(Str3,"rb"); + + map_read(m,fd,levelNumber); + + fclose(fd); +} + +void map_close(map *m) +{ + free(m->sites); + free(m); +} + +char map_getSiteChar(map *m, int i, int j) +{ + assert(i < m->width); + assert(j < m->length); + assert(m->sites[j*m->width + i]); + return m->sites[j*m->width + i]; +} + diff --git a/Omega/src/move.cpp b/Omega/src/move.cpp index d55d342..ed2a705 100644 --- a/Omega/src/move.cpp +++ b/Omega/src/move.cpp @@ -1,1185 +1,1178 @@ -/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ -/* move.c */ -/* general functions for player moving */ - -#include "glob.h" - -/* various miscellaneous location functions */ -void l_water(void) -{ - if (! State.getMounted()) { - if ((Player.possessions[O_ARMOR] != NULL)) { - print1("Your heavy armor drags you under the water!"); - morewait(); - p_drown(); - print2("You reach the surface again."); - } - else if (Player.itemweight > ((int) (Player.maxweight / 2))) { - print1("The weight of your burden drags you under water!"); - morewait(); - p_drown(); - print2("You reach the surface again."); - } - else switch(random_range(32)) { - case 0: - print1("Splish. Splash!"); - break; - case 1: - print1("I want my ducky!"); - break; - case 2: - print1("So finally you take a bath!"); - break; - case 3: - print1("You must be very thirsty!"); - break; - } - } - else switch(random_range(32)) { - case 0: - print1("Your horse frolics playfully in the water."); - break; - case 1: - print1("Your horse quenches its thirst."); - break; - case 2: - print1("Your steed begins to swim...."); - break; - case 3: - print1("Your mount thrashes about in the water."); - break; - } -} - - - -void l_chaos(void) -{ - if (State.getMounted()) { - print1("Your steed tries to swim in the raw Chaos, but seems to"); - print2("be having some difficulties..."); - morewait(); - print1("probably because it's just turned into a chaffinch."); - morewait(); - State.setMounted(false); - } - if (! onewithchaos) - print1("You are immersed in raw Chaos...."); - if (Player.rank[ADEPT]) { - if (! onewithchaos) - { - onewithchaos = 1; - print2("You achieve oneness of Chaos...."); - } - Player.mana = max(Player.mana,calcmana()); - Player.hp = max(Player.hp, Player.maxhp); - } - else if (onewithchaos) /* adept that gets amnesia from chaos storm */ - { - print2("The chaos sea doesn't seem to bother you at all."); - } - else if (Player.rank[PRIESTHOOD] && (! saved)) { - print2("A mysterious force protects you from the Chaos!"); - print3("Wow.... You feel a bit smug."); - gain_experience(500); - saved = true; - } - else { - print2("Uh oh...."); - if (saved) nprint2("Nothing mysterious happens this time...."); - morewait(); - print1("Congratulations! You've achieved maximal entropy!"); - Player.alignment -= 50; - gain_experience(1000); - p_death("immersion in raw Chaos"); - } -} - - - - -void l_hedge(void) -{ - if (Player.patron == DRUID) print1("You move through the hedges freely."); - else { - print1("You struggle in the brambly hedge... "); - switch(random_range(6)) { - case 0: - print2("You are stabbed by thorns!"); - p_damage(random_range(6),NORMAL_DAMAGE,"a hedge"); - print3("The thorns were poisonous!"); - p_poison(random_range(12)); - break; - case 1: - print2("You are stabbed by thorns!"); - p_damage(random_range(12),NORMAL_DAMAGE,"a hedge"); - break; - case 2: - print2("You seem to have gotten stuck in the hedge."); - Player.status[IMMOBILE]+=random_range(5)+1; - break; - case 3: - if (Player.possessions[O_CLOAK] != NULL) { - print2("Your cloak was torn on the brambles!"); - dispose_lost_objects(1,Player.possessions[O_CLOAK]); - } - else print2("Ouch! These thorns are scratchy!"); - break; - default: - print2("You make your way through unscathed."); - break; - } - } -} - - - -void l_lava(void) -{ - print1("Very clever -- walking into a pool of lava..."); - if (State.getMounted()) { - print2("Your horse is incinerated... You fall in too!"); - State.setMounted(false); - } - morewait(); - if (strcmp(Player.name,"Saltheart Foamfollower")==0) { - print1("Strangely enough, you don't seem terribly affected."); - p_damage(1,UNSTOPPABLE,"slow death in a pool of lava"); - } - else { - p_damage(random_range(75),FLAME,"incineration in a pool of lava"); - if (Player.hp> 0) p_drown(); - Player.status[IMMOBILE]+=2; - } -} - - - -void l_fire(void) -{ - print1("You boldly stride through the curtain of fire..."); - if (State.getMounted()) { - print2("Your horse is fried and so are you..."); - State.setMounted(false); - } - p_damage(random_range(100),FLAME,"self-immolation"); -} - -void l_abyss(void) -{ - int i; - if (Current_Environment != Current_Dungeon) { - print1("You fall through a dimensional portal!"); - morewait(); - strategic_teleport(-1); - } - else { - print1("You enter the infinite abyss!"); - morewait(); - if (random_range(100)==13) { - print1("As you fall you see before you what seems like"); - print2("an infinite congerie of iridescent bubbles."); - print3("You have met Yog Sothoth!!!"); - morewait(); - clearmsg(); - if (Player.alignment > -10) - p_death("the Eater of Souls"); - else { - print1("The All-In-One must have taken pity on you."); - print2("A transdimensional portal appears..."); - morewait(); - change_level(Level->depth,Level->depth+1,false); - gain_experience(2000); - Player.alignment -= 50; - } - } - else { - i = 0; - print1("You fall..."); - while(random_range(3)!=2) { - if (i%6 == 0) - print2("and fall... "); - else - nprint2("and fall... "); - i++; - morewait(); - } - i++; - print1("Finally,you emerge through an interdimensional interstice..."); - morewait(); - if (Level->depth+i>MaxDungeonLevels) { - print2("You emerge high above the ground!!!!"); - print3("Yaaaaaaaah........"); - morewait(); - change_environment(E_COUNTRYSIDE); - do { - setPlayerXY( random_range(COUNTRY_WIDTH), random_range(COUNTRY_LENGTH)); - } while(Country[Player.x][Player.y].base_terrain_type == CHAOS_SEA); - p_damage(i*50,NORMAL_DAMAGE,"a fall from a great height"); - } - else { - print2("You built up some velocity during your fall, though...."); - morewait(); - p_damage(i*5,NORMAL_DAMAGE,"a fall through the abyss"); - change_level(Level->depth,Level->depth+i,false); - gain_experience(i*i*50); - } - } - } -} - - -void l_lift(void) -{ - char response; - int levelnum; - int distance; - int too_far = 0; - - Level->site[Player.x][Player.y].locchar = FLOOR; - Level->site[Player.x][Player.y].p_locf = L_NO_OP; - lset(Player.x, Player.y, CHANGED); - print1("You walk onto a shimmering disk...."); - print2("The disk vanishes, and a glow surrounds you."); - print3("You feel weightless.... You feel ghostly...."); - morewait(); - clearmsg(); - print1("Go up, down, or neither [u,d,ESCAPE] "); - do response = (char) mcigetc(); - while ((response != 'u') && - (response != 'd') && - (response != ESCAPE)); - if (response != ESCAPE) { - print1("How many levels?"); - levelnum = (int) parsenum(""); - if (levelnum > 6) { - too_far = 1; - levelnum = 6; - } - if (response == 'u' && Level->depth - levelnum < 1) { - distance = levelnum - Level->depth; - change_environment(E_COUNTRYSIDE); /* "you return to the countryside." */ - if (distance > 0) { - nprint1(".."); - print2("...and keep going up! You hang in mid air..."); - morewait(); - print3("\"What goes up...\""); - morewait(); - print3("Yaaaaaaaah........"); - p_damage(distance*10,NORMAL_DAMAGE,"a fall from a great height"); - } - return; - } - else if (response == 'd' && Level->depth + levelnum > MaxDungeonLevels) { - too_far = 1; - levelnum = MaxDungeonLevels - Level->depth; - } - if (levelnum == 0) { - print1("Nothing happens."); - return; - } - if (too_far) { - print1("The lift gives out partway..."); - print2("You rematerialize....."); - } - else - print1("You rematerialize....."); - change_level(Level->depth, - (response=='d' ? - Level->depth+levelnum : - Level->depth-levelnum), - false); - roomcheck(); - } -} - - -void l_magic_pool(void) -{ - int possibilities=random_range(100); - print1("This pool seems to be enchanted...."); - if (State.getMounted()) { - if (random_range(2)) { - print2("Your horse is polymorphed into a fig newton."); - State.setMounted(false); - } - else print2("Whatever it was, your horse enjoyed it...."); - } - else if (possibilities == 0) { - print1("Oh no! You encounter the DREADED AQUAE MORTIS..."); - if (random_range(1000) < Player.level*Player.level*Player.level) { - print2("The DREADED AQUAE MORTIS throttles you within inches...."); - print3("but for some reason chooses to let you escape."); - gain_experience(500); - Player.hp = 1; - } - else p_death("the DREADED AQUAE MORTIS!"); - } - else if (possibilities < 25) - augment(0); - else if (possibilities < 30) - augment(1); - else if (possibilities < 60) - augment(-1); - else if (possibilities < 65) - cleanse(1); - else if (possibilities < 80) { - if (Player.possessions[O_WEAPON_HAND] != NULL) { - print1("You drop your weapon in the pool! It's gone forever!"); - dispose_lost_objects(1,Player.possessions[O_WEAPON_HAND]); - } - else print1("You feel fortunate."); - } - else if (possibilities < 90) { - if (Player.possessions[O_WEAPON_HAND] != NULL) { - print1("Your weapon leaves the pool with a new edge...."); - Player.possessions[O_WEAPON_HAND]->plus += random_range(10)+1; - calc_melee(); - } - else print1("You feel unfortunate."); - } - else if (possibilities < 95) { - Player.hp += 10; - print1("You feel healthier after the dip..."); - } - else if (possibilities < 99) { - print1("Oooh, a tainted pool..."); - p_poison(10); - } - else if (possibilities == 99) { - print1("Wow! A pool of azoth!"); - heal(10); - cleanse(1); - Player.mana = calcmana()*3; - Player.str = (Player.maxstr++)*3; - } - print2("The pool seems to have dried up."); - Level->site[Player.x][Player.y].locchar = TRAP; - Level->site[Player.x][Player.y].p_locf = L_TRAP_PIT; - lset(Player.x, Player.y, CHANGED); -} - -void l_no_op(void) -{ -} - -void l_tactical_exit(void) -{ - if (optionp(CONFIRM)) { - if (cinema_confirm("You're about to leave this place.") != 'y') - return; - } - /* Free up monsters and items, and the level */ - free_level(Level); - Level = NULL; - if ((Current_Environment == E_TEMPLE) || - (Current_Environment == E_TACTICAL_MAP) ) - change_environment(E_COUNTRYSIDE); - else change_environment(Last_Environment); -} - -void l_rubble(void) -{ - int screwup = random_range(100) - (Player.agi + Player.level); - print1("You climb over the unstable pile of rubble...."); - if (screwup < 0) print2("No problem!"); - else { - print2("You tumble and fall in a small avalanche of debris!"); - print3("You're trapped in the pile!"); - Player.status[IMMOBILE]+=2; - p_damage(screwup/5,UNSTOPPABLE,"rubble and debris"); - morewait(); - } -} - -/* Drops all portcullises in 5 moves */ -void l_portcullis_trap(void) -{ - int i,j,slam=false; - - print3("Click."); - morewait(); - for (i=max(Player.x-5,0); ilevel_width); i++) - for(j=max(Player.y-5,0); jlevel_length); j++) { - if ((Level->site[i][j].p_locf == L_PORTCULLIS) && - (Level->site[i][j].locchar != PORTCULLIS)) { - Level->site[i][j].locchar = PORTCULLIS; - lset(i, j, CHANGED); - putspot(i,j,PORTCULLIS); - if ((i==Player.x)&&(j==Player.y)) { - print3("Smash! You've been hit by a falling portcullis!"); - morewait(); - p_damage(random_range(1000),NORMAL_DAMAGE,"a portcullis"); - } - slam = true; - } - } - if (slam) print3("You hear heavy walls slamming down!"); -} - -/* drops every portcullis on level, then kills itself and all similar traps. */ -void l_drop_every_portcullis(void) -{ - int i,j,slam=false; - - print3("Click."); - morewait(); - for(j=0; jlevel_length; j++) - for(i=0; ilevel_width; i++) { - if (Level->site[i][j].p_locf == L_DROP_EVERY_PORTCULLIS) { - Level->site[i][j].p_locf = L_NO_OP; - lset(i, j, CHANGED); - } - else if ((Level->site[i][j].p_locf == L_PORTCULLIS) && - (Level->site[i][j].locchar != PORTCULLIS)) { - Level->site[i][j].locchar = PORTCULLIS; - lset(i, j, CHANGED); - putspot(i,j,PORTCULLIS); - if ((i==Player.x)&&(j==Player.y)) { - print3("Smash! You've been hit by a falling portcullis!"); - morewait(); - p_damage(random_range(1000),NORMAL_DAMAGE,"a portcullis"); - } - slam = true; - } - } - if (slam) print3("You hear heavy walls slamming down!"); -} - - - -void l_raise_portcullis(void) -{ - int i,j,open=false; - for(j=0; jlevel_length; j++) - for(i=0; ilevel_width; i++) { - if (Level->site[i][j].locchar == PORTCULLIS) { - Level->site[i][j].locchar = FLOOR; - lset(i, j, CHANGED); - putspot(i,j,FLOOR); - open = true; - } - } - if (open) print1("You hear the sound of steel on stone!"); -} - - -void l_arena_exit(void) -{ - State.setInArena( false ); -#if !defined(WIN32) - free_level(Level); -#endif - Level = NULL; - change_environment(E_CITY); -} - - -void l_house_exit(void) -{ - if (optionp(CONFIRM)) { - clearmsg(); - if (cinema_confirm("You're about to step out of this abode.") != 'y') - return; - } -#if !defined(WIN32) - free_level(Level); -#endif - Level = NULL; - change_environment(Last_Environment); -} - - -void l_void(void) -{ - clearmsg(); - print1("Geronimo!"); - morewait(); - clearmsg(); - print1("You leap into the void."); - if (Level->mlist) { - print2("Death peers over the edge and gazes quizzically at you...."); - morewait(); - print3("'Bye-bye,' he says... 'We'll meet again.'"); - } - morewait(); - while(Player.hp>0) { - Time+=60; - hourly_check(); - /* WDT: GCC doesn't like usleep being included from unistd.h when it's - * checking for ANSI compliance. That's the stupidest thing I've seen, - * but I wasn't offered a choice -- the man pages don't document any other - * options. - * Fortunately, this is a bad use of usleep, so commenting it out won't - * hurt the game, and might even help it. */ - /* usleep(250000);*/ - } -} - - -void l_fire_station(void) -{ - print1("The flames leap up, and the heat is incredible."); - if (Player.immunity[FLAME]) { - print2("You feel the terrible heat despite your immunity to fire!"); - morewait(); - } - print2("Enter the flames? [yn] "); - if (ynq2()=='y') { - if (Player.hp == 1) p_death("total incineration"); - else Player.hp = 1; - dataprint(); - print1("You feel like you are being incinerated! Jump back? [yn] "); - if (ynq1()=='y') - print2("Phew! That was close!"); - else { - Player.pow -= (15+random_range(15)); - if (Player.pow > 0) { - print2("That's odd, the flame seems to have cooled down now...."); - print3("A flicker of fire seems to dance above the void nearby."); - Level->site[Player.x][Player.y].locchar = FLOOR; - Level->site[Player.x][Player.y].p_locf = L_NO_OP; - stationcheck(); - } - else { - print2("The flames seem to have leached away all your mana!"); - p_death("the Essence of Fire"); - } - } - } - else print2("You flinch away from the all-consuming fire."); -} - - - - -void l_water_station(void) -{ - print1("The fluid seems murky and unknowably deep."); - print2("It bubbles and hisses threateningly."); - morewait(); - if (Player.status[BREATHING]) { - print1("You don't feel sanguine about trying to breathe that stuff!"); - morewait(); - } - if (Player.immunity[ACID]) { - print2("The vapor burns despite your immunity to acid!"); - morewait(); - } - print1("Enter the fluid? [yn] "); - if (ynq1()=='y') { - if (Player.hp == 1) p_death("drowning in acid (ick, what a way to go)"); - else Player.hp = 1; - dataprint(); - print2("You choke...."); - morewait(); - nprint2("Your lungs burn...."); - morewait(); - print2("Your body begins to disintegrate.... Leave the pool? [yn] "); - if (ynq2()=='y') - print2("Phew! That was close!"); - else { - clearmsg(); - Player.con -= (15+random_range(15)); - if (Player.con > 0) { - print1("That's odd, the fluid seems to have been neutralized...."); - print2("A moist miasma wafts above the void nearby."); - Level->site[Player.x][Player.y].locchar = FLOOR; - Level->site[Player.x][Player.y].p_locf = L_NO_OP; - stationcheck(); - } - else { - print2("The bubbling fluid has destroyed your constitution!"); - p_death("the Essence of Water"); - } - } - - } - else print2("You step back from the pool of acid."); -} - - - - -void l_air_station(void) -{ - print1("The whirlwind spins wildly and crackles with lightning."); - if (Player.immunity[ELECTRICITY]) - print2("You feel static cling despite your immunity to electricity!"); - morewait(); - print1("Enter the storm? [yn] "); - if (ynq1()=='y') { - if (Player.hp == 1) p_death("being torn apart and then electrocuted"); - else Player.hp = 1; - dataprint(); - print1("You are buffeted and burnt by the storm...."); - print2("You begin to lose consciousness.... Leave the storm? [yn] "); - if (ynq1()=='y') - print2("Phew! That was close!"); - else { - Player.iq -= (random_range(15)+15); - if (Player.iq > 0) { - print1("That's odd, the storm subsides...."); - print2("A gust of wind brushes past the void nearby."); - Level->site[Player.x][Player.y].locchar = FLOOR; - Level->site[Player.x][Player.y].p_locf = L_NO_OP; - stationcheck(); - } - else { - print2("The swirling storm has destroyed your intelligence!"); - p_death("the Essence of Air"); - } - } - } - else print2("You step back from the ominous whirlwind."); -} - - - - -void l_earth_station(void) -{ - Object* o; - print1("The tendrilled mass reaches out for you from the muddy ooze."); - if (find_item(&o,OB_SALT_WATER,-1)) - print2("A splash of salt water does nothing to dissuade the vines."); - morewait(); - print1("Enter the overgrown mire? [yn] "); - if (ynq1()=='y') { - if (Player.hp == 1) p_death("being eaten alive"); - else Player.hp = 1; - dataprint(); - print1("You are being dragged into the muck. Suckers bite you...."); - print2("You're about to be entangled.... Leave the mud? [yn] "); - if (ynq2()=='y') - print2("Phew! That was close!"); - else { - Player.str -= (15+random_range(15)); - if (Player.str > 0) { - print1("That's odd, the vine withdraws...."); - print2("A spatter of dirt sprays into the void nearby."); - Level->site[Player.x][Player.y].locchar = FLOOR; - Level->site[Player.x][Player.y].p_locf = L_NO_OP; - stationcheck(); - } - else { - print2("The tendril has destroyed your strength!"); - p_death("the Essence of Earth"); - } - } - } - else print2("You step back from the ominous vegetation."); -} - -void stationcheck(void) -{ - int stationsleft=false; - int i,j; - morewait(); - clearmsg(); - print1("You feel regenerated."); - Player.hp = Player.maxhp; - dataprint(); - for(j=0; jlevel_length; j++) - for(i=0; ilevel_width; i++) - if ((Level->site[i][j].locchar == WATER) || - (Level->site[i][j].locchar == HEDGE) || - (Level->site[i][j].locchar == WHIRLWIND) || - (Level->site[i][j].locchar == FIRE)) - stationsleft=true; - if (! stationsleft) { - print1("There is a noise like a wild horse's neigh."); - print2("You spin around, and don't see anyone around at all"); - print3("except for a spurred black cloaked figure carrying a scythe."); - morewait(); - clearmsg(); - print1("Death coughs apologetically. He seems a little embarrassed."); - print2("A voice peals out:"); - print3("'An Adept must be able to conquer Death himself...."); - make_site_monster(32,4,DEATH); - } -} - - -/* To survive the void, the other four stations must be visited first, - to activate the void, then something (Death's scythe, possibly) - must be thrown in to satiate the void, then all other items must - be dropped, then the void must be entered. */ - -void l_void_station(void) -{ - int i,something=false; - if (cinema_confirm("You're about to Peter Pan into an endless void.")=='y') { - if (Level->mlist == NULL) { - print2("You fall forever. Eventually you die of starvation."); - morewait(); - while(Player.hp>0) { - Time+=60; - hourly_check(); - usleep(250000); - } - } - else { - print1("You enter the void."); - print2("You feel a sudden surge of power from five directions."); - morewait(); - something = (Player.packptr > 0); - if (! something) - for(i=0; ((isite[Player.x][Player.y].p_locf = L_NO_OP; -} - -void l_voice2(void) -{ - print1("A strange voice recites: Enter the Void as you entered the World."); - Level->site[Player.x][Player.y].p_locf = L_NO_OP; -} - -void l_voice3(void) -{ - print1("An eerie voice resounds: The Void is the fifth Elemental Station."); - Level->site[Player.x][Player.y].p_locf = L_NO_OP; -} - - -void l_whirlwind(void) -{ - print1("Buffeting winds swirl you up!"); - p_damage(random_range(difficulty()*10),NORMAL_DAMAGE,"a magic whirlwind"); - if (random_range(2)) { - print2("You are jolted by lightning!"); - p_damage(random_range(difficulty()*10),ELECTRICITY,"a magic whirlwind"); - } - morewait(); - if (random_range(2)) { - print1("The whirlwind carries you off...."); - if (random_range(20)==17) - print2("'I don't think we're in Kansas anymore, toto.'"); - p_teleport(0); - } -} - - -void l_enter_circle(void) -{ - print1("You see a translucent stairway before you, leading down."); - print2("Take it? [yn] "); - if (ynq()=='y') - change_environment(E_CIRCLE); -} - -void l_circle_library(void) -{ - print1("You see before you the arcane library of the Circle of Sorcerors."); -} - -void l_tome1(void) -{ - menuclear(); - menuprint("\nYou discover in a dusty tome some interesting information...."); - menuprint("\nThe Star Gem holds a vast amount of mana, usable"); - menuprint("\nfor either Law or Chaos. It is magically linked to Star Peak"); - menuprint("\nand can either be activated or destroyed there. If destroyed,"); - menuprint("\nits power will be used for Chaos, if activated, for Law."); - menuprint("\n\nIt is said the LawBringer has waited for an eternity"); - menuprint("\nat Star Peak for someone to bring him the gem."); - menuprint("\nIt is also rumored that while anyone might destroy the gem,"); - menuprint("\nreleasing chaotic energy, only the LawBringer can release"); - menuprint("\nthe lawful potential of the gem."); - showmenu(); - morewait(); - xredraw(); -} - - -void l_tome2(void) -{ - menuclear(); - menuprint("\nYou discover in some ancient notes that the Star Gem can be"); - menuprint("\nused for transportation, but also read a caution that it must"); - menuprint("\nbe allowed to recharge a long time between uses."); - menuprint("\nA marginal note says 'if only it could be reset to go somewhere"); - menuprint("\nbesides Star Peak, the gem might be useful....'"); - showmenu(); - morewait(); - xredraw(); -} - - -void l_temple_warning(void) -{ - print1("A stern voice thunders in the air around you:"); - print2("'No unbelievers may enter these sacred precincts;"); - print3("those who defile this shrine will be destroyed!"); -} - -void l_throne(void) -{ - Object* o; - int i; - print1("You have come upon a huge ornately appointed throne!"); - print2("Sit in it? [yn] "); - if (ynq1()=='y') { - if (! find_item(&o,OB_SCEPTRE,-1)) { - print1("The throne emits an eerie violet-black radiance."); - print2("You find, to your horror, that you cannot get up!"); - print3("You feel an abstract sucking sensation..."); - for(i=0; isite[Player.x][Player.y].locchar = RUBBLE; - Level->site[Player.x][Player.y].p_locf = L_RUBBLE; - lset(Player.x, Player.y, CHANGED); - if (find_and_remove_item(OB_SCEPTRE,-1)) { - morewait(); - print1("Your sceptre reverberates with the noise, and"); - print2("it too explodes in a spray of shards."); - } - break; - } - calc_melee(); - dataprint(); - } - } - } -} - - -void l_escalator(void) -{ - print1("You have found an extremely long stairway going straight up."); - print2("The stairs are grilled steel and the bannister is rubber."); - morewait(); - print1("Take the stairway? [yn] "); - if (ynq1()=='y') { - print1("The stairs suddenly start moving with a grind of gears!"); - print2("You are wafted to the surface...."); - change_environment(E_COUNTRYSIDE); - } -} - -void l_enter_court(void) -{ - print1("You have found a magical portal! Enter it? [yn] "); - if (ynq1()=='y') { - if (State.getCompletedCastle() == false) { - if (State.getAttackedOracle() == false) { - print2("A dulcet voice says: 'Jolly good show!'"); - morewait(); - } - State.setCompletedCastle( true ); - } - change_environment(E_COURT); - } -} - -void l_chaostone(void) -{ - print1("This is a menhir carved of black marble with veins of gold."); - print2("It emanates an aura of raw chaos, which is not terribly"); - morewait(); - print1("surprising, considering its location."); - if (Player.alignment < 0) - print2("You feel an almost unbearable attraction to the stone."); - else print2("You find it extremely difficult to approach the stone."); - morewait(); - clearmsg(); - if (cinema_confirm("You reach out your fist to strike it.")=='y') { - print1("A sudden flux of energy surrounds you!"); - morewait(); - if (stonecheck(-1)) { - print2("You feel stronger!"); - Player.maxstr = min(Player.maxstr+10,max(30,Player.maxstr)); - dataprint(); - } - } - else print1("You step back from the ominous dolmech."); -} - - -void l_balancestone(void) -{ - print1("This is a massive granite slab teetering dangerously on a corner."); - print2("You feel a sense of balance as you regard it."); - morewait(); - clearmsg(); - if (cinema_confirm("Your hand naturally drifts forward to touch it.")=='y') { - print1("A vortex of mana spins about you!"); - if (abs(Player.alignment) > random_range(50)) { - print2("The cyclone whirls you off to a strange place!"); - morewait(); - change_environment(E_COUNTRYSIDE); - do { - setPlayerXY( random_range(COUNTRY_WIDTH), random_range(COUNTRY_LENGTH)); - } while (Country[Player.x][Player.y].current_terrain_type == CHAOS_SEA); - screencheck(Player.x,Player.y); - drawvision(Player.x,Player.y); - } - else { - print2("You are being drained of experience! Step back? [yn] "); - if (ynq2()=='y') { - clearmsg(); - print1("The vortex calms down, dimishes, and then disappears."); - } - else { - Player.xp -= Player.xp/4; - dataprint(); - print2("The vortex vanishes. Suddenly, there is a clap of thunder!"); - morewait(); - Player.alignment = 0; - strategic_teleport(1); - } - } - } - else print1("You step back from the unlikely boulder."); -} - - -void l_lawstone(void) -{ - print1("This is a stele carved of blueish-green feldspar."); - print2("You feel an aura of serenity rising from it, and your gaze"); - morewait(); - print1("is attracted to the bulk of Star Peak to the North-East."); - if (Player.alignment > 0) - print2("You feel a subtle attraction to the stone."); - else print2("You find the stone extremely distasteful to contemplate."); - morewait(); - clearmsg(); - if (cinema_confirm("Your arm moves as though compelled to grasp it.")=='y') { - print1("A matrix of power flows about you!"); - morewait(); - if (stonecheck(1)) { - print2("You feel more vigorous!"); - Player.maxcon = min(Player.maxcon+10,max(Player.maxcon,30)); - dataprint(); - } - } - else print1("You step back from the strange obelisk."); -} - - -void l_voidstone(void) -{ - int i; - print1("This is a grey and uninteresting stone."); - print2("A feeling of nihility emanates from it."); - morewait(); - clearmsg(); - if (cinema_confirm("You're about to touch it.")=='y') { - print1("You feel negated."); - morewait(); - Player.mana = 0; - toggle_item_use(true); - for(i=0; iblessing = 0; - Player.possessions[i]->plus = 0; - Player.possessions[i]->usef = I_NOTHING; - } - toggle_item_use(false); - calc_melee(); - } - else print1("You back away from the strange rock."); -} - -void l_sacrificestone(void) -{ - int sacrifice=1; - int oldmaxhp = Player.maxhp; - print1("You have come on a weathered basaltic block."); - print2("On the top surface is an indentation in human shape."); - morewait(); - print1("You see old rust colored stains in the grain of the stone."); - print2("You sense something awakening. Touch the block? [yn] "); - if (ynq2() == 'y') { - print1("You sense great pain emanating from the ancient altar."); - print2("Climb on to the block? [yn] "); - if (ynq2() == 'y') { - print1("You are stuck fast to the block!"); - print2("You feel your life-force being sucked away!"); - morewait(); - print1("Hit ESCAPE to try and get up at any moment, SPACE to remain."); - do { - switch(random_range(4)) { - case 0: - print2("You feel weaker."); - break; - case 1: - print2("You feel your life fading."); - break; - case 2: - print2("Your energy is vanishing."); - break; - case 3: - print2("You are being drained."); - break; - } - Player.hp -= sacrifice; - Player.maxhp -= sacrifice/2; - sacrifice *= 2; - dataprint(); - if ((Player.hp < 1) || (Player.maxhp < 1)) - p_death("self-sacrifice"); - } while (stillonblock()); - print1("You manage to wrench yourself off the ancient altar!"); - print2("You leave some skin behind, though...."); - morewait(); - if ((oldmaxhp > 10) && (Player.maxhp < 3 * oldmaxhp/4)) { - print1("A strange red glow arises from the altar."); - print2("The glow surrounds you.... You sense gratitude."); - Player.pow += sacrifice; - Player.maxpow += sacrifice/10; - dataprint(); - } - else { - print1("You a have a sense of rejection."); - print2("A roil of fetid vapor smokes up from the altar."); - gain_experience(sacrifice); - } - } - else { - print1("You sense an emotion of pique all around you."); - print2("You retreat from the strange stone."); - } - } - else { - print1("You decide discretion to be the better part of valour."); - print2("The stone seems to subside sleepily."); - } -} - -void l_mindstone(void) -{ - print1("You approach a giant crystal of some opaline material."); - print2("Flashes of irridescent light glint from the object."); - morewait(); - print1("You feel your attention being drawn by the intricate crystal."); - print2("Look away from the interesting phenomenon? [yn] "); - if (ynq2()=='n') { - print1("Your gaze focuses deeply on the gem...."); - print2("The crystal seems to open up and surround you!"); - morewait(); - if (stonecheck(0)) { - print1("Your mind has been enhanced by the experience!"); - Player.maxiq = min(Player.maxiq+10,max(Player.maxiq,30)); - dataprint(); - } - } - else { - print1("You manage to wrench your gaze from the odd jewel."); - print2("The light flashes from the crystal diminish in frequency."); - } -} +/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ +/* move.c */ +/* general functions for player moving */ + +#include "glob.h" + +/* various miscellaneous location functions */ +void l_water(void) +{ + if (! State.getMounted()) { + if ((Player.possessions[O_ARMOR] != NULL)) { + print1("Your heavy armor drags you under the water!"); + morewait(); + p_drown(); + print2("You reach the surface again."); + } + else if (Player.itemweight > ((int) (Player.maxweight / 2))) { + print1("The weight of your burden drags you under water!"); + morewait(); + p_drown(); + print2("You reach the surface again."); + } + else switch(random_range(32)) { + case 0: + print1("Splish. Splash!"); + break; + case 1: + print1("I want my ducky!"); + break; + case 2: + print1("So finally you take a bath!"); + break; + case 3: + print1("You must be very thirsty!"); + break; + } + } + else switch(random_range(32)) { + case 0: + print1("Your horse frolics playfully in the water."); + break; + case 1: + print1("Your horse quenches its thirst."); + break; + case 2: + print1("Your steed begins to swim...."); + break; + case 3: + print1("Your mount thrashes about in the water."); + break; + } +} + + + +void l_chaos(void) +{ + if (State.getMounted()) { + print1("Your steed tries to swim in the raw Chaos, but seems to"); + print2("be having some difficulties..."); + morewait(); + print1("probably because it's just turned into a chaffinch."); + morewait(); + State.setMounted(false); + } + if (! onewithchaos) + print1("You are immersed in raw Chaos...."); + if (Player.rank[ADEPT]) { + if (! onewithchaos) + { + onewithchaos = 1; + print2("You achieve oneness of Chaos...."); + } + Player.mana = max(Player.mana,calcmana()); + Player.hp = max(Player.hp, Player.maxhp); + } + else if (onewithchaos) /* adept that gets amnesia from chaos storm */ + { + print2("The chaos sea doesn't seem to bother you at all."); + } + else if (Player.rank[PRIESTHOOD] && (! saved)) { + print2("A mysterious force protects you from the Chaos!"); + print3("Wow.... You feel a bit smug."); + gain_experience(500); + saved = true; + } + else { + print2("Uh oh...."); + if (saved) nprint2("Nothing mysterious happens this time...."); + morewait(); + print1("Congratulations! You've achieved maximal entropy!"); + Player.alignment -= 50; + gain_experience(1000); + p_death("immersion in raw Chaos"); + } +} + + + + +void l_hedge(void) +{ + if (Player.patron == DRUID) print1("You move through the hedges freely."); + else { + print1("You struggle in the brambly hedge... "); + switch(random_range(6)) { + case 0: + print2("You are stabbed by thorns!"); + p_damage(random_range(6),NORMAL_DAMAGE,"a hedge"); + print3("The thorns were poisonous!"); + p_poison(random_range(12)); + break; + case 1: + print2("You are stabbed by thorns!"); + p_damage(random_range(12),NORMAL_DAMAGE,"a hedge"); + break; + case 2: + print2("You seem to have gotten stuck in the hedge."); + Player.status[IMMOBILE]+=random_range(5)+1; + break; + case 3: + if (Player.possessions[O_CLOAK] != NULL) { + print2("Your cloak was torn on the brambles!"); + dispose_lost_objects(1,Player.possessions[O_CLOAK]); + } + else print2("Ouch! These thorns are scratchy!"); + break; + default: + print2("You make your way through unscathed."); + break; + } + } +} + + + +void l_lava(void) +{ + print1("Very clever -- walking into a pool of lava..."); + if (State.getMounted()) { + print2("Your horse is incinerated... You fall in too!"); + State.setMounted(false); + } + morewait(); + if (strcmp(Player.name,"Saltheart Foamfollower")==0) { + print1("Strangely enough, you don't seem terribly affected."); + p_damage(1,UNSTOPPABLE,"slow death in a pool of lava"); + } + else { + p_damage(random_range(75),FLAME,"incineration in a pool of lava"); + if (Player.hp> 0) p_drown(); + Player.status[IMMOBILE]+=2; + } +} + + + +void l_fire(void) +{ + print1("You boldly stride through the curtain of fire..."); + if (State.getMounted()) { + print2("Your horse is fried and so are you..."); + State.setMounted(false); + } + p_damage(random_range(100),FLAME,"self-immolation"); +} + +void l_abyss(void) +{ + int i; + if (Current_Environment != Current_Dungeon) { + print1("You fall through a dimensional portal!"); + morewait(); + strategic_teleport(-1); + } + else { + print1("You enter the infinite abyss!"); + morewait(); + if (random_range(100)==13) { + print1("As you fall you see before you what seems like"); + print2("an infinite congerie of iridescent bubbles."); + print3("You have met Yog Sothoth!!!"); + morewait(); + clearmsg(); + if (Player.alignment > -10) + p_death("the Eater of Souls"); + else { + print1("The All-In-One must have taken pity on you."); + print2("A transdimensional portal appears..."); + morewait(); + change_level(Level->depth,Level->depth+1,false); + gain_experience(2000); + Player.alignment -= 50; + } + } + else { + i = 0; + print1("You fall..."); + while(random_range(3)!=2) { + if (i%6 == 0) + print2("and fall... "); + else + nprint2("and fall... "); + i++; + morewait(); + } + i++; + print1("Finally,you emerge through an interdimensional interstice..."); + morewait(); + if (Level->depth+i>MaxDungeonLevels) { + print2("You emerge high above the ground!!!!"); + print3("Yaaaaaaaah........"); + morewait(); + change_environment(E_COUNTRYSIDE); + do { + setPlayerXY( random_range(COUNTRY_WIDTH), random_range(COUNTRY_LENGTH)); + } while(Country[Player.x][Player.y].base_terrain_type == CHAOS_SEA); + p_damage(i*50,NORMAL_DAMAGE,"a fall from a great height"); + } + else { + print2("You built up some velocity during your fall, though...."); + morewait(); + p_damage(i*5,NORMAL_DAMAGE,"a fall through the abyss"); + change_level(Level->depth,Level->depth+i,false); + gain_experience(i*i*50); + } + } + } +} + + +void l_lift(void) +{ + char response; + int levelnum; + int distance; + int too_far = 0; + + Level->site[Player.x][Player.y].locchar = FLOOR; + Level->site[Player.x][Player.y].p_locf = L_NO_OP; + lset(Player.x, Player.y, CHANGED); + print1("You walk onto a shimmering disk...."); + print2("The disk vanishes, and a glow surrounds you."); + print3("You feel weightless.... You feel ghostly...."); + morewait(); + clearmsg(); + print1("Go up, down, or neither [u,d,ESCAPE] "); + do response = (char) mcigetc(); + while ((response != 'u') && + (response != 'd') && + (response != ESCAPE)); + if (response != ESCAPE) { + print1("How many levels?"); + levelnum = (int) parsenum(""); + if (levelnum > 6) { + too_far = 1; + levelnum = 6; + } + if (response == 'u' && Level->depth - levelnum < 1) { + distance = levelnum - Level->depth; + change_environment(E_COUNTRYSIDE); /* "you return to the countryside." */ + if (distance > 0) { + nprint1(".."); + print2("...and keep going up! You hang in mid air..."); + morewait(); + print3("\"What goes up...\""); + morewait(); + print3("Yaaaaaaaah........"); + p_damage(distance*10,NORMAL_DAMAGE,"a fall from a great height"); + } + return; + } + else if (response == 'd' && Level->depth + levelnum > MaxDungeonLevels) { + too_far = 1; + levelnum = MaxDungeonLevels - Level->depth; + } + if (levelnum == 0) { + print1("Nothing happens."); + return; + } + if (too_far) { + print1("The lift gives out partway..."); + print2("You rematerialize....."); + } + else + print1("You rematerialize....."); + change_level(Level->depth, + (response=='d' ? + Level->depth+levelnum : + Level->depth-levelnum), + false); + roomcheck(); + } +} + + +void l_magic_pool(void) +{ + int possibilities=random_range(100); + print1("This pool seems to be enchanted...."); + if (State.getMounted()) { + if (random_range(2)) { + print2("Your horse is polymorphed into a fig newton."); + State.setMounted(false); + } + else print2("Whatever it was, your horse enjoyed it...."); + } + else if (possibilities == 0) { + print1("Oh no! You encounter the DREADED AQUAE MORTIS..."); + if (random_range(1000) < Player.level*Player.level*Player.level) { + print2("The DREADED AQUAE MORTIS throttles you within inches...."); + print3("but for some reason chooses to let you escape."); + gain_experience(500); + Player.hp = 1; + } + else p_death("the DREADED AQUAE MORTIS!"); + } + else if (possibilities < 25) + augment(0); + else if (possibilities < 30) + augment(1); + else if (possibilities < 60) + augment(-1); + else if (possibilities < 65) + cleanse(1); + else if (possibilities < 80) { + if (Player.possessions[O_WEAPON_HAND] != NULL) { + print1("You drop your weapon in the pool! It's gone forever!"); + dispose_lost_objects(1,Player.possessions[O_WEAPON_HAND]); + } + else print1("You feel fortunate."); + } + else if (possibilities < 90) { + if (Player.possessions[O_WEAPON_HAND] != NULL) { + print1("Your weapon leaves the pool with a new edge...."); + Player.possessions[O_WEAPON_HAND]->plus += random_range(10)+1; + calc_melee(); + } + else print1("You feel unfortunate."); + } + else if (possibilities < 95) { + Player.hp += 10; + print1("You feel healthier after the dip..."); + } + else if (possibilities < 99) { + print1("Oooh, a tainted pool..."); + p_poison(10); + } + else if (possibilities == 99) { + print1("Wow! A pool of azoth!"); + heal(10); + cleanse(1); + Player.mana = calcmana()*3; + Player.str = (Player.maxstr++)*3; + } + print2("The pool seems to have dried up."); + Level->site[Player.x][Player.y].locchar = TRAP; + Level->site[Player.x][Player.y].p_locf = L_TRAP_PIT; + lset(Player.x, Player.y, CHANGED); +} + +void l_no_op(void) +{ +} + +void l_tactical_exit(void) +{ + if (optionp(CONFIRM)) { + if (cinema_confirm("You're about to leave this place.") != 'y') + return; + } + /* Free up monsters and items, and the level */ + free_level(Level); + Level = NULL; + if ((Current_Environment == E_TEMPLE) || + (Current_Environment == E_TACTICAL_MAP) ) + change_environment(E_COUNTRYSIDE); + else change_environment(Last_Environment); +} + +void l_rubble(void) +{ + int screwup = random_range(100) - (Player.agi + Player.level); + print1("You climb over the unstable pile of rubble...."); + if (screwup < 0) print2("No problem!"); + else { + print2("You tumble and fall in a small avalanche of debris!"); + print3("You're trapped in the pile!"); + Player.status[IMMOBILE]+=2; + p_damage(screwup/5,UNSTOPPABLE,"rubble and debris"); + morewait(); + } +} + +/* Drops all portcullises in 5 moves */ +void l_portcullis_trap(void) +{ + int i,j,slam=false; + + print3("Click."); + morewait(); + for (i=max(Player.x-5,0); ilevel_width); i++) + for(j=max(Player.y-5,0); jlevel_length); j++) { + if ((Level->site[i][j].p_locf == L_PORTCULLIS) && + (Level->site[i][j].locchar != PORTCULLIS)) { + Level->site[i][j].locchar = PORTCULLIS; + lset(i, j, CHANGED); + putspot(i,j,PORTCULLIS); + if ((i==Player.x)&&(j==Player.y)) { + print3("Smash! You've been hit by a falling portcullis!"); + morewait(); + p_damage(random_range(1000),NORMAL_DAMAGE,"a portcullis"); + } + slam = true; + } + } + if (slam) print3("You hear heavy walls slamming down!"); +} + +/* drops every portcullis on level, then kills itself and all similar traps. */ +void l_drop_every_portcullis(void) +{ + int i,j,slam=false; + + print3("Click."); + morewait(); + for(j=0; jlevel_length; j++) + for(i=0; ilevel_width; i++) { + if (Level->site[i][j].p_locf == L_DROP_EVERY_PORTCULLIS) { + Level->site[i][j].p_locf = L_NO_OP; + lset(i, j, CHANGED); + } + else if ((Level->site[i][j].p_locf == L_PORTCULLIS) && + (Level->site[i][j].locchar != PORTCULLIS)) { + Level->site[i][j].locchar = PORTCULLIS; + lset(i, j, CHANGED); + putspot(i,j,PORTCULLIS); + if ((i==Player.x)&&(j==Player.y)) { + print3("Smash! You've been hit by a falling portcullis!"); + morewait(); + p_damage(random_range(1000),NORMAL_DAMAGE,"a portcullis"); + } + slam = true; + } + } + if (slam) print3("You hear heavy walls slamming down!"); +} + + + +void l_raise_portcullis(void) +{ + int i,j,open=false; + for(j=0; jlevel_length; j++) + for(i=0; ilevel_width; i++) { + if (Level->site[i][j].locchar == PORTCULLIS) { + Level->site[i][j].locchar = FLOOR; + lset(i, j, CHANGED); + putspot(i,j,FLOOR); + open = true; + } + } + if (open) print1("You hear the sound of steel on stone!"); +} + + +void l_arena_exit(void) +{ + State.setInArena( false ); +#if !defined(WIN32) + free_level(Level); +#endif + Level = NULL; + change_environment(E_CITY); +} + + +void l_house_exit(void) +{ + if (optionp(CONFIRM)) { + clearmsg(); + if (cinema_confirm("You're about to step out of this abode.") != 'y') + return; + } +#if !defined(WIN32) + free_level(Level); +#endif + Level = NULL; + change_environment(Last_Environment); +} + + +void l_void(void) +{ + clearmsg(); + print1("Geronimo!"); + morewait(); + clearmsg(); + print1("You leap into the void."); + if (Level->mlist) { + print2("Death peers over the edge and gazes quizzically at you...."); + morewait(); + print3("'Bye-bye,' he says... 'We'll meet again.'"); + } + morewait(); + while(Player.hp>0) { + Time+=60; + hourly_check(); + } +} + + +void l_fire_station(void) +{ + print1("The flames leap up, and the heat is incredible."); + if (Player.immunity[FLAME]) { + print2("You feel the terrible heat despite your immunity to fire!"); + morewait(); + } + print2("Enter the flames? [yn] "); + if (ynq2()=='y') { + if (Player.hp == 1) p_death("total incineration"); + else Player.hp = 1; + dataprint(); + print1("You feel like you are being incinerated! Jump back? [yn] "); + if (ynq1()=='y') + print2("Phew! That was close!"); + else { + Player.pow -= (15+random_range(15)); + if (Player.pow > 0) { + print2("That's odd, the flame seems to have cooled down now...."); + print3("A flicker of fire seems to dance above the void nearby."); + Level->site[Player.x][Player.y].locchar = FLOOR; + Level->site[Player.x][Player.y].p_locf = L_NO_OP; + stationcheck(); + } + else { + print2("The flames seem to have leached away all your mana!"); + p_death("the Essence of Fire"); + } + } + } + else print2("You flinch away from the all-consuming fire."); +} + + + + +void l_water_station(void) +{ + print1("The fluid seems murky and unknowably deep."); + print2("It bubbles and hisses threateningly."); + morewait(); + if (Player.status[BREATHING]) { + print1("You don't feel sanguine about trying to breathe that stuff!"); + morewait(); + } + if (Player.immunity[ACID]) { + print2("The vapor burns despite your immunity to acid!"); + morewait(); + } + print1("Enter the fluid? [yn] "); + if (ynq1()=='y') { + if (Player.hp == 1) p_death("drowning in acid (ick, what a way to go)"); + else Player.hp = 1; + dataprint(); + print2("You choke...."); + morewait(); + nprint2("Your lungs burn...."); + morewait(); + print2("Your body begins to disintegrate.... Leave the pool? [yn] "); + if (ynq2()=='y') + print2("Phew! That was close!"); + else { + clearmsg(); + Player.con -= (15+random_range(15)); + if (Player.con > 0) { + print1("That's odd, the fluid seems to have been neutralized...."); + print2("A moist miasma wafts above the void nearby."); + Level->site[Player.x][Player.y].locchar = FLOOR; + Level->site[Player.x][Player.y].p_locf = L_NO_OP; + stationcheck(); + } + else { + print2("The bubbling fluid has destroyed your constitution!"); + p_death("the Essence of Water"); + } + } + + } + else print2("You step back from the pool of acid."); +} + + + + +void l_air_station(void) +{ + print1("The whirlwind spins wildly and crackles with lightning."); + if (Player.immunity[ELECTRICITY]) + print2("You feel static cling despite your immunity to electricity!"); + morewait(); + print1("Enter the storm? [yn] "); + if (ynq1()=='y') { + if (Player.hp == 1) p_death("being torn apart and then electrocuted"); + else Player.hp = 1; + dataprint(); + print1("You are buffeted and burnt by the storm...."); + print2("You begin to lose consciousness.... Leave the storm? [yn] "); + if (ynq1()=='y') + print2("Phew! That was close!"); + else { + Player.iq -= (random_range(15)+15); + if (Player.iq > 0) { + print1("That's odd, the storm subsides...."); + print2("A gust of wind brushes past the void nearby."); + Level->site[Player.x][Player.y].locchar = FLOOR; + Level->site[Player.x][Player.y].p_locf = L_NO_OP; + stationcheck(); + } + else { + print2("The swirling storm has destroyed your intelligence!"); + p_death("the Essence of Air"); + } + } + } + else print2("You step back from the ominous whirlwind."); +} + + + + +void l_earth_station(void) +{ + Object* o; + print1("The tendrilled mass reaches out for you from the muddy ooze."); + if (find_item(&o,OB_SALT_WATER,-1)) + print2("A splash of salt water does nothing to dissuade the vines."); + morewait(); + print1("Enter the overgrown mire? [yn] "); + if (ynq1()=='y') { + if (Player.hp == 1) p_death("being eaten alive"); + else Player.hp = 1; + dataprint(); + print1("You are being dragged into the muck. Suckers bite you...."); + print2("You're about to be entangled.... Leave the mud? [yn] "); + if (ynq2()=='y') + print2("Phew! That was close!"); + else { + Player.str -= (15+random_range(15)); + if (Player.str > 0) { + print1("That's odd, the vine withdraws...."); + print2("A spatter of dirt sprays into the void nearby."); + Level->site[Player.x][Player.y].locchar = FLOOR; + Level->site[Player.x][Player.y].p_locf = L_NO_OP; + stationcheck(); + } + else { + print2("The tendril has destroyed your strength!"); + p_death("the Essence of Earth"); + } + } + } + else print2("You step back from the ominous vegetation."); +} + +void stationcheck(void) +{ + int stationsleft=false; + int i,j; + morewait(); + clearmsg(); + print1("You feel regenerated."); + Player.hp = Player.maxhp; + dataprint(); + for(j=0; jlevel_length; j++) + for(i=0; ilevel_width; i++) + if ((Level->site[i][j].locchar == WATER) || + (Level->site[i][j].locchar == HEDGE) || + (Level->site[i][j].locchar == WHIRLWIND) || + (Level->site[i][j].locchar == FIRE)) + stationsleft=true; + if (! stationsleft) { + print1("There is a noise like a wild horse's neigh."); + print2("You spin around, and don't see anyone around at all"); + print3("except for a spurred black cloaked figure carrying a scythe."); + morewait(); + clearmsg(); + print1("Death coughs apologetically. He seems a little embarrassed."); + print2("A voice peals out:"); + print3("'An Adept must be able to conquer Death himself...."); + make_site_monster(32,4,DEATH); + } +} + + +/* To survive the void, the other four stations must be visited first, + to activate the void, then something (Death's scythe, possibly) + must be thrown in to satiate the void, then all other items must + be dropped, then the void must be entered. */ + +void l_void_station(void) +{ + int i,something=false; + if (cinema_confirm("You're about to Peter Pan into an endless void.")=='y') { + if (Level->mlist == NULL) { + print2("You fall forever. Eventually you die of starvation."); + morewait(); + while(Player.hp>0) { + Time+=60; + hourly_check(); + usleep(250000); + } + } + else { + print1("You enter the void."); + print2("You feel a sudden surge of power from five directions."); + morewait(); + something = (Player.packptr > 0); + if (! something) + for(i=0; ((isite[Player.x][Player.y].p_locf = L_NO_OP; +} + +void l_voice2(void) +{ + print1("A strange voice recites: Enter the Void as you entered the World."); + Level->site[Player.x][Player.y].p_locf = L_NO_OP; +} + +void l_voice3(void) +{ + print1("An eerie voice resounds: The Void is the fifth Elemental Station."); + Level->site[Player.x][Player.y].p_locf = L_NO_OP; +} + + +void l_whirlwind(void) +{ + print1("Buffeting winds swirl you up!"); + p_damage(random_range(difficulty()*10),NORMAL_DAMAGE,"a magic whirlwind"); + if (random_range(2)) { + print2("You are jolted by lightning!"); + p_damage(random_range(difficulty()*10),ELECTRICITY,"a magic whirlwind"); + } + morewait(); + if (random_range(2)) { + print1("The whirlwind carries you off...."); + if (random_range(20)==17) + print2("'I don't think we're in Kansas anymore, toto.'"); + p_teleport(0); + } +} + + +void l_enter_circle(void) +{ + print1("You see a translucent stairway before you, leading down."); + print2("Take it? [yn] "); + if (ynq()=='y') + change_environment(E_CIRCLE); +} + +void l_circle_library(void) +{ + print1("You see before you the arcane library of the Circle of Sorcerors."); +} + +void l_tome1(void) +{ + menuclear(); + menuprint("\nYou discover in a dusty tome some interesting information...."); + menuprint("\nThe Star Gem holds a vast amount of mana, usable"); + menuprint("\nfor either Law or Chaos. It is magically linked to Star Peak"); + menuprint("\nand can either be activated or destroyed there. If destroyed,"); + menuprint("\nits power will be used for Chaos, if activated, for Law."); + menuprint("\n\nIt is said the LawBringer has waited for an eternity"); + menuprint("\nat Star Peak for someone to bring him the gem."); + menuprint("\nIt is also rumored that while anyone might destroy the gem,"); + menuprint("\nreleasing chaotic energy, only the LawBringer can release"); + menuprint("\nthe lawful potential of the gem."); + showmenu(); + morewait(); + xredraw(); +} + + +void l_tome2(void) +{ + menuclear(); + menuprint("\nYou discover in some ancient notes that the Star Gem can be"); + menuprint("\nused for transportation, but also read a caution that it must"); + menuprint("\nbe allowed to recharge a long time between uses."); + menuprint("\nA marginal note says 'if only it could be reset to go somewhere"); + menuprint("\nbesides Star Peak, the gem might be useful....'"); + showmenu(); + morewait(); + xredraw(); +} + + +void l_temple_warning(void) +{ + print1("A stern voice thunders in the air around you:"); + print2("'No unbelievers may enter these sacred precincts;"); + print3("those who defile this shrine will be destroyed!"); +} + +void l_throne(void) +{ + Object* o; + int i; + print1("You have come upon a huge ornately appointed throne!"); + print2("Sit in it? [yn] "); + if (ynq1()=='y') { + if (! find_item(&o,OB_SCEPTRE,-1)) { + print1("The throne emits an eerie violet-black radiance."); + print2("You find, to your horror, that you cannot get up!"); + print3("You feel an abstract sucking sensation..."); + for(i=0; isite[Player.x][Player.y].locchar = RUBBLE; + Level->site[Player.x][Player.y].p_locf = L_RUBBLE; + lset(Player.x, Player.y, CHANGED); + if (find_and_remove_item(OB_SCEPTRE,-1)) { + morewait(); + print1("Your sceptre reverberates with the noise, and"); + print2("it too explodes in a spray of shards."); + } + break; + } + calc_melee(); + dataprint(); + } + } + } +} + + +void l_escalator(void) +{ + print1("You have found an extremely long stairway going straight up."); + print2("The stairs are grilled steel and the bannister is rubber."); + morewait(); + print1("Take the stairway? [yn] "); + if (ynq1()=='y') { + print1("The stairs suddenly start moving with a grind of gears!"); + print2("You are wafted to the surface...."); + change_environment(E_COUNTRYSIDE); + } +} + +void l_enter_court(void) +{ + print1("You have found a magical portal! Enter it? [yn] "); + if (ynq1()=='y') { + if (State.getCompletedCastle() == false) { + if (State.getAttackedOracle() == false) { + print2("A dulcet voice says: 'Jolly good show!'"); + morewait(); + } + State.setCompletedCastle( true ); + } + change_environment(E_COURT); + } +} + +void l_chaostone(void) +{ + print1("This is a menhir carved of black marble with veins of gold."); + print2("It emanates an aura of raw chaos, which is not terribly"); + morewait(); + print1("surprising, considering its location."); + if (Player.alignment < 0) + print2("You feel an almost unbearable attraction to the stone."); + else print2("You find it extremely difficult to approach the stone."); + morewait(); + clearmsg(); + if (cinema_confirm("You reach out your fist to strike it.")=='y') { + print1("A sudden flux of energy surrounds you!"); + morewait(); + if (stonecheck(-1)) { + print2("You feel stronger!"); + Player.maxstr = min(Player.maxstr+10,max(30,Player.maxstr)); + dataprint(); + } + } + else print1("You step back from the ominous dolmech."); +} + + +void l_balancestone(void) +{ + print1("This is a massive granite slab teetering dangerously on a corner."); + print2("You feel a sense of balance as you regard it."); + morewait(); + clearmsg(); + if (cinema_confirm("Your hand naturally drifts forward to touch it.")=='y') { + print1("A vortex of mana spins about you!"); + if (abs(Player.alignment) > random_range(50)) { + print2("The cyclone whirls you off to a strange place!"); + morewait(); + change_environment(E_COUNTRYSIDE); + do { + setPlayerXY( random_range(COUNTRY_WIDTH), random_range(COUNTRY_LENGTH)); + } while (Country[Player.x][Player.y].current_terrain_type == CHAOS_SEA); + screencheck(Player.x,Player.y); + drawvision(Player.x,Player.y); + } + else { + print2("You are being drained of experience! Step back? [yn] "); + if (ynq2()=='y') { + clearmsg(); + print1("The vortex calms down, dimishes, and then disappears."); + } + else { + Player.xp -= Player.xp/4; + dataprint(); + print2("The vortex vanishes. Suddenly, there is a clap of thunder!"); + morewait(); + Player.alignment = 0; + strategic_teleport(1); + } + } + } + else print1("You step back from the unlikely boulder."); +} + + +void l_lawstone(void) +{ + print1("This is a stele carved of blueish-green feldspar."); + print2("You feel an aura of serenity rising from it, and your gaze"); + morewait(); + print1("is attracted to the bulk of Star Peak to the North-East."); + if (Player.alignment > 0) + print2("You feel a subtle attraction to the stone."); + else print2("You find the stone extremely distasteful to contemplate."); + morewait(); + clearmsg(); + if (cinema_confirm("Your arm moves as though compelled to grasp it.")=='y') { + print1("A matrix of power flows about you!"); + morewait(); + if (stonecheck(1)) { + print2("You feel more vigorous!"); + Player.maxcon = min(Player.maxcon+10,max(Player.maxcon,30)); + dataprint(); + } + } + else print1("You step back from the strange obelisk."); +} + + +void l_voidstone(void) +{ + int i; + print1("This is a grey and uninteresting stone."); + print2("A feeling of nihility emanates from it."); + morewait(); + clearmsg(); + if (cinema_confirm("You're about to touch it.")=='y') { + print1("You feel negated."); + morewait(); + Player.mana = 0; + toggle_item_use(true); + for(i=0; iblessing = 0; + Player.possessions[i]->plus = 0; + Player.possessions[i]->usef = I_NOTHING; + } + toggle_item_use(false); + calc_melee(); + } + else print1("You back away from the strange rock."); +} + +void l_sacrificestone(void) +{ + int sacrifice=1; + int oldmaxhp = Player.maxhp; + print1("You have come on a weathered basaltic block."); + print2("On the top surface is an indentation in human shape."); + morewait(); + print1("You see old rust colored stains in the grain of the stone."); + print2("You sense something awakening. Touch the block? [yn] "); + if (ynq2() == 'y') { + print1("You sense great pain emanating from the ancient altar."); + print2("Climb on to the block? [yn] "); + if (ynq2() == 'y') { + print1("You are stuck fast to the block!"); + print2("You feel your life-force being sucked away!"); + morewait(); + print1("Hit ESCAPE to try and get up at any moment, SPACE to remain."); + do { + switch(random_range(4)) { + case 0: + print2("You feel weaker."); + break; + case 1: + print2("You feel your life fading."); + break; + case 2: + print2("Your energy is vanishing."); + break; + case 3: + print2("You are being drained."); + break; + } + Player.hp -= sacrifice; + Player.maxhp -= sacrifice/2; + sacrifice *= 2; + dataprint(); + if ((Player.hp < 1) || (Player.maxhp < 1)) + p_death("self-sacrifice"); + } while (stillonblock()); + print1("You manage to wrench yourself off the ancient altar!"); + print2("You leave some skin behind, though...."); + morewait(); + if ((oldmaxhp > 10) && (Player.maxhp < 3 * oldmaxhp/4)) { + print1("A strange red glow arises from the altar."); + print2("The glow surrounds you.... You sense gratitude."); + Player.pow += sacrifice; + Player.maxpow += sacrifice/10; + dataprint(); + } + else { + print1("You a have a sense of rejection."); + print2("A roil of fetid vapor smokes up from the altar."); + gain_experience(sacrifice); + } + } + else { + print1("You sense an emotion of pique all around you."); + print2("You retreat from the strange stone."); + } + } + else { + print1("You decide discretion to be the better part of valour."); + print2("The stone seems to subside sleepily."); + } +} + +void l_mindstone(void) +{ + print1("You approach a giant crystal of some opaline material."); + print2("Flashes of irridescent light glint from the object."); + morewait(); + print1("You feel your attention being drawn by the intricate crystal."); + print2("Look away from the interesting phenomenon? [yn] "); + if (ynq2()=='n') { + print1("Your gaze focuses deeply on the gem...."); + print2("The crystal seems to open up and surround you!"); + morewait(); + if (stonecheck(0)) { + print1("Your mind has been enhanced by the experience!"); + Player.maxiq = min(Player.maxiq+10,max(Player.maxiq,30)); + dataprint(); + } + } + else { + print1("You manage to wrench your gaze from the odd jewel."); + print2("The light flashes from the crystal diminish in frequency."); + } +} diff --git a/Omega/src/scr.cpp b/Omega/src/scr.cpp index 0b6bb8c..e41448f 100644 --- a/Omega/src/scr.cpp +++ b/Omega/src/scr.cpp @@ -1,2322 +1,2327 @@ -/* omega (c) 1987,1988,1989 by Laurence Raphael Brothers */ -/* scr.c */ -/* functions that use curses routines directly */ -/* plus a few file i/o stuff */ -/* also some in file.c */ - -#define CHARATTR(c) ((c) & ~0xff) - -#include "glob.h" - -// Screen flicker fix -#undef wclear -#define wclear werase - -WINDOW *Bankw; - -/* note these variables are not exported to other files */ - -WINDOW *Levelw,*Dataw,*Flagw,*Timew,*Menuw,*Locw,*Morew,*Phasew; -WINDOW *Comwin,*Msg1w,*Msg2w,*Msg3w,*Msgw; - -WINDOW *Cinema; -/* WDT: interactions and special effects which currently - * go into the message window should instead go here. This - * should simplify history-keeping, since we only need to - * record actual messages, not special effects. */ - -WINDOW *Showline[MAXITEMS]; - -WINDOW *Wizlistw; - -#define SL3_LEN 160 -char screenLine3[SL3_LEN]; - -/* static function prototypes */ - -static long input_number (WINDOW * w); - -/* function definitions */ - -void phaseprint(void) -{ - wclear(Phasew); - wprintw(Phasew,"Moon's Phase:\n"); - switch(Phase/2) { - case 0: - wprintw(Phasew,"NEW"); - break; - case 1: - case 11: - wprintw(Phasew,"CRESCENT"); - break; - case 2: - case 10: - wprintw(Phasew,"1/4"); - break; - case 3: - case 9: - wprintw(Phasew,"HALF"); - break; - case 4: - case 8: - wprintw(Phasew,"3/4"); - break; - case 5: - case 7: - wprintw(Phasew,"GIBBOUS"); - break; - case 6: - wprintw(Phasew,"FULL"); - break; - } - wrefresh(Phasew); -} - -static void show_screen_level (int top, int left, int bottom, int right) -{ - int j; - int last_attr = 0; - - for (j = top; j < bottom; ++j) - { - int i; - - wmove(Levelw, screenmody(j), 0); - - for (i = left; i < right; ++i) - { - int c; - - if (loc_statusp(i, j, SEEN)) - c = getspot(i, j, false); - else - c = SPACE; - - if (optionp(SHOW_COLOUR) && CHARATTR(c) != last_attr) - { - last_attr = CHARATTR(c); - wattrset(Levelw, last_attr); - } - - waddch(Levelw, c & 0xff); - } - } -} - -static void show_screen_country (int top, int left, int bottom, int right) -{ - int j; - int last_attr = 0; - - for (j = top; j < bottom; ++j) - { - int i; - - wmove(Levelw, screenmody(j), 0); - - for (i = left; i < right; ++i) - { - int c; - - if (c_statusp(i, j, SEEN)) - c = Country[i][j].current_terrain_type; - else - c = SPACE; - - if (optionp(SHOW_COLOUR) && CHARATTR(c) != last_attr) - { - last_attr = CHARATTR(c); - wattrset(Levelw, last_attr); - } - - waddch(Levelw, c & 0xff); - } - } -} - -void show_screen(void) -{ - int top; - int left; - int right; - int bottom; - - wclear(Levelw); - - if (ScreenOffset < 0) ScreenOffset = 0; - if (ScreenXOffset < 0) ScreenXOffset = 0; - - top = ScreenOffset; - left = ScreenXOffset; - right = ScreenXOffset + ScreenWidth; - bottom = ScreenOffset + ScreenLength; - - if (Current_Environment != E_COUNTRYSIDE) - { - if (right > Level->level_width) right = Level->level_width; - if (bottom > Level->level_length) bottom = Level->level_length; - } - else - { - if (right > COUNTRY_WIDTH) right = COUNTRY_WIDTH; - if (bottom > COUNTRY_LENGTH) bottom = COUNTRY_LENGTH; - } - - if (Current_Environment != E_COUNTRYSIDE) - { - show_screen_level(top, left, bottom, right); - } - else - { - show_screen_country(top, left, bottom, right); -#if 0 - for (j=top; j=(int)'A') && (c<=(int)'Z')) - return(c+(int)('a'-'A')); - else - return(c); -} - -char menugetc(void) -{ - return(wgetch(Menuw)); -} - -char lgetc(void) -{ - return(wgetch(Levelw)); -} - -int ynq(void) -{ - int p='*'; /* the user's choice; start with something impossible - * to prevent a loop. */ - while ((p != 'n') && (p != 'y') && (p != 'q') && (p != ESCAPE) && - (p != EOF) && (p != ' ')) - p = wgetch(Msgw); - switch (p) { - case 'y': - wprintw(Msgw,"yes. "); - break; - case 'n': - wprintw(Msgw,"no. "); - break; - - case ESCAPE: - p = 'q'; /* fall through to 'q' */ - case ' ': - p = 'q'; /* fall through to 'q' */ - case 'q': - wprintw(Msgw,"quit. "); - break; - default: - assert( p == EOF ); - } - wrefresh(Msgw); - return(p); -} - - -int ynq1(void) -{ - int p='*'; /* the user's choice; start with something impossible - * to prevent a loop. */ - while ((p != 'n') && (p != 'y') && (p != 'q') && (p != ESCAPE) && - (p != ' ') && (p != EOF)) - p = wgetch(Msg1w); - switch (p) { - case 'y': - wprintw(Msg1w,"yes. "); - break; - case 'n': - wprintw(Msg1w,"no. "); - break; - - case ESCAPE: - p = 'q'; /* fall through to 'q' */ - case ' ': - p = 'q'; /* fall through to 'q' */ - case 'q': - wprintw(Msg1w,"quit. "); - break; - default: - assert( p == EOF ); - } - wrefresh(Msg1w); - return(p); -} - - -int ynq2(void) -{ - int p='*'; /* the user's choice; start with something impossible - * to prevent a loop. */ - while ((p != 'n') && (p != 'y') && (p != 'q') && (p != ESCAPE) && - (p != ' ') && (p != EOF)) - p = wgetch(Msg2w); - switch (p) { - case 'y': - wprintw(Msg2w,"yes. "); - break; - case 'n': - wprintw(Msg2w,"no. "); - break; - - case ESCAPE: - p = 'q'; /* fall through to 'q' */ - case ' ': - p = 'q'; /* fall through to 'q' */ - case 'q': - wprintw(Msg2w,"quit. "); - break; - default: - assert( p == EOF ); - } - wrefresh(Msg2w); - return(p); -} - -void erasemsg3 (void) -{ - werase(Msg3w); - memset(screenLine3, 0, SL3_LEN); -} - -/* puts up a morewait to allow reading if anything in top two lines */ -void checkclear(void) -{ - int x1,y,x2; - getyx(Msg1w,x1,y); - getyx(Msg2w,x2,y); - if ((x1 != 0) || (x2 != 0)) { - morewait(); - wclear(Msg1w); - wclear(Msg2w); - wrefresh(Msg1w); - wrefresh(Msg2w); - } -} - -/* for external call */ -void clearmsg(void) -{ - wclear(Msg1w); - wclear(Msg2w); - erasemsg3(); - Msgw = Msg1w; - wrefresh(Msg1w); - wrefresh(Msg2w); - wrefresh(Msg3w); -} - -void clearmsg3(void) -{ - erasemsg3(); - wrefresh(Msg3w); -} - -void clearmsg1(void) -{ - wclear(Msg1w); - wclear(Msg2w); - Msgw = Msg1w; - wrefresh(Msg1w); - wrefresh(Msg2w); -} - -void erase_level(void) -{ - wclear(Levelw); - wrefresh(Levelw); -} - -/* direct print to first msg line */ -void print1(const char *s) -{ - if (! State.getSuppressPrinting()) { - buffercycle(s); - wclear(Msg1w); - wprintw(Msg1w,s); - wrefresh(Msg1w); - } -} - -/* for run on-messages -- print1 clears first.... */ -void nprint1(char *s) -{ - if (! State.getSuppressPrinting()) { - if (bufferappend(s)) { - wprintw(Msg1w,s); - wrefresh(Msg1w); - } - } -} - -/* direct print to second msg line */ -void print2(char *s) -{ - if (! State.getSuppressPrinting()) { - buffercycle(s); - wclear(Msg2w); - wprintw(Msg2w,s); - wrefresh(Msg2w); - } -} - -/* for run on-messages -- print2 clears first.... */ -void nprint2(char *s) -{ - if (! State.getSuppressPrinting()) { - if (bufferappend(s)) { - wprintw(Msg2w,s); - wrefresh(Msg2w); - } - } -} - - -/* msg line 3 is not part of the region that mprint or printm can reach */ -/* typical use of print3 is for "you can't do that" type error messages */ -/* WDT: it's also typically used for messages intended to persist a while. - * Thus I'm having print3 save its input in a global variable which other - * things can use. */ -void print3 (char *s) -{ - if (!State.getSuppressPrinting()) - { - buffercycle(s); - erasemsg3(); - wprintw(Msg3w, s); - strcpy(screenLine3, s); - wrefresh(Msg3w); - } -} - -/* for run on-messages -- print3 clears first.... */ -void nprint3(char *s) -{ - if (!State.getSuppressPrinting()) - { - if (bufferappend(s)) - { - strcat(screenLine3, s); - wprintw(Msg3w,s); - wrefresh(Msg3w); - } - } -} - - - -/* prints wherever cursor is in window, but checks to see if -it should morewait and clear window */ -void mprint(char *s) -{ - int x,y; - if (! State.getSuppressPrinting()) { - getyx(Msgw,y,x); - if (x+strlen(s) >= ScreenWidth) { - buffercycle(s); - if (Msgw == Msg1w) { - wclear(Msg2w); - Msgw = Msg2w; - } - else { - morewait(); - wclear(Msg1w); - wclear(Msg2w); - wrefresh(Msg2w); - Msgw = Msg1w; - } - } - else if (x > 0) - bufferappend(s); - else - buffercycle(s); - wprintw(Msgw,s); - waddch(Msgw,' '); - wrefresh(Msgw); - } -} - - -void omega_title(void) -{ - showmotd(); - clear(); - touchwin(stdscr); - refresh(); - /* showscores();*/ /* DG */ -} - - - -/* blanks out ith line of Menuw or Levelw */ -void hide_line(int i) -{ - wclear(Showline[i]); - touchwin(Showline[i]); - wrefresh(Showline[i]); -} - -#ifdef USE_OPCURSES -static void load_tiles (void) -{ - char * path; - - path = malloc(strlen(OMEGALIB) + strlen(TILEFILE) + 1); - if (0 == path) return; - - strcpy(path, OMEGALIB); - strcat(path, TILEFILE); - - set_tiles(path); - - free(path); -} -#endif - -/* initialize, screen, windows */ -void initgraf(void) -{ - int i; - -#ifdef USE_OPCURSES - load_tiles(); -#endif - - initscr(); - start_color(); - clrgen_init(); - - if (LINES < 24 || COLS < 80) { - printf("Minimum Screen Size: 24 Lines by 80 Columns."); - exit(0); - } - ScreenLength = LINES - 6; - ScreenWidth = 64; /* PGM */ - Msg1w = newwin(1,80,0,0); - scrollok(Msg1w, 0); - Msg2w = newwin(1,80,1,0); - scrollok(Msg2w, 0); - Msg3w = newwin(1,80,2,0); - scrollok(Msg3w, 0); - Msgw = Msg1w; - Morew = newwin(1,15,3,65); - scrollok(Morew, 0); - - // Bank window - Bankw = newwin( 20, 50, ( ScreenLength - 20 ) / 2 + 3, 7 ); - scrollok( Bankw, 0 ); - - // Wiz flag list window - Wizlistw = newwin( 20, 50, 3, 0 ); - scrollok( Wizlistw, 0 ); - - Locw = newwin(1,80,ScreenLength+3,0); - scrollok(Locw, 0); - Levelw = newwin(ScreenLength,ScreenWidth,3,0); - scrollok(Levelw, 0); - for(i=0; i 0); - - while (1) - { - cinema_display(line1, line2, line3); - response = cinema_getch(); - if (-1 == response) break; - if (strchr(choices, response)) break; - if (!line3) line3 = "What? Try again!"; - } - - cinema_hide(); - return response; -} - -int cinema_interact_line (int line, char * choices, char * text) -{ - int response; - - assert(0 == line || 1 == line); - assert(choices && strlen(choices) > 0); - - while (1) - { - cinema_print_line(line, text); - response = cinema_getch(); - if (ABORT == response) break; - if (strchr(choices, response)) break; - cinema_print_line(2, "What? Try again!"); - } - - return response; -} - -int cinema_ynq_line (int line, char * prompt) -{ - return cinema_interact_line(line, "ynqYNQ", prompt); -} - -int cinema_getnum_line (int line, char * prompt) -{ - int num; - - assert(0 == line || 1 == line); - - cinema_blank_line(line); - cinema_print_line(line, prompt); - num = (int)input_number(Cinema); - - return num; -} - -int cinema_confirm (char * action_description) -{ - char *msg; - - switch (random_range(4)) - { - case 0: - msg = "Are you sure? [yn] "; - break; - case 1: - msg = "Certain about that? [yn] "; - break; - case 2: - msg = "Do you really mean it? [yn] "; - break; - default: - msg = "Confirm that, would you? [yn] "; - break; - } - - return cinema_interact("ynqYNQ", action_description, msg, NULL); -} - -int cinema_ynq (char *action_description) -{ - return cinema_interact("ynqYNQ", action_description, NULL, NULL); -} - -void cinema_scene (char *line1, char *line2, char *line3) -{ - cinema_display(line1, line2, line3); - morewait(); - cinema_hide(); -} - -int lastx= -1,lasty= -1; - -void drawplayer(void) -{ - int c; - - if (E_COUNTRYSIDE == Current_Environment) - { - if (inbounds(lastx, lasty) && !offscreen(lastx, lasty)) - { - wmove(Levelw, screenmody(lasty), screenmodx(lastx)); - c = Country[lastx][lasty].current_terrain_type; - - if (optionp(SHOW_COLOUR)) wattrset(Levelw, CHARATTR(c)); - - waddch(Levelw, c & 0xff); - } - - wmove(Levelw, screenmody(Player.y), screenmodx(Player.x)); - - if (optionp(SHOW_COLOUR)) wattrset(Levelw, CHARATTR(PLAYER)); - - waddch(Levelw, PLAYER & 0xff); - } - else - { - if (inbounds(lastx, lasty) && !offscreen(lastx, lasty)) - plotspot(lastx, lasty, (Player.status[BLINDED] > 0 ? false : true)); - - wmove(Levelw, screenmody(Player.y), screenmodx(Player.x)); - - if ((!Player.status[INVISIBLE]) || Player.status[TRUESIGHT]) - { - if (optionp(SHOW_COLOUR)) wattrset(Levelw, CHARATTR(PLAYER)); - waddch(Levelw, PLAYER & 0xff); - } - } - - lastx = Player.x; - lasty = Player.y; -} - -void setlastxy(int new_x, int new_y) /* used when changing environments */ -{ - lastx = new_x; - lasty = new_y; -} - -int litroom(int x, int y) -{ - if (Level->site[x][y].roomnumber < ROOMBASE) return(false); - else return(loc_statusp(x,y,LIT) || - Player.status[ILLUMINATION]); -} - -void drawvision(int x, int y) -{ - static int oldx = -1,oldy = -1; - int i,j,c; - - if (Current_Environment != E_COUNTRYSIDE) { - if (Player.status[BLINDED]) { - drawspot(oldx,oldy); - drawspot(x,y); - drawplayer(); - } - else { - if (Player.status[ILLUMINATION] > 0) { - for (i= -2; i<3; i++) - for (j= -2; j<3; j++) - if (inbounds(x+i,y+j)) - if (view_los_p(x+i,y+j,Player.x,Player.y)) - dodrawspot(x+i,y+j); - } - else { - for (i= -1; i<2; i++) - for (j= -1; j<2; j++) - if (inbounds(x+i,y+j)) - dodrawspot(x+i,y+j); - } - drawplayer(); - drawmonsters(false); /* erase all monsters */ - drawmonsters(true); /* draw those now visible */ - } - if ((State.getFastMove() == false) || (! optionp(JUMPMOVE))) - omshowcursor(Player.x,Player.y); - oldx = x; - oldy = y; - } - else { - for (i= -1; i<2; i++) - for (j= -1; j<2; j++) - if (inbounds(x+i,y+j)) { - c_set(x+i, y+j, SEEN); - if (!offscreen(x+i,y+j)) { - wmove(Levelw,screenmody(y+j),screenmodx(x+i)); - c = Country[x+i][y+j].current_terrain_type; - if (optionp(SHOW_COLOUR)) - wattrset(Levelw, CHARATTR(c)); - waddch(Levelw,(c&0xff)); - } - } - drawplayer(); - omshowcursor(Player.x,Player.y); - } -} - - -void omshowcursor(int x, int y) -{ - if (! offscreen(x,y)) { - wmove(Levelw,screenmody(y),screenmodx(x)); - wrefresh(Levelw); - } -} - -void levelrefresh(void) -{ - wrefresh(Levelw); -} - - -/* draws a particular spot under if in line-of-sight */ -void drawspot(int x, int y) -{ - Symbol c; - if (inbounds(x,y)) { - c = getspot(x,y,false); - if (c != Level->site[x][y].showchar) - if (view_los_p(Player.x,Player.y,x,y)) { - lset(x,y,SEEN); - Level->site[x][y].showchar = c; - putspot(x,y,c); - } - } -} - - - -/* draws a particular spot regardless of line-of-sight */ -void dodrawspot(int x, int y) -{ - Symbol c; - if (inbounds(x,y)) { - c = getspot(x,y,false); - if (c != Level->site[x][y].showchar) { - lset(x,y,SEEN); - Level->site[x][y].showchar = c; - putspot(x,y,c); - } - } -} - -/* write a blank to a spot if it is floor */ -void blankoutspot(int i, int j) -{ - if (inbounds(i,j)) { - lreset(i,j,LIT); - lset(i, j, CHANGED); - if (Level->site[i][j].locchar == FLOOR) { - Level->site[i][j].showchar = SPACE; - putspot(i,j,SPACE); - } - } -} - -/* blank out a spot regardless */ -void blotspot(int i, int j) -{ - if (inbounds(i,j)) { - lreset(i,j,SEEN); - Level->site[i][j].showchar = SPACE; - if (! offscreen(i,j)) { - wmove(Levelw,screenmody(j),screenmodx(i)); - wattrset(Levelw, CHARATTR(SPACE)); - waddch(Levelw, SPACE&0xff); - } - } -} - - -/* for displaying activity specifically at some point */ -void plotspot(int x, int y, int showmonster) -{ - if (loc_statusp(x,y,SEEN)) - putspot(x,y,getspot(x,y,showmonster)); - else - putspot(x,y,SPACE); -} - - -/* Puts c at x,y on screen. No fuss, no bother. */ -void putspot(int x, int y, Symbol c) -{ - if (! offscreen(x,y)) { - wmove(Levelw,screenmody(y),screenmodx(x)); - if (optionp(SHOW_COLOUR)) - wattrset(Levelw, CHARATTR(c)); - waddch(Levelw,(0xff&c)); - } -} - - -/* regardless of line of sight, etc, draw a monster */ -void plotmon(Monster* m) -{ - if (! offscreen(m->x,m->y)) { - wmove(Levelw,screenmody(m->y),screenmodx(m->x)); - if (optionp(SHOW_COLOUR)) - wattrset(Levelw, CHARATTR(m->symbol)); - waddch(Levelw,(m->symbol&0xff)); - } -} - -/* if display, displays monsters, otherwise erases them */ -void drawmonsters(int display) -{ - MonsterList* ml; - for (ml=Level->mlist; ml!=NULL; ml=ml->next) { - if (ml->monster->hp > 0) { - if (display) { - if (view_los_p(Player.x,Player.y,ml->monster->x,ml->monster->y)) { - if (Player.status[TRUESIGHT] || (! m_statusp(ml->monster,M_INVISIBLE))) { - if (!optionp(SHOW_COLOUR) && - (ml->monster->level > 5) && - ((ml->monster->symbol&0xff) != '@') && - ((ml->monster->symbol&0xff) != '|')) wstandout(Levelw); - putspot(ml->monster->x,ml->monster->y,ml->monster->symbol); - if (!optionp(SHOW_COLOUR)) - wstandend(Levelw); - } - } - } - else erase_monster(ml->monster); - } - } -} - -/* replace monster with what would be displayed if monster weren't there */ -void erase_monster(Monster* m) -{ - if (loc_statusp(m->x,m->y,SEEN)) - putspot(m->x,m->y,getspot(m->x,m->y,false)); - else blotspot(m->x,m->y); -} - -/* find apt char to display at some location */ -Symbol getspot(int x, int y, int showmonster) -{ -#ifdef CENTER_ON_PLAYER - /* funny scrolling may cause this. PGM */ - if (!inbounds(x,y ) ) - { - return SPACE; - } -#endif - - if (loc_statusp(x,y,SECRET)) - { - if ( Level->site[x][y].roomnumber == RS_DRUID ) - return(HEDGE); /* secret doors in druid temple are brambles -DAG */ - else - return(WALL); - } - else switch (Level->site[x][y].locchar) { - case WATER: - if (Level->site[x][y].creature == NULL) - return(WATER); - else if (m_statusp(Level->site[x][y].creature,SWIMMING)) - return(WATER); - else if (showmonster) - return(Level->site[x][y].creature->symbol); - else return(WATER); - /* these sites never show anything but their location char's */ - case CLOSED_DOOR: - case LAVA: - case FIRE: - case ABYSS: - return(Level->site[x][y].locchar); - /* rubble and hedge don't show items on their location */ - case RUBBLE: - case HEDGE: - if (showmonster && (Level->site[x][y].creature != NULL)) { - if ((m_statusp(Level->site[x][y].creature,M_INVISIBLE)) && - (! Player.status[TRUESIGHT])) - return(getspot(x,y,false)); - else return (Level->site[x][y].creature->symbol); - } - else return(Level->site[x][y].locchar); - /* everywhere else, first try to show monster, next show items, next show - location char */ - default: - if (showmonster && (Level->site[x][y].creature != NULL)) { - if ((m_statusp(Level->site[x][y].creature,M_INVISIBLE)) && - (! Player.status[TRUESIGHT])) - return(getspot(x,y,false)); - else return (Level->site[x][y].creature->symbol); - } - else if (Level->site[x][y].things != NULL) { - if (Level->site[x][y].things->next != NULL) - return(PILE); - else return(Level->site[x][y].things->thing->objchar); - } - else return(Level->site[x][y].locchar); - } -} - -void commanderror(void) -{ - erasemsg3(); - wprintw(Msg3w, "%c : unknown command", Cmd); - wrefresh(Msg3w); -} - -void timeprint(void) -{ - static char * old_month = 0; - - /* WSS * HACK * This shouldn't be here at all but time is so screwed up */ - /* WSS * HACK * I don't know where else I can check for a new month reliably */ - if (!old_month) - old_month = month(); - else - { - /* WSS * HACK * ptr comparision... works cause they're static */ - if (old_month != month() && Player.rank[LEGION] > 0) - { - bank_account * account; - account = bank_index_number(SalaryAccount); - if (account) account->balance += SalaryAmount; - old_month = month(); - } - } - - wclear(Timew); - wprintw(Timew,"%d:%d",showhour(),showminute()); - if (showminute()==0) waddch(Timew,'0'); - wprintw(Timew,hour()>11 ? " PM \n" : " AM \n"); - wprintw(Timew,month()); - wprintw(Timew," the %d",day()); - wprintw(Timew,ordinal(day())); - wrefresh(Timew); -} - - -void comwinprint(void) -{ - wclear(Comwin); - wprintw(Comwin,"Hit: %d \n",Player.hit); - wprintw(Comwin,"Dmg: %d \n",Player.dmg); - wprintw(Comwin,"Def: %d \n",Player.defense); - wprintw(Comwin,"Arm: %d \n",Player.absorption); - wprintw(Comwin,"Spd: %d.%d \n", 5/Player.speed, 500/Player.speed%100); - wrefresh(Comwin); -} - -void dataprint(void) -{ - wclear(Dataw); - /* WDT HACK: I should make these fields spaced and appropriately justified. - * Maybe I don't feel like it right now. */ - wprintw(Dataw,"Hp:%d/%d Mana:%ld/%ld Au:%ld Level:%d/%ld Carry:%d/%d \n", - Player.hp,Player.maxhp,Player.mana,Player.maxmana,Player.cash, - Player.level,Player.xp,Player.itemweight,Player.maxweight); - wprintw(Dataw,"Str:%d/%d Con:%d/%d Dex:%d/%d Agi:%d/%d Int:%d/%d Pow:%d/%d ", - Player.str,Player.maxstr,Player.con,Player.maxcon, - Player.dex,Player.maxdex,Player.agi,Player.maxagi, - Player.iq,Player.maxiq,Player.pow,Player.maxpow); - wrefresh(Dataw); -} - - -/* redraw everything currently displayed */ -void redraw(void) -{ - touchwin(curscr); - wrefresh(curscr); -} - -/* redraw each permanent window */ -void xredraw(void) -{ - touchwin(Msgw); - touchwin(Msg3w); - touchwin(Levelw); - touchwin(Timew); - touchwin(Flagw); - touchwin(Dataw); - touchwin(Locw); - touchwin(Morew); - touchwin(Phasew); - touchwin(Comwin); - wrefresh(Msgw); - wrefresh(Msg3w); - wrefresh(Levelw); - wrefresh(Timew); - wrefresh(Flagw); - wrefresh(Dataw); - wrefresh(Locw); - wrefresh(Morew); - wrefresh(Phasew); - wrefresh(Comwin); -} - - - -void menuaddch(char c) -{ - waddch(Menuw,c); - wrefresh(Menuw); -} - - - -void morewait(void) -{ - int display=true; - int c; - if (State.getSuppressPrinting()) - return; - do { - wclear(Morew); - if (display) wprintw(Morew,"*** MORE ***"); - else wprintw(Morew,"+++ MORE +++"); - display = ! display; - wrefresh(Morew); - /* c = wgetch(Msgw); */ - c = wgetch(Morew); - } while ((c != ' ') && (c != RETURN) && (c != EOF)); - wclear(Morew); - wrefresh(Morew); -} - -int stillonblock(void) -{ - int display=true; - int c; - do { - wclear(Morew); - if (display) wprintw(Morew,"<<>>"); - else wprintw(Morew,">>>STAY?<<<"); - display = ! display; - wrefresh(Morew); - c = wgetch(Msgw); - } while ((c != ' ') && (c != ESCAPE) && (c != EOF)); - wclear(Morew); - wrefresh(Morew); - return (c == ' '); -} - -void menuclear(void) -{ - wclear(Menuw); - touchwin(Menuw); - wrefresh(Menuw); -} - -void menuspellprint(int i) -{ - int x,y; - getyx(Menuw,y,x); - if (y >= ScreenLength - 2) { - wrefresh(Menuw); - morewait(); - wclear(Menuw); - touchwin(Menuw); - } - wprintw(Menuw,spellid(i)); - wprintw(Menuw,"(%d)\n",Spells[i].powerdrain); -} - -void menuprint(char *s) -{ - int x,y; - getyx(Menuw,y,x); - if (y >= ScreenLength - 2) { - wrefresh(Menuw); - morewait(); - wclear(Menuw); - touchwin(Menuw); - } - wprintw(Menuw,s); -} - -void showmenu(void) -{ - wrefresh(Menuw); -} - - -void endgraf(void) -{ - clear(); - touchwin(stdscr); - refresh(); - endwin(); -} - - -void plotchar(Symbol pyx, int x, int y) -{ - if (! offscreen(x,y)) { - wmove(Levelw,screenmody(y),screenmodx(x)); - if (optionp(SHOW_COLOUR)) - wattrset(Levelw, CHARATTR(pyx)); - waddch(Levelw,(pyx&0xff)); - wrefresh(Levelw); - } -} - - - -void draw_explosion(Symbol pyx, int x, int y) -{ - int i,j; - - for(j=0; j<3; j++) { - for(i=0; i<9; i++) - plotchar(pyx,x+Dirs[0][i],y+Dirs[1][i]); - usleep(150000); - for(i=0; i<9; i++) - plotchar(SPACE,x+Dirs[0][i],y+Dirs[1][i]); - usleep(150000); - } - for(i=0; i<9; i++) - plotspot(x+Dirs[0][i],y+Dirs[1][i],true); - wrefresh(Levelw); -} - -char *msgscanstring(void) -{ - static char instring[80],byte='x'; - int i=0; - - instring[0]=0; - byte = mgetc(); - while (byte != '\n') { - if ((byte == 8) || (byte == 127)) { /* ^h or delete */ - if (i>0) { - i--; - dobackspace(); - } - instring[i] = 0; - } - else { - instring[i] = byte; - waddch(Msgw,byte); - wrefresh(Msgw); - i++; - instring[i] = 0; - } - byte = mgetc(); - } - return(instring); -} - - -void locprint(char *s) -{ - wclear(Locw); - wprintw(Locw,s); - wrefresh(Locw); -} - -/* draw everything whether visible or not */ -void drawscreen(void) -{ - int i,j; - if (Current_Environment == E_COUNTRYSIDE) - for (i=0; ilevel_width; i++) - for(j=0; jlevel_length; j++) - lset(i,j,SEEN); - if (Current_Environment == E_CITY) - for (i = 0; i < NUMCITYSITES; i++) - CitySiteList[i][0] = 1; - show_screen(); -} - -/*selects a number up to range */ -/* WDT HACK! This should use the interaction code, and should allow - * direct input. */ -int getnumber(int range) -{ - int done=false,value=1; - int atom; - - if (range==1) return(1); - else while (! done) { - clearmsg(); - wprintw(Msg1w,"How many? Change with < or >, ESCAPE to select:"); - mnumprint(value); -#if !defined(WIN32) - do atom=mcigetc(); - while ((atom != '<')&&(atom != '>')&&(atom!=ESCAPE)); - if ((atom=='>') && (value < range)) value++; - else if ((atom=='<') && (value > 1)) value--; - else if (atom==ESCAPE) done = true; -#else - atom=mcigetc(); - switch (atom) - { - case '>': - case 'k': -#ifdef KEY_UP - case KEY_UP: -#endif - if (value < range) - value++; - break; - case '<': - case 'j': -#ifdef KEY_DOWN - case KEY_DOWN: -#endif - if (value > 1) - value--; - break; -#ifdef KEY_HOME - case KEY_HOME: -#endif - value = 1; - break; -#ifdef KEY_LL - case KEY_LL: -#endif - value = range; - break; - case ESCAPE: - clearmsg(); - done = true; - break; - } -#endif - } - return(value); -} - -static long input_number (WINDOW * w) -{ - int ch; - int ypos, xpos; - int numlen = 0; - int amount = 0; - - getyx(w, ypos, xpos); - - while (1) - { - ch = mvwgetch(w, ypos, xpos); - - if ('\n' == ch || '\r' == ch) - { - return amount; - } - else if (EOF == ch || ESCAPE == ch) - { - return ABORT; - } - else if (BACKSPACE == ch || DELETE_CHAR == ch) - { - if (numlen > 0) - { - --numlen; - amount /= 10; - mvwaddch(w, ypos, --xpos, ' '); - } - } - else if (isdigit(ch) && (numlen < 9)) - { - ++xpos; - ++numlen; - waddch(w, ch); - amount = 10 * amount + (ch - '0'); - } - else - { - beep(); - } - } -} - -/* reads a positive number up to 999999 */ -/* WDT: now asks for the number, and receives it through the cinema - * interface. Returns ABORT (-1) if aborted. */ -long parsenum (char *message) -{ - int number[8]; - int place = -1; - int i,x,y,mult=1; - long num=0; - char byte=' '; - int entering_digits = true; - - cinema_display(message, "enter a number or ESC: ", NULL); - while (entering_digits) { - byte = wgetch(Cinema); - if ((byte == BACKSPACE) || (byte == DELETE_CHAR)) { - if (place > -1) { - number[place] = 0; - place--; - getyx(Cinema,y,x); - wmove(Cinema,y,x-1); - waddch(Cinema,' '); - wmove(Cinema,y,x-1); - wrefresh(Cinema); - } - } - else if ((byte <= '9') && (byte >= '0') && (place < 7)) { - place++; - number[place]=byte; - waddch(Cinema,byte); - wrefresh(Cinema); - } - else if (isprint(byte)) { - /* I suppose I should beep here, to indicate that only digits belong. - * Right now I'm just ignoring them. - */ - } - else entering_digits = 0; - } - if (byte != '\n') num = ABORT; - else { - for (i=place; i>=0; i--) { - num += mult*(number[i]-'0'); - mult*=10; - } - } - cinema_hide(); - return num; -} - - - -void maddch(char c) -{ - waddch(Msgw,c); - wrefresh(Msgw); -} - - -void display_death(char *source) -{ - clear(); - touchwin(stdscr); - printw("\n\n\n\n"); - printw("Requiescat In Pace, "); - printw(Player.name); - printw(" (%ld points)",calc_points()); - strcpy(Str4,"Killed by "); - strcat(Str4,source); - printw("\n"); - printw(Str4); - printw("."); - printw("\n\n\n\n\nHit 'c' to continue."); - refresh(); - while (wgetch(stdscr) != 'c') - ; - clear(); - touchwin(stdscr); - refresh(); - extendlog(Str4,DEAD); -} - - -void display_win(void) -{ - clear(); - touchwin(stdscr); - printw("\n\n\n\n"); - printw(Player.name); - if (Player.rank[ADEPT]) { - printw(" is a total master of omega with %ld points!",FixedPoints); - strcpy(Str4,"A total master of omega"); - } - else { - strcpy(Str4,"retired a winner"); - printw(" triumphed in omega with %ld points!",calc_points()); - } - printw("\n\n\n\n\nHit 'c' to continue."); - refresh(); - while (wgetch(stdscr) != 'c') - ; - clear(); - touchwin(stdscr); - refresh(); - if (Player.rank[ADEPT]) - extendlog(Str4,BIGWIN); - else extendlog(Str4,WIN); -} - -void display_quit(void) -{ - clear(); - touchwin(stdscr); - printw("\n\n\n\n"); - printw(Player.name); - strcpy(Str4,"A quitter."); - printw(" wimped out with %ld points!",calc_points()); - printw("\n\n\n\n\nHit 'c' to continue."); - refresh(); - while (wgetch(stdscr) != 'c') - ; - clear(); - touchwin(stdscr); - refresh(); - extendlog(Str4,QUIT); -} - - -void display_bigwin(void) -{ - clear(); - touchwin(stdscr); - printw("\n\n\n\n"); - printw(Player.name); - strcpy(Str4,"retired, an Adept of Omega."); - printw(" retired, an Adept of Omega with %ld points!",FixedPoints); - printw("\n\n\n\n\nHit 'c' to continue."); - refresh(); - while (wgetch(stdscr) != 'c') - ; - clear(); - touchwin(stdscr); - refresh(); - extendlog(Str4,BIGWIN); -} - - -void mnumprint(int n) -{ - char numstr[20]; - sprintf(numstr,"%d",n); - bufferappend(numstr); - wprintw(Msgw,"%d",n); - wrefresh(Msgw); -} - -void mlongprint(long n) -{ - char numstr[20]; - sprintf(numstr,"%ld",n); - bufferappend(numstr); - wprintw(Msgw,"%ld",n); - wrefresh(Msgw); -} - - -void menunumprint(int n) -{ - int x,y; - getyx(Menuw,y,x); - if (y >= ScreenLength - 2) { - wrefresh(Menuw); - morewait(); - wclear(Menuw); - touchwin(Menuw); - } - wprintw(Menuw,"%d",n); -} - -void menulongprint(long n) -{ - int x,y; - getyx(Menuw,y,x); - if (y >= ScreenLength - 2) { - wrefresh(Menuw); - morewait(); - wclear(Menuw); - touchwin(Menuw); - } - wprintw(Menuw,"%ld",n); -} - - -void dobackspace(void) -{ - int x,y; - - getyx(Msgw,y,x); - if (x > 0) { - waddch(Msgw,' '); - wmove(Msgw,y,x-1); - waddch(Msgw,' '); - wmove(Msgw,y,x-1); - } - wrefresh(Msgw); -} - - -void showflags(void) -{ - - phaseprint(); - wclear(Flagw); - if (Player.food < 0) - wprintw(Flagw,"Starving\n"); - else if (Player.food <= 3) - wprintw(Flagw,"Weak\n"); - else if (Player.food <= 10) - wprintw(Flagw,"Ravenous\n"); - else if (Player.food <= 20) - wprintw(Flagw,"Hungry\n"); - else if (Player.food <= 30) - wprintw(Flagw,"A mite peckish\n"); - else if (Player.food <= 36) - wprintw(Flagw,"Content\n"); - else if (Player.food <= 44) - wprintw(Flagw,"Satiated\n"); - else wprintw(Flagw,"Bloated\n"); - - - if (Player.status[POISONED]>0) - wprintw(Flagw,"Poisoned\n"); - else wprintw(Flagw,"Vigorous\n"); - - if (Player.status[DISEASED]>0) - wprintw(Flagw,"Diseased\n"); - else wprintw(Flagw,"Healthy\n"); - - if (State.getMounted()) wprintw(Flagw,"Mounted\n"); - else if (Player.status[LEVITATING]) wprintw(Flagw,"Levitating\n"); - else wprintw(Flagw,"Afoot\n"); - - wrefresh(Flagw); -} - -void drawomega(void) -{ - int i; - clear(); - touchwin(stdscr); - for(i=0; i<7; i++) { - move(1, 1); - if (optionp(SHOW_COLOUR)) - wattrset(stdscr, CHARATTR(CLR(LIGHT_BLUE))); - printw("\n\n\n"); - printw("\n *****"); - printw("\n ****** ******"); - printw("\n *** ***"); - printw("\n *** ***"); - printw("\n ** **"); - printw("\n *** ***"); - printw("\n ** **"); - printw("\n ** **"); - printw("\n *** ***"); - printw("\n *** ***"); - printw("\n ** **"); - printw("\n * *** *** *"); - printw("\n **** ****"); - refresh(); - usleep(200000); - move(1, 1); - if (optionp(SHOW_COLOUR)) - wattrset(stdscr, CHARATTR(CLR(CYAN))); - printw("\n\n\n"); - printw("\n +++++"); - printw("\n ++++++ ++++++"); - printw("\n +++ +++"); - printw("\n +++ +++"); - printw("\n ++ ++"); - printw("\n +++ +++"); - printw("\n ++ ++"); - printw("\n ++ ++"); - printw("\n +++ +++"); - printw("\n +++ +++"); - printw("\n ++ ++"); - printw("\n + +++ +++ +"); - printw("\n ++++ ++++"); - refresh(); - usleep(200000); - move(1, 1); - if (optionp(SHOW_COLOUR)) - wattrset(stdscr, CHARATTR(CLR(BLUE))); - printw("\n\n\n"); - printw("\n ....."); - printw("\n ...... ......"); - printw("\n ... ..."); - printw("\n ... ..."); - printw("\n .. .."); - printw("\n ... ..."); - printw("\n .. .."); - printw("\n .. .."); - printw("\n ... ..."); - printw("\n ... ..."); - printw("\n .. .."); - printw("\n . ... ... ."); - printw("\n .... ...."); - refresh(); - usleep(200000); - } - wattrset(stdscr, CHARATTR(CLR(WHITE))); -} - -/* y is an absolute coordinate */ -/* ScreenOffset is the upper left hand corner of the current screen - in absolute coordinates */ -#if 0 -void screencheck(int y) -{ - if (((y-ScreenOffset) < (ScreenLength/8)) || - ((y-ScreenOffset) > (7*ScreenLength/8))) { - ScreenOffset = y - (ScreenLength/2); - show_screen(); - if (Current_Environment != E_COUNTRYSIDE) - drawmonsters(true); - if (!offscreen(Player.x,Player.y)) - drawplayer(); - } -} -#else -void screencheck(int x, int y) -{ - int change = 0; -#ifdef CENTER_ON_PLAYER - - change = 1; - ScreenOffset = y - (ScreenLength/2); - ScreenXOffset = x - (ScreenWidth/2); - - -#else - if (((y-ScreenOffset) < (ScreenLength/8)) || - ((y-ScreenOffset) > (7*ScreenLength/8))) { - change = 1; - ScreenOffset = y - (ScreenLength/2); - } - - if (((x-ScreenXOffset) < (ScreenWidth/8)) || - ((x-ScreenXOffset) > (7*ScreenWidth/8))) { - -#if 0 - int width; - if ( Current_Environment == E_COUNTRYSIDE ) - width = COUNTRY_WIDTH; - else - width = Level->level_width; - - /* - PGM: this code prevents scrolling when near the right edge of the level, - but this unfortunately results in a badly placed view when, for examples, - restoring a save near the edge of a level. Ideas on fixing this, or moving - it, appreciated. PGM July 1999. - */ - if ( ( (x-ScreenXOffset) + (7*ScreenWidth/8) ) < width +( ScreenWidth/8 ) ) -#endif - { - change = 1; - ScreenXOffset = x - (ScreenWidth/2); - if (ScreenXOffset < 0) - ScreenXOffset = 0; - } - } - -#endif - if ( change == 1 ) { - show_screen(); - if (Current_Environment != E_COUNTRYSIDE) - drawmonsters(true); - if (!offscreen(Player.x,Player.y)) - drawplayer(); - } -} -#endif - -void spreadroomlight(int x, int y, int roomno) -{ - if (inbounds(x,y) && !loc_statusp(x,y,LIT) && - Level->site[x][y].roomnumber == roomno) { - lightspot(x,y); - spreadroomlight(x+1,y,roomno); - spreadroomlight(x,y+1,roomno); - spreadroomlight(x-1,y,roomno); - spreadroomlight(x,y-1,roomno); - } -} - -/* illuminate one spot at x y */ -void lightspot(int x, int y) -{ - Symbol c; - lset(x,y,LIT); - lset(x,y,SEEN); - lset(x, y, CHANGED); - c = getspot(x,y,false); - Level->site[x][y].showchar = c; - putspot(x,y,c); -} - - -void spreadroomdark(int x, int y, int roomno) -{ - if (inbounds(x,y)) - if (loc_statusp(x,y,LIT) && (Level->site[x][y].roomnumber == roomno)) { - blankoutspot(x,y); - spreadroomdark(x+1,y,roomno); - spreadroomdark(x,y+1,roomno); - spreadroomdark(x-1,y,roomno); - spreadroomdark(x,y-1,roomno); - } -} - - -void display_pack(void) -{ - int i; - if (Player.packptr < 1) print3("Pack is empty."); - else { - menuclear(); - menuprint("Items in Pack:\n"); - for(i=0; iused) - usechar = '>'; - if (topline) W = Msg3w; - else { - W = Showline[slotnum]; - hide_line(slotnum); - } - idchar = index_to_key(slotnum); - touchwin(W); - wclear(W); - switch(slotnum) { - case O_UP_IN_AIR: - wprintw(W,"-- Object 'up in air':",usechar); - break; - case O_READY_HAND: - wprintw(W,"-- %c%c ready hand: ",idchar,usechar); - break; - case O_WEAPON_HAND: - wprintw(W,"-- %c%c weapon hand: ",idchar,usechar); - break; - case O_LEFT_SHOULDER: - wprintw(W,"-- %c%c left shoulder: ",idchar,usechar); - break; - case O_RIGHT_SHOULDER: - wprintw(W,"-- %c%c right shoulder: ",idchar,usechar); - break; - case O_BELT1: - wprintw(W,"-- %c%c belt: ",idchar,usechar); - break; - case O_BELT2: - wprintw(W,"-- %c%c belt: ",idchar,usechar); - break; - case O_BELT3: - wprintw(W,"-- %c%c belt: ",idchar,usechar); - break; - case O_SHIELD: - wprintw(W,"-- %c%c shield: ",idchar,usechar); - break; - case O_ARMOR: - wprintw(W,"-- %c%c armor: ",idchar,usechar); - break; - case O_BOOTS: - wprintw(W,"-- %c%c boots: ",idchar,usechar); - break; - case O_CLOAK: - wprintw(W,"-- %c%c cloak: ",idchar,usechar); - break; - case O_RING1: - wprintw(W,"-- %c%c finger: ",idchar,usechar); - break; - case O_RING2: - wprintw(W,"-- %c%c finger: ",idchar,usechar); - break; - case O_RING3: - wprintw(W,"-- %c%c finger: ",idchar,usechar); - break; - case O_RING4: - wprintw(W,"-- %c%c finger: ",idchar,usechar); - break; - } - if (Player.possessions[slotnum] != NULL) - wprintw(W,itemid(Player.possessions[slotnum])); - wrefresh(W); -} - -int move_slot(int oldslot, int newslot, int maxslot) -{ - if ((newslot >= 0) && (newslot < maxslot)) { - wmove(Showline[oldslot],0,0); - waddstr(Showline[oldslot],"--"); - wrefresh(Showline[oldslot]); - wmove(Showline[newslot],0,0); - wstandout(Showline[newslot]); - waddstr(Showline[newslot],">>"); - wstandend(Showline[newslot]); - wrefresh(Showline[newslot]); - return(newslot); - } - else return(oldslot); -} - -void colour_on(void) -{ -} - -void colour_off(void) -{ - wattrset(Levelw, CHARATTR(CLR(WHITE))); -} - -void display_option_slot(int slot) -{ - hide_line(slot); - wclear(Showline[slot]); - switch(slot) { - case 1: - wprintw(Showline[slot],"-- Option BELLICOSE [TF]: "); - wprintw(Showline[slot], optionp(BELLICOSE) ? "(now T) " : "(now F) "); - break; - case 2: - wprintw(Showline[slot],"-- Option JUMPMOVE [TF]: "); - wprintw(Showline[slot], optionp(JUMPMOVE) ? "(now T) " : "(now F) "); - break; - case 3: - wprintw(Showline[slot],"-- Option RUNSTOP [TF]: "); - wprintw(Showline[slot], optionp(RUNSTOP) ? "(now T) " : "(now F) "); - break; - case 4: - wprintw(Showline[slot],"-- Option PICKUP [TF]: "); - wprintw(Showline[slot], optionp(PICKUP) ? "(now T) " : "(now F) "); - break; - case 5: - wprintw(Showline[slot],"-- Option CONFIRM [TF]: "); - wprintw(Showline[slot], optionp(CONFIRM) ? "(now T) " : "(now F) "); - break; - case 6: - wprintw(Showline[slot],"-- Option TOPINV [TF]: "); - wprintw(Showline[slot], optionp(TOPINV) ? "(now T) " : "(now F) "); - break; - case 7: - wprintw(Showline[slot],"-- Option PACKADD [TF]: "); - wprintw(Showline[slot], optionp(PACKADD) ? "(now T) " : "(now F) "); - break; - case 8: - wprintw(Showline[slot],"-- Option COLOUR [TF]: "); - wprintw(Showline[slot], optionp(SHOW_COLOUR) ? "(now T) " : "(now F) "); - break; - case VERBOSITY_LEVEL: - wprintw(Showline[slot], - "-- Option VERBOSITY [(T)erse,(M)edium,(V)erbose]: (now "); - if (Verbosity == VERBOSE) wprintw(Showline[slot],"Verbose)"); - else if (Verbosity == MEDIUM) wprintw(Showline[slot],"Medium)"); - else wprintw(Showline[slot],"Terse)"); - break; - case SEARCH_DURATION: - wprintw(Showline[slot],"-- Option SEARCHNUM [0>x>10]: (now %d)",Searchnum); - break; - } - wrefresh(Showline[slot]); -} - -void display_stat_slot(int slot) -{ - hide_line(slot); - wclear(Showline[slot]); - switch(slot) { - case 1: - wprintw(Showline[slot],"-- Strength ... [%d]: ", Player.str); - break; - case 2: - wprintw(Showline[slot],"-- Constitution [%d]: ", Player.con); - break; - case 3: - wprintw(Showline[slot],"-- Dexterity .. [%d]: ", Player.dex); - break; - case 4: - wprintw(Showline[slot],"-- Agility .... [%d]: ", Player.agi); - break; - case 5: - wprintw(Showline[slot],"-- Intelligence [%d]: ", Player.iq); - break; - case 6: - wprintw(Showline[slot],"-- Power ...... [%d]: ", Player.pow); - break; - case 7: - wprintw(Showline[slot],"-- HP ......... [%d]: ", Player.hp); - break; - case 8: - wprintw(Showline[slot],"-- Max HP ..... [%d]: ", Player.maxhp); - break; - case 9: - wprintw(Showline[slot],"-- Mana ....... [%d]: ", Player.mana); - break; - case 10: - wprintw(Showline[slot],"-- Max Mana ... [%d]: ", Player.maxmana); - break; - case 11: - wprintw(Showline[slot],"-- Cash ....... [%d]: ", Player.cash); - break; - } - wrefresh(Showline[slot]); -} - -void display_options(void) -{ - int i; - menuclear(); - hide_line(0); - for(i=1; i<=NUMOPTIONS; i++) - display_option_slot(i); -} - -void display_stats(void) -{ - int i; - menuclear(); - hide_line(0); - for(i=1; i<=NUMSTATS; i++) - display_stat_slot(i); -} - -/* nya ha ha ha ha haaaa.... */ -void deathprint(void) -{ - mgetc(); - waddch(Msgw,'D'); - wrefresh(Msgw); - mgetc(); - waddch(Msgw,'e'); - wrefresh(Msgw); - mgetc(); - waddch(Msgw,'a'); - wrefresh(Msgw); - mgetc(); - waddch(Msgw,'t'); - wrefresh(Msgw); - mgetc(); - waddch(Msgw,'h'); - wrefresh(Msgw); - mgetc(); -} - -void clear_if_necessary(void) -{ - int x,y; - getyx(Msg1w,y,x); - - if (x != 0) { - wclear(Msg1w); - wrefresh(Msg1w); - } - - getyx(Msg2w,y,x); - - if (x != 0) { - wclear(Msg2w); - wrefresh(Msg2w); - } - - getyx(Msg3w,y,x); - - if (x != 0) { - erasemsg3(); - wrefresh(Msg3w); - } -} - -int bufferpos = 0; - -void buffercycle(const char *s) -{ - strcpy(Stringbuffer[bufferpos++],s); - if (bufferpos >= STRING_BUFFER_SIZE) - bufferpos = 0; -} - -int bufferappend(char *s) -{ - int pos = bufferpos - 1; - - if (pos < 0) - pos = STRING_BUFFER_SIZE - 1; - if (strlen(Stringbuffer[pos]) + strlen(s) < 80 - 1) { - strcat(Stringbuffer[pos],s); - return 1; - } - else - return 0; -} - - -void bufferprint(void) -{ - int i = bufferpos - 1, c, finished = 0; - clearmsg(); -#if !defined(WIN32) - wprintw(Msg1w,"^p for previous message, ^n for next, anything else to quit."); -#else - wprintw(Msg1w,"^o for last message, ^n for next, anything else to quit."); -#endif - wrefresh(Msg1w); - do { - if (i >= STRING_BUFFER_SIZE) i = 0; - if (i < 0) i = STRING_BUFFER_SIZE - 1; - wclear(Msg2w); - wprintw(Msg2w,Stringbuffer[i]); - wrefresh(Msg2w); - c = mgetc(); -#if !defined(WIN32) - if (c == 16) /* ^p */ -#else - if (c == 15) /* ^o */ -#endif - i--; - else if (c == 14) /* ^n */ - i++; - else - finished = 1; - } while (!finished); - clearmsg(); - omshowcursor(Player.x,Player.y); -} - -void clear_screen(void) -{ - clear(); - touchwin(stdscr); - refresh(); -} +/* omega (c) 1987,1988,1989 by Laurence Raphael Brothers */ +/* scr.c */ +/* functions that use curses routines directly */ +/* plus a few file i/o stuff */ +/* also some in file.c */ + +#define CHARATTR(c) ((c) & ~0xff) + +#include "glob.h" + +// Screen flicker fix +#undef wclear +#define wclear werase + +WINDOW *Bankw; + +/* note these variables are not exported to other files */ + +WINDOW *Levelw,*Dataw,*Flagw,*Timew,*Menuw,*Locw,*Morew,*Phasew; +WINDOW *Comwin,*Msg1w,*Msg2w,*Msg3w,*Msgw; + +WINDOW *Cinema; +/* WDT: interactions and special effects which currently + * go into the message window should instead go here. This + * should simplify history-keeping, since we only need to + * record actual messages, not special effects. */ + +WINDOW *Showline[MAXITEMS]; + +WINDOW *Wizlistw; + +#define SL3_LEN 160 +char screenLine3[SL3_LEN]; + +/* static function prototypes */ + +static long input_number (WINDOW * w); + +/* function definitions */ + +void phaseprint(void) +{ + wclear(Phasew); + wprintw(Phasew,"Moon's Phase:\n"); + switch(Phase/2) { + case 0: + wprintw(Phasew,"NEW"); + break; + case 1: + case 11: + wprintw(Phasew,"CRESCENT"); + break; + case 2: + case 10: + wprintw(Phasew,"1/4"); + break; + case 3: + case 9: + wprintw(Phasew,"HALF"); + break; + case 4: + case 8: + wprintw(Phasew,"3/4"); + break; + case 5: + case 7: + wprintw(Phasew,"GIBBOUS"); + break; + case 6: + wprintw(Phasew,"FULL"); + break; + } + wrefresh(Phasew); +} + +static void show_screen_level (int top, int left, int bottom, int right) +{ + int j; + int last_attr = 0; + + for (j = top; j < bottom; ++j) + { + int i; + + wmove(Levelw, screenmody(j), 0); + + for (i = left; i < right; ++i) + { + int c; + + if (loc_statusp(i, j, SEEN)) + c = getspot(i, j, false); + else + c = SPACE; + + if (optionp(SHOW_COLOUR) && CHARATTR(c) != last_attr) + { + last_attr = CHARATTR(c); + wattrset(Levelw, last_attr); + } + + waddch(Levelw, c & 0xff); + } + } +} + +static void show_screen_country (int top, int left, int bottom, int right) +{ + int j; + int last_attr = 0; + + for (j = top; j < bottom; ++j) + { + int i; + + wmove(Levelw, screenmody(j), 0); + + for (i = left; i < right; ++i) + { + int c; + + if (c_statusp(i, j, SEEN)) + c = Country[i][j].current_terrain_type; + else + c = SPACE; + + if (optionp(SHOW_COLOUR) && CHARATTR(c) != last_attr) + { + last_attr = CHARATTR(c); + wattrset(Levelw, last_attr); + } + + waddch(Levelw, c & 0xff); + } + } +} + +void show_screen(void) +{ + int top; + int left; + int right; + int bottom; + + wclear(Levelw); + + if (ScreenOffset < 0) ScreenOffset = 0; + if (ScreenXOffset < 0) ScreenXOffset = 0; + + top = ScreenOffset; + left = ScreenXOffset; + right = ScreenXOffset + ScreenWidth; + bottom = ScreenOffset + ScreenLength; + + if (Current_Environment != E_COUNTRYSIDE) + { + if (right > Level->level_width) right = Level->level_width; + if (bottom > Level->level_length) bottom = Level->level_length; + } + else + { + if (right > COUNTRY_WIDTH) right = COUNTRY_WIDTH; + if (bottom > COUNTRY_LENGTH) bottom = COUNTRY_LENGTH; + } + + if (Current_Environment != E_COUNTRYSIDE) + { + show_screen_level(top, left, bottom, right); + } + else + { + show_screen_country(top, left, bottom, right); +#if 0 // anyone remember why this is out? to prevent redrawing the screen every damn time? + for (j=top; j=(int)'A') && (c<=(int)'Z')) + return(c+(int)('a'-'A')); + else + return(c); +} + +char menugetc(void) +{ + return(wgetch(Menuw)); +} + +char lgetc(void) +{ + return(wgetch(Levelw)); +} + +int ynq(void) +{ + int p='*'; /* the user's choice; start with something impossible + * to prevent a loop. */ + while ((p != 'n') && (p != 'y') && (p != 'q') && (p != ESCAPE) && + (p != EOF) && (p != ' ')) + p = wgetch(Msgw); + switch (p) { + case 'y': + wprintw(Msgw,"yes. "); + break; + case 'n': + wprintw(Msgw,"no. "); + break; + + case ESCAPE: + p = 'q'; /* fall through to 'q' */ + case ' ': + p = 'q'; /* fall through to 'q' */ + case 'q': + wprintw(Msgw,"quit. "); + break; + default: + assert( p == EOF ); + } + wrefresh(Msgw); + return(p); +} + + +int ynq1(void) +{ + int p='*'; /* the user's choice; start with something impossible + * to prevent a loop. */ + while ((p != 'n') && (p != 'y') && (p != 'q') && (p != ESCAPE) && + (p != ' ') && (p != EOF)) + p = wgetch(Msg1w); + switch (p) { + case 'y': + wprintw(Msg1w,"yes. "); + break; + case 'n': + wprintw(Msg1w,"no. "); + break; + + case ESCAPE: + p = 'q'; /* fall through to 'q' */ + case ' ': + p = 'q'; /* fall through to 'q' */ + case 'q': + wprintw(Msg1w,"quit. "); + break; + default: + assert( p == EOF ); + } + wrefresh(Msg1w); + return(p); +} + + +int ynq2(void) +{ + int p='*'; /* the user's choice; start with something impossible + * to prevent a loop. */ + while ((p != 'n') && (p != 'y') && (p != 'q') && (p != ESCAPE) && + (p != ' ') && (p != EOF)) + p = wgetch(Msg2w); + switch (p) { + case 'y': + wprintw(Msg2w,"yes. "); + break; + case 'n': + wprintw(Msg2w,"no. "); + break; + + case ESCAPE: + p = 'q'; /* fall through to 'q' */ + case ' ': + p = 'q'; /* fall through to 'q' */ + case 'q': + wprintw(Msg2w,"quit. "); + break; + default: + assert( p == EOF ); + } + wrefresh(Msg2w); + return(p); +} + +void erasemsg3 (void) +{ + werase(Msg3w); + memset(screenLine3, 0, SL3_LEN); +} + +/* puts up a morewait to allow reading if anything in top two lines */ +void checkclear(void) +{ + int x1,y,x2; + getyx(Msg1w,x1,y); + getyx(Msg2w,x2,y); + if ((x1 != 0) || (x2 != 0)) { + morewait(); + wclear(Msg1w); + wclear(Msg2w); + wrefresh(Msg1w); + wrefresh(Msg2w); + } +} + +/* for external call */ +void clearmsg(void) +{ + wclear(Msg1w); + wclear(Msg2w); + erasemsg3(); + Msgw = Msg1w; + wrefresh(Msg1w); + wrefresh(Msg2w); + wrefresh(Msg3w); +} + +void clearmsg3(void) +{ + erasemsg3(); + wrefresh(Msg3w); +} + +void clearmsg1(void) +{ + wclear(Msg1w); + wclear(Msg2w); + Msgw = Msg1w; + wrefresh(Msg1w); + wrefresh(Msg2w); +} + +void erase_level(void) +{ + wclear(Levelw); + wrefresh(Levelw); +} + +/* direct print to first msg line */ +void print1(const char *s) +{ + if (! State.getSuppressPrinting()) { + buffercycle(s); + wclear(Msg1w); + wprintw(Msg1w,s); + wrefresh(Msg1w); + } +} + +/* for run on-messages -- print1 clears first.... */ +void nprint1(char *s) +{ + if (! State.getSuppressPrinting()) { + if (bufferappend(s)) { + wprintw(Msg1w,s); + wrefresh(Msg1w); + } + } +} + +/* direct print to second msg line */ +void print2(char *s) +{ + if (! State.getSuppressPrinting()) { + buffercycle(s); + wclear(Msg2w); + wprintw(Msg2w,s); + wrefresh(Msg2w); + } +} + +/* for run on-messages -- print2 clears first.... */ +void nprint2(char *s) +{ + if (! State.getSuppressPrinting()) { + if (bufferappend(s)) { + wprintw(Msg2w,s); + wrefresh(Msg2w); + } + } +} + + +/* msg line 3 is not part of the region that mprint or printm can reach */ +/* typical use of print3 is for "you can't do that" type error messages */ +/* WDT: it's also typically used for messages intended to persist a while. + * Thus I'm having print3 save its input in a global variable which other + * things can use. */ +void print3 (char *s) +{ + if (!State.getSuppressPrinting()) + { + buffercycle(s); + erasemsg3(); + wprintw(Msg3w, s); + strcpy(screenLine3, s); + wrefresh(Msg3w); + } +} + +/* for run on-messages -- print3 clears first.... */ +void nprint3(char *s) +{ + if (!State.getSuppressPrinting()) + { + if (bufferappend(s)) + { + strcat(screenLine3, s); + wprintw(Msg3w,s); + wrefresh(Msg3w); + } + } +} + + + +/* prints wherever cursor is in window, but checks to see if +it should morewait and clear window */ +void mprint(char *s) +{ + int x,y; + if (! State.getSuppressPrinting()) { + getyx(Msgw,y,x); + if (x+strlen(s) >= ScreenWidth) { + buffercycle(s); + if (Msgw == Msg1w) { + wclear(Msg2w); + Msgw = Msg2w; + } + else { + morewait(); + wclear(Msg1w); + wclear(Msg2w); + wrefresh(Msg2w); + Msgw = Msg1w; + } + } + else if (x > 0) + bufferappend(s); + else + buffercycle(s); + wprintw(Msgw,s); + waddch(Msgw,' '); + wrefresh(Msgw); + } +} + + +void omega_title(void) +{ + showmotd(); + clear(); + touchwin(stdscr); + refresh(); + /* showscores();*/ /* DG */ +} + + + +/* blanks out ith line of Menuw or Levelw */ +void hide_line(int i) +{ + wclear(Showline[i]); + touchwin(Showline[i]); + wrefresh(Showline[i]); +} + +#ifdef USE_OPCURSES +static void load_tiles (void) +{ + char * path; + + path = malloc(strlen(OMEGALIB) + strlen(TILEFILE) + 1); + if (0 == path) return; + + strcpy(path, OMEGALIB); + strcat(path, TILEFILE); + + set_tiles(path); + + free(path); +} +#endif + +/* initialize, screen, windows */ +void initgraf(void) +{ + int i; + +#ifdef USE_OPCURSES + load_tiles(); +#endif + + initscr(); + start_color(); + clrgen_init(); + + if (LINES < 24 || COLS < 80) { + printf("Minimum Screen Size: 24 Lines by 80 Columns."); + exit(0); + } + ScreenLength = LINES - 6; + ScreenWidth = 64; + Msg1w = newwin(1,80,0,0); + scrollok(Msg1w, 0); + Msg2w = newwin(1,80,1,0); + scrollok(Msg2w, 0); + Msg3w = newwin(1,80,2,0); + scrollok(Msg3w, 0); + Msgw = Msg1w; + Morew = newwin(1,15,3,65); + scrollok(Morew, 0); + + // Bank window + Bankw = newwin( 20, 50, ( ScreenLength - 20 ) / 2 + 3, 7 ); + scrollok( Bankw, 0 ); + + // Wiz flag list window + Wizlistw = newwin( 20, 50, 3, 0 ); + scrollok( Wizlistw, 0 ); + + Locw = newwin(1,80,ScreenLength+3,0); + scrollok(Locw, 0); + Levelw = newwin(ScreenLength,ScreenWidth,3,0); + scrollok(Levelw, 0); + for(i=0; i 0); + + while (1) + { + cinema_display(line1, line2, line3); + response = cinema_getch(); + if (-1 == response) break; + if (strchr(choices, response)) break; + if (!line3) line3 = "What? Try again!"; + } + + cinema_hide(); + return response; +} + +int cinema_interact_line (int line, char * choices, char * text) +{ + int response; + + assert(0 == line || 1 == line); + assert(choices && strlen(choices) > 0); + + while (1) + { + cinema_print_line(line, text); + response = cinema_getch(); + if (ABORT == response) break; + if (strchr(choices, response)) break; + cinema_print_line(2, "What? Try again!"); + } + + return response; +} + +int cinema_ynq_line (int line, char * prompt) +{ + return cinema_interact_line(line, "ynqYNQ", prompt); +} + +int cinema_getnum_line (int line, char * prompt) +{ + int num; + + assert(0 == line || 1 == line); + + cinema_blank_line(line); + cinema_print_line(line, prompt); + num = (int)input_number(Cinema); + + return num; +} + +int cinema_confirm (char * action_description) +{ + char *msg; + + switch (random_range(4)) + { + case 0: + msg = "Are you sure? [yn] "; + break; + case 1: + msg = "Certain about that? [yn] "; + break; + case 2: + msg = "Do you really mean it? [yn] "; + break; + default: + msg = "Confirm that, would you? [yn] "; + break; + } + + //const char *msg = m[random_range(4)].c_str(); + return cinema_interact("ynqYNQ", action_description, (char*)msg, NULL); +} + +int cinema_ynq (char *action_description) +{ + return cinema_interact("ynqYNQ", action_description, NULL, NULL); +} + +void cinema_scene (char *line1, char *line2, char *line3) +{ + cinema_display(line1, line2, line3); + morewait(); + cinema_hide(); +} + +int lastx= -1,lasty= -1; + +void drawplayer(void) +{ + int c; + + if (E_COUNTRYSIDE == Current_Environment) + { + if (inbounds(lastx, lasty) && !offscreen(lastx, lasty)) + { + wmove(Levelw, screenmody(lasty), screenmodx(lastx)); + c = Country[lastx][lasty].current_terrain_type; + + if (optionp(SHOW_COLOUR)) wattrset(Levelw, CHARATTR(c)); + + waddch(Levelw, c & 0xff); + } + + wmove(Levelw, screenmody(Player.y), screenmodx(Player.x)); + + if (optionp(SHOW_COLOUR)) wattrset(Levelw, CHARATTR(PLAYER)); + + waddch(Levelw, PLAYER & 0xff); + } + else + { + if (inbounds(lastx, lasty) && !offscreen(lastx, lasty)) + plotspot(lastx, lasty, (Player.status[BLINDED] > 0 ? false : true)); + + wmove(Levelw, screenmody(Player.y), screenmodx(Player.x)); + + if ((!Player.status[INVISIBLE]) || Player.status[TRUESIGHT]) + { + if (optionp(SHOW_COLOUR)) wattrset(Levelw, CHARATTR(PLAYER)); + waddch(Levelw, PLAYER & 0xff); + } + } + + lastx = Player.x; + lasty = Player.y; +} + +void setlastxy(int new_x, int new_y) /* used when changing environments */ +{ + lastx = new_x; + lasty = new_y; +} + +int litroom(int x, int y) +{ + if (Level->site[x][y].roomnumber < ROOMBASE) return(false); + else return(loc_statusp(x,y,LIT) || + Player.status[ILLUMINATION]); +} + +void drawvision(int x, int y) +{ + static int oldx = -1,oldy = -1; + int i,j,c; + + if (Current_Environment != E_COUNTRYSIDE) { + if (Player.status[BLINDED]) { + drawspot(oldx,oldy); + drawspot(x,y); + drawplayer(); + } + else { + if (Player.status[ILLUMINATION] > 0) { + for (i= -2; i<3; i++) + for (j= -2; j<3; j++) + if (inbounds(x+i,y+j)) + if (view_los_p(x+i,y+j,Player.x,Player.y)) + dodrawspot(x+i,y+j); + } + else { + for (i= -1; i<2; i++) + for (j= -1; j<2; j++) + if (inbounds(x+i,y+j)) + dodrawspot(x+i,y+j); + } + drawplayer(); + drawmonsters(false); /* erase all monsters */ + drawmonsters(true); /* draw those now visible */ + } + if ((State.getFastMove() == false) || (! optionp(JUMPMOVE))) + omshowcursor(Player.x,Player.y); + oldx = x; + oldy = y; + } + else { + for (i= -1; i<2; i++) + for (j= -1; j<2; j++) + if (inbounds(x+i,y+j)) { + c_set(x+i, y+j, SEEN); + if (!offscreen(x+i,y+j)) { + wmove(Levelw,screenmody(y+j),screenmodx(x+i)); + c = Country[x+i][y+j].current_terrain_type; + if (optionp(SHOW_COLOUR)) + wattrset(Levelw, CHARATTR(c)); + waddch(Levelw,(c&0xff)); + } + } + drawplayer(); + omshowcursor(Player.x,Player.y); + } +} + + +void omshowcursor(int x, int y) +{ + if (! offscreen(x,y)) { + wmove(Levelw,screenmody(y),screenmodx(x)); + wrefresh(Levelw); + } +} + +void levelrefresh(void) +{ + wrefresh(Levelw); +} + + +/* draws a particular spot under if in line-of-sight */ +void drawspot(int x, int y) +{ + Symbol c; + if (inbounds(x,y)) { + c = getspot(x,y,false); + if (c != Level->site[x][y].showchar) + if (view_los_p(Player.x,Player.y,x,y)) { + lset(x,y,SEEN); + Level->site[x][y].showchar = c; + putspot(x,y,c); + } + } +} + + + +/* draws a particular spot regardless of line-of-sight */ +void dodrawspot(int x, int y) +{ + Symbol c; + if (inbounds(x,y)) { + c = getspot(x,y,false); + if (c != Level->site[x][y].showchar) { + lset(x,y,SEEN); + Level->site[x][y].showchar = c; + putspot(x,y,c); + } + } +} + +/* write a blank to a spot if it is floor */ +void blankoutspot(int i, int j) +{ + if (inbounds(i,j)) { + lreset(i,j,LIT); + lset(i, j, CHANGED); + if (Level->site[i][j].locchar == FLOOR) { + Level->site[i][j].showchar = SPACE; + putspot(i,j,SPACE); + } + } +} + +/* blank out a spot regardless */ +void blotspot(int i, int j) +{ + if (inbounds(i,j)) { + lreset(i,j,SEEN); + Level->site[i][j].showchar = SPACE; + if (! offscreen(i,j)) { + wmove(Levelw,screenmody(j),screenmodx(i)); + wattrset(Levelw, CHARATTR(SPACE)); + waddch(Levelw, SPACE&0xff); + } + } +} + + +/* for displaying activity specifically at some point */ +void plotspot(int x, int y, int showmonster) +{ + if (loc_statusp(x,y,SEEN)) + putspot(x,y,getspot(x,y,showmonster)); + else + putspot(x,y,SPACE); +} + + +/* Puts c at x,y on screen. No fuss, no bother. */ +void putspot(int x, int y, Symbol c) +{ + if (! offscreen(x,y)) { + wmove(Levelw,screenmody(y),screenmodx(x)); + if (optionp(SHOW_COLOUR)) + wattrset(Levelw, CHARATTR(c)); + waddch(Levelw,(0xff&c)); + } +} + + +/* regardless of line of sight, etc, draw a monster */ +void plotmon(Monster* m) +{ + if (! offscreen(m->x,m->y)) { + wmove(Levelw,screenmody(m->y),screenmodx(m->x)); + if (optionp(SHOW_COLOUR)) + wattrset(Levelw, CHARATTR(m->symbol)); + waddch(Levelw,(m->symbol&0xff)); + } +} + +/* if display, displays monsters, otherwise erases them */ +void drawmonsters(int display) +{ + MonsterList* ml; + for (ml=Level->mlist; ml!=NULL; ml=ml->next) { + if (ml->monster->hp > 0) { + if (display) { + if (view_los_p(Player.x,Player.y,ml->monster->x,ml->monster->y)) { + if (Player.status[TRUESIGHT] || (! m_statusp(ml->monster,M_INVISIBLE))) { + if (!optionp(SHOW_COLOUR) && + (ml->monster->level > 5) && + ((ml->monster->symbol&0xff) != '@') && + ((ml->monster->symbol&0xff) != '|')) wstandout(Levelw); + putspot(ml->monster->x,ml->monster->y,ml->monster->symbol); + if (!optionp(SHOW_COLOUR)) + wstandend(Levelw); + } + } + } + else erase_monster(ml->monster); + } + } +} + +/* replace monster with what would be displayed if monster weren't there */ +void erase_monster(Monster* m) +{ + if (loc_statusp(m->x,m->y,SEEN)) + putspot(m->x,m->y,getspot(m->x,m->y,false)); + else blotspot(m->x,m->y); +} + +/* find apt char to display at some location */ +Symbol getspot(int x, int y, int showmonster) +{ +#ifdef CENTER_ON_PLAYER + /* funny scrolling may cause this. PGM */ + if (!inbounds(x,y ) ) + { + return SPACE; + } +#endif + + if (loc_statusp(x,y,SECRET)) + { + if ( Level->site[x][y].roomnumber == RS_DRUID ) + return(HEDGE); /* secret doors in druid temple are brambles -DAG */ + else + return(WALL); + } + else switch (Level->site[x][y].locchar) { + case WATER: + if (Level->site[x][y].creature == NULL) + return(WATER); + else if (m_statusp(Level->site[x][y].creature,SWIMMING)) + return(WATER); + else if (showmonster) + return(Level->site[x][y].creature->symbol); + else return(WATER); + /* these sites never show anything but their location char's */ + case CLOSED_DOOR: + case LAVA: + case FIRE: + case ABYSS: + return(Level->site[x][y].locchar); + /* rubble and hedge don't show items on their location */ + case RUBBLE: + case HEDGE: + if (showmonster && (Level->site[x][y].creature != NULL)) { + if ((m_statusp(Level->site[x][y].creature,M_INVISIBLE)) && + (! Player.status[TRUESIGHT])) + return(getspot(x,y,false)); + else return (Level->site[x][y].creature->symbol); + } + else return(Level->site[x][y].locchar); + /* everywhere else, first try to show monster, next show items, next show + location char */ + default: + if (showmonster && (Level->site[x][y].creature != NULL)) { + if ((m_statusp(Level->site[x][y].creature,M_INVISIBLE)) && + (! Player.status[TRUESIGHT])) + return(getspot(x,y,false)); + else return (Level->site[x][y].creature->symbol); + } + else if (Level->site[x][y].things != NULL) { + if (Level->site[x][y].things->next != NULL) + return(PILE); + else return(Level->site[x][y].things->thing->objchar); + } + else return(Level->site[x][y].locchar); + } +} + +void commanderror(void) +{ + erasemsg3(); + wprintw(Msg3w, "%c : unknown command", Cmd); + wrefresh(Msg3w); +} + +void timeprint(void) +{ + static char * old_month = 0; + + /* WSS * HACK * This shouldn't be here at all but time is so screwed up */ + /* WSS * HACK * I don't know where else I can check for a new month reliably */ + if (!old_month) + old_month = month(); + else + { + /* WSS * HACK * ptr comparision... works cause they're static */ + if (old_month != month() && Player.rank[LEGION] > 0) + { + bank_account * account; + account = bank_index_number(SalaryAccount); + if (account) account->balance += SalaryAmount; + old_month = month(); + } + } + + wclear(Timew); + wprintw(Timew,"%d:%d",showhour(),showminute()); + if (showminute()==0) waddch(Timew,'0'); + wprintw(Timew,hour()>11 ? " PM \n" : " AM \n"); + wprintw(Timew,month()); + wprintw(Timew," the %d",day()); + wprintw(Timew,ordinal(day())); + wrefresh(Timew); +} + + +void comwinprint(void) +{ + wclear(Comwin); + wprintw(Comwin,"Hit: %d \n",Player.hit); + wprintw(Comwin,"Dmg: %d \n",Player.dmg); + wprintw(Comwin,"Def: %d \n",Player.defense); + wprintw(Comwin,"Arm: %d \n",Player.absorption); + wprintw(Comwin,"Spd: %d.%d \n", 5/Player.speed, 500/Player.speed%100); + wrefresh(Comwin); +} + +void dataprint(void) +{ + wclear(Dataw); + /* WDT HACK: I should make these fields spaced and appropriately justified. + * Maybe I don't feel like it right now. */ + wprintw(Dataw,"Hp:%d/%d Mana:%ld/%ld Au:%ld Level:%d/%ld Carry:%d/%d \n", + Player.hp,Player.maxhp,Player.mana,Player.maxmana,Player.cash, + Player.level,Player.xp,Player.itemweight,Player.maxweight); + wprintw(Dataw,"Str:%d/%d Con:%d/%d Dex:%d/%d Agi:%d/%d Int:%d/%d Pow:%d/%d ", + Player.str,Player.maxstr,Player.con,Player.maxcon, + Player.dex,Player.maxdex,Player.agi,Player.maxagi, + Player.iq,Player.maxiq,Player.pow,Player.maxpow); + wrefresh(Dataw); +} + + +/* redraw everything currently displayed */ +void redraw(void) +{ + touchwin(curscr); + wrefresh(curscr); +} + +/* redraw each permanent window */ +void xredraw(void) +{ + touchwin(Msgw); + touchwin(Msg3w); + touchwin(Levelw); + touchwin(Timew); + touchwin(Flagw); + touchwin(Dataw); + touchwin(Locw); + touchwin(Morew); + touchwin(Phasew); + touchwin(Comwin); + wrefresh(Msgw); + wrefresh(Msg3w); + wrefresh(Levelw); + wrefresh(Timew); + wrefresh(Flagw); + wrefresh(Dataw); + wrefresh(Locw); + wrefresh(Morew); + wrefresh(Phasew); + wrefresh(Comwin); +} + + + +void menuaddch(char c) +{ + waddch(Menuw,c); + wrefresh(Menuw); +} + + + +void morewait(void) +{ + int display=true; + int c; + if (State.getSuppressPrinting()) + return; + do { + wclear(Morew); + if (display) wprintw(Morew,"*** MORE ***"); + else wprintw(Morew,"+++ MORE +++"); + display = ! display; + wrefresh(Morew); + /* c = wgetch(Msgw); */ + c = wgetch(Morew); + } while ((c != ' ') && (c != RETURN) && (c != EOF)); + wclear(Morew); + wrefresh(Morew); +} + +int stillonblock(void) +{ + int display=true; + int c; + do { + wclear(Morew); + if (display) wprintw(Morew,"<<>>"); + else wprintw(Morew,">>>STAY?<<<"); + display = ! display; + wrefresh(Morew); + c = wgetch(Msgw); + } while ((c != ' ') && (c != ESCAPE) && (c != EOF)); + wclear(Morew); + wrefresh(Morew); + return (c == ' '); +} + +void menuclear(void) +{ + wclear(Menuw); + touchwin(Menuw); + wrefresh(Menuw); +} + +void menuspellprint(int i) +{ + int x,y; + getyx(Menuw,y,x); + if (y >= ScreenLength - 2) { + wrefresh(Menuw); + morewait(); + wclear(Menuw); + touchwin(Menuw); + } + wprintw(Menuw,spellid(i)); + wprintw(Menuw,"(%d)\n",Spells[i].powerdrain); +} + +void menuprint(char *s) +{ + int x,y; + getyx(Menuw,y,x); + if (y >= ScreenLength - 2) { + wrefresh(Menuw); + morewait(); + wclear(Menuw); + touchwin(Menuw); + } + wprintw(Menuw,s); +} + +void showmenu(void) +{ + wrefresh(Menuw); +} + + +void endgraf(void) +{ + clear(); + touchwin(stdscr); + refresh(); + endwin(); +} + + +void plotchar(Symbol pyx, int x, int y) +{ + if (! offscreen(x,y)) { + wmove(Levelw,screenmody(y),screenmodx(x)); + if (optionp(SHOW_COLOUR)) + wattrset(Levelw, CHARATTR(pyx)); + waddch(Levelw,(pyx&0xff)); + wrefresh(Levelw); + } +} + + + +void draw_explosion(Symbol pyx, int x, int y) +{ + int i,j; + + for(j=0; j<3; j++) { + for(i=0; i<9; i++) + plotchar(pyx,x+Dirs[0][i],y+Dirs[1][i]); + usleep(150000); + for(i=0; i<9; i++) + plotchar(SPACE,x+Dirs[0][i],y+Dirs[1][i]); + usleep(150000); + } + for(i=0; i<9; i++) + plotspot(x+Dirs[0][i],y+Dirs[1][i],true); + wrefresh(Levelw); +} + +char *msgscanstring(void) +{ + static char instring[80],byte='x'; + int i=0; + + instring[0]=0; + byte = mgetc(); + while (byte != '\n') { + if ((byte == 8) || (byte == 127)) { /* ^h or delete */ + if (i>0) { + i--; + dobackspace(); + } + instring[i] = 0; + } + else { + instring[i] = byte; + waddch(Msgw,byte); + wrefresh(Msgw); + i++; + instring[i] = 0; + } + byte = mgetc(); + } + return(instring); +} + + +void locprint(char *s) +{ + wclear(Locw); + wprintw(Locw,s); + wrefresh(Locw); +} + +/* draw everything whether visible or not */ +void drawscreen(void) +{ + int i,j; + if (Current_Environment == E_COUNTRYSIDE) + for (i=0; ilevel_width; i++) + for(j=0; jlevel_length; j++) + lset(i,j,SEEN); + if (Current_Environment == E_CITY) + for (i = 0; i < NUMCITYSITES; i++) + CitySiteList[i][0] = 1; + show_screen(); +} + +/*selects a number up to range */ +/* WDT HACK! This should use the interaction code, and should allow + * direct input. */ +int getnumber(int range) +{ + int done=false,value=1; + int atom; + + if (range==1) return(1); + else while (! done) { + clearmsg(); + wprintw(Msg1w,"How many? Change with < or >, ESCAPE to select:"); + mnumprint(value); +#if !defined(WIN32) + do atom=mcigetc(); + while ((atom != '<')&&(atom != '>')&&(atom!=ESCAPE)); + if ((atom=='>') && (value < range)) value++; + else if ((atom=='<') && (value > 1)) value--; + else if (atom==ESCAPE) done = true; +#else + atom=mcigetc(); + switch (atom) + { + case '>': + case 'k': +#ifdef KEY_UP + case KEY_UP: +#endif + case (char)KEY_ARROW_UP: + case (char)KEY_ARROW_LEFT: + if (value < range) + value++; + break; + case '<': + case 'j': +#ifdef KEY_DOWN + case KEY_DOWN: +#endif + case (char)KEY_ARROW_DOWN: + case (char)KEY_ARROW_RIGHT: + if (value > 1) + value--; + break; +#ifdef KEY_HOME + case KEY_HOME: +#endif + value = 1; + break; +#ifdef KEY_LL + case KEY_LL: +#endif + value = range; + break; + case ESCAPE: + clearmsg(); + done = true; + break; + } +#endif + } + return(value); +} + +static long input_number (WINDOW * w) +{ + int ch; + int ypos, xpos; + int numlen = 0; + int amount = 0; + + getyx(w, ypos, xpos); + + while (1) + { + ch = mvwgetch(w, ypos, xpos); + + if ('\n' == ch || '\r' == ch) + { + return amount; + } + else if (EOF == ch || ESCAPE == ch) + { + return ABORT; + } + else if (BACKSPACE == ch || DELETE_CHAR == ch) + { + if (numlen > 0) + { + --numlen; + amount /= 10; + mvwaddch(w, ypos, --xpos, ' '); + } + } + else if (isdigit(ch) && (numlen < 9)) + { + ++xpos; + ++numlen; + waddch(w, ch); + amount = 10 * amount + (ch - '0'); + } + else + { + beep(); + } + } +} + +/* reads a positive number up to 999999 */ +/* WDT: now asks for the number, and receives it through the cinema + * interface. Returns ABORT (-1) if aborted. */ +long parsenum (char *message) +{ + int number[8]; + int place = -1; + int i,x,y,mult=1; + long num=0; + char byte=' '; + int entering_digits = true; + + cinema_display(message, "enter a number or ESC: ", NULL); + while (entering_digits) { + byte = wgetch(Cinema); + if ((byte == BACKSPACE) || (byte == DELETE_CHAR)) { + if (place > -1) { + number[place] = 0; + place--; + getyx(Cinema,y,x); + wmove(Cinema,y,x-1); + waddch(Cinema,' '); + wmove(Cinema,y,x-1); + wrefresh(Cinema); + } + } + else if ((byte <= '9') && (byte >= '0') && (place < 7)) { + place++; + number[place]=byte; + waddch(Cinema,byte); + wrefresh(Cinema); + } + else if (isprint(byte)) { + /* I suppose I should beep here, to indicate that only digits belong. + * Right now I'm just ignoring them. + */ + } + else entering_digits = 0; + } + if (byte != '\n') num = ABORT; + else { + for (i=place; i>=0; i--) { + num += mult*(number[i]-'0'); + mult*=10; + } + } + cinema_hide(); + return num; +} + + + +void maddch(char c) +{ + waddch(Msgw,c); + wrefresh(Msgw); +} + + +void display_death(char *source) +{ + clear(); + touchwin(stdscr); + printw("\n\n\n\n"); + printw("Requiescat In Pace, "); + printw(Player.name); + printw(" (%ld points)",calc_points()); + strcpy(Str4,"Killed by "); + strcat(Str4,source); + printw("\n"); + printw(Str4); + printw("."); + printw("\n\n\n\n\nHit 'c' to continue."); + refresh(); + while (wgetch(stdscr) != 'c') + ; + clear(); + touchwin(stdscr); + refresh(); + extendlog(Str4,DEAD); +} + + +void display_win(void) +{ + clear(); + touchwin(stdscr); + printw("\n\n\n\n"); + printw(Player.name); + if (Player.rank[ADEPT]) { + printw(" is a total master of omega with %ld points!",FixedPoints); + strcpy(Str4,"A total master of omega"); + } + else { + strcpy(Str4,"retired a winner"); + printw(" triumphed in omega with %ld points!",calc_points()); + } + printw("\n\n\n\n\nHit 'c' to continue."); + refresh(); + while (wgetch(stdscr) != 'c') + ; + clear(); + touchwin(stdscr); + refresh(); + if (Player.rank[ADEPT]) + extendlog(Str4,BIGWIN); + else extendlog(Str4,WIN); +} + +void display_quit(void) +{ + clear(); + touchwin(stdscr); + printw("\n\n\n\n"); + printw(Player.name); + strcpy(Str4,"A quitter."); + printw(" wimped out with %ld points!",calc_points()); + printw("\n\n\n\n\nHit 'c' to continue."); + refresh(); + while (wgetch(stdscr) != 'c') + ; + clear(); + touchwin(stdscr); + refresh(); + extendlog(Str4,QUIT); +} + + +void display_bigwin(void) +{ + clear(); + touchwin(stdscr); + printw("\n\n\n\n"); + printw(Player.name); + strcpy(Str4,"retired, an Adept of Omega."); + printw(" retired, an Adept of Omega with %ld points!",FixedPoints); + printw("\n\n\n\n\nHit 'c' to continue."); + refresh(); + while (wgetch(stdscr) != 'c') + ; + clear(); + touchwin(stdscr); + refresh(); + extendlog(Str4,BIGWIN); +} + + +void mnumprint(int n) +{ + char numstr[20]; + sprintf(numstr,"%d",n); + bufferappend(numstr); + wprintw(Msgw,"%d",n); + wrefresh(Msgw); +} + +void mlongprint(long n) +{ + char numstr[20]; + sprintf(numstr,"%ld",n); + bufferappend(numstr); + wprintw(Msgw,"%ld",n); + wrefresh(Msgw); +} + + +void menunumprint(int n) +{ + int x,y; + getyx(Menuw,y,x); + if (y >= ScreenLength - 2) { + wrefresh(Menuw); + morewait(); + wclear(Menuw); + touchwin(Menuw); + } + wprintw(Menuw,"%d",n); +} + +void menulongprint(long n) +{ + int x,y; + getyx(Menuw,y,x); + if (y >= ScreenLength - 2) { + wrefresh(Menuw); + morewait(); + wclear(Menuw); + touchwin(Menuw); + } + wprintw(Menuw,"%ld",n); +} + + +void dobackspace(void) +{ + int x,y; + + getyx(Msgw,y,x); + if (x > 0) { + waddch(Msgw,' '); + wmove(Msgw,y,x-1); + waddch(Msgw,' '); + wmove(Msgw,y,x-1); + } + wrefresh(Msgw); +} + + +void showflags(void) +{ + + phaseprint(); + wclear(Flagw); + if (Player.food < 0) + wprintw(Flagw,"Starving\n"); + else if (Player.food <= 3) + wprintw(Flagw,"Weak\n"); + else if (Player.food <= 10) + wprintw(Flagw,"Ravenous\n"); + else if (Player.food <= 20) + wprintw(Flagw,"Hungry\n"); + else if (Player.food <= 30) + wprintw(Flagw,"A mite peckish\n"); + else if (Player.food <= 36) + wprintw(Flagw,"Content\n"); + else if (Player.food <= 44) + wprintw(Flagw,"Satiated\n"); + else wprintw(Flagw,"Bloated\n"); + + + if (Player.status[POISONED]>0) + wprintw(Flagw,"Poisoned\n"); + else wprintw(Flagw,"Vigorous\n"); + + if (Player.status[DISEASED]>0) + wprintw(Flagw,"Diseased\n"); + else wprintw(Flagw,"Healthy\n"); + + if (State.getMounted()) wprintw(Flagw,"Mounted\n"); + else if (Player.status[LEVITATING]) wprintw(Flagw,"Levitating\n"); + else wprintw(Flagw,"Afoot\n"); + + wrefresh(Flagw); +} + +void drawomega(void) +{ + int i; + clear(); + touchwin(stdscr); + for(i=0; i<7; i++) { + move(1, 1); + if (optionp(SHOW_COLOUR)) + wattrset(stdscr, CHARATTR(CLR(LIGHT_BLUE))); + printw("\n\n\n"); + printw("\n *****"); + printw("\n ****** ******"); + printw("\n *** ***"); + printw("\n *** ***"); + printw("\n ** **"); + printw("\n *** ***"); + printw("\n ** **"); + printw("\n ** **"); + printw("\n *** ***"); + printw("\n *** ***"); + printw("\n ** **"); + printw("\n * *** *** *"); + printw("\n **** ****"); + refresh(); + usleep(200000); + move(1, 1); + if (optionp(SHOW_COLOUR)) + wattrset(stdscr, CHARATTR(CLR(CYAN))); + printw("\n\n\n"); + printw("\n +++++"); + printw("\n ++++++ ++++++"); + printw("\n +++ +++"); + printw("\n +++ +++"); + printw("\n ++ ++"); + printw("\n +++ +++"); + printw("\n ++ ++"); + printw("\n ++ ++"); + printw("\n +++ +++"); + printw("\n +++ +++"); + printw("\n ++ ++"); + printw("\n + +++ +++ +"); + printw("\n ++++ ++++"); + refresh(); + usleep(200000); + move(1, 1); + if (optionp(SHOW_COLOUR)) + wattrset(stdscr, CHARATTR(CLR(BLUE))); + printw("\n\n\n"); + printw("\n ....."); + printw("\n ...... ......"); + printw("\n ... ..."); + printw("\n ... ..."); + printw("\n .. .."); + printw("\n ... ..."); + printw("\n .. .."); + printw("\n .. .."); + printw("\n ... ..."); + printw("\n ... ..."); + printw("\n .. .."); + printw("\n . ... ... ."); + printw("\n .... ...."); + refresh(); + usleep(200000); + } + wattrset(stdscr, CHARATTR(CLR(WHITE))); +} + +/* y is an absolute coordinate */ +/* ScreenOffset is the upper left hand corner of the current screen + in absolute coordinates */ +#if 0 +void screencheck(int y) +{ + if (((y-ScreenOffset) < (ScreenLength/8)) || + ((y-ScreenOffset) > (7*ScreenLength/8))) { + ScreenOffset = y - (ScreenLength/2); + show_screen(); + if (Current_Environment != E_COUNTRYSIDE) + drawmonsters(true); + if (!offscreen(Player.x,Player.y)) + drawplayer(); + } +} +#else +void screencheck(int x, int y) +{ + int change = 0; +#ifdef CENTER_ON_PLAYER + + change = 1; + ScreenOffset = y - (ScreenLength/2); + ScreenXOffset = x - (ScreenWidth/2); + + +#else + if (((y-ScreenOffset) < (ScreenLength/8)) || + ((y-ScreenOffset) > (7*ScreenLength/8))) { + change = 1; + ScreenOffset = y - (ScreenLength/2); + } + + if (((x-ScreenXOffset) < (ScreenWidth/8)) || + ((x-ScreenXOffset) > (7*ScreenWidth/8))) { + +#if 0 + int width; + if ( Current_Environment == E_COUNTRYSIDE ) + width = COUNTRY_WIDTH; + else + width = Level->level_width; + + /* + PGM: this code prevents scrolling when near the right edge of the level, + but this unfortunately results in a badly placed view when, for examples, + restoring a save near the edge of a level. Ideas on fixing this, or moving + it, appreciated. PGM July 1999. + */ + if ( ( (x-ScreenXOffset) + (7*ScreenWidth/8) ) < width +( ScreenWidth/8 ) ) +#endif + { + change = 1; + ScreenXOffset = x - (ScreenWidth/2); + if (ScreenXOffset < 0) + ScreenXOffset = 0; + } + } + +#endif + if ( change == 1 ) { + show_screen(); + if (Current_Environment != E_COUNTRYSIDE) + drawmonsters(true); + if (!offscreen(Player.x,Player.y)) + drawplayer(); + } +} +#endif + +void spreadroomlight(int x, int y, int roomno) +{ + if (inbounds(x,y) && !loc_statusp(x,y,LIT) && + Level->site[x][y].roomnumber == roomno) { + lightspot(x,y); + spreadroomlight(x+1,y,roomno); + spreadroomlight(x,y+1,roomno); + spreadroomlight(x-1,y,roomno); + spreadroomlight(x,y-1,roomno); + } +} + +/* illuminate one spot at x y */ +void lightspot(int x, int y) +{ + Symbol c; + lset(x,y,LIT); + lset(x,y,SEEN); + lset(x, y, CHANGED); + c = getspot(x,y,false); + Level->site[x][y].showchar = c; + putspot(x,y,c); +} + + +void spreadroomdark(int x, int y, int roomno) +{ + if (inbounds(x,y)) + if (loc_statusp(x,y,LIT) && (Level->site[x][y].roomnumber == roomno)) { + blankoutspot(x,y); + spreadroomdark(x+1,y,roomno); + spreadroomdark(x,y+1,roomno); + spreadroomdark(x-1,y,roomno); + spreadroomdark(x,y-1,roomno); + } +} + + +void display_pack(void) +{ + int i; + if (Player.packptr < 1) print3("Pack is empty."); + else { + menuclear(); + menuprint("Items in Pack:\n"); + for(i=0; iused) + usechar = '>'; + if (topline) W = Msg3w; + else { + W = Showline[slotnum]; + hide_line(slotnum); + } + idchar = index_to_key(slotnum); + touchwin(W); + wclear(W); + switch(slotnum) { + case O_UP_IN_AIR: + wprintw(W,"-- Object 'up in air':",usechar); + break; + case O_READY_HAND: + wprintw(W,"-- %c%c ready hand: ",idchar,usechar); + break; + case O_WEAPON_HAND: + wprintw(W,"-- %c%c weapon hand: ",idchar,usechar); + break; + case O_LEFT_SHOULDER: + wprintw(W,"-- %c%c left shoulder: ",idchar,usechar); + break; + case O_RIGHT_SHOULDER: + wprintw(W,"-- %c%c right shoulder: ",idchar,usechar); + break; + case O_BELT1: + wprintw(W,"-- %c%c belt: ",idchar,usechar); + break; + case O_BELT2: + wprintw(W,"-- %c%c belt: ",idchar,usechar); + break; + case O_BELT3: + wprintw(W,"-- %c%c belt: ",idchar,usechar); + break; + case O_SHIELD: + wprintw(W,"-- %c%c shield: ",idchar,usechar); + break; + case O_ARMOR: + wprintw(W,"-- %c%c armor: ",idchar,usechar); + break; + case O_BOOTS: + wprintw(W,"-- %c%c boots: ",idchar,usechar); + break; + case O_CLOAK: + wprintw(W,"-- %c%c cloak: ",idchar,usechar); + break; + case O_RING1: + wprintw(W,"-- %c%c finger: ",idchar,usechar); + break; + case O_RING2: + wprintw(W,"-- %c%c finger: ",idchar,usechar); + break; + case O_RING3: + wprintw(W,"-- %c%c finger: ",idchar,usechar); + break; + case O_RING4: + wprintw(W,"-- %c%c finger: ",idchar,usechar); + break; + } + if (Player.possessions[slotnum] != NULL) + wprintw(W,itemid(Player.possessions[slotnum])); + wrefresh(W); +} + +int move_slot(int oldslot, int newslot, int maxslot) +{ + if ((newslot >= 0) && (newslot < maxslot)) { + wmove(Showline[oldslot],0,0); + waddstr(Showline[oldslot],"--"); + wrefresh(Showline[oldslot]); + wmove(Showline[newslot],0,0); + wstandout(Showline[newslot]); + waddstr(Showline[newslot],">>"); + wstandend(Showline[newslot]); + wrefresh(Showline[newslot]); + return(newslot); + } + else return(oldslot); +} + +void colour_on(void) +{ +} + +void colour_off(void) +{ + wattrset(Levelw, CHARATTR(CLR(WHITE))); +} + +void display_option_slot(int slot) +{ + hide_line(slot); + wclear(Showline[slot]); + switch(slot) { + case 1: + wprintw(Showline[slot],"-- Option BELLICOSE [TF]: "); + wprintw(Showline[slot], optionp(BELLICOSE) ? "(now T) " : "(now F) "); + break; + case 2: + wprintw(Showline[slot],"-- Option JUMPMOVE [TF]: "); + wprintw(Showline[slot], optionp(JUMPMOVE) ? "(now T) " : "(now F) "); + break; + case 3: + wprintw(Showline[slot],"-- Option RUNSTOP [TF]: "); + wprintw(Showline[slot], optionp(RUNSTOP) ? "(now T) " : "(now F) "); + break; + case 4: + wprintw(Showline[slot],"-- Option PICKUP [TF]: "); + wprintw(Showline[slot], optionp(PICKUP) ? "(now T) " : "(now F) "); + break; + case 5: + wprintw(Showline[slot],"-- Option CONFIRM [TF]: "); + wprintw(Showline[slot], optionp(CONFIRM) ? "(now T) " : "(now F) "); + break; + case 6: + wprintw(Showline[slot],"-- Option TOPINV [TF]: "); + wprintw(Showline[slot], optionp(TOPINV) ? "(now T) " : "(now F) "); + break; + case 7: + wprintw(Showline[slot],"-- Option PACKADD [TF]: "); + wprintw(Showline[slot], optionp(PACKADD) ? "(now T) " : "(now F) "); + break; + case 8: + wprintw(Showline[slot],"-- Option COLOUR [TF]: "); + wprintw(Showline[slot], optionp(SHOW_COLOUR) ? "(now T) " : "(now F) "); + break; + case VERBOSITY_LEVEL: + wprintw(Showline[slot], + "-- Option VERBOSITY [(T)erse,(M)edium,(V)erbose]: (now "); + if (Verbosity == VERBOSE) wprintw(Showline[slot],"Verbose)"); + else if (Verbosity == MEDIUM) wprintw(Showline[slot],"Medium)"); + else wprintw(Showline[slot],"Terse)"); + break; + case SEARCH_DURATION: + wprintw(Showline[slot],"-- Option SEARCHNUM [0>x>10]: (now %d)",Searchnum); + break; + } + wrefresh(Showline[slot]); +} + +void display_stat_slot(int slot) +{ + hide_line(slot); + wclear(Showline[slot]); + switch(slot) { + case 1: + wprintw(Showline[slot],"-- Strength ... [%d]: ", Player.str); + break; + case 2: + wprintw(Showline[slot],"-- Constitution [%d]: ", Player.con); + break; + case 3: + wprintw(Showline[slot],"-- Dexterity .. [%d]: ", Player.dex); + break; + case 4: + wprintw(Showline[slot],"-- Agility .... [%d]: ", Player.agi); + break; + case 5: + wprintw(Showline[slot],"-- Intelligence [%d]: ", Player.iq); + break; + case 6: + wprintw(Showline[slot],"-- Power ...... [%d]: ", Player.pow); + break; + case 7: + wprintw(Showline[slot],"-- HP ......... [%d]: ", Player.hp); + break; + case 8: + wprintw(Showline[slot],"-- Max HP ..... [%d]: ", Player.maxhp); + break; + case 9: + wprintw(Showline[slot],"-- Mana ....... [%d]: ", Player.mana); + break; + case 10: + wprintw(Showline[slot],"-- Max Mana ... [%d]: ", Player.maxmana); + break; + case 11: + wprintw(Showline[slot],"-- Cash ....... [%d]: ", Player.cash); + break; + } + wrefresh(Showline[slot]); +} + +void display_options(void) +{ + int i; + menuclear(); + hide_line(0); + for(i=1; i<=NUMOPTIONS; i++) + display_option_slot(i); +} + +void display_stats(void) +{ + int i; + menuclear(); + hide_line(0); + for(i=1; i<=NUMSTATS; i++) + display_stat_slot(i); +} + +/* nya ha ha ha ha haaaa.... */ +void deathprint(void) +{ + mgetc(); + waddch(Msgw,'D'); + wrefresh(Msgw); + mgetc(); + waddch(Msgw,'e'); + wrefresh(Msgw); + mgetc(); + waddch(Msgw,'a'); + wrefresh(Msgw); + mgetc(); + waddch(Msgw,'t'); + wrefresh(Msgw); + mgetc(); + waddch(Msgw,'h'); + wrefresh(Msgw); + mgetc(); +} + +void clear_if_necessary(void) +{ + int x,y; + getyx(Msg1w,y,x); + + if (x != 0) { + wclear(Msg1w); + wrefresh(Msg1w); + } + + getyx(Msg2w,y,x); + + if (x != 0) { + wclear(Msg2w); + wrefresh(Msg2w); + } + + getyx(Msg3w,y,x); + + if (x != 0) { + erasemsg3(); + wrefresh(Msg3w); + } +} + +int bufferpos = 0; + +void buffercycle(const char *s) +{ + strcpy(Stringbuffer[bufferpos++],s); + if (bufferpos >= STRING_BUFFER_SIZE) + bufferpos = 0; +} + +int bufferappend(char *s) +{ + int pos = bufferpos - 1; + + if (pos < 0) + pos = STRING_BUFFER_SIZE - 1; + if (strlen(Stringbuffer[pos]) + strlen(s) < 80 - 1) { + strcat(Stringbuffer[pos],s); + return 1; + } + else + return 0; +} + + +void bufferprint(void) +{ + int i = bufferpos - 1, c, finished = 0; + clearmsg(); +#if !defined(WIN32) + wprintw(Msg1w,"^p for previous message, ^n for next, anything else to quit."); +#else + wprintw(Msg1w,"^o for last message, ^n for next, anything else to quit."); +#endif + wrefresh(Msg1w); + do { + if (i >= STRING_BUFFER_SIZE) i = 0; + if (i < 0) i = STRING_BUFFER_SIZE - 1; + wclear(Msg2w); + wprintw(Msg2w,Stringbuffer[i]); + wrefresh(Msg2w); + c = mgetc(); +#if !defined(WIN32) + if (c == 16) /* ^p */ +#else + if (c == 15) /* ^o */ +#endif + i--; + else if (c == 14) /* ^n */ + i++; + else + finished = 1; + } while (!finished); + clearmsg(); + omshowcursor(Player.x,Player.y); +} + +void clear_screen(void) +{ + clear(); + touchwin(stdscr); + refresh(); +} diff --git a/Omega/src/stats.cpp b/Omega/src/stats.cpp index 95f5921..45796b6 100644 --- a/Omega/src/stats.cpp +++ b/Omega/src/stats.cpp @@ -1,114 +1,117 @@ -/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988, 1989 */ -/* stats.c */ - -/* this file contains one function, editstats(), that allows the player - * (if in cheat mode) to alter their stats, HP, mana, gold, etc. - * - * a later version may add options to set other things like guild - * membership, alignment, and so on - */ - -#include "glob.h" - -void editstats(void) -{ - int slot = 1, to, done = false; - int response, num; - - clearmsg(); - menuclear(); - - display_stats(); - - move_slot(1,1,NUMSTATS); - - do { - print1("Currently selected stat is preceded by highlit >>"); - print2("Move selected option with '>' and '<', ' ' to change value, ESCAPE to quit"); - - response = mcigetc(); - switch(response) { - case 'j': - case '>': -#ifdef KEY_DOWN - case KEY_DOWN: -#endif - to = slot + 1; - slot = move_slot(slot,to,NUMSTATS+1); - break; - case 'k': - case '<': -#ifdef KEY_UP - case KEY_UP: -#endif - to = slot - 1; - if (to > 0) - slot = move_slot(slot,to, NUMSTATS+1); - break; - case ESCAPE: - clearmsg(); - done = true; - break; - case ' ': - print1("enter new value:"); - num = (int) parsenum(""); - if ((slot < 7) && ((num > 32) || (num < 1))) - { - print1("You don't really think I'll let you get away with that, do you?"); - morewait(); - break; - } - switch(slot) - { - case 1: - Player.str = Player.maxstr = num; - break; - case 2: - Player.con = Player.maxcon = num; - break; - case 3: - Player.dex = Player.maxdex = num; - break; - case 4: - Player.agi = Player.maxagi = num; - break; - case 5: - Player.iq = Player.maxiq = num; - break; - case 6: - Player.pow = Player.maxpow = num; - break; - case 7: - Player.hp = num; - break; - case 8: - Player.maxhp = num; - break; - case 9: - Player.mana = num; - break; - case 10: - Player.maxmana = num; - break; - case 11: - Player.cash = num; - break; - } - calc_melee(); - break; - default: - print3("That response is meaningless for this option."); - break; - } - print1("Currently selected stat is preceded by highlit >>"); - display_stat_slot(slot/*,slot,NUMSTATS+1 WDT HACK! */); - move_slot(slot,slot,NUMSTATS+1); - } while (! done); - if (optionp(SHOW_COLOUR)) - colour_on(); - else - colour_off(); - - xredraw(); -} - +/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988, 1989 */ +/* stats.c */ + +/* this file contains one function, editstats(), that allows the player + * (if in cheat mode) to alter their stats, HP, mana, gold, etc. + * + * a later version may add options to set other things like guild + * membership, alignment, and so on + */ + +#include "glob.h" + +void editstats(void) +{ + int slot = 1, to, done = false; + int response, num; + + clearmsg(); + menuclear(); + + display_stats(); + + move_slot(1,1,NUMSTATS); + + do { + print1("Currently selected stat is preceded by highlit >>"); + print2("Move selected option with '>' and '<', ' ' to change value, ESCAPE to quit"); + + response = mcigetc(); + switch(response) { + case 'j': + case '>': +#ifdef KEY_DOWN + case KEY_DOWN: +#endif + case (char)KEY_ARROW_DOWN: + case (char)KEY_ARROW_RIGHT: + to = slot + 1; + slot = move_slot(slot,to,NUMSTATS+1); + break; + case 'k': + case '<': +#ifdef KEY_UP + case KEY_UP: +#endif + case (char)KEY_ARROW_UP: + case (char)KEY_ARROW_LEFT: + to = slot - 1; + if (to > 0) + slot = move_slot(slot,to, NUMSTATS+1); + break; + case ESCAPE: + clearmsg(); + done = true; + break; + case ' ': + print1("enter new value:"); + num = (int) parsenum(""); + if ((slot < 7) && ((num > 32) || (num < 1))) + { + print1("You don't really think I'll let you get away with that, do you?"); + morewait(); + break; + } + switch(slot) + { + case 1: + Player.str = Player.maxstr = num; + break; + case 2: + Player.con = Player.maxcon = num; + break; + case 3: + Player.dex = Player.maxdex = num; + break; + case 4: + Player.agi = Player.maxagi = num; + break; + case 5: + Player.iq = Player.maxiq = num; + break; + case 6: + Player.pow = Player.maxpow = num; + break; + case 7: + Player.hp = num; + break; + case 8: + Player.maxhp = num; + break; + case 9: + Player.mana = num; + break; + case 10: + Player.maxmana = num; + break; + case 11: + Player.cash = num; + break; + } + calc_melee(); + break; + default: + print3("That response is meaningless for this option."); + break; + } + print1("Currently selected stat is preceded by highlit >>"); + display_stat_slot(slot/*,slot,NUMSTATS+1 WDT HACK! */); + move_slot(slot,slot,NUMSTATS+1); + } while (! done); + if (optionp(SHOW_COLOUR)) + colour_on(); + else + colour_off(); + + xredraw(); +} diff --git a/Tools/src/bwt.c b/Tools/src/bwt.c index feb6dde..732fea0 100644 --- a/Tools/src/bwt.c +++ b/Tools/src/bwt.c @@ -1,208 +1,209 @@ - -/* - * bwt.c - * - * Code modified from Mark Nelson's article: - * "Data Compression With The Burrows-Wheeler Transform" - * Dr. Dobbs Journal, September 1996. - * See: http://www.dogma.net/markn/articles/bwt/bwt.htm to make sense - * of this source code. - */ - -/* - * It is because of limitations of the standard C qsort function that - * we have global data. - * we want to sort indices into the temporaryBuffer, but qsort doesn't provide - * any mechanism of forwarding arbitrary out of band data to the called - * function. - */ - -#include -#include -#include - -unsigned char *BWT_temporaryBuffer; -unsigned int BWT_length; - - -/* The following function compares two substrings of length "length" - * and returns a value less than 0 if the index1 string would be sorted - * first, 0 if they are the same, and a positive number if the index2 - * string should be sorted first. - * - * Standard memcmp has an issue that some implementations treat - * characters as signed, and others don't. Since this is a string - * compression algorithm, that should not make a difference to - * compressibility, but it will make the output different on two - * different platforms. - * We are only using this for ASCII data with OMEGA, so this is not - * an issue at present. - * - */ - -int BWT_Compare( const void *pointer1, const void *pointer2 ) -{ - unsigned int index1=*( unsigned int * )pointer1; - unsigned int index2=*( unsigned int * )pointer2; - - return memcmp(BWT_temporaryBuffer+index1, BWT_temporaryBuffer+index2, BWT_length); -}; - -/* The following function does the actual transform. It does this - * transform "in place" in the buffer, and returns an unsigned int - * in the range 0 <= X < length as out of band data for the transform. - * This value needs to be passed to the "detransform". - * - * Large "length" values passed in may take awhile do to the (O)N lg N - * time of sorting (On most platforms). - */ - -unsigned int BWT_Transform(unsigned char *buffer, unsigned int length) -{ - unsigned int i; - unsigned int first = 0; - unsigned int index; - - unsigned int *indices; - - BWT_length=length; - BWT_temporaryBuffer=malloc(2*length*sizeof(unsigned char)); - if(BWT_temporaryBuffer==NULL) - { - printf( "Failure allocating memory in BWT_transform.\n" ); - exit( EXIT_FAILURE ); - } - indices=malloc(length*sizeof(unsigned int)); - if(indices==NULL) - { - free( BWT_temporaryBuffer ); - printf( "Failure allocating memory in BWT_transform.\n" ); - exit( EXIT_FAILURE ); - } - - - memcpy(BWT_temporaryBuffer, buffer, length); - memcpy(BWT_temporaryBuffer+length, buffer, length); - - for( i=0; i < length; i++) - { - indices[ i ] = i; - } - qsort( indices, length, sizeof( unsigned int ), BWT_Compare ); - - for( i = 0; i < length; i++ ) - { - if( indices[ i ] == 0 ) - { - index = length-1; - } - else - { - index = indices[ i ]-1; - if( index == 0 ) - { - first=i; - } - } - - buffer[i] = BWT_temporaryBuffer[ index ]; - } - free( BWT_temporaryBuffer ); - free( indices ); - return first; -} - -void BWT_Detransform( unsigned char *buffer, unsigned int length, unsigned int first ) -{ - unsigned int i,index; - unsigned char *temporaryBuffer; - unsigned int *characterCountArray, *runningCountArray; - unsigned int *transpositionBuffer; - unsigned int sum=0; - unsigned int previous; - unsigned char character; - - - runningCountArray = malloc( 256*sizeof( unsigned int ) ); /* Too big to put on stack */ - if( runningCountArray == NULL ) - { - printf( "Failure allocating memory in BWT_Detransform.\n" ); - exit( EXIT_FAILURE ); - } - - characterCountArray = malloc( 256*sizeof( unsigned int ) ); /* Too big to put on stack */ - if( characterCountArray == NULL ) - { - free( runningCountArray ); - printf( "Failure allocating memory in BWT_Detransform.\n" ); /* Too big to put on stack */ - exit( EXIT_FAILURE ); - } - - temporaryBuffer=malloc( length*sizeof( unsigned char ) ); - if( temporaryBuffer == NULL ) - { - free( runningCountArray ); - free( characterCountArray ); - printf( "Failure allocating memory in BWT_transform.\n" ); /* Too big to put on stack */ - exit( EXIT_FAILURE ); - } - memcpy( temporaryBuffer, buffer, length ); - transpositionBuffer = malloc(length*sizeof(unsigned int)); - if( transpositionBuffer == NULL ) - { - free( runningCountArray ); - free( characterCountArray ); - free( temporaryBuffer ); - } - - /* Calculate the running totals for characters fo the alphabet. */ - - /* First initialize arrays */ - for( i = 0 ; i < 256 ; i++ ) - { - runningCountArray[ i ] = 0; - characterCountArray[ i ] = 0; - } - for( i = 0; i < length; i++ ) - { - runningCountArray[ buffer[ i ] ]++; - } - - - for( i = 0; i < 256; i++ ) - { - previous=runningCountArray[ i ]; - runningCountArray[ i ]=sum; - sum = sum + previous; - } - - /* Okay, now, for each character we have a map of how many characters are in - * the file that are smaller than it. - */ - - /* Given this information (which represents the "sorted" block) */ - /* And the information of how many times the character was */ - /* found previously in the "buffer" added together we come up */ - /* with a unique position on the transposition table */ - - for ( i = 0 ; i < length ; i++ ) - { - character = buffer[ i ]; - transpositionBuffer[ characterCountArray[ character ] + runningCountArray[ character ] ] = i; - characterCountArray[ character ]++; - } - - /* Transpose by following indices. */ - index = first; - for ( i = 0 ; i < length ; i++ ) - { - buffer[ i ]=temporaryBuffer[ index ]; - index = transpositionBuffer[ index ]; - } - free( runningCountArray ); - free( characterCountArray ); - free( temporaryBuffer ); - free( transpositionBuffer ); -} - - + +/* + * bwt.c + * + * Code modified from Mark Nelson's article: + * "Data Compression With The Burrows-Wheeler Transform" + * Dr. Dobbs Journal, September 1996. + * See: http://www.dogma.net/markn/articles/bwt/bwt.htm to make sense + * of this source code. + */ + +/* + * It is because of limitations of the standard C qsort function that + * we have global data. + * we want to sort indices into the temporaryBuffer, but qsort doesn't provide + * any mechanism of forwarding arbitrary out of band data to the called + * function. + */ + +#include +#include +#include + +unsigned char *BWT_temporaryBuffer; +unsigned int BWT_length; + + +/* The following function compares two substrings of length "length" + * and returns a value less than 0 if the index1 string would be sorted + * first, 0 if they are the same, and a positive number if the index2 + * string should be sorted first. + * + * Standard memcmp has an issue that some implementations treat + * characters as signed, and others don't. Since this is a string + * compression algorithm, that should not make a difference to + * compressibility, but it will make the output different on two + * different platforms. + * We are only using this for ASCII data with OMEGA, so this is not + * an issue at present. + * + */ + +int BWT_Compare( const void *pointer1, const void *pointer2 ) +{ + unsigned int index1=*( unsigned int * )pointer1; + unsigned int index2=*( unsigned int * )pointer2; + + return memcmp(BWT_temporaryBuffer+index1, BWT_temporaryBuffer+index2, BWT_length); +}; + +/* The following function does the actual transform. It does this + * transform "in place" in the buffer, and returns an unsigned int + * in the range 0 <= X < length as out of band data for the transform. + * This value needs to be passed to the "detransform". + * + * Large "length" values passed in may take awhile do to the (O)N lg N + * time of sorting (On most platforms). + */ + +unsigned int BWT_Transform(unsigned char *buffer, unsigned int length) +{ + unsigned int i; + unsigned int first = 0; + unsigned int index; + + unsigned int *indices; + + BWT_length=length; + BWT_temporaryBuffer = (unsigned char*)malloc(2*length*sizeof(unsigned char)); + if(BWT_temporaryBuffer==NULL) + { + printf( "Failure allocating memory in BWT_transform.\n" ); + exit( EXIT_FAILURE ); + } + indices = (unsigned int*)malloc(length*sizeof(unsigned int)); + if(indices==NULL) + { + free( BWT_temporaryBuffer ); + printf( "Failure allocating memory in BWT_transform.\n" ); + exit( EXIT_FAILURE ); + } + + + memcpy(BWT_temporaryBuffer, buffer, length); + memcpy(BWT_temporaryBuffer+length, buffer, length); + + for( i=0; i < length; i++) + { + indices[ i ] = i; + } + qsort( indices, length, sizeof( unsigned int ), BWT_Compare ); + + for( i = 0; i < length; i++ ) + { + if( indices[ i ] == 0 ) + { + index = length-1; + } + else + { + index = indices[ i ]-1; + if( index == 0 ) + { + first=i; + } + } + + buffer[i] = BWT_temporaryBuffer[ index ]; + } + free( BWT_temporaryBuffer ); + free( indices ); + return first; +} + +void BWT_Detransform( unsigned char *buffer, unsigned int length, unsigned int first ) +{ + unsigned int i,index; + unsigned char *temporaryBuffer; + unsigned int *characterCountArray, *runningCountArray; + unsigned int *transpositionBuffer; + unsigned int sum=0; + unsigned int previous; + unsigned char character; + + + runningCountArray = (unsigned int*)malloc( 256*sizeof( unsigned int ) ); /* Too big to put on stack */ + if( runningCountArray == NULL ) + { + printf( "Failure allocating memory in BWT_Detransform.\n" ); + exit( EXIT_FAILURE ); + } + + characterCountArray = (unsigned int*)malloc( 256*sizeof( unsigned int ) ); /* Too big to put on stack */ + if( characterCountArray == NULL ) + { + free( runningCountArray ); + printf( "Failure allocating memory in BWT_Detransform.\n" ); /* Too big to put on stack */ + exit( EXIT_FAILURE ); + } + + temporaryBuffer = (unsigned char*)malloc( length*sizeof( unsigned char ) ); + if( temporaryBuffer == NULL ) + { + free( runningCountArray ); + free( characterCountArray ); + printf( "Failure allocating memory in BWT_transform.\n" ); /* Too big to put on stack */ + exit( EXIT_FAILURE ); + } + memcpy( temporaryBuffer, buffer, length ); + transpositionBuffer = (unsigned int*)malloc(length*sizeof(unsigned int)); + if( transpositionBuffer == NULL ) + { + free( runningCountArray ); + free( characterCountArray ); + free( temporaryBuffer ); + } + + /* Calculate the running totals for characters fo the alphabet. */ + + /* First initialize arrays */ + for( i = 0 ; i < 256 ; i++ ) + { + runningCountArray[ i ] = 0; + characterCountArray[ i ] = 0; + } + for( i = 0; i < length; i++ ) + { + runningCountArray[ buffer[ i ] ]++; + } + + + for( i = 0; i < 256; i++ ) + { + previous=runningCountArray[ i ]; + runningCountArray[ i ]=sum; + sum = sum + previous; + } + + /* Okay, now, for each character we have a map of how many characters are in + * the file that are smaller than it. + */ + + /* Given this information (which represents the "sorted" block) */ + /* And the information of how many times the character was */ + /* found previously in the "buffer" added together we come up */ + /* with a unique position on the transposition table */ + + for ( i = 0 ; i < length ; i++ ) + { + character = buffer[ i ]; + // TODO transpositionBuffer could technically be null here + transpositionBuffer[ characterCountArray[ character ] + runningCountArray[ character ] ] = i; + characterCountArray[ character ]++; + } + + /* Transpose by following indices. */ + index = first; + for ( i = 0 ; i < length ; i++ ) + { + buffer[ i ]=temporaryBuffer[ index ]; + index = transpositionBuffer[ index ]; + } + free( runningCountArray ); + free( characterCountArray ); + free( temporaryBuffer ); + free( transpositionBuffer ); +} + + diff --git a/Tools/src/decrypt.c b/Tools/src/decrypt.c index 5423a46..e237a3f 100644 --- a/Tools/src/decrypt.c +++ b/Tools/src/decrypt.c @@ -1,184 +1,186 @@ -/* WDT: todo later: move this into the Omega source, probably changing both - * encode and decode into command line options to omega itself. Oh, and - * change the name from 'crypt' to 'pack'. */ - -#include -#include -#include -#include - -#define VERSION 2 -#define HEADER_SIZE 3 -#define ITEM_SIZE 9 - -/* These _must_ match the equivalent values in Omega, and if they - * change, I need to define a new version. */ -#define MAXWIDTH 128 -#define MAXLENGTH 64 - -void error(char *explanation, ...) -{ - va_list ap; - - va_start (ap, explanation); - vfprintf (stderr, explanation, ap); - va_end (ap); - exit(-1); -} - -int fgetint(FILE *f) -{ - int x; - assert(sizeof(int) == 4); /* This assumption is explicit here, but it's - * also elsewhere. */ - x = fgetc(f) &0x000000FF; - x|= (fgetc(f) << 8) &0x0000FF00; - x|= (fgetc(f) <<16) &0x00FF0000; - x|= (fgetc(f) <<24) &0xFF000000; - - if ( feof(f) ) - error("Unexpected end of file while parsing binary file."); - - return x; -} - -int fgetshort(FILE *f) -{ - int x; - assert(sizeof(int) == 4); /* This assumption is explicit here, but it's - * also elsewhere. */ - x = fgetc(f) &0x000000FF; - x|= (fgetc(f) << 8) &0x0000FF00; - - if ( feof(f) ) - error("Unexpected end of file while parsing binary file."); - - return x; -} - -int rle_decode(char *in, char *out, int inLength, int outLength) -{ - int pos = 0; - int run = 0; - int offset = 0; - - while (pos < inLength && offset < outLength) - { - run = 1; - if ( in[pos] == 0x55 ) - pos++; - else if ( in[pos] & 0x80 ) - run = in[pos++] & ~0x80; - - if ( offset + run > outLength ) - { - fprintf(stderr,"Error: dest overrun during decompression, expected" - " %d, got %d.\n", outLength, offset+run); - return 0; - } - while ( run-- > 0 ) - out[offset++] = in[pos]; - pos++; - } - - return offset; -} - -void decode(char **data, int *length, int expectedLength) -{ - char *result = malloc(expectedLength); - *length = rle_decode(*data,result,*length,expectedLength); - if ( !*length ) - error("Unable to decrypt input map data.\n"); - free(*data); - *data = result; -} - -int unpack(int num_args, char *args[]) -{ - char *code; - FILE *out, *in; - int map, version, maps, x, y, this_map, offset, size, items, depth; - - if ( num_args != 4 ) - error("Usage: %s \n", - args[0]); - - out = fopen(args[3],"w"); - if ( out == NULL ) - error("Unable to open output file '%s'.\n", args[3]); - - map = atoi(args[2]); - - in = fopen(args[1],"rb"); - if (!in) - error("Unable to open map file '%s'.\n", args[1]); - - version = fgetc(in); /* The file version */ - if ( version != VERSION ) - error("Mapfile version mismatch: expected %d, got %d.\n", - VERSION, version); - - maps = fgetshort(in); /* The number of files it's supposed to contain */ - if ( maps < 1 ) - error("Mapfile has bad format: claims to contain %d maps.", maps); - - fprintf(out,"v%d\n",VERSION); - fprintf(out,"map %d\n",map); - - items = 0; - do { - this_map = fgetshort(in); - x = fgetc(in); - y = fgetc(in); - depth = fgetc(in); - offset = fgetint(in); - items++; - printf("%d: map %d, %dx%d, offset %d.\n", items, this_map, x, y, offset); - } while (this_map != map && items < maps); - - if ( items == maps ) - error("Map #%d was not found in mapfile.\n", map ); - - fprintf(out,"%d %d,%d\n", depth, x, y); - - /* Then seek to the location of the data -- to its offset, plus the constant - * space taken by the header, plus the space taken by all of the map - * table of content entries. */ - fseek(in,offset+HEADER_SIZE+maps*ITEM_SIZE,SEEK_SET); - - while ( depth-- ) - { - /* Read the size of this level. */ - size = fgetshort(in); - code = malloc(size); - fread(code,size,1,in); - - /* Decode the whole level. */ - /* decode(&code,&size, x*y);*/ - - if ( size != x*y ) - error("Invalid size: expected %d, got %d.\n", x*y, size); - - /* Write every line of the level to the output file. */ - y = 0; - while(size) - { - fwrite(code+y*x, x, 1, out); - fputc('\n', out); - y++; - size -= x; - } - /* If there's another level in the map, print a seperator. */ - if ( depth ) - fprintf(out, "========*** Level Seperator ***=======\n"); - else fprintf(out, "===END OF MAP===\n"); - free(code); - } - - fclose(in); - fclose(out); - - exit(EXIT_SUCCESS); -} - +/* WDT: todo later: move this into the Omega source, probably changing both + * encode and decode into command line options to omega itself. Oh, and + * change the name from 'crypt' to 'pack'. */ + +#include +#include +#include +#include + +#define VERSION 2 +#define HEADER_SIZE 3 +#define ITEM_SIZE 9 + +/* These _must_ match the equivalent values in Omega, and if they + * change, I need to define a new version. */ +#define MAXWIDTH 128 +#define MAXLENGTH 64 + +void error(char *explanation, ...) +{ + va_list ap; + + va_start (ap, explanation); + vfprintf (stderr, explanation, ap); + va_end (ap); + exit(-1); +} + +int fgetint(FILE *f) +{ + int x; + assert(sizeof(int) == 4); /* This assumption is explicit here, but it's + * also elsewhere. */ + x = fgetc(f) &0x000000FF; + x|= (fgetc(f) << 8) &0x0000FF00; + x|= (fgetc(f) <<16) &0x00FF0000; + x|= (fgetc(f) <<24) &0xFF000000; + + if ( feof(f) ) + error("Unexpected end of file while parsing binary file."); + + return x; +} + +int fgetshort(FILE *f) +{ + int x; + assert(sizeof(int) == 4); /* This assumption is explicit here, but it's + * also elsewhere. */ + x = fgetc(f) &0x000000FF; + x|= (fgetc(f) << 8) &0x0000FF00; + + if ( feof(f) ) + error("Unexpected end of file while parsing binary file."); + + return x; +} + +int rle_decode(char *in, char *out, int inLength, int outLength) +{ + int pos = 0; + int run = 0; + int offset = 0; + + while (pos < inLength && offset < outLength) + { + run = 1; + if ( in[pos] == 0x55 ) + pos++; + else if ( in[pos] & 0x80 ) + run = in[pos++] & ~0x80; + + if ( offset + run > outLength ) + { + fprintf(stderr,"Error: dest overrun during decompression, expected" + " %d, got %d.\n", outLength, offset+run); + return 0; + } + while ( run-- > 0 ) + out[offset++] = in[pos]; + pos++; + } + + return offset; +} + +void decode(char **data, int *length, int expectedLength) +{ + char *result = malloc(expectedLength); + *length = rle_decode(*data,result,*length,expectedLength); + if ( !*length ) + error("Unable to decrypt input map data.\n"); + free(*data); + *data = result; +} + +int unpack(int num_args, char *args[]) +{ + char *code; + FILE *out, *in; + int map, version, maps, x, y, this_map, offset, size, items, depth; + + if ( num_args != 4 ) + error("Usage: %s \n", + args[0]); + + out = fopen(args[3],"w"); + if ( out == NULL ) + error("Unable to open output file '%s'.\n", args[3]); + + map = atoi(args[2]); + + in = fopen(args[1],"rb"); + if (!in) + error("Unable to open map file '%s'.\n", args[1]); + + version = fgetc(in); /* The file version */ + if ( version != VERSION ) + error("Mapfile version mismatch: expected %d, got %d.\n", + VERSION, version); + + maps = fgetshort(in); /* The number of files it's supposed to contain */ + if ( maps < 1 ) + error("Mapfile has bad format: claims to contain %d maps.", maps); + + fprintf(out,"v%d\n",VERSION); + fprintf(out,"map %d\n",map); + + items = 0; + do { + this_map = fgetshort(in); + x = fgetc(in); + y = fgetc(in); + depth = fgetc(in); + offset = fgetint(in); + items++; + printf("%d: map %d, %dx%d, offset %d.\n", items, this_map, x, y, offset); + } while (this_map != map && items < maps); + + if ( items == maps ) + error("Map #%d was not found in mapfile.\n", map ); + + fprintf(out,"%d %d,%d\n", depth, x, y); + + /* Then seek to the location of the data -- to its offset, plus the constant + * space taken by the header, plus the space taken by all of the map + * table of content entries. */ + fseek(in,offset+HEADER_SIZE+maps*ITEM_SIZE,SEEK_SET); + + while ( depth-- ) + { + /* Read the size of this level. */ + size = fgetshort(in); + code = (char *)malloc(size); + if (code == NULL) + error("Could not allocate memory for map reading."); + fread(code,size,1,in); + + /* Decode the whole level. */ + /* decode(&code,&size, x*y);*/ + + if ( size != x*y ) + error("Invalid size: expected %d, got %d.\n", x*y, size); + + /* Write every line of the level to the output file. */ + y = 0; + while(size) + { + fwrite(code+y*x, x, 1, out); + fputc('\n', out); + y++; + size -= x; + } + /* If there's another level in the map, print a seperator. */ + if ( depth ) + fprintf(out, "========*** Level Seperator ***=======\n"); + else fprintf(out, "===END OF MAP===\n"); + free(code); + } + + fclose(in); + fclose(out); + + exit(EXIT_SUCCESS); +} + From e0d275c134043ac6a1381033abb251123f886fa0 Mon Sep 17 00:00:00 2001 From: Patrick McCuller Date: Sun, 4 May 2014 18:17:26 -0700 Subject: [PATCH 09/12] Added arrow keys to setspot targeting. Fixed save game load error that caused HP, pow reset. --- Omega/src/aux1.cpp | 1752 ++++++++++++++++++++++---------------------- Omega/src/char.cpp | 1 + 2 files changed, 884 insertions(+), 869 deletions(-) diff --git a/Omega/src/aux1.cpp b/Omega/src/aux1.cpp index 195aff3..0338783 100644 --- a/Omega/src/aux1.cpp +++ b/Omega/src/aux1.cpp @@ -1,869 +1,883 @@ -/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ -/* aux1.c */ -/* auxiliary functions for those in com.c, also see aux2.c and aux3.c */ - -#include "glob.h" - -/* check to see if too much tunneling has been done in this level */ -void tunnelcheck(void) -{ - if ((Level->depth == 0 && Current_Environment != E_DLAIR) || - Current_Environment == E_ASTRAL) - return; - Level->tunnelled++; - if ((Level->tunnelled) > (Level->level_length)/4) - mprint("Dust and stone fragments fall on you from overhead."); - if ((Level->tunnelled) >(Level->level_length)/2) - mprint("You hear groaning and creaking noises."); - if ((Level->tunnelled) > (3*(Level->level_length))/4) - mprint("The floor trembles and you hear a loud grinding screech."); - if ((Level->tunnelled) > Level->level_length) { - mprint("With a scream of tortured stone, the entire dungeon caves in!!!"); - gain_experience(5000); - if (Player.status[SHADOWFORM]) { - change_environment(E_COUNTRYSIDE); - switch (Country[Player.x][Player.y].base_terrain_type) - { - case CASTLE: - case STARPEAK: - case CAVES: - case VOLCANO: - Country[Player.x][Player.y].current_terrain_type = MOUNTAINS; - break; - case DRAGONLAIR: - Country[Player.x][Player.y].current_terrain_type = DESERT; - break; - case MAGIC_ISLE: - Country[Player.x][Player.y].current_terrain_type = CHAOS_SEA; - break; - case PALACE: - Country[Player.x][Player.y].current_terrain_type = JUNGLE; - break; - } - Country[Player.x][Player.y].base_terrain_type = - Country[Player.x][Player.y].current_terrain_type; - c_set(Player.x, Player.y, CHANGED); - print1("In your shadowy state, you float back up to the surface."); - return; - } - mprint("You are flattened into an unpleasant jellylike substance."); - p_death("dungeon cave-in"); - } -} - -/* displays a room's name */ -void showroom(int i) -{ - strcpy(Str1,""); - strcpy(Str2,""); - switch(Current_Environment) { - case E_MANSION: - strcpy(Str2,"A luxurious mansion: "); - break; - case E_HOUSE: - strcpy(Str2,"A house: "); - break; - case E_HOVEL: - strcpy(Str2,"A hovel: "); - break; - case E_CITY: - strcpy(Str2,"The City of Rampart"); - break; - case E_VILLAGE: - switch(Villagenum) { - case 1: - strcpy(Str2,"The Village of Star View"); - break; - case 2: - strcpy(Str2,"The Village of Woodmere"); - break; - case 3: - strcpy(Str2,"The Village of Stormwatch"); - break; - case 4: - strcpy(Str2,"The Village of Thaumaris"); - break; - case 5: - strcpy(Str2,"The Village of Skorch"); - break; - case 6: - strcpy(Str2,"The Village of Whorfen"); - break; - } - break; - case E_CAVES: - strcpy(Str2,"The Goblin Caves: "); - break; - case E_CASTLE: - strcpy(Str2,"The Archmage's Castle: "); - break; - case E_ASTRAL: - strcpy(Str2,"The Astral Plane: "); - break; - case E_VOLCANO: - strcpy(Str2,"The Volcano: "); - break; - case E_PALACE: - strcpy(Str2,"The Palace Dungeons: "); - break; - case E_SEWERS: - strcpy(Str2,"The Sewers: "); - break; - case E_TACTICAL_MAP: - strcpy(Str2,"The Tactical Map "); - break; - default: - strcpy(Str2,""); - break; - } - if (Current_Environment == Current_Dungeon) { - strcpy(Str1,"Level "); - if (Level->depth < 10) { - Str1[6] = Level->depth + '0'; - Str1[7] = 0; - } - else { - Str1[6] = (Level->depth / 10) + '0'; - Str1[7] = (Level->depth % 10) + '0'; - Str1[8] = 0; - } - strcat(Str1," ("); - strcat(Str1,roomname(i)); - strcat(Str1,")"); - } - else if (strlen(Str2) == 0 || Current_Environment == E_MANSION || - Current_Environment == E_HOUSE || Current_Environment == E_HOVEL) - strcpy(Str1,roomname(i)); - strcat(Str2,Str1); - locprint(Str2); -} - - -int player_on_sanctuary(void) -{ - if ((Player.x==Player.sx) && - (Player.y==Player.sy)) - return(true); - else { - if (Player.patron) { - if ((Level->site[Player.x][Player.y].locchar == ALTAR) && - (Level->site[Player.x][Player.y].aux == Player.patron)) - return(true); - else return(false); - } - else return(false); - } -} - - -/* check a move attempt, maybe attack something, return true if ok to move. */ -/* x y is the proposed place to move to */ -int p_moveable(int x, int y) -{ - State.setSkipMonsters(); - if (! inbounds(x,y)) return (false); - else if (Player.status[SHADOWFORM]) { - switch(Level->site[x][y].p_locf) { - case L_CHAOS: - case L_ABYSS: - case L_VOID: - return cinema_confirm("That looks dangerous.") == 'y'; - default: - State.setSkipMonsters(false); - return(true); - } - } - else if (loc_statusp(x,y,SECRET)) { - if (State.getFastMove() == false) print3("Ouch!"); - return(false); - } - else if (Level->site[x][y].creature != NULL) { - if (State.getFastMove() == false) { - Level->site[x][y].creature->fight_monster(); - State.setSkipMonsters(false); - return(false); - } - else return(false); - } - else if ((Level->site[x][y].locchar == WALL) || - (Level->site[x][y].locchar == STATUE) || - (Level->site[x][y].locchar == PORTCULLIS) || - (Level->site[x][y].locchar == CLOSED_DOOR) || - (State.getFastMove() && - ((Level->site[x][y].locchar == HEDGE) || - (Level->site[x][y].locchar == LAVA) || - (Level->site[x][y].locchar == ABYSS) || - (Level->site[x][y].locchar == VOID_CHAR) || - (Level->site[x][y].locchar == FIRE) || - (Level->site[x][y].locchar == WHIRLWIND) || - (Level->site[x][y].locchar == WATER) || - (Level->site[x][y].locchar == LIFT) || - (Level->site[x][y].locchar == TRAP)))) { - if (State.getFastMove() == false) print3("Ouch!"); - return(false); - } - else if (optionp(CONFIRM)) { - if ((Level->site[x][y].locchar == HEDGE) || - (Level->site[x][y].locchar == LAVA) || - (Level->site[x][y].locchar == FIRE) || - (Level->site[x][y].locchar == WHIRLWIND) || - (Level->site[x][y].locchar == ABYSS) || - (Level->site[x][y].locchar == VOID_CHAR) || - (Level->site[x][y].locchar == WATER) || - (Level->site[x][y].locchar == RUBBLE) || - (Level->site[x][y].locchar == LIFT) || - (Level->site[x][y].locchar == TRAP)) { - /* horses WILL go into water... */ - if (State.getMounted()) { - if (Level->site[x][y].locchar != WATER || - Level->site[x][y].p_locf != L_WATER) { - print1("You can't convince your steed to continue."); - State.setSkipMonsters(); - return(false); - } - else return(true); - } - else if (cinema_confirm("Look where you're about to step!") == 'y') State.setSkipMonsters(false); - else State.setSkipMonsters(); - return(State.getSkipMonsters() == false); - } - else { - State.setSkipMonsters(false); - return(true); - } - } - else { - State.setSkipMonsters(false); - return(true); - } -} - - - -/* check a move attempt in the countryside */ -int p_country_moveable(int x, int y) -{ - if (! inbounds(x,y)) return (false); - else if (optionp(CONFIRM)) { - if ((Country[x][y].current_terrain_type == CHAOS_SEA) || - (Country[x][y].current_terrain_type == MOUNTAINS)) - return(cinema_confirm("That's dangerous terrain, and slow going.")=='y'); - else return(true); - } - else return(true); -} - - - - - -/* search once particular spot */ -void searchat(int x, int y) -{ - int i; - if (inbounds(x,y) && (random_range(3) || Player.status[ALERT])) { - if (loc_statusp(x,y,SECRET)) { - lreset(x,y,SECRET); - lset(x, y, CHANGED); - if ((Level->site[x][y].locchar==OPEN_DOOR) || - (Level->site[x][y].locchar==CLOSED_DOOR)) { - mprint("You find a secret door!"); - for(i=0; i<=8; i++) { /* FIXED! 12/25/98 */ - lset(x+Dirs[0][i],y+Dirs[1][i],STOPS); - lset(x+Dirs[0][i], y+Dirs[1][i], CHANGED); - } - } - else mprint("You find a secret passage!"); - drawvision(Player.x,Player.y); - } - if ((Level->site[x][y].p_locf >= TRAP_BASE) && - (Level->site[x][y].locchar != TRAP) && - (Level->site[x][y].p_locf <= TRAP_BASE+NUMTRAPS)) { - Level->site[x][y].locchar = TRAP; - lset(x, y, CHANGED); - mprint("You find a trap!"); - drawvision(Player.x,Player.y); - State.setFastMove(false); - } - } -} - - - -/* This is to be called whenever anything might change player performance in -melee, such as changing weapon, statistics, etc. */ -void calc_melee(void) -{ - calc_weight(); - - Player.maxweight = (Player.str * Player.agi * 10); - Player.absorption = Player.status[PROTECTION]; - Player.defense = 2 * statmod(Player.agi)+(Player.level/2); - Player.hit = Player.level + statmod(Player.dex)+1; - Player.dmg = statmod(Player.str)+3; - Player.speed = 5 - min(4,(statmod(Player.agi)/2)); - if (Player.status[HASTED] > 0) Player.speed = Player.speed / 2; - if (Player.status[SLOWED] > 0) Player.speed = Player.speed * 2; - if (Player.itemweight > 0) - switch(Player.maxweight / Player.itemweight) { - case 0: - Player.speed+=6; - break; - case 1: - Player.speed+=3; - break; - case 2: - Player.speed+=2; - break; - case 3: - Player.speed+=1; - break; - } - - if (Player.status[ACCURATE]) Player.hit+=20; - if (Player.status[HERO]) Player.hit+=Player.dex; - if (Player.status[HERO]) Player.dmg+=Player.str; - if (Player.status[HERO]) Player.defense+=Player.agi; - if (Player.status[HERO]) Player.speed=Player.speed / 2; - - Player.speed = max(1,min(25,Player.speed)); - - if (State.getMounted()) { - Player.speed = 3; - Player.hit += 10; - Player.dmg += 10; - } - else if (Player.rank[MONKS] > 0) - { - /* monks are faster when not in armor or on horseback */ - if (Player.possessions[O_ARMOR] == NULL) { - Player.speed += (min(0,(Player.rank[MONKS] -1))); - } - } - - /* weapon */ - /* have to check for used since it could be a 2h weapon just carried - in one hand */ - if (Player.possessions[O_WEAPON_HAND] != NULL) - if (Player.possessions[O_WEAPON_HAND]->used && - ((Player.possessions[O_WEAPON_HAND]->objchar==WEAPON)|| - (Player.possessions[O_WEAPON_HAND]->objchar==MISSILEWEAPON))) { - Player.hit += - Player.possessions[O_WEAPON_HAND]->hit + - Player.possessions[O_WEAPON_HAND]->plus; - Player.dmg += - Player.possessions[O_WEAPON_HAND]->dmg + - Player.possessions[O_WEAPON_HAND]->plus; - } - - if (Player.rank[MONKS] > 0) - { - /* monks */ - /* aren't monks just obscene? PGM */ - if (Player.possessions[O_WEAPON_HAND] == NULL) /*barehanded*/ - { - /* all monks get a bonus in unarmed combat */ - Player.hit += ( Player.rank[MONKS] * Player.level ); - Player.dmg += ( Player.rank[MONKS] * Player.level ); - Player.defense += ( Player.rank[MONKS] * Player.level ); - - if (Player.rank[MONKS] == MONK_GRANDMASTER) - { - /* Grandmaster does 3x damage in unarmed combat. */ - Player.dmg *= 3; - } - } - } - - /* shield or defensive weapon */ - if (Player.possessions[O_SHIELD] != NULL) { - Player.defense += - Player.possessions[O_SHIELD]->aux + - Player.possessions[O_SHIELD]->plus; - } - - /* armor */ - if (Player.possessions[O_ARMOR] != NULL) { - Player.absorption += Player.possessions[O_ARMOR]->dmg; - Player.defense += - Player.possessions[O_ARMOR]->plus - - Player.possessions[O_ARMOR]->aux; - } - - if (strlen(Player.combatManeuvers) > 2*maneuvers()) - default_maneuvers(); - comwinprint(); - showflags(); - dataprint(); -} - -/* Attempt to break an object o */ -int damage_item(Object* o) -{ - /* special case -- break star gem */ - if (o->id == OB_STARGEM) { - print1("The Star Gem shatters into a million glistening shards...."); - if (Current_Environment == E_STARPEAK) { - if (!State.getKilledLawbringer()) - print2("You hear an agonizing scream of anguish and despair."); - morewait(); - print1("A raging torrent of energy escapes in an explosion of magic!"); - print2("The energy flows to the apex of Star Peak where there is"); - morewait(); - clearmsg(); - print1("an enormous explosion!"); - morewait(); - annihilate(1); - print3("You seem to gain strength in the chaotic glare of magic!"); - Player.str = max(Player.str, Player.maxstr + 5); /* FIXED! 12/25/98 */ - Player.pow = max(Player.pow, Player.maxpow + 5); /* ditto */ - Player.alignment -= 200; - dispose_lost_objects(1,o); - } - else { - morewait(); - print1("The shards coalesce back together again, and vanish"); - print2("with a muted giggle."); - dispose_lost_objects(1,o); - Objects[o->id].uniqueness = UNIQUE_UNMADE; /* FIXED! 12/30/98 */ - } - return 1; - } - else { - if (o->fragility < random_range(30)) { - if (o->objchar == STICK && o->charge > 0) { - strcpy(Str1,"Your "); - strcat(Str1,(o->blessing >= 0 ? o->truename : o->cursestr)); - strcat(Str1," explodes!"); - print1(Str1); - morewait(); - nprint1(" Ka-Blamm!!!"); - /* general case. Some sticks will eventually do special things */ - morewait(); - manastorm(Player.x, Player.y, o->charge*o->level*10); - dispose_lost_objects(1,o); - return 1; - } - else if ((o->blessing > 0) && (o->level > random_range(10))) { - strcpy(Str1,"Your "); - strcat(Str1,itemid(o)); - strcat(Str1," glows strongly."); - print1(Str1); - return 0; - } - else if ((o->blessing < -1) && (o->level > random_range(10))) { - strcpy(Str1,"You hear an evil giggle from your "); - strcat(Str1,itemid(o)); - print1(Str1); - return 0; - } - else if (o->plus > 0) { - strcpy(Str1,"Your "); - strcat(Str1,itemid(o)); - strcat(Str1," glows and then fades."); - print1(Str1); - o->plus--; - return 0; - } - else { - if (o->blessing > 0) print1("You hear a faint despairing cry!"); - else if (o->blessing < 0) print1("You hear an agonized scream!"); - strcpy(Str1,"Your "); - strcat(Str1,itemid(o)); - strcat(Str1," shatters in a thousand lost fragments!"); - print2(Str1); - morewait(); - dispose_lost_objects(1,o); - return 1; - } - } - return 0; - } -} - -/* do dmg points of damage of type dtype, from source fromstring */ -void p_damage(int dmg, int dtype, char *fromstring) -{ - if (State.getFastMove()) { - drawvision(Player.x,Player.y); - State.setFastMove(false); - } - if (! p_immune(dtype)) { - if (dtype == NORMAL_DAMAGE) Player.hp -= max(1,(dmg-Player.absorption)); - else Player.hp -= dmg; - if (Player.hp < 1) p_death(fromstring); - } - else mprint("You resist the effects!"); - dataprint(); -} - -/* game over, you lose! */ -void p_death(char *fromstring) -{ - Player.hp = -1; - print3("You died!"); - morewait(); - display_death(fromstring); - player_dump(); - endgraf(); - exit(0); -} - -/* move the cursor around, like for firing a wand, sets x and y to target */ -void setspot(int *x, int *y) -{ - char c = ' '; - mprint("Targeting.... ? for help"); - omshowcursor(*x,*y); - while ((c != '.') && (c != ESCAPE)) { - c = lgetc(); - switch(c) { - case 'h': - case '4': - movecursor(x,y,-1,0); - break; - case 'j': - case '2': - movecursor(x,y,0,1); - break; - case 'k': - case '8': - movecursor(x,y,0,-1); - break; - case 'l': - case '6': - movecursor(x,y,1,0); - break; - case 'b': - case '1': - movecursor(x,y,-1,1); - break; - case 'n': - case '3': - movecursor(x,y,1,1); - break; - case 'y': - case '7': - movecursor(x,y,-1,-1); - break; - case 'u': - case '9': - movecursor(x,y,1,-1); - break; - case '?': - clearmsg(); - mprint("Use vi keys or numeric keypad to move cursor to target."); - mprint("Hit the '.' key when done, or ESCAPE to abort."); - break; - } - } - if (c==ESCAPE) { - *x = *y = ABORT; - clearmsg(); - } - screencheck(Player.x,Player.y); -} - - -/* get a direction: return index into Dirs array corresponding to direction */ -int getdir(void) -{ - while (1) { - mprint("Select direction [hjklyubn, ESCAPE to quit]: "); - switch (mgetc()) { - case '4': - case 'h': - case 'H': - return(5); - case '2': - case 'j': - case 'J': - return(6); - case '8': - case 'k': - case 'K': - return(7); - case '6': - case 'l': - case 'L': - return(4); - case '7': - case 'y': - case 'Y': - return(3); - case '9': - case 'u': - case 'U': - return(1); - case '1': - case 'b': - case 'B': - return(2); - case '3': - case 'n': - case 'N': - return(0); - case ESCAPE: - clearmsg(); - return(ABORT); - default: - print3("That's not a direction! "); - } - } -} - -/* for the examine function */ -void describe_player(void) -{ - if (Player.hp < (Player.maxhp /5)) - print1("A grievously injured "); - else if (Player.hp < (Player.maxhp /2)) - print1("A seriously wounded "); - else if (Player.hp < Player.maxhp) - print1("A somewhat bruised "); - else print1("A fit "); - - if (Player.status[SHADOWFORM]) - nprint1("shadow"); - else - nprint1(levelname(Player.level)); - nprint1(" named "); - nprint1(Player.name); - if (State.getMounted()) - nprint1(" (riding a horse.)"); -} - - -/* access to player experience... */ -/* share out experience among guild memberships */ -void gain_experience(int amount) -{ - int i,count=0,share; - Player.xp += (long) amount; - gain_level(); /* actually, check to see if should gain level */ - for(i=0; i 0) count++; - share = amount/(max(count,1)); - for(i=0; i 0) Player.guildxp[i]+=share; -} - -/* try to hit a monster in an adjacent space. If there are none -return false. Note if you're berserk you get to attack ALL -adjacent monsters! */ -int goberserk(void) -{ - int wentberserk=false,i; - char combatManeuvers[80]; - strcpy(combatManeuvers,Player.combatManeuvers); - strcpy(Player.combatManeuvers,"lLlClH"); - for(i=0; i<8; i++) - if (Level->site[Player.x+Dirs[0][i]][Player.y+Dirs[1][i]].creature - != NULL) { - wentberserk=true; - Level->site[Player.x+Dirs[0][i]][Player.y+Dirs[1][i]].creature->fight_monster(); - morewait(); - } - strcpy(Player.combatManeuvers,combatManeuvers); - return(wentberserk); -} - -/* identifies a trap for examine() by its aux value */ -char *trapid(int trapno) -{ - switch (trapno) { - case L_TRAP_SIREN: - return("A siren trap"); - case L_TRAP_DART: - return("A dart trap"); - case L_TRAP_PIT: - return("A pit"); - case L_TRAP_SNARE: - return("A snare"); - case L_TRAP_BLADE: - return("A blade trap"); - case L_TRAP_FIRE: - return("A fire trap"); - case L_TRAP_TELEPORT: - return("A teleport trap"); - case L_TRAP_DISINTEGRATE: - return("A disintegration trap"); - case L_TRAP_DOOR: - return("A trap door"); - case L_TRAP_MANADRAIN: - return("A manadrain trap"); - case L_TRAP_ACID: - return("An acid shower trap"); - case L_TRAP_SLEEP_GAS: - return("A sleep gas trap"); - case L_TRAP_ABYSS: - return("A concealed entrance to the abyss"); - default: - return("A completely inoperative trap."); - } -} - - -/* checks current food status of player, every hour, and when food is eaten */ -void foodcheck(void) -{ - if (Player.food > 48) { - print3("You vomit up your huge meal."); - Player.food = 12; - } - else if (Player.food == 30) - print3("Time for a smackerel of something."); - else if (Player.food == 20) - print3("You feel hungry."); - else if (Player.food == 12) - print3("You are ravenously hungry."); - else if (Player.food == 3) { - print3("You feel weak."); - if (State.getFastMove()) { - drawvision(Player.x,Player.y); - State.setFastMove(false); - } - } - else if (Player.food < 0) { - if (State.getFastMove()) { - drawvision(Player.x,Player.y); - State.setFastMove(false); - } - print3("You're starving!"); - p_damage(-5*Player.food,UNSTOPPABLE,"starvation"); - } - showflags(); -} - - - - -/* see whether room should be illuminated */ -void roomcheck(void) -{ - static int oldroomno = -1; -#if defined(WIN32) - static int oldlevel = -1; -#else - static plv oldlevel = NULL; -#endif - int roomno = Level->site[Player.x][Player.y].roomnumber; - - if ((roomno == RS_CAVERN) || - (roomno == RS_SEWER_DUCT) || - (roomno == RS_KITCHEN) || - (roomno == RS_BATHROOM) || - (roomno == RS_BEDROOM) || - (roomno == RS_DININGROOM) || - (roomno == RS_CLOSET) || - (roomno > ROOMBASE)) - if ((! loc_statusp(Player.x,Player.y,LIT)) && - (! Player.status[BLINDED]) && - (Player.status[ILLUMINATION] || (difficulty() < 6))) { - showroom(Level->site[Player.x][Player.y].roomnumber); - spreadroomlight(Player.x,Player.y,roomno); - levelrefresh(); - } - if ((oldroomno != roomno) || -#if defined(WIN32) - (oldlevel != Level->depth)) { -#else - (oldlevel != Level)) { -#endif - showroom(roomno); - oldroomno = roomno; -#if defined(WIN32) - oldlevel = Level->depth; -#else - oldlevel = Level; -#endif - } -} - - - -/* name of the player's experience level */ -char *levelname(int level) -{ - switch(level) { - case 0: - strcpy(Str3,"neophyte"); - break; - case 1: - strcpy(Str3,"beginner"); - break; - case 2: - strcpy(Str3,"tourist"); - break; - case 3: - strcpy(Str3,"traveller"); - break; - case 4: - strcpy(Str3,"wayfarer"); - break; - case 5: - strcpy(Str3,"peregrinator"); - break; - case 6: - strcpy(Str3,"wanderer"); - break; - case 7: - strcpy(Str3,"hunter"); - break; - case 8: - strcpy(Str3,"scout"); - break; - case 9: - strcpy(Str3,"trailblazer"); - break; - case 10: - strcpy(Str3,"discoverer"); - break; - case 11: - strcpy(Str3,"explorer"); - break; - case 12: - strcpy(Str3,"senior explorer"); - break; - case 13: - strcpy(Str3,"ranger"); - break; - case 14: - strcpy(Str3,"ranger captain"); - break; - case 15: - strcpy(Str3,"ranger knight"); - break; - case 16: - strcpy(Str3,"adventurer"); - break; - case 17: - strcpy(Str3,"experienced adventurer"); - break; - case 18: - strcpy(Str3,"skilled adventurer"); - break; - case 19: - strcpy(Str3,"master adventurer"); - break; - case 20: - strcpy(Str3,"hero"); - break; - case 21: - strcpy(Str3,"superhero"); - break; - case 22: - strcpy(Str3,"demigod"); - break; - default: - if (level < 100) { - strcpy(Str3,"Order "); - Str3[6] = ((level/10)-2) + '0'; - Str3[7] = 0; - strcat(Str3," Master of Omega"); - } - else strcpy(Str3,"Ultimate Master of Omega"); - break; - } - return(Str3); -} +/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ +/* aux1.c */ +/* auxiliary functions for those in com.c, also see aux2.c and aux3.c */ + +#include "glob.h" + +/* check to see if too much tunneling has been done in this level */ +void tunnelcheck(void) +{ + if ((Level->depth == 0 && Current_Environment != E_DLAIR) || + Current_Environment == E_ASTRAL) + return; + Level->tunnelled++; + if ((Level->tunnelled) > (Level->level_length)/4) + mprint("Dust and stone fragments fall on you from overhead."); + if ((Level->tunnelled) >(Level->level_length)/2) + mprint("You hear groaning and creaking noises."); + if ((Level->tunnelled) > (3*(Level->level_length))/4) + mprint("The floor trembles and you hear a loud grinding screech."); + if ((Level->tunnelled) > Level->level_length) { + mprint("With a scream of tortured stone, the entire dungeon caves in!!!"); + gain_experience(5000); + if (Player.status[SHADOWFORM]) { + change_environment(E_COUNTRYSIDE); + switch (Country[Player.x][Player.y].base_terrain_type) + { + case CASTLE: + case STARPEAK: + case CAVES: + case VOLCANO: + Country[Player.x][Player.y].current_terrain_type = MOUNTAINS; + break; + case DRAGONLAIR: + Country[Player.x][Player.y].current_terrain_type = DESERT; + break; + case MAGIC_ISLE: + Country[Player.x][Player.y].current_terrain_type = CHAOS_SEA; + break; + case PALACE: + Country[Player.x][Player.y].current_terrain_type = JUNGLE; + break; + } + Country[Player.x][Player.y].base_terrain_type = + Country[Player.x][Player.y].current_terrain_type; + c_set(Player.x, Player.y, CHANGED); + print1("In your shadowy state, you float back up to the surface."); + return; + } + mprint("You are flattened into an unpleasant jellylike substance."); + p_death("dungeon cave-in"); + } +} + +/* displays a room's name */ +void showroom(int i) +{ + strcpy(Str1,""); + strcpy(Str2,""); + switch(Current_Environment) { + case E_MANSION: + strcpy(Str2,"A luxurious mansion: "); + break; + case E_HOUSE: + strcpy(Str2,"A house: "); + break; + case E_HOVEL: + strcpy(Str2,"A hovel: "); + break; + case E_CITY: + strcpy(Str2,"The City of Rampart"); + break; + case E_VILLAGE: + switch(Villagenum) { + case 1: + strcpy(Str2,"The Village of Star View"); + break; + case 2: + strcpy(Str2,"The Village of Woodmere"); + break; + case 3: + strcpy(Str2,"The Village of Stormwatch"); + break; + case 4: + strcpy(Str2,"The Village of Thaumaris"); + break; + case 5: + strcpy(Str2,"The Village of Skorch"); + break; + case 6: + strcpy(Str2,"The Village of Whorfen"); + break; + } + break; + case E_CAVES: + strcpy(Str2,"The Goblin Caves: "); + break; + case E_CASTLE: + strcpy(Str2,"The Archmage's Castle: "); + break; + case E_ASTRAL: + strcpy(Str2,"The Astral Plane: "); + break; + case E_VOLCANO: + strcpy(Str2,"The Volcano: "); + break; + case E_PALACE: + strcpy(Str2,"The Palace Dungeons: "); + break; + case E_SEWERS: + strcpy(Str2,"The Sewers: "); + break; + case E_TACTICAL_MAP: + strcpy(Str2,"The Tactical Map "); + break; + default: + strcpy(Str2,""); + break; + } + if (Current_Environment == Current_Dungeon) { + strcpy(Str1,"Level "); + if (Level->depth < 10) { + Str1[6] = Level->depth + '0'; + Str1[7] = 0; + } + else { + Str1[6] = (Level->depth / 10) + '0'; + Str1[7] = (Level->depth % 10) + '0'; + Str1[8] = 0; + } + strcat(Str1," ("); + strcat(Str1,roomname(i)); + strcat(Str1,")"); + } + else if (strlen(Str2) == 0 || Current_Environment == E_MANSION || + Current_Environment == E_HOUSE || Current_Environment == E_HOVEL) + strcpy(Str1,roomname(i)); + strcat(Str2,Str1); + locprint(Str2); +} + + +int player_on_sanctuary(void) +{ + if ((Player.x==Player.sx) && + (Player.y==Player.sy)) + return(true); + else { + if (Player.patron) { + if ((Level->site[Player.x][Player.y].locchar == ALTAR) && + (Level->site[Player.x][Player.y].aux == Player.patron)) + return(true); + else return(false); + } + else return(false); + } +} + + +/* check a move attempt, maybe attack something, return true if ok to move. */ +/* x y is the proposed place to move to */ +int p_moveable(int x, int y) +{ + State.setSkipMonsters(); + if (! inbounds(x,y)) return (false); + else if (Player.status[SHADOWFORM]) { + switch(Level->site[x][y].p_locf) { + case L_CHAOS: + case L_ABYSS: + case L_VOID: + return cinema_confirm("That looks dangerous.") == 'y'; + default: + State.setSkipMonsters(false); + return(true); + } + } + else if (loc_statusp(x,y,SECRET)) { + if (State.getFastMove() == false) print3("Ouch!"); + return(false); + } + else if (Level->site[x][y].creature != NULL) { + if (State.getFastMove() == false) { + Level->site[x][y].creature->fight_monster(); + State.setSkipMonsters(false); + return(false); + } + else return(false); + } + else if ((Level->site[x][y].locchar == WALL) || + (Level->site[x][y].locchar == STATUE) || + (Level->site[x][y].locchar == PORTCULLIS) || + (Level->site[x][y].locchar == CLOSED_DOOR) || + (State.getFastMove() && + ((Level->site[x][y].locchar == HEDGE) || + (Level->site[x][y].locchar == LAVA) || + (Level->site[x][y].locchar == ABYSS) || + (Level->site[x][y].locchar == VOID_CHAR) || + (Level->site[x][y].locchar == FIRE) || + (Level->site[x][y].locchar == WHIRLWIND) || + (Level->site[x][y].locchar == WATER) || + (Level->site[x][y].locchar == LIFT) || + (Level->site[x][y].locchar == TRAP)))) { + if (State.getFastMove() == false) print3("Ouch!"); + return(false); + } + else if (optionp(CONFIRM)) { + if ((Level->site[x][y].locchar == HEDGE) || + (Level->site[x][y].locchar == LAVA) || + (Level->site[x][y].locchar == FIRE) || + (Level->site[x][y].locchar == WHIRLWIND) || + (Level->site[x][y].locchar == ABYSS) || + (Level->site[x][y].locchar == VOID_CHAR) || + (Level->site[x][y].locchar == WATER) || + (Level->site[x][y].locchar == RUBBLE) || + (Level->site[x][y].locchar == LIFT) || + (Level->site[x][y].locchar == TRAP)) { + /* horses WILL go into water... */ + if (State.getMounted()) { + if (Level->site[x][y].locchar != WATER || + Level->site[x][y].p_locf != L_WATER) { + print1("You can't convince your steed to continue."); + State.setSkipMonsters(); + return(false); + } + else return(true); + } + else if (cinema_confirm("Look where you're about to step!") == 'y') State.setSkipMonsters(false); + else State.setSkipMonsters(); + return(State.getSkipMonsters() == false); + } + else { + State.setSkipMonsters(false); + return(true); + } + } + else { + State.setSkipMonsters(false); + return(true); + } +} + + + +/* check a move attempt in the countryside */ +int p_country_moveable(int x, int y) +{ + if (! inbounds(x,y)) return (false); + else if (optionp(CONFIRM)) { + if ((Country[x][y].current_terrain_type == CHAOS_SEA) || + (Country[x][y].current_terrain_type == MOUNTAINS)) + return(cinema_confirm("That's dangerous terrain, and slow going.")=='y'); + else return(true); + } + else return(true); +} + + + + + +/* search once particular spot */ +void searchat(int x, int y) +{ + int i; + if (inbounds(x,y) && (random_range(3) || Player.status[ALERT])) { + if (loc_statusp(x,y,SECRET)) { + lreset(x,y,SECRET); + lset(x, y, CHANGED); + if ((Level->site[x][y].locchar==OPEN_DOOR) || + (Level->site[x][y].locchar==CLOSED_DOOR)) { + mprint("You find a secret door!"); + for(i=0; i<=8; i++) { /* FIXED! 12/25/98 */ + lset(x+Dirs[0][i],y+Dirs[1][i],STOPS); + lset(x+Dirs[0][i], y+Dirs[1][i], CHANGED); + } + } + else mprint("You find a secret passage!"); + drawvision(Player.x,Player.y); + } + if ((Level->site[x][y].p_locf >= TRAP_BASE) && + (Level->site[x][y].locchar != TRAP) && + (Level->site[x][y].p_locf <= TRAP_BASE+NUMTRAPS)) { + Level->site[x][y].locchar = TRAP; + lset(x, y, CHANGED); + mprint("You find a trap!"); + drawvision(Player.x,Player.y); + State.setFastMove(false); + } + } +} + + + +/* This is to be called whenever anything might change player performance in +melee, such as changing weapon, statistics, etc. */ +void calc_melee(void) +{ + calc_weight(); + + Player.maxweight = (Player.str * Player.agi * 10); + Player.absorption = Player.status[PROTECTION]; + Player.defense = 2 * statmod(Player.agi)+(Player.level/2); + Player.hit = Player.level + statmod(Player.dex)+1; + Player.dmg = statmod(Player.str)+3; + Player.speed = 5 - min(4,(statmod(Player.agi)/2)); + if (Player.status[HASTED] > 0) Player.speed = Player.speed / 2; + if (Player.status[SLOWED] > 0) Player.speed = Player.speed * 2; + if (Player.itemweight > 0) + switch(Player.maxweight / Player.itemweight) { + case 0: + Player.speed+=6; + break; + case 1: + Player.speed+=3; + break; + case 2: + Player.speed+=2; + break; + case 3: + Player.speed+=1; + break; + } + + if (Player.status[ACCURATE]) Player.hit+=20; + if (Player.status[HERO]) Player.hit+=Player.dex; + if (Player.status[HERO]) Player.dmg+=Player.str; + if (Player.status[HERO]) Player.defense+=Player.agi; + if (Player.status[HERO]) Player.speed=Player.speed / 2; + + Player.speed = max(1,min(25,Player.speed)); + + if (State.getMounted()) { + Player.speed = 3; + Player.hit += 10; + Player.dmg += 10; + } + else if (Player.rank[MONKS] > 0) + { + /* monks are faster when not in armor or on horseback */ + if (Player.possessions[O_ARMOR] == NULL) { + Player.speed += (min(0,(Player.rank[MONKS] -1))); + } + } + + /* weapon */ + /* have to check for used since it could be a 2h weapon just carried + in one hand */ + if (Player.possessions[O_WEAPON_HAND] != NULL) + if (Player.possessions[O_WEAPON_HAND]->used && + ((Player.possessions[O_WEAPON_HAND]->objchar==WEAPON)|| + (Player.possessions[O_WEAPON_HAND]->objchar==MISSILEWEAPON))) { + Player.hit += + Player.possessions[O_WEAPON_HAND]->hit + + Player.possessions[O_WEAPON_HAND]->plus; + Player.dmg += + Player.possessions[O_WEAPON_HAND]->dmg + + Player.possessions[O_WEAPON_HAND]->plus; + } + + if (Player.rank[MONKS] > 0) + { + /* monks */ + /* aren't monks just obscene? PGM */ + if (Player.possessions[O_WEAPON_HAND] == NULL) /*barehanded*/ + { + /* all monks get a bonus in unarmed combat */ + Player.hit += ( Player.rank[MONKS] * Player.level ); + Player.dmg += ( Player.rank[MONKS] * Player.level ); + Player.defense += ( Player.rank[MONKS] * Player.level ); + + if (Player.rank[MONKS] == MONK_GRANDMASTER) + { + /* Grandmaster does 3x damage in unarmed combat. */ + Player.dmg *= 3; + } + } + } + + /* shield or defensive weapon */ + if (Player.possessions[O_SHIELD] != NULL) { + Player.defense += + Player.possessions[O_SHIELD]->aux + + Player.possessions[O_SHIELD]->plus; + } + + /* armor */ + if (Player.possessions[O_ARMOR] != NULL) { + Player.absorption += Player.possessions[O_ARMOR]->dmg; + Player.defense += + Player.possessions[O_ARMOR]->plus - + Player.possessions[O_ARMOR]->aux; + } + + if (strlen(Player.combatManeuvers) > 2*maneuvers()) + default_maneuvers(); + comwinprint(); + showflags(); + dataprint(); +} + +/* Attempt to break an object o */ +int damage_item(Object* o) +{ + /* special case -- break star gem */ + if (o->id == OB_STARGEM) { + print1("The Star Gem shatters into a million glistening shards...."); + if (Current_Environment == E_STARPEAK) { + if (!State.getKilledLawbringer()) + print2("You hear an agonizing scream of anguish and despair."); + morewait(); + print1("A raging torrent of energy escapes in an explosion of magic!"); + print2("The energy flows to the apex of Star Peak where there is"); + morewait(); + clearmsg(); + print1("an enormous explosion!"); + morewait(); + annihilate(1); + print3("You seem to gain strength in the chaotic glare of magic!"); + Player.str = max(Player.str, Player.maxstr + 5); /* FIXED! 12/25/98 */ + Player.pow = max(Player.pow, Player.maxpow + 5); /* ditto */ + Player.alignment -= 200; + dispose_lost_objects(1,o); + } + else { + morewait(); + print1("The shards coalesce back together again, and vanish"); + print2("with a muted giggle."); + dispose_lost_objects(1,o); + Objects[o->id].uniqueness = UNIQUE_UNMADE; /* FIXED! 12/30/98 */ + } + return 1; + } + else { + if (o->fragility < random_range(30)) { + if (o->objchar == STICK && o->charge > 0) { + strcpy(Str1,"Your "); + strcat(Str1,(o->blessing >= 0 ? o->truename : o->cursestr)); + strcat(Str1," explodes!"); + print1(Str1); + morewait(); + nprint1(" Ka-Blamm!!!"); + /* general case. Some sticks will eventually do special things */ + morewait(); + manastorm(Player.x, Player.y, o->charge*o->level*10); + dispose_lost_objects(1,o); + return 1; + } + else if ((o->blessing > 0) && (o->level > random_range(10))) { + strcpy(Str1,"Your "); + strcat(Str1,itemid(o)); + strcat(Str1," glows strongly."); + print1(Str1); + return 0; + } + else if ((o->blessing < -1) && (o->level > random_range(10))) { + strcpy(Str1,"You hear an evil giggle from your "); + strcat(Str1,itemid(o)); + print1(Str1); + return 0; + } + else if (o->plus > 0) { + strcpy(Str1,"Your "); + strcat(Str1,itemid(o)); + strcat(Str1," glows and then fades."); + print1(Str1); + o->plus--; + return 0; + } + else { + if (o->blessing > 0) print1("You hear a faint despairing cry!"); + else if (o->blessing < 0) print1("You hear an agonized scream!"); + strcpy(Str1,"Your "); + strcat(Str1,itemid(o)); + strcat(Str1," shatters in a thousand lost fragments!"); + print2(Str1); + morewait(); + dispose_lost_objects(1,o); + return 1; + } + } + return 0; + } +} + +/* do dmg points of damage of type dtype, from source fromstring */ +void p_damage(int dmg, int dtype, char *fromstring) +{ + if (State.getFastMove()) { + drawvision(Player.x,Player.y); + State.setFastMove(false); + } + if (! p_immune(dtype)) { + if (dtype == NORMAL_DAMAGE) Player.hp -= max(1,(dmg-Player.absorption)); + else Player.hp -= dmg; + if (Player.hp < 1) p_death(fromstring); + } + else mprint("You resist the effects!"); + dataprint(); +} + +/* game over, you lose! */ +void p_death(char *fromstring) +{ + Player.hp = -1; + print3("You died!"); + morewait(); + display_death(fromstring); + player_dump(); + endgraf(); + exit(0); +} + +/* move the cursor around, like for firing a wand, sets x and y to target */ +void setspot(int *x, int *y) +{ + char c = ' '; + mprint("Targeting.... ? for help"); + omshowcursor(*x,*y); + while ((c != '.') && (c != ESCAPE)) { + c = lgetc(); + switch(c) { +#ifdef KEY_LEFT + case KEY_LEFT: +#endif + case (char)4: + case (char)KEY_ARROW_LEFT: + case 'h': + case '4': + movecursor(x,y,-1,0); + break; + case (char)2: + case (char)KEY_ARROW_DOWN: + case 'j': + case '2': + movecursor(x,y,0,1); + break; + case (char)8: + case (char)KEY_ARROW_UP: + case 'k': + case '8': + movecursor(x,y,0,-1); + break; +#ifdef KEY_RIGHT + case KEY_RIGHT: +#endif + case (char)6: + case (char)KEY_ARROW_RIGHT: + case 'l': + case '6': + movecursor(x,y,1,0); + break; + case 'b': + case '1': + movecursor(x,y,-1,1); + break; + case 'n': + case '3': + movecursor(x,y,1,1); + break; + case 'y': + case '7': + movecursor(x,y,-1,-1); + break; + case 'u': + case '9': + movecursor(x,y,1,-1); + break; + case '?': + clearmsg(); + mprint("Use vi keys or numeric keypad to move cursor to target."); + mprint("Hit the '.' key when done, or ESCAPE to abort."); + break; + } + } + if (c==ESCAPE) { + *x = *y = ABORT; + clearmsg(); + } + screencheck(Player.x,Player.y); +} + + +/* get a direction: return index into Dirs array corresponding to direction */ +int getdir(void) +{ + while (1) { + mprint("Select direction [hjklyubn, ESCAPE to quit]: "); + switch (mgetc()) { + case '4': + case 'h': + case 'H': + return(5); + case '2': + case 'j': + case 'J': + return(6); + case '8': + case 'k': + case 'K': + return(7); + case '6': + case 'l': + case 'L': + return(4); + case '7': + case 'y': + case 'Y': + return(3); + case '9': + case 'u': + case 'U': + return(1); + case '1': + case 'b': + case 'B': + return(2); + case '3': + case 'n': + case 'N': + return(0); + case ESCAPE: + clearmsg(); + return(ABORT); + default: + print3("That's not a direction! "); + } + } +} + +/* for the examine function */ +void describe_player(void) +{ + if (Player.hp < (Player.maxhp /5)) + print1("A grievously injured "); + else if (Player.hp < (Player.maxhp /2)) + print1("A seriously wounded "); + else if (Player.hp < Player.maxhp) + print1("A somewhat bruised "); + else print1("A fit "); + + if (Player.status[SHADOWFORM]) + nprint1("shadow"); + else + nprint1(levelname(Player.level)); + nprint1(" named "); + nprint1(Player.name); + if (State.getMounted()) + nprint1(" (riding a horse.)"); +} + + +/* access to player experience... */ +/* share out experience among guild memberships */ +void gain_experience(int amount) +{ + int i,count=0,share; + Player.xp += (long) amount; + gain_level(); /* actually, check to see if should gain level */ + for(i=0; i 0) count++; + share = amount/(max(count,1)); + for(i=0; i 0) Player.guildxp[i]+=share; +} + +/* try to hit a monster in an adjacent space. If there are none +return false. Note if you're berserk you get to attack ALL +adjacent monsters! */ +int goberserk(void) +{ + int wentberserk=false,i; + char combatManeuvers[80]; + strcpy(combatManeuvers,Player.combatManeuvers); + strcpy(Player.combatManeuvers,"lLlClH"); + for(i=0; i<8; i++) + if (Level->site[Player.x+Dirs[0][i]][Player.y+Dirs[1][i]].creature + != NULL) { + wentberserk=true; + Level->site[Player.x+Dirs[0][i]][Player.y+Dirs[1][i]].creature->fight_monster(); + morewait(); + } + strcpy(Player.combatManeuvers,combatManeuvers); + return(wentberserk); +} + +/* identifies a trap for examine() by its aux value */ +char *trapid(int trapno) +{ + switch (trapno) { + case L_TRAP_SIREN: + return("A siren trap"); + case L_TRAP_DART: + return("A dart trap"); + case L_TRAP_PIT: + return("A pit"); + case L_TRAP_SNARE: + return("A snare"); + case L_TRAP_BLADE: + return("A blade trap"); + case L_TRAP_FIRE: + return("A fire trap"); + case L_TRAP_TELEPORT: + return("A teleport trap"); + case L_TRAP_DISINTEGRATE: + return("A disintegration trap"); + case L_TRAP_DOOR: + return("A trap door"); + case L_TRAP_MANADRAIN: + return("A manadrain trap"); + case L_TRAP_ACID: + return("An acid shower trap"); + case L_TRAP_SLEEP_GAS: + return("A sleep gas trap"); + case L_TRAP_ABYSS: + return("A concealed entrance to the abyss"); + default: + return("A completely inoperative trap."); + } +} + + +/* checks current food status of player, every hour, and when food is eaten */ +void foodcheck(void) +{ + if (Player.food > 48) { + print3("You vomit up your huge meal."); + Player.food = 12; + } + else if (Player.food == 30) + print3("Time for a smackerel of something."); + else if (Player.food == 20) + print3("You feel hungry."); + else if (Player.food == 12) + print3("You are ravenously hungry."); + else if (Player.food == 3) { + print3("You feel weak."); + if (State.getFastMove()) { + drawvision(Player.x,Player.y); + State.setFastMove(false); + } + } + else if (Player.food < 0) { + if (State.getFastMove()) { + drawvision(Player.x,Player.y); + State.setFastMove(false); + } + print3("You're starving!"); + p_damage(-5*Player.food,UNSTOPPABLE,"starvation"); + } + showflags(); +} + + + + +/* see whether room should be illuminated */ +void roomcheck(void) +{ + static int oldroomno = -1; +#if defined(WIN32) + static int oldlevel = -1; +#else + static plv oldlevel = NULL; +#endif + int roomno = Level->site[Player.x][Player.y].roomnumber; + + if ((roomno == RS_CAVERN) || + (roomno == RS_SEWER_DUCT) || + (roomno == RS_KITCHEN) || + (roomno == RS_BATHROOM) || + (roomno == RS_BEDROOM) || + (roomno == RS_DININGROOM) || + (roomno == RS_CLOSET) || + (roomno > ROOMBASE)) + if ((! loc_statusp(Player.x,Player.y,LIT)) && + (! Player.status[BLINDED]) && + (Player.status[ILLUMINATION] || (difficulty() < 6))) { + showroom(Level->site[Player.x][Player.y].roomnumber); + spreadroomlight(Player.x,Player.y,roomno); + levelrefresh(); + } + if ((oldroomno != roomno) || +#if defined(WIN32) + (oldlevel != Level->depth)) { +#else + (oldlevel != Level)) { +#endif + showroom(roomno); + oldroomno = roomno; +#if defined(WIN32) + oldlevel = Level->depth; +#else + oldlevel = Level; +#endif + } +} + + + +/* name of the player's experience level */ +char *levelname(int level) +{ + switch(level) { + case 0: + strcpy(Str3,"neophyte"); + break; + case 1: + strcpy(Str3,"beginner"); + break; + case 2: + strcpy(Str3,"tourist"); + break; + case 3: + strcpy(Str3,"traveller"); + break; + case 4: + strcpy(Str3,"wayfarer"); + break; + case 5: + strcpy(Str3,"peregrinator"); + break; + case 6: + strcpy(Str3,"wanderer"); + break; + case 7: + strcpy(Str3,"hunter"); + break; + case 8: + strcpy(Str3,"scout"); + break; + case 9: + strcpy(Str3,"trailblazer"); + break; + case 10: + strcpy(Str3,"discoverer"); + break; + case 11: + strcpy(Str3,"explorer"); + break; + case 12: + strcpy(Str3,"senior explorer"); + break; + case 13: + strcpy(Str3,"ranger"); + break; + case 14: + strcpy(Str3,"ranger captain"); + break; + case 15: + strcpy(Str3,"ranger knight"); + break; + case 16: + strcpy(Str3,"adventurer"); + break; + case 17: + strcpy(Str3,"experienced adventurer"); + break; + case 18: + strcpy(Str3,"skilled adventurer"); + break; + case 19: + strcpy(Str3,"master adventurer"); + break; + case 20: + strcpy(Str3,"hero"); + break; + case 21: + strcpy(Str3,"superhero"); + break; + case 22: + strcpy(Str3,"demigod"); + break; + default: + if (level < 100) { + strcpy(Str3,"Order "); + Str3[6] = ((level/10)-2) + '0'; + Str3[7] = 0; + strcat(Str3," Master of Omega"); + } + else strcpy(Str3,"Ultimate Master of Omega"); + break; + } + return(Str3); +} diff --git a/Omega/src/char.cpp b/Omega/src/char.cpp index 7ebb284..befb05f 100644 --- a/Omega/src/char.cpp +++ b/Omega/src/char.cpp @@ -83,6 +83,7 @@ bool initplayer(void) optionset(CONFIRM); optionset(SHOW_COLOUR); ret_value = initstats() ; /* RM 04-19-2000:loading patch */ /* DAG */ + return ret_value > 0; } /* This gets executed when the player loads from .omegarc */ /* DAG - put the code back in the same place, rather than duplicating */ From 6aadc69ce5b5f367abeacee99a4e515451fc0611 Mon Sep 17 00:00:00 2001 From: Patrick McCuller Date: Wed, 7 May 2014 22:19:32 -0700 Subject: [PATCH 10/12] "Fixed" food bug that crashed game on any food ingested. Essentially hacked the old function back in but did not remove the new LizzardBucket code entirely. Added simple arrow keys to setdir(), country movement, getpos, etc. Fixed typos Fixed static analysis items like malloc(size_t) instead of malloc(int) Fixed stats reset on load bug Fixed inventory spot sqap bug (one bug remains) Added save file scum while debugging code Added auto-display-inventory-slots on up-in-air swap selection Added detection of and friendlier error messages on memory allocation failures. --- Omega/src/aux1.cpp | 34 +- Omega/src/aux3.cpp | 2586 ++++++++++++++++++++-------------------- Omega/src/bank.cpp | 5 +- Omega/src/char.cpp | 16 +- Omega/src/command1.cpp | 20 + Omega/src/command2.cpp | 2367 ++++++++++++++++++------------------ Omega/src/defs.h | 2 +- Omega/src/inv.cpp | 9 +- Omega/src/item.cpp | 2215 +++++++++++++++++----------------- Omega/src/itemf1.cpp | 1980 +++++++++++++++--------------- Omega/src/map.cpp | 2 + Omega/src/omega.cpp | 482 ++++---- Omega/src/site1.cpp | 2220 +++++++++++++++++----------------- Omega/src/util.cpp | 2308 +++++++++++++++++------------------ Tools/src/bwt.c | 2 +- Tools/src/decrypt.c | 4 +- data/omega.hi | 6 +- data/omega.log | 8 + 18 files changed, 7183 insertions(+), 7083 deletions(-) diff --git a/Omega/src/aux1.cpp b/Omega/src/aux1.cpp index 0338783..d1e4fa8 100644 --- a/Omega/src/aux1.cpp +++ b/Omega/src/aux1.cpp @@ -527,25 +527,33 @@ void setspot(int *x, int *y) case '4': movecursor(x,y,-1,0); break; +#ifdef KEY_DOWN + case KEY_DOWN: +#endif case (char)2: case (char)KEY_ARROW_DOWN: case 'j': case '2': movecursor(x,y,0,1); break; - case (char)8: +#ifdef KEY_UP + case KEY_UP: +#endif + case (char)3: case (char)KEY_ARROW_UP: case 'k': case '8': movecursor(x,y,0,-1); break; + #ifdef KEY_RIGHT case KEY_RIGHT: #endif - case (char)6: + case (char)5: case (char)KEY_ARROW_RIGHT: - case 'l': case '6': + case 'l': + case 'L': movecursor(x,y,1,0); break; case 'b': @@ -585,18 +593,38 @@ int getdir(void) while (1) { mprint("Select direction [hjklyubn, ESCAPE to quit]: "); switch (mgetc()) { +#ifdef KEY_LEFT + case KEY_LEFT: +#endif + case (char)4: + case (char)KEY_ARROW_LEFT: case '4': case 'h': case 'H': return(5); +#ifdef KEY_DOWN + case KEY_DOWN: +#endif + case (char)2: + case (char)KEY_ARROW_DOWN: case '2': case 'j': case 'J': return(6); +#ifdef KEY_UP + case KEY_UP: +#endif + case (char)KEY_ARROW_UP: + case (char)8: case '8': case 'k': case 'K': return(7); +#ifdef KEY_RIGHT + case KEY_RIGHT: +#endif + case (char)6: + case (char)KEY_ARROW_RIGHT: case '6': case 'l': case 'L': diff --git a/Omega/src/aux3.cpp b/Omega/src/aux3.cpp index bf98033..c4e8130 100644 --- a/Omega/src/aux3.cpp +++ b/Omega/src/aux3.cpp @@ -1,1293 +1,1293 @@ -/* omega copyright (C) by Laurence Raphael Brothers, 1987,1988,1989 */ -/* aux3.c */ -/* some functions called by com.c, also see aux1.c, aux2.c */ -/* This is a real grab bag file. It contains functions used by -aux1.c and omega.c, as well as elsewhere. It is mainly here so aux1.c -and aux2.c are not huge */ - -#include "glob.h" - -/* check every ten minutes */ -void tenminute_check(void) -{ - if (Time % 60 == 0) hourly_check(); - else { - if (Current_Environment == Current_Dungeon) wandercheck(); - minute_status_check(); - tenminute_status_check(); - if ((Player.status[DISEASED] < 1) && (Player.hp < Player.maxhp)) - Player.hp = min(Player.maxhp,Player.hp+Player.level+1); - if (Current_Environment != E_COUNTRYSIDE && Current_Environment != E_ABYSS) - indoors_random_event(); - } -} - - - -/* hourly check is same as ten_minutely check except food is also -checked, and since time moves in hours out of doors, also -outdoors_random_event is possible */ - -void hourly_check(void) -{ - Player.food--; - foodcheck(); - if (hour()==0) { /* midnight, a new day */ - moon_check(); - Date++; - } - torch_check(); - if (Current_Environment == Current_Dungeon) wandercheck(); - minute_status_check(); - tenminute_status_check(); - if ((Player.status[DISEASED] == 0) && (Player.hp < Player.maxhp)) - Player.hp = min(Player.maxhp,Player.hp+Player.level+1); - if (Current_Environment != E_COUNTRYSIDE && Current_Environment != E_ABYSS) - indoors_random_event(); -} - - - - -void indoors_random_event(void) -{ - MonsterList* ml; - pol ol; - - switch(random_range(1000)) { - case 0: - print3("You feel an unexplainable elation."); - morewait(); - break; - case 1: - print3("You hear a distant rumbling."); - morewait(); - break; - case 2: - print3("You realize your fly is open."); - morewait(); - break; - case 3: - print3("You have a sudden craving for a pecan twirl."); - morewait(); - break; - case 4: - print3("A mysterious healing flux settles over the level."); - morewait(); - for (ml=Level->mlist; ml!=NULL; ml=ml->next) - if (ml->monster->hp > 0) ml->monster->hp = Monsters[ml->monster->id].hp; - Player.hp = max(Player.hp,Player.maxhp); - break; - case 5: - print3("You discover an itch just where you can't scratch it."); - morewait(); - break; - case 6: - print3("A cosmic ray strikes!"); - p_damage(10,UNSTOPPABLE,"a cosmic ray"); - morewait(); - break; - case 7: - print3("You catch your second wind...."); - Player.maxhp++; - Player.hp = max(Player.hp, Player.maxhp); - Player.mana = max(Player.mana, calcmana()); - morewait(); - break; - case 8: - print3("You find some spare change in a hidden pocket."); - morewait(); - Player.cash += Player.level*Player.level+1; - break; - case 9: - print3("You feel strangely lucky."); - morewait(); - break; - case 10: - print3("You trip over something hidden in a shadow..."); - morewait(); - ol = ((pol) checkmalloc(sizeof(oltype))); - ol->thing = create_object(difficulty()); /* FIXED! 12/30/98 */ - assert(ol->thing); /* WDT I want to make sure... */ - ol->next = Level->site[Player.x][Player.y].things; - Level->site[Player.x][Player.y].things = ol; - pickup(); - break; - case 11: - print3("A mysterious voice echoes all around you...."); - morewait(); - hint(); - morewait(); - break; - } - dataprint(); - showflags(); -} - - - -void outdoors_random_event(void) -{ - int num,i,j; - Object* ob; - - switch(random_range(300)) { - case 0: - switch(Country[Player.x][Player.y].current_terrain_type) { - case TUNDRA: - mprint("It begins to snow. Heavily."); - break; - case DESERT: - mprint("A sandstorm swirls around you."); - break; - default: - if ((Date > 75) && (Date < 330)) - mprint("You are drenched by a sudden downpour!"); - else mprint("It begins to snow. Heavily."); - } - morewait(); - mprint("Due to the inclement weather conditions, you have become lost."); - morewait(); - Precipitation+=random_range(12)+1; - State.setLost( true ); - break; - case 1: - mprint("You enter a field of brightly colored flowers..."); - mprint("Wow, man! These are some pretty poppies..."); - morewait(); - mprint("poppies..."); - morewait(); - mprint("poppies..."); - morewait(); - print3("You become somewhat disoriented..."); - State.setLost( true ); - break; - case 2: - mprint("You discover a sprig of athelas growing lonely in the wild."); - morewait(); - mprint("Using your herbalist lore you cook a cake of lembas...."); - morewait(); - ob = ((Object*) checkmalloc(sizeof(Object))); - *ob = Objects[OB_LEMBAS]; - gain_item(ob); - break; - case 3: - if (Precipitation > 0) { - mprint("You are struck by a bolt of lightning!"); - p_damage(random_range(25),ELECTRICITY,"a lightning strike"); - morewait(); - } - else mprint("You feel static cling"); - break; - case 4: - mprint("You find a fast-food establishment."); - morewait(); - l_commandant(); - break; - case 5: - mprint("A weird howling tornado hits from out of the West!"); - morewait(); - mprint("You've been caught in a chaos storm!"); - morewait(); - num = random_range(300); - if (num <10) { - mprint("Your cell-structure was disrupted!"); - p_damage(random_range(100),UNSTOPPABLE,"a chaos storm"); - morewait(); - } - else if (num < 20) { - mprint("The chaos storm warps your frame!"); - morewait(); - mprint("Your statistical entropy has been maximized."); - morewait(); - mprint("You feel average..."); - morewait(); - toggle_item_use(true); /* FIXED! 12/30/98 */ - Player.str = Player.maxstr = Player.con = Player.maxcon = - Player.dex = Player.maxdex = Player.agi = Player.maxagi = - Player.iq = Player.maxiq = Player.pow = Player.maxpow = - ((Player.maxstr+Player.maxcon+Player.maxdex+Player.maxagi+ - Player.maxiq+Player.maxpow+12)/6); - toggle_item_use(false); /* FIXED! 12/30/98 */ - } - else if (num < 30) { - mprint("Your entire body glows with an eerie flickering light."); - morewait(); - toggle_item_use(true); /* FIXED! 12/30/98 */ - for(i=1; iplus++; - if (Player.possessions[i]->objchar == STICK) - Player.possessions[i]->charge+=10; - Player.possessions[i]->blessing+=10; - } - toggle_item_use(false); /* FIXED! 12/30/98 */ - cleanse(1); - mprint("You feel filled with energy!"); - morewait(); - Player.maxpow += 5; - Player.pow += 5; - Player.mana = Player.maxmana = calcmana() * 5; - mprint("You also feel weaker. Paradoxical, no?"); - morewait(); - Player.con -= 5; - Player.maxcon -= 5; - if (Player.con < 3) - p_death("congestive heart failure"); - } - else if (num < 40) { - mprint("Your entire body glows black."); - morewait(); - dispel(-1); - dispel(-1); - Player.pow-=10; - Player.mana=0; - } - else if (num < 60) { - mprint("The storm deposits you in a strange place...."); - morewait(); - setPlayerXY( random_range(COUNTRY_WIDTH), random_range(COUNTRY_LENGTH)); - screencheck(Player.x,Player.y); - } - else if (num < 70) { - mprint("A tendril of the storm condenses and falls into your hands."); - morewait(); - ob = ((Object*) checkmalloc(sizeof(Object))); - make_artifact(ob,-1); - gain_item(ob); - } - else if (num < 80) { - if (State.getMounted()) { - mprint("Your horse screams as he is transformed into an"); - morewait(); - mprint("imaginary unseen dead tortoise."); - morewait(); - mprint("You are now on foot."); - morewait(); - State.setMounted(false); - } - else { - mprint("You notice you are riding a horse. Odd. Very odd...."); - morewait(); - mprint("Now that's a horse of a different color!"); - morewait(); - State.setMounted( true ); - } - } - else if (num < 90) { - mprint("You feel imbued with godlike power...."); - morewait(); - wish(1); - } - else if (num < 100) { - mprint("The chaos storm has wiped your memory!"); - morewait(); - mprint("You feel extraordinarily naive...."); - morewait(); - mprint("You can't remember a thing! Not even your name."); - morewait(); - Player.xp = 0; - Player.level = 0; - for (i=0; i 0) && - (Player.level/2 + random_range(20) > - hostile_magic + random_range(20))) { - if (Player.mana > hostile_magic * hostile_magic) { - mprint("Thinking fast, you defend youself with a counterspell!"); - Player.mana -= hostile_magic * hostile_magic; - dataprint(); - return(true); - } - } - if (Player.level/4 + Player.status[PROTECTION] + random_range(20) > - hostile_magic + random_range(30)) { - mprint("You resist the spell!"); - return(true); - } - else return(false); -} - - -void terrain_check(int takestime) -{ - int faster = 0; - - if (Player.patron == DRUID) { - faster = 1; - switch(random_range(32)) { - case 0: - print2("Along the many paths of nature..."); - break; - case 1: - print2("You move swiftly through the wilderness."); - break; - } - } - else if (State.getMounted()) { - faster = 1; - switch(random_range(32)) { - case 0: - case 1: - print2("Clippity Clop."); - break; - case 2: - print2("....my spurs go jingle jangle jingle...."); - break; - case 3: - print2("....as I go riding merrily along...."); - break; - } - } - else if (Player.possessions[O_BOOTS] && - Player.possessions[O_BOOTS]->usef == I_BOOTS_7LEAGUE) { - takestime = 0; - switch(random_range(32)) { - case 0: - print2("Boingg!"); - break; - case 1: - print2("Whooosh!"); - break; - case 2: - print2("Over hill, over dale...."); - break; - case 3: - print2("...able to leap over 7 leagues in a single bound...."); - break; - } - } - else if (Player.status[SHADOWFORM]) { - faster = 1; - switch(random_range(32)) { - case 0: - print2("As swift as a shadow."); - break; - case 1: - print2("\"I walk through the trees...\""); - break; - } - } - else switch(random_range(32)) { - case 0: - print2("Trudge. Trudge."); - break; - case 1: - print2("The road goes ever onward...."); - break; - } - switch(Country[Player.x][Player.y].current_terrain_type) { - case RIVER: - if ((Player.y < 6) && (Player.x > 20)) locprint("Star Lake."); - else if (Player.y < 41) { - if (Player.x < 10) locprint("Aerie River."); - else locprint("The Great Flood."); - } - else if (Player.x < 42) locprint("The Swamp Runs."); - else locprint("River Greenshriek."); - if (takestime) { - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - } - break; - case ROAD: - locprint("A well-maintained road."); - if (takestime) { - Time += 60; - hourly_check(); - } - break; - case PLAINS: - locprint("A rippling sea of grass."); - if (takestime) { - Time += 60; - hourly_check(); - if (! faster) { - Time += 60; - hourly_check(); - } - } - break; - case TUNDRA: - locprint("The Great Northern Wastes."); - if (takestime) { - Time += 60; - hourly_check(); - if (! faster) { - Time += 60; - hourly_check(); - } - } - break; - case FOREST: - if (Player.y < 10) locprint("The Deepwood."); - else if (Player.y < 18) locprint("The Forest of Erelon."); - else if (Player.y < 46) locprint("The Great Forest."); - if (takestime) { - Time += 60; - hourly_check(); - if (Player.rank[PRIESTHOOD] == 0 || Player.patron != DRUID) { - Time += 60; - hourly_check(); - if (! faster) { - Time += 60; - hourly_check(); - } - } - } - break; - case JUNGLE: - locprint("Greenshriek Jungle."); - if (takestime) { - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - if (! faster) { - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - } - } - break; - case DESERT: - locprint("The Waste of Time."); - if (takestime) { - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - if (! faster) { - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - } - } - break; - case MOUNTAINS: - if ((Player.y < 9) && (Player.x < 12)) - locprint("The Magic Mountains"); - else if ((Player.y < 9) && (Player.y > 2) && (Player.x < 40)) - locprint("The Peaks of the Fist."); - else if (Player.x < 52) - locprint("The Rift Mountains."); - else locprint("Borderland Mountains."); - if (takestime) { - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - if (! faster) { - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - } - } - break; - case PASS: - locprint("A hidden pass."); - if (takestime) { - Time += 60; - hourly_check(); - } - break; - case CHAOS_SEA: - locprint("The Sea of Chaos."); - if (takestime) { - Time += 60; - hourly_check(); - } - mprint("You have entered the sea of chaos..."); - morewait(); - l_chaos(); - break; - case SWAMP: - locprint("The Loathly Swamp."); - if (takestime) { - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - if (! faster) { - Time += 60; - hourly_check(); - Time += 60; - hourly_check(); - } - } - break; - case CITY: - if (State.getLost()) { - State.setLost( false ); - mprint("Well, I guess you know where you are now...."); - } - locprint("Outside Rampart, the city."); - break; - case VILLAGE: - if (State.getLost()) { - State.setLost( false ); - mprint("The village guards let you know where you are...."); - } - locprint("Outside a small village."); - break; - case CAVES: - locprint("A deserted hillside."); - if (takestime) { - Time += 60; - hourly_check(); - } - mprint("You notice a concealed entrance into the hill."); - break; - case CASTLE: - locprint("Near a fortified castle."); - if (takestime) { - Time += 60; - hourly_check(); - } - mprint("The castle is hewn from solid granite. The drawbridge is down."); - break; - case TEMPLE: - switch(Country[Player.x][Player.y].aux) { - case ODIN: - locprint("A rough-hewn granite temple."); - break; - case SET: - locprint("A black pyramidal temple made of sandstone."); - break; - case ATHENA: - locprint("A classical marble-columned temple."); - break; - case HECATE: - locprint("A temple of ebony adorned with ivory."); - break; - case DRUID: - locprint("A temple formed of living trees."); - break; - case DESTINY: - locprint("A temple of some mysterious blue crystal."); - break; - } - if (takestime) { - Time += 60; - hourly_check(); - } - mprint("You notice an entrance conveniently at hand."); - break; - case MAGIC_ISLE: - locprint("A strange island in the midst of the Sea of Chaos."); - if (takestime) { - Time += 60; - hourly_check(); - } - mprint("There is a narrow causeway to the island from here."); - break; - case STARPEAK: - locprint("Star Peak."); - if (takestime) { - Time += 60; - hourly_check(); - } - mprint("The top of the mountain seems to glow with a allochroous aura."); - break; - case DRAGONLAIR: - locprint("A rocky chasm."); - if (takestime) { - Time += 60; - hourly_check(); - } - mprint("You are at a cave entrance from which you see the glint of gold."); - break; - case PALACE: - locprint("The ruins of a once expansive palace."); - if (takestime) { - Time += 60; - hourly_check(); - } - mprint("The palace dungeons are still intact..."); - break; - case VOLCANO: - locprint("HellWell Volcano."); - if (takestime) { - Time += 60; - hourly_check(); - } - mprint("A shimmer of heat lightning plays about the crater rim."); - break; - default: - locprint("I haven't any idea where you are!!!"); - break; - } - outdoors_random_event(); -} - - - -void countrysearch(void) -{ - int x,y; - Time+=60; - hourly_check(); - for (x=Player.x-1; x