1use crate::{
2 comp::{
3 BuffKind, ability,
4 inventory::{
5 InventorySortOrder,
6 item::tool::ToolKind,
7 slot::{EquipSlot, InvSlotId, Slot},
8 },
9 invite::{InviteKind, InviteResponse},
10 },
11 mounting::VolumePos,
12 rtsim,
13 trade::{TradeAction, TradeId},
14 uid::Uid,
15 util::Dir,
16};
17use serde::{Deserialize, Serialize};
18use specs::Component;
19use std::{collections::BTreeMap, num::NonZeroU32};
20use vek::*;
21
22#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
23pub enum InventoryEvent {
24 Pickup(Uid),
25 Swap(InvSlotId, InvSlotId),
26 SplitSwap(InvSlotId, InvSlotId),
27 Drop(InvSlotId),
28 SplitDrop(InvSlotId),
29 Sort(InventorySortOrder),
30 CraftRecipe {
31 craft_event: CraftEvent,
32 craft_sprite: Option<VolumePos>,
33 },
34 OverflowMove(usize, InvSlotId),
35 OverflowDrop(usize),
36 OverflowSplitDrop(usize),
37}
38
39#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
40pub enum InventoryAction {
41 Swap(EquipSlot, Slot),
42 Drop(EquipSlot),
43 Use(Slot),
44 Sort(InventorySortOrder),
45 Collect(Vec3<i32>),
46 ToggleSpriteLight(VolumePos, bool),
49}
50
51#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
52pub enum InventoryManip {
53 Pickup(Uid),
54 Collect {
55 sprite_pos: Vec3<i32>,
56 required_item: Option<(InvSlotId, bool)>,
58 },
59 Use(Slot),
60 Swap(Slot, Slot),
61 SplitSwap(Slot, Slot),
62 Drop(Slot),
63 SplitDrop(Slot),
64 Sort(InventorySortOrder),
65 CraftRecipe {
66 craft_event: CraftEvent,
67 craft_sprite: Option<VolumePos>,
68 },
69 SwapEquippedWeapons,
70 Delete(InvSlotId, NonZeroU32),
71}
72
73impl From<InventoryEvent> for InventoryManip {
74 fn from(inv_event: InventoryEvent) -> Self {
75 match inv_event {
76 InventoryEvent::Pickup(pickup) => Self::Pickup(pickup),
77 InventoryEvent::Swap(inv1, inv2) => {
78 Self::Swap(Slot::Inventory(inv1), Slot::Inventory(inv2))
79 },
80 InventoryEvent::SplitSwap(inv1, inv2) => {
81 Self::SplitSwap(Slot::Inventory(inv1), Slot::Inventory(inv2))
82 },
83 InventoryEvent::Drop(inv) => Self::Drop(Slot::Inventory(inv)),
84 InventoryEvent::SplitDrop(inv) => Self::SplitDrop(Slot::Inventory(inv)),
85 InventoryEvent::Sort(sort_order) => Self::Sort(sort_order),
86 InventoryEvent::CraftRecipe {
87 craft_event,
88 craft_sprite,
89 } => Self::CraftRecipe {
90 craft_event,
91 craft_sprite,
92 },
93 InventoryEvent::OverflowMove(o, inv) => {
94 Self::Swap(Slot::Overflow(o), Slot::Inventory(inv))
95 },
96 InventoryEvent::OverflowDrop(o) => Self::Drop(Slot::Overflow(o)),
97 InventoryEvent::OverflowSplitDrop(o) => Self::SplitDrop(Slot::Overflow(o)),
98 }
99 }
100}
101
102#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
103pub enum CraftEvent {
104 Simple {
105 recipe: String,
106 slots: Vec<(u32, InvSlotId)>,
107 amount: u32,
108 },
109 Salvage(InvSlotId),
110 ModularWeapon {
112 primary_component: InvSlotId,
113 secondary_component: InvSlotId,
114 },
115 ModularWeaponPrimaryComponent {
117 toolkind: ToolKind,
118 material: InvSlotId,
119 modifier: Option<InvSlotId>,
120 slots: Vec<(u32, InvSlotId)>,
121 },
122 Repair(Slot),
123}
124
125#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
126pub enum GroupManip {
127 Leave,
128 Kick(Uid),
129 AssignLeader(Uid),
130}
131
132#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, strum::EnumString)]
133pub enum UtteranceKind {
134 Calm,
135 Angry,
136 Surprised,
137 Hurt,
138 Greeting,
139 Scream,
140 Ambush,
141 }
145
146#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
147pub enum ControlEvent {
148 EnableLantern,
150 DisableLantern,
151 Interact(Uid),
152 InitiateInvite(Uid, InviteKind),
153 InviteResponse(InviteResponse),
154 PerformTradeAction(TradeId, TradeAction),
155 Mount(Uid),
156 MountVolume(VolumePos),
157 Unmount,
158 SetPetStay(Uid, bool),
159 InventoryEvent(InventoryEvent),
160 GroupManip(GroupManip),
161 RemoveBuff(BuffKind),
162 LeaveStance,
163 GiveUp,
164 Respawn,
165 Utterance(UtteranceKind),
166 ChangeAbility {
167 slot: usize,
168 auxiliary_key: ability::AuxiliaryKey,
169 new_ability: ability::AuxiliaryAbility,
170 },
171 ActivatePortal(Uid),
172 InteractWith {
173 target: Uid,
174 kind: crate::interaction::InteractionKind,
175 },
176 Dialogue(Uid, rtsim::Dialogue),
177}
178
179#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
180pub enum ControlAction {
181 SwapEquippedWeapons,
182 InventoryAction(InventoryAction),
183 Wield,
184 GlideWield,
185 Unwield,
186 Sit,
187 Crawl,
188 Dance,
189 Sneak,
190 Stand,
191 Talk(Option<Uid>),
192 StartInput {
193 input: InputKind,
194 target_entity: Option<Uid>,
195 select_pos: Option<Vec3<f32>>,
197 },
198 CancelInput {
199 input: InputKind,
200 },
201}
202
203impl ControlAction {
204 pub fn basic_input(input: InputKind) -> Self {
205 ControlAction::StartInput {
206 input,
207 target_entity: None,
208 select_pos: None,
209 }
210 }
211}
212
213#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Ord, PartialOrd)]
214#[repr(u32)]
215pub enum InputKind {
216 Primary = 0,
217 Secondary = 1,
218 Block = 2,
219 Ability(usize) = 3,
220 Roll = 4,
221 Jump = 5,
222 Fly = 6,
223 WallJump = 7,
224}
225
226impl InputKind {
227 pub fn is_ability(self) -> bool {
228 matches!(
229 self,
230 Self::Primary | Self::Secondary | Self::Ability(_) | Self::Block
231 )
232 }
233}
234
235impl From<InputKind> for Option<ability::AbilityInput> {
236 fn from(input: InputKind) -> Option<ability::AbilityInput> {
237 use ability::AbilityInput;
238 match input {
239 InputKind::Block => Some(AbilityInput::Guard),
240 InputKind::Primary => Some(AbilityInput::Primary),
241 InputKind::Secondary => Some(AbilityInput::Secondary),
242 InputKind::Roll => Some(AbilityInput::Movement),
243 InputKind::Ability(index) => Some(AbilityInput::Auxiliary(index)),
244 InputKind::Jump | InputKind::WallJump | InputKind::Fly => None,
245 }
246 }
247}
248
249#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
250pub struct InputAttr {
251 pub select_pos: Option<Vec3<f32>>,
252 pub target_entity: Option<Uid>,
253}
254
255#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
256pub struct ControllerInputs {
257 pub move_dir: Vec2<f32>,
258 pub move_z: f32, pub look_dir: Dir,
261 pub break_block_pos: Option<Vec3<f32>>,
262 pub strafing: bool,
266}
267
268#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
269pub struct Controller {
270 pub inputs: ControllerInputs,
271 pub queued_inputs: BTreeMap<InputKind, InputAttr>,
272 pub events: Vec<ControlEvent>,
274 pub actions: Vec<ControlAction>,
275}
276
277impl ControllerInputs {
278 pub fn sanitize(&mut self) {
280 self.move_dir = if self.move_dir.map(|e| e.is_finite()).reduce_and() {
281 self.move_dir / self.move_dir.magnitude().max(1.0)
282 } else {
283 Vec2::zero()
284 };
285 self.move_z = if self.move_z.is_finite() {
286 self.move_z.clamped(-1.0, 1.0)
287 } else {
288 0.0
289 };
290 }
291
292 pub fn update_with_new(&mut self, new: Self) {
294 self.move_dir = new.move_dir;
295 self.move_z = new.move_z;
296 self.look_dir = new.look_dir;
297 self.break_block_pos = new.break_block_pos;
298 }
299}
300
301impl Controller {
302 pub fn reset(&mut self) {
304 self.inputs = Default::default();
305 self.queued_inputs = Default::default();
306 }
307
308 pub fn clear_events(&mut self) { self.events.clear(); }
309
310 pub fn push_event(&mut self, event: ControlEvent) { self.events.push(event); }
311
312 pub fn push_utterance(&mut self, utterance: UtteranceKind) {
313 self.push_event(ControlEvent::Utterance(utterance));
314 }
315
316 pub fn push_invite_response(&mut self, invite_response: InviteResponse) {
317 self.push_event(ControlEvent::InviteResponse(invite_response));
318 }
319
320 pub fn push_initiate_invite(&mut self, uid: Uid, invite: InviteKind) {
321 self.push_event(ControlEvent::InitiateInvite(uid, invite));
322 }
323
324 pub fn push_action(&mut self, action: ControlAction) { self.actions.push(action); }
325
326 pub fn push_basic_input(&mut self, input: InputKind) {
327 self.push_action(ControlAction::basic_input(input));
328 }
329
330 pub fn push_cancel_input(&mut self, input: InputKind) {
331 self.push_action(ControlAction::CancelInput { input });
332 }
333}
334
335impl Component for Controller {
336 type Storage = specs::VecStorage<Self>;
337}