NSMBW-Decomp
A decompilation of New Super Mario Bros. Wii
Loading...
Searching...
No Matches
d_wm_csvdata.cpp
Go to the documentation of this file.
3#include <game/bases/d_wm_lib.hpp>
4#include <lib/nw4r/g3d.h>
5#include <lib/MSL/stdlib.h>
6#include <constants/sjis_constants.h>
7/// @file
8
9const int dCsvData_c::c_COURSE_ID = STAGE_1;
10const int dCsvData_c::c_GHOST_ID = STAGE_GHOST_HOUSE;
11const int dCsvData_c::c_TOWER_ID = STAGE_TOWER;
12const int dCsvData_c::c_CASTLE_ID = STAGE_CASTLE;
13const int dCsvData_c::c_KINOKO_ID = STAGE_KINOKO_HOUSE;
14const int dCsvData_c::c_ENEMY_ID = STAGE_ENEMY;
15const int dCsvData_c::c_CANON_ID = STAGE_CANNON;
16const int dCsvData_c::c_TRSHIP_ID = STAGE_TRSHIP;
17const int dCsvData_c::c_AIRSHIP_ID = STAGE_AIRSHIP;
18const int dCsvData_c::c_START_ID = STAGE_START_KINOKO_HOUSE;
19const int dCsvData_c::c_PEACH_ID = STAGE_PEACH_CASTLE;
20
21const char *l_routeInfoArcName = "RouteInfo";
22
23/// @brief Reads a single CSV field into a buffer.
24/// @return The length of the field read.
25int read(char *buffer, const char *csv, int bufferSize) {
26 int len = 0;
27 if (*csv == '"') {
28 csv++;
29 if (*csv == '"') {
30 return 0;
31 }
32 }
33
34 if (*csv == ',') {
35 return 0;
36 }
37
38 while (true) {
39 if (*csv == ',' || *csv == '"' || *csv == '\r' && *(csv + 1) == '\n') {
40 buffer[len] = '\0';
41 break;
42 }
43 buffer[len] = *csv;
44 len++;
45 csv++;
46 }
47 return len;
48}
49
51 for (int i = 0; i < MAX_ROUTE_COUNT; i++) {
52 if (mRoutes[i].mChildPoints != nullptr) {
54 }
55 }
56}
57
58void dCsvData_c::initialize(int world, int subworld) {
59 mWorld = world;
60 mSubworld = subworld;
63}
64
66 mPointCount = 0;
68 mRouteCount = 0;
69 for (int i = 0; i < MAX_POINT_COUNT; i++) {
70 for (int j = 0; j < MAX_POINT_NAME_LEN; j++) {
71 mPoints[i].mName[j] = '\0';
72 }
73 for (int k = 0; k < MAX_OPEN_POINT_COUNT; k++) {
74 for (int j = 0; j < MAX_POINT_NAME_LEN; j++) {
75 mPoints[i].mOpenPointNameRegular[k][j] = '\0';
76 mPoints[i].mOpenPointNameSecret[k][j] = '\0';
77 }
78 }
79 // [Bug: This should be MAX_OPEN_ROUTE_COUNT (16)]
80 for (int k = 0; k < 64; k++) {
81 for (int j = 0; j < MAX_ROUTE_NAME_LEN; j++) {
82 mPoints[i].mRouteNameRegular[k][j] = '\0';
83 mPoints[i].mRouteNameSecret[k][j] = '\0';
84 }
85 }
86 for (int k = 0; k < MAX_FLAG_DATA_COUNT; k++) {
87 for (int j = 0; j < MAX_FLAG_DATA_LEN; j++) {
88 mPoints[i].mFlagDataRegular[k][j] = '\0';
89 mPoints[i].mFlagDataSecret[k][j] = '\0';
90 }
91 }
92 mPoints[i].mFlagDataNumRegular = 0;
93 mPoints[i].mFlagDataNumSecret = 0;
94 mPoints[i].mFlags = 0;
95 mPoints[i].mParam = 0;
96 mPoints[i].mFlagsEnemy = 0;
97 mPoints[i].m_1bc = 0;
98 }
99 for (int i = 0; i < MAX_SUBROUTE_COUNT; i++) {
100 for (int j = 0; j < MAX_ROUTE_NAME_LEN; j++) {
101 mSubRoutes[i].mName[j] = '\0';
102 }
103 mSubRoutes[i].mActionType = ACTION_TYPE_NONE;
104 mSubRoutes[i].m_10 = 0;
105 mSubRoutes[i].mFlags = 0;
106 }
107 for (int i = 0; i < MAX_ROUTE_COUNT; i++) {
108 for (int j = 0; j < MAX_ROUTE_NAME_LEN; j++) {
109 mRoutes[i].mName[j] = '\0';
110 }
111 mRoutes[i].mChildPoints = nullptr;
112 mRoutes[i].mNumSubroutes = 99999;
113 mRoutes[i].mChildPointNum = 0;
114 }
115}
116
119
120 char fileName[0x20];
121 size_t fileSize;
122 nw4r::g3d::ResFile res;
123 char *csv;
124
125 // Load the point CSV file
126 snprintf(fileName, sizeof(fileName), "W%X/pointW%X.csv", mWorld + 1, mWorld + 1);
127 res = resMng->getResSilently(l_routeInfoArcName, fileName, &fileSize);
128 if (!res.IsValid()) {
129 snprintf(fileName, sizeof(fileName), "W%X/pointW%Xa.csv", mWorld + 1, mWorld + 1);
130 fileName[SUBWORLD_CHAR_OFFSET] += mSubworld;
131 res = resMng->getRes(l_routeInfoArcName, fileName, &fileSize);
132 }
133 csv = (char *) res.ptr();
134
135 int pos = 0;
136 do {
137 // Skip ahead to the first comma. Each file in the line starts with a line number,
138 // which we don't need to process.
139 while (csv[pos] != ',') {
140 pos++;
141 }
142 pos++;
143
144 ReadPointName(csv, pos);
145 if (isLineEnd(csv, pos)) goto end;
146 pos++;
147 if (isLineEnd(csv, pos)) goto end;
148
149 ReadPointType(csv, pos);
150 if (isLineEnd(csv, pos)) goto end;
151 if (isLineEnd(csv, pos)) goto end;
152
153 // Regular exit data
154
155 ReadOpenPointName(csv, pos, true);
156 if (isLineEnd(csv, pos)) goto end;
157 pos++;
158 if (isLineEnd(csv, pos)) goto end;
159
160 ReadOpenRouteName(csv, pos, true);
161 if (isLineEnd(csv, pos)) goto end;
162 pos++;
163 if (isLineEnd(csv, pos)) goto end;
164
165 ReadFlagData(csv, pos, true);
166 if (isLineEnd(csv, pos)) goto end;
167 if (isLineEnd(csv, pos)) goto end;
168
169 // Secret exit data
170
171 ReadOpenPointName(csv, pos, false);
172 if (isLineEnd(csv, pos)) goto end;
173 pos++;
174 if (isLineEnd(csv, pos)) goto end;
175
176 ReadOpenRouteName(csv, pos, false);
177 if (isLineEnd(csv, pos)) goto end;
178 pos++;
179 if (isLineEnd(csv, pos)) goto end;
180
181 ReadFlagData(csv, pos, false);
182
183 end:
184 mPointCount++;
185 pos += 2;
186 } while (pos != fileSize);
187
188 // Now load the route CSV file
189 snprintf(fileName, sizeof(fileName), "W%X/routeW%X.csv", mWorld + 1, mWorld + 1);
190 res = resMng->getResSilently(l_routeInfoArcName, fileName, &fileSize);
191 if (!res.IsValid()) {
192 snprintf(fileName, sizeof(fileName), "W%X/routeW%Xa.csv", mWorld + 1, mWorld + 1);
193 fileName[SUBWORLD_CHAR_OFFSET] += mSubworld;
194 res = resMng->getRes(l_routeInfoArcName, fileName, &fileSize);
195 }
196 csv = (char *) res.ptr();
197
198 pos = 0;
199 do {
200 ReadAnimeRouteName(csv, pos);
201 pos++;
202 ReadAction(csv, pos);
203 pos++;
204 ReadRouteFlag(csv, pos);
205 if (mSubRoutes[mSubrouteCount].mName[0] != '0') {
207 }
208 pos += 2;
209 } while (pos != fileSize);
210}
211
212void dCsvData_c::ReadPointName(char *csv, int &pos) {
213 pos += read(mPoints[mPointCount].mName, &csv[pos], sizeof(mPoints[mPointCount].mName));
214}
215
216void dCsvData_c::ReadPointType(char *csv, int &pos) {
218 if (csv[pos] == '"' && csv[pos + 1] == '"') {
219 pos += 3;
220 return;
221 }
222 if (csv[pos] == ',') {
223 pos++;
224 return;
225 }
226
227 bool isStr = false;
228 if (csv[pos] == '"') {
229 isStr = true;
230 pos++;
231 }
232
233 char pointName[32];
234 while (true) {
235 int i = 0;
236 while (true) {
237 if (csv[pos] == ',' || csv[pos] == '"' || isLineEnd(csv, pos)) {
238 pointName[i] = '\0';
239 break;
240 }
241 pointName[i] = csv[pos];
242 i++;
243 pos++;
244 }
245
246 // Normal points
247 if (strcmp(pointName, "ura") == 0) {
248 mPoints[mPointCount].mFlags |= POINT_URA;
249 } else if (strcmp(pointName, "stop") == 0) {
250 mPoints[mPointCount].mFlags |= POINT_STOP;
251 } else if (strcmp(pointName, "link1") == 0) {
252 mPoints[mPointCount].mFlags |= POINT_LINK1;
253 } else if (strcmp(pointName, "link2") == 0) {
254 mPoints[mPointCount].mFlags |= POINT_LINK2;
255 } else if (strcmp(pointName, "link3") == 0) {
256 mPoints[mPointCount].mFlags |= POINT_LINK3;
257 } else if (strcmp(pointName, "link4") == 0) {
258 mPoints[mPointCount].mFlags |= POINT_LINK4;
259 } else if (strcmp(pointName, "link5") == 0) {
260 mPoints[mPointCount].mFlags |= POINT_LINK5;
261 } else if (strcmp(pointName, "scroll") == 0) {
262 mPoints[mPointCount].mFlags |= POINT_SCROLL;
263 } else if (strcmp(pointName, "scale") == 0) {
264 mPoints[mPointCount].mFlags |= POINT_SCALE;
265 } else if (strcmp(pointName, "dokan") == 0) {
266 mPoints[mPointCount].mFlags |= POINT_DOKAN;
267 } else if (strcmp(pointName, "switch") == 0) {
268 mPoints[mPointCount].mFlags |= POINT_SWITCH;
269 } else if (strcmp(pointName, "crossroad") == 0) {
270 mPoints[mPointCount].mFlags |= POINT_CROSSROAD;
271 } else if (strcmp(pointName, "focus") == 0) {
272 mPoints[mPointCount].mFlags |= POINT_FOCUS;
273 } else if (strncmp(pointName, "anchor", 6) == 0) {
274 int len = strlen(pointName);
275 if (len == 6) {
276 mPoints[mPointCount].mFlags |= POINT_ANCHOR_X;
277 mPoints[mPointCount].mFlags |= POINT_ANCHOR_Y;
278 } else if (len == 7 || len == 8) {
279 if (pointName[6] == 'x') {
280 mPoints[mPointCount].mFlags |= POINT_ANCHOR_X;
281 } else if (pointName[6] == 'y') {
282 mPoints[mPointCount].mFlags |= POINT_ANCHOR_Y;
283 } else if ('1' <= pointName[6] && pointName[6] <= '9') {
284 mPoints[mPointCount].mParam = atoi(&pointName[6]);
285 }
286 if ('1' <= pointName[7] && pointName[7] <= '9') {
287 mPoints[mPointCount].mParam = atoi(&pointName[7]);
288 }
289 }
290 } else if (strcmp(pointName, "tilt") == 0) {
291 mPoints[mPointCount].mFlags |= POINT_TILT;
292 } else if (strcmp(pointName, "demo1") == 0) {
293 mPoints[mPointCount].mFlags |= POINT_DEMO1;
294 } else if (strcmp(pointName, "demo2") == 0) {
295 mPoints[mPointCount].mFlags |= POINT_DEMO2;
296 } else if (strcmp(pointName, "demo3") == 0) {
297 mPoints[mPointCount].mFlags |= POINT_DEMO3;
298 } else if (strcmp(pointName, "demo4") == 0) {
299 mPoints[mPointCount].mFlags |= POINT_DEMO4;
300 } else if (strcmp(pointName, "demo5") == 0) {
301 mPoints[mPointCount].mFlags |= POINT_DEMO5;
302 } else if (strcmp(pointName, "demo6") == 0) {
303 mPoints[mPointCount].mFlags |= POINT_DEMO6;
304 } else if (strcmp(pointName, "demo7") == 0) {
305 mPoints[mPointCount].mFlags |= POINT_DEMO7;
306 } else if (strcmp(pointName, "camstop") == 0) {
307 mPoints[mPointCount].mFlags |= POINT_CAMSTOP;
308 } else if (strcmp(pointName, "noshift") == 0) {
309 mPoints[mPointCount].mFlags |= POINT_NOSHIFT;
310 } else if (strncmp(pointName, "board", 5) == 0) {
311 mPoints[mPointCount].mFlags |= POINT_BOARD;
312 } else if (strcmp(pointName, "demostop") == 0) {
313 mPoints[mPointCount].mFlags |= POINT_DEMOSTOP;
314 } else if (strcmp(pointName, "scrollY") == 0) {
315 mPoints[mPointCount].mFlags |= POINT_SCROLL_Y;
316 } else if (strcmp(pointName, "sand") == 0) {
317 mPoints[mPointCount].mFlags |= POINT_SAND;
318 } else if (strcmp(pointName, "ice") == 0) {
319 mPoints[mPointCount].mFlags |= POINT_ICE;
320 } else if (strcmp(pointName, "scrollA") == 0) {
321 mPoints[mPointCount].mFlags |= POINT_SCROLL_A;
322 }
323
324 // Enemy points
325 if (strcmp(pointName, "kuribo1") == 0) {
326 mPoints[mPointCount].mFlagsEnemy |= ENEMY_KURIBO1;
327 } else if (strcmp(pointName, "kuribo2") == 0) {
328 mPoints[mPointCount].mFlagsEnemy |= ENEMY_KURIBO2;
329 } else if (strcmp(pointName, "Puku1") == 0) {
330 mPoints[mPointCount].mFlagsEnemy |= ENEMY_PUKU1;
331 } else if (strcmp(pointName, "Puku2") == 0) {
332 mPoints[mPointCount].mFlagsEnemy |= ENEMY_PUKU2;
333 } else if (strcmp(pointName, "Pak1") == 0) {
334 mPoints[mPointCount].mFlagsEnemy |= ENEMY_PAK1;
335 } else if (strcmp(pointName, "Pak2") == 0) {
336 mPoints[mPointCount].mFlagsEnemy |= ENEMY_PAK2;
337 } else if (strcmp(pointName, "Pak3") == 0) {
338 mPoints[mPointCount].mFlagsEnemy |= ENEMY_PAK3;
339 } else if (strcmp(pointName, "Hbros1") == 0) {
340 mPoints[mPointCount].mFlagsEnemy |= ENEMY_HBROS1;
341 } else if (strcmp(pointName, "trap1") == 0) {
342 mPoints[mPointCount].mFlagsEnemy |= ENEMY_TRAP1;
343 } else if (strcmp(pointName, "trap2") == 0) {
344 mPoints[mPointCount].mFlagsEnemy |= ENEMY_TRAP2;
345 }
346
347 if (csv[pos] == '"') {
348 pos++;
349 break;
350 }
351 if (!isStr && csv[pos] == ',' || isLineEnd(csv, pos)) {
352 break;
353 }
354 pos++;
355 }
356 if (!isLineEnd(csv, pos)) {
357 pos++;
358 }
359}
360
361void dCsvData_c::ReadOpenPointName(char *csv, int &pos, bool regularExit) {
362 int count = 0;
363 if (csv[pos] == '"' && csv[pos + 1] == '"') {
364 pos += 2;
365 } else if (csv[pos] == '"') {
366 int pointIdx = 0;
367 pos++;
368 do {
369 for (int i = 0; i < MAX_POINT_NAME_LEN - 1; i++) {
370 if (csv[pos] == ',') {
371 continue;
372 }
373 if (regularExit) {
374 mPoints[mPointCount].mOpenPointNameRegular[pointIdx][i] = csv[pos];
375 } else {
376 mPoints[mPointCount].mOpenPointNameSecret[pointIdx][i] = csv[pos];
377 }
378 pos++;
379 }
380 pointIdx++;
381 count++;
382 } while (csv[pos++] != '"');
383 } else if (csv[pos] != ',') {
384 int pointIdx = 0;
385 do {
386 for (int i = 0; i < MAX_POINT_NAME_LEN - 1; i++) {
387 if (csv[pos] == ',') {
388 continue;
389 }
390 if (regularExit) {
391 mPoints[mPointCount].mOpenPointNameRegular[pointIdx][i] = csv[pos];
392 } else {
393 mPoints[mPointCount].mOpenPointNameSecret[pointIdx][i] = csv[pos];
394 }
395 pos++;
396 }
397 pointIdx++;
398 count++;
399 while (csv[pos] != ',') {
400 if (isLineEnd(csv, pos)) {
401 break;
402 }
403 pos++;
404 }
405 } while (csv[pos] != ',' && !isLineEnd(csv, pos));
406 }
407 if (regularExit) {
408 mPoints[mPointCount].mOpenPointNumRegular = count;
409 } else {
410 mPoints[mPointCount].mOpenPointNumSecret = count;
411 }
412}
413
414void dCsvData_c::ReadOpenRouteName(char *csv, int &pos, bool regularExit) {
415 int count = 0;
416 if (csv[pos] == '"' && csv[pos + 1] == '"') {
417 pos += 2;
418 } else if (csv[pos] == '"') {
419 int routeIdx = 0;
420 pos++;
421 do {
422 for (int i = 0; i < MAX_ROUTE_NAME_LEN - 1; i++) {
423 if (csv[pos] == ',' || csv[pos] == '"') {
424 continue;
425 }
426 if (csv[pos] != ' ') {
427 if (regularExit) {
428 mPoints[mPointCount].mRouteNameRegular[routeIdx][i] = csv[pos];
429 } else {
430 mPoints[mPointCount].mRouteNameSecret[routeIdx][i] = csv[pos];
431 }
432 }
433 pos++;
434 }
435 routeIdx++;
436 count++;
437 } while (csv[pos++] != '"');
438 } else if (csv[pos] != ',') {
439 int routeIdx = 0;
440 do {
441 for (int i = 0; i < MAX_ROUTE_NAME_LEN - 1; i++) {
442 if (csv[pos] == ',' || csv[pos] == '"') {
443 continue;
444 }
445 if (csv[pos] != ' ') {
446 if (regularExit) {
447 mPoints[mPointCount].mRouteNameRegular[routeIdx][i] = csv[pos];
448 } else {
449 mPoints[mPointCount].mRouteNameSecret[routeIdx][i] = csv[pos];
450 }
451 }
452 pos++;
453 }
454 routeIdx++;
455 count++;
456 while (csv[pos] != ',') {
457 if (isLineEnd(csv, pos)) {
458 break;
459 }
460 pos++;
461 }
462 } while (csv[pos] != ',' && !isLineEnd(csv, pos));
463 }
464 if (regularExit) {
465 mPoints[mPointCount].mOpenRouteNumRegular = count;
466 } else {
467 mPoints[mPointCount].mOpenRouteNumSecret = count;
468 }
469}
470
471void dCsvData_c::ReadFlagData(char *csv, int &pos, bool regularExit) {
472 int flagIndex, i;
473 bool isStr = false;
474 if (csv[pos] == '"') {
475 isStr = true;
476 pos++;
477 }
478 flagIndex = 0;
479 while (true) {
480 i = 0;
481 while (true) {
482 if (csv[pos] == ',' || csv[pos] == '"' || csv[pos] == '\r' && csv[pos + 1] == '\n') {
483 if (regularExit) {
484 mPoints[mPointCount].mFlagDataRegular[flagIndex][i] = '\0';
485 } else {
486 mPoints[mPointCount].mFlagDataSecret[flagIndex][i] = '\0';
487 }
488 if (i > 0) {
489 if (regularExit) {
490 mPoints[mPointCount].mFlagDataNumRegular++;
491 } else {
492 mPoints[mPointCount].mFlagDataNumSecret++;
493 }
494 }
495 break;
496 }
497 if (regularExit) {
498 mPoints[mPointCount].mFlagDataRegular[flagIndex][i] = csv[pos];
499 } else {
500 mPoints[mPointCount].mFlagDataSecret[flagIndex][i] = csv[pos];
501 }
502 i++;
503 pos++;
504 }
505 if (csv[pos] == '\"') {
506 pos++;
507 break;
508 }
509 if (!isStr && csv[pos] == ',' || csv[pos] == '\r' && csv[pos + 1] == '\n') {
510 if (i == 0 && csv[pos] == ',') {
511 pos++;
512 }
513 break;
514 }
515 flagIndex++;
516 pos++;
517 }
518}
519
520void dCsvData_c::ReadAnimeRouteName(char *csv, int &pos) {
521 SubRoute_s *firstFreeRoute = &mSubRoutes[mSubrouteCount];
522
523 char buf[MAX_ROUTE_NAME_LEN];
524 int len = read(buf, &csv[pos], sizeof(buf));
525
526 bool found = false;
527 for (int i = 0; i < mSubrouteCount - 1; i++) {
528 if (strncmp(mSubRoutes[i].mName, buf, sizeof(buf)) == 0) {
529 found = true;
530 }
531 }
532 if (!found) {
533 // Add if doesn't exist yet
534 strncpy(firstFreeRoute->mName, buf, sizeof(firstFreeRoute->mName));
535 }
536
537 pos += len;
538}
539
540void dCsvData_c::ReadAction(char *csv, int &pos) {
541 char buf[20];
542 pos += read(buf, &csv[pos], sizeof(buf));
543
544 // [Must have some static local here based on symbol names...]
545 static int unusedLocal[] = { 0, 0, 0, 0 };
546
547 static const char *l_actionName[] = {
548 CSV_ACTION_ROAD,
549 CSV_ACTION_SAND,
550 CSV_ACTION_WOOD,
551 CSV_ACTION_JUMP,
552 CSV_ACTION_LADDER,
553 CSV_ACTION_VINE,
554 CSV_ACTION_SLOPE,
555 CSV_ACTION_ICE_SLOPE,
556 CSV_ACTION_SWITCH_BLOCK,
557 CSV_ACTION_QUICKSAND,
558 CSV_ACTION_SNOW,
559 CSV_ACTION_ICE,
560 CSV_ACTION_CLOUD,
561 CSV_ACTION_WATER,
562 CSV_ACTION_RIGHT_LADDER,
563 CSV_ACTION_LEFT_LADDER,
564 CSV_ACTION_ROCK_LADDER,
565 CSV_ACTION_ROPE_LADDER,
566 CSV_ACTION_DIRT,
567 nullptr
568 };
569
570 static const ActionType_e l_actionType[] = {
571 ACTION_TYPE_ROAD,
572 ACTION_TYPE_SAND,
573 ACTION_TYPE_WOOD,
574 ACTION_TYPE_JUMP,
575 ACTION_TYPE_LADDER,
576 ACTION_TYPE_VINE,
577 ACTION_TYPE_SLOPE,
578 ACTION_TYPE_ICE_SLOPE,
579 ACTION_TYPE_SWITCH_BLOCK,
580 ACTION_TYPE_QUICKSAND,
581 ACTION_TYPE_SNOW,
582 ACTION_TYPE_ICE,
583 ACTION_TYPE_CLOUD,
584 ACTION_TYPE_WATER,
585 ACTION_TYPE_RIGHT_LADDER,
586 ACTION_TYPE_LEFT_LADDER,
587 ACTION_TYPE_ROCK_LADDER,
588 ACTION_TYPE_ROPE_LADDER,
589 ACTION_TYPE_DIRT,
590 };
591
592 if (mSubRoutes[mSubrouteCount].mName[0] != '0') {
593 int i = 0;
594 while (l_actionName[i] != nullptr) {
595 if (strcmp(l_actionName[i], buf) == 0) {
596 mSubRoutes[mSubrouteCount].mActionType = l_actionType[i];
597 break;
598 }
599 i++;
600 }
601 }
602}
603
604void dCsvData_c::ReadRouteFlag(char *csv, int &pos) {
605 if (csv[pos] == '\r' && csv[pos + 1] == '\n') {
606 return;
607 }
608
609 bool isStr = false;
610 if (csv[pos] == '"') {
611 isStr = true;
612 pos++;
613 }
614 while (true) {
615 int i = 0;
616 char buf[40];
617 while (true) {
618 if (csv[pos] == ',' || csv[pos] == '"' || csv[pos] == '\r' && csv[pos + 1] == '\n') {
619 buf[i] = '\0';
620 break;
621 }
622 buf[i] = csv[pos];
623 i++;
624 pos++;
625 }
626 if (mSubRoutes[mSubrouteCount].mName[0] != '0') {
627 if (strcmp(buf, "A") == 0) {
628 mSubRoutes[mSubrouteCount].mFlags |= BIT_FLAG(0);
629 } else if (strcmp(buf, "B") == 0) {
630 mSubRoutes[mSubrouteCount].mFlags |= BIT_FLAG(1);
631 } else if (strcmp(buf, "C") == 0) {
632 mSubRoutes[mSubrouteCount].mFlags |= BIT_FLAG(2);
633 }
634 }
635 if (csv[pos] == '\"') {
636 pos++;
637 break;
638 }
639 if (!isStr && csv[pos] == ',' || csv[pos] == '\r' && csv[pos + 1] == '\n') {
640 break;
641 }
642 pos++;
643 }
644}
645
647 for (int i = 0; i < mSubrouteCount; i++) {
648 if (strcmp(mSubRoutes[i].mName, route) == 0) {
649 return mSubRoutes[i].mActionType;
650 }
651 }
652 return ACTION_TYPE_NONE;
653}
654
655int dCsvData_c::GetIndexFromPointName(const char *pointName) {
656 for (int i = 0; i < mPointCount; i++) {
657 if (strcmp(mPoints[i].mName, pointName) == 0) {
658 return i;
659 }
660 }
661 return -1;
662}
663
665 nw4r::g3d::ResMdl res = model.getResMdl();
666 for (int i = 0; i < res.GetResNodeNumEntries(); i++) {
667 nw4r::g3d::ResNode node = res.GetResNode(i);
668 const char *name = node.GetName();
669 if (name[0] == 'K') {
670 strncpy(mPoints[mPointCount].mName, name, sizeof(mPoints[mPointCount].mName));
671 mPointCount++;
672 }
673 }
674}
675
677 nw4r::g3d::ResMdl res = model.getResMdl();
678 for (int i = 0; i < res.GetResNodeNumEntries(); i++) {
679 nw4r::g3d::ResNode node = res.GetResNode(i);
680 const char *name = node.GetName();
681 if (strlen(name) != 9) {
682 continue;
683 }
684 if (name[0] == 'R' && name[4] >= '0' && name[4] <= '9' && name[8] >= '0' && name[8] <= '9') {
685 strncpy(mRoutes[mRouteCount].mName, name, sizeof(mRoutes[mRouteCount].mName));
686
687 char startPoint[MAX_POINT_NAME_LEN];
688 char endPoint[MAX_POINT_NAME_LEN];
689 dWmLib::GetStartPointNameFromRouteName(mRoutes[mRouteCount].mName, startPoint);
690 dWmLib::GetEndPointNameFromRouteName(mRoutes[mRouteCount].mName, endPoint);
691
693 findSubRoutesForRoute(startPoint, endPoint, &mRoutes[mRouteCount], 20);
694 appendChildFromSubRoute(startPoint, endPoint, &mRoutes[mRouteCount], 20);
695
696 mRouteCount++;
697
700 }
701 }
702}
703
704const char *dCsvData_c::GetPointName(int idx) const {
705 return mPoints[idx].mName;
706}
707
708const char *dCsvData_c::GetOpenPointName(bool regularExit, int idx, int openPointIdx) const {
709 if (regularExit) {
710 return mPoints[idx].mOpenPointNameRegular[openPointIdx];
711 } else {
712 return mPoints[idx].mOpenPointNameSecret[openPointIdx];
713 }
714}
715
716int dCsvData_c::GetOpenPointNum(bool regularExit, int idx) const {
717 if (regularExit) {
718 return mPoints[idx].mOpenPointNumRegular;
719 } else {
720 return mPoints[idx].mOpenPointNumSecret;
721 }
722}
723
724const char *dCsvData_c::GetOpenRouteName(bool regularExit, int idx, int openRouteIdx) const {
725 if (regularExit) {
726 return mPoints[idx].mRouteNameRegular[openRouteIdx];
727 } else {
728 return mPoints[idx].mRouteNameSecret[openRouteIdx];
729 }
730}
731
732int dCsvData_c::GetOpenRouteNum(bool regularExit, int idx) const {
733 if (regularExit) {
734 return mPoints[idx].mOpenRouteNumRegular;
735 } else {
736 return mPoints[idx].mOpenRouteNumSecret;
737 }
738}
739
740u32 dCsvData_c::GetPointFlags(int idx, PointFlag_e flags) const {
741 return mPoints[idx].mFlags & flags;
742}
743
745 return mPoints[idx].mFlagsEnemy & flags;
746}
747
749 return mPoints[idx].mParam;
750}
751
752const char *dCsvData_c::GetRouteName(int idx) {
753 return mRoutes[idx].mName;
754}
755
756const char *dCsvData_c::GetChildPointName(int idx, int childIdx) {
757 return mRoutes[idx].mChildPoints[childIdx];
758}
759
760const char *dCsvData_c::GetSubRouteName(int idx) {
761 return mSubRoutes[idx].mName;
762}
763
764int dCsvData_c::GetSubRouteIdx(const char *pointA, const char *pointB) {
765 int i = 0;
766 while (i < mSubrouteCount) {
767 const char *subRoutePointA = &GetSubRouteName(i)[1];
768 const char *subRoutePointB = &GetSubRouteName(i)[5];
769 if (
770 strncmp(subRoutePointA, pointA, 4) == 0 && strncmp(subRoutePointB, pointB, 4) == 0 ||
771 strncmp(subRoutePointB, pointA, 4) == 0 && strncmp(subRoutePointA, pointB, 4) == 0
772 ) {
773 return i;
774 }
775 i++;
776 }
777 return -1;
778}
779
781 return mRoutes[idx].mChildPointNum;
782}
783
785 return mSubRoutes[idx].mFlags;
786}
787
788int dCsvData_c::GetRouteAnimNum(bool regularExit, int idx) {
789 if (regularExit) {
790 return mPoints[idx].mFlagDataNumRegular;
791 } else {
792 return mPoints[idx].mFlagDataNumSecret;
793 }
794}
795
796const char *dCsvData_c::GetRouteAnimName(bool regularExit, int idx, int animIdx) {
797 if (regularExit) {
798 return mPoints[idx].mFlagDataRegular[animIdx];
799 } else {
800 return mPoints[idx].mFlagDataSecret[animIdx];
801 }
802}
803
804void dCsvData_c::initRouteStruct(Route_s *route, int childCount) {
805 route->mChildPoints = new char[childCount][MAX_POINT_NAME_LEN];
806 for (int i = 0; i < childCount; i++) {
807 memset(route->mChildPoints[i], 0, MAX_POINT_NAME_LEN);
808 }
809 route->mChildPointNum = 0;
810 route->mNumSubroutes = 99999;
811}
812
814 delete[] route->mChildPoints;
815}
816
817bool dCsvData_c::appendChildFromSubRoute(const char *startPointName, const char *endPointName, Route_s *route, int maxLevel, bool resetLevel) {
818 static int s_Level = 0;
819 bool success = false;
820
821 if (resetLevel) {
822 s_Level = 0;
823 }
824
825 s_Level++;
826 if (s_Level >= maxLevel) {
827 s_Level--;
828 return false;
829 }
830
831 for (int i = 0; i < mSubrouteCount; i++) {
832 char routeStartPoint[MAX_POINT_NAME_LEN];
833 char routeEndPoint[MAX_POINT_NAME_LEN];
834
835 dWmLib::GetStartPointNameFromRouteName(mSubRoutes[i].mName, routeStartPoint);
836 if (strncmp(routeStartPoint, startPointName, ARRAY_MAX_STRLEN(routeStartPoint)) == 0) {
837 dWmLib::GetEndPointNameFromRouteName(mSubRoutes[i].mName, routeEndPoint);
838 if (strncmp(routeEndPoint, endPointName, ARRAY_MAX_STRLEN(routeEndPoint)) == 0) {
839 if (route->mNumSubroutes == s_Level) {
840 success = true;
841 }
842 break;
843 }
844
845 if (appendChildFromSubRoute(routeEndPoint, endPointName, route, maxLevel, false)) {
846 strncpy(route->mChildPoints[route->mChildPointNum], routeEndPoint, ARRAY_MAX_STRLEN(route->mChildPoints[route->mChildPointNum]));
847 route->mChildPoints[route->mChildPointNum][5] = '0'; // [Not sure what this is... this also writes out-of-bounds!]
848 route->mChildPointNum++;
849 success = true;
850 break;
851 }
852 }
853 }
854 s_Level--;
855
856 return success;
857}
858
859bool dCsvData_c::findSubRoutesForRoute(const char *startPointName, const char *endPointName, Route_s *route, int maxLevel, bool resetLevel) {
860 static int s_Level = 0;
861
862 if (resetLevel) {
863 s_Level = 0;
864 }
865
866 bool success = false;
867 s_Level++;
868 if (s_Level >= maxLevel) {
869 s_Level--;
870 return false;
871 }
872
873 for (int i = 0; i < mSubrouteCount; i++) {
874 char routeStartPoint[MAX_POINT_NAME_LEN];
875 char routeEndPoint[MAX_POINT_NAME_LEN];
876
877 dWmLib::GetStartPointNameFromRouteName(mSubRoutes[i].mName, routeStartPoint);
878 if (strncmp(routeStartPoint, startPointName, ARRAY_MAX_STRLEN(routeStartPoint)) == 0) {
879 dWmLib::GetEndPointNameFromRouteName(mSubRoutes[i].mName, routeEndPoint);
880 if (strncmp(routeEndPoint, endPointName, ARRAY_MAX_STRLEN(routeEndPoint)) == 0) {
881 if (route->mNumSubroutes > s_Level) {
882 route->mNumSubroutes = s_Level;
883 }
884 success = true;
885 break;
886 }
887
888 findSubRoutesForRoute(routeEndPoint, endPointName, route, maxLevel, false);
889 }
890 }
891
892 s_Level--;
893
894 return success;
895}
896
897void dCsvData_c::appendChildFromModel(const nw4r::g3d::ResNode &node, int routeIdx) {
898 // [Fake match...]
899 nw4r::g3d::ResNodeData *nodeData = (nw4r::g3d::ResNodeData *) (node.ptr());
900 nw4r::g3d::ResNode curr;
901
902 curr = nw4r::g3d::ResNode(nodeData).GetChildNode();
903 int count = 0;
904 while (curr.IsValid()) {
905 count++;
906 curr = curr.GetChildNode();
907 }
908
909 if (count < mRoutes[routeIdx].mChildPointNum) {
910 return;
911 }
912
913 curr = nw4r::g3d::ResNode(nodeData).GetChildNode();
914 mRoutes[routeIdx].mChildPointNum = 0;
915 while (curr.IsValid()) {
916 strncpy(mRoutes[routeIdx].mChildPoints[mRoutes[routeIdx].mChildPointNum], curr.GetName(), MAX_POINT_NAME_LEN);
917 mRoutes[routeIdx].mChildPointNum++;
918 curr = curr.GetChildNode();
919 }
920}
921
923 static char s_Tmp[MAX_POINT_NAME_LEN + 1];
924
925 int pointNum = route->mChildPointNum;
926 if (pointNum > 1) {
927 for (int i = 0; i < pointNum / 2; i++) {
928 int otherIdx = pointNum - i - 1;
929 strncpy(s_Tmp, route->mChildPoints[i], MAX_POINT_NAME_LEN);
930 strncpy(route->mChildPoints[i], route->mChildPoints[otherIdx], MAX_POINT_NAME_LEN);
931 strncpy(route->mChildPoints[otherIdx], s_Tmp, MAX_POINT_NAME_LEN);
932 }
933 }
934}
935
936bool dCsvData_c::isLineEnd(char *csv, int pos) {
937 bool lineEnd = false;
938 if (csv[pos] == '\r' && csv[pos + 1] == '\n') {
939 lineEnd = true;
940 }
941 return lineEnd;
942}
u32 GetPointFlags(int idx, PointFlag_e flags) const
Returns the flags ANDed with flags.
Route_s mRoutes[(64)]
The loaded route data.
SubRoute_s mSubRoutes[(160)]
The loaded subroute data.
int GetOpenPointNum(bool regularExit, int idx) const
Returns the number of points that are opened from a regular or secret exit from this point.
bool findSubRoutesForRoute(const char *startPointName, const char *endPointName, Route_s *route, int maxLevel, bool resetLevel=true)
Searches the subroute graph for a path between two points and writes the length of the path to route.
virtual ~dCsvData_c()
Destroys the class.
bool isLineEnd(char *csv, int pos)
Returns whether the the CSV has a line ending at the specified position.
const char * GetRouteAnimName(bool regularExit, int idx, int animIdx)
Returns the value of a flag data entry for a point.
ActionType_e GetActionLabel(const char *route)
Gets the action type for a given route name.
const char * GetOpenRouteName(bool regularExit, int idx, int openRouteIdx) const
Returns the name of a route that is opened from a regular or secret exit from this point.
int GetPointNum(int idx)
Returns the number of points that are part of a route at the specified index.
void ReadPointType(char *csv, int &pos)
Reads a point type from a CSV entry.
int mWorld
The world number for which to load the point and route data.
void RouteInfoInit()
Resets all currently loaded point and route data.
int GetOpenRouteNum(bool regularExit, int idx) const
Returns the number of routes that are opened from a regular or secret exit from this point.
const char * GetChildPointName(int idx, int childIdx)
Returns the name of a point that is part of a route at the specified index.
void ReadRouteFlag(char *csv, int &pos)
Reads the route flag data from a CSV entry.
int mSubrouteCount
The number of loaded subroutes in mSubRoutes.
int mRouteCount
The number of loaded routes in mRoutes.
void ReadOpenRouteName(char *csv, int &pos, bool regularExit)
Reads an open route name from a CSV entry.
u32 GetSubRouteFlag(int idx)
Returns the flags for a route at the specified index.
int GetSubRouteIdx(const char *pointA, const char *pointB)
Returns the index of a route connecting two points.
int mPointCount
The number of loaded points in mPoints.
void ReadPointName(char *csv, int &pos)
Reads a point name from a CSV entry.
const char * GetPointName(int idx) const
Returns the name of a point at the specified index.
const char * GetOpenPointName(bool regularExit, int idx, int openPointIdx) const
Returns the name of a point that is opened from a regular or secret exit from this point.
void SetRouteInfo(const m3d::mdl_c &model)
Creates a route from a model and adds it to the route list.
void initialize(int world, int subworld)
Initializes the class and loads the CSV data for the specified world and subworld.
void ReadOpenPointName(char *csv, int &pos, bool regularExit)
Reads an open point name from a CSV entry.
u32 GetEnemyPointFlags(int idx, EnemyFlag_e flags) const
Returns the enemy flags ANDed with flags.
static void initRouteStruct(Route_s *route, int childCount)
Initializes a route with the specified number of child points.
void ReadCsvData()
Loads the CSV point and route data for the specified world and subworld.
void ReadAnimeRouteName(char *csv, int &pos)
Reads a route name from a CSV entry.
const char * GetRouteName(int idx)
Returns the name of a route at the specified index.
int GetIndexFromPointName(const char *pointName)
Gets the index of a point.
Point_s mPoints[(192)]
The loaded point data.
const char * GetSubRouteName(int idx)
Returns the name of a subroute at the specified index.
bool appendChildFromSubRoute(const char *startPointName, const char *endPointName, Route_s *route, int maxLevel, bool resetLevel=true)
Searches the subroute graph for a path between two points and appends the child points to route.
int GetRouteAnimNum(bool regularExit, int idx)
Returns the number of flag data entries for a point.
int mSubworld
The subworld number for which to load the point and route data.
void appendChildFromModel(const nw4r::g3d::ResNode &node, int)
Appends the child points of a route from a model to route.
void ReadFlagData(char *csv, int &pos, bool regularExit)
Reads the point flag data from a CSV entry.
static void destroyRouteStruct(Route_s *route)
Destroys a route and frees its child point data.
void ReadAction(char *csv, int &pos)
Reads a route action type from a CSV entry.
void addKeyPoint(const m3d::mdl_c &model)
Adds a key point from a model.
u32 GetPointParam(int idx)
Returns the parameter value for this point.
void adjustChildInfo(Route_s *route)
Reverses the order of the child points of a route.
A higher-level archive resource management class.
Definition d_res_mng.hpp:10
nw4r::g3d::ResFile getRes(const char *arcName, const char *resPath) const
Gets a resource.
Definition d_res_mng.hpp:42
static dResMng_c * m_instance
The instance of this class.
Definition d_res_mng.hpp:71
nw4r::g3d::ResFile getResSilently(const char *arcName, const char *resPath) const
Gets a resource without logging a message if the resource is not found.
Definition d_res_mng.hpp:52
int read(char *buffer, const char *csv, int bufferSize)
Reads a single CSV field into a buffer.
@ STAGE_START_KINOKO_HOUSE
The toad house on the starting node of each world.
Contains the points of a route on the world map.
int mChildPointNum
The number of occupied entries in mChildPoints.
char(* mChildPoints)[(5)]
The points that make up the route.
int mNumSubroutes
The number of subroutes this route is made up of.
Contains the data for a point-to-point route on the world map.
char mName[(10)]
The name of the route.