Added beginning of simulator
This commit is contained in:
parent
26d8058cf4
commit
6122aa1670
@ -27,6 +27,7 @@ dependencies {
|
|||||||
|
|
||||||
implementation 'org.yaml:snakeyaml:2.2'
|
implementation 'org.yaml:snakeyaml:2.2'
|
||||||
implementation 'org.ojalgo:ojalgo:54.0.0'
|
implementation 'org.ojalgo:ojalgo:54.0.0'
|
||||||
|
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.named('test') {
|
tasks.named('test') {
|
||||||
|
|||||||
@ -1,18 +1,58 @@
|
|||||||
package com.bernard.greposimu;
|
package com.bernard.greposimu;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.bernard.greposimu.engine.Registerar;
|
import com.bernard.greposimu.engine.Registerar;
|
||||||
|
import com.bernard.greposimu.engine.game.Buildings;
|
||||||
|
import com.bernard.greposimu.engine.json.MapJsonDeserializer;
|
||||||
import com.bernard.greposimu.model.Dieu;
|
import com.bernard.greposimu.model.Dieu;
|
||||||
import com.bernard.greposimu.model.Heros;
|
import com.bernard.greposimu.model.Heros;
|
||||||
import com.bernard.greposimu.model.OffDefStats;
|
import com.bernard.greposimu.model.OffDefStats;
|
||||||
|
import com.bernard.greposimu.model.game.GameData;
|
||||||
|
import com.fasterxml.jackson.core.JsonFactory;
|
||||||
|
import com.fasterxml.jackson.core.StreamReadFeature;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
|
|
||||||
public class GrepoSimu {
|
public class GrepoSimu {
|
||||||
|
|
||||||
|
public static GameData readGameData() throws IOException {
|
||||||
|
|
||||||
|
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
|
||||||
|
try (InputStream is = classLoader.getResourceAsStream("gamedata.json")) {
|
||||||
|
if (is == null) return null;
|
||||||
|
try (InputStreamReader isr = new InputStreamReader(is);
|
||||||
|
BufferedReader reader = new BufferedReader(isr)) {
|
||||||
|
// Reading the file
|
||||||
|
String json = reader.lines().collect(Collectors.joining(System.lineSeparator()));
|
||||||
|
|
||||||
|
// De-serialize to an object
|
||||||
|
JsonFactory jsonFactory = JsonFactory.builder()
|
||||||
|
.enable(StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION)
|
||||||
|
.build();
|
||||||
|
SimpleModule module = new SimpleModule();
|
||||||
|
module.addDeserializer(Map.class, new MapJsonDeserializer());
|
||||||
|
ObjectMapper mapper = new ObjectMapper(jsonFactory);
|
||||||
|
mapper.registerModule(module);
|
||||||
|
GameData data = mapper.readValue(json, GameData.class);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
for(int i=0;i<26;i++)
|
||||||
|
System.out.println(i+"->"+Buildings.wallBonus(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void mainZ(String[] args) {
|
||||||
Registerar.regiter();
|
Registerar.regiter();
|
||||||
|
|
||||||
System.out.println(Registerar.unites.size());
|
System.out.println(Registerar.unites.size());
|
||||||
|
|||||||
14
src/main/java/com/bernard/greposimu/ServletInitializer.java
Normal file
14
src/main/java/com/bernard/greposimu/ServletInitializer.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/*package com.bernard.greposimu;
|
||||||
|
|
||||||
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
|
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||||
|
|
||||||
|
public class ServletInitializer extends SpringBootServletInitializer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||||
|
return application.sources(GrepoSimuApplication.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
69
src/main/java/com/bernard/greposimu/Utils.java
Normal file
69
src/main/java/com/bernard/greposimu/Utils.java
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package com.bernard.greposimu;
|
||||||
|
|
||||||
|
import java.util.AbstractMap;
|
||||||
|
import java.util.AbstractSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class Utils {
|
||||||
|
|
||||||
|
public static final double poly5(double a0, double a1, double a2, double a3, double a4, double a5, double x) {
|
||||||
|
return
|
||||||
|
a0 +
|
||||||
|
a1 * x +
|
||||||
|
a2 * x * x +
|
||||||
|
a3 * x * x * x +
|
||||||
|
a4 * x * x * x * x +
|
||||||
|
a5 * x * x * x * x * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final <T> Map<T,Boolean> setToMap(Set<T> set){
|
||||||
|
return new AbstractMap<T,Boolean>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Entry<T, Boolean>> entrySet() {
|
||||||
|
return new AbstractSet<Map.Entry<T,Boolean>>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Entry<T, Boolean>> iterator() {
|
||||||
|
Iterator<T> it = set.iterator();
|
||||||
|
return new Iterator<Map.Entry<T,Boolean>>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return it.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Entry<T, Boolean> next() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return new AbstractMap.SimpleEntry<>(it.next(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return set.size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean put(T k, Boolean v) {
|
||||||
|
Boolean old = set.contains(k);
|
||||||
|
if(v != null && v)
|
||||||
|
set.add(k);
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,4 +1,7 @@
|
|||||||
package com.bernard.greposimu.controller;
|
package com.bernard.greposimu.controller;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -14,17 +17,68 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
|
||||||
|
import com.bernard.greposimu.GrepoSimu;
|
||||||
import com.bernard.greposimu.engine.Optimizer;
|
import com.bernard.greposimu.engine.Optimizer;
|
||||||
import com.bernard.greposimu.engine.Optimizer.UnitesProportions;
|
import com.bernard.greposimu.engine.Optimizer.UnitesProportions;
|
||||||
import com.bernard.greposimu.engine.Registerar;
|
import com.bernard.greposimu.engine.Registerar;
|
||||||
|
import com.bernard.greposimu.engine.game.Fight;
|
||||||
|
import com.bernard.greposimu.engine.game.Game;
|
||||||
|
import com.bernard.greposimu.model.DefContext;
|
||||||
import com.bernard.greposimu.model.Dieu;
|
import com.bernard.greposimu.model.Dieu;
|
||||||
|
import com.bernard.greposimu.model.FightStats;
|
||||||
import com.bernard.greposimu.model.Heros;
|
import com.bernard.greposimu.model.Heros;
|
||||||
import com.bernard.greposimu.model.OffDefStats;
|
import com.bernard.greposimu.model.OffDefStats;
|
||||||
import com.bernard.greposimu.model.Unite;
|
import com.bernard.greposimu.model.Unite;
|
||||||
|
import com.bernard.greposimu.model.game.GameData;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class GrepoSimuController {
|
public class GrepoSimuController {
|
||||||
|
|
||||||
|
@GetMapping("/gamedata")
|
||||||
|
public String gamedata(Model model) {
|
||||||
|
System.out.println("Reading game data");
|
||||||
|
GameData data;
|
||||||
|
try {
|
||||||
|
data = GrepoSimu.readGameData();
|
||||||
|
model.addAttribute("content",data.toString());
|
||||||
|
} catch (IOException e) {
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
e.printStackTrace(new PrintWriter(writer));
|
||||||
|
model.addAttribute("content",writer.toString());
|
||||||
|
}
|
||||||
|
return "debug";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/simulator")
|
||||||
|
public String simulator(Model model) throws IOException {
|
||||||
|
GameData data = GrepoSimu.readGameData();
|
||||||
|
model.addAttribute("heroes", data.heroes.values());
|
||||||
|
model.addAttribute("defUnits", Fight.relevantDefUnits(data));
|
||||||
|
model.addAttribute("defCounsellors",Fight.relevantDefCounsellors(data));
|
||||||
|
model.addAttribute("defResearches",Fight.relevantDefResearch(data));
|
||||||
|
model.addAttribute("defPowers",Fight.relevantDefPowers(data));
|
||||||
|
model.addAttribute("defCtx",new DefContext());
|
||||||
|
return "simulator";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/simulate")
|
||||||
|
@GetMapping("/simulate")
|
||||||
|
public String simulate(@ModelAttribute DefContext defCtx, Model model) throws IOException {
|
||||||
|
if(defCtx == null)
|
||||||
|
defCtx = new DefContext();
|
||||||
|
GameData data = GrepoSimu.readGameData();
|
||||||
|
Game g = new Game(data);
|
||||||
|
|
||||||
|
FightStats cityStats = g.fight.computeDefStats(defCtx);
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||||
|
|
||||||
|
model.addAttribute("content",cityStats.toString()+"\n"+mapper.writerWithDefaultPrettyPrinter().writeValueAsString(defCtx));
|
||||||
|
return "debug";
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/optimizer")
|
@GetMapping("/optimizer")
|
||||||
public String greeting(Model model) {
|
public String greeting(Model model) {
|
||||||
model.addAttribute("heros", Registerar.heros);
|
model.addAttribute("heros", Registerar.heros);
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
package com.bernard.greposimu.engine.game;
|
||||||
|
|
||||||
|
import com.bernard.greposimu.Utils;
|
||||||
|
import com.bernard.greposimu.model.FightStats;
|
||||||
|
|
||||||
|
public class Buildings {
|
||||||
|
|
||||||
|
Game g;
|
||||||
|
|
||||||
|
public Buildings(Game g) {
|
||||||
|
this.g = g;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FightStats cityBaseStats(int wallLevel) {
|
||||||
|
double value = 10.0+10.0*wallLevel;
|
||||||
|
return new FightStats(value, value, value, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FightStats wallBonus(int wallLevel) {
|
||||||
|
double value = (Math.pow(1.035, wallLevel)-1);
|
||||||
|
//TODO find exact value
|
||||||
|
value = Utils.poly5(0.0, 0.036679, 0.000528, 0.000011, 0.0, 0.0, wallLevel);
|
||||||
|
return new FightStats(value, value, value, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
124
src/main/java/com/bernard/greposimu/engine/game/Fight.java
Normal file
124
src/main/java/com/bernard/greposimu/engine/game/Fight.java
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package com.bernard.greposimu.engine.game;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.bernard.greposimu.model.DefContext;
|
||||||
|
import com.bernard.greposimu.model.FightStats;
|
||||||
|
import com.bernard.greposimu.model.OffContext;
|
||||||
|
import com.bernard.greposimu.model.game.GameData;
|
||||||
|
import com.bernard.greposimu.model.game.Power;
|
||||||
|
import com.bernard.greposimu.model.game.Research;
|
||||||
|
import com.bernard.greposimu.model.game.Unit;
|
||||||
|
|
||||||
|
public class Fight {
|
||||||
|
|
||||||
|
Game g;
|
||||||
|
|
||||||
|
public Fight(Game g) {
|
||||||
|
this.g = g;
|
||||||
|
}
|
||||||
|
public FightStats computeDefStats(DefContext def) {
|
||||||
|
|
||||||
|
|
||||||
|
FightStats everyoneStatsBonus = FightStats.zero();
|
||||||
|
Map<String,FightStats> unitsBonuses;
|
||||||
|
FightStats cityBaseStats;
|
||||||
|
|
||||||
|
// Heroes
|
||||||
|
unitsBonuses = g.heroes.heroFightBonuses(def.hero, def.heroLevel, false);
|
||||||
|
|
||||||
|
// Tower & wall
|
||||||
|
cityBaseStats = Buildings.cityBaseStats(def.wallLevel);
|
||||||
|
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, Buildings.wallBonus(def.wallLevel));
|
||||||
|
if(def.hasTower)
|
||||||
|
// Add 10% to all units
|
||||||
|
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.cst(0.1));
|
||||||
|
|
||||||
|
// Powers
|
||||||
|
|
||||||
|
//TODO powers
|
||||||
|
|
||||||
|
// Researches
|
||||||
|
if(def.counsellors.contains("divine_selection"))
|
||||||
|
for(String uid : g.data.units.keySet())
|
||||||
|
if(g.data.units.get(uid).isMythological())
|
||||||
|
unitsBonuses.put(uid, FightStats.add(unitsBonuses.getOrDefault(uid, FightStats.zero()), FightStats.cst(0.1)));
|
||||||
|
if(def.counsellors.contains("phalanx"))
|
||||||
|
for(String uid : g.data.units.keySet())
|
||||||
|
if(g.data.units.get(uid).isGround())
|
||||||
|
unitsBonuses.put(uid, FightStats.add(unitsBonuses.getOrDefault(uid, FightStats.zero()), FightStats.cst(0.1)));
|
||||||
|
if(def.counsellors.contains("ram"))
|
||||||
|
for(String uid : g.data.units.keySet())
|
||||||
|
if(g.data.units.get(uid).isNaval())
|
||||||
|
unitsBonuses.put(uid, FightStats.add(unitsBonuses.getOrDefault(uid, FightStats.zero()), FightStats.cst(0.1)));
|
||||||
|
|
||||||
|
// Counsellors
|
||||||
|
if(def.counsellors.contains("priest"))
|
||||||
|
for(String uid : g.data.units.keySet())
|
||||||
|
if(g.data.units.get(uid).isMythological())
|
||||||
|
unitsBonuses.put(uid, FightStats.add(unitsBonuses.getOrDefault(uid, FightStats.zero()), FightStats.cst(0.2)));
|
||||||
|
if(def.counsellors.contains("commander"))
|
||||||
|
for(String uid : g.data.units.keySet())
|
||||||
|
if(g.data.units.get(uid).isGround())
|
||||||
|
unitsBonuses.put(uid, FightStats.add(unitsBonuses.getOrDefault(uid, FightStats.zero()), FightStats.cst(0.2)));
|
||||||
|
if(def.counsellors.contains("captain"))
|
||||||
|
for(String uid : g.data.units.keySet())
|
||||||
|
if(g.data.units.get(uid).isNaval())
|
||||||
|
unitsBonuses.put(uid, FightStats.add(unitsBonuses.getOrDefault(uid, FightStats.zero()), FightStats.cst(0.2)));
|
||||||
|
|
||||||
|
// Night Bonus
|
||||||
|
if(def.nightBonus)
|
||||||
|
everyoneStatsBonus = FightStats.add(everyoneStatsBonus, FightStats.cst(1.0));
|
||||||
|
|
||||||
|
// Units
|
||||||
|
FightStats total = cityBaseStats.clone();
|
||||||
|
for(Unit u : g.data.units.values()) {
|
||||||
|
// total = total + ucount * ((1+bonus+bonus) * ustats)
|
||||||
|
if(def.units.containsKey(u.id) && def.units.get(u.id) != null)
|
||||||
|
total = FightStats.add(total,
|
||||||
|
FightStats.prod(def.units.get(u.id),
|
||||||
|
FightStats.mul(
|
||||||
|
FightStats.add(FightStats.one(),everyoneStatsBonus,unitsBonuses.getOrDefault(u.id, FightStats.zero()))
|
||||||
|
, u.getDefStats())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Power> relevantDefPowers(GameData 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","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")
|
||||||
|
.stream().map(gd.powers::get).toList();
|
||||||
|
}
|
||||||
|
public static List<Research> relevantDefResearch(GameData gd) {
|
||||||
|
return List.of("divine_selection","phalanx","ram")
|
||||||
|
.stream().map(gd.researches::get).toList();
|
||||||
|
}
|
||||||
|
public static List<Unit> relevantDefUnits(GameData data) {
|
||||||
|
return data.units.values().stream().toList();
|
||||||
|
}
|
||||||
|
public static List<String> relevantDefCounsellors(GameData data) {
|
||||||
|
return List.of("priest","commander","captain");
|
||||||
|
}
|
||||||
|
public FightStats computeOffStats(DefContext off) {
|
||||||
|
//TODO computeOffStats
|
||||||
|
throw new UnsupportedOperationException("Simulator not created");
|
||||||
|
}
|
||||||
|
|
||||||
|
public FightResult simulateFight(OffContext off, DefContext def) {
|
||||||
|
//TODO simulateFight
|
||||||
|
throw new UnsupportedOperationException("Simulator not created");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FightResult {
|
||||||
|
|
||||||
|
Map<String, Integer> def_losses;
|
||||||
|
Map<String, Integer> att_losses;
|
||||||
|
int wall_loss;
|
||||||
|
int att_battle_points;
|
||||||
|
int def_battle_points;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
20
src/main/java/com/bernard/greposimu/engine/game/Game.java
Normal file
20
src/main/java/com/bernard/greposimu/engine/game/Game.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package com.bernard.greposimu.engine.game;
|
||||||
|
|
||||||
|
import com.bernard.greposimu.model.game.GameData;
|
||||||
|
|
||||||
|
public class Game {
|
||||||
|
|
||||||
|
GameData data;
|
||||||
|
public Heroes heroes;
|
||||||
|
public Buildings buildings;
|
||||||
|
public Fight fight;
|
||||||
|
|
||||||
|
|
||||||
|
public Game(GameData data) {
|
||||||
|
this.data = data;
|
||||||
|
this.heroes = new Heroes(this);
|
||||||
|
this.buildings = new Buildings(this);
|
||||||
|
this.fight = new Fight(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
119
src/main/java/com/bernard/greposimu/engine/game/Heroes.java
Normal file
119
src/main/java/com/bernard/greposimu/engine/game/Heroes.java
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
package com.bernard.greposimu.engine.game;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.bernard.greposimu.model.FightStats;
|
||||||
|
import com.bernard.greposimu.model.game.Hero;
|
||||||
|
|
||||||
|
public class Heroes {
|
||||||
|
|
||||||
|
Game g;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public Heroes(Game g) {
|
||||||
|
this.g = g;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the bonus applied to each unit
|
||||||
|
* @param hero The uid of the hero
|
||||||
|
* @param level The level of the hero
|
||||||
|
* @param off true for the off stat, false for the def stat
|
||||||
|
* @return For each unit, the bonus that should be applied to it
|
||||||
|
*/
|
||||||
|
public Map<String,FightStats> heroFightBonuses(String hero, int level, boolean off){
|
||||||
|
|
||||||
|
Map<String,FightStats> bonuses = new HashMap<>();
|
||||||
|
|
||||||
|
if(hero == null)
|
||||||
|
return new HashMap<>();
|
||||||
|
|
||||||
|
double bonus = 0.0;
|
||||||
|
Hero heroD = g.data.heroes.get(hero);
|
||||||
|
if(heroD != null && heroD.description_args != null && heroD.description_args.containsKey("1")) {
|
||||||
|
Hero.DescriptionArgs args = heroD.description_args.get("1");
|
||||||
|
if(args.unit.equals("%"))
|
||||||
|
bonus = args.value + level * args.level_mod;
|
||||||
|
else
|
||||||
|
throw new UnsupportedOperationException("I don't know about unit "+args.unit);
|
||||||
|
}
|
||||||
|
FightStats appliedBonus = null;
|
||||||
|
switch(hero) {
|
||||||
|
case "agamemnon":
|
||||||
|
appliedBonus = FightStats.terrestre(bonus);
|
||||||
|
bonuses.put("hoplite", appliedBonus);
|
||||||
|
bonuses.put("archer", appliedBonus);
|
||||||
|
break;
|
||||||
|
case "ajax":
|
||||||
|
appliedBonus = FightStats.terrestre(bonus);
|
||||||
|
bonuses.put("hoplites", appliedBonus);
|
||||||
|
break;
|
||||||
|
case "alexandrios":
|
||||||
|
appliedBonus = FightStats.terrestre(bonus);
|
||||||
|
bonuses.put("archers", appliedBonus);
|
||||||
|
break;
|
||||||
|
case "deimos":
|
||||||
|
appliedBonus = FightStats.cst(bonus);
|
||||||
|
if(off)
|
||||||
|
for(String uid : g.data.units.keySet())bonuses.put(uid,appliedBonus);
|
||||||
|
break;
|
||||||
|
case "hector":
|
||||||
|
appliedBonus = FightStats.terrestre(bonus);
|
||||||
|
bonuses.put("sword", appliedBonus);
|
||||||
|
bonuses.put("slinger", appliedBonus);
|
||||||
|
break;
|
||||||
|
case "lysippe":
|
||||||
|
appliedBonus = FightStats.terrestre(bonus);
|
||||||
|
bonuses.put("rider", appliedBonus);
|
||||||
|
break;
|
||||||
|
case "leonidas":
|
||||||
|
appliedBonus = FightStats.terrestre(bonus);
|
||||||
|
if(!off)
|
||||||
|
for(String uid : g.data.units.keySet())bonuses.put(uid,appliedBonus);
|
||||||
|
break;
|
||||||
|
case "mihalis":
|
||||||
|
appliedBonus = new FightStats(bonus, bonus, 0.0, 0.0);
|
||||||
|
for(String uid : g.data.units.keySet())bonuses.put(uid,appliedBonus);
|
||||||
|
break;
|
||||||
|
case "medea":
|
||||||
|
appliedBonus = FightStats.terrestre(bonus);
|
||||||
|
bonuses.put("slinger", appliedBonus);
|
||||||
|
break;
|
||||||
|
case "melousa":
|
||||||
|
appliedBonus = FightStats.terrestre(bonus);
|
||||||
|
bonuses.put("chariot", appliedBonus);
|
||||||
|
break;
|
||||||
|
case "pelops":
|
||||||
|
appliedBonus = FightStats.terrestre(bonus);
|
||||||
|
bonuses.put("hoplite", appliedBonus);
|
||||||
|
bonuses.put("chariot", appliedBonus);
|
||||||
|
break;
|
||||||
|
case "themistokles":
|
||||||
|
appliedBonus = FightStats.terrestre(bonus);
|
||||||
|
bonuses.put("godsent", appliedBonus);
|
||||||
|
bonuses.put("rider", appliedBonus);
|
||||||
|
break;
|
||||||
|
case "telemachos":
|
||||||
|
appliedBonus = FightStats.terrestre(bonus);
|
||||||
|
bonuses.put("sword", appliedBonus);
|
||||||
|
break;
|
||||||
|
case "urephon":
|
||||||
|
appliedBonus = FightStats.terrestre(bonus);
|
||||||
|
for(String uid : g.data.units.keySet())if(g.data.units.get(uid).isMythological())bonuses.put(uid,appliedBonus);
|
||||||
|
break;
|
||||||
|
case "zuretha":
|
||||||
|
appliedBonus = new FightStats(0.0, 0.0, 0.0, bonus);
|
||||||
|
for(String uid : g.data.units.keySet())bonuses.put(uid,appliedBonus);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// No buff
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return bonuses;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
package com.bernard.greposimu.engine.json;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.core.ObjectCodec;
|
||||||
|
import com.fasterxml.jackson.databind.BeanProperty;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.JavaType;
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
|
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
|
||||||
|
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
|
||||||
|
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
|
||||||
|
|
||||||
|
public class MapJsonDeserializer extends StdDeserializer<Map<String,?>> implements ContextualDeserializer{
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -888029778299077908L;
|
||||||
|
private JavaType type;
|
||||||
|
|
||||||
|
public MapJsonDeserializer() {
|
||||||
|
super(Object.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException{
|
||||||
|
MapJsonDeserializer deserializer = new MapJsonDeserializer();
|
||||||
|
if(property != null)
|
||||||
|
deserializer.type = property.getType().containedType(1);
|
||||||
|
else
|
||||||
|
deserializer.type = ctxt.getContextualType();
|
||||||
|
return deserializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String,?> deserialize(JsonParser parser, DeserializationContext deserializationContext) throws IOException {
|
||||||
|
JsonNode node = parser.getCodec().readTree(parser);
|
||||||
|
if(node.isNull() || (node.isArray() && node.isEmpty()))
|
||||||
|
return new HashMap<>();
|
||||||
|
else if(node.isObject()) {
|
||||||
|
ObjectCodec codec = parser.getCodec();
|
||||||
|
Map<String,Object> output = new HashMap<>();
|
||||||
|
java.util.Iterator<Entry<String, JsonNode>> it = node.fields();
|
||||||
|
while(it.hasNext()) {
|
||||||
|
Entry<String, JsonNode> entry = it.next();
|
||||||
|
output.put(entry.getKey(), entry.getValue().traverse(codec).readValueAs(this.type.getRawClass()));
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
} else
|
||||||
|
throw MismatchedInputException.from(parser, Map.class, "JSON is neither an empty array nor a map");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
118
src/main/java/com/bernard/greposimu/model/DefContext.java
Normal file
118
src/main/java/com/bernard/greposimu/model/DefContext.java
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
package com.bernard.greposimu.model;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.bernard.greposimu.Utils;
|
||||||
|
|
||||||
|
public class DefContext {
|
||||||
|
// unitID -> number of units
|
||||||
|
public Map<String, Integer> units;
|
||||||
|
|
||||||
|
public String hero;
|
||||||
|
public int heroLevel;
|
||||||
|
|
||||||
|
public int wallLevel;
|
||||||
|
public boolean hasTower;
|
||||||
|
|
||||||
|
public Set<String> powers;
|
||||||
|
public Set<String> researches;
|
||||||
|
|
||||||
|
public Set<String> counsellors;
|
||||||
|
|
||||||
|
public boolean nightBonus;
|
||||||
|
|
||||||
|
public DefContext() {
|
||||||
|
this.units = new HashMap<>();
|
||||||
|
this.hero = null;
|
||||||
|
this.heroLevel = 0;
|
||||||
|
this.wallLevel = 0;
|
||||||
|
this.hasTower = false;
|
||||||
|
this.powers = new HashSet<>();
|
||||||
|
this.researches = new HashSet<>();
|
||||||
|
this.counsellors = new HashSet<>();
|
||||||
|
this.nightBonus = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Integer> getUnits() {
|
||||||
|
return units;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHero() {
|
||||||
|
return hero;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeroLevel() {
|
||||||
|
return heroLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWallLevel() {
|
||||||
|
return wallLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHasTower() {
|
||||||
|
return hasTower;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getPowers() {
|
||||||
|
return powers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getResearches() {
|
||||||
|
return researches;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getCounsellors() {
|
||||||
|
return counsellors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Boolean> getPowersAsMap() {
|
||||||
|
return Utils.setToMap(powers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Boolean> getResearchesAsMap() {
|
||||||
|
return Utils.setToMap(researches);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Boolean> getCounsellorsAsMap() {
|
||||||
|
return Utils.setToMap(counsellors);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNightBonus() {
|
||||||
|
return nightBonus;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void setHero(String hero) {
|
||||||
|
this.hero = hero;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeroLevel(int heroLevel) {
|
||||||
|
this.heroLevel = heroLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWallLevel(int wallLevel) {
|
||||||
|
this.wallLevel = wallLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHasTower(boolean hasTower) {
|
||||||
|
this.hasTower = hasTower;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNightBonus(boolean nightBonus) {
|
||||||
|
this.nightBonus = nightBonus;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "DefContext [units=" + units + ", heros=" + hero + ", herosLevel=" + heroLevel + ", wallLevel="
|
||||||
|
+ wallLevel + ", hasTower=" + hasTower + ", powers=" + powers + ", researches=" + researches
|
||||||
|
+ ", counsellors=" + counsellors + ", nightBonus=" + nightBonus + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
63
src/main/java/com/bernard/greposimu/model/FightStats.java
Normal file
63
src/main/java/com/bernard/greposimu/model/FightStats.java
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package com.bernard.greposimu.model;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class FightStats implements Cloneable{
|
||||||
|
public double hack;
|
||||||
|
public double pierce;
|
||||||
|
public double distance;
|
||||||
|
public double ship;
|
||||||
|
|
||||||
|
public FightStats(double hack, double pierce, double distance, double ship) {
|
||||||
|
this.hack = hack;
|
||||||
|
this.pierce = pierce;
|
||||||
|
this.distance = distance;
|
||||||
|
this.ship = ship;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final FightStats zero() {
|
||||||
|
return new FightStats(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final FightStats one() {
|
||||||
|
return new FightStats(1.0, 1.0, 1.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final FightStats terrestre(double value) {
|
||||||
|
return new FightStats(value, value, value, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final FightStats cst(double value) {
|
||||||
|
return new FightStats(value, value, value, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final FightStats add(FightStats a,FightStats b) {
|
||||||
|
return new FightStats(a.hack + b.hack, a.pierce + b.pierce, a.distance + b.distance, a.ship + b.ship);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final FightStats add(FightStats... arr) {
|
||||||
|
return Arrays.stream(arr).reduce(FightStats.zero(), FightStats::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final FightStats sub(FightStats a,FightStats b) {
|
||||||
|
return new FightStats(a.hack - b.hack, a.pierce - b.pierce, a.distance - b.distance, a.ship - b.ship);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final FightStats mul(FightStats a,FightStats b) {
|
||||||
|
return new FightStats(a.hack * b.hack, a.pierce * b.pierce, a.distance * b.distance, a.ship * b.ship);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final FightStats prod(int k,FightStats b) {
|
||||||
|
return new FightStats(k * b.hack, k * b.pierce, k * b.distance, k * b.ship);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FightStats clone() {
|
||||||
|
return new FightStats(hack, pierce, distance, ship);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "(%.4f,%.4f,%.4f,%.4f)".formatted(hack,pierce,distance,ship);
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/main/java/com/bernard/greposimu/model/OffContext.java
Normal file
23
src/main/java/com/bernard/greposimu/model/OffContext.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package com.bernard.greposimu.model;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class OffContext {
|
||||||
|
// unitID -> number of units
|
||||||
|
public Map<String, Integer> units;
|
||||||
|
|
||||||
|
public String heros;
|
||||||
|
public int herosLevel;
|
||||||
|
|
||||||
|
public int luck;
|
||||||
|
public int morale;
|
||||||
|
|
||||||
|
public Set<String> powers;
|
||||||
|
public Set<String> researches;
|
||||||
|
|
||||||
|
public Set<String> counsellors;
|
||||||
|
|
||||||
|
public boolean strategy_breach;
|
||||||
|
public boolean alliance_modifier;
|
||||||
|
}
|
||||||
53
src/main/java/com/bernard/greposimu/model/game/Building.java
Normal file
53
src/main/java/com/bernard/greposimu/model/game/Building.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package com.bernard.greposimu.model.game;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Building {
|
||||||
|
public String id;
|
||||||
|
public String name;
|
||||||
|
public String controller;
|
||||||
|
public Object image;
|
||||||
|
public String description;
|
||||||
|
public Object level;
|
||||||
|
public int max_level;
|
||||||
|
public int min_level;
|
||||||
|
public Object requiredBuildings;
|
||||||
|
public String coordinates;
|
||||||
|
public Resources resources;
|
||||||
|
public int pop;
|
||||||
|
public double wood_factor;
|
||||||
|
public double stone_factor;
|
||||||
|
public double iron_factor;
|
||||||
|
public double pop_factor;
|
||||||
|
public Object hide_factor;
|
||||||
|
public int points;
|
||||||
|
public double points_factor;
|
||||||
|
public int build_time;
|
||||||
|
public double build_time_factor;
|
||||||
|
public double build_time_reduction;
|
||||||
|
public Object bolt_protected;
|
||||||
|
public List<Integer> image_levels;
|
||||||
|
public Map<String,Integer> dependencies;
|
||||||
|
public Map<Integer,Integer> fixed_building_times;
|
||||||
|
public Map<Integer, LeveledFactor> level_build_time_factors;
|
||||||
|
public boolean special;
|
||||||
|
public Object resourcesFor;
|
||||||
|
public List<Object> resourcesForLevelFixed;
|
||||||
|
public Map<Integer, Double> resourcesForLevelFactor;
|
||||||
|
public List<Object> resourcesForLevelReduceFactor;
|
||||||
|
public List<Object> offset_value_map;
|
||||||
|
public double catapult_factor;
|
||||||
|
public double catapult_power;
|
||||||
|
public double def_factor_per_level;
|
||||||
|
public double storage_factor;
|
||||||
|
public double storage_pow;
|
||||||
|
public double farm_pow;
|
||||||
|
public double farm_factor;
|
||||||
|
public double thermal_pow;
|
||||||
|
|
||||||
|
public static class LeveledFactor {
|
||||||
|
public int level;
|
||||||
|
public double factor;
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/main/java/com/bernard/greposimu/model/game/GameData.java
Normal file
37
src/main/java/com/bernard/greposimu/model/game/GameData.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package com.bernard.greposimu.model.game;
|
||||||
|
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.yaml.snakeyaml.DumperOptions;
|
||||||
|
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
|
||||||
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class GameData {
|
||||||
|
|
||||||
|
public Map<String,Unit> units;
|
||||||
|
|
||||||
|
public Map<String, Power> powers;
|
||||||
|
|
||||||
|
public Map<String, God> gods;
|
||||||
|
|
||||||
|
public Map<String, Hero> heroes;
|
||||||
|
|
||||||
|
public Map<String, Research> researches;
|
||||||
|
|
||||||
|
public Map<String, Building> buildings;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
DumperOptions options = new DumperOptions();
|
||||||
|
options.setDefaultFlowStyle(FlowStyle.BLOCK);
|
||||||
|
options.setPrettyFlow(true);
|
||||||
|
Yaml yaml = new Yaml(options);
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
yaml.dump(this, writer);
|
||||||
|
return writer.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/main/java/com/bernard/greposimu/model/game/God.java
Normal file
12
src/main/java/com/bernard/greposimu/model/game/God.java
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package com.bernard.greposimu.model.game;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class God {
|
||||||
|
public String name;
|
||||||
|
public String id;
|
||||||
|
public List<Unit> units;
|
||||||
|
public List<String> powers;
|
||||||
|
public String topic;
|
||||||
|
public String description;
|
||||||
|
}
|
||||||
36
src/main/java/com/bernard/greposimu/model/game/Hero.java
Normal file
36
src/main/java/com/bernard/greposimu/model/game/Hero.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package com.bernard.greposimu.model.game;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Hero {
|
||||||
|
public String id;
|
||||||
|
public String category;
|
||||||
|
public String name;
|
||||||
|
public String description;
|
||||||
|
public Map<String,DescriptionArgs> description_args;
|
||||||
|
public String short_description;
|
||||||
|
public int default_level;
|
||||||
|
public int cost;
|
||||||
|
public List<Object> award_requirements;
|
||||||
|
public boolean is_naval;
|
||||||
|
public boolean exclusive;
|
||||||
|
public boolean hidden;
|
||||||
|
public String attack_type;
|
||||||
|
public int attack;
|
||||||
|
public int def_hack;
|
||||||
|
public int def_pierce;
|
||||||
|
public int def_distance;
|
||||||
|
public int speed;
|
||||||
|
public int booty;
|
||||||
|
public List<Object> preconditions;
|
||||||
|
public int max_per_attack;
|
||||||
|
public int max_per_support;
|
||||||
|
|
||||||
|
public static class DescriptionArgs {
|
||||||
|
public double value;
|
||||||
|
public double level_mod;
|
||||||
|
public String unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package com.bernard.greposimu.model.game;
|
||||||
|
|
||||||
|
public class Image {
|
||||||
|
public String mini;
|
||||||
|
public String small;
|
||||||
|
public String medium;
|
||||||
|
public String large;
|
||||||
|
}
|
||||||
48
src/main/java/com/bernard/greposimu/model/game/Power.java
Normal file
48
src/main/java/com/bernard/greposimu/model/game/Power.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package com.bernard.greposimu.model.game;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Power {
|
||||||
|
public Object effect;
|
||||||
|
public int lifetime;
|
||||||
|
public String id;
|
||||||
|
public Object name;
|
||||||
|
public Object description;
|
||||||
|
public String short_effect;
|
||||||
|
public int favor;
|
||||||
|
public int fury_percentage_cost;
|
||||||
|
public String god_id;
|
||||||
|
public BigInteger temple_level_sum_dependency;
|
||||||
|
public List<String> targets;
|
||||||
|
public boolean only_own_towns;
|
||||||
|
public boolean boost;
|
||||||
|
public boolean is_fake_power;
|
||||||
|
public List<Object> area_of_effect;
|
||||||
|
public boolean destructive;
|
||||||
|
public boolean negative;
|
||||||
|
public boolean extendible;
|
||||||
|
public String power_group;
|
||||||
|
public int power_group_level;
|
||||||
|
public List<String> seeds_to;
|
||||||
|
public Image images;
|
||||||
|
public List<String> effects;
|
||||||
|
public boolean is_valid_for_happenings;
|
||||||
|
public List<String> meta_fields;
|
||||||
|
public Object meta_defaults;
|
||||||
|
public boolean removed_on_target_loss;
|
||||||
|
public boolean needs_level;
|
||||||
|
public boolean requires_god;
|
||||||
|
public boolean ignores_democritus;
|
||||||
|
public boolean display_amount;
|
||||||
|
public boolean wasteable;
|
||||||
|
public boolean is_ritual;
|
||||||
|
public boolean recreate_on_restart;
|
||||||
|
public boolean transfer_to_casual_world;
|
||||||
|
public boolean is_onetime_power;
|
||||||
|
public boolean is_upgradable;
|
||||||
|
public boolean is_capped;
|
||||||
|
public List<String> compatible_powers;
|
||||||
|
public boolean no_lifetime;
|
||||||
|
public boolean passive;
|
||||||
|
}
|
||||||
15
src/main/java/com/bernard/greposimu/model/game/Research.java
Normal file
15
src/main/java/com/bernard/greposimu/model/game/Research.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package com.bernard.greposimu.model.game;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Research {
|
||||||
|
public String id;
|
||||||
|
public String name;
|
||||||
|
public String description;
|
||||||
|
public List<Object> research_dependencies;
|
||||||
|
public Map<String,Integer> building_dependencies;
|
||||||
|
public Resources resources;
|
||||||
|
public int required_time;
|
||||||
|
public int research_points;
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package com.bernard.greposimu.model.game;
|
||||||
|
|
||||||
|
public class Resources {
|
||||||
|
public int wood;
|
||||||
|
public int stone;
|
||||||
|
public int iron;
|
||||||
|
}
|
||||||
70
src/main/java/com/bernard/greposimu/model/game/Unit.java
Normal file
70
src/main/java/com/bernard/greposimu/model/game/Unit.java
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package com.bernard.greposimu.model.game;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.bernard.greposimu.model.FightStats;
|
||||||
|
|
||||||
|
public class Unit {
|
||||||
|
|
||||||
|
public String id;
|
||||||
|
public String name;
|
||||||
|
public String name_plural;
|
||||||
|
public int speed;
|
||||||
|
public int attack;
|
||||||
|
public String description;
|
||||||
|
public Resources resources;
|
||||||
|
public int favor;
|
||||||
|
public int population;
|
||||||
|
public int build_time;
|
||||||
|
public String god_id;
|
||||||
|
public List<String> research_dependencies;
|
||||||
|
public Map<String, Integer> building_dependencies;
|
||||||
|
public boolean is_naval;
|
||||||
|
public int max_per_attack;
|
||||||
|
public int max_per_support;
|
||||||
|
public String unit_function;
|
||||||
|
public String category;
|
||||||
|
public List<Object> special_abilities;
|
||||||
|
public String passive;
|
||||||
|
public boolean is_npc_unit_only;
|
||||||
|
public int def_hack;
|
||||||
|
public int def_pierce;
|
||||||
|
public int def_distance;
|
||||||
|
public int booty;
|
||||||
|
public Object infantry;
|
||||||
|
public boolean flying;
|
||||||
|
public String attack_type;
|
||||||
|
|
||||||
|
// Naval
|
||||||
|
public int defense;
|
||||||
|
public boolean transport;
|
||||||
|
public int capacity;
|
||||||
|
|
||||||
|
public FightStats getDefStats() {
|
||||||
|
return new FightStats(def_hack, def_pierce, def_distance, defense);
|
||||||
|
}
|
||||||
|
public FightStats getAttStats() {
|
||||||
|
switch(attack_type) {
|
||||||
|
case "hack":
|
||||||
|
return new FightStats(attack, 0.0, 0.0, 0.0);
|
||||||
|
case "pierce":
|
||||||
|
return new FightStats(0.0, attack, 0.0, 0.0);
|
||||||
|
case "distance":
|
||||||
|
return new FightStats(0.0, 0.0, attack, 0.0);
|
||||||
|
}
|
||||||
|
if(is_naval)
|
||||||
|
return new FightStats(0.0, 0.0, 0.0, attack);
|
||||||
|
throw new IllegalStateException("This unit has no known attack type, and is not a ship");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMythological() {
|
||||||
|
return category.equals("mythological_ground") || category.equals("mythological_naval");
|
||||||
|
}
|
||||||
|
public boolean isGround() {
|
||||||
|
return category.equals("regular_ground") || category.equals("mythological_ground");
|
||||||
|
}
|
||||||
|
public boolean isNaval() {
|
||||||
|
return category.equals("regular_naval") || category.equals("mythological_naval");
|
||||||
|
}
|
||||||
|
}
|
||||||
33180
src/main/resources/gamedata.json
Normal file
33180
src/main/resources/gamedata.json
Normal file
File diff suppressed because it is too large
Load Diff
21
src/main/resources/templates/debug.html
Normal file
21
src/main/resources/templates/debug.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||||
|
<meta name="description" content="Simulation du MMO Grepolis">
|
||||||
|
|
||||||
|
<title>GrepoSimu - Debug</title>
|
||||||
|
|
||||||
|
<link rel="shortcut icon" th:href="@{/favicon.ico}" type="image/x-icon">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #ffecc3;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre th:text="${content}"></pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
233
src/main/resources/templates/simulator.html
Normal file
233
src/main/resources/templates/simulator.html
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||||
|
<meta name="description" content="Simulation du MMO Grepolis">
|
||||||
|
|
||||||
|
<title>GrepoSimu</title>
|
||||||
|
|
||||||
|
<link rel="shortcut icon" th:href="@{/favicon.ico}" type="image/x-icon">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #ffecc3;
|
||||||
|
}
|
||||||
|
.squareImage {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
.squareNumber {
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
.slider {
|
||||||
|
-webkit-appearance: none; /* Override default CSS styles */
|
||||||
|
appearance: none;
|
||||||
|
width: 276px; /* Full-width */
|
||||||
|
height: 8px; /* Specified height */
|
||||||
|
background-image: url("[[@{/images/slider3.png}]]"); /* Grey background */
|
||||||
|
outline: none; /* Remove outline */
|
||||||
|
}
|
||||||
|
.slider::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none; /* Override default look */
|
||||||
|
appearance: none;
|
||||||
|
width: 18px; /* Set a specific slider handle width */
|
||||||
|
height: 18px; /* Slider handle height */
|
||||||
|
background-image: url("[[@{/images/sliderButton.png}]]"); /* Grey background */
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider::-moz-range-thumb {
|
||||||
|
width: 18px; /* Set a specific slider handle width */
|
||||||
|
height: 18px; /* Slider handle height */
|
||||||
|
background-image: url("[[@{/images/sliderButton.png}]]"); /* Grey background */
|
||||||
|
}
|
||||||
|
|
||||||
|
span.fixed50px {
|
||||||
|
width: 50px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.parameters-selection {
|
||||||
|
display: flex;
|
||||||
|
column-gap: 0px
|
||||||
|
}
|
||||||
|
.small-number-selection {
|
||||||
|
border: 2px solid #e1af55;
|
||||||
|
background: #ffe2a1;
|
||||||
|
display: inline-flex;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.numbered-unit {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #CCCCCC;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.numbered-unit span {
|
||||||
|
width: 50px;
|
||||||
|
color: #000000;
|
||||||
|
float: left;
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
padding-top: 26px;
|
||||||
|
text-align: right;
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 1px 1px 0 #000;
|
||||||
|
font-family: Verdana;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.numbered-unit img {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border: 0px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<form action="#" th:object="${defCtx}" 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">
|
||||||
|
<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">
|
||||||
|
<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"/>
|
||||||
|
</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">
|
||||||
|
<img class="squareImage" th:for="'counsellor-'+${counsellor}" th:src="@{/images/counsellor/{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>
|
||||||
|
|
||||||
|
<button type="button" id="compute">Calculer</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<section id="result">
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function computeResults() {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("POST", "[[@{/simulate}]]");
|
||||||
|
xhr.onload = function(event){
|
||||||
|
document.getElementById("result").innerHTML = event.target.response
|
||||||
|
};
|
||||||
|
// or onerror, onabort
|
||||||
|
var formData = new FormData(document.getElementById("simuform"));
|
||||||
|
xhr.send(formData);
|
||||||
|
}
|
||||||
|
document.getElementById("compute").addEventListener('click',computeResults)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
@ -1,5 +1,7 @@
|
|||||||
package com.bernard.greposimu;
|
package com.bernard.greposimu;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
@ -7,7 +9,9 @@ import org.springframework.boot.test.context.SpringBootTest;
|
|||||||
class GrepoSimuApplicationTests {
|
class GrepoSimuApplicationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void contextLoads() {
|
void loadGameData() throws IOException {
|
||||||
|
// System.out.println("Reading game data");
|
||||||
|
// System.out.println(GrepoSimu.readGameData());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user