Skip to content

Commit 4c78193

Browse files
committed
Merge branch 'feat/encounter-combatant' into 'master'
Přidání spojenců a oponentů do encounterů See merge request fmasa/pv239-project!84
2 parents 0c6d45b + d08d300 commit 4c78193

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1347
-83
lines changed

app/src/main/java/cz/muni/fi/rpg/di/container.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import cz.muni.fi.rpg.model.cache.CharacterRepositoryIdentityMap
1313
import cz.muni.fi.rpg.model.cache.PartyRepositoryIdentityMap
1414
import cz.muni.fi.rpg.model.domain.armour.Armor
1515
import cz.muni.fi.rpg.model.domain.character.*
16+
import cz.muni.fi.rpg.model.domain.encounter.CombatantRepository
1617
import cz.muni.fi.rpg.model.domain.encounter.EncounterRepository
1718
import cz.muni.fi.rpg.model.domain.encounters.EncounterId
1819
import cz.muni.fi.rpg.model.domain.inventory.InventoryItemRepository
@@ -34,6 +35,7 @@ import cz.muni.fi.rpg.ui.characterCreation.CharacterInfoFormFragment
3435
import cz.muni.fi.rpg.ui.characterCreation.CharacterStatsFormFragment
3536
import cz.muni.fi.rpg.ui.common.AdManager
3637
import cz.muni.fi.rpg.ui.gameMaster.GameMasterFragment
38+
import cz.muni.fi.rpg.ui.gameMaster.encounters.CombatantFragment
3739
import cz.muni.fi.rpg.ui.gameMaster.encounters.EncounterDetailFragment
3840
import cz.muni.fi.rpg.ui.gameMaster.encounters.EncountersFragment
3941
import cz.muni.fi.rpg.ui.partyList.PartyListFragment
@@ -91,6 +93,7 @@ val appModule = module {
9193
FirestoreCharacterFeatureRepository(Feature.ARMOR, get(), Armor(), aggregateMapper())
9294
}
9395
single<EncounterRepository> { FirestoreEncounterRepository(get(), aggregateMapper()) }
96+
single<CombatantRepository> { FirestoreCombatantRepository(get(), aggregateMapper()) }
9497

9598
single { AdManager(get()) }
9699

@@ -103,7 +106,7 @@ val appModule = module {
103106
viewModel { (characterId: CharacterId) -> CharacterViewModel(characterId, get(), get())}
104107
viewModel { (partyId: UUID) -> GameMasterViewModel(partyId, get(), get()) }
105108
viewModel { (partyId: UUID) -> EncountersViewModel(partyId, get()) }
106-
viewModel { (encounterId: EncounterId) -> EncounterDetailViewModel(encounterId, get(), get()) }
109+
viewModel { (encounterId: EncounterId) -> EncounterDetailViewModel(encounterId, get(), get(), get()) }
107110
viewModel { (characterId: CharacterId) -> InventoryViewModel(characterId, get(), get(), get()) }
108111
viewModel { (characterId: CharacterId) -> SkillsViewModel(characterId, get()) }
109112
viewModel { (characterId: CharacterId) -> SpellsViewModel(characterId, get()) }
@@ -130,4 +133,5 @@ val appModule = module {
130133
fragment { CharacterArmorFragment() }
131134
fragment { EncountersFragment() }
132135
fragment { EncounterDetailFragment() }
136+
fragment { CombatantFragment() }
133137
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package cz.muni.fi.rpg.model.domain.encounter
2+
3+
import cz.muni.fi.rpg.model.domain.armour.Armor
4+
import cz.muni.fi.rpg.model.domain.character.Stats
5+
import java.util.*
6+
7+
class Combatant(
8+
val id: UUID,
9+
name: String,
10+
note: String,
11+
wounds: Wounds,
12+
stats: Stats,
13+
armor: Armor,
14+
enemy: Boolean,
15+
alive: Boolean,
16+
traits: List<String>,
17+
trappings: List<String>,
18+
val position: Int
19+
) {
20+
21+
var name: String = name
22+
private set
23+
var note: String = note
24+
private set
25+
var wounds: Wounds = wounds
26+
private set
27+
var stats: Stats = stats
28+
private set
29+
var armor: Armor = armor
30+
private set
31+
var enemy: Boolean = enemy
32+
private set
33+
var alive: Boolean = alive
34+
private set
35+
var traits: List<String> = traits
36+
private set
37+
var trappings: List<String> = trappings
38+
private set
39+
40+
companion object {
41+
const val NAME_MAX_LENGTH = 100
42+
const val NOTE_MAX_LENGTH = 400
43+
}
44+
45+
init {
46+
validate(name, note)
47+
require(position >= 0)
48+
}
49+
50+
fun update(
51+
name: String,
52+
note: String,
53+
wounds: Wounds,
54+
stats: Stats,
55+
armor: Armor,
56+
enemy: Boolean,
57+
alive: Boolean,
58+
traits: List<String>,
59+
trappings: List<String>
60+
) {
61+
validate(name, note)
62+
63+
this.name = name
64+
this.note = note
65+
this.wounds = wounds
66+
this.stats = stats
67+
this.armor = armor
68+
this.enemy = enemy
69+
this.alive = alive
70+
this.traits = traits
71+
this.trappings = trappings
72+
}
73+
74+
private fun validate(name: String, note: String) {
75+
require(name.isNotBlank() && name.length <= NAME_MAX_LENGTH)
76+
require(note.length <= NOTE_MAX_LENGTH)
77+
}
78+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package cz.muni.fi.rpg.model.domain.encounter
2+
3+
import android.os.Parcelable
4+
import cz.muni.fi.rpg.model.domain.encounters.EncounterId
5+
import kotlinx.android.parcel.Parcelize
6+
import java.util.*
7+
8+
@Parcelize
9+
data class CombatantId(val encounterId: EncounterId, val combatantId: UUID) : Parcelable
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package cz.muni.fi.rpg.model.domain.encounter
2+
3+
import java.lang.Exception
4+
5+
class CombatantNotFound(combatantId: CombatantId, cause: Throwable?) :
6+
Exception("Combatant $combatantId was not found", cause)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package cz.muni.fi.rpg.model.domain.encounter
2+
3+
import androidx.lifecycle.LiveData
4+
import cz.muni.fi.rpg.model.domain.encounters.EncounterId
5+
6+
interface CombatantRepository {
7+
fun findByEncounter(encounterId: EncounterId): LiveData<List<Combatant>>
8+
9+
/**
10+
* @throws CombatantNotFound
11+
*/
12+
suspend fun get(id: CombatantId): Combatant
13+
14+
/**
15+
* Creates or updates given combatant
16+
*/
17+
suspend fun save(encounterId: EncounterId, vararg combatants: Combatant)
18+
19+
/**
20+
* Removes combatant if she exists or does nothing
21+
*/
22+
suspend fun remove(id: CombatantId)
23+
24+
/**
25+
* Returns value that can be used for new combatant so that it's sorted at the end
26+
*/
27+
suspend fun getNextPosition(encounterId: EncounterId): Int
28+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package cz.muni.fi.rpg.model.domain.encounter
2+
3+
data class Wounds(
4+
val current: Int,
5+
val max: Int
6+
) {
7+
companion object {
8+
fun fromMax(max: Int) = Wounds(max, max)
9+
}
10+
11+
init {
12+
require(current >= 0)
13+
require(max > 0)
14+
require(current <= max)
15+
}
16+
}

app/src/main/java/cz/muni/fi/rpg/model/firestore/constants.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const val COLLECTION_PARTIES = "parties"
44
const val COLLECTION_CHARACTERS = "characters"
55
const val COLLECTION_FEATURES = "features"
66
const val COLLECTION_ENCOUNTERS = "encounters"
7+
const val COLLECTION_COMBATANTS = "combatants"
78
const val COLLECTION_INVENTORY_ITEMS = "inventory"
89
const val COLLECTION_SKILLS = "skills"
910
const val COLLECTION_TALENTS = "talents"
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package cz.muni.fi.rpg.model.firestore.repositories
2+
3+
import androidx.lifecycle.LiveData
4+
import com.google.firebase.firestore.FirebaseFirestore
5+
import com.google.firebase.firestore.FirebaseFirestoreException
6+
import com.google.firebase.firestore.Query
7+
import com.google.firebase.firestore.SetOptions
8+
import cz.muni.fi.rpg.model.domain.encounter.*
9+
import cz.muni.fi.rpg.model.domain.encounters.EncounterId
10+
import cz.muni.fi.rpg.model.firestore.*
11+
import cz.muni.fi.rpg.model.firestore.AggregateMapper
12+
import cz.muni.fi.rpg.model.firestore.QueryLiveData
13+
import kotlinx.coroutines.tasks.await
14+
import java.util.*
15+
16+
internal class FirestoreCombatantRepository(
17+
private val firestore: FirebaseFirestore,
18+
private val mapper: AggregateMapper<Combatant>
19+
) : CombatantRepository {
20+
override fun findByEncounter(encounterId: EncounterId): LiveData<List<Combatant>> {
21+
return QueryLiveData(
22+
combatants(encounterId).orderBy("position", Query.Direction.ASCENDING),
23+
mapper
24+
)
25+
}
26+
27+
override suspend fun get(id: CombatantId): Combatant {
28+
try {
29+
return mapper.fromDocumentSnapshot(
30+
combatants(id.encounterId)
31+
.document(id.combatantId.toString())
32+
.get()
33+
.await()
34+
)
35+
} catch (e: FirebaseFirestoreException) {
36+
throw CombatantNotFound(id, e)
37+
}
38+
}
39+
40+
override suspend fun save(encounterId: EncounterId, vararg combatants: Combatant) {
41+
val collection = combatants(encounterId)
42+
43+
firestore.runTransaction { transaction ->
44+
combatants.forEach { combatant ->
45+
transaction.set(
46+
collection.document(combatant.id.toString()),
47+
mapper.toDocumentData(combatant),
48+
SetOptions.merge()
49+
)
50+
}
51+
}.await()
52+
}
53+
54+
override suspend fun remove(id: CombatantId) {
55+
combatants(id.encounterId).document(id.combatantId.toString()).delete().await()
56+
}
57+
58+
override suspend fun getNextPosition(encounterId: EncounterId): Int {
59+
val snapshot = combatants(encounterId)
60+
.orderBy("position", Query.Direction.DESCENDING)
61+
.get()
62+
.await()
63+
64+
val lastPosition = snapshot.documents.map(mapper::fromDocumentSnapshot)
65+
.getOrNull(0)?.position ?: -1
66+
67+
return lastPosition + 1
68+
}
69+
70+
private fun combatants(encounterId: EncounterId) =
71+
firestore.collection(COLLECTION_PARTIES)
72+
.document(encounterId.partyId.toString())
73+
.collection(COLLECTION_ENCOUNTERS)
74+
.document(encounterId.encounterId.toString())
75+
.collection(COLLECTION_COMBATANTS)
76+
}

app/src/main/java/cz/muni/fi/rpg/ui/character/CharacterMiscFragment.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ internal class CharacterMiscFragment : Fragment(R.layout.fragment_character_misc
8080

8181
view.xpPointsInput.setText(currentXpPoints.toString())
8282

83-
AlertDialog.Builder(requireContext())
83+
AlertDialog.Builder(requireContext(), R.style.FormDialog)
8484
.setTitle("Change amount of XP")
8585
.setView(view)
8686
.setPositiveButton(R.string.button_save) { _, _ ->

app/src/main/java/cz/muni/fi/rpg/ui/character/edit/CharacterEditFragment.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class CharacterEditFragment(
7272
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
7373
super.onCreateOptionsMenu(menu, inflater)
7474

75-
inflater.inflate(R.menu.character_edit_menu, menu)
75+
inflater.inflate(R.menu.form_fragment_menu, menu)
7676
}
7777

7878
override fun onOptionsItemSelected(item: MenuItem): Boolean {

0 commit comments

Comments
 (0)