Files
oboe/osx/boe.actions.cpp
Celtic Minstrel c413d292a9 Tear out most of the legacy code in the game - see below for details
(PC Editor and Scenario Editor are unaffected by this commit.)

Things removed:
- All references to Carbon and QuickDraw are gone.
- No more Resource Manager; the game no longer relies on old resource files at all
- The old dialog framework (from dlogtool.c, functions usually prefixed with cd_) is no longer used.
- Files that weren't being compiled
- Boost libraries that are now in the C++ library (function, shared_ptr)
- Obsolete build settings

Replacement dependencies:
- Boost Filesystem replaces references to things like FSSpec
- SFML replaces all the QuickDraw code and most window management
- Cocoa replaces AppleEvent management, menu management, and some window management
- I wrote a resource manager interface to mimick the important aspects of the behaviour of the Mac Resource Manager
- I had to rewrite some functions that QuickDraw provided natively, such as clipping regions; not all of these are tested

Things added:
- Every referenced dialog has been converted from a DITL resource into the new XML-based dialog format.
- All referenced STR# resources have been extracted into simple text files
- Now compiles against Mac OSX 10.7 SDK and libc++
- The first item in the Help menu opens the docs on Sylae's website
- It seems all the constants for soundtool vanished somewhere, so I added them back from the original Mac source

Other changes:
- Updated to XCode 4(?) project format
- Added the xcschemes created by XCode 4; I'm not sure how important these are, but they seem like they might be important
- Added document on converting dialogs to the XML format.
- Make string formatting mismatches into errors instead of warnings
- Disable error limit
- Graphics sheets that previously used masking now have alpha transparency
- Converted all graphics sheets to 8-bit PNG
- Trimmed white border from intro image
- Converted dialogs in the resource file have their resource name set to the name of the XML file of the converted version
- Referenced string resources in the resource file have their resource name set to the name of the text file of the extracted version
- Add the black-and-white patterns from the PAT resources to the pixpats.png; at least one of them is used somewhere in the game
- Recreated the menu.xib as a Cocoa xib file instead of a Carbon xib file
- Disable GNU C++ extensions; maybe this'll make it easier to compile with cl.exe later
- Add marks to the enormous handle_action function to make it easier to navigate\
- A build step to validate the XML dialogs using xmllint (doesn't quite work properly yet but does at least catch dialogs that are not well-formed)- Fix a lot of warnings about assigning string constants to non-const char pointers
- Fixed the file and application icons (which had somehow become corrupted at some point)
- Lots of additional functions in the custom location and rectangle classes, including implicit conversion to and from SFML rects and vectors; also they now store coordinates as int instead of char
- A new enum for encounter note types
- Much tweaking of the encounter note recording mechanisms
- To ease porting, I added a simple function that converts from classic Mac ticks (about 1/60 of a second) to the SFML time type
- Python script to convert STR# resources to txt files, replacing newlines with vertical bars
- Extracted the Mac font (Dungeon Bold) from the resource file and also added the Windows font (MaidenWord)

XML Dialog Framework changes:
- Remove the static initialization object in favour of manually calling cDialog::init()
- {set,get}Format() no longer used for colour; there's a dedicated {set,get}Colour() instead
- draw() methods unprotected in the control classes so that controls can be drawn in the main window
- There's no longer a friend relationship between the dialogs and the controls
- Fixed buttons duplicating the "depressed" boolean
- Buttons now properly offset the label for tiny and push buttons, and for LEDs
- Buttons no longer assume that either none or both of "width" and "height" are given in the XML
- Add {get,set}BtnType() to cButton
- cLedGroup now overrides handleClick(), which has also been made virtual; this was necessary for LEDs within a group to properly hilite while being clicked
- Add addChoice() to cLedGroup to insert additional LED choices
- Moved the key enums and cKey to a separate file
- Add a method to get a control's attached key
- Add methods to get and set a control's rect and position
- Controls can now directly take a window as a parent rather than a dialog
- Add addLabelFor() method to cDialog which adds a static text control as a label for another control
- Remove hack for storing a dialog result of arbitrary type in favour of boost::any
- Add method to get default text colour for a dialog
- Add method to get a dialog's rect
- Add method to add the same event handler to multiple controls in a dialog
- Add concept of default button to dialogs
- Add enum for text field type (currently either number or text)
- Implement the text field without use of native controls, including somewhat decent text input and a flashing insertion point
- cPict no longer stores references to every sheet; it fetches them as needed from the resource manager
- The many draw functions in cPict are no longer static, since they need to access the window containing the pict (before they could only be static due to QuickDraw's global state)
- Add setPict() without a type argument to change the graphic without changing the type, which is a common operation
- Add a scrollbar control; the specifics aren't implemented yet
- Change signature of the record callback for cStrDlog; it will no longer be passed the strings
- Publicize the no-button constructor of cChoiceDlog; it'll assume "okay" is the only button
- Add operator-> to cPictChoice for accessing the underlying dialog
- Add constructor to cPictChoice that takes a starting and ending pic num
- Remove err parameter from giveError
- Many more keys handled, plus support for catching copy, paste, cut, and select all keyboard shortcuts
- Text input fields take priority, overriding any other keyboard shortcuts in the dialog, but they never catch help (F1), escape, or enter
- Some changes to the format itself:
-> keys go in the "def-key" attribute, but modifiers go in "key-mod"
-> "clickable" is no longer a recognized attribute
-> "title" is now a recognized text size (18pt, even larger than "large" at 12pt)
-> "defbtn" attribute on the root element
2014-04-14 13:52:01 -04:00

3141 lines
98 KiB
C++

#include <cmath>
//#include "item.h"
#include "boe.global.h"
#include "classes.h"
#include "boe.actions.h"
#include "boe.graphutil.h"
#include "boe.graphics.h"
#include "boe.townspec.h"
#include "boe.fileio.h"
#include "boe.dlgutil.h"
#include "boe.locutils.h"
#include "boe.fields.h"
#include "boe.town.h"
#include "boe.text.h"
#include "boe.party.h"
#include "boe.monster.h"
#include "boe.specials.h"
#include "boe.newgraph.h"
#include "boe.combat.h"
#include "boe.items.h"
#include "soundtool.h"
#include "boe.infodlg.h"
#include "boe.itemdata.h"
#include "boe.main.h"
#include "mathutil.h"
#include "fileio.h"
#include "dlogutil.h"
#include "dialog.h"
#include "scrollbar.h"
#include "boe.menus.h"
#include "winutil.h"
RECT bottom_buttons[7];
RECT town_buttons[10];
RECT combat_buttons[9];
RECT world_screen = {23, 23, 346, 274};
// TODO: The duplication of RECT here shouldn't be necessary...
RECT item_screen_button_rects[9] = {RECT{126,11,140,28},RECT{126,40,140,57},RECT{126,69,140,86},RECT{126,98,140,115},
RECT{126,127,140,144},RECT{126,156,140,173},RECT{126,176,141,211},
RECT{126,213,125,248},//// made rect disappear
RECT{127,251,139,267}};
RECT border_rect[4] = {RECT{5, 5, 15, 283}, RECT{5, 5, 355, 15},
RECT{345, 5, 355, 283}, RECT{5, 273, 355, 283}};
RECT medium_buttons[4] = {RECT{383,190,401,225}, RECT{402, 190, 420, 225},
RECT{383, 227, 401, 263}, RECT{402, 227,420, 263}}; ;
RECT item_buttons[8][6];
// name, use, give, drip, info, sell/id
RECT pc_buttons[6][5];
// name, hp, sp, info, trade
short num_chirps_played = 0;
extern RECT startup_button[6];
extern bool flushingInput;
bool ghost_mode;
RECT startup_top;
// For menu spell casting, some info needs to be stored up here.
short refer_mage[62] = {0,2,1,1,2,2,0,2,2,0, 2,2,2,2,1,2,2,2,2,2, 0,1,2,0,2,2,3,3,2,1,
2,2,1,0,2,2,3,2, 0,1,2,0,2,3,2,3, 2,1,2,3,2,2,2,0, 1,1,1,0,3,2,2,3};
short refer_priest[62] = {1,0,0,2,0,0,0,0,0,2, 1,0,2,0,2,2,0,2,3,0, 0,0,2,0,0,0,2,0,0,3,
0,1,2,0,3,0,0,0, 1,0,0,2,0,3,0,2, 0,0,0,0,2,1,1,1, 0,2,0,2,1,2,0,0};
// 0 - refer 1 - do in combat immed. 2 - need targeting 3 - need fancy targeting
short mage_need_select[62] = {0,0,1,1,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,1,0,0,0,0};
short priest_need_select[62] = {1,1,1,0,0,1,1,0,0,0, 1,1,0,0,0,0,0,0,0,1, 1,0,0,0,1,0,0,1,1,0,
0,0,0,1,0,1,1,0, 0,1,2,0,0,0,0,0, 0,1,0,2,0,0,0,0, 0,0,2,0,0,0,0,0};
// 0 - no select 1 - active only 2 - any existing
// TODO: The duplication of RECT here shouldn't be necessary...
word_rect_type preset_words[9] = {{"Look",RECT{366,4,386,54}},{"Name",RECT{366,70,386,130}},{"Job",RECT{366,136,386,186}},
{"Buy",RECT{389,4,409,54}},{"Sell",RECT{389,70,409,120}},{"Record",RECT{389,121,409,186}},
{"Done",RECT{389,210,409,270}},{"Go Back",RECT{366,190,386,270}},
{"Ask About...",RECT{343,4,363,134}}};
cItemRec start_items[6] = {cItemRec('nife'),cItemRec('buck'),cItemRec('bow '),cItemRec('arrw'),cItemRec('pole'),cItemRec('helm')};
bool item_area_button_active[8][6];
bool pc_area_button_active[6][5];
short item_bottom_button_active[9] = {0,0,0,0,0, 0,1,1,1};
bool unreg_party_in_scen_not_check = false;
RECT pc_help_button,pc_area_rect,item_area_rect;
short current_terrain_type = 0,num_out_moves = 0;
short door_pc,store_drop_item;
short current_switch = 6;
cOutdoors::cWandering store_wandering_special;
long dummy;
short store_shop_type;
short store_selling_values[8] = {0,0,0,0,0,0,0,0};
extern short cen_x, cen_y, stat_window,give_delays;//,pc_moves[6];
extern eGameMode overall_mode;
extern location to_create;
extern bool in_startup_mode,All_Done,play_sounds,frills_on,spell_forced,save_maps,monsters_going;
extern bool party_in_memory,in_scen_debug;
// game info globals
//extern stored_town_maps_type town_maps;
extern sf::RenderWindow mainPtr;
////extern party_record_type party;
//extern cOutdoors outdoors[2][2];
//extern current_town_type c_town;
//extern big_tr_type t_d;
//extern unsigned char out[96][96],out_e[96][96];
extern short which_item_page[6];
extern short /*town_size[3],*/store_spell_target,pc_last_cast[2][6],pc_casting,store_mage,store_priest;
//extern town_item_list t_i; // shouldn't be here
//extern unsigned char misc_i[64][64];
extern short spec_item_array[60];
extern cScenario scenario;
extern cUniverse univ;
//extern piles_of_stuff_dumping_type *data_store;
// combat globals
extern short which_combat_type,num_targets_left;
extern ter_num_t combat_terrain[64][64];
extern location center;
extern location pc_pos[6];
extern short current_pc,town_type;
extern short combat_active_pc,stat_screen_mode;
extern bool map_visible,diff_depth_ok;
extern sf::RenderWindow mini_map;
//extern stored_items_list_type stored_items[3];
//extern stored_outdoor_maps_type o_maps;
extern location ul;
extern std::shared_ptr<cScrollbar> text_sbar,item_sbar,shop_sbar;
extern short shop_identify_cost;
const char *dir_string[] = {"North", "NorthEast", "East", "SouthEast", "South", "SouthWest", "West", "NorthWest"};
char get_new_terrain();
cCreature save_monster_type;
short wand_loc_count = 0;
short monst_place_count = 0; // 1 - standard place 2 - place last
// 0 - whole area, 1 - active area 2 - graphic 3 - item name
// 4 - item cost 5 - item extra str 6 - item help button
RECT shopping_rects[8][7];
pending_special_type special_queue[20];
bool end_scenario = false;
void init_screen_locs() ////
{
short i,j,k,l;
RECT startup_base = {279,5,327,306};
RECT shop_base = {63,12,99,267};
for (i = 0; i < 7; i++)
shopping_rects[0][i] = shop_base;
shopping_rects[0][SHOPRECT_ACTIVE_AREA].right -= 35;
shopping_rects[0][SHOPRECT_GRAPHIC].right = shopping_rects[0][SHOPRECT_GRAPHIC].left + 28;
shopping_rects[0][SHOPRECT_ITEM_NAME].top += 4;
shopping_rects[0][SHOPRECT_ITEM_NAME].left += 28;
shopping_rects[0][SHOPRECT_ITEM_COST].top += 20;
shopping_rects[0][SHOPRECT_ITEM_COST].left += 154;
shopping_rects[0][SHOPRECT_ITEM_EXTRA].top += 20;
shopping_rects[0][SHOPRECT_ITEM_EXTRA].left += 34;
shopping_rects[0][SHOPRECT_ITEM_HELP].top += 3;
shopping_rects[0][SHOPRECT_ITEM_HELP].bottom -= 21;
shopping_rects[0][SHOPRECT_ITEM_HELP].right -= 19;
shopping_rects[0][SHOPRECT_ITEM_HELP].left = shopping_rects[0][SHOPRECT_ITEM_HELP].right - 14;
for (i = 1; i < 8; i++)
for (j = 0; j < 7; j++) {
shopping_rects[i][j] = shopping_rects[0][j];
shopping_rects[i][j].offset(0,i * 36);
}
for (i = 0; i < 6; i++) {
startup_button[i] = startup_base;
startup_button[i].offset(301 * (i / 3) - 18,48 * (i % 3));
}
startup_top.top = 5;
startup_top.bottom = startup_button[STARTBTN_LOAD].top;
startup_top.left = 5;
startup_top.right = startup_button[STARTBTN_JOIN].right;
for (i = 0; i < 200; i++)
for (j = 0; j < 8; j++)
for (k = 0; k < 64; k++)////
univ.town_maps[i][j][k] = 0;
for (i = 0; i < 100; i++)
for (k = 0; k < 6; k++)
for (l = 0; l < 48; l++)
univ.out_maps[i][k][l] = 0;
for (i = 0; i < 7; i++) {
bottom_buttons[i].top = 383;
bottom_buttons[i].bottom = 420;
bottom_buttons[i].left = 5 + (i * 37);
bottom_buttons[i].right = bottom_buttons[i].left + 36;
town_buttons[i] = bottom_buttons[i];
//FrameRect (&bottom_buttons[i]);
}
for (i = 0; i < 5; i++) {
combat_buttons[i] = bottom_buttons[i];
}
town_buttons[7] = bottom_buttons[6];
town_buttons[5] = medium_buttons[0];
town_buttons[6] = medium_buttons[1];
for (i = 5; i < 9; i++) {
combat_buttons[i] = medium_buttons[i - 5];
}
// name, use, give, drip, info, sell/id each one 13 down
item_buttons[0][ITEMBTN_NAME].top = 17;
item_buttons[0][ITEMBTN_NAME].bottom = item_buttons[0][ITEMBTN_NAME].top + 12;
item_buttons[0][ITEMBTN_NAME].left = 3;
item_buttons[0][ITEMBTN_NAME].right = item_buttons[0][ITEMBTN_NAME].left + 185;
item_buttons[0][ITEMBTN_USE] = item_buttons[0][0];
item_buttons[0][ITEMBTN_USE].left = 196;
item_buttons[0][ITEMBTN_USE].right = 210;
item_buttons[0][ITEMBTN_GIVE] = item_buttons[0][ITEMBTN_NAME];
item_buttons[0][ITEMBTN_GIVE].left = 210;
item_buttons[0][ITEMBTN_GIVE].right = 224;
item_buttons[0][ITEMBTN_DROP] = item_buttons[0][ITEMBTN_NAME];
item_buttons[0][ITEMBTN_DROP].left = 224;
item_buttons[0][ITEMBTN_DROP].right = 238;
item_buttons[0][ITEMBTN_INFO] = item_buttons[0][ITEMBTN_NAME];
item_buttons[0][ITEMBTN_INFO].left = 238;
item_buttons[0][ITEMBTN_INFO].right = 252;
item_buttons[0][ITEMBTN_SPEC] = item_buttons[0][ITEMBTN_NAME];
item_buttons[0][ITEMBTN_SPEC].left = 173;
item_buttons[0][ITEMBTN_SPEC].right = 232;
for (i = 1; i < 8; i++)
for (j = 0; j < 6; j++) {
item_buttons[i][j] = item_buttons[0][j];
item_buttons[i][j].offset(0,13 * i);
}
/* for (i = 0; i < 8; i++) {
item_screen_button_rects[i] = bottom_base;
OffsetRect(&item_screen_button_rects[i],10 + i * 29,126);
}
item_screen_button_rects[6].left = 176;
item_screen_button_rects[6].right = 211;
item_screen_button_rects[7].left = 213;
item_screen_button_rects[7].right = 248;
item_screen_button_rects[8].top = 127;
item_screen_button_rects[8].bottom = 140;
item_screen_button_rects[8].left = 251;
item_screen_button_rects[8].right = 267; */
// name, hp, sp, info, trade
pc_buttons[0][PCBTN_NAME].top = 18;
pc_buttons[0][PCBTN_NAME].bottom = pc_buttons[0][PCBTN_NAME].top + 12;
pc_buttons[0][PCBTN_NAME].left = 3;
pc_buttons[0][PCBTN_NAME].right = pc_buttons[0][PCBTN_NAME].left + 177;
pc_buttons[0][PCBTN_HP] = pc_buttons[0][PCBTN_NAME];
pc_buttons[0][PCBTN_HP].left = 184;
pc_buttons[0][PCBTN_HP].right = 214;
pc_buttons[0][PCBTN_SP] = pc_buttons[0][PCBTN_NAME];
pc_buttons[0][PCBTN_SP].left = 214;
pc_buttons[0][PCBTN_SP].right = 237;
pc_buttons[0][PCBTN_INFO] = pc_buttons[0][PCBTN_NAME];
pc_buttons[0][PCBTN_INFO].left = 241;
pc_buttons[0][PCBTN_INFO].right = 253;
pc_buttons[0][PCBTN_TRADE] = pc_buttons[0][PCBTN_NAME];
pc_buttons[0][PCBTN_TRADE].left = 253;
pc_buttons[0][PCBTN_TRADE].right = 262;
for (i = 1; i < 6; i++)
for (j = 0; j < 5; j++) {
pc_buttons[i][j] = pc_buttons[0][j];
pc_buttons[i][j].offset(0,13 * i);
}
pc_help_button.top = 101;
pc_help_button.bottom = 114;
pc_help_button.left = 251;
pc_help_button.right = 267;
pc_area_rect.top = PC_WIN_UL_Y;
pc_area_rect.left = PC_WIN_UL_X;
pc_area_rect.bottom = PC_WIN_UL_Y + 116;
pc_area_rect.right = PC_WIN_UL_X + 271;
item_area_rect.top = ITEM_WIN_UL_Y;
item_area_rect.left = ITEM_WIN_UL_X;
item_area_rect.bottom = ITEM_WIN_UL_Y + 143;
item_area_rect.right = ITEM_WIN_UL_X + 271;
}
bool prime_time()
{
if ((overall_mode < MODE_TALK_TOWN) || (overall_mode == MODE_COMBAT))
return true;
return false;
}
bool handle_action(sf::Event event)
{
short i,j,k,item_hit,which_t,s1,s2,s3;
bool are_done = false;
bool need_redraw = false, did_something = false, need_reprint = false;
bool town_move_done = false,pc_delayed = false;
short storage;
location destination,cur_loc,loc_in_sec,cur_direction;
unsigned char debug_storage;
short find_direction_from,ter_looked_at,button_hit = 12,store_cur_pc;
short store_sp[6];
ter_num_t ter;
char str[60];
location the_point,point_in_area;
debug_storage = univ.party.spec_items[1];
the_point = location(event.mouseButton.x, event.mouseButton.y);
the_point.x -= ul.x;
the_point.y -= ul.y;
for (i = 0; i < 20; i++) // TODO: Does this cause problems by leaving some specials uncalled?
special_queue[i].spec = -1;
end_scenario = false;
if (unreg_party_in_scen_not_check == true) {
if (/*enter_password() == */false) {
end_scenario = true;
}
else {
in_scen_debug = true;
ASB("Debug mode ON.");
}
unreg_party_in_scen_not_check = false;
}
// Now split off the extra stuff, like talking and shopping.
if (overall_mode == MODE_TALKING) {
handle_talk_event(the_point);
if (overall_mode != MODE_TALKING)
return false;
}
if (overall_mode == MODE_SHOPPING) {
handle_shop_event(the_point);
if (overall_mode != MODE_SHOPPING)
return false;
}
num_chirps_played = 0;
// MARK: First, figure out where party is
switch (overall_mode) {
case MODE_OUTDOORS: case MODE_LOOK_OUTDOORS:
cur_loc = univ.party.p_loc;
for (i = 0; i < 7; i++)
if(the_point.in(bottom_buttons[i])) {
button_hit = i;
if (spell_forced == false)
main_button_click(overall_mode,bottom_buttons[i]);
}
break;
case MODE_TOWN: case MODE_TALK_TOWN: case MODE_USE_TOWN: case MODE_LOOK_TOWN: case MODE_DROP_TOWN:
// I think 5 is "town drop"
// cur_loc = c_town.p_loc;
cur_loc = center;
for (i = 0; i < 8; i++)
if(the_point.in(town_buttons[i])) {
button_hit = i;
if (spell_forced == false)
main_button_click(overall_mode,town_buttons[i]);
}
break;
case MODE_TALKING: case MODE_SHOPPING: break;
case MODE_TOWN_TARGET: case MODE_COMBAT: case MODE_SPELL_TARGET: case MODE_FIRING: case MODE_THROWING:
case MODE_FANCY_TARGET: case MODE_DROP_COMBAT: case MODE_LOOK_COMBAT:
cur_loc = (overall_mode > MODE_COMBAT) ? center : pc_pos[current_pc];
for (i = 0; i < 9; i++)
if(the_point.in(combat_buttons[i])) {
button_hit = i;
if (spell_forced == false)
main_button_click(overall_mode,combat_buttons[i]);
}
break;
default:
// either resting or startup; do nothing
// TODO: A call to handle_startup_action() would make sense here, though
break;
}
// MARK: Then, handle a button being hit.
if (button_hit != 12)
switch(button_hit)
{
case 0: case 1:
if (someone_awake() == false) {
ASB("Everyone's asleep/paralyzed.");
need_reprint = true;
need_redraw = true;
}
if (overall_mode == MODE_OUTDOORS) {
cast_spell(button_hit,0);
spell_forced = false;
need_reprint = true;
need_redraw = true;
}
else if (overall_mode == MODE_TOWN) {
for (i = 0; i < 6; i++)
store_sp[i] = univ.party[i].cur_sp;
cast_spell(button_hit,1);
spell_forced = false;
need_reprint = true;
need_redraw = true;
for (i = 0; i < 6; i++)
if (store_sp[i] != univ.party[i].cur_sp)
did_something = true;
}
else if (overall_mode == MODE_TOWN_TARGET) {
add_string_to_buf(" Cancelled. ");
overall_mode = MODE_TOWN;
}
else if (overall_mode >= MODE_COMBAT) {
if ((overall_mode == MODE_COMBAT) && (button_hit == 0)) {
did_something = combat_cast_mage_spell();
need_reprint = true;
}
if ((overall_mode == MODE_COMBAT) && (button_hit == 1)) {
did_something = combat_cast_priest_spell();
need_reprint = true;
}
if ((overall_mode != MODE_SPELL_TARGET) && (overall_mode != MODE_FANCY_TARGET)) {
need_redraw = true;
}
else did_something = false;
spell_forced = false;
redraw_terrain();
}
else if ((overall_mode == MODE_SPELL_TARGET) || (overall_mode == MODE_FANCY_TARGET)) {
add_string_to_buf(" Cancelled. ");
overall_mode = MODE_COMBAT;
center = pc_pos[current_pc];
pause(10);
need_redraw = true;
}
put_pc_screen();
put_item_screen(stat_window,0);
break;
case 2:
if (overall_mode == MODE_OUTDOORS) {
overall_mode = MODE_LOOK_OUTDOORS;
add_string_to_buf("Look: Select a space. Option-click ");
add_string_to_buf(" to look more than once.");
need_redraw = true;
}
if (overall_mode == MODE_TOWN) {
overall_mode = MODE_LOOK_TOWN;
add_string_to_buf("Look: Select a space. Option-click ");
add_string_to_buf(" to look more than once.");
need_redraw = true;
}
if (overall_mode == MODE_COMBAT) {
overall_mode = MODE_LOOK_COMBAT;
add_string_to_buf("Look: Select a space. Option-click ");
add_string_to_buf(" to look more than once.");
need_redraw = true;
}
break;
case 3:
if (overall_mode == MODE_COMBAT) {
add_string_to_buf("Parry. ");
char_parry();
did_something = true;
need_reprint = true;
need_redraw = true;
}
if (overall_mode == MODE_TOWN) {
overall_mode = MODE_TALK_TOWN;
add_string_to_buf("Talk: Select someone ");
need_reprint = true;
}
if (overall_mode == MODE_OUTDOORS) { // Resting
i = 0;
ter = univ.out[univ.party.p_loc.x][univ.party.p_loc.y];
if (univ.party.in_boat >= 0)////
add_string_to_buf("Rest: Not in boat. ");
else if (someone_poisoned() == true)
add_string_to_buf("Rest: Someone poisoned. ");
else if (univ.party.food <= 12)
add_string_to_buf("Rest: Not enough food. ");
else if (nearest_monster() <= 3)
add_string_to_buf("Rest: Monster too close. ");
else if ((scenario.ter_types[ter].special == TER_SPEC_DAMAGING) || (scenario.ter_types[ter].special == TER_SPEC_DANGEROUS))
add_string_to_buf("Rest: It's dangerous here.");////
else if (flying() == true)
add_string_to_buf("Rest: Not while flying. ");
else {
add_string_to_buf("Resting... ");
print_buf();
play_sound(20);
draw_rest_screen();
pause(25);
univ.party.food -= 6;
while (i < 50) {
increase_age();
j = get_ran(1,1,2);
if (j == 2)
do_monsters();
j = get_ran(1,1,70);
if (j == 10)
create_wand_monst();
if (nearest_monster() <= 3) {
i = 200;
add_string_to_buf(" Monsters nearby.");
}
else i++;
}
put_pc_screen();
}
if (i == 50) {
univ.party.age += 1200;////
add_string_to_buf(" Rest successful. ");
k = get_ran(5,1,10);
heal_party(k);
restore_sp_party(50);
put_pc_screen();
}
need_reprint = true;
need_redraw = true;
}
break;
case 4:
if (overall_mode == MODE_OUTDOORS) {
give_help(62,0);
display_map();
make_cursor_sword();
}
if ((overall_mode == MODE_TOWN) || (overall_mode == MODE_COMBAT)) {
if (univ.party.in_boat >= 0) {////
j = 0;
add_string_to_buf("Get: Not while in boat. ");
}
if (overall_mode == MODE_TOWN)
j = get_item(univ.town.p_loc,6,false);
else {
j = get_item(pc_pos[current_pc],current_pc,false);
take_ap(4);
}
if (j > 0) {
put_item_screen(stat_window, 0);
put_pc_screen();
need_redraw = true;
did_something = true;
}
need_reprint = true;
}
break;
case 5:
if (overall_mode == MODE_OUTDOORS) {
save_party(univ.file);
need_redraw = true;
current_switch = 6;
break;
}
if (overall_mode == MODE_TOWN) {
add_string_to_buf("Use: Select a space or item.");
add_string_to_buf(" (Hit button again to cancel.)");
need_reprint = true;
overall_mode = MODE_USE_TOWN;
}
else if (overall_mode == MODE_USE_TOWN) {
overall_mode = MODE_TOWN;
need_reprint = true;
add_string_to_buf(" Cancelled.");
}
if (overall_mode == MODE_COMBAT) {
need_reprint = true;
need_redraw = true;
pc_delayed = true;
}
break;
case 6:
if (overall_mode == MODE_OUTDOORS) {
do_load();
break;
}
if (overall_mode == MODE_TOWN) {
give_help(62,0);
display_map();
make_cursor_sword();
}
if (overall_mode == MODE_COMBAT) {
load_missile();
need_reprint = true;
redraw_terrain();
}
else if ((overall_mode == MODE_FIRING) || (overall_mode == MODE_THROWING)) {
add_string_to_buf(" Cancelled. ");
center = pc_pos[current_pc];
pause(10);
need_redraw = true;
overall_mode = MODE_COMBAT;
}
break;
case 7:
if (overall_mode == MODE_TOWN) {
if (univ.party.in_boat >= 0) {////
need_reprint = true;
add_string_to_buf("Combat: Not while in boat. ");
}
else if (univ.party.in_horse >= 0) {
need_reprint = true;
add_string_to_buf("Combat: Not while on horseback. ");
}
else {
add_string_to_buf("Combat! ");
play_sound(18);
need_reprint = true;
start_town_combat(univ.party.direction);
need_redraw = true;
current_pc = 6;
did_something = true;
put_pc_screen();
}
}
else if (overall_mode == MODE_COMBAT) {
if (which_combat_type == 0) {
if (hit_end_c_button() == true) {
end_town_mode(0,univ.town.p_loc);
play_sound(93);
add_string_to_buf("End combat. ");
handle_wandering_specials(0,1);
menu_activate();
put_pc_screen();
set_stat_window(current_pc);
}
else add_string_to_buf("Can't end combat yet. ");
}
else {
univ.party.direction = end_town_combat();
center = univ.town.p_loc;
//put_pc_screen();
set_stat_window(current_pc);
redraw_screen();
play_sound(93);
need_reprint = true;
need_redraw = true;
did_something = true;
menu_activate();
}
need_redraw = true;
}
break;
case 8:
if (overall_mode == MODE_COMBAT) {
if (combat_active_pc == 6) {
add_string_to_buf("This PC now active. ");
combat_active_pc = current_pc;
}
else {
add_string_to_buf("All PC's now active. ");
current_pc = combat_active_pc;
combat_active_pc = 6;
}
need_reprint = true;
}
break;
}
/* if (overall_mode == 30) /// I don't know what this is for.
if (PtInRect(the_point, &text_panel_rect)) {
through_sending();
restore_mode();
print_buf();
} */
// MARK: Begin : click in terrain
if ((the_point.in(world_screen)) && ((is_out()) || (is_town()) || (is_combat())) ){
i = (the_point.x - 23) / 28;
j = (the_point.y - 23) / 36;
destination = cur_loc;
if ((overall_mode == MODE_OUTDOORS) || (overall_mode == MODE_TOWN) || (overall_mode == MODE_COMBAT))
if ((i == 4) & (j == 4)) { // Pausing
if (overall_mode == MODE_COMBAT) {
char_stand_ready();
add_string_to_buf("Stand ready. ");
if (univ.party[current_pc].status[6] > 0) {
add_string_to_buf("You clean webs. ");
univ.party[current_pc].status[6] = move_to_zero(univ.party[current_pc].status[6]);
univ.party[current_pc].status[6] = move_to_zero(univ.party[current_pc].status[6]);
put_pc_screen();
}
check_fields(pc_pos[current_pc],2,current_pc);
}
else {
add_string_to_buf("Pause.");
for (k = 0; k < 6; k++)
if ((univ.party[k].main_status == 1) && (univ.party[k].status[6] > 0)) {
sprintf((char *) str,"%s cleans webs.",univ.party[k].name.c_str());
add_string_to_buf((char *) str);
univ.party[k].status[6] = move_to_zero(univ.party[k].status[6]);
univ.party[k].status[6] = move_to_zero(univ.party[k].status[6]);
}
if (univ.party.in_horse >= 0) {
if (overall_mode == MODE_OUTDOORS) {
univ.party.horses[univ.party.in_horse].which_town = 200;
univ.party.horses[univ.party.in_horse].loc_in_sec = global_to_local(univ.party.p_loc);
univ.party.horses[univ.party.in_horse].loc = univ.party.p_loc;
univ.party.horses[univ.party.in_horse].sector.x = univ.party.outdoor_corner.x + univ.party.i_w_c.x;
univ.party.horses[univ.party.in_horse].sector.y = univ.party.outdoor_corner.y + univ.party.i_w_c.y;
univ.party.in_horse = -1;
}
else if (overall_mode == MODE_TOWN){
univ.party.horses[univ.party.in_horse].loc = univ.town.p_loc;
univ.party.horses[univ.party.in_horse].which_town = univ.town.num;
univ.party.in_horse = -1;
}
}
put_pc_screen();
check_fields(univ.town.p_loc,1,0);
}
did_something = true;
need_redraw = true;
}
else {
cur_direction = get_cur_direction(the_point);
destination.x += cur_direction.x;
destination.y += cur_direction.y;
// for (i = 0; i < 6; i++) // debug
// if (univ.party[i].exp_adj != 100) {
// ASB("Error: Flag 1");
// }
// MARK: Begin: Moving
if (overall_mode == MODE_COMBAT) {
if (pc_combat_move(destination) == true) {
center = pc_pos[current_pc];
did_something = true;
update_explored(destination);
}
need_redraw = true;
menu_activate();
}
if (overall_mode == MODE_TOWN) {
if (someone_awake() == false) {
ASB("Everyone's asleep/paralyzed.");
need_reprint = true;
need_redraw = true;
}
else {
need_redraw = true;
if (town_move_party(destination,0) == true) {
did_something = true;
center = univ.town.p_loc;
update_explored(destination);
if (loc_off_act_area(univ.town.p_loc) == true) {
destination = end_town_mode(0,destination);
town_move_done = true;
flushingInput = true;
}
}
else need_reprint = true;
menu_activate();
}
}
if (overall_mode == MODE_OUTDOORS) {
if (outd_move_party(destination,town_move_done) == true) {
center = destination;
need_redraw = true;
did_something = true;
update_explored(univ.party.p_loc);
menu_activate();
}
else need_redraw = true;
storage = univ.out[univ.party.p_loc.x][univ.party.p_loc.y];
if (scenario.ter_types[storage].special == TER_SPEC_TOWN_ENTRANCE) {//// town entry
if (univ.party.direction == 0) find_direction_from = 2;
else if (univ.party.direction == 4) find_direction_from = 0;
else if (univ.party.direction < 4) find_direction_from = 3;
else find_direction_from = 1;
for (i = 0; i < 8; i++)
if (univ.party.loc_in_sec == univ.out.outdoors[univ.party.i_w_c.x][univ.party.i_w_c.y].exit_locs[i]) {
which_t = univ.out.outdoors[univ.party.i_w_c.x][univ.party.i_w_c.y].exit_dests[i];
if (which_t >= 0)
start_town_mode(univ.out.outdoors[univ.party.i_w_c.x][univ.party.i_w_c.y].exit_dests[i], find_direction_from);
if (is_town() == true) {
need_redraw = false;
i = 8;
if (univ.party.in_boat >= 0)
univ.party.boats[univ.party.in_boat].which_town = univ.town.num;
if (univ.party.in_horse >= 0)
univ.party.horses[univ.party.in_horse].which_town = univ.town.num;
}
}
}
} // End if(overall_mode == MODE_OUTDOORS)
}
// MARK: End: Moving
// MARK: Begin: Looking at something
if ((overall_mode == MODE_LOOK_OUTDOORS) || (overall_mode == MODE_LOOK_TOWN) || (overall_mode == MODE_LOOK_COMBAT)) {
destination.x = destination.x + i - 4;
destination.y = destination.y + j - 4;
need_reprint = true;
// if ((can_see(cur_loc,destination) >= 4) || ((overall_mode != 35) && (loc_off_world(destination) == true)))
if ((overall_mode != MODE_LOOK_COMBAT) && (party_can_see(destination) == 6))
add_string_to_buf(" Can't see space. ");
else if ((overall_mode == MODE_LOOK_COMBAT) && (can_see(pc_pos[current_pc],destination,0) >= 4))
add_string_to_buf(" Can't see space. ");
else {
add_string_to_buf("You see... ");
ter_looked_at = do_look(destination);
if ((overall_mode == MODE_LOOK_TOWN) || (overall_mode == MODE_LOOK_COMBAT))
if (adjacent(univ.town.p_loc,destination) == true)
if (adj_town_look(destination) == true)
need_redraw = true;
if (is_sign(ter_looked_at)) {
print_buf();
need_reprint = false;
k = 0;
if (overall_mode == MODE_LOOK_TOWN) {
while (k < 15) {
if (destination == univ.town->sign_locs[k]) {
need_reprint = true;
if (adjacent(univ.town->sign_locs[k],univ.town.p_loc)==true)
do_sign(univ.town.num,k,(short) ter_looked_at,destination);
else add_string_to_buf(" Too far away to read sign. ");
}
k++;
}
}
if (overall_mode == MODE_LOOK_OUTDOORS) {
loc_in_sec = univ.party.loc_in_sec;
loc_in_sec.x += i - 4;
loc_in_sec.y += j - 4;
while (k < 8) {
if (loc_in_sec == univ.out.outdoors[univ.party.i_w_c.x][univ.party.i_w_c.y].sign_locs[k]) {
need_reprint = true;
if (adjacent(univ.out.outdoors[univ.party.i_w_c.x][univ.party.i_w_c.y].sign_locs[k],univ.party.loc_in_sec)==true)
do_sign((short) (200 + get_outdoor_num()),k,(short) ter_looked_at,destination);
else add_string_to_buf(" Too far away to read sign. ");
}
k++;
}
}
}
}
// sprintf(store_str," Mod: %d",event.modifiers);
// add_string_to_buf(store_str);
// If option not pressed, looking done, so restore center
if(!sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt) && !sf::Keyboard::isKeyPressed(sf::Keyboard::RAlt)) {
if (overall_mode == MODE_LOOK_COMBAT) {
overall_mode = MODE_COMBAT;
center = pc_pos[current_pc];
pause(5);
need_redraw = true;
}
else if (overall_mode == MODE_LOOK_TOWN) {
overall_mode = MODE_TOWN;
center = univ.town.p_loc;
need_redraw = true;
}
else if (overall_mode == MODE_LOOK_OUTDOORS)
overall_mode = MODE_OUTDOORS;
}
}
// MARK: End: looking at something
// MARK: Begin : talking to someone
if (overall_mode == MODE_TALK_TOWN) {
destination.x = destination.x + i - 4;
destination.y = destination.y + j - 4;
if ((can_see(cur_loc,destination,0) >= 4) || (loc_off_world(destination) == true)) {
add_string_to_buf(" Can't see space ");
need_reprint = true;
}
else {
for (i = 0; i < univ.town->max_monst(); i++) {
if (monst_on_space(destination,i) == true) {
did_something = true;
need_redraw = true;
if (univ.town.monst[i].attitude % 2 == 1) {
add_string_to_buf(" Creature is hostile. ");
}
else if ((univ.town.monst[i].summoned > 0)////
|| (univ.town.monst[i].personality < 0))
add_string_to_buf("Talk: No response. ");
else {
start_talk_mode(i,univ.town.monst[i].personality,univ.town.monst[i].number,
univ.town.monst[i].facial_pic);
did_something = false;
need_redraw = false;
break;
}
}
}
if ((did_something == false) && (overall_mode != MODE_TALKING)){
add_string_to_buf(" Nobody there");
need_reprint = true;
}
if (overall_mode != MODE_TALKING)
overall_mode = MODE_TOWN;
}
if (overall_mode != MODE_TALKING)
need_redraw = true;
}
// MARK: End : talking to someone
// MARK: Begin : Targeting a space
if ((overall_mode == MODE_SPELL_TARGET) || (overall_mode == MODE_FIRING) || (overall_mode == MODE_THROWING) ||
(overall_mode == MODE_FANCY_TARGET) || (overall_mode == MODE_DROP_COMBAT)) {
destination.x = destination.x + i - 4;
destination.y = destination.y + j - 4;
if (overall_mode == MODE_SPELL_TARGET)
do_combat_cast(destination);
if ((overall_mode == MODE_THROWING) || (overall_mode == MODE_FIRING))
fire_missile(destination);
if (overall_mode == MODE_FANCY_TARGET) {
place_target(destination);
need_reprint = true;
}
if (overall_mode != MODE_FANCY_TARGET) {
did_something = true;
center = pc_pos[current_pc];
}
if (overall_mode == MODE_DROP_COMBAT) { // dropping
if (adjacent(pc_pos[current_pc],destination) == false)
add_string_to_buf("Drop: must be adjacent.");
else {
drop_item(current_pc,store_drop_item,destination);
take_ap(1);
}
}
pause(6);
need_redraw = true;
if ((overall_mode >= MODE_COMBAT) && (overall_mode < MODE_TALKING) && (overall_mode != MODE_FANCY_TARGET))
overall_mode = MODE_COMBAT;
put_pc_screen();
put_item_screen(stat_window,0);
}
if ((overall_mode > MODE_TALK_TOWN) && (overall_mode < MODE_COMBAT/*6*/)) {
destination.x = destination.x + i - 4;
destination.y = destination.y + j - 4;
if (overall_mode == MODE_TOWN_TARGET) {
cast_town_spell(destination);
did_something = true;
}else if(overall_mode == MODE_USE_TOWN) {
if (adjacent(destination,univ.town.p_loc) == false)
add_string_to_buf(" Must be adjacent. ");
else
did_something = use_space(destination);
}else if(overall_mode == MODE_DROP_TOWN) {
if (adjacent(univ.town.p_loc,destination) == false)
add_string_to_buf("Drop: must be adjacent.");
else if (get_obscurity(destination.x,destination.y) == 5)
ASB("Drop: Space is blocked.");
else drop_item(current_pc,store_drop_item,destination);
}
overall_mode = MODE_TOWN;
need_redraw = true;
put_pc_screen();
put_item_screen(stat_window,0);
}
// MARK: End : Targeting a space
}
// MARK: End: click in terrain
// MARK: Begin: Screen shift
if ((overall_mode == MODE_SPELL_TARGET) || (overall_mode == MODE_FIRING) || (overall_mode == MODE_THROWING) || (overall_mode == MODE_FANCY_TARGET)
|| (overall_mode == MODE_LOOK_COMBAT) || (overall_mode == MODE_LOOK_TOWN)) {
if ((the_point.in(border_rect[0])) && (center.y > univ.town->in_town_rect.top)
&& (center.y > 4)) {
center.y--;
need_redraw = true;
}
if ((the_point.in(border_rect[1])) && (center.x > univ.town->in_town_rect.left)
&& (center.x > 4)) {
center.x--;
need_redraw = true;
}
if ((the_point.in(border_rect[2])) && (center.y < univ.town->in_town_rect.bottom)
&& (center.y < univ.town->max_dim() - 5)) {
center.y++;
need_redraw = true;
}
if ((the_point.in(border_rect[3])) && (center.x < univ.town->in_town_rect.right)
&& (center.x < univ.town->max_dim() - 5)) {
center.x++;
need_redraw = true;
}
}
// MARK: End: Screen shift
// MARK: Process clicks in PC stats area
if (the_point.in(pc_area_rect)) {
point_in_area = the_point;
point_in_area.x -= PC_WIN_UL_X;
point_in_area.y -= PC_WIN_UL_Y;
if (point_in_area.in(pc_help_button)) {
pc_help_button.offset(PC_WIN_UL_X,PC_WIN_UL_Y);
arrow_button_click(pc_help_button);
pc_help_button.offset(-PC_WIN_UL_X,-PC_WIN_UL_Y);
cChoiceDlog("help-party").show();
}
for (i = 0; i < 6; i++)
for (j = 0; j < 5; j++)
if((pc_area_button_active[i][j] > 0) && (point_in_area.in(pc_buttons[i][j]))) {
pc_buttons[i][j].offset(PC_WIN_UL_X,PC_WIN_UL_Y);
arrow_button_click(pc_buttons[i][j]);
pc_buttons[i][j].offset(-PC_WIN_UL_X,-PC_WIN_UL_Y);
switch (j) {
case 0:
if ((prime_time() == false) && (overall_mode != MODE_SHOPPING)&& (overall_mode != MODE_TALKING))
add_string_to_buf("Set active: Finish what you're doing first.");
else if (is_combat())
add_string_to_buf("Set active: Can't set this in combat.");
else if ((univ.party[i].main_status != 1) &&
((overall_mode != MODE_SHOPPING) || (store_shop_type != 3)))
add_string_to_buf("Set active: PC must be here & active.");
else {
current_pc = i;
set_stat_window (i);
if (overall_mode == MODE_SHOPPING)
sprintf((char *) str,"Now shopping: %s",univ.party[i].name.c_str());
else sprintf((char *) str,"Now active: %s",univ.party[i].name.c_str());
add_string_to_buf((char *)str);
adjust_spell_menus();
}
break;
case 1:
sprintf((char *) str,"%s has %d health out of %d.",univ.party[i].name.c_str(),
univ.party[i].cur_health,univ.party[i].max_health);
add_string_to_buf((char *)str);
break;
case 2:
sprintf((char *) str,"%s has %d spell pts. out of %d.",univ.party[i].name.c_str(),
univ.party[i].cur_sp,univ.party[i].max_sp);
add_string_to_buf((char *)str);
break;
case 3: // pc info
give_pc_info(i);
break;
case 4: // trade places
if (prime_time() == false)
add_string_to_buf("Trade places: Finish what you're doing first.");
else if (is_combat())
add_string_to_buf("Trade places: Can't do this in combat.");
else {
switch_pc(i);
}
break;
}
}
need_reprint = true;
put_pc_screen();
put_item_screen(stat_window,0);
if (overall_mode == MODE_SHOPPING) {
set_up_shop_array();
draw_shop_graphics(0,pc_buttons[0][0]);
}
}
// Process clicks in item stats area
if (the_point.in(item_area_rect)) {
point_in_area = the_point;
point_in_area.x -= ITEM_WIN_UL_X;
point_in_area.y -= ITEM_WIN_UL_Y;
for (i = 0; i < 9; i++)
if ((item_bottom_button_active[i] > 0) && (point_in_area.in(item_screen_button_rects[i]))) {
item_screen_button_rects[i].offset(ITEM_WIN_UL_X,ITEM_WIN_UL_Y);
arrow_button_click(item_screen_button_rects[i]);
item_screen_button_rects[i].offset(-ITEM_WIN_UL_X,-ITEM_WIN_UL_Y);
switch (i) {
case 0: case 1: case 2: case 3: case 4: case 5:
if ((prime_time() == false) && (overall_mode != MODE_TALKING) && (overall_mode != MODE_SHOPPING))
add_string_to_buf("Set active: Finish what you're doing first.");
else {
if (!(is_combat())) {
if ((univ.party[i].main_status != 1) &&
((overall_mode != MODE_SHOPPING) || (store_shop_type != 12)))
add_string_to_buf("Set active: PC must be here & active.");
else {
current_pc = i;
sprintf((char *) str,"Now active: %s",univ.party[i].name.c_str());
add_string_to_buf((char *)str);
adjust_spell_menus();
}
}
set_stat_window(i);
if (overall_mode == MODE_SHOPPING) {
set_up_shop_array();
draw_shop_graphics(0,item_screen_button_rects[i]); // rect is dummy
}
}
break;
case 6: // special screen
give_help(50,0);
set_stat_window(6);
break;
case 8: // help
cChoiceDlog("help-inventory.xml").show();
break;
}
}
if (stat_window < 7) {
for (i = 0; i < 8; i++)
for (j = 0; j < 6; j++)
if((item_area_button_active[i][j] > 0) && (point_in_area.in(item_buttons[i][j]))) {
item_buttons[i][j].offset(ITEM_WIN_UL_X,ITEM_WIN_UL_Y);
arrow_button_click(item_buttons[i][j]);
item_buttons[i][j].offset(-ITEM_WIN_UL_X,-ITEM_WIN_UL_Y);
item_hit = item_sbar->getPosition() + i;
if ((prime_time() == false) && (j < 4)
&& ((j > 0) || (stat_screen_mode < 2)))
add_string_to_buf("Item action: Finish what you're doing first.");
else switch (j) {
case 0: // equip
if (overall_mode == MODE_USE_TOWN) {
add_string_to_buf("Note: Clicking 'U' button by item");
add_string_to_buf(" uses the item.");
use_item(stat_window, item_hit);
overall_mode = MODE_TOWN;
take_ap(3);
}
else if (prime_time() == true) {
equip_item(stat_window, item_hit);
take_ap(1);
}
break;
case 1: // use
use_item(stat_window, item_hit);
if ((overall_mode != MODE_TOWN_TARGET) && (overall_mode != MODE_SPELL_TARGET))
did_something = true;
take_ap(3);
break;
case 2: // give
give_thing(stat_window, item_hit);
did_something = true;
take_ap(1);
break;
case 3: // drop
if (stat_window == 6){
use_spec_item(spec_item_array[item_hit]);
need_redraw = true;////
}
else if (is_out())
drop_item(stat_window,item_hit,univ.party.p_loc);
else {
add_string_to_buf("Drop item: Click where to drop item.");
store_drop_item = item_hit;
overall_mode = (is_town()) ? MODE_DROP_TOWN : MODE_DROP_COMBAT;
}
break;
case 4: // info
if (stat_window == 6)
put_spec_item_info(spec_item_array[item_hit]);
else display_pc_item(stat_window, item_hit,univ.party[stat_window].items[item_hit],0);
break;
case 5: // sell? That this codes was reached indicates that the item was sellable
switch (stat_screen_mode) {
case 2: // identify item
if (take_gold(shop_identify_cost,false) == false)
ASB("Identify: You don't have the gold.");
else {
play_sound(68);
ASB("Your item is identified.");
univ.party[stat_window].items[item_hit].ident = true;
}
break;
case 3: case 4: case 5: // various selling
play_sound(-39);
univ.party.gold += store_selling_values[i];
ASB("You sell your item.");
take_item(stat_window,item_hit);
break;
case 6: // enchant item
if (take_gold(store_selling_values[i],false) == false)
ASB("Enchant: You don't have the gold.");
else {
play_sound(51);
ASB("Your item is now enchanted.");
enchant_weapon(stat_window,item_hit,shop_identify_cost,store_selling_values[i]);
}
break;
}
break;
}
}
}
put_pc_screen();
put_item_screen(stat_window,0);
need_reprint = true;
}
// MARK: Alchemy
if (the_point.x == 1000) {
need_reprint = true;
need_redraw = true;
if (overall_mode == MODE_TOWN) {
do_alchemy();
}
else add_string_to_buf("Alchemy: Only in town.");
}
// MARK: Wait 40 spaces (town only)
if (the_point.x == 1001) {
need_reprint = true;
need_redraw = true;
if (party_sees_a_monst() == true)
add_string_to_buf("Long wait: Monster in sight.");
else {
add_string_to_buf("Long wait... ");
print_buf();
play_sound(-20);
draw_rest_screen();
pause(10);
for (i = 0; i < 6; i++) {
store_sp[i] = univ.party[i].cur_health;
univ.party[i].status[6] = 0;
}
}
i = 0;
while ((i < 80) && (party_sees_a_monst() == false)){
increase_age();
do_monsters();
do_monster_turn();
j = get_ran(1,1,160 - univ.town.difficulty);
if (j == 10)
create_wand_monst();
for (j = 0; j < 6; j++)
if (univ.party[j].cur_health < store_sp[j]) {
i = 200;
j = 6;
add_string_to_buf(" Waiting interrupted.");
}
if (party_sees_a_monst() == true) {
i = 200;
add_string_to_buf(" Monster sighted!");
}
else i++;
}
put_pc_screen();
}
// MARK: If in combat and pc delayed, jump forward a step
if (pc_delayed == true) {
draw_terrain();
//pause(2);
current_pc++;
combat_next_step();
set_stat_window(current_pc);
put_pc_screen();
}
// MARK: At this point, see if any specials have been queued up, and deal with them
for (i = 0; i < 20; i++)
if (special_queue[i].spec >= 0) {
long long store_time = univ.party.age;
univ.party.age = special_queue[i].trigger_time;
s3 = 0;
run_special(special_queue[i].mode,special_queue[i].type,special_queue[i].spec,
special_queue[i].where,&s1,&s2,&s3);
special_queue[i].spec = -1;
long long change_time = univ.party.age - special_queue[i].trigger_time;
univ.party.age = store_time + change_time;
if (s3 > 0)
draw_terrain();
}
// MARK: Handle non-PC stuff (like monsters) if the party actually did something
if (did_something == true) {
draw_map(mini_map,5);
play_ambient_sound();
if ((overall_mode >= MODE_COMBAT) && (overall_mode < MODE_TALKING)) {
if (no_pcs_left() == true) {
end_combat();
if (which_combat_type == 0) {
end_town_mode(0,univ.party.p_loc);
add_string_to_buf("Fled the combat. ");
handle_wandering_specials(0,2);
}
}
else {
if (need_redraw == true) {
draw_terrain();
if ((combat_active_pc == 6) || (univ.party[combat_active_pc].ap > 0))
need_redraw = false;
}
//pause(2);
store_cur_pc = current_pc;
if (combat_next_step() == true)
need_redraw = true;
/* if ((store_cur_pc != current_pc) && (combat_active_pc == 6)) {
// need_reprint = true;
need_redraw = true;
} */
}
}
else {
increase_age();
if (!(is_out()) || ((is_out()) && (univ.party.age % 10 == 0))) // no monst move is party outdoors and on horse
do_monsters();
if (overall_mode != MODE_OUTDOORS)
do_monster_turn();
// Wand monsts
if ((overall_mode == MODE_OUTDOORS) && (party_toast() == false) && (univ.party.age % 10 == 0)) {
i = get_ran(1,1,70 + PSD[SDF_LESS_WANDER_ENC] * 200);
if (i == 10)
create_wand_monst();
for (i = 0; i < 10; i++)
if (univ.party.out_c[i].exists == true)
if (((adjacent(univ.party.p_loc,univ.party.out_c[i].m_loc) == true) ||
(univ.party.out_c[i].what_monst.cant_flee >= 10))
&& (univ.party.in_boat < 0) && (flying() == false)) {
store_wandering_special = univ.party.out_c[i].what_monst;
if (handle_wandering_specials(0,0) == true)
initiate_outdoor_combat(i);
univ.party.out_c[i].exists = false;
// Get rid of excess keyclicks
flushingInput = true;
need_reprint = false;
i = 20;
}
}
if (overall_mode == MODE_TOWN) {
i = get_ran(1,1,160 - univ.town.difficulty + PSD[SDF_LESS_WANDER_ENC] * 200);
if (i == 2)
create_wand_monst();
}
}
}
if (need_redraw == true) {
draw_terrain();
}
if ((need_reprint == true) || (need_redraw == true)) {
print_buf();
}
if (end_scenario) {
reload_startup();
in_startup_mode = true;
draw_startup(0);
menu_activate();
univ.party.scen_name = ".exs"; // should be harmless...
if(cChoiceDlog("congrats-save.xml",{"cancel","save"}).show() == "save"){
try{
fs::path file = nav_put_party();
save_party(file);
} catch(no_file_chosen){}
}
}
else if (party_toast() == true) {
for (i = 0; i < 6; i++)
if (univ.party[i].main_status == MAIN_STATUS_FLED) {
univ.party[i].main_status = MAIN_STATUS_ALIVE;
if (is_combat()) {
end_town_mode(0,univ.town.p_loc);
add_string_to_buf("End combat. ");
handle_wandering_specials(0,2);
}
}
if (univ.party.is_split()) {
ASB(univ.party.end_split(0));
update_explored(univ.town.p_loc);
center = univ.town.p_loc;
if (is_combat()) {
overall_mode = MODE_TOWN;
}
else if (is_town()) {
}
center = univ.town.p_loc;
}
menu_activate();
draw_terrain();
put_pc_screen();
put_item_screen(stat_window,0);
if (party_toast() == true) {
play_sound(13);
handle_death();
if (All_Done == true)
return true;
}
}
are_done = All_Done;
return are_done;
}
bool someone_awake()
{
short i;
for (i = 0; i < 6; i++)
if ((univ.party[i].main_status == 1) && (univ.party[i].status[11] <= 0) && (univ.party[i].status[12] <= 0))
return true;
return false;
}
void handle_menu_spell(short spell_picked,short spell_type)
{
location pass_point;
sf::Event event;
spell_forced = true;
pc_casting = current_pc;
pc_last_cast[spell_type][current_pc] = spell_picked;
if (spell_type == 0)
store_mage = spell_picked;
else store_priest = spell_picked;
if ((spell_type == 0) && (mage_need_select[spell_picked] > 0)) {
if ((store_spell_target = char_select_pc(2 - mage_need_select[spell_picked],0,"Cast spell on who?")) == 6)
return;
}
else {
if ((spell_type == 1) && (priest_need_select[spell_picked] > 0))
if ((store_spell_target = char_select_pc(2 - priest_need_select[spell_picked],0,"Cast spell on who?")) == 6)
return;
}
/* if ((is_combat()) && (((spell_type == 0) && (refer_mage[spell_picked] > 0)) ||
((spell_type == 1) && (refer_priest[spell_picked] > 0)))){
if ((spell_type == 0) && (mage_need_select[spell_picked] > 0))
store_spell_target = char_select_pc(2 - mage_need_select[spell_picked],0,"Cast spell on who?");
else if ((spell_type == 1) && (priest_need_select[spell_picked] > 0))
store_spell_target = char_select_pc(2 - priest_need_select[spell_picked],0,"Cast spell on who?");
}
else {
} */
pass_point.x = bottom_buttons[spell_type].left + 5;
pass_point.y = bottom_buttons[spell_type].top + 5;
event.mouseButton.x = pass_point.x + ul.x;
event.mouseButton.y = pass_point.y + ul.y;
handle_action(event);
}
void initiate_outdoor_combat(short i)
{
short m,n;
location to_place;
draw_terrain();
// Is combat too easy?
if ((party_total_level() > ((out_enc_lev_tot(i) * 5) / 3) ) && (out_enc_lev_tot(i) < 200)
&& (univ.party.out_c[i].what_monst.cant_flee % 10 != 1)) {
add_string_to_buf("Combat: Monsters fled! ");
univ.party.out_c[i].exists = false;
return;
}
// Delay((long) 100,&dummy);
start_outdoor_combat(univ.party.out_c[i], univ.out[univ.party.p_loc.x][univ.party.p_loc.y],count_walls(univ.party.p_loc));
univ.party.out_c[i].exists = false;
for (m = 0; m < 6; m++)
if (univ.party[m].main_status == 1)
to_place = pc_pos[m];
for (m = 0; m < 6; m++)
for (n = 0; n < 24; n++)
if ((univ.party[m].main_status != 1) && (univ.party[m].items[n].variety != 0)) {
place_item(univ.party[m].items[n],to_place,true);
univ.party[m].items[n].variety = ITEM_TYPE_NO_ITEM;
}
overall_mode = MODE_COMBAT;
center = pc_pos[current_pc];
draw_terrain();
}
// TODO: I'm sure there's a better way to do this (maybe one that's keyboard layout agnostic)
char keyToChar(sf::Keyboard::Key key, bool isShift) {
using kb = sf::Keyboard;
switch(key) {
case kb::A: return isShift ? 'A' : 'a';
case kb::B: return isShift ? 'B' : 'b';
case kb::C: return isShift ? 'C' : 'c';
case kb::D: return isShift ? 'D' : 'd';
case kb::E: return isShift ? 'E' : 'e';
case kb::F: return isShift ? 'F' : 'f';
case kb::G: return isShift ? 'G' : 'g';
case kb::H: return isShift ? 'H' : 'h';
case kb::I: return isShift ? 'I' : 'i';
case kb::J: return isShift ? 'J' : 'j';
case kb::K: return isShift ? 'K' : 'k';
case kb::L: return isShift ? 'L' : 'l';
case kb::M: return isShift ? 'M' : 'm';
case kb::N: return isShift ? 'N' : 'n';
case kb::O: return isShift ? 'O' : 'o';
case kb::P: return isShift ? 'P' : 'p';
case kb::Q: return isShift ? 'Q' : 'q';
case kb::R: return isShift ? 'R' : 'r';
case kb::S: return isShift ? 'S' : 's';
case kb::T: return isShift ? 'T' : 't';
case kb::U: return isShift ? 'U' : 'u';
case kb::V: return isShift ? 'V' : 'v';
case kb::W: return isShift ? 'W' : 'w';
case kb::X: return isShift ? 'X' : 'x';
case kb::Y: return isShift ? 'Y' : 'y';
case kb::Z: return isShift ? 'Z' : 'z';
case kb::Num1: return isShift ? '!' : '1';
case kb::Num2: return isShift ? '@' : '2';
case kb::Num3: return isShift ? '#' : '3';
case kb::Num4: return isShift ? '$' : '4';
case kb::Num5: return isShift ? '%' : '5';
case kb::Num6: return isShift ? '^' : '6';
case kb::Num7: return isShift ? '&' : '7';
case kb::Num8: return isShift ? '*' : '8';
case kb::Num9: return isShift ? '(' : '9';
case kb::Num0: return isShift ? ')' : '0';
case kb::Tilde: return isShift ? '~' : '`';
case kb::Dash: return isShift ? '_' : '-';
case kb::Equal: return isShift ? '+' : '=';
case kb::LBracket: return isShift ? '{' : '[';
case kb::RBracket: return isShift ? '}' : ']';
case kb::SemiColon: return isShift ? ':' : ';';
case kb::Quote: return isShift ? '"' : '\'';
case kb::Comma: return isShift ? '<' : ',';
case kb::Period: return isShift ? '>' : '.';
case kb::Slash: return isShift ? '?' : '/';
case kb::BackSlash: return isShift ? '|' : '\\';
case kb::Tab: return '\t';
case kb::Space: return ' ';
case kb::Return: return '\n';
case kb::BackSpace: return '\b';
case kb::Delete: return '\x7f';
}
}
bool handle_keystroke(sf::Event& event){
bool are_done = false;
location pass_point; // TODO: This isn't needed
short i,j;
std::ostringstream sout;
using kb = sf::Keyboard;
using Key = sf::Keyboard::Key;
// TODO: Make sure these are in the right order
char keypad[10] = {kb::Numpad7,kb::Numpad8,kb::Numpad9,kb::Numpad4,kb::Numpad5,kb::Numpad6,kb::Numpad1,kb::Numpad2,kb::Numpad3,kb::Numpad0};
// TODO: The duplication of location here shouldn't be necessary...
location terrain_click[10] = {location{150,185},location{120,215},location{150,215},location{180,215},
location{120,185},location{150,185},location{180,185},
location{120,155},location{150,155},location{180,135}};
Key talk_chars[9] = {kb::L,kb::N,kb::J,kb::B,kb::S,kb::R,kb::D,kb::G,kb::A};
Key shop_chars[8] = {kb::A,kb::B,kb::C,kb::D,kb::E,kb::F,kb::G,kb::H};
if(map_visible && isFrontWindow(mini_map) && event.key.code == kb::Escape
&& (overall_mode != MODE_TALKING) && (overall_mode != MODE_SHOPPING)) {
mini_map.setVisible(false);
map_visible = false;
mainPtr.setActive();
return false;
}
if (in_startup_mode == true)
return false;
mainPtr.setMouseCursorVisible(false);
// DEBUG
// sprintf((char *) debug, "%d ",(short) chr2);
// add_string_to_buf((char *) debug);
// print_buf();
Key chr2 = event.key.code;
sf::Event pass_event = {sf::Event::MouseButtonPressed};
if (overall_mode == MODE_TALKING) {
if (chr2 == kb::Escape)
chr2 = kb::D;
if (chr2 == kb::Space)
chr2 = kb::G;
for (i = 0; i < 9; i++)
if (chr2 == talk_chars[i]) {
pass_point.x = preset_words[i].word_rect.left + 9 + ul.x;
pass_point.y = preset_words[i].word_rect.top + 9 + ul.y;
pass_event.mouseButton.x = pass_point.x;
pass_event.mouseButton.y = pass_point.y;
are_done = handle_action(pass_event);
}
}
else if (overall_mode == MODE_SHOPPING) { // shopping keystrokes
if (chr2 == kb::Escape) {
pass_point.x = 222 + ul.x;
pass_point.y = 398 + ul.y;
pass_event.mouseButton.x = pass_point.x;
pass_event.mouseButton.y = pass_point.y;
are_done = handle_action(pass_event);
}
for (i = 0; i < 8; i++)
if (chr2 == shop_chars[i]) {
pass_point.x = shopping_rects[i][1].left + 9 + ul.x;
pass_point.y = shopping_rects[i][1].top + 9 + ul.y;
pass_event.mouseButton.x = pass_point.x;
pass_event.mouseButton.y = pass_point.y;
are_done = handle_action(pass_event);
}
} else {
for (i = 0; i < 10; i++)
if (chr2 == keypad[i]) {
if (i == 0) {
chr2 = kb::Z;
}
else {
pass_point.x = terrain_click[i].x + ul.x;
pass_point.y = terrain_click[i].y + ul.y;
pass_event.mouseButton.x = pass_point.x;
pass_event.mouseButton.y = pass_point.y;
are_done = handle_action(pass_event);
return are_done;
}
}
}
char chr = keyToChar(chr2, event.key.shift);
switch(chr)
{
case '&':
add_string_to_buf("If Valorim ...");
print_buf();
break;
case '*':
add_string_to_buf("You want to save ...");
print_buf();
break;
case '(':
add_string_to_buf("Back up your save files ...");
print_buf();
break;
case ')':
add_string_to_buf("Burma Shave.");
print_buf();
break;
case '?':
if (overall_mode == MODE_SHOPPING) {
univ.party.help_received[26] = 0;
give_help(226,27);
break;
}
if (overall_mode == MODE_TALKING) {
univ.party.help_received[5] = 0;
give_help(205,6);
break;
}
if (is_out()) cChoiceDlog("help-outdoor.xml").show();
if (is_town()) cChoiceDlog("help-town.xml").show();
if (is_combat()) cChoiceDlog("help-combat.xml").show();
break;
case '1': case '2': case '3': case '4': case '5': case '6':
pass_point.x = pc_buttons[((short) chr) - 49][0].left + 1 + PC_WIN_UL_X + ul.x;
pass_point.y = pc_buttons[((short) chr) - 49][0].top + PC_WIN_UL_Y + ul.y;
pass_event.mouseButton.x = pass_point.x;
pass_event.mouseButton.y = pass_point.y;
are_done = handle_action(pass_event);
break;
case '9':
pass_point.x = item_screen_button_rects[6].left + ITEM_WIN_UL_X + ul.x;
pass_point.y = item_screen_button_rects[6].top + ITEM_WIN_UL_Y + ul.y;
pass_event.mouseButton.x = pass_point.x;
pass_event.mouseButton.y = pass_point.y;
are_done = handle_action(pass_event);
break;
case ' ':
if (overall_mode == MODE_FANCY_TARGET) { // cast multi-target spell, set # targets to 0 so that
// space clicked doesn't matter
num_targets_left = 0;
pass_point = terrain_click[5];
pass_event.mouseButton.x = pass_point.x + ul.x;
pass_event.mouseButton.y = pass_point.y + ul.y;
are_done = handle_action(pass_event);
}
if (overall_mode == MODE_SPELL_TARGET)
spell_cast_hit_return();
break;
case 'D':
if (in_scen_debug) {
in_scen_debug = false;
ASB("Debug mode OFF.");
} else {
in_scen_debug = true;
ASB("Debug mode ON.");
}
print_buf();
break;
case 'z':
if (((overall_mode >= MODE_COMBAT) && (overall_mode < MODE_TALKING)) || (overall_mode == MODE_LOOK_COMBAT)) {
set_stat_window(current_pc);
put_item_screen(stat_window,0);
} else {
set_stat_window(0);
put_item_screen(stat_window,0);
}
break;
case '=':
if(!in_scen_debug) break;
univ.party.gold += 100;
univ.party.food += 100;
for (i = 0; i < 6; i++) {
univ.party[i].main_status = MAIN_STATUS_ALIVE;
univ.party[i].cur_health = univ.party[i].max_health;
univ.party[i].cur_sp = 100;
}
award_party_xp(25);
for (i = 0; i < 6; i++)
for (j = 0; j < 62; j++) {
univ.party[i].priest_spells[j] = 1;
univ.party[i].mage_spells[j] = 1;
}
refresh_store_items();
add_string_to_buf("Debug: Add stuff and heal.");
print_buf();
put_pc_screen();
break;
case 'B':
if(!in_scen_debug) break;
for(i=0;i<6;i++)
if(univ.party[i].main_status >= MAIN_STATUS_SPLIT)
univ.party[i].main_status -= MAIN_STATUS_SPLIT;
if(overall_mode == MODE_OUTDOORS){
add_string_to_buf("Debug - Leave Town: You're not in town!");
print_buf();
break;
}
overall_mode = MODE_OUTDOORS;
position_party(univ.party.outdoor_corner.x,univ.party.outdoor_corner.y,univ.party.p_loc.x,univ.party.p_loc.y);
clear_map();
add_string_to_buf("Debug: Reunite party and leave town.");
print_buf();
redraw_screen();
break;
case 'C':
if(!in_scen_debug) break;
for (i = 0; i < 6; i++) {
univ.party[i].status[STATUS_POISON] = 0;
if(univ.party[i].status[STATUS_BLESS_CURSE] < 0)
univ.party[i].status[STATUS_BLESS_CURSE] = 0;
if (univ.party[i].status[STATUS_HASTE_SLOW] < 0)
univ.party[i].status[STATUS_HASTE_SLOW] = 0;
univ.party[i].status[STATUS_WEBS] = 0;
univ.party[i].status[STATUS_DISEASE] = 0;
univ.party[i].status[STATUS_DUMB] = 0;
univ.party[i].status[STATUS_ASLEEP] = 0;
univ.party[i].status[STATUS_PARALYZED] = 0;
univ.party[i].status[STATUS_ACID] = 0;
}
add_string_to_buf("Debug: You get cleaned up!");
print_buf();
put_pc_screen();
break;
case 'E':
if(!in_scen_debug) break;
PSD[SDF_PARTY_STEALTHY] += 10;
PSD[SDF_PARTY_DETECT_LIFE] += 10;
PSD[SDF_PARTY_FIREWALK] += 10;
add_string_to_buf("Debug: Stealth, Detect Life, Firewalk!");
print_buf();
put_pc_screen();
break;
case 'F':
if(!in_scen_debug) break;
if(overall_mode != MODE_OUTDOORS){
add_string_to_buf("Debug: Can only fly outdoors.");
}else{
PSD[SDF_PARTY_FLIGHT] += 10;
add_string_to_buf("Debug: You start flying!");
}
print_buf();
put_pc_screen();
break;
case 'G':
if(!in_scen_debug) break;
if(ghost_mode){
ghost_mode = false;
ASB("Debug: Ghost mode OFF.");
}else{
ghost_mode = true;
ASB("Debug:Ghost mode ON.");
}
print_buf();
break;
case 'H':
if(!in_scen_debug) break;
univ.party.gold += 100;
univ.party.food += 100;
for (i = 0; i < 6; i++) {
if ((univ.party[i].main_status > MAIN_STATUS_ALIVE) && (univ.party[i].main_status < MAIN_STATUS_FLED))
univ.party[i].main_status = MAIN_STATUS_ALIVE;
}
heal_party(250);
restore_sp_party(100);
add_string_to_buf("Debug: Heal party.");
print_buf();
put_pc_screen();
break;
case 'K':
if (!in_scen_debug) break;
for (i = 0; i < univ.town->max_monst(); i++) {
if ((is_combat()) && (univ.town.monst[i].active > 0) && (univ.town.monst[i].attitude % 2 == 1))
univ.town.monst[i].active = 0;
if ((univ.town.monst[i].active > 0) && (univ.town.monst[i].attitude % 2 == 1)
&& (dist(univ.town.monst[i].cur_loc,univ.town.p_loc) <= 10) )
damage_monst(i, 7,1000,0, DAMAGE_UNBLOCKABLE,0);
}
// kill_monst(&univ.town.monst[i],6);
draw_terrain();
add_string_to_buf("Debug: Kill things. ");
print_buf();
break;
case 'N':
if(!in_scen_debug) break;
end_scenario = true;
in_scen_debug = false;
break;
case 'O':
if(!in_scen_debug) break;
if (is_town()) {
sout << "Debug: You're at x " << (short) univ.town.p_loc.x << ", y " << (short) univ.town.p_loc.y
<< " in town " << univ.town.num << '.';
} else if (is_out()) {
short x = univ.party.p_loc.x;
short y = univ.party.p_loc.y;
x += 48 * univ.party.outdoor_corner.x;
y += 48 * univ.party.outdoor_corner.y;
sout << "Debug: You're outside at x " << x << ", y " << y << ',';
}
add_string_to_buf(sout.str());
print_buf();
break;
case 'I': // TODO: Seems useless?
// if(!in_scen_debug) break;
// sout << "Debug: The party's age is " << univ.party.age;
// add_string_to_buf(sout.str());
// add_string_to_buf("Debug: Reset map."); // Surely this won't work?
// print_buf();
break;
case 'Q':
if(!in_scen_debug) break;
if (overall_mode == MODE_OUTDOORS) {
for (i = 0; i < 96; i++)
for (j = 0; j < 96; j++)
make_explored(i,j);
} else {
for (i = 0; i < 64; i++)
for (j = 0; j < 64; j++)
make_explored(i,j);
}
clear_map();
add_string_to_buf("Debug: Magic Map.");
print_buf();
break;
case 'R':
if(!in_scen_debug) break;
if (univ.party.in_boat >= 0) {
add_string_to_buf(" Not while in boat. ");
break;
}
if (univ.party.in_horse >= 0) {
add_string_to_buf(" Not while on horse. ");
break;
}
force_town_enter(scenario.which_town_start,scenario.where_start);
start_town_mode(scenario.which_town_start,9);
position_party(scenario.out_sec_start.x,scenario.out_sec_start.y,
scenario.out_start.x,scenario.out_start.y);
center = univ.town.p_loc = scenario.where_start;
redraw_screen();
add_string_to_buf("Debug: You return to the start.");
print_buf();
break;
case 'S': // TODO: Create a dedicated dialog for this.
if (!in_scen_debug) break;
cStrDlog("Enter Stuff Done Flag Part A (between 1 and 299)","","Which SDFa ?",130,PIC_DLOG).show();
i = atoi(get_text_response(873,0).c_str());
if(i > 0 && i < 300){
cStrDlog("Enter Stuff Done Flag Part B (between 0 and 49)","","Which SDFb ?",130,PIC_DLOG).show();
j = atoi(get_text_response(873,0).c_str());
if(j >= 0 && j < 50){
cStrDlog("Enter Stuff Done Flag Value (up to 255)","","Which value ?",130,PIC_DLOG).show();
int x = atoi(get_text_response(873,0).c_str());
if(x < 256 && x >= 0)
PSD[i][j] = x;
else if(x == -1){
sout << "SDF(" << i << ',' << j << ") = " << PSD[i][j];
add_string_to_buf(sout.str());
}
}
}
break;
case 'T':
// TODO: Create a dedicated dialog for this?
if(!in_scen_debug) break;
short find_direction_from;
sout << "Enter Town Number (between 0 and " << scenario.num_towns - 1 << ')';
cStrDlog(sout.str(),"","Which Town ?",130,PIC_DLOG).show();
i = atoi(get_text_response(873,0).c_str());
if(i >= 0 && i < scenario.num_towns ){
if (univ.party.direction == 0) find_direction_from = 2;
else if (univ.party.direction == 4) find_direction_from = 0;
else if (univ.party.direction < 4) find_direction_from = 3;
else find_direction_from = 1;
start_town_mode(i, find_direction_from);
}
break;
case 'W':
refresh_store_items();
add_string_to_buf("Debug: Refreshed jobs/shops. ");
print_buf();
break;
// case '`':
// break;
// case '[':
// break;
// case '+':
// break;
case '<':
//break;
if (!in_scen_debug) break;
ASB("Debug: Increase age.");
ASB(" It is now 1 day later.");
print_buf();
univ.party.age += 3700;
put_pc_screen();
break;
case '>':
ASB("DEBUG: Towns have short memory.");
ASB("Your deeds have been forgotten.");
print_buf();
for (i = 0; i < 4; i++)
univ.party.creature_save[i].which_town = 200;
break;
case '/':
if(!in_scen_debug) break;
ASB("Debug hot keys");
ASB(" B Leave town");
ASB(" C Get cleaned up");
ASB(" D Toggle Debug mode");
ASB(" E Stealth, Detect Life, Firewalk");
ASB(" F Flight");
ASB(" G Ghost");
ASB(" H Heal");
ASB(" K Kill things");
ASB(" N End Scenario");
ASB(" O Location");
ASB(" Q Magic map");
ASB(" R Return to Start");
ASB(" S Set a SDF");
ASB(" T Enter Town");
ASB(" W Refresh jobs/shops");
ASB(" = Heal, increase magic skills");
ASB(" < Make one day pass");
ASB(" > Towns forgive you");
ASB(" / Bring up this list");
print_buf();
break;
case 'a':
if (overall_mode < MODE_TALK_TOWN) {
pass_point.x = (overall_mode == MODE_OUTDOORS) ? 170 : 221;
pass_point.y = 405;
pass_event.mouseButton.x = pass_point.x + ul.x;
pass_event.mouseButton.y = pass_point.y + ul.y;
are_done = handle_action(pass_event);
}
break;
case 'b': case 'u': case 'L':
if (overall_mode == MODE_TOWN) {
pass_point.x = (chr == 'u') ? 220 : 205;
pass_point.y = (chr == 'L') ? 405 : 388;
pass_event.mouseButton.x = pass_point.x + ul.x;
pass_event.mouseButton.y = pass_point.y + ul.y;
are_done = handle_action(pass_event);
}
break;
case 's': case 'x': case 'e':
if ((overall_mode == MODE_COMBAT) ||
((overall_mode == MODE_FIRING) && (chr == 's')) ||
((overall_mode == MODE_THROWING) && (chr == 's')) ) {
pass_point.x = (chr == 's') ? 205 : 240;
pass_point.y = (chr == 'e') ? 390 : 406;
pass_event.mouseButton.x = pass_point.x + ul.x;
pass_event.mouseButton.y = pass_point.y + ul.y;
are_done = handle_action(pass_event);
}
break;
case 'm': case 'p': case 'l': case 'r': case 'w': case 't': case 'd': case 'g': case 'f':
case 'M': case 'P': case 'A':
j = 50;
if ((chr == 'm') && ((overall_mode == MODE_SPELL_TARGET) || (overall_mode == MODE_FANCY_TARGET))) // cancel spell
j = 0;
if ((chr == 'p') && ((overall_mode == MODE_SPELL_TARGET) || (overall_mode == MODE_FANCY_TARGET))) // cancel spell
j = 1;
if ((overall_mode == MODE_OUTDOORS) || (overall_mode == MODE_TOWN) || (overall_mode == MODE_COMBAT)) {
switch (chr) {
case 'M': spell_forced = true; j = 0; break;
case 'm': j = 0; break;
case 'P': spell_forced = true; j = 1; break;
case 'p': j = 1; break;
case 'l': j = 2; break;
case 'r': if (overall_mode != MODE_OUTDOORS) return false;
j = 3;
break;
case 't': if (overall_mode == MODE_TOWN)
j = 3;
else return false;
break;
case 'A':if (overall_mode == MODE_TOWN) {
// TODO: Uh, what about ul.y?
pass_point.x = 1000 + ul.x;
pass_event.mouseButton.x = pass_point.x;
pass_event.mouseButton.y = pass_point.y;
are_done = handle_action(pass_event);
}
else {
add_string_to_buf("Alchemy: In town only.");
print_buf();
return false;
}
break;
case 'w':if (overall_mode == MODE_COMBAT)
j = 5;
else if (overall_mode == MODE_TOWN) {
// TODO: Uh, what about ul.y?
pass_point.x = 1001 + ul.x;
pass_event.mouseButton.x = pass_point.x;
pass_event.mouseButton.y = pass_point.y;
are_done = handle_action(pass_event);
}
else {
add_string_to_buf("Wait: In town only.");
print_buf();
return false;
}
break;
case 'd': if (overall_mode != MODE_COMBAT) return false;
j = 3;
break;
case 'g': if (overall_mode == MODE_OUTDOORS) return false;
j = 4;
break;
case 'f': if (overall_mode != MODE_TOWN) return false;
j = 6;
break;
}
}
if (j < 50) {
pass_point.x = bottom_buttons[j].left + 5;
pass_point.y = bottom_buttons[j].top + 5;
pass_event.mouseButton.x = pass_point.x + ul.x;
pass_event.mouseButton.y = pass_point.y + ul.y;
are_done = handle_action(event);
}
break;
}
spell_forced = false;
return are_done;
}
void do_load()
{
try{
fs::path file_to_load = nav_get_party();
load_party(file_to_load);
} catch(no_file_chosen){}
if (in_startup_mode == false)
post_load();
menu_activate();
}
void post_load()
{
current_switch = 6;
reset_item_max();
if (overall_mode == MODE_OUTDOORS)
update_explored(univ.party.p_loc);
// if (overall_mode == MODE_TOWN) {
// make_town_trim(0);
// }
// make_out_trim();
// TODO: Presumably need to call draw() as well, but maybe not here
text_sbar->show();
item_sbar->show();
shop_sbar->hide();
set_stat_window(0);
put_pc_screen();
draw_terrain();
draw_buttons(0);
draw_text_bar(1);
print_buf();
clear_map();
adjust_spell_menus();
adjust_monst_menu();
}
void do_save(short mode)
//mode; // 0 - normal 1 - save as
{
// SelectWindow(mainPtr);
if (overall_mode > MODE_TOWN) {
add_string_to_buf("Save: Only while outdoors, or in ");
add_string_to_buf(" town and not looking/casting. ");
print_buf();
return;
}
try{
if(mode == 1) univ.file = nav_put_party();
save_party(univ.file);
} catch(no_file_chosen){}
pause(6);
// initiate_redraw();
// put_pc_screen();
// put_item_screen(stat_window,0);
// print_buf();
redraw_screen();
}
void increase_age()////
{
short i,j,item,how_many_short = 0,r1,store_day;
bool update_stat = false;
// Increase age, adjust light level & stealth
store_day = calc_day();
if (is_out()) {
if (univ.party.in_horse < 0)
univ.party.age -= univ.party.age % 10;
else univ.party.age -= univ.party.age % 5;
univ.party.age += 5;
if (univ.party.in_horse < 0)
univ.party.age += 5;
}
else univ.party.age++;
if (calc_day() != store_day) { // Day changed, so check for interesting stuff.
update_stat = true;
}
univ.party.light_level = move_to_zero(univ.party.light_level);
// if (PSD[128][9] == 1)
// clear_map();
// decrease monster present counter
PSD[SDF_HOSTILES_PRESENT] = move_to_zero(PSD[SDF_HOSTILES_PRESENT]);
// Party spell effects
if (PSD[SDF_PARTY_STEALTHY] == 1) {reset_text_bar();
add_string_to_buf("Your footsteps grow louder. "); }
PSD[SDF_PARTY_STEALTHY] = move_to_zero(PSD[SDF_PARTY_STEALTHY]);
if (PSD[SDF_PARTY_DETECT_LIFE] == 1) {reset_text_bar();
add_string_to_buf("You stop detecting monsters. ");}
PSD[SDF_PARTY_DETECT_LIFE] = move_to_zero(PSD[SDF_PARTY_DETECT_LIFE]);
if (PSD[SDF_PARTY_FIREWALK] == 1) {reset_text_bar();
add_string_to_buf("Your feet stop glowing. ");}
PSD[SDF_PARTY_FIREWALK] = move_to_zero(PSD[SDF_PARTY_FIREWALK]);
if (PSD[SDF_PARTY_FLIGHT] == 2)
add_string_to_buf("You are starting to descend.");
if (PSD[SDF_PARTY_FLIGHT] == 1) {
if (scenario.ter_types[univ.out[univ.party.p_loc.x][univ.party.p_loc.y]].blockage > 2) {
add_string_to_buf(" You plummet to your deaths. ");
slay_party(MAIN_STATUS_DEAD);
print_buf();
pause(150);
}
else add_string_to_buf(" You land safely. ");
reset_text_bar();
}
PSD[SDF_PARTY_FLIGHT] = move_to_zero(PSD[SDF_PARTY_FLIGHT]);
if ((overall_mode > MODE_OUTDOORS) && (univ.town->lighting_type == 2))
univ.party.light_level = max (0,univ.party.light_level - 9);
if (univ.town->lighting_type == 3) {
if (univ.party.light_level > 0)
ASB("Your light is drained.");
univ.party.light_level = 0;
}
// Specials countdowns
if ((univ.party.age % 500 == 0
) && (get_ran(1,0,5) == 3) && (party_has_abil(52) == true)) {
update_stat = true;
// TODO: This seems to be the "radioactivity" handler, and the string appears to not exist.
cStrDlog display_enc_string("Missing String: Radioactivity", "", "", 8, PIC_DLOG);
display_enc_string.setSound(3);
display_enc_string.show();
for (i = 0; i < 6; i++)
disease_pc(i,2);
}
// Plants and magic shops
if (univ.party.age % 4000 == 0) {
//SysBeep(2);
//ASB("DEBUG: Stuff replaced.");
refresh_store_items();
//for (i = 0; i < 10; i++)
// PSD[302][i] = 0;
//for (i = 0; i < 10; i++)
// PSD[301][i] = 0;
//for (i = 0; i < 10; i++)
//// PSD[300][i] = 0;
}
// Protection, etc.
for (i = 0; i < 6; i++) { // Process some status things, and check if stats updated
if ((univ.party[i].status[4] == 1) || (univ.party[i].status[5] == 1) || (univ.party[i].status[8] == 1)
|| (univ.party[i].status[11] == 1)|| (univ.party[i].status[12] == 1))
update_stat = true;
univ.party[i].status[4] = move_to_zero(univ.party[i].status[4]);
univ.party[i].status[5] = move_to_zero(univ.party[i].status[5]);
univ.party[i].status[8] = move_to_zero(univ.party[i].status[8]);
univ.party[i].status[10] = move_to_zero(univ.party[i].status[10]);
univ.party[i].status[11] = move_to_zero(univ.party[i].status[11]);
univ.party[i].status[12] = move_to_zero(univ.party[i].status[12]);
if ((univ.party.age % 40 == 0) && (univ.party[i].status[0] > 0)) {
update_stat = true;
univ.party[i].status[0] = move_to_zero(univ.party[i].status[0]);
}
}
// Food
if ((univ.party.age % 1000 == 0) && (overall_mode < MODE_COMBAT)) {
for (i = 0; i < 6; i++)
if (univ.party[i].main_status == 1)
how_many_short++;
how_many_short = take_food (how_many_short,false);
if (how_many_short > 0) {
add_string_to_buf("Starving! ");
play_sound(66);
r1 = get_ran(3,1,6);
hit_party(r1,DAMAGE_UNBLOCKABLE);
update_stat = true;
if (overall_mode < MODE_COMBAT)
boom_space(univ.party.p_loc,overall_mode,0,r1,0);
}
else {
play_sound(6);
add_string_to_buf("You eat. ");
}
update_stat = true;
}
// Poison, acid, disease damage
for (i = 0; i < 6; i++) // Poison
if (univ.party[i].status[2] > 0) {
i = 6;
if (((overall_mode == MODE_OUTDOORS) && (univ.party.age % 50 == 0)) || ((overall_mode == MODE_TOWN) && (univ.party.age % 20 == 0))) {
update_stat = true;
do_poison();
}
}
for (i = 0; i < 6; i++) // Disease
if (univ.party[i].status[7] > 0) {
i = 6;
if (((overall_mode == MODE_OUTDOORS) && (univ.party.age % 100 == 0)) || ((overall_mode == MODE_TOWN) && (univ.party.age % 25 == 0))) {
update_stat = true;
handle_disease();
}
}
for (i = 0; i < 6; i++) // Acid
if (univ.party[i].status[13] > 0) {
i = 6;
update_stat = true;
handle_acid();
}
// Healing and restoration of spell pts.
if (is_out()) {
if (univ.party.age % 100 == 0) {
for (i = 0; i < 6; i++)
if ((univ.party[i].main_status == 1) && (univ.party[i].cur_health < univ.party[i].max_health))
update_stat = true;
heal_party(2);
}
}
else {
if (univ.party.age % 50 == 0) {
for (i = 0; i < 6; i++)
if ((univ.party[i].main_status == 1) && (univ.party[i].cur_health < univ.party[i].max_health))
update_stat = true;
heal_party(1);
}
}
if (is_out()) {
if (univ.party.age % 80 == 0) {
for (i = 0; i < 6; i++)
if ((univ.party[i].main_status == 1) && (univ.party[i].cur_sp < univ.party[i].max_sp))
update_stat = true;
restore_sp_party(2);
}
}
else {
if (univ.party.age % 40 == 0) {
for (i = 0; i < 6; i++)
if ((univ.party[i].main_status == 1) && (univ.party[i].cur_sp < univ.party[i].max_sp))
update_stat = true;
restore_sp_party(1);
}
}
// Recuperation and chronic disease disads
for (i = 0; i < 6; i++)
if (univ.party[i].main_status == 1) {
if ((univ.party[i].traits[9] > 0) && (get_ran(1,0,10) == 1) && (univ.party[i].cur_health < univ.party[i].max_health)) {
heal_pc(i,2);
update_stat = true;
}
if ((univ.party[i].traits[13] > 0) && (get_ran(1,0,110) == 1)) {
disease_pc(i,4);
update_stat = true;
}
}
// Blessing, slowed,etc.
if (univ.party.age % 4 == 0)
for (i = 0; i < 6; i++) {
if ((univ.party[i].status[1] != 0) || (univ.party[i].status[3] != 0))
update_stat = true;
univ.party[i].status[1] = move_to_zero(univ.party[i].status[1]);
univ.party[i].status[3] = move_to_zero(univ.party[i].status[3]);
if (((item = pc_has_abil_equip(i,50)) < 24)
&& (univ.party[i].cur_health < univ.party[i].max_health)
&& ((overall_mode > MODE_OUTDOORS) || (get_ran(1,0,10) == 5))){
j = get_ran(1,0,univ.party[i].items[item].ability_strength / 3);
if (univ.party[i].items[item].ability_strength / 3 == 0)
j = get_ran(1,0,1);
if (is_out()) j = j * 4;
heal_pc(i,j);
update_stat = true;
}
}
dump_gold(1);
special_increase_age();
//if (debug_on == false)
push_things();
if (is_town()) {
process_fields();
}
// Cancel switching PC order
current_switch = 6;
// If a change, draw stat screen
if (update_stat == true)
put_pc_screen();
adjust_spell_menus();
}
void handle_cave_lore()////
{
char str[60];
short i,pic;
ter_num_t ter;
if (!is_out())
return;
ter = univ.out[univ.party.p_loc.x][univ.party.p_loc.y];
pic = scenario.ter_types[ter].picture;
for (i = 0; i < 6; i++)
if ((univ.party[i].main_status == 1) && (univ.party[i].traits[4] > 0) && (get_ran(1,0,12) == 5)
&& (((pic >= 0) && (pic <= 1)) || ((pic >= 70) && (pic <= 76))) ) {
sprintf((char *)str,"%s hunts.",univ.party[i].name.c_str());
univ.party.food += get_ran(2,1,6);
add_string_to_buf((char *)str);
put_pc_screen();
}
for (i = 0; i < 6; i++)
if (
(univ.party[i].main_status == 1) && (univ.party[i].traits[5] > 0) && (get_ran(1,0,12) == 5)
&& (((pic >= 2) && (pic <= 4)) || ((pic >= 79) && (pic <= 84)))) {
sprintf((char *)str,"%s hunts.",univ.party[i].name.c_str());
univ.party.food += get_ran(2,1,6);
add_string_to_buf((char *)str);
put_pc_screen();
}
}
void switch_pc(short which)
{
cPlayer store_pc;
if (current_switch < 6) {
add_string_to_buf("Switch: OK.");
if (current_switch != which) {
store_pc = univ.party[which];
univ.party[which] = univ.party[current_switch];
univ.party[current_switch] = store_pc;
if (current_pc == current_switch)
current_pc = which;
else if (current_pc == which)
current_pc = current_switch;
set_stat_window(current_pc);
current_switch = 6;
}
}
else {
add_string_to_buf("Switch: Switch with who? ");
current_switch = which;
}
}
void drop_pc(short which)
{
std::string choice;
choice = cChoiceDlog("delete-pc-confirm.xml",{"yes","no"}).show();
if (choice == "no") {
add_string_to_buf("Delete PC: Cancelled. ");
return;
}
add_string_to_buf("Delete PC: OK. ");
kill_pc(which,MAIN_STATUS_ABSENT);
for(short i = which; i < 5; i++)
univ.party[i] = univ.party[i + 1];
univ.party[5].main_status = MAIN_STATUS_ABSENT;
set_stat_window(0);
put_pc_screen();
}
void handle_death()
{
std::string choice;
in_startup_mode = true;
while (in_startup_mode == true) {
// Use death (or leave Exile) dialog
in_startup_mode = false;
choice = cChoiceDlog("party-death.xml",{"load","new","quit"}).show(); //// FCD hates it when it gets called in startup mode
// and startup graphiocs aren't loaded.
in_startup_mode = true;
if(choice == "quit") {
in_startup_mode = false;
All_Done = true;
}
else if(choice == "load") {
in_startup_mode = false;
try{
fs::path file_to_load = nav_get_party();
load_party(file_to_load);
} catch(no_file_chosen){}
if (party_toast() == false) {
if (in_startup_mode == false)
post_load();
else return;
}
else in_startup_mode = true;
}
else if(choice == "new") {
start_new_game();
}
}
}
void start_new_game()
{
short i;
std::string choice;
using kb = sf::Keyboard;
choice = cChoiceDlog("new-party.xml",{"okay","cancel"}).show();
if(choice == "cancel")
return;
//which = choice - 1;
// display_intro();
if(kb::isKeyPressed(kb::LSystem) || kb::isKeyPressed(kb::RSystem)) init_party(2); // if command key held down, create debug party
else init_party(0);
//while (creation_done == false) {
edit_party(1,0);
/* if ((i > 0) || (in_startup_mode == false))
creation_done = true;
if ((i == 0) && (in_startup_mode == false))
return;
} */
// if no PCs left, forget it
for (i = 0 ; i < 6; i++)
if (univ.party[i].main_status == 1)
i = 100;
if (i == 6)
return;
// everyone gets a weapon
for (i = 0; i < 6; i++)
if (univ.party[i].main_status == 1) {
univ.party[i].items[0] = start_items[univ.party[i].race * 2];
univ.party[i].equip[0] = true;
univ.party[i].items[1] = start_items[univ.party[i].race * 2 + 1];
univ.party[i].equip[1] = true;
}
// PCs get adjustments
for (i = 0; i < 6; i++)
if (univ.party[i].main_status == 1) {
// Do stat adjs for selected race.
if (univ.party[i].race == 1)
univ.party[i].skills[1] += 2;
if (univ.party[i].race == 2) {
univ.party[i].skills[0] += 2;
univ.party[i].skills[2] += 1;
}
univ.party[i].max_sp += univ.party[i].skills[9] * 3 + univ.party[i].skills[10] * 3;
univ.party[i].cur_sp = univ.party[i].max_sp;
}
try{
fs::path file = nav_put_party();
save_party(file);
party_in_memory = true;
} catch(no_file_chosen){}
party_in_memory = true;
}
location get_cur_direction(location the_point)
{
location store_dir;
// This is a kludgy adjustment to adjust for the screen shifting between Exile I & II
the_point.x += 5;
the_point.y += 5;
if ((the_point.x < 135) & (the_point.y >= ((the_point.x * 34) / 10) - 293)
& (the_point.y <= (-1 * ((the_point.x * 34) / 10) + 663)))
store_dir.x--;
if ((the_point.x > 163) & (the_point.y <= ((the_point.x * 34) / 10) - 350)
& (the_point.y >= (-1 * ((the_point.x * 34) / 10) + 721)))
store_dir.x++;
if ((the_point.y < 167) & (the_point.y <= (the_point.x / 2) + 102)
& (the_point.y <= (-1 * (the_point.x / 2) + 249)))
store_dir.y--;
if ((the_point.y > 203) & (the_point.y >= (the_point.x / 2) + 123)
& (the_point.y >= (-1 * (the_point.x / 2) + 268)))
store_dir.y++;
return store_dir;
}
eDirection find_waterfall(short x, short y, short mode){
// If more than one waterfall adjacent, randomly selects
bool to_dir[8];
for(eDirection i = DIR_N; i < DIR_HERE; i++){
if(mode == 0){
to_dir[i] = (scenario.ter_types[univ.town->terrain(x + dir_x_dif[i],y + dir_y_dif[i])].special == TER_SPEC_WATERFALL);
//printf("%i\n",scenario.ter_types[univ.town->terrain(x + dir_x_dif[i],y + dir_y_dif[i])].flag1);
if(scenario.ter_types[univ.town->terrain(x + dir_x_dif[i],y + dir_y_dif[i])].flag1.u != i) to_dir[i] = false;
}else{
to_dir[i] = (scenario.ter_types[univ.out[x + dir_x_dif[i]][y + dir_y_dif[i]]].special == TER_SPEC_WATERFALL);
if(scenario.ter_types[univ.out[x + dir_x_dif[i]][y + dir_y_dif[i]]].flag1.u != i) to_dir[i] = false;
}
}
short count = 0;
for(int i = 0; i < 8; i++)
count += to_dir[i];
if(count > 0) count = get_ran(1,1,count);
else return DIR_HERE;
for(eDirection i = DIR_N; i < DIR_HERE; i++){
if(to_dir[i]){
count--;
if(count == 0) return i;
}
}
return DIR_HERE; // just in case something wonky happens
}
void run_waterfalls(short mode){ // mode 0 - town, 1 - outdoors
short x,y;
if(mode == 0){
x = univ.town.p_loc.x;
y = univ.town.p_loc.y;
}else{
x = univ.party.p_loc.x;
y = univ.party.p_loc.y;
}
eDirection dir;
while((dir = find_waterfall(x,y,mode)) != DIR_HERE){
add_string_to_buf(" Waterfall! ");
if(mode == 0){
x += 2 * dir_x_dif[dir];
y += 2 * dir_y_dif[dir];
univ.town.p_loc.x += 2 * dir_x_dif[dir];
univ.town.p_loc.y += 2 * dir_y_dif[dir];
update_explored(univ.party.p_loc);
}else{
x += 2 * dir_x_dif[dir];
y += 2 * dir_y_dif[dir];
univ.party.p_loc.x += 2 * dir_x_dif[dir];
univ.party.loc_in_sec.x += 2 * dir_x_dif[dir];
univ.party.p_loc.y += 2 * dir_y_dif[dir];
univ.party.loc_in_sec.y += 2 * dir_y_dif[dir];
update_explored(univ.party.p_loc);
}
draw_terrain();
print_buf();
if ((cave_lore_present() > 0) && (get_ran(1,0,1) == 0))
add_string_to_buf(" (No supplies lost.)");
else if (univ.party.food > 1800){
add_string_to_buf(" (Many supplies lost.)");
univ.party.food -= 50;
}
else {
int n = univ.party.food;
char s[25];
univ.party.food = (univ.party.food * 19) / 20;
sprintf(s," (%d supplies lost.)",n - univ.party.food);
add_string_to_buf(s);
}
put_pc_screen();
play_sound(28);
pause(8);
}
if(mode == 0){
univ.party.boats[univ.party.in_boat].loc = univ.town.p_loc;
univ.party.boats[univ.party.in_boat].which_town = univ.town.num;
}else{
univ.party.boats[univ.party.in_boat].which_town = 200;
univ.party.boats[univ.party.in_boat].loc_in_sec = univ.party.loc_in_sec;
univ.party.boats[univ.party.in_boat].loc = univ.party.p_loc;
univ.party.boats[univ.party.in_boat].sector.x = univ.party.outdoor_corner.x + univ.party.i_w_c.x;
univ.party.boats[univ.party.in_boat].sector.y = univ.party.outdoor_corner.y + univ.party.i_w_c.y;
}
}
bool outd_move_party(location destination,bool forced)
{
char create_line[60];
short boat_num,horse_num,spec_num;
location real_dest, sector_p_in;
bool keep_going = true,check_f;
location store_corner,store_iwc;
ter_num_t ter;
keep_going = check_special_terrain(destination,0,0,&spec_num,&check_f);
if (check_f == true)
forced = true;
if (in_scen_debug && ghost_mode)
forced = true;
if (spec_num == 50)
forced = true;
// If not blocked and not put in town by a special, process move
if ((keep_going == true) && (overall_mode == MODE_OUTDOORS)) {
real_dest.x = destination.x - univ.party.p_loc.x;
real_dest.y = destination.y - univ.party.p_loc.y;
sector_p_in.x = univ.party.outdoor_corner.x + univ.party.i_w_c.x;
sector_p_in.y = univ.party.outdoor_corner.y + univ.party.i_w_c.y;
store_corner = univ.party.outdoor_corner;
store_iwc = univ.party.i_w_c;
// Check if party moves into new sector
if ((destination.x < 6) && (univ.party.outdoor_corner.x > 0))
shift_universe_left();
if ((destination.x > 90) && (univ.party.outdoor_corner.x < scenario.out_width - 1))
shift_universe_right();
if ((destination.y < 6) && (univ.party.outdoor_corner.y > 0)) {
shift_universe_up();
}
else if ((destination.y > 90) && (univ.party.outdoor_corner.y < scenario.out_height - 1))
shift_universe_down();
// Now stop from going off the world's edge
real_dest.x = univ.party.p_loc.x + real_dest.x;
real_dest.y =univ. party.p_loc.y + real_dest.y;
if ((real_dest.x < 1 /*4*/) && (univ.party.outdoor_corner.x <= 0)) {
ASB("You've reached the world's edge.");
return false;
}
if (((real_dest.x > 95 /*92*/) && (univ.party.outdoor_corner.x >= scenario.out_width - 2)) ||
((real_dest.x > 47 /*44*/) && (univ.party.outdoor_corner.x >= scenario.out_width - 1))) {
ASB("You've reached the world's edge.");
return false;
}
if ((real_dest.y < 1 /*4*/) && (univ.party.outdoor_corner.y <= 0)) {
ASB("You've reached the world's edge.");
return false;
}
else if (((real_dest.y > 95 /*92*/) && (univ.party.outdoor_corner.y >= scenario.out_height - 2)) ||
((real_dest.y > 47 /*44*/) && (univ.party.outdoor_corner.y >= scenario.out_height - 1))) {
ASB("You've reached the world's edge.");
return false;
}
// if ((store_corner.x != party.outdoor_corner.x) || (store_corner.y != party.outdoor_corner.y) ||
// (store_iwc.x != party.i_w_c.x) || (store_iwc.y != party.i_w_c.y))
// clear_map();
//if (forced == true)
// for (i = 0; i < 10; i++)
// if (same_point(destination,party.out_c[i].m_loc) == true)
// party.out_c[i].exists = false;
ter = univ.out[real_dest.x][real_dest.y];
if (univ.party.in_boat >= 0) {
if ((outd_is_blocked(real_dest) == false) //&& (outd_is_special(real_dest) == false)
// not in towns
&& ((scenario.ter_types[ter].boat_over == false)
|| ((real_dest.x != univ.party.p_loc.x) && (real_dest.y != univ.party.p_loc.y)))
&& (scenario.ter_types[ter].special != TER_SPEC_TOWN_ENTRANCE)) {
add_string_to_buf("You leave the boat.");
univ.party.in_boat = -1;
}
else if (((real_dest.x != univ.party.p_loc.x) && (real_dest.y != univ.party.p_loc.y))
|| ((forced == false) && (out_boat_there(destination) < 30)))
return false;
else if ((outd_is_blocked(real_dest) == false)
&& (scenario.ter_types[ter].boat_over == true)
&& (scenario.ter_types[ter].special != TER_SPEC_TOWN_ENTRANCE)) {
if(cChoiceDlog("boat-bridge.xml",{"under","land"}).show() == "under")
forced = true;
else {
add_string_to_buf("You leave the boat. ");
univ.party.in_boat = -1;
}
}
else if (scenario.ter_types[ter].boat_over == true)
forced = true;
}
if (((boat_num = out_boat_there(real_dest)) < 30) && (univ.party.in_boat < 0) && (univ.party.in_horse < 0)) {
if (flying() == true) {
add_string_to_buf("You land first. ");
PSD[SDF_PARTY_FLIGHT] = 0;
}
give_help(61,0);
add_string_to_buf("Move: You board the boat. ");
univ.party.in_boat = boat_num;
univ.party.direction = set_direction(univ.party.p_loc, destination);
univ.party.p_loc = real_dest;
univ.party.i_w_c.x = (univ.party.p_loc.x > 48) ? 1 : 0;
univ.party.i_w_c.y = (univ.party.p_loc.y > 48) ? 1 : 0;
univ.party.loc_in_sec = global_to_local(univ.party.p_loc);
if ((store_corner.x != univ.party.outdoor_corner.x) || (store_corner.y != univ.party.outdoor_corner.y) ||
(store_iwc.x != univ.party.i_w_c.x) || (store_iwc.y != univ.party.i_w_c.y))
clear_map();
return true;
}
else if (((horse_num = out_horse_there(real_dest)) < 30) && (univ.party.in_boat < 0) && (univ.party.in_horse < 0)) {
if (flying() == true) {
add_string_to_buf("Land before mounting horses.");
return false;
}
give_help(60,0);
add_string_to_buf("Move: You mount the horses. ");
play_sound(84);
univ.party.in_horse = horse_num;
univ.party.direction = set_direction(univ.party.p_loc, destination);
univ.party.p_loc = real_dest;
univ.party.i_w_c.x = (univ.party.p_loc.x > 48) ? 1 : 0;
univ.party.i_w_c.y = (univ.party.p_loc.y > 48) ? 1 : 0;
univ.party.loc_in_sec = global_to_local(univ.party.p_loc);
if ((store_corner.x != univ.party.outdoor_corner.x) || (store_corner.y != univ.party.outdoor_corner.y) ||
(store_iwc.x != univ.party.i_w_c.x) || (store_iwc.y != univ.party.i_w_c.y))
clear_map();
return true;
}
else if ((outd_is_blocked(real_dest) == false) || (forced == true)
// Check if can fly over
|| ((flying() == true) &&
(scenario.ter_types[ter].fly_over == true)) ) {
if (scenario.ter_types[ter].special == TER_SPEC_DAMAGING || scenario.ter_types[ter].special == TER_SPEC_DANGEROUS) {
ASB("Your horses quite sensibly refuse.");
return false;
}
univ.party.direction = set_direction(univ.party.p_loc, destination);
if ((flying() == true) && (scenario.ter_types[ter].special == TER_SPEC_TOWN_ENTRANCE)) {
add_string_to_buf("Moved: You have to land first. ");
return false;
}
univ.party.p_loc = real_dest;
univ.party.i_w_c.x = (univ.party.p_loc.x > 47) ? 1 : 0;
univ.party.i_w_c.y = (univ.party.p_loc.y > 47) ? 1 : 0;
univ.party.loc_in_sec = global_to_local(univ.party.p_loc);
sprintf ((char *) create_line, "Moved: %s",dir_string[univ.party.direction]);//, univ.party.p_loc.x, univ.party.p_loc.y, univ.party.loc_in_sec.x, univ.party.loc_in_sec.y);
add_string_to_buf((char *) create_line);
move_sound(univ.out[real_dest.x][real_dest.y],num_out_moves);
num_out_moves++;
if (univ.party.in_boat >= 0) { // Waterfall!!!
run_waterfalls(1);
}
if (univ.party.in_horse >= 0) {
univ.party.horses[univ.party.in_horse].which_town = 200;
univ.party.horses[univ.party.in_horse].loc_in_sec = univ.party.loc_in_sec;
univ.party.horses[univ.party.in_horse].loc = univ.party.p_loc;
univ.party.horses[univ.party.in_horse].sector.x = univ.party.outdoor_corner.x + univ.party.i_w_c.x;
univ.party.horses[univ.party.in_horse].sector.y = univ.party.outdoor_corner.y + univ.party.i_w_c.y;
}
if ((store_corner.x != univ.party.outdoor_corner.x) || (store_corner.y != univ.party.outdoor_corner.y) ||
(store_iwc.x != univ.party.i_w_c.x) || (store_iwc.y != univ.party.i_w_c.y))
clear_map();
return true;
}
else {
sprintf ((char *) create_line, "Blocked: %s",dir_string[set_direction(univ.party.p_loc, destination)]);
add_string_to_buf((char *) create_line);
return false;
}
}
return false;
}
bool town_move_party(location destination,short forced)////
{
char create_line[60],keep_going = true;
short boat_there,horse_there,spec_num;
ter_num_t ter;
bool check_f = false;
if (in_scen_debug && ghost_mode)
forced = true;
// remove if not registered
/*
if ((scenario.out_width != 3) || (scenario.out_height != 3) ||
(scenario.num_towns != 21) || (scenario.town_size[3] != 1) || (scenario.town_size[9] != 0)) {
ASB("Blades of Exile must be registered");
ASB("before you can play scenarios besides");
ASB("the unmodified Valley of Dying things.");
print_buf();
return false;
}
*/
if (monst_there(destination) > univ.town->max_monst())
keep_going = check_special_terrain(destination,1,0,&spec_num,&check_f);
if (check_f == true)
forced = true;
if (spec_num == 50)
forced = true;
ter = univ.town->terrain(destination.x,destination.y);
if (keep_going == true) {
if (univ.party.in_boat >= 0) {
if ((!is_blocked(destination)) && (!is_special(destination))
// If to bridge, exit if heading diagonal, keep going if heading horiz or vert
&& ( (!scenario.ter_types[ter].boat_over)
|| ((destination.x != univ.town.p_loc.x) && (destination.y != univ.town.p_loc.y)))) {
add_string_to_buf("You leave the boat. ");
univ.party.in_boat = -1;
}
else if ((destination.x != univ.town.p_loc.x) && (destination.y != univ.town.p_loc.y))
return false;
// Crossing bridge: land or go through
else if ((!is_blocked(destination)) && (scenario.ter_types[ter].boat_over) && (scenario.ter_types[ter].special == TER_SPEC_BRIDGE)) {
if(cChoiceDlog("boat-bridge.xml",{"under","land"}).show() == "under")
forced = true;
else if (is_blocked(destination) == false) {
add_string_to_buf("You leave the boat. ");
univ.party.in_boat = -1;
}
}
// boat in destination
else if (town_boat_there(destination) < 30) {
add_string_to_buf(" Boat there already. ");
return false;
}
// water or lava
else if (scenario.ter_types[ter].boat_over == true)
forced = true;
}
if (((boat_there = town_boat_there(destination)) < 30) && (univ.party.in_boat < 0)) {
if (univ.party.boats[boat_there].property == true) {
add_string_to_buf(" Not your boat. ");
return false;
}
give_help(61,0);
add_string_to_buf("Move: You board the boat. ");
univ.party.in_boat = boat_there;
univ.party.direction = set_direction(univ.town.p_loc, destination);
univ.town.p_loc = destination;
center = univ.town.p_loc;
return true;
}
else if (((horse_there = town_horse_there(destination)) < 30) && (univ.party.in_horse < 0)) {
if (univ.party.horses[horse_there].property == true) {
add_string_to_buf(" Not your horses. ");
return false;
}
give_help(60,0);
add_string_to_buf("Move: You mount the horses. ");
play_sound(84);
univ.party.in_horse = horse_there;
univ.party.direction = set_direction(univ.town.p_loc, destination);
univ.town.p_loc = destination;
center = univ.town.p_loc;
return true;
}
else if ((is_blocked(destination) == false) || (forced == 1)) {
if (univ.party.in_horse >= 0) {
if (scenario.ter_types[ter].special == TER_SPEC_DAMAGING) {
ASB("Your horses quite sensibly refuse.");
return false;
}
if (scenario.ter_types[ter].block_horse == true) {
ASB("You can't take horses there!");
return false;
}
if ((univ.town->lighting_type > 0) && (get_ran(1,0,1) == 0)) {
ASB("The darkness spooks your horses.");
return false;
}
}
univ.party.direction = set_direction(univ.town.p_loc, destination);
univ.town.p_loc = destination;
sprintf ((char *) create_line, "Moved: %s",dir_string[univ.party.direction]);
add_string_to_buf((char *) create_line);
// place_treasure(destination,5,3);
move_sound(univ.town->terrain(destination.x,destination.y),(short) univ.party.age);
if (univ.party.in_boat >= 0) {
// Waterfall!!!
run_waterfalls(0);
}
if (univ.party.in_horse >= 0) {
univ.party.horses[univ.party.in_horse].loc = univ.town.p_loc;
univ.party.horses[univ.party.in_horse].which_town = univ.town.num;
}
center = univ.town.p_loc;
return true;
}
else {
if (is_door(destination) == true)
sprintf ((char *) create_line, "Door locked: %s ",dir_string[set_direction(univ.town.p_loc, destination)]);
else sprintf ((char *) create_line, "Blocked: %s ",dir_string[set_direction(univ.town.p_loc, destination)]);
add_string_to_buf((char *) create_line);
return false;
}
}
return false;
}
bool someone_poisoned()
{
short i;
for (i = 0; i < 6; i++)
if ((univ.party[i].main_status == 1) && (univ.party[i].status[2] > 0))
return true;
return false;
}
short nearest_monster()
{
short i = 100,j,s;
for (j = 0; j < 10; j++)
if (univ.party.out_c[j].exists == true) {
s = dist(univ.party.p_loc,univ.party.out_c[j].m_loc);
i = min(i,s);
}
return i;
}
void setup_outdoors(location where)
{
update_explored(where);
}
short get_outdoor_num()////
{
return (scenario.out_width * (univ.party.outdoor_corner.y + univ.party.i_w_c.y) + univ.party.outdoor_corner.x + univ.party.i_w_c.x);
}
short count_walls(location loc) // TODO: Generalize this function
{
unsigned char walls[31] = {5,6,7,8,9, 10,11,12,13,14, 15,16,17,18,19, 20,21,22,23,24,
25,26,27,28,29, 30,31,32,33,34, 35};
short answer = 0;
short k = 0;
for (k = 0; k < 31 ; k++) {
if (univ.out[loc.x + 1][loc.y] == walls[k])
answer++;
if (univ.out[loc.x - 1][loc.y] == walls[k])
answer++;
if (univ.out[loc.x][loc.y + 1] == walls[k])
answer++;
if (univ.out[loc.x][loc.y - 1] == walls[k])
answer++;
}
return answer;
}
bool is_sign(ter_num_t ter)
{
if (scenario.ter_types[ter].special == TER_SPEC_IS_A_SIGN)
return true;
return false;
}
bool check_for_interrupt(){
using kb = sf::Keyboard;
#ifdef __APPLE__
if((kb::isKeyPressed(kb::LSystem) || kb::isKeyPressed(kb::RSystem)) && kb::isKeyPressed(kb::Period))
return true;
#endif
if((kb::isKeyPressed(kb::LControl) || kb::isKeyPressed(kb::RControl)) && kb::isKeyPressed(kb::C))
return true;
return false;
}