3.2 JS API Wishlist :)

For AI and campaign script related discussions and questions
Post Reply
User avatar
Duha
Trained
Trained
Posts: 287
Joined: 25 Mar 2012, 20:05
Location: SPb, Russia

Re: 3.2 JS API Wishlist :)

Post by Duha » 16 Nov 2012, 09:22

aubergine wrote: I like the idea of reading the stats files, maybe as the files get converted to .ini format, some functions could be added to allow js to read those files, or better still, have some globals that provide the data in ready-made objects?

<global>.ini = {}

<global>.ini.ecm = object containing a JS representation of ecm.ini

...etc?
It that case json is better than ini :)

Reading weapon data files will not help you. Research change it during games.
http://addons.wz2100.net/ developer

User avatar
aubergine
Professional
Professional
Posts: 3459
Joined: 10 Oct 2010, 00:58
Contact:

Re: 3.2 JS API Wishlist :)

Post by aubergine » 16 Nov 2012, 09:26

@Duha - I originally wanted the stats in JSON format, but as time has passed I've come to the conclusion that .ini files are better from a modding perspective. And they are still easy to convert to JS objects.

As for weapon data files, yes, I know research will change things, but I can quite easily write a wrapper API for dealing with that sort of thing, and I'll learn a lot about how the internal mechanics of the game works in the process, and I'll be documenting stuff along the way.

EDIT: Also, see my revised ideas about functions to import ini data -- I think these would give us scripters a lot of room to play around with different ways of representing and processing the data.
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO

User avatar
NoQ
Special
Special
Posts: 6225
Joined: 24 Dec 2009, 11:35
Location: /var/zone

Re: 3.2 JS API Wishlist :)

Post by NoQ » 16 Nov 2012, 09:50

Just curious: why not import the whole ini into a single object, whose sections are property objects having its fields as properties?

User avatar
aubergine
Professional
Professional
Posts: 3459
Joined: 10 Oct 2010, 00:58
Contact:

Re: 3.2 JS API Wishlist :)

Post by aubergine » 16 Nov 2012, 10:40

@NoQ: As a longer term goal, I think that would make sense. However, initially I would like the ability to build those object myself so I can find a desirable format for them. It's trivially easy for me to write a little API that automates it (and will make it easy for others to use same code) but I think some trial and error is required to get a really nice format for the objects.

As Duha mentioned, things like weapon stats change based on research. So for the weapon stats ini I'd probably want define my own object classes with dynamic properties, rather than just have static data from the ini file. I imagine quite a few other things will behave similarly. I don't want to waste loads of Per's time over the ini stuff -- the basic functions enumIniFiles(), enumIniSections() and iniSection() should be relatively straightforward for Per to implement and give us scripters maximum flexibility for how we want to work with the resulting data.

To build a basic ini object structure is trivial for any scripter to do:

Code: Select all

// put this in to a .js file and include it

void (function buildIniObject(_global) {

    var getFolderAndName = function(iniFile) {
        var path = iniFile.split("/");
        var name = path.pop(); // get file.ext from end of path
        name = name.split(".").shift(); // remove extension from name
        path = path.pop(); // get last folder in path
        return {folder:path, name:name};
    }

    _global.ini = {};

    enumIniFiles("base/stats/*.ini").forEach(function(iniFile) {
        var file = getFolderAndName(iniFile);
        if (!_global.ini.hasOwnProperty(file.folder)) _global.ini[file.folder] = {}; // eg. ini.stats = {}
        _global.ini[file.folder][file.name] = {}; // eg. ini.stats.ecm
        enumIniSections(iniFile).forEach(function(section) {
           _global.ini[file.folder][file.name][section] = iniSection(iniFile, section);
        });
    });

})(this);

// then in your main script

// weight property from [wheeled03] section in base/stats/propulsion.ini can be accessed via:
ini.stats.propulsion.wheeled03.weight

// but you could also do

ini.propulsion = function(droid) {
    try {
        return this.stats.populsion[droid.propulsion];
    } catch(e) { // must be missing
        return this.stats.propulsion.ZNULLPROP;
    }
}

ini.propulsion(myDroid).weight; // gets propulsion weight of your droid

// or you could replace the propulsion property of a droid with the stats object...
myDroid.propulsion = ini.propulsion(myDroid);

myDroid.propulsion.weight // weight of propulsion for that droid

// etc......
That code builds a complete data structure representing the ini files in the stats folder, and I've shown how you can easily start extending it to make common tasks easier. The possibilities are endless.

But I'd want something more elaborate. I'd want to grab the ZNULL section from each ini file and insert that in to the prototype chain of each of the section objects, so that it acts as the default properties and values for the sections. I'd want to replace certain properties in certain ini files with getter/setter accessor properties that run some algorithm to take account of research, etc. I'd want to make sure all properties are immutable to avoid accidental deletion or assignment by code elsewhere. I'd want to add some helper methods to the stats object, eg. stats.droidStats(droid) would return a bunch of detailed info about the droid passed in (or just add extra properties to that droid object). Or I might want to change the prototype chain of all droid objects so that they have loads of new properties that pull data from the stats directly. This ability to play around with the structure is really important to find the best way of interacting with it.

Also, remember that ini files are used for more than just stats. For example, the config file is an ini file. I might want to read that to get screen height/width so that I can set up a cinematic scene properly based on the users screen size. I might want to read a .ai file to get extra data out of it. Or read .ini files in challenges/ folder to see what challenges are available. Or read the ini associated with the current map? Or I might not. So having these functions lets the script decide what ini file's it's interested in, what sections it's interested in and what data structures it wants to work with, etc.
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO

User avatar
Duha
Trained
Trained
Posts: 287
Joined: 25 Mar 2012, 20:05
Location: SPb, Russia

Re: 3.2 JS API Wishlist :)

Post by Duha » 16 Nov 2012, 12:11

aubergine wrote:@NoQ: As a longer term goal, I think that would make sense. However, initially I would like the ability to build those object myself so I can find a desirable format for them. It's trivially easy for me to write a little API that automates it (and will make it easy for others to use same code) but I think some trial and error is required to get a really nice format for the objects.

As Duha mentioned, things like weapon stats change based on research. So for the weapon stats ini I'd probably want define my own object classes with dynamic properties, rather than just have static data from the ini file. I imagine quite a few other things will behave similarly. I don't want to waste loads of Per's time over the ini stuff -- the basic functions enumIniFiles(), enumIniSections() and iniSection() should be relatively straightforward for Per to implement and give us scripters maximum flexibility for how we want to work with the resulting data.

To build a basic ini object structure is trivial for any scripter to do:

Code: Select all

// put this in to a .js file and include it

void (function buildIniObject(_global) {

    var getFolderAndName = function(iniFile) {
        var path = iniFile.split("/");
        var name = path.pop(); // get file.ext from end of path
        name = name.split(".").shift(); // remove extension from name
        path = path.pop(); // get last folder in path
        return {folder:path, name:name};
    }

    _global.ini = {};

    enumIniFiles("base/stats/*.ini").forEach(function(iniFile) {
        var file = getFolderAndName(iniFile);
        if (!_global.ini.hasOwnProperty(file.folder)) _global.ini[file.folder] = {}; // eg. ini.stats = {}
        _global.ini[file.folder][file.name] = {}; // eg. ini.stats.ecm
        enumIniSections(iniFile).forEach(function(section) {
           _global.ini[file.folder][file.name][section] = iniSection(iniFile, section);
        });
    });

})(this);

// then in your main script

// weight property from [wheeled03] section in base/stats/propulsion.ini can be accessed via:
ini.stats.propulsion.wheeled03.weight

// but you could also do

ini.propulsion = function(droid) {
    try {
        return this.stats.populsion[droid.propulsion];
    } catch(e) { // must be missing
        return this.stats.propulsion.ZNULLPROP;
    }
}

ini.propulsion(myDroid).weight; // gets propulsion weight of your droid

// or you could replace the propulsion property of a droid with the stats object...
myDroid.propulsion = ini.propulsion(myDroid);

myDroid.propulsion.weight // weight of propulsion for that droid

// etc......
That code builds a complete data structure representing the ini files in the stats folder, and I've shown how you can easily start extending it to make common tasks easier. The possibilities are endless.

But I'd want something more elaborate. I'd want to grab the ZNULL section from each ini file and insert that in to the prototype chain of each of the section objects, so that it acts as the default properties and values for the sections. I'd want to replace certain properties in certain ini files with getter/setter accessor properties that run some algorithm to take account of research, etc. I'd want to make sure all properties are immutable to avoid accidental deletion or assignment by code elsewhere. I'd want to add some helper methods to the stats object, eg. stats.droidStats(droid) would return a bunch of detailed info about the droid passed in (or just add extra properties to that droid object). Or I might want to change the prototype chain of all droid objects so that they have loads of new properties that pull data from the stats directly. This ability to play around with the structure is really important to find the best way of interacting with it.

Also, remember that ini files are used for more than just stats. For example, the config file is an ini file. I might want to read that to get screen height/width so that I can set up a cinematic scene properly based on the users screen size. I might want to read a .ai file to get extra data out of it. Or read .ini files in challenges/ folder to see what challenges are available. Or read the ini associated with the current map? Or I might not. So having these functions lets the script decide what ini file's it's interested in, what sections it's interested in and what data structures it wants to work with, etc.

All you need: readfile() # read file inside game folder. if not file found return '' or exception ()
Other features can be done via js (parse ini to object and others).
http://addons.wz2100.net/ developer

User avatar
aubergine
Professional
Professional
Posts: 3459
Joined: 10 Oct 2010, 00:58
Contact:

Re: 3.2 JS API Wishlist :)

Post by aubergine » 16 Nov 2012, 15:32

@Duha, yes but is that not getting excessively low level?

Also, when quoting forum comments, could you trim the quote down to the applicable content -- quoting entire posts just to reply with a two line comment seems excessive :lecture:
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO

User avatar
Shadow Wolf TJC
Regular
Regular
Posts: 1047
Joined: 16 Apr 2011, 05:12
Location: Raleigh, NC

Re: 3.2 JS API Wishlist :)

Post by Shadow Wolf TJC » 17 Nov 2012, 06:59

Ideas for use with cooperative AI players:

placeBeacon(x,y): Places a beacon at the designated coordinates.

eventBeaconPlaced(x,y,sender): Triggers whenever a beacon is placed on the map.

With these functions, AI designers could enable their AIs to better coordinate attacks with their allies.
Creator of Warzone 2100: Contingency!
Founder of Wikizone 2100: http://wikizone2100.wikia.com/wiki/Wikizone_2100

User avatar
aubergine
Professional
Professional
Posts: 3459
Joined: 10 Oct 2010, 00:58
Contact:

Re: 3.2 JS API Wishlist :)

Post by aubergine » 17 Nov 2012, 19:19

@Shadow: Page 1 of this topic, first post, 3rd wish... keep up ;)
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO

User avatar
Shadow Wolf TJC
Regular
Regular
Posts: 1047
Joined: 16 Apr 2011, 05:12
Location: Raleigh, NC

Re: 3.2 JS API Wishlist :)

Post by Shadow Wolf TJC » 23 Nov 2012, 05:00

Sorry if this has already been proposed before, but I have a few new ideas for functions (most of which would be of benefit for so-called "support structures"):

eventStructureActivated(structure, target): This function would be called whenever a support structure, such as a LasSat Command Post, was activated, regardless of who owns the structure (so that functions that are called when this event is called in rules.js wouldn't normally cause desyncs in multiplayer). The target property could be either an object, or a location. This would not only enable AIs to react to LasSats that don't target themselves directly (such as prompting an AI allied with the structure's owner to launch an attack on the victim), but would also allow for the creation of custom support structures that could provide map-wide or area-wide effects that don't necessarily involve destroying enemy units, such as revealing the entire map, or parts of the map, or jamming all enemy sensors on the map, rendering them temporarily unable to spot targets for artillery bombardment.

revealMap(player, enable/disable): This function would manually enable/disable the player's ability to see the entire map, as if the player built/lost a Satellite Uplink, or (de)activated the "deity" cheat, allowing for a spectator mode to be implemented without requiring spectators to have a Satellite Uplink, or any kind of physical presence for that matter (especially when used alongside the setMiniMap() function). It would also allow for the creation of support structures that would only reveal the entire map for a short period of time (much like the Strategy Center or Satellite Hack from Command & Conquer: Generals), as opposed to the Satellite Uplink constantly revealing the entire map as long as the structure stands. (Speaking of, the Satellite Uplink could be unhardcoded and its functionality written in rules.js if such a function was implemented.)

fireAtTarget(object, target): Normally used in eventStructureActivated(), it orders a unit or structure with a weapon equipped, such as a LasSat Command Post, to fire at the designated game or location object using its equipped weapon. Would allow for the creation of custom superweapons, such as, for example, a tactical howitzer or missile launcher that fires EMPs with a wide splash radius towards distant locations. (Would also add some incentive to unhardcode the LasSat Command Post's functionality and write its programming in rules.js.)

freezeObject(object, duration): The target object will be unable to move or take action for the designated amount of time, as if struck by an EMP. Would be useful with eventAttackedUnthrottled()... if the event was called regardless of who owned the object that was attacked.

adjustDroidSpeed(droid, speed multiplier, duration): Applies a multiplier to the targeted droid's speed, either slowing it down, or speeding it up. Could be used to develop custom objects or support powers that can either speed up friendly droids, or slow down enemy droids. Could also be used by modders to adjust the speed of all of a player's droids once that player has researched a particular tech (assuming that eventResearched() is adjusted so that it's called whenever ANY player researches the given tech).

eventAttacking(attacker, target): This is called whenever an object fires its weapon, regardless of who owns the object. This would allow modders to, say, have cloaked units decloak while attacking another object.

setObjectColor(object, alpha, red, green, blue): Applies a colored filter to the target object. Useful for creating special effects with the object. For example, an object which is disabled via EMP could appear darker than usual to indicate that it's powered down, or an object could appear to be glowing brightly to indicate that it is invulnerable or shielded.

setObjectTransparencyToPlayer(object, player, transparency): Sets the target object's transparency (the degree of how others can see through the object) towards the target player. It could allow modders to program certain objects (such as stealth units) to become invisible to all players' eyes, unless the player controls the object, unless the object attacks, or unless the object is within a certain distance of a certain other object (all of which could also be programmed in using rules.js), in which case, the object could appear as half-visible, or fully visible while attacking.

Also, I'd like to have objects be given the "damageable" property, which could allow certain droids or structures, through certain scripts (such as the addition of a makeObjectDamageable(true/false) function), to not only become invulnerable, but also untargetable by anyone (though the owner of the object could still be able to select it). This would allow modders to create objects that could, say, be added onto the map when a certain support power is activated, and give visibility over a certain location without being targetable or visible (essentially providing an effect similar to a radar scan support power, as seen in games such as StarCraft 2 or Command & Conquer), or could render the target unit or structure invulnerable to damage (similar to the Iron Curtain support power from Command & Conquer: Red Alert 1-3).
Creator of Warzone 2100: Contingency!
Founder of Wikizone 2100: http://wikizone2100.wikia.com/wiki/Wikizone_2100

User avatar
aubergine
Professional
Professional
Posts: 3459
Joined: 10 Oct 2010, 00:58
Contact:

Re: 3.2 JS API Wishlist :)

Post by aubergine » 23 Nov 2012, 13:45

Having some control over droid speed would be useful for coordinated attacks. You could find the slowest droid in the group and make all others slow down to that speed, so they'd move as a group without constantly needing to regroup them.
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO

User avatar
NoQ
Special
Special
Posts: 6225
Joined: 24 Dec 2009, 11:35
Location: /var/zone

Re: 3.2 JS API Wishlist :)

Post by NoQ » 26 Nov 2012, 17:02

aubergine wrote: Beacons API
+1, just wanted to use some of these (: Related: I think playSound doesn't work as intended when used in an AI script.

Per
Warzone 2100 Team Member
Warzone 2100 Team Member
Posts: 3775
Joined: 03 Aug 2006, 19:39

Re: 3.2 JS API Wishlist :)

Post by Per » 26 Nov 2012, 19:13

NoQ wrote:Related: I think playSound doesn't work as intended when used in an AI script.
If 'me' is not the human host player, it does nothing. This is by design, and is also how it was in wzscript... Why do you want to make sounds for another player from an AI script?

User avatar
NoQ
Special
Special
Posts: 6225
Joined: 24 Dec 2009, 11:35
Location: /var/zone

Re: 3.2 JS API Wishlist :)

Post by NoQ » 26 Nov 2012, 19:49

Emm, just it's the only way to place a beacon currently.

User avatar
aubergine
Professional
Professional
Posts: 3459
Joined: 10 Oct 2010, 00:58
Contact:

Re: 3.2 JS API Wishlist :)

Post by aubergine » 26 Nov 2012, 21:06

Actually the playSound() way of doing beacons seems broken even when used in rules.js. In Enhanced SitRep Mod, each time there is an event playSound() should be showing a beacon - at first I thought it was, but then I realised only the hard-coded sitrep in the C++ code is showing beacons and not stuff done from JS API.
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO

Per
Warzone 2100 Team Member
Warzone 2100 Team Member
Posts: 3775
Joined: 03 Aug 2006, 19:39

Re: 3.2 JS API Wishlist :)

Post by Per » 26 Nov 2012, 23:16

NoQ wrote:Emm, just it's the only way to place a beacon currently.
I think you must be mistaken... from what I can tell, the playSound{Pos}() calls in wzscript do not place beacons, nor does the new one in javascript.

Post Reply