diff options
Diffstat (limited to 'src/lua_bind.c')
-rw-r--r-- | src/lua_bind.c | 691 |
1 files changed, 691 insertions, 0 deletions
diff --git a/src/lua_bind.c b/src/lua_bind.c new file mode 100644 index 00000000..67b75ee6 --- /dev/null +++ b/src/lua_bind.c @@ -0,0 +1,691 @@ +/* File: lua_bind.c */ + +/* Purpose: various lua bindings */ + +/* + * Copyright (c) 2001 DarkGod + * + * This software may be copied and distributed for educational, research, and + * not for profit purposes provided that this copyright and statement are + * included in all such copies. + */ + +#include "angband.h" + +#include "lua.h" +#include "tolua.h" +extern lua_State *L; + +magic_power *grab_magic_power(magic_power *m_ptr, int num) +{ + return (&m_ptr[num]); +} + +bool_ lua_spell_success(magic_power *spell, int stat, char *oups_fct) +{ + int chance; + int minfail = 0; + + /* Spell failure chance */ + chance = spell->fail; + + /* Reduce failure rate by "effective" level adjustment */ + chance -= 3 * (p_ptr->lev - spell->min_lev); + + /* Reduce failure rate by INT/WIS adjustment */ + chance -= 3 * (adj_mag_stat[p_ptr->stat_ind[stat]] - 1); + + /* Not enough mana to cast */ + if (spell->mana_cost > p_ptr->csp) + { + chance += 5 * (spell->mana_cost - p_ptr->csp); + } + + /* Extract the minimum failure rate */ + minfail = adj_mag_fail[p_ptr->stat_ind[stat]]; + + /* Failure rate */ + chance = clamp_failure_chance(chance, minfail); + + /* Failed spell */ + if (rand_int(100) < chance) + { + if (flush_failure) flush(); + msg_format("You failed to concentrate hard enough!"); + sound(SOUND_FAIL); + + if (oups_fct != NULL) + exec_lua(format("%s(%d)", oups_fct, chance)); + return (FALSE); + } + return (TRUE); +} + +/* + * Create objects + */ +object_type *new_object() +{ + object_type *o_ptr; + MAKE(o_ptr, object_type); + return (o_ptr); +} + +void end_object(object_type *o_ptr) +{ + FREE(o_ptr, object_type); +} + +/* + * Powers + */ +s16b add_new_power(cptr name, cptr desc, cptr gain, cptr lose, byte level, byte cost, byte stat, byte diff) +{ + /* Increase the size */ + reinit_powers_type(power_max + 1); + + /* Copy the strings */ + C_MAKE(powers_type[power_max - 1].name, strlen(name) + 1, char); + strcpy(powers_type[power_max - 1].name, name); + C_MAKE(powers_type[power_max - 1].desc_text, strlen(desc) + 1, char); + strcpy(powers_type[power_max - 1].desc_text, desc); + C_MAKE(powers_type[power_max - 1].gain_text, strlen(gain) + 1, char); + strcpy(powers_type[power_max - 1].gain_text, gain); + C_MAKE(powers_type[power_max - 1].lose_text, strlen(lose) + 1, char); + strcpy(powers_type[power_max - 1].lose_text, lose); + + /* Copy the other stuff */ + powers_type[power_max - 1].level = level; + powers_type[power_max - 1].cost = cost; + powers_type[power_max - 1].stat = stat; + powers_type[power_max - 1].diff = diff; + + return (power_max - 1); +} + +static char *lua_item_tester_fct; +static bool_ lua_item_tester(object_type* o_ptr) +{ + int oldtop = lua_gettop(L); + bool_ ret; + + lua_getglobal(L, lua_item_tester_fct); + tolua_pushusertype(L, o_ptr, tolua_tag(L, "object_type")); + lua_call(L, 1, 1); + ret = lua_tonumber(L, -1); + lua_settop(L, oldtop); + return (ret); +} + +void lua_set_item_tester(int tval, char *fct) +{ + if (tval) + { + item_tester_tval = tval; + } + else + { + lua_item_tester_fct = fct; + item_tester_hook = lua_item_tester; + } +} + +char *lua_object_desc(object_type *o_ptr, int pref, int mode) +{ + static char buf[150]; + + object_desc(buf, o_ptr, pref, mode); + return (buf); +} + +/* + * Monsters + */ + +void find_position(int y, int x, int *yy, int *xx) +{ + int attempts = 500; + + do + { + scatter(yy, xx, y, x, 6); + } + while (!(in_bounds(*yy, *xx) && cave_floor_bold(*yy, *xx)) && --attempts); +} + +static char *summon_lua_okay_fct; +bool_ summon_lua_okay(int r_idx) +{ + int oldtop = lua_gettop(L); + bool_ ret; + + lua_getglobal(L, lua_item_tester_fct); + tolua_pushnumber(L, r_idx); + lua_call(L, 1, 1); + ret = lua_tonumber(L, -1); + lua_settop(L, oldtop); + return (ret); +} + +bool_ lua_summon_monster(int y, int x, int lev, bool_ friend_, char *fct) +{ + summon_lua_okay_fct = fct; + + if (!friend_) + return summon_specific(y, x, lev, SUMMON_LUA); + else + return summon_specific_friendly(y, x, lev, SUMMON_LUA, TRUE); +} + +/* + * Quests + */ +s16b add_new_quest(char *name) +{ + int i; + + /* Increase the size */ + reinit_quests(max_q_idx + 1); + quest[max_q_idx - 1].type = HOOK_TYPE_LUA; + strncpy(quest[max_q_idx - 1].name, name, 39); + + for (i = 0; i < 10; i++) + strncpy(quest[max_q_idx - 1].desc[i], "", 39); + + return (max_q_idx - 1); +} + +void desc_quest(int q_idx, int d, char *desc) +{ + if (d >= 0 && d < 10) + strncpy(quest[q_idx].desc[d], desc, 79); +} + +/* + * Misc + */ +bool_ get_com_lua(cptr prompt, int *com) +{ + char c; + + if (!get_com(prompt, &c)) return (FALSE); + *com = c; + return (TRUE); +} + +/* Spell schools */ +s16b new_school(int i, cptr name, s16b skill) +{ + schools[i].name = string_make(name); + schools[i].skill = skill; + return (i); +} + +s16b new_spell(int i, cptr name) +{ + school_spells[i].name = string_make(name); + school_spells[i].level = 0; + school_spells[i].level = 0; + return (i); +} + +spell_type *grab_spell_type(s16b num) +{ + return (&school_spells[num]); +} + +school_type *grab_school_type(s16b num) +{ + return (&schools[num]); +} + +/* Change this fct if I want to switch to learnable spells */ +s32b lua_get_level(s32b s, s32b lvl, s32b max, s32b min, s32b bonus) +{ + s32b tmp; + + tmp = lvl - ((school_spells[s].skill_level - 1) * (SKILL_STEP / 10)); + + if (tmp >= (SKILL_STEP / 10)) /* We require at least one spell level */ + tmp += bonus; + + tmp = (tmp * (max * (SKILL_STEP / 10)) / (SKILL_MAX / 10)); + + if (tmp < 0) /* Shift all negative values, so they map to appropriate integer */ + tmp -= SKILL_STEP / 10 - 1; + + /* Now, we can safely divide */ + lvl = tmp / (SKILL_STEP / 10); + + if (lvl < min) + lvl = min; + + return lvl; +} + +s32b lua_spell_chance(s32b chance, int level, int skill_level, int mana, int cur_mana, int stat) +{ + int minfail; + /* Reduce failure rate by "effective" level adjustment */ + chance -= 3 * (level - 1); + + /* Reduce failure rate by INT/WIS adjustment */ + chance -= 3 * (adj_mag_stat[p_ptr->stat_ind[stat]] - 1); + + /* Not enough mana to cast */ + if (chance < 0) chance = 0; + if (mana > cur_mana) + { + chance += 15 * (mana - cur_mana); + } + + /* Extract the minimum failure rate */ + minfail = adj_mag_fail[p_ptr->stat_ind[stat]]; + + /* + * Non mage characters never get too good + */ + if (!(has_ability(AB_PERFECT_CASTING))) + { + if (minfail < 5) minfail = 5; + } + + /* Hack -- Priest prayer penalty for "edged" weapons -DGK */ + if ((forbid_non_blessed()) && (p_ptr->icky_wield)) chance += 25; + + /* Return the chance */ + return clamp_failure_chance(chance, minfail); +} + +s32b lua_spell_device_chance(s32b chance, int level, int base_level) +{ + int minfail; + + /* Reduce failure rate by "effective" level adjustment */ + chance -= (level - 1); + + /* Extract the minimum failure rate */ + minfail = 15 - get_skill_scale(SKILL_DEVICE, 25); + + /* Return the chance */ + return clamp_failure_chance(chance, minfail); +} + +/* Cave */ +cave_type *lua_get_cave(int y, int x) +{ + return (&(cave[y][x])); +} + +void set_target(int y, int x) +{ + target_who = -1; + target_col = x; + target_row = y; +} + +void get_target(int dir, int *y, int *x) +{ + int ty, tx; + + /* Use the given direction */ + tx = p_ptr->px + (ddx[dir] * 100); + ty = p_ptr->py + (ddy[dir] * 100); + + /* Hack -- Use an actual "target" */ + if ((dir == 5) && target_okay()) + { + tx = target_col; + ty = target_row; + } + *y = ty; + *x = tx; +} + +/* Level gen */ +void get_map_size(char *name, int *ysize, int *xsize) +{ + *xsize = 0; + *ysize = 0; + init_flags = INIT_GET_SIZE; + process_dungeon_file(name, ysize, xsize, cur_hgt, cur_wid, TRUE, TRUE); +} + +void load_map(char *name, int *y, int *x) +{ + /* Set the correct monster hook */ + set_mon_num_hook(); + + /* Prepare allocation table */ + get_mon_num_prep(); + + init_flags = INIT_CREATE_DUNGEON; + process_dungeon_file(name, y, x, cur_hgt, cur_wid, TRUE, TRUE); +} + +bool_ alloc_room(int by0, int bx0, int ysize, int xsize, int *y1, int *x1, int *y2, int *x2) +{ + int xval, yval, x, y; + + /* Try to allocate space for room. If fails, exit */ + if (!room_alloc(xsize + 2, ysize + 2, FALSE, by0, bx0, &xval, &yval)) return FALSE; + + /* Get corner values */ + *y1 = yval - ysize / 2; + *x1 = xval - xsize / 2; + *y2 = yval + (ysize) / 2; + *x2 = xval + (xsize) / 2; + + /* Place a full floor under the room */ + for (y = *y1 - 1; y <= *y2 + 1; y++) + { + for (x = *x1 - 1; x <= *x2 + 1; x++) + { + cave_type *c_ptr = &cave[y][x]; + cave_set_feat(y, x, floor_type[rand_int(100)]); + c_ptr->info |= (CAVE_ROOM); + c_ptr->info |= (CAVE_GLOW); + } + } + return TRUE; +} + + +/* Files */ +void lua_print_hook(cptr str) +{ + fprintf(hook_file, "%s", str); +} + + +/* + * Finds a good random bounty monster + * Im too lazy to write it in lua since the lua API for monsters is not very well yet + */ + +/* + * Hook for bounty monster selection. + */ +static bool_ lua_mon_hook_bounty(int r_idx) +{ + monster_race* r_ptr = &r_info[r_idx]; + + + /* Reject uniques */ + if (r_ptr->flags1 & RF1_UNIQUE) return (FALSE); + + /* Reject those who cannot leave anything */ + if (!(r_ptr->flags9 & RF9_DROP_CORPSE)) return (FALSE); + + /* Accept only monsters that can be generated */ + if (r_ptr->flags9 & RF9_SPECIAL_GENE) return (FALSE); + if (r_ptr->flags9 & RF9_NEVER_GENE) return (FALSE); + + /* Reject pets */ + if (r_ptr->flags7 & RF7_PET) return (FALSE); + + /* Reject friendly creatures */ + if (r_ptr->flags7 & RF7_FRIENDLY) return (FALSE); + + /* Accept only monsters that are not breeders */ + if (r_ptr->flags4 & RF4_MULTIPLY) return (FALSE); + + /* Forbid joke monsters */ + if (r_ptr->flags8 & RF8_JOKEANGBAND) return (FALSE); + + /* Accept only monsters that are not good */ + if (r_ptr->flags3 & RF3_GOOD) return (FALSE); + + /* The rest are acceptable */ + return (TRUE); +} + +int lua_get_new_bounty_monster(int lev) +{ + int r_idx; + + /* + * Set up the hooks -- no bounties on uniques or monsters + * with no corpses + */ + get_mon_num_hook = lua_mon_hook_bounty; + get_mon_num_prep(); + + /* Set up the quest monster. */ + r_idx = get_mon_num(lev); + + /* Undo the filters */ + get_mon_num_hook = NULL; + get_mon_num_prep(); + + return r_idx; +} + +/* + * Some misc functions + */ +char *lua_input_box(cptr title, int max) +{ + static char buf[80]; + int wid, hgt; + + strcpy(buf, ""); + Term_get_size(&wid, &hgt); + if (!input_box(title, hgt / 2, wid / 2, buf, (max > 79) ? 79 : max)) + return ""; + return buf; +} + +char lua_msg_box(cptr title) +{ + int wid, hgt; + + Term_get_size(&wid, &hgt); + return msg_box(title, hgt / 2, wid / 2); +} + +list_type *lua_create_list(int size) +{ + list_type *l; + cptr *list; + + MAKE(l, list_type); + C_MAKE(list, size, cptr); + l->list = list; + return l; +} + +void lua_delete_list(list_type *l, int size) +{ + int i; + + for (i = 0; i < size; i++) + string_free(l->list[i]); + C_FREE(l->list, size, cptr); + FREE(l, list_type); +} + +void lua_add_to_list(list_type *l, int idx, cptr str) +{ + l->list[idx] = string_make(str); +} + +void lua_display_list(int y, int x, int h, int w, cptr title, list_type* list, int max, int begin, int sel, byte sel_color) +{ + display_list(y, x, h, w, title, list->list, max, begin, sel, sel_color); +} + +/* + * Gods + */ +s16b add_new_gods(char *name) +{ + int i; + + /* Increase the size */ + reinit_gods(max_gods + 1); + deity_info[max_gods - 1].name = string_make(name); + + for (i = 0; i < 10; i++) + strncpy(deity_info[max_gods - 1].desc[i], "", 39); + + return (max_gods - 1); +} + +void desc_god(int g_idx, int d, char *desc) +{ + if (d >= 0 && d < 10) + strncpy(deity_info[g_idx].desc[d], desc, 79); +} + +/* + * Returns the direction of the compass that y2, x2 is from y, x + * the return value will be one of the following: north, south, + * east, west, north-east, south-east, south-west, north-west, + * or "close" if it is within 2 tiles. + */ +cptr compass(int y, int x, int y2, int x2) +{ + static char compass_dir[64]; + + // is it close to the north/south meridian? + int y_diff = y2 - y; + + // determine if y2, x2 is to the north or south of y, x + const char *y_axis; + if ((y_diff > -3) && (y_diff < 3)) + { + y_axis = 0; + } + else if (y2 > y) + { + y_axis = "south"; + } + else + { + y_axis = "north"; + } + + // is it close to the east/west meridian? + int x_diff = x2 - x; + + // determine if y2, x2 is to the east or west of y, x + const char *x_axis; + if ((x_diff > -3) && (x_diff < 3)) + { + x_axis = 0; + } + else if (x2 > x) + { + x_axis = "east"; + } + else + { + x_axis = "west"; + } + + // Maybe it is very close + if ((!x_axis) && (!y_axis)) { strcpy(compass_dir, "close"); } + // Maybe it is (almost) due N/S + else if (!x_axis) { strcpy(compass_dir, y_axis); } + // Maybe it is (almost) due E/W + else if (!y_axis) { strcpy(compass_dir, x_axis); } + // or if it is neither + else { sprintf(compass_dir, "%s-%s", y_axis, x_axis); } + return compass_dir; +} + +/* Returns a relative approximation of the 'distance' of y2, x2 from y, x. */ +cptr approximate_distance(int y, int x, int y2, int x2) +{ + // how far to away to the north/south? + int y_diff = abs(y2 - y); + // how far to away to the east/west? + int x_diff = abs(x2 - x); + // find which one is the larger distance + int most_dist = x_diff; + if (y_diff > most_dist) { + most_dist = y_diff; + } + + // how far away then? + if (most_dist >= 41) { + return "a very long way"; + } else if (most_dist >= 25) { + return "a long way"; + } else if (most_dist >= 8) { + return "quite some way"; + } else { + return "not very far"; + } +} + +bool_ drop_text_left(byte c, cptr str, int y, int o) +{ + int i = strlen(str); + int x = 39 - (strlen(str) / 2) + o; + while (i > 0) + { + int a = 0; + int time = 0; + + if (str[i-1] != ' ') + { + while (a < x + i - 1) + { + Term_putch(a - 1, y, c, 32); + Term_putch(a, y, c, str[i-1]); + time = time + 1; + if (time >= 4) + { + Term_xtra(TERM_XTRA_DELAY, 1); + time = 0; + } + Term_redraw_section(a - 1, y, a, y); + a = a + 1; + + inkey_scan = TRUE; + if (inkey()) { + return TRUE; + } + } + } + + i = i - 1; + } + return FALSE; +} + +bool_ drop_text_right(byte c, cptr str, int y, int o) +{ + int x = 39 - (strlen(str) / 2) + o; + int i = 1; + while (i <= strlen(str)) + { + int a = 79; + int time = 0; + + if (str[i-1] != ' ') { + while (a >= x + i - 1) + { + Term_putch(a + 1, y, c, 32); + Term_putch(a, y, c, str[i-1]); + time = time + 1; + if (time >= 4) { + Term_xtra(TERM_XTRA_DELAY, 1); + time = 0; + } + Term_redraw_section(a, y, a + 1, y); + a = a - 1; + + inkey_scan = TRUE; + if (inkey()) { + return TRUE; + } + } + } + + i = i + 1; + } + return FALSE; +} |