Javascript API documentation

For AI and campaign script related discussions and questions
Post Reply
User avatar
aubergine
Professional
Professional
Posts: 3459
Joined: 10 Oct 2010, 00:58
Contact:

Re: Javascript API documentation

Post by aubergine »

Couldn't you keep an array of what your trucks are building and update it when you set truck order and again when the building is finished?
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO
User avatar
aubergine
Professional
Professional
Posts: 3459
Joined: 10 Oct 2010, 00:58
Contact:

Re: Javascript API documentation

Post by aubergine »

@per I noticed a playerData object in rules.js - any info on it's properties? Or, better, where can I find the code that makes objects/properties/etc., available to the JS API in git as then I can probably answer a lot of these questions myself?

Found where they are defined: https://github.com/Warzone2100/warzone2 ... tfuncs.cpp
"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: 6226
Joined: 24 Dec 2009, 11:35
Location: /var/zone

Re: Javascript API documentation

Post by NoQ »

aubergine wrote:Couldn't you keep an array of what your trucks are building and update it when you set truck order and again when the building is finished?
We've been advised not to store objects globally (?)
User avatar
aubergine
Professional
Professional
Posts: 3459
Joined: 10 Oct 2010, 00:58
Contact:

Re: Javascript API documentation

Post by aubergine »

Store it internally or as a property on an instantiated class or function, or in an activation object?

Quickest way:

Code: Select all

function foo() { ... }
foo.nonGlobalArray = []; // reference anywhere in your script as foo.nonGlobalArray
Approach if you want to make the array private:

Code: Select all

var myFunction = (function() {
  var myPrivateArray = [];
  return function() {
    // do stuff with array here
  }
})();
You can create class definitions in a similar way to give multiple methods (but not superclass methods) access to the array.
"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: 6226
Joined: 24 Dec 2009, 11:35
Location: /var/zone

Re: Javascript API documentation

Post by NoQ »

That's not the point. The point is that
You only get a snapshot of their state, the state is not updated
We aren't allowed to store an array of all our trucks. If in some other function call we are given a truck and we want to find it in our array, we won't be able to do that, cause it will be a completely different object by that time. We may use droid ids for identifying trucks, but we are not allowed to do that either.
User avatar
aubergine
Professional
Professional
Posts: 3459
Joined: 10 Oct 2010, 00:58
Contact:

Re: Javascript API documentation

Post by aubergine »

Looking at the WZ source code, from what I can see a droid's ID remains the same through it's lifecycle - ie. from when it first appears on the map until the point at which it's destroyed. And, if I understand the C++ code correctly, the same ID will not be used again during a game.

The issue with IDs is not so much in storing the ID (which is just a 32 bit integer) but more the fact that getDroidFromID() is likely still under construction and subject to future change (it's really more of a getObjectFromID() as Per mentioned earlier).

However, in your case it sounds like you want to know what each of your trucks are doing, so you could do something like this:

Code: Select all

/* Note:
    structureType = type of structure (constant), only used in myOrderDroidBuild()
    structureObj = actual structure object (structure object), not type of structure
*/

var truckRoster = [];

function myOrderDroidBuild(droid,order,structureType,x,y) {
  orderDroidBuild(droid,order,structureType,x,y);
  truckRoster.push({id:droid.id,task:x+","+y}); // building will be at this exact location, so we can use location as task id
}

function helpBuild(droid,structureObj) {
  order droid to help build structure; // can't remember what function call does this
  truckRoster.push({id:droid.id,task:structureObj.x+","+structureObj.y});
}

// <whatever> could be a compound string of x,y,structuretype
function howManyDroidsBuilding(structureObj) {
  var ret = [];
  var truck = truckRoster.length;
  var task = structureObj.x+","+structureObj.y;
  while (-1<--truck) if (truckRoster[truck].task == task) ret.push(truckRoster[truck].id);
  return ret; // looking at length of this array tells you how many trucks are doing <whatever>
}

function truckIdle(droid) {
  var truck = truckRoster.length;
  while (-1<--truck) if (truckRoster[truck].id == droid.id) truckRoster[truck].task = null;
}
function eventDroidIdle(droid) {
  if (droid.droidType == DROID_CONSTRUCT) truckIdle(droid);
}

function eventDroidDestroyed(droid) {
  if (droid.droidType == DROID_CONSTRUCT) {
    var truck = truckRoster.length;
    while (-1<--truck) if (truckRoster[truck].id == droid.id) truckRoster.splice(truck,1);
  }
}

function eventDroidBuilt(droid,structure) {
  // bind will call a function when a droid is destroyed
  bind("eventDroidDestroyed",{id:droid.id,droidType:droid.droidType});
}
Would something like that suffice as an interim way of keeping track of what trucks are doing?
Last edited by aubergine on 18 Jan 2012, 18:28, edited 3 times in total.
"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: 6226
Joined: 24 Dec 2009, 11:35
Location: /var/zone

Re: Javascript API documentation

Post by NoQ »

We can't find out if a truck was killed before finishing the task without some form of getDroidFromId() anyway, right?
User avatar
aubergine
Professional
Professional
Posts: 3459
Joined: 10 Oct 2010, 00:58
Contact:

Re: Javascript API documentation

Post by aubergine »

I've updated my code in post above to be more complete, including detection of destroyed droids.

EDIT: And if you call a truck away to do something else you'd need to update truckRoster() accordingly. So it's not an ideal way of doing things but might tide you over until API gets updated.
"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: 6226
Joined: 24 Dec 2009, 11:35
Location: /var/zone

Re: Javascript API documentation

Post by NoQ »

Ok, this might work, thanks! (:

But still, that's a whole bunch of code instead of adding a trivial object property ... probably we shouldn't hurry with that and wait for an official reply instead.
User avatar
aubergine
Professional
Professional
Posts: 3459
Joined: 10 Oct 2010, 00:58
Contact:

Persistence in JS API

Post by aubergine »

@NoQ - ya, getting more properties and events exposed will certainly be a big help. I think at some point it might be worth taking a holistic view of the API and seeing if we can make everything nice and consistent in terms of naming conventions, etc., as well.

@Per - some thoughts on persistence...

I think it would perhaps be best if only a specific named variable got put in the savegame, eg. "persistedData" which would be a normal object.

Reason: Developers are human

No matter how hard AI developers try, they're going to end up creating crufty global vars at some point in time - either due to inexperience, carelessness, or mistake.

Also, developers will inadvertently end up with functions and other more complex objects getting in to global vars as well. Consider the case of a global var containing an object with a circular reference, or a class instance (ie. having custom prototype chain), etc.

So I think it would be better to just say: "If you want data persisted when the game is saved, put it in the global persistedData object. You can store basic arrays, objects and primitive values, but don't store any custom class instances, functions or game objects in there as they will break when the savegame is loaded."

This approach:

a) Makes developers think more carefully about what they want saving
b) Makes developers take more care over how they define that data
c) Avoids savegames getting filled with random global var cruft
d) Makes it unambiguous to devs what data will get loaded from a savegame

I really don't think the game should be saving all global vars, or trying to persist game objects. There are some cases where making developers lives a little harder gives better results, and this is one of them IMHO.
"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: 6226
Joined: 24 Dec 2009, 11:35
Location: /var/zone

Re: Javascript API documentation

Post by NoQ »

By the way, do we have any "eventGameLoaded()" that is called every time a game was restored from a saved state? Just to re-calculate some variables that aren't supposed to be stored or can't be stored.
User avatar
aubergine
Professional
Professional
Posts: 3459
Joined: 10 Oct 2010, 00:58
Contact:

Re: Javascript API documentation

Post by aubergine »

currently I'd achieve that sort of thing as follows:

Code: Select all

// define global var to track if we're starting fresh or from savegame
var savegame = false;

.....

function eventStartLevel() {
  if (savegame) {
    // a save game was loaded
    ...
  } else {
    // we're starting fresh
    ...
    savegame = true;
  }
  // do stuff here that always needs doing regardless of whether it's new or savegame
}
"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: 6226
Joined: 24 Dec 2009, 11:35
Location: /var/zone

Re: Javascript API documentation

Post by NoQ »

Good point (:
Per
Warzone 2100 Team Member
Warzone 2100 Team Member
Posts: 3780
Joined: 03 Aug 2006, 19:39

Re: Javascript API documentation

Post by Per »

Except eventStartLevel() is not called on game load... If need be, I can add an eventGameLoaded().

Here are my current thoughts on persistence API:

Groups. I intend to change their implementation to be more general (allowing droids to be member of multiple groups, eg), but they are already a good way to store droid information persistently. They are saved and loaded. Whenever a droid is destroyed, it is immediately removed from the group.

Globals. You can put as many variables as you want on the global object, and then will be saved and restored. However, the saving/loading code may not be very intelligent, so complex objects may confuse it and lead to bugs. I have not tested this, so most objects may actually work fine. However, saving game objects that you get from eg enumDroid() to global is always a mistake.

I want to add a new persistent structure that I have called 'annotations' so far. Basically they are custom fields added to any game object, and that are added under a .notes object attached to them when you get them from the scripting API. Eg you could call "annotate(oil, "hqSentToBuild", gameTime);" to add a oil.notes.hqSentToBuild property that contains the gameTime that you last sent a droid to build on that oil resource. (I think it is is a good idea to add them under a .notes hierarchy to avoid future name collisions.)

You cannot not use the above to store one game object in another, though. Eg you could store the attack target of a droid, but that would only give you the snapshot information of that object when you added it, so querying that information later would be next to useless.

So another idea that I am toying with is a similar structure for storing links to game objects. For example, "link(droid, "build", oil);" would add the .notes.builder property to droid, and if it is read later, it is updated to the latest information, and if either object is destroyed, then the property is removed automatically. (The ideal would be to detect that the type passed to annotate() is a game object, and do this automatically, but since javascript is untyped, there seems to be no good way to do this.)
Per
Warzone 2100 Team Member
Warzone 2100 Team Member
Posts: 3780
Joined: 03 Aug 2006, 19:39

Re: Javascript API documentation

Post by Per »

NoQ wrote:How do i find out wether a VTOL droid is fully recharged?
Added 'armed' property to vtol droids (only), which is a percentage of how fully armed it is. (Also fixed embarrassing health calculation bug.)
Post Reply