#! /usr/bin/env python # Conozco Uruguay # Copyright (C) 2008,2009,2010 Gabriel Eirea # # 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 3 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, see . # # Contact information: # Gabriel Eirea geirea@gmail.com # Ceibal Jam http://ceibaljam.org import sys import random import os import pygame import olpcgames import gtk # constantes XMAPAMAX = 786 DXPANEL = 414 XCENTROPANEL = 1002 YGLOBITO = 310 DXBICHO = 218 DYBICHO = 268 XBICHO = 1200-DXBICHO YBICHO = 900-DYBICHO XNAVE = 800 YNAVE = 650 DXNAVE = 100 DYNAVE = 200 CAMINORECURSOS = "recursos" CAMINOCOMUN = "comun" CAMINOFUENTES = "fuentes" CAMINODATOS = "datos" ARCHIVOINFO = "info.txt" ARCHIVONIVELES = "niveles.txt" ARCHIVONOMBRE = "nombre.txt" ARCHIVOZONAS = "zonas.txt" ARCHIVOEXPLORACIONES = "exploraciones.txt" ARCHIVOCREDITOS = "creditos.txt" CAMINOIMAGENES = "imagenes" CAMINOSONIDOS = "sonidos" COLORNOMBRE = (10,10,10) COLORPREGUNTAS = (80,80,155) COLORPANEL = (156,158,172) TOTALAVANCE = 7 EVENTORESPUESTA = pygame.USEREVENT+1 TIEMPORESPUESTA = 2300 EVENTODESPEGUE = EVENTORESPUESTA+1 TIEMPODESPEGUE = 40 EVENTOREFRESCO = EVENTODESPEGUE+1 TIEMPOREFRESCO = 250 ESTADONORMAL = 1 ESTADOPESTANAS = 2 ESTADOFRENTE = 3 ESTADODESPEGUE = 4 # variables globales para adaptar la pantalla a distintas resoluciones scale = 1 shift_x = 0 shift_y = 0 xo_resolution = True clock = pygame.time.Clock() def wait_events(): """ Funcion para esperar por eventos de pygame sin consumir CPU """ global clock clock.tick(20) return pygame.event.get() class Zona(): """Clase para objetos geograficos que se pueden definir como una zona. La posicion esta dada por una imagen bitmap pintada con un color especifico, dado por la clave (valor 0 a 255 del componente rojo). """ ################ tipo????????????? def __init__(self,mapa,nombre,claveColor,tipo,posicion,rotacion): self.mapa = mapa self.nombre = nombre self.claveColor = int(claveColor) self.tipo = int(tipo) self.posicion = (int(int(posicion[0])*scale+shift_x), int(int(posicion[1])*scale+shift_y)) self.rotacion = int(rotacion) def estaAca(self,pos): """Devuelve True si la coordenada pos esta en la zona""" if pos[0] < XMAPAMAX*scale+shift_x: try: colorAca = self.mapa.get_at((int(pos[0]-shift_x), int(pos[1]-shift_y))) except: # probablemente click fuera de la imagen return False if colorAca[0] == self.claveColor: return True else: return False else: return False def mostrarNombre(self,pantalla,fuente,color,flipAhora): """Escribe el nombre de la zona en su posicion""" text = fuente.render(self.nombre, 1, color) textrot = pygame.transform.rotate(text, self.rotacion) textrect = textrot.get_rect() textrect.center = (self.posicion[0], self.posicion[1]) pantalla.blit(textrot, textrect) if flipAhora: pygame.display.flip() class Nivel(): """Clase para definir los niveles del juego. Cada nivel tiene un dibujo inicial, los elementos pueden estar etiquetados con el nombre o no, y un conjunto de preguntas. """ def __init__(self,nombre): self.nombre = nombre self.preguntas = list() self.indicePreguntaActual = 0 self.elementosActivos = list() def prepararPreguntas(self): """Este metodo sirve para preparar la lista de preguntas al azar.""" random.shuffle(self.preguntas) def siguientePregunta(self,listaSufijos,listaPrefijos): """Prepara el texto de la pregunta siguiente""" self.preguntaActual = self.preguntas[self.indicePreguntaActual] self.sufijoActual = random.randint(1,len(listaSufijos))-1 self.prefijoActual = random.randint(1,len(listaPrefijos))-1 lineas = listaPrefijos[self.prefijoActual].split("\\") lineas.extend(self.preguntaActual[0].split("\\")) lineas.extend(listaSufijos[self.sufijoActual].split("\\")) self.indicePreguntaActual = self.indicePreguntaActual+1 if self.indicePreguntaActual == len(self.preguntas): self.indicePreguntaActual = 0 return lineas def devolverAyuda(self): """Devuelve la linea de ayuda""" self.preguntaActual = self.preguntas[self.indicePreguntaActual-1] return self.preguntaActual[2].split("\\") def mostrarPregunta(self,pantalla,fuente,sufijo,prefijo): """Muestra la pregunta en el globito""" self.preguntaActual = self.preguntas[self.indicePreguntaActual] lineas = prefijo.split("\\") lineas.extend(self.preguntaActual[0].split("\\")) lineas.extend(sufijo.split("\\")) yLinea = 100 for l in lineas: text = fuente.render(l, 1, COLORPREGUNTAS) textrect = text.get_rect() textrect.center = (XCENTROPANEL,yLinea) pantalla.blit(text, textrect) yLinea = yLinea + fuente.get_height() pygame.display.flip() class ConozcoUy(): """Clase principal del juego. """ def mostrarTexto(self,texto,fuente,posicion,color): """Muestra texto en una determinada posicion""" text = fuente.render(texto, 1, color) textrect = text.get_rect() textrect.center = posicion self.pantalla.blit(text, textrect) def cargarZonas(self): """Carga las imagenes y los datos de las zonas""" self.zonas = self.cargarImagen("zonas.png") self.listaZonas = list() # falta sanitizar manejo de archivo f = open(os.path.join(self.camino_datos,ARCHIVOZONAS),"r") linea = f.readline() while linea: if linea[0] == "#": linea = f.readline() continue [nombreZona,claveColor,posx,posy,rotacion] = \ linea.strip().split("|") nuevaZona = Zona(self.zonas, unicode(nombreZona,'iso-8859-1'), claveColor,1,(posx,posy),rotacion) self.listaZonas.append(nuevaZona) linea = f.readline() f.close() def cargarListaDirectorios(self): """Carga la lista de directorios con los distintos mapas""" self.listaDirectorios = list() self.listaNombreDirectorios = list() listaTemp = os.listdir(CAMINORECURSOS) listaTemp.sort() for d in listaTemp: if d == "comun": pass else: self.listaDirectorios.append(d) f = open(os.path.join(CAMINORECURSOS,d,ARCHIVONOMBRE),"r") linea = f.readline() self.listaNombreDirectorios.append(\ unicode(linea.strip(),'iso-8859-1')) f.close() def cargarNiveles(self): """Carga los niveles del archivo de configuracion""" self.listaNiveles = list() self.listaPrefijos = list() self.listaSufijos = list() self.listaCorrecto = list() self.listaMal = list() self.listaDespedidas = list() # falta sanitizar manejo de archivo f = open(os.path.join(self.camino_datos,ARCHIVONIVELES),"r") linea = f.readline() while linea: if linea[0] == "#": linea = f.readline() continue if linea[0] == "[": # empieza nivel nombreNivel = linea.strip("[]\n") nuevoNivel = Nivel(nombreNivel) self.listaNiveles.append(nuevoNivel) linea = f.readline() continue if linea.find("=") == -1: linea = f.readline() continue [var,valor] = linea.strip().split("=") if var.startswith("Prefijo"): self.listaPrefijos.append( unicode(valor.strip(),'iso-8859-1')) elif var.startswith("Sufijo"): self.listaSufijos.append( unicode(valor.strip(),'iso-8859-1')) elif var.startswith("Correcto"): self.listaCorrecto.append( unicode(valor.strip(),'iso-8859-1')) elif var.startswith("Mal"): self.listaMal.append( unicode(valor.strip(),'iso-8859-1')) elif var.startswith("Despedida"): self.listaDespedidas.append( unicode(valor.strip(),'iso-8859-1')) elif var.startswith("Pregunta"): [texto,respuesta,ayuda] = valor.split("|") listaRespuestas = unicode(respuesta.strip(),'iso-8859-1').split(",") nuevoNivel.preguntas.append( (unicode(texto.strip(),'iso-8859-1'), listaRespuestas, unicode(ayuda.strip(),'iso-8859-1'))) linea = f.readline() f.close() self.indiceNivelActual = 0 self.numeroNiveles = len(self.listaNiveles) self.numeroSufijos = len(self.listaSufijos) self.numeroPrefijos = len(self.listaPrefijos) self.numeroCorrecto = len(self.listaCorrecto) self.numeroMal = len(self.listaMal) self.numeroDespedidas = len(self.listaDespedidas) def pantallaAcercaDe(self): """Pantalla con los datos del juego, creditos, etc""" global scale, shift_x, shift_y, xo_resolution self.pantallaTemp = pygame.Surface( (self.anchoPantalla,self.altoPantalla)) self.pantallaTemp.blit(self.pantalla,(0,0)) self.pantalla.fill((0,0,0)) self.pantalla.blit(self.terron, (int(20*scale+shift_x), int(20*scale+shift_y))) self.mostrarTexto("Acerca de Conozco", self.fuente40, (int(600*scale+shift_x), int(100*scale+shift_y)), (255,255,255)) # falta sanitizar acceso a archivo f = open(os.path.join(CAMINORECURSOS, CAMINOCOMUN, CAMINODATOS, ARCHIVOCREDITOS),"r") yLinea = int(200*scale+shift_y) for linea in f: self.mostrarTexto(linea.strip(), self.fuente32, (int(600*scale+shift_x),yLinea), (155,155,255)) yLinea = yLinea + int(40*scale) f.close() self.mostrarTexto("Presiona cualquier tecla para volver", self.fuente32, (int(600*scale+shift_x), int(800*scale+shift_y)), (255,155,155)) pygame.display.flip() while 1: for event in wait_events(): if event.type == pygame.KEYDOWN or \ event.type == pygame.MOUSEBUTTONDOWN: self.click.play() self.pantalla.blit(self.pantallaTemp,(0,0)) pygame.display.flip() return elif event.type == EVENTOREFRESCO: pygame.display.flip() def pantallaInicial(self): """Pantalla con el menu principal del juego""" global scale, shift_x, shift_y self.pantalla.fill((0,0,0)) self.mostrarTexto("CONOZCO", self.fuente48, (int(600*scale+shift_x), int(80*scale+shift_y)), (255,255,255)) self.mostrarTexto("Has elegido la lamina "+\ self.listaNombreDirectorios\ [self.indiceDirectorioActual], self.fuente40, (int(600*scale+shift_x), int(140*scale+shift_y)), (200,100,100)) self.mostrarTexto("Selecciona el nivel", self.fuente40, (int(600*scale+shift_x), int(220*scale+shift_y)), (200,100,100)) yLista = int(300*scale+shift_y) for n in self.listaNiveles: self.pantalla.fill((20,20,20), (int(310*scale+shift_x), yLista-int(24*scale), int(590*scale), int(48*scale))) self.mostrarTexto(n.nombre, self.fuente40, (int(600*scale+shift_x), yLista), (200,100,100)) yLista += int(50*scale) self.pantalla.fill((20,20,20), (int(10*scale+shift_x), int(801*scale+shift_y), int(590*scale),int(48*scale))) self.mostrarTexto("Sobre este juego", self.fuente40, (int(300*scale+shift_x),int(825*scale+shift_y)), (100,200,100)) self.pantalla.fill((20,20,20), (int(610*scale+shift_x), int(801*scale+shift_y), int(590*scale),int(48*scale))) self.mostrarTexto("Volver", self.fuente40, (int(900*scale+shift_x),int(825*scale+shift_y)), (100,200,100)) pygame.display.flip() while 1: for event in wait_events(): if event.type == pygame.KEYDOWN: if event.key == 27: # escape: volver self.click.play() self.elegir_directorio = True return elif event.type == pygame.MOUSEBUTTONDOWN: self.click.play() pos = event.pos if pos[1] > 275*scale + shift_y and \ pos[1] < 800*scale +shift_y and \ pos[0] > 300*scale + shift_x and \ pos[0] < 900*scale + shift_x: # zona de opciones if pos[1] < 275*scale + shift_y + \ len(self.listaNiveles)*50*scale: # nivel self.indiceNivelActual = \ int((pos[1]-int(275*scale+shift_y))//\ int(50*scale)) return elif pos[1] > 800*scale + shift_y and \ pos[1] < 850*scale + shift_y and \ pos[0] > shift_x and \ pos[0] < 600*scale + shift_x: # acerca de self.pantallaAcercaDe() elif pos[1] > 800*scale + shift_y and \ pos[1] < 850*scale+shift_y and \ pos[0] > 600*scale + shift_x and \ pos[0] < 1200*scale + shift_x: # volver self.elegir_directorio = True return elif event.type == EVENTOREFRESCO: pygame.display.flip() def pantallaDirectorios(self): """Pantalla con el menu de directorios""" global scale, shift_x, shift_y self.pantalla.fill((0,0,0)) self.mostrarTexto("CONOZCO", self.fuente48, (int(600*scale+shift_x),int(80*scale+shift_y)), (255,255,255)) self.mostrarTexto("Elige la lamina a utilizar", self.fuente40, (int(600*scale+shift_x),int(140*scale+shift_y)), (200,100,100)) nDirectorios = len(self.listaNombreDirectorios) paginaDirectorios = self.paginaDir while 1: yLista = int(200*scale+shift_y) self.pantalla.fill((0,0,0), (int(shift_x),yLista-int(24*scale), int(1200*scale),int(600*scale))) if paginaDirectorios == 0: paginaAnteriorActiva = False else: paginaAnteriorActiva = True paginaSiguienteActiva = False if paginaAnteriorActiva: self.pantalla.fill((20,20,20), (int(10*scale+shift_x),yLista-int(24*scale), int(590*scale),int(48*scale))) self.mostrarTexto("<<< Pagina anterior", self.fuente40, (int(300*scale+shift_x),yLista), (100,100,200)) yLista += int(50*scale) indiceDir = paginaDirectorios * 20 terminar = False while not terminar: self.pantalla.fill((20,20,20), (int(10*scale+shift_x),yLista-int(24*scale), int(590*scale),int(48*scale))) self.mostrarTexto(self.listaNombreDirectorios[indiceDir], self.fuente40, (int(300*scale+shift_x),yLista), (200,100,100)) yLista += int(50*scale) indiceDir = indiceDir + 1 if indiceDir == nDirectorios or \ indiceDir == paginaDirectorios * 20 + 10: terminar = True if indiceDir == paginaDirectorios * 20 + 10 and \ not indiceDir == nDirectorios: nDirectoriosCol1 = 10 yLista = int(250*scale+shift_y) terminar = False while not terminar: self.pantalla.fill((20,20,20), (int(610*scale+shift_x), yLista-int(24*scale), int(590*scale),int(48*scale))) self.mostrarTexto(self.listaNombreDirectorios[indiceDir], self.fuente40, (int(900*scale+shift_x),yLista), (200,100,100)) yLista += int(50*scale) indiceDir = indiceDir + 1 if indiceDir == nDirectorios or \ indiceDir == paginaDirectorios * 20 + 20: terminar = True if indiceDir == paginaDirectorios * 20 + 20: if indiceDir < nDirectorios: self.pantalla.fill((20,20,20), (int(610*scale+shift_x), yLista-int(24*scale), int(590*scale),int(48*scale))) self.mostrarTexto("Pagina siguiente >>>", self.fuente40, (int(900*scale+shift_x),yLista), (100,100,200)) paginaSiguienteActiva = True nDirectoriosCol2 = 10 else: nDirectoriosCol2 = indiceDir - paginaDirectorios * 20 - 10 else: nDirectoriosCol1 = indiceDir - paginaDirectorios * 20 nDirectoriosCol2 = 0 self.pantalla.fill((20,20,20), (int(10*scale+shift_x),int(801*scale+shift_y), int(590*scale),int(48*scale))) self.mostrarTexto("Sobre este juego", self.fuente40, (int(300*scale+shift_x),int(825*scale+shift_y)), (100,200,100)) self.pantalla.fill((20,20,20), (int(610*scale+shift_x),int(801*scale+shift_y), int(590*scale),int(48*scale))) self.mostrarTexto("Salir", self.fuente40, (int(900*scale+shift_x),int(825*scale+shift_y)), (100,200,100)) pygame.display.flip() cambiarPagina = False while not cambiarPagina: for event in wait_events(): if event.type == pygame.KEYDOWN: if event.key == 27: # escape: salir self.click.play() sys.exit() elif event.type == pygame.MOUSEBUTTONDOWN: self.click.play() pos = event.pos if pos[1] > 175*scale+shift_y: # zona de opciones if pos[0] < 600*scale+shift_x: # primera columna if pos[1] < 175*scale + shift_y + \ (nDirectoriosCol1+1)*50*scale: # mapa self.indiceDirectorioActual = \ int((pos[1]-int(175*scale+shift_y))//\ int(50*scale)) - 1 + \ paginaDirectorios*20 if self.indiceDirectorioActual == \ paginaDirectorios*20-1 and \ paginaAnteriorActiva: # pag. ant. paginaDirectorios = paginaDirectorios-1 paginaSiguienteActiva = True cambiarPagina = True elif self.indiceDirectorioActual>\ paginaDirectorios*20-1: self.paginaDir = paginaDirectorios return elif pos[1] > 800*scale + shift_y and \ pos[1] < 850*scale + shift_y: # acerca self.pantallaAcercaDe() else: if pos[1] < 225*scale + shift_y + \ nDirectoriosCol2*50*scale or \ (paginaSiguienteActiva and \ pos[1]<775*scale+shift_y): # mapa self.indiceDirectorioActual = \ int((pos[1]-int(225*scale+shift_y))//\ int(50*scale)) + \ paginaDirectorios*20 + 10 if self.indiceDirectorioActual == \ paginaDirectorios*20+9: pass # ignorar; espacio vacio elif self.indiceDirectorioActual == \ paginaDirectorios*20+20 and \ paginaSiguienteActiva: # pag. sig. paginaDirectorios = \ paginaDirectorios + 1 paginaAnteriorActiva = True cambiarPagina = True elif self.indiceDirectorioActual<\ paginaDirectorios*20+20: self.paginaDir = paginaDirectorios return elif pos[1] > 800*scale+shift_y and \ pos[1] < 850*scale+shift_y: # salir sys.exit() elif event.type == EVENTOREFRESCO: pygame.display.flip() def cargarImagen(self,nombre): """Carga una imagen y la escala de acuerdo a la resolucion""" global scale, xo_resolution if xo_resolution: imagen = pygame.image.load( \ os.path.join(self.camino_imagenes,nombre)) else: imagen0 = pygame.image.load( \ os.path.join(self.camino_imagenes,nombre)) imagen = pygame.transform.scale(imagen0, (int(imagen0.get_width()*scale), int(imagen0.get_height()*scale))) del imagen0 return imagen def __init__(self): """Esta es la inicializacion del juego""" global scale, shift_x, shift_y, xo_resolution pygame.init() # crear pantalla self.anchoPantalla = gtk.gdk.screen_width() self.altoPantalla = gtk.gdk.screen_height() self.pantalla = pygame.display.set_mode((self.anchoPantalla, self.altoPantalla)) if self.anchoPantalla==1200 and self.altoPantalla==900: xo_resolution = True scale = 1 shift_x = 0 shift_y = 0 else: xo_resolution = False if self.anchoPantalla/1200.0 975*scale+shift_x and \ event.pos[0] < 1175*scale+shift_x and \ event.pos[1] > 25*scale+shift_y and \ event.pos[1] < 75*scale+shift_y: # terminar return elif event.type == EVENTORESPUESTA: pygame.time.set_timer(EVENTORESPUESTA,0) if self.esCorrecto: if self.avanceNivel == TOTALAVANCE: return self.avanceNivel = self.avanceNivel + 1 if self.avanceNivel == TOTALAVANCE: # fin self.lineasPregunta = self.listaDespedidas[\ random.randint(1,self.numeroDespedidas)-1]\ .split("\\") self.mostrarGlobito(self.lineasPregunta) pygame.time.set_timer(EVENTORESPUESTA, TIEMPORESPUESTA) else: # pregunta siguiente self.lineasPregunta = \ self.nivelActual.siguientePregunta(\ self.listaSufijos,self.listaPrefijos) self.mostrarGlobito(self.lineasPregunta) self.nRespuestasMal = 0 else: if self.nRespuestasMal >= 2: # ayuda self.mostrarGlobito( self.nivelActual.devolverAyuda()) self.nRespuestasMal = 0 pygame.time.set_timer( EVENTORESPUESTA,TIEMPORESPUESTA) else: # volver a preguntar self.mostrarGlobito(self.lineasPregunta) elif event.type == EVENTOREFRESCO: if self.estadobicho == ESTADONORMAL: if random.randint(1,15) == 1: self.estadobicho = ESTADOPESTANAS self.pantalla.blit(self.bichopestanas, (int(XBICHO*scale+shift_x), int(YBICHO*scale+shift_y))) elif random.randint(1,20) == 1: self.estadobicho = ESTADOFRENTE self.pantalla.blit(self.bichofrente, (int(XBICHO*scale+shift_x), int(YBICHO*scale+shift_y))) elif self.estadobicho == ESTADOPESTANAS: self.estadobicho = ESTADONORMAL self.pantalla.blit(self.bicho, (int(XBICHO*scale+shift_x), int(YBICHO*scale+shift_y))) elif self.estadobicho == ESTADOFRENTE: if random.randint(1,10) == 1: self.estadobicho = ESTADONORMAL self.pantalla.blit(self.bicho, (int(XBICHO*scale+shift_x), int(YBICHO*scale+shift_y))) elif self.estadobicho == ESTADODESPEGUE: pass pygame.display.flip() def principal(self): """Este es el loop principal del juego""" global scale, shift_x, shift_y pygame.time.set_timer(EVENTOREFRESCO,TIEMPOREFRESCO) self.paginaDir = 0 while 1: self.pantallaDirectorios() # seleccion de mapa pygame.mouse.set_cursor((32,32), (1,1), *self.cursor_espera) self.directorio = self.listaDirectorios\ [self.indiceDirectorioActual] self.cargarDirectorio() pygame.mouse.set_cursor((32,32), (1,1), *self.cursor) while 1: # pantalla inicial de juego self.elegir_directorio = False self.pantallaInicial() if self.elegir_directorio: # volver a seleccionar mapa break # dibujar fondo y panel self.pantalla.blit(self.fondo, (shift_x, shift_y)) self.pantalla.fill(COLORPANEL, (int(XMAPAMAX*scale+shift_x),shift_y, int(DXPANEL*scale),int(900*scale))) self.pantalla.blit(self.bicho, (int(XBICHO*scale+shift_x), int(YBICHO*scale+shift_y))) self.estadobicho = ESTADONORMAL # mostrar pantalla pygame.display.flip() # ir al juego self.jugarNivel() def main(): juego = ConozcoUy() juego.principal() if __name__ == "__main__": main()