diff --git a/src/main/java/legends/model/HistoricalFigure.java b/src/main/java/legends/model/HistoricalFigure.java index da3d59c..47e34de 100644 --- a/src/main/java/legends/model/HistoricalFigure.java +++ b/src/main/java/legends/model/HistoricalFigure.java @@ -110,10 +110,10 @@ public class HistoricalFigure extends AbstractObject { private int kills = 0; @Xml(value = "intrigue_actor", elementClass = IntrigueActor.class, multiple = true) - private List intrigueActors = new ArrayList<>(); + private List intrigueActors = new ArrayList<>(); @Xml(value = "intrigue_plot", elementClass = IntriguePlot.class, multiple = true) - private List intriguePlots = new ArrayList<>(); + private List intriguePlots = new ArrayList<>(); private static HistoricalFigure context = null; @@ -539,11 +539,11 @@ public void addKill() { this.kills++; } - public List getIntrigueActors() { + public List getIntrigueActors() { return intrigueActors; } - public List getIntriguePlots() { + public List getIntriguePlots() { return intriguePlots; } diff --git a/src/main/java/legends/web/HfsController.java b/src/main/java/legends/web/HfsController.java index e9db0d8..418fcac 100644 --- a/src/main/java/legends/web/HfsController.java +++ b/src/main/java/legends/web/HfsController.java @@ -16,6 +16,7 @@ import legends.helper.EventHelper; import legends.helper.Templates; import legends.model.HistoricalFigure; +import legends.model.IntrigueActor; import legends.model.World; import legends.model.events.HfDoesInteractionEvent; import legends.model.events.basic.Filters; @@ -116,10 +117,14 @@ public Template hf(VelocityContext context, int id) { HistoricalFigure.setContext(hf); context.put("hf", hf); - context.put("family", new Family(hf, false)); + context.put("family", new Family(hf, 0)); if (hf.isWerebeast()) { - context.put("curse", new Family(hf, true)); + context.put("curse", new Family(hf, 1)); + } + + if (!hf.getIntrigueActors().isEmpty()) { + context.put("villain", new Family(hf, 2)); } context.put("events", World.getHistoricalEvents().stream().filter(e -> EventHelper.related(hf, e)) @@ -135,6 +140,7 @@ public class FamilyMember { float x; float offset = 0; boolean strongLink = false; + String relation = ""; FamilyMember father, mother, spouse; Set children = new HashSet<>(); @@ -253,98 +259,100 @@ public void layoutDown() { } public String getRelation() { - if (generation == 0 && distance == 0) { - return " "; - } - if (generation == -3 && distance == 3) { - // grand parents - if (hf.isFemale()) - return "great-grandmother"; - else - return "great-grandfather"; - } - if (generation == -2 && distance == 2) { - // grand parents - if (hf.isFemale()) - return "grandmother"; - else - return "grandfather"; - } - if (generation == -1 && distance == 1) { - // parents - if (hf.isFemale()) - return "mother"; - else - return "father"; - } - if (generation == -1 && distance == 3) { - // parents - if (hf.isFemale()) - return "aunt"; - else - return "uncle"; - } - if (generation == 0 && distance == 1) { - // spouse - if (hf.isFemale()) - return "wife"; - else - return "husband"; - } - if (generation == 0 && distance == 2) { - // sibling - if (hf.isFemale()) - return "sister"; - else - return "brother"; - } - if (generation == 0 && distance == 3) { - if (hf.isFemale()) - return "sister-in-law"; - else - return "brother-in-law"; - } - if (generation == 0 && distance == 4) { - // spouse - return "cousin"; - } - if (generation == 1 && distance == 1) { - // child - if (hf.isFemale()) - return "daughter"; - else - return "son"; - } - if (generation == 1 && distance == 2) { - // child - if (hf.isFemale()) - return "daughter-in-law"; - else - return "son-in-law"; - } - if (generation == 1 && distance == 3) { - // child - if (hf.isFemale()) - return "niece"; - else - return "nephew"; - } - if (generation == 2 && distance == 2) { - // grand child - if (hf.isFemale()) - return "granddaughter"; - else - return "grandson"; - } - if (generation == 3 && distance == 3) { - // grand child - if (hf.isFemale()) - return "great-granddaughter"; - else - return "great-grandson"; + if (relation.isBlank()) { + if (generation == 0 && distance == 0) { + return " "; + } + if (generation == -3 && distance == 3) { + // grand parents + if (hf.isFemale()) + return "great-grandmother"; + else + return "great-grandfather"; + } + if (generation == -2 && distance == 2) { + // grand parents + if (hf.isFemale()) + return "grandmother"; + else + return "grandfather"; + } + if (generation == -1 && distance == 1) { + // parents + if (hf.isFemale()) + return "mother"; + else + return "father"; + } + if (generation == -1 && distance == 3) { + // parents + if (hf.isFemale()) + return "aunt"; + else + return "uncle"; + } + if (generation == 0 && distance == 1) { + // spouse + if (hf.isFemale()) + return "wife"; + else + return "husband"; + } + if (generation == 0 && distance == 2) { + // sibling + if (hf.isFemale()) + return "sister"; + else + return "brother"; + } + if (generation == 0 && distance == 3) { + if (hf.isFemale()) + return "sister-in-law"; + else + return "brother-in-law"; + } + if (generation == 0 && distance == 4) { + // spouse + return "cousin"; + } + if (generation == 1 && distance == 1) { + // child + if (hf.isFemale()) + return "daughter"; + else + return "son"; + } + if (generation == 1 && distance == 2) { + // child + if (hf.isFemale()) + return "daughter-in-law"; + else + return "son-in-law"; + } + if (generation == 1 && distance == 3) { + // child + if (hf.isFemale()) + return "niece"; + else + return "nephew"; + } + if (generation == 2 && distance == 2) { + // grand child + if (hf.isFemale()) + return "granddaughter"; + else + return "grandson"; + } + if (generation == 3 && distance == 3) { + // grand child + if (hf.isFemale()) + return "great-granddaughter"; + else + return "great-grandson"; + } } - return ""; + return relation; } @Override @@ -415,23 +423,25 @@ public int hashCode() { } public class Family { - private boolean curse; + private int type; //0=family, 1=curse, 2=crime private List members = new ArrayList<>(); private Set links = new LinkedHashSet<>(); private FamilyMember root; private String interaction; - public Family(HistoricalFigure hf, boolean curse) { - this.curse = curse; + public Family(HistoricalFigure hf, int type) { + this.type = type; FamilyMember m = new FamilyMember(hf, 0, 0); root = m; - if (!curse) { + if (type==0) { members.add(m); analyzeFamily(); - } else { + } else if (type==1) { analyzeCurse(); + } else { + analyzeNetwork(); } root.layout(); @@ -578,6 +588,90 @@ private void analyzeBites(FamilyMember m) { analyzeBites(m2); }); } + + private void analyzeNetwork() { + analyzeCrimeBoss(root); + analyzeAssets(root); + } + + private void analyzeCrimeBoss(FamilyMember m) { + //System.out.print(m.getHf().getName()+" entering analysis of crime boss\n"); + for (IntrigueActor actor : m.hf.getIntrigueActors()) { + if (actor.getRole().toLowerCase().contentEquals("master") + || actor.getRole().toLowerCase().contentEquals("handler")) { + FamilyMember master = new FamilyMember(World.getHistoricalFigure(actor.getHfid()), m.generation - 1, m.distance + 1); + m.father = master; + master.children.add(m); + master.relation = actor.getRole().replace(" ", "-"); + links.add(new FamilyLink(actor.getStrategy().replace("-", " "), master, m)); + analyzeCrimeBoss(master); + addMember(master); + } + } + } + + private void analyzeAssets(FamilyMember m) { + if (members.contains(m)) + return; + members.add(m); + + List childRoles = new ArrayList<>(); + List assetRoles = new ArrayList<>(); + List enemyRoles = new ArrayList<>(); + childRoles.add("asset"); + childRoles.add("lieutenant"); + childRoles.add("corrupt position holder"); + childRoles.add("source of funds"); + childRoles.add("source of funds for master"); + assetRoles.add("usable assassin"); + assetRoles.add("usable thief"); + assetRoles.add("usable snatcher"); + assetRoles.add("underworld contact"); + assetRoles.add("potential employer"); + enemyRoles.add("enemy"); + enemyRoles.add("rebuffed"); + enemyRoles.add("suspected criminal"); + enemyRoles.add("possible threat"); + enemyRoles.add("delivery target"); + + for (IntrigueActor actor : m.getHf().getIntrigueActors()) { + //System.out.print("checking "+ actor.getHfid()+ " " + actor.getRole()+"\n"); + if (actor.getHfid() == -1) { + //skip when there's no hfid. + continue; + } + if (childRoles.contains(actor.getRole()) || assetRoles.contains(actor.getRole()) || enemyRoles.contains(actor.getRole())) { + // if actor has a handler, get the handler instead. + if (actor.getHandlerLocalId() > -1) { + //System.out.print("getting handler "+ actor.getHandlerLocalId()+"\n"); + for (IntrigueActor handler : m.getHf().getIntrigueActors()) { + if (handler.getLocalId() == actor.getHandlerLocalId()) { + handler.setRole("asset"); + actor = handler; + } + } + } + for (FamilyMember member : members) { + if (member.hf.getId() == actor.getHfid()) { + //skip members that have already been added. + //System.out.print(member.hf.getName()+" skipped\n"); + continue; + } + } + FamilyMember m2 = new FamilyMember(World.getHistoricalFigure(actor.getHfid()), m.getGeneration() + 1, m.getDistance() + 1); + m2.relation = actor.getRole().replace(" ", "-"); + m2.father = m; + m.children.add(m2); + links.add(new FamilyLink(actor.getStrategy().replace("-", " "), m, m2)); + //System.out.print("added "+ actor.getHfid()+ " " + m2.hf.getName()+"\n"); + if (childRoles.contains(actor.getRole())) { + analyzeAssets(m2); + } else { + addMember(m2); + } + } + } + } @SuppressWarnings("serial") public class MemeberExistsException extends Exception { @@ -597,7 +691,7 @@ public String getMessage() { } public boolean isCurse() { - return curse; + return type>0; } private FamilyMember getRoot() { diff --git a/src/main/resources/lib/legends.css b/src/main/resources/lib/legends.css index 89b4e57..bf3f3c4 100644 --- a/src/main/resources/lib/legends.css +++ b/src/main/resources/lib/legends.css @@ -188,6 +188,23 @@ rect.family.deity { stroke: rgb(100, 100, 100); } +rect.master, rect.handler { + stroke: rgb(202, 0, 202); + stroke-width:1; +} +rect.asset, rect.lieutenant { + stroke: rgb(255, 202, 0); + stroke-width:1; +} +rect.corrupt-position-holder, rect.source-of-funds, rect.source-of-funds-for-master { + stroke: rgb(0, 202, 255); + stroke-width:1; +} +rect.underworld-contact, rect.usable-assassin, rect.usable-snatcher, rect.usable-thief { + stroke: rgb(0, 202, 0); + stroke-width:1; +} + rect.family.important { stroke-width: 2; } @@ -303,9 +320,34 @@ rect.family.deity { stroke: rgb(202, 202, 202); } +rect.master, rect.handler { + stroke: rgb(202, 0, 202); + stroke-width:1; +} +rect.asset, rect.lieutenant { + stroke: rgb(255, 202, 0); + stroke-width:1; +} +rect.corrupt-position-holder, rect.source-of-funds, rect.source-of-funds-for-master, rect.potential-employer { + stroke: rgb(0, 202, 255); + stroke-width:1; +} +rect.underworld-contact, rect.usable-assassin, rect.usable-snatcher, rect.usable-thief { + stroke: rgb(0, 202, 0); + stroke-width:1; +} +rect.enemy, rect.suspected-criminal, rect.possible-threat { + stroke: rgb(202, 0, 0); + stroke-width:1; +} +rect.rebuffed, rect.delivery-target { + stroke: rgb(202, 100, 0); + stroke-width:1; +} + g.group>text { fill: rgb(255, 255, 255); } -} \ No newline at end of file +} diff --git a/src/main/resources/templates/hf.vm b/src/main/resources/templates/hf.vm index 04f6276..cde137d 100644 --- a/src/main/resources/templates/hf.vm +++ b/src/main/resources/templates/hf.vm @@ -35,6 +35,13 @@ #set($family=$curse) #parse("hffamily.vm") #end + +#if($villain) +

Network

+ #set($family=$villain) + #parse("hffamily.vm") +#end +
#if(($hf.siteLinks.size()+$hf.entityPositionLinks.size()+$hf.entityFormerPositionLinks.size())>0)
diff --git a/src/main/resources/templates/hffamily.vm b/src/main/resources/templates/hffamily.vm index f463c3d..333250b 100644 --- a/src/main/resources/templates/hffamily.vm +++ b/src/main/resources/templates/hffamily.vm @@ -36,7 +36,9 @@ #else #set($ym = ($y1+$y2)/2) #if($link.m2.generation - $link.m1.generation == 1) - + + $link.type.replace("-", " ") + #end #end #end @@ -49,7 +51,7 @@ #foreach($m in $family.getMembers($generation)) #set($x = $st + ($m.x) * ($bw+$sx)) #set($y = $st + ($gc - 1) * ($bh+$sy)) - + #set($x = $x + $bw/2) #if($family.curse || ($hf.id == $m.hf.id)) @@ -64,9 +66,9 @@ #end#end - #if(!$family.curse && ($hf.id != $m.hf.id)) + #if(!$m.relation != "" && ($hf.id != $m.hf.id)) #set($y = $y + 11) - $m.relation + $m.relation.replace("-", " ") #end #if(!$m.hf.deity && !$m.hf.force)