package de.lighti.model.game; import java.util.Arrays; import java.util.HashSet; import java.util.Map.Entry; import java.util.Queue; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.LinkedBlockingQueue; public class Hero extends Unit { public class ItemEvent { public Dota2Item item; public int slot; public boolean added; public long tick; private ItemEvent( long tick, Dota2Item item, int slot, boolean added ) { super(); this.tick = tick; this.item = item; this.slot = slot; this.added = added; } } private static int countItem( Dota2Item[] list, Dota2Item n ) { if (n == null) { throw new IllegalArgumentException( "n must not be null" ); } int count = 0; for (final Dota2Item m : list) { if (m != null && m.getKey().equals( n.getKey() )) { count++; } } return count; } private final TreeMap<Long, Dota2Item[]> items; private final Set<Ability> abilities; private final Queue<ItemEvent> itemLog; private final TreeMap<Long, int[]> deaths; public final static int BAG_SIZE = 12; //two bags of 6. Not sure where courier itmes go public Hero( String name ) { super( name ); items = new TreeMap<Long, Dota2Item[]>(); items.put( 0l, new Dota2Item[BAG_SIZE] ); itemLog = new LinkedBlockingQueue<ItemEvent>(); abilities = new HashSet<Ability>(); deaths = new TreeMap<>(); } public void addDeath( long tickMs, int x, int y ) { deaths.put( tickMs, new int[] { x, y } ); } private void generateLogEntries( long tick, Dota2Item[] previous, Dota2Item[] current ) { for (int i = 0; i < previous.length; i++) { if (previous[i] != current[i]) { if (current[i] != null) { if (countItem( previous, current[i] ) == 0) { itemLog.add( new ItemEvent( tick, current[i], i, true ) ); } } else if (previous[i] != null) { itemLog.add( new ItemEvent( tick, previous[i], i, false ) ); } } } } public Set<Ability> getAbilities() { return abilities; } public Ability getAbilityByName( String name ) { for (final Ability a : abilities) { if (a.getKey().equals( name )) { return a; } } return null; } /** * Get all items held by this hero. Beware that this will give * you a Dota2Item for every internal Entity that was attached to this hero, the set * might return a number of objects for the same actual game item. If you're interested * in the unique items a hero bought, you should use getItemLog() instead. * @return a set of items */ public Set<Dota2Item> getAllItems() { final Set<Dota2Item> ret = new HashSet<Dota2Item>(); for (final Dota2Item[] a : items.values()) { for (final Dota2Item i : a) { if (i != null) { ret.add( i ); } } } return ret; } public TreeMap<Long, int[]> getDeaths() { return deaths; } public Queue<ItemEvent> getItemLog() { return itemLog; } /** * Same behaviour as getAllItems, allows to filter returned items by name. * @param itemKey the item name * @return all items with a certain a hero has */ public Set<Dota2Item> getItemsByName( String itemKey ) { final Set<Dota2Item> ret = new HashSet<Dota2Item>(); for (final Dota2Item[] a : items.values()) { for (final Dota2Item i : a) { if (i != null && i.getKey().equals( itemKey )) { ret.add( i ); } } } return ret; } public void setItem( long tickMs, int slot, Dota2Item newItem ) { if (items.containsKey( tickMs )) { //Just store the update items.get( tickMs )[slot] = newItem; } else { //We advanced. Push the current bag configuration, calculate the diff to the previous one and make //a new array for the new tick final Entry<Long, Dota2Item[]> current = items.floorEntry( tickMs ); final Entry<Long, Dota2Item[]> previous = items.floorEntry( current.getKey() - 1 ); final Dota2Item[] newBag = Arrays.copyOf( current.getValue(), current.getValue().length ); newBag[slot] = newItem; items.put( tickMs, newBag ); //previous might be null if we actually pulled the 0l entry into current if (previous != null) { generateLogEntries( current.getKey(), previous.getValue(), current.getValue() ); } } } @Override public String toString() { return "Hero [getName()=" + getName() + "]"; } }