added worldarea -> will be responsible for world map rendering
[dboe.git] / town.c
blob3502cd9f3eda6c962f3d329ee84c502ef0b364a9
3 #include <Windows.h>
4 #include "stdio.h"
6 #include "global.h"
8 #include "gutils.h"
9 #include "graphics.h"
10 #include "newgraph.h"
11 #include "fileio.h"
12 #include "items.h"
13 #include "itemdata.h"
14 #include "monster.h"
15 #include "town.h"
16 #include "combat.h"
17 #include "party.h"
18 #include "text.h"
19 #include "exlsound.h"
20 #include "fields.h"
21 #include "locutils.h"
22 #include "dlogtool.h"
23 #include "infodlgs.h"
24 #include "graphutl.h"
26 extern HBITMAP mixed_gworld,spec_scen_g;
27 extern current_town_type far c_town;
28 extern party_record_type far party;
29 extern pc_record_type far adven[6];
30 extern town_item_list far t_i;
31 extern short stat_window,overall_mode,store_spell_target,which_combat_type,current_pc,combat_active_pc;
32 extern location center;
33 extern HWND mainPtr;
34 extern short monst_target[T_M]; // 0-5 target that pc 6 - no target 100 + x - target monster x
35 extern unsigned char far combat_terrain[64][64];
36 extern outdoor_record_type far outdoors[2][2];
37 extern unsigned char far misc_i[64][64];
38 extern short store_current_pc,current_ground;
39 extern pascal Boolean cd_event_filter();
40 extern Boolean dialog_not_toast;
42 extern short store_pre_shop_mode,store_pre_talk_mode;
43 extern location monster_targs[T_M];
44 extern scenario_data_type far scenario;
46 extern Boolean modeless_exists[18],diff_depth_ok,belt_present;
47 extern short modeless_key[18];
48 extern HWND modeless_dialogs[18];
49 extern unsigned char far out[96][96];
50 extern unsigned char far out_e[96][96];
51 extern unsigned char far sfx[64][64];
52 extern stored_items_list_type far stored_items[3];
53 extern stored_town_maps_type far maps;
54 extern stored_outdoor_maps_type far o_maps;
55 extern big_tr_type far t_d;
56 extern short town_size[3];
57 extern short town_type;
58 extern setup_save_type far setup_save;
59 extern Boolean web,crate,barrel,fire_barrier,force_barrier,quickfire,force_wall,fire_wall,antimagic,scloud,ice_wall,blade_wall;
60 extern location pc_pos[6];
61 extern short last_attacked[6],pc_dir[6],pc_parry[6],pc_moves[6];
63 extern location hor_vert_place[14];
64 extern location diag_place[14];
65 extern short far terrain_pic[256];
66 extern char terrain_blocked[256];
67 extern location far golem_m_locs[16];
68 extern short special_queue[20];
70 extern HPALETTE hpal;
71 extern far PALETTEENTRY ape[256];
72 extern HDC main_dc,main_dc2,main_dc3;
73 extern HANDLE store_hInstance;
74 extern stored_town_maps_type far town_maps,town_maps2;
75 extern piles_of_stuff_dumping_type *data_store;
76 extern piles_of_stuff_dumping_type2 *data_store2;
77 extern stored_town_maps_type far town_maps,town_maps2;
79 extern short ulx,uly;
81 FARPROC map_proc = NULL;
83 // extra devices for maps
84 HBRUSH hbrush[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
85 HPEN hpen[6];
86 COLORREF map_colors[6] = {RGB(0,0,0),RGB(63,223,95),RGB(0,0,255),
87 RGB(191,0,191),RGB(255,0,0),RGB(204,204,204)};
89 RECT store_map_window_rect = {0,0,0,0};
91 Boolean need_map_full_refresh = TRUE,forcing_map_button_redraw = FALSE;
92 HBITMAP map_gworld;
93 HBRUSH bg[14];
94 HBRUSH map_brush[25];
95 HBITMAP map_bitmap[25];
96 extern HFONT small_bold_font;
98 unsigned char map_pats[256] = {1,1,2,2,2,7,7,7,7,7, ////
99 7,7,7,7,7,7,7,7,3,3,
100 3,3,3,3,3,3,3,3,3,3,
101 3,3,5,5,5,5,5,5,5,5,
102 5,5,5,5,5,5,4,4,4,4,
103 4,4,4,4,4,4,4,4,4,0, // 50
104 0,0,0,0,0,0,0,24,24,24,
105 16,16,25,25,0,0,0,0,18,8,
106 8,9,2,15,15,10,10,10,6,0,
107 0,0,0,0,0,0,0,0,0,0,
108 19,0,0,0,0,0,0,0,0,0, // 100
109 23,0,0,0,0,0,0,0,0,0,
110 0,0,0,11,0,0,0,0,0,0,
111 0,0,0,0,0,0,0,0,0,0,
112 0,0,0,0,0,0,0,0,0,0,
113 0,0,0,0,0,0,0,12,0,0, // 150
114 0,0,0,13,0,0,0,0,0,0,
115 0,0,0,0,0,0,0,0,0,0,
116 0,18,0,0,0,0,0,0,0,0,
117 0,0,0,0,0,0,0,0,0,0,
118 0,0,0,0,0,0,0,0,0,0, // 200
119 0,0,0,0,0,17,17,0,17,17,
120 17,17,17,17,17,17,0,0,0,0,
121 0,0,0,0,0,0,0,0,0,0,
122 0,0,0,0,0,0,0,0,0,0,
123 0,0,0,0,0,0};// 250
124 unsigned char anim_map_pats[18] = {14,0,0,0,22, 0,0,21,20,21, 20,0,0,0,0, 0,0,0};
126 long pause_dummy;
128 location town_map_adj = {0,0};
129 short town_force = 200,store_which_shop,store_min,store_max,store_shop,store_selling_pc;
130 short sell_offset = 0;
131 location town_force_loc;
132 Boolean shop_button_active[12];
133 RECT map_title_rect = {50,8,300,20}; /**/
134 // Rect map_bar_rect = {285,47,301,218};
135 RECT map_bar_rect = {230,2,400,10};
136 unsigned char far map_graphic_placed[8][64]; // keeps track of what's been filled on map
137 char the_string[256];
138 Boolean kludge_force_full_refresh = FALSE;
140 void force_town_enter(short which_town,location where_start)
142 town_force = which_town;
143 town_force_loc = where_start;
147 void start_town_mode(short which_town, short entry_dir)
148 //short entry_dir; // if 9, go to forced
150 short i,m,n;
151 long number_given;
152 char message[60];
153 short j,k,town_number;
154 short at_which_save_slot,former_town;
155 Boolean monsters_loaded = FALSE,town_toast = FALSE;
156 location loc;
157 unsigned char temp;
158 Boolean play_town_sound = FALSE;
161 if (town_force < 200)
162 which_town = town_force;
163 else if (PSD[304][9] == 0) {
164 play_town_sound = TRUE;
168 former_town = town_number = which_town;
170 if ((town_number < 0) || (town_number >= scenario.num_towns)) {
171 give_error("The scenario tried to put you into a town that doesn't exist.","",0);
172 return;
176 // Now adjust town number as necessary.
177 for (i = 0; i < 10; i++)
178 if ((scenario.town_to_add_to[i] >= 0) && (scenario.town_to_add_to[i] < 200) &&
179 (town_number == scenario.town_to_add_to[i]) &&
180 (sd_legit(scenario.flag_to_add_to_town[i][0],scenario.flag_to_add_to_town[i][1]) == TRUE)) {
181 former_town = town_number;
182 town_number += PSD[scenario.flag_to_add_to_town[i][0]][scenario.flag_to_add_to_town[i][1]];
183 // Now update horses & boats
184 for (i = 0; i < 30; i++)
185 if ((party.horses[i].exists == TRUE) && (party.horses[i].which_town == former_town))
186 party.horses[i].which_town = town_number;
187 for (i = 0; i < 30; i++)
188 if ((party.boats[i].exists == TRUE) && (party.boats[i].which_town == former_town))
189 party.boats[i].which_town = town_number;
194 if ((town_number < 0) || (town_number >= scenario.num_towns)) {
195 give_error("The scenario tried to put you into a town that doesn't exist.","",0);
196 return;
198 overall_mode = 1;
200 load_town(town_number,0,0,NULL);
202 c_town.town_num = town_number;
204 if (play_town_sound == TRUE) {
205 if (c_town.town.lighting > 0)
206 play_sound(95);
207 else play_sound(16);
213 belt_present = FALSE;
214 // Set up map, using stored map
215 for (i = 0; i < town_size[town_type]; i++)
216 for (j = 0; j < town_size[town_type]; j++) {
217 c_town.explored[i][j] = 0;
218 if (c_town.town_num < 100) {
219 if (town_maps.town_maps[c_town.town_num][i / 8][j] & (char)(s_pow(2,i % 8)))
220 make_explored(i,j);
222 else {
223 if (town_maps2.town_maps[c_town.town_num - 100][i / 8][j] & (char)(s_pow(2,i % 8)))
224 make_explored(i,j);
226 if (t_d.terrain[i][j] == 0)
227 current_ground = 0;
228 else if (t_d.terrain[i][j] == 2)
229 current_ground = 2;
230 if ((scenario.ter_types[t_d.terrain[i][j]].special >= 16) &&
231 (scenario.ter_types[t_d.terrain[i][j]].special <= 19))
232 belt_present = TRUE;
234 c_town.hostile = 0;
235 c_town.monst.which_town = town_number;
236 c_town.monst.friendly = 0;
238 at_which_save_slot = party.at_which_save_slot;
240 for (i = 0; i < 4; i++)
241 if (town_number == party.creature_save[i].which_town) {
242 c_town.monst = party.creature_save[i];
243 monsters_loaded = TRUE;
245 for (j = 0; j < T_M; j++) {
246 if (loc_off_act_area(c_town.monst.dudes[j].m_loc) == TRUE)
247 c_town.monst.dudes[j].active = 0;
248 if (c_town.monst.dudes[j].active == 2)
249 c_town.monst.dudes[j].active = 1;
250 c_town.monst.dudes[j].m_loc = t_d.creatures[j].start_loc;
251 c_town.monst.dudes[j].m_d.health = c_town.monst.dudes[j].m_d.m_health;
252 c_town.monst.dudes[j].m_d.mp = c_town.monst.dudes[j].m_d.max_mp;
253 c_town.monst.dudes[j].m_d.morale = c_town.monst.dudes[j].m_d.m_morale;
254 for (k = 0; k < 15; k++)
255 c_town.monst.dudes[j].m_d.status[k] = 0;
256 if (c_town.monst.dudes[j].summoned > 0)
257 c_town.monst.dudes[j].active = 0;
258 monst_target[j] = 6;
261 // Now, travelling NPCs might have arrived. Go through and put them in.
262 // These should have protected status (i.e. spec1 >= 200, spec1 <= 204)
263 for (j = 0; j < T_M; j++)
264 if ((c_town.monst.dudes[j].monst_start.time_flag >= 4) &&
265 (c_town.monst.dudes[j].monst_start.time_flag <= 6)) {
266 if ((((short) (party.age / 1000) % 3) + 4) != c_town.monst.dudes[j].monst_start.time_flag)
267 c_town.monst.dudes[j].active = 0;
268 else {
269 c_town.monst.dudes[j].active = 1;
270 c_town.monst.dudes[j].monst_start.spec_enc_code = 0;
271 // Now remove time flag so it doesn't geet reappearing
272 c_town.monst.dudes[j].monst_start.time_flag = 0;
273 c_town.monst.dudes[j].m_loc = t_d.creatures[j].start_loc;
274 c_town.monst.dudes[j].m_d.health = c_town.monst.dudes[j].m_d.m_health;
280 for (j = 0; j < town_size[town_type]; j++)
281 for (k = 0; k < town_size[town_type]; k++) { // now load in saved setup,
282 // except that barrels and crates resotre to orig locs
283 temp = setup_save.setup[i][j][k] & 231;
285 misc_i[j][k] = (misc_i[j][k] & 24) | temp;//setup_save.setup[i][j][k];
289 if (monsters_loaded == FALSE) {
290 for (i = 0; i < T_M; i++)
291 if (t_d.creatures[i].number == 0) {
292 c_town.monst.dudes[i].active = 0;
293 c_town.monst.dudes[i].number = 0;
294 c_town.monst.dudes[i].monst_start.time_flag = 0;
295 c_town.monst.dudes[i].m_loc.x = 80;
297 else {
298 // First set up the values.
299 monst_target[i] = 6;
300 c_town.monst.dudes[i].active = 1;
301 c_town.monst.dudes[i].number = t_d.creatures[i].number;
302 c_town.monst.dudes[i].attitude = t_d.creatures[i].start_attitude;
303 c_town.monst.dudes[i].m_loc = t_d.creatures[i].start_loc;
304 c_town.monst.dudes[i].mobile = t_d.creatures[i].mobile;
305 c_town.monst.dudes[i].m_d = return_monster_template(c_town.monst.dudes[i].number);
307 c_town.monst.dudes[i].summoned = 0;
308 c_town.monst.dudes[i].monst_start = t_d.creatures[i];
310 if (c_town.monst.dudes[i].monst_start.spec_enc_code > 0)
311 c_town.monst.dudes[i].active = 0;
313 // Now, if necessary, fry the monster.
314 switch (c_town.monst.dudes[i].monst_start.time_flag) {
315 case 1:
316 if (day_reached(c_town.monst.dudes[i].monst_start.monster_time,
317 c_town.monst.dudes[i].monst_start.time_code) == FALSE)
318 c_town.monst.dudes[i].active = 0;
319 break;
320 case 2:
321 if (day_reached(c_town.monst.dudes[i].monst_start.monster_time,
322 c_town.monst.dudes[i].monst_start.time_code) == TRUE)
323 c_town.monst.dudes[i].active = 0;
324 break;
325 case 3:
326 // unused
327 break;
328 case 4: case 5: case 6:
329 if ((((short) (party.age / 1000) % 3) + 4) != c_town.monst.dudes[i].monst_start.time_flag) {
330 c_town.monst.dudes[i].active = 0;
331 c_town.monst.dudes[i].monst_start.spec_enc_code = 50;
333 else {
334 c_town.monst.dudes[i].active = 1;
335 // Now remove time flag so it doesn't keep reappearing
336 c_town.monst.dudes[i].monst_start.time_flag = 0;
338 break;
339 case 7:
340 if (calc_day() < party.key_times[c_town.monst.dudes[i].monst_start.time_code])
341 c_town.monst.dudes[i].active = 0;
342 break;
344 case 8:
345 if (calc_day() > party.key_times[c_town.monst.dudes[i].monst_start.time_code])
346 c_town.monst.dudes[i].active = 0;
347 break;
348 case 9:
349 if (c_town.town.town_chop_time > 0)
350 if (day_reached(c_town.town.town_chop_time,c_town.town.town_chop_key) == TRUE) {
351 c_town.monst.dudes[i].active += 10;
352 break;
354 c_town.monst.dudes[i].active = 0;
355 break;
356 case 0:
357 break;
358 default:
359 //ASB("ERROR! Odd character data.");
360 //print_nums(0,i,c_town.monst.dudes[i].monst_start.time_flag);
361 break; }
365 // Now munch all large monsters that are misplaced
366 // only large monsters, as some smaller monsters are intentionally placed
367 // where they cannot be
368 for (i = 0; i < T_M; i++) {
369 if (c_town.monst.dudes[i].active > 0)
370 if (((c_town.monst.dudes[i].m_d.x_width > 1) || (c_town.monst.dudes[i].m_d.y_width > 1)) &&
371 (monst_can_be_there(c_town.monst.dudes[i].m_loc,i) == FALSE))
372 c_town.monst.dudes[i].active = 0;
374 // Thrash town?
375 if (party.m_killed[c_town.town_num] > c_town.town.max_num_monst) {
376 town_toast = TRUE;
377 add_string_to_buf("Area has been cleaned out.");
379 if (c_town.town.town_chop_time > 0) {
380 if (day_reached(c_town.town.town_chop_time,c_town.town.town_chop_key) == TRUE){
381 //add_string_to_buf("Area has been abandoned.");
382 for (i = 0; i < T_M; i++)
383 if ((c_town.monst.dudes[i].active > 0) && (c_town.monst.dudes[i].active < 10) &&
384 (c_town.monst.dudes[i].attitude % 2 == 1))
385 c_town.monst.dudes[i].active += 10;
386 town_toast = TRUE;
389 if (town_toast == TRUE) {
390 for (i = 0; i < T_M; i++)
391 if (c_town.monst.dudes[i].active >= 10)
392 c_town.monst.dudes[i].active -= 10;
393 else c_town.monst.dudes[i].active = 0;
395 handle_town_specials(town_number, (short) town_toast,(entry_dir < 9) ? c_town.town.start_locs[entry_dir] : town_force_loc);
396 // Flush excess doomguards and viscous goos
397 for (i = 0; i < T_M; i++)
398 if ((c_town.monst.dudes[i].m_d.spec_skill == 12) &&
399 (c_town.monst.dudes[i].number != t_d.creatures[i].number))
400 c_town.monst.dudes[i].active = 0;
403 quickfire = FALSE;
404 crate = FALSE;
405 barrel = FALSE;
406 web = FALSE;
407 fire_barrier = FALSE;
408 force_barrier = FALSE;
409 // Set up field booleans, correct for doors
410 for (j = 0; j < town_size[town_type]; j++)
411 for (k = 0; k < town_size[town_type]; k++) {
412 loc.x = j; loc.y = k;
413 if (is_door(loc) == TRUE)
414 misc_i[j][k] = misc_i[j][k] & 3;
416 // Set up field booleans
417 if (is_web(j,k) == TRUE)
418 web = TRUE;
419 if (is_crate(j,k) == TRUE)
420 crate = TRUE;
421 if (is_barrel(j,k) == TRUE)
422 barrel = TRUE;
423 if (is_fire_barrier(j,k) == TRUE)
424 fire_barrier = TRUE;
425 if (is_force_barrier(j,k) == TRUE)
426 force_barrier = TRUE;
427 if (is_quickfire(j,k) == TRUE)
428 quickfire = TRUE;
431 // Set up items, maybe place items already there
432 for (i = 0; i < NUM_TOWN_ITEMS; i++)
433 t_i.items[i] = return_dummy_item();
436 for (j = 0; j < 3; j++)
437 if (scenario.store_item_towns[j] == town_number) {
438 for (i = 0; i < NUM_TOWN_ITEMS; i++)
439 t_i.items[i] = stored_items[j].items[i];
442 //print_nums(party.item_taken[c_town.town_num][0],party.item_taken[c_town.town_num][1],party.item_taken[c_town.town_num][2]);
443 //print_nums(party.item_taken[c_town.town_num][3],party.item_taken[c_town.town_num][4],party.item_taken[c_town.town_num][5]);
444 //print_nums(party.item_taken[c_town.town_num][6],party.item_taken[c_town.town_num][7],999);
445 for (i = 0; i < 64; i++)
446 if ((c_town.town.preset_items[i].item_code >= 0)
447 && (((party.item_taken[c_town.town_num][i / 8] & s_pow(2,i % 8)) == 0) ||
448 (c_town.town.preset_items[i].always_there == TRUE))) {
449 for (j = 0; j < NUM_TOWN_ITEMS; j++)
451 // place the preset item, if party hasn't gotten it already
452 if (t_i.items[j].variety == 0) {
453 t_i.items[j] = get_stored_item(c_town.town.preset_items[i].item_code);
454 t_i.items[j].item_loc = c_town.town.preset_items[i].item_loc;
456 // Not use the items data flags, starting with forcing an ability
457 if (c_town.town.preset_items[i].ability >= 0) {
458 switch (t_i.items[j].variety) {
459 case 3: case 11: // If gold or food, this value is amount
460 if (c_town.town.preset_items[i].ability > 0)
461 t_i.items[j].item_level = c_town.town.preset_items[i].ability;
462 break;
466 if (c_town.town.preset_items[i].property == TRUE)
467 t_i.items[j].item_properties = t_i.items[j].item_properties | 2;
468 if (town_toast == TRUE)
469 t_i.items[j].item_properties = t_i.items[j].item_properties & 253;
470 if (c_town.town.preset_items[i].contained == TRUE)
471 t_i.items[j].item_properties = t_i.items[j].item_properties | 8;
472 t_i.items[j].is_special = i + 1;
474 j = NUM_TOWN_ITEMS;
479 for (i = 0; i < T_M; i++)
480 if (loc_off_act_area(c_town.monst.dudes[i].m_loc) == TRUE)
481 c_town.monst.dudes[i].active = 0;
482 for (i = 0; i < NUM_TOWN_ITEMS; i++)
483 if (loc_off_act_area(t_i.items[i].item_loc) == TRUE)
484 t_i.items[i].variety = 0;
486 // Clean out unwanted monsters
487 for (i = 0; i < T_M; i++)
488 if (sd_legit(c_town.monst.dudes[i].monst_start.spec1,c_town.monst.dudes[i].monst_start.spec2) == TRUE) {
489 if (party.stuff_done[c_town.monst.dudes[i].monst_start.spec1][c_town.monst.dudes[i].monst_start.spec2] > 0)
490 c_town.monst.dudes[i].active = 0;
493 erase_specials();
494 make_town_trim(0);
496 load_area_graphics();
499 c_town.p_loc = (entry_dir < 9) ? c_town.town.start_locs[entry_dir] : town_force_loc;
500 center = c_town.p_loc;
501 if (party.in_boat >= 0) {
502 party.boats[party.in_boat].which_town = which_town;
503 party.boats[party.in_boat].boat_loc = c_town.p_loc;
505 if (party.in_horse >= 0) {
506 party.horses[party.in_horse].which_town = which_town;
507 party.horses[party.in_horse].horse_loc = c_town.p_loc;
511 // End flying
512 if (party.stuff_done[305][1] > 0) {
513 party.stuff_done[305][1] = 0;
514 add_string_to_buf("You land, and enter. ");
517 // No hostile monsters present.
518 party.stuff_done[305][9] = 0;
520 add_string_to_buf("Now entering:");
521 sprintf ((char *) message, " %-30.30s ",data_store->town_strs[0]);
522 add_string_to_buf((char *) message);
525 // clear entry space, and check exploration
526 misc_i[c_town.p_loc.x][c_town.p_loc.y] = misc_i[c_town.p_loc.x][c_town.p_loc.y] & 3;
527 update_explored(c_town.p_loc);
529 // If a PC dead, drop his items
530 for (m = 0; m < 6; m++)
531 for (n = 0; n < 24; n++)
532 if ((adven[m].main_status != 1) && (adven[m].items[n].variety != 0)) {
533 place_item(adven[m].items[n],c_town.p_loc,TRUE);
534 adven[m].items[n].variety = 0;
537 for (i = 0; i < T_M; i++)
538 {monster_targs[i].x = 0; monster_targs[i].y = 0;}
541 //// check horses
542 for (i = 0; i < 30; i++) {
543 if ((scenario.scen_boats[i].which_town >= 0) && (scenario.scen_boats[i].boat_loc.x >= 0)) {
544 if (party.boats[i].exists == FALSE) {
545 party.boats[i] = scenario.scen_boats[i];
546 party.boats[i].exists = TRUE;
549 if ((scenario.scen_horses[i].which_town >= 0) && (scenario.scen_horses[i].horse_loc.x >= 0)) {
550 if (party.horses[i].exists == FALSE) {
551 party.horses[i] = scenario.scen_horses[i];
552 party.horses[i].exists = TRUE;
557 // Place correct graphics
558 redraw_screen(0);
561 clear_map();
562 reset_item_max();
563 town_force = 200;
567 location end_town_mode(short switching_level,location destination) // returns new party location
569 location to_return;
570 short i,j,k,exit_code;
571 Boolean data_saved = FALSE,combat_end = FALSE;
573 if (is_combat())
574 combat_end = TRUE;
576 if (overall_mode == 1) {
577 for (i = 0; i < 4; i++)
578 if (party.creature_save[i].which_town == c_town.town_num) {
579 party.creature_save[i] = c_town.monst;
580 for (j = 0; j < town_size[town_type]; j++)
581 for (k = 0; k < town_size[town_type]; k++)
582 setup_save.setup[i][j][k] = misc_i[j][k];
583 data_saved = TRUE;
585 if (data_saved == FALSE) {
586 party.creature_save[party.at_which_save_slot] = c_town.monst;
587 for (j = 0; j < town_size[town_type]; j++)
588 for (k = 0; k < town_size[town_type]; k++)
589 setup_save.setup[party.at_which_save_slot][j][k] = misc_i[j][k];
590 party.at_which_save_slot = (party.at_which_save_slot == 3) ? 0 : party.at_which_save_slot + 1;
593 // Store items, if necessary
594 for (j = 0; j < 3; j++)
595 if (scenario.store_item_towns[j] == c_town.town_num) {
596 for (i = 0; i < NUM_TOWN_ITEMS; i++)
597 if ((t_i.items[i].variety != 0) && (t_i.items[i].is_special == 0) &&
598 ((t_i.items[i].item_loc.x >= scenario.store_item_rects[j].left) &&
599 (t_i.items[i].item_loc.x <= scenario.store_item_rects[j].right) &&
600 (t_i.items[i].item_loc.y >= scenario.store_item_rects[j].top) &&
601 (t_i.items[i].item_loc.y <= scenario.store_item_rects[j].bottom)) ) {
602 stored_items[j].items[i] = t_i.items[i];
604 else stored_items[j].items[i].variety = 0;
608 // Clean up special data, just in case
609 for (i = 0; i < T_M; i++) {
610 c_town.monst.dudes[i].monst_start.spec1 = 0;
611 c_town.monst.dudes[i].monst_start.spec2 = 0;
614 // Now store map
615 for (i = 0; i < town_size[town_type]; i++)
616 for (j = 0; j < town_size[town_type]; j++)
617 if (is_explored(i,j) > 0) {
618 if (c_town.town_num < 100)
619 town_maps.town_maps[c_town.town_num][i / 8][j] = town_maps.town_maps[c_town.town_num][i / 8][j] |
620 (char) (s_pow(2,i % 8));
621 else town_maps2.town_maps[c_town.town_num - 100][i / 8][j] = town_maps.town_maps[c_town.town_num][i / 8][j] |
622 (char) (s_pow(2,i % 8));
626 to_return = party.p_loc;
628 for (i = 0; i < 30; i++)
629 if ((party.party_event_timers[i] > 0) && (party.global_or_town[i] == 1))
630 party.party_event_timers[i] = 0;
634 // Check for exit specials, if leaving town
635 if (switching_level == 0) {
636 to_return = party.p_loc;
638 if (is_town()) {
639 if (destination.x <= c_town.town.in_town_rect.left) {
640 if (c_town.town.exit_locs[1].x > 0)
641 to_return = local_to_global(c_town.town.exit_locs[1]);
642 else to_return.x--;
643 party.p_loc = to_return; party.p_loc.x++;
644 handle_leave_town_specials(c_town.town_num, c_town.town.exit_specs[1],destination) ;
646 else if (destination.x >= c_town.town.in_town_rect.right) {
647 if (c_town.town.exit_locs[3].x > 0)
648 to_return = local_to_global(c_town.town.exit_locs[3]);
649 else to_return.x++;
650 party.p_loc = to_return; party.p_loc.x--;
651 handle_leave_town_specials(c_town.town_num, c_town.town.exit_specs[3],destination) ;
653 else if (destination.y <= c_town.town.in_town_rect.top) {
654 if (c_town.town.exit_locs[0].x > 0)
655 to_return = local_to_global(c_town.town.exit_locs[0]);
656 else to_return.y--;
657 party.p_loc = to_return; party.p_loc.y++;
658 handle_leave_town_specials(c_town.town_num, c_town.town.exit_specs[0],destination) ;
660 else if (destination.y >= c_town.town.in_town_rect.bottom) {
661 if (c_town.town.exit_locs[2].x > 0)
662 to_return = local_to_global(c_town.town.exit_locs[2]);
663 else to_return.y++;
664 party.p_loc = to_return; party.p_loc.y--;
665 handle_leave_town_specials(c_town.town_num, c_town.town.exit_specs[2],destination) ;
671 if (switching_level == 0) {
672 fix_boats();
673 overall_mode = 0;
675 erase_out_specials();
677 load_area_graphics();
679 party.stuff_done[305][0] = 0;
680 for (i = 0; i < 6; i++)
681 for (j = 0; j < 15; j++)
682 if ((j != 2) && (j != 7) && (j != 9))
683 adven[i].status[j] = 0;
686 update_explored(to_return);
687 redraw_screen(0);
694 if (combat_end == FALSE)
695 clear_map();
697 return to_return;
701 void handle_town_specials(short town_number, short entry_dir,location start_loc)
703 short s1,s2,s3;
705 if (entry_dir > 0)
706 special_queue[0] = c_town.town.spec_on_entry_if_dead;
707 else special_queue[0] = c_town.town.spec_on_entry;
710 void handle_leave_town_specials(short town_number, short which_spec,location start_loc)
712 short s1,s2,s3;
714 //run_special(6,2,which_spec,start_loc,&s1,&s2,&s3);
715 special_queue[1] = which_spec;
718 Boolean abil_exists(short abil) // use when outdoors
720 short i,j;
722 for (i = 0; i < 6; i++)
723 for (j = 0; j < 24; j++)
724 if ((adven[i].items[j].variety != 0) && (adven[i].items[j].ability == abil))
725 return TRUE;
726 for (i = 0; i < 3; i++)
727 for (j = 0; j < NUM_TOWN_ITEMS; j++)
728 if ((stored_items[i].items[j].variety != 0) && (stored_items[i].items[j].ability == abil))
729 return TRUE;
731 return FALSE;
737 void start_town_combat(short direction)
739 short i,j,r1,r2,how_many,num_tries = 0;
741 create_town_combat_terrain();
743 place_party(direction);
745 if (current_pc == 6) {
746 for (i = 0; i < 6; i++)
747 if (adven[i].main_status == 1) {
748 current_pc = i;
749 i = 6;
752 center = pc_pos[current_pc];
754 which_combat_type = 1;
755 overall_mode = 10;
757 combat_active_pc = 6;
758 for (i = 0; i < T_M; i++)
759 monst_target[i] = 6;
761 for (i = 0; i < 6; i++) {
762 last_attacked[i] = T_M + 10;
763 pc_parry[i] = 0;
764 pc_dir[i] = direction;
765 adven[current_pc].direction = direction;
766 if (adven[i].main_status == 1)
767 update_explored(pc_pos[i]);
770 store_current_pc = current_pc;
771 current_pc = 0;
772 set_pc_moves();
773 pick_next_pc();
774 center = pc_pos[current_pc];
775 draw_buttons(0);
776 put_pc_screen();
777 set_stat_window(current_pc);
778 give_help(48,49,0);
782 short end_town_combat()
784 short num_tries = 0,r1,i;
786 r1 = get_ran(1,0,5);
787 while ((adven[r1].main_status != 1) && (num_tries++ < 1000))
788 r1 = get_ran(1,0,5);
789 c_town.p_loc = pc_pos[r1];
790 overall_mode = 1;
791 current_pc = store_current_pc;
792 if (adven[current_pc].main_status != 1)
793 current_pc = first_active_pc();
794 for (i = 0; i < 6; i++) {
795 pc_parry[i] = 0;
797 return pc_dir[r1];
800 void place_party(short direction)
802 Boolean spot_ok[14] = {TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,
803 TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE};
804 location pos_locs[14];
805 location check_loc;
806 short x_adj,y_adj,how_many_ok = 1,where_in_a = 0,i;
808 for (i = 0; i < 14; i++) {
809 check_loc = c_town.p_loc;
810 if (direction % 4 < 2)
811 x_adj = ((direction % 2 == 0) ? hor_vert_place[i].x : diag_place[i].x);
812 else x_adj = ((direction % 2 == 0) ? hor_vert_place[i].y : diag_place[i].y);
813 if (direction % 2 == 0)
814 x_adj = (direction < 4) ? x_adj : -1 * x_adj;
815 else x_adj = ((direction == 1) || (direction == 7)) ? -1 * x_adj : x_adj;
816 check_loc.x -= x_adj;
817 if (direction % 4 < 2)
818 y_adj = ((direction % 2 == 0) ? hor_vert_place[i].y : diag_place[i].y);
819 else y_adj = ((direction % 2 == 0) ? hor_vert_place[i].x : diag_place[i].x);
820 if (direction % 2 == 0)
821 y_adj = ((direction > 1) && (direction < 6)) ? y_adj : -1 * y_adj;
822 else y_adj = ((direction == 3) || (direction == 1)) ? -1 * y_adj : y_adj;
824 check_loc.y -= y_adj;
825 pos_locs[i] = check_loc;
826 if ((loc_off_act_area(check_loc) == FALSE) &&
827 (is_blocked(check_loc) == FALSE) && (is_special(check_loc) == FALSE) && (get_obscurity(check_loc.x,check_loc.y) == 0)
828 && (can_see(c_town.p_loc,check_loc,1) < 1)) {
829 spot_ok[i] = TRUE;
830 how_many_ok += (i > 1) ? 1 : 0;
832 else spot_ok[i] = FALSE;
834 if (i == 0)
835 spot_ok[i] = TRUE;
837 i = 0;
838 while (i < 6) {
839 if (adven[i].main_status == 1) {
840 if (how_many_ok == 1)
841 pc_pos[i] = pos_locs[where_in_a];
842 else {
843 pc_pos[i] = pos_locs[where_in_a];
844 if (how_many_ok > 1)
845 where_in_a++;
846 how_many_ok--;
847 // if (how_many_ok > 1) {
848 while (spot_ok[where_in_a] == FALSE)
849 where_in_a++;
850 // }
853 i++;
859 void create_town_combat_terrain()
861 short id;
862 location where;
864 for (where.x = 0; where.x < town_size[town_type]; where.x++)
865 for (where.y = 0; where.y < town_size[town_type]; where.y++)
866 combat_terrain[where.x][where.y] = t_d.terrain[where.x][where.y];
869 void create_out_combat_terrain(short type,short num_walls,short spec_code)
870 // spec_code is encounter's spec_code
872 short i,j,k,l,r1,r2,ter_type;
873 // 0 grass 1 cave 2 mntn 3 bridge 4 cave bridge 5 rubble cave 6 cave tree 7 cave mush
874 // 8 cave swamp 9 surfac eorcks 10 surf swamp 11 surface woods 12 s. shrub 13 stalags
875 short general_types[260] = {1,1,0,0,0,1,1,1,1,1,
876 1,1,1,1,1,1,1,1,2,2,
877 2,2,2,2,2,2,2,2,2,2,
878 2,2,2,2,2,2,2,2,2,2,
879 2,2,2,2,2,2,0,0,0,0,
880 0,0,0,0,0,0,0,0,0,0,// 50
881 0,3,3,3,3,3,3,5,5,5,
882 6,6,7,7,1,1,8,9,10,11,
883 10,11,12,13,13,9,9,9,1,1,
884 1,1,1,1,1,1,1,1,1,1,
885 1,1,1,1,1,1,1,1,1,1,// 100
886 1,1,1,1,1,1,1,1,1,1,
887 1,1,1,1,1,1,1,1,1,1,
888 1,1,1,1,1,1,1,1,1,1,
889 1,1,1,1,1,1,1,1,1,1,
890 1,1,1,1,1,1,1,1,1,1,// 150
891 1,1,1,1,1,1,1,1,1,1,
892 1,1,1,1,1,1,1,1,1,1,
893 1,0,1,1,1,1,1,1,1,0,
894 0,0,0,0,1,0,0,0,0,0,
895 0,0,1,0,2,0,0,1,1,1,// 200
896 1,0,2,1,1,0,1,1,1,1,
897 1,1,0,0,0,0,1,0,1,1,
898 1,1,1,1,1,1,1,1,1,1,
899 1,1,1,1,1,1,1,1,1,1,
900 1,1,1,1,1,1,1,1,1,1};// 250
901 short ter_base[14] = {2,0,36,50,71, 0,0,0,0,2, 2,2,2,0};
902 short ground_type[14] = {2,0,36,50,71, 0,0,0,0,2, 2,2,2,0};
904 location special_ter_locs[15] = {{11,10},{11,14},{10,20},{11,26},{9,30},
905 {15,19},{23,19},{19,29},{20,11},{28,16},
906 {28,24},{27,19},{27,29},{15,28},{19,19}};
907 unsigned char cave_pillar[4][4] = {{0,14,11,1},{14,19,20,11},{17,18,21,8},{1,17,8,0}};
908 unsigned char mntn_pillar[4][4] = {{37,29,27,36},{29,33,34,27},{31,32,35,25},{36,31,25,37}};
909 unsigned char surf_lake[4][4] = {{56,55,54,3},{57,50,61,54},{58,51,59,53},{3,4,58,52}};
910 unsigned char cave_lake[4][4] = {{93,96,71,71},{96,71,71,71},{71,71,71,96},{71,71,71,96}};
911 location stuff_ul;
912 short terrain_odds[14][10] = {{3,80,4,40,115,20,114,10,112,1},
913 {1,50,93,25,94,5,98,10,95,1},
914 {37,20,0,0,0,0,0,0,0,0},
915 {64,3,63,1,0,0,0,0,0,0},
916 {74,1,0,0,0,0,0,0,0,0},
917 {84,700,97,30,98,20,92,4,95,1},
918 {93,280,91,300,92,270,95,7,98,10},
919 {1,800,93,600,94,10,92,10,95,4},
920 {1,700,96,200,95,100,92,10,112,5},
921 {3,600,87,90,110,20,114,6,113,2},
922 {3,200,4,400,111,250,0,0,0,0},
923 {3,200,4,300,112,50,113,60,114,100},
924 {3,100,4,250,115,120,114,30,112,2},
925 {1,25,84,15,98,300,97,280,0,0}}; // ter then odds then ter then odds ...
926 item_record_type store_i;
928 ter_type = scenario.ter_types[type].picture;
929 if (ter_type > 260)
930 ter_type = 1;
931 else ter_type = general_types[ter_type];
933 for (i = 0; i < 48; i++)
934 for (j = 0; j < 48; j++) {
935 c_town.explored[i][j] = 0;
936 misc_i[i][j] = 0;
937 sfx[i][j] = 0;
938 if ((j <= 8) || (j >= 35) || (i <= 8) || (i >= 35))
939 t_d.terrain[i][j] = 90;
940 else t_d.terrain[i][j] = ter_base[ter_type];
942 for (i = 0; i < 48; i++)
943 for (j = 0; j < 48; j++)
944 for (k = 0; k < 5; k++)
945 if ((t_d.terrain[i][j] != 90) && (get_ran(1,1,1000) < terrain_odds[ter_type][k * 2 + 1]))
946 t_d.terrain[i][j] = terrain_odds[ter_type][k * 2];
948 t_d.terrain[0][0] = ter_base[ter_type];
950 if ((ter_type == 3) || (ter_type == 4) ) {
951 t_d.terrain[0][0] = 83;
952 for (i = 15; i < 26; i++)
953 for (j = 9; j < 35; j++)
954 t_d.terrain[i][j] = 83;
956 if ((type >= 79) && (type <= 81)) {
957 t_d.terrain[0][0] = 82;
958 for (i = 19; i < 23; i++)
959 for (j = 9; j < 35; j++)
960 t_d.terrain[i][j] = 82;
964 // Now place special lakes, etc.
965 if (ter_type == 2)
966 for (i = 0; i < 15; i++)
967 if (get_ran(1,0,5) == 1) {
968 stuff_ul = special_ter_locs[i];
969 for (j = 0; j < 4; j++)
970 for (k = 0; k < 4; k++)
971 t_d.terrain[stuff_ul.x + j][stuff_ul.y + k] = mntn_pillar[k][j];
973 if (t_d.terrain[0][0] == 0)
974 for (i = 0; i < 15; i++)
975 if (get_ran(1,0,25) == 1) {
976 stuff_ul = special_ter_locs[i];
977 for (j = 0; j < 4; j++)
978 for (k = 0; k < 4; k++)
979 t_d.terrain[stuff_ul.x + j][stuff_ul.y + k] = cave_pillar[k][j];
981 if (t_d.terrain[0][0] == 0)
982 for (i = 0; i < 15; i++)
983 if (get_ran(1,0,40) == 1) {
984 stuff_ul = special_ter_locs[i];
985 for (j = 0; j < 4; j++)
986 for (k = 0; k < 4; k++)
987 t_d.terrain[stuff_ul.x + j][stuff_ul.y + k] = cave_lake[k][j];
989 if (t_d.terrain[0][0] == 2)
990 for (i = 0; i < 15; i++)
991 if (get_ran(1,0,40) == 1) {
992 stuff_ul = special_ter_locs[i];
993 for (j = 0; j < 4; j++)
994 for (k = 0; k < 4; k++)
995 t_d.terrain[stuff_ul.x + j][stuff_ul.y + k] = surf_lake[k][j];
999 if (ground_type[ter_type] == 0) {
1000 for (i = 0; i < num_walls; i++) {
1001 r1 = get_ran(1,0,3);
1002 for (j = 9; j < 35; j++)
1003 switch (r1) {
1004 case 0:
1005 t_d.terrain[j][8] = 6;
1006 break;
1007 case 1:
1008 t_d.terrain[8][j] = 9;
1009 break;
1010 case 2:
1011 t_d.terrain[j][35] = 12;
1012 break;
1013 case 3:
1014 t_d.terrain[32][j] = 15;
1015 break;
1018 if ((t_d.terrain[17][8] == 6) && (t_d.terrain[8][20] == 9))
1019 t_d.terrain[8][8] = 21;
1020 if ((t_d.terrain[32][20] == 15) && (t_d.terrain[17][35] == 12))
1021 t_d.terrain[32][35] = 19;
1022 if ((t_d.terrain[17][8] == 6) && (t_d.terrain[32][20] == 15))
1023 t_d.terrain[32][8] = 32;
1024 if ((t_d.terrain[8][20] == 9) && (t_d.terrain[17][35] == 12))
1025 t_d.terrain[8][35] = 20;
1027 if (ground_type[ter_type] == 36) {
1028 for (i = 0; i < num_walls; i++) {
1029 r1 = get_ran(1,0,3);
1030 for (j = 9; j < 35; j++)
1031 switch (r1) {
1032 case 0:
1033 t_d.terrain[j][8] = 24;
1034 break;
1035 case 1:
1036 t_d.terrain[8][j] = 26;
1037 break;
1038 case 2:
1039 t_d.terrain[j][35] = 28;
1040 break;
1041 case 3:
1042 t_d.terrain[32][j] = 30;
1043 break;
1046 if ((t_d.terrain[17][8] == 6) && (t_d.terrain[8][20] == 9))
1047 t_d.terrain[8][8] = 35;
1048 if ((t_d.terrain[32][20] == 15) && (t_d.terrain[17][35] == 12))
1049 t_d.terrain[32][35] = 33;
1050 if ((t_d.terrain[17][8] == 6) && (t_d.terrain[32][20] == 15))
1051 t_d.terrain[32][8] = 32;
1052 if ((t_d.terrain[8][20] == 9) && (t_d.terrain[17][35] == 12))
1053 t_d.terrain[8][35] = 34;
1056 for (i = 0; i < 48; i++)
1057 for (j = 0; j < 48; j++)
1058 combat_terrain[i][j] = t_d.terrain[i][j];
1060 make_town_trim(1);
1064 void elim_monst(unsigned char which,short spec_a,short spec_b)
1066 short i;
1068 if (party.stuff_done[spec_a][spec_b] > 0) {
1069 for (i = 0; i < T_M; i++)
1070 if (c_town.monst.dudes[i].number == which) {
1071 c_town.monst.dudes[i].active = 0;
1079 void dump_gold(short print_mes)
1080 //short print_mes; // 0 - no 1 - yes
1082 // Mildly kludgy gold check
1083 if (party.gold > 30000) {
1084 party.gold = 30000;
1085 if (print_mes == 1) {
1086 put_pc_screen();
1087 add_string_to_buf("Excess gold dropped. ");
1088 print_buf();
1091 if (party.food > 25000) {
1092 party.food = 25000;
1093 if (print_mes == 1) {
1094 put_pc_screen();
1095 add_string_to_buf("Excess food dropped. ");
1096 print_buf();
1103 void pick_lock(location where,short pc_num)
1105 unsigned char terrain;
1106 short r1,which_item;
1107 Boolean will_break = FALSE;
1108 short unlock_adjust;
1110 terrain = t_d.terrain[where.x][where.y];
1111 which_item = pc_has_abil_equip(pc_num,161);
1112 if (which_item == 24) {
1113 add_string_to_buf(" Need lockpick equipped. ");
1114 return;
1117 r1 = get_ran(1,0,100) + adven[pc_num].items[which_item].ability_strength * 7;
1119 if (r1 < 75)
1120 will_break = TRUE;
1122 r1 = get_ran(1,0,100) - 5 * stat_adj(pc_num,1) + c_town.difficulty * 7
1123 - 5 * adven[pc_num].skills[15] - adven[pc_num].items[which_item].ability_strength * 7;
1125 // Nimble?
1126 if (adven[pc_num].traits[3] == FALSE)
1127 r1 -= 8;
1129 if (pc_has_abil_equip(pc_num,42) < 24)
1130 r1 = r1 - 12;
1132 if ((scenario.ter_types[terrain].special < 9) || (scenario.ter_types[terrain].special > 10)) {
1133 add_string_to_buf(" Wrong terrain type. ");
1134 return;
1136 unlock_adjust = scenario.ter_types[terrain].flag2;
1137 if ((unlock_adjust >= 5) || (r1 > (unlock_adjust * 15 + 30))) {
1138 add_string_to_buf(" Didn't work. ");
1139 if (will_break == TRUE) {
1140 add_string_to_buf(" Pick breaks. ");
1141 remove_charge(pc_num,which_item);
1143 play_sound(41);
1145 else {
1146 add_string_to_buf(" Door unlocked. ");
1147 play_sound(9);
1148 t_d.terrain[where.x][where.y] = scenario.ter_types[terrain].flag1;
1152 void bash_door(location where,short pc_num)
1154 unsigned char terrain;
1155 short r1,unlock_adjust;
1157 terrain = t_d.terrain[where.x][where.y];
1158 r1 = get_ran(1,0,100) - 15 * stat_adj(pc_num,0) + c_town.difficulty * 4;
1160 if ((scenario.ter_types[terrain].special < 9) || (scenario.ter_types[terrain].special > 10)) {
1161 add_string_to_buf(" Wrong terrain type. ");
1162 return;
1165 unlock_adjust = scenario.ter_types[terrain].flag2;
1166 if ((unlock_adjust >= 5) || (r1 > (unlock_adjust * 15 + 40)) || (scenario.ter_types[terrain].special != 10)) {
1167 add_string_to_buf(" Didn't work. ");
1168 damage_pc(pc_num,get_ran(1,1,4),4,-1);
1170 else {
1171 add_string_to_buf(" Lock breaks. ");
1172 play_sound(9);
1173 t_d.terrain[where.x][where.y] = scenario.ter_types[terrain].flag1;
1178 void erase_specials()
1180 location where;
1181 short k,sd1,sd2;
1182 unsigned char floors[6] = {0,150,186,193,2,36};
1183 special_node_type sn;
1185 if ((is_combat()) && (which_combat_type == 0))
1186 return;
1187 if ((is_town() == FALSE) && (is_combat() == FALSE))
1188 return;
1189 for (k = 0; k < 50; k++) {
1190 if (c_town.town.spec_id[k] >= 0) {
1191 sn = c_town.town.specials[c_town.town.spec_id[k]];
1192 sd1 = sn.sd1; sd2 = sn.sd2;
1193 if ((sd_legit(sd1,sd2) == TRUE) && (PSD[sd1][sd2] == 250)) {
1194 where = c_town.town.special_locs[k];
1195 if ((where.x != 100) && ((where.x > town_size[town_type]) || (where.y > town_size[town_type])
1196 || (where.x < 0) || (where.y < 0))) {
1197 SysBeep(2);
1198 add_string_to_buf("Town corrupt. Problem fixed.");
1199 print_nums(where.x,where.y,k);
1200 c_town.town.special_locs[k].x = 0;
1203 if (where.x != 100) {
1204 switch (scenario.ter_types[t_d.terrain[where.x][where.y]].picture) {
1205 case 207: t_d.terrain[where.x][where.y] = 0; break;
1206 case 208: t_d.terrain[where.x][where.y] = 170; break;
1207 case 209: t_d.terrain[where.x][where.y] = 210; break;
1208 case 210: t_d.terrain[where.x][where.y] = 217; break;
1209 case 211: t_d.terrain[where.x][where.y] = 2; break;
1210 case 212: t_d.terrain[where.x][where.y] = 36; break;
1212 take_special(where.x,where.y);
1221 void erase_out_specials()
1224 short i,j,k,l,m,out_num;
1225 unsigned char floors[6] = {0,150,186,193,2,36},store;
1226 unsigned char exit_g_type[12] = {0,0,2,2,2, 28,26,6,30,2, 2,0};
1227 special_node_type sn;
1228 short sd1,sd2;
1229 location where;
1231 for (k = 0; k < 2; k++)
1232 for (l = 0; l < 2; l++)
1233 if (quadrant_legal(k,l) == TRUE) {
1234 for (m = 0; m < 8; m++)
1235 if ((outdoors[k][l].exit_dests[m] >= 0) &&
1236 (outdoors[k][l].exit_locs[m].x == minmax(0,47,outdoors[k][l].exit_locs[m].x)) &&
1237 (outdoors[k][l].exit_locs[m].y == minmax(0,47,outdoors[k][l].exit_locs[m].y))) {
1238 if (party.can_find_town[outdoors[k][l].exit_dests[m]] == 0) {
1239 out[48 * k + outdoors[k][l].exit_locs[m].x][48 * l + outdoors[k][l].exit_locs[m].y] =
1240 scenario.ter_types[outdoors[k][l].terrain[outdoors[k][l].exit_locs[m].x][outdoors[k][l].exit_locs[m].y]].flag1;
1241 //exit_g_type[out[48 * k + outdoors[k][l].exit_locs[m].x][48 * l + outdoors[k][l].exit_locs[m].y] - 217];
1244 else if (party.can_find_town[outdoors[k][l].exit_dests[m]] > 0) {
1245 out[48 * k + outdoors[k][l].exit_locs[m].x][48 * l + outdoors[k][l].exit_locs[m].y] =
1246 outdoors[k][l].terrain[outdoors[k][l].exit_locs[m].x][outdoors[k][l].exit_locs[m].y];
1251 for (i = 0; i < 2; i++)
1252 for (j = 0; j < 2; j++)
1253 if (quadrant_legal(i,j) == TRUE) {
1254 for (k = 0; k < 18; k++)
1255 if (outdoors[i][j].special_id[k] >= 0) {
1256 out_num = scenario.out_width * (party.outdoor_corner.y + j) + party.outdoor_corner.x + i;
1258 sn = outdoors[i][j].specials[outdoors[i][j].special_id[k]];
1259 sd1 = sn.sd1; sd2 = sn.sd2;
1260 if ((sd_legit(sd1,sd2) == TRUE) && (PSD[sd1][sd2] == 250)) {
1261 where = outdoors[i][j].special_locs[k];
1262 if (where.x != 100) {
1263 if ((where.x > 48) || (where.y > 48)
1264 || (where.x < 0) || (where.y < 0)) {
1265 SysBeep(2);
1266 add_string_to_buf("Outdoor section corrupt. Problem fixed.");
1267 outdoors[i][j].special_id[k] = -1;
1270 switch (scenario.ter_types[outdoors[i][j].terrain[where.x][where.y]].picture) {
1271 case 207: out[48 * i + where.x][48 * j + where.y] = 0; break;
1272 case 208: out[48 * i + where.x][48 * j + where.y] = 170; break;
1273 case 209: out[48 * i + where.x][48 * j + where.y] = 210; break;
1274 case 210: out[48 * i + where.x][48 * j + where.y] = 217; break;
1275 case 211: out[48 * i + where.x][48 * j + where.y] = 2; break;
1276 case 212: out[48 * i + where.x][48 * j + where.y] = 36; break;
1286 // returns id # of special at where, or 40 if there is none.
1287 short get_town_spec_id(location where)
1289 short i = 0;
1291 while ((same_point(c_town.town.special_locs[i],where) == FALSE) && (i < 40))
1292 i++;
1293 return i;
1297 void clear_map()
1299 RECT map_world_rect = {0,0,384,384};
1300 HBITMAP old_bmp;
1301 HDC hdc;
1302 HBRUSH oldb;
1303 HPEN oldp;
1305 hdc = CreateCompatibleDC(main_dc);
1306 SelectPalette(hdc,hpal,0);
1307 old_bmp = SelectObject(hdc, map_gworld);
1309 oldp = SelectObject(hdc,GetStockObject(BLACK_PEN));
1310 oldb = SelectObject(hdc,GetStockObject(BLACK_BRUSH));
1311 Rectangle(hdc, map_world_rect.left,map_world_rect.top,map_world_rect.right,map_world_rect.bottom);
1312 SelectObject(hdc,oldp);
1313 SelectObject(hdc,oldb);
1314 SelectObject(hdc, old_bmp);
1315 DeleteDC(hdc);
1317 draw_map(modeless_dialogs[5],10);
1323 void draw_map (HWND the_dialog, short the_item)
1324 //short the_item; // Being sneaky - if this gets value of 5, this is not a full restore -
1325 // just update near party, if it gets 11, blank out middle and leave
1326 // No redrawing in gworld
1327 // If a 10, do a regular full restore
1328 // Also, can get a 5 even when the window is not up, so have to make
1329 // sure dialog exists before accessing it.
1332 // RECT map_rect = {47,29,297,279},map_world_rect = {0,0,321,321};
1333 RECT map_rect = {53,7,303,257},map_world_rect = {0,0,321,321};
1334 RECT whole_map_win_rect = {0,0,400,400};
1335 char *comb_mess = " Map unavailable.";
1336 char *unav_mess = " Map unavailable.";
1337 char *blank_mess = "";
1338 location top_left,map_adj = {0,0};
1339 location where;
1340 location kludge;
1341 RECT draw_rect;
1342 RECT source_rect,ter_temp_from,dlogpicrect = {6,6,42,42},orig_draw_rect = {0,0,6,6};
1343 Boolean draw_pcs = TRUE;
1344 RECT view_rect= {0,0,48,48},tiny_rect = {0,0,32,32},
1345 redraw_rect = {0,0,48,48},small_rect = {0,0,9,9},big_rect = {0,0,64,64}; // RECTangle visible in view screen
1346 HDC hdc = NULL,hdc2;
1347 HBITMAP old_bmp;
1348 HBRUSH old_brush;
1349 HPEN old_pen;
1350 short k,i,j,pic,pic2;
1351 RECT area_to_draw_from,area_to_draw_on = {47,29,287,269};
1352 Boolean draw_surroundings = FALSE,expl,expl2;
1353 short total_size = 48; // if full redraw, use this to figure out everything
1354 RECT area_to_put_on_map_rect;
1355 short small_adj = 0;
1356 unsigned char what_ter,what_ter2;
1357 Boolean out_mode;
1358 UINT c;
1359 RECT custom_from;
1361 if (the_item == 4) {
1362 draw_surroundings = TRUE;
1363 the_item = 5;
1365 if (kludge_force_full_refresh == TRUE)
1366 draw_surroundings = TRUE;
1367 if ((modeless_exists[5] == FALSE) && (the_item == 5) && (need_map_full_refresh == TRUE))
1368 return;
1369 if ((modeless_exists[5] == FALSE) && (the_item == 10)) {
1370 need_map_full_refresh = TRUE;
1371 return;
1373 if ((modeless_exists[5] == TRUE) && (the_item != 11) && (need_map_full_refresh == TRUE)) {
1374 need_map_full_refresh = FALSE;
1375 the_item = 10;
1378 OffsetRect(&area_to_draw_on,0,-23);
1380 if (the_item == 10) {
1381 for (i = 0; i < 8; i++)
1382 for (j = 0; j < 64; j++)
1383 map_graphic_placed[i][j] = 0;
1387 town_map_adj.x = 0;
1388 town_map_adj.y = 0;
1389 // view rect is rect that is visible, redraw rect is area to redraw now
1390 // area_to_draw_from is final draw from rect
1391 // area_to_draw_on is final draw to rect
1392 // extern short store_pre_shop_mode,store_pre_talk_mode;
1393 if ((is_out()) || ((is_combat()) && (which_combat_type == 0)) ||
1394 ((overall_mode == 20) && (store_pre_talk_mode == 0)) ||
1395 ((overall_mode == 21) && (store_pre_shop_mode == 0))) {
1396 view_rect.left = minmax(0,8,party.loc_in_sec.x - 20);
1397 view_rect.right = view_rect.left + 40;
1398 view_rect.top = minmax(0,8,party.loc_in_sec.y - 20);
1399 view_rect.bottom = view_rect.top + 40;
1400 redraw_rect = view_rect;
1402 else {
1403 switch (town_type) {
1404 case 0:
1405 view_rect.left = minmax(0,24,c_town.p_loc.x - 20);
1406 view_rect.right = view_rect.left + 40;
1407 view_rect.top = minmax(0,24,c_town.p_loc.y - 20);
1408 view_rect.bottom = view_rect.top + 40;
1409 if (the_item == 5)
1410 redraw_rect = view_rect;
1411 else redraw_rect = big_rect;
1412 total_size = 64;
1413 break;
1414 case 1:
1415 view_rect.left = minmax(0,8,c_town.p_loc.x - 20);
1416 view_rect.right = view_rect.left + 40;
1417 view_rect.top = minmax(0,8,c_town.p_loc.y - 20);
1418 view_rect.bottom = view_rect.top + 40;
1419 redraw_rect = view_rect;
1420 break;
1421 case 2:
1422 view_rect = tiny_rect;
1423 redraw_rect = view_rect;
1424 //InsetRect(&area_to_draw_to,48,48);
1425 total_size = 32;
1426 break;
1429 if ((is_out()) || ((is_combat()) && (which_combat_type == 0)) ||
1430 ((overall_mode == 20) && (store_pre_talk_mode == 0)) ||
1431 ((overall_mode == 21) && (store_pre_shop_mode == 0)) ||
1432 (((is_town()) || (is_combat())) && (town_type != 2))) {
1433 area_to_draw_from = view_rect;
1434 area_to_draw_from.left *= 6;
1435 area_to_draw_from.right *= 6;
1436 area_to_draw_from.top *= 6;
1437 area_to_draw_from.bottom *= 6;
1439 else {
1440 area_to_draw_from = area_to_draw_on;
1441 OffsetRect(&area_to_draw_from,-1 * area_to_draw_from.left,-1 * area_to_draw_from.top);
1442 small_adj = 0;
1445 if (is_combat())
1446 draw_pcs = FALSE;
1448 // make map pens
1449 if (hbrush[0] == NULL) {
1450 for (i = 0; i < 6; i++) {
1451 c = GetNearestPaletteIndex(hpal,map_colors[i]);
1452 hbrush[i] = CreateSolidBrush(PALETTEINDEX(c));
1453 hpen[i] = CreatePen(PS_SOLID,1,PALETTEINDEX(c));
1458 hdc = CreateCompatibleDC(main_dc);
1459 SelectPalette(hdc,hpal,0);
1460 old_bmp = SelectObject(hdc, map_gworld);
1461 old_brush = SelectObject(hdc,map_brush[0]);
1462 old_pen = SelectObject(hdc,GetStockObject(NULL_PEN));
1464 if (the_item == 11) {
1465 SelectObject(hdc,GetStockObject(WHITE_BRUSH));
1466 Rectangle(hdc, map_world_rect.left,map_world_rect.top,map_world_rect.right,map_world_rect.bottom);
1467 draw_pcs = FALSE;
1469 else {
1470 if (modeless_exists[5] == TRUE) {
1471 SetDlgItemText(the_dialog,3,"");
1474 if (is_out()) { // for outside map, adjust for where in outdoors is being mapped
1475 if (party.i_w_c.x == 1)
1476 map_adj.x += 48;
1477 if (party.i_w_c.y == 1)
1478 map_adj.y += 48;
1481 // Now, if doing just partial restore, crop redraw_rect to save time.
1482 if (the_item == 5) {
1483 if ((is_out()) || ((is_combat()) && (which_combat_type == 0)) ||
1484 ((overall_mode == 20) && (store_pre_talk_mode == 0)) ||
1485 ((overall_mode == 21) && (store_pre_shop_mode == 0)))
1486 kludge = global_to_local(party.p_loc);
1487 else if (is_combat())
1488 kludge = pc_pos[current_pc];
1489 else kludge = c_town.p_loc;
1490 redraw_rect.left = max(0,kludge.x - 4);
1491 redraw_rect.right = min(view_rect.right,kludge.x + 5);
1492 redraw_rect.top = max(0,kludge.y - 4);
1493 redraw_rect.bottom = min(view_rect.bottom,kludge.y + 5);
1496 // Now, if shopping or talking, just don't touch anything.
1497 if ((overall_mode == 21) || (overall_mode == 20))
1498 redraw_rect.right = -1;
1500 if ((is_out()) ||
1501 ((is_combat()) && (which_combat_type == 0)) ||
1502 ((overall_mode == 20) && (store_pre_talk_mode == 0)) ||
1503 ((overall_mode == 21) && (store_pre_shop_mode == 0)))
1504 out_mode = TRUE;
1505 else out_mode = FALSE;
1507 area_to_put_on_map_rect = redraw_rect;
1508 if (the_item == 10) {
1509 area_to_put_on_map_rect.top = area_to_put_on_map_rect.left = 0;
1510 area_to_put_on_map_rect.right = area_to_put_on_map_rect.bottom = total_size;
1515 for (where.x= area_to_put_on_map_rect.left; where.x < area_to_put_on_map_rect.right; where.x++)
1516 for (where.y= area_to_put_on_map_rect.top; where.y < area_to_put_on_map_rect.bottom; where.y++)
1517 if ((map_graphic_placed[where.x / 8][where.y] & (unsigned char)(s_pow(2,where.x % 8))) == 0)
1519 draw_rect = orig_draw_rect;
1520 OffsetRect(&draw_rect,6 * where.x + small_adj, 6 * where.y + small_adj);
1522 if (out_mode == TRUE)
1523 what_ter = out[where.x + 48 * party.i_w_c.x][where.y + 48 * party.i_w_c.y];
1524 else what_ter = t_d.terrain[where.x][where.y];
1526 ter_temp_from = orig_draw_rect;
1528 if (out_mode == TRUE)
1529 expl = out_e[where.x + 48 * party.i_w_c.x][where.y + 48 * party.i_w_c.y];
1530 else expl = is_explored(where.x,where.y);
1532 if (expl != 0) {
1533 map_graphic_placed[where.x / 8][where.y] =
1534 map_graphic_placed[where.x / 8][where.y] | (unsigned char)(s_pow(2,where.x % 8));
1535 pic = scenario.ter_types[what_ter].picture;
1536 if (pic >= 1000) {
1538 if (spec_scen_g != NULL) {
1540 pic = pic % 1000;
1541 custom_from = coord_to_rect(pic % 10, pic / 10);
1542 OffsetRect(&custom_from,-13,-13);
1543 SelectObject(hdc,old_bmp);
1544 rect_draw_some_item(spec_scen_g,custom_from,map_gworld,draw_rect,0,0);
1545 SelectObject(hdc,map_gworld);
1548 else switch ((pic >= 400) ? anim_map_pats[pic - 400] : map_pats[pic]) {
1549 case 0: case 10: case 11:
1550 if (terrain_pic[what_ter] < 400)
1551 OffsetRect(&ter_temp_from,
1552 6 * (terrain_pic[what_ter] % 10) + 312,6 * (terrain_pic[what_ter] / 10));
1553 else OffsetRect(&ter_temp_from,
1554 24 * ((terrain_pic[what_ter] - 400) / 5) + 312,6 * ((terrain_pic[what_ter] - 400) % 5) + 163);
1555 SelectObject(hdc,old_bmp);
1556 rect_draw_some_item(mixed_gworld,ter_temp_from,
1557 map_gworld,draw_rect,0,0);
1558 SelectObject(hdc,map_gworld);
1559 break;
1561 default:
1562 if (((pic >= 400) ? anim_map_pats[pic - 400] : map_pats[pic]) < 30) {
1563 // Try a little optimization
1564 if ((pic < 400) && (where.x < area_to_put_on_map_rect.right - 1)) {
1565 if (out_mode == TRUE)
1566 what_ter2 = out[(where.x + 1)+ 48 * party.i_w_c.x][where.y + 48 * party.i_w_c.y];
1567 else what_ter2 = t_d.terrain[where.x + 1][where.y];
1568 if (out_mode == TRUE)
1569 expl2 = out_e[(where.x + 1) + 48 * party.i_w_c.x][where.y + 48 * party.i_w_c.y];
1570 else expl2 = is_explored(where.x + 1,where.y);
1571 pic2 = scenario.ter_types[what_ter2].picture;
1572 if ((map_pats[pic] == map_pats[pic2]) && (expl2 != 0)) {
1573 draw_rect.right += 6;
1574 map_graphic_placed[(where.x + 1)/ 8][where.y] =
1575 map_graphic_placed[(where.x + 1)/ 8][where.y] | (unsigned char)(s_pow(2,(where.x + 1)% 8));
1578 SelectObject(hdc,map_brush[((pic >= 400) ? anim_map_pats[pic - 400] : map_pats[pic]) - 1]);
1579 Rectangle(hdc,draw_rect.left, draw_rect.top,draw_rect.right + 1,draw_rect.bottom + 1);
1580 break;
1582 OffsetRect(&ter_temp_from,
1583 312 + 24 * ((map_pats[what_ter] - 30) / 5),
1584 138 + 6 * ((map_pats[what_ter] - 30) % 5));
1585 //OffsetRect(&ter_temp_from,0,115);
1586 SelectObject(hdc,old_bmp);
1587 rect_draw_some_item(mixed_gworld,ter_temp_from,
1588 map_gworld,draw_rect,0,0);
1589 SelectObject(hdc,map_gworld);
1590 break;
1597 SelectObject(hdc,old_brush);
1598 SelectObject(hdc,old_pen);
1599 SelectObject(hdc, old_bmp);
1600 DeleteDC(hdc);
1601 if (modeless_exists[5] == TRUE) {
1602 hdc2 = GetDC(the_dialog);
1603 SelectPalette(hdc2,hpal,0);
1605 // Now place terrain map gworld
1606 if (modeless_exists[5] == TRUE) {
1608 // graphics goes here
1609 if ((draw_surroundings == TRUE) || (the_item != 5)) { // redraw much stuff
1610 //old_brush = SelectObject(hdc2,bg[0]);
1611 //old_pen = SelectObject(hdc2,GetStockObject(NULL_PEN));
1612 //Rectangle(hdc2,whole_map_win_rect.left, whole_map_win_rect.top,whole_map_win_rect.right,whole_map_win_rect.bottom);
1613 paint_pattern(hdc2,2,whole_map_win_rect,0);
1614 //SelectObject(hdc2,old_brush);
1615 //SelectObject(hdc2,old_pen);
1616 SetBkMode(hdc2,TRANSPARENT);
1617 SelectObject(hdc2,small_bold_font);
1621 //char_win_draw_string(hdc2,
1622 // map_title_rect,"Your map: (Hit Escape to close.)",0,12);
1624 //ShowOwnedPopups(the_dialog,TRUE);
1626 GetClientRect(GetDlgItem(the_dialog,1),&draw_rect);
1627 InvalidateRect(GetDlgItem(the_dialog,1),&draw_rect,FALSE);
1630 rect_draw_some_item(map_gworld,area_to_draw_from,hdc2,area_to_draw_on,0,2);
1633 // Now place PCs and monsters
1634 if ((draw_pcs == TRUE) && (modeless_exists[5] == TRUE)) {
1635 if ((is_town()) && (party.stuff_done[305][2] > 0))
1636 for (i = 0; i < T_M; i++)
1637 if (c_town.monst.dudes[i].active > 0) {
1638 where = c_town.monst.dudes[i].m_loc;
1639 if ((is_explored(where.x,where.y)) &&
1640 ((where.x >= view_rect.left) && (where.x <= view_rect.right)
1641 && (where.y >= view_rect.top) && (where.x <= view_rect.bottom))){
1643 draw_rect.left = area_to_draw_on.left + 6 * (where.x - view_rect.left);
1644 draw_rect.top = area_to_draw_on.top + 6 * (where.y - view_rect.top);
1645 //if ((!is_out()) && (town_type == 2)) {
1646 // draw_rect.left += 48;
1647 // draw_rect.top += 48;
1648 // }
1649 draw_rect.right = draw_rect.left + 6;
1650 draw_rect.bottom = draw_rect.top + 6;
1652 map_graphic_placed[where.x / 8][where.y] =
1653 map_graphic_placed[where.x / 8][where.y] & ~((unsigned char)(s_pow(2,where.x % 8)));
1654 SelectObject(hdc2,hpen[0]);
1655 SelectObject(hdc2,hbrush[0]);
1656 Rectangle(hdc2, draw_rect.left,draw_rect.top,draw_rect.right,draw_rect.bottom);
1657 SelectObject(hdc2,hpen[4]);
1658 SelectObject(hdc2,hbrush[5]);
1659 Ellipse(hdc2, draw_rect.left,draw_rect.top,draw_rect.right,draw_rect.bottom);
1663 if ((overall_mode != 21) && (overall_mode != 20)) {
1664 where = (is_town()) ? c_town.p_loc : global_to_local(party.p_loc);
1666 draw_rect.left = area_to_draw_on.left + 6 * (where.x - view_rect.left);
1667 draw_rect.top = area_to_draw_on.top + 6 * (where.y - view_rect.top);
1668 //if ((!is_out()) && (town_type == 2)) {
1669 // draw_rect.left += 48;
1670 // draw_rect.top += 48;
1671 // }
1672 draw_rect.right = draw_rect.left + 6;
1673 draw_rect.bottom = draw_rect.top + 6;
1674 if ((where.x >= 0) && (where.x < 64) &&
1675 (where.y >= 0) && (where.y < 64)) {
1676 map_graphic_placed[where.x / 8][where.y] = /* Crash! vvv */
1677 map_graphic_placed[where.x / 8][where.y] & ~((unsigned char)(s_pow(2,where.x % 8)));
1679 SelectObject(hdc2,hpen[0]);
1680 SelectObject(hdc2,hbrush[0]);
1681 Rectangle(hdc2, draw_rect.left,draw_rect.top,draw_rect.right,draw_rect.bottom);
1682 SelectObject(hdc2,hpen[3]);
1683 SelectObject(hdc2,hbrush[3]);
1684 Ellipse(hdc2, draw_rect.left,draw_rect.top,draw_rect.right,draw_rect.bottom);
1692 // Now exit gracefully
1693 if (modeless_exists[5] == TRUE)
1694 fry_dc(the_dialog,hdc2);
1696 if (modeless_exists[5] == TRUE) {
1698 // graphics goes here
1699 if ((draw_surroundings == TRUE) || (the_item != 5)) { // redraw much stuff
1700 draw_dialog_graphic(the_dialog, dlogpicrect,
1701 721, FALSE,0); // draw the map graphic
1708 BOOL FAR PASCAL _export map_dialog_proc
1709 (HWND hDlg, UINT message, UINT wParam, LONG lParam) {
1710 short i,which_d,store_which;
1711 char item_str[256];
1712 Boolean do_stnd = TRUE,id_dlg = TRUE;
1713 RECT to_rect = {10,11,46,47},d_rect = {0,0,240,240};
1714 HDC hdc;
1716 switch (message) {
1717 case WM_INITDIALOG:
1718 if (store_map_window_rect.right > 0)
1719 MoveWindow(hDlg,store_map_window_rect.left,store_map_window_rect.top,
1720 store_map_window_rect.right - store_map_window_rect.left,
1721 store_map_window_rect.bottom - store_map_window_rect.top,FALSE);
1722 else {
1723 GetWindowRect(hDlg,&store_map_window_rect);
1724 MoveWindow(hDlg,294 + ulx, 47 + uly,
1725 store_map_window_rect.right - store_map_window_rect.left,
1726 store_map_window_rect.bottom - store_map_window_rect.top,FALSE);
1729 kludge_force_full_refresh = TRUE;
1730 draw_map(hDlg,10);
1731 kludge_force_full_refresh = FALSE;
1732 SetFocus(mainPtr);
1733 break;
1734 case WM_ERASEBKGND:
1735 return 1;
1737 case WM_PAINT:
1738 kludge_force_full_refresh = TRUE;
1739 draw_map(hDlg,5);
1740 kludge_force_full_refresh = FALSE;
1741 // ShowOwnedPopups(hDlg,TRUE);
1742 return FALSE;
1744 case WM_KEYDOWN:
1745 // force_play_sound(0);
1746 if (wParam != VK_RETURN)
1747 return 0;
1748 case WM_COMMAND:
1749 modeless_exists[5] = FALSE;
1750 GetWindowRect(hDlg,&store_map_window_rect);
1751 DestroyWindow(hDlg);
1752 return TRUE;
1753 case WM_DESTROY:
1754 modeless_exists[5] = FALSE;
1755 return 0;
1757 return FALSE;
1761 void display_map()
1763 short i,which_d;
1765 if ( modeless_exists[5] == TRUE)
1766 return;
1768 modeless_exists[5] = TRUE;
1769 if (map_proc == NULL) {
1770 map_proc = MakeProcInstance((FARPROC) map_dialog_proc,store_hInstance);
1772 modeless_dialogs[5] = CreateDialog(store_hInstance,
1773 MAKEINTRESOURCE(1046),mainPtr,map_proc);
1775 // draw_map(modeless_dialogs[5],10);
1778 Boolean is_door(location destination)
1780 short i;
1782 if ((scenario.ter_types[t_d.terrain[destination.x][destination.y]].special == 9) ||
1783 (scenario.ter_types[t_d.terrain[destination.x][destination.y]].special == 1) ||
1784 (scenario.ter_types[t_d.terrain[destination.x][destination.y]].special == 10))
1785 return TRUE;
1786 return FALSE;
1789 Boolean quadrant_legal(short i, short j)
1791 if (party.outdoor_corner.x + i >= scenario.out_width)
1792 return FALSE;
1793 if (party.outdoor_corner.y + j >= scenario.out_height)
1794 return FALSE;
1795 if (party.outdoor_corner.x + i < 0)
1796 return FALSE;
1797 if (party.outdoor_corner.y + j < 0)
1798 return FALSE;
1799 return TRUE;