diff --git a/GameData.cs b/GameData.cs index 9fb0789..8972751 100644 --- a/GameData.cs +++ b/GameData.cs @@ -109,6 +109,7 @@ static void Load(string Path, ParseBlock Block) Block.AddParser("unit-status", Parse.EnumBlockParser(typeof(UnitStatus))); Block.AddParser("block-type", Parse.EnumBlockParser(typeof(BlockType))); Block.AddParser("front", Parse.EnumBlockParser(typeof(Front))); + Block.AddParser("weapon", i => new Weapon(i)); Block.AddParser("movement-rule", i => new MovementRule(i)); Block.AddParser("unit-movement-rules", i => new UnitMovementRules(i)); diff --git a/Model/Unit/UnitConfiguration.cs b/Model/Unit/UnitConfiguration.cs index 3e20b4a..2dd0cf0 100644 --- a/Model/Unit/UnitConfiguration.cs +++ b/Model/Unit/UnitConfiguration.cs @@ -11,9 +11,13 @@ enum Attribute { NAME, UNIT_CLASS, + + PRIMARY_WEAPON, + SECONDARY_WEAPON, WEAPON_CLASS, ATTACK, RANGE, + DEFENSE, MOVEMENT, @@ -56,8 +60,7 @@ enum Attribute DISMOUNT_AS, CAN_REMOUNT, - CAN_SUPPORT_ARMORED, - UNLIMITED_MOVEMENT + CAN_SUPPORT_ARMORED }; public readonly string UniqueKey; @@ -181,24 +184,28 @@ public UnitConfiguration(ParseBlock Block) Name = (string)attributes[(int)Attribute.NAME]; UnitClass = (UnitClass)attributes[(int)Attribute.UNIT_CLASS]; - WeaponClass weaponClass = (WeaponClass)attributes[(int)Attribute.WEAPON_CLASS]; - byte attack = (byte)attributes[(int)Attribute.ATTACK]; - byte range = (byte)attributes[(int)Attribute.RANGE]; + WeaponClass weaponClass = Parse.DefaultIfNull(attributes[(int)Attribute.WEAPON_CLASS], WeaponClass.NA); + byte attack = Parse.DefaultIfNull(attributes[(int)Attribute.ATTACK], (byte)0); + byte range = Parse.DefaultIfNull(attributes[(int)Attribute.RANGE], (byte)0); bool canDoubleRange = Parse.DefaultIfNull(attributes[(int)Attribute.CAN_DOUBLE_RANGE], false); - PrimaryWeapon = new Weapon(weaponClass, attack, range, canDoubleRange); + PrimaryWeapon = Parse.DefaultIfNull( + attributes[(int)Attribute.PRIMARY_WEAPON], new Weapon(weaponClass, attack, range, canDoubleRange)); + SecondaryWeapon = Parse.DefaultIfNull(attributes[(int)Attribute.SECONDARY_WEAPON], default(Weapon)); Defense = (byte)attributes[(int)Attribute.DEFENSE]; Movement = Parse.DefaultIfNull(attributes[(int)Attribute.MOVEMENT], IsAircraft() ? byte.MaxValue : (byte)0); - IsVehicle = Parse.DefaultIfNull(attributes[(int)Attribute.IS_VEHICLE], - UnitClass == UnitClass.AMPHIBIOUS_VEHICLE - || UnitClass == UnitClass.ASSAULT_GUN - || UnitClass == UnitClass.ENGINEER_VEHICLE - || UnitClass == UnitClass.FLAME_TANK - || UnitClass == UnitClass.RECONNAISSANCE_VEHICLE - || UnitClass == UnitClass.SELF_PROPELLED_ARTILLERY - || UnitClass == UnitClass.TANK - || UnitClass == UnitClass.TRANSPORT - || UnitClass == UnitClass.WRECKAGE); + IsVehicle = Parse.DefaultIfNull( + attributes[(int)Attribute.IS_VEHICLE], + IsAircraft() + || UnitClass == UnitClass.AMPHIBIOUS_VEHICLE + || UnitClass == UnitClass.ASSAULT_GUN + || UnitClass == UnitClass.ENGINEER_VEHICLE + || UnitClass == UnitClass.FLAME_TANK + || UnitClass == UnitClass.RECONNAISSANCE_VEHICLE + || UnitClass == UnitClass.SELF_PROPELLED_ARTILLERY + || UnitClass == UnitClass.TANK + || UnitClass == UnitClass.TRANSPORT + || UnitClass == UnitClass.WRECKAGE); IsArmored = Parse.DefaultIfNull( attributes[(int)Attribute.IS_ARMORED], (IsVehicle && UnitClass != UnitClass.TRANSPORT) || UnitClass == UnitClass.FORT); @@ -212,9 +219,7 @@ public UnitConfiguration(ParseBlock Block) MovementRules = Parse.DefaultIfNull( attributes[(int)Attribute.MOVEMENT_RULES], - IsVehicle - ? Block.Get("unit-movement-rules.default-vehicle") - : Block.Get("unit-movement-rules.default-non-vehicle")); + Block.Get(GetDefaultMovementRules())); IsCarrier = Parse.DefaultIfNull( attributes[(int)Attribute.IS_CARRIER], IsVehicle || UnitClass == UnitClass.TRANSPORT); @@ -271,6 +276,13 @@ public UnitConfiguration(ParseBlock Block) CanSupportArmored = Parse.DefaultIfNull(attributes[(int)Attribute.CAN_SUPPORT_ARMORED], false); } + string GetDefaultMovementRules() + { + if (IsAircraft()) return "unit-movement-rules.default-aircraft"; + if (IsVehicle) return "unit-movement-rules.default-vehicle"; + return "unit-movement-rules.default-non-vehicle"; + } + public Weapon GetWeapon(bool Secondary) { return Secondary ? SecondaryWeapon : PrimaryWeapon; diff --git a/Modules/Default/Scenarios/Russia1941/Scenario_01.blk b/Modules/Default/Scenarios/Russia1941/Scenario_01.blk index 717f5b8..f728bf9 100644 --- a/Modules/Default/Scenarios/Russia1941/Scenario_01.blk +++ b/Modules/Default/Scenarios/Russia1941/Scenario_01.blk @@ -39,7 +39,7 @@ var[]:deployment-configurations { positional-deployment-configuration:_ { tile-within:matcher { - zone:zone { 0,0 10,0 10,20 0,20 } + zone:zone { 0,0 31,0 31,20 0,20 } } unit-group:unit-group { string:name { Russian Front-Line } @@ -137,7 +137,7 @@ var[]:deployment-configurations { positional-deployment-configuration:_ { tile-within:matcher { - zone:zone { 0,22 10,22 10,33 0,33 } + zone:zone { 0,22 31,22 31,33 0,33 } } unit-group:unit-group { string:name { Panzer Spearhead } diff --git a/Modules/Default/UnitConfigurationLinks/German.blk b/Modules/Default/UnitConfigurationLinks/German.blk index 9946146..aab2de2 100644 --- a/Modules/Default/UnitConfigurationLinks/German.blk +++ b/Modules/Default/UnitConfigurationLinks/German.blk @@ -706,4 +706,74 @@ unit-configuration-link:tiger-ii { !unit-configuration:unit-configuration { unit-configurations.tiger-ii } int:introduce-year { 1944 } +} +unit-configuration-link:fw-190 { + !faction:faction { factions.german } + !unit-configuration:unit-configuration { unit-configurations.fw-190 } + + int:introduce-year { 1941 } +} +unit-configuration-link:ju-87-b-early { + !faction:faction { factions.german } + !unit-configuration:unit-configuration { unit-configurations.ju-87-b-early } +} +unit-configuration-link:ju-87-b { + !faction:faction { factions.german } + !unit-configuration:unit-configuration { unit-configurations.ju-87-b } +} +unit-configuration-link:ju-87-g { + !faction:faction { factions.german } + !unit-configuration:unit-configuration { unit-configurations.ju-87-g } + + int:introduce-year { 1943 } +} +unit-configuration-link:hs-123 { + !faction:faction { factions.german } + !unit-configuration:unit-configuration { unit-configurations.hs-123 } +} +unit-configuration-link:do-17-z { + !faction:faction { factions.german } + !unit-configuration:unit-configuration { unit-configurations.do-17-z } +} +unit-configuration-link:hs-129_r1 { + !faction:faction { factions.german } + !unit-configuration:unit-configuration { unit-configurations.hs-129_r1 } + + int:introduce-year { 1942 } +} +unit-configuration-link:hs-129_r2-early { + !faction:faction { factions.german } + !unit-configuration:unit-configuration { unit-configurations.hs-129_r2-early } + + int:introduce-year { 1942 } +} +unit-configuration-link:hs-129_r2 { + !faction:faction { factions.german } + !unit-configuration:unit-configuration { unit-configurations.hs-129_r2 } + + int:introduce-year { 1944 } +} +unit-configuration-link:hs-129_r2-late { + !faction:faction { factions.german } + !unit-configuration:unit-configuration { unit-configurations.hs-129_r2-late } + + int:introduce-year { 1945 } +} +unit-configuration-link:ju-88 { + !faction:faction { factions.german } + !unit-configuration:unit-configuration { unit-configurations.ju-88 } + + int:introduce-year { 1939 } +} +unit-configuration-link:ju-52 { + !faction:faction { factions.german } + !unit-configuration:unit-configuration { unit-configurations.ju-52 } +} +unit-configuration-link:glider-german { + !faction:faction { factions.german } + !unit-configuration:unit-configuration { unit-configurations.glider-german } +} +unit-configuration-link:spotter-german { + !faction:faction { factions.german } + !unit-configuration:unit-configuration { unit-configurations.spotter-german } } \ No newline at end of file diff --git a/Modules/Default/UnitConfigurations/German.blk b/Modules/Default/UnitConfigurations/German.blk index 78f7700..c27963b 100644 --- a/Modules/Default/UnitConfigurations/German.blk +++ b/Modules/Default/UnitConfigurations/German.blk @@ -1095,4 +1095,183 @@ unit-configuration:tiger-ii { byte:range { 12 } byte:defense { 16 } byte:movement { 6 } +} +unit-configuration:fw-190 { + string:name { FW-190 } + unit-class:unit-class { fighter-bomber } + + weapon:primary-weapon { + weapon-class:weapon-class { high-explosive } + byte:attack { 10 } + byte:range { 1 } + } + weapon:secondary-weapon { + weapon-class:weapon-class { anti-armor } + byte:attack { 4 } + byte:range { 1 } + } + byte:defense { 1 } +} +unit-configuration:ju-87-b-early { + string:name { JU-87 B } + unit-class:unit-class { fighter-bomber } + + weapon:primary-weapon { + weapon-class:weapon-class { high-explosive } + byte:attack { 10 } + byte:range { 1 } + } + weapon:secondary-weapon { + weapon-class:weapon-class { infantry } + byte:attack { 1 } + byte:range { 1 } + } + byte:defense { 1 } +} +unit-configuration:ju-87-b { + string:name { JU-87 B } + unit-class:unit-class { fighter-bomber } + + weapon:primary-weapon { + weapon-class:weapon-class { high-explosive } + byte:attack { 20 } + byte:range { 1 } + } + weapon:secondary-weapon { + weapon-class:weapon-class { infantry } + byte:attack { 1 } + byte:range { 1 } + } + byte:defense { 1 } +} +unit-configuration:ju-87-g { + string:name { JU-87 G } + unit-class:unit-class { fighter-bomber } + + weapon:primary-weapon { + weapon-class:weapon-class { anti-armor } + byte:attack { 6 } + byte:range { 1 } + } + byte:defense { 1 } +} +unit-configuration:hs-123 { + string:name { Hs-123 } + unit-class:unit-class { fighter-bomber } + + weapon:primary-weapon { + weapon-class:weapon-class { high-explosive } + byte:attack { 8 } + byte:range { 1 } + } + weapon:secondary-weapon { + weapon-class:weapon-class { infantry } + byte:attack { 2 } + byte:range { 1 } + } + byte:defense { 1 } +} +unit-configuration:do-17-z { + string:name { Do-17 Z } + unit-class:unit-class { fighter-bomber } + + weapon:primary-weapon { + weapon-class:weapon-class { high-explosive } + byte:attack { 10 } + byte:range { 1 } + } + byte:defense { 1 } +} +unit-configuration:hs-129_r1 { + string:name { Hs-129 (R1) } + unit-class:unit-class { fighter-bomber } + + weapon:primary-weapon { + weapon-class:weapon-class { anti-armor } + byte:attack { 2 } + byte:range { 1 } + } + weapon:secondary-weapon { + weapon-class:weapon-class { infantry } + byte:attack { 30 } + byte:range { 1 } + } + byte:defense { 1 } +} +unit-configuration:hs-129_r2-early { + string:name { Hs-129 (R2) } + unit-class:unit-class { fighter-bomber } + + weapon:primary-weapon { + weapon-class:weapon-class { anti-armor } + byte:attack { 3 } + byte:range { 1 } + } + byte:defense { 1 } +} +unit-configuration:hs-129_r2 { + string:name { Hs-129 (R2) } + unit-class:unit-class { fighter-bomber } + + weapon:primary-weapon { + weapon-class:weapon-class { anti-armor } + byte:attack { 6 } + byte:range { 1 } + } + byte:defense { 1 } +} +unit-configuration:hs-129_r2-late { + string:name { Hs-129 (R2) } + unit-class:unit-class { fighter-bomber } + + weapon:primary-weapon { + weapon-class:weapon-class { anti-armor } + byte:attack { 8 } + byte:range { 1 } + } + byte:defense { 1 } +} +unit-configuration:ju-88 { + string:name { JU-88 } + unit-class:unit-class { fighter-bomber } + + weapon:primary-weapon { + weapon-class:weapon-class { high-explosive } + byte:attack { 10 } + byte:range { 1 } + } + byte:defense { 1 } +} +unit-configuration:ju-52 { + string:name { JU-52 } + unit-class:unit-class { observation-aircraft } + + weapon:primary-weapon { + weapon-class:weapon-class { na } + byte:attack { 0 } + byte:range { 0 } + } + byte:defense { 1 } +} +unit-configuration:glider-german { + string:name { Glider } + unit-class:unit-class { observation-aircraft } + + weapon:primary-weapon { + weapon-class:weapon-class { na } + byte:attack { 0 } + byte:range { 0 } + } + byte:defense { 1 } +} +unit-configuration:spotter-german { + string:name { Spotter } + unit-class:unit-class { observation-aircraft } + + weapon:primary-weapon { + weapon-class:weapon-class { na } + byte:attack { 0 } + byte:range { 0 } + } + byte:defense { 1 } } \ No newline at end of file diff --git a/Modules/Default/UnitMovementRules.blk b/Modules/Default/UnitMovementRules.blk index 1b7975d..d59a0db 100644 --- a/Modules/Default/UnitMovementRules.blk +++ b/Modules/Default/UnitMovementRules.blk @@ -11,6 +11,7 @@ movement-rule:swamp { impassable } movement-rule:water { impassable } } + unit-movement-rules:default-aircraft { } unit-movement-rules:amphibious-transport { movement-rule:dense-edge { impassable } movement-rule:frozen { impassable } diff --git a/Modules/Default/UnitRenderDetails/German.blk b/Modules/Default/UnitRenderDetails/German.blk index dc21c9e..5c24140 100644 --- a/Modules/Default/UnitRenderDetails/German.blk +++ b/Modules/Default/UnitRenderDetails/German.blk @@ -335,4 +335,46 @@ unit-render-details:tiger-i { } unit-render-details:tiger-ii { string:image-path { tiger-ii.png } +} +unit-render-details:fw-190 { + string:image-path { fw-190.png } +} +unit-render-details:ju-87-b-early { + string:image-path { fw-190.png } +} +unit-render-details:ju-87-b { + string:image-path { ju-87.png } +} +unit-render-details:ju-87-g { + string:image-path { ju-87.png } +} +unit-render-details:hs-123 { + string:image-path { hs-123.png } +} +unit-render-details:do-17-z { + string:image-path { fw-190.png } +} +unit-render-details:hs-129_r1 { + string:image-path { do-17-z.png } +} +unit-render-details:hs-129_r2-early { + string:image-path { hs-129.png } +} +unit-render-details:hs-129_r2 { + string:image-path { hs-129.png } +} +unit-render-details:hs-129_r2-late { + string:image-path { hs-129.png } +} +unit-render-details:ju-88 { + string:image-path { ju-88.png } +} +unit-render-details:ju-52 { + string:image-path { ju-52.png } +} +unit-render-details:glider-german { + string:image-path { glider-2.png } +} +unit-render-details:spotter-german { + string:image-path { spotter.png } } \ No newline at end of file diff --git a/Modules/Default/UnitSprites/spotter.png b/Modules/Default/UnitSprites/spotter.png new file mode 100644 index 0000000..641b4e7 Binary files /dev/null and b/Modules/Default/UnitSprites/spotter.png differ diff --git a/PanzerBlitz.csproj b/PanzerBlitz.csproj index ed63f54..4fa3e88 100644 --- a/PanzerBlitz.csproj +++ b/PanzerBlitz.csproj @@ -2232,6 +2232,9 @@ PreserveNewest + + PreserveNewest + \ No newline at end of file diff --git a/View/Unit/UnitConfigurationRenderer.cs b/View/Unit/UnitConfigurationRenderer.cs index 8a01e59..7529f51 100644 --- a/View/Unit/UnitConfigurationRenderer.cs +++ b/View/Unit/UnitConfigurationRenderer.cs @@ -69,15 +69,12 @@ public override void Render(RenderTarget Target, Transform Transform, UnitConfig return; } - Weapon weapon = Object.GetWeapon(false); - var attackText = new Text(weapon.Attack.ToString(), Font, 36); - attackText.Color = Color.Black; - attackText.Position = SpriteSize * new Vector2f(1f / 6, 1f / 12) - GetCenter(attackText); - - var rangeText = new Text( - weapon.Range.ToString() + (weapon.CanDoubleRange ? "*" : ""), Font, 36); - rangeText.Color = Color.Black; - rangeText.Position = SpriteSize * new Vector2f(5f / 6, 1f / 12) - GetCenter(rangeText); + if (Object.SecondaryWeapon == default(Weapon)) RenderWeapon(Target, r, Object, Object.GetWeapon(false)); + else + { + RenderWeapon(Target, r, Object, Object.GetWeapon(false), new Vector2f(1f / 6, 1f / 12), true); + RenderWeapon(Target, r, Object, Object.GetWeapon(true), new Vector2f(5f / 6, 1f / 12), true); + } var defenseText = new Text(Object.Defense.ToString(), Font, 36); defenseText.Color = Color.Black; @@ -89,22 +86,46 @@ public override void Render(RenderTarget Target, Transform Transform, UnitConfig moveText.Color = Color.Black; moveText.Position = SpriteSize * new Vector2f(5f / 6, 3f / 4) - GetCenter(moveText); - var weaponClassText = new Text(WeaponClassString(Object, false), Font, 28); - weaponClassText.Color = Color.Black; - weaponClassText.Position = SpriteSize * new Vector2f(.5f, 1f / 12) - GetCenter(weaponClassText); - var nameText = new Text(renderDetails.OverrideDisplayName ?? Object.Name, Font, 24); nameText.Color = Color.Black; nameText.Position = SpriteSize * new Vector2f(.5f, 13f / 16) - GetCenter(nameText); - Target.Draw(attackText, r); - Target.Draw(rangeText, r); + if (!Object.HasUnlimitedMovement()) Target.Draw(moveText, r); Target.Draw(defenseText, r); - Target.Draw(moveText, r); - Target.Draw(weaponClassText, r); Target.Draw(nameText, r); } + void RenderWeapon( + RenderTarget Target, + RenderStates RenderStates, + UnitConfiguration Object, + Weapon Weapon, + Vector2f Origin = default(Vector2f), + bool Vertical = false) + { + var attackText = new Text(Weapon.Attack.ToString(), Font, 36) { Color = Color.Black }; + var weaponClassText = new Text(WeaponClassString(Object, false), Font, 28) { Color = Color.Black }; + var rangeText = new Text( + Weapon.Range.ToString() + (Weapon.CanDoubleRange ? "*" : ""), Font, 36) + { Color = Color.Black }; + if (Vertical) + { + Vector2f padding = new Vector2f(0, 1f / 4); + attackText.Position = SpriteSize * Origin - GetCenter(attackText); + weaponClassText.Position = SpriteSize * (Origin + padding * 2) - GetCenter(weaponClassText); + rangeText.Position = SpriteSize * (Origin + padding * 1) - GetCenter(rangeText); + } + else + { + attackText.Position = SpriteSize * new Vector2f(1f / 6, 1f / 12) - GetCenter(attackText); + weaponClassText.Position = SpriteSize * new Vector2f(.5f, 1f / 12) - GetCenter(weaponClassText); + rangeText.Position = SpriteSize * new Vector2f(5f / 6, 1f / 12) - GetCenter(rangeText); + } + Target.Draw(attackText, RenderStates); + Target.Draw(weaponClassText, RenderStates); + Target.Draw(rangeText, RenderStates); + } + Vector2f GetCenter(Text Text) { return new Vector2f(Text.GetLocalBounds().Width, Text.GetLocalBounds().Height) * .5f;