mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2025-01-07 08:01:16 +00:00
Synchronized inside-painting state
This commit is contained in:
parent
f32d3a2ba7
commit
4452b38848
10 changed files with 189 additions and 42 deletions
|
@ -3944,6 +3944,7 @@
|
|||
<ClCompile Include="..\src\pc\ini.c" />
|
||||
<ClCompile Include="..\src\pc\mixer.c" />
|
||||
<ClCompile Include="..\src\pc\network\network.c" />
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_inside_painting.c" />
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_level_warp.c" />
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_object.c" />
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_player.c" />
|
||||
|
|
|
@ -2761,13 +2761,12 @@ s16 render_sync_level_screen(void) {
|
|||
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
||||
|
||||
|
||||
// text
|
||||
// synchronizing text
|
||||
u8 colorFade = sins(gDialogColorFadeTimer) * 50.0f + 200.0f;
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
||||
gDPSetEnvColor(gDisplayListHead++, colorFade, colorFade, colorFade, 255);
|
||||
u8 synchronizing[] = { 0x1C,0x22,0x17,0x0C,0x11,0x1B,0x18,0x17,0x12,0x02,0x12,0x17,0x10,0xFF };
|
||||
// s y n c h r o n i z i n g \0
|
||||
print_hud_lut_string(HUD_LUT_GLOBAL, 70, 200, synchronizing);
|
||||
u8 synchronizing[] = { TEXT_SYNCHRONIZING };
|
||||
print_hud_lut_string(HUD_LUT_GLOBAL, 80, 200, synchronizing);
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -174,6 +174,11 @@ s8 D_8032C9E0 = 0;
|
|||
u8 unused3[4];
|
||||
u8 unused4[2];
|
||||
|
||||
u8 gInsidePainting = false;
|
||||
u8 gControlPainting = false;
|
||||
u8 gWaitingForRemotePainting = false;
|
||||
struct WarpNode gPaintingWarpNode = { 0 };
|
||||
|
||||
u16 level_control_timer(s32 timerOp) {
|
||||
switch (timerOp) {
|
||||
case TIMER_CONTROL_SHOW:
|
||||
|
@ -657,38 +662,48 @@ struct WarpNode *get_painting_warp_node(void) {
|
|||
*/
|
||||
void initiate_painting_warp(void) {
|
||||
if (gCurrentArea->paintingWarpNodes != NULL && gMarioState->floor != NULL) {
|
||||
struct WarpNode warpNode;
|
||||
struct WarpNode *pWarpNode = get_painting_warp_node();
|
||||
|
||||
if (pWarpNode != NULL) {
|
||||
if (gMarioState->action & ACT_FLAG_INTANGIBLE) {
|
||||
play_painting_eject_sound();
|
||||
} else if (pWarpNode->id != 0) {
|
||||
warpNode = *pWarpNode;
|
||||
|
||||
if (!(warpNode.destLevel & 0x80)) {
|
||||
D_8032C9E0 = check_warp_checkpoint(&warpNode);
|
||||
}
|
||||
|
||||
initiate_warp(warpNode.destLevel & 0x7F, warpNode.destArea, warpNode.destNode, 0);
|
||||
check_if_should_set_warp_checkpoint(&warpNode);
|
||||
|
||||
play_transition_after_delay(WARP_TRANSITION_FADE_INTO_COLOR, 30, 255, 255, 255, 45);
|
||||
level_set_transition(74, basic_update);
|
||||
|
||||
initiate_painting_warp_node(pWarpNode, false);
|
||||
gControlPainting = true;
|
||||
gWaitingForRemotePainting = true;
|
||||
set_mario_action(gMarioState, ACT_DISAPPEARED, 0);
|
||||
|
||||
gMarioState->marioObj->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
|
||||
|
||||
play_sound(SOUND_MENU_STAR_SOUND, gDefaultSoundArgs);
|
||||
fadeout_music(398);
|
||||
queue_rumble_data(80, 70);
|
||||
func_sh_8024C89C(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initiate_painting_warp_node(struct WarpNode *pWarpNode, u8 instant) {
|
||||
if (pWarpNode->id == 0) { return; }
|
||||
|
||||
gControlPainting = false;
|
||||
gWaitingForRemotePainting = false;
|
||||
gInsidePainting = true;
|
||||
|
||||
gPaintingWarpNode = *pWarpNode;
|
||||
struct WarpNode warpNode = *pWarpNode;
|
||||
|
||||
if (!(warpNode.destLevel & 0x80)) {
|
||||
D_8032C9E0 = check_warp_checkpoint(&warpNode);
|
||||
}
|
||||
|
||||
initiate_warp(warpNode.destLevel & 0x7F, warpNode.destArea, warpNode.destNode, 0);
|
||||
check_if_should_set_warp_checkpoint(&warpNode);
|
||||
|
||||
play_transition_after_delay(WARP_TRANSITION_FADE_INTO_COLOR, 30, 255, 255, 255, instant ? 1 : 45);
|
||||
level_set_transition(instant ? 1 : 74, basic_update);
|
||||
|
||||
play_sound(SOUND_MENU_STAR_SOUND, gDefaultSoundArgs);
|
||||
fadeout_music(398);
|
||||
queue_rumble_data(80, 70);
|
||||
func_sh_8024C89C(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is not already a delayed warp, schedule one. The source node is
|
||||
* based on the warp operation and sometimes Mario's used object.
|
||||
|
|
|
@ -65,6 +65,10 @@ extern struct CreditsEntry *gCurrCreditsEntry;
|
|||
|
||||
extern struct MarioState gMarioStates[];
|
||||
extern struct MarioState *gMarioState;
|
||||
extern u8 gInsidePainting;
|
||||
extern u8 gControlPainting;
|
||||
extern u8 gWaitingForRemotePainting;
|
||||
extern struct WarpNode gPaintingWarpNode;
|
||||
|
||||
extern s16 sCurrPlayMode;
|
||||
extern u16 D_80339ECA;
|
||||
|
@ -132,4 +136,7 @@ void basic_update(UNUSED s16 *arg);
|
|||
|
||||
s32 init_level(void);
|
||||
|
||||
void initiate_painting_warp_node(struct WarpNode *pWarpNode, u8 instant);
|
||||
void star_select_finish_selection(void);
|
||||
|
||||
#endif // LEVEL_UPDATE_H
|
||||
|
|
|
@ -190,6 +190,7 @@ s16 find_mario_anim_flags_and_translation(struct Object *obj, s32 yaw, Vec3s tra
|
|||
f32 dz;
|
||||
|
||||
struct Animation *curAnim = (void *) obj->header.gfx.unk38.curAnim;
|
||||
if (curAnim == NULL) { return 0; }
|
||||
s16 animFrame = geo_update_animation_frame(&obj->header.gfx.unk38, NULL);
|
||||
u16 *animIndex = segmented_to_virtual((void *) curAnim->index);
|
||||
s16 *animValues = segmented_to_virtual((void *) curAnim->values);
|
||||
|
@ -1846,6 +1847,8 @@ s32 execute_mario_action(UNUSED struct Object *o) {
|
|||
**************************************************/
|
||||
|
||||
void init_mario(void) {
|
||||
gInsidePainting = false;
|
||||
|
||||
bool isMario = (gMarioState == &gMarioStates[0]);
|
||||
if (isMario && gMarioObject == NULL) { goto skippy; }
|
||||
if (!isMario && gLuigiObject == NULL) { goto skippy; }
|
||||
|
|
|
@ -43,11 +43,11 @@ static s8 sVisibleStars;
|
|||
static u8 sInitSelectedActNum;
|
||||
|
||||
// Index value of the act selected in the act menu.
|
||||
static s8 sSelectedActIndex = 0;
|
||||
s8 sSelectedActIndex = 0;
|
||||
|
||||
// Index value of the star that is selectable in the act menu.
|
||||
// Excluding the next star, it doesn't count other transparent stars.
|
||||
static s8 sSelectableStarIndex = 0;
|
||||
s8 sSelectableStarIndex = 0;
|
||||
|
||||
// Act Selector menu timer that keeps counting until you choose an act.
|
||||
static s32 sActSelectorMenuTimer = 0;
|
||||
|
@ -172,7 +172,7 @@ void bhv_act_selector_loop(void) {
|
|||
// Sometimes, stars are not selectable even if they appear on the screen.
|
||||
// This code filters selectable and non-selectable stars.
|
||||
sSelectedActIndex = 0;
|
||||
handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &sSelectableStarIndex, 0, sObtainedStars);
|
||||
if (gControlPainting) { handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &sSelectableStarIndex, 0, sObtainedStars); }
|
||||
starIndexCounter = sSelectableStarIndex;
|
||||
for (i = 0; i < sVisibleStars; i++) {
|
||||
// Can the star be selected (is it either already completed or the first non-completed mission)
|
||||
|
@ -186,7 +186,7 @@ void bhv_act_selector_loop(void) {
|
|||
}
|
||||
} else {
|
||||
// If all stars are collected then they are all selectable.
|
||||
handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &sSelectableStarIndex, 0, sVisibleStars - 1);
|
||||
if (gControlPainting) { handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &sSelectableStarIndex, 0, sVisibleStars - 1); }
|
||||
sSelectedActIndex = sSelectableStarIndex;
|
||||
}
|
||||
|
||||
|
@ -257,6 +257,17 @@ void print_course_number(void) {
|
|||
* Print act selector strings, some with special checks.
|
||||
*/
|
||||
void print_act_selector_strings(void) {
|
||||
// synchronizing text
|
||||
if (!gControlPainting || gWaitingForRemotePainting) {
|
||||
static int fadeTimer = 0;
|
||||
u8 colorFade = sin(fadeTimer++ * 0.2f) * 50.0f + 200.0f;
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
||||
gDPSetEnvColor(gDisplayListHead++, colorFade, colorFade, colorFade, 255);
|
||||
u8 synchronizing[] = { TEXT_SYNCHRONIZING };
|
||||
print_hud_lut_string(HUD_LUT_GLOBAL, 80, 8, synchronizing);
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
||||
}
|
||||
|
||||
#ifdef VERSION_EU
|
||||
unsigned char myScore[][10] = { {TEXT_MYSCORE}, {TEXT_MY_SCORE_FR}, {TEXT_MY_SCORE_DE} };
|
||||
#else
|
||||
|
@ -414,7 +425,8 @@ s32 lvl_init_act_selector_values_and_stars(UNUSED s32 arg, UNUSED s32 unused) {
|
|||
* Also updates objects and returns act number selected after is chosen.
|
||||
*/
|
||||
s32 lvl_update_obj_and_load_act_button_actions(UNUSED s32 arg, UNUSED s32 unused) {
|
||||
if (sActSelectorMenuTimer >= 11) {
|
||||
u8 allowSelection = (gControlPainting && !gWaitingForRemotePainting);
|
||||
if (sActSelectorMenuTimer >= 11 && allowSelection) {
|
||||
// If any of these buttons are pressed, play sound and go to course act
|
||||
#ifndef VERSION_EU
|
||||
if ((gPlayer3Controller->buttonPressed & A_BUTTON)
|
||||
|
@ -423,17 +435,7 @@ s32 lvl_update_obj_and_load_act_button_actions(UNUSED s32 arg, UNUSED s32 unused
|
|||
#else
|
||||
if ((gPlayer3Controller->buttonPressed & (A_BUTTON | START_BUTTON | B_BUTTON | Z_TRIG))) {
|
||||
#endif
|
||||
#if defined(VERSION_JP) || defined(VERSION_SH)
|
||||
play_sound(SOUND_MENU_STAR_SOUND, gDefaultSoundArgs);
|
||||
#else
|
||||
play_sound(SOUND_MENU_STAR_SOUND_LETS_A_GO, gDefaultSoundArgs);
|
||||
#endif
|
||||
if (sInitSelectedActNum >= sSelectedActIndex + 1) {
|
||||
sLoadedActNum = sSelectedActIndex + 1;
|
||||
} else {
|
||||
sLoadedActNum = sInitSelectedActNum;
|
||||
}
|
||||
gDialogCourseActNum = sSelectedActIndex + 1;
|
||||
star_select_finish_selection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,3 +443,17 @@ s32 lvl_update_obj_and_load_act_button_actions(UNUSED s32 arg, UNUSED s32 unused
|
|||
sActSelectorMenuTimer++;
|
||||
return sLoadedActNum;
|
||||
}
|
||||
|
||||
void star_select_finish_selection(void) {
|
||||
#if defined(VERSION_JP) || defined(VERSION_SH)
|
||||
play_sound(SOUND_MENU_STAR_SOUND, gDefaultSoundArgs);
|
||||
#else
|
||||
play_sound(SOUND_MENU_STAR_SOUND_LETS_A_GO, gDefaultSoundArgs);
|
||||
#endif
|
||||
if (sInitSelectedActNum >= sSelectedActIndex + 1) {
|
||||
sLoadedActNum = sSelectedActIndex + 1;
|
||||
} else {
|
||||
sLoadedActNum = sInitSelectedActNum;
|
||||
}
|
||||
gDialogCourseActNum = sSelectedActIndex + 1;
|
||||
}
|
|
@ -76,7 +76,10 @@ void network_send(struct Packet* p) {
|
|||
void network_update(void) {
|
||||
if (networkType == NT_NONE) { return; }
|
||||
|
||||
if (sCurrPlayMode == PLAY_MODE_SYNC_LEVEL) {
|
||||
// TODO: refactor the way we do these update functions, it will get messy quick
|
||||
if (gInsidePainting && sCurrPlayMode == PLAY_MODE_CHANGE_LEVEL) {
|
||||
network_update_inside_painting();
|
||||
} else if (sCurrPlayMode == PLAY_MODE_SYNC_LEVEL) {
|
||||
network_update_level_warp();
|
||||
} else {
|
||||
network_update_player();
|
||||
|
@ -101,6 +104,7 @@ void network_update(void) {
|
|||
case PACKET_PLAYER: network_receive_player(&p); break;
|
||||
case PACKET_OBJECT: network_receive_object(&p); break;
|
||||
case PACKET_LEVEL_WARP: network_receive_level_warp(&p); break;
|
||||
case PACKET_INSIDE_PAINTING: network_receive_inside_painting(&p); break;
|
||||
default: printf("%s received unknown packet: %d\n", NETWORKTYPESTR, p.buffer[0]);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef NETWORK_H
|
||||
#define NETWORK_H
|
||||
|
||||
#include <time.h>
|
||||
#include <types.h>
|
||||
#include <assert.h>
|
||||
#include "../cliopts.h"
|
||||
|
@ -14,6 +15,7 @@ enum PacketType {
|
|||
PACKET_PLAYER,
|
||||
PACKET_OBJECT,
|
||||
PACKET_LEVEL_WARP,
|
||||
PACKET_INSIDE_PAINTING,
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
|
@ -32,6 +34,7 @@ struct SyncObject {
|
|||
};
|
||||
|
||||
extern struct MarioState gMarioStates[];
|
||||
extern u8 gInsidePainting;
|
||||
extern s16 sCurrPlayMode;
|
||||
extern enum NetworkType networkType;
|
||||
extern struct SyncObject syncObjects[];
|
||||
|
@ -57,4 +60,7 @@ void network_receive_object(struct Packet* p);
|
|||
void network_update_level_warp(void);
|
||||
void network_receive_level_warp(struct Packet* p);
|
||||
|
||||
void network_update_inside_painting(void);
|
||||
void network_receive_inside_painting(struct Packet* p);
|
||||
|
||||
#endif
|
||||
|
|
97
src/pc/network/packets/packet_inside_painting.c
Normal file
97
src/pc/network/packets/packet_inside_painting.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
#include <stdio.h>
|
||||
#include "../network.h"
|
||||
#include "src/game/level_update.h"
|
||||
#include "src/game/area.h"
|
||||
|
||||
extern struct WarpNode gPaintingWarpNode;
|
||||
extern u8 sSelectableStarIndex;
|
||||
extern u8 sSelectedActIndex;
|
||||
|
||||
struct PacketDataInsidePainting {
|
||||
u8 insidePainting;
|
||||
u8 controlPainting;
|
||||
u8 starIndex;
|
||||
u8 actIndex;
|
||||
struct WarpNode warpNode;
|
||||
};
|
||||
|
||||
static clock_t lastSentTime = 0;
|
||||
static float minUpdateRate = 0.5f;
|
||||
static struct PacketDataInsidePainting lastSentData = { 0 };
|
||||
|
||||
static void populate_packet_data(struct PacketDataInsidePainting* data) {
|
||||
data->insidePainting = gInsidePainting;
|
||||
data->controlPainting = gControlPainting;
|
||||
data->starIndex = sSelectableStarIndex;
|
||||
data->actIndex = sSelectedActIndex;
|
||||
data->warpNode = gPaintingWarpNode;
|
||||
}
|
||||
|
||||
void network_send_inside_painting(void) {
|
||||
struct PacketDataInsidePainting data = { 0 };
|
||||
populate_packet_data(&data);
|
||||
|
||||
struct Packet p;
|
||||
packet_init(&p, PACKET_INSIDE_PAINTING);
|
||||
packet_write(&p, &data, sizeof(struct PacketDataInsidePainting));
|
||||
network_send(&p);
|
||||
|
||||
lastSentData = data;
|
||||
lastSentTime = clock();
|
||||
}
|
||||
|
||||
void network_receive_inside_painting(struct Packet* p) {
|
||||
struct PacketDataInsidePainting remote = { 0 };
|
||||
packet_read(p, &remote, sizeof(struct PacketDataInsidePainting));
|
||||
|
||||
if (networkType == NT_CLIENT && gControlPainting && remote.controlPainting) {
|
||||
// we both think we should control the painting, host wins the tie
|
||||
gControlPainting = false;
|
||||
}
|
||||
|
||||
if (!gControlPainting && remote.controlPainting) {
|
||||
// update star/act index to show the one in control's selection
|
||||
sSelectableStarIndex = remote.starIndex;
|
||||
sSelectedActIndex = remote.actIndex;
|
||||
}
|
||||
|
||||
// see if the warp nodes are the same
|
||||
int compareNodes = memcmp(&gPaintingWarpNode, &remote.warpNode, sizeof(struct WarpNode));
|
||||
|
||||
if (gControlPainting && !remote.controlPainting && (compareNodes == 0)) {
|
||||
// remote is well behaved now, we can control the painting
|
||||
gWaitingForRemotePainting = false;
|
||||
}
|
||||
|
||||
bool shouldJumpInside = !gControlPainting && (!gInsidePainting && remote.insidePainting);
|
||||
|
||||
// ERROR: THE DESTINATION MISMATCH DOESN'T MOVE THE CLIENT TO THE CORRECT SCREEN!
|
||||
bool destinationMismatch = !gControlPainting && (compareNodes != 0);
|
||||
|
||||
if (shouldJumpInside || destinationMismatch) {
|
||||
initiate_painting_warp_node(&remote.warpNode, true);
|
||||
set_play_mode(PLAY_MODE_CHANGE_LEVEL);
|
||||
}
|
||||
|
||||
if (gControlPainting && !remote.controlPainting && !gInsidePainting && remote.insidePainting) {
|
||||
// we're in control and no longer in the painting, let remote know
|
||||
network_send_inside_painting();
|
||||
}
|
||||
|
||||
if (!gControlPainting && remote.controlPainting && !remote.insidePainting) {
|
||||
// remote is in control and in game, we should be too
|
||||
star_select_finish_selection();
|
||||
}
|
||||
}
|
||||
|
||||
void network_update_inside_painting(void) {
|
||||
struct PacketDataInsidePainting data = { 0 };
|
||||
populate_packet_data(&data);
|
||||
int compareData = memcmp(&data, &lastSentData, sizeof(struct PacketDataInsidePainting));
|
||||
|
||||
float timeSinceSend = (clock() - lastSentTime) / CLOCKS_PER_SEC;
|
||||
|
||||
if (compareData != 0 || timeSinceSend > minUpdateRate) {
|
||||
network_send_inside_painting();
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ void network_send_level_warp(void) {
|
|||
packet_write(&p, &gCurrLevelNum, 2);
|
||||
packet_write(&p, &sDelayedWarpArg, 4);
|
||||
packet_write(&p, &sSourceWarpNodeId, 2);
|
||||
|
||||
|
||||
network_send(&p);
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,6 @@ void network_receive_level_warp(struct Packet* p) {
|
|||
s16 remoteLevelNum;
|
||||
s32 remoteWarpArg;
|
||||
s16 remoteWarpNodeId;
|
||||
struct WarpDest remoteWarpDest;
|
||||
|
||||
packet_read(p, &remotePlayMode, 2);
|
||||
packet_read(p, &remoteLevelNum, 2);
|
||||
|
|
Loading…
Reference in a new issue