1use crate::{
2 comp::{
3 BuffKind, ability,
4 dialogue::Subject,
5 inventory::{
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,
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,
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,
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 => Self::Sort,
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, Subject),
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,
194 StartInput {
195 input: InputKind,
196 target_entity: Option<Uid>,
197 select_pos: Option<Vec3<f32>>,
199 },
200 CancelInput(InputKind),
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}
224
225impl InputKind {
226 pub fn is_ability(self) -> bool {
227 matches!(
228 self,
229 Self::Primary | Self::Secondary | Self::Ability(_) | Self::Block
230 )
231 }
232}
233
234impl From<InputKind> for Option<ability::AbilityInput> {
235 fn from(input: InputKind) -> Option<ability::AbilityInput> {
236 use ability::AbilityInput;
237 match input {
238 InputKind::Block => Some(AbilityInput::Guard),
239 InputKind::Primary => Some(AbilityInput::Primary),
240 InputKind::Secondary => Some(AbilityInput::Secondary),
241 InputKind::Roll => Some(AbilityInput::Movement),
242 InputKind::Ability(index) => Some(AbilityInput::Auxiliary(index)),
243 InputKind::Jump | InputKind::Fly => None,
244 }
245 }
246}
247
248#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
249pub struct InputAttr {
250 pub select_pos: Option<Vec3<f32>>,
251 pub target_entity: Option<Uid>,
252}
253
254#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
255pub enum Climb {
256 Up,
257 Down,
258 Hold,
259}
260
261#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
262pub struct ControllerInputs {
263 pub climb: Option<Climb>,
264 pub move_dir: Vec2<f32>,
265 pub move_z: f32, pub look_dir: Dir,
268 pub break_block_pos: Option<Vec3<f32>>,
269 pub strafing: bool,
273}
274
275#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
276pub struct Controller {
277 pub inputs: ControllerInputs,
278 pub queued_inputs: BTreeMap<InputKind, InputAttr>,
279 pub events: Vec<ControlEvent>,
281 pub actions: Vec<ControlAction>,
282}
283
284impl ControllerInputs {
285 pub fn sanitize(&mut self) {
287 self.move_dir = if self.move_dir.map(|e| e.is_finite()).reduce_and() {
288 self.move_dir / self.move_dir.magnitude().max(1.0)
289 } else {
290 Vec2::zero()
291 };
292 self.move_z = if self.move_z.is_finite() {
293 self.move_z.clamped(-1.0, 1.0)
294 } else {
295 0.0
296 };
297 }
298
299 pub fn update_with_new(&mut self, new: Self) {
301 self.climb = new.climb;
302 self.move_dir = new.move_dir;
303 self.move_z = new.move_z;
304 self.look_dir = new.look_dir;
305 self.break_block_pos = new.break_block_pos;
306 }
307}
308
309impl Controller {
310 pub fn reset(&mut self) {
312 self.inputs = Default::default();
313 self.queued_inputs = Default::default();
314 }
315
316 pub fn clear_events(&mut self) { self.events.clear(); }
317
318 pub fn push_event(&mut self, event: ControlEvent) { self.events.push(event); }
319
320 pub fn push_utterance(&mut self, utterance: UtteranceKind) {
321 self.push_event(ControlEvent::Utterance(utterance));
322 }
323
324 pub fn push_invite_response(&mut self, invite_response: InviteResponse) {
325 self.push_event(ControlEvent::InviteResponse(invite_response));
326 }
327
328 pub fn push_initiate_invite(&mut self, uid: Uid, invite: InviteKind) {
329 self.push_event(ControlEvent::InitiateInvite(uid, invite));
330 }
331
332 pub fn push_action(&mut self, action: ControlAction) { self.actions.push(action); }
333
334 pub fn push_basic_input(&mut self, input: InputKind) {
335 self.push_action(ControlAction::basic_input(input));
336 }
337
338 pub fn push_cancel_input(&mut self, input: InputKind) {
339 self.push_action(ControlAction::CancelInput(input));
340 }
341}
342
343impl Component for Controller {
344 type Storage = specs::VecStorage<Self>;
345}