(info) Most of the information here is for Warzone 3.1 and above.

Enhanced SitRep Mod

This mod adds a new rules.js in order to increase the number of situation report audio messages in the game. It also adds a number of new audio files.

 

Folders and Files

 Enhanced_SitRep_Mod.wz – the mod folder packaged as a Warzone Zip (.wz).

 audio

 sitrepmod – contains several new .ogg format audio files

 audio.cfg – used to define volume and other settings for the new audio files

 multiplay

 skirmish

 rules.js – custom game rules

 rules.init.js – player initialisation script

 rules.report.js – situation reporting API

 rules.report.msg.js – situation reporting message config

 wrf

 audio.wrf – defines locations of custom audio files

Let's take a closer look at each of those things...

 audio, multiplay, skirmish and wrf

These are all standard Warzone folders - places where Warzone is expecting to find its Config files (Stats) and other resources such as audio and scripts.

 sitrepmod

This is a custom folder to store audio files that are specific to the Enhanced SitRep Mod - it just keeps them together and separate from Warzone (or other mods) audio files.

To ensure filenames were unique, each audio file is prefixed with "sit-". You can see a list of the files and download them from sitrepmod.

The audio files were created using Audacity, a free open source audio editor that has native support for OGG audio files.

It was desirable to use the same female voice that's used for other in-game messages and mission briefings for these new audio files. In order to do that, segments of existing audio files (see Audio Directory) were spliced together in Audacity and then saved as new .ogg files.

(lightbulb) Tip: You can use the search box on this wiki to locate audio files based on the words spoken in them (we've transcribed every single audio file!) to save time when looking for specific words.

There's also lots of voice audio in the Video Directory, however don't load video .ogg files in to Adacity as it tends to crash horribly - you'll have to somehow extract the audio track from the files (I used an audio recorder app to record the audio while the video was playing to achieve this).

 audio.cfg (download)

This is one of Warzone's Config files (Stats) - it defines the volume and several other properties for each of the custom audio files included in the mod:

/*sitrepmod*/
	audio	"sit-batatk.ogg"		oneshot 100 1800	/*Battery Under Attack*/
	audio	"sit-batcomp.ogg"		oneshot 100 1800	/*Battery Completed*/
	audio	"sit-cmdatk.ogg"		oneshot 100 1800	/*Commander under attack*/
	audio	"sit-cbcomp.ogg"		oneshot 100 1800	/*Counter Battery Radar Completed*/
	audio	"sit-lasactiv.ogg"		oneshot 100 1800	/*Laser Satellite Activated*/
	audio	"sit-lascomp.ogg"		oneshot 100 1800	/*Laser Satellite Completed*/
	audio	"sit-scavfirst.ogg"		oneshot 100 1800	/*Scavs approaching, defend, destroy*/
	audio	"sit-scavraid.ogg"		oneshot 100 1800	/*Scavs approaching*/

For more information on configuring this file, see audio.cfg.

 audio.wrf (download)

This is one of Warzone's Config files (Stats) - it defines the location of the custom audio files included in the mod using their relative folder path from the mod's "Enhanced_SitRep_Mod" folder:

directory	"audio/sitrepmod"
file		WAV	"sit-batatk.ogg"
file		WAV	"sit-batcomp.ogg"
file		WAV	"sit-cbcomp.ogg"
file		WAV	"sit-cmdatk.ogg"
file		WAV	"sit-lasactiv.ogg"
file		WAV	"sit-lascomp.ogg"
file		WAV	"sit-scavfirst.ogg"
file		WAV	"sit-scavraid.ogg"

For more information on configuring this file, see audio.wrf.

 rules.js (download)

This is one of Warzone's Config files (Stats) - it initialises players when the game starts, checks victory conditions and a bunch of other stuff.

In true modding style, it was decided to rewrite rules.js from scratch. (smile) Here's the version of the file at the time of writing this guide for reference: rules.js

To interact with Warzone, the script uses the Warzone Javascript API and various standard Javascript Coding techniques. If you've developed Javascript for web browsers, then you pretty much know what to expect.

Includes

To avoid the file getting too big it was decided to split out key chunks of functionality in to external .js files. At the start of the file, the include() function is used to include the three resulting files (which are described later on this page).

Constants

Next, a few constants are set-up - these are read-only variables that can't be changed after they've been defined. Note that the constants don't follow the usual convention of using ALL_UPPERCASE - not sure why. You can find some coding conventions on the JS API's Introduction page.

The "teams" constant keeps track of whether the game is running in "Fixed Teams" alliance mode - while it's a simple check, using the alliancesType global and ALLIANCES_TEAMS constant, it's going to be done regularly (in the checkPlayers() function described later) hence us storing the result in a constant.

The "humanPlayer" constant is set to selectedPlayer to remember which player ID corresponds to the human player that rules.js is monitoring. It's impossible for the human player to switch to another player ID at this point in the game (while the game is still initialising) so this can't be circumvented. Knowing this helps when it comes to checking events relating to the construction and destruction of the HQ.

Player initialisation

The eventGameInit() event is then used to initialise all the players, The event is called once at the start of the game, as soon as the game environment is ready for interaction with scripts.

When altering player settings, you need to first hackNetOff() and then later hackNetOn() to avoid desynch between players. A loop goes through each player in turn and initialises them by calling functions that are in the rules.js.init.js file. Because structure limits have been defined, the applyLimitSet() function is called to merge them with the default structure limits.

Next we enable or disable the design mode (setDesign()) and mini map (setMiniMap()) depending on whether the player has (enumStruct()) a HQ or not. This is just the standard rule with Warzone and you'll get shouted at if you change it without good reason! The enableTemplate() function is used to ensure that the player can produce construction trucks regardless of whether the unit designer is enabled or not.

Backwards while loops

I'm addicted to backwards "while" loops - you'll see them regularly in any script that I work on!

// assuming "whatever" is an array...
var num = whatever.length;
while (-1<--num) {
  // do stuff with whatever[num]
}

This will iterate from "length-1" to "0", so it's obviously only useful if you don't care about iterating backwards through the array. There's no real benefit to doing this - you could use a "for" loop or several other approaches. I just thought I'd mention the backwards while loop as many people haven't seen it before for some reason?!

Game initialisation

Because we want to keep track of player statuses, so we can work out when they are defeated or revived, a "playerLiving" array is set up - it will be initialised later.

It's really important to define as few globals as possible and keep their contents simple due to the way that Warzone saves games - for more information, see Saved game files and Common Mistakes.

The isPlayerAlive() function works out if a player is still alive or defeated. In standard Warzone game rules, a player is considered dead if the don't have any factories or units left - because at that point they can't really engage in war any more.

The eventStartLevel() event is used is then used to initialise the game, it's called just once when the game starts. In this event:

  • We initialise the playerLiving array by looping through all players (maxPlayers) and checking if they are alive
  • A timer is set (setTimer()) that periodically checks player states via the checkPlayers() function
  • The reporting API (in rules.report.js) is called to welcome the player to the game

Victory conditions

As mentioned above, the checkPlayers() function is called periodically to determine if the game is won or lost. In standard Warzone game rules:

  • The player wins if they have no enemies left
  • The player loses if they are dead, unless they are part of a fixed team in which case they only lose when all of their team is also dead

The checkPlayers() function goes through each player in turn to work out who's alive and who's dead. It keeps track of how many allies, team members and enemies are alive with respect to the player. The allianceExistsBetween() function determines if two players are allied with each other.

Using the playerLiving array, it's possible to detect when a player dies or gets revived (by an ally giving them a truck or other unit) and thus report on the situation.

After checking each player status and tallying the number of living allies, team mates and enemies, the victory conditions are then checked at the bottom of the checkPlayers() function. the gameOverMessage() function is called if the game is won or lost, and the "checkPlayers" timer is removed (removeTimer()) to prevent further calls to checkPlayers().

HQ monitoring

As mentioned earlier, the design tool and mini map features are toggled on or off based on the existence of a HQ structure. This means the script has to keep track of when the HQ gets built and destroyed - it does this using eventStructureBuilt() and eventDestroyed().

The game's debug menu (also known as cheat mode) allows a player to switch to other players at which point rules.js starts to operate as the player they've selected. To avoid confusion, the "humanPlayer" constant we defined earlier is used to make sure the event was triggered in relation to that player ID.

The events are passed a Structure object that defines what structure was built or destroyed, but they can also be triggered for other things (such as droids/units being destroyed and even map features) so it's useful to check that the object type is STRUCTURE before checking that it's a HQ - this is because only structure objects have a .stattype property: if we tried accessing that property on any other type of object it would cause an error.

Situation reporting

Now we finally get to the situation reporting - it's what this mod is about after all!

This is achieved by listening to a bunch of game Events & Timers and then relaying them on to the reporting API in rules.report.js.

 rules.init.js (download)

This script contains all the player initialisation code and data that gets called from eventGameInit() in rules.js.

Settings & config data

An empty init() function is created as a namespace to store all the data associated with player initialisation - this prevents all that stuff finding its way on to the global scope.

The properties are named so it's clear what their contents are used for, and the functions that process them follow a similar naming convention. By putting all these settings and config data at the top of the script, it's easy to change them without worrying about breaking any of the code lower down the script.

The first few properties are arrays of IDs relating to structures, components and technologies. You can find the ID's for these things in the game's Config files (Stats) (or alternatively use the online guide – click on an item to view it's detail page and you'll see it's ID at the top). Towards the end of the settings, in the "baseTypes" bit, a lot of the JS API's Constants are used.

Initialisation functions

There's a function to deal with each config setting property defined at the top of the script. The functions have the same name as the property with a "For" tagged on the end so that the code in rules.js is really easy to read:

init.enableStructuresFor(player);
init.enableComponentsFor(player);
init.enableTechnologiesFor(player);
init.setLimitsFor(player);
init.applyBaseTypeFor(player);

It's pretty obvious what's going on there!

The functions are pretty much self explanatory and use a lot of the constants, globals and functions that are documented with examples in the Javascript API.

You'll notice that the native Javascript Array object's forEach() and some() functions are used quite a lot - these make it easy to iterate through arrays, calling a function on each item in the array, without needing to define custom variables and loops. While they might look a bit odd at first, I highly recommend them as they're really quick and easy to use once you get used to them.

 rules.report.js (download)

This file is much too big to describe in detail, but we'll take a look at a few things...

constants

The JavaScript API defines a number of Constants, however depending on which version of the JS API is being used some or all of them might be missing. So, the first block of code checks whether required constants are defined, and if not it creates them.

closures

Because the script contains dozens of functions, it was decided to use a closure to keep them from getting on to the global scope. For more information on closures, see Scopes & Closures.

The basic format used is as follows:

var report = (function() {
   // lots of stuff
   return thingYouWantToAssignToReport;
})();

Here, we're creating an anonymous self-running function. When you wrap a function definition in (brackets like this)() you run the function and it's return value is assigned to "report".

Object classification

This code will probably come in useful for other mods, You pass classify() a "game object" (which can be any of the standard Warzone object types – see Objects) and it returns a string ID that classifies what that object is, for example if you pass it a VTOL Factory structure object, the returned string will be something like "base.factory.vtol".

This might seem like overkill, especially when you consider object properties like .stattype and .droidType which tell you fairly accurately what something is. But as you look in closer detail you'll see that this classification abstracts us away from lots of crufty object classification code and version-specific API features. It also goes beyond what the JS API provides because it can classify features and different types of weapons, etc.

report() function

This is responsible for taking an object classification string and finding an associated object defined in rules.report.msg.js. What's interesting here is that the object classification will be "reduced" until a matching object is found, or not. For more details on how that works, take a look at the extensive code comment in rules.report.msg.js.

is*() functions

At the bottom of rules.report.js, there's a plethora of functions that check whether a passed in object meets some specific criteria - for example, isTransport() checks to see if the passed in object is a transporter.

These are all easy to do without having functions, but I find that putting all this stuff in to functions makes code elsewhere a lot more readable, like this:

// custom attacked reports...
report.attacked.custom = function(obj, attacker) {
	if (obj.type != DROID) return;
	if (isFixVTOL(obj)) { // custom: vtols attacked while fleeing the battlefield
		if (!!attacker && isAntiAir(attacker)) return "custom.abort";
		if (isRepairing(obj)) return "custom.rearm";
		if (isRetreating(obj)) return "custom.return";
	} else { // custom: non-vtol droids attacked while fleeing the battlefield
		if (isRepairing(obj)) return "custom.repairs";
		if (isRetreating(obj)) return "custom.retreat";
	}
}

 rules.report.msg.js (download)

This script is really just a huge object definition - it works as a look-up table between a game object's classification string (generated by code in rules.report.js) and an object that defines what should happen in relation to it.

There's extensive code comments at the start of the file that explain it in detail.

This plugin was originally developed by Shadow Wolf TJC. For more information see Enhance SitRep Mod in the Warzone forums.

It's also featured in Awesome Addons in the Warzone 2100 Encyclopaedia.

Audio resources:

Customising game rules:

  • Game Rules & SitRep – several guides and examples
  • rules.js – the main JavaScript file that initialises players and checks victory conditions

Scipting: