This page is work in progress, at this point working just as an info dump.
In general, anything stated below may change at any point during game development, there's certainly some room for cleanup/consistency improvements in there. The information on this page is representative of 1.65. Note that parts of the examples below haven't specifically been tested, so there may be typos in there.
Script flows and interactions[ | ]
Campaign game modes[ | ]
The package_config.xml
file in the root folder of a game mod references the campaign_entry_script, which can be an angel script file of your choosing. Scripts load as follows (each script #includes the next):
scripts/start_campaign.as
This is the default campaign_entry_script, which links to your mod's source folder and script files, if any.scripts/my_gamemode.as
Imports standard RWR game mechanics and introduces the ability to extend the game's behaviours. This script includes numerous other scripts:scripts/gamemodes/campaign/gamemode_campaign.as
Specifies general functions like load and save. Also loadsscripts/gamemodes/invasion/gamemode_invasion.as
, which is given its own section, below.scripts/my_stage_configurator.as
Sets faction names, links to faction config files, and specifies faction colours on the game hud and map.scripts/my_item_delivery_configurator.as
Lists weapons that are given as rewards for drop off missions and weapons that are tracked on drop off to armouries for the purpose of unlocking them for the player's factionscripts/my_vehicle_delivery_configurator.as
Similar to the item delivery configurator, lists rewards that will be randomly chosen when tracked vehicles are dropped off at a friendly armoury.
IMPORTANT if your mod's folder structure doesn't contain these .as files, the ones in vanilla/scripts
will be used instead. To simplify things — and save you losing your work when the game's scripts are updated — you may want to copy the entire scripts folder from vanilla into your mod's script folder, remove the include reference to the vanilla scripts folder from start_campaign.as
(or replace it with the path to your mod's scripts folder) and then go ahead modifying scripts within your mod, only.
Important files[ | ]
scripts/gamemodes/invasion/gamemode_invasion.as
- - of particular note in this file is the method postBeginMatch(), which includes various addTracker() calls. If you add any Classes that extend the abstract class Tracker (
scripts/internal/tracker.as
), you will need to reference them here as well as ensuring you#include
the associated .as file here as well.
scripts/internal/tracker.as
starts with an update method, which is constantly triggered by the game engine. The float time value passed to this method is the time that has passed since update was last called. Functions found inside the update method can use this value to manage timed events; indeed, the functions stored here —handle*Event()
— are the entry point to many of the other script files used in the game.
- - Use a find files containing ... search of the
vanilla/scripts
folder (or your mod's scripts folder if you've copied the vanilla scripts into your mod's folder structure) to see how these functions of thescripts/internal/tracker.as
update method operate. - - It's also a very good time to note that game events will generally be logged in
rwr_game.log
. For finer detail about what methods of what classes are being called as various game events trigger, add your own_log("my text here", 1);
inside the functions you're working with. When you've found your way and are starting to script more confidently, you'll be creating your own variables through scripts and will move onto doing things like_log("the value of myVariable is: " + myVariable, 1);
or_log(bombCount + " artillery rounds were fired by faction " + factionID + "'s " + vehName + " and hit " + hitVeh + "at " + pos1, 1);
.
Metagame Interface[ | ]
A quick intro to how game scripts work in RWR can be seen by entering the lobby/training mission and typing /_test in chat. That will attempt to launch media/packages/(mod|vanilla)/scripts/start_tester.as
, which enables trackers/basic_command_handler.as
, a simple chat command listener. Try tailing the rwr_game.log
file to see how this all fits together.
- Linux:
tail -f ~/.running_with_rifles/rwr_game.log
- Windows:
get-content "$env:APPDATA\running with rifles\rwr_game.log" -wait
- Mac:
tail -f '/Users/<username>/Library/Application Support/RunningWithRifles/rwr_game.log'
When the basic_command_handler angel script is operating, you can issue numerous commands to it via text chat. For example, typing /test will result in the commander chat saying "test yourself", while typing /_m29 will spawn a magnum revolver near the player. Take a look through the file to see the other commands the listener is programmed to respond to and give them a shot in the game chat.
- Important note: When the /_test system is executed, it replaces the active metagame (i.e. the scripts from your mod) and enables a new metagame, under which the basic command handler script inputs and outputs occur. Any other scripts that were running at this point may stop working until you restart. Again, you can tail the
rwr_game.log
to see this happening.
Commands, i.e. inputs to RWR[ | ]
The sections below detail XML commands or metagame calls that can be executed in one or more of the following methods:
- From an Angel Script
(*.as)
file found in the scripts folder of the mod, e.g.:
string command = "<command class='value' key1='value1' key2='value2' />"; m_metagame.getComms().send(command);
- With
init_match.xml
, usually in a map folder, to run a number of commands at the start of a match - When a radio call is made, if the call supplies <command>s inside its <round>s
- As a <result class="xml_command"><command ... /></result> in events in grenade or vehicle specifications
- As a local player by typing /_execute file.xml with file.xml in RWR root folder, the file consisting of a <command /> or <commands><command>...</commands>
- From server console by typing execute file.xml, like above
start_game[ | ]
<command class="start_game" vehicles="1" soldier_capacity_model="variable" soldier_capacity_variance="0.3" max_soldiers="100" player_ai_compensation="0" player_ai_reduction="0" xp_multiplier="1.0" rp_multiplier="1.0" initial_xp="0.1" initial_rp="200" randomize_respawn_items="0" base_capture_system="any" clear_profiles_at_start="0" team_kills_as_score="0" defense_win_time="-1" friendly_fire="0"> <faction initial_occupied_bases="2" initial_over_capacity="0" ai_accuracy="0.94" capacity_multiplier="1.0" capacity_offset="10" /> <faction initial_occupied_bases="-1" initial_over_capacity="0" ai_accuracy="0.94" capacity_multiplier="1.0" capacity_offset="10" /> </command>
restart_game[ | ]
- takes same parameters as start_game, with undefined values from the current game
change_game_settings[ | ]
- takes same parameters as start_game
- currently can affect player_ai_compensation, player_ai_reduction, max_soldiers, base_capture_system and faction settings
change_map[ | ]
<command class="change_map" map="media/packages/vanilla/maps/map5"> <overlay path="media/overlays/mod1" /> <overlay path="media/overlays/mod2" /> <overlay path="media/overlays/mod3" /> <map_config> <faction file="green.xml" /> <faction file="grey.xml" /> <weapon file="all_weapons.xml" /> <projectile file="all_throwables.xml" /> <call file="all_calls.xml" /> <vehicle file="all_vehicles.xml" /> <carry_item file="all_carry_items.xml" /> </map_config> </command>
- map config can be omitted, will use the map_config.xml provided by the map
start_server[ | ]
<command class="start_server" server_name="dedicated" server_port="1238" register_in_serverlist="0" client_faction_index="-1" persistency="forever" url="http://runningwithrifles.com" comment="halp me" > </command>
set_game_timer[ | ]
<command class="set_game_timer" time="600" faction_id="0" > </command>
<command class="set_game_timer" time="-1" > </command>
update_score_display[ | ]
<command class="update_score_display" id="0" // this is the faction_id text="123" > </command>
commander_ai[ | ]
<command class="commander_ai" faction="1" base_defense="0.8" border_defense="0.2" active="1"> </command>
soldier_ai[ | ]
<command class="soldier_ai" faction="1"> <parameter class="willingness_to_charge" value="1.0" /> </command>
make_query[ | ]
<command class="make_query" id="my_query_tag1"> <!-- generally, you should query as little data as possible, this is just a test --> <data class="factions" /> <data class="bases" /> <data class="players" /> <data class="characters" faction_id="0" /> <data class="characters" faction_id="1" /> <data class="vehicles" faction_id="1" key="cargo_truck.vehicle" /> <data class="vehicles" type_id="42" /> <!-- a vehicle's 'type_id' is determined by its line position in all_vehicles.xml. The first vehicle type referenced receives type_id '0' --> <!-- note a gotcha here is multiple 'special_crate' vehicles are defined in one file, and each vehicle key receives its own type_id... thus the type_id count is thrown out by .xml files in the /vehicles folder where multiple <vehicle> definitions are included. --> <data class="hitboxes" faction_id="0" /> <!-- info about specific character, you need to find out id from elsewhere, like characters-query or from incoming events --> <!-- <data class="character" id="0" /> --> <!-- <data class="vehicle" id="0" /> --> </command>
- data classes available
- general
- faction
- factions
- bases
- players
- characters
- character
- vehicles
- vehicle
- hitboxes
- item_containers
- resources
- saved_data
In most cases it is not necessary to create queries yourself. The file scripts/internal/query_helpers.as
contains utility functions for the most common queries.
xp_reward[ | ]
<command class="xp_reward" character_id="1" reward="5.0"> <!-- 1.0000 equals 10000 XP --> <!-- 0.0001 equals 1 XP --> <!-- 0.1000 equals 1000 XP, one full rank step --> </command>
rp_reward[ | ]
<command class="rp_reward" character_id="1" reward="10000"> </command>
add_custom_stat[ | ]
<command class="add_custom_stat" character_id="1" tag="??"> </command>
This appears to be used when applying an achievement to a character (e.g. blow up 15 barbecues --> "burninator")
kick_player[ | ]
<command class="kick_player" player_id="0"> </command>
update_player[ | ]
<command class="update_player" player_id="0" color="#FF0000" faction_id="1"> </command>
add_hitbox_check[ | ]
<command class="add_hitbox_check" id="item_supply2_weapon_rack" instance_type="vehicle" instance_id="1" > </command>
<command class="add_hitbox_check" id="item_supply2_weapon_rack" instance_type="character" instance_id="1" > </command>
remove_hitbox_check[ | ]
<command class="remove_hitbox_check" id="item_supply2_weapon_rack" instance_type="vehicle" instance_id="1" > </command>
update_vehicle[ | ]
<command class="update_vehicle" id="0" locked="1" health="0.5"> </command>
remove_vehicle[ | ]
<command class="remove_vehicle" id="0"> </command>
chat[ | ]
<command class="chat" text="hello world!" faction_id="-1" player_id="-1" position="512 0 512"> </command>
<command class="chat" key="map start with completed map" faction_id="-1" player_id="-1" position="512 0 512"> </command>
<command class='chat' key='loot objective' priority='1' faction_id='0'> <replacement key='%base_name' text='Ranch' /> <replacement key='%map_name' text='Keepsake Bay' /> <replacement key='%number_of_bases' text='0' /> </command>
notify[ | ]
<command class="notify" text="hello world!"> </command>
set_world_situation[ | ]
<command class="set_world_situation"> <faction id="0" name="Green" color="0 1 0" /> <faction id="1" name="Grey" color="0.5 0.5 0.5" /> <faction id="2" name="Brown" color="1 1 0" /> <faction id="3" name="Blue" color="0 0 1" /> <region id='0' name='map1' position='240.318 118.728' size='339.76 297.573' texture_rect='0.00279018 0.00111607 0.317383 0.276646'> <occupant id="0" value="1.0"/> </region> <region id='1' name='map2' position='332.227 172.969' size='587.612 372.154' texture_rect='0.351562 0.317104 0.895647 0.661691'> <occupant id="0" value="0.5"/> <occupant id="1" value="0.5"/> </region> <region id='2' name='map3' position='253.878 391.44' size='376.674 247.852' texture_rect='0.00279017 0.317104 0.351563 0.546596'> <occupant id="2" value="0.8"/> <occupant id="3" value="0.2"/> </region> <region id='3' name='map4' position='595.898 432.874' size='314.146 360.854' texture_rect='0.351563 0.661691 0.642439 0.995815'> <occupant id="2" value="1.0"/> </region> <region id='4' name='map5' position='383.454 584.297' size='311.886 252.372' texture_rect='0.00279018 0.661691 0.291574 0.895368'> <occupant id="1" value="1.0"/> </region> <region id='5' name='map6' position='176.283 539.096' size='328.46 341.267' texture_rect='0.351562 0.00111608 0.655692 0.317104'> <occupant id="3" value="1.0"/> </region> </command>
faction_resources[ | ]
<command class="faction_resources" faction_id="0" clear_weapons="1"> <weapon key="ak47.weapon" /> </command>
<command class="faction_resources" faction_id="0" soldier_group_name="miniboss"> <projectile key="hand_grenade.projectile" enabled="0" /> </command>
<command class="faction_resources" faction_id="0" clear_calls="1"> <call key="tank_drop.call"/> </command>
<command class="faction_resources" faction_id="0"> <carry_item key="vest2.carry_item" enabled="0" /> </command>
set_marker[ | ]
<command class="set_marker" faction_id="0" id="0" enabled="1" atlas_index="0" text="squad alpha rally point" position="512 0 512" color="#ff0000" range="10.0"> </command>
set_match_status[ | ]
<command class="set_match_status" faction_id="0" lose="1"> </command>
<command class="set_match_status" faction_id="1" win="1"> </command>
set_metagame_event[ | ]
<command class='set_metagame_event' name='character_kill' enabled='1' />
Enable the character kill method handleCharacterKillEvent
to be processed through scripts/tracker.as
set_spotting[ | ]
<command class="set_spotting" vehicle_id="1" faction_id="0"> </command>
Show the vehicle with id '1' on the mini-map for faction '0'.
create_instance[ | ]
<command class="create_instance" faction_id="0" position="512 0 512" offset="0 0 0" character_id="0" instance_class="carry_item" instance_key="suitcase.carry_item" > </command>
<command class="create_instance" faction_id="0" position="512 0 512" instance_class="character" instance_key="default" /> </command>
update_static_object[ | ]
<command class="update_static_object" key="wall_door" destroyed="1" > </command>
create_call[ | ]
<command class="create_call" faction_id="0" position="512 0 512" key="cover_drop.call"> </command>
update_inventory[ | ]
<command class="update_inventory" character_id="0" container_type_class="stash" add="1" instance_class="carry_item" instance_key="painting.carry_item"> </command>
<command class='update_inventory' character_id='0' container_type_class='backpack'> <item class='carry_item' key='painting.carry_item' /> </command>
update_character[ | ]
<command class="update_character" id="123" dead="1" /> </command>
update_camera[ | ]
<command class="update_camera" position="512 0 512" look_at="??" /> </command>
set_comms[ | ]
<command class="set_comms" faction_id="1" enabled="0"> </command>
set_soldier_spawn[ | ]
<command class="set_soldier_spawn" faction_id="1" enabled="0"> </command>
set_soundtrack[ | ]
<command class="set_soundtrack" enabled="1" filename="mysound.wav"> </command>
save_data[ | ]
<command class="save_data"> <root> <foo bar="0" /> </root> </command>
Events, i.e. outputs from RWR[ | ]
- - Don't forget to tail the
rwr_game.log
file to see these events being output as they occur
match_result[ | ]
<match_result> <win_condition type="map_capture" faction_id="0" faction_name="Greenbelts" /> </match_result>
faction_lost[ | ]
<faction_lost> <lose_condition type="time_expired" faction_id="1" faction_name="Graycollars" /> </faction_lost>
comms_change_event[ | ]
<comms_change_event faction_id="0" state="0" />
vehicle_holder_change_event[ | ]
<vehicle_holder_change_event vehicle_id="0" holder_id="0" owner_id="1" />
vehicle_destroyed_event[ | ]
<vehicle_destroyed_event vehicle_id="0" character_id="0" />
base_owner_change_event[ | ]
<base_owner_change_event base_id="0" owner_id="0" />
chat_event[ | ]
<chat_event player_id="0" player_name="pasik" message="OMG JEEP" global="1" />
player_connect_event[ | ]
<player_connect_event> <player name="pasik" player_id="0" faction_id="0" profile_hash="........." ip="192.168.1.5" port="43243" character_id="123" /> </player_connect_event>
player_disconnect_event[ | ]
<player_disconnect_event> <player name="pasik" player_id="0" faction_id="0" profile_hash="........." ip="192.168.1.5" port="43243" character_id="123" /> </player_disconnect_event>
player_kill[ | ]
<player_kill> <killer name="pasik" player_id="0" faction_id="0" profile_hash="........." ip="192.168.1.5" port="43243" character_id="123" /> <target name="JackMayol" player_id="1" faction_id="1" profile_hash="........." ip="xxx.xxx.xxx.xxx" port="43221" character_id="124" /> </player_kill>
player_die[ | ]
<player_die> <target name="JackMayol" player_id="1" faction_id="1" profile_hash="........." ip="xxx.xxx.xxx.xxx" port="43221" character_id="124" /> </player_die>
player_spawn[ | ]
<player_spawn> <player name="JackMayol" player_id="1" faction_id="1" profile_hash="........." ip="xxx.xxx.xxx.xxx" port="43221" character_id="125" /> </player_spawn>
hitbox_event[ | ]
<hitbox_event hitbox_id="blahblah" instance_type="character" instance_id="125" />
<hitbox_event hitbox_id="blahblah" instance_type="vehicle" instance_id="125" />
item_drop_event[ | ]
<item_drop_event character_id="0" item_class="0" item_type_id="0" target_container_type_id="0" item_key="ak47.weapon" position="512 0 512" player_id="0" />
call_request_event[ | ]
<call_request_event character_id="0" faction_id="0" call_id="0" call_key="cover_drop.call" target_position="968.851 16.7647 400.99" player_id="0" />
This event is only emitted when the call has the attribute notify_metagame set to "1" like
<call key="cover_drop.call" notify_metagame="1"> <!-- defition goes here --> </call>
user_quit_event[ | ]
<user_quit_event />
Troubleshooting / bug smashing[ | ]
rwr_game.log
error messages[ | ]
loading faction resources in <mod_folder_path>/factions/<file_name> <some_text> CHECK: characters or character element not found execution halted
This error indicates you have made reference to a non-existent character file in factions/<faction>.xml
.
Ensure the file exists in the factions folder, is spelled correctly, matches the case and launch the game again.
loading faction resources <mod_folder_path>/factions/common.resources loading faction resources in <mod_folder_path>/factions/<another_file>.resources loading faction resources in CHECK: resources element not found execution halted
This error indicates you have made reference to a non-existent resources file. The actual file causing the error (typo, doesn't exist, or trying to load a non-existent resource) will be the file loaded after <another_file>.resources
is listed in factions/<faction>.xml
.
loading calls in <mod_folder_path>/calls/<call_name> loading calls in CHECK: calls or call element not found execution halted
Similar to the error above, this error indicates you have made reference to a non-existent call file in calls/all_calls.xml
. Calls are generally processed in the order they are listed in all_calls.xml
, so check which call was the last to load before the error occurred and the error will most likely be to do with the next referenced file.
<filename.as> (line_num, col) : ERR : No matching signatures to '<text>'
Does <filename>.as
include the file that contains the class, constructor, method, etc. referenced in text?
Issues that don't show up in rwr_game.log
[ | ]
- Commander briefing at start of mission fails to appear
- - This generally indicates you have made a syntax error early on in
/languages/en/default_shared.character
, such as a missing forward slash '/' at the end of a<comment key="blah" text="blah blah" />
tag. Every line after the one(s) with a syntax issue will fail to be read at start time, resulting in the comment keys used in the commander briefing failing to appear. - - You may also notice unprivileged calls (xp < 1000) don't result in a text bubble advising "I don't have a radio yet" or other text string appropriate to the
<comment key="no radio equipment"... />
. These comment tags start from line 110, so your syntax error is going to be before this line.
Creating your own Class[ | ]
Extending the Tracker Class[ | ]
- Create a new file within the
scripts/trackers
folder named something likemyClass.as
#include
the .as scripts your class relies on (e.g. calls to _log() requirelog.as
or another file that includes it to be listed here).- Define your class with
class MyClass : Tracker { ... }
- Specify its constants and variables e.g.
protected Metagame@ m_metagame;
- Add the constructor e.g.
MyClass(Metagame@ metagame) { @m_metagame = @metagame; }
- Add your custom methods
protected void doSomethingMethod(const XmlElement@ block) { ... }
- Finally, add common class methods:
/* These first two are often commented out, but are left in here as a reference, should you choose to use them // -------------------------------------------- void init() { } // -------------------------------------------- void start() { } End comment*/ // -------------------------------------------- bool hasEnded() const { // always on return false; } // -------------------------------------------- bool hasStarted() const { // always on return true; } // -------------------------------------------- void update(float time) { // add your custom update scripts in here like: // incrementing or decrementing counters // testing for something based on the counter value e.g. <= 0 // writing something to the log (warning! will spam the log - update methods are called multiple times per second) } // ----------------------------------------------------