mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-01 02:03:29 +00:00
058bb44273
## Description: Saw this in an Enzo video about beating impossible nations: You can just donate 1% gold / 1% troops to a nation to get a friendly relation with them. This PR adds randomized minimum donation requirements based on the difficulty. Randomized in a way that there is a minimum someone has to donate to surely get the relation improvement, but you can also gamble and send less. For troop donations, the minimum is calculated based on what percentage of their troops the sender donated. For gold donations, it's fixed values. We cannot use percentages here because “having nearly no gold” is a usual case. Donating 100% of your gold wouldn’t hurt if you just spent all your gold on buildings. I tried to add tests for this but it's really horrible. Because the test would have to wait until the relation update from the alliance accepting is gone (we need to have an alliance to send stuff), has returned to Neutral, and then changes back to Friendly after the donation. ## Please complete the following: - [X] I have added screenshots for all UI updates - [X] I process any text displayed to the user through translateText() and I've added it to the en.json file - [X] I have added relevant tests to the test directory - [X] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: FloPinguin --------- Co-authored-by: Evan <evanpelle@gmail.com>
100 lines
2.8 KiB
TypeScript
100 lines
2.8 KiB
TypeScript
import { Difficulty, Execution, Game, Player, PlayerID } from "../game/Game";
|
|
import { PseudoRandom } from "../PseudoRandom";
|
|
import { assertNever } from "../Util";
|
|
|
|
export class DonateTroopsExecution implements Execution {
|
|
private recipient: Player;
|
|
private random: PseudoRandom;
|
|
private mg: Game;
|
|
|
|
private active = true;
|
|
|
|
constructor(
|
|
private sender: Player,
|
|
private recipientID: PlayerID,
|
|
private troops: number | null,
|
|
) {}
|
|
|
|
init(mg: Game, ticks: number): void {
|
|
this.mg = mg;
|
|
this.random = new PseudoRandom(mg.ticks());
|
|
|
|
if (!mg.hasPlayer(this.recipientID)) {
|
|
console.warn(
|
|
`DonateTroopExecution recipient ${this.recipientID} not found`,
|
|
);
|
|
this.active = false;
|
|
return;
|
|
}
|
|
|
|
this.recipient = mg.player(this.recipientID);
|
|
this.troops ??= mg.config().defaultDonationAmount(this.sender);
|
|
const maxDonation =
|
|
mg.config().maxTroops(this.recipient) - this.recipient.troops();
|
|
this.troops = Math.min(this.troops, maxDonation);
|
|
}
|
|
|
|
tick(ticks: number): void {
|
|
if (this.troops === null) throw new Error("not initialized");
|
|
|
|
const minTroops = this.getMinTroopsForRelationUpdate();
|
|
|
|
if (
|
|
this.sender.canDonateTroops(this.recipient) &&
|
|
this.sender.donateTroops(this.recipient, this.troops)
|
|
) {
|
|
// Prevent players from just buying a good relation by sending 1% troops. Instead, a minimum is needed, and it's random.
|
|
if (this.troops >= minTroops) {
|
|
this.recipient.updateRelation(this.sender, 50);
|
|
}
|
|
} else {
|
|
console.warn(
|
|
`cannot send troops from ${this.sender} to ${this.recipient}`,
|
|
);
|
|
}
|
|
this.active = false;
|
|
}
|
|
|
|
private getMinTroopsForRelationUpdate(): number {
|
|
const { difficulty } = this.mg.config().gameConfig();
|
|
const recipientMaxTroops = this.mg.config().maxTroops(this.recipient);
|
|
|
|
switch (difficulty) {
|
|
// ~7.7k - ~9.1k troops (for 100k troops)
|
|
case Difficulty.Easy:
|
|
return this.random.nextInt(
|
|
recipientMaxTroops / 13,
|
|
recipientMaxTroops / 11,
|
|
);
|
|
// ~9.1k - ~11.1k troops (for 100k troops)
|
|
case Difficulty.Medium:
|
|
return this.random.nextInt(
|
|
recipientMaxTroops / 11,
|
|
recipientMaxTroops / 9,
|
|
);
|
|
// ~11.1k - ~14.3k troops (for 100k troops)
|
|
case Difficulty.Hard:
|
|
return this.random.nextInt(
|
|
recipientMaxTroops / 9,
|
|
recipientMaxTroops / 7,
|
|
);
|
|
// ~14.3k - ~20k troops (for 100k troops)
|
|
case Difficulty.Impossible:
|
|
return this.random.nextInt(
|
|
recipientMaxTroops / 7,
|
|
recipientMaxTroops / 5,
|
|
);
|
|
default:
|
|
assertNever(difficulty);
|
|
}
|
|
}
|
|
|
|
isActive(): boolean {
|
|
return this.active;
|
|
}
|
|
|
|
activeDuringSpawnPhase(): boolean {
|
|
return false;
|
|
}
|
|
}
|