mirror of
https://git.do.srb2.org/KartKrew/Kart-Public.git
synced 2025-01-08 10:50:42 +00:00
Followers but they crash when you join netgames
This commit is contained in:
parent
fe3852f005
commit
157e3197f3
13 changed files with 390 additions and 38 deletions
|
@ -931,6 +931,7 @@ static void IdentifyVersion(void)
|
|||
D_AddFile(va(pandf,srb2waddir,"textures.kart"));
|
||||
D_AddFile(va(pandf,srb2waddir,"chars.kart"));
|
||||
D_AddFile(va(pandf,srb2waddir,"maps.kart"));
|
||||
D_AddFile(va(pandf,srb2waddir,"followers.kart")); // merge this in GFX later, this is mostly to avoid uploading a MASSIVE patch.kart /gfx.kart for testing. -Lat'
|
||||
#ifdef USE_PATCH_KART
|
||||
D_AddFile(va(pandf,srb2waddir,"patch.kart"));
|
||||
#endif
|
||||
|
|
|
@ -1257,7 +1257,7 @@ static void SendNameAndColor(void)
|
|||
{
|
||||
XBOXSTATIC char buf[MAXPLAYERNAME+3];
|
||||
char *p;
|
||||
|
||||
|
||||
p = buf;
|
||||
|
||||
// normal player colors
|
||||
|
@ -1280,6 +1280,10 @@ static void SendNameAndColor(void)
|
|||
CV_StealthSet(&cv_playercolor, cv_playercolor.defaultvalue);
|
||||
}
|
||||
|
||||
// so like, this is sent before we even use anything like cvars or w/e so it's possible that follower is set to a pretty yikes value, so let's fix that before we send garbage that could crash the game:
|
||||
if (cv_follower.value > numfollowers-1 || cv_follower.value < -1)
|
||||
CV_StealthSet(&cv_follower, "-1");
|
||||
|
||||
if (!strcmp(cv_playername.string, player_names[consoleplayer])
|
||||
&& cv_playercolor.value == players[consoleplayer].skincolor
|
||||
&& !strcmp(cv_skin.string, skins[players[consoleplayer].skin].name)
|
||||
|
@ -1410,6 +1414,10 @@ static void SendNameAndColor2(void)
|
|||
CV_StealthSet(&cv_playercolor2, cv_playercolor2.defaultvalue);
|
||||
}
|
||||
|
||||
// so like, this is sent before we even use anything like cvars or w/e so it's possible that follower is set to a pretty yikes value, so let's fix that before we send garbage that could crash the game:
|
||||
if (cv_follower2.value > numfollowers-1 || cv_follower2.value < -1)
|
||||
CV_StealthSet(&cv_follower2, "-1");
|
||||
|
||||
// We'll handle it later if we're not playing.
|
||||
if (!Playing())
|
||||
return;
|
||||
|
@ -1534,6 +1542,10 @@ static void SendNameAndColor3(void)
|
|||
CV_StealthSet(&cv_playercolor3, cv_playercolor3.defaultvalue);
|
||||
}
|
||||
|
||||
// so like, this is sent before we even use anything like cvars or w/e so it's possible that follower is set to a pretty yikes value, so let's fix that before we send garbage that could crash the game:
|
||||
if (cv_follower3.value > numfollowers-1 || cv_follower3.value < -1)
|
||||
CV_StealthSet(&cv_follower3, "-1");
|
||||
|
||||
// We'll handle it later if we're not playing.
|
||||
if (!Playing())
|
||||
return;
|
||||
|
@ -1650,6 +1662,10 @@ static void SendNameAndColor4(void)
|
|||
CV_StealthSet(&cv_playercolor4, cv_playercolor4.defaultvalue);
|
||||
}
|
||||
|
||||
// so like, this is sent before we even use anything like cvars or w/e so it's possible that follower is set to a pretty yikes value, so let's fix that before we send garbage that could crash the game:
|
||||
if (cv_follower4.value > numfollowers-1 || cv_follower4.value < -1)
|
||||
CV_StealthSet(&cv_follower4, "-1");
|
||||
|
||||
// We'll handle it later if we're not playing.
|
||||
if (!Playing())
|
||||
return;
|
||||
|
@ -1741,7 +1757,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
|
|||
char name[MAXPLAYERNAME+1];
|
||||
UINT8 color, skin;
|
||||
SINT8 follower;
|
||||
|
||||
|
||||
#ifdef PARANOIA
|
||||
if (playernum < 0 || playernum > MAXPLAYERS)
|
||||
I_Error("There is no player %d!", playernum);
|
||||
|
@ -1823,7 +1839,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
|
|||
}
|
||||
else
|
||||
SetPlayerSkinByNum(playernum, skin);
|
||||
|
||||
|
||||
// set follower:
|
||||
SetFollower(playernum, follower);
|
||||
}
|
||||
|
@ -1885,6 +1901,7 @@ static void Got_WeaponPref(UINT8 **cp,INT32 playernum)
|
|||
players[playernum].pflags |= PF_FLIPCAM;
|
||||
if (prefs & 2)
|
||||
players[playernum].pflags |= PF_ANALOGMODE;
|
||||
|
||||
}
|
||||
|
||||
void D_SendPlayerConfig(void)
|
||||
|
@ -5119,19 +5136,19 @@ static void Follower_OnChange(void)
|
|||
{
|
||||
if (!Playing())
|
||||
return; // do whatever you want
|
||||
|
||||
|
||||
// there is a slight chance that we will actually use a string instead so...
|
||||
// let's investigate the string...
|
||||
char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1];
|
||||
strcpy(str, cv_follower.string);
|
||||
strcpy(cpy, cv_follower.string);
|
||||
strlwr(str);
|
||||
if (!atoi(cpy)) // yep, that's a string alright...
|
||||
if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright...
|
||||
{
|
||||
INT32 num = R_FollowerAvailable(str);
|
||||
if (num == -1) // that's an error.
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
|
||||
|
||||
|
||||
char set[10];
|
||||
sprintf(set, "%d", num);
|
||||
CV_StealthSet(&cv_follower, set); // set it to a number. It's easier for us to send later :)
|
||||
|
@ -5143,17 +5160,17 @@ static void Follower2_OnChange(void)
|
|||
{
|
||||
if (!Playing() || !splitscreen)
|
||||
return; // do whatever you want
|
||||
|
||||
|
||||
char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1];
|
||||
strcpy(str, cv_follower2.string);
|
||||
strcpy(cpy, cv_follower2.string);
|
||||
strlwr(str);
|
||||
if (!atoi(cpy)) // yep, that's a string alright...
|
||||
if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright...
|
||||
{
|
||||
INT32 num = R_FollowerAvailable(str);
|
||||
if (num == -1) // that's an error.
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
|
||||
|
||||
|
||||
char set[10];
|
||||
sprintf(set, "%d", num);
|
||||
CV_StealthSet(&cv_follower2, set); // set it to a number. It's easier for us to send later :)
|
||||
|
@ -5170,16 +5187,16 @@ static void Follower3_OnChange(void)
|
|||
strcpy(str, cv_follower3.string);
|
||||
strcpy(cpy, cv_follower3.string);
|
||||
strlwr(str);
|
||||
if (!atoi(cpy)) // yep, that's a string alright...
|
||||
if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright...
|
||||
{
|
||||
INT32 num = R_FollowerAvailable(str);
|
||||
if (num == -1) // that's an error.
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
|
||||
|
||||
|
||||
char set[10];
|
||||
sprintf(set, "%d", num);
|
||||
CV_StealthSet(&cv_follower3, set); // set it to a number. It's easier for us to send later :)
|
||||
}
|
||||
}
|
||||
SendNameAndColor3();
|
||||
}
|
||||
|
||||
|
@ -5192,16 +5209,16 @@ static void Follower4_OnChange(void)
|
|||
strcpy(str, cv_follower4.string);
|
||||
strcpy(cpy, cv_follower4.string);
|
||||
strlwr(str);
|
||||
if (!atoi(cpy)) // yep, that's a string alright...
|
||||
if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright...
|
||||
{
|
||||
INT32 num = R_FollowerAvailable(str);
|
||||
if (num == -1) // that's an error.
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
|
||||
|
||||
|
||||
char set[10];
|
||||
sprintf(set, "%d", num);
|
||||
CV_StealthSet(&cv_follower4, set); // set it to a number. It's easier for us to send later :)
|
||||
}
|
||||
}
|
||||
SendNameAndColor4();
|
||||
}
|
||||
|
||||
|
|
|
@ -444,10 +444,11 @@ typedef struct player_s
|
|||
// SRB2kart
|
||||
UINT8 kartspeed; // Kart speed stat between 1 and 9
|
||||
UINT8 kartweight; // Kart weight stat between 1 and 9
|
||||
|
||||
|
||||
INT32 followerskin; // Kart: This player's follower "skin"
|
||||
boolean followerready; // Kart: Used to know when we can have a follower or not. (This is set on the first NameAndColor follower update)
|
||||
mobj_t *follower; // Kart: This is the follower object we have. (If any)
|
||||
|
||||
|
||||
//
|
||||
|
||||
fixed_t normalspeed; // Normal ground
|
||||
|
|
|
@ -707,7 +707,7 @@ static void readfollower(MYFILE *f)
|
|||
}
|
||||
|
||||
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
|
||||
char *word, *word2, *dname = malloc(SKINNAMESIZE+1);
|
||||
char *word, *word2, dname[SKINNAMESIZE+1];
|
||||
char *tmp;
|
||||
|
||||
boolean nameset;
|
||||
|
@ -758,6 +758,11 @@ static void readfollower(MYFILE *f)
|
|||
DEH_WriteUndoline(word, va("%d", followers[numfollowers].zoffs), UNDO_NONE);
|
||||
followers[numfollowers].zoffs = (INT32)atoi(word2);
|
||||
}
|
||||
else if (fastcmp(word, "DISTANCE") || (fastcmp(word, "DIST")))
|
||||
{
|
||||
DEH_WriteUndoline(word, va("%d", followers[numfollowers].dist), UNDO_NONE);
|
||||
followers[numfollowers].dist = (INT32)atoi(word2);
|
||||
}
|
||||
else if (fastcmp(word, "IDLESTATE"))
|
||||
{
|
||||
if (word2)
|
||||
|
@ -828,12 +833,11 @@ static void readfollower(MYFILE *f)
|
|||
// get ready to print the name...
|
||||
strcpy(dname, followers[numfollowers].skinname);
|
||||
|
||||
// check for atangle and zoffs. But don't error if they aren't set, just give them logical values.
|
||||
if (!followers[numfollowers].atangle && followers[numfollowers].atangle != 0)
|
||||
followers[numfollowers].atangle = 300;
|
||||
if (followers[numfollowers].dist < 0)
|
||||
followers[numfollowers].dist = 0;
|
||||
|
||||
if ((!followers[numfollowers].zoffs || followers[numfollowers].zoffs < 0) && followers[numfollowers].zoffs != 0) // yikes, no offset or negative offset
|
||||
followers[numfollowers].zoffs = 64;
|
||||
if (followers[numfollowers].zoffs < 0)
|
||||
followers[numfollowers].zoffs = 0;
|
||||
|
||||
|
||||
// also check if we forgot states :V
|
||||
|
@ -854,7 +858,6 @@ if (!followers[numfollowers].field) \
|
|||
|
||||
CONS_Printf("Added follower '%s'\n", dname);
|
||||
numfollowers++; // add 1 follower
|
||||
free(dname); // free name memory
|
||||
Z_Free(s);
|
||||
}
|
||||
|
||||
|
@ -7322,6 +7325,28 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_KARMAFIREWORK4",
|
||||
"S_KARMAFIREWORKTRAIL",
|
||||
|
||||
"S_GCHAOIDLE",
|
||||
"S_GCHAOFLY",
|
||||
"S_GCHAOSAD1",
|
||||
"S_GCHAOSAD2",
|
||||
"S_GCHAOSAD3",
|
||||
"S_GCHAOSAD4",
|
||||
"S_GCHAOHAPPY1",
|
||||
"S_GCHAOHAPPY2",
|
||||
"S_GCHAOHAPPY3",
|
||||
"S_GCHAOHAPPY4",
|
||||
|
||||
"S_CHEESEIDLE",
|
||||
"S_CHEESEFLY",
|
||||
"S_CHEESESAD1",
|
||||
"S_CHEESESAD2",
|
||||
"S_CHEESESAD3",
|
||||
"S_CHEESESAD4",
|
||||
"S_CHEESEHAPPY1",
|
||||
"S_CHEESEHAPPY2",
|
||||
"S_CHEESEHAPPY3",
|
||||
"S_CHEESEHAPPY4",
|
||||
|
||||
#ifdef SEENAMES
|
||||
"S_NAMECHECK",
|
||||
#endif
|
||||
|
@ -8109,6 +8134,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
|
||||
"MT_KARMAFIREWORK",
|
||||
|
||||
"MT_FOLLOWER",
|
||||
|
||||
#ifdef SEENAMES
|
||||
"MT_NAMECHECK",
|
||||
#endif
|
||||
|
|
|
@ -140,7 +140,7 @@
|
|||
extern FILE *logstream;
|
||||
#endif
|
||||
|
||||
//#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3
|
||||
#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3
|
||||
#ifdef DEVELOP
|
||||
#define VERSION 0 // Game version
|
||||
#define SUBVERSION 0 // more precise version number
|
||||
|
|
14
src/g_game.c
14
src/g_game.c
|
@ -2327,6 +2327,9 @@ void G_PlayerReborn(INT32 player)
|
|||
// SRB2kart
|
||||
UINT8 kartspeed;
|
||||
UINT8 kartweight;
|
||||
boolean followerready;
|
||||
INT32 followerskin;
|
||||
mobj_t *follower; // old follower, will probably be removed by the time we're dead but you never know.
|
||||
//
|
||||
fixed_t normalspeed;
|
||||
fixed_t runspeed;
|
||||
|
@ -2398,6 +2401,9 @@ void G_PlayerReborn(INT32 player)
|
|||
// SRB2kart
|
||||
kartspeed = players[player].kartspeed;
|
||||
kartweight = players[player].kartweight;
|
||||
follower = players[player].follower;
|
||||
followerready = players[player].followerready;
|
||||
followerskin = players[player].followerskin;
|
||||
//
|
||||
normalspeed = players[player].normalspeed;
|
||||
runspeed = players[player].runspeed;
|
||||
|
@ -2531,6 +2537,14 @@ void G_PlayerReborn(INT32 player)
|
|||
p->kartstuff[k_wanted] = wanted;
|
||||
p->kartstuff[k_eggmanblame] = -1;
|
||||
|
||||
if (follower)
|
||||
P_RemoveMobj(follower);
|
||||
|
||||
p->followerready = followerready;
|
||||
p->followerskin = followerskin;
|
||||
p->follower = NULL; // respawn a new one with you, it looks better.
|
||||
|
||||
|
||||
// Don't do anything immediately
|
||||
p->pflags |= PF_USEDOWN;
|
||||
p->pflags |= PF_ATTACKDOWN;
|
||||
|
|
57
src/info.c
57
src/info.c
|
@ -69,7 +69,7 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"CNDL","DOCH","DUCK","GTRE","CHES","CHIM","DRGN","LZMN","PGSS","ZTCH",
|
||||
"MKMA","MKMP","RTCH","BOWL","BOWH","BRRL","BRRR","HRSE","TOAH","BFRT",
|
||||
"OFRT","RFRT","PFRT","ASPK","HBST","HBSO","HBSF","WBLZ","WBLN","FWRK",
|
||||
"XMS4","XMS5","VIEW"
|
||||
"XMS4","XMS5","GCHA","CHEZ","VIEW"
|
||||
};
|
||||
|
||||
// Doesn't work with g++, needs actionf_p1 (don't modify this comment)
|
||||
|
@ -3393,7 +3393,33 @@ state_t states[NUMSTATES] =
|
|||
{SPR_FWRK, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_KARMAFIREWORK4}, // S_KARMAFIREWORK3
|
||||
{SPR_FWRK, 3|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_KARMAFIREWORK1}, // S_KARMAFIREWORK4
|
||||
{SPR_FWRK, 4|FF_FULLBRIGHT, TICRATE, {NULL}, 0, 0, S_NULL}, // S_KARMAFIREWORKTRAIL
|
||||
|
||||
|
||||
// followers:
|
||||
|
||||
// generic chao:
|
||||
{SPR_GCHA, FF_ANIMATE, -1, {NULL}, 1, 4, S_GCHAOIDLE}, //S_GCHAOIDLE
|
||||
{SPR_GCHA, 2|FF_ANIMATE, -1, {NULL}, 1, 2, S_GCHAOFLY}, //S_GCHAOFLY
|
||||
{SPR_GCHA, 7, 5, {NULL}, 0, 0, S_GCHAOSAD2}, //S_GCHAOSAD1
|
||||
{SPR_GCHA, 8, 3, {NULL}, 0, 0, S_GCHAOSAD3}, //S_GCHAOSAD2
|
||||
{SPR_GCHA, 9, 6, {NULL}, 0, 0, S_GCHAOSAD4}, //S_GCHAOSAD3
|
||||
{SPR_GCHA, 8, 3, {NULL}, 0, 0, S_GCHAOSAD1}, //S_GCHAOSAD4
|
||||
{SPR_GCHA, 4, 8, {NULL}, 0, 0, S_GCHAOHAPPY2}, //S_GCHAOHAPPY1
|
||||
{SPR_GCHA, 5, 4, {NULL}, 0, 0, S_GCHAOHAPPY3}, //S_GCHAOHAPPY2
|
||||
{SPR_GCHA, 6, 8, {NULL}, 0, 0, S_GCHAOHAPPY4}, //S_GCHAOHAPPY3
|
||||
{SPR_GCHA, 5, 4, {NULL}, 0, 0, S_GCHAOHAPPY1}, //S_GCHAOHAPPY4
|
||||
|
||||
// cheese:
|
||||
{SPR_CHEZ, FF_ANIMATE, -1, {NULL}, 1, 4, S_CHEESEIDLE}, //S_CHEESEIDLE
|
||||
{SPR_CHEZ, 2|FF_ANIMATE, -1, {NULL}, 1, 2, S_CHEESEFLY}, //S_CHEESEFLY
|
||||
{SPR_CHEZ, 7, 5, {NULL}, 0, 0, S_CHEESESAD2}, //S_CHEESESAD1
|
||||
{SPR_CHEZ, 8, 3, {NULL}, 0, 0, S_CHEESESAD3}, //S_CHEESESAD2
|
||||
{SPR_CHEZ, 9, 6, {NULL}, 0, 0, S_CHEESESAD4}, //S_CHEESESAD3
|
||||
{SPR_CHEZ, 8, 3, {NULL}, 0, 0, S_CHEESESAD1}, //S_CHEESESAD4
|
||||
{SPR_CHEZ, 4, 8, {NULL}, 0, 0, S_CHEESEHAPPY2}, //S_CHEESEHAPPY1
|
||||
{SPR_CHEZ, 5, 4, {NULL}, 0, 0, S_CHEESEHAPPY3}, //S_CHEESEHAPPY2
|
||||
{SPR_CHEZ, 6, 8, {NULL}, 0, 0, S_CHEESEHAPPY4}, //S_CHEESEHAPPY3
|
||||
{SPR_CHEZ, 5, 4, {NULL}, 0, 0, S_CHEESEHAPPY1}, //S_CHEESEHAPPY4
|
||||
|
||||
#ifdef SEENAMES
|
||||
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK
|
||||
#endif
|
||||
|
@ -20052,6 +20078,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_FOLLOWER
|
||||
-1, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
8<<FRACBITS, // radius
|
||||
16<<FRACBITS, // height
|
||||
1, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
// ============================================================================================================================//
|
||||
|
||||
#ifdef SEENAMES
|
||||
|
|
35
src/info.h
35
src/info.h
|
@ -779,7 +779,10 @@ typedef enum sprite
|
|||
// Xmas-specific sprites that don't fit aboxe
|
||||
SPR_XMS4,
|
||||
SPR_XMS5,
|
||||
|
||||
|
||||
SPR_GCHA, // follower: generic chao
|
||||
SPR_CHEZ, // follower: cheese
|
||||
|
||||
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
||||
SPR_VIEW,
|
||||
|
||||
|
@ -4051,6 +4054,32 @@ typedef enum state
|
|||
S_KARMAFIREWORK3,
|
||||
S_KARMAFIREWORK4,
|
||||
S_KARMAFIREWORKTRAIL,
|
||||
|
||||
// followers:
|
||||
|
||||
// generic chao:
|
||||
S_GCHAOIDLE,
|
||||
S_GCHAOFLY,
|
||||
S_GCHAOSAD1,
|
||||
S_GCHAOSAD2,
|
||||
S_GCHAOSAD3,
|
||||
S_GCHAOSAD4,
|
||||
S_GCHAOHAPPY1,
|
||||
S_GCHAOHAPPY2,
|
||||
S_GCHAOHAPPY3,
|
||||
S_GCHAOHAPPY4,
|
||||
|
||||
// cheese:
|
||||
S_CHEESEIDLE,
|
||||
S_CHEESEFLY,
|
||||
S_CHEESESAD1,
|
||||
S_CHEESESAD2,
|
||||
S_CHEESESAD3,
|
||||
S_CHEESESAD4,
|
||||
S_CHEESEHAPPY1,
|
||||
S_CHEESEHAPPY2,
|
||||
S_CHEESEHAPPY3,
|
||||
S_CHEESEHAPPY4,
|
||||
|
||||
#ifdef SEENAMES
|
||||
S_NAMECHECK,
|
||||
|
@ -4853,8 +4882,10 @@ typedef enum mobj_type
|
|||
MT_BOOSTON,
|
||||
MT_LIZARDMAN,
|
||||
MT_LIONMAN,
|
||||
|
||||
|
||||
MT_KARMAFIREWORK,
|
||||
|
||||
MT_FOLLOWER,
|
||||
|
||||
#ifdef SEENAMES
|
||||
MT_NAMECHECK,
|
||||
|
|
20
src/m_menu.c
20
src/m_menu.c
|
@ -8530,6 +8530,11 @@ static void M_SetupMultiPlayer(INT32 choice)
|
|||
setupm_cvfollower = &cv_follower;
|
||||
|
||||
setupm_fakefollower = atoi(setupm_cvfollower->string); // update fake follower value
|
||||
|
||||
// yikes, we don't want none of that...
|
||||
if (setupm_fakefollower > numfollowers-1)
|
||||
setupm_fakefollower = -1;
|
||||
|
||||
M_GetFollowerState(); // update follower state
|
||||
|
||||
// For whatever reason this doesn't work right if you just use ->value
|
||||
|
@ -8565,6 +8570,11 @@ static void M_SetupMultiPlayer2(INT32 choice)
|
|||
setupm_cvfollower = &cv_follower;
|
||||
|
||||
setupm_fakefollower = atoi(setupm_cvfollower->string); // update fake follower value
|
||||
|
||||
// yikes, we don't want none of that...
|
||||
if (setupm_fakefollower > numfollowers-1)
|
||||
setupm_fakefollower = -1;
|
||||
|
||||
M_GetFollowerState(); // update follower state
|
||||
|
||||
// For whatever reason this doesn't work right if you just use ->value
|
||||
|
@ -8600,6 +8610,11 @@ static void M_SetupMultiPlayer3(INT32 choice)
|
|||
setupm_cvfollower = &cv_follower;
|
||||
|
||||
setupm_fakefollower = atoi(setupm_cvfollower->string); // update fake follower value
|
||||
|
||||
// yikes, we don't want none of that...
|
||||
if (setupm_fakefollower > numfollowers-1)
|
||||
setupm_fakefollower = -1;
|
||||
|
||||
M_GetFollowerState(); // update follower state
|
||||
|
||||
// For whatever reason this doesn't work right if you just use ->value
|
||||
|
@ -8635,6 +8650,11 @@ static void M_SetupMultiPlayer4(INT32 choice)
|
|||
setupm_cvfollower = &cv_follower;
|
||||
|
||||
setupm_fakefollower = atoi(setupm_cvfollower->string); // update fake follower value
|
||||
|
||||
// yikes, we don't want none of that...
|
||||
if (setupm_fakefollower > numfollowers-1)
|
||||
setupm_fakefollower = -1;
|
||||
|
||||
M_GetFollowerState(); // update follower state
|
||||
|
||||
// For whatever reason this doesn't work right if you just use ->value
|
||||
|
|
|
@ -52,10 +52,11 @@ typedef enum
|
|||
{
|
||||
// RFLAGPOINT = 0x01,
|
||||
// BFLAGPOINT = 0x02,
|
||||
CAPSULE = 0x04,
|
||||
AWAYVIEW = 0x08,
|
||||
FIRSTAXIS = 0x10,
|
||||
SECONDAXIS = 0x20,
|
||||
CAPSULE = 4,
|
||||
AWAYVIEW = 8,
|
||||
FIRSTAXIS = 16,
|
||||
SECONDAXIS = 32,
|
||||
FOLLOWER = 64,
|
||||
} player_saveflags;
|
||||
|
||||
//
|
||||
|
@ -114,6 +115,8 @@ static void P_NetArchivePlayers(void)
|
|||
UINT16 flags;
|
||||
// size_t q;
|
||||
|
||||
CONS_Printf("SENDING NET INFO\n");
|
||||
|
||||
WRITEUINT32(save_p, ARCHIVEBLOCK_PLAYERS);
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
|
@ -238,6 +241,9 @@ static void P_NetArchivePlayers(void)
|
|||
if (players[i].axis2)
|
||||
flags |= SECONDAXIS;
|
||||
|
||||
if (players[i].follower)
|
||||
flags |= FOLLOWER;
|
||||
|
||||
WRITEINT16(save_p, players[i].lastsidehit);
|
||||
WRITEINT16(save_p, players[i].lastlinehit);
|
||||
|
||||
|
@ -275,6 +281,13 @@ static void P_NetArchivePlayers(void)
|
|||
// SRB2kart
|
||||
WRITEUINT8(save_p, players[i].kartspeed);
|
||||
WRITEUINT8(save_p, players[i].kartweight);
|
||||
|
||||
WRITEUINT8(save_p, players[i].followerskin);
|
||||
WRITEUINT8(save_p, players[i].followerready); // booleans are really just numbers eh??
|
||||
if (flags & FOLLOWER)
|
||||
WRITEUINT32(save_p, players[i].follower->mobjnum);
|
||||
|
||||
|
||||
//
|
||||
WRITEFIXED(save_p, players[i].normalspeed);
|
||||
WRITEFIXED(save_p, players[i].runspeed);
|
||||
|
@ -299,6 +312,8 @@ static void P_NetUnArchivePlayers(void)
|
|||
INT32 i, j;
|
||||
UINT16 flags;
|
||||
|
||||
CONS_Printf("FETCHING NET INFO\n");
|
||||
|
||||
if (READUINT32(save_p) != ARCHIVEBLOCK_PLAYERS)
|
||||
I_Error("Bad $$$.sav at archive block Players");
|
||||
|
||||
|
@ -455,6 +470,12 @@ static void P_NetUnArchivePlayers(void)
|
|||
// SRB2kart
|
||||
players[i].kartspeed = READUINT8(save_p);
|
||||
players[i].kartweight = READUINT8(save_p);
|
||||
|
||||
players[i].followerskin = READUINT8(save_p);
|
||||
players[i].followerready = READUINT8(save_p);
|
||||
if (flags & FOLLOWER)
|
||||
players[i].follower = (mobj_t *)(size_t)READUINT32(save_p);
|
||||
|
||||
//
|
||||
players[i].normalspeed = READFIXED(save_p);
|
||||
players[i].runspeed = READFIXED(save_p);
|
||||
|
|
159
src/p_user.c
159
src/p_user.c
|
@ -8933,6 +8933,162 @@ void P_DoTimeOver(player_t *player)
|
|||
countdown2 = 5*TICRATE;
|
||||
}
|
||||
|
||||
/* set follower state with our weird hacks
|
||||
the reason we do this is to avoid followers ever using actions (majormods, yikes!)
|
||||
without having to touch p_mobj.c.
|
||||
so we give it 1more tic and change the state when tic == 1 instead of 0
|
||||
cool beans?
|
||||
cool beans.
|
||||
*/
|
||||
static void P_SetFollowerState(mobj_t *f, INT32 state)
|
||||
{
|
||||
P_SetMobjStateNF(f, state);
|
||||
if (f->state->tics > 0)
|
||||
f->tics++;
|
||||
}
|
||||
|
||||
//
|
||||
//P_HandleFllower
|
||||
//
|
||||
//Handle the follower's spawning and moving along with the player. Do note that some of the stuff like the removal if a player doesn't exist anymore is handled in MT_FOLLOWER's thinker.
|
||||
static void P_HandleFollower(player_t *player)
|
||||
{
|
||||
|
||||
if (!player->followerready)
|
||||
return; // we aren't ready to perform anything follower related yet.
|
||||
|
||||
// How about making sure our follower exists and is added before trying to spawn it n' all?
|
||||
if (player->followerskin > numfollowers-1 || player->followerskin < -1)
|
||||
{
|
||||
CONS_Printf("Follower skin invlaid. Setting to -1.\n");
|
||||
player->followerskin = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// don't do anything if we can't have a follower to begin with. (It gets removed under those conditions)
|
||||
if (player->spectator)
|
||||
return;
|
||||
if (player->followerskin < 0)
|
||||
return;
|
||||
|
||||
// Before we do anything, let's be sure of where we're supposed to be
|
||||
follower_t fl = followers[player->followerskin];
|
||||
|
||||
angle_t an = player->mo->angle + (fl.atangle)*ANG1; // it's aproximative but it really doesn't matter in the grand scheme of things...
|
||||
fixed_t zoffs = (fl.zoffs)*FRACUNIT;
|
||||
|
||||
// do you like angle maths? I certainly don't...
|
||||
fixed_t sx, sy, sz;
|
||||
sx = player->mo->x + FixedMul((player->mo->scale*fl.dist), FINECOSINE((an)>>ANGLETOFINESHIFT));
|
||||
sy = player->mo->y + FixedMul((player->mo->scale*fl.dist), FINESINE((an)>>ANGLETOFINESHIFT));
|
||||
|
||||
// for the z coordinate, don't be a doof like Steel and forget that MFE_VERTICALFLIP exists :P
|
||||
sz = player->mo->z + FixedMul(player->mo->scale, zoffs);
|
||||
/*if (player->mo->eflags & MFE_VERTICALFLIP) // it's safe to assume that VERTICALFLIP accounts for MF2_OBJECTFLIP too
|
||||
sz -= (player->mo->height + FixedMul(player->mo->scale, zoffs*2));*/
|
||||
// ^ handled by K_matchgenericextraflags oops
|
||||
|
||||
|
||||
// finally, add a cool floating effect to the z height, unless we have no zoffs, in which case I guess this means we WANT to be on the ground...???
|
||||
if (fl.zoffs)
|
||||
{
|
||||
// not stolen from k_kart I swear!!
|
||||
const fixed_t pi = (22<<FRACBITS) / 7; // loose approximation, this doesn't need to be incredibly precise
|
||||
fixed_t sine = 4 * FINESINE((((8*pi*(TICRATE*2)) * leveltime)>>ANGLETOFINESHIFT) & FINEMASK);
|
||||
sz += sine;
|
||||
}
|
||||
|
||||
if (!player->follower) // follower doesn't exist / isn't valid
|
||||
{
|
||||
CONS_Printf("Spawning follower...\n");
|
||||
// so let's spawn one!
|
||||
player->follower = P_SpawnMobj(sx, sy, sz, MT_FOLLOWER);
|
||||
P_SetFollowerState(player->follower, fl.idlestate);
|
||||
P_SetTarget(&player->follower->target, player->mo); // we need that to know when we need to disappear
|
||||
|
||||
player->follower->extravalue1 = 0; // extravalue1 is used to know what "state set" to use.
|
||||
/*
|
||||
0 = idle
|
||||
1 = forwards
|
||||
2 = hurt
|
||||
3 = win
|
||||
4 = lose
|
||||
*/
|
||||
}
|
||||
else // follower exists, woo!
|
||||
{
|
||||
// first of all, handle states following the same model as above:
|
||||
if (player->follower->tics == 1)
|
||||
P_SetFollowerState(player->follower, player->follower->state->nextstate);
|
||||
|
||||
// move the follower next to us (yes, this is really basic maths but it looks pretty damn clean in practice)!
|
||||
player->follower->momx = (sx - player->follower->x)/2;
|
||||
player->follower->momy = (sy - player->follower->y)/2;
|
||||
player->follower->momz = (sz - player->follower->z)/6; // make z momentum a bit floatier, it'll look cute I promise!
|
||||
player->follower->angle = player->mo->angle;
|
||||
player->follower->color = player->mo->color;
|
||||
player->follower->colorized = player->mo->colorized;
|
||||
|
||||
P_SetScale(player->follower, player->mo->scale);
|
||||
K_MatchGenericExtraFlags(player->follower, player->mo);
|
||||
|
||||
|
||||
// handle follower animations. Yes, it looks like very bad kiddie script so what, do you have any better idea genius? Go get a life instead of criticizing my unpaid work!!!!!!
|
||||
|
||||
// hurt or dead
|
||||
if (player->kartstuff[k_spinouttimer] || player->mo->health <= 0)
|
||||
{
|
||||
player->follower->angle = leveltime*48*ANG1;
|
||||
if (player->follower->extravalue1 != 2)
|
||||
{
|
||||
player->follower->extravalue1 = 2;
|
||||
P_SetFollowerState(player->follower, fl.hurtstate);
|
||||
}
|
||||
if (player->mo->health <= 0) // if dead, snap to z pos
|
||||
player->follower->z = sz;
|
||||
}
|
||||
else if (player->speed > 10*player->mo->scale)
|
||||
{
|
||||
if (player->follower->extravalue1 != 1)
|
||||
{
|
||||
player->follower->extravalue1 = 1;
|
||||
P_SetFollowerState(player->follower, fl.followstate);
|
||||
}
|
||||
}
|
||||
else // nvm you're slow
|
||||
{
|
||||
if (player->follower->extravalue1 != 0)
|
||||
{
|
||||
|
||||
if (player->exiting)
|
||||
{
|
||||
if (K_IsPlayerLosing(player)) // L
|
||||
{
|
||||
if (player->follower->extravalue1 != 4)
|
||||
{
|
||||
player->follower->extravalue1 = 4;
|
||||
P_SetFollowerState(player->follower, fl.losestate);
|
||||
}
|
||||
}
|
||||
else // W
|
||||
{
|
||||
if (player->follower->extravalue1 != 3)
|
||||
{
|
||||
player->follower->extravalue1 = 3;
|
||||
P_SetFollowerState(player->follower, fl.winstate);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
player->follower->extravalue1 = 0;
|
||||
P_SetFollowerState(player->follower, fl.idlestate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// P_PlayerThink
|
||||
//
|
||||
|
@ -9466,6 +9622,9 @@ void P_PlayerThink(player_t *player)
|
|||
|
||||
K_KartPlayerThink(player, cmd); // SRB2kart
|
||||
|
||||
// we're done doing all of this, now take care of followers...
|
||||
P_HandleFollower(player);
|
||||
|
||||
/*
|
||||
// Colormap verification
|
||||
{
|
||||
|
|
|
@ -2502,6 +2502,8 @@ void R_DrawMasked(void)
|
|||
// We can assume those are tied to skins somewhat, hence why they're defined here.
|
||||
INT32 numskins = 0;
|
||||
follower_t followers[MAXSKINS];
|
||||
// default followers are defined in SOC_FLWR in followers.kart / gfx.kart (depending on what exe this is, at this point)
|
||||
|
||||
|
||||
skin_t skins[MAXSKINS];
|
||||
// FIXTHIS: don't work because it must be inistilised before the config load
|
||||
|
@ -2706,7 +2708,6 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
|
|||
{
|
||||
player_t *player = &players[playernum];
|
||||
skin_t *skin = &skins[skinnum];
|
||||
CONS_Printf("skin\n");
|
||||
if (skinnum >= 0 && skinnum < numskins) // Make sure it exists!
|
||||
{
|
||||
player->skin = skinnum;
|
||||
|
@ -2769,16 +2770,22 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
|
|||
void SetFollower(INT32 playernum, INT32 skinnum)
|
||||
{
|
||||
player_t *player = &players[playernum];
|
||||
|
||||
|
||||
player->followerready = true; // we are ready to perform follower related actions in the player thinker, now.
|
||||
if (skinnum >= -1 && skinnum <= numfollowers) // Make sure it exists!
|
||||
{
|
||||
player->followerskin = skinnum;
|
||||
CONS_Printf("Updated player follower num\n");
|
||||
/*
|
||||
We don't actually set anything there, becasuse we need to be sure that a proper player->mo is available to spawn the follower.
|
||||
Moreover, the follower will self-handle itself the rest of the time, hence, its skinnum stored to the player is all we need right now.
|
||||
We don't spawn the follower here since it'll be easier to handle all of it in the Player thinker itself.
|
||||
However, we will despawn it right here if there's any to make it easy for the player thinker to replace it or delete it.
|
||||
*/
|
||||
|
||||
if (player->follower)
|
||||
{
|
||||
P_RemoveMobj(player->follower);
|
||||
player->follower = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -127,6 +127,7 @@ typedef struct follower_s
|
|||
|
||||
// some position shenanigans:
|
||||
INT32 atangle; // angle the object will be at around the player. The object itself will always face the same direction as the player.
|
||||
INT32 dist; // distance relative to the player. (In a circle)
|
||||
INT32 zoffs; // Z offset relative to the player's height. Cannot be negative.
|
||||
|
||||
// from there on out, everything is STATES to allow customization
|
||||
|
|
Loading…
Reference in a new issue