1
+ #include " ShowHitboxes.h"
2
+ #include " Common.h"
3
+ #include " Settings.hpp"
4
+
5
+ #include < Geode/modify/CCDrawNode.hpp>
6
+ #include < Geode/modify/LevelEditorLayer.hpp>
7
+ #include < Geode/modify/PlayLayer.hpp>
8
+
9
+ using namespace ShowHitboxes ;
10
+
11
+ CCDrawNode* ShowHitboxes::getDrawNode ()
12
+ {
13
+ return MBO (CCDrawNode*, GameManager::get ()->getGameLayer (), 11632 );
14
+ }
15
+
16
+ CCRect ShowHitboxes::getObjectRect (cocos2d::CCRect r, float a, float b)
17
+ {
18
+ r.origin .x += r.size .width / 2 ;
19
+ r.origin .y += r.size .height / 2 ;
20
+ r.size .width *= a;
21
+ r.size .height *= b;
22
+ r.origin .x -= r.size .width / 2 ;
23
+ r.origin .y -= r.size .height / 2 ;
24
+ return r;
25
+ }
26
+
27
+ void ShowHitboxes::drawRectangleHitbox (CCDrawNode* node, cocos2d::CCRect const & rect, ccColor4B colBase)
28
+ {
29
+ constexpr size_t N = 4 ;
30
+ std::vector<cocos2d::CCPoint> points (N);
31
+
32
+ points[0 ] = CCPointMake (rect.getMinX (), rect.getMinY ());
33
+ points[1 ] = CCPointMake (rect.getMinX (), rect.getMaxY ());
34
+ points[2 ] = CCPointMake (rect.getMaxX (), rect.getMaxY ());
35
+ points[3 ] = CCPointMake (rect.getMaxX (), rect.getMinY ());
36
+
37
+ node->drawPolygon (const_cast <cocos2d::CCPoint*>(points.data ()), points.size (), ccc4FFromccc4B (colBase),
38
+ 0.25 , ccc4FFromccc4B (colBase));
39
+ }
40
+
41
+ void ShowHitboxes::drawForPlayer (CCDrawNode* node, PlayerObject* player)
42
+ {
43
+ if (!player)
44
+ return ;
45
+
46
+ CCRect* rect1 = reinterpret_cast <CCRect*(__thiscall*)(GameObject*)>(base::get () + 0x13a570 )(player);
47
+ CCRect rect2 = player->m_vehicleSize >= 1 .f ? getObjectRect (*rect1, 0 .25f , 0 .25f ) : getObjectRect (*rect1, 0 .4f , 0 .4f );
48
+ drawRectangleHitbox (node, *rect1, ccColor4B (255 , 0 , 0 , 255 ));
49
+ drawRectangleHitbox (node, rect2, ccColor4B (0 , 255 , 0 , 255 ));
50
+ }
51
+
52
+ void ShowHitboxes::forceDraw (GJBaseGameLayer* self, bool editor)
53
+ {
54
+ bool show = Settings::get<bool >(" level/show_hitbox/enabled" , false );
55
+ getDrawNode ()->setVisible (show);
56
+
57
+ GameManager::get ()->setGameVariable (" 0045" , show);
58
+
59
+ if (!show)
60
+ return ;
61
+
62
+ bool onDeath = Settings::get<bool >(" level/show_hitbox/on_death" , false );
63
+
64
+ if (onDeath)
65
+ getDrawNode ()->setVisible (dead);
66
+
67
+ debugDrawing = true ;
68
+ reinterpret_cast <void (__thiscall*)(cocos2d::CCLayer*)>(base::get () + (editor ? 0x248420 : 0x1986f0 ))(
69
+ self);
70
+
71
+ bool isDual = MBO (bool , self, 878 );
72
+ bool trail = Settings::get<bool >(" level/show_hitbox/queue_enabled" , false );
73
+
74
+ drawForPlayer (getDrawNode (), self->m_player1 );
75
+ if (isDual)
76
+ drawForPlayer (getDrawNode (), self->m_player2 );
77
+
78
+ if (!trail)
79
+ {
80
+ debugDrawing = false ;
81
+ return ;
82
+ }
83
+
84
+ for (auto &pair : player1Queue)
85
+ {
86
+ drawRectangleHitbox (getDrawNode (), pair.first , ccColor4B (255 , 0 , 0 , 255 ));
87
+ drawRectangleHitbox (getDrawNode (), pair.second , ccColor4B (0 , 255 , 0 , 255 ));
88
+ }
89
+
90
+ for (auto &pair : player2Queue)
91
+ {
92
+ drawRectangleHitbox (getDrawNode (), pair.first , ccColor4B (255 , 0 , 0 , 255 ));
93
+ drawRectangleHitbox (getDrawNode (), pair.second , ccColor4B (0 , 255 , 0 , 255 ));
94
+ }
95
+ debugDrawing = false ;
96
+ }
97
+
98
+ void LevelEditorLayerUpdateEditor (LevelEditorLayer* self, float dt)
99
+ {
100
+ reinterpret_cast <void (__thiscall *)(LevelEditorLayer *, float )>(base::get () + 0x23f720 )(self, dt);
101
+
102
+ dead = false ;
103
+
104
+ forceDraw (self, true );
105
+ }
106
+
107
+ void GJBaseGameLayerProcessCommands (GJBaseGameLayer* self)
108
+ {
109
+ reinterpret_cast <void (__thiscall *)(GJBaseGameLayer *)>(base::get () + 0x1BD240 )(self);
110
+
111
+ bool show = Settings::get<bool >(" level/show_hitbox/enabled" , false );
112
+ bool trail = Settings::get<bool >(" level/show_hitbox/queue_enabled" , false );
113
+
114
+ if (!show || !trail)
115
+ return ;
116
+
117
+ bool isDual = MBO (bool , self, 878 );
118
+
119
+ CCRect* rect1 = reinterpret_cast <CCRect*(__thiscall*)(GameObject*)>(base::get () + 0x13a570 )(self->m_player1 );
120
+ CCRect rect2 = self->m_player1 ->m_vehicleSize >= 1 .f ? getObjectRect (*rect1, 0 .25f , 0 .25f ) : getObjectRect (*rect1, 0 .4f , 0 .4f );
121
+
122
+ player1Queue.push_back ({*rect1, rect2});
123
+
124
+ int maxQueue = Settings::get<int >(" level/show_hitbox/max_queue" , 240 );
125
+
126
+ if (player1Queue.size () > maxQueue)
127
+ player1Queue.pop_front ();
128
+
129
+ if (!isDual)
130
+ return ;
131
+
132
+ rect1 = reinterpret_cast <CCRect*(__thiscall*)(GameObject*)>(base::get () + 0x13a570 )(self->m_player2 );
133
+ rect2 = self->m_player2 ->m_vehicleSize >= 1 .f ? getObjectRect (*rect1, 0 .25f , 0 .25f ) : getObjectRect (*rect1, 0 .4f , 0 .4f );
134
+
135
+ player2Queue.push_back ({*rect1, rect2});
136
+
137
+ if (player2Queue.size () > maxQueue)
138
+ player2Queue.pop_front ();
139
+ }
140
+
141
+ $execute
142
+ {
143
+ Mod::get ()->hook (reinterpret_cast <void *>(base::get () + 0x23f720 ), &LevelEditorLayerUpdateEditor, " LevelEditorLayer::UpdateEditor" , tulip::hook::TulipConvention::Thiscall);
144
+ Mod::get ()->hook (reinterpret_cast <void *>(base::get () + 0x1BD240 ), &GJBaseGameLayerProcessCommands, " GJBaseGameLayer::processCommands" , tulip::hook::TulipConvention::Thiscall);
145
+ }
146
+
147
+ class $modify(CCDrawNode)
148
+ {
149
+ bool drawPolygon (CCPoint *verts, unsigned int count, const ccColor4F &colFill, float borderWidth, const ccColor4F& colBase)
150
+ {
151
+ ccColor4F colBaseNew = colBase;
152
+ ccColor4F colFillNew = colBase;
153
+
154
+ if (ShowHitboxes::debugDrawing)
155
+ {
156
+ borderWidth = Settings::get<float >(" level/show_hitbox/size" , 0 .25f );
157
+ colBaseNew.a = Settings::get<int >(" level/show_hitbox/border_alpha" , 255 ) / 255 .f ;
158
+ colFillNew.a = Settings::get<int >(" level/show_hitbox/fill_alpha" , 50 ) / 255 .f ;
159
+ }
160
+
161
+ bool res = CCDrawNode::drawPolygon (verts, count, colFillNew, borderWidth, colBaseNew);
162
+
163
+ return res;
164
+ }
165
+ };
166
+
167
+ class $modify(PlayLayer)
168
+ {
169
+ void postUpdate (float dt)
170
+ {
171
+ PlayLayer::postUpdate (dt);
172
+
173
+ forceDraw (this , false );
174
+ };
175
+
176
+ void resetLevel ()
177
+ {
178
+ PlayLayer::resetLevel ();
179
+ player1Queue.clear ();
180
+ player2Queue.clear ();
181
+
182
+ dead = false ;
183
+ }
184
+
185
+ void fullReset ()
186
+ {
187
+ PlayLayer::fullReset ();
188
+
189
+ dead = false ;
190
+ }
191
+
192
+ void destroyPlayer (PlayerObject* p0, GameObject* p1)
193
+ {
194
+ PlayLayer::destroyPlayer (p0, p1);
195
+
196
+ if (p1 && p1->getPositionX () == 0 && p1->getPositionY () == 105 )
197
+ return ;
198
+
199
+ dead = true ;
200
+ }
201
+ };
202
+
203
+ class $modify(LevelEditorLayer)
204
+ {
205
+ void onPlaytest ()
206
+ {
207
+ LevelEditorLayer::onPlaytest ();
208
+
209
+ player1Queue.clear ();
210
+ player2Queue.clear ();
211
+ }
212
+ };
213
+
214
+ class $modify(GJBaseGameLayer)
215
+ {
216
+ bool init ()
217
+ {
218
+ dead = false ;
219
+ return GJBaseGameLayer::init ();
220
+ }
221
+ };
0 commit comments