diff --git a/constants/event_flags.asm b/constants/event_flags.asm
index e150e4903..89d945450 100644
--- a/constants/event_flags.asm
+++ b/constants/event_flags.asm
@@ -2,6 +2,7 @@
const_def
+
;; The first eight flags are reset upon reloading the map
const EVENT_TEMPORARY_UNTIL_MAP_RELOAD_1
const EVENT_TEMPORARY_UNTIL_MAP_RELOAD_2
@@ -17,6 +18,7 @@ const_value = const_value + 8 - (const_value % 8)
endc
EVENT_TEMPORARY_UNTIL_MAP_RELOAD_FLAGS_END EQU const_value
+
;; The next flags are reset upon entering a new level (for e.g. trainers)
EVENT_LEVEL_SCOPED_FLAGS_START EQU EVENT_TEMPORARY_UNTIL_MAP_RELOAD_FLAGS_END
@@ -46,8 +48,39 @@ const_value = const_value + 8 - (const_value % 8)
endc
EVENT_LEVEL_SCOPED_FLAGS_END EQU const_value
+
+;; The next flags are reset upon taking a step (for e.g. talker)
+EVENT_TURN_SCOPED_FLAGS_START EQU EVENT_LEVEL_SCOPED_FLAGS_END
+
+ const EVENT_TURN_SCOPED_1
+ const EVENT_TURN_SCOPED_2
+ const EVENT_TURN_SCOPED_3
+ const EVENT_TURN_SCOPED_4
+ const EVENT_TURN_SCOPED_5
+ const EVENT_TURN_SCOPED_6
+ const EVENT_TURN_SCOPED_7
+ const EVENT_TURN_SCOPED_8
+ const EVENT_TURN_SCOPED_9
+ const EVENT_TURN_SCOPED_10
+ const EVENT_TURN_SCOPED_11
+ const EVENT_TURN_SCOPED_12
+ const EVENT_TURN_SCOPED_13
+ const EVENT_TURN_SCOPED_14
+ const EVENT_TURN_SCOPED_15
+ const EVENT_TURN_SCOPED_16
+ const EVENT_TURN_SCOPED_17
+ const EVENT_TURN_SCOPED_18
+ const EVENT_TURN_SCOPED_19
+ const EVENT_TURN_SCOPED_20
+
+if (const_value % 8) != 0
+const_value = const_value + 8 - (const_value % 8)
+endc
+EVENT_TURN_SCOPED_FLAGS_END EQU const_value
+
+
;; The remaining flags are only reset explicitly
-EVENT_REGULAR_FLAGS_START EQU EVENT_LEVEL_SCOPED_FLAGS_END
+EVENT_REGULAR_FLAGS_START EQU EVENT_TURN_SCOPED_FLAGS_END
const EVENT_INITIALIZED_EVENTS
diff --git a/constants/trainer_data_constants.asm b/constants/trainer_data_constants.asm
index dda4fd451..639b2d61a 100644
--- a/constants/trainer_data_constants.asm
+++ b/constants/trainer_data_constants.asm
@@ -47,10 +47,12 @@ DEF CONTEXT_USE EQU 1 << CONTEXT_USE_F
const TRAINERTYPE_ITEM_MOVES
; talker events (from talker macro and high bit of wTempTalkerType)
-DEF TALKER_OPTIONAL EQU %0
-DEF TALKER_MANDATORY EQU %1
+DEF TALKEREVENTTYPE_MASK EQU %10000000
+DEF TALKEREVENTTYPE_OPTIONAL EQU %0
+DEF TALKEREVENTTYPE_MANDATORY EQU %1
; talker types (from talker macro and low seven bits of wTempTalkerType)
+DEF TALKERTYPE_MASK EQU %01111111
const_def
const TALKERTYPE_TEXT
const TALKERTYPE_MODAL_TEXT
diff --git a/docs/event_commands.md b/docs/event_commands.md
index e6aa4c229..29cc2520f 100644
--- a/docs/event_commands.md
+++ b/docs/event_commands.md
@@ -342,7 +342,7 @@ If item_id
= `USE_SCRIPT_VAR`, then it uses `[hScriptVar]` i
## `$62`: trainertext text_id
-## `$63`: trainerflagaction action
+## `$63`: trainerortalkerflagaction action
## `$64`: winlosstext win_text_pointer, loss_text_pointer
diff --git a/engine/board/menu.asm b/engine/board/menu.asm
index 411c4c9c0..e20a88b5a 100755
--- a/engine/board/menu.asm
+++ b/engine/board/menu.asm
@@ -20,12 +20,22 @@ BoardMenuScript::
; save after opentext to reanchor map first
; save before processing variables like wCurTurn due to BoardMenuScript reentry after game reset
farcall AutoSaveGameInOverworld
+; reset turn-scoped variables (wDieRoll, wSpacesLeft) and update wCurTurn
ld hl, wTurnData
ld bc, wTurnDataEnd - wTurnData
xor a
call ByteFill
ld hl, wCurTurn
inc [hl]
+; reset turn-scoped event flags
+ ld hl, wEventFlags + EVENT_LEVEL_SCOPED_FLAGS_START / 8
+ ld c, (EVENT_LEVEL_SCOPED_FLAGS_END / 8) - (EVENT_LEVEL_SCOPED_FLAGS_START / 8)
+ xor a
+.loop
+ ld [hli], a
+ dec c
+ jr nz, .loop
+; load the data for the current space to wCurSpaceStruct
jp LoadCurSpaceData
.Die:
diff --git a/engine/events/trainer_scripts.asm b/engine/events/trainer_scripts.asm
index 030130fc5..9f2b16248 100644
--- a/engine/events/trainer_scripts.asm
+++ b/engine/events/trainer_scripts.asm
@@ -1,6 +1,6 @@
TalkToTrainerScript::
faceplayer
- trainerflagaction CHECK_FLAG
+ trainerortalkerflagaction CHECK_FLAG
iftrue AlreadyBeatenTrainerScript
loadtemptrainer
encountermusic
@@ -25,7 +25,7 @@ StartBattleWithMapTrainerScript:
loadtemptrainer
startbattle
reloadmapafterbattle
- trainerflagaction SET_FLAG
+ trainerortalkerflagaction SET_FLAG
loadmem wRunningTrainerBattleScript, -1
AlreadyBeatenTrainerScript:
@@ -34,8 +34,30 @@ AlreadyBeatenTrainerScript:
SeenByTalkerScript::
waitsfx ; wait for any pending space-related sfx
showemote EMOTE_TALK, LAST_TALKED, 20
+ callasm .TalkOrSkipTalker
+ iffalse .skipped
callasm TrainerOrTalkerWalkToPlayer
applymovementlasttalked wMovementBuffer
writeobjectxy LAST_TALKED
faceobject PLAYER, LAST_TALKED
+.skipped
end
+
+.TalkOrSkipTalker:
+ ld a, [wTempTalkerType]
+ and %1
+ cp TALKEREVENTTYPE_MANDATORY
+ jr z, .skip
+ call WaitButton
+ call PlayClickSFX
+ call WaitSFX
+ ldh a, [hJoyPressed]
+ bit A_BUTTON_F, a
+ jr z, .skip ; jump if b was pressed
+ ld a, TRUE
+ jr .done
+.skip
+ xor a ; FALSE
+.done
+ ld [hScriptVar], a
+ ret
diff --git a/engine/overworld/events.asm b/engine/overworld/events.asm
index b047f326c..c854b1078 100644
--- a/engine/overworld/events.asm
+++ b/engine/overworld/events.asm
@@ -459,7 +459,7 @@ CheckTrainerOrTalkerEvent:
call CheckTrainerBattleOrTalkerPrompt
jr nc, .nope
- ld a, [wTrainerOrTalkerIsTalker]
+ ld a, [wSeenTrainerOrTalkerIsTalker]
and a ; cp FALSE
ld a, PLAYEREVENT_SEENBYTRAINER
jr z, .done
diff --git a/engine/overworld/scripting.asm b/engine/overworld/scripting.asm
index bada8759e..18cc56d10 100644
--- a/engine/overworld/scripting.asm
+++ b/engine/overworld/scripting.asm
@@ -163,7 +163,7 @@ ScriptCommandTable:
dw Script_reloadmapafterbattle ; 60
dw Script_catchtutorial ; 61
dw Script_trainertext ; 62
- dw Script_trainerflagaction ; 63
+ dw Script_trainerortalkerflagaction ; 63
dw Script_winlosstext ; 64
dw Script_scripttalkafter ; 65
dw Script_endifjustbattled ; 66
@@ -685,10 +685,10 @@ Script_scripttalkafter:
ld b, a
jp ScriptJump
-Script_trainerflagaction:
+Script_trainerortalkerflagaction:
xor a
ldh [hScriptVar], a
- ld hl, wTempTrainerEventFlag
+ ld hl, wTempTrainerEventFlag ; wTempTalkerEventFlag
ld e, [hl]
inc hl
ld d, [hl]
diff --git a/home/trainers.asm b/home/trainers.asm
index bbfe25ed9..536444cdc 100644
--- a/home/trainers.asm
+++ b/home/trainers.asm
@@ -39,14 +39,14 @@ _CheckTrainerBattleOrTalkerPrompt::
jr z, .is_trainer
cp OBJECTTYPE_TALKER
jr nz, .next
-; also set wTrainerOrTalkerIsTalker accordingly (flag is only relevant if there's actually an event)
+; also set wSeenTrainerOrTalkerIsTalker accordingly (flag is only relevant if there's actually an event)
;.is_talker
ld a, TRUE
- ld [wTrainerOrTalkerIsTalker], a
+ ld [wSeenTrainerOrTalkerIsTalker], a
jr .go
.is_trainer
xor a ; FALSE
- ld [wTrainerOrTalkerIsTalker], a
+ ld [wSeenTrainerOrTalkerIsTalker], a
.go
; Is visible on the map
@@ -68,11 +68,31 @@ _CheckTrainerBattleOrTalkerPrompt::
cp b
jr c, .next
- ld a, [wTrainerOrTalkerIsTalker]
- and a ; TRUE?
- jr z, .trainer_battle
+; And hasn't already been beaten if it's a trainer, or talked to if it's a talker,
+; according to the scope of the flag of the trainer or talker event.
+ push bc
+ push de
+ ld hl, MAPOBJECT_SCRIPT_POINTER
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld e, [hl]
+ inc hl
+ ld d, [hl] ; de = wTempTrainerEventFlag = wTempTalkerEventFlag
+ ld b, CHECK_FLAG
+ call EventFlagAction
+ ld a, c
+ pop de
+ pop bc
+ and a
+ jr nz, .next
-;.talker_prompt
+ ld a, [wSeenTrainerOrTalkerIsTalker]
+ and a ; cp FALSE
+ jr z, .prepare_trainer_battle
+
+;.prepare_talker_prompt
pop de
pop af
ldh [hLastTalked], a
@@ -98,26 +118,6 @@ _CheckTrainerBattleOrTalkerPrompt::
scf
ret
-.trainer_battle
-; And hasn't already been beaten if it's a trainer
- push bc
- push de
- ld hl, MAPOBJECT_SCRIPT_POINTER
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld e, [hl]
- inc hl
- ld d, [hl]
- ld b, CHECK_FLAG
- call EventFlagAction
- ld a, c
- pop de
- pop bc
- and a
- jr z, .startbattle
-
.next
pop de
ld hl, MAPOBJECT_LENGTH
@@ -132,7 +132,7 @@ _CheckTrainerBattleOrTalkerPrompt::
xor a
ret
-.startbattle
+.prepare_trainer_battle
pop de
pop af
ldh [hLastTalked], a
diff --git a/macros/legacy.asm b/macros/legacy.asm
index 696cfece3..49abe93d9 100644
--- a/macros/legacy.asm
+++ b/macros/legacy.asm
@@ -206,7 +206,7 @@ DEF battlecheck EQUS "randomwildmon"
DEF loadtrainerdata EQUS "loadtemptrainer"
DEF loadpokedata EQUS "loadwildmon"
DEF returnafterbattle EQUS "reloadmapafterbattle"
-DEF trainerstatus EQUS "trainerflagaction"
+DEF trainerstatus EQUS "trainerortalkerflagaction"
DEF talkaftercancel EQUS "endifjustbattled"
DEF talkaftercheck EQUS "checkjustbattled"
DEF playrammusic EQUS "encountermusic"
diff --git a/macros/scripts/events.asm b/macros/scripts/events.asm
index 71f52e94f..adf4e8442 100644
--- a/macros/scripts/events.asm
+++ b/macros/scripts/events.asm
@@ -632,9 +632,9 @@ MACRO trainertext
db \1 ; text_id
ENDM
- const trainerflagaction_command ; $63
-MACRO trainerflagaction
- db trainerflagaction_command
+ const trainerortalkerflagaction_command ; $63
+MACRO trainerortalkerflagaction
+ db trainerortalkerflagaction_command
db \1 ; action
ENDM
diff --git a/maps/DebugLevel5_Map1.asm b/maps/DebugLevel5_Map1.asm
index f50a1ee47..196623344 100755
--- a/maps/DebugLevel5_Map1.asm
+++ b/maps/DebugLevel5_Map1.asm
@@ -28,7 +28,7 @@ DebugLevel5_Map1_MapEvents:
.DebugLevel5_Map1TrainerYoungsterMikey2:
trainer YOUNGSTER, MIKEY, EVENT_LEVEL_SCOPED_2, .YoungsterMikeySeenText, .YoungsterMikeyBeatenText, 0, .Script
-; talker EVENT_STEP_SCOPED_*, OPTIONAL/MANDATORY | TEXT/MODAL_TEXT/SCRIPT, .Data
+; talker EVENT_TURN_SCOPED_*, OPTIONAL/MANDATORY | TEXT/MODAL_TEXT/SCRIPT, .Data
; .Data: ; Text
; db .Text
; .Data: ; Modal text
diff --git a/ram/wram.asm b/ram/wram.asm
index 619423540..fb1f6b28f 100644
--- a/ram/wram.asm
+++ b/ram/wram.asm
@@ -1551,7 +1551,7 @@ SECTION UNION "Miscellaneous WRAM 1", WRAMX
UNION
; trainer and talker data
-wTrainerOrTalkerIsTalker:: db ; TRUE means talker; FALSE means trainer
+wSeenTrainerOrTalkerIsTalker:: db ; TRUE means talker; FALSE means trainer
wSeenTrainerOrTalkerBank:: db
wSeenTrainerOrTalkerDistance:: db
wSeenTrainerOrTalkerDirection:: db