short sight_obscurity(short x,short y) { ter_num_t what_terrain; short store; what_terrain = coord_to_ter(x,y); // TODO: This should not be hard-coded! // It appears to refer to mountain cave entrances, surface tower, and surface pit. (WHY?) if((what_terrain >= 237) && (what_terrain <= 242)) return 1; store = get_blockage(what_terrain); if(is_town()) { if(univ.town.is_special(x,y)) store++; } if((is_town()) || (is_combat())) { if(univ.town.is_web(x,y)) store += 2; if((univ.town.is_fire_barr(x,y)) || (univ.town.is_force_barr(x,y))) return 5; if(univ.town.is_crate(x,y) || univ.town.is_barrel(x,y) || univ.town.is_block(x,y)) store++; } return store; }
// All purpose function to check is spot is free for travel into. bool is_blocked(location to_check) { short i,gr; ter_num_t ter; if(is_out()) { if(impassable(univ.out[to_check.x][to_check.y])) { return true; } if(to_check == univ.party.p_loc) return true; for(i = 0; i < univ.party.out_c.size(); i++) if((univ.party.out_c[i].exists)) if(univ.party.out_c[i].m_loc == to_check) return true; return false; } if((is_town()) || (is_combat())) { ter = univ.town->terrain(to_check.x,to_check.y); gr = univ.scenario.ter_types[ter].picture; // Terrain blocking? if(impassable(ter)) { return true; } // Keep away from marked specials during combat if((is_combat()) && univ.town.is_spot(to_check.x, to_check.y)) return true; if((is_combat()) && (univ.scenario.ter_types[coord_to_ter(to_check.x,to_check.y)].trim_type == eTrimType::CITY)) return true; // TODO: Maybe replace eTrimType::CITY with a blockage == clear/special && is_special() check // Note: The purpose of the above check is to avoid portals. // Party there? if(is_town()) if(to_check == univ.town.p_loc) return true; if(is_combat()) for(i = 0; i < 6; i++) if(univ.party[i].main_status == eMainStatus::ALIVE && to_check == univ.party[i].combat_pos) return true; // Monster there? if(univ.target_there(to_check, TARG_MONST)) return true; // Magic barrier? if(univ.town.is_force_barr(to_check.x,to_check.y)) return true; if(univ.town.is_force_cage(to_check.x,to_check.y)) return true; return false; } return true; }
bool is_town() { if((overall_mode > MODE_OUTDOORS && overall_mode < MODE_COMBAT) || overall_mode == MODE_LOOK_TOWN || cartoon_happening) return true; else if(overall_mode == MODE_SHOPPING) { std::swap(overall_mode, store_pre_shop_mode); bool ret = is_town(); std::swap(overall_mode, store_pre_shop_mode); return ret; } else if(overall_mode == MODE_TALKING) { std::swap(overall_mode, store_pre_talk_mode); bool ret = is_town(); std::swap(overall_mode, store_pre_talk_mode); return ret; } else return false; }
// Looks at all spaces within 2, looking for a spot which is clear of nastiness and beings // returns {0,0} if none found // THIS MAKES NO ADJUSTMENTS FOR BIG MONSTERS!!! location find_clear_spot(location from_where,short mode) //mode; // 0 - normal 1 - prefer adjacent space { location loc,store_loc; short num_tries = 0,r1; while (num_tries < 75) { num_tries++; loc = from_where; r1 = get_ran(1,-2,2); loc.x = loc.x + r1; r1 = get_ran(1,-2,2); loc.y = loc.y + r1; if ((loc_off_act_area(loc) == false) && (is_blocked(loc) == false) && (can_see(from_where,loc,1) == 0) && (!(is_combat()) || (pc_there(loc) == 6)) && (!(is_town()) || (loc != univ.town.p_loc)) && (!(univ.town.misc_i(loc.x,loc.y) & 248)) && // check for crate, barrel, barrier, quickfire (!(univ.town.explored(loc.x,loc.y) & 254))) { // check for fields, clouds if ((mode == 0) || ((mode == 1) && (adjacent(from_where,loc) == true))) return loc; else store_loc = loc; } } return store_loc; }
short monst_pick_target_pc(short m_num,cCreature *which_m)//// { short num_tries = 0,r1,store_targ = 6; if (which_m->attitude % 2 == 0) return 6; if (is_town()) return 0; // First pick any visible, nearby PC r1 = get_ran(1,0,5); while ((num_tries < 6) && ((univ.party[r1].main_status != 1) || (monst_can_see(m_num,pc_pos[r1]) == false))) { r1 = get_ran(1,0,5); num_tries++; } if (num_tries < 6) store_targ = r1; // Then, see if target can be replaced with someone nice and close r1 = get_ran(1,0,5); while ((num_tries < 6) && ((univ.party[r1].main_status != 1) || (dist(which_m->cur_loc,pc_pos[r1]) > 4) || (monst_can_see(m_num,pc_pos[r1]) == false))) { r1 = get_ran(1,0,5); num_tries++; } if (num_tries < 6) return r1; else return store_targ; }
// Returns 6 if can't see, O.W. returns the # of a PC that can see short party_can_see(location where) { short i; if(is_out()) { if((point_onscreen(univ.party.p_loc,where)) && (can_see_light(univ.party.p_loc,where,sight_obscurity) < 5)) return 1; else return 6; } if(fog_lifted) return point_onscreen(univ.town.p_loc,where) ? 1 : 6; if(is_town()) { if( ((point_onscreen(univ.town.p_loc,where)) || (overall_mode == MODE_LOOK_TOWN)) && (pt_in_light(univ.town.p_loc,where) ) && (can_see_light(univ.town.p_loc,where,sight_obscurity) < 5)) return 1; else return 6; } // Now for combat checks. Doing separately for efficiency. Check first for light. If // dark, give up. if((which_combat_type != 0) && !combat_pt_in_light(where)) return 6; for(i = 0; i < 6; i++) if(univ.party[i].main_status == eMainStatus::ALIVE) { if(can_see_light(univ.party[i].combat_pos,where,sight_obscurity) < 5) return i; } return 6; }
//short dest; // 0 - terrain gworld 1 - screen // if terrain_to_draw is -1, do black // if terrain_to_draw >= 10000, force to draw graphic which is terrain_to_draw - 10000 void draw_one_terrain_spot (short i,short j,short terrain_to_draw) { rectangle where_draw; rectangle source_rect; sf::Texture* source_gworld; short anim_type = 0; location l; l.x = i; l.y = j; if(supressing_some_spaces && (l != ok_space[0]) && (l != ok_space[1]) && (l != ok_space[2]) && (l != ok_space[3])) return; where_draw = calc_rect(i,j); where_draw.offset(13,13); if(terrain_to_draw == -1) { fill_rect(terrain_screen_gworld, where_draw, sf::Color::Black); return; } if(terrain_to_draw >= 10000) { // force using a specific graphic terrain_to_draw -= 10000; int which_sheet = terrain_to_draw / 50; source_gworld = ResMgr::get<ImageRsrc>("ter" + std::to_string(1 + which_sheet)).get(); terrain_to_draw %= 50; source_rect = calc_rect(terrain_to_draw % 10, terrain_to_draw / 10); anim_type = -1; } else if(univ.scenario.ter_types[terrain_to_draw].picture >= 2000) { // custom graf_pos_ref(source_gworld, source_rect) = spec_scen_g.find_graphic(univ.scenario.ter_types[terrain_to_draw].picture - 2000 + (anim_ticks % 4)); anim_type = 0; } else if(univ.scenario.ter_types[terrain_to_draw].picture >= 1000) { // custom graf_pos_ref(source_gworld, source_rect) = spec_scen_g.find_graphic(univ.scenario.ter_types[terrain_to_draw].picture - 1000); } else if(univ.scenario.ter_types[terrain_to_draw].picture >= 960) { // animated source_gworld = ResMgr::get<ImageRsrc>("teranim").get(); terrain_to_draw = univ.scenario.ter_types[terrain_to_draw].picture; source_rect = calc_rect(4 * ((terrain_to_draw - 960) / 5) + (anim_ticks % 4),(terrain_to_draw - 960) % 5); anim_type = 0; } else { terrain_to_draw = univ.scenario.ter_types[terrain_to_draw].picture; int which_sheet = terrain_to_draw / 50; source_gworld = ResMgr::get<ImageRsrc>("ter" + std::to_string(1 + which_sheet)).get(); terrain_to_draw %= 50; source_rect = calc_rect(terrain_to_draw % 10, terrain_to_draw / 10); anim_type = -1; } if(anim_type >= 0) { if((is_town()) || (is_out())) anim_onscreen = true; } rect_draw_some_item(*source_gworld, source_rect, terrain_screen_gworld, where_draw); }
// returns true if placement was successful bool summon_monster(m_num_t which,location where,short duration,short given_attitude) //which; // if in town, this is caster loc., if in combat, this is where to try // to put monster { location loc; short which_m,spot; if ((is_town()) || (monsters_going)) { // Ooooh ... mondo kludge. Need to find caster's attitude to give it to monst. which_m = monst_there(where); // if (pc_there(where) < 6) // which_att = 2; // else if (which_m == 90) // which_att = 1; // else which_att = univ.town.monst[which_m].attitude; loc = find_clear_spot(where,0); if (loc.x == 0) return false; } else { // pc may be summoning using item, in which case where will be pc's space, so fix if (pc_there(where) < 6) { where = find_clear_spot(where,0); if (where.x == 0) return false; } if ((univ.town.is_barrel(where.x,where.y)) || (univ.town.is_crate(where.x,where.y))) return false; loc = where; } spot = place_monster(which,loc); if (spot >= univ.town->max_monst()) { if (duration < 100) add_string_to_buf(" Too many monsters."); //ASB(" Monster fails to summon monster."); return false; } //play_sound(61); // if (duration < 100) univ.town.monst[spot].attitude = given_attitude; // else univ.town.monst[spot].attitude = which_att; if (which > 0) {//monster here for good univ.town.monst[spot].summoned = duration; monst_spell_note(which,21); } else univ.town.monst[spot].summoned = 0; return true; }
void handle_menu_choice(eMenu item_hit) { std::string dialogToShow; sf::Event dummyEvent = {sf::Event::KeyPressed}; short i, choice; switch(item_hit) { case eMenu::NONE: break; case eMenu::FILE_OPEN: do_load(); break; case eMenu::FILE_SAVE: do_save(0); break; case eMenu::FILE_SAVE_AS: do_save(1); break; case eMenu::FILE_NEW: if(overall_mode != MODE_STARTUP) { std::string choice = cChoiceDlog("restart-game",{"okay","cancel"}).show(); if(choice == "cancel") return; for(i = 0; i < 6; i++) univ.party[i].main_status = eMainStatus::ABSENT; party_in_memory = false; reload_startup(); overall_mode = MODE_STARTUP; draw_startup(0); } start_new_game(); draw_startup(0); menu_activate(); break; case eMenu::FILE_ABORT: if(overall_mode != MODE_STARTUP) { std::string choice = cChoiceDlog("abort-game",{"okay","cancel"}).show(); if (choice=="cancel") return; reload_startup(); overall_mode = MODE_STARTUP; } party_in_memory = false; draw_startup(0); menu_activate(); break; case eMenu::PREFS: pick_preferences(); break; case eMenu::QUIT: if(overall_mode == MODE_STARTUP) { if(party_in_memory) { std::string choice = cChoiceDlog("quit-confirm-save", {"save","quit","cancel"}).show(); if(choice == "cancel") break; if(choice == "save") { fs::path file = nav_put_party(); if(!file.empty()) break; save_party(file, univ); } } All_Done = true; break; } if(overall_mode > MODE_TOWN) { std::string choice = cChoiceDlog("quit-confirm-nosave",{"quit","cancel"}).show(); if(choice == "cancel") return; } else { std::string choice = cChoiceDlog("quit-confirm-save",{"quit","save","cancel"}).show(); if(choice == "cancel") break; if(choice == "save") { if(univ.file.empty()) { univ.file = nav_put_party(); if(univ.file.empty()) break; } save_party(univ.file, univ); } } All_Done = true; break; case eMenu::OPTIONS_PC_GRAPHIC: choice = char_select_pc(1,"New graphic for who?"); if(choice < 6) pick_pc_graphic(choice,1,nullptr); draw_terrain(); break; case eMenu::OPTIONS_DELETE_PC: if(!prime_time()) { ASB("Finish what you're doing first."); print_buf(); } else { choice = char_select_pc(1,"Delete who?"); if(choice < 6) { std::string confirm = cChoiceDlog("delete-pc-confirm",{"yes","no"}).show(); if(confirm == "yes") kill_pc(univ.party[choice],eMainStatus::ABSENT); } draw_terrain(); } break; case eMenu::OPTIONS_RENAME_PC: choice = char_select_pc(1,"Rename who?"); if(choice < 6) pick_pc_name(choice,nullptr); put_pc_screen(); put_item_screen(stat_window); break; case eMenu::OPTIONS_NEW_PC: if(!(is_town())) { add_string_to_buf("Add PC: Town mode only."); print_buf(); break; } for(i = 0; i < 6; i++) if(univ.party[i].main_status == eMainStatus::ABSENT) i = 20; if(i == 6) { ASB("Add PC: You already have 6 PCs."); print_buf(); break; } if(univ.town->has_tavern) { give_help(56,0); create_pc(6,nullptr); } else { add_string_to_buf("Add PC: You cannot add new characters in this town. Try in the town you started in.", 2); } print_buf(); put_pc_screen(); put_item_screen(stat_window); break; case eMenu::OPTIONS_JOURNAL: journal(); break; case eMenu::OPTIONS_TALK_NOTES: if(overall_mode == MODE_TALKING) { ASB("Talking notes: Can't read while talking."); print_buf(); return; } talk_notes(); break; case eMenu::OPTIONS_ENCOUNTER_NOTES: adventure_notes(); break; case eMenu::OPTIONS_STATS: if(overall_mode != MODE_STARTUP) print_party_stats(); break; case eMenu::HELP_OUT: dialogToShow = "help-outdoor"; break; case eMenu::HELP_TOWN: dialogToShow = "help-town"; break; case eMenu::HELP_COMBAT: dialogToShow = "help-combat"; break; case eMenu::HELP_BARRIER: dialogToShow = "help-fields"; break; case eMenu::HELP_HINTS: dialogToShow = "help-hints"; break; case eMenu::HELP_SPELLS: dialogToShow = "help-magic"; break; case eMenu::ABOUT: dialogToShow = "about-boe"; break; case eMenu::LIBRARY_MAGE: display_spells(eSkill::MAGE_SPELLS,100,0); break; case eMenu::LIBRARY_PRIEST: display_spells(eSkill::PRIEST_SPELLS,100,0); break; case eMenu::LIBRARY_SKILLS: display_skills(eSkill::INVALID,0); break; case eMenu::LIBRARY_ALCHEMY: // TODO: Create a dedicated dialog for alchemy info display_alchemy(); break; case eMenu::LIBRARY_TIPS: tip_of_day(); break; case eMenu::LIBRARY_INTRO: dialogToShow = "welcome"; break; case eMenu::ACTIONS_ALCHEMY: dummyEvent.key.code = sf::Keyboard::A; dummyEvent.key.shift = true; handle_keystroke(dummyEvent); break; case eMenu::ACTIONS_WAIT: dummyEvent.key.code = sf::Keyboard::W; handle_keystroke(dummyEvent); break; case eMenu::ACTIONS_AUTOMAP: if(!prime_time()) { ASB("Finish what you're doing first."); print_buf(); } else { give_help(62,0); display_map(); } make_cursor_sword(); break; case eMenu::HELP_TOC: if(fs::is_directory(progDir/"doc")) launchURL("file://" + (progDir/"doc/game/Contents.html").string()); else launchURL("https://blades.calref.net/doc/game/Contents.html"); break; case eMenu::ABOUT_MAGE: case eMenu::ABOUT_PRIEST: give_help(209,0); break; case eMenu::ABOUT_MONSTERS: give_help(212,0); break; } if(!dialogToShow.empty()) { cChoiceDlog dlog(dialogToShow); dlog.show(); } }
Boolean handle_menu (short item, HMENU) { short choice,i; POINT x = {1001,0},pass_point; Boolean to_return = false; switch (item) { case 1: // File Menu if (in_startup_mode == true) startup_load(); else do_load(); break; case 2: do_save(0); break; case 3: if (in_startup_mode == true) save_file(1); else do_save(1); break; case 4: if (in_startup_mode == false) { choice = FCD(1091,0); if (choice == 1) return false; for (i = 0; i < 6; i++) adven[i].main_status = MAIN_STATUS_ABSENT; party_in_memory = false; reload_startup(); in_startup_mode = true; draw_startup(0); } start_new_game(); draw_startup(0); break; case 6: pick_preferences(); break; case 7: pick_compatibility(); break; case 8: // Quit if (in_startup_mode == true) { to_return = All_Done = true; break; } if (overall_mode > MODE_TOWN) { choice = FCD(1067,0); if (choice == 1) return All_Done; } else { choice = FCD(1066,0); if (choice == 3) break; if (choice == 1) save_file(0); } to_return = All_Done = true; break; // Options menu case 21: choice = char_select_pc(0,0,"New graphic for who?"); if (choice < 6) pick_pc_graphic(choice,1,0); initiate_redraw(); break; case 22: choice = select_pc(0,0); if (choice < 6) pick_pc_name(choice,0); put_pc_screen(); put_item_screen(stat_window,0); break; case 23: if (!(is_town())) { add_string_to_buf("Add PC: Town mode only."); print_buf(); break; } for (i = 0; i < NUM_OF_PCS; i++) if (adven[i].main_status == MAIN_STATUS_ABSENT) i = 20; if (i == INVALID_PC) { ASB("Add PC: You already have 6 PCs."); print_buf(); } if (c_town.town_num == scenario.which_town_start) { give_help(56,0,0); create_pc(6,0); } else { add_string_to_buf("Add PC: You can only make new"); add_string_to_buf(" characters in the town you "); add_string_to_buf(" started in."); } print_buf(); put_pc_screen(); put_item_screen(stat_window,0); break; case 24: if (prime_time() == false) { ASB("Finish what you're doing first."); print_buf(); } else { choice = char_select_pc(0,0,"Delete who?"); if (choice < 6) { if ((i = FCD(1053,0)) == 2) adven[choice].kill(0); } initiate_redraw(); } break; case 27: if (overall_mode == MODE_TALKING) { ASB("Talking notes: Can't read while talking."); print_buf(); return to_return; } talk_notes(); break; case 28: adventure_notes(); break; case 29: if (in_startup_mode == false) print_party_stats(); break; // Help menu case 41: FCD(1079,0); break; case 42: FCD(1080,0); break; case 43: FCD(1081,0); break; case 44: FCD(1072,0); break; // magic barriers case 46: FCD(1084,0); break; case 47: FCD(1088,0); break; // Library case 61: display_spells(0,100,0); break; case 62: display_spells(1,100,0); break; case 63: display_skills(100,0); break; case 64: display_help(0,0); break; case 65: tip_of_day(); break; case 67: FCD(986,0); break; // Actions case 81: if (overall_mode != MODE_TOWN) { ASB("Alchemy: In town mode only."); print_buf(); break; } pass_point.x = 1000; pass_point.y = 405; to_return = handle_action(pass_point,(WPARAM) 0,(LPARAM)-1); break; case 82: to_return = handle_action(x,(WPARAM) 0,(LPARAM)-1); break; case 84: if (prime_time() == false) { ASB("Finish what you're doing first."); print_buf(); } else { give_help(62,0,0); display_map(); } SetCursor(sword_curs); break; // Mage is 399 case 399: give_help(209,0,0); party.help_received[9] = false; break; // Priest is 499 case 499: give_help(209,0,0); party.help_received[9] = false; break; // Monsters is 599 case 599: give_help(212,0,0); break; case 100: // Index WinHelp(mainPtr,"Blades of Exile.hlp",HELP_CONTENTS,0L); break; case 200: // About FCD(1062,0); break; default: if ((item >= 400) && (item < 500)) { // mage spell if (prime_time() == false) { ASB("Finish what you're doing first."); print_buf(); } else handle_menu_spell(item - 400,0); break; } if ((item >= 500) && (item < 600)) { // priest spell if (prime_time() == false) { ASB("Finish what you're doing first."); print_buf(); } else handle_menu_spell(item - 500,1); break; } if ((item >= 600) && (item < 700)) { // monster spell display_monst(item - 600,(creature_data_type *) NULL,1); break; } break; } if (in_startup_mode == true) menu_activate(0); else menu_activate(1); return to_return; }
bool monst_check_special_terrain(location where_check,short mode,short which_monst) //mode; // 1 - town 2 - combat { ter_num_t ter = 0; short r1,i,guts = 0; bool can_enter = true,mage = false; location from_loc,to_loc; bool do_look = false; // If becomes true, terrain changed, so need to update what party sees cCreature *which_m; short ter_abil; unsigned short ter_flag; from_loc = univ.town.monst[which_monst].cur_loc; switch (mode) { case 1: ter = univ.town->terrain(where_check.x,where_check.y); break; case 2: ter = combat_terrain[where_check.x][where_check.y]; break; } //// which_m = &univ.town.monst[which_monst]; ter_abil = scenario.ter_types[ter].special; ter_flag = scenario.ter_types[ter].flag3.u; if ((mode > 0) && (ter_abil == TER_SPEC_CONVEYOR)) { if ( ((ter_flag == DIR_N) && (where_check.y > from_loc.y)) || ((ter_flag == DIR_E) && (where_check.x < from_loc.x)) || ((ter_flag == DIR_S) && (where_check.y < from_loc.y)) || ((ter_flag == DIR_W) && (where_check.x > from_loc.x)) ) { return false; } } // begin determining guts, which determines how enthused the monst is about entering // nasty barriers if ((which_m->mu > 0) || (which_m->cl > 0)) mage = true; if (which_m->spec_skill == 13) guts = 20; else guts = get_ran(1,1,(which_m->level / 2)); guts += which_m->health / 20; if (mage == true) guts = guts / 2; if (which_m->attitude == 0) guts = guts / 2; if ((univ.town.is_antimagic(where_check.x,where_check.y)) && (mage == true)) return false; if ((univ.town.is_fire_wall(where_check.x,where_check.y)) && (which_m->spec_skill != 22)) { if (guts < 3) return false; } if (univ.town.is_force_wall(where_check.x,where_check.y)) { if (guts < 4) return false; } if ((univ.town.is_ice_wall(where_check.x,where_check.y)) && (which_m->spec_skill != 23)) { if (guts < 5) return false; } if (univ.town.is_sleep_cloud(where_check.x,where_check.y)) { if (guts < 8) return false; } if (univ.town.is_blade_wall(where_check.x,where_check.y)) { if (guts < 8) return false; } if (univ.town.is_quickfire(where_check.x,where_check.y)) { if (guts < 8) return false; } if (univ.town.is_scloud(where_check.x,where_check.y)) { if (guts < 4) return false; } if ((univ.town.is_web(where_check.x,where_check.y)) && (which_m->m_type != 12)) { if (guts < 3) return false; } if (univ.town.is_fire_barr(where_check.x,where_check.y)) { if ((which_m->attitude % 2 == 1) && (get_ran(1,1,100) < (which_m->mu * 10 + which_m->cl * 4))) { play_sound(60); add_string_to_buf("Monster breaks barrier."); univ.town.set_fire_barr(where_check.x,where_check.y,false); } else { if (guts < 6) return false; r1 = get_ran(1,0,10); if ((r1 < 8) || (monster_placid(which_monst))) can_enter = false; } } if (univ.town.is_force_barr(where_check.x,where_check.y)) { /// Not in big towns if ((which_m->attitude % 2 == 1) && (get_ran(1,1,100) < (which_m->mu * 10 + which_m->cl * 4)) && (!univ.town->strong_barriers)) { play_sound(60); add_string_to_buf("Monster breaks barrier."); univ.town.set_force_barr(where_check.x,where_check.y,false); } else can_enter = false; } if (univ.town.is_crate(where_check.x,where_check.y)) { if (monster_placid(which_monst)) can_enter = false; else { to_loc = push_loc(from_loc,where_check); univ.town.set_crate((short) where_check.x,(short) where_check.y,false); if (to_loc.x > 0) univ.town.set_crate((short) to_loc.x,(short) to_loc.y, true); for (i = 0; i < NUM_TOWN_ITEMS; i++) if ((univ.town.items[i].variety > 0) && (univ.town.items[i].item_loc == where_check) && (univ.town.items[i].contained)) univ.town.items[i].item_loc = to_loc; } } if (univ.town.is_barrel(where_check.x,where_check.y)) { if (monster_placid(which_monst)) can_enter = false; else { to_loc = push_loc(from_loc,where_check); univ.town.set_barrel((short) where_check.x,(short) where_check.y,false); if (to_loc.x > 0) univ.town.set_barrel((short) to_loc.x,(short) to_loc.y,true); for (i = 0; i < NUM_TOWN_ITEMS; i++) if ((univ.town.items[i].variety > 0) && (univ.town.items[i].item_loc == where_check) && (univ.town.items[i].contained)) univ.town.items[i].item_loc = to_loc; } } if (monster_placid(which_monst) && // monsters don't hop into bed when things are calm (scenario.ter_types[ter].special == TER_SPEC_BED)) can_enter = false; if (mode == 1 && univ.town.is_spot(where_check.x, where_check.y)) can_enter = false; if (ter == 90) { if ((is_combat()) && (which_combat_type == 0)) { univ.town.monst[which_monst].active = 0; add_string_to_buf("Monster escaped! "); } return false; } switch (ter_abil) { // changing ter case TER_SPEC_CHANGE_WHEN_STEP_ON: can_enter = false; if (!(monster_placid(which_monst))) { univ.town->terrain(where_check.x,where_check.y) = scenario.ter_types[ter].flag1.u; combat_terrain[where_check.x][where_check.y] = scenario.ter_types[ter].flag1.u; do_look = true; if (point_onscreen(center,where_check)) play_sound(scenario.ter_types[ter].flag2.u); } break; case TER_SPEC_BLOCKED_TO_MONSTERS: case TER_SPEC_TOWN_ENTRANCE: case TER_SPEC_WATERFALL: can_enter = false; break; case TER_SPEC_DAMAGING: // TODO: Update this to check other cases if (ter_flag == DAMAGE_FIRE && univ.town.monst[which_monst].immunities & 8) return true; else return false; break; } // Action may change terrain, so update what's been seen if (do_look == true) { if (is_town()) update_explored(univ.town.p_loc); if (is_combat()) for (i = 0; i < 6; i++) if (univ.party[i].main_status == 1) update_explored(pc_pos[i]); } return can_enter; }
short switch_target_to_adjacent(short which_m,short orig_target) { location monst_loc; short i,num_adj = 0; monst_loc = univ.town.monst[which_m].cur_loc; // First, take care of friendly monsters. if (univ.town.monst[which_m].attitude % 2 == 0) { if (orig_target >= 100) if ((univ.town.monst[orig_target - 100].active > 0) && (monst_adjacent(univ.town.monst[orig_target - 100].cur_loc,which_m) == true)) return orig_target; for (i = 0; i < univ.town->max_monst(); i++) if ((univ.town.monst[i].active > 0) && (univ.town.monst[i].attitude % 2 == 1) && (monst_adjacent(univ.town.monst[i].cur_loc,which_m) == true)) return i + 100; return orig_target; } // If we get here while in town, just need to check if switch to pc if ((is_town()) && (monst_adjacent(univ.town.p_loc,which_m) == true)) return 0; if (is_town()) return orig_target; // If target is already adjacent, we're done here. if ((is_combat()) && (orig_target < 6)) if ((univ.party[orig_target].main_status == 1) && (monst_adjacent(pc_pos[orig_target],which_m) == true)) return orig_target; if (orig_target >= 100) if ((univ.town.monst[orig_target - 100].active > 0) && (monst_adjacent(univ.town.monst[orig_target - 100].cur_loc,which_m) == true)) return orig_target; // Anyone unarmored? Heh heh heh... if (is_combat()) for (i = 0; i < 6; i++) if ((univ.party[i].main_status == 1) && (monst_adjacent(pc_pos[i],which_m) == true) && (get_encumberance(i) < 2)) return i; // Check for a nice, adjacent, friendly monster and maybe attack for (i = 0; i < univ.town->max_monst(); i++) if ((univ.town.monst[i].active > 0) && (univ.town.monst[i].attitude % 2 == 0) && (monst_adjacent(univ.town.monst[i].cur_loc,which_m) == true) && (get_ran(1,0,2) < 2)) return i + 100; // OK. Now if this monster has PCs adjacent, pick one at randomn and hack. Otherwise, // stick with orig. target. for (i = 0; i < 6; i++) if ((univ.party[i].main_status == 1) && (monst_adjacent(pc_pos[i],which_m) == true)) num_adj++; if (num_adj == 0) return orig_target; i = 0; num_adj = get_ran(1,1,num_adj); while ((num_adj > 1) || (univ.party[i].main_status != 1) || (monst_adjacent(pc_pos[i],which_m) == false)) { if ((univ.party[i].main_status == 1) && (monst_adjacent(pc_pos[i],which_m) == true)) num_adj--; i++; } return i; }
short monst_pick_target(short which_m) { cCreature *cur_monst; short targ_pc,targ_m; cur_monst = &univ.town.monst[which_m]; // First, any chance target is screwed? if (univ.town.monst[which_m].target >= 100) { if (((cur_monst->attitude % 2 == 1) && (univ.town.monst[univ.town.monst[which_m].target - 100].attitude == cur_monst->attitude)) || ((cur_monst->attitude % 2 == 0) && (univ.town.monst[univ.town.monst[which_m].target - 100].attitude % 2 == 0))) univ.town.monst[which_m].target = 6; else if (univ.town.monst[univ.town.monst[which_m].target - 100].active == 0) univ.town.monst[which_m].target = 6; } if (univ.town.monst[which_m].target < 6) if ((univ.party[univ.town.monst[which_m].target].main_status != 1) || (get_ran(1,0,3) == 1)) univ.town.monst[which_m].target = 6; if ((is_combat()) && (cur_monst->attitude % 2 == 1)) { if (spell_caster < 6) if ((get_ran(1,1,5) < 5) && (monst_can_see(which_m,pc_pos[spell_caster]) == true) && (univ.party[spell_caster].main_status == 1)) return spell_caster; if (missile_firer < 6) if ((get_ran(1,1,5) < 3) && (monst_can_see(which_m,pc_pos[missile_firer]) == true) && (univ.party[missile_firer].main_status == 1)) return missile_firer; if (univ.town.monst[which_m].target < 6) if ((monst_can_see(which_m,pc_pos[univ.town.monst[which_m].target]) == true) && (univ.party[univ.town.monst[which_m].target].main_status == 1)) return univ.town.monst[which_m].target; } // if (monst_target[which_m] >= 100) { // if ((can_see(cur_monst->m_loc,univ.town.monst[monst_target[which_m] - 100].m_loc,0) < 4) // && (univ.town.monst[monst_target[which_m] - 100].active > 0)) // return monst_target[which_m]; // } // Now pick a target pc and a target monst and see which is more attractive targ_pc = monst_pick_target_pc(which_m,cur_monst); targ_m = monst_pick_target_monst(cur_monst); if ((targ_pc != 6) && (targ_m == 6)) return targ_pc; if ((targ_pc == 6) && (targ_m != 6)) return targ_m; if ((targ_pc == 6) && (targ_m == 6)) return 6; if (is_town()) { if (cur_monst->attitude % 2 == 0) { return targ_m; } if ((targ_m == 6) && (cur_monst->attitude % 2 == 1)) return 0; if (dist(cur_monst->cur_loc,univ.town.monst[targ_m - 100].cur_loc) < dist(cur_monst->cur_loc,univ.town.p_loc)) return targ_m; else return 0; } // Otherwise we're in combat if ((dist(cur_monst->cur_loc,univ.town.monst[targ_m - 100].cur_loc) == dist(cur_monst->cur_loc,pc_pos[targ_pc])) && (get_ran(1,0,6) < 3)) return targ_m; else return targ_pc; if (dist(cur_monst->cur_loc,univ.town.monst[targ_m - 100].cur_loc) < dist(cur_monst->cur_loc,pc_pos[targ_pc])) return targ_m; else return targ_pc; }
void draw_party_symbol(location center) { rectangle source_rect; location target(4,4); short i = 0; if(!can_draw_pcs) return; if(!univ.party.is_alive()) return; if((is_town()) && (univ.town.p_loc.x > 70)) return; if(overall_mode == MODE_LOOK_TOWN || cartoon_happening) { target.x += univ.town.p_loc.x - center.x; target.y += univ.town.p_loc.y - center.y; } if((univ.party.in_boat < 0) && (univ.party.in_horse < 0)) { i = first_active_pc(); sf::Texture* from_gw; pic_num_t pic = univ.party[i].which_graphic; if(pic >= 1000) { bool isParty = pic >= 10000; pic_num_t need_pic = pic % 1000; if(univ.party.direction >= 4) need_pic++; graf_pos_ref(from_gw, source_rect) = spec_scen_g.find_graphic(need_pic, isParty); } else if(pic >= 100) { // Note that we assume it's a 1x1 graphic. // PCs can't be larger than that, but we leave it to the scenario designer to avoid assigning larger graphics. pic_num_t need_pic = pic - 100; int mode = 0; if(univ.party.direction >= 4) mode++; source_rect = get_monster_template_rect(need_pic, mode, 0); int which_sheet = m_pic_index[need_pic].i / 20; from_gw = ResMgr::get<ImageRsrc>("monst" + std::to_string(1 + which_sheet)).get(); } else { source_rect = calc_rect(2 * (pic / 8), pic % 8); if(univ.party.direction >= 4) source_rect.offset(28,0); from_gw = ResMgr::get<ImageRsrc>("pcs").get(); } ter_num_t ter = 0; if(is_out()) ter = univ.out[univ.party.p_loc.x][univ.party.p_loc.y]; else if(is_town() || is_combat()) ter = univ.town->terrain(univ.town.p_loc.x,univ.town.p_loc.y); // now wedge in bed graphic if(is_town() && univ.scenario.ter_types[ter].special == eTerSpec::BED) draw_one_terrain_spot((short) target.x,(short) target.y,10000 + univ.scenario.ter_types[ter].flag1); else Draw_Some_Item(*from_gw, source_rect, terrain_screen_gworld, target, 1, 0); } else if(univ.party.in_boat >= 0) { if(univ.party.direction == DIR_N) i = 2; else if(univ.party.direction == DIR_S) i = 3; else i = univ.party.direction > DIR_S; Draw_Some_Item(*ResMgr::get<ImageRsrc>("vehicle"), calc_rect(i,0), terrain_screen_gworld, target, 1, 0); }else { i = univ.party.direction > 3; Draw_Some_Item(*ResMgr::get<ImageRsrc>("vehicle"), calc_rect(i + 2, 1), terrain_screen_gworld, target, 1, 0); } }
void draw_monsters() { short i,j = 0,k; short width,height; rectangle source_rect,to_rect; location where_draw,store_loc; ter_num_t ter; rectangle monst_rects[4][4] = { {{0,0,36,28}}, {{0,7,18,21},{18,7,36,21}}, {{9,0,27,14},{9,14,27,28}}, {{0,0,18,14},{0,14,18,28},{18,0,36,14},{18,14,36,28}} }; if(is_out()) for(i = 0; i < 10; i++) if(univ.party.out_c[i].exists) { if((point_onscreen(univ.party.p_loc, univ.party.out_c[i].m_loc)) && (can_see_light(univ.party.p_loc, univ.party.out_c[i].m_loc,sight_obscurity) < 5)) { where_draw.x = univ.party.out_c[i].m_loc.x - univ.party.p_loc.x + 4; where_draw.y = univ.party.out_c[i].m_loc.y - univ.party.p_loc.y + 4; for(j = 0; univ.party.out_c[i].what_monst.monst[j] == 0 && j < 7; j++); short picture_wanted; if(j == 7) univ.party.out_c[i].exists = false; // begin watch out else { picture_wanted = get_monst_picnum(univ.party.out_c[i].what_monst.monst[j]); } // end watch out if(univ.party.out_c[i].exists) { get_monst_dims(univ.party.out_c[i].what_monst.monst[j],&width,&height); if(picture_wanted >= 1000) { for(k = 0; k < width * height; k++) { sf::Texture* src_gw; graf_pos_ref(src_gw, source_rect) = spec_scen_g.find_graphic(picture_wanted % 1000 + ((univ.party.out_c[i].direction < 4) ? 0 : (width * height)) + k); to_rect = monst_rects[(width - 1) * 2 + height - 1][k]; to_rect.offset(13 + 28 * where_draw.x,13 + 36 * where_draw.y); rect_draw_some_item(*src_gw, source_rect, terrain_screen_gworld,to_rect, sf::BlendAlpha); } } if(picture_wanted < 1000) { for(k = 0; k < width * height; k++) { source_rect = get_monster_template_rect(picture_wanted,(univ.party.out_c[i].direction < 4) ? 0 : 1,k); to_rect = monst_rects[(width - 1) * 2 + height - 1][k]; to_rect.offset(13 + 28 * where_draw.x,13 + 36 * where_draw.y); int which_sheet = m_pic_index[picture_wanted].i / 20; sf::Texture& monst_gworld = *ResMgr::get<ImageRsrc>("monst" + std::to_string(1 + which_sheet)); rect_draw_some_item(monst_gworld, source_rect, terrain_screen_gworld,to_rect, sf::BlendAlpha); } } } } } if(is_town() || is_combat()) { for(i = 0; i < univ.town.monst.size(); i++) if(univ.town.monst[i].active != 0 && !univ.town.monst[i].invisible && univ.town.monst[i].status[eStatus::INVISIBLE] <= 0) if(point_onscreen(center,univ.town.monst[i].cur_loc) && party_can_see_monst(i)) { where_draw.x = univ.town.monst[i].cur_loc.x - center.x + 4; where_draw.y = univ.town.monst[i].cur_loc.y - center.y + 4; get_monst_dims(univ.town.monst[i].number,&width,&height); for(k = 0; k < width * height; k++) { store_loc = where_draw; store_loc.x += k % width; store_loc.y += k / width; ter = univ.town->terrain(univ.town.monst[i].cur_loc.x,univ.town.monst[i].cur_loc.y); // in bed? if(store_loc.x >= 0 && store_loc.x < 9 && store_loc.y >= 0 && store_loc.y < 9 && (univ.scenario.ter_types[ter].special == eTerSpec::BED) && isHumanoid(univ.town.monst[i].m_type) && (univ.town.monst[i].active == 1 || univ.town.monst[i].target == 6) && width == 1 && height == 1) draw_one_terrain_spot((short) where_draw.x,(short) where_draw.y,10000 + univ.scenario.ter_types[ter].flag1); else if(univ.town.monst[i].picture_num >= 1000) { bool isParty = univ.town.monst[i].picture_num >= 10000; sf::Texture* src_gw; pic_num_t need_pic = (univ.town.monst[i].picture_num % 1000) + k; if(univ.town.monst[i].direction >= 4) need_pic += width * height; if(combat_posing_monster == i + 100) need_pic += (2 * width * height); graf_pos_ref(src_gw, source_rect) = spec_scen_g.find_graphic(need_pic, isParty); Draw_Some_Item(*src_gw, source_rect, terrain_screen_gworld, store_loc, 1, 0); } else { pic_num_t this_monst = univ.town.monst[i].picture_num; int pic_mode = (univ.town.monst[i].direction) < 4 ? 0 : 1; pic_mode += (combat_posing_monster == i + 100) ? 10 : 0; source_rect = get_monster_template_rect(this_monst, pic_mode, k); int which_sheet = m_pic_index[this_monst].i / 20; sf::Texture& monst_gworld = *ResMgr::get<ImageRsrc>("monst" + std::to_string(1 + which_sheet)); Draw_Some_Item(monst_gworld, source_rect, terrain_screen_gworld, store_loc, 1, 0); } } } } }
short can_see_light(location p1, location p2, std::function<short(short,short)> get_obscurity) { if(is_combat() && !combat_pt_in_light(p2)) return 6; else if(is_town() && !pt_in_light(p1,p2)) return 6; return can_see(p1, p2, get_obscurity); }