# 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 time, random, math, slune.sound as sound import soya, soya.widget as widget, soya.ray as ray import py2play.level as py2p_level, py2play.action as action, py2play.character as character from soya import Point, Vector import slune.character as slune_character import slune.controler def init_freestyle_game(level): pass def start_freestyle_game(level, time_limit = -1.0, no_time_left_message = None): competitors = [] for character in level.characters: if isinstance(character, slune_character.Competitor): character.score = 0 character.score_start = time.time() competitors.append(character) from py2play.idler import IDLER IDLER.no_blackbands_group.add(ScoreLabel(competitors, time_limit, no_time_left_message)) def end_freestyle_game(level): for widget in soya.root_widget.children: if isinstance(widget, ScoreLabel): soya.root_widget.remove(widget) break def start_time_limit(level, time_limits, no_time_left_message = None, start_checker = 0): competitors = [] for character in level.characters: if isinstance(character, slune_character.Competitor): character.score_start = time.time() competitors.append(character) from py2play.idler import IDLER IDLER.no_blackbands_group.add(TimerLabel(competitors, time_limits[level.difficulty], no_time_left_message)) if start_checker: Checker(level) if not hasattr(level, "flags"): import race level.flags = [] # Indexes all flags for item in level: if isinstance(item, race.Flag): item.visible = (item.name == "flag_0") level.flags.append(item) level.flags.sort(lambda f1, f2: cmp(f1.flag_id, f2.flag_id)) def end_time_limit(level): for widget in soya.root_widget.children: if isinstance(widget, TimerLabel): soya.root_widget.remove(widget) break class Checker(soya.Volume): def begin_round(self): from py2play.idler import IDLER level = self.parent for character in level.characters: if isinstance(character, slune_character.Competitor): flag = level.flags[character.next_flag_id] if character.distance_to(flag) < (flag.radius + character.radius): if character.next_flag_id + 1 < len(self.parent.flags): next_flag_id = character.next_flag_id + 1 next_flag = self.parent.flags[next_flag_id] else: next_flag_id = 0 next_flag = self.parent.flags[0] character.nb_laps += 1 now = time.time() this_lap = now - character.lap_start if this_lap < character.best_lap: character.best_lap = this_lap character.lap_start = now if character.nb_laps >= 0: firework = soya.FlagFirework(level, nb_particles = 6) firework.move(flag) firework.regenerate() firework.removable = 1 character.next_flag_id = 0 level.ranks.append(character) if len(level.ranks) == 1: # Winner IDLER.level_completed(character, 1, _("__race_winner__")) else: IDLER.level_completed(character, 0, _("__race_looser__") % len(level.ranks)) from py2play.player import CURRENT_PLAYER if not character is CURRENT_PLAYER.character: IDLER.message(_("__race_arrival__") % (character.displayname(), len(level.ranks))) if not character.played: character.level.remove_character(character) return character.next_flag_id = next_flag_id sound.play("flag-1.wav", character) if character.played and character.player.active: flag.visible = 0 next_flag.visible = 1 firework = soya.Smoke(level, nb_particles = 10, removable = 1) firework.move(flag) firework.regenerate() V = Vector() SCORES = { "jump" : 5, "longjump" : 10, "verylongjump" : 150, "climbing" : 10, "highjump" : 15, "180" : 50, "360" : 85, "720" : 110, "rotup" : 50, "rotup180" : 120, "rotup360" : 150, "rotup720" : 1000, "looping" : 100, "doublelooping" : 1000, "retrolooping" : 200, "doubleretrolooping" : 1500, "s" : 100, "doubles" : 1000, "spinfall" : 150, "bigspinfall" : 1200, "flamingtorch" : 80, "bigflamingtorch" : 800, } class FreeStyle(soya.Volume): def __init__(self, parent = None, character = None): soya.Volume.__init__(self, parent) self.character = character self.last_figure = "" self.last_figure_nb = 0 self.last_figure_time = 0 self.jump_direction = Vector() self.last_180_direction = Vector() self.last_180_y = 1.0 self.on_ground = 1 self.y_angle = 0.0 self.y_direction = Vector() self.jump_time = 0 self.nb_180 = 0 self.nb_s = 0 self.next_s_dir = -1.0 self.jump_y = 0.0 self.max_y = 0.0 self.spinfall = 0 self.flamingtorch = 0 def recognized(self, figure): from py2play.idler import IDLER if (self.last_figure == figure) and (self.character.round - self.last_figure_time < 500): self.last_figure = figure self.last_figure_nb += 1 self.last_figure_time = self.character.round bonus = self.last_figure_nb * SCORES[figure] IDLER.message(_("__figure_" + figure + "__") + " X " + str(self.last_figure_nb) + " (" + str(bonus) + ")") else: self.last_figure = figure self.last_figure_nb = 1 self.last_figure_time = self.character.round bonus = SCORES[figure] IDLER.message(_("__figure_" + figure + "__") + " (" + str(bonus) + ")") self.character.score += bonus def begin_round(self): if self.on_ground and not self.character.on_ground: # Start jumping self.jump_time = 0 self.on_ground = 0 self.y_angle = 0.0 self.nb_180 = 0 self.nb_s = 0 self.next_s_dir = -1.0 self.spinfall = 0 self.flamingtorch = 0 self.jump_y = self.character.y self.max_y = self.jump_y self.last_180_y = 1.0 self.jump_direction.set_xyz(*self.character.level.transform_vector(0.0, 0.0, -1.0, self.character)) self.last_180_direction.clone(self.jump_direction) self.y_direction.clone(self.jump_direction) elif self.character.on_ground and not self.on_ground: # End jumping self.on_ground = 1 if self.jump_time < 20: return # NOT a valid jump !!! if (self.y_angle > 560.0): self.recognized("doublelooping"); return if (self.y_angle > 200.0): self.recognized("looping"); return if (self.y_angle < -560.0): self.recognized("doubleretrolooping"); return if (self.y_angle < -200.0): self.recognized("retrolooping"); return if self.nb_s == 2: self.recognized("s"); return if self.nb_s == 4: self.recognized("doubles"); return if self.spinfall > 27: self.recognized("bigspinfall"); return if self.spinfall > 10: self.recognized("spinfall"); return if self.flamingtorch > 30: self.recognized("bigflamingtorch"); return if self.flamingtorch > 10: self.recognized("flamingtorch"); return if self.y_direction.y > 0.75: if self.nb_180 == 1: self.recognized("180"); return if self.nb_180 == 2: self.recognized("360"); return if self.nb_180 == 4: self.recognized("720"); return elif self.y_direction.y < -0.75: if self.nb_180 == 2: self.recognized("rotup180"); return if self.nb_180 == 3: self.recognized("rotup360"); return if self.nb_180 == 5: self.recognized("rotup720"); return if self.y_direction.y < -0.5: self.recognized("rotup"); return if self.jump_time > 200: self.recognized("verylongjump"); return if self.character.y - self.jump_y > 3.0: self.recognized("climbing"); return if self.max_y - self.jump_y > 7.0: self.recognized("highjump"); return if self.jump_time > 70: self.recognized("longjump"); return if self.jump_time > 20: self.recognized("jump"); return if not self.character.on_ground: # Jumping self.jump_time += 1 if self.max_y < self.character.y: self.max_y = self.character.y x, y, z = self.character.transform_vector(self.y_direction.x, self.y_direction.y, self.y_direction.z, self.character.level) #self.y_angle -= z if self.character.current_action.action == slune_character.ACTION_ROTUP: self.y_angle += self.character.rotup_speed elif self.character.current_action.action == slune_character.ACTION_ROTDOWN: self.y_angle -= self.character.rotup_speed self.y_direction.set_xyz(*self.character.level.transform_vector(0.0, 1.0, 0.0, self.character)) if self.y_direction.y * self.next_s_dir > 0.8: self.nb_s += 1 self.next_s_dir *= -1.0 V.set_xyz(*self.character.level.transform_vector(0.0, 0.0, -1.0, self.character)) if V.dot_product(self.last_180_direction) < -0.5: if self.last_180_y * self.y_direction.y > 0.3: self.nb_180 += 1 self.last_180_direction *= -1 else: self.last_180_y *= -1.0 if self.character.current_action.action == slune_character.ACTION_ROTLAT: if V.y < -0.6: self.spinfall += 1 elif (V.y > 0.8) and self.character.current_action.mouse_y > 0.8: self.flamingtorch += 1 class ScoreLabel(widget.Label): def __init__(self, characters, time_limit = -1.0, no_time_left_message = None): self.characters = characters self.format1 = str(_("__scoreformat1__")) + "\n" format2 = str(_("__scoreformat2__")) self.format2s = "\n".join([character.displayname() + format2 for character in characters]) widget.Label.__init__(self) self.left = 10 self.top = soya.root_widget.height - 33 * (len(self.characters) + 1) self.width = 400 self.height = 100 self.time_limit = time_limit self.no_time_left_message = no_time_left_message or _("__no_time_left__") def resize(self, parent_left, parent_top, parent_width, parent_height): self.top = soya.root_widget.height - 33 * (len(self.characters) + 1) def render(self): if self.time_limit == -1.0: time_left = 0.0 else: time_left = (self.time_limit - (time.time() - self.characters[0].score_start)) if time_left < 0.0: self.time_limit = -1.0 import videosequence for character in self.characters: videosequence.MissionCompleted(0, self.no_time_left_message).start(tux = character) if len(self.characters) == 1: self.text = self.format1 % time_left + self.format2s % self.characters[0].score else: self.text = self.format1 % time_left + self.format2s % [str(character.score) for character in self.characters] widget.Label.render(self) class TimerLabel(widget.Label): def __init__(self, characters, time_limit = -1.0, no_time_left = None): self.characters = characters self.format1 = str(_("__scoreformat1__")) + "\n" widget.Label.__init__(self) self.left = 10 self.top = soya.root_widget.height - 33 self.width = 400 self.height = 100 self.time_limit = time_limit self.no_time_left = no_time_left or _("__no_time_left__") def resize(self, parent_left, parent_top, parent_width, parent_height): self.top = soya.root_widget.height - 33 def render(self): if self.time_limit == -1.0: time_left = 0.0 else: time_left = (self.time_limit - (time.time() - self.characters[0].score_start)) if time_left < 0.0: self.time_limit = -1.0 if callable(self.no_time_left): self.no_time_left(self.characters) else: import videosequence for character in self.characters: videosequence.MissionCompleted(0, self.no_time_left).start(tux = character) self.text = self.format1 % time_left widget.Label.render(self)