Added offencive frontend
This commit is contained in:
parent
8454e3a711
commit
6e2f916927
@ -2,13 +2,11 @@ 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.Random;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.bernard.greposimu.model.game.Identified;
|
||||
|
||||
@ -82,4 +80,9 @@ public class Utils {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public static <E> E randFromSet(Random r, Set<E> set) {
|
||||
E el = set.stream().sorted().skip(r.nextInt(set.size())).findFirst().get();
|
||||
return el;
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +40,6 @@ public class JSONReader {
|
||||
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()) {
|
||||
@ -61,7 +60,6 @@ public class JSONReader {
|
||||
.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)),
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
package com.bernard.greposimu.controller;
|
||||
|
||||
public class Randomizer {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -4,6 +4,7 @@ import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
@ -11,13 +12,16 @@ import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import com.bernard.greposimu.GrepoSimuApplication;
|
||||
import com.bernard.greposimu.Utils;
|
||||
import com.bernard.greposimu.engine.game.Fight;
|
||||
import com.bernard.greposimu.model.DefContext;
|
||||
import com.bernard.greposimu.model.FightStats;
|
||||
import com.bernard.greposimu.model.OffContext;
|
||||
import com.bernard.greposimu.model.game.GameConfig;
|
||||
import com.bernard.greposimu.model.game.God;
|
||||
import com.bernard.greposimu.model.game.units.Unit;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
@ -26,91 +30,249 @@ import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
public class SimulatorController {
|
||||
|
||||
@GetMapping("/simulator")
|
||||
public String simulator(Model model) throws IOException {
|
||||
public String simulator(Model model, @RequestParam boolean random) throws IOException {
|
||||
GameConfig gc = GrepoSimuApplication.GREPOLIS_GC;
|
||||
model.addAttribute("heroes", gc.getHeroes());
|
||||
model.addAttribute("defUnits", Fight.relevantDefUnits(gc));
|
||||
model.addAttribute("defCounsellors",Fight.relevantDefCounsellors(gc));
|
||||
model.addAttribute("defResearches",Fight.relevantDefResearches(gc));
|
||||
model.addAttribute("defPowers",Fight.relevantDefPowers(gc));
|
||||
model.addAttribute("ctx",new DefSimulatorParams());
|
||||
model.addAttribute("defCounsellors",DefContext.COUNSELLORS);
|
||||
model.addAttribute("defResearches",DefContext.RESEARCHES);
|
||||
model.addAttribute("defPowers",DefContext.POWERS);
|
||||
model.addAttribute("offUnits", Fight.relevantOffUnits(gc));
|
||||
model.addAttribute("offCounsellors",OffContext.COUNSELLORS);
|
||||
model.addAttribute("offResearches",OffContext.RESEARCHES);
|
||||
model.addAttribute("offPowers",OffContext.POWERS);
|
||||
SimulatorParams params = new SimulatorParams();
|
||||
if(random)
|
||||
params.randomize(new Random(), gc);
|
||||
model.addAttribute("ctx",params);
|
||||
return "simulator";
|
||||
}
|
||||
|
||||
@PostMapping("/simulate")
|
||||
@GetMapping("/simulate")
|
||||
public String simulate(@ModelAttribute DefSimulatorParams defParams, Model model) throws IOException {
|
||||
if(defParams == null)
|
||||
defParams = new DefSimulatorParams();
|
||||
public String simulate(@ModelAttribute SimulatorParams params, Model model) throws IOException {
|
||||
if(params == null)
|
||||
params = new SimulatorParams();
|
||||
GameConfig gc = GrepoSimuApplication.GREPOLIS_GC;
|
||||
DefContext defCtx = defParams.asDefContext(gc);
|
||||
|
||||
FightStats cityStats = Fight.computeDefStats(gc,defCtx);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
DefContext defCtx = params.asDefContext(gc);
|
||||
OffContext offCtx = params.asOffContext(gc);
|
||||
FightStats defStats = Fight.computeDefStats(gc,defCtx);
|
||||
FightStats offStats = Fight.computeOffStats(gc,offCtx);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
|
||||
model.addAttribute("content",cityStats.toString()+"\n"+mapper.writerWithDefaultPrettyPrinter().writeValueAsString(defCtx));
|
||||
model.addAttribute("content",
|
||||
defStats.toString()+"\n"+
|
||||
offStats.toString()+"\n"+
|
||||
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(defCtx)+"\n"+
|
||||
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(offCtx)
|
||||
);
|
||||
return "debug";
|
||||
}
|
||||
|
||||
public static class DefSimulatorParams {
|
||||
public static class SimulatorParams {
|
||||
|
||||
// unitID -> number of units
|
||||
public Map<String, Integer> units = new HashMap<>();
|
||||
|
||||
public String hero = "";
|
||||
public int heroLevel = 0;
|
||||
public Map<String, Integer> defUnits = new HashMap<>();
|
||||
public Map<String, Integer> offUnits = new HashMap<>();
|
||||
|
||||
public String defHero = "";
|
||||
public int defHeroLevel = 0;
|
||||
public String offHero = "";
|
||||
public int offHeroLevel = 0;
|
||||
|
||||
public int wallLevel = 0;
|
||||
public boolean hasTower = false;
|
||||
|
||||
public Set<String> powers = new HashSet<>();
|
||||
public Set<String> researches = new HashSet<>();
|
||||
|
||||
public Set<String> counsellors = new HashSet<>();
|
||||
public Set<String> defPowers = new HashSet<>();
|
||||
public Set<String> offPowers = new HashSet<>();
|
||||
public Set<String> defResearches = new HashSet<>();
|
||||
public Set<String> offResearches = new HashSet<>();
|
||||
public Set<String> defCounsellors = new HashSet<>();
|
||||
public Set<String> offCounsellors = new HashSet<>();
|
||||
|
||||
public boolean nightBonus = false;
|
||||
|
||||
int luck, moral;
|
||||
|
||||
int olympicSwordGrepolympiaSummerLevel = 1;
|
||||
int offOlympicSensesGrepolympiaSummerLevel = 1;
|
||||
int aresRageLevel = 1;
|
||||
int aresArmyFurySpent = 0;
|
||||
int bloodlustFurySpent = 0;
|
||||
|
||||
int defOlympicSensesGrepolympiaSummerLevel = 1;
|
||||
int olympicTorchGrepolympiaSummerLevel = 1;
|
||||
int soteriasShrineLevel = 1;
|
||||
|
||||
boolean strategyBreach = false;
|
||||
boolean allianceModifier = false;
|
||||
|
||||
public DefContext asDefContext(GameConfig gc) {
|
||||
Map<Unit,Integer> unitsU = new HashMap<>(units.size());
|
||||
for(String u : units.keySet())
|
||||
unitsU.put(gc.getUnit(u), units.get(u));
|
||||
Map<Unit,Integer> unitsU = new HashMap<>(defUnits.size());
|
||||
for(String u : defUnits.keySet())
|
||||
unitsU.put(gc.getUnit(u), defUnits.get(u));
|
||||
return new DefContext(
|
||||
unitsU,
|
||||
gc.getHero(hero),
|
||||
heroLevel,
|
||||
gc.getHero(defHero),
|
||||
defHeroLevel,
|
||||
wallLevel,
|
||||
hasTower,
|
||||
powers,
|
||||
1, 1, 1,
|
||||
researches,
|
||||
counsellors,
|
||||
defPowers,
|
||||
defOlympicSensesGrepolympiaSummerLevel, olympicTorchGrepolympiaSummerLevel, soteriasShrineLevel,
|
||||
defResearches,
|
||||
defCounsellors,
|
||||
nightBonus
|
||||
);
|
||||
}
|
||||
|
||||
public Map<String, Integer> getUnits() {
|
||||
return units;
|
||||
public static Object random() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setUnits(Map<String, Integer> units) {
|
||||
this.units = units;
|
||||
public OffContext asOffContext(GameConfig gc) {
|
||||
Map<Unit,Integer> unitsU = new HashMap<>(offUnits.size());
|
||||
for(String u : offUnits.keySet())
|
||||
unitsU.put(gc.getUnit(u), offUnits.get(u));
|
||||
return new OffContext(
|
||||
unitsU,
|
||||
gc.getHero(defHero),
|
||||
defHeroLevel,
|
||||
luck, moral, defPowers,
|
||||
olympicSwordGrepolympiaSummerLevel, offOlympicSensesGrepolympiaSummerLevel, aresRageLevel, aresArmyFurySpent, bloodlustFurySpent, defResearches,
|
||||
defCounsellors, allianceModifier, allianceModifier
|
||||
);
|
||||
}
|
||||
|
||||
public void randomize(Random r,GameConfig gc) {
|
||||
|
||||
offUnits = new HashMap<>();
|
||||
God g = null;
|
||||
if(r.nextDouble()<0.8)
|
||||
g = Utils.randFromSet(r, gc.getGods());
|
||||
for(Unit u : Fight.relevantOffUnits(gc))
|
||||
if(u.getGod() == null || u.getGod().equals(g))
|
||||
if(r.nextDouble() < 0.7)
|
||||
offUnits.put(u.getId(), (int) ((r.nextExponential()*50+10)/Math.max(u.getPopulation(),1)));
|
||||
defUnits = new HashMap<>();
|
||||
g = null;
|
||||
if(r.nextDouble()<0.8)
|
||||
g = Utils.randFromSet(r, gc.getGods());
|
||||
for(Unit u : Fight.relevantDefUnits(gc))
|
||||
if(u.getGod() == null || u.getGod().equals(g))
|
||||
if(r.nextDouble() < 0.7)
|
||||
defUnits.put(u.getId(), (int) ((r.nextExponential()*50+10)/Math.max(u.getPopulation(),1)));
|
||||
|
||||
offHero = null;
|
||||
offHeroLevel = 0;
|
||||
if(r.nextDouble()<.7) {
|
||||
offHero = Utils.randFromSet(r, gc.getHeroes()).getId();
|
||||
offHeroLevel = r.nextInt(1, 21);
|
||||
}
|
||||
defHero = null;
|
||||
defHeroLevel = 0;
|
||||
if(r.nextDouble()<.7) {
|
||||
defHero = Utils.randFromSet(r, gc.getHeroes()).getId();
|
||||
defHeroLevel = r.nextInt(1, 21);
|
||||
}
|
||||
|
||||
wallLevel = r.nextInt(0, 26);
|
||||
hasTower = (wallLevel>20) && (r.nextDouble()<0.2);
|
||||
|
||||
luck = (int) (Math.tanh(r.nextGaussian())*20);
|
||||
moral = 100;
|
||||
if(r.nextDouble()<.7)
|
||||
moral = (int) Math.max(100-(r.nextExponential()*20),0);
|
||||
|
||||
offPowers = new HashSet<>();
|
||||
defPowers = new HashSet<>();
|
||||
for(String p : OffContext.POWERS) {
|
||||
if(r.nextDouble()<0.05)
|
||||
offPowers.add(p);
|
||||
if(r.nextDouble()<0.05)
|
||||
defPowers.add(p);
|
||||
}
|
||||
|
||||
olympicSwordGrepolympiaSummerLevel = r.nextInt(1, 5);
|
||||
offOlympicSensesGrepolympiaSummerLevel = r.nextInt(1, 5);
|
||||
aresRageLevel = r.nextInt(1, 11);
|
||||
aresArmyFurySpent = r.nextInt(1, 5000);
|
||||
bloodlustFurySpent = r.nextInt(1, 5000);
|
||||
defOlympicSensesGrepolympiaSummerLevel = r.nextInt(1, 5);
|
||||
olympicTorchGrepolympiaSummerLevel = r.nextInt(1, 5);
|
||||
soteriasShrineLevel = r.nextInt(1, 11);
|
||||
|
||||
offResearches = new HashSet<>();
|
||||
defResearches = new HashSet<>();
|
||||
for(String p : OffContext.RESEARCHES) {
|
||||
if(r.nextDouble()<0.20)
|
||||
offResearches.add(p);
|
||||
if(r.nextDouble()<0.20)
|
||||
defResearches.add(p);
|
||||
}
|
||||
offCounsellors = new HashSet<>();
|
||||
defCounsellors = new HashSet<>();
|
||||
for(String p : OffContext.COUNSELLORS) {
|
||||
if(r.nextDouble()<0.05)
|
||||
offCounsellors.add(p);
|
||||
if(r.nextDouble()<0.05)
|
||||
defCounsellors.add(p);
|
||||
}
|
||||
|
||||
strategyBreach = (r.nextDouble()<0.02);
|
||||
allianceModifier = (r.nextDouble()<0.001);
|
||||
nightBonus = (r.nextDouble()<0.02);
|
||||
|
||||
}
|
||||
|
||||
public String getHero() {
|
||||
return hero;
|
||||
|
||||
public Map<String, Integer> getDefUnits() {
|
||||
return defUnits;
|
||||
}
|
||||
|
||||
public void setHero(String hero) {
|
||||
this.hero = hero;
|
||||
public void setDefUnits(Map<String, Integer> defUnits) {
|
||||
this.defUnits = defUnits;
|
||||
}
|
||||
|
||||
public int getHeroLevel() {
|
||||
return heroLevel;
|
||||
public Map<String, Integer> getOffUnits() {
|
||||
return offUnits;
|
||||
}
|
||||
|
||||
public void setHeroLevel(int heroLevel) {
|
||||
this.heroLevel = heroLevel;
|
||||
public void setOffUnits(Map<String, Integer> offUnits) {
|
||||
this.offUnits = offUnits;
|
||||
}
|
||||
|
||||
public String getDefHero() {
|
||||
return defHero;
|
||||
}
|
||||
|
||||
public void setDefHero(String defHero) {
|
||||
this.defHero = defHero;
|
||||
}
|
||||
|
||||
public int getDefHeroLevel() {
|
||||
return defHeroLevel;
|
||||
}
|
||||
|
||||
public void setDefHeroLevel(int defHeroLevel) {
|
||||
this.defHeroLevel = defHeroLevel;
|
||||
}
|
||||
|
||||
public String getOffHero() {
|
||||
return offHero;
|
||||
}
|
||||
|
||||
public void setOffHero(String offHero) {
|
||||
this.offHero = offHero;
|
||||
}
|
||||
|
||||
public int getOffHeroLevel() {
|
||||
return offHeroLevel;
|
||||
}
|
||||
|
||||
public void setOffHeroLevel(int offHeroLevel) {
|
||||
this.offHeroLevel = offHeroLevel;
|
||||
}
|
||||
|
||||
public int getWallLevel() {
|
||||
@ -129,22 +291,98 @@ public static class DefSimulatorParams {
|
||||
this.hasTower = hasTower;
|
||||
}
|
||||
|
||||
public Set<String> getPowers() {
|
||||
return powers;
|
||||
}
|
||||
|
||||
public Map<String,Boolean> getPowersAsMap() {
|
||||
return Utils.setToMap(powers);
|
||||
public Set<String> getDefPowers() {
|
||||
return defPowers;
|
||||
}
|
||||
|
||||
public Map<String,Boolean> getResearchesAsMap() {
|
||||
return Utils.setToMap(researches);
|
||||
public void setDefPowers(Set<String> defPowers) {
|
||||
this.defPowers = defPowers;
|
||||
}
|
||||
|
||||
public Map<String,Boolean> getCounsellorsAsMap() {
|
||||
return Utils.setToMap(counsellors);
|
||||
|
||||
public Set<String> getOffPowers() {
|
||||
return offPowers;
|
||||
}
|
||||
|
||||
|
||||
public void setOffPowers(Set<String> offPowers) {
|
||||
this.offPowers = offPowers;
|
||||
}
|
||||
|
||||
public Set<String> getDefResearches() {
|
||||
return defResearches;
|
||||
}
|
||||
|
||||
public void setDefResearches(Set<String> defResearches) {
|
||||
this.defResearches = defResearches;
|
||||
}
|
||||
|
||||
public Set<String> getOffResearches() {
|
||||
return offResearches;
|
||||
}
|
||||
|
||||
public void setOffResearches(Set<String> offResearches) {
|
||||
this.offResearches = offResearches;
|
||||
}
|
||||
|
||||
public Set<String> getDefCounsellors() {
|
||||
return defCounsellors;
|
||||
}
|
||||
|
||||
public void setDefCounsellors(Set<String> defCounsellors) {
|
||||
this.defCounsellors = defCounsellors;
|
||||
}
|
||||
|
||||
public Set<String> getOffCounsellors() {
|
||||
return offCounsellors;
|
||||
}
|
||||
|
||||
public void setOffCounsellors(Set<String> offCounsellors) {
|
||||
this.offCounsellors = offCounsellors;
|
||||
}
|
||||
|
||||
public int getLuck() {
|
||||
return luck;
|
||||
}
|
||||
|
||||
public void setLuck(int luck) {
|
||||
this.luck = luck;
|
||||
}
|
||||
|
||||
public int getMoral() {
|
||||
return moral;
|
||||
}
|
||||
|
||||
public void setMoral(int moral) {
|
||||
this.moral = moral;
|
||||
}
|
||||
|
||||
public boolean isStrategyBreach() {
|
||||
return strategyBreach;
|
||||
}
|
||||
|
||||
public void setStrategyBreach(boolean strategyBreach) {
|
||||
this.strategyBreach = strategyBreach;
|
||||
}
|
||||
|
||||
public boolean isAllianceModifier() {
|
||||
return allianceModifier;
|
||||
}
|
||||
|
||||
public void setAllianceModifier(boolean allianceModifier) {
|
||||
this.allianceModifier = allianceModifier;
|
||||
}
|
||||
|
||||
public Map<String, Boolean> getDefPowersAsMap() {
|
||||
return Utils.setToMap(defPowers);
|
||||
}
|
||||
|
||||
public Map<String, Boolean> getDefResearchesAsMap() {
|
||||
return Utils.setToMap(defResearches);
|
||||
}
|
||||
|
||||
public Map<String, Boolean> getDefCounsellorsAsMap() {
|
||||
return Utils.setToMap(defCounsellors);
|
||||
}
|
||||
|
||||
public boolean isNightBonus() {
|
||||
return nightBonus;
|
||||
}
|
||||
@ -153,6 +391,5 @@ public static class DefSimulatorParams {
|
||||
this.nightBonus = nightBonus;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import com.bernard.greposimu.model.FightStats;
|
||||
import com.bernard.greposimu.model.OffContext;
|
||||
import com.bernard.greposimu.model.game.GameConfig;
|
||||
import com.bernard.greposimu.model.game.researches.Research;
|
||||
import com.bernard.greposimu.model.game.units.FightType;
|
||||
import com.bernard.greposimu.model.game.units.NavalUnit;
|
||||
import com.bernard.greposimu.model.game.units.TerrestrialUnit;
|
||||
import com.bernard.greposimu.model.game.units.Unit;
|
||||
@ -41,18 +42,14 @@ public class Fight {
|
||||
if(u.isMythological())
|
||||
unitsBonuses.put(u, FightStats.add(unitsBonuses.getOrDefault(u, FightStats.zero()), FightStats.cst(0.1)));
|
||||
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)));
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(0.1));
|
||||
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)));
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.naval(0.1));
|
||||
|
||||
// Counsellors
|
||||
if(def.hasPriest())
|
||||
for(Unit u : gc.getUnits())
|
||||
if(u.isGround())
|
||||
if(u.isMythological())
|
||||
unitsBonuses.put(u, FightStats.add(unitsBonuses.getOrDefault(u, FightStats.zero()), FightStats.cst(0.2)));
|
||||
if(def.hasCommander())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(0.2));
|
||||
@ -75,7 +72,7 @@ public class Fight {
|
||||
if(def.getOlympicTorchGrepolympiaSummerLevel()!=0)
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(+0.05*def.getOlympicTorchGrepolympiaSummerLevel()));
|
||||
if(def.getSoteriasShrineLevel()!=0)
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(+0.007*def.getOlympicTorchGrepolympiaSummerLevel()));
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(+0.007*def.getSoteriasShrineLevel()));
|
||||
if(def.hasNarcissism())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(-0.1));
|
||||
|
||||
@ -95,6 +92,16 @@ public class Fight {
|
||||
));
|
||||
}
|
||||
|
||||
// HeroStat
|
||||
if(def.getHero() != null) {
|
||||
total = FightStats.add(total, new FightStats(
|
||||
def.getHero().getHackDef() * (1.0+0.1*def.getHeroLevel()),
|
||||
def.getHero().getPierceDef() * (1.0+0.1*def.getHeroLevel()),
|
||||
def.getHero().getDistanceDef() * (1.0+0.1*def.getHeroLevel()),
|
||||
0.0
|
||||
));
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
@ -109,27 +116,127 @@ public class Fight {
|
||||
throw new UnsupportedOperationException("I don't know how to manage units of type "+u.getClass().getName());
|
||||
}
|
||||
|
||||
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","narcissism");
|
||||
public static FightStats computeOffStats(GameConfig gc, OffContext off) {
|
||||
|
||||
FightStats everyoneStatsBonus = FightStats.zero();
|
||||
Map<Unit,FightStats> unitsBonuses;
|
||||
|
||||
// Heroes
|
||||
unitsBonuses = Heroes.heroFightBonuses(gc, off.getHero(), off.getHeroLevel(), false);
|
||||
|
||||
// Researches
|
||||
if(off.hasDivineSelection())
|
||||
for(Unit u : gc.getUnits())
|
||||
if(u.isMythological())
|
||||
unitsBonuses.put(u, FightStats.add(unitsBonuses.getOrDefault(u, FightStats.zero()), FightStats.cst(0.1)));
|
||||
if(off.hasPhalanx())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(0.1));
|
||||
if(off.hasRam())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.naval(0.1));
|
||||
|
||||
|
||||
// Counsellors
|
||||
if(off.hasPriest())
|
||||
for(Unit u : gc.getUnits())
|
||||
if(u.isMythological())
|
||||
unitsBonuses.put(u, FightStats.add(unitsBonuses.getOrDefault(u, FightStats.zero()), FightStats.cst(0.2)));
|
||||
if(off.hasCommander())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(0.2));
|
||||
if(off.hasCaptain())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.naval(0.2));
|
||||
|
||||
// Powers
|
||||
if(off.hasMyrmidionAttack())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(+0.1));
|
||||
if(off.hasAttackBoost())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(+0.1));
|
||||
if(off.hasAttackPenalty())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(-0.1));
|
||||
if(off.hasLongtermAttackBoost())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(+0.1));
|
||||
if(off.hasLuxurious_residence())
|
||||
;//XXX Unimplemented
|
||||
if(off.hasAttack_ship_attack_boost_small())
|
||||
unitsBonuses.put(gc.getUnit("attack_ship"), FightStats.add(unitsBonuses.getOrDefault(gc.getUnit("attack_ship"), FightStats.zero()), FightStats.cst(0.1)));
|
||||
if(off.hasAttack_ship_attack_boost_medium())
|
||||
unitsBonuses.put(gc.getUnit("attack_ship"), FightStats.add(unitsBonuses.getOrDefault(gc.getUnit("attack_ship"), FightStats.zero()), FightStats.cst(0.2)));
|
||||
if(off.hasAttack_ship_attack_boost_large())
|
||||
unitsBonuses.put(gc.getUnit("attack_ship"), FightStats.add(unitsBonuses.getOrDefault(gc.getUnit("attack_ship"), FightStats.zero()), FightStats.cst(0.3)));
|
||||
if(off.hasRareAttackBoost())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(+0.1));
|
||||
if(off.hasEpicAttackBoost())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(+0.2));
|
||||
if(off.getOlympicSwordGrepolympiaSummerLevel()!=0)
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(+0.05*off.getOlympicSwordGrepolympiaSummerLevel()));
|
||||
if(off.getAresRageLevel()!=0)
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(+0.01*off.getAresRageLevel()));
|
||||
if(off.getBloodlust()!=0)
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(0.05+0.01*Math.floorDiv(off.getBloodlust(),200)));
|
||||
if(off.hasFairWind())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.naval(0.1));
|
||||
if(off.hasDesire())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(-0.1));
|
||||
if(off.hasStrengthOfHeroes())
|
||||
//XXX check if working
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.terrestre(0.1));
|
||||
if(off.hasEffortOfTheHuntress())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.ofType(FightType.DISTANCE,0.15));
|
||||
|
||||
if(off.hasStrategyBreach())
|
||||
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.naval(-0.5));
|
||||
|
||||
|
||||
// Units
|
||||
FightStats total = FightStats.zero();
|
||||
for(Unit u : gc.getUnits()) {
|
||||
// total = total + ucount * ((1+bonusA+bonusB) * ustats)
|
||||
total = FightStats.add(total,
|
||||
FightStats.prod(off.unitCount(u),
|
||||
FightStats.mul(
|
||||
FightStats.add(FightStats.one(),everyoneStatsBonus,unitsBonuses.getOrDefault(u, FightStats.zero()))
|
||||
, makeOffStats(u))
|
||||
));
|
||||
}
|
||||
if(off.getAresArmyFurySpent()!=0)
|
||||
// Ading aresarmy/25 spartiates
|
||||
total = FightStats.add(total,
|
||||
FightStats.prod(Math.floorDiv(off.getAresArmyFurySpent(), 25),
|
||||
FightStats.mul(
|
||||
FightStats.add(FightStats.one(),everyoneStatsBonus,unitsBonuses.getOrDefault(gc.getUnit("spartoi"), FightStats.zero()))
|
||||
, makeOffStats(gc.getUnit("spartoi")))
|
||||
));
|
||||
|
||||
|
||||
|
||||
// HeroStat
|
||||
if(off.getHero() != null) {
|
||||
total = FightStats.add(total, new FightStats(
|
||||
off.getHero().getHackDef() * (1.0+0.1*off.getHeroLevel()),
|
||||
off.getHero().getPierceDef() * (1.0+0.1*off.getHeroLevel()),
|
||||
off.getHero().getDistanceDef() * (1.0+0.1*off.getHeroLevel()),
|
||||
0.0
|
||||
));
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
public static List<Research> relevantDefResearches(GameConfig gd) {
|
||||
return List.of("divine_selection","phalanx","ram")
|
||||
.stream().map(gd::getResearch).toList();
|
||||
|
||||
public static FightStats makeOffStats(Unit u) {
|
||||
if(u instanceof TerrestrialUnit) {
|
||||
TerrestrialUnit tu = (TerrestrialUnit)u;
|
||||
return FightStats.ofType(tu.getAttackType(), tu.getAttack());
|
||||
}else if(u instanceof NavalUnit) {
|
||||
NavalUnit nu = (NavalUnit)u;
|
||||
return new FightStats(0.0, 0.0, 0.0, nu.getAttack());
|
||||
}
|
||||
throw new UnsupportedOperationException("I don't know how to manage units of type "+u.getClass().getName());
|
||||
}
|
||||
|
||||
public static List<Unit> relevantDefUnits(GameConfig gc) {
|
||||
return gc.getUnits().stream().toList();
|
||||
}
|
||||
public static List<String> relevantDefCounsellors(GameConfig data) {
|
||||
return List.of("priest","commander","captain");
|
||||
}
|
||||
public FightStats computeOffStats(DefContext off) {
|
||||
//TODO computeOffStats
|
||||
throw new UnsupportedOperationException("Simulator not created");
|
||||
public static List<Unit> relevantOffUnits(GameConfig gc) {
|
||||
return gc.getUnits().stream().toList();
|
||||
}
|
||||
|
||||
public FightResult simulateFight(OffContext off, DefContext def) {
|
||||
|
||||
@ -1,21 +1,22 @@
|
||||
package com.bernard.greposimu.model;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
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 {
|
||||
|
||||
// UNITS
|
||||
Map<Unit, Integer> units;
|
||||
// Units unrelated to the attacker
|
||||
Map<Unit, Integer> otherUnits;
|
||||
// Units owned by allies of the attacker
|
||||
Map<Unit, Integer> alliedUnits;
|
||||
// Units owned by the attacher
|
||||
Map<Unit, Integer> selfUnits;
|
||||
|
||||
// HEROS
|
||||
Hero hero = null;
|
||||
@ -81,8 +82,16 @@ public class DefContext {
|
||||
boolean nightBonus = false;
|
||||
|
||||
public DefContext(Map<Unit, Integer> units, Hero hero, int heroLevel, int wallLevel, boolean hasTower,
|
||||
Set<String> powers, int soteriasShrinePowerLevel, int olympicTorchGrepolympiaSummerLevel, int olympicSensesGrepolympiaSummerLevel,
|
||||
Set<String> researches, Set<String> counsellors, boolean nightBonus) {
|
||||
this(units,Map.of(),Map.of(),hero,heroLevel,wallLevel,hasTower,powers,soteriasShrinePowerLevel,olympicTorchGrepolympiaSummerLevel,olympicSensesGrepolympiaSummerLevel,researches,counsellors,nightBonus);
|
||||
}
|
||||
|
||||
public DefContext(Map<Unit, Integer> otherUnits, Map<Unit, Integer> alliedUnits, Map<Unit, Integer> selfUnits, Hero hero, int heroLevel, int wallLevel, boolean hasTower,
|
||||
Set<String> powers, int soteriasShrinePowerLevel, int olympicTorchGrepolympiaSummerLevel, int olympicSensesGrepolympiaSummerLevel, Set<String> researches, Set<String> counsellors, boolean nightBonus) {
|
||||
this.units = units;
|
||||
this.otherUnits = otherUnits;
|
||||
this.alliedUnits = alliedUnits;
|
||||
this.selfUnits = selfUnits;
|
||||
this.hero = hero;
|
||||
this.heroLevel = heroLevel;
|
||||
this.wallLevel = wallLevel;
|
||||
@ -96,7 +105,7 @@ public class DefContext {
|
||||
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("epic_defense_boost"))this.epicDefenseBoost = 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;
|
||||
@ -117,11 +126,11 @@ public class DefContext {
|
||||
this.nightBonus = nightBonus;
|
||||
}
|
||||
|
||||
public Map<Unit, Integer> getUnits() {
|
||||
return units;
|
||||
}
|
||||
public int unitCount(Unit u) {
|
||||
return Optional.ofNullable(units.getOrDefault(u,0)).orElse(0);
|
||||
return
|
||||
Optional.ofNullable(otherUnits.getOrDefault(u,0)).orElse(0) +
|
||||
Optional.ofNullable(alliedUnits.getOrDefault(u,0)).orElse(0) +
|
||||
Optional.ofNullable(selfUnits.getOrDefault(u,0)).orElse(0);
|
||||
}
|
||||
public Hero getHero() {
|
||||
return hero;
|
||||
@ -247,4 +256,11 @@ public class DefContext {
|
||||
return narcissism;
|
||||
}
|
||||
|
||||
public static final List<String> POWERS = 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", "olympic_senses", "missions_power_4", "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", "narcissism");
|
||||
public static final List<String> RESEARCHES = List.of("divine_selection","phalanx","ram");
|
||||
public static final List<String> COUNSELLORS = List.of("priest","commander","captain");
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@ package com.bernard.greposimu.model;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.bernard.greposimu.model.game.units.FightType;
|
||||
|
||||
public class FightStats implements Cloneable{
|
||||
public double hack;
|
||||
public double pierce;
|
||||
@ -15,6 +17,19 @@ public class FightStats implements Cloneable{
|
||||
this.ship = ship;
|
||||
}
|
||||
|
||||
public static final FightStats ofType(FightType type, double value) {
|
||||
switch(type) {
|
||||
case HACK:
|
||||
return new FightStats(value, 0.0, 0.0, 0.0);
|
||||
case PIERCE:
|
||||
return new FightStats(0.0, value, 0.0, 0.0);
|
||||
case DISTANCE:
|
||||
return new FightStats(0.0, 0.0, value, 0.0);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static final FightStats zero() {
|
||||
return new FightStats(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
@ -1,23 +1,288 @@
|
||||
package com.bernard.greposimu.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import com.bernard.greposimu.model.game.units.Hero;
|
||||
import com.bernard.greposimu.model.game.units.Unit;
|
||||
|
||||
public class OffContext {
|
||||
// unitID -> number of units
|
||||
public Map<String, Integer> units;
|
||||
|
||||
public String heros;
|
||||
public int herosLevel;
|
||||
Map<Unit, Integer> units;
|
||||
|
||||
public int luck;
|
||||
public int morale;
|
||||
Hero hero;
|
||||
int heroLevel;
|
||||
|
||||
public Set<String> powers;
|
||||
public Set<String> researches;
|
||||
int luck;
|
||||
int moral;
|
||||
|
||||
public Set<String> counsellors;
|
||||
// RESEARCHES
|
||||
boolean divineSelection= false, phalanx = false, ram=false, combatExperience=false;
|
||||
|
||||
// COUNSELLORS
|
||||
boolean commander= false;
|
||||
boolean priest = false;
|
||||
boolean captain = false;
|
||||
|
||||
// EFFECTS
|
||||
// PC x2
|
||||
boolean acumen = false;
|
||||
// PC x4
|
||||
boolean divineSenses= false;
|
||||
// Attq +10%, Def -10%
|
||||
boolean myrmidionAttack= false;
|
||||
// Attq +10%
|
||||
boolean attackBoost= false;
|
||||
// Attq -10%
|
||||
boolean attackPenalty= false;
|
||||
// Attq +10%
|
||||
boolean longtermAttackBoost = false;
|
||||
//XXX implement this :/
|
||||
boolean luxuriousResidence = false;
|
||||
// BF attq +10%
|
||||
boolean attack_ship_attack_boost_small = false;
|
||||
// BF attq +20%
|
||||
boolean attack_ship_attack_boost_medium = false;
|
||||
// BF attq +30%
|
||||
boolean attack_ship_attack_boost_large = false;
|
||||
// PC +50%
|
||||
boolean assassinsAcumen= false;
|
||||
// Attq +10%
|
||||
boolean rareAttackBoost= false;
|
||||
// Attq +20%
|
||||
boolean epicAttackBoost= false;
|
||||
// Attq +5%*level
|
||||
int olympicSwordGrepolympiaSummerLevel = 0;
|
||||
// PC+10%*level
|
||||
int olympicSensesGrepolympiaSummerLevel = 0;
|
||||
// +50% PC
|
||||
boolean missionsPower4= false;
|
||||
// PC+50% (sauf BC, transport)
|
||||
boolean divineBattleStrategyRare= false;
|
||||
// PC+100% (sauf BC, transport)
|
||||
boolean divineBattleStrategyEpic= false;
|
||||
// PC+50% against naval (sauf BC,transports)
|
||||
boolean navalBattleStrategyRare= false;
|
||||
// PC+100% against naval (sauf BC, transport)
|
||||
boolean navalBattleStrategyEpic= false;
|
||||
// PC+50% against terrestres
|
||||
boolean landBattleStrategyRare= false;
|
||||
// PC+100% against terrestre
|
||||
boolean landBattleStrategyEpic= false;
|
||||
// Attq +1%*level
|
||||
int aresRageLevel = 0;
|
||||
|
||||
// SPELLS
|
||||
// Add one sparte for every 25 fury used
|
||||
int aresArmyFurySpent = 0;
|
||||
// Attq +5% +(1% for each 200 fury spent)
|
||||
// PC + 1% for each 100 fury spent
|
||||
int bloodlustFurySpent = 0;
|
||||
// Attq naval +10%
|
||||
boolean fairWind = false;
|
||||
// Attq -10%
|
||||
boolean desire = false;
|
||||
// Terr + aer +10% attq
|
||||
boolean strengthOfHeroes = false;
|
||||
// Attq distance +15%
|
||||
boolean effortOfTheHuntress = false;
|
||||
|
||||
boolean strategyBreach = false;
|
||||
boolean allianceModifier = false;
|
||||
|
||||
|
||||
public OffContext(Map<Unit, Integer> units, Hero hero, int heroLevel, int luck, int moral,
|
||||
Set<String> powers, int olympicSwordGrepolympiaSummerLevel, int olympicSensesGrepolympiaSummerLevel,
|
||||
int aresRageLevel, int aresArmyFurySpent, int bloodlustFurySpent, Set<String> researches, Set<String> counsellors,
|
||||
boolean strategyBreach, boolean allianceModifier) {
|
||||
this.units = units;
|
||||
this.hero = hero;
|
||||
this.heroLevel = heroLevel;
|
||||
this.luck = luck;
|
||||
this.moral = moral;
|
||||
|
||||
if(powers.contains("acumen"))this.acumen = true;
|
||||
if(powers.contains("divine_senses"))this.divineSenses = true;
|
||||
if(powers.contains("myrmidion_attack"))this.myrmidionAttack = true;
|
||||
if(powers.contains("attack_boost"))this.attackBoost = true;
|
||||
if(powers.contains("attack_penalty"))this.attackPenalty = true;
|
||||
if(powers.contains("longterm_attack_boost"))this.longtermAttackBoost = true;
|
||||
if(powers.contains("attack_ship_attack_boost_small"))this.attack_ship_attack_boost_small = true;
|
||||
if(powers.contains("attack_ship_attack_boost_medium"))this.attack_ship_attack_boost_medium = true;
|
||||
if(powers.contains("attack_ship_attack_boost_large"))this.attack_ship_attack_boost_large = true;
|
||||
if(powers.contains("assassins_acumen"))this.assassinsAcumen = true;
|
||||
if(powers.contains("rare_attack_boost"))this.rareAttackBoost = true;
|
||||
if(powers.contains("epic_attack_boost"))this.epicAttackBoost = true;
|
||||
if(powers.contains("olympic_sword"))this.olympicSwordGrepolympiaSummerLevel = olympicSwordGrepolympiaSummerLevel;
|
||||
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("ares_rage"))this.aresRageLevel = aresRageLevel;
|
||||
if(powers.contains("ares_army"))this.aresArmyFurySpent = aresArmyFurySpent;
|
||||
if(powers.contains("bloodlust"))this.bloodlustFurySpent = bloodlustFurySpent;
|
||||
if(powers.contains("fair_wind"))this.fairWind = true;
|
||||
if(powers.contains("desire"))this.desire = true;
|
||||
if(powers.contains("effort_of_the_huntress"))this.effortOfTheHuntress = true;
|
||||
if(powers.contains("strength_of_heroes"))this.strengthOfHeroes = true;
|
||||
if(researches.contains("divine_selection"))this.divineSelection = true;
|
||||
if(researches.contains("phalanx"))this.phalanx = true;
|
||||
if(researches.contains("ram"))this.ram = true;
|
||||
if(researches.contains("combat_experience"))this.combatExperience = true;
|
||||
if(counsellors.contains("commander"))this.commander = true;
|
||||
if(counsellors.contains("priest"))this.priest = true;
|
||||
if(counsellors.contains("captain"))this.captain = true;
|
||||
this.strategyBreach = strategyBreach;
|
||||
this.allianceModifier = allianceModifier;
|
||||
}
|
||||
|
||||
public int unitCount(Unit u) {
|
||||
return Optional.ofNullable(units.getOrDefault(u,0)).orElse(0);
|
||||
}
|
||||
public Map<Unit, Integer> getUnits() {
|
||||
return units;
|
||||
}
|
||||
public Hero getHero() {
|
||||
return hero;
|
||||
}
|
||||
public int getHeroLevel() {
|
||||
return heroLevel;
|
||||
}
|
||||
public int getLuck() {
|
||||
return luck;
|
||||
}
|
||||
public int getMorale() {
|
||||
return moral;
|
||||
}
|
||||
public boolean hasDivineSelection() {
|
||||
return divineSelection;
|
||||
}
|
||||
public boolean hasPhalanx() {
|
||||
return phalanx;
|
||||
}
|
||||
public boolean hasRam() {
|
||||
return ram;
|
||||
}
|
||||
public boolean hasCombatExperience() {
|
||||
return combatExperience;
|
||||
}
|
||||
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 hasAttackBoost() {
|
||||
return attackBoost;
|
||||
}
|
||||
public boolean hasAttackPenalty() {
|
||||
return attackPenalty;
|
||||
}
|
||||
public boolean hasLongtermAttackBoost() {
|
||||
return longtermAttackBoost;
|
||||
}
|
||||
public boolean hasLuxurious_residence() {
|
||||
return luxuriousResidence;
|
||||
}
|
||||
public boolean hasAttack_ship_attack_boost_small() {
|
||||
return attack_ship_attack_boost_small;
|
||||
}
|
||||
public boolean hasAttack_ship_attack_boost_medium() {
|
||||
return attack_ship_attack_boost_medium;
|
||||
}
|
||||
public boolean hasAttack_ship_attack_boost_large() {
|
||||
return attack_ship_attack_boost_large;
|
||||
}
|
||||
public boolean hasAssassinsAcumen() {
|
||||
return assassinsAcumen;
|
||||
}
|
||||
public boolean hasRareAttackBoost() {
|
||||
return rareAttackBoost;
|
||||
}
|
||||
public boolean hasEpicAttackBoost() {
|
||||
return epicAttackBoost;
|
||||
}
|
||||
public int getOlympicSwordGrepolympiaSummerLevel() {
|
||||
return olympicSwordGrepolympiaSummerLevel;
|
||||
}
|
||||
public int getOlympicSensesGrepolympiaSummerLevel() {
|
||||
return olympicSensesGrepolympiaSummerLevel;
|
||||
}
|
||||
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 getAresRageLevel() {
|
||||
return aresRageLevel;
|
||||
}
|
||||
public int getAresArmyFurySpent() {
|
||||
return aresArmyFurySpent;
|
||||
}
|
||||
public int getBloodlust() {
|
||||
return bloodlustFurySpent;
|
||||
}
|
||||
public boolean hasFairWind() {
|
||||
return fairWind;
|
||||
}
|
||||
public boolean hasDesire() {
|
||||
return desire;
|
||||
}
|
||||
public boolean hasStrengthOfHeroes() {
|
||||
return strengthOfHeroes;
|
||||
}
|
||||
public boolean hasEffortOfTheHuntress() {
|
||||
return effortOfTheHuntress;
|
||||
}
|
||||
public boolean hasStrategyBreach() {
|
||||
return strategyBreach;
|
||||
}
|
||||
public boolean hasAllianceModifier() {
|
||||
return allianceModifier;
|
||||
}
|
||||
|
||||
public static final List<String> POWERS = List.of("acumen", "divine_senses", "myrmidion_attack", "attack_boost",
|
||||
"attack_penalty", "longterm_attack_boost", "attack_ship_attack_boost_small",
|
||||
"attack_ship_attack_boost_medium", "attack_ship_attack_boost_large", "assassins_acumen",
|
||||
"rare_attack_boost", "epic_attack_boost", "olympic_sword", "olympic_senses", "missions_power_4",
|
||||
"divine_battle_strategy_rare", "divine_battle_strategy_epic", "naval_battle_strategy_rare",
|
||||
"naval_battle_strategy_epic", "land_battle_strategy_rare", "land_battle_strategy_epic", "ares_rage",
|
||||
"ares_army", "bloodlust", "fair_wind", "desire", "effort_of_the_huntress", "strength_of_heroes");
|
||||
public static final List<String> RESEARCHES = List.of("divine_selection","phalanx","ram","combat_experience");
|
||||
public static final List<String> COUNSELLORS = List.of("priest","commander","captain");
|
||||
|
||||
public boolean strategy_breach;
|
||||
public boolean alliance_modifier;
|
||||
}
|
||||
|
||||
@ -31,6 +31,10 @@ public class GameConfig {
|
||||
this.researches = researches;
|
||||
this.powers = powers;
|
||||
}
|
||||
|
||||
public Set<God> getGods() {
|
||||
return gods;
|
||||
}
|
||||
|
||||
public Set<Unit> getUnits() {
|
||||
return Collections.unmodifiableSet(this.units);
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package com.bernard.greposimu.model.game;
|
||||
|
||||
public class God implements Identified{
|
||||
import java.util.Objects;
|
||||
|
||||
public class God implements Identified,Comparable<God>{
|
||||
|
||||
String id;
|
||||
String name;
|
||||
@ -18,5 +20,33 @@ public class God implements Identified{
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(God o) {
|
||||
return this.getId().compareTo(o.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
God other = (God) obj;
|
||||
return Objects.equals(id, other.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "God [id=" + id + ", name=" + name + "]";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
package com.bernard.greposimu.model.game.units;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import com.bernard.greposimu.model.game.God;
|
||||
import com.bernard.greposimu.model.game.Identified;
|
||||
import com.bernard.greposimu.model.game.Resources;
|
||||
|
||||
public class Hero extends TerrestrialUnit{
|
||||
public class Hero extends TerrestrialUnit implements Comparable<Hero>{
|
||||
|
||||
// Zero population
|
||||
// Non mythological
|
||||
@ -76,6 +75,34 @@ public class Hero extends TerrestrialUnit{
|
||||
return powerValuePerLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Hero o) {
|
||||
return this.getId().compareTo(o.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Hero other = (Hero) obj;
|
||||
return Objects.equals(id, other.id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Hero [category=" + category + ", cost=" + cost + ", shortDescription=" + shortDescription
|
||||
+ ", powerBaseValue=" + powerBaseValue + ", powerValuePerLevel=" + powerValuePerLevel + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1 @@
|
||||
missions_power_4.missions_dionysia.disabled.png
|
||||
@ -0,0 +1 @@
|
||||
missions_power_4.missions_dionysia.hover.png
|
||||
1
src/main/resources/static/images/powers/missions_power_4.png
Symbolic link
1
src/main/resources/static/images/powers/missions_power_4.png
Symbolic link
@ -0,0 +1 @@
|
||||
missions_power_4.missions_dionysia.png
|
||||
@ -85,6 +85,17 @@ span.fixed50px {
|
||||
border: 0px;
|
||||
margin: auto;
|
||||
}
|
||||
.container {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.columns {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.formcol {
|
||||
flex: 50%;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@ -92,95 +103,147 @@ span.fixed50px {
|
||||
<body>
|
||||
|
||||
<form action="#" th:object="${ctx}" method="post" id="simuform" >
|
||||
|
||||
<fieldset id="herosFields">
|
||||
<legend>Héros</legend>
|
||||
<select name="heros" id="heros" th:field="*{hero}">
|
||||
<option value="none">Aucun</option>
|
||||
<option th:each="hero : ${heroes}" th:value="${hero.id}"><span th:text="${hero.name}"/></option>
|
||||
</select>
|
||||
|
||||
<label for="heroLevelSlider">Niveau du héros: (<span id="heroLevelSliderInfo" class="fixed50px"></span>)</label>
|
||||
<input type="range" min="1" max="20" value="1" class="slider" id="heroLevelSlider" th:field="*{heroLevel}">
|
||||
|
||||
<script>
|
||||
var heroSlider = document.getElementById("heroLevelSlider");
|
||||
var heroOutput = document.getElementById("heroLevelSliderInfo");
|
||||
heroOutput.innerHTML = "lvl. "+heroSlider.value;
|
||||
// Update the current slider value (each time you drag the slider handle)
|
||||
heroSlider.oninput = function() {
|
||||
heroOutput.innerHTML = "lvl. "+this.value;
|
||||
}
|
||||
</script>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Unités</legend>
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td th:each="unite : ${defUnits}" class="squareContainer">
|
||||
<div class="columns">
|
||||
<fieldset class="formcol">
|
||||
<legend>Attaque</legend>
|
||||
<fieldset id="herosFields">
|
||||
<legend>Héros</legend>
|
||||
<select name="offHeros" id="offHeros" th:field="*{offHero}">
|
||||
<option value="none">Aucun</option>
|
||||
<option th:each="hero : ${heroes}" th:value="${hero.id}"><span th:text="${hero.name}"/></option>
|
||||
</select>
|
||||
|
||||
<label for="offHeroLevelSlider">Niveau du héros: (<span id="offHeroLevelSliderInfo" class="fixed50px"></span>)</label>
|
||||
<input type="range" min="1" max="20" value="1" class="slider" id="offHeroLevelSlider" th:field="*{offHeroLevel}">
|
||||
|
||||
<script>
|
||||
var offHeroSlider = document.getElementById("offHeroLevelSlider");
|
||||
var offHeroOutput = document.getElementById("offHeroLevelSliderInfo");
|
||||
offHeroOutput.innerHTML = "lvl. "+offHeroSlider.value;
|
||||
// Update the current slider value (each time you drag the slider handle)
|
||||
offHeroSlider.oninput = function() {
|
||||
offHeroOutput.innerHTML = "lvl. "+this.value;
|
||||
}
|
||||
</script>
|
||||
</fieldset>
|
||||
<fieldset id="unitesFS">
|
||||
<legend>Unités</legend>
|
||||
<div th:each="unite : ${defUnits}" class="container">
|
||||
<img class="squareImage" th:for="'unite-'+${unite.id}" th:src="@{/images/units/{uname}.png(uname=${unite.id})}"/>
|
||||
<input type="number" class="squareNumber" th:id="'unite-'+${unite.id}" th:field="*{units[__${unite.id}__]}"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Batiments</legend>
|
||||
<label for="hasTower">Tour :</label>
|
||||
<input type="checkbox" id="hasTower" th:field="*{hasTower}"/><br/>
|
||||
|
||||
<label for="wallLevelSlider">Niveau des remparts: (<span id="wallLevelSliderInfo" class="fixed50px"></span>)</label>
|
||||
<input type="range" min="0" max="25" value="1" class="slider" id="wallLevelSlider" th:field="*{wallLevel}">
|
||||
|
||||
<script>
|
||||
var wallSlider = document.getElementById("wallLevelSlider");
|
||||
var wallOutput = document.getElementById("wallLevelSliderInfo");
|
||||
wallOutput.innerHTML = "lvl. "+wallSlider.value;
|
||||
// Update the current slider value (each time you drag the slider handle)
|
||||
wallSlider.oninput = function() {
|
||||
wallOutput.innerHTML = "lvl. "+this.value;
|
||||
}
|
||||
</script>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Pouvoirs</legend>
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td th:each="power : ${defPowers}" class="squareContainer">
|
||||
<br/>
|
||||
<input type="number" class="squareNumber" th:id="'unite-'+${unite.id}" th:field="*{offUnits[__${unite.id}__]}"/>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Pouvoirs</legend>
|
||||
<div th:each="power : ${offPowers}" class="container">
|
||||
<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>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Recherches</legend>
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td th:each="research : ${defResearches}" class="squareContainer">
|
||||
<img class="squareImage" th:for="'research-'+${research.id}" th:src="@{/images/researches/{rname}.png(rname=${research.id})}"/>
|
||||
<input type="checkbox" th:id="'research-'+${research.id}" th:field="*{researchesAsMap[__${research.id}__]}" th:value="true"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Conseillers</legend>
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td th:each="counsellor : ${defCounsellors}" class="squareContainer">
|
||||
<input type="checkbox" th:id="'power-'+${power}" th:field="*{defPowersAsMap[__${power}__]}" th:value="true"/>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Recherches</legend>
|
||||
<div th:each="research : ${offResearches}" class="container">
|
||||
<img class="squareImage" th:for="'research-'+${research}" th:src="@{/images/researches/{rname}.png(rname=${research})}"/>
|
||||
<input type="checkbox" th:id="'research-'+${research}" th:field="*{defResearchesAsMap[__${research}__]}" th:value="true"/>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Conseillers</legend>
|
||||
<div th:each="counsellor : ${offCounsellors}" class="container">
|
||||
<img class="squareImage" th:for="'counsellor-'+${counsellor}" th:src="@{/images/counsellors/{cname}.png(cname=${counsellor})}"/>
|
||||
<input type="checkbox" th:id="'counsellor-'+${counsellor}" th:field="*{counsellorsAsMap[__${counsellor}__]}" th:value="true"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Bonus de jeu</legend>
|
||||
<label for="nightBonus">Bonus de nuit :</label>
|
||||
<input type="checkbox" id="nightBonus" th:field="*{nightBonus}" th:value="true"/><br/>
|
||||
</fieldset>
|
||||
|
||||
<input type="checkbox" th:id="'counsellor-'+${counsellor}" th:field="*{defCounsellorsAsMap[__${counsellor}__]}" th:value="true"/>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Paramètres</legend>
|
||||
|
||||
<label for="moralInput">Moral:</label>
|
||||
<input type="number" min="0" max="100" value="1" id="moralInput" th:field="*{moral}">
|
||||
<label for="luckInput">Chance:</label>
|
||||
<input type="number" min="-20" max="20" value="1" id="luckInput" th:field="*{luck}">
|
||||
<label for="breachInput">Percée:</label>
|
||||
<input type="checkbox" id="breachInput" th:field="*{strategyBreach}">
|
||||
<label for="allianceInput">Alliance:</label>
|
||||
<input type="checkbox" id="allianceInput" th:field="*{allianceModifier}">
|
||||
</fieldset>
|
||||
</fieldset>
|
||||
<fieldset class="formcol">
|
||||
<legend>Défense</legend>
|
||||
<fieldset id="herosFields">
|
||||
<legend>Héros</legend>
|
||||
<select name="defHeros" id="defHeros" th:field="*{defHero}">
|
||||
<option value="none">Aucun</option>
|
||||
<option th:each="hero : ${heroes}" th:value="${hero.id}"><span th:text="${hero.name}"/></option>
|
||||
</select>
|
||||
|
||||
<label for="heroLevelSlider">Niveau du héros: (<span id="heroLevelSliderInfo" class="fixed50px"></span>)</label>
|
||||
<input type="range" min="1" max="20" value="1" class="slider" id="heroLevelSlider" th:field="*{defHeroLevel}">
|
||||
|
||||
<script>
|
||||
var heroSlider = document.getElementById("heroLevelSlider");
|
||||
var heroOutput = document.getElementById("heroLevelSliderInfo");
|
||||
heroOutput.innerHTML = "lvl. "+heroSlider.value;
|
||||
// Update the current slider value (each time you drag the slider handle)
|
||||
heroSlider.oninput = function() {
|
||||
heroOutput.innerHTML = "lvl. "+this.value;
|
||||
}
|
||||
</script>
|
||||
</fieldset>
|
||||
<fieldset id="unitesFS">
|
||||
<legend>Unités</legend>
|
||||
<div th:each="unite : ${defUnits}" class="container">
|
||||
<img class="squareImage" th:for="'unite-'+${unite.id}" th:src="@{/images/units/{uname}.png(uname=${unite.id})}"/>
|
||||
<br/>
|
||||
<input type="number" class="squareNumber" th:id="'unite-'+${unite.id}" th:field="*{defUnits[__${unite.id}__]}"/>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Batiments</legend>
|
||||
<label for="hasTower">Tour :</label>
|
||||
<input type="checkbox" id="hasTower" th:field="*{hasTower}"/><br/>
|
||||
|
||||
<label for="wallLevelSlider">Niveau des remparts: (<span id="wallLevelSliderInfo" class="fixed50px"></span>)</label>
|
||||
<input type="range" min="0" max="25" value="1" class="slider" id="wallLevelSlider" th:field="*{wallLevel}">
|
||||
|
||||
<script>
|
||||
var wallSlider = document.getElementById("wallLevelSlider");
|
||||
var wallOutput = document.getElementById("wallLevelSliderInfo");
|
||||
wallOutput.innerHTML = "lvl. "+wallSlider.value;
|
||||
// Update the current slider value (each time you drag the slider handle)
|
||||
wallSlider.oninput = function() {
|
||||
wallOutput.innerHTML = "lvl. "+this.value;
|
||||
}
|
||||
</script>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Pouvoirs</legend>
|
||||
<div th:each="power : ${defPowers}" class="container">
|
||||
<img class="squareImage" th:for="'power-'+${power}" th:src="@{/images/powers/{pname}.png(pname=${power})}"/>
|
||||
<input type="checkbox" th:id="'power-'+${power}" th:field="*{defPowersAsMap[__${power}__]}" th:value="true"/>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Recherches</legend>
|
||||
<div th:each="research : ${defResearches}" class="container">
|
||||
<img class="squareImage" th:for="'research-'+${research}" th:src="@{/images/researches/{rname}.png(rname=${research})}"/>
|
||||
<input type="checkbox" th:id="'research-'+${research}" th:field="*{defResearchesAsMap[__${research}__]}" th:value="true"/>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Conseillers</legend>
|
||||
<div th:each="counsellor : ${defCounsellors}" class="container">
|
||||
<img class="squareImage" th:for="'counsellor-'+${counsellor}" th:src="@{/images/counsellors/{cname}.png(cname=${counsellor})}"/>
|
||||
<input type="checkbox" th:id="'counsellor-'+${counsellor}" th:field="*{defCounsellorsAsMap[__${counsellor}__]}" th:value="true"/>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Bonus de jeu</legend>
|
||||
<label for="nightBonus">Bonus de nuit :</label>
|
||||
<input type="checkbox" id="nightBonus" th:field="*{nightBonus}" th:value="true"/><br/>
|
||||
</fieldset>
|
||||
</fieldset>
|
||||
</div>
|
||||
<button type="button" id="compute">Calculer</button>
|
||||
</form>
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user