In-game scripting and what should be done

BlitzMax Forums/BlitzMax Programming/In-game scripting and what should be done

I'm currently giving my game the ability to read scripts
from a file during runtime, then execute them. This will be
used for cutscenes, etc. The script will activate events
which are hard-coded into the program. Events will tell a
character to go here or say this or kill that, etc. I have
almost completely fleshed out the system on paper, but
one question remains. How do I write these events into
the program?

Currently, the only system I can come up with is:

Repeat
	If event[1] = ACTIVE Then
		doSomething()
	EndIf
	If event[2] = ACTIVE Then
		doSomethingElse()
	EndIf
Forever

And Then have functions that correspond To them:

Function doSomething()
	make main character walk over there
EndFunction
	
Function doSomethingElse()
	turn the snow level And windspeed up
EndFunction


This is such a hack-job and I hate having to do it like this,
but I don't know how not to have events hard-coded.

Is this the sort of thing that Lua handles well? I'm
completely unfamiliar with it at the moment.

If you want a true scripting system then your options are LUA and the upcoming BVM v2.0

LUA already comes with BMAX. But BVM's binding functions are the greatest thing since sliced bread imo.

Have a look at LUA. It's fantastic. As soon as you've got a groundwork to build on you can do just about anything. There is one problem though. It's extremely hard to debug in bmx at the moment (at least for me anyway).

You bind your bmx functions to LUA so it can use them. You can also go the other way. For simplish things like the ones you've outlined above, LUA would be perfect fo you.

http://www.blitzbasic.com/Community/posts.php?topic=52524

Noel's the bloke to talk to about this.

Here's a quick example:
 ' ******************************* LUA CODE BELOW

' LUA doesn't have data types as such.

Rem

-- these are global to this scriptEngine

a_variable = 2
something = "hello there"
windPower = 0.4474



function update()
	local name = getPlayerName()
	
	print("We are updating - "..name)
end

EndRem


 ' ******************************* LUA CODE ABOVE



' example:

Strict

Global windSpeed#=0.004
Global playerName$="jeff"


Local a:LUAScript=New LUAScript
	a.init("example.lua")
	
	While KeyHit(KEY_ESCAPE)=0
		a.update()
	Wend
	
	a=Null
	
	End



 ' ******************************* BMX CODE BELOW

Type LUAScript
	Field se:ScriptEngine
	Field file$
	
	Method init(_file$)
		se=New ScriptEngine
		se.reset()
		file=_file		
		' run the main script
		If (Not se.RunScriptFile(file)) Then
			Print "Error: " + se.GetLastErrorString()
		EndIf		
	
		' now add our functions we want LUA to have access to.
		'				our function			LUA uses		params?		returns
		se.AddFunction(LUA_setWindLevel, 	"setWindLevel") '	[ wind# ]
		se.AddFunction(LUA_getWindLevel, 	"getWindLevel")	'				 returns #
		
		se.AddFunction(LUA_getplayerName, 	"getplayerName")'				Returns $
		se.AddFunction(LUA_setPlayerName, 	"setPlayerName")'	[ name$ ]
	End Method
	
	Method update()
		' we can call LUA methods, like if you have an update function in LUA
		se.BeginLUAFunctionCall()
		se.CallFunction("update", True) ' true = we expect a return at some point from LUA
	End Method
	
	Method Delete()
		se.shutDown() ' shutdown LUA
	End Method
	
End Type

' params are put on a stack, so if we call the function setPlayerName("jeff","blah")
' 													then jeff is -2 and blah is -1
Function LUA_setPlayerName(ls:Byte Ptr)
	Local something$ = String.FromCString(luaL_checkstring(ls, -1))
	Local name$ =String.FromCString(luaL_checkstring(ls, -2))	
	playerName = name
	Return 0 ' we're not returning anything (this is important)
End Function

' an example of getting something from your game and putting it back into LUA
Function LUA_getWindLevel(ls:Byte Ptr)	
	lua_pushnumber(ls,windSpeed) ' send it back to LUA	
	Return 1 ' yes, we return something, a number.
End Function

' an example of sending a string back
Function LUA_getplayerName(ls:Byte Ptr)	
	lua_pushstring(ls, playerName.ToCString()) ' send it back to LUA	
	Return 1 ' yes, we return something, a string.
End Function

Function LUA_setWindLevel(ls:Byte Ptr)
	Local newWind# = luaL_checknumber(ls, -1)	
	windSpeed = newWind
	Return 0 ' we're not returning anything (this is important)
End Function


your options are LUA and the upcoming BVM v2.0

I wouldn't put off any project waiting for BVM2. Use Lua and maybe down the track expand into BVM but it's not really an option any time soon.

I've been doing something similar to your script system for some time... This is what I do.

My game always has a script file open. Events are not hardcoded, they are scripted (well, the 'trigger' IS hardcoded). There is a set of script functions, being some of them like this:

event_timer 1000 label1

this enqueues an timer-trigger activated event. 1000 ms later of reading this line, the parser will jump to label1 and will start parsing. There are other kinds of events like on_die ID, enters_zone ID X1 Y1 X2 Y2... etc

There has to be a mode to tell the parser "stop parsing and continue when some event is triggered". In my case the function 'stop' does this. So a simplified script would be like this:

fade_off
load_map "blah"
put_camera 50 50
put_text 1 "Green Hill"
fade_on
event_timer 2000 start
stop

.start
spawn_char 50 50
delete_text 1
stop

It's just an example of how it works -more or less-, didn't use actual script code.
And there is the fact that I don't parse script directly, I compile it to a bytecode for faster in-game parsing.

Notice that my script is not only for cutscenes, but for any kind of ingame event, changing music, spawning enemies, vehicles, etc. That's why a script file is always open and ready to parse any moment.

Nevertheless, although I don't use it for my own reasons - LUA is surely a better choice.

You guys are always so helpful. I appreciate it. I don't have
time to learn Lua in a week, so I will have to use my
hack-method for now. But after this Hellish rush I'm in is
over, I'm coming back and trying Ferminho's variation, and
then maybe some Lua.

In case you're wondering, I am writing the code for this
game while someone else(a non-programmer) is supposed
to convert his story and cutscenes into game script. So I
need to keep the script very simple to understand.

You can always make your own system. I have a custom script system I'm using based on executing functions.