PHP SCX Editor

Article written by AzZzRu
Published on 07-04-2016; updated on 03-16-2017
Tags:

PHP SCX Editor is a powerful tool / framework to edit aoc scenarios with PHP programming language. If you handle it you could make anything very easily. It’s A LOT more powerful than aokts, you have the ability to build your own editor fonctionnalities very easily and organize your scenario how you want. That is very accessible to people who like programming and know it already a little bit. For others, you can still try it, programming is an intuitive skill and can be innate ! You could love it as you could hate it, it depends of people. Aoc triggers is a crap programming language which is boring and quite repetitive, if you can like that, you will love to practice a real programming language like PHP that allows you to build anything faster and smarter.

Don’t be scared about complexity, the functions that are available are very intuitive and easy to use. It’s much more smooth than an UI, but it takes more time to handle that, of course. When you’ll handle the script you will have more time to think to your scenario instead of writing triggers, you could create fast almost whatever you think, and modify result very easily. You can contact me at voobly, if you are motivated I will help you by Skype: My profile

Original version is made by AOHH. Thanks to him for allowing me to modify and publish its code.

Compatibility: 1.0c / 1.4 RC / FE / HD*

(*) For HD designer: Set SCX::$editor_version parameter to ‘HD’ to use new triggers effects. Also PSE can’t read HD scenarios yet, so you need to use 1.0c or 1.4 RC maps as input scenario.

Download the script to the blacksmith: https://aok.heavengames.com/blacksmith/showfile.php?fileid=12246

Project is shared on GitLab if you want to contribute you are welcome: https://gitlab.com/sychavanne/php-scx-editor

Features

  • Design scenarios how you want with PHP programmation. You can build them in smoother and faster ways, no more boring repetive tasks.
  • Use ready to use simple and intuitive functions to read / write scenarios properties and write triggers.
  • Use conditions, loops and any classic programming feature to generate triggers or anything in a scenario.
  • Create complex custom conditions / effects / triggers sequence / macros.
  • Assign any fields to values calculated by algorithm and variables.
  • Copy paste triggers or any reusable code in new scenarios.
  • Have a great overview of your triggers and your whole scenario in a single page.
  • Build your own aoc editor framework to fill your needs.
  • Modify your scenario by changing variables, no more need to edit triggers one per one.
  • Change triggers order as you want, just cut paste code.
  • Scenarios that would need 100 hours to make could need only 10 hours now !
  • And more…!

Algorithms examples

If you are not used to programmation you won’t see why it is so much awesome. Some examples:

In a RPG map where you can pick berries you could write with few lines:


For each berries in the whole map
      If a player is next to it
      Give him 5 food
      Remove the berry

So now, you can start thinking where to put berries, just place it, and triggers are made ! And you want to move one by 1 tile ? Do it ! Triggers will adapt ! It’s only a fraction of what you can do now. ;)

In a SP map you are lazy to handle conversation between player and actors ? You could create a custom trigger to achieve this with only one line, instead of creating 1 trigger + 1 condition + 1 effect. The function prototype would looks like:


TrigConversation($actor, $whatHeSay);

Then you will use it like this:


$Unit["The King"] = 10; # The unit id that is the king
TrigConversation("The King", "Hello, Im the king.");

This code will in fact generate this trigger:


Trigger: Conversation with The King
Condition: Bring object in the area around unit 10
Effect: Display instruction "The King: Hello, Im the king."

So, you can see it’s much faster and clearer with PHP. It gives you an overview and prevent you doing mistakes, and if one day you want to change “The King” unit, you will have to change only the line “$Unit[“The King”] = 10;”, and in your whole scenario triggers will adapt. Or if finally you want the conversation starts when the player select the actor instead of reaching close area, you will just have to change the function TrigConversation.

Another interesting point: You think that your custom trigger is great, post it here in this thread, and I will add it in the standard library of PHP SCX Editor, and everybody could use it ! You could also share it with your friends. Aoc scenarios designing could become much easier and funny to handle. It’s very cool that people can share mods, graphics, etc… now it is possible to share triggers too.

In a MP map you could handle teams in much more intuitive ways, by creating your own condition:


Condition: player A is enemy to player B
Effects...

This condition will in fact check if the palissade wall from the team detector is destroyed, but it will be unseen in your code ! All logics is more clear.

Creating team detector with palissade walls and sabs is quite boring work right ? You can know create a function that can do it with only one line !


Create a team detector at X,Y

Or create an anti-deleter is also quite boring ! Automate it !


Build anti-deleter for buildings

You want to play a sound to all players for each instructions displayed ? Then instead of writing 1 + 8 effects always, customize your display instruction effect ! Then it will do it by default, and you will need to write only one effect. Your code will looks like:


Effect: Display instruction "blabla"

And so on !


Condition: If player X is level 10
Condition: If player X is alive
Effect: Send chat to all player
Effect: Play sound to all player
Effect: Deactivate all triggers assigned to player X (useful for boot)
Effect: Boot player X
etc...

Here is the power of PHP, you can share code, save lot of time and create your scenario in much more intuitive ways.

A last example to show you how would really looks code to create all CBA spawns triggers with tasks for 8 players, with only 12 lines, 5 minutes of work if you are used to PSE:


$spawns = array(array(22,48),array(22,52),array(22,55),array(22,59));
$meetPoint = AreaPlayers(array(29,53));
Trig("Research Civ Techs");
foreach(range(1,8) as $p)foreach(LIB::$CivTechs as $tech)Efft_Research($p,$tech);
foreach(range(1,8) as $p)foreach(LIB::$CivTechs as $civ => $tech){
    Trig("Spawn Player $p - Civ $civ",1,1);
    Cond_Researched($p,$tech);
    Cond_Timer(4);
    Cond_NotOwnY($p,Y_MILITARY,40);
    foreach($spawns as $spawn)Efft_Create($p,LIB::$CivEliteUnit[$civ],AreaPlayer($p,$spawn));}
Trig("Tasks",1,1);
foreach(range(1,8) as $p)foreach($spawns as $spawn)Efft_TaskO($p,AreaPlayer($p,$spawn),$meetPoint[$p]);

Example of maps made by programming:

These four maps are almost impossible to make without a programming method and show you the power of scripting.

Requirements / Installation

Installation should be very easy, however if you have any troubles ask help in this thread.

1. You need a PHP IDE, I advise you to use the same as me, it has nice features and nice code completion: PHP Designer 8. But it is not free.

You can also download PHP Designer 2007, the personal version is free: http://download.cnet.com/PHP-Designer-2007-Personal/3000-10248_4-10575026.html

A PHP IDE is an advanced text editor to write PHP a lot more easily with nice features, it would be possible to write PHP with notepad, but it’s not worth it.

2. You need a PHP compiler, take v5.6 Non Thread Safe x86 or x64 depending of your system (as zip): http://windows.php.net/download#php-5.6

A PHP compiler is a program that can interpret and execute what you wrote with your PHP IDE.

3. Install your PHP IDE.

4. Unzip PHP compiler files in a folder without space at the root of your hard drive. EG: “C:/PHP-5.6.9/”. You also need to rename “php.ini-development” file to “php.ini”.

5. Configure your PHP IDE, for PHP Designer 8: Go to “Tools / Preferences / Run” and specify paths to your compiler php.exe and configuration file php.ini which are in the PHP compiler folder. Do the same in “Tools / Preferences / Debugger”.

6. Open php.ini with notepad and edit “max_execution_time” and “memory_limit” values (ctrl + F to find them):


max_execution_time = 300000
memory_limit = 4294967296

php.ini is a configuration file for the php compiler.

7. All is ready. To use PHP SCX Editor open the 3 files in your PHP IDE: Compiler.php, Scenario.php and Library.php. You will use those 3 files to build a scenario.

8. To check if your installation is good, try to compile the example:

  • In aoc create a blank map called “My Map”
  • In Compiler.php, specify your scenarios folder path in $scenarios_path
  • Run two times Compiler.php (On PHP Designer 8 click on “Run” button in toolbar / For PHP Designer 7 it’s called “Debug” I think.)
  • A new map is created: “My Compiled Map”, you can open it in aoc and see the result

How to make maps

The script loads an existing map, edits it, and exports it. It will ignore all triggers of the input file.

The script is divided in 4 files:

  • Compiler.php: It decompress the input scenario and compress it after you did your modifications. You have to run two times Compiler.php to generate the output scenario.
  • Scenario.php: This is here you write your scenario modifications. You always start from an input scenario and edit it. In fact PHP SCX Editor doesn’t create scenarios, it edits existing ones.
  • Library.php: It is the standard PHP SCX Editor library to make scenarios. It contains the essential functions to read / write properties, and triggers. You should create your own library in addition depending of your needs, sharing it could be nice too.
  • data_aok.php: It’s exactly like data_aok.xml, it contains all aoc constants. It’s useful because you can specify units, techs, ressources, groups, types, terrains ID with names.

Steps to edit a scenario:

  1. Duplicate “New Project” folder where you want and rename it to your scenario name or whatever.
  2. Configure compiler constants in Compiler.php. (aok path and input/output scenario filename)
  3. As examples, write triggers, terrain modifications, etc… in Scenario.php ( inside Scenario() ).
  4. Run two times Compiler.php. (On PD8 click on “Run” button in toolbar)
  5. Done, you can test it.

There are some examples by default in Scenario.php which show you how to make triggers, place objects, modify terrain and other constants of your scenario.

Feel free to organize your code as you want, keep in mind that all you write is reusable code by you or other people. You can create your own framework specialized in RPGs, Bloods, SP maps, or whatever you want, just include files in Scenario.php.

You don’t need to understand how works Compiler.php to use this script, you just need to understand Library.php which is quite intuitive. However it is good to know how works Compiler.php to do really all you want with scenario designing.

From this point (with examples), you have all tools to learn more by yourself and get used to scripting. It will need time but worth it, scripting is very powerful and funny to handle to design complex mechanics maps.

Also you have to know keys for conditions and effects fields, don’t worry with time you will know them by heart:

P = Source Player ID [Integer]
E = Target Player ID [Integer]
U = Object Constant ID [Integer]
G = Object Group ID [Integer]
Y = Object Type ID [Integer]
A = Area [Array(Array(X,Y),Array(X,Y))]
L = Location [Array(X,Y)]
Q = Quantity [Integer]
R = Resource [Integer]
H = Technology ID [Integer]
I = Trigger Name [String]
X = Text [String]
T = Time [Integer]
N = Panel [Integer 0 | 1 | 2]
S = Objects IDs [Array(ID_1,ID_2,ID_3,…,ID_n)]
F = Object Source ID [Integer]
O = Object Location ID [Integer]
D = Sound [String]
M = Diplomacy [Integer 0 | 1 | 2 | 3]
Z = AI Signal / AI Goal [Integer]
K = Inverted condition (Only for 1.4 RC) [Boolean]

Important:

– Activation / Deactivation are set with trigger name, not id. So you have to be sure you don’t have multiple triggers with same name else it won’t work. Also you have to compile your code 2 times always to make these effects working.

Convert images as terrain

Requirements: You need to enable GD library, to do that open php.ini and replace these lines:


; extension_dir = "ext"
;extension=php_gd2.dll

by these lines:


extension_dir = "./ext"
extension=php_gd2.dll

It will unlock functions to read images.

  1. Put your image in indexed colors mode and save it as .png or .gif, to achieve this: Open your image in gimp 2 and switch in indexed color mode, now your image will have an id assigned to each colour. You can know this id by loading indexed color palette. The image should have same size as your map.
  2. In Scenario.php write SetTerrainFromImage(‘path_to_your_image’, terrain_ids). terrain_ids is an array that contains the terrains ids bound to colors ids. For example with an image that contains 3 colors we can do:

SetTerrainFromImage('C:/MyImage.png', array(
      0 => 4, # Bind color 0 to Shallows
      1 => 0, # Bind color 1 to Grass 1
      2 => 5  # Bind color 2 to Leaves
)); 

When you done that just run it and you have your awesome design. :D

Example:

Example Map

Library Functions

You should need this list if your IDE doesn’t have intelligent code completion or you are a notepad purist. This list is up to date, new functions should be added frequently. As well, any new stuff is notified in changelog. To know how to use them you can look them in Library.php, there are help comments for complex ones.

General:


out($data)
Trig($N = '', $S = 1, $L = 0, $P = 0, $E = 0, $D = '', $R = '')
NewObject($ID, $P, $U, $L, $R = 0, $G = -1, $F = 0)
Area($X1, $Y1, $X2, $Y2)
Color($P)

Triggers:


Cond_AISignal($Z)
Cond_Accumulate($P, $Q, $R)
Cond_AccumulateExactly($P, $Q, $R)
Cond_Alive($P)
Cond_BringOToA($F, $A)
Cond_BringOToO($F, $O)
Cond_Capture($P, $F)
Cond_Destroy($F)
Cond_Died($P)
Cond_Difficulty($difficultyName)
Cond_False($P, $R)
Cond_Garrisoned($F)
Cond_HasTarget($F, $O)
Cond_InAreaG($P, $Q, $G, $A)
Cond_InAreaO($P, $Q, $A)
Cond_InAreaU($P, $Q, $U, $A)
Cond_InAreaY($P, $Q, $Y, $A)
Cond_NotAISignal($Z)
Cond_NotAccumulate($P, $Q, $R)
Cond_NotBringOToA($F, $A)
Cond_NotBringOToO($F, $O)
Cond_NotCapture($P, $F)
Cond_NotDestroy($F)
Cond_NotDifficulty($difficultyName)
Cond_NotGarrisoned($F)
Cond_NotHasTarget($F, $O)
Cond_NotInAreaG($P, $Q, $G, $A)
Cond_NotInAreaO($P, $Q, $A)
Cond_NotInAreaU($P, $Q, $U, $A)
Cond_NotInAreaY($P, $Q, $Y, $A)
Cond_NotOwnG($P, $Q, $G)
Cond_NotOwnO($P, $Q)
Cond_NotOwnU($P, $Q, $U)
Cond_NotOwnY($P, $Q, $Y)
Cond_NotResearched($P, $H)
Cond_NotResearching($P, $H)
Cond_NotSelected($F)
Cond_NotTimer($T)
Cond_NotVisible($F)
Cond_OwnG($P, $Q, $G)
Cond_OwnO($P, $Q)
Cond_OwnU($P, $Q, $U)
Cond_OwnY($P, $Q, $Y)
Cond_Researched($P, $H)
Cond_Researching($P, $H)
Cond_Selected($F)
Cond_Timer($T)
Cond_True($P, $R)
Cond_Visible($F)
Efft_AIGoal($P, $Z)
Efft_APG($P, $Q, $G, $A = null)
Efft_APO($P, $Q, $A = null)
Efft_APS($Q, $S)
Efft_APU($P, $Q, $U, $A = null)
Efft_APY($P, $Q, $Y, $A = null)
Efft_Act($I)
Efft_ArmorG($P, $Q, $G, $A = null)
Efft_ArmorO($P, $Q, $A = null)
Efft_ArmorS($Q, $S)
Efft_ArmorU($P, $Q, $U, $A = null)
Efft_ArmorY($P, $Q, $Y, $A = null)
Efft_ChangeDiplomacy($P, $E, $stateName)
Efft_ChangeOwnerG($P, $G, $A = null, $E = 0)
Efft_ChangeOwnerO($P, $A = null, $E = 0)
Efft_ChangeOwnerS($S, $E = 0)
Efft_ChangeOwnerU($P, $U, $A = null, $E = 0)
Efft_ChangeOwnerY($P, $Y, $A = null, $E = 0)
Efft_ChangeView($P, $L)
Efft_Chat($P, $X)
Efft_Clear($N)
Efft_Create($P, $U, $L)
Efft_DamageG($P, $Q, $G, $A = null)
Efft_DamageO($P, $Q, $A = null)
Efft_DamageS($Q, $S)
Efft_DamageU($P, $Q, $U, $A = null)
Efft_DamageY($P, $Q, $Y, $A = null)
Efft_Deact($I)
Efft_DeclareVictory($P)
Efft_Display($T, $N, $X)
Efft_False($R, $R)
Efft_FreezeG($P, $G, $A = null)
Efft_FreezeO($P, $A = null)
Efft_FreezeS($S)
Efft_FreezeU($P, $U, $A = null)
Efft_FreezeY($P, $Y, $A = null)
Efft_Give($P, $Q, $R)
Efft_HPG($P, $Q, $G, $A = null)
Efft_HPO($P, $Q, $A = null)
Efft_HPS($Q, $S)
Efft_HPU($P, $Q, $U, $A = null)
Efft_HPY($P, $Q, $Y, $A = null)
Efft_KillG($P, $G, $A = null)
Efft_KillO($P, $A = null)
Efft_KillS($S)
Efft_KillU($P, $U, $A = null)
Efft_KillY($P, $Y, $A = null)
Efft_LockGate($S)
Efft_MSG($P, $Q, $G, $A = null)
Efft_MSO($P, $Q, $A = null)
Efft_MSS($Q, $S)
Efft_MSU($P, $Q, $U, $A = null)
Efft_MSY($P, $Q, $Y, $A = null)
Efft_NameO($P, $X, $A = null)
Efft_NameS($S, $X)
Efft_NameU($P, $X, $U, $A = null)
Efft_NameY($P, $X, $Y, $A = null)
Efft_PatrolG($P, $G, $A = null, $L)
Efft_PatrolO($P, $A = null, $L)
Efft_PatrolS($S, $L)
Efft_PatrolU($P, $U, $A = null, $L)
Efft_PatrolY($P, $Y, $A = null, $L)
Efft_PlaceFoundation($P, $U, $L)
Efft_PlaySound($P, $D)
Efft_RangeG($P, $Q, $G, $A = null)
Efft_RangeO($P, $Q, $A = null)
Efft_RangeS($Q, $S)
Efft_RangeU($P, $Q, $U, $A = null)
Efft_RangeY($P, $Q, $Y, $A = null)
Efft_RemoveG($P, $G, $A = null)
Efft_RemoveO($P, $A = null)
Efft_RemoveS($S)
Efft_RemoveU($P, $U, $A = null)
Efft_RemoveY($P, $Y, $A = null)
Efft_Research($P, $H)
Efft_Reset($P, $R)
Efft_Set($P, $Q, $R)
Efft_StopG($P, $G, $A = null)
Efft_StopO($P, $A = null)
Efft_StopS($S)
Efft_StopU($P, $U, $A = null)
Efft_StopY($P, $Y, $A = null)
Efft_TaskG($P, $G, $A = null, $LO)
Efft_TaskO($P, $A = null, $LO)
Efft_TaskS($S, $LO)
Efft_TaskU($P, $U, $A = null, $LO)
Efft_TaskY($P, $Y, $A = null, $LO)
Efft_Tribute($P, $Q, $R, $E = 0)
Efft_True($P, $R)
Efft_UnloadG($P, $G, $A = null, $L)
Efft_UnloadO($P, $A = null, $L)
Efft_UnloadS($S, $L)
Efft_UnloadU($P, $U, $A = null, $L)
Efft_UnloadY($P, $Y, $A = null, $L)
Efft_UnlockGate($S)

Triggers – Advanced:


Efft_Boost($P, $Params)
Efft_DeactPlayerTriggers($P)
Efft_Explosion($L, $Rayon = 0, $Filled = false)
Efft_InvincibleG($P, $G, $HP_For_Buildings = null, $A = null)
Efft_InvincibleO($P, $HP_For_Buildings = null, $A = null)
Efft_InvincibleS($S, $HP_For_Buildings = null)
Efft_InvincibleU($P, $U, $HP_For_Buildings = null, $A = null)
Efft_InvincibleY($P, $Y, $HP_For_Buildings = null, $A = null)

Properties:


GetAllTech()
GetMapSize()
GetMessageFailure()
GetMessageHints()
GetMessageHistory()
GetMessageObjective()
GetMessageScouts()
GetMessageVictory()
GetPlayerCiv($player)
GetPlayerDiplomacy($player)
GetPlayerDisabilityBuildingList($player)
GetPlayerDisabilityTechList($player)
GetPlayerDisabilityUnitList($player)
GetPlayerMaxPop($player)
GetPlayerName($player)
GetPlayerObjects($player)
GetPlayerStartAge($player)
GetPlayerStartFood($player)
GetPlayerStartGold($player)
GetPlayerStartStone($player)
GetPlayerStartView($player)
GetPlayerStartWood($player)
GetPlayersCount()
GetTerrainCell($x,$y)
SetAllTech($boolean)
SetMapSize($size)
SetMessageFailure($text)
SetMessageHints($text)
SetMessageHistory($text)
SetMessageObjective($text)
SetMessageScouts($text)
SetMessageVictory($text)
SetPlayerCiv($player, $civName)
SetPlayerDiplomacy($player, $diplomacyStates)
SetPlayerDisabilityBuildingList($player, $idsArray)
SetPlayerDisabilityTechList($player, $idsArray)
SetPlayerDisabilityUnitList($player, $idsArray)
SetPlayerMaxPop($player, $maxPop)
SetPlayerName($player, $name)
SetPlayerObjects($player, $objects)
SetPlayerStartAge($player, $ageName)
SetPlayerStartFood($player, $quantity)
SetPlayerStartGold($player, $quantity)
SetPlayerStartStone($player, $quantity)
SetPlayerStartView($player, $location, $objectIdAvailable, $objectConstantId)
SetPlayerStartWood($player, $quantity)
SetPlayersCount($playersCount)
SetTerrainCell($x,$y,$cell)
SetTerrainFromImage($filename, $terrainIds)

Areas:


Area($X1, $Y1, $X2, $Y2)
AreaAdvanced($L, $Axe, $Width = 3, $Depth = 2)
AreaCut($A, $Cuts = 1)
AreaMerge($Areas)
AreaOffset($A, $OffsetX = 0, $OffsetY = 0)
AreaPlayer($P, $A)
AreaPlayers($Area, $StepX = 0, $StepY = 0, $Players = 0)
AreaPts($A)
AreaSet($L, $Size = 1)

Do you want to comment on this article? Thank the author? Tribute resources for its improvement? Raze it to the ground?

Come by and visit its thread in the University Forum!