# Balazar # Copyright (C) 2003-2005 Jean-Baptiste LAMY # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA import random import tofu, soya, soya.tofu4soya, soya.sdlconst as sdlconst from soya.ray import Ray, HalfRay import balazar, balazar.base as base class KillRay(soya.Point): def __init__(self, parent = None, x = 0.0, y = 0.0, z = 0.0, dir_x = 0.0, dir_y = 0.0, dir_z = -1.0): soya.Point.__init__(self, parent, x, y, z) self.dir = soya.Vector(parent, dir_x, dir_y, dir_z) self.length = self.dir.length() #soya.Face(parent, [soya.Vertex(parent, x, y, z), soya.Vertex(parent, x + dir_x, y + dir_y, z + dir_z)]) UP = soya.Vector(None, 0.0, 1.0, 0.0) class Item(soya.World, base.Entity, base.Discutable, tofu.Unique): blessed = 0 price = 0 can_rotate = 1 equiped = 0 discussion_radius = 2.0 def __deepcopy__(self, memo): memo[id(self.owner)] = None return soya.World.__deepcopy__(self, memo) def __init__(self, parent = None): tofu.Unique.__init__(self) soya.World.__init__(self, parent) self.owner = None self.duration = 50 def start_discussion(self, hero): from balazar.character import ItemAction, ACTION_GRAB_ITEM from balazar.game_interface import Discussion Discussion(hero, u"", _(u"Objet au sol : %s") % base.display_name(self), check = lambda : hero.distance_to(self) < self.discussion_radius, source = self, choices = [ Discussion(hero, _(u"Ramasser"), action = lambda : hero.doer.do_action(ItemAction(ACTION_GRAB_ITEM, self)), ), ]).activate(1) def kesako(self): return _("__kesako__%s" % self.__class__.__name__) def display_name(self): return _("__item__%s" % self.__class__.__name__) def incompatible_with(self, other): return 0 def set_owner(self, character): self.owner = character self.visible = 1 self.duration = 25 + abs(self.blessed) * 50 def fighting_bonus (self, target): return 0.0 def resistance_bonus(self, target): return 0.0 def zap(self): pass def set_inventory_pos(self): """Set the item in the right position / orientation, when it is displayed in the inventory""" self.set_identity() self.rotate_vertical(90.0) self.rotate_lateral (90.0) min, max = self.get_box() self.y = -(min.y + max.y) / 2.0 def set_ground_pos(self, ground = None, dir = None, ground_normal = None): """Set the item in the right position / orientation, when it is on ground""" #self.set_identity() if ground: self.move(ground) self.y += 0.05 if dir: self.look_at(dir) self.look_at_y(ground_normal or UP) if self.can_rotate: self.turn_incline(90.0) self.zap() def loaded(self): tofu.Unique.loaded(self) soya.World .loaded(self) def big_round(self): self.duration -= 1 if self.duration < 1: soya.IDLER.next_round_tasks.append(self.destroy) def begin_round(self): if self.duration < 6: self.visible = soya.IDLER.big_round_count % 2 def destroy(self): if self.parent: self.parent.remove(self) class UseableItem(Item): def used_by(self, user): pass class EquipableItem(Item): def __init__(self, parent): Item.__init__(self, parent) self.equiped = 0 def unequip_incompatible_items(self): for item in self.owner.items: if isinstance(item, EquipableItem) and item.equiped and item.incompatible_with(self): item.owner.doer.do_action(balazar.character.ItemAction(balazar.character.ACTION_UNEQUIP_ITEM, item)) def set_equiped(self, equiped): self.equiped = equiped def set_owner(self, owner): if self.equiped: self.set_equiped(0) Item.set_owner(self, owner) class RightHandItem(EquipableItem): def incompatible_with(self, other): return isinstance(other, RightHandItem) def set_equiped(self, equiped): if equiped == self.equiped: return EquipableItem.set_equiped(self, equiped) if equiped: self.owner.right_hand_item = self self.owner.right_hand = soya.World(self.owner) self.owner.perso.attach_to_bone(self.owner.right_hand, "mainD") self.owner.right_hand.add(self) self.set_identity() self.set_equiped_pos() self.zap() else: self.owner.right_hand_item = None #print self.parent, self.parent.parent self.parent.remove(self) self.owner.perso.detach_from_bone(self.owner.right_hand) self.owner.remove(self.owner.right_hand) del self.owner.right_hand def set_equiped_pos(self): self.rotate_incline(180.0) self.set_xyz(0.05, 0.1, 0.0) class LeftHandItem(EquipableItem): def incompatible_with(self, other): return isinstance(other, LeftHandItem) def set_equiped(self, equiped): EquipableItem.set_equiped(self, equiped) if equiped: self.owner.left_hand_item = self self.owner.left_hand = soya.World(self.owner) self.owner.perso.attach_to_bone(self.owner.left_hand, "mainG") self.owner.left_hand.add(self) self.set_identity() self.set_equiped_pos() self.zap() else: self.owner.left_hand_item = None self.parent.remove(self) self.owner.perso.detach_from_bone(self.owner.left_hand) self.owner.remove(self.owner.left_hand) def set_equiped_pos(self): self.set_xyz(0.0, 0.1, 0.0) class Weapon(RightHandItem): range = 1.0 # Used by AI hurt_weapon = 1 def set_equiped(self, equiped): RightHandItem.set_equiped(self, equiped) if equiped: self.owner.weapon = self self.owner.kill_rays = self.kill_rays else: self.owner.weapon = None self.owner.kill_rays = () def display_name(self): self.equiped = 1 r = _(u"__item__%s" % self.__class__.__name__) + u" (+%s)" % int(round(self.fighting_bonus(None))) self.equiped = 0 return r class Camera(LeftHandItem): price = 50 def __init__(self, parent = None): LeftHandItem.__init__(self, parent) self.set_shape(soya.Shape.get("camera")) def set_equiped_pos(self): self.rotate_lateral(25.0) self.set_xyz(-0.05, 0.34, 0.0) photo_model = soya.World() soya.Face(photo_model, [ soya.Vertex(photo_model, -0.5333, 0.36, 0.0, 0.005, 0.005), soya.Vertex(photo_model, 0.5333, 0.36, 0.0, 0.995, 0.005), soya.Vertex(photo_model, 0.5333, -0.36, 0.0, 0.995, 0.995), soya.Vertex(photo_model, -0.5333, -0.36, 0.0, 0.005, 0.995), ]).double_sided = 1 class Photo(UseableItem): price = 1 def __init__(self, parent = None, image = None, content = []): UseableItem.__init__(self, parent) self.image = image self.content = content photo_model.children[0].material = material = soya.Material(soya.image_from_pil(image.resize((64, 64)))) material.clamp = 1 self.shape = photo_model.shapify() photo_model.children[0].material = soya.DEFAULT_MATERIAL self.life = 250 def __deepcopy__(self, memo): memo[id(self.image)] = self.image memo[id(self.shape)] = self.shape return UseableItem.__deepcopy__(self, memo) def set_owner(self, character): UseableItem.set_owner(self, character) if not character: self.life = 250 def begin_round(self): self.life -= 1 if self.life == 0: soya.IDLER.next_round_tasks.append(self.destroy) def destroy(self): if self.parent: self.parent.remove(self) def set_inventory_pos(self): self.set_identity() def used_by(self, user): if user.controller.local and user.player: import balazar.discussion import balazar.inventory balazar.discussion.Bubble(soya.root_widget, user, balazar.inventory.PhotoViewer(self)).set_focus(1) def display_name(self): if len(self.content) < 3: content = self.content else: content = self.content[:2] + ["..."] return _("__item__%s" % self.__class__.__name__) + u" (%s : %s)" % (self.score, ", ".join(content)) def full_display_name(self): return _("__item__%s" % self.__class__.__name__) + u" (%s : %s)" % (self.score, ", ".join(self.content)) def kesako(self): return _("__kesako__%s" % self.__class__.__name__) + u"\n%s" % ", ".join(self.content) class Sword(Weapon): price = 100 range = 1.9 def __init__(self, parent = None): Weapon.__init__(self, parent) self.set_shape(soya.Shape.get("epee")) #m = soya.Material() #m.diffuse = [168 / 255.0, 165 / 255.0, 108 / 255.0, 1.0] #m.separate_specular = 1 #m.filename = "epee_rayon" #m.save() m = soya.Material.get("epee_rayon") self.ray = HalfRay(self, soya.Material.get("epee_rayon")) self.ray.z = -0.16 self.ray.endpoint.z = -1.7 self.ray.length = 5 self.kill_rays = [ KillRay(self, 0.0, 0.2, 0.0, 0.0, 0.0, -1.9), KillRay(self, 0.0, -0.2, 0.0, 0.0, 0.0, -1.9), ] self.prot = soya.Volume(self, soya.Shape.get("epee_prot")) self.prot.visible = self.prot.solid = 0 def fighting_bonus(self, target): if self.equiped: return 2.0 return 0.0 def zap(self): self.ray.zap() class LargeSword(Weapon): price = 100 range = 1.2 def __init__(self, parent = None): Weapon.__init__(self, parent) self.set_shape(soya.Shape.get("epee_large")) #m = soya.Material() #m.diffuse = [168 / 255.0, 165 / 255.0, 108 / 255.0, 1.0] #m.separate_specular = 1 #m.filename = "epee_rayon" #m.save() m = soya.Material.get("epee_rayon") self.ray = HalfRay(self, soya.Material.get("epee_rayon")) self.ray.z = -0.16 self.ray.endpoint.z = -1.0 self.ray.length = 5 self.kill_rays = [ KillRay(self, 0.0, 0.2, 0.0, 0.0, 0.0, -1.2), KillRay(self, 0.0, -0.2, 0.0, 0.0, 0.0, -1.2), ] self.prot = soya.Volume(self, soya.Shape.get("epee_prot")) self.prot.visible = self.prot.solid = 0 def fighting_bonus(self, target): if self.equiped: return 4.0 return 0.0 def zap(self): self.ray.zap() class TuryleSword(Weapon): blessed = 2 price = 100 range = 2.0 def __init__(self, parent = None): Weapon.__init__(self, parent) self.set_shape(soya.Shape.get("epee_turyle")) self.ray = HalfRay(self, soya.Material.get("epee_turyle_rayon")) self.ray.z = -0.16 self.ray.endpoint.z = -1.8 self.ray.length = 5 self.kill_rays = [ KillRay(self, 0.0, 0.2, 0.0, 0.0, 0.0, -2.0), KillRay(self, 0.0, -0.2, 0.0, 0.0, 0.0, -2.0), ] self.prot = soya.Volume(self, soya.Shape.get("epee_turyle_prot")) self.prot.visible = self.prot.solid = 0 # import soya.sphere as sphere # m = soya.Material() # m.diffuse = 1.0, 0.0, 0.0, 0.5 # m. # w = sphere.Sphere(None, m) # w.scale(1.3, 1.3, 1.3) # soya.Volume(self, w.shapify()).move(self.kill_point) # Halo (ideal pour un baton magique) # import soya.sphere as sphere # m = soya.Material() # m.diffuse = 0.15, 0.1, 0.2, 1.0 # m.diffuse = 0.5, 0.4, 0.8, 1.0 # m.additive_blending = 1 # w = sphere.Sphere(None, m) # w.scale(1.3, 1.3, 1.3) # soya.Volume(self, w.shapify()).move(self.kill_point) def fighting_bonus(self, target): if self.equiped: return 5.0 return 0.0 def zap(self): self.ray.zap() class Axe(Weapon): range = 1.7 price = 30 def __init__(self, parent = None): Weapon.__init__(self, parent) self.set_shape(soya.Shape.get("hache")) self.ray = HalfRay(self, soya.Material.get("couteau_rayon")) self.ray. set_xyz(0.0, -0.5, -0.4) self.ray.endpoint.set_xyz(0.0, 0.0, -1.1) self.ray.length = 5 self.kill_rays = [ KillRay(self, 0.0, 0.15, 0.0, 0.0, 0.0, -1.5), KillRay(self, 0.0, -0.15, 0.0, 0.0, -0.6, -1.2), ] self.prot = soya.Volume(self, soya.Shape.get("hache_prot")) self.prot.visible = self.prot.solid = 0 def fighting_bonus(self, target): if self.equiped: return 2.0 return 0.0 def zap(self): self.ray.zap() class HalfVisibleAxe(Axe): price = 80 blessed = 1 hurt_weapon = 0 def __init__(self, parent = None): Axe.__init__(self, parent) def begin_round(self): self.visible = soya.IDLER.big_round_count % 4 class Scepter(object): pass class PomponScepter(LeftHandItem, Scepter): price = 200 blessed = 3 def __init__(self, parent = None): LeftHandItem.__init__(self, parent) self.set_shape(soya.Shape.get("sceptre_pompon")) self.nb_round = 0 def begin_round(self): if self.owner: self.nb_round += 1 if self.nb_round == 200: self.nb_round = 0 self.owner.invincible = 120 def set_equiped_pos(self): self.rotate_incline(180.0) self.set_xyz(-0.05, 0.1, 0.0) class Knife(Weapon): range = 1.3 price = 5 def __init__(self, parent = None): Weapon.__init__(self, parent) self.set_shape(soya.Shape.get("couteau")) self.ray = HalfRay(self, soya.Material.get("couteau_rayon")) self.ray.z = -0.16 self.ray.endpoint.z = -0.85 self.ray.length = 5 self.kill_rays = [ KillRay(self, 0.0, 0.15, 0.2, 0.0, 0.0, -1.4), KillRay(self, 0.0, -0.15, 0.2, 0.0, 0.0, -1.4), ] self.prot = soya.Volume(self, soya.Shape.get("couteau_prot")) self.prot.visible = self.prot.solid = 0 def fighting_bonus(self, target): if self.equiped: return 1.0 return 0.0 def zap(self): self.ray.zap() class MorkulKillerKnife(Knife): price = 70 def fighting_bonus(self, target): if self.equiped: import balazar.morkul if isinstance(target, balazar.morkul.Morkul): #if tofu.GAME_INTERFACE: # e = KillerEffect(self.owner.level) # e.move(self) # e.regenerate() return 8.0 return 1.0 return 0.0 def zap(self): self.ray.zap() class KillerEffect(soya.Particles): def __init__(self, parent = None, nb_particles = 6): soya.Particles.__init__(self, parent, soya.Material.get("x_lumiere_1"), nb_particles) self.set_colors((0.3, 0.1, 1.0, 1.0), (0.3, 0.1, 1.0, 1.0), (0.3, 0.1, 1.0, 1.0), (0.0, 0.0, 0.1, 1.0)) #self.set_sizes((0.4, 0.4)) self.set_sizes((2.0, 2.0), (0.1, 0.1)) self.lit = 0 self.removeable = 1 self.auto_generate_particle = 0 self.max_particles_per_round = 200 def generate(self, index): sx = random.uniform(-0.01, 0.01) sy = random.uniform(-0.0 , 0.01) sz = random.uniform(-0.01, 0.01) self.set_particle(index, random.uniform(2.0 , 3.0), 10.0 * sx, 10.0 * sy, 10.0 * sz, sx, sy, sz) class Key(Item): price = 5 def __init__(self, parent = None): Item.__init__(self, parent) self.set_shape(soya.Shape.get("clef")) class LeftHandHorizontalItem(LeftHandItem): def equip(self, character): Item.equip(self, character) character.left_hand = soya.World(character) character.perso.attach_to_bone(character.left_hand, "mainG") character.add(self) self.set_identity() self.rotate_incline(180.0) self.set_xyz(-0.05, 0.1, 0.0) def unequip(self): self.owner.perso.detach_from_bone(self.owner.left_hand) self.owner.remove(self.owner.left_hand) self.owner.remove(self) Item.unequip(self) def advance_time(self, proportion): if self.owner: xyz = self.owner.left_hand.x, self.owner.left_hand.y, self.owner.left_hand.z self.set_identity() self.set_xyz(*xyz) def set_inventory_pos(self): """Set the item in the right position / orientation, when it is displayed in the inventory""" self.set_identity() min, max = self.get_box() self.y = -(min.y + max.y) / 2.0 class Food(UseableItem): can_rotate = 0 def set_inventory_pos(self): self.set_identity() min, max = self.get_box() self.y = -(min.y + max.y) / 2.0 class MushroomFood(Food): price = 9 def __init__(self, parent = None): Food.__init__(self, parent) self.set_shape(soya.Shape.get("nourriture_champignon")) def used_by(self, user): if not user.doer.remote: user.doer.action_done(balazar.character.ValueState(user, balazar.character.STATE_HEAL_LIFE, 0.4)) self.owner.items.remove(self) class OldMushroomFood(Food): price = 2 def __init__(self, parent = None): Food.__init__(self, parent) self.set_shape(soya.Shape.get("nourriture_champignon_blet")) #self.volume = soya.Volume(self, soya.Shape.get("nourriture_champignon_blet")) def used_by(self, user): if not user.doer.remote: user.hurt(0.2, user, can_resist = 0) self.owner.items.remove(self) class TelekinesyCursedItem(Item): price = 3 blessed = -1 def __init__(self, parent = None): super(TelekinesyCursedItem, self).__init__(parent) self.cursed_owner = None self.kill_point = KillPoint(self, 0.0, 0.0, -1.5) def set_owner(self, character): if self.owner and (self.owner.life <= 0.0): # Free the curse if the previous owner is dead self.cursed_owner = None super(TelekinesyCursedItem, self).set_owner(character) if not self.cursed_owner: self.cursed_owner = character elif character and (not self.cursed_owner is character): # Cursed items cannot be given to someone else character.drop_item(self) if self.owner: self.set_equiped(1) def set_equiped(self, equiped): super(TelekinesyCursedItem, self).set_equiped(equiped) if (not equiped) and (self.owner.life > 0.0): self.owner.drop_item(self) # => will activate the curse ! def big_round(self): if self.cursed_owner and (not self.owner): if self.distance_to(self.cursed_owner) > 1.0: from balazar.activity import TelekinesyEffect TelekinesyEffect(self.parent, self.cursed_owner, self).move(self) self.cursed_owner = None def reset_curse(self): self.cursed_owner = None class CursedSword(TelekinesyCursedItem, Weapon): range = 1.6 def __init__(self, parent = None): TelekinesyCursedItem.__init__(self, parent) self.set_shape(soya.Shape.get("epee_maudite")) self.ray = HalfRay(self, soya.Material.get("epee_maudite_rayon")) self.ray.z = -0.16 self.ray.endpoint.set_xyz(0.0, 0.27, -1.38) self.ray.length = 5 self.kill_rays = [ KillRay(self, 0.0, 0.15, 0.0, 0.0, 0.2, -1.6), KillRay(self, 0.0, -0.15, 0.0, 0.0, 0.2, -1.6), ] self.prot = soya.Volume(self, soya.Shape.get("epee_maudite_prot")) self.prot.visible = self.prot.solid = 0 def fighting_bonus(self, target): if self.equiped: return -1.0 return 0.0 def zap(self): self.ray.zap() class Map(Item): can_rotate = 0 blessed = 1 def __init__(self, country_name): Item.__init__(self) self.set_shape(soya.Shape.get("item_map")) self.country_name = country_name def display_name(self): return _("__item__Map_%s" % self.country_name) def set_inventory_pos(self): self.set_identity() min, max = self.get_box() self.y = -(min.y + max.y) / 2.0 def set_ground_pos(self, ground = None, dir = None, ground_normal = None): Item.set_ground_pos(self, ground, dir, ground_normal) self.turn_vertical(90.0) self.y += 0.05 # Tables for random item choice SMALL_TREASURE = [ MushroomFood, MushroomFood, Key, Key, Knife, Knife, Axe, Sword, lambda : Map("foret_pompon"), # CursedSword, ] BIG_TREASURE = [ Key, TuryleSword, HalfVisibleAxe, # CursedSword, ]