{* UltraStar Deluxe - Karaoke Game * * UltraStar Deluxe is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * 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; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * $URL$ * $Id$ *} unit ULuaParty; interface {$IFDEF FPC} {$MODE Delphi} {$ENDIF} {$I switches.inc} uses ULua; { lua c functions from Party table. Enables creating of party modes w/ lua scripts } { Party.Register - register party mode at party manager arguments: info: table Name: String; //< Name used as identifier (language strings, etc.). Has to be set. CanNonParty: Boolean //< mode is playable when not in party mode. defaulted to false if not set CanParty: Boolean //< mode is playable in party mode. defaulted to false if not set PlayerCount: Table //< playable with one, two, three etc. players per team. defaulted to no restrictions if not set. (use table constructor e.g. {1, 2, 3) means playable w/ 1, 2 or three players) TeamCount: Table //< playable with one, two, three etc. different teams. defaulted to no restrictions if not set. (use table constructor e.g. {1, 2, 3) means playable w/ 1, 2 or three players) BeforeSongSelect: String //< name of global that will be called before song select screen is shown (if nil, not callable or returns true, default action will be executed) AfterSongSelect: String //< name of global that will be called after song is selected (if nil, not callable or returns true, default action will be executed) BeforeSing: String //< name of global that will be called before song select screen is shown (if nil, not callable or returns true, default action will be executed) OnSing: String //< name of global that will be called before song select screen is shown (if nil, not callable or returns true, default action will be executed) AfterSing: String //< name of global that will be called before song select screen is shown (if nil, not callable or returns true, default action will be executed)} function ULuaParty_Register(L: Plua_State): Integer; cdecl; { Party.GameFinished - returns true if no party game is running or all rounds of current game were played } function ULuaParty_GameFinished(L: Plua_State): Integer; cdecl; (* Party.SetRoundRanking - sets ranking of current party round, arguments: Ranking: table ranking of team i is the value (integer from 1 to number of teams) of the table with index [i: number]. you may call this function in the following way: Party.SetRoundRanking({3, 1, 2}); this means: team 1 is ranked third, team 2 is ranked first and team 3 is ranked second. if no party game is started or party game is finished it will raise an error *) function ULuaParty_SetRoundRanking(L: Plua_State): Integer; cdecl; { Party.GetTeams - returns a table with all information and structure as in the TPartyGame.Teams array } function ULuaParty_GetTeams(L: Plua_State): Integer; cdecl; { Party.SetTeams - changes all fields from TPartyGame.Teams that have been set in the table given as first argument} function ULuaParty_SetTeams(L: Plua_State): Integer; cdecl; const ULuaParty_Lib_f: array [0..4] of lual_reg = ( (name:'Register'; func:ULuaParty_Register), (name:'GameFinished'; func:ULuaParty_GameFinished), (name:'SetRoundRanking'; func:ULuaParty_SetRoundRanking), (name:'GetTeams'; func:ULuaParty_GetTeams), (name:'SetTeams'; func:ULuaParty_SetTeams) ); implementation uses ULuaCore, ULuaUtils, UParty, SysUtils; { Party.Register - register party mode at party manager arguments: info: table Name: String; //< Name used as identifier (language strings, etc.). Has to be set. CanNonParty: Boolean //< mode is playable when not in party mode. defaulted to false if not set CanParty: Boolean //< mode is playable in party mode. defaulted to false if not set PlayerCount: Table //< playable with one, two, three etc. players per team. defaulted to no restrictions if not set. (use table constructor e.g. {1, 2, 3) means playable w/ 1, 2 or three players) TeamCount: Table //< playable with one, two, three etc. different teams. defaulted to no restrictions if not set. (use table constructor e.g. {1, 2, 3) means playable w/ 1, 2 or three players) BeforeSongSelect: String //< name of global that will be called before song select screen is shown (if nil, not callable or returns true, default action will be executed) AfterSongSelect: String //< name of global that will be called after song is selected (if nil, not callable or returns true, default action will be executed) BeforeSing: String //< name of global that will be called before song select screen is shown (if nil, not callable or returns true, default action will be executed) OnSing: String //< name of global that will be called before song select screen is shown (if nil, not callable or returns true, default action will be executed) AfterSing: String //< name of global that will be called before song select screen is shown (if nil, not callable or returns true, default action will be executed)} function ULuaParty_Register(L: Plua_State): Integer; cdecl; var Info: TParty_ModeInfo; Key: String; P: TLuaPlugin; begin Result := 0; // check for table on stack luaL_checkType(L, 1, LUA_TTABLE); // get parent id P := Lua_GetOwner(L); // set mode info to default Party.DefaultModeInfo(Info); // set parent in info rec and pop it from stack Info.Parent := P.Id; // go through table elements lua_pushNil(L); while (lua_Next(L, 1) <> 0) do begin Key := lowercase(lua_ToString(L, -2)); if (Key = 'name') and lua_isString(L, -1) then Info.Name := lua_toString(L, -1) else if (Key = 'cannonparty') and lua_isBoolean(L, -1) then Info.CanNonParty := lua_toBoolean(L, -1) else if (Key = 'canparty') and lua_isBoolean(L, -1) then Info.CanParty := lua_toBoolean(L, -1) else if (Key = 'playercount') and lua_isTable(L, -1) then Info.PlayerCount := lua_toBinInt(L, -1) else if (Key = 'teamcount') and lua_isTable(L, -1) then Info.TeamCount := lua_toBinInt(L, -1) else if (Key = 'beforesongselect') and lua_isString(L, -1) then Info.Functions.BeforeSongSelect := lua_toString(L, -1) else if (Key = 'aftersongselect') and lua_isString(L, -1) then Info.Functions.AfterSongSelect := lua_toString(L, -1) else if (Key = 'beforesing') and lua_isString(L, -1) then Info.Functions.BeforeSing := lua_toString(L, -1) else if (Key = 'onsing') and lua_isString(L, -1) then Info.Functions.OnSing := lua_toString(L, -1) else if (Key = 'aftersing') and lua_isString(L, -1) then Info.Functions.AfterSing := lua_toString(L, -1); // pop value from stack so key is on top lua_pop(L, 1); end; // clear stack from table lua_pop(L, lua_gettop(L)); if not Party.RegisterMode(Info) then luaL_error(L, PChar('can''t register party mode at party manager in Party.Register. Is Info.Name defined or is there another mode with this name?')); end; { Party.GameFinished - returns true if no party game is running or all rounds of current game were played } function ULuaParty_GameFinished(L: Plua_State): Integer; cdecl; begin // clear stack lua_pop(L, lua_gettop(L)); // push result lua_pushBoolean(L, Party.GameFinished); //we return one value Result := 1; end; { Party.SetRoundRanking - sets ranking of current party round, if no party game is started or party game is finished it will raise an error } function ULuaParty_SetRoundRanking(L: Plua_State): Integer; cdecl; var R: AParty_TeamRanking; I: Integer; Rank: Integer; begin Result := 0; luaL_checktype(L, 1, LUA_TTABLE); lua_checkstack(L, 1); SetLength(R, Length(Party.Teams)); for I := 0 to High(R) do begin lua_pushInteger(L, (I+1)); lua_gettable(L, 1); R[I].Rank := Length(R); R[I].Team := I; if (lua_isnumber(L, -1)) then begin Rank := lua_toInteger(L, -1); if (Rank >= 1) and (Rank <= Length(R)) then R[I].Rank := Rank end; lua_pop(L, 1); end; // pop table lua_pop(L, 1); if (not Party.SetRanking(R)) then luaL_error(L, PChar('cann''t set party round ranking. Is party started and not finished yet?')); end; { Party.GetTeams - returns a table with all information and structure as in the TPartyGame.Teams array } function ULuaParty_GetTeams(L: Plua_State): Integer; cdecl; var Team: Integer; Player: Integer; begin // clear stack lua_pop(L, lua_gettop(L)); // ensure we have enough stack slots left lua_checkstack(L, 7); // create the table we want to return lua_createtable(L, Length(Party.Teams), 0); // add the teams for Team := 0 to High(Party.Teams) do begin // push key for current teams value. lua array beggins at 1 lua_pushInteger(L, Team + 1); // push table containing team info and players table lua_createtable(L, 0, 5); // team name lua_pushString(L, PChar(Party.Teams[Team].Name)); lua_setField(L, -2, 'Name'); // team score lua_pushInteger(L, Party.Teams[Team].Score); lua_setField(L, -2, 'Score'); // team jokers left lua_pushInteger(L, Party.Teams[Team].JokersLeft); lua_setField(L, -2, 'JokersLeft'); // team nextPlayer lua_pushInteger(L, Party.Teams[Team].NextPlayer); lua_setField(L, -2, 'NextPlayer'); // team players table lua_createtable(L, Length(Party.Teams[Team].Players), 0); //add players for Player := 0 to High(Party.Teams[Team].Players) do begin // push key for current players value. lua array beggins at 1 lua_pushInteger(L, Player + 1); // push table containing player info lua_createTable(L, 0, 2); // player name lua_PushString(L, PChar(Party.Teams[Team].Players[Player].Name)); lua_SetField(L, -2, 'Name'); // players times played lua_PushInteger(L, Party.Teams[Team].Players[Player].TimesPlayed); lua_SetField(L, -2, 'TimesPlayed'); // add value - key - pair to teams player table lua_setTable(L, -3); end; lua_setField(L, -2, 'Players'); // add value - key - pair to returned table lua_setTable(L, -3); end; // we return 1 value (the first table) Result := 1; end; { Party.SetTeams - changes all fields from TPartyGame.Teams that have been set in the table given as first argument} function ULuaParty_SetTeams(L: Plua_State): Integer; cdecl; procedure Do_Player(Team, Player: Integer); var Key: String; begin if (Player >= 0) and (Player <= High(Party.Teams[Team].Players)) then begin // go through table elements lua_pushNil(L); while (lua_Next(L, -2) <> 0) do begin Key := lowercase(lua_ToString(L, -2)); if (Key = 'name') and lua_isString(L, -1) then Party.Teams[Team].Players[Player].Name := lua_toString(L, -1) else if (Key = 'timesplayed') and lua_isNumber(L, -1) then Party.Teams[Team].Players[Player].TimesPlayed := lua_toInteger(L, -1); // pop value from stack so key is on top lua_pop(L, 1); end; end; end; procedure Do_Players(Team: Integer); begin // go through table elements lua_pushNil(L); while (lua_Next(L, -2) <> 0) do begin // check if key is a number and value is a table if (lua_isNumber(L, -2)) and (lua_isTable(L, -1)) then Do_Player(Team, lua_toInteger(L, -2)); // pop value from stack so key is on top lua_pop(L, 1); end; end; procedure Do_Team(Team: Integer); var Key: String; begin if (Team >= 0) and (Team <= High(Party.Teams)) then begin // go through table elements lua_pushNil(L); while (lua_Next(L, -2) <> 0) do begin Key := lowercase(lua_ToString(L, -2)); if (Key = 'name') and lua_isString(L, -1) then Party.Teams[Team].Name := lua_toString(L, -1) else if (Key = 'score') and lua_isNumber(L, -1) then Party.Teams[Team].Score := lua_toInteger(L, -1) else if (Key = 'jokersleft') and lua_isNumber(L, -1) then Party.Teams[Team].JokersLeft := lua_toInteger(L, -1) else if (Key = 'currentplayer') and lua_isNumber(L, -1) then Party.Teams[Team].NextPlayer := lua_toInteger(L, -1) else if (Key = 'players') and lua_isTable(L, -1) then Do_Players(Team); // pop value from stack so key is on top lua_pop(L, 1); end; end; end; begin Result := 0; // check for table on stack luaL_checkType(L, 1, LUA_TTABLE); // go through table elements lua_pushNil(L); while (lua_Next(L, 1) <> 0) do begin // check if key is a number and value is a table if (lua_isNumber(L, -2)) and (lua_isTable(L, -1)) then Do_Team(lua_toInteger(L, -2)); // pop value from stack so key is on top lua_pop(L, 1); end; // clear stack from table lua_pop(L, lua_gettop(L)); end; end.