Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • main
1 result

Target

Select target project
  • diegval/el-legado-de-pintia
1 result
Select Git revision
  • main
1 result
Show changes
Commits on Source (5)
Showing
with 233 additions and 91 deletions
......@@ -19,9 +19,11 @@ import com.example.ellegadodepintia.exploradoresDePintia.model.GameState
import com.example.ellegadodepintia.exploradoresDePintia.model.GeneradorDeEventos
import com.example.ellegadodepintia.exploradoresDePintia.model.LayoutUtils
import com.example.ellegadodepintia.exploradoresDePintia.model.GestorDeEventos
import com.example.ellegadodepintia.soundManager.SoundManager
import java.lang.ref.WeakReference
class ExploradoresDePintia : AppCompatActivity() {
private lateinit var soundManager: SoundManager
private var dificultad = 0
private lateinit var startForResult: ActivityResultLauncher<Intent>
......@@ -30,6 +32,8 @@ class ExploradoresDePintia : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_exploradores_de_pintia)
soundManager = SoundManager(this)
soundManager.playSoundLoop(R.raw.sound_exploradores_idle,100)
startForResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
......@@ -102,5 +106,10 @@ class ExploradoresDePintia : AppCompatActivity() {
}
override fun onDestroy() {
super.onDestroy()
soundManager.stopSound()
}
}
......@@ -8,29 +8,84 @@ import com.example.ellegadodepintia.exploradoresDePintia.model.GameState.context
import com.example.ellegadodepintia.exploradoresDePintia.model.eventoFactory.Evento
import com.example.ellegadodepintia.exploradoresDePintia.model.eventoFactory.EventoCombate
import com.example.ellegadodepintia.exploradoresDePintia.model.eventoFactory.EventoFactorySelector
import kotlin.random.Random
object GeneradorDeEventos {
private const val CANTIDAD = 7 // Numero de eventos generados
private const val CANTIDAD = 10 // Numero de eventos generados
private var eventos = ArrayList<Evento>()
private fun crearEvento(): Evento {
val factory = EventoFactorySelector.obtenerFactory()
return factory.generarEvento()
}
private val pesosBase = mutableMapOf(
TipoEvento.Reliquia to 0.25,
TipoEvento.Tienda to 0.1,
TipoEvento.Riesgo to 0.2,
TipoEvento.Trampa to 0.1,
TipoEvento.Combate to 0.25,
TipoEvento.Descanso to 0.0,
TipoEvento.Ladron to 0.1
)
private var historialTipos = mutableListOf<TipoEvento>()
fun generarEventos() {
val eventosGenerados = ArrayList<Evento>()
historialTipos = mutableListOf()
while (eventosGenerados.size < CANTIDAD) {
val nuevoEvento = crearEvento()
val tipoSeleccionado = seleccionarTipoEvento()
println(historialTipos)
if (historialTipos.isNotEmpty() && tipoSeleccionado == historialTipos.last()) {
continue
}
val nuevoEvento = EventoFactorySelector.obtenerFactory(tipoSeleccionado).generarEvento()
if (!eventosGenerados.contains(nuevoEvento)) {
eventosGenerados.add(nuevoEvento)
historialTipos.add(tipoSeleccionado)
}
}
eventos = eventosGenerados
}
private fun seleccionarTipoEvento(): TipoEvento {
val pesosActuales = pesosBase.toMutableMap()
// 20% Descanso tras dos riegsos en los últimos 3 eventos
val recientes = historialTipos.takeLast(3)
if (recientes.count { it == TipoEvento.Riesgo } >= 2) {
pesosActuales[TipoEvento.Tienda] = pesosActuales[TipoEvento.Tienda]!! + 0.2
// 25% Ladron si 2 reliquias
}else if(recientes.count{it == TipoEvento.Reliquia} >= 2){
pesosActuales[TipoEvento.Ladron] = 0.25
}
// 35% Prob de descanso tras combate 20% Tienda 10% Combate
val ultimoTipo = historialTipos.lastOrNull()
if (ultimoTipo == TipoEvento.Combate) {
pesosActuales[TipoEvento.Descanso] = 0.35
pesosActuales[TipoEvento.Tienda] = 0.2
pesosActuales[TipoEvento.Combate] = 0.1
}
val totalPesos = pesosActuales.values.sum()
val probabilidadesNormalizadas = pesosActuales.mapValues { it.value / totalPesos }
val acumulado = probabilidadesNormalizadas.entries.fold(mutableListOf<Pair<Double, TipoEvento>>()) { acc, entry ->
val sumaAcumulada = acc.lastOrNull()?.first ?: 0.0
acc.add(Pair(sumaAcumulada + entry.value, entry.key))
acc
}
val random = Random.nextDouble()
val tipoSeleccionado = acumulado.first { random <= it.first }.second
return tipoSeleccionado
}
fun comprobarEventoDisponible() : Boolean{
return eventos.size >= 1
}
......@@ -66,7 +121,7 @@ object GeneradorDeEventos {
private fun filtrarEventosPorDificultad(eventos: ArrayList<Evento>, dificultad: Int): Evento {
val eventosFiltrados = eventos.filter { it.dificultad == dificultad }
return eventosFiltrados[eventosFiltrados.indices.random()]
return eventosFiltrados[eventosFiltrados.indices.first]
}
......
package com.example.ellegadodepintia.exploradoresDePintia.model
import android.animation.ObjectAnimator
import android.graphics.drawable.AnimationDrawable
import android.os.Handler
import android.os.Looper
......@@ -10,6 +11,7 @@ import com.example.ellegadodepintia.R
import com.example.ellegadodepintia.exploradoresDePintia.model.GameState.context
import com.example.ellegadodepintia.exploradoresDePintia.model.efecto.Efecto
import com.example.ellegadodepintia.exploradoresDePintia.model.efecto.EfectoInvestigarEnemigo
import com.example.ellegadodepintia.exploradoresDePintia.model.efecto.EfectoRegeneracionEnemigo
import com.example.ellegadodepintia.exploradoresDePintia.model.eventoFactory.EventoCombate
import com.example.ellegadodepintia.exploradoresDePintia.model.habilidad.efectoHabilidad.EfectoHabilidad
......@@ -62,6 +64,24 @@ object GestorCombate {
}, ataqueDuracion.toLong())
}
fun cargarAnimacionsRegeneracionEnemigo() {
val imagenEvento = context!!.findViewById<ImageView>(R.id.imagenEvento)
val imagenEfecto = context!!.findViewById<ImageView>(R.id.imagenEfectoEvento)
imagenEvento?.let {
val salto = ObjectAnimator.ofFloat(it, "translationY", 0f, -40f, 0f)
salto.duration = 300
salto.start()
imagenEfecto?.setImageResource(R.drawable.effect_regeneracion_animation)
val efectoAnimacion = imagenEfecto?.drawable as? AnimationDrawable
efectoAnimacion?.start()
Handler(Looper.getMainLooper()).postDelayed({
imagenEfecto?.setImageDrawable(null)
}, 600)
}
}
fun calcularAtaque(ataqueBase: Int): Int {
val ataqueFinal: Int
val resultadoTirada = (0..100).random()
......@@ -81,9 +101,15 @@ object GestorCombate {
} else {
evento.actualizarFinalizado(true)
turnoJugador = true
"¡Enhorabuena has acabado con el monstruo!".also {
if(evento.resistenciaActual <= 0) {
GameState.jugador.conseguirObjeto(evento.recompensa)
Handler(Looper.getMainLooper()).postDelayed({
"¡Enhorabuena has acabado con el monstruo!\n Te das cuenta que defendía un/una ${evento.recompensa.nombre}".also {
context!!.findViewById<TextView>(R.id.textoResultado).text = it
}
}, 200)
}
}
}
......@@ -125,7 +151,7 @@ object GestorCombate {
private fun accionEnemigo() {
val textoResultado = context!!.findViewById<TextView>(R.id.textoResultado)
val efectoAtaque = evento.acciones.random().ejecutar()
val efectoAtaque = seleccionarAccionEnemigo().ejecutar()
if (GameState.jugador.atributos[Atributo.Vida]!! <= 0) {
Handler(Looper.getMainLooper()).postDelayed({
turnoJugador = true
......@@ -136,4 +162,15 @@ object GestorCombate {
}
}
private fun seleccionarAccionEnemigo(): Efecto {
val tieneRecuperacion = evento.acciones.any { it is EfectoRegeneracionEnemigo }
val porcentajeVida =
GameState.eventoActual.resistenciaActual / GameState.eventoActual.resistenciaMax.toDouble()
return if (tieneRecuperacion && porcentajeVida <= 0.3) {
evento.acciones.random()
} else {
evento.acciones.filterNot { it is EfectoRegeneracionEnemigo }.random()
}
}
}
\ No newline at end of file
......@@ -8,7 +8,7 @@ enum class TipoEvento {
Riesgo,
Descanso,
Ladron,
/*Trampa,
/*
Aliado,
Misterio,
Magia,
......
......@@ -15,7 +15,7 @@ class EfectoAtaqueProtagonista(probabilidadExito: Int) : Efecto(probabilidadExit
GameState.eventoActual.actualizarResistencia(-ataqueReal)
mensaje = "¡Ataque realizado con éxito has hecho $ataqueReal de daño"
} else {
mensaje = "El enemigo ha aguantado el golpe, recibe 0 de daño"
mensaje = "Has fallado el golpe, recibe 0 de daño"
}
return mensaje
}
......
package com.example.ellegadodepintia.exploradoresDePintia.model.efecto
import com.example.ellegadodepintia.exploradoresDePintia.model.GameState
import com.example.ellegadodepintia.exploradoresDePintia.model.GestorCombate
class EfectoRegeneracionEnemigo(private val mensajeCuracion: String,private val cantidad: Int) : Efecto(100) {
override fun ejecutar(): String {
GestorCombate.cargarAnimacionsRegeneracionEnemigo()
GameState.eventoActual.actualizarResistencia(cantidad)
return mensajeCuracion
}
}
\ No newline at end of file
......@@ -5,16 +5,28 @@ import com.example.ellegadodepintia.exploradoresDePintia.model.GameState
import com.example.ellegadodepintia.exploradoresDePintia.model.Atributo
import com.example.ellegadodepintia.exploradoresDePintia.model.Opcion
import com.example.ellegadodepintia.exploradoresDePintia.model.OpcionCombate
import com.example.ellegadodepintia.exploradoresDePintia.model.efecto.Efecto
import com.example.ellegadodepintia.exploradoresDePintia.model.efecto.EfectoAtaqueEnemigo
import com.example.ellegadodepintia.exploradoresDePintia.model.efecto.EfectoAtaqueProtagonista
import com.example.ellegadodepintia.exploradoresDePintia.model.efecto.EfectoHabilidadesProtagonista
import com.example.ellegadodepintia.exploradoresDePintia.model.efecto.EfectoHuirProtagonista
import com.example.ellegadodepintia.exploradoresDePintia.model.efecto.EfectoInvestigarEnemigo
import com.example.ellegadodepintia.exploradoresDePintia.model.efecto.EfectoRegeneracionEnemigo
import com.example.ellegadodepintia.exploradoresDePintia.model.objeto.Objeto
import com.example.ellegadodepintia.repositorios.RepositorioObjetos
data class CombateInfo(
val imagenIdle: Int,
val imagenAtaque: Int,
val opciones: List<Opcion>,
val habilidades: List<Efecto>,
val recompensa: Objeto
)
class CombateFactory : EventoFactory {
private val combatesMap = mapOf(
"El Metal Volador es una criatura formada por fragmentos de metal antiguo. Protege los secretos del yacimiento de Pintia." to Triple(
"El Metal Volador es una criatura formada por fragmentos de metal antiguo. Protege los secretos del yacimiento de Pintia." to CombateInfo(
R.drawable.monster_metal_idle_animation,
R.drawable.monster_metal_attack_animation,
listOf(
......@@ -26,7 +38,7 @@ class CombateFactory : EventoFactory {
Opcion(
descripcion = "Investigar",
atributoRequerida = Atributo.Investigacion,
EfectoInvestigarEnemigo(100)
efecto = EfectoInvestigarEnemigo(100)
),
Opcion(
descripcion = "Habilidades",
......@@ -38,7 +50,12 @@ class CombateFactory : EventoFactory {
atributoRequerida = Atributo.Vida,
efecto = EfectoHuirProtagonista(GameState.jugador.atributos[Atributo.Vida]!!),
),
)
),
listOf(
EfectoAtaqueEnemigo(80),
EfectoRegeneracionEnemigo("El metal reconfigura sus fragmentos recuperando parte de su vida", (1..2).random())
),
RepositorioObjetos.obtenerObjetoPorNombre("Moneda de plata Vaccea")!!
),
)
......@@ -48,30 +65,29 @@ class CombateFactory : EventoFactory {
override fun generarEvento(): EventoCombate {
val descripcion = generarDescripcion()
val combateInfo = combatesMap[descripcion] ?: throw IllegalArgumentException("No se encontró información de combate")
return EventoCombate(
descripcion = descripcion,
dificultad = 0,
opciones = generarOpciones(descripcion),
imagenAtaque = generarImagenAtaque(descripcion),
imagen = generarImagen(descripcion),
opciones = combateInfo.opciones.toMutableList(),
imagenAtaque = combateInfo.imagenAtaque,
imagen = combateInfo.imagenIdle,
resistenciaMax = (5..10).random(),
ataque = (1..2).random(),
finalizado = false,
acciones = mutableListOf(EfectoAtaqueEnemigo(70))
acciones = combateInfo.habilidades.toMutableList(),
recompensa = combateInfo.recompensa
)
}
override fun generarOpciones(descripcion: String): MutableList<Opcion> {
return combatesMap[descripcion]?.third?.take(4)?.toMutableList()
?: mutableListOf()
val combateInfo = combatesMap[descripcion] ?: return mutableListOf()
return combateInfo.opciones.take(4).toMutableList()
}
override fun generarImagen(descripcion: String): Int {
return combatesMap[descripcion]?.first!!
}
private fun generarImagenAtaque(descripcion: String): Int {
return combatesMap[descripcion]?.second!!
return combatesMap[descripcion]!!.imagenIdle
}
}
......@@ -7,9 +7,14 @@ import com.example.ellegadodepintia.exploradoresDePintia.model.efecto.EfectoIgno
import com.example.ellegadodepintia.exploradoresDePintia.model.efecto.EfectoNubeVaccea
class DescansoFactory : EventoFactory {
private val descansosMap = mapOf(
"Llegaste a un campamento vacceo, con un gran fuego en el centro y chozas hechas de madera y barro. Aquí puedes descansar, recuperar energía y estar listo para nuevas aventuras." to Pair(
R.drawable.asi_exploradores_campamento, listOf(
val descripcion = "Llegaste a un campamento vacceo, con un gran fuego en el centro y chozas hechas de madera y barro. Aquí puedes descansar, recuperar energía y estar listo para nuevas aventuras."
override fun generarDescripcion(): String {
return descripcion
}
override fun generarOpciones(descripcion: String): MutableList<Opcion> {
return mutableListOf(
Opcion(
descripcion = "Descansar",
atributoRequerida = Atributo.Energia,
......@@ -19,28 +24,16 @@ class DescansoFactory : EventoFactory {
descripcion = "Continuar",
atributoRequerida = Atributo.Nula,
EfectoIgnorar(100)
)
)
)
)
override fun generarDescripcion(): String {
return descansosMap.keys.random()
}
override fun generarOpciones(descripcion: String): MutableList<Opcion> {
return descansosMap[descripcion]?.second?.toMutableList()
?: mutableListOf()
))
}
override fun generarImagen(descripcion: String): Int {
return descansosMap[descripcion]?.first!!
return R.drawable.asi_exploradores_campamento
}
override fun generarEvento(): EventoDescanso {
val descripcion = generarDescripcion()
return EventoDescanso(
descripcion = descripcion,
descripcion = generarDescripcion(),
dificultad = 0,
opciones = generarOpciones(descripcion),
imagen = generarImagen(descripcion),
......
......@@ -25,6 +25,9 @@ abstract class Evento(
fun actualizarResistencia(valor : Int){
resistenciaActual += valor
if(resistenciaActual >= resistenciaMax){
resistenciaActual = resistenciaMax
}
notifyObservers()
}
......
......@@ -2,8 +2,11 @@ package com.example.ellegadodepintia.exploradoresDePintia.model.eventoFactory
import com.example.ellegadodepintia.exploradoresDePintia.model.Opcion
import com.example.ellegadodepintia.exploradoresDePintia.model.efecto.Efecto
import com.example.ellegadodepintia.exploradoresDePintia.model.objeto.Objeto
import java.util.UUID
class EventoCombate(
override val descripcion: String,
override val dificultad: Int,
override val opciones: MutableList<Opcion>,
......@@ -12,4 +15,18 @@ class EventoCombate(
var ataque: Int,
val imagenAtaque : Int,
val acciones: MutableList<Efecto>,
) : Evento(descripcion, dificultad, opciones, imagen, resistenciaMax, resistenciaMax, finalizado)
\ No newline at end of file
val recompensa : Objeto
) : Evento(descripcion, dificultad, opciones, imagen, resistenciaMax, resistenciaMax, finalizado){
val id: String = UUID.randomUUID().toString()
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || javaClass != other.javaClass) return false
other as EventoCombate
return id == other.id
}
override fun hashCode(): Int {
return 31 * id.hashCode()
}
}
\ No newline at end of file
package com.example.ellegadodepintia.exploradoresDePintia.model.eventoFactory
import com.example.ellegadodepintia.exploradoresDePintia.model.Opcion
import java.util.UUID
class EventoDescanso(
override val descripcion: String,
......@@ -8,4 +9,18 @@ class EventoDescanso(
override val opciones: MutableList<Opcion>,
override val imagen: Int, resistenciaMax: Int,
override var finalizado: Boolean,
) : Evento(descripcion, dificultad, opciones, imagen, resistenciaMax, resistenciaMax, finalizado)
\ No newline at end of file
) : Evento(descripcion, dificultad, opciones, imagen, resistenciaMax, resistenciaMax, finalizado) {
val id: String = UUID.randomUUID().toString()
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || javaClass != other.javaClass) return false
other as EventoDescanso
return id == other.id
}
override fun hashCode(): Int {
return 31 * id.hashCode()
}
}
\ No newline at end of file
......@@ -4,9 +4,7 @@ import com.example.ellegadodepintia.exploradoresDePintia.model.TipoEvento
object EventoFactorySelector {
fun obtenerFactory(): EventoFactory {
val tipo = seleccionarTipoEventoConProbabilidades()
fun obtenerFactory(tipo: TipoEvento): EventoFactory {
return when (tipo) {
TipoEvento.Reliquia -> ReliquiaFactory()
TipoEvento.Combate -> CombateFactory()
......@@ -17,25 +15,4 @@ object EventoFactorySelector {
TipoEvento.Ladron -> LadronFactory()
}
}
private fun seleccionarTipoEventoConProbabilidades(): TipoEvento {
val probabilidades = mapOf(
TipoEvento.Reliquia to 0.2,
TipoEvento.Tienda to 0.1,
TipoEvento.Riesgo to 0.2,
TipoEvento.Trampa to 0.1,
TipoEvento.Combate to 0.2,
TipoEvento.Descanso to 0.1,
TipoEvento.Ladron to 0.1
)
val acumulado = probabilidades.entries.fold(mutableListOf<Pair<Double, TipoEvento>>()) { acc, entry ->
val sumaAcumulada = acc.lastOrNull()?.first ?: 0.0
acc.add(Pair(sumaAcumulada + entry.value, entry.key))
acc
}
val random = Math.random()
return acumulado.first { random <= it.first }.second
}
}
......@@ -76,7 +76,7 @@ class RiesgoFactory : EventoFactory {
val evento = EventoRiesgo(
id = id,
descripcion = descripcionComun,
descripcion = generarDescripcion(),
dificultad = 0,
opciones = eventoData.opciones.toMutableList(),
imagen = eventoData.imagen,
......
......@@ -2,7 +2,7 @@ package com.example.ellegadodepintia.exploradoresDePintia.model.objeto
import com.example.ellegadodepintia.exploradoresDePintia.model.objeto.efectoObjeto.EfectoVender
class ObjetoDeValor(
open class ObjetoDeValor(
nombre: String,
descripcion: String,
imagen: Int,
......
......@@ -78,6 +78,12 @@ object RepositorioObjetos {
nombre = "Ticket",
descripcion = "Representa una invitación a un evento relacionado con la cultura vaccea, como una feria arqueológica o un festival cultural",
imagen = R.drawable.asi_objeto_ticket
),
ObjetoDeValor(
nombre= "Moneda de plata Vaccea",
descripcion = "Pequeño denario con símbolos celtíberos, utilizadas para el comercio. Su circulación refleja una economía organizada en torno a la élite guerrera",
imagen = R.drawable.asi_objeto_moneda,
coste = 15
)
).associateBy { it.nombre }
}
......
app/src/main/res/drawable-nodpi/asi_objeto_moneda.JPG

266 KiB

app/src/main/res/drawable/asi_objeto_tesoro.jpg

265 KiB

app/src/main/res/drawable/effect_regeneracion_00.png

292 B

app/src/main/res/drawable/effect_regeneracion_01.png

397 B

app/src/main/res/drawable/effect_regeneracion_010.png

933 B