mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-09 09:40:49 +00:00
6c5d9c3507
When doing this during startup it can be done by regular cleanup measures. This also moves two larger chunks of networking code out of game.cpp. Nevertheless, the fact that enet is a very dirty library which directly depends on Windows types is a big problem because it bleeds Windows definitions everywhere thanks to poor abstraction in all relevant layers.
4100 lines
131 KiB
C++
4100 lines
131 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 (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;
|
|
|
|
strncpy(g_player[myconnectindex].user_name, playername, 32);
|
|
|
|
if (numplayers < 2) return;
|
|
|
|
tempbuf[0] = PACKET_CLIENT_INFO;
|
|
l = 1;
|
|
|
|
//null terminated player name to send
|
|
strncpy(tempbuf + l, playername, 32);
|
|
l += 32;
|
|
tempbuf[l++] = 0;
|
|
|
|
tempbuf[l++] = g_player[myconnectindex].ps->aim_mode = in_aimmode;
|
|
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;
|
|
}
|
|
|
|
void Net_SendTaunt(int ridiculeNum)
|
|
{
|
|
tempbuf[0] = PACKET_MESSAGE;
|
|
tempbuf[1] = 255;
|
|
tempbuf[2] = 0;
|
|
Bstrcat(tempbuf + 2, *CombatMacros[ridiculeNum - 1]);
|
|
|
|
ridiculeNum = 2 + strlen(*CombatMacros[ridiculeNum - 1]);
|
|
|
|
tempbuf[ridiculeNum++] = myconnectindex;
|
|
|
|
if (g_netClient)
|
|
enet_peer_send(g_netClientPeer, CHAN_CHAT, enet_packet_create(&tempbuf[0], ridiculeNum, 0));
|
|
else if (g_netServer)
|
|
enet_host_broadcast(g_netServer, CHAN_CHAT, enet_packet_create(&tempbuf[0], ridiculeNum, 0));
|
|
|
|
}
|
|
|
|
void Net_SendRTS(int ridiculeNum)
|
|
{
|
|
if ((g_netServer || ud.multimode > 1))
|
|
{
|
|
tempbuf[0] = PACKET_RTS;
|
|
tempbuf[1] = ridiculeNum;
|
|
tempbuf[2] = myconnectindex;
|
|
|
|
if (g_netClient)
|
|
enet_peer_send(g_netClientPeer, CHAN_CHAT, enet_packet_create(&tempbuf[0], 3, 0));
|
|
else if (g_netServer)
|
|
enet_host_broadcast(g_netServer, CHAN_CHAT, enet_packet_create(&tempbuf[0], 3, 0));
|
|
}
|
|
}
|
|
|
|
#endif // !defined NETCODE_DISABLE
|
|
|
|
END_RR_NS
|