mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-07 05:21:12 +00:00
4072 lines
130 KiB
C++
4072 lines
130 KiB
C++
//-------------------------------------------------------------------------
|
|
/*
|
|
Copyright (C) 2010 EDuke32 developers and contributors
|
|
|
|
This file is part of EDuke32.
|
|
|
|
EDuke32 is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License version 2
|
|
as published by the Free Software Foundation.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
//-------------------------------------------------------------------------
|
|
#include "ns.h" // Must come before everything else!
|
|
|
|
#include "duke3d.h"
|
|
#include "game.h"
|
|
#include "gamedef.h"
|
|
#include "net.h"
|
|
#include "premap.h"
|
|
#include "savegame.h"
|
|
#include "input.h"
|
|
|
|
#include "enet.h"
|
|
#include "lz4.h"
|
|
#include "crc32_.h"
|
|
|
|
BEGIN_RR_NS
|
|
|
|
#define TIMERUPDATESIZ 32
|
|
|
|
ENetHost *g_netServer = NULL;
|
|
ENetHost *g_netClient = NULL;
|
|
ENetPeer *g_netClientPeer = NULL;
|
|
ENetPeer* g_netPlayerPeer[MAXPLAYERS];
|
|
enet_uint16 g_netPort = 23513;
|
|
int32_t g_netDisconnect = 0;
|
|
char g_netPassword[32];
|
|
int32_t g_netPlayersWaiting = 0;
|
|
#ifndef NETCODE_DISABLE
|
|
int32_t g_networkMode = NET_CLIENT;
|
|
#endif
|
|
int32_t g_netIndex = 2;
|
|
newgame_t pendingnewgame;
|
|
|
|
#ifdef NETCODE_DISABLE
|
|
void faketimerhandler(void) {}
|
|
#else
|
|
|
|
static char recbuf[180];
|
|
static int32_t g_chatPlayer = -1;
|
|
|
|
|
|
// sync a connecting player up with the current game state
|
|
void Net_SyncPlayer(ENetEvent *event)
|
|
{
|
|
int32_t i, j;
|
|
|
|
if (numplayers + g_netPlayersWaiting >= MAXPLAYERS)
|
|
{
|
|
enet_peer_disconnect_later(event->peer, DISC_SERVER_FULL);
|
|
initprintf("Refused peer; server full.\n");
|
|
return;
|
|
}
|
|
|
|
g_netPlayersWaiting++;
|
|
|
|
S_PlaySound(DUKE_GETWEAPON2);
|
|
|
|
// open a new slot if necessary and save off the resulting slot # for future reference
|
|
for (TRAVERSE_CONNECT(i))
|
|
{
|
|
if (g_player[i].playerquitflag == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == -1)
|
|
{
|
|
i = g_mostConcurrentPlayers++;
|
|
}
|
|
|
|
event->peer->data = (void *)(intptr_t)i;
|
|
|
|
//g_player[i].netsynctime = totalclock;
|
|
g_player[i].playerquitflag = 1;
|
|
//g_player[i].revision = g_netMapRevision;
|
|
|
|
for (j=0; j<g_mostConcurrentPlayers-1; j++)
|
|
{
|
|
connectpoint2[j] = j+1;
|
|
}
|
|
|
|
connectpoint2[g_mostConcurrentPlayers-1] = -1;
|
|
|
|
G_MaybeAllocPlayer(i);
|
|
|
|
g_netPlayersWaiting--;
|
|
++numplayers;
|
|
++ud.multimode;
|
|
Net_SendNewPlayer(i);
|
|
Net_SendPlayerIndex(i, event->peer);
|
|
Net_SendClientInfo();
|
|
Net_SendUserMapName();
|
|
// Net_SendNewGame(0, event->peer);
|
|
}
|
|
|
|
//void Net_SpawnPlayer(int32_t player)
|
|
//{
|
|
// int32_t j = 0;
|
|
// packbuf[j++] = PACKET_PLAYER_SPAWN;
|
|
// packbuf[j++] = player;
|
|
//
|
|
// Bmemcpy(&packbuf[j], &g_player[player].ps->pos.x, sizeof(vec3_t) * 2);
|
|
// j += sizeof(vec3_t) * 2;
|
|
//
|
|
// packbuf[j++] = 0;
|
|
//
|
|
// enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(packbuf, j, ENET_PACKET_FLAG_RELIABLE));
|
|
//}
|
|
|
|
static void display_betascreen(void)
|
|
{
|
|
rotatesprite_fs(160<<16,100<<16,65536,0,BETASCREEN,0,0,2+8+64+BGSTRETCH);
|
|
|
|
rotatesprite_fs(160<<16,(104)<<16,60<<10,0,DUKENUKEM,0,0,2+8);
|
|
rotatesprite_fs(160<<16,(129)<<16,30<<11,0,THREEDEE,0,0,2+8);
|
|
if (PLUTOPAK) // JBF 20030804
|
|
rotatesprite_fs(160<<16,(151)<<16,30<<11,0,PLUTOPAKSPRITE+1,0,0,2+8);
|
|
}
|
|
|
|
void faketimerhandler(void)
|
|
{
|
|
if (g_netServer==NULL && g_netClient==NULL)
|
|
return;
|
|
|
|
enet_host_service(g_netServer ? g_netServer : g_netClient, NULL, 0);
|
|
|
|
//Net_Update();
|
|
}
|
|
|
|
void Net_WaitForEverybody(void)
|
|
{
|
|
if (numplayers < 2) return;
|
|
|
|
packbuf[0] = PACKET_TYPE_PLAYER_READY;
|
|
g_player[myconnectindex].playerreadyflag++;
|
|
|
|
// if we're a peer or slave, not a master
|
|
if ((g_networkBroadcastMode == 1) || (!g_networkBroadcastMode && (myconnectindex != connecthead)))
|
|
for (int TRAVERSE_CONNECT(i))
|
|
{
|
|
if (i != myconnectindex) Net_SendPacket(i, packbuf, 1);
|
|
if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master
|
|
}
|
|
|
|
|
|
P_SetGamePalette(g_player[myconnectindex].ps, TITLEPAL, 8+2+1);
|
|
|
|
do
|
|
{
|
|
//if (quitevent || keystatus[sc_Escape]) G_GameExit("");
|
|
|
|
if (G_FPSLimit())
|
|
{
|
|
display_betascreen();
|
|
gametext_center_shade(170, "Waiting for players", 14);
|
|
videoNextPage();
|
|
};
|
|
|
|
G_HandleAsync();
|
|
Net_GetPackets();
|
|
|
|
int i;
|
|
for (TRAVERSE_CONNECT(i))
|
|
{
|
|
if (g_player[i].playerreadyflag < g_player[myconnectindex].playerreadyflag) break;
|
|
if ((!g_networkBroadcastMode) && (myconnectindex != connecthead))
|
|
{
|
|
// we're a slave
|
|
i = -1; break;
|
|
}
|
|
//slaves in M/S mode only wait for master
|
|
}
|
|
if (i < 0)
|
|
{
|
|
// master sends ready packet once it hears from all slaves
|
|
if (!g_networkBroadcastMode && myconnectindex == connecthead)
|
|
for (int TRAVERSE_CONNECT(i))
|
|
{
|
|
packbuf[0] = PACKET_TYPE_PLAYER_READY;
|
|
if (i != myconnectindex) Net_SendPacket(i, packbuf, 1);
|
|
}
|
|
|
|
P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 8+2+1);
|
|
return;
|
|
}
|
|
}
|
|
while (1);
|
|
}
|
|
|
|
void Net_ResetPrediction(void)
|
|
{
|
|
mypos = omypos = g_player[myconnectindex].ps->pos;
|
|
myvel = { 0, 0, 0 };
|
|
myang = omyang = g_player[myconnectindex].ps->q16ang;
|
|
myhoriz = omyhoriz = g_player[myconnectindex].ps->q16horiz;
|
|
myhorizoff = omyhorizoff = g_player[myconnectindex].ps->q16horizoff;
|
|
mycursectnum = g_player[myconnectindex].ps->cursectnum;
|
|
myjumpingcounter = g_player[myconnectindex].ps->jumping_counter;
|
|
myjumpingtoggle = g_player[myconnectindex].ps->jumping_toggle;
|
|
myonground = g_player[myconnectindex].ps->on_ground;
|
|
myhardlanding = g_player[myconnectindex].ps->hard_landing;
|
|
myreturntocenter = g_player[myconnectindex].ps->return_to_center;
|
|
my_moto_speed = g_player[myconnectindex].ps->moto_speed;
|
|
my_not_on_water = g_player[myconnectindex].ps->not_on_water;
|
|
my_moto_on_ground = g_player[myconnectindex].ps->moto_on_ground;
|
|
my_moto_do_bump = g_player[myconnectindex].ps->moto_do_bump;
|
|
my_moto_bump_fast = g_player[myconnectindex].ps->moto_bump_fast;
|
|
my_moto_on_oil = g_player[myconnectindex].ps->moto_on_oil;
|
|
my_moto_on_mud = g_player[myconnectindex].ps->moto_on_mud;
|
|
my_moto_bump = g_player[myconnectindex].ps->moto_do_bump;
|
|
my_moto_bump_target = g_player[myconnectindex].ps->moto_bump_target;
|
|
my_moto_turb = g_player[myconnectindex].ps->moto_turb;
|
|
my_stairs = g_player[myconnectindex].ps->stairs;
|
|
}
|
|
|
|
void Net_DoPrediction(void)
|
|
{
|
|
DukePlayer_t *const pPlayer = g_player[myconnectindex].ps;
|
|
spritetype *const pSprite = &sprite[pPlayer->i];
|
|
|
|
input_t *const pInput = &inputfifo[predictfifoplc&(MOVEFIFOSIZ-1)][myconnectindex];
|
|
|
|
int16_t backcstat = pSprite->cstat;
|
|
pSprite->cstat &= ~257;
|
|
|
|
uint32_t playerBits = pInput->bits;
|
|
|
|
if (RRRA)
|
|
{
|
|
if (pPlayer->on_motorcycle && pSprite->extra > 0)
|
|
{
|
|
int var64, var68, var6c, var74, var7c;
|
|
if (my_moto_speed < 0)
|
|
my_moto_speed = 0;
|
|
if (TEST_SYNC_KEY(playerBits, SK_CROUCH))
|
|
{
|
|
var64 = 1;
|
|
playerBits &= ~(1<<SK_CROUCH);
|
|
}
|
|
else
|
|
var64 = 0;
|
|
|
|
if (TEST_SYNC_KEY(playerBits, SK_JUMP))
|
|
{
|
|
var68 = 1;
|
|
playerBits &= ~(1<< SK_JUMP);
|
|
}
|
|
else
|
|
{
|
|
var68 = 0;
|
|
}
|
|
if (TEST_SYNC_KEY(playerBits, SK_AIM_UP))
|
|
{
|
|
var6c = 1;
|
|
playerBits &= ~(1<<SK_AIM_UP);
|
|
}
|
|
else
|
|
var6c = 0;
|
|
if (TEST_SYNC_KEY(playerBits, SK_AIM_DOWN))
|
|
{
|
|
var74 = 1;
|
|
playerBits &= ~(1<<SK_AIM_DOWN);
|
|
}
|
|
else
|
|
{
|
|
var74 = 0;
|
|
}
|
|
if (TEST_SYNC_KEY(playerBits, SK_LOOK_LEFT))
|
|
{
|
|
var7c = 1;
|
|
playerBits &= ~(1<<SK_LOOK_LEFT);
|
|
}
|
|
else
|
|
{
|
|
var7c = 0;
|
|
}
|
|
if (myonground == 1)
|
|
{
|
|
if (var64 && my_moto_speed > 0)
|
|
{
|
|
if (my_moto_on_oil)
|
|
my_moto_speed -= 2;
|
|
else
|
|
my_moto_speed -= 4;
|
|
if (my_moto_speed < 0)
|
|
my_moto_speed = 0;
|
|
my_moto_bump_target = -30;
|
|
my_moto_do_bump = 1;
|
|
}
|
|
else if (var68 && !var64)
|
|
{
|
|
if (my_moto_speed < 40)
|
|
{
|
|
my_moto_bump_target = 70;
|
|
my_moto_bump_fast = 1;
|
|
}
|
|
my_moto_speed += 2;
|
|
if (my_moto_speed > 120)
|
|
my_moto_speed = 120;
|
|
if (!my_not_on_water)
|
|
if (my_moto_speed > 80)
|
|
my_moto_speed = 80;
|
|
}
|
|
else if (my_moto_speed > 0)
|
|
my_moto_speed--;
|
|
if (my_moto_do_bump && (!var64 || my_moto_speed == 0))
|
|
{
|
|
my_moto_bump_target = 0;
|
|
my_moto_do_bump = 0;
|
|
}
|
|
if (var6c && my_moto_speed <= 0 && !var64)
|
|
{
|
|
int var88;
|
|
my_moto_speed = -15;
|
|
var88 = var7c;
|
|
var7c = var74;
|
|
var74 = var88;
|
|
}
|
|
}
|
|
if (my_moto_speed != 0 && myonground == 1)
|
|
{
|
|
if (!my_moto_bump)
|
|
if ((g_globalRandom&3) == 2)
|
|
my_moto_bump_target = (my_moto_speed>>4)*((randomseed&7)-4);
|
|
}
|
|
if (my_moto_turb)
|
|
{
|
|
if (my_moto_turb <= 1)
|
|
{
|
|
myhoriz = F16(100);
|
|
my_moto_turb = 0;
|
|
my_moto_bump = 0;
|
|
}
|
|
else
|
|
{
|
|
myhoriz = F16(100+(g_globalRandom&15)-7);
|
|
my_moto_turb--;
|
|
}
|
|
}
|
|
else if (my_moto_bump_target > my_moto_bump)
|
|
{
|
|
if (my_moto_bump_fast)
|
|
my_moto_bump += 6;
|
|
else
|
|
my_moto_bump++;
|
|
if (my_moto_bump_target < my_moto_bump)
|
|
my_moto_bump = my_moto_bump_target;
|
|
myhoriz = F16(100+my_moto_bump/3);
|
|
}
|
|
else if (my_moto_bump_target < my_moto_bump)
|
|
{
|
|
if (my_moto_bump_fast)
|
|
my_moto_bump -= 6;
|
|
else
|
|
my_moto_bump--;
|
|
if (my_moto_bump_target > my_moto_bump)
|
|
my_moto_bump = my_moto_bump_target;
|
|
myhoriz = F16(100+my_moto_bump/3);
|
|
}
|
|
else
|
|
{
|
|
my_moto_bump_fast = 0;
|
|
}
|
|
if (my_moto_speed >= 20 && myonground == 1 && (var74 || var7c))
|
|
{
|
|
short var8c, var90, var94, var98;
|
|
var8c = my_moto_speed;
|
|
var90 = fix16_to_int(myang);
|
|
if (var74)
|
|
var94 = -10;
|
|
else
|
|
var94 = 10;
|
|
if (var94 < 0)
|
|
var98 = 350;
|
|
else
|
|
var98 = -350;
|
|
if (my_moto_on_mud || my_moto_on_oil || !my_not_on_water)
|
|
{
|
|
if (my_moto_on_oil)
|
|
var8c <<= 3;
|
|
else
|
|
var8c <<= 2;
|
|
if (my_moto_do_bump)
|
|
{
|
|
myvel.x += (var8c>>5)*(sintable[(var94*-51+var90+512)&2047]<<4);
|
|
myvel.y += (var8c>>5)*(sintable[(var94*-51+var90)&2047]<<4);
|
|
myang = F16((var90-(var98>>2))&2047);
|
|
}
|
|
else
|
|
{
|
|
myvel.x += (var8c>>7)*(sintable[(var94*-51+var90+512)&2047]<<4);
|
|
myvel.y += (var8c>>7)*(sintable[(var94*-51+var90)&2047]<<4);
|
|
myang = F16((var90-(var98>>6))&2047);
|
|
}
|
|
my_moto_on_mud = 0;
|
|
my_moto_on_oil = 0;
|
|
}
|
|
else
|
|
{
|
|
if (my_moto_do_bump)
|
|
{
|
|
myvel.x += (var8c >> 5)*(sintable[(var94*-51 + var90 + 512) & 2047] << 4);
|
|
myvel.y += (var8c>>5)*(sintable[(var94*-51+var90)&2047]<<4);
|
|
myang = F16((var90-(var98>>4))&2047);
|
|
}
|
|
else
|
|
{
|
|
myvel.x += (var8c >> 7)*(sintable[(var94*-51 + var90 + 512) & 2047] << 4);
|
|
myvel.y += (var8c>>7)*(sintable[(var94*-51+var90)&2047]<<4);
|
|
myang = F16((var90-(var98>>7))&2047);
|
|
}
|
|
}
|
|
}
|
|
else if (my_moto_speed >= 20 && myonground == 1 && (my_moto_on_mud || my_moto_on_oil))
|
|
{
|
|
short var9c, vara0;
|
|
var9c = my_moto_speed;
|
|
vara0 = fix16_to_int(myang);
|
|
if (my_moto_on_oil)
|
|
var9c *= 10;
|
|
else
|
|
var9c *= 5;
|
|
myvel.x += (var9c>>7)*(sintable[(vara0+512)&2047]<<4);
|
|
myvel.y += (var9c>>7)*(sintable[(vara0)&2047]<<4);
|
|
}
|
|
my_moto_on_mud = 0;
|
|
my_moto_on_oil = 0;
|
|
}
|
|
else if (pPlayer->on_boat && pSprite->extra > 0)
|
|
{
|
|
int vara8, varac, varb0, varb4, varbc, varc4;
|
|
if (my_moto_speed < 0)
|
|
my_moto_speed = 0;
|
|
if (TEST_SYNC_KEY(playerBits, SK_CROUCH) && TEST_SYNC_KEY(playerBits, SK_JUMP))
|
|
{
|
|
vara8 = 1;
|
|
varac = 0;
|
|
playerBits &= ~(1<<SK_JUMP);
|
|
varb0 = 0;
|
|
playerBits &= ~(1<<SK_CROUCH);
|
|
}
|
|
else
|
|
vara8 = 0;
|
|
if (TEST_SYNC_KEY(playerBits, SK_JUMP))
|
|
{
|
|
varac = 1;
|
|
playerBits &= ~(1<<SK_JUMP);
|
|
}
|
|
else
|
|
{
|
|
varac = 0;
|
|
}
|
|
if (TEST_SYNC_KEY(playerBits, SK_CROUCH))
|
|
{
|
|
varb0 = 1;
|
|
playerBits &= ~(1<<SK_CROUCH);
|
|
}
|
|
else
|
|
varb0 = 0;
|
|
if (TEST_SYNC_KEY(playerBits, SK_AIM_UP))
|
|
{
|
|
varb4 = 1;
|
|
playerBits &= ~(1<<SK_AIM_UP);
|
|
}
|
|
else varb4 = 0;
|
|
if (TEST_SYNC_KEY(playerBits, SK_AIM_DOWN))
|
|
{
|
|
varbc = 1;
|
|
playerBits &= ~(1<<SK_AIM_DOWN);
|
|
}
|
|
else
|
|
{
|
|
varbc = 0;
|
|
}
|
|
if (TEST_SYNC_KEY(playerBits, SK_LOOK_LEFT))
|
|
{
|
|
varc4 = 1;
|
|
playerBits &= ~(1<< SK_LOOK_LEFT);
|
|
}
|
|
else
|
|
{
|
|
varc4 = 0;
|
|
}
|
|
if (myonground == 1)
|
|
{
|
|
if (vara8)
|
|
{
|
|
if (my_moto_speed <= 25)
|
|
{
|
|
my_moto_speed++;
|
|
}
|
|
else
|
|
{
|
|
my_moto_speed -= 2;
|
|
if (my_moto_speed < 0)
|
|
my_moto_speed = 0;
|
|
my_moto_bump_target = 30;
|
|
my_moto_do_bump = 1;
|
|
}
|
|
}
|
|
else if (varb0 && my_moto_speed > 0)
|
|
{
|
|
my_moto_speed -= 2;
|
|
if (my_moto_speed < 0)
|
|
my_moto_speed = 0;
|
|
my_moto_bump_target = 30;
|
|
my_moto_do_bump = 1;
|
|
}
|
|
else if (varac)
|
|
{
|
|
if (my_moto_speed < 40)
|
|
if (!my_not_on_water)
|
|
{
|
|
my_moto_bump_target = -30;
|
|
my_moto_bump_fast = 1;
|
|
}
|
|
my_moto_speed++;
|
|
if (my_moto_speed > 120)
|
|
my_moto_speed = 120;
|
|
}
|
|
else if (my_moto_speed > 0)
|
|
my_moto_speed--;
|
|
if (my_moto_do_bump && (!varb0 || my_moto_speed == 0))
|
|
{
|
|
my_moto_bump_target = 0;
|
|
my_moto_do_bump = 0;
|
|
}
|
|
if (varb4 && my_moto_speed == 0 && !varb0)
|
|
{
|
|
int vard0;
|
|
if (!my_not_on_water)
|
|
my_moto_speed = -25;
|
|
else
|
|
my_moto_speed = -20;
|
|
vard0 = varc4;
|
|
varc4 = varbc;
|
|
varbc = vard0;
|
|
}
|
|
}
|
|
if (my_moto_speed != 0 && myonground == 1)
|
|
{
|
|
if (!my_moto_bump)
|
|
if ((g_globalRandom & 15) == 14)
|
|
my_moto_bump_target = (my_moto_speed>>4)*((randomseed&3)-2);
|
|
}
|
|
if (my_moto_turb)
|
|
{
|
|
if (my_moto_turb <= 1)
|
|
{
|
|
myhoriz = F16(100);
|
|
my_moto_turb = 0;
|
|
my_moto_bump_target = 0;
|
|
my_moto_bump = 0;
|
|
}
|
|
else
|
|
{
|
|
myhoriz = F16(100+((g_globalRandom&15)-7));
|
|
my_moto_turb--;
|
|
}
|
|
}
|
|
else if (my_moto_bump_target > my_moto_bump)
|
|
{
|
|
if (my_moto_bump_fast)
|
|
my_moto_bump += 6;
|
|
else
|
|
my_moto_bump++;
|
|
if (my_moto_bump_target < my_moto_bump)
|
|
my_moto_bump = my_moto_bump_target;
|
|
myhoriz = F16(100+my_moto_bump/3);
|
|
}
|
|
else if (my_moto_bump_target < my_moto_bump)
|
|
{
|
|
if (my_moto_bump_fast)
|
|
my_moto_bump -= 6;
|
|
else
|
|
my_moto_bump--;
|
|
if (my_moto_bump_target > my_moto_bump)
|
|
my_moto_bump = my_moto_bump_target;
|
|
myhoriz = F16(100+my_moto_bump/3);
|
|
}
|
|
else
|
|
{
|
|
my_moto_bump_target = 0;
|
|
my_moto_bump_fast = 0;
|
|
}
|
|
if (my_moto_speed > 0 && myonground == 1 && (varbc || varc4))
|
|
{
|
|
short vard4, vard8, vardc, vare0;
|
|
vard4 = my_moto_speed;
|
|
vard8 = fix16_to_int(myang);
|
|
if (varbc)
|
|
vardc = -10;
|
|
else
|
|
vardc = 10;
|
|
if (vardc < 0)
|
|
vare0 = 350;
|
|
else
|
|
vare0 = -350;
|
|
vard4 <<= 2;
|
|
if (my_moto_do_bump)
|
|
{
|
|
myvel.x += (vard4>>6)*(sintable[(vardc*-51+vard8+512)&2047]<<4);
|
|
myvel.y += (vard4>>6)*(sintable[(vardc*-51+vard8)&2047]<<4);
|
|
myang = F16((vard8-(vare0>>5))&2047);
|
|
}
|
|
else
|
|
{
|
|
myvel.x += (vard4>>7)*(sintable[(vardc*-51+vard8+512)&2047]<<4);
|
|
myvel.y += (vard4>>7)*(sintable[(vardc*-51+vard8)&2047]<<4);
|
|
myang = F16((vard8-(vare0>>6))&2047);
|
|
}
|
|
}
|
|
if (my_not_on_water)
|
|
if (my_moto_speed > 50)
|
|
my_moto_speed -= (my_moto_speed>>1);
|
|
}
|
|
}
|
|
|
|
int sectorLotag = sector[mycursectnum].lotag;
|
|
int myclipdist = 64;
|
|
int spriteNum = 0;
|
|
|
|
if (RR)
|
|
{
|
|
if (sectorLotag == 867)
|
|
{
|
|
int spriteNum = headspritesect[mycursectnum];
|
|
while (spriteNum >= 0)
|
|
{
|
|
int const nextSprite = nextspritesect[spriteNum];
|
|
if (sprite[spriteNum].picnum == RRTILE380)
|
|
if (sprite[spriteNum].z - ZOFFSET3 < mypos.z)
|
|
sectorLotag = 2;
|
|
spriteNum = nextSprite;
|
|
}
|
|
}
|
|
|
|
if (sectorLotag == 848 && sector[mycursectnum].floorpicnum == WATERTILE2)
|
|
sectorLotag = 1;
|
|
|
|
if (sectorLotag == 857)
|
|
myclipdist = 1;
|
|
else
|
|
myclipdist = 64;
|
|
}
|
|
|
|
uint8_t spritebridge = 0;
|
|
|
|
int stepHeight, centerHoriz;
|
|
int16_t ceilingBunch, floorBunch;
|
|
|
|
if (ud.noclip == 0 && (mycursectnum < 0 || mycursectnum >= MAXSECTORS || sector[mycursectnum].floorpicnum == MIRROR))
|
|
{
|
|
mypos.x = omypos.x;
|
|
mypos.y = omypos.y;
|
|
}
|
|
else
|
|
{
|
|
omypos.x = mypos.x;
|
|
omypos.y = mypos.y;
|
|
}
|
|
|
|
omyhoriz = myhoriz;
|
|
omyhorizoff = myhorizoff;
|
|
omypos.z = mypos.z;
|
|
omyang = myang;
|
|
|
|
int32_t floorZ, ceilZ, highZhit, lowZhit;
|
|
if (!RR || myclipdist == 64)
|
|
getzrange(&mypos, mycursectnum, &ceilZ, &highZhit, &floorZ, &lowZhit, 163, CLIPMASK0);
|
|
else
|
|
getzrange(&mypos, mycursectnum, &ceilZ, &highZhit, &floorZ, &lowZhit, 1, CLIPMASK0);
|
|
|
|
int truecz, truefz;
|
|
#ifdef YAX_ENABLE
|
|
getzsofslope_player(mycursectnum, mypos.x, mypos.y, &truecz, &truefz);
|
|
#else
|
|
getzsofslope(psect, mypos.x, mypos.y, &truecz, &truefz);
|
|
#endif
|
|
int const trueFloorZ = truefz;
|
|
int const trueFloorDist = klabs(mypos.z - trueFloorZ);
|
|
|
|
if ((lowZhit & 49152) == 16384 && sectorLotag == 1 && trueFloorDist > PHEIGHT + ZOFFSET2)
|
|
sectorLotag = 0;
|
|
|
|
// calculates automatic view angle for playing without a mouse
|
|
if (pPlayer->aim_mode == 0 && myonground && sectorLotag != ST_2_UNDERWATER
|
|
&& (sector[mycursectnum].floorstat & 2))
|
|
{
|
|
vec2_t const adjustedPlayer = { mypos.x + (sintable[(fix16_to_int(myang) + 512) & 2047] >> 5),
|
|
mypos.y + (sintable[fix16_to_int(myang) & 2047] >> 5) };
|
|
int16_t curSectNum = mycursectnum;
|
|
|
|
updatesector(adjustedPlayer.x, adjustedPlayer.y, &curSectNum);
|
|
|
|
if (curSectNum >= 0)
|
|
{
|
|
int const slopeZ = getflorzofslope(mycursectnum, adjustedPlayer.x, adjustedPlayer.y);
|
|
if ((mycursectnum == curSectNum) ||
|
|
(klabs(getflorzofslope(curSectNum, adjustedPlayer.x, adjustedPlayer.y) - slopeZ) <= ZOFFSET6))
|
|
myhorizoff += fix16_from_int(mulscale16(trueFloorZ - slopeZ, 160));
|
|
}
|
|
}
|
|
if (myhorizoff > 0)
|
|
{
|
|
myhorizoff -= ((myhorizoff >> 3) + fix16_one);
|
|
myhorizoff = max(myhorizoff, 0);
|
|
}
|
|
else if (myhorizoff < 0)
|
|
{
|
|
myhorizoff += (((-myhorizoff) >> 3) + fix16_one);
|
|
myhorizoff = min(myhorizoff, 0);
|
|
}
|
|
|
|
if (highZhit >= 0 && (highZhit&49152) == 49152)
|
|
{
|
|
highZhit &= (MAXSPRITES-1);
|
|
|
|
if (sprite[highZhit].statnum == STAT_ACTOR && sprite[highZhit].extra >= 0)
|
|
{
|
|
highZhit = 0;
|
|
ceilZ = truecz;
|
|
}
|
|
if (RR)
|
|
{
|
|
if (sprite[highZhit].picnum == RRTILE3587)
|
|
{
|
|
if (!my_stairs)
|
|
{
|
|
my_stairs = 10;
|
|
if (TEST_SYNC_KEY(playerBits, SK_JUMP) && (!RRRA || !pPlayer->on_motorcycle))
|
|
{
|
|
highZhit = 0;
|
|
ceilZ = pPlayer->truecz;
|
|
}
|
|
}
|
|
else
|
|
my_stairs--;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lowZhit >= 0 && (lowZhit&49152) == 49152)
|
|
{
|
|
int spriteNum = lowZhit&(MAXSPRITES-1);
|
|
|
|
if ((sprite[spriteNum].cstat&33) == 33)
|
|
{
|
|
sectorLotag = 0;
|
|
spritebridge = 1;
|
|
//pPlayer->sbs = spriteNum;
|
|
}
|
|
else if (!RRRA)
|
|
goto check_enemy_sprite;
|
|
|
|
if (RRRA)
|
|
{
|
|
if (pPlayer->on_motorcycle)
|
|
{
|
|
if (A_CheckEnemySprite(&sprite[spriteNum]))
|
|
{
|
|
my_moto_speed -= my_moto_speed >> 4;
|
|
}
|
|
}
|
|
if (pPlayer->on_boat)
|
|
{
|
|
if (A_CheckEnemySprite(&sprite[spriteNum]))
|
|
{
|
|
my_moto_speed -= my_moto_speed >> 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
check_enemy_sprite:
|
|
if (A_CheckEnemySprite(&sprite[spriteNum]) && sprite[spriteNum].xrepeat > 24
|
|
&& klabs(pSprite->z - sprite[spriteNum].z) < (84 << 8))
|
|
{
|
|
// TX: I think this is what makes the player slide off enemies... might
|
|
// be a good sprite flag to add later.
|
|
// Helix: there's also SLIDE_ABOVE_ENEMY.
|
|
int spriteAng = getangle(sprite[spriteNum].x - mypos.x,
|
|
sprite[spriteNum].y - mypos.y);
|
|
myvel.x -= sintable[(spriteAng + 512) & 2047] << 4;
|
|
myvel.y -= sintable[spriteAng & 2047] << 4;
|
|
}
|
|
}
|
|
}
|
|
if (RR)
|
|
{
|
|
if (sprite[spriteNum].picnum == RRTILE3587)
|
|
{
|
|
if (!my_stairs)
|
|
{
|
|
my_stairs = 10;
|
|
if (TEST_SYNC_KEY(playerBits, SK_CROUCH) && (!RRRA || !pPlayer->on_motorcycle))
|
|
{
|
|
ceilZ = sprite[spriteNum].z;
|
|
highZhit = 0;
|
|
floorZ = sprite[spriteNum].z + ZOFFSET6;
|
|
}
|
|
}
|
|
else
|
|
my_stairs--;
|
|
}
|
|
}
|
|
}
|
|
|
|
int velocityModifier = TICSPERFRAME;
|
|
int floorZOffset = 40;
|
|
int const playerShrunk = (pSprite->yrepeat < (RR ? 8 : 32));
|
|
|
|
if (pSprite->extra <= 0)
|
|
{
|
|
if (sectorLotag == ST_2_UNDERWATER)
|
|
{
|
|
if (pPlayer->on_warping_sector == 0)
|
|
{
|
|
if (klabs(mypos.z - floorZ) >(PHEIGHT>>1))
|
|
mypos.z += 348;
|
|
}
|
|
clipmove(&mypos, &mycursectnum,
|
|
0, 0, 164, (4L<<8), (4L<<8), CLIPMASK0);
|
|
}
|
|
|
|
updatesector(mypos.x, mypos.y, &mycursectnum);
|
|
pushmove(&mypos, &mycursectnum, 128L, (4L<<8), (20L<<8), CLIPMASK0);
|
|
|
|
myhoriz = F16(100);
|
|
myhorizoff = 0;
|
|
|
|
goto ENDFAKEPROCESSINPUT;
|
|
}
|
|
|
|
if (pPlayer->on_crane >= 0)
|
|
goto FAKEHORIZONLY;
|
|
|
|
if (pPlayer->one_eighty_count < 0)
|
|
myang += F16(128);
|
|
|
|
if (sectorLotag == ST_2_UNDERWATER)
|
|
{
|
|
myjumpingcounter = 0;
|
|
|
|
if (TEST_SYNC_KEY(playerBits, SK_JUMP))
|
|
{
|
|
myvel.z = max(min(-348, myvel.z - 348), -(256 * 6));
|
|
}
|
|
else if (TEST_SYNC_KEY(playerBits, SK_CROUCH))
|
|
{
|
|
myvel.z = min(max(348, myvel.z + 348), (256 * 6));
|
|
}
|
|
else
|
|
{
|
|
// normal view
|
|
if (myvel.z < 0)
|
|
myvel.z = min(0, myvel.z + 256);
|
|
|
|
if (myvel.z > 0)
|
|
myvel.z = max(0, myvel.z - 256);
|
|
}
|
|
|
|
if (myvel.z > 2048)
|
|
myvel.z >>= 1;
|
|
|
|
mypos.z += myvel.z;
|
|
|
|
if (mypos.z > (floorZ-(15<<8)))
|
|
mypos.z += ((floorZ-(15<<8))-mypos.z)>>1;
|
|
|
|
if (mypos.z < ceilZ+ZOFFSET6)
|
|
{
|
|
mypos.z = ceilZ+ZOFFSET6;
|
|
myvel.z = 0;
|
|
}
|
|
}
|
|
else if (!RR && pPlayer->jetpack_on)
|
|
{
|
|
myonground = 0;
|
|
myjumpingcounter = 0;
|
|
myhardlanding = 0;
|
|
|
|
if (pPlayer->jetpack_on < 11)
|
|
mypos.z -= (pPlayer->jetpack_on<<7); //Goin up
|
|
|
|
int const zAdjust = playerShrunk ? 512 : 2048;
|
|
|
|
if (TEST_SYNC_KEY(playerBits, SK_JUMP)) // jumping, flying up
|
|
{
|
|
mypos.z -= zAdjust;
|
|
}
|
|
|
|
if (TEST_SYNC_KEY(playerBits, SK_CROUCH)) // crouching, flying down
|
|
{
|
|
mypos.z += zAdjust;
|
|
}
|
|
|
|
int const Zdiff = (playerShrunk == 0 && (sectorLotag == 0 || sectorLotag == ST_2_UNDERWATER)) ? 32 : 16;
|
|
|
|
if (mypos.z > (floorZ - (Zdiff << 8)))
|
|
mypos.z += ((floorZ - (Zdiff << 8)) - mypos.z) >> 1;
|
|
|
|
if (mypos.z < (ceilZ + (18 << 8)))
|
|
mypos.z = ceilZ + (18 << 8);
|
|
}
|
|
else
|
|
{
|
|
if (sectorLotag == ST_1_ABOVE_WATER && spritebridge == 0)
|
|
{
|
|
floorZOffset = playerShrunk ? 12 : 34;
|
|
}
|
|
if (mypos.z < (floorZ-(floorZOffset<<8))) //falling
|
|
{
|
|
if ((!TEST_SYNC_KEY(playerBits, SK_JUMP) && !TEST_SYNC_KEY(playerBits, SK_CROUCH)) && myonground &&
|
|
(sector[mycursectnum].floorstat & 2) && mypos.z >= (floorZ - (floorZOffset << 8) - ZOFFSET2))
|
|
mypos.z = floorZ - (floorZOffset << 8);
|
|
else
|
|
{
|
|
myonground = 0;
|
|
|
|
if (RRRA && (pPlayer->on_motorcycle || pPlayer->on_boat) && floorZ - (floorZOffset << 9) > mypos.z)
|
|
{
|
|
if (my_moto_on_ground)
|
|
{
|
|
my_moto_bump_target = 80;
|
|
my_moto_bump_fast = 1;
|
|
myvel.z -= g_spriteGravity*(my_moto_speed>>4);
|
|
my_moto_on_ground = 0;
|
|
}
|
|
else
|
|
{
|
|
myvel.z += g_spriteGravity-80+(120-my_moto_speed);
|
|
}
|
|
}
|
|
else
|
|
myvel.z += (g_spriteGravity + 80);
|
|
|
|
if (myvel.z >= (4096 + 2048))
|
|
myvel.z = (4096 + 2048);
|
|
|
|
if ((mypos.z + myvel.z) >= (floorZ - (floorZOffset << 8)) && mycursectnum >= 0) // hit the ground
|
|
{
|
|
if (sector[mycursectnum].lotag != ST_1_ABOVE_WATER)
|
|
{
|
|
if (RRRA)
|
|
my_moto_on_ground = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
if ((sectorLotag != ST_1_ABOVE_WATER && sectorLotag != ST_2_UNDERWATER) &&
|
|
(myonground == 0 && myvel.z > (6144 >> 1)))
|
|
myhardlanding = myvel.z>>10;
|
|
myonground = 1;
|
|
|
|
if (floorZOffset == 40)
|
|
{
|
|
//Smooth on the ground
|
|
int Zdiff = ((floorZ - (floorZOffset << 8)) - mypos.z) >> 1;
|
|
|
|
if (klabs(Zdiff) < 256)
|
|
Zdiff = 0;
|
|
|
|
mypos.z += ((klabs(Zdiff) >= 256) ? (((floorZ - (floorZOffset << 8)) - mypos.z) >> 1) : 0);
|
|
//myz += k; // ((fz-(i<<8))-myz)>>1;
|
|
myvel.z -= 768; // 412;
|
|
if (myvel.z < 0)
|
|
myvel.z = 0;
|
|
}
|
|
else if (myjumpingcounter == 0)
|
|
{
|
|
mypos.z += ((floorZ - (floorZOffset << 7)) - mypos.z) >> 1; // Smooth on the water
|
|
|
|
if (pPlayer->on_warping_sector == 0 && mypos.z > floorZ - ZOFFSET2)
|
|
{
|
|
mypos.z = floorZ - ZOFFSET2;
|
|
myvel.z >>= 1;
|
|
}
|
|
}
|
|
|
|
if (TEST_SYNC_KEY(playerBits, SK_CROUCH) && (!RRRA || !pPlayer->on_motorcycle))
|
|
mypos.z += (2048+768);
|
|
|
|
if (!TEST_SYNC_KEY(playerBits, SK_JUMP) && (!RRRA || !pPlayer->on_motorcycle) && myjumpingtoggle == 1)
|
|
myjumpingtoggle = 0;
|
|
else if (TEST_SYNC_KEY(playerBits, SK_JUMP) && (!RRRA || !pPlayer->on_motorcycle) && myjumpingtoggle == 0)
|
|
{
|
|
if (myjumpingcounter == 0)
|
|
if ((floorZ-ceilZ) > (56<<8))
|
|
{
|
|
myjumpingcounter = 1;
|
|
myjumpingtoggle = 1;
|
|
}
|
|
}
|
|
if (!RR && myjumpingcounter && !TEST_SYNC_KEY(playerBits, SK_JUMP))
|
|
myjumpingcounter = 0;
|
|
}
|
|
|
|
if (myjumpingcounter)
|
|
{
|
|
if (!TEST_SYNC_KEY(playerBits, SK_JUMP) && (!RRRA || !pPlayer->on_motorcycle) && myjumpingtoggle == 1)
|
|
myjumpingtoggle = 0;
|
|
|
|
if (myjumpingcounter < (RR ? 768 : (1024+256)))
|
|
{
|
|
if (sectorLotag == ST_1_ABOVE_WATER && myjumpingcounter > 768)
|
|
{
|
|
myjumpingcounter = 0;
|
|
myvel.z = -512;
|
|
}
|
|
else
|
|
{
|
|
myvel.z -= (sintable[(2048-128+myjumpingcounter)&2047])/12;
|
|
myjumpingcounter += 180;
|
|
myonground = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
myjumpingcounter = 0;
|
|
myvel.z = 0;
|
|
}
|
|
}
|
|
|
|
mypos.z += myvel.z;
|
|
|
|
if (mypos.z < (ceilZ+ZOFFSET6))
|
|
{
|
|
myjumpingcounter = 0;
|
|
if (myvel.z < 0)
|
|
myvel.x = myvel.y = 0;
|
|
myvel.z = 128;
|
|
mypos.z = ceilZ+ZOFFSET6;
|
|
}
|
|
|
|
}
|
|
|
|
if (pPlayer->fist_incs || pPlayer->transporter_hold > 2 || myhardlanding || pPlayer->access_incs > 0 ||
|
|
pPlayer->knee_incs > 0 || (!RR && pPlayer->curr_weapon == TRIPBOMB_WEAPON &&
|
|
pPlayer->kickback_pic > 1 && pPlayer->kickback_pic < 4))
|
|
{
|
|
velocityModifier = 0;
|
|
myvel.x = 0;
|
|
myvel.y = 0;
|
|
}
|
|
else if (pInput->q16avel) //p->ang += syncangvel * constant
|
|
{
|
|
fix16_t const inputAng = pInput->q16avel;
|
|
|
|
myang += (sectorLotag == ST_2_UNDERWATER) ? fix16_mul(inputAng - (inputAng >> 3), fix16_from_int(ksgn(velocityModifier)))
|
|
: fix16_mul(inputAng, fix16_from_int(ksgn(velocityModifier)));
|
|
|
|
myang &= 0x7FFFFFF;
|
|
}
|
|
|
|
if (myvel.x || myvel.y || pInput->fvel || pInput->svel)
|
|
{
|
|
if (RRRA)
|
|
{
|
|
if (spritebridge == 0 && myonground)
|
|
{
|
|
if (sectorLotag == ST_1_ABOVE_WATER)
|
|
my_not_on_water = 0;
|
|
else if (pPlayer->on_boat)
|
|
{
|
|
if (sectorLotag == 1234)
|
|
my_not_on_water = 0;
|
|
else
|
|
my_not_on_water = 1;
|
|
}
|
|
else
|
|
my_not_on_water = 1;
|
|
}
|
|
}
|
|
if (pPlayer->jetpack_on == 0 && pPlayer->inv_amount[GET_STEROIDS] > 0 && pPlayer->inv_amount[GET_STEROIDS] < 400)
|
|
velocityModifier <<= 1;
|
|
|
|
myvel.x += ((pInput->fvel * velocityModifier) << 6);
|
|
myvel.y += ((pInput->svel * velocityModifier) << 6);
|
|
|
|
int playerSpeedReduction = 0;
|
|
|
|
if (!RRRA && myonground && (TEST_SYNC_KEY(playerBits, SK_CROUCH)
|
|
|| (pPlayer->kickback_pic > 10 && pPlayer->curr_weapon == KNEE_WEAPON)))
|
|
playerSpeedReduction = 0x2000;
|
|
else if (sectorLotag == ST_2_UNDERWATER)
|
|
playerSpeedReduction = 0x1400;
|
|
|
|
myvel.x = mulscale16(myvel.x, pPlayer->runspeed - playerSpeedReduction);
|
|
myvel.y = mulscale16(myvel.y, pPlayer->runspeed - playerSpeedReduction);
|
|
|
|
if (RR)
|
|
{
|
|
if (RRRA)
|
|
{
|
|
if (sector[mycursectnum].floorpicnum == RRTILE7888)
|
|
{
|
|
if (pPlayer->on_motorcycle && myonground)
|
|
my_moto_on_oil = 1;
|
|
}
|
|
else if (sector[mycursectnum].floorpicnum == RRTILE7889)
|
|
{
|
|
if (pPlayer->on_motorcycle)
|
|
{
|
|
if (myonground)
|
|
my_moto_on_mud = 1;
|
|
}
|
|
else if (pPlayer->inv_amount[GET_BOOTS] <= 0)
|
|
{
|
|
myvel.x = mulscale16(myvel.x, pPlayer->runspeed);
|
|
myvel.y = mulscale16(myvel.y, pPlayer->runspeed);
|
|
}
|
|
}
|
|
}
|
|
if (sector[mycursectnum].floorpicnum == RRTILE3073 || sector[mycursectnum].floorpicnum == RRTILE2702)
|
|
{
|
|
if (RRRA && pPlayer->on_motorcycle)
|
|
{
|
|
if (myonground)
|
|
{
|
|
myvel.x = mulscale16(myvel.x, pPlayer->runspeed-0x1800);
|
|
myvel.y = mulscale16(myvel.y, pPlayer->runspeed-0x1800);
|
|
}
|
|
}
|
|
else if (pPlayer->inv_amount[GET_BOOTS] <= 0)
|
|
{
|
|
myvel.x = mulscale16(myvel.x, pPlayer->runspeed-0x1800);
|
|
myvel.y = mulscale16(myvel.y, pPlayer->runspeed-0x1800);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (klabs(myvel.x) < 2048 && klabs(myvel.y) < 2048)
|
|
myvel.x = myvel.y = 0;
|
|
|
|
if (playerShrunk)
|
|
{
|
|
myvel.x = mulscale16(myvel.x, pPlayer->runspeed - (pPlayer->runspeed >> 1) + (pPlayer->runspeed >> 2));
|
|
myvel.y = mulscale16(myvel.y, pPlayer->runspeed - (pPlayer->runspeed >> 1) + (pPlayer->runspeed >> 2));
|
|
}
|
|
}
|
|
|
|
FAKEHORIZONLY:;
|
|
stepHeight = (sectorLotag == ST_1_ABOVE_WATER || spritebridge == 1) ? pPlayer->autostep_sbw : pPlayer->autostep;
|
|
|
|
#ifdef YAX_ENABLE
|
|
if (mycursectnum >= 0)
|
|
yax_getbunches(mycursectnum, &ceilingBunch, &floorBunch);
|
|
|
|
// This updatesectorz conflicts with Duke3D's way of teleporting through water,
|
|
// so make it a bit conditional... OTOH, this way we have an ugly z jump when
|
|
// changing from above water to underwater
|
|
|
|
if ((mycursectnum >= 0 && !(sector[mycursectnum].lotag == ST_1_ABOVE_WATER && myonground && floorBunch >= 0))
|
|
&& ((floorBunch >= 0 && !(sector[mycursectnum].floorstat & 512))
|
|
|| (ceilingBunch >= 0 && !(sector[mycursectnum].ceilingstat & 512))))
|
|
{
|
|
mycursectnum += MAXSECTORS; // skip initial z check, restored by updatesectorz
|
|
updatesectorz(mypos.x, mypos.y, mypos.z, &mycursectnum);
|
|
}
|
|
#endif
|
|
clipmove(&mypos, &mycursectnum, myvel.x, myvel.y, 164, (4L << 8), stepHeight, CLIPMASK0);
|
|
pushmove(&mypos, &mycursectnum, 164, (4L << 8), (4L << 8), CLIPMASK0);
|
|
|
|
// This makes the player view lower when shrunk. NOTE that it can get the
|
|
// view below the sector floor (and does, when on the ground).
|
|
if (pPlayer->jetpack_on == 0 && sectorLotag != ST_2_UNDERWATER && sectorLotag != ST_1_ABOVE_WATER && playerShrunk)
|
|
mypos.z += ZOFFSET5;
|
|
|
|
if (RR)
|
|
{
|
|
if ((spriteNum & 49152) == 32768)
|
|
{
|
|
int const wallNum = spriteNum&(MAXWALLS-1);
|
|
if (RRRA && pPlayer->on_motorcycle)
|
|
{
|
|
int16_t var108, var10c;
|
|
var108 = getangle(wall[wall[wallNum].point2].x-wall[wallNum].x,wall[wall[wallNum].point2].y-wall[wallNum].y);
|
|
var10c = klabs(fix16_to_int(myang)-var108);
|
|
if (var10c >= 441 && var10c <= 581)
|
|
{
|
|
my_moto_speed = 0;
|
|
}
|
|
else if (var10c >= 311 && var10c <= 711)
|
|
{
|
|
my_moto_speed -= (my_moto_speed>>1)+(my_moto_speed>>2);
|
|
}
|
|
else if (var10c >= 111 && var10c <= 911)
|
|
{
|
|
my_moto_speed -= (my_moto_speed>>1);
|
|
}
|
|
else
|
|
{
|
|
my_moto_speed -= (my_moto_speed>>3);
|
|
}
|
|
}
|
|
else if (RRRA && pPlayer->on_boat)
|
|
{
|
|
short var114, var118;
|
|
var114 = getangle(wall[wall[wallNum].point2].x-wall[wallNum].x,wall[wall[wallNum].point2].y-wall[wallNum].y);
|
|
var118 = klabs(fix16_to_int(myang)-var114);
|
|
if (var118 >= 441 && var118 <= 581)
|
|
{
|
|
my_moto_speed = ((my_moto_speed>>1)+(my_moto_speed>>2))>>2;
|
|
}
|
|
else if (var118 >= 311 && var118 <= 711)
|
|
{
|
|
my_moto_speed -= ((my_moto_speed>>1)+(my_moto_speed>>2))>>3;
|
|
}
|
|
else if (var118 >= 111 && var118 <= 911)
|
|
{
|
|
my_moto_speed -= (my_moto_speed>>4);
|
|
}
|
|
else
|
|
{
|
|
my_moto_speed -= (my_moto_speed>>6);
|
|
}
|
|
}
|
|
}
|
|
else if ((spriteNum & 49152) == 49152)
|
|
{
|
|
spriteNum &= (MAXSPRITES-1);
|
|
|
|
if (RRRA && pPlayer->on_motorcycle)
|
|
{
|
|
if (A_CheckEnemySprite(&sprite[spriteNum]) || sprite[spriteNum].picnum == APLAYER)
|
|
{
|
|
my_moto_speed -= my_moto_speed>>2;
|
|
my_moto_turb = 6;
|
|
}
|
|
}
|
|
else if (RRRA && pPlayer->on_boat)
|
|
{
|
|
if (A_CheckEnemySprite(&sprite[spriteNum]) || sprite[spriteNum].picnum == APLAYER)
|
|
{
|
|
my_moto_speed -= my_moto_speed>>2;
|
|
my_moto_turb = 6;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
centerHoriz = 0;
|
|
if (TEST_SYNC_KEY(playerBits, SK_CENTER_VIEW) || myhardlanding)
|
|
myreturntocenter = 9;
|
|
|
|
if (TEST_SYNC_KEY(playerBits, SK_LOOK_UP))
|
|
{
|
|
myreturntocenter = 9;
|
|
myhoriz += fix16_from_int(12<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN)));
|
|
centerHoriz++;
|
|
}
|
|
else if (TEST_SYNC_KEY(playerBits, SK_LOOK_DOWN))
|
|
{
|
|
myreturntocenter = 9;
|
|
myhoriz -= fix16_from_int(12<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN)));
|
|
centerHoriz++;
|
|
}
|
|
else if (TEST_SYNC_KEY(playerBits, SK_AIM_UP))
|
|
{
|
|
myhoriz += fix16_from_int(6<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN)));
|
|
centerHoriz++;
|
|
}
|
|
else if (TEST_SYNC_KEY(playerBits, SK_AIM_DOWN))
|
|
{
|
|
myhoriz -= fix16_from_int(6<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN)));
|
|
centerHoriz++;
|
|
}
|
|
|
|
if (RR && pPlayer->recoil && pPlayer->kickback_pic == 0)
|
|
{
|
|
int delta = pPlayer->recoil >> 1;
|
|
if (!delta) delta++;
|
|
myhoriz -= F16(delta);
|
|
}
|
|
if (myreturntocenter > 0 && !TEST_SYNC_KEY(playerBits, SK_LOOK_UP) && !TEST_SYNC_KEY(playerBits, SK_LOOK_DOWN))
|
|
{
|
|
myreturntocenter--;
|
|
myhoriz += F16(33)-fix16_div(myhoriz, F16(3));
|
|
centerHoriz++;
|
|
}
|
|
if (myhardlanding > 0)
|
|
{
|
|
myhardlanding--;
|
|
myhoriz -= fix16_from_int(myhardlanding<<4);
|
|
}
|
|
|
|
myhoriz = fix16_clamp(myhoriz + pInput->q16horz, F16(HORIZ_MIN), F16(HORIZ_MAX));
|
|
|
|
if (centerHoriz)
|
|
{
|
|
if (myhoriz > F16(95) && myhoriz < F16(105)) myhoriz = F16(100);
|
|
if (myhorizoff > F16(-5) && myhorizoff < F16(5)) myhorizoff = 0;
|
|
}
|
|
|
|
if (pPlayer->knee_incs > 0)
|
|
{
|
|
myhoriz -= F16(48);
|
|
myreturntocenter = 9;
|
|
}
|
|
|
|
|
|
ENDFAKEPROCESSINPUT:
|
|
|
|
myposbak[predictfifoplc&(MOVEFIFOSIZ-1)] = mypos;
|
|
myangbak[predictfifoplc&(MOVEFIFOSIZ-1)] = myang;
|
|
myhorizbak[predictfifoplc&(MOVEFIFOSIZ-1)] = myhoriz;
|
|
predictfifoplc++;
|
|
|
|
pSprite->cstat = backcstat;
|
|
}
|
|
|
|
void Net_CorrectPrediction(void)
|
|
{
|
|
if (numplayers < 2)
|
|
return;
|
|
|
|
int i = ((movefifoplc-1)&(MOVEFIFOSIZ-1));
|
|
DukePlayer_t *p = g_player[myconnectindex].ps;
|
|
|
|
if (!Bmemcmp(&p->pos, &myposbak[i], sizeof(vec3_t))
|
|
&& p->q16horiz == myhorizbak[i] && p->q16ang == myangbak[i]) return;
|
|
|
|
mypos = p->pos; omypos = p->opos, myvel = p->vel;
|
|
myang = p->q16ang; omyang = p->oq16ang;
|
|
mycursectnum = p->cursectnum;
|
|
myhoriz = p->q16horiz; omyhoriz = p->oq16horiz;
|
|
myhorizoff = p->q16horizoff; omyhorizoff = p->oq16horizoff;
|
|
myjumpingcounter = p->jumping_counter;
|
|
myjumpingtoggle = p->jumping_toggle;
|
|
myonground = p->on_ground;
|
|
myhardlanding = p->hard_landing;
|
|
myreturntocenter = p->return_to_center;
|
|
my_moto_speed = p->moto_speed;
|
|
my_not_on_water = p->not_on_water;
|
|
my_moto_on_ground = p->moto_on_ground;
|
|
my_moto_do_bump = p->moto_do_bump;
|
|
my_moto_bump_fast = p->moto_bump_fast;
|
|
my_moto_on_oil = p->moto_on_oil;
|
|
my_moto_on_mud = p->moto_on_mud;
|
|
my_moto_bump = p->moto_do_bump;
|
|
my_moto_bump_target = p->moto_bump_target;
|
|
my_moto_turb = p->moto_turb;
|
|
my_stairs = p->stairs;
|
|
|
|
predictfifoplc = movefifoplc;
|
|
while (predictfifoplc < g_player[myconnectindex].movefifoend)
|
|
Net_DoPrediction();
|
|
}
|
|
|
|
int g_numSyncBytes = 1;
|
|
char g_szfirstSyncMsg[MAXSYNCBYTES][60];
|
|
int g_foundSyncError = 0;
|
|
|
|
char syncstat[MAXSYNCBYTES];
|
|
int syncvaltail, syncvaltottail;
|
|
|
|
static int crctable[256];
|
|
#define updatecrc(dcrc,xz) (dcrc = (crctable[((dcrc)>>8)^((xz)&255)]^((dcrc)<<8)))
|
|
|
|
void initsynccrc(void)
|
|
{
|
|
int i, j, k, a;
|
|
|
|
for (j=0;j<256;j++) //Calculate CRC table
|
|
{
|
|
k = (j<<8); a = 0;
|
|
for (i=7;i>=0;i--)
|
|
{
|
|
if (((k^a)&0x8000) > 0)
|
|
a = ((a<<1)&65535) ^ 0x1021; //0x1021 = genpoly
|
|
else
|
|
a = ((a<<1)&65535);
|
|
k = ((k<<1)&65535);
|
|
}
|
|
crctable[j] = (a&65535);
|
|
}
|
|
}
|
|
|
|
char Net_PlayerSync(void)
|
|
{
|
|
uint16_t crc = 0;
|
|
DukePlayer_t *pp;
|
|
|
|
for(int TRAVERSE_CONNECT(i))
|
|
{
|
|
pp = g_player[i].ps;
|
|
updatecrc(crc, pp->pos.x & 255);
|
|
updatecrc(crc, pp->pos.y & 255);
|
|
updatecrc(crc, pp->pos.z & 255);
|
|
updatecrc(crc, pp->q16ang & 255);
|
|
}
|
|
|
|
return ((char) crc & 255);
|
|
}
|
|
|
|
char Net_PlayerSync2(void)
|
|
{
|
|
int nextj;
|
|
uint16_t crc = 0;
|
|
DukePlayer_t *pp;
|
|
spritetype *spr;
|
|
|
|
for (int TRAVERSE_CONNECT(i))
|
|
{
|
|
pp = g_player[i].ps;
|
|
|
|
updatecrc(crc, pp->q16horiz & 255);
|
|
updatecrc(crc, sprite[pp->i].extra & 255);
|
|
updatecrc(crc, pp->bobcounter & 255);
|
|
}
|
|
|
|
for (int TRAVERSE_SPRITE_STAT(headspritestat[STAT_PLAYER], j, nextj))
|
|
{
|
|
spr = &sprite[j];
|
|
updatecrc(crc, (spr->x) & 255);
|
|
updatecrc(crc, (spr->y) & 255);
|
|
updatecrc(crc, (spr->z) & 255);
|
|
updatecrc(crc, (spr->ang) & 255);
|
|
}
|
|
|
|
return ((char) crc & 255);
|
|
}
|
|
|
|
char Net_ActorSync(void)
|
|
{
|
|
uint16_t crc = 0;
|
|
int nextj;
|
|
spritetype *spr;
|
|
|
|
for (int TRAVERSE_SPRITE_STAT(headspritestat[STAT_ACTOR], j, nextj))
|
|
{
|
|
spr = &sprite[j];
|
|
updatecrc(crc, (spr->x) & 255);
|
|
updatecrc(crc, (spr->y) & 255);
|
|
updatecrc(crc, (spr->z) & 255);
|
|
updatecrc(crc, (spr->lotag) & 255);
|
|
updatecrc(crc, (spr->hitag) & 255);
|
|
updatecrc(crc, (spr->ang) & 255);
|
|
}
|
|
|
|
for (int TRAVERSE_SPRITE_STAT(headspritestat[STAT_ZOMBIEACTOR], j, nextj))
|
|
{
|
|
spr = &sprite[j];
|
|
updatecrc(crc, (spr->x) & 255);
|
|
updatecrc(crc, (spr->y) & 255);
|
|
updatecrc(crc, (spr->z) & 255);
|
|
updatecrc(crc, (spr->lotag) & 255);
|
|
updatecrc(crc, (spr->hitag) & 255);
|
|
updatecrc(crc, (spr->ang) & 255);
|
|
}
|
|
|
|
return ((char) crc & 255);
|
|
}
|
|
|
|
char Net_WeaponSync(void)
|
|
{
|
|
uint16_t crc = 0;
|
|
int nextj;
|
|
spritetype *spr;
|
|
|
|
for (int TRAVERSE_SPRITE_STAT(headspritestat[STAT_PROJECTILE], j, nextj))
|
|
{
|
|
spr = &sprite[j];
|
|
updatecrc(crc, (spr->x) & 255);
|
|
updatecrc(crc, (spr->y) & 255);
|
|
updatecrc(crc, (spr->z) & 255);
|
|
updatecrc(crc, (spr->ang) & 255);
|
|
}
|
|
|
|
return ((char) crc & 255);
|
|
}
|
|
|
|
char Net_MapSync(void)
|
|
{
|
|
uint16_t crc = 0;
|
|
int nextj;
|
|
spritetype *spr;
|
|
walltype *wal;
|
|
sectortype *sect;
|
|
|
|
for (int TRAVERSE_SPRITE_STAT(headspritestat[STAT_EFFECTOR], j, nextj))
|
|
{
|
|
spr = &sprite[j];
|
|
updatecrc(crc, (spr->x) & 255);
|
|
updatecrc(crc, (spr->y) & 255);
|
|
updatecrc(crc, (spr->z) & 255);
|
|
updatecrc(crc, (spr->ang) & 255);
|
|
updatecrc(crc, (spr->lotag) & 255);
|
|
updatecrc(crc, (spr->hitag) & 255);
|
|
}
|
|
|
|
for (int j=numwalls;j>=0;j--)
|
|
{
|
|
wal = &wall[j];
|
|
updatecrc(crc, (wal->x) & 255);
|
|
updatecrc(crc, (wal->y) & 255);
|
|
}
|
|
|
|
for (int j=numsectors;j>=0;j--)
|
|
{
|
|
sect = §or[j];
|
|
updatecrc(crc, (sect->floorz) & 255);
|
|
updatecrc(crc, (sect->ceilingz) & 255);
|
|
}
|
|
|
|
return ((char) crc & 255);
|
|
}
|
|
|
|
char Net_RandomSync(void)
|
|
{
|
|
unsigned short crc = 0;
|
|
|
|
updatecrc(crc, randomseed & 255);
|
|
updatecrc(crc, (randomseed >> 8) & 255);
|
|
updatecrc(crc, g_globalRandom & 255);
|
|
updatecrc(crc, (g_globalRandom >> 8) & 255);
|
|
|
|
if (g_numSyncBytes == 1)
|
|
{
|
|
updatecrc(crc,Net_PlayerSync() & 255);
|
|
updatecrc(crc,Net_PlayerSync2() & 255);
|
|
updatecrc(crc,Net_WeaponSync() & 255);
|
|
updatecrc(crc,Net_ActorSync() & 255);
|
|
updatecrc(crc,Net_MapSync() & 255);
|
|
}
|
|
|
|
return ((char) crc & 255);
|
|
}
|
|
|
|
const char *SyncNames[] =
|
|
{
|
|
"Net_CheckRandomSync",
|
|
"Net_CheckPlayerSync",
|
|
"Net_CheckPlayerSync2",
|
|
"Net_CheckWeaponSync",
|
|
"Net_CheckActorSync",
|
|
"Net_CheckMapSync",
|
|
NULL
|
|
};
|
|
|
|
static char(*SyncFunc[MAXSYNCBYTES + 1])(void) =
|
|
{
|
|
Net_RandomSync,
|
|
Net_PlayerSync,
|
|
Net_PlayerSync2,
|
|
Net_WeaponSync,
|
|
Net_ActorSync,
|
|
Net_MapSync,
|
|
NULL
|
|
};
|
|
|
|
void Net_GetSyncStat(void)
|
|
{
|
|
int i;
|
|
playerdata_t *pp = &g_player[myconnectindex];
|
|
unsigned int val;
|
|
static unsigned int count;
|
|
|
|
if (numplayers < 2)
|
|
return;
|
|
|
|
for (i = 0; SyncFunc[i]; i++)
|
|
{
|
|
pp->syncval[pp->syncvalhead & (SYNCFIFOSIZ - 1)][i] = (*SyncFunc[i])();
|
|
}
|
|
|
|
val = pp->syncval[pp->syncvalhead & (SYNCFIFOSIZ - 1)][0];
|
|
count += val;
|
|
|
|
pp->syncvalhead++;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Sync Message print
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
void Net_DisplaySyncMsg(void)
|
|
{
|
|
int i, j;
|
|
static unsigned int moveCount = 0;
|
|
extern unsigned int g_moveThingsCount;
|
|
|
|
// if (!SyncPrintMode)
|
|
// return;
|
|
|
|
if (numplayers < 2)
|
|
return;
|
|
|
|
for (i = 0; i < g_numSyncBytes; i++)
|
|
{
|
|
// syncstat is NON 0 - out of sync
|
|
if (syncstat[i] != 0)
|
|
{
|
|
if (g_numSyncBytes > 1)
|
|
{
|
|
Bsprintf(tempbuf, "Out Of Sync - %s", SyncNames[i]);
|
|
printext256(4L, 100L + (i * 8), 31, 1, tempbuf, 0);
|
|
}
|
|
|
|
if (!g_foundSyncError && g_szfirstSyncMsg[i][0] == '\0')
|
|
{
|
|
// g_foundSyncError one so test all of them and then never test again
|
|
g_foundSyncError = 1;
|
|
|
|
// save off loop count
|
|
moveCount = g_moveThingsCount;
|
|
|
|
for (j = 0; j < g_numSyncBytes; j++)
|
|
{
|
|
if (syncstat[j] != 0 && g_szfirstSyncMsg[j][0] == '\0')
|
|
{
|
|
Bsprintf(tempbuf, "Out Of Sync (%s) - Please restart game", SyncNames[j]);
|
|
Bstrcpy(g_szfirstSyncMsg[j], tempbuf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// print out the g_szfirstSyncMsg message you got
|
|
for (i = 0; i < g_numSyncBytes; i++)
|
|
{
|
|
if (g_szfirstSyncMsg[i][0] != '\0')
|
|
{
|
|
if (g_numSyncBytes > 1)
|
|
{
|
|
Bsprintf(tempbuf, "FIRST %s", g_szfirstSyncMsg[i]);
|
|
printext256(4L, 44L + (i * 8), 31, 1, tempbuf, 0);
|
|
Bsprintf(tempbuf, "moveCount %d",moveCount);
|
|
printext256(4L, 52L + (i * 8), 31, 1, tempbuf, 0);
|
|
}
|
|
else
|
|
{
|
|
printext256(4L,100L,31,0,g_szfirstSyncMsg[i],0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// if (syncstate != 0)
|
|
// printext256(68L, 92L, 1, 31, "Missed Network packet!", 0);
|
|
}
|
|
|
|
|
|
void Net_AddSyncInfoToPacket(int *j)
|
|
{
|
|
int sb;
|
|
int count = 0;
|
|
|
|
// sync testing
|
|
while (g_player[myconnectindex].syncvalhead != syncvaltail && count++ < 4)
|
|
{
|
|
for (sb = 0; sb < g_numSyncBytes; sb++)
|
|
packbuf[(*j)++] = g_player[myconnectindex].syncval[syncvaltail & (SYNCFIFOSIZ - 1)][sb];
|
|
|
|
syncvaltail++;
|
|
}
|
|
}
|
|
|
|
void Net_GetSyncInfoFromPacket(uint8_t *packbuf, int packbufleng, int *j, int otherconnectindex)
|
|
{
|
|
int sb;
|
|
extern int syncvaltail, syncvaltottail;
|
|
playerdata_t *ppo = &g_player[otherconnectindex];
|
|
char found = 0;
|
|
|
|
// have had problems with this routine crashing when players quit
|
|
// games.
|
|
|
|
// if ready2send is not set then don't try to get sync info
|
|
|
|
if (!ready2send)
|
|
return;
|
|
|
|
// Suspect that its trying to traverse the connect list
|
|
// for a player that does not exist. This tries to take care of that
|
|
|
|
for (int TRAVERSE_CONNECT(i))
|
|
{
|
|
if (otherconnectindex == i)
|
|
found = 1;
|
|
}
|
|
|
|
if (!found)
|
|
return;
|
|
|
|
// sync testing
|
|
//while ((*j) != packbufleng) // changed this on Kens suggestion
|
|
while ((*j) < packbufleng)
|
|
{
|
|
for (sb = 0; sb < g_numSyncBytes; sb++)
|
|
{
|
|
ppo->syncval[ppo->syncvalhead & (SYNCFIFOSIZ - 1)][sb] = packbuf[(*j)++];
|
|
}
|
|
ppo->syncvalhead++;
|
|
}
|
|
|
|
// update syncstat
|
|
// if any of the syncstat vars is non-0 then there is a problem
|
|
for (int TRAVERSE_CONNECT(i))
|
|
{
|
|
if (g_player[i].syncvalhead == syncvaltottail)
|
|
return;
|
|
}
|
|
|
|
//for (sb = 0; sb < g_numSyncBytes; sb++)
|
|
// syncstat[sb] = 0;
|
|
|
|
while (1)
|
|
{
|
|
for (int i = connectpoint2[connecthead]; i >= 0; i = connectpoint2[i])
|
|
{
|
|
for (sb = 0; sb < g_numSyncBytes; sb++)
|
|
{
|
|
if (g_player[i].connected && (g_player[i].syncval[syncvaltottail & (SYNCFIFOSIZ - 1)][sb] != g_player[connecthead].syncval[syncvaltottail & (SYNCFIFOSIZ - 1)][sb]))
|
|
{
|
|
syncstat[sb] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
syncvaltottail++;
|
|
|
|
for (int TRAVERSE_CONNECT(i))
|
|
{
|
|
if (g_player[i].syncvalhead == syncvaltottail)
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Net_ClearFIFO(void)
|
|
{
|
|
int i = 0;
|
|
|
|
syncvaltail = 0L;
|
|
syncvaltottail = 0L;
|
|
memset(&syncstat, 0, sizeof(syncstat));
|
|
memset(&g_szfirstSyncMsg, 0, sizeof(g_szfirstSyncMsg));
|
|
g_foundSyncError = 0;
|
|
|
|
bufferjitter = 1;
|
|
mymaxlag = otherminlag = 0;
|
|
movefifoplc = movefifosendplc = predictfifoplc = 0;
|
|
avgfvel = avgsvel = avgavel = avghorz = avgbits = avgextbits = 0;
|
|
|
|
for (; i < MAXPLAYERS; i++)
|
|
{
|
|
Bmemset(&g_player[i].movefifoend, 0, sizeof(g_player[i].movefifoend));
|
|
Bmemset(&g_player[i].syncvalhead, 0, sizeof(g_player[i].syncvalhead));
|
|
Bmemset(&g_player[i].myminlag, 0, sizeof(g_player[i].myminlag));
|
|
}
|
|
}
|
|
|
|
void Net_GetInput(void)
|
|
{
|
|
input_t* osyn, * nsyn;
|
|
|
|
if (numplayers > 1)
|
|
Net_GetPackets();
|
|
|
|
if (g_player[myconnectindex].movefifoend - movefifoplc >= 100)
|
|
return;
|
|
|
|
if (RRRA && g_player[myconnectindex].ps->on_motorcycle)
|
|
P_GetInputMotorcycle(myconnectindex);
|
|
else if (RRRA && g_player[myconnectindex].ps->on_boat)
|
|
P_GetInputBoat(myconnectindex);
|
|
else
|
|
P_GetInput(myconnectindex);
|
|
|
|
avgfvel += localInput.fvel;
|
|
avgsvel += localInput.svel;
|
|
avgavel += localInput.q16avel;
|
|
avghorz += localInput.q16horz;
|
|
avgbits |= localInput.bits;
|
|
avgextbits |= localInput.extbits;
|
|
|
|
if (g_player[myconnectindex].movefifoend&(g_movesPerPacket-1))
|
|
{
|
|
copybufbyte(&inputfifo[(g_player[myconnectindex].movefifoend-1)&(MOVEFIFOSIZ-1)][myconnectindex],
|
|
&inputfifo[g_player[myconnectindex].movefifoend&(MOVEFIFOSIZ-1)][myconnectindex],sizeof(input_t));
|
|
g_player[myconnectindex].movefifoend++;
|
|
return;
|
|
}
|
|
nsyn = &inputfifo[g_player[myconnectindex].movefifoend&(MOVEFIFOSIZ-1)][myconnectindex];
|
|
nsyn[0].fvel = avgfvel/g_movesPerPacket;
|
|
nsyn[0].svel = avgsvel/g_movesPerPacket;
|
|
nsyn[0].q16avel = avgavel/g_movesPerPacket;
|
|
nsyn[0].q16horz = avghorz/g_movesPerPacket;
|
|
nsyn[0].bits = avgbits;
|
|
nsyn[0].extbits = avgextbits;
|
|
avgfvel = avgsvel = avgavel = avghorz = avgbits = avgextbits = 0;
|
|
g_player[myconnectindex].movefifoend++;
|
|
|
|
#if 0
|
|
if (numplayers < 2)
|
|
{
|
|
if (ud.multimode > 1)
|
|
{
|
|
for (int TRAVERSE_CONNECT(i))
|
|
{
|
|
if (i != myconnectindex)
|
|
{
|
|
//clearbufbyte(&inputfifo[g_player[i].movefifoend&(MOVEFIFOSIZ-1)][i],sizeof(input_t),0L);
|
|
if (ud.playerai)
|
|
{
|
|
computergetinput(i, &inputfifo[g_player[i].movefifoend&(MOVEFIFOSIZ - 1)][i]);
|
|
inputfifo[g_player[i].movefifoend&(MOVEFIFOSIZ - 1)][i].svel++;
|
|
inputfifo[g_player[i].movefifoend&(MOVEFIFOSIZ - 1)][i].fvel++;
|
|
}
|
|
g_player[i].movefifoend++;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
for (int TRAVERSE_CONNECT(i))
|
|
if (i != myconnectindex)
|
|
{
|
|
int k = (g_player[myconnectindex].movefifoend-1)-g_player[i].movefifoend;
|
|
g_player[i].myminlag = min(g_player[i].myminlag,k);
|
|
mymaxlag = max(mymaxlag,k);
|
|
}
|
|
#if 0
|
|
if (((g_player[myconnectindex].movefifoend - 1) & (TIMERUPDATESIZ - 1)) == 0)
|
|
{
|
|
i = mymaxlag - bufferjitter;
|
|
mymaxlag = 0;
|
|
if (i > 0)
|
|
bufferjitter += ((2 + i) >> 2);
|
|
else if (i < 0)
|
|
bufferjitter -= ((2 - i) >> 2);
|
|
}
|
|
#else
|
|
if (((g_player[myconnectindex].movefifoend-1)&(TIMERUPDATESIZ-1)) == 0)
|
|
{
|
|
int i = mymaxlag-bufferjitter; mymaxlag = 0;
|
|
if (i > 0) bufferjitter += ((3+i)>>2);
|
|
else if (i < 0) bufferjitter -= ((1-i)>>2);
|
|
}
|
|
#endif
|
|
|
|
if (g_networkBroadcastMode == 1)
|
|
{
|
|
packbuf[0] = SERVER_GENERATED_BROADCAST;
|
|
if ((g_player[myconnectindex].movefifoend-1) == 0) packbuf[0] = PACKET_TYPE_BROADCAST;
|
|
int j = 1;
|
|
|
|
//Fix timers and buffer/jitter value
|
|
if (((g_player[myconnectindex].movefifoend-1)&(TIMERUPDATESIZ-1)) == 0)
|
|
{
|
|
if (myconnectindex != connecthead)
|
|
{
|
|
int i = g_player[connecthead].myminlag-otherminlag;
|
|
if (klabs(i) > 8) i >>= 1;
|
|
else if (klabs(i) > 2) i = ksgn(i);
|
|
else i = 0;
|
|
|
|
totalclock -= TICSPERFRAME*i;
|
|
g_player[connecthead].myminlag -= i; otherminlag += i;
|
|
}
|
|
|
|
if (myconnectindex == connecthead)
|
|
for(int i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
packbuf[j++] = min(max(g_player[i].myminlag,-128),127);
|
|
|
|
for(int i=connecthead;i>=0;i=connectpoint2[i])
|
|
g_player[i].myminlag = 0x7fffffff;
|
|
}
|
|
|
|
osyn = (input_t *)&inputfifo[(g_player[myconnectindex].movefifoend-2)&(MOVEFIFOSIZ-1)][myconnectindex];
|
|
nsyn = (input_t *)&inputfifo[(g_player[myconnectindex].movefifoend-1)&(MOVEFIFOSIZ-1)][myconnectindex];
|
|
|
|
int k = j;
|
|
packbuf[j++] = 0;
|
|
packbuf[j++] = 0;
|
|
|
|
if (nsyn[0].fvel != osyn[0].fvel)
|
|
{
|
|
packbuf[j++] = (char)nsyn[0].fvel;
|
|
packbuf[j++] = (char)(nsyn[0].fvel>>8);
|
|
packbuf[k] |= 1;
|
|
}
|
|
if (nsyn[0].svel != osyn[0].svel)
|
|
{
|
|
packbuf[j++] = (char)nsyn[0].svel;
|
|
packbuf[j++] = (char)(nsyn[0].svel>>8);
|
|
packbuf[k] |= 2;
|
|
}
|
|
if (nsyn[0].q16avel != osyn[0].q16avel)
|
|
{
|
|
packbuf[j++] = (char)((nsyn[0].q16avel) & 255);
|
|
packbuf[j++] = (char)((nsyn[0].q16avel >> 8) & 255);
|
|
packbuf[j++] = (char)((nsyn[0].q16avel >> 16) & 255);
|
|
packbuf[j++] = (char)((nsyn[0].q16avel >> 24) & 255);
|
|
packbuf[k] |= 4;
|
|
}
|
|
|
|
if ((nsyn[0].bits^osyn[0].bits)&0x000000ff) packbuf[j++] = (nsyn[0].bits&255), packbuf[k] |= 8;
|
|
if ((nsyn[0].bits^osyn[0].bits)&0x0000ff00) packbuf[j++] = ((nsyn[0].bits>>8)&255), packbuf[k] |= 16;
|
|
if ((nsyn[0].bits^osyn[0].bits)&0x00ff0000) packbuf[j++] = ((nsyn[0].bits>>16)&255), packbuf[k] |= 32;
|
|
if ((nsyn[0].bits^osyn[0].bits)&0xff000000) packbuf[j++] = ((nsyn[0].bits>>24)&255), packbuf[k] |= 64;
|
|
|
|
if (nsyn[0].q16horz != osyn[0].q16horz)
|
|
{
|
|
packbuf[j++] = (char)((nsyn[0].q16horz) & 255);
|
|
packbuf[j++] = (char)((nsyn[0].q16horz >> 8) & 255);
|
|
packbuf[j++] = (char)((nsyn[0].q16horz >> 16) & 255);
|
|
packbuf[j++] = (char)((nsyn[0].q16horz >> 24) & 255);
|
|
packbuf[k] |= 128;
|
|
}
|
|
// k++;
|
|
packbuf[++k] = 0;
|
|
if (nsyn[0].extbits != osyn[0].extbits) packbuf[j++] = nsyn[0].extbits, packbuf[k] |= 1;
|
|
/* if ((nsyn[0].extbits^osyn[0].extbits)&0x000000ff) packbuf[j++] = (nsyn[0].extbits&255), packbuf[k] |= 1;
|
|
if ((nsyn[0].extbits^osyn[0].extbits)&0x0000ff00) packbuf[j++] = ((nsyn[0].extbits>>8)&255), packbuf[k] |= 2;
|
|
if ((nsyn[0].extbits^osyn[0].extbits)&0x00ff0000) packbuf[j++] = ((nsyn[0].extbits>>16)&255), packbuf[k] |= 4;
|
|
if ((nsyn[0].extbits^osyn[0].extbits)&0xff000000) packbuf[j++] = ((nsyn[0].extbits>>24)&255), packbuf[k] |= 8; */
|
|
|
|
/* while (g_player[myconnectindex].syncvalhead != syncvaltail)
|
|
{
|
|
packbuf[j++] = g_player[myconnectindex].syncval[syncvaltail&(MOVEFIFOSIZ-1)];
|
|
syncvaltail++;
|
|
} */
|
|
|
|
Net_AddSyncInfoToPacket(&j);
|
|
|
|
for (int TRAVERSE_CONNECT(i))
|
|
if (i != myconnectindex)
|
|
Net_SendPacket(i,packbuf,j);
|
|
|
|
return;
|
|
}
|
|
if (myconnectindex != connecthead) //Slave
|
|
{
|
|
//Fix timers and buffer/jitter value
|
|
if (((g_player[myconnectindex].movefifoend-1)&(TIMERUPDATESIZ-1)) == 0)
|
|
{
|
|
int i = g_player[connecthead].myminlag - otherminlag;
|
|
if (klabs(i) > 2)
|
|
{
|
|
if (klabs(i) > 8)
|
|
{
|
|
if (i < 0)
|
|
i++;
|
|
i >>= 1;
|
|
}
|
|
else
|
|
{
|
|
if (i < 0)
|
|
i = -1;
|
|
if (i > 0)
|
|
i = 1;
|
|
}
|
|
totalclock -= TICSPERFRAME * i;
|
|
otherminlag += i;
|
|
}
|
|
|
|
for (int TRAVERSE_CONNECT(i))
|
|
{
|
|
g_player[i].myminlag = 0x7fffffff;
|
|
}
|
|
}
|
|
|
|
packbuf[0] = PACKET_TYPE_SLAVE_TO_MASTER;
|
|
packbuf[1] = 0;
|
|
packbuf[2] = 0;
|
|
int j = 3;
|
|
|
|
osyn = (input_t *)&inputfifo[(g_player[myconnectindex].movefifoend-2)&(MOVEFIFOSIZ-1)][myconnectindex];
|
|
nsyn = (input_t *)&inputfifo[(g_player[myconnectindex].movefifoend-1)&(MOVEFIFOSIZ-1)][myconnectindex];
|
|
|
|
if (nsyn[0].fvel != osyn[0].fvel)
|
|
{
|
|
packbuf[j++] = (char)nsyn[0].fvel;
|
|
packbuf[j++] = (char)(nsyn[0].fvel>>8);
|
|
packbuf[1] |= 1;
|
|
}
|
|
if (nsyn[0].svel != osyn[0].svel)
|
|
{
|
|
packbuf[j++] = (char)nsyn[0].svel;
|
|
packbuf[j++] = (char)(nsyn[0].svel>>8);
|
|
packbuf[1] |= 2;
|
|
}
|
|
if (nsyn[0].q16avel != osyn[0].q16avel)
|
|
{
|
|
packbuf[j++] = (char)((nsyn[0].q16avel) & 255);
|
|
packbuf[j++] = (char)((nsyn[0].q16avel >> 8) & 255);
|
|
packbuf[j++] = (char)((nsyn[0].q16avel >> 16) & 255);
|
|
packbuf[j++] = (char)((nsyn[0].q16avel >> 24) & 255);
|
|
packbuf[1] |= 4;
|
|
}
|
|
|
|
if ((nsyn[0].bits^osyn[0].bits)&0x000000ff) packbuf[j++] = (nsyn[0].bits&255), packbuf[1] |= 8;
|
|
if ((nsyn[0].bits^osyn[0].bits)&0x0000ff00) packbuf[j++] = ((nsyn[0].bits>>8)&255), packbuf[1] |= 16;
|
|
if ((nsyn[0].bits^osyn[0].bits)&0x00ff0000) packbuf[j++] = ((nsyn[0].bits>>16)&255), packbuf[1] |= 32;
|
|
if ((nsyn[0].bits^osyn[0].bits)&0xff000000) packbuf[j++] = ((nsyn[0].bits>>24)&255), packbuf[1] |= 64;
|
|
|
|
if (nsyn[0].q16horz != osyn[0].q16horz)
|
|
{
|
|
packbuf[j++] = (char)((nsyn[0].q16horz) & 255);
|
|
packbuf[j++] = (char)((nsyn[0].q16horz >> 8) & 255);
|
|
packbuf[j++] = (char)((nsyn[0].q16horz >> 16) & 255);
|
|
packbuf[j++] = (char)((nsyn[0].q16horz >> 24) & 255);
|
|
packbuf[1] |= 128;
|
|
}
|
|
packbuf[2] = 0;
|
|
if (nsyn[0].extbits != osyn[0].extbits) packbuf[j++] = nsyn[0].extbits, packbuf[2] |= 1;
|
|
/* if ((nsyn[0].extbits^osyn[0].extbits)&0x000000ff) packbuf[j++] = (nsyn[0].extbits&255), packbuf[2] |= 1;
|
|
if ((nsyn[0].extbits^osyn[0].extbits)&0x0000ff00) packbuf[j++] = ((nsyn[0].extbits>>8)&255), packbuf[2] |= 2;
|
|
if ((nsyn[0].extbits^osyn[0].extbits)&0x00ff0000) packbuf[j++] = ((nsyn[0].extbits>>16)&255), packbuf[2] |= 4;
|
|
if ((nsyn[0].extbits^osyn[0].extbits)&0xff000000) packbuf[j++] = ((nsyn[0].extbits>>24)&255), packbuf[2] |= 8; */
|
|
|
|
/* while (g_player[myconnectindex].syncvalhead != syncvaltail)
|
|
{
|
|
packbuf[j++] = g_player[myconnectindex].syncval[syncvaltail&(MOVEFIFOSIZ-1)];
|
|
syncvaltail++;
|
|
} */
|
|
Net_AddSyncInfoToPacket(&j);
|
|
|
|
Net_SendPacket(connecthead,packbuf,j);
|
|
return;
|
|
}
|
|
|
|
//This allows allow packet resends
|
|
for (int TRAVERSE_CONNECT(i))
|
|
if (g_player[i].movefifoend <= movefifosendplc)
|
|
{
|
|
packbuf[0] = PACKET_TYPE_NULL_PACKET;
|
|
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
Net_SendPacket(i,packbuf,1);
|
|
return;
|
|
}
|
|
|
|
while (1) //Master
|
|
{
|
|
for (int TRAVERSE_CONNECT(i))
|
|
if (g_player[i].playerquitflag && (g_player[i].movefifoend <= movefifosendplc)) return;
|
|
|
|
osyn = (input_t *)&inputfifo[(movefifosendplc-1)&(MOVEFIFOSIZ-1)][0];
|
|
nsyn = (input_t *)&inputfifo[(movefifosendplc)&(MOVEFIFOSIZ-1)][0];
|
|
|
|
//MASTER -> SLAVE packet
|
|
packbuf[0] = PACKET_TYPE_MASTER_TO_SLAVE;
|
|
int j = 1;
|
|
|
|
//Fix timers and buffer/jitter value
|
|
if ((movefifosendplc&(TIMERUPDATESIZ-1)) == 0)
|
|
{
|
|
for (int i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
if (g_player[i].playerquitflag)
|
|
packbuf[j++] = min(max(g_player[i].myminlag,-128),127);
|
|
|
|
for (int TRAVERSE_CONNECT(i))
|
|
g_player[i].myminlag = 0x7fffffff;
|
|
}
|
|
|
|
int k = j;
|
|
for (int TRAVERSE_CONNECT(i))
|
|
j += g_player[i].playerquitflag + g_player[i].playerquitflag;
|
|
for (int TRAVERSE_CONNECT(i))
|
|
{
|
|
if (g_player[i].playerquitflag == 0) continue;
|
|
|
|
packbuf[k] = 0;
|
|
if (nsyn[i].fvel != osyn[i].fvel)
|
|
{
|
|
packbuf[j++] = (char)nsyn[i].fvel;
|
|
packbuf[j++] = (char)(nsyn[i].fvel>>8);
|
|
packbuf[k] |= 1;
|
|
}
|
|
if (nsyn[i].svel != osyn[i].svel)
|
|
{
|
|
packbuf[j++] = (char)nsyn[i].svel;
|
|
packbuf[j++] = (char)(nsyn[i].svel>>8);
|
|
packbuf[k] |= 2;
|
|
}
|
|
if (nsyn[i].q16avel != osyn[i].q16avel)
|
|
{
|
|
packbuf[j++] = (char)((nsyn[i].q16avel) & 255);
|
|
packbuf[j++] = (char)((nsyn[i].q16avel >> 8) & 255);
|
|
packbuf[j++] = (char)((nsyn[i].q16avel >> 16) & 255);
|
|
packbuf[j++] = (char)((nsyn[i].q16avel >> 24) & 255);
|
|
packbuf[k] |= 4;
|
|
}
|
|
|
|
if ((nsyn[i].bits^osyn[i].bits)&0x000000ff) packbuf[j++] = (nsyn[i].bits&255), packbuf[k] |= 8;
|
|
if ((nsyn[i].bits^osyn[i].bits)&0x0000ff00) packbuf[j++] = ((nsyn[i].bits>>8)&255), packbuf[k] |= 16;
|
|
if ((nsyn[i].bits^osyn[i].bits)&0x00ff0000) packbuf[j++] = ((nsyn[i].bits>>16)&255), packbuf[k] |= 32;
|
|
if ((nsyn[i].bits^osyn[i].bits)&0xff000000) packbuf[j++] = ((nsyn[i].bits>>24)&255), packbuf[k] |= 64;
|
|
|
|
if (nsyn[i].q16horz != osyn[i].q16horz)
|
|
{
|
|
packbuf[j++] = (char)((nsyn[i].q16horz) & 255);
|
|
packbuf[j++] = (char)((nsyn[i].q16horz >> 8) & 255);
|
|
packbuf[j++] = (char)((nsyn[i].q16horz >> 16) & 255);
|
|
packbuf[j++] = (char)((nsyn[i].q16horz >> 24) & 255);
|
|
packbuf[k] |= 128;
|
|
}
|
|
k++;
|
|
packbuf[k] = 0;
|
|
if (nsyn[i].extbits != osyn[i].extbits) packbuf[j++] = nsyn[i].extbits, packbuf[k] |= 1;
|
|
/*
|
|
if ((nsyn[i].extbits^osyn[i].extbits)&0x000000ff) packbuf[j++] = (nsyn[i].extbits&255), packbuf[k] |= 1;
|
|
if ((nsyn[i].extbits^osyn[i].extbits)&0x0000ff00) packbuf[j++] = ((nsyn[i].extbits>>8)&255), packbuf[k] |= 2;
|
|
if ((nsyn[i].extbits^osyn[i].extbits)&0x00ff0000) packbuf[j++] = ((nsyn[i].extbits>>16)&255), packbuf[k] |= 4;
|
|
if ((nsyn[i].extbits^osyn[i].extbits)&0xff000000) packbuf[j++] = ((nsyn[i].extbits>>24)&255), packbuf[k] |= 8; */
|
|
k++;
|
|
}
|
|
|
|
/* while (g_player[myconnectindex].syncvalhead != syncvaltail)
|
|
{
|
|
packbuf[j++] = g_player[myconnectindex].syncval[syncvaltail&(MOVEFIFOSIZ-1)];
|
|
syncvaltail++;
|
|
} */
|
|
Net_AddSyncInfoToPacket(&j);
|
|
|
|
for (int i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
if (g_player[i].playerquitflag)
|
|
{
|
|
Net_SendPacket(i,packbuf,j);
|
|
if (TEST_SYNC_KEY(nsyn[i].bits,SK_GAMEQUIT))
|
|
g_player[i].playerquitflag = 0;
|
|
}
|
|
|
|
movefifosendplc += g_movesPerPacket;
|
|
}
|
|
|
|
}
|
|
|
|
void Net_ParsePacket(uint8_t *packbuf, int packbufleng)
|
|
{
|
|
int i, j, k, l;
|
|
int other = *packbuf++;
|
|
packbufleng--;
|
|
|
|
input_t *osyn, *nsyn;
|
|
|
|
//if (numplayers < 2) return;
|
|
//while ((packbufleng = mmulti_getpacket(&other,packbuf)) > 0)
|
|
//{
|
|
//lastpackettime = totalclock;
|
|
#if 0
|
|
initprintf("RECEIVED PACKET: type: %d : len %d\n", packbuf[0], packbufleng);
|
|
#endif
|
|
switch (packbuf[0])
|
|
{
|
|
case PACKET_TYPE_MASTER_TO_SLAVE: //[0] (receive master sync buffer)
|
|
j = 1;
|
|
|
|
if ((g_player[other].movefifoend&(TIMERUPDATESIZ-1)) == 0)
|
|
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
{
|
|
if (g_player[i].playerquitflag == 0) continue;
|
|
if (i == myconnectindex)
|
|
otherminlag = (int)((signed char)packbuf[j]);
|
|
j++;
|
|
}
|
|
|
|
osyn = (input_t *)&inputfifo[(g_player[connecthead].movefifoend-1)&(MOVEFIFOSIZ-1)][0];
|
|
nsyn = (input_t *)&inputfifo[(g_player[connecthead].movefifoend)&(MOVEFIFOSIZ-1)][0];
|
|
|
|
k = j;
|
|
for(TRAVERSE_CONNECT(i))
|
|
j += g_player[i].playerquitflag+g_player[i].playerquitflag;
|
|
for(TRAVERSE_CONNECT(i))
|
|
{
|
|
if (g_player[i].playerquitflag == 0) continue;
|
|
|
|
l = packbuf[k]+(int)(packbuf[k+1]<<8);
|
|
k += 2;
|
|
|
|
if (i == myconnectindex)
|
|
{
|
|
//j += ((l&1)<<1)+(l&2)+((l&4)>>2)+((l&8)>>3)+((l&16)>>4)+((l&32)>>5)+((l&64)>>6)+((l&128)>>7)+((l&256)>>8)/*+((l&512)>>9)+((l&1024)>>10)+((l&2048)>>11)*/;
|
|
|
|
if (l & 1) j += 2;
|
|
if (l & 2) j += 2;
|
|
if (l & 4) j += 4;
|
|
if (l & 8) j++;
|
|
if (l & 16) j++;
|
|
if (l & 32) j++;
|
|
if (l & 64) j++;
|
|
if (l & 128) j += 4;
|
|
if (l & 256) j++;
|
|
|
|
continue;
|
|
}
|
|
|
|
copybufbyte(&osyn[i],&nsyn[i],sizeof(input_t));
|
|
if (l&1) nsyn[i].fvel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2;
|
|
if (l&2) nsyn[i].svel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2;
|
|
if (l&4)
|
|
{
|
|
nsyn[i].q16avel = (fix16_t)packbuf[j];
|
|
nsyn[i].q16avel += (fix16_t)packbuf[j + 1] << 8;
|
|
nsyn[i].q16avel += (fix16_t)packbuf[j + 2] << 16;
|
|
nsyn[i].q16avel += (fix16_t)packbuf[j + 3] << 24;
|
|
j += 4;
|
|
}
|
|
if (l&8) nsyn[i].bits = ((nsyn[i].bits&0xffffff00)|((int)packbuf[j++]));
|
|
if (l&16) nsyn[i].bits = ((nsyn[i].bits&0xffff00ff)|((int)packbuf[j++])<<8);
|
|
if (l&32) nsyn[i].bits = ((nsyn[i].bits&0xff00ffff)|((int)packbuf[j++])<<16);
|
|
if (l&64) nsyn[i].bits = ((nsyn[i].bits&0x00ffffff)|((int)packbuf[j++])<<24);
|
|
if (l&128)
|
|
{
|
|
nsyn[i].q16horz = (fix16_t)packbuf[j];
|
|
nsyn[i].q16horz += (fix16_t)packbuf[j + 1] << 8;
|
|
nsyn[i].q16horz += (fix16_t)packbuf[j + 2] << 16;
|
|
nsyn[i].q16horz += (fix16_t)packbuf[j + 3] << 24;
|
|
j += 4;
|
|
}
|
|
if (l&256) nsyn[i].extbits = (unsigned char)packbuf[j++];
|
|
/* if (l&256) nsyn[i].extbits = ((nsyn[i].extbits&0xffffff00)|((int)packbuf[j++]));
|
|
if (l&512) nsyn[i].extbits = ((nsyn[i].extbits&0xffff00ff)|((int)packbuf[j++])<<8);
|
|
if (l&1024) nsyn[i].extbits = ((nsyn[i].extbits&0xff00ffff)|((int)packbuf[j++])<<16);
|
|
if (l&2048) nsyn[i].extbits = ((nsyn[i].extbits&0x00ffffff)|((int)packbuf[j++])<<24); */
|
|
|
|
if (TEST_SYNC_KEY(nsyn[i].bits,SK_GAMEQUIT)) g_player[i].playerquitflag = 0;
|
|
g_player[i].movefifoend++;
|
|
}
|
|
|
|
Net_GetSyncInfoFromPacket(packbuf, packbufleng, &j, other);
|
|
|
|
for (TRAVERSE_CONNECT(i))
|
|
if (i != myconnectindex)
|
|
for (j=g_movesPerPacket-1;j>=1;j--)
|
|
{
|
|
copybufbyte(&nsyn[i],&inputfifo[g_player[i].movefifoend&(MOVEFIFOSIZ-1)][i],sizeof(input_t));
|
|
g_player[i].movefifoend++;
|
|
}
|
|
|
|
movefifosendplc += g_movesPerPacket;
|
|
|
|
break;
|
|
case PACKET_TYPE_SLAVE_TO_MASTER: //[1] (receive slave sync buffer)
|
|
j = 3;
|
|
k = packbuf[1] + (int)(packbuf[2]<<8);
|
|
|
|
osyn = (input_t *)&inputfifo[(g_player[other].movefifoend-1)&(MOVEFIFOSIZ-1)][0];
|
|
nsyn = (input_t *)&inputfifo[(g_player[other].movefifoend)&(MOVEFIFOSIZ-1)][0];
|
|
|
|
copybufbyte(&osyn[other],&nsyn[other],sizeof(input_t));
|
|
if (k&1) nsyn[other].fvel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2;
|
|
if (k&2) nsyn[other].svel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2;
|
|
if (k&4)
|
|
{
|
|
nsyn[other].q16avel = (fix16_t)packbuf[j];
|
|
nsyn[other].q16avel += (fix16_t)packbuf[j + 1] << 8;
|
|
nsyn[other].q16avel += (fix16_t)packbuf[j + 2] << 16;
|
|
nsyn[other].q16avel += (fix16_t)packbuf[j + 3] << 24;
|
|
j += 4;
|
|
}
|
|
if (k&8) nsyn[other].bits = ((nsyn[other].bits&0xffffff00)|((int)packbuf[j++]));
|
|
if (k&16) nsyn[other].bits = ((nsyn[other].bits&0xffff00ff)|((int)packbuf[j++])<<8);
|
|
if (k&32) nsyn[other].bits = ((nsyn[other].bits&0xff00ffff)|((int)packbuf[j++])<<16);
|
|
if (k&64) nsyn[other].bits = ((nsyn[other].bits&0x00ffffff)|((int)packbuf[j++])<<24);
|
|
if (k&128)
|
|
{
|
|
nsyn[other].q16horz = (fix16_t)packbuf[j];
|
|
nsyn[other].q16horz += (fix16_t)packbuf[j + 1] << 8;
|
|
nsyn[other].q16horz += (fix16_t)packbuf[j + 2] << 16;
|
|
nsyn[other].q16horz += (fix16_t)packbuf[j + 3] << 24;
|
|
j += 4;
|
|
}
|
|
if (k&256) nsyn[other].extbits = (unsigned char)packbuf[j++];
|
|
/* if (k&256) nsyn[other].extbits = ((nsyn[other].extbits&0xffffff00)|((int)packbuf[j++]));
|
|
if (k&512) nsyn[other].extbits = ((nsyn[other].extbits&0xffff00ff)|((int)packbuf[j++])<<8);
|
|
if (k&1024) nsyn[other].extbits = ((nsyn[other].extbits&0xff00ffff)|((int)packbuf[j++])<<16);
|
|
if (k&2048) nsyn[other].extbits = ((nsyn[other].extbits&0x00ffffff)|((int)packbuf[j++])<<24); */
|
|
g_player[other].movefifoend++;
|
|
|
|
/* while (j != packbufleng)
|
|
{
|
|
g_player[other].syncval[g_player[other].syncvalhead&(MOVEFIFOSIZ-1)] = packbuf[j++];
|
|
g_player[other].syncvalhead++;
|
|
} */
|
|
Net_GetSyncInfoFromPacket(packbuf, packbufleng, &j, other);
|
|
|
|
for (i=g_movesPerPacket-1;i>=1;i--)
|
|
{
|
|
copybufbyte(&nsyn[other],&inputfifo[g_player[other].movefifoend&(MOVEFIFOSIZ-1)][other],sizeof(input_t));
|
|
g_player[other].movefifoend++;
|
|
}
|
|
|
|
break;
|
|
|
|
case PACKET_TYPE_BROADCAST:
|
|
g_player[other].movefifoend = movefifoplc = movefifosendplc = predictfifoplc = 0;
|
|
g_player[other].syncvalhead = syncvaltottail = 0L;
|
|
case SERVER_GENERATED_BROADCAST:
|
|
j = 1;
|
|
|
|
if ((g_player[other].movefifoend&(TIMERUPDATESIZ-1)) == 0)
|
|
if (other == connecthead)
|
|
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
{
|
|
if (i == myconnectindex)
|
|
otherminlag = (int)((signed char)packbuf[j]);
|
|
j++;
|
|
}
|
|
|
|
osyn = (input_t *)&inputfifo[(g_player[other].movefifoend-1)&(MOVEFIFOSIZ-1)][0];
|
|
nsyn = (input_t *)&inputfifo[(g_player[other].movefifoend)&(MOVEFIFOSIZ-1)][0];
|
|
|
|
copybufbyte(&osyn[other],&nsyn[other],sizeof(input_t));
|
|
k = packbuf[j] + (int)(packbuf[j+1]<<8);
|
|
j += 2;
|
|
|
|
if (k&1) nsyn[other].fvel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2;
|
|
if (k&2) nsyn[other].svel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2;
|
|
if (k&4)
|
|
{
|
|
nsyn[other].q16avel = (fix16_t)packbuf[j];
|
|
nsyn[other].q16avel += (fix16_t)packbuf[j + 1] << 8;
|
|
nsyn[other].q16avel += (fix16_t)packbuf[j + 2] << 16;
|
|
nsyn[other].q16avel += (fix16_t)packbuf[j + 3] << 24;
|
|
j += 4;
|
|
}
|
|
if (k&8) nsyn[other].bits = ((nsyn[other].bits&0xffffff00)|((int)packbuf[j++]));
|
|
if (k&16) nsyn[other].bits = ((nsyn[other].bits&0xffff00ff)|((int)packbuf[j++])<<8);
|
|
if (k&32) nsyn[other].bits = ((nsyn[other].bits&0xff00ffff)|((int)packbuf[j++])<<16);
|
|
if (k&64) nsyn[other].bits = ((nsyn[other].bits&0x00ffffff)|((int)packbuf[j++])<<24);
|
|
if (k&128)
|
|
{
|
|
nsyn[other].q16horz = (fix16_t)packbuf[j];
|
|
nsyn[other].q16horz += (fix16_t)packbuf[j + 1] << 8;
|
|
nsyn[other].q16horz += (fix16_t)packbuf[j + 2] << 16;
|
|
nsyn[other].q16horz += (fix16_t)packbuf[j + 3] << 24;
|
|
j += 4;
|
|
}
|
|
|
|
if (k&256) nsyn[other].extbits = (unsigned char)packbuf[j++];
|
|
/* if (k&256) nsyn[other].extbits = ((nsyn[other].extbits&0xffffff00)|((int)packbuf[j++]));
|
|
if (k&512) nsyn[other].extbits = ((nsyn[other].extbits&0xffff00ff)|((int)packbuf[j++])<<8);
|
|
if (k&1024) nsyn[other].extbits = ((nsyn[other].extbits&0xff00ffff)|((int)packbuf[j++])<<16);
|
|
if (k&2048) nsyn[other].extbits = ((nsyn[other].extbits&0x00ffffff)|((int)packbuf[j++])<<24); */
|
|
g_player[other].movefifoend++;
|
|
|
|
for (i=g_movesPerPacket-1;i>=1;i--)
|
|
{
|
|
copybufbyte(&nsyn[other],&inputfifo[g_player[other].movefifoend&(MOVEFIFOSIZ-1)][other],sizeof(input_t));
|
|
g_player[other].movefifoend++;
|
|
}
|
|
|
|
/*
|
|
while (j < packbufleng)
|
|
{
|
|
g_player[other].syncval[g_player[other].syncvalhead&(MOVEFIFOSIZ-1)] = packbuf[j++];
|
|
g_player[other].syncvalhead++;
|
|
}
|
|
*/
|
|
Net_GetSyncInfoFromPacket(packbuf, packbufleng, &j, other);
|
|
|
|
if (j > packbufleng)
|
|
initprintf("INVALID GAME PACKET!!! (packet %d, %d too many bytes (%d %d))\n",packbuf[0],j-packbufleng,packbufleng,k);
|
|
|
|
break;
|
|
case PACKET_TYPE_NULL_PACKET:
|
|
break;
|
|
|
|
case PACKET_TYPE_PLAYER_READY:
|
|
if (g_player[other].playerreadyflag == 0)
|
|
initprintf("Player %d is ready\n", other);
|
|
g_player[other].playerreadyflag++;
|
|
return;
|
|
//case PACKET_TYPE_QUIT:
|
|
// G_GameExit(" ");
|
|
// break;
|
|
#if 0
|
|
default:
|
|
switch (packbuf[0])
|
|
{
|
|
case PACKET_TYPE_MESSAGE:
|
|
//slaves in M/S mode only send to master
|
|
if ((!g_networkBroadcastMode) && (myconnectindex == connecthead))
|
|
{
|
|
if (packbuf[1] == 255)
|
|
{
|
|
//Master re-transmits message to all others
|
|
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
if (i != other)
|
|
Net_SendPacket(i,packbuf,packbufleng);
|
|
}
|
|
else if (((int)packbuf[1]) != myconnectindex)
|
|
{
|
|
//Master re-transmits message not intended for master
|
|
Net_SendPacket((int)packbuf[1],packbuf,packbufleng);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Bstrcpy(recbuf,(char*)packbuf+2);
|
|
recbuf[packbufleng-2] = 0;
|
|
|
|
G_AddUserQuote(recbuf);
|
|
S_PlaySound(EXITMENUSOUND);
|
|
|
|
pus = NUMPAGES;
|
|
pub = NUMPAGES;
|
|
|
|
break;
|
|
|
|
case PACKET_TYPE_NEW_GAME:
|
|
//Slaves in M/S mode only send to master
|
|
//Master re-transmits message to all others
|
|
if ((!g_networkBroadcastMode) && (myconnectindex == connecthead))
|
|
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
if (i != other) Net_SendPacket(i,packbuf,packbufleng);
|
|
|
|
if (vote_map != -1 || vote_episode != -1 || voting != -1)
|
|
G_AddUserQuote("VOTE SUCCEEDED");
|
|
|
|
ud.m_level_number = ud.level_number = packbuf[1];
|
|
ud.m_volume_number = ud.volume_number = packbuf[2];
|
|
ud.m_player_skill = ud.player_skill = packbuf[3];
|
|
|
|
// Non-menu variables handled by G_EnterLevel
|
|
ud.m_monsters_off = packbuf[4];
|
|
ud.m_respawn_monsters = packbuf[5];
|
|
ud.m_respawn_items = packbuf[6];
|
|
ud.m_respawn_inventory = packbuf[7];
|
|
ud.m_coop = packbuf[8];
|
|
ud.m_marker = packbuf[9];
|
|
ud.m_ffire = packbuf[10];
|
|
ud.m_noexits = packbuf[11];
|
|
//ud.m_weaponstay = packbuf[12];
|
|
|
|
for (int TRAVERSE_CONNECT(i))
|
|
{
|
|
P_ResetWeapons(i);
|
|
P_ResetInventory(i);
|
|
}
|
|
|
|
G_NewGame(ud.volume_number,ud.level_number,ud.player_skill);
|
|
|
|
if (G_EnterLevel(MODE_GAME)) G_BackToMenu();
|
|
|
|
break;
|
|
|
|
case PACKET_TYPE_INIT_SETTINGS:
|
|
//Slaves in M/S mode only send to master
|
|
//Master re-transmits message to all others
|
|
if ((!g_networkBroadcastMode) && (myconnectindex == connecthead))
|
|
for (i = connectpoint2[connecthead]; i >= 0; i = connectpoint2[i])
|
|
if (i != other) Net_SendPacket(i, packbuf, packbufleng);
|
|
|
|
ud.m_level_number = ud.level_number = packbuf[1];
|
|
ud.m_volume_number = ud.volume_number = packbuf[2];
|
|
ud.m_player_skill = ud.player_skill = packbuf[3];
|
|
|
|
// Non-menu variables handled by G_EnterLevel
|
|
ud.m_monsters_off = packbuf[4];
|
|
ud.m_respawn_monsters = packbuf[5];
|
|
ud.m_respawn_items = packbuf[6];
|
|
ud.m_respawn_inventory = packbuf[7];
|
|
ud.m_coop = packbuf[8];
|
|
ud.m_marker = packbuf[9];
|
|
ud.m_ffire = packbuf[10];
|
|
ud.m_noexits = packbuf[11];
|
|
//ud.m_weaponstay = packbuf[12];
|
|
break;
|
|
|
|
case PACKET_TYPE_VERSION:
|
|
//slaves in M/S mode only send to master
|
|
//Master re-transmits message to all others
|
|
if ((!g_networkBroadcastMode) && (myconnectindex == connecthead))
|
|
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
if (i != other) Net_SendPacket(i,packbuf,packbufleng);
|
|
|
|
if (packbuf[2] != (char)atoi(s_buildDate))
|
|
{
|
|
initprintf("Player has version %d, expecting %d\n",packbuf[2],(char)atoi(s_buildDate));
|
|
G_GameExit("You cannot play with different versions of EDuke32!");
|
|
}
|
|
if (packbuf[3] != (char)BYTEVERSION)
|
|
{
|
|
initprintf("Player has version %d, expecting %d (%d, %d, %d)\n",packbuf[3],BYTEVERSION, NETVERSION, PLUTOPAK, VOLUMEONE);
|
|
G_GameExit("You cannot play Duke with different versions!");
|
|
}
|
|
if (packbuf[4] > g_numSyncBytes)
|
|
{
|
|
initprintf("Sync debugging enabled\n");
|
|
g_numSyncBytes = packbuf[4];
|
|
}
|
|
|
|
break;
|
|
|
|
case PACKET_TYPE_PLAYER_OPTIONS:
|
|
//slaves in M/S mode only send to master
|
|
//Master re-transmits message to all others
|
|
if ((!g_networkBroadcastMode) && (myconnectindex == connecthead))
|
|
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
if (i != other) Net_SendPacket(i,packbuf,packbufleng);
|
|
|
|
other = packbuf[1];
|
|
i = 2;
|
|
|
|
g_player[other].ps->aim_mode = packbuf[i++];
|
|
g_player[other].ps->auto_aim = packbuf[i++];
|
|
g_player[other].ps->weaponswitch = packbuf[i++];
|
|
g_player[other].ps->palookup = g_player[other].pcolor = packbuf[i++];
|
|
g_player[other].pteam = packbuf[i++];
|
|
|
|
break;
|
|
|
|
//case PACKET_TYPE_FRAGLIMIT_CHANGED:
|
|
// //slaves in M/S mode only send to master
|
|
// //Master re-transmits message to all others
|
|
// if ((!g_networkBroadcastMode) && (myconnectindex == connecthead))
|
|
// for (i = connectpoint2[connecthead];i >= 0;i = connectpoint2[i])
|
|
// if (i != other) Net_SendPacket(i, packbuf, packbufleng);
|
|
//
|
|
// ud.fraglimit = packbuf[2];
|
|
//
|
|
// Bsprintf(tempbuf, "FRAGLIMIT CHANGED TO %d", ud.fraglimit);
|
|
// G_AddUserQuote(tempbuf);
|
|
// break;
|
|
|
|
case PACKET_TYPE_EOL:
|
|
if ((!g_networkBroadcastMode) && (myconnectindex == connecthead))
|
|
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
if (i != other) Net_SendPacket(i,packbuf,packbufleng);
|
|
|
|
for (TRAVERSE_CONNECT(i))
|
|
g_player[i].ps->gm = MODE_EOL;
|
|
|
|
ud.level_number = packbuf[1];
|
|
ud.m_level_number = ud.level_number;
|
|
ud.from_bonus = packbuf[2];
|
|
break;
|
|
|
|
case PACKET_TYPE_PLAYER_NAME:
|
|
//slaves in M/S mode only send to master
|
|
//Master re-transmits message to all others
|
|
if ((!g_networkBroadcastMode) && (myconnectindex == connecthead))
|
|
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
if (i != other) Net_SendPacket(i,packbuf,packbufleng);
|
|
|
|
other = packbuf[1];
|
|
|
|
for (i=2;packbuf[i];i++)
|
|
g_player[other].user_name[i-2] = packbuf[i];
|
|
g_player[other].user_name[i-2] = 0;
|
|
i++;
|
|
|
|
initprintf("Player %d's name is now %s\n", other, g_player[other].user_name);
|
|
|
|
break;
|
|
|
|
case PACKET_TYPE_WEAPON_CHOICE:
|
|
//slaves in M/S mode only send to master
|
|
//Master re-transmits message to all others
|
|
if ((!g_networkBroadcastMode) && (myconnectindex == connecthead))
|
|
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
if (i != other) Net_SendPacket(i,packbuf,packbufleng);
|
|
|
|
other = packbuf[1];
|
|
|
|
i = 2;
|
|
|
|
j = i; //This used to be Duke packet #9... now concatenated with Duke packet #6
|
|
for (;i-j<10;i++) g_player[other].wchoice[i-j] = packbuf[i];
|
|
|
|
break;
|
|
case PACKET_TYPE_RTS:
|
|
//slaves in M/S mode only send to master
|
|
//Master re-transmits message to all others
|
|
if ((!g_networkBroadcastMode) && (myconnectindex == connecthead))
|
|
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
if (i != other) Net_SendPacket(i,packbuf,packbufleng);
|
|
|
|
G_StartRTS(packbuf[1], other);
|
|
break;
|
|
|
|
case PACKET_TYPE_MENU_LEVEL_QUIT:
|
|
//slaves in M/S mode only send to master
|
|
if (myconnectindex == connecthead)
|
|
{
|
|
//Master re-transmits message to all others
|
|
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
if (i != other)
|
|
Net_SendPacket(i,packbuf,packbufleng);
|
|
}
|
|
|
|
G_GameExit("Game aborted from menu; disconnected.");
|
|
|
|
break;
|
|
|
|
case PACKET_TYPE_USER_MAP:
|
|
//slaves in M/S mode only send to master
|
|
if (myconnectindex == connecthead)
|
|
{
|
|
//Master re-transmits message to all others
|
|
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
if (i != other)
|
|
Net_SendPacket(i,packbuf,packbufleng);
|
|
}
|
|
|
|
Bstrcpy(boardfilename,(char*)packbuf+1);
|
|
boardfilename[packbufleng-1] = 0;
|
|
Bcorrectfilename(boardfilename,0);
|
|
if (boardfilename[0] != 0)
|
|
{
|
|
if (testkopen(boardfilename,0))
|
|
{
|
|
Bmemset(boardfilename,0,sizeof(boardfilename));
|
|
Net_SendUserMapName();
|
|
}
|
|
}
|
|
|
|
if (ud.m_level_number == 7 && ud.m_volume_number == 0 && boardfilename[0] == 0)
|
|
ud.m_level_number = 0;
|
|
|
|
break;
|
|
|
|
case PACKET_TYPE_MAP_VOTE:
|
|
case PACKET_TYPE_MAP_VOTE_INITIATE:
|
|
case PACKET_TYPE_MAP_VOTE_CANCEL:
|
|
|
|
if (myconnectindex == connecthead)
|
|
{
|
|
//Master re-transmits message to all others
|
|
for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
if (i != other)
|
|
Net_SendPacket(i,packbuf,packbufleng);
|
|
}
|
|
|
|
switch (packbuf[0])
|
|
{
|
|
case PACKET_TYPE_MAP_VOTE:
|
|
if (voting == myconnectindex && g_player[packbuf[1]].gotvote == 0)
|
|
{
|
|
g_player[packbuf[1]].gotvote = 1;
|
|
g_player[packbuf[1]].vote = packbuf[2];
|
|
Bsprintf(tempbuf,"Confirmed vote from %s",g_player[packbuf[1]].user_name);
|
|
G_AddUserQuote(tempbuf);
|
|
}
|
|
break;
|
|
|
|
case PACKET_TYPE_MAP_VOTE_INITIATE: // call map vote
|
|
/* if (g_networkBroadcastMode == 0 && packbuf[1] == connecthead)
|
|
break; // ignore this from master */
|
|
voting = packbuf[1];
|
|
vote_episode = packbuf[2];
|
|
vote_map = packbuf[3];
|
|
|
|
Bsprintf(tempbuf,"%s^00 HAS CALLED A VOTE TO CHANGE MAP TO %s (E%dL%d)",
|
|
g_player[packbuf[1]].user_name,
|
|
g_mapInfo[(unsigned char)(packbuf[2]*MAXLEVELS + packbuf[3])].name,
|
|
packbuf[2]+1,packbuf[3]+1);
|
|
G_AddUserQuote(tempbuf);
|
|
|
|
Bsprintf(tempbuf,"Press F1 to Accept, F2 to Decline");
|
|
G_AddUserQuote(tempbuf);
|
|
|
|
for (i=MAXPLAYERS-1;i>=0;i--)
|
|
{
|
|
g_player[i].vote = 0;
|
|
g_player[i].gotvote = 0;
|
|
}
|
|
g_player[voting].gotvote = g_player[voting].vote = 1;
|
|
break;
|
|
|
|
case PACKET_TYPE_MAP_VOTE_CANCEL: // cancel map vote
|
|
if (voting == packbuf[1])
|
|
{
|
|
voting = -1;
|
|
i = 0;
|
|
for (j=MAXPLAYERS-1;j>=0;j--)
|
|
i += g_player[j].gotvote;
|
|
|
|
if (i != numplayers)
|
|
Bsprintf(tempbuf,"%s^00 has canceled the vote",g_player[(unsigned char)packbuf[1]].user_name);
|
|
else Bsprintf(tempbuf,"Vote failed");
|
|
for (i=MAXPLAYERS-1;i>=0;i--)
|
|
{
|
|
g_player[i].vote = 0;
|
|
g_player[i].gotvote = 0;
|
|
}
|
|
G_AddUserQuote(tempbuf);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//case PACKET_TYPE_LOAD_GAME:
|
|
// //Slaves in M/S mode only send to master
|
|
// //Master re-transmits message to all others
|
|
// if ((!g_networkBroadcastMode) && (myconnectindex == connecthead))
|
|
// for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i])
|
|
// if (i != other) Net_SendPacket(i,packbuf,packbufleng);
|
|
//
|
|
// multiflag = 2;
|
|
// multiwhat = 0;
|
|
// multiwho = packbuf[2]; //other: need to send in m/s mode because of possible re-transmit
|
|
// multipos = packbuf[1];
|
|
// G_LoadPlayer(multipos);
|
|
// multiflag = 0;
|
|
// break;
|
|
}
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Connect/Disconnect
|
|
|
|
void Net_Connect(const char *srvaddr)
|
|
{
|
|
ENetAddress address;
|
|
ENetEvent event;
|
|
char *addrstr = NULL;
|
|
int32_t i;
|
|
|
|
char *oursrvaddr = Xstrdup(srvaddr);
|
|
|
|
Net_Disconnect();
|
|
|
|
g_netClient = enet_host_create(NULL, 1, CHAN_MAX, 0, 0);
|
|
|
|
if (g_netClient == NULL)
|
|
{
|
|
initprintf("An error occurred while trying to create an ENet client host.\n");
|
|
return;
|
|
}
|
|
|
|
addrstr = strtok(oursrvaddr, ":");
|
|
enet_address_set_host(&address, addrstr);
|
|
addrstr = strtok(NULL, ":");
|
|
address.port = addrstr==NULL ? g_netPort : Batoi(addrstr);
|
|
|
|
g_netClientPeer = enet_host_connect(g_netClient, &address, CHAN_MAX, 0);
|
|
|
|
if (g_netClientPeer == NULL)
|
|
{
|
|
initprintf("No available peers for initiating an ENet connection.\n");
|
|
return;
|
|
}
|
|
|
|
for (i=4; i>0; i--)
|
|
{
|
|
/* Wait up to 5 seconds for the connection attempt to succeed. */
|
|
if (enet_host_service(g_netClient, & event, 5000) > 0 &&
|
|
event.type == ENET_EVENT_TYPE_CONNECT)
|
|
{
|
|
initprintf("Connection to %s:%d succeeded.\n", oursrvaddr, address.port);
|
|
Bfree(oursrvaddr);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
/* Either the 5 seconds are up or a disconnect event was */
|
|
/* received. Reset the peer in the event the 5 seconds */
|
|
/* had run out without any significant event. */
|
|
enet_peer_reset(g_netClientPeer);
|
|
initprintf("Connection to %s:%d failed.\n", oursrvaddr, address.port);
|
|
}
|
|
initprintf(i ? "Retrying...\n" : "Giving up connection attempt.\n");
|
|
}
|
|
|
|
Bfree(oursrvaddr);
|
|
Net_Disconnect();
|
|
}
|
|
|
|
void Net_Disconnect(void)
|
|
{
|
|
if (g_netClient)
|
|
{
|
|
ENetEvent event;
|
|
|
|
if (g_netClientPeer)
|
|
enet_peer_disconnect_later(g_netClientPeer, 0);
|
|
|
|
while (enet_host_service(g_netClient, & event, 3000) > 0)
|
|
{
|
|
switch (event.type)
|
|
{
|
|
case ENET_EVENT_TYPE_CONNECT:
|
|
case ENET_EVENT_TYPE_NONE:
|
|
case ENET_EVENT_TYPE_RECEIVE:
|
|
if (event.packet)
|
|
enet_packet_destroy(event.packet);
|
|
break;
|
|
|
|
case ENET_EVENT_TYPE_DISCONNECT:
|
|
numplayers = g_mostConcurrentPlayers = ud.multimode = 1;
|
|
myconnectindex = screenpeek = 0;
|
|
G_BackToMenu();
|
|
break;
|
|
}
|
|
}
|
|
|
|
enet_peer_reset(g_netClientPeer);
|
|
g_netClientPeer = NULL;
|
|
enet_host_destroy(g_netClient);
|
|
g_netClient = NULL;
|
|
return;
|
|
}
|
|
|
|
if (g_netServer)
|
|
{
|
|
int32_t i;
|
|
ENetEvent event;
|
|
|
|
for (i=0; i<(signed)g_netServer->peerCount; i++)
|
|
enet_peer_disconnect_later(&g_netServer->peers[i], DISC_SERVER_QUIT);
|
|
|
|
while (enet_host_service(g_netServer, & event, 3000) > 0)
|
|
{
|
|
switch (event.type)
|
|
{
|
|
case ENET_EVENT_TYPE_CONNECT:
|
|
case ENET_EVENT_TYPE_NONE:
|
|
case ENET_EVENT_TYPE_RECEIVE:
|
|
case ENET_EVENT_TYPE_DISCONNECT:
|
|
if (event.packet)
|
|
enet_packet_destroy(event.packet);
|
|
break;
|
|
}
|
|
}
|
|
enet_host_destroy(g_netServer);
|
|
g_netServer = NULL;
|
|
}
|
|
}
|
|
|
|
void Net_ReceiveDisconnect(ENetEvent *event)
|
|
{
|
|
g_netDisconnect = 1;
|
|
numplayers = g_mostConcurrentPlayers = ud.multimode = 1;
|
|
myconnectindex = screenpeek = 0;
|
|
G_BackToMenu();
|
|
|
|
switch (event->data)
|
|
{
|
|
case DISC_GAME_STARTED:
|
|
initprintf("Game already started.\n");
|
|
return;
|
|
case DISC_BAD_PASSWORD:
|
|
initprintf("Bad password.\n");
|
|
return;
|
|
case DISC_VERSION_MISMATCH:
|
|
initprintf("Version mismatch.\n");
|
|
return;
|
|
case DISC_INVALID:
|
|
initprintf("Invalid data detected.\n");
|
|
return;
|
|
case DISC_SERVER_QUIT:
|
|
initprintf("The server is quitting.\n");
|
|
return;
|
|
case DISC_SERVER_FULL:
|
|
initprintf("The server is full.\n");
|
|
return;
|
|
case DISC_KICKED:
|
|
initprintf("You have been kicked from the server.\n");
|
|
return;
|
|
case DISC_BANNED:
|
|
initprintf("You are banned from this server.\n");
|
|
return;
|
|
default:
|
|
initprintf("Disconnected.\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Packet Handlers
|
|
|
|
#endif
|
|
|
|
void Net_GetPackets(void)
|
|
{
|
|
timerUpdate();
|
|
MUSIC_Update();
|
|
|
|
G_HandleSpecialKeys();
|
|
|
|
if (g_netDisconnect)
|
|
{
|
|
Net_Disconnect();
|
|
g_netDisconnect = 0;
|
|
|
|
if (g_gameQuit)
|
|
G_GameExit(" ");
|
|
|
|
return;
|
|
}
|
|
|
|
if (g_netServer)
|
|
{
|
|
Net_HandleClientPackets();
|
|
}
|
|
else if (g_netClient)
|
|
{
|
|
Net_HandleServerPackets();
|
|
}
|
|
}
|
|
|
|
#ifndef NETCODE_DISABLE
|
|
|
|
static void P_RemovePlayer(int32_t p);
|
|
|
|
void Net_HandleClientPackets(void)
|
|
{
|
|
ENetEvent event;
|
|
|
|
// pull events from the wire into the packet queue without dispatching them, once per Net_GetPackets() call
|
|
enet_host_service(g_netServer, NULL, 0);
|
|
|
|
// dispatch any pending events from the local packet queue
|
|
while (enet_host_check_events(g_netServer, &event) > 0)
|
|
{
|
|
const intptr_t playeridx = (intptr_t)event.peer->data;
|
|
|
|
if (playeridx < 0 || playeridx >= MAXPLAYERS)
|
|
{
|
|
enet_peer_disconnect_later(event.peer, DISC_INVALID);
|
|
buildprint("Invalid player id (", playeridx, ") from client.\n");
|
|
continue;
|
|
}
|
|
|
|
switch (event.type)
|
|
{
|
|
case ENET_EVENT_TYPE_CONNECT:
|
|
{
|
|
char ipaddr[32];
|
|
|
|
enet_address_get_host_ip(&event.peer->address, ipaddr, sizeof(ipaddr));
|
|
|
|
initprintf("A new client connected from %s:%u.\n", ipaddr, event.peer->address.port);
|
|
|
|
Net_SendAcknowledge(event.peer);
|
|
break;
|
|
}
|
|
|
|
case ENET_EVENT_TYPE_RECEIVE:
|
|
/*
|
|
initprintf ("A packet of length %u containing %s was received from player %d on channel %u.\n",
|
|
event.packet -> dataLength,
|
|
event.packet -> data,
|
|
event.peer -> data,
|
|
event.channelID);
|
|
*/
|
|
Net_ParseClientPacket(&event);
|
|
// broadcast takes care of enet_packet_destroy itself
|
|
// we set the state to disconnected so enet_host_broadcast
|
|
// doesn't send the player back his own packets
|
|
if ((event.channelID == CHAN_GAMESTATE && event.packet->data[0] > PACKET_BROADCAST)
|
|
|| event.channelID == CHAN_CHAT)
|
|
{
|
|
const ENetPacket *pak = event.packet;
|
|
|
|
event.peer->state = ENET_PEER_STATE_DISCONNECTED;
|
|
enet_host_broadcast(g_netServer, event.channelID,
|
|
enet_packet_create(pak->data, pak->dataLength, pak->flags&ENET_PACKET_FLAG_RELIABLE));
|
|
event.peer->state = ENET_PEER_STATE_CONNECTED;
|
|
}
|
|
|
|
enet_packet_destroy(event.packet);
|
|
//g_player[playeridx].ping = (event.peer->lastRoundTripTime + event.peer->roundTripTime)/2;
|
|
break;
|
|
|
|
case ENET_EVENT_TYPE_DISCONNECT:
|
|
numplayers--;
|
|
ud.multimode--;
|
|
|
|
P_RemovePlayer(playeridx);
|
|
|
|
packbuf[0] = PACKET_PLAYER_DISCONNECTED;
|
|
packbuf[1] = playeridx;
|
|
packbuf[2] = numplayers;
|
|
packbuf[3] = ud.multimode;
|
|
packbuf[4] = g_mostConcurrentPlayers;
|
|
packbuf[5] = myconnectindex;
|
|
|
|
enet_host_broadcast(g_netServer, CHAN_GAMESTATE,
|
|
enet_packet_create(packbuf, 6, ENET_PACKET_FLAG_RELIABLE));
|
|
|
|
initprintf("%s disconnected.\n", g_player[playeridx].user_name);
|
|
event.peer->data = NULL;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Net_HandleServerPackets(void)
|
|
{
|
|
ENetEvent event;
|
|
|
|
enet_host_service(g_netClient, NULL, 0);
|
|
|
|
while (enet_host_check_events(g_netClient, &event) > 0)
|
|
{
|
|
if (event.type == ENET_EVENT_TYPE_DISCONNECT)
|
|
{
|
|
Net_ReceiveDisconnect(&event);
|
|
}
|
|
else if (event.type == ENET_EVENT_TYPE_RECEIVE)
|
|
{
|
|
Net_ParseServerPacket(&event);
|
|
}
|
|
|
|
enet_packet_destroy(event.packet);
|
|
}
|
|
}
|
|
|
|
void Net_ParseClientPacket(ENetEvent *event)
|
|
{
|
|
switch (event->channelID)
|
|
{
|
|
case CHAN_REROUTE:
|
|
{
|
|
char *packet = (char*)event->packet->data;
|
|
int dest = *packet++;
|
|
int source = *packet++;
|
|
int size = event->packet->dataLength-2;
|
|
if (g_netPlayerPeer[dest])
|
|
{
|
|
ENetPacket *netpacket = enet_packet_create(NULL, size+1, ENET_PACKET_FLAG_RELIABLE);
|
|
char *buffer = (char*)netpacket->data;
|
|
*buffer++ = source;
|
|
Bmemcpy(buffer, packet, size);
|
|
enet_peer_send(g_netPlayerPeer[dest], CHAN_GAMESTATE, netpacket);
|
|
enet_host_service(g_netServer, NULL, 0);
|
|
}
|
|
break;
|
|
}
|
|
case CHAN_GAME:
|
|
Net_ParsePacket(event->packet->data, event->packet->dataLength);
|
|
break;
|
|
default:
|
|
{
|
|
uint8_t *pbuf = event->packet->data;
|
|
int32_t packbufleng = event->packet->dataLength;
|
|
int32_t other = pbuf[--packbufleng];
|
|
switch (pbuf[0])
|
|
{
|
|
//case PACKET_SLAVE_TO_MASTER: //[1] (receive slave sync buffer)
|
|
// Net_ReceiveClientUpdate(event);
|
|
// break;
|
|
|
|
//case PACKET_PLAYER_READY:
|
|
//
|
|
// if (other == 0)
|
|
// {
|
|
// break;
|
|
// }
|
|
//
|
|
// j = g_player[other].ps->i;
|
|
// Bmemcpy(g_player[other].ps, g_player[0].ps, sizeof(DukePlayer_t));
|
|
//
|
|
// g_player[other].ps->i = j;
|
|
// changespritestat(j, STAT_PLAYER);
|
|
//
|
|
// g_player[other].ps->last_extra = sprite[g_player[other].ps->i].extra = g_player[other].ps->max_player_health;
|
|
// sprite[g_player[other].ps->i].cstat = 1+256;
|
|
// actor[g_player[other].ps->i].t_data[2] = actor[g_player[other].ps->i].t_data[3] = actor[g_player[other].ps->i].t_data[4] = 0;
|
|
//
|
|
// P_ResetPlayer(other);
|
|
// Net_SpawnPlayer(other);
|
|
//
|
|
// break;
|
|
|
|
//case PACKET_PLAYER_PING:
|
|
// if (g_player[myconnectindex].ps->gm & MODE_GAME)
|
|
// {
|
|
// packbuf[0] = PACKET_PLAYER_PING;
|
|
// packbuf[1] = myconnectindex;
|
|
// enet_peer_send(event->peer, CHAN_GAMESTATE, enet_packet_create(packbuf, 2, ENET_PACKET_FLAG_RELIABLE));
|
|
// }
|
|
// g_player[other].pingcnt++;
|
|
// break;
|
|
|
|
case PACKET_AUTH:
|
|
Net_ReceiveChallenge(pbuf, packbufleng, event);
|
|
break;
|
|
|
|
default:
|
|
Net_ParsePacketCommon(pbuf, packbufleng, 0);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
initprintf("Received Packet: type: %d : len %d\n", pbuf[0], packbufleng);
|
|
#endif
|
|
}
|
|
|
|
void Net_ParseServerPacket(ENetEvent *event)
|
|
{
|
|
if (event->channelID == CHAN_GAME)
|
|
{
|
|
Net_ParsePacket(event->packet->data, event->packet->dataLength);
|
|
return;
|
|
}
|
|
uint8_t *pbuf = event->packet->data;
|
|
int32_t packbufleng = event->packet->dataLength;
|
|
// input_t *nsyn;
|
|
|
|
--packbufleng; // int32_t other = pbuf[--packbufleng];
|
|
|
|
#if 0
|
|
initprintf("Received Packet: type: %d : len %d\n", pbuf[0], packbufleng);
|
|
#endif
|
|
switch (pbuf[0])
|
|
{
|
|
|
|
//case PACKET_MAP_STREAM:
|
|
//
|
|
// if (!(g_player[myconnectindex].ps->gm & MODE_GAME))
|
|
// return;
|
|
//
|
|
// Net_ReceiveMapUpdate(event);
|
|
//
|
|
// break;
|
|
|
|
case PACKET_NEW_GAME:
|
|
Net_ReceiveNewGame(event);
|
|
break;
|
|
|
|
case PACKET_ACK:
|
|
Net_ReceiveAcknowledge(pbuf, packbufleng);
|
|
break;
|
|
|
|
case PACKET_NUM_PLAYERS:
|
|
Net_ReceiveNewPlayer(event->packet->data, event->packet->dataLength);
|
|
break;
|
|
|
|
case PACKET_PLAYER_INDEX:
|
|
Net_ReceivePlayerIndex(event->packet->data, event->packet->dataLength);
|
|
break;
|
|
|
|
case PACKET_PLAYER_DISCONNECTED:
|
|
//if ((g_player[myconnectindex].ps->gm & MODE_GAME))
|
|
P_RemovePlayer(pbuf[1]);
|
|
numplayers = pbuf[2];
|
|
ud.multimode = pbuf[3];
|
|
g_mostConcurrentPlayers = pbuf[4];
|
|
break;
|
|
|
|
//case PACKET_PLAYER_SPAWN:
|
|
// if (!(g_player[myconnectindex].ps->gm & MODE_GAME)) break;
|
|
//
|
|
// P_ResetPlayer(pbuf[1]);
|
|
// Bmemcpy(&g_player[pbuf[1]].ps->pos.x, &pbuf[2], sizeof(vec3_t) * 2);
|
|
// Bmemcpy(&sprite[g_player[pbuf[1]].ps->i], &pbuf[2], sizeof(vec3_t));
|
|
// break;
|
|
|
|
//case PACKET_PLAYER_PING:
|
|
// g_player[0].pingcnt++;
|
|
// return;
|
|
|
|
//case PACKET_FRAG:
|
|
// if (!(g_player[myconnectindex].ps->gm & MODE_GAME)) break;
|
|
// g_player[pbuf[1]].ps->frag_ps = pbuf[2];
|
|
// actor[g_player[pbuf[1]].ps->i].picnum = pbuf[3];
|
|
// ticrandomseed = B_UNBUF32(&pbuf[4]);
|
|
// P_FragPlayer(pbuf[1]);
|
|
// break;
|
|
|
|
default:
|
|
Net_ParsePacketCommon(pbuf, packbufleng, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Net_SendPacket(int dest, uint8_t *pbuf, int32_t packbufleng)
|
|
{
|
|
if (g_networkMode == NET_SERVER)
|
|
{
|
|
if (!g_netServer)
|
|
return;
|
|
if (g_netPlayerPeer[dest] != NULL)
|
|
{
|
|
ENetPacket* packet = enet_packet_create(NULL, packbufleng+1, ENET_PACKET_FLAG_RELIABLE);
|
|
uint8_t* buffer = packet->data;
|
|
*buffer++ = myconnectindex;
|
|
Bmemcpy(buffer, pbuf, packbufleng);
|
|
enet_peer_send(g_netPlayerPeer[dest], CHAN_GAME, packet);
|
|
enet_host_service(g_netServer, NULL, 0);
|
|
}
|
|
}
|
|
if (g_networkMode == NET_CLIENT)
|
|
{
|
|
if (!g_netClient)
|
|
return;
|
|
if (dest == 0)
|
|
{
|
|
ENetPacket *packet = enet_packet_create(NULL, packbufleng+1, ENET_PACKET_FLAG_RELIABLE);
|
|
uint8_t* buffer = packet->data;
|
|
*buffer++ = myconnectindex;
|
|
Bmemcpy(buffer, pbuf, packbufleng);
|
|
enet_peer_send(g_netClientPeer, CHAN_GAME, packet);
|
|
}
|
|
else
|
|
{
|
|
ENetPacket * packet = enet_packet_create(NULL, packbufleng+2, ENET_PACKET_FLAG_RELIABLE);
|
|
uint8_t* buffer = packet->data;
|
|
*buffer++ = dest;
|
|
*buffer++ = myconnectindex;
|
|
Bmemcpy(buffer, pbuf, packbufleng);
|
|
enet_peer_send(g_netClientPeer, CHAN_REROUTE, packet);
|
|
}
|
|
enet_host_service(g_netClient, NULL, 0);
|
|
}
|
|
}
|
|
|
|
void Net_ParsePacketCommon(uint8_t *pbuf, int32_t packbufleng, int32_t serverpacketp)
|
|
{
|
|
switch (pbuf[0])
|
|
{
|
|
case PACKET_MESSAGE:
|
|
Net_ReceiveMessage(pbuf, packbufleng);
|
|
break;
|
|
|
|
case PACKET_CLIENT_INFO:
|
|
Net_ReceiveClientInfo(pbuf, packbufleng, serverpacketp);
|
|
break;
|
|
|
|
case PACKET_RTS:
|
|
G_StartRTS(pbuf[1], 0);
|
|
break;
|
|
|
|
case PACKET_USER_MAP:
|
|
Net_ReceiveUserMapName(pbuf, packbufleng);
|
|
break;
|
|
|
|
case PACKET_MAP_VOTE:
|
|
Net_ReceiveMapVote(pbuf);
|
|
break;
|
|
|
|
case PACKET_MAP_VOTE_INITIATE: // call map vote
|
|
Net_ReceiveMapVoteInitiate(pbuf);
|
|
break;
|
|
|
|
case PACKET_MAP_VOTE_CANCEL: // cancel map vote
|
|
Net_ReceiveMapVoteCancel(pbuf);
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Acknowledgement Packets
|
|
|
|
void Net_SendAcknowledge(ENetPeer *client)
|
|
{
|
|
if (!g_netServer)
|
|
return;
|
|
|
|
tempbuf[0] = PACKET_ACK;
|
|
tempbuf[1] = myconnectindex;
|
|
|
|
enet_peer_send(client, CHAN_GAMESTATE, enet_packet_create(&tempbuf[0], 2, ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
|
|
void Net_ReceiveAcknowledge(uint8_t *pbuf, int32_t packbufleng)
|
|
{
|
|
UNREFERENCED_PARAMETER(pbuf); // remove when this variable is used
|
|
UNREFERENCED_PARAMETER(packbufleng); // remove when this variable is used
|
|
|
|
Net_SendChallenge();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Challenge Packets
|
|
|
|
// sends the version and a simple crc32 of the current password, all verified by the server before the connection can continue
|
|
void Net_SendChallenge()
|
|
{
|
|
if (!g_netClientPeer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
tempbuf[0] = PACKET_AUTH;
|
|
B_BUF16(&tempbuf[1], BYTEVERSION);
|
|
B_BUF16(&tempbuf[3], NETVERSION);
|
|
B_BUF32(&tempbuf[5], Bcrc32((uint8_t *)g_netPassword, Bstrlen(g_netPassword), 0));
|
|
tempbuf[9] = myconnectindex;
|
|
|
|
enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(&tempbuf[0], 10, ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
|
|
void Net_ReceiveChallenge(uint8_t *pbuf, int32_t packbufleng, ENetEvent *event)
|
|
{
|
|
const uint16_t byteVersion = B_UNBUF16(&pbuf[1]);
|
|
const uint16_t netVersion = B_UNBUF16(&pbuf[3]);
|
|
const uint32_t crc = B_UNBUF32(&pbuf[5]);
|
|
|
|
UNREFERENCED_PARAMETER(packbufleng); // remove when this variable is used
|
|
|
|
if (g_player[myconnectindex].ps->gm&MODE_GAME)
|
|
{
|
|
enet_peer_disconnect_later(event->peer, DISC_GAME_STARTED);
|
|
initprintf("Client attempted to connect to started game\n");
|
|
return;
|
|
}
|
|
|
|
if (byteVersion != BYTEVERSION || netVersion != NETVERSION)
|
|
{
|
|
enet_peer_disconnect_later(event->peer, DISC_VERSION_MISMATCH);
|
|
initprintf("Bad client protocol: version %u.%u\n", byteVersion, netVersion);
|
|
return;
|
|
}
|
|
if (crc != Bcrc32((uint8_t *)g_netPassword, Bstrlen(g_netPassword), 0))
|
|
{
|
|
enet_peer_disconnect_later(event->peer, DISC_BAD_PASSWORD);
|
|
initprintf("Bad password from client.\n");
|
|
return;
|
|
}
|
|
|
|
Net_SyncPlayer(event);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Num Players Packets
|
|
|
|
static void P_RemovePlayer(int32_t p)
|
|
{
|
|
// server obviously can't leave the game, and index 0 shows up for disconnect events from
|
|
// players that haven't gotten far enough into the connection process to get a player ID
|
|
|
|
if (p <= 0) return;
|
|
|
|
g_player[p].playerquitflag = 0;
|
|
|
|
Bsprintf(recbuf,"%s^00 is history!",g_player[p].user_name);
|
|
G_AddUserQuote(recbuf);
|
|
|
|
if (numplayers == 1)
|
|
S_PlaySound(GENERIC_AMBIENCE17);
|
|
}
|
|
|
|
void Net_SendNewPlayer(int32_t newplayerindex)
|
|
{
|
|
packbuf[0] = PACKET_NUM_PLAYERS;
|
|
packbuf[1] = numplayers;
|
|
packbuf[2] = g_mostConcurrentPlayers;
|
|
packbuf[3] = ud.multimode;
|
|
packbuf[4] = newplayerindex;
|
|
packbuf[5] = g_networkMode;
|
|
packbuf[6] = myconnectindex;
|
|
enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(packbuf, 7, ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
|
|
void Net_ReceiveNewPlayer(uint8_t *pbuf, int32_t packbufleng)
|
|
{
|
|
int32_t i;
|
|
|
|
UNREFERENCED_PARAMETER(packbufleng); // remove when this variable is used
|
|
|
|
numplayers = pbuf[1];
|
|
g_mostConcurrentPlayers = pbuf[2];
|
|
ud.multimode = pbuf[3];
|
|
if (pbuf[4]) // ID of new player
|
|
{
|
|
g_player[pbuf[4]].playerquitflag = 1;
|
|
|
|
if (!g_player[pbuf[4]].ps)
|
|
{
|
|
g_player[pbuf[4]].ps = (DukePlayer_t *) Xcalloc(1,sizeof(DukePlayer_t));
|
|
}
|
|
if (!g_player[pbuf[4]].inputBits)
|
|
{
|
|
g_player[pbuf[4]].inputBits = (input_t *) Xcalloc(1,sizeof(input_t));
|
|
}
|
|
}
|
|
|
|
//#ifndef NETCODE_DISABLE
|
|
// if (pbuf[5] == NET_DEDICATED_SERVER)
|
|
// {
|
|
// g_networkMode = NET_DEDICATED_CLIENT;
|
|
// }
|
|
//#endif
|
|
|
|
for (i=0; i<g_mostConcurrentPlayers-1; i++)
|
|
{
|
|
connectpoint2[i] = i+1;
|
|
}
|
|
|
|
connectpoint2[g_mostConcurrentPlayers-1] = -1;
|
|
|
|
S_PlaySound(DUKE_GETWEAPON2);
|
|
|
|
// myconnectindex is 0 until we get PACKET_PLAYER_INDEX
|
|
if (myconnectindex != 0)
|
|
{
|
|
Net_SendClientInfo();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Player Index Packets
|
|
|
|
void Net_SendPlayerIndex(int32_t index, ENetPeer *peer)
|
|
{
|
|
packbuf[0] = PACKET_PLAYER_INDEX;
|
|
packbuf[1] = index;
|
|
packbuf[2] = myconnectindex;
|
|
g_netPlayerPeer[index] = peer;
|
|
enet_peer_send(peer, CHAN_GAMESTATE, enet_packet_create(packbuf, 3, ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
|
|
void Net_ReceivePlayerIndex(uint8_t *pbuf, int32_t packbufleng)
|
|
{
|
|
UNREFERENCED_PARAMETER(packbufleng); // remove when this variable is used
|
|
|
|
myconnectindex = pbuf[1];
|
|
g_player[myconnectindex].playerquitflag = 1;
|
|
Net_SendClientInfo();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Client Info Packets
|
|
|
|
void Net_SendClientInfo(void)
|
|
{
|
|
int32_t i,l;
|
|
|
|
for (l=0; (unsigned)l<sizeof(szPlayerName)-1; l++)
|
|
g_player[myconnectindex].user_name[l] = szPlayerName[l];
|
|
|
|
if (numplayers < 2) return;
|
|
|
|
tempbuf[0] = PACKET_CLIENT_INFO;
|
|
l = 1;
|
|
|
|
//null terminated player name to send
|
|
for (i=0; szPlayerName[i]; i++)
|
|
{
|
|
tempbuf[l++] = szPlayerName[i];
|
|
}
|
|
tempbuf[l++] = 0;
|
|
|
|
tempbuf[l++] = g_player[myconnectindex].ps->aim_mode = ud.mouseaiming;
|
|
tempbuf[l++] = g_player[myconnectindex].ps->auto_aim = cl_autoaim;
|
|
tempbuf[l++] = g_player[myconnectindex].ps->weaponswitch = cl_weaponswitch;
|
|
tempbuf[l++] = g_player[myconnectindex].ps->palookup = g_player[myconnectindex].pcolor = ud.color;
|
|
|
|
tempbuf[l++] = g_player[myconnectindex].pteam = ud.team;
|
|
|
|
for (i=0; i<10; i++)
|
|
{
|
|
g_player[myconnectindex].wchoice[i] = g_player[0].wchoice[i];
|
|
tempbuf[l++] = (uint8_t)g_player[0].wchoice[i];
|
|
}
|
|
|
|
tempbuf[l++] = myconnectindex;
|
|
|
|
if (g_netClient)
|
|
{
|
|
enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(&tempbuf[0], l, ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
else if (g_netServer)
|
|
{
|
|
enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(&tempbuf[0], l, ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
}
|
|
|
|
void Net_ReceiveClientInfo(uint8_t *pbuf, int32_t packbufleng, int32_t fromserver)
|
|
{
|
|
uint32_t i, j;
|
|
int32_t other = pbuf[packbufleng];
|
|
|
|
for (i=1; pbuf[i]; i++)
|
|
{
|
|
g_player[other].user_name[i-1] = pbuf[i];
|
|
}
|
|
|
|
g_player[other].user_name[i-1] = 0;
|
|
i++;
|
|
|
|
g_player[other].ps->aim_mode = pbuf[i++];
|
|
g_player[other].ps->auto_aim = pbuf[i++];
|
|
g_player[other].ps->weaponswitch = pbuf[i++];
|
|
g_player[other].ps->palookup = g_player[other].pcolor = pbuf[i++];
|
|
g_player[other].pteam = pbuf[i++];
|
|
|
|
for (j=i; i-j<10; i++)
|
|
{
|
|
g_player[other].wchoice[i-j] = pbuf[i];
|
|
}
|
|
|
|
if (fromserver)
|
|
{
|
|
g_player[other].playerquitflag = 1;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Map Name Packets
|
|
|
|
void Net_SendUserMapName(void)
|
|
{
|
|
int32_t j;
|
|
|
|
if (numplayers < 2)
|
|
return;
|
|
|
|
packbuf[0] = PACKET_USER_MAP;
|
|
|
|
Bcorrectfilename(boardfilename,0);
|
|
|
|
// user map name is sent with a NUL at the end
|
|
j = Bstrlen(boardfilename)+1;
|
|
Bmemcpy(&packbuf[1], boardfilename, j);
|
|
j++;
|
|
|
|
packbuf[j++] = myconnectindex;
|
|
|
|
if (g_netClient)
|
|
{
|
|
enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(packbuf, j, ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
else if (g_netServer)
|
|
{
|
|
enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(packbuf, j, ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
}
|
|
|
|
void Net_ReceiveUserMapName(uint8_t *pbuf, int32_t packbufleng)
|
|
{
|
|
Bstrcpy(boardfilename,(char *)pbuf+1);
|
|
boardfilename[packbufleng-1] = 0;
|
|
Bcorrectfilename(boardfilename,0);
|
|
if (boardfilename[0] != 0)
|
|
{
|
|
if (testkopen(boardfilename,0))
|
|
{
|
|
Bmemset(boardfilename,0,sizeof(boardfilename));
|
|
Net_SendUserMapName();
|
|
}
|
|
}
|
|
|
|
if (ud.m_level_number == 7 && ud.m_volume_number == 0 && boardfilename[0] == 0)
|
|
ud.m_level_number = 0;
|
|
}
|
|
|
|
void Net_SendMessage(void)
|
|
{
|
|
|
|
if (g_player[myconnectindex].ps->gm&MODE_SENDTOWHOM)
|
|
{
|
|
int32_t i, j;
|
|
if (g_chatPlayer != -1 || ud.multimode < 3)
|
|
{
|
|
tempbuf[0] = PACKET_MESSAGE;
|
|
tempbuf[2] = 0;
|
|
recbuf[0] = 0;
|
|
|
|
if (ud.multimode < 3)
|
|
g_chatPlayer = 2;
|
|
|
|
if (typebuf[0] == '/' && Btoupper(typebuf[1]) == 'M' && Btoupper(typebuf[2]) == 'E')
|
|
{
|
|
Bstrcat(recbuf,"* ");
|
|
i = 3, j = Bstrlen(typebuf);
|
|
Bstrcpy(tempbuf,typebuf);
|
|
while (i < j)
|
|
{
|
|
typebuf[i-3] = tempbuf[i];
|
|
i++;
|
|
}
|
|
typebuf[i-3] = '\0';
|
|
Bstrcat(recbuf,g_player[myconnectindex].user_name);
|
|
}
|
|
else
|
|
{
|
|
Bstrcat(recbuf,g_player[myconnectindex].user_name);
|
|
Bstrcat(recbuf,": ");
|
|
}
|
|
|
|
Bstrcat(recbuf,"^00");
|
|
Bstrcat(recbuf,typebuf);
|
|
j = Bstrlen(recbuf);
|
|
recbuf[j] = 0;
|
|
Bstrcat(tempbuf+2,recbuf);
|
|
|
|
if (g_chatPlayer >= ud.multimode)
|
|
{
|
|
tempbuf[1] = 255;
|
|
tempbuf[j+2] = myconnectindex;
|
|
j++;
|
|
if (g_netServer) enet_host_broadcast(g_netServer, CHAN_CHAT, enet_packet_create(tempbuf, j+2, 0));
|
|
else if (g_netClient) enet_peer_send(g_netClientPeer, CHAN_CHAT, enet_packet_create(tempbuf, j+2, 0));
|
|
G_AddUserQuote(recbuf);
|
|
}
|
|
g_chatPlayer = -1;
|
|
g_player[myconnectindex].ps->gm &= ~(MODE_TYPE|MODE_SENDTOWHOM);
|
|
}
|
|
else if (g_chatPlayer == -1)
|
|
{
|
|
j = 50;
|
|
gametext_center(j, "Send message to...");
|
|
j += 8;
|
|
for (TRAVERSE_CONNECT(i))
|
|
{
|
|
if (i == myconnectindex)
|
|
{
|
|
minitextshade((320>>1)-40+1,j+1,"A/ENTER - ALL",26,0,2+8+16);
|
|
minitext((320>>1)-40,j,"A/ENTER - ALL",0,2+8+16);
|
|
j += 7;
|
|
}
|
|
else
|
|
{
|
|
Bsprintf(recbuf," %d - %s",i+1,g_player[i].user_name);
|
|
minitextshade((320>>1)-40-6+1,j+1,recbuf,26,0,2+8+16);
|
|
minitext((320>>1)-40-6,j,recbuf,0,2+8+16);
|
|
j += 7;
|
|
}
|
|
}
|
|
minitextshade((320>>1)-40-4+1,j+1," ESC - Abort",26,0,2+8+16);
|
|
minitext((320>>1)-40-4,j," ESC - Abort",0,2+8+16);
|
|
j += 7;
|
|
|
|
mpgametext(mpgametext_x, ud.screen_size > 0 ? (200-45)<<16 : (200-8)<<16, typebuf, 0, 0, 0, 0);
|
|
|
|
if (KB_KeyWaiting())
|
|
{
|
|
i = KB_GetCh();
|
|
|
|
if (i == 'A' || i == 'a' || i == 13)
|
|
g_chatPlayer = ud.multimode;
|
|
else if (i >= '1' || i <= (ud.multimode + '1'))
|
|
g_chatPlayer = i - '1';
|
|
else
|
|
{
|
|
g_chatPlayer = ud.multimode;
|
|
if (i == 27)
|
|
{
|
|
g_player[myconnectindex].ps->gm &= ~(MODE_TYPE|MODE_SENDTOWHOM);
|
|
g_chatPlayer = -1;
|
|
}
|
|
else
|
|
typebuf[0] = 0;
|
|
}
|
|
|
|
KB_ClearKeyDown(sc_1);
|
|
KB_ClearKeyDown(sc_2);
|
|
KB_ClearKeyDown(sc_3);
|
|
KB_ClearKeyDown(sc_4);
|
|
KB_ClearKeyDown(sc_5);
|
|
KB_ClearKeyDown(sc_6);
|
|
KB_ClearKeyDown(sc_7);
|
|
KB_ClearKeyDown(sc_8);
|
|
KB_ClearKeyDown(sc_A);
|
|
KB_ClearKeyDown(sc_Escape);
|
|
KB_ClearKeyDown(sc_Enter);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#define MAXCHATLENGTH 120
|
|
EDUKE32_STATIC_ASSERT(MAXCHATLENGTH < TYPEBUFSIZE);
|
|
int32_t const hitstate = I_EnterText(typebuf, MAXCHATLENGTH, 0);
|
|
|
|
int32_t const y = ud.screen_size > 1 ? (200-58)<<16 : (200-35)<<16;
|
|
|
|
int32_t const width = mpgametextsize(typebuf, TEXT_LITERALESCAPE).x;
|
|
int32_t const fullwidth = width + textsc((tilesiz[SPINNINGNUKEICON].x<<15)+(2<<16));
|
|
int32_t const text_x = fullwidth >= (320<<16) ? (320<<16) - fullwidth : mpgametext_x;
|
|
mpgametext(text_x, y, typebuf, 1, 2|8|16|ROTATESPRITE_FULL16, 0, TEXT_YCENTER|TEXT_LITERALESCAPE);
|
|
int32_t const cursor_x = text_x + width + textsc((tilesiz[SPINNINGNUKEICON].x<<14)+(1<<16));
|
|
rotatesprite_fs(cursor_x, y, textsc(32768), 0, SPINNINGNUKEICON+(((int32_t) totalclock>>3)%7), 4-(sintable[((int32_t) totalclock<<4)&2047]>>11), 0, 2|8);
|
|
|
|
if (hitstate == 1)
|
|
{
|
|
KB_ClearKeyDown(sc_Enter);
|
|
if (Bstrlen(typebuf) == 0)
|
|
{
|
|
g_player[myconnectindex].ps->gm &= ~(MODE_TYPE|MODE_SENDTOWHOM);
|
|
return;
|
|
}
|
|
if (cl_automsg)
|
|
{
|
|
if (SHIFTS_IS_PRESSED) g_chatPlayer = -1;
|
|
else g_chatPlayer = ud.multimode;
|
|
}
|
|
g_player[myconnectindex].ps->gm |= MODE_SENDTOWHOM;
|
|
}
|
|
else if (hitstate == -1)
|
|
g_player[myconnectindex].ps->gm &= ~(MODE_TYPE|MODE_SENDTOWHOM);
|
|
else pub = NUMPAGES;
|
|
}
|
|
}
|
|
|
|
void Net_ReceiveMessage(uint8_t *pbuf, int32_t packbufleng)
|
|
{
|
|
Bstrncpy(recbuf, (char *)pbuf+2, packbufleng-2);
|
|
recbuf[packbufleng-2] = 0;
|
|
|
|
G_AddUserQuote(recbuf);
|
|
S_PlaySound(EXITMENUSOUND);
|
|
|
|
pus = pub = NUMPAGES;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// New Game Packets
|
|
|
|
void Net_StartNewGame()
|
|
{
|
|
int32_t i;
|
|
|
|
for (TRAVERSE_CONNECT(i))
|
|
{
|
|
P_ResetWeapons(i);
|
|
P_ResetInventory(i);
|
|
//g_player[i].revision = 0;
|
|
}
|
|
|
|
Net_ExtractNewGame(&pendingnewgame, 0);
|
|
G_NewGame(ud.volume_number,ud.level_number,ud.player_skill);
|
|
ud.coop = ud.m_coop;
|
|
|
|
//g_netMapRevision = 0;
|
|
|
|
if (G_EnterLevel(MODE_GAME))
|
|
{
|
|
G_BackToMenu();
|
|
}
|
|
}
|
|
|
|
void Net_NotifyNewGame()
|
|
{
|
|
}
|
|
|
|
void Net_SendNewGame(int32_t frommenu, ENetPeer *peer)
|
|
{
|
|
newgame_t newgame;
|
|
|
|
newgame.header = PACKET_NEW_GAME;
|
|
Net_FillNewGame(&newgame, frommenu);
|
|
|
|
if (peer)
|
|
{
|
|
enet_peer_send(peer, CHAN_GAMESTATE, enet_packet_create(&newgame, sizeof(newgame_t), ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
else
|
|
{
|
|
enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(&newgame, sizeof(newgame_t), ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
}
|
|
|
|
void Net_ReceiveNewGame(ENetEvent *event)
|
|
{
|
|
if ((vote_map + vote_episode + voting) != -3)
|
|
G_AddUserQuote("Vote Succeeded");
|
|
|
|
Bmemcpy(&pendingnewgame, event->packet->data, sizeof(newgame_t));
|
|
Net_StartNewGame();
|
|
|
|
//packbuf[0] = PACKET_PLAYER_READY;
|
|
//packbuf[1] = myconnectindex;
|
|
//
|
|
//if (g_netClientPeer)
|
|
//{
|
|
// enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(packbuf, 2, ENET_PACKET_FLAG_RELIABLE));
|
|
//}
|
|
//
|
|
//g_player[myconnectindex].ps->gm = MODE_GAME;
|
|
//ready2send = 1;
|
|
}
|
|
|
|
void Net_FillNewGame(newgame_t *newgame, int32_t frommenu)
|
|
{
|
|
if (frommenu)
|
|
{
|
|
newgame->level_number = ud.m_level_number;
|
|
newgame->volume_number = ud.m_volume_number;
|
|
newgame->player_skill = ud.m_player_skill;
|
|
newgame->monsters_off = ud.m_monsters_off;
|
|
newgame->respawn_monsters = ud.m_respawn_monsters;
|
|
newgame->respawn_items = ud.m_respawn_items;
|
|
newgame->respawn_inventory = ud.m_respawn_inventory;
|
|
newgame->ffire = ud.m_ffire;
|
|
newgame->noexits = ud.m_noexits;
|
|
newgame->coop = ud.m_coop;
|
|
}
|
|
else
|
|
{
|
|
newgame->level_number = ud.level_number;
|
|
newgame->volume_number = ud.volume_number;
|
|
newgame->player_skill = ud.player_skill;
|
|
newgame->monsters_off = ud.monsters_off;
|
|
newgame->respawn_monsters = ud.respawn_monsters;
|
|
newgame->respawn_items = ud.respawn_items;
|
|
newgame->respawn_inventory = ud.respawn_inventory;
|
|
newgame->ffire = ud.ffire;
|
|
newgame->noexits = ud.noexits;
|
|
newgame->coop = ud.coop;
|
|
}
|
|
}
|
|
|
|
void Net_ExtractNewGame(newgame_t *newgame, int32_t menuonly)
|
|
{
|
|
ud.m_level_number = newgame->level_number;
|
|
ud.m_volume_number = newgame->volume_number;
|
|
ud.m_player_skill = newgame->player_skill;
|
|
ud.m_monsters_off = newgame->monsters_off;
|
|
ud.m_respawn_monsters = newgame->respawn_monsters;
|
|
ud.m_respawn_items = newgame->respawn_items;
|
|
ud.m_respawn_inventory = newgame->respawn_inventory;
|
|
ud.m_ffire = newgame->ffire;
|
|
ud.m_noexits = newgame->noexits;
|
|
ud.m_coop = newgame->coop;
|
|
|
|
if (!menuonly)
|
|
{
|
|
ud.level_number = newgame->level_number;
|
|
ud.volume_number = newgame->volume_number;
|
|
ud.player_skill = newgame->player_skill;
|
|
ud.monsters_off = newgame->monsters_off;
|
|
ud.respawn_monsters = newgame->respawn_monsters;
|
|
ud.respawn_monsters = newgame->respawn_items;
|
|
ud.respawn_inventory = newgame->respawn_inventory;
|
|
ud.ffire = newgame->ffire;
|
|
ud.noexits = newgame->noexits;
|
|
ud.coop = newgame->coop;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Map Vote Packets
|
|
|
|
void Net_SendMapVoteInitiate(void)
|
|
{
|
|
newgame_t newgame;
|
|
|
|
if (!g_netClient)
|
|
{
|
|
return;
|
|
}
|
|
|
|
voting = myconnectindex;
|
|
|
|
newgame.header = PACKET_MAP_VOTE_INITIATE;
|
|
newgame.connection = myconnectindex;
|
|
Net_FillNewGame(&newgame, 1);
|
|
|
|
enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(&newgame, sizeof(newgame_t), ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
|
|
void Net_ReceiveMapVoteInitiate(uint8_t *pbuf)
|
|
{
|
|
int32_t i;
|
|
|
|
Bmemcpy(&pendingnewgame, pbuf, sizeof(newgame_t));
|
|
Net_ExtractNewGame(&pendingnewgame, 1);
|
|
|
|
voting = pendingnewgame.connection;
|
|
vote_episode = pendingnewgame.volume_number;
|
|
vote_map = pendingnewgame.level_number;
|
|
|
|
Bsprintf(tempbuf,"%s^00 has called a vote to change map to %s (E%dL%d)",
|
|
g_player[voting].user_name,
|
|
g_mapInfo[(uint8_t)(vote_episode*MAXLEVELS + vote_map)].name,
|
|
vote_episode+1,vote_map+1);
|
|
G_AddUserQuote(tempbuf);
|
|
|
|
Bsprintf(tempbuf,"Press F1 to Accept, F2 to Decline");
|
|
G_AddUserQuote(tempbuf);
|
|
|
|
for (i=MAXPLAYERS-1; i>=0; i--)
|
|
{
|
|
g_player[i].vote = 0;
|
|
g_player[i].gotvote = 0;
|
|
}
|
|
|
|
g_player[voting].gotvote = g_player[voting].vote = 1;
|
|
}
|
|
|
|
void Net_SendMapVote(int32_t votefor)
|
|
{
|
|
voting = -1;
|
|
g_player[myconnectindex].gotvote = 1;
|
|
g_player[myconnectindex].vote = votefor;
|
|
|
|
tempbuf[0] = PACKET_MAP_VOTE;
|
|
tempbuf[1] = myconnectindex;
|
|
tempbuf[2] = votefor;
|
|
tempbuf[3] = myconnectindex;
|
|
|
|
if (g_netClient)
|
|
{
|
|
enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(tempbuf, 4, ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
else if (g_netServer)
|
|
{
|
|
enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(tempbuf, 4, ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
|
|
Net_CheckForEnoughVotes();
|
|
}
|
|
|
|
void Net_ReceiveMapVote(uint8_t *pbuf)
|
|
{
|
|
if (voting == myconnectindex && g_player[(uint8_t)pbuf[1]].gotvote == 0)
|
|
{
|
|
Bsprintf(tempbuf,"Confirmed vote from %s",g_player[(uint8_t)pbuf[1]].user_name);
|
|
G_AddUserQuote(tempbuf);
|
|
}
|
|
|
|
if (!g_netServer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_player[(uint8_t)pbuf[1]].gotvote = 1;
|
|
g_player[(uint8_t)pbuf[1]].vote = pbuf[2];
|
|
Net_CheckForEnoughVotes();
|
|
}
|
|
|
|
void Net_CheckForEnoughVotes()
|
|
{
|
|
int32_t i;
|
|
int32_t requiredvotes;
|
|
int32_t numfor, numagainst;
|
|
|
|
// Only the server can decide map changes
|
|
if (!g_netServer || numplayers <= 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// If there are just two players, both of them deserve a vote
|
|
if (numplayers == 2)
|
|
{
|
|
requiredvotes = 2;
|
|
}
|
|
else
|
|
{
|
|
// If more than two players, we need at least 50% of the players to vote
|
|
// Which means that if there's an odd number of players, we'll need slightly more than 50% of the vote.
|
|
requiredvotes = numplayers / 2;
|
|
if (numplayers % 2 == 1)
|
|
{
|
|
requiredvotes++;
|
|
}
|
|
}
|
|
|
|
numfor = numagainst = 0;
|
|
for (i=0; i<MAXPLAYERS; i++)
|
|
{
|
|
if (g_player[i].gotvote)
|
|
{
|
|
if (g_player[i].vote)
|
|
{
|
|
numfor++;
|
|
}
|
|
else
|
|
{
|
|
numagainst++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (numfor >= requiredvotes)
|
|
{
|
|
Net_StartNewGame();
|
|
Net_SendNewGame(1, NULL);
|
|
}
|
|
else if (numagainst >= requiredvotes || (numfor + numagainst) == numplayers)
|
|
{
|
|
Net_SendMapVoteCancel(1);
|
|
}
|
|
}
|
|
|
|
// If failed is true, that means the vote lost. Otherwise it was cancelled by the client who initiated it.
|
|
void Net_SendMapVoteCancel(int32_t failed)
|
|
{
|
|
// Only the server or the client that initiated the vote can cancel the vote
|
|
if (g_netClient && voting != myconnectindex)
|
|
{
|
|
return;
|
|
}
|
|
|
|
tempbuf[0] = PACKET_MAP_VOTE_CANCEL;
|
|
tempbuf[1] = myconnectindex;
|
|
|
|
// If we're forwarding a cancelled message, change the connection index to the one who cancelled it.
|
|
if (g_netServer && !failed)
|
|
{
|
|
tempbuf[1] = voting;
|
|
}
|
|
|
|
voting = -1;
|
|
|
|
if (g_netClient)
|
|
{
|
|
enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(tempbuf, 2, ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
else if (g_netServer)
|
|
{
|
|
enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(tempbuf, 2, ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
}
|
|
|
|
void Net_ReceiveMapVoteCancel(uint8_t *pbuf)
|
|
{
|
|
// int32_t numvotes;
|
|
|
|
// Ignore if we're not voting
|
|
if (voting == -1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Ignore cancellations from clients that did not initiate the map vote
|
|
if (voting != pbuf[1] && voting != myconnectindex)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (voting == myconnectindex || voting != pbuf[1])
|
|
{
|
|
Bsprintf(tempbuf,"Vote Failed");
|
|
}
|
|
else if (voting == pbuf[1])
|
|
{
|
|
Bsprintf(tempbuf,"%s^00 has canceled the vote",g_player[voting].user_name);
|
|
}
|
|
|
|
G_AddUserQuote(tempbuf);
|
|
|
|
if (g_netServer)
|
|
{
|
|
Net_SendMapVoteCancel(0);
|
|
}
|
|
|
|
voting = -1;
|
|
}
|
|
|
|
#endif // !defined NETCODE_DISABLE
|
|
|
|
END_RR_NS
|