Repository reorganisation

Unified kotlin and java into just src/main
Unified the rs09 and core packages
Took all content out of the core package, and placed it into the new content package
Reorganised all source code relating to content to be easier to find and explore
This commit is contained in:
Ceikry
2023-01-26 13:59:28 +00:00
committed by Ryan
parent e4b799c44a
commit a100affda2
3156 changed files with 24205 additions and 30585 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,578 @@
package core.game.bots;
import core.game.node.entity.impl.PulseType;
import core.ServerConstants;
import core.game.container.impl.EquipmentContainer;
import core.game.interaction.DestinationFlag;
import core.game.interaction.MovementPulse;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.info.PlayerDetails;
import core.game.node.entity.player.link.appearance.Gender;
import core.game.node.item.Item;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.map.path.Pathfinder;
import core.game.world.map.zone.impl.WildernessZone;
import core.game.world.repository.Repository;
import core.net.packet.context.MessageContext;
import core.tools.RandomFunction;
import core.tools.StringUtils;
import core.game.node.entity.skill.Skills;
import content.region.misc.tutisland.handlers.iface.CharacterDesign;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
/**
* Represents an <b>A</b>rtificial <b>I</b>ntelligent <b>P</b>layer.
*
* @author Emperor
*/
public class AIPlayer extends Player {
/**
* The current UID.
*/
private static int currentUID = 0x1;
private static final List<String> botNames = new ArrayList<String>();
/**
* The active Artificial intelligent players mapping.
*/
private static final Map<Integer, AIPlayer> botMapping = new HashMap<>();
/**
* A line of data from namesandarmor.txt that will be used to generate the appearance
* Data in format:
* //name:cblevel:helmet:cape:neck:weapon:chest:shield:unknown:legs:unknown:gloves:boots:
*/
private static String OSRScopyLine;
/**
* The AIP's UID.
*/
private final int uid;
/**
* The start location of the AIP.
*/
private final Location startLocation;
/**
* The username.
*/
private String username;
/**
* The player controlling this AIP.
*/
private Player controler;
/**
* Constructs a new {@code AIPlayer} {@code Object}.
*
* @param l The location.
*/
static {
loadNames("botnames.txt");
}
public AIPlayer(Location l) {
this(getRandomName(), l, null);
}
public AIPlayer(String fileName, Location l) {
this(retrieveRandomName(fileName), l, null);
}
@SuppressWarnings("deprecation")
private AIPlayer(String name, Location l, String ignored) {
super(new PlayerDetails("/aip" + (currentUID + 1) + ":" + name));
super.setLocation(startLocation = l);
super.artificial = true;
super.getDetails().setSession(ArtificialSession.getSingleton());
Repository.getPlayers().add(this);
this.username = StringUtils.formatDisplayName(name + (currentUID + 1));
this.uid = currentUID++;
this.updateRandomValues();
this.init();
}
/**
* Generates bot stats/equipment/etc based on OSRScopyLine
*/
public void updateRandomValues() {
this.getAppearance().setGender(RandomFunction.random(5) == 1 ? Gender.FEMALE : Gender.MALE);
int setTo = RandomFunction.random(0,10);
CharacterDesign.randomize(this,true);
this.setDirection(Direction.values()[new Random().nextInt(Direction.values().length)]); //Random facing dir
this.getSkills().updateCombatLevel();
this.getAppearance().sync();
}
@Override
public void update() {
return;
}
private void setLevels() {
//Create realistic player stats
int maxLevel = RandomFunction.random(1, Math.min(parseOSRS(1), 99));
for (int i = 0; i < Skills.NUM_SKILLS; i++) {
this.getSkills().setStaticLevel(i, RandomFunction.linearDecreaseRand(maxLevel));
}
int combatLevelsLeft = parseOSRS(1);
int hitpoints = Math.max(RandomFunction.random(10, Math.min(maxLevel, combatLevelsLeft * 4)), 10);
combatLevelsLeft -= 0.25 * hitpoints;
int prayer = combatLevelsLeft > 0 ? RandomFunction.random(Math.min(maxLevel, combatLevelsLeft * 8)) : 1;
combatLevelsLeft -= 0.125 * prayer;
int defence = combatLevelsLeft > 0 ? RandomFunction.random(Math.min(maxLevel, combatLevelsLeft * 4)) : 1;
combatLevelsLeft -= 0.25 * defence;
combatLevelsLeft = Math.min(combatLevelsLeft, 199);
int attack = combatLevelsLeft > 0 ? RandomFunction.normalRandDist(Math.min(maxLevel, combatLevelsLeft * 3)) : 1;
int strength = combatLevelsLeft > 0 ? combatLevelsLeft * 3 - attack : 1;
this.getSkills().setStaticLevel(Skills.HITPOINTS, hitpoints);
this.getSkills().setStaticLevel(Skills.PRAYER, prayer);
this.getSkills().setStaticLevel(Skills.DEFENCE, defence);
this.getSkills().setStaticLevel(Skills.ATTACK, attack);
this.getSkills().setStaticLevel(Skills.STRENGTH, strength);
this.getSkills().setStaticLevel(Skills.RANGE, combatLevelsLeft / 2);
this.getSkills().setStaticLevel(Skills.MAGIC, combatLevelsLeft / 2);
}
private void giveArmor() {
//name:cblevel:helmet2:cape3:neck4:weapon5:chest6:shield7:unknown8:legs9:unknown10:gloves11:boots12:
//sicriona:103:1163: 1023: 1725 :1333: 1127 :1201 :0: 1079 :0: 2922: 1061:0:
equipIfExists(new Item(parseOSRS(2)), EquipmentContainer.SLOT_HAT);
equipIfExists(new Item(parseOSRS(3)), EquipmentContainer.SLOT_CAPE);
equipIfExists(new Item(parseOSRS(4)), EquipmentContainer.SLOT_AMULET);
equipIfExists(new Item(parseOSRS(5)), EquipmentContainer.SLOT_WEAPON);
equipIfExists(new Item(parseOSRS(6)), EquipmentContainer.SLOT_CHEST);
equipIfExists(new Item(parseOSRS(7)), EquipmentContainer.SLOT_SHIELD);
equipIfExists(new Item(parseOSRS(9)), EquipmentContainer.SLOT_LEGS);
equipIfExists(new Item(parseOSRS(11)), EquipmentContainer.SLOT_HANDS);
equipIfExists(new Item(parseOSRS(12)), EquipmentContainer.SLOT_FEET);
}
private int parseOSRS(int index) {
return Integer.parseInt(OSRScopyLine.split(":")[index]);
}
private void equipIfExists(Item e, int slot) {
if (e == null || e.getName().equalsIgnoreCase("null")) {
return;
}
if (e.getId() != 0)
getEquipment().replace(e, slot);
}
/**
* Load a list of bot names into memory
*/
public static void loadNames(String fileName){
try {
Scanner sc = new Scanner(new File(ServerConstants.BOT_DATA_PATH + fileName));
while (sc.hasNextLine()) {
botNames.add(sc.nextLine());
}
} catch (Exception e){
e.printStackTrace();
}
}
public static String getRandomName(){
int index = (RandomFunction.random(botNames.size()));
String name = botNames.get(index);
botNames.remove(index);
return name;
}
/**
* Get a bot content
*/
public static void updateRandomOSRScopyLine(String fileName) {
Random rand = new Random();
int n = 0;
try {
for (Scanner sc = new Scanner(new File(ServerConstants.BOT_DATA_PATH + fileName)); sc.hasNext(); ) {
++n;
String line = sc.nextLine();
if (rand.nextInt(n) == 0) { //Chance of overwriting line is lower and lower
if (line.length() < 3 || line.startsWith("#")) //probably an empty line
{
continue;
}
OSRScopyLine = line;
}
}
} catch (FileNotFoundException e) {
System.out.println("Missing " + fileName);
e.printStackTrace();
}
}
private static String retrieveRandomName(String fileName) {
do {
updateRandomOSRScopyLine(fileName);
} while (OSRScopyLine.startsWith("#") || OSRScopyLine.contains("_") || OSRScopyLine.contains(" ")); //Comment
return OSRScopyLine.split(":")[0];
}
private static String retrieveRandomName() {
return retrieveRandomName("namesandarmor.txt");
}
@Override
public void init() {
getProperties().setSpawnLocation(startLocation);
getInterfaceManager().openDefaultTabs();
getSession().setObject(this);
botMapping.put(uid, this);
super.init();
getSettings().setRunToggled(true);
CharacterDesign.randomize(this, false);
getPlayerFlags().setLastSceneGraph(location);
}
/**
* Handles the following.
*
* @param e The entity to follow.
*/
public void follow(final Entity e) {
getPulseManager().run(new MovementPulse(this, e, DestinationFlag.FOLLOW_ENTITY) {
@Override
public boolean pulse() {
face(e);
return false;
}
}, PulseType.STANDARD);
}
public void randomWalkAroundPoint(Location point, int radius) {
Pathfinder.find(this, point.transform(RandomFunction.random(radius, (radius * -1)), RandomFunction.random(radius, (radius * -1)), 0), true, Pathfinder.SMART).walk(this);
}
public void randomWalk(int radiusX, int radiusY) {
Pathfinder.find(this, this.getLocation().transform(RandomFunction.random(radiusX, (radiusX * -1)), RandomFunction.random(radiusY, (radiusY * -1)), 0), false, Pathfinder.SMART).walk(this);
}
public void walkToPosSmart(int x, int y) {
walkToPosSmart(new Location(x, y));
}
public void walkToPosSmart(Location loc) {
Pathfinder.find(this, loc, true, Pathfinder.SMART).walk(this);
}
public void walkPos(int x, int y) {
Pathfinder.find(this, new Location(x, y));
}
public boolean checkVictimIsPlayer() {
if (this.getProperties().getCombatPulse().getVictim() != null)
if (this.getProperties().getCombatPulse().getVictim().isPlayer())
return true;
return false;
}
@Override
public void tick() {
super.tick();
if(getSkullManager().isWilderness()) {
getSkullManager().setLevel(WildernessZone.getWilderness(this));
}
if(getSkills().getLifepoints() <= 0){
//deregister(this.uid);
}
}
public Item getItemById(int id) {
for (int i = 0; i < 28; i++) {
Item item = this.getInventory().get(i);
if (item != null) {
if (item.getId() == id)
return item;
}
}
return null;
}
public void handleIncomingChat(MessageContext ctx){
}
private ArrayList<Node> getNodeInRange(int range, int entry) {
int meX = this.getLocation().getX();
int meY = this.getLocation().getY();
ArrayList<Node> nodes = new ArrayList<Node>();
for (NPC npc : RegionManager.getLocalNpcs(this, range)) {
if (npc.getId() == entry)
nodes.add(npc);
}
for (int x = 0; x < range; x++) {
for (int y = 0; y < range - x; y++) {
Node node = RegionManager.getObject(0, meX + x, meY + y);
if (node != null)
if (node.getId() == entry)
nodes.add(node);
Node node2 = RegionManager.getObject(0, meX + x, meY - y);
if (node2 != null)
if (node2.getId() == entry)
nodes.add(node2);
Node node3 = RegionManager.getObject(0, meX - x, meY + y);
if (node3 != null)
if (node3.getId() == entry)
nodes.add(node3);
Node node4 = RegionManager.getObject(0, meX - x, meY - y);
if (node4 != null)
if (node4.getId() == entry)
nodes.add(node4);
}
}
return nodes;
}
private ArrayList<Node> getNodeInRange(int range, List<Integer> entrys) {
int meX = this.getLocation().getX();
int meY = this.getLocation().getY();
//int meX2 = this.getLocation().getX();
//System.out.println("local " + meX + " real x? " + meX2 );
ArrayList<Node> nodes = new ArrayList<Node>();
for (NPC npc : RegionManager.getLocalNpcs(this, range)) {
if (entrys.contains(npc.getId()))
nodes.add(npc);
}
for (int x = 0; x < range; x++) {
for (int y = 0; y < range - x; y++) {
Node node = RegionManager.getObject(0, meX + x, meY + y);
if (node != null)
if (entrys.contains(node.getId()))
nodes.add(node);
Node node2 = RegionManager.getObject(0, meX + x, meY - y);
if (node2 != null)
if (entrys.contains(node2.getId()))
nodes.add(node2);
Node node3 = RegionManager.getObject(0, meX - x, meY + y);
if (node3 != null)
if (entrys.contains(node3.getId()))
nodes.add(node3);
Node node4 = RegionManager.getObject(0, meX - x, meY - y);
if (node4 != null)
if (entrys.contains(node4.getId()))
nodes.add(node4);
}
}
return nodes;
}
public Node getClosestNodeWithEntryAndDirection(int range, int entry, Direction direction) {
ArrayList<Node> nodeList = getNodeInRange(range, entry);
if (nodeList.isEmpty()) {
//System.out.println("nodelist empty");
return null;
}
Node node = getClosestNodeinNodeListWithDirection(nodeList, direction);
return node;
}
public Node getClosestNodeWithEntry(int range, int entry) {
ArrayList<Node> nodeList = getNodeInRange(range, entry);
if (nodeList.isEmpty()) {
//System.out.println("nodelist empty");
return null;
}
Node node = getClosestNodeinNodeList(nodeList);
return node;
}
public Node getClosestNodeWithEntry(int range, List<Integer> entrys) {
ArrayList<Node> nodeList = getNodeInRange(range, entrys);
if (nodeList.isEmpty()) {
//System.out.println("nodelist empty");
return null;
}
Node node = getClosestNodeinNodeList(nodeList);
return node;
}
public Node getClosesCreature(int radius) {
int distance = radius + 1;
Node npcReturn = null;
for (NPC npc : RegionManager.getLocalNpcs(this, radius)) {
double distanceToNpc = npc.getLocation().getDistance(this.getLocation());
if ((distanceToNpc) < distance) {
distance = (int) distanceToNpc;
npcReturn = npc;
}
}
return npcReturn;
}
public Node getClosesCreature(int radius, int entry) {
int distance = radius + 1;
Node npcReturn = null;
for (NPC npc : RegionManager.getLocalNpcs(this, radius)) {
double distanceToNpc = npc.getLocation().getDistance(this.getLocation());
if (npc.getId() == entry) {
if ((distanceToNpc) < distance) {
distance = (int) distanceToNpc;
npcReturn = npc;
}
}
}
return npcReturn;
}
public Node getClosesCreature(int radius, ArrayList<Integer> entrys) {
int distance = radius + 1;
Node npcReturn = null;
for (NPC npc : RegionManager.getLocalNpcs(this, radius)) {
double distanceToNpc = npc.getLocation().getDistance(this.getLocation());
if (entrys.contains(npc.getId())) {
if ((distanceToNpc) < distance) {
distance = (int) distanceToNpc;
npcReturn = npc;
}
}
}
return npcReturn;
}
private Node getClosestNodeinNodeListWithDirection(ArrayList<Node> nodes, Direction direction) {
if (nodes.isEmpty()) {
//System.out.println("nodelist empty");
return null;
}
double distance = 0;
Node nodeReturn = null;
for (Node node : nodes) {
double nodeDistance = this.getLocation().getDistance(node.getLocation());
if ((nodeReturn == null || nodeDistance < distance) && node.getDirection() == direction) {
distance = nodeDistance;
nodeReturn = node;
}
}
return nodeReturn;
}
private Node getClosestNodeinNodeList(ArrayList<Node> nodes) {
if (nodes.isEmpty()) {
//System.out.println("nodelist empty");
return null;
}
double distance = 0;
Node nodeReturn = null;
for (Node node : nodes) {
double nodeDistance = this.getLocation().getDistance(node.getLocation());
if (nodeReturn == null || nodeDistance < distance) {
distance = nodeDistance;
nodeReturn = node;
}
}
return nodeReturn;
}
@Override
public void clear() {
botMapping.remove(uid);
super.clear(true);
}
@Override
public void reset() {
if (getPlayerFlags().isUpdateSceneGraph()) {
getPlayerFlags().setLastSceneGraph(getLocation());
}
super.reset();
}
@Override
public void finalizeDeath(Entity killer) {
super.finalizeDeath(killer);
fullRestore();
}
/**
* Gets the UID.
*
* @return the UID.
*/
public int getUid() {
return uid;
}
/**
* Deregisters an AIP.
*
* @param uid The player's UID.
*/
public static void deregister(int uid) {
AIPlayer player = botMapping.get(uid);
if (player != null) {
player.clear();
Repository.getPlayers().remove(player);
return;
}
//SystemLogger.logErr(this.getClass(), "Could not deregister AIP#" + uid + ": UID not added to the mapping!");
}
@Override
public String getUsername() {
return username;
}
/**
* Gets the AIP for the given UID.
*
* @param uid The UID.
* @return The AIPlayer.
*/
public static AIPlayer get(int uid) {
return botMapping.get(uid);
}
/**
* @return the startLocation.
*/
public Location getStartLocation() {
return startLocation;
}
/**
* Gets the controler.
*
* @return The controler.
*/
public Player getControler() {
return controler;
}
/**
* Sets the controler.
*
* @param controler The controler to set.
*/
public void setControler(Player controler) {
this.controler = controler;
}
public void interact(Node n) {
// InteractionPacket.handleObjectInteraction(this, 0, n.getLocation(), n.getId());
}
}
@@ -0,0 +1,53 @@
package core.game.bots
import core.game.node.entity.player.Player
import core.game.node.item.GroundItem
import core.game.ge.GrandExchangeOffer
/**
* A repository for bots to make use of that can contain any info that might be useful to them.
* @author Ceikry
*/
class AIRepository {
companion object {
val groundItems = HashMap<Player,ArrayList<GroundItem>>()
val GEOffers = HashMap<Player, GrandExchangeOffer>()
@JvmStatic
val PulseRepository = HashMap<String, GeneralBotCreator.BotScriptPulse>() // Lowercase username, pulse
@JvmStatic
fun addItem(item: GroundItem){
if(groundItems[item.dropper] == null){
val list = ArrayList<GroundItem>()
list.add(item)
groundItems[item.dropper] = list
return
}
groundItems[item.dropper]!!.add(item)
}
@JvmStatic
fun getItems(player: Player): ArrayList<GroundItem>?{
return groundItems[player]
}
@JvmStatic
fun addOffer(player: Player, offer: GrandExchangeOffer){
GEOffers[player] = offer
}
@JvmStatic
fun getOffer(player: Player): GrandExchangeOffer? {
return GEOffers[player]
}
@JvmStatic fun clearAllBots() {
PulseRepository.forEach { (_, it) ->
it.stop();
it.botScript.bot.clear();
AIPlayer.deregister((it.botScript.bot as AIPlayer).uid)
}
}
}
}
@@ -0,0 +1,53 @@
package core.game.bots;
import java.nio.ByteBuffer;
import core.net.IoSession;
/**
* Represents an artificial networking session.
* @author Emperor
*/
public final class ArtificialSession extends IoSession {
/**
* The artificial session singleton.
*/
private static final ArtificialSession SINGLETON = new ArtificialSession();
/**
* Constructs a new {@code ArtificialSession} {@code Object}.
*/
private ArtificialSession() {
super(null, null);
}
@Override
public String getRemoteAddress() {
return "127.0.0.1";
}
@Override
public void write(Object context, boolean instant) {
}
@Override
public void queue(ByteBuffer buffer) {
}
@Override
public void write() {
}
@Override
public void disconnect() {
}
/**
* @return the singleton.
*/
public static ArtificialSession getSingleton() {
return SINGLETON;
}
}
@@ -0,0 +1,55 @@
package core.game.bots
import core.game.node.entity.player.link.appearance.Gender
import core.game.node.entity.player.link.prayer.PrayerType
import core.game.node.item.Item
import core.game.world.map.Direction
import core.game.world.map.Location
import core.tools.RandomFunction
import core.game.consumable.Consumable
import content.data.consumables.Consumables
import core.game.consumable.Food
import content.data.consumables.effects.HealingEffect
import core.game.node.entity.skill.Skills
import java.util.*
class CombatBot(location: Location) : AIPlayer(location) {
var tick = 0
override fun updateRandomValues() {
appearance.gender = if (RandomFunction.random(5) == 1) Gender.FEMALE else Gender.MALE
setDirection(Direction.values()[Random().nextInt(Direction.values().size)]) //Random facing dir
skills.updateCombatLevel()
appearance.sync()
}
override fun tick() {
super.tick()
this.tick++
//Despawn
if (skills.lifepoints == 0) {
//CombatBotAssembler.produce(CombatBotAssembler.Type.RANGE, CombatBotAssembler.Tier.LOW,this.location)
deregister(uid)
}
}
fun CheckPrayer(type: Array<PrayerType?>) {
for (i in type.indices) prayer.toggle(type[i])
}
fun eat(foodId: Int) {
val foodItem = Item(foodId)
if (skills.getStaticLevel(Skills.HITPOINTS) >= skills.lifepoints * 3 && inventory.containsItem(foodItem)) {
this.lock(3)
//this.animate(new Animation(829));
val food = inventory.getItem(foodItem)
var consumable: Consumable? = Consumables.getConsumableById(food.id)
if (consumable == null) {
consumable = Food(IntArray(food.id), HealingEffect(1))
}
consumable.consume(food, this)
properties.combatPulse.delayNextAttack(3)
}
if (!checkVictimIsPlayer()) if (!inventory.contains(foodId, 1)) inventory.add(Item(foodId, 5)) //Add Food to Inventory
}
}
@@ -0,0 +1,532 @@
package core.game.bots
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.game.world.map.Location
import core.tools.RandomFunction
import org.rs09.consts.Items
import java.util.*
import kotlin.collections.ArrayList
/**
* Assembles combat-style bots, intended to replace PVMBotBuilder.
* @author Ceikry
*/
class CombatBotAssembler {
enum class Type{
RANGE,
MAGE,
MELEE
}
enum class Tier{
LOW,
MED,
HIGH,
PURE
}
/**
* Produces a bot with the specified parameters.
* @param type the type of bot to produce. Melee, Ranged, or Mage.
* @param tier specifies the range of skills the bot can have, and thereby, the gear. LOW, MED, or HIGH.
* @param location the location that the bot spawns and respawns at.
* @return an AIPlayer with the specified values.
* @author Ceikry
*/
fun produce(type: Type, tier: Tier, location: Location): AIPlayer? {
return when (type) {
Type.RANGE -> assembleRangedBot(tier, location)
Type.MELEE -> assembleMeleeBot(tier,location)
Type.MAGE -> assembleMeleeBot(tier,location)
}
}
/**
* Assembles a ranged bot with the specified values.
* @param tier the tier to use which defines skill ranges and gear.
* @param location the bot's spawn and respawn location
* @param crossbow (optional) whether or not this bot should use a crossbow
* @return a CombatBot with the specified values.
* @author Ceikry
*/
fun assembleRangedBot(tier: Tier, location: Location, crossbow: Boolean? = null): CombatBot {
val bot = CombatBot(location)
generateStats(bot, tier, Skills.RANGE, Skills.DEFENCE)
gearRangedBot(bot, crossbow ?: Random().nextInt() % 2 == 0)
return bot
}
/**
* Assembles a melee bot with the specified values.
* @param tier the tier of the bot. Specifies levels and gear.
* @param location the spawn and respawn location of the bot.
* @return a CombatBot with the specified values.
* @author Ceikry
*/
fun assembleMeleeBot(tier: Tier, location: Location): CombatBot {
val bot = CombatBot(location)
generateStats(bot, tier, Skills.ATTACK, Skills.STRENGTH, Skills.DEFENCE)
gearMeleeBot(bot)
return bot
}
/**
* Assembles a melee bot with gear appropriate for killing dragons.
* @param tier the tier of the bot, specifying levels and gear.
* @param location the spawn and respawn location of the bot.
* @return a CombatBot suited for killing dragons.
* @author Kermit
*/
fun MeleeAdventurer(tier: Tier, location: Location): CombatBot {
val bot = CombatBot(location)
var max = 0
val level = RandomFunction.random(25, 65).also {max = 99 }
generateStats(bot,tier,Skills.ATTACK, Skills.STRENGTH, Skills.DEFENCE)
bot.skills.setStaticLevel(Skills.HITPOINTS, level)
bot.skills.setStaticLevel(Skills.ATTACK, level + 5)
bot.skills.setStaticLevel(Skills.STRENGTH, level + 5)
bot.skills.setLevel(Skills.HITPOINTS, level)
bot.skills.setLevel(Skills.ATTACK, level + 5)
bot.skills.setLevel(Skills.STRENGTH, level + 5)
bot.skills.updateCombatLevel()
equipHighest(bot, MELEE_HELMS)
equipHighest(bot, MELEE_TOP)
equipHighest(bot, MELEE_LEG)
equipHighest(bot, MELEE_WEP)
equipHighest(bot, MELEE_SHIELD)
equipHighest(bot, CAPE)
equipHighest(bot, NNECK)
equipHighest(bot, NGLOVES)
equipHighest(bot, NBOOTS)
bot.equipment.refresh()
return bot
}
/**
* Assembles a melee bot with gear appropriate for killing dragons.
* @param tier the tier of the bot, specifying levels and gear.
* @param location the spawn and respawn location of the bot.
* @return a CombatBot suited for killing dragons.
* @author Kermit
*/
fun RangeAdventurer(tier: Tier, location: Location): CombatBot {
val bot = CombatBot(location)
var max = 0
val level = RandomFunction.random(35, 65).also {max = 75 }
generateStats(bot,tier,Skills.ATTACK, Skills.STRENGTH)
bot.skills.setStaticLevel(Skills.HITPOINTS, level)
bot.skills.setStaticLevel(Skills.DEFENCE, level)
bot.skills.setStaticLevel(Skills.RANGE, level + 10)
bot.skills.setLevel(Skills.HITPOINTS, level)
bot.skills.setLevel(Skills.DEFENCE, level)
bot.skills.setLevel(Skills.RANGE, level + 10)
bot.skills.updateCombatLevel()
equipHighest(bot,RANGE_HELMS,65)
equipHighest(bot,RANGE_TOPS,65)
equipHighest(bot,RANGE_LEGS,65)
equipHighest(bot,CROSSBOWS,50)
equipHighest(bot, CAPE)
equipHighest(bot, NRANGENECK)
equipHighest(bot, NRANGESHIELD)
equipHighest(bot, PCRANGE_BACK)
equipHighest(bot, NGLOVES)
equipHighest(bot, NRBOOTS)
bot.equipment.add(Item(Items.BRONZE_BOLTS_877,100000),13,false,false)
bot.equipment.refresh()
return bot
}
/**
* Assembles a melee bot with gear appropriate for killing dragons.
* @param tier the tier of the bot, specifying levels and gear.
* @param location the spawn and respawn location of the bot.
* @return a CombatBot suited for killing dragons.
* @author Ceikry
*/
fun assembleMeleeDragonBot(tier: Tier, location: Location): CombatBot {
val bot = CombatBot(location)
generateStats(bot,tier,Skills.ATTACK, Skills.STRENGTH, Skills.DEFENCE)
equipHighest(bot, MELEE_HELMS, 50)
equipHighest(bot, MELEE_TOP, 40)
equipHighest(bot, MELEE_LEG, 40)
equipHighest(bot, MELEE_WEP, 60)
equipHighest(bot, CAPE)
equipHighest(bot, NGLOVES)
equipHighest(bot, NBOOTS)
bot.equipment.refresh()
return bot
}
/**
* Assembles a ranged bot with gear appropriate for killing dragons.
* @param tier the tier of the bot, specifying levels and gear.
* @param location the spawn and respawn location of the bot.
* @return a CombatBot suited for killing dragons.
* @author Ceikry
*/
fun assembleRangeDragonBot(tier: Tier, location: Location): CombatBot {
val bot = CombatBot(location)
bot.fullRestore()
generateStats(bot,tier,Skills.RANGE,Skills.DEFENCE)
equipHighest(bot,RANGE_HELMS,50)
equipHighest(bot,RANGE_TOPS,50)
equipHighest(bot,RANGE_LEGS,50)
equipHighest(bot,CROSSBOWS,50)
equipHighest(bot, CAPE)
equipHighest(bot, NGLOVES)
equipHighest(bot, NRBOOTS)
bot.equipment.add(Item(Items.BRONZE_BOLTS_877,100000),13,false,false)
bot.equipment.refresh()
return bot
}
/**
* Gears a ranged bot with the best gear for its stats.
* @param bot the bot to gear
* @param crossbow (optional) whether or not this bot should use a crossbow. Default is false.
* @author Ceikry
*/
fun gearRangedBot(bot: AIPlayer, crossbow: Boolean? = false) {
equipHighest(bot, RANGE_HELMS)
equipHighest(bot, RANGE_TOPS)
equipHighest(bot, RANGE_LEGS)
equipHighest(bot, CAPE)
equipHighest(bot, NGLOVES)
equipHighest(bot, NRBOOTS)
if(crossbow == true) { equipHighest(bot,CROSSBOWS); equipHighest(bot,MELEE_SHIELD); bot.equipment.add(Item(Items.BRONZE_BOLTS_877,Integer.MAX_VALUE),13,false,false) }
else {equipHighest(bot, BOWS); bot.equipment.add(Item(Items.BRONZE_ARROW_882,Integer.MAX_VALUE),13,false,false) }
bot.equipment.refresh()
}
/**
* Gears a melee bot with the best gear for its stats.
* @param bot the bot to gear.
* @author Ceikry
*/
fun gearMeleeBot(bot: AIPlayer){
equipHighest(bot, MELEE_HELMS)
equipHighest(bot, MELEE_LEG)
equipHighest(bot, MELEE_SHIELD)
equipHighest(bot, MELEE_TOP)
equipHighest(bot, CAPE)
equipHighest(bot, NGLOVES)
equipHighest(bot, NBOOTS)
equipHighest(bot, MELEE_WEP)
bot.equipment.refresh()
}
/**
* Gears a Novice Pest control bot.
* @author Sir Kermit & Ceikry
*/
fun gearPCnRangedBot(bot: AIPlayer, crossbow: Boolean? = false, vararg skills: Int) {
var max = 0
val level = RandomFunction.random(30, 70).also {max = 75 }
bot.fullRestore()
bot.skills.setStaticLevel(Skills.RANGE, 50)
bot.skills.setStaticLevel(Skills.DEFENCE, 50)
bot.skills.setStaticLevel(Skills.ATTACK, level)
bot.skills.setStaticLevel(Skills.STRENGTH, level)
bot.skills.setStaticLevel(Skills.HITPOINTS, level)
bot.skills.setLevel(Skills.RANGE, 50)
bot.skills.setLevel(Skills.DEFENCE, 50)
bot.skills.setLevel(Skills.ATTACK, level)
bot.skills.setLevel(Skills.STRENGTH, level)
bot.skills.setLevel(Skills.HITPOINTS, level)
bot.skills.updateCombatLevel()
equipHighest(bot, PCRANGE_HELMS)
equipHighest(bot, PCRANGE_TOPS)
equipHighest(bot, PCRANGE_BACK)
equipHighest(bot, PCRANGE_LEGS)
bot.equipment.refresh()
equipHighest(bot, NECK)
equipHighest(bot, GLOVES)
equipHighest(bot, BOOTS)
equipHighest(bot, RING_ARCH)
bot.equipment.refresh()
if(crossbow == true) { equipHighest(bot,PCCROSSBOWS); equipHighest(bot,MELEE_SHIELD); bot.equipment.add(Item(Items.BRONZE_BOLTS_877,Integer.MAX_VALUE),13,false,false) }
else {equipHighest(bot, PCBOWS); bot.equipment.add(Item(Items.BRONZE_ARROW_882,Integer.MAX_VALUE),13,false,false) }
bot.skills.setStaticLevel(Skills.RANGE, 99)
bot.skills.setLevel(Skills.RANGE, 99)
bot.equipment.refresh()
}
fun gearPCnMeleeBot(bot: AIPlayer, vararg skills: Int){
var max = 0
val initial = RandomFunction.random(30, 75).also {max = 75 }
var level = initial
bot.fullRestore()
bot.skills.setStaticLevel(Skills.STRENGTH, level)
bot.skills.setStaticLevel(Skills.DEFENCE, level)
bot.skills.setStaticLevel(Skills.ATTACK, level)
bot.skills.setStaticLevel(Skills.HITPOINTS, level)
bot.skills.setStaticLevel(Skills.PRAYER, 70)
bot.skills.setStaticLevel(Skills.RANGE, 10)
bot.skills.setStaticLevel(Skills.MAGIC, 10)
bot.skills.setLevel(Skills.STRENGTH, level)
bot.skills.setLevel(Skills.DEFENCE, level)
bot.skills.setLevel(Skills.ATTACK, level)
bot.skills.setLevel(Skills.HITPOINTS, level)
bot.skills.setLevel(Skills.PRAYER, 70)
bot.skills.setLevel(Skills.RANGE, 10)
bot.skills.setLevel(Skills.MAGIC, 10)
bot.skills.updateCombatLevel()
equipHighest(bot, PCMELEE_HELMS)
equipHighest(bot, PCMELEE_LEG)
equipHighest(bot, PCMELEE_SHIELD)
equipHighest(bot, PCMELEE_TOP)
equipHighest(bot, PCMELEE_WEP)
bot.equipment.refresh()
equipHighest(bot, CAPE)
equipHighest(bot, NECK)
equipHighest(bot, GLOVES)
equipHighest(bot, BOOTS)
equipHighest(bot, RING_BERS)
bot.equipment.refresh()
bot.skills.setStaticLevel(Skills.DEFENCE, 70)
bot.skills.setStaticLevel(Skills.ATTACK, 99)
bot.skills.setStaticLevel(Skills.STRENGTH, 99)
bot.skills.setStaticLevel(Skills.HITPOINTS, 80)
bot.skills.setLevel(Skills.DEFENCE, 70)
bot.skills.setLevel(Skills.ATTACK, 99)
bot.skills.setLevel(Skills.STRENGTH, 99)
bot.skills.setLevel(Skills.HITPOINTS, 80)
bot.fullRestore()
}
/**
* Gears a Intermediate Pest control bot.
* @author Sir Kermit & Ceikry
*/
fun gearPCiRangedBot(bot: AIPlayer, crossbow: Boolean? = false, vararg skills: Int) {
var max = 0
val level = RandomFunction.random(50, 80).also {max=99 }
bot.fullRestore()
bot.skills.setStaticLevel(Skills.RANGE, level)
bot.skills.setStaticLevel(Skills.DEFENCE, 80)
bot.skills.setStaticLevel(Skills.ATTACK, level)
bot.skills.setStaticLevel(Skills.STRENGTH, level)
bot.skills.setStaticLevel(Skills.HITPOINTS, 70)
bot.skills.setStaticLevel(Skills.SUMMONING, 99)
bot.skills.setLevel(Skills.RANGE, level)
bot.skills.setLevel(Skills.DEFENCE, 80)
bot.skills.setLevel(Skills.ATTACK, level)
bot.skills.setLevel(Skills.STRENGTH, level)
bot.skills.setLevel(Skills.HITPOINTS, 70)
bot.skills.setLevel(Skills.SUMMONING, 99)
bot.skills.updateCombatLevel()
equipHighest(bot, PCRANGE_HELMS)
equipHighest(bot, PCRANGE_TOPS)
equipHighest(bot, PCRANGE_BACK)
equipHighest(bot, PCRANGE_LEGS)
bot.equipment.refresh()
equipHighest(bot, GLOVES)
equipHighest(bot, NECK)
equipHighest(bot, BOOTS)
equipHighest(bot, RING_ARCH)
bot.equipment.refresh()
if(crossbow == true) { equipHighest(bot,PCCROSSBOWS); equipHighest(bot,MELEE_SHIELD); bot.equipment.add(Item(Items.BRONZE_BOLTS_877,Integer.MAX_VALUE),13,false,false) }
else {equipHighest(bot, PCBOWS); bot.equipment.add(Item(Items.BRONZE_ARROW_882,Integer.MAX_VALUE),13,false,false) }
bot.skills.setStaticLevel(Skills.RANGE, 99)
bot.skills.setLevel(Skills.RANGE, 99)
bot.equipment.refresh()
}
fun gearPCiMeleeBot(bot: AIPlayer, vararg skills: Int){
var max = 0
val initial = RandomFunction.random(55, 95).also {max=95 }
var level = initial
bot.fullRestore()
bot.skills.setStaticLevel(Skills.STRENGTH, level)
bot.skills.setStaticLevel(Skills.DEFENCE, level)
bot.skills.setStaticLevel(Skills.ATTACK, level)
bot.skills.setStaticLevel(Skills.HITPOINTS, level)
bot.skills.setStaticLevel(Skills.PRAYER, 99)
bot.skills.setStaticLevel(Skills.RANGE, level)
bot.skills.setStaticLevel(Skills.MAGIC, level)
bot.skills.setStaticLevel(Skills.SUMMONING, 99)
bot.skills.setLevel(Skills.STRENGTH, level)
bot.skills.setLevel(Skills.DEFENCE, level)
bot.skills.setLevel(Skills.ATTACK, level)
bot.skills.setLevel(Skills.HITPOINTS, level)
bot.skills.setLevel(Skills.PRAYER, 99)
bot.skills.setLevel(Skills.RANGE, level)
bot.skills.setLevel(Skills.MAGIC, level)
bot.skills.setLevel(Skills.SUMMONING, 99)
bot.skills.updateCombatLevel()
equipHighest(bot, PCMELEE_HELMS)
equipHighest(bot, PCMELEE_LEG)
equipHighest(bot, PCMELEE_SHIELD)
equipHighest(bot, PCMELEE_TOP)
equipHighest(bot, PCMELEE_WEP)
bot.equipment.refresh()
equipHighest(bot, CAPE)
equipHighest(bot, NECK)
equipHighest(bot, GLOVES)
equipHighest(bot, BOOTS)
equipHighest(bot, RING_BERS)
bot.equipment.refresh()
bot.skills.setStaticLevel(Skills.DEFENCE, 99)
bot.skills.setStaticLevel(Skills.ATTACK, 99)
bot.skills.setStaticLevel(Skills.STRENGTH, 99)
bot.skills.setStaticLevel(Skills.HITPOINTS, 99)
bot.skills.setLevel(Skills.DEFENCE, 99)
bot.skills.setLevel(Skills.ATTACK, 99)
bot.skills.setLevel(Skills.STRENGTH, 99)
bot.skills.setLevel(Skills.HITPOINTS, 99)
bot.fullRestore()
}
/**
* Generates the stats for a bot with the given tier.
* @param bot the bot to gear
* @param tier the Tier of stats and gear. LOW, MED, HIGH, PURE.
* @param skills the skills that we should generate.
* @author Ceikry and Eli
*/
fun generateStats(bot: AIPlayer, tier: Tier, vararg skills: Int) {
var totalXPAdd = 0.0
var skillAmt = 0.0
val variance = 0.5
var max = 0
val initial = when (tier) {
Tier.LOW -> RandomFunction.random(33).also { max = 33 }
Tier.MED -> RandomFunction.random(33, 66).also { max = 66 }
Tier.HIGH -> RandomFunction.random(66, 99).also { max = 99 }
Tier.PURE -> RandomFunction.random(90, 99).also {max = 99 }
}
for (skill in skills.indices) {
val perc = RandomFunction.random(-variance,variance)
var level = initial + (perc * 33).toInt()
if(level < 1)
level = 1
if(level > max)
level = max
bot.skills.setLevel(skills[skill], level)
bot.skills.setStaticLevel(skills[skill], level)
totalXPAdd += bot.skills.getExperience(skills[skill])
skillAmt++
}
when (tier){
Tier.PURE -> {
bot.skills.setStaticLevel(Skills.DEFENCE,10)
bot.skills.setStaticLevel(Skills.STRENGTH,99)
bot.skills.setStaticLevel(Skills.ATTACK,90)
bot.skills.setStaticLevel(Skills.PRAYER,43)
bot.skills.setStaticLevel(Skills.RANGE,1)
bot.skills.setStaticLevel(Skills.MAGIC,1)
}
}
bot.skills.addExperience(Skills.HITPOINTS, (totalXPAdd / skillAmt) * 0.2)
val new_hp = bot.skills.levelFromXP((totalXPAdd / skillAmt) * 0.2)
bot.skills.setStaticLevel(Skills.HITPOINTS,10 + new_hp)
bot.skills.updateCombatLevel()
bot.fullRestore()
}
/**
* Equips the highest piece of gear from a set for the stats the bot has.
* @param bot the bot to equip gear to.
* @param set the IntArray set to check
* @param levelcap (optional) the max level of gear to equip.
* @author Ceikry
*/
private fun equipHighest(bot: AIPlayer, set: Array<Int>, levelcap: Int? = null) {
val highestItems = ArrayList<Item>()
var highest: Item? = null
for (i in set.indices) {
val item = Item(set[i])
var canEquip = true
(item.definition.handlers.getOrDefault("requirements",null) as HashMap<Int,Int>?)?.let { map ->
levelcap?.let {levelcap ->
map.map {
if (bot.skills.getLevel(it.key) < it.value || it.value > levelcap)
canEquip = false
}
} ?: map.map {
if (bot.skills.getLevel(it.key) < it.value)
canEquip = false
}
}
if (canEquip) {
if (highest == null) {
highest = item
highestItems.add(item)
continue
}
if (item.lvlAvg() > highest.lvlAvg()) {
highest = item
highestItems.clear()
highestItems.add(item)
} else if(item.lvlAvg() == highest.lvlAvg()){
highestItems.add(item)
}
}
}
bot.equipment.add(highestItems.random(), highest!!.definition!!.handlers["equipment_slot"] as Int, false, false)
}
/**
* Extension function for the Item class that gets the average of its level requirements.
* @author Ceikry
*/
fun Item.lvlAvg(): Int {
var total = 1
var count = 1
(definition.handlers.getOrDefault("requirements",null) as HashMap<Int,Int>?)?.let { map ->
map.map {
total += it.value
count++
}
}
return total / count
}
val RANGE_HELMS = arrayOf(1167,4732,3749)
val RANGE_TOPS = arrayOf(1129,1131,1135,2499,2501,2503)
val RANGE_LEGS = arrayOf(1095,1097,1099,2493,2495,2497)
val BOWS = arrayOf(841,843,847,853)
val CROSSBOWS = arrayOf(9185,9174,9177,9176,9179,9181,9183)
val PCRANGE_HELMS = arrayOf(1167,4732,3749,11718)
val PCRANGE_TOPS = arrayOf(1129,1131,1135,2503,11720)
val PCRANGE_LEGS = arrayOf(1095,1097,1099,2497,11722)
val PCRANGE_BACK = arrayOf(1019,10498,10499)
val PCBOWS = arrayOf(841,843,847,853)
val PCCROSSBOWS = arrayOf(9185,9174,9177,9176,9179,9181,9183)
val MELEE_HELMS = arrayOf(1137,1139, 1141, 6621, 1143,1145,1147,1149,1151,1153, 6623, 1159,1163,1165,3748, 3751, 3753, 4716,4724, 4745, 4753)
val MELEE_TOP = arrayOf(1101,1103,1105,1107,1109,1111,1113,2513,1115,1117,1119,1121,1123,1125,1127,4720,4728,4749,4749)
val MELEE_LEG = arrayOf(1081,1083,1085,1087,1089,1091,1093,4759,1067,1069,1071,1073,1075,1077,1079,4722,4751,4722,4751)
val MELEE_SHIELD = arrayOf(1171,1173,1175,1177,1179,1181,1183,1185,1187,1189,1191,1193,1195,1197,1199,1201)
val MELEE_WEP = arrayOf(1277,1279,1281,1283,1285,1287,1289,1291,1293,1295,1297,1299,1301,1303,1305,1321,1323,1325,1327,1329,1331,1333,4587,4151,1363,1365,1367,1369,1371,1373,1375,1377)
val NGLOVES = arrayOf(1059,2922,2912,2902,2932,2942,3799)
val NBOOTS = arrayOf(4121,4123,4125,4127,4129,4131,1061,1837,2579,9005)
val NRBOOTS = arrayOf(9006,626,628,630,632,634)
val NNECK = arrayOf(1704,1725,1729,1731)
val NRANGENECK = arrayOf(1478,1704)
val NRANGESHIELD = arrayOf(1191,1193,1195,1197,1199,1201)
val PCMELEE_HELMS = arrayOf(1137,1139, 1141, 6621, 1143,1145,1147,1149,1151,1153, 6623, 1159,1163,1165,3748, 3751, 10828, 11335, 3753, 4716,4724, 4745, 4753, 3751)
val PCMELEE_TOP = arrayOf(1101,1103,1105,1107,1109,1111,1113,2513,1115,1117,1119,1121,1123,1125,1127,4720,4728,4749,4749,11724,14479,2513)
val PCMELEE_LEG = arrayOf(1081,1083,1085,1087,1089,1091,1093,4759,1067,1069,1071,1073,1075,1077,1079,4722,4751,4722,4751,11726,4087)
val PCMELEE_SHIELD = arrayOf(1171,1173,1175,1177,1179,1181,1183,1185,1187,1189,1191,1193,1195,1197,1199,1201,6524,13742,13740,13738,13736,13734)
val PCMELEE_WEP = arrayOf(1277,1279,1281,1283,1285,1287,1289,1291,1293,1295,1297,1299,1301,1303,1305,1321,1323,1325,1327,1329,1331,1333,4587,4151,1363,1365,1367,1369,1371,1373,1375,1377,1434,5698)
val NECK = arrayOf(1704,6585)
val CAPE = arrayOf(1019,1021,1023,6568,4315,4317,4319,4321,4323,4325,4327,4329,4331,4333,4335,4337,4339,4341,4343,4345,4347,4349,4351)
val GLOVES = arrayOf(1059,7456,7457,7458,7459,7460,7461,7462)
val BOOTS = arrayOf(1061,4131,11732,11728,4131)
val RING_BERS = arrayOf(6737)
val RING_ARCH = arrayOf(6733)
val RICH_MELEE_HELMS = arrayOf(2587,2595,2605,2613,2619,2627,2657,2665,2673,3486,1149,10828,4716,4724,4753)
}
@@ -0,0 +1,80 @@
package core.game.bots
import core.game.node.entity.player.Player
import core.game.system.task.Pulse
import core.game.world.GameWorld
import core.game.world.map.Location
import core.tools.RandomFunction
import core.Server
import content.global.bots.Idler
class GeneralBotCreator {
//org/crandor/net/packet/in/InteractionPacket.java <<< This is a very useful class for learning to code bots
constructor(botScript: Script, loc: Location?) {
botScript.bot = AIPBuilder.create(loc)
GameWorld.Pulser.submit(BotScriptPulse(botScript))
}
constructor(botScript: Script, bot: AIPlayer?) {
botScript.bot = bot
GameWorld.Pulser.submit(BotScriptPulse(botScript).also { AIRepository.PulseRepository[it.botScript.bot.username.lowercase()] = it })
}
constructor(botScript: Script, player: Player, isPlayer: Boolean){
botScript.bot = player
val pulse = BotScriptPulse(botScript,isPlayer)
GameWorld.Pulser.submit(pulse)
player.setAttribute("/save:not_on_highscores",true)
player.setAttribute("botting:script",pulse)
}
inner class BotScriptPulse(public val botScript: Script, val isPlayer: Boolean = false) : Pulse(1){
var ticks = 0
init {
botScript.init(isPlayer)
}
var randomDelay = 0
override fun pulse(): Boolean {
if(randomDelay > 0){
randomDelay -= 1
return false
}
if (!botScript.bot.pulseManager.hasPulseRunning()) {
/*if (ticks++ >= RandomFunction.random(90000,120000)) {
AIPlayer.deregister(botScript.bot.uid)
ticks = 0
SystemLogger.log("Submitting transition pulse from ticks")
GameWorld.Pulser.submit(TransitionPulse(botScript))
return true
}*/
if(!botScript.running) return true //has to be separated this way or it double-submits the respawn pulse.
val idleRoll = RandomFunction.random(50)
if(idleRoll == 2 && botScript !is Idler){
randomDelay += RandomFunction.random(2,20)
return false
}
botScript.tick()
}
return false
}
override fun stop() {
ticks = Integer.MAX_VALUE - 20 //Sets the ticks as high as they can go (safely) and then runs pulse again
pulse() //to trigger the transition pulse to be submitted.
super.stop()
if (Server.running) AIRepository.PulseRepository.remove(this.botScript.bot.username.lowercase())
}
}
inner class TransitionPulse(val script: Script) : Pulse(RandomFunction.random(60,200)){
override fun pulse(): Boolean {
// This does not get called and should be removed
GameWorld.Pulser.submit(BotScriptPulse(script.newInstance()).also { AIRepository.PulseRepository[it.botScript.bot.username.lowercase()] = it })
return true
}
}
}
@@ -0,0 +1,3 @@
package core.game.bots
annotation class PlayerCompatible
@@ -0,0 +1,6 @@
package core.game.bots
object PlayerScripts {
class PlayerScript(val identifier: String, val description: Array<String>, val name: String, val clazz: Class<*>)
val identifierMap = HashMap<String, PlayerScript>()
}
+149
View File
@@ -0,0 +1,149 @@
package core.game.bots;
import java.util.ArrayList;
import java.util.List;
import core.game.consumable.Consumable;
import content.data.consumables.Consumables;
import core.game.consumable.Food;
import content.data.consumables.effects.HealingEffect;
import core.game.node.entity.skill.Skills;
import core.game.node.entity.Entity;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.prayer.PrayerType;
import core.game.node.item.Item;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.tools.RandomFunction;
public class PvMBots extends AIPlayer {
//Used so the bot doesn't spam actions
private int tick = 0;
public PvMBots(Location l) {
super(l);
}
public PvMBots(String copyFromFile, Location l) {
super(copyFromFile, l);
}
public List<Entity> FindTargets(Entity entity, int radius) {
List<Entity> targets = new ArrayList<>(20);
Object[] localNPCs = RegionManager.getLocalNpcs(entity,radius).toArray();
int length = localNPCs.length;
if(length > 5){length = 5;}
for (int i = 0; i < length; i++) {
NPC npc = (NPC) localNPCs[i];
{
if (checkValidTargets(npc))
targets.add(npc);
}
}
if (targets.size() == 0)
return null;
return targets;
}
public boolean checkValidTargets(NPC target) {
if (!target.isActive()) {
return false;
}
if (!target.getProperties().isMultiZone() && target.inCombat()) {
return false;
}
if (!target.getDefinition().hasAction("attack")) {
return false;
}
return true;
}
public boolean AttackNpcsInRadius(int radius)
{
return AttackNpcsInRadius(this, radius);
}
/**
* Attacks NPCs in radius of bot
* @param bot
* @param radius
* @return true if bot will be fighting
*/
public boolean AttackNpcsInRadius(Player bot, int radius) {
if (bot.inCombat())
return true;
List<Entity> creatures = FindTargets(bot, radius);
if (creatures == null) {
return false;
}
bot.attack(creatures.get(RandomFunction.getRandom((creatures.size() - 1))));
if (!creatures.isEmpty()) {
return true;
} else {
creatures = FindTargets(bot, radius);
if (!creatures.isEmpty())
{
bot.attack(creatures.get(RandomFunction.getRandom((creatures.size() - 1))));
return true;
}
return false;
}
}
@Override
public void tick() {
super.tick();
this.tick++;
//Despawn
if (this.getSkills().getLifepoints() <= 5){
//TODO: Just respawn a new bot (not sure how you'd do that :L)
// Maybe make all PvMBots know what to do if they aren't in right area? I.e. pest control bots teleport to PC
//this.teleport(new Location(500, 500));
//Despawning not being delayed causes 3 errors in the console
this.getSkills().setLifepoints(20);
}
//Npc Combat
/*if (this.tick % 10 == 0) {
if (!this.inCombat())
AttackNpcsInRadius(this, 5);
}*/
if (this.tick == 100) this.tick = 0;
//this.eat();
//this.getPrayer().toggle()
}
public void CheckPrayer(PrayerType type[]) {
for (int i = 0; i < type.length; i++)
this.getPrayer().toggle(type[i]);
}
public void eat(int foodId) {
Item foodItem = new Item(foodId);
if ((this.getSkills().getStaticLevel(Skills.HITPOINTS) >= this.getSkills().getLifepoints() * 3) && this.getInventory().containsItem(foodItem)) {
this.lock(3);
//this.animate(new Animation(829));
Item food = this.getInventory().getItem(foodItem);
Consumable consumable = Consumables.getConsumableById(food.getId());
if (consumable == null) {
consumable = new Food(new int[] {food.getId()}, new HealingEffect(1));
}
consumable.consume(food, this);
this.getProperties().getCombatPulse().delayNextAttack(3);
}
if (this.checkVictimIsPlayer() == false)
if (!(this.getInventory().contains(foodId, 1)))
this.getInventory().add(new Item(foodId, 5)); //Add Food to Inventory
}
}
@@ -0,0 +1,30 @@
package core.game.bots
import core.game.world.map.Location
import content.minigame.pestcontrol.bots.PestControlTestBot
import content.minigame.pestcontrol.bots.PestControlTestBot2
// import sun.util.resources.CalendarData;
class PvMBotsBuilder {
companion object {
var botsSpawned = 0
fun create(l: Location?): PvMBots {
botsSpawned++
return PvMBots(l)
}
@JvmStatic
fun createPestControlTestBot2(l: Location?): PestControlTestBot2 {
botsSpawned++
return PestControlTestBot2(l!!)
}
@JvmStatic
fun createPestControlTestBot(l: Location?): PestControlTestBot {
botsSpawned++
return PestControlTestBot(l!!)
}
}
}
@@ -0,0 +1,57 @@
package core.game.bots;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public abstract class Script {
public ScriptAPI scriptAPI;
public ArrayList<Item> inventory = new ArrayList<>(20);
public ArrayList<Item> equipment = new ArrayList<>(20);
public Map<Integer, Integer> skills = new HashMap<>();
public Player bot;
public boolean running = true;
public void init(boolean isPlayer)
{
//bot.init();
scriptAPI = new ScriptAPI(bot);
if(!isPlayer) {
for (Item i : equipment) {
bot.getEquipment().add(i, true, false);
}
bot.getInventory().clear();
for (Item i : inventory) {
bot.getInventory().add(i);
}
for (Map.Entry<Integer, Integer> skill : skills.entrySet()) {
setLevel(skill.getKey(), skill.getValue());
}
}
}
@Override
public String toString() {
return bot.getName() + " is a " + this.getClass().getSimpleName() + " at location " + bot.getLocation().toString() + " Current pulse: " + bot.getPulseManager().getCurrent();
}
public abstract void tick();
public void setLevel(int skill, int level) {
bot.getSkills().setLevel(skill, level);
bot.getSkills().setStaticLevel(skill, level);
bot.getSkills().updateCombatLevel();
bot.getAppearance().sync();
}
// This does not get called and all implementations should be removed
public abstract Script newInstance();
}
+827
View File
@@ -0,0 +1,827 @@
package core.game.bots
import core.api.*
import core.cache.def.impl.ItemDefinition
import core.game.component.Component
import core.game.consumable.Consumable
import content.data.consumables.Consumables
import core.game.consumable.Food
import content.data.consumables.effects.HealingEffect
import core.game.interaction.DestinationFlag
import core.game.interaction.MovementPulse
import core.game.interaction.Option
import core.game.node.Node
import core.game.node.scenery.Scenery
import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.GroundItem
import core.game.node.item.GroundItemManager
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.game.world.map.RegionManager
import core.game.world.map.path.Pathfinder
import core.game.world.update.flag.context.Animation
import core.game.world.update.flag.context.ChatMessage
import core.game.world.update.flag.context.Graphics
import core.game.world.update.flag.player.ChatFlag
import core.tools.RandomFunction
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.json.simple.JSONArray
import org.json.simple.JSONObject
import org.rs09.consts.Items
import core.ServerConstants.Companion.SERVER_GE_NAME
import core.game.ge.GrandExchange
import core.game.ge.GrandExchangeOffer
import core.game.interaction.IntType
import core.game.interaction.InteractionListeners
import core.tools.SystemLogger
import core.game.system.config.ItemConfigParser
import core.game.world.GameWorld
import core.game.world.repository.Repository
import core.tools.colorize
import java.util.*
import java.util.concurrent.CountDownLatch
import kotlin.math.max
import kotlin.math.pow
import kotlin.math.sqrt
class ScriptAPI(private val bot: Player) {
val GRAPHICSUP = Graphics(1576)
val ANIMATIONUP = Animation(8939)
val GRAPHICSDOWN = Graphics(1577)
val ANIMATIONDOWN = Animation(8941)
/**
* Gets the distance between two nodes
* @param n1 the first node
* @param n2 the second node
* @author Ceikry
*/
fun distance(n1: Node, n2: Node): Double {
return sqrt((n1.location.x - n2.location.x.toDouble()).pow(2.0) + (n2.location.y - n1.location.y.toDouble()).pow(2.0))
}
fun interact(bot: Player, node: Node?, option: String){
if(node == null) return
val type = when(node){
is Scenery -> IntType.SCENERY
is NPC -> IntType.NPC
is Item -> IntType.ITEM
else -> null
} ?: return
val opt: Option? = node.interaction.options.filter {it != null && it.name.equals(option, true) }.firstOrNull()
if(opt == null){
SystemLogger.logWarn(this::class.java, "Invalid option name provided: $option")
return
}
if(!InteractionListeners.run(node.id, type, option, bot, node)) node.interaction.handle(bot, opt)
}
/**
* Gets the nearest node with name entityName
* @param entityName the name of the node to look for
* @return the nearest node with a matching name or null
* @author Ceikry
*/
fun getNearestNode(entityName: String): Node? {
var entity: Node? = null
var minDistance = Double.MAX_VALUE
for (node in RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities) {
if (node != null && node.name == entityName && distance(bot, node) < minDistance && !Pathfinder.find(bot, node).isMoveNear) {
entity = node
minDistance = distance(bot, node)
}
}
return entity
}
fun sendChat(message: String) {
bot.sendChat(message)
bot.updateMasks.register(ChatFlag(ChatMessage(bot, message, 0, 0)))
}
/**
* Gets the nearest node with a name contained in the list of acceptable names
* @param acceptedNames the list of accepted npc/object names
* @return the nearest node with a matching name or null
* @author Ceikry
*/
fun getNearestNodeFromList(acceptedNames: List<String>, isObject: Boolean): Node? {
if (isObject) {
var entity: Node? = null
var minDistance = Double.MAX_VALUE
for (objects in RegionManager.forId(bot.location.regionId).planes[bot.location.z].objects) {
for(e in objects) {
val name = e?.name
if (e != null && acceptedNames.contains(name) && distance(bot, e) < minDistance && !Pathfinder.find(bot, e).isMoveNear && e.isActive) {
entity = e
minDistance = distance(bot, e)
}
}
}
return if(entity == null) null else entity as Scenery
} else {
var entity: Node? = null
var minDistance = Double.MAX_VALUE
for (e in RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities) {
val name = e?.name
if (e != null && acceptedNames.contains(name) && distance(bot, e) < minDistance && !Pathfinder.find(bot, e).isMoveNear) {
entity = e
minDistance = distance(bot, e)
}
}
return entity
}
}
/**
* Gets the nearest node with matching id.
* @param id the id to look for
* @param object whether or not the node we are looking for is an object.
* @return the closest node with matching id or null.
* @author Ceikry
*/
fun getNearestNode(id: Int, `object`: Boolean): Node? {
if (`object`) {
var entity: Node? = null
var minDistance = Double.MAX_VALUE
for (objects in RegionManager.forId(bot.location.regionId).planes[bot.location.z].objects) {
for(e in objects) {
if (e != null && e.id == id && distance(bot, e) < minDistance && !Pathfinder.find(bot, e).isMoveNear && e.isActive) {
entity = e
minDistance = distance(bot, e)
}
}
}
return if(entity == null) null else entity as Scenery
} else {
var entity: Node? = null
var minDistance = Double.MAX_VALUE
for (e in RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities) {
if (e != null && e.id == id && distance(bot, e) < minDistance && !Pathfinder.find(bot, e).isMoveNear) {
entity = e
minDistance = distance(bot, e)
}
}
return entity
}
}
/**
* Gets the nearest node with a matching name.
* @param name the name to look for.
* @param object whether or not the node we are looking for is an object.
* @return the nearest matching node or null.
* @author Ceikry
*/
fun getNearestNode(name: String, `object`: Boolean): Node? {
if (`object`) {
var entity: Node? = null
var minDistance = Double.MAX_VALUE
for (objects in RegionManager.forId(bot.location.regionId).planes[bot.location.z].objects) {
for(e in objects) {
if (e != null && e.name.toLowerCase() == name.toLowerCase() && distance(bot, e) < minDistance && !Pathfinder.find(bot, e).isMoveNear && e.isActive) {
entity = e
minDistance = distance(bot, e)
}
}
}
return if(entity == null) null else entity as Scenery
} else {
var entity: Node? = null
var minDistance = Double.MAX_VALUE
for (e in RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities) {
if (e != null && e.name.toLowerCase() == name.toLowerCase() && distance(bot, e) < minDistance && !Pathfinder.find(bot, e).isMoveNear) {
entity = e
minDistance = distance(bot, e)
}
}
return entity
}
}
/**
* Gets the nearest ground item with matching ID from the list in AIRepository.
* @param id the id of the ground item we are looking for.
* @return the nearest GroundItem with a matching id or null
* @author Ceikry
*/
private fun getNearestGroundItem(id: Int): GroundItem? {
var distance = 11.0
var closest: GroundItem? = null
if(AIRepository.getItems(bot) != null) {
for (item in AIRepository.getItems(bot)!!.filter { it: GroundItem -> it.distance(bot.location) < 10 }) {
if (item.id == id) {
//distance = item.distance(bot.location)
closest = item
}
}
if (!GroundItemManager.getItems().contains(closest)){
AIRepository.getItems(bot)?.remove(closest)
return null
}
} else {
val items: ArrayList<GroundItem>? = bot.getAttribute("botting:drops",null)
if(items != null){
for(item in items.filter { it.distance(bot.location) < 10 }){
if(item.id == id) return item.also { items.remove(item); bot.setAttribute("botting:drops",items) }
}
}
}
return closest
}
/**
* Takes the nearest ground item with a matching id if it exists.
* @param id the id to look for
* @author Ceikry
*/
fun takeNearestGroundItem(id: Int) : Boolean{
val item = getNearestGroundItem(id)
if(item != null){
item.interaction?.handle(bot, item.interaction[2])
return true
}
else return false
}
/**
* Gets the nearest GameObject to loc with matching objectId
* @param loc the location we are checking around
* @param objectId the id of the object we are looking for
* @return the nearest matching object or null.
* @author Ceikry
*/
fun getNearestGameObject(loc: Location, objectId: Int): Scenery? {
var nearestObject: Scenery? = null
val minDistance = Double.MAX_VALUE
for (o in RegionManager.forId(loc.regionId).planes[0].objects) {
for (obj in o) {
if (obj != null) {
if (distance(loc, obj) < minDistance && obj.id == objectId) {
nearestObject = obj
}
}
}
}
return nearestObject
}
/**
* Gets a list of NPCs that are attackable around the entity.
* @param entity the entity to search around.
* @param radius the radius around entity to search in.
* @param name the name of the NPC to look for.
* @return an Array of the nearest NPCs with matching name, or null.
* @author Ceikry
*/
private fun findTargets(entity: Entity, radius: Int, name: String? = null): List<Entity>? {
val targets: MutableList<Entity> = ArrayList()
val localNPCs: Array<Any> = RegionManager.getLocalNpcs(entity, radius).toTypedArray()
var length = localNPCs.size
if (length > 5) {
length = 5
}
for (i in 0 until length) {
val npc = localNPCs[i] as NPC
run { if (checkValidTargets(npc, name)) targets.add(npc) }
}
return if (targets.size == 0) null else targets
}
/**
* Checks if the given target is a valid target for a combat bot.
* @param target the NPC that we are checking
* @param name the expected name of the NPC.
* @return true if the target is valid, false if not.
* @author Ceikry
*/
private fun checkValidTargets(target: NPC, name: String?): Boolean {
if (!target.isActive) {
return false
}
if (!target.properties.isMultiZone && target.inCombat()) {
return false
}
if (name != null){
if(target.name != name)
return false
}
return target.definition.hasAction("attack")
}
/**
* Attacks npcs in the given radius of the bot.
* @param bot the bot that is attacking
* @param radius the radius to attack in
* @return true if successfully attacking an NPC within that radius, false if not.
* @author Ceikry
*/
fun attackNpcsInRadius(bot: Player, radius: Int): Boolean {
if (bot.inCombat()) return true
var creatures: List<Entity>? = findTargets(bot, radius) ?: return false
bot.attack(creatures!![RandomFunction.getRandom(creatures.size - 1)])
return if (creatures.isNotEmpty()) {
true
} else {
creatures = findTargets(bot, radius)
if (!creatures!!.isEmpty()) {
bot.attack(creatures[RandomFunction.getRandom(creatures.size - 1)])
return true
}
false
}
}
/**
* Function to iteratively walk a bot to a faraway location. Limited by doors and large obstacles like mountains.
* @param loc the location to walk to.
* @author Ceikry
*/
fun walkTo(loc: Location){
if(!bot.walkingQueue.isMoving) {
GlobalScope.launch {
walkToIterator(loc)
}
}
}
/**
* Function to iteratively walk an array of Locations to get over complex obstacles.
* @param steps the array of locations to walk to.
* @author dginovker
*/
fun walkArray(steps: Array<Location>){
bot.pulseManager.run(object : Pulse(){
var stepIndex = 0
override fun pulse(): Boolean {
// If the stepIndex is out of bounds, we're done
if(stepIndex >= steps.size) return true
// If we're near the last step, we're done
if (bot.location.withinDistance(steps[steps.size - 1], 2)) {
return true
}
// If we're not near the next step, walk to it
if (!bot.location.withinDistance(steps[stepIndex], 5)) {
walkTo(steps[stepIndex])
return false
}
// If we're near the next step, increment the step index
stepIndex++
return false
}
})
}
/**
* @param loc the location to walk to.
* @param radius tiles around the location the bot could walk to.
* @author Kermit
*/
fun randomWalkTo(loc: Location, radius: Int) {
if(!bot.walkingQueue.isMoving) {
GlobalScope.launch {
var newloc = loc.transform(RandomFunction.random(radius,-radius),
RandomFunction.random(radius,-radius), 0)
walkToIterator(newloc)
}
}
}
/**
* The iterator for long-distance walking. Limited by doors and large obstacles like mountains.
* @param loc the location to find a path to.
* @author Ceikry
*/
private fun walkToIterator(loc: Location){
var diffX = loc.x - bot.location.x
var diffY = loc.y - bot.location.y
while(!bot.location.transform(diffX, diffY, 0).withinDistance(bot.location)) {
diffX /= 2
diffY /= 2
}
GameWorld.Pulser.submit(object : MovementPulse(bot, bot.location.transform(diffX, diffY, 0), Pathfinder.SMART) {
override fun pulse(): Boolean {
return true
}
})
}
/**
* Attacks npcs in the given radius of the bot.
* @param bot the bot that is attacking
* @param radius the radius to attack in
* @param name the name of the NPC to target.
* @return true if successfully attacking an NPC within that radius, false if not.
* @author Ceikry
*/
fun attackNpcInRadius(bot: Player, name: String, radius: Int): Boolean {
if (bot.inCombat()) return true
var creatures: List<Entity>? = findTargets(bot, radius, name) ?: return false
bot.attack(creatures!![RandomFunction.getRandom(creatures.size - 1)])
return if (creatures.isNotEmpty()) {
true
} else {
creatures = findTargets(bot, radius, name)
if (!creatures!!.isEmpty()) {
bot.attack(creatures.random())
return true
}
false
}
}
/**
* Extension function to find the distance between a location and a ground item.
* @param loc the location to check the distance from.
* @return a Double representing the distance.
* @author Ceikry
*/
fun GroundItem.distance(loc: Location): Double{
return location.getDistance(loc)
}
/**
* A function for teleporting the bot to the GE
* @author Ceikry
*/
fun teleportToGE() : Boolean{
if (bot.isTeleBlocked) {
return false
}
bot.lock()
bot.visualize(ANIMATIONUP, GRAPHICSUP)
bot.impactHandler.disabledTicks = 4
val location = Location.create(3165, 3482, 0)
bot.pulseManager.run(object : Pulse(4, bot) {
override fun pulse(): Boolean {
bot.unlock()
bot.properties.teleportLocation = location
bot.animator.reset()
return true
}
})
return true
}
/**
* A function for selling a given item on the GE.
* @param id the ID of the item to sell on the GE. Pulls from the bot's bank.
* @author Ceikry
* @author Angle
*/
fun sellOnGE(id: Int){
class toCounterPulse : MovementPulse(bot, Location.create(3165, 3487, 0)){
override fun pulse(): Boolean {
var actualId = id
val itemAmt = bot.bank.getAmount(id)
if (ItemDefinition.forId(id).noteId == id){
actualId = Item(id).noteChange
}
val canSell = GrandExchange.addBotOffer(actualId, itemAmt)
if (canSell && saleIsBigNews(actualId, itemAmt)) {
SystemLogger.logAI(this::class.java, "Offered $itemAmt of $actualId on the GE.")
Repository.sendNews(SERVER_GE_NAME + " just offered " + itemAmt + " " + ItemDefinition.forId(actualId).name.toLowerCase() + " on the GE.")
}
bot.bank.remove(Item(id, itemAmt))
bot.bank.refresh()
return true
}
}
bot.pulseManager.run(toCounterPulse())
}
/**
* Function to sell all items in a bot's bank on the Grand Exchange, if they are tradable.
* @author Ceikry
*/
fun sellAllOnGe(){
class toCounterPulseAll : MovementPulse(bot, Location.create(3165, 3487, 0)){
override fun pulse(): Boolean {
for(item in bot.bank.toArray()) {
item ?: continue
if (item.id == Items.LOBSTER_379) continue
if (item.id == Items.SWORDFISH_373) continue
if (item.id == Items.SHARK_385) continue
if(!item.definition.isTradeable) {continue}
val itemAmt = item.amount
var actualId = item.id
if (ItemDefinition.forId(actualId).noteId == actualId){
actualId = Item(actualId).noteChange
}
val canSell = GrandExchange.addBotOffer(actualId, itemAmt)
if (canSell && saleIsBigNews(actualId, itemAmt)) {
Repository.sendNews(SERVER_GE_NAME + " just offered " + itemAmt + " " + ItemDefinition.forId(actualId).name.toLowerCase() + " on the GE.")
}
bot.bank.remove(item)
bot.bank.refresh()
}
return true
}
}
bot.pulseManager.run(toCounterPulseAll())
}
/**
* Function to sell all items in a bot's bank on the Grand Exchange, if they are tradable.
* @author Ceikry & Kermit
*/
fun sellAllOnGeAdv(){
val ge: Scenery? = getNearestNode("Desk", true) as Scenery?
class toCounterPulseAll : MovementPulse(bot, ge, DestinationFlag.OBJECT) {
override fun pulse(): Boolean {
for(item in bot.bank.toArray()) {
item ?: continue
if(!item.definition.isTradeable) {continue}
val itemAmt = item.amount
var actualId = item.id
if (ItemDefinition.forId(actualId).noteId == actualId){
actualId = Item(actualId).noteChange
}
val canSell = GrandExchange.addBotOffer(actualId, itemAmt)
if (canSell && saleIsBigNews(actualId, itemAmt)) {
when (actualId){
1511 -> continue
1513 -> continue
1515 -> continue
1517 -> continue
1519 -> continue
1521 -> continue
else -> Repository.sendNews(SERVER_GE_NAME + " just offered " + itemAmt + " " + ItemDefinition.forId(actualId).name.toLowerCase() + " on the GE.")
}
}
bot.bank.remove(item)
bot.bank.refresh()
}
return true
}
}
bot.pulseManager.run(toCounterPulseAll())
}
/**
* Function to determine whether or not to bother everyone on the server
* with the big news that a bot is selling something to the GE, based on item value
* @param itemID
* @param amount
* @author Gexja
*/
fun saleIsBigNews(itemID: Int, amount: Int): Boolean {
return ItemDefinition.forId(itemID).getAlchemyValue(true) * amount >= 500
}
/**
* Function to teleport a bot to the given location.
* @param loc the location to teleport to
* @author Ceikry
*/
fun teleport(loc: Location) : Boolean {
if (bot.isTeleBlocked) {
return false
}
bot.lock()
bot.visualize(ANIMATIONUP, GRAPHICSUP)
bot.impactHandler.disabledTicks = 4
val location = loc
GameWorld.Pulser.submit(object : Pulse(4, bot) {
override fun pulse(): Boolean {
bot.unlock()
bot.properties.teleportLocation = location
bot.animator.reset()
return true
}
})
return true
}
/**
* Takes the given item out of the bot's inventory and places it into the bank. Banks all items with matching ID.
* @param item the ID of the item to bank
* @author Ceikry
*/
fun bankItem(item: Int){
class BankingPulse() : Pulse(20){
override fun pulse(): Boolean {
val logs = bot.inventory.getAmount(item)
bot.inventory.remove(Item(item, logs))
bot.bank.add(Item(item, logs))
return true
}
}
bot.pulseManager.run(BankingPulse())
}
/**
* Takes every item out of the bots inventory and places it into the bank.
* @param none
* @author cfunnyman joe
*/
fun bankAll(){
class BankingPulse() : Pulse(20){
override fun pulse(): Boolean {
for(item in bot.inventory.toArray()){
var itemAmount = bot.inventory.getAmount(item)
bot.inventory.remove(item)
bot.bank.add(item)
}
return true
}
}
bot.pulseManager.run(BankingPulse())
}
/**
* Function that makes the bot eat the food item in their inventory if their HP is below 2/3.
* @author Ceikry
* @param foodId the ID of the food item to eat
*/
fun eat(foodId: Int) {
val foodItem = Item(foodId)
if (bot.skills.getStaticLevel(Skills.HITPOINTS) * RandomFunction.random(0.5, 0.75) >= bot.skills.lifepoints && bot.inventory.containsItem(foodItem)) {
bot.lock(3)
//this.animate(new Animation(829));
val food = bot.inventory.getItem(foodItem)
var consumable: Consumable? = Consumables.getConsumableById(foodId)
if (consumable == null) {
consumable = Food(intArrayOf(food.id), HealingEffect(1))
}
consumable.consume(food, bot)
bot.properties.combatPulse.delayNextAttack(3)
}
}
/**
* Same as the eat function, except that it forces the bot to eat regardless of HP.
* @author Ceikry
* @param foodId the ID of the food item to eat.
*/
fun forceEat(foodId: Int) {
val foodItem = Item(foodId)
if (bot.inventory.containsItem(foodItem)) {
bot.lock(3)
//this.animate(new Animation(829));
val food = bot.inventory.getItem(foodItem)
var consumable: Consumable? = Consumables.getConsumableById(foodId)
if (consumable == null) {
consumable = Food(intArrayOf(foodId), HealingEffect(1))
}
consumable.consume(food, bot)
bot.properties.combatPulse.delayNextAttack(3)
}
}
/**
* Function for buying items off the GE.
* @param itemID the id of the item to buy off the GE.
* @param amount the amount to buy.
* @return true if item was successfully bought, false if not.
*/
fun buyFromGE(bot: Player, itemID: Int, amount: Int){
GlobalScope.launch {
val offer = GrandExchangeOffer()
offer.itemID = itemID
offer.sell = false
offer.offeredValue = checkPriceOverrides(itemID) ?: ItemDefinition.forId(itemID).value
offer.amount = amount
offer.player = bot
//GrandExchange.dispatch(bot, offer)
AIRepository.addOffer(bot, offer)
var bought: Boolean = false
val latch = CountDownLatch(1)
bot.pulseManager.run(object : Pulse(5) {
override fun pulse(): Boolean {
bought = offer.completedAmount == offer.amount
latch.countDown()
return true
}
})
latch.await()
if(bought){
bot.bank.add(Item(offer.itemID, offer.completedAmount))
bot.bank.refresh()
}
}
}
/**
* Method to allow a bot to withdraw items from its bank.
* @param itemID the item to withdraw.
* @param amount the amount to withdraw.
* @author Ceikry
*/
fun withdraw(itemID: Int, amount: Int){
var item: Item? = null
if(bot.bank.containsItem(Item(itemID, amount))){
item = Item(itemID, amount)
} else {
item = Item(itemID, bot.bank.getAmount(itemID))
}
if(item.amount == 0) return
if(!bot.inventory.hasSpaceFor(item)){
item.amount = bot.inventory.getMaximumAdd(item)
}
bot.bank.remove(item)
bot.inventory.add(item)
}
/**
* Method to equip list of items and set stats
* Useful for starting a bot up
* @param items the list of items to equip
* @author dginovker
*/
fun equipAndSetStats(items: List<Item>?){
if (items == null) return
for(item in items){
equipAndSetStats(item)
}
}
/**
* Method to equip a single item and set stats
* Useful for starting a bot up
* @param item the item to equip
* @author dginovker
*/
fun equipAndSetStats(item: Item){
val configs = item.definition.handlers
val slot = configs["equipment_slot"] ?: return
bot.equipment.add(item, slot as Int,
false,false)
val reqs = configs["requirements"]
if(reqs != null)
for(req in configs["requirements"] as HashMap<Int,Int>)
bot.skills.setStaticLevel(req.key, req.value)
bot.skills.updateCombatLevel()
}
/**
* Method to load appearance and equipment from JSON
* Useful for starting a bot up
* @param json the JSON object to load from (dumped via ::dumpappearance)
* @author dginovker
*/
fun loadAppearanceAndEquipment(json: JSONObject?) {
if (json == null) return
bot.equipment.clear()
bot.appearance.parse(json["appearance"] as JSONObject)
val equipment = json["equipment"] as JSONArray
bot.equipment.parse(equipment)
bot.appearance.sync()
for (i in 0 until bot.equipment.capacity()) {
val item = bot.equipment.get(i)
if (item != null) {
equipAndSetStats(item)
}
}
// Set all combat stats to a function of the highest combat stat(otherwise you end up with lopsided stats)
val highestCombatSkill = bot.skills.getStaticLevel(bot.skills.highestCombatSkillId)
for (i in 0 until 7) {
bot.skills.setStaticLevel(i, max((highestCombatSkill * 0.75).toInt(), bot.skills.getStaticLevel(i)))
}
bot.skills.updateCombatLevel()
}
fun getOverlay(): BottingOverlay {
return BottingOverlay(bot)
}
/**
* Function to check for price overrides.
* @param id the id to check for overrides for.
* @author Ceikry
*/
fun checkPriceOverrides(id: Int): Int?{
return when(id){
else -> itemDefinition(id).getConfiguration(ItemConfigParser.GE_PRICE)
}
}
class BottingOverlay(val player: Player){
fun init(){
player.interfaceManager.openOverlay(Component(195))
player.packetDispatch.sendInterfaceConfig(195,5,true)
}
fun setTitle(title: String){
player.packetDispatch.sendString(colorize("%B$title"),195,7)
}
fun setTaskLabel(label: String){
player.packetDispatch.sendString(colorize("%B$label"),195,8)
}
fun setAmount(amount: Int){
player.packetDispatch.sendString(colorize("%B$amount"),195,9)
}
}
}
@@ -0,0 +1,3 @@
package core.game.bots
annotation class ScriptDescription(vararg val value: String)
@@ -0,0 +1,3 @@
package core.game.bots
annotation class ScriptIdentifier(val value: String)
@@ -0,0 +1,3 @@
package core.game.bots
annotation class ScriptName(val value: String)
@@ -0,0 +1,44 @@
package core.game.bots
import core.game.node.item.Item
import core.game.world.map.Location
class SkillingBotAssembler {
fun produce(type: Wealth, loc: Location): AIPlayer {
return assembleBot(AIPlayer(loc),type)
}
fun assembleBot(bot: AIPlayer, type: Wealth): AIPlayer {
return when(type){
Wealth.POOR -> equipSet(bot,POORSETS.random())
Wealth.AVERAGE -> equipSet(bot,AVGSETS.random())
Wealth.RICH -> equipSet(bot,RICHSETS.random())
}
}
fun equipSet(bot: AIPlayer, set: List<Int>): AIPlayer {
for(i in set){
val item = Item(i)
val configs = item.definition.handlers
val slot = configs["equipment_slot"] ?: continue
bot.equipment.add(item, slot as Int,
false,false)
val reqs = configs["requirements"]
if(reqs != null)
for(req in configs["requirements"] as HashMap<Int,Int>)
bot.skills.setStaticLevel(req.key, req.value)
}
bot.skills.updateCombatLevel()
return bot
}
enum class Wealth {
POOR,
AVERAGE,
RICH
}
val POORSETS = arrayOf(listOf(542,544), listOf(581), listOf(6654,6655,6656), listOf(6654,6656), listOf(636,646), listOf(638,648), listOf(), listOf(), listOf())
val AVGSETS = arrayOf(listOf(2649,342,344), listOf(2651,542,544), listOf(6654,6655,6656), listOf(6139,6141), listOf(9923,9924,9925), listOf(10400,10402,2649), listOf(10404,10406), listOf(12971,12978))
val RICHSETS = arrayOf(listOf(10330,10332,2649), listOf(12873,12880,1046), listOf(13858,13861,13864), listOf(13887,13893), listOf(3481,3483), listOf(2653,2655), listOf(2661,2663), listOf(2591,2593), listOf(14490,14492))
}