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.ojalgo:ojalgo:54.0.0'
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1'
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
|
||||
@ -1,18 +1,58 @@
|
||||
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.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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.Heros;
|
||||
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 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) {
|
||||
for(int i=0;i<26;i++)
|
||||
System.out.println(i+"->"+Buildings.wallBonus(i));
|
||||
}
|
||||
|
||||
public static void mainZ(String[] args) {
|
||||
Registerar.regiter();
|
||||
|
||||
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;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
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.PostMapping;
|
||||
|
||||
import com.bernard.greposimu.GrepoSimu;
|
||||
import com.bernard.greposimu.engine.Optimizer;
|
||||
import com.bernard.greposimu.engine.Optimizer.UnitesProportions;
|
||||
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.FightStats;
|
||||
import com.bernard.greposimu.model.Heros;
|
||||
import com.bernard.greposimu.model.OffDefStats;
|
||||
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
|
||||
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")
|
||||
public String greeting(Model model) {
|
||||
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;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@ -7,7 +9,9 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
class GrepoSimuApplicationTests {
|
||||
|
||||
@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