-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
23 changed files
with
695 additions
and
609 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import type { BattleStack } from "shared/types/battle"; | ||
|
||
/** | ||
* Sum up unit NP losses | ||
**/ | ||
export const calcBattleSummary = (attackingArmy: BattleStack[], defendingArmy: BattleStack[]) => { | ||
let attackerStartingNP = 0; | ||
let defenderStartingNP = 0; | ||
attackingArmy.forEach(stack => attackerStartingNP += stack.netPower); | ||
defendingArmy.forEach(stack => defenderStartingNP += stack.netPower); | ||
|
||
let attackerPowerLoss = 0; | ||
let attackerUnitLoss = 0; | ||
attackingArmy.forEach(stack => { | ||
const np = stack.unit.powerRank * stack.loss; | ||
attackerPowerLoss += np; | ||
attackerUnitLoss += stack.loss; | ||
// console.log('\t', stack.unit.name, stack.loss, `(net power = ${np})`); | ||
}); | ||
|
||
console.log('=== Defender summary ==='); | ||
let defenderPowerLoss = 0; | ||
let defenderUnitLoss = 0; | ||
defendingArmy.forEach(stack => { | ||
const np = stack.unit.powerRank * stack.loss; | ||
defenderPowerLoss += np; | ||
defenderUnitLoss += stack.loss; | ||
// console.log('\t', stack.unit.name, stack.loss, `(net power = ${np})`); | ||
}); | ||
|
||
|
||
return { | ||
attacker: { | ||
netPower: attackerStartingNP, | ||
netPowerLoss: attackerPowerLoss, | ||
unitsLoss: attackerUnitLoss, | ||
armyLoss: attackingArmy.map(d => ({id: d.unit.id, size: d.loss})) | ||
}, | ||
defender: { | ||
netPower: defenderStartingNP, | ||
netPowerLoss: defenderPowerLoss, | ||
unitsLoss: defenderUnitLoss, | ||
armyLoss: defendingArmy.map(d => ({id: d.unit.id, size: d.loss})) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import type { Mage } from "shared/types/mage"; | ||
import { totalLand } from "../base/mage"; | ||
|
||
/** | ||
* Calculate fort bonus for unit hit points | ||
**/ | ||
export const calcFortBonus = (defenderMage: Mage, attackType: string) => { | ||
const defenderLand = totalLand(defenderMage); | ||
const defenderForts = defenderMage.forts; | ||
const fortsMin = 0.0067; | ||
const fortsMax = 0.0250; | ||
const fortsRatio = Math.min((defenderForts / defenderLand), fortsMax); | ||
|
||
let base = attackType === 'regular' ? 10 : 20; | ||
if (attackType === 'regular' && fortsRatio > fortsMin) { | ||
const additionalBonus = 27.5 * (fortsRatio - fortsMin) / (fortsMax - fortsMin); | ||
base += additionalBonus; | ||
} | ||
|
||
if (attackType === 'siege' && fortsRatio > fortsMin) { | ||
const additionalBonus = 55 * (fortsRatio - fortsMin) / (fortsMax - fortsMin); | ||
base += additionalBonus; | ||
} | ||
return base; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import _ from 'lodash'; | ||
import { Mage } from "shared/types/mage"; | ||
import { totalLand } from "../base/mage"; | ||
|
||
// Lose 10% | ||
const siegePercentage = 0.10; | ||
|
||
// Lose 5% | ||
const regularPercenage = 0.05; | ||
|
||
const unitsNeededPerAcre = 50; | ||
const attackerGain = 0.33; | ||
|
||
export const calcLandLoss = (mage: Mage, attackType: string, unitsRemaining: number) => { | ||
const landLoss = { | ||
farms: 0, | ||
towns: 0, | ||
workshops: 0, | ||
nodes: 0, | ||
barracks: 0, | ||
guilds: 0, | ||
forts: 0, | ||
barriers: 0, | ||
wilderness: 0, | ||
}; | ||
|
||
const landGain = { | ||
farms: 0, | ||
towns: 0, | ||
workshops: 0, | ||
nodes: 0, | ||
barracks: 0, | ||
guilds: 0, | ||
forts: 0, | ||
barriers: 0, | ||
wilderness: 0, | ||
} | ||
|
||
const buildingTypes = [ | ||
'wilderness', 'farms', 'towns', | ||
'workshops', 'nodes', 'barracks', | ||
'guilds', 'barriers', 'forts' | ||
]; | ||
|
||
const takePercentage = attackType === 'siege' ? siegePercentage : regularPercenage; | ||
const mageLand = totalLand(mage); | ||
let landTaken = Math.ceil(Math.min(takePercentage * mageLand, unitsRemaining / unitsNeededPerAcre)); | ||
// result.land = mageLand; | ||
// result.landTaken = landTaken; | ||
|
||
const tempMage = _.pick(mage, buildingTypes); | ||
|
||
const calcLoss = (buildingType: string, val: number) => { | ||
// Handle forts, say 1500 units to take a fort | ||
if (buildingType === 'forts') { | ||
let maxFortTaken = Math.floor(unitsRemaining / 1500); | ||
const forts = Math.floor(Math.min(1 + 0.1 * mage.forts, maxFortTaken)); | ||
return Math.min(forts, tempMage['forts']); | ||
} | ||
return Math.floor(val * landTaken / mageLand); | ||
} | ||
|
||
// To a first round calculation | ||
// Do forts first, then proportionally distribute over remainder building types | ||
landLoss.forts = calcLoss('forts', null); | ||
landTaken -= landLoss.forts; | ||
|
||
buildingTypes.forEach(buildingType => { | ||
if (buildingType === 'forts') return; | ||
landLoss[buildingType] = calcLoss(buildingType, tempMage[buildingType]); | ||
tempMage[buildingType] -= landLoss[buildingType]; | ||
landTaken -= landLoss[buildingType]; | ||
}); | ||
|
||
// Resolve any mathematic remainder | ||
if (landTaken > 0) { | ||
console.log('handle remainder land', landTaken); | ||
|
||
while (landTaken > 0) { | ||
for (const v of buildingTypes) { | ||
if (tempMage[v] > 0) { | ||
landLoss[v] ++; | ||
tempMage[v] --; | ||
landTaken --; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
|
||
landGain.forts = Math.max(1, Math.floor(attackerGain * landLoss.forts)); | ||
buildingTypes.forEach(buildingType => { | ||
if (buildingType === 'forts') return; | ||
landGain[buildingType] = Math.floor(attackerGain * landLoss[buildingType]); | ||
}); | ||
|
||
// Dump any remainder into wilderness | ||
let tempTotal = 0; | ||
buildingTypes.forEach(d => { | ||
tempTotal += landGain[d]; | ||
}); | ||
const extra = Math.floor(attackerGain * landTaken) - tempTotal; | ||
if (extra > 0) { landGain['wilderness'] += extra; } | ||
|
||
|
||
// Done | ||
return { landLoss, landGain }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import type { BattleStack } from "shared/types/battle"; | ||
import { hasHealing, hasRegeneration } from "../base/unit"; | ||
|
||
export const calcHealing = (stack: BattleStack) => { | ||
if (stack.size <= 0) return 0; | ||
|
||
let totalUnitsHealed = 0; | ||
|
||
// Healing points | ||
if (stack.healingPoints > 0 && stack.loss > 0) { | ||
let unitsHealed = Math.floor(stack.healingPoints / stack.unit.hitPoints); | ||
if (unitsHealed >= stack.loss) { | ||
unitsHealed = stack.loss; | ||
} | ||
totalUnitsHealed += unitsHealed; | ||
} | ||
|
||
// Percentage based healing | ||
if (hasHealing(stack.unit)) { | ||
stack.healingBuffer.push(30); | ||
} | ||
if (hasRegeneration(stack.unit)) { | ||
stack.healingBuffer.push(20); | ||
} | ||
if (stack.healingBuffer.length > 0 && stack.loss > 0) { | ||
let heal = 1.0; | ||
stack.healingBuffer.forEach(hValue => { | ||
heal = heal * (100 - hValue) / 100; | ||
}); | ||
heal = 1 - heal; | ||
|
||
let unitsHealed = Math.floor(heal * stack.loss); | ||
// if (unitsHealed >= stack.loss) { | ||
// unitsHealed = stack.loss; | ||
// } | ||
// stack.loss -= unitsHealed; | ||
// stack.size += unitsHealed; | ||
totalUnitsHealed += unitsHealed; | ||
// console.log(`healing ${stack.unit.name} = ${unitsHealed}`); | ||
} | ||
return totalUnitsHealed; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import type { BattleReport } from "shared/types/battle"; | ||
import type { Combatant } from "shared/types/mage"; | ||
import { v4 as uuidv4 } from 'uuid'; | ||
|
||
export const newBattleReport = (attacker: Combatant, defender: Combatant, attackType: string) => { | ||
const battleReport: BattleReport = { | ||
id: uuidv4(), | ||
timestamp: Date.now(), | ||
attackType: attackType, | ||
isSuccessful: false, | ||
|
||
attacker: { | ||
id: attacker.mage.id, | ||
name: attacker.mage.name, | ||
spellId: attacker.spellId, | ||
itemId: attacker.itemId, | ||
army: [] | ||
}, | ||
defender: { | ||
id: defender.mage.id, | ||
name: defender.mage.name, | ||
spellId: defender.spellId, | ||
itemId: defender.itemId, | ||
army: [] | ||
}, | ||
|
||
// Tracking spells, heros, ... etc | ||
preBattle: { | ||
attacker: { | ||
spellResult: null, | ||
itemResult: null, | ||
}, | ||
defender: { | ||
spellResult: null, | ||
itemResult: null, | ||
} | ||
}, | ||
|
||
// Tracking engagement | ||
battleLogs: [], | ||
|
||
// Units lost/gained | ||
postBattleLogs: [], | ||
|
||
// Summary | ||
summary: { | ||
attacker: { | ||
netPower: 0, | ||
netPowerLoss: 0, | ||
unitsLoss: 0, | ||
armyLoss: [] | ||
}, | ||
defender: { | ||
netPower: 0, | ||
netPowerLoss: 0, | ||
unitsLoss: 0, | ||
armyLoss: [] | ||
} | ||
}, | ||
|
||
landResult: { | ||
landLoss: {}, | ||
landGain: {} | ||
} | ||
}; | ||
return battleReport; | ||
} |
Oops, something went wrong.