mirror of
https://github.com/nacabaro/vbhelper.git
synced 2026-06-05 22:02:54 +00:00
Swapped to 3 panel battle.
This commit is contained in:
parent
7843be7004
commit
b3cf823c3f
@ -96,8 +96,8 @@ fun BattleScreen(
|
|||||||
LaunchedEffect(battleSystem.attackPhase) {
|
LaunchedEffect(battleSystem.attackPhase) {
|
||||||
when (battleSystem.attackPhase) {
|
when (battleSystem.attackPhase) {
|
||||||
1 -> {
|
1 -> {
|
||||||
// Phase 1: Player attack on player screen
|
// Phase 1: Both attacks from middle screen
|
||||||
println("Starting Phase 1: Player attack on player screen")
|
println("Starting Phase 1: Both attacks from middle screen")
|
||||||
var progress = 0f
|
var progress = 0f
|
||||||
while (progress < 1f) {
|
while (progress < 1f) {
|
||||||
progress += 0.016f // 60 FPS
|
progress += 0.016f // 60 FPS
|
||||||
@ -108,86 +108,72 @@ fun BattleScreen(
|
|||||||
battleSystem.advanceAttackPhase()
|
battleSystem.advanceAttackPhase()
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
// Phase 2: Player attack on opponent screen
|
// Phase 2: Player attack on enemy screen
|
||||||
println("Starting Phase 2: Player attack on opponent screen")
|
println("Starting Phase 2: Player attack on enemy screen")
|
||||||
battleSystem.switchToView(1)
|
battleSystem.switchToView(2) // Enemy screen
|
||||||
var progress = 0f
|
var progress = 0f
|
||||||
while (progress < 1f) {
|
while (progress < 1f) {
|
||||||
progress += 0.016f // 60 FPS
|
progress += 0.016f // 60 FPS
|
||||||
battleSystem.setAttackProgress(progress)
|
battleSystem.setAttackProgress(progress)
|
||||||
|
|
||||||
// Trigger animation when attack reaches the opponent (around 55% progress for opponent dodge)
|
// Trigger animation when attack reaches the enemy (around 55% progress for enemy dodge)
|
||||||
if (progress >= 0.55f && !battleSystem.isOpponentHit && !battleSystem.isOpponentDodging) {
|
if (progress >= 0.55f && !battleSystem.isOpponentHit && !battleSystem.isOpponentDodging) {
|
||||||
if (battleSystem.attackIsHit) {
|
if (battleSystem.attackIsHit) {
|
||||||
// Player attack hits opponent
|
// Player attack hits enemy
|
||||||
println("Player attack hits opponent at progress $progress")
|
println("Player attack hits enemy at progress $progress")
|
||||||
battleSystem.startOpponentHit()
|
battleSystem.startOpponentHit()
|
||||||
} else {
|
} else {
|
||||||
// Player attack misses, opponent dodges
|
// Player attack misses, enemy dodges
|
||||||
println("Player attack misses, opponent dodges at progress $progress")
|
println("Player attack misses, enemy dodges at progress $progress")
|
||||||
battleSystem.startOpponentDodge()
|
battleSystem.startOpponentDodge()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(16) // 60 FPS
|
delay(16) // 60 FPS
|
||||||
}
|
}
|
||||||
println("Phase 2 completed, applying damage and starting opponent attack")
|
println("Phase 2 completed, applying damage and starting Phase 3")
|
||||||
// Apply player's damage
|
// Apply player's damage
|
||||||
battleSystem.completeAttackAnimation(opponentDamage = pendingOpponentDamage)
|
battleSystem.completeAttackAnimation(opponentDamage = pendingOpponentDamage)
|
||||||
pendingOpponentDamage = 0f
|
pendingOpponentDamage = 0f
|
||||||
delay(500)
|
delay(500)
|
||||||
|
|
||||||
// Check if there's a counter-attack set up
|
// Check if there should be a counter-attack
|
||||||
if (battleSystem.shouldCounterAttack) {
|
if (battleSystem.shouldCounterAttack) {
|
||||||
println("Starting counter-attack")
|
println("Starting counter-attack from Phase 2")
|
||||||
battleSystem.startCounterAttack()
|
battleSystem.startCounterAttack()
|
||||||
} else {
|
} else {
|
||||||
// Normal opponent attack
|
println("No counter-attack, advancing to Phase 3")
|
||||||
battleSystem.startOpponentAttack()
|
battleSystem.advanceAttackPhase()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
3 -> {
|
3 -> {
|
||||||
// Phase 3: Opponent attack on opponent screen
|
// Phase 3: Enemy attack on player screen
|
||||||
println("Starting Phase 3: Opponent attack on opponent screen")
|
println("Starting Phase 3: Enemy attack on player screen")
|
||||||
battleSystem.switchToView(1)
|
battleSystem.switchToView(1) // Player screen
|
||||||
var progress = 0f
|
|
||||||
while (progress < 1f) {
|
|
||||||
progress += 0.016f // 60 FPS
|
|
||||||
battleSystem.setAttackProgress(progress)
|
|
||||||
delay(16) // 60 FPS
|
|
||||||
}
|
|
||||||
println("Phase 3 completed, advancing to Phase 4")
|
|
||||||
battleSystem.advanceAttackPhase()
|
|
||||||
}
|
|
||||||
4 -> {
|
|
||||||
// Phase 4: Opponent attack on player screen
|
|
||||||
println("Starting Phase 4: Opponent attack on player screen")
|
|
||||||
battleSystem.switchToView(0)
|
|
||||||
var progress = 0f
|
var progress = 0f
|
||||||
while (progress < 1f) {
|
while (progress < 1f) {
|
||||||
progress += 0.016f // 60 FPS
|
progress += 0.016f // 60 FPS
|
||||||
battleSystem.setAttackProgress(progress)
|
battleSystem.setAttackProgress(progress)
|
||||||
|
|
||||||
// Trigger animation when attack reaches the player (around 75% progress - earlier for better timing)
|
// Trigger animation when attack reaches the player (around 75% progress for player dodge)
|
||||||
if (progress >= 0.75f && !battleSystem.isPlayerHit && !battleSystem.isPlayerDodging) {
|
if (progress >= 0.75f && !battleSystem.isPlayerHit && !battleSystem.isPlayerDodging) {
|
||||||
println("Phase 4: Checking player animation at progress $progress, opponentAttackIsHit=${battleSystem.opponentAttackIsHit}, shouldCounterAttack=${battleSystem.shouldCounterAttack}, counterAttackIsHit=${battleSystem.counterAttackIsHit}")
|
println("Phase 3: Checking player animation at progress $progress, opponentAttackIsHit=${battleSystem.opponentAttackIsHit}")
|
||||||
println("Phase 4: Player animation decision - opponentAttackIsHit=${battleSystem.opponentAttackIsHit}, will ${if (battleSystem.opponentAttackIsHit) "HIT" else "DODGE"}")
|
println("Phase 3: Player animation decision - opponentAttackIsHit=${battleSystem.opponentAttackIsHit}, will ${if (battleSystem.opponentAttackIsHit) "HIT" else "DODGE"}")
|
||||||
println("Phase 4: Full debug - attackPhase=${battleSystem.attackPhase}, isPlayerAttacking=${battleSystem.isPlayerAttacking}")
|
|
||||||
if (battleSystem.opponentAttackIsHit) {
|
if (battleSystem.opponentAttackIsHit) {
|
||||||
// Opponent attack hits player
|
// Enemy attack hits player
|
||||||
println("Opponent attack hits player at progress $progress")
|
println("Enemy attack hits player at progress $progress")
|
||||||
battleSystem.startPlayerHit()
|
battleSystem.startPlayerHit()
|
||||||
} else {
|
} else {
|
||||||
// Opponent attack misses, player dodges
|
// Enemy attack misses, player dodges
|
||||||
println("Opponent attack misses, player dodges at progress $progress")
|
println("Enemy attack misses, player dodges at progress $progress")
|
||||||
battleSystem.startPlayerDodge()
|
battleSystem.startPlayerDodge()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(16) // 60 FPS
|
delay(16) // 60 FPS
|
||||||
}
|
}
|
||||||
println("Phase 4 completed, applying damage and resetting")
|
println("Phase 3 completed, applying damage and resetting")
|
||||||
// Apply opponent's damage and reset
|
// Apply enemy's damage and reset
|
||||||
battleSystem.completeAttackAnimation(playerDamage = pendingPlayerDamage)
|
battleSystem.completeAttackAnimation(playerDamage = pendingPlayerDamage)
|
||||||
pendingPlayerDamage = 0f
|
pendingPlayerDamage = 0f
|
||||||
battleSystem.resetAttackState()
|
battleSystem.resetAttackState()
|
||||||
@ -314,7 +300,28 @@ fun BattleScreen(
|
|||||||
) {
|
) {
|
||||||
when (battleSystem.currentView) {
|
when (battleSystem.currentView) {
|
||||||
0 -> {
|
0 -> {
|
||||||
// Player view
|
// Middle screen - both Digimon
|
||||||
|
MiddleBattleView(
|
||||||
|
battleSystem = battleSystem,
|
||||||
|
stage = stage,
|
||||||
|
playerName = playerName,
|
||||||
|
opponentName = opponentName,
|
||||||
|
attackAnimationProgress = battleSystem.attackProgress,
|
||||||
|
onAttackClick = {
|
||||||
|
battleSystem.startPlayerAttack()
|
||||||
|
},
|
||||||
|
activeCharacter = activeCharacter,
|
||||||
|
opponentCharacter = opponentCharacter,
|
||||||
|
context = context,
|
||||||
|
onSetPendingDamage = { playerDamage, opponentDamage ->
|
||||||
|
pendingPlayerDamage = playerDamage
|
||||||
|
pendingOpponentDamage = opponentDamage
|
||||||
|
},
|
||||||
|
coroutineScope = coroutineScope
|
||||||
|
)
|
||||||
|
}
|
||||||
|
1 -> {
|
||||||
|
// Player screen - enemy attack
|
||||||
PlayerBattleView(
|
PlayerBattleView(
|
||||||
battleSystem = battleSystem,
|
battleSystem = battleSystem,
|
||||||
stage = stage,
|
stage = stage,
|
||||||
@ -333,9 +340,9 @@ fun BattleScreen(
|
|||||||
coroutineScope = coroutineScope
|
coroutineScope = coroutineScope
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
1 -> {
|
2 -> {
|
||||||
// Opponent view
|
// Enemy screen - player attack
|
||||||
OpponentBattleView(
|
EnemyBattleView(
|
||||||
battleSystem = battleSystem,
|
battleSystem = battleSystem,
|
||||||
stage = stage,
|
stage = stage,
|
||||||
opponentName = opponentName,
|
opponentName = opponentName,
|
||||||
@ -348,6 +355,394 @@ fun BattleScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MiddleBattleView(
|
||||||
|
battleSystem: ArenaBattleSystem,
|
||||||
|
stage: String,
|
||||||
|
playerName: String,
|
||||||
|
opponentName: String,
|
||||||
|
attackAnimationProgress: Float,
|
||||||
|
onAttackClick: () -> Unit,
|
||||||
|
activeCharacter: APIBattleCharacter?,
|
||||||
|
opponentCharacter: APIBattleCharacter?,
|
||||||
|
context: android.content.Context?,
|
||||||
|
onSetPendingDamage: (Float, Float) -> Unit,
|
||||||
|
coroutineScope: kotlinx.coroutines.CoroutineScope
|
||||||
|
) {
|
||||||
|
// Track previous character ID to detect transitions
|
||||||
|
var previousCharacterId by remember { mutableStateOf<String?>(null) }
|
||||||
|
var previousAttackPhase by remember { mutableStateOf<Int?>(null) }
|
||||||
|
var isTransitioning by remember { mutableStateOf(false) }
|
||||||
|
var lastApiResult by remember { mutableStateOf<com.github.nacabaro.vbhelper.battle.PVPDataModel?>(null) }
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
// Top section: Exit button, HP bars, and HP numbers
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
// Exit button at the top-right
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = { /* TODO: Add exit functionality */ },
|
||||||
|
modifier = Modifier.align(Alignment.TopEnd),
|
||||||
|
colors = ButtonDefaults.buttonColors(containerColor = Color.Red)
|
||||||
|
) {
|
||||||
|
Text("Exit", color = Color.White, fontSize = 14.sp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
// Debug display
|
||||||
|
if (lastApiResult != null) {
|
||||||
|
Text(
|
||||||
|
text = "Debug: state=${lastApiResult!!.state}, playerAttackHit=${lastApiResult!!.playerAttackHit}, opponentDamage=${lastApiResult!!.opponentAttackDamage}",
|
||||||
|
color = Color.Red,
|
||||||
|
fontSize = 10.sp
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enemy HP bar (top)
|
||||||
|
LinearProgressIndicator(
|
||||||
|
progress = battleSystem.opponentHP / (opponentCharacter?.baseHp?.toFloat() ?: 100f),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(10.dp),
|
||||||
|
color = Color.Red,
|
||||||
|
trackColor = Color.Gray
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enemy HP display numbers
|
||||||
|
Text(
|
||||||
|
text = "Enemy HP: ${battleSystem.opponentHP.toInt()}/${opponentCharacter?.baseHp ?: 100}",
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = Color.Black
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
// Player HP bar (bottom)
|
||||||
|
LinearProgressIndicator(
|
||||||
|
progress = battleSystem.playerHP / (activeCharacter?.baseHp?.toFloat() ?: 100f),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(10.dp),
|
||||||
|
color = Color.Green,
|
||||||
|
trackColor = Color.Gray
|
||||||
|
)
|
||||||
|
|
||||||
|
// Player HP display numbers
|
||||||
|
Text(
|
||||||
|
text = "HP: ${battleSystem.playerHP.toInt()}/${activeCharacter?.baseHp ?: 100}",
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = Color.Black
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Middle section: Both Digimon with horizontal line separator
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(16.dp),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
verticalArrangement = Arrangement.SpaceEvenly
|
||||||
|
) {
|
||||||
|
// Enemy Digimon (top half)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(1f),
|
||||||
|
contentAlignment = Alignment.CenterEnd
|
||||||
|
) {
|
||||||
|
// Determine animation type for enemy
|
||||||
|
val enemyAnimationType = when {
|
||||||
|
battleSystem.isOpponentDodging -> DigimonAnimationType.WALK
|
||||||
|
battleSystem.isOpponentHit -> DigimonAnimationType.SLEEP
|
||||||
|
battleSystem.attackPhase == 1 -> DigimonAnimationType.ATTACK // Both attacking
|
||||||
|
else -> DigimonAnimationType.IDLE
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate vertical offset for enemy dodge animation
|
||||||
|
val enemyVerticalOffset = if (battleSystem.isOpponentDodging) {
|
||||||
|
val dodgeHeight = 30.dp
|
||||||
|
val progress = battleSystem.opponentDodgeProgress
|
||||||
|
val direction = battleSystem.opponentDodgeDirection
|
||||||
|
|
||||||
|
if (direction > 0) {
|
||||||
|
-(progress * dodgeHeight.value).dp
|
||||||
|
} else {
|
||||||
|
-((1f - progress) * dodgeHeight.value).dp
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
0.dp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate hit effect for enemy
|
||||||
|
val enemyHitOffset = if (battleSystem.isOpponentHit) {
|
||||||
|
val shakeAmount = 5.dp
|
||||||
|
val progress = battleSystem.hitProgress
|
||||||
|
val shake = if (progress < 0.5f) progress * 2f else (1f - progress) * 2f
|
||||||
|
(shake * shakeAmount.value).dp
|
||||||
|
} else {
|
||||||
|
0.dp
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimatedSpriteImage(
|
||||||
|
characterId = opponentCharacter?.charaId ?: "dim011_mon01",
|
||||||
|
animationType = enemyAnimationType,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(80.dp)
|
||||||
|
.offset(
|
||||||
|
x = enemyHitOffset,
|
||||||
|
y = enemyVerticalOffset
|
||||||
|
),
|
||||||
|
contentScale = ContentScale.Fit,
|
||||||
|
reloadMappings = false
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enemy attack sprite (Phase 1 only)
|
||||||
|
if (battleSystem.attackPhase == 1) {
|
||||||
|
val xOffset = (attackAnimationProgress * 400 + 50).dp // Move right off screen
|
||||||
|
|
||||||
|
AttackSpriteImage(
|
||||||
|
characterId = opponentCharacter?.charaId ?: "dim011_mon01",
|
||||||
|
isLarge = true,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(60.dp)
|
||||||
|
.offset(
|
||||||
|
x = xOffset,
|
||||||
|
y = 0.dp
|
||||||
|
),
|
||||||
|
contentScale = ContentScale.Fit
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horizontal line separator
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(2.dp)
|
||||||
|
.background(Color.Black)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Player Digimon (bottom half)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(1f),
|
||||||
|
contentAlignment = Alignment.CenterStart
|
||||||
|
) {
|
||||||
|
// Determine animation type for player
|
||||||
|
val playerAnimationType = when {
|
||||||
|
battleSystem.isPlayerDodging -> DigimonAnimationType.WALK
|
||||||
|
battleSystem.isPlayerHit -> DigimonAnimationType.SLEEP
|
||||||
|
battleSystem.attackPhase == 1 -> DigimonAnimationType.ATTACK // Both attacking
|
||||||
|
else -> DigimonAnimationType.IDLE
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate vertical offset for player dodge animation
|
||||||
|
val playerVerticalOffset = if (battleSystem.isPlayerDodging) {
|
||||||
|
val dodgeHeight = 30.dp
|
||||||
|
val progress = battleSystem.playerDodgeProgress
|
||||||
|
val direction = battleSystem.playerDodgeDirection
|
||||||
|
|
||||||
|
if (direction > 0) {
|
||||||
|
-(progress * dodgeHeight.value).dp
|
||||||
|
} else {
|
||||||
|
-((1f - progress) * dodgeHeight.value).dp
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
0.dp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate hit effect for player
|
||||||
|
val playerHitOffset = if (battleSystem.isPlayerHit) {
|
||||||
|
val shakeAmount = 5.dp
|
||||||
|
val progress = battleSystem.hitProgress
|
||||||
|
val shake = if (progress < 0.5f) progress * 2f else (1f - progress) * 2f
|
||||||
|
(shake * shakeAmount.value).dp
|
||||||
|
} else {
|
||||||
|
0.dp
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimatedSpriteImage(
|
||||||
|
characterId = activeCharacter?.charaId ?: "dim011_mon01",
|
||||||
|
animationType = playerAnimationType,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(80.dp)
|
||||||
|
.scale(-1f, 1f) // Flip player Digimon horizontally
|
||||||
|
.offset(
|
||||||
|
x = playerHitOffset,
|
||||||
|
y = playerVerticalOffset
|
||||||
|
),
|
||||||
|
contentScale = ContentScale.Fit,
|
||||||
|
reloadMappings = false
|
||||||
|
)
|
||||||
|
|
||||||
|
// Player attack sprite (Phase 1 only)
|
||||||
|
if (battleSystem.attackPhase == 1) {
|
||||||
|
val xOffset = (-attackAnimationProgress * 400 - 50).dp // Move left off screen
|
||||||
|
|
||||||
|
AttackSpriteImage(
|
||||||
|
characterId = activeCharacter?.charaId ?: "dim011_mon01",
|
||||||
|
isLarge = true,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(60.dp)
|
||||||
|
.offset(
|
||||||
|
x = xOffset,
|
||||||
|
y = 0.dp
|
||||||
|
)
|
||||||
|
.scale(-1f, 1f), // Flip attack sprite
|
||||||
|
contentScale = ContentScale.Fit
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom section: Critical bar and Attack button
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
|
.align(Alignment.BottomCenter),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
// Critical bar
|
||||||
|
LinearProgressIndicator(
|
||||||
|
progress = battleSystem.critBarProgress / 100f,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(10.dp),
|
||||||
|
color = Color.Yellow,
|
||||||
|
trackColor = Color.Gray
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
// Attack button
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
println("Attack button clicked!")
|
||||||
|
|
||||||
|
// Get crit bar progress as float (0.0f to 100.0f)
|
||||||
|
val critBarProgressFloat = battleSystem.critBarProgress.toFloat()
|
||||||
|
|
||||||
|
// Determine player and opponent stages
|
||||||
|
val playerStage = when (activeCharacter?.stage) {
|
||||||
|
0 -> 0 // rookie
|
||||||
|
1 -> 1 // champion
|
||||||
|
2 -> 2 // ultimate
|
||||||
|
3 -> 3 // mega
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
val opponentStage = when (opponentCharacter?.stage) {
|
||||||
|
0 -> 0 // rookie
|
||||||
|
1 -> 1 // champion
|
||||||
|
2 -> 2 // ultimate
|
||||||
|
3 -> 3 // mega
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send API call with all parameters
|
||||||
|
context?.let { ctx ->
|
||||||
|
// Start both attacks simultaneously
|
||||||
|
battleSystem.startPlayerAttack()
|
||||||
|
|
||||||
|
RetrofitHelper().getPVPWinner(
|
||||||
|
ctx,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
activeCharacter?.name ?: "Player",
|
||||||
|
playerStage,
|
||||||
|
opponentStage,
|
||||||
|
opponentCharacter?.name ?: "Opponent",
|
||||||
|
opponentStage
|
||||||
|
) { apiResult ->
|
||||||
|
// Handle API response here
|
||||||
|
println("API Result: $apiResult")
|
||||||
|
lastApiResult = apiResult // Store for debug display
|
||||||
|
|
||||||
|
// Update HP based on API response
|
||||||
|
when (apiResult.state) {
|
||||||
|
1 -> {
|
||||||
|
// Match is still ongoing - update HP and continue
|
||||||
|
println("Round ${apiResult.currentRound}: Player HP=${apiResult.playerHP}, Opponent HP=${apiResult.opponentHP}")
|
||||||
|
|
||||||
|
// Set pending damage based on API result
|
||||||
|
if (apiResult.playerAttackDamage > 0) {
|
||||||
|
// Player attack hit - enemy takes damage at end of player animation
|
||||||
|
println("Player attack hit! Enemy will take ${apiResult.playerAttackDamage} damage")
|
||||||
|
onSetPendingDamage(0f, apiResult.playerAttackDamage.toFloat()) // Opponent takes damage
|
||||||
|
battleSystem.setAttackHitState(true)
|
||||||
|
} else {
|
||||||
|
// Player attack missed - enemy counter-attacks
|
||||||
|
println("Player attack missed! Enemy counter-attacks")
|
||||||
|
battleSystem.setAttackHitState(false)
|
||||||
|
// Set up counter-attack - determine if it hits based on API result
|
||||||
|
val counterAttackHits = apiResult.opponentAttackDamage > 0
|
||||||
|
println("Setting up counter-attack: counterAttackHits=$counterAttackHits, opponentAttackDamage=${apiResult.opponentAttackDamage}")
|
||||||
|
println("Full API response: status=${apiResult.status}, state=${apiResult.state}, playerAttackHit=${apiResult.playerAttackHit}, playerAttackDamage=${apiResult.playerAttackDamage}, opponentAttackDamage=${apiResult.opponentAttackDamage}, playerHP=${apiResult.playerHP}, opponentHP=${apiResult.opponentHP}")
|
||||||
|
println("DEBUG: Using playerAttackDamage > 0 instead of playerAttackHit for hit detection")
|
||||||
|
|
||||||
|
// Use opponentAttackDamage to determine counter-attack hit
|
||||||
|
val finalCounterAttackHits = counterAttackHits
|
||||||
|
println("Using opponentAttackDamage > 0 for counter-attack: $finalCounterAttackHits")
|
||||||
|
|
||||||
|
if (finalCounterAttackHits) {
|
||||||
|
println("Counter-attack hits! Player takes ${apiResult.opponentAttackDamage} damage")
|
||||||
|
onSetPendingDamage(apiResult.opponentAttackDamage.toFloat(), 0f) // Player takes damage
|
||||||
|
} else {
|
||||||
|
println("Counter-attack misses! Player dodges")
|
||||||
|
onSetPendingDamage(0f, 0f) // No damage
|
||||||
|
}
|
||||||
|
battleSystem.setupCounterAttack(finalCounterAttackHits)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 -> {
|
||||||
|
// Match is over - transition to results screen
|
||||||
|
println("Match is over! Winner: ${apiResult.winner}")
|
||||||
|
battleSystem.updateHPFromAPI(apiResult.playerHP.toFloat(), apiResult.opponentHP.toFloat())
|
||||||
|
onAttackClick() // This will transition to battle-results screen
|
||||||
|
}
|
||||||
|
-1 -> {
|
||||||
|
// Error occurred
|
||||||
|
println("API Error: ${apiResult.status}")
|
||||||
|
battleSystem.resetAttackState()
|
||||||
|
battleSystem.enableAttackButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enabled = battleSystem.isAttackButtonEnabled,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(50.dp),
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = Color.Red,
|
||||||
|
disabledContainerColor = Color.Gray
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(8.dp)
|
||||||
|
) {
|
||||||
|
Text("Attack", color = Color.White, fontSize = 18.sp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PlayerBattleView(
|
fun PlayerBattleView(
|
||||||
battleSystem: ArenaBattleSystem,
|
battleSystem: ArenaBattleSystem,
|
||||||
@ -488,24 +883,21 @@ fun PlayerBattleView(
|
|||||||
|
|
||||||
// Attack sprite visibility and positioning based on attack phase
|
// Attack sprite visibility and positioning based on attack phase
|
||||||
val shouldShowAttack = when (battleSystem.attackPhase) {
|
val shouldShowAttack = when (battleSystem.attackPhase) {
|
||||||
1 -> true // Player attack on player screen
|
1 -> false // Both attacks from middle screen
|
||||||
2 -> true // Player attack on opponent screen
|
2 -> false // Player attack on enemy screen
|
||||||
3 -> false // Opponent attack on opponent screen
|
3 -> true // Enemy attack on player screen
|
||||||
4 -> true // Opponent attack on player screen
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldShowAttack) {
|
if (shouldShowAttack) {
|
||||||
val xOffset = when (battleSystem.attackPhase) {
|
val xOffset = when (battleSystem.attackPhase) {
|
||||||
1 -> (attackAnimationProgress * 400 + 50).dp // Player attack on player screen - start and end more to the right
|
3 -> (-attackAnimationProgress * 400 + 350).dp // Enemy attack on player screen - start more to the right
|
||||||
2 -> (attackAnimationProgress * 400 - 200).dp // Player attack on opponent screen
|
|
||||||
4 -> (-attackAnimationProgress * 400 + 350).dp // Opponent attack on player screen - start more to the right
|
|
||||||
else -> 0.dp
|
else -> 0.dp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use opponent character ID for Phase 4 (opponent attack)
|
// Use opponent character ID for Phase 3 (enemy attack)
|
||||||
val characterId = when (battleSystem.attackPhase) {
|
val characterId = when (battleSystem.attackPhase) {
|
||||||
4 -> opponent?.charaId ?: "dim011_mon01" // Use opponent's character ID
|
3 -> opponent?.charaId ?: "dim011_mon01" // Use opponent's character ID
|
||||||
else -> activeCharacter?.charaId ?: "dim011_mon01" // Use player's character ID
|
else -> activeCharacter?.charaId ?: "dim011_mon01" // Use player's character ID
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,7 +926,7 @@ fun PlayerBattleView(
|
|||||||
x = xOffset,
|
x = xOffset,
|
||||||
y = 0.dp
|
y = 0.dp
|
||||||
)
|
)
|
||||||
.scale(if (battleSystem.attackPhase == 4) 1f else -1f, 1f), // Don't flip opponent attacks
|
.scale(if (battleSystem.attackPhase == 3) 1f else -1f, 1f), // Don't flip enemy attacks
|
||||||
contentScale = ContentScale.Fit
|
contentScale = ContentScale.Fit
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -675,7 +1067,7 @@ fun PlayerBattleView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun OpponentBattleView(
|
fun EnemyBattleView(
|
||||||
battleSystem: ArenaBattleSystem,
|
battleSystem: ArenaBattleSystem,
|
||||||
stage: String,
|
stage: String,
|
||||||
opponentName: String,
|
opponentName: String,
|
||||||
@ -715,14 +1107,14 @@ fun OpponentBattleView(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Middle section: Opponent Digimon
|
// Middle section: Enemy Digimon
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
// Opponent Digimon
|
// Enemy Digimon
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@ -733,10 +1125,7 @@ fun OpponentBattleView(
|
|||||||
val animationType = when {
|
val animationType = when {
|
||||||
battleSystem.isOpponentDodging -> DigimonAnimationType.WALK // Use walk animation for dodge
|
battleSystem.isOpponentDodging -> DigimonAnimationType.WALK // Use walk animation for dodge
|
||||||
battleSystem.isOpponentHit -> DigimonAnimationType.SLEEP // Use sleep animation for hit effect (injured sprite)
|
battleSystem.isOpponentHit -> DigimonAnimationType.SLEEP // Use sleep animation for hit effect (injured sprite)
|
||||||
battleSystem.attackPhase == 1 -> DigimonAnimationType.IDLE // Player attack on player screen
|
battleSystem.attackPhase == 2 -> DigimonAnimationType.IDLE // Player attack on enemy screen
|
||||||
battleSystem.attackPhase == 2 -> DigimonAnimationType.IDLE // Player attack on opponent screen
|
|
||||||
battleSystem.attackPhase == 3 -> DigimonAnimationType.ATTACK // Opponent attack on opponent screen
|
|
||||||
battleSystem.attackPhase == 4 -> DigimonAnimationType.ATTACK // Opponent attack on player screen
|
|
||||||
else -> DigimonAnimationType.IDLE
|
else -> DigimonAnimationType.IDLE
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -783,26 +1172,15 @@ fun OpponentBattleView(
|
|||||||
|
|
||||||
// Attack sprite visibility and positioning based on attack phase
|
// Attack sprite visibility and positioning based on attack phase
|
||||||
val shouldShowAttack = when (battleSystem.attackPhase) {
|
val shouldShowAttack = when (battleSystem.attackPhase) {
|
||||||
1 -> false // Player attack on player screen
|
2 -> true // Player attack on enemy screen
|
||||||
2 -> true // Player attack on opponent screen
|
|
||||||
3 -> true // Opponent attack on opponent screen
|
|
||||||
4 -> false // Opponent attack on player screen
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldShowAttack) {
|
if (shouldShowAttack) {
|
||||||
val xOffset = when (battleSystem.attackPhase) {
|
val xOffset = (attackAnimationProgress * 400 - 350).dp // Player attack on enemy screen - start more to the left
|
||||||
2 -> (attackAnimationProgress * 400 - 350).dp // Player attack on opponent screen - start more to the left
|
|
||||||
3 -> (-attackAnimationProgress * 400 + -50).dp // Opponent attack on opponent screen - start more to the left
|
|
||||||
else -> 0.dp
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use correct character ID based on attack phase
|
// Use player's character ID for player attack
|
||||||
val characterId = when (battleSystem.attackPhase) {
|
val characterId = playerCharacter?.charaId ?: "dim011_mon01"
|
||||||
2 -> playerCharacter?.charaId ?: "dim011_mon01" // Use player's character ID for player attack
|
|
||||||
3 -> activeCharacter?.charaId ?: "dim011_mon01" // Use opponent's character ID for opponent attack
|
|
||||||
else -> "dim011_mon01"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle sprite transition
|
// Handle sprite transition
|
||||||
LaunchedEffect(characterId, battleSystem.attackPhase) {
|
LaunchedEffect(characterId, battleSystem.attackPhase) {
|
||||||
@ -817,7 +1195,7 @@ fun OpponentBattleView(
|
|||||||
previousAttackPhase = battleSystem.attackPhase
|
previousAttackPhase = battleSystem.attackPhase
|
||||||
}
|
}
|
||||||
|
|
||||||
println("OpponentBattleView - Attack sprite - Phase: ${battleSystem.attackPhase}, Progress: $attackAnimationProgress, X Offset: $xOffset, CurrentView: ${battleSystem.currentView}")
|
println("EnemyBattleView - Attack sprite - Phase: ${battleSystem.attackPhase}, Progress: $attackAnimationProgress, X Offset: $xOffset, CurrentView: ${battleSystem.currentView}")
|
||||||
|
|
||||||
if (!isTransitioning) {
|
if (!isTransitioning) {
|
||||||
AttackSpriteImage(
|
AttackSpriteImage(
|
||||||
@ -829,7 +1207,7 @@ fun OpponentBattleView(
|
|||||||
x = xOffset,
|
x = xOffset,
|
||||||
y = 0.dp
|
y = 0.dp
|
||||||
)
|
)
|
||||||
.scale(if (battleSystem.attackPhase == 2) -1f else 1f, 1f), // Flip player attacks only
|
.scale(-1f, 1f), // Flip player attacks
|
||||||
contentScale = ContentScale.Fit
|
contentScale = ContentScale.Fit
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1201,9 +1579,12 @@ fun BattlesScreen() {
|
|||||||
|
|
||||||
Scaffold (
|
Scaffold (
|
||||||
topBar = {
|
topBar = {
|
||||||
TopBanner(
|
// Only show TopBanner when not in battle mode
|
||||||
text = "Online battles"
|
if (currentView != "battle-main" && currentView != "battle-results") {
|
||||||
)
|
TopBanner(
|
||||||
|
text = "Online battles"
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
) { contentPadding ->
|
) { contentPadding ->
|
||||||
Column(
|
Column(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user