Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Move saved files into res/ ; add LuaValueContext for better errors wh…

…en converting lua objects
  • Loading branch information...
commit fe144994c8fe0713e6965212004b790ea3e0e157 1 parent 6d10ef6
@ludamad authored
View
4 CMakeLists.txt
@@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 2.6)
set(CMAKE_BUILD_TYPE DEBUG)
-# add_definitions(-DNDEBUG)
+add_definitions(-DNDEBUG)
## Compiler flags
if(CMAKE_COMPILER_IS_GNUCXX)
- add_definitions("-mfpmath=sse -msse2 -ffp-contract=on")
+ add_definitions("-mfpmath=sse -msse2 -ffp-contract=on -std=c++98")
endif()
option(MSVC_SHARED_RT "MSVC: Build with shared runtime libs (/MD)" ON)
View
3  README
@@ -6,8 +6,7 @@ Inventory - 1 through 9 for item slots
Mouse use - click to use last weapon/spell, note mouse use is currently unwieldy and not recommended
Using stairs, picking up items - Simply stop on top of them
-F5 - Save / Force sync in online play
-F6 - Load
+To change the games resolution/toggle fullscrene and other settings, check out settings.yaml.
DEVELOPMENT:
View
2  res/event_occurred.lua
@@ -30,7 +30,7 @@ function events.PlayerEnterLevel()
local single_player = (settings.connection_type == net.NONE)
if single_player then
game.score_board_store()
- game.save("savefile.save")
+ game.save("res/savefile.save")
end
end
View
12 res/game_loop.lua
@@ -59,9 +59,12 @@ end
local fps_timer = timer_create()
local fps_count = 1
+local fps_lastframe = 0
local fps = nil
function game_overlay_draw()
- fps_count = fps_count + 1
+ local frame_increase = math.max(0, game.frame - fps_lastframe)
+ fps_lastframe = game.frame
+ fps_count = fps_count + frame_increase
if fps then
local w,h = unpack( display.window_size )
@@ -102,10 +105,11 @@ function game_loop()
show_message("Press Shift + Esc to exit, your progress will be saved.")
end
- if not game_loop_body(false) then
+ local steponly = (game.frame % settings.steps_per_draw ~= 0)
+ if not game_loop_body(steponly) then
if single_player then
game.score_board_store()
- game.save("savefile.save")
+ game.save("res/savefile.save")
end
break
end
@@ -124,4 +128,4 @@ function game_loop()
print( "Step time: " .. string.format("%f", perf.get_timing("**Step**")) )
print( "Draw time: " .. string.format("%f", perf.get_timing("**Draw**")) )
-end
+end
View
11 res/menus/game_settings_menu.lua
@@ -360,7 +360,7 @@ local function center_setting_fields_create()
fields:add_instance( connection_toggle_create() )
- if current_setting == net.NONE then
+ if current_setting ~= net.CLIENT then
fields:add_instance( respawn_toggle_create() )
end
@@ -368,14 +368,15 @@ local function center_setting_fields_create()
fields:add_instance( speed_toggle_create() )
end
- fields:add_instance( name_field_create() )
+ if current_setting == net.CLIENT then
+ fields:add_instance( host_IP_field_create() )
+ end
+
if current_setting == net.SERVER then
fields:add_instance( frame_action_repeat_toggle_create() )
end
- if current_setting == net.CLIENT then
- fields:add_instance( host_IP_field_create() )
- end
+ fields:add_instance( name_field_create() )
if current_setting ~= net.NONE then
fields:add_instance( connection_port_field_create() )
View
8 res/menus/start_menu.lua
@@ -36,7 +36,7 @@ local function start_menu_create(on_start_click, on_load_click, on_score_click)
)
y_position = y_position + 50
- if file_exists("savefile.save") then
+ if file_exists("res/savefile.save") then
menu:add_instance(
text_button_create("Continue Game", on_load_click, text_button_params),
CENTER,
@@ -95,15 +95,15 @@ function setup_start_menu()
local function on_load_click()
game_loop_control.startup_function = function()
- if file_exists("savefile.save") then
- game.load("savefile.save")
+ if file_exists("res/savefile.save") then
+ game.load("res/savefile.save")
end
end
settings.connection_type = net.NONE
exit_menu()
end
- if file_exists("savefile.save") then
+ if file_exists("res/savefile.save") then
menu_state.continue = on_load_click
else
menu_state.continue = setup_settings_menu
View
421 res/start_menu/game_settings_menu.lua~
@@ -1,421 +0,0 @@
-require "utils"
-require "InstanceGroup"
-require "InstanceLine"
-require "TextInputBox"
-require "TextLabel"
-require "Sprite"
-
-local SETTINGS_BOX_MAXCHARS = 18
-local SETTINGS_BOX_SIZE = {180, 34}
-
-local CONFIG_MENU_SIZE = {640, 480}
-
-local SETTINGS_FONT = font_cached_load(settings.font, 10)
-local BIG_SETTINGS_FONT = font_cached_load(settings.menu_font, 20)
-
-local function text_field_create(label_text, default_text, callbacks)
-
- local field = InstanceGroup.create()
-
- -- Add text label
- field:add_instance(
- TextLabel.create(
- SETTINGS_FONT, -- TextLabel font
- {color = COL_YELLOW },
- label_text
- ),
- {0, -20} -- position
- )
-
- -- Add text input box
- field:add_instance(
- TextInputBox.create(
- SETTINGS_FONT, -- TextInputBox font
- SETTINGS_BOX_SIZE, -- Text input box size
- {SETTINGS_BOX_MAXCHARS, default_text}, -- input box parameters
- callbacks
- ),
- {0, 0} -- position
- )
-
- field.size = SETTINGS_BOX_SIZE
-
- return field
-end
-
-local function name_field_create()
- return text_field_create(
- "Enter your name:",
- "User",
- { -- Field validating & updating
- update = function(field) -- Update username based on contents
- settings.username = field.text
- end
- }
- )
-end
-
-local function is_valid_ip_string(text)
- if text == "localhost" then return true end
-
- local parts = string_split(text, ".")
-
- -- Valid IP string has 4 components, eg 1.2.3.4
- if #parts ~= 4 then return false end
-
- -- Assert all components are numbers <= 255
- for part in values(parts) do
- local number = tonumber(part)
- if number == nil then return false end
- if number < 0 or number > 255 then return false end
- end
-
- return true
-end
-
-local function host_IP_field_create()
- return text_field_create(
- "Host IP:",
- settings.ip,
- { -- Field validating & updating
- update = function(field) -- Update host IP based on contents
- settings.ip = field.text
- end,
- valid_string = is_valid_ip_string
- }
- )
-end
-
-local function connection_port_field_create()
- return text_field_create(
- "Connection Port:",
- settings.port,
- { -- Field validating & updating
- update = function(field) -- Update connection port based on contents
- settings.port = tonumber(field.text)
- end,
- valid_string = tonumber
- }
- )
-end
-
-local function connection_toggle_create()
-
- local client_option_image = image_cached_load("res/interface/sprites/config/client_icon.png")
- local server_option_image = image_cached_load("res/interface/sprites/config/server_icon.png")
- local single_player_option_image = image_cached_load("res/interface/sprites/config/single_player_icon.png")
-
- local toggle = {
- size = SETTINGS_BOX_SIZE,
- font = SETTINGS_FONT
- }
-
- function toggle:step(xy)
- -- Toggle the connection type
- if mouse_left_pressed and mouse_over(xy, self.size) then
- settings.connection_type = (settings.connection_type + 1) % 3
- end
- end
-
- function toggle:draw(xy)
- -- Draw the connection type
-
- local text, color, box_color, sprite
-
- if settings.connection_type == net.CLIENT then
- text = "Connect to a game"
- color = COL_MUTED_GREEN
- sprite = client_option_image
- elseif settings.connection_type == net.SERVER then
- text = "Host a game"
- color = COL_PALE_RED
- sprite = server_option_image
- else -- settings.connection_type == net.NONE
- text = "Single-player"
- color = COL_BABY_BLUE
- sprite = single_player_option_image
- end
-
- local x,y = unpack(xy)
- local w, h = unpack(self.size)
-
- sprite:draw( { color = color, origin = LEFT_CENTER }, { x, y + h / 2 } )
- self.font:draw( { color = color, origin = LEFT_CENTER }, { x + 8 + sprite.size[2], y + h / 2 }, text )
-
- local box_color = mouse_over(xy, self.size) and COL_GOLD or color
- draw_rectangle_outline(box_color, bbox_create(xy, self.size), 1)
- end
-
- return toggle
-end
-
-local function respawn_toggle_create()
- local toggle = {
- size = SETTINGS_BOX_SIZE,
- font = SETTINGS_FONT,
- }
-
- local respawn = image_cached_load("res/interface/sprites/config/respawn_setting.png")
- local hardcore = image_cached_load("res/interface/sprites/config/hardcore_setting.png")
-
- function toggle:step(xy)
- -- Toggle the connection type
- if mouse_left_pressed and mouse_over(xy, self.size) then
- settings.regen_on_death = not settings.regen_on_death
- end
- end
-
- function toggle:draw(xy)
- local sprite = settings.regen_on_death and respawn or hardcore
-
- local x,y = unpack(xy)
- local w, h = unpack(self.size)
-
- local text = settings.regen_on_death and "Respawn on Death" or "Hardcore (No respawn!)"
- local text_color = settings.regen_on_death and COL_WHITE or COL_LIGHT_RED
- local sprite_color = settings.regen_on_death and COL_WHITE or COL_LIGHT_RED
- local box_color = sprite_color
-
- if mouse_over(xy, self.size) then
- box_color = COL_GOLD
- end
-
- sprite:draw( {origin = LEFT_CENTER, color = sprite_color}, { x, y + h / 2 } )
- self.font:draw( {origin = LEFT_CENTER, color = text_color}, { x + 8 + sprite.size[2], y + h / 2 }, text )
-
- draw_rectangle_outline(box_color, bbox_create(xy, self.size), 1)
- end
-
- return toggle
-end
-
-local function speed_toggle_create()
- local toggle = {
- size = SETTINGS_BOX_SIZE,
- font = SETTINGS_FONT,
- sprite = image_cached_load("res/interface/sprites/config/speed_setting.png")
- }
-
- function toggle:step(xy)
- -- Toggle the connection type
- if mouse_left_pressed and mouse_over(xy, self.size) then
- settings.time_per_step = settings.time_per_step - 2
- if settings.time_per_step < 10 then
- settings.time_per_step = 16
- end
- end
- end
-
- function toggle:draw(xy)
- local text = "Speed: Slow"
-
- if settings.time_per_step <= 10 then
- text = "Speed: Very Fast"
- elseif settings.time_per_step <= 12 then
- text = "Speed: Fast"
- elseif settings.time_per_step <= 14 then
- text = "Speed: Normal"
- end
-
- local alpha = 255 - (settings.time_per_step - 10) * 30
-
- local x,y = unpack(xy)
- local w, h = unpack(self.size)
-
- self.sprite:draw( { color = {255, 255, 255, alpha}, origin = LEFT_CENTER }, { x, y + h / 2 } )
- self.font:draw( {origin = LEFT_CENTER}, { x + 8 + self.sprite.size[2], y + h / 2 }, text )
-
- local box_color = mouse_over(xy, self.size) and COL_GOLD or COL_WHITE
- draw_rectangle_outline(box_color, bbox_create(xy, self.size), 1)
- end
-
- return toggle
-end
-
-local function label_button_create(params, color_formula, on_click)
- local sprite = Sprite.create(params.sprite, { color = COL_WHITE })
- local label = TextLabel.create(params.font, {}, params.text)
-
- local size = params.size
-
- local label_button = InstanceBox.create( params )
-
- label_button:add_instance( sprite, CENTER_TOP )
- label_button:add_instance( label, CENTER_BOTTOM )
-
- function label_button:step(xy) -- Makeshift inheritance
- InstanceBox.step(self, xy)
-
- if self:mouse_over(xy) and mouse_left_pressed then
- on_click(self, xy)
- end
-
- local color = color_formula(self, xy)
- sprite.options.color = color
- label.options.color = color
- end
-
- return label_button
-end
-
-local function class_choice_buttons_create()
- local sprite_base = "res/interface/sprites/class_icons/"
- local x_padding, y_padding = 32, 16
- local font = BIG_SETTINGS_FONT
-
- local buttons = {
- { "Mage", sprite_base .. "wizard.png"},
- { "Fighter", sprite_base .. "fighter.png"},
- { "Archer", sprite_base .. "archer.png"}
- }
-
- local button_size = { 96, 96 + y_padding + font.height }
- local button_row = InstanceLine.create( { dx = button_size[1] + x_padding } )
-
- function button_row:step(xy)
- InstanceLine.step(self, xy)
-
- -- Allow choosing a class by using left/right arrows or tab
- if key_pressed(keys.LEFT) then
- settings.class_type = ( settings.class_type - 1 ) % #buttons
- elseif key_pressed(keys.RIGHT) or key_pressed(keys.TAB) then
- settings.class_type = ( settings.class_type + 1 ) % #buttons
- end
- end
-
- for i = 1, #buttons do
- local button = buttons[i]
-
- button_row:add_instance(
- label_button_create(
- { size = button_size,
- font = font,
- text = button[1],
- sprite = image_cached_load(button[2])
- },
- function(self, xy) -- color_formula
- if settings.class_type == i-1 then
- return COL_GOLD
- else
- return self:mouse_over(xy) and COL_PALE_YELLOW or COL_WHITE
- end
- end,
- function(self, xy) -- on_click
- settings.class_type = i-1
- end
- )
- )
-
- end
-
- return button_row
-end
-
-local function center_setting_fields_create()
- local fields = InstanceLine.create( {force_size = {500, 162}, dx = 320, dy = 64, per_row = 2} )
- local current_setting
-
- local function add_fields()
- current_setting = settings.connection_type
-
- fields:clear()
-
- fields:add_instance( connection_toggle_create() )
-
- if current_setting == net.NONE then
- fields:add_instance( respawn_toggle_create() )
- end
-
- fields:add_instance( speed_toggle_create() )
- fields:add_instance( name_field_create() )
-
- if current_setting == net.CLIENT then
- fields:add_instance( host_IP_field_create() )
- end
-
- if current_setting ~= net.NONE then
- fields:add_instance( connection_port_field_create() )
- end
-
- end
-
- add_fields() -- Do initial creation
-
- function fields:step(xy) -- Makeshift inheritance
- InstanceLine.step(self, xy)
- if current_setting ~= settings.connection_type then
- add_fields()
- end
- end
-
- return fields
-end
-
-local function choose_class_message_create()
- local label = TextLabel.create(SETTINGS_FONT, {}, "Choose your Class!")
-
- function label:step(xy) -- Makeshift inheritance
- TextLabel.step(self, xy)
- self:set_color()
- end
-
- function label:set_color()
- self.options.color = settings.class_type == -1 and COL_PALE_RED or COL_INVISIBLE
- end
-
- label:set_color() -- Ensure correct starting color
-
- return label
-end
-
-local function back_and_continue_options_create(on_back_click, on_start_click)
- local font = BIG_SETTINGS_FONT
- local options = InstanceLine.create( { dx = 200 } )
-
- -- associate each label with a handler
- -- we make use of the ability to have objects as keys
- local components = {
- [ TextLabel.create(BIG_SETTINGS_FONT, "Back") ] = on_back_click or do_nothing ,
- [ TextLabel.create(BIG_SETTINGS_FONT, "Start") ] = on_start_click or do_nothing
- }
-
- for obj, handler in pairs(components) do
- options:add_instance(obj)
- end
-
- function options:step(xy) -- Makeshift inheritance
- InstanceLine.step(self, xy)
- for obj, obj_xy in self:instances(xy) do
- local click_handler = components[obj]
-
- local mouse_is_over = obj:mouse_over(obj_xy)
- obj.options.color = mouse_is_over and COL_GOLD or COL_WHITE
-
- if mouse_is_over and mouse_left_pressed then click_handler() end
- end
- end
-
- return options
-end
-
-function game_settings_menu_create(on_back_click, on_start_click)
- local fields = InstanceBox.create( {size = { 640, 480 } } )
-
- fields:add_instance(
- class_choice_buttons_create(),
- CENTER_TOP, --[[Down 50 pixels]] { 0, 50 } )
-
- fields:add_instance(
- center_setting_fields_create(),
- {0.50, 0.70} )
-
- fields:add_instance(
- back_and_continue_options_create(on_back_click, on_start_click),
- CENTER_BOTTOM, --[[Up 20 pixels]] { 0, -20 } )
-
- fields:add_instance(
- choose_class_message_create(),
- CENTER_BOTTOM, --[[Up 50 pixels]] { 0, -50 } )
-
- return fields
-end
View
1  src/lanarts/CMakeLists.txt
@@ -11,7 +11,6 @@ include(FindFreetype)
set( SRC ..)
set( LIBS ../../libs)
-
include_directories(
${SDL_INCLUDE_DIR}
${SDLIMAGE_INCLUDE_DIR}
View
5 src/lanarts/src/gamestate/GameSettings.h
@@ -60,7 +60,7 @@ struct GameSettings {
view_width = 960;
view_height = 720;
steps_per_draw = 1;
- time_per_step = 12;
+ time_per_step = 14;
frame_action_repeat = 0;
free_memory_while_idle = false;
@@ -70,7 +70,8 @@ struct GameSettings {
invincible = false;
draw_diagnostics = false;
- port = 0;
+ ip = "localhost";
+ port = 6112;
conntype = NONE;
network_debug_mode = false;
verbose_output = false;
View
70 src/lanarts/src/lua_api/LuaValueContext.cpp
@@ -0,0 +1,70 @@
+/*
+ * LuaValueContext.cpp:
+ * A LuaValue along with the context of how it was computed.
+ * Useful for decoding object tables as C++ objects.
+ */
+
+#include <lcommon/strformat.h>
+
+#include "LuaValueContext.h"
+
+LuaValueContext::LuaValueContext(const LuaValue& root, const char* fmt) :
+ _child(root),
+ _parent(NULL),
+ _integer_idx(-1),
+ _string_idx(NULL),
+ _fmt(fmt) {
+ if (!_fmt) {
+ _fmt = "Non-existent member 'object%s'\n";
+ }
+}
+
+LuaValueContext::LuaValueContext(const LuaValueContext* parent,
+ const char* string_idx, const char* fmt) :
+ _child(parent->value()[string_idx]),
+ _parent(parent),
+ _integer_idx(-1),
+ _string_idx(string_idx),
+ _fmt(fmt) {
+ if (_child.isnil()) {
+ throw_index_error();
+ }
+}
+
+LuaValueContext::LuaValueContext(const LuaValueContext* parent, int integer_idx,
+ const char* fmt) :
+ _child(parent->value()[integer_idx]),
+ _parent(parent),
+ _integer_idx(integer_idx),
+ _string_idx(NULL),
+ _fmt(fmt) {
+ if (_child.isnil()) {
+ throw_index_error();
+ }
+}
+
+LuaValueContext LuaValueContext::operator [](const char* string_idx) const {
+ return LuaValueContext(this, string_idx, _fmt);
+}
+
+LuaValueContext LuaValueContext::operator [](int integer_idx) const {
+ return LuaValueContext(this, integer_idx, _fmt);
+}
+
+void LuaValueContext::trace_object_path(std::string& object_path) const {
+ if (_parent) {
+ _parent->trace_object_path(object_path);
+ if (_string_idx != NULL) {
+ object_path += format("[\"%s\"]", _string_idx);
+ } else {
+ object_path += format("[%d]", _integer_idx);
+ }
+ }
+}
+
+void LuaValueContext::throw_index_error() const {
+ std::string object_path;
+ trace_object_path(object_path);
+
+ throw LuaValueContextIndexError(format(_fmt, object_path.c_str()));
+}
View
68 src/lanarts/src/lua_api/LuaValueContext.h
@@ -0,0 +1,68 @@
+/*
+ * LuaValueContext.h:
+ * A LuaValue along with the context of how it was computed.
+ * Meant to be used -only- as stack values!
+ * Useful for decoding object tables as C++ objects.
+ */
+
+#ifndef LUAVALUECONTEXT_H_
+#define LUAVALUECONTEXT_H_
+
+#include <stdexcept>
+#include <string>
+
+#include <luawrap/LuaValue.h>
+
+/* Thrown when an invalid index is passed */
+class LuaValueContextIndexError: public std::runtime_error {
+public:
+ LuaValueContextIndexError(const std::string& msg) :
+ runtime_error(msg) {
+ }
+};
+
+class LuaValueContext {
+public:
+ /* Construct the context root */
+ LuaValueContext(const LuaValue& root, const char* fmt = NULL);
+
+ /* These can throw an error message. */
+ LuaValueContext(const LuaValueContext* parent, const char* string_idx,
+ const char* fmt);
+ LuaValueContext(const LuaValueContext* parent, int integer_idx,
+ const char* fmt);
+
+ /* syntax sugar is important for data parsing */
+ const LuaValue* operator->() const {
+ return &_child;
+ }
+ const LuaValue& operator*() const {
+ return _child;
+ }
+ const LuaValue& value() const {
+ return _child;
+ }
+ bool has(const char* string_idx) const {
+ return !_child[string_idx].isnil();
+ }
+ template <typename T>
+ T defaulted(const char* string_idx, const T& default_value) const {
+ return _child[string_idx].defaulted(default_value);
+ }
+ LuaValueContext operator[](const char* string_idx) const;
+ LuaValueContext operator[](int integer_idx) const;
+private:
+ void trace_object_path(std::string& object_path) const;
+ void throw_index_error() const;
+
+ const LuaValue _child;
+ const LuaValueContext* _parent;
+
+ int _integer_idx;
+
+ const char* _string_idx;
+
+ const char* _fmt;
+};
+
+#endif /* LUAVALUECONTEXT_H_ */
View
21 src/lanarts/src/lua_api/lua_io.cpp
@@ -124,6 +124,18 @@ static int lua_newtextinput(lua_State* L) {
return 1;
}
+static std::string textfield_get_text(const LuaStackValue& obj, const LuaStackValue& key) {
+ return obj.as<TextField>().text();
+}
+
+static void textfield_set_text(const LuaStackValue& obj, const LuaStackValue& key, const std::string& val) {
+ obj.as<TextField>().set_text(val);
+}
+
+static int textfield_get_max_length(const LuaStackValue& obj, const LuaStackValue& key) {
+ return obj.as<TextField>().max_length();
+}
+
LuaValue lua_textfieldmetatable(lua_State* L) {
LuaValue meta = luameta_new(L, "TextInput");
@@ -131,13 +143,10 @@ LuaValue lua_textfieldmetatable(lua_State* L) {
LuaValue getters = luameta_getters(meta);
LuaValue setters = luameta_setters(meta);
- getters["text"] = &luawrap::getter<TextField, const std::string&,
- &TextField::text>;
- getters["max_length"] = &luawrap::getter<TextField, int,
- &TextField::max_length>;
- setters["text"] = &luawrap::setter<TextField, const std::string&,
- &TextField::set_text>;
+ getters["text"].bind_function(textfield_get_text);
+ setters["text"].bind_function(textfield_set_text);
+ getters["max_length"].bind_function(textfield_get_max_length);
methods["step"].bind_function(textfield_step);
methods["event_handle"].bind_function(textfield_handle_event);
methods["clear"].bind_function(textfield_clear);
View
9 src/lanarts/src/main.cpp
@@ -43,7 +43,7 @@ static GameState* init_gamestate() {
fatal_error("Fatal error: settings.yaml not found, the game is probably being loaded from the wrong place.\n");
}
- load_settings_data(settings, "saved_settings.yaml"); // Override with remembered settings
+ load_settings_data(settings, "res/saved_settings.yaml"); // Override with remembered settings
if (SDL_Init(0) < 0) {
exit(0);
@@ -83,7 +83,7 @@ int main(int argc, char** argv) {
engine["menu_start"].push();
bool did_exit = !luawrap::call<bool>(L);
- save_settings_data(gs->game_settings(), "saved_settings.yaml"); // Save settings from menu
+ save_settings_data(gs->game_settings(), "res/saved_settings.yaml"); // Save settings from menu
if (did_exit) goto label_Quit; /* User has quit! */
gs->start_connection();
@@ -103,13 +103,16 @@ int main(int argc, char** argv) {
luawrap::call<void>(L);
if (!gs->io_controller().user_has_exit()) {
+ if (gs->game_settings().conntype != GameSettings::CLIENT) {
+ save_settings_data(gs->game_settings(), "res/saved_settings.yaml"); // Save settings from in-game
+ }
delete gs;
goto label_StartOver;
}
}
if (gs->game_settings().conntype != GameSettings::CLIENT) {
- save_settings_data(gs->game_settings(), "saved_settings.yaml"); // Save settings from in-game
+ save_settings_data(gs->game_settings(), "res/saved_settings.yaml"); // Save settings from in-game
}
label_Quit:
View
108 src/lanarts/src/stats/ClassEntry.cpp
@@ -6,6 +6,10 @@
#include <lua.hpp>
#include <luawrap/luawrap.h>
+#include "lua_api/LuaValueContext.h"
+
+#include <lcommon/strformat.h>
+
#include "data/game_data.h"
#include "stats/stat_formulas.h"
#include "ClassEntry.h"
@@ -18,106 +22,107 @@ const char* ClassEntry::entry_type() {
return "ClassEntry";
}
-static Item parse_as_item(const LuaValue& value, const char* key = "item") {
- return Item(get_item_by_name(value[key].as<const char*>()),
- value["amount"].defaulted(1));
+static Item parse_as_item(const LuaValueContext& value,
+ const char* key = "item") {
+ return Item(get_item_by_name(value[key]->as<const char*>()),
+ value.defaulted("amount", 1));
}
-static Inventory parse_inventory(const LuaValue& value) {
+static Inventory parse_inventory(const LuaValueContext& value) {
Inventory ret;
- int len = value.objlen();
+ int len = value->objlen();
for (int i = 1; i <= len; i++) {
ret.add(parse_as_item(value[i]));
}
return ret;
}
-static EquipmentStats parse_equipment(const LuaValue& value) {
+static EquipmentStats parse_equipment(const LuaValueContext& value) {
EquipmentStats ret;
- if (!value["inventory"].isnil()) {
+ if (value.has("inventory")) {
ret.inventory = parse_inventory(value["inventory"]);
}
- if (!value["weapon"].isnil()) {
+ if (value.has("weapon")) {
Item item = parse_as_item(value, "weapon");
ret.inventory.add(item, true);
}
- if (!value["projectile"].isnil()) {
+ if (value.has("projectile")) {
Item item = parse_as_item(value["projectile"]);
ret.inventory.add(item, true);
}
return ret;
}
-static CoreStats parse_core_stats(const LuaValue& value) {
+static CoreStats parse_core_stats(const LuaValueContext& value) {
CoreStats core;
- core.max_mp = value["mp"].defaulted(0);
- core.max_hp = value["hp"].defaulted(0);
+ core.max_mp = value.defaulted("mp", 0);
+ core.max_hp = value.defaulted("hp", 0);
core.hp = core.max_hp;
core.mp = core.max_mp;
- core.hpregen = value["mpregen"].defaulted(0.0f);
- core.mpregen = value["hpregen"].defaulted(0.0f);
+ core.hpregen = value.defaulted("mpregen", 0.0f);
+ core.mpregen = value.defaulted("hpregen", 0.0f);
- core.strength = value["strength"].defaulted(0);
- core.defence = value["defence"].defaulted(0);
+ core.strength = value.defaulted("strength", 0);
+ core.defence = value.defaulted("defence", 0);
- core.magic = value["magic"].defaulted(0);
- core.willpower = value["willpower"].defaulted(0);
+ core.magic = value.defaulted("magic", 0);
+ core.willpower = value.defaulted("willpower", 0);
return core;
}
-static AttackStats parse_attack_stats(const LuaValue& value) {
+static AttackStats parse_attack_stats(const LuaValueContext& value) {
AttackStats ret;
- if (!value["weapon"].isnil()) {
+ if (value.has("weapon")) {
ret.weapon = Weapon(
- get_weapon_by_name(value["weapon"].as<const char*>()));
+ get_weapon_by_name(value["weapon"]->as<const char*>()));
}
- if (!value["projectile"].isnil()) {
+ if (value.has("projectile")) {
ret.projectile = Projectile(
- get_projectile_by_name(value["projectile"].as<const char*>()));
+ get_projectile_by_name(value["projectile"]->as<const char*>()));
}
return ret;
}
-static CombatStats parse_combat_stats(const LuaValue& value) {
+static CombatStats parse_combat_stats(const LuaValueContext& value) {
CombatStats ret;
- ret.movespeed = value["movespeed"];
- if (!value["equipment"].isnil()) {
+ ret.movespeed = value["movespeed"]->as<float>();
+ if (value.has("equipment")) {
ret.equipment = parse_equipment(value["equipment"]);
}
ret.core = parse_core_stats(value);
- ret.class_stats.xpneeded = value["xpneeded"].defaulted(
+ ret.class_stats.xpneeded = value.defaulted("xpneeded",
experience_needed_formula(1));
- ret.class_stats.xplevel = value["xplevel"].defaulted(1);
+ ret.class_stats.xplevel = value.defaulted("xplevel", 1);
- if (!value["attacks"].isnil()) {
+ if (value.has("attacks")) {
ret.attacks.push_back(parse_attack_stats(value));
}
return ret;
}
-static ClassSpell parse_class_spell(const LuaValue& value) {
+static ClassSpell parse_class_spell(const LuaValueContext& value) {
ClassSpell spell;
- spell.spell = get_spell_by_name(value["spell"].as<const char*>());
- spell.xplevel_required = value["level_needed"];
+ spell.spell = get_spell_by_name(value["spell"]->as<const char*>());
+ spell.xplevel_required = value["level_needed"]->as<int>();
return spell;
}
static ClassSpellProgression parse_class_spell_progression(
- const LuaValue& value) {
+ const LuaValueContext& value) {
ClassSpellProgression progression;
- int valuelen = value.objlen();
+ int valuelen = value->objlen();
for (int i = 1; i <= valuelen; i++) {
progression.available_spells.push_back(parse_class_spell(value[i]));
}
@@ -125,32 +130,37 @@ static ClassSpellProgression parse_class_spell_progression(
return progression;
}
-static void parse_gain_per_level(ClassEntry& entry, const LuaValue& value) {
- entry.hp_perlevel = value["hp"].defaulted(0);
- entry.mp_perlevel = value["mp"].defaulted(0);
+static void parse_gain_per_level(ClassEntry& entry,
+ const LuaValueContext& value) {
+ entry.hp_perlevel = value.defaulted("hp", 0);
+ entry.mp_perlevel = value.defaulted("mp", 0);
- entry.str_perlevel = value["strength"].defaulted(0);
- entry.def_perlevel = value["defence"].defaulted(0);
- entry.mag_perlevel = value["magic"].defaulted(0);
- entry.will_perlevel = value["willpower"].defaulted(0);
+ entry.str_perlevel = value.defaulted("strength", 0);
+ entry.def_perlevel = value.defaulted("defence", 0);
+ entry.mag_perlevel = value.defaulted("magic", 0);
+ entry.will_perlevel = value.defaulted("willpower", 0);
- entry.mpregen_perlevel = value["mpregen"].defaulted(0.0f);
- entry.hpregen_perlevel = value["hpregen"].defaulted(0.0f);
+ entry.mpregen_perlevel = value.defaulted("mpregen", 0.0f);
+ entry.hpregen_perlevel = value.defaulted("hpregen", 0.0f);
}
void ClassEntry::parse_lua_table(const LuaValue& table) {
ResourceEntryBase::parse_lua_table(table);
- parse_gain_per_level(*this, table["gain_per_level"]);
+ std::string fmt = format("Error while creating ClassEntry: "
+ "expected %s%%s field, but did not exist!\n", name.c_str());
+ LuaValueContext value(table, fmt.c_str());
+
+ parse_gain_per_level(*this, value["gain_per_level"]);
spell_progression = parse_class_spell_progression(
- table["available_spells"]);
- starting_stats = parse_combat_stats(table["start_stats"]);
+ value["available_spells"]);
+ starting_stats = parse_combat_stats(value["start_stats"]);
- LuaValue sprites = table["sprites"];
- int sprite_len = sprites.objlen();
+ LuaValueContext sprites = value["sprites"];
+ int sprite_len = sprites->objlen();
for (int i = 1; i <= sprite_len; i++) {
- this->sprites.push_back(res::spriteid(sprites[i].as<const char*>()));
+ this->sprites.push_back(res::spriteid(sprites[i]->as<const char*>()));
}
}
namespace res {
View
24 src/lanarts/tests/LuaValueContext_tests.cpp
@@ -0,0 +1,24 @@
+#include <lcommon/unittest.h>
+#include <luawrap/luawrap.h>
+
+#include "lua_api/LuaValueContext.h"
+
+SUITE(LuaValueContext_tests) {
+ TEST(test_index_error_message) {
+ TestLuaState L;
+ luawrap::dostring(L, "table = { a = { b = { } } }");
+
+ LuaValue value = luawrap::globals(L)["table"];
+ LuaValueContext context(value);
+ try {
+ context["a"];
+ context["a"]["b"];
+ context["a"]["b"]["c"];
+ } catch (const LuaValueContextIndexError& lvcie) {
+ std::string error = lvcie.what();
+ CHECK( error.find("[\"a\"][\"b\"][\"c\"]") != std::string::npos );
+ }
+
+ L.finish_check();
+ }
+}
View
3  src/luawrap/include/luawrap/LuaValue.h
@@ -54,8 +54,8 @@ namespace _luawrap_private {
template<typename T>
T as();
- template<typename T> operator T();
operator LuaValue();
+ template<typename T> operator T();
// get if not nil
template<typename T>
@@ -96,6 +96,7 @@ class LuaValue {
LuaValue(lua_State* L, const char* global);
LuaValue(lua_State* L, int pos);
LuaValue(const LuaStackValue& svalue);
+ LuaValue(const _luawrap_private::_LuaField& field);
LuaValue(lua_State* L);
LuaValue(const LuaValue& value);
View
6 src/luawrap/src/LuaValue.cpp
@@ -328,6 +328,12 @@ LuaValue LuaValue::operator [](int idx) const {
return ret;
}
+LuaValue::LuaValue(const _luawrap_private::_LuaField& field) {
+ impl = new _LuaValueImpl(field.value.luastate());
+ field.push();
+ pop();
+}
+
LuaValue LuaValue::pop_value(lua_State* L) {
luawrap::_private::PopHack delayedpop(L);
return LuaValue(L, -1);
Please sign in to comment.
Something went wrong with that request. Please try again.