Skip to content

Commit ac116fa

Browse files
committed
docs: deduplicate content and fix broken links in documentation book
1 parent 55e47d5 commit ac116fa

6 files changed

Lines changed: 333 additions & 172 deletions

File tree

docs/SUMMARY.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
- [Core Rules Overview](mtg_core/index.md)
88
- [Turn Structure](mtg_core/turn_structure/index.md)
9+
- [Priority System](mtg_core/turn_structure/priority.md)
910
- [Zones](mtg_core/zones/index.md)
1011
- [Stack](mtg_core/stack/index.md)
1112
- [State-Based Actions](mtg_core/state_actions/index.md)
@@ -162,7 +163,7 @@
162163
- [End-to-End Testing](testing/end_to_end_testing.md)
163164
- [Visual Testing](testing/visual_testing.md)
164165
- [Performance Testing](testing/performance_testing.md)
165-
- [Snapshot Testing](core_systems/snapshot/testing.md)
166+
- [Snapshot Testing](testing/snapshot_testing.md)
166167
- [CI/CD Pipeline](testing/ci_cd_pipeline.md)
167168
- [Development Integration](testing/development_integration.md)
168169

@@ -192,6 +193,7 @@
192193
- [Commander-Specific Rules](mtg_rules/commander_specific.md)
193194
- [Turn Structure](mtg_rules/turn_structure.md)
194195
- [Stack](mtg_rules/stack.md)
196+
- [Zones](mtg_rules/zones.md)
195197
- [Combat](mtg_rules/combat.md)
196198
- [State-Based Actions](mtg_rules/state_based_actions.md)
197199
- [Targeting](mtg_rules/targeting.md)
Lines changed: 131 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -1,210 +1,183 @@
11
# Priority System
22

3-
This document details the implementation of the priority system in Rummage, which determines which player can take actions at any given time during a game of Magic: The Gathering.
3+
This document describes the implementation of Magic: The Gathering's priority system in Rummage.
44

55
## Overview
66

7-
The priority system is a fundamental part of Magic: The Gathering's turn structure. It determines when players can cast spells, activate abilities, and take other game actions. Understanding and correctly implementing the priority system is essential for proper game flow.
7+
The priority system determines when players can take actions during a game of Magic: The Gathering. It's a fundamental component that controls the game's flow and ensures players have appropriate opportunities to act.
88

99
## Core Priority Rules
1010

11-
The basic rules of priority in MTG are:
11+
In Magic: The Gathering, priority follows these key rules:
1212

13-
1. The active player receives priority first in each step and phase
14-
2. When a player has priority, they may:
15-
- Cast a spell
16-
- Activate an ability
17-
- Take a special action
18-
- Pass priority
19-
3. When a player passes priority, the next player in turn order receives priority
20-
4. When all players pass priority in succession:
21-
- If the stack is empty, the current step or phase ends
22-
- If the stack has objects, the top object on the stack resolves, then the active player gets priority again
13+
1. The active player receives priority first in each step and phase.
14+
2. When a player has priority, they may cast spells, activate abilities, or pass.
15+
3. When a player passes priority, the next player in turn order receives priority.
16+
4. When all players pass priority in succession with an empty stack, the current step or phase ends.
17+
5. When all players pass priority in succession with objects on the stack, the top object on the stack resolves, then the active player receives priority.
2318

24-
## Implementation
19+
## Implementation Details
2520

26-
In Rummage, the priority system is implemented as follows:
21+
The priority system in Rummage is implemented through a combination of resources and systems:
2722

2823
```rust
29-
#[derive(Resource)]
30-
pub struct PrioritySystem {
31-
// The player who currently has priority
24+
#[derive(Resource, Debug, Clone)]
25+
pub struct PriorityManager {
3226
pub current_player: Entity,
33-
34-
// Set of players who have passed priority in succession
35-
pub passed_players: HashSet<Entity>,
36-
37-
// Whether the priority system is currently active
38-
pub active: bool,
39-
}
40-
41-
#[derive(Event)]
42-
pub struct PriorityEvent {
43-
pub player: Entity,
44-
pub action: PriorityAction,
27+
pub all_passed: bool,
28+
pub stack_empty_when_passed: bool,
29+
pub last_to_act: Option<Entity>,
30+
pub player_order: Vec<Entity>,
4531
}
4632

47-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48-
pub enum PriorityAction {
49-
Receive, // Player receives priority
50-
Pass, // Player passes priority
51-
TakeAction, // Player takes an action (cast spell, activate ability, etc.)
52-
}
53-
```
54-
55-
## Priority Flow
56-
57-
The flow of priority follows this pattern:
58-
59-
1. **Phase/Step Start**: At the beginning of each phase or step, the active player receives priority
60-
2. **Action Taken**: If a player takes an action, all players who have passed are reset, and priority returns to the active player
61-
3. **Passing**: When a player passes, the next player in turn order receives priority
62-
4. **Resolution**: When all players pass in succession, either the top of the stack resolves or the phase/step ends
63-
64-
### Priority System Implementation
65-
66-
```rust
67-
pub fn handle_priority_system(
68-
mut commands: Commands,
69-
mut priority: ResMut<PrioritySystem>,
70-
mut priority_events: EventReader<PriorityEvent>,
71-
game_state: Res<GameState>,
72-
stack: Res<Stack>,
73-
) {
74-
for event in priority_events.iter() {
75-
match event.action {
76-
PriorityAction::Pass => {
77-
// Record that this player passed
78-
priority.passed_players.insert(event.player);
33+
impl PriorityManager {
34+
pub fn new(starting_player: Entity, player_order: Vec<Entity>) -> Self {
35+
PriorityManager {
36+
current_player: starting_player,
37+
all_passed: false,
38+
stack_empty_when_passed: true,
39+
last_to_act: None,
40+
player_order,
41+
}
42+
}
43+
44+
pub fn pass_priority(&mut self, stack: &Stack) -> PriorityResult {
45+
let current_index = self.player_order
46+
.iter()
47+
.position(|&p| p == self.current_player)
48+
.expect("Current player not found in player order");
49+
50+
let next_index = (current_index + 1) % self.player_order.len();
51+
let next_player = self.player_order[next_index];
52+
53+
// Record if this is the last player to act
54+
if let Some(last_player) = self.last_to_act {
55+
if last_player == self.current_player {
56+
// All players have passed priority
57+
self.all_passed = true;
58+
self.stack_empty_when_passed = stack.is_empty();
7959

80-
// Check if all players have passed
81-
if priority.passed_players.len() == game_state.players.len() {
82-
// All players have passed
83-
if !stack.items.is_empty() {
84-
// Resolve top of stack
85-
commands.add(resolve_stack_command());
86-
87-
// Reset passed players
88-
priority.passed_players.clear();
89-
90-
// Active player gets priority again
91-
priority.current_player = game_state.active_player;
92-
} else {
93-
// Stack is empty, end current phase/step
94-
commands.add(advance_phase_command());
95-
96-
// Priority will be set by the phase transition system
97-
priority.active = false;
98-
}
60+
if stack.is_empty() {
61+
return PriorityResult::EndPhase;
9962
} else {
100-
// Not all players have passed, give priority to next player
101-
let next_player = get_next_player(event.player, &game_state);
102-
priority.current_player = next_player;
63+
return PriorityResult::ResolveStack;
10364
}
104-
},
105-
PriorityAction::TakeAction => {
106-
// Player took an action, reset passed players
107-
priority.passed_players.clear();
108-
109-
// Active player gets priority again
110-
priority.current_player = game_state.active_player;
111-
},
112-
PriorityAction::Receive => {
113-
// Player receives priority (usually at beginning of phase/step)
114-
priority.current_player = event.player;
115-
priority.active = true;
11665
}
66+
} else {
67+
// First player to pass
68+
self.last_to_act = Some(self.current_player);
11769
}
70+
71+
// Pass to next player
72+
self.current_player = next_player;
73+
PriorityResult::Continue
74+
}
75+
76+
pub fn reset_for_new_phase(&mut self, active_player: Entity) {
77+
self.current_player = active_player;
78+
self.all_passed = false;
79+
self.stack_empty_when_passed = true;
80+
self.last_to_act = None;
81+
}
82+
83+
pub fn reset_after_stack_resolution(&mut self, active_player: Entity) {
84+
self.current_player = active_player;
85+
self.all_passed = false;
86+
self.last_to_act = None;
11887
}
11988
}
120-
```
121-
122-
## Special Priority Rules
123-
124-
### No Priority Phases
12589

126-
Some steps do not normally grant players priority:
127-
128-
- **Untap Step**: No player receives priority during this step
129-
- **Cleanup Step**: No player receives priority unless a triggered ability triggers
130-
131-
```rust
132-
pub fn should_grant_priority(phase: Phase, step: Step) -> bool {
133-
match (phase, step) {
134-
(Phase::Beginning, Step::Untap) => false,
135-
(Phase::Ending, Step::Cleanup) => false,
136-
_ => true,
137-
}
90+
#[derive(Debug, Clone, PartialEq, Eq)]
91+
pub enum PriorityResult {
92+
Continue, // Continue with priority passing
93+
EndPhase, // End the current phase
94+
ResolveStack, // Resolve the top of the stack
13895
}
13996
```
14097

141-
### Triggered Abilities During No-Priority Steps
98+
## Priority Systems
99+
100+
The following systems manage priority in the game:
142101

143-
If a triggered ability triggers during a step where players don't normally receive priority, players will receive priority:
102+
1. **Initialize Priority System**: Sets up priority at the beginning of a phase
103+
2. **Handle Priority Actions System**: Processes actions from the player with priority
104+
3. **Pass Priority System**: Handles the passing of priority between players
105+
4. **Stack Resolution System**: Resolves stack objects when all players pass
144106

145107
```rust
146-
pub fn handle_cleanup_triggers(
108+
pub fn handle_priority_actions(
147109
mut commands: Commands,
148-
mut priority: ResMut<PrioritySystem>,
110+
priority: Res<PriorityManager>,
111+
mut action_events: EventReader<PlayerAction>,
112+
mut pass_events: EventWriter<PassPriorityEvent>,
113+
mut stack: ResMut<Stack>,
149114
game_state: Res<GameState>,
150-
triggers: Res<TriggeredAbilities>,
151115
) {
152-
// If we're in cleanup step and there are triggers
153-
if game_state.current_phase == Phase::Ending &&
154-
game_state.current_step == Step::Cleanup &&
155-
!triggers.pending.is_empty() {
116+
for action in action_events.read() {
117+
if action.player != priority.current_player {
118+
// Only the player with priority can act
119+
continue;
120+
}
156121

157-
// Grant priority to active player
158-
priority.active = true;
159-
priority.current_player = game_state.active_player;
160-
priority.passed_players.clear();
122+
match &action.action_type {
123+
ActionType::CastSpell { card, targets } => {
124+
// Handle casting a spell
125+
// ...
126+
},
127+
ActionType::ActivateAbility { source, ability_id, targets } => {
128+
// Handle activating an ability
129+
// ...
130+
},
131+
ActionType::PlayLand { card } => {
132+
// Handle playing a land
133+
// ...
134+
},
135+
ActionType::Pass => {
136+
// Player passes priority
137+
pass_events.send(PassPriorityEvent {
138+
player: action.player,
139+
phase: game_state.current_phase.clone(),
140+
});
141+
},
142+
// Other action types...
143+
}
161144
}
162145
}
163146
```
164147

165-
## APNAP Order
148+
## Special Phase Rules
166149

167-
When multiple players would receive priority simultaneously (such as for triggered abilities), they are processed in APNAP (Active Player, Non-Active Player) order:
150+
Priority is handled differently in certain phases and steps:
151+
152+
1. **Untap Step**: No player receives priority
153+
2. **Cleanup Step**: No player receives priority unless a triggered ability triggers
154+
3. **Combat Damage Step**: Players receive priority after combat damage is dealt
168155

169156
```rust
170-
pub fn get_players_in_apnap_order(game_state: &GameState) -> Vec<Entity> {
171-
let mut players = Vec::new();
172-
173-
// Start with active player
174-
let mut current = game_state.active_player;
175-
players.push(current);
176-
177-
// Add remaining players in turn order
178-
for _ in 1..game_state.players.len() {
179-
current = get_next_player(current, game_state);
180-
players.push(current);
157+
pub fn should_receive_priority(phase: &Phase) -> bool {
158+
match phase {
159+
Phase::Beginning(BeginningStep::Untap) => false,
160+
Phase::Ending(EndingStep::Cleanup) => false,
161+
_ => true,
181162
}
182-
183-
players
184163
}
185164
```
186165

187166
## Integration with Other Systems
188167

189-
The priority system integrates with:
190-
191-
1. **Turn Structure**: Phase and step transitions affect priority
192-
2. **Stack System**: Stack resolution and priority are tightly coupled
193-
3. **Action System**: Player actions affect priority flow
194-
4. **UI System**: The UI must indicate which player has priority
168+
The priority system integrates closely with several other game systems:
195169

196-
## Implementation Status
170+
- **Turn Structure**: Controls when phases begin and end based on priority passing
171+
- **Stack**: Determines when objects on the stack resolve
172+
- **Triggered Abilities**: Manages when triggered abilities are put on the stack
173+
- **State-Based Actions**: Checks whenever a player would receive priority
197174

198-
The priority system implementation currently:
175+
## Format-Specific Extensions
199176

200-
- ✅ Handles basic priority passing
201-
- ✅ Integrates with stack resolution
202-
- ✅ Implements APNAP order
203-
- ✅ Handles special steps without priority
204-
- ✅ Supports triggered abilities during cleanup
205-
- 🔄 Implementing special actions that don't use the stack
206-
- 🔄 Handling priority with split second spells
177+
For Commander-specific priority implementation details, see [Commander Priority System](../../formats/commander/turns_and_phases/priority_system.md).
207178

208-
---
179+
## Related Documentation
209180

210-
Next: [Turn Phases](phases.md)
181+
- [Turn Structure](index.md): How turns are structured
182+
- [Stack](../stack/index.md): How the stack handles spell and ability resolution
183+
- [Commander Priority System](../../formats/commander/turns_and_phases/priority_system.md): Commander-specific priority rules

0 commit comments

Comments
 (0)