# Copyright (c) 1997 Cabochon Technologies, Inc.  All rights reserved.

"""
Magically enchants a weapon.
Author:  rhialto, fenixdown
"""

from wyvern.lib import Range, Kernel, Weapon, Monster
from wyvern.lib.classes.magic import Spell
from wyvern.lib.predicates import ClassPredicate

"""
This class desperately needs to be made a subclass of enchant_armor.
Not sure how to do that yet.  -Rhialto
"""

class enchant_weapon(Spell):

    def start(self):
        target = self.get_target()

        if target is None or not self.enchantable(target):
            return

        if Range.percent() < self.get_destroy_chance(target):
            self.blow_up_weapon(self.agent, target)
            return

        self.modify_weapon(target, target.toString())


    def modify_weapon(self, target, desc):
        if self.isCursed():
            self.do_cursed_effects(target, desc)
            return

        # increment enchantment counter
        target.adjustIntProperty("wc-magic", 1)
        target.adjustIntProperty("to-hit", 1)
        target.adjustIntProperty("enchantment", 1)
        self.set_enchant_info(target)
        self.increase_value(target)
        self.upgrade_curse_level(target, desc)


    def get_target(self):
        target = self.findTargetObject()

        # no target specified => operate on first weapon in inv
        if target is None:
            target = self.find_first_weapon(self.agent)

        if target is None:
            self.tellCaster("Cast enchant weapon on what?")

        return target


    def set_enchant_info(self, target):
        target.setProperty("enchanted-by", self.agent.name)
        target.setProperty("enchanted-on", Kernel.getDate())


    def upgrade_curse_level(self, target, desc):
        # remove curse.  damned goes to cursed.
        if target.hasProperty("damned"):
            target.removeProperty("damned")
            target.addProperty("cursed")

        elif target.hasProperty("cursed"):
            target.removeProperty("cursed")

        # if scroll was blessed, bless the item
        elif self.isBlessed():
            target.addProperty("blessed")

        target.invalidateText()
        self.tellCaster("Your " + desc + " glows blue for a moment.")


    def increase_value(self, target):
        # this is actually pretty close to how much people
        # have to pay to enchant them to the corresponding level
        if not target.hasProperty("groupable"):
            if target.value <= 0:
                target.setIntProperty("value", 0)
            else:
                value = target.getIntProperty('value')
                target.setIntProperty("value", value * 2)


    def do_cursed_effects(self, target, desc):
        # decrement enchantment counter and curse the item
        target.adjustIntProperty("wc-magic", -1)
        target.adjustIntProperty("to-hit", -1)
        target.adjustIntProperty("enchantment", -1)
        target.curse()

        self.tellCaster("Your %s glows with a black aura." % desc)
        self.reduce_value(target)


    def reduce_value(self, target):
        # don't adjust value for missiles - it's kinda gross
        # (numbers like 730275418)
        if not target.hasProperty("groupable"):
            if target.value <= 0:
                target.setIntProperty("value", 0)
            else:
                target.setIntProperty("value", target.value / 2)


    def enchantable(self, target):
        """Checks if this is an enchantable weapon.

        If not, issues a message to the caster and returns false.
        If it's enchantable, it returns true.
        """

        if target is None:
            return 0

        if (target.hasProperty("unique") or
            target.hasProperty("no-enchant") or
            not isinstance(target, Weapon )):

            self.tellCaster(`target` + " is not an enchantable weapon.")
            return 0

        if target.quantity > 1:
            self.tellCaster("You can only enchant one at a time.")
            return 0

        return 1



    def get_destroy_chance(self, target):
        # chance the thing will blow depends on enchantment level
        enchant = target.getIntProperty("enchantment")
        chance = enchant * 20

        if self.isBlessed():
            chance = enchant * 15;

        # take into account earth and spirit
        chance -= self.getLevel(self.EARTH_AND_SPIRIT)
        return chance


    def find_first_weapon(self, agent):
        """Locates first weapon the agent is carrying."""
        p = ClassPredicate(Weapon)
        return agent.inventory.find(p)


    def blow_up_weapon(self, agent, weapon):
        msg = self.get_destroy_message(weapon)
        self.tellCaster(msg)

        # this takes care of removing from ground or inv
        weapon.destroy();

        if not isinstance(agent, Monster):
            return

        # hurt the user too
        self.setIntProperty("wc-magic", 10)
        self.damageMonster(self.agent, self)


    def get_destroy_message(self, weapon):
        name = weapon.toString()
        return ("Your " + name + " glows with a blinding white light!\n" +
                "Your " + name + " explodes!")

    def consumeReagents(self, agent):
        """Finds and consumes the required reagent(s).  We have
        special reagent needs, so we do it manually.

        Returns true if the had the right reagents.
        """

        if self.getMagicItem() is not None:
            return 1

        if agent is None or agent.inventory is None:
            return 0

        return self.find_reagent(agent)


    def find_reagent(self, agent):
        for i in agent.inventory.objects():
            if self.is_usable_reagent(i):
                self.adjust_quantity_in_inventory(i, agent)
                return 1

        # didn't find it
        return 0


    def is_usable_reagent(self, obj):
        return (obj.value >= 1000 and
                Kernel.isInstance(obj, self.get_reagent_type()))


    def adjust_quantity_in_inventory(self, obj, agent):
        if obj.quantity > 1:
            obj.quantity = obj.quantity - 1
        else:
            agent.inventory.remove(obj)


    def get_reagent_type(self):
        """Returns the type of gem to use as a reagent.

        Return:  the archetype path
        """

        return "objects/treasure/diamond"


    def canDamageSelf(self, caster, spell):
        return 1