# Slune # Copyright (C) 2002-2003 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 from __future__ import generators import struct, math, random import py2play.action as action, py2play.character as py2play_character #from py2play import recvall import soya, soya.ray as ray, soya.widget as widget from soya import Point, Vector import slune.globdef as globdef, slune.sound as sound ACTION_WAIT = action.ACTION_WAIT ACTION_JUMP = "j" ACTION_TURBO = "t" ACTION_ROTUP = "u" ACTION_ROTDOWN = "d" ACTION_ROTLAT = "l" ACTION_DEBUG = "°" ACTION_STARTGAME = "!" class Action: def __init__(self, action = ACTION_WAIT, mouse_x = 0.0, mouse_y = 1.0, round = None): self.round = round self.action = action self.mouse_x = mouse_x self.mouse_y = mouse_y def __repr__(self): return "" % (self.action, self.round, self.mouse_x, self.mouse_y) from socket import MSG_WAITALL #def WRITE_ACTION(socket, action): # socket.sendall(struct.pack("!cddi", action.action, action.mouse_x, action.mouse_y, action.round)) #def READ_ACTION(socket): # return Action(*struct.unpack("!cddi", recvall(socket, 21))) action.Action = Action #action.READ_ACTION = READ_ACTION #action.WRITE_ACTION = WRITE_ACTION RIGHT = Vector(None, 1.0, 0.0, 0.0) DOWN = Vector(None, 0.0, -1.0, 0.0) UP = Vector(None, 0.0, 1.0, 0.0) FRONT = Vector(None, 0.0, 0.0, -1.0) # Re-useable Points and Vectors _P = Point() _P2 = Point() _P3 = Point() _V = Vector() _V2 = Vector() VEHICLE_PERSO_COORDS = [ (0.0, 0.1 , 0.03), (0.0, 0.1 , 0.03), (0.0, 0.4 , -0.2), (0.0, 0.3 , 0.35), (0.0, 0.48, 0.0), ] class Pusher: pass class Competitor: pass class Character(soya.World, Pusher): nitro_enabled = 1 push_fly = 0.3 context = None def __init__(self, parent = None): soya.World.__init__(self, parent) self.radius = 0.7 self.floating = 0.3 self.weight = 1.0 self.rotup_speed = 7.0 self.mode_grip = 0 self.gripped = 0 self.rot_vert = 0.0 self.speed = Vector(self) self.force = Vector(None) self.solid = 0 self.nitro = None self.nitro_time = 0 self.flame_thrower = 0 self.flame_throw_time = 0 self.camera_target = self self.old_speed_x = 0.0 self.context = None self.on_ground = 0 self.was_on_ground = 0 self.vertical_angle = 0.0 self.platform_speed = None self.CENTER = Point(self, 0.0, 0.3, 0.0) self.scramble = 0.0 self.next_pos = Point(self, 0.0, 0.0, 0.0) self.internal = soya.World(self) self.perso = soya.Volume(self.internal) self.perso_name = None self.vehicle = 1 self.life = 1.0 self.pushed_by = None # IA stuff self.jumping = 0.0 self.max_speed = 1.0 self.current_action = Action() self.speed.y = 0.01 # Avoid null speed (null speed => jumping for AI). The speed will be overrided later. self.check_ground_vector = Vector(self, 0.0, -1.0, -2.0) # blam hack to test raypicking #import soya.laser #laser = soya.laser.Laser(self) #laser.rotate_vertical(-90.0) #laser.reflect = 1 def __getstate__(self): state = soya.World.__getstate__(self) if state[1] is self.__dict__: state = state[0], state[1].copy() del state[1]["context"] return state def __setstate__(self, state): state = soya.World.__setstate__(self, state) self.context = None def set_perso(self, perso_name): self.perso_name = perso_name self.perso.set_shape(soya.Shape.get(self.perso_name + "1")) def displayname(self): return self.perso_name.title() def set_vehicle(self, vehicle, add_ray = 1): self.vehicle = vehicle self.internal.set_shape(soya.Shape.get("vehicle" + str(self.vehicle))) if hasattr(self, "ray"): self.internal.remove(self.ray) del self.ray if hasattr(self, "ray2"): self.internal.remove(self.ray2) del self.ray2 if vehicle == 0: self.radius = 0.7 self.floating = 0.5 self.weight = 1.3 self.maxspeedx = 0.8 self.maxspeedz = 0.98 self.rotup_speed = 7.0 self.mode_grip = 0 if add_ray: self.ray = ray.Ray(self.internal, RAY_MATERIAL2) self.ray.set_xyz(-0.84, 0.10, 0.0) self.ray.endpoint.set_xyz(0.45, 0.0, 0.0) self.ray.length = 20 self.ray2 = ray.Ray(self.internal, RAY_MATERIAL2) self.ray2.set_xyz(0.84, 0.10, 0.0) self.ray2.endpoint.set_xyz(-0.45, 0.0, 0.0) self.ray2.length = 20 elif vehicle == 1: self.radius = 0.7 self.floating = 0.3 self.weight = 1.0 self.maxspeedx = 1.0 self.maxspeedz = 1.0 self.rotup_speed = 8.0 self.mode_grip = 0 if add_ray: self.ray = ray.Ray(self.internal, RAY_MATERIAL) self.ray.set_xyz(-0.3, 0.15, 0.5) self.ray.endpoint.set_xyz(0.6, 0.0, 0.0) self.ray.length = 20 elif vehicle == 2: self.radius = 0.8 self.floating = 0.3 self.weight = 1.6 self.maxspeedx = 0.9 self.maxspeedz = 0.95 self.rotup_speed = 6.0 self.mode_grip = 0 if add_ray: self.ray = ray.Ray(self.internal, RAY_MATERIAL2) self.ray.set_xyz(-0.5, 0.2, 1.0) self.ray.endpoint.set_xyz(1.0, 0.0, 0.0) self.ray.length = 20 elif vehicle == 3: self.radius = 0.7 self.floating = 0.3 self.weight = 0.6 self.maxspeedx = 1.0 self.maxspeedz = 1.0 self.rotup_speed = 9.0 self.mode_grip = 1 self.DOWN = Vector(self, 0.0, -1.0, 0.0) if add_ray: self.ray = ray.Ray(self.internal, RAY_MATERIAL2) self.ray.set_xyz(0.0, 0.07, 0.65) self.ray.endpoint.set_xyz(0.0, 0.3, 0.0) self.ray.length = 20 elif vehicle == 4: self.radius = 1.0 self.floating = 0.5 self.weight = 2.2 self.maxspeedx = 0.7 self.maxspeedz = 0.8 self.rotup_speed = 4.0 self.mode_grip = 0 self.DOWN = Vector(self, 0.0, -1.0, 0.0) if add_ray: self.ray = ray.Ray(self.internal, RAY_MATERIAL3) self.ray.set_xyz(-0.6, 0.35, 0.6) self.ray.endpoint.set_xyz(1.2, 0.0, 0.0) self.ray.set_xyz(-0.95, -0.4, 0.0) self.ray.endpoint.set_xyz(1.9, 0.0, 0.0) self.ray.length = 10 self.perso.set_xyz(*VEHICLE_PERSO_COORDS[vehicle]) self.perso_y = self.perso.y def add_headlight(self): light = self.light = soya.Light(self) light.set_xyz(0.0, 1.2, -0.5) light.diffuse = (0.5, 0.6, 1.0, 1.0) light.specular = (0.0, 0.0, 0.0, 1.0) light.quadratic = 0.0 light.linear = 0.07 light.constant = 0.0 light.exponent = 3.0 light.angle = 90.0 light.cast_shadow = 0 def init(self): pass def default_mouse_x(self): return 0.0 def set_level(self, level, init = 0): level.add(self) super(Character, self).set_level(level, init) def begin_action(self, action): from py2play.idler import IDLER as root speed = self.speed force = self.force self.internal.rotate_incline((self.old_speed_x - speed.x) * 6000.0) self.perso .rotate_lateral((self.old_speed_x - speed.x) * 12000.0) self.old_speed_x = speed.x self.turn_lateral(-500.0 * speed.x) if self.flame_throw_time: self.flame_throw_time -= 1 if self.nitro_time: self.nitro.set_sizes(( 1.0 - (10 - self.nitro_time) / 15.0, 1.0 - (10 - self.nitro_time) / 15.0, )) self.nitro_time -= 1 if not self.nitro_time: self.nitro.auto_generate_particle = 0 self.life = min(1.0, self.life + 0.0003) if action.action == ACTION_ROTUP : self.turn_vertical( self.rotup_speed) elif action.action == ACTION_ROTDOWN: self.turn_vertical(-self.rotup_speed) elif action.action == ACTION_ROTLAT : self.rotate_lateral(30.0) elif (action.action == ACTION_TURBO) and (self.flame_throw_time == 0): if self.flame_thrower and ((not self.nitro) or not self.nitro.auto_generate_particle): self.flame_thrower -= 1 self.flame_throw_time = 50 flame_thrower = FlameThrower(self) elif self.nitro_enabled: length = force.length() d = 0.09 * max(0.0, (1.0 - length)) if self.life > d: force.add_vector(Vector(self, 0.0, 0.0, -2.0) % root) force.set_length(max(1.0, length)) self.life -= 0.08 * max(0.0, (1.0 - length)) if self.nitro is None: self.nitro = Nitro(self) sound.play("nitro-1.wav", self) elif not self.nitro.auto_generate_particle: self.nitro.auto_generate_particle = 1 sound.play("nitro-1.wav", self) self.nitro.set_sizes((1.0, 1.0)) self.nitro_time = 10 elif action.action == ACTION_DEBUG : print self.position(), self.round print self.level.parent.camera.position(), Point(self.level.parent.camera, 0.0, 0.0, -1.0) % self.get_root() self.hurt(2.0) poqjfcpjk elif (action.action == ACTION_JUMP) and self.was_on_ground: force.y += 0.4 self.rot_vert += 0.4 if self.context: self.was_on_ground = self.on_ground if self.context.raypick(self.CENTER, DOWN, self.floating + 0.45, 1, 1, _P, _V): self.on_ground = 1 self.gripped = 0 elif self.mode_grip and self.context.raypick(self.CENTER, self.DOWN, 6.0 * self.speed.length(), 1, 1, _P, _V): self.on_ground = self.gripped = 1 else: self.on_ground = self.gripped = 0 if self.context and self.on_ground: _P.convert_to(self.parent) if (self.y < _P.y + self.floating - force.y): if (not self.scramble) and self.parent: self.scramble = min(30.0, ((force.y + self.parent.transform_vector(speed.x, speed.y, speed.z, self)[1]) * 7.0) ** 2) #if (self.scramble > 2) and (-20.0 < self.y < 20.0): # Snow(self.level).move(self) # "force.y = _P.y + self.floating - self.y" give better visual effect, but clashes # with mode grip. if self.gripped: force.y = 0.0 else: force.y = _P.y + self.floating - self.y elif self.y > _P.y + self.floating + 0.1: force.y -= 0.03 if force.y < 0.2: if (action.action != ACTION_ROTUP) and (action.action != ACTION_ROTDOWN): _V.convert_to(self) if _V.y < -0.3: self.turn_incline(10.0) elif (_V.y < 0.996) and _V.y: #soya.cross_vector(_V, UP, _V2) _V.cross_product(UP, _V2) _V2.convert_to(self.parent) self.vertical_angle = -_V.angle_to(UP) self.rotate_axe(self.vertical_angle / 3.0, _V2) #self.rotate_axe(-_V.angle_to(UP) / 4.0, _V2.x, _V2.y, _V2.z) else: force.y -= 0.03 # comment this line if you want to fly if self.y < -35.0: self.hurt(1.0) force.__imul__(0.95) if self.rot_vert > 0.0: self.turn_vertical(self.rot_vert * 14.0) self.rot_vert -= 0.03 x, y, z = self.transform_vector(force.x, force.y, force.z, self.parent) speed.x += x speed.y += y speed.z += z if speed.length() > 0.75: speed.set_length(0.75) for character in self.level.pushables: if not character is self: if self.distance_to(character) < self.radius + character.radius: _V.set_start_end(self, character) f = 3.0 * max(0.0, _V.dot_product(self.speed)) * self.weight / character.weight if f: _V.set_length(f) character.push(_V.x, _V.y + character.push_fly * f, _V.z, self) f = -0.3 * character.weight / self.weight self.push(f * _V.x, f * _V.y, f * _V.z, character) _P2.__init__(self, 0.0, 0.3, 0.0) _P2.add_vector(speed) _P2.convert_to(root) self.context = root.RaypickContext(_P2, max(self.radius, 0.7) + 0.5, self.context) bouree = 0 for vec in (RIGHT, FRONT): if self.context.raypick(_P2, vec, self.radius, 0, 0, _P, _V): _P.convert_to(root) _V.convert_to(root) #a = _V.cross_product(Vector(self, 0.0, 1.0, 0.0)) % root #print a #self.turn_axe(-15.0, a.x, a.y, a.z) if vec.dot_product(_V) > 0.0: _P3.__init__(root, _P2.x - self.radius * vec.x, _P2.y - self.radius * vec.y, _P2.z - self.radius * vec.z) else: _P3.__init__(root, _P2.x + self.radius * vec.x, _P2.y + self.radius * vec.y, _P2.z + self.radius * vec.z) if force.dot_product(_V) < 0.0: if abs(force.x) + abs(force.z) > 0.1: # Else force is only due to gravity! _V2.clone(_V) _V2.set_length(-2.0 * force.dot_product(_V2)) force += _V2 force *= 0.5 bouree = 1 if (_P.x - _P2.x) * _V.x + (_P.y - _P2.y) * _V.y + (_P.z - _P2.z) * _V.z > 0.0: _V.set_start_end(_P2, _P) else: _V.set_start_end(_P3, _P) _P2 .__iadd__(_V) speed.__iadd__(_V) _P2.y += 0.2 if self.context.raypick(_P2, DOWN, 0.7, 0, 1, _P, _V): _P.convert_to(root) _V.convert_to(root) if DOWN.dot_product(_V) > 0.0: _P3.__init__(root, _P2.x - self.radius * DOWN.x, _P2.y - self.radius * DOWN.y, _P2.z - self.radius * DOWN.z) else: if force.y > 0.0: force.y = 0.0 # Stop and break a jump _P3.__init__(root, _P2.x + self.radius * DOWN.x, _P2.y + self.radius * DOWN.y, _P2.z + self.radius * DOWN.z) if force.dot_product(_V) < -0.4: bouree = 1 _V.set_start_end(_P3, _P) #_P2 .__iadd__(_V) # Useless since it is the last raypicking. speed.__iadd__(_V) #if bouree and not self.nitro.auto_generate_particle: if bouree: couic = min(0.5, force.x ** 2 + force.z ** 2) * 0.8 if couic > 0.01: #force.x = force.z = 0.0 if self.hurt(couic) and (len(explosions) < 4): # Limit the number of simultaneous explosions explode = Explosion(self.parent) explode.move(self) sound.play("explose-1.wav", explode) self.next_pos.clone(speed) self.next_pos.convert_to(self.parent) self.next_pos.parent = None def push(self, x, y, z, pusher = None, play_sound = 1): if play_sound: sound.play("push-1.wav", self) from py2play.idler import IDLER def f(): self.force.add_xyz(x, y, z) self.rot_vert += max(0.0, y) IDLER.next_round_tasks.append(f) self.pushed_by = pusher def end_round(self): # Restore the real position -- advance_time may cause rounding error on the position !!! self.move(self.next_pos) if self.platform_speed: self += self.platform_speed self.platform_speed = None def advance_time(self, proportion): soya.World.advance_time(self, proportion) self.add_mul_vector(proportion, self.speed) if self.scramble: if self.scramble <= proportion: self.internal.y = 0.0 self.scramble = 0.0 else: self.internal.y = abs(math.sin(self.scramble)) * self.scramble * 0.04 self.scramble -= proportion / 3.0 self.perso.y = self.perso_y + self.internal.y def teleport(self, x, y, z): self.set_xyz(x, y, z) self.force.set_xyz(0.0, 0.0, 0.0) if self.scramble: self.scramble = 0.0 self.internal.y = 0.0 self.perso.y = self.perso_y if hasattr(self, "ray" ): self.ray .zap() if hasattr(self, "ray2"): self.ray2.zap() self.context = None # The raypick context is no longer valid !!! def hurt(self, life): """Kills LIFE life to this character. Returns true if the character is still alive.""" self.life -= life if self.life < 0.0: self.die() else: return 1 def die(self): explode = Explosion(self.parent) explode.move(self) explode.life = 60 explode.particle_width = explode.particle_height = 0.7 sound.play("explose-3.wav", explode) self.level.remove_character(self) class NonPlayerCharacter(Character, py2play_character.NonPlayerCharacter): clan = 0 def __init__(self, parent = None): py2play_character.NonPlayerCharacter.__init__(self) Character.__init__(self, parent) import slune.controler self.controler = slune.controler.StackControler([self.IAControler()]) def choose_action(self): return self.controler.next() def begin_round(self): py2play_character.NonPlayerCharacter.begin_round(self) Character.begin_round(self) def begin_action(self, action): self.speed.set_xyz(action.mouse_x / 120.0 * self.maxspeedx, 0.0, (action.mouse_y * 0.2 - 0.2) * self.maxspeedz) Character.begin_action(self, self.current_action) def __getstate__(self): state = Character.__getstate__(self) del state[0]["controler"] return state def __setstate__(self, state): state = Character.__setstate__(self, state) import slune.controler self.controler = slune.controler.StackControler([self.IAControler()]) def IAControler(self): while 1: yield Action() # Does nothing ! class Pushable(soya.Volume, Pusher): clan = 0 bonus_chance = 0.15 bonus_type = 0 on_bourre = None push_fly = 0.3 def __init__(self, parent = None): soya.Volume.__init__(self, parent) self.radius = 1.0 self.radius_y = 1.0 self.weight = 1.0 self.life = 1.0 self.on_ground = 1 # 0 ??? self.speed = Vector(self) self.force = Vector(None) self.solid = 0 self.worth_playing = 0 self.CENTER = Point(self, 0.0, 0.3, 0.0) self.next_pos = Point(self, 0.0, 0.0, 0.0) def begin_round(self): soya.Volume.begin_round(self) force = self.force if not self.worth_playing: if (abs(force.x) > 0.1) or (abs(force.y) > 0.1) or (abs(force.z) > 0.1): self.worth_playing = 1 if self.on_bourre: if self.on_bourre == "win": from videosequence import MissionCompleted, PLAYER MissionCompleted(1).start(tux = PLAYER) from py2play.idler import IDLER IDLER.camera.add_traveling(soya.ThirdPersonTraveling(self)) else: self.on_bourre() else: return speed = self.speed speed.set_xyz(0.0, 0.0, 0.0) from py2play.idler import IDLER as root if root.raypick(self.CENTER, DOWN, self.radius_y / 2.0 + 0.45, 1, 1, _P, _V): _P.convert_to(self.parent) self.on_ground = 1 if (self.y < _P.y + self.radius_y / 2.0 - self.force.y): force.y = 0.0 self.force.y += _P.y + self.radius_y / 2.0 - self.y elif self.y > _P.y + self.radius_y / 2.0 + 0.1: force.y -= 0.03 if self.force.y < 0.05: _V.convert_to(self) if _V.y < 0.0: self.turn_incline(10.0) elif _V.y < 0.999: _V.cross_product(UP, _V2) _V2.convert_to(self.parent) angle = _V.angle_to(UP) self.rotate_axe(-angle / 4.0, _V2) else: self.worth_playing = 0 else: self.on_ground = 0 force.y -= 0.03 if self.y < -35.0: self.die() force.__imul__(0.95) if force.y > 0.0: self.turn_vertical(force.y * 14.0) x, y, z = self.transform_vector(force.x, force.y, force.z, self.parent) speed.x += x speed.y += y speed.z += z if speed.length() > 0.5: speed.set_length(0.5) if self.parent: for character in self.parent.pushables: if not character is self: if self.distance_to(character) < self.radius + character.radius: _V.set_start_end(self, character) _V.y += character.push_fly f = 2.5 * max(0.0, _V.dot_product(self.speed)) if f: _V.set_length(f * self.weight / character.weight) character.push(_V.x, _V.y, _V.z, self) _P2.__init__(self, 0.0, self.radius_y / 2.0, 0.0) _P2.add_vector(speed) _P2.convert_to(root) context = root.RaypickContext(_P2, max(self.radius, 0.7)) bouree = 0 for vec in (RIGHT, FRONT): if context.raypick(_P2, vec, self.radius, 0, 0, _P, _V): _P.convert_to(root) _V.convert_to(root) if vec.dot_product(_V) > 0.0: _P3.__init__(root, _P2.x - self.radius * vec.x, _P2.y - self.radius * vec.y, _P2.z - self.radius * vec.z) else: _P3.__init__(root, _P2.x + self.radius * vec.x, _P2.y + self.radius * vec.y, _P2.z + self.radius * vec.z) if force.dot_product(_V) < 0.0: _V2.clone(_V) _V2.set_length(-2.0 * force.dot_product(_V2)) force += _V2 #force *= 0.5 bouree = 1 if (_P.x - _P2.x) * _V.x + (_P.y - _P2.y) * _V.y + (_P.z - _P2.z) * _V.z > 0.0: _V.set_start_end(_P2, _P) else: _V.set_start_end(_P3, _P) _P2 .__iadd__(_V) speed.__iadd__(_V) _P2.y += 0.2 if context.raypick(_P2, DOWN, self.radius_y, 0, 1, _P, _V): _P.convert_to(root) _V.convert_to(root) if DOWN.dot_product(_V) > 0.0: _P3.__init__(root, _P2.x - self.radius_y * DOWN.x, _P2.y - self.radius_y * DOWN.y, _P2.z - self.radius_y * DOWN.z) else: if force.y > 0.0: force.y = 0.0 # Stop and break a jump _P3.__init__(root, _P2.x + self.radius_y * DOWN.x, _P2.y + self.radius_y * DOWN.y, _P2.z + self.radius_y * DOWN.z) if force.dot_product(_V) < 0.0: bouree = 1 _V.set_start_end(_P3, _P) #_P2 .__iadd__(_V) # Useless since it is the last raypicking. speed.__iadd__(_V) if bouree: couic = min(0.5, force.x ** 2 + force.z ** 2) if couic > 0.01: #force.x = force.z = 0.0 if self.hurt(couic) and (len(explosions) < 4): # Limit the number of simultaneous explosions explode = Explosion(self.parent, nb_particles = 15) sound.play("explose-1.wav", explode) explode.move(self) self.next_pos.clone(speed) self.next_pos.convert_to(self.parent) self.next_pos.parent = None def push(self, x, y, z, pusher = None, play_sound = 1): if play_sound: sound.play("push-2.wav", self) from py2play.idler import IDLER IDLER.next_round_tasks.append(lambda : self.force.add_xyz(x, y, z)) def end_round(self): if self.worth_playing: # Restore the real position -- advance_time may cause rounding error on the position !!! self.move(self.next_pos) def advance_time(self, proportion): if self.worth_playing: self.add_mul_vector(proportion, self.speed) def hurt(self, life): """Kills LIFE life to this character. Returns true if the character is still alive.""" self.life -= life if self.life < 0.0: self.die() else: return 1 def die(self): explode = Explosion(self.parent, nb_particles = 20) explode.move(self) explode.life = 30 explode.particle_width = explode.particle_height = 0.7 if self.bonus_type: import slune.level as slune_level if self.bonus_type == 1: bonus = slune_level.LifeBonus(self.parent) elif self.bonus_type == 2: bonus = slune_level.FlameThrowerBonus(self.parent) bonus.move(self) bonus.come_back = 0 self.parent.bonuss.append(bonus) sound.play("explose-2.wav", explode) else: sound.play("explose-2.wav", explode) self.parent.pushables.remove(self) self.parent.remove(self) def Barrier(parent, p = None): p = p or Pushable(parent) p.set_shape(soya.Shape.get("gate3")) p.radius_y = 0.5 p.life = 0.5 p.weight = 0.6 return p def Barrier2(parent, p = None): p = p or Pushable(parent) p.set_shape(soya.Shape.get("gate4")) p.radius_y = 0.5 p.life = 0.5 p.weight = 0.6 return p def TreeTrunc(parent, p = None): p = p or Pushable(parent) p.set_shape(soya.Shape.get("tree_trunc")) p.radius = 2.0 p.radius_y = 0.3 p.life = 2.0 p.weight = 1.2 return p def Quille(parent, p = None): p = p or Pushable(parent) p.set_shape(soya.Shape.get("quille-1")) p.radius = 0.7 p.radius_y = 0.7 p.life = 0.1 p.weight = 0.4 return p def Ball(parent, p = None): p = p or Pushable(parent) p.set_shape(soya.Shape.get("ball1")) p.radius = 0.9 p.radius_y = 0.9 p.life = 50.0 p.weight = 0.1 p.bonus_chance = 0.0 return p class TakeableVehicle(soya.Volume): radius = 5.0 def __init__(self, parent = None, vehicle = 3): soya.Volume.__init__(self, parent) self.set_vehicle(vehicle) self.disabled = {} self.changing = 0 self.solid = 0 def set_vehicle(self, vehicle): self.vehicle = vehicle self.set_shape(soya.Shape.get("vehicle" + str(self.vehicle))) def disable(self, character): self.disabled[character] = 1 self.changing = 0 def begin_round(self): soya.Volume.begin_round(self) if not self.changing: for character in self.parent.characters: if isinstance(character, PlayerCharacter): if self.disabled.get(character, 0): if (self.distance_to(character) > self.radius * 2.0): del self.disabled[character] elif (self.distance_to(character) < self.radius): self.changing = 1 # Avoid 2 changing at the same time !!! from videosequence import ChangeVehicle ChangeVehicle(character, self).start(character = character) class Remorque(NonPlayerCharacter, py2play_character.NonPlayerCharacter): clan = 0 def __init__(self, parent = None, remorqued_by = None, remorqued_distance = 1.5): py2play_character.NonPlayerCharacter.__init__(self) NonPlayerCharacter.__init__(self, parent, 0) self.remorqued_by = remorqued_by self.remorqued_distance = remorqued_distance self.set_vehicle(1) def begin_action(self, action): self.current_action = Action() self.speed.set_xyz(0.0, 0.0, 0.0) if self.remorqued_by: _V.set_start_end(self, self.remorqued_by) _V.convert_to(self) _V.set_length(_V.length() - self.remorqued_distance) if _V.length() > 0.48: _V.set_length(0.48) _V.y = _V.y - self.force.y self.speed.set_xyz(_V.x / 20.0, _V.y, _V.z) else: self.speed.set_xyz(0.0, 0.0, 0.0) Character.begin_action(self, self.current_action) RAY_MATERIAL = soya.Material() RAY_MATERIAL.diffuse = (0.7, 0.4, 0.95, 1.0) RAY_MATERIAL.additive_blending = 1 RAY_MATERIAL2 = soya.Material() RAY_MATERIAL2.diffuse = (0.9, 0.6, 0.3, 1.0) RAY_MATERIAL2.additive_blending = 1 RAY_MATERIAL3 = soya.Material() RAY_MATERIAL3.diffuse = (0.0, 0.0, 0.9, 1.0) RAY_MATERIAL3.additive_blending = 1 def PlayerLight(parent): return None light = soya.Light(parent) light.set_xyz(0.0, 1.2, -0.5) light.diffuse = (0.5, 0.6, 1.0, 1.0) light.specular = (0.0, 0.0, 0.0, 1.0) light.quadratic = 0.005 light.linear = 0.2 light.constant = 0.0 light.exponent = 1.0 light.look_at(Vector(parent, 0.0, 0.0, -1.0)) light.angle = 90.0 return light class PlayerCharacter(Character, py2play_character.PlayerCharacter, Competitor): clan = 1 def __init__(self, player = None): py2play_character.PlayerCharacter.__init__(self, player) Character.__init__(self) if player: player.default_action = action.ACTION_WAIT self.set_perso (globdef.CHARACTER.lower()) self.set_vehicle(globdef.VEHICLE) #self.light = PlayerLight(self) if globdef.VERIFICATION_SERVER and self.player: self.logon_verif() def displayname(self): return self.perso_name.title() + " (" + self.player.name + ")" def default_mouse_x(self): if self.controler.uncancelable_controler: return 0.0 return self.player.controler.mouse_x def logon_verif(self): """Log on the verif server.""" import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((globdef.VERIFICATION_SERVER, 36081)) self.player.verif = s.makefile("w", 0) self.player.verif.write("P") # Check position def begin_round(self): if self.player.active: self.plan_action(self.player.controler.next()) else: self.controler.next() py2play_character.PlayerCharacter.begin_round(self) Character.begin_round(self) def begin_action(self, action): if globdef.VERIFICATION_SERVER: import cPickle as pickle pickle.dump((self.player.name, self.round, (self.x, self.y, self.z), None), self.player.verif) # Compute the speed #self.speed.set_xyz(action.mouse_x / 120.0 * self.maxspeedx, 0.0, (action.mouse_y * 0.2 - 0.28) * self.maxspeedz) self.speed.set_xyz(action.mouse_x / 120.0 * self.maxspeedx, 0.0, (action.mouse_y * 0.2 - 0.2) * self.maxspeedz) if action.action == ACTION_STARTGAME: from py2play.idler import IDLER if IDLER.waiting_until_ready: IDLER.start_game() else: IDLER.unpause() Character.begin_action(self, action) def get_controler(self): return self.player.controler if self.player.active: return self.player.controler return None controler = property(get_controler) def hurt(self, life): if self.level.difficulty == 0: return Character.hurt(self, 0.6 * life) elif self.level.difficulty == 1: return Character.hurt(self, 0.9 * life) else: return Character.hurt(self, life) def die(self): if len(explosions) < 4: # Limit the number of simultaneous explosions explode = Explosion(self.parent) explode.move(self) explode.life = 60 explode.particle_width = explode.particle_height = 0.7 sound.play("explose-3.wav", explode) oldlevel = self.level self.level.remove_character(self) self.player.level = oldlevel # May be required !!! if self.player.active: from py2play.idler import IDLER IDLER.show_blackbands() IDLER.camera.add_traveling(soya.FixTraveling(IDLER.camera, Vector(IDLER.camera, 0.0, 0.0, -1.0) % IDLER)) IDLER.message(_("__gameover__"), 100000) # As the character has been removed from the level, the controler # does no longer listen for event such as the "escape" key. AllowQuit(IDLER) def __getstate__(self): state = Character.__getstate__(self) return state[0], self._treat_getstate(state[1]) def __setstate__(self, state): Character.__setstate__(self, state) self._treat_setstate(state) #py2play_character.PlayerCharacter.__setstate__(self, state) # Loaded => imply this character is a phantom one !!! from slune.controler import PhantomControler self.player.controler = PhantomControler() if globdef.VERIFICATION_SERVER: self.logon_verif() def __repr__(self): if self.player: return "" % (self.player.name, self.player.host, self.player.port) explosions = [] class Explosion(soya.Particles): def __init__(self, parent = None, material = None, nb_particles = 30): soya.Particles.__init__(self, parent, material, nb_particles) self.auto_generate_particle = 1 self.set_colors((0.9, 0.0, 0.2, 0.4), (0.9, 0.2, 0.2, 0.8), (0.8, 0.7, 0.1, 0.9), (0.6, 0.4, 0.2, 0.2)) self.set_sizes((1.0, 1.0)) self.life = 25 explosions.append(self) def generate(self, index): angle = random.random() * 3.1417 sx = math.cos(angle) sy = -math.sqrt(random.random() * 3.0) sz = math.sin(angle) l = (0.06 * (1.5 + random.random())) / math.sqrt(sx * sx + sy * sy + sz * sz) self.set_particle(index, 0.5 + random.random(), sx * l, sy * l, sz * l, 0.0, 0.01, 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 explosions.remove(self) self.life = -1 class FlameThrower(soya.Particles): def __init__(self, parent = None, material = None, nb_particles = 35): soya.Particles.__init__(self, parent, material, nb_particles) self.auto_generate_particle = 1 self.set_colors((0.0, 0.8, 0.0, 0.4), (0.1, 0.8, 0.1, 0.9), (0.8, 0.1, 0.1, 0.9), (0.1, 0.1, 0.8, 0.9), (0.2, 0.2, 0.8, 0.2)) self.set_sizes((2.0, 2.0)) self.life = 30 explosions.append(self) def generate(self, index): angle = random.random() * 3.1417 v = Vector(self, random.uniform(-0.3, 0.3), random.uniform(-0.3, 0.3), random.uniform(-1.5, -1.0), ) v.convert_to(self.parent.parent) a = Vector(self, 0.0, 0.00, 0.02) a.convert_to(self.parent.parent) self.set_particle(index, 0.5 + random.random(), v.x, v.y, v.z, a.x, a.y, a.z) def begin_round(self): soya.Particles.begin_round(self) if (self.life > 0) and self.parent: for character in self.parent.level.pushables: cx, cy, cz = self.transform_point(character.x, character.y, character.z, character.parent) if (-20.0 < cz < -0.2) and (-0.5 < cy / cz < 0.5) and (-0.5 < cx / cz < 0.5): character.hurt(-0.1 / (cz - 1.0)) _V.set_start_end(self, character) _V.convert_to(character.parent) _V.set_length(-1.0 / (cz - 1.0) / character.weight) character.push(_V.x, _V.y + 0.04, _V.z, self.parent) if self.life > 0: self.life -= 1 elif self.life == 0: self.auto_generate_particle = 0 self.removable = 1 explosions.remove(self) self.life = -1 class Nitro(soya.Particles): def __init__(self, parent = None, material = None, nb_particles = 50): soya.Particles.__init__(self, parent, material, nb_particles) self.set_colors((0.4, 0.7, 0.8, 0.4), (0.2, 0.7, 0.9, 0.8), (0.2, 0.9, 0.9, 0.9), (0.1, 0.3, 0.3, 0.2)) self.set_sizes((1.0, 1.0)) self.life = 25 self.max_particles_per_round = 4 self.auto_generate_particle = 1 def generate(self, index): angle = random.random() * 3.1417 sx = math.cos(angle) sy = -math.sqrt(random.random() * 3.0) sz = math.sin(angle) l = (0.06 * (1.5 + random.random())) / math.sqrt(sx * sx + sy * sy + sz * sz) #self.set_particle(index, 0.5 + random.random(), 0.0, 0.0, 0.0, random.random() - 0.5, random.random() - 0.5, random.random() - 0.5) pos = self.get_root().transform_vector((random.random() - 0.5) * 0.2, (random.random() - 0.5) * 0.2, 0.2, self) self.set_particle(index, 0.5 + random.random(), pos[0], pos[1], pos[2], 0.0, 0.0, 0.0) # class Explosion(particle.SpriteSystem): # def __init__(self, parent = None, material = None, nb_particles = 30): # particle.SpriteSystem.__init__(self, parent, particle.FireGenerator(initial_speed = 0.4), material or particle._default(), nb_particles = nb_particles) # self.particle_width = self.particle_height = 0.5 # self.life = 25 # explosions.append(self) # def begin_round(self): # if self.life > 0: self.life -= 1 # elif self.life == 0: # self.generator = None # self.removable = 1 # explosions.remove(self) # self.life = -1 # class Snow(particle.Particles): # def __init__(self, parent = None, material = None, nb_particles = 10): # particle.Particles.__init__(self, parent, material or particle._default(), nb_particles) # self.auto_generate_particle = 1 # self.removable = 1 # self.set_colors((0.6, 0.75, 0.8, 0.2), (0.6, 0.75, 0.8, 0.6), (0.4, 0.7, 0.8, 0.2)) # self.set_sizes((1.0, 1.0)) # self.life = 10 # def generate(self, index): # angle = random.random() * 3.1417 # sx = math.cos(angle) # sy = -math.sqrt(random.random() * 3.0) # sz = math.sin(angle) # l = (0.06 * (1.5 + random.random())) / math.sqrt(sx * sx + sy * sy + sz * sz) # self.set_particle(index, 0.5 + random.random(), sx * l, sy * l, sz * l, 0.0, 0.01, 0.0) # def begin_round(self): # particle.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 class LifeBar(widget.Widget): def __init__(self, character = None): widget.Widget.__init__(self) self.character = character self.left = soya.get_screen_width() - 30.0 self.top = 10.0 self.width = 20.0 self.height = soya.get_screen_height() - 20.0 def render(self): if self.character: import soya.opengl as soyaopengl soyaopengl.glBegin(soyaopengl.GL_QUADS) soyaopengl.glColor4f(0.7, 0.0, 0.0, 1.0) soyaopengl.glVertex2f(self.left , self.top + self.height) soyaopengl.glVertex2f(self.left + self.width, self.top + self.height) top = self.top + (1.0 - self.character.life) * self.height soyaopengl.glColor4f(1.0, 0.7, 0.0, 1.0) soyaopengl.glVertex2f(self.left + self.width, top) soyaopengl.glVertex2f(self.left , top) soyaopengl.glEnd() class BossLifeBar(widget.Widget): def __init__(self, character = None): widget.Widget.__init__(self) self.character = character self.left = 20.0 self.top = 10.0 self.width = 20.0 self.height = soya.get_screen_height() - 20.0 def render(self): if self.character: import soya.opengl as soyaopengl soyaopengl.glBegin(soyaopengl.GL_QUADS) soyaopengl.glColor4f(0.0, 0.5, 0.0, 1.0) soyaopengl.glVertex2f(self.left , self.top + self.height) soyaopengl.glVertex2f(self.left + self.width, self.top + self.height) top = self.top + (1.0 - self.character.life) * self.height soyaopengl.glColor4f(0.7, 1.0, 0.0, 1.0) soyaopengl.glVertex2f(self.left + self.width, top) soyaopengl.glVertex2f(self.left , top) soyaopengl.glEnd() class AllowQuit(soya.CoordSyst): def begin_round(self): soya.CoordSyst.begin_round(self) import soya.sdlconst as soyasdlconst for event in soya.process_event(): if (event[0] == soyasdlconst.MOUSEBUTTONDOWN) or (event[0] == soyasdlconst.KEYDOWN) or (event[0] == soyasdlconst.JOYBUTTONDOWN): from py2play.idler import IDLER IDLER.end_game()