# 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 math import tofu, soya, soya.tofu4soya import balazar.sound, balazar.base as base, balazar.item from balazar.item import Item, Weapon def noop(): pass ACTION_WAIT = 0 ACTION_ADVANCE = 1 ACTION_ADVANCE_LEFT = 2 ACTION_ADVANCE_RIGHT = 3 ACTION_TURN_LEFT = 4 ACTION_TURN_RIGHT = 5 ACTION_GO_BACK = 6 ACTION_GO_BACK_LEFT = 7 ACTION_GO_BACK_RIGHT = 8 ACTION_JUMP = 9 ACTION_STOP_JUMPING = 10 ACTION_HURTED = 11 ACTION_KILLED = 12 ACTION_GUARD = 13 ACTION_WALKED_ON = 14 class Action(soya.tofu4soya.Action): prioritary = 1 def __init__(self, action): self.action = action def is_crucial(self): return 1 ACTION_EQUIP_ITEM = 21 ACTION_UNEQUIP_ITEM = 22 ACTION_GRAB_ITEM = 23 ACTION_DROP_ITEM = 24 ACTION_USE_ITEM = 25 class ItemAction(soya.tofu4soya.Action): prioritary = 1 def __init__(self, action, item): self.action = action self.item_uid = item.uid ACTION_FIGHT_LEFT = 31 ACTION_FIGHT_RIGHT = 32 ACTION_FIGHT_SAGITTAL = 33 ACTION_FIGHT_CHARGE = 34 ACTION_WEAPON_HURTED_LEFT = 38 ACTION_WEAPON_HURTED_RIGHT = 39 class FightAction(soya.tofu4soya.Action): prioritary = 1 def __init__(self, action, target = None): self.action = action self.target_uid = (target and target.uid) or 0 ACTION_DISCUSSING = 51 ACTION_END_DISCUSSING = 52 ACTION_DISCUSSION = 53 class DiscussionAction(soya.tofu4soya.Action): prioritary = 1 def __init__(self, action, character, text_key = ""): self.action = action self.character_uid = (character and character.uid) or 0 self.text_key = text_key class State(soya.tofu4soya.CoordSystState): def __init__(self, mobile): soya.tofu4soya.CoordSystState.__init__(self, mobile) self.animation = "attente" def is_crucial(self): return 0 class SoundState(tofu.State): def __init__(self, mobile, sound, gain = 1.0): tofu.State.__init__(self) self.sound = sound self.gain = gain class ItemState(tofu.State): def __init__(self, mobile, action, item_uid): tofu.State.__init__(self) self.action = action self.item_uid = item_uid class NewItemState(tofu.State): def __init__(self, item): tofu.State.__init__(self) self.item = item ADD_ECLAT = 200 ADD_STEP = 201 ADD_BLOOD = 202 class AddState(soya.tofu4soya.CoordSystState): def __init__(self, mobile, element): soya.tofu4soya.CoordSystState.__init__(self, mobile) self.element = element STATE_KILL_LIFE = 222 STATE_HEAL_LIFE = 223 class ValueState(tofu.State): def __init__(self, mobile, type, value): tofu.State.__init__(self) self.type = type self.value = value _CONTEXT = None _P = soya.Point() _V = soya.Vector() _P2 = soya.Point() _V2 = soya.Vector() _TEMP = [ (_P , _V ), (_P2, _V2), ] class Character(soya.tofu4soya.Mobile): range = 0.7 couic_sound = "couic1.wav" die_sound = "couic2.wav" move_speed = 1.0 def __init__(self): soya.tofu4soya.Mobile.__init__(self) self.lod = 0 self.current_animation = "" self.current_deplacement = ACTION_WAIT self.solid = 0 #self.perso.solid = 0 self.speed = soya.Vector(self) self.radius = 0.5 # We need radius * sqrt(2)/2 > max speed (here, 0.35) self.radius_y = 1.0 self.center = soya.Point(self, 0.0, self.radius_y, 0.0) self.left = soya.Vector(self, -1.0, 0.0, 0.0) #self.right = soya.Vector(self, 1.0, 0.0, 0.0) self.down = soya.Vector(self, 0.0, -1.0, 0.0) self.up = soya.Vector(self, 0.0, 1.0, 0.0) self.front = soya.Vector(self, 0.0, 0.0, -1.0) #self.back = soya.Vector(self, 0.0, 0.0, 1.0) self.fight_skill = 2.0 self.resistance = 2.0 self.life = 1.0 self.items = [] self.weapon = None self.striking = 0 self.invincible = 0 self.jumping = 0 self.ground = soya.Point() self.last_ground = soya.Point() self.last_land_ground = soya.Point() self.ground_dir = soya.Vector() self.last_ground_dir = soya.Vector() self.on_ground = 0 self.current_action = None self.kill_rays = () self.relations = {} def do_action(self, action): if isinstance(action, FightAction): if not self.weapon: return if (not self.current_action) or not self.current_action.prioritary: action.duration = 0 self.current_action = action return elif isinstance(action, ItemAction): if tofu.Unique.hasuid(action.item_uid): item = tofu.Unique.getbyuid(action.item_uid) if ((action.action == ACTION_EQUIP_ITEM) or (action.action == ACTION_UNEQUIP_ITEM) or (action.action == ACTION_USE_ITEM) or (action.action == ACTION_DROP_ITEM)) and not (self is item.owner): print "* Balazar * %s cannot equip / unequip / use / drop item %s: not owner !" % (self.uid, item.uid) return if ((action.action == ACTION_EQUIP_ITEM) or (action.action == ACTION_UNEQUIP_ITEM)) and not isinstance(item, balazar.item.EquipableItem): print "* Balazar * %s cannot equip / unequip item %s: not equipable !" % (self.uid, item.uid) return if (action.action == ACTION_USE_ITEM) and not isinstance(item, balazar.item.UseableItem): print "* Balazar * %s cannot use item %s: not useable !" % (self.uid, item.uid) return if (action.action == ACTION_EQUIP_ITEM) and (item.equiped): print "* Balazar * %s cannot equip item %s: already equiped !" % (self.uid, item.uid) return if action.action == ACTION_EQUIP_ITEM: item.unequip_incompatible_items() if (action.action == ACTION_UNEQUIP_ITEM) and (not item.equiped): print "* Balazar * %s cannot unequip item %s: already unequiped !" % (self.uid, item.uid) return if (action.action == ACTION_DROP_ITEM) and not (self.on_ground): print "* Balazar * %s cannot drop item %s: not on ground !" % (self.uid, item.uid) return if (action.action == ACTION_DROP_ITEM) and item.equiped: self.doer.action_done(ItemState(self, ACTION_UNEQUIP_ITEM, action.item_uid)) # Unequip before dropping if (action.action == ACTION_GRAB_ITEM) and not (self.distance_to(item) < item.discussion_radius): print "* Balazar * %s cannot grab item %s: too far !" % (self.uid, item.uid) return self.doer.action_done(ItemState(self, action.action, action.item_uid)) return elif isinstance(action, DiscussionAction): if action.action == ACTION_DISCUSSING: if tofu.Unique.hasuid(action.character_uid): character = tofu.Unique.getbyuid(action.character_uid) character.controller.discussing(self) elif action.action == ACTION_END_DISCUSSING: if tofu.Unique.hasuid(action.character_uid): character = tofu.Unique.getbyuid(action.character_uid) character.controller.end_discussing(self) elif action.action == ACTION_DISCUSSION: if tofu.Unique.hasuid(action.character_uid): character = tofu.Unique.getbyuid(action.character_uid) # Ensure the discussion is valid (to avoid cheating in multiplayer mode) discussion_is_valid = getattr(character, "discussion_is_valid_%s" % action.text_key, None) if discussion_is_valid and not discussion_is_valid(self): return discussion_action = getattr(character, "discussion_action_%s" % action.text_key, None) if discussion_action: discussion_action(self) return if not self.level: return state = State(self) if action: if action.action == ACTION_GUARD: if not self.current_action: self.strinking = 0 self.current_action = action action.prioritary = 0 elif action.action == ACTION_KILLED: self.hurt(0.5, self, can_resist = 0) if 0 <= action.action < 9: self.current_deplacement = action.action if self.current_deplacement in (ACTION_TURN_LEFT, ACTION_ADVANCE_LEFT, ACTION_GO_BACK_LEFT): state.rotate_lateral( 4.0) state.animation = "tourneG" elif self.current_deplacement in (ACTION_TURN_RIGHT, ACTION_ADVANCE_RIGHT, ACTION_GO_BACK_RIGHT): state.rotate_lateral(-4.0) state.animation = "tourneD" if self.current_deplacement in (ACTION_ADVANCE, ACTION_ADVANCE_LEFT, ACTION_ADVANCE_RIGHT): state.shift(0.0, 0.0, -0.25 * self.move_speed) state.animation = "marche" elif self.current_deplacement in (ACTION_GO_BACK, ACTION_GO_BACK_LEFT, ACTION_GO_BACK_RIGHT): state.shift(0.0, 0.0, 0.15 * self.move_speed) state.animation = "recule" if self.on_ground == 2: # For mobile platform self.ground.convert_to(self.level) state.add_xyz(self.ground.x - self.last_ground.x, self.ground.y - self.last_ground.y, self.ground.z - self.last_ground.z) self.ground_dir.convert_to(state) self.ground_dir.y = 0.0 axe = self.last_ground_dir.cross_product(self.ground_dir) angle = self.last_ground_dir.angle_to (self.ground_dir) if axe.length() > 0.001: state.rotate_axe(angle, axe) if self.current_action: getattr(self, "do_action_%s" % self.current_action.action, noop)(self.current_action, state) scene = self.level state_center = soya.Point(state, 0.0, self.radius_y, 0.0) global _CONTEXT context = _CONTEXT = scene.RaypickContext(state_center, self.radius_y + 0.1, _CONTEXT) # Fall if context.raypick(state_center, self.down, 0.1 + self.radius_y, 1, 0, self.ground, _V) and not self.jumping: if (not self.on_ground) and (self.speed.y < -0.15): self.doer.action_done(SoundState(self, "chute.wav")) self.speed.y = 0.0 if self.ground.parent.is_inside(self.level.children[0]): state.y = self.level.transform_point(self.ground.x, self.ground.y, self.ground.z, self.ground.parent)[1] if isinstance(self.ground.parent, soya.Land): self.last_land_ground.move(self.ground) if state.y > self.level.push_down_level + 0.4: state.y -= 0.4 elif state.y > self.level.push_down_level: state.y = self.level.push_down_level self.on_ground = 1 # Not on a mobile platform (level.children[0] is the static part !!!) self.ground.parent = None # Avoid to store a useless parent else: # Possibly (not sure) on a mobile platform self.on_ground = 2 self.last_ground.clone(self.ground) self.last_ground.convert_to(self.level) self.ground_dir.__init__(self, 0.0, 0.0, -1.0) self.ground_dir.convert_to(self.ground.parent) self.last_ground_dir.__init__(self, 0.0, 0.0, -1.0) self.last_ground_dir.convert_to(self.level) ground = self.ground.parent while ground: if isinstance(ground, base.SensitiveFloor): ground.character_on(self) break ground = ground.parent state.y = self.level.transform_point(self.ground.x, self.ground.y, self.ground.z, self.ground.parent)[1] if action and (action.action == ACTION_JUMP): self.jumping = 1 self.speed.y = 0.4 self.doer.action_done(SoundState(self, "jump1.wav")) else: self.on_ground = 0 #self.speed.y = max(self.speed.y - 0.02, -0.25) if self.speed.y > -0.25: self.speed.y -= 0.02 if not self.current_action: state.animation = "chute" if self.speed.y < 0.0: self.jumping = 0 elif action and (action.action == ACTION_STOP_JUMPING): self.speed.y = 0.0 # Allow to fly : #if action and (action.action == ACTION_JUMP): # self.jumping = 1 # self.speed.y = 0.4 # self.doer.action_done(SoundState(self, "jump1.wav")) state.y += self.speed.y for character in self.level.mobiles: if isinstance(character, Character) and (not character is self) and character.visible: d = character.distance_to(self) - 0.5 - self.radius - character.radius if d < 0.0: d /= 2.0 state.add_xyz(d * (character.x - self.x), d * (character.y - self.y), d * (character.z - self.z)) if context.raypick(state_center, self.left, self.radius, 0, 0, _P, _V): _V.convert_to(self.parent) _V.normalize() state.add_mul_vector(self.radius - state_center.distance_to(_P), _V) if context.raypick(state_center, self.front, self.radius, 0, 0, _P, _V): _V.convert_to(self.parent) _V.normalize() state.add_mul_vector(self.radius - state_center.distance_to(_P), _V) if context.raypick(state_center, self.up, self.radius_y, 1, 0, _P, _V): _V.convert_to(self.parent) _V.normalize() state.add_mul_vector(self.radius_y - state_center.distance_to(_P), _V) if self.speed.y > 0.0: self.speed.y = 0.0 self.doer.action_done(SoundState(self, "chute.wav")) # Weapon collisions if self.striking and self.kill_rays: for mobile in self.level.mobiles: if isinstance(mobile, Character) and (not mobile.invincible) and mobile.visible: mobile.solid = 1 # Temporarily enable raypick on characters #mobile.perso.solid = 1 if mobile.weapon and mobile.weapon.prot: mobile.weapon.prot.solid = 1 # Activate raypicking on protection shape self.solid = 0 # but not on self ! self.level.children[0].children[0].solid = 0 kill_context = scene.RaypickContext(self.kill_rays[0], self.range, _CONTEXT) res = [kill_context.raypick(kill_ray, kill_ray.dir, kill_ray.length, 1, 0, _TEMP[i][0], _TEMP[i][1]) for (i, kill_ray) in enumerate(self.kill_rays) ] for i in range(len(res)): if self.weapon.hurt_weapon and res[i]: target = _TEMP[i][0].parent while target: if isinstance(target, Weapon): if target.owner and not target.owner.invincible: self.doer.action_done(SoundState(self, "weapon_hurted2.wav")) state2 = AddState(self, ADD_ECLAT) state2.move (_TEMP[i][0]) state2.look_at(_TEMP[i][1]) self.doer.action_done(state2) self.weapon_hurted() break target = target.parent else: continue break else: # No weapon hurted => check hit for i in range(len(res)): if res[i]: target = _TEMP[i][0].parent while 1: if isinstance(target, Character): if (not target.invincible) and self.is_enemy(target): fighting = self.fight_skill for item in self.items: fighting += item.fighting_bonus(target) _TEMP[i][1].__imul__(-1) target.hurt(fighting / 10.0, self, *_TEMP[i]) break elif isinstance(target, base.Strikeable): fighting = self.fight_skill - target.resistance + random.uniform(-10.0, 10.0) for item in self.items: fighting += item.fighting_bonus(target) if not target.hurt(self, fighting): self.weapon_hurted() break elif isinstance(target, soya.Land): break elif target is None: if self.weapon and (kill_ray in self.weapon.kill_rays): self.doer.action_done(SoundState(self, "weapon_hurted2.wav")) state2 = AddState(self, ADD_ECLAT) state2.move (_TEMP[i][0]) state2.look_at(_TEMP[i][1]) self.doer.action_done(state2) self.weapon_hurted() break target = target.parent else: continue break for mobile in self.level.mobiles: if isinstance(mobile, Character): mobile.solid = 0 if mobile.weapon and mobile.weapon.prot: mobile.weapon.prot.solid = 0 self.level.children[0].children[0].solid = 1 self.doer.action_done(state) def set_state(self, state): if isinstance(state, SoundState): balazar.sound.play(state.sound, self, gain = state.gain) elif isinstance(state, ValueState): if state.type == STATE_KILL_LIFE: self.life -= state.value if self.life > 0.0: # Else, dead if self.bot: self.invincible = 10 else: self.invincible = 40 if tofu.GAME_INTERFACE and (not self.bot) and (not self.controller.remote): tofu.GAME_INTERFACE.life_bar.set_life(self.life) elif state.type == STATE_HEAL_LIFE: if self.life > 0.0: # Else, dead self.life = min(1.0, self.life + state.value) if tofu.GAME_INTERFACE: #heal = HealEffect(self.level) #heal.move(self) #heal.y += 5.0 if (not self.bot) and (not self.controller.remote): tofu.GAME_INTERFACE.life_bar.set_life(self.life) elif isinstance(state, AddState): if state.element == ADD_ECLAT: if not tofu.GAME_INTERFACE: return element = Eclat(self.level) if state.element == ADD_STEP: if not tofu.GAME_INTERFACE: return element = Step(self.level) if state.element == ADD_BLOOD: if not tofu.GAME_INTERFACE: return element = Blood(self.level) element.matrix = state.matrix elif isinstance(state, ItemState): if tofu.Unique.hasuid(state.item_uid): item = tofu.Unique.getbyuid(state.item_uid) if state.action == ACTION_EQUIP_ITEM : item.set_equiped(1) elif state.action == ACTION_UNEQUIP_ITEM: item.set_equiped(0) elif state.action == ACTION_USE_ITEM : item.used_by(self) elif state.action == ACTION_GRAB_ITEM : if item.parent: item.parent.remove(item) self.add_item(item) elif state.action == ACTION_DROP_ITEM: if not item.owner is self: raise "jiba" item.set_owner(None) try: self.items.remove(item) except: return speed = soya.Vector(self, (int(str(item.uid)[-2]) - 5) * 0.02, 0.2, -0.1) speed.convert_to(self.parent) f = FallingItem(self.parent, item, speed) f.move(soya.Point(self, 0.0, 2.0, 0.0)) item.look_at(self.front) #if self.level.raypick(soya.Point(self, 0.0, 2.0, -1.5), self.down, -1.0, 1, 1, _P, _V): # _P.convert_to(self.level) # self.parent.add(item) # item.set_ground_pos(self.front, _V) # item.move(_P) # item.y += 0.05 else: #if self.distance_to(state) > 10.0: return soya.tofu4soya.Mobile.set_state(self, state) if tofu.GAME_INTERFACE and (self.on_ground == 1) and (self.y > self.level.step_level): if (state.animation != "attente") and (state.animation != "tourneG") and (state.animation != "tourneD") and ((soya.IDLER.big_round_count == 1) or (soya.IDLER.big_round_count == 5) or (soya.IDLER.big_round_count == 9) or (soya.IDLER.big_round_count == 13)): if self.level.children[0].raypick(self, self.up, 0.5, 1, 0, _P, _V): step = Step(self.level) step.move(_P) step.y += 0.02 step.look_at (self.front) step.look_at_y(_V) if self.current_animation != state.animation: if self.current_animation: self.perso.animate_clear_cycle(self.current_animation, 0.2) self.perso.animate_reset() self.perso.animate_blend_cycle(state.animation, 1.0, 0.2) self.current_animation = state.animation def control_owned(self): soya.tofu4soya.Mobile.control_owned(self) from balazar.controller import HumanController, StackController from balazar.camera import Traveling self.controller = StackController(self) self.controller.append(HumanController(self)) traveling = tofu.GAME_INTERFACE.traveling = Traveling(self, soya.Vector(None, 0.0, 0.0, 2.0)) tofu.GAME_INTERFACE.camera.add_traveling(traveling) tofu.GAME_INTERFACE.camera.zap() tofu.GAME_INTERFACE.hero = self tofu.GAME_INTERFACE.life_bar.set_life(self.life) self.advertise_country() if getattr(self, "is_new_player", 0): del self.is_new_player balazar.game_interface.StartDiscussion(self).activate(1) def advertise_country(self): country = self.level.get_country() if not country is tofu.GAME_INTERFACE.current_country: balazar.sound.play_music(country.music) if tofu.GAME_INTERFACE.current_country: d = balazar.game_interface.Discussion(self, u"", _("__welcome__%s" % country.name), choices = [balazar.game_interface.Discussion(self, _(u"Ok"))]) balazar.game_interface.Bubble(soya.root_widget, self, balazar.game_interface.DiscussionWidget(d)).set_focus(1) tofu.GAME_INTERFACE.current_country = country def zap(self): for item in self.items: item.zap() # Disable interpolation self.state1.x = self.state2.x = self.x self.state1.y = self.state2.y = self.y self.state1.z = self.state2.z = self.z def next_action(self): return Action(ACTION_WAIT) def begin_round(self): soya.tofu4soya.Mobile.begin_round(self) if self.invincible: self.visible = self.invincible % 2 self.invincible -= 1 def big_round(self): if hasattr(self.controller, "big_round"): self.controller.big_round() if not self.doer.remote: if self.y < -5.0: if self.life > 0.0: if self.hurt(((self.bot and 1.0) or 0.3), self, vector = 0, can_resist = 0): # Else dead if self.last_land_ground. y != 0.0: self.move(self.last_land_ground) self.zap() # elif 0 and not self.bot: # if self.x < -balazar.level.BRIDGE_DEMI_DIM - 0.0: # p = self % self.get_root() # new_level = self.level.get_by_pos(self.level.X - 1, self.level.Z) # p.y = p.y - self.level.bridge_0_1.y + new_level.bridge_2_1.y # self.level.remove_mobile(self) # p.convert_to(new_level) # self.move(p) # new_level.add_mobile(self) # self.last_land_ground.move(self) # self.current_deplacement = ACTION_WAIT # return # elif self.x > balazar.level.LAND_DIM + balazar.level.BRIDGE_DEMI_DIM + 0.0: # p = self % self.get_root() # new_level = self.level.get_by_pos(self.level.X + 1, self.level.Z) # p.y = p.y - self.level.bridge_2_1.y + new_level.bridge_0_1.y # self.level.remove_mobile(self) # p.convert_to(new_level) # self.move(p) # new_level.add_mobile(self) # self.last_land_ground.move(self) # self.current_deplacement = ACTION_WAIT # return # elif self.z < -balazar.level.BRIDGE_DEMI_DIM - 0.0: # p = self % self.get_root() # new_level = self.level.get_by_pos(self.level.X, self.level.Z - 1) # p.y = p.y - self.level.bridge_1_0.y + new_level.bridge_1_2.y # self.level.remove_mobile(self) # p.convert_to(new_level) # self.move(p) # new_level.add_mobile(self) # self.last_land_ground.move(self) # self.current_deplacement = ACTION_WAIT # return # elif self.z > balazar.level.LAND_DIM + balazar.level.BRIDGE_DEMI_DIM + 0.0: # p = self % self.get_root() # new_level = self.level.get_by_pos(self.level.X, self.level.Z + 1) # p.y = p.y - self.level.bridge_1_2.y + new_level.bridge_1_0.y # self.level.remove_mobile(self) # p.convert_to(new_level) # self.move(p) # new_level.add_mobile(self) # self.last_land_ground.move(self) # self.current_deplacement = ACTION_WAIT # return if tofu.GAME_INTERFACE: if self.lod: # Check LODs if self.distance_to(tofu.GAME_INTERFACE.camera) < 15.0: self.lod = 0 try: self.perso.detach("perso_poor") self.perso.attach("perso") except: pass else: if self.distance_to(tofu.GAME_INTERFACE.camera) > 17.0: self.lod = 1 try: self.perso.detach("perso") self.perso.attach("perso_poor") except: pass else: self.perso.detach("perso") self.perso.attach("perso_poor") def loaded(self): soya.tofu4soya.Mobile.loaded(self) self.current_animation = "" if self.on_ground == 2: self.on_ground = 1 self.lod = 0 try: self.perso.detach("perso_poor") self.perso.attach("perso") except: pass for item in self.items: item.loaded() def received(self): soya.tofu4soya.Mobile.received(self) self.current_animation = "" if self.on_ground == 2: self.on_ground = 1 self.lod = 0 try: self.perso.detach("perso_poor") self.perso.attach("perso") except: pass for item in self.items: item.received() def add_item(self, item): self.items.append(item) item.set_owner(self) item.zap() def get_item(self, Item): for item in self.items: if isinstance(item, Item): return item def is_enemy(self, other): return self.get_relation(other) < 0.0 def change_relation(self, other, delta_relation): self.set_relation(other, self.get_relation(other) + delta_relation) self.controller.relation_changed(other) def set_relation(self, other, relation): if isinstance(other, Character): self ._set_relation(other, relation) other._set_relation(self , relation) self.controller.relation_changed(other) else: self.relations[other] = relation def _set_relation(self, other, relation): self.relations[other.race, other.uid] = relation def get_relation(self, other): if isinstance(other, Character): return min(self._get_relation(other), other._get_relation(self)) else: if self.relations.has_key(other): return self.relations[other] return self.relations.get(None, 0.2) def _get_relation(self, other): if self.relations.has_key((other.race, other.uid)): return self.relations[other.race, other.uid] if self.relations.has_key(other.race): return self.relations[other.race] return self.relations.get(None, 0.2) def hurt(self, life, caster, localisation = None, vector = None, can_resist = 1): if self.life > 0.0: if can_resist: resistance = self.resistance for item in self.items: resistance += item.resistance_bonus(caster) life = life / resistance state = AddState(self, ADD_BLOOD) state.move(localisation or self.center) self.doer.action_done(state) if self.life - life <= 0.0: self.doer.action_done(ValueState(self, STATE_KILL_LIFE, life)) # Do this AFTER the if !!! (because it can change self.life immediately) self.doer.action_done(SoundState(self, self.die_sound)) action = self.current_action = FightAction(ACTION_KILLED) action.duration = 0 return 0 else: self.doer.action_done(ValueState(self, STATE_KILL_LIFE, life)) # Do this AFTER the if !!! (because it can change self.life immediately) self.doer.action_done(SoundState(self, self.couic_sound)) if not (self.current_action and self.current_action.action == ACTION_KILLED): action = self.current_action = FightAction(ACTION_HURTED) action.duration = 0 #if (self.life > 0.5) and (self.life - life <= 0.5): length = 0.5 #else: length = 0.1 length = 0.25 if vector: vector %= self.level vector.set_length(length) action.vector_x = vector.x action.vector_z = vector.z elif vector == 0: action.vector_x = 0.0 action.vector_z = 0.0 else: _V.parent = self _V.set_xyz(0.0, 0.0, length) _V.convert_to(self.level) action.vector_x = _V.x action.vector_z = _V.z self.striking = 0 return 1 def weapon_hurted(self): if self.current_action and (ACTION_HURTED <= self.current_action.action <= ACTION_KILLED): return action = FightAction(ACTION_WEAPON_HURTED_LEFT) if self.current_animation == "combat0": action.action = ACTION_WEAPON_HURTED_LEFT elif self.current_animation == "combat1": action.action = ACTION_WEAPON_HURTED_RIGHT else: _P.clone(self.weapon) _P.convert_to(self) if _P.x < 0.0: action.action = ACTION_WEAPON_HURTED_LEFT else: action.action = ACTION_WEAPON_HURTED_RIGHT action.duration = 0 self.current_action = action self.striking = 0 def do_action_38(self, action, state): # ACTION_WEAPON_HURTED_LEFT state.animation = "combat0c" if action.duration == 0: state.y += 0.1 action.duration += 1 if action.duration > 12: self.current_action = None def do_action_39(self, action, state): # ACTION_WEAPON_HURTED_RIGHT state.animation = "combat1c" if action.duration == 0: state.y += 0.1 action.duration += 1 if action.duration > 12: self.current_action = None def do_action_11(self, action, state): # ACTION_HURTED state.animation = "couic" if action.duration == 0: state.y += 0.1 action.duration += 1 if action.duration > 7: action.vector_x /= 2.0 action.vector_z /= 2.0 if action.duration > 9: self.current_action = None state.add_xyz(action.vector_x, 0.0, action.vector_z) def do_action_12(self, action, state): # ACTION_KILLED state.animation = "mort" if action.duration == 0: #print "throwing items of", self.uid for item in self.items[:]: if self.bot or item.equiped: self.doer.action_done(ItemState(self, ACTION_DROP_ITEM, item.uid)) action.duration += 1 state.matrix = self.matrix self.speed.y = 0.0 if action.duration < self.die_duration1: state.shift(0.0, 0.0, 0.04) elif action.duration > self.die_duration2: self.kill() def killed(self): if tofu.GAME_INTERFACE: tofu.GAME_INTERFACE.close_all_widgets() soya.tofu4soya.Mobile.killed(self) #for item in self.items: def do_action_13(self, action, state): # ACTION_GUARD state.animation = "garde" def strike_rot(self, target, state): _P.clone(target) _P.convert_to(self) if _P.x < -0.2: state.rotate_lateral( 4.0) elif _P.x > 0.2: state.rotate_lateral(-4.0) #DOWN = soya.Vector(None, 0.0, -1.0, 0.0) class FallingItem(soya.World): def __init__(self, parent = None, item = None, speed = None): soya.World.__init__(self, parent) self.item = item self.speed = speed or soya.Vector() self.solid = 0 self.add(item) item.set_ground_pos() item.set_xyz(0.0, 0.0, 0.0) def big_round(self): if self.y < -5.0: self.parent.remove(self) def begin_round(self): if self.speed.y > -0.23: self.speed.y -= 0.02 self.add_vector(self.speed) if self.parent.raypick(self, self.speed, 0.35, 1, 1, _P, _V): self.parent.add(self.item) self.parent.remove(self) self.item.set_ground_pos(_P, None, _V) #def advance_time(self, proportion): # self.add_mul_vector(proportion, self.speed) import random class Blood(soya.Particles): def __init__(self, parent = None, material = None, nb_particles = 20): soya.Particles.__init__(self, parent, material or soya.PARTICLE_DEFAULT_MATERIAL, nb_particles) self.auto_generate_particle = 1 self.set_colors((1.0, 0.1, 0.1, 1.0), (1.0, 0.1, 0.1, 1.0), (0.8, 0.1, 0.1, 1.0), (0.4, 0.0, 0.0, 1.0)) self.set_sizes((0.7, 0.7)) self.max_particles_per_round = 2 self.life = 11 self.lit = 0 def generate(self, index): angle = random.uniform(0.0, 6.2834) sx = math.cos(angle) sz = math.sin(angle) l = 0.06 / math.sqrt(sx * sx + 1.0 + sz * sz) self.set_particle(index, random.uniform(0.5, 1.5), sx * l, 3 * l, sz * l, 0.0, -0.01, 0.0) def begin_round(self): soya.Particles.begin_round(self) if self.life == 1: self.auto_generate_particle = 0 self.removable = 1 self.life = 0 else: self.life -= 1 class Eclat(soya.Volume): def __init__(self, parent = None): soya.Volume.__init__(self, parent, soya.Shape.get("eclat")) self.solid = 0 self.angle = 0.0 def advance_time(self, proportion): self.angle += 0.08 * proportion f = math.cos(self.angle) if f < 0.0: if self.parent: self.parent.remove(self) else: self.set_scale_factors(f, f, f) class Step(soya.Volume): def __init__(self, parent = None): soya.Volume.__init__(self, parent, soya.Shape.get("pas")) self.solid = 0 def big_round(self): if (not tofu.GAME_INTERFACE) or (not tofu.GAME_INTERFACE.camera.is_in_frustum(self)): self.parent.remove(self) class HealEffect(soya.Particles): def __init__(self, parent = None, nb_particles = 35): soya.Particles.__init__(self, parent, soya.PARTICLE_DEFAULT_MATERIAL, nb_particles) self.auto_generate_particle = 1 self.set_colors((1.0, 0.2, 0.8, 0.4), (1.0, 0.2, 0.8, 1.0), (1.0, 0.2, 0.2, 1.0), (0.8, 0.2, 0.1, 1.0), (0.3, 0.1, 0.0, 1.0)) self.set_sizes((1.0, 1.0)) self.max_particles_per_round = 2 self.life = 60 self.lit = 0 def generate(self, index): angle = random.uniform(0.0, 6.2834) sx = math.cos(angle) sy = -7.0 sz = math.sin(angle) l = 0.15 / math.sqrt(sx * sx + sy * sy + sz * sz) self.set_particle(index, random.uniform(0.6, 1.5), sx * l, sy * l, sz * l, 0.0, 0.0, 0.0) def begin_round(self): soya.Particles.begin_round(self) if self.life > 0: self.life -= 1 elif self.life == 0: self.auto_generate_particle = 0 self.removable = 1 self.life = -1