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 {
123 item: Slot,
124 slots: Vec<(u32, InvSlotId)>,
125 },
126}
127
128#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
129pub enum GroupManip {
130 Leave,
131 Kick(Uid),
132 AssignLeader(Uid),
133}
134
135#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, strum::EnumString)]
136pub enum UtteranceKind {
137 Calm,
138 Angry,
139 Surprised,
140 Hurt,
141 Greeting,
142 Scream,
143 Ambush,
144 }
148
149#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
150pub enum ControlEvent {
151 EnableLantern,
153 DisableLantern,
154 Interact(Uid),
155 InitiateInvite(Uid, InviteKind),
156 InviteResponse(InviteResponse),
157 PerformTradeAction(TradeId, TradeAction),
158 Mount(Uid),
159 MountVolume(VolumePos),
160 Unmount,
161 SetPetStay(Uid, bool),
162 InventoryEvent(InventoryEvent),
163 GroupManip(GroupManip),
164 RemoveBuff(BuffKind),
165 LeaveStance,
166 GiveUp,
167 Respawn,
168 Utterance(UtteranceKind),
169 ChangeAbility {
170 slot: usize,
171 auxiliary_key: ability::AuxiliaryKey,
172 new_ability: ability::AuxiliaryAbility,
173 },
174 ActivatePortal(Uid),
175 InteractWith {
176 target: Uid,
177 kind: crate::interaction::InteractionKind,
178 },
179 Dialogue(Uid, rtsim::Dialogue),
180}
181
182#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
183pub enum ControlAction {
184 SwapEquippedWeapons,
185 InventoryAction(InventoryAction),
186 Wield,
187 GlideWield,
188 Unwield,
189 Sit,
190 Crawl,
191 Dance,
192 Sneak,
193 Stand,
194 Talk(Option<Uid>),
195 StartInput {
196 input: InputKind,
197 target_entity: Option<Uid>,
198 select_pos: Option<Vec3<f32>>,
200 },
201 CancelInput {
202 input: InputKind,
203 },
204}
205
206impl ControlAction {
207 pub fn basic_input(input: InputKind) -> Self {
208 ControlAction::StartInput {
209 input,
210 target_entity: None,
211 select_pos: None,
212 }
213 }
214}
215
216#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Ord, PartialOrd)]
217#[repr(u32)]
218pub enum InputKind {
219 Primary = 0,
220 Secondary = 1,
221 Block = 2,
222 Ability(usize) = 3,
223 Roll = 4,
224 Jump = 5,
225 Fly = 6,
226 WallJump = 7,
227}
228
229impl InputKind {
230 pub fn is_ability(self) -> bool {
231 matches!(
232 self,
233 Self::Primary | Self::Secondary | Self::Ability(_) | Self::Block
234 )
235 }
236}
237
238impl From<InputKind> for Option<ability::AbilityInput> {
239 fn from(input: InputKind) -> Option<ability::AbilityInput> {
240 use ability::AbilityInput;
241 match input {
242 InputKind::Block => Some(AbilityInput::Guard),
243 InputKind::Primary => Some(AbilityInput::Primary),
244 InputKind::Secondary => Some(AbilityInput::Secondary),
245 InputKind::Roll => Some(AbilityInput::Movement),
246 InputKind::Ability(index) => Some(AbilityInput::Auxiliary(index)),
247 InputKind::Jump | InputKind::WallJump | InputKind::Fly => None,
248 }
249 }
250}
251
252#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
253pub struct InputAttr {
254 pub select_pos: Option<Vec3<f32>>,
255 pub target_entity: Option<Uid>,
256}
257
258#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
259pub struct ControllerInputs {
260 pub move_dir: Vec2<f32>,
261 pub move_z: f32, pub look_dir: Dir,
264 pub break_block_pos: Option<Vec3<f32>>,
265 pub strafing: bool,
269}
270
271#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
272pub struct Controller {
273 pub inputs: ControllerInputs,
274 pub queued_inputs: BTreeMap<InputKind, InputAttr>,
275 pub events: Vec<ControlEvent>,
277 pub actions: Vec<ControlAction>,
278}
279
280impl ControllerInputs {
281 pub fn sanitize(&mut self) {
283 self.move_dir = if self.move_dir.map(|e| e.is_finite()).reduce_and() {
284 self.move_dir / self.move_dir.magnitude().max(1.0)
285 } else {
286 Vec2::zero()
287 };
288 self.move_z = if self.move_z.is_finite() {
289 self.move_z.clamped(-1.0, 1.0)
290 } else {
291 0.0
292 };
293 }
294
295 pub fn update_with_new(&mut self, new: Self) {
297 self.move_dir = new.move_dir;
298 self.move_z = new.move_z;
299 self.look_dir = new.look_dir;
300 self.break_block_pos = new.break_block_pos;
301 }
302}
303
304impl Controller {
305 pub fn reset(&mut self) {
307 self.inputs = Default::default();
308 self.queued_inputs = Default::default();
309 }
310
311 pub fn clear_events(&mut self) { self.events.clear(); }
312
313 pub fn push_event(&mut self, event: ControlEvent) { self.events.push(event); }
314
315 pub fn push_utterance(&mut self, utterance: UtteranceKind) {
316 self.push_event(ControlEvent::Utterance(utterance));
317 }
318
319 pub fn push_invite_response(&mut self, invite_response: InviteResponse) {
320 self.push_event(ControlEvent::InviteResponse(invite_response));
321 }
322
323 pub fn push_initiate_invite(&mut self, uid: Uid, invite: InviteKind) {
324 self.push_event(ControlEvent::InitiateInvite(uid, invite));
325 }
326
327 pub fn push_action(&mut self, action: ControlAction) { self.actions.push(action); }
328
329 pub fn push_basic_input(&mut self, input: InputKind) {
330 self.push_action(ControlAction::basic_input(input));
331 }
332
333 pub fn push_cancel_input(&mut self, input: InputKind) {
334 self.push_action(ControlAction::CancelInput { input });
335 }
336}
337
338impl Component for Controller {
339 type Storage = specs::VecStorage<Self>;
340}