diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml index b44213f..d634db1 100644 --- a/composeApp/src/commonMain/composeResources/values/strings.xml +++ b/composeApp/src/commonMain/composeResources/values/strings.xml @@ -184,8 +184,9 @@ Supprimer la feuille de personnage Êtes-vous sûr de vouloir supprimer "%1$s" ? - Ajouter un objet Filtrer l'inventaire + Ajouter un objet + Utiliser Ajouter à la bourse Retirer de la bourse Filtrer les objets @@ -193,6 +194,9 @@ Ajouter à l'inventaire Quantité Modifier + Jetter + Equiper + Utiliser Cet objet n'a pas de description. Les caractéristiques constituent les aptitudes innées d’un personnage comme son intelligence, sa force, son charisme, etc. Elles ne sont pas acquises, mais peuvent être parfois augmentées par un entraînement ou une utilisation réussie. Les caractéristiques des humains normaux varient de 2 (niveau extrêmement bas) à 20 (maximum du potentiel humain), avec une moyenne de 10 ou 11. Plus une caractéristique est élevée plus le personnage est puissant dans cette aptitude.\nÀ la création de votre personnage, répartissez les valeurs suivantes dans les différentes caractéristiques : 15, 15, 13, 11, 10, 9 et 7. diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClient.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClient.kt index 254ddf2..dff8ec1 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClient.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClient.kt @@ -115,13 +115,35 @@ interface LwaClient { create: Boolean, ): APIResponse + suspend fun deleteInventory( + characterSheetId: String, + ): APIResponse + suspend fun createInventoryItem( characterSheetId: String, itemId: String, ): APIResponse - suspend fun deleteInventory( + suspend fun changeInventoryItemCount( characterSheetId: String, + inventoryId: String, + count: Float, + ): APIResponse + + suspend fun equipInventoryItem( + characterSheetId: String, + inventoryId: String, + equip: Boolean, + ): APIResponse + + suspend fun consumeInventoryItem( + characterSheetId: String, + inventoryId: String, + ): APIResponse + + suspend fun deleteInventoryItem( + characterSheetId: String, + inventoryId: String, ): APIResponse // Tags diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClientImpl.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClientImpl.kt index 48af180..032edbc 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClientImpl.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClientImpl.kt @@ -192,18 +192,52 @@ class LwaClientImpl( } .body>() + @Throws + override suspend fun deleteInventory(characterSheetId: String): APIResponse = client + .delete("$root/inventory/delete?characterSheetId=$characterSheetId") + .body() + @Throws override suspend fun createInventoryItem( characterSheetId: String, itemId: String, ): APIResponse = client - .put("$root/inventory/create?characterSheetId=$characterSheetId&itemId=$itemId") + .put("$root/inventory/item/create?characterSheetId=$characterSheetId&itemId=$itemId") .body>() @Throws - override suspend fun deleteInventory(characterSheetId: String): APIResponse = client - .delete("$root/inventory/delete?characterSheetId=$characterSheetId") - .body() + override suspend fun changeInventoryItemCount( + characterSheetId: String, + inventoryId: String, + count: Float, + ): APIResponse = client + .put("$root/inventory/item/count?characterSheetId=$characterSheetId&inventoryId=$inventoryId&count=$count") + .body>() + + @Throws + override suspend fun equipInventoryItem( + characterSheetId: String, + inventoryId: String, + equip: Boolean, + ): APIResponse = client + .put("$root/inventory/item/equip?characterSheetId=$characterSheetId&inventoryId=$inventoryId&equip=$equip") + .body>() + + @Throws + override suspend fun consumeInventoryItem( + characterSheetId: String, + inventoryId: String, + ): APIResponse = client + .put("$root/inventory/item/consume?characterSheetId=$characterSheetId&inventoryId=$inventoryId") + .body>() + + @Throws + override suspend fun deleteInventoryItem( + characterSheetId: String, + inventoryId: String, + ): APIResponse = client + .delete("$root/inventory/item/delete?characterSheetId=$characterSheetId&inventoryId=$inventoryId") + .body>() @Throws override suspend fun getAlterationTags(): APIResponse> = client diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/inventory/InventoryRepository.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/inventory/InventoryRepository.kt index 277d3d1..665c9cf 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/inventory/InventoryRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/inventory/InventoryRepository.kt @@ -53,11 +53,52 @@ class InventoryRepository( } @Throws - suspend fun deleteItem( + suspend fun changeInventoryItemCount( characterSheetId: String, + inventoryId: String, + count: Float, ) { - inventoryStore.deleteInventory( + inventoryStore.changeInventoryItemCount( characterSheetId = characterSheetId, + inventoryId = inventoryId, + count = count, + ) + } + + @Throws + suspend fun consumeInventoryItem( + characterSheetId: String, + inventoryId: String, + ) { + inventoryStore.consumeInventoryItem( + characterSheetId = characterSheetId, + inventoryId = inventoryId, + ) + } + + @Throws + suspend fun equipInventoryItem( + characterSheetId: String, + inventoryId: String, + ) { + val inventory = inventory(characterSheetId = characterSheetId) + val inventoryItem = inventory.items.firstOrNull { it.inventoryId == inventoryId } + + inventoryStore.equipInventoryItem( + characterSheetId = characterSheetId, + inventoryId = inventoryId, + equip = inventoryItem?.equipped?.not() ?: true, + ) + } + + @Throws + suspend fun deleteInventoryItem( + characterSheetId: String, + inventoryId: String, + ) { + inventoryStore.deleteInventoryItem( + characterSheetId = characterSheetId, + inventoryId = inventoryId, ) } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/inventory/InventoryStore.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/inventory/InventoryStore.kt index 5a86be5..2d5dc2f 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/inventory/InventoryStore.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/inventory/InventoryStore.kt @@ -73,6 +73,16 @@ class InventoryStore( } } + @Throws + suspend fun deleteInventory( + characterSheetId: String, + ) { + val request = client.deleteInventory(characterSheetId = characterSheetId) + if (request.success.not()) { + LwaClient.error(error = request) + } + } + @Throws suspend fun createInventoryItem( characterSheetId: String, @@ -89,10 +99,60 @@ class InventoryStore( } @Throws - suspend fun deleteInventory( + suspend fun changeInventoryItemCount( characterSheetId: String, + inventoryId: String, + count: Float, ) { - val request = client.deleteInventory(characterSheetId = characterSheetId) + val request = client.changeInventoryItemCount( + characterSheetId = characterSheetId, + inventoryId = inventoryId, + count = count, + ) + if (request.success.not()) { + LwaClient.error(error = request) + } + } + + @Throws + suspend fun consumeInventoryItem( + characterSheetId: String, + inventoryId: String, + ) { + val request = client.consumeInventoryItem( + characterSheetId = characterSheetId, + inventoryId = inventoryId, + ) + if (request.success.not()) { + LwaClient.error(error = request) + } + } + + @Throws + suspend fun equipInventoryItem( + characterSheetId: String, + inventoryId: String, + equip: Boolean, + ) { + val request = client.equipInventoryItem( + characterSheetId = characterSheetId, + inventoryId = inventoryId, + equip = equip, + ) + if (request.success.not()) { + LwaClient.error(error = request) + } + } + + @Throws + suspend fun deleteInventoryItem( + characterSheetId: String, + inventoryId: String, + ) { + val request = client.deleteInventoryItem( + characterSheetId = characterSheetId, + inventoryId = inventoryId, + ) if (request.success.not()) { LwaClient.error(error = request) } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/item/ItemDetailDialog.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/item/ItemDetailDialog.kt index 5cf0f31..fb369bd 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/item/ItemDetailDialog.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/item/ItemDetailDialog.kt @@ -1,6 +1,9 @@ package com.pixelized.desktop.lwa.ui.composable.character.item import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.togetherWith import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -42,7 +45,10 @@ import com.pixelized.desktop.lwa.ui.theme.lwa import com.pixelized.desktop.lwa.utils.rememberSaturationFilter import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.character__inventory__inventory__dialog__action +import lwacharactersheet.composeapp.generated.resources.character__inventory__inventory__dialog__consume_action import lwacharactersheet.composeapp.generated.resources.character__inventory__inventory__dialog__count_action +import lwacharactersheet.composeapp.generated.resources.character__inventory__inventory__dialog__equip_action +import lwacharactersheet.composeapp.generated.resources.character__inventory__inventory__dialog__throw_action import lwacharactersheet.composeapp.generated.resources.ic_close_24dp import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource @@ -59,12 +65,14 @@ data class ItemDetailDialogUio( val count: Float, // options val countable: LwaTextFieldUio?, + val consumable: Boolean, + val equipable: Boolean, ) @Stable object ItemDetailDialogDefault { @Stable - val paddings = PaddingValues(all = 16.dp) + val paddings = PaddingValues(top = 16.dp, start = 16.dp, end = 16.dp, bottom = 8.dp) @Stable val spacings = 8.dp @@ -78,6 +86,9 @@ fun ItemDetailDialog( onDismissRequest: () -> Unit, onConfirm: (ItemDetailDialogUio) -> Unit, onAddItem: (ItemDetailDialogUio) -> Unit, + onEquip: (ItemDetailDialogUio) -> Unit, + onConsume: (ItemDetailDialogUio) -> Unit, + onThrow: (ItemDetailDialogUio) -> Unit, ) { LwaDialog( state = dialog, @@ -85,7 +96,8 @@ fun ItemDetailDialog( onConfirm = { dialog.value?.let(onConfirm) ?: onDismissRequest }, ) { state -> val layoutDirection = LocalLayoutDirection.current - val end = remember(layoutDirection, paddings) { paddings.calculateEndPadding(layoutDirection) } + val end = + remember(layoutDirection, paddings) { paddings.calculateEndPadding(layoutDirection) } val top = remember(paddings) { paddings.calculateTopPadding() } takeIf { state.image?.isNotEmpty() == true }?.let { @@ -140,6 +152,7 @@ fun ItemDetailDialog( AnimatedContent( targetState = state.inventoryId, + transitionSpec = { fadeIn() togetherWith fadeOut() }, ) { when (it) { null -> Row( @@ -158,14 +171,12 @@ fun ItemDetailDialog( else -> Column( verticalArrangement = Arrangement.spacedBy(space = spacings) ) { - if (state.countable != null) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy( - space = spacings, - Alignment.End, - ) - ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(space = spacings), + verticalAlignment = Alignment.Bottom, + ) { + if (state.countable != null) { LwaTextField( modifier = Modifier.width(width = 128.dp), colors = LwaTextFieldColors( @@ -188,6 +199,34 @@ fun ItemDetailDialog( ) } } + Spacer( + modifier = Modifier.weight(weight = 1f), + ) + TextButton( + onClick = { onThrow(state) }, + ) { + Text( + text = stringResource(Res.string.character__inventory__inventory__dialog__throw_action), + ) + } + if (state.equipable) { + TextButton( + onClick = { onEquip(state) }, + ) { + Text( + text = stringResource(Res.string.character__inventory__inventory__dialog__equip_action), + ) + } + } + if (state.consumable) { + TextButton( + onClick = { onConsume(state) }, + ) { + Text( + text = stringResource(Res.string.character__inventory__inventory__dialog__consume_action), + ) + } + } } } } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/item/ItemDetailDialogFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/item/ItemDetailDialogFactory.kt index f0382f1..efde7eb 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/item/ItemDetailDialogFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/item/ItemDetailDialogFactory.kt @@ -37,6 +37,8 @@ class ItemDetailDialogFactory { countable = takeIf { item.options.stackable } ?.let { createFieldFlow(value = format.format(count)) } ?.createTextField(label = getString(Res.string.character__inventory__inventory__dialog__count)), + consumable = item.options.consumable, + equipable = item.options.equipable, ) } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/item/ItemDetailDialogViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/item/ItemDetailDialogViewModel.kt index dc2ab62..a9fae35 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/item/ItemDetailDialogViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/item/ItemDetailDialogViewModel.kt @@ -83,49 +83,99 @@ class ItemDetailDialogViewModel( suspend fun onAddInventoryItem( characterSheetId: String, itemId: String, - ) { + ) : Boolean { try { // create the inventory item on the server, get the newly create id from that. val inventoryId = inventoryRepository.createInventoryItem( characterSheetId = characterSheetId, itemId = itemId, ) + return true // update the dialog with the id only if this dialog still correspond to this item. (should always be the case but hey). - if (selectedItemId.value?.let { it.itemId == itemId && it.characterSheetId == characterSheetId } == true) { - selectedItemId.update { - it?.copy(inventoryId = inventoryId) - } - } +// if (selectedItemId.value?.let { it.itemId == itemId && it.characterSheetId == characterSheetId } == true) { +// selectedItemId.update { +// it?.copy(inventoryId = inventoryId) +// } +// } } catch (exception: Exception) { val message = ErrorSnackUio.from(exception) _error.emit(message) + return false + } + } + + suspend fun throwInventoryItem( + characterSheetId: String, + inventoryId: String?, + ): Boolean { + if (inventoryId == null) return false + try { + inventoryRepository.deleteInventoryItem( + characterSheetId = characterSheetId, + inventoryId = inventoryId, + ) + return true + } catch (exception: Exception) { + val message = ErrorSnackUio.from(exception) + _error.emit(message) + return false + } + } + + suspend fun consumeInventoryItem( + characterSheetId: String, + inventoryId: String?, + ): Boolean { + if (inventoryId == null) return false + try { + inventoryRepository.consumeInventoryItem( + characterSheetId = characterSheetId, + inventoryId = inventoryId, + ) + return true + } catch (exception: Exception) { + val message = ErrorSnackUio.from(exception) + _error.emit(message) + return false + } + } + + suspend fun equipInventoryItem( + characterSheetId: String, + inventoryId: String?, + ) : Boolean { + if (inventoryId == null) return false + try { + inventoryRepository.equipInventoryItem( + characterSheetId = characterSheetId, + inventoryId = inventoryId, + ) + return true + } catch (exception: Exception) { + val message = ErrorSnackUio.from(exception) + _error.emit(message) + return false } } suspend fun changeInventoryItemQuantity( - dialog: ItemDetailDialogUio - ) : Boolean { + dialog: ItemDetailDialogUio, + ): Boolean { if (dialog.countable?.isError?.value == true) return false val characterSheetId = dialog.characterSheetId val inventoryId = dialog.inventoryId ?: return false val quantity = dialog.countable?.valueFlow?.value ?: return false - val count = factory.parse(quantity = quantity) ?: return false - - val inventory = inventoryRepository.inventory(characterSheetId = characterSheetId) + val count = factory.parse(quantity = quantity) + ?: quantity.toFloatOrNull() + ?: return false try { - inventoryRepository.updateInventory( - inventory = inventory.copy( - items = inventory.items.toMutableList().also { items -> - val index = items.indexOfFirst { item -> item.inventoryId == inventoryId } - items[index] = items[index].copy( - count = count, - ) - } - ), - create = false, + inventoryRepository.changeInventoryItemCount( + characterSheetId = characterSheetId, + inventoryId = inventoryId, + count = count ) return true } catch (exception: Exception) { diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/CharacterDetailInventory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/CharacterDetailInventory.kt index a6e28fa..c2bc1e1 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/CharacterDetailInventory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/CharacterDetailInventory.kt @@ -29,7 +29,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import coil3.compose.rememberDrawScopeSizeResolver import com.pixelized.desktop.lwa.LocalBlurController import com.pixelized.desktop.lwa.ui.composable.character.inventory.InventoryDialog import com.pixelized.desktop.lwa.ui.composable.character.inventory.InventoryDialogViewModel @@ -118,6 +117,14 @@ fun CharacterDetailInventory( inventoryDialogViewModel.showInventoryDialog( characterSheetId = it, ) + }, + onConsume = { + scope.launch { + itemDetailDialogViewModel.consumeInventoryItem( + characterSheetId = it.characterSheetId, + inventoryId = it.inventoryId, + ) + } } ) } @@ -165,10 +172,14 @@ fun CharacterDetailInventory( }, onAddItem = { dialog -> scope.launch { - itemDetailDialogViewModel.onAddInventoryItem( + val result = itemDetailDialogViewModel.onAddInventoryItem( characterSheetId = dialog.characterSheetId, itemId = dialog.itemId, ) + if (result) { + blur.hide() + itemDetailDialogViewModel.hideItemDialog() + } } }, onConfirm = { dialog -> @@ -181,12 +192,51 @@ fun CharacterDetailInventory( itemDetailDialogViewModel.hideItemDialog() } } + }, + onEquip = { dialog -> + scope.launch { + val result = itemDetailDialogViewModel.equipInventoryItem( + characterSheetId = dialog.characterSheetId, + inventoryId = dialog.inventoryId, + ) + if (result) { + blur.hide() + itemDetailDialogViewModel.hideItemDialog() + } + } + }, + onConsume = { dialog -> + scope.launch { + val result = itemDetailDialogViewModel.consumeInventoryItem( + characterSheetId = dialog.characterSheetId, + inventoryId = dialog.inventoryId, + ) + if (result) { + blur.hide() + itemDetailDialogViewModel.hideItemDialog() + } + } + }, + onThrow = { dialog -> + scope.launch { + val result = itemDetailDialogViewModel.throwInventoryItem( + characterSheetId = dialog.characterSheetId, + inventoryId = dialog.inventoryId, + ) + if (result) { + blur.hide() + itemDetailDialogViewModel.hideItemDialog() + } + } } ) ErrorSnackHandler( error = purseViewModel.error, ) + ErrorSnackHandler( + error = itemDetailDialogViewModel.error, + ) } @Composable @@ -197,6 +247,7 @@ private fun CharacterDetailInventoryContent( inventory: CharacterDetailInventoryUio, onPurse: (String) -> Unit, onItem: (InventoryItemUio) -> Unit, + onConsume: (InventoryItemUio) -> Unit, onAddItem: (String) -> Unit, ) { Box( @@ -257,6 +308,7 @@ private fun CharacterDetailInventoryContent( modifier = Modifier.animateItem(), item = it, onClick = { onItem(it) }, + onConsume = { onConsume(it) }, ) } } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/CharacterDetailInventoryFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/CharacterDetailInventoryFactory.kt index dff60d6..52c0663 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/CharacterDetailInventoryFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/CharacterDetailInventoryFactory.kt @@ -86,6 +86,7 @@ class CharacterDetailInventoryFactory( label = item.metadata.label, count = it.count, equipped = it.equipped, + consumable = item.options.consumable, tooltips = takeIf { item.metadata.description.isNotEmpty() }?.let { InventoryItemUio.Tooltips( label = item.metadata.label, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/item/InventoryItem.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/item/InventoryItem.kt index 828302a..e9c54d2 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/item/InventoryItem.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/item/InventoryItem.kt @@ -19,6 +19,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface import androidx.compose.material.Text +import androidx.compose.material.TextButton import androidx.compose.material.minimumInteractiveComponentSize import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable @@ -38,6 +39,9 @@ import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipLayout2 import com.pixelized.desktop.lwa.ui.theme.lwa import com.pixelized.desktop.lwa.utils.extention.ribbon import com.pixelized.desktop.lwa.utils.rememberSaturationFilter +import lwacharactersheet.composeapp.generated.resources.Res +import lwacharactersheet.composeapp.generated.resources.character__inventory__use__action +import org.jetbrains.compose.resources.stringResource @Stable data class InventoryItemUio( @@ -47,6 +51,7 @@ data class InventoryItemUio( val label: String, val count: Float, val equipped: Boolean, + val consumable: Boolean, val tooltips: Tooltips?, ) { @Stable @@ -60,7 +65,7 @@ data class InventoryItemUio( @Stable object GMCharacterPreviewDefault { @Stable - val paddings = PaddingValues(horizontal = 16.dp, vertical = 4.dp) + val paddings = PaddingValues(horizontal = 16.dp) @Stable val spacing: Dp = 4.dp @@ -74,6 +79,7 @@ fun InventoryItem( spacing: Dp = GMCharacterPreviewDefault.spacing, item: InventoryItemUio, onClick: () -> Unit, + onConsume: () -> Unit, ) { TooltipLayout2( modifier = modifier, @@ -134,30 +140,41 @@ fun InventoryItem( .fillMaxWidth() .padding(paddingValues = padding) .then(other = modifier), - horizontalArrangement = Arrangement.spacedBy(space = spacing), + horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { - Text( - modifier = Modifier.alignByBaseline(), - style = MaterialTheme.lwa.typography.base.body1, - fontWeight = FontWeight.Bold, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - text = item.label, - ) - AnimatedContent( - modifier = Modifier.alignByBaseline(), - targetState = item.count, - transitionSpec = { fadeIn() togetherWith fadeOut() }, + Row( + horizontalArrangement = Arrangement.spacedBy(space = spacing), ) { - when (it) { - 0f, 1f -> Unit - else -> Text( - style = MaterialTheme.lwa.typography.base.caption, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - text = "x${it}", - ) + Text( + modifier = Modifier.alignByBaseline(), + style = MaterialTheme.lwa.typography.base.body1, + fontWeight = FontWeight.Bold, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + text = item.label, + ) + AnimatedContent( + modifier = Modifier.alignByBaseline(), + targetState = item.count, + transitionSpec = { fadeIn() togetherWith fadeOut() }, + ) { + when (it) { + 0f, 1f -> Unit + else -> Text( + style = MaterialTheme.lwa.typography.base.caption, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + text = "x${it}", + ) + } + } + } + if (item.consumable) { + TextButton( + onClick = onConsume, + ) { + Text(text = stringResource(Res.string.character__inventory__use__action)) } } } diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/model/inventory/InventoryService.kt b/server/src/main/kotlin/com/pixelized/server/lwa/model/inventory/InventoryService.kt index 789bf8b..7ebb404 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/model/inventory/InventoryService.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/model/inventory/InventoryService.kt @@ -1,5 +1,7 @@ package com.pixelized.server.lwa.model.inventory +import com.pixelized.server.lwa.model.item.ItemStore +import com.pixelized.server.lwa.server.exception.BusinessException import com.pixelized.shared.lwa.model.inventory.Inventory import com.pixelized.shared.lwa.model.inventory.InventoryJson import com.pixelized.shared.lwa.model.inventory.factory.InventoryJsonFactory @@ -9,9 +11,11 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn +import java.util.UUID class InventoryService( private val inventoryStore: InventoryStore, + private val itemStore: ItemStore, private val factory: InventoryJsonFactory, ) { private val scope = CoroutineScope(Dispatchers.IO + Job()) @@ -51,13 +55,185 @@ class InventoryService( } @Throws - fun createItem( + fun createInventoryItem( characterSheetId: String, itemId: String, - ) : String { - return inventoryStore.createItem( - characterSheetId = characterSheetId, + ): String { + // get the inventory of the character, if none create one. + val inventory = inventoryStore.inventoryFlow().value[characterSheetId] + ?: Inventory.empty(characterSheetId = characterSheetId) + // create an inventoryId. + val inventoryId = inventory.items.createInventoryId() + // create an inventory Item. + val item = Inventory.Item( + inventoryId = inventoryId, itemId = itemId, + count = 1f, + equipped = false, + ) + // update the inventory with the updated item. + val updatedInventory = inventory.copy( + items = inventory.items.toMutableList().also { + it.add(item) + } + ) + // save the inventory + inventoryStore.save( + inventory = updatedInventory, + create = false, + ) + return inventoryId + } + + @Throws + fun changeInventoryItemCount( + characterSheetId: String, + inventoryId: String, + count: Float, + ) { + if (count < 0) { + throw BusinessException( + message = "InventoryItem (id:$inventoryId) quantity cannot go below 0.", + ) + } + // get the inventory of the character, if none create one. + val inventory = inventoryStore.inventoryFlow().value[characterSheetId] + ?: Inventory.empty(characterSheetId = characterSheetId) + // Guard case. + val inventoryItemIndex = inventory.items.indexOfFirst { it.inventoryId == inventoryId } + if (inventoryItemIndex < 0) { + throw BusinessException( + message = "InventoryItem (id:$inventoryId) not found in Inventory(characterSheetId:$characterSheetId).", + ) + } + // update the inventory with the updated item. + val updatedInventory = inventory.copy( + items = inventory.items.toMutableList().also { items -> + if (count == 0f) { + items.removeAt(inventoryItemIndex) + } else { + items[inventoryItemIndex] = items[inventoryItemIndex].copy(count = count) + } + } + ) + // save the inventory + inventoryStore.save( + inventory = updatedInventory, + create = false, ) } + + @Throws + fun consumeInventoryItem( + characterSheetId: String, + inventoryId: String, + ) { + // get the inventory of the character, if none create one. + val inventory = inventoryStore.inventoryFlow().value[characterSheetId] + ?: Inventory.empty(characterSheetId = characterSheetId) + // Guard case. + val inventoryItemIndex = inventory.items.indexOfFirst { it.inventoryId == inventoryId } + if (inventoryItemIndex < 0) { + throw BusinessException( + message = "InventoryItem (id:$inventoryId) not found in Inventory(characterSheetId:$characterSheetId).", + ) + } + // other Guard case. + val itemId = inventory.items[inventoryItemIndex].itemId + val item = itemStore.item(itemId = itemId) + ?: throw BusinessException(message = "Item (id:$itemId) not found.") + if (item.options.consumable.not()) { + throw BusinessException(message = "Item (id:$itemId) is not consumable.") + } + // update the inventory with the updated item. + val updatedInventory = inventory.copy( + items = inventory.items.toMutableList().also { items -> + val inventoryItem = inventory.items[inventoryItemIndex] + if (inventoryItem.count - 1f <= 0f) { + items.removeAt(inventoryItemIndex) + } else { + items[inventoryItemIndex] = inventoryItem.copy(count = inventoryItem.count - 1f) + } + } + ) + // save the inventory + inventoryStore.save( + inventory = updatedInventory, + create = false, + ) + } + + @Throws + fun equipInventoryItem( + characterSheetId: String, + inventoryId: String, + equip: Boolean, + ) { + // get the inventory of the character, if none create one. + val inventory = inventoryStore.inventoryFlow().value[characterSheetId] + ?: Inventory.empty(characterSheetId = characterSheetId) + // Guard case. + val inventoryItemIndex = inventory.items.indexOfFirst { it.inventoryId == inventoryId } + if (inventoryItemIndex < 0) { + throw BusinessException( + message = "InventoryItem (id:$inventoryId) not found in Inventory(characterSheetId:$characterSheetId).", + ) + } + // other Guard case. + val itemId = inventory.items[inventoryItemIndex].itemId + val item = itemStore.item(itemId = itemId) + ?: throw BusinessException(message = "Item (id:$itemId) not found.") + if (item.options.equipable.not()) { + throw BusinessException(message = "Item (id:$itemId) is not equipable.") + } + // update the inventory with the updated item. + val updatedInventory = inventory.copy( + items = inventory.items.toMutableList().also { items -> + items[inventoryItemIndex] = inventory.items[inventoryItemIndex].copy( + equipped = equip + ) + } + ) + // save the inventory + inventoryStore.save( + inventory = updatedInventory, + create = false, + ) + } + + @Throws + fun deleteInventoryItem( + characterSheetId: String, + inventoryId: String, + ) { + // get the inventory of the character, if none create one. + val inventory = inventoryStore.inventoryFlow().value[characterSheetId] + ?: Inventory.empty(characterSheetId = characterSheetId) + // Guard case. + val inventoryItemIndex = inventory.items.indexOfFirst { it.inventoryId == inventoryId } + if (inventoryItemIndex < 0) { + throw BusinessException( + message = "InventoryItem (id:$inventoryId) not found in Inventory(characterSheetId:$characterSheetId)", + ) + } + // update the inventory with the updated item. + val updatedInventory = inventory.copy( + items = inventory.items.toMutableList().also { items -> + items.removeAt(inventoryItemIndex) + } + ) + // save the inventory + inventoryStore.save( + inventory = updatedInventory, + create = false, + ) + } + + private fun List.createInventoryId(): String { + var inventoryId: String + do { + inventoryId = UUID.randomUUID().toString() + } while (any { inventoryId == it.inventoryId }) + return inventoryId + } } diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/model/inventory/InventoryStore.kt b/server/src/main/kotlin/com/pixelized/server/lwa/model/inventory/InventoryStore.kt index 6378c18..1bb13a5 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/model/inventory/InventoryStore.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/model/inventory/InventoryStore.kt @@ -153,49 +153,7 @@ class InventoryStore( } } - @Throws - fun createItem( - characterSheetId: String, - itemId: String, - ): String { - val (updatedInventory, inventoryId) = inventoryFlow.value.toMutableMap().let { characters -> - // get the inventory of the character, if none create one. - val inventory = characters[characterSheetId] - ?: Inventory.empty(characterSheetId = characterSheetId) - // create an inventoryId. - val inventoryId = inventory.items.createInventoryId() - // create an inventory Item. - val item = Inventory.Item( - inventoryId = inventoryId, - itemId = itemId, - count = 1f, - equipped = false, - ) - // update the inventory with the updated item. - inventory.copy( - items = inventory.items.toMutableList().also { - it.add(item) - } - ) to inventoryId - } - // save the inventory - save( - inventory = updatedInventory, - create = false, - ) - // return the inventory ID. - return inventoryId - } - private fun inventoryFile(id: String): File { return File("${pathProvider.inventoryPath()}${id}.json") } - - private fun List.createInventoryId(): String { - var inventoryId: String - do { - inventoryId = UUID.randomUUID().toString() - } while (any { inventoryId == it.inventoryId }) - return inventoryId - } } diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/model/item/ItemStore.kt b/server/src/main/kotlin/com/pixelized/server/lwa/model/item/ItemStore.kt index af04b54..0915684 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/model/item/ItemStore.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/model/item/ItemStore.kt @@ -37,6 +37,10 @@ class ItemStore( } } + fun item(itemId: String?): Item? { + return itemFlow.value.firstOrNull { it.id == itemId } + } + fun itemsFlow(): StateFlow> = itemFlow private fun updateItemsFlow() { diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/Server.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/Server.kt index 8fb3a98..5582ca7 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/server/Server.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/Server.kt @@ -19,8 +19,12 @@ import com.pixelized.server.lwa.server.rest.character.putCharacterAlteration import com.pixelized.server.lwa.server.rest.character.putCharacterDamage import com.pixelized.server.lwa.server.rest.character.putCharacterDiminished import com.pixelized.server.lwa.server.rest.character.putCharacterFatigue -import com.pixelized.server.lwa.server.rest.inventory.createInventory +import com.pixelized.server.lwa.server.rest.inventory.changeInventoryItemCount +import com.pixelized.server.lwa.server.rest.inventory.consumeInventoryItem +import com.pixelized.server.lwa.server.rest.inventory.createInventoryItem +import com.pixelized.server.lwa.server.rest.inventory.equipInventoryItem import com.pixelized.server.lwa.server.rest.inventory.deleteInventory +import com.pixelized.server.lwa.server.rest.inventory.deleteInventoryItem import com.pixelized.server.lwa.server.rest.inventory.getInventory import com.pixelized.server.lwa.server.rest.inventory.putInventory import com.pixelized.server.lwa.server.rest.item.deleteItem @@ -218,7 +222,7 @@ class LocalServer { body = engine.deleteAlteration() ) } - route(path = "item") { + route(path = "/item") { get( path = "/all", body = engine.getItems(), @@ -236,7 +240,7 @@ class LocalServer { body = engine.deleteItem(), ) } - route(path = "tag") { + route(path = "/tag") { get( path = "/character", body = engine.getCharacterTags(), @@ -250,7 +254,7 @@ class LocalServer { body = engine.getItemTags(), ) } - route(path = "inventory") { + route(path = "/inventory") { get( path = "/detail", body = engine.getInventory(), @@ -259,14 +263,34 @@ class LocalServer { path = "/update", body = engine.putInventory() ) - put( - path = "/create", - body = engine.createInventory() - ) delete( path = "/delete", body = engine.deleteInventory() ) + route( + path = "/item" + ) { + put( + path = "/create", + body = engine.createInventoryItem() + ) + put( + path = "/count", + body = engine.changeInventoryItemCount() + ) + put( + path = "/consume", + body = engine.consumeInventoryItem() + ) + put( + path = "/equip", + body = engine.equipInventoryItem() + ) + delete( + path = "/delete", + body = engine.deleteInventoryItem() + ) + } } } } diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/DELETE_InventoryItem.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/DELETE_InventoryItem.kt new file mode 100644 index 0000000..4567f18 --- /dev/null +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/DELETE_InventoryItem.kt @@ -0,0 +1,40 @@ +package com.pixelized.server.lwa.server.rest.inventory + +import com.pixelized.server.lwa.server.Engine +import com.pixelized.server.lwa.utils.extentions.characterSheetId +import com.pixelized.server.lwa.utils.extentions.exception +import com.pixelized.server.lwa.utils.extentions.inventoryId +import com.pixelized.server.lwa.utils.extentions.itemId +import com.pixelized.shared.lwa.protocol.rest.APIResponse +import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation +import io.ktor.server.response.respond +import io.ktor.server.routing.RoutingContext + +fun Engine.deleteInventoryItem(): suspend RoutingContext.() -> Unit { + return { + try { + // get the query parameter + val characterSheetId = call.queryParameters.characterSheetId + val inventoryId = call.queryParameters.inventoryId + // add the item to the inventory. + inventoryService.deleteInventoryItem( + characterSheetId = characterSheetId, + inventoryId = inventoryId, + ) + // API & WebSocket responses. + call.respond( + message = APIResponse.success(), + ) + webSocket.emit( + value = ApiSynchronisation.InventoryUpdate( + timestamp = System.currentTimeMillis(), + characterSheetId = characterSheetId, + ), + ) + } catch (exception: Exception) { + call.exception( + exception = exception, + ) + } + } +} diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/PUT_ChangeInventoryItemCount.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/PUT_ChangeInventoryItemCount.kt new file mode 100644 index 0000000..0e3c9e4 --- /dev/null +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/PUT_ChangeInventoryItemCount.kt @@ -0,0 +1,42 @@ +package com.pixelized.server.lwa.server.rest.inventory + +import com.pixelized.server.lwa.server.Engine +import com.pixelized.server.lwa.utils.extentions.characterSheetId +import com.pixelized.server.lwa.utils.extentions.count +import com.pixelized.server.lwa.utils.extentions.exception +import com.pixelized.server.lwa.utils.extentions.inventoryId +import com.pixelized.shared.lwa.protocol.rest.APIResponse +import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation +import io.ktor.server.response.respond +import io.ktor.server.routing.RoutingContext + +fun Engine.changeInventoryItemCount(): suspend RoutingContext.() -> Unit { + return { + try { + // get the query parameter + val characterSheetId = call.queryParameters.characterSheetId + val inventoryId = call.queryParameters.inventoryId + val count = call.queryParameters.count + // add the item to the inventory. + inventoryService.changeInventoryItemCount( + characterSheetId = characterSheetId, + inventoryId = inventoryId, + count = count, + ) + // API & WebSocket responses. + call.respond( + message = APIResponse.success(), + ) + webSocket.emit( + value = ApiSynchronisation.InventoryUpdate( + timestamp = System.currentTimeMillis(), + characterSheetId = characterSheetId, + ), + ) + } catch (exception: Exception) { + call.exception( + exception = exception, + ) + } + } +} diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/PUT_ConsumeInventoryItem.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/PUT_ConsumeInventoryItem.kt new file mode 100644 index 0000000..322c553 --- /dev/null +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/PUT_ConsumeInventoryItem.kt @@ -0,0 +1,39 @@ +package com.pixelized.server.lwa.server.rest.inventory + +import com.pixelized.server.lwa.server.Engine +import com.pixelized.server.lwa.utils.extentions.characterSheetId +import com.pixelized.server.lwa.utils.extentions.exception +import com.pixelized.server.lwa.utils.extentions.inventoryId +import com.pixelized.shared.lwa.protocol.rest.APIResponse +import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation +import io.ktor.server.response.respond +import io.ktor.server.routing.RoutingContext + +fun Engine.consumeInventoryItem(): suspend RoutingContext.() -> Unit { + return { + try { + // get the query parameter + val characterSheetId = call.queryParameters.characterSheetId + val inventoryId = call.queryParameters.inventoryId + // add the item to the inventory. + inventoryService.consumeInventoryItem( + characterSheetId = characterSheetId, + inventoryId = inventoryId, + ) + // API & WebSocket responses. + call.respond( + message = APIResponse.success(), + ) + webSocket.emit( + value = ApiSynchronisation.InventoryUpdate( + timestamp = System.currentTimeMillis(), + characterSheetId = characterSheetId, + ), + ) + } catch (exception: Exception) { + call.exception( + exception = exception, + ) + } + } +} diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/PUT_EquipInventoryItem.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/PUT_EquipInventoryItem.kt new file mode 100644 index 0000000..e7aecbc --- /dev/null +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/PUT_EquipInventoryItem.kt @@ -0,0 +1,43 @@ +package com.pixelized.server.lwa.server.rest.inventory + +import com.pixelized.server.lwa.server.Engine +import com.pixelized.server.lwa.utils.extentions.characterSheetId +import com.pixelized.server.lwa.utils.extentions.equip +import com.pixelized.server.lwa.utils.extentions.exception +import com.pixelized.server.lwa.utils.extentions.inventoryId +import com.pixelized.shared.lwa.protocol.rest.APIResponse +import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation +import io.ktor.server.response.respond +import io.ktor.server.routing.RoutingContext + +fun Engine.equipInventoryItem(): suspend RoutingContext.() -> Unit { + return { + try { + // get the query parameter + val characterSheetId = call.queryParameters.characterSheetId + val inventoryId = call.queryParameters.inventoryId + val equip = call.queryParameters.equip + + // add the item to the inventory. + inventoryService.equipInventoryItem( + characterSheetId = characterSheetId, + inventoryId = inventoryId, + equip = equip, + ) + // API & WebSocket responses. + call.respond( + message = APIResponse.success(), + ) + webSocket.emit( + value = ApiSynchronisation.InventoryUpdate( + timestamp = System.currentTimeMillis(), + characterSheetId = characterSheetId, + ), + ) + } catch (exception: Exception) { + call.exception( + exception = exception, + ) + } + } +} diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/CREATE_Inventory.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/PUT_InventoryItem.kt similarity index 91% rename from server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/CREATE_Inventory.kt rename to server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/PUT_InventoryItem.kt index 186be00..4a67738 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/CREATE_Inventory.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/inventory/PUT_InventoryItem.kt @@ -9,14 +9,14 @@ import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation import io.ktor.server.response.respond import io.ktor.server.routing.RoutingContext -fun Engine.createInventory(): suspend RoutingContext.() -> Unit { +fun Engine.createInventoryItem(): suspend RoutingContext.() -> Unit { return { try { // get the query parameter val characterSheetId = call.queryParameters.characterSheetId val itemId = call.queryParameters.itemId // add the item to the inventory. - val inventoryId = inventoryService.createItem( + val inventoryId = inventoryService.createInventoryItem( characterSheetId = characterSheetId, itemId = itemId, ) diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/utils/extentions/ParametersExt.kt b/server/src/main/kotlin/com/pixelized/server/lwa/utils/extentions/ParametersExt.kt index 3c71759..0475558 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/utils/extentions/ParametersExt.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/utils/extentions/ParametersExt.kt @@ -10,6 +10,7 @@ inline fun Parameters.param( ): T { return when (T::class) { String::class -> this[name] as? T + Float::class -> this[name]?.toFloatOrNull() as? T Boolean::class -> this[name]?.toBooleanStrictOrNull() as? T else -> null } ?: throw MissingParameterException( @@ -30,12 +31,24 @@ val Parameters.alterationId: String code = APIResponse.ErrorCode.AlterationId, ) +val Parameters.inventoryId: String + get() = param( + name = "inventoryId", + code = APIResponse.ErrorCode.InventoryId, + ) + val Parameters.itemId: String get() = param( name = "itemId", code = APIResponse.ErrorCode.ItemId, ) +val Parameters.count: Float + get() = param( + name = "count", + code = APIResponse.ErrorCode.Count, + ) + val Parameters.create: Boolean get() = param( name = "create", @@ -46,4 +59,10 @@ val Parameters.active: Boolean get() = param( name = "active", code = APIResponse.ErrorCode.Active, + ) + +val Parameters.equip: Boolean + get() = param( + name = "equip", + code = APIResponse.ErrorCode.Equip, ) \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/APIResponse.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/APIResponse.kt index 52b62ce..b058d0d 100644 --- a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/APIResponse.kt +++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/APIResponse.kt @@ -15,13 +15,16 @@ data class APIResponse( AlterationId, AlterationName, ItemId, + InventoryId, ItemName, CharacterSheetId, Create, Active, + Equip, Damage, Fatigue, Diminished, + Count, } companion object {