OK, cool. Let's start with a bit of background.
You can think of the current WM game as looking a bit like this:

The grey box is the C++ code, which we need to handle things like drawing pictures on the screen. The trouble is that C++ has a steep learning curve. There's a lot of stuff you have to get your head around before you can write "hello world", let alone understand how WM works.
The big problem though is that a lot of the game data, and almost all of the game logic, is embedded in the C++. That means that everyone is relying on the devs no only for changes to the display engine, but also for fairly simple changes to how the game works. (Actually this makes WM look worse than it really is - necno did a good job of moving a lot of data out to text files. But the game still assumes a lot about the format of those files...)
Anyway... the way I want CloneMaster to look is more like this:

Here we have the minimum data possible (where to look for the scripts and data files) in the C++ blob, and a lot of lua and XML files to control how the game works and what objects and characters appear in it.
That means you can leave the graphics engine stuff to the devs, but changing the game is open to anyone with a text editor. Of course, you still need to understand the game, and the script language.
The script language is
Lua. It's a lot simpler than C++, and is used for scripting in a lot of commercial gams. World of Warcraft is one. So there's a lot of tutorials out there., It's easy to learn.
As for understanding how the game works, that's something I want to explain in these posts. If nothing else, it means there'll be some documentation when I'm done with this
[edit]
Look at the start up. When you launch the program, the C++ part of the game looks in Resources/Script for a script called startup.lua. This is what it looks like:
-- most of the game data is bundled up an a module called "Game"
--
-- we'll need to include that
--
require "Game"
--
-- package.path tells the "require" function where to look for modules
-- the wm.log function writes to the game log
-- so this line logs the module search path as a debug aid
--
wm.log(package.path)
--
-- OK: we need to
-- * create the game object
-- * load all the window definitions
-- * set the background for the game window, and
-- * open the initial window
--
-- Start with the game object:
--
local game = Game:new()
--
-- now use the game object to load the windows
--
game:load_windows(
"GameMenu.xml",
"Intro.xml",
"Chapter.xml",
"Main.xml",
"Cloning.xml"
)
--
-- set the window background
--
game:set_background("background")
--
-- push the first screen onto the stack
--
wm.show("game_menu")
return game
It's worth going over that in a bit more detail. There are some key concepts here. If you know a bit of Lua you'll already know some of this, of course.
-- most of the game data is bundled up an a module called "Game"
--
-- we'll need to include that
--
require "Game"
First thing: two dashes together "--" in Lua mean a comment. Everything after them is ignored. You can also do multiline comments by starting with "--[[" and ending with "]]" but I don't use that so much.
The "require" function is a Lua builtin which loads a lua module. in this case the module is called Game. So this line tells lua to search for a module called "Game.lua" and to load it. The game module collects all the game data into one place, which is why we need to load it first thing.
--
-- package.path tells the "require" function where to look for modules
-- the wm.log function writes to the game log
-- so this line logs the module search path as a debug aid
--
wm.log(package.path)
wm.log means the function caleld "log" in the "wm" namespace. The "wm" stands for "whore master" and is the namespace for all the C++ support functions. We'll use these to display screens, show messages and generally talk to the C++ end of things.
The log function is probably the simplest one - it writes to the game log. Here I'm printing package.path which is the search path used by lua when searching for modules. Basically, it's just a debug thing.
--
-- OK: we need to
-- * create the game object
-- * load all the window definitions
-- * set the background for the game window, and
-- * open the initial window
--
-- Start with the game object:
--
local game = Game:new()
Right. As the comment says, this is where we create the Game object that collects the game data. By declaring the game variable with "local" we ensure that the variable is private to the file in which it is declared. This is a good idea, since it means that some other coder can't unwittingly use the same variable name somewhere else and change all your data when you're not expecting it.
Game:new() calls the consructor for the Game class. The colon in Game:new means that the Game object (everything can be considered to be an object) gets passed as the first parameter. So Game:new() is the same as Game.new(Game). That's not hugely important here, but it will be later. For now, just remember that the difference can be important.
Anyway ...
--
-- now use the game object to load the windows
--
game:load_windows(
"GameMenu.xml",
"Intro.xml",
"Chapter.xml",
"Main.xml",
"Cloning.xml"
)
This is a list of xml files defining screens in the game. "GameMenu" is the initial New/Load/Quit screen, Main is the equivalent of WM's brothel screen, cloning is the cloning lab screen, etc. The load_windows method looks for each of these in Resources/Interfaces and parses the XML to get screen definitions. The XML format is more or less the same as the one used in WhoreMaster. Once a window definition has been loaded like this, it can be displayed with the show function. Which we're about to do - but before that...
--
-- set the window background
--
game:set_background("background")
This sets the main window background. It looks for "background.jpg" in Resources/Images. Lastly ....
--
-- push the first screen onto the stack
--
wm.show("game_menu")
This displays the opening screen. Why "game_menu" rather than "GameMenu" or "GameMenu.xml"? Well, because the screen name in GameMenu.xml is defined as "game_menu". Which is possible not the most sensbile way to do it, now I think about it. wm.show is the show function in the wm namespace, which means that show() is another one of the functions written in C++ to talk to the game engine.
The other thing worth mentioning here is the idea of a screen stack. Essentially, you can have lots of screens displayed, all stacked one on top fo the other. So in WM you might have the Brothel screen open, with the town screen open on top of it (and hiding it) and then have the bank screen on top of that with the town screen still partly visible underneath. When you close the bank screen, you pop it off the stack, and the town screen becomes fully visible and active. So when I talk about pushing and popping the stack, that's what it means. The screen stack is part of the basic WM architecure, going back to necno's earliest released version.
So: that's talked about
- modules and how to require them
- the wm namespace and how it contains the C++ interface functions
- how to write to the log from a script
- The Game class
- how to load and display a screen
- how to set the window background
- and comments
Which is probably enough for one session. More later.