merged over all stuff from 0.2 to trunk
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 58 KiB |
BIN
data/game.png
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 99 KiB |
|
@ -433,7 +433,7 @@ weapons {
|
|||
visual_size 96
|
||||
offsetx 4.0
|
||||
offsety -20.0
|
||||
meleedamage 3
|
||||
meleedamage 4
|
||||
meleereach 40
|
||||
ammoregentime 0
|
||||
duration -1
|
||||
|
|
|
@ -29,7 +29,6 @@ static int info_request_end;
|
|||
static int snapshot_part;
|
||||
static int64 local_start_time;
|
||||
static int64 game_start_time;
|
||||
static int current_tick;
|
||||
static float latency = 0;
|
||||
static int extra_polating = 0;
|
||||
static int debug_font;
|
||||
|
@ -37,8 +36,12 @@ static float frametime = 0.0001f;
|
|||
static net_client net;
|
||||
static netaddr4 master_server;
|
||||
static netaddr4 server_address;
|
||||
static const char *server_spam_address=0;
|
||||
static int window_must_refocus = 0;
|
||||
static int snaploss = 0;
|
||||
|
||||
static int current_tick = 0;
|
||||
static float intratick = 0;
|
||||
|
||||
|
||||
// --- input wrappers ---
|
||||
static int keyboard_state[2][input::last];
|
||||
|
@ -151,14 +154,9 @@ static void client_snapshot_purge_until(int tick)
|
|||
|
||||
static snapshot_info *snapshots[NUM_SNAPSHOT_TYPES];
|
||||
static int recived_snapshots;
|
||||
static int64 snapshot_start_time;
|
||||
static char snapshot_incomming_data[MAX_SNAPSHOT_SIZE];
|
||||
|
||||
// ---
|
||||
float client_localtime()
|
||||
{
|
||||
return (time_get()-local_start_time)/(float)(time_freq());
|
||||
}
|
||||
|
||||
const void *snap_get_item(int snapid, int index, snap_item *item)
|
||||
{
|
||||
|
@ -199,7 +197,7 @@ static void snap_init()
|
|||
// ------ time functions ------
|
||||
float client_intratick()
|
||||
{
|
||||
return (time_get() - snapshot_start_time)/(float)(time_freq()/SERVER_TICK_SPEED);
|
||||
return intratick;
|
||||
}
|
||||
|
||||
int client_tick()
|
||||
|
@ -217,6 +215,10 @@ float client_frametime()
|
|||
return frametime;
|
||||
}
|
||||
|
||||
float client_localtime()
|
||||
{
|
||||
return (time_get()-local_start_time)/(float)(time_freq());
|
||||
}
|
||||
|
||||
int menu_loop(); // TODO: what is this?
|
||||
|
||||
|
@ -312,9 +314,11 @@ void client_serverbrowse_refresh(int lan)
|
|||
|
||||
if(serverlist_lan)
|
||||
{
|
||||
dbg_msg("client", "broadcasting for servers");
|
||||
if(config.debug)
|
||||
dbg_msg("client", "broadcasting for servers");
|
||||
NETPACKET packet;
|
||||
packet.client_id = -1;
|
||||
mem_zero(&packet, sizeof(packet));
|
||||
packet.address.ip[0] = 0;
|
||||
packet.address.ip[1] = 0;
|
||||
packet.address.ip[2] = 0;
|
||||
|
@ -330,8 +334,10 @@ void client_serverbrowse_refresh(int lan)
|
|||
}
|
||||
else
|
||||
{
|
||||
dbg_msg("client", "requesting server list");
|
||||
if(config.debug)
|
||||
dbg_msg("client", "requesting server list");
|
||||
NETPACKET packet;
|
||||
mem_zero(&packet, sizeof(packet));
|
||||
packet.client_id = -1;
|
||||
packet.address = master_server;
|
||||
packet.flags = PACKETFLAG_CONNLESS;
|
||||
|
@ -347,9 +353,12 @@ void client_serverbrowse_refresh(int lan)
|
|||
|
||||
static void client_serverbrowse_request(int id)
|
||||
{
|
||||
dbg_msg("client", "requesting server info from %d.%d.%d.%d:%d",
|
||||
servers.addresses[id].ip[0], servers.addresses[id].ip[1], servers.addresses[id].ip[2],
|
||||
servers.addresses[id].ip[3], servers.addresses[id].port);
|
||||
if(config.debug)
|
||||
{
|
||||
dbg_msg("client", "requesting server info from %d.%d.%d.%d:%d",
|
||||
servers.addresses[id].ip[0], servers.addresses[id].ip[1], servers.addresses[id].ip[2],
|
||||
servers.addresses[id].ip[3], servers.addresses[id].port);
|
||||
}
|
||||
NETPACKET packet;
|
||||
packet.client_id = -1;
|
||||
packet.address = servers.addresses[id];
|
||||
|
@ -388,7 +397,8 @@ static int state;
|
|||
int client_state() { return state; }
|
||||
static void client_set_state(int s)
|
||||
{
|
||||
dbg_msg("game", "state change. last=%d current=%d", state, s);
|
||||
if(config.debug)
|
||||
dbg_msg("client", "state change. last=%d current=%d", state, s);
|
||||
int old = state;
|
||||
state = s;
|
||||
if(old != s)
|
||||
|
@ -422,6 +432,7 @@ void client_connect(const char *server_address_str)
|
|||
|
||||
net.connect(&server_address);
|
||||
client_set_state(CLIENTSTATE_CONNECTING);
|
||||
current_tick = 0;
|
||||
}
|
||||
|
||||
void client_disconnect()
|
||||
|
@ -459,9 +470,10 @@ static void client_debug_render()
|
|||
static float frametime_avg = 0;
|
||||
frametime_avg = frametime_avg*0.9f + frametime*0.1f;
|
||||
char buffer[512];
|
||||
sprintf(buffer, "send: %6d recv: %6d latency: %4.0f %c gfxmem: %6dk fps: %3d",
|
||||
sprintf(buffer, "send: %6d recv: %6d snaploss: %4d latency: %4.0f %c gfxmem: %6dk fps: %3d",
|
||||
(current.send_bytes-prev.send_bytes)*10,
|
||||
(current.recv_bytes-prev.recv_bytes)*10,
|
||||
snaploss,
|
||||
latency*1000.0f, extra_polating?'E':' ',
|
||||
gfx_memory_usage()/1024,
|
||||
(int)(1.0f/frametime_avg));
|
||||
|
@ -488,7 +500,7 @@ static void client_render()
|
|||
|
||||
static void client_error(const char *msg)
|
||||
{
|
||||
dbg_msg("game", "error: %s", msg);
|
||||
dbg_msg("client", "error: %s", msg);
|
||||
client_send_error(msg);
|
||||
client_set_state(CLIENTSTATE_QUITING);
|
||||
}
|
||||
|
@ -549,7 +561,8 @@ static void client_process_packet(NETPACKET *packet)
|
|||
packet->address.ip[0], packet->address.ip[1], packet->address.ip[2],
|
||||
packet->address.ip[3], packet->address.port);
|
||||
|
||||
dbg_msg("client", "got server info");
|
||||
if(config.debug)
|
||||
dbg_msg("client", "got server info");
|
||||
servers.num++;
|
||||
|
||||
}
|
||||
|
@ -565,7 +578,8 @@ static void client_process_packet(NETPACKET *packet)
|
|||
servers.infos[i].max_players = unpacker.get_int();
|
||||
servers.infos[i].num_players = unpacker.get_int();
|
||||
servers.infos[i].latency = ((time_get() - servers.request_times[i])*1000)/time_freq();
|
||||
dbg_msg("client", "got server info");
|
||||
if(config.debug)
|
||||
dbg_msg("client", "got server info");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -611,7 +625,7 @@ static void client_process_packet(NETPACKET *packet)
|
|||
if(msg != NETMSG_SNAPEMPTY)
|
||||
part_size = msg_unpack_int();
|
||||
|
||||
if(snapshot_part == part)
|
||||
if(snapshot_part == part && game_tick > current_tick)
|
||||
{
|
||||
// TODO: clean this up abit
|
||||
const char *d = (const char *)msg_unpack_raw(part_size);
|
||||
|
@ -620,7 +634,38 @@ static void client_process_packet(NETPACKET *packet)
|
|||
|
||||
if(snapshot_part == num_parts)
|
||||
{
|
||||
current_tick = game_tick;
|
||||
snapshot_part = 0;
|
||||
|
||||
// find snapshot that we should use as delta
|
||||
static snapshot emptysnap;
|
||||
emptysnap.data_size = 0;
|
||||
emptysnap.num_items = 0;
|
||||
|
||||
snapshot *deltashot = &emptysnap;
|
||||
|
||||
// find delta
|
||||
if(delta_tick >= 0)
|
||||
{
|
||||
//void *delta_data;
|
||||
snapshot_info *delta_info = client_snapshot_find(delta_tick);
|
||||
//deltashot_size = snapshots_new.get(delta_tick, 0, &delta_data);
|
||||
if(delta_info)
|
||||
deltashot = delta_info->snap;
|
||||
else
|
||||
{
|
||||
// couldn't find the delta snapshots that the server used
|
||||
// to compress this snapshot. force the server to resync
|
||||
if(config.debug)
|
||||
dbg_msg("client", "error, couldn't find the delta snapshot");
|
||||
|
||||
// ack snapshot
|
||||
msg_pack_start_system(NETMSG_SNAPACK, 0);
|
||||
msg_pack_int(-1);
|
||||
msg_pack_end();
|
||||
client_send_msg();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// decompress snapshot
|
||||
void *deltadata = snapshot_empty_delta();
|
||||
|
@ -636,27 +681,6 @@ static void client_process_packet(NETPACKET *packet)
|
|||
deltasize = intsize;
|
||||
}
|
||||
|
||||
// find snapshot that we should use as delta
|
||||
static snapshot emptysnap;
|
||||
emptysnap.data_size = 0;
|
||||
emptysnap.num_items = 0;
|
||||
|
||||
snapshot *deltashot = &emptysnap;
|
||||
|
||||
if(delta_tick >= 0)
|
||||
{
|
||||
//void *delta_data;
|
||||
snapshot_info *delta_info = client_snapshot_find(delta_tick);
|
||||
//deltashot_size = snapshots_new.get(delta_tick, 0, &delta_data);
|
||||
if(delta_info)
|
||||
deltashot = delta_info->snap;
|
||||
else
|
||||
{
|
||||
// TODO: handle this
|
||||
dbg_msg("client", "error, couldn't find the delta snapshot");
|
||||
}
|
||||
}
|
||||
|
||||
//dbg_msg("UNPACK", "%d unpacked with %d", game_tick, delta_tick);
|
||||
|
||||
unsigned char tmpbuffer3[MAX_SNAPSHOT_SIZE];
|
||||
|
@ -681,12 +705,17 @@ static void client_process_packet(NETPACKET *packet)
|
|||
// apply snapshot, cycle pointers
|
||||
recived_snapshots++;
|
||||
|
||||
|
||||
if(current_tick > 0)
|
||||
snaploss += game_tick-current_tick-1;
|
||||
|
||||
current_tick = game_tick;
|
||||
|
||||
// we got two snapshots until we see us self as connected
|
||||
if(recived_snapshots <= 2)
|
||||
{
|
||||
snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT];
|
||||
snapshots[SNAP_CURRENT] = snap;
|
||||
snapshot_start_time = time_get();
|
||||
}
|
||||
|
||||
if(recived_snapshots == 2)
|
||||
|
@ -699,7 +728,8 @@ static void client_process_packet(NETPACKET *packet)
|
|||
int64 t = now - game_tick*time_freq()/50;
|
||||
if(game_start_time == -1 || t < game_start_time)
|
||||
{
|
||||
dbg_msg("client", "adjusted time");
|
||||
if(config.debug)
|
||||
dbg_msg("client", "adjusted time");
|
||||
game_start_time = t;
|
||||
}
|
||||
|
||||
|
@ -707,11 +737,6 @@ static void client_process_packet(NETPACKET *packet)
|
|||
float current_latency = (now-wanted)/(float)time_freq();
|
||||
latency = latency*0.95f+current_latency*0.05f;
|
||||
|
||||
//if(recived_snapshots > 2)
|
||||
// modc_newsnapshot();
|
||||
|
||||
snapshot_part = 0;
|
||||
|
||||
// ack snapshot
|
||||
msg_pack_start_system(NETMSG_SNAPACK, 0);
|
||||
msg_pack_int(game_tick);
|
||||
|
@ -781,14 +806,14 @@ static void client_run(const char *direct_connect_server)
|
|||
if(!client_load_data())
|
||||
return;
|
||||
|
||||
// init menu
|
||||
modmenu_init(); // TODO: remove
|
||||
|
||||
// init snapshotting
|
||||
snap_init();
|
||||
|
||||
// init the mod
|
||||
modc_init();
|
||||
|
||||
// init menu
|
||||
modmenu_init(); // TODO: remove
|
||||
|
||||
// open socket
|
||||
NETADDR4 bindaddr;
|
||||
|
@ -837,7 +862,8 @@ static void client_run(const char *direct_connect_server)
|
|||
{
|
||||
snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT];
|
||||
snapshots[SNAP_CURRENT] = next;
|
||||
snapshot_start_time = t;
|
||||
if(snapshots[SNAP_CURRENT] && snapshots[SNAP_PREV])
|
||||
modc_newsnapshot();
|
||||
|
||||
if(snapshots[SNAP_CURRENT] && snapshots[SNAP_PREV])
|
||||
modc_newsnapshot();
|
||||
|
@ -854,12 +880,25 @@ static void client_run(const char *direct_connect_server)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(snapshots[SNAP_CURRENT] && snapshots[SNAP_PREV])
|
||||
{
|
||||
int64 curtick_start = game_start_time + (snapshots[SNAP_CURRENT]->tick+1)*time_freq()/50;
|
||||
if(latency > 0)
|
||||
curtick_start += (int64)(time_freq()*(latency*1.1f));
|
||||
|
||||
int64 prevtick_start = game_start_time + (snapshots[SNAP_PREV]->tick+1)*time_freq()/50;
|
||||
if(latency > 0)
|
||||
prevtick_start += (int64)(time_freq()*(latency*1.1f));
|
||||
|
||||
intratick = (now - prevtick_start) / (float)(curtick_start-prevtick_start);
|
||||
}
|
||||
}
|
||||
|
||||
// send input
|
||||
if(client_state() == CLIENTSTATE_ONLINE)
|
||||
{
|
||||
if(server_spam_address)
|
||||
if(config.stress&1 && client_localtime() > 10.0f)
|
||||
client_disconnect();
|
||||
|
||||
if(input_is_changed || time_get() > last_input+time_freq())
|
||||
|
@ -870,8 +909,8 @@ static void client_run(const char *direct_connect_server)
|
|||
}
|
||||
}
|
||||
|
||||
if(client_state() == CLIENTSTATE_OFFLINE && server_spam_address)
|
||||
client_connect(server_spam_address);
|
||||
if(client_state() == CLIENTSTATE_OFFLINE && config.stress && (frames%100) == 0)
|
||||
client_connect(config.cl_stress_server);
|
||||
|
||||
// update input
|
||||
inp_update();
|
||||
|
@ -933,10 +972,19 @@ static void client_run(const char *direct_connect_server)
|
|||
client_serverbrowse_update();
|
||||
|
||||
// render
|
||||
client_render();
|
||||
|
||||
// swap the buffers
|
||||
gfx_swap();
|
||||
if(config.stress)
|
||||
{
|
||||
if((frames%10) == 0)
|
||||
{
|
||||
client_render();
|
||||
gfx_swap();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
client_render();
|
||||
gfx_swap();
|
||||
}
|
||||
|
||||
// check conditions
|
||||
if(client_state() == CLIENTSTATE_QUITING)
|
||||
|
@ -948,8 +996,11 @@ static void client_run(const char *direct_connect_server)
|
|||
|
||||
if(reporttime < time_get())
|
||||
{
|
||||
dbg_msg("client/report", "fps=%.02f netstate=%d",
|
||||
frames/(float)(reportinterval/time_freq()), net.state());
|
||||
if(config.debug)
|
||||
{
|
||||
dbg_msg("client/report", "fps=%.02f netstate=%d",
|
||||
frames/(float)(reportinterval/time_freq()), net.state());
|
||||
}
|
||||
frames = 0;
|
||||
reporttime += reportinterval;
|
||||
}
|
||||
|
@ -977,12 +1028,24 @@ int main(int argc, char **argv)
|
|||
dbg_msg("client", "starting...");
|
||||
|
||||
config_reset();
|
||||
|
||||
#ifdef CONF_PLATFORM_MACOSX
|
||||
config_load("~/.teewars");
|
||||
const char *config_filename = "~/.teewars";
|
||||
#else
|
||||
config_load("default.cfg");
|
||||
const char *config_filename = "default.cfg";
|
||||
#endif
|
||||
|
||||
for(int i = 1; i < argc; i++)
|
||||
{
|
||||
if(argv[i][0] == '-' && argv[i][1] == 'f' && argv[i][2] == 0 && argc - i > 1)
|
||||
{
|
||||
config_filename = argv[i+1];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
config_load(config_filename);
|
||||
|
||||
const char *direct_connect_server = 0x0;
|
||||
snd_set_master_volume(config.volume / 255.0f);
|
||||
bool editor = false;
|
||||
|
@ -999,28 +1062,12 @@ int main(int argc, char **argv)
|
|||
i++;
|
||||
direct_connect_server = argv[i];
|
||||
}
|
||||
else if(argv[i][0] == '-' && argv[i][1] == 's' && argv[i][2] == 0 && argc - i > 1)
|
||||
{
|
||||
// -s SERVER:PORT
|
||||
i++;
|
||||
server_spam_address = argv[i];
|
||||
}
|
||||
else if(argv[i][0] == '-' && argv[i][1] == 'n' && argv[i][2] == 0 && argc - i > 1)
|
||||
{
|
||||
// -n NAME
|
||||
i++;
|
||||
config_set_player_name(&config, argv[i]);
|
||||
}
|
||||
else if(argv[i][0] == '-' && argv[i][1] == 'w' && argv[i][2] == 0)
|
||||
{
|
||||
// -w
|
||||
config.gfx_fullscreen = 0;
|
||||
}
|
||||
|
||||
else if(argv[i][0] == '-' && argv[i][1] == 'e' && argv[i][2] == 0)
|
||||
{
|
||||
editor = true;
|
||||
}
|
||||
else
|
||||
config_set(argv[i]);
|
||||
}
|
||||
|
||||
if(editor)
|
||||
|
|
|
@ -122,6 +122,12 @@ bool gfx_init()
|
|||
screen_width = config.gfx_screen_width;
|
||||
screen_height = config.gfx_screen_height;
|
||||
|
||||
if(config.stress)
|
||||
{
|
||||
screen_width = 320;
|
||||
screen_height = 240;
|
||||
}
|
||||
|
||||
if(config.gfx_fullscreen)
|
||||
{
|
||||
if(!context.create(screen_width, screen_height, 24, 0, 0, 0, opengl::context::FLAG_FULLSCREEN))
|
||||
|
@ -138,7 +144,12 @@ bool gfx_init()
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
context.set_title("Teewars");
|
||||
|
||||
// We don't want to see the window when we run the stress testing
|
||||
if(config.stress)
|
||||
context.iconify();
|
||||
|
||||
// Init vertices
|
||||
if (vertices)
|
||||
|
@ -146,7 +157,6 @@ bool gfx_init()
|
|||
vertices = (custom_vertex*)mem_alloc(sizeof(custom_vertex) * vertex_buffer_size, 1);
|
||||
num_vertices = 0;
|
||||
|
||||
context.set_title("---");
|
||||
|
||||
/*
|
||||
dbg_msg("gfx", "OpenGL version %d.%d.%d", context.version_major(),
|
||||
|
@ -250,6 +260,7 @@ int gfx_get_video_modes(video_mode *list, int maxcount)
|
|||
mem_copy(list, fakemodes, sizeof(fakemodes));
|
||||
return min((int)(sizeof(fakemodes)/sizeof(video_mode)), maxcount);
|
||||
}
|
||||
|
||||
return context.getvideomodes((opengl::videomode *)list, maxcount);
|
||||
}
|
||||
|
||||
|
@ -321,7 +332,8 @@ int gfx_load_texture_raw(int w, int h, int format, const void *data)
|
|||
}
|
||||
}
|
||||
|
||||
dbg_msg("gfx", "%d = %dx%d", tex, w, h);
|
||||
if(config.debug)
|
||||
dbg_msg("gfx", "%d = %dx%d", tex, w, h);
|
||||
|
||||
// set data and return
|
||||
if(config.gfx_texture_compression && GLEW_ARB_texture_compression)
|
||||
|
@ -790,64 +802,93 @@ double extra_kerning[256*256] = {0};
|
|||
|
||||
pretty_font *current_font = &default_font;
|
||||
|
||||
void gfx_pretty_text(float x, float y, float size, const char *text, int max_width)
|
||||
static int word_length(const char *text)
|
||||
{
|
||||
int s = 1;
|
||||
while(1)
|
||||
{
|
||||
if(*text == 0)
|
||||
return s-1;
|
||||
if(*text == '\n' || *text == '\t' || *text == ' ')
|
||||
return s;
|
||||
text++;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
float gfx_pretty_text_raw(float x, float y, float size, const char *text_, int length)
|
||||
{
|
||||
const unsigned char *text = (unsigned char *)text_;
|
||||
const float spacing = 0.05f;
|
||||
gfx_texture_set(current_font->font_texture);
|
||||
gfx_quads_begin();
|
||||
|
||||
float startx = x;
|
||||
if(length < 0)
|
||||
length = strlen(text_);
|
||||
|
||||
while (*text)
|
||||
while(length)
|
||||
{
|
||||
const int c = *text;
|
||||
|
||||
if(c == '\n')
|
||||
{
|
||||
x = startx;
|
||||
y += size;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float width = current_font->m_CharEndTable[c] - current_font->m_CharStartTable[c];
|
||||
|
||||
x -= size * current_font->m_CharStartTable[c];
|
||||
|
||||
gfx_quads_setsubset(
|
||||
(c%16)/16.0f, // startx
|
||||
(c/16)/16.0f, // starty
|
||||
(c%16)/16.0f+1.0f/16.0f, // endx
|
||||
(c/16)/16.0f+1.0f/16.0f); // endy
|
||||
|
||||
gfx_quads_drawTL(x, y, size, size);
|
||||
|
||||
double x_nudge = 0;
|
||||
if (text[1])
|
||||
x_nudge = extra_kerning[text[0] + text[1] * 256];
|
||||
|
||||
x += (width + current_font->m_CharStartTable[c] + spacing + x_nudge) * size;
|
||||
|
||||
if (max_width != -1 && x - startx > max_width)
|
||||
{
|
||||
x = startx;
|
||||
y += size - 2;
|
||||
}
|
||||
}
|
||||
|
||||
text++;
|
||||
|
||||
const float width = current_font->m_CharEndTable[c] - current_font->m_CharStartTable[c];
|
||||
|
||||
x -= size * current_font->m_CharStartTable[c];
|
||||
|
||||
gfx_quads_setsubset(
|
||||
(c%16)/16.0f, // startx
|
||||
(c/16)/16.0f, // starty
|
||||
(c%16)/16.0f+1.0f/16.0f, // endx
|
||||
(c/16)/16.0f+1.0f/16.0f); // endy
|
||||
|
||||
gfx_quads_drawTL(x, y, size, size);
|
||||
|
||||
double x_nudge = 0;
|
||||
if(length > 1 && text[1])
|
||||
x_nudge = extra_kerning[text[0] + text[1] * 256];
|
||||
|
||||
x += (width + current_font->m_CharStartTable[c] + spacing + x_nudge) * size;
|
||||
length--;
|
||||
}
|
||||
|
||||
gfx_quads_end();
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
float gfx_pretty_text_width(float size, const char *text, int length)
|
||||
void gfx_pretty_text(float x, float y, float size, const char *text, int max_width)
|
||||
{
|
||||
if(max_width == -1)
|
||||
gfx_pretty_text_raw(x, y, size, text, -1);
|
||||
else
|
||||
{
|
||||
float startx = x;
|
||||
while(*text)
|
||||
{
|
||||
int wlen = word_length(text);
|
||||
float w = gfx_pretty_text_width(size, text, wlen);
|
||||
if(x+w-startx > max_width)
|
||||
{
|
||||
y += size-2;
|
||||
x = startx;
|
||||
}
|
||||
|
||||
x = gfx_pretty_text_raw(x, y, size, text, wlen);
|
||||
|
||||
text += wlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float gfx_pretty_text_width(float size, const char *text_, int length)
|
||||
{
|
||||
const float spacing = 0.05f;
|
||||
float w = 0.0f;
|
||||
const unsigned char *text = (unsigned char *)text_;
|
||||
|
||||
const char *stop;
|
||||
const unsigned char *stop;
|
||||
if (length == -1)
|
||||
stop = text + strlen(text);
|
||||
stop = text + strlen((char*)text);
|
||||
else
|
||||
stop = text + length;
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <baselib/stream/file.h>
|
||||
|
||||
#include <engine/interface.h>
|
||||
#include <engine/config.h>
|
||||
|
||||
extern "C" {
|
||||
#include "../../wavpack/wavpack.h"
|
||||
|
@ -24,6 +25,16 @@ static const float GLOBAL_SOUND_DELAY = 0.05f;
|
|||
class sound_data
|
||||
{
|
||||
public:
|
||||
sound_data() :
|
||||
data(0x0),
|
||||
num_samples(0),
|
||||
rate(0),
|
||||
channels(0),
|
||||
sustain_start(-1),
|
||||
sustain_end(-1),
|
||||
last_played(0)
|
||||
{ }
|
||||
|
||||
short *data;
|
||||
int num_samples;
|
||||
int rate;
|
||||
|
@ -33,13 +44,14 @@ public:
|
|||
int64 last_played;
|
||||
};
|
||||
|
||||
inline short clamp(int i)
|
||||
template<typename T>
|
||||
inline const T clamp(const T val, const T lower, const T upper)
|
||||
{
|
||||
if(i > 0x7fff)
|
||||
return 0x7fff;
|
||||
if(i < -0x7fff)
|
||||
return -0x7fff;
|
||||
return i;
|
||||
if(val > upper)
|
||||
return upper;
|
||||
if(val < lower)
|
||||
return lower;
|
||||
return val;
|
||||
}
|
||||
|
||||
static class mixer : public audio_stream
|
||||
|
@ -65,34 +77,40 @@ public:
|
|||
enum
|
||||
{
|
||||
MAX_CHANNELS=32,
|
||||
MAX_FILL_FRAMES=256,
|
||||
};
|
||||
|
||||
channel channels[MAX_CHANNELS];
|
||||
int buffer[MAX_FILL_FRAMES*2];
|
||||
|
||||
void fill_mono(short *out, unsigned long frames, channel *c, float dv = 0.0f)
|
||||
void fill_mono(int *out, unsigned long frames, channel *c, float dv = 0.0f)
|
||||
{
|
||||
float pl = clamp(1.0f - c->pan, 0.0f, 1.0f);
|
||||
float pr = clamp(1.0f + c->pan, 0.0f, 1.0f);
|
||||
|
||||
for(unsigned long i = 0; i < frames; i++)
|
||||
{
|
||||
float p = (1.0f-(c->pan+1.0f)*0.5f);
|
||||
int val = (int)(p*c->vol * master_volume * c->data->data[c->tick]);
|
||||
out[i<<1] += (short)val;
|
||||
out[(i<<1)+1] += (short)val;
|
||||
float val = c->vol * master_volume * c->data->data[c->tick];
|
||||
|
||||
out[i<<1] += (int)(pl*val);
|
||||
out[(i<<1)+1] += (int)(pr*val);
|
||||
c->tick++;
|
||||
c->vol += dv;
|
||||
if(c->vol < 0.0f) c->vol = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void fill_stereo(short *out, unsigned long frames, channel *c, float dv = 0.0f)
|
||||
void fill_stereo(int *out, unsigned long frames, channel *c, float dv = 0.0f)
|
||||
{
|
||||
float pl = clamp(1.0f - c->pan, 0.0f, 1.0f);
|
||||
float pr = clamp(1.0f + c->pan, 0.0f, 1.0f);
|
||||
|
||||
for(unsigned long i = 0; i < frames; i++)
|
||||
{
|
||||
float pl = c->pan<0.0f?-c->pan:1.0f;
|
||||
float pr = c->pan>0.0f?1.0f-c->pan:1.0f;
|
||||
int vl = (int)(pl*c->vol * master_volume * c->data->data[c->tick]);
|
||||
int vr = (int)(pr*c->vol * master_volume * c->data->data[c->tick + 1]);
|
||||
out[i<<1] += (short)vl;
|
||||
out[(i<<1)+1] += (short)vr;
|
||||
out[i<<1] += vl;
|
||||
out[(i<<1)+1] += vr;
|
||||
c->tick += 2;
|
||||
c->vol += dv;
|
||||
if(c->vol < 0.0f) c->vol = 0.0f;
|
||||
|
@ -103,10 +121,12 @@ public:
|
|||
{
|
||||
short *out = (short*)output;
|
||||
|
||||
dbg_assert(frames <= MAX_FILL_FRAMES, "not enough fill frames in buffer");
|
||||
|
||||
for(unsigned long i = 0; i < frames; i++)
|
||||
{
|
||||
out[i<<1] = 0;
|
||||
out[(i<<1)+1] = 0;
|
||||
buffer[i<<1] = 0;
|
||||
buffer[(i<<1)+1] = 0;
|
||||
}
|
||||
|
||||
for(int c = 0; c < MAX_CHANNELS; c++)
|
||||
|
@ -133,9 +153,9 @@ public:
|
|||
}
|
||||
|
||||
if(channels[c].data->channels == 1)
|
||||
fill_mono(out, to_fill, &channels[c], dv);
|
||||
fill_mono(buffer, to_fill, &channels[c], dv);
|
||||
else
|
||||
fill_stereo(out, to_fill, &channels[c], dv);
|
||||
fill_stereo(buffer, to_fill, &channels[c], dv);
|
||||
|
||||
if(channels[c].loop >= 0 &&
|
||||
channels[c].data->sustain_start >= 0 &&
|
||||
|
@ -156,6 +176,12 @@ public:
|
|||
filled += to_fill;
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned long i = 0; i < frames; i++)
|
||||
{
|
||||
out[i<<1] = (short)clamp(buffer[i<<1], -0x7fff, 0x7fff);
|
||||
out[(i<<1)+1] = (short)clamp(buffer[(i<<1)+1], -0x7fff, 0x7fff);
|
||||
}
|
||||
}
|
||||
|
||||
int play(sound_data *sound, unsigned loop, float vol, float pan)
|
||||
|
@ -262,7 +288,7 @@ int snd_load_wv(const char *filename)
|
|||
|
||||
char error[100];
|
||||
|
||||
file = fopen(filename, "r");
|
||||
file = fopen(filename, "rb");
|
||||
|
||||
WavpackContext *context = WavpackOpenFileInput(read_data, error);
|
||||
if (context)
|
||||
|
@ -453,7 +479,8 @@ int snd_load_wav(const char *filename)
|
|||
{
|
||||
unsigned char smpl[36];
|
||||
unsigned char loop[24];
|
||||
dbg_msg("sound/wav", "got sustain");
|
||||
if(config.debug)
|
||||
dbg_msg("sound/wav", "got sustain");
|
||||
|
||||
file.read(smpl, sizeof(smpl));
|
||||
unsigned num_loops = (smpl[28] | (smpl[29]<<8) | (smpl[30]<<16) | (smpl[31]<<24));
|
||||
|
@ -482,7 +509,10 @@ int snd_load_wav(const char *filename)
|
|||
}
|
||||
|
||||
if(id >= 0)
|
||||
dbg_msg("sound/wav", "loaded %s", filename);
|
||||
{
|
||||
if(config.debug)
|
||||
dbg_msg("sound/wav", "loaded %s", filename);
|
||||
}
|
||||
else
|
||||
dbg_msg("sound/wav", "failed to load %s", filename);
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ const unsigned char *vint_unpack(const unsigned char *src, int *i)
|
|||
int sign = (*src>>6)&1;
|
||||
*i = *src&0x3F;
|
||||
|
||||
while(1)
|
||||
do
|
||||
{
|
||||
if(!(*src&0x80)) break;
|
||||
src++;
|
||||
|
@ -49,7 +49,7 @@ const unsigned char *vint_unpack(const unsigned char *src, int *i)
|
|||
if(!(*src&0x80)) break;
|
||||
src++;
|
||||
*i |= (*src&(0x7F))<<(6+7+7+7);
|
||||
}
|
||||
} while(0);
|
||||
|
||||
src++;
|
||||
*i ^= -sign; // if(sign) *i = ~(*i)
|
||||
|
|
|
@ -119,7 +119,7 @@ void config_save(const char *filename)
|
|||
#else
|
||||
const char newline[] = "\n";
|
||||
#endif
|
||||
const int newline_len = sizeof(newline);
|
||||
const int newline_len = sizeof(newline)-1;
|
||||
|
||||
#define MACRO_CONFIG_INT(name,def,min,max) { char str[256]; sprintf(str, "%s=%i", #name, config.name); file.write(str, strlen(str)); file.write(newline, newline_len); }
|
||||
#define MACRO_CONFIG_STR(name,len,def) { file.write(#name, strlen(#name)); file.write("=", 1); file.write(config.name, strlen(config.name)); file.write(newline, newline_len); }
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
#include "../game/game_variables.h"
|
||||
|
||||
MACRO_CONFIG_INT(debug, 0, 0, 1)
|
||||
MACRO_CONFIG_INT(volume, 200, 0, 255)
|
||||
MACRO_CONFIG_INT(cpu_throttle, 0, 0, 1)
|
||||
MACRO_CONFIG_STR(player_name, 32, "nameless tee")
|
||||
MACRO_CONFIG_STR(clan_name, 32, "")
|
||||
MACRO_CONFIG_STR(password, 32, "")
|
||||
|
||||
|
||||
MACRO_CONFIG_INT(debug, 0, 0, 1)
|
||||
MACRO_CONFIG_INT(stress, 0, 0, 0)
|
||||
MACRO_CONFIG_STR(cl_stress_server, 32, "localhost")
|
||||
|
||||
MACRO_CONFIG_INT(gfx_screen_width, 800, 0, 0)
|
||||
MACRO_CONFIG_INT(gfx_screen_height, 600, 0, 0)
|
||||
MACRO_CONFIG_INT(gfx_fullscreen, 1, 0, 1)
|
||||
|
@ -25,3 +29,7 @@ MACRO_CONFIG_STR(sv_name, 128, "unnamed server")
|
|||
MACRO_CONFIG_STR(sv_bindaddr, 128, "")
|
||||
MACRO_CONFIG_INT(sv_port, 8303, 0, 0)
|
||||
MACRO_CONFIG_INT(sv_sendheartbeats, 1, 0, 1)
|
||||
MACRO_CONFIG_STR(sv_map, 128, "dm1")
|
||||
|
||||
MACRO_CONFIG_INT(sv_max_clients, 8, 1, 8)
|
||||
|
||||
|
|
|
@ -12,15 +12,11 @@ enum
|
|||
{
|
||||
MAX_CLIENTS=8,
|
||||
SERVER_TICK_SPEED=50,
|
||||
SERVER_CLIENT_TIMEOUT=5,
|
||||
SNAP_CURRENT=0,
|
||||
SNAP_PREV=1,
|
||||
|
||||
IMG_RGB=0,
|
||||
IMG_RGBA=1,
|
||||
/*
|
||||
IMG_BGR,
|
||||
IMG_BGRA,*/
|
||||
|
||||
CLIENTSTATE_OFFLINE=0,
|
||||
CLIENTSTATE_CONNECTING,
|
||||
|
@ -795,4 +791,7 @@ void client_quit();
|
|||
void client_serverbrowse_refresh(int lan);
|
||||
int client_serverbrowse_getlist(server_info **servers);
|
||||
|
||||
int snap_new_id();
|
||||
void snap_free_id(int id);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include <baselib/system.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "network.h"
|
||||
#include "ringbuffer.h"
|
||||
|
||||
|
@ -39,6 +41,8 @@ enum
|
|||
NETWORK_PACKETFLAG_VITAL=0x08,
|
||||
NETWORK_PACKETFLAG_RESEND=0x10,
|
||||
NETWORK_PACKETFLAG_CONNLESS=0x20,
|
||||
|
||||
NETWORK_MAX_SEQACK=0x1000,
|
||||
};
|
||||
|
||||
static int current_token = 1;
|
||||
|
@ -75,19 +79,23 @@ static void send_packet(NETSOCKET socket, NETADDR4 *addr, NETPACKETDATA *packet)
|
|||
|
||||
struct NETCONNECTION
|
||||
{
|
||||
unsigned seq;
|
||||
unsigned ack;
|
||||
unsigned short seq;
|
||||
unsigned short ack;
|
||||
unsigned state;
|
||||
|
||||
int token;
|
||||
|
||||
int remote_closed;
|
||||
|
||||
int connected;
|
||||
int disconnected;
|
||||
|
||||
ring_buffer buffer;
|
||||
|
||||
int64 last_update_time;
|
||||
int64 last_recv_time;
|
||||
int64 last_send_time;
|
||||
|
||||
char error_string[256];
|
||||
|
||||
NETADDR4 peeraddr;
|
||||
|
@ -104,6 +112,10 @@ struct NETSERVER
|
|||
{
|
||||
NETSOCKET socket;
|
||||
NETSLOT slots[NETWORK_MAX_CLIENTS];
|
||||
int max_clients;
|
||||
NETFUNC_NEWCLIENT new_client;
|
||||
NETFUNC_NEWCLIENT del_client;
|
||||
void *user_ptr;
|
||||
unsigned char recv_buffer[NETWORK_MAX_PACKET_SIZE];
|
||||
};
|
||||
|
||||
|
@ -125,6 +137,7 @@ static void conn_reset(NETCONNECTION *conn)
|
|||
{
|
||||
conn->seq = 0;
|
||||
conn->ack = 0;
|
||||
conn->remote_closed = 0;
|
||||
//dbg_msg("connection", "state = %d->%d", conn->state, NETWORK_CONNSTATE_OFFLINE);
|
||||
|
||||
if(conn->state == NETWORK_CONNSTATE_ONLINE ||
|
||||
|
@ -136,6 +149,7 @@ static void conn_reset(NETCONNECTION *conn)
|
|||
conn->state = NETWORK_CONNSTATE_OFFLINE;
|
||||
conn->last_send_time = 0;
|
||||
conn->last_recv_time = 0;
|
||||
conn->last_update_time = 0;
|
||||
conn->token = -1;
|
||||
conn->buffer.reset();
|
||||
}
|
||||
|
@ -176,7 +190,7 @@ static void conn_ack(NETCONNECTION *conn, int ack)
|
|||
break;
|
||||
|
||||
NETPACKETDATA *resend = (NETPACKETDATA *)i->data();
|
||||
if(resend->seq <= ack)
|
||||
if(resend->seq <= ack || (ack < NETWORK_MAX_SEQACK/3 && resend->seq > NETWORK_MAX_SEQACK/2))
|
||||
conn->buffer.pop_first();
|
||||
else
|
||||
break;
|
||||
|
@ -207,7 +221,9 @@ static void conn_resend(NETCONNECTION *conn)
|
|||
static void conn_send(NETCONNECTION *conn, int flags, int data_size, const void *data)
|
||||
{
|
||||
if(flags&NETWORK_PACKETFLAG_VITAL)
|
||||
conn->seq++;
|
||||
{
|
||||
conn->seq = (conn->seq+1)%NETWORK_MAX_SEQACK;
|
||||
}
|
||||
|
||||
NETPACKETDATA p;
|
||||
p.ID[0] = 'T';
|
||||
|
@ -244,6 +260,7 @@ static int conn_connect(NETCONNECTION *conn, NETADDR4 *addr)
|
|||
conn_reset(conn);
|
||||
conn->peeraddr = *addr;
|
||||
conn->token = current_token++;
|
||||
mem_zero(conn->error_string, sizeof(conn->error_string));
|
||||
//dbg_msg("connection", "state = %d->%d", conn->state, NETWORK_CONNSTATE_CONNECT);
|
||||
conn->state = NETWORK_CONNSTATE_CONNECT;
|
||||
conn_send(conn, NETWORK_PACKETFLAG_CONNECT, 0, 0);
|
||||
|
@ -252,10 +269,13 @@ static int conn_connect(NETCONNECTION *conn, NETADDR4 *addr)
|
|||
|
||||
static void conn_disconnect(NETCONNECTION *conn, const char *reason)
|
||||
{
|
||||
if(reason)
|
||||
conn_send(conn, NETWORK_PACKETFLAG_CLOSE, strlen(reason)+1, reason);
|
||||
else
|
||||
conn_send(conn, NETWORK_PACKETFLAG_CLOSE, 0, 0);
|
||||
if(conn->remote_closed == 0)
|
||||
{
|
||||
if(reason)
|
||||
conn_send(conn, NETWORK_PACKETFLAG_CLOSE, strlen(reason)+1, reason);
|
||||
else
|
||||
conn_send(conn, NETWORK_PACKETFLAG_CLOSE, 0, 0);
|
||||
}
|
||||
conn_reset(conn);
|
||||
}
|
||||
|
||||
|
@ -267,12 +287,16 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETDATA *p, NETADDR4 *addr)
|
|||
|
||||
if(p->flags&NETWORK_PACKETFLAG_CLOSE)
|
||||
{
|
||||
conn_reset(conn);
|
||||
conn->state = NETWORK_CONNSTATE_ERROR;
|
||||
conn->remote_closed = 1;
|
||||
|
||||
//conn_reset(conn);
|
||||
if(p->data_size)
|
||||
conn_set_error(conn, (char *)p->data);
|
||||
else
|
||||
conn_set_error(conn, "no reason given");
|
||||
dbg_msg("conn", "closed reason='%s'", conn_error(conn));
|
||||
if(config.debug)
|
||||
dbg_msg("conn", "closed reason='%s'", conn_error(conn));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -288,7 +312,8 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETDATA *p, NETADDR4 *addr)
|
|||
conn->token = p->token;
|
||||
//dbg_msg("connection", "token set to %d", p->token);
|
||||
conn_send(conn, NETWORK_PACKETFLAG_CONNECT|NETWORK_PACKETFLAG_ACCEPT, 0, 0);
|
||||
dbg_msg("connection", "got connection, sending connect+accept");
|
||||
if(config.debug)
|
||||
dbg_msg("connection", "got connection, sending connect+accept");
|
||||
}
|
||||
}
|
||||
else if(net_addr4_cmp(&conn->peeraddr, addr) == 0)
|
||||
|
@ -310,15 +335,15 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETDATA *p, NETADDR4 *addr)
|
|||
|
||||
if(p->flags&NETWORK_PACKETFLAG_VITAL)
|
||||
{
|
||||
if(p->seq == conn->ack+1)
|
||||
if(p->seq == (conn->ack+1)%NETWORK_MAX_SEQACK)
|
||||
{
|
||||
// in sequence
|
||||
conn->ack++;
|
||||
conn->ack = (conn->ack+1)%NETWORK_MAX_SEQACK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// out of sequence, request resend
|
||||
//dbg_msg("conn", "asking for resend");
|
||||
dbg_msg("conn", "asking for resend %d %d", p->seq, (conn->ack+1)%NETWORK_MAX_SEQACK);
|
||||
conn_send(conn, NETWORK_PACKETFLAG_RESEND, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
@ -361,8 +386,10 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETDATA *p, NETADDR4 *addr)
|
|||
}*/
|
||||
else
|
||||
{
|
||||
conn_reset(conn);
|
||||
//conn_reset(conn);
|
||||
// strange packet, wrong state
|
||||
conn->state = NETWORK_CONNSTATE_ERROR;
|
||||
conn_set_error(conn, "strange state and packet");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -379,15 +406,37 @@ static int conn_update(NETCONNECTION *conn)
|
|||
{
|
||||
if(conn->state == NETWORK_CONNSTATE_OFFLINE || conn->state == NETWORK_CONNSTATE_ERROR)
|
||||
return 0;
|
||||
|
||||
// watch out for major hitches
|
||||
int64 now = time_get();
|
||||
int64 delta = now-conn->last_update_time;
|
||||
if(conn->last_update_time && delta > time_freq()/2)
|
||||
{
|
||||
dbg_msg("conn", "hitch %d", (int)((delta*1000)/time_freq()));
|
||||
|
||||
conn->last_recv_time += delta;
|
||||
|
||||
ring_buffer::item *i = conn->buffer.first();
|
||||
while(i)
|
||||
{
|
||||
NETPACKETDATA *resend = (NETPACKETDATA *)i->data();
|
||||
resend->first_send_time += delta;
|
||||
i = i->next;
|
||||
}
|
||||
}
|
||||
|
||||
conn->last_update_time = now;
|
||||
|
||||
// check for timeout
|
||||
if(conn->state != NETWORK_CONNSTATE_OFFLINE &&
|
||||
conn->state != NETWORK_CONNSTATE_CONNECT &&
|
||||
(time_get()-conn->last_recv_time) > time_freq()*3)
|
||||
(now-conn->last_recv_time) > time_freq()*10)
|
||||
{
|
||||
//dbg_msg("connection", "state = %d->%d", conn->state, NETWORK_CONNSTATE_ERROR);
|
||||
conn->state = NETWORK_CONNSTATE_ERROR;
|
||||
conn_set_error(conn, "timeout");
|
||||
char buf[128];
|
||||
sprintf(buf, "timeout %lld %lld %lld %lld", now-conn->last_recv_time, now, conn->last_recv_time, time_freq()*10);
|
||||
conn_set_error(conn, buf);
|
||||
}
|
||||
|
||||
// check for large buffer errors
|
||||
|
@ -401,11 +450,11 @@ static int conn_update(NETCONNECTION *conn)
|
|||
if(conn->buffer.first())
|
||||
{
|
||||
NETPACKETDATA *resend = (NETPACKETDATA *)conn->buffer.first()->data();
|
||||
if(time_get()-resend->first_send_time > time_freq()*3)
|
||||
if(now-resend->first_send_time > time_freq()*10)
|
||||
{
|
||||
//dbg_msg("connection", "state = %d->%d", conn->state, NETWORK_CONNSTATE_ERROR);
|
||||
conn->state = NETWORK_CONNSTATE_ERROR;
|
||||
conn_set_error(conn, "too weak connection (not acked for 3 seconds)");
|
||||
conn_set_error(conn, "too weak connection (not acked for 10 seconds)");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,9 +512,18 @@ static int check_packet(unsigned char *buffer, int size, NETPACKETDATA *packet)
|
|||
|
||||
NETSERVER *net_server_open(NETADDR4 bindaddr, int max_clients, int flags)
|
||||
{
|
||||
NETSOCKET socket = net_udp4_create(bindaddr);
|
||||
if(socket == NETSOCKET_INVALID)
|
||||
return 0;
|
||||
|
||||
NETSERVER *server = (NETSERVER *)mem_alloc(sizeof(NETSERVER), 1);
|
||||
mem_zero(server, sizeof(NETSERVER));
|
||||
server->socket = net_udp4_create(bindaddr);
|
||||
server->socket = socket;
|
||||
server->max_clients = max_clients;
|
||||
if(server->max_clients > NETWORK_MAX_CLIENTS)
|
||||
server->max_clients = NETWORK_MAX_CLIENTS;
|
||||
if(server->max_clients < 1)
|
||||
server->max_clients = 1;
|
||||
|
||||
for(int i = 0; i < NETWORK_MAX_CLIENTS; i++)
|
||||
conn_init(&server->slots[i].conn, server->socket);
|
||||
|
@ -473,15 +531,24 @@ NETSERVER *net_server_open(NETADDR4 bindaddr, int max_clients, int flags)
|
|||
return server;
|
||||
}
|
||||
|
||||
int net_server_set_callbacks(NETSERVER *s, NETFUNC_NEWCLIENT new_client, NETFUNC_DELCLIENT del_client, void *user)
|
||||
{
|
||||
s->new_client = new_client;
|
||||
s->del_client = del_client;
|
||||
s->user_ptr = user;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int net_server_close(NETSERVER *s)
|
||||
{
|
||||
// TODO: implement me
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
int net_server_newclient(NETSERVER *s)
|
||||
{
|
||||
for(int i = 0; i < NETWORK_MAX_CLIENTS; i++)
|
||||
for(int i = 0; i < s->max_clients; i++)
|
||||
{
|
||||
if(s->slots[i].conn.connected)
|
||||
{
|
||||
|
@ -495,7 +562,7 @@ int net_server_newclient(NETSERVER *s)
|
|||
|
||||
int net_server_delclient(NETSERVER *s)
|
||||
{
|
||||
for(int i = 0; i < NETWORK_MAX_CLIENTS; i++)
|
||||
for(int i = 0; i < s->max_clients; i++)
|
||||
{
|
||||
if(s->slots[i].conn.disconnected)
|
||||
{
|
||||
|
@ -505,20 +572,24 @@ int net_server_delclient(NETSERVER *s)
|
|||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}*/
|
||||
|
||||
int net_server_drop(NETSERVER *s, int client_id, const char *reason)
|
||||
{
|
||||
// TODO: insert lots of checks here
|
||||
dbg_msg("net_server", "client dropped. cid=%d reason=\"%s\"", client_id, reason);
|
||||
conn_disconnect(&s->slots[client_id].conn, reason);
|
||||
|
||||
if(s->del_client)
|
||||
s->del_client(client_id, s->user_ptr);
|
||||
|
||||
//conn_reset(&s->slots[client_id].conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int net_server_update(NETSERVER *s)
|
||||
{
|
||||
for(int i = 0; i < NETWORK_MAX_CLIENTS; i++)
|
||||
for(int i = 0; i < s->max_clients; i++)
|
||||
{
|
||||
conn_update(&s->slots[i].conn);
|
||||
if(s->slots[i].conn.state == NETWORK_CONNSTATE_ERROR)
|
||||
|
@ -560,7 +631,7 @@ int net_server_recv(NETSERVER *s, NETPACKET *packet)
|
|||
int found = 0;
|
||||
|
||||
// check if we already got this client
|
||||
for(int i = 0; i < NETWORK_MAX_CLIENTS; i++)
|
||||
for(int i = 0; i < s->max_clients; i++)
|
||||
{
|
||||
if(s->slots[i].conn.state != NETWORK_CONNSTATE_OFFLINE &&
|
||||
net_addr4_cmp(&s->slots[i].conn.peeraddr, &addr) == 0)
|
||||
|
@ -574,27 +645,42 @@ int net_server_recv(NETSERVER *s, NETPACKET *packet)
|
|||
// client that wants to connect
|
||||
if(!found)
|
||||
{
|
||||
for(int i = 0; i < NETWORK_MAX_CLIENTS; i++)
|
||||
for(int i = 0; i < s->max_clients; i++)
|
||||
{
|
||||
if(s->slots[i].conn.state == NETWORK_CONNSTATE_OFFLINE)
|
||||
{
|
||||
//dbg_msg("netserver", "connection started %d", i);
|
||||
conn_feed(&s->slots[i].conn, &data, &addr);
|
||||
found = 1;
|
||||
conn_feed(&s->slots[i].conn, &data, &addr);
|
||||
if(s->new_client)
|
||||
s->new_client(i, s->user_ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(found)
|
||||
if(!found)
|
||||
{
|
||||
// TODO: send error
|
||||
// send connectionless packet
|
||||
const char errstring[] = "server full";
|
||||
NETPACKETDATA p;
|
||||
p.ID[0] = 'T';
|
||||
p.ID[1] = 'W';
|
||||
p.version = NETWORK_VERSION;
|
||||
p.flags = NETWORK_PACKETFLAG_CLOSE;
|
||||
p.seq = 0;
|
||||
p.ack = 0;
|
||||
p.crc = 0;
|
||||
p.token = data.token;
|
||||
p.data_size = sizeof(errstring);
|
||||
p.data = (unsigned char *)errstring;
|
||||
send_packet(s->socket, &addr, &p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// find matching slot
|
||||
for(int i = 0; i < NETWORK_MAX_CLIENTS; i++)
|
||||
for(int i = 0; i < s->max_clients; i++)
|
||||
{
|
||||
if(net_addr4_cmp(&s->slots[i].conn.peeraddr, &addr) == 0)
|
||||
{
|
||||
|
@ -648,7 +734,7 @@ int net_server_send(NETSERVER *s, NETPACKET *packet)
|
|||
else
|
||||
{
|
||||
dbg_assert(packet->client_id >= 0, "errornous client id");
|
||||
dbg_assert(packet->client_id < NETWORK_MAX_CLIENTS, "errornous client id");
|
||||
dbg_assert(packet->client_id < s->max_clients, "errornous client id");
|
||||
int flags = 0;
|
||||
if(packet->flags&PACKETFLAG_VITAL)
|
||||
flags |= NETWORK_PACKETFLAG_VITAL;
|
||||
|
@ -664,7 +750,7 @@ void net_server_stats(NETSERVER *s, NETSTATS *stats)
|
|||
int num_stats = sizeof(NETSTATS)/sizeof(int);
|
||||
int *istats = (int *)stats;
|
||||
|
||||
for(int c = 0; c < NETWORK_MAX_CLIENTS; c++)
|
||||
for(int c = 0; c < s->max_clients; c++)
|
||||
{
|
||||
int *sstats = (int *)(&(s->slots[c].conn.stats));
|
||||
for(int i = 0; i < num_stats; i++)
|
||||
|
@ -774,6 +860,7 @@ int net_client_send(NETCLIENT *c, NETPACKET *packet)
|
|||
p.seq = 0;
|
||||
p.ack = 0;
|
||||
p.crc = 0;
|
||||
p.token = 0;
|
||||
p.data_size = packet->data_size;
|
||||
p.data = (unsigned char *)packet->data;
|
||||
send_packet(c->socket, &packet->address, &p);
|
||||
|
|
|
@ -35,15 +35,19 @@ enum
|
|||
NETSTATE_ONLINE,
|
||||
};
|
||||
|
||||
typedef int (*NETFUNC_DELCLIENT)(int cid, void *user);
|
||||
typedef int (*NETFUNC_NEWCLIENT)(int cid, void *user);
|
||||
|
||||
// server side
|
||||
NETSERVER *net_server_open(NETADDR4 bindaddr, int max_clients, int flags);
|
||||
int net_server_set_callbacks(NETSERVER *s, NETFUNC_NEWCLIENT new_client, NETFUNC_DELCLIENT del_client, void *user);
|
||||
int net_server_recv(NETSERVER *s, NETPACKET *packet);
|
||||
int net_server_send(NETSERVER *s, NETPACKET *packet);
|
||||
int net_server_close(NETSERVER *s);
|
||||
int net_server_update(NETSERVER *s);
|
||||
int net_server_drop(NETSERVER *s, int client_id, const char *reason);
|
||||
int net_server_newclient(NETSERVER *s); // -1 when no more, else, client id
|
||||
int net_server_delclient(NETSERVER *s); // -1 when no more, else, client id
|
||||
//int net_server_newclient(NETSERVER *s); // -1 when no more, else, client id
|
||||
//int net_server_delclient(NETSERVER *s); // -1 when no more, else, client id
|
||||
void net_server_stats(NETSERVER *s, NETSTATS *stats);
|
||||
|
||||
// client side
|
||||
|
@ -71,13 +75,16 @@ public:
|
|||
int open(NETADDR4 bindaddr, int max, int flags) { ptr = net_server_open(bindaddr, max, flags); return ptr != 0; }
|
||||
int close() { int r = net_server_close(ptr); ptr = 0; return r; }
|
||||
|
||||
int set_callbacks(NETFUNC_NEWCLIENT new_client, NETFUNC_DELCLIENT del_client, void *user)
|
||||
{ return net_server_set_callbacks(ptr, new_client, del_client, user); }
|
||||
|
||||
int recv(NETPACKET *packet) { return net_server_recv(ptr, packet); }
|
||||
int send(NETPACKET *packet) { return net_server_send(ptr, packet); }
|
||||
int update() { return net_server_update(ptr); }
|
||||
|
||||
int drop(int client_id, const char *reason) { return net_server_drop(ptr, client_id, reason); }
|
||||
int newclient() { return net_server_newclient(ptr); }
|
||||
int delclient() { return net_server_delclient(ptr); }
|
||||
//int newclient() { return net_server_newclient(ptr); }
|
||||
//int delclient() { return net_server_delclient(ptr); }
|
||||
|
||||
void stats(NETSTATS *stats) { net_server_stats(ptr, stats); }
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <baselib/stream/file.h>
|
||||
#include <baselib/network.h>
|
||||
|
||||
|
@ -273,6 +274,9 @@ public:
|
|||
|
||||
int get_int()
|
||||
{
|
||||
if(current >= end)
|
||||
return 0;
|
||||
|
||||
int i;
|
||||
current = vint_unpack(current, &i);
|
||||
// TODO: might be changed into variable width
|
||||
|
@ -285,6 +289,9 @@ public:
|
|||
|
||||
const char *get_string()
|
||||
{
|
||||
if(current >= end)
|
||||
return "";
|
||||
|
||||
// TODO: add range check
|
||||
// TODO: add debug marker
|
||||
const char *ptr = (const char *)current;
|
||||
|
|
|
@ -30,6 +30,97 @@ void *snap_new_item(int type, int id, int size)
|
|||
return builder.new_item(type, id, size);
|
||||
}
|
||||
|
||||
|
||||
struct snap_id
|
||||
{
|
||||
short next;
|
||||
short state; // 0 = free, 1 = alloced, 2 = timed
|
||||
int timeout_tick;
|
||||
};
|
||||
|
||||
static const int MAX_IDS = 8*1024; // should be lowered
|
||||
static snap_id snap_ids[8*1024];
|
||||
static int snap_first_free_id;
|
||||
static int snap_first_timed_id;
|
||||
static int snap_last_timed_id;
|
||||
static int snap_id_usage;
|
||||
static int snap_id_inusage;
|
||||
|
||||
static int snap_id_inited = 0;
|
||||
|
||||
void snap_init_id()
|
||||
{
|
||||
for(int i = 0; i < MAX_IDS; i++)
|
||||
{
|
||||
snap_ids[i].next = i+1;
|
||||
snap_ids[i].state = 0;
|
||||
}
|
||||
|
||||
snap_ids[MAX_IDS-1].next = -1;
|
||||
snap_first_free_id = 0;
|
||||
snap_first_timed_id = -1;
|
||||
snap_last_timed_id = -1;
|
||||
snap_id_usage = 0;
|
||||
snap_id_inusage = 0;
|
||||
|
||||
snap_id_inited = 1;
|
||||
}
|
||||
|
||||
int snap_new_id()
|
||||
{
|
||||
dbg_assert(snap_id_inited == 1, "requesting id too soon");
|
||||
|
||||
// process timed ids
|
||||
while(snap_first_timed_id != -1 && snap_ids[snap_first_timed_id].timeout_tick < server_tick())
|
||||
{
|
||||
int next_timed = snap_ids[snap_first_timed_id].next;
|
||||
|
||||
// add it to the free list
|
||||
snap_ids[snap_first_timed_id].next = snap_first_free_id;
|
||||
snap_ids[snap_first_timed_id].state = 0;
|
||||
snap_first_free_id = snap_first_timed_id;
|
||||
|
||||
// remove it from the timed list
|
||||
snap_first_timed_id = next_timed;
|
||||
if(snap_first_timed_id == -1)
|
||||
snap_last_timed_id = -1;
|
||||
|
||||
snap_id_usage--;
|
||||
}
|
||||
|
||||
int id = snap_first_free_id;
|
||||
dbg_assert(id != -1, "id error");
|
||||
snap_first_free_id = snap_ids[snap_first_free_id].next;
|
||||
snap_ids[id].state = 1;
|
||||
snap_id_usage++;
|
||||
snap_id_inusage++;
|
||||
return id;
|
||||
}
|
||||
|
||||
void snap_free_id(int id)
|
||||
{
|
||||
dbg_assert(snap_ids[id].state == 1, "id is not alloced");
|
||||
|
||||
snap_id_inusage--;
|
||||
snap_ids[id].state = 2;
|
||||
snap_ids[id].timeout_tick = server_tick() + server_tickspeed()*5;
|
||||
snap_ids[id].next = -1;
|
||||
|
||||
if(snap_last_timed_id != -1)
|
||||
{
|
||||
snap_ids[snap_last_timed_id].next = id;
|
||||
snap_last_timed_id = id;
|
||||
}
|
||||
else
|
||||
{
|
||||
snap_first_timed_id = id;
|
||||
snap_last_timed_id = id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
class client
|
||||
{
|
||||
|
@ -132,31 +223,51 @@ int server_send_msg(int client_id)
|
|||
net.send(&packet);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int new_client_callback(int cid, void *user)
|
||||
{
|
||||
clients[cid].state = client::STATE_CONNECTING;
|
||||
clients[cid].name[0] = 0;
|
||||
clients[cid].clan[0] = 0;
|
||||
clients[cid].snapshots.purge_all();
|
||||
clients[cid].last_acked_snapshot = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int del_client_callback(int cid, void *user)
|
||||
{
|
||||
clients[cid].state = client::STATE_EMPTY;
|
||||
clients[cid].name[0] = 0;
|
||||
clients[cid].clan[0] = 0;
|
||||
clients[cid].snapshots.purge_all();
|
||||
|
||||
mods_client_drop(cid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: remove this class
|
||||
class server
|
||||
{
|
||||
public:
|
||||
//socket_udp4 game_socket;
|
||||
|
||||
const char *map_name;
|
||||
int64 lasttick;
|
||||
int64 lastheartbeat;
|
||||
netaddr4 master_server;
|
||||
|
||||
int biggest_snapshot;
|
||||
|
||||
bool run(const char *mapname)
|
||||
bool run()
|
||||
{
|
||||
biggest_snapshot = 0;
|
||||
|
||||
net_init(); // For Windows compatibility.
|
||||
map_name = mapname;
|
||||
|
||||
snap_init_id();
|
||||
|
||||
// load map
|
||||
if(!map_load(mapname))
|
||||
if(!map_load(config.sv_map))
|
||||
{
|
||||
dbg_msg("server", "failed to load map. mapname='%s'", mapname);
|
||||
dbg_msg("server", "failed to load map. mapname='%s'", config.sv_map);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -173,12 +284,14 @@ public:
|
|||
bindaddr.port = config.sv_port;
|
||||
}
|
||||
|
||||
if(!net.open(bindaddr, 0, 0))
|
||||
if(!net.open(bindaddr, config.sv_max_clients, 0))
|
||||
{
|
||||
dbg_msg("network/server", "couldn't open socket");
|
||||
dbg_msg("server", "couldn't open socket. port might already be in use");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
net.set_callbacks(new_client_callback, del_client_callback, 0);
|
||||
|
||||
dbg_msg("server", "server name is '%s'", config.sv_name);
|
||||
dbg_msg("server", "masterserver is '%s'", config.masterserver);
|
||||
if (net_host_lookup(config.masterserver, MASTERSERVER_PORT, &master_server) != 0)
|
||||
|
@ -242,12 +355,16 @@ public:
|
|||
|
||||
if(reporttime < time_get())
|
||||
{
|
||||
dbg_msg("server/report", "sim=%.02fms snap=%.02fms net=%.02fms total=%.02fms load=%.02f%%",
|
||||
(simulationtime/reportinterval)/(double)time_freq()*1000,
|
||||
(snaptime/reportinterval)/(double)time_freq()*1000,
|
||||
(networktime/reportinterval)/(double)time_freq()*1000,
|
||||
(totaltime/reportinterval)/(double)time_freq()*1000,
|
||||
(totaltime)/reportinterval/(double)time_freq()*100.0f);
|
||||
if(config.debug)
|
||||
{
|
||||
dbg_msg("server", "sim=%.02fms snap=%.02fms net=%.02fms total=%.02fms load=%.02f%% ids=%d/%d",
|
||||
(simulationtime/reportinterval)/(double)time_freq()*1000,
|
||||
(snaptime/reportinterval)/(double)time_freq()*1000,
|
||||
(networktime/reportinterval)/(double)time_freq()*1000,
|
||||
(totaltime/reportinterval)/(double)time_freq()*1000,
|
||||
(totaltime)/reportinterval/(double)time_freq()*100.0f,
|
||||
snap_id_inusage, snap_id_usage);
|
||||
}
|
||||
|
||||
simulationtime = 0;
|
||||
snaptime = 0;
|
||||
|
@ -313,8 +430,6 @@ public:
|
|||
delta_tick = clients[i].last_acked_snapshot;
|
||||
deltashot = (snapshot *)delta_data;
|
||||
}
|
||||
else
|
||||
dbg_msg("server", "no delta, sending full snapshot");
|
||||
}
|
||||
|
||||
// create delta
|
||||
|
@ -337,6 +452,7 @@ public:
|
|||
|
||||
const int max_size = MAX_SNAPSHOT_PACKSIZE;
|
||||
int numpackets = (snapshot_size+max_size-1)/max_size;
|
||||
(void)numpackets;
|
||||
for(int n = 0, left = snapshot_size; left; n++)
|
||||
{
|
||||
int chunk = left < max_size ? left : max_size;
|
||||
|
@ -373,14 +489,13 @@ public:
|
|||
void send_map(int cid)
|
||||
{
|
||||
msg_pack_start_system(NETMSG_MAP, MSGFLAG_VITAL);
|
||||
msg_pack_string(map_name, 0);
|
||||
msg_pack_string(config.sv_map, 0);
|
||||
msg_pack_end();
|
||||
server_send_msg(cid);
|
||||
}
|
||||
|
||||
void send_heartbeat()
|
||||
{
|
||||
dbg_msg("server", "sending heartbeat");
|
||||
NETPACKET packet;
|
||||
packet.client_id = -1;
|
||||
packet.address = master_server;
|
||||
|
@ -397,7 +512,7 @@ public:
|
|||
|
||||
clients[cid].state = client::STATE_EMPTY;
|
||||
mods_client_drop(cid);
|
||||
dbg_msg("game", "player dropped. reason='%s' cid=%x name='%s'", reason, cid, clients[cid].name);
|
||||
dbg_msg("server", "player dropped. reason='%s' cid=%x name='%s'", reason, cid, clients[cid].name);
|
||||
}
|
||||
|
||||
void process_client_packet(NETPACKET *packet)
|
||||
|
@ -434,7 +549,7 @@ public:
|
|||
{
|
||||
if(clients[cid].state != client::STATE_INGAME)
|
||||
{
|
||||
dbg_msg("game", "player as entered the game. cid=%x", cid);
|
||||
dbg_msg("server", "player as entered the game. cid=%x", cid);
|
||||
clients[cid].state = client::STATE_INGAME;
|
||||
mods_client_enter(cid);
|
||||
}
|
||||
|
@ -483,7 +598,7 @@ public:
|
|||
packer.reset();
|
||||
packer.add_raw(SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO));
|
||||
packer.add_string(config.sv_name, 128);
|
||||
packer.add_string(map_name, 128);
|
||||
packer.add_string(config.sv_map, 128);
|
||||
packer.add_int(MAX_CLIENTS); // max_players
|
||||
int c = 0;
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
|
@ -537,7 +652,8 @@ public:
|
|||
else if(packet.data_size == sizeof(SERVERBROWSE_FWOK) &&
|
||||
memcmp(packet.data, SERVERBROWSE_FWOK, sizeof(SERVERBROWSE_FWOK)) == 0)
|
||||
{
|
||||
dbg_msg("server", "no firewall/nat problems detected");
|
||||
if(config.debug)
|
||||
dbg_msg("server", "no firewall/nat problems detected");
|
||||
}
|
||||
else if(packet.data_size == sizeof(SERVERBROWSE_FWERROR) &&
|
||||
memcmp(packet.data, SERVERBROWSE_FWERROR, sizeof(SERVERBROWSE_FWERROR)) == 0)
|
||||
|
@ -549,35 +665,6 @@ public:
|
|||
else
|
||||
process_client_packet(&packet);
|
||||
}
|
||||
|
||||
// check for removed clients
|
||||
while(1)
|
||||
{
|
||||
int cid = net.delclient();
|
||||
if(cid == -1)
|
||||
break;
|
||||
|
||||
clients[cid].state = client::STATE_EMPTY;
|
||||
clients[cid].name[0] = 0;
|
||||
clients[cid].clan[0] = 0;
|
||||
clients[cid].snapshots.purge_all();
|
||||
|
||||
mods_client_drop(cid);
|
||||
}
|
||||
|
||||
// check for new clients
|
||||
while(1)
|
||||
{
|
||||
int cid = net.newclient();
|
||||
if(cid == -1)
|
||||
break;
|
||||
|
||||
clients[cid].state = client::STATE_CONNECTING;
|
||||
clients[cid].name[0] = 0;
|
||||
clients[cid].clan[0] = 0;
|
||||
clients[cid].snapshots.purge_all();
|
||||
clients[cid].last_acked_snapshot = -1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -586,50 +673,30 @@ int main(int argc, char **argv)
|
|||
dbg_msg("server", "starting...");
|
||||
|
||||
config_reset();
|
||||
|
||||
#ifdef CONF_PLATFORM_MACOSX
|
||||
config_load("~/.teewars");
|
||||
const char *config_filename = "~/.teewars";
|
||||
#else
|
||||
config_load("default.cfg");
|
||||
const char *config_filename = "default.cfg";
|
||||
#endif
|
||||
|
||||
const char *mapname = "dm1";
|
||||
|
||||
// parse arguments
|
||||
for(int i = 1; i < argc; i++)
|
||||
{
|
||||
if(argv[i][0] == '-' && argv[i][1] == 'm' && argv[i][2] == 0 && argc - i > 1)
|
||||
if(argv[i][0] == '-' && argv[i][1] == 'f' && argv[i][2] == 0 && argc - i > 1)
|
||||
{
|
||||
// -m map
|
||||
config_filename = argv[i+1];
|
||||
i++;
|
||||
mapname = argv[i];
|
||||
}
|
||||
else if(argv[i][0] == '-' && argv[i][1] == 'n' && argv[i][2] == 0 && argc - i > 1)
|
||||
{
|
||||
// -n server name
|
||||
i++;
|
||||
config_set_sv_name(&config, argv[i]);
|
||||
}
|
||||
else if(argv[i][0] == '-' && argv[i][1] == 'p' && argv[i][2] == 0)
|
||||
{
|
||||
// -p (private server)
|
||||
config_set_sv_sendheartbeats(&config, 0);
|
||||
}
|
||||
else if(argv[i][0] == '-' && argv[i][1] == 'o' && argv[i][2] == 0)
|
||||
{
|
||||
// -o port
|
||||
i++;
|
||||
config_set_sv_port(&config, atol(argv[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if(!mapname)
|
||||
{
|
||||
dbg_msg("server", "no map given (-m MAPNAME)");
|
||||
return 0;
|
||||
}
|
||||
config_load(config_filename);
|
||||
|
||||
// parse arguments
|
||||
for(int i = 1; i < argc; i++)
|
||||
config_set(argv[i]);
|
||||
|
||||
server_init();
|
||||
server s;
|
||||
s.run(mapname);
|
||||
s.run();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,19 @@ int snapshot_crc(snapshot *snap)
|
|||
return crc;
|
||||
}
|
||||
|
||||
void snapshot_debug_dump(snapshot *snap)
|
||||
{
|
||||
dbg_msg("snapshot", "data_size=%d num_items=%d", snap->data_size, snap->num_items);
|
||||
for(int i = 0; i < snap->num_items; i++)
|
||||
{
|
||||
snapshot::item *item = snap->get_item(i);
|
||||
int size = snap->get_item_datasize(i);
|
||||
dbg_msg("snapshot", "\ttype=%d id=%d", item->type(), item->id());
|
||||
for(int b = 0; b < size/4; b++)
|
||||
dbg_msg("snapshot", "\t\t%3d %12d\t%08x", b, item->data()[b], item->data()[b]);
|
||||
}
|
||||
}
|
||||
|
||||
static int diff_item(int *past, int *current, int *out, int size)
|
||||
{
|
||||
/*
|
||||
|
|
|
@ -42,6 +42,7 @@ struct snapshot
|
|||
|
||||
void *snapshot_empty_delta();
|
||||
int snapshot_crc(snapshot *snap);
|
||||
void snapshot_debug_dump(snapshot *snap);
|
||||
int snapshot_create_delta(snapshot *from, snapshot *to, void *data);
|
||||
int snapshot_unpack_delta(snapshot *from, snapshot *to, void *data, int data_size);
|
||||
|
||||
|
|
|
@ -61,10 +61,10 @@ void snd_play_random(int setid, float vol, float pan)
|
|||
}
|
||||
|
||||
// sound volume tweak
|
||||
static const float stereo_separation = 0.01f;
|
||||
static const float stereo_separation_deadzone = 512.0f;
|
||||
static const float volume_distance_falloff = 100.0f;
|
||||
static const float volume_distance_deadzone = 512.0f;
|
||||
static const float stereo_separation = 0.001f;
|
||||
static const float stereo_separation_deadzone = 200.0f;
|
||||
static const float volume_distance_falloff = 200.0f;
|
||||
static const float volume_distance_deadzone = 320.0f;
|
||||
static const float volume_gun = 0.5f;
|
||||
static const float volume_tee = 0.5f;
|
||||
static const float volume_hit = 0.5f;
|
||||
|
@ -434,16 +434,59 @@ static int killmsg_current = 0;
|
|||
|
||||
extern unsigned char internal_data[];
|
||||
|
||||
|
||||
extern void draw_round_rect(float x, float y, float w, float h, float r);
|
||||
extern int render_popup(const char *caption, const char *text, const char *button_text);
|
||||
|
||||
static void render_loading(float percent)
|
||||
{
|
||||
gfx_clear(0.65f,0.78f,0.9f);
|
||||
gfx_mapscreen(0,0,800.0f,600.0f);
|
||||
|
||||
float tw;
|
||||
|
||||
float w = 700;
|
||||
float h = 200;
|
||||
float x = 800/2-w/2;
|
||||
float y = 600/2-h/2;
|
||||
|
||||
gfx_blend_normal();
|
||||
|
||||
gfx_texture_set(-1);
|
||||
gfx_quads_begin();
|
||||
gfx_quads_setcolor(0,0,0,0.50f);
|
||||
draw_round_rect(x, y, w, h, 40.0f);
|
||||
gfx_quads_end();
|
||||
|
||||
const char *caption = "Loading";
|
||||
|
||||
tw = gfx_pretty_text_width(48.0f, caption);
|
||||
ui_do_label(x+w/2-tw/2, y+20, caption, 48.0f);
|
||||
|
||||
gfx_texture_set(-1);
|
||||
gfx_quads_begin();
|
||||
gfx_quads_setcolor(1,1,1,1.0f);
|
||||
draw_round_rect(x+40, y+h-75, (w-80)*percent, 25, 5.0f);
|
||||
gfx_quads_end();
|
||||
|
||||
gfx_swap();
|
||||
}
|
||||
|
||||
void modc_init()
|
||||
{
|
||||
// load the data container
|
||||
data = load_data_from_memory(internal_data);
|
||||
|
||||
// TODO: should be removed
|
||||
music_menu = snd_load_wav("data/audio/menu_music.wav");
|
||||
music_menu = snd_load_wav("data/audio/music_menu.wav");
|
||||
|
||||
float total = data->num_sounds+data->num_images;
|
||||
float current = 0;
|
||||
|
||||
// load sounds
|
||||
for(int s = 0; s < data->num_sounds; s++)
|
||||
{
|
||||
render_loading(current/total);
|
||||
for(int i = 0; i < data->sounds[s].num_sounds; i++)
|
||||
{
|
||||
int id;
|
||||
|
@ -454,10 +497,17 @@ void modc_init()
|
|||
|
||||
data->sounds[s].sounds[i].id = id;
|
||||
}
|
||||
|
||||
current++;
|
||||
}
|
||||
|
||||
// load textures
|
||||
for(int i = 0; i < data->num_images; i++)
|
||||
{
|
||||
render_loading(current/total);
|
||||
data->images[i].id = gfx_load_texture(data->images[i].filename);
|
||||
current++;
|
||||
}
|
||||
}
|
||||
|
||||
void modc_entergame()
|
||||
|
@ -483,13 +533,15 @@ void modc_shutdown()
|
|||
{
|
||||
}
|
||||
|
||||
void modc_newsnapshot()
|
||||
static bool must_process_events = false;
|
||||
|
||||
static void process_events(int s)
|
||||
{
|
||||
int num = snap_num_items(SNAP_CURRENT);
|
||||
int num = snap_num_items(s);
|
||||
for(int i = 0; i < num; i++)
|
||||
{
|
||||
snap_item item;
|
||||
const void *data = snap_get_item(SNAP_CURRENT, i, &item);
|
||||
const void *data = snap_get_item(s, i, &item);
|
||||
|
||||
if(item.type == EVENT_DAMAGEINDICATION)
|
||||
{
|
||||
|
@ -618,6 +670,26 @@ void modc_newsnapshot()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
must_process_events = false;
|
||||
}
|
||||
|
||||
void modc_newsnapshot()
|
||||
{
|
||||
if(must_process_events)
|
||||
process_events(SNAP_PREV);
|
||||
must_process_events = true;
|
||||
|
||||
if(config.stress)
|
||||
{
|
||||
if((client_tick()%250) == 0)
|
||||
{
|
||||
msg_pack_start(MSG_SAY, MSGFLAG_VITAL);
|
||||
msg_pack_string("galenskap!!!!", 512);
|
||||
msg_pack_end();
|
||||
client_send_msg();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void render_projectile(const obj_projectile *prev, const obj_projectile *current, int itemid)
|
||||
|
@ -883,7 +955,7 @@ static void render_tee(animstate *anim, int skin, int emote, vec2 dir, vec2 pos)
|
|||
select_sprite(SPRITE_TEE_EYE_NORMAL, 0, 0, shift*4);
|
||||
break;
|
||||
}
|
||||
int h = emote == EMOTE_BLINK ? basesize/3 : basesize;
|
||||
int h = emote == EMOTE_BLINK ? (int)(basesize/3) : (int)(basesize);
|
||||
gfx_quads_draw(position.x-4+direction.x*4, position.y-8+direction.y*3, basesize, h);
|
||||
gfx_quads_draw(position.x+4+direction.x*4, position.y-8+direction.y*3, -basesize, h);
|
||||
}
|
||||
|
@ -956,6 +1028,7 @@ static void render_player(const obj_player *prev, const obj_player *player)
|
|||
{
|
||||
if(player->health < 0) // dont render dead players
|
||||
return;
|
||||
|
||||
int skin = gametype == GAMETYPE_TDM ? skinseed + player->team : player->clientid;
|
||||
|
||||
vec2 direction = get_direction(player->angle);
|
||||
|
@ -1248,7 +1321,7 @@ void render_game()
|
|||
int c = input::last_char(); // TODO: bypasses the engine interface
|
||||
int k = input::last_key(); // TODO: bypasses the engine interface
|
||||
|
||||
if (c >= 32 && c < 255)
|
||||
if (!(c >= 0 && c < 32))
|
||||
{
|
||||
if (chat_input_len < sizeof(chat_input) - 1)
|
||||
{
|
||||
|
@ -1291,13 +1364,9 @@ void render_game()
|
|||
{
|
||||
player_input input;
|
||||
mem_zero(&input, sizeof(input));
|
||||
|
||||
float a = atan((float)mouse_pos.y/(float)mouse_pos.x);
|
||||
if(mouse_pos.x < 0)
|
||||
a = a+pi;
|
||||
|
||||
input.target_x = (int)mouse_pos.x; //(int)(a*256.0f);
|
||||
input.target_y = (int)mouse_pos.y; //(int)(a*256.0f);
|
||||
input.target_x = (int)mouse_pos.x;
|
||||
input.target_y = (int)mouse_pos.y;
|
||||
input.activeweapon = -1;
|
||||
|
||||
if(chat_active)
|
||||
|
@ -1313,25 +1382,30 @@ void render_game()
|
|||
input.fire = inp_key_pressed(config.key_fire);
|
||||
input.hook = inp_key_pressed(config.key_hook);
|
||||
|
||||
input.blink = inp_key_pressed('S');
|
||||
|
||||
//input.blink = inp_key_pressed('S');
|
||||
// Weapon switching
|
||||
#define TEST_WEAPON_KEY(key) if (inp_key_pressed(config.key_weapon ## key)) input.activeweapon = key-1;
|
||||
if(config.scroll_weapon)
|
||||
{
|
||||
int delta = inp_mouse_scroll();
|
||||
input.activeweapon = input.activeweapon + delta;
|
||||
|
||||
if(input.activeweapon > 3)
|
||||
input.activeweapon = 3;
|
||||
else if(input.activeweapon < 0)
|
||||
input.activeweapon = 0;
|
||||
}
|
||||
|
||||
TEST_WEAPON_KEY(1);
|
||||
TEST_WEAPON_KEY(2);
|
||||
TEST_WEAPON_KEY(3);
|
||||
TEST_WEAPON_KEY(4);
|
||||
if(inp_key_pressed(config.key_weapon1)) input.activeweapon = 0;
|
||||
if(inp_key_pressed(config.key_weapon2)) input.activeweapon = 1;
|
||||
if(inp_key_pressed(config.key_weapon3)) input.activeweapon = 2;
|
||||
if(inp_key_pressed(config.key_weapon4)) input.activeweapon = 3;
|
||||
}
|
||||
|
||||
// stress testing
|
||||
if(config.stress)
|
||||
{
|
||||
float t = client_localtime();
|
||||
mem_zero(&input, sizeof(input));
|
||||
input.left = 1;
|
||||
input.jump = ((int)t)&1;
|
||||
input.fire = ((int)(t*10))&1;
|
||||
input.hook = ((int)t)&1;
|
||||
input.activeweapon = ((int)t)%NUM_WEAPONS;
|
||||
input.target_x = (int)(sinf(t*3)*100.0f);
|
||||
input.target_y = (int)(cosf(t*3)*100.0f);
|
||||
|
||||
//input.target_x = (int)((rand()/(float)RAND_MAX)*64-32);
|
||||
//input.target_y = (int)((rand()/(float)RAND_MAX)*64-32);
|
||||
|
||||
}
|
||||
|
||||
snap_input(&input, sizeof(input));
|
||||
|
@ -1365,6 +1439,10 @@ void render_game()
|
|||
gameobj = (obj_game *)data;
|
||||
}
|
||||
}
|
||||
|
||||
// everything updated, do events
|
||||
if(must_process_events)
|
||||
process_events(SNAP_PREV);
|
||||
|
||||
// pseudo format
|
||||
float zoom = 3.0f;
|
||||
|
@ -1413,7 +1491,7 @@ void render_game()
|
|||
{
|
||||
float parallax_amount = 0.55f;
|
||||
select_sprite(cloud_sprites[i]);
|
||||
draw_sprite((cloud_pos[i].x+fmod(client_localtime()*cloud_speed[i]+i*100.0f, 1700.0f))+screen_x*parallax_amount,
|
||||
draw_sprite((cloud_pos[i].x+fmod(client_localtime()*cloud_speed[i]+i*100.0f, 3000.0f))+screen_x*parallax_amount,
|
||||
cloud_pos[i].y+screen_y*parallax_amount, 300);
|
||||
}
|
||||
gfx_quads_end();
|
||||
|
@ -1707,7 +1785,7 @@ void render_game()
|
|||
// sort players
|
||||
for(int k = 0; k < num_players; k++) // ffs, bubblesort
|
||||
{
|
||||
for(int i = k; i < num_players-1; i++)
|
||||
for(int i = 0; i < num_players-k-1; i++)
|
||||
{
|
||||
if(players[i]->score < players[i+1]->score)
|
||||
{
|
||||
|
|
|
@ -414,7 +414,7 @@ int ui_do_edit_box(void *id, float x, float y, float w, float h, char *str, int
|
|||
if (at_index > len)
|
||||
at_index = len;
|
||||
|
||||
if (c >= 32 && c < 128)
|
||||
if (!(c >= 0 && c < 32))
|
||||
{
|
||||
if (len < str_size - 1 && at_index < str_size - 1)
|
||||
{
|
||||
|
@ -673,7 +673,7 @@ static int do_server_list(float x, float y, int *scroll_index, int *selected_ind
|
|||
}
|
||||
|
||||
*scroll_index = do_scroll_bar_vert(scroll_index, x + real_width - 16, y, real_height,
|
||||
min(num_servers - visible_items, 0), *scroll_index);
|
||||
max(num_servers - visible_items, 0), *scroll_index);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -837,8 +837,11 @@ static int settings_controls_render()
|
|||
static const int MAX_RESOLUTIONS = 128;
|
||||
static int settings_video_render_select_mode()
|
||||
{
|
||||
video_mode modes[MAX_RESOLUTIONS];
|
||||
int num_modes = gfx_get_video_modes(modes, MAX_RESOLUTIONS);
|
||||
static video_mode modes[MAX_RESOLUTIONS];
|
||||
static int num_modes = -1;
|
||||
|
||||
if(num_modes == -1)
|
||||
num_modes = gfx_get_video_modes(modes, MAX_RESOLUTIONS);
|
||||
|
||||
static int scroll_index = 0;
|
||||
scroll_index = do_scroll_bar_vert(&scroll_index, 500, row1_y, 40 * 7, num_modes - 7, scroll_index);
|
||||
|
@ -1033,10 +1036,10 @@ static int settings_render(bool ingame)
|
|||
extern int gametype;
|
||||
static int ingame_main_render()
|
||||
{
|
||||
static int menu_resume, menu_active, menu_quit, menu_settings;
|
||||
char buf[128];
|
||||
static int menu_resume, menu_quit, menu_settings;
|
||||
/*if (gametype == GAMETYPE_TDM)
|
||||
{
|
||||
char buf[128];
|
||||
// Switch team
|
||||
ui_do_label(100,100,"Switch Team",40);
|
||||
sprintf(buf,"Team: %s",local_player->team ? "A" : "B");
|
||||
|
@ -1255,7 +1258,7 @@ static int kerning_render()
|
|||
}
|
||||
|
||||
|
||||
static int render_popup(const char *caption, const char *text, const char *button_text)
|
||||
int render_popup(const char *caption, const char *text, const char *button_text)
|
||||
{
|
||||
float tw;
|
||||
|
||||
|
@ -1278,9 +1281,14 @@ static int render_popup(const char *caption, const char *text, const char *butto
|
|||
tw = gfx_pretty_text_width(32.0f, text);
|
||||
ui_do_label(x+w/2-tw/2, y+130, text, 32.0f);
|
||||
|
||||
static int back_button = 0;
|
||||
if(ui_do_button(&back_button, button_text, 0, x+w/2-100, y+220, 200, 48, draw_teewars_button))
|
||||
return 1;
|
||||
if(button_text)
|
||||
{
|
||||
static int back_button = 0;
|
||||
if(ui_do_button(&back_button, button_text, 0, x+w/2-100, y+220, 200, 48, draw_teewars_button))
|
||||
return 1;
|
||||
if(inp_key_down(input::esc) || inp_key_down(input::enter))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -175,6 +175,11 @@ event_handler::event_handler()
|
|||
|
||||
void *event_handler::create(int type, int size, int target)
|
||||
{
|
||||
if(num_events == MAX_EVENTS)
|
||||
return 0;
|
||||
if(current_offset+size >= MAX_DATASIZE)
|
||||
return 0;
|
||||
|
||||
void *p = &data[current_offset];
|
||||
offsets[num_events] = current_offset;
|
||||
types[num_events] = type;
|
||||
|
@ -215,8 +220,7 @@ entity::entity(int objtype)
|
|||
flags = FLAG_ALIVE;
|
||||
proximity_radius = 0;
|
||||
|
||||
current_id++;
|
||||
id = current_id;
|
||||
id = snap_new_id();
|
||||
|
||||
next_entity = 0;
|
||||
prev_entity = 0;
|
||||
|
@ -226,10 +230,9 @@ entity::entity(int objtype)
|
|||
|
||||
entity::~entity()
|
||||
{
|
||||
snap_free_id(id);
|
||||
}
|
||||
|
||||
int entity::current_id = 1;
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// game world
|
||||
//////////////////////////////////////////////////
|
||||
|
@ -538,7 +541,7 @@ void gameobject::tick()
|
|||
|
||||
void gameobject::snap(int snapping_client)
|
||||
{
|
||||
obj_game *game = (obj_game *)snap_new_item(OBJTYPE_GAME, id, sizeof(obj_game));
|
||||
obj_game *game = (obj_game *)snap_new_item(OBJTYPE_GAME, 0, sizeof(obj_game));
|
||||
game->paused = world.paused;
|
||||
game->game_over = game_over_tick==-1?0:1;
|
||||
game->sudden_death = sudden_death;
|
||||
|
@ -563,7 +566,7 @@ int gameobject::getteam(int notthisid)
|
|||
return numplayers[0] > numplayers[1] ? 1 : 0;
|
||||
}
|
||||
|
||||
gameobject gameobj;
|
||||
gameobject *gameobj = 0;
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// projectile
|
||||
|
@ -733,6 +736,15 @@ void player::init()
|
|||
team = 0;
|
||||
extrapowerflags = 0;
|
||||
ninjaactivationtick = 0;
|
||||
|
||||
|
||||
latency_accum = 0;
|
||||
latency_accum_min = 0;
|
||||
latency_accum_max = 0;
|
||||
latency_avg = 0;
|
||||
latency_min = 0;
|
||||
latency_max = 0;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
|
@ -750,10 +762,25 @@ void player::reset()
|
|||
die_tick = 0;
|
||||
damage_taken = 0;
|
||||
state = STATE_UNKNOWN;
|
||||
|
||||
mem_zero(&input, sizeof(input));
|
||||
mem_zero(&previnput, sizeof(previnput));
|
||||
|
||||
last_action = -1;
|
||||
|
||||
emote_stop = 0;
|
||||
damage_taken_tick = 0;
|
||||
attack_tick = 0;
|
||||
}
|
||||
|
||||
void player::destroy() { }
|
||||
|
||||
void player::set_weapon(int w)
|
||||
{
|
||||
last_weapon = active_weapon;
|
||||
active_weapon = w;
|
||||
}
|
||||
|
||||
|
||||
void player::respawn()
|
||||
{
|
||||
|
@ -788,7 +815,7 @@ void player::try_respawn()
|
|||
defered_pos = pos;
|
||||
|
||||
|
||||
health = data->playerinfo[gameobj.gametype].maxhealth;
|
||||
health = data->playerinfo[gameobj->gametype].maxhealth;
|
||||
armor = 0;
|
||||
jumped = 0;
|
||||
dead = false;
|
||||
|
@ -803,9 +830,11 @@ void player::try_respawn()
|
|||
weapons[WEAPON_HAMMER].got = true;
|
||||
weapons[WEAPON_HAMMER].ammo = -1;
|
||||
weapons[WEAPON_GUN].got = true;
|
||||
weapons[WEAPON_GUN].ammo = data->weapons[active_weapon].maxammo;
|
||||
weapons[WEAPON_GUN].ammo = data->weapons[WEAPON_GUN].maxammo;
|
||||
|
||||
active_weapon = WEAPON_GUN;
|
||||
last_weapon = WEAPON_HAMMER;
|
||||
|
||||
reload_timer = 0;
|
||||
|
||||
// Create sound and spawn effects
|
||||
|
@ -849,7 +878,7 @@ int player::handle_ninja()
|
|||
if ((server_tick() - ninjaactivationtick) > (data->weapons[WEAPON_NINJA].duration * server_tickspeed() / 1000))
|
||||
{
|
||||
// time's up, return
|
||||
active_weapon = WEAPON_GUN;
|
||||
active_weapon = last_weapon;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -935,6 +964,18 @@ int player::handle_ninja()
|
|||
|
||||
int player::handle_weapons()
|
||||
{
|
||||
if(config.stress)
|
||||
{
|
||||
for(int i = 0; i < NUM_WEAPONS; i++)
|
||||
{
|
||||
weapons[i].got = true;
|
||||
weapons[i].ammo = 10;
|
||||
}
|
||||
|
||||
if(reload_timer) // twice as fast reload
|
||||
reload_timer--;
|
||||
}
|
||||
|
||||
// check reload timer
|
||||
if(reload_timer)
|
||||
{
|
||||
|
@ -954,8 +995,8 @@ int player::handle_weapons()
|
|||
if (active_weapon != input.activeweapon)
|
||||
create_sound(pos, SOUND_WEAPON_SWITCH);
|
||||
|
||||
last_weapon = active_weapon;
|
||||
active_weapon = input.activeweapon;
|
||||
|
||||
}
|
||||
|
||||
if(!previnput.fire && input.fire)
|
||||
|
@ -1342,6 +1383,8 @@ void player::tick_defered()
|
|||
|
||||
void player::die(int killer, int weapon)
|
||||
{
|
||||
dbg_msg("game", "kill killer='%d:%s' victim='%d:%s' weapon=%d", killer, players[killer].name, client_id, name, weapon);
|
||||
|
||||
// send the kill message
|
||||
msg_pack_start(MSG_KILLMSG, MSGFLAG_VITAL);
|
||||
msg_pack_int(killer);
|
||||
|
@ -1372,7 +1415,7 @@ bool player::take_damage(vec2 force, int dmg, int from, int weapon)
|
|||
if(from == client_id)
|
||||
dmg = max(1, dmg/2);
|
||||
|
||||
if (gameobj.gametype == GAMETYPE_TDM && from >= 0 && players[from].team == team)
|
||||
if (gameobj->gametype == GAMETYPE_TDM && from >= 0 && players[from].team == team)
|
||||
return false;
|
||||
|
||||
damage_taken++;
|
||||
|
@ -1505,7 +1548,12 @@ void player::snap(int snaping_client)
|
|||
player->hook_x = (int)hook_pos.x;
|
||||
player->hook_y = (int)hook_pos.y;
|
||||
|
||||
float a = atan((float)input.target_y/(float)input.target_x);
|
||||
float a = 0;
|
||||
if(input.target_x == 0)
|
||||
a = atan((float)input.target_y);
|
||||
else
|
||||
a = atan((float)input.target_y/(float)input.target_x);
|
||||
|
||||
if(input.target_x < 0)
|
||||
a = a+pi;
|
||||
|
||||
|
@ -1517,7 +1565,7 @@ void player::snap(int snaping_client)
|
|||
player->state = state;
|
||||
}
|
||||
|
||||
player players[MAX_CLIENTS];
|
||||
player *players;
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// powerup
|
||||
|
@ -1569,18 +1617,18 @@ void powerup::tick()
|
|||
switch (type)
|
||||
{
|
||||
case POWERUP_HEALTH:
|
||||
if(pplayer->health < data->playerinfo[gameobj.gametype].maxhealth)
|
||||
if(pplayer->health < data->playerinfo[gameobj->gametype].maxhealth)
|
||||
{
|
||||
create_sound(pos, SOUND_PICKUP_HEALTH, 0);
|
||||
pplayer->health = min((int)data->playerinfo[gameobj.gametype].maxhealth, pplayer->health + data->powerupinfo[type].amount);
|
||||
pplayer->health = min((int)data->playerinfo[gameobj->gametype].maxhealth, pplayer->health + data->powerupinfo[type].amount);
|
||||
respawntime = data->powerupinfo[type].respawntime;
|
||||
}
|
||||
break;
|
||||
case POWERUP_ARMOR:
|
||||
if(pplayer->armor < data->playerinfo[gameobj.gametype].maxarmor)
|
||||
if(pplayer->armor < data->playerinfo[gameobj->gametype].maxarmor)
|
||||
{
|
||||
create_sound(pos, SOUND_PICKUP_ARMOR, 0);
|
||||
pplayer->armor = min((int)data->playerinfo[gameobj.gametype].maxarmor, pplayer->armor + data->powerupinfo[type].amount);
|
||||
pplayer->armor = min((int)data->playerinfo[gameobj->gametype].maxarmor, pplayer->armor + data->powerupinfo[type].amount);
|
||||
respawntime = data->powerupinfo[type].respawntime;
|
||||
}
|
||||
break;
|
||||
|
@ -1607,6 +1655,7 @@ void powerup::tick()
|
|||
// activate ninja on target player
|
||||
pplayer->ninjaactivationtick = server_tick();
|
||||
pplayer->weapons[WEAPON_NINJA].got = true;
|
||||
pplayer->last_weapon = pplayer->active_weapon;
|
||||
pplayer->active_weapon = WEAPON_NINJA;
|
||||
respawntime = data->powerupinfo[type].respawntime;
|
||||
create_sound(pos, SOUND_PICKUP_NINJA);
|
||||
|
@ -1635,7 +1684,10 @@ void powerup::tick()
|
|||
};
|
||||
|
||||
if(respawntime >= 0)
|
||||
{
|
||||
dbg_msg("game", "pickup player='%d:%s' item=%d/%d", pplayer->client_id, pplayer->name, type, subtype);
|
||||
spawntick = server_tick() + server_tickspeed() * respawntime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1757,9 +1809,12 @@ void create_damageind(vec2 p, float angle, int amount)
|
|||
{
|
||||
float f = mix(s, e, float(i+1)/float(amount+2));
|
||||
ev_damageind *ev = (ev_damageind *)events.create(EVENT_DAMAGEINDICATION, sizeof(ev_damageind));
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
ev->angle = (int)(f*256.0f);
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
ev->angle = (int)(f*256.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1767,8 +1822,11 @@ void create_explosion(vec2 p, int owner, int weapon, bool bnodamage)
|
|||
{
|
||||
// create the event
|
||||
ev_explosion *ev = (ev_explosion *)events.create(EVENT_EXPLOSION, sizeof(ev_explosion));
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
}
|
||||
|
||||
if (!bnodamage)
|
||||
{
|
||||
|
@ -1796,24 +1854,33 @@ void create_smoke(vec2 p)
|
|||
{
|
||||
// create the event
|
||||
ev_explosion *ev = (ev_explosion *)events.create(EVENT_SMOKE, sizeof(ev_explosion));
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
}
|
||||
}
|
||||
|
||||
void create_spawn(vec2 p)
|
||||
{
|
||||
// create the event
|
||||
ev_spawn *ev = (ev_spawn *)events.create(EVENT_SPAWN, sizeof(ev_spawn));
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
}
|
||||
}
|
||||
|
||||
void create_death(vec2 p)
|
||||
{
|
||||
// create the event
|
||||
ev_death *ev = (ev_death *)events.create(EVENT_DEATH, sizeof(ev_death));
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
}
|
||||
}
|
||||
|
||||
void create_targetted_sound(vec2 pos, int sound, int target, int loopingflags)
|
||||
|
@ -1823,9 +1890,12 @@ void create_targetted_sound(vec2 pos, int sound, int target, int loopingflags)
|
|||
|
||||
// create a sound
|
||||
ev_sound *ev = (ev_sound *)events.create(EVENT_SOUND, sizeof(ev_sound), target);
|
||||
ev->x = (int)pos.x;
|
||||
ev->y = (int)pos.y;
|
||||
ev->sound = sound | loopingflags;
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)pos.x;
|
||||
ev->y = (int)pos.y;
|
||||
ev->sound = sound | loopingflags;
|
||||
}
|
||||
}
|
||||
|
||||
void create_sound(vec2 pos, int sound, int loopingflags)
|
||||
|
@ -1864,7 +1934,7 @@ void mods_tick()
|
|||
world.tick();
|
||||
|
||||
if(world.paused) // make sure that the game object always updates
|
||||
gameobj.tick();
|
||||
gameobj->tick();
|
||||
|
||||
if(debug_bots)
|
||||
{
|
||||
|
@ -1905,6 +1975,11 @@ void mods_client_input(int client_id, void *input)
|
|||
|
||||
void send_chat_all(int cid, const char *msg)
|
||||
{
|
||||
if(cid >= 0 && cid < MAX_CLIENTS)
|
||||
dbg_msg("chat", "%d:%s: %s", cid, players[cid].name, msg);
|
||||
else
|
||||
dbg_msg("chat", "*** %s", msg);
|
||||
|
||||
msg_pack_start(MSG_CHAT, MSGFLAG_VITAL);
|
||||
msg_pack_int(cid);
|
||||
msg_pack_string(msg, 512);
|
||||
|
@ -1928,10 +2003,13 @@ void mods_client_enter(int client_id)
|
|||
else
|
||||
strcpy(players[client_id].name, "(bot)");
|
||||
|
||||
if (gameobj.gametype == GAMETYPE_TDM)
|
||||
|
||||
dbg_msg("game", "join player='%d:%s'", client_id, players[client_id].name);
|
||||
|
||||
if (gameobj->gametype == GAMETYPE_TDM)
|
||||
{
|
||||
// Check which team the player should be on
|
||||
players[client_id].team = gameobj.getteam(client_id);
|
||||
players[client_id].team = gameobj->getteam(client_id);
|
||||
}
|
||||
|
||||
msg_pack_start(MSG_SETNAME, MSGFLAG_VITAL);
|
||||
|
@ -1962,8 +2040,9 @@ void mods_client_drop(int client_id)
|
|||
char buf[512];
|
||||
sprintf(buf, "%s has left the game", players[client_id].name);
|
||||
send_chat_all(-1, buf);
|
||||
|
||||
dbg_msg("game", "leave player='%d:%s'", client_id, players[client_id].name);
|
||||
|
||||
dbg_msg("mods", "client drop %d", client_id);
|
||||
world.remove_entity(&players[client_id]);
|
||||
players[client_id].client_id = -1;
|
||||
}
|
||||
|
@ -1990,6 +2069,9 @@ void mods_init()
|
|||
data = load_data_from_memory(internal_data);
|
||||
col_init(32);
|
||||
|
||||
players = new player[MAX_CLIENTS];
|
||||
gameobj = new gameobject;
|
||||
|
||||
int start, num;
|
||||
map_get_type(MAPRES_ITEM, &start, &num);
|
||||
|
||||
|
@ -1999,7 +2081,7 @@ void mods_init()
|
|||
mapres_item *it = (mapres_item *)map_get_item(start+i, 0, 0);
|
||||
|
||||
int type = -1;
|
||||
int subtype = -1;
|
||||
int subtype = 0;
|
||||
|
||||
switch(it->type)
|
||||
{
|
||||
|
@ -2043,7 +2125,7 @@ void mods_init()
|
|||
}
|
||||
}
|
||||
|
||||
world.insert_entity(&gameobj);
|
||||
world.insert_entity(gameobj);
|
||||
}
|
||||
|
||||
void mods_shutdown() {}
|
||||
|
|
|
@ -35,7 +35,6 @@ private:
|
|||
entity *next_type_entity;
|
||||
|
||||
int index;
|
||||
static int current_id;
|
||||
protected:
|
||||
int id;
|
||||
|
||||
|
@ -123,7 +122,7 @@ public:
|
|||
virtual int getteam(int notthisid);
|
||||
};
|
||||
|
||||
extern gameobject gameobj;
|
||||
extern gameobject *gameobj;
|
||||
|
||||
|
||||
// TODO: move to seperate file
|
||||
|
@ -214,6 +213,7 @@ public:
|
|||
bool got;
|
||||
} weapons[NUM_WEAPONS];
|
||||
int active_weapon;
|
||||
int last_weapon;
|
||||
int reload_timer;
|
||||
int attack_tick;
|
||||
|
||||
|
@ -291,6 +291,8 @@ public:
|
|||
void respawn();
|
||||
|
||||
bool is_grounded();
|
||||
|
||||
void set_weapon(int w);
|
||||
|
||||
void release_hooked();
|
||||
void release_hooks();
|
||||
|
@ -307,7 +309,7 @@ public:
|
|||
virtual void snap(int snaping_client);
|
||||
};
|
||||
|
||||
extern player players[MAX_CLIENTS];
|
||||
extern player *players;
|
||||
|
||||
// TODO: move to seperate file
|
||||
class flag : public entity
|
||||
|
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 93 KiB |
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 88 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 76 KiB |