Skip to content

Commit

Permalink
Properly port [music] to Lua
Browse files Browse the repository at this point in the history
  • Loading branch information
CelticMinstrel committed Apr 24, 2017
1 parent 7cd638f commit 3793951
Show file tree
Hide file tree
Showing 15 changed files with 335 additions and 5 deletions.
13 changes: 13 additions & 0 deletions changelog
Expand Up @@ -20,6 +20,19 @@ Version 1.13.7+dev:
For example, wesnoth.scroll(5, -2)
* New is_local attribute in side proxy table allows you to detect whether or not the side is
controlled by a network player. Note that use of this has the potential for OOS errors.
* New wesnoth.music_list table which allows controlling the music playlist:
* wesnoth.music_list[1] etc returns mutable information about a specific track on the playlist
* #wesnoth.music_list counts the number of tracks on the playlist
* wesnoth.music_list.current returns mutable information about the currently-playing track
* wesnoth.music_list.current_i returns the index of the current track on the list
* wesnoth.music_list.play plays a specific track (as [music]play_once=yes)
* wesnoth.music_list.add appends a track to the playlist (as [music]append=yes)
* wesnoth.music_list.clear clears the current playlist
* wesnoth.music_list.force_refresh forces any pending playlist changes to be immediately applied
* Each track has modifiable shuffle, once, ms_before, ms_after attributes and
read-only append, immediate, name, title attributes. They are also
comparable with == or ~=
* wesnoth.set_music is now deprecated, in favour of the above new API
* Multiplayer:
* Fixed statistics being lost when reloading an MP game.
* Performance:
Expand Down
4 changes: 4 additions & 0 deletions data/lua/backwards-compatibility.lua
Expand Up @@ -4,6 +4,10 @@

local helper = wesnoth.require "lua/helper.lua"

function wesnoth.set_music(cfg)
wesnoth.wml_actions.music(cfg)
end

-- Calling wesnoth.fire isn't the same as calling wesnoth.wml_actions[name] due to the passed vconfig userdata
-- which also provides "constness" of the passed wml object from the point of view of the caller.
-- So please don't remove since it's not deprecated.
Expand Down
19 changes: 18 additions & 1 deletion data/lua/wml-tags.lua
Expand Up @@ -266,7 +266,24 @@ function wml_actions.lua(cfg)
end

function wml_actions.music(cfg)
wesnoth.set_music(cfg)
if cfg.play_once then
wesnoth.music_list.play(cfg.name)
else
if not cfg.append then
if cfg.immediate then
wesnoth.music_list.current.once = true
end
wesnoth.music_list.clear()
end
wesnoth.music_list.add(cfg.name, not not cfg.immediate, cfg.ms_before or 0, cfg.ms_after or 0)
local n = #wesnoth.music_list
if cfg.shuffle == false then
wesnoth.music_list[n].shuffle = false
end
if cfg.title ~= nil then
wesnoth.music_list[n].title = cfg.title
end
end
end

-- This is mainly for use in unit test macros, but maybe it can be useful elsewhere too
Expand Down
2 changes: 1 addition & 1 deletion data/lua/wml-utils.lua
Expand Up @@ -155,7 +155,7 @@ function utils.handle_event_commands(cfg, scope_type)
current_exit = "none"
end
-- Apply music alterations once all the commands have been processed.
wesnoth.set_music()
wesnoth.music_list.force_refresh()
return current_exit
end
Expand Down
7 changes: 7 additions & 0 deletions projectfiles/VC12/wesnoth.vcxproj
Expand Up @@ -2581,6 +2581,12 @@
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Scripting\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Scripting\</ObjectFileName>
</ClCompile>
<ClCompile Include="..\..\src\scripting\lua_audio.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Scripting\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Scripting\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Scripting\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Scripting\</ObjectFileName>
</ClCompile>
<ClCompile Include="..\..\src\scripting\lua_common.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Scripting\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Scripting\</ObjectFileName>
Expand Down Expand Up @@ -3864,6 +3870,7 @@
<ClInclude Include="..\..\src\scripting\application_lua_kernel.hpp" />
<ClInclude Include="..\..\src\scripting\debug_lua.hpp" />
<ClInclude Include="..\..\src\scripting\game_lua_kernel.hpp" />
<ClInclude Include="..\..\src\scripting\lua_audio.hpp" />
<ClInclude Include="..\..\src\scripting\lua_common.hpp" />
<ClInclude Include="..\..\src\scripting\lua_cpp_function.hpp" />
<ClInclude Include="..\..\src\scripting\lua_fileops.hpp" />
Expand Down
6 changes: 6 additions & 0 deletions projectfiles/VC12/wesnoth.vcxproj.filters
Expand Up @@ -1529,6 +1529,9 @@
<ClCompile Include="..\..\src\font\text_surface.cpp">
<Filter>Font</Filter>
</ClCompile>
<ClCompile Include="..\..\src\scripting\lua_audio.cpp">
<Filter>Scripting</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\addon\client.hpp">
Expand Down Expand Up @@ -2972,6 +2975,9 @@
<ClInclude Include="..\..\src\font\pango\stream_ops.hpp">
<Filter>Font\Pango</Filter>
</ClInclude>
<ClInclude Include="..\..\src\scripting\lua_audio.hpp">
<Filter>Scripting</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\tests\test_sdl_utils.hpp">
Expand Down
1 change: 1 addition & 0 deletions source_lists/wesnoth
Expand Up @@ -338,6 +338,7 @@ savegame.cpp
scripting/application_lua_kernel.cpp
scripting/debug_lua.cpp
scripting/game_lua_kernel.cpp
scripting/lua_audio.cpp
scripting/lua_common.cpp
scripting/lua_cpp_function.cpp
scripting/lua_fileops.cpp
Expand Down
1 change: 1 addition & 0 deletions src/playsingle_controller.cpp
Expand Up @@ -323,6 +323,7 @@ LEVEL_RESULT playsingle_controller::play_scenario(const config& level)
// instead should they want special music.
const std::string& end_music = select_music(is_victory);
if((!is_victory || end_level.transient.carryover_report) && !end_music.empty()) {
sound::empty_playlist();
sound::play_music_once(end_music);
}
persist_.end_transaction();
Expand Down
5 changes: 5 additions & 0 deletions src/scripting/game_lua_kernel.cpp
Expand Up @@ -70,6 +70,7 @@
#include "recall_list_manager.hpp" // for recall_list_manager
#include "replay.hpp" // for get_user_choice, etc
#include "reports.hpp" // for register_generator, etc
#include "scripting/lua_audio.hpp"
#include "scripting/lua_unit.hpp"
#include "scripting/lua_unit_attacks.hpp"
#include "scripting/lua_common.hpp"
Expand Down Expand Up @@ -2503,6 +2504,7 @@ int game_lua_kernel::intf_simulate_combat(lua_State *L)
*/
static int intf_set_music(lua_State *L)
{
lg::wml_error() << "set_music is deprecated; please use the wesnoth.playlist table instead!\n";
if (lua_isnoneornil(L, 1)) {
sound::commit_music_changes();
return 0;
Expand Down Expand Up @@ -4113,6 +4115,9 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports
lua_setfield(L, -2, "current");
lua_pop(L, 1);

// Create the playlist table with its metatable
cmd_log_ << lua_audio::register_table(L);

// Create the wml_actions table.
cmd_log_ << "Adding wml_actions table...\n";

Expand Down
217 changes: 217 additions & 0 deletions src/scripting/lua_audio.cpp
@@ -0,0 +1,217 @@
/*
Copyright (C) 2017 by the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/

#include "lua_audio.hpp"

#include "lua/lua.h"
#include "lua/lauxlib.h"
#include "scripting/lua_common.hpp"
#include "sound.hpp"
#include "sound_music_track.hpp"
#include "config_assign.hpp"

static const char* Track = "music track";

class music_track {
int i;
sound::music_track& track;
public:
explicit music_track(int i) : i(i), track(sound::get_track(i)) {}
bool valid() {
sound::music_track& current = sound::get_track(i);
return &track == &current && track.valid() && track.id() == current.id();
}
sound::music_track& operator*() {
return track;
}
sound::music_track* operator->() {
return &track;
}
int index() {
return i;
}
};

static music_track* push_track(lua_State* L, int i) {
music_track* trk = new(L) music_track(i);
luaL_setmetatable(L, Track);
return trk;
}

static music_track* get_track(lua_State* L, int i) {
return static_cast<music_track*>(luaL_checkudata(L, i, Track));
}

static int impl_music_get(lua_State* L) {
if(lua_isnumber(L, 2)) {
push_track(L, lua_tointeger(L, 2) - 1);
return 1;
}
const char* m = luaL_checkstring(L, 2);
if(strcmp(m, "current") == 0) {
push_track(L, sound::get_current_track());
return 1;
}
return_int_attrib("current_i", sound::get_current_track() + 1);
return luaW_getmetafield(L, 1, m);
}

static int impl_music_set(lua_State* L) {
if(lua_isnumber(L, 2)) {
music_track& track = *get_track(L, 3);
sound::set_track(lua_tointeger(L, 2), *track);
return 0;
}
// TODO: Set "current" and "current_i"
return 0;
}

static int impl_music_len(lua_State* L) {
lua_pushinteger(L, sound::get_num_tracks());
return 1;
}

static int intf_music_play(lua_State* L) {
sound::play_music_once(luaL_checkstring(L, 1));
return 0;
}

static int intf_music_add(lua_State* L) {
config cfg = config_of
("name", luaL_checkstring(L, 1))
("append", true);
bool found_ms_before = false, found_ms_after = false, found_imm = false;
for(int i = 2; i <= lua_gettop(L); i++) {
if(lua_isboolean(L, i)) {
if(found_imm) {
return luaL_argerror(L, i, "only one boolean argument may be passed");
} else {
cfg["immediate"] = luaW_toboolean(L, i);
}
} else if(lua_isnumber(L, i)) {
if(found_ms_after) {
return luaL_argerror(L, i, "only two integer arguments may be passed");
} else if(found_ms_before) {
cfg["ms_after"] = lua_tointeger(L, i);
found_ms_after = true;
} else {
cfg["ms_before"] = lua_tointeger(L, i);
found_ms_before = true;
}
} else {
return luaL_argerror(L, i, "unrecognized argument");
}
}
sound::play_music_config(cfg);
return 0;
}

static int intf_music_clear(lua_State*) {
sound::empty_playlist();
return 0;
}

static int intf_music_commit(lua_State*) {
sound::commit_music_changes();
return 0;
}

static int impl_track_get(lua_State* L) {
music_track& track = *get_track(L, 1);
const char* m = luaL_checkstring(L, 2);
return_bool_attrib("valid", track.valid());
if(!track.valid()) {
return luaL_error(L, "Tried to access member of track that is no longer valid.");
}
return_bool_attrib("append", track->append());
return_bool_attrib("shuffle", track->shuffle());
return_bool_attrib("immediate", track->immediate());
return_bool_attrib("once", track->play_once());
return_int_attrib("ms_before", track->ms_before());
return_int_attrib("ms_after", track->ms_after());
return_string_attrib("name", track->id());
return_string_attrib("title", track->title());
return luaW_getmetafield(L, 1, m);
}

static int impl_track_set(lua_State* L) {
music_track& track = *get_track(L, 1);
const char* m = luaL_checkstring(L, 2);
modify_bool_attrib("shuffle", track->set_shuffle(value));
modify_bool_attrib("once", track->set_play_once(value));
modify_int_attrib("ms_before", track->set_ms_before(value));
modify_int_attrib("ms_after", track->set_ms_after(value));
return 0;
}

static int impl_track_eq(lua_State* L) {
music_track* a = get_track(L, 1);
music_track* b = get_track(L, 2);
if(!a || !b) {
// This implies that one argument is not a music track, though I suspect this is dead code...?
// Does Lua ever call this if the arguments are not of the same type?
lua_pushboolean(L, false);
return 1;
}
if(!a->valid() && !b->valid()) {
lua_pushboolean(L, true);
return 1;
}
if(a->valid() && b->valid()) {
music_track& lhs = *a;
music_track& rhs = *b;
lua_pushboolean(L, lhs->id() == rhs->id() && lhs->shuffle() == rhs->shuffle() && lhs->play_once() == rhs->play_once() && lhs->ms_before() == rhs->ms_before() && lhs->ms_after() == rhs->ms_after());
return 1;
}
lua_pushboolean(L, false);
return 1;
}

namespace lua_audio {
std::string register_table(lua_State* L) {
// The music playlist metatable
lua_getglobal(L, "wesnoth");
lua_newuserdata(L, 0);
lua_createtable(L, 0, 4);
static luaL_Reg pl_callbacks[] = {
{ "__index", impl_music_get },
{ "__newindex", impl_music_set },
{ "__len", impl_music_len },
{ "play", intf_music_play },
{ "add", intf_music_add },
{ "clear", intf_music_clear },
{ "force_refresh", intf_music_commit },
{ nullptr, nullptr },
};
luaL_setfuncs(L, pl_callbacks, 0);
lua_pushstring(L, "music playlist");
lua_setfield(L, -2, "__metatable");
lua_setmetatable(L, -2);
lua_setfield(L, -2, "music_list");
lua_pop(L, 1);

// The music track metatable
luaL_newmetatable(L, Track);
static luaL_Reg track_callbacks[] = {
{ "__index", impl_track_get },
{ "__newindex", impl_track_set },
{ "__eq", impl_track_eq },
{ nullptr, nullptr },
};
luaL_setfuncs(L, track_callbacks, 0);
lua_pushstring(L, Track);
lua_setfield(L, -2, "__metatable");

return "Adding music playlist table...";
}
}
20 changes: 20 additions & 0 deletions src/scripting/lua_audio.hpp
@@ -0,0 +1,20 @@
/*
Copyright (C) 2017 by the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/

#include <string>

struct lua_State;

namespace lua_audio {
std::string register_table(lua_State*);
}
2 changes: 1 addition & 1 deletion src/scripting/lua_team.cpp
Expand Up @@ -207,7 +207,7 @@ namespace lua_team {
};
luaL_setfuncs(L, callbacks, 0);

lua_pushstring(L, "side");
lua_pushstring(L, Team);
lua_setfield(L, -2, "__metatable");
// Side methods
luaW_getglobal(L, "wesnoth", "match_side");
Expand Down

0 comments on commit 3793951

Please sign in to comment.