===== Drone Training Script =====
Here's an example of a chunky script that uses entities to provide a basic single player game with multiple levels.
First off we've got a basic building script file that's used to provide an access point for the player where they can start the minigame:
$kPlayGamePlinthBuildingType = 5
Event( "OSDSelect", "GameOSD:PlaySingle" )
{
$gPlayerKey[DroneGameMode] = 1
// Play game music
*playmusic %PLAYER% http://yyy.com/musicfile.mp3
*crowspawn %PLAYER% 128 128
Sleep( 5 )
*gocrow %PLAYER%
*texteffect %PLAYER%,1,First wave incoming! Ready Up!
Sleep( 20 )
CustomEvent( "StartGame" ) // Defined in LevelSpawner.mit
}
Event( "AccessBuilding", "$kPlayGamePlinthBuildingType" )
{
osdcreate(OSDBUILDING,"GameOSD", "" )
osdadd(EXITBUTTON, 100, 80, 400, 35, "PlaySingle", "Example Single Player Game" )
osdactivate()
}
All pretty standard so far. Now we get on to the good stuff.. \\
//----------------------------------------------------------
// LevelSpawner.mit
//
//----------------------------------------------------------
$mSpawnPositionType = 1
// -------------------------------
// Here we're definining a 'kindof' struct thats used to specify the details of each level
// Each row in our table has 7 values, and we store that in a constant $kSizeOfWavesStruct
// Each row corresponds to a 'level' in the game, so if we want to access the values for level 3
// we start with the array value at 3 * $kSizeOfWavesStruct ( + 1 coz arrays are not zero-indexed _rolls_eyes_)
//---------------------
$kSizeOfWavesStruct = 7
$maEnemyWaves[] =
{ // num2spawn(1) min lead(2) max lead(3) min speed(4) max spd(5) min acc(6) max acc(7)
2, 20, 50, 1700, 2100, 800, 100, // Wave 1
4, 30, 50, 2000, 2700, 1100, 200, // Wave 2
4, 50, 70, 2100, 2600, 1400, 1600, // Wave 3
5, 60, 70, 2300, 3000, 1100, 1400, // Wave 4
6, 80, 100, 2400, 3100, 1200, 1700, // Wave 5
7, 90, 100, 2500, 3200, 1300, 1500, // Wave 6
8, 90, 100, 2700, 3500, 1300, 1800 // Wave 7
10, 90, 100, 3000, 4000, 1200, 1900, // Wave 8
10, 90, 100, 3100, 4500, 1500, 2000, // Wave 9
}
//----------------------------------------------------------------------------------------------------
// -------------------------------
// The table contains a few numbers that define a min--max range for properties of the enemies.
// This function returns a random number between those ranges.
// It uses the $gPlayerKey[WaveNum] to determine which level we're on and then the baseIndex tells us where in
// each 'row' we should be looking.
// (Of course, we could do away with all this nonsense if the script language supported more than just integer arrays, but thats for another time :] )
//---------------------
Function GetTableMinMaxVal( $baseIndex )
{
$waveTable = $gPlayerKey[WaveNum] - 1
if ( $waveTable > 8 )
{
$waveTable = 8
}
$waveTable *= $kSizeOfWavesStruct
$min = $maEnemyWaves[$waveTable+$baseIndex]
$max = $maEnemyWaves[$waveTable+$baseIndex+1]
$diff = $max - $min
$min += sysRand( $diff )
return( $min )
}
///------------------------------------------------
// The custom StartGame event is triggered from the game access building defined separately
//------------------------------------
Event( "Custom", "StartGame" )
{
// Delete all entities for the current player
EntityDeleteAll( $gPlayerID );
$gPlayerKey[NumEntitiesAlive] = 0
$gPlayerKey[WaveNum] = 1
$gPlayerKey[NumKills] = 0
SpawnMoreBadGuys()
}
///------------------------------------------------
// SpawnMoreBadGuys
// Called at the start of each 'wave'/level to trigger a new wave
// of enemies
//---------------------------------------------
Function SpawnMoreBadGuys( )
{
$waveNum = $gPlayerKey[WaveNum]
*notifylarge %PLAYER% Wave $waveNum
$loop = 0
$waveTable = $waveNum - 1
$waveTable *= $kSizeOfWavesStruct
$numEntitiesToSpawn = $maEnemyWaves[$waveTable+1]
while ( $loop < $numEntitiesToSpawn )
{
SpawnRandomHunter( 15000, 25000 )
$loop += 1
}
$gPlayerKey[NumEntitiesAlive] += $numEntitiesToSpawn
}
//-------------------------------------------------
// SpawnRandomHunter
// Earlier code has determined we need an extra enemy , and it provides the min/max range where
// that new enemy should appear. This function converts that range to an actual X,Y world position
// and then calls the 'SpawnBadGuy' function above to add an entity
//------------------
Function SpawnRandomHunter( $minrange, $maxrange )
{
// Spawn somewhere randomnly near the player
if ( $mSpawnPositionType == 0 )
{
$spawnAngle = sysRand( 360 )
$rangeval = $maxrange - $minrange
$spawnRange = sysRand( $rangeval )
$spawnRange += $minrange
$spawnSin = sysSin( $spawnAngle, $spawnRange )
$spawnCos = sysCos( $spawnAngle, $spawnRange )
$xpos = $gPlayerWorldX + $spawnSin
$ypos = $gPlayerWorldY + $spawnCos
}
else // Spawn on the edges of the Drone Shooter pitch
{
$side = sysRand(4)
if ( $side == 1 )
{
$mapPosX = 103
$mapPosY = sysRand( 50 )
$mapPosY += 103
}
else if ( $side == 2 )
{
$mapPosX = 153
$mapPosY = sysRand( 50 )
$mapPosY += 103
}
else if ( $side == 3 )
{
$mapPosX = sysRand( 50 )
$mapPosX += 103
$mapPosY = 103
}
else if ( $side == 4 )
{
$mapPosX = sysRand( 50 )
$mapPosX += 103
$mapPosY = 153
}
$xpos = sysMapToWorld( $mapPosX )
$ypos = sysMapToWorld( $mapPosY )
}
SpawnBadGuy( $xpos, $ypos )
}
// -------------------------------
// SpawnBadGuy
// Here we'll have some fun with entities. The calling function has worked out where to spawn a new enemy,
// So here we calculate some of its properties and then create the actual entity
//---
Function SpawnBadGuy( $xpos, $ypos )
{
$waveNum = $gPlayerKey[WaveNum]
$targetLeadPercentage = GetTableMinMaxVal( 2 )
$moveSpeed = GetTableMinMaxVal( 4 )
$moveAcc = GetTableMinMaxVal( 6 )
// Create an entity that is managed locally (i.e. is effectively just run for the one player)
// with a HUNT behaviour. (This means the entity will attempt to hunt down the local player).
// Note that the entity does not actually get sent to the player until we add it to the world, later in this function
$mhTestEntity = EntityCreate( $gPlayerID, "LOCAL", "HUNT" )
// Note, currently all entity graphics need to be present in the game's main web content folder on the CDN
EntitySetModel( $mhTestEntity, "uniRobocrow2.atm", "uniRobocrow2.jpg" )
EntitySetPosition( $mhTestEntity, $xpos, $ypos, 0 )
// Behaviour Control flags
// FaceTarget = Set the entity to always to always look towards the target
EntitySetValue( $mhTestEntity, "FaceTarget", 1 )
// AttackProx = Start attacking when within the ProxRange
EntitySetValue( $mhTestEntity, "AttackProx", 1 )
// DieOnTargetDeath = Entity is destroyed if the target dies
EntitySetValue( $mhTestEntity, "DieOnTargetDeath", 1 )
// Parameters and values
// ZOffset = Vertical position offset above the ground
EntitySetValue( $mhTestEntity, "ZOffset", 800 )
// ProxRange = Used to determine attack range
EntitySetValue( $mhTestEntity, "ProxRange", 6000 )
$targetDist = $waveNum * 200
$targetDist += 2300
// Distance from the target the entity will try to maintain
EntitySetValue( $mhTestEntity, "TargetDist", $targetDist )
// Who the target is..
EntitySetValue( $mhTestEntity, "Target", $gPlayerID )
EntitySetValue( $mhTestEntity, "Weapon", 1 )
// Basically this sets how good the entity is at aiming
EntitySetValue( $mhTestEntity, "TargetLead", $targetLeadPercentage )
$health = $waveNum * 25
$health += 100
// Health = how much damage this entity can take before dieing
EntitySetValue( $mhTestEntity, "Health", $health )
// Set Speed and acceleration (Determined by the level settings table)
EntitySetValue( $mhTestEntity, "MoveSpeed", $moveSpeed )
EntitySetValue( $mhTestEntity, "MoveAcc", $moveAcc )
// Now all set.. add the entity to the world
EntityAddToWorld( $mhTestEntity )
}
///------------------------------------------------
// Every time an entity is destroyed we update the player's kill count and decrease the
// count of enemies remaining. Once that gets to 0 we start the next wave
//------------------------------------
Event( "EntityDestroyed", "" )
{
$gPlayerKey[NumKills] += 1
$gPlayerKey[NumEntitiesAlive] -= 1
if ( $gPlayerKey[NumEntitiesAlive] == 0 )
{
$gPlayerKey[WaveNum] += 1
SpawnMoreBadGuys()
}
}
///------------------------------------------------
// GameEnd is triggered from RobocrowDeath Event and displays final score etc
Event ("RobocrowDeath", "" )
{
if ( $gPlayerKey[DroneGameMode] == 1 )
{
*event %PLAYER% GameEnd
}
}
//------------------------------------
Event( "Custom", "GameEnd" )
{
*fademusic %PLAYER% 5
Sleep(10)
*texteffect %PLAYER%,1,Game Over
Sleep(20)
$numKills = $gPlayerKey[NumKills]
if ( $numKills > $gPlayerKudos )
{
*setkudos %PLAYER% $numKills
*announce %PLAYER% acheived a new personal best of $numKills kills ( Level $gPlayerKey[WaveNum] )
}
else
{
*announce %PLAYER% reached level $gPlayerKey[WaveNum] with $numKills kills
}
}