|
1 | 1 | /datum/component/orbiter |
2 | 2 | can_transfer = TRUE |
3 | 3 | dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS |
4 | | - var/list/orbiters |
| 4 | + /// Assoc list of all orbiters -> their initial matrix |
| 5 | + var/list/orbiter_list |
| 6 | + /// Assoc list of orbiters -> their orbiting parameters |
| 7 | + var/list/orbiter_params |
| 8 | + /// Movement tracker used to check when our owner moves |
| 9 | + var/datum/movement_detector/tracker |
5 | 10 |
|
6 | 11 | //radius: range to orbit at, radius of the circle formed by orbiting (in pixels) |
7 | 12 | //clockwise: whether you orbit clockwise or anti clockwise |
|
12 | 17 | if(!istype(orbiter) || !isatom(parent) || isarea(parent)) |
13 | 18 | return COMPONENT_INCOMPATIBLE |
14 | 19 |
|
15 | | - orbiters = list() |
16 | | - |
17 | | - var/atom/master = parent |
18 | | - master.orbiters = src |
| 20 | + orbiter_list = list() |
| 21 | + orbiter_params = list() |
19 | 22 |
|
20 | 23 | begin_orbit(orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation) |
21 | 24 |
|
22 | 25 | /datum/component/orbiter/RegisterWithParent() |
23 | | - . = ..() |
24 | 26 | var/atom/target = parent |
25 | | - while(ismovable(target)) |
26 | | - RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(move_react)) |
27 | | - target = target.loc |
| 27 | + |
| 28 | + target.orbiters = src |
| 29 | + if(ismovable(target)) |
| 30 | + tracker = new(target, CALLBACK(src, PROC_REF(move_react))) |
| 31 | + |
| 32 | + RegisterSignal(parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, PROC_REF(orbiter_glide_size_update)) |
28 | 33 |
|
29 | 34 | /datum/component/orbiter/UnregisterFromParent() |
30 | | - . = ..() |
| 35 | + UnregisterSignal(parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE) |
31 | 36 | var/atom/target = parent |
32 | | - while(ismovable(target)) |
33 | | - UnregisterSignal(target, COMSIG_MOVABLE_MOVED) |
34 | | - target = target.loc |
| 37 | + target.orbiters = null |
| 38 | + QDEL_NULL(tracker) |
35 | 39 |
|
36 | 40 | /datum/component/orbiter/Destroy() |
37 | 41 | var/atom/master = parent |
38 | | - master.orbiters = null |
39 | | - for(var/i in orbiters) |
| 42 | + if(master.orbiters == src) |
| 43 | + master.orbiters = null |
| 44 | + for(var/i in orbiter_list) |
40 | 45 | end_orbit(i) |
41 | | - orbiters = null |
| 46 | + orbiter_list = null |
| 47 | + orbiter_params = null |
42 | 48 | return ..() |
43 | 49 |
|
44 | 50 | /datum/component/orbiter/InheritComponent(datum/component/orbiter/newcomp, original, atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation) |
45 | 51 | if(!newcomp) |
46 | 52 | begin_orbit(arglist(args.Copy(3))) |
47 | 53 | return |
48 | 54 | // The following only happens on component transfers |
49 | | - orbiters += newcomp.orbiters |
50 | | - |
51 | | -/datum/component/orbiter/PostTransfer() |
52 | | - if(!isatom(parent) || isarea(parent) || !get_turf(parent)) |
| 55 | + for(var/o in newcomp.orbiter_list) |
| 56 | + var/atom/movable/incoming_orbiter = o |
| 57 | + incoming_orbiter.orbiting = src |
| 58 | + // It is important to transfer the signals so we don't get locked to the new orbiter component for all time |
| 59 | + newcomp.UnregisterSignal(incoming_orbiter, list(COMSIG_MOVABLE_MOVED /*, COMSIG_ATOM_BEFORE_SHUTTLE_MOVE, COMSIG_ATOM_AFTER_SHUTTLE_MOVE */)) |
| 60 | + RegisterSignal(incoming_orbiter, COMSIG_MOVABLE_MOVED, PROC_REF(orbiter_move_react)) |
| 61 | + // RegisterSignal(incoming_orbiter, COMSIG_ATOM_BEFORE_SHUTTLE_MOVE, PROC_REF(orbiter_before_shuttle_move)) |
| 62 | + |
| 63 | + orbiter_list += newcomp.orbiter_list |
| 64 | + orbiter_params += newcomp.orbiter_params |
| 65 | + newcomp.orbiter_list = null |
| 66 | + newcomp.orbiter_params = null |
| 67 | + |
| 68 | +/datum/component/orbiter/PostTransfer(datum/new_parent) |
| 69 | + if(!isatom(new_parent) || isarea(new_parent) || !get_turf(new_parent)) |
53 | 70 | return COMPONENT_INCOMPATIBLE |
54 | | - move_react() |
| 71 | + move_react(new_parent) |
55 | 72 |
|
56 | 73 | /datum/component/orbiter/proc/begin_orbit(atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation) |
57 | | - SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_BEGIN, orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation) |
58 | 74 | if(orbiter.orbiting) |
59 | 75 | if(orbiter.orbiting == src) |
60 | 76 | orbiter.orbiting.end_orbit(orbiter, TRUE) |
61 | 77 | else |
62 | 78 | orbiter.orbiting.end_orbit(orbiter) |
63 | | - orbiters[orbiter] = TRUE |
| 79 | + |
| 80 | + orbiter_params[orbiter] = args.Copy(2) |
| 81 | + orbiter_list[orbiter] = TRUE |
64 | 82 | orbiter.orbiting = src |
| 83 | + |
| 84 | + // ADD_TRAIT(orbiter, TRAIT_NO_FLOATING_ANIM, ORBITING_TRAIT) |
65 | 85 | RegisterSignal(orbiter, COMSIG_MOVABLE_MOVED, PROC_REF(orbiter_move_react)) |
| 86 | + // RegisterSignal(orbiter, COMSIG_ATOM_BEFORE_SHUTTLE_MOVE, PROC_REF(orbiter_before_shuttle_move)) |
| 87 | + |
| 88 | + SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_BEGIN, orbiter) |
66 | 89 |
|
67 | 90 | var/matrix/initial_transform = matrix(orbiter.transform) |
68 | | - orbiters[orbiter] = initial_transform |
| 91 | + orbiter_list[orbiter] = initial_transform |
69 | 92 |
|
70 | 93 | // Head first! |
71 | 94 | if(pre_rotation) |
|
82 | 105 |
|
83 | 106 | orbiter.SpinAnimation(rotation_speed, -1, clockwise, rotation_segments, parallel = FALSE) |
84 | 107 |
|
85 | | - orbiter.forceMove(get_turf(parent)) |
86 | | - to_chat(orbiter, "<span class='notice'>Now orbiting [parent].</span>") |
| 108 | + // if(ismob(orbiter)) |
| 109 | + // var/mob/orbiter_mob = orbiter |
| 110 | + // orbiter_mob.updating_glide_size = FALSE |
| 111 | + if(ismovable(parent)) |
| 112 | + var/atom/movable/movable_parent = parent |
| 113 | + orbiter.glide_size = movable_parent.glide_size |
| 114 | + |
| 115 | + orbiter.abstract_move(get_turf(parent)) |
| 116 | + to_chat(orbiter, SPAN_NOTICE("Now orbiting [parent].")) |
| 117 | + |
| 118 | +/datum/component/orbiter/proc/orbiter_before_shuttle_move(atom/source) |
| 119 | + SIGNAL_HANDLER |
| 120 | + // We need to detach ourselves before the shuttle moves and reattach afterwards |
| 121 | + end_orbit(source, TRUE) |
| 122 | + // RegisterSignal(source, COMSIG_ATOM_AFTER_SHUTTLE_MOVE, PROC_REF(orbiter_after_shuttle_move)) |
| 123 | + |
| 124 | +/datum/component/orbiter/proc/orbiter_after_shuttle_move(atom/source) |
| 125 | + SIGNAL_HANDLER |
| 126 | + // UnregisterSignal(source, COMSIG_ATOM_AFTER_SHUTTLE_MOVE) |
| 127 | + begin_orbit(arglist(list(source) + orbiter_params[source])) |
87 | 128 |
|
88 | 129 | /datum/component/orbiter/proc/end_orbit(atom/movable/orbiter, refreshing=FALSE) |
89 | | - if(!orbiters[orbiter]) |
| 130 | + if(!orbiter_list[orbiter]) |
90 | 131 | return |
91 | | - SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_END, orbiter, refreshing) |
92 | | - UnregisterSignal(orbiter, COMSIG_MOVABLE_MOVED) |
93 | | - orbiter.SpinAnimation(0, 0, parallel = FALSE) |
94 | | - if(istype(orbiters[orbiter],/matrix)) //This is ugly. |
95 | | - orbiter.transform = orbiters[orbiter] |
96 | | - orbiters -= orbiter |
| 132 | + UnregisterSignal(orbiter, list(COMSIG_MOVABLE_MOVED /*, COMSIG_ATOM_BEFORE_SHUTTLE_MOVE, COMSIG_ATOM_AFTER_SHUTTLE_MOVE */)) |
| 133 | + // SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_STOP, orbiter) // on tg used by ghost player plays |
| 134 | + orbiter.SpinAnimation(0, 0) |
| 135 | + if(istype(orbiter_list[orbiter],/matrix)) //This is ugly. |
| 136 | + orbiter.transform = orbiter_list[orbiter] |
| 137 | + orbiter_list -= orbiter |
| 138 | + if(!refreshing) |
| 139 | + orbiter_params -= orbiter |
97 | 140 | orbiter.stop_orbit(src) |
98 | 141 | orbiter.orbiting = null |
99 | | - if(!refreshing && !length(orbiters) && !QDELING(src)) |
| 142 | + |
| 143 | + if(ismob(orbiter)) |
| 144 | + var/mob/orbiter_mob = orbiter |
| 145 | + // orbiter_mob.updating_glide_size = TRUE |
| 146 | + orbiter_mob.glide_size = 8 |
| 147 | + |
| 148 | + if(isobserver(orbiter)) |
| 149 | + var/mob/observer/dead/ghostie = orbiter |
| 150 | + ghostie.orbiting_ref = null |
| 151 | + |
| 152 | + // REMOVE_TRAIT(orbiter, TRAIT_NO_FLOATING_ANIM, ORBITING_TRAIT) |
| 153 | + |
| 154 | + if(!refreshing && !length(orbiter_list) && !QDELING(src)) |
100 | 155 | qdel(src) |
101 | 156 |
|
102 | 157 | // This proc can receive signals by either the thing being directly orbited or anything holding it |
103 | | -/datum/component/orbiter/proc/move_react(atom/orbited, atom/oldloc, direction) |
| 158 | +/datum/component/orbiter/proc/move_react(atom/movable/master, atom/mover, atom/oldloc, direction) |
104 | 159 | set waitfor = FALSE // Transfer calls this directly and it doesnt care if the ghosts arent done moving |
105 | 160 |
|
106 | | - var/atom/movable/master = parent |
107 | 161 | if(master.loc == oldloc) |
108 | 162 | return |
109 | 163 |
|
110 | 164 | var/turf/newturf = get_turf(master) |
111 | 165 | if(!newturf) |
112 | 166 | qdel(src) |
113 | 167 |
|
114 | | - // Handling the signals of stuff holding us (or not anymore) |
115 | | - // These are prety rarely activated, how often are you following something in a bag? |
116 | | - if(oldloc && !isturf(oldloc)) // We used to be registered to it, probably |
117 | | - var/atom/target = oldloc |
118 | | - while(ismovable(target)) |
119 | | - UnregisterSignal(target, COMSIG_MOVABLE_MOVED) |
120 | | - target = target.loc |
121 | | - if(orbited?.loc && orbited.loc != newturf) // We want to know when anything holding us moves too |
122 | | - var/atom/target = orbited.loc |
123 | | - while(ismovable(target)) |
124 | | - RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(move_react), TRUE) |
125 | | - target = target.loc |
126 | | - |
127 | 168 | var/atom/curloc = master.loc |
128 | | - for(var/i in orbiters) |
129 | | - var/atom/movable/thing = i |
130 | | - if(QDELETED(thing) || thing.loc == newturf) |
| 169 | + for(var/atom/movable/movable_orbiter as anything in orbiter_list) |
| 170 | + if(QDELETED(movable_orbiter) || movable_orbiter.loc == newturf) |
131 | 171 | continue |
132 | | - thing.forceMove(newturf) |
| 172 | + movable_orbiter.abstract_move(newturf) |
133 | 173 | if(CHECK_TICK && master.loc != curloc) |
134 | 174 | // We moved again during the checktick, cancel current operation |
135 | 175 | break |
136 | 176 |
|
137 | 177 |
|
138 | 178 | /datum/component/orbiter/proc/orbiter_move_react(atom/movable/orbiter, atom/oldloc, direction) |
| 179 | + SIGNAL_HANDLER |
| 180 | + |
139 | 181 | if(orbiter.loc == get_turf(parent)) |
140 | 182 | return |
141 | 183 | end_orbit(orbiter) |
142 | 184 |
|
| 185 | +/datum/component/orbiter/proc/orbiter_glide_size_update(datum/source, target) |
| 186 | + SIGNAL_HANDLER |
| 187 | + for(var/orbiter in orbiter_list) |
| 188 | + var/atom/movable/movable_orbiter = orbiter |
| 189 | + movable_orbiter.glide_size = target |
| 190 | + |
143 | 191 | ///////////////////// |
144 | 192 |
|
145 | 193 | /atom/movable/proc/orbit(atom/A, radius = 10, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, pre_rotation = TRUE) |
146 | 194 | if(!istype(A) || !get_turf(A) || A == src) |
147 | 195 | return |
148 | | - |
| 196 | + if (HAS_TRAIT(A, TRAIT_ORBITING_FORBIDDEN)) |
| 197 | + // Stealth-mins have an empty name, don't want "You cannot orbit at this time." |
| 198 | + to_chat(src, SPAN_NOTICE("You cannot orbit ["[A]" || "them"] at this time.")) |
| 199 | + return |
149 | 200 | orbit_target = A |
150 | 201 | return A.AddComponent(/datum/component/orbiter, src, radius, clockwise, rotation_speed, rotation_segments, pre_rotation) |
151 | 202 |
|
|
0 commit comments