// Path: slclient/src/org/solhost/folko/uosl/common/RandUtil.java
// public class RandUtil {
//     // [minimum, maximum)
//     public static int random(int min, int max) {
//         Random rng = ThreadLocalRandom.current();
//         return rng.nextInt(max - min) + min;
//     }
// 
//     public static <T extends Object> T randomElement(T[] array) {
//         if(array.length == 0) return null;
//         int index = random(0, array.length);
//         return array[index];
//     }
// 
//     public static boolean tryChance(double chance) {
//         Random rng = ThreadLocalRandom.current();
//         return rng.nextDouble() <= chance;
//     }
// }
// 
// Path: libuosl/src/org/solhost/folko/uosl/libuosl/types/Direction.java
// public enum Direction {
//     NORTH, NORTH_EAST, EAST, SOUTH_EAST, SOUTH, SOUTH_WEST, WEST, NORTH_WEST;
// 
//     public static Direction parse(short b) {
//         switch(b) {
//         case 0: return NORTH;
//         case 1: return NORTH_EAST;
//         case 2: return EAST;
//         case 3: return SOUTH_EAST;
//         case 4: return SOUTH;
//         case 5: return SOUTH_WEST;
//         case 6: return WEST;
//         case 7: return NORTH_WEST;
//         default: return NORTH;
//         }
//     }
// 
//     public short toByte() {
//         switch(this) {
//         case NORTH:         return 0;
//         case NORTH_EAST:    return 1;
//         case EAST:          return 2;
//         case SOUTH_EAST:    return 3;
//         case SOUTH:         return 4;
//         case SOUTH_WEST:    return 5;
//         case WEST:          return 6;
//         case NORTH_WEST:    return 7;
//         default:            return 0;
//         }
//     }
// 
//     // angle must be in [0, 360]. 0 is north west and positive angles turn clockwise
//     public static Direction fromAngle(double angle) {
//         double r = 360 / 16.0;
//         if(angle < 45 - r) {
//             return Direction.NORTH_WEST;
//         } else if(angle < 90 - r) {
//             return Direction.NORTH;
//         } else if(angle < 135 - r) {
//             return Direction.NORTH_EAST;
//         } else if(angle < 180 - r) {
//             return Direction.EAST;
//         } else if(angle < 225 - r) {
//             return Direction.SOUTH_EAST;
//         } else if(angle < 270 - r) {
//             return Direction.SOUTH;
//         } else if(angle < 315 - r) {
//             return Direction.SOUTH_WEST;
//         } else if(angle < 360 - r) {
//             return Direction.WEST;
//         } else {
//             return Direction.NORTH_WEST;
//         }
//     }
// 
//     public int getFrameIndex() {
//         switch(this) {
//         case NORTH:         return 3;
//         case NORTH_EAST:    return 2;
//         case EAST:          return 1;
//         case SOUTH_EAST:    return 0;
//         case SOUTH:         return 1;
//         case SOUTH_WEST:    return 2;
//         case WEST:          return 3;
//         case NORTH_WEST:    return 4;
//         default:            return -1;
//         }
//     }
// 
//     public Direction getOpposingDirection() {
//         switch(this) {
//         case NORTH:         return SOUTH;
//         case NORTH_EAST:    return SOUTH_WEST;
//         case EAST:          return WEST;
//         case SOUTH_EAST:    return NORTH_WEST;
//         case SOUTH:         return NORTH;
//         case SOUTH_WEST:    return NORTH_EAST;
//         case WEST:          return EAST;
//         case NORTH_WEST:    return SOUTH_EAST;
//         default:            return SOUTH;
//         }
//     }
// }


import org.solhost.folko.uosl.libuosl.network.SendableMobile;
import org.solhost.folko.uosl.libuosl.types.Attribute;
import org.solhost.folko.uosl.libuosl.types.Direction;
import org.solhost.folko.uosl.libuosl.types.Items;
import org.solhost.folko.uosl.libuosl.types.Mobiles;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.logging.Logger;
import org.solhost.folko.uosl.common.RandUtil;
import org.solhost.folko.uosl.libuosl.data.SLTiles;
import org.solhost.folko.uosl.libuosl.data.SLTiles.StaticTile;
        }
        return null;
    }

    public void unequipItem(Item item) {
        item.setParent(null);
        equipped.remove(item);
    }

    // changes won't be reflected
    public Set<Item> getEquippedItems() {
        Set<Item> res = new HashSet<Item>();
        for(Item equip : equipped) {
            res.add(equip);
        }
        return res;
    }

    public boolean checkSkill(Attribute skill, long minRequired, long maxUntilNoGain) {
        long value = getAttribute(skill);
        if(value < minRequired) {
            log.fine(String.format("%s: Checking %s for %d -> failure due to no chance", getName(), skill, minRequired));
            return false;
        } else if(value >= maxUntilNoGain) {
            log.fine(String.format("%s: Checking %s for %d -> success due to high chance", getName(), skill, minRequired));
            return true;
        }

        // Interesting range where gains happen
        double successChance = (double) (value - minRequired) / (double) (maxUntilNoGain - minRequired);
// Path: slclient/src/org/solhost/folko/uosl/common/RandUtil.java
// public class RandUtil {
//     // [minimum, maximum)
//     public static int random(int min, int max) {
//         Random rng = ThreadLocalRandom.current();
//         return rng.nextInt(max - min) + min;
//     }
// 
//     public static <T extends Object> T randomElement(T[] array) {
//         if(array.length == 0) return null;
//         int index = random(0, array.length);
//         return array[index];
//     }
// 
//     public static boolean tryChance(double chance) {
//         Random rng = ThreadLocalRandom.current();
//         return rng.nextDouble() <= chance;
//     }
// }
// 
// Path: libuosl/src/org/solhost/folko/uosl/libuosl/types/Direction.java
// public enum Direction {
//     NORTH, NORTH_EAST, EAST, SOUTH_EAST, SOUTH, SOUTH_WEST, WEST, NORTH_WEST;
// 
//     public static Direction parse(short b) {
//         switch(b) {
//         case 0: return NORTH;
//         case 1: return NORTH_EAST;
//         case 2: return EAST;
//         case 3: return SOUTH_EAST;
//         case 4: return SOUTH;
//         case 5: return SOUTH_WEST;
//         case 6: return WEST;
//         case 7: return NORTH_WEST;
//         default: return NORTH;
//         }
//     }
// 
//     public short toByte() {
//         switch(this) {
//         case NORTH:         return 0;
//         case NORTH_EAST:    return 1;
//         case EAST:          return 2;
//         case SOUTH_EAST:    return 3;
//         case SOUTH:         return 4;
//         case SOUTH_WEST:    return 5;
//         case WEST:          return 6;
//         case NORTH_WEST:    return 7;
//         default:            return 0;
//         }
//     }
// 
//     // angle must be in [0, 360]. 0 is north west and positive angles turn clockwise
//     public static Direction fromAngle(double angle) {
//         double r = 360 / 16.0;
//         if(angle < 45 - r) {
//             return Direction.NORTH_WEST;
//         } else if(angle < 90 - r) {
//             return Direction.NORTH;
//         } else if(angle < 135 - r) {
//             return Direction.NORTH_EAST;
//         } else if(angle < 180 - r) {
//             return Direction.EAST;
//         } else if(angle < 225 - r) {
//             return Direction.SOUTH_EAST;
//         } else if(angle < 270 - r) {
//             return Direction.SOUTH;
//         } else if(angle < 315 - r) {
//             return Direction.SOUTH_WEST;
//         } else if(angle < 360 - r) {
//             return Direction.WEST;
//         } else {
//             return Direction.NORTH_WEST;
//         }
//     }
// 
//     public int getFrameIndex() {
//         switch(this) {
//         case NORTH:         return 3;
//         case NORTH_EAST:    return 2;
//         case EAST:          return 1;
//         case SOUTH_EAST:    return 0;
//         case SOUTH:         return 1;
//         case SOUTH_WEST:    return 2;
//         case WEST:          return 3;
//         case NORTH_WEST:    return 4;
//         default:            return -1;
//         }
//     }
// 
//     public Direction getOpposingDirection() {
//         switch(this) {
//         case NORTH:         return SOUTH;
//         case NORTH_EAST:    return SOUTH_WEST;
//         case EAST:          return WEST;
//         case SOUTH_EAST:    return NORTH_WEST;
//         case SOUTH:         return NORTH;
//         case SOUTH_WEST:    return NORTH_EAST;
//         case WEST:          return EAST;
//         case NORTH_WEST:    return SOUTH_EAST;
//         default:            return SOUTH;
//         }
//     }
// }


// Path: jphex/src/org/solhost/folko/uosl/jphex/types/Mobile.java
import org.solhost.folko.uosl.libuosl.network.SendableMobile;
import org.solhost.folko.uosl.libuosl.types.Attribute;
import org.solhost.folko.uosl.libuosl.types.Direction;
import org.solhost.folko.uosl.libuosl.types.Items;
import org.solhost.folko.uosl.libuosl.types.Mobiles;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.logging.Logger;
import org.solhost.folko.uosl.common.RandUtil;
import org.solhost.folko.uosl.libuosl.data.SLTiles;
import org.solhost.folko.uosl.libuosl.data.SLTiles.StaticTile;

        }
        return null;
    }

    public void unequipItem(Item item) {
        item.setParent(null);
        equipped.remove(item);
    }

    // changes won't be reflected
    public Set<Item> getEquippedItems() {
        Set<Item> res = new HashSet<Item>();
        for(Item equip : equipped) {
            res.add(equip);
        }
        return res;
    }

    public boolean checkSkill(Attribute skill, long minRequired, long maxUntilNoGain) {
        long value = getAttribute(skill);
        if(value < minRequired) {
            log.fine(String.format("%s: Checking %s for %d -> failure due to no chance", getName(), skill, minRequired));
            return false;
        } else if(value >= maxUntilNoGain) {
            log.fine(String.format("%s: Checking %s for %d -> success due to high chance", getName(), skill, minRequired));
            return true;
        }

        // Interesting range where gains happen
        double successChance = (double) (value - minRequired) / (double) (maxUntilNoGain - minRequired);
        boolean success = RandUtil.tryChance(successChance);