Skip to content

Commit b27a43f

Browse files
committed
housekeeping
1 parent dde6c03 commit b27a43f

5 files changed

Lines changed: 74 additions & 70 deletions

File tree

src/main/kotlin/dev/robothanzo/werewolf/game/model/ActionDefinitionId.kt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,5 @@ enum class ActionDefinitionId(val actionName: String) {
5454
fun fromString(id: String): ActionDefinitionId? {
5555
return entries.find { it.toString() == id }
5656
}
57-
58-
/**
59-
* Check if a string ID is valid
60-
*/
61-
fun isValid(id: String): Boolean {
62-
return entries.any { it.toString() == id }
63-
}
6457
}
6558
}

src/main/kotlin/dev/robothanzo/werewolf/game/model/GameStateData.kt

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,6 @@ data class RoleActionInstance(
5252
var targetPromptId: Long? = null // Discord message ID for target selection prompt
5353
)
5454

55-
data class ActionSubmissionStatus(
56-
val playerId: Int,
57-
val role: String,
58-
val status: ActionStatus, // PENDING, ACTING, SUBMITTED, SKIPPED
59-
val actionType: String? = null, // The action chosen (e.g., "KILL", "HEAL", "CHECK")
60-
val targetId: String? = null,
61-
val submittedAt: Long? = null
62-
)
63-
6455
/**
6556
* Group action state for coordinated actions like wolf kills
6657
*/

src/main/kotlin/dev/robothanzo/werewolf/game/roles/actions/DreamWeaverAction.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ class DreamWeaverLinkAction : BaseRoleAction(
1818
): ActionExecutionResult {
1919
if (action.targets.isEmpty()) return accumulatedState
2020
val targetId = action.targets.firstOrNull() ?: return accumulatedState
21-
val target = session.getPlayer(targetId) ?: return accumulatedState
22-
21+
2322
// Record the target for this day
2423
session.stateData.dreamWeaverTargets[session.day] = targetId
2524

src/test/kotlin/dev/robothanzo/werewolf/game/DreamWeaverNightmareTest.kt

Lines changed: 71 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,28 @@ import dev.robothanzo.werewolf.WerewolfApplication
44
import dev.robothanzo.werewolf.database.documents.Player
55
import dev.robothanzo.werewolf.database.documents.Session
66
import dev.robothanzo.werewolf.game.model.*
7-
import dev.robothanzo.werewolf.game.roles.PredefinedRoles
87
import dev.robothanzo.werewolf.game.roles.RoleRegistry
98
import dev.robothanzo.werewolf.game.roles.actions.ActionExecutionResult
109
import dev.robothanzo.werewolf.game.roles.actions.DeathResolutionAction
1110
import dev.robothanzo.werewolf.game.roles.actions.RoleActionExecutor
1211
import dev.robothanzo.werewolf.service.GameSessionService
13-
import org.junit.jupiter.api.Assertions.*
12+
import org.junit.jupiter.api.Assertions.assertFalse
13+
import org.junit.jupiter.api.Assertions.assertTrue
1414
import org.junit.jupiter.api.BeforeEach
1515
import org.junit.jupiter.api.Test
1616
import org.junit.jupiter.api.extension.ExtendWith
1717
import org.mockito.Mock
18-
import org.mockito.Mockito.`when`
1918
import org.mockito.junit.jupiter.MockitoExtension
20-
import java.util.*
2119

2220
@ExtendWith(MockitoExtension::class)
2321
class DreamWeaverNightmareTest {
2422

2523
private lateinit var session: Session
2624
private lateinit var roleRegistry: RoleRegistry
27-
25+
2826
@Mock
2927
private lateinit var roleActionExecutor: RoleActionExecutor
30-
28+
3129
@Mock
3230
private lateinit var gameSessionService: GameSessionService
3331

@@ -36,26 +34,26 @@ class DreamWeaverNightmareTest {
3634
session = Session()
3735
session.stateData = GameStateData()
3836
session.day = 1
39-
37+
4038
// Setup static mocks
4139
WerewolfApplication.gameSessionService = gameSessionService
42-
40+
4341
// Setup Players
4442
val dw = Player(id = 1).apply { roles.add("攝夢人") }
4543
val nm = Player(id = 2).apply { roles.add("夢魘") } // Nightmare is wolf team but role logic handles it
46-
nm.roles.add("狼人") // Add generic wolf role just in case or depend on Nightmare being wolf?
44+
nm.roles.add("狼人") // Add generic wolf role just in case or depend on Nightmare being wolf?
4745
// Nightmare should be a wolf role. PredefinedRoles? GameData?
4846
// In Player.isWolf, it checks: role.contains("狼") || role == "石像鬼" || role == "血月使者" || role == "惡靈騎士"
4947
// Nightmare is new. Does Player.isWolf know about it?
5048
// Player.kt: fun isWolf(role: String) { return role.contains("狼") || ... }
5149
// "夢魘" does not contain "狼". I should update Player.kt OR just add "狼人" to roles for test simplicity.
52-
// Let's check Player.kt isWolf again.
50+
// Let's check Player.kt isWolf again.
5351
// It has hardcoded list. I need to update it for Nightmare too?
5452
// Or just add "狼人" as secondary role in test to make it simple.
55-
53+
5654
val villager = Player(id = 3).apply { roles.add("平民") }
5755
val wolf = Player(id = 4).apply { roles.add("狼人") }
58-
56+
5957
session.addPlayer(dw)
6058
session.addPlayer(nm)
6159
session.addPlayer(villager)
@@ -66,132 +64,155 @@ class DreamWeaverNightmareTest {
6664
fun testWolfFearBlocksCamp() {
6765
// Nightmare (ID 2) fears the Wolf (ID 4)
6866
session.stateData.nightmareFearTargets[1] = 4
69-
67+
7068
// This is the logic used in NightStep to filter wolves
7169
val fearedId = session.stateData.nightmareFearTargets[session.day]
7270
val isAnyWolfFeared = fearedId != null && session.getPlayer(fearedId)?.wolf == true
73-
71+
7472
assertTrue(isAnyWolfFeared, "Wolf should be detected as feared if teammate is nightmared")
75-
73+
7674
// The list of werewolves allowed to vote should be empty in NightStep if this is true
77-
val werewolves = if (isAnyWolfFeared) emptyList<Int>() else session.players.values.filter { it.wolf }.map { it.id }
75+
val werewolves =
76+
if (isAnyWolfFeared) emptyList<Int>() else session.players.values.filter { it.wolf }.map { it.id }
7877
assertTrue(werewolves.isEmpty(), "Werewolf voting list should be empty if a wolf is nightmared")
7978
}
8079

8180
@Test
8281
fun testDreamWeaverImmunity() {
8382
// Day 1: Dream Weaver links Villager
8483
session.stateData.dreamWeaverTargets[1] = 3
85-
84+
8685
// Wolf kills Villager
8786
val executionResult = ActionExecutionResult()
8887
executionResult.deaths.getOrPut(DeathCause.WEREWOLF) { mutableListOf() }.add(3)
89-
88+
9089
// Run Death Resolution
9190
val resolutionAction = DeathResolutionAction()
92-
val result = resolutionAction.execute(session, RoleActionInstance(0, "", null, mutableListOf(), ActionSubmissionSource.SYSTEM, ActionStatus.PROCESSED), executionResult)
93-
91+
val result = resolutionAction.execute(
92+
session,
93+
RoleActionInstance(0, "", null, mutableListOf(), ActionSubmissionSource.SYSTEM, ActionStatus.PROCESSED),
94+
executionResult
95+
)
96+
9497
// Villager should NOT be in deaths (Immunity)
95-
assertFalse(result.deaths[DeathCause.WEREWOLF]?.contains(3) == true, "Villager should be immune to Wolf kill due to Dream Weaver")
98+
assertFalse(
99+
result.deaths[DeathCause.WEREWOLF]?.contains(3) == true,
100+
"Villager should be immune to Wolf kill due to Dream Weaver"
101+
)
96102
}
97103

98104
@Test
99105
fun testDreamWeaverConsecutiveDeath() {
100106
// Day 1: Dream Weaver links Villager (done in history)
101107
session.stateData.dreamWeaverTargets[1] = 3
102-
108+
103109
// Day 2
104110
session.day = 2
105111
// Dream Weaver links Villager AGAIN
106112
session.stateData.dreamWeaverTargets[2] = 3
107-
113+
108114
val executionResult = ActionExecutionResult()
109-
115+
110116
// Run Death Resolution
111117
val resolutionAction = DeathResolutionAction()
112-
val result = resolutionAction.execute(session, RoleActionInstance(0, "", null, mutableListOf(), ActionSubmissionSource.SYSTEM, ActionStatus.PROCESSED), executionResult)
113-
118+
val result = resolutionAction.execute(
119+
session,
120+
RoleActionInstance(0, "", null, mutableListOf(), ActionSubmissionSource.SYSTEM, ActionStatus.PROCESSED),
121+
executionResult
122+
)
123+
114124
// Villager should die from Dream Weaver
115-
assertTrue(result.deaths[DeathCause.DREAM_WEAVER]?.contains(3) == true, "Villager should die due to consecutive Dream Weaver link")
125+
assertTrue(
126+
result.deaths[DeathCause.DREAM_WEAVER]?.contains(3) == true,
127+
"Villager should die due to consecutive Dream Weaver link"
128+
)
116129
}
117130

118131
@Test
119132
fun testDreamWeaverLinkedDeath() {
120133
// Day 1: Dream Weaver links Villager
121134
session.stateData.dreamWeaverTargets[1] = 3
122-
135+
123136
// Dream Weaver dies (e.g. Wolf kill)
124137
val executionResult = ActionExecutionResult()
125138
executionResult.deaths.getOrPut(DeathCause.WEREWOLF) { mutableListOf() }.add(1) // 1 is DW
126-
139+
127140
// Run Death Resolution
128141
val resolutionAction = DeathResolutionAction()
129-
val result = resolutionAction.execute(session, RoleActionInstance(0, "", null, mutableListOf(), ActionSubmissionSource.SYSTEM, ActionStatus.PROCESSED), executionResult)
130-
142+
val result = resolutionAction.execute(
143+
session,
144+
RoleActionInstance(0, "", null, mutableListOf(), ActionSubmissionSource.SYSTEM, ActionStatus.PROCESSED),
145+
executionResult
146+
)
147+
131148
// Dream Weaver dies
132149
assertTrue(result.deaths[DeathCause.WEREWOLF]?.contains(1) == true)
133150
// Villager should also die (Linked Death)
134-
assertTrue(result.deaths[DeathCause.DREAM_WEAVER]?.contains(3) == true, "Villager should die because Dream Weaver died")
151+
assertTrue(
152+
result.deaths[DeathCause.DREAM_WEAVER]?.contains(3) == true,
153+
"Villager should die because Dream Weaver died"
154+
)
135155
}
136156

137157
@Test
138158
fun testNightmareFearRestriction() {
139159
// Day 1 night: Nightmare fears Villager (ID 3)
140160
session.stateData.nightmareFearTargets[1] = 3
141161
session.currentState = "NIGHT_PHASE"
142-
162+
143163
// Villager tries to use skill? (e.g. if Villager was Seer)
144164
// Here we test SessionExtensions.isActionAvailable manually or mock logic
145165
// But since I modified SessionExtensions, I can test the logic directly if I can invoke extension method.
146166
// Assuming test can call extension method:
147-
167+
148168
// Let's pretend Villager is Seer for this test
149169
val seer = Player(id = 5).apply { roles.add("預言家") }
150170
session.addPlayer(seer)
151-
171+
152172
// Fear Seer
153173
session.stateData.nightmareFearTargets[1] = 5
154-
174+
155175
// Create a dummy Seer Action
156-
val actionId = ActionDefinitionId.SEER_CHECK
157-
176+
ActionDefinitionId.SEER_CHECK
177+
158178
// To test isActionAvailable, we need RoleRegistry mock
159179
// Instead of full registry, let's just inspect the logic we added:
160180
// if (fearedId == playerId && isNightPhase) return false
161-
162-
// I will reproduce the logic here to verify my understanding/implementation or use reflection if needed,
181+
182+
// I will reproduce the logic here to verify my understanding/implementation or use reflection if needed,
163183
// but ideally I should call the actual method.
164-
// Since I cannot easily compile extensions in this test snippet without full context setup,
184+
// Since I cannot easily compile extensions in this test snippet without full context setup,
165185
// I will trust the logic `if (fearedId == playerId && isNightPhase) return false` which is simple.
166-
186+
167187
// Instead, let's test Werewolf Kill restriction
168188
// Nightmare fears Wolf (ID 4)
169189
session.stateData.nightmareFearTargets[1] = 4
170-
190+
171191
// Helper to simulate Wolf Kill execution
172192
val killActionInstance = RoleActionInstance(
173-
actor = 4,
174-
actorRole = "WEREWOLF",
193+
actor = 4,
194+
actorRole = "WEREWOLF",
175195
actionDefinitionId = ActionDefinitionId.WEREWOLF_KILL,
176196
targets = mutableListOf(3), // Try to kill Villager
177197
submittedBy = ActionSubmissionSource.PLAYER,
178198
status = ActionStatus.SUBMITTED
179199
)
180-
200+
181201
// Use a real WerewolfKillAction (or anonymous subclass if needed)
182202
// I need to instantiate WerewolfKillAction. Since it's a class, I can just new it.
183203
val wolfKillAction = dev.robothanzo.werewolf.game.roles.actions.WerewolfKillAction()
184-
204+
185205
val executionResult = ActionExecutionResult()
186-
206+
187207
val result = wolfKillAction.execute(session, killActionInstance, executionResult)
188-
208+
189209
// Result should NOT have death because wolf teammate is feared
190210
assertFalse(result.deaths.containsKey(DeathCause.WEREWOLF), "Wolf kill should fail if teammate is feared")
191-
211+
192212
// Verify log is added (mock session addLog?)
193213
// assert(session.logs.isNotEmpty()) // Mocking logs might be hard with just data class
194214
}
215+
195216
@Test
196217
fun testNightmareActionIsCompulsory() {
197218
val action = dev.robothanzo.werewolf.game.roles.actions.NightmareFearAction()

src/test/kotlin/dev/robothanzo/werewolf/service/impl/ActionUIServiceImplTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ class ActionUIServiceImplTest {
157157
)
158158

159159
// Mock role to return actions
160-
val mockRole = mock<dev.robothanzo.werewolf.game.model.Role>()
160+
val mockRole = mock<Role>()
161161
whenever(mockRole.getActions()).thenReturn(listOf(mandatoryRoleAction))
162162
whenever(roleRegistry.getRole("狼弟")).thenReturn(mockRole)
163163
whenever(roleRegistry.getAction(ActionDefinitionId.WOLF_YOUNGER_BROTHER_EXTRA_KILL)).thenReturn(
@@ -228,7 +228,7 @@ class ActionUIServiceImplTest {
228228
targets = { _, _, _ -> listOf(targetId) }
229229
)
230230

231-
val mockRole = mock<dev.robothanzo.werewolf.game.model.Role>()
231+
val mockRole = mock<Role>()
232232
whenever(mockRole.getActions()).thenReturn(listOf(mandatoryRoleAction))
233233
whenever(roleRegistry.getRole("預言家")).thenReturn(mockRole)
234234
whenever(roleRegistry.getAction(ActionDefinitionId.SEER_CHECK)).thenReturn(mandatoryRoleAction)

0 commit comments

Comments
 (0)