summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/luadgn.cc
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source/luadgn.cc')
-rw-r--r--crawl-ref/source/luadgn.cc663
1 files changed, 653 insertions, 10 deletions
diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc
index 5099dd9bdd..da053fb639 100644
--- a/crawl-ref/source/luadgn.cc
+++ b/crawl-ref/source/luadgn.cc
@@ -2,25 +2,31 @@
* File: luadgn.cc
* Summary: Dungeon-builder Lua interface.
*
- * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-06-21T19:20:47.183838Z $
+ * Modified for Crawl Reference by $Author$ on $Date$
*/
#include "AppHdr.h"
#include <sstream>
+#include "branch.h"
#include "clua.h"
+#include "cloud.h"
#include "direct.h"
#include "dungeon.h"
#include "files.h"
#include "initfile.h"
+#include "items.h"
#include "luadgn.h"
#include "mapdef.h"
#include "mapmark.h"
#include "maps.h"
+#include "misc.h"
+#include "spl-util.h"
#include "stuff.h"
#include "tags.h"
#include "terrain.h"
+#include "view.h"
// Lua interpreter for the dungeon builder.
CLua dlua(false);
@@ -430,6 +436,95 @@ static int dgn_tags_remove(lua_State *ls)
PLUARET(string, map->tags.c_str());
}
+static const std::string level_flag_names[] =
+ {"no_tele_control", "not_mappable", "no_magic_map", ""};
+
+static int dgn_lflags(lua_State *ls)
+{
+ MAP(ls, 1, map);
+
+ try
+ {
+ map->level_flags = map_flags::parse(level_flag_names,
+ luaL_checkstring(ls, 2));
+ }
+ catch (const std::string &error)
+ {
+ luaL_argerror(ls, 2, error.c_str());
+ }
+
+ return (0);
+}
+
+static int dgn_change_level_flags(lua_State *ls)
+{
+ map_flags flags;
+
+ try {
+ flags = map_flags::parse(level_flag_names,
+ luaL_checkstring(ls, 1));
+ }
+ catch (const std::string &error)
+ {
+ luaL_argerror(ls, 2, error.c_str());
+ lua_pushboolean(ls, false);
+ return (1);
+ }
+
+ bool silent = lua_toboolean(ls, 2);
+
+ bool changed1 = set_level_flags(flags.flags_set, silent);
+ bool changed2 = unset_level_flags(flags.flags_unset, silent);
+
+ lua_pushboolean(ls, changed1 || changed2);
+
+ return (1);
+}
+
+static const std::string branch_flag_names[] =
+ {"no_tele_control", "not_mappable", "no_magic_map", ""};
+
+static int dgn_bflags(lua_State *ls)
+{
+ MAP(ls, 1, map);
+
+ try {
+ map->branch_flags = map_flags::parse(branch_flag_names,
+ luaL_checkstring(ls, 2));
+ }
+ catch (const std::string &error)
+ {
+ luaL_argerror(ls, 2, error.c_str());
+ }
+
+ return (0);
+}
+
+static int dgn_change_branch_flags(lua_State *ls)
+{
+ map_flags flags;
+
+ try {
+ flags = map_flags::parse(branch_flag_names,
+ luaL_checkstring(ls, 1));
+ }
+ catch (const std::string &error)
+ {
+ luaL_argerror(ls, 2, error.c_str());
+ lua_pushboolean(ls, false);
+ return (1);
+ }
+
+ bool silent = lua_toboolean(ls, 2);
+
+ bool changed1 = set_branch_flags(flags.flags_set, silent);
+ bool changed2 = unset_branch_flags(flags.flags_unset, silent);
+
+ lua_pushboolean(ls, changed1 || changed2);
+
+ return (1);
+}
+
static int dgn_weight(lua_State *ls)
{
MAP(ls, 1, map);
@@ -707,6 +802,15 @@ static int dgn_kitem(lua_State *ls)
return (0);
}
+static int dgn_kmask(lua_State *ls)
+{
+ MAP(ls, 1, map);
+ std::string err = map->add_key_mask(luaL_checkstring(ls, 2));
+ if (!err.empty())
+ luaL_error(ls, err.c_str());
+ return (0);
+}
+
static int dgn_name(lua_State *ls)
{
MAP(ls, 1, map);
@@ -825,18 +929,152 @@ static int dgn_load_des_file(lua_State *ls)
return (0);
}
+static int dgn_floor_colour(lua_State *ls)
+{
+ MAP(ls, 1, map);
+
+ const char *s = luaL_checkstring(ls, 2);
+ int colour = str_to_colour(s);
+
+ if (colour < 0 || colour == BLACK)
+ {
+ std::string error;
+
+ if (colour == BLACK)
+ {
+ error = "Can't set floor to black.";
+ }
+ else {
+ error = "No such colour as '";
+ error += s;
+ error += "'";
+ }
+
+ luaL_argerror(ls, 2, error.c_str());
+
+ return (0);
+ }
+
+ map->floor_colour = (unsigned char) colour;
+ return (0);
+}
+
+static int dgn_rock_colour(lua_State *ls)
+{
+ MAP(ls, 1, map);
+
+ const char *s = luaL_checkstring(ls, 2);
+ int colour = str_to_colour(s);
+
+ if (colour < 0 || colour == BLACK)
+ {
+ std::string error;
+
+ if (colour == BLACK)
+ {
+ error = "Can't set rock to black.";
+ }
+ else {
+ error = "No such colour as '";
+ error += s;
+ error += "'";
+ }
+
+ luaL_argerror(ls, 2, error.c_str());
+
+ return (0);
+ }
+
+ map->rock_colour = (unsigned char) colour;
+
+ return (0);
+}
+
+static int dgn_get_floor_colour(lua_State *ls)
+{
+ PLUARET(string, colour_to_str(env.floor_colour));
+}
+
+static int dgn_get_rock_colour(lua_State *ls)
+{
+ PLUARET(string, colour_to_str(env.rock_colour));
+}
+
+static int dgn_change_floor_colour(lua_State *ls)
+{
+ const char *s = luaL_checkstring(ls, 1);
+ int colour = str_to_colour(s);
+
+ if (colour < 0 || colour == BLACK)
+ {
+ std::string error;
+
+ if (colour == BLACK)
+ {
+ error = "Can't set floor to black.";
+ }
+ else {
+ error = "No such colour as '";
+ error += s;
+ error += "'";
+ }
+
+ luaL_argerror(ls, 1, error.c_str());
+
+ return (0);
+ }
+
+ env.floor_colour = (unsigned char) colour;
+
+ viewwindow(true, false);
+
+ return (0);
+}
+
+static int dgn_change_rock_colour(lua_State *ls)
+{
+ const char *s = luaL_checkstring(ls, 1);
+ int colour = str_to_colour(s);
+
+ if (colour < 0 || colour == BLACK)
+ {
+ std::string error;
+
+ if (colour == BLACK)
+ {
+ error = "Can't set rock to black.";
+ }
+ else {
+ error = "No such colour as '";
+ error += s;
+ error += "'";
+ }
+
+ luaL_argerror(ls, 1, error.c_str());
+
+ return (0);
+ }
+
+ env.rock_colour = (unsigned char) colour;
+
+ viewwindow(true, false);
+
+ return (0);
+}
+
const char *dngn_feature_names[] =
{
- "unseen", "rock_wall", "stone_wall", "closed_door", "metal_wall",
- "secret_door", "green_crystal_wall", "orcish_idol", "wax_wall",
- "permarock_wall", "", "", "", "", "", "", "", "", "", "", "",
- "silver_statue", "granite_statue", "orange_crystal_statue",
- "statue_reserved_1", "statue_reserved_2", "", "", "", "", "", "",
+ "unseen", "closed_door", "secret_door", "wax_wall", "metal_wall",
+ "green_crystal_wall", "rock_wall", "stone_wall", "permarock_wall",
+ "clear_rock_wall", "clear_stone_wall", "clear_permarock_wall",
+ "orcish_idol", "", "", "", "", "", "", "", "",
+ "granite_statue", "statue_reserved_1", "statue_reserved_2",
+ "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "lava",
"deep_water", "", "", "shallow_water", "water_stuck", "floor",
"floor_special", "floor_reserved", "exit_hell", "enter_hell",
- "open_door", "", "", "trap_mechanical", "trap_magical", "trap_iii",
+ "open_door", "", "", "trap_mechanical", "trap_magical", "trap_natural",
"undiscovered_trap", "", "enter_shop", "enter_labyrinth",
"stone_stairs_down_i", "stone_stairs_down_ii",
"stone_stairs_down_iii", "rock_stairs_down", "stone_stairs_up_i",
@@ -925,8 +1163,9 @@ static int dgn_feature_name(lua_State *ls)
static const char *dgn_event_type_names[] =
{
- "none", "turn", "mons_move", "player_move", "leave_level", "enter_level",
- "player_los", "player_climb"
+ "none", "turn", "mons_move", "player_move", "leave_level",
+ "entering_level", "entered_level", "player_los", "player_climb",
+ "monster_dies", "item_pickup", "feat_change"
};
static dgn_event_type dgn_event_type_by_name(const std::string &name)
@@ -1010,6 +1249,22 @@ static int dgn_remove_marker(lua_State *ls)
return (0);
}
+static int dgn_num_matching_markers(lua_State *ls)
+{
+ const char* key = luaL_checkstring(ls, 1);
+ const char* val_ptr = lua_tostring(ls, 2);
+ const char* val;
+
+ if (val_ptr == NULL)
+ val = "";
+ else
+ val = val_ptr;
+
+ std::vector<map_marker*> markers = env.markers.get_all(key, val);
+
+ PLUARET(number, markers.size());
+}
+
static int dgn_feature_desc(lua_State *ls)
{
const dungeon_feature_type feat =
@@ -1054,6 +1309,354 @@ static int dgn_terrain_changed(lua_State *ls)
return (0);
}
+static int dgn_item_from_index(lua_State *ls)
+{
+ const int index = luaL_checkint(ls, 1);
+
+ item_def *item = &mitm[index];
+
+ if (is_valid_item(*item))
+ lua_pushlightuserdata(ls, item);
+ else
+ lua_pushnil(ls);
+
+ return (1);
+}
+
+static int dgn_mons_from_index(lua_State *ls)
+{
+ const int index = luaL_checkint(ls, 1);
+
+ monsters *mons = &menv[index];
+
+ if (mons->type != -1)
+ push_monster(ls, mons);
+ else
+ lua_pushnil(ls);
+
+ return (1);
+}
+
+static int lua_dgn_set_lt_callback(lua_State *ls)
+{
+ const char *level_type = luaL_checkstring(ls, 1);
+
+ if (level_type == NULL || strlen(level_type) == 0)
+ return (0);
+
+ const char *callback_name = luaL_checkstring(ls, 2);
+
+ if (callback_name == NULL || strlen(callback_name) == 0)
+ return (0);
+
+ dgn_set_lt_callback(level_type, callback_name);
+
+ return (0);
+}
+
+static int dgn_fixup_stairs(lua_State *ls)
+{
+ const dungeon_feature_type up_feat =
+ dungeon_feature_by_name(luaL_checkstring(ls, 1));
+
+ const dungeon_feature_type down_feat =
+ dungeon_feature_by_name(luaL_checkstring(ls, 2));
+
+ if (up_feat == DNGN_UNSEEN && down_feat == DNGN_UNSEEN)
+ return(0);
+
+ for (int y = 0; y < GYM; ++y)
+ {
+ for (int x = 0; x < GXM; ++x)
+ {
+ const dungeon_feature_type feat = grd[x][y];
+ if (grid_is_stone_stair(feat) || grid_is_rock_stair(feat))
+ {
+ dungeon_feature_type new_feat = DNGN_UNSEEN;
+
+ if (grid_stair_direction(feat) == CMD_GO_DOWNSTAIRS)
+ new_feat = down_feat;
+ else
+ new_feat = up_feat;
+
+ if (new_feat != DNGN_UNSEEN)
+ {
+ grd[x][y] = new_feat;
+ env.markers.add(
+ new map_feature_marker(
+ coord_def(x, y),
+ new_feat));
+ }
+ }
+ }
+ }
+
+ return (0);
+}
+
+static int dgn_floor_halo(lua_State *ls)
+{
+ std::string error = "";
+
+ const char* s1 = luaL_checkstring(ls, 1);
+ const dungeon_feature_type target = dungeon_feature_by_name(s1);
+
+ if (target == DNGN_UNSEEN)
+ {
+ error += "No such dungeon feature as '";
+ error += s1;
+ error += "'. ";
+ }
+
+ const char* s2 = luaL_checkstring(ls, 2);
+ short colour = str_to_colour(s2);
+
+ if (colour == -1)
+ {
+ error += "No such colour as '";
+ error += s2;
+ error += "'.";
+ }
+ else if (colour == BLACK)
+ {
+ error += "Can't set floor colour to black.";
+ }
+
+ if (error != "")
+ {
+ luaL_argerror(ls, 2, error.c_str());
+ return(0);
+ }
+
+ for (int y = 0; y < GYM; ++y)
+ {
+ for (int x = 0; x < GXM; ++x)
+ {
+ const dungeon_feature_type feat = grd[x][y];
+ if (feat == target)
+ {
+
+ for (int i=-1; i<=1; i++)
+ for (int j=-1; j<=1; j++)
+ {
+ if (!map_bounds(x+i, y+j))
+ continue;
+
+ const dungeon_feature_type feat2 = grd[x+i][y+j];
+
+ if (feat2 == DNGN_FLOOR
+ || feat2 == DNGN_UNDISCOVERED_TRAP)
+ {
+ env.grid_colours[x+i][y+j] = colour;
+ }
+ }
+ }
+ }
+ }
+
+ return (0);
+}
+
+#define SQRT_2 1.41421356237309504880
+
+static int dgn_random_walk(lua_State *ls)
+{
+ const int x = luaL_checkint(ls, 1);
+ const int y = luaL_checkint(ls, 2);
+ const int dist = luaL_checkint(ls, 3);
+
+ // Fourth param being true means that we can move past
+ // statues.
+ const dungeon_feature_type minmove =
+ lua_isnil(ls, 4) ? DNGN_MINMOVE : DNGN_ORCISH_IDOL;
+
+ if (!in_bounds(x, y))
+ {
+ char buf[80];
+ sprintf(buf, "Point (%d,%d) isn't in bounds.", x, y);
+ luaL_argerror(ls, 1, buf);
+ return (0);
+ }
+ if (dist < 1)
+ {
+ luaL_argerror(ls, 3, "Distance must be positive.");
+ return (0);
+ }
+
+ float dist_left = dist;
+ // Allow movement to all 8 adjacent squares if distance is 1
+ // (needed since diagonal moves are distance sqrt(2))
+ if (dist == 1)
+ dist_left = SQRT_2;
+
+ int moves_left = dist;
+ coord_def pos(x, y);
+ while (dist_left >= 1.0 && moves_left-- > 0)
+ {
+ int okay_dirs = 0;
+ int dir = -1;
+ for (int j = 0; j < 8; j++)
+ {
+ const coord_def new_pos = pos + Compass[j];
+ const float move_dist = (j % 2 == 0) ? 1.0 : SQRT_2;
+
+ if (in_bounds(new_pos) && grd(new_pos) >= minmove
+ && move_dist <= dist_left)
+ {
+ if (one_chance_in(++okay_dirs))
+ dir = j;
+ }
+ }
+
+ if (okay_dirs == 0)
+ break;
+
+ if (one_chance_in(++okay_dirs))
+ continue;
+
+ pos += Compass[dir];
+ dist_left -= (dir % 2 == 0) ? 1.0 : SQRT_2;
+ }
+
+ dlua_push_coord(ls, pos);
+
+ return (2);
+}
+
+static cloud_type dgn_cloud_name_to_type(std::string name)
+{
+ lowercase(name);
+
+ if (name == "random")
+ return (CLOUD_RANDOM);
+ else if (name == "debugging")
+ return (CLOUD_DEBUGGING);
+
+ for (int i = CLOUD_NONE; i < CLOUD_RANDOM; i++)
+ if (cloud_name(static_cast<cloud_type>(i)) == name)
+ return static_cast<cloud_type>(i);
+
+ return (CLOUD_NONE);
+}
+
+static kill_category dgn_kill_name_to_category(std::string name)
+{
+ if (name == "")
+ return KC_OTHER;
+
+ lowercase(name);
+
+ if (name == "you")
+ return KC_YOU;
+ else if (name == "friendly")
+ return KC_FRIENDLY;
+ else if (name == "other")
+ return KC_OTHER;
+ else
+ return KC_NCATEGORIES;
+}
+
+static int lua_cloud_pow_min;
+static int lua_cloud_pow_max;
+static int lua_cloud_pow_rolls;
+
+static int make_a_lua_cloud(int x, int y, int garbage, int spread_rate,
+ cloud_type ctype, kill_category whose)
+{
+ UNUSED( garbage );
+ const int pow = random_range(lua_cloud_pow_min,
+ lua_cloud_pow_max,
+ lua_cloud_pow_rolls);
+ place_cloud( ctype, x, y, pow, whose, spread_rate );
+
+ return 1;
+}
+
+static int dgn_apply_area_cloud(lua_State *ls)
+{
+ const int x = luaL_checkint(ls, 1);
+ const int y = luaL_checkint(ls, 2);
+ lua_cloud_pow_min = luaL_checkint(ls, 3);
+ lua_cloud_pow_max = luaL_checkint(ls, 4);
+ lua_cloud_pow_rolls = luaL_checkint(ls, 5);
+ const int size = luaL_checkint(ls, 6);
+
+ const cloud_type ctype = dgn_cloud_name_to_type(luaL_checkstring(ls, 7));
+ const char* kname = lua_isstring(ls, 8) ? luaL_checkstring(ls, 8)
+ : "";
+ const kill_category kc = dgn_kill_name_to_category(kname);
+
+ const int spread_rate = lua_isnumber(ls, 9) ? luaL_checkint(ls, 9) : -1;
+
+ if (!in_bounds(x, y))
+ {
+ char buf[80];
+ sprintf(buf, "Point (%d,%d) isn't in bounds.", x, y);
+ luaL_argerror(ls, 1, buf);
+ return (0);
+ }
+
+ if (lua_cloud_pow_min < 0)
+ {
+ luaL_argerror(ls, 4, "pow_min must be non-negative");
+ return (0);
+ }
+
+ if (lua_cloud_pow_max < lua_cloud_pow_min)
+ {
+ luaL_argerror(ls, 5, "pow_max must not be less than pow_min");
+ return (0);
+ }
+
+ if (lua_cloud_pow_max == 0)
+ {
+ luaL_argerror(ls, 5, "pow_max must be positive");
+ return (0);
+ }
+
+ if (lua_cloud_pow_rolls <= 0)
+ {
+ luaL_argerror(ls, 6, "pow_rolls must be positive");
+ return (0);
+ }
+
+ if (size < 1)
+ {
+ luaL_argerror(ls, 4, "size must be positive.");
+ return (0);
+ }
+
+ if (ctype == CLOUD_NONE)
+ {
+ std::string error = "Invalid cloud type '";
+ error += luaL_checkstring(ls, 7);
+ error += "'";
+ luaL_argerror(ls, 7, error.c_str());
+ return (0);
+ }
+
+ if (kc == KC_NCATEGORIES)
+ {
+ std::string error = "Invalid kill category '";
+ error += kname;
+ error += "'";
+ luaL_argerror(ls, 8, error.c_str());
+ return (0);
+ }
+
+ if (spread_rate < -1 || spread_rate > 100)
+ {
+ luaL_argerror(ls, 9, "spread_rate must be between -1 and 100,"
+ "inclusive");
+ return (0);
+ }
+
+ apply_area_cloud(make_a_lua_cloud, x, y, 0, size,
+ ctype, kc, spread_rate);
+
+ return (0);
+}
+
static const struct luaL_reg dgn_lib[] =
{
{ "default_depth", dgn_default_depth },
@@ -1062,6 +1665,8 @@ static const struct luaL_reg dgn_lib[] =
{ "place", dgn_place },
{ "tags", dgn_tags },
{ "tags_remove", dgn_tags_remove },
+ { "lflags", dgn_lflags },
+ { "bflags", dgn_bflags },
{ "chance", dgn_weight },
{ "welcome", dgn_welcome },
{ "weight", dgn_weight },
@@ -1071,6 +1676,8 @@ static const struct luaL_reg dgn_lib[] =
{ "subst", dgn_subst },
{ "nsubst", dgn_nsubst },
{ "colour", dgn_colour },
+ { "floor_colour", dgn_floor_colour},
+ { "rock_colour", dgn_rock_colour},
{ "subst_remove", dgn_subst_remove },
{ "map", dgn_map },
{ "mons", dgn_mons },
@@ -1079,6 +1686,7 @@ static const struct luaL_reg dgn_lib[] =
{ "kfeat", dgn_kfeat },
{ "kitem", dgn_kitem },
{ "kmons", dgn_kmons },
+ { "kmask", dgn_kmask },
{ "grid", dgn_grid },
{ "terrain_changed", dgn_terrain_changed },
{ "points_connected", dgn_points_connected },
@@ -1094,8 +1702,23 @@ static const struct luaL_reg dgn_lib[] =
{ "register_listener", dgn_register_listener },
{ "remove_listener", dgn_remove_listener },
{ "remove_marker", dgn_remove_marker },
+ { "num_matching_markers", dgn_num_matching_markers},
{ "feature_desc", dgn_feature_desc },
{ "feature_desc_at", dgn_feature_desc_at },
+ { "item_from_index", dgn_item_from_index },
+ { "mons_from_index", dgn_mons_from_index },
+ { "change_level_flags", dgn_change_level_flags},
+ { "change_branch_flags", dgn_change_branch_flags},
+ { "get_floor_colour", dgn_get_floor_colour},
+ { "get_rock_colour", dgn_get_rock_colour},
+ { "change_floor_colour", dgn_change_floor_colour},
+ { "change_rock_colour", dgn_change_rock_colour},
+ { "set_lt_callback", lua_dgn_set_lt_callback},
+ { "fixup_stairs", dgn_fixup_stairs},
+ { "floor_halo", dgn_floor_halo},
+ { "random_walk", dgn_random_walk},
+ { "apply_area_cloud", dgn_apply_area_cloud},
+
{ NULL, NULL }
};
@@ -1226,10 +1849,16 @@ static const struct luaL_reg file_lib[] =
LUARET1(you_can_hear_pos, boolean,
player_can_hear(luaL_checkint(ls,1), luaL_checkint(ls, 2)))
+LUARET1(you_x_pos, number, you.x_pos)
+LUARET1(you_y_pos, number, you.y_pos)
+LUARET2(you_pos, number, you.x_pos, you.y_pos)
static const struct luaL_reg you_lib[] =
{
{ "hear_pos", you_can_hear_pos },
+ { "x_pos", you_x_pos },
+ { "y_pos", you_y_pos },
+ { "pos", you_pos },
{ NULL, NULL }
};
@@ -1253,11 +1882,25 @@ static int dgnevent_ticks(lua_State *ls)
PLUARET(number, dev->elapsed_ticks);
}
+static int dgnevent_arg1(lua_State *ls)
+{
+ DEVENT(ls, 1, dev);
+ PLUARET(number, dev->arg1);
+}
+
+static int dgnevent_arg2(lua_State *ls)
+{
+ DEVENT(ls, 1, dev);
+ PLUARET(number, dev->arg2);
+}
+
static const struct luaL_reg dgnevent_lib[] =
{
{ "type", dgnevent_type },
- { "pos", dgnevent_place },
+ { "pos", dgnevent_place },
{ "ticks", dgnevent_ticks },
+ { "arg1", dgnevent_arg1 },
+ { "arg2", dgnevent_arg2 },
{ NULL, NULL }
};