diff --git a/binaries/data/mods/official/art/actors/units/celt_isp_a.xml b/binaries/data/mods/official/art/actors/units/celt_isp_a.xml index c6f4d04106..e348d505d2 100644 --- a/binaries/data/mods/official/art/actors/units/celt_isp_a.xml +++ b/binaries/data/mods/official/art/actors/units/celt_isp_a.xml @@ -9,10 +9,10 @@ - + - + skeletal/m_pants_c.pmd diff --git a/binaries/data/mods/official/art/actors/units/celt_isp_b.xml b/binaries/data/mods/official/art/actors/units/celt_isp_b.xml index d2b1a068dd..15d1d455c6 100644 --- a/binaries/data/mods/official/art/actors/units/celt_isp_b.xml +++ b/binaries/data/mods/official/art/actors/units/celt_isp_b.xml @@ -9,10 +9,10 @@ - + - + skeletal/m_pants_c.pmd diff --git a/binaries/data/mods/official/art/actors/units/celt_isp_e.xml b/binaries/data/mods/official/art/actors/units/celt_isp_e.xml index 4b6f9740c3..30ba13a20d 100644 --- a/binaries/data/mods/official/art/actors/units/celt_isp_e.xml +++ b/binaries/data/mods/official/art/actors/units/celt_isp_e.xml @@ -9,10 +9,10 @@ - + - + diff --git a/binaries/data/mods/official/entities/gaia/template_gaia.xml b/binaries/data/mods/official/entities/gaia/template_gaia.xml index 3f27974d39..a87562df86 100755 --- a/binaries/data/mods/official/entities/gaia/template_gaia.xml +++ b/binaries/data/mods/official/entities/gaia/template_gaia.xml @@ -12,8 +12,7 @@ version="0.1 pasap2" class1="Gaia" - type.gaia="true" - type.gaia.group="true" + classes="gaia" /> \ No newline at end of file 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 d9bb455783..7e22dd4d04 100755 --- a/binaries/data/mods/official/entities/gaia/template_gaia_fauna.xml +++ b/binaries/data/mods/official/entities/gaia/template_gaia_fauna.xml @@ -6,7 +6,7 @@ generic="Generic Fauna" class2="Fauna" - type.gaia.group.fauna="true" + classes="gaia_fauna" /> diff --git a/binaries/data/mods/official/entities/gaia/template_gaia_flora_bush_berry.xml b/binaries/data/mods/official/entities/gaia/template_gaia_flora_bush_berry.xml index 7e831f2374..7112dae72c 100644 --- a/binaries/data/mods/official/entities/gaia/template_gaia_flora_bush_berry.xml +++ b/binaries/data/mods/official/entities/gaia/template_gaia_flora_bush_berry.xml @@ -8,8 +8,8 @@ icon="flora_deciduotree" - type.gaia.group.resource="true" - + classes="gaia_resource" + rollover="Foragers can gather the fruit from these bushes to accumulate Food." history="Berries are tasty, fruity, and scrunchiously crunchable." diff --git a/binaries/data/mods/official/entities/gaia/template_gaia_flora_tree.xml b/binaries/data/mods/official/entities/gaia/template_gaia_flora_tree.xml index dd41404fce..9ec3b773d0 100755 --- a/binaries/data/mods/official/entities/gaia/template_gaia_flora_tree.xml +++ b/binaries/data/mods/official/entities/gaia/template_gaia_flora_tree.xml @@ -6,7 +6,7 @@ generic="Tree" class3="Tree" - type.gaia.group.resource="true" + classes="gaia_resource" rollover="Chop these down to accumulate Wood." /> 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 7c3214af8e..ef4004f402 100755 --- a/binaries/data/mods/official/entities/gaia/template_gaia_geo.xml +++ b/binaries/data/mods/official/entities/gaia/template_gaia_geo.xml @@ -6,7 +6,7 @@ generic="Generic Geology" class2="Geo" - type.gaia.group.geo="true" + classes="gaia_geo" /> 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 1610659d32..05900383f8 100755 --- a/binaries/data/mods/official/entities/gaia/template_gaia_special.xml +++ b/binaries/data/mods/official/entities/gaia/template_gaia_special.xml @@ -6,6 +6,7 @@ generic="Generic Special" class2="Special" + classes="gaia_special" type.gaia.group.special="true" /> - \ No newline at end of file diff --git a/binaries/data/mods/official/entities/other/template_other.xml b/binaries/data/mods/official/entities/other/template_other.xml index 76bca6819c..f3799fb8ad 100755 --- a/binaries/data/mods/official/entities/other/template_other.xml +++ b/binaries/data/mods/official/entities/other/template_other.xml @@ -10,8 +10,6 @@ version="0.1 pasap2" class1="Other" - type.other="true" - type.other.group="true" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/other/template_other_projectile.xml b/binaries/data/mods/official/entities/other/template_other_projectile.xml index b0b2bda485..ff989b525b 100755 --- a/binaries/data/mods/official/entities/other/template_other_projectile.xml +++ b/binaries/data/mods/official/entities/other/template_other_projectile.xml @@ -6,7 +6,7 @@ generic="Generic Projectile" class2="Projectile" - type.other.group.projectile="true" + classes="projectile" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/other/template_other_special.xml b/binaries/data/mods/official/entities/other/template_other_special.xml index c1a0233000..82a60c7433 100755 --- a/binaries/data/mods/official/entities/other/template_other_special.xml +++ b/binaries/data/mods/official/entities/other/template_other_special.xml @@ -6,7 +6,7 @@ generic="Generic Special" class2="Special" - type.other.group.special="true" + classes="special" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/structures/template_structure.xml b/binaries/data/mods/official/entities/structures/template_structure.xml index 58de196025..15b617a69f 100755 --- a/binaries/data/mods/official/entities/structures/template_structure.xml +++ b/binaries/data/mods/official/entities/structures/template_structure.xml @@ -11,10 +11,7 @@ version="0.1 pasap2" class1="Structure" - type.structure="true" - type.structure.group="true" - type.structure.phase="true" - type.structure.material="true" + classes="structure" /> \ 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 b386bda42d..1df4b0e8b8 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 @@ -9,8 +9,7 @@ rollover="The heart of the player's empire. Trains economic units, and can only be built on settlements." - type.structure.group.housing="true" - type.structure.phase.vp="true" + classes="structure_housing, structure_village" /> 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 fd65b6eb5c..ca221f21ed 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 @@ -9,7 +9,7 @@ rollover="Herd domestic animals into a Corral, and they will provide Food for your civilisation." - type.structure.phase.vp="true" + classes="structure_village" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_cavalry_melee_csp.xml b/binaries/data/mods/official/entities/units/template_unit_cavalry_melee_csp.xml index 5d4786e770..855daed90b 100755 --- a/binaries/data/mods/official/entities/units/template_unit_cavalry_melee_csp.xml +++ b/binaries/data/mods/official/entities/units/template_unit_cavalry_melee_csp.xml @@ -7,10 +7,9 @@ icon_cell="15" - type.unit.mounted.spear="true" - type.unit.weapon.spear="true" + classes="unit_mounted_spear, unit_spear" - rollover="This was the weapon of choice from horseback. This was the unit that would eventually evolve to the medieval knight (after heavy influence by the Sarmartians and their lances). Infantry were an easy kill; just ride them down and skewer them with your stick and its point on the end. As with all cavalry – it was only the rich and the nobles who were able to fight from horseback due to the cost of owning such a beast." + rollover="This was the weapon of choice from horseback. This was the unit that would eventually evolve to the medieval knight (after heavy influence by the Sarmartians and their lances). Infantry were an easy kill; just ride them down and skewer them with your stick and its point on the end. As with all cavalry - it was only the rich and the nobles who were able to fight from horseback due to the cost of owning such a beast." /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_cavalry_melee_csw.xml b/binaries/data/mods/official/entities/units/template_unit_cavalry_melee_csw.xml index ce3e793692..6dd5b601ac 100755 --- a/binaries/data/mods/official/entities/units/template_unit_cavalry_melee_csw.xml +++ b/binaries/data/mods/official/entities/units/template_unit_cavalry_melee_csw.xml @@ -7,10 +7,9 @@ icon_cell="18" - type.unit.mounted.sword="true" - type.unit.weapon.sword="true" + classes="unit_mounted_sword, unit_sword" - rollover="Fighting from horseback with a sword is a tricky thing to do. This required usage of a sword that was longer than the typical infantry sword. One needed a good reach to attack from the height of a horse. If you were without spear (the ideal weapon of choice) it was probably because you needed your hands free to do other tasks such as riding hard and fast. It wasn’t uncommon for the men to dismount and attack from foot if they were armed with only a sword." + rollover="Fighting from horseback with a sword is a tricky thing to do. This required usage of a sword that was longer than the typical infantry sword. One needed a good reach to attack from the height of a horse. If you were without spear (the ideal weapon of choice) it was probably because you needed your hands free to do other tasks such as riding hard and fast. It wasn't uncommon for the men to dismount and attack from foot if they were armed with only a sword." /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_cavalry_ranged.xml b/binaries/data/mods/official/entities/units/template_unit_cavalry_ranged.xml index 386d256891..a0f4a3af5e 100755 --- a/binaries/data/mods/official/entities/units/template_unit_cavalry_ranged.xml +++ b/binaries/data/mods/official/entities/units/template_unit_cavalry_ranged.xml @@ -6,8 +6,8 @@ generic="Generic Ranged Cavalry Unit" class3="Ranged" - - type.unit.attack.ranged="true" + + classes="unit_ranged" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_cavalry_ranged_car.xml b/binaries/data/mods/official/entities/units/template_unit_cavalry_ranged_car.xml index ee938bd815..ed256f526f 100755 --- a/binaries/data/mods/official/entities/units/template_unit_cavalry_ranged_car.xml +++ b/binaries/data/mods/official/entities/units/template_unit_cavalry_ranged_car.xml @@ -7,10 +7,9 @@ icon_cell="24" - type.unit.mounted.bow="true" - type.unit.weapon.bow="true" - - rollover="A very rare unit in Part 1. It was used by the Persians, but it didn’t gain much traction until the Parthians, Huns, Mongols, and other people of the nomadic steeps introduced them to western Europe. This was the most effective unit on the battlefield for several hundred years until the well armoured knight came along. Therefore, this unit will gain much more prominence in Part 2." + classes="unit_mounted_bow, unit_bow" + + rollover="A very rare unit in Part 1. It was used by the Persians, but it didn't gain much traction until the Parthians, Huns, Mongols, and other people of the nomadic steeps introduced them to western Europe. This was the most effective unit on the battlefield for several hundred years until the well armoured knight came along. Therefore, this unit will gain much more prominence in Part 2." /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_cavalry_ranged_cjv.xml b/binaries/data/mods/official/entities/units/template_unit_cavalry_ranged_cjv.xml index 639680b6ae..1084499174 100755 --- a/binaries/data/mods/official/entities/units/template_unit_cavalry_ranged_cjv.xml +++ b/binaries/data/mods/official/entities/units/template_unit_cavalry_ranged_cjv.xml @@ -7,10 +7,9 @@ icon_cell="21" - type.unit.mounted.javelin="true" - type.unit.weapon.javelin="true" - - rollover="The javelins thrown from a horse’s back were probably 3 at most. The idea was to quickly advance with 3 in hand, then throw them all. After you had done that it was time to switch to your secondary weapon which was usually a spear or a sword. However, in the game - these units will only have ranged attack." + classes="unit_mounted_javelin, unit_javelin" + + rollover="The javelins thrown from a horse's back were probably 3 at most. The idea was to quickly advance with 3 in hand, then throw them all. After you had done that it was time to switch to your secondary weapon which was usually a spear or a sword. However, in the game - these units will only have ranged attack." /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_hero.xml b/binaries/data/mods/official/entities/units/template_unit_hero.xml index 362a50f794..50433ac8ab 100755 --- a/binaries/data/mods/official/entities/units/template_unit_hero.xml +++ b/binaries/data/mods/official/entities/units/template_unit_hero.xml @@ -7,9 +7,7 @@ class2="Hero" - type.unit.group.military="true" - type.unit.group.hero="true" - type.unit.material.organic="true" + classes="unit_military, unit_hero, unit_organic" /> - + - + + diff --git a/binaries/data/mods/official/entities/units/template_unit_infantry_melee.xml b/binaries/data/mods/official/entities/units/template_unit_infantry_melee.xml index ef4f95933b..f15c727d8b 100755 --- a/binaries/data/mods/official/entities/units/template_unit_infantry_melee.xml +++ b/binaries/data/mods/official/entities/units/template_unit_infantry_melee.xml @@ -7,7 +7,7 @@ class3="Melee" - type.unit.attack.melee="true" + classes="unit_melee" /> diff --git a/binaries/data/mods/official/entities/units/template_unit_infantry_melee_isp.xml b/binaries/data/mods/official/entities/units/template_unit_infantry_melee_isp.xml index 40f59957b4..36f4f70f6d 100755 --- a/binaries/data/mods/official/entities/units/template_unit_infantry_melee_isp.xml +++ b/binaries/data/mods/official/entities/units/template_unit_infantry_melee_isp.xml @@ -7,9 +7,9 @@ icon_cell="3" - type.unit.foot.spear="true" - type.unit.weapon.spear="true" - rollover="Probably one of the most primitive units in the game. Fighting with a sharp object at the end of the pole didn’t require a lot of technology to develop. It also allowed the human to distance themselves from their attacker. As time passed the spears got longer and longer. Started with a fighting style similar to using a quarterstaff, then to using them in numbers as a ‘pin cushion’ vs. humans (sarissa in a phalanx). Later it was developed to combat cavalry. During the medieval period it evolved to the pike. These units tended to be armoured as heavily as possible." + classes="unit_foot_spear, unit_spear" + + rollover="Probably one of the most primitive units in the game. Fighting with a sharp object at the end of the pole didn't require a lot of technology to develop. It also allowed the human to distance themselves from their attacker. As time passed the spears got longer and longer. Started with a fighting style similar to using a quarterstaff, then to using them in numbers as a 'pin cushion' vs. humans (sarissa in a phalanx). Later it was developed to combat cavalry. During the medieval period it evolved to the pike. These units tended to be armoured as heavily as possible." /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_infantry_melee_isw.xml b/binaries/data/mods/official/entities/units/template_unit_infantry_melee_isw.xml index 8e2b99fa92..ce0ec42ce6 100755 --- a/binaries/data/mods/official/entities/units/template_unit_infantry_melee_isw.xml +++ b/binaries/data/mods/official/entities/units/template_unit_infantry_melee_isw.xml @@ -7,8 +7,8 @@ icon_cell="0" - type.unit.foot.sword="true" - type.unit.weapon.sword="true" + classes="unit_foot_sword, unit_sword" + rollover="Weapon is basically a developed sickle. Probably from the club, to the axe, to the sickle to the sword. It was the Romans who used them to combat the long range of the sarissa. Their spears were so long they had to use two hands to wield them. In a formation they were almost impossible to maneouvre. If flanked, they were easily cut down by a sword as demonstrated by the Romans at the battle of Cynoscephalae. Generally swordsmen were well armoured, had shields, and tended to be nobles. A good sword was an expensive weapon." /> 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 4c274f93b1..af713b72b4 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 @@ -7,7 +7,7 @@ class3="Ranged" - type.unit.attack.ranged="true" + classes="unit_ranged" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_infantry_ranged_iar.xml b/binaries/data/mods/official/entities/units/template_unit_infantry_ranged_iar.xml index 5d7f33aeea..7ec278e2c1 100755 --- a/binaries/data/mods/official/entities/units/template_unit_infantry_ranged_iar.xml +++ b/binaries/data/mods/official/entities/units/template_unit_infantry_ranged_iar.xml @@ -7,9 +7,9 @@ icon_cell="9" - type.unit.foot.bow="true" - type.unit.weapon.bow="true" - rollover="They tended to be lightly armoured. They usually only participated in the first stage of a battle, sending a volley of arrows raining down the enemy. Of course they would have to stop shooting once the melee units closed in. This means their job was largely over once the ‘true battle’ was underway. They spent hours training with a bow, but if you were hit by an arrow it was more likely an act of random chance than being specifically targeted by an archer." + classes="unit_foot_bow, unit_bow" + + rollover="They tended to be lightly armoured. They usually only participated in the first stage of a battle, sending a volley of arrows raining down the enemy. Of course they would have to stop shooting once the melee units closed in. This means their job was largely over once the 'true battle' was underway. They spent hours training with a bow, but if you were hit by an arrow it was more likely an act of random chance than being specifically targeted by an archer." /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_infantry_ranged_ijv.xml b/binaries/data/mods/official/entities/units/template_unit_infantry_ranged_ijv.xml index 6ea5eb98ee..a33f040223 100755 --- a/binaries/data/mods/official/entities/units/template_unit_infantry_ranged_ijv.xml +++ b/binaries/data/mods/official/entities/units/template_unit_infantry_ranged_ijv.xml @@ -7,9 +7,9 @@ icon_cell="6" - type.unit.foot.javelin="true" - type.unit.weapon.javelin="true" - rollover="These were the skirmishers. These lightly armoured units would advance quickly, throw a hail of javelins and then retreat back to their ranks. Grab another spear and repeat. They would do well against any unit that wasn’t wearing proper armour, but more poorly if they fought hand to hand vs a well armoured unit. They didn’t always have to thow their spears either. They used these light small spears in hand to hand similar to a quarterstaff. Also note that the development of the pilum was a key transition. This pilum was a weapon with a long steel shaft that would sink into a shield, nearly impossible to remove. This rendered the shield useless. They also weighted and balanced them to make them accurately hit with a punch." + classes="unit_foot_javelin, unit_javelin" + + rollover="These were the skirmishers. These lightly armoured units would advance quickly, throw a hail of javelins and then retreat back to their ranks. Grab another spear and repeat. They would do well against any unit that wasn't wearing proper armour, but more poorly if they fought hand to hand vs a well armoured unit. They didn't always have to thow their spears either. They used these light small spears in hand to hand similar to a quarterstaff. Also note that the development of the pilum was a key transition. This pilum was a weapon with a long steel shaft that would sink into a shield, nearly impossible to remove. This rendered the shield useless. They also weighted and balanced them to make them accurately hit with a punch." /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_infantry_ranged_isl.xml b/binaries/data/mods/official/entities/units/template_unit_infantry_ranged_isl.xml index 280e5d9644..c66113d287 100755 --- a/binaries/data/mods/official/entities/units/template_unit_infantry_ranged_isl.xml +++ b/binaries/data/mods/official/entities/units/template_unit_infantry_ranged_isl.xml @@ -7,10 +7,9 @@ icon_cell="12" - type.unit.foot.sling="true" - type.unit.weapon.sling="true" - - rollover="They were amazing shots with their slings. They used choice rocks, and often specifically created ‘shot’ made from lead. They could pierce armour at close distances. They were lightly armoured because they needed the mobility in their arm regions. However, in the game we are making a gameplay consideration to have slingers act as 'mini-organic-onagers' that may cause damage to structures." + classes="unit_foot_sling, unit_sling" + + rollover="They were amazing shots with their slings. They used choice rocks, and often specifically created 'shot' made from lead. They could pierce armour at close distances. They were lightly armoured because they needed the mobility in their arm regions. However, in the game we are making a gameplay consideration to have slingers act as 'mini-organic-onagers' that may cause damage to structures." /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_mechanical.xml b/binaries/data/mods/official/entities/units/template_unit_mechanical.xml index dd75c1319d..2c4356506d 100755 --- a/binaries/data/mods/official/entities/units/template_unit_mechanical.xml +++ b/binaries/data/mods/official/entities/units/template_unit_mechanical.xml @@ -7,8 +7,7 @@ class2="Mechanical" - type.unit.group.military="true" - type.unit.material.mechanical="true" + classes="unit_military, unit_mechanical" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_bir.xml b/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_bir.xml index 430093efe8..ec5dd1261d 100755 --- a/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_bir.xml +++ b/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_bir.xml @@ -7,7 +7,7 @@ icon_cell="39" - type.unit.group.warship="true" + classes="unit_warship" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_mer.xml b/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_mer.xml index a810b675ef..08519944d3 100755 --- a/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_mer.xml +++ b/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_mer.xml @@ -2,13 +2,14 @@ + \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_qui.xml b/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_qui.xml index a78ac59805..5d124e13da 100755 --- a/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_qui.xml +++ b/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_qui.xml @@ -6,8 +6,8 @@ generic="Quinquereme" icon_cell="41" - - type.unit.group.warship="true" + + classes="unit_warship" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_tri.xml b/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_tri.xml index c5ff9f4f87..5c50000e9e 100755 --- a/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_tri.xml +++ b/binaries/data/mods/official/entities/units/template_unit_mechanical_ship_tri.xml @@ -7,7 +7,7 @@ icon_cell="40" - type.unit.group.warship="true" + classes="unit_warship" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_mechanical_siege.xml b/binaries/data/mods/official/entities/units/template_unit_mechanical_siege.xml index f9c18c7541..3985023ac5 100755 --- a/binaries/data/mods/official/entities/units/template_unit_mechanical_siege.xml +++ b/binaries/data/mods/official/entities/units/template_unit_mechanical_siege.xml @@ -7,7 +7,7 @@ class3="Siege" - type.unit.group.siege="true" + classes="unit_siege" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_mechanical_siege_bal.xml b/binaries/data/mods/official/entities/units/template_unit_mechanical_siege_bal.xml index 5455307162..f79cac7243 100755 --- a/binaries/data/mods/official/entities/units/template_unit_mechanical_siege_bal.xml +++ b/binaries/data/mods/official/entities/units/template_unit_mechanical_siege_bal.xml @@ -7,7 +7,7 @@ icon_cell="37" - type.unit.attack.ranged="true" + classes="unit_ranged" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_mechanical_siege_ong.xml b/binaries/data/mods/official/entities/units/template_unit_mechanical_siege_ong.xml index ee441ab726..4e537a613f 100755 --- a/binaries/data/mods/official/entities/units/template_unit_mechanical_siege_ong.xml +++ b/binaries/data/mods/official/entities/units/template_unit_mechanical_siege_ong.xml @@ -7,7 +7,7 @@ icon_cell="35" - type.unit.attack.ranged="true" + classes="unit_ranged" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_mechanical_siege_ram.xml b/binaries/data/mods/official/entities/units/template_unit_mechanical_siege_ram.xml index c87b67602a..6f375de38e 100755 --- a/binaries/data/mods/official/entities/units/template_unit_mechanical_siege_ram.xml +++ b/binaries/data/mods/official/entities/units/template_unit_mechanical_siege_ram.xml @@ -7,7 +7,7 @@ icon_cell="36" - type.unit.attack.melee="true" + classes="unit_melee" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_superunit.xml b/binaries/data/mods/official/entities/units/template_unit_superunit.xml index 39e9652ec3..acaaea0f12 100755 --- a/binaries/data/mods/official/entities/units/template_unit_superunit.xml +++ b/binaries/data/mods/official/entities/units/template_unit_superunit.xml @@ -7,8 +7,7 @@ class2="Super Unit" - type.unit.group.military="true" - type.unit.group.superunit="true" + classes="unit_military, unit_superunit" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_superunit_siu.xml b/binaries/data/mods/official/entities/units/template_unit_superunit_siu.xml index 8cecbe96d4..9d444a5ef2 100755 --- a/binaries/data/mods/official/entities/units/template_unit_superunit_siu.xml +++ b/binaries/data/mods/official/entities/units/template_unit_superunit_siu.xml @@ -9,8 +9,7 @@ class3="Super Infantry Unit" - type.unit.material.organic="true" - type.unit.foot="true" + classes="unit_organic, unit_foot" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_superunit_ssu.xml b/binaries/data/mods/official/entities/units/template_unit_superunit_ssu.xml index 1b35388b5a..7747922965 100755 --- a/binaries/data/mods/official/entities/units/template_unit_superunit_ssu.xml +++ b/binaries/data/mods/official/entities/units/template_unit_superunit_ssu.xml @@ -9,8 +9,7 @@ class3="Super Siege Unit" - type.unit.material.mechanical="true" - type.unit.group.siege="true" + classes="unit_mechanical, unit_siege" /> \ No newline at end of file diff --git a/binaries/data/mods/official/entities/units/template_unit_support.xml b/binaries/data/mods/official/entities/units/template_unit_support.xml index baf1f62300..b5e50c8c46 100755 --- a/binaries/data/mods/official/entities/units/template_unit_support.xml +++ b/binaries/data/mods/official/entities/units/template_unit_support.xml @@ -9,7 +9,8 @@ personal2="female_names_2nd.csv" class2="Support" - type.unit.support="true" + + classes="unit_support" /> diff --git a/binaries/data/mods/official/gui/test/functions_session_team_tray.js b/binaries/data/mods/official/gui/test/functions_session_team_tray.js index bb283bdf72..0342e8e122 100755 --- a/binaries/data/mods/official/gui/test/functions_session_team_tray.js +++ b/binaries/data/mods/official/gui/test/functions_session_team_tray.js @@ -27,12 +27,21 @@ function SelectGroup(groupNumber) // Set the current selection to the specified group (team) number, 1-9. // If the group is already selected, centre on the group. + console.write( groupNumber ); + if (groups[groupNumber].length > 0) { // If group already selected, - if (selection == groups[groupNumber]) + if (selection.equals( groups[groupNumber] ) ) { - setCameraTarget(selection[0].position); // Centre on it. + // Find the average position of the group + position_avg = new Vector3D(); + for( t = 0; t < selection.length; t++ ) + position_avg = position_avg.add( selection[t].position ); + + position_avg = position_avg.divide( selection.length ); + + setCameraTarget( position_avg ); // Centre on it. } else selection = groups[groupNumber]; // If not, select it. diff --git a/source/graphics/Model.cpp b/source/graphics/Model.cpp index cd3fe11f11..8e7f149637 100755 --- a/source/graphics/Model.cpp +++ b/source/graphics/Model.cpp @@ -181,6 +181,11 @@ void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result) transform.SetIdentity(); SetTransform(transform); + // Following seems to stomp over the current animation time - which, unsurprisingly, + // introduces artefacts in the currently playing animation. Save it here and restore it + // at the end. + float AnimTime = m_AnimTime; + // iterate through every frame of the animation for (uint j=0;jGetNumFrames();j++) { // extend bounds by vertex positions at the frame @@ -194,12 +199,13 @@ void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result) } SetTransform(oldtransform); + m_AnimTime = AnimTime; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // BuildAnimation: load raw animation frame animation from given file, and build a // animation specific to this model -CSkeletonAnim* CModel::BuildAnimation(const char* filename,float speed,size_t actionpos) +CSkeletonAnim* CModel::BuildAnimation(const char* filename,float speed,double actionpos) { CSkeletonAnimDef* def=g_SkelAnimMan.GetAnimation(filename); if (!def) return 0; @@ -207,9 +213,7 @@ CSkeletonAnim* CModel::BuildAnimation(const char* filename,float speed,size_t ac CSkeletonAnim* anim=new CSkeletonAnim; anim->m_AnimDef=def; anim->m_Speed=speed; - anim->m_ActionPos=actionpos; - if( actionpos > anim->m_AnimDef->GetDuration() ) - anim->m_ActionPos = anim->m_AnimDef->GetDuration(); + anim->m_ActionPos=(size_t)( actionpos * anim->m_AnimDef->GetDuration() ); anim->m_ObjectBounds.SetEmpty(); InvalidateBounds(); diff --git a/source/graphics/Model.h b/source/graphics/Model.h index 55cbaad3ed..8c60df0218 100755 --- a/source/graphics/Model.h +++ b/source/graphics/Model.h @@ -102,7 +102,7 @@ public: // load raw animation frame animation from given file, and build a // animation specific to this model - CSkeletonAnim* BuildAnimation(const char* filename,float speed,size_t actionpos); + CSkeletonAnim* BuildAnimation(const char* filename,float speed, double actionpos); // add a prop to the model on the given point void AddProp(SPropPoint* point,CModel* model); diff --git a/source/graphics/ObjectBase.cpp b/source/graphics/ObjectBase.cpp index d3ca7ad880..7a252945fa 100644 --- a/source/graphics/ObjectBase.cpp +++ b/source/graphics/ObjectBase.cpp @@ -159,7 +159,7 @@ bool CObjectBase::Load(const char* filename) AT(file); AT(name); AT(speed); - AT(actionpos); + AT(event); AT(attachpoint); AT(actor); AT(frequency); @@ -220,10 +220,12 @@ bool CObjectBase::Load(const char* filename) anim.m_Speed = CStr(ae.Value).ToInt() / 100.f; if (anim.m_Speed <= 0.0) anim.m_Speed = 1.0f; } - else if (ae.Name == at_actionpos) + else if (ae.Name == at_event) { - anim.m_ActionPos = CStr(ae.Value).ToInt(); - if (anim.m_ActionPos < 0) anim.m_ActionPos = 0; + anim.m_ActionPos = CStr(ae.Value).ToDouble(); + if (anim.m_ActionPos < 0.0) anim.m_ActionPos = 0.0; + else if (anim.m_ActionPos > 100.0) anim.m_ActionPos = 1.0; + else if (anim.m_ActionPos > 1.0) anim.m_ActionPos /= 100.0; } else ; // unrecognised element diff --git a/source/graphics/ObjectBase.h b/source/graphics/ObjectBase.h index 358923561f..da451836ab 100644 --- a/source/graphics/ObjectBase.h +++ b/source/graphics/ObjectBase.h @@ -13,7 +13,7 @@ public: struct Anim { // constructor - Anim() : m_Speed(1), m_ActionPos( 0 ), m_AnimData(0) {} + Anim() : m_Speed(1), m_ActionPos( 0.0 ), m_AnimData(0) {} // name of the animation - "Idle", "Run", etc CStr m_AnimName; @@ -21,8 +21,10 @@ public: CStr m_FileName; // animation speed, as specified in XML actor file float m_Speed; - // time during the animation at which the interesting bit happens (msec) - size_t m_ActionPos; + // fraction of the way through the animation that the interesting bit + // happens (this is converted to an absolute time when the animation + // data is loaded) + double m_ActionPos; // the animation data, specific to the this model CSkeletonAnim* m_AnimData; }; diff --git a/source/lib/sysdep/sysdep.h b/source/lib/sysdep/sysdep.h index ccbbe910bc..870645d257 100755 --- a/source/lib/sysdep/sysdep.h +++ b/source/lib/sysdep/sysdep.h @@ -62,12 +62,15 @@ extern float fmaxf(float a, float b); // C++ linkage -// STL_HASH_MAP, STL_HASH_MULTIMAP +// STL_HASH_MAP, STL_HASH_MULTIMAP, STL_HASH_SET #ifdef __GNUC__ // GCC # include +# include // Probably? + # define STL_HASH_MAP __gnu_cxx::hash_map # define STL_HASH_MULTIMAP __gnu_cxx::hash_multimap +# define STL_HASH_SET __gnu_cxx::hash_set // Hack: GCC Doesn't have a hash instance for std::string included (and it looks // like they won't add it - marked resolved/wontfix in the gcc bugzilla) @@ -84,14 +87,17 @@ namespace __gnu_cxx #else // !__GNUC__ # include +# include # if defined(_MSC_VER) && (_MSC_VER >= 1300) // VC7 or above # define STL_HASH_MAP stdext::hash_map # define STL_HASH_MULTIMAP stdext::hash_multimap +# define STL_HASH_SET stdext::hash_set # else // VC6 and anything else (most likely name) # define STL_HASH_MAP std::hash_map # define STL_HASH_MULTIMAP std::hash_multimap +# define STL_HASH_SET std::hash_set # endif // defined(_MSC_VER) && (_MSC_VER >= 1300) #endif // !__GNUC__ diff --git a/source/ps/scripting/JSCollection.h b/source/ps/scripting/JSCollection.h index 31a1564f1b..2ad10a44d7 100755 --- a/source/ps/scripting/JSCollection.h +++ b/source/ps/scripting/JSCollection.h @@ -37,7 +37,8 @@ private: static JSBool Remove( JSContext* cx, JSObject* obj, uintN argc, jsval* agv, jsval* rval ); static JSBool GetLength( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); static JSBool IsEmpty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); - static JSBool Clear( JSContext* cx, JSObject* obj, uintN argc, jsval* agv, jsval* rval ); + static JSBool Clear( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval ); + static JSBool Equals( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval ); static JSBool AddProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); static JSBool RemoveProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); static JSBool GetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); @@ -77,12 +78,13 @@ template JSFunctionSpec CJSCollection std::vector* CJSCollection::RetrieveSet( JSContext* cx, JSObject* obj ) { - CJSCollectionData* Info = (CJSCollectionData*)JS_GetPrivate( cx, obj ); + CJSCollectionData* Info = (CJSCollectionData*)JS_GetInstancePrivate( cx, obj, &JSI_class, NULL ); if( !Info ) return( NULL ); return( Info->m_Data ); } @@ -272,6 +274,43 @@ template JSBool CJSCollection::I return( JS_TRUE ); } +template JSBool CJSCollection::Equals( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval ) +{ + std::vector* a = RetrieveSet( cx, obj ); + if( !a ) + return( JS_FALSE ); + if( ( argc == 0 ) || ( !JSVAL_IS_OBJECT( argv[0] ) ) ) return( JS_FALSE ); + std::vector* b = RetrieveSet( cx, JSVAL_TO_OBJECT( argv[0] ) ); + if( !b ) + return( JS_FALSE ); + std::vector::iterator ita, itb; + + size_t seek = a->size(); + for( ita = a->begin(); ita != a->end(); ita++ ) + for( itb = b->begin(); itb != b->end(); itb++ ) + if( *ita == *itb ) { seek--; break; } + + if( seek ) + { + *rval = JSVAL_FALSE; + return( JS_TRUE ); + } + + seek = b->size(); + for( itb = b->begin(); itb != b->end(); itb++ ) + for( ita = a->begin(); ita != a->end(); ita++ ) + if( *ita == *itb ) { seek--; break; } + + if( seek ) + { + *rval = JSVAL_FALSE; + return( JS_TRUE ); + } + + *rval = JSVAL_TRUE; + return( JS_TRUE ); +} + template JSBool CJSCollection::Subset( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval ) { assert( argc > 0 ); diff --git a/source/scripting/ScriptableComplex.h b/source/scripting/ScriptableComplex.h index e838f1ea23..898225fa80 100644 --- a/source/scripting/ScriptableComplex.h +++ b/source/scripting/ScriptableComplex.h @@ -78,6 +78,9 @@ public: // Rebuild any intrinsic (mapped-to-C++-variable) properties virtual void Rebuild() = 0; + // HACK: Doesn't belong here. + virtual void rebuildClassSet() = 0; + // Check for a property virtual IJSComplexProperty* HasProperty( CStrW PropertyName ) = 0; diff --git a/source/simulation/BaseEntity.cpp b/source/simulation/BaseEntity.cpp index 4bcff6b431..2dc69fda0b 100755 --- a/source/simulation/BaseEntity.cpp +++ b/source/simulation/BaseEntity.cpp @@ -17,8 +17,12 @@ CBaseEntity::CBaseEntity() AddProperty( L"parent", &m_base, false ); AddProperty( L"actions.move.speed", &m_speed ); AddProperty( L"actions.move.turningradius", &m_turningRadius ); - AddProperty( L"actions.attack.range", &m_meleeRange ); - AddProperty( L"actions.attack.rangemin", &m_meleeRangeMin ); + AddProperty( L"actions.attack.range", &( m_melee.m_MaxRange ) ); + AddProperty( L"actions.attack.rangemin", &( m_melee.m_MinRange ) ); + AddProperty( L"actions.attack.speed", &( m_melee.m_Speed ) ); + AddProperty( L"actions.gather.range", &( m_gather.m_MaxRange ) ); + AddProperty( L"actions.gather.rangemin", &( m_gather.m_MinRange ) ); + AddProperty( L"actions.gather.speed", &( m_gather.m_Speed ) ); AddProperty( L"actor", &m_actorName ); AddProperty( L"traits.extant", &m_extant ); AddProperty( L"traits.corpse", &m_corpse ); @@ -30,7 +34,7 @@ CBaseEntity::CBaseEntity() } // Initialize, make life a little easier on the scriptors - m_speed = m_turningRadius = m_meleeRange = m_meleeRangeMin = 0.0f; + m_speed = m_turningRadius = 0.0f; m_extant = true; m_corpse = CStrW(); m_bound_type = CBoundingObject::BOUND_NONE; @@ -65,9 +69,76 @@ void CBaseEntity::loadBase() } SetBase( m_base ); + m_classes.SetParent( &( m_base->m_classes ) ); SetNextObject( m_base ); } +jsval CBaseEntity::getClassSet() +{ + STL_HASH_SET::iterator it; + it = m_classes.m_Set.begin(); + CStrW result = *( it++ ); + for( ; it != m_classes.m_Set.end(); it++ ) + result += L" " + *it; + return( ToJSVal( result ) ); +} + +void CBaseEntity::setClassSet( jsval value ) +{ + // Get the set that was passed in. + CStr temp = ToPrimitive( value ); + CStr entry; + + m_classes.m_Added.clear(); + m_classes.m_Removed.clear(); + + while( true ) + { + long brk_sp = temp.Find( ' ' ); + long brk_cm = temp.Find( ',' ); + long brk = ( brk_sp == -1 ) ? brk_cm : ( brk_cm == -1 ) ? brk_sp : ( brk_sp < brk_cm ) ? brk_sp : brk_cm; + + if( brk == -1 ) + { + entry = temp; + } + else + { + entry = temp.GetSubstring( 0, brk ); + temp = temp.GetSubstring( brk + 1, temp.Length() ); + } + + if( brk != 0 ) + { + + if( entry[0] == '-' ) + { + entry = entry.GetSubstring( 1, entry.Length() ); + if( entry.Length() ) + m_classes.m_Removed.push_back( entry ); + } + else + { + if( entry[0] == '+' ) + entry = entry.GetSubstring( 1, entry.Length() ); + if( entry.Length() ) + m_classes.m_Added.push_back( entry ); + } + } + if( brk == -1 ) break; + } + + rebuildClassSet(); +} + +void CBaseEntity::rebuildClassSet() +{ + m_classes.Rebuild(); + InheritorsList::iterator it; + for( it = m_Inheritors.begin(); it != m_Inheritors.end(); it++ ) + (*it)->rebuildClassSet(); +} + bool CBaseEntity::loadXML( CStr filename ) { CXeromyces XeroFile; @@ -267,6 +338,7 @@ void CBaseEntity::XMLLoadProperty( const CXeromyces& XeroFile, const XMBElement& void CBaseEntity::ScriptingInit() { AddMethod( "toString", 0 ); + AddClassProperty( L"traits.id.classes", (GetFn)getClassSet, (SetFn)setClassSet ); CJSComplex::ScriptingInit( "EntityTemplate" ); } diff --git a/source/simulation/BaseEntity.h b/source/simulation/BaseEntity.h index d172fd83f4..2d91f1bb26 100755 --- a/source/simulation/BaseEntity.h +++ b/source/simulation/BaseEntity.h @@ -13,7 +13,6 @@ // properties such as position, current HP, etc. cannot be inherited from // a template in this way. // -// Note: Data-inheritance is not currently implemented. #ifndef BASE_ENTITY_INCLUDED #define BASE_ENTITY_INCLUDED @@ -24,6 +23,7 @@ #include "scripting/ScriptableComplex.h" #include "BoundingObjects.h" #include "EventHandlers.h" +#include "EntitySupport.h" #include "ScriptObject.h" #include "Xeromyces.h" @@ -43,6 +43,9 @@ public: CStrW m_corpse; bool m_extant; + // The class types this entity has + SClassSet m_classes; + CStrW m_Base_Name; // <- We don't guarantee the order XML files will be loaded in, so we'll store the name of the // parent entity referenced, then, after all files are loaded, attempt to match names to objects. @@ -55,13 +58,16 @@ public: CBoundingObject::EBoundingType m_bound_type; float m_speed; - float m_meleeRange; - float m_meleeRangeMin; + SEntityAction m_melee; + SEntityAction m_gather; float m_turningRadius; CScriptObject m_EventHandlers[EVENT_LAST]; void loadBase(); + jsval getClassSet(); + void setClassSet( jsval value ); + void rebuildClassSet(); // Script-bound functions diff --git a/source/simulation/Entity.cpp b/source/simulation/Entity.cpp index b22dbce06b..ffdd8629f4 100755 --- a/source/simulation/Entity.cpp +++ b/source/simulation/Entity.cpp @@ -34,8 +34,12 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation ) AddProperty( L"traits.extant", &m_extant ); AddProperty( L"traits.corpse", &m_corpse ); AddProperty( L"actions.move.turningradius", &m_turningRadius ); - AddProperty( L"actions.attack.range", &m_meleeRange ); - AddProperty( L"actions.attack.rangemin", &m_meleeRangeMin ); + AddProperty( L"actions.attack.range", &( m_melee.m_MaxRange ) ); + AddProperty( L"actions.attack.rangemin", &( m_melee.m_MinRange ) ); + AddProperty( L"actions.attack.speed", &( m_melee.m_Speed ) ); + AddProperty( L"actions.gather.range", &( m_gather.m_MaxRange ) ); + AddProperty( L"actions.gather.rangemin", &( m_gather.m_MinRange ) ); + AddProperty( L"actions.gather.speed", &( m_gather.m_Speed ) ); AddProperty( L"position", &m_graphics_position, false, (NotifyFn)&CEntity::teleport ); AddProperty( L"orientation", &m_graphics_orientation, false, (NotifyFn)&CEntity::reorient ); AddProperty( L"player", &m_player ); @@ -52,6 +56,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation ) m_lastState = -1; m_transition = true; + m_fsm_cyclepos = NOT_IN_CYCLE; m_base = base; @@ -105,6 +110,7 @@ void CEntity::loadBase() // Set up our instance data SetBase( m_base ); + m_classes.SetParent( &( m_base->m_classes ) ); SetNextObject( m_base ); if( m_base->m_bound_type == CBoundingObject::BOUND_CIRCLE ) @@ -168,6 +174,76 @@ void CEntity::snapToGround() m_graphics_position.Y = pTerrain->getExactGroundLevel( m_graphics_position.X, m_graphics_position.Z ); } +jsval CEntity::getClassSet() +{ + STL_HASH_SET::iterator it; + it = m_classes.m_Set.begin(); + CStrW result = L""; + if( it != m_classes.m_Set.end() ) + { + result = *( it++ ); + for( ; it != m_classes.m_Set.end(); it++ ) + result += L" " + *it; + } + return( ToJSVal( result ) ); +} + +void CEntity::setClassSet( jsval value ) +{ + // Get the set that was passed in. + CStr temp = ToPrimitive( value ); + CStr entry; + + m_classes.m_Added.clear(); + m_classes.m_Removed.clear(); + + while( true ) + { + long brk_sp = temp.Find( ' ' ); + long brk_cm = temp.Find( ',' ); + long brk = ( brk_sp == -1 ) ? brk_cm : ( brk_cm == -1 ) ? brk_sp : ( brk_sp < brk_cm ) ? brk_sp : brk_cm; + + if( brk == -1 ) + { + entry = temp; + } + else + { + entry = temp.GetSubstring( 0, brk ); + temp = temp.GetSubstring( brk + 1, temp.Length() ); + } + + if( brk != 0 ) + { + + if( entry[0] == '-' ) + { + entry = entry.GetSubstring( 1, entry.Length() ); + if( entry.Length() ) + m_classes.m_Removed.push_back( entry ); + } + else + { + if( entry[0] == '+' ) + entry = entry.GetSubstring( 1, entry.Length() ); + if( entry.Length() ) + m_classes.m_Added.push_back( entry ); + } + } + if( brk == -1 ) break; + } + + rebuildClassSet(); +} + +void CEntity::rebuildClassSet() +{ + m_classes.Rebuild(); + InheritorsList::iterator it; + for( it = m_Inheritors.begin(); it != m_Inheritors.end(); it++ ) + (*it)->rebuildClassSet(); +} + void CEntity::update( size_t timestep ) { m_position_previous = m_position; @@ -183,10 +259,11 @@ void CEntity::update( size_t timestep ) { CEntityOrder* current = &m_orderQueue.front(); - m_transition = ( current->m_type != m_lastState ); - - if( m_transition ) + if( current->m_type != m_lastState ) { + m_transition = true; + m_fsm_cyclepos = NOT_IN_CYCLE; + PROFILE( "state transition / order" ); CEntity* target = NULL; @@ -210,6 +287,8 @@ void CEntity::update( size_t timestep ) m_lastState = current->m_type; } + else + m_transition = false; switch( current->m_type ) { @@ -288,48 +367,6 @@ void CEntity::Damage( CDamageType& damage, CEntity* inflictor ) DispatchEvent( &evt ); } -/* -void CEntity::dispatch( const CMessage* msg ) -{ - - switch( msg->type ) - { - case CMessage::EMSG_TICK: - { - CEventTick Tick; - DispatchEvent( &Tick ); - break; - } - case CMessage::EMSG_INIT: - { - CEventInitialize Init; - if( !DispatchEvent( &Init ) ) - break; - - if( m_base->m_Tag == CStrW( L"Prometheus Dude" ) ) - { - if( getCollisionObject( this ) ) - { - // Prometheus telefragging. (Appeared inside another object) - kill(); - return; - } - } - break; - } - case CMessage::EMSG_ORDER: - CMessageOrder* m; - m = (CMessageOrder*)msg; - if( !m->queue ) - clearOrders(); - pushOrder( m->order ); - break; - case CMessage::EMSG_DAMAGE: - CEntityOrder* o; - } -} -*/ - void CEntity::clearOrders() { m_orderQueue.clear(); @@ -607,9 +644,11 @@ void CEntity::ScriptingInit() AddMethod( "kill", 0 ); AddMethod( "damage", 1 ); AddMethod( "isIdle", 0 ); + AddMethod( "hasClass", 1 ); AddMethod( "getSpawnPoint", 1 ); AddClassProperty( L"template", (CBaseEntity* CEntity::*)&CEntity::m_base, false, (NotifyFn)&CEntity::loadBase ); + AddClassProperty( L"traits.id.classes", (GetFn)getClassSet, (SetFn)setClassSet ); CJSComplex::ScriptingInit( "Entity", Construct, 2 ); } diff --git a/source/simulation/Entity.h b/source/simulation/Entity.h index d331870d6e..111a430dfa 100755 --- a/source/simulation/Entity.h +++ b/source/simulation/Entity.h @@ -66,10 +66,13 @@ public: // The entity to switch to when this dies. CStrW m_corpse; + // The class types this entity has + SClassSet m_classes; + float m_speed; float m_turningRadius; - float m_meleeRange; - float m_meleeRangeMin; + SEntityAction m_melee; + SEntityAction m_gather; bool m_selected; i32 m_grouped; @@ -99,10 +102,6 @@ public: // Get script execution contexts - always run in the context of the entity that fired it. JSObject* GetScriptExecContext( IEventTarget* target ) { return( ((CEntity*)target)->GetScript() ); } - // EventListener adaptation? - //typedef std::vector ExtendedHandlerList; - //typedef STL_HASH_MAP ExtendedHandlerTable; - CScriptObject m_EventHandlers[EVENT_LAST]; CUnit* m_actor; @@ -110,16 +109,23 @@ public: // State transition in the FSM (animations should be reset) bool m_transition; int m_lastState; + + // Position in the current state's cycle + static const size_t NOT_IN_CYCLE = -1; + size_t m_fsm_cyclepos; // -cycle_length....cycle_length + CSkeletonAnim* m_fsm_animation; // the animation we're about to play this cycle, + size_t m_fsm_anipos; // the time at which we should start playing it. + size_t m_fsm_anipos2; // for when there are two animation-related events we need to take care of. std::deque m_orderQueue; private: CEntity( CBaseEntity* base, CVector3D position, float orientation ); - /*EGotoSituation*/ uint processGotoHelper( CEntityOrder* current, size_t timestep_milli, HEntity& collide ); + 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 processContactAction( CEntityOrder* current, size_t timestep_millis, int transition, SEntityAction* action ); + bool processContactActionNoPathing( CEntityOrder* current, size_t timestep_millis, CSkeletonAnim* animation, CScriptEvent* contactEvent, SEntityAction* action ); bool processAttackMelee( CEntityOrder* current, size_t timestep_milli ); bool processAttackMeleeNoPathing( CEntityOrder* current, size_t timestep_milli ); @@ -162,6 +168,11 @@ public: void snapToGround(); void updateActorTransforms(); + // Getter and setter for the class sets + jsval getClassSet(); + void setClassSet( jsval value ); + void rebuildClassSet(); + // Things like selection circles and debug info - possibly move to gui if/when it becomes responsible for (and capable of) it. void render(); void renderSelectionOutline( float alpha = 1.0f ); @@ -207,6 +218,11 @@ public: { return( m_orderQueue.empty() ); } + bool HasClass( JSContext* cx, uintN argc, jsval* argv ) + { + assert( argc >= 1 ); + return( m_classes.IsMember( ToPrimitive( cx, argv[0] ) ) ); + } static void ScriptingInit(); }; diff --git a/source/simulation/EntityStateProcessing.cpp b/source/simulation/EntityStateProcessing.cpp index e8c127f38f..c810cf8ea1 100755 --- a/source/simulation/EntityStateProcessing.cpp +++ b/source/simulation/EntityStateProcessing.cpp @@ -269,7 +269,7 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, size_t timestep_milli } // 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 ) +bool CEntity::processContactAction( CEntityOrder* current, size_t timestep_millis, int transition, SEntityAction* action ) { m_orderQueue.pop_front(); @@ -278,7 +278,7 @@ bool CEntity::processContactAction( CEntityOrder* current, size_t timestep_milli current->m_data[0].location = current->m_data[0].entity->m_position; - if( ( current->m_data[0].location - m_position ).length() < m_meleeRange ) + if( ( current->m_data[0].location - m_position ).length() < action->m_MaxRange ) { (int&)current->m_type = transition; return( true ); @@ -297,9 +297,45 @@ bool CEntity::processContactAction( CEntityOrder* current, size_t timestep_milli return( true ); } -bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t timestep_millis, CSkeletonAnim* animation, CScriptEvent* contactEvent, float range, float minRange = 0.0f ) +bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t timestep_millis, CSkeletonAnim* animation, CScriptEvent* contactEvent, SEntityAction* action ) { - static size_t cyclepos = 0; + if( m_fsm_cyclepos != NOT_IN_CYCLE ) + { + size_t nextpos = m_fsm_cyclepos + timestep_millis * 2; + if( ( m_fsm_cyclepos <= m_fsm_anipos ) && + ( nextpos > m_fsm_anipos ) ) + { + // Start playing. + // Start the animation. Actual damage/gather will be done in a + // few hundred ms, at the 'action point' of the animation we're + // now setting. + + m_actor->GetModel()->SetAnimation( m_fsm_animation, true ); + } + + if( ( m_fsm_cyclepos <= action->m_Speed ) && ( nextpos > action->m_Speed ) ) + { + 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. + // It depends what we think is worse: stopping an animation halfway through, + // or playing the animation without getting a game effect. + + // Could also check again here if the entity still exists, is in range, etc.. + // and cancel if not, but we'll see how it looks without that, first. + } + + if( nextpos >= ( action->m_Speed * 2 ) ) + { + // End of cycle. + m_fsm_cyclepos = NOT_IN_CYCLE; + return( false ); + } + + // Otherwise, increment position. + m_fsm_cyclepos = nextpos; + return( false ); + } // Target's dead (or exhausted)? Then our work here is done. if( !current->m_data[0].entity || !current->m_data[0].entity->m_extant ) @@ -308,42 +344,13 @@ bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t times return( false ); } - if( m_actor ) - { - if( animation && ( m_actor->GetModel()->GetAnimation() == animation ) ) - { - size_t cyclenext = cyclepos + timestep_millis; - if( ( cyclepos <= animation->m_ActionPos ) && - ( cyclenext > animation->m_ActionPos ) ) - { - // Actually execute the action script in the sim frame - // that contains the animation's 'action point' (as - // specified by the artist that created it) - if( !DispatchEvent( contactEvent ) ) - { - // The script is cancelling the attack/gather action. - - // Cancel the animation (will probably cause a graphical - // glitch, but can't be helped) - m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_WalkAnim ); - } - } - cyclepos = cyclenext; - return( false ); - } - - // Just transitioned? No animation? (=> melee just finished) Play walk. - if( m_transition || !m_actor->GetModel()->GetAnimation() ) - m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_WalkAnim ); - } - CVector2D delta = current->m_data[0].entity->m_position - m_position; - float adjRange = range + m_bounds->m_radius + current->m_data[0].entity->m_bounds->m_radius; + float adjRange = action->m_MaxRange + m_bounds->m_radius + current->m_data[0].entity->m_bounds->m_radius; - if( minRange > 0.0f ) + if( action->m_MinRange > 0.0f ) { - float adjMinRange = m_meleeRangeMin + m_bounds->m_radius + current->m_data[0].entity->m_bounds->m_radius; + float adjMinRange = action->m_MinRange + m_bounds->m_radius + current->m_data[0].entity->m_bounds->m_radius; if( delta.within( adjMinRange ) ) { // Too close... do nothing. @@ -357,6 +364,14 @@ bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t times // We're aiming to end up at a location just inside our maximum range // (is this good enough?) + // Play walk for a bit. + if( m_actor && ( m_actor->GetModel()->GetAnimation() != m_actor->GetObject()->m_WalkAnim ) ) + { + m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_WalkAnim ); + // Animation desync + m_actor->GetModel()->Update( ( rand() * 1000.0f ) / 1000.0f ); + } + delta = delta.normalize() * ( adjRange - m_bounds->m_radius ); current->m_data[0].location = (CVector2D)current->m_data[0].entity->m_position - delta; @@ -411,39 +426,52 @@ bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t times } else { - // Close enough, but turn to face them. + // Close enough, but turn to face them. m_orientation = atan2( delta.x, delta.y ); m_ahead = delta.normalize(); } - // Start the animation. Actual damage/gather will be done in a - // few hundred msec, at the 'action point' of the animation we're - // now setting. + // Pick our animation, calculate the time to play it, and start the timer. + m_fsm_animation = animation; // <- Replace with a call that gets one randomly, probably pass in a CSkeletonAnim* (void) fn for this purpose + + // Here's the idea - we want to be at that animation's event point + // when the timer reaches action->m_Speed. The timer increments by 2 every millisecond. + // animation->m_actionpos is the time offset into that animation that event + // should happen. So... + m_fsm_anipos = action->m_Speed - ( m_fsm_animation->m_ActionPos * 2 ); + // But... + if( action->m_Speed < ( m_fsm_animation->m_ActionPos * 2 ) ) + { + // We ought to have started it in the past. Oh well. + // Here's what we'll do: play it now, and advance it to + // the point it should be by now. + m_actor->GetModel()->SetAnimation( m_fsm_animation, true ); + m_actor->GetModel()->Update( m_fsm_animation->m_ActionPos / 1000.0f - action->m_Speed / 2000.0f ); + } - m_actor->GetModel()->SetAnimation( animation, true ); - cyclepos = 0; + m_fsm_cyclepos = 0; return( false ); } bool CEntity::processAttackMelee( CEntityOrder* current, size_t timestep_millis ) { - return( processContactAction( current, timestep_millis, CEntityOrder::ORDER_ATTACK_MELEE_NOPATHING, 0.5 ) ); + return( processContactAction( current, timestep_millis, CEntityOrder::ORDER_ATTACK_MELEE_NOPATHING, &m_melee ) ); } 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 ) ); + return( processContactActionNoPathing( current, timestep_milli, m_actor ? m_actor->GetObject()->m_MeleeAnim : NULL, &evt, &m_melee ) ); } bool CEntity::processGather( CEntityOrder* current, size_t timestep_millis ) { - return( processContactAction( current, timestep_millis, CEntityOrder::ORDER_GATHER_NOPATHING, 0.5 ) ); + return( processContactAction( current, timestep_millis, CEntityOrder::ORDER_GATHER_NOPATHING, &m_gather ) ); } 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 ) ); + return( processContactActionNoPathing( current, timestep_millis, m_actor ? m_actor->GetObject()->m_GatherAnim : NULL, &evt, &m_gather ) ); } bool CEntity::processGoto( CEntityOrder* current, size_t timestep_millis ) diff --git a/source/simulation/EntitySupport.h b/source/simulation/EntitySupport.h index 9e62d68bdd..902d8df899 100755 --- a/source/simulation/EntitySupport.h +++ b/source/simulation/EntitySupport.h @@ -1,5 +1,8 @@ // Supporting data types for CEntity and related +#ifndef ENTITY_SUPPORT_INCLUDED +#define ENTITY_SUPPORT_INCLUDED + class CEntityManager; class CDamageType : public CJSObject @@ -68,3 +71,44 @@ public: return( JS_TRUE ); } }; + +struct SEntityAction +{ + float m_MaxRange; + float m_MinRange; + size_t m_Speed; + SEntityAction() { m_MaxRange = m_MinRange = 0.0f; m_Speed = 1000; } +}; + +struct SClassSet +{ + SClassSet* m_Parent; + + STL_HASH_SET m_Set; + std::vector m_Added; + std::vector m_Removed; + + inline SClassSet() { m_Parent = NULL; } + + inline bool IsMember( CStrW Test ) + { return( m_Set.find( Test ) != m_Set.end() ); } + + inline void SetParent( SClassSet* Parent ) + { m_Parent = Parent; Rebuild(); } + + void Rebuild() + { + if( m_Parent ) + m_Set = m_Parent->m_Set; + else + m_Set.clear(); + + std::vector::iterator it; + for( it = m_Removed.begin(); it != m_Removed.end(); it++ ) + m_Set.erase( *it ); + for( it = m_Added.begin(); it != m_Added.end(); it++ ) + m_Set.insert( *it ); + } +}; + +#endif \ No newline at end of file