mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-05 15:59:50 +07:00
Added Privateer unit; updated Coastal Raider promotion (#4301)
* Added privateer unit * Privateers can now capture other naval units * Updated Coastal Raider promotion to include the gold gained from damaging cities * Added missing translatable notification * Implemented requested changes * Implemented requested changes _but better_ * Forgot to update a variable name
This commit is contained in:
BIN
android/ImagesToPackSeparately/UnitIcons/Privateer.png
Normal file
BIN
android/ImagesToPackSeparately/UnitIcons/Privateer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
@ -564,170 +564,177 @@ Pikeman
|
|||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Rifleman
|
Privateer
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1300, 868
|
xy: 1300, 868
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Rocket Artillery
|
Rifleman
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 544, 4
|
xy: 544, 4
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Samurai
|
Rocket Artillery
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 652, 112
|
xy: 652, 112
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Scout
|
Samurai
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 760, 226
|
xy: 760, 226
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Settler
|
Scout
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 868, 328
|
xy: 868, 328
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Ship of the Line
|
Settler
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 976, 436
|
xy: 976, 436
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Sipahi
|
Ship of the Line
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1084, 544
|
xy: 1084, 544
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Slinger
|
Sipahi
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1192, 653
|
xy: 1192, 653
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Spearman
|
Slinger
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1300, 760
|
xy: 1300, 760
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Stealth Bomber
|
Spearman
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1408, 868
|
xy: 1408, 868
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Submarine
|
Stealth Bomber
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 652, 4
|
xy: 652, 4
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Swordsman
|
Submarine
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 760, 118
|
xy: 760, 118
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Tank
|
Swordsman
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 868, 220
|
xy: 868, 220
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Tercio
|
Tank
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 976, 328
|
xy: 976, 328
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Trebuchet
|
Tercio
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1084, 436
|
xy: 1084, 436
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Triplane
|
Trebuchet
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1192, 545
|
xy: 1192, 545
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
|
Triplane
|
||||||
|
rotate: false
|
||||||
|
xy: 1300, 652
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
Trireme
|
Trireme
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1300, 651
|
xy: 1408, 759
|
||||||
size: 100, 101
|
size: 100, 101
|
||||||
orig: 100, 101
|
orig: 100, 101
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Turtle Ship
|
Turtle Ship
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1408, 760
|
xy: 1516, 868
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
War Chariot
|
War Chariot
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1516, 868
|
xy: 760, 10
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
War Elephant
|
War Elephant
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 760, 10
|
xy: 868, 112
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Warrior
|
Warrior
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 868, 112
|
xy: 976, 220
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Work Boats
|
Work Boats
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 976, 220
|
xy: 1084, 328
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Worker
|
Worker
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1084, 328
|
xy: 1192, 437
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
Zero
|
Zero
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1192, 437
|
xy: 1300, 544
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 325 KiB After Width: | Height: | Size: 330 KiB |
@ -213,19 +213,19 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
"name": "Coastal Raider I",
|
"name": "Coastal Raider I",
|
||||||
"effect": "+[15]% Strength vs [City]",
|
"uniques": ["+[20]% Strength vs [City]", "Earn [33]% of the damage done to [City] units as [Gold]"],
|
||||||
"unitTypes": ["WaterMelee"]
|
"unitTypes": ["WaterMelee"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Coastal Raider II",
|
"name": "Coastal Raider II",
|
||||||
"prerequisites": ["Coastal Raider I"],
|
"prerequisites": ["Coastal Raider I"],
|
||||||
"effect": "+[15]% Strength vs [City]",
|
"uniques": ["+[20]% Strength vs [City]", "Earn [33]% of the damage done to [City] units as [Gold]"],
|
||||||
"unitTypes": ["WaterMelee"]
|
"unitTypes": ["WaterMelee"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Coastal Raider III",
|
"name": "Coastal Raider III",
|
||||||
"prerequisites": ["Coastal Raider II"],
|
"prerequisites": ["Coastal Raider II"],
|
||||||
"effect": "+[15]% Strength vs [City]",
|
"uniques": ["+[20]% Strength vs [City]", "Earn [33]% of the damage done to [City] units as [Gold]"],
|
||||||
"unitTypes": ["WaterMelee"]
|
"unitTypes": ["WaterMelee"]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@
|
|||||||
"strength": 10,
|
"strength": 10,
|
||||||
"cost": 45,
|
"cost": 45,
|
||||||
"requiredTech": "Sailing",
|
"requiredTech": "Sailing",
|
||||||
"uniques": ["Cannot enter ocean tiles",],
|
"uniques": ["Cannot enter ocean tiles"],
|
||||||
"upgradesTo": "Caravel",
|
"upgradesTo": "Caravel",
|
||||||
"obsoleteTech": "Astronomy",
|
"obsoleteTech": "Astronomy",
|
||||||
"attackSound": "nonmetalhit"
|
"attackSound": "nonmetalhit"
|
||||||
@ -790,6 +790,17 @@
|
|||||||
"uniques": ["+[50]% Strength vs [Mounted]"],
|
"uniques": ["+[50]% Strength vs [Mounted]"],
|
||||||
"attackSound": "shot"
|
"attackSound": "shot"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Privateer",
|
||||||
|
"unitType": "WaterMelee",
|
||||||
|
"movement": 5,
|
||||||
|
"strength": 25,
|
||||||
|
"cost": 150,
|
||||||
|
"requiredTech": "Navigation",
|
||||||
|
"upgradesTo": "Destroyer",
|
||||||
|
"promotions": ["Coastal Raider I"],
|
||||||
|
"uniques": ["May capture killed [Water] units"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Frigate",
|
"name": "Frigate",
|
||||||
"unitType": "WaterRanged",
|
"unitType": "WaterRanged",
|
||||||
@ -1057,7 +1068,7 @@
|
|||||||
"cost": 375,
|
"cost": 375,
|
||||||
"requiredResource": "Oil",
|
"requiredResource": "Oil",
|
||||||
"requiredTech": "Electronics",
|
"requiredTech": "Electronics",
|
||||||
"uniques": ["Ranged attacks may be performed over obstacles"],
|
"uniques": ["Ranged attacks may be performed over obstacles"]
|
||||||
// Does not actually upgrade to Missile Cruisers
|
// Does not actually upgrade to Missile Cruisers
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -446,6 +446,8 @@ A(n) [nukeType] exploded in our territory! =
|
|||||||
After being hit by our [nukeType], [civName] has declared war on us!
|
After being hit by our [nukeType], [civName] has declared war on us!
|
||||||
The civilization of [civName] has been destroyed! =
|
The civilization of [civName] has been destroyed! =
|
||||||
The City-State of [name] has been destroyed! =
|
The City-State of [name] has been destroyed! =
|
||||||
|
Your [ourUnit] captured an enemy [theirUnit]! =
|
||||||
|
Your [ourUnit] plundered [amount] [Stat] from [theirUnit] =
|
||||||
We have captured a barbarian encampment and recovered [goldAmount] gold! =
|
We have captured a barbarian encampment and recovered [goldAmount] gold! =
|
||||||
A barbarian [unitType] has joined us! =
|
A barbarian [unitType] has joined us! =
|
||||||
We have found survivors in the ruins - population added to [cityName] =
|
We have found survivors in the ruins - population added to [cityName] =
|
||||||
|
@ -12,7 +12,6 @@ import com.unciv.models.AttackableTile
|
|||||||
import com.unciv.models.ruleset.Unique
|
import com.unciv.models.ruleset.Unique
|
||||||
import com.unciv.models.ruleset.unit.UnitType
|
import com.unciv.models.ruleset.unit.UnitType
|
||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
import com.unciv.models.translations.tr
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
@ -72,20 +71,16 @@ object Battle {
|
|||||||
if (!defender.isDefeated() && defender is MapUnitCombatant && defender.unit.action == Constants.unitActionExplore)
|
if (!defender.isDefeated() && defender is MapUnitCombatant && defender.unit.action == Constants.unitActionExplore)
|
||||||
defender.unit.action = null
|
defender.unit.action = null
|
||||||
|
|
||||||
// we're a melee unit and we destroyed\captured an enemy unit
|
|
||||||
postBattleMoveToAttackedTile(attacker, defender, attackedTile)
|
|
||||||
|
|
||||||
reduceAttackerMovementPointsAndAttacks(attacker, defender)
|
|
||||||
|
|
||||||
if (!isAlreadyDefeatedCity) postBattleAddXp(attacker, defender)
|
|
||||||
|
|
||||||
// Add culture when defeating a barbarian when Honor policy is adopted, gold from enemy killed when honor is complete
|
// Add culture when defeating a barbarian when Honor policy is adopted, gold from enemy killed when honor is complete
|
||||||
// or any enemy military unit with Sacrificial captives unique (can be either attacker or defender!)
|
// or any enemy military unit with Sacrificial captives unique (can be either attacker or defender!)
|
||||||
|
// or check if unit is captured by the attacker (prize ships unique)
|
||||||
if (defender.isDefeated() && defender is MapUnitCombatant && !defender.getUnitType().isCivilian()) {
|
if (defender.isDefeated() && defender is MapUnitCombatant && !defender.getUnitType().isCivilian()) {
|
||||||
tryEarnFromKilling(attacker, defender)
|
tryEarnFromKilling(attacker, defender)
|
||||||
|
tryCaptureUnit(attacker, defender)
|
||||||
tryHealAfterKilling(attacker)
|
tryHealAfterKilling(attacker)
|
||||||
} else if (attacker.isDefeated() && attacker is MapUnitCombatant && !attacker.getUnitType().isCivilian()) {
|
} else if (attacker.isDefeated() && attacker is MapUnitCombatant && !attacker.getUnitType().isCivilian()) {
|
||||||
tryEarnFromKilling(defender, attacker)
|
tryEarnFromKilling(defender, attacker)
|
||||||
|
tryCaptureUnit(defender, attacker)
|
||||||
tryHealAfterKilling(defender)
|
tryHealAfterKilling(defender)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +90,14 @@ object Battle {
|
|||||||
else if (attacker.unit.isMoving())
|
else if (attacker.unit.isMoving())
|
||||||
attacker.unit.action = null
|
attacker.unit.action = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we're a melee unit and we destroyed\captured an enemy unit
|
||||||
|
// Should be called after tryCaptureUnit(), as that might spawn a unit on the tile we go to
|
||||||
|
postBattleMoveToAttackedTile(attacker, defender, attackedTile)
|
||||||
|
|
||||||
|
reduceAttackerMovementPointsAndAttacks(attacker, defender)
|
||||||
|
|
||||||
|
if (!isAlreadyDefeatedCity) postBattleAddXp(attacker, defender)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tryEarnFromKilling(civUnit: ICombatant, defeatedUnit: MapUnitCombatant) {
|
private fun tryEarnFromKilling(civUnit: ICombatant, defeatedUnit: MapUnitCombatant) {
|
||||||
@ -125,33 +128,79 @@ object Battle {
|
|||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
} // parameter is not a stat
|
} // parameter is not a stat
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tryCaptureUnit(attacker: ICombatant, defender: ICombatant) {
|
||||||
|
// https://forums.civfanatics.com/threads/prize-ships-for-land-units.650196/
|
||||||
|
// https://civilization.fandom.com/wiki/Module:Data/Civ5/GK/Defines
|
||||||
|
if (!defender.isDefeated()) return
|
||||||
|
if (attacker !is MapUnitCombatant) return
|
||||||
|
if (defender is MapUnitCombatant && !defender.getUnitType().isMilitary()) return
|
||||||
|
if (attacker.unit.getMatchingUniques("May capture killed [] units").none { defender.matchesCategory(it.params[0]) }) return
|
||||||
|
|
||||||
|
var captureChance = 10 + attacker.getAttackingStrength().toFloat() / defender.getDefendingStrength().toFloat() * 40
|
||||||
|
if (captureChance > 80) captureChance = 80f
|
||||||
|
if (100 * Random().nextFloat() > captureChance) return
|
||||||
|
|
||||||
|
val newUnit = attacker.getCivInfo().placeUnitNearTile(defender.getTile().position, defender.getName())
|
||||||
|
if (newUnit == null) return // silently fail
|
||||||
|
attacker.getCivInfo().addNotification("Your [${attacker.getName()}] captured an enemy [${defender.getName()}]", newUnit.getTile().position, NotificationIcon.War)
|
||||||
|
|
||||||
|
newUnit.currentMovement = 0f
|
||||||
|
newUnit.health = 50
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun takeDamage(attacker: ICombatant, defender: ICombatant) {
|
private fun takeDamage(attacker: ICombatant, defender: ICombatant) {
|
||||||
var damageToDefender = BattleDamage.calculateDamageToDefender(attacker, attacker.getTile(), defender)
|
var potentialDamageToDefender = BattleDamage.calculateDamageToDefender(attacker, attacker.getTile(), defender)
|
||||||
var damageToAttacker = BattleDamage.calculateDamageToAttacker(attacker, attacker.getTile(), defender)
|
var potentialDamageToAttacker = BattleDamage.calculateDamageToAttacker(attacker, attacker.getTile(), defender)
|
||||||
|
|
||||||
|
var damageToAttacker = attacker.getHealth() // These variables names don't make any sense as of yet ...
|
||||||
|
var damageToDefender = defender.getHealth()
|
||||||
|
|
||||||
if (defender.getUnitType().isCivilian() && attacker.isMelee()) {
|
if (defender.getUnitType().isCivilian() && attacker.isMelee()) {
|
||||||
captureCivilianUnit(attacker, defender as MapUnitCombatant)
|
captureCivilianUnit(attacker, defender as MapUnitCombatant)
|
||||||
} else if (attacker.isRanged()) {
|
} else if (attacker.isRanged()) {
|
||||||
defender.takeDamage(damageToDefender) // straight up
|
defender.takeDamage(potentialDamageToDefender) // straight up
|
||||||
} else {
|
} else {
|
||||||
//melee attack is complicated, because either side may defeat the other midway
|
//melee attack is complicated, because either side may defeat the other midway
|
||||||
//so...for each round, we randomize who gets the attack in. Seems to be a good way to work for now.
|
//so...for each round, we randomize who gets the attack in. Seems to be a good way to work for now.
|
||||||
|
|
||||||
while (damageToDefender + damageToAttacker > 0) {
|
while (potentialDamageToDefender + potentialDamageToAttacker > 0) {
|
||||||
if (Random().nextInt(damageToDefender + damageToAttacker) < damageToDefender) {
|
if (Random().nextInt(potentialDamageToDefender + potentialDamageToAttacker) < potentialDamageToDefender) {
|
||||||
damageToDefender--
|
potentialDamageToDefender--
|
||||||
defender.takeDamage(1)
|
defender.takeDamage(1)
|
||||||
if (defender.isDefeated()) break
|
if (defender.isDefeated()) break
|
||||||
} else {
|
} else {
|
||||||
damageToAttacker--
|
potentialDamageToAttacker--
|
||||||
attacker.takeDamage(1)
|
attacker.takeDamage(1)
|
||||||
if (attacker.isDefeated()) break
|
if (attacker.isDefeated()) break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
damageToAttacker -= attacker.getHealth() // ... but from here on they are accurate
|
||||||
|
damageToDefender -= defender.getHealth()
|
||||||
|
|
||||||
|
if (attacker is MapUnitCombatant) {
|
||||||
|
for (unique in attacker.unit.getMatchingUniques("Earn []% of the damage done to [] units as []"))
|
||||||
|
if (defender.matchesCategory(unique.params[1])) {
|
||||||
|
val resourcesPlundered =
|
||||||
|
(unique.params[0].toFloat() / 100f * damageToDefender).toInt()
|
||||||
|
attacker.getCivInfo().addStat(Stat.valueOf(unique.params[2]), resourcesPlundered)
|
||||||
|
attacker.getCivInfo()
|
||||||
|
.addNotification(
|
||||||
|
"Your [${attacker.getName()}] plundered [${resourcesPlundered}] [${unique.params[2]}] from [${defender.getName()}]",
|
||||||
|
defender.getTile().position,
|
||||||
|
NotificationIcon.War
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (defender is MapUnitCombatant) {
|
||||||
|
for (unique in defender.unit.getMatchingUniques("Earn []% of the damage done to [] units as []"))
|
||||||
|
if (attacker.matchesCategory(unique.params[1]))
|
||||||
|
defender.getCivInfo().addStat(Stat.valueOf(unique.params[2]), (unique.params[0].toFloat() / 100f * damageToAttacker).toInt())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -380,7 +429,7 @@ object Battle {
|
|||||||
attacker.popupAlerts.add(PopupAlert(AlertType.Defeated, attackedCiv.civName))
|
attacker.popupAlerts.add(PopupAlert(AlertType.Defeated, attackedCiv.civName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun NUKE(attacker: MapUnitCombatant, targetTile: TileInfo) {
|
fun NUKE(attacker: MapUnitCombatant, targetTile: TileInfo) {
|
||||||
val attackingCiv = attacker.getCivInfo()
|
val attackingCiv = attacker.getCivInfo()
|
||||||
fun tryDeclareWar(civSuffered: CivilizationInfo) {
|
fun tryDeclareWar(civSuffered: CivilizationInfo) {
|
||||||
@ -392,8 +441,8 @@ object Battle {
|
|||||||
attackingCiv.addNotification("After being hit by our [${attacker.getName()}], [${civSuffered}] has declared war on us!", targetTile.position, NotificationIcon.War)
|
attackingCiv.addNotification("After being hit by our [${attacker.getName()}], [${civSuffered}] has declared war on us!", targetTile.position, NotificationIcon.War)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val blastRadius =
|
val blastRadius =
|
||||||
if (!attacker.unit.hasUnique("Blast radius []")) 2
|
if (!attacker.unit.hasUnique("Blast radius []")) 2
|
||||||
else attacker.unit.getMatchingUniques("Blast radius []").first().params[0].toInt()
|
else attacker.unit.getMatchingUniques("Blast radius []").first().params[0].toInt()
|
||||||
|
|
||||||
@ -405,13 +454,13 @@ object Battle {
|
|||||||
//
|
//
|
||||||
else -> return
|
else -> return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the tiles that are hit
|
// Calculate the tiles that are hit
|
||||||
val hitTiles = targetTile.getTilesInDistance(blastRadius)
|
val hitTiles = targetTile.getTilesInDistance(blastRadius)
|
||||||
|
|
||||||
// Declare war on the owners of all hit tiles
|
// Declare war on the owners of all hit tiles
|
||||||
for (hitCiv in hitTiles.mapNotNull { it.getOwner() }.distinct()) {
|
for (hitCiv in hitTiles.mapNotNull { it.getOwner() }.distinct()) {
|
||||||
hitCiv.addNotification("A(n) [${attacker.getName()}] exploded in our territory!".tr(), targetTile.position, NotificationIcon.War)
|
hitCiv.addNotification("A(n) [${attacker.getName()}] exploded in our territory!", targetTile.position, NotificationIcon.War)
|
||||||
tryDeclareWar(hitCiv)
|
tryDeclareWar(hitCiv)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,14 +472,14 @@ object Battle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (attacker.isDefeated()) return
|
if (attacker.isDefeated()) return
|
||||||
|
|
||||||
// Destroy units on the target tile
|
// Destroy units on the target tile
|
||||||
for (defender in targetTile.getUnits().filter { it != attacker.unit }) {
|
for (defender in targetTile.getUnits().filter { it != attacker.unit }) {
|
||||||
defender.destroy()
|
defender.destroy()
|
||||||
postBattleNotifications(attacker, MapUnitCombatant(defender), defender.getTile())
|
postBattleNotifications(attacker, MapUnitCombatant(defender), defender.getTile())
|
||||||
destroyIfDefeated(defender.civInfo, attacker.getCivInfo())
|
destroyIfDefeated(defender.civInfo, attacker.getCivInfo())
|
||||||
}
|
}
|
||||||
|
|
||||||
for (tile in hitTiles) {
|
for (tile in hitTiles) {
|
||||||
// Handle complicated effects
|
// Handle complicated effects
|
||||||
when (strength) {
|
when (strength) {
|
||||||
@ -439,19 +488,19 @@ object Battle {
|
|||||||
else -> nukeStrength1Effect(attacker, tile)
|
else -> nukeStrength1Effect(attacker, tile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instead of postBattleAction() just destroy the unit, all other functions are not relevant
|
// Instead of postBattleAction() just destroy the unit, all other functions are not relevant
|
||||||
if (attacker.unit.hasUnique("Self-destructs when attacking")) {
|
if (attacker.unit.hasUnique("Self-destructs when attacking")) {
|
||||||
attacker.unit.destroy()
|
attacker.unit.destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's unclear whether using nukes results in a penalty with all civs, or only affected civs.
|
// It's unclear whether using nukes results in a penalty with all civs, or only affected civs.
|
||||||
// For now I'll make it give a diplomatic penalty to all known civs, but some testing for this would be appreciated
|
// For now I'll make it give a diplomatic penalty to all known civs, but some testing for this would be appreciated
|
||||||
for (civ in attackingCiv.getKnownCivs()) {
|
for (civ in attackingCiv.getKnownCivs()) {
|
||||||
civ.getDiplomacyManager(attackingCiv).setModifier(DiplomaticModifiers.UsedNuclearWeapons, -50f)
|
civ.getDiplomacyManager(attackingCiv).setModifier(DiplomaticModifiers.UsedNuclearWeapons, -50f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nukeStrength1Effect(attacker: MapUnitCombatant, tile: TileInfo) {
|
private fun nukeStrength1Effect(attacker: MapUnitCombatant, tile: TileInfo) {
|
||||||
// https://forums.civfanatics.com/resources/unit-guide-modern-future-units-g-k.25628/
|
// https://forums.civfanatics.com/resources/unit-guide-modern-future-units-g-k.25628/
|
||||||
// https://www.carlsguides.com/strategy/civilization5/units/aircraft-nukes.php
|
// https://www.carlsguides.com/strategy/civilization5/units/aircraft-nukes.php
|
||||||
@ -462,7 +511,7 @@ object Battle {
|
|||||||
if (civResources[resource]!! < 0 && !attacker.getCivInfo().isBarbarian())
|
if (civResources[resource]!! < 0 && !attacker.getCivInfo().isBarbarian())
|
||||||
damageModifierFromMissingResource *= 0.5f // I could not find a source for this number, but this felt about right
|
damageModifierFromMissingResource *= 0.5f // I could not find a source for this number, but this felt about right
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrease health & population of a hit city
|
// Decrease health & population of a hit city
|
||||||
val city = tile.getCity()
|
val city = tile.getCity()
|
||||||
if (city != null && tile.position == city.location) {
|
if (city != null && tile.position == city.location) {
|
||||||
@ -484,7 +533,7 @@ object Battle {
|
|||||||
}
|
}
|
||||||
postBattleNotifications(attacker, CityCombatant(city), city.getCenterTile())
|
postBattleNotifications(attacker, CityCombatant(city), city.getCenterTile())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Damage and/or destroy units on the tile
|
// Damage and/or destroy units on the tile
|
||||||
for (unit in tile.getUnits()) {
|
for (unit in tile.getUnits()) {
|
||||||
val defender = MapUnitCombatant(unit)
|
val defender = MapUnitCombatant(unit)
|
||||||
@ -496,7 +545,7 @@ object Battle {
|
|||||||
postBattleNotifications(attacker, defender, defender.getTile())
|
postBattleNotifications(attacker, defender, defender.getTile())
|
||||||
destroyIfDefeated(defender.getCivInfo(), attacker.getCivInfo())
|
destroyIfDefeated(defender.getCivInfo(), attacker.getCivInfo())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove improvements, add fallout
|
// Remove improvements, add fallout
|
||||||
tile.improvement = null
|
tile.improvement = null
|
||||||
tile.improvementInProgress = null
|
tile.improvementInProgress = null
|
||||||
@ -514,7 +563,7 @@ object Battle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nukeStrength2Effect(attacker: MapUnitCombatant, tile: TileInfo) {
|
private fun nukeStrength2Effect(attacker: MapUnitCombatant, tile: TileInfo) {
|
||||||
// https://forums.civfanatics.com/threads/unit-guide-modern-future-units-g-k.429987/#2
|
// https://forums.civfanatics.com/threads/unit-guide-modern-future-units-g-k.429987/#2
|
||||||
// https://www.carlsguides.com/strategy/civilization5/units/aircraft-nukes.php
|
// https://www.carlsguides.com/strategy/civilization5/units/aircraft-nukes.php
|
||||||
@ -525,7 +574,7 @@ object Battle {
|
|||||||
if (civResources[resource]!! < 0 && !attacker.getCivInfo().isBarbarian())
|
if (civResources[resource]!! < 0 && !attacker.getCivInfo().isBarbarian())
|
||||||
damageModifierFromMissingResource *= 0.5f // I could not find a source for this number, but this felt about right
|
damageModifierFromMissingResource *= 0.5f // I could not find a source for this number, but this felt about right
|
||||||
}
|
}
|
||||||
|
|
||||||
// Damage and/or destroy cities
|
// Damage and/or destroy cities
|
||||||
val city = tile.getCity()
|
val city = tile.getCity()
|
||||||
if (city != null && city.location == tile.position) {
|
if (city != null && city.location == tile.position) {
|
||||||
@ -549,14 +598,14 @@ object Battle {
|
|||||||
postBattleNotifications(attacker, CityCombatant(city), city.getCenterTile())
|
postBattleNotifications(attacker, CityCombatant(city), city.getCenterTile())
|
||||||
destroyIfDefeated(city.civInfo, attacker.getCivInfo())
|
destroyIfDefeated(city.civInfo, attacker.getCivInfo())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy all hit units
|
// Destroy all hit units
|
||||||
for (defender in tile.getUnits()) {
|
for (defender in tile.getUnits()) {
|
||||||
defender.destroy()
|
defender.destroy()
|
||||||
postBattleNotifications(attacker, MapUnitCombatant(defender), defender.currentTile)
|
postBattleNotifications(attacker, MapUnitCombatant(defender), defender.currentTile)
|
||||||
destroyIfDefeated(defender.civInfo, attacker.getCivInfo())
|
destroyIfDefeated(defender.civInfo, attacker.getCivInfo())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove improvements
|
// Remove improvements
|
||||||
tile.improvement = null
|
tile.improvement = null
|
||||||
tile.improvementInProgress = null
|
tile.improvementInProgress = null
|
||||||
|
@ -74,6 +74,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
|||||||
* [Black powder musket](https://thenounproject.com/term/black-powder-musket/1202078/) By Jarem Fyre for Minuteman
|
* [Black powder musket](https://thenounproject.com/term/black-powder-musket/1202078/) By Jarem Fyre for Minuteman
|
||||||
* [Rapier](https://thenounproject.com/search/?q=musketeer&i=819822) By Hamish for Musketeer
|
* [Rapier](https://thenounproject.com/search/?q=musketeer&i=819822) By Hamish for Musketeer
|
||||||
* [Ship](https://thenounproject.com/term/ship/1293899/) By Orin Zuu for Frigate
|
* [Ship](https://thenounproject.com/term/ship/1293899/) By Orin Zuu for Frigate
|
||||||
|
* [Pirate](https://thenounproject.com/search/?q=pirate&i=2349496) by Berkah Icon for Privateer
|
||||||
* [Ship](https://thenounproject.com/search/?q=ship&i=800131) By Mungang Kim for Ship of the Line
|
* [Ship](https://thenounproject.com/search/?q=ship&i=800131) By Mungang Kim for Ship of the Line
|
||||||
* [Lance](https://thenounproject.com/search/?q=Lance&i=440122) By parkjisun for Lancer
|
* [Lance](https://thenounproject.com/search/?q=Lance&i=440122) By parkjisun for Lancer
|
||||||
* [Sword](https://thenounproject.com/search/?q=saber&i=1174742) By Daniela Baptista for Sipahi
|
* [Sword](https://thenounproject.com/search/?q=saber&i=1174742) By Daniela Baptista for Sipahi
|
||||||
|
Reference in New Issue
Block a user