mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-14 03:58:18 +00:00
341 lines
6.5 KiB
C++
341 lines
6.5 KiB
C++
#include <new>
|
|
#include <engine/e_server_interface.h>
|
|
#include "gamecontext.hpp"
|
|
|
|
GAMECONTEXT game;
|
|
|
|
GAMECONTEXT::GAMECONTEXT()
|
|
{
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
players[i] = 0;
|
|
|
|
vote_closetime = 0;
|
|
}
|
|
|
|
GAMECONTEXT::~GAMECONTEXT()
|
|
{
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
delete players[i];
|
|
}
|
|
|
|
void GAMECONTEXT::clear()
|
|
{
|
|
this->~GAMECONTEXT();
|
|
mem_zero(this, sizeof(*this));
|
|
new (this) GAMECONTEXT();
|
|
}
|
|
|
|
|
|
void GAMECONTEXT::create_damageind(vec2 p, float angle, int amount)
|
|
{
|
|
float a = 3 * 3.14159f / 2 + angle;
|
|
//float a = get_angle(dir);
|
|
float s = a-pi/3;
|
|
float e = a+pi/3;
|
|
for(int i = 0; i < amount; i++)
|
|
{
|
|
float f = mix(s, e, float(i+1)/float(amount+2));
|
|
NETEVENT_DAMAGEIND *ev = (NETEVENT_DAMAGEIND *)events.create(NETEVENTTYPE_DAMAGEIND, sizeof(NETEVENT_DAMAGEIND));
|
|
if(ev)
|
|
{
|
|
ev->x = (int)p.x;
|
|
ev->y = (int)p.y;
|
|
ev->angle = (int)(f*256.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
void GAMECONTEXT::create_hammerhit(vec2 p)
|
|
{
|
|
// create the event
|
|
NETEVENT_HAMMERHIT *ev = (NETEVENT_HAMMERHIT *)events.create(NETEVENTTYPE_HAMMERHIT, sizeof(NETEVENT_HAMMERHIT));
|
|
if(ev)
|
|
{
|
|
ev->x = (int)p.x;
|
|
ev->y = (int)p.y;
|
|
}
|
|
}
|
|
|
|
|
|
void GAMECONTEXT::create_explosion(vec2 p, int owner, int weapon, bool bnodamage)
|
|
{
|
|
// create the event
|
|
NETEVENT_EXPLOSION *ev = (NETEVENT_EXPLOSION *)events.create(NETEVENTTYPE_EXPLOSION, sizeof(NETEVENT_EXPLOSION));
|
|
if(ev)
|
|
{
|
|
ev->x = (int)p.x;
|
|
ev->y = (int)p.y;
|
|
}
|
|
|
|
if (!bnodamage)
|
|
{
|
|
// deal damage
|
|
CHARACTER *ents[64];
|
|
float radius = 128.0f;
|
|
float innerradius = 42.0f;
|
|
int num = game.world.find_entities(p, radius, (ENTITY**)ents, 64, NETOBJTYPE_CHARACTER);
|
|
for(int i = 0; i < num; i++)
|
|
{
|
|
vec2 diff = ents[i]->pos - p;
|
|
vec2 forcedir(0,1);
|
|
float l = length(diff);
|
|
if(l)
|
|
forcedir = normalize(diff);
|
|
l = 1-clamp((l-innerradius)/(radius-innerradius), 0.0f, 1.0f);
|
|
float dmg = 6 * l;
|
|
if((int)dmg)
|
|
ents[i]->take_damage(forcedir*dmg*2, (int)dmg, owner, weapon);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
void create_smoke(vec2 p)
|
|
{
|
|
// create the event
|
|
EV_EXPLOSION *ev = (EV_EXPLOSION *)events.create(EVENT_SMOKE, sizeof(EV_EXPLOSION));
|
|
if(ev)
|
|
{
|
|
ev->x = (int)p.x;
|
|
ev->y = (int)p.y;
|
|
}
|
|
}*/
|
|
|
|
void GAMECONTEXT::create_playerspawn(vec2 p)
|
|
{
|
|
// create the event
|
|
NETEVENT_SPAWN *ev = (NETEVENT_SPAWN *)events.create(NETEVENTTYPE_SPAWN, sizeof(NETEVENT_SPAWN));
|
|
if(ev)
|
|
{
|
|
ev->x = (int)p.x;
|
|
ev->y = (int)p.y;
|
|
}
|
|
}
|
|
|
|
void GAMECONTEXT::create_death(vec2 p, int cid)
|
|
{
|
|
// create the event
|
|
NETEVENT_DEATH *ev = (NETEVENT_DEATH *)events.create(NETEVENTTYPE_DEATH, sizeof(NETEVENT_DEATH));
|
|
if(ev)
|
|
{
|
|
ev->x = (int)p.x;
|
|
ev->y = (int)p.y;
|
|
ev->cid = cid;
|
|
}
|
|
}
|
|
|
|
void GAMECONTEXT::create_sound(vec2 pos, int sound, int mask)
|
|
{
|
|
if (sound < 0)
|
|
return;
|
|
|
|
// create a sound
|
|
NETEVENT_SOUNDWORLD *ev = (NETEVENT_SOUNDWORLD *)events.create(NETEVENTTYPE_SOUNDWORLD, sizeof(NETEVENT_SOUNDWORLD), mask);
|
|
if(ev)
|
|
{
|
|
ev->x = (int)pos.x;
|
|
ev->y = (int)pos.y;
|
|
ev->soundid = sound;
|
|
}
|
|
}
|
|
|
|
void GAMECONTEXT::create_sound_global(int sound, int target)
|
|
{
|
|
if (sound < 0)
|
|
return;
|
|
|
|
NETMSG_SV_SOUNDGLOBAL msg;
|
|
msg.soundid = sound;
|
|
msg.pack(MSGFLAG_VITAL);
|
|
server_send_msg(target);
|
|
}
|
|
|
|
void GAMECONTEXT::send_chat(int chatter_cid, int team, const char *text)
|
|
{
|
|
if(chatter_cid >= 0 && chatter_cid < MAX_CLIENTS)
|
|
dbg_msg("chat", "%d:%d:%s: %s", chatter_cid, team, server_clientname(chatter_cid), text);
|
|
else
|
|
dbg_msg("chat", "*** %s", text);
|
|
|
|
if(team == CHAT_ALL)
|
|
{
|
|
NETMSG_SV_CHAT msg;
|
|
msg.team = 0;
|
|
msg.cid = chatter_cid;
|
|
msg.message = text;
|
|
msg.pack(MSGFLAG_VITAL);
|
|
server_send_msg(-1);
|
|
}
|
|
else
|
|
{
|
|
NETMSG_SV_CHAT msg;
|
|
msg.team = 1;
|
|
msg.cid = chatter_cid;
|
|
msg.message = text;
|
|
msg.pack(MSGFLAG_VITAL);
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
{
|
|
if(game.players[i] && game.players[i]->team == team)
|
|
server_send_msg(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void GAMECONTEXT::send_emoticon(int cid, int emoticon)
|
|
{
|
|
NETMSG_SV_EMOTICON msg;
|
|
msg.cid = cid;
|
|
msg.emoticon = emoticon;
|
|
msg.pack(MSGFLAG_VITAL);
|
|
server_send_msg(-1);
|
|
}
|
|
|
|
void GAMECONTEXT::send_weapon_pickup(int cid, int weapon)
|
|
{
|
|
NETMSG_SV_WEAPONPICKUP msg;
|
|
msg.weapon = weapon;
|
|
msg.pack(MSGFLAG_VITAL);
|
|
server_send_msg(cid);
|
|
}
|
|
|
|
|
|
void GAMECONTEXT::send_broadcast(const char *text, int cid)
|
|
{
|
|
NETMSG_SV_BROADCAST msg;
|
|
msg.message = text;
|
|
msg.pack(MSGFLAG_VITAL);
|
|
server_send_msg(cid);
|
|
}
|
|
|
|
//
|
|
void GAMECONTEXT::start_vote(const char *desc, const char *command)
|
|
{
|
|
// check if a vote is already running
|
|
if(vote_closetime)
|
|
return;
|
|
|
|
// reset votes
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
{
|
|
if(players[i])
|
|
players[i]->vote = 0;
|
|
}
|
|
|
|
// start vote
|
|
vote_closetime = time_get() + time_freq()*10;
|
|
str_copy(vote_description, desc, sizeof(vote_description));
|
|
str_copy(vote_command, command, sizeof(vote_description));
|
|
send_vote_set(-1);
|
|
send_vote_status(-1);
|
|
}
|
|
|
|
|
|
void GAMECONTEXT::end_vote()
|
|
{
|
|
vote_closetime = 0;
|
|
send_vote_set(-1);
|
|
}
|
|
|
|
void GAMECONTEXT::send_vote_set(int cid)
|
|
{
|
|
NETMSG_SV_VOTE_SET msg;
|
|
if(vote_closetime)
|
|
{
|
|
msg.timeout = (vote_closetime-time_get())/time_freq();
|
|
msg.description = vote_description;
|
|
msg.command = vote_command;
|
|
}
|
|
else
|
|
{
|
|
msg.timeout = 0;
|
|
msg.description = "";
|
|
msg.command = "";
|
|
}
|
|
msg.pack(MSGFLAG_VITAL);
|
|
server_send_msg(cid);
|
|
}
|
|
|
|
void GAMECONTEXT::send_vote_status(int cid)
|
|
{
|
|
NETMSG_SV_VOTE_STATUS msg = {0};
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
{
|
|
if(players[i])
|
|
{
|
|
msg.total++;
|
|
if(players[i]->vote > 0)
|
|
msg.yes++;
|
|
else if(players[i]->vote < 0)
|
|
msg.no++;
|
|
else
|
|
msg.pass++;
|
|
}
|
|
}
|
|
|
|
msg.pack(MSGFLAG_VITAL);
|
|
server_send_msg(cid);
|
|
|
|
}
|
|
|
|
void GAMECONTEXT::tick()
|
|
{
|
|
world.core.tuning = tuning;
|
|
world.tick();
|
|
|
|
//if(world.paused) // make sure that the game object always updates
|
|
controller->tick();
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
{
|
|
if(players[i])
|
|
players[i]->tick();
|
|
}
|
|
|
|
// update voting
|
|
if(vote_closetime)
|
|
{
|
|
// count votes
|
|
int total = 0, yes = 0, no = 0;
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
{
|
|
if(players[i])
|
|
{
|
|
total++;
|
|
if(players[i]->vote > 0)
|
|
yes++;
|
|
else if(players[i]->vote < 0)
|
|
no++;
|
|
}
|
|
}
|
|
|
|
if(yes >= total/2+1)
|
|
{
|
|
console_execute_line(vote_command);
|
|
end_vote();
|
|
send_chat(-1, GAMECONTEXT::CHAT_ALL, "Vote passed");
|
|
|
|
if(players[vote_creator])
|
|
players[vote_creator]->last_votecall = 0;
|
|
}
|
|
else if(time_get() > vote_closetime || no >= total/2+1 || yes+no == total)
|
|
{
|
|
end_vote();
|
|
send_chat(-1, GAMECONTEXT::CHAT_ALL, "Vote failed");
|
|
}
|
|
}
|
|
}
|
|
|
|
void GAMECONTEXT::snap(int client_id)
|
|
{
|
|
world.snap(client_id);
|
|
controller->snap(client_id);
|
|
events.snap(client_id);
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
{
|
|
if(players[i])
|
|
players[i]->snap(client_id);
|
|
}
|
|
}
|