Script integration work - valueOf() is no longer required most of the time; also property-change watches and enumeration over entities (but not yet other native objects), rudimentary beginnings of a global events system, and adjusted the status orb to update only on changes.
This was SVN commit r2157.
This commit is contained in:
parent
498d58ee61
commit
bcabe3aa53
@ -22,13 +22,13 @@ function entity_event_gather( evt )
|
|||||||
{
|
{
|
||||||
if( evt.target.traits.supply.curr <= gather_amt )
|
if( evt.target.traits.supply.curr <= gather_amt )
|
||||||
{
|
{
|
||||||
gather_amt = evt.target.traits.supply.curr;
|
gather_amt = evt.target.traits.supply.curr;
|
||||||
evt.target.kill();
|
evt.target.kill();
|
||||||
}
|
}
|
||||||
console.write( evt.target.traits.supply.type);
|
console.write( evt.target.traits.supply.type);
|
||||||
console.write( evt.target.traits.supply.type.toString().toUpperCase() );
|
console.write( evt.target.traits.supply.type.toString().toUpperCase() );
|
||||||
evt.target.traits.supply.curr -= gather_amt;
|
evt.target.traits.supply.curr -= gather_amt;
|
||||||
this.player.resource.valueOf()[evt.target.traits.supply.type.toString().toUpperCase()] += gather_amt;
|
this.player.resource[evt.target.traits.supply.type.toString().toUpperCase()] += gather_amt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,19 +130,31 @@ function entity_event_targetchanged( evt )
|
|||||||
// hidden from you) and comparing an object to any other object in JavaScript (1.5, at least)
|
// hidden from you) and comparing an object to any other object in JavaScript (1.5, at least)
|
||||||
// yields false. ToString converts them to their actual values (i.e. the four character
|
// yields false. ToString converts them to their actual values (i.e. the four character
|
||||||
// string) first.
|
// string) first.
|
||||||
|
|
||||||
evt.defaultAction = ORDER_GOTO;
|
evt.defaultAction = ORDER_GOTO;
|
||||||
|
evt.defaultCursor = "arrow-default";
|
||||||
if( evt.target )
|
if( evt.target )
|
||||||
{
|
{
|
||||||
if( this.actions.attack &&
|
if( this.actions.attack &&
|
||||||
( evt.target.traits.id.civ_code != "gaia" ) &&
|
( evt.target.player != gaiaPlayer ) &&
|
||||||
( evt.target.traits.id.civ_code.toString() != this.traits.id.civ_code.toString() ) )
|
( evt.target.player != this.player ) )
|
||||||
evt.defaultAction = ORDER_ATTACK;
|
{
|
||||||
|
evt.defaultAction = ORDER_ATTACK;
|
||||||
|
evt.defaultCursor = "action-attack";
|
||||||
|
}
|
||||||
if( this.actions.gather && evt.target.traits.supply &&
|
if( this.actions.gather && evt.target.traits.supply &&
|
||||||
this.actions.gather[evt.target.traits.supply.type] &&
|
this.actions.gather[evt.target.traits.supply.type] &&
|
||||||
( ( evt.target.traits.supply.curr > 0 ) || ( evt.target.traits.supply.max == 0 ) ) )
|
( ( evt.target.traits.supply.curr > 0 ) || ( evt.target.traits.supply.max == 0 ) ) )
|
||||||
|
{
|
||||||
evt.defaultAction = ORDER_GATHER;
|
evt.defaultAction = ORDER_GATHER;
|
||||||
}
|
if( evt.target.traits.supply.type == "wood" )
|
||||||
|
{
|
||||||
|
evt.defaultCursor = "action-chop";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
evt.defaultCursor = "action-mine";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function entity_event_prepareorder( evt )
|
function entity_event_prepareorder( evt )
|
||||||
@ -161,11 +173,8 @@ function entity_event_prepareorder( evt )
|
|||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
break;
|
break;
|
||||||
case ORDER_ATTACK:
|
case ORDER_ATTACK:
|
||||||
// If we can't attack, we're not targeting a unit, or that unit is the same civ as us.
|
|
||||||
// (Should of course be same /player/ as us - not ready yet.)
|
|
||||||
if( !this.actions.attack ||
|
if( !this.actions.attack ||
|
||||||
!evt.target ||
|
!evt.target )
|
||||||
( evt.target.traits.id.civ_code.toString() == this.traits.id.civ_code.toString() ) )
|
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
break;
|
break;
|
||||||
case ORDER_GATHER:
|
case ORDER_GATHER:
|
||||||
@ -191,10 +200,11 @@ function entity_add_create_queue( template, list, tab )
|
|||||||
comboTemplate.tab = tab;
|
comboTemplate.tab = tab;
|
||||||
|
|
||||||
// Append to the end of this queue
|
// Append to the end of this queue
|
||||||
this.actions.create.queue.valueOf().push( comboTemplate );
|
|
||||||
|
this.actions.create.queue.push( template );
|
||||||
|
|
||||||
// If we're not already building something...
|
// If we're not already building something...
|
||||||
if( !this.actions.create.progress || !this.actions.create.progress.valueOf() )
|
if( !this.actions.create.progress )
|
||||||
{
|
{
|
||||||
console.write( "Starting work on (unqueued) ", template.tag );
|
console.write( "Starting work on (unqueued) ", template.tag );
|
||||||
// Start the progress timer.
|
// Start the progress timer.
|
||||||
@ -218,7 +228,7 @@ function entity_create_complete()
|
|||||||
// at http://www.mozilla.org/js/language/E262-3.pdf. Bit technical but
|
// at http://www.mozilla.org/js/language/E262-3.pdf. Bit technical but
|
||||||
// the sections on 'Native ECMAScript Objects' are quite useful)
|
// the sections on 'Native ECMAScript Objects' are quite useful)
|
||||||
|
|
||||||
var template = this.actions.create.queue.valueOf().shift();
|
var template = this.actions.create.queue.shift();
|
||||||
|
|
||||||
// Code to find a free space around an object is tedious and slow, so
|
// Code to find a free space around an object is tedious and slow, so
|
||||||
// I wrote it in C. Takes the template object so it can determine how
|
// I wrote it in C. Takes the template object so it can determine how
|
||||||
@ -232,26 +242,26 @@ function entity_create_complete()
|
|||||||
// Oh well. The player's just lost all the resources and time they put into
|
// Oh well. The player's just lost all the resources and time they put into
|
||||||
// construction - serves them right for not paying attention to the land
|
// construction - serves them right for not paying attention to the land
|
||||||
// around their barracks, doesn't it?
|
// around their barracks, doesn't it?
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
created = new Entity( template, position );
|
||||||
|
|
||||||
created = new Entity( template, position );
|
// Above shouldn't ever fail, but just in case...
|
||||||
|
if( created )
|
||||||
// Above shouldn't ever fail, but just in case...
|
{
|
||||||
if( !created )
|
console.write( "Created: ", template.tag );
|
||||||
return;
|
|
||||||
|
|
||||||
console.write( "Created: ", template.tag );
|
|
||||||
|
|
||||||
// Entities start under Gaia control - make the controller
|
|
||||||
// the same as our controller
|
|
||||||
created.player = this.player;
|
|
||||||
|
|
||||||
|
// Entities start under Gaia control - make the controller
|
||||||
|
// the same as our controller
|
||||||
|
created.player = this.player;
|
||||||
|
}
|
||||||
|
}
|
||||||
// If there's something else in the build queue...
|
// If there's something else in the build queue...
|
||||||
if( this.actions.create.queue.valueOf().length > 0 )
|
if( this.actions.create.queue.length > 0 )
|
||||||
{
|
{
|
||||||
// Start on the next item.
|
// Start on the next item.
|
||||||
template = this.actions.create.queue.valueOf()[0];
|
template = this.actions.create.queue[0];
|
||||||
console.write( "Starting work on (queued) ", template.tag );
|
console.write( "Starting work on (queued) ", template.tag );
|
||||||
this.actions.create.progress = new ProgressTimer( template.traits.creation.time, this.actions.create.construct / 1000, entity_create_complete, this )
|
this.actions.create.progress = new ProgressTimer( template.traits.creation.time, this.actions.create.construct / 1000, entity_create_complete, this )
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ function setupSession()
|
|||||||
CreateResources();
|
CreateResources();
|
||||||
|
|
||||||
// Start refreshing the session controls.
|
// Start refreshing the session controls.
|
||||||
setInterval( getObjectInfo, 1, 1000 );
|
setInterval( getObjectInfo, 1, 100 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// ====================================================================
|
// ====================================================================
|
||||||
|
@ -463,31 +463,41 @@ function PressCommandButton(GUIObject, list, tab)
|
|||||||
|
|
||||||
function UpdateCommandButtons()
|
function UpdateCommandButtons()
|
||||||
{
|
{
|
||||||
// Update train/research/build lists.
|
if( shouldUpdateStat( "actions.create.list" ) )
|
||||||
listCounter = 1;
|
|
||||||
unitArray = UpdateList(action_tab_train, listCounter); if (unitArray != 0) listCounter++;
|
|
||||||
structcivArray = UpdateList(action_tab_buildciv, listCounter); if (structcivArray != 0) listCounter++;
|
|
||||||
structmilArray = UpdateList(action_tab_buildmil, listCounter); if (structmilArray != 0) listCounter++;
|
|
||||||
techArray = UpdateList(action_tab_research, listCounter); if (techArray != 0) listCounter++;
|
|
||||||
formationArray = UpdateList(action_tab_formation, listCounter); if (formationArray != 0) listCounter++;
|
|
||||||
stanceArray = UpdateList(action_tab_stance, listCounter); if (stanceArray != 0) listCounter++;
|
|
||||||
|
|
||||||
// Update commands.
|
|
||||||
commandCounter = SN_STATUS_PANE_COMMAND.tab.max;
|
|
||||||
commandCounter = UpdateCommand(action_attack, commandCounter);
|
|
||||||
commandCounter = UpdateCommand(action_patrol, commandCounter);
|
|
||||||
commandCounter = UpdateCommand(action_repair, commandCounter);
|
|
||||||
commandCounter = UpdateCommand(action_gather_food, commandCounter);
|
|
||||||
commandCounter = UpdateCommand(action_gather_wood, commandCounter);
|
|
||||||
commandCounter = UpdateCommand(action_gather_stone, commandCounter);
|
|
||||||
commandCounter = UpdateCommand(action_gather_ore, commandCounter);
|
|
||||||
|
|
||||||
// Clear remaining buttons between them.
|
|
||||||
for (commandClearLoop = listCounter; commandClearLoop <= commandCounter; commandClearLoop++)
|
|
||||||
{
|
{
|
||||||
GUIObjectHide("SN_STATUS_PANE_COMMAND_" + commandClearLoop + "_1");
|
// Everything in this block is tied to properties in
|
||||||
// If this slot could possibly contain a list, hide that too.
|
// actions.create.list, the above check should limit the
|
||||||
GUIObjectHide("SN_STATUS_PANE_COMMAND_" + commandClearLoop + "_GROUP");
|
// number of times this update is needlessly made.
|
||||||
|
|
||||||
|
// Update train/research/build lists.
|
||||||
|
listCounter = 1;
|
||||||
|
unitArray = UpdateList(action_tab_train, listCounter); if (unitArray != 0) listCounter++;
|
||||||
|
structcivArray = UpdateList(action_tab_buildciv, listCounter); if (structcivArray != 0) listCounter++;
|
||||||
|
structmilArray = UpdateList(action_tab_buildmil, listCounter); if (structmilArray != 0) listCounter++;
|
||||||
|
techArray = UpdateList(action_tab_research, listCounter); if (techArray != 0) listCounter++;
|
||||||
|
formationArray = UpdateList(action_tab_formation, listCounter); if (formationArray != 0) listCounter++;
|
||||||
|
stanceArray = UpdateList(action_tab_stance, listCounter); if (stanceArray != 0) listCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( shouldUpdateStat( "actions" ) )
|
||||||
|
{
|
||||||
|
// Update commands.
|
||||||
|
commandCounter = SN_STATUS_PANE_COMMAND.tab.max;
|
||||||
|
commandCounter = UpdateCommand(action_attack, commandCounter);
|
||||||
|
commandCounter = UpdateCommand(action_patrol, commandCounter);
|
||||||
|
commandCounter = UpdateCommand(action_repair, commandCounter);
|
||||||
|
commandCounter = UpdateCommand(action_gather_food, commandCounter);
|
||||||
|
commandCounter = UpdateCommand(action_gather_wood, commandCounter);
|
||||||
|
commandCounter = UpdateCommand(action_gather_stone, commandCounter);
|
||||||
|
commandCounter = UpdateCommand(action_gather_ore, commandCounter);
|
||||||
|
|
||||||
|
// Clear remaining buttons between them.
|
||||||
|
for (commandClearLoop = listCounter; commandClearLoop <= commandCounter; commandClearLoop++)
|
||||||
|
{
|
||||||
|
GUIObjectHide("SN_STATUS_PANE_COMMAND_" + commandClearLoop + "_1");
|
||||||
|
// If this slot could possibly contain a list, hide that too.
|
||||||
|
GUIObjectHide("SN_STATUS_PANE_COMMAND_" + commandClearLoop + "_GROUP");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update production queue.
|
// Update production queue.
|
||||||
@ -521,107 +531,224 @@ function UpdateCommandButtons()
|
|||||||
|
|
||||||
// ====================================================================
|
// ====================================================================
|
||||||
|
|
||||||
|
// Update-on-alteration trickery...
|
||||||
|
|
||||||
|
// We don't really want to update every single time we get a
|
||||||
|
// selection-changed or property-changed event; that could happen
|
||||||
|
// a lot. Instead, use this bunch of globals to cache any changes
|
||||||
|
// that happened between GUI updates.
|
||||||
|
|
||||||
|
// This boolean determines whether the selection has been changed.
|
||||||
|
var selectionChanged = false;
|
||||||
|
|
||||||
|
// This boolean determines what the template of the selected object
|
||||||
|
// was when last we looked
|
||||||
|
var selectionTemplate = null;
|
||||||
|
|
||||||
|
// This array holds the name of all properties that need to be updated
|
||||||
|
var selectionPropertiesChanged = new Array();
|
||||||
|
|
||||||
|
// This array holds a list of all the objects we hold property-change
|
||||||
|
// watches on
|
||||||
|
var propertyWatches = new Array();
|
||||||
|
|
||||||
|
// This function resets all the update variables, above
|
||||||
|
function resetUpdateVars()
|
||||||
|
{
|
||||||
|
if( selectionChanged )
|
||||||
|
{
|
||||||
|
for( watchedObject in propertyWatches )
|
||||||
|
propertyWatches[watchedObject].unwatchAll( selectionWatchHandler ); // Remove the handler
|
||||||
|
|
||||||
|
propertyWatches = new Array();
|
||||||
|
if( selection[0] )
|
||||||
|
{
|
||||||
|
// Watch the object itself
|
||||||
|
selection[0].watchAll( selectionWatchHandler );
|
||||||
|
propertyWatches.push( selection[0] );
|
||||||
|
// And every parent back up the tree (changes there will affect
|
||||||
|
// displayed properties via inheritance)
|
||||||
|
var parent = selection[0].template
|
||||||
|
while( parent )
|
||||||
|
{
|
||||||
|
parent.watchAll( selectionWatchHandler );
|
||||||
|
propertyWatches.push( selection[0] );
|
||||||
|
parent = parent.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selectionChanged = false;
|
||||||
|
if( selection[0] )
|
||||||
|
{
|
||||||
|
selectionTemplate = selection[0].template;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
selectionTemplate = null;
|
||||||
|
|
||||||
|
selectionPropertiesChanged = new Array();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function returns whether we should update a particular statistic
|
||||||
|
// in the GUI (e.g. "actions.attack") - this should happen if: the selection
|
||||||
|
// changed, the selection had its template altered (changing lots of stuff)
|
||||||
|
// or an assignment has been made to that stat or any property within that
|
||||||
|
// stat.
|
||||||
|
function shouldUpdateStat( statname )
|
||||||
|
{
|
||||||
|
if( selectionChanged || ( selectionTemplate != selection[0].template ) )
|
||||||
|
return( true );
|
||||||
|
for( var property in selectionPropertiesChanged )
|
||||||
|
{
|
||||||
|
// If property starts with statname
|
||||||
|
if( selectionPropertiesChanged[property].substring( 0, statname.length ) == statname )
|
||||||
|
return( true );
|
||||||
|
}
|
||||||
|
return( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is a handler for the 'selectionChanged' event,
|
||||||
|
// it updates the selectionChanged flag
|
||||||
|
function selectionChangedHandler()
|
||||||
|
{
|
||||||
|
selectionChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register it.
|
||||||
|
addGlobalHandler( "selectionChanged", selectionChangedHandler );
|
||||||
|
|
||||||
|
// This function is a handler for a watch event; it updates the
|
||||||
|
// selectionPropertiesChanged array
|
||||||
|
function selectionWatchHandler( propname, oldvalue, newvalue )
|
||||||
|
{
|
||||||
|
selectionPropertiesChanged.push( propname );
|
||||||
|
// This bit's important (watches allow the handler to change the value
|
||||||
|
// before it gets written; we don't want to affect things, so make sure
|
||||||
|
// the value we send back is the one that was going to be written)
|
||||||
|
return( newvalue );
|
||||||
|
}
|
||||||
|
|
||||||
function UpdateStatusOrb()
|
function UpdateStatusOrb()
|
||||||
{
|
{
|
||||||
// Update heading.
|
// Update heading.
|
||||||
GUIObject = getGUIObjectByName("SN_STATUS_PANE_HEADING");
|
if( shouldUpdateStat( "player" ) || shouldUpdateStat( "traits.id.civ" ) )
|
||||||
GUIObject.caption = selection[0].player.name; // Player name (placeholder; replace with proper callsign).
|
{
|
||||||
if (selection[0].traits.id.civ)
|
GUIObject = getGUIObjectByName("SN_STATUS_PANE_HEADING");
|
||||||
GUIObject.caption += " [icon=bullet_icon] " + selection[0].traits.id.civ;
|
GUIObject.caption = selection[0].player.name; // Player name (placeholder; replace with proper callsign).
|
||||||
|
if (selection[0].traits.id.civ)
|
||||||
|
GUIObject.caption += " [icon=bullet_icon] " + selection[0].traits.id.civ;
|
||||||
|
}
|
||||||
|
|
||||||
// Update name text.
|
// Update name text.
|
||||||
GUIObject = getGUIObjectByName("SN_STATUS_PANE_NAME1");
|
if( shouldUpdateStat( "traits.id" ) )
|
||||||
GUIObject.caption = "";
|
|
||||||
// Personal name.
|
|
||||||
if (selection[0].traits.id.personal && selection[0].traits.id.personal != "")
|
|
||||||
{
|
|
||||||
GUIObject.caption += selection[0].traits.id.personal + "\n";
|
|
||||||
}
|
|
||||||
// Generic name.
|
|
||||||
if (selection[0].traits.id.generic)
|
|
||||||
{
|
|
||||||
GUIObject.caption += selection[0].traits.id.generic + "\n";
|
|
||||||
}
|
|
||||||
// Specific/ranked name.
|
|
||||||
if (selection[0].traits.id.ranked)
|
|
||||||
{
|
{
|
||||||
GUIObject = getGUIObjectByName("SN_STATUS_PANE_NAME1");
|
GUIObject = getGUIObjectByName("SN_STATUS_PANE_NAME1");
|
||||||
GUIObject.caption += selection[0].traits.id.ranked + "\n";
|
GUIObject.caption = "";
|
||||||
}
|
|
||||||
else{
|
// Personal name.
|
||||||
if (selection[0].traits.id.specific)
|
if (selection[0].traits.id.personal && selection[0].traits.id.personal != "")
|
||||||
|
GUIObject.caption += selection[0].traits.id.personal + "\n";
|
||||||
|
// Generic name.
|
||||||
|
if (selection[0].traits.id.generic)
|
||||||
|
GUIObject.caption += selection[0].traits.id.generic + "\n";
|
||||||
|
// Specific/ranked name.
|
||||||
|
if (selection[0].traits.id.ranked)
|
||||||
{
|
{
|
||||||
GUIObject.caption += selection[0].traits.id.specific + "\n";
|
GUIObject = getGUIObjectByName("SN_STATUS_PANE_NAME1");
|
||||||
|
GUIObject.caption += selection[0].traits.id.ranked + "\n";
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (selection[0].traits.id.specific)
|
||||||
|
{
|
||||||
|
GUIObject.caption += selection[0].traits.id.specific + "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if( shouldUpdateStat( "traits.id.icon" ) )
|
||||||
// Update portrait
|
|
||||||
if (selection[0].traits.id.icon)
|
|
||||||
setPortrait("SN_STATUS_PANE_PORTRAIT", selection[0].traits.id.icon, selection[0].traits.id.civ_code, selection[0].traits.id.icon_cell);
|
|
||||||
|
|
||||||
// Update rank.
|
|
||||||
GUIObject = getGUIObjectByName("SN_STATUS_PANE_ICON_RANK");
|
|
||||||
if (selection[0].traits.up.rank > 1)
|
|
||||||
{
|
{
|
||||||
GUIObject.sprite = "ui_icon_sheet_statistic";
|
// Update portrait
|
||||||
GUIObject.cell_id = stat_rank1 + (selection[0].traits.up.rank-2);
|
if (selection[0].traits.id.icon)
|
||||||
|
setPortrait("SN_STATUS_PANE_PORTRAIT", selection[0].traits.id.icon, selection[0].traits.id.civ_code, selection[0].traits.id.icon_cell);
|
||||||
}
|
}
|
||||||
else
|
if( shouldUpdateStat( "traits.up.rank" ) )
|
||||||
GUIObject.sprite = "";
|
|
||||||
|
|
||||||
// Update hitpoints
|
|
||||||
if (selection[0].traits.health.curr && selection[0].traits.health.max)
|
|
||||||
{
|
{
|
||||||
getGUIObjectByName("SN_STATUS_PANE_ICON_HP_TEXT").caption = Math.round(selection[0].traits.health.curr) + "/" + Math.round(selection[0].traits.health.max);
|
// Update rank.
|
||||||
getGUIObjectByName("SN_STATUS_PANE_ICON_HP_TEXT").hidden = false;
|
GUIObject = getGUIObjectByName("SN_STATUS_PANE_ICON_RANK");
|
||||||
getGUIObjectByName("SN_STATUS_PANE_ICON_HP_BAR").caption = ((Math.round(selection[0].traits.health.curr) * 100 ) / Math.round(selection[0].traits.health.max));
|
if (selection[0].traits.up.rank > 1)
|
||||||
getGUIObjectByName("SN_STATUS_PANE_ICON_HP_BAR").hidden = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
getGUIObjectByName("SN_STATUS_PANE_ICON_HP_TEXT").hidden = true;
|
|
||||||
getGUIObjectByName("SN_STATUS_PANE_ICON_HP_BAR").hidden = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update upgrade points
|
|
||||||
if (selection[0].traits.up && selection[0].traits.up.curr && selection[0].traits.up.req)
|
|
||||||
{
|
|
||||||
getGUIObjectByName("SN_STATUS_PANE_ICON_XP_TEXT").caption = Math.round(selection[0].traits.up.curr) + "/" + Math.round(selection[0].traits.up.req);
|
|
||||||
getGUIObjectByName("SN_STATUS_PANE_ICON_XP_TEXT").hidden = false;
|
|
||||||
getGUIObjectByName("SN_STATUS_PANE_ICON_XP_BAR").caption = ((Math.round(selection[0].traits.up.curr) * 100 ) / Math.round(selection[0].traits.up.req));
|
|
||||||
getGUIObjectByName("SN_STATUS_PANE_ICON_XP_BAR").hidden = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
getGUIObjectByName("SN_STATUS_PANE_ICON_XP_TEXT").hidden = true;
|
|
||||||
getGUIObjectByName("SN_STATUS_PANE_ICON_XP_BAR").hidden = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update Supply/Garrison
|
|
||||||
GUIObject = getGUIObjectByName("SN_STATUS_PANE_2STAT");
|
|
||||||
GUIObject.caption = '';
|
|
||||||
|
|
||||||
if (selection[0].traits.garrison)
|
|
||||||
{
|
|
||||||
if (selection[0].traits.garrison.curr && selection[0].traits.garrison.max)
|
|
||||||
{
|
{
|
||||||
GUIObject.caption += '[icon="icon_statistic_garrison"] [color="100 100 255"]' + selection[0].traits.garrison.curr + '/' + selection[0].traits.garrison.max + '[/color] ';
|
GUIObject.sprite = "ui_icon_sheet_statistic";
|
||||||
|
GUIObject.cell_id = stat_rank1 + (selection[0].traits.up.rank-2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
GUIObject.sprite = "";
|
||||||
|
}
|
||||||
|
if( shouldUpdateStat( "traits.health" ) )
|
||||||
|
{
|
||||||
|
// Update hitpoints
|
||||||
|
if (selection[0].traits.health.curr && selection[0].traits.health.max)
|
||||||
|
{
|
||||||
|
getGUIObjectByName("SN_STATUS_PANE_ICON_HP_TEXT").caption = Math.round(selection[0].traits.health.curr) + "/" + Math.round(selection[0].traits.health.max);
|
||||||
|
getGUIObjectByName("SN_STATUS_PANE_ICON_HP_TEXT").hidden = false;
|
||||||
|
getGUIObjectByName("SN_STATUS_PANE_ICON_HP_BAR").caption = ((Math.round(selection[0].traits.health.curr) * 100 ) / Math.round(selection[0].traits.health.max));
|
||||||
|
getGUIObjectByName("SN_STATUS_PANE_ICON_HP_BAR").hidden = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
getGUIObjectByName("SN_STATUS_PANE_ICON_HP_TEXT").hidden = true;
|
||||||
|
getGUIObjectByName("SN_STATUS_PANE_ICON_HP_BAR").hidden = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selection[0].traits.supply)
|
if( shouldUpdateStat( "traits.up" ) )
|
||||||
{
|
{
|
||||||
if (selection[0].traits.supply.curr && selection[0].traits.supply.max && selection[0].traits.supply.type)
|
// Update upgrade points
|
||||||
|
if (selection[0].traits.up && selection[0].traits.up.curr && selection[0].traits.up.req)
|
||||||
{
|
{
|
||||||
// Special case for infinity.
|
getGUIObjectByName("SN_STATUS_PANE_ICON_XP_TEXT").caption = Math.round(selection[0].traits.up.curr) + "/" + Math.round(selection[0].traits.up.req);
|
||||||
if (selection[0].traits.supply.curr == "0" && selection[0].traits.supply.max == "0")
|
getGUIObjectByName("SN_STATUS_PANE_ICON_XP_TEXT").hidden = false;
|
||||||
GUIObject.caption += '[icon="icon_resource_' + selection[0].traits.supply.type + '"] [color="100 100 255"] [icon="infinity_icon"] [/color] ';
|
getGUIObjectByName("SN_STATUS_PANE_ICON_XP_BAR").caption = ((Math.round(selection[0].traits.up.curr) * 100 ) / Math.round(selection[0].traits.up.req));
|
||||||
else
|
getGUIObjectByName("SN_STATUS_PANE_ICON_XP_BAR").hidden = false;
|
||||||
GUIObject.caption += '[icon="icon_resource_' + selection[0].traits.supply.type + '"] [color="100 100 255"]' + selection[0].traits.supply.curr + '/' + selection[0].traits.supply.max + '[/color] ';
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
getGUIObjectByName("SN_STATUS_PANE_ICON_XP_TEXT").hidden = true;
|
||||||
|
getGUIObjectByName("SN_STATUS_PANE_ICON_XP_BAR").hidden = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if( shouldUpdateStat( "traits.garrison" ) )
|
||||||
|
{
|
||||||
|
// Update Supply/Garrison
|
||||||
|
GUIObject = getGUIObjectByName("SN_STATUS_PANE_2STAT");
|
||||||
|
GUIObject.caption = '';
|
||||||
|
|
||||||
|
if (selection[0].traits.garrison)
|
||||||
|
{
|
||||||
|
if (selection[0].traits.garrison.curr && selection[0].traits.garrison.max)
|
||||||
|
{
|
||||||
|
GUIObject.caption += '[icon="icon_statistic_garrison"] [color="100 100 255"]' + selection[0].traits.garrison.curr + '/' + selection[0].traits.garrison.max + '[/color] ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( shouldUpdateStat( "traits.supply" ) )
|
||||||
|
{
|
||||||
|
GUIObject = getGUIObjectByName("SN_STATUS_PANE_2STAT");
|
||||||
|
GUIObject.caption = '';
|
||||||
|
|
||||||
|
if (selection[0].traits.supply)
|
||||||
|
{
|
||||||
|
if (selection[0].traits.supply.curr && selection[0].traits.supply.max && selection[0].traits.supply.type)
|
||||||
|
{
|
||||||
|
// Special case for infinity.
|
||||||
|
if (selection[0].traits.supply.curr == "0" && selection[0].traits.supply.max == "0")
|
||||||
|
GUIObject.caption += '[icon="icon_resource_' + selection[0].traits.supply.type + '"] [color="100 100 255"] [icon="infinity_icon"] [/color] ';
|
||||||
|
else
|
||||||
|
GUIObject.caption += '[icon="icon_resource_' + selection[0].traits.supply.type + '"] [color="100 100 255"]' + selection[0].traits.supply.curr + '/' + selection[0].traits.supply.max + '[/color] ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update Attack stats
|
// Update Attack stats
|
||||||
|
if( shouldUpdateStat( "actions.attack" ) )
|
||||||
|
{
|
||||||
if (selection[0].actions.attack && selection[0].actions.attack.damage && selection[0].actions.attack.damage > 0)
|
if (selection[0].actions.attack && selection[0].actions.attack.damage && selection[0].actions.attack.damage > 0)
|
||||||
getGUIObjectByName("SN_STATUS_PANE_STAT1").caption = '[icon="icon_statistic_attack"]' + selection[0].actions.attack.damage;
|
getGUIObjectByName("SN_STATUS_PANE_STAT1").caption = '[icon="icon_statistic_attack"]' + selection[0].actions.attack.damage;
|
||||||
else
|
else
|
||||||
@ -651,8 +778,10 @@ function UpdateStatusOrb()
|
|||||||
getGUIObjectByName("SN_STATUS_PANE_STAT6").caption = '[icon="icon_statistic_accuracy"]' + Math.round(selection[0].actions.attack.accuracy*100) + '%';
|
getGUIObjectByName("SN_STATUS_PANE_STAT6").caption = '[icon="icon_statistic_accuracy"]' + Math.round(selection[0].actions.attack.accuracy*100) + '%';
|
||||||
else
|
else
|
||||||
getGUIObjectByName("SN_STATUS_PANE_STAT6").caption = "";
|
getGUIObjectByName("SN_STATUS_PANE_STAT6").caption = "";
|
||||||
|
}
|
||||||
// Update Armour & Other stats
|
// Update Armour & Other stats
|
||||||
|
if( shouldUpdateStat( "traits.armour" ) )
|
||||||
|
{
|
||||||
if (selection[0].traits.armour && selection[0].traits.armour.value && selection[0].traits.armour.value > 0)
|
if (selection[0].traits.armour && selection[0].traits.armour.value && selection[0].traits.armour.value > 0)
|
||||||
getGUIObjectByName("SN_STATUS_PANE_STAT7").caption = '[icon="icon_statistic_armour"]' + selection[0].traits.armour.value;
|
getGUIObjectByName("SN_STATUS_PANE_STAT7").caption = '[icon="icon_statistic_armour"]' + selection[0].traits.armour.value;
|
||||||
else getGUIObjectByName("SN_STATUS_PANE_STAT7").caption = "";
|
else getGUIObjectByName("SN_STATUS_PANE_STAT7").caption = "";
|
||||||
@ -665,18 +794,26 @@ function UpdateStatusOrb()
|
|||||||
if (selection[0].traits.armour && selection[0].traits.armour.crush && selection[0].traits.armour.crush > 0)
|
if (selection[0].traits.armour && selection[0].traits.armour.crush && selection[0].traits.armour.crush > 0)
|
||||||
getGUIObjectByName("SN_STATUS_PANE_STAT10").caption = '[icon="icon_statistic_crush"]' + Math.round(selection[0].traits.armour.crush*100) + '%';
|
getGUIObjectByName("SN_STATUS_PANE_STAT10").caption = '[icon="icon_statistic_crush"]' + Math.round(selection[0].traits.armour.crush*100) + '%';
|
||||||
else getGUIObjectByName("SN_STATUS_PANE_STAT10").caption = "";
|
else getGUIObjectByName("SN_STATUS_PANE_STAT10").caption = "";
|
||||||
|
}
|
||||||
if (selection[0].actions.move && selection[0].actions.move.speed)
|
if( shouldUpdateStat( "actions.move" ) )
|
||||||
getGUIObjectByName("SN_STATUS_PANE_STAT11").caption = '[icon="icon_statistic_speed"]' + selection[0].actions.move.speed;
|
{
|
||||||
else getGUIObjectByName("SN_STATUS_PANE_STAT11").caption = "";
|
if (selection[0].actions.move && selection[0].actions.move.speed)
|
||||||
if (selection[0].traits.vision && selection[0].traits.vision.los)
|
getGUIObjectByName("SN_STATUS_PANE_STAT11").caption = '[icon="icon_statistic_speed"]' + selection[0].actions.move.speed;
|
||||||
getGUIObjectByName("SN_STATUS_PANE_STAT12").caption = '[icon="icon_statistic_los"]' + selection[0].traits.vision.los;
|
else getGUIObjectByName("SN_STATUS_PANE_STAT11").caption = "";
|
||||||
else getGUIObjectByName("SN_STATUS_PANE_STAT12").caption = "";
|
}
|
||||||
|
if( shouldUpdateStat( "traits.vision" ) )
|
||||||
|
{
|
||||||
|
if (selection[0].traits.vision && selection[0].traits.vision.los)
|
||||||
|
getGUIObjectByName("SN_STATUS_PANE_STAT12").caption = '[icon="icon_statistic_los"]' + selection[0].traits.vision.los;
|
||||||
|
else getGUIObjectByName("SN_STATUS_PANE_STAT12").caption = "";
|
||||||
|
}
|
||||||
|
|
||||||
// Reveal Status Orb
|
// Reveal Status Orb
|
||||||
getGUIObjectByName("session_status_orb").hidden = false;
|
getGUIObjectByName("session_status_orb").hidden = false;
|
||||||
|
|
||||||
// Update Command Buttons.
|
// Update Command Buttons.
|
||||||
UpdateCommandButtons();
|
UpdateCommandButtons();
|
||||||
|
|
||||||
|
resetUpdateVars();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result)
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// BuildAnimation: load raw animation frame animation from given file, and build a
|
// BuildAnimation: load raw animation frame animation from given file, and build a
|
||||||
// animation specific to this model
|
// animation specific to this model
|
||||||
CSkeletonAnim* CModel::BuildAnimation(const char* filename,float speed)
|
CSkeletonAnim* CModel::BuildAnimation(const char* filename,float speed,size_t actionpos)
|
||||||
{
|
{
|
||||||
CSkeletonAnimDef* def=g_SkelAnimMan.GetAnimation(filename);
|
CSkeletonAnimDef* def=g_SkelAnimMan.GetAnimation(filename);
|
||||||
if (!def) return 0;
|
if (!def) return 0;
|
||||||
@ -207,6 +207,9 @@ CSkeletonAnim* CModel::BuildAnimation(const char* filename,float speed)
|
|||||||
CSkeletonAnim* anim=new CSkeletonAnim;
|
CSkeletonAnim* anim=new CSkeletonAnim;
|
||||||
anim->m_AnimDef=def;
|
anim->m_AnimDef=def;
|
||||||
anim->m_Speed=speed;
|
anim->m_Speed=speed;
|
||||||
|
anim->m_ActionPos=actionpos;
|
||||||
|
if( actionpos > anim->m_AnimDef->GetDuration() )
|
||||||
|
anim->m_ActionPos = anim->m_AnimDef->GetDuration();
|
||||||
anim->m_ObjectBounds.SetEmpty();
|
anim->m_ObjectBounds.SetEmpty();
|
||||||
InvalidateBounds();
|
InvalidateBounds();
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ public:
|
|||||||
|
|
||||||
// load raw animation frame animation from given file, and build a
|
// load raw animation frame animation from given file, and build a
|
||||||
// animation specific to this model
|
// animation specific to this model
|
||||||
CSkeletonAnim* BuildAnimation(const char* filename,float speed);
|
CSkeletonAnim* BuildAnimation(const char* filename,float speed,size_t actionpos);
|
||||||
|
|
||||||
// add a prop to the model on the given point
|
// add a prop to the model on the given point
|
||||||
void AddProp(SPropPoint* point,CModel* model);
|
void AddProp(SPropPoint* point,CModel* model);
|
||||||
|
@ -159,6 +159,7 @@ bool CObjectBase::Load(const char* filename)
|
|||||||
AT(file);
|
AT(file);
|
||||||
AT(name);
|
AT(name);
|
||||||
AT(speed);
|
AT(speed);
|
||||||
|
AT(actionpos);
|
||||||
AT(attachpoint);
|
AT(attachpoint);
|
||||||
AT(actor);
|
AT(actor);
|
||||||
AT(frequency);
|
AT(frequency);
|
||||||
@ -220,6 +221,11 @@ bool CObjectBase::Load(const char* filename)
|
|||||||
anim.m_Speed = CStr(ae.Value).ToInt() / 100.f;
|
anim.m_Speed = CStr(ae.Value).ToInt() / 100.f;
|
||||||
if (anim.m_Speed <= 0.0) anim.m_Speed = 1.0f;
|
if (anim.m_Speed <= 0.0) anim.m_Speed = 1.0f;
|
||||||
}
|
}
|
||||||
|
else if (ae.Name == at_actionpos)
|
||||||
|
{
|
||||||
|
anim.m_ActionPos = CStr(ae.Value).ToInt();
|
||||||
|
if (anim.m_ActionPos < 0) anim.m_ActionPos = 0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
; // unrecognised element
|
; // unrecognised element
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ public:
|
|||||||
|
|
||||||
struct Anim {
|
struct Anim {
|
||||||
// constructor
|
// constructor
|
||||||
Anim() : m_Speed(1), m_AnimData(0) {}
|
Anim() : m_Speed(1), m_ActionPos( 0 ), m_AnimData(0) {}
|
||||||
|
|
||||||
// name of the animation - "Idle", "Run", etc
|
// name of the animation - "Idle", "Run", etc
|
||||||
CStr m_AnimName;
|
CStr m_AnimName;
|
||||||
@ -21,6 +21,8 @@ public:
|
|||||||
CStr m_FileName;
|
CStr m_FileName;
|
||||||
// animation speed, as specified in XML actor file
|
// animation speed, as specified in XML actor file
|
||||||
float m_Speed;
|
float m_Speed;
|
||||||
|
// time during the animation at which the interesting bit happens (msec)
|
||||||
|
size_t m_ActionPos;
|
||||||
// the animation data, specific to the this model
|
// the animation data, specific to the this model
|
||||||
CSkeletonAnim* m_AnimData;
|
CSkeletonAnim* m_AnimData;
|
||||||
};
|
};
|
||||||
|
@ -144,7 +144,7 @@ bool CObjectEntry::BuildRandomVariant(CObjectBase::variation_key& vars, CObjectB
|
|||||||
if (m_Animations[t].m_FileName.Length() > 0)
|
if (m_Animations[t].m_FileName.Length() > 0)
|
||||||
{
|
{
|
||||||
const char* animfilename = m_Animations[t].m_FileName;
|
const char* animfilename = m_Animations[t].m_FileName;
|
||||||
m_Animations[t].m_AnimData = m_Model->BuildAnimation(animfilename, m_Animations[t].m_Speed);
|
m_Animations[t].m_AnimData = m_Model->BuildAnimation(animfilename, m_Animations[t].m_Speed, m_Animations[t].m_ActionPos);
|
||||||
|
|
||||||
CStr AnimNameLC = m_Animations[t].m_AnimName.LowerCase();
|
CStr AnimNameLC = m_Animations[t].m_AnimName.LowerCase();
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ public:
|
|||||||
CSkeletonAnimDef* m_AnimDef;
|
CSkeletonAnimDef* m_AnimDef;
|
||||||
// speed at which this animation runs
|
// speed at which this animation runs
|
||||||
float m_Speed;
|
float m_Speed;
|
||||||
|
// time during the animation at which the interesting bit happens (msec)
|
||||||
|
size_t m_ActionPos;
|
||||||
// object space bounds of the model when this animation is applied to it
|
// object space bounds of the model when this animation is applied to it
|
||||||
CBound m_ObjectBounds;
|
CBound m_ObjectBounds;
|
||||||
};
|
};
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
#include "StringConvert.h"
|
#include "StringConvert.h"
|
||||||
|
|
||||||
#include "scripting/ScriptingHost.h"
|
#include "scripting/ScriptingHost.h"
|
||||||
|
#include "scripting/GameEvents.h"
|
||||||
#include "scripting/JSInterface_Entity.h"
|
#include "scripting/JSInterface_Entity.h"
|
||||||
#include "scripting/JSInterface_BaseEntity.h"
|
#include "scripting/JSInterface_BaseEntity.h"
|
||||||
#include "scripting/JSInterface_Vector3D.h"
|
#include "scripting/JSInterface_Vector3D.h"
|
||||||
@ -789,7 +790,7 @@ TIMER(InitScripting)
|
|||||||
|
|
||||||
PlayerCollection::Init( "PlayerCollection" );
|
PlayerCollection::Init( "PlayerCollection" );
|
||||||
CDamageType::ScriptingInit();
|
CDamageType::ScriptingInit();
|
||||||
CJSPropertyAccessor<CEntity>::ScriptingInit(); // <-- Doesn't really matter which we use, but we know CJSPropertyAccessor<T> is already being compiled for T = CEntity.
|
CJSComplexPropertyAccessor<CEntity>::ScriptingInit(); // <-- Doesn't really matter which we use, but we know CJSPropertyAccessor<T> is already being compiled for T = CEntity.
|
||||||
CScriptEvent::ScriptingInit();
|
CScriptEvent::ScriptingInit();
|
||||||
CJSProgressTimer::ScriptingInit();
|
CJSProgressTimer::ScriptingInit();
|
||||||
|
|
||||||
@ -801,6 +802,8 @@ TIMER(InitScripting)
|
|||||||
|
|
||||||
JSI_Camera::init();
|
JSI_Camera::init();
|
||||||
JSI_Console::init();
|
JSI_Console::init();
|
||||||
|
|
||||||
|
new CGameEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1069,6 +1072,7 @@ static void Shutdown()
|
|||||||
// delete &g_EntityManager;
|
// delete &g_EntityManager;
|
||||||
|
|
||||||
delete &g_GameAttributes;
|
delete &g_GameAttributes;
|
||||||
|
delete &g_JSGameEvents;
|
||||||
|
|
||||||
delete &g_EntityTemplateCollection;
|
delete &g_EntityTemplateCollection;
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@ CPlayerSlot::CPlayerSlot(int slotID, CPlayer *pPlayer):
|
|||||||
);
|
);
|
||||||
|
|
||||||
//AddProperty(L"session", (GetFn)&CPlayerSlot::JSI_GetSession);
|
//AddProperty(L"session", (GetFn)&CPlayerSlot::JSI_GetSession);
|
||||||
AddReadOnlyProperty(L"session", &m_pSession);
|
AddLocalProperty(L"session", &m_pSession, true );
|
||||||
AddReadOnlyProperty(L"player", &m_pPlayer);
|
AddLocalProperty(L"player", &m_pPlayer, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
CPlayerSlot::~CPlayerSlot()
|
CPlayerSlot::~CPlayerSlot()
|
||||||
@ -34,7 +34,7 @@ void CPlayerSlot::ScriptingInit()
|
|||||||
AddMethod<bool, &CPlayerSlot::JSI_AssignToSession>("assignToSession", 1);
|
AddMethod<bool, &CPlayerSlot::JSI_AssignToSession>("assignToSession", 1);
|
||||||
AddMethod<bool, &CPlayerSlot::JSI_AssignLocal>("assignLocal", 0);
|
AddMethod<bool, &CPlayerSlot::JSI_AssignLocal>("assignLocal", 0);
|
||||||
AddMethod<bool, &CPlayerSlot::JSI_AssignOpen>("assignOpen", 0);
|
AddMethod<bool, &CPlayerSlot::JSI_AssignOpen>("assignOpen", 0);
|
||||||
AddClassProperty(L"assignment", (GetFn)&CPlayerSlot::JSI_GetAssignment);
|
AddProperty(L"assignment", (GetFn)&CPlayerSlot::JSI_GetAssignment);
|
||||||
// AddMethod<bool, &CPlayerSlot::JSI_AssignAI>("assignAI", <num_args>);
|
// AddMethod<bool, &CPlayerSlot::JSI_AssignAI>("assignAI", <num_args>);
|
||||||
|
|
||||||
CJSObject<CPlayerSlot>::ScriptingInit("PlayerSlot");
|
CJSObject<CPlayerSlot>::ScriptingInit("PlayerSlot");
|
||||||
@ -258,7 +258,7 @@ void CGameAttributes::ScriptingInit()
|
|||||||
PlayerSlotArray_JS::Construct, 0, NULL, NULL, NULL, NULL);
|
PlayerSlotArray_JS::Construct, 0, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
AddMethod<jsval, &CGameAttributes::JSI_GetOpenSlot>("getOpenSlot", 0);
|
AddMethod<jsval, &CGameAttributes::JSI_GetOpenSlot>("getOpenSlot", 0);
|
||||||
AddClassProperty(L"slots", (GetFn)&CGameAttributes::JSI_GetPlayerSlots);
|
AddProperty(L"slots", (GetFn)&CGameAttributes::JSI_GetPlayerSlots);
|
||||||
|
|
||||||
CJSObject<CGameAttributes>::ScriptingInit("GameAttributes");
|
CJSObject<CGameAttributes>::ScriptingInit("GameAttributes");
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "BoundingObjects.h"
|
#include "BoundingObjects.h"
|
||||||
#include "Unit.h"
|
#include "Unit.h"
|
||||||
#include "Model.h"
|
#include "Model.h"
|
||||||
|
#include "scripting/GameEvents.h"
|
||||||
|
|
||||||
extern CConsole* g_Console;
|
extern CConsole* g_Console;
|
||||||
extern int g_mouse_x, g_mouse_y;
|
extern int g_mouse_x, g_mouse_y;
|
||||||
@ -120,10 +121,12 @@ void CSelectedEntities::renderOverlays()
|
|||||||
glDisable( GL_BLEND );
|
glDisable( GL_BLEND );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
glTranslatef( (float)( g_mouse_x + 16 ), (float)( g_Renderer.GetHeight() - g_mouse_y - 8 ), 0.0f );
|
glTranslatef( (float)( g_mouse_x + 16 ), (float)( g_Renderer.GetHeight() - g_mouse_y - 8 ), 0.0f );
|
||||||
glScalef( 1.0f, -1.0f, 1.0f );
|
glScalef( 1.0f, -1.0f, 1.0f );
|
||||||
glColor4f( 1.0f, 1.0f, 1.0f, 0.5f );
|
glColor4f( 1.0f, 1.0f, 1.0f, 0.5f );
|
||||||
|
|
||||||
switch( m_contextOrder )
|
switch( m_contextOrder )
|
||||||
{
|
{
|
||||||
case CEntityOrder::ORDER_GOTO:
|
case CEntityOrder::ORDER_GOTO:
|
||||||
@ -139,6 +142,7 @@ void CSelectedEntities::renderOverlays()
|
|||||||
glwprintf( L"Gather" );
|
glwprintf( L"Gather" );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
glDisable( GL_TEXTURE_2D );
|
glDisable( GL_TEXTURE_2D );
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
@ -350,6 +354,14 @@ CVector3D CSelectedEntities::getGroupPosition( i8 groupid )
|
|||||||
|
|
||||||
void CSelectedEntities::update()
|
void CSelectedEntities::update()
|
||||||
{
|
{
|
||||||
|
static std::vector<HEntity> lastSelection;
|
||||||
|
|
||||||
|
if( !( m_selected == lastSelection ) )
|
||||||
|
{
|
||||||
|
g_JSGameEvents.FireSelectionChanged( m_selectionChanged );
|
||||||
|
lastSelection = m_selected;
|
||||||
|
}
|
||||||
|
|
||||||
if( m_selectionChanged || g_Mouseover.m_targetChanged )
|
if( m_selectionChanged || g_Mouseover.m_targetChanged )
|
||||||
{
|
{
|
||||||
// Can't order anything off the map
|
// Can't order anything off the map
|
||||||
@ -362,6 +374,8 @@ void CSelectedEntities::update()
|
|||||||
// Quick count to see which is the modal default order.
|
// Quick count to see which is the modal default order.
|
||||||
|
|
||||||
int defaultPoll[CEntityOrder::ORDER_LAST];
|
int defaultPoll[CEntityOrder::ORDER_LAST];
|
||||||
|
std::map<CStrW, int, CStrW_hash_compare> defaultCursor[CEntityOrder::ORDER_LAST];
|
||||||
|
|
||||||
int t, vote;
|
int t, vote;
|
||||||
for( t = 0; t < CEntityOrder::ORDER_LAST; t++ )
|
for( t = 0; t < CEntityOrder::ORDER_LAST; t++ )
|
||||||
defaultPoll[t] = 0;
|
defaultPoll[t] = 0;
|
||||||
@ -369,9 +383,15 @@ void CSelectedEntities::update()
|
|||||||
std::vector<HEntity>::iterator it;
|
std::vector<HEntity>::iterator it;
|
||||||
for( it = m_selected.begin(); it < m_selected.end(); it++ )
|
for( it = m_selected.begin(); it < m_selected.end(); it++ )
|
||||||
{
|
{
|
||||||
vote = (*it)->defaultOrder( g_Mouseover.m_target );
|
CEventTargetChanged evt( g_Mouseover.m_target );
|
||||||
|
(*it)->DispatchEvent( &evt );
|
||||||
|
vote = evt.m_defaultAction;
|
||||||
|
|
||||||
if( ( vote >= 0 ) && ( vote < CEntityOrder::ORDER_LAST ) )
|
if( ( vote >= 0 ) && ( vote < CEntityOrder::ORDER_LAST ) )
|
||||||
|
{
|
||||||
defaultPoll[vote]++;
|
defaultPoll[vote]++;
|
||||||
|
defaultCursor[vote][evt.m_defaultCursor]++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vote = -1;
|
vote = -1;
|
||||||
@ -381,16 +401,17 @@ void CSelectedEntities::update()
|
|||||||
vote = t;
|
vote = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<CStrW, int, CStrW_hash_compare>::iterator itv;
|
||||||
m_contextOrder = vote;
|
m_contextOrder = vote;
|
||||||
switch( m_contextOrder )
|
|
||||||
{
|
// Now find the most appropriate cursor
|
||||||
case CEntityOrder::ORDER_ATTACK_MELEE:
|
t = 0;
|
||||||
g_CursorName = "action-attack";
|
for( itv = defaultCursor[vote].begin(); itv != defaultCursor[vote].end(); itv++ )
|
||||||
break;
|
if( itv->second > t )
|
||||||
default:
|
{
|
||||||
g_CursorName = "arrow-default";
|
t = itv->second;
|
||||||
break;
|
g_CursorName = itv->first;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_selectionChanged = false;
|
m_selectionChanged = false;
|
||||||
g_Mouseover.m_targetChanged = false;
|
g_Mouseover.m_targetChanged = false;
|
||||||
|
@ -22,13 +22,13 @@ CNetClient::CServerSession::CServerSession(int sessionID, const CStrW &name):
|
|||||||
m_Name(name)
|
m_Name(name)
|
||||||
{
|
{
|
||||||
ONCE( ScriptingInit(); );
|
ONCE( ScriptingInit(); );
|
||||||
|
|
||||||
AddReadOnlyProperty(L"id", &m_SessionID);
|
|
||||||
AddReadOnlyProperty(L"name", &m_Name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNetClient::CServerSession::ScriptingInit()
|
void CNetClient::CServerSession::ScriptingInit()
|
||||||
{
|
{
|
||||||
|
AddProperty(L"id", &CNetClient::CServerSession::m_SessionID, true);
|
||||||
|
AddProperty(L"name", &CNetClient::CServerSession::m_Name, true);
|
||||||
|
|
||||||
CJSObject<CServerSession>::ScriptingInit("NetClient_ServerSession");
|
CJSObject<CServerSession>::ScriptingInit("NetClient_ServerSession");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,18 +57,18 @@ void CNetClient::ScriptingInit()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
AddClassProperty(L"onStartGame", &CNetClient::m_OnStartGame);
|
AddProperty(L"onStartGame", &CNetClient::m_OnStartGame);
|
||||||
AddClassProperty(L"onChat", &CNetClient::m_OnChat);
|
AddProperty(L"onChat", &CNetClient::m_OnChat);
|
||||||
AddClassProperty(L"onConnectComplete", &CNetClient::m_OnConnectComplete);
|
AddProperty(L"onConnectComplete", &CNetClient::m_OnConnectComplete);
|
||||||
AddClassProperty(L"onDisconnect", &CNetClient::m_OnDisconnect);
|
AddProperty(L"onDisconnect", &CNetClient::m_OnDisconnect);
|
||||||
AddClassProperty(L"onClientConnect", &CNetClient::m_OnClientConnect);
|
AddProperty(L"onClientConnect", &CNetClient::m_OnClientConnect);
|
||||||
AddClassProperty(L"onClientDisconnect", &CNetClient::m_OnClientDisconnect);
|
AddProperty(L"onClientDisconnect", &CNetClient::m_OnClientDisconnect);
|
||||||
|
|
||||||
|
|
||||||
AddClassProperty(L"password", &CNetClient::m_Password);
|
AddProperty(L"password", &CNetClient::m_Password);
|
||||||
AddClassProperty<CStrW>(L"playerName", &CNetClient::m_Name);
|
AddProperty<CStrW>(L"playerName", &CNetClient::m_Name);
|
||||||
|
|
||||||
AddClassProperty(L"sessions", &CNetClient::m_JSI_ServerSessions);
|
AddProperty(L"sessions", &CNetClient::m_JSI_ServerSessions);
|
||||||
CJSMap<SessionMap>::ScriptingInit("NetClient_SessionMap");
|
CJSMap<SessionMap>::ScriptingInit("NetClient_SessionMap");
|
||||||
CJSObject<CNetClient>::ScriptingInit("NetClient");
|
CJSObject<CNetClient>::ScriptingInit("NetClient");
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ class CStartGameEvent: public CScriptEvent
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CStartGameEvent():
|
CStartGameEvent():
|
||||||
CScriptEvent(L"startGame", false, NET_JS_EVENT_START_GAME)
|
CScriptEvent(L"startGame", NET_JS_EVENT_START_GAME, false)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -29,12 +29,12 @@ class CChatEvent: public CScriptEvent
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
CChatEvent(CStrW sender, CStrW message):
|
CChatEvent(CStrW sender, CStrW message):
|
||||||
CScriptEvent(L"chat", false, NET_JS_EVENT_CHAT),
|
CScriptEvent(L"chat", NET_JS_EVENT_CHAT, false ),
|
||||||
m_Sender(sender),
|
m_Sender(sender),
|
||||||
m_Message(message)
|
m_Message(message)
|
||||||
{
|
{
|
||||||
AddReadOnlyProperty(L"sender", &m_Sender);
|
AddLocalProperty(L"sender", &m_Sender, true);
|
||||||
AddReadOnlyProperty(L"message", &m_Message);
|
AddLocalProperty(L"message", &m_Message, true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -45,12 +45,12 @@ class CConnectCompleteEvent: public CScriptEvent
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
CConnectCompleteEvent(CStrW message, bool success):
|
CConnectCompleteEvent(CStrW message, bool success):
|
||||||
CScriptEvent(L"connectComplete", false, NET_JS_EVENT_CONNECT_COMPLETE),
|
CScriptEvent(L"connectComplete", NET_JS_EVENT_CONNECT_COMPLETE, false),
|
||||||
m_Message(message),
|
m_Message(message),
|
||||||
m_Success(success)
|
m_Success(success)
|
||||||
{
|
{
|
||||||
AddReadOnlyProperty(L"message", &m_Message);
|
AddLocalProperty(L"message", &m_Message, true);
|
||||||
AddReadOnlyProperty(L"success", &m_Success);
|
AddLocalProperty(L"success", &m_Success, true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -60,10 +60,10 @@ class CDisconnectEvent: public CScriptEvent
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
CDisconnectEvent(CStrW message):
|
CDisconnectEvent(CStrW message):
|
||||||
CScriptEvent(L"disconnect", false, NET_JS_EVENT_DISCONNECT),
|
CScriptEvent(L"disconnect", NET_JS_EVENT_DISCONNECT, false),
|
||||||
m_Message(message)
|
m_Message(message)
|
||||||
{
|
{
|
||||||
AddReadOnlyProperty(L"message", &m_Message);
|
AddLocalProperty(L"message", &m_Message, true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -76,15 +76,15 @@ class CClientConnectDisconnectCommon: public CScriptEvent
|
|||||||
public:
|
public:
|
||||||
CClientConnectDisconnectCommon(const wchar_t* eventName, int eventType,
|
CClientConnectDisconnectCommon(const wchar_t* eventName, int eventType,
|
||||||
int sessionID, const CStrW &name, CNetServerSession *pSession):
|
int sessionID, const CStrW &name, CNetServerSession *pSession):
|
||||||
CScriptEvent(L"clientConnect", false, NET_JS_EVENT_CLIENT_CONNECT),
|
CScriptEvent(L"clientConnect", NET_JS_EVENT_CLIENT_CONNECT, false),
|
||||||
m_SessionID(sessionID),
|
m_SessionID(sessionID),
|
||||||
m_Name(name),
|
m_Name(name),
|
||||||
m_pSession(pSession)
|
m_pSession(pSession)
|
||||||
{
|
{
|
||||||
AddReadOnlyProperty(L"id", &m_SessionID);
|
AddLocalProperty(L"id", &m_SessionID, true);
|
||||||
AddReadOnlyProperty(L"name", &m_Name);
|
AddLocalProperty(L"name", &m_Name, true);
|
||||||
if (m_pSession)
|
if (m_pSession)
|
||||||
AddReadOnlyProperty(L"session", &m_pSession);
|
AddLocalProperty(L"session", &m_pSession, true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -60,18 +60,6 @@ CNetServer::CNetServer(CGame *pGame, CGameAttributes *pGameAttribs):
|
|||||||
ScriptingInit();
|
ScriptingInit();
|
||||||
);
|
);
|
||||||
|
|
||||||
AddProperty(L"sessions", &m_JSI_Sessions);
|
|
||||||
|
|
||||||
AddProperty(L"serverPlayerName", &m_ServerPlayerName);
|
|
||||||
AddProperty(L"serverName", &m_ServerName);
|
|
||||||
AddProperty(L"welcomeMessage", &m_WelcomeMessage);
|
|
||||||
|
|
||||||
AddProperty(L"port", &m_Port);
|
|
||||||
|
|
||||||
AddProperty(L"onChat", &m_OnChat);
|
|
||||||
AddProperty(L"onClientConnect", &m_OnClientConnect);
|
|
||||||
AddProperty(L"onClientDisconnect", &m_OnClientDisconnect);
|
|
||||||
|
|
||||||
m_pGameAttributes->SetUpdateCallback(AttributeUpdate, this);
|
m_pGameAttributes->SetUpdateCallback(AttributeUpdate, this);
|
||||||
m_pGameAttributes->SetPlayerUpdateCallback(PlayerAttributeUpdate, this);
|
m_pGameAttributes->SetPlayerUpdateCallback(PlayerAttributeUpdate, this);
|
||||||
m_pGameAttributes->SetPlayerSlotAssignmentCallback(PlayerSlotAssignmentCallback, this);
|
m_pGameAttributes->SetPlayerSlotAssignmentCallback(PlayerSlotAssignmentCallback, this);
|
||||||
@ -102,6 +90,18 @@ void CNetServer::ScriptingInit()
|
|||||||
|
|
||||||
AddMethod<bool, &CNetServer::JSI_Open>("open", 0);
|
AddMethod<bool, &CNetServer::JSI_Open>("open", 0);
|
||||||
|
|
||||||
|
AddProperty(L"sessions", &CNetServer::m_JSI_Sessions);
|
||||||
|
|
||||||
|
AddProperty(L"serverPlayerName", &CNetServer::m_ServerPlayerName);
|
||||||
|
AddProperty(L"serverName", &CNetServer::m_ServerName);
|
||||||
|
AddProperty(L"welcomeMessage", &CNetServer::m_WelcomeMessage);
|
||||||
|
|
||||||
|
AddProperty(L"port", &CNetServer::m_Port);
|
||||||
|
|
||||||
|
AddProperty(L"onChat", &CNetServer::m_OnChat);
|
||||||
|
AddProperty(L"onClientConnect", &CNetServer::m_OnClientConnect);
|
||||||
|
AddProperty(L"onClientDisconnect", &CNetServer::m_OnClientDisconnect);
|
||||||
|
|
||||||
CJSObject<CNetServer>::ScriptingInit("NetServer");
|
CJSObject<CNetServer>::ScriptingInit("NetServer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,9 +19,6 @@ CNetServerSession::CNetServerSession(CNetServer *pServer, CSocketInternal *pInt,
|
|||||||
ONCE(
|
ONCE(
|
||||||
ScriptingInit();
|
ScriptingInit();
|
||||||
);
|
);
|
||||||
|
|
||||||
AddProperty(L"id", &m_ID);
|
|
||||||
AddProperty(L"name", &m_Name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CNetServerSession::~CNetServerSession()
|
CNetServerSession::~CNetServerSession()
|
||||||
@ -209,6 +206,9 @@ void CNetServerSession::ScriptingInit()
|
|||||||
AddMethod<bool, &CNetServerSession::JSI_Close>("close", 0);
|
AddMethod<bool, &CNetServerSession::JSI_Close>("close", 0);
|
||||||
|
|
||||||
CJSObject<CNetServerSession>::ScriptingInit("NetSession");
|
CJSObject<CNetServerSession>::ScriptingInit("NetSession");
|
||||||
|
// Hope this doesn't break anything...
|
||||||
|
AddProperty( L"id", &CNetServerSession::m_ID );
|
||||||
|
AddProperty( L"name", (CStrW CNetServerSession::*)&CNetServerSession::m_Name );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CNetServerSession::JSI_Close(JSContext *cx, uintN argc, jsval *argv)
|
bool CNetServerSession::JSI_Close(JSContext *cx, uintN argc, jsval *argv)
|
||||||
|
@ -35,12 +35,12 @@ void CPlayer::ScriptingInit()
|
|||||||
AddMethod<jsval, &CPlayer::JSI_ToString>( "toString", 0 );
|
AddMethod<jsval, &CPlayer::JSI_ToString>( "toString", 0 );
|
||||||
AddMethod<jsval, &CPlayer::JSI_SetColour>( "setColour", 1);
|
AddMethod<jsval, &CPlayer::JSI_SetColour>( "setColour", 1);
|
||||||
|
|
||||||
AddReadOnlyClassProperty( L"id", &CPlayer::m_PlayerID );
|
AddProperty( L"id", &CPlayer::m_PlayerID, true );
|
||||||
// MT: Work out how this fits with the Synched stuff...
|
// MT: Work out how this fits with the Synched stuff...
|
||||||
|
|
||||||
// AddClassProperty( L"name", &CPlayer::m_Name );
|
// AddClassProperty( L"name", &CPlayer::m_Name );
|
||||||
// AddClassProperty( L"colour", &CPlayer::m_Colour );
|
// AddClassProperty( L"colour", &CPlayer::m_Colour );
|
||||||
AddClassProperty( L"controlled", (IJSObject::GetFn)JSI_GetControlledEntities );
|
AddProperty( L"controlled", (IJSObject::GetFn)JSI_GetControlledEntities );
|
||||||
|
|
||||||
CJSObject<CPlayer>::ScriptingInit( "Player" );
|
CJSObject<CPlayer>::ScriptingInit( "Player" );
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ bool CProfileNode::Return()
|
|||||||
|
|
||||||
void CProfileNode::ScriptingInit()
|
void CProfileNode::ScriptingInit()
|
||||||
{
|
{
|
||||||
AddClassProperty( L"name", (IJSObject::GetFn)CProfileNode::JS_GetName );
|
AddProperty( L"name", (IJSObject::GetFn)CProfileNode::JS_GetName );
|
||||||
/*
|
/*
|
||||||
AddReadOnlyClassProperty( L"callsTotal", &CProfileNode::calls_total );
|
AddReadOnlyClassProperty( L"callsTotal", &CProfileNode::calls_total );
|
||||||
AddReadOnlyClassProperty( L"callsPerFrame", &CProfileNode::calls_frame_last );
|
AddReadOnlyClassProperty( L"callsPerFrame", &CProfileNode::calls_frame_last );
|
||||||
|
@ -38,7 +38,7 @@ JSBool JSI_Selection::setSelection( JSContext* context, JSObject* globalObject,
|
|||||||
|
|
||||||
for( it = Info->m_Data->begin(); it < Info->m_Data->end(); it++ )
|
for( it = Info->m_Data->begin(); it < Info->m_Data->end(); it++ )
|
||||||
g_Selection.addSelection( *it );
|
g_Selection.addSelection( *it );
|
||||||
|
|
||||||
return( JS_TRUE );
|
return( JS_TRUE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,157 @@
|
|||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
#include "DOMEvent.h"
|
#include "DOMEvent.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
#include "Profile.h"
|
||||||
|
#include "ScriptObject.h"
|
||||||
|
|
||||||
CScriptEvent::CScriptEvent( const CStrW& Type, bool Cancelable, unsigned int TypeCode )
|
IEventTarget::~IEventTarget()
|
||||||
{
|
{
|
||||||
m_Type = Type; m_TypeCode = TypeCode; m_Cancelable = Cancelable; m_Cancelled = false; m_Timestamp = (long)( get_time() * 1000.0 );
|
HandlerMap::iterator it;
|
||||||
AddReadOnlyProperty( L"type", &m_Type );
|
for( it = m_Handlers_name.begin(); it != m_Handlers_name.end(); it++ )
|
||||||
AddReadOnlyProperty( L"cancelable", &m_Cancelable );
|
delete( it->second );
|
||||||
AddReadOnlyProperty( L"timeStamp", &m_Timestamp );
|
}
|
||||||
|
|
||||||
|
bool IEventTarget::_DispatchEvent( CScriptEvent* evt, IEventTarget* target )
|
||||||
|
{
|
||||||
|
if( before && before->_DispatchEvent( evt, target ) )
|
||||||
|
return( true ); // Stop propagation.
|
||||||
|
|
||||||
|
evt->m_CurrentTarget = this;
|
||||||
|
|
||||||
|
HandlerList::iterator it;
|
||||||
|
for( it = m_Handlers_id[evt->m_TypeCode].begin(); it != m_Handlers_id[evt->m_TypeCode].end(); it++ )
|
||||||
|
{
|
||||||
|
DOMEventHandler id = *it;
|
||||||
|
if( id && id->DispatchEvent( GetScriptExecContext( target ), evt ) )
|
||||||
|
return( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerRange range = m_Handlers_name.equal_range( evt->m_Type );
|
||||||
|
HandlerMap::iterator itm;
|
||||||
|
for( itm = range.first; itm != range.second; itm++ )
|
||||||
|
{
|
||||||
|
DOMEventHandler id = itm->second;
|
||||||
|
if( id && id->DispatchEvent( GetScriptExecContext( target ), evt ) )
|
||||||
|
return( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( after && after->_DispatchEvent( evt, target ) )
|
||||||
|
return( true ); // Stop propagation.
|
||||||
|
|
||||||
|
return( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IEventTarget::DispatchEvent( CScriptEvent* evt )
|
||||||
|
{
|
||||||
|
const char* data = g_Profiler.InternString( "script: " + (CStr8)evt->m_Type );
|
||||||
|
g_Profiler.StartScript( data );
|
||||||
|
evt->m_Target = this;
|
||||||
|
_DispatchEvent( evt, this );
|
||||||
|
g_Profiler.Stop();
|
||||||
|
return( !evt->m_Cancelled );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IEventTarget::AddHandler( int TypeCode, DOMEventHandler handler )
|
||||||
|
{
|
||||||
|
HandlerList::iterator it;
|
||||||
|
for( it = m_Handlers_id[TypeCode].begin(); it != m_Handlers_id[TypeCode].end(); it++ )
|
||||||
|
if( **it == *handler ) return( false );
|
||||||
|
m_Handlers_id[TypeCode].push_back( handler );
|
||||||
|
return( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IEventTarget::AddHandler( CStrW TypeString, DOMEventHandler handler )
|
||||||
|
{
|
||||||
|
HandlerMap::iterator it;
|
||||||
|
HandlerRange range = m_Handlers_name.equal_range( TypeString );
|
||||||
|
for( it = range.first; it != range.second; it++ )
|
||||||
|
if( *( it->second ) == *handler ) return( false );
|
||||||
|
m_Handlers_name.insert( HandlerMap::value_type( TypeString, handler ) );
|
||||||
|
return( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IEventTarget::RemoveHandler( int TypeCode, DOMEventHandler handler )
|
||||||
|
{
|
||||||
|
HandlerList::iterator it;
|
||||||
|
for( it = m_Handlers_id[TypeCode].begin(); it != m_Handlers_id[TypeCode].end(); it++ )
|
||||||
|
if( **it == *handler )
|
||||||
|
{
|
||||||
|
m_Handlers_id[TypeCode].erase( it );
|
||||||
|
return( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
return( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IEventTarget::RemoveHandler( CStrW TypeString, DOMEventHandler handler )
|
||||||
|
{
|
||||||
|
HandlerMap::iterator it;
|
||||||
|
HandlerRange range = m_Handlers_name.equal_range( TypeString );
|
||||||
|
for( it = range.first; it != range.second; it++ )
|
||||||
|
if( *( it->second ) == *handler )
|
||||||
|
{
|
||||||
|
delete( it->second );
|
||||||
|
m_Handlers_name.erase( it );
|
||||||
|
return( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
return( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IEventTarget::AddHandlerJS( JSContext* cx, uintN argc, jsval* argv )
|
||||||
|
{
|
||||||
|
assert( argc >= 2 );
|
||||||
|
DOMEventHandler handler = new CScriptObject( argv[1] );
|
||||||
|
if( !handler->Defined() )
|
||||||
|
{
|
||||||
|
delete( handler );
|
||||||
|
return( false );
|
||||||
|
}
|
||||||
|
if( !AddHandler( ToPrimitive<CStrW>( argv[0] ), handler ) )
|
||||||
|
{
|
||||||
|
delete( handler );
|
||||||
|
return( false );
|
||||||
|
}
|
||||||
|
return( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IEventTarget::RemoveHandlerJS( JSContext* cx, uintN argc, jsval* argv )
|
||||||
|
{
|
||||||
|
assert( argc >= 2 );
|
||||||
|
DOMEventHandler handler = new CScriptObject( argv[1] );
|
||||||
|
if( !handler->Defined() )
|
||||||
|
{
|
||||||
|
delete( handler );
|
||||||
|
return( false );
|
||||||
|
}
|
||||||
|
if( !RemoveHandler( ToPrimitive<CStrW>( argv[0] ), handler ) )
|
||||||
|
{
|
||||||
|
delete( handler );
|
||||||
|
return( false );
|
||||||
|
}
|
||||||
|
delete( handler );
|
||||||
|
return( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
CScriptEvent::CScriptEvent( const CStrW& Type, unsigned int TypeCode, bool Cancelable, bool Blockable )
|
||||||
|
{
|
||||||
|
m_Type = Type; m_TypeCode = TypeCode;
|
||||||
|
m_Cancelable = Cancelable; m_Cancelled = false;
|
||||||
|
m_Blockable = Blockable; m_Blocked = false;
|
||||||
|
m_Timestamp = (long)( get_time() * 1000.0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CScriptEvent::ScriptingInit()
|
void CScriptEvent::ScriptingInit()
|
||||||
{
|
{
|
||||||
AddMethod<jsval, &CScriptEvent::ToString>( "toString", 0 );
|
AddMethod<jsval, &CScriptEvent::ToString>( "toString", 0 );
|
||||||
AddMethod<jsval, &CScriptEvent::PreventDefault>( "preventDefault", 0 );
|
AddMethod<jsval, &CScriptEvent::PreventDefault>( "preventDefault", 0 );
|
||||||
|
AddMethod<jsval, &CScriptEvent::PreventDefault>( "cancel", 0 );
|
||||||
|
AddMethod<jsval, StopPropagation>( "stopPropagation", 0 );
|
||||||
|
|
||||||
|
AddProperty( L"type", &CScriptEvent::m_Type, true );
|
||||||
|
AddProperty( L"cancelable", &CScriptEvent::m_Cancelable, true );
|
||||||
|
AddProperty( L"blockable", &CScriptEvent::m_Blockable, true );
|
||||||
|
AddProperty( L"timestamp", &CScriptEvent::m_Timestamp, true );
|
||||||
|
|
||||||
CJSObject<CScriptEvent>::ScriptingInit( "Event" );
|
CJSObject<CScriptEvent>::ScriptingInit( "Event" );
|
||||||
}
|
}
|
||||||
@ -25,6 +163,13 @@ jsval CScriptEvent::PreventDefault( JSContext* cx, uintN argc, jsval* argv )
|
|||||||
return( JSVAL_VOID );
|
return( JSVAL_VOID );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jsval CScriptEvent::StopPropagation( JSContext* cx, uintN argc, jsval* argv )
|
||||||
|
{
|
||||||
|
if( m_Blockable )
|
||||||
|
m_Blocked = true;
|
||||||
|
return( JSVAL_VOID );
|
||||||
|
}
|
||||||
|
|
||||||
jsval CScriptEvent::ToString( JSContext* cx, uintN argc, jsval* argv )
|
jsval CScriptEvent::ToString( JSContext* cx, uintN argc, jsval* argv )
|
||||||
{
|
{
|
||||||
wchar_t buffer[256];
|
wchar_t buffer[256];
|
||||||
|
@ -9,6 +9,56 @@
|
|||||||
|
|
||||||
#include "ScriptableObject.h"
|
#include "ScriptableObject.h"
|
||||||
|
|
||||||
|
#include "EventTypes.h"
|
||||||
|
|
||||||
|
class CScriptObject;
|
||||||
|
class CScriptEvent;
|
||||||
|
|
||||||
|
typedef CScriptObject* DOMEventHandler;
|
||||||
|
|
||||||
|
class IEventTarget
|
||||||
|
{
|
||||||
|
// Return 'true' if we should stop propagating.
|
||||||
|
bool _DispatchEvent( CScriptEvent* evt, IEventTarget* target );
|
||||||
|
|
||||||
|
// Events dispatched to this object are sent here before being processed.
|
||||||
|
IEventTarget* before;
|
||||||
|
// Events dispatched to this object are sent here after being processed.
|
||||||
|
IEventTarget* after;
|
||||||
|
|
||||||
|
typedef std::vector<DOMEventHandler> HandlerList;
|
||||||
|
HandlerList m_Handlers_id[EVENT_LAST];
|
||||||
|
typedef STL_HASH_MULTIMAP<CStrW, DOMEventHandler, CStrW_hash_compare> HandlerMap;
|
||||||
|
HandlerMap m_Handlers_name;
|
||||||
|
typedef std::pair<HandlerMap::iterator, HandlerMap::iterator> HandlerRange;
|
||||||
|
public:
|
||||||
|
IEventTarget()
|
||||||
|
{
|
||||||
|
before = NULL;
|
||||||
|
after = NULL;
|
||||||
|
}
|
||||||
|
~IEventTarget();
|
||||||
|
inline void SetPriorObject( IEventTarget* obj ) { before = obj; }
|
||||||
|
inline void SetNextObject( IEventTarget* obj ) { after = obj; }
|
||||||
|
|
||||||
|
// Returns false if the handler was already present
|
||||||
|
bool AddHandler( int TypeCode, DOMEventHandler handler );
|
||||||
|
bool AddHandler( CStrW TypeString, DOMEventHandler handler );
|
||||||
|
// Returns false if the handler was not present
|
||||||
|
bool RemoveHandler( int TypeCode, DOMEventHandler handler );
|
||||||
|
bool RemoveHandler( CStrW TypeString, DOMEventHandler handler );
|
||||||
|
|
||||||
|
bool AddHandlerJS( JSContext* cx, uintN argc, jsval* argv );
|
||||||
|
bool RemoveHandlerJS( JSContext* cx, uintN argc, jsval* argv );
|
||||||
|
|
||||||
|
// Return the JSObject* we'd like to be the 'this' object
|
||||||
|
// when executing the handler. The argument is the object
|
||||||
|
// to which the event is targeted.
|
||||||
|
virtual JSObject* GetScriptExecContext( IEventTarget* target ) = 0;
|
||||||
|
|
||||||
|
bool DispatchEvent( CScriptEvent* evt );
|
||||||
|
};
|
||||||
|
|
||||||
class CScriptEvent : public CJSObject<CScriptEvent>
|
class CScriptEvent : public CJSObject<CScriptEvent>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -20,10 +70,10 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Target (currently unused)
|
// Target (currently unused)
|
||||||
// EventTarget* m_Target;
|
IEventTarget* m_Target;
|
||||||
|
|
||||||
// Listening object currently being processed (currently unused)
|
// Listening object currently being processed (currently unused)
|
||||||
// EventTarget* m_CurrentTarget;
|
IEventTarget* m_CurrentTarget;
|
||||||
|
|
||||||
// Phase type (currently unused)
|
// Phase type (currently unused)
|
||||||
// EPhaseType m_EventPhase;
|
// EPhaseType m_EventPhase;
|
||||||
@ -34,6 +84,9 @@ public:
|
|||||||
// Can be cancelled (default actions prevented)
|
// Can be cancelled (default actions prevented)
|
||||||
bool m_Cancelable;
|
bool m_Cancelable;
|
||||||
|
|
||||||
|
// Can be blocked (prevented from propogating along the handler chain)
|
||||||
|
bool m_Blockable;
|
||||||
|
|
||||||
// Timestamp (milliseconds since epoch (start of game?))
|
// Timestamp (milliseconds since epoch (start of game?))
|
||||||
i32 m_Timestamp;
|
i32 m_Timestamp;
|
||||||
|
|
||||||
@ -46,13 +99,17 @@ public:
|
|||||||
// Has been cancelled?
|
// Has been cancelled?
|
||||||
bool m_Cancelled;
|
bool m_Cancelled;
|
||||||
|
|
||||||
|
// Has it been blocked (won't be sent to any more handlers)
|
||||||
|
bool m_Blocked;
|
||||||
|
|
||||||
// --
|
// --
|
||||||
|
|
||||||
jsval ToString( JSContext* cx, uintN argc, jsval* argv );
|
jsval ToString( JSContext* cx, uintN argc, jsval* argv );
|
||||||
jsval PreventDefault( JSContext* cx, uintN argc, jsval* argv );
|
jsval PreventDefault( JSContext* cx, uintN argc, jsval* argv );
|
||||||
|
jsval StopPropagation( JSContext* cx, uintN argc, jsval* argv );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CScriptEvent( const CStrW& Type, bool Cancelable, unsigned int TypeCode = (unsigned int)-1 );
|
CScriptEvent( const CStrW& Type, unsigned int TypeCode = (unsigned int)-1, bool Cancelable = true, bool Blockable = true );
|
||||||
static void ScriptingInit();
|
static void ScriptingInit();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,13 +62,6 @@ template<typename T> bool ToPrimitive( JSContext* cx, jsval v, T*& Storage )
|
|||||||
return( true );
|
return( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
template<typename T> JSObject* ToScript( T** Native )
|
|
||||||
{
|
|
||||||
return( ToScript( *Native ) );
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
template<typename T> inline T ToPrimitive( JSContext* cx, jsval v ) { T Temp; ToPrimitive( cx, v, Temp ); return( Temp ); }
|
template<typename T> inline T ToPrimitive( JSContext* cx, jsval v ) { T Temp; ToPrimitive( cx, v, Temp ); return( Temp ); }
|
||||||
template<typename T> inline T ToPrimitive( jsval v ) { return( ToPrimitive<T>( g_ScriptingHost.GetContext(), v ) ); }
|
template<typename T> inline T ToPrimitive( jsval v ) { return( ToPrimitive<T>( g_ScriptingHost.GetContext(), v ) ); }
|
||||||
|
|
||||||
|
@ -48,10 +48,10 @@ void SColour::SColourInit( float _r, float _g, float _b, float _a )
|
|||||||
void SColour::ScriptingInit()
|
void SColour::ScriptingInit()
|
||||||
{
|
{
|
||||||
AddMethod<jsval, &SColour::ToString>( "toString", 0 );
|
AddMethod<jsval, &SColour::ToString>( "toString", 0 );
|
||||||
AddClassProperty<float>( L"r", (float IJSObject::*)&SColour::r );
|
AddProperty<float>( L"r", (float IJSObject::*)&SColour::r );
|
||||||
AddClassProperty<float>( L"g", (float IJSObject::*)&SColour::g );
|
AddProperty<float>( L"g", (float IJSObject::*)&SColour::g );
|
||||||
AddClassProperty<float>( L"b", (float IJSObject::*)&SColour::b );
|
AddProperty<float>( L"b", (float IJSObject::*)&SColour::b );
|
||||||
AddClassProperty<float>( L"a", (float IJSObject::*)&SColour::a );
|
AddProperty<float>( L"a", (float IJSObject::*)&SColour::a );
|
||||||
|
|
||||||
CJSObject<SColour>::ScriptingInit( "Colour", SColour::Construct, 3 );
|
CJSObject<SColour>::ScriptingInit( "Colour", SColour::Construct, 3 );
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "LightEnv.h"
|
#include "LightEnv.h"
|
||||||
#include "MapWriter.h"
|
#include "MapWriter.h"
|
||||||
|
#include "GameEvents.h"
|
||||||
|
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "Network/Server.h"
|
#include "Network/Server.h"
|
||||||
@ -59,6 +60,8 @@ JSFunctionSpec ScriptFunctionTable[] =
|
|||||||
{"getGlobal", getGlobal, 0, 0, 0 },
|
{"getGlobal", getGlobal, 0, 0, 0 },
|
||||||
{"getGUIGlobal", getGUIGlobal, 0, 0, 0 },
|
{"getGUIGlobal", getGUIGlobal, 0, 0, 0 },
|
||||||
{"setCursor", setCursor, 1, 0, 0 },
|
{"setCursor", setCursor, 1, 0, 0 },
|
||||||
|
{"addGlobalHandler", AddGlobalHandler, 2, 0, 0 },
|
||||||
|
{"removeGlobalHandler", RemoveGlobalHandler, 2, 0, 0 },
|
||||||
{"setCameraTarget", setCameraTarget, 1, 0, 0 },
|
{"setCameraTarget", setCameraTarget, 1, 0, 0 },
|
||||||
{"startGame", startGame, 0, 0, 0 },
|
{"startGame", startGame, 0, 0, 0 },
|
||||||
{"endGame", endGame, 0, 0, 0 },
|
{"endGame", endGame, 0, 0, 0 },
|
||||||
@ -227,6 +230,18 @@ JSBool SetLocalPlayer( JSContext* context, JSObject* obj, jsval id, jsval* vp )
|
|||||||
return( JS_TRUE );
|
return( JS_TRUE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSBool AddGlobalHandler( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval )
|
||||||
|
{
|
||||||
|
*rval = BOOLEAN_TO_JSVAL( g_JSGameEvents.AddHandlerJS( cx, argc, argv ) );
|
||||||
|
return( JS_TRUE );
|
||||||
|
}
|
||||||
|
|
||||||
|
JSBool RemoveGlobalHandler( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval )
|
||||||
|
{
|
||||||
|
*rval = BOOLEAN_TO_JSVAL( g_JSGameEvents.RemoveHandlerJS( cx, argc, argv ) );
|
||||||
|
return( JS_TRUE );
|
||||||
|
}
|
||||||
|
|
||||||
JSBool setCameraTarget( JSContext* context, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval )
|
JSBool setCameraTarget( JSContext* context, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval )
|
||||||
{
|
{
|
||||||
CVector3D* target;
|
CVector3D* target;
|
||||||
|
@ -20,7 +20,11 @@ JSBool GetPlayerSet( JSContext* context, JSObject* globalObject, jsval id, jsval
|
|||||||
JSBool GetLocalPlayer( JSContext* context, JSObject* globalObject, jsval id, jsval* vp );
|
JSBool GetLocalPlayer( JSContext* context, JSObject* globalObject, jsval id, jsval* vp );
|
||||||
JSBool SetLocalPlayer( JSContext* context, JSObject* globalObject, jsval id, jsval* vp );
|
JSBool SetLocalPlayer( JSContext* context, JSObject* globalObject, jsval id, jsval* vp );
|
||||||
JSBool GetGaiaPlayer( JSContext* context, JSObject* globalObject, jsval id, jsval* vp );
|
JSBool GetGaiaPlayer( JSContext* context, JSObject* globalObject, jsval id, jsval* vp );
|
||||||
JSBool GetLocalPlayer( JSContext* context, JSObject* globalObject, jsval argv, jsval* vp );
|
// JSBool SetGaiaPlayer( JSContext* context, JSObject* globalObject, jsval argv, jsval* vp );
|
||||||
|
|
||||||
|
// Events system
|
||||||
|
JSFunc AddGlobalHandler;
|
||||||
|
JSFunc RemoveGlobalHandler;
|
||||||
|
|
||||||
// Camera
|
// Camera
|
||||||
JSFunc setCameraTarget;
|
JSFunc setCameraTarget;
|
||||||
|
@ -4,36 +4,6 @@
|
|||||||
//
|
//
|
||||||
// Mark Thompson (mark@wildfiregames.com / mot20@cam.ac.uk)
|
// Mark Thompson (mark@wildfiregames.com / mot20@cam.ac.uk)
|
||||||
//
|
//
|
||||||
// General idea:
|
|
||||||
//
|
|
||||||
// IJSProperty is the interface representing a property of an object.
|
|
||||||
// Objects contain a mapping of names->IJSProperties
|
|
||||||
// Some IJSProperties wrap C++ variables that are declared by the engine
|
|
||||||
// Others wrap pairs of getter/setter functions
|
|
||||||
// Most, however, wrap a jsval and are defined by scripts and XML files.
|
|
||||||
// Objects may also have a parent object. If an attempt is made to
|
|
||||||
// access a property that doesn't exist in this object, the parent's object
|
|
||||||
// is checked, and so on.
|
|
||||||
// To allow this parent system to work for C++ properties, when a C++
|
|
||||||
// is set on an object, it's also set on any object that inherits it
|
|
||||||
// (Unless that object specifies its own value for that property, or
|
|
||||||
// the property is marked as being uninheritable)
|
|
||||||
|
|
||||||
// Objects and properties may be flagged read-only, causing all attempts to
|
|
||||||
// set values to become no-ops. If an object is read-only, all properties are
|
|
||||||
// - even ones that are flagged as writable.
|
|
||||||
|
|
||||||
// Usage: Create a class CSomething inheriting CJSObject<CSomething>
|
|
||||||
// In CSomething's constructor, add properties to the new object with
|
|
||||||
// AddProperty( name, pointer-to-C++-variable ).
|
|
||||||
// Also, ScriptingInit( "Some Name" ) must be called at initialization
|
|
||||||
// - put it in main. There's also AddMethod<ReturnType, NativeFunction>( Name,
|
|
||||||
// MinArgs ) - call that at initialization, too.
|
|
||||||
// If you include data members or functions that return types that JSConversions.h
|
|
||||||
// doesn't handle sensibly, you need to make it do so.
|
|
||||||
// If you're looking for examples, DOMEvent.h is the simplest user of this class
|
|
||||||
// CBaseEntity and CEntity do also (and use other stuff not mentioned above)
|
|
||||||
// but are more complex.
|
|
||||||
|
|
||||||
#include "scripting/ScriptingHost.h"
|
#include "scripting/ScriptingHost.h"
|
||||||
#include "JSConversions.h"
|
#include "JSConversions.h"
|
||||||
@ -41,72 +11,27 @@
|
|||||||
#ifndef SCRIPTABLE_INCLUDED
|
#ifndef SCRIPTABLE_INCLUDED
|
||||||
#define SCRIPTABLE_INCLUDED
|
#define SCRIPTABLE_INCLUDED
|
||||||
|
|
||||||
|
#define ALLOW_NONSHARED_NATIVES
|
||||||
|
|
||||||
class IJSObject;
|
class IJSObject;
|
||||||
|
|
||||||
class IJSProperty
|
class IJSProperty
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual jsval Get( JSContext* cx, IJSObject* obj ) = 0;
|
||||||
bool m_AllowsInheritance;
|
virtual void Set( JSContext* cx, IJSObject* obj, jsval value ) = 0;
|
||||||
bool m_Inherited;
|
|
||||||
bool m_Intrinsic;
|
|
||||||
|
|
||||||
// This is to make sure that all the fields are initialized at construction
|
|
||||||
inline IJSProperty():
|
|
||||||
m_AllowsInheritance(true),
|
|
||||||
m_Inherited(true),
|
|
||||||
m_Intrinsic(true)
|
|
||||||
{}
|
|
||||||
|
|
||||||
virtual jsval Get( JSContext* cx, IJSObject* owner ) = 0;
|
|
||||||
virtual void Set( JSContext* cx, IJSObject* owner, jsval Value ) = 0;
|
|
||||||
|
|
||||||
// Copies the data directly out of a parent property
|
|
||||||
// Warning: Don't use if you're not certain the properties are not of the same type.
|
|
||||||
virtual void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty ) = 0;
|
|
||||||
|
|
||||||
jsval Get( IJSObject* owner ) { return( Get( g_ScriptingHost.GetContext(), owner ) ); }
|
|
||||||
void Set( IJSObject* owner, jsval Value ) { return( Set( g_ScriptingHost.GetContext(), owner, Value ) ); }
|
|
||||||
|
|
||||||
virtual ~IJSProperty() {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class IJSObject
|
class IJSObject
|
||||||
{
|
{
|
||||||
// Make copy constructor and assignment operator private - since copying of
|
|
||||||
// these objects is unsafe unless done specially.
|
|
||||||
// These will never be implemented (they are, after all, here to *prevent*
|
|
||||||
// copying)
|
|
||||||
IJSObject(const IJSObject &other);
|
|
||||||
IJSObject& operator=(const IJSObject &other);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef STL_HASH_MAP<CStrW, IJSProperty*, CStrW_hash_compare> PropertyTable;
|
typedef STL_HASH_MAP<CStrW, IJSProperty*, CStrW_hash_compare> PropertyTable;
|
||||||
typedef std::vector<IJSObject*> InheritorsList;
|
|
||||||
|
|
||||||
// Used for freshen/update
|
|
||||||
typedef void (IJSObject::*NotifyFn)();
|
|
||||||
|
|
||||||
// Property getters and setters
|
// Property getters and setters
|
||||||
typedef jsval (IJSObject::*GetFn)();
|
typedef jsval (IJSObject::*GetFn)();
|
||||||
typedef void (IJSObject::*SetFn)( jsval );
|
typedef void (IJSObject::*SetFn)( jsval value );
|
||||||
|
|
||||||
// Properties of this object
|
// Return a pointer to a property, if it exists
|
||||||
PropertyTable m_Properties;
|
|
||||||
|
|
||||||
// Parent object
|
|
||||||
IJSObject* m_Parent;
|
|
||||||
|
|
||||||
// Objects that inherit from this
|
|
||||||
InheritorsList m_Inheritors;
|
|
||||||
|
|
||||||
// Set the base, and rebuild
|
|
||||||
void SetBase( IJSObject* m_Parent );
|
|
||||||
|
|
||||||
// Rebuild any intrinsic (mapped-to-C++-variable) properties
|
|
||||||
virtual void Rebuild() = 0;
|
|
||||||
|
|
||||||
// Check for a property
|
|
||||||
virtual IJSProperty* HasProperty( CStrW PropertyName ) = 0;
|
virtual IJSProperty* HasProperty( CStrW PropertyName ) = 0;
|
||||||
|
|
||||||
// Retrieve the value of a property (returning false if that property is not defined)
|
// Retrieve the value of a property (returning false if that property is not defined)
|
||||||
@ -121,263 +46,49 @@ public:
|
|||||||
|
|
||||||
template<typename T, bool ReadOnly = false> class CJSObject;
|
template<typename T, bool ReadOnly = false> class CJSObject;
|
||||||
|
|
||||||
template<typename T> class CJSPropertyAccessor
|
template<typename T, bool ReadOnly> class CJSProperty : public IJSProperty
|
||||||
{
|
|
||||||
T* m_Owner;
|
|
||||||
CStrW m_PropertyRoot;
|
|
||||||
template<typename Q, bool ReadOnly> friend class CJSObject;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CJSPropertyAccessor( T* Owner, CStrW PropertyRoot )
|
|
||||||
{
|
|
||||||
m_Owner = Owner;
|
|
||||||
m_PropertyRoot = PropertyRoot;
|
|
||||||
}
|
|
||||||
static JSObject* CreateAccessor( JSContext* cx, T* Owner, CStrW PropertyRoot )
|
|
||||||
{
|
|
||||||
JSObject* Accessor = JS_NewObject( cx, &JSI_Class, NULL, NULL );
|
|
||||||
JS_SetPrivate( cx, Accessor, new CJSPropertyAccessor( Owner, PropertyRoot ) );
|
|
||||||
|
|
||||||
return( Accessor );
|
|
||||||
}
|
|
||||||
static JSBool JSGetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
|
|
||||||
{
|
|
||||||
CJSPropertyAccessor* Instance = (CJSPropertyAccessor*)JS_GetPrivate( cx, obj );
|
|
||||||
if( !Instance ) return( JS_TRUE );
|
|
||||||
|
|
||||||
CStrW PropName = Instance->m_PropertyRoot + CStrW( L"." ) + g_ScriptingHost.ValueToUCString( id );
|
|
||||||
|
|
||||||
Instance->m_Owner->GetProperty( cx, PropName, vp );
|
|
||||||
|
|
||||||
return( JS_TRUE );
|
|
||||||
}
|
|
||||||
static JSBool JSSetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
|
|
||||||
{
|
|
||||||
CJSPropertyAccessor* Instance = (CJSPropertyAccessor*)JS_GetPrivate( cx, obj );
|
|
||||||
if( !Instance ) return( JS_TRUE );
|
|
||||||
|
|
||||||
CStrW PropName = g_ScriptingHost.ValueToUCString( id );
|
|
||||||
|
|
||||||
Instance->m_Owner->SetProperty( cx, Instance->m_PropertyRoot + CStrW( L"." ) + PropName, vp );
|
|
||||||
|
|
||||||
return( JS_TRUE );
|
|
||||||
}
|
|
||||||
static JSBool JSPrimitive( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
|
||||||
{
|
|
||||||
CJSPropertyAccessor* Instance = (CJSPropertyAccessor*)JS_GetPrivate( cx, obj );
|
|
||||||
if( !Instance ) return( JS_TRUE );
|
|
||||||
|
|
||||||
// Check all along the inheritance tree
|
|
||||||
// Possible optimization: Store the hashed value over the lookups
|
|
||||||
IJSObject* Target = Instance->m_Owner;
|
|
||||||
IJSProperty* Property;
|
|
||||||
|
|
||||||
while( Target )
|
|
||||||
{
|
|
||||||
Property = Target->HasProperty( Instance->m_PropertyRoot );
|
|
||||||
if( Property )
|
|
||||||
{
|
|
||||||
*rval = Property->Get( cx, Target );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Target = Target->m_Parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return( JS_TRUE );
|
|
||||||
}
|
|
||||||
static JSBool JSToString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
|
||||||
{
|
|
||||||
CJSPropertyAccessor* Instance = (CJSPropertyAccessor*)JS_GetPrivate( cx, obj );
|
|
||||||
if( !Instance ) return( JS_TRUE );
|
|
||||||
|
|
||||||
// Check all along the inheritance tree
|
|
||||||
// TODO: Optimization: Store the hashed value over the lookups
|
|
||||||
IJSObject* Target = Instance->m_Owner;
|
|
||||||
IJSProperty* Property;
|
|
||||||
JSString* str;
|
|
||||||
|
|
||||||
while( Target )
|
|
||||||
{
|
|
||||||
Property = Target->HasProperty( Instance->m_PropertyRoot );
|
|
||||||
if( Property )
|
|
||||||
{
|
|
||||||
str = JS_ValueToString( cx, Property->Get( cx, Target ) );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Target = Target->m_Parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
*rval = STRING_TO_JSVAL( str );
|
|
||||||
|
|
||||||
return( JS_TRUE );
|
|
||||||
}
|
|
||||||
static JSClass JSI_Class;
|
|
||||||
static void ScriptingInit()
|
|
||||||
{
|
|
||||||
JSFunctionSpec JSI_methods[] = { { "valueOf", JSPrimitive, 0, 0, 0 }, { "toString", JSToString, 0, 0, 0 }, { 0 } };
|
|
||||||
JSPropertySpec JSI_props[] = { { 0 } };
|
|
||||||
|
|
||||||
g_ScriptingHost.DefineCustomObjectType( &JSI_Class, NULL, 0, JSI_props, JSI_methods, NULL, NULL );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> JSClass CJSPropertyAccessor<T>::JSI_Class = {
|
|
||||||
"Property", JSCLASS_HAS_PRIVATE,
|
|
||||||
JS_PropertyStub, JS_PropertyStub,
|
|
||||||
JSGetProperty, JSSetProperty,
|
|
||||||
JS_EnumerateStub, JS_ResolveStub,
|
|
||||||
JS_ConvertStub, JS_FinalizeStub,
|
|
||||||
NULL, NULL, NULL, NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template<typename T, bool ReadOnly> class CJSSharedProperty : public IJSProperty
|
|
||||||
{
|
{
|
||||||
T IJSObject::*m_Data;
|
T IJSObject::*m_Data;
|
||||||
|
|
||||||
// Function on Owner to call after value is changed
|
|
||||||
IJSObject::NotifyFn m_Update;
|
|
||||||
|
|
||||||
// Function on Owner to call before reading or writing the value
|
|
||||||
IJSObject::NotifyFn m_Freshen;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CJSSharedProperty( T IJSObject::*Data, bool AllowsInheritance = false, IJSObject::NotifyFn Update = NULL, IJSObject::NotifyFn Freshen = NULL )
|
CJSProperty( T IJSObject::*Data )
|
||||||
{
|
{
|
||||||
m_Data = Data;
|
m_Data = Data;
|
||||||
m_AllowsInheritance = AllowsInheritance;
|
|
||||||
m_Update = Update;
|
|
||||||
m_Freshen = Freshen;
|
|
||||||
m_Intrinsic = true;
|
|
||||||
m_Inherited = true;
|
|
||||||
}
|
}
|
||||||
jsval Get( JSContext* cx, IJSObject* owner )
|
jsval Get( JSContext* cx, IJSObject* owner )
|
||||||
{
|
{
|
||||||
if( m_Freshen ) (owner->*m_Freshen)();
|
|
||||||
return( ToJSVal( owner->*m_Data ) );
|
return( ToJSVal( owner->*m_Data ) );
|
||||||
}
|
}
|
||||||
void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty )
|
|
||||||
{
|
|
||||||
debug_warn( "Inheritance not supported for CJSSharedProperties" );
|
|
||||||
}
|
|
||||||
void Set( JSContext* cx, IJSObject* owner, jsval Value )
|
void Set( JSContext* cx, IJSObject* owner, jsval Value )
|
||||||
{
|
{
|
||||||
if( !ReadOnly )
|
if( !ReadOnly )
|
||||||
{
|
ToPrimitive( cx, Value, owner->*m_Data );
|
||||||
if( m_Freshen ) (owner->*m_Freshen)();
|
|
||||||
if( ToPrimitive( cx, Value, owner->*m_Data ) )
|
|
||||||
if( m_Update ) (owner->*m_Update)();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, bool ReadOnly> class CJSProperty : public IJSProperty
|
#ifdef ALLOW_NONSHARED_NATIVES
|
||||||
|
|
||||||
|
template<typename T, bool ReadOnly> class CJSNonsharedProperty : public IJSProperty
|
||||||
{
|
{
|
||||||
T* m_Data;
|
T* m_Data;
|
||||||
|
|
||||||
// Function on Owner to call after value is changed
|
|
||||||
IJSObject::NotifyFn m_Update;
|
|
||||||
|
|
||||||
// Function on Owner to call before reading or writing the value
|
|
||||||
IJSObject::NotifyFn m_Freshen;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CJSProperty( T* Data, bool AllowsInheritance = false, IJSObject::NotifyFn Update = NULL, IJSObject::NotifyFn Freshen = NULL )
|
CJSNonsharedProperty( T* Data )
|
||||||
{
|
{
|
||||||
m_Data = Data;
|
m_Data = Data;
|
||||||
m_AllowsInheritance = AllowsInheritance;
|
|
||||||
m_Update = Update;
|
|
||||||
m_Freshen = Freshen;
|
|
||||||
m_Intrinsic = true;
|
|
||||||
}
|
}
|
||||||
jsval Get( JSContext* cx, IJSObject* owner )
|
jsval Get( JSContext* cx, IJSObject* owner )
|
||||||
{
|
{
|
||||||
if( m_Freshen ) (owner->*m_Freshen)();
|
|
||||||
return( ToJSVal( *m_Data ) );
|
return( ToJSVal( *m_Data ) );
|
||||||
}
|
}
|
||||||
void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty )
|
|
||||||
{
|
|
||||||
*m_Data = *( ( (CJSProperty*)CopyProperty )->m_Data );
|
|
||||||
}
|
|
||||||
void Set( JSContext* cx, IJSObject* owner, jsval Value )
|
void Set( JSContext* cx, IJSObject* owner, jsval Value )
|
||||||
{
|
{
|
||||||
if( !ReadOnly )
|
if( !ReadOnly )
|
||||||
{
|
ToPrimitive( cx, Value, *m_Data );
|
||||||
if( m_Freshen ) (owner->*m_Freshen)();
|
|
||||||
if( ToPrimitive( cx, Value, *m_Data ) )
|
|
||||||
if( m_Update ) (owner->*m_Update)();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class CJSReflector
|
|
||||||
{
|
|
||||||
template<typename Q, bool ReadOnly> friend class CJSObject;
|
|
||||||
JSObject* m_JSAccessor;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CJSDynamicProperty : public IJSProperty
|
|
||||||
{
|
|
||||||
template<typename Q, bool ReadOnly> friend class CJSObject;
|
|
||||||
|
|
||||||
JSObject* m_JSAccessor;
|
|
||||||
public:
|
|
||||||
CJSDynamicProperty()
|
|
||||||
{
|
|
||||||
m_JSAccessor = NULL;
|
|
||||||
m_Intrinsic = false;
|
|
||||||
m_Inherited = false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CJSValProperty : public CJSDynamicProperty
|
#endif /* ALLOW_NONSHARED_NATIVES */
|
||||||
{
|
|
||||||
template<typename Q, bool ReadOnly> friend class CJSObject;
|
|
||||||
|
|
||||||
jsval m_Data;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CJSValProperty( jsval Data, bool Inherited )
|
|
||||||
{
|
|
||||||
m_Inherited = Inherited;
|
|
||||||
m_Data = Data;
|
|
||||||
Root();
|
|
||||||
}
|
|
||||||
~CJSValProperty()
|
|
||||||
{
|
|
||||||
Uproot();
|
|
||||||
}
|
|
||||||
void Root()
|
|
||||||
{
|
|
||||||
if( JSVAL_IS_GCTHING( m_Data ) )
|
|
||||||
#ifndef NDEBUG
|
|
||||||
JS_AddNamedRoot( g_ScriptingHost.GetContext(), (void*)&m_Data, "jsval property" );
|
|
||||||
#else
|
|
||||||
JS_AddRoot( g_ScriptingHost.GetContext(), (void*)&m_Data );
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
void Uproot()
|
|
||||||
{
|
|
||||||
if( JSVAL_IS_GCTHING( m_Data ) )
|
|
||||||
JS_RemoveRoot( g_ScriptingHost.GetContext(), (void*)&m_Data );
|
|
||||||
}
|
|
||||||
jsval Get( JSContext* cx, IJSObject* owner )
|
|
||||||
{
|
|
||||||
return( m_Data );
|
|
||||||
}
|
|
||||||
void Set( JSContext* cx, IJSObject* owner, jsval Value )
|
|
||||||
{
|
|
||||||
Uproot();
|
|
||||||
m_Data = Value;
|
|
||||||
Root();
|
|
||||||
}
|
|
||||||
void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty )
|
|
||||||
{
|
|
||||||
assert( 0 && "ImmediateCopy called on a CJSValProperty (something's gone wrong with the inheritance on this object)" );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CJSFunctionProperty : public IJSProperty
|
class CJSFunctionProperty : public IJSProperty
|
||||||
{
|
{
|
||||||
@ -390,28 +101,59 @@ class CJSFunctionProperty : public IJSProperty
|
|||||||
public:
|
public:
|
||||||
CJSFunctionProperty( IJSObject::GetFn Getter, IJSObject::SetFn Setter )
|
CJSFunctionProperty( IJSObject::GetFn Getter, IJSObject::SetFn Setter )
|
||||||
{
|
{
|
||||||
m_Inherited = false;
|
|
||||||
m_Intrinsic = true;
|
|
||||||
m_Getter = Getter;
|
m_Getter = Getter;
|
||||||
m_Setter = Setter;
|
m_Setter = Setter;
|
||||||
// Must at least be able to read
|
// Must at least be able to read
|
||||||
assert( m_Getter );
|
assert( m_Getter );
|
||||||
}
|
}
|
||||||
jsval Get( JSContext* cx, IJSObject* owner )
|
jsval Get( JSContext* cx, IJSObject* obj )
|
||||||
{
|
{
|
||||||
return( (owner->*m_Getter)() );
|
return( (obj->*m_Getter)() );
|
||||||
}
|
}
|
||||||
void Set( JSContext* cx, IJSObject* owner, jsval Value )
|
void Set( JSContext* cx, IJSObject* obj, jsval value )
|
||||||
{
|
{
|
||||||
if( m_Setter )
|
if( m_Setter )
|
||||||
(owner->*m_Setter)( Value );
|
(obj->*m_Setter)( value );
|
||||||
}
|
|
||||||
void ImmediateCopy( IJSObject* CopyTo, IJSObject* CopyFrom, IJSProperty* CopyProperty )
|
|
||||||
{
|
|
||||||
assert( 0 && "ImmediateCopy called on a property wrapping getter/setter functions (something's gone wrong with the inheritance for this object)" );
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CJSValProperty : public IJSProperty
|
||||||
|
{
|
||||||
|
template<typename Q, bool ReadOnly> friend class CJSObject;
|
||||||
|
|
||||||
|
jsval m_Data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CJSValProperty( jsval Data )
|
||||||
|
{
|
||||||
|
m_Data = Data;
|
||||||
|
Root();
|
||||||
|
}
|
||||||
|
~CJSValProperty()
|
||||||
|
{
|
||||||
|
Uproot();
|
||||||
|
}
|
||||||
|
void Root()
|
||||||
|
{
|
||||||
|
if( JSVAL_IS_GCTHING( m_Data ) )
|
||||||
|
JS_AddRoot( g_ScriptingHost.GetContext(), (void*)&m_Data );
|
||||||
|
}
|
||||||
|
void Uproot()
|
||||||
|
{
|
||||||
|
if( JSVAL_IS_GCTHING( m_Data ) )
|
||||||
|
JS_RemoveRoot( g_ScriptingHost.GetContext(), (void*)&m_Data );
|
||||||
|
}
|
||||||
|
jsval Get( JSContext* cx, IJSObject* object )
|
||||||
|
{
|
||||||
|
return( m_Data );
|
||||||
|
}
|
||||||
|
void Set( JSContext* cx, IJSObject* owner, jsval value )
|
||||||
|
{
|
||||||
|
Uproot();
|
||||||
|
m_Data = value;
|
||||||
|
Root();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Wrapper around native functions that are attached to CJSObjects
|
// Wrapper around native functions that are attached to CJSObjects
|
||||||
|
|
||||||
@ -432,14 +174,17 @@ public:
|
|||||||
|
|
||||||
template<typename T, bool ReadOnly> class CJSObject : public IJSObject
|
template<typename T, bool ReadOnly> class CJSObject : public IJSObject
|
||||||
{
|
{
|
||||||
typedef STL_HASH_MAP<CStrW, CJSReflector*, CStrW_hash_compare> ReflectorTable;
|
// This object
|
||||||
|
|
||||||
JSObject* m_JS;
|
JSObject* m_JS;
|
||||||
|
|
||||||
ReflectorTable m_Reflectors;
|
protected:
|
||||||
|
// The properties defined by the engine
|
||||||
public:
|
static PropertyTable m_NativeProperties;
|
||||||
static JSClass JSI_class;
|
#ifdef ALLOW_NONSHARED_NATIVES
|
||||||
|
PropertyTable m_NonsharedProperties;
|
||||||
|
#endif
|
||||||
|
// Properties added by script
|
||||||
|
PropertyTable m_ScriptProperties;
|
||||||
|
|
||||||
// Whether native code is responsible for managing this object.
|
// Whether native code is responsible for managing this object.
|
||||||
// Script constructors should clear this *BEFORE* creating a JS
|
// Script constructors should clear this *BEFORE* creating a JS
|
||||||
@ -447,8 +192,45 @@ public:
|
|||||||
|
|
||||||
bool m_EngineOwned;
|
bool m_EngineOwned;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Property getters and setters
|
||||||
|
typedef jsval (T::*TGetFn)();
|
||||||
|
typedef void (T::*TSetFn)( jsval value );
|
||||||
|
|
||||||
|
static JSClass JSI_class;
|
||||||
|
|
||||||
|
static void ScriptingInit( const char* ClassName, JSNative Constructor = NULL, uintN ConstructorMinArgs = 0 )
|
||||||
|
{
|
||||||
|
JSFunctionSpec* JSI_methods = new JSFunctionSpec[ m_Methods.size() + 1 ];
|
||||||
|
unsigned int MethodID;
|
||||||
|
for( MethodID = 0; MethodID < m_Methods.size(); MethodID++ )
|
||||||
|
JSI_methods[MethodID] = m_Methods[MethodID];
|
||||||
|
|
||||||
|
JSI_methods[MethodID].name = 0;
|
||||||
|
|
||||||
|
JSI_class.name = ClassName;
|
||||||
|
g_ScriptingHost.DefineCustomObjectType( &JSI_class, Constructor, ConstructorMinArgs, JSI_props, JSI_methods, NULL, NULL );
|
||||||
|
|
||||||
|
delete[]( JSI_methods );
|
||||||
|
|
||||||
|
atexit( ScriptingShutdown );
|
||||||
|
}
|
||||||
|
static void ScriptingShutdown()
|
||||||
|
{
|
||||||
|
PropertyTable::iterator it;
|
||||||
|
for( it = m_NativeProperties.begin(); it != m_NativeProperties.end(); it++ )
|
||||||
|
delete( it->second );
|
||||||
|
}
|
||||||
|
|
||||||
// JS Property access
|
// JS Property access
|
||||||
bool GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp );
|
bool GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp )
|
||||||
|
{
|
||||||
|
IJSProperty* Property = HasProperty( PropertyName );
|
||||||
|
if( Property )
|
||||||
|
*vp = Property->Get( cx, this );
|
||||||
|
|
||||||
|
return( true );
|
||||||
|
}
|
||||||
void SetProperty( JSContext* cx, CStrW PropertyName, jsval* vp )
|
void SetProperty( JSContext* cx, CStrW PropertyName, jsval* vp )
|
||||||
{
|
{
|
||||||
if( !ReadOnly )
|
if( !ReadOnly )
|
||||||
@ -459,29 +241,6 @@ public:
|
|||||||
{
|
{
|
||||||
// Already exists
|
// Already exists
|
||||||
prop->Set( cx, this, *vp );
|
prop->Set( cx, this, *vp );
|
||||||
|
|
||||||
prop->m_Inherited = false;
|
|
||||||
|
|
||||||
// If it's a C++ property, reflect this change in objects that inherit this.
|
|
||||||
if( prop->m_AllowsInheritance && prop->m_Intrinsic )
|
|
||||||
{
|
|
||||||
InheritorsList UpdateSet( m_Inheritors );
|
|
||||||
|
|
||||||
while( !UpdateSet.empty() )
|
|
||||||
{
|
|
||||||
IJSObject* UpdateObj = UpdateSet.back();
|
|
||||||
UpdateSet.pop_back();
|
|
||||||
IJSProperty* UpdateProp = UpdateObj->HasProperty( PropertyName );
|
|
||||||
// Property must exist, also be a C++ property, and not have its value specified.
|
|
||||||
if( UpdateProp && UpdateProp->m_Intrinsic && UpdateProp->m_Inherited )
|
|
||||||
{
|
|
||||||
UpdateProp->Set( cx, this, *vp );
|
|
||||||
InheritorsList::iterator it2;
|
|
||||||
for( it2 = UpdateObj->m_Inheritors.begin(); it2 != UpdateObj->m_Inheritors.end(); it2++ )
|
|
||||||
UpdateSet.push_back( *it2 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -491,9 +250,110 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IJSProperty* HasProperty( CStrW PropertyName )
|
||||||
|
{
|
||||||
|
PropertyTable::iterator it;
|
||||||
|
|
||||||
|
// Engine-defined properties take precedence
|
||||||
|
it = m_NativeProperties.find( PropertyName );
|
||||||
|
if( it != m_NativeProperties.end() )
|
||||||
|
return( it->second );
|
||||||
|
// Next are the object-local engine-defined properties
|
||||||
|
// (if they're compiled in)
|
||||||
|
#ifdef ALLOW_NONSHARED_NATIVES
|
||||||
|
it = m_NonsharedProperties.find( PropertyName );
|
||||||
|
if( it != m_NonsharedProperties.end() )
|
||||||
|
return( it->second );
|
||||||
|
#endif
|
||||||
|
// Then check in script properties
|
||||||
|
it = m_ScriptProperties.find( PropertyName );
|
||||||
|
if( it != m_ScriptProperties.end() )
|
||||||
|
return( it->second );
|
||||||
|
|
||||||
|
// Otherwise not found
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddProperty( CStrW PropertyName, jsval Value )
|
||||||
|
{
|
||||||
|
assert( !HasProperty( PropertyName ) );
|
||||||
|
CJSValProperty* newProp = new CJSValProperty( Value );
|
||||||
|
m_ScriptProperties[PropertyName] = newProp;
|
||||||
|
}
|
||||||
|
void AddProperty( CStrW PropertyName, CStrW Value )
|
||||||
|
{
|
||||||
|
AddProperty( PropertyName, JSParseString( Value ) );
|
||||||
|
}
|
||||||
|
static void AddProperty( CStrW PropertyName, TGetFn Getter, TSetFn Setter = NULL )
|
||||||
|
{
|
||||||
|
m_NativeProperties[PropertyName] = new CJSFunctionProperty( (GetFn)Getter, (SetFn)Setter );
|
||||||
|
}
|
||||||
|
template<typename ReturnType, ReturnType (T::*NativeFunction)( JSContext* cx, uintN argc, jsval* argv )>
|
||||||
|
static void AddMethod( const char* Name, uintN MinArgs )
|
||||||
|
{
|
||||||
|
JSFunctionSpec FnInfo = { Name, CNativeFunction<T, ReadOnly, ReturnType, NativeFunction>::JSFunction, MinArgs, 0, 0 };
|
||||||
|
m_Methods.push_back( FnInfo );
|
||||||
|
}
|
||||||
|
template<typename PropType> static void AddProperty( CStrW PropertyName, PropType T::*Native, bool PropReadOnly = ReadOnly )
|
||||||
|
{
|
||||||
|
IJSProperty* prop;
|
||||||
|
if( PropReadOnly )
|
||||||
|
{
|
||||||
|
prop = new CJSProperty<PropType, true>( (PropType IJSObject::*)Native );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
prop = new CJSProperty<PropType, ReadOnly>( (PropType IJSObject::*)Native );
|
||||||
|
m_NativeProperties[PropertyName] = prop;
|
||||||
|
}
|
||||||
|
#ifdef ALLOW_NONSHARED_NATIVES
|
||||||
|
template<typename PropType> void AddLocalProperty( CStrW PropertyName, PropType* Native, bool PropReadOnly = ReadOnly )
|
||||||
|
{
|
||||||
|
IJSProperty* prop;
|
||||||
|
if( PropReadOnly )
|
||||||
|
{
|
||||||
|
prop = new CJSNonsharedProperty<PropType, true>( Native );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
prop = new CJSNonsharedProperty<PropType, ReadOnly>( Native );
|
||||||
|
m_NonsharedProperties[PropertyName] = prop;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Object operations
|
||||||
|
JSObject* GetScript()
|
||||||
|
{
|
||||||
|
if( !m_JS )
|
||||||
|
CreateScriptObject();
|
||||||
|
return( m_JS );
|
||||||
|
}
|
||||||
|
// Creating and releasing script objects is done automatically most of the time, but you
|
||||||
|
// can do it explicitly.
|
||||||
|
void CreateScriptObject()
|
||||||
|
{
|
||||||
|
if( !m_JS )
|
||||||
|
{
|
||||||
|
m_JS = JS_NewObject( g_ScriptingHost.GetContext(), &JSI_class, NULL, NULL );
|
||||||
|
if( m_EngineOwned )
|
||||||
|
JS_AddRoot( g_ScriptingHost.GetContext(), (void*)&m_JS );
|
||||||
|
|
||||||
|
JS_SetPrivate( g_ScriptingHost.GetContext(), m_JS, (T*)this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void ReleaseScriptObject()
|
||||||
|
{
|
||||||
|
if( m_JS )
|
||||||
|
{
|
||||||
|
JS_SetPrivate( g_ScriptingHost.GetContext(), m_JS, NULL );
|
||||||
|
if( m_EngineOwned )
|
||||||
|
JS_RemoveRoot( g_ScriptingHost.GetContext(), &m_JS );
|
||||||
|
m_JS = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Functions that must be provided to JavaScript
|
// Functions and data that must be provided to JavaScript
|
||||||
//
|
//
|
||||||
|
private:
|
||||||
static JSBool JSGetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
|
static JSBool JSGetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
|
||||||
{
|
{
|
||||||
T* Instance = ToNative<T>( cx, obj );
|
T* Instance = ToNative<T>( cx, obj );
|
||||||
@ -519,28 +379,6 @@ public:
|
|||||||
|
|
||||||
return( JS_TRUE );
|
return( JS_TRUE );
|
||||||
}
|
}
|
||||||
static void ScriptingInit( const char* ClassName, JSNative Constructor = NULL, uintN ConstructorMinArgs = 0 )
|
|
||||||
{
|
|
||||||
JSFunctionSpec* JSI_methods = new JSFunctionSpec[ m_Methods.size() + 1 ];
|
|
||||||
unsigned int MethodID;
|
|
||||||
for( MethodID = 0; MethodID < m_Methods.size(); MethodID++ )
|
|
||||||
JSI_methods[MethodID] = m_Methods[MethodID];
|
|
||||||
|
|
||||||
JSI_methods[MethodID].name = 0;
|
|
||||||
|
|
||||||
JSI_class.name = ClassName;
|
|
||||||
g_ScriptingHost.DefineCustomObjectType( &JSI_class, Constructor, ConstructorMinArgs, JSI_props, JSI_methods, NULL, NULL );
|
|
||||||
|
|
||||||
delete[]( JSI_methods );
|
|
||||||
|
|
||||||
atexit( ScriptingShutdown );
|
|
||||||
}
|
|
||||||
static void ScriptingShutdown()
|
|
||||||
{
|
|
||||||
PropertyTable::iterator it;
|
|
||||||
for( it = m_IntrinsicProperties.begin(); it != m_IntrinsicProperties.end(); it++ )
|
|
||||||
delete( it->second );
|
|
||||||
}
|
|
||||||
static void DefaultFinalize( JSContext *cx, JSObject *obj )
|
static void DefaultFinalize( JSContext *cx, JSObject *obj )
|
||||||
{
|
{
|
||||||
T* Instance = ToNative<T>( cx, obj );
|
T* Instance = ToNative<T>( cx, obj );
|
||||||
@ -551,52 +389,14 @@ public:
|
|||||||
JS_SetPrivate( cx, obj, NULL );
|
JS_SetPrivate( cx, obj, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
JSObject* GetScript()
|
|
||||||
{
|
|
||||||
if( !m_JS )
|
|
||||||
CreateScriptObject();
|
|
||||||
return( m_JS );
|
|
||||||
}
|
|
||||||
// Creating and releasing script objects is done automatically most of the time, but you
|
|
||||||
// can do it explicitly.
|
|
||||||
void CreateScriptObject()
|
|
||||||
{
|
|
||||||
if( !m_JS )
|
|
||||||
{
|
|
||||||
m_JS = JS_NewObject( g_ScriptingHost.GetContext(), &JSI_class, NULL, NULL );
|
|
||||||
if( m_EngineOwned )
|
|
||||||
{
|
|
||||||
#ifndef NDEBUG // Name the GC roots something more useful than 'ScriptableObject.h'
|
|
||||||
JS_AddNamedRoot( g_ScriptingHost.GetContext(), (void*)&m_JS, JSI_class.name );
|
|
||||||
#else
|
|
||||||
JS_AddRoot( g_ScriptingHost.GetContext(), (void*)&m_JS );
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
JS_SetPrivate( g_ScriptingHost.GetContext(), m_JS, (T*)this );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void ReleaseScriptObject()
|
|
||||||
{
|
|
||||||
if( m_JS )
|
|
||||||
{
|
|
||||||
JS_SetPrivate( g_ScriptingHost.GetContext(), m_JS, NULL );
|
|
||||||
if( m_EngineOwned )
|
|
||||||
JS_RemoveRoot( g_ScriptingHost.GetContext(), &m_JS );
|
|
||||||
m_JS = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
static JSPropertySpec JSI_props[];
|
static JSPropertySpec JSI_props[];
|
||||||
static std::vector<JSFunctionSpec> m_Methods;
|
static std::vector<JSFunctionSpec> m_Methods;
|
||||||
static PropertyTable m_IntrinsicProperties;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// Standard constructors/destructors
|
||||||
CJSObject()
|
CJSObject()
|
||||||
{
|
{
|
||||||
m_Parent = NULL;
|
|
||||||
m_JS = NULL;
|
m_JS = NULL;
|
||||||
m_EngineOwned = true;
|
m_EngineOwned = true;
|
||||||
}
|
}
|
||||||
@ -607,163 +407,15 @@ public:
|
|||||||
void Shutdown()
|
void Shutdown()
|
||||||
{
|
{
|
||||||
PropertyTable::iterator it;
|
PropertyTable::iterator it;
|
||||||
for( it = m_Properties.begin(); it != m_Properties.end(); it++ )
|
for( it = m_ScriptProperties.begin(); it != m_ScriptProperties.end(); it++ )
|
||||||
{
|
|
||||||
if( !it->second->m_Intrinsic )
|
|
||||||
{
|
|
||||||
CJSDynamicProperty* extProp = (CJSValProperty*)it->second;
|
|
||||||
if( extProp->m_JSAccessor )
|
|
||||||
{
|
|
||||||
CJSPropertyAccessor< CJSObject<T, ReadOnly> >* accessor = (CJSPropertyAccessor< CJSObject<T, ReadOnly> >*)JS_GetPrivate( g_ScriptingHost.GetContext(), extProp->m_JSAccessor );
|
|
||||||
assert( accessor );
|
|
||||||
delete( accessor );
|
|
||||||
JS_SetPrivate( g_ScriptingHost.GetContext(), extProp->m_JSAccessor, NULL );
|
|
||||||
JS_RemoveRoot( g_ScriptingHost.GetContext(), &( extProp->m_JSAccessor ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete( it->second );
|
delete( it->second );
|
||||||
}
|
m_ScriptProperties.clear();
|
||||||
|
|
||||||
|
|
||||||
ReflectorTable::iterator it_a;
|
|
||||||
for( it_a = m_Reflectors.begin(); it_a != m_Reflectors.end(); it_a++ )
|
|
||||||
{
|
|
||||||
CJSPropertyAccessor< CJSObject<T, ReadOnly> >* accessor = (CJSPropertyAccessor< CJSObject<T, ReadOnly> >*)JS_GetPrivate( g_ScriptingHost.GetContext(), it_a->second->m_JSAccessor );
|
|
||||||
assert( accessor );
|
|
||||||
delete( accessor );
|
|
||||||
JS_SetPrivate( g_ScriptingHost.GetContext(), it_a->second->m_JSAccessor, NULL );
|
|
||||||
JS_RemoveRoot( g_ScriptingHost.GetContext(), &( it_a->second->m_JSAccessor ) );
|
|
||||||
delete( it_a->second );
|
|
||||||
}
|
|
||||||
ReleaseScriptObject();
|
ReleaseScriptObject();
|
||||||
}
|
#ifdef ALLOW_NONSHARED_NATIVES
|
||||||
void SetBase( IJSObject* Parent )
|
for( it = m_NonsharedProperties.begin(); it != m_NonsharedProperties.end(); it++ )
|
||||||
{
|
|
||||||
if( m_Parent )
|
|
||||||
{
|
|
||||||
// Remove this from the list of our parent's inheritors
|
|
||||||
InheritorsList::iterator it;
|
|
||||||
for( it = m_Parent->m_Inheritors.begin(); it != m_Parent->m_Inheritors.end(); it++ )
|
|
||||||
if( (*it) == this )
|
|
||||||
{
|
|
||||||
m_Parent->m_Inheritors.erase( it );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_Parent = Parent;
|
|
||||||
if( m_Parent )
|
|
||||||
{
|
|
||||||
// Place this in the list of our parent's inheritors
|
|
||||||
m_Parent->m_Inheritors.push_back( this );
|
|
||||||
Rebuild();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Rebuild()
|
|
||||||
{
|
|
||||||
PropertyTable::iterator it;
|
|
||||||
// For each intrinsic property we have,
|
|
||||||
for( it = m_Properties.begin(); it != m_Properties.end(); it++ )
|
|
||||||
{
|
|
||||||
if( !it->second->m_Intrinsic || !it->second->m_Inherited )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Attempt to locate it in the parent
|
|
||||||
IJSProperty* cp = m_Parent->HasProperty( it->first );
|
|
||||||
|
|
||||||
// If it doesn't have it, we've inherited from an object of a different type
|
|
||||||
// This isn't allowed at the moment; but I don't have an totally convincing
|
|
||||||
// reason for forbidding it entirely. Mind, I can't think of any use for it,
|
|
||||||
// either.
|
|
||||||
// If it can be inherited, inherit it.
|
|
||||||
if( cp && cp->m_AllowsInheritance )
|
|
||||||
{
|
|
||||||
assert( cp->m_Intrinsic );
|
|
||||||
it->second->ImmediateCopy( this, m_Parent, cp );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Do the same for the shared properties table, too
|
|
||||||
for( it = m_IntrinsicProperties.begin(); it != m_IntrinsicProperties.end(); it++ )
|
|
||||||
{
|
|
||||||
if( !it->second->m_Inherited )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
IJSProperty* cp = m_Parent->HasProperty( it->first );
|
|
||||||
|
|
||||||
if( cp && cp->m_AllowsInheritance )
|
|
||||||
{
|
|
||||||
assert( cp->m_Intrinsic );
|
|
||||||
it->second->ImmediateCopy( this, m_Parent, cp );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now recurse.
|
|
||||||
InheritorsList::iterator c;
|
|
||||||
for( c = m_Inheritors.begin(); c != m_Inheritors.end(); c++ )
|
|
||||||
(*c)->Rebuild();
|
|
||||||
|
|
||||||
}
|
|
||||||
IJSProperty* HasProperty( CStrW PropertyName )
|
|
||||||
{
|
|
||||||
PropertyTable::iterator it;
|
|
||||||
it = T::m_IntrinsicProperties.find( PropertyName );
|
|
||||||
if( it != T::m_IntrinsicProperties.end() )
|
|
||||||
return( it->second );
|
|
||||||
|
|
||||||
it = m_Properties.find( PropertyName );
|
|
||||||
if( it != m_Properties.end() )
|
|
||||||
return( it->second );
|
|
||||||
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddProperty( CStrW PropertyName, jsval Value )
|
|
||||||
{
|
|
||||||
assert( !HasProperty( PropertyName ) );
|
|
||||||
CJSDynamicProperty* newProp = new CJSValProperty( Value, false );
|
|
||||||
m_Properties[PropertyName] = newProp;
|
|
||||||
|
|
||||||
ReflectorTable::iterator it;
|
|
||||||
it = m_Reflectors.find( PropertyName );
|
|
||||||
if( it != m_Reflectors.end() )
|
|
||||||
{
|
|
||||||
// We had an accessor pointing to this property before it was defined.
|
|
||||||
newProp->m_JSAccessor = it->second->m_JSAccessor;
|
|
||||||
JS_RemoveRoot( g_ScriptingHost.GetContext(), &( it->second->m_JSAccessor ) );
|
|
||||||
JS_AddRoot( g_ScriptingHost.GetContext(), &( newProp->m_JSAccessor ) );
|
|
||||||
delete( it->second );
|
delete( it->second );
|
||||||
m_Reflectors.erase( it );
|
m_NonsharedProperties.clear();
|
||||||
}
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
void AddProperty( CStrW PropertyName, CStrW Value )
|
|
||||||
{
|
|
||||||
AddProperty( PropertyName, JSParseString( Value ) );
|
|
||||||
}
|
|
||||||
static void AddClassProperty( CStrW PropertyName, GetFn Getter, SetFn Setter = NULL )
|
|
||||||
{
|
|
||||||
T::m_IntrinsicProperties[PropertyName] = new CJSFunctionProperty( Getter, Setter );
|
|
||||||
}
|
|
||||||
template<typename ReturnType, ReturnType (T::*NativeFunction)( JSContext* cx, uintN argc, jsval* argv )>
|
|
||||||
static void AddMethod( const char* Name, uintN MinArgs )
|
|
||||||
{
|
|
||||||
JSFunctionSpec FnInfo = { Name, CNativeFunction<T, ReadOnly, ReturnType, NativeFunction>::JSFunction, MinArgs, 0, 0 };
|
|
||||||
T::m_Methods.push_back( FnInfo );
|
|
||||||
}
|
|
||||||
template<typename PropType> static void AddClassProperty( CStrW PropertyName, PropType T::*Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
|
|
||||||
{
|
|
||||||
T::m_IntrinsicProperties[PropertyName] = new CJSSharedProperty<PropType, ReadOnly>( (PropType IJSObject::*)Native, PropAllowInheritance, Update, Refresh );
|
|
||||||
}
|
|
||||||
template<typename PropType> static void AddReadOnlyClassProperty( CStrW PropertyName, PropType T::*Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
|
|
||||||
{
|
|
||||||
T::m_IntrinsicProperties[PropertyName] = new CJSSharedProperty<PropType, true>( (PropType IJSObject::*)Native, PropAllowInheritance, Update, Refresh );
|
|
||||||
}
|
|
||||||
template<typename PropType> void AddProperty( CStrW PropertyName, PropType* Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
|
|
||||||
{
|
|
||||||
m_Properties[PropertyName] = new CJSProperty<PropType, ReadOnly>( Native, PropAllowInheritance, Update, Refresh );
|
|
||||||
}
|
|
||||||
template<typename PropType> void AddReadOnlyProperty( CStrW PropertyName, PropType* Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
|
|
||||||
{
|
|
||||||
m_Properties[PropertyName] = new CJSProperty<PropType, true>( Native, PropAllowInheritance, Update, Refresh );
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -781,72 +433,8 @@ template<typename T, bool ReadOnly> JSPropertySpec CJSObject<T, ReadOnly>::JSI_p
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, bool ReadOnly> std::vector<JSFunctionSpec> CJSObject<T, ReadOnly>::m_Methods;
|
template<typename T, bool ReadOnly> std::vector<JSFunctionSpec> CJSObject<T, ReadOnly>::m_Methods;
|
||||||
template<typename T, bool ReadOnly> typename CJSObject<typename T, ReadOnly>::PropertyTable CJSObject<T, ReadOnly>::m_IntrinsicProperties;
|
|
||||||
|
|
||||||
template<typename T, bool ReadOnly> bool CJSObject<T, ReadOnly>::GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp )
|
template<typename T, bool ReadOnly> typename CJSObject<typename T, ReadOnly>::PropertyTable CJSObject<T, ReadOnly>::m_NativeProperties;
|
||||||
{
|
|
||||||
IJSProperty* Property = HasProperty( PropertyName );
|
|
||||||
if( Property && Property->m_Intrinsic )
|
|
||||||
{
|
|
||||||
*vp = Property->Get( cx, this );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CJSDynamicProperty* extProp;
|
|
||||||
|
|
||||||
if( Property )
|
|
||||||
{
|
|
||||||
extProp = (CJSValProperty*)Property;
|
|
||||||
|
|
||||||
if( !extProp->m_JSAccessor )
|
|
||||||
{
|
|
||||||
extProp->m_JSAccessor = CJSPropertyAccessor< CJSObject<T, ReadOnly> >::CreateAccessor( cx, this, PropertyName );
|
|
||||||
JS_AddNamedRoot( cx, &extProp->m_JSAccessor, "property accessor" );
|
|
||||||
}
|
|
||||||
|
|
||||||
*vp = OBJECT_TO_JSVAL( extProp->m_JSAccessor );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Check to see if it exists on a parent
|
|
||||||
IJSObject* check = m_Parent;
|
|
||||||
while( check )
|
|
||||||
{
|
|
||||||
if( check->HasProperty( PropertyName ) ) break;
|
|
||||||
check = check->m_Parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !check )
|
|
||||||
return( false );
|
|
||||||
|
|
||||||
// FIXME: Fiddle a way so this /doesn't/ require multiple kilobytes
|
|
||||||
// of memory. Can't think of any better way to do it yet. Problem is
|
|
||||||
// that script may access a property that isn't defined locally, but
|
|
||||||
// is defined by an ancestor. We can't return an accessor to the
|
|
||||||
// ancestor's property, because then if it's altered it affects that
|
|
||||||
// object, not this. At the moment, creating a 'reflector' property
|
|
||||||
// accessor that references /this/ object to be returned to script.
|
|
||||||
|
|
||||||
// (N.B. Can't just put JSObjects* in the table -> table entries can
|
|
||||||
// move -> root no longer refers to the JSObject.)
|
|
||||||
|
|
||||||
ReflectorTable::iterator it;
|
|
||||||
it = m_Reflectors.find( PropertyName );
|
|
||||||
|
|
||||||
if( it == m_Reflectors.end() )
|
|
||||||
{
|
|
||||||
CJSReflector* reflector = new CJSReflector();
|
|
||||||
reflector->m_JSAccessor = CJSPropertyAccessor< CJSObject<T, ReadOnly> >::CreateAccessor( cx, this, PropertyName );
|
|
||||||
JS_AddRoot( cx, &reflector->m_JSAccessor );
|
|
||||||
m_Reflectors.insert( std::pair<CStrW, CJSReflector*>( PropertyName, reflector ) );
|
|
||||||
*vp = OBJECT_TO_JSVAL( reflector->m_JSAccessor );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*vp = OBJECT_TO_JSVAL( it->second->m_JSAccessor );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return( true );
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -114,8 +114,6 @@ struct CSynchedJSObjectBase
|
|||||||
m_Owner(owner),
|
m_Owner(owner),
|
||||||
m_Update(update)
|
m_Update(update)
|
||||||
{
|
{
|
||||||
m_AllowsInheritance = false;
|
|
||||||
m_Intrinsic = true;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,7 +138,7 @@ protected:
|
|||||||
template <typename T> void AddSynchedProperty(CStrW name, T *native, UpdateFn update=NULL)
|
template <typename T> void AddSynchedProperty(CStrW name, T *native, UpdateFn update=NULL)
|
||||||
{
|
{
|
||||||
ISynchedJSProperty *prop=new CSynchedJSProperty<T>(name, native, this, update);
|
ISynchedJSProperty *prop=new CSynchedJSProperty<T>(name, native, this, update);
|
||||||
m_Properties[name]=prop;
|
m_NonsharedProperties[name]=prop;
|
||||||
m_SynchedProperties[name]=prop;
|
m_SynchedProperties[name]=prop;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -24,7 +24,10 @@ CBaseEntity::CBaseEntity()
|
|||||||
AddProperty( L"traits.corpse", &m_corpse );
|
AddProperty( L"traits.corpse", &m_corpse );
|
||||||
|
|
||||||
for( int t = 0; t < EVENT_LAST; t++ )
|
for( int t = 0; t < EVENT_LAST; t++ )
|
||||||
AddProperty( EventNames[t], &m_EventHandlers[t] );
|
{
|
||||||
|
AddProperty( EventNames[t], &m_EventHandlers[t], false );
|
||||||
|
AddHandler( t, &m_EventHandlers[t] );
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize, make life a little easier on the scriptors
|
// Initialize, make life a little easier on the scriptors
|
||||||
m_speed = m_turningRadius = m_meleeRange = m_meleeRangeMin = 0.0f;
|
m_speed = m_turningRadius = m_meleeRange = m_meleeRangeMin = 0.0f;
|
||||||
@ -62,6 +65,7 @@ void CBaseEntity::loadBase()
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetBase( m_base );
|
SetBase( m_base );
|
||||||
|
SetNextObject( m_base );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBaseEntity::loadXML( CStr filename )
|
bool CBaseEntity::loadXML( CStr filename )
|
||||||
@ -204,7 +208,7 @@ void CBaseEntity::XMLLoadProperty( const CXeromyces& XeroFile, const XMBElement&
|
|||||||
// Add a property, put the node text into it.
|
// Add a property, put the node text into it.
|
||||||
CStrW PropertyName = BasePropertyName + CStr8( XeroFile.getElementString( Source.getNodeName() ) );
|
CStrW PropertyName = BasePropertyName + CStr8( XeroFile.getElementString( Source.getNodeName() ) );
|
||||||
|
|
||||||
IJSProperty* Existing = HasProperty( PropertyName );
|
IJSComplexProperty* Existing = HasProperty( PropertyName );
|
||||||
if( Existing )
|
if( Existing )
|
||||||
{
|
{
|
||||||
if( !Existing->m_Intrinsic )
|
if( !Existing->m_Intrinsic )
|
||||||
@ -264,11 +268,16 @@ void CBaseEntity::ScriptingInit()
|
|||||||
{
|
{
|
||||||
AddMethod<jsval, &CBaseEntity::ToString>( "toString", 0 );
|
AddMethod<jsval, &CBaseEntity::ToString>( "toString", 0 );
|
||||||
|
|
||||||
CJSObject<CBaseEntity>::ScriptingInit( "EntityTemplate" );
|
CJSComplex<CBaseEntity>::ScriptingInit( "EntityTemplate" );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Script-bound functions
|
// Script-bound functions
|
||||||
|
|
||||||
|
JSObject* CBaseEntity::GetScriptExecContext( IEventTarget* target )
|
||||||
|
{
|
||||||
|
return( target->GetScriptExecContext( target ) );
|
||||||
|
}
|
||||||
|
|
||||||
jsval CBaseEntity::ToString( JSContext* cx, uintN argc, jsval* argv )
|
jsval CBaseEntity::ToString( JSContext* cx, uintN argc, jsval* argv )
|
||||||
{
|
{
|
||||||
wchar_t buffer[256];
|
wchar_t buffer[256];
|
||||||
|
@ -21,13 +21,13 @@
|
|||||||
#include "CStr.h"
|
#include "CStr.h"
|
||||||
#include "ObjectEntry.h"
|
#include "ObjectEntry.h"
|
||||||
|
|
||||||
#include "scripting/ScriptableObject.h"
|
#include "scripting/ScriptableComplex.h"
|
||||||
#include "BoundingObjects.h"
|
#include "BoundingObjects.h"
|
||||||
#include "EventHandlers.h"
|
#include "EventHandlers.h"
|
||||||
#include "ScriptObject.h"
|
#include "ScriptObject.h"
|
||||||
#include "Xeromyces.h"
|
#include "Xeromyces.h"
|
||||||
|
|
||||||
class CBaseEntity : public CJSObject<CBaseEntity>
|
class CBaseEntity : public CJSComplex<CBaseEntity>, public IEventTarget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CBaseEntity();
|
CBaseEntity();
|
||||||
@ -65,6 +65,9 @@ public:
|
|||||||
|
|
||||||
// Script-bound functions
|
// Script-bound functions
|
||||||
|
|
||||||
|
// Get script execution contexts - always run in the context of the entity that fired it.
|
||||||
|
JSObject* GetScriptExecContext( IEventTarget* target );
|
||||||
|
|
||||||
jsval ToString( JSContext* cx, uintN argc, jsval* argv );
|
jsval ToString( JSContext* cx, uintN argc, jsval* argv );
|
||||||
|
|
||||||
static void ScriptingInit();
|
static void ScriptingInit();
|
||||||
|
@ -41,7 +41,10 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation )
|
|||||||
AddProperty( L"player", &m_player );
|
AddProperty( L"player", &m_player );
|
||||||
|
|
||||||
for( int t = 0; t < EVENT_LAST; t++ )
|
for( int t = 0; t < EVENT_LAST; t++ )
|
||||||
AddProperty( EventNames[t], &m_EventHandlers[t] );
|
{
|
||||||
|
AddProperty( EventNames[t], &m_EventHandlers[t], false );
|
||||||
|
AddHandler( t, &m_EventHandlers[t] );
|
||||||
|
}
|
||||||
|
|
||||||
// Set our parent unit and build us an actor.
|
// Set our parent unit and build us an actor.
|
||||||
m_actor = NULL;
|
m_actor = NULL;
|
||||||
@ -102,6 +105,7 @@ void CEntity::loadBase()
|
|||||||
// Set up our instance data
|
// Set up our instance data
|
||||||
|
|
||||||
SetBase( m_base );
|
SetBase( m_base );
|
||||||
|
SetNextObject( m_base );
|
||||||
|
|
||||||
if( m_base->m_bound_type == CBoundingObject::BOUND_CIRCLE )
|
if( m_base->m_bound_type == CBoundingObject::BOUND_CIRCLE )
|
||||||
{
|
{
|
||||||
@ -326,16 +330,6 @@ void CEntity::dispatch( const CMessage* msg )
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool CEntity::DispatchEvent( CScriptEvent* evt )
|
|
||||||
{
|
|
||||||
const char* data = g_Profiler.InternString( "script: " + (CStr8)evt->m_Type );
|
|
||||||
|
|
||||||
g_Profiler.StartScript( data );
|
|
||||||
bool rval = m_EventHandlers[evt->m_TypeCode].DispatchEvent( GetScript(), evt );
|
|
||||||
g_Profiler.Stop();
|
|
||||||
return( rval );
|
|
||||||
}
|
|
||||||
|
|
||||||
void CEntity::clearOrders()
|
void CEntity::clearOrders()
|
||||||
{
|
{
|
||||||
m_orderQueue.clear();
|
m_orderQueue.clear();
|
||||||
@ -346,13 +340,6 @@ void CEntity::pushOrder( CEntityOrder& order )
|
|||||||
m_orderQueue.push_back( order );
|
m_orderQueue.push_back( order );
|
||||||
}
|
}
|
||||||
|
|
||||||
int CEntity::defaultOrder( CEntity* orderTarget )
|
|
||||||
{
|
|
||||||
CEventTargetChanged evt( orderTarget );
|
|
||||||
DispatchEvent( &evt );
|
|
||||||
return( evt.m_defaultAction );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CEntity::acceptsOrder( int orderType, CEntity* orderTarget )
|
bool CEntity::acceptsOrder( int orderType, CEntity* orderTarget )
|
||||||
{
|
{
|
||||||
CEventPrepareOrder evt( orderTarget, orderType );
|
CEventPrepareOrder evt( orderTarget, orderType );
|
||||||
@ -624,7 +611,7 @@ void CEntity::ScriptingInit()
|
|||||||
|
|
||||||
AddClassProperty( L"template", (CBaseEntity* CEntity::*)&CEntity::m_base, false, (NotifyFn)&CEntity::loadBase );
|
AddClassProperty( L"template", (CBaseEntity* CEntity::*)&CEntity::m_base, false, (NotifyFn)&CEntity::loadBase );
|
||||||
|
|
||||||
CJSObject<CEntity>::ScriptingInit( "Entity", Construct, 2 );
|
CJSComplex<CEntity>::ScriptingInit( "Entity", Construct, 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Script constructor
|
// Script constructor
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
#define ENTITY_INCLUDED
|
#define ENTITY_INCLUDED
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include "scripting/ScriptableObject.h"
|
#include "scripting/ScriptableComplex.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
|
|
||||||
#include "Vector2D.h"
|
#include "Vector2D.h"
|
||||||
@ -52,7 +52,7 @@ class CUnit;
|
|||||||
|
|
||||||
// TODO MT: Put this is /some/ sort of order...
|
// TODO MT: Put this is /some/ sort of order...
|
||||||
|
|
||||||
class CEntity : public CJSObject<CEntity>
|
class CEntity : public CJSComplex<CEntity>, public IEventTarget
|
||||||
{
|
{
|
||||||
friend class CEntityManager;
|
friend class CEntityManager;
|
||||||
private:
|
private:
|
||||||
@ -96,22 +96,15 @@ public:
|
|||||||
|
|
||||||
//-- Scripts
|
//-- Scripts
|
||||||
|
|
||||||
|
// Get script execution contexts - always run in the context of the entity that fired it.
|
||||||
|
JSObject* GetScriptExecContext( IEventTarget* target ) { return( ((CEntity*)target)->GetScript() ); }
|
||||||
|
|
||||||
// EventListener adaptation?
|
// EventListener adaptation?
|
||||||
//typedef std::vector<CScriptObject> ExtendedHandlerList;
|
//typedef std::vector<CScriptObject> ExtendedHandlerList;
|
||||||
//typedef STL_HASH_MAP<CStrW, HandlerList, CStrW_hash_compare> ExtendedHandlerTable;
|
//typedef STL_HASH_MAP<CStrW, HandlerList, CStrW_hash_compare> ExtendedHandlerTable;
|
||||||
|
|
||||||
CScriptObject m_EventHandlers[EVENT_LAST];
|
CScriptObject m_EventHandlers[EVENT_LAST];
|
||||||
|
|
||||||
// EventListener adaptation?
|
|
||||||
/*
|
|
||||||
void AddListener( const CStrW& EventType, CScriptObject* Handler )
|
|
||||||
{
|
|
||||||
m_EventHandlers[EventType].push_back( Handler );
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool DispatchEvent( CScriptEvent* evt );
|
|
||||||
|
|
||||||
CUnit* m_actor;
|
CUnit* m_actor;
|
||||||
|
|
||||||
// State transition in the FSM (animations should be reset)
|
// State transition in the FSM (animations should be reset)
|
||||||
@ -185,8 +178,6 @@ public:
|
|||||||
void checkGroup(); // Groups
|
void checkGroup(); // Groups
|
||||||
void checkExtant(); // Existence
|
void checkExtant(); // Existence
|
||||||
|
|
||||||
// Returns the default action of the entity upon the target (or -1 if none apply)
|
|
||||||
int CEntity::defaultOrder( CEntity* orderTarget );
|
|
||||||
// Returns whether the entity is capable of performing the given orderType on the target.
|
// Returns whether the entity is capable of performing the given orderType on the target.
|
||||||
bool acceptsOrder( int orderType, CEntity* orderTarget );
|
bool acceptsOrder( int orderType, CEntity* orderTarget );
|
||||||
|
|
||||||
|
@ -299,6 +299,8 @@ bool CEntity::processContactAction( CEntityOrder* current, size_t timestep_milli
|
|||||||
}
|
}
|
||||||
bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t timestep_millis, CSkeletonAnim* animation, CScriptEvent* contactEvent, float range, float minRange = 0.0f )
|
bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t timestep_millis, CSkeletonAnim* animation, CScriptEvent* contactEvent, float range, float minRange = 0.0f )
|
||||||
{
|
{
|
||||||
|
static size_t cyclepos = 0;
|
||||||
|
|
||||||
// Target's dead (or exhausted)? Then our work here is done.
|
// Target's dead (or exhausted)? Then our work here is done.
|
||||||
if( !current->m_data[0].entity || !current->m_data[0].entity->m_extant )
|
if( !current->m_data[0].entity || !current->m_data[0].entity->m_extant )
|
||||||
{
|
{
|
||||||
@ -308,9 +310,27 @@ bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t times
|
|||||||
|
|
||||||
if( m_actor )
|
if( m_actor )
|
||||||
{
|
{
|
||||||
// Still playing attack animation? Suspend processing.
|
if( animation && ( m_actor->GetModel()->GetAnimation() == animation ) )
|
||||||
if( m_actor->GetModel()->GetAnimation() == animation )
|
{
|
||||||
|
size_t cyclenext = cyclepos + timestep_millis;
|
||||||
|
if( ( cyclepos <= animation->m_ActionPos ) &&
|
||||||
|
( cyclenext > animation->m_ActionPos ) )
|
||||||
|
{
|
||||||
|
// Actually execute the action script in the sim frame
|
||||||
|
// that contains the animation's 'action point' (as
|
||||||
|
// specified by the artist that created it)
|
||||||
|
if( !DispatchEvent( contactEvent ) )
|
||||||
|
{
|
||||||
|
// The script is cancelling the attack/gather action.
|
||||||
|
|
||||||
|
// Cancel the animation (will probably cause a graphical
|
||||||
|
// glitch, but can't be helped)
|
||||||
|
m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_WalkAnim );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cyclepos = cyclenext;
|
||||||
return( false );
|
return( false );
|
||||||
|
}
|
||||||
|
|
||||||
// Just transitioned? No animation? (=> melee just finished) Play walk.
|
// Just transitioned? No animation? (=> melee just finished) Play walk.
|
||||||
if( m_transition || !m_actor->GetModel()->GetAnimation() )
|
if( m_transition || !m_actor->GetModel()->GetAnimation() )
|
||||||
@ -396,8 +416,12 @@ bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t times
|
|||||||
m_ahead = delta.normalize();
|
m_ahead = delta.normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( DispatchEvent( contactEvent ) && m_actor )
|
// Start the animation. Actual damage/gather will be done in a
|
||||||
m_actor->GetModel()->SetAnimation( animation, true );
|
// few hundred msec, at the 'action point' of the animation we're
|
||||||
|
// now setting.
|
||||||
|
|
||||||
|
m_actor->GetModel()->SetAnimation( animation, true );
|
||||||
|
cyclepos = 0;
|
||||||
|
|
||||||
return( false );
|
return( false );
|
||||||
}
|
}
|
||||||
|
@ -35,10 +35,10 @@ public:
|
|||||||
}
|
}
|
||||||
static void ScriptingInit()
|
static void ScriptingInit()
|
||||||
{
|
{
|
||||||
AddClassProperty<float>( L"crush", &CDamageType::m_Crush );
|
AddProperty<float>( L"crush", &CDamageType::m_Crush );
|
||||||
AddClassProperty<float>( L"hack", &CDamageType::m_Hack );
|
AddProperty<float>( L"hack", &CDamageType::m_Hack );
|
||||||
AddClassProperty<float>( L"pierce", &CDamageType::m_Pierce );
|
AddProperty<float>( L"pierce", &CDamageType::m_Pierce );
|
||||||
AddClassProperty<float>( L"typeless", &CDamageType::m_Typeless );
|
AddProperty<float>( L"typeless", &CDamageType::m_Typeless );
|
||||||
CJSObject<CDamageType>::ScriptingInit( "DamageType", Construct, 3 );
|
CJSObject<CDamageType>::ScriptingInit( "DamageType", Construct, 3 );
|
||||||
}
|
}
|
||||||
static JSBool Construct( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval )
|
static JSBool Construct( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval )
|
||||||
|
@ -2,50 +2,52 @@
|
|||||||
#include "EventHandlers.h"
|
#include "EventHandlers.h"
|
||||||
#include "Entity.h"
|
#include "Entity.h"
|
||||||
|
|
||||||
CEventAttack::CEventAttack( CEntity* target ) : CScriptEvent( L"attack", true, EVENT_ATTACK )
|
CEventAttack::CEventAttack( CEntity* target ) : CScriptEvent( L"attack", EVENT_ATTACK, true )
|
||||||
{
|
{
|
||||||
m_target = target;
|
m_target = target;
|
||||||
AddProperty( L"target", &m_target );
|
AddLocalProperty( L"target", &m_target );
|
||||||
}
|
}
|
||||||
|
|
||||||
CEventGather::CEventGather( CEntity* target ) : CScriptEvent( L"gather", true, EVENT_GATHER )
|
CEventGather::CEventGather( CEntity* target ) : CScriptEvent( L"gather", EVENT_GATHER, true )
|
||||||
{
|
{
|
||||||
m_target = target;
|
m_target = target;
|
||||||
AddProperty( L"target", &m_target );
|
AddLocalProperty( L"target", &m_target );
|
||||||
}
|
}
|
||||||
|
|
||||||
CEventDamage::CEventDamage( CEntity* inflictor, CDamageType* damage ) : CScriptEvent( L"takesDamage", true, EVENT_DAMAGE )
|
CEventDamage::CEventDamage( CEntity* inflictor, CDamageType* damage ) : CScriptEvent( L"takesDamage", EVENT_DAMAGE, true )
|
||||||
{
|
{
|
||||||
m_inflictor = inflictor;
|
m_inflictor = inflictor;
|
||||||
m_damage = damage;
|
m_damage = damage;
|
||||||
AddReadOnlyProperty( L"inflictor", &m_inflictor );
|
AddLocalProperty( L"inflictor", &m_inflictor, true );
|
||||||
AddProperty( L"damage", &m_damage );
|
AddLocalProperty( L"damage", &m_damage );
|
||||||
}
|
}
|
||||||
|
|
||||||
CEventTargetChanged::CEventTargetChanged( CEntity* target ) : CScriptEvent( L"targetChanged", false, EVENT_TARGET_CHANGED )
|
CEventTargetChanged::CEventTargetChanged( CEntity* target ) : CScriptEvent( L"targetChanged", EVENT_TARGET_CHANGED, false )
|
||||||
{
|
{
|
||||||
m_target = target;
|
m_target = target;
|
||||||
m_defaultAction = -1;
|
m_defaultAction = -1;
|
||||||
AddReadOnlyProperty( L"target", &m_target );
|
m_defaultCursor = L"arrow-default";
|
||||||
AddProperty( L"defaultAction", &m_defaultAction );
|
AddLocalProperty( L"target", &m_target, true );
|
||||||
|
AddLocalProperty( L"defaultAction", &m_defaultAction );
|
||||||
|
AddLocalProperty( L"defaultCursor", &m_defaultCursor );
|
||||||
}
|
}
|
||||||
|
|
||||||
CEventPrepareOrder::CEventPrepareOrder( CEntity* target, int orderType ) : CScriptEvent( L"prepareOrder", true, EVENT_PREPARE_ORDER )
|
CEventPrepareOrder::CEventPrepareOrder( CEntity* target, int orderType ) : CScriptEvent( L"prepareOrder", EVENT_PREPARE_ORDER, true )
|
||||||
{
|
{
|
||||||
m_target = target;
|
m_target = target;
|
||||||
m_orderType = orderType;
|
m_orderType = orderType;
|
||||||
AddReadOnlyProperty( L"target", &m_target );
|
AddLocalProperty( L"target", &m_target, true );
|
||||||
AddReadOnlyProperty( L"orderType", &m_orderType );
|
AddLocalProperty( L"orderType", &m_orderType, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
CEventOrderTransition::CEventOrderTransition( int orderPrevious, int orderCurrent, CEntity*& target, CVector3D& worldPosition ) : CScriptEvent( L"orderTransition", true, EVENT_ORDER_TRANSITION )
|
CEventOrderTransition::CEventOrderTransition( int orderPrevious, int orderCurrent, CEntity*& target, CVector3D& worldPosition ) : CScriptEvent( L"orderTransition", EVENT_ORDER_TRANSITION, true )
|
||||||
{
|
{
|
||||||
m_orderPrevious = orderPrevious;
|
m_orderPrevious = orderPrevious;
|
||||||
m_orderCurrent = orderCurrent;
|
m_orderCurrent = orderCurrent;
|
||||||
m_target = ⌖
|
m_target = ⌖
|
||||||
m_worldPosition = &worldPosition;
|
m_worldPosition = &worldPosition;
|
||||||
AddReadOnlyProperty( L"orderPrevious", &m_orderPrevious );
|
AddLocalProperty( L"orderPrevious", &m_orderPrevious, true );
|
||||||
AddProperty( L"orderCurrent", &m_orderCurrent );
|
AddLocalProperty( L"orderCurrent", &m_orderCurrent );
|
||||||
AddProperty( L"target", m_target );
|
AddLocalProperty( L"target", m_target );
|
||||||
AddProperty( L"position", m_worldPosition );
|
AddLocalProperty( L"position", m_worldPosition );
|
||||||
}
|
}
|
||||||
|
@ -10,41 +10,16 @@
|
|||||||
|
|
||||||
class CDamageType;
|
class CDamageType;
|
||||||
|
|
||||||
enum EEventType
|
|
||||||
{
|
|
||||||
EVENT_INITIALIZE,
|
|
||||||
EVENT_TICK,
|
|
||||||
EVENT_ATTACK,
|
|
||||||
EVENT_GATHER,
|
|
||||||
EVENT_DAMAGE,
|
|
||||||
EVENT_TARGET_CHANGED,
|
|
||||||
EVENT_PREPARE_ORDER,
|
|
||||||
EVENT_ORDER_TRANSITION,
|
|
||||||
EVENT_LAST,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const wchar_t* EventNames[] =
|
|
||||||
{
|
|
||||||
/* EVENT_INITIALIZE */ L"onInitialize",
|
|
||||||
/* EVENT_TICK */ L"onTick",
|
|
||||||
/* EVENT_ATTACK */ L"onAttack", /* This unit is the one doing the attacking... */
|
|
||||||
/* EVENT_GATHER */ L"onGather", /* This unit is the one doing the gathering... */
|
|
||||||
/* EVENT_DAMAGE */ L"onTakesDamage",
|
|
||||||
/* EVENT_TARGET_CHANGED */ L"onTargetChanged", /* If this unit is selected and the mouseover object changes */
|
|
||||||
/* EVENT_PREPARE_ORDER */ L"onPrepareOrder", /* To check if a unit can execute a given order */
|
|
||||||
/* EVENT_ORDER_TRANSITION */ L"onOrderTransition" /* When we change orders (sometimes...) */
|
|
||||||
};
|
|
||||||
|
|
||||||
class CEventInitialize : public CScriptEvent
|
class CEventInitialize : public CScriptEvent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CEventInitialize() : CScriptEvent( L"initialize", false, EVENT_INITIALIZE ) {}
|
CEventInitialize() : CScriptEvent( L"initialize", EVENT_INITIALIZE, false ) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CEventTick : public CScriptEvent
|
class CEventTick : public CScriptEvent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CEventTick() : CScriptEvent( L"tick", false, EVENT_TICK ) {}
|
CEventTick() : CScriptEvent( L"tick", EVENT_TICK, false ) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CEventAttack : public CScriptEvent
|
class CEventAttack : public CScriptEvent
|
||||||
@ -74,6 +49,7 @@ class CEventTargetChanged : public CScriptEvent
|
|||||||
CEntity* m_target;
|
CEntity* m_target;
|
||||||
public:
|
public:
|
||||||
int m_defaultAction;
|
int m_defaultAction;
|
||||||
|
CStrW m_defaultCursor;
|
||||||
CEventTargetChanged( CEntity* target );
|
CEventTargetChanged( CEntity* target );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -121,9 +121,9 @@ CJSProgressTimer::CJSProgressTimer( double Max, double Increment, JSFunction* Ca
|
|||||||
|
|
||||||
void CJSProgressTimer::ScriptingInit()
|
void CJSProgressTimer::ScriptingInit()
|
||||||
{
|
{
|
||||||
AddClassProperty( L"max", &CJSProgressTimer::m_Max );
|
AddProperty( L"max", &CJSProgressTimer::m_Max );
|
||||||
AddClassProperty( L"current", &CJSProgressTimer::m_Current );
|
AddProperty( L"current", &CJSProgressTimer::m_Current );
|
||||||
AddClassProperty( L"increment", &CJSProgressTimer::m_Increment );
|
AddProperty( L"increment", &CJSProgressTimer::m_Increment );
|
||||||
|
|
||||||
CJSObject<CJSProgressTimer>::ScriptingInit( "ProgressTimer", Construct, 2 );
|
CJSObject<CJSProgressTimer>::ScriptingInit( "ProgressTimer", Construct, 2 );
|
||||||
}
|
}
|
||||||
|
@ -76,15 +76,15 @@ JSObject* CScriptObject::GetFunctionObject()
|
|||||||
// Executes a script attached to a JS object.
|
// Executes a script attached to a JS object.
|
||||||
// Returns false if the script isn't defined, if the script can't be executed,
|
// Returns false if the script isn't defined, if the script can't be executed,
|
||||||
// otherwise true. Script return value is in rval.
|
// otherwise true. Script return value is in rval.
|
||||||
bool CScriptObject::Run( JSObject* Context, jsval* rval )
|
bool CScriptObject::Run( JSObject* Context, jsval* rval, uintN argc, jsval* argv )
|
||||||
{
|
{
|
||||||
if( !Function )
|
if( !Function )
|
||||||
return( false );
|
return( false );
|
||||||
return( JS_TRUE == JS_CallFunction( g_ScriptingHost.GetContext(), Context, Function, 0, NULL, rval ) );
|
return( JS_TRUE == JS_CallFunction( g_ScriptingHost.GetContext(), Context, Function, argc, argv, rval ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// This variant casts script return value to a boolean, and passes it back.
|
// This variant casts script return value to a boolean, and passes it back.
|
||||||
bool CScriptObject::Run( JSObject* Context )
|
bool CScriptObject::Run( JSObject* Context, uintN argc, jsval* argv )
|
||||||
{
|
{
|
||||||
jsval Temp;
|
jsval Temp;
|
||||||
if( !Run( Context, &Temp ) )
|
if( !Run( Context, &Temp ) )
|
||||||
@ -95,11 +95,13 @@ bool CScriptObject::Run( JSObject* Context )
|
|||||||
// Treat this as an event handler and dispatch an event to it. Return !evt->m_cancelled, as a convenience.
|
// Treat this as an event handler and dispatch an event to it. Return !evt->m_cancelled, as a convenience.
|
||||||
bool CScriptObject::DispatchEvent( JSObject* Context, CScriptEvent* evt )
|
bool CScriptObject::DispatchEvent( JSObject* Context, CScriptEvent* evt )
|
||||||
{
|
{
|
||||||
jsval Temp;
|
|
||||||
jsval EventObject = OBJECT_TO_JSVAL( evt->GetScript() );
|
|
||||||
if( Function )
|
if( Function )
|
||||||
|
{
|
||||||
|
jsval Temp;
|
||||||
|
jsval EventObject = OBJECT_TO_JSVAL( evt->GetScript() );
|
||||||
JS_CallFunction( g_ScriptingHost.GetContext(), Context, Function, 1, &EventObject, &Temp );
|
JS_CallFunction( g_ScriptingHost.GetContext(), Context, Function, 1, &EventObject, &Temp );
|
||||||
return( !evt->m_Cancelled );
|
}
|
||||||
|
return( evt->m_Blocked );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CScriptObject::Compile( CStrW FileNameTag, CStrW FunctionBody )
|
void CScriptObject::Compile( CStrW FileNameTag, CStrW FunctionBody )
|
||||||
|
@ -37,15 +37,19 @@ public:
|
|||||||
return( Function != NULL );
|
return( Function != NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline operator bool() { return( Function != NULL ); }
|
||||||
|
inline bool operator!() { return( !Function ); }
|
||||||
|
inline bool operator==( const CScriptObject& compare ) { return( Function == compare.Function ); }
|
||||||
|
|
||||||
// JSObject wrapping the function if it's defined, NULL if it isn't.
|
// JSObject wrapping the function if it's defined, NULL if it isn't.
|
||||||
JSObject* GetFunctionObject();
|
JSObject* GetFunctionObject();
|
||||||
|
|
||||||
// Executes a script attached to a JS object.
|
// Executes a script attached to a JS object.
|
||||||
// Returns false if the script isn't defined, if the script can't be executed,
|
// Returns false if the script isn't defined, if the script can't be executed,
|
||||||
// otherwise true. Script return value is in rval.
|
// otherwise true. Script return value is in rval.
|
||||||
bool Run( JSObject* Context, jsval* rval );
|
bool Run( JSObject* Context, jsval* rval, uintN argc = 0, jsval* argv = NULL );
|
||||||
// This variant casts script return value to a boolean, and passes it back.
|
// This variant casts script return value to a boolean, and passes it back.
|
||||||
bool Run( JSObject* Context );
|
bool Run( JSObject* Context, uintN argc = 0, jsval* argv = NULL );
|
||||||
|
|
||||||
// Treat this as an event handler and dispatch an event to it.
|
// Treat this as an event handler and dispatch an event to it.
|
||||||
bool DispatchEvent( JSObject* Context, CScriptEvent* evt );
|
bool DispatchEvent( JSObject* Context, CScriptEvent* evt );
|
||||||
|
Loading…
Reference in New Issue
Block a user