TbScreenMode switch_to_next_video_mode(void) { TbScreenMode scrmode; scrmode = get_next_vidmode(lbDisplay.ScreenMode); if ( setup_screen_mode(scrmode) ) { settings.video_scrnmode = scrmode; } else { SYNCLOG("Can't enter %s (mode %d), falling to failsafe mode", get_vidmode_name(scrmode),(int)scrmode); scrmode = get_failsafe_vidmode(); if ( !setup_screen_mode(scrmode) ) { FatalError = 1; exit_keeper = 1; return Lb_SCREEN_MODE_INVALID; } settings.video_scrnmode = scrmode; } SYNCLOG("Switched video to %s (mode %d)", get_vidmode_name(scrmode),(int)scrmode); save_settings(); if (game.numfield_C & 0x20) setup_engine_window(status_panel_width, 0, MyScreenWidth, MyScreenHeight); else setup_engine_window(0, 0, MyScreenWidth, MyScreenHeight); // reinit_all_menus(); return scrmode; }
TbResult LbMouseChangeSpriteAndHotspot(struct TbSprite *pointerSprite, long hot_x, long hot_y) { #if (BFDEBUG_LEVEL > 18) if (pointerSprite == NULL) SYNCLOG("Setting to %s","NONE"); else SYNCLOG("Setting to %dx%d, data at %p",(int)pointerSprite->SWidth,(int)pointerSprite->SHeight,pointerSprite); #endif if (!lbMouseInstalled) return Lb_FAIL; if (!pointerHandler.SetMousePointerAndOffset(pointerSprite, hot_x, hot_y)) return Lb_FAIL; return Lb_SUCCESS; }
/** * Re-adds item to the amount available to be placed on map, if an empty trap gets destroyed. * @param owner * @param tngclass * @param tngmodel * @return * @note was named add_workshop_item() */ TbBool readd_workshop_item_to_amount_placeable_f(PlayerNumber plyr_idx, ThingClass tngclass, ThingModel tngmodel, const char *func_name) { struct Dungeon *dungeon; dungeon = get_players_num_dungeon_f(plyr_idx,func_name); if (dungeon_invalid(dungeon)) { ERRORLOG("%s: Can't add item; player %d has no dungeon.",func_name,(int)plyr_idx); return false; } switch (tngclass) { case TCls_Trap: SYNCDBG(8,"%s: Adding Trap %s",func_name,trap_code_name(tngmodel)); dungeon->trap_amount_placeable[tngmodel]++; if (dungeon->trap_amount_placeable[tngmodel] > dungeon->trap_amount_stored[tngmodel]+dungeon->trap_amount_offmap[tngmodel]) { SYNCLOG("%s: Placeable %s traps amount for player %d was too large; fixed",func_name,trap_code_name(tngmodel),(int)plyr_idx); dungeon->trap_amount_placeable[tngmodel] = dungeon->trap_amount_stored[tngmodel]+dungeon->trap_amount_offmap[tngmodel]; } if (dungeon->trap_amount_placeable[tngmodel] < dungeon->trap_amount_offmap[tngmodel]) { WARNLOG("%s: Placeable %s traps amount for player %d was too small; fixed",func_name,trap_code_name(tngmodel),(int)plyr_idx); dungeon->trap_amount_placeable[tngmodel] = dungeon->trap_amount_offmap[tngmodel]; } break; case TCls_Door: SYNCDBG(8,"%s: Adding Door %s",func_name,door_code_name(tngmodel)); dungeon->door_amount_placeable[tngmodel]++; // In case the placeable amount lost it, do a fix if (dungeon->door_amount_placeable[tngmodel] > dungeon->door_amount_stored[tngmodel]+dungeon->door_amount_offmap[tngmodel]) { SYNCLOG("%s: Placeable %s doors amount for player %d was too large; fixed",func_name,door_code_name(tngmodel),(int)plyr_idx); dungeon->door_amount_placeable[tngmodel] = dungeon->door_amount_stored[tngmodel]+dungeon->door_amount_offmap[tngmodel]; } if (dungeon->door_amount_placeable[tngmodel] < dungeon->door_amount_offmap[tngmodel]) { WARNLOG("%s: Placeable %s doors amount for player %d was too small; fixed",func_name,door_code_name(tngmodel),(int)plyr_idx); dungeon->door_amount_placeable[tngmodel] = dungeon->door_amount_offmap[tngmodel]; } break; default: ERRORLOG("%s: Can't add item; illegal item class %d",func_name,(int)tngclass); return false; } return true; }
/** * Loads the language-specific strings data for game interface. */ TbBool setup_gui_strings_data(void) { char *strings_data_end; char *fname; short result; long filelen; long loaded_size; SYNCDBG(8,"Starting"); fname = prepare_file_fmtpath(FGrp_FxData,"gtext_%s.dat",get_language_lwrstr(install_info.lang_id)); filelen = LbFileLengthRnc(fname); if (filelen <= 0) { ERRORLOG("GUI Strings file does not exist or can't be opened"); SYNCLOG("Strings file name is \"%s\"",fname); return false; } gui_strings_data = (char *)LbMemoryAlloc(filelen + 256); if (gui_strings_data == NULL) { ERRORLOG("Can't allocate memory for GUI Strings data"); SYNCLOG("Strings file name is \"%s\"",fname); return false; } strings_data_end = gui_strings_data+filelen+255; loaded_size = LbFileLoadAt(fname, gui_strings_data); if (loaded_size < 16) { ERRORLOG("GUI Strings file couldn't be loaded or is too small"); return false; } // Resetting all values to empty strings reset_strings(gui_strings); // Analyzing strings data and filling correct values result = create_strings_list(gui_strings, gui_strings_data, strings_data_end); // Updating strings inside the DLL LbMemoryCopy(_DK_strings, gui_strings, DK_STRINGS_MAX*sizeof(char *)); SYNCDBG(19,"Finished"); return result; }
TbBool set_creature_assigned_job(struct Thing *thing, CreatureJob new_job) { struct CreatureControl *cctrl; TRACE_THING(thing); cctrl = creature_control_get_from_thing(thing); if (creature_control_invalid(cctrl)) { ERRORLOG("The %s index %d has invalid control",thing_model_name(thing),(int)thing->index); return false; } cctrl->job_assigned = new_job; SYNCLOG("Assigned job %s for %s index %d owner %d",creature_job_code_name(new_job),thing_model_name(thing),(int)thing->index,(int)thing->owner); return true; }
/** * Changes mouse movement ratio. * Note that this function can be run even before mouse setup. Still, the factor * will be reset during the installation - so use it after LbMouseSetup(). * * @param ratio_x Movement ratio in X direction; 256 means unchanged ratio from OS. * @param ratio_y Movement ratio in Y direction; 256 means unchanged ratio from OS. * @return Lb_SUCCESS if the ratio values were of correct range and have been set. */ TbResult LbMouseChangeMoveRatio(long ratio_x, long ratio_y) { if ((ratio_x < -8192) || (ratio_x > 8192) || (ratio_x == 0)) return Lb_FAIL; if ((ratio_y < -8192) || (ratio_y > 8192) || (ratio_y == 0)) return Lb_FAIL; SYNCLOG("New ratio %ldx%ld",ratio_x, ratio_y); // Currently we don't have two ratio factors, so let's store an average lbDisplay.MouseMoveRatio = (ratio_x + ratio_y)/2; //TODO INPUT Separate mouse ratios in X and Y direction when lbDisplay from DLL will no longer be used. //minfo.XMoveRatio = ratio_x; //minfo.YMoveRatio = ratio_y; return Lb_SUCCESS; }
TbScreenMode reenter_video_mode(void) { TbScreenMode scrmode; scrmode=validate_vidmode(settings.video_scrnmode); if ( setup_screen_mode(scrmode) ) { settings.video_scrnmode = scrmode; } else { SYNCLOG("Can't enter %s (mode %d), falling to failsafe mode", get_vidmode_name(scrmode),(int)scrmode); scrmode=get_failsafe_vidmode(); if ( !setup_screen_mode(scrmode) ) { _DK_FatalError = 1; exit_keeper = 1; return Lb_SCREEN_MODE_INVALID; } settings.video_scrnmode = scrmode; save_settings(); } SYNCLOG("Switched video to %s (mode %d)", get_vidmode_name(scrmode),(int)scrmode); return scrmode; }
TbBool good_setup_wander_to_exit(struct Thing *creatng) { struct Thing *gatetng; SYNCDBG(7,"Starting"); gatetng = find_hero_door_hero_can_navigate_to(creatng); if (thing_is_invalid(gatetng)) { SYNCLOG("Can't find any exit gate for hero %s.",thing_model_name(creatng)); return false; } if (!setup_person_move_to_coord(creatng, &gatetng->mappos, NavRtF_Default)) { WARNLOG("Hero %s index %d can't move to exit gate at (%d,%d).",thing_model_name(creatng), (int)gatetng->index, (int)gatetng->mappos.x.stl.num, (int)gatetng->mappos.y.stl.num); return false; } creatng->continue_state = CrSt_GoodLeaveThroughExitDoor; return true; }
/** * Quick attack is just putting CTA spell on enemy room. * @param comp * @param check */ long computer_check_for_quick_attack(struct Computer2 *comp, struct ComputerCheck * check) { struct Dungeon *dungeon; SYNCDBG(8,"Starting"); dungeon = comp->dungeon; int creatrs_num; creatrs_num = check->param1 * dungeon->num_active_creatrs / 100; if (check->param3 >= creatrs_num) { return CTaskRet_Unk4; } if (computer_able_to_use_magic(comp, PwrK_CALL2ARMS, 1, 3) != 1) { return CTaskRet_Unk4; } if ((check_call_to_arms(comp) != 1) || is_there_an_attack_task(comp)) { return CTaskRet_Unk4; } struct Room *room; room = get_hated_room_for_quick_attack(comp, check->param3); if (room_is_invalid(room)) { return CTaskRet_Unk4; } struct Coord3d pos; // TODO COMPUTER_PLAYER We should make sure the place of cast is accessible for creatures pos.x.val = subtile_coord_center(room->central_stl_x); pos.y.val = subtile_coord_center(room->central_stl_y); pos.z.val = subtile_coord(1,0); if (count_creatures_availiable_for_fight(comp, &pos) <= check->param3) { return CTaskRet_Unk4; } if (!create_task_magic_support_call_to_arms(comp, &pos, check->param2, 0, creatrs_num)) { return CTaskRet_Unk4; } SYNCLOG("Player %d decided to attack %s owned by player %d",(int)dungeon->owner,room_code_name(room->kind),(int)room->owner); output_message(SMsg_EnemyHarassments+ACTION_RANDOM(8), 500, 1); return CTaskRet_Unk1; }
TbBool init_sound_heap_two_banks(unsigned char *heap_mem, long heap_size, char *snd_fname, char *spc_fname, long a5) { long i; long buf_len; unsigned char *buf; SYNCDBG(8,"Starting"); LbMemorySet(heap_mem, 0, heap_size); using_two_banks = 0; // Open first sound bank and prepare sample table if (sound_file != -1) close_sound_bank(0); samples_in_bank = 0; sound_file = _DK_LbFileOpen(snd_fname,Lb_FILE_MODE_READ_ONLY); if (sound_file == -1) { ERRORLOG("Couldn't open primary sound bank file \"%s\"",snd_fname); return false; } buf = heap_mem; buf_len = heap_size; i = parse_sound_file(sound_file, buf, &samples_in_bank, buf_len, a5); if (i == 0) { ERRORLOG("Couldn't parse sound bank file \"%s\"",snd_fname); close_sound_heap(); return false; } sample_table = (struct SampleTable *)buf; buf_len -= i; buf += i; if (buf_len <= 0) { ERRORLOG("Sound bank buffer too short"); close_sound_heap(); return false; } // Open second sound bank and prepare sample table if (sound_file2 != -1) close_sound_bank(1); samples_in_bank2 = 0; sound_file2 = _DK_LbFileOpen(spc_fname,Lb_FILE_MODE_READ_ONLY); if (sound_file2 == -1) { ERRORLOG("Couldn't open secondary sound bank file \"%s\"",spc_fname); return false; } i = parse_sound_file(sound_file2, buf, &samples_in_bank2, buf_len, a5); if (i == 0) { ERRORLOG("Couldn't parse sound bank file \"%s\"",spc_fname); close_sound_heap(); return false; } sample_table2 = (struct SampleTable *)buf; buf_len -= i; buf += i; if (buf_len <= 0) { ERRORLOG("Sound bank buffer too short"); close_sound_heap(); return false; } SYNCLOG("Got sound buffer of %ld bytes, samples in banks: %d,%d",buf_len,(int)samples_in_bank,(int)samples_in_bank2); sndheap = heapmgr_init(buf, buf_len, samples_in_bank2 + samples_in_bank); if (sndheap == NULL) { ERRORLOG("Sound heap manager init error"); close_sound_heap(); return false; } using_two_banks = 1; return true; }
TbBool lights_stats_debug_dump(void) { long lights[LIGHTS_COUNT]; long lgh_things[THING_CLASSES_COUNT]; long shadowcs[SHADOW_CACHE_COUNT]; long shdc_used,shdc_linked,shdc_free; long lgh_used,lgh_free; long lgh_sttc,lgh_dynm; struct Thing * thing; struct Light *lgt; struct ShadowCache *shdc; long i,n; for (i=0; i < SHADOW_CACHE_COUNT; i++) { shdc = &game.lish.shadow_cache[i]; if ((shdc->flags & ShCF_Allocated) != 0) shadowcs[i] = -1; else shadowcs[i] = 0; } lgh_sttc = 0; lgh_dynm = 0; for (i=0; i < LIGHTS_COUNT; i++) { lgt = &game.lish.lights[i]; if ((lgt->flags & LgtF_Allocated) != 0) { lights[i] = -1; if ((lgt->flags & LgtF_Dynamic) != 0) lgh_dynm++; else lgh_sttc++; if ( (lgt->shadow_index > 0) && (lgt->shadow_index < SHADOW_CACHE_COUNT) ) { if (shadowcs[lgt->shadow_index] == -1) { shadowcs[lgt->shadow_index] = i; } else if (shadowcs[lgt->shadow_index] == 0) { WARNLOG("Shadow Cache %d is not allocated, but used by light %d!",(int)lgt->shadow_index,(int)i); } else { WARNLOG("Shadow Cache %d is double-allocated, for lights %d and %d!",(int)lgt->shadow_index,(int)shadowcs[lgt->shadow_index],(int)i); } } else if ((lgt->flags & LgtF_Dynamic) != 0) { WARNLOG("Dynamic light %d has bad Shadow Cache %d!",(int)i,(int)lgt->shadow_index); } } else { lights[i] = 0; } } for (i=1; i < THINGS_COUNT; i++) { thing = thing_get(i); if (thing_exists(thing)) { if ((thing->light_id > 0) && (thing->light_id < LIGHTS_COUNT)) { n = 1000+(long)thing->class_id; if (lights[thing->light_id] == -1) { lights[thing->light_id] = n; } else if (lights[thing->light_id] == 0) { WARNLOG("Light %d is not allocated, but used by %s!",(int)thing->light_id, thing_model_name(thing)); } else { WARNLOG("Light %d is double-allocated, for %d and %d!",(int)thing->light_id, (int)lights[thing->light_id], (int)n); } } } } lgh_used = 0; lgh_free = 0; for (i=0; i < THING_CLASSES_COUNT; i++) lgh_things[i] = 0; for (i=0; i < LIGHTS_COUNT; i++) { if (lights[i] != 0) { lgh_used++; if ((lights[i] > 1000) && (lights[i] < 1000+THING_CLASSES_COUNT)) lgh_things[lights[i]-1000]++; } else { lgh_free++; } } shdc_free = 0; shdc_used = 0; shdc_linked = 0; for (i=0; i < SHADOW_CACHE_COUNT; i++) { if (shadowcs[i] != 0) { shdc_used++; if (shadowcs[i] > 0) shdc_linked++; } else { shdc_free++; } } SYNCLOG("Lights: %ld free, %ld used; %ld static, %ld dynamic; for things:%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld",lgh_free,lgh_used,lgh_sttc,lgh_dynm,lgh_things[1],lgh_things[2],lgh_things[3],lgh_things[4],lgh_things[5],lgh_things[6],lgh_things[7],lgh_things[8],lgh_things[9],lgh_things[10],lgh_things[11],lgh_things[12],lgh_things[13]); if ((shdc_used != shdc_linked) || (shdc_used != lgh_dynm)) { WARNLOG("Amount of shadow cache mismatches: %ld free, %ld used, %ld linked to lights, %d dyn. lights.",shdc_free,shdc_used,shdc_linked,light_total_dynamic_lights); } if (lgh_sttc != light_total_stat_lights) { WARNLOG("Wrong global lights counter: %ld static lights and counter says %ld.",lgh_sttc,light_total_stat_lights); } if (lgh_dynm != light_total_dynamic_lights) { WARNLOG("Wrong global lights counter: %ld dynamic lights and counter says %ld.",lgh_dynm,light_total_dynamic_lights); } return false; }