From b6fa2a24e84e13e20d1697b137663ffbb7220907 Mon Sep 17 00:00:00 2001 From: test Date: Tue, 9 Jul 2024 11:31:47 +1000 Subject: [PATCH] WIP port grant to slash --- .../apiv1/enums/city/building/Buildings.java | 1 + .../v2/impl/pw/commands/GrantCommands.java | 181 ++++++++++++++++-- .../commands/sheets/DepositsSheet.java | 34 ++-- .../locutus/discord/db/entities/DBNation.java | 2 +- .../discord/event/mail/MailReceivedEvent.java | 4 + .../discord/util/update/MailListener.java | 4 +- 6 files changed, 196 insertions(+), 30 deletions(-) diff --git a/src/main/java/link/locutus/discord/apiv1/enums/city/building/Buildings.java b/src/main/java/link/locutus/discord/apiv1/enums/city/building/Buildings.java index 34a7f173..31a264ea 100644 --- a/src/main/java/link/locutus/discord/apiv1/enums/city/building/Buildings.java +++ b/src/main/java/link/locutus/discord/apiv1/enums/city/building/Buildings.java @@ -133,6 +133,7 @@ public int cap(Predicate hasProject) { public final static Building[] BUILDINGS; public final static Building[] POLLUTION_BUILDINGS; public final static Building[] COMMERCE_BUILDINGS = {SUBWAY, MALL, STADIUM, BANK, SUPERMARKET}; + public final static Building[] MILITARY_BUILDINGS = {BARRACKS, FACTORY, HANGAR, DRYDOCK}; public final static Map RESOURCE_BUILDING = new ConcurrentHashMap<>(); static { diff --git a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/GrantCommands.java b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/GrantCommands.java index 0c157253..05bd63e0 100644 --- a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/GrantCommands.java +++ b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/GrantCommands.java @@ -3,6 +3,9 @@ import link.locutus.discord.Locutus; import link.locutus.discord.apiv1.enums.*; import link.locutus.discord.apiv1.enums.city.JavaCity; +import link.locutus.discord.apiv1.enums.city.building.Building; +import link.locutus.discord.apiv1.enums.city.building.Buildings; +import link.locutus.discord.apiv1.enums.city.building.MilitaryBuilding; import link.locutus.discord.apiv1.enums.city.project.Project; import link.locutus.discord.apiv1.enums.city.project.Projects; import link.locutus.discord.commands.manager.v2.binding.annotation.*; @@ -16,10 +19,7 @@ import link.locutus.discord.commands.manager.v2.impl.pw.NationFilter; import link.locutus.discord.config.Settings; import link.locutus.discord.db.GuildDB; -import link.locutus.discord.db.entities.DBAlliance; -import link.locutus.discord.db.entities.DBNation; -import link.locutus.discord.db.entities.MMRInt; -import link.locutus.discord.db.entities.TaxBracket; +import link.locutus.discord.db.entities.*; import link.locutus.discord.db.entities.grant.AGrantTemplate; import link.locutus.discord.db.entities.grant.BuildTemplate; import link.locutus.discord.db.entities.grant.CityTemplate; @@ -161,7 +161,7 @@ public String grantProject( public String grantInfra( @Me IMessageIO io, @Me GuildDB db, @Me DBNation me, @Me User author, Set receivers, - @Range(min=50, max=10000) int amount, + @Range(min=50, max=10000) int infra_level, @Switch("o") boolean onlySendMissingFunds, @Arg("The nation account to deduct from") @Switch("n") DBNation depositsAccount, @Arg("The alliance bank to send from\nDefaults to the offshore") @Switch("a") DBAlliance useAllianceBank, @@ -175,30 +175,183 @@ public String grantInfra( @Arg("The mode for escrowing funds (e.g. if the receiver is blockaded)\nDefaults to never") @Switch("em") EscrowMode escrow_mode, @Switch("u") Boolean urbanization, + @Switch("aec") Boolean advanced_engineering_corps, + @Switch("cfce") Boolean center_for_civil_engineering, @Switch("gsa") Boolean gov_support_agency, @Switch("b") boolean bypass_checks, @Switch("f") boolean force + ) throws IOException, GeneralSecurityException { + return Grant.generateCommandLogic(io, db, me, author, receivers, onlySendMissingFunds, depositsAccount, useAllianceBank, useOffshoreAccount, taxAccount, existingTaxAccount, expire, decay, ignore, convertToMoney, escrow_mode, bypass_checks, force, + receiver -> { + double cost = receiver.getBuyInfraCost(infra_level, + urbanization != null ? urbanization : false, + advanced_engineering_corps != null ? advanced_engineering_corps : false, + center_for_civil_engineering != null ? center_for_civil_engineering : false, + gov_support_agency != null ? gov_support_agency : false); + if (cost <= 0) { + TransferResult error = new TransferResult(OffshoreInstance.TransferStatus.NOTHING_WITHDRAWN, receiver, new HashMap<>(), "Nation already has infra level: " + infra_level); + return Triple.of(null, null, error); + } + return Triple.of(ResourceType.MONEY.toArray(cost), DepositType.INFRA.withAmount(infra_level), null); + }, DepositType.INFRA, receiver -> { + return InfraTemplate.getRequirements(me, receiver, null, (double) infra_level); + }); + } + + // land + @Command(desc = "Grant land to a set of nations") + @RolePermission(Roles.ECON) + @IsAlliance + public String grantLand( + @Me IMessageIO io, @Me GuildDB db, @Me DBNation me, @Me User author, + Set receivers, + @Range(min=1, max=10000) int to_land, + @Switch("o") boolean onlySendMissingFunds, + @Arg("The nation account to deduct from") @Switch("n") DBNation depositsAccount, + @Arg("The alliance bank to send from\nDefaults to the offshore") @Switch("a") DBAlliance useAllianceBank, + @Arg("The alliance account to deduct from\nAlliance must be registered to this guild\nDefaults to all the alliances of this guild") @Switch("o") DBAlliance useOffshoreAccount, + @Arg("The tax account to deduct from") @Switch("t") TaxBracket taxAccount, + @Arg("Deduct from the receiver's tax bracket account") @Switch("ta") boolean existingTaxAccount, + @Arg("Have the transfer ignored from nation holdings after a timeframe") @Switch("e") @Timediff Long expire, + @Arg("Have the transfer decrease linearly from balances over a timeframe") @Switch("d") @Timediff Long decay, + @Switch("i") boolean ignore, + @Arg("Have the transfer valued as cash in nation holdings")@Switch("m") boolean convertToMoney, + @Arg("The mode for escrowing funds (e.g. if the receiver is blockaded)\nDefaults to never") @Switch("em") EscrowMode escrow_mode, + + @Switch("ra") Boolean rapid_expansion, + @Switch("aec") Boolean advanced_engineering_corps, + @Switch("ala") Boolean arable_land_agency, + @Switch("gsa") Boolean gov_support_agency, + + @Switch("b") boolean bypass_checks, + @Switch("f") boolean force ) throws IOException, GeneralSecurityException { return Grant.generateCommandLogic(io, db, me, author, receivers, onlySendMissingFunds, depositsAccount, useAllianceBank, useOffshoreAccount, taxAccount, existingTaxAccount, expire, decay, ignore, convertToMoney, escrow_mode, bypass_checks, force, receiver -> { - // infra is per city, not nation - return null; - }, DepositType.INFRA, receiver -> { - return InfraTemplate.getRequirements(me, receiver, null, (double) amount); + double cost = receiver.getBuyLandCost(to_land, + rapid_expansion != null ? rapid_expansion : false, + advanced_engineering_corps != null ? advanced_engineering_corps : false, + arable_land_agency != null ? arable_land_agency : false, + gov_support_agency != null ? gov_support_agency : false); + if (cost <= 0) { + TransferResult error = new TransferResult(OffshoreInstance.TransferStatus.NOTHING_WITHDRAWN, receiver, new HashMap<>(), "Nation already has " + to_land + " land"); + return Triple.of(null, null, error); + } + return Triple.of(ResourceType.MONEY.toArray(cost), DepositType.LAND.withAmount(to_land), null); + }, DepositType.LAND, receiver -> { + return LandTemplate.getRequirements(me, receiver, null, (double) to_land); }); } - // land + // unit + @Command(desc = "Grant units to a set of nations") + @RolePermission(Roles.ECON) + @IsAlliance + public String grantUnit( + @Me IMessageIO io, @Me GuildDB db, @Me DBNation me, @Me User author, + Set receivers, + Map units, + boolean scale_per_city, + boolean only_missing_units, - // build + @Switch("o") boolean onlySendMissingFunds, + @Arg("The nation account to deduct from") @Switch("n") DBNation depositsAccount, + @Arg("The alliance bank to send from\nDefaults to the offshore") @Switch("a") DBAlliance useAllianceBank, + @Arg("The alliance account to deduct from\nAlliance must be registered to this guild\nDefaults to all the alliances of this guild") @Switch("o") DBAlliance useOffshoreAccount, + @Arg("The tax account to deduct from") @Switch("t") TaxBracket taxAccount, + @Arg("Deduct from the receiver's tax bracket account") @Switch("ta") boolean existingTaxAccount, + @Arg("Have the transfer ignored from nation holdings after a timeframe") @Switch("e") @Timediff Long expire, + @Arg("Have the transfer decrease linearly from balances over a timeframe") @Switch("d") @Timediff Long decay, + @Switch("i") boolean ignore, + @Arg("Have the transfer valued as cash in nation holdings")@Switch("m") boolean convertToMoney, + @Arg("The mode for escrowing funds (e.g. if the receiver is blockaded)\nDefaults to never") @Switch("em") EscrowMode escrow_mode, + + @Switch("b") boolean bypass_checks, + @Switch("f") boolean force + ) throws IOException, GeneralSecurityException { + return Grant.generateCommandLogic(io, db, me, author, receivers, onlySendMissingFunds, depositsAccount, useAllianceBank, useOffshoreAccount, taxAccount, existingTaxAccount, expire, decay, ignore, convertToMoney, escrow_mode, bypass_checks, force, + receiver -> { + Map unitsToGrant = new HashMap<>(); + units.forEach((unit, amount) -> { + long scaledAmount = scale_per_city ? amount * receiver.getCities() : amount; + long current = receiver.getUnits(unit); + long finalAmount = only_missing_units ? Math.max(scaledAmount - current, 0) : scaledAmount; + if (finalAmount > 0) { + unitsToGrant.put(unit, finalAmount); + } + }); + if (unitsToGrant.isEmpty()) { + TransferResult error = new TransferResult(OffshoreInstance.TransferStatus.NOTHING_WITHDRAWN, receiver, new HashMap<>(), "Nation already has the units"); + return Triple.of(null, null, error); + } + ResourceType.ResourcesBuilder cost = ResourceType.builder(); + unitsToGrant.forEach((unit, amount) -> { + cost.add(unit.getCost(amount.intValue())); + }); + return Triple.of(cost.build(), DepositType.WARCHEST.withValue(), null); + }, + DepositType.WARCHEST, receiver -> { + return null; + }); + } // mmr - // mmrbuy - // unit + @Command(desc = "Grant units equivalent to an MMR value to a set of nations") + @RolePermission(Roles.ECON) + @IsAlliance + public String grantMMR( + @Me IMessageIO io, @Me GuildDB db, @Me DBNation me, @Me User author, + Set receivers, + MMRDouble mmr, + @Arg("If the mmr being granted is for new units, rather than only the difference from current units") @Switch("n") boolean is_additional, + @Switch("o") boolean onlySendMissingFunds, + @Arg("The nation account to deduct from") @Switch("n") DBNation depositsAccount, + @Arg("The alliance bank to send from\nDefaults to the offshore") @Switch("a") DBAlliance useAllianceBank, + @Arg("The alliance account to deduct from\nAlliance must be registered to this guild\nDefaults to all the alliances of this guild") @Switch("o") DBAlliance useOffshoreAccount, + @Arg("The tax account to deduct from") @Switch("t") TaxBracket taxAccount, + @Arg("Deduct from the receiver's tax bracket account") @Switch("ta") boolean existingTaxAccount, + @Arg("Have the transfer ignored from nation holdings after a timeframe") @Switch("e") @Timediff Long expire, + @Arg("Have the transfer decrease linearly from balances over a timeframe") @Switch("d") @Timediff Long decay, + @Switch("i") boolean ignore, + @Arg("Have the transfer valued as cash in nation holdings")@Switch("m") boolean convertToMoney, + @Arg("The mode for escrowing funds (e.g. if the receiver is blockaded)\nDefaults to never") @Switch("em") EscrowMode escrow_mode, + + @Switch("b") boolean bypass_checks, + @Switch("f") boolean force + ) throws IOException, GeneralSecurityException { + return Grant.generateCommandLogic(io, db, me, author, receivers, onlySendMissingFunds, depositsAccount, useAllianceBank, useOffshoreAccount, taxAccount, existingTaxAccount, expire, decay, ignore, convertToMoney, escrow_mode, bypass_checks, force, + receiver -> { + int cities = receiver.getCities(); + Map unitsToGrant = new HashMap<>(); + for (Building building : Buildings.MILITARY_BUILDINGS) { + MilitaryBuilding militaryBuilding = (MilitaryBuilding) building; + MilitaryUnit unit = militaryBuilding.getMilitaryUnit(); + double pctGrant = mmr.getPercent(unit); + int unitCap = militaryBuilding.cap(receiver::hasProject) * militaryBuilding.getUnitCap() * cities; + double currPct = receiver.getUnits(unit) / (double) unitCap; + if (!is_additional) { + pctGrant -= currPct; + } + int numUnits = (int) Math.ceil(pctGrant * unitCap); + if (numUnits > 0) unitsToGrant.put(unit, numUnits); + } + if (unitsToGrant.isEmpty()) { + TransferResult error = new TransferResult(OffshoreInstance.TransferStatus.NOTHING_WITHDRAWN, receiver, new HashMap<>(), "Nation already has the units"); + return Triple.of(null, null, error); + } + ResourceType.ResourcesBuilder cost = ResourceType.builder(); + unitsToGrant.forEach((unit, amount) -> cost.add(unit.getCost(amount))); + return Triple.of(cost.build(), DepositType.WARCHEST.withValue(), null); + + }, DepositType.WARCHEST, receiver -> { + return null; + }); + } // consumption - // ?? warchest + // build + // warchest_ratio // Template commands diff --git a/src/main/java/link/locutus/discord/commands/sheets/DepositsSheet.java b/src/main/java/link/locutus/discord/commands/sheets/DepositsSheet.java index 8723cbac..c2ddd7ae 100644 --- a/src/main/java/link/locutus/discord/commands/sheets/DepositsSheet.java +++ b/src/main/java/link/locutus/discord/commands/sheets/DepositsSheet.java @@ -70,20 +70,31 @@ public String onCommand(Guild guild, IMessageIO channel, User author, DBNation m } } + boolean ignoreTaxBase = flags.contains('b'); + boolean ignoreOffset = flags.contains('o'); + boolean noLoans = flags.contains('l'); + boolean noGrants = flags.contains('g'); + boolean noTaxes = flags.contains('t'); + boolean noDeposits = flags.contains('d'); + Set includePastDepositors = flags.contains('p') ? db.getAllianceIds() : null; + boolean noEscrowSheet = flags.contains('e'); + return BankCommands.depositSheet( channel, guild, db, nations, tracked == null ? null : new ArrayList<>(tracked).stream().map(f -> DBAlliance.getOrCreate(f.intValue())).collect(Collectors.toSet()), - flags.contains('f'), - flags.contains('o'), - flags.contains('t'), - flags.contains('l'), - flags.contains('g'), - flags.contains('d'), - flags.contains('p') ? db.getAllianceIds() : null, - flags.contains('e'), + ignoreTaxBase, + ignoreOffset, + false, + false, + noTaxes, + noLoans, + noGrants, + noDeposits, + includePastDepositors, + noEscrowSheet, noteFlow == null ? null : PWBindings.DepositType(noteFlow), flags.contains('f') ); @@ -111,12 +122,7 @@ public String onCommand(Guild guild, IMessageIO channel, User author, DBNation m // // sheet.setHeader(header); // -// boolean useTaxBase = !flags.contains('b'); -// boolean useOffset = !flags.contains('o'); -// boolean noLoans = flags.contains('l'); -// boolean noGrants = flags.contains('g'); -// boolean noTaxes = flags.contains('t'); -// boolean noDeposits = flags.contains('d'); + // // double[] aaTotalPositive = ResourceType.getBuffer(); // double[] aaTotalNet = ResourceType.getBuffer(); diff --git a/src/main/java/link/locutus/discord/db/entities/DBNation.java b/src/main/java/link/locutus/discord/db/entities/DBNation.java index b48cccb8..99fe9896 100644 --- a/src/main/java/link/locutus/discord/db/entities/DBNation.java +++ b/src/main/java/link/locutus/discord/db/entities/DBNation.java @@ -6311,7 +6311,7 @@ public void updateCities(boolean bulk) { } public double[] projectCost(Project project) { - return project.cost(getDomesticPolicy() == DomesticPolicy.TECHNOLOGICAL_ADVANCEMENT); + return project.cost(getDomesticPolicy() == DomesticPolicy.TECHNOLOGICAL_ADVANCEMENT, hasProject(Projects.GOVERNMENT_SUPPORT_AGENCY)); } public double getGrossModifier() { diff --git a/src/main/java/link/locutus/discord/event/mail/MailReceivedEvent.java b/src/main/java/link/locutus/discord/event/mail/MailReceivedEvent.java index f3562cbf..b7f72223 100644 --- a/src/main/java/link/locutus/discord/event/mail/MailReceivedEvent.java +++ b/src/main/java/link/locutus/discord/event/mail/MailReceivedEvent.java @@ -54,6 +54,10 @@ public DBNation getAuthNation() { return auth.getNation(); } + public int getAuthNationId() { + return auth.getNationId(); + } + public GuildMessageChannel getChannel() { String[] split = mail.subject.split("/"); if (split.length > 1 && MathMan.isInteger(split[split.length - 1])) { diff --git a/src/main/java/link/locutus/discord/util/update/MailListener.java b/src/main/java/link/locutus/discord/util/update/MailListener.java index e1691ef5..69ca9f5e 100644 --- a/src/main/java/link/locutus/discord/util/update/MailListener.java +++ b/src/main/java/link/locutus/discord/util/update/MailListener.java @@ -89,10 +89,12 @@ public void onMailReceived(MailReceivedEvent event) throws IOException { builder.embed(event.getTitle(), body.toString()); DBNation receiver = Locutus.imp().getNationDB().getNationByLeader(event.getMail().leader); + int authId = event.getAuthNationId(); + CM.mail.reply mailCmd = CM.mail.reply.cmd.receiver(receiver.getId() + "").url(event.getUrl()).message("").sender(event.getAuth().getNationId() + ""); builder.modal(CommandBehavior.DELETE_PRESSED_BUTTON, mailCmd, "\uD83D\uDCE7 Reply"); - builder.commandButton(CM.mail.read.cmd.messageId(event.getMail().id + "").account(receiver.getId() + ""), "Read"); + builder.commandButton(CommandBehavior.UNPRESS, CM.mail.read.cmd.messageId(event.getMail().id + "").account(authId + ""), "Read"); builder.send(); processCommands(Locutus.imp().getGuildDB(guild), guild, outputBuilder, event);