From 86dc3512058f9d47eb10ad1902214acfa3913d2e Mon Sep 17 00:00:00 2001 From: MarkT Date: Tue, 10 May 2005 07:13:25 +0000 Subject: [PATCH] Projectile code and updates to some actors that can use it (celt_ijv and hele_iar) This was SVN commit r2266. --- .../official/art/actors/units/celt_ijv_a.xml | 5 +- .../official/art/actors/units/celt_ijv_b.xml | 5 +- .../official/art/actors/units/celt_ijv_e.xml | 5 +- .../official/art/actors/units/hele_iar_a.xml | 4 +- .../official/art/actors/units/hele_iar_b.xml | 4 +- .../official/art/actors/units/hele_iar_e.xml | 4 +- .../entities/gaia/template_gaia_fauna.xml | 2 +- .../entities/gaia/template_gaia_flora.xml | 2 +- .../entities/gaia/template_gaia_geo.xml | 2 +- .../entities/gaia/template_gaia_special.xml | 2 +- .../official/entities/gaia/template_tree.xml | 2 +- .../template_structure_norm_civic_cc.xml | 2 +- .../template_structure_norm_civic_hc.xml | 2 +- .../template_structure_norm_civic_ho.xml | 2 +- .../template_structure_norm_civic_tf.xml | 2 +- .../template_structure_norm_civic_wc.xml | 2 +- .../template_structure_norm_civic_wg.xml | 2 +- .../template_structure_norm_civic_wt.xml | 2 +- .../template_structure_norm_economic_fc.xml | 2 +- .../template_structure_norm_economic_rc.xml | 2 +- .../template_structure_norm_economic_tc.xml | 2 +- .../template_structure_norm_military_ff.xml | 2 +- .../template_structure_norm_military_mc.xml | 2 +- .../template_structure_norm_military_pc.xml | 2 +- .../template_structure_norm_special_sb.xml | 2 +- ...emplate_structure_resource_economic_fc.xml | 2 +- ...emplate_structure_resource_economic_fv.xml | 2 +- .../entities/template_entity_script.js | 73 +++++ .../official/entities/units/template_unit.xml | 2 +- .../entities/units/template_unit_cavalry.xml | 2 +- .../units/template_unit_cavalry_ranged.xml | 8 + .../units/template_unit_infantry_ranged.xml | 8 + .../mods/official/gui/test/2_mainmenu.xml | 2 +- .../official/maps/scenarios/gathertest2.pmp | 3 + .../official/maps/scenarios/gathertest2.xml | 3 + .../data/profiles/default/settings/history | 50 ++++ .../data/profiles/default/settings/user.cfg | 3 + source/graphics/GameView.cpp | 13 +- source/graphics/GameView.h | 3 +- source/graphics/Model.cpp | 5 +- source/graphics/ObjectEntry.cpp | 40 ++- source/graphics/ObjectEntry.h | 5 + source/graphics/Unit.cpp | 25 ++ source/graphics/Unit.h | 4 + source/graphics/UnitManager.cpp | 6 +- source/graphics/UnitManager.h | 1 + source/main.cpp | 13 +- source/ps/CConsole.cpp | 48 ++++ source/ps/CConsole.h | 10 +- source/ps/World.cpp | 1 + source/ps/World.h | 9 +- source/scripting/DOMEvent.cpp | 2 + source/scripting/EventTypes.h | 3 + source/scripting/JSConversions.cpp | 10 +- source/scripting/JSConversions.h | 9 +- source/scripting/ScriptableObject.h | 6 +- source/simulation/BaseEntity.cpp | 14 +- source/simulation/BoundingObjects.cpp | 82 +++--- source/simulation/BoundingObjects.h | 18 +- source/simulation/Collision.cpp | 143 +++++++++- source/simulation/Collision.h | 9 +- source/simulation/Entity.cpp | 36 +-- source/simulation/Entity.h | 7 +- source/simulation/EntityManager.cpp | 9 + source/simulation/EntityManager.h | 1 + source/simulation/EntityStateProcessing.cpp | 49 +++- source/simulation/Projectile.cpp | 266 ++++++++++++++++++ source/simulation/Projectile.h | 107 +++++++ source/simulation/ScriptObject.cpp | 7 + source/simulation/ScriptObject.h | 4 + source/simulation/Simulation.cpp | 23 +- 71 files changed, 1057 insertions(+), 154 deletions(-) create mode 100644 binaries/data/mods/official/maps/scenarios/gathertest2.pmp create mode 100644 binaries/data/mods/official/maps/scenarios/gathertest2.xml create mode 100644 binaries/data/profiles/default/settings/history create mode 100644 binaries/data/profiles/default/settings/user.cfg create mode 100644 source/simulation/Projectile.cpp create mode 100644 source/simulation/Projectile.h diff --git a/binaries/data/mods/official/art/actors/units/celt_ijv_a.xml b/binaries/data/mods/official/art/actors/units/celt_ijv_a.xml index ea17acbea7..2f779eb669 100644 --- a/binaries/data/mods/official/art/actors/units/celt_ijv_a.xml +++ b/binaries/data/mods/official/art/actors/units/celt_ijv_a.xml @@ -12,13 +12,14 @@ - + skeletal/m_pants_b.pmd - + + diff --git a/binaries/data/mods/official/art/actors/units/celt_ijv_b.xml b/binaries/data/mods/official/art/actors/units/celt_ijv_b.xml index 8344bd5cc3..46dc825fab 100644 --- a/binaries/data/mods/official/art/actors/units/celt_ijv_b.xml +++ b/binaries/data/mods/official/art/actors/units/celt_ijv_b.xml @@ -12,13 +12,14 @@ - + skeletal/m_pants_b.pmd - + + skeletal/celt_ijv_b_01.dds diff --git a/binaries/data/mods/official/art/actors/units/celt_ijv_e.xml b/binaries/data/mods/official/art/actors/units/celt_ijv_e.xml index 7ed3835f55..13ebf4679d 100644 --- a/binaries/data/mods/official/art/actors/units/celt_ijv_e.xml +++ b/binaries/data/mods/official/art/actors/units/celt_ijv_e.xml @@ -12,14 +12,15 @@ - + skeletal/m_tights.pmd - + + skeletal/celt_ijv_e_01.dds diff --git a/binaries/data/mods/official/art/actors/units/hele_iar_a.xml b/binaries/data/mods/official/art/actors/units/hele_iar_a.xml index c3c95bf758..1511c77c36 100644 --- a/binaries/data/mods/official/art/actors/units/hele_iar_a.xml +++ b/binaries/data/mods/official/art/actors/units/hele_iar_a.xml @@ -12,7 +12,7 @@ - + skeletal/m_tunic_b.pmd @@ -20,6 +20,8 @@ + + skeletal/hele_isp_b.dds diff --git a/binaries/data/mods/official/art/actors/units/hele_iar_b.xml b/binaries/data/mods/official/art/actors/units/hele_iar_b.xml index bd68f4fefb..b8af29fdd6 100644 --- a/binaries/data/mods/official/art/actors/units/hele_iar_b.xml +++ b/binaries/data/mods/official/art/actors/units/hele_iar_b.xml @@ -12,7 +12,7 @@ - + skeletal/m_tunic_b.pmd @@ -20,6 +20,8 @@ + + skeletal/hele_iar_b.dds diff --git a/binaries/data/mods/official/art/actors/units/hele_iar_e.xml b/binaries/data/mods/official/art/actors/units/hele_iar_e.xml index b748d0b6e3..a3da8a05e5 100644 --- a/binaries/data/mods/official/art/actors/units/hele_iar_e.xml +++ b/binaries/data/mods/official/art/actors/units/hele_iar_e.xml @@ -12,7 +12,7 @@ - + skeletal/m_tunic_b.pmd @@ -21,6 +21,8 @@ + + skeletal/plac_hele_e.dds diff --git a/binaries/data/mods/official/entities/gaia/template_gaia_fauna.xml b/binaries/data/mods/official/entities/gaia/template_gaia_fauna.xml index 7e22dd4d04..0d5651290e 100755 --- a/binaries/data/mods/official/entities/gaia/template_gaia_fauna.xml +++ b/binaries/data/mods/official/entities/gaia/template_gaia_fauna.xml @@ -21,5 +21,5 @@ subtype="meat" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/gaia/template_gaia_flora.xml b/binaries/data/mods/official/entities/gaia/template_gaia_flora.xml index 0b28594f2e..dd496e4f3c 100755 --- a/binaries/data/mods/official/entities/gaia/template_gaia_flora.xml +++ b/binaries/data/mods/official/entities/gaia/template_gaia_flora.xml @@ -9,5 +9,5 @@ classes="gaia_flora" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/gaia/template_gaia_geo.xml b/binaries/data/mods/official/entities/gaia/template_gaia_geo.xml index ef4004f402..15a61cf473 100755 --- a/binaries/data/mods/official/entities/gaia/template_gaia_geo.xml +++ b/binaries/data/mods/official/entities/gaia/template_gaia_geo.xml @@ -9,5 +9,5 @@ classes="gaia_geo" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/gaia/template_gaia_special.xml b/binaries/data/mods/official/entities/gaia/template_gaia_special.xml index 05900383f8..10a79601b2 100755 --- a/binaries/data/mods/official/entities/gaia/template_gaia_special.xml +++ b/binaries/data/mods/official/entities/gaia/template_gaia_special.xml @@ -13,5 +13,5 @@ type="Special" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/gaia/template_tree.xml b/binaries/data/mods/official/entities/gaia/template_tree.xml index 19b3b98819..a584347066 100755 --- a/binaries/data/mods/official/entities/gaia/template_tree.xml +++ b/binaries/data/mods/official/entities/gaia/template_tree.xml @@ -16,5 +16,5 @@ - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_norm_civic_cc.xml b/binaries/data/mods/official/entities/structures/template_structure_norm_civic_cc.xml index 1df4b0e8b8..cdeaaa0140 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_norm_civic_cc.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_norm_civic_cc.xml @@ -31,5 +31,5 @@ construct="1" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_norm_civic_hc.xml b/binaries/data/mods/official/entities/structures/template_structure_norm_civic_hc.xml index c5611cefb7..635fc63095 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_norm_civic_hc.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_norm_civic_hc.xml @@ -19,5 +19,5 @@ add="5" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_norm_civic_ho.xml b/binaries/data/mods/official/entities/structures/template_structure_norm_civic_ho.xml index 870b9fe138..a834c6fb7f 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_norm_civic_ho.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_norm_civic_ho.xml @@ -19,5 +19,5 @@ add="5" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_norm_civic_tf.xml b/binaries/data/mods/official/entities/structures/template_structure_norm_civic_tf.xml index 600be07806..7c169f4d1a 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_norm_civic_tf.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_norm_civic_tf.xml @@ -20,5 +20,5 @@ max="60" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_norm_civic_wc.xml b/binaries/data/mods/official/entities/structures/template_structure_norm_civic_wc.xml index 481d9265c4..d00e3aa395 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_norm_civic_wc.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_norm_civic_wc.xml @@ -16,5 +16,5 @@ hitpoints="500" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_norm_civic_wg.xml b/binaries/data/mods/official/entities/structures/template_structure_norm_civic_wg.xml index 92dc5d5e89..0739029062 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_norm_civic_wg.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_norm_civic_wg.xml @@ -16,5 +16,5 @@ hitpoints="100" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_norm_civic_wt.xml b/binaries/data/mods/official/entities/structures/template_structure_norm_civic_wt.xml index 33e19c6269..52f60a5a2a 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_norm_civic_wt.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_norm_civic_wt.xml @@ -20,5 +20,5 @@ max="80" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_norm_economic_fc.xml b/binaries/data/mods/official/entities/structures/template_structure_norm_economic_fc.xml index ebe0440c52..40be3990c0 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_norm_economic_fc.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_norm_economic_fc.xml @@ -20,5 +20,5 @@ max="50" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_norm_economic_rc.xml b/binaries/data/mods/official/entities/structures/template_structure_norm_economic_rc.xml index 18c8984e60..b6378f3211 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_norm_economic_rc.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_norm_economic_rc.xml @@ -16,5 +16,5 @@ hitpoints="50" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_norm_economic_tc.xml b/binaries/data/mods/official/entities/structures/template_structure_norm_economic_tc.xml index 3e7b354c95..f4eaa0f3f9 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_norm_economic_tc.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_norm_economic_tc.xml @@ -23,5 +23,5 @@ add="10" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_norm_military_ff.xml b/binaries/data/mods/official/entities/structures/template_structure_norm_military_ff.xml index 56661e1472..28cc75f7ec 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_norm_military_ff.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_norm_military_ff.xml @@ -23,5 +23,5 @@ add="20" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_norm_military_mc.xml b/binaries/data/mods/official/entities/structures/template_structure_norm_military_mc.xml index d84633c69f..a2d5fae8c8 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_norm_military_mc.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_norm_military_mc.xml @@ -16,5 +16,5 @@ hitpoints="600" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_norm_military_pc.xml b/binaries/data/mods/official/entities/structures/template_structure_norm_military_pc.xml index 9d9028b3a4..5f7cc1df26 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_norm_military_pc.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_norm_military_pc.xml @@ -19,5 +19,5 @@ add="15" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_norm_special_sb.xml b/binaries/data/mods/official/entities/structures/template_structure_norm_special_sb.xml index bc2c98c7ed..64d3d2b427 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_norm_special_sb.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_norm_special_sb.xml @@ -12,5 +12,5 @@ classes="structure_city" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_resource_economic_fc.xml b/binaries/data/mods/official/entities/structures/template_structure_resource_economic_fc.xml index ca221f21ed..df5b8dd4cd 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_resource_economic_fc.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_resource_economic_fc.xml @@ -30,5 +30,5 @@ los="0" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure_resource_economic_fv.xml b/binaries/data/mods/official/entities/structures/template_structure_resource_economic_fv.xml index 1f3e87388e..919e1c3013 100755 --- a/binaries/data/mods/official/entities/structures/template_structure_resource_economic_fv.xml +++ b/binaries/data/mods/official/entities/structures/template_structure_resource_economic_fv.xml @@ -30,5 +30,5 @@ los="0" /> - + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/template_entity_script.js b/binaries/data/mods/official/entities/template_entity_script.js index 6b8054bd5c..4d18ce7fa0 100644 --- a/binaries/data/mods/official/entities/template_entity_script.js +++ b/binaries/data/mods/official/entities/template_entity_script.js @@ -13,6 +13,79 @@ function entity_event_attack( evt ) // ==================================================================== +function entity_event_attack_ranged( evt ) +{ + // Create a projectile from us, to the target, that will do some damage when it hits them. + 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); + + // The parameters for Projectile are: + // 1 - The actor to use as the projectile. There are two ways of specifying this: + // the first is by giving an entity. The projectile's actor is found by looking + // in the actor of that entity. This way is usual, and preferred - visual + // information, like the projectile model, should be stored in the actor files. + // The second way is to give a actor/file name string (e.g. "props/weapon/weap_ + // arrow_front.xml"). This is only meant to be used for 'Acts of Gaia' where + // there is no originating entity. Right now, this entity is the one doing the + // firing, so pass this. + // 2 - Where the projectile is coming from. This can be an entity or a Vector3D. + // For now, that's also us. + // 3 - Where the projectile is going to. Again, either a vector (attack ground?) + // or an entity. Let's shoot at our target, lest we get people terribly confused. + // 4 - How fast the projectile should go. To keep things clear, we'll set it to + // just a bit faster than the average cavalry. + // 5 - Who fired it? Erm... yep, us again. + // 6 - The function you'd like to call when it hits an entity. + // There's also a seventh parameter, for a function to call when it misses (more + // accurately, when it hits the floor). At the moment, however, the default + // action (do nothing) is what we want. + // Parameters 5, 6, and 7 are all optional. + + projectile = new Projectile( this, this, evt.target, 12.0, this, projectile_event_impact ) + + // We'll attach the damage information to the projectile, just to show you can + // do that like you can with most other objects. Could also do this by making + // the function we pass a closure. + + projectile.damage = dmg; + + // Finally, tell the engine not to send this event to anywhere else - + // in particular, this shouldn't get to the melee event handler, above. + + evt.stopPropagation(); + + console.write( "Fire!" ); +} + +// ==================================================================== + +function projectile_event_impact( evt ) +{ + console.write( "Hit!" ); + evt.impacted.damage( this.damage, evt.originator ); + + // Just so you know - there's no guarantee that evt.impacted is the thing you were + // aiming at. This function gets called when the projectile hits *anything*. + // For example: + + if( evt.impacted.player == evt.originator.player ) + console.write( "Friendly fire!" ); + + // The three properties of the ProjectileImpact event are: + // - impacted, the thing it hit + // - originator, the thing that fired it (the fifth parameter of Projectile's + // constructor) - may be null + // - position, the position the arrow was in the world when it hit. + + // The properties of the ProjectileMiss event (the one that gets sent to the + // handler that was the seventh parameter of the constructor) are similar, + // but it doesn't have 'impacted' - for obvious reasons. +} + +// ==================================================================== + function entity_event_gather( evt ) { if (this.actions.gather[evt.target.traits.supply.type][evt.target.traits.supply.subtype]) diff --git a/binaries/data/mods/official/entities/units/template_unit.xml b/binaries/data/mods/official/entities/units/template_unit.xml index 7226a7cf8e..97fc73b4fc 100755 --- a/binaries/data/mods/official/entities/units/template_unit.xml +++ b/binaries/data/mods/official/entities/units/template_unit.xml @@ -32,7 +32,7 @@ los="2" /> - + - + + + + + + + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_infantry_ranged.xml b/binaries/data/mods/official/entities/units/template_unit_infantry_ranged.xml index af713b72b4..d09d32cf05 100755 --- a/binaries/data/mods/official/entities/units/template_unit_infantry_ranged.xml +++ b/binaries/data/mods/official/entities/units/template_unit_infantry_ranged.xml @@ -10,4 +10,12 @@ classes="unit_ranged" /> + + + + + + \ No newline at end of file diff --git a/binaries/data/mods/official/gui/test/2_mainmenu.xml b/binaries/data/mods/official/gui/test/2_mainmenu.xml index 95b6d85032..8fa87b2fc7 100644 --- a/binaries/data/mods/official/gui/test/2_mainmenu.xml +++ b/binaries/data/mods/official/gui/test/2_mainmenu.xml @@ -398,7 +398,7 @@ - gathertest + gathertest2 diff --git a/binaries/data/mods/official/maps/scenarios/gathertest2.pmp b/binaries/data/mods/official/maps/scenarios/gathertest2.pmp new file mode 100644 index 0000000000..a37730c583 --- /dev/null +++ b/binaries/data/mods/official/maps/scenarios/gathertest2.pmp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1143575ffdca143c02bddf9fea01ce44bcf15308a74901d695b388f240b26941 +size 741044 diff --git a/binaries/data/mods/official/maps/scenarios/gathertest2.xml b/binaries/data/mods/official/maps/scenarios/gathertest2.xml new file mode 100644 index 0000000000..a519f783c2 --- /dev/null +++ b/binaries/data/mods/official/maps/scenarios/gathertest2.xml @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:45d95a45122ab878be9472b468c2a3a87c0e95770cde4418c25fe535e8d9dd1d +size 8201 diff --git a/binaries/data/profiles/default/settings/history b/binaries/data/profiles/default/settings/history new file mode 100644 index 0000000000..d10cff4c7e --- /dev/null +++ b/binaries/data/profiles/default/settings/history @@ -0,0 +1,50 @@ +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 10.5, this.position.z ), target, 12 ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 10.5, this.position.z ), target, 12 ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 10.5, this.position.z ), target, 12 ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 10.5, this.position.z ), target, 12 ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 10.5, this.position.z ), target, 12 ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 10.5, this.position.z ), target, 12 ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 10.5, this.position.z ), target, 12 ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 10.5, this.position.z ), target, 12 ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 10.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 10, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?target = this +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?target = this; +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?new Projectile( "props/weapon/weap_arrow_front.xml", Vector3D( this.position.x, this.position.y + 2.5, this.position.z ), target, 12, this ); +?b +?this.traits.health.curr +?this.traits.health.max +?entities.subset( function() { return( this.traits.health.cur < this.traits.health.max ); } +?entities.subset( function() { return( this.traits.health.cur < this.traits.health.max ); } ); +?entities.subset( function() { return( this.traits.health.curr < this.traits.health.max ); } ); +?selection = entities.subset( function() { return( this.traits.health.curr < this.traits.health.max ); } ); diff --git a/binaries/data/profiles/default/settings/user.cfg b/binaries/data/profiles/default/settings/user.cfg new file mode 100644 index 0000000000..b388d1a42f --- /dev/null +++ b/binaries/data/profiles/default/settings/user.cfg @@ -0,0 +1,3 @@ +; Settings in a profile config are used instead of the equivalent settings in the system.cfg file, +; but note that not some settings are only allowed to be specified in system.cfg, for security reasons. + diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index bc2c5f1c2a..b89e44e09c 100755 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -20,10 +20,10 @@ #include "Profile.h" #include "LoaderThunks.h" - #include "Quaternion.h" #include "Unit.h" #include "Model.h" +#include "Projectile.h" #include "sdl.h" #include "input.h" @@ -129,7 +129,7 @@ void CGameView::Render() PROFILE_END( "render terrain" ); MICROLOG(L"render models"); PROFILE_START( "render models" ); - RenderModels(m_pWorld->GetUnitManager()); + RenderModels(m_pWorld->GetUnitManager(), m_pWorld->GetProjectileManager()); PROFILE_END( "render models" ); } @@ -147,7 +147,7 @@ void CGameView::RenderTerrain(CTerrain *pTerrain) } } -void CGameView::RenderModels(CUnitManager *pUnitMan) +void CGameView::RenderModels(CUnitManager *pUnitMan, CProjectileManager *pProjectileMan) { CFrustum frustum=m_Camera.GetFrustum(); @@ -157,6 +157,13 @@ void CGameView::RenderModels(CUnitManager *pUnitMan) SubmitModelRecursive(units[i]->GetModel()); } } + + const std::vector& projectiles=pProjectileMan->GetProjectiles(); + for (uint i=0;iGetModel()->GetBounds())) { + SubmitModelRecursive(projectiles[i]->GetModel()); + } + } } void CGameView::SubmitModelRecursive(CModel* model) diff --git a/source/graphics/GameView.h b/source/graphics/GameView.h index b926765422..5d261db69c 100755 --- a/source/graphics/GameView.h +++ b/source/graphics/GameView.h @@ -9,6 +9,7 @@ class CGameAttributes; class CWorld; class CTerrain; class CUnitManager; +class CProjectileManager; class CModel; class CGameView @@ -43,7 +44,7 @@ class CGameView // RenderModels: iterate through model list and submit all models in viewing // frustum to the Renderer - void RenderModels(CUnitManager *pUnitMan); + void RenderModels(CUnitManager *pUnitMan, CProjectileManager *pProjectileManager); // SubmitModelRecursive: recurse down given model, submitting it and all its // descendents to the renderer diff --git a/source/graphics/Model.cpp b/source/graphics/Model.cpp index 33c5017ff8..5bbb7cabc6 100755 --- a/source/graphics/Model.cpp +++ b/source/graphics/Model.cpp @@ -213,8 +213,8 @@ CSkeletonAnim* CModel::BuildAnimation(const char* filename,float speed,double ac CSkeletonAnim* anim=new CSkeletonAnim; anim->m_AnimDef=def; anim->m_Speed=speed; - anim->m_ActionPos=(size_t)( actionpos * anim->m_AnimDef->GetDuration() ); - anim->m_ActionPos2=(size_t)( actionpos2 * anim->m_AnimDef->GetDuration() ); + anim->m_ActionPos=(size_t)( actionpos * anim->m_AnimDef->GetDuration() / speed ); + anim->m_ActionPos2=(size_t)( actionpos2 * anim->m_AnimDef->GetDuration() / speed ); anim->m_ObjectBounds.SetEmpty(); InvalidateBounds(); @@ -361,6 +361,7 @@ void CModel::RemoveProp(SPropPoint* point) for (Iter iter=m_Props.begin();iter!=m_Props.end();++iter) { const Prop& prop=*iter; if (prop.m_Point==point) { + delete prop.m_Model; m_Props.erase(iter); return; } diff --git a/source/graphics/ObjectEntry.cpp b/source/graphics/ObjectEntry.cpp index bebbb3bd0d..cc244e19dd 100755 --- a/source/graphics/ObjectEntry.cpp +++ b/source/graphics/ObjectEntry.cpp @@ -30,6 +30,9 @@ CObjectEntry::CObjectEntry(int type, CObjectBase* base) m_MeleeAnim=0; m_GatherAnim=0; m_RangedAnim=0; + m_ProjectileModel=0; + m_AmmunitionPoint=0; + m_AmmunitionModel=0; } CObjectEntry::~CObjectEntry() @@ -189,11 +192,32 @@ bool CObjectEntry::BuildRandomVariant(CObjectBase::variation_key& vars, CObjectB for (size_t p = 0; p < m_Props.size(); p++) { const CObjectBase::Prop& prop = m_Props[p]; - SPropPoint* proppoint = modeldef->FindPropPoint((const char*) prop.m_PropPointName); - if (proppoint) + + CObjectEntry* oe = g_ObjMan.FindObjectVariation(prop.m_ModelName, vars, vars_it); + if (!oe) { - CObjectEntry* oe = g_ObjMan.FindObjectVariation(prop.m_ModelName, vars, vars_it); - if (oe) + LOG(ERROR, LOG_CATEGORY, "Failed to build prop model \"%s\" on actor \"%s\"", (const char*)prop.m_ModelName, (const char*)m_Base->m_ShortName); + continue; + } + + // Pluck out the special attachpoint 'projectile' + if( prop.m_PropPointName == "projectile" ) + { + m_ProjectileModel = oe->m_Model; + } + // Also the other special attachpoint 'loaded-' + else if( ( prop.m_PropPointName.Length() > 7 ) && ( prop.m_PropPointName.Left( 7 ) == "loaded-" ) ) + { + CStr ppn = prop.m_PropPointName.GetSubstring( 7, prop.m_PropPointName.Length() - 7 ); + m_AmmunitionModel = oe->m_Model; + m_AmmunitionPoint = modeldef->FindPropPoint((const char*)ppn ); + if( !m_AmmunitionPoint ) + LOG(ERROR, LOG_CATEGORY, "Failed to find matching prop point called \"%s\" in model \"%s\" on actor \"%s\"", (const char*)ppn, modelfilename, (const char*)prop.m_ModelName); + } + else + { + SPropPoint* proppoint = modeldef->FindPropPoint((const char*) prop.m_PropPointName); + if (proppoint) { CModel* propmodel = oe->m_Model->Clone(); m_Model->AddProp(proppoint, propmodel); @@ -201,13 +225,7 @@ bool CObjectEntry::BuildRandomVariant(CObjectBase::variation_key& vars, CObjectB propmodel->SetAnimation(oe->m_IdleAnim); } else - { - LOG(ERROR, LOG_CATEGORY, "Failed to build prop model \"%s\" on actor \"%s\"", (const char*)prop.m_ModelName, (const char*)m_Base->m_ShortName); - } - } - else - { - LOG(ERROR, LOG_CATEGORY, "Failed to find matching prop point called \"%s\" in model \"%s\" on actor \"%s\"", (const char*)prop.m_PropPointName, modelfilename, (const char*)prop.m_ModelName); + LOG(ERROR, LOG_CATEGORY, "Failed to find matching prop point called \"%s\" in model \"%s\" on actor \"%s\"", (const char*)prop.m_PropPointName, modelfilename, (const char*)prop.m_ModelName); } } diff --git a/source/graphics/ObjectEntry.h b/source/graphics/ObjectEntry.h index dccf5ff8b2..b8a19f6104 100755 --- a/source/graphics/ObjectEntry.h +++ b/source/graphics/ObjectEntry.h @@ -3,6 +3,7 @@ class CModel; class CSkeletonAnim; +struct SPropPoint; #include #include "CStr.h" @@ -39,6 +40,10 @@ public: CSkeletonAnim* m_RangedAnim; CSkeletonAnim* m_CorpseAnim; + CModel* m_ProjectileModel; + CModel* m_AmmunitionModel; + SPropPoint* m_AmmunitionPoint; + CSkeletonAnim* GetNamedAnimation( CStr animationName ); // list of props attached to object std::vector m_Props; diff --git a/source/graphics/Unit.cpp b/source/graphics/Unit.cpp index 4926703296..5c2786857b 100644 --- a/source/graphics/Unit.cpp +++ b/source/graphics/Unit.cpp @@ -2,7 +2,32 @@ #include "Unit.h" #include "Model.h" +#include "ObjectEntry.h" CUnit::~CUnit() { delete m_Model; } + +void CUnit::ShowAmmunition() +{ + if( !m_Object->m_AmmunitionModel || !m_Object->m_AmmunitionPoint ) + return; + m_Model->AddProp( m_Object->m_AmmunitionPoint, m_Object->m_AmmunitionModel->Clone() ); +} + +void CUnit::HideAmmunition() +{ + if( !m_Object->m_AmmunitionModel || !m_Object->m_AmmunitionPoint ) + return; + // Find out what the usual prop is: + std::vector& props = m_Object->m_Model->GetProps(); + std::vector::iterator it; + for( it = props.begin(); it != props.end(); ++it ) + if( it->m_Point == m_Object->m_AmmunitionPoint ) + { + m_Model->AddProp( m_Object->m_AmmunitionPoint, it->m_Model->Clone() ); + return; + } + // No usual prop. + m_Model->RemoveProp( m_Object->m_AmmunitionPoint ); +} \ No newline at end of file diff --git a/source/graphics/Unit.h b/source/graphics/Unit.h index f8df0169cf..36cecb25f2 100755 --- a/source/graphics/Unit.h +++ b/source/graphics/Unit.h @@ -31,6 +31,10 @@ public: // get actor's entity CEntity* GetEntity() { return m_Entity; } + // Put here as it conveniently references both the model and the ObjectEntry + void ShowAmmunition(); + void HideAmmunition(); + private: // object from which unit was created CObjectEntry* m_Object; diff --git a/source/graphics/UnitManager.cpp b/source/graphics/UnitManager.cpp index fe2c591e07..053d0d5f15 100755 --- a/source/graphics/UnitManager.cpp +++ b/source/graphics/UnitManager.cpp @@ -65,12 +65,14 @@ void CUnitManager::DeleteUnit(CUnit* unit) // DeleteAll: remove and delete all units void CUnitManager::DeleteAll() { - for (uint i=0;im_Model->Clone(), entity); AddUnit(unit); return unit; -} +} \ No newline at end of file diff --git a/source/graphics/UnitManager.h b/source/graphics/UnitManager.h index 5785ea092b..35f2e8480e 100755 --- a/source/graphics/UnitManager.h +++ b/source/graphics/UnitManager.h @@ -13,6 +13,7 @@ #include "Singleton.h" class CUnit; +class CModel; class CVector3D; class CEntity; class CStr; diff --git a/source/main.cpp b/source/main.cpp index 4d88d4b524..bf0884e64a 100755 --- a/source/main.cpp +++ b/source/main.cpp @@ -55,6 +55,7 @@ #include "EntityManager.h" #include "PathfindEngine.h" #include "Scheduler.h" +#include "Projectile.h" #include "StringConvert.h" #include "scripting/ScriptingHost.h" @@ -635,9 +636,14 @@ static void Render() static void LoadProfile( CStr profile ) { - CStr filename = CStr( "profiles/" ) + profile + CStr( ".cfg" ); - g_ConfigDB.SetConfigFile( CFG_USER, true, filename ); + CStr base = CStr( "profiles/" ) + profile; + g_ConfigDB.SetConfigFile( CFG_USER, true, base + "/settings/user.cfg" ); g_ConfigDB.Reload( CFG_USER ); + int history_size = 50; + CConfigValue* config_value = g_ConfigDB.GetValue( CFG_USER, "console.history.size" ); + if( config_value ) + config_value->GetInt( history_size ); + g_Console->UseHistoryFile( base + "/settings/history", ( history_size >= 0 ) ? history_size : 50 ); } // Fill in the globals from the config files. @@ -793,6 +799,7 @@ TIMER(InitScripting) CJSComplexPropertyAccessor::ScriptingInit(); // <-- Doesn't really matter which we use, but we know CJSPropertyAccessor is already being compiled for T = CEntity. CScriptEvent::ScriptingInit(); CJSProgressTimer::ScriptingInit(); + CProjectile::ScriptingInit(); g_ScriptingHost.DefineConstant( "ORDER_NONE", -1 ); g_ScriptingHost.DefineConstant( "ORDER_GOTO", CEntityOrder::ORDER_GOTO ); @@ -831,7 +838,7 @@ TIMER(InitVfs) vfs_init(); vfs_mount("", "mods/official", VFS_MOUNT_RECURSIVE|VFS_MOUNT_ARCHIVES|VFS_MOUNT_WATCH); vfs_mount("screenshots/", "screenshots"); - vfs_mount("profiles/", "profiles"); + vfs_mount("profiles/", "profiles", VFS_MOUNT_RECURSIVE); } /* double t0 = get_time(); diff --git a/source/ps/CConsole.cpp b/source/ps/CConsole.cpp index 84a3b25148..a40282f317 100755 --- a/source/ps/CConsole.cpp +++ b/source/ps/CConsole.cpp @@ -13,6 +13,8 @@ #include "Network/Client.h" #include "Network/Server.h" +#include "lib/res/vfs.h" + #include "Interact.h" extern bool keys[SDLK_LAST]; @@ -460,6 +462,12 @@ void CConsole::SetBuffer(const wchar_t* szMessage, ...) m_iBufferLength = m_iBufferPos = (int)wcslen(m_szBuffer); } +void CConsole::UseHistoryFile( CStr filename, unsigned int historysize ) +{ + m_sHistoryFile = filename; + m_iHistorySize = historysize; + LoadHistory(); +} void CConsole::ProcessBuffer(const wchar_t* szLine){ if (szLine == NULL) return; @@ -468,6 +476,8 @@ void CConsole::ProcessBuffer(const wchar_t* szLine){ assert(wcslen(szLine) < CONSOLE_BUFFER_SIZE); m_deqBufHistory.push_front(szLine); + SaveHistory(); // Do this each line for the moment; if a script causes + // a crash it's a useful record. wchar_t szCommand[CONSOLE_BUFFER_SIZE]; memset(szCommand, '\0', sizeof(wchar_t) * CONSOLE_BUFFER_SIZE); @@ -545,6 +555,44 @@ void CConsole::ProcessBuffer(const wchar_t* szLine){ SendChatMessage(szLine); } +void CConsole::LoadHistory() +{ + void* buffer; unsigned int buflen; + Handle h = vfs_load( m_sHistoryFile, buffer, buflen ); + if( h > 0 ) + { + std::string utf8( (char*)buffer, buflen ); + CStrW str( utf8 ); + size_t pos = 0; + while( pos != -1 ) + { + pos = str.find( '\n' ); + if( pos != -1 ) + { + if( pos > 0 ) + m_deqBufHistory.push_front( str.Left( str[pos-1] == '\r' ? pos - 1 : pos ) ); + str = str.GetSubstring( pos + 1, str.npos ); + } + else if( str.Length() > 0 ) + m_deqBufHistory.push_front( str ); + } + } + // Don't care about failure; just don't load anything. +} + +void CConsole::SaveHistory() +{ + CStr buffer; + std::deque::iterator it; + unsigned int count = 0; + for( it = m_deqBufHistory.begin(); it != m_deqBufHistory.end(); ++it ) + { + if( count++ >= m_iHistorySize ) break; + buffer = CStr( *it ) + "\n" + buffer; + } + vfs_store( m_sHistoryFile, (void*)buffer.c_str(), buffer.Length(), FILE_NO_AIO ); +} + void CConsole::SendChatMessage(const wchar_t *szMessage) { if (g_NetClient || g_NetServer) diff --git a/source/ps/CConsole.h b/source/ps/CConsole.h index 5287c32d3e..486a30be34 100755 --- a/source/ps/CConsole.h +++ b/source/ps/CConsole.h @@ -19,7 +19,7 @@ #include "ogl.h" #include "lib.h" #include "sdl.h" - +#include "CStr.h" #ifndef CCONSOLE_H #define CCONSOLE_H @@ -53,6 +53,9 @@ private: int m_iBufferPos; int m_iBufferLength; + CStr m_sHistoryFile; + unsigned int m_iHistorySize; + bool m_bFocus; bool m_bVisible; // console is to be drawn bool m_bToggle; // show/hide animation is currently active @@ -73,6 +76,9 @@ private: void InsertBuffer(void){InsertMessage(L"%ls", m_szBuffer);}; void ProcessBuffer(const wchar_t* szLine); + void LoadHistory(); + void SaveHistory(); + public: CConsole(); ~CConsole(); @@ -94,6 +100,8 @@ public: void SetBuffer(const wchar_t* szMessage, ...); + void UseHistoryFile( CStr filename, unsigned int historysize ); + // Only returns a pointer to the buffer; copy out of here if you want to keep it. const wchar_t* GetBuffer(); void FlushBuffer(); diff --git a/source/ps/World.cpp b/source/ps/World.cpp index 18bef89379..98d9645eae 100755 --- a/source/ps/World.cpp +++ b/source/ps/World.cpp @@ -60,4 +60,5 @@ CWorld::~CWorld() // The reason for not keeping the instance around is that we require a // clean slate for each game start. delete &m_EntityManager; + delete &m_ProjectileManager; } diff --git a/source/ps/World.h b/source/ps/World.h index 9bbc4b28da..9837ab631b 100755 --- a/source/ps/World.h +++ b/source/ps/World.h @@ -4,6 +4,7 @@ #include "Terrain.h" #include "UnitManager.h" #include "EntityManager.h" +#include "Projectile.h" class CGame; class CGameAttributes; @@ -13,18 +14,20 @@ class CWorld CGame *m_pGame; CTerrain m_Terrain; - // These both point to the respective g_* globals - the plan is to remove + // These all point to the respective g_* globals - the plan is to remove // the globals and move them into CWorld members as soon as all code has // been converted CUnitManager &m_UnitManager; CEntityManager &m_EntityManager; + CProjectileManager &m_ProjectileManager; public: inline CWorld(CGame *pGame): m_pGame(pGame), m_Terrain(), m_UnitManager(g_UnitMan), - m_EntityManager(*(new CEntityManager())) + m_EntityManager(*(new CEntityManager())), + m_ProjectileManager( *(new CProjectileManager())) {} ~CWorld(); @@ -40,6 +43,8 @@ public: { return &m_Terrain; } inline CUnitManager *GetUnitManager() { return &m_UnitManager; } + inline CProjectileManager *GetProjectileManager() + { return &m_ProjectileManager; } }; #include "Game.h" diff --git a/source/scripting/DOMEvent.cpp b/source/scripting/DOMEvent.cpp index de39a3d88e..c0c3a1573d 100755 --- a/source/scripting/DOMEvent.cpp +++ b/source/scripting/DOMEvent.cpp @@ -13,6 +13,8 @@ IEventTarget::~IEventTarget() bool IEventTarget::_DispatchEvent( CScriptEvent* evt, IEventTarget* target ) { + // TODO: Deal correctly with multiple handlers + if( before && before->_DispatchEvent( evt, target ) ) return( true ); // Stop propagation. diff --git a/source/scripting/EventTypes.h b/source/scripting/EventTypes.h index 1c9cfd7507..452d3a4944 100644 --- a/source/scripting/EventTypes.h +++ b/source/scripting/EventTypes.h @@ -13,6 +13,9 @@ enum EEventType EVENT_PREPARE_ORDER, EVENT_ORDER_TRANSITION, EVENT_LAST, + // Projectile events + EVENT_IMPACT = 0, + EVENT_MISS, // General events EVENT_GAME_START = 0, EVENT_GAME_TICK, diff --git a/source/scripting/JSConversions.cpp b/source/scripting/JSConversions.cpp index 8ae2ab5e53..06c024c865 100755 --- a/source/scripting/JSConversions.cpp +++ b/source/scripting/JSConversions.cpp @@ -11,7 +11,7 @@ template<> HEntity* ToNative( JSContext* cx, JSObject* obj ) { CEntity* e = ToNative( cx, obj ); - return( &( e->me ) ); + return( e ? &( e->me ) : NULL ); } template<> JSObject* ToScript( HEntity* Native ) @@ -22,7 +22,7 @@ template<> JSObject* ToScript( HEntity* Native ) // CPlayer* template<> bool ToPrimitive( JSContext* cx, jsval v, CPlayer*& Storage ) { - if( !JSVAL_IS_OBJECT( v ) ) return( false ); + if( !JSVAL_IS_OBJECT( v ) || ( v == JSVAL_NULL ) ) return( false ); CPlayer* Data = (CPlayer*)JS_GetInstancePrivate( cx, JSVAL_TO_OBJECT( v ), &CPlayer::JSI_class, NULL ); if( !Data ) return( false ); Storage = Data; @@ -38,7 +38,7 @@ template<> JSObject* ToScript( CPlayer** Native ) template<> bool ToPrimitive( JSContext* cx, jsval v, CBaseEntity*& Storage ) { - if( !JSVAL_IS_OBJECT( v ) ) return( false ); + if( !JSVAL_IS_OBJECT( v ) || ( v == JSVAL_NULL ) ) return( false ); CBaseEntity* Data = (CBaseEntity*)JS_GetInstancePrivate( cx, JSVAL_TO_OBJECT( v ), &CBaseEntity::JSI_class, NULL ); if( !Data ) return( false ); Storage = Data; @@ -54,8 +54,8 @@ template<> JSObject* ToScript( CBaseEntity** Native ) template<> CVector3D* ToNative( JSContext* cx, JSObject* obj ) { - JSI_Vector3D::Vector3D_Info* v = (JSI_Vector3D::Vector3D_Info*)JS_GetPrivate( cx, obj ); - return( v->vector ); + JSI_Vector3D::Vector3D_Info* v = (JSI_Vector3D::Vector3D_Info*)JS_GetInstancePrivate( cx, obj, &JSI_Vector3D::JSI_class, NULL ); + return( v ? v->vector : NULL ); } template<> JSObject* ToScript( CVector3D* Native ) diff --git a/source/scripting/JSConversions.h b/source/scripting/JSConversions.h index 43247968cc..c2fbd47096 100755 --- a/source/scripting/JSConversions.h +++ b/source/scripting/JSConversions.h @@ -23,25 +23,20 @@ class CPlayer; template T* ToNative( JSContext* cx, JSObject* obj ) { -#ifndef NDEBUG - if( OBJECT_TO_JSVAL( obj ) == JSVAL_NULL ) - return( NULL ); - assert( JS_GetClass( obj ) == &T::JSI_class ); - return( (T*)JS_GetPrivate( cx, obj ) ); -#endif return( (T*)JS_GetInstancePrivate( cx, obj, &T::JSI_class, NULL ) ); } template JSObject* ToScript( T* Native ) { if( !Native ) - return( (JSObject*)JSVAL_NULL ); + return( (JSObject*)NULL ); return( Native->GetScript() ); } template T* ToNative( jsval v ) { if( !JSVAL_IS_OBJECT( v ) ) return( NULL ); + if( v == JSVAL_NULL ) return( NULL ); return( ToNative( g_ScriptingHost.GetContext(), JSVAL_TO_OBJECT( v ) ) ); } diff --git a/source/scripting/ScriptableObject.h b/source/scripting/ScriptableObject.h index b8304aac91..9f774303c7 100755 --- a/source/scripting/ScriptableObject.h +++ b/source/scripting/ScriptableObject.h @@ -13,6 +13,8 @@ #define ALLOW_NONSHARED_NATIVES +static int pcount = 0; + class IJSObject; class IJSProperty @@ -137,7 +139,7 @@ public: void Root() { if( JSVAL_IS_GCTHING( m_Data ) ) - JS_AddRoot( g_ScriptingHost.GetContext(), (void*)&m_Data ); + JS_AddNamedRoot( g_ScriptingHost.GetContext(), (void*)&m_Data, "ScriptableObjectProperty" ); } void Uproot() { @@ -337,7 +339,7 @@ public: { m_JS = JS_NewObject( g_ScriptingHost.GetContext(), &JSI_class, NULL, NULL ); if( m_EngineOwned ) - JS_AddRoot( g_ScriptingHost.GetContext(), (void*)&m_JS ); + JS_AddNamedRoot( g_ScriptingHost.GetContext(), (void*)&m_JS, JSI_class.name ); JS_SetPrivate( g_ScriptingHost.GetContext(), m_JS, (T*)this ); } diff --git a/source/simulation/BaseEntity.cpp b/source/simulation/BaseEntity.cpp index 2dc69fda0b..9741edc6cc 100755 --- a/source/simulation/BaseEntity.cpp +++ b/source/simulation/BaseEntity.cpp @@ -59,11 +59,13 @@ void CBaseEntity::loadBase() { m_bound_circle = new CBoundingCircle(); m_bound_circle->setRadius( m_base->m_bound_circle->m_radius ); + m_bound_circle->setHeight( m_base->m_bound_circle->m_height ); } else if( m_base->m_bound_type == CBoundingObject::BOUND_OABB ) { m_bound_box = new CBoundingBox(); - m_bound_box->setDimensions( m_base->m_bound_box->getWidth(), m_base->m_bound_box->getHeight() ); + m_bound_box->setDimensions( m_base->m_bound_box->getWidth(), m_base->m_bound_box->getDepth() ); + m_bound_box->setHeight( m_base->m_bound_box->m_height ); } m_bound_type = m_base->m_bound_type; } @@ -157,6 +159,7 @@ bool CBaseEntity::loadXML( CStr filename ) AT(parent); AT(radius); AT(width); + AT(depth); AT(height); AT(on); AT(file); @@ -217,17 +220,22 @@ bool CBaseEntity::loadXML( CStr filename ) if( !m_bound_circle ) m_bound_circle = new CBoundingCircle(); CStrW radius (Child.getAttributes().getNamedItem(at_radius)); + CStrW height (Child.getAttributes().getNamedItem(at_height)); + m_bound_circle->setRadius( radius.ToFloat() ); + m_bound_circle->setHeight( height.ToFloat() ); m_bound_type = CBoundingObject::BOUND_CIRCLE; } else { if( !m_bound_box ) - m_bound_box = new CBoundingBox(); + m_bound_box = new CBoundingBox(); CStrW width (Child.getAttributes().getNamedItem(at_width)); + CStrW depth (Child.getAttributes().getNamedItem(at_depth)); CStrW height (Child.getAttributes().getNamedItem(at_height)); - m_bound_box->setDimensions( width.ToFloat(), height.ToFloat() ); + m_bound_box->setDimensions( width.ToFloat(), depth.ToFloat() ); + m_bound_box->setHeight( height.ToFloat() ); m_bound_type = CBoundingObject::BOUND_OABB; } } diff --git a/source/simulation/BoundingObjects.cpp b/source/simulation/BoundingObjects.cpp index c1167d69ee..bab387eca3 100755 --- a/source/simulation/BoundingObjects.cpp +++ b/source/simulation/BoundingObjects.cpp @@ -30,11 +30,23 @@ bool CBoundingObject::contains( const CVector2D& point ) return( _contains( point, delta ) ); } -CBoundingCircle::CBoundingCircle( float x, float y, float radius ) + +void CBoundingObject::setPosition( float x, float y ) +{ + m_pos.x = x; m_pos.y = y; +} + +void CBoundingObject::setHeight( float height ) +{ + m_height = height; +} + +CBoundingCircle::CBoundingCircle( float x, float y, float radius, float height ) { m_type = BOUND_CIRCLE; setPosition( x, y ); setRadius( radius ); + setHeight( height ); } CBoundingCircle::CBoundingCircle( float x, float y, CBoundingCircle* copy ) @@ -42,11 +54,7 @@ CBoundingCircle::CBoundingCircle( float x, float y, CBoundingCircle* copy ) m_type = BOUND_CIRCLE; setPosition( x, y ); setRadius( copy->m_radius ); -} - -void CBoundingObject::setPosition( float x, float y ) -{ - m_pos.x = x; m_pos.y = y; + setHeight( copy->m_height ); } void CBoundingCircle::setRadius( float radius ) @@ -82,11 +90,12 @@ void CBoundingCircle::render( float height ) glEnd(); } -CBoundingBox::CBoundingBox( float x, float y, const CVector2D& u, float width, float height ) +CBoundingBox::CBoundingBox( float x, float y, const CVector2D& u, float width, float depth, float height ) { m_type = BOUND_OABB; setPosition( x, y ); - setDimensions( width, height ); + setDimensions( width, depth ); + setHeight( height ); setOrientation( u ); } @@ -94,15 +103,17 @@ CBoundingBox::CBoundingBox( float x, float y, const CVector2D& u, CBoundingBox* { m_type = BOUND_OABB; setPosition( x, y ); - setDimensions( copy->getWidth(), copy->getHeight() ); + setDimensions( copy->getWidth(), copy->getDepth() ); + setHeight( copy->m_height ); setOrientation( u ); } -CBoundingBox::CBoundingBox( float x, float y, float orientation, float width, float height ) +CBoundingBox::CBoundingBox( float x, float y, float orientation, float width, float depth, float height ) { m_type = BOUND_OABB; setPosition( x, y ); - setDimensions( width, height ); + setDimensions( width, depth ); + setHeight( height ); setOrientation( orientation ); } @@ -110,15 +121,16 @@ CBoundingBox::CBoundingBox( float x, float y, float orientation, CBoundingBox* c { m_type = BOUND_OABB; setPosition( x, y ); - setDimensions( copy->getWidth(), copy->getHeight() ); + setDimensions( copy->getWidth(), copy->getDepth() ); + setHeight( copy->m_height ); setOrientation( orientation ); } -void CBoundingBox::setDimensions( float width, float height ) +void CBoundingBox::setDimensions( float width, float depth ) { m_w = width / 2.0f; - m_h = height / 2.0f; - m_radius = sqrt( ( m_w * m_w ) + ( m_h * m_h ) ); + m_d = depth / 2.0f; + m_radius = sqrt( ( m_w * m_w ) + ( m_d * m_d ) ); } void CBoundingBox::setOrientation( float orientation ) @@ -143,8 +155,8 @@ bool CBoundingBox::_intersects( CBoundingObject* obj, const CVector2D& delta ) // Imperfect but quick... CBoundingCircle* c = (CBoundingCircle*)obj; - float deltah = fabs( delta.dot( m_u ) ); - if( deltah > ( m_h + c->m_radius ) ) return( false ); + float deltad = fabs( delta.dot( m_u ) ); + if( deltad > ( m_d + c->m_radius ) ) return( false ); float deltaw = fabs( delta.dot( m_v ) ); if( deltaw > ( m_w + c->m_radius ) ) return( false ); return( true ); @@ -180,8 +192,8 @@ bool CBoundingBox::_intersects( CBoundingObject* obj, const CVector2D& delta ) // Project box 2 onto v-axis of box 1 - prj1 = fabs( vu * b->m_h + vv * b->m_w ); - prj2 = fabs( vu * b->m_h - vv * b->m_h ); + prj1 = fabs( vu * b->m_d + vv * b->m_w ); + prj2 = fabs( vu * b->m_d - vv * b->m_w ); dm = delta.dot( m_v ); if( prj1 > prj2 ) @@ -193,21 +205,21 @@ bool CBoundingBox::_intersects( CBoundingObject* obj, const CVector2D& delta ) // Project box 2 onto u-axis of box 1 - prj1 = fabs( uu * b->m_h + uv * b->m_w ); - prj2 = fabs( uu * b->m_h - uv * b->m_w ); + prj1 = fabs( uu * b->m_d + uv * b->m_w ); + prj2 = fabs( uu * b->m_d - uv * b->m_w ); dm = delta.dot( m_u ); if( prj1 > prj2 ) { - if( ( dm - prj1 ) > m_h ) return( false ); + if( ( dm - prj1 ) > m_d ) return( false ); } else - if( ( dm - prj2 ) > m_h ) return( false ); + if( ( dm - prj2 ) > m_d ) return( false ); // Project box 1 onto v-axis of box 2 - prj1 = fabs( uv * m_h + vv * m_w ); - prj2 = fabs( uv * m_h - vv * m_w ); + prj1 = fabs( uv * m_d + vv * m_w ); + prj2 = fabs( uv * m_d - vv * m_w ); dm = delta.dot( b->m_v ); if( prj1 > prj2 ) @@ -219,16 +231,16 @@ bool CBoundingBox::_intersects( CBoundingObject* obj, const CVector2D& delta ) // Project box 1 onto u-axis of box 2 - prj1 = fabs( uu * m_h + vu * m_w ); - prj2 = fabs( uu * m_h - vu * m_w ); + prj1 = fabs( uu * m_d + vu * m_w ); + prj2 = fabs( uu * m_d - vu * m_w ); dm = delta.dot( b->m_u ); if( prj1 > prj2 ) { - if( ( dm - prj1 ) > b->m_h ) return( false ); + if( ( dm - prj1 ) > b->m_d ) return( false ); } else - if( ( dm - prj2 ) > b->m_h ) return( false ); + if( ( dm - prj2 ) > b->m_d ) return( false ); return( true ); @@ -237,8 +249,8 @@ bool CBoundingBox::_intersects( CBoundingObject* obj, const CVector2D& delta ) bool CBoundingBox::_contains( const CVector2D& point, const CVector2D& delta ) { - float deltah = fabs( delta.dot( m_u ) ); - if( deltah > m_h ) return( false ); + float deltad = fabs( delta.dot( m_u ) ); + if( deltad > m_d ) return( false ); float deltaw = fabs( delta.dot( m_v ) ); if( deltaw > m_w ) return( false ); return( true ); @@ -250,16 +262,16 @@ void CBoundingBox::render( float height ) CVector2D p; - p = m_pos + m_u * m_h + m_v * m_w; + p = m_pos + m_u * m_d + m_v * m_w; glVertex3f( p.x, height, p.y ); - p = m_pos + m_u * m_h - m_v * m_w; + p = m_pos + m_u * m_d - m_v * m_w; glVertex3f( p.x, height, p.y ); - p = m_pos - m_u * m_h - m_v * m_w; + p = m_pos - m_u * m_d - m_v * m_w; glVertex3f( p.x, height, p.y ); - p = m_pos - m_u * m_h + m_v * m_w; + p = m_pos - m_u * m_d + m_v * m_w; glVertex3f( p.x, height, p.y ); glEnd(); diff --git a/source/simulation/BoundingObjects.h b/source/simulation/BoundingObjects.h index 09114bbdba..d1018f2428 100755 --- a/source/simulation/BoundingObjects.h +++ b/source/simulation/BoundingObjects.h @@ -5,7 +5,6 @@ // Bounding circle and object-aligned bounding box. 2D, for simulation code. // // Note: object-aligned bounding boxes are often referred to as oriented bounding boxes (OBBs) -// At present, this stuff compiles; no guarantee is made of it actually working yet, however. #ifndef BOUNDING_OBJECTS_INCLUDED #define BOUNDING_OBJECTS_INCLUDED @@ -28,7 +27,10 @@ public: EBoundingType m_type; CVector2D m_pos; float m_radius; + float m_height; + void setPosition( float x, float y ); + void setHeight( float height ); bool intersects( CBoundingObject* obj ); bool contains( const CVector2D& point ); virtual bool _intersects( CBoundingObject* obj, const CVector2D& delta ) = 0; @@ -40,7 +42,7 @@ class CBoundingCircle : public CBoundingObject { public: CBoundingCircle() { m_type = BOUND_OABB; } - CBoundingCircle( float x, float y, float radius ); + CBoundingCircle( float x, float y, float radius, float height ); CBoundingCircle( float x, float y, CBoundingCircle* copy ); void setRadius( float radius ); bool _intersects( CBoundingObject* obj, const CVector2D& delta ); @@ -52,19 +54,19 @@ class CBoundingBox : public CBoundingObject { public: CBoundingBox() { m_type = BOUND_OABB; } - CVector2D m_u; // Unit vector along the direction of this box's height. + CVector2D m_u; // Unit vector along the direction of this box's depth. CVector2D m_v; // Unit vector along the direction of this box's width. - float m_h; // Half this box's height. + float m_d; // Half this box's depth. float m_w; // Half this box's width. - CBoundingBox( float x, float y, float orientation, float width, float height ); - CBoundingBox( float x, float y, const CVector2D& orientation, float width, float height ); + CBoundingBox( float x, float y, float orientation, float width, float depth, float height ); + CBoundingBox( float x, float y, const CVector2D& orientation, float width, float depth, float height ); CBoundingBox( float x, float y, float orientation, CBoundingBox* copy ); CBoundingBox( float x, float y, const CVector2D& orientation, CBoundingBox* copy ); - void setDimensions( float width, float height ); + void setDimensions( float width, float depth ); void setOrientation( float orientation ); void setOrientation( const CVector2D& orientation ); float getWidth() const { return( 2.0f * m_w ); }; - float getHeight() const { return( 2.0f * m_h ); }; + float getDepth() const { return( 2.0f * m_d ); }; bool _intersects( CBoundingObject* obj, const CVector2D& delta ); bool _contains( const CVector2D& point, const CVector2D& delta ); void render( float height ); // Temporary diff --git a/source/simulation/Collision.cpp b/source/simulation/Collision.cpp index 5d7aba43a4..bcbe0ec7b1 100755 --- a/source/simulation/Collision.cpp +++ b/source/simulation/Collision.cpp @@ -23,6 +23,27 @@ CBoundingObject* getContainingObject( const CVector2D& point ) return( NULL ); } +CEntity* GetCollisionObject( float x, float y ) +{ + CVector2D point( x, y ); + std::vector* entities = g_EntityManager.getExtant(); + std::vector::iterator it; + + for( it = entities->begin(); it != entities->end(); it++ ) + { + if( !(*it)->m_bounds ) continue; + if( (*it)->m_bounds->contains( point ) ) + { + CEntity* e = (*it); + delete( entities ); + return( e ); + } + } + + delete( entities ); + return( NULL ); +} + CBoundingObject* getCollisionObject( CBoundingObject* bounds ) { std::vector* entities = g_EntityManager.getExtant(); @@ -83,8 +104,10 @@ HEntity getCollisionObject( CEntity* entity, float x, float y ) bool getRayIntersection( const CVector2D& source, const CVector2D& forward, const CVector2D& right, float length, float maxDistance, CBoundingObject* destinationCollisionObject, rayIntersectionResults* results ) { - std::vector* entities = g_EntityManager.getExtant(); - std::vector::iterator it; + std::vector entities; + g_EntityManager.GetExtant( entities ); + + std::vector::iterator it; float closestApproach, dist; @@ -93,7 +116,7 @@ bool getRayIntersection( const CVector2D& source, const CVector2D& forward, cons results->distance = length + maxDistance; results->boundingObject = NULL; - for( it = entities->begin(); it != entities->end(); it++ ) + for( it = entities.begin(); it != entities.end(); it++ ) { if( !(*it)->m_bounds ) continue; if( (*it)->m_bounds == destinationCollisionObject ) continue; @@ -114,12 +137,122 @@ bool getRayIntersection( const CVector2D& source, const CVector2D& forward, cons results->boundingObject = obj; results->closestApproach = closestApproach; results->distance = dist; - results->hEntity = (*it); + results->Entity = (*it); results->position = obj->m_pos; } } } - delete( entities ); if( results->boundingObject ) return( true ); return( false ); } + +void GetProjectileIntersection( const CVector2D& position, const CVector2D& axis, float length, RayIntersects& results ) +{ + results.clear(); + + std::vector entities; + g_EntityManager.GetExtant( entities ); + + float dist, closestApproach, l; + CVector2D delta; + + std::vector::iterator it; + for( it = entities.begin(); it != entities.end(); it++ ) + { + CBoundingObject* obj = (*it)->m_bounds; + delta = obj->m_pos - position; + closestApproach = delta.betadot( axis ); + if( fabs( closestApproach ) > obj->m_radius ) + continue; // Safe, doesn't get close enough. + dist = delta.dot( axis ); + // I just want to see if this will work before I simplify the maths + l = sqrt( obj->m_radius * obj->m_radius - closestApproach * closestApproach ); + if( dist > 0 ) + { + // Forward... + if( ( dist - length ) > l ) + continue; // OK, won't reach it. + } + else + { + // Backward... + if( -dist > l ) + continue; // OK, started far enough away + } + + if( obj->m_type == CBoundingObject::BOUND_OABB ) + { + // Run a more accurate test against the box + CBoundingBox* box = (CBoundingBox*)obj; + const float EPSILON = 0.0001f; + float first = FLT_MAX, last = -FLT_MAX; + CVector2D delta2; + + // Test against those sides of the box parallel with it's u vector. + float t = box->m_u.y * axis.x - axis.y * box->m_u.x; + float abs_t = fabs( t ); + if( abs_t >= EPSILON ) + { + // If not parallel, + delta2 = delta - box->m_v * box->m_w; + if( fabs( axis.y * delta2.x - axis.x * delta2.y ) < box->m_d * abs_t ) + { + // Possible intersection with one side + float pos = ( box->m_u.y * delta2.x - box->m_u.x * delta2.y ) / t; + if( pos < first ) first = pos; + if( pos > last ) last = pos; + } + + delta2 = delta + box->m_v * box->m_w; + if( fabs( axis.y * delta2.x - axis.x * delta2.y ) < box->m_d * abs_t ) + { + // Possible intersection with one side + float pos = ( box->m_u.y * delta2.x - box->m_u.x * delta2.y ) / t; + if( pos < first ) first = pos; + if( pos > last ) last = pos; + } + } + + // Next test against those sides of the box parallel with it's v vector. + t = box->m_v.y * axis.x - axis.y * box->m_v.x; + abs_t = fabs( t ); + if( abs_t >= EPSILON ) + { + // If not parallel, + delta2 = delta - box->m_u * box->m_d; + if( fabs( axis.y * delta2.x - axis.x * delta2.y ) < box->m_w * abs_t ) + { + // Possible intersection with one side + float pos = ( box->m_v.y * delta2.x - box->m_v.x * delta2.y ) / t; + if( pos < first ) first = pos; + if( pos > last ) last = pos; + } + + delta2 = delta + box->m_u * box->m_d; + if( fabs( axis.y * delta2.x - axis.x * delta2.y ) < box->m_w * abs_t ) + { + // Possible intersection with one side + float pos = ( box->m_v.y * delta2.x - box->m_v.x * delta2.y ) / t; + if( pos < first ) first = pos; + if( pos > last ) last = pos; + } + } + + // Then work out if we actually hit it within the given range. + if( last < 0.0f ) + continue; // No, we started far enough 'after' there. + if( first > length ) + continue; // No, we haven't yet moved far enough to hit it. + } + + results.push_back( *it ); + } +} + +static RayIntersects SharedResults; + +RayIntersects& GetProjectileIntersection( const CVector2D& position, const CVector2D& axis, float length ) +{ + GetProjectileIntersection( position, axis, length, SharedResults ); + return( SharedResults ); +} diff --git a/source/simulation/Collision.h b/source/simulation/Collision.h index f37c4819aa..6675928dc0 100755 --- a/source/simulation/Collision.h +++ b/source/simulation/Collision.h @@ -20,17 +20,24 @@ struct rayIntersectionResults { - HEntity hEntity; + CEntity* Entity; CBoundingObject* boundingObject; CVector2D position; float closestApproach; float distance; }; +typedef std::vector RayIntersects; + HEntity getCollisionObject( CEntity* entity ); HEntity getCollisionObject( CEntity* entity, float x, float y ); CBoundingObject* getCollisionObject( CBoundingObject* bounds ); CBoundingObject* getContainingObject( const CVector2D& point ); +CEntity* GetCollisionObject( float x, float y ); // Point collision bool getRayIntersection( const CVector2D& source, const CVector2D& forward, const CVector2D& right, float length, float maxDistance, CBoundingObject* destinationCollisionObject, rayIntersectionResults* results ); +// Assumes zero width, also includes moving units (other one doesn't). +void GetProjectileIntersection( const CVector2D& position, const CVector2D& axis, float length, RayIntersects& results ); +// Stores results in shared area +RayIntersects& GetProjectileIntersection( const CVector2D& position, const CVector2D& axis, float length ); #endif diff --git a/source/simulation/Entity.cpp b/source/simulation/Entity.cpp index ffdd8629f4..8e9788efec 100755 --- a/source/simulation/Entity.cpp +++ b/source/simulation/Entity.cpp @@ -574,7 +574,7 @@ void CEntity::renderSelectionOutline( float alpha ) CVector2D p, q; CVector2D u, v; q.x = pos.X; q.y = pos.Z; - float h = ((CBoundingBox*)m_bounds)->m_h; + float d = ((CBoundingBox*)m_bounds)->m_d; float w = ((CBoundingBox*)m_bounds)->m_w; u.x = sin( m_graphics_orientation ); @@ -585,25 +585,25 @@ void CEntity::renderSelectionOutline( float alpha ) #ifdef SELECTION_TERRAIN_CONFORMANCE for( int i = SELECTION_BOX_POINTS; i > -SELECTION_BOX_POINTS; i-- ) { - p = q + u * h + v * ( w * (float)i / (float)SELECTION_BOX_POINTS ); + p = q + u * d + v * ( w * (float)i / (float)SELECTION_BOX_POINTS ); glVertex3f( p.x, pTerrain->getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); } for( int i = SELECTION_BOX_POINTS; i > -SELECTION_BOX_POINTS; i-- ) { - p = q + u * ( h * (float)i / (float)SELECTION_BOX_POINTS ) - v * w; + p = q + u * ( d * (float)i / (float)SELECTION_BOX_POINTS ) - v * w; glVertex3f( p.x, pTerrain->getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); } for( int i = -SELECTION_BOX_POINTS; i < SELECTION_BOX_POINTS; i++ ) { - p = q - u * h + v * ( w * (float)i / (float)SELECTION_BOX_POINTS ); + p = q - u * d + v * ( w * (float)i / (float)SELECTION_BOX_POINTS ); glVertex3f( p.x, pTerrain->getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); } for( int i = -SELECTION_BOX_POINTS; i < SELECTION_BOX_POINTS; i++ ) { - p = q + u * ( h * (float)i / (float)SELECTION_BOX_POINTS ) + v * w; + p = q + u * ( d * (float)i / (float)SELECTION_BOX_POINTS ) + v * w; glVertex3f( p.x, pTerrain->getExactGroundLevel( p.x, p.y ) + 0.25f, p.y ); } #else @@ -887,7 +887,7 @@ jsval CEntity::GetSpawnPoint( JSContext* cx, uintN argc, jsval* argv ) assert( 0 && "No arguments to Entity::GetSpawnPoint()" ); // TODO: Make netsafe. - CBoundingCircle spawn( 0.0f, 0.0f, spawn_clearance ); + CBoundingCircle spawn( 0.0f, 0.0f, spawn_clearance, 0.0f ); if( m_bounds->m_type == CBoundingObject::BOUND_OABB ) { @@ -898,22 +898,22 @@ jsval CEntity::GetSpawnPoint( JSContext* cx, uintN argc, jsval* argv ) 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; + double max_d = oabb->m_d + spawn_clearance + 1.0; int w_count = (int)( max_w * 2 ); - int h_count = (int)( max_h * 2 ); + int d_count = (int)( max_d * 2 ); CVector2D w_step = oabb->m_v * (float)( max_w / w_count ); - CVector2D h_step = oabb->m_u * (float)( max_h / h_count ); + CVector2D d_step = oabb->m_u * (float)( max_d / d_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 ); + point = rand() % ( 2 * d_count ) - d_count; + pos += ( oabb->m_v * (float)max_w + d_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 ); + pos += ( oabb->m_u * (float)max_d + w_step * (float)point ) * ( ( edge & 2 ) ? -1.0f : 1.0f ); } int start_edge = edge; int start_point = point; @@ -931,12 +931,12 @@ jsval CEntity::GetSpawnPoint( JSContext* cx, uintN argc, jsval* argv ) if( point >= w_count ) { edge = 1; - point = -h_count; + point = -d_count; } break; case 1: - point++; pos -= h_step; - if( point >= h_count ) + point++; pos -= d_step; + if( point >= d_count ) { edge = 2; point = w_count; @@ -947,12 +947,12 @@ jsval CEntity::GetSpawnPoint( JSContext* cx, uintN argc, jsval* argv ) if( point <= -w_count ) { edge = 3; - point = h_count; + point = d_count; } break; case 3: - point--; pos += h_step; - if( point <= -h_count ) + point--; pos += d_step; + if( point <= -d_count ) { edge = 0; point = -w_count; diff --git a/source/simulation/Entity.h b/source/simulation/Entity.h index 111a430dfa..c6d76fa188 100755 --- a/source/simulation/Entity.h +++ b/source/simulation/Entity.h @@ -7,8 +7,7 @@ // Usage: Do not attempt to instantiate this class directly. (See EntityManager.h) // Most of the members are trivially obvious; some highlights are: // -// HEntity me: is a reference to this entity. Use instead of the address-of operator for -// non-temporary references. See EntityHandles.h +// HEntity me: is a reference to this entity. See EntityHandles.h // // Destroying entities: An entity is destroyed when all references to it expire. // It is somewhat unfunny if this happens while a method from this @@ -18,15 +17,11 @@ // prior to its next update cycle. // // CUnit* m_actor: is the visible representation of this entity. -// std::hash_map m_properties: isn't yet used, is capable of storing properties defined by script. // // snapToGround(): Called every frame, this will ensure the entity never takes flight. // updateActorTransforms(): Must be called every time the position of this entity changes. // Also remember to update the collision object if you alter the position directly. // -// Some notes: update() and dispatch() /can/ be called directly without ill effects, -// but it's preferable to go through the Entity manager and the Scheduler, respectively. -// #ifndef ENTITY_INCLUDED #define ENTITY_INCLUDED diff --git a/source/simulation/EntityManager.cpp b/source/simulation/EntityManager.cpp index ff0274be83..118ab0414c 100755 --- a/source/simulation/EntityManager.cpp +++ b/source/simulation/EntityManager.cpp @@ -1,3 +1,4 @@ + #include "precompiled.h" #include "EntityManager.h" @@ -97,6 +98,14 @@ std::vector* CEntityManager::getExtant() return( activelist ); } +void CEntityManager::GetExtant( std::vector& results ) +{ + results.clear(); + for( int i = 0; i < MAX_HANDLES; i++ ) + if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed ) + results.push_back( m_entities[i].m_entity ); +} + /* void CEntityManager::dispatchAll( CMessage* msg ) { diff --git a/source/simulation/EntityManager.h b/source/simulation/EntityManager.h index 5ed5e5f715..8fa79ddab5 100755 --- a/source/simulation/EntityManager.h +++ b/source/simulation/EntityManager.h @@ -68,6 +68,7 @@ public: std::vector* matches( EntityPredicate predicate, void* userdata = NULL ); std::vector* getExtant(); + void GetExtant( std::vector& results ); // TODO: Switch most/all uses of getExtant() to this. static inline bool extant() // True if the singleton is actively maintaining handles. When false, system is shutting down, handles are quietly dumped. { return( m_extant ); diff --git a/source/simulation/EntityStateProcessing.cpp b/source/simulation/EntityStateProcessing.cpp index c810cf8ea1..bff0a8220b 100755 --- a/source/simulation/EntityStateProcessing.cpp +++ b/source/simulation/EntityStateProcessing.cpp @@ -3,6 +3,7 @@ #include "precompiled.h" #include "Entity.h" +#include "BaseEntity.h" #include "Model.h" #include "ObjectEntry.h" #include "Unit.h" @@ -146,7 +147,7 @@ uint CEntity::processGotoHelper( CEntityOrder* current, size_t timestep_millis, if( ( m_orderQueue.size() == 1 ) && ( len <= 10.0f ) ) { - CBoundingCircle destinationObs( current->m_data[0].location.x, current->m_data[0].location.y, m_bounds->m_radius ); + CBoundingCircle destinationObs( current->m_data[0].location.x, current->m_data[0].location.y, m_bounds->m_radius, 0.0f ); if( getCollisionObject( &destinationObs ) ) { // Yes. (Chances are a bunch of units were tasked to the same destination) @@ -206,7 +207,7 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, size_t timestep_milli { // Here's a wierd idea: (I hope it works) // Spiral round the destination until a free point is found. - CBoundingCircle destinationObs( current->m_data[0].location.x, current->m_data[0].location.y, m_bounds->m_radius ); + CBoundingCircle destinationObs( current->m_data[0].location.x, current->m_data[0].location.y, m_bounds->m_radius, 0.0f ); float interval = destinationObs.m_radius; float r = interval, theta = 0.0f, delta; @@ -312,9 +313,16 @@ bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t times m_actor->GetModel()->SetAnimation( m_fsm_animation, true ); } - + if( ( m_fsm_cyclepos <= m_fsm_anipos2 ) && + ( nextpos > m_fsm_anipos2 ) ) + { + // Load the ammunition. + m_actor->ShowAmmunition(); + } if( ( m_fsm_cyclepos <= action->m_Speed ) && ( nextpos > action->m_Speed ) ) { + // Fire! + m_actor->HideAmmunition(); DispatchEvent( contactEvent ); // Note that, at the moment, we don't care if the action succeeds or fails - // we could check for failure, then abort the animation. @@ -448,6 +456,22 @@ bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t times m_actor->GetModel()->SetAnimation( m_fsm_animation, true ); m_actor->GetModel()->Update( m_fsm_animation->m_ActionPos / 1000.0f - action->m_Speed / 2000.0f ); } + else + { + // If we've just transitioned, play idle. Otherwise, let the previous animation complete, if it + // hasn't already. + if( m_transition ) + m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_IdleAnim ); + } + + // Load time needs to be animation->m_ActionPos2 ms after the start of the animation. + + m_fsm_anipos2 = m_fsm_anipos + ( m_fsm_animation->m_ActionPos2 * 2 ); + if( action->m_Speed < ( ( m_fsm_animation->m_ActionPos + m_fsm_animation->m_ActionPos2 ) * 2 ) ) + { + // Load now. + m_actor->ShowAmmunition(); + } m_fsm_cyclepos = 0; @@ -461,7 +485,15 @@ bool CEntity::processAttackMelee( CEntityOrder* current, size_t timestep_millis 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_melee ) ); + if( !m_actor ) return( false ); + CSkeletonAnim* animation = m_actor->GetObject()->m_MeleeAnim; + if( !animation ) animation = m_actor->GetObject()->m_IdleAnim; + if( !animation ) return( false ); // Should probably tell people why this is failing + // (didn't specify an actor or animation) but that + // would probably involve including CLogger.h, which + // conflicts. + + return( processContactActionNoPathing( current, timestep_milli, animation, &evt, &m_melee ) ); } bool CEntity::processGather( CEntityOrder* current, size_t timestep_millis ) { @@ -471,7 +503,14 @@ bool CEntity::processGather( CEntityOrder* current, size_t timestep_millis ) 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, &m_gather ) ); + if( !m_actor ) return( false ); + CSkeletonAnim* animation = m_actor->GetObject()->m_GatherAnim; + if( !animation ) animation = m_actor->GetObject()->m_IdleAnim; + if( !animation ) return( false ); // Should probably tell people why this is failing + // (didn't specify an actor or animation) but that + // would probably involve including CLogger.h, which + // conflicts. + return( processContactActionNoPathing( current, timestep_millis, animation, &evt, &m_gather ) ); } bool CEntity::processGoto( CEntityOrder* current, size_t timestep_millis ) diff --git a/source/simulation/Projectile.cpp b/source/simulation/Projectile.cpp new file mode 100644 index 0000000000..7de93b1baa --- /dev/null +++ b/source/simulation/Projectile.cpp @@ -0,0 +1,266 @@ +#include "precompiled.h" + +#include "Projectile.h" +#include "Entity.h" +#include "Model.h" +#include "Unit.h" +#include "Matrix3D.h" +#include "ScriptObject.h" +#include "Game.h" +#include "Collision.h" +#include "ObjectManager.h" +#include "CLogger.h" + +const double GRAVITY = 0.0000002; +const double GRAVITY_2 = GRAVITY * 0.5; + +CProjectile::CProjectile( const CModel* Actor, const CVector3D& Position, const CVector3D& Target, float Speed, CEntity* Originator, const CScriptObject& ImpactScript, const CScriptObject& MissScript ) +{ + m_Actor = Actor->Clone(); + m_Position = m_Position_Previous = m_Position_Graphics = Position; + m_Speed_H = Speed; + m_Originator = Originator; + m_ImpactEventHandler = ImpactScript; + m_MissEventHandler = MissScript; + + AddHandler( EVENT_IMPACT, &m_ImpactEventHandler ); + AddHandler( EVENT_MISS, &m_MissEventHandler ); + + // That was the easy stuff. + // We want horizontal distance only: + + m_Axis = Target - Position; + double s = m_Axis.length(); + m_Axis /= (float)s; + + // Now vertical distance: + double d_h = Target.Y - Position.Y; + // Time of impact: + double t = s / m_Speed_H; + // Required vertical velocity at launch: + m_Speed_V = (float)( d_h / t + GRAVITY_2 * t ); +} + +CProjectile::~CProjectile() +{ + std::vector::iterator it; + for( it = g_ProjectileManager.m_Projectiles.begin(); it != g_ProjectileManager.m_Projectiles.end(); ++it ) + if( *it == this ) + { + g_ProjectileManager.m_Projectiles.erase( it ); + break; + } + delete( m_Actor ); +} + +bool CProjectile::Update( size_t timestep_millis ) +{ + m_Position_Previous = m_Position; + m_Position.X += timestep_millis * m_Axis.x * m_Speed_H; + m_Position.Z += timestep_millis * m_Axis.y * m_Speed_H; + + m_Position.Y += (float)( timestep_millis * ( m_Speed_V - timestep_millis * GRAVITY_2 ) ); + m_Speed_V -= (float)( timestep_millis * GRAVITY ); + + float height = m_Position.Y - g_Game->GetWorld()->GetTerrain()->getExactGroundLevel( m_Position.X, m_Position.Z ); + + if( height < 0.0f ) + { + // We appear to have missed. + CEventProjectileMiss evt( m_Originator, m_Position ); + DispatchEvent( &evt ); + // Not going to let this be cancelled. + return( false ); + } + RayIntersects& r = GetProjectileIntersection( m_Position_Previous, m_Axis, timestep_millis * m_Speed_H ); + RayIntersects::iterator it; + for( it = r.begin(); it != r.end(); it++ ) + { + // Hit something? + if( *it != m_Originator ) /* That wouldn't be fair at all... */ + { + // Low enough to hit it? + if( height < (*it)->m_bounds->m_height ) + { + CEventProjectileImpact evt( m_Originator, *it, m_Position ); + if( DispatchEvent( &evt ) ) + return( false ); + } + } + } + return( true ); +} + +void CProjectile::Interpolate( size_t timestep_millis ) +{ + m_Position_Graphics.X = m_Position_Previous.X + timestep_millis * m_Speed_H * m_Axis.x; + m_Position_Graphics.Z = m_Position_Previous.Z + timestep_millis * m_Speed_H * m_Axis.y; + m_Position_Graphics.Y = (float)( m_Position_Previous.Y + timestep_millis * ( m_Speed_V - timestep_millis * GRAVITY_2 ) ); + float dh_dt = (float)( m_Speed_V - timestep_millis * GRAVITY ); + float scale = 1 / sqrt( m_Speed_H * m_Speed_H + dh_dt * dh_dt ); + float scale2 = m_Speed_H * scale; + + float y = dh_dt * scale; + CMatrix3D rotateInc; + rotateInc.SetIdentity(); + rotateInc._22 = rotateInc._33 = y; + rotateInc._23 = -( rotateInc._32 = scale2 ); + + CMatrix3D rotateDir; + rotateDir.SetIdentity(); + rotateDir._11 = rotateDir._33 = m_Axis.y; + rotateDir._31 = -( rotateDir._13 = m_Axis.x ); + rotateInc.Concatenate( rotateDir ); + + rotateInc._14 = m_Position_Graphics.X; + rotateInc._24 = m_Position_Graphics.Y; + rotateInc._34 = m_Position_Graphics.Z; + + m_Actor->SetTransform( rotateInc ); +} + +void CProjectile::ScriptingInit() +{ + CJSObject::ScriptingInit( "Projectile", Construct, 4 ); +} + +JSBool CProjectile::Construct( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval ) +{ + assert( argc >= 4 ); + CStr ModelString; + CVector3D Here, There; + float Speed; + CEntity* Temp, *Originator = NULL; + CObjectEntry* oe = NULL; + CModel* Model = NULL; + CScriptObject Impact, Miss; + const char* err = NULL; + + + if( Temp = ToNative( argv[0] ) ) + { + Model = Temp->m_actor->GetObject()->m_ProjectileModel; + if( !Model ) + { + err = "No projectile model is defined for that entity's actor."; + goto fail; + } + } + else if( !ToPrimitive( cx, argv[0], ModelString ) || !( oe = g_ObjMan.FindObject( ModelString ) ) || !( Model = oe->m_Model ) ) + { + err = "Invalid actor"; + goto fail; + } + if( Temp = ToNative( argv[1] ) ) + { + // Use the position vector of this entity, add a bit (so the arrow doesn't appear out of the ground) + // In future, find the appropriate position from the entity (location of a specific prop point?) + Here = Temp->m_position; + Here.Y = g_Game->GetWorld()->GetTerrain()->getExactGroundLevel( Here.X, Here.Z ) + 2.5f; + } + else if( !( ToPrimitive( cx, argv[1], Here ) ) ) + { + err = "Invalid vector"; + goto fail; + } + if( Temp = ToNative( argv[2] ) ) + { + // Use the position vector of this entity. + // TODO: Maybe: Correct for the movement of this entity. + // Then again, that doesn't belong here. + There = Temp->m_position; + There.Y = g_Game->GetWorld()->GetTerrain()->getExactGroundLevel( There.X, There.Z ) + 2.5f; + } + else if( !( ToPrimitive( cx, argv[2], There ) ) ) + { + err = "Invalid vector"; + goto fail; + } + if( ( Speed = ToPrimitive( cx, argv[3] ) ) == 0.0f ) + { + // Either wasn't specified, or was zero. In either case, + // can't allow it: div/0 errors in the physics + err = "Invalid speed"; + goto fail; + } + // Ignore errors in these last few and use the defaults if there's a problem. + + if( argc >= 5 ) + Originator = ToNative( argv[4] ); + if( argc >= 6 ) + Impact = argv[5]; // Script to run on impact with an entity. + if( argc >= 7 ) + Miss = argv[6]; // Script to run on impact with the floor. + + CProjectile* p = g_ProjectileManager.AddProjectile( Model, Here, There, Speed / 1000.0f, Originator, Impact, Miss ); + + *rval = ToJSVal( *p ); + return( JS_TRUE ); + +fail: + *rval = JSVAL_NULL; + JS_ReportError( cx, err ); + return( JS_TRUE ); +} + +CEventProjectileImpact::CEventProjectileImpact( CEntity* Originator, CEntity* Impact, const CVector3D& Position ) : CScriptEvent( L"ProjectileImpact", EVENT_IMPACT ) +{ + m_Originator = Originator; + m_Impact = Impact; + m_Position = Position; + AddLocalProperty( L"originator", &m_Originator, true ); + AddLocalProperty( L"impacted", &m_Impact ); + AddLocalProperty( L"position", &m_Position ); +} + +CEventProjectileMiss::CEventProjectileMiss( CEntity* Originator, const CVector3D& Position ) : CScriptEvent( L"ProjectileMiss", EVENT_MISS ) +{ + m_Originator = Originator; + m_Position = Position; + AddLocalProperty( L"originator", &m_Originator, true ); + AddLocalProperty( L"position", &m_Position ); +} + +CProjectileManager::CProjectileManager() +{ + m_LastTurnLength = 0; + debug_out( "CProjectileManager CREATED\n" ); +} + +CProjectileManager::~CProjectileManager() +{ + while( m_Projectiles.size() ) + delete( m_Projectiles[0] ); + debug_out( "CProjectileManager DESTROYED\n" ); +} + +CProjectile* CProjectileManager::AddProjectile( const CModel* Actor, const CVector3D& Position, const CVector3D& Target, float Speed, CEntity* Originator, const CScriptObject& ImpactScript, const CScriptObject& MissScript ) +{ + CProjectile* p = new CProjectile( Actor, Position, Target, Speed, Originator, ImpactScript, MissScript ); + m_Projectiles.push_back( p ); + return( p ); +} + +void CProjectileManager::DeleteProjectile( CProjectile* p ) +{ + delete( p ); +} + +void CProjectileManager::UpdateAll( size_t timestep ) +{ + uint i; + for( i = 0; i < m_Projectiles.size(); i++ ) + if( !( m_Projectiles[i]->Update( timestep ) ) ) + { + delete( m_Projectiles[i] ); + i--; + } +} + +void CProjectileManager::InterpolateAll( double relativeOffset ) +{ + size_t absoluteOffset = (size_t)( (double)m_LastTurnLength * relativeOffset ); + std::vector::iterator it; + for( it = m_Projectiles.begin(); it != m_Projectiles.end(); ++it ) + (*it)->Interpolate( absoluteOffset ); +} \ No newline at end of file diff --git a/source/simulation/Projectile.h b/source/simulation/Projectile.h new file mode 100644 index 0000000000..c5b54a883e --- /dev/null +++ b/source/simulation/Projectile.h @@ -0,0 +1,107 @@ +// Projectile.h +// +// Simple class that represents a single projectile in the simulation. +// +// Mark Thompson (mot20@cam.ac.uk / mark@wildfiregames.com) + +#ifndef PROJECTILE_INCLUDED +#define PROJECTILE_INCLUDED + +#include "Vector3D.h" +#include "Vector2D.h" +#include "Singleton.h" +#include "Scripting/ScriptableObject.h" +#include "scripting/DOMEvent.h" +#include "ScriptObject.h" + +class CProjectileManager; +class CModel; +class CEntity; + +class CProjectile : public CJSObject, public IEventTarget +{ + friend class CProjectileManager; + friend class CJSObject; + + CModel* m_Actor; + + CVector3D m_Position; + CVector2D m_Axis; + + CVector3D m_Position_Previous; + CVector3D m_Position_Graphics; + + // Horizontal and vertical velocities + float m_Speed_H; + float m_Speed_V; + + CEntity* m_Originator; + + CScriptObject m_ImpactEventHandler; + CScriptObject m_MissEventHandler; + + CProjectile( const CModel* Actor, const CVector3D& Position, const CVector3D& Target, float Speed, CEntity* Originator, const CScriptObject& ImpactScript, const CScriptObject& MissScript ); + ~CProjectile(); + + // Updates gameplay information for the specified timestep. Returns 'false' if the projectile should be removed from the world. + bool Update( size_t timestep_millis ); + // Updates graphical information for a point timestep_millis after the previous simulation frame (and before the current one) + void Interpolate( size_t timestep_millis ); + + // Scripty things. +public: + static void ScriptingInit(); + static JSBool Construct( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval ); + JSObject* GetScriptExecContext( IEventTarget* target ) { return( GetScript() ); } + + inline CModel* GetModel() const { return( m_Actor ); } +}; + +class CEventProjectileImpact : public CScriptEvent +{ + CEntity* m_Originator; + CEntity* m_Impact; + CVector3D m_Position; +public: + CEventProjectileImpact( CEntity* Originator, CEntity* Impact, const CVector3D& Position ); +}; + +class CEventProjectileMiss : public CScriptEvent +{ + CEntity* m_Originator; + CVector3D m_Position; +public: + CEventProjectileMiss( CEntity* Originator, const CVector3D& Position ); +}; + +// TODO: Maybe roll this (or at least the graphics bit) into the particle system? +// Initially this had g_UnitMan managing the models and g_EntityManager holding the +// projectiles themselves. This way may be less confusing - I'm not sure. + +class CProjectileManager : public Singleton +{ + friend class CProjectile; +public: + CProjectileManager(); + ~CProjectileManager(); + + void UpdateAll( size_t timestep ); + void InterpolateAll( double frametime ); + + inline const std::vector& GetProjectiles() { return m_Projectiles; } + + CProjectile* AddProjectile( const CModel* Actor, const CVector3D& Position, const CVector3D& Target, float Speed, CEntity* Originator, const CScriptObject& ImpactScript, const CScriptObject& MissScript ); + // Only if you have some reason to prematurely get rid of a projectile. + // Under normal circumstances, it will delete itself when it hits something. + void DeleteProjectile( CProjectile* p ); +private: + // Keep this so we can go from relative->absolute offsets in interpolate. + size_t m_LastTurnLength; + + // Maintain a list of the projectiles in the world + std::vector m_Projectiles; +}; + +#define g_ProjectileManager CProjectileManager::GetSingleton() + +#endif diff --git a/source/simulation/ScriptObject.cpp b/source/simulation/ScriptObject.cpp index 5be0b42470..66afb454f7 100755 --- a/source/simulation/ScriptObject.cpp +++ b/source/simulation/ScriptObject.cpp @@ -31,6 +31,7 @@ void CScriptObject::Uproot() CScriptObject::CScriptObject( JSFunction* _Function ) { + Function = NULL; SetFunction( _Function ); } @@ -40,6 +41,12 @@ CScriptObject::CScriptObject( jsval v ) SetJSVal( v ); } +CScriptObject::CScriptObject( const CScriptObject& copy ) +{ + Function = NULL; + SetFunction( copy.Function ); +} + void CScriptObject::SetFunction( JSFunction* _Function ) { Uproot(); diff --git a/source/simulation/ScriptObject.h b/source/simulation/ScriptObject.h index 968be382be..b63bc0402a 100755 --- a/source/simulation/ScriptObject.h +++ b/source/simulation/ScriptObject.h @@ -19,11 +19,15 @@ class CScriptObject void Root(); void Uproot(); + // TODO: Remove, debugging + static int count; + public: CScriptObject(); CScriptObject( JSFunction* _Function ); CScriptObject( jsval v ); + CScriptObject( const CScriptObject& copy ); ~CScriptObject(); diff --git a/source/simulation/Simulation.cpp b/source/simulation/Simulation.cpp index b67bbeb547..2c7943040f 100755 --- a/source/simulation/Simulation.cpp +++ b/source/simulation/Simulation.cpp @@ -7,6 +7,7 @@ #include "TurnManager.h" #include "Game.h" #include "EntityManager.h" +#include "Projectile.h" #include "Scheduler.h" #include "Network/NetMessage.h" #include "CLogger.h" @@ -66,6 +67,21 @@ void CSimulation::Update(double frameTime) // frames as fast as possible. m_DeltaTime = 0.0; } + + /* + // TODO Remove + // Fountain of arrows + CObjectEntry* arrow = g_ObjMan.FindObject( "props/weapon/weap_arrow_front.xml" ); + assert( arrow ); + + float mapsize = (float)( m_pWorld->GetTerrain()->GetVerticesPerSide() * 4 ); + + CVector3D here( mapsize / 2, m_pWorld->GetTerrain()->getExactGroundLevel( mapsize / 2, mapsize / 2 ), mapsize / 2 ); + float x = ( rand() % 1000 ) * mapsize / 1000.0f; + float y = ( rand() % 1000 ) * mapsize / 1000.0f; + CVector3D there( x, m_pWorld->GetTerrain()->getExactGroundLevel( x, y ), y ); + g_ProjectileManager.AddProjectile( arrow->m_Model, here, there, 0.006f, NULL ); + */ } PROFILE_START( "simulation interpolation" ); @@ -79,7 +95,8 @@ void CSimulation::Interpolate(double frameTime, double offset) for (uint i=0;iGetModel()->Update((float)frameTime); - g_EntityManager.interpolateAll((float)offset); + g_EntityManager.interpolateAll( (float)offset ); + g_ProjectileManager.InterpolateAll( (float)offset ); } void CSimulation::Simulate() @@ -92,6 +109,10 @@ void CSimulation::Simulate() g_EntityManager.updateAll( m_pTurnManager->GetTurnLength() ); PROFILE_END( "entity updates" ); + PROFILE_START( "projectile updates" ); + g_ProjectileManager.UpdateAll( m_pTurnManager->GetTurnLength() ); + PROFILE_END( "projectile updates" ); + PROFILE_START( "turn manager update" ); m_pTurnManager->NewTurn(); m_pTurnManager->IterateBatch(0, TranslateMessage, this);