A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
ObjectDirector.cc
1#include "ObjectDirector.hh"
2
3#include "game/field/BoxColManager.hh"
4#include "game/field/ObjectDrivableDirector.hh"
5#include "game/field/obj/ObjectRegistry.hh"
6
7#include "game/kart/KartObject.hh"
8
9#include "game/system/CourseMap.hh"
10#include "game/system/RaceConfig.hh"
11
12namespace Kinoko::Field {
13
15void ObjectDirector::init() {
16 for (auto *&obj : m_objects) {
17 obj->init();
18 obj->calcModel();
19 }
20
21 ObjectDrivableDirector::Instance()->init();
22}
23
25void ObjectDirector::calc() {
26 for (auto *&obj : m_calcObjects) {
27 obj->calc();
28 }
29
30 for (auto *&obj : m_calcObjects) {
31 obj->calcModel();
32 }
33
34 ObjectDrivableDirector::Instance()->calc();
35}
36
38void ObjectDirector::addObject(ObjectCollidable *obj) {
39 u32 loadFlags = obj->loadFlags();
40
41 if (loadFlags & 1) {
42 m_calcObjects.push_back(obj);
43 }
44
45 const auto *set = m_flowTable.set(m_flowTable.slot(obj->id()));
46
47 // In the base game, it's possible an object here will access slot -1 (e.g. Moonview Highway
48 // cars). We add a nullptr check here to prevent this.
49 if (set && set->mode != 0) {
50 if (obj->collision()) {
51 m_collisionObjects.push_back(obj);
52 }
53 }
54
55 m_objects.push_back(obj);
56}
57
58void ObjectDirector::addObjectNoImpl(ObjectBase *obj) {
59 m_objects.push_back(obj);
60}
61
63void ObjectDirector::addManagedObject(ObjectCollidable *obj) {
64 m_managedObjects.push_back(obj);
65}
66
68size_t ObjectDirector::checkKartObjectCollision(Kart::KartObject *kartObj,
69 ObjectCollisionConvexHull *convexHull) {
70 size_t count = 0;
71
72 while (ObjectCollidable *obj = BoxColManager::Instance()->getNextObject()) {
73 auto *objCollision = obj->collision();
74 if (!objCollision) {
75 continue;
76 }
77
78 obj->calcCollisionTransform();
79 if (!obj->checkCollision(convexHull, m_hitDepths[count])) {
80 continue;
81 }
82
83 // We have a collision, process it
84 // Assume that we are not in a star, mega, or bullet
85 Kart::Reaction reactionOnKart = m_hitTableKart.reaction(m_hitTableKart.slot(obj->id()));
86 Kart::Reaction reactionOnObj =
87 m_hitTableKartObject.reaction(m_hitTableKartObject.slot(obj->id()));
88
89 // The object might change the reaction states
90 obj->processKartReactions(kartObj, reactionOnKart, reactionOnObj);
91
92 Kart::Reaction reaction =
93 obj->onCollision(kartObj, reactionOnKart, reactionOnObj, m_hitDepths[count]);
94 m_reactions[count] = reaction;
95
96 if (reaction == Kart::Reaction::WallAllSpeed || reaction == Kart::Reaction::WallSpark) {
97 obj->onWallCollision(kartObj, m_hitDepths[count]);
98 } else {
99 obj->onObjectCollision(kartObj);
100 }
101
102 m_collidingObjects[count] = obj;
103 if (m_hitDepths[count].y < 0.0f) {
104 m_hitDepths[count].y = 0.0f;
105 }
106
107 ++count;
108 }
109
110 return count;
111}
112
114f32 ObjectDirector::distAboveRisingWater(f32 offset) const {
115 ASSERT(m_psea);
116 return offset - m_psea->pos().y;
117}
118
120f32 ObjectDirector::risingWaterKillPlaneHeight() const {
121 ASSERT(m_psea);
122 return m_psea->pos().y - 260.0f;
123}
124
126ObjectDirector *ObjectDirector::CreateInstance() {
127 ASSERT(!s_instance);
128 s_instance = EGG::egg_new<ObjectDirector>();
129
130 ObjectDrivableDirector::CreateInstance();
131
132 s_instance->createObjects();
133
134 return s_instance;
135}
136
138void ObjectDirector::DestroyInstance() {
139 ASSERT(s_instance);
140 auto *instance = s_instance;
141 s_instance = nullptr;
142 EGG::egg_delete(instance);
143
144 ObjectDrivableDirector::DestroyInstance();
145}
146
148ObjectDirector::ObjectDirector()
149 : m_flowTable("ObjFlow.bin"), m_hitTableKart("GeoHitTableKart.bin"),
150 m_hitTableKartObject("GeoHitTableKartObj.bin"), m_objects(MAX_UNIT_COUNT),
151 m_calcObjects(MAX_UNIT_COUNT), m_collisionObjects(MAX_UNIT_COUNT), m_psea(nullptr),
152 m_managedObjects(MAX_MANAGED_OBJECTS) {}
153
155ObjectDirector::~ObjectDirector() {
156 if (s_instance) {
157 s_instance = nullptr;
158 WARN("ObjectDirector instance not explicitly handled!");
159 }
160
161 for (auto *&obj : m_objects) {
162 EGG::egg_delete(obj);
163 }
164}
165
167void ObjectDirector::createObjects() {
168 const auto *courseMap = System::CourseMap::Instance();
169 size_t objectCount = courseMap->getGeoObjCount();
170
171 auto *objDrivableDir = ObjectDrivableDirector::Instance();
172 auto course = System::RaceConfig::Instance()->raceScenario().course;
173 bool rGV2 = course == Course::SNES_Ghost_Valley_2;
174 bool sun = false;
175
176 // The max pitch of the Chain Chomp only needs to be set once,
177 // so we set it here instead of in the Chain Chomp constructor.
178 s_wanwanMaxPitch = course == Course::GCN_Mario_Circuit ? -20.0f : -30.0f;
179
180 for (size_t i = 0; i < objectCount; ++i) {
181 const auto *pObj = courseMap->getGeoObj(i);
182 ASSERT(pObj);
183
184 // Assume one player - if the presence flag isn't set, don't construct it
185 if (!(pObj->presenceFlag() & 1)) {
186 continue;
187 }
188
189 // Prevent construction of objects with disabled or no collision
190 if (IsObjectBlacklisted(pObj->id())) {
191 continue;
192 }
193
194 // rGV2's blocks are created outside of the factory function
195 if (rGV2) {
196 switch (static_cast<ObjectId>(pObj->id())) {
197 case ObjectId::ObakeBlockSFCc:
198 case ObjectId::ObakeBlock2SFCc:
199 case ObjectId::ObakeBlock3SFCc: {
200 // Create the manager if this is the first block.
201 auto *obakeManager = objDrivableDir->obakeManager();
202 if (!obakeManager) {
203 objDrivableDir->createObakeManager(*pObj);
204 } else {
205 obakeManager->addBlock(*pObj);
206 }
207 } break;
208 default:
209 break;
210 }
211 } else {
212 ObjectBase *object = createObject(*pObj);
213 object->load();
214 }
215
216 if (static_cast<ObjectId>(pObj->id()) == ObjectId::SunDS) {
217 sun = true;
218 }
219 }
220
221 if (course == Course::Moonview_Highway) {
222 auto *highwayMgr = EGG::egg_new<ObjectHighwayManager>();
223 highwayMgr->load();
224 }
225
226 if (sun) {
227 auto *sunMgr = EGG::egg_new<ObjectSunManager>();
228 sunMgr->load();
229 }
230
231 if (course == Course::GBA_Shy_Guy_Beach) {
232 auto *shipMgr = EGG::egg_new<ObjectHeyhoShipManager>();
233 shipMgr->load();
234 }
235}
236
238ObjectBase *ObjectDirector::createObject(const System::MapdataGeoObj &params) {
239 ObjectId id = static_cast<ObjectId>(params.id());
240 switch (id) {
241 case ObjectId::Psea:
242 return EGG::egg_new<ObjectPsea>(params);
243 case ObjectId::Woodbox:
244 return EGG::egg_new<ObjectWoodbox>(params);
245 case ObjectId::WLWallGC:
246 return EGG::egg_new<ObjectWLWallGC>(params);
247 case ObjectId::CarA1:
248 case ObjectId::CarA2:
249 case ObjectId::CarA3:
250 return EGG::egg_new<ObjectCarA>(params);
251 case ObjectId::Basabasa:
252 return EGG::egg_new<ObjectBasabasa>(params);
253 case ObjectId::HeyhoShipGBA:
254 return EGG::egg_new<ObjectHeyhoShip>(params);
255 case ObjectId::KartTruck:
256 case ObjectId::CarBody:
257 return EGG::egg_new<ObjectCarTGE>(params);
258 case ObjectId::KoopaBall:
259 return EGG::egg_new<ObjectKoopaBall>(params);
260 case ObjectId::W_Woodbox:
261 return EGG::egg_new<ObjectWoodboxW>(params);
262 case ObjectId::SunDS:
263 return EGG::egg_new<ObjectSunDS>(params);
264 case ObjectId::ItemboxLine:
265 return EGG::egg_new<ObjectItemboxLine>(params);
266 case ObjectId::VolcanoBall:
267 return EGG::egg_new<ObjectVolcanoBallLauncher>(params);
268 case ObjectId::PenguinS:
269 return EGG::egg_new<ObjectPenguinS>(params);
270 case ObjectId::PenguinM:
271 return EGG::egg_new<ObjectPenguin>(params);
272 case ObjectId::Dossunc:
273 return EGG::egg_new<ObjectDossunc>(params);
274 case ObjectId::Boble:
275 return EGG::egg_new<ObjectBoble>(params);
276 case ObjectId::Hanachan:
277 return EGG::egg_new<ObjectHanachan>(params);
278 case ObjectId::Seagull:
279 return EGG::egg_new<ObjectBird>(params);
280 case ObjectId::Crab:
281 return EGG::egg_new<ObjectCrab>(params);
282 case ObjectId::Hwanwan:
283 return EGG::egg_new<ObjectHwanwanManager>(params);
284 case ObjectId::HeyhoBallGBA:
285 return EGG::egg_new<ObjectHeyhoBall>(params);
286 case ObjectId::DokanSFC:
287 return EGG::egg_new<ObjectDokan>(params);
288 case ObjectId::Pylon:
289 return EGG::egg_new<ObjectPylon>(params);
290 case ObjectId::OilSFC:
291 return EGG::egg_new<ObjectOilSFC>(params);
292 case ObjectId::ParasolR:
293 return EGG::egg_new<ObjectParasolR>(params);
294 case ObjectId::KoopaFigure64:
295 return EGG::egg_new<ObjectKoopaFigure64>(params);
296 case ObjectId::Kuribo:
297 return EGG::egg_new<ObjectKuribo>(params);
298 case ObjectId::Choropu:
299 case ObjectId::Choropu2:
300 return EGG::egg_new<ObjectChoropu>(params);
301 case ObjectId::Cow:
302 return EGG::egg_new<ObjectCowHerd>(params);
303 case ObjectId::PakkunF:
304 return EGG::egg_new<ObjectPakkunF>(params);
305 case ObjectId::WLFirebarGC:
306 case ObjectId::KoopaFirebar:
307 return EGG::egg_new<ObjectFirebar>(params);
308 case ObjectId::Wanwan:
309 return EGG::egg_new<ObjectWanwan>(params);
310 case ObjectId::Poihana:
311 return EGG::egg_new<ObjectPoihana>(params);
312 case ObjectId::Propeller:
313 return EGG::egg_new<ObjectPropeller>(params);
314 case ObjectId::DKRockGC:
315 return EGG::egg_new<ObjectRock>(params);
316 case ObjectId::Sanbo:
317 return EGG::egg_new<ObjectSanbo>(params);
318 case ObjectId::TruckWagon:
319 return EGG::egg_new<ObjectTruckWagon>(params);
320 case ObjectId::Heyho:
321 return EGG::egg_new<ObjectHeyho>(params);
322 case ObjectId::Press:
323 return EGG::egg_new<ObjectPress>(params);
324 case ObjectId::WLFireRingGC:
325 return EGG::egg_new<ObjectFireRing>(params);
326 case ObjectId::FireSnake:
327 return EGG::egg_new<ObjectFireSnake>(params);
328 case ObjectId::FireSnakeV:
329 return EGG::egg_new<ObjectFireSnakeV>(params);
330 case ObjectId::PuchiPakkun:
331 return EGG::egg_new<ObjectPuchiPakkun>(params);
332 case ObjectId::KinokoUd:
333 return EGG::egg_new<ObjectKinokoUd>(params);
334 case ObjectId::KinokoBend:
335 return EGG::egg_new<ObjectKinokoBend>(params);
336 case ObjectId::VolcanoRock:
337 return EGG::egg_new<ObjectVolcanoRock>(params);
338 case ObjectId::BulldozerL:
339 case ObjectId::BulldozerR:
340 return EGG::egg_new<ObjectBulldozer>(params);
341 case ObjectId::KinokoNm:
342 return EGG::egg_new<ObjectKinokoNm>(params);
343 case ObjectId::Crane:
344 return EGG::egg_new<ObjectCrane>(params);
345 case ObjectId::VolcanoPiece:
346 return EGG::egg_new<ObjectVolcanoPiece>(params);
347 case ObjectId::FlamePole:
348 return EGG::egg_new<ObjectFlamePoleFoot>(params);
349 case ObjectId::TwistedWay:
350 return EGG::egg_new<ObjectTwistedWay>(params);
351 case ObjectId::TownBridge:
352 return EGG::egg_new<ObjectTownBridge>(params);
353 case ObjectId::DKShip64:
354 return EGG::egg_new<ObjectShip64>(params);
355 case ObjectId::Turibashi:
356 return EGG::egg_new<ObjectTuribashi>(params);
357 case ObjectId::Aurora:
358 return EGG::egg_new<ObjectAurora>(params);
359 case ObjectId::DCPillar:
360 return EGG::egg_new<ObjectPillar>(params);
361 case ObjectId::Sandcone:
362 return EGG::egg_new<ObjectSandcone>(params);
363 case ObjectId::FlamePoleV:
364 case ObjectId::FlamePoleVBig:
365 return EGG::egg_new<ObjectFlamePoleV>(params);
366 case ObjectId::Ami:
367 return EGG::egg_new<ObjectAmi>(params);
368 case ObjectId::BeltEasy:
369 return EGG::egg_new<ObjectBeltEasy>(params);
370 case ObjectId::BeltCrossing:
371 return EGG::egg_new<ObjectBeltCrossing>(params);
372 case ObjectId::BeltCurveA:
373 return EGG::egg_new<ObjectBeltCurveA>(params);
374 case ObjectId::Escalator:
375 return EGG::egg_new<ObjectEscalator>(params);
376 case ObjectId::EscalatorGroup:
377 return EGG::egg_new<ObjectEscalatorGroup>(params);
378
379 // Non-specified objects are stock collidable objects by default
380 // However, we need to specify an impl, so we don't use default
381 case ObjectId::DummyPole:
382 case ObjectId::CastleTree1c:
383 case ObjectId::MarioTreeGCc:
384 case ObjectId::PeachTreeGCc:
385 case ObjectId::MarioGo64c:
386 case ObjectId::KinokoT1:
387 case ObjectId::PalmTree:
388 case ObjectId::Parasol:
389 case ObjectId::HeyhoTreeGBAc:
390 case ObjectId::GardenTreeDSc:
391 case ObjectId::DKtreeA64c:
392 case ObjectId::DKTreeB64c:
393 case ObjectId::TownTreeDsc:
394 case ObjectId::PakkunDokan:
395 return EGG::egg_new<ObjectCollidable>(params);
396 case ObjectId::WLDokanGC:
397 case ObjectId::Mdush:
398 return EGG::egg_new<ObjectKCL>(params);
399 default:
400 return EGG::egg_new<ObjectNoImpl>(params);
401 }
402}
403
404f32 ObjectDirector::s_wanwanMaxPitch;
405
406ObjectDirector *ObjectDirector::s_instance = nullptr;
407
408} // namespace Kinoko::Field
Smallest convex shape that encloses a given set of points.
fixed_vector< ObjectBase * > m_objects
All objects live here.
fixed_vector< ObjectBase * > m_collisionObjects
Objects having collision live here too.
std::array< ObjectCollidable *, MAX_UNIT_COUNT > m_collidingObjects
Objects we are currently colliding with.
fixed_vector< ObjectBase * > m_calcObjects
Objects needing calc() live here too.
Pertains to collision.