From b98662f2b69b3ba9c1e5f9437fe47bb5603f3243 Mon Sep 17 00:00:00 2001 From: Pieter Vandecandelaere Date: Thu, 30 Jan 2025 16:05:36 +0100 Subject: [PATCH] Refactor in preparation for Lua (#3855) --- Makefile | 2 +- keeperfx_vs2010.vcxproj | 4 +- keeperfx_vs2010.vcxproj.filters | 12 +- src/creature_states.c | 2 +- src/engine_redraw.c | 2 +- src/frontend.cpp | 2 +- src/frontmenu_ingame_evnt.c | 2 +- src/frontmenu_ingame_tabs.c | 2 +- src/game_loop.c | 2 +- src/globals.h | 3 + src/keeperfx.hpp | 1 - src/lvl_script_lib.c | 79 +----------- src/lvl_script_lib.h | 1 - src/lvl_script_value.c | 215 +------------------------------- src/{magic.c => magic_powers.c} | 145 ++++++++++++++++----- src/{magic.h => magic_powers.h} | 13 +- src/main.cpp | 87 +------------ src/map_locations.c | 102 ++++++++++++++- src/map_locations.h | 11 +- src/packets.c | 2 +- src/packets_cheats.c | 2 +- src/packets_input.c | 2 +- src/player_compchecks.c | 2 +- src/player_compevents.c | 2 +- src/player_comptask.c | 46 ++++++- src/player_computer.c | 2 +- src/player_computer.h | 1 + src/player_computer_data.cpp | 2 +- src/player_instances.c | 2 +- src/player_utils.c | 2 +- src/power_hand.c | 2 +- src/power_specials.c | 46 +++++++ src/power_specials.h | 6 + src/room_data.c | 2 +- src/room_library.c | 2 +- src/thing_creature.c | 179 +++++++++++++++++++------- src/thing_creature.h | 2 + src/thing_list.c | 2 +- src/thing_objects.c | 2 +- src/thing_shots.c | 2 +- src/thing_traps.c | 2 +- 41 files changed, 504 insertions(+), 495 deletions(-) rename src/{magic.c => magic_powers.c} (94%) rename src/{magic.h => magic_powers.h} (89%) diff --git a/Makefile b/Makefile index dd89b4bd58..7b8f0cc6c5 100644 --- a/Makefile +++ b/Makefile @@ -250,7 +250,7 @@ obj/lvl_script_commands_old.o \ obj/lvl_script_lib.o \ obj/lvl_script_conditions.o \ obj/lvl_script_value.o \ -obj/magic.o \ +obj/magic_powers.o \ obj/main_game.o \ obj/map_blocks.o \ obj/map_columns.o \ diff --git a/keeperfx_vs2010.vcxproj b/keeperfx_vs2010.vcxproj index 5f8b340e85..779e86e185 100644 --- a/keeperfx_vs2010.vcxproj +++ b/keeperfx_vs2010.vcxproj @@ -184,7 +184,7 @@ - + @@ -414,7 +414,7 @@ - + diff --git a/keeperfx_vs2010.vcxproj.filters b/keeperfx_vs2010.vcxproj.filters index 54560434d6..f5e45e9c70 100644 --- a/keeperfx_vs2010.vcxproj.filters +++ b/keeperfx_vs2010.vcxproj.filters @@ -399,9 +399,6 @@ Source Files - - Source Files - Source Files @@ -738,6 +735,9 @@ Source Files + + Source Files + @@ -1172,9 +1172,6 @@ Header Files - - Header Files - Header Files @@ -1397,6 +1394,9 @@ Header Files + + Header Files + diff --git a/src/creature_states.c b/src/creature_states.c index 1cb11dfd2d..2e0f458e49 100644 --- a/src/creature_states.c +++ b/src/creature_states.c @@ -59,7 +59,7 @@ #include "player_instances.h" #include "player_computer.h" #include "thing_traps.h" -#include "magic.h" +#include "magic_powers.h" #include "sounds.h" #include "game_legacy.h" #include "sprites.h" diff --git a/src/engine_redraw.c b/src/engine_redraw.c index b9e5a5824f..c5621bb997 100644 --- a/src/engine_redraw.c +++ b/src/engine_redraw.c @@ -56,7 +56,7 @@ #include "config_players.h" #include "config_magic.h" #include "config_spritecolors.h" -#include "magic.h" +#include "magic_powers.h" #include "game_merge.h" #include "game_legacy.h" #include "creature_instances.h" diff --git a/src/frontend.cpp b/src/frontend.cpp index d2dff748a7..4d0b14a931 100644 --- a/src/frontend.cpp +++ b/src/frontend.cpp @@ -73,7 +73,7 @@ #include "thing_stats.h" #include "thing_traps.h" #include "power_hand.h" -#include "magic.h" +#include "magic_powers.h" #include "player_instances.h" #include "player_utils.h" #include "config_players.h" diff --git a/src/frontmenu_ingame_evnt.c b/src/frontmenu_ingame_evnt.c index fbc08c2969..0c38b0e563 100644 --- a/src/frontmenu_ingame_evnt.c +++ b/src/frontmenu_ingame_evnt.c @@ -32,7 +32,7 @@ #include "creature_battle.h" #include "creature_graphics.h" #include "config_creature.h" -#include "magic.h" +#include "magic_powers.h" #include "gui_draw.h" #include "gui_frontbtns.h" #include "gui_frontmenu.h" diff --git a/src/frontmenu_ingame_tabs.c b/src/frontmenu_ingame_tabs.c index d1464a83d2..f5496e753a 100644 --- a/src/frontmenu_ingame_tabs.c +++ b/src/frontmenu_ingame_tabs.c @@ -50,7 +50,7 @@ #include "gui_parchment.h" #include "gui_draw.h" #include "packets.h" -#include "magic.h" +#include "magic_powers.h" #include "player_computer.h" #include "player_instances.h" #include "config_players.h" diff --git a/src/game_loop.c b/src/game_loop.c index ba9123b212..3c2045a4fa 100644 --- a/src/game_loop.c +++ b/src/game_loop.c @@ -28,7 +28,7 @@ #include "room_workshop.h" #include "map_columns.h" #include "creature_states.h" -#include "magic.h" +#include "magic_powers.h" #include "game_merge.h" #include "sounds.h" #include "game_legacy.h" diff --git a/src/globals.h b/src/globals.h index 94848e9dfe..3243d910cf 100644 --- a/src/globals.h +++ b/src/globals.h @@ -282,6 +282,9 @@ typedef int8_t SmallAroundIndex; /** a player state as defined in config_players*/ typedef unsigned char PlayerState; typedef unsigned short CctrlIndex; +/** index to a function, positive for C functions, negative for lua functions*/ +typedef short FuncIdx; +typedef unsigned long TbMapLocation; /** diff --git a/src/keeperfx.hpp b/src/keeperfx.hpp index 4d0ab393cd..b2571dbe4f 100644 --- a/src/keeperfx.hpp +++ b/src/keeperfx.hpp @@ -263,7 +263,6 @@ void draw_gold_total(PlayerNumber plyr_idx, long scr_x, long scr_y, long units_p void draw_mini_things_in_hand(long x, long y); TbBool screen_to_map(struct Camera *camera, long screen_x, long screen_y, struct Coord3d *mappos); void update_creatr_model_activities_list(TbBool forced); -void find_map_location_coords(TbMapLocation location, long *x, long *y, int plyr_idx, const char *func_name); TbBool any_player_close_enough_to_see(const struct Coord3d *pos); void affect_nearby_stuff_with_vortex(struct Thing *thing); void affect_nearby_friends_with_alarm(struct Thing *thing); diff --git a/src/lvl_script_lib.c b/src/lvl_script_lib.c index 7f82c4e50f..0ee3eaed0e 100644 --- a/src/lvl_script_lib.c +++ b/src/lvl_script_lib.c @@ -23,7 +23,7 @@ #include "dungeon_data.h" #include "lvl_filesdk1.h" #include "creature_states_pray.h" -#include "magic.h" +#include "magic_powers.h" #include "config_creature.h" #include "gui_msgs.h" #include "post_inc.h" @@ -198,83 +198,6 @@ long get_players_range_single_f(long plr_range_id, const char *func_name, long l return -2; } -static int filter_criteria_type(long desc_type) -{ - return desc_type & 0x0F; -} - -static long filter_criteria_loc(long desc_type) -{ - return desc_type >> 4; -} - -struct Thing* script_get_creature_by_criteria(PlayerNumber plyr_idx, ThingModel crmodel, long criteria) -{ - switch (filter_criteria_type(criteria)) - { - case CSelCrit_Any: - return get_random_players_creature_of_model(plyr_idx, crmodel); - case CSelCrit_MostExperienced: - return find_players_highest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Any, plyr_idx, 0); - case CSelCrit_MostExpWandering: - return find_players_highest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Wandering, plyr_idx, 0); - case CSelCrit_MostExpWorking: - return find_players_highest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Working, plyr_idx, 0); - case CSelCrit_MostExpFighting: - return find_players_highest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Fighting, plyr_idx, 0); - case CSelCrit_LeastExperienced: - return find_players_lowest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Any, plyr_idx, 0); - case CSelCrit_LeastExpWandering: - return find_players_lowest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Wandering, plyr_idx, 0); - case CSelCrit_LeastExpWorking: - return find_players_lowest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Working, plyr_idx, 0); - case CSelCrit_LeastExpFighting: - return find_players_lowest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Fighting, plyr_idx, 0); - case CSelCrit_NearOwnHeart: - return get_player_creature_in_range_around_own_heart(plyr_idx, crmodel, 11); - case CSelCrit_NearEnemyHeart: - return get_player_creature_in_range_around_any_enemy_heart(plyr_idx, crmodel, 11); - case CSelCrit_OnEnemyGround: - return get_random_players_creature_of_model_on_territory(plyr_idx, crmodel, 0); - case CSelCrit_OnFriendlyGround: - return get_random_players_creature_of_model_on_territory(plyr_idx, crmodel, 1); - case CSelCrit_OnNeutralGround: - return get_random_players_creature_of_model_on_territory(plyr_idx, crmodel, 2); - case CSelCrit_NearAP: - { - int loc = filter_criteria_loc(criteria); - struct ActionPoint* apt = action_point_get(loc); - if (!action_point_exists(apt)) - { - WARNLOG("Action point is invalid:%d", apt->num); - return INVALID_THING; - } - if (apt->range == 0) - { - WARNLOG("Action point with zero range:%d", apt->num); - return INVALID_THING; - } - // Action point range should be inside spiral in subtiles - int dist = 2 * coord_subtile(apt->range + COORD_PER_STL - 1) + 1; - dist = dist * dist; - - Thing_Maximizer_Filter filter = near_map_block_creature_filter_diagonal_random; - struct CompoundTngFilterParam param; - param.model_id = crmodel; - param.plyr_idx = (unsigned char)plyr_idx; - param.num1 = apt->mappos.x.val; - param.num2 = apt->mappos.y.val; - param.num3 = apt->range; - return get_thing_spiral_near_map_block_with_filter(apt->mappos.x.val, apt->mappos.y.val, - dist, - filter, ¶m); - } - default: - ERRORLOG("Invalid level up criteria %d", (int)criteria); - return INVALID_THING; - } -} - void get_player_number_from_value(const char* txt, char* id, char* type) { char idx; diff --git a/src/lvl_script_lib.h b/src/lvl_script_lib.h index 719346f873..bebd2025e5 100644 --- a/src/lvl_script_lib.h +++ b/src/lvl_script_lib.h @@ -301,7 +301,6 @@ enum ScriptVariables { #define FX_LINE_TIME_PARTS 4 -struct Thing* script_get_creature_by_criteria(PlayerNumber plyr_idx, ThingModel crmodel, long criteria); ThingModel parse_creature_name(const char *creature_name); struct ScriptValue *allocate_script_value(void); struct Thing *script_process_new_object(ThingModel tngmodel, MapSubtlCoord stl_x, MapSubtlCoord stl_y, long arg, PlayerNumber plyr_idx, short move_angle); diff --git a/src/lvl_script_value.c b/src/lvl_script_value.c index 1e880e1f80..3c37a4e8e0 100644 --- a/src/lvl_script_value.c +++ b/src/lvl_script_value.c @@ -22,7 +22,7 @@ #include "map_data.h" #include "map_locations.h" #include "player_data.h" -#include "magic.h" +#include "magic_powers.h" #include "keeperfx.hpp" #include "lvl_filesdk1.h" #include "power_hand.h" @@ -131,219 +131,6 @@ TbBool script_level_up_creature(PlayerNumber plyr_idx, long crmodel, long criter return true; } -/** - * Cast a keeper power on a creature which meets given criteria. - * @param plyr_idx The player whose creature will be affected. - * @param crmodel Model of the creature to find. - * @param criteria Criteria, from CreatureSelectCriteria enumeration. - * @param fmcl_bytes encoded bytes: f=cast for free flag,m=power kind,c=caster player index,l=spell level. - * @return TbResult whether the spell was successfully cast - */ -TbResult script_use_power_on_creature_matching_criterion(PlayerNumber plyr_idx, long crmodel, long criteria, long fmcl_bytes) -{ - struct Thing* thing = script_get_creature_by_criteria(plyr_idx, crmodel, criteria); - if (thing_is_invalid(thing)) { - SYNCDBG(5, "No matching player %d creature of model %d (%s) found to use power on.", (int)plyr_idx, (int)crmodel, creature_code_name(crmodel)); - return Lb_FAIL; - } - - char is_free = (fmcl_bytes >> 24) != 0; - PowerKind pwkind = (fmcl_bytes >> 16) & 255; - PlayerNumber caster = (fmcl_bytes >> 8) & 255; - KeepPwrLevel power_level = fmcl_bytes & 255; - return script_use_power_on_creature(thing, pwkind, power_level, caster, is_free); -} - -/** - * Cast a spell on a creature which meets given criteria. - * @param plyr_idx The player whose creature will be affected. - * @param crmodel Model of the creature to find. - * @param criteria Criteria, from CreatureSelectCriteria enumeration. - * @param fmcl_bytes encoded bytes: f=cast for free flag,m=power kind,c=caster player index,l=spell level. - * @return TbResult whether the spell was successfully cast - */ -TbResult script_use_spell_on_creature(PlayerNumber plyr_idx, ThingModel crmodel, long criteria, long fmcl_bytes) -{ - struct Thing *thing = script_get_creature_by_criteria(plyr_idx, crmodel, criteria); - if (thing_is_invalid(thing)) - { - SYNCDBG(5, "No matching player %d creature of model %d (%s) found to use spell on.", (int)plyr_idx, (int)crmodel, creature_code_name(crmodel)); - return Lb_FAIL; - } - SpellKind spkind = (fmcl_bytes >> 8) & 255; - struct SpellConfig *spconf = get_spell_config(spkind); - if (!creature_is_immune_to_spell_effect(thing, spconf->spell_flags)) - { // Immunity is handled in 'apply_spell_effect_to_thing', but this command plays sounds, so check for it. - if (thing_is_picked_up(thing)) - { - SYNCDBG(5, "Found creature to cast the spell on but it is being held."); - return Lb_FAIL; - } - CrtrExpLevel spell_level = fmcl_bytes & 255; - if (spconf->caster_affect_sound) - { - thing_play_sample(thing, spconf->caster_affect_sound + UNSYNC_RANDOM(spconf->caster_sounds_count), NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); - } - apply_spell_effect_to_thing(thing, spkind, spell_level, plyr_idx); - if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) - { - struct CreatureControl *cctrl; - cctrl = creature_control_get_from_thing(thing); - cctrl->disease_caster_plyridx = game.neutral_player_num; // Does not spread. - } - return Lb_SUCCESS; - } - else - { - SCRPTERRLOG("Spell not supported for this command: %d", (int)spkind); - return Lb_FAIL; - } -} - -/** - * Adds a dig task for the player between 2 map locations. - * @param plyr_idx: The player who does the task. - * @param origin: The start location of the disk task. - * @param destination: The desitination of the disk task. - * @return TbResult whether the spell was successfully cast - */ -TbResult script_computer_dig_to_location(long plyr_idx, TbMapLocation origin, TbMapLocation destination) -{ - struct Computer2* comp = get_computer_player(plyr_idx); - long orig_x, orig_y = 0; - long dest_x, dest_y = 0; - - //dig origin - find_map_location_coords(origin, &orig_x, &orig_y, plyr_idx, __func__); - if ((orig_x == 0) && (orig_y == 0)) - { - WARNLOG("Can't decode origin location %ld", origin); - return Lb_FAIL; - } - struct Coord3d startpos; - startpos.x.val = subtile_coord_center(stl_slab_center_subtile(orig_x)); - startpos.y.val = subtile_coord_center(stl_slab_center_subtile(orig_y)); - startpos.z.val = subtile_coord(1, 0); - - //dig destination - find_map_location_coords(destination, &dest_x, &dest_y, plyr_idx, __func__); - if ((dest_x == 0) && (dest_y == 0)) - { - WARNLOG("Can't decode destination location %ld", destination); - return Lb_FAIL; - } - struct Coord3d endpos; - endpos.x.val = subtile_coord_center(stl_slab_center_subtile(dest_x)); - endpos.y.val = subtile_coord_center(stl_slab_center_subtile(dest_y)); - endpos.z.val = subtile_coord(1, 0); - - if (create_task_dig_to_neutral(comp, startpos, endpos)) - { - return Lb_SUCCESS; - } - return Lb_FAIL; -} - -/** - * Casts spell at a location set by subtiles. - * @param plyr_idx caster player. - * @param stl_x subtile's x position. - * @param stl_y subtile's y position - * @param fml_bytes encoded bytes: f=cast for free flag,m=power kind,l=spell level. - * @return TbResult whether the spell was successfully cast - */ -TbResult script_use_power_at_pos(PlayerNumber plyr_idx, MapSubtlCoord stl_x, MapSubtlCoord stl_y, long fml_bytes) -{ - char is_free = (fml_bytes >> 16) != 0; - PowerKind powerKind = (fml_bytes >> 8) & 255; - KeepPwrLevel power_level = fml_bytes & 255; - - unsigned long allow_flags = PwCast_AllGround | PwCast_Unrevealed; - unsigned long mod_flags = 0; - if (is_free) - set_flag(mod_flags,PwMod_CastForFree); - - return magic_use_power_on_subtile(plyr_idx, powerKind, power_level, stl_x, stl_y, allow_flags, mod_flags); -} - -/** - * Casts spell at a location set by action point/hero gate. - * @param plyr_idx caster player. - * @param target action point/hero gate. - * @param fml_bytes encoded bytes: f=cast for free flag,m=power kind,l=spell level. - * @return TbResult whether the spell was successfully cast - */ -TbResult script_use_power_at_location(PlayerNumber plyr_idx, TbMapLocation target, long fml_bytes) -{ - SYNCDBG(0, "Using power at location of type %lu", target); - long x = 0; - long y = 0; - find_map_location_coords(target, &x, &y, plyr_idx, __func__); - if ((x == 0) && (y == 0)) - { - WARNLOG("Can't decode location %lu", target); - return Lb_FAIL; - } - return script_use_power_at_pos(plyr_idx, x, y, fml_bytes); -} - -/** - * Casts a spell for player. - * @param plyr_idx caster player. - * @param power_kind the spell: magic id. - * @param free cast for free flag. - * @return TbResult whether the spell was successfully cast - */ -TbResult script_use_power(PlayerNumber plyr_idx, PowerKind power_kind, char free) -{ - return magic_use_power_on_level(plyr_idx, power_kind, 1, free != 0 ? PwMod_CastForFree : 0); // power_level gets ignored anyway -> pass 1 -} - -/** - * Increases creatures' levels for player. - * @param plyr_idx target player - * @param count how many times should the level be increased - */ -void script_use_special_increase_level(PlayerNumber plyr_idx, int count) -{ - increase_level(get_player(plyr_idx), count); -} - -/** - * Multiplies every creature for player. - * @param plyr_idx target player - */ -void script_use_special_multiply_creatures(PlayerNumber plyr_idx) -{ - multiply_creatures(get_player(plyr_idx)); -} - -/** - * Fortifies player's dungeon. - * @param plyr_idx target player - */ -void script_make_safe(PlayerNumber plyr_idx) -{ - make_safe(get_player(plyr_idx)); -} - -/** - * Defortifies player's dungeon. - * @param plyr_idx target player - */ -void script_make_unsafe(PlayerNumber plyr_idx) -{ - make_unsafe(plyr_idx); -} - -/** - * Enables bonus level for current player. - */ -TbBool script_locate_hidden_world() -{ - return activate_bonus_level(get_player(my_player_number)); -} - /** * Processes given VALUE immediately. * This processes given script command. It is used to process VALUEs at start when they have diff --git a/src/magic.c b/src/magic_powers.c similarity index 94% rename from src/magic.c rename to src/magic_powers.c index 01bc2a2380..2d3bce88cf 100644 --- a/src/magic.c +++ b/src/magic_powers.c @@ -1,7 +1,7 @@ /******************************************************************************/ // Free implementation of Bullfrog's Dungeon Keeper strategy game. /******************************************************************************/ -/** @file magic.c +/** @file magic_powers.c * magic support functions. * @par Purpose: * Functions to magic. @@ -17,7 +17,7 @@ */ /******************************************************************************/ #include "pre_inc.h" -#include "magic.h" +#include "magic_powers.h" #include "globals.h" #include "bflib_basics.h" @@ -59,6 +59,7 @@ #include "sounds.h" #include "game_legacy.h" #include "creature_instances.h" +#include "map_locations.h" #include "post_inc.h" #ifdef __cplusplus @@ -117,7 +118,7 @@ const Magic_use_Func magic_use_func_list[] = { /******************************************************************************/ /** - * Returns if spell can be casted or given thing and/or coordinates. + * Returns if power can be casted or given thing and/or coordinates. * @param plyr_idx * @param pwkind * @param stl_x @@ -630,12 +631,12 @@ TbBool can_cast_power_at_xy(PlayerNumber plyr_idx, PowerKind pwkind, MapSubtlCoo if (power_model_stats_invalid(powerst)) return false; can_cast = powerst->can_cast_flags | allow_flags; - // Allow casting only on revealed tiles (unless the spell overrides this) + // Allow casting only on revealed tiles (unless the power overrides this) if ((can_cast & PwCast_Unrevealed) == 0) { if (!map_block_revealed(mapblk, plyr_idx)) { - // If it's not revealed, we may still accept revealing by SOE spell + // If it's not revealed, we may still accept revealing by SOE power if ((can_cast & PwCast_RevealedTemp) == 0) { return false; } else @@ -780,7 +781,7 @@ GoldAmount compute_power_price(PlayerNumber plyr_idx, PowerKind pwkind, KeepPwrL long price; switch (powerst->cost_formula) { - case Cost_Digger: // Special price algorithm for "create imp" spell + case Cost_Digger: // Special price algorithm for "create imp" power dungeon = get_players_num_dungeon(plyr_idx); // Increase price by amount of diggers, reduce by count of sacrificed diggers. Cheaper diggers may be a negative amount. if (get_players_special_digger_model(plyr_idx) == powerst->creature_model) @@ -819,7 +820,7 @@ GoldAmount compute_lowest_power_price(PlayerNumber plyr_idx, PowerKind pwkind, K long price; switch (pwkind) { - case PwrK_MKDIGGER: // Special price algorithm for "create imp" spell + case PwrK_MKDIGGER: // Special price algorithm for "create imp" power // To get lowest price = compute_power_price_scaled_with_amount(plyr_idx, pwkind, power_level, 0); break; @@ -929,7 +930,7 @@ static TbResult magic_use_power_armageddon(PowerKind power_kind, PlayerNumber pl } if ((mod_flags & PwMod_CastForFree) == 0) { - // If we can't afford the spell, fail + // If we can't afford the power, fail if (!pay_for_spell(plyr_idx, power_kind, 0)) { if (is_my_player_number(plyr_idx)) output_message(SMsg_GoldNotEnough, 0, true); @@ -1002,7 +1003,7 @@ static TbResult magic_use_power_armageddon(PowerKind power_kind, PlayerNumber pl * Starts and stops the use of Must obey. * What differs this power from others is that it is a toggle - pressing once * starts the power, and second press disables it. - * The spell is paid for somewhere else - it takes money every few turns when active. + * The power is paid for somewhere else - it takes money every few turns when active. * @param plyr_idx * @param mod_flags * @return @@ -1011,7 +1012,7 @@ static TbResult magic_use_power_obey(PowerKind power_kind, PlayerNumber plyr_idx { struct Dungeon *dungeon; dungeon = get_players_num_dungeon(plyr_idx); - // Toggle the spell + // Toggle the power if (dungeon->must_obey_turn != 0) { dungeon->must_obey_turn = 0; } else { @@ -1072,7 +1073,7 @@ static TbResult magic_use_power_hold_audience(PowerKind power_kind, PlayerNumber } if ((mod_flags & PwMod_CastForFree) == 0) { - // If we can't afford the spell, fail + // If we can't afford the power, fail if (!pay_for_spell(plyr_idx, PwrK_HOLDAUDNC, 0)) { return Lb_FAIL; } @@ -1135,11 +1136,11 @@ static TbResult magic_use_power_hand(PowerKind power_kind, PlayerNumber plyr_idx static TbResult magic_use_power_destroy_walls(PowerKind power_kind, PlayerNumber plyr_idx, struct Thing *thing, MapSubtlCoord stl_x, MapSubtlCoord stl_y, KeepPwrLevel power_level, unsigned long mod_flags) { - // If we can't afford the spell, fail + // If we can't afford the power, fail SYNCDBG(16,"Starting"); if ((mod_flags & PwMod_CastForFree) == 0) { - // If we can't afford the spell, fail + // If we can't afford the power, fail if (!pay_for_spell(plyr_idx, power_kind, power_level)) { return Lb_FAIL; } @@ -1214,7 +1215,7 @@ static TbResult magic_use_power_imp(PowerKind power_kind, PlayerNumber plyr_idx, } if ((mod_flags & PwMod_CastForFree) == 0) { - // If we can't afford the spell, fail + // If we can't afford the power, fail if (!pay_for_spell(plyr_idx, power_kind, power_level)) { return Lb_FAIL; } @@ -1261,7 +1262,7 @@ static TbResult magic_use_power_tunneller(PowerKind power_kind, PlayerNumber ply } if ((mod_flags & PwMod_CastForFree) == 0) { - // If we can't afford the spell, fail + // If we can't afford the power, fail if (!pay_for_spell(plyr_idx, power_kind, power_level)) { return Lb_FAIL; } @@ -1296,7 +1297,7 @@ static TbResult magic_use_power_apply_spell(PowerKind power_kind, PlayerNumber p { struct PowerConfigStats *powerst = get_power_model_stats(power_kind); struct SpellConfig *spconf = get_spell_config(powerst->spell_idx); - // If this spell is already casted at that creature, do nothing. + // If this power is already casted at that creature, do nothing. if (creature_under_spell_effect(thing, spconf->spell_flags)) { return Lb_OK; @@ -1309,13 +1310,13 @@ static TbResult magic_use_power_apply_spell(PowerKind power_kind, PlayerNumber p } if ((mod_flags & PwMod_CastForFree) == 0) { - // If we can't afford the spell, fail. + // If we can't afford the power, fail. if (!pay_for_spell(plyr_idx, power_kind, power_level)) { return Lb_FAIL; } } - // Check if the creature kind isn't affected by that spell. + // Check if the creature kind isn't affected by that power. if (creature_is_immune_to_spell_effect(thing, spconf->spell_flags)) { // Refusal sound. @@ -1362,12 +1363,12 @@ static TbResult magic_use_power_lightning(PowerKind power_kind, PlayerNumber ply pos.x.val = subtile_coord_center(stl_x); pos.y.val = subtile_coord_center(stl_y); pos.z.val = get_floor_height_at(&pos); - // make sure the spell level is correct + // make sure the power level is correct if (power_level >= MAGIC_OVERCHARGE_LEVELS) power_level = MAGIC_OVERCHARGE_LEVELS-1; if ((mod_flags & PwMod_CastForFree) == 0) { - // If we can't afford the spell, fail + // If we can't afford the power, fail if (!pay_for_spell(plyr_idx, power_kind, power_level)) { return Lb_FAIL; } @@ -1455,7 +1456,7 @@ static TbResult magic_use_power_sight(PowerKind power_kind, PlayerNumber plyr_id } if ((mod_flags & PwMod_CastForFree) == 0) { - // If we can't afford the spell, fail + // If we can't afford the power, fail if (!pay_for_spell(plyr_idx, PwrK_SIGHT, power_level)) { if (is_my_player_number(plyr_idx)) output_message(SMsg_GoldNotEnough, 0, true); @@ -1523,7 +1524,7 @@ static TbResult magic_use_power_cave_in(PowerKind power_kind, PlayerNumber plyr_ { if ((mod_flags & PwMod_CastForFree) == 0) { - // If we can't afford the spell, fail + // If we can't afford the power, fail if (!pay_for_spell(plyr_idx, power_kind, power_level)) { return Lb_FAIL; } @@ -1545,9 +1546,9 @@ static TbResult magic_use_power_cave_in(PowerKind power_kind, PlayerNumber plyr_ } /** - * Changes creature state and marks it as being affected by CTA spell. + * Changes creature state and marks it as being affected by CTA power. * - * @param cta_pos Position where the CTA spell is casted. + * @param cta_pos Position where the CTA power is casted. * @param creatng The target creature thing. * @return */ @@ -1932,7 +1933,7 @@ TbResult magic_use_available_power_on_thing(PlayerNumber plyr_idx, PowerKind pwk { TbResult ret; if (!is_power_available(plyr_idx, pwkind)) { - // It shouldn't be possible to select unavailable spell + // It shouldn't be possible to select unavailable power WARNLOG("Player %d tried to cast %s which is unavailable",(int)plyr_idx,power_code_name(pwkind)); ret = Lb_FAIL; } @@ -2026,7 +2027,7 @@ TbResult magic_use_power_on_thing(PlayerNumber plyr_idx, PowerKind pwkind, * @param power_level Power overcharge level. * @param stl_x The target subtile, X coord. * @param stl_y The target subtile, Y coord. - * @param allow_flags Additional castability flags, to loosen constaints in the spell config. + * @param allow_flags Additional castability flags, to loosen constaints in the power config. * @return */ TbResult magic_use_available_power_on_subtile(PlayerNumber plyr_idx, PowerKind pwkind, @@ -2035,7 +2036,7 @@ TbResult magic_use_available_power_on_subtile(PlayerNumber plyr_idx, PowerKind p TbResult ret; ret = Lb_OK; if (!is_power_available(plyr_idx, pwkind)) { - // It shouldn't be possible to select unavailable spell + // It shouldn't be possible to select unavailable power WARNLOG("Player %d tried to cast %s which is unavailable",(int)plyr_idx,power_code_name(pwkind)); ret = Lb_FAIL; } @@ -2098,8 +2099,8 @@ TbResult magic_use_available_power_on_level(PlayerNumber plyr_idx, PowerKind spl KeepPwrLevel power_level, unsigned long mod_flags) { if (!is_power_available(plyr_idx, spl_idx)) { - // It shouldn't be possible to select unavailable spell - WARNLOG("Player %d tried to cast unavailable spell %d",(int)plyr_idx,(int)spl_idx); + // It shouldn't be possible to select unavailable power + WARNLOG("Player %d tried to cast unavailable power %d",(int)plyr_idx,(int)spl_idx); return Lb_FAIL; } return magic_use_power_on_level(plyr_idx, spl_idx, power_level, mod_flags); @@ -2127,9 +2128,9 @@ void directly_cast_spell_on_thing(PlayerNumber plyr_idx, PowerKind pwkind, Thing * @param thing The creature to target. * @param pwkind The ID of the Keeper Power. * @param power_level The overcharge level of the keeperpower. Is ignored when not applicable. - * @param caster The player number of the player who is made to cast the spell. - * @param is_free If gold is used when casting the spell. It will fail to cast if it is not free and money is not available. - * @return TbResult whether the spell was successfully cast + * @param caster The player number of the player who is made to cast the power. + * @param is_free If gold is used when casting the power. It will fail to cast if it is not free and money is not available. + * @return TbResult whether the power was successfully cast */ TbResult script_use_power_on_creature(struct Thing* thing, short pwkind, KeepPwrLevel power_level, PlayerNumber caster, TbBool is_free) { @@ -2195,6 +2196,86 @@ TbBool update_power_overcharge(struct PlayerInfo *player, int pwkind) } return (i < POWER_MAX_LEVEL); } + +/** + * Casts power at a location set by subtiles. + * @param plyr_idx caster player. + * @param stl_x subtile's x position. + * @param stl_y subtile's y position + * @param fml_bytes encoded bytes: f=cast for free flag,m=power kind,l=power level. + * @return TbResult whether the power was successfully cast + */ +TbResult script_use_power_at_pos(PlayerNumber plyr_idx, MapSubtlCoord stl_x, MapSubtlCoord stl_y, long fml_bytes) +{ + char is_free = (fml_bytes >> 16) != 0; + PowerKind powerKind = (fml_bytes >> 8) & 255; + KeepPwrLevel power_level = fml_bytes & 255; + + unsigned long allow_flags = PwCast_AllGround | PwCast_Unrevealed; + unsigned long mod_flags = 0; + if (is_free) + set_flag(mod_flags,PwMod_CastForFree); + + return magic_use_power_on_subtile(plyr_idx, powerKind, power_level, stl_x, stl_y, allow_flags, mod_flags); +} + +/** + * Casts power at a location set by action point/hero gate. + * @param plyr_idx caster player. + * @param target action point/hero gate. + * @param fml_bytes encoded bytes: f=cast for free flag,m=power kind,l=power level. + * @return TbResult whether the power was successfully cast + */ +TbResult script_use_power_at_location(PlayerNumber plyr_idx, TbMapLocation target, long fml_bytes) +{ + SYNCDBG(0, "Using power at location of type %lu", target); + long x = 0; + long y = 0; + find_map_location_coords(target, &x, &y, plyr_idx, __func__); + if ((x == 0) && (y == 0)) + { + WARNLOG("Can't decode location %lu", target); + return Lb_FAIL; + } + return script_use_power_at_pos(plyr_idx, x, y, fml_bytes); +} + +/** + * Casts a power for player. + * @param plyr_idx caster player. + * @param power_kind the power: magic id. + * @param free cast for free flag. + * @return TbResult whether the power was successfully cast + */ +TbResult script_use_power(PlayerNumber plyr_idx, PowerKind power_kind, char free) +{ + return magic_use_power_on_level(plyr_idx, power_kind, 1, free != 0 ? PwMod_CastForFree : 0); // power_level gets ignored anyway -> pass 1 +} + +/** + * Cast a keeper power on a creature which meets given criteria. + * @param plyr_idx The player whose creature will be affected. + * @param crmodel Model of the creature to find. + * @param criteria Criteria, from CreatureSelectCriteria enumeration. + * @param fmcl_bytes encoded bytes: f=cast for free flag,m=power kind,c=caster player index,l=power level. + * @return TbResult whether the power was successfully cast + */ +TbResult script_use_power_on_creature_matching_criterion(PlayerNumber plyr_idx, long crmodel, long criteria, long fmcl_bytes) +{ + struct Thing* thing = script_get_creature_by_criteria(plyr_idx, crmodel, criteria); + if (thing_is_invalid(thing)) { + SYNCDBG(5, "No matching player %d creature of model %d (%s) found to use power on.", (int)plyr_idx, (int)crmodel, creature_code_name(crmodel)); + return Lb_FAIL; + } + + char is_free = (fmcl_bytes >> 24) != 0; + PowerKind pwkind = (fmcl_bytes >> 16) & 255; + PlayerNumber caster = (fmcl_bytes >> 8) & 255; + KeepPwrLevel power_level = fmcl_bytes & 255; + return script_use_power_on_creature(thing, pwkind, power_level, caster, is_free); +} + + /******************************************************************************/ #ifdef __cplusplus } diff --git a/src/magic.h b/src/magic_powers.h similarity index 89% rename from src/magic.h rename to src/magic_powers.h index 21dcc2c5aa..4814a3d3de 100644 --- a/src/magic.h +++ b/src/magic_powers.h @@ -1,14 +1,12 @@ /******************************************************************************/ // Free implementation of Bullfrog's Dungeon Keeper strategy game. /******************************************************************************/ -/** @file magic.h - * Header file for magic.c. +/** @file magic_powers.h + * Header file for magic_powers.c. * @par Purpose: - * magic functions. + * functions related to keeper powers. * @par Comment: * Just a header file - #defines, typedefs, function prototypes etc. - * @author Tomasz Lis - * @date 11 Mar 2010 - 12 May 2010 * @par Copying and copyrights: * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -67,6 +65,11 @@ void process_dungeon_power_magic(void); TbResult magic_use_power_direct(PlayerNumber plyr_idx, PowerKind pwkind, KeepPwrLevel power_level, MapSubtlCoord stl_x, MapSubtlCoord stl_y, struct Thing *thing, unsigned long allow_flags); +TbResult script_use_power_at_pos(PlayerNumber plyr_idx, MapSubtlCoord stl_x, MapSubtlCoord stl_y, long fml_bytes); +TbResult script_use_power_at_location(PlayerNumber plyr_idx, TbMapLocation target, long fml_bytes); +TbResult script_use_power(PlayerNumber plyr_idx, PowerKind power_kind, char free); +TbResult script_use_power_on_creature_matching_criterion(PlayerNumber plyr_idx, long crmodel, long criteria, long fmcl_bytes); + TbResult magic_use_available_power_on_thing(PlayerNumber plyr_idx, PowerKind spl_idx, KeepPwrLevel power_level, MapSubtlCoord stl_x, MapSubtlCoord stl_y, struct Thing *thing, unsigned long mod_flags); TbResult magic_use_available_power_on_subtile(PlayerNumber plyr_idx, PowerKind spl_idx, diff --git a/src/main.cpp b/src/main.cpp index 5d1452f173..f08888f8db 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -104,7 +104,7 @@ #include "creature_states_mood.h" #include "lens_api.h" #include "light_data.h" -#include "magic.h" +#include "magic_powers.h" #include "power_process.h" #include "power_hand.h" #include "game_merge.h" @@ -1915,91 +1915,6 @@ void level_lost_go_first_person(PlayerNumber plyr_idx) SYNCDBG(8,"Finished"); } -// TODO: replace this function by find_location_pos -void find_map_location_coords(TbMapLocation location, long *x, long *y, int plyr_idx, const char *func_name) -{ - struct ActionPoint *apt; - struct Thing *thing; - struct Coord3d pos; - - long pos_x; - long pos_y; - long i; - SYNCDBG(15,"From %s; Location %ld, pos(%ld,%ld)",func_name, location, *x, *y); - pos_y = 0; - pos_x = 0; - i = get_map_location_longval(location); - switch (get_map_location_type(location)) - { - case MLoc_ACTIONPOINT: - // Location stores action point index - apt = action_point_get(i); - if (!action_point_is_invalid(apt)) - { - pos_y = apt->mappos.y.stl.num; - pos_x = apt->mappos.x.stl.num; - } else - WARNMSG("%s: Action Point %ld location not found",func_name,i); - break; - case MLoc_HEROGATE: - thing = find_hero_gate_of_number(i); - if (!thing_is_invalid(thing)) - { - pos_y = thing->mappos.y.stl.num; - pos_x = thing->mappos.x.stl.num; - } else - WARNMSG("%s: Hero Gate %ld location not found",func_name,i); - break; - case MLoc_PLAYERSHEART: - if (i < PLAYERS_COUNT) - { - thing = get_player_soul_container(i); - } else - thing = INVALID_THING; - if (!thing_is_invalid(thing)) - { - pos_y = thing->mappos.y.stl.num; - pos_x = thing->mappos.x.stl.num; - } else - WARNMSG("%s: Dungeon Heart location for player %ld not found",func_name,i); - break; - case MLoc_NONE: - pos_y = *y; - pos_x = *x; - break; - case MLoc_THING: - thing = thing_get(i); - if (!thing_is_invalid(thing)) - { - pos_y = thing->mappos.y.stl.num; - pos_x = thing->mappos.x.stl.num; - } else - WARNMSG("%s: Thing %ld location not found",func_name,i); - break; - case MLoc_METALOCATION: - if (get_coords_at_meta_action(&pos, plyr_idx, i)) - { - pos_x = pos.x.stl.num; - pos_y = pos.y.stl.num; - } - else - WARNMSG("%s: Metalocation not found %ld",func_name,i); - break; - case MLoc_CREATUREKIND: - case MLoc_OBJECTKIND: - case MLoc_ROOMKIND: - case MLoc_PLAYERSDUNGEON: - case MLoc_APPROPRTDUNGEON: - case MLoc_DOORKIND: - case MLoc_TRAPKIND: - default: - WARNMSG("%s: Unsupported location, %lu.",func_name,location); - break; - } - *y = pos_y; - *x = pos_x; -} - void set_general_information(long msg_id, TbMapLocation target, long x, long y) { struct PlayerInfo *player; diff --git a/src/map_locations.c b/src/map_locations.c index 4fb07425a1..7bdbc40b60 100644 --- a/src/map_locations.c +++ b/src/map_locations.c @@ -30,7 +30,6 @@ extern "C" { #endif /******************************************************************************/ - const struct NamedCommand head_for_desc[] = { {"ACTION_POINT", MLoc_ACTIONPOINT}, {"DUNGEON", MLoc_PLAYERSDUNGEON}, @@ -39,6 +38,11 @@ const struct NamedCommand head_for_desc[] = { {NULL, 0}, }; +TbMapLocation get_coord_encoded_location(MapSubtlCoord stl_x,MapSubtlCoord stl_y) +{ + return ((stl_x & 0x0FFF) << 20) + ((stl_y & 0x0FFF) << 8) + MLoc_COORDS; +} + TbBool get_coords_at_location(struct Coord3d *pos, TbMapLocation location, TbBool random_factor) { @@ -57,6 +61,12 @@ TbBool get_coords_at_location(struct Coord3d *pos, TbMapLocation location, TbBoo case MLoc_METALOCATION: return get_coords_at_meta_action(pos, 0, i); + + case MLoc_COORDS: + pos->x.val = subtile_coord_center(location >> 20); + pos->y.val = subtile_coord_center(((location >> 8) & 0xFFF)); + pos->z.val = get_floor_height_at(pos); + return true; case MLoc_CREATUREKIND: case MLoc_OBJECTKIND: @@ -328,6 +338,11 @@ void find_location_pos(long location, PlayerNumber plyr_idx, struct Coord3d *pos if (!get_coords_at_meta_action(pos, plyr_idx, i)) WARNMSG("%s: Metalocation not found %lu",func_name,i); break; + case MLoc_COORDS: + pos->x.val = subtile_coord_center(location >> 20); + pos->y.val = subtile_coord_center((location >> 8) & 0xFFF); + pos->z.val = 0; + break; case MLoc_CREATUREKIND: case MLoc_OBJECTKIND: case MLoc_ROOMKIND: @@ -628,6 +643,91 @@ TbBool get_map_heading_id_f(const char *headname, long target, TbMapLocation *lo return false; } +// TODO: replace this function by find_location_pos +void find_map_location_coords(TbMapLocation location, long *x, long *y, int plyr_idx, const char *func_name) +{ + struct ActionPoint *apt; + struct Thing *thing; + struct Coord3d pos; + + long pos_x; + long pos_y; + long i; + SYNCDBG(15,"From %s; Location %ld, pos(%ld,%ld)",func_name, location, *x, *y); + pos_y = 0; + pos_x = 0; + i = get_map_location_longval(location); + switch (get_map_location_type(location)) + { + case MLoc_ACTIONPOINT: + // Location stores action point index + apt = action_point_get(i); + if (!action_point_is_invalid(apt)) + { + pos_y = apt->mappos.y.stl.num; + pos_x = apt->mappos.x.stl.num; + } else + WARNMSG("%s: Action Point %ld location not found",func_name,i); + break; + case MLoc_HEROGATE: + thing = find_hero_gate_of_number(i); + if (!thing_is_invalid(thing)) + { + pos_y = thing->mappos.y.stl.num; + pos_x = thing->mappos.x.stl.num; + } else + WARNMSG("%s: Hero Gate %ld location not found",func_name,i); + break; + case MLoc_PLAYERSHEART: + if (i < PLAYERS_COUNT) + { + thing = get_player_soul_container(i); + } else + thing = INVALID_THING; + if (!thing_is_invalid(thing)) + { + pos_y = thing->mappos.y.stl.num; + pos_x = thing->mappos.x.stl.num; + } else + WARNMSG("%s: Dungeon Heart location for player %ld not found",func_name,i); + break; + case MLoc_NONE: + pos_y = *y; + pos_x = *x; + break; + case MLoc_THING: + thing = thing_get(i); + if (!thing_is_invalid(thing)) + { + pos_y = thing->mappos.y.stl.num; + pos_x = thing->mappos.x.stl.num; + } else + WARNMSG("%s: Thing %ld location not found",func_name,i); + break; + case MLoc_METALOCATION: + if (get_coords_at_meta_action(&pos, plyr_idx, i)) + { + pos_x = pos.x.stl.num; + pos_y = pos.y.stl.num; + } + else + WARNMSG("%s: Metalocation not found %ld",func_name,i); + break; + case MLoc_CREATUREKIND: + case MLoc_OBJECTKIND: + case MLoc_ROOMKIND: + case MLoc_PLAYERSDUNGEON: + case MLoc_APPROPRTDUNGEON: + case MLoc_DOORKIND: + case MLoc_TRAPKIND: + default: + WARNMSG("%s: Unsupported location, %lu.",func_name,location); + break; + } + *y = pos_y; + *x = pos_x; +} + /******************************************************************************/ #ifdef __cplusplus diff --git a/src/map_locations.h b/src/map_locations.h index 9974878306..5277a0a8aa 100644 --- a/src/map_locations.h +++ b/src/map_locations.h @@ -21,6 +21,7 @@ #include "globals.h" #include "bflib_basics.h" +#include "config.h" #ifdef __cplusplus @@ -28,9 +29,6 @@ extern "C" { #endif /******************************************************************************/ - -typedef unsigned long TbMapLocation; - enum MapLocationTypes { MLoc_NONE = 0, MLoc_ACTIONPOINT, @@ -45,6 +43,7 @@ enum MapLocationTypes { MLoc_DOORKIND, MLoc_TRAPKIND, MLoc_METALOCATION, // 12 // Triggered box, Combat, Last entered creature etc + MLoc_COORDS, // 13 // contains stl coords encoded in the number actual location will be center of said subtile }; enum MetaLocation { @@ -55,6 +54,8 @@ enum MetaLocation { MML_LAST_TRAP_EVENT, }; +extern const struct NamedCommand head_for_desc[]; + /******************************************************************************/ unsigned short get_map_location_type(TbMapLocation location); unsigned long get_map_location_longval(TbMapLocation location); @@ -68,6 +69,10 @@ TbBool get_coords_at_action_point(struct Coord3d *pos, long apt_idx, unsigned ch TbBool get_coords_at_hero_door(struct Coord3d *pos, long gate_num, unsigned char random_factor); TbBool get_coords_at_dungeon_heart(struct Coord3d *pos, PlayerNumber plyr_idx); +TbMapLocation get_coord_encoded_location(MapSubtlCoord stl_x,MapSubtlCoord stl_y); + +void find_map_location_coords(TbMapLocation location, long *x, long *y, int plyr_idx, const char *func_name); + void find_location_pos(long location, PlayerNumber plyr_idx, struct Coord3d *pos, const char *func_name); #define get_map_location_id(locname, location) get_map_location_id_f(locname, location, __func__, text_line_number) diff --git a/src/packets.c b/src/packets.c index 307c8c0847..33469090e2 100644 --- a/src/packets.c +++ b/src/packets.c @@ -72,7 +72,7 @@ #include "room_data.h" #include "thing_stats.h" #include "thing_traps.h" -#include "magic.h" +#include "magic_powers.h" #include "map_blocks.h" #include "map_utils.h" #include "light_data.h" diff --git a/src/packets_cheats.c b/src/packets_cheats.c index 0c05312b34..b6e7d9f12a 100644 --- a/src/packets_cheats.c +++ b/src/packets_cheats.c @@ -33,7 +33,7 @@ #include "config_effects.h" #include "map_utils.h" #include "map_blocks.h" -#include "magic.h" +#include "magic_powers.h" #include "keeperfx.hpp" #include "gui_frontmenu.h" #include "frontend.h" diff --git a/src/packets_input.c b/src/packets_input.c index d7fe88ffbc..0d807116b4 100644 --- a/src/packets_input.c +++ b/src/packets_input.c @@ -32,7 +32,7 @@ #include "power_hand.h" #include "frontend.h" #include "config_players.h" -#include "magic.h" +#include "magic_powers.h" #include "player_utils.h" #include "thing_physics.h" #include "thing_navigate.h" diff --git a/src/player_compchecks.c b/src/player_compchecks.c index 25eb3e19f8..69d958fe31 100644 --- a/src/player_compchecks.c +++ b/src/player_compchecks.c @@ -34,7 +34,7 @@ #include "creature_states.h" #include "creature_states_mood.h" #include "spdigger_stack.h" -#include "magic.h" +#include "magic_powers.h" #include "map_blocks.h" #include "map_utils.h" #include "dungeon_data.h" diff --git a/src/player_compevents.c b/src/player_compevents.c index 4ea2517309..02bd7e43cc 100644 --- a/src/player_compevents.c +++ b/src/player_compevents.c @@ -27,7 +27,7 @@ #include "bflib_math.h" #include "config.h" -#include "magic.h" +#include "magic_powers.h" #include "player_instances.h" #include "config_terrain.h" #include "creature_instances.h" diff --git a/src/player_comptask.c b/src/player_comptask.c index 0f403facdf..38afbc1785 100644 --- a/src/player_comptask.c +++ b/src/player_comptask.c @@ -39,7 +39,7 @@ #include "creature_states_lair.h" #include "creature_states_combt.h" #include "creature_states_mood.h" -#include "magic.h" +#include "magic_powers.h" #include "thing_traps.h" #include "thing_physics.h" #include "thing_effects.h" @@ -3928,4 +3928,48 @@ long process_tasks(struct Computer2 *comp) } return ndone; } + +/** + * Adds a dig task for the player between 2 map locations. + * @param plyr_idx: The player who does the task. + * @param origin: The start location of the disk task. + * @param destination: The desitination of the disk task. + * @return TbResult whether the spell was successfully cast + */ +TbResult script_computer_dig_to_location(long plyr_idx, TbMapLocation origin, TbMapLocation destination) +{ + struct Computer2* comp = get_computer_player(plyr_idx); + long orig_x, orig_y = 0; + long dest_x, dest_y = 0; + + //dig origin + find_map_location_coords(origin, &orig_x, &orig_y, plyr_idx, __func__); + if ((orig_x == 0) && (orig_y == 0)) + { + WARNLOG("Can't decode origin location %ld", origin); + return Lb_FAIL; + } + struct Coord3d startpos; + startpos.x.val = subtile_coord_center(stl_slab_center_subtile(orig_x)); + startpos.y.val = subtile_coord_center(stl_slab_center_subtile(orig_y)); + startpos.z.val = subtile_coord(1, 0); + + //dig destination + find_map_location_coords(destination, &dest_x, &dest_y, plyr_idx, __func__); + if ((dest_x == 0) && (dest_y == 0)) + { + WARNLOG("Can't decode destination location %ld", destination); + return Lb_FAIL; + } + struct Coord3d endpos; + endpos.x.val = subtile_coord_center(stl_slab_center_subtile(dest_x)); + endpos.y.val = subtile_coord_center(stl_slab_center_subtile(dest_y)); + endpos.z.val = subtile_coord(1, 0); + + if (create_task_dig_to_neutral(comp, startpos, endpos)) + { + return Lb_SUCCESS; + } + return Lb_FAIL; +} /******************************************************************************/ diff --git a/src/player_computer.c b/src/player_computer.c index b5689d7612..27e97098b8 100644 --- a/src/player_computer.c +++ b/src/player_computer.c @@ -36,7 +36,7 @@ #include "creature_states.h" #include "ariadne_wallhug.h" #include "spdigger_stack.h" -#include "magic.h" +#include "magic_powers.h" #include "map_utils.h" #include "thing_traps.h" #include "thing_navigate.h" diff --git a/src/player_computer.h b/src/player_computer.h index 4270d5fb50..8359642121 100644 --- a/src/player_computer.h +++ b/src/player_computer.h @@ -620,6 +620,7 @@ TbBool create_task_dig_to_gold(struct Computer2 *comp, const struct Coord3d star TbBool create_task_dig_to_entrance(struct Computer2 *comp, const struct Coord3d startpos, const struct Coord3d endpos, long parent_cproc_idx, long entroom_idx); TbBool create_task_magic_speed_up(struct Computer2 *comp, const struct Thing *creatng, KeepPwrLevel power_level); TbBool create_task_attack_magic(struct Computer2 *comp, const struct Thing *creatng, PowerKind pwkind, int repeat_num, KeepPwrLevel power_level, int gaction); +TbResult script_computer_dig_to_location(long plyr_idx, TbMapLocation origin, TbMapLocation destination); TbBool computer_able_to_use_power(struct Computer2 *comp, PowerKind pwkind, KeepPwrLevel power_level, long amount); long computer_get_room_role_total_capacity(struct Computer2 *comp, RoomRole rrole); diff --git a/src/player_computer_data.cpp b/src/player_computer_data.cpp index 5111f5b349..194f9eab0b 100644 --- a/src/player_computer_data.cpp +++ b/src/player_computer_data.cpp @@ -35,7 +35,7 @@ #include "creature_states.h" #include "ariadne_wallhug.h" #include "spdigger_stack.h" -#include "magic.h" +#include "magic_powers.h" #include "thing_traps.h" #include "thing_navigate.h" #include "player_complookup.h" diff --git a/src/player_instances.c b/src/player_instances.c index 09a4965d4b..eb39414f7b 100644 --- a/src/player_instances.c +++ b/src/player_instances.c @@ -45,7 +45,7 @@ #include "player_utils.h" #include "config_players.h" #include "room_workshop.h" -#include "magic.h" +#include "magic_powers.h" #include "gui_frontmenu.h" #include "gui_soundmsgs.h" #include "engine_arrays.h" diff --git a/src/player_utils.c b/src/player_utils.c index b7f64cc115..97547d695f 100644 --- a/src/player_utils.c +++ b/src/player_utils.c @@ -48,7 +48,7 @@ #include "game_saves.h" #include "game_legacy.h" #include "frontend.h" -#include "magic.h" +#include "magic_powers.h" #include "engine_redraw.h" #include "frontmenu_ingame_tabs.h" #include "frontmenu_ingame_map.h" diff --git a/src/power_hand.c b/src/power_hand.c index 4d6c81bba5..fe0359ac33 100644 --- a/src/power_hand.c +++ b/src/power_hand.c @@ -26,7 +26,7 @@ #include "bflib_vidraw.h" #include "bflib_sound.h" #include "custom_sprites.h" -#include "magic.h" +#include "magic_powers.h" #include "power_specials.h" #include "power_process.h" #include "player_data.h" diff --git a/src/power_specials.c b/src/power_specials.c index 8edddcce1e..cc16f0bb3c 100644 --- a/src/power_specials.c +++ b/src/power_specials.c @@ -60,6 +60,52 @@ long resurrect_creature_scroll_offset; unsigned short dungeon_special_selected; /******************************************************************************/ +/** + * Increases creatures' levels for player. + * @param plyr_idx target player + * @param count how many times should the level be increased + */ +void script_use_special_increase_level(PlayerNumber plyr_idx, int count) +{ + increase_level(get_player(plyr_idx), count); +} + +/** + * Multiplies every creature for player. + * @param plyr_idx target player + */ +void script_use_special_multiply_creatures(PlayerNumber plyr_idx) +{ + multiply_creatures(get_player(plyr_idx)); +} + +/** + * Fortifies player's dungeon. + * @param plyr_idx target player + */ +void script_make_safe(PlayerNumber plyr_idx) +{ + make_safe(get_player(plyr_idx)); +} + +/** + * Fortifies player's dungeon. + * @param plyr_idx target player + */ +void script_make_unsafe(PlayerNumber plyr_idx) +{ + make_unsafe(plyr_idx); +} + +/** + * Enables bonus level for current player. + */ +TbBool script_locate_hidden_world() +{ + return activate_bonus_level(get_player(my_player_number)); +} + + /** * Makes a bonus level for current SP level visible on the land map screen. */ diff --git a/src/power_specials.h b/src/power_specials.h index 4ccb643372..b97e0d71f4 100644 --- a/src/power_specials.h +++ b/src/power_specials.h @@ -69,6 +69,12 @@ void start_resurrect_creature(struct PlayerInfo *player, struct Thing *thing); void start_transfer_creature(struct PlayerInfo *player, struct Thing *thing); long create_transferred_creatures_on_level(void); +void script_use_special_increase_level(PlayerNumber plyr_idx, int count); +void script_use_special_multiply_creatures(PlayerNumber plyr_idx); +void script_make_safe(PlayerNumber plyr_idx); +void script_make_unsafe(PlayerNumber plyr_idx); +TbBool script_locate_hidden_world(); + /******************************************************************************/ #ifdef __cplusplus } diff --git a/src/room_data.c b/src/room_data.c index 979068899c..5c1ab8ca64 100644 --- a/src/room_data.c +++ b/src/room_data.c @@ -48,7 +48,7 @@ #include "creature_states.h" #include "gui_topmsg.h" #include "gui_soundmsgs.h" -#include "magic.h" +#include "magic_powers.h" #include "room_util.h" #include "game_legacy.h" #include "frontmenu_ingame_map.h" diff --git a/src/room_library.c b/src/room_library.c index c1e04e346a..56354c252c 100644 --- a/src/room_library.c +++ b/src/room_library.c @@ -33,7 +33,7 @@ #include "config_terrain.h" #include "creature_states.h" #include "creature_states_rsrch.h" -#include "magic.h" +#include "magic_powers.h" #include "gui_soundmsgs.h" #include "game_legacy.h" #include "post_inc.h" diff --git a/src/thing_creature.c b/src/thing_creature.c index 49fa02f1e2..bfebda3f3a 100644 --- a/src/thing_creature.c +++ b/src/thing_creature.c @@ -67,7 +67,7 @@ #include "kjm_input.h" #include "lens_api.h" #include "light_data.h" -#include "magic.h" +#include "magic_powers.h" #include "map_blocks.h" #include "map_utils.h" #include "player_instances.h" @@ -6694,7 +6694,6 @@ void illuminate_creature(struct Thing *creatng) struct Thing *script_create_creature_at_location(PlayerNumber plyr_idx, ThingModel crmodel, TbMapLocation location, char spawn_type) { - long i = get_map_location_longval(location); struct Coord3d pos; if (!creature_count_below_map_limit(0)) @@ -6703,15 +6702,16 @@ struct Thing *script_create_creature_at_location(PlayerNumber plyr_idx, ThingMod return INVALID_THING; } - switch (get_map_location_type(location)) + if (!get_coords_at_location(&pos, location,false)) { - case MLoc_ACTIONPOINT: - if (!get_coords_at_action_point(&pos, i, 1)) - { - return INVALID_THING; - } - if (spawn_type == SpwnT_Default) + return INVALID_THING; + } + + if (spawn_type == SpwnT_Default) + { + switch (get_map_location_type(location)) { + case MLoc_ACTIONPOINT: if (player_is_roaming(plyr_idx)) { spawn_type = SpwnT_Fall; @@ -6720,41 +6720,11 @@ struct Thing *script_create_creature_at_location(PlayerNumber plyr_idx, ThingMod { spawn_type = SpwnT_None; } - } - break; - case MLoc_HEROGATE: - if (!get_coords_at_hero_door(&pos, i, 1)) - { - return INVALID_THING; - } - if (spawn_type == SpwnT_Default) - { + break; + case MLoc_HEROGATE: spawn_type = SpwnT_Jump; + break; } - break; - case MLoc_PLAYERSHEART: - if (!get_coords_at_dungeon_heart(&pos, i)) - { - return INVALID_THING; - } - break; - case MLoc_METALOCATION: - if (!get_coords_at_meta_action(&pos, plyr_idx, i)) - { - return INVALID_THING; - } - break; - case MLoc_CREATUREKIND: - case MLoc_OBJECTKIND: - case MLoc_ROOMKIND: - case MLoc_THING: - case MLoc_PLAYERSDUNGEON: - case MLoc_APPROPRTDUNGEON: - case MLoc_DOORKIND: - case MLoc_TRAPKIND: - case MLoc_NONE: - default: - return INVALID_THING; } struct Thing* thing = create_thing_at_position_then_move_to_valid_and_add_light(&pos, TCls_Creature, crmodel, plyr_idx); @@ -7455,6 +7425,86 @@ PlayerNumber get_appropriate_player_for_creature(struct Thing *creatng) return creatng->owner; } +static int filter_criteria_type(long desc_type) +{ + return desc_type & 0x0F; +} + +static long filter_criteria_loc(long desc_type) +{ + return desc_type >> 4; +} + +struct Thing* script_get_creature_by_criteria(PlayerNumber plyr_idx, ThingModel crmodel, long criteria) +{ + switch (filter_criteria_type(criteria)) + { + case CSelCrit_Any: + return get_random_players_creature_of_model(plyr_idx, crmodel); + case CSelCrit_MostExperienced: + return find_players_highest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Any, plyr_idx, 0); + case CSelCrit_MostExpWandering: + return find_players_highest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Wandering, plyr_idx, 0); + case CSelCrit_MostExpWorking: + return find_players_highest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Working, plyr_idx, 0); + case CSelCrit_MostExpFighting: + return find_players_highest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Fighting, plyr_idx, 0); + case CSelCrit_LeastExperienced: + return find_players_lowest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Any, plyr_idx, 0); + case CSelCrit_LeastExpWandering: + return find_players_lowest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Wandering, plyr_idx, 0); + case CSelCrit_LeastExpWorking: + return find_players_lowest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Working, plyr_idx, 0); + case CSelCrit_LeastExpFighting: + return find_players_lowest_level_creature_of_breed_and_gui_job(crmodel, CrGUIJob_Fighting, plyr_idx, 0); + case CSelCrit_NearOwnHeart: + { + const struct Coord3d* pos = dungeon_get_essential_pos(plyr_idx); + return get_creature_near_and_owned_by(pos->x.val, pos->y.val, plyr_idx, crmodel); + } + case CSelCrit_NearEnemyHeart: + //return get_creature_in_range_around_any_of_enemy_heart(plyr_idx, crmodel, 11); + case CSelCrit_OnEnemyGround: + return get_random_players_creature_of_model_on_territory(plyr_idx, crmodel, 0); + case CSelCrit_OnFriendlyGround: + return get_random_players_creature_of_model_on_territory(plyr_idx, crmodel, 1); + case CSelCrit_OnNeutralGround: + return get_random_players_creature_of_model_on_territory(plyr_idx, crmodel, 2); + case CSelCrit_NearAP: + { + int loc = filter_criteria_loc(criteria); + struct ActionPoint* apt = action_point_get(loc); + if (!action_point_exists(apt)) + { + WARNLOG("Action point is invalid:%d", apt->num); + return INVALID_THING; + } + if (apt->range == 0) + { + WARNLOG("Action point with zero range:%d", apt->num); + return INVALID_THING; + } + // Action point range should be inside spiral in subtiles + int dist = 2 * coord_subtile(apt->range + COORD_PER_STL - 1) + 1; + dist = dist * dist; + + Thing_Maximizer_Filter filter = near_map_block_creature_filter_diagonal_random; + struct CompoundTngFilterParam param; + param.model_id = crmodel; + param.plyr_idx = (unsigned char)plyr_idx; + param.num1 = apt->mappos.x.val; + param.num2 = apt->mappos.y.val; + param.num3 = apt->range; + return get_thing_spiral_near_map_block_with_filter(apt->mappos.x.val, apt->mappos.y.val, + dist, + filter, ¶m); + } + default: + ERRORLOG("Invalid level up criteria %d", (int)criteria); + return INVALID_THING; + } +} + void query_creature(struct PlayerInfo *player, ThingIndex index, TbBool reset, TbBool zoom) { if (is_my_player(player)) @@ -7682,6 +7732,51 @@ TbBool grow_up_creature(struct Thing *thing, ThingModel grow_up_model, CrtrExpLe return true; } +/** + * Cast a spell on a creature which meets given criteria. + * @param plyr_idx The player whose creature will be affected. + * @param crmodel Model of the creature to find. + * @param criteria Criteria, from CreatureSelectCriteria enumeration. + * @param fmcl_bytes encoded bytes: f=cast for free flag,m=spell kind,c=caster player index,l=spell level. + * @return TbResult whether the spell was successfully cast + */ +TbResult script_use_spell_on_creature(PlayerNumber plyr_idx, ThingModel crmodel, long criteria, long fmcl_bytes) +{ + struct Thing *thing = script_get_creature_by_criteria(plyr_idx, crmodel, criteria); + if (thing_is_invalid(thing)) + { + SYNCDBG(5, "No matching player %d creature of model %d (%s) found to use spell on.", (int)plyr_idx, (int)crmodel, creature_code_name(crmodel)); + return Lb_FAIL; + } + SpellKind spkind = (fmcl_bytes >> 8) & 255; + struct SpellConfig *spconf = get_spell_config(spkind); + if (!creature_is_immune_to_spell_effect(thing, spconf->spell_flags)) + { // Immunity is handled in 'apply_spell_effect_to_thing', but this command plays sounds, so check for it. + if (thing_is_picked_up(thing)) + { + SYNCDBG(5, "Found creature to cast the spell on but it is being held."); + return Lb_FAIL; + } + CrtrExpLevel spell_level = fmcl_bytes & 255; + if (spconf->caster_affect_sound) + { + thing_play_sample(thing, spconf->caster_affect_sound + UNSYNC_RANDOM(spconf->caster_sounds_count), NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); + } + apply_spell_effect_to_thing(thing, spkind, spell_level, plyr_idx); + if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) + { + struct CreatureControl *cctrl; + cctrl = creature_control_get_from_thing(thing); + cctrl->disease_caster_plyridx = game.neutral_player_num; // Does not spread. + } + return Lb_SUCCESS; + } + else + { + return Lb_FAIL; + } +} + /******************************************************************************/ #ifdef __cplusplus } diff --git a/src/thing_creature.h b/src/thing_creature.h index 005863b8e4..46bde79b24 100644 --- a/src/thing_creature.h +++ b/src/thing_creature.h @@ -163,6 +163,7 @@ TbBool clear_thing_spell_flags_f(struct Thing *thing, unsigned long spell_flags, void clean_spell_effect_f(struct Thing *thing, unsigned long spell_flags, const char *func_name); #define clean_spell_effect(thing, spell_flags) clean_spell_effect_f(thing, spell_flags, __func__) +TbResult script_use_spell_on_creature(PlayerNumber plyr_idx, ThingModel crmodel, long criteria, long fmcl_bytes); void apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx); void first_apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx); void reapply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, int slot_idx); @@ -238,6 +239,7 @@ struct Thing *script_create_new_creature(PlayerNumber plyr_idx, ThingModel crmod struct Thing *script_create_creature_at_location(PlayerNumber plyr_idx, ThingModel crmodel, TbMapLocation location, char spawn_type); void script_process_new_creatures(PlayerNumber plyr_idx, ThingModel crmodel, TbMapLocation location, long copies_num, long carried_gold, CrtrExpLevel exp_level, char spawn_type); PlayerNumber get_appropriate_player_for_creature(struct Thing *creatng); +struct Thing* script_get_creature_by_criteria(PlayerNumber plyr_idx, ThingModel crmodel, long criteria); /******************************************************************************/ void throw_out_gold(struct Thing* thing, long amount); ThingModel get_random_creature_kind_with_model_flags(unsigned long model_flags); diff --git a/src/thing_list.c b/src/thing_list.c index 88c54f4a5c..335b7482c8 100644 --- a/src/thing_list.c +++ b/src/thing_list.c @@ -37,7 +37,7 @@ #include "creature_senses.h" #include "spdigger_stack.h" #include "power_hand.h" -#include "magic.h" +#include "magic_powers.h" #include "map_utils.h" #include "config_creature.h" #include "config_magic.h" diff --git a/src/thing_objects.c b/src/thing_objects.c index f35fb40bdd..3e690fb551 100644 --- a/src/thing_objects.c +++ b/src/thing_objects.c @@ -40,7 +40,7 @@ #include "map_data.h" #include "map_columns.h" #include "map_utils.h" -#include "magic.h" +#include "magic_powers.h" #include "room_entrance.h" #include "gui_topmsg.h" #include "gui_soundmsgs.h" diff --git a/src/thing_shots.c b/src/thing_shots.c index f33fef90f5..8c87d89bd1 100644 --- a/src/thing_shots.c +++ b/src/thing_shots.c @@ -35,7 +35,7 @@ #include "front_simple.h" #include "thing_stats.h" #include "map_blocks.h" -#include "magic.h" +#include "magic_powers.h" #include "room_garden.h" #include "config_creature.h" #include "config_terrain.h" diff --git a/src/thing_traps.c b/src/thing_traps.c index e77fbf1770..604b2c3673 100644 --- a/src/thing_traps.c +++ b/src/thing_traps.c @@ -32,7 +32,7 @@ #include "thing_effects.h" #include "thing_physics.h" #include "thing_shots.h" -#include "magic.h" +#include "magic_powers.h" #include "map_blocks.h" #include "map_utils.h" #include "room_util.h"