Compare commits

..
Author SHA1 Message Date
Nacho fd76c46f39 Not much
- Imported card backgrounds (not necessary but future proofing just in case)
- Readded the sprite viewer just to verify everything is working as intended, will probably get rid of it again? or maybe I should keep it since it holds a copy of all the sprites in the card...
- TODO: Remove old unused tables
2025-09-14 02:39:52 +02:00
Nacho e85e1f45bf More name changes 2025-09-14 01:09:33 +02:00
Nacho 630cccefe4 Increased AGP version and changed some terminology 2025-09-14 00:49:17 +02:00
21 changed files with 214 additions and 216 deletions
+35 -66
View File
@@ -1,69 +1,38 @@
# VBHelper # VBHelper
Application to interact with the Vital series, VB, VH, VBC and VBBE. ## Developer Setup
## Current state of the project 1. Clone vb-nfc-reader (https://github.com/cfogrady/lib-vb-nfc)
2. Run vb-nfc-reader/publishToMavenLocal gradle task in the lib-vb-nfc project.
Right now the project is still under development, and until further notice, any database updates will result in having to erase application data. 3. Clone vb-dim-reader (https://github.com/cfogrady/vb-dim-reader)
4. Run publishToMavenLocal gradle task in the vb-dim-reader project.
This document will be updated once the application does not need any more database resets. 5. Create res/values/keys.xml within the app module.
6. Populate with:
## Features ```
<?xml version="1.0" encoding="utf-8"?>
As of now, the project allows you to read characters, view characters stats, and send them back to your watch. <resources>
<string name="password1">beHmacKey1</string>
You can also apply items to the characters read, such as special missions, or change timers, and store characters in the storage section. <string name="password2">beHmacKey2</string>
<string name="decryptionKey">aesKey</string>
You also earn new items every time an item such as a special mission (VB only) or a character completes an in-app adventure mission. <integer-array name="substitutionArray">
<item>0</item>
App also comes with a dex that will update every time a new character is added, and allows you to see evolution requirements and current adventure stage in the watch. <item>1</item>
<item>2</item>
## How to set up <item>3</item>
<item>4</item>
1. Download the latest version for VB Arena APK from a trustworthy source. If your download is a standalone APK, continue to step 2. Otherwise, if your download is an XAPK, do the following: <item>5</item>
<item>6</item>
1. Using your phone file manager, rename the XAPK file to ZIP, and extract its contents. You can also do this with any other device, such as Windows, macOS and Linux. <item>7</item>
<item>8</item>
2. Once the files are extracted, look for an APK called `com.bandai.vitalbraceletarena.apk`. Copy it somewhere else, you will need it. <item>9</item>
<item>10</item>
2. Install an APK release for VB Arena. You will find the releases [here](http://github.com/nacabaro/vbhelper/releases). Download the latest release and install its APK. <item>11</item>
<item>12</item>
Note, in the current stage of the project, you will have to delete the old application from your device. If the app keeps crashing after installing, clear application data and storage. <item>13</item>
<item>14</item>
3. Import secrets in the app. These secrets will allow the app to talk to the watch. On the main screen, click on the gear icon, then `Import secrets`. <item>15</item>
</integer-array>
You will be prompted to choose a file. Choose the APK file that was previously obtained. </resources>
```
4. Import cards. Due to copyright laws, we cannot offer the characters and sprites themselves in the application. In order to import the cards do the following. 7. Replace the values in the keys.xml file with those extracted from the original app.
8. Run
1. Using your own DiM/BEm cards, dump the cards to your device. You can get an in-depth tutorial in [here](http://mrblinky.net/digimon/vb/dimcardtool/dimcardtool.html). You can download the dump tool from [here](http://mrblinky.net/digimon/vb/dimcardtool/)
2. Once installed the tool and drivers, open the tool, connect your DiM/BEm reader hardware to yout computer and click on Read card.
3. Transfer the resulting file to your mobile device. You can put them anywhere, as long as they are accessible. My recommendation is to put them under a folder called `Cards` in your `Internal storage` or `SD Card`
4. In the app, click on import card. Next choose the BIN file corresponding to the card you want to import.
**Note: if you do not import the card, whenever you attempt to read a character from th watch, the character you read will get deleted.**
5. App will now be ready to be used.
## Planned features
- Online battles, undegoing development by `lightheel`.
- VitalWear compatibility, undergoing development by `cfogrady`.
- Support for multiple languages, not yet started.
- Database backup/restore.
## Credits
- `cyanic` for helping us understand more about the VB connection protocol.
- `cfogrady` for making both [`VB-DIM-Reader`](https://github.com/cfogrady/VB-DIM-Reader) and [`lib-vb-nfc`](https://github.com/cfogrady/lib-vb-nfc)
- `lightheel` for working on the online component in the application, both server and battle client.
- `shvstrz` for the app icon.
@@ -0,0 +1,24 @@
package com.github.nacabaro.vbhelper.daos
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import com.github.nacabaro.vbhelper.domain.card.CardBackground
@Dao
interface CardBackgroundDao {
@Insert
suspend fun insertCardBackground(vararg cardBackground: CardBackground)
@Query("""
SELECT * FROM CardBackground
WHERE cardId = :cardId
""")
suspend fun getCardBackground(cardId: Long): CardBackground
@Query("""
SELECT * FROM CardBackground
""")
suspend fun getBackgrounds(): List<CardBackground>
}
@@ -5,6 +5,7 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy import androidx.room.OnConflictStrategy
import androidx.room.Query import androidx.room.Query
import com.github.nacabaro.vbhelper.domain.card.Card import com.github.nacabaro.vbhelper.domain.card.Card
import com.github.nacabaro.vbhelper.domain.card.CardSprites
@Dao @Dao
interface CardDao { interface CardDao {
@@ -33,4 +34,11 @@ interface CardDao {
@Query("DELETE FROM Card WHERE id = :id") @Query("DELETE FROM Card WHERE id = :id")
suspend fun deleteCard(id: Long) suspend fun deleteCard(id: Long)
@Insert
suspend fun insertSprites(vararg sprites: CardSprites)
@Query("SELECT * FROM CardSprites")
suspend fun getSprites(): List<CardSprites>
} }
@@ -5,28 +5,30 @@ import androidx.room.Query
@Dao @Dao
interface CardFusionsDao { interface CardFusionsDao {
@Query(""" @Query(
"""
INSERT INTO INSERT INTO
CardFusions ( CardFusions (
fromCharaId, fromCharaId,
attribute1Fusion, toVirusFusion,
attribute2Fusion, toDataFusion,
attribute3Fusion, toVaccineFusion,
attribute4Fusion toFreeFusion
) )
SELECT SELECT
(SELECT id FROM CardCharacter WHERE cardId = :cardId AND charaIndex = :fromCharaId), (SELECT id FROM CardCharacter WHERE cardId = :cardId AND charaIndex = :fromCharaId),
(SELECT id FROM CardCharacter WHERE cardId = :cardId AND charaIndex = :toCharaIdAttr1), (SELECT id FROM CardCharacter WHERE cardId = :cardId AND charaIndex = :toCharaIdVirus),
(SELECT id FROM CardCharacter WHERE cardId = :cardId AND charaIndex = :toCharaIdAttr2), (SELECT id FROM CardCharacter WHERE cardId = :cardId AND charaIndex = :toCharaIdData),
(SELECT id FROM CardCharacter WHERE cardId = :cardId AND charaIndex = :toCharaIdAttr3), (SELECT id FROM CardCharacter WHERE cardId = :cardId AND charaIndex = :toCharaIdVaccine),
(SELECT id FROM CardCharacter WHERE cardId = :cardId AND charaIndex = :toCharaIdAttr4) (SELECT id FROM CardCharacter WHERE cardId = :cardId AND charaIndex = :toCharaIdFree)
""") """
)
suspend fun insertNewFusion( suspend fun insertNewFusion(
cardId: Long, cardId: Long,
fromCharaId: Int, fromCharaId: Int,
toCharaIdAttr1: Int, toCharaIdVirus: Int,
toCharaIdAttr2: Int, toCharaIdData: Int,
toCharaIdAttr3: Int, toCharaIdVaccine: Int,
toCharaIdAttr4: Int toCharaIdFree: Int
) )
} }
@@ -1,28 +1,17 @@
package com.github.nacabaro.vbhelper.daos package com.github.nacabaro.vbhelper.daos
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query import androidx.room.Query
import androidx.room.Upsert
import com.github.nacabaro.vbhelper.domain.card.CardProgress import com.github.nacabaro.vbhelper.domain.card.CardProgress
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
@Dao @Dao
interface CardProgressDao { interface CardProgressDao {
@Query(""" @Upsert
UPDATE CardProgress fun updateDimProgress(vararg cardProgresses: CardProgress)
SET
currentStage = :currentStage,
unlocked = :unlocked
WHERE cardId = :cardId AND
currentStage < :currentStage
""")
fun updateCardProgress(currentStage: Int, cardId: Long, unlocked: Boolean)
@Query( @Query(
"SELECT currentStage FROM CardProgress WHERE cardId = :cardId" "SELECT currentStage FROM CardProgress WHERE cardId = :cardId"
) )
fun getCardProgress(cardId: Long): Int fun getCardProgress(cardId: Long): Int
@Insert
fun insertCardProgress(cardProgress: CardProgress)
} }
@@ -24,12 +24,10 @@ interface CharacterDao {
d.cardId as cardId, d.cardId as cardId,
c.charaIndex as charId, c.charaIndex as charId,
c.stage as stage, c.stage as stage,
c.attribute as attribute, c.attribute as attribute
cp.currentStage as currentStage
FROM CardCharacter c FROM CardCharacter c
JOIN UserCharacter uc ON c.id = uc.charId JOIN UserCharacter uc ON c.id = uc.charId
JOIN Card d ON c.cardId = d.id JOIN Card d ON c.cardId = d.id
JOIN CardProgress cp ON d.id = cp.cardId
WHERE c.id = :charId WHERE c.id = :charId
""" """
) )
@@ -37,7 +35,7 @@ interface CharacterDao {
@Query( @Query(
""" """
INSERT INTO PossibleTransformations (charaId, requiredVitals, requiredTrophies, requiredBattles, requiredWinRate, changeTimerHours, requiredAdventureLevelCompleted, toCharaId) INSERT INTO CardTransformations (charaId, requiredVitals, requiredTrophies, requiredBattles, requiredWinRate, changeTimerHours, requiredAdventureLevelCompleted, toCharaId)
SELECT SELECT
(SELECT id FROM CardCharacter WHERE charaIndex = :fromChraraIndex AND cardId = :cardId), (SELECT id FROM CardCharacter WHERE charaIndex = :fromChraraIndex AND cardId = :cardId),
:requiredVitals, :requiredVitals,
@@ -77,7 +75,7 @@ interface CharacterDao {
pt.changeTimerHours as changeTimerHours, pt.changeTimerHours as changeTimerHours,
pt.requiredAdventureLevelCompleted as requiredAdventureLevelCompleted pt.requiredAdventureLevelCompleted as requiredAdventureLevelCompleted
FROM FROM
PossibleTransformations pt CardTransformations pt
JOIN CardCharacter c on pt.toCharaId = c.id JOIN CardCharacter c on pt.toCharaId = c.id
JOIN Sprite s ON s.id = c.spriteId JOIN Sprite s ON s.id = c.spriteId
LEFT JOIN Dex d ON d.id = pt.toCharaId LEFT JOIN Dex d ON d.id = pt.toCharaId
@@ -4,6 +4,7 @@ import androidx.room.Database
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import com.github.nacabaro.vbhelper.daos.AdventureDao import com.github.nacabaro.vbhelper.daos.AdventureDao
import com.github.nacabaro.vbhelper.daos.CardAdventureDao import com.github.nacabaro.vbhelper.daos.CardAdventureDao
import com.github.nacabaro.vbhelper.daos.CardBackgroundDao
import com.github.nacabaro.vbhelper.daos.CharacterDao import com.github.nacabaro.vbhelper.daos.CharacterDao
import com.github.nacabaro.vbhelper.daos.DexDao import com.github.nacabaro.vbhelper.daos.DexDao
import com.github.nacabaro.vbhelper.daos.CardDao import com.github.nacabaro.vbhelper.daos.CardDao
@@ -13,13 +14,14 @@ import com.github.nacabaro.vbhelper.daos.ItemDao
import com.github.nacabaro.vbhelper.daos.SpecialMissionDao import com.github.nacabaro.vbhelper.daos.SpecialMissionDao
import com.github.nacabaro.vbhelper.daos.SpriteDao import com.github.nacabaro.vbhelper.daos.SpriteDao
import com.github.nacabaro.vbhelper.daos.UserCharacterDao import com.github.nacabaro.vbhelper.daos.UserCharacterDao
import com.github.nacabaro.vbhelper.domain.card.Background import com.github.nacabaro.vbhelper.domain.card.CardBackground
import com.github.nacabaro.vbhelper.domain.card.CardCharacter import com.github.nacabaro.vbhelper.domain.card.CardCharacter
import com.github.nacabaro.vbhelper.domain.card.Card import com.github.nacabaro.vbhelper.domain.card.Card
import com.github.nacabaro.vbhelper.domain.card.CardAdventure import com.github.nacabaro.vbhelper.domain.card.CardAdventure
import com.github.nacabaro.vbhelper.domain.card.CardFusions import com.github.nacabaro.vbhelper.domain.card.CardFusions
import com.github.nacabaro.vbhelper.domain.card.CardProgress import com.github.nacabaro.vbhelper.domain.card.CardProgress
import com.github.nacabaro.vbhelper.domain.card.PossibleTransformations import com.github.nacabaro.vbhelper.domain.card.CardSprites
import com.github.nacabaro.vbhelper.domain.card.CardTransformations
import com.github.nacabaro.vbhelper.domain.characters.Sprite import com.github.nacabaro.vbhelper.domain.characters.Sprite
import com.github.nacabaro.vbhelper.domain.characters.Adventure import com.github.nacabaro.vbhelper.domain.characters.Adventure
import com.github.nacabaro.vbhelper.domain.characters.Dex import com.github.nacabaro.vbhelper.domain.characters.Dex
@@ -39,6 +41,7 @@ import com.github.nacabaro.vbhelper.domain.items.Items
CardCharacter::class, CardCharacter::class,
CardAdventure::class, CardAdventure::class,
CardFusions::class, CardFusions::class,
CardSprites::class,
Sprite::class, Sprite::class,
UserCharacter::class, UserCharacter::class,
BECharacterData::class, BECharacterData::class,
@@ -49,8 +52,8 @@ import com.github.nacabaro.vbhelper.domain.items.Items
Dex::class, Dex::class,
Items::class, Items::class,
Adventure::class, Adventure::class,
Background::class, CardBackground::class,
PossibleTransformations::class CardTransformations::class
] ]
) )
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
@@ -65,4 +68,5 @@ abstract class AppDatabase : RoomDatabase() {
abstract fun specialMissionDao(): SpecialMissionDao abstract fun specialMissionDao(): SpecialMissionDao
abstract fun cardAdventureDao(): CardAdventureDao abstract fun cardAdventureDao(): CardAdventureDao
abstract fun cardFusionsDao(): CardFusionsDao abstract fun cardFusionsDao(): CardFusionsDao
abstract fun cardBackgroundDao(): CardBackgroundDao
} }
@@ -1,30 +0,0 @@
package com.github.nacabaro.vbhelper.domain
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
@Entity(
foreignKeys = [
ForeignKey(
entity = Character::class,
parentColumns = ["id"],
childColumns = ["monId"],
onDelete = ForeignKey.CASCADE
),
ForeignKey(
entity = Character::class,
parentColumns = ["id"],
childColumns = ["nextMon"],
onDelete = ForeignKey.CASCADE
)
]
)
data class Evolutions(
@PrimaryKey val monId: Int,
@PrimaryKey val nextMon: Int,
val trophies: Int,
val vitals: Int,
val totalBattles: Int,
val winRate: Int // Does not need to be a floating point
)
@@ -14,8 +14,8 @@ import androidx.room.PrimaryKey
) )
] ]
) )
data class Background ( data class CardBackground (
@PrimaryKey(autoGenerate = true) val id: Long, @PrimaryKey(autoGenerate = true) val id: Long = 0,
val cardId: Long, val cardId: Long,
val background: ByteArray, val background: ByteArray,
val backgroundWidth: Int, val backgroundWidth: Int,
@@ -15,25 +15,25 @@ import androidx.room.PrimaryKey
ForeignKey( ForeignKey(
entity = CardCharacter::class, entity = CardCharacter::class,
parentColumns = ["id"], parentColumns = ["id"],
childColumns = ["attribute1Fusion"], childColumns = ["toVirusFusion"],
onDelete = ForeignKey.CASCADE onDelete = ForeignKey.CASCADE
), ),
ForeignKey( ForeignKey(
entity = CardCharacter::class, entity = CardCharacter::class,
parentColumns = ["id"], parentColumns = ["id"],
childColumns = ["attribute2Fusion"], childColumns = ["toDataFusion"],
onDelete = ForeignKey.CASCADE onDelete = ForeignKey.CASCADE
), ),
ForeignKey( ForeignKey(
entity = CardCharacter::class, entity = CardCharacter::class,
parentColumns = ["id"], parentColumns = ["id"],
childColumns = ["attribute3Fusion"], childColumns = ["toVaccineFusion"],
onDelete = ForeignKey.CASCADE onDelete = ForeignKey.CASCADE
), ),
ForeignKey( ForeignKey(
entity = CardCharacter::class, entity = CardCharacter::class,
parentColumns = ["id"], parentColumns = ["id"],
childColumns = ["attribute4Fusion"], childColumns = ["toFreeFusion"],
onDelete = ForeignKey.CASCADE onDelete = ForeignKey.CASCADE
) )
] ]
@@ -41,8 +41,8 @@ import androidx.room.PrimaryKey
data class CardFusions( data class CardFusions(
@PrimaryKey(autoGenerate = true) val id: Long, @PrimaryKey(autoGenerate = true) val id: Long,
val fromCharaId: Long, val fromCharaId: Long,
val attribute1Fusion: Long?, val toVirusFusion: Long?,
val attribute2Fusion: Long?, val toDataFusion: Long?,
val attribute3Fusion: Long?, val toVaccineFusion: Long?,
val attribute4Fusion: Long? val toFreeFusion: Long?
) )
@@ -0,0 +1,12 @@
package com.github.nacabaro.vbhelper.domain.card
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
data class CardSprites(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
val sprite: ByteArray,
val width: Int,
val height: Int
)
@@ -20,7 +20,7 @@ import androidx.room.PrimaryKey
) )
] ]
) )
data class PossibleTransformations ( data class CardTransformations (
@PrimaryKey(autoGenerate = true) val id: Long = 0, @PrimaryKey(autoGenerate = true) val id: Long = 0,
var charaId: Long, var charaId: Long,
val requiredVitals: Int, val requiredVitals: Int,
@@ -38,8 +38,7 @@ object CharacterDtos {
val cardId: Long, val cardId: Long,
val charId: Int, val charId: Int,
val stage: Int, val stage: Int,
val attribute: NfcCharacter.Attribute, val attribute: NfcCharacter.Attribute
val currentStage: Int
) )
data class TransformationHistory( data class TransformationHistory(
@@ -7,11 +7,8 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.navigation.NavController import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.components.TopBanner import com.github.nacabaro.vbhelper.components.TopBanner
@@ -26,7 +23,7 @@ fun CardAdventureScreen(
cardId: Long cardId: Long
) { ) {
val cardAdventureMissions = remember { mutableStateOf(emptyList<CardDtos.CardAdventureWithSprites>()) } val cardAdventureMissions = remember { mutableStateOf(emptyList<CardDtos.CardAdventureWithSprites>()) }
var currentCardAdventure by remember { mutableIntStateOf(0) } var currentCardAdventure = remember { 0 }
LaunchedEffect(cardId) { LaunchedEffect(cardId) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
@@ -58,7 +55,7 @@ fun CardAdventureScreen(
cardAdventureMissions.value.mapIndexed { index, it -> cardAdventureMissions.value.mapIndexed { index, it ->
CardAdventureEntry( CardAdventureEntry(
cardAdventureEntry = it, cardAdventureEntry = it,
obscure = index > currentCardAdventure - 1 obscure = index > currentCardAdventure
) )
} }
} }
@@ -152,13 +152,15 @@ class FromNfcConverter (
nfcCharacter: NfcCharacter, nfcCharacter: NfcCharacter,
cardData: Card cardData: Card
) { ) {
val currentCardProgress = CardProgress(
cardId = cardData.id,
currentStage = nfcCharacter.nextAdventureMissionStage.toInt(),
unlocked = nfcCharacter.nextAdventureMissionStage.toInt() > cardData.stageCount
)
database database
.cardProgressDao() .cardProgressDao()
.updateCardProgress( .updateDimProgress(currentCardProgress)
currentStage = nfcCharacter.nextAdventureMissionStage.toInt(),
cardId = cardData.id,
unlocked = nfcCharacter.nextAdventureMissionStage.toInt() > cardData.stageCount,
)
} }
@@ -38,10 +38,14 @@ class ToNfcConverter(
.characterDao() .characterDao()
.getCharacterInfo(userCharacter.charId) .getCharacterInfo(userCharacter.charId)
val currentCardStage = database
.cardProgressDao()
.getCardProgress(characterInfo.cardId)
return if (userCharacter.characterType == DeviceType.BEDevice) return if (userCharacter.characterType == DeviceType.BEDevice)
nfcToBENfc(characterId, characterInfo, userCharacter) nfcToBENfc(characterId, characterInfo, currentCardStage, userCharacter)
else else
nfcToVBNfc(characterId, characterInfo, userCharacter) nfcToVBNfc(characterId, characterInfo, currentCardStage, userCharacter)
} }
@@ -49,6 +53,7 @@ class ToNfcConverter(
private suspend fun nfcToVBNfc( private suspend fun nfcToVBNfc(
characterId: Long, characterId: Long,
characterInfo: CharacterDtos.CardCharacterInfo, characterInfo: CharacterDtos.CardCharacterInfo,
currentCardStage: Int,
userCharacter: UserCharacter userCharacter: UserCharacter
): VBNfcCharacter { ): VBNfcCharacter {
val vbData = database val vbData = database
@@ -65,7 +70,7 @@ class ToNfcConverter(
stage = characterInfo.stage.toByte(), stage = characterInfo.stage.toByte(),
attribute = characterInfo.attribute, attribute = characterInfo.attribute,
ageInDays = userCharacter.ageInDays.toByte(), ageInDays = userCharacter.ageInDays.toByte(),
nextAdventureMissionStage = characterInfo.currentStage.toByte(), nextAdventureMissionStage = currentCardStage.toByte(),
mood = userCharacter.mood.toByte(), mood = userCharacter.mood.toByte(),
vitalPoints = userCharacter.vitalPoints.toUShort(), vitalPoints = userCharacter.vitalPoints.toUShort(),
transformationCountdownInMinutes = userCharacter.transformationCountdown.toUShort(), transformationCountdownInMinutes = userCharacter.transformationCountdown.toUShort(),
@@ -168,6 +173,7 @@ class ToNfcConverter(
private suspend fun nfcToBENfc( private suspend fun nfcToBENfc(
characterId: Long, characterId: Long,
characterInfo: CharacterDtos.CardCharacterInfo, characterInfo: CharacterDtos.CardCharacterInfo,
currentCardStage: Int,
userCharacter: UserCharacter userCharacter: UserCharacter
): BENfcCharacter { ): BENfcCharacter {
val beData = database val beData = database
@@ -182,7 +188,7 @@ class ToNfcConverter(
stage = characterInfo.stage.toByte(), stage = characterInfo.stage.toByte(),
attribute = characterInfo.attribute, attribute = characterInfo.attribute,
ageInDays = userCharacter.ageInDays.toByte(), ageInDays = userCharacter.ageInDays.toByte(),
nextAdventureMissionStage = characterInfo.currentStage.toByte(), nextAdventureMissionStage = currentCardStage.toByte(),
mood = userCharacter.mood.toByte(), mood = userCharacter.mood.toByte(),
vitalPoints = userCharacter.vitalPoints.toUShort(), vitalPoints = userCharacter.vitalPoints.toUShort(),
itemEffectMentalStateValue = beData.itemEffectMentalStateValue.toByte(), itemEffectMentalStateValue = beData.itemEffectMentalStateValue.toByte(),
@@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.navigation.NavController import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.components.TopBanner import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.navigation.NavigationItems
@Composable @Composable
fun CreditsScreen( fun CreditsScreen(
@@ -19,6 +20,9 @@ fun CreditsScreen(
text = "Credits", text = "Credits",
onBackClick = { onBackClick = {
navController.popBackStack() navController.popBackStack()
},
onGearClick = {
navController.navigate(NavigationItems.Viewer.route)
} }
) )
}, },
@@ -17,8 +17,10 @@ import com.github.nacabaro.vbhelper.database.AppDatabase
import com.github.nacabaro.vbhelper.di.VBHelper import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.domain.characters.Sprite import com.github.nacabaro.vbhelper.domain.characters.Sprite
import com.github.nacabaro.vbhelper.domain.card.Card import com.github.nacabaro.vbhelper.domain.card.Card
import com.github.nacabaro.vbhelper.domain.card.CardBackground
import com.github.nacabaro.vbhelper.domain.card.CardProgress import com.github.nacabaro.vbhelper.domain.card.CardProgress
import com.github.nacabaro.vbhelper.domain.card.CardCharacter import com.github.nacabaro.vbhelper.domain.card.CardCharacter
import com.github.nacabaro.vbhelper.domain.card.CardSprites
import com.github.nacabaro.vbhelper.source.ApkSecretsImporter import com.github.nacabaro.vbhelper.source.ApkSecretsImporter
import com.github.nacabaro.vbhelper.source.SecretsImporter import com.github.nacabaro.vbhelper.source.SecretsImporter
import com.github.nacabaro.vbhelper.source.SecretsRepository import com.github.nacabaro.vbhelper.source.SecretsRepository
@@ -215,7 +217,7 @@ class SettingsScreenControllerImpl(
spriteHappy = card.spriteData.sprites[spriteCounter + 4].pixelData, spriteHappy = card.spriteData.sprites[spriteCounter + 4].pixelData,
spriteSleep = card.spriteData.sprites[spriteCounter + 5].pixelData, spriteSleep = card.spriteData.sprites[spriteCounter + 5].pixelData,
spriteAttack = card.spriteData.sprites[spriteCounter + 2].pixelData, spriteAttack = card.spriteData.sprites[spriteCounter + 2].pixelData,
spriteDodge = card.spriteData.sprites[spriteCounter + 3].pixelData spriteDodge = card.spriteData.sprites[spriteCounter + 3].pixelData,
) )
} else { } else {
domainSprite = Sprite( domainSprite = Sprite(
@@ -324,10 +326,10 @@ class SettingsScreenControllerImpl(
.insertNewFusion( .insertNewFusion(
cardId = cardId, cardId = cardId,
fromCharaId = it.characterIndex, fromCharaId = it.characterIndex,
toCharaIdAttr1 = it.attribute1Fusion, toCharaIdVirus = it.attribute1Fusion,
toCharaIdAttr2 = it.attribute2Fusion, toCharaIdData = it.attribute2Fusion,
toCharaIdAttr3 = it.attribute3Fusion, toCharaIdVaccine = it.attribute3Fusion,
toCharaIdAttr4 = it.attribute4Fusion toCharaIdFree = it.attribute4Fusion
) )
} }
} }
@@ -336,15 +338,49 @@ class SettingsScreenControllerImpl(
private fun updateCardProgress( private fun updateCardProgress(
cardId: Long, cardId: Long,
) { ) {
val cardProgress = CardProgress(
cardId = cardId,
currentStage = 0,
unlocked = false
)
database database
.cardProgressDao() .cardProgressDao()
.insertCardProgress( .updateDimProgress(cardProgress)
CardProgress( }
private suspend fun importBackgrounds(
cardId: Long,
card: com.github.cfogrady.vb.dim.card.Card<*, *, *, *, *, *>
) {
val backgrounds = mutableListOf<CardBackground>()
if (card is DimCard) {
backgrounds.add(
CardBackground(
cardId = cardId, cardId = cardId,
currentStage = 1, background = card.spriteData.sprites[1].pixelData,
unlocked = false backgroundWidth = card.spriteData.sprites[1].width,
backgroundHeight = card.spriteData.sprites[1].height
) )
) )
} else if (card is BemCard) {
val possibleBackgroundsIds = listOf(1, 10, 30, 31, 32, 33)
for (id in possibleBackgroundsIds) {
backgrounds.add(
CardBackground(
cardId = cardId,
background = card.spriteData.sprites[id].pixelData,
backgroundWidth = card.spriteData.sprites[id].width,
backgroundHeight = card.spriteData.sprites[id].height
)
)
}
}
database
.cardBackgroundDao()
.insertCardBackground(*backgrounds.toTypedArray())
} }
private fun importCard(uri: Uri) { private fun importCard(uri: Uri) {
@@ -379,6 +415,20 @@ class SettingsScreenControllerImpl(
importAdventureMissions(cardId, card) importAdventureMissions(cardId, card)
importCardFusions(cardId, card) importCardFusions(cardId, card)
importBackgrounds(cardId, card)
val cardSprites: List<CardSprites> = card.spriteData.sprites.map {
CardSprites(
sprite = it.pixelData,
width = it.width,
height = it.height
)
}
database
.cardDao()
.insertSprites(*cardSprites.toTypedArray())
} }
inputStream?.close() inputStream?.close()
@@ -1,9 +1,9 @@
package com.github.nacabaro.vbhelper.screens.spriteViewer package com.github.nacabaro.vbhelper.screens.spriteViewer
import android.graphics.Bitmap import android.graphics.Bitmap
import com.github.nacabaro.vbhelper.domain.characters.Sprite import com.github.nacabaro.vbhelper.domain.card.CardBackground
interface SpriteViewerController { interface SpriteViewerController {
suspend fun getAllSprites(): List<Sprite> suspend fun getAllSprites(): List<CardBackground>
fun convertToBitmap(sprites: List<Sprite>): List<Bitmap> fun convertToBitmap(sprites: List<CardBackground>): List<Bitmap>
} }
@@ -1,65 +1,29 @@
package com.github.nacabaro.vbhelper.screens.spriteViewer package com.github.nacabaro.vbhelper.screens.spriteViewer
import android.graphics.Bitmap import android.graphics.Bitmap
import android.util.Log
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.asImageBitmap
import com.github.nacabaro.vbhelper.di.VBHelper import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.domain.characters.Sprite
import java.nio.ByteBuffer import java.nio.ByteBuffer
import androidx.core.graphics.createBitmap
import com.github.nacabaro.vbhelper.domain.card.CardBackground
class SpriteViewerControllerImpl( class SpriteViewerControllerImpl(
private val context: ComponentActivity private val context: ComponentActivity
) : SpriteViewerController { ) : SpriteViewerController {
override suspend fun getAllSprites(): List<Sprite> { override suspend fun getAllSprites(): List<CardBackground> {
val applicationContext = context.applicationContext as VBHelper val applicationContext = context.applicationContext as VBHelper
val db = applicationContext.container.db val db = applicationContext.container.db
val sprites = db.spriteDao().getAllSprites() val sprites = db.cardBackgroundDao().getBackgrounds()
return sprites return sprites
} }
// I don't like this, chief // I don't like this, chief
override fun convertToBitmap(sprites: List<Sprite>): List<Bitmap> { override fun convertToBitmap(sprites: List<CardBackground>): List<Bitmap> {
val bitmapList = mutableListOf<Bitmap>() val bitmapList = mutableListOf<Bitmap>()
for (sprite in sprites) { for (sprite in sprites) {
Log.d("SpriteViewer", "sprite: $sprite") bitmapList.add(createBitmap(sprite.backgroundWidth, sprite.backgroundHeight, Bitmap.Config.RGB_565).apply {
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply { copyPixelsFromBuffer(ByteBuffer.wrap(sprite.background))
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteIdle1))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteIdle2))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteWalk1))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteWalk2))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteRun1))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteRun2))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteTrain1))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteTrain2))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteHappy))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteSleep))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteAttack))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteDodge))
}) })
} }
+1 -1
View File
@@ -1,5 +1,5 @@
[versions] [versions]
agp = "8.12.2" agp = "8.12.3"
datastore = "1.1.2" datastore = "1.1.2"
kotlin = "2.0.0" kotlin = "2.0.0"
coreKtx = "1.15.0" coreKtx = "1.15.0"