Gathering and unit training (engine-side); also other minor improvements
This was SVN commit r2132.
This commit is contained in:
parent
79e1c273e6
commit
2120576bc7
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
|
||||
|
||||
<Entity Parent="template_gaia_flora">
|
||||
<Entity Parent="template_gaia_flora" Corpse="template_dead_tree">
|
||||
<Traits>
|
||||
<Id
|
||||
generic="Tree"
|
||||
|
@ -29,6 +29,7 @@
|
||||
list=""
|
||||
list.unit="isw_b;isp_b;ijv_b;iar_b;isl_b;csw_b;csp_b;cjv_b;car_b;fem"
|
||||
list.tech="fem"
|
||||
construct="1"
|
||||
/>
|
||||
</Actions>
|
||||
<Footprint Width="24.0" Height="24.0"/>
|
||||
|
@ -16,158 +16,17 @@
|
||||
<Up
|
||||
rank="0"
|
||||
/>
|
||||
<Creation
|
||||
time="20"
|
||||
/>
|
||||
</Traits>
|
||||
<Event On="Attack">
|
||||
<![CDATA[
|
||||
curr_hit = getGUIGlobal().newRandomSound("voice", "hit", this.traits.audio.path);
|
||||
curr_hit.play();
|
||||
<Script File="entities/template_entity_script.js" />
|
||||
|
||||
// Attack logic.
|
||||
dmg = new DamageType();
|
||||
dmg.crush = parseInt(this.actions.attack.damage * this.actions.attack.crush);
|
||||
dmg.hack = parseInt(this.actions.attack.damage * this.actions.attack.hack);
|
||||
dmg.pierce = parseInt(this.actions.attack.damage * this.actions.attack.pierce);
|
||||
<Event On="Attack" Function="entity_event_attack" />
|
||||
<Event On="Gather" Function="entity_event_gather" />
|
||||
<Event On="TakesDamage" Function="entity_event_takesdamage" />
|
||||
<Event On="TargetChanged" Function="entity_event_targetchanged" />
|
||||
<Event On="PrepareOrder" Function="entity_event_prepareorder" />
|
||||
|
||||
evt.target.damage( dmg, this );
|
||||
]]>
|
||||
</Event>
|
||||
|
||||
<Event On="TakesDamage">
|
||||
<![CDATA[
|
||||
// Apply armour and work out how much damage we actually take
|
||||
crushDamage = parseInt(evt.damage.crush - this.traits.armour.value * this.traits.armour.crush);
|
||||
if ( crushDamage < 0 ) crushDamage = 0;
|
||||
pierceDamage = parseInt(evt.damage.pierce - this.traits.armour.value * this.traits.armour.pierce);
|
||||
if ( pierceDamage < 0 ) pierceDamage = 0;
|
||||
hackDamage = parseInt(evt.damage.hack - this.traits.armour.value * this.traits.armour.hack);
|
||||
if ( hackDamage < 0 ) hackDamage = 0;
|
||||
|
||||
totalDamage = parseInt(evt.damage.typeless + crushDamage + pierceDamage + hackDamage);
|
||||
|
||||
// Minimum of 1 damage
|
||||
|
||||
if( totalDamage < 1 ) totalDamage = 1;
|
||||
|
||||
this.traits.health.curr -= totalDamage;
|
||||
|
||||
if( this.traits.health.curr <= 0 )
|
||||
{
|
||||
// If the inflictor gains promotions, and he's capable of earning more ranks,
|
||||
if (evt.inflictor.traits.up && evt.inflictor.traits.up.curr && evt.inflictor.traits.up.req && evt.inflictor.traits.up.newentity && evt.inflictor.traits.up.newentity != "")
|
||||
{
|
||||
// Give him the fallen's upgrade points (if he has any).
|
||||
if (this.traits.loot.up)
|
||||
evt.inflictor.traits.up.curr = parseInt(evt.inflictor.traits.up.curr) + parseInt(this.traits.loot.up);
|
||||
|
||||
// Notify player.
|
||||
if (this.traits.id.specific)
|
||||
console.write(this.traits.id.specific + " has earned " + this.traits.loot.up + " upgrade points!");
|
||||
else
|
||||
console.write("One of your units has earned " + this.traits.loot.up + " upgrade points!");
|
||||
|
||||
// If he now has maximum upgrade points for his rank,
|
||||
if (evt.inflictor.traits.up.curr >= evt.inflictor.traits.up.req)
|
||||
{
|
||||
// Notify the player.
|
||||
if (this.traits.id.specific)
|
||||
console.write(this.traits.id.specific + " has gained a promotion!");
|
||||
else
|
||||
console.write("One of your units has gained a promotion!");
|
||||
|
||||
// Reset his upgrade points.
|
||||
evt.inflictor.traits.up.curr = 0;
|
||||
|
||||
// Transmogrify him into his next rank.
|
||||
evt.inflictor.template = getEntityTemplate(evt.inflictor.traits.up.newentity);
|
||||
}
|
||||
}
|
||||
|
||||
// If the fallen is worth any loot,
|
||||
if (this.traits.loot && (this.traits.loot.food || this.traits.loot.wood || this.traits.loot.stone || this.traits.loot.ore))
|
||||
{
|
||||
// Give the inflictor his resources.
|
||||
if (this.traits.loot.food)
|
||||
getGUIGlobal().GiveResources("Food", parseInt(this.traits.loot.food));
|
||||
if (this.traits.loot.wood)
|
||||
getGUIGlobal().GiveResources("Wood", parseInt(this.traits.loot.wood));
|
||||
if (this.traits.loot.stone)
|
||||
getGUIGlobal().GiveResources("Stone", parseInt(this.traits.loot.stone));
|
||||
if (this.traits.loot.ore)
|
||||
getGUIGlobal().GiveResources("Ore", parseInt(this.traits.loot.ore));
|
||||
}
|
||||
|
||||
// Notify player.
|
||||
if( evt.inflictor )
|
||||
console.write( this.traits.id.generic + " got the point of " + evt.inflictor.traits.id.generic + "'s Gladius." );
|
||||
else
|
||||
console.write( this.traits.id.generic + " died in mysterious circumstances." );
|
||||
|
||||
// Make him cry out in pain.
|
||||
curr_pain = getGUIGlobal().newRandomSound("voice", "pain", this.traits.audio.path);
|
||||
curr_pain.play();
|
||||
|
||||
// We've taken what we need. Kill the swine.
|
||||
this.kill();
|
||||
}
|
||||
else if( evt.inflictor && this.actions.attack )
|
||||
{
|
||||
// If we're not already doing something else, take a measured response - hit 'em back.
|
||||
// You know, I think this is quite possibly the first AI code the AI divlead has written
|
||||
// for 0 A.D....
|
||||
|
||||
if( this.isIdle() )
|
||||
this.order( ORDER_ATTACK, evt.inflictor );
|
||||
}
|
||||
]]>
|
||||
</Event>
|
||||
<Event On="TargetChanged">
|
||||
<![CDATA[
|
||||
// This event lets us know when the user moves his/her cursor to a different unit (provided this
|
||||
// unit is selected) - use it to tell the engine what context cursor should be displayed, given
|
||||
// the target.
|
||||
|
||||
// Attack iff there's a target, it's our enemy, and we're armed. Otherwise move.
|
||||
// ToString is needed because every property is actually an object (though that's usually
|
||||
// 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
|
||||
// string) first.
|
||||
if( evt.target &&
|
||||
this.actions.attack &&
|
||||
( evt.target.traits.id.civ_code != "gaia" ) &&
|
||||
( evt.target.traits.id.civ_code.toString() != this.traits.id.civ_code.toString() ) )
|
||||
evt.defaultAction = ORDER_ATTACK;
|
||||
else
|
||||
evt.defaultAction = ORDER_GOTO;
|
||||
]]>
|
||||
</Event>
|
||||
<Event On="PrepareOrder">
|
||||
<![CDATA[
|
||||
// This event gives us a chance to veto any order we're given before we execute it.
|
||||
// Not sure whether this really belongs here like this: the alternative is to override it in
|
||||
// subtypes - then you wouldn't need to check tags, you could hardcode results.
|
||||
switch( evt.orderType )
|
||||
{
|
||||
case ORDER_GOTO:
|
||||
if( !this.actions.move )
|
||||
evt.preventDefault();
|
||||
break;
|
||||
case ORDER_PATROL:
|
||||
if( !this.actions.patrol )
|
||||
evt.preventDefault();
|
||||
break;
|
||||
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 ||
|
||||
!evt.target ||
|
||||
( evt.target.traits.id.civ_code.toString() == this.traits.id.civ_code.toString() ) )
|
||||
evt.preventDefault();
|
||||
break;
|
||||
default:
|
||||
evt.preventDefault();
|
||||
}
|
||||
]]>
|
||||
</Event>
|
||||
<Actions>
|
||||
</Actions>
|
||||
<Actions />
|
||||
</Entity>
|
257
binaries/data/mods/official/entities/template_entity_script.js
Normal file
257
binaries/data/mods/official/entities/template_entity_script.js
Normal file
@ -0,0 +1,257 @@
|
||||
function entity_event_attack( evt )
|
||||
{
|
||||
curr_hit = getGUIGlobal().newRandomSound("voice", "hit", this.traits.audio.path);
|
||||
curr_hit.play();
|
||||
|
||||
// Attack logic.
|
||||
dmg = new DamageType();
|
||||
dmg.crush = parseInt(this.actions.attack.damage * this.actions.attack.crush);
|
||||
dmg.hack = parseInt(this.actions.attack.damage * this.actions.attack.hack);
|
||||
dmg.pierce = parseInt(this.actions.attack.damage * this.actions.attack.pierce);
|
||||
evt.target.damage( dmg, this );
|
||||
}
|
||||
|
||||
function entity_event_gather( evt )
|
||||
{
|
||||
gather_amt = parseInt( this.actions.gather[evt.target.traits.supply.type].speed );
|
||||
if( evt.target.traits.supply.max > 0 )
|
||||
{
|
||||
if( evt.target.traits.supply.curr <= gather_amt )
|
||||
{
|
||||
gather_amt = evt.target.traits.supply.curr;
|
||||
evt.target.kill();
|
||||
}
|
||||
console.write( evt.target.traits.supply.type );
|
||||
console.write( evt.target.traits.supply.type.toString().toUpperCase() );
|
||||
evt.target.traits.supply.curr -= gather_amt;
|
||||
this.player.resource.valueOf()[evt.target.traits.supply.type.toString().toUpperCase()] += gather_amt;
|
||||
}
|
||||
}
|
||||
|
||||
function entity_event_takesdamage( evt )
|
||||
{
|
||||
// Apply armour and work out how much damage we actually take
|
||||
crushDamage = parseInt(evt.damage.crush - this.traits.armour.value * this.traits.armour.crush);
|
||||
if ( crushDamage < 0 ) crushDamage = 0;
|
||||
pierceDamage = parseInt(evt.damage.pierce - this.traits.armour.value * this.traits.armour.pierce);
|
||||
if ( pierceDamage < 0 ) pierceDamage = 0;
|
||||
hackDamage = parseInt(evt.damage.hack - this.traits.armour.value * this.traits.armour.hack);
|
||||
if ( hackDamage < 0 ) hackDamage = 0;
|
||||
|
||||
totalDamage = parseInt(evt.damage.typeless + crushDamage + pierceDamage + hackDamage);
|
||||
|
||||
// Minimum of 1 damage
|
||||
|
||||
if( totalDamage < 1 ) totalDamage = 1;
|
||||
|
||||
this.traits.health.curr -= totalDamage;
|
||||
|
||||
if( this.traits.health.curr <= 0 )
|
||||
{
|
||||
// If the inflictor gains promotions, and he's capable of earning more ranks,
|
||||
if (evt.inflictor.traits.up && evt.inflictor.traits.up.curr && evt.inflictor.traits.up.req && evt.inflictor.traits.up.newentity && evt.inflictor.traits.up.newentity != "")
|
||||
{
|
||||
// Give him the fallen's upgrade points (if he has any).
|
||||
if (this.traits.loot.up)
|
||||
evt.inflictor.traits.up.curr = parseInt(evt.inflictor.traits.up.curr) + parseInt(this.traits.loot.up);
|
||||
// Notify player.
|
||||
if (this.traits.id.specific)
|
||||
console.write(this.traits.id.specific + " has earned " + this.traits.loot.up + " upgrade points!");
|
||||
else
|
||||
console.write("One of your units has earned " + this.traits.loot.up + " upgrade points!");
|
||||
|
||||
// If he now has maximum upgrade points for his rank,
|
||||
if (evt.inflictor.traits.up.curr >= evt.inflictor.traits.up.req)
|
||||
{
|
||||
// Notify the player.
|
||||
if (this.traits.id.specific)
|
||||
console.write(this.traits.id.specific + " has gained a promotion!");
|
||||
else
|
||||
console.write("One of your units has gained a promotion!");
|
||||
|
||||
// Reset his upgrade points.
|
||||
evt.inflictor.traits.up.curr = 0;
|
||||
|
||||
// Transmogrify him into his next rank.
|
||||
evt.inflictor.template = getEntityTemplate(evt.inflictor.traits.up.newentity);
|
||||
}
|
||||
}
|
||||
|
||||
// If the fallen is worth any loot,
|
||||
if (this.traits.loot && (this.traits.loot.food || this.traits.loot.wood || this.traits.loot.stone || this.traits.loot.ore))
|
||||
{
|
||||
// Give the inflictor his resources.
|
||||
if (this.traits.loot.food)
|
||||
getGUIGlobal().GiveResources("Food", parseInt(this.traits.loot.food));
|
||||
if (this.traits.loot.wood)
|
||||
getGUIGlobal().GiveResources("Wood", parseInt(this.traits.loot.wood));
|
||||
if (this.traits.loot.stone)
|
||||
getGUIGlobal().GiveResources("Stone", parseInt(this.traits.loot.stone));
|
||||
if (this.traits.loot.ore)
|
||||
getGUIGlobal().GiveResources("Ore", parseInt(this.traits.loot.ore));
|
||||
}
|
||||
|
||||
// Notify player.
|
||||
if( evt.inflictor )
|
||||
console.write( this.traits.id.generic + " got the point of " + evt.inflictor.traits.id.generic + "'s Gladius." );
|
||||
else
|
||||
console.write( this.traits.id.generic + " died in mysterious circumstances." );
|
||||
|
||||
// Make him cry out in pain.
|
||||
curr_pain = getGUIGlobal().newRandomSound("voice", "pain", this.traits.audio.path);
|
||||
curr_pain.play();
|
||||
|
||||
// We've taken what we need. Kill the swine.
|
||||
this.kill();
|
||||
}
|
||||
else if( evt.inflictor && this.actions.attack )
|
||||
{
|
||||
// If we're not already doing something else, take a measured response - hit 'em back.
|
||||
// You know, I think this is quite possibly the first AI code the AI divlead has written
|
||||
// for 0 A.D....
|
||||
if( this.isIdle() )
|
||||
this.order( ORDER_ATTACK, evt.inflictor );
|
||||
}
|
||||
}
|
||||
|
||||
function entity_event_targetchanged( evt )
|
||||
{
|
||||
// This event lets us know when the user moves his/her cursor to a different unit (provided this
|
||||
// unit is selected) - use it to tell the engine what context cursor should be displayed, given
|
||||
// the target.
|
||||
|
||||
// Attack iff there's a target, it's our enemy, and we're armed. Otherwise, if we can gather, and
|
||||
// the target supplies, gather. If all else fails, move.
|
||||
// ToString is needed because every property is actually an object (though that's usually
|
||||
// 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
|
||||
// string) first.
|
||||
|
||||
evt.defaultAction = ORDER_GOTO;
|
||||
if( evt.target )
|
||||
{
|
||||
if( this.actions.attack &&
|
||||
( evt.target.traits.id.civ_code != "gaia" ) &&
|
||||
( evt.target.traits.id.civ_code.toString() != this.traits.id.civ_code.toString() ) )
|
||||
evt.defaultAction = ORDER_ATTACK;
|
||||
if( this.actions.gather && evt.target.traits.supply &&
|
||||
this.actions.gather.valueOf()[evt.target.traits.supply.type] &&
|
||||
( ( evt.target.traits.supply.curr > 0 ) || ( evt.target.traits.supply.max == 0 ) ) )
|
||||
evt.defaultAction = ORDER_GATHER;
|
||||
}
|
||||
}
|
||||
|
||||
function entity_event_prepareorder( evt )
|
||||
{
|
||||
// This event gives us a chance to veto any order we're given before we execute it.
|
||||
// Not sure whether this really belongs here like this: the alternative is to override it in
|
||||
// subtypes - then you wouldn't need to check tags, you could hardcode results.
|
||||
switch( evt.orderType )
|
||||
{
|
||||
case ORDER_GOTO:
|
||||
if( !this.actions.move )
|
||||
evt.preventDefault();
|
||||
break;
|
||||
case ORDER_PATROL:
|
||||
if( !this.actions.patrol )
|
||||
evt.preventDefault();
|
||||
break;
|
||||
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 ||
|
||||
!evt.target ||
|
||||
( evt.target.traits.id.civ_code.toString() == this.traits.id.civ_code.toString() ) )
|
||||
evt.preventDefault();
|
||||
break;
|
||||
case ORDER_GATHER:
|
||||
if( !this.actions.gather ||
|
||||
!this.actions.gather.valueOf()[evt.target.traits.supply.type] ||
|
||||
( ( evt.target.traits.supply.curr == 0 ) && ( evt.target.traits.supply.max > 0 ) ) )
|
||||
evt.preventDefault();
|
||||
default:
|
||||
evt.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
function entity_add_create_queue( template )
|
||||
{
|
||||
// Make sure we have a queue to put things in...
|
||||
if( !this.actions.create.queue )
|
||||
this.actions.create.queue = new Array();
|
||||
// Append to the end of this queue
|
||||
this.actions.create.queue.valueOf().push( template );
|
||||
// If we're not already building something...
|
||||
if( !this.actions.create.progress || !this.actions.create.progress.valueOf() )
|
||||
{
|
||||
console.write( "Starting work on (unqueued) ", template.tag );
|
||||
// Start the progress timer.
|
||||
// - First parameter is target value (in this case, base build time in seconds)
|
||||
// - Second parameter is increment per millisecond (use build rate modifier and correct for milliseconds)
|
||||
// - Third parameter is the function to call when the timer finishes.
|
||||
// - Fourth parameter is the scope under which to run that function (what the 'this' parameter should be)
|
||||
this.actions.create.progress = new ProgressTimer( template.traits.creation.time, this.actions.create.construct / 1000, entity_create_complete, this )
|
||||
}
|
||||
}
|
||||
|
||||
// This is the syntax to add a function (or a property) to absolutely every entity.
|
||||
|
||||
Entity.prototype.add_create_queue = entity_add_create_queue;
|
||||
|
||||
function entity_create_complete()
|
||||
{
|
||||
// Get the unit that was at the head of our queue, and remove it.
|
||||
// (Oh, for information about all these nifty properties and functions
|
||||
// of the Array object that I use, see the ECMA-262 documentation
|
||||
// at http://www.mozilla.org/js/language/E262-3.pdf. Bit technical but
|
||||
// the sections on 'Native ECMAScript Objects' are quite useful)
|
||||
|
||||
var template = this.actions.create.queue.valueOf().shift();
|
||||
|
||||
// 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
|
||||
// much space it needs to leave.
|
||||
position = this.getSpawnPoint( template );
|
||||
|
||||
// The above function returns null if it couldn't find a large enough space.
|
||||
if( !position )
|
||||
{
|
||||
console.write( "Couldn't train unit - not enough space" );
|
||||
// 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
|
||||
// around their barracks, doesn't it?
|
||||
return;
|
||||
}
|
||||
|
||||
created = new Entity( template, position );
|
||||
|
||||
// Above shouldn't ever fail, but just in case...
|
||||
if( !created )
|
||||
return;
|
||||
|
||||
console.write( "Created: ", template.tag );
|
||||
|
||||
// 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( this.actions.create.queue.valueOf().length > 0 )
|
||||
{
|
||||
// Start on the next item.
|
||||
template = this.actions.create.queue.valueOf()[0];
|
||||
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 )
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, delete the timer.
|
||||
this.actions.create.progress = null;
|
||||
}
|
||||
}
|
||||
|
||||
function attempt_add_to_build_queue( entity, create_tag )
|
||||
{
|
||||
console.write( "Adding ", create_tag, " to build queue..." );
|
||||
entity.add_create_queue( getEntityTemplate( create_tag ) );
|
||||
}
|
@ -58,10 +58,10 @@
|
||||
food.fruit="1"
|
||||
food.grain="1"
|
||||
food.fish="1"
|
||||
wood="1"
|
||||
stone="1"
|
||||
ore="1"
|
||||
/>
|
||||
ore="1" >
|
||||
<Wood speed="1" />
|
||||
</Gather>
|
||||
<Repair
|
||||
rate="1"
|
||||
/>
|
||||
|
@ -12,17 +12,6 @@
|
||||
</Traits>
|
||||
<Event On="Initialize">
|
||||
<![CDATA[
|
||||
// PASAP wander-between-houses script
|
||||
|
||||
houses = entities.subset( "this.template.tag == \"House\"" );
|
||||
while( houses.length )
|
||||
{
|
||||
index = Math.floor( Math.random() * houses.length );
|
||||
house = houses[index];
|
||||
console.write( house.position );
|
||||
this.orderQueued( 4 /* patrol */, house.position.x, house.position.z );
|
||||
houses.remove( index );
|
||||
}
|
||||
console.write( "A new Dude has entered your dungeon." );
|
||||
]]>
|
||||
</Event>
|
||||
|
@ -49,26 +49,21 @@ function AddResource(resourceName, resourceQty)
|
||||
{
|
||||
// Creates a resource type.
|
||||
|
||||
// MT: Rewritten to use JavaScript's nice associative-array-alikes. Requires the valueOf() hack - I'm looking into this.
|
||||
|
||||
if (!localPlayer.resource)
|
||||
{
|
||||
// Define the base resource group if it does not exist.
|
||||
localPlayer.resource = new Array();
|
||||
|
||||
// Define resource total.
|
||||
localPlayer.resource.last = new Object();
|
||||
localPlayer.resource.last = 0;
|
||||
}
|
||||
|
||||
// Set resource name to upper-case to ensure it matches resource control name.
|
||||
resourceName = resourceName.toUpperCase();
|
||||
|
||||
// Store resource's name and starting value.
|
||||
localPlayer.resource[localPlayer.resource.last] = new Object();
|
||||
localPlayer.resource[localPlayer.resource.last].name = resourceName;
|
||||
localPlayer.resource[localPlayer.resource.last].qty = resourceQty;
|
||||
localPlayer.resource.last++;
|
||||
localPlayer.resource.valueOf()[resourceName] = resourceQty;
|
||||
|
||||
console.write("Added " + resourceName + " (" + localPlayer.resource.last + ")");
|
||||
console.write("Added " + resourceName );
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
@ -91,20 +86,17 @@ function GiveResources(resourceName, resourceQty)
|
||||
{
|
||||
// Generic function to add resources to the player's Pool.
|
||||
|
||||
// Find the resource in the list.
|
||||
resourceSeek = 0;
|
||||
while (resourceName != localPlayer.resource[resourceSeek].name && resourceSeek < localPlayer.resource.last)
|
||||
resourceSeek++;
|
||||
// MT: Rewritten to use JavaScript's nice associative-array-alikes. Requires the valueOf() hack - I'm looking into this.
|
||||
|
||||
if( localPlayer.resource.valueOf()[resourceName] )
|
||||
{
|
||||
localPlayer.resource.valueOf()[resourceName] += resourceQty;
|
||||
console.write("Earned " + resourceQty + " resources.");
|
||||
return( true );
|
||||
}
|
||||
|
||||
// If the resource wasn't in the list, report an error.
|
||||
return false;
|
||||
|
||||
// Add the quantity to the resource.
|
||||
localPlayer.resource[resourceSeek].qty += resourceQty;
|
||||
|
||||
console.write("Earned " + resourceQty + " resources.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
@ -113,20 +105,23 @@ function UpdateResourcePool()
|
||||
{
|
||||
// Populate the resource pool with current quantities.
|
||||
|
||||
for (resourceSeek = 0; resourceSeek < localPlayer.resource.last; resourceSeek++)
|
||||
// MT: Rewritten to use JavaScript's nice associative-array-alikes. Requires the valueOf() hack - I'm looking into this.
|
||||
|
||||
pool = localPlayer.resource.valueOf();
|
||||
for( resource in pool )
|
||||
{
|
||||
switch (localPlayer.resource[resourceSeek].name.toString())
|
||||
switch( resource )
|
||||
{
|
||||
case "POPULATION":
|
||||
// If it's population, combine population and housing in one string.
|
||||
getGUIObjectByName("SN_RESOURCE_COUNTER_POPULATION").caption = localPlayer.resource[resourceSeek].qty + "/" + localPlayer.resource[resourceSeek].qty;
|
||||
getGUIObjectByName("SN_RESOURCE_COUNTER_POPULATION").caption = pool.POPULATION + "/" + pool.HOUSING;
|
||||
break;
|
||||
case "HOUSING":
|
||||
// Skip housing, as it's handled as a component of population.
|
||||
break;
|
||||
default:
|
||||
// Set the value of a normal resource caption.
|
||||
getGUIObjectByName("SN_RESOURCE_COUNTER_" + localPlayer.resource[resourceSeek].name).caption = localPlayer.resource[resourceSeek].qty.toString();
|
||||
getGUIObjectByName("SN_RESOURCE_COUNTER_" + resource ).caption = pool[resource].toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -227,7 +227,9 @@ function initStatusOrb()
|
||||
{
|
||||
for (SN_STATUS_PANE_COMMAND.list.curr = 1; SN_STATUS_PANE_COMMAND.list.curr <= SN_STATUS_PANE_COMMAND.list.max; SN_STATUS_PANE_COMMAND.list.curr++)
|
||||
{
|
||||
SN_STATUS_PANE_COMMAND[SN_STATUS_PANE_COMMAND.list.curr][SN_STATUS_PANE_COMMAND.tab.curr] = addArrayElement(Crd, Crd.last);
|
||||
// MT: What's going on here?
|
||||
|
||||
SN_STATUS_PANE_COMMAND[SN_STATUS_PANE_COMMAND.list.curr][SN_STATUS_PANE_COMMAND.tab.curr] = new Number( addArrayElement(Crd, Crd.last) );
|
||||
Crd[Crd.last-1].rleft = left_screen; Crd[Crd.last-1].rtop = bottom_screen;
|
||||
Crd[Crd.last-1].rright = left_screen; Crd[Crd.last-1].rbottom = bottom_screen;
|
||||
Crd[Crd.last-1].width = crd_portrait_sml_width;
|
||||
@ -375,10 +377,10 @@ function UpdateList(listIcon, listCol)
|
||||
|
||||
setPortrait("SN_STATUS_PANE_COMMAND_" + listCol + "_" + parseInt(createLoop+2), getEntityTemplate(UpdateListEntityName).traits.id.icon, selection[0].traits.id.civ_code, getEntityTemplate(UpdateListEntityName).traits.id.icon_cell);
|
||||
GUIObjectUnhide("SN_STATUS_PANE_COMMAND_" + listCol + "_" + parseInt(createLoop+2));
|
||||
|
||||
|
||||
// Store content info in tab button for future reference.
|
||||
SN_STATUS_PANE_COMMAND[parseInt(createLoop+2)][listCol].name = listArray[createLoop];
|
||||
SN_STATUS_PANE_COMMAND[parseInt(createLoop+2)][listCol].last++;
|
||||
SN_STATUS_PANE_COMMAND[parseInt(createLoop+2)][listCol].last++;
|
||||
}
|
||||
else
|
||||
GUIObjectHide("SN_STATUS_PANE_COMMAND_" + listCol + "_" + parseInt(createLoop+2));
|
||||
@ -415,7 +417,7 @@ function UpdateCommand(listIcon, listCol)
|
||||
SN_STATUS_PANE_COMMAND[1][listCol].type = "command";
|
||||
SN_STATUS_PANE_COMMAND[1][listCol].last = 0;
|
||||
SN_STATUS_PANE_COMMAND[1][listCol].name = listIcon;
|
||||
|
||||
|
||||
return (listCol-1);
|
||||
}
|
||||
else
|
||||
@ -444,7 +446,9 @@ function PressCommandButton(list, tab)
|
||||
break;
|
||||
default:
|
||||
tempListObject.caption = list-1;
|
||||
//console.write("Clicked [" + list + "," + tab + "]: list of type " + SN_STATUS_PANE_COMMAND[list][tab].type + "; " + SN_STATUS_PANE_COMMAND[list][tab].last + "; " + SN_STATUS_PANE_COMMAND[list][tab].name);
|
||||
console.write("Clicked [" + list + "," + tab + "]: list of type " + SN_STATUS_PANE_COMMAND[list][tab].type + "; " + SN_STATUS_PANE_COMMAND[list][tab].name);
|
||||
|
||||
attempt_add_to_build_queue( selection[0], selection[0].traits.id.civ_code + "_" + SN_STATUS_PANE_COMMAND[list][tab].name );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ CObjectEntry::CObjectEntry(int type, CObjectBase* base)
|
||||
m_DeathAnim=0;
|
||||
m_CorpseAnim=0;
|
||||
m_MeleeAnim=0;
|
||||
m_GatherAnim=0;
|
||||
m_RangedAnim=0;
|
||||
}
|
||||
|
||||
@ -156,6 +157,9 @@ bool CObjectEntry::BuildRandomVariant(CObjectBase::variation_key& vars, CObjectB
|
||||
if (AnimNameLC == "attack")
|
||||
m_MeleeAnim = m_Animations[t].m_AnimData;
|
||||
else
|
||||
if (AnimNameLC == "chop")
|
||||
m_GatherAnim = m_Animations[t].m_AnimData;
|
||||
else
|
||||
if (AnimNameLC == "death")
|
||||
m_DeathAnim = m_Animations[t].m_AnimData;
|
||||
else
|
||||
|
@ -35,6 +35,7 @@ public:
|
||||
CSkeletonAnim* m_WalkAnim;
|
||||
CSkeletonAnim* m_DeathAnim;
|
||||
CSkeletonAnim* m_MeleeAnim;
|
||||
CSkeletonAnim* m_GatherAnim;
|
||||
CSkeletonAnim* m_RangedAnim;
|
||||
CSkeletonAnim* m_CorpseAnim;
|
||||
|
||||
|
@ -330,7 +330,7 @@ void CGUI::Initialize()
|
||||
AddObjectType("progressbar", &CProgressBar::ConstructObject);
|
||||
AddObjectType("minimap", &CMiniMap::ConstructObject);
|
||||
AddObjectType("input", &CInput::ConstructObject);
|
||||
AddObjectType("list", &CList::ConstructObject);
|
||||
// AddObjectType("list", &CList::ConstructObject);
|
||||
}
|
||||
|
||||
void CGUI::Process()
|
||||
|
@ -772,11 +772,13 @@ TIMER(InitScripting)
|
||||
CDamageType::ScriptingInit();
|
||||
CJSPropertyAccessor<CEntity>::ScriptingInit(); // <-- Doesn't really matter which we use, but we know CJSPropertyAccessor<T> is already being compiled for T = CEntity.
|
||||
CScriptEvent::ScriptingInit();
|
||||
CJSProgressTimer::ScriptingInit();
|
||||
|
||||
g_ScriptingHost.DefineConstant( "ORDER_NONE", -1 );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_GOTO", CEntityOrder::ORDER_GOTO );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_PATROL", CEntityOrder::ORDER_PATROL );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_ATTACK", CEntityOrder::ORDER_ATTACK_MELEE );
|
||||
g_ScriptingHost.DefineConstant( "ORDER_GATHER", CEntityOrder::ORDER_GATHER );
|
||||
|
||||
JSI_Camera::init();
|
||||
JSI_Console::init();
|
||||
|
@ -135,6 +135,9 @@ void CSelectedEntities::renderOverlays()
|
||||
case CEntityOrder::ORDER_ATTACK_MELEE:
|
||||
glwprintf( L"Attack" );
|
||||
break;
|
||||
case CEntityOrder::ORDER_GATHER:
|
||||
glwprintf( L"Gather" );
|
||||
break;
|
||||
}
|
||||
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
@ -392,18 +395,6 @@ void CSelectedEntities::update()
|
||||
m_selectionChanged = false;
|
||||
g_Mouseover.m_targetChanged = false;
|
||||
}
|
||||
/*
|
||||
if( !isContextValid( m_contextOrder ) )
|
||||
{
|
||||
// This order isn't valid for the current selection and/or target.
|
||||
for( int t = 0; t < CEntityOrder::ORDER_LAST; t++ )
|
||||
if( isContextValid( t ) )
|
||||
{
|
||||
m_contextOrder = t; return;
|
||||
}
|
||||
m_contextOrder = -1;
|
||||
}
|
||||
*/
|
||||
|
||||
if( ( m_group_highlight != -1 ) && getGroupCount( m_group_highlight ) )
|
||||
g_Game->GetView()->SetCameraTarget( getGroupPosition( m_group_highlight ) );
|
||||
@ -504,6 +495,18 @@ void CSelectedEntities::contextOrder( bool pushQueue )
|
||||
}
|
||||
return;
|
||||
}
|
||||
case CEntityOrder::ORDER_GATHER:
|
||||
{
|
||||
context.m_data[0].entity = g_Mouseover.m_target;
|
||||
for( it = m_selected.begin(); it < m_selected.end(); it++ )
|
||||
if( (*it)->acceptsOrder( m_contextOrder, g_Mouseover.m_target ) )
|
||||
{
|
||||
if( !pushQueue )
|
||||
(*it)->clearOrders();
|
||||
(*it)->pushOrder( context );
|
||||
}
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -192,6 +192,10 @@ CProfileManager::CProfileManager()
|
||||
|
||||
CProfileManager::~CProfileManager()
|
||||
{
|
||||
std::map<CStr8, const char*>::iterator it;
|
||||
for( it = m_internedStrings.begin(); it != m_internedStrings.end(); it++ )
|
||||
delete[]( it->second );
|
||||
|
||||
delete( root );
|
||||
}
|
||||
|
||||
@ -209,6 +213,20 @@ void CProfileManager::StartScript( const char* name )
|
||||
current->Call();
|
||||
}
|
||||
|
||||
const char* CProfileManager::InternString( CStr8 intern )
|
||||
{
|
||||
std::map<CStr8, const char*>::iterator it = m_internedStrings.find( intern );
|
||||
if( it != m_internedStrings.end() )
|
||||
return( it->second );
|
||||
|
||||
size_t length = intern.length();
|
||||
char* data = new char[length + 1];
|
||||
strcpy( data, intern.c_str() );
|
||||
data[length] = 0;
|
||||
m_internedStrings.insert( std::pair<CStr8, const char*>( intern, data ) );
|
||||
return( data );
|
||||
}
|
||||
|
||||
void CProfileManager::Stop()
|
||||
{
|
||||
if( current->Return() )
|
||||
|
@ -99,6 +99,7 @@ class CProfileManager : public Singleton<CProfileManager>
|
||||
CProfileNode* current;
|
||||
double start;
|
||||
double frame_start;
|
||||
std::map<CStr8, const char*> m_internedStrings;
|
||||
|
||||
public:
|
||||
CProfileManager();
|
||||
@ -118,6 +119,8 @@ public:
|
||||
// Resets absolutely everything
|
||||
void StructuralReset();
|
||||
|
||||
const char* InternString( CStr8 intern );
|
||||
|
||||
inline const CProfileNode* GetCurrent() { return( current ); }
|
||||
inline const CProfileNode* GetRoot() { return( root ); }
|
||||
double GetTime();
|
||||
@ -128,6 +131,7 @@ public:
|
||||
|
||||
class CProfileSample
|
||||
{
|
||||
static std::map<CStrW, char*> evMap;
|
||||
public:
|
||||
CProfileSample( const char* name )
|
||||
{
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "res/unifont.h"
|
||||
#include "Hotkey.h"
|
||||
|
||||
bool profileVisible = true;
|
||||
bool profileVisible = false;
|
||||
extern int g_xres, g_yres;
|
||||
|
||||
const CProfileNode* currentNode = NULL;
|
||||
|
@ -90,7 +90,7 @@ JSBool JSI_Console::writeConsole( JSContext* UNUSEDPARAM(context), JSObject* UNU
|
||||
{
|
||||
try
|
||||
{
|
||||
CStrW arg = g_ScriptingHost.ValueToUCString( argv[0] );
|
||||
CStrW arg = g_ScriptingHost.ValueToUCString( argv[i] );
|
||||
output += arg;
|
||||
}
|
||||
catch( PSERROR_Scripting_ConversionFailed )
|
||||
|
@ -109,8 +109,8 @@ public:
|
||||
// Check for a property
|
||||
virtual IJSProperty* HasProperty( CStrW PropertyName ) = 0;
|
||||
|
||||
// Retrieve the value of a property
|
||||
virtual void GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp ) = 0;
|
||||
// Retrieve the value of a property (returning false if that property is not defined)
|
||||
virtual bool GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp ) = 0;
|
||||
|
||||
// Add a property (with immediate value)
|
||||
virtual void AddProperty( CStrW PropertyName, jsval Value ) = 0;
|
||||
@ -435,9 +435,12 @@ template<typename T, bool ReadOnly> class CJSObject : public IJSObject
|
||||
typedef STL_HASH_MAP<CStrW, CJSReflector*, CStrW_hash_compare> ReflectorTable;
|
||||
|
||||
JSObject* m_JS;
|
||||
|
||||
ReflectorTable m_Reflectors;
|
||||
|
||||
public:
|
||||
static JSClass JSI_class;
|
||||
|
||||
// Whether native code is responsible for managing this object.
|
||||
// Script constructors should clear this *BEFORE* creating a JS
|
||||
// mirror (otherwise it'll be rooted).
|
||||
@ -445,7 +448,7 @@ public:
|
||||
bool m_EngineOwned;
|
||||
|
||||
// JS Property access
|
||||
void GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp );
|
||||
bool GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp );
|
||||
void SetProperty( JSContext* cx, CStrW PropertyName, jsval* vp )
|
||||
{
|
||||
if( !ReadOnly )
|
||||
@ -499,7 +502,8 @@ public:
|
||||
|
||||
CStrW PropName = g_ScriptingHost.ValueToUCString( id );
|
||||
|
||||
Instance->GetProperty( cx, PropName, vp );
|
||||
if( !Instance->GetProperty( cx, PropName, vp ) )
|
||||
return( JS_TRUE );
|
||||
|
||||
return( JS_TRUE );
|
||||
}
|
||||
@ -528,11 +532,13 @@ public:
|
||||
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_SharedProperties.begin(); it != m_SharedProperties.end(); it++ )
|
||||
for( it = m_IntrinsicProperties.begin(); it != m_IntrinsicProperties.end(); it++ )
|
||||
delete( it->second );
|
||||
}
|
||||
static void DefaultFinalize( JSContext *cx, JSObject *obj )
|
||||
@ -546,7 +552,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
static JSClass JSI_class;
|
||||
|
||||
JSObject* GetScript()
|
||||
{
|
||||
if( !m_JS )
|
||||
@ -777,7 +783,7 @@ 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> typename CJSObject<typename T, ReadOnly>::PropertyTable CJSObject<T, ReadOnly>::m_IntrinsicProperties;
|
||||
|
||||
template<typename T, bool ReadOnly> void CJSObject<T, ReadOnly>::GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp )
|
||||
template<typename T, bool ReadOnly> bool CJSObject<T, ReadOnly>::GetProperty( JSContext* cx, CStrW PropertyName, jsval* vp )
|
||||
{
|
||||
IJSProperty* Property = HasProperty( PropertyName );
|
||||
if( Property && Property->m_Intrinsic )
|
||||
@ -811,7 +817,7 @@ template<typename T, bool ReadOnly> void CJSObject<T, ReadOnly>::GetProperty( JS
|
||||
}
|
||||
|
||||
if( !check )
|
||||
return;
|
||||
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
|
||||
@ -839,6 +845,7 @@ template<typename T, bool ReadOnly> void CJSObject<T, ReadOnly>::GetProperty( JS
|
||||
*vp = OBJECT_TO_JSVAL( it->second->m_JSAccessor );
|
||||
}
|
||||
}
|
||||
return( true );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -98,6 +98,7 @@ public:
|
||||
// TODO: Remove one of these
|
||||
inline JSContext *getContext() { return m_Context; }
|
||||
inline JSContext *GetContext() { return m_Context; }
|
||||
inline JSObject* GetGlobalObject() { return m_GlobalObject; }
|
||||
|
||||
void LoadScriptFromDisk(const std::string & fileName);
|
||||
|
||||
|
@ -85,6 +85,7 @@ bool CBaseEntity::loadXML( CStr filename )
|
||||
AT(height);
|
||||
AT(on);
|
||||
AT(file);
|
||||
AT(function);
|
||||
#undef AT
|
||||
#undef EL
|
||||
|
||||
@ -161,14 +162,28 @@ bool CBaseEntity::loadXML( CStr filename )
|
||||
CStrW EventName = L"on" + (CStrW)Child.getAttributes().getNamedItem( at_on );
|
||||
|
||||
CStrW Code (Child.getText());
|
||||
|
||||
CStrW ExternalFunction = (CStrW)Child.getAttributes().getNamedItem( at_function );
|
||||
|
||||
// Does a property with this name already exist?
|
||||
|
||||
for( uint eventID = 0; eventID < EVENT_LAST; eventID++ )
|
||||
{
|
||||
if( CStrW( EventNames[eventID] ) == EventName )
|
||||
{
|
||||
m_EventHandlers[eventID].Compile( CStrW( filename ) + L"::" + EventName + L" (" + CStrW( Child.getLineNumber() ) + L")", Code );
|
||||
if( ExternalFunction != CStrW() )
|
||||
{
|
||||
jsval fnval;
|
||||
assert( JS_TRUE == JS_GetUCProperty( g_ScriptingHost.GetContext(), g_ScriptingHost.GetGlobalObject(), ExternalFunction.c_str(), ExternalFunction.Length(), &fnval ) );
|
||||
JSFunction* fn = JS_ValueToFunction( g_ScriptingHost.GetContext(), fnval );
|
||||
if( !fn )
|
||||
{
|
||||
LOG( ERROR, LOG_CATEGORY, "CBaseEntity::LoadXML: Function does not exist for event %hs in file %s. Load failed.", EventName.c_str(), filename.c_str() );
|
||||
break;
|
||||
}
|
||||
m_EventHandlers[eventID].SetFunction( fn );
|
||||
}
|
||||
else
|
||||
m_EventHandlers[eventID].Compile( CStrW( filename ) + L"::" + EventName + L" (" + CStrW( Child.getLineNumber() ) + L")", Code );
|
||||
HasProperty( EventName )->m_Inherited = false;
|
||||
break;
|
||||
}
|
||||
|
@ -220,6 +220,12 @@ void CEntity::update( size_t timestep )
|
||||
case CEntityOrder::ORDER_ATTACK_MELEE_NOPATHING:
|
||||
if( processAttackMeleeNoPathing( current, timestep ) ) break;
|
||||
return;
|
||||
case CEntityOrder::ORDER_GATHER:
|
||||
if( processGather( current, timestep ) ) break;
|
||||
return;
|
||||
case CEntityOrder::ORDER_GATHER_NOPATHING:
|
||||
if( processGatherNoPathing( current, timestep ) ) break;
|
||||
return;
|
||||
case CEntityOrder::ORDER_GOTO:
|
||||
if( processGoto( current, timestep ) ) break;
|
||||
return;
|
||||
@ -322,24 +328,7 @@ void CEntity::dispatch( const CMessage* msg )
|
||||
|
||||
bool CEntity::DispatchEvent( CScriptEvent* evt )
|
||||
{
|
||||
// MT: HACK. And it leaks.
|
||||
static std::map<CStrW, char*> evMap;
|
||||
char* data;
|
||||
std::map<CStrW, char*>::iterator it = evMap.find( evt->m_Type );
|
||||
if( it != evMap.end() )
|
||||
{
|
||||
data = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
CStr8 short_string( evt->m_Type );
|
||||
size_t length = short_string.length();
|
||||
data = new char[length + 9];
|
||||
strcpy( data, "script: " );
|
||||
strcpy( data + 8, short_string.c_str() );
|
||||
data[length + 8] = 0;
|
||||
evMap.insert( std::pair<CStrW, char*>( evt->m_Type, data ) );
|
||||
}
|
||||
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 );
|
||||
@ -368,19 +357,6 @@ bool CEntity::acceptsOrder( int orderType, CEntity* orderTarget )
|
||||
{
|
||||
CEventPrepareOrder evt( orderTarget, orderType );
|
||||
return( DispatchEvent( &evt ) );
|
||||
|
||||
/*
|
||||
// Hardcoding...
|
||||
switch( orderType )
|
||||
{
|
||||
case CEntityOrder::ORDER_GOTO:
|
||||
case CEntityOrder::ORDER_PATROL:
|
||||
return( m_speed > 0.0f );
|
||||
case CEntityOrder::ORDER_ATTACK_MELEE:
|
||||
return( orderTarget && ( m_meleeRange > 0.0f ) );
|
||||
}
|
||||
return( false );
|
||||
*/
|
||||
}
|
||||
|
||||
void CEntity::repath()
|
||||
@ -644,7 +620,7 @@ void CEntity::ScriptingInit()
|
||||
AddMethod<bool, &CEntity::Kill>( "kill", 0 );
|
||||
AddMethod<bool, &CEntity::Damage>( "damage", 1 );
|
||||
AddMethod<bool, &CEntity::IsIdle>( "isIdle", 0 );
|
||||
|
||||
AddMethod<jsval, &CEntity::GetSpawnPoint>( "getSpawnPoint", 1 );
|
||||
|
||||
AddClassProperty( L"template", (CBaseEntity* CEntity::*)&CEntity::m_base, false, (NotifyFn)&CEntity::loadBase );
|
||||
|
||||
@ -659,7 +635,7 @@ JSBool CEntity::Construct( JSContext* cx, JSObject* obj, unsigned int argc, jsva
|
||||
|
||||
CBaseEntity* baseEntity = NULL;
|
||||
CVector3D position;
|
||||
float orientation = 0.0f;
|
||||
float orientation = (float)( PI * ( (double)( rand() & 0x7fff ) / (double)0x4000 ) );
|
||||
|
||||
JSObject* jsBaseEntity = JSVAL_TO_OBJECT( argv[0] );
|
||||
CStrW templateName;
|
||||
@ -765,6 +741,7 @@ bool CEntity::Order( JSContext* cx, uintN argc, jsval* argv, bool Queued )
|
||||
}
|
||||
break;
|
||||
case CEntityOrder::ORDER_ATTACK_MELEE:
|
||||
case CEntityOrder::ORDER_GATHER:
|
||||
if( argc < 1 )
|
||||
{
|
||||
JS_ReportError( cx, "Too few parameters" );
|
||||
@ -779,6 +756,7 @@ bool CEntity::Order( JSContext* cx, uintN argc, jsval* argv, bool Queued )
|
||||
}
|
||||
newOrder.m_data[0].entity = target->me;
|
||||
break;
|
||||
|
||||
default:
|
||||
JS_ReportError( cx, "Invalid order type" );
|
||||
return( false );
|
||||
@ -860,3 +838,134 @@ bool CEntity::Kill( JSContext* cx, uintN argc, jsval* argv )
|
||||
|
||||
return( true );
|
||||
}
|
||||
|
||||
jsval CEntity::GetSpawnPoint( JSContext* cx, uintN argc, jsval* argv )
|
||||
{
|
||||
float spawn_clearance = 2.0f;
|
||||
if( argc >= 1 )
|
||||
{
|
||||
CBaseEntity* be = ToNative<CBaseEntity>( argv[0] );
|
||||
if( be )
|
||||
{
|
||||
switch( be->m_bound_type )
|
||||
{
|
||||
case CBoundingObject::BOUND_CIRCLE: spawn_clearance = be->m_bound_circle->m_radius; break;
|
||||
case CBoundingObject::BOUND_OABB: spawn_clearance = be->m_bound_box->m_radius; break;
|
||||
default: assert( 0 && "No bounding information for spawned object!" );
|
||||
}
|
||||
}
|
||||
else
|
||||
spawn_clearance = ToPrimitive<float>( argv[0] );
|
||||
}
|
||||
else
|
||||
assert( 0 && "No arguments to Entity::GetSpawnPoint()" );
|
||||
|
||||
// TODO: Make netsafe.
|
||||
CBoundingCircle spawn( 0.0f, 0.0f, spawn_clearance );
|
||||
|
||||
if( m_bounds->m_type == CBoundingObject::BOUND_OABB )
|
||||
{
|
||||
CBoundingBox* oabb = (CBoundingBox*)m_bounds;
|
||||
|
||||
// Pick a start point
|
||||
|
||||
int edge = rand() & 3; int point;
|
||||
|
||||
double max_w = oabb->m_w + spawn_clearance + 1.0;
|
||||
double max_h = oabb->m_h + spawn_clearance + 1.0;
|
||||
int w_count = (int)( max_w * 2 );
|
||||
int h_count = (int)( max_h * 2 );
|
||||
|
||||
CVector2D w_step = oabb->m_v * (float)( max_w / w_count );
|
||||
CVector2D h_step = oabb->m_u * (float)( max_h / h_count );
|
||||
CVector2D pos( m_position );
|
||||
if( edge & 1 )
|
||||
{
|
||||
point = rand() % ( 2 * h_count ) - h_count;
|
||||
pos += ( oabb->m_v * (float)max_w + h_step * (float)point ) * ( ( edge & 2 ) ? -1.0f : 1.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
point = rand() % ( 2 * w_count ) - w_count;
|
||||
pos += ( oabb->m_u * (float)max_h + w_step * (float)point ) * ( ( edge & 2 ) ? -1.0f : 1.0f );
|
||||
}
|
||||
|
||||
int start_edge = edge; int start_point = point;
|
||||
|
||||
spawn.m_pos = pos;
|
||||
|
||||
// Then step around the edge (clockwise) until a free space is found, or
|
||||
// we've gone all the way around.
|
||||
while( getCollisionObject( &spawn ) )
|
||||
{
|
||||
switch( edge )
|
||||
{
|
||||
case 0:
|
||||
point++; pos += w_step;
|
||||
if( point >= w_count )
|
||||
{
|
||||
edge = 1;
|
||||
point = -h_count;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
point++; pos -= h_step;
|
||||
if( point >= h_count )
|
||||
{
|
||||
edge = 2;
|
||||
point = w_count;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
point--; pos -= w_step;
|
||||
if( point <= -w_count )
|
||||
{
|
||||
edge = 3;
|
||||
point = h_count;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
point--; pos += h_step;
|
||||
if( point <= -h_count )
|
||||
{
|
||||
edge = 0;
|
||||
point = -w_count;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if( ( point == start_point ) && ( edge == start_edge ) )
|
||||
return( JSVAL_NULL );
|
||||
spawn.m_pos = pos;
|
||||
}
|
||||
CVector3D rval( pos.x, g_Game->GetWorld()->GetTerrain()->getExactGroundLevel( pos.x, pos.y ), pos.y );
|
||||
return( ToJSVal( rval ) );
|
||||
}
|
||||
else if( m_bounds->m_type == CBoundingObject::BOUND_CIRCLE )
|
||||
{
|
||||
float ang;
|
||||
ang = (float)( rand() & 0x7fff ) / (float)0x4000; /* 0...2 */
|
||||
ang *= PI;
|
||||
float radius = m_bounds->m_radius + 1.0f + spawn_clearance;
|
||||
float d_ang = spawn_clearance / ( 2.0f * radius );
|
||||
float ang_end = ang + 2.0f * PI;
|
||||
float x, y;
|
||||
for( ; ang < ang_end; ang += d_ang )
|
||||
{
|
||||
x = m_position.X + radius * cos( ang );
|
||||
y = m_position.Z + radius * sin( ang );
|
||||
spawn.setPosition( x, y );
|
||||
if( !getCollisionObject( &spawn ) )
|
||||
break;
|
||||
}
|
||||
if( ang < ang_end )
|
||||
{
|
||||
// Found a satisfactory position...
|
||||
CVector3D pos( x, 0, y );
|
||||
pos.Y = g_Game->GetWorld()->GetTerrain()->getExactGroundLevel( x, y );
|
||||
return( ToJSVal( pos ) );
|
||||
}
|
||||
else
|
||||
return( JSVAL_NULL );
|
||||
}
|
||||
return( JSVAL_NULL );
|
||||
}
|
||||
|
@ -43,7 +43,7 @@
|
||||
#include "EntityMessage.h"
|
||||
#include "EventHandlers.h"
|
||||
#include "ScriptObject.h"
|
||||
|
||||
#include "ObjectEntry.h"
|
||||
#include "EntitySupport.h"
|
||||
|
||||
class CBaseEntity;
|
||||
@ -124,8 +124,15 @@ private:
|
||||
CEntity( CBaseEntity* base, CVector3D position, float orientation );
|
||||
|
||||
/*EGotoSituation*/ uint processGotoHelper( CEntityOrder* current, size_t timestep_milli, HEntity& collide );
|
||||
|
||||
bool processContactAction( CEntityOrder* current, size_t timestep_millis, int transition, float range );
|
||||
bool processContactActionNoPathing( CEntityOrder* current, size_t timestep_millis, CSkeletonAnim* animation, CScriptEvent* contactEvent, float range, float minRange );
|
||||
|
||||
bool processAttackMelee( CEntityOrder* current, size_t timestep_milli );
|
||||
bool processAttackMeleeNoPathing( CEntityOrder* current, size_t timestep_milli );
|
||||
bool processGather( CEntityOrder* current, size_t timestep_milli );
|
||||
bool processGatherNoPathing( CEntityOrder* current, size_t timestep_milli );
|
||||
|
||||
bool processGotoNoPathing( CEntityOrder* current, size_t timestep_milli );
|
||||
bool processGoto( CEntityOrder* current, size_t timestep_milli );
|
||||
bool processPatrol( CEntityOrder* current, size_t timestep_milli );
|
||||
@ -204,6 +211,7 @@ public:
|
||||
}
|
||||
bool Damage( JSContext* cx, uintN argc, jsval* argv );
|
||||
bool Kill( JSContext* cx, uintN argc, jsval* argv );
|
||||
jsval GetSpawnPoint( JSContext* cx, uintN argc, jsval* argv );
|
||||
bool IsIdle( JSContext* cx, uintN argc, jsval* argv )
|
||||
{
|
||||
return( m_orderQueue.empty() );
|
||||
|
@ -58,6 +58,8 @@ public:
|
||||
ORDER_PATROL,
|
||||
ORDER_ATTACK_MELEE,
|
||||
ORDER_ATTACK_MELEE_NOPATHING,
|
||||
ORDER_GATHER,
|
||||
ORDER_GATHER_NOPATHING,
|
||||
ORDER_PATH_END_MARKER,
|
||||
ORDER_LAST
|
||||
} m_type;
|
||||
|
@ -268,7 +268,8 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, size_t timestep_milli
|
||||
}
|
||||
}
|
||||
|
||||
bool CEntity::processAttackMelee( CEntityOrder* current, size_t timestep_millis )
|
||||
// Handles processing common to (at the moment) gather and melee attack actions
|
||||
bool CEntity::processContactAction( CEntityOrder* current, size_t timestep_millis, int transition, float range )
|
||||
{
|
||||
m_orderQueue.pop_front();
|
||||
|
||||
@ -279,7 +280,7 @@ bool CEntity::processAttackMelee( CEntityOrder* current, size_t timestep_millis
|
||||
|
||||
if( ( current->m_data[0].location - m_position ).length() < m_meleeRange )
|
||||
{
|
||||
current->m_type = CEntityOrder::ORDER_ATTACK_MELEE_NOPATHING;
|
||||
(int&)current->m_type = transition;
|
||||
return( true );
|
||||
}
|
||||
|
||||
@ -292,14 +293,13 @@ bool CEntity::processAttackMelee( CEntityOrder* current, size_t timestep_millis
|
||||
|
||||
// The pathfinder will push its result back into this unit's queue.
|
||||
|
||||
g_Pathfinder.requestMeleeAttackPath( me, current->m_data[0].entity );
|
||||
g_Pathfinder.requestContactPath( me, current->m_data[0].entity, transition );
|
||||
|
||||
return( true );
|
||||
}
|
||||
|
||||
bool CEntity::processAttackMeleeNoPathing( CEntityOrder* current, size_t timestep_millis )
|
||||
bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t timestep_millis, CSkeletonAnim* animation, CScriptEvent* contactEvent, float range, float minRange = 0.0f )
|
||||
{
|
||||
// Target's dead? 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 )
|
||||
{
|
||||
m_orderQueue.pop_front();
|
||||
@ -309,7 +309,7 @@ bool CEntity::processAttackMeleeNoPathing( CEntityOrder* current, size_t timeste
|
||||
if( m_actor )
|
||||
{
|
||||
// Still playing attack animation? Suspend processing.
|
||||
if( m_actor->GetModel()->GetAnimation() == m_actor->GetObject()->m_MeleeAnim )
|
||||
if( m_actor->GetModel()->GetAnimation() == animation )
|
||||
return( false );
|
||||
|
||||
// Just transitioned? No animation? (=> melee just finished) Play walk.
|
||||
@ -319,13 +319,16 @@ bool CEntity::processAttackMeleeNoPathing( CEntityOrder* current, size_t timeste
|
||||
|
||||
CVector2D delta = current->m_data[0].entity->m_position - m_position;
|
||||
|
||||
float adjRange = m_meleeRange + m_bounds->m_radius + current->m_data[0].entity->m_bounds->m_radius;
|
||||
float adjMinRange = m_meleeRangeMin + m_bounds->m_radius + current->m_data[0].entity->m_bounds->m_radius;
|
||||
float adjRange = range + m_bounds->m_radius + current->m_data[0].entity->m_bounds->m_radius;
|
||||
|
||||
if( delta.within( adjMinRange ) )
|
||||
if( minRange > 0.0f )
|
||||
{
|
||||
// Too close... do nothing.
|
||||
return( false );
|
||||
float adjMinRange = m_meleeRangeMin + m_bounds->m_radius + current->m_data[0].entity->m_bounds->m_radius;
|
||||
if( delta.within( adjMinRange ) )
|
||||
{
|
||||
// Too close... do nothing.
|
||||
return( false );
|
||||
}
|
||||
}
|
||||
|
||||
if( !delta.within( adjRange ) )
|
||||
@ -393,17 +396,32 @@ bool CEntity::processAttackMeleeNoPathing( CEntityOrder* current, size_t timeste
|
||||
m_ahead = delta.normalize();
|
||||
}
|
||||
|
||||
// Now we've got this far:
|
||||
// Pointy end goes into the other man...
|
||||
|
||||
CEventAttack AttackEvent( current->m_data[0].entity );
|
||||
|
||||
if( DispatchEvent( &AttackEvent ) && m_actor )
|
||||
m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_MeleeAnim, true );
|
||||
if( DispatchEvent( contactEvent ) && m_actor )
|
||||
m_actor->GetModel()->SetAnimation( animation, true );
|
||||
|
||||
return( false );
|
||||
}
|
||||
|
||||
bool CEntity::processAttackMelee( CEntityOrder* current, size_t timestep_millis )
|
||||
{
|
||||
return( processContactAction( current, timestep_millis, CEntityOrder::ORDER_ATTACK_MELEE_NOPATHING, 0.5 ) );
|
||||
}
|
||||
bool CEntity::processAttackMeleeNoPathing( CEntityOrder* current, size_t timestep_milli )
|
||||
{
|
||||
CEventAttack evt( current->m_data[0].entity );
|
||||
return( processContactActionNoPathing( current, timestep_milli, m_actor ? m_actor->GetObject()->m_MeleeAnim : NULL, &evt, m_meleeRange, m_meleeRangeMin ) );
|
||||
}
|
||||
bool CEntity::processGather( CEntityOrder* current, size_t timestep_millis )
|
||||
{
|
||||
return( processContactAction( current, timestep_millis, CEntityOrder::ORDER_GATHER_NOPATHING, 0.5 ) );
|
||||
}
|
||||
|
||||
bool CEntity::processGatherNoPathing( CEntityOrder* current, size_t timestep_millis )
|
||||
{
|
||||
CEventGather evt( current->m_data[0].entity );
|
||||
return( processContactActionNoPathing( current, timestep_millis, m_actor ? m_actor->GetObject()->m_GatherAnim : NULL, &evt, 5.0, 0.0 ) );
|
||||
}
|
||||
|
||||
bool CEntity::processGoto( CEntityOrder* current, size_t timestep_millis )
|
||||
{
|
||||
float timestep=timestep_millis/1000.0f;
|
||||
|
@ -8,6 +8,12 @@ CEventAttack::CEventAttack( CEntity* target ) : CScriptEvent( L"attack", true, E
|
||||
AddProperty( L"target", &m_target );
|
||||
}
|
||||
|
||||
CEventGather::CEventGather( CEntity* target ) : CScriptEvent( L"gather", true, EVENT_GATHER )
|
||||
{
|
||||
m_target = target;
|
||||
AddProperty( L"target", &m_target );
|
||||
}
|
||||
|
||||
CEventDamage::CEventDamage( CEntity* inflictor, CDamageType* damage ) : CScriptEvent( L"takesDamage", true, EVENT_DAMAGE )
|
||||
{
|
||||
m_inflictor = inflictor;
|
||||
|
@ -15,6 +15,7 @@ enum EEventType
|
||||
EVENT_INITIALIZE,
|
||||
EVENT_TICK,
|
||||
EVENT_ATTACK,
|
||||
EVENT_GATHER,
|
||||
EVENT_DAMAGE,
|
||||
EVENT_TARGET_CHANGED,
|
||||
EVENT_PREPARE_ORDER,
|
||||
@ -27,6 +28,7 @@ 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 */
|
||||
@ -52,6 +54,13 @@ public:
|
||||
CEventAttack( CEntity* target );
|
||||
};
|
||||
|
||||
class CEventGather : public CScriptEvent
|
||||
{
|
||||
CEntity* m_target;
|
||||
public:
|
||||
CEventGather( CEntity* target );
|
||||
};
|
||||
|
||||
class CEventDamage : public CScriptEvent
|
||||
{
|
||||
CEntity* m_inflictor;
|
||||
|
@ -16,7 +16,7 @@ void CPathfindEngine::requestPath( HEntity entity, const CVector2D& destination
|
||||
pathSparse( entity, destination );
|
||||
}
|
||||
|
||||
void CPathfindEngine::requestMeleeAttackPath( HEntity entity, HEntity target )
|
||||
void CPathfindEngine::requestContactPath( HEntity entity, HEntity target, int transition )
|
||||
{
|
||||
pathSparse( entity, target->m_position );
|
||||
// For attack orders, do some additional postprocessing (replace goto/nopathing
|
||||
@ -28,7 +28,7 @@ void CPathfindEngine::requestMeleeAttackPath( HEntity entity, HEntity target )
|
||||
break;
|
||||
if( it->m_type == CEntityOrder::ORDER_GOTO_NOPATHING )
|
||||
{
|
||||
it->m_type = CEntityOrder::ORDER_ATTACK_MELEE_NOPATHING;
|
||||
(int&)it->m_type = transition;
|
||||
it->m_data[0].entity = target;
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ class CPathfindEngine : public Singleton<CPathfindEngine>
|
||||
public:
|
||||
CPathfindEngine();
|
||||
void requestPath( HEntity entity, const CVector2D& destination );
|
||||
void requestMeleeAttackPath( HEntity entity, HEntity target );
|
||||
void requestContactPath( HEntity entity, HEntity target, int transition );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -47,10 +47,16 @@ void CScheduler::pushInterval( size_t first, size_t interval, JSFunction* functi
|
||||
timeFunction.push( SDispatchObjectFunction( function, simulationTime + first, operateOn, interval ) );
|
||||
}
|
||||
|
||||
void CScheduler::pushProgressTimer( CJSProgressTimer* progressTimer )
|
||||
{
|
||||
progressTimers.push_back( progressTimer );
|
||||
}
|
||||
|
||||
void CScheduler::update(size_t simElapsed)
|
||||
{
|
||||
simulationTime += simElapsed;
|
||||
frameCount++;
|
||||
jsval rval;
|
||||
|
||||
while( !timeScript.empty() )
|
||||
{
|
||||
@ -77,7 +83,6 @@ void CScheduler::update(size_t simElapsed)
|
||||
if( top.deliveryTime > simulationTime )
|
||||
break;
|
||||
timeFunction.pop();
|
||||
jsval rval;
|
||||
m_abortInterval = false;
|
||||
|
||||
JS_CallFunction( g_ScriptingHost.getContext(), top.operateOn, top.function, 0, NULL, &rval );
|
||||
@ -91,9 +96,66 @@ void CScheduler::update(size_t simElapsed)
|
||||
if( top.deliveryTime > frameCount )
|
||||
break;
|
||||
frameFunction.pop();
|
||||
jsval rval;
|
||||
|
||||
JS_CallFunction( g_ScriptingHost.getContext(), top.operateOn, top.function, 0, NULL, &rval );
|
||||
|
||||
}
|
||||
|
||||
std::list<CJSProgressTimer*>::iterator it;
|
||||
for( it = progressTimers.begin(); it != progressTimers.end(); it++ )
|
||||
{
|
||||
(*it)->m_Current += (*it)->m_Increment * simElapsed;
|
||||
if( (*it)->m_Current >= (*it)->m_Max )
|
||||
{
|
||||
(*it)->m_Current = (*it)->m_Max;
|
||||
if( (*it)->m_Callback )
|
||||
JS_CallFunction( g_ScriptingHost.GetContext(), (*it)->m_OperateOn, (*it)->m_Callback, 0, NULL, &rval );
|
||||
it = progressTimers.erase( it );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CJSProgressTimer::CJSProgressTimer( double Max, double Increment, JSFunction* Callback, JSObject* OperateOn )
|
||||
{
|
||||
m_Max = Max; m_Increment = Increment; m_Callback = Callback; m_OperateOn = OperateOn; m_Current = 0.0;
|
||||
}
|
||||
|
||||
void CJSProgressTimer::ScriptingInit()
|
||||
{
|
||||
AddClassProperty( L"max", &CJSProgressTimer::m_Max );
|
||||
AddClassProperty( L"current", &CJSProgressTimer::m_Current );
|
||||
AddClassProperty( L"increment", &CJSProgressTimer::m_Increment );
|
||||
|
||||
CJSObject<CJSProgressTimer>::ScriptingInit( "ProgressTimer", Construct, 2 );
|
||||
}
|
||||
|
||||
JSBool CJSProgressTimer::Construct( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
assert( argc >= 2 );
|
||||
double max = ToPrimitive<double>( argv[0] );
|
||||
double increment = ToPrimitive<double>( argv[1] );
|
||||
JSFunction* callback_fn = NULL;
|
||||
JSObject* scope_obj = NULL;
|
||||
if( argc >= 3 )
|
||||
{
|
||||
callback_fn = JS_ValueToFunction( cx, argv[2] );
|
||||
if( ( argc >= 4 ) && JSVAL_IS_OBJECT( argv[3] ) )
|
||||
{
|
||||
scope_obj = JSVAL_TO_OBJECT( argv[3] );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Attempt to determine object to operate on automatically.
|
||||
|
||||
// SpiderMonkey docs say the 'this' parameter of the calling
|
||||
// function is in argv[-2]. Do I believe them? One way to find out.
|
||||
scope_obj = JSVAL_TO_OBJECT( argv[-2] );
|
||||
}
|
||||
}
|
||||
CJSProgressTimer* timer = new CJSProgressTimer( max, increment, callback_fn, scope_obj );
|
||||
timer->m_EngineOwned = false;
|
||||
|
||||
g_Scheduler.pushProgressTimer( timer );
|
||||
|
||||
*rval = OBJECT_TO_JSVAL( timer->GetScript() );
|
||||
return( JS_TRUE );
|
||||
}
|
@ -13,7 +13,9 @@
|
||||
#include "EntityHandles.h"
|
||||
#include "Singleton.h"
|
||||
#include "CStr.h"
|
||||
#include "scripting/ScriptingHost.h"
|
||||
#include "scripting/ScriptableObject.h"
|
||||
|
||||
class CJSProgressTimer;
|
||||
|
||||
// Message, destination and delivery time information.
|
||||
struct SDispatchObject
|
||||
@ -30,19 +32,6 @@ struct SDispatchObject
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
struct SDispatchObjectMessage : public SDispatchObject
|
||||
{
|
||||
HEntity destination;
|
||||
const CMessage* message;
|
||||
inline SDispatchObjectMessage( const HEntity& _destination, size_t _deliveryTime, const CMessage* _message )
|
||||
: SDispatchObject( _deliveryTime ), destination( _destination ), message( _message ) {}
|
||||
inline SDispatchObjectMessage( const HEntity& _destination, size_t _deliveryTime, const CMessage* _message, const size_t recurrence )
|
||||
: SDispatchObject( _deliveryTime, recurrence ), destination( _destination ), message( _message ) {}
|
||||
|
||||
};
|
||||
*/
|
||||
|
||||
struct SDispatchObjectScript : public SDispatchObject
|
||||
{
|
||||
CStrW script;
|
||||
@ -65,28 +54,35 @@ struct SDispatchObjectFunction : public SDispatchObject
|
||||
|
||||
struct CScheduler : public Singleton<CScheduler>
|
||||
{
|
||||
// std::priority_queue<SDispatchObjectMessage> timeMessage, frameMessage;
|
||||
std::priority_queue<SDispatchObjectScript> timeScript, frameScript;
|
||||
std::priority_queue<SDispatchObjectFunction> timeFunction, frameFunction;
|
||||
|
||||
std::list<CJSProgressTimer*> progressTimers;
|
||||
bool m_abortInterval;
|
||||
|
||||
/*
|
||||
void pushTime( size_t delay, const HEntity& destination, const CMessage* message );
|
||||
void pushFrame( size_t delay, const HEntity& destination, const CMessage* message );
|
||||
*/
|
||||
|
||||
void pushTime( size_t delay, const CStrW& fragment, JSObject* operateOn = NULL );
|
||||
void pushFrame( size_t delay, const CStrW& fragment, JSObject* operateOn = NULL );
|
||||
void pushInterval( size_t first, size_t interval, const CStrW& fragment, JSObject* operateOn = NULL );
|
||||
void pushTime( size_t delay, JSFunction* function, JSObject* operateOn = NULL );
|
||||
void pushFrame( size_t delay, JSFunction* function, JSObject* operateOn = NULL );
|
||||
void pushInterval( size_t first, size_t interval, JSFunction* function, JSObject* operateOn = NULL );
|
||||
void pushProgressTimer( CJSProgressTimer* progressTimer );
|
||||
void update(size_t elapsedSimulationTime);
|
||||
};
|
||||
|
||||
#define g_Scheduler CScheduler::GetSingleton()
|
||||
|
||||
class CJSProgressTimer : public CJSObject<CJSProgressTimer>
|
||||
{
|
||||
friend CScheduler;
|
||||
double m_Max, m_Current, m_Increment;
|
||||
JSFunction* m_Callback;
|
||||
JSObject* m_OperateOn;
|
||||
CJSProgressTimer( double Max, double Increment, JSFunction* Callback, JSObject* OperateOn );
|
||||
static JSBool Construct( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval );
|
||||
public:
|
||||
static void ScriptingInit();
|
||||
};
|
||||
|
||||
extern const int ORDER_DELAY;
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user