summaryrefslogblamecommitdiff
path: root/plugins/battlebot.py
blob: 5cba46755b71bb18fe6ae206a1e8056f3e53fb98 (plain) (tree)


































































































































































































































                                                                             
import time
import net.mapserv as mapserv
import net.charserv as charserv
import net.stats as stats
import walkto
import logicmanager
import commands
from net.common import distance
from net.inventory import get_item_index
from utils import extends
from loggers import debuglog
from actor import find_nearest_being


__all__ = [ 'PLUGIN', 'init',
            'hp_healing_ids', 'hp_heal_at', 'mp_healing_ids', 'mp_heal_at',
            'auto_attack', 'auto_pickup', 'auto_heal_self',
            'auto_heal_others' ]


PLUGIN = {
    'name': 'battlebot',
    'requires': (),
    'blocks': (),
}

target = None
# last_time_attacked = 0
aa_next_time = 0

hp_healing_ids = [ 535, 541 ]
hp_heal_at = 0.3
hp_is_healing = False
hp_prev_value = 0

mp_healing_ids = [ 826 ]
mp_heal_at = 0.5
mp_is_healing = False
mp_prev_value = 0

players_taken_damage = {}
player_damage_heal = 300

aa_monster_types = []

auto_pickup = True
auto_attack = False
auto_heal_self = False
auto_heal_others = False


@extends('smsg_being_action')
def being_action(data):
    # global last_time_attacked
    global aa_next_time

    if data.type in (0, 10):

        if data.src_id == charserv.server.account:
            # last_time_attacked = time.time()
            aa_next_time = time.time() + 5.0

        if (auto_heal_others and
                data.dst_id != charserv.server.account and
                data.dst_id in mapserv.beings_cache and
                mapserv.beings_cache[data.dst_id].type == 'player'):

            players_taken_damage[data.dst_id] = players_taken_damage.get(
                data.dst_id, 0) + data.damage

            if players_taken_damage[data.dst_id] >= player_damage_heal:
                mapserv.cmsg_chat_message("#inma {}".format(
                    mapserv.beings_cache[data.dst_id].name))
                players_taken_damage[data.dst_id] = 0


@extends('smsg_item_dropped')
@extends('smsg_item_visible')
def flooritem_appears(data):
    if not auto_pickup:
        return

    item = mapserv.floor_items[data.id]
    px = mapserv.player_pos['x']
    py = mapserv.player_pos['y']

    if distance(px, py, item.x, item.y) > 3:
        return

    walkto.walkto_and_action(item, 'pickup')


@extends('smsg_player_status_change')
def player_status_change(data):
    global hp_is_healing
    if data.id == charserv.server.account:
        if data.effect == 256:
            hp_is_healing = True
        elif data.effect == 0:
            hp_is_healing = False


@extends('smsg_player_stat_update_x')
def player_stat_update(data):
    if not auto_heal_self:
        return

    global hp_prev_value, mp_prev_value

    if data.type == stats.HP:
        max_hp = mapserv.player_stats.get(stats.MAX_HP, 0)
        if data.stat_value < max_hp * hp_heal_at and not hp_is_healing:
            healing_found = False
            for item_id in hp_healing_ids:
                index = get_item_index(item_id)
                if index > 0:
                    healing_found = True
                    debuglog.info("Consuming %d", item_id)
                    mapserv.cmsg_player_inventory_use(index, item_id)
                    break
            if not healing_found:
                debuglog.info("Low health, but no HP healing item found")

        hp_prev_value = data.stat_value

    elif data.type == stats.MP:
        max_mp = mapserv.player_stats.get(stats.MAX_MP, 0)
        if data.stat_value < max_mp * mp_heal_at and not mp_is_healing:
            healing_found = False
            for item_id in mp_healing_ids:
                index = get_item_index(item_id)
                if index > 0:
                    healing_found = True
                    debuglog.info("Consuming %d", item_id)
                    mapserv.cmsg_player_inventory_use(index, item_id)
                    break

            if not healing_found:
                debuglog.info("Low mana, but no MP healing item found")

        mp_prev_value = data.stat_value


@extends('smsg_being_remove')
def being_remove(data):
    global target
    if target is not None and target.id == data.id:
        target = None
        aa_next_time = time.time() + 5.0


def battlebot_logic(ts):

    if not auto_attack:
        return

    global target
    # global last_time_attacked
    global aa_next_time

    if ts < aa_next_time:
        return

    if target is None:
        if walkto.state:
            return

        target = find_nearest_being(type='monster',
                                    ignored_ids=walkto.unreachable_ids,
                                    allowed_jobs=aa_monster_types)
        if target is not None:
            # last_time_attacked = time.time()
            aa_next_time = time.time() + 5.0
            walkto.walkto_and_action(target, 'attack')

    elif ts > aa_next_time:
        walkto.walkto_and_action(target, 'attack')


def startbot(_, arg):
    '''Start autoattacking and autolooting'''
    global auto_attack
    global auto_pickup
    global aa_monster_types
    auto_attack = True
    auto_pickup = True
    try:
        aa_monster_types = map(int, arg.split())
    except ValueError:
        aa_monster_types = []


def stopbot(cmd, _):
    '''Stop battlebot'''
    global auto_attack
    global auto_pickup
    global auto_heal_self
    global auto_heal_others
    global target
    auto_attack = False
    auto_pickup = False
    auto_heal_self = False
    auto_heal_others = False
    if target is not None:
        mapserv.cmsg_player_stop_attack()
        target = None


def debugbot(cmd, _):
    px = mapserv.player_pos['x']
    py = mapserv.player_pos['y']
    target_info = '<no_target>'
    if target is not None:
        target_info = '{} at ({},{})'.format(target.name, target.x, target.y)
    debuglog.info('target = %s | player at (%d, %d)', target_info, px, py)


bot_commands = {
    'startbot' : startbot,
    'stopbot'  : stopbot,
    'debugbot' : debugbot,
}


def init(config):
    logicmanager.logic_manager.add_logic(battlebot_logic)
    commands.commands.update(bot_commands)