mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
added chat, better damage indicators
This commit is contained in:
parent
7acef9eb86
commit
568b9f1f4a
Binary file not shown.
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 23 KiB |
|
@ -252,9 +252,6 @@ sprites {
|
|||
part7 4 2 2 2
|
||||
part8 6 2 2 2
|
||||
part9 8 2 2 2
|
||||
|
||||
star1 0 0 2 2
|
||||
star2 0 2 2 2
|
||||
}
|
||||
|
||||
hud images.game 32 16 {
|
||||
|
@ -262,6 +259,9 @@ sprites {
|
|||
health_empty 5 0 4 4
|
||||
armor_full 0 5 4 4
|
||||
armor_empty 5 5 4 4
|
||||
star1 0 10 3 3
|
||||
star2 3 10 3 3
|
||||
star3 6 10 3 3
|
||||
}
|
||||
|
||||
weapons images.weapons 32 32 {
|
||||
|
|
|
@ -6,30 +6,38 @@ Group: 0.1.1 - Awesome Alpha Bug Fixed (NEXT)
|
|||
DONE * Bobbing powerups
|
||||
DONE * Get -c working under windows
|
||||
DONE * Bigger powerups
|
||||
* Pickup sounds
|
||||
* FAQ on the webpage
|
||||
DONE * Private server (no heartbeats)
|
||||
DONE * Can't pickup ammo, health or armor when not needed
|
||||
DONE * Fix so that the homepage is in the SVN
|
||||
|
||||
Group: 0.2.x -
|
||||
* Cleanup: SVN
|
||||
* Cleanup: client.cpp / server.cpp
|
||||
* Cleanup: game_client.cpp / game_server.cpp
|
||||
* Cleanup: editor.cpp
|
||||
|
||||
* Web: FAQ on the webpage
|
||||
* Game: Events for kills and such
|
||||
* Game: Pickup sounds
|
||||
* Game: Add the sounds
|
||||
* Game: Fix the hammer again
|
||||
* Game: Tweak graphics
|
||||
|
||||
* Client: More robust and smoother handling of snapshots
|
||||
* Need to add some smoothed timer or something
|
||||
|
||||
* Masterserver: Master server should only hold ips. Clients should ask servers for more info + ping
|
||||
* Masterserver: NAT/FW detection
|
||||
* Game: Respawn time
|
||||
* Game: Chat
|
||||
* Game: Bigger and better scoreboard
|
||||
* Game: Events for kills and such
|
||||
DONE * Client: Only send input when needed
|
||||
* Client: Should timeout from server
|
||||
* Client: More robust and smoother handling of snapshots
|
||||
* Client: Some sort of settings format (think KISS).
|
||||
* Server: LAN / Internet / Private servers.
|
||||
* Server: Answer to a getinfo message
|
||||
|
||||
DONE * Game: Chat
|
||||
DONE * Game: Bigger and better scoreboard
|
||||
DONE * Cleanup: SVN
|
||||
DONE * Cleanup: game_client.cpp / game_server.cpp
|
||||
DONE * Game: Respawn time
|
||||
DONE * Client: Only send input when needed
|
||||
DONE * Client: Should timeout from server
|
||||
DONE * Client: Some sort of settings format (think KISS).
|
||||
|
||||
Group: 0.3.0 - Editor Edition
|
||||
* Fix the editor
|
||||
|
||||
|
|
|
@ -194,7 +194,7 @@ public:
|
|||
{
|
||||
recived_snapshots = 0;
|
||||
|
||||
msg_pack_start(NETMSG_INFO, MSGFLAG_VITAL);
|
||||
msg_pack_start_system(NETMSG_INFO, MSGFLAG_VITAL);
|
||||
msg_pack_string(config.player_name, 128);
|
||||
msg_pack_string(config.clan_name, 128);
|
||||
msg_pack_string(config.password, 128);
|
||||
|
@ -205,7 +205,7 @@ public:
|
|||
|
||||
void send_entergame()
|
||||
{
|
||||
msg_pack_start(NETMSG_ENTERGAME, MSGFLAG_VITAL);
|
||||
msg_pack_start_system(NETMSG_ENTERGAME, MSGFLAG_VITAL);
|
||||
msg_pack_end();
|
||||
client_send_msg();
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ public:
|
|||
|
||||
void send_input()
|
||||
{
|
||||
msg_pack_start(NETMSG_INPUT, 0);
|
||||
msg_pack_start_system(NETMSG_INPUT, 0);
|
||||
msg_pack_int(input_data_size);
|
||||
for(int i = 0; i < input_data_size/4; i++)
|
||||
msg_pack_int(input_data[i]);
|
||||
|
@ -462,136 +462,146 @@ public:
|
|||
|
||||
void process_packet(NETPACKET *packet)
|
||||
{
|
||||
int msg = msg_unpack_start(packet->data, packet->data_size);
|
||||
if(msg == NETMSG_MAP)
|
||||
int sys;
|
||||
int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
|
||||
if(sys)
|
||||
{
|
||||
const char *map = msg_unpack_string();
|
||||
dbg_msg("client/network", "connection accepted, map=%s", map);
|
||||
set_state(STATE_LOADING);
|
||||
|
||||
if(map_load(map))
|
||||
// system message
|
||||
if(msg == NETMSG_MAP)
|
||||
{
|
||||
modc_entergame();
|
||||
send_entergame();
|
||||
dbg_msg("client/network", "loading done");
|
||||
// now we will wait for two snapshots
|
||||
// to finish the connection
|
||||
}
|
||||
else
|
||||
{
|
||||
error("failure to load map");
|
||||
}
|
||||
}
|
||||
else if(msg == NETMSG_SNAP || msg == NETMSG_SNAPSMALL || msg == NETMSG_SNAPEMPTY)
|
||||
{
|
||||
//dbg_msg("client/network", "got snapshot");
|
||||
int game_tick = msg_unpack_int();
|
||||
int delta_tick = game_tick-msg_unpack_int();
|
||||
int num_parts = 1;
|
||||
int part = 0;
|
||||
int part_size = 0;
|
||||
const char *map = msg_unpack_string();
|
||||
dbg_msg("client/network", "connection accepted, map=%s", map);
|
||||
set_state(STATE_LOADING);
|
||||
|
||||
if(msg == NETMSG_SNAP)
|
||||
{
|
||||
num_parts = msg_unpack_int();
|
||||
part = msg_unpack_int();
|
||||
}
|
||||
|
||||
if(msg != NETMSG_SNAPEMPTY)
|
||||
part_size = msg_unpack_int();
|
||||
|
||||
if(snapshot_part == part)
|
||||
{
|
||||
// TODO: clean this up abit
|
||||
const char *d = (const char *)msg_unpack_raw(part_size);
|
||||
mem_copy((char*)snapshots[SNAP_INCOMMING] + part*MAX_SNAPSHOT_PACKSIZE, d, part_size);
|
||||
snapshot_part++;
|
||||
|
||||
if(snapshot_part == num_parts)
|
||||
if(map_load(map))
|
||||
{
|
||||
snapshot *tmp = snapshots[SNAP_PREV];
|
||||
snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT];
|
||||
snapshots[SNAP_CURRENT] = tmp;
|
||||
current_tick = game_tick;
|
||||
|
||||
// decompress snapshot
|
||||
void *deltadata = snapshot_empty_delta();
|
||||
int deltasize = sizeof(int)*3;
|
||||
|
||||
unsigned char tmpbuffer[MAX_SNAPSHOT_SIZE];
|
||||
unsigned char tmpbuffer2[MAX_SNAPSHOT_SIZE];
|
||||
if(part_size)
|
||||
{
|
||||
//int snapsize = lzw_decompress(snapshots[SNAP_INCOMMING], snapshots[SNAP_CURRENT]);
|
||||
int compsize = zerobit_decompress(snapshots[SNAP_INCOMMING], part_size, tmpbuffer);
|
||||
//int compsize = lzw_decompress(snapshots[SNAP_INCOMMING],tmpbuffer);
|
||||
int intsize = intpack_decompress(tmpbuffer, compsize, tmpbuffer2);
|
||||
deltadata = tmpbuffer2;
|
||||
deltasize = intsize;
|
||||
}
|
||||
|
||||
// find snapshot that we should use as delta
|
||||
static snapshot emptysnap;
|
||||
emptysnap.data_size = 0;
|
||||
emptysnap.num_items = 0;
|
||||
|
||||
snapshot *deltashot = &emptysnap;
|
||||
int deltashot_size;
|
||||
|
||||
if(delta_tick >= 0)
|
||||
{
|
||||
void *delta_data;
|
||||
deltashot_size = snapshots_new.get(delta_tick, &delta_data);
|
||||
if(deltashot_size >= 0)
|
||||
{
|
||||
deltashot = (snapshot *)delta_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: handle this
|
||||
dbg_msg("client", "error, couldn't find the delta snapshot");
|
||||
}
|
||||
}
|
||||
|
||||
int snapsize = snapshot_unpack_delta(deltashot, (snapshot*)snapshots[SNAP_CURRENT], deltadata, deltasize);
|
||||
//snapshot *shot = (snapshot *)snapshots[SNAP_CURRENT];
|
||||
|
||||
// purge old snapshots
|
||||
snapshots_new.purge_until(delta_tick);
|
||||
snapshots_new.purge_until(game_tick-50); // TODO: change this to server tickrate
|
||||
|
||||
// add new
|
||||
snapshots_new.add(game_tick, snapsize, snapshots[SNAP_CURRENT]);
|
||||
|
||||
// apply snapshot, cycle pointers
|
||||
recived_snapshots++;
|
||||
snapshot_start_time = time_get();
|
||||
|
||||
// we got two snapshots until we see us self as connected
|
||||
if(recived_snapshots == 2)
|
||||
{
|
||||
local_start_time = time_get();
|
||||
set_state(STATE_ONLINE);
|
||||
}
|
||||
|
||||
if(recived_snapshots > 2)
|
||||
modc_newsnapshot();
|
||||
|
||||
snapshot_part = 0;
|
||||
|
||||
// ack snapshot
|
||||
msg_pack_start(NETMSG_SNAPACK, 0);
|
||||
msg_pack_int(game_tick);
|
||||
msg_pack_end();
|
||||
client_send_msg();
|
||||
modc_entergame();
|
||||
send_entergame();
|
||||
dbg_msg("client/network", "loading done");
|
||||
// now we will wait for two snapshots
|
||||
// to finish the connection
|
||||
}
|
||||
else
|
||||
{
|
||||
error("failure to load map");
|
||||
}
|
||||
}
|
||||
else
|
||||
else if(msg == NETMSG_SNAP || msg == NETMSG_SNAPSMALL || msg == NETMSG_SNAPEMPTY)
|
||||
{
|
||||
dbg_msg("client", "snapshot reset!");
|
||||
snapshot_part = 0;
|
||||
//dbg_msg("client/network", "got snapshot");
|
||||
int game_tick = msg_unpack_int();
|
||||
int delta_tick = game_tick-msg_unpack_int();
|
||||
int num_parts = 1;
|
||||
int part = 0;
|
||||
int part_size = 0;
|
||||
|
||||
if(msg == NETMSG_SNAP)
|
||||
{
|
||||
num_parts = msg_unpack_int();
|
||||
part = msg_unpack_int();
|
||||
}
|
||||
|
||||
if(msg != NETMSG_SNAPEMPTY)
|
||||
part_size = msg_unpack_int();
|
||||
|
||||
if(snapshot_part == part)
|
||||
{
|
||||
// TODO: clean this up abit
|
||||
const char *d = (const char *)msg_unpack_raw(part_size);
|
||||
mem_copy((char*)snapshots[SNAP_INCOMMING] + part*MAX_SNAPSHOT_PACKSIZE, d, part_size);
|
||||
snapshot_part++;
|
||||
|
||||
if(snapshot_part == num_parts)
|
||||
{
|
||||
snapshot *tmp = snapshots[SNAP_PREV];
|
||||
snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT];
|
||||
snapshots[SNAP_CURRENT] = tmp;
|
||||
current_tick = game_tick;
|
||||
|
||||
// decompress snapshot
|
||||
void *deltadata = snapshot_empty_delta();
|
||||
int deltasize = sizeof(int)*3;
|
||||
|
||||
unsigned char tmpbuffer[MAX_SNAPSHOT_SIZE];
|
||||
unsigned char tmpbuffer2[MAX_SNAPSHOT_SIZE];
|
||||
if(part_size)
|
||||
{
|
||||
//int snapsize = lzw_decompress(snapshots[SNAP_INCOMMING], snapshots[SNAP_CURRENT]);
|
||||
int compsize = zerobit_decompress(snapshots[SNAP_INCOMMING], part_size, tmpbuffer);
|
||||
//int compsize = lzw_decompress(snapshots[SNAP_INCOMMING],tmpbuffer);
|
||||
int intsize = intpack_decompress(tmpbuffer, compsize, tmpbuffer2);
|
||||
deltadata = tmpbuffer2;
|
||||
deltasize = intsize;
|
||||
}
|
||||
|
||||
// find snapshot that we should use as delta
|
||||
static snapshot emptysnap;
|
||||
emptysnap.data_size = 0;
|
||||
emptysnap.num_items = 0;
|
||||
|
||||
snapshot *deltashot = &emptysnap;
|
||||
int deltashot_size;
|
||||
|
||||
if(delta_tick >= 0)
|
||||
{
|
||||
void *delta_data;
|
||||
deltashot_size = snapshots_new.get(delta_tick, &delta_data);
|
||||
if(deltashot_size >= 0)
|
||||
{
|
||||
deltashot = (snapshot *)delta_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: handle this
|
||||
dbg_msg("client", "error, couldn't find the delta snapshot");
|
||||
}
|
||||
}
|
||||
|
||||
int snapsize = snapshot_unpack_delta(deltashot, (snapshot*)snapshots[SNAP_CURRENT], deltadata, deltasize);
|
||||
//snapshot *shot = (snapshot *)snapshots[SNAP_CURRENT];
|
||||
|
||||
// purge old snapshots
|
||||
snapshots_new.purge_until(delta_tick);
|
||||
snapshots_new.purge_until(game_tick-50); // TODO: change this to server tickrate
|
||||
|
||||
// add new
|
||||
snapshots_new.add(game_tick, snapsize, snapshots[SNAP_CURRENT]);
|
||||
|
||||
// apply snapshot, cycle pointers
|
||||
recived_snapshots++;
|
||||
snapshot_start_time = time_get();
|
||||
|
||||
// we got two snapshots until we see us self as connected
|
||||
if(recived_snapshots == 2)
|
||||
{
|
||||
local_start_time = time_get();
|
||||
set_state(STATE_ONLINE);
|
||||
}
|
||||
|
||||
if(recived_snapshots > 2)
|
||||
modc_newsnapshot();
|
||||
|
||||
snapshot_part = 0;
|
||||
|
||||
// ack snapshot
|
||||
msg_pack_start_system(NETMSG_SNAPACK, 0);
|
||||
msg_pack_int(game_tick);
|
||||
msg_pack_end();
|
||||
client_send_msg();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_msg("client", "snapshot reset!");
|
||||
snapshot_part = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// game message
|
||||
modc_message(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void pump_network()
|
||||
|
|
|
@ -617,7 +617,7 @@ pretty_font *current_font = &default_font;
|
|||
void gfx_pretty_text(float x, float y, float size, const char *text)
|
||||
{
|
||||
const float spacing = 0.05f;
|
||||
|
||||
gfx_texture_set(current_font->font_texture);
|
||||
gfx_quads_begin();
|
||||
|
||||
while (*text)
|
||||
|
|
|
@ -705,6 +705,7 @@ enum
|
|||
MSGFLAG_VITAL=1,
|
||||
};
|
||||
|
||||
void msg_pack_start_system(int msg, int flags);
|
||||
void msg_pack_start(int msg, int flags);
|
||||
void msg_pack_int(int i);
|
||||
void msg_pack_string(const char *p, int limit);
|
||||
|
@ -722,20 +723,23 @@ struct msg_info
|
|||
const msg_info *msg_get_info();
|
||||
|
||||
// message unpacking
|
||||
int msg_unpack_start(const void *data, int data_size);
|
||||
int msg_unpack_start(const void *data, int data_size, int *system);
|
||||
int msg_unpack_int();
|
||||
const char *msg_unpack_string();
|
||||
const unsigned char *msg_unpack_raw(int size);
|
||||
|
||||
// message sending
|
||||
int server_send_msg(int client_id);
|
||||
int server_send_msg(int client_id); // client_id == -1 == broadcast
|
||||
int client_send_msg();
|
||||
|
||||
int client_tick();
|
||||
float client_intratick();
|
||||
|
||||
void gfx_pretty_text(float x, float y, float size, const char *text);
|
||||
float gfx_pretty_text_width(float size, const char *text);
|
||||
|
||||
int modc_message();
|
||||
void mods_message(int msg, int client_id);
|
||||
void modc_message(int msg);
|
||||
|
||||
#define MASTER_SERVER_ADDRESS "master.teewars.com"
|
||||
#define MASTER_SERVER_PORT 8300
|
||||
|
|
|
@ -10,13 +10,22 @@ void msg_pack_int(int i) { packer.add_int(i); }
|
|||
void msg_pack_string(const char *p, int limit) { packer.add_string(p, limit); }
|
||||
void msg_pack_raw(const void *data, int size) { packer.add_raw((const unsigned char *)data, size); }
|
||||
|
||||
void msg_pack_start_system(int msg, int flags)
|
||||
{
|
||||
packer.reset();
|
||||
pack_info.msg = (msg<<1)|1;
|
||||
pack_info.flags = flags;
|
||||
|
||||
msg_pack_int(pack_info.msg);
|
||||
}
|
||||
|
||||
void msg_pack_start(int msg, int flags)
|
||||
{
|
||||
packer.reset();
|
||||
pack_info.msg = msg;
|
||||
pack_info.msg = msg<<1;
|
||||
pack_info.flags = flags;
|
||||
|
||||
msg_pack_int(msg);
|
||||
msg_pack_int(pack_info.msg);
|
||||
}
|
||||
|
||||
void msg_pack_end()
|
||||
|
@ -32,10 +41,12 @@ const msg_info *msg_get_info()
|
|||
|
||||
// message unpacking
|
||||
static data_unpacker unpacker;
|
||||
int msg_unpack_start(const void *data, int data_size)
|
||||
int msg_unpack_start(const void *data, int data_size, int *system)
|
||||
{
|
||||
unpacker.reset((const unsigned char *)data, data_size);
|
||||
return msg_unpack_int();
|
||||
int msg = msg_unpack_int();
|
||||
*system = msg&1;
|
||||
return msg>>1;
|
||||
}
|
||||
|
||||
int msg_unpack_int() { return unpacker.get_int(); }
|
||||
|
|
|
@ -108,7 +108,18 @@ int server_send_msg(int client_id)
|
|||
if(info->flags&MSGFLAG_VITAL)
|
||||
packet.flags = PACKETFLAG_VITAL;
|
||||
|
||||
net.send(&packet);
|
||||
if(client_id == -1)
|
||||
{
|
||||
// broadcast
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
if(clients[i].is_ingame())
|
||||
{
|
||||
packet.client_id = i;
|
||||
net.send(&packet);
|
||||
}
|
||||
}
|
||||
else
|
||||
net.send(&packet);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -337,9 +348,9 @@ public:
|
|||
left -= chunk;
|
||||
|
||||
if(numpackets == 1)
|
||||
msg_pack_start(NETMSG_SNAPSMALL, 0);
|
||||
msg_pack_start_system(NETMSG_SNAPSMALL, 0);
|
||||
else
|
||||
msg_pack_start(NETMSG_SNAP, 0);
|
||||
msg_pack_start_system(NETMSG_SNAP, 0);
|
||||
msg_pack_int(current_tick);
|
||||
msg_pack_int(current_tick-delta_tick); // compressed with
|
||||
msg_pack_int(chunk);
|
||||
|
@ -352,7 +363,7 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
msg_pack_start(NETMSG_SNAPEMPTY, 0);
|
||||
msg_pack_start_system(NETMSG_SNAPEMPTY, 0);
|
||||
msg_pack_int(current_tick);
|
||||
msg_pack_int(current_tick-delta_tick); // compressed with
|
||||
msg_pack_end();
|
||||
|
@ -366,7 +377,7 @@ public:
|
|||
|
||||
void send_map(int cid)
|
||||
{
|
||||
msg_pack_start(NETMSG_MAP, MSGFLAG_VITAL);
|
||||
msg_pack_start_system(NETMSG_MAP, MSGFLAG_VITAL);
|
||||
msg_pack_string(map_name, 0);
|
||||
msg_pack_end();
|
||||
server_send_msg(cid);
|
||||
|
@ -385,40 +396,49 @@ public:
|
|||
void process_client_packet(NETPACKET *packet)
|
||||
{
|
||||
int cid = packet->client_id;
|
||||
int msg = msg_unpack_start(packet->data, packet->data_size);
|
||||
if(msg == NETMSG_INFO)
|
||||
int sys;
|
||||
int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
|
||||
if(sys)
|
||||
{
|
||||
strncpy(clients[cid].name, msg_unpack_string(), MAX_NAME_LENGTH);
|
||||
strncpy(clients[cid].clan, msg_unpack_string(), MAX_CLANNAME_LENGTH);
|
||||
const char *password = msg_unpack_string();
|
||||
const char *skin = msg_unpack_string();
|
||||
(void)password; // ignore these variables
|
||||
(void)skin;
|
||||
send_map(cid);
|
||||
}
|
||||
else if(msg == NETMSG_ENTERGAME)
|
||||
{
|
||||
dbg_msg("game", "player as entered the game. cid=%x", cid);
|
||||
clients[cid].state = client::STATE_INGAME;
|
||||
mods_client_enter(cid);
|
||||
}
|
||||
else if(msg == NETMSG_INPUT)
|
||||
{
|
||||
int input[MAX_INPUT_SIZE];
|
||||
int size = msg_unpack_int();
|
||||
for(int i = 0; i < size/4; i++)
|
||||
input[i] = msg_unpack_int();
|
||||
mods_client_input(cid, input);
|
||||
}
|
||||
else if(msg == NETMSG_SNAPACK)
|
||||
{
|
||||
clients[cid].last_acked_snapshot = msg_unpack_int();
|
||||
// system message
|
||||
if(msg == NETMSG_INFO)
|
||||
{
|
||||
strncpy(clients[cid].name, msg_unpack_string(), MAX_NAME_LENGTH);
|
||||
strncpy(clients[cid].clan, msg_unpack_string(), MAX_CLANNAME_LENGTH);
|
||||
const char *password = msg_unpack_string();
|
||||
const char *skin = msg_unpack_string();
|
||||
(void)password; // ignore these variables
|
||||
(void)skin;
|
||||
send_map(cid);
|
||||
}
|
||||
else if(msg == NETMSG_ENTERGAME)
|
||||
{
|
||||
dbg_msg("game", "player as entered the game. cid=%x", cid);
|
||||
clients[cid].state = client::STATE_INGAME;
|
||||
mods_client_enter(cid);
|
||||
}
|
||||
else if(msg == NETMSG_INPUT)
|
||||
{
|
||||
int input[MAX_INPUT_SIZE];
|
||||
int size = msg_unpack_int();
|
||||
for(int i = 0; i < size/4; i++)
|
||||
input[i] = msg_unpack_int();
|
||||
mods_client_input(cid, input);
|
||||
}
|
||||
else if(msg == NETMSG_SNAPACK)
|
||||
{
|
||||
clients[cid].last_acked_snapshot = msg_unpack_int();
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_msg("server", "strange message cid=%d msg=%d data_size=%d", cid, msg, packet->data_size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_msg("server", "strange message cid=%d msg=%d data_size=%d", cid, msg, packet->data_size);
|
||||
// game message
|
||||
mods_message(msg, cid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void process_packet(NETPACKET *packet)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include <baselib/math.h>
|
||||
//#include <baselib/keys.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <engine/config.h>
|
||||
#include "../game.h"
|
||||
#include "mapres_image.h"
|
||||
|
@ -17,6 +19,11 @@ static vec2 mouse_pos;
|
|||
static vec2 local_player_pos;
|
||||
static obj_player *local_player;
|
||||
|
||||
struct client_data
|
||||
{
|
||||
char name[64];
|
||||
} client_datas[MAX_CLIENTS];
|
||||
|
||||
inline float frandom() { return rand()/(float)(RAND_MAX); }
|
||||
|
||||
void snd_play_random(int setid, float vol, float pan)
|
||||
|
@ -144,28 +151,27 @@ void move_point(vec2 *inout_pos, vec2 *inout_vel, float elasticity)
|
|||
}
|
||||
}
|
||||
|
||||
class health_texts
|
||||
class damage_indicators
|
||||
{
|
||||
public:
|
||||
int64 lastupdate;
|
||||
struct item
|
||||
{
|
||||
vec2 pos;
|
||||
vec2 vel;
|
||||
int amount;
|
||||
int istar;
|
||||
vec2 dir;
|
||||
float life;
|
||||
float startangle;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_ITEMS=16,
|
||||
MAX_ITEMS=64,
|
||||
};
|
||||
|
||||
health_texts()
|
||||
damage_indicators()
|
||||
{
|
||||
lastupdate = 0;
|
||||
num_items = 0;
|
||||
}
|
||||
|
||||
item items[MAX_ITEMS];
|
||||
|
@ -188,54 +194,35 @@ public:
|
|||
*i = items[num_items];
|
||||
}
|
||||
|
||||
void create(vec2 pos, int amount)
|
||||
void create(vec2 pos, vec2 dir)
|
||||
{
|
||||
amount = max(1,amount);
|
||||
for (int j = 0; j < amount; j++)
|
||||
item *i = create_i();
|
||||
if (i)
|
||||
{
|
||||
//float a = j/(float)amount-0.5f;
|
||||
item *i = create_i();
|
||||
if (i)
|
||||
{
|
||||
i->pos = pos;
|
||||
i->pos.y -= 20.0f;
|
||||
i->pos.x += ((float)rand()/(float)RAND_MAX) * 5.0f;
|
||||
i->amount = amount;
|
||||
i->life = 1.5f;
|
||||
i->istar = rand()%2;
|
||||
i->vel = vec2(((float)rand()/(float)RAND_MAX) * 50.0f,-150.0f);
|
||||
i->startangle = (( (float)rand()/(float)RAND_MAX) - 1.0f) * 2.0f * pi;
|
||||
}
|
||||
i->pos = pos;
|
||||
i->life = 0.75f;
|
||||
i->dir = dir;
|
||||
i->startangle = (( (float)rand()/(float)RAND_MAX) - 1.0f) * 2.0f * pi;
|
||||
}
|
||||
}
|
||||
|
||||
void render()
|
||||
{
|
||||
if (!lastupdate)
|
||||
lastupdate = time_get();
|
||||
|
||||
int64 lasttime = lastupdate;
|
||||
lastupdate = time_get();
|
||||
|
||||
float delta = (float) (lastupdate - lasttime) / (float)time_freq();
|
||||
gfx_texture_set(data->images[IMAGE_PARTICLES].id);
|
||||
gfx_texture_set(data->images[IMAGE_GAME].id);
|
||||
gfx_quads_begin();
|
||||
for(int i = 0; i < num_items;)
|
||||
{
|
||||
items[i].vel += vec2(0,500.0f) * delta;
|
||||
items[i].pos += items[i].vel * delta;
|
||||
items[i].life -= delta;
|
||||
//items[i].pos.y -= frametime*15.0f;
|
||||
vec2 pos = mix(items[i].pos+items[i].dir*75.0f, items[i].pos, clamp((items[i].life-0.60f)/0.15f, 0.0f, 1.0f));
|
||||
|
||||
items[i].life -= client_frametime();
|
||||
if(items[i].life < 0.0f)
|
||||
destroy_i(&items[i]);
|
||||
else
|
||||
{
|
||||
gfx_quads_setcolor(1.0f,1.0f,1.0f, items[i].life / 1.5f);
|
||||
gfx_quads_setcolor(1.0f,1.0f,1.0f, items[i].life/0.1f);
|
||||
gfx_quads_setrotation(items[i].startangle + items[i].life * 2.0f);
|
||||
float size = 64.0f;
|
||||
const int stars[] = {SPRITE_STAR1, SPRITE_STAR2};
|
||||
select_sprite(stars[items[i].istar]);
|
||||
gfx_quads_draw(items[i].pos.x-size/2, items[i].pos.y-size/2, size, size);
|
||||
select_sprite(SPRITE_STAR1);
|
||||
draw_sprite(pos.x, pos.y, 48.0f);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
@ -244,7 +231,7 @@ public:
|
|||
|
||||
};
|
||||
|
||||
static health_texts healthmods;
|
||||
static damage_indicators damageind;
|
||||
|
||||
class particle_system
|
||||
{
|
||||
|
@ -350,6 +337,35 @@ public:
|
|||
|
||||
static particle_system temp_system;
|
||||
|
||||
|
||||
static bool chat_active = false;
|
||||
static char chat_input[512];
|
||||
static unsigned chat_input_len;
|
||||
static const int chat_max_lines = 10;
|
||||
|
||||
struct chatline
|
||||
{
|
||||
int tick;
|
||||
char text[512+64];
|
||||
};
|
||||
|
||||
chatline chat_lines[chat_max_lines];
|
||||
static int chat_current_line = 0;
|
||||
|
||||
void chat_reset()
|
||||
{
|
||||
for(int i = 0; i < chat_max_lines; i++)
|
||||
chat_lines[i].tick = -1000000;
|
||||
chat_current_line = 0;
|
||||
}
|
||||
|
||||
void chat_add_line(int client_id, const char *line)
|
||||
{
|
||||
chat_current_line = (chat_current_line+1)%chat_max_lines;
|
||||
chat_lines[chat_current_line].tick = client_tick();
|
||||
sprintf(chat_lines[chat_current_line].text, "%s: %s", client_datas[client_id].name, line); // TODO: abit nasty
|
||||
}
|
||||
|
||||
void modc_init()
|
||||
{
|
||||
// load the data container
|
||||
|
@ -370,6 +386,10 @@ void modc_entergame()
|
|||
col_init(32);
|
||||
img_init();
|
||||
tilemap_init();
|
||||
chat_reset();
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
client_datas[i].name[0] = 0;
|
||||
}
|
||||
|
||||
void modc_shutdown()
|
||||
|
@ -384,10 +404,10 @@ void modc_newsnapshot()
|
|||
snap_item item;
|
||||
void *data = snap_get_item(SNAP_CURRENT, i, &item);
|
||||
|
||||
if(item.type == EVENT_HEALTHMOD)
|
||||
if(item.type == EVENT_DAMAGEINDICATION)
|
||||
{
|
||||
ev_healthmod *ev = (ev_healthmod *)data;
|
||||
healthmods.create(vec2(ev->x, ev->y), ev->amount);
|
||||
ev_damageind *ev = (ev_damageind *)data;
|
||||
damageind.create(vec2(ev->x, ev->y), get_direction(ev->angle));
|
||||
}
|
||||
else if(item.type == EVENT_EXPLOSION)
|
||||
{
|
||||
|
@ -567,6 +587,8 @@ struct animstate
|
|||
keyframe attach;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void anim_eval(animation *anim, float time, animstate *state)
|
||||
{
|
||||
anim_seq_eval(&anim->body, time, &state->body);
|
||||
|
@ -597,8 +619,64 @@ static void anim_eval_add(animstate *state, animation *anim, float time, float a
|
|||
anim_add(state, &add, amount);
|
||||
}
|
||||
|
||||
static void render_tee(animstate *anim, int skin, vec2 dir, vec2 pos)
|
||||
{
|
||||
vec2 direction = dir;
|
||||
//float angle = info->angle;
|
||||
vec2 position = pos;
|
||||
|
||||
gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id);
|
||||
gfx_quads_begin();
|
||||
|
||||
// draw foots
|
||||
for(int p = 0; p < 2; p++)
|
||||
{
|
||||
// first pass we draw the outline
|
||||
// second pass we draw the filling
|
||||
|
||||
int outline = p==0 ? 1 : 0;
|
||||
int shift = charids[skin%16];
|
||||
|
||||
for(int f = 0; f < 2; f++)
|
||||
{
|
||||
float basesize = 10.0f;
|
||||
if(f == 1)
|
||||
{
|
||||
// draw body
|
||||
select_sprite(outline?SPRITE_TEE_BODY_OUTLINE:SPRITE_TEE_BODY, 0, 0, shift*4);
|
||||
gfx_quads_draw(position.x+anim->body.x, position.y+anim->body.y, 4*basesize, 4*basesize);
|
||||
|
||||
// draw eyes
|
||||
if(p == 1)
|
||||
{
|
||||
// normal
|
||||
select_sprite(SPRITE_TEE_EYE_NORMAL, 0, 0, shift*4);
|
||||
gfx_quads_draw(position.x-4+direction.x*4, position.y-8+direction.y*3, basesize, basesize);
|
||||
gfx_quads_draw(position.x+4+direction.x*4, position.y-8+direction.y*3, basesize, basesize);
|
||||
}
|
||||
}
|
||||
|
||||
// draw feet
|
||||
select_sprite(outline?SPRITE_TEE_FOOT_OUTLINE:SPRITE_TEE_FOOT, 0, 0, shift*4);
|
||||
|
||||
keyframe *foot = f ? &anim->front_foot : &anim->back_foot;
|
||||
|
||||
float w = basesize*2.5f;
|
||||
float h = basesize*1.425f;
|
||||
|
||||
gfx_quads_setrotation(foot->angle);
|
||||
gfx_quads_draw(position.x+foot->x, position.y+foot->y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
gfx_quads_end();
|
||||
}
|
||||
|
||||
static void render_player(obj_player *prev, obj_player *player)
|
||||
{
|
||||
if(player->health < 0) // dont render dead players
|
||||
return;
|
||||
|
||||
vec2 direction = get_direction(player->angle);
|
||||
float angle = player->angle/256.0f;
|
||||
vec2 position = mix(vec2(prev->x, prev->y), vec2(player->x, player->y), client_intratick());
|
||||
|
@ -692,6 +770,9 @@ static void render_player(obj_player *prev, obj_player *player)
|
|||
gfx_quads_end();
|
||||
}
|
||||
|
||||
render_tee(&state, player->clientid, direction, position);
|
||||
|
||||
/*
|
||||
gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id);
|
||||
gfx_quads_begin();
|
||||
|
||||
|
@ -741,10 +822,60 @@ static void render_player(obj_player *prev, obj_player *player)
|
|||
}
|
||||
|
||||
gfx_quads_end();
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
void modc_render()
|
||||
{
|
||||
if(inp_key_down(input::enter))
|
||||
{
|
||||
if(chat_active)
|
||||
{
|
||||
// send message
|
||||
msg_pack_start(MSG_SAY, MSGFLAG_VITAL);
|
||||
msg_pack_string(chat_input, 512);
|
||||
msg_pack_end();
|
||||
client_send_msg();
|
||||
}
|
||||
else
|
||||
{
|
||||
mem_zero(chat_input, sizeof(chat_input));
|
||||
chat_input_len = 0;
|
||||
}
|
||||
chat_active = !chat_active;
|
||||
}
|
||||
|
||||
if(chat_active)
|
||||
{
|
||||
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 (chat_input_len < sizeof(chat_input) - 1)
|
||||
{
|
||||
chat_input[chat_input_len] = c;
|
||||
chat_input[chat_input_len+1] = 0;
|
||||
chat_input_len++;
|
||||
}
|
||||
}
|
||||
|
||||
if(k == input::backspace)
|
||||
{
|
||||
if(chat_input_len > 0)
|
||||
{
|
||||
chat_input[chat_input_len-1] = 0;
|
||||
chat_input_len--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
input::clear_char(); // TODO: bypasses the engine interface
|
||||
input::clear_key(); // TODO: bypasses the engine interface
|
||||
|
||||
// fetch new input
|
||||
{
|
||||
int x, y;
|
||||
|
@ -765,20 +896,24 @@ void modc_render()
|
|||
a = a+pi;
|
||||
|
||||
input.angle = (int)(a*256.0f);
|
||||
input.left = inp_key_pressed(config.key_move_left);
|
||||
input.right = inp_key_pressed(config.key_move_right);
|
||||
input.jump = inp_key_pressed(config.key_jump);
|
||||
input.fire = inp_key_pressed(config.key_fire);
|
||||
input.hook = inp_key_pressed(config.key_hook);
|
||||
|
||||
input.blink = inp_key_pressed('S');
|
||||
|
||||
// Weapon switching
|
||||
input.activeweapon = -1;
|
||||
input.activeweapon = inp_key_pressed('1') ? 0 : input.activeweapon;
|
||||
input.activeweapon = inp_key_pressed('2') ? 1 : input.activeweapon;
|
||||
input.activeweapon = inp_key_pressed('3') ? 2 : input.activeweapon;
|
||||
input.activeweapon = inp_key_pressed('4') ? 3 : input.activeweapon;
|
||||
|
||||
if(!chat_active)
|
||||
{
|
||||
input.left = inp_key_pressed(config.key_move_left);
|
||||
input.right = inp_key_pressed(config.key_move_right);
|
||||
input.jump = inp_key_pressed(config.key_jump);
|
||||
input.fire = inp_key_pressed(config.key_fire);
|
||||
input.hook = inp_key_pressed(config.key_hook);
|
||||
|
||||
input.blink = inp_key_pressed('S');
|
||||
|
||||
// Weapon switching
|
||||
input.activeweapon = inp_key_pressed('1') ? 0 : input.activeweapon;
|
||||
input.activeweapon = inp_key_pressed('2') ? 1 : input.activeweapon;
|
||||
input.activeweapon = inp_key_pressed('3') ? 2 : input.activeweapon;
|
||||
input.activeweapon = inp_key_pressed('4') ? 3 : input.activeweapon;
|
||||
}
|
||||
|
||||
snap_input(&input, sizeof(input));
|
||||
}
|
||||
|
@ -811,7 +946,7 @@ void modc_render()
|
|||
}
|
||||
|
||||
// pseudo format
|
||||
float zoom = inp_key_pressed('T') ? 1.0 : 3.0f;
|
||||
float zoom = 3.0f;
|
||||
|
||||
float width = 400*zoom;
|
||||
float height = 300*zoom;
|
||||
|
@ -907,8 +1042,8 @@ void modc_render()
|
|||
|
||||
tilemap_render(32.0f, 1);
|
||||
|
||||
// render health mods
|
||||
healthmods.render();
|
||||
// render damage indications
|
||||
damageind.render();
|
||||
|
||||
if(local_player)
|
||||
{
|
||||
|
@ -958,14 +1093,73 @@ void modc_render()
|
|||
// render gui stuff
|
||||
gfx_mapscreen(0,0,400,300);
|
||||
|
||||
{
|
||||
float x = 10.0f;
|
||||
float y = 300.0f-50.0f;
|
||||
float starty = -1;
|
||||
if(chat_active)
|
||||
{
|
||||
|
||||
gfx_texture_set(-1); // TODO: remove when the font looks better
|
||||
gfx_quads_begin();
|
||||
gfx_quads_setcolor(0,0,0,0.4f);
|
||||
gfx_quads_drawTL(x-2, y+1, 300, 8);
|
||||
gfx_quads_end();
|
||||
|
||||
// render chat input
|
||||
char buf[sizeof(chat_input)+16];
|
||||
sprintf(buf, "Chat: %s_", chat_input);
|
||||
gfx_pretty_text(x, y, 10, buf);
|
||||
starty = y;
|
||||
}
|
||||
|
||||
y -= 10;
|
||||
|
||||
int i;
|
||||
for(i = 0; i < chat_max_lines; i++)
|
||||
{
|
||||
int r = ((chat_current_line-i)+chat_max_lines)%chat_max_lines;
|
||||
if(client_tick() > chat_lines[r].tick+50*15)
|
||||
break;
|
||||
|
||||
gfx_texture_set(-1); // TODO: remove when the font looks better
|
||||
gfx_quads_begin();
|
||||
gfx_quads_setcolor(0,0,0,0.4f);
|
||||
gfx_quads_drawTL(x-2, y+1, gfx_pretty_text_width(10, chat_lines[r].text)+3, 8);
|
||||
gfx_quads_end();
|
||||
|
||||
gfx_pretty_text(x, y, 10, chat_lines[r].text);
|
||||
y -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
// render score board
|
||||
if(inp_key_pressed(baselib::input::tab))
|
||||
{
|
||||
gfx_mapscreen(0, 0, width, height);
|
||||
|
||||
float x = 50.0f;
|
||||
float y = 150.0f;
|
||||
|
||||
gfx_blend_normal();
|
||||
|
||||
gfx_texture_set(-1);
|
||||
gfx_quads_text(10, 50, 8, "Score Board");
|
||||
gfx_quads_begin();
|
||||
gfx_quads_setcolor(0,0,0,0.5f);
|
||||
gfx_quads_drawTL(x-10.f, y-10.f, 400.0f, 600.0f);
|
||||
gfx_quads_end();
|
||||
|
||||
//gfx_texture_set(current_font->font_texture);
|
||||
gfx_pretty_text(x, y, 64, "Score Board");
|
||||
y += 100.0f;
|
||||
|
||||
//gfx_texture_set(-1);
|
||||
//gfx_quads_text(10, 50, 8, "Score Board");
|
||||
animstate state;
|
||||
anim_eval(&data->animations[ANIM_BASE], 0, &state);
|
||||
anim_eval_add(&state, &data->animations[ANIM_IDLE], 0, 1.0f);
|
||||
|
||||
int num = snap_num_items(SNAP_CURRENT);
|
||||
int row = 1;
|
||||
for(int i = 0; i < num; i++)
|
||||
{
|
||||
snap_item item;
|
||||
|
@ -977,13 +1171,31 @@ void modc_render()
|
|||
if(player)
|
||||
{
|
||||
char buf[128];
|
||||
char name[32] = "tjo";
|
||||
//snap_decode_string(player->name, name, 32);
|
||||
sprintf(buf, "%4d %s", player->score, name);
|
||||
gfx_quads_text(10, 50 + 10 * row, 8, buf);
|
||||
row++;
|
||||
sprintf(buf, "%4d", player->score);
|
||||
gfx_pretty_text(x+60-gfx_pretty_text_width(48,buf), y, 48, buf);
|
||||
gfx_pretty_text(x+128, y, 48, client_datas[player->clientid].name);
|
||||
|
||||
render_tee(&state, player->clientid, vec2(1,0), vec2(x+90, y+24));
|
||||
y += 58.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void modc_message(int msg)
|
||||
{
|
||||
if(msg == MSG_CHAT)
|
||||
{
|
||||
int cid = msg_unpack_int();
|
||||
const char *message = msg_unpack_string();
|
||||
dbg_msg("message", "chat cid=%d msg='%s'", cid, message);
|
||||
chat_add_line(cid, message);
|
||||
}
|
||||
else if(msg == MSG_SETNAME)
|
||||
{
|
||||
int cid = msg_unpack_int();
|
||||
const char *name = msg_unpack_string();
|
||||
strncpy(client_datas[cid].name, name, 64);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,11 +30,19 @@ enum
|
|||
OBJTYPE_PROJECTILE,
|
||||
OBJTYPE_POWERUP,
|
||||
EVENT_EXPLOSION,
|
||||
EVENT_HEALTHMOD,
|
||||
EVENT_DAMAGEINDICATION,
|
||||
EVENT_SOUND,
|
||||
EVENT_SMOKE,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MSG_NULL=0,
|
||||
MSG_SAY,
|
||||
MSG_CHAT,
|
||||
MSG_SETNAME,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
EMOTE_NORMAL=0,
|
||||
|
@ -67,11 +75,10 @@ struct ev_sound
|
|||
int sound; // if (0x80000000 flag is set -> looping) if (0x40000000 is set -> stop looping
|
||||
};
|
||||
|
||||
struct ev_healthmod
|
||||
struct ev_damageind
|
||||
{
|
||||
int x, y; // could perhaps be an client id
|
||||
int vx, vy; // should be an angle instead
|
||||
int amount;
|
||||
int x, y;
|
||||
int angle;
|
||||
};
|
||||
|
||||
struct obj_projectile
|
||||
|
@ -91,7 +98,6 @@ struct obj_powerup
|
|||
struct obj_player
|
||||
{
|
||||
//int name[8];
|
||||
|
||||
int local;
|
||||
int clientid;
|
||||
|
||||
|
@ -106,7 +112,6 @@ struct obj_player
|
|||
// current active weapon
|
||||
int weapon;
|
||||
// current active modifier
|
||||
//int modifier;
|
||||
|
||||
// num attack ticks left of current attack
|
||||
int attacktick;
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
using namespace baselib;
|
||||
|
||||
// ---------
|
||||
const bool debug_bots = false;
|
||||
// --------- DEBUG STUFF ---------
|
||||
const bool debug_bots = true;
|
||||
|
||||
// --------- PHYSICS TWEAK! --------
|
||||
const float ground_control_speed = 7.0f;
|
||||
|
@ -23,7 +23,7 @@ const float hook_drag_speed = 15.0f;
|
|||
const float gravity = 0.5f;
|
||||
|
||||
class player* get_player(int index);
|
||||
void create_healthmod(vec2 p, int amount);
|
||||
void create_damageind(vec2 p, vec2 dir, int amount);
|
||||
void create_explosion(vec2 p, int owner = -1, bool bnodamage = false);
|
||||
void create_smoke(vec2 p);
|
||||
void create_sound(vec2 pos, int sound, int loopflags = 0);
|
||||
|
@ -175,6 +175,10 @@ private:
|
|||
friend class player;
|
||||
entity *prev_entity;
|
||||
entity *next_entity;
|
||||
|
||||
entity *prev_type_entity;
|
||||
entity *next_type_entity;
|
||||
|
||||
int index;
|
||||
static int current_id;
|
||||
protected:
|
||||
|
@ -189,19 +193,28 @@ public:
|
|||
enum
|
||||
{
|
||||
FLAG_DESTROY=0x00000001,
|
||||
FLAG_ALIVE=0x00000002,
|
||||
};
|
||||
|
||||
entity(int objtype)
|
||||
{
|
||||
this->objtype = objtype;
|
||||
pos = vec2(0,0);
|
||||
flags = 0;
|
||||
flags = FLAG_ALIVE;
|
||||
proximity_radius = 0;
|
||||
|
||||
current_id++;
|
||||
id = current_id;
|
||||
|
||||
next_entity = 0;
|
||||
prev_entity = 0;
|
||||
prev_type_entity = 0;
|
||||
next_type_entity = 0;
|
||||
}
|
||||
|
||||
void set_flag(unsigned flag) { flags |= flag; }
|
||||
void clear_flag(unsigned flag) { flags &= ~flag; }
|
||||
|
||||
virtual ~entity()
|
||||
{
|
||||
}
|
||||
|
@ -221,10 +234,19 @@ int entity::current_id = 1;
|
|||
class game_world
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
NUM_ENT_TYPES=10,
|
||||
};
|
||||
|
||||
entity *first_entity;
|
||||
entity *first_entity_types[NUM_ENT_TYPES];
|
||||
|
||||
game_world()
|
||||
{
|
||||
first_entity = 0x0;
|
||||
for(int i = 0; i < NUM_ENT_TYPES; i++)
|
||||
first_entity_types[i] = 0;
|
||||
}
|
||||
|
||||
int find_entities(vec2 pos, float radius, entity **ents, int max)
|
||||
|
@ -232,6 +254,9 @@ public:
|
|||
int num = 0;
|
||||
for(entity *ent = first_entity; ent; ent = ent->next_entity)
|
||||
{
|
||||
if(!(ent->flags&entity::FLAG_ALIVE))
|
||||
continue;
|
||||
|
||||
if(distance(ent->pos, pos) < radius+ent->proximity_radius)
|
||||
{
|
||||
ents[num] = ent;
|
||||
|
@ -247,14 +272,13 @@ public:
|
|||
int find_entities(vec2 pos, float radius, entity **ents, int max, const int* types, int maxtypes)
|
||||
{
|
||||
int num = 0;
|
||||
for(entity *ent = first_entity; ent; ent = ent->next_entity)
|
||||
for(int t = 0; t < maxtypes; t++)
|
||||
{
|
||||
for (int i = 0; i < maxtypes; i++)
|
||||
for(entity *ent = first_entity_types[types[t]]; ent; ent = ent->next_type_entity)
|
||||
{
|
||||
if (ent->objtype != types[i])
|
||||
if(!(ent->flags&entity::FLAG_ALIVE))
|
||||
continue;
|
||||
|
||||
// TODO: this seams like it could be done several times unnessesary
|
||||
if(distance(ent->pos, pos) < radius+ent->proximity_radius)
|
||||
{
|
||||
ents[num] = ent;
|
||||
|
@ -276,11 +300,18 @@ public:
|
|||
ent->next_entity = first_entity;
|
||||
ent->prev_entity = 0x0;
|
||||
first_entity = ent;
|
||||
|
||||
// into typelist aswell
|
||||
if(first_entity_types[ent->objtype])
|
||||
first_entity_types[ent->objtype]->prev_type_entity = ent;
|
||||
ent->next_type_entity = first_entity_types[ent->objtype];
|
||||
ent->prev_type_entity = 0x0;
|
||||
first_entity_types[ent->objtype] = ent;
|
||||
}
|
||||
|
||||
void destroy_entity(entity *ent)
|
||||
{
|
||||
ent->flags |= entity::FLAG_DESTROY;
|
||||
ent->set_flag(entity::FLAG_DESTROY);
|
||||
}
|
||||
|
||||
void remove_entity(entity *ent)
|
||||
|
@ -292,6 +323,13 @@ public:
|
|||
first_entity = ent->next_entity;
|
||||
if(ent->next_entity)
|
||||
ent->next_entity->prev_entity = ent->prev_entity;
|
||||
|
||||
if(ent->prev_type_entity)
|
||||
ent->prev_type_entity->next_type_entity = ent->next_type_entity;
|
||||
else
|
||||
first_entity_types[ent->objtype] = ent->next_type_entity;
|
||||
if(ent->next_type_entity)
|
||||
ent->next_type_entity->prev_type_entity = ent->prev_type_entity;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -394,7 +432,7 @@ public:
|
|||
if (flags & PROJECTILE_FLAGS_EXPLODE)
|
||||
create_explosion(oldpos, owner);
|
||||
else if (targetplayer)
|
||||
targetplayer->take_damage(normalize(vel) * force, damage, owner);
|
||||
targetplayer->take_damage(normalize(vel) * max(0.001f, force), damage, owner);
|
||||
|
||||
world.destroy_entity(this);
|
||||
}
|
||||
|
@ -442,7 +480,7 @@ public:
|
|||
|
||||
//
|
||||
int client_id;
|
||||
char name[32];
|
||||
char name[64];
|
||||
|
||||
// input
|
||||
player_input previnput;
|
||||
|
@ -456,6 +494,9 @@ public:
|
|||
|
||||
int score;
|
||||
|
||||
bool dead;
|
||||
int die_tick;
|
||||
|
||||
// hooking stuff
|
||||
enum
|
||||
{
|
||||
|
@ -496,6 +537,8 @@ public:
|
|||
direction = vec2(0.0f, 1.0f);
|
||||
client_id = -1;
|
||||
score = 0;
|
||||
dead = true;
|
||||
die_tick = 0;
|
||||
}
|
||||
|
||||
virtual void destroy() { }
|
||||
|
@ -505,6 +548,8 @@ public:
|
|||
health = PLAYER_MAXHEALTH;
|
||||
armor = 0;
|
||||
jumped = 0;
|
||||
dead = false;
|
||||
set_flag(entity::FLAG_ALIVE);
|
||||
|
||||
mem_zero(&input, sizeof(input));
|
||||
vel = vec2(0.0f, 0.0f);
|
||||
|
@ -520,6 +565,7 @@ public:
|
|||
}
|
||||
else
|
||||
pos = vec2(100.0f, -60.0f);
|
||||
defered_pos = pos;
|
||||
|
||||
// init weapons
|
||||
mem_zero(&weapons, sizeof(weapons));
|
||||
|
@ -638,6 +684,14 @@ public:
|
|||
{
|
||||
// TODO: rework the input to be more robust
|
||||
// TODO: remove this tick count, it feels weird
|
||||
if(dead)
|
||||
{
|
||||
if(server_tick()-die_tick >= server_tickspeed()*3) // auto respawn after 3 sec
|
||||
respawn();
|
||||
if(input.fire && server_tick()-die_tick >= server_tickspeed()/2) // auto respawn after 0.5 sec
|
||||
respawn();
|
||||
return;
|
||||
}
|
||||
|
||||
// fetch some info
|
||||
bool grounded = is_grounded();
|
||||
|
@ -796,7 +850,9 @@ public:
|
|||
release_hooks();
|
||||
|
||||
// TODO: insert timer here
|
||||
respawn();
|
||||
dead = true;
|
||||
die_tick = server_tick();
|
||||
clear_flag(entity::FLAG_ALIVE);
|
||||
}
|
||||
|
||||
virtual bool take_damage(vec2 force, int dmg, int from)
|
||||
|
@ -819,7 +875,7 @@ public:
|
|||
armor -= dmg;
|
||||
|
||||
// create healthmod indicator
|
||||
create_healthmod(pos, dmg);
|
||||
create_damageind(pos, normalize(force), dmg);
|
||||
|
||||
damage_taken_tick = server_tick()+50;
|
||||
|
||||
|
@ -876,6 +932,9 @@ public:
|
|||
player->armor = armor;
|
||||
}
|
||||
|
||||
if(dead)
|
||||
player->health = -1;
|
||||
|
||||
if(length(vel) > 15.0f)
|
||||
player->emote = EMOTE_HAPPY;
|
||||
|
||||
|
@ -981,20 +1040,26 @@ void powerup::snap(int snapping_client)
|
|||
|
||||
// POWERUP END ///////////////////////
|
||||
|
||||
static const int NUM_BOTS = 1;
|
||||
static player players[MAX_CLIENTS+NUM_BOTS];
|
||||
static player players[MAX_CLIENTS];
|
||||
|
||||
player *get_player(int index)
|
||||
{
|
||||
return &players[index];
|
||||
}
|
||||
|
||||
void create_healthmod(vec2 p, int amount)
|
||||
void create_damageind(vec2 p, vec2 dir, int amount)
|
||||
{
|
||||
ev_healthmod *ev = (ev_healthmod *)events.create(EVENT_HEALTHMOD, sizeof(ev_healthmod));
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
ev->amount = amount;
|
||||
float a = get_angle(dir);
|
||||
float s = a-pi/3;
|
||||
float e = a+pi/3;
|
||||
for(int i = 0; i < amount; i++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void create_explosion(vec2 p, int owner, bool bnodamage)
|
||||
|
@ -1052,13 +1117,13 @@ player* intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, entity* notthis)
|
|||
vec2 dir = pos1 - pos0;
|
||||
float radius = length(dir * 0.5f);
|
||||
vec2 center = pos0 + dir * 0.5f;
|
||||
int num = world.find_entities(center, radius, ents, 64);
|
||||
const int types[] = {OBJTYPE_PLAYER};
|
||||
int num = world.find_entities(center, radius, ents, 64, types, 1);
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
// Check if entity is a player
|
||||
if (ents[i] != notthis && ents[i]->objtype == OBJTYPE_PLAYER)
|
||||
if (ents[i] != notthis)
|
||||
{
|
||||
// temp, set hook pos to our position
|
||||
new_pos = ents[i]->pos;
|
||||
return (player*)ents[i];
|
||||
}
|
||||
|
@ -1082,8 +1147,11 @@ void mods_tick()
|
|||
count++;
|
||||
if(count == 10)
|
||||
{
|
||||
for(int i = 0; i < NUM_BOTS; i++)
|
||||
mods_client_enter(MAX_CLIENTS+i);
|
||||
for(int i = 0; i < 1; i++)
|
||||
{
|
||||
mods_client_enter(MAX_CLIENTS-i-1);
|
||||
strcpy(players[MAX_CLIENTS-i-1].name, "(bot)");
|
||||
}
|
||||
count = -1;
|
||||
}
|
||||
}
|
||||
|
@ -1108,6 +1176,30 @@ void mods_client_enter(int client_id)
|
|||
players[client_id].client_id = client_id;
|
||||
players[client_id].respawn();
|
||||
world.insert_entity(&players[client_id]);
|
||||
|
||||
client_info info; // fetch login name
|
||||
if(server_getclientinfo(client_id, &info))
|
||||
strcpy(players[client_id].name, info.name);
|
||||
else
|
||||
strcpy(players[client_id].name, "(bot)");
|
||||
|
||||
msg_pack_start(MSG_SETNAME, MSGFLAG_VITAL);
|
||||
msg_pack_int(client_id);
|
||||
msg_pack_string(players[client_id].name, 64);
|
||||
msg_pack_end();
|
||||
server_send_msg(-1);
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(players[client_id].client_id != -1)
|
||||
{
|
||||
msg_pack_start(MSG_SETNAME, MSGFLAG_VITAL);
|
||||
msg_pack_int(i);
|
||||
msg_pack_string(players[i].name, 64);
|
||||
msg_pack_end();
|
||||
server_send_msg(client_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mods_client_drop(int client_id)
|
||||
|
@ -1116,6 +1208,18 @@ void mods_client_drop(int client_id)
|
|||
world.remove_entity(&players[client_id]);
|
||||
}
|
||||
|
||||
void mods_message(int msg, int client_id)
|
||||
{
|
||||
if(msg == MSG_SAY)
|
||||
{
|
||||
msg_pack_start(MSG_CHAT, MSGFLAG_VITAL);
|
||||
msg_pack_int(client_id);
|
||||
msg_pack_string(msg_unpack_string(), 512);
|
||||
msg_pack_end();
|
||||
server_send_msg(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void mods_init()
|
||||
{
|
||||
col_init(32);
|
||||
|
|
Loading…
Reference in a new issue