/* $Id$ */
/* 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.
 */

/* added this for consistency in some (unrelated) header-inclusion,
   it IS a server file, isn't it? */
#define SERVER

#include "angband.h"

#if 0
/*
 * Get a new magic type
 */
magic_power *new_magic_power(int num) {
	magic_power *m_ptr;
	C_MAKE(m_ptr, num, magic_power);
	return(m_ptr);
}
magic_power *grab_magic_power(magic_power *m_ptr, int num) {
	return(&m_ptr[num]);
}
static char *magic_power_info_lua_fct;
static void magic_power_info_lua(char *p, int power) {
	int oldtop = lua_gettop(L);

	lua_getglobal(L, magic_power_info_lua_fct);
	tolua_pushnumber(L, power);
	lua_call(L, 1, 1);
	strcpy(p, lua_tostring(L, -1));
	lua_settop(L, oldtop);
}
int get_magic_power_lua(int *sn, magic_power *powers, int max_powers, char *info_fct, int plev, int cast_stat) {
	magic_power_info_lua_fct = info_fct;
	return(get_magic_power(sn, powers, max_powers, magic_power_info_lua, plev, cast_stat));
}

/* unused */
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 -= adj_mag_stat[p_ptr->stat_ind[stat]] - 3;

	/* Not enough mana to cast */
	if (spell->mana_cost > p_ptr->cmp) chance += 5 * (spell->mana_cost - p_ptr->cmp);

	/* Extract the minimum failure rate */
	minfail = adj_mag_fail[p_ptr->stat_ind[stat]];

	/* Minimum failure rate */
	if (chance < minfail) chance = minfail;

	/* Stunning makes spells harder */
	if (p_ptr->stun > 50) chance += 25;
	else if (p_ptr->stun) chance += 15;

	/* Always a 5 percent chance of working */
	if (chance > 95) chance = 95;

	/* Failed spell */
	if (rand_int(100) < chance) {
		if (flush_failure) flush();
		msg_print("You failed to concentrate hard enough!");
#ifdef USE_SOUND_2010
#else
		sound(SOUND_FAIL);
#endif

		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, 0);
	} 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;
	bool ok;

	if (!friend)
		ok = summon_specific(y, x, lev, SUMMON_LUA, 1, 0);
	else
		ok = summon_specific_friendly(y, x, lev, SUMMON_LUA, TRUE);

#ifdef USE_SOUND_2010
//	if (ok) sound_near_site(y, x, wpos, 0, "summon", NULL, SFX_TYPE_MON_SPELL, FALSE);
#endif

	return(ok);
}

/*
 * Quests
 */
s16b add_new_quest(char *name) {
	int i;

	/* Increase the size */
	reinit_quests(max_xo_idx + 1);
	quest[max_xo_idx - 1].type = HOOK_TYPE_LUA;
	strncpy(quest[max_xo_idx - 1].name, name, 39);

	for (i = 0; i < 10; i++)
		strncpy(quest[max_xo_idx - 1].desc[i], "", 39);

	return(max_xo_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);
}
#endif	// 0

/* 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 */
/* NOTE: KEEP CONSISTENT WITH CLIENT-SIDE lua_bind.c:lua_get_level()! */
s32b lua_get_level(int Ind, s32b s, s32b lvl, s32b max, s32b min, s32b bonus) {
	player_type *p_ptr = Players[Ind];
	s32b tmp;

#ifdef FIX_LUA_GET_LEVEL
	/* Improved version with the following changes:
	 * - Fixed spell power calculations so that they have an effect with small values of 'max'.
	 * - Higher resolution for spell-power calculations.
	 * - Fixed LIMIT_SPELLS
	 */
	tmp = lvl - ((school_spells[s].skill_level - 1) * (SKILL_STEP / 10));

	/* Require at least one spell level before applying bonus */
	if (tmp >= (SKILL_STEP / 10)) {
		/* Applying spell power bonus here makes it work for small values of 'max' */
		if (school_spells[s].spell_power) {
			tmp += tmp * get_skill_scale(p_ptr, SKILL_SPELL, 4000) / 10000;
		}

		/* Currently not used... */
		tmp += bonus;
	}

 #ifdef LIMIT_SPELLS
	if (p_ptr->limit_spells > 0) {
		s32b tmp_limit = p_ptr->limit_spells * (SKILL_STEP / 10);
		if (tmp > tmp_limit) tmp = tmp_limit;
	}
 #endif

	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;
#else
	tmp = lvl - ((school_spells[s].skill_level - 1) * (SKILL_STEP / 10));
	lvl = (tmp * (max * (SKILL_STEP / 10)) / (SKILL_MAX / 10)) / (SKILL_STEP / 10);

	//hack to fix rounding-down, for correctly displaying spell levels <= 0:
	if (tmp < 0 && tmp % 100) lvl--;

	if (lvl < min) lvl = min;
	else if (lvl > 0) {
		tmp += bonus;
		lvl = (tmp * (max * (SKILL_STEP / 10)) / (SKILL_MAX / 10)) / (SKILL_STEP / 10);
		if (school_spells[s].spell_power) {
			lvl *= (100 + get_skill_scale(p_ptr, SKILL_SPELL, 40));
			lvl /= 100;
		}
	}

 #ifdef LIMIT_SPELLS
	if (p_ptr->limit_spells > 0 && lvl > p_ptr->limit_spells) lvl = p_ptr->limit_spells;
 #endif
#endif

	return(lvl);
}

/* adj_mag_stat? stat_ind??  pfft */
/* NOTE: KEEP CONSISTENT WITH CLIENT-SIDE lua_bind.c:lua_spell_chance()! */
s32b lua_spell_chance(int i, s32b chance, int level, int skill_level, int mana, int cur_mana, int stat) {
	player_type *p_ptr = Players[i];
	int	     minfail;

//s_printf("i %d - chance %d - level %d - skill_level %d - mana %d - cur_mana %d - stat %d\n", i, chance, level, skill_level, mana, cur_mana, stat);

	/* correct LUA overflow bug ('fail' is type char, ie unsigned byte) */
	if (chance > 100) chance -= 256;

	/* Reduce failure rate by "effective" level adjustment */
	chance -= 3 * (level - skill_level);

	/* Reduce failure rate by INT/WIS adjustment */
	chance -= adj_mag_stat[p_ptr->stat_ind[stat]] - 3;

	 /* Not enough mana to cast */
	if (chance < 0) chance = 0;

#if 0 /* you cannot cast the spell anyway, so this just confuses */
	if (mana > cur_mana) chance += 15 * (mana - cur_mana);
#endif

	/* Extract the minimum failure rate */
	minfail = adj_mag_fail[p_ptr->stat_ind[stat]];

#if 0	/* disabled for the time being */
	/*
	 * Non mage characters never get too good
	 */
	if (!(PRACE_FLAG(PR1_ZERO_FAIL))) {
		if (minfail < 5) minfail = 5;
	}

	/* Hack -- Priest prayer penalty for "edged" weapons  -DGK */
	if ((forbid_non_blessed()) && (p_ptr->icky_wield)) chance += 25;
#endif

	/* Minimum failure rate */
	if (chance < minfail) chance = minfail;

	/* Stunning makes spells harder */
	if (p_ptr->stun > 50) chance += 25;
	else if (p_ptr->stun) chance += 15;

	/* icky_wield increases fail chance */
	if (p_ptr->icky_wield) chance += 15;

	/* Always a 5 percent chance of working */
	if (chance > 95) chance = 95;

	/* Return the chance */
	return(chance);
}

#if 0
/* 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_who = 0 - MAX_PLAYERS - 2; //TARGET_STATIONARY
	target_col = x;
	target_row = y;
}

/* Level gen */
void get_map_size(char *name, int *ysize, int *xsize) {
	*xsize = 0;
	*ysize = 0;
	init_flags = INIT_GET_SIZE;
	process_dungeon_file_full = TRUE;
	process_dungeon_file(name, ysize, xsize, cur_hgt, cur_wid, TRUE);
	process_dungeon_file_full = FALSE;

}

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(0, NULL);

	init_flags = INIT_CREATE_DUNGEON;
	process_dungeon_file_full = TRUE;
	process_dungeon_file(name, y, x, cur_hgt, cur_wid, TRUE);
	process_dungeon_file_full = FALSE;
}

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(1000)]);
			c_ptr->info |= (CAVE_ROOM);
			c_ptr->info |= (CAVE_GLOW);
		}
	}
	return(TRUE);
}


/* Files */
void lua_print_hook(cptr str) {
	fprintf(hook_file, 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 'non-spawning' monsters */
	if (!r_ptr->rarity) return(FALSE);

	/* Reject uniques */
	if ((r_ptr->flags1 & RF1_UNIQUE)) return(FALSE);

	/* Reject quest NPCs */
	//if ((r_ptr->flags1 & RF1_QUESTOR)) 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);

	/* Reject pets */
	if ((r_ptr->flags7 & RF7_PET)) return(FALSE);

	/* Reject friendly creatures */
	if ((r_ptr->flags7 & RF7_FRIENDLY)) return(FALSE);

	/* Reject neutral creatures */
	if ((r_ptr->flags7 & RF7_NEUTRAL)) 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);

	/* Forbid C. Blue's monsters */
	if ((r_ptr->flags8 & RF8_BLUEBAND)) 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(0, NULL);

	/* Set up the quest monster. */
	r_idx = get_mon_num(lev, lev);

	/* Undo the filters */
	get_mon_num_hook = dungeon_aux;

	return(r_idx);
}

#endif

/* To do some connection magik ! */
void remote_update_lua(int Ind, cptr file) {
	player_type *p_ptr = Players[Ind];
	unsigned short chunksize;

	/* Count # of LUA files to check for updates (for 4.4.8.1.0.0 crash bug) */
	p_ptr->warning_lua_count++;

	/* Starting from protocol version 4.6.1.2, the client can receive 1024 bytes in one packet */
	if (is_newer_than(&p_ptr->version, 4, 6, 1, 1, 0, 1)) chunksize = 1024;
	else chunksize = 256;

	remote_update(p_ptr->conn, file, chunksize);
}

/* Write a string to the log file */
void lua_s_print(cptr logstr) {
	s_printf("%s", logstr);
}

/* Write a time-stamped string to an external file. - Added for AI experiments - C. Blue */
void lua_x_print(cptr logstr) {
	x_printf("%s", logstr);
}

void lua_add_anote(char *anote) {
	int i;

	bracer_ff(anote); /* allow colouring */

	for (i = 0; i < MAX_ADMINNOTES; i++)
		if (!strcmp(admin_note[i], "")) break;

	if (i < MAX_ADMINNOTES) {
		strcpy(admin_note[i], anote);
		msg_broadcast_format(0, "\375\377s->MotD: %s", anote);
	} else
		s_printf("lua_add_anote() failed: out of notes.\n");
}
void lua_del_anotes(void) {
	int i;

	for (i = 0; i < MAX_ADMINNOTES; i++)
		if (strcmp(admin_note[i], "")) strcpy(admin_note[i], "");
}
void lua_broadcast_motd(void) {
	int p, i;
	bool first = TRUE;

	for (i = 0; i < MAX_ADMINNOTES; i++) {
		if (!strcmp(admin_note[i], "")) continue;
		if (first) {
			first = FALSE;
			for (p = 1; p <= NumPlayers; p++)
				msg_print(p, "\375\377sMotD:");
		}
		for (p = 1; p <= NumPlayers; p++)
			msg_format(p, "\375\377s %s", admin_note[i]);
	}

	if (server_warning[0])
		for (p = 1; p <= NumPlayers; p++)
			msg_format(p, "\377R*** Note: %s ***", server_warning);
}

void lua_count_houses(int Ind) {
	int i;
	player_type *p_ptr = Players[Ind];

	p_ptr->houses_owned = 0;
	p_ptr->castles_owned = 0;
	for (i = 0; i < num_houses; i++)
		if ((houses[i].dna->owner_type == OT_PLAYER) &&
		    (houses[i].dna->owner == p_ptr->id)) {
			p_ptr->houses_owned++;

			if (cfg.houses_per_player &&
			    p_ptr->houses_owned > (p_ptr->max_plv >= 50 ? 50 : p_ptr->max_plv) / cfg.houses_per_player)
				s_printf("HOUSES_EXCEEDED: %s owns %d houses.\n", p_ptr->name, p_ptr->houses_owned);

			if (houses[i].flags & HF_MOAT) {
				p_ptr->castles_owned++;

				if (cfg.castles_per_player &&
				    p_ptr->castles_owned > cfg.castles_per_player)
					s_printf("HOUSES_EXCEEDED: %s owns %d castles.\n", p_ptr->name, p_ptr->castles_owned);

				if (cfg.castles_for_kings && !p_ptr->once_winner)
					s_printf("HOUSES_EXCEEDED: non-(ex)winner %s owns castle(s).\n", p_ptr->name);
			}
		}
}
int lua_count_houses_id(s32b id) {
	int i, ho = 0, co = 0, lev = lookup_player_maxplv(id);

	for (i = 0; i < num_houses; i++)
		if ((houses[i].dna->owner_type == OT_PLAYER) &&
		    (houses[i].dna->owner == id)) {
			ho++;

			if (cfg.houses_per_player &&
			    ho > (lev >= 50 ? 50 : lev) / cfg.houses_per_player)
				/* only maybe, because lev isnt max_plv! */
				s_printf("HOUSES_EXCEEDED_MAYBE: %s owns %d houses.\n", lookup_player_name(id), ho);

			if (houses[i].flags & HF_MOAT) {
				co++;

				if (cfg.castles_per_player &&
				    co > cfg.castles_per_player)
					s_printf("HOUSES_EXCEEDED: %s owns %d castles.\n", lookup_player_name(id), co);

				if (cfg.castles_for_kings && lookup_player_winner(id) > 0)
					s_printf("HOUSES_EXCEEDED: non-(ex)winner %s owns castle(s).\n", lookup_player_name(id));
			}
		}
	return(ho);
}

/* keep whole function in sync with birth.c! */
void lua_recalc_char(int Ind) {
	player_type *p_ptr = Players[Ind];
	int i, j, min_value, max_value, min_value_king = 0, max_value_king = 9999;
	int tries = 500;

	/* Hitdice */
	p_ptr->hitdie = p_ptr->rp_ptr->r_mhp + p_ptr->cp_ptr->c_mhp;

	/* keep in sync with birth.c! */
#if 0
	/* Minimum hitpoints at highest level */
	min_value = (PY_MAX_LEVEL * (p_ptr->hitdie - 1) * 3) / 8;
	min_value += PY_MAX_LEVEL;

	/* Maximum hitpoints at highest level */
	max_value = (PY_MAX_LEVEL * (p_ptr->hitdie - 1) * 5) / 8;
	max_value += PY_MAX_LEVEL;
#endif
#if 0 /* 300 tries */
	/* Minimum hitpoints at kinging level */
	min_value_king = (50 * (p_ptr->hitdie - 1) * 15) / 32;
	min_value_king += 50;
	/* Maximum hitpoints at kinging level */
	max_value_king = (50 * (p_ptr->hitdie - 1) * 17) / 32;
	max_value_king += 50;

	/* Minimum hitpoints at highest level */
	min_value = (PY_MAX_LEVEL * (p_ptr->hitdie - 1) * 15) / 32;
	min_value += PY_MAX_LEVEL;
	/* Maximum hitpoints at highest level */
	max_value = (PY_MAX_LEVEL * (p_ptr->hitdie - 1) * 17) / 32;
	max_value += PY_MAX_LEVEL;
#endif
#if 1
	/* Minimum hitpoints at kinging level */
	min_value_king = (50 * (p_ptr->hitdie - 1) * 31) / 64;
	min_value_king += 50;
	/* Maximum hitpoints at kinging level */
	max_value_king = (50 * (p_ptr->hitdie - 1) * 33) / 64;
	max_value_king += 50;

	/* Minimum hitpoints at highest level */
	min_value = (PY_MAX_LEVEL * (p_ptr->hitdie - 1) * 31) / 64;
	min_value += PY_MAX_LEVEL;
	/* Maximum hitpoints at highest level */
	max_value = (PY_MAX_LEVEL * (p_ptr->hitdie - 1) * 33) / 64;
	max_value += PY_MAX_LEVEL;
#endif

	/* Pre-calculate level 1 hitdice */
	p_ptr->player_hp[0] = p_ptr->hitdie;

	/* Roll out the hitpoints */
	while (--tries) {
		/* Roll the hitpoint values */
		for (i = 1; i < PY_MAX_LEVEL; i++) {
			//j = randint(p_ptr->hitdie);
			j = 2 + randint(p_ptr->hitdie - 4);
			p_ptr->player_hp[i] = p_ptr->player_hp[i - 1] + j;
		}
		/* XXX Could also require acceptable "mid-level" hitpoints */

		/* Require "valid" hitpoints at kinging level */
		if (p_ptr->player_hp[50 - 1] < min_value_king) continue;
		if (p_ptr->player_hp[50 - 1] > max_value_king) continue;

		/* Require "valid" hitpoints at highest level */
		if (p_ptr->player_hp[PY_MAX_LEVEL - 1] < min_value) continue;
		if (p_ptr->player_hp[PY_MAX_LEVEL - 1] > max_value) continue;

		/* Acceptable */
		break;
	}

	if (!tries) s_printf("CHAR_REROLLING: %s exceeded 500 tries for HP rolling.\n", p_ptr->name);

	p_ptr->update |= PU_HP;
	update_stuff(Ind);
}

void lua_examine_item(int Ind, int Ind_target, int item) {
	identify_fully_aux(Ind, &Players[Ind_target]->inventory[item], FALSE, item, Ind_target != Ind ? Ind_target : 0);
}

void lua_determine_level_req(int Ind, int item) {
	/* -9999 is a fixed hack value, see object2.c, determine_level_req.
	   It means: assume that finding-depth is same as object-base-level,
	   for smooth and easy calculation. */
	determine_level_req(-9999, &Players[Ind]->inventory[item]);
}

/* the essential function for art reset */
void lua_strip_true_arts_from_present_player(int Ind, int mode) {
	player_type *p_ptr = Players[Ind];
	object_type *o_ptr;
	int i, total_number = 0;
	bool reimbursed = FALSE, gold_overflow = FALSE;
	s32b cost;

	for (i = 0; i < INVEN_TOTAL; i++) {
		o_ptr = &p_ptr->inventory[i];
		if (resettable_artifact_p(o_ptr))
			total_number++;
	}

	/* Tell the player what's going on.. */
	if (total_number == 1) msg_print(Ind, "\377yYour true artifact vanishes into the air!");
	else if (total_number == 2) msg_print(Ind, "\377yBoth of your true artifacts vanish into the air!");
	else if (total_number) msg_print(Ind, "\377yYour true artifacts all vanish into the air!");

	for (i = 0; i < INVEN_TOTAL; i++) {
		o_ptr = &p_ptr->inventory[i];
		if (resettable_artifact_p(o_ptr)) {
			//char  o_name[ONAME_LEN];
			//object_desc(Ind, o_name, o_ptr, TRUE, 0);
			//msg_format(Ind, "%s fades into the air!", o_name);

			/* reimburse player monetarily */
			cost = a_info[o_ptr->name1].cost;
			if (cost > 0) {
//				if (cost > 500000) cost = 500000; //not required, it's still fair
				if (gain_au(Ind, cost, gold_overflow, FALSE)) reimbursed = TRUE;
				else gold_overflow = TRUE;
			}

			if (mode == 0) handle_art_d(o_ptr->name1);

			/* Decrease the item, optimize. */
			inven_item_increase(Ind, i, -o_ptr->number);
			inven_item_describe(Ind, i);
			inven_item_optimize(Ind, i);
			i--;
		}
	}
	if (total_number) s_printf("True-art strip: %s loses %d artifact(s).\n", p_ptr->name, total_number);
	if (reimbursed) msg_print(Ind, "\377yYour purse magically seems heavier.");
}

void lua_check_player_for_true_arts(int Ind) {
	player_type *p_ptr = Players[Ind];
	object_type *o_ptr;
	int i, total_number = 0;

	for (i = 0; i < INVEN_TOTAL; i++) {
		o_ptr = &p_ptr->inventory[i];
		if (true_artifact_p(o_ptr)) total_number++;
	}
	if (total_number) s_printf("True-art scan: %s carries %d.\n", p_ptr->name, total_number);
}

void lua_strip_true_arts_from_absent_players(void) {
	strip_true_arts_from_hashed_players();
}

/* Remove all true artifacts in the world, excluding traditional houses. */
void lua_strip_true_arts_from_floors(void) {
	int i, cnt = 0, dcnt = 0;
	object_type *o_ptr;

	for (i = 0; i < o_max; i++) {
		o_ptr = &o_list[i];
		if (o_ptr->k_idx) {
			cnt++;
			if (resettable_artifact_p(o_ptr)) {
				delete_object_idx(i, TRUE);
				dcnt++;
			}
		}
	}
	s_printf("Scanned %d objects. Removed %d artefacts.\n", cnt, dcnt);
}

/* Return a monster level */
int lua_get_mon_lev(int r_idx) {
	return(r_info[r_idx].level);
}
/* Return a monster name */
char *lua_get_mon_name(int r_idx) {
	return(r_name + r_info[r_idx].name);
}

/* Return the last chat line */
inline char *lua_get_last_chat_line() {
	return(last_chat_line);
}

/* Return the last person who said the last chat line */
char *lua_get_last_chat_owner() {
	return(last_chat_owner);
}

/* Return the last person's account name who said the last chat line */
char *lua_get_last_chat_account() {
	return(last_chat_account);
}

/* Reset all towns */
void lua_towns_treset(void) {
	int x, y;
	struct worldpos wpos;

	wpos.wz = 0;

	for (x = 0; x < MAX_WILD_X; x++)
	for (y = 0; y < MAX_WILD_Y; y++) {
		wpos.wx = x;
		wpos.wy = y;
		if (istown(&wpos)) {
			unstatic_level(&wpos);
			if (getcave(&wpos)) dealloc_dungeon_level(&wpos);
		}
	}
}

/* To do some connection magik ! */
long lua_player_exp(int level, int expfact) {
	s64b adv;

	if (level < 1) level = 1;
	if (level > PY_MAX_LEVEL) level = PY_MAX_LEVEL;

#ifndef ALT_EXPRATIO
	adv = ((s64b)player_exp[level - 2] * (s64b)expfact / 100L);
#else
	adv = (s64b)player_exp[level - 2];
#endif

	return(adv);
}

/* Fix all spellbooks not in players inventories, but in houses or on the floor.
   Currently does not handle carried (monster inventory) or embedded (special floor) objects.
 * Adds mod to spellbook pval if it's greater than or equal to spell
 * spell in most cases is the number of the new spell and mod is 1
 * - mikaelh */
void lua_fix_spellbooks(int spell, int mod) {
	int i, j;
	object_type *o_ptr;
	house_type *h_ptr;

	/* scan world (includes MAngband-style houses) */
	for (i = 0; i < o_max; i++) {
		o_ptr = &o_list[i];
		if (o_ptr->tval == TV_BOOK) {
			if (o_ptr->sval == SV_SPELLBOOK && o_ptr->pval >= spell) o_ptr->pval += mod;
			/* spells inside custom books */
			if (is_custom_tome(o_ptr->sval)) {
				if (o_ptr->xtra1 - 1 >= spell) o_ptr->xtra1 += mod;
				if (o_ptr->xtra2 - 1 >= spell) o_ptr->xtra2 += mod;
				if (o_ptr->xtra3 - 1 >= spell) o_ptr->xtra3 += mod;
				if (o_ptr->xtra4 - 1 >= spell) o_ptr->xtra4 += mod;
				if (o_ptr->xtra5 - 1 >= spell) o_ptr->xtra5 += mod;
				if (o_ptr->xtra6 - 1 >= spell) o_ptr->xtra6 += mod;
				if (o_ptr->xtra7 - 1 >= spell) o_ptr->xtra7 += mod;
				if (o_ptr->xtra8 - 1 >= spell) o_ptr->xtra8 += mod;
				if (o_ptr->xtra9 - 1 >= spell) o_ptr->xtra9 += mod;
			}
		}
	}

#ifndef USE_MANG_HOUSE_ONLY
	/* scan traditional (vanilla) houses */
	for (j = 0; j < num_houses; j++) {
		h_ptr = &houses[j];
		for (i = 0; i < h_ptr->stock_num; i++) {
			o_ptr = &h_ptr->stock[i];
			if (!o_ptr->k_idx) continue;
			if (o_ptr->tval == TV_BOOK) {
				if (o_ptr->sval == SV_SPELLBOOK && o_ptr->pval >= spell) o_ptr->pval += mod;
				/* spells inside custom books */
				if (is_custom_tome(o_ptr->sval)) {
					if (o_ptr->xtra1 - 1 >= spell) o_ptr->xtra1 += mod;
					if (o_ptr->xtra2 - 1 >= spell) o_ptr->xtra2 += mod;
					if (o_ptr->xtra3 - 1 >= spell) o_ptr->xtra3 += mod;
					if (o_ptr->xtra4 - 1 >= spell) o_ptr->xtra4 += mod;
					if (o_ptr->xtra5 - 1 >= spell) o_ptr->xtra5 += mod;
					if (o_ptr->xtra6 - 1 >= spell) o_ptr->xtra6 += mod;
					if (o_ptr->xtra7 - 1 >= spell) o_ptr->xtra7 += mod;
					if (o_ptr->xtra8 - 1 >= spell) o_ptr->xtra8 += mod;
					if (o_ptr->xtra9 - 1 >= spell) o_ptr->xtra9 += mod;
				}
			}
		}
	}
#endif
}

/* hacked crap if above function wasn't executed properly -.- regarding custom tomes */
void lua_fix_spellbooks_hackfix(int spell, int mod) {
	int i, j;
	object_type *o_ptr;
	house_type *h_ptr;

#ifndef USE_MANG_HOUSE_ONLY
	/* scan world (includes MAngband-style houses) */
	for (i = 0; i < o_max; i++) {
		o_ptr = &o_list[i];
		if (o_ptr->tval == TV_BOOK) {
			/* spells inside custom books */
			if (is_custom_tome(o_ptr->sval)) {
				if (o_ptr->xtra1 - 1 >= spell) o_ptr->xtra1 += mod;
				if (o_ptr->xtra2 - 1 >= spell) o_ptr->xtra2 += mod;
				if (o_ptr->xtra3 - 1 >= spell) o_ptr->xtra3 += mod;
				if (o_ptr->xtra4 - 1 >= spell) o_ptr->xtra4 += mod;
				if (o_ptr->xtra5 - 1 >= spell) o_ptr->xtra5 += mod;
				if (o_ptr->xtra6 - 1 >= spell) o_ptr->xtra6 += mod;
				if (o_ptr->xtra7 - 1 >= spell) o_ptr->xtra7 += mod;
				if (o_ptr->xtra8 - 1 >= spell) o_ptr->xtra8 += mod;
				if (o_ptr->xtra9 - 1 >= spell) o_ptr->xtra9 += mod;
			}
		}
	}
#endif

	/* scan traditional (vanilla) houses */
	for (j = 0; j < num_houses; j++) {
		h_ptr = &houses[j];
		for (i = 0; i < h_ptr->stock_num; i++) {
			o_ptr = &h_ptr->stock[i];
			if (!o_ptr->k_idx) continue;
			if (o_ptr->tval == TV_BOOK) {
				/* spells inside custom books */
				if (is_custom_tome(o_ptr->sval)) {
					if (o_ptr->xtra1 - 1 >= spell) o_ptr->xtra1 += mod;
					if (o_ptr->xtra2 - 1 >= spell) o_ptr->xtra2 += mod;
					if (o_ptr->xtra3 - 1 >= spell) o_ptr->xtra3 += mod;
					if (o_ptr->xtra4 - 1 >= spell) o_ptr->xtra4 += mod;
					if (o_ptr->xtra5 - 1 >= spell) o_ptr->xtra5 += mod;
					if (o_ptr->xtra6 - 1 >= spell) o_ptr->xtra6 += mod;
					if (o_ptr->xtra7 - 1 >= spell) o_ptr->xtra7 += mod;
					if (o_ptr->xtra8 - 1 >= spell) o_ptr->xtra8 += mod;
					if (o_ptr->xtra9 - 1 >= spell) o_ptr->xtra9 += mod;
				}
			}
		}
	}
}

/* Similar to lua_fix_spellbooks() this function deletes, replaces or swaps spells.
   snew == -1 will erase the spell in custom books. */
void lua_fix_spellbooks2(int sold, int snew, int swap) {
	int i, j;
	object_type *o_ptr;
	house_type *h_ptr;

	/* catch bad parameter choice */
	if (snew == -1) swap = FALSE;

#ifndef USE_MANG_HOUSE_ONLY
	/* scan world (includes MAngband-style houses) */
	for (i = 0; i < o_max; i++) {
		o_ptr = &o_list[i];
		if (o_ptr->tval != TV_BOOK) continue;

		if (o_ptr->sval == SV_SPELLBOOK) {
			if (o_ptr->pval == sold) o_ptr->pval = (snew != -1 ? snew : 0);
			else if (swap && o_ptr->pval == snew) o_ptr->pval = sold;
		}
		/* spells inside custom books */
		if (is_custom_tome(o_ptr->sval)) {
			if (o_ptr->xtra1 - 1 == sold) o_ptr->xtra1 = snew + 1;
			else if (swap && o_ptr->xtra1 - 1 == snew) o_ptr->xtra1 = sold + 1;
			if (o_ptr->xtra2 - 1 == sold) o_ptr->xtra2 = snew + 1;
			else if (swap && o_ptr->xtra2 - 1 == snew) o_ptr->xtra2 = sold + 1;
			if (o_ptr->xtra3 - 1 == sold) o_ptr->xtra3 = snew + 1;
			else if (swap && o_ptr->xtra3 - 1 == snew) o_ptr->xtra3 = sold + 1;
			if (o_ptr->xtra4 - 1 == sold) o_ptr->xtra4 = snew + 1;
			else if (swap && o_ptr->xtra4 - 1 == snew) o_ptr->xtra4 = sold + 1;
			if (o_ptr->xtra5 - 1 == sold) o_ptr->xtra5 = snew + 1;
			else if (swap && o_ptr->xtra5 - 1 == snew) o_ptr->xtra5 = sold + 1;
			if (o_ptr->xtra6 - 1 == sold) o_ptr->xtra6 = snew + 1;
			else if (swap && o_ptr->xtra6 - 1 == snew) o_ptr->xtra6 = sold + 1;
			if (o_ptr->xtra7 - 1 == sold) o_ptr->xtra7 = snew + 1;
			else if (swap && o_ptr->xtra7 - 1 == snew) o_ptr->xtra7 = sold + 1;
			if (o_ptr->xtra8 - 1 == sold) o_ptr->xtra8 = snew + 1;
			else if (swap && o_ptr->xtra8 - 1 == snew) o_ptr->xtra8 = sold + 1;
			if (o_ptr->xtra9 - 1 == sold) o_ptr->xtra9 = snew + 1;
			else if (swap && o_ptr->xtra9 - 1 == snew) o_ptr->xtra9 = sold + 1;
		}
	}
#endif

	/* scan traditional (vanilla) houses */
	for (j = 0; j < num_houses; j++) {
		h_ptr = &houses[j];
		for (i = 0; i < h_ptr->stock_num; i++) {
			o_ptr = &h_ptr->stock[i];
			if (!o_ptr->k_idx) continue;
			if (o_ptr->tval != TV_BOOK) continue;

			if (o_ptr->sval == SV_SPELLBOOK) {
				if (o_ptr->pval == sold) o_ptr->pval = (snew != -1 ? snew : 0);
				else if (swap && o_ptr->pval == snew) o_ptr->pval = sold;
			}
			/* spells inside custom books */
			if (is_custom_tome(o_ptr->sval)) {
				if (o_ptr->xtra1 - 1 == sold) o_ptr->xtra1 = snew + 1;
				else if (swap && o_ptr->xtra1 - 1 == snew) o_ptr->xtra1 = sold + 1;
				if (o_ptr->xtra2 - 1 == sold) o_ptr->xtra2 = snew + 1;
				else if (swap && o_ptr->xtra2 - 1 == snew) o_ptr->xtra2 = sold + 1;
				if (o_ptr->xtra3 - 1 == sold) o_ptr->xtra3 = snew + 1;
				else if (swap && o_ptr->xtra3 - 1 == snew) o_ptr->xtra3 = sold + 1;
				if (o_ptr->xtra4 - 1 == sold) o_ptr->xtra4 = snew + 1;
				else if (swap && o_ptr->xtra4 - 1 == snew) o_ptr->xtra4 = sold + 1;
				if (o_ptr->xtra5 - 1 == sold) o_ptr->xtra5 = snew + 1;
				else if (swap && o_ptr->xtra5 - 1 == snew) o_ptr->xtra5 = sold + 1;
				if (o_ptr->xtra6 - 1 == sold) o_ptr->xtra6 = snew + 1;
				else if (swap && o_ptr->xtra6 - 1 == snew) o_ptr->xtra6 = sold + 1;
				if (o_ptr->xtra7 - 1 == sold) o_ptr->xtra7 = snew + 1;
				else if (swap && o_ptr->xtra7 - 1 == snew) o_ptr->xtra7 = sold + 1;
				if (o_ptr->xtra8 - 1 == sold) o_ptr->xtra8 = snew + 1;
				else if (swap && o_ptr->xtra8 - 1 == snew) o_ptr->xtra8 = sold + 1;
				if (o_ptr->xtra9 - 1 == sold) o_ptr->xtra9 = snew + 1;
				else if (swap && o_ptr->xtra9 - 1 == snew) o_ptr->xtra9 = sold + 1;
			}
		}
	}
}

/* This function is called after load_player, so his artifacts would already be set to 1;
   for that reason we disable the mega-hack in load2.c instead for players whose updated_savegame
   flag shows that they might still carry unfixed arts, and do a general incrementing here  - C. Blue */
void lua_arts_fix(int Ind) {
	player_type *p_ptr = Players[Ind];
	object_type *o_ptr;
	int i; //, total_number = 0;

	for (i = 0; i < INVEN_TOTAL; i++) {
		o_ptr = &p_ptr->inventory[i];
		if (resettable_artifact_p(o_ptr))
			handle_art_i(o_ptr->name1);
	}
}

/* Display a player's global_event status */
void lua_get_pgestat(int Ind, int n) {
	player_type *p_ptr = Players[Ind];

	msg_format(Ind, "%s: #%d, type %d, signup %ld, started %ld,",
		    p_ptr->name, n, p_ptr->global_event_type[n], (long)p_ptr->global_event_signup[n], (long)p_ptr->global_event_started[n]);
	msg_format(Ind, "  progress: %d,%d,%d,%d", p_ptr->global_event_progress[n][0], p_ptr->global_event_progress[n][1],
		    p_ptr->global_event_progress[n][2], p_ptr->global_event_progress[n][3]);
}

void lua_start_global_event(int Ind, int evtype, char *parm) {
	start_global_event(Ind, evtype, parm);
}

/* Fix items that were changed on updating the server. If Ind == 0 -> scan world/houses - C. Blue */
void lua_apply_item_changes(int Ind, int changes) {
	int i, j;
	object_type *o_ptr;
	house_type *h_ptr;

	if (!Ind) {
	/* scan world/houses */
#ifndef USE_MANG_HOUSE_ONLY
		/* scan traditional (vanilla) houses */
		for (j = 0; j < num_houses; j++) {
			h_ptr = &houses[j];
			for (i = 0; i < h_ptr->stock_num; i++) {
				o_ptr = &h_ptr->stock[i];
				if (!o_ptr->k_idx) continue;
				lua_apply_item_changes_aux(o_ptr, changes);
			}
		}
#endif
		/* scan world (includes MAngband-style houses) */
		for (i = 0; i < o_max; i++) {
			o_ptr = &o_list[i];
			if (!o_ptr->k_idx) continue;
			lua_apply_item_changes_aux(o_ptr, changes);
		}
	} else {
		/* scan a player's inventory/equipment */
		for (i = 0; i < INVEN_TOTAL; i++) {
			o_ptr = &Players[Ind]->inventory[i];
			if (!o_ptr->k_idx) continue;
			lua_apply_item_changes_aux(o_ptr, changes);
		}
	}
}
void lua_apply_item_changes_aux(object_type *o_ptr, int changes) {
}

/* sets LFx_ flags on the dungeon master's floor to specific values */
void lua_set_floor_flags(int Ind, u32b flags) {
	getfloor(&Players[Ind]->wpos)->flags1 = flags;
}

s32b lua_get_skill_mod(int Ind, int i) {
	s32b value = 0, mod = 0;
	player_type *p_ptr = Players[Ind];
	compute_skills(p_ptr, &value, &mod, i);
	return(mod);
}

s32b lua_get_skill_value(int Ind, int i) {
	s32b value = 0, mod = 0;
	player_type *p_ptr = Players[Ind];
	compute_skills(p_ptr, &value, &mod, i);
	return(value);
}

/* fix dual-wield slot position change */
void lua_fix_equip_slots(int Ind) {
	int i;
	player_type *p_ptr = Players[Ind];
	object_type *o_ptr;

	for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
		if (p_ptr->inventory[i].k_idx &&
		    wield_slot(Ind, &p_ptr->inventory[i]) != i &&
		    !(i == INVEN_ARM && wield_slot(Ind, &p_ptr->inventory[i]) == INVEN_WIELD)) {

			/* Hack - wield_slot always returns INVEN_LEFT for rings because they're already being worn
			 * This prevents the ring in the right hand from being taken off
			 * - mikaelh
			 */
			if ((i == INVEN_RIGHT || i == INVEN_LEFT) &&
			    p_ptr->inventory[i].tval == TV_RING)
				continue;

			inven_takeoff(Ind, i, 255, FALSE, TRUE);
	}

	/* excise bugged zero-items */
	/* (same as in do_cmd_refresh) */
	/* Hack -- fix the inventory count */
	p_ptr->inven_cnt = 0;
	for (i = 0; i < INVEN_PACK; i++) {
		o_ptr = &p_ptr->inventory[i];
		/* Skip empty items */
		if (!o_ptr->k_idx || !o_ptr->tval) {
			/* hack - make sure the item is really erased - had some bugs there
			   since some code parts use k_idx, and some tval, to kill/test items - C. Blue */
			invwipe(o_ptr);
			continue;
		}
		p_ptr->inven_cnt++;
	}
}

void lua_season_change(int s, int force) {
	season_change(s, (force != 0) ? TRUE : FALSE);
}

#if 0 /* no pointer support / dangerous ? */
/* added for changing seasons via lua cron_24h() - C. Blue */
void lua_get_date(int *weekday, int *day, int *month, int *year)
{
	time_t		now;
	struct tm	*tmp;
	time(&now);
	tmp = localtime(&now);
	*weekday = tmp->tm_wday;
	*day = tmp->tm_mday;
	*month = tmp->tm_mon + 1;
	*year = tmp->tm_mday;
}
#endif

/* for Player-Customizable Tomes feature - C. Blue */
int get_inven_sval(int Ind, int inven_slot) {
	return(Players[Ind]->inventory[inven_slot].sval);
}
s16b get_inven_xtra(int Ind, int inven_slot, int n) {
	switch (n) {
	case 1: return(Players[Ind]->inventory[inven_slot].xtra1);
	case 2: return(Players[Ind]->inventory[inven_slot].xtra2);
	case 3: return(Players[Ind]->inventory[inven_slot].xtra3);
	case 4: return(Players[Ind]->inventory[inven_slot].xtra4);
	case 5: return(Players[Ind]->inventory[inven_slot].xtra5);
	case 6: return(Players[Ind]->inventory[inven_slot].xtra6);
	case 7: return(Players[Ind]->inventory[inven_slot].xtra7);
	case 8: return(Players[Ind]->inventory[inven_slot].xtra8);
	case 9: return(Players[Ind]->inventory[inven_slot].xtra9);
	default: return(0); //failure
	}
}

/* re-initialize the skill chart, keeping all values though */
//#define MODIFY_DEV_STATE /* mess with expand/collapse status? might be annoying if happens on every login */
void lua_fix_skill_chart(int Ind) {
	player_type *p_ptr = Players[Ind];
	int i, j;

#ifdef MODIFY_DEV_STATE
	for (i = 0; i < MAX_SKILLS; i++)
		p_ptr->s_info[i].dev = FALSE;
#endif
	for (i = 0; i < MAX_SKILLS; i++) {
		//s32b value = 0, mod = 0;
		/* Make sure all are touched */
		p_ptr->s_info[i].touched = TRUE;
		//compute_skills(p_ptr, &value, &mod, i);
		//init_skill(p_ptr, value, mod, i);
		/* pseudo-init-skill */
#if 0 //SMOOTHSKILLS
		if (s_info[i].flags1 & SKF1_HIDDEN) {
			p_ptr->s_info[i].hidden = TRUE;
		} else {
			p_ptr->s_info[i].hidden = FALSE;
		}
		if (s_info[i].flags1 & SKF1_DUMMY) {
			p_ptr->s_info[i].dummy = TRUE;
		} else {
			p_ptr->s_info[i].dummy = FALSE;
		}
#else
		p_ptr->s_info[i].flags1 = (char)(s_info[i].flags1 & 0xFF);

		/* hack: Rangers can train limited Archery skill */
		if (p_ptr->pclass == CLASS_RANGER && i == SKILL_ARCHERY)
			p_ptr->s_info[i].flags1 |= SKF1_MAX_10;
		/* hack: Druids/Vampires can't train Mimicry skill */
		if ((p_ptr->pclass == CLASS_DRUID || p_ptr->prace == RACE_VAMPIRE)
		    && i == SKILL_MIMIC)
			p_ptr->s_info[i].flags1 |= SKF1_MAX_1;
#endif
		/* Develop only revelant branches */
		if (p_ptr->s_info[i].value || p_ptr->s_info[i].mod) {
			j = s_info[i].father;
			while (j != -1) {
#ifdef MODIFY_DEV_STATE
				p_ptr->s_info[j].dev = TRUE;
#endif
				j = s_info[j].father;
				if (j == 0) break;
			}
		}
	}

	/* hack - fix SKILL_STANCE skill */
	if (get_skill(p_ptr, SKILL_STANCE)) {
		if (p_ptr->max_plv < 50) p_ptr->s_info[SKILL_STANCE].value = p_ptr->max_plv * 1000;
		else p_ptr->s_info[SKILL_STANCE].value = 50000;
		/* Update the client */
		Send_skill_info(Ind, SKILL_STANCE, TRUE);
		/* Also update the client's 'm' menu for fighting techniques */
		calc_techniques(Ind);
		Send_skill_info(Ind, SKILL_TECHNIQUE, TRUE);
	}

	p_ptr->update |= PU_SKILL_INFO | PU_SKILL_MOD;
	update_stuff(Ind);
}

void lua_takeoff_costumes(int Ind) {
	player_type *p_ptr = Players[Ind];

	if ((p_ptr->inventory[INVEN_BODY].tval == TV_SOFT_ARMOR) && (p_ptr->inventory[INVEN_BODY].sval == SV_COSTUME)) {
		inven_takeoff(Ind, INVEN_BODY, 255, FALSE, TRUE);
		msg_print(Ind, "It's not that time of the year anymore.");
	}
}

bool lua_is_unique(int r_idx) {
	if (r_info[r_idx].flags1 & RF1_UNIQUE) return(TRUE); else return(FALSE);
}

/* Return if a certain race/class combo could in theory learn a monster form if mimicry was high enough */
bool lua_mimic_eligible(int Ind, int r_idx) {
	/* also filter out unattainable (in theory) forms */
	if (r_info[r_idx].rarity == 255) return(FALSE);
	if ((r_info[r_idx].flags1 & RF1_UNIQUE)) return(FALSE);
	if (!mon_allowed_chance(&r_info[r_idx])) return(FALSE);

	if (Players[Ind]->prace == RACE_VAMPIRE) {
		return(mimic_vampire(r_idx, Players[Ind]->lev));
	}

	if (Players[Ind]->pclass == CLASS_SHAMAN) {
		return(mimic_shaman(r_idx));
	} else if (Players[Ind]->pclass == CLASS_DRUID) {
		return(mimic_druid(r_idx, Players[Ind]->lev));
	}

	return(TRUE);
}

/* Return if a monster form is considered basically humanoid, ie has all extremities required for full equipment */
bool lua_mimic_humanoid(int r_idx) {
	if (!r_info[r_idx].body_parts[BODY_WEAPON]) return(FALSE);
	if (r_info[r_idx].body_parts[BODY_FINGER] < 2) return(FALSE);
	if (!r_info[r_idx].body_parts[BODY_HEAD]) return(FALSE);
	if (!r_info[r_idx].body_parts[BODY_ARMS]) return(FALSE);
	if (!r_info[r_idx].body_parts[BODY_TORSO]) return(FALSE);
	if (!r_info[r_idx].body_parts[BODY_LEGS]) return(FALSE);
	return(TRUE);
}

void swear_add(char *word, int level) {
	int i;

	for (i = 0; i < MAX_SWEAR - 1; i++) {
		if (swear[i].word[0]) continue;
		strcpy(swear[i].word, word);
		swear[i].level = level;
		return;
	}
	s_printf("FAILED to add swear word '%s' (%d).\n", word, level);
}
char *swear_get_word(int i) {
	return(swear[i].word);
}
int swear_get_level(int i) {
	return(swear[i].level);
}
void nonswear_add(char *word, int affix) {
	int i;

	for (i = 0; i < MAX_NONSWEAR - 1; i++) {
		if (nonswear[i][0]) continue;
		strcpy(nonswear[i], word);
		nonswear_affix[i] = affix;
		return;
	}
	s_printf("FAILED to add non-swear word '%s'.\n", word);
}
char *nonswear_get(int i) {
	return(nonswear[i]);
}
int nonswear_affix_get(int i) {
	return(nonswear_affix[i]);
}
void lua_swear_list(int Ind, int level) {
	int i, c = 0;

	for (i = 0; i < MAX_SWEAR; i++) {
		if (!swear[i].word[0]) continue;
		if (swear[i].level < level) continue;
		c++;
		msg_format(Ind, "%3d (Lv %d): %s", i, swear[i].level, swear[i].word);
	}
	msg_format(Ind, "Total of %d/%d swear words.", c, MAX_SWEAR);
}
void lua_nonswear_list(int Ind) {
	int i, c = 0;

	for (i = 0; i < MAX_NONSWEAR; i++) {
		if (!nonswear[i][0]) continue;
		c++;
		msg_format(Ind, "%3d (Pre/Suf %c%c): %s", i, (nonswear_affix[i] & 0x1) ? '*' : '-', (nonswear_affix[i] & 0x2) ? '*' : '-', nonswear[i]);
	}
	msg_format(Ind, "Total of %d/%d nonswear terms.", c, MAX_NONSWEAR);
}

void lua_fix_max_depth(int Ind) {
	player_type *p_ptr = Players[Ind];
	fix_max_depth(p_ptr);
}

void lua_fix_max_depth_bug(int Ind) {
	player_type *p_ptr = Players[Ind];
	fix_max_depth_bug(p_ptr);
}

/* for use with flavour reset by '-f' */
void lua_forget_flavours(int Ind) {
	int i;

	for (i = 0; i < MAX_K_IDX; i++) {
		Players[Ind]->obj_aware[i] = FALSE;
		Players[Ind]->obj_tried[i] = FALSE;
		Players[Ind]->obj_felt[i] = FALSE;
		Players[Ind]->obj_felt_heavy[i] = FALSE;
	}
}

/* for use with '-w' wilderness creation */
void lua_forget_map(int Ind) {
	int i;

	for (i = 0; i < MAX_WILD_8; i++)
		Players[Ind]->wild_map[i] = 0;
}

/* for resetting all party information */
void lua_forget_parties(void) {
	int i, j;
	for (i = 1; i <= NumPlayers; i++) {
		Players[i]->party = 0;
		clockin(i, 2);
	}
	for (i = 0; i < MAX_PARTIES; i++) {
		parties[i].name[0] = '\0';
		parties[i].owner[0] = '\0';
		parties[i].members = 0;
		parties[i].created = 0;
		parties[i].mode = 0;
		parties[i].cmode = 0;
		parties[i].flags = 0x0;
		for (j = 0; j < BBS_LINES; j++)
			pbbs_line[i][j][0] = '\0';
	}
}

/* for resetting all guild information
   --note: guild halls/save files? */
void lua_forget_guilds(void) {
	int i, j;
	for (i = 1; i <= NumPlayers; i++) {
		Players[i]->guild = 0;
		clockin(i, 3);
	}
	for (i = 0; i < MAX_GUILDS; i++) {
		guilds[i].name[0] = '\0';
		guilds[i].master = 0;
		guilds[i].members = 0;
		guilds[i].cmode = 0;
		guilds[i].flags = 0x0;
		guilds[i].minlev = 0;
		for (j = 0; j < 5; j++)
			guilds[i].adder[j][0] = '\0';
		for (j = 0; j < BBS_LINES; j++)
			gbbs_line[i][j][0] = '\0';
	}
}

/* Workaround for ACC_HOUSE_LIMIT bug:
   Just recount houses after every login, this should fix the glitch where people can suddenly have 33 (instead of the limit of 30) houses or more..
   This is usually only called from custom.lua, when a player logs in. */
void lua_fix_acc_house_limit(int Ind) {
	player_type *p_ptr = Players[Ind];
	int i, j;
	struct account acc;
#if 0
	int h, ht = 0, ids, *id_list;
	hash_entry *ptr;
#endif

	/* how many houses he should have */
	i = acc_get_houses(p_ptr->accountname);

	if (!GetAccount(&acc, p_ptr->accountname, NULL, FALSE)) {
		s_printf("lua_fix_acc_house_limit: Couldn't find that account.\n");
		return;
	}

	/* recount how many houses he really has */
	j = acc_sum_houses(&acc, TRUE);

#if 0
	/* recount how many houses he really has */
	ids = player_id_list(&id_list, acc.id);
	for (i = 0; i < ids; i++) {
		ptr = lookup_player(id_list[i]);
		h = lua_count_houses_id(id_list[i]);
		ht += h;
	}
	if (ids) C_KILL(id_list, ids, int);
#endif

	if (i != j) {
		acc_set_houses(p_ptr->accountname, j);
		s_printf("lua_fix_acc_house_limit: FIXED '%s'('%s'): %d houses are really -> %d.\n", p_ptr->name, p_ptr->accountname, i, j);
	}
}

/* Simplified wish() version for lua scripts */
void lua_wish(int Ind, int tval, int sval, int number, int bpval, int pval, int name1, int name2, int name2b, int level) {
	wish(Ind, NULL, tval, sval, number, bpval, pval, name1, name2, name2b, level, NULL);
}
