Serialized powers for the simulatoxr

This commit is contained in:
Samy Avrillon 2024-07-08 13:07:10 +02:00
parent f9bc9e4fa5
commit b783361264
Signed by: Mysaa
GPG Key ID: 0220AC4A3D6A328B
14 changed files with 843 additions and 213 deletions

View File

@ -8,6 +8,7 @@ import java.util.stream.Collectors;
import org.json.JSONObject;
import com.bernard.greposimu.controller.JSONReader;
import com.bernard.greposimu.model.game.GameConfig;
public class GrepoSimu {
@ -24,7 +25,7 @@ public class GrepoSimu {
JSONObject obj = new JSONObject(json);
return new GameConfig(obj);
return JSONReader.makeGameConfig(obj);
}
}
}

View File

@ -2,9 +2,13 @@ package com.bernard.greposimu;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Function;
import com.bernard.greposimu.model.game.Identified;
@ -24,6 +28,13 @@ public class Utils {
return set.stream().filter(x -> x.getId().equals(id)).findAny().orElse(null);
}
public static final <E extends Enum<E>> EnumSet<E> toEnumSet(Class<E> c,Set<E> set){
if(set.isEmpty())
return EnumSet.noneOf(c);
else
return EnumSet.copyOf(set);
}
public static final <T> Map<T,Boolean> setToMap(Set<T> set){
return new AbstractMap<T,Boolean>() {

View File

@ -0,0 +1,357 @@
package com.bernard.greposimu.controller;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.json.JSONObject;
import com.bernard.greposimu.Utils;
import com.bernard.greposimu.model.game.GameConfig;
import com.bernard.greposimu.model.game.God;
import com.bernard.greposimu.model.game.Resources;
import com.bernard.greposimu.model.game.powers.FuryPower;
import com.bernard.greposimu.model.game.powers.GodPower;
import com.bernard.greposimu.model.game.powers.MultitypePower;
import com.bernard.greposimu.model.game.powers.Power;
import com.bernard.greposimu.model.game.researches.Research;
import com.bernard.greposimu.model.game.units.FightType;
import com.bernard.greposimu.model.game.units.Hero;
import com.bernard.greposimu.model.game.units.Hero.HeroCategory;
import com.bernard.greposimu.model.game.units.NavalUnit;
import com.bernard.greposimu.model.game.units.TerrestrialUnit;
import com.bernard.greposimu.model.game.units.TransportUnit;
import com.bernard.greposimu.model.game.units.Unit;
public class JSONReader {
public static GameConfig makeGameConfig(JSONObject json) {
JSONObject godsJ = json.getJSONObject("gods");
Set<God> gods = new HashSet<>();
for(String g : godsJ.keySet()) {
JSONObject godJ = godsJ.getJSONObject(g);
gods.add(new God(godJ.getString("id"), godJ.getString("name")));
}
JSONObject powersJ = json.getJSONObject("powers");
Set<Power> powers = new HashSet<>();
for(String p : powersJ.keySet()) {
System.out.println("Power "+p);
JSONObject power = powersJ.getJSONObject(p);
JSONObject metadefaults = power.isNull("meta_defaults")?null:power.getJSONObject("meta_defaults");
if(power.isNull("god_id") || power.getString("god_id").isEmpty()) {
// DETECTING TYPE DEPEDENCY
boolean dependent =
power.optJSONObject("name")!=null ||
power.optJSONObject("effect")!=null ||
power.optJSONObject("description")!=null;
String dependentKind = dependent?
(metadefaults != null && metadefaults.has("type"))?"type":
(metadefaults != null && metadefaults.has("god"))?"god":"unknown"
:null;
if(dependent) {
Set<String> kinds =
Optional.ofNullable(power.optJSONObject("name"))
.orElseGet(() -> Optional.ofNullable(power.optJSONObject("effect"))
.orElseGet(() -> power.optJSONObject("description"))
).getJSONObject(dependentKind).keySet();
for(String kind : kinds){
System.out.println("kind "+kind);
powers.add(new MultitypePower(
power.getString("id")+":"+kind,
Optional.ofNullable(power.optString("name")).orElseGet(() -> power.getJSONObject("name").getJSONObject(dependentKind).getString(kind)),
Optional.ofNullable(power.optString("description")).orElseGet(() -> power.getJSONObject("description").getJSONObject(dependentKind).getString(kind)),
power.isNull("short_effect")?null:power.getString("short_effect"),
Optional.ofNullable(power.optString("effect")).orElseGet(() -> power.getJSONObject("effect").getJSONObject(dependentKind).getString(kind)),
Utils.toEnumSet(Power.Target.class,power.getJSONArray("targets").toList().stream().map(k -> getPowerTarget((String)k)).collect(Collectors.toSet())),
Utils.toEnumSet(Power.Target.class,power.getJSONArray("seeds_to").toList().stream().map(k -> getPowerTarget((String)k)).collect(Collectors.toSet())),
getPowerGroup(power.getString("power_group")),
power.getBoolean("negative"),
power.getInt("power_group_level"),
Utils.toEnumSet(Power.Effect.class,power.getJSONArray("effects").toList().stream().map(k -> getPowerEffect((String)k)).collect(Collectors.toSet())),
power.getBoolean("ignores_democritus"),
Utils.toEnumSet(Power.AreaOfEffect.class,power.getJSONArray("area_of_effect").toList().stream().map(k -> getPowerAOE((String)k)).collect(Collectors.toSet())),
getPowerTags(power),
power.getInt("lifetime"),
metadefaults==null?Map.of():metadefaults.toMap(),
power.getString("id")
));
}
}else {
powers.add(new Power(
power.getString("id"),
power.getString("name"),
power.getString("description"),
power.isNull("short_effect")?null:power.getString("short_effect"),
power.getString("effect"),
Utils.toEnumSet(Power.Target.class,power.getJSONArray("targets").toList().stream().map(k -> getPowerTarget((String)k)).collect(Collectors.toSet())),
Utils.toEnumSet(Power.Target.class,power.getJSONArray("seeds_to").toList().stream().map(k -> getPowerTarget((String)k)).collect(Collectors.toSet())),
getPowerGroup(power.getString("power_group")),
power.getBoolean("negative"),
power.getInt("power_group_level"),
Utils.toEnumSet(Power.Effect.class,power.getJSONArray("effects").toList().stream().map(k -> getPowerEffect((String)k)).collect(Collectors.toSet())),
power.getBoolean("ignores_democritus"),
Utils.toEnumSet(Power.AreaOfEffect.class,power.getJSONArray("area_of_effect").toList().stream().map(k -> getPowerAOE((String)k)).collect(Collectors.toSet())),
getPowerTags(power),
power.getInt("lifetime"),
metadefaults==null?Map.of():metadefaults.toMap()
));
}
} else {
if(power.getInt("fury_percentage_cost") != 0) {
powers.add(new FuryPower(
power.getString("id"),
power.getString("name"),
power.getString("description"),
power.isNull("short_effect")?null:power.getString("short_effect"),
Optional.ofNullable(power.optString("effect")).orElseGet(() -> power.optJSONObject("effect").getString("not_cast")),
Utils.toEnumSet(Power.Target.class,power.getJSONArray("targets").toList().stream().map(k -> getPowerTarget((String)k)).collect(Collectors.toSet())),
Utils.toEnumSet(Power.Target.class,power.getJSONArray("seeds_to").toList().stream().map(k -> getPowerTarget((String)k)).collect(Collectors.toSet())),
getPowerGroup(power.getString("power_group")),
power.getBoolean("negative"),
power.getInt("power_group_level"),
Utils.toEnumSet(Power.Effect.class,power.getJSONArray("effects").toList().stream().map(k -> getPowerEffect((String)k)).collect(Collectors.toSet())),
power.getBoolean("ignores_democritus"),
Utils.toEnumSet(Power.AreaOfEffect.class,power.getJSONArray("area_of_effect").toList().stream().map(k -> getPowerAOE((String)k)).collect(Collectors.toSet())),
getPowerTags(power),
power.getInt("lifetime"),
metadefaults==null?Map.of():metadefaults.toMap(),
power.isNull("god_id")?null:gods.stream().filter(g -> g.getId().equals(power.getString("god_id"))).findAny().get(),
power.getInt("favor"),
power.isNull("temple_level_sum_dependency")?0:power.getInt("temple_level_sum_dependency"),
power.getInt("fury_percentage_cost")/100.0
));
} else {
powers.add(new GodPower(
power.getString("id"),
power.getString("name"),
power.getString("description"),
power.isNull("short_effect")?null:power.getString("short_effect"),
Optional.ofNullable(power.optString("effect")).orElseGet(() -> power.optJSONObject("effect").getString("not_cast")),
Utils.toEnumSet(Power.Target.class,power.getJSONArray("targets").toList().stream().map(k -> getPowerTarget((String)k)).collect(Collectors.toSet())),
Utils.toEnumSet(Power.Target.class,power.getJSONArray("seeds_to").toList().stream().map(k -> getPowerTarget((String)k)).collect(Collectors.toSet())),
getPowerGroup(power.getString("power_group")),
power.getBoolean("negative"),
power.getInt("power_group_level"),
Utils.toEnumSet(Power.Effect.class,power.getJSONArray("effects").toList().stream().map(k -> getPowerEffect((String)k)).collect(Collectors.toSet())),
power.getBoolean("ignores_democritus"),
Utils.toEnumSet(Power.AreaOfEffect.class,power.getJSONArray("area_of_effect").toList().stream().map(k -> getPowerAOE((String)k)).collect(Collectors.toSet())),
getPowerTags(power),
power.getInt("lifetime"),
metadefaults==null?Map.of():metadefaults.toMap(),
power.isNull("god_id")?null:gods.stream().filter(g -> g.getId().equals(power.getString("god_id"))).findAny().get(),
power.getInt("favor"),
power.isNull("temple_level_sum_dependency")?0:power.getInt("temple_level_sum_dependency")
));}
}
}
JSONObject researchesJ = json.getJSONObject("researches");
Set<Research> researches = new HashSet<>();
for(String r : researchesJ.keySet()) {
JSONObject research = researchesJ.getJSONObject(r);
researches.add(new Research(
research.getString("id"),
research.getString("name"),
research.getString("description"),
research.isNull("research_dependencies")?Set.of():research.getJSONArray("research_dependencies").toList().stream().map(k -> Utils.getIdentified(researches,(String)k)).collect(Collectors.toSet()),
research.isNull("building_dependencies")?Map.of():research.getJSONObject("building_dependencies").keySet().stream()
.collect(Collectors.toMap(Function.identity(), b -> research.getJSONObject("building_dependencies").getInt(b))),
research.isNull("resources")?null:new Resources(
research.getJSONObject("resources").getInt("wood"),
research.getJSONObject("resources").getInt("stone"),
research.getJSONObject("resources").getInt("iron")),
research.getInt("required_time"),
research.getInt("research_points")
));
}
JSONObject unitsJ = json.getJSONObject("units");
Set<Unit> units = new HashSet<>();
for(String u : unitsJ.keySet()) {
JSONObject unit = unitsJ.getJSONObject(u);
if(unit.getBoolean("is_naval")) {
if(unit.getInt("capacity")>0) {
units.add(new TransportUnit(
unit.getString("id"),
unit.getString("name"),
unit.getString("description"),
unit.getInt("population"),
unit.getInt("speed"),
unit.getString("category").equals("mythological_ground") || unit.getString("category").equals("mythological_naval"),
unit.isNull("god_id")?null:gods.stream().filter(g -> g.getId().equals(unit.getString("god_id"))).findAny().orElse(null),
unit.isNull("resources")?null:new Resources(
unit.getJSONObject("resources").getInt("wood"),
unit.getJSONObject("resources").getInt("stone"),
unit.getJSONObject("resources").getInt("iron")),
unit.getInt("favor"),
unit.getInt("build_time"),
unit.isNull("research_dependencies")?Set.of():unit.getJSONArray("research_dependencies").toList().stream().map(k -> Utils.getIdentified(researches, (String)k)).collect(Collectors.toSet()),
unit.isNull("building_dependencies")?Map.of():unit.getJSONObject("building_dependencies").keySet().stream()
.collect(Collectors.toMap(Function.identity(), b -> unit.getJSONObject("building_dependencies").getInt(b))),
unit.getInt("attack"),
unit.getInt("defense"),
unit.getInt("capacity")
));
} else {
units.add(new NavalUnit(
unit.getString("id"),
unit.getString("name"),
unit.getString("description"),
unit.getInt("population"),
unit.getInt("speed"),
unit.getString("category").equals("mythological_ground") || unit.getString("category").equals("mythological_naval"),
unit.isNull("god_id")?null:gods.stream().filter(g -> g.getId().equals(unit.getString("god_id"))).findAny().orElse(null),
unit.isNull("resources")?null:new Resources(
unit.getJSONObject("resources").getInt("wood"),
unit.getJSONObject("resources").getInt("stone"),
unit.getJSONObject("resources").getInt("iron")),
unit.getInt("favor"),
unit.getInt("build_time"),
unit.isNull("research_dependencies")?Set.of():unit.getJSONArray("research_dependencies").toList().stream().map(k -> Utils.getIdentified(researches,(String)k)).collect(Collectors.toSet()),
unit.isNull("building_dependencies")?Map.of():unit.getJSONObject("building_dependencies").keySet().stream()
.collect(Collectors.toMap(Function.identity(), b -> unit.getJSONObject("building_dependencies").getInt(b))),
unit.getInt("attack"),
unit.getInt("defense")
));
}
} else {
FightType ft = null;
switch(unit.getString("attack_type")) {
case "pierce": ft = FightType.PIERCE;break;
case "hack": ft = FightType.HACK;break;
case "distance": ft = FightType.DISTANCE;break;
}
units.add(new TerrestrialUnit(
unit.getString("id"),
unit.getString("name"),
unit.getString("description"),
unit.getInt("population"),
unit.getInt("speed"),
unit.getString("category").equals("mythological_ground") || unit.getString("category").equals("mythological_naval"),
unit.isNull("god_id")?null:gods.stream().filter(g -> g.getId().equals(unit.getString("god_id"))).findAny().orElse(null),
unit.isNull("resources")?null:new Resources(
unit.getJSONObject("resources").getInt("wood"),
unit.getJSONObject("resources").getInt("stone"),
unit.getJSONObject("resources").getInt("iron")),
unit.getInt("favor"),
unit.getInt("build_time"),
unit.isNull("research_dependencies")?Set.of():unit.getJSONArray("research_dependencies").toList().stream().map(k -> Utils.getIdentified(researches, (String)k)).collect(Collectors.toSet()),
unit.isNull("building_dependencies")?Map.of():unit.getJSONObject("building_dependencies").keySet().stream()
.collect(Collectors.toMap(Function.identity(), b -> unit.getJSONObject("building_dependencies").getInt(b))),
unit.getInt("attack"),
ft,
unit.getInt("def_pierce"),
unit.getInt("def_hack"),
unit.getInt("def_distance"),
(unit.has("booty"))?unit.getInt("booty"):0,
unit.getJSONArray("special_abilities").toList().stream().filter(o -> o.equals("flying")).findAny().isPresent()
));
}
}
JSONObject heroesJ = json.getJSONObject("heroes");
Set<Hero> heroes = new HashSet<>();
for(String h : heroesJ.keySet()) {
JSONObject hero = heroesJ.getJSONObject(h);
FightType ft = null;
switch(hero.getString("attack_type")) {
case "pierce": ft = FightType.PIERCE;break;
case "hack": ft = FightType.HACK;break;
case "distance": ft = FightType.DISTANCE;break;
}
JSONObject descargs = hero.getJSONObject("description_args").getJSONObject("1");
heroes.add(new Hero(
hero.getString("id"),
hero.getString("name"),
hero.getString("description"),
hero.getInt("speed"),
hero.getInt("attack"),
ft,
hero.getInt("def_pierce"),
hero.getInt("def_hack"),
hero.getInt("def_distance"),
hero.getInt("booty"),
hero.getString("category").equals("war")?HeroCategory.WAR:HeroCategory.WISDOM,
hero.getInt("cost"),
hero.getString("short_description"),
descargs.getDouble("value"),
descargs.getDouble("level_mod")
));
}
return new GameConfig(gods, units, heroes, researches, powers);
}
private static EnumSet<Power.Tag> getPowerTags(JSONObject o) {
Set<Power.Tag> out = new HashSet<Power.Tag>();
if(o.getBoolean("extendible"))out.add(Power.Tag.EXTENDIBLE);
if(o.getBoolean("display_amount"))out.add(Power.Tag.DISPLAY_AMOUNT);
if(o.getBoolean("destructive"))out.add(Power.Tag.DESTRUCTIVE);
if(o.getBoolean("is_capped"))out.add(Power.Tag.CAPPED);
if(o.getBoolean("is_fake_power"))out.add(Power.Tag.FAKE_POWER);
if(o.getBoolean("is_onetime_power"))out.add(Power.Tag.ONETIME_POWER);
if(o.getBoolean("is_ritual"))out.add(Power.Tag.RITUAL);
if(o.getBoolean("is_upgradable"))out.add(Power.Tag.UPGRADABLE);
if(o.getBoolean("is_valid_for_happenings"))out.add(Power.Tag.VALID_FOR_HAPPENINGS);
if(o.getBoolean("transfer_to_casual_world"))out.add(Power.Tag.TRANSFER_TO_CASUAL_WORLD);
if(o.getBoolean("wasteable"))out.add(Power.Tag.WASTEABLE);
if(o.getBoolean("needs_level"))out.add(Power.Tag.NEEDS_LEVEL);
if(o.getBoolean("passive"))out.add(Power.Tag.PASSIVE);
if(o.getBoolean("recreate_on_restart"))out.add(Power.Tag.RECREATE_ON_RESTART);
if(o.getBoolean("removed_on_target_loss"))out.add(Power.Tag.REMOVED_ON_TARGET_LOSS);
if(o.getBoolean("requires_god"))out.add(Power.Tag.REQUIRES_GOD);
if(o.getBoolean("no_lifetime"))out.add(Power.Tag.NO_LIFETIME);
return Utils.toEnumSet(Power.Tag.class,out);
}
private static Power.AreaOfEffect getPowerAOE(String s){
switch(s) {
case "area_of_effect_build_time": return Power.AreaOfEffect.BUILDTIME;
case "area_of_effect_commands": return Power.AreaOfEffect.COMMANDS;
case "area_of_effect_favor": return Power.AreaOfEffect.FAVOR;
case "area_of_effect_militia": return Power.AreaOfEffect.MILITIA;
case "area_of_effect_resources": return Power.AreaOfEffect.RESOURCES;
}
throw new IllegalArgumentException("I don't know Power AreaOfEffect "+s);
}
private static Power.Effect getPowerEffect(String s){
switch(s) {
case "effects_ground": return Power.Effect.GROUND;
case "effects_naval": return Power.Effect.NAVAL;
case "effects_wall": return Power.Effect.WALL;
}
throw new IllegalArgumentException("I don't know Power Effect "+s);
}
private static Power.Group getPowerGroup(String s){
switch(s) {
case "attack_boost_group": return Power.Group.ATTACK_BOOST;
case "attack_ship_attack_boost_group": return Power.Group.ATTACK_SHIP_ATTACK_BOOST;
case "battle_point_boost_group": return Power.Group.BATTLE_POINT_BOOST;
case "building_boost_group": return Power.Group.BUILDING_BOOST;
case "defense_boost_group": return Power.Group.DEFENSE_BOOST;
case "favor_boost_group": return Power.Group.FAVOR_BOOST;
case "resource_boost_group": return Power.Group.RESOURCE_BOOST;
case "unit_boost_group": return Power.Group.UNIT_BOOST;
case "": return null;
}
throw new IllegalArgumentException("I don't know Power Group "+s);
}
private static Power.Target getPowerTarget(String s){
switch(s) {
case "target_alliance": return Power.Target.ALLIANCE;
case "target_command": return Power.Target.COMMAND;
case "target_player": return Power.Target.PLAYER;
case "target_support_command": return Power.Target.SUPPORT_COMMAND;
case "target_town": return Power.Target.TOWN;
}
throw new IllegalArgumentException("I don't know Power Target "+s);
}
}

View File

@ -31,7 +31,7 @@ public class SimulatorController {
model.addAttribute("heroes", gc.getHeroes());
model.addAttribute("defUnits", Fight.relevantDefUnits(gc));
model.addAttribute("defCounsellors",Fight.relevantDefCounsellors(gc));
model.addAttribute("defResearches",Fight.relevantDefResearch(gc));
model.addAttribute("defResearches",Fight.relevantDefResearches(gc));
model.addAttribute("defPowers",Fight.relevantDefPowers(gc));
model.addAttribute("ctx",new DefSimulatorParams());
return "simulator";
@ -82,6 +82,7 @@ public static class DefSimulatorParams {
wallLevel,
hasTower,
powers,
1, 1, 1,
researches,
counsellors,
nightBonus

View File

@ -0,0 +1,26 @@
package com.bernard.greposimu.engine.game;
public class Effects {
/*
* PC boost per level
*/
public static final double olympicSensesGrepolympiaSummerBoost(int level) {
return 0.1*level;
}
/*
* Defense boost per level
*/
public static final double olympicTorchGrepolympiaSummerBoost(int level) {
return 0.05*level;
}
/*
* Defense boost per level
*/
public static final double soteriasShrineBoost(int level) {
return 0.007*level;
}
}

View File

@ -36,29 +36,29 @@ public class Fight {
//TODO powers
// Researches
if(def.getCounsellors().contains("divine_selection"))
if(def.hasDivineSelection())
for(Unit u : gc.getUnits())
if(u.isMythological())
unitsBonuses.put(u, FightStats.add(unitsBonuses.getOrDefault(u, FightStats.zero()), FightStats.cst(0.1)));
if(def.getCounsellors().contains("phalanx"))
if(def.hasPhalanx())
for(Unit u : gc.getUnits())
if(u.isGround())
unitsBonuses.put(u, FightStats.add(unitsBonuses.getOrDefault(u, FightStats.zero()), FightStats.cst(0.1)));
if(def.getCounsellors().contains("ram"))
if(def.hasRam())
for(Unit u : gc.getUnits())
if(u.isNaval())
unitsBonuses.put(u, FightStats.add(unitsBonuses.getOrDefault(u, FightStats.zero()), FightStats.cst(0.1)));
// Counsellors
if(def.getCounsellors().contains("priest"))
if(def.hasPriest())
for(Unit u : gc.getUnits())
if(u.isMythological())
unitsBonuses.put(u, FightStats.add(unitsBonuses.getOrDefault(u, FightStats.zero()), FightStats.cst(0.2)));
if(def.getCounsellors().contains("commander"))
if(def.hasCommander())
for(Unit u : gc.getUnits())
if(u.isGround())
unitsBonuses.put(u, FightStats.add(unitsBonuses.getOrDefault(u, FightStats.zero()), FightStats.cst(0.2)));
if(def.getCounsellors().contains("captain"))
if(def.hasCaptain())
for(Unit u : gc.getUnits())
if(u.isNaval())
unitsBonuses.put(u, FightStats.add(unitsBonuses.getOrDefault(u, FightStats.zero()), FightStats.cst(0.2)));
@ -71,13 +71,12 @@ public class Fight {
FightStats total = cityBaseStats.clone();
for(Unit u : gc.getUnits()) {
// total = total + ucount * ((1+bonus+bonus) * ustats)
if(def.getUnits().containsKey(u) && def.getUnits().get(u) != null)
total = FightStats.add(total,
FightStats.prod(def.getUnits().get(u),
FightStats.mul(
FightStats.add(FightStats.one(),everyoneStatsBonus,unitsBonuses.getOrDefault(u, FightStats.zero()))
, makeDefStats(u))
));
total = FightStats.add(total,
FightStats.prod(def.unitCount(u),
FightStats.mul(
FightStats.add(FightStats.one(),everyoneStatsBonus,unitsBonuses.getOrDefault(u, FightStats.zero()))
, makeDefStats(u))
));
}
return total;
@ -94,16 +93,15 @@ public class Fight {
throw new UnsupportedOperationException("I don't know how to manage units of type "+u.getClass().getName());
}
public static List<Object> relevantDefPowers(GameConfig gd) {
return List.of();
/*List.of("acumen", "divine_senses", "myrmidion_attack", "trojan_defense", "defense_boost",
public static List<String> relevantDefPowers(GameConfig gd) {
return List.of("acumen", "divine_senses", "myrmidion_attack", "trojan_defense", "defense_boost",
"defense_penalty", "longterm_defense_boost", "assassins_acumen", "rare_defense_boost",
"epic_defense_boost", "olympic_torch.grepolympia_summer", "olympic_senses.grepolympia_summer", "missions_power_4.missions_dionysia",
"divine_battle_strategy_rare", "divine_battle_strategy_epic", "naval_battle_strategy_rare",
"naval_battle_strategy_epic", "land_battle_strategy_rare", "land_battle_strategy_epic",
"soterias_shrine.not_cast").stream().map(gd.powers::get).map(p -> (Power)p).toList();*/
"soterias_shrine.not_cast");
}
public static List<Research> relevantDefResearch(GameConfig gd) {
public static List<Research> relevantDefResearches(GameConfig gd) {
return List.of("divine_selection","phalanx","ram")
.stream().map(gd::getResearch).toList();
}

View File

@ -1,46 +1,93 @@
package com.bernard.greposimu.model;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import com.bernard.greposimu.model.game.GameConfig;
import com.bernard.greposimu.model.game.units.Hero;
import com.bernard.greposimu.model.game.units.Unit;
public class DefContext {
// unitID -> number of units
// UNITS
Map<Unit, Integer> units;
// HEROS
Hero hero;
int heroLevel;
// BUILDINGS
int wallLevel;
boolean hasTower;
Set<String> powers;
Set<String> researches;
// RESEARCHES
boolean divineSelection, phalanx, ram;
Set<String> counsellors;
// COUNSELLORS
boolean commander;
boolean priest;
boolean captain;
// EFFECTS
boolean acumen, divineSenses, myrmidionAttack, trojanDefense,
defenseBoost, defensePenalty, longtermDefenseBoost, assassinsAcumen,
rareDefenseBoost, epicDefenseBoost, missionsPower4,
divineBattleStrategyRare, divineBattleStrategyEpic, navalBattleStrategyRare,
navalBattleStrategyEpic, landBattleStrategyRare, landBattleStrategyEpic;
int olympicSensesGrepolympiaSummerLevel = 0;
int olympicTorchGrepolympiaSummerLevel = 0;
int soteriasShrineLevel = 0;
// BONUSES
boolean nightBonus;
public DefContext(Map<Unit, Integer> units, Hero hero, int heroLevel, int wallLevel, boolean hasTower,
Set<String> powers, Set<String> researches, Set<String> counsellors, boolean nightBonus) {
Set<String> powers, int soteriasShrinePowerLevel, int olympicTorchGrepolympiaSummerLevel, int olympicSensesGrepolympiaSummerLevel, Set<String> researches, Set<String> counsellors, boolean nightBonus) {
this.units = units;
this.hero = hero;
this.heroLevel = heroLevel;
this.wallLevel = wallLevel;
this.hasTower = hasTower;
this.powers = powers;
this.researches = researches;
this.counsellors = counsellors;
if(powers.contains("acumen"))this.acumen = true;
if(powers.contains("divine_senses"))this.divineSenses = true;
if(powers.contains("myrmdion_attack"))this.myrmidionAttack = true;
if(powers.contains("trojan_defense"))this.trojanDefense = true;
if(powers.contains("defense_boost"))this.defenseBoost = true;
if(powers.contains("defense_penalty"))this.defensePenalty = true;
if(powers.contains("longterm_defense_boost"))this.longtermDefenseBoost = true;
if(powers.contains("assassins_acumen"))this.assassinsAcumen = true;
if(powers.contains("rare_defense_boost"))this.rareDefenseBoost = true;
if(powers.contains("epic_defense_boost"))this.defenseBoost = true;
if(powers.contains("olympic_torch"))this.olympicTorchGrepolympiaSummerLevel = olympicTorchGrepolympiaSummerLevel;
if(powers.contains("olympic_senses"))this.olympicSensesGrepolympiaSummerLevel = olympicSensesGrepolympiaSummerLevel;
if(powers.contains("missions_power_4"))this.missionsPower4 = true;
if(powers.contains("divine_battle_strategy_rare"))this.divineBattleStrategyRare = true;
if(powers.contains("divine_battle_strategy_epic"))this.divineBattleStrategyEpic = true;
if(powers.contains("naval_battle_strategy_rare"))this.navalBattleStrategyRare = true;
if(powers.contains("naval_battle_strategy_epic"))this.navalBattleStrategyEpic = true;
if(powers.contains("land_battle_strategy_rare"))this.landBattleStrategyRare = true;
if(powers.contains("land_battle_strategy_epic"))this.landBattleStrategyEpic = true;
if(powers.contains("soterias_shrine"))this.soteriasShrineLevel = soteriasShrinePowerLevel;
if(researches.contains("divine_selection"))this.divineSelection = true;
if(researches.contains("phalanx"))this.phalanx = true;
if(researches.contains("ram"))this.ram = true;
if(counsellors.contains("commander"))this.commander = true;
if(counsellors.contains("priest"))this.priest = true;
if(counsellors.contains("captain"))this.captain = true;
this.nightBonus = nightBonus;
}
public Map<Unit, Integer> getUnits() {
return units;
}
public int unitCount(Unit u) {
return Optional.ofNullable(units.getOrDefault(u,0)).orElse(0);
}
public Hero getHero() {
return hero;
}
@ -53,26 +100,112 @@ public class DefContext {
public boolean hasTower() {
return hasTower;
}
public Set<String> getPowers() {
return powers;
}
public Set<String> getResearches() {
return researches;
}
public Set<String> getCounsellors() {
return counsellors;
}
public boolean isNightBonus() {
return nightBonus;
}
public boolean hasDivineSelection() {
return divineSelection;
}
public boolean hasPhalanx() {
return phalanx;
}
public boolean hasRam() {
return ram;
}
@Override
public String toString() {
return "DefContext [units=" + units + ", heros=" + hero + ", herosLevel=" + heroLevel + ", wallLevel="
+ wallLevel + ", hasTower=" + hasTower + ", powers=" + powers + ", researches=" + researches
+ ", counsellors=" + counsellors + ", nightBonus=" + nightBonus + "]";
public boolean hasCommander() {
return commander;
}
public boolean hasPriest() {
return priest;
}
public boolean hasCaptain() {
return captain;
}
public boolean hasAcumen() {
return acumen;
}
public boolean hasDivineSenses() {
return divineSenses;
}
public boolean hasMyrmidionAttack() {
return myrmidionAttack;
}
public boolean hasTrojanDefense() {
return trojanDefense;
}
public boolean hasDefenseBoost() {
return defenseBoost;
}
public boolean hasDefensePenalty() {
return defensePenalty;
}
public boolean hasLongtermDefenseBoost() {
return longtermDefenseBoost;
}
public boolean hasAssassinsAcumen() {
return assassinsAcumen;
}
public boolean hasRareDefenseBoost() {
return rareDefenseBoost;
}
public boolean hasEpicDefenseBoost() {
return epicDefenseBoost;
}
public boolean hasMhassionsPower4() {
return missionsPower4;
}
public boolean hasDivineBattleStrategyRare() {
return divineBattleStrategyRare;
}
public boolean hasDivineBattleStrategyEpic() {
return divineBattleStrategyEpic;
}
public boolean hasNavalBattleStrategyRare() {
return navalBattleStrategyRare;
}
public boolean hasNavalBattleStrategyEpic() {
return navalBattleStrategyEpic;
}
public boolean hasLandBattleStrategyRare() {
return landBattleStrategyRare;
}
public boolean hasLandBattleStrategyEpic() {
return landBattleStrategyEpic;
}
public int getOlympicSensesGrepolympiaSummerLevel() {
return olympicSensesGrepolympiaSummerLevel;
}
public int getOlympicTorchGrepolympiaSummerLevel() {
return olympicTorchGrepolympiaSummerLevel;
}
public int getSoteriasShrineLevel() {
return soteriasShrineLevel;
}

View File

@ -1,22 +1,12 @@
package com.bernard.greposimu.model.game;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.json.JSONObject;
import com.bernard.greposimu.Utils;
import com.bernard.greposimu.model.game.powers.Power;
import com.bernard.greposimu.model.game.researches.Research;
import com.bernard.greposimu.model.game.units.FightType;
import com.bernard.greposimu.model.game.units.Hero;
import com.bernard.greposimu.model.game.units.Hero.HeroCategory;
import com.bernard.greposimu.model.game.units.NavalUnit;
import com.bernard.greposimu.model.game.units.TerrestrialUnit;
import com.bernard.greposimu.model.game.units.TransportUnit;
import com.bernard.greposimu.model.game.units.Unit;
public class GameConfig {
@ -30,6 +20,18 @@ public class GameConfig {
Set<Research> researches;
Set<Power> powers;
public GameConfig(Set<God> gods, Set<Unit> units, Set<Hero> heroes, Set<Research> researches, Set<Power> powers) {
this.gods = gods;
this.units = units;
this.heroes = heroes;
this.researches = researches;
this.powers = powers;
}
public Set<Unit> getUnits() {
return Collections.unmodifiableSet(this.units);
}
@ -52,149 +54,4 @@ public class GameConfig {
return Utils.getIdentified(this.researches, id);
}
public GameConfig(JSONObject json) {
JSONObject godsJ = json.getJSONObject("gods");
this.gods = new HashSet<>();
for(String g : godsJ.keySet()) {
JSONObject godJ = godsJ.getJSONObject(g);
gods.add(new God(godJ.getString("id"), godJ.getString("name")));
}
JSONObject researchesJ = json.getJSONObject("researches");
this.researches = new HashSet<>();
for(String r : researchesJ.keySet()) {
JSONObject research = researchesJ.getJSONObject(r);
this.researches.add(new Research(
research.getString("id"),
research.getString("name"),
research.getString("description"),
research.isNull("research_dependencies")?Set.of():research.getJSONArray("research_dependencies").toList().stream().map(k -> this.getResearch((String)k)).collect(Collectors.toSet()),
research.isNull("building_dependencies")?Map.of():research.getJSONObject("building_dependencies").keySet().stream()
.collect(Collectors.toMap(Function.identity(), b -> research.getJSONObject("building_dependencies").getInt(b))),
research.isNull("resources")?null:new Resources(
research.getJSONObject("resources").getInt("wood"),
research.getJSONObject("resources").getInt("stone"),
research.getJSONObject("resources").getInt("iron")),
research.getInt("required_time"),
research.getInt("research_points")
));
}
JSONObject unitsJ = json.getJSONObject("units");
this.units = new HashSet<>();
for(String u : unitsJ.keySet()) {
JSONObject unit = unitsJ.getJSONObject(u);
if(unit.getBoolean("is_naval")) {
if(unit.getInt("capacity")>0) {
units.add(new TransportUnit(
unit.getString("id"),
unit.getString("name"),
unit.getString("description"),
unit.getInt("population"),
unit.getInt("speed"),
unit.getString("category").equals("mythological_ground") || unit.getString("category").equals("mythological_naval"),
unit.isNull("god_id")?null:gods.stream().filter(g -> g.getId().equals(unit.getString("god_id"))).findAny().orElse(null),
unit.isNull("resources")?null:new Resources(
unit.getJSONObject("resources").getInt("wood"),
unit.getJSONObject("resources").getInt("stone"),
unit.getJSONObject("resources").getInt("iron")),
unit.getInt("favor"),
unit.getInt("build_time"),
unit.isNull("research_dependencies")?Set.of():unit.getJSONArray("research_dependencies").toList().stream().map(k -> this.getResearch((String)k)).collect(Collectors.toSet()),
unit.isNull("building_dependencies")?Map.of():unit.getJSONObject("building_dependencies").keySet().stream()
.collect(Collectors.toMap(Function.identity(), b -> unit.getJSONObject("building_dependencies").getInt(b))),
unit.getInt("attack"),
unit.getInt("defense"),
unit.getInt("capacity")
));
} else {
units.add(new NavalUnit(
unit.getString("id"),
unit.getString("name"),
unit.getString("description"),
unit.getInt("population"),
unit.getInt("speed"),
unit.getString("category").equals("mythological_ground") || unit.getString("category").equals("mythological_naval"),
unit.isNull("god_id")?null:gods.stream().filter(g -> g.getId().equals(unit.getString("god_id"))).findAny().orElse(null),
unit.isNull("resources")?null:new Resources(
unit.getJSONObject("resources").getInt("wood"),
unit.getJSONObject("resources").getInt("stone"),
unit.getJSONObject("resources").getInt("iron")),
unit.getInt("favor"),
unit.getInt("build_time"),
unit.isNull("research_dependencies")?Set.of():unit.getJSONArray("research_dependencies").toList().stream().map(k -> this.getResearch((String)k)).collect(Collectors.toSet()),
unit.isNull("building_dependencies")?Map.of():unit.getJSONObject("building_dependencies").keySet().stream()
.collect(Collectors.toMap(Function.identity(), b -> unit.getJSONObject("building_dependencies").getInt(b))),
unit.getInt("attack"),
unit.getInt("defense")
));
}
} else {
FightType ft = null;
switch(unit.getString("attack_type")) {
case "pierce": ft = FightType.PIERCE;break;
case "hack": ft = FightType.HACK;break;
case "distance": ft = FightType.DISTANCE;break;
}
units.add(new TerrestrialUnit(
unit.getString("id"),
unit.getString("name"),
unit.getString("description"),
unit.getInt("population"),
unit.getInt("speed"),
unit.getString("category").equals("mythological_ground") || unit.getString("category").equals("mythological_naval"),
unit.isNull("god_id")?null:gods.stream().filter(g -> g.getId().equals(unit.getString("god_id"))).findAny().orElse(null),
unit.isNull("resources")?null:new Resources(
unit.getJSONObject("resources").getInt("wood"),
unit.getJSONObject("resources").getInt("stone"),
unit.getJSONObject("resources").getInt("iron")),
unit.getInt("favor"),
unit.getInt("build_time"),
unit.isNull("research_dependencies")?Set.of():unit.getJSONArray("research_dependencies").toList().stream().map(k -> this.getResearch((String)k)).collect(Collectors.toSet()),
unit.isNull("building_dependencies")?Map.of():unit.getJSONObject("building_dependencies").keySet().stream()
.collect(Collectors.toMap(Function.identity(), b -> unit.getJSONObject("building_dependencies").getInt(b))),
unit.getInt("attack"),
ft,
unit.getInt("def_pierce"),
unit.getInt("def_hack"),
unit.getInt("def_distance"),
(unit.has("booty"))?unit.getInt("booty"):0,
unit.getJSONArray("special_abilities").toList().stream().filter(o -> o.equals("flying")).findAny().isPresent()
));
}
}
JSONObject heroesJ = json.getJSONObject("heroes");
this.heroes = new HashSet<>();
for(String h : heroesJ.keySet()) {
JSONObject hero = heroesJ.getJSONObject(h);
FightType ft = null;
switch(hero.getString("attack_type")) {
case "pierce": ft = FightType.PIERCE;break;
case "hack": ft = FightType.HACK;break;
case "distance": ft = FightType.DISTANCE;break;
}
JSONObject descargs = hero.getJSONObject("description_args").getJSONObject("1");
this.heroes.add(new Hero(
hero.getString("id"),
hero.getString("name"),
hero.getString("description"),
hero.getInt("speed"),
hero.getInt("attack"),
ft,
hero.getInt("def_pierce"),
hero.getInt("def_hack"),
hero.getInt("def_distance"),
hero.getInt("booty"),
hero.getString("category").equals("war")?HeroCategory.WAR:HeroCategory.WISDOM,
hero.getInt("cost"),
hero.getString("short_description"),
descargs.getDouble("value"),
descargs.getDouble("level_mod")
));
}
}
}

View File

@ -0,0 +1,25 @@
package com.bernard.greposimu.model.game.powers;
import java.util.EnumSet;
import java.util.Map;
import com.bernard.greposimu.model.game.God;
public class FuryPower extends GodPower {
double furyProportionCost;
public FuryPower(String id, String name, String description, String shortEffect, String effect,
EnumSet<Target> targets, EnumSet<Target> seedsTo, Group powerGroup, boolean negative, int powerGroupLevel,
EnumSet<Effect> effects, boolean ignores_democritus, EnumSet<AreaOfEffect> areaOfEffect, EnumSet<Tag> tags,
int lifetime, Map<String, Object> metaDefaults, God god, int furyCost, int templeLevelSumDependency,
double furyProportionCost) {
super(id, name, description, shortEffect, effect, targets, seedsTo, powerGroup, negative, powerGroupLevel,
effects, ignores_democritus, areaOfEffect, tags, lifetime, metaDefaults, god, furyCost,
templeLevelSumDependency);
this.furyProportionCost = furyProportionCost;
}
public double getFuryProportionCost() {
return furyProportionCost;
}
}

View File

@ -0,0 +1,42 @@
package com.bernard.greposimu.model.game.powers;
import java.util.EnumSet;
import java.util.Map;
import com.bernard.greposimu.model.game.God;
public class GodPower extends Power {
God god;
int furyCost;
int templeLevelSumDependency;
public GodPower(String id, String name, String description, String shortEffect, String effect,
EnumSet<Target> targets, EnumSet<Target> seedsTo, Group powerGroup, boolean negative, int powerGroupLevel,
EnumSet<Effect> effects, boolean ignores_democritus, EnumSet<AreaOfEffect> areaOfEffect, EnumSet<Tag> tags,
int lifetime, Map<String, Object> metaDefaults, God god, int furyCost, int templeLevelSumDependency) {
super(id, name, description, shortEffect, effect, targets, seedsTo, powerGroup, negative, powerGroupLevel,
effects, ignores_democritus, areaOfEffect, tags, lifetime, metaDefaults);
this.god = god;
this.furyCost = furyCost;
this.templeLevelSumDependency = templeLevelSumDependency;
}
public God getGod() {
return god;
}
public int getFuryCost() {
return furyCost;
}
public int getTempleLevelSumDependency() {
return templeLevelSumDependency;
}
}

View File

@ -0,0 +1,21 @@
package com.bernard.greposimu.model.game.powers;
import java.util.EnumSet;
import java.util.Map;
public class MultitypePower extends Power{
String commonId;
public MultitypePower(String id, String name, String description, String shortEffect, String effect,
EnumSet<Target> targets, EnumSet<Target> seedsTo, Group powerGroup, boolean negative, int powerGroupLevel,
EnumSet<Effect> effects, boolean ignores_democritus, EnumSet<AreaOfEffect> areaOfEffect, EnumSet<Tag> tags,
int lifetime, Map<String, Object> metaDefaults, String commonId) {
super(id, name, description, shortEffect, effect, targets, seedsTo, powerGroup, negative, powerGroupLevel,
effects, ignores_democritus, areaOfEffect, tags, lifetime, metaDefaults);
this.commonId = commonId;
}
public String getCommonId() {
return commonId;
}
}

View File

@ -0,0 +1,158 @@
package com.bernard.greposimu.model.game.powers;
import java.util.EnumSet;
import java.util.Map;
import com.bernard.greposimu.model.game.Identified;
public class Power implements Identified {
String id;
String name;
String description;
String shortEffect;
String effect;
/**
* The target it applies to
*/
EnumSet<Target> targets;
/**
* The targets it is seeded to. For example, attack boost is targeted to towns, and is seeded to commands.
*/
EnumSet<Target> seedsTo;
// EFFECTS
Group powerGroup;
boolean negative;
int powerGroupLevel;
EnumSet<Effect> effects;
boolean ignores_democritus;
EnumSet<AreaOfEffect> areaOfEffect;
// images -> IGNORE
EnumSet<Tag> tags;
int lifetime;
Map<String,Object> metaDefaults;
public static enum Tag {
EXTENDIBLE,
DISPLAY_AMOUNT,
DESTRUCTIVE,
CAPPED,
FAKE_POWER,
ONETIME_POWER,
RITUAL,
UPGRADABLE,
VALID_FOR_HAPPENINGS,
TRANSFER_TO_CASUAL_WORLD,
WASTEABLE,
NEEDS_LEVEL,
PASSIVE,
RECREATE_ON_RESTART,
REMOVED_ON_TARGET_LOSS,
REQUIRES_GOD,
NO_LIFETIME;
}
public static enum AreaOfEffect {
BUILDTIME,COMMANDS,FAVOR,MILITIA,RESOURCES;
}
public static enum Effect {
GROUND,NAVAL,WALL;
}
public static enum Group {
ATTACK_BOOST,ATTACK_SHIP_ATTACK_BOOST,BATTLE_POINT_BOOST,BUILDING_BOOST,DEFENSE_BOOST,FAVOR_BOOST,RESOURCE_BOOST,UNIT_BOOST;
}
public static enum Target {
ALLIANCE,COMMAND,PLAYER,SUPPORT_COMMAND,TOWN;
}
public Power(String id, String name, String description, String shortEffect, String effect, EnumSet<Target> targets,
EnumSet<Target> seedsTo, Group powerGroup, boolean negative, int powerGroupLevel, EnumSet<Effect> effects,
boolean ignores_democritus, EnumSet<AreaOfEffect> areaOfEffect, EnumSet<Tag> tags, int lifetime,
Map<String, Object> metaDefaults) {
this.id = id;
this.name = name;
this.description = description;
this.shortEffect = shortEffect;
this.effect = effect;
this.targets = targets;
this.seedsTo = seedsTo;
this.powerGroup = powerGroup;
this.negative = negative;
this.powerGroupLevel = powerGroupLevel;
this.effects = effects;
this.ignores_democritus = ignores_democritus;
this.areaOfEffect = areaOfEffect;
this.tags = tags;
this.lifetime = lifetime;
this.metaDefaults = metaDefaults;
}
@Override
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public String getShortEffect() {
return shortEffect;
}
public String getEffect() {
return effect;
}
public EnumSet<Target> getTargets() {
return targets;
}
public EnumSet<Target> getSeedsTo() {
return seedsTo;
}
public Group getPowerGroup() {
return powerGroup;
}
public boolean isNegative() {
return negative;
}
public int getPowerGroupLevel() {
return powerGroupLevel;
}
public EnumSet<Effect> getEffects() {
return effects;
}
public boolean isIgnores_democritus() {
return ignores_democritus;
}
public EnumSet<AreaOfEffect> getAreaOfEffect() {
return areaOfEffect;
}
public EnumSet<Tag> getTags() {
return tags;
}
public int getLifetime() {
return lifetime;
}
public Map<String, Object> getMetaDefaults() {
return metaDefaults;
}
}

View File

@ -12,10 +12,10 @@ public class Research implements Identified{
String name;
String description;
Set<Research> researchDependencies;
Map<String,Integer> building_dependencies;
Map<String,Integer> buildingDependencies;
Resources resources;
int required_time;
int research_points;
int requiredTime;
int researchPoints;
public Research(String id, String name, String description, Set<Research> researchDependencies,
Map<String, Integer> building_dependencies, Resources resources, int required_time, int research_points) {
@ -23,10 +23,10 @@ public class Research implements Identified{
this.name = name;
this.description = description;
this.researchDependencies = researchDependencies;
this.building_dependencies = building_dependencies;
this.buildingDependencies = building_dependencies;
this.resources = resources;
this.required_time = required_time;
this.research_points = research_points;
this.requiredTime = required_time;
this.researchPoints = research_points;
}
@Override
@ -46,20 +46,20 @@ public class Research implements Identified{
return researchDependencies;
}
public Map<String, Integer> getBuilding_dependencies() {
return building_dependencies;
public Map<String, Integer> getBuildingDependencies() {
return buildingDependencies;
}
public Resources getResources() {
return resources;
}
public int getRequired_time() {
return required_time;
public int getRequiredTime() {
return requiredTime;
}
public int getResearch_points() {
return research_points;
public int getResearchpoints() {
return researchPoints;
}

View File

@ -147,8 +147,8 @@ span.fixed50px {
<table cellspacing="0" cellpadding="0">
<tr>
<td th:each="power : ${defPowers}" class="squareContainer">
<img class="squareImage" th:for="'power-'+${power.id}" th:src="@{/images/powers/{pname}.png(pname=${power.id})}"/>
<input type="checkbox" th:id="'power-'+${power.id}" th:field="*{powersAsMap[__${power.id}__]}" th:value="true"/>
<img class="squareImage" th:for="'power-'+${power}" th:src="@{/images/powers/{pname}.png(pname=${power})}"/>
<input type="checkbox" th:id="'power-'+${power}" th:field="*{powersAsMap[__${power}__]}" th:value="true"/>
</td>
</tr>
</table>