marioparty4/src/game/board/com.c
2025-05-13 20:17:15 -05:00

800 lines
21 KiB
C
Executable file

#include "game/board/com.h"
#include "game/gamework.h"
#include "game/gamework_data.h"
#include "game/board/com_path.h"
#include "game/board/main.h"
#include "game/board/player.h"
#include "game/board/space.h"
#include "game/board/tutorial.h"
#include "game/board/window.h"
#include "game/board/boo.h"
#include "game/chrman.h"
#include "ext_math.h"
typedef BOOL (*UseCheckFunc)(s32 player, s32 item);
static void ExecComKeyLeft(void);
static void ExecComKeyRight(void);
static void ExecComKeyUp(void);
static void ExecComKeyDown(void);
static void ExecComKey(s32 player, s32 move, s32 vertical);
static s32 ChooseUseItem(s32 player);
static BOOL CheckMiniUse(s32 player, s32 item);
static BOOL CheckMegaUse(s32 player, s32 item);
static BOOL CheckSparkUse(s32 player, s32 item);
static BOOL CheckBoardChangeUse(s32 player, s32 item);
static BOOL CheckSwapUse(s32 player, s32 item);
static BOOL CheckBooUse(s32 player, s32 item);
static BOOL CheckLampUse(s32 player, s32 item);
static s8 itemUse = -1;
#define BOARD_ITEM_MINI_MUSHROOM 0
#define BOARD_ITEM_MEGA_MUSHROOM 1
#define BOARD_ITEM_SUPER_MINI_MUSHROOM 2
#define BOARD_ITEM_SUPER_MEGA_MUSHROOM 3
#define BOARD_ITEM_MINI_MEGA_HAMMER 4
#define BOARD_ITEM_WARP_PIPE 5
#define BOARD_ITEM_SWAP_CARD 6
#define BOARD_ITEM_SPARKY_STICKER 7
#define BOARD_ITEM_GADDLIGHT 8
#define BOARD_ITEM_CHOMP_CALL 9
#define BOARD_ITEM_BOWSER_SUIT 10
#define BOARD_ITEM_BOOS_CRYSTAL_BALL 11
#define BOARD_ITEM_MAGIC_LAMP 12
#define SHOP_ITEMS_END BOARD_ITEM_MAGIC_LAMP
#define BOARD_ITEM_ITEM_BAG 13
#define BOARD_ITEMS_END BOARD_ITEM_ITEM_BAG
static s8 comItemPreferTbl[CHARNO_MAX ][SHOP_ITEMS_END] = {
{ //Mario
BOARD_ITEM_MAGIC_LAMP,
BOARD_ITEM_BOOS_CRYSTAL_BALL,
BOARD_ITEM_WARP_PIPE,
BOARD_ITEM_SUPER_MEGA_MUSHROOM,
BOARD_ITEM_MEGA_MUSHROOM,
BOARD_ITEM_SUPER_MINI_MUSHROOM,
BOARD_ITEM_SWAP_CARD,
BOARD_ITEM_MINI_MEGA_HAMMER,
BOARD_ITEM_MINI_MUSHROOM,
BOARD_ITEM_SPARKY_STICKER,
BOARD_ITEM_CHOMP_CALL,
BOARD_ITEM_BOWSER_SUIT
},
{ //Luigi
BOARD_ITEM_MAGIC_LAMP,
BOARD_ITEM_BOOS_CRYSTAL_BALL,
BOARD_ITEM_WARP_PIPE,
BOARD_ITEM_BOWSER_SUIT,
BOARD_ITEM_SUPER_MEGA_MUSHROOM,
BOARD_ITEM_MEGA_MUSHROOM,
BOARD_ITEM_SUPER_MINI_MUSHROOM,
BOARD_ITEM_MINI_MUSHROOM,
BOARD_ITEM_SWAP_CARD,
BOARD_ITEM_MINI_MEGA_HAMMER,
BOARD_ITEM_SPARKY_STICKER,
BOARD_ITEM_CHOMP_CALL
},
{ //Peach
BOARD_ITEM_MAGIC_LAMP,
BOARD_ITEM_BOOS_CRYSTAL_BALL,
BOARD_ITEM_WARP_PIPE,
BOARD_ITEM_SWAP_CARD,
BOARD_ITEM_SUPER_MEGA_MUSHROOM,
BOARD_ITEM_MEGA_MUSHROOM,
BOARD_ITEM_SUPER_MINI_MUSHROOM,
BOARD_ITEM_BOWSER_SUIT,
BOARD_ITEM_SPARKY_STICKER,
BOARD_ITEM_CHOMP_CALL,
BOARD_ITEM_MINI_MUSHROOM,
BOARD_ITEM_MINI_MEGA_HAMMER
},
{ //Yoshi
BOARD_ITEM_MAGIC_LAMP,
BOARD_ITEM_WARP_PIPE,
BOARD_ITEM_BOOS_CRYSTAL_BALL,
BOARD_ITEM_CHOMP_CALL,
BOARD_ITEM_SUPER_MEGA_MUSHROOM,
BOARD_ITEM_MEGA_MUSHROOM,
BOARD_ITEM_SUPER_MINI_MUSHROOM,
BOARD_ITEM_SWAP_CARD,
BOARD_ITEM_MINI_MUSHROOM,
BOARD_ITEM_MINI_MEGA_HAMMER,
BOARD_ITEM_BOWSER_SUIT,
BOARD_ITEM_SPARKY_STICKER
},
{ //Wario
BOARD_ITEM_MAGIC_LAMP,
BOARD_ITEM_BOOS_CRYSTAL_BALL,
BOARD_ITEM_MINI_MEGA_HAMMER,
BOARD_ITEM_CHOMP_CALL,
BOARD_ITEM_BOWSER_SUIT,
BOARD_ITEM_SUPER_MEGA_MUSHROOM,
BOARD_ITEM_MEGA_MUSHROOM,
BOARD_ITEM_WARP_PIPE,
BOARD_ITEM_SUPER_MINI_MUSHROOM,
BOARD_ITEM_SWAP_CARD,
BOARD_ITEM_MINI_MUSHROOM,
BOARD_ITEM_SPARKY_STICKER
},
{ //DK
BOARD_ITEM_MAGIC_LAMP,
BOARD_ITEM_BOOS_CRYSTAL_BALL,
BOARD_ITEM_WARP_PIPE,
BOARD_ITEM_SUPER_MEGA_MUSHROOM,
BOARD_ITEM_MEGA_MUSHROOM,
BOARD_ITEM_BOWSER_SUIT,
BOARD_ITEM_SWAP_CARD,
BOARD_ITEM_SUPER_MINI_MUSHROOM,
BOARD_ITEM_MINI_MUSHROOM,
BOARD_ITEM_MINI_MEGA_HAMMER,
BOARD_ITEM_CHOMP_CALL,
BOARD_ITEM_SPARKY_STICKER
},
{ //Daisy
BOARD_ITEM_MAGIC_LAMP,
BOARD_ITEM_WARP_PIPE,
BOARD_ITEM_BOOS_CRYSTAL_BALL,
BOARD_ITEM_MINI_MEGA_HAMMER,
BOARD_ITEM_SPARKY_STICKER,
BOARD_ITEM_CHOMP_CALL,
BOARD_ITEM_SUPER_MEGA_MUSHROOM,
BOARD_ITEM_MEGA_MUSHROOM,
BOARD_ITEM_BOWSER_SUIT,
BOARD_ITEM_SWAP_CARD,
BOARD_ITEM_SUPER_MINI_MUSHROOM,
BOARD_ITEM_MINI_MUSHROOM
},
{ //Waluigi
BOARD_ITEM_MAGIC_LAMP,
BOARD_ITEM_WARP_PIPE,
BOARD_ITEM_SPARKY_STICKER,
BOARD_ITEM_BOOS_CRYSTAL_BALL,
BOARD_ITEM_BOWSER_SUIT,
BOARD_ITEM_CHOMP_CALL,
BOARD_ITEM_MINI_MEGA_HAMMER,
BOARD_ITEM_SWAP_CARD,
BOARD_ITEM_SUPER_MEGA_MUSHROOM,
BOARD_ITEM_MEGA_MUSHROOM,
BOARD_ITEM_SUPER_MINI_MUSHROOM,
BOARD_ITEM_MINI_MUSHROOM
}
};
static UseCheckFunc comItemUseCheckFuncTbl[] = {
CheckMiniUse,
CheckMegaUse,
CheckMiniUse,
CheckMegaUse,
CheckBoardChangeUse,
CheckBoardChangeUse,
CheckSwapUse,
CheckSparkUse,
NULL,
CheckBoardChangeUse,
NULL,
CheckBooUse,
CheckLampUse,
NULL
};
static Vec comJunctionDirTbl[] = {
{ 0.0f, 0.0f, -72.0f },
{ 90.0f, 72.0f, 0.0f },
{ 180.0f, 0.0f, 72.0f },
{ 270.0f, -72.0f, 0.0f }
};
static void ExecComKeyLeft(void) {
ExecComKey(GWSystem.player_curr, 0, 1);
}
void BoardComKeySetLeft(void) {
BoardWinComKeyFuncSet(ExecComKeyLeft);
}
static void ExecComKeyRight(void) {
ExecComKey(GWSystem.player_curr, 1, 1);
}
void BoardComKeySetRight(void) {
BoardWinComKeyFuncSet(ExecComKeyRight);
}
static void ExecComKeyUp(void) {
ExecComKey(GWSystem.player_curr, 0, 0);
}
void BoardComKeySetUp(void) {
BoardWinComKeyFuncSet(ExecComKeyUp);
}
static void ExecComKeyDown(void) {
ExecComKey(GWSystem.player_curr, 1, 0);
}
void BoardComKeySetDown(void) {
BoardWinComKeyFuncSet(ExecComKeyDown);
}
static void ExecComKey(s32 player, s32 move, s32 vertical) {
s32 comkey[4];
s32 port;
s16 delay;
s32 dpad;
comkey[0] = comkey[1] = comkey[2] = comkey[3] = 0;
port = GWPlayer[player].port;
delay = GWMessDelayGet();
if (vertical == 0) {
dpad = PAD_BUTTON_DOWN;
} else {
dpad = PAD_BUTTON_RIGHT;
}
if (move == 1) {
comkey[port] = dpad;
HuWinComKeyWait(comkey[0], comkey[1], comkey[2], comkey[3], delay);
}
comkey[port] = 0x100;
HuWinComKeyWait(comkey[0], comkey[1], comkey[2], comkey[3], delay);
}
s8 BoardComPreferItemGet(s32 player, s8 *items, s8 num_items) {
s32 character;
s32 weight;
s32 item;
s32 prefer;
s32 i;
s32 j;
character = GWPlayer[player].character;
prefer = -1;
weight = 100;
for (i = 0; i < num_items; i++) {
item = items[i];
for (j = 0; j < SHOP_ITEMS_END; j++) {
if (item == comItemPreferTbl[character][j]) {
if (j < weight && (BoardPlayerItemFind(player, item) == -1 || item == BOARD_ITEM_MAGIC_LAMP || item == BOARD_ITEM_BOOS_CRYSTAL_BALL)) {
weight = j;
prefer = i;
}
break;
}
}
}
if (weight == 100) {
return -1;
}
return prefer;
}
s8 BoardComPreferItemCheck(s32 player, s8 item1, s8 item2, s8 item3) {
s8 items[3];
s8 prefer;
items[0] = item1;
items[1] = item2;
items[2] = item3;
prefer = BoardComPreferItemGet(player, items, 3);
return prefer;
}
s32 BoardComItemWeightGet(s32 player, s32 item) {
s32 weight;
s32 i;
for (i = 0; i < SHOP_ITEMS_END; i++) {
if (item == comItemPreferTbl[GWPlayer[player].character][i]) {
break;
}
}
weight = 12-1-i;
return weight;
}
s32 BoardComUseItemSlotGet(s32 player) {
s32 slot;
s32 item;
if (!GWPlayer[player].com) {
return -1;
}
if (itemUse != -1) {
item = itemUse;
}
if (boardTutorialUseItem >= 0 && boardTutorialUseItem <= 13) {
item = boardTutorialUseItem;
boardTutorialUseItem = -1;
}
if (item != -1) {
slot = BoardPlayerItemFind(player, item);
} else {
slot = -1;
}
return slot;
}
s32 BoardComUseItemSet(s32 player, s32 item) {
if (item == -1) {
itemUse = -1;
return 1;
}
if (BoardPlayerItemFind(player, item) != -1) {
itemUse = item;
return 1;
}
return 0;
}
BOOL BoardComUseItemCheck(s32 player) {
s32 count;
count = BoardPlayerItemCount(player);
if (count <= 0) {
return FALSE;
}
if (ChooseUseItem(player) != -1) {
return TRUE;
}
return FALSE;
}
static s32 ChooseUseItem(s32 player) {
s32 i;
s32 j;
s32 useItem;
s32 weight;
s32 item;
s32 character;
UseCheckFunc func;
s8 result;
useItem = -1;
character = GWPlayer[player].character;
weight = 100;
for (i = 0; i < 3; i++) {
item = GWPlayer[player].items[i];
if (item == -1) {
continue;
}
func = comItemUseCheckFuncTbl[item];
if (!func) {
continue;
}
result = func(player, item);
if (result) {
for (j = 0; j < SHOP_ITEMS_END; j++) {
if (item == comItemPreferTbl[character][j]) {
if (j < weight) {
weight = j;
}
break;
}
}
}
}
if (weight == 100) {
return -1;
}
useItem = comItemPreferTbl[character][weight];
if (useItem == -1) {
itemUse = -1;
} else if (BoardPlayerItemFind(player, useItem) != -1) {
itemUse = useItem;
}
return useItem;
}
static BOOL CheckMiniUse(s32 player, s32 item) {
s32 space;
s32 star_dist_pipe;
s32 star_dist_no_pipe;
s32 diff;
s32 character;
s32 force_use_mini;
s32 max_dist;
s32 chance;
force_use_mini = 0;
space = GWPlayer[player].space_curr;
diff = GWPlayer[player].diff;
character = GWPlayer[player].character;
switch (diff) {
case 0:
chance = 50;
break;
case 1:
chance = 25;
break;
case 2:
chance = 5;
break;
case 3:
chance = 0;
break;
}
if ((diff == 0 || diff == 1) && character == 1) {
chance = 7;
}
if (GWBoardGet() != BOARD_ID_EXTRA1 && GWBoardGet() != BOARD_ID_EXTRA2) {
star_dist_pipe = BoardComPathShortcutLenGet(space, 8, 0);
star_dist_no_pipe = BoardComPathShortcutLenGet(space, 8, 1);
} else {
star_dist_pipe = 999;
star_dist_no_pipe = BoardComPathBestGetFlag(space, 0x10000000, 10);
if ((GWBoardGet() == BOARD_ID_EXTRA2 || GWBoardGet() == BOARD_ID_EXTRA1) && BoardRandMod(100) < 60) {
force_use_mini = 1;
}
}
switch (GWPlayer[player].diff) {
case 0:
max_dist = 5;
break;
case 1:
max_dist = 7;
break;
case 2:
max_dist = 9;
break;
case 3:
max_dist = 10;
break;
}
if ((star_dist_no_pipe < max_dist || star_dist_pipe < max_dist || force_use_mini != 0) && BoardRandMod(100) >= chance) {
return TRUE;
}
return FALSE;
}
static BOOL CheckMegaUse(s32 player, s32 item) {
s32 short_len;
s32 character;
s32 space;
s32 diff;
s16 path_len;
s16 max_len;
s16 space_search;
s16 space_other;
s16 i;
diff = GWPlayer[player].diff;
character = GWPlayer[player].character;
switch (diff) {
case 0:
max_len = 5;
break;
case 1:
max_len = 7;
break;
case 2:
max_len = 9;
break;
case 3:
max_len = 10;
break;
}
if (((diff == 0 || diff == 1) && character == 0) || ((diff == 0 || diff == 1) && character == 5)) {
max_len = 8;
}
if (GWBoardGet() != BOARD_ID_EXTRA1 || BoardRandMod(100) >= 60) {
space = GWPlayer[player].space_curr;
short_len = BoardComPathShortcutLenGet(space, 8, 0);
space_search = GWPlayer[player].space_curr;
for (i = 0; i < 4; i++) {
if (i != player) {
space_other = GWPlayer[i].space_curr;
path_len = BoardComPathLenGet(space_search, space_other);
if (path_len < max_len + 20 && path_len > 0 && GWTeamGet() && i == BoardPlayerSameTeamFind(player)) {
return FALSE;
}
}
}
if (GWBoardGet() != BOARD_ID_EXTRA1 && GWBoardGet() != BOARD_ID_EXTRA2 && short_len < 10 && short_len > 0) {
return FALSE;
}
}
if (BoardPlayerItemFind(player, item) != -1) {
return TRUE;
}
return FALSE;
}
static BOOL CheckSparkUse(s32 player, s32 item) {
s32 length;
s32 diff;
s32 space_other;
s32 space;
s32 character;
s32 i;
s32 chance;
space = GWPlayer[player].space_curr;
diff = GWPlayer[player].diff;
character = GWPlayer[player].character;
switch (diff) {
case 0:
chance = 50;
break;
case 1:
chance = 25;
break;
case 2:
chance = 5;
break;
case 3:
chance = 0;
break;
}
if ((diff == 0 || diff == 1) && character == 7) {
chance = 7;
}
for (i = 0; i < 4; i++) {
if (i != player) {
space_other = GWPlayer[i].space_curr;
length = BoardComPathLenGet(space_other, space);
if (length > 0 && length <= 15 && BoardPlayerItemFind(player, item) != -1 && BoardRandMod(0x64) >= chance) {
return TRUE;
}
}
}
return FALSE;
}
static BOOL CheckBoardChangeUse(s32 player, s32 item) {
s32 diff;
s32 character;
s32 mini_len;
s32 non_mini_len;
s32 search_space;
s32 space;
s32 length_min;
s32 length;
s32 chance;
s32 i;
diff = GWPlayer[player].diff;
character = GWPlayer[player].character;
switch (diff) {
case 0:
chance = 0x32;
break;
case 1:
chance = 0x19;
break;
case 2:
chance = 5;
break;
case 3:
chance = 0;
break;
}
if (((item == 4 && character == 4) || (item == 5 && (character == 6 || character == 3))) && (diff == 0 || diff == 1)) {
chance = 7;
}
length_min = 999;
for (i = 0; i < 4; i++) {
if (player == i) {
continue;
}
search_space = GWPlayer[i].space_curr;
if (!GWTeamGet() || i != BoardPlayerSameTeamFind(player)) {
space = GWPlayer[i].space_curr;
if (GWBoardGet() == BOARD_ID_EXTRA1) {
if (BoardComPathBestGetFlag(search_space, 0x10000000, 10) != -1) {
length = 10;
} else {
length = 0;
}
} else if (GWBoardGet() == BOARD_ID_EXTRA2) {
if (BoardComPathBestGetFlag(search_space, 0x200000, 10) != -1 || BoardComPathBestGetFlag(search_space, 0x400000, 10) != -1) {
length = 10;
} else {
length = 0;
}
} else {
length = BoardComPathShortcutLenGet(space, 8, 0);
}
if (length != 0 && length < length_min) {
length_min = length;
}
}
}
if ((length_min > 0xF && length_min != 999) || (GWTeamGet() && i == BoardPlayerSameTeamFind(player))) {
return FALSE;
}
space = GWPlayer[player].space_curr;
mini_len = BoardComPathShortcutLenGet(space, 8, 0);
non_mini_len = BoardComPathShortcutLenGet(space, 8, 1);
if (BoardPlayerItemFind(player, item) != -1 && BoardRandMod(0x64) >= chance) {
if ((mini_len == 0 || non_mini_len == 0) && length_min == 999) {
return TRUE;
}
if (mini_len > length_min || non_mini_len > length_min) {
return TRUE;
}
if (mini_len > 10 || non_mini_len > 10) {
return TRUE;
}
}
return FALSE;
}
static BOOL CheckSwapUse(s32 player, s32 item) {
s32 diff;
s32 team_player;
s32 character;
s32 item_count;
s32 chance;
s32 i;
diff = GWPlayer[player].diff;
character = GWPlayer[player].character;
switch (diff) {
case 0:
chance = 0x32;
break;
case 1:
chance = 0x19;
break;
case 2:
chance = 5;
break;
case 3:
chance = 0;
break;
}
if ((diff == 0 || diff == 1) && character == 2) {
chance = 7;
}
for (item_count = i = 0; i < 4; i++) {
if (i != player) {
item_count += BoardPlayerItemCount(i);
}
}
if (item_count == 0) {
return FALSE;
}
if (GWTeamGet()) {
team_player = BoardPlayerSameTeamFind(player);
for (item_count = i = 0; i < 4; i++) {
if (team_player != i && i != player) {
item_count += BoardPlayerItemCount(i);
}
}
if (item_count == 0) {
return FALSE;
}
}
if (BoardPlayerItemFind(player, item) != -1 && BoardRandMod(0x64) >= chance) {
return TRUE;
}
return FALSE;
}
static BOOL CheckBooUse(s32 player, s32 item) {
if (BoardPlayerCoinsGet(player) < 5) {
return FALSE;
}
if (BoardBooComUseCheck(player) == 0) {
return FALSE;
}
if (BoardPlayerItemFind(player, item) == -1) {
return FALSE;
}
return TRUE;
}
static BOOL CheckLampUse(s32 player, s32 item) {
if ((BoardPlayerCoinsGet(player) >= 0x14 || GWSystem.last5_effect == 4) && BoardPlayerItemFind(player, item) != -1) {
return TRUE;
}
return FALSE;
}
s32 BoardComJunctionInputGet(s32 item, Vec *input, s32 num_dirs, float *dirs) {
Vec pos_next;
Vec pos_junction;
Vec dir;
float dist_min;
float dist;
float angle;
s32 chance_random;
s32 best_dir;
s32 board;
s32 path_unknown;
s32 choose_path;
s32 dir_random;
s32 i;
s16 space_next;
s16 space;
s16 roll;
board = GWBoardGet();
path_unknown = 0;
space = GWPlayer[item].space_curr;
space_next = -1;
roll = GWPlayer[item].roll;
switch (GWPlayer[item].diff) {
case 3:
chance_random = 0;
break;
case 2:
chance_random = 0;
break;
case 1:
chance_random = 10;
break;
default:
case 0:
chance_random = 0x1E;
break;
}
if (BoardRandMod(0x64) >= chance_random) {
choose_path = 1;
} else {
choose_path = 0;
}
if (choose_path != 0) {
if (board >= 0 && board <= 5) {
space_next = BoardComPathBestGet(space);
} else if (board == 7) {
space_next = BoardComPathBestGetFlag(space, 0x10000000, 10);
}
if (space_next == -1) {
path_unknown = 1;
} else {
BoardSpacePosGet(0, space, &pos_junction);
BoardSpacePosGet(0, space_next, &pos_next);
VECSubtract(&pos_next, &pos_junction, &dir);
angle = BoardDAngleCalc(90.0 - atan2d(dir.z, dir.x));
if (angle < 0.0f) {
angle += 360.0f;
}
if (angle > 360.0f) {
angle -= 360.0f;
}
}
}
if (path_unknown != 0) {
dir_random = BoardRandMod(num_dirs);
angle = dirs[dir_random];
}
dist_min = 999.0f;
for (best_dir = i = 0; i < 4; i++) {
dist = (comJunctionDirTbl[i].x - angle < 0.0f)
? -(comJunctionDirTbl[i].x - angle)
: (comJunctionDirTbl[i].x - angle);
if (dist < dist_min) {
best_dir = i;
dist_min = dist;
}
}
input->x = comJunctionDirTbl[best_dir].y;
input->z = comJunctionDirTbl[best_dir].z;
input->y = 0.0f;
return 0;
}
s32 BoardComFarPlayerFind(void) {
s32 len;
s32 max_len;
s32 far_player;
s32 space;
s32 i;
if (_CheckFlag(FLAG_ID_MAKE(1, 11)) != 0) {
return -1;
}
far_player = -1;
max_len = -1;
for (i = 0; i < 4; i++) {
space = GWPlayer[i].space_curr;
len = BoardComPathShortcutLenGet(space, 8, 0);
if (len > 0 && len > max_len) {
max_len = len;
far_player = i;
}
}
return far_player;
}