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