2007-11-25 19:42:40 +00:00
|
|
|
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
|
2007-05-22 15:03:32 +00:00
|
|
|
#include <stdlib.h>
|
2007-07-30 07:05:34 +00:00
|
|
|
#include <stdio.h>
|
2007-05-22 15:03:32 +00:00
|
|
|
#include <string.h>
|
2007-12-15 10:24:49 +00:00
|
|
|
#include <engine/e_config.h>
|
2008-01-19 10:57:25 +00:00
|
|
|
#include <engine/e_server_interface.h>
|
2008-01-13 11:15:32 +00:00
|
|
|
#include <game/g_version.h>
|
|
|
|
#include <game/g_collision.h>
|
|
|
|
#include <game/g_layers.h>
|
2007-12-15 10:24:49 +00:00
|
|
|
#include "gs_common.h"
|
|
|
|
#include "gs_game_ctf.h"
|
|
|
|
#include "gs_game_tdm.h"
|
|
|
|
#include "gs_game_dm.h"
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
data_container *data = 0x0;
|
|
|
|
|
2008-02-02 12:38:36 +00:00
|
|
|
tuning_params tuning;
|
|
|
|
|
2007-05-22 15:03:32 +00:00
|
|
|
class player* get_player(int index);
|
2007-08-05 09:12:38 +00:00
|
|
|
void create_damageind(vec2 p, float angle_mod, int amount);
|
2007-07-14 22:35:00 +00:00
|
|
|
void create_explosion(vec2 p, int owner, int weapon, bool bnodamage);
|
2007-05-22 15:03:32 +00:00
|
|
|
void create_smoke(vec2 p);
|
2008-01-29 21:39:41 +00:00
|
|
|
void create_playerspawn(vec2 p);
|
2007-07-21 21:17:38 +00:00
|
|
|
void create_death(vec2 p);
|
2007-12-09 12:40:34 +00:00
|
|
|
void create_sound(vec2 pos, int sound, int mask=-1);
|
2007-07-15 10:47:50 +00:00
|
|
|
class player *intersect_player(vec2 pos0, vec2 pos1, vec2 &new_pos, class entity *notthis = 0);
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-09-23 22:54:31 +00:00
|
|
|
game_world *world;
|
|
|
|
|
2007-12-16 23:48:48 +00:00
|
|
|
void send_chat(int cid, int team, const char *msg)
|
|
|
|
{
|
|
|
|
if(cid >= 0 && cid < MAX_CLIENTS)
|
|
|
|
dbg_msg("chat", "%d:%d:%s: %s", cid, team, server_clientname(cid), msg);
|
|
|
|
else
|
|
|
|
dbg_msg("chat", "*** %s", msg);
|
|
|
|
|
|
|
|
if(team == -1)
|
|
|
|
{
|
|
|
|
msg_pack_start(MSG_CHAT, MSGFLAG_VITAL);
|
|
|
|
msg_pack_int(cid);
|
|
|
|
msg_pack_int(0);
|
|
|
|
msg_pack_string(msg, 512);
|
|
|
|
msg_pack_end();
|
|
|
|
server_send_msg(-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msg_pack_start(MSG_CHAT, MSGFLAG_VITAL);
|
|
|
|
msg_pack_int(cid);
|
|
|
|
msg_pack_int(1);
|
|
|
|
msg_pack_string(msg, 512);
|
|
|
|
msg_pack_end();
|
|
|
|
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if(players[i].client_id != -1 && players[i].team == team)
|
|
|
|
server_send_msg(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-02 12:38:36 +00:00
|
|
|
void send_tuning_params(int cid)
|
|
|
|
{
|
|
|
|
msg_pack_start(MSG_TUNE_PARAMS, MSGFLAG_VITAL);
|
|
|
|
int *params = (int *)&tuning;
|
|
|
|
for(unsigned i = 0; i < sizeof(tuning_params)/sizeof(int); i++)
|
|
|
|
msg_pack_int(params[i]);
|
|
|
|
msg_pack_end();
|
|
|
|
server_send_msg(cid);
|
|
|
|
}
|
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
//////////////////////////////////////////////////
|
|
|
|
// Event handler
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
event_handler::event_handler()
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-15 10:47:50 +00:00
|
|
|
clear();
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-12-09 12:40:34 +00:00
|
|
|
void *event_handler::create(int type, int size, int mask)
|
2007-07-15 10:47:50 +00:00
|
|
|
{
|
2007-08-14 18:37:16 +00:00
|
|
|
if(num_events == MAX_EVENTS)
|
|
|
|
return 0;
|
|
|
|
if(current_offset+size >= MAX_DATASIZE)
|
|
|
|
return 0;
|
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
void *p = &data[current_offset];
|
|
|
|
offsets[num_events] = current_offset;
|
|
|
|
types[num_events] = type;
|
|
|
|
sizes[num_events] = size;
|
2007-12-09 12:40:34 +00:00
|
|
|
client_masks[num_events] = mask;
|
2007-07-15 10:47:50 +00:00
|
|
|
current_offset += size;
|
|
|
|
num_events++;
|
|
|
|
return p;
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
void event_handler::clear()
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-15 10:47:50 +00:00
|
|
|
num_events = 0;
|
|
|
|
current_offset = 0;
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
void event_handler::snap(int snapping_client)
|
|
|
|
{
|
|
|
|
for(int i = 0; i < num_events; i++)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-12-09 12:40:34 +00:00
|
|
|
if(cmask_is_set(client_masks[i], snapping_client))
|
2007-08-04 17:28:31 +00:00
|
|
|
{
|
2007-10-28 11:30:25 +00:00
|
|
|
ev_common *ev = (ev_common *)&data[offsets[i]];
|
|
|
|
if(distance(players[snapping_client].pos, vec2(ev->x, ev->y)) < 1500.0f)
|
|
|
|
{
|
|
|
|
void *d = snap_new_item(types[i], i, sizes[i]);
|
|
|
|
mem_copy(d, &data[offsets[i]], sizes[i]);
|
|
|
|
}
|
2007-08-04 17:28:31 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
event_handler events;
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
// Entity
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
entity::entity(int objtype)
|
|
|
|
{
|
|
|
|
this->objtype = objtype;
|
|
|
|
pos = vec2(0,0);
|
2007-10-07 20:23:33 +00:00
|
|
|
flags = FLAG_PHYSICS;
|
2007-07-15 10:47:50 +00:00
|
|
|
proximity_radius = 0;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-08-14 18:37:16 +00:00
|
|
|
id = snap_new_id();
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
next_entity = 0;
|
|
|
|
prev_entity = 0;
|
|
|
|
prev_type_entity = 0;
|
|
|
|
next_type_entity = 0;
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
entity::~entity()
|
|
|
|
{
|
2007-08-14 18:37:16 +00:00
|
|
|
snap_free_id(id);
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
//////////////////////////////////////////////////
|
|
|
|
// game world
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
game_world::game_world()
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-15 10:47:50 +00:00
|
|
|
paused = false;
|
|
|
|
reset_requested = false;
|
|
|
|
first_entity = 0x0;
|
|
|
|
for(int i = 0; i < NUM_ENT_TYPES; i++)
|
|
|
|
first_entity_types[i] = 0;
|
|
|
|
}
|
2007-07-14 13:09:42 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
int game_world::find_entities(vec2 pos, float radius, entity **ents, int max)
|
|
|
|
{
|
|
|
|
int num = 0;
|
|
|
|
for(entity *ent = first_entity; ent; ent = ent->next_entity)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-10-07 20:23:33 +00:00
|
|
|
if(!(ent->flags&entity::FLAG_PHYSICS))
|
2007-07-15 10:47:50 +00:00
|
|
|
continue;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
if(distance(ent->pos, pos) < radius+ent->proximity_radius)
|
|
|
|
{
|
|
|
|
ents[num] = ent;
|
|
|
|
num++;
|
|
|
|
if(num == max)
|
|
|
|
break;
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
int game_world::find_entities(vec2 pos, float radius, entity **ents, int max, const int* types, int maxtypes)
|
|
|
|
{
|
|
|
|
int num = 0;
|
|
|
|
for(int t = 0; t < maxtypes; t++)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-15 10:47:50 +00:00
|
|
|
for(entity *ent = first_entity_types[types[t]]; ent; ent = ent->next_type_entity)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-10-07 20:23:33 +00:00
|
|
|
if(!(ent->flags&entity::FLAG_PHYSICS))
|
2007-07-14 13:09:42 +00:00
|
|
|
continue;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-05-22 15:03:32 +00:00
|
|
|
if(distance(ent->pos, pos) < radius+ent->proximity_radius)
|
|
|
|
{
|
|
|
|
ents[num] = ent;
|
|
|
|
num++;
|
|
|
|
if(num == max)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
void game_world::insert_entity(entity *ent)
|
|
|
|
{
|
2007-07-25 07:24:57 +00:00
|
|
|
entity *cur = first_entity;
|
|
|
|
while(cur)
|
|
|
|
{
|
|
|
|
dbg_assert(cur != ent, "err");
|
|
|
|
cur = cur->next_entity;
|
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
// insert it
|
|
|
|
if(first_entity)
|
|
|
|
first_entity->prev_entity = ent;
|
|
|
|
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 game_world::destroy_entity(entity *ent)
|
|
|
|
{
|
|
|
|
ent->set_flag(entity::FLAG_DESTROY);
|
|
|
|
}
|
|
|
|
|
|
|
|
void game_world::remove_entity(entity *ent)
|
|
|
|
{
|
2007-08-05 15:42:48 +00:00
|
|
|
// not in the list
|
|
|
|
if(!ent->next_entity && !ent->prev_entity && first_entity != ent)
|
|
|
|
return;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
// remove
|
|
|
|
if(ent->prev_entity)
|
|
|
|
ent->prev_entity->next_entity = ent->next_entity;
|
|
|
|
else
|
|
|
|
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;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-08-05 15:42:48 +00:00
|
|
|
ent->next_entity = 0;
|
|
|
|
ent->prev_entity = 0;
|
|
|
|
ent->next_type_entity = 0;
|
|
|
|
ent->prev_type_entity = 0;
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
void game_world::snap(int snapping_client)
|
|
|
|
{
|
|
|
|
for(entity *ent = first_entity; ent; ent = ent->next_entity)
|
|
|
|
ent->snap(snapping_client);
|
|
|
|
}
|
|
|
|
|
|
|
|
void game_world::reset()
|
|
|
|
{
|
|
|
|
// reset all entities
|
|
|
|
for(entity *ent = first_entity; ent; ent = ent->next_entity)
|
|
|
|
ent->reset();
|
|
|
|
remove_entities();
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
for(entity *ent = first_entity; ent; ent = ent->next_entity)
|
|
|
|
ent->post_reset();
|
|
|
|
remove_entities();
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
reset_requested = false;
|
|
|
|
}
|
2007-07-14 13:09:42 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
void game_world::remove_entities()
|
|
|
|
{
|
|
|
|
// destroy objects marked for destruction
|
|
|
|
entity *ent = first_entity;
|
|
|
|
while(ent)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-15 10:47:50 +00:00
|
|
|
entity *next = ent->next_entity;
|
|
|
|
if(ent->flags&entity::FLAG_DESTROY)
|
|
|
|
{
|
|
|
|
remove_entity(ent);
|
|
|
|
ent->destroy();
|
|
|
|
}
|
|
|
|
ent = next;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void game_world::tick()
|
|
|
|
{
|
|
|
|
if(reset_requested)
|
|
|
|
reset();
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
if(!paused)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-12-16 15:33:44 +00:00
|
|
|
static PERFORMACE_INFO scopes[OBJTYPE_FLAG+1] =
|
|
|
|
{
|
|
|
|
{"null", 0},
|
|
|
|
{"game", 0},
|
|
|
|
{"player_info", 0},
|
|
|
|
{"player_character", 0},
|
|
|
|
{"projectile", 0},
|
|
|
|
{"powerup", 0},
|
|
|
|
{"flag", 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
static PERFORMACE_INFO scopes_def[OBJTYPE_FLAG+1] =
|
|
|
|
{
|
|
|
|
{"null", 0},
|
|
|
|
{"game", 0},
|
|
|
|
{"player_info", 0},
|
|
|
|
{"player_character", 0},
|
|
|
|
{"projectile", 0},
|
|
|
|
{"powerup", 0},
|
|
|
|
{"flag", 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
static PERFORMACE_INFO tick_scope = {"tick", 0};
|
|
|
|
perf_start(&tick_scope);
|
|
|
|
|
2007-05-22 15:03:32 +00:00
|
|
|
// update all objects
|
|
|
|
for(entity *ent = first_entity; ent; ent = ent->next_entity)
|
2007-12-16 14:00:22 +00:00
|
|
|
{
|
2007-12-16 15:33:44 +00:00
|
|
|
if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG)
|
|
|
|
perf_start(&scopes[ent->objtype]);
|
2007-05-22 15:03:32 +00:00
|
|
|
ent->tick();
|
2007-12-16 15:33:44 +00:00
|
|
|
if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG)
|
|
|
|
perf_end();
|
2007-12-16 14:00:22 +00:00
|
|
|
}
|
2007-12-16 15:33:44 +00:00
|
|
|
|
|
|
|
perf_end();
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-12-16 15:33:44 +00:00
|
|
|
static PERFORMACE_INFO deftick_scope = {"tick_defered", 0};
|
|
|
|
perf_start(&deftick_scope);
|
2007-07-13 13:40:04 +00:00
|
|
|
for(entity *ent = first_entity; ent; ent = ent->next_entity)
|
2007-12-16 14:00:22 +00:00
|
|
|
{
|
2007-12-16 15:33:44 +00:00
|
|
|
if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG)
|
|
|
|
perf_start(&scopes_def[ent->objtype]);
|
2007-07-13 13:40:04 +00:00
|
|
|
ent->tick_defered();
|
2007-12-16 15:33:44 +00:00
|
|
|
if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG)
|
|
|
|
perf_end();
|
2007-12-16 14:00:22 +00:00
|
|
|
}
|
2007-12-16 15:33:44 +00:00
|
|
|
perf_end();
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
remove_entities();
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-12-27 17:46:32 +00:00
|
|
|
struct input_count
|
|
|
|
{
|
|
|
|
int presses;
|
|
|
|
int releases;
|
|
|
|
};
|
|
|
|
|
|
|
|
static input_count count_input(int prev, int cur)
|
|
|
|
{
|
|
|
|
input_count c = {0,0};
|
|
|
|
prev &= INPUT_STATE_MASK;
|
|
|
|
cur &= INPUT_STATE_MASK;
|
|
|
|
int i = prev;
|
|
|
|
while(i != cur)
|
|
|
|
{
|
|
|
|
i = (i+1)&INPUT_STATE_MASK;
|
|
|
|
if(i&1)
|
|
|
|
c.presses++;
|
|
|
|
else
|
|
|
|
c.releases++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
//////////////////////////////////////////////////
|
|
|
|
// projectile
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
projectile::projectile(int type, int owner, vec2 pos, vec2 vel, int span, entity* powner,
|
|
|
|
int damage, int flags, float force, int sound_impact, int weapon)
|
|
|
|
: entity(OBJTYPE_PROJECTILE)
|
|
|
|
{
|
|
|
|
this->type = type;
|
|
|
|
this->pos = pos;
|
2008-01-19 10:57:25 +00:00
|
|
|
this->vel = vel * server_tickspeed(); // TODO: remove this
|
2007-07-15 10:47:50 +00:00
|
|
|
this->lifespan = span;
|
|
|
|
this->owner = owner;
|
|
|
|
this->powner = powner;
|
|
|
|
this->flags = flags;
|
|
|
|
this->force = force;
|
|
|
|
this->damage = damage;
|
|
|
|
this->sound_impact = sound_impact;
|
|
|
|
this->weapon = weapon;
|
2007-08-04 19:00:06 +00:00
|
|
|
this->bounce = 0;
|
2007-11-11 21:02:36 +00:00
|
|
|
this->start_tick = server_tick();
|
2007-09-23 22:54:31 +00:00
|
|
|
world->insert_entity(this);
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void projectile::reset()
|
|
|
|
{
|
2007-09-23 22:54:31 +00:00
|
|
|
world->destroy_entity(this);
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void projectile::tick()
|
|
|
|
{
|
2007-11-11 21:02:36 +00:00
|
|
|
float gravity = -400;
|
2008-02-02 18:05:16 +00:00
|
|
|
if(type != WEAPON_GRENADE)
|
2007-12-09 13:51:55 +00:00
|
|
|
gravity = -100;
|
|
|
|
|
2008-01-19 10:57:25 +00:00
|
|
|
float pt = (server_tick()-start_tick-1)/(float)server_tickspeed();
|
|
|
|
float ct = (server_tick()-start_tick)/(float)server_tickspeed();
|
2007-11-11 21:02:36 +00:00
|
|
|
vec2 prevpos = calc_pos(pos, vel, gravity, pt);
|
|
|
|
vec2 curpos = calc_pos(pos, vel, gravity, ct);
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
lifespan--;
|
2007-11-11 21:02:36 +00:00
|
|
|
|
|
|
|
int collide = col_check_point((int)curpos.x, (int)curpos.y);
|
|
|
|
|
2007-07-21 18:07:27 +00:00
|
|
|
vec2 new_pos;
|
2007-11-11 21:02:36 +00:00
|
|
|
entity *targetplayer = (entity*)intersect_player(prevpos, curpos, new_pos, powner);
|
|
|
|
|
2008-01-29 21:39:41 +00:00
|
|
|
if(targetplayer || collide || lifespan < 0)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2008-02-02 18:05:16 +00:00
|
|
|
if (lifespan >= 0 || weapon == WEAPON_GRENADE)
|
2008-02-04 07:36:54 +00:00
|
|
|
create_sound(curpos, sound_impact);
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
if (flags & PROJECTILE_FLAGS_EXPLODE)
|
2007-11-11 21:02:36 +00:00
|
|
|
create_explosion(prevpos, owner, weapon, false);
|
2007-07-15 10:47:50 +00:00
|
|
|
else if (targetplayer)
|
2007-08-04 17:28:31 +00:00
|
|
|
{
|
2007-07-15 10:47:50 +00:00
|
|
|
targetplayer->take_damage(normalize(vel) * max(0.001f, force), damage, owner, weapon);
|
2007-08-04 17:28:31 +00:00
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-09-23 22:54:31 +00:00
|
|
|
world->destroy_entity(this);
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2008-02-10 15:32:30 +00:00
|
|
|
void projectile::fill_info(obj_projectile *proj)
|
|
|
|
{
|
|
|
|
proj->x = (int)pos.x;
|
|
|
|
proj->y = (int)pos.y;
|
|
|
|
proj->vx = (int)vel.x;
|
|
|
|
proj->vy = (int)vel.y;
|
|
|
|
proj->start_tick = start_tick;
|
|
|
|
proj->type = type;
|
|
|
|
}
|
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
void projectile::snap(int snapping_client)
|
|
|
|
{
|
2008-01-19 10:57:25 +00:00
|
|
|
float ct = (server_tick()-start_tick)/(float)server_tickspeed();
|
|
|
|
vec2 curpos = calc_pos(pos, vel, -7.5f*server_tickspeed(), ct);
|
2007-11-11 21:02:36 +00:00
|
|
|
|
|
|
|
if(distance(players[snapping_client].pos, curpos) > 1000.0f)
|
2007-10-28 11:30:25 +00:00
|
|
|
return;
|
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
obj_projectile *proj = (obj_projectile *)snap_new_item(OBJTYPE_PROJECTILE, id, sizeof(obj_projectile));
|
2008-02-10 15:32:30 +00:00
|
|
|
fill_info(proj);
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2008-02-02 18:05:16 +00:00
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
// laser
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
laser::laser(vec2 pos, vec2 direction, float start_energy, player *owner)
|
|
|
|
: entity(OBJTYPE_LASER)
|
|
|
|
{
|
|
|
|
this->pos = pos;
|
|
|
|
this->owner = owner;
|
|
|
|
energy = start_energy;
|
|
|
|
dir = direction;
|
|
|
|
bounces = 0;
|
|
|
|
do_bounce();
|
|
|
|
|
|
|
|
world->insert_entity(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool laser::hit_player(vec2 from, vec2 to)
|
|
|
|
{
|
|
|
|
vec2 at;
|
|
|
|
player *hit = intersect_player(pos, to, at, owner);
|
|
|
|
if(!hit)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
this->from = from;
|
|
|
|
pos = at;
|
|
|
|
energy = -1;
|
2008-02-04 07:59:25 +00:00
|
|
|
hit->take_damage(vec2(0,0), tuning.laser_damage, owner->client_id, WEAPON_RIFLE);
|
2008-02-02 18:05:16 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void laser::do_bounce()
|
|
|
|
{
|
|
|
|
eval_tick = server_tick();
|
|
|
|
|
|
|
|
if(energy < 0)
|
|
|
|
{
|
|
|
|
//dbg_msg("laser", "%d removed", server_tick());
|
|
|
|
world->destroy_entity(this);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vec2 to = pos + dir*energy;
|
|
|
|
|
|
|
|
if(col_intersect_line(pos, to, &to))
|
|
|
|
{
|
|
|
|
if(!hit_player(pos, to))
|
|
|
|
{
|
|
|
|
// intersected
|
|
|
|
from = pos;
|
|
|
|
pos = to - dir*2;
|
|
|
|
vec2 temp_pos = pos;
|
|
|
|
vec2 temp_dir = dir*4.0f;
|
|
|
|
|
|
|
|
move_point(&temp_pos, &temp_dir, 1.0f, 0);
|
|
|
|
dir = normalize(temp_dir);
|
|
|
|
|
|
|
|
energy -= distance(from, pos) + tuning.laser_bounce_cost;
|
|
|
|
bounces++;
|
|
|
|
|
|
|
|
if(bounces > tuning.laser_bounce_num)
|
|
|
|
energy = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(!hit_player(pos, to))
|
|
|
|
{
|
|
|
|
from = pos;
|
|
|
|
pos = to;
|
|
|
|
energy = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//dbg_msg("laser", "%d done %f %f %f %f", server_tick(), from.x, from.y, pos.x, pos.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
void laser::reset()
|
|
|
|
{
|
|
|
|
world->destroy_entity(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void laser::tick()
|
|
|
|
{
|
|
|
|
if(server_tick() > eval_tick+(server_tickspeed()*tuning.laser_bounce_delay)/1000.0f)
|
|
|
|
do_bounce();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void laser::snap(int snapping_client)
|
|
|
|
{
|
|
|
|
if(distance(players[snapping_client].pos, pos) > 1000.0f)
|
|
|
|
return;
|
|
|
|
|
|
|
|
obj_laser *obj = (obj_laser *)snap_new_item(OBJTYPE_LASER, id, sizeof(obj_laser));
|
|
|
|
obj->x = (int)pos.x;
|
|
|
|
obj->y = (int)pos.y;
|
|
|
|
obj->from_x = (int)from.x;
|
|
|
|
obj->from_y = (int)from.y;
|
|
|
|
obj->eval_tick = eval_tick;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
//////////////////////////////////////////////////
|
|
|
|
// player
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
// TODO: move to separate file
|
|
|
|
player::player()
|
2007-10-28 11:30:25 +00:00
|
|
|
: entity(OBJTYPE_PLAYER_CHARACTER)
|
2007-07-15 10:47:50 +00:00
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
void player::init()
|
|
|
|
{
|
|
|
|
proximity_radius = phys_size;
|
|
|
|
client_id = -1;
|
2007-10-07 20:23:33 +00:00
|
|
|
team = -1; // -1 == spectator
|
2007-08-14 18:37:16 +00:00
|
|
|
|
|
|
|
latency_accum = 0;
|
|
|
|
latency_accum_min = 0;
|
|
|
|
latency_accum_max = 0;
|
|
|
|
latency_avg = 0;
|
|
|
|
latency_min = 0;
|
|
|
|
latency_max = 0;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void player::reset()
|
|
|
|
{
|
|
|
|
pos = vec2(0.0f, 0.0f);
|
2007-09-09 18:21:14 +00:00
|
|
|
core.vel = vec2(0.0f, 0.0f);
|
|
|
|
//direction = vec2(0.0f, 1.0f);
|
2007-07-15 10:47:50 +00:00
|
|
|
score = 0;
|
|
|
|
dead = true;
|
2007-10-28 11:30:25 +00:00
|
|
|
clear_flag(entity::FLAG_PHYSICS);
|
2007-08-02 20:17:18 +00:00
|
|
|
spawning = false;
|
2007-07-15 10:47:50 +00:00
|
|
|
die_tick = 0;
|
2007-12-18 23:21:57 +00:00
|
|
|
die_pos = vec2(0,0);
|
2007-08-05 09:12:38 +00:00
|
|
|
damage_taken = 0;
|
2008-01-29 21:55:13 +00:00
|
|
|
player_state = PLAYERSTATE_UNKNOWN;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-08-14 18:37:16 +00:00
|
|
|
mem_zero(&input, sizeof(input));
|
|
|
|
mem_zero(&previnput, sizeof(previnput));
|
2007-12-09 16:10:12 +00:00
|
|
|
num_inputs = 0;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-08-10 11:55:59 +00:00
|
|
|
last_action = -1;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-08-14 18:37:16 +00:00
|
|
|
emote_stop = 0;
|
|
|
|
damage_taken_tick = 0;
|
|
|
|
attack_tick = 0;
|
2007-12-13 20:28:22 +00:00
|
|
|
numobjectshit = 0;
|
2008-01-29 21:55:13 +00:00
|
|
|
|
|
|
|
mem_zero(&ninja, sizeof(ninja));
|
2007-12-10 19:13:00 +00:00
|
|
|
|
|
|
|
active_weapon = WEAPON_GUN;
|
|
|
|
last_weapon = WEAPON_HAMMER;
|
|
|
|
wanted_weapon = WEAPON_GUN;
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
void player::destroy() { }
|
2007-08-14 18:37:16 +00:00
|
|
|
|
|
|
|
void player::set_weapon(int w)
|
|
|
|
{
|
|
|
|
last_weapon = active_weapon;
|
|
|
|
active_weapon = w;
|
2007-12-10 19:13:00 +00:00
|
|
|
if(active_weapon < 0 || active_weapon >= NUM_WEAPONS)
|
|
|
|
active_weapon = 0;
|
2007-08-14 18:37:16 +00:00
|
|
|
}
|
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
void player::respawn()
|
|
|
|
{
|
2007-08-02 20:17:18 +00:00
|
|
|
spawning = true;
|
|
|
|
}
|
|
|
|
|
2007-12-16 23:48:48 +00:00
|
|
|
const char *get_team_name(int team)
|
|
|
|
{
|
|
|
|
if(gameobj->gametype == GAMETYPE_DM)
|
|
|
|
{
|
|
|
|
if(team == 0)
|
|
|
|
return "game";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(team == 0)
|
|
|
|
return "red team";
|
|
|
|
else if(team == 1)
|
|
|
|
return "blue team";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "spectators";
|
|
|
|
}
|
2007-10-07 20:23:33 +00:00
|
|
|
|
|
|
|
void player::set_team(int new_team)
|
|
|
|
{
|
2007-12-18 23:21:57 +00:00
|
|
|
// clamp the team
|
|
|
|
new_team = gameobj->clampteam(new_team);
|
2007-12-16 23:48:48 +00:00
|
|
|
if(team == new_team)
|
|
|
|
return;
|
|
|
|
|
|
|
|
char buf[512];
|
|
|
|
sprintf(buf, "%s joined the %s", server_clientname(client_id), get_team_name(new_team));
|
|
|
|
send_chat(-1, -1, buf);
|
|
|
|
|
2007-10-07 20:23:33 +00:00
|
|
|
team = new_team;
|
|
|
|
die(client_id, -1);
|
2007-12-16 23:48:48 +00:00
|
|
|
score = 0;
|
2008-01-30 13:15:58 +00:00
|
|
|
dbg_msg("game", "team_join player='%d:%s' team=%d", client_id, server_clientname(client_id), team);
|
2007-10-07 20:23:33 +00:00
|
|
|
}
|
|
|
|
|
2008-01-13 11:15:32 +00:00
|
|
|
vec2 spawn_points[3][64];
|
|
|
|
int num_spawn_points[3] = {0};
|
|
|
|
|
2007-12-18 23:21:57 +00:00
|
|
|
struct spawneval
|
|
|
|
{
|
|
|
|
spawneval()
|
|
|
|
{
|
|
|
|
got = false;
|
|
|
|
friendly_team = -1;
|
|
|
|
die_pos = vec2(0,0);
|
|
|
|
pos = vec2(100,100);
|
|
|
|
}
|
|
|
|
|
|
|
|
vec2 pos;
|
|
|
|
bool got;
|
|
|
|
int friendly_team;
|
|
|
|
float score;
|
|
|
|
vec2 die_pos;
|
|
|
|
};
|
|
|
|
|
|
|
|
static float evaluate_spawn(spawneval *eval, vec2 pos)
|
|
|
|
{
|
|
|
|
float score = 0.0f;
|
|
|
|
|
|
|
|
for(int c = 0; c < MAX_CLIENTS; c++)
|
|
|
|
{
|
|
|
|
if(players[c].client_id == -1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// don't count dead people
|
|
|
|
if(!(players[c].flags&entity::FLAG_PHYSICS))
|
|
|
|
continue;
|
|
|
|
|
2008-01-12 12:08:26 +00:00
|
|
|
// team mates are not as dangerous as enemies
|
|
|
|
float scoremod = 1.0f;
|
2007-12-18 23:21:57 +00:00
|
|
|
if(eval->friendly_team != -1 && players[c].team == eval->friendly_team)
|
2008-01-12 12:08:26 +00:00
|
|
|
scoremod = 0.5f;
|
2007-12-18 23:21:57 +00:00
|
|
|
|
|
|
|
float d = distance(pos, players[c].pos);
|
|
|
|
if(d == 0)
|
|
|
|
score += 1000000000.0f;
|
|
|
|
else
|
|
|
|
score += 1.0f/d;
|
|
|
|
}
|
|
|
|
|
|
|
|
// weight in the die posititon
|
|
|
|
float d = distance(pos, eval->die_pos);
|
|
|
|
if(d == 0)
|
|
|
|
score += 1000000000.0f;
|
|
|
|
else
|
|
|
|
score += 1.0f/d;
|
|
|
|
|
|
|
|
return score;
|
|
|
|
}
|
2007-10-07 20:23:33 +00:00
|
|
|
|
2007-12-18 23:21:57 +00:00
|
|
|
static void evaluate_spawn_type(spawneval *eval, int t)
|
2007-08-02 20:17:18 +00:00
|
|
|
{
|
|
|
|
// get spawn point
|
2008-01-13 11:15:32 +00:00
|
|
|
/*
|
2007-08-02 20:17:18 +00:00
|
|
|
int start, num;
|
2007-08-30 07:15:26 +00:00
|
|
|
map_get_type(t, &start, &num);
|
|
|
|
if(!num)
|
2007-12-18 23:21:57 +00:00
|
|
|
return;
|
2008-01-13 11:15:32 +00:00
|
|
|
*/
|
|
|
|
for(int i = 0; i < num_spawn_points[t]; i++)
|
2007-12-18 23:21:57 +00:00
|
|
|
{
|
2008-01-13 11:15:32 +00:00
|
|
|
//num_spawn_points[t]
|
|
|
|
//mapres_spawnpoint *sp = (mapres_spawnpoint*)map_get_item(start + i, NULL, NULL);
|
|
|
|
vec2 p = spawn_points[t][i];// vec2((float)sp->x, (float)sp->y);
|
2007-12-18 23:21:57 +00:00
|
|
|
float s = evaluate_spawn(eval, p);
|
|
|
|
if(!eval->got || eval->score > s)
|
|
|
|
{
|
|
|
|
eval->got = true;
|
|
|
|
eval->score = s;
|
|
|
|
eval->pos = p;
|
|
|
|
}
|
|
|
|
}
|
2007-08-30 07:15:26 +00:00
|
|
|
}
|
2007-08-02 20:17:18 +00:00
|
|
|
|
2007-08-30 07:15:26 +00:00
|
|
|
void player::try_respawn()
|
|
|
|
{
|
2007-08-02 20:17:18 +00:00
|
|
|
vec2 spawnpos = vec2(100.0f, -60.0f);
|
2007-12-10 19:13:00 +00:00
|
|
|
|
2007-08-30 07:15:26 +00:00
|
|
|
// get spawn point
|
2007-12-18 23:21:57 +00:00
|
|
|
spawneval eval;
|
|
|
|
eval.die_pos = die_pos;
|
|
|
|
|
2008-01-13 11:15:32 +00:00
|
|
|
eval.pos = vec2(100, 100);
|
|
|
|
|
2007-08-30 07:15:26 +00:00
|
|
|
if(gameobj->gametype == GAMETYPE_CTF)
|
2007-08-02 20:17:18 +00:00
|
|
|
{
|
2007-12-18 23:21:57 +00:00
|
|
|
eval.friendly_team = team;
|
|
|
|
|
2007-08-30 07:15:26 +00:00
|
|
|
// try first try own team spawn, then normal spawn and then enemy
|
2008-01-13 11:15:32 +00:00
|
|
|
evaluate_spawn_type(&eval, 1+(team&1));
|
2007-12-18 23:21:57 +00:00
|
|
|
if(!eval.got)
|
2007-08-30 07:15:26 +00:00
|
|
|
{
|
2008-01-13 11:15:32 +00:00
|
|
|
evaluate_spawn_type(&eval, 0);
|
2007-12-18 23:21:57 +00:00
|
|
|
if(!eval.got)
|
2008-01-13 11:15:32 +00:00
|
|
|
evaluate_spawn_type(&eval, 1+((team+1)&1));
|
2007-08-30 07:15:26 +00:00
|
|
|
}
|
2007-08-02 20:17:18 +00:00
|
|
|
}
|
2007-08-30 07:15:26 +00:00
|
|
|
else
|
|
|
|
{
|
2007-12-18 23:21:57 +00:00
|
|
|
if(gameobj->gametype == GAMETYPE_TDM)
|
|
|
|
eval.friendly_team = team;
|
|
|
|
|
2008-01-13 11:15:32 +00:00
|
|
|
evaluate_spawn_type(&eval, 0);
|
|
|
|
evaluate_spawn_type(&eval, 1);
|
|
|
|
evaluate_spawn_type(&eval, 2);
|
2007-08-30 07:15:26 +00:00
|
|
|
}
|
2007-12-18 23:21:57 +00:00
|
|
|
|
|
|
|
spawnpos = eval.pos;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-08-02 20:17:18 +00:00
|
|
|
// check if the position is occupado
|
|
|
|
entity *ents[2] = {0};
|
2007-10-28 11:30:25 +00:00
|
|
|
int types[] = {OBJTYPE_PLAYER_CHARACTER};
|
2007-09-23 22:54:31 +00:00
|
|
|
int num_ents = world->find_entities(spawnpos, 64, ents, 2, types, 1);
|
2007-08-02 20:17:18 +00:00
|
|
|
for(int i = 0; i < num_ents; i++)
|
|
|
|
{
|
|
|
|
if(ents[i] != this)
|
|
|
|
return;
|
|
|
|
}
|
2007-12-13 22:22:25 +00:00
|
|
|
|
2007-08-02 20:17:18 +00:00
|
|
|
spawning = false;
|
|
|
|
pos = spawnpos;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-09-09 18:21:14 +00:00
|
|
|
core.pos = pos;
|
2007-10-28 11:30:25 +00:00
|
|
|
core.vel = vec2(0,0);
|
2007-09-09 18:21:14 +00:00
|
|
|
core.hooked_player = -1;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-08-30 07:15:26 +00:00
|
|
|
health = 10;
|
2007-07-15 10:47:50 +00:00
|
|
|
armor = 0;
|
|
|
|
jumped = 0;
|
2007-12-15 12:04:48 +00:00
|
|
|
|
2008-01-29 21:55:13 +00:00
|
|
|
mem_zero(&ninja, sizeof(ninja));
|
2007-12-15 12:04:48 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
dead = false;
|
2007-10-07 20:23:33 +00:00
|
|
|
set_flag(entity::FLAG_PHYSICS);
|
2008-01-29 21:55:13 +00:00
|
|
|
player_state = PLAYERSTATE_PLAYING;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-09-09 18:21:14 +00:00
|
|
|
core.hook_state = HOOK_IDLE;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
mem_zero(&input, sizeof(input));
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
// init weapons
|
|
|
|
mem_zero(&weapons, sizeof(weapons));
|
|
|
|
weapons[WEAPON_HAMMER].got = true;
|
|
|
|
weapons[WEAPON_HAMMER].ammo = -1;
|
|
|
|
weapons[WEAPON_GUN].got = true;
|
2007-08-14 18:37:16 +00:00
|
|
|
weapons[WEAPON_GUN].ammo = data->weapons[WEAPON_GUN].maxammo;
|
2007-10-14 13:54:02 +00:00
|
|
|
|
2008-02-04 07:59:25 +00:00
|
|
|
weapons[WEAPON_RIFLE].got = true;
|
|
|
|
weapons[WEAPON_RIFLE].ammo = 100000; //data->weapons[WEAPON_LASER].maxammo;
|
2008-02-02 18:05:16 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
active_weapon = WEAPON_GUN;
|
2007-08-14 18:37:16 +00:00
|
|
|
last_weapon = WEAPON_HAMMER;
|
2007-12-09 17:15:18 +00:00
|
|
|
wanted_weapon = WEAPON_GUN;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
reload_timer = 0;
|
2007-08-09 00:18:11 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
// Create sound and spawn effects
|
2007-07-15 10:47:50 +00:00
|
|
|
create_sound(pos, SOUND_PLAYER_SPAWN);
|
2008-01-29 21:39:41 +00:00
|
|
|
create_playerspawn(pos);
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-09-25 21:53:14 +00:00
|
|
|
gameobj->on_player_spawn(this);
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
bool player::is_grounded()
|
|
|
|
{
|
|
|
|
if(col_check_point((int)(pos.x+phys_size/2), (int)(pos.y+phys_size/2+5)))
|
|
|
|
return true;
|
|
|
|
if(col_check_point((int)(pos.x-phys_size/2), (int)(pos.y+phys_size/2+5)))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-12-09 15:38:19 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
int player::handle_ninja()
|
|
|
|
{
|
2008-01-12 12:08:26 +00:00
|
|
|
vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y));
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2008-01-29 21:55:13 +00:00
|
|
|
if ((server_tick() - ninja.activationtick) > (data->weapons[WEAPON_NINJA].duration * server_tickspeed() / 1000))
|
2007-07-21 19:03:50 +00:00
|
|
|
{
|
|
|
|
// time's up, return
|
2007-12-10 21:14:45 +00:00
|
|
|
weapons[WEAPON_NINJA].got = false;
|
2007-08-14 18:37:16 +00:00
|
|
|
active_weapon = last_weapon;
|
2007-12-10 19:13:00 +00:00
|
|
|
set_weapon(active_weapon);
|
2007-07-21 19:03:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
// Check if it should activate
|
2008-01-29 21:55:13 +00:00
|
|
|
if (count_input(latest_previnput.fire, latest_input.fire).presses && (server_tick() > ninja.currentcooldown))
|
2007-07-21 19:03:50 +00:00
|
|
|
{
|
|
|
|
// ok then, activate ninja
|
|
|
|
attack_tick = server_tick();
|
2008-01-29 21:55:13 +00:00
|
|
|
ninja.activationdir = direction;
|
|
|
|
ninja.currentmovetime = data->weapons[WEAPON_NINJA].movetime * server_tickspeed() / 1000;
|
|
|
|
ninja.currentcooldown = data->weapons[WEAPON_NINJA].firedelay * server_tickspeed() / 1000 + server_tick();
|
2007-12-13 20:28:22 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
// reset hit objects
|
|
|
|
numobjectshit = 0;
|
|
|
|
|
|
|
|
create_sound(pos, SOUND_NINJA_FIRE);
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-08-04 08:31:44 +00:00
|
|
|
// release all hooks when ninja is activated
|
2007-09-25 21:53:14 +00:00
|
|
|
//release_hooked();
|
|
|
|
//release_hooks();
|
2007-07-21 19:03:50 +00:00
|
|
|
}
|
|
|
|
|
2008-01-29 21:55:13 +00:00
|
|
|
ninja.currentmovetime--;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2008-01-29 21:55:13 +00:00
|
|
|
if (ninja.currentmovetime == 0)
|
2007-10-28 11:30:25 +00:00
|
|
|
{
|
2007-07-21 19:03:50 +00:00
|
|
|
// reset player velocity
|
2007-09-09 18:21:14 +00:00
|
|
|
core.vel *= 0.2f;
|
2007-07-21 19:03:50 +00:00
|
|
|
//return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON;
|
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2008-01-29 21:55:13 +00:00
|
|
|
if (ninja.currentmovetime > 0)
|
2007-07-21 19:03:50 +00:00
|
|
|
{
|
|
|
|
// Set player velocity
|
2008-01-29 21:55:13 +00:00
|
|
|
core.vel = ninja.activationdir * data->weapons[WEAPON_NINJA].velocity;
|
2007-07-21 19:03:50 +00:00
|
|
|
vec2 oldpos = pos;
|
2007-09-09 18:21:14 +00:00
|
|
|
move_box(&core.pos, &core.vel, vec2(phys_size, phys_size), 0.0f);
|
2007-07-21 19:03:50 +00:00
|
|
|
// reset velocity so the client doesn't predict stuff
|
2007-09-09 18:21:14 +00:00
|
|
|
core.vel = vec2(0.0f,0.0f);
|
2008-01-29 21:55:13 +00:00
|
|
|
if ((ninja.currentmovetime % 2) == 0)
|
2007-07-21 19:03:50 +00:00
|
|
|
{
|
|
|
|
create_smoke(pos);
|
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
// check if we hit anything along the way
|
|
|
|
{
|
2007-10-28 11:30:25 +00:00
|
|
|
int type = OBJTYPE_PLAYER_CHARACTER;
|
2007-07-21 19:03:50 +00:00
|
|
|
entity *ents[64];
|
|
|
|
vec2 dir = pos - oldpos;
|
2007-07-22 13:46:45 +00:00
|
|
|
float radius = phys_size * 2.0f; //length(dir * 0.5f);
|
2007-07-21 19:03:50 +00:00
|
|
|
vec2 center = oldpos + dir * 0.5f;
|
2007-09-23 22:54:31 +00:00
|
|
|
int num = world->find_entities(center, radius, ents, 64, &type, 1);
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
for (int i = 0; i < num; i++)
|
|
|
|
{
|
|
|
|
// Check if entity is a player
|
|
|
|
if (ents[i] == this)
|
|
|
|
continue;
|
|
|
|
// make sure we haven't hit this object before
|
|
|
|
bool balreadyhit = false;
|
|
|
|
for (int j = 0; j < numobjectshit; j++)
|
|
|
|
{
|
|
|
|
if (hitobjects[j] == ents[i])
|
|
|
|
balreadyhit = true;
|
|
|
|
}
|
|
|
|
if (balreadyhit)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// check so we are sufficiently close
|
|
|
|
if (distance(ents[i]->pos, pos) > (phys_size * 2.0f))
|
|
|
|
continue;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
// hit a player, give him damage and stuffs...
|
|
|
|
create_sound(ents[i]->pos, SOUND_NINJA_HIT);
|
|
|
|
// set his velocity to fast upward (for now)
|
2007-12-12 19:52:57 +00:00
|
|
|
if(numobjectshit < 10)
|
|
|
|
hitobjects[numobjectshit++] = ents[i];
|
2007-08-05 08:59:38 +00:00
|
|
|
ents[i]->take_damage(vec2(0,10.0f), data->weapons[WEAPON_NINJA].meleedamage, client_id,WEAPON_NINJA);
|
2007-07-21 19:03:50 +00:00
|
|
|
}
|
|
|
|
}
|
2008-01-29 21:55:13 +00:00
|
|
|
return 0;
|
2007-12-15 12:04:48 +00:00
|
|
|
}
|
2007-10-14 13:54:02 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-10 15:32:30 +00:00
|
|
|
void player::fire_weapon()
|
|
|
|
{
|
|
|
|
if(reload_timer != 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y));
|
|
|
|
|
|
|
|
bool fullauto = false;
|
|
|
|
if(active_weapon == WEAPON_GRENADE || active_weapon == WEAPON_SHOTGUN)
|
|
|
|
fullauto = true;
|
|
|
|
|
|
|
|
//if(count_input(latest_previnput.fire, latest_input.fire).presses) || ((fullauto && latest_input.fire&1) && weapons[active_weapon].ammo))
|
|
|
|
if(!count_input(latest_previnput.fire, latest_input.fire).presses)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// check for ammo
|
|
|
|
if(!weapons[active_weapon].ammo)
|
|
|
|
{
|
|
|
|
create_sound(pos, SOUND_WEAPON_NOAMMO);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch(active_weapon)
|
|
|
|
{
|
|
|
|
case WEAPON_HAMMER:
|
|
|
|
{
|
|
|
|
// reset objects hit
|
|
|
|
numobjectshit = 0;
|
|
|
|
create_sound(pos, SOUND_HAMMER_FIRE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case WEAPON_GUN:
|
|
|
|
{
|
|
|
|
projectile *proj = new projectile(WEAPON_GUN,
|
|
|
|
client_id,
|
|
|
|
pos+vec2(0,0),
|
|
|
|
direction*tuning.gun_speed,
|
|
|
|
server_tickspeed(),
|
|
|
|
this,
|
|
|
|
1, 0, 0, -1, WEAPON_GUN);
|
|
|
|
|
|
|
|
// pack the projectile and send it to the client directly
|
|
|
|
obj_projectile p;
|
|
|
|
proj->fill_info(&p);
|
|
|
|
|
|
|
|
msg_pack_start(MSG_EXTRA_PROJECTILE, 0);
|
|
|
|
msg_pack_int(1);
|
|
|
|
for(unsigned i = 0; i < sizeof(obj_projectile)/sizeof(int); i++)
|
|
|
|
msg_pack_int(((int *)&p)[i]);
|
|
|
|
msg_pack_end();
|
|
|
|
server_send_msg(client_id);
|
|
|
|
|
|
|
|
create_sound(pos, SOUND_GUN_FIRE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WEAPON_GRENADE:
|
|
|
|
{
|
|
|
|
projectile *proj = new projectile(WEAPON_GRENADE,
|
|
|
|
client_id,
|
|
|
|
pos+vec2(0,0),
|
|
|
|
direction*tuning.grenade_speed,
|
|
|
|
100,
|
|
|
|
this,
|
|
|
|
1, projectile::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE);
|
|
|
|
|
|
|
|
// pack the projectile and send it to the client directly
|
|
|
|
obj_projectile p;
|
|
|
|
proj->fill_info(&p);
|
|
|
|
|
|
|
|
msg_pack_start(MSG_EXTRA_PROJECTILE, 0);
|
|
|
|
msg_pack_int(1);
|
|
|
|
for(unsigned i = 0; i < sizeof(obj_projectile)/sizeof(int); i++)
|
|
|
|
msg_pack_int(((int *)&p)[i]);
|
|
|
|
msg_pack_end();
|
|
|
|
server_send_msg(client_id);
|
|
|
|
|
|
|
|
create_sound(pos, SOUND_GRENADE_FIRE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WEAPON_SHOTGUN:
|
|
|
|
{
|
|
|
|
int shotspread = 2;
|
|
|
|
|
|
|
|
msg_pack_start(MSG_EXTRA_PROJECTILE, 0);
|
|
|
|
msg_pack_int(shotspread*2+1);
|
|
|
|
|
|
|
|
for(int i = -shotspread; i <= shotspread; i++)
|
|
|
|
{
|
|
|
|
float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f};
|
|
|
|
float a = get_angle(direction);
|
|
|
|
float v = 1.0f-fabs(i/(float)shotspread);
|
|
|
|
a += spreading[i+2];
|
|
|
|
float speed = mix((float)tuning.shotgun_speed_wide, (float)tuning.shotgun_speed_center, v);
|
|
|
|
projectile *proj = new projectile(WEAPON_SHOTGUN,
|
|
|
|
client_id,
|
|
|
|
pos+vec2(0,0),
|
|
|
|
vec2(cosf(a), sinf(a))*speed,
|
|
|
|
(int)(server_tickspeed()*0.25f),
|
|
|
|
this,
|
|
|
|
1, 0, 0, -1, WEAPON_SHOTGUN);
|
|
|
|
|
|
|
|
// pack the projectile and send it to the client directly
|
|
|
|
obj_projectile p;
|
|
|
|
proj->fill_info(&p);
|
|
|
|
|
|
|
|
for(unsigned i = 0; i < sizeof(obj_projectile)/sizeof(int); i++)
|
|
|
|
msg_pack_int(((int *)&p)[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
msg_pack_end();
|
|
|
|
server_send_msg(client_id);
|
|
|
|
|
|
|
|
create_sound(pos, SOUND_SHOTGUN_FIRE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case WEAPON_RIFLE:
|
|
|
|
{
|
|
|
|
new laser(pos, direction, tuning.laser_reach, this);
|
|
|
|
create_sound(pos, SOUND_RIFLE_FIRE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
weapons[active_weapon].ammo--;
|
|
|
|
attack_tick = server_tick();
|
|
|
|
reload_timer = data->weapons[active_weapon].firedelay * server_tickspeed() / 1000;
|
|
|
|
}
|
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
int player::handle_weapons()
|
2007-07-15 10:47:50 +00:00
|
|
|
{
|
2008-01-12 12:08:26 +00:00
|
|
|
vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y));
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-12-11 23:10:07 +00:00
|
|
|
if(config.dbg_stress)
|
2007-08-14 18:37:16 +00:00
|
|
|
{
|
|
|
|
for(int i = 0; i < NUM_WEAPONS; i++)
|
|
|
|
{
|
|
|
|
weapons[i].got = true;
|
|
|
|
weapons[i].ammo = 10;
|
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-08-14 18:37:16 +00:00
|
|
|
if(reload_timer) // twice as fast reload
|
|
|
|
reload_timer--;
|
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
// check reload timer
|
|
|
|
if(reload_timer)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-15 10:47:50 +00:00
|
|
|
reload_timer--;
|
2007-07-21 19:03:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2007-12-09 17:15:18 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
if (active_weapon == WEAPON_NINJA)
|
|
|
|
{
|
|
|
|
// don't update other weapons while ninja is active
|
|
|
|
return handle_ninja();
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-12-09 17:15:18 +00:00
|
|
|
// select weapon
|
2008-01-12 12:08:26 +00:00
|
|
|
int next = count_input(latest_previnput.next_weapon, latest_input.next_weapon).presses;
|
|
|
|
int prev = count_input(latest_previnput.prev_weapon, latest_input.prev_weapon).presses;
|
2007-12-10 19:13:00 +00:00
|
|
|
|
|
|
|
if(next < 128) // make sure we only try sane stuff
|
2007-08-04 16:49:57 +00:00
|
|
|
{
|
2007-12-10 19:13:00 +00:00
|
|
|
while(next) // next weapon selection
|
|
|
|
{
|
|
|
|
wanted_weapon = (wanted_weapon+1)%NUM_WEAPONS;
|
|
|
|
if(weapons[wanted_weapon].got)
|
|
|
|
next--;
|
|
|
|
}
|
2007-12-09 17:15:18 +00:00
|
|
|
}
|
2007-10-07 23:43:14 +00:00
|
|
|
|
2007-12-10 19:13:00 +00:00
|
|
|
if(prev < 128) // make sure we only try sane stuff
|
2007-12-09 17:15:18 +00:00
|
|
|
{
|
2007-12-10 19:13:00 +00:00
|
|
|
while(prev) // prev weapon selection
|
|
|
|
{
|
|
|
|
wanted_weapon = (wanted_weapon-1)<0?NUM_WEAPONS-1:wanted_weapon-1;
|
|
|
|
if(weapons[wanted_weapon].got)
|
|
|
|
prev--;
|
|
|
|
}
|
2007-12-09 17:15:18 +00:00
|
|
|
}
|
|
|
|
|
2008-01-12 12:08:26 +00:00
|
|
|
if(latest_input.wanted_weapon) // direct weapon selection
|
2007-12-09 17:15:18 +00:00
|
|
|
wanted_weapon = input.wanted_weapon-1;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-12-10 19:13:00 +00:00
|
|
|
if(wanted_weapon < 0 || wanted_weapon >= NUM_WEAPONS)
|
|
|
|
wanted_weapon = 0;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-12-09 17:15:18 +00:00
|
|
|
// switch weapon if wanted
|
|
|
|
if(data->weapons[active_weapon].duration <= 0)
|
|
|
|
{
|
2007-12-10 19:13:00 +00:00
|
|
|
if(wanted_weapon != -1 && wanted_weapon != active_weapon && wanted_weapon >= 0 && wanted_weapon < NUM_WEAPONS && weapons[wanted_weapon].got)
|
2007-10-04 22:37:35 +00:00
|
|
|
{
|
2007-12-09 17:15:18 +00:00
|
|
|
if(active_weapon != wanted_weapon)
|
2007-10-04 22:37:35 +00:00
|
|
|
create_sound(pos, SOUND_WEAPON_SWITCH);
|
2007-08-04 16:49:57 +00:00
|
|
|
|
2007-12-10 19:13:00 +00:00
|
|
|
set_weapon(wanted_weapon);
|
2007-10-04 22:37:35 +00:00
|
|
|
}
|
2007-08-04 16:49:57 +00:00
|
|
|
}
|
2007-10-14 13:54:02 +00:00
|
|
|
|
2008-02-10 15:32:30 +00:00
|
|
|
//if(reload_timer == 0)
|
|
|
|
fire_weapon();
|
|
|
|
//}
|
|
|
|
/*
|
2007-12-18 20:33:34 +00:00
|
|
|
bool fullauto = false;
|
2008-02-02 18:05:16 +00:00
|
|
|
if(active_weapon == WEAPON_GRENADE || active_weapon == WEAPON_SHOTGUN)
|
2007-12-18 20:33:34 +00:00
|
|
|
fullauto = true;
|
|
|
|
|
2008-01-12 12:08:26 +00:00
|
|
|
if(count_input(latest_previnput.fire, latest_input.fire).presses || ((fullauto && latest_input.fire&1) && weapons[active_weapon].ammo))
|
2007-07-13 13:40:04 +00:00
|
|
|
{
|
2007-07-15 10:47:50 +00:00
|
|
|
// fire!
|
|
|
|
if(weapons[active_weapon].ammo)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-15 10:47:50 +00:00
|
|
|
switch(active_weapon)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-15 10:47:50 +00:00
|
|
|
case WEAPON_HAMMER:
|
2007-12-15 12:04:48 +00:00
|
|
|
{
|
2007-07-21 19:03:50 +00:00
|
|
|
// reset objects hit
|
|
|
|
numobjectshit = 0;
|
2007-07-21 17:35:28 +00:00
|
|
|
create_sound(pos, SOUND_HAMMER_FIRE);
|
2007-07-15 10:47:50 +00:00
|
|
|
break;
|
2007-12-15 12:04:48 +00:00
|
|
|
}
|
2007-07-13 13:40:04 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
case WEAPON_GUN:
|
2007-12-15 12:04:48 +00:00
|
|
|
{
|
2007-10-04 23:58:22 +00:00
|
|
|
new projectile(WEAPON_GUN,
|
2007-07-15 10:47:50 +00:00
|
|
|
client_id,
|
|
|
|
pos+vec2(0,0),
|
2008-02-02 18:05:16 +00:00
|
|
|
direction*tuning.gun_speed,
|
2008-01-29 21:39:41 +00:00
|
|
|
server_tickspeed(),
|
2007-07-15 10:47:50 +00:00
|
|
|
this,
|
|
|
|
1, 0, 0, -1, WEAPON_GUN);
|
2007-07-21 17:35:28 +00:00
|
|
|
create_sound(pos, SOUND_GUN_FIRE);
|
2007-07-15 10:47:50 +00:00
|
|
|
break;
|
2007-12-15 12:04:48 +00:00
|
|
|
}
|
2008-02-02 18:05:16 +00:00
|
|
|
case WEAPON_GRENADE:
|
2007-08-04 19:00:06 +00:00
|
|
|
{
|
2008-02-02 18:05:16 +00:00
|
|
|
new projectile(WEAPON_GRENADE,
|
2007-07-15 10:47:50 +00:00
|
|
|
client_id,
|
|
|
|
pos+vec2(0,0),
|
2008-02-02 18:05:16 +00:00
|
|
|
direction*tuning.grenade_speed,
|
2007-07-15 10:47:50 +00:00
|
|
|
100,
|
|
|
|
this,
|
2008-02-02 18:05:16 +00:00
|
|
|
1, projectile::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE);
|
|
|
|
create_sound(pos, SOUND_GRENADE_FIRE);
|
2007-07-15 10:47:50 +00:00
|
|
|
break;
|
2007-08-04 19:00:06 +00:00
|
|
|
}
|
2007-07-15 10:47:50 +00:00
|
|
|
case WEAPON_SHOTGUN:
|
2007-08-04 01:57:01 +00:00
|
|
|
{
|
2007-08-04 19:28:40 +00:00
|
|
|
int shotspread = 2;
|
2007-08-04 01:53:26 +00:00
|
|
|
for(int i = -shotspread; i <= shotspread; i++)
|
2007-07-15 10:47:50 +00:00
|
|
|
{
|
2007-12-16 22:46:23 +00:00
|
|
|
float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f};
|
2007-07-15 23:52:36 +00:00
|
|
|
float a = get_angle(direction);
|
2007-12-09 13:51:55 +00:00
|
|
|
float v = 1.0f-fabs(i/(float)shotspread);
|
|
|
|
a += spreading[i+2];
|
2008-02-02 18:05:16 +00:00
|
|
|
float speed = mix((float)tuning.shotgun_speed_wide, (float)tuning.shotgun_speed_center, v);
|
2007-10-04 23:58:22 +00:00
|
|
|
new projectile(WEAPON_SHOTGUN,
|
2007-07-13 13:40:04 +00:00
|
|
|
client_id,
|
|
|
|
pos+vec2(0,0),
|
2008-02-02 18:05:16 +00:00
|
|
|
vec2(cosf(a), sinf(a))*speed,
|
2008-01-29 21:39:41 +00:00
|
|
|
(int)(server_tickspeed()*0.25f),
|
2007-07-13 13:40:04 +00:00
|
|
|
this,
|
2007-08-04 19:00:06 +00:00
|
|
|
1, 0, 0, -1, WEAPON_SHOTGUN);
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
2007-07-21 17:35:28 +00:00
|
|
|
create_sound(pos, SOUND_SHOTGUN_FIRE);
|
2007-07-15 10:47:50 +00:00
|
|
|
break;
|
2007-10-28 11:30:25 +00:00
|
|
|
}
|
2007-12-15 12:04:48 +00:00
|
|
|
|
2008-02-04 07:59:25 +00:00
|
|
|
case WEAPON_RIFLE:
|
2007-12-15 12:04:48 +00:00
|
|
|
{
|
2008-02-02 18:05:16 +00:00
|
|
|
new laser(pos, direction, tuning.laser_reach, this);
|
2008-02-04 07:59:25 +00:00
|
|
|
create_sound(pos, SOUND_RIFLE_FIRE);
|
2007-12-15 12:04:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-08-04 16:49:57 +00:00
|
|
|
weapons[active_weapon].ammo--;
|
2007-07-21 19:03:50 +00:00
|
|
|
attack_tick = server_tick();
|
|
|
|
reload_timer = data->weapons[active_weapon].firedelay * server_tickspeed() / 1000;
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-08-04 16:49:57 +00:00
|
|
|
create_sound(pos, SOUND_WEAPON_NOAMMO);
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
}
|
2008-02-10 15:32:30 +00:00
|
|
|
}*/
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
// Update weapons
|
|
|
|
if (active_weapon == WEAPON_HAMMER && reload_timer > 0)
|
|
|
|
{
|
|
|
|
// Handle collisions
|
|
|
|
// only one that needs update (for now)
|
|
|
|
// do selection for the weapon and bash anything in it
|
|
|
|
// check if we hit anything along the way
|
2007-10-28 11:30:25 +00:00
|
|
|
int type = OBJTYPE_PLAYER_CHARACTER;
|
2007-07-21 19:03:50 +00:00
|
|
|
entity *ents[64];
|
|
|
|
vec2 lookdir(direction.x > 0.0f ? 1.0f : -1.0f, 0.0f);
|
|
|
|
vec2 dir = lookdir * data->weapons[active_weapon].meleereach;
|
|
|
|
float radius = length(dir * 0.5f);
|
|
|
|
vec2 center = pos + dir * 0.5f;
|
2007-09-23 22:54:31 +00:00
|
|
|
int num = world->find_entities(center, radius, ents, 64, &type, 1);
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
for (int i = 0; i < num; i++)
|
|
|
|
{
|
|
|
|
// Check if entity is a player
|
|
|
|
if (ents[i] == this)
|
|
|
|
continue;
|
|
|
|
// make sure we haven't hit this object before
|
|
|
|
bool balreadyhit = false;
|
|
|
|
for (int j = 0; j < numobjectshit; j++)
|
|
|
|
{
|
|
|
|
if (hitobjects[j] == ents[i])
|
|
|
|
balreadyhit = true;
|
|
|
|
}
|
|
|
|
if (balreadyhit)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// check so we are sufficiently close
|
|
|
|
if (distance(ents[i]->pos, pos) > (phys_size * 2.0f))
|
|
|
|
continue;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
// hit a player, give him damage and stuffs...
|
|
|
|
// create sound for bash
|
|
|
|
//create_sound(ents[i]->pos, sound_impact);
|
2007-08-04 19:00:06 +00:00
|
|
|
vec2 fdir = normalize(ents[i]->pos- pos);
|
2007-07-21 19:03:50 +00:00
|
|
|
|
|
|
|
// set his velocity to fast upward (for now)
|
|
|
|
create_smoke(ents[i]->pos);
|
2007-07-22 14:16:57 +00:00
|
|
|
create_sound(pos, SOUND_HAMMER_HIT);
|
2007-12-12 19:52:57 +00:00
|
|
|
if(numobjectshit < 10)
|
|
|
|
hitobjects[numobjectshit++] = ents[i];
|
2007-08-04 19:00:06 +00:00
|
|
|
ents[i]->take_damage(vec2(0,-1.0f), data->weapons[active_weapon].meleedamage, client_id, active_weapon);
|
2007-07-21 19:03:50 +00:00
|
|
|
player* target = (player*)ents[i];
|
|
|
|
vec2 dir;
|
|
|
|
if (length(target->pos - pos) > 0.0f)
|
|
|
|
dir = normalize(target->pos - pos);
|
|
|
|
else
|
|
|
|
dir = vec2(0,-1);
|
2007-12-10 21:27:14 +00:00
|
|
|
|
|
|
|
target->core.vel += normalize(dir + vec2(0,-1.1f)) * 10.0f;
|
2007-07-21 19:03:50 +00:00
|
|
|
}
|
|
|
|
}
|
2007-12-10 19:13:00 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
if (data->weapons[active_weapon].ammoregentime)
|
|
|
|
{
|
|
|
|
// If equipped and not active, regen ammo?
|
|
|
|
if (reload_timer <= 0)
|
|
|
|
{
|
|
|
|
if (weapons[active_weapon].ammoregenstart < 0)
|
|
|
|
weapons[active_weapon].ammoregenstart = server_tick();
|
|
|
|
|
|
|
|
if ((server_tick() - weapons[active_weapon].ammoregenstart) >= data->weapons[active_weapon].ammoregentime * server_tickspeed() / 1000)
|
|
|
|
{
|
|
|
|
// Add some ammo
|
|
|
|
weapons[active_weapon].ammo = min(weapons[active_weapon].ammo + 1, data->weapons[active_weapon].maxammo);
|
|
|
|
weapons[active_weapon].ammoregenstart = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
weapons[active_weapon].ammoregenstart = -1;
|
|
|
|
}
|
|
|
|
}
|
2007-12-10 19:13:00 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
return 0;
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
|
|
|
|
2008-02-10 15:32:30 +00:00
|
|
|
void player::on_direct_input(player_input *new_input)
|
|
|
|
{
|
|
|
|
mem_copy(&latest_previnput, &latest_input, sizeof(latest_input));
|
|
|
|
mem_copy(&latest_input, new_input, sizeof(latest_input));
|
|
|
|
fire_weapon();
|
|
|
|
}
|
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
void player::tick()
|
|
|
|
{
|
2007-12-16 20:16:27 +00:00
|
|
|
server_setclientscore(client_id, score);
|
2008-01-12 12:08:26 +00:00
|
|
|
|
|
|
|
// grab latest input
|
2008-02-10 15:32:30 +00:00
|
|
|
/*
|
2008-01-12 12:08:26 +00:00
|
|
|
{
|
|
|
|
int size = 0;
|
|
|
|
int *input = server_latestinput(client_id, &size);
|
|
|
|
if(input)
|
|
|
|
{
|
|
|
|
mem_copy(&latest_previnput, &latest_input, sizeof(latest_input));
|
|
|
|
mem_copy(&latest_input, input, sizeof(latest_input));
|
|
|
|
}
|
2008-02-10 15:32:30 +00:00
|
|
|
}*/
|
2007-12-16 20:16:27 +00:00
|
|
|
|
2007-12-09 16:10:12 +00:00
|
|
|
// check if we have enough input
|
|
|
|
// this is to prevent initial weird clicks
|
|
|
|
if(num_inputs < 2)
|
2008-01-12 12:08:26 +00:00
|
|
|
{
|
|
|
|
latest_previnput = latest_input;
|
2007-12-09 16:10:12 +00:00
|
|
|
previnput = input;
|
2008-01-12 12:08:26 +00:00
|
|
|
}
|
|
|
|
|
2007-07-26 07:15:52 +00:00
|
|
|
// do latency stuff
|
|
|
|
{
|
2007-08-22 07:52:33 +00:00
|
|
|
CLIENT_INFO info;
|
2007-07-26 07:15:52 +00:00
|
|
|
if(server_getclientinfo(client_id, &info))
|
|
|
|
{
|
|
|
|
latency_accum += info.latency;
|
|
|
|
latency_accum_max = max(latency_accum_max, info.latency);
|
|
|
|
latency_accum_min = min(latency_accum_min, info.latency);
|
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-26 07:15:52 +00:00
|
|
|
if(server_tick()%server_tickspeed() == 0)
|
|
|
|
{
|
|
|
|
latency_avg = latency_accum/server_tickspeed();
|
|
|
|
latency_max = latency_accum_max;
|
|
|
|
latency_min = latency_accum_min;
|
|
|
|
latency_accum = 0;
|
|
|
|
latency_accum_min = 1000;
|
|
|
|
latency_accum_max = 0;
|
|
|
|
}
|
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-11-26 20:19:59 +00:00
|
|
|
// enable / disable physics
|
|
|
|
if(team == -1 || dead)
|
|
|
|
world->core.players[client_id] = 0;
|
|
|
|
else
|
|
|
|
world->core.players[client_id] = &core;
|
|
|
|
|
|
|
|
// spectator
|
2007-10-07 20:23:33 +00:00
|
|
|
if(team == -1)
|
|
|
|
return;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-08-02 20:17:18 +00:00
|
|
|
if(spawning)
|
|
|
|
try_respawn();
|
2007-07-26 07:15:52 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
// TODO: rework the input to be more robust
|
|
|
|
if(dead)
|
|
|
|
{
|
2008-01-12 12:08:26 +00:00
|
|
|
if(server_tick()-die_tick >= server_tickspeed()/2 && count_input(latest_previnput.fire, latest_input.fire).presses)
|
2007-12-19 22:36:54 +00:00
|
|
|
die_tick = -1;
|
2007-07-22 12:27:49 +00:00
|
|
|
if(server_tick()-die_tick >= server_tickspeed()*5) // auto respawn after 3 sec
|
2007-07-15 10:47:50 +00:00
|
|
|
respawn();
|
2007-12-19 22:36:54 +00:00
|
|
|
//if((input.fire&1) && server_tick()-die_tick >= server_tickspeed()/2) // auto respawn after 0.5 sec
|
|
|
|
//respawn();
|
2007-07-15 10:47:50 +00:00
|
|
|
return;
|
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-09-09 18:21:14 +00:00
|
|
|
//player_core core;
|
|
|
|
//core.pos = pos;
|
|
|
|
//core.jumped = jumped;
|
|
|
|
core.input = input;
|
|
|
|
core.tick();
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
// handle weapons
|
2007-09-23 22:54:31 +00:00
|
|
|
handle_weapons();
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2008-01-29 21:55:13 +00:00
|
|
|
player_state = input.player_state;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
// Previnput
|
|
|
|
previnput = input;
|
2007-07-15 10:47:50 +00:00
|
|
|
return;
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
void player::tick_defered()
|
|
|
|
{
|
2007-11-26 20:58:44 +00:00
|
|
|
if(!dead)
|
|
|
|
{
|
2007-12-12 19:52:57 +00:00
|
|
|
vec2 start_pos = core.pos;
|
|
|
|
vec2 start_vel = core.vel;
|
|
|
|
bool stuck_before = test_box(core.pos, vec2(28.0f, 28.0f));
|
2007-12-16 13:32:59 +00:00
|
|
|
|
2007-11-26 20:58:44 +00:00
|
|
|
core.move();
|
2007-12-12 19:52:57 +00:00
|
|
|
bool stuck_after_move = test_box(core.pos, vec2(28.0f, 28.0f));
|
2007-11-26 20:58:44 +00:00
|
|
|
core.quantize();
|
2007-12-12 19:52:57 +00:00
|
|
|
bool stuck_after_quant = test_box(core.pos, vec2(28.0f, 28.0f));
|
2007-11-26 20:58:44 +00:00
|
|
|
pos = core.pos;
|
2007-12-12 19:52:57 +00:00
|
|
|
|
|
|
|
if(!stuck_before && (stuck_after_move || stuck_after_quant))
|
|
|
|
{
|
2007-12-12 20:05:18 +00:00
|
|
|
dbg_msg("player", "STUCK!!! %d %d %d %f %f %f %f %x %x %x %x",
|
|
|
|
stuck_before,
|
|
|
|
stuck_after_move,
|
|
|
|
stuck_after_quant,
|
2007-12-12 19:52:57 +00:00
|
|
|
start_pos.x, start_pos.y,
|
|
|
|
start_vel.x, start_vel.y,
|
2007-12-12 20:05:18 +00:00
|
|
|
*((unsigned *)&start_pos.x), *((unsigned *)&start_pos.y),
|
|
|
|
*((unsigned *)&start_vel.x), *((unsigned *)&start_vel.y));
|
2007-12-12 19:52:57 +00:00
|
|
|
}
|
2007-12-09 12:40:34 +00:00
|
|
|
|
|
|
|
int events = core.triggered_events;
|
|
|
|
int mask = cmask_all_except_one(client_id);
|
|
|
|
|
|
|
|
if(events&COREEVENT_GROUND_JUMP) create_sound(pos, SOUND_PLAYER_JUMP, mask);
|
2007-12-09 16:04:37 +00:00
|
|
|
if(events&COREEVENT_AIR_JUMP)
|
|
|
|
{
|
2007-12-15 14:30:22 +00:00
|
|
|
create_sound(pos, SOUND_PLAYER_AIRJUMP, mask);
|
2007-12-09 16:04:37 +00:00
|
|
|
ev_common *c = (ev_common *)::events.create(EVENT_AIR_JUMP, sizeof(ev_common), mask);
|
2007-12-13 20:28:22 +00:00
|
|
|
if(c)
|
|
|
|
{
|
|
|
|
c->x = (int)pos.x;
|
|
|
|
c->y = (int)pos.y;
|
|
|
|
}
|
2007-12-09 16:04:37 +00:00
|
|
|
}
|
|
|
|
|
2007-12-09 12:40:34 +00:00
|
|
|
//if(events&COREEVENT_HOOK_LAUNCH) snd_play_random(CHN_WORLD, SOUND_HOOK_LOOP, 1.0f, pos);
|
2007-12-09 13:36:54 +00:00
|
|
|
if(events&COREEVENT_HOOK_ATTACH_PLAYER) create_sound(pos, SOUND_HOOK_ATTACH_PLAYER, mask);
|
|
|
|
if(events&COREEVENT_HOOK_ATTACH_GROUND) create_sound(pos, SOUND_HOOK_ATTACH_GROUND, mask);
|
2007-12-09 12:40:34 +00:00
|
|
|
//if(events&COREEVENT_HOOK_RETRACT) snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos);
|
|
|
|
|
2007-11-26 20:58:44 +00:00
|
|
|
}
|
2007-11-26 20:19:59 +00:00
|
|
|
|
|
|
|
if(team == -1)
|
|
|
|
{
|
|
|
|
pos.x = input.target_x;
|
|
|
|
pos.y = input.target_y;
|
|
|
|
}
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
void player::die(int killer, int weapon)
|
|
|
|
{
|
2008-02-04 00:13:34 +00:00
|
|
|
if (dead || team == -1)
|
|
|
|
return;
|
|
|
|
|
2007-11-18 23:29:34 +00:00
|
|
|
int mode_special = gameobj->on_player_death(this, get_player(killer), weapon);
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-11-18 23:29:34 +00:00
|
|
|
dbg_msg("game", "kill killer='%d:%s' victim='%d:%s' weapon=%d special=%d",
|
2007-11-04 00:19:41 +00:00
|
|
|
killer, server_clientname(killer),
|
2007-11-18 23:29:34 +00:00
|
|
|
client_id, server_clientname(client_id), weapon, mode_special);
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
// send the kill message
|
|
|
|
msg_pack_start(MSG_KILLMSG, MSGFLAG_VITAL);
|
|
|
|
msg_pack_int(killer);
|
|
|
|
msg_pack_int(client_id);
|
|
|
|
msg_pack_int(weapon);
|
2007-11-18 23:29:34 +00:00
|
|
|
msg_pack_int(mode_special);
|
2007-07-15 10:47:50 +00:00
|
|
|
msg_pack_end();
|
|
|
|
server_send_msg(-1);
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
// a nice sound
|
|
|
|
create_sound(pos, SOUND_PLAYER_DIE);
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
// set dead state
|
2007-12-18 23:21:57 +00:00
|
|
|
die_pos = pos;
|
2007-07-15 10:47:50 +00:00
|
|
|
dead = true;
|
|
|
|
die_tick = server_tick();
|
2007-10-07 20:23:33 +00:00
|
|
|
clear_flag(FLAG_PHYSICS);
|
2007-07-21 21:17:38 +00:00
|
|
|
create_death(pos);
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
bool player::take_damage(vec2 force, int dmg, int from, int weapon)
|
|
|
|
{
|
2007-09-09 18:21:14 +00:00
|
|
|
core.vel += force;
|
2007-12-10 20:53:37 +00:00
|
|
|
|
|
|
|
if(gameobj->is_friendly_fire(client_id, from) && !config.sv_teamdamage)
|
|
|
|
return false;
|
2007-07-15 10:47:50 +00:00
|
|
|
|
2007-10-28 11:30:25 +00:00
|
|
|
// player only inflicts half damage on self
|
2007-08-04 19:00:06 +00:00
|
|
|
if(from == client_id)
|
|
|
|
dmg = max(1, dmg/2);
|
|
|
|
|
2007-09-25 21:53:14 +00:00
|
|
|
// CTF and TDM (TODO: check for FF)
|
|
|
|
//if (gameobj->gametype != GAMETYPE_DM && from >= 0 && players[from].team == team)
|
|
|
|
//return false;
|
2007-07-22 12:32:57 +00:00
|
|
|
|
2007-08-05 09:12:38 +00:00
|
|
|
damage_taken++;
|
|
|
|
|
|
|
|
// create healthmod indicator
|
|
|
|
if(server_tick() < damage_taken_tick+25)
|
|
|
|
{
|
|
|
|
// make sure that the damage indicators doesn't group together
|
|
|
|
create_damageind(pos, damage_taken*0.25f, dmg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
damage_taken = 0;
|
|
|
|
create_damageind(pos, 0, dmg);
|
|
|
|
}
|
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
if(armor)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-15 10:47:50 +00:00
|
|
|
armor -= 1;
|
|
|
|
dmg--;
|
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
if(dmg > armor)
|
|
|
|
{
|
|
|
|
dmg -= armor;
|
|
|
|
armor = 0;
|
|
|
|
health -= dmg;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
armor -= dmg;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-08-05 09:12:38 +00:00
|
|
|
damage_taken_tick = server_tick();
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-08-05 08:59:38 +00:00
|
|
|
// do damage hit sound
|
2008-01-11 16:48:34 +00:00
|
|
|
if(from >= 0 && from != client_id)
|
2007-12-09 12:40:34 +00:00
|
|
|
create_sound(get_player(from)->pos, SOUND_HIT, cmask_one(from));
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
// check for death
|
|
|
|
if(health <= 0)
|
|
|
|
{
|
|
|
|
die(from, weapon);
|
2007-08-09 00:35:27 +00:00
|
|
|
|
|
|
|
// set attacker's face to happy (taunt!)
|
|
|
|
if (from >= 0 && from != client_id)
|
|
|
|
{
|
|
|
|
player *p = get_player(from);
|
|
|
|
|
|
|
|
p->emote_type = EMOTE_HAPPY;
|
2007-10-28 11:30:25 +00:00
|
|
|
p->emote_stop = server_tick() + server_tickspeed();
|
2007-08-09 00:35:27 +00:00
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dmg > 2)
|
|
|
|
create_sound(pos, SOUND_PLAYER_PAIN_LONG);
|
|
|
|
else
|
|
|
|
create_sound(pos, SOUND_PLAYER_PAIN_SHORT);
|
|
|
|
|
2007-08-09 00:18:11 +00:00
|
|
|
emote_type = EMOTE_PAIN;
|
|
|
|
emote_stop = server_tick() + 500 * server_tickspeed() / 1000;
|
2007-08-05 08:59:38 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
// spawn blood?
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void player::snap(int snaping_client)
|
|
|
|
{
|
2007-10-28 11:30:25 +00:00
|
|
|
if(1)
|
2007-09-09 18:21:14 +00:00
|
|
|
{
|
2007-10-28 11:30:25 +00:00
|
|
|
obj_player_info *info = (obj_player_info *)snap_new_item(OBJTYPE_PLAYER_INFO, client_id, sizeof(obj_player_info));
|
2007-08-09 00:18:11 +00:00
|
|
|
|
2008-02-10 15:32:30 +00:00
|
|
|
info->latency = latency_min;
|
2007-10-28 11:30:25 +00:00
|
|
|
info->latency_flux = latency_max-latency_min;
|
|
|
|
info->local = 0;
|
|
|
|
info->clientid = client_id;
|
|
|
|
info->score = score;
|
|
|
|
info->team = team;
|
2007-08-09 00:18:11 +00:00
|
|
|
|
2007-10-28 11:30:25 +00:00
|
|
|
if(client_id == snaping_client)
|
|
|
|
info->local = 1;
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2008-01-12 12:08:26 +00:00
|
|
|
if(health > 0 && team >= 0 && distance(players[snaping_client].pos, pos) < 1000.0f)
|
2007-07-15 10:47:50 +00:00
|
|
|
{
|
2007-10-28 11:30:25 +00:00
|
|
|
obj_player_character *character = (obj_player_character *)snap_new_item(OBJTYPE_PLAYER_CHARACTER, client_id, sizeof(obj_player_character));
|
|
|
|
|
|
|
|
core.write(character);
|
|
|
|
|
2007-10-28 17:54:28 +00:00
|
|
|
// this is to make sure that players that are just standing still
|
|
|
|
// isn't sent. this is because the physics keep bouncing between
|
|
|
|
// 0-128 when just standing.
|
|
|
|
// TODO: fix the physics so this isn't needed
|
|
|
|
if(snaping_client != client_id && abs(character->vy) < 256.0f)
|
2007-10-28 11:30:25 +00:00
|
|
|
character->vy = 0;
|
|
|
|
|
|
|
|
if (emote_stop < server_tick())
|
|
|
|
{
|
|
|
|
emote_type = EMOTE_NORMAL;
|
|
|
|
emote_stop = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
character->emote = emote_type;
|
|
|
|
|
|
|
|
character->ammocount = weapons[active_weapon].ammo;
|
|
|
|
character->health = 0;
|
|
|
|
character->armor = 0;
|
|
|
|
character->weapon = active_weapon;
|
|
|
|
character->attacktick = attack_tick;
|
|
|
|
|
|
|
|
if(client_id == snaping_client)
|
|
|
|
{
|
|
|
|
character->health = health;
|
|
|
|
character->armor = armor;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(dead)
|
|
|
|
character->health = -1;
|
|
|
|
|
|
|
|
//if(length(vel) > 15.0f)
|
|
|
|
// player->emote = EMOTE_HAPPY;
|
2007-07-26 11:33:49 +00:00
|
|
|
|
2007-10-28 11:30:25 +00:00
|
|
|
//if(damage_taken_tick+50 > server_tick())
|
|
|
|
// player->emote = EMOTE_PAIN;
|
|
|
|
|
|
|
|
if (character->emote == EMOTE_NORMAL)
|
|
|
|
{
|
|
|
|
if(250 - ((server_tick() - last_action)%(250)) < 5)
|
|
|
|
character->emote = EMOTE_BLINK;
|
|
|
|
}
|
|
|
|
|
2008-01-29 21:55:13 +00:00
|
|
|
character->player_state = player_state;
|
2007-10-28 11:30:25 +00:00
|
|
|
}
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-08-14 18:37:16 +00:00
|
|
|
player *players;
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
//////////////////////////////////////////////////
|
|
|
|
// powerup
|
|
|
|
//////////////////////////////////////////////////
|
2007-07-13 13:40:04 +00:00
|
|
|
powerup::powerup(int _type, int _subtype)
|
|
|
|
: entity(OBJTYPE_POWERUP)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
|
|
|
type = _type;
|
|
|
|
subtype = _subtype;
|
|
|
|
proximity_radius = phys_size;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
reset();
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
// TODO: should this be done here?
|
2007-09-23 22:54:31 +00:00
|
|
|
world->insert_entity(this);
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-15 10:47:50 +00:00
|
|
|
void powerup::reset()
|
|
|
|
{
|
2007-07-23 17:52:04 +00:00
|
|
|
if (data->powerupinfo[type].startspawntime > 0)
|
|
|
|
spawntick = server_tick() + server_tickspeed() * data->powerupinfo[type].startspawntime;
|
|
|
|
else
|
|
|
|
spawntick = -1;
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
|
|
|
|
2007-11-24 14:07:06 +00:00
|
|
|
|
|
|
|
void send_weapon_pickup(int cid, int weapon);
|
|
|
|
|
2007-05-22 15:03:32 +00:00
|
|
|
void powerup::tick()
|
|
|
|
{
|
|
|
|
// wait for respawn
|
|
|
|
if(spawntick > 0)
|
|
|
|
{
|
|
|
|
if(server_tick() > spawntick)
|
2007-07-29 16:44:30 +00:00
|
|
|
{
|
|
|
|
// respawn
|
2007-05-22 15:03:32 +00:00
|
|
|
spawntick = -1;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-29 16:44:30 +00:00
|
|
|
if(type == POWERUP_WEAPON)
|
2007-12-09 12:40:34 +00:00
|
|
|
create_sound(pos, SOUND_WEAPON_SPAWN);
|
2007-07-29 16:44:30 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Check if a player intersected us
|
|
|
|
vec2 meh;
|
|
|
|
player* pplayer = intersect_player(pos, pos + vec2(0,16), meh, 0);
|
|
|
|
if (pplayer)
|
|
|
|
{
|
|
|
|
// player picked us up, is someone was hooking us, let them go
|
|
|
|
int respawntime = -1;
|
|
|
|
switch (type)
|
|
|
|
{
|
2007-07-23 17:52:04 +00:00
|
|
|
case POWERUP_HEALTH:
|
2007-08-30 07:15:26 +00:00
|
|
|
if(pplayer->health < 10)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-12-09 12:40:34 +00:00
|
|
|
create_sound(pos, SOUND_PICKUP_HEALTH);
|
2007-08-30 07:15:26 +00:00
|
|
|
pplayer->health = min(10, pplayer->health + data->powerupinfo[type].amount);
|
2007-07-23 17:52:04 +00:00
|
|
|
respawntime = data->powerupinfo[type].respawntime;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-07-13 13:40:04 +00:00
|
|
|
break;
|
2007-07-23 17:52:04 +00:00
|
|
|
case POWERUP_ARMOR:
|
2007-08-30 07:15:26 +00:00
|
|
|
if(pplayer->armor < 10)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-12-09 12:40:34 +00:00
|
|
|
create_sound(pos, SOUND_PICKUP_ARMOR);
|
2007-08-30 07:15:26 +00:00
|
|
|
pplayer->armor = min(10, pplayer->armor + data->powerupinfo[type].amount);
|
2007-07-23 17:52:04 +00:00
|
|
|
respawntime = data->powerupinfo[type].respawntime;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-07-13 13:40:04 +00:00
|
|
|
break;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-07-23 17:52:04 +00:00
|
|
|
case POWERUP_WEAPON:
|
2007-07-13 13:40:04 +00:00
|
|
|
if(subtype >= 0 && subtype < NUM_WEAPONS)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
if(pplayer->weapons[subtype].ammo < 10 || !pplayer->weapons[subtype].got)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
pplayer->weapons[subtype].got = true;
|
2007-07-23 17:52:04 +00:00
|
|
|
pplayer->weapons[subtype].ammo = min(10, pplayer->weapons[subtype].ammo + data->powerupinfo[type].amount);
|
|
|
|
respawntime = data->powerupinfo[type].respawntime;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-08-03 06:35:35 +00:00
|
|
|
// TODO: data compiler should take care of stuff like this
|
2008-02-02 18:05:16 +00:00
|
|
|
if(subtype == WEAPON_GRENADE)
|
|
|
|
create_sound(pos, SOUND_PICKUP_GRENADE);
|
2007-08-03 06:35:35 +00:00
|
|
|
else if(subtype == WEAPON_SHOTGUN)
|
|
|
|
create_sound(pos, SOUND_PICKUP_SHOTGUN);
|
2007-11-24 14:07:06 +00:00
|
|
|
|
|
|
|
send_weapon_pickup(pplayer->client_id, subtype);
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
}
|
2007-07-13 13:40:04 +00:00
|
|
|
break;
|
2007-07-23 17:52:04 +00:00
|
|
|
case POWERUP_NINJA:
|
2007-07-21 19:03:50 +00:00
|
|
|
{
|
|
|
|
// activate ninja on target player
|
2008-01-29 21:55:13 +00:00
|
|
|
pplayer->ninja.activationtick = server_tick();
|
2007-07-21 19:03:50 +00:00
|
|
|
pplayer->weapons[WEAPON_NINJA].got = true;
|
2007-08-14 18:37:16 +00:00
|
|
|
pplayer->last_weapon = pplayer->active_weapon;
|
2007-07-21 19:03:50 +00:00
|
|
|
pplayer->active_weapon = WEAPON_NINJA;
|
2007-07-23 17:52:04 +00:00
|
|
|
respawntime = data->powerupinfo[type].respawntime;
|
2007-08-03 06:35:35 +00:00
|
|
|
create_sound(pos, SOUND_PICKUP_NINJA);
|
2007-08-09 00:18:11 +00:00
|
|
|
|
|
|
|
// loop through all players, setting their emotes
|
|
|
|
entity *ents[64];
|
2007-10-28 11:30:25 +00:00
|
|
|
const int types[] = {OBJTYPE_PLAYER_CHARACTER};
|
2007-09-23 22:54:31 +00:00
|
|
|
int num = world->find_entities(vec2(0, 0), 1000000, ents, 64, types, 1);
|
2007-08-09 00:18:11 +00:00
|
|
|
for (int i = 0; i < num; i++)
|
|
|
|
{
|
|
|
|
player *p = (player *)ents[i];
|
|
|
|
if (p != pplayer)
|
|
|
|
{
|
|
|
|
p->emote_type = EMOTE_SURPRISE;
|
|
|
|
p->emote_stop = server_tick() + server_tickspeed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pplayer->emote_type = EMOTE_ANGRY;
|
|
|
|
pplayer->emote_stop = server_tick() + 1200 * server_tickspeed() / 1000;
|
2007-12-15 15:32:01 +00:00
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
};
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-05-22 15:03:32 +00:00
|
|
|
if(respawntime >= 0)
|
2007-08-14 18:37:16 +00:00
|
|
|
{
|
2007-11-04 00:19:41 +00:00
|
|
|
dbg_msg("game", "pickup player='%d:%s' item=%d/%d",
|
|
|
|
pplayer->client_id, server_clientname(pplayer->client_id), type, subtype);
|
2007-05-22 15:03:32 +00:00
|
|
|
spawntick = server_tick() + server_tickspeed() * respawntime;
|
2007-08-14 18:37:16 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void powerup::snap(int snapping_client)
|
|
|
|
{
|
|
|
|
if(spawntick != -1)
|
|
|
|
return;
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
obj_powerup *up = (obj_powerup *)snap_new_item(OBJTYPE_POWERUP, id, sizeof(obj_powerup));
|
|
|
|
up->x = (int)pos.x;
|
|
|
|
up->y = (int)pos.y;
|
|
|
|
up->type = type; // TODO: two diffrent types? what gives?
|
|
|
|
up->subtype = subtype;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// POWERUP END ///////////////////////
|
|
|
|
|
|
|
|
player *get_player(int index)
|
|
|
|
{
|
|
|
|
return &players[index];
|
|
|
|
}
|
|
|
|
|
2007-08-05 09:12:38 +00:00
|
|
|
void create_damageind(vec2 p, float angle, int amount)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-08-05 09:12:38 +00:00
|
|
|
float a = 3 * 3.14159f / 2 + angle;
|
2007-07-21 12:57:36 +00:00
|
|
|
//float a = get_angle(dir);
|
2007-07-14 13:09:42 +00:00
|
|
|
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));
|
2007-08-14 18:37:16 +00:00
|
|
|
if(ev)
|
|
|
|
{
|
|
|
|
ev->x = (int)p.x;
|
|
|
|
ev->y = (int)p.y;
|
|
|
|
ev->angle = (int)(f*256.0f);
|
|
|
|
}
|
2007-07-14 13:09:42 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-14 22:35:00 +00:00
|
|
|
void create_explosion(vec2 p, int owner, int weapon, bool bnodamage)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
|
|
|
// create the event
|
|
|
|
ev_explosion *ev = (ev_explosion *)events.create(EVENT_EXPLOSION, sizeof(ev_explosion));
|
2007-08-14 18:37:16 +00:00
|
|
|
if(ev)
|
|
|
|
{
|
|
|
|
ev->x = (int)p.x;
|
|
|
|
ev->y = (int)p.y;
|
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-05-22 15:03:32 +00:00
|
|
|
if (!bnodamage)
|
|
|
|
{
|
|
|
|
// deal damage
|
|
|
|
entity *ents[64];
|
2007-12-27 17:46:32 +00:00
|
|
|
float radius = 128.0f;
|
|
|
|
float innerradius = 42.0f;
|
|
|
|
|
2007-09-23 22:54:31 +00:00
|
|
|
int num = world->find_entities(p, radius, ents, 64);
|
2007-05-22 15:03:32 +00:00
|
|
|
for(int i = 0; i < num; i++)
|
|
|
|
{
|
|
|
|
vec2 diff = ents[i]->pos - p;
|
|
|
|
vec2 forcedir(0,1);
|
|
|
|
float l = length(diff);
|
2007-07-21 18:07:27 +00:00
|
|
|
if(l)
|
|
|
|
forcedir = normalize(diff);
|
|
|
|
l = 1-clamp((l-innerradius)/(radius-innerradius), 0.0f, 1.0f);
|
|
|
|
float dmg = 6 * l;
|
2007-05-22 15:03:32 +00:00
|
|
|
if((int)dmg)
|
2007-08-04 19:00:06 +00:00
|
|
|
ents[i]->take_damage(forcedir*dmg*2, (int)dmg, owner, weapon);
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void create_smoke(vec2 p)
|
|
|
|
{
|
|
|
|
// create the event
|
|
|
|
ev_explosion *ev = (ev_explosion *)events.create(EVENT_SMOKE, sizeof(ev_explosion));
|
2007-08-14 18:37:16 +00:00
|
|
|
if(ev)
|
|
|
|
{
|
|
|
|
ev->x = (int)p.x;
|
|
|
|
ev->y = (int)p.y;
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2008-01-29 21:39:41 +00:00
|
|
|
void create_playerspawn(vec2 p)
|
2007-07-21 19:03:50 +00:00
|
|
|
{
|
|
|
|
// create the event
|
2008-01-29 21:39:41 +00:00
|
|
|
ev_spawn *ev = (ev_spawn *)events.create(EVENT_PLAYERSPAWN, sizeof(ev_spawn));
|
2007-08-14 18:37:16 +00:00
|
|
|
if(ev)
|
|
|
|
{
|
|
|
|
ev->x = (int)p.x;
|
|
|
|
ev->y = (int)p.y;
|
|
|
|
}
|
2007-07-21 19:03:50 +00:00
|
|
|
}
|
|
|
|
|
2007-07-21 21:17:38 +00:00
|
|
|
void create_death(vec2 p)
|
|
|
|
{
|
|
|
|
// create the event
|
|
|
|
ev_death *ev = (ev_death *)events.create(EVENT_DEATH, sizeof(ev_death));
|
2007-08-14 18:37:16 +00:00
|
|
|
if(ev)
|
|
|
|
{
|
|
|
|
ev->x = (int)p.x;
|
|
|
|
ev->y = (int)p.y;
|
|
|
|
}
|
2007-07-21 21:17:38 +00:00
|
|
|
}
|
|
|
|
|
2007-12-09 12:40:34 +00:00
|
|
|
void create_sound(vec2 pos, int sound, int mask)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
|
|
|
if (sound < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// create a sound
|
2007-12-09 12:40:34 +00:00
|
|
|
ev_sound *ev = (ev_sound *)events.create(EVENT_SOUND_WORLD, sizeof(ev_sound), mask);
|
2007-08-14 18:37:16 +00:00
|
|
|
if(ev)
|
|
|
|
{
|
|
|
|
ev->x = (int)pos.x;
|
|
|
|
ev->y = (int)pos.y;
|
2007-12-09 12:40:34 +00:00
|
|
|
ev->sound = sound;
|
2007-08-14 18:37:16 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-11-27 19:32:35 +00:00
|
|
|
void create_sound_global(int sound, int target)
|
|
|
|
{
|
|
|
|
if (sound < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
msg_pack_start(MSG_SOUND_GLOBAL, MSGFLAG_VITAL);
|
|
|
|
msg_pack_int(sound);
|
2007-12-15 15:35:50 +00:00
|
|
|
server_send_msg(target);
|
2007-11-27 19:32:35 +00:00
|
|
|
}
|
|
|
|
|
2008-02-02 18:05:16 +00:00
|
|
|
float closest_point_on_line(vec2 line_point0, vec2 line_point1, vec2 target_point)
|
|
|
|
{
|
|
|
|
vec2 c = target_point - line_point0;
|
|
|
|
vec2 v = (line_point1 - line_point0);
|
|
|
|
v = normalize(v);
|
|
|
|
float d = length(line_point0-line_point1);
|
|
|
|
float t = dot(v, c);
|
|
|
|
|
|
|
|
if (t < 0) return 0;
|
|
|
|
if (t > d) return 1;
|
|
|
|
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: should be more general
|
|
|
|
player *intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, entity *notthis)
|
|
|
|
{
|
|
|
|
// Find other players
|
|
|
|
float closest_time = distance(pos0, pos1) * 100.0f;
|
|
|
|
vec2 line_dir = normalize(pos1-pos0);
|
|
|
|
player *closest = 0;
|
|
|
|
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if(players[i].client_id < 0 || (entity *)&players[i] == notthis)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if(!(players[i].flags&entity::FLAG_PHYSICS))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
float t = closest_point_on_line(pos0, pos1, players[i].pos);
|
|
|
|
vec2 intersect_pos = pos0 + line_dir*t;
|
|
|
|
float len = distance(players[i].pos, intersect_pos);
|
|
|
|
if(len < player::phys_size)
|
|
|
|
{
|
|
|
|
if(t < closest_time)
|
|
|
|
{
|
|
|
|
new_pos = intersect_pos;
|
|
|
|
closest_time = t;
|
|
|
|
closest = &players[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return closest;
|
|
|
|
|
|
|
|
/*
|
|
|
|
entity *ents[64];
|
|
|
|
vec2 dir = pos1 - pos0;
|
|
|
|
float radius = length(dir * 0.5f);
|
|
|
|
vec2 center = pos0 + dir * 0.5f;
|
|
|
|
const int types[] = {OBJTYPE_PLAYER_CHARACTER};
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
new_pos = ents[i]->pos;
|
|
|
|
return (player*)ents[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;*/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
// TODO: should be more general
|
2008-02-02 18:05:16 +00:00
|
|
|
|
|
|
|
/*
|
2007-05-22 15:03:32 +00:00
|
|
|
player* intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, entity* notthis)
|
|
|
|
{
|
|
|
|
// Find other players
|
2008-02-02 18:05:16 +00:00
|
|
|
|
|
|
|
|
2007-05-22 15:03:32 +00:00
|
|
|
entity *ents[64];
|
|
|
|
vec2 dir = pos1 - pos0;
|
|
|
|
float radius = length(dir * 0.5f);
|
|
|
|
vec2 center = pos0 + dir * 0.5f;
|
2007-10-28 11:30:25 +00:00
|
|
|
const int types[] = {OBJTYPE_PLAYER_CHARACTER};
|
2007-09-23 22:54:31 +00:00
|
|
|
int num = world->find_entities(center, radius, ents, 64, types, 1);
|
2007-05-22 15:03:32 +00:00
|
|
|
for (int i = 0; i < num; i++)
|
|
|
|
{
|
|
|
|
// Check if entity is a player
|
2007-07-14 13:09:42 +00:00
|
|
|
if (ents[i] != notthis)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
|
|
|
new_pos = ents[i]->pos;
|
|
|
|
return (player*)ents[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2008-02-02 18:05:16 +00:00
|
|
|
*/
|
2007-05-22 15:03:32 +00:00
|
|
|
|
|
|
|
// Server hooks
|
|
|
|
void mods_tick()
|
|
|
|
{
|
2008-02-02 12:38:36 +00:00
|
|
|
world->core.tuning = tuning;
|
2007-09-23 22:54:31 +00:00
|
|
|
world->tick();
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-09-23 22:54:31 +00:00
|
|
|
if(world->paused) // make sure that the game object always updates
|
2007-08-14 18:37:16 +00:00
|
|
|
gameobj->tick();
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-12-11 23:10:07 +00:00
|
|
|
if(config.sv_restart)
|
2007-10-04 23:58:22 +00:00
|
|
|
{
|
2007-12-11 23:10:07 +00:00
|
|
|
if(config.sv_restart > 1)
|
|
|
|
gameobj->do_warmup(config.sv_restart);
|
2007-10-06 17:36:24 +00:00
|
|
|
else
|
|
|
|
gameobj->startround();
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-12-11 23:10:07 +00:00
|
|
|
config.sv_restart = 0;
|
2007-10-04 23:58:22 +00:00
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-10-07 20:48:15 +00:00
|
|
|
if(config.sv_msg[0] != 0)
|
|
|
|
{
|
2007-12-16 23:48:48 +00:00
|
|
|
send_chat(-1, -1, config.sv_msg);
|
2007-10-07 20:48:15 +00:00
|
|
|
config.sv_msg[0] = 0;
|
|
|
|
}
|
2007-12-17 00:27:41 +00:00
|
|
|
|
|
|
|
if(config.sv_kick != -1)
|
|
|
|
{
|
|
|
|
server_kick(config.sv_kick, "kicked");
|
|
|
|
config.sv_kick = -1;
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void mods_snap(int client_id)
|
|
|
|
{
|
2007-09-23 22:54:31 +00:00
|
|
|
world->snap(client_id);
|
2007-05-22 15:03:32 +00:00
|
|
|
events.snap(client_id);
|
|
|
|
}
|
|
|
|
|
2008-02-10 15:32:30 +00:00
|
|
|
void mods_client_direct_input(int client_id, void *input)
|
|
|
|
{
|
|
|
|
if(!world->paused)
|
|
|
|
players[client_id].on_direct_input((player_input *)input);
|
|
|
|
|
|
|
|
/*
|
|
|
|
if(i->fire)
|
|
|
|
{
|
|
|
|
msg_pack_start(MSG_EXTRA_PROJECTILE, 0);
|
|
|
|
msg_pack_end();
|
|
|
|
server_send_msg(client_id);
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
|
|
|
|
void mods_client_predicted_input(int client_id, void *input)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-09-23 22:54:31 +00:00
|
|
|
if(!world->paused)
|
2007-07-15 10:47:50 +00:00
|
|
|
{
|
2007-08-10 11:55:59 +00:00
|
|
|
if (memcmp(&players[client_id].input, input, sizeof(player_input)) != 0)
|
|
|
|
players[client_id].last_action = server_tick();
|
|
|
|
|
2007-07-21 19:03:50 +00:00
|
|
|
//players[client_id].previnput = players[client_id].input;
|
2007-07-15 10:47:50 +00:00
|
|
|
players[client_id].input = *(player_input*)input;
|
2007-12-09 16:10:12 +00:00
|
|
|
players[client_id].num_inputs++;
|
2007-12-16 20:07:31 +00:00
|
|
|
|
|
|
|
if(players[client_id].input.target_x == 0 && players[client_id].input.target_y == 0)
|
|
|
|
players[client_id].input.target_y = -1;
|
2007-07-15 10:47:50 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-11-04 00:19:41 +00:00
|
|
|
void send_info(int who, int to_who)
|
2007-08-14 22:48:49 +00:00
|
|
|
{
|
2007-11-04 00:19:41 +00:00
|
|
|
msg_pack_start(MSG_SETINFO, MSGFLAG_VITAL);
|
|
|
|
msg_pack_int(who);
|
|
|
|
msg_pack_string(server_clientname(who), 64);
|
|
|
|
msg_pack_string(players[who].skin_name, 64);
|
2007-11-18 14:24:34 +00:00
|
|
|
msg_pack_int(players[who].use_custom_color);
|
|
|
|
msg_pack_int(players[who].color_body);
|
|
|
|
msg_pack_int(players[who].color_feet);
|
2007-08-14 22:48:49 +00:00
|
|
|
msg_pack_end();
|
2007-11-04 00:19:41 +00:00
|
|
|
server_send_msg(to_who);
|
2007-08-14 22:48:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void send_emoticon(int cid, int emoticon)
|
|
|
|
{
|
|
|
|
msg_pack_start(MSG_EMOTICON, MSGFLAG_VITAL);
|
|
|
|
msg_pack_int(cid);
|
|
|
|
msg_pack_int(emoticon % 16);
|
|
|
|
msg_pack_end();
|
|
|
|
server_send_msg(-1);
|
|
|
|
}
|
|
|
|
|
2007-11-24 14:07:06 +00:00
|
|
|
void send_weapon_pickup(int cid, int weapon)
|
|
|
|
{
|
|
|
|
msg_pack_start(MSG_WEAPON_PICKUP, MSGFLAG_VITAL);
|
|
|
|
msg_pack_int(weapon);
|
|
|
|
msg_pack_end();
|
|
|
|
server_send_msg(cid);
|
|
|
|
}
|
|
|
|
|
2007-05-22 15:03:32 +00:00
|
|
|
void mods_client_enter(int client_id)
|
|
|
|
{
|
2007-09-23 22:54:31 +00:00
|
|
|
world->insert_entity(&players[client_id]);
|
2007-07-15 10:47:50 +00:00
|
|
|
players[client_id].respawn();
|
2007-11-04 00:19:41 +00:00
|
|
|
dbg_msg("game", "join player='%d:%s'", client_id, server_clientname(client_id));
|
2007-12-16 23:48:48 +00:00
|
|
|
|
|
|
|
|
2007-11-04 00:19:41 +00:00
|
|
|
char buf[512];
|
2007-12-16 23:48:48 +00:00
|
|
|
sprintf(buf, "%s entered and joined the %s", server_clientname(client_id), get_team_name(players[client_id].team));
|
|
|
|
send_chat(-1, -1, buf);
|
2008-01-30 13:15:58 +00:00
|
|
|
|
|
|
|
dbg_msg("game", "team_join player='%d:%s' team=%d", client_id, server_clientname(client_id), players[client_id].team);
|
2007-11-04 00:19:41 +00:00
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-11-04 00:19:41 +00:00
|
|
|
void mods_connected(int client_id)
|
|
|
|
{
|
|
|
|
players[client_id].init();
|
|
|
|
players[client_id].client_id = client_id;
|
2007-08-14 18:37:16 +00:00
|
|
|
|
2007-11-18 14:24:34 +00:00
|
|
|
//dbg_msg("game", "connected player='%d:%s'", client_id, server_clientname(client_id));
|
2007-08-14 18:37:16 +00:00
|
|
|
|
2007-12-18 22:07:57 +00:00
|
|
|
|
2007-10-07 20:23:33 +00:00
|
|
|
// Check which team the player should be on
|
2007-12-18 22:07:57 +00:00
|
|
|
if(config.sv_tournament_mode)
|
|
|
|
players[client_id].team = -1;
|
2007-10-07 20:23:33 +00:00
|
|
|
else
|
2007-12-18 22:07:57 +00:00
|
|
|
{
|
|
|
|
if(gameobj->gametype == GAMETYPE_DM)
|
|
|
|
players[client_id].team = 0;
|
|
|
|
else
|
|
|
|
players[client_id].team = gameobj->getteam(client_id);
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void mods_client_drop(int client_id)
|
|
|
|
{
|
2007-07-30 07:05:34 +00:00
|
|
|
char buf[512];
|
2007-11-04 00:19:41 +00:00
|
|
|
sprintf(buf, "%s has left the game", server_clientname(client_id));
|
2007-09-25 21:53:14 +00:00
|
|
|
send_chat(-1, -1, buf);
|
2007-08-14 18:37:16 +00:00
|
|
|
|
2007-11-04 00:19:41 +00:00
|
|
|
dbg_msg("game", "leave player='%d:%s'", client_id, server_clientname(client_id));
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-09-25 21:53:14 +00:00
|
|
|
gameobj->on_player_death(&players[client_id], 0, -1);
|
2007-09-23 22:54:31 +00:00
|
|
|
world->remove_entity(&players[client_id]);
|
2007-12-09 15:46:44 +00:00
|
|
|
world->core.players[client_id] = 0x0;
|
2007-07-26 07:15:52 +00:00
|
|
|
players[client_id].client_id = -1;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-14 13:09:42 +00:00
|
|
|
void mods_message(int msg, int client_id)
|
|
|
|
{
|
|
|
|
if(msg == MSG_SAY)
|
|
|
|
{
|
2007-09-25 21:53:14 +00:00
|
|
|
int team = msg_unpack_int();
|
|
|
|
const char *text = msg_unpack_string();
|
2007-10-04 22:00:10 +00:00
|
|
|
if(team)
|
|
|
|
team = players[client_id].team;
|
|
|
|
else
|
|
|
|
team = -1;
|
2007-09-25 21:53:14 +00:00
|
|
|
send_chat(client_id, team, text);
|
2007-07-14 13:09:42 +00:00
|
|
|
}
|
2007-10-07 20:23:33 +00:00
|
|
|
else if (msg == MSG_SETTEAM)
|
2007-07-22 11:53:15 +00:00
|
|
|
{
|
|
|
|
// Switch team on given client and kill/respawn him
|
2007-10-07 20:23:33 +00:00
|
|
|
players[client_id].set_team(msg_unpack_int());
|
2007-11-18 14:49:56 +00:00
|
|
|
gameobj->on_player_info_change(&players[client_id]);
|
|
|
|
|
|
|
|
// send all info to this client
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if(players[i].client_id != -1)
|
|
|
|
send_info(i, -1);
|
|
|
|
}
|
2007-07-22 11:53:15 +00:00
|
|
|
}
|
2007-11-04 00:19:41 +00:00
|
|
|
else if (msg == MSG_CHANGEINFO || msg == MSG_STARTINFO)
|
2007-08-14 22:48:49 +00:00
|
|
|
{
|
|
|
|
const char *name = msg_unpack_string();
|
2007-11-04 00:19:41 +00:00
|
|
|
const char *skin_name = msg_unpack_string();
|
2007-11-18 14:24:34 +00:00
|
|
|
players[client_id].use_custom_color = msg_unpack_int();
|
|
|
|
players[client_id].color_body = msg_unpack_int();
|
|
|
|
players[client_id].color_feet = msg_unpack_int();
|
2007-08-14 22:48:49 +00:00
|
|
|
|
|
|
|
// check for invalid chars
|
2007-12-19 19:56:38 +00:00
|
|
|
unsigned char *p = (unsigned char *)name;
|
2007-08-14 22:48:49 +00:00
|
|
|
while (*p)
|
2007-11-04 00:19:41 +00:00
|
|
|
{
|
|
|
|
if(*p < 32)
|
2007-12-19 19:56:38 +00:00
|
|
|
*p = ' ';
|
2007-11-04 00:19:41 +00:00
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
if(msg == MSG_CHANGEINFO && strcmp(name, server_clientname(client_id)) != 0)
|
|
|
|
{
|
|
|
|
char msg[256];
|
|
|
|
sprintf(msg, "*** %s changed name to %s", server_clientname(client_id), name);
|
|
|
|
send_chat(-1, -1, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
//send_set_name(client_id, players[client_id].name, name);
|
|
|
|
strncpy(players[client_id].skin_name, skin_name, 64);
|
|
|
|
server_setclientname(client_id, name);
|
2007-11-18 14:24:34 +00:00
|
|
|
|
|
|
|
gameobj->on_player_info_change(&players[client_id]);
|
2007-11-04 00:19:41 +00:00
|
|
|
|
|
|
|
if(msg == MSG_STARTINFO)
|
|
|
|
{
|
2008-02-02 12:38:36 +00:00
|
|
|
// a client that connected!
|
|
|
|
|
2007-11-04 00:19:41 +00:00
|
|
|
// send all info to this client
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if(players[i].client_id != -1)
|
|
|
|
send_info(i, client_id);
|
|
|
|
}
|
2008-02-02 12:38:36 +00:00
|
|
|
|
|
|
|
// send tuning parameters to client
|
|
|
|
send_tuning_params(client_id);
|
2007-11-04 00:19:41 +00:00
|
|
|
|
2008-02-02 12:38:36 +00:00
|
|
|
//
|
2007-11-04 00:19:41 +00:00
|
|
|
msg_pack_start(MSG_READY_TO_ENTER, MSGFLAG_VITAL);
|
|
|
|
msg_pack_end();
|
|
|
|
server_send_msg(client_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
send_info(client_id, -1);
|
2007-08-14 22:48:49 +00:00
|
|
|
}
|
|
|
|
else if (msg == MSG_EMOTICON)
|
|
|
|
{
|
|
|
|
int emoteicon = msg_unpack_int();
|
|
|
|
send_emoticon(client_id, emoteicon % 16);
|
|
|
|
}
|
2008-02-04 00:13:34 +00:00
|
|
|
else if (msg == MSG_KILL)
|
|
|
|
{
|
|
|
|
//int kill_client_id = msg_unpack_int(); // to be used to kill players from rcon? hihi
|
|
|
|
|
|
|
|
player *pplayer = get_player(client_id);
|
|
|
|
pplayer->die(client_id, -1);
|
|
|
|
}
|
2007-07-14 13:09:42 +00:00
|
|
|
}
|
|
|
|
|
2007-07-24 23:46:29 +00:00
|
|
|
extern unsigned char internal_data[];
|
|
|
|
|
2008-02-02 12:38:36 +00:00
|
|
|
|
|
|
|
static void con_tune_param(void *result, void *user_data)
|
|
|
|
{
|
|
|
|
const char *param_name;
|
|
|
|
float new_value;
|
|
|
|
|
|
|
|
if(console_result_string(result, 1, ¶m_name) == 0)
|
|
|
|
{
|
|
|
|
if(console_result_float(result, 2, &new_value) == 0)
|
|
|
|
{
|
|
|
|
if(tuning.set(param_name, new_value))
|
|
|
|
{
|
|
|
|
dbg_msg("tuning", "%s changed to %.2f", param_name, new_value);
|
|
|
|
send_tuning_params(-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
console_print("No such tuning parameter");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//console_print("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void con_tune_reset(void *result, void *user_data)
|
|
|
|
{
|
|
|
|
tuning_params p;
|
|
|
|
tuning = p;
|
|
|
|
send_tuning_params(-1);
|
|
|
|
console_print("tuning reset");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void con_tune_dump(void *result, void *user_data)
|
|
|
|
{
|
|
|
|
for(int i = 0; i < tuning.num(); i++)
|
|
|
|
{
|
|
|
|
float v;
|
|
|
|
tuning.get(i, &v);
|
|
|
|
dbg_msg("tuning", "%s %.2f", tuning.names[i], v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mods_console_init()
|
|
|
|
{
|
|
|
|
MACRO_REGISTER_COMMAND("tune", "s?i", con_tune_param, 0);
|
|
|
|
MACRO_REGISTER_COMMAND("tune_reset", "", con_tune_reset, 0);
|
|
|
|
MACRO_REGISTER_COMMAND("tune_dump", "", con_tune_dump, 0);
|
|
|
|
}
|
|
|
|
|
2007-05-22 15:03:32 +00:00
|
|
|
void mods_init()
|
|
|
|
{
|
2007-09-23 22:54:31 +00:00
|
|
|
if(!data) /* only load once */
|
|
|
|
data = load_data_from_memory(internal_data);
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2008-01-13 11:15:32 +00:00
|
|
|
layers_init();
|
|
|
|
col_init();
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-09-23 22:54:31 +00:00
|
|
|
world = new game_world;
|
2007-08-14 18:37:16 +00:00
|
|
|
players = new player[MAX_CLIENTS];
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-09-25 23:03:15 +00:00
|
|
|
// select gametype
|
2007-12-11 23:10:07 +00:00
|
|
|
if(strcmp(config.sv_gametype, "ctf") == 0)
|
2007-09-25 23:03:15 +00:00
|
|
|
gameobj = new gameobject_ctf;
|
2007-12-11 23:10:07 +00:00
|
|
|
else if(strcmp(config.sv_gametype, "tdm") == 0)
|
2007-09-25 23:03:15 +00:00
|
|
|
gameobj = new gameobject_tdm;
|
|
|
|
else
|
|
|
|
gameobj = new gameobject_dm;
|
2007-10-28 11:30:25 +00:00
|
|
|
|
|
|
|
// setup core world
|
2007-09-09 18:21:14 +00:00
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
2007-09-23 22:54:31 +00:00
|
|
|
players[i].core.world = &world->core;
|
2007-08-14 18:37:16 +00:00
|
|
|
|
2008-01-13 11:15:32 +00:00
|
|
|
// create all entities from the game layer
|
2008-01-29 21:39:41 +00:00
|
|
|
MAPITEM_LAYER_TILEMAP *tmap = layers_game_layer();
|
2008-01-13 11:15:32 +00:00
|
|
|
TILE *tiles = (TILE *)map_get_data(tmap->data);
|
|
|
|
|
|
|
|
num_spawn_points[0] = 0;
|
|
|
|
num_spawn_points[1] = 0;
|
|
|
|
num_spawn_points[2] = 0;
|
|
|
|
|
|
|
|
for(int y = 0; y < tmap->height; y++)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2008-01-13 11:15:32 +00:00
|
|
|
for(int x = 0; x < tmap->width; x++)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2008-01-13 11:15:32 +00:00
|
|
|
int index = tiles[y*tmap->width+x].index - ENTITY_OFFSET;
|
|
|
|
vec2 pos(x*32.0f+16.0f, y*32.0f+16.0f);
|
2008-01-13 11:43:43 +00:00
|
|
|
gameobj->on_entity(index, pos);
|
2007-07-22 12:01:20 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-09-23 22:54:31 +00:00
|
|
|
world->insert_entity(gameobj);
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-10-04 23:00:20 +00:00
|
|
|
if(config.dbg_bots)
|
|
|
|
{
|
2007-11-18 14:49:56 +00:00
|
|
|
for(int i = 0; i < config.dbg_bots ; i++)
|
2007-10-04 23:00:20 +00:00
|
|
|
{
|
2007-11-18 14:49:56 +00:00
|
|
|
mods_connected(MAX_CLIENTS-i-1);
|
|
|
|
mods_client_enter(MAX_CLIENTS-i-1);
|
|
|
|
if(gameobj->gametype != GAMETYPE_DM)
|
|
|
|
players[MAX_CLIENTS-i-1].team = i&1;
|
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-09-23 22:54:31 +00:00
|
|
|
void mods_shutdown()
|
|
|
|
{
|
|
|
|
delete [] players;
|
|
|
|
delete gameobj;
|
|
|
|
delete world;
|
|
|
|
gameobj = 0;
|
|
|
|
players = 0;
|
|
|
|
world = 0;
|
|
|
|
}
|
2007-10-28 11:30:25 +00:00
|
|
|
|
2007-05-22 15:03:32 +00:00
|
|
|
void mods_presnap() {}
|
2007-12-17 23:15:40 +00:00
|
|
|
void mods_postsnap()
|
|
|
|
{
|
|
|
|
events.clear();
|
|
|
|
}
|
2007-08-22 21:13:33 +00:00
|
|
|
|
|
|
|
extern "C" const char *mods_net_version() { return TEEWARS_NETVERSION; }
|
2007-12-19 19:56:38 +00:00
|
|
|
extern "C" const char *mods_version() { return TEEWARS_VERSION; }
|