-
Notifications
You must be signed in to change notification settings - Fork 30
Home
The Seventh uses Leola as its scripting engine. Maps may be scripted by creating the following files:
-
[mapname.json].client.props.leola
- This is client side scripting to add visual/sound effects. This is non-authoritative of the server. This is always applied no matter the game type.
-
[mapname.json].client.[game type].leola
- Same thing as the
client.props.leola
only that it is applied per game type.
- Same thing as the
-
[mapname.json].props.leola
- This is server side scripting which allows the scripter to add game timers, triggers, spawn entities and listen for server side events. This is always applied no matter the game type.
-
[mapname.json].[game type].leola
- Same thing as
props.leola
only that it is applied per game type.
- Same thing as
-
[mapname.json].objects.leola
- Any
MapObject
s defined in the map
- Any
- Team Death Match (
tdm
) - Objective (
obj
) - Capture the Flag (
ctf
) - Survivor (
svr
)
- BombDisarmedEvent
- BombExplodedEvent
- BombPlantedEvent
- FlagCapturedEvent
- FlagReturnedEvent
- FlagStolenEvent
- GameEndEvent
- KillRollEvent
- KillStreakEvent
- PlayerAwardEvent
- PlayerJoinedEvent
- PlayerKilledEvent
- PlayerLeftEvent
- PlayerSpawnedEvent
- RoundEndedEvent
- RoundStartedEvent
- SoundEmittedEvent
- SurvivorEvent
- TileRemovedEvent
A MapObject
is something interactive on the map. They are different from an Entity
because the state of the MapObject
is not synchronized with the clients. The clients get the same MapObject as the server by loading the map; it assumes the server and clients map files are the same (which works if indeed the versions of the Map are identical -- in which cases where they do not match, the server is authoritative and the clients/users will have weird behavior).
When defining a MapObject, there are two parts:
- The
[mapname.json].objects.leola
file defines all possible MapObjects. As an example file:
{
"objects" : [
// This defines a Car MapObject, players/bullets can't move thru it
{
"type": "CarA", // defines the 'type' of MapObject -- this is important to match the type with TileD MapObject type
"width" : 80, // the width of this object
"height" : 140, // the height of this object
"surfaceType" : "METAL", // the surface type; used for if this MapObject is collidable, what sounds to make when bullets hit it
"isCollidable" : true, // if true, bullets/players collide with the MapObject
// [optional] Image to display on the client
"image" : {
"path" : "./assets/gfx/map_objects/car_a.png", // the image path
// the below are optional fields if you want to take a sub-image; if omitted, then the dimensions of the image file are used
"x" : 4, // the image x offset
"y" : 9, // the image y offset
"width" : 145, // the image width
"height" : 311 // the image height
}
},
// This defines a breakable window MapObject
{
"type": "Window",
"width": 32,
"height": 16,
"surfaceType": "GLASS",
"isCollidable": true,
"onTouched": "breakWindow" // the 'onTouched' is a leola function that is called when this MapObject is touched by an Entity. The function may be defined in either `core.leola` or the `[mapname.json].props.leola` files
},
{
"type": "ExplosiveCrate",
"width": 32,
"height": 32,
"surfaceType": "WOOD",
"isCollidable": true,
"onTouched": "explodeCrate"
}
}
- The
[mapname.json]
itself is a TileD output format which includes MapObjects.
Here is TileD with the Window
MapObject placed. The MapObject in TileD is matched by the type
field defined in the Properties
panel and the type
field defined in the [mapname.json].objects.leola
file.
Server side script that always runs for the map Carentan
File name: carentan.json.props.leola
// spawn a tank
var tank = game.newTank(620, 835)
// Add Doors
var door1 = game.newDoor(607,940, -1, 0)
var door2 = game.newDoor(31,716, -1, 0)
// Add a light source
var light = game.newLight(647,960)
light.setLuminacity(1)
light.setColor(1,1,1)
light.setSize(128)
// Flicker a Light, randomly trigger the function between 50msec and 60sec looping
game.addRandomGameTimer(true, 50, 60, def() {
// change the luminacity of the light source
var lum = light.getLuminacity()
if lum < 1 {
light.setLuminacity(1)
}
else {
light.setLuminacity(0.25)
}
})
// When a door opens, cause an explosion
class DoorBomb(door) {
var isActive = false
// the game engine checks this trigger condition; if true will call the execute method
// after a trigger has been fired, it is removed
var checkCondition = def(game) {
return !isActive && door.isOpened()
}
// executes when the trigger condition is met
var execute = def(game) {
isActive = true
// spawns an explosion, probably killing whoever opened the door
game.newBigExplosion(door.getCenterPos(), door, 20, 15, 5)
// add this trigger back after 5 seconds
game.addGameTimer(false, 5000, def() {
isActive = false
game.addTrigger(this)
})
}
}
// add the door bomb trigger
game.addTrigger(new DoorBomb(door1))
// When a player dies, spawn a health pack
game.addEventListener("PlayerKilledEvent", def(event) {
console.println(event.getPlayer().getName() + " died by " + event.getMeansOfDeath().name())
game.newHealthPack( event.getPlayer().getKilledAt() )
})
Client Side script that only runs if the game type is Team Death Match
File name: carentan.json.client.tdm.leola
// make this night time by adjusting the ambient light intensity, give it a blue hue too
var lightSystem = game.getLightSystem()
lightSystem.setAmbientColor(0.85, 0.85, 1)
lightSystem.setAmbientIntensity(0.7)
// load some ambient sounds (background explosions and crickets)
var ambientSounds = {
bombs -> [game.loadSound("./assets/sfx/ambient/explo_distant01.wav"),
game.loadSound("./assets/sfx/ambient/explo_distant02.wav"),
game.loadSound("./assets/sfx/ambient/explo_distant03.wav"),
game.loadSound("./assets/sfx/ambient/explo_distant04.wav"),
game.loadSound("./assets/sfx/ambient/explo_distant05.wav"),
game.loadSound("./assets/sfx/ambient/explo_distant06.wav"),
game.loadSound("./assets/sfx/ambient/explo_distant07.wav"),
game.loadSound("./assets/sfx/ambient/explo_distant08.wav")],
cricket -> [game.loadSound("./assets/sfx/ambient/cricket.wav")],
}
// play a random sound of a sound type
var playSnd = def(type) {
return def() {
var rand = game.getRandom()
var index = rand.nextInt(length(ambientSounds[type]))
var sound = ambientSounds[type][index]
if sound {
game.playGlobalSound(sound)
}
}
}
// when the Round Starts, game in some client side game timers that randomly
// play cricket and bomb sounds
var onRoundStarted = def(game) {
game.addRandomGameTimer(true, 1000, 2500, playSnd("cricket"))
game.addRandomGameTimer(true, 5000, 12500, playSnd("bombs"))
}
// free the sound's from memory once the game is finished
var onDestroy = def(game) {
ambientSounds.bombs.foreach(game.unloadSound)
ambientSounds.cricket.foreach(game.unloadSound)
}