ddnet/src/game/server/gameworld.cpp
2008-09-07 08:57:59 +00:00

218 lines
4.4 KiB
C++

#include "gameworld.hpp"
#include "entity.hpp"
#include "gamecontext.hpp"
//////////////////////////////////////////////////
// game world
//////////////////////////////////////////////////
GAMEWORLD::GAMEWORLD()
{
paused = false;
reset_requested = false;
first_entity = 0x0;
for(int i = 0; i < NUM_ENT_TYPES; i++)
first_entity_types[i] = 0;
}
GAMEWORLD::~GAMEWORLD()
{
// delete all entities
while(first_entity)
delete first_entity;
}
ENTITY *GAMEWORLD::find_first(int type)
{
return first_entity_types[type];
}
int GAMEWORLD::find_entities(vec2 pos, float radius, ENTITY **ents, int max, int type)
{
int num = 0;
for(ENTITY *ent = (type<0) ? first_entity : first_entity_types[type];
ent; ent = (type<0) ? ent->next_entity : ent->next_type_entity)
{
if(distance(ent->pos, pos) < radius+ent->proximity_radius)
{
ents[num] = ent;
num++;
if(num == max)
break;
}
}
return num;
}
void GAMEWORLD::insert_entity(ENTITY *ent)
{
ENTITY *cur = first_entity;
while(cur)
{
dbg_assert(cur != ent, "err");
cur = cur->next_entity;
}
// 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 GAMEWORLD::destroy_entity(ENTITY *ent)
{
ent->marked_for_destroy = true;
}
void GAMEWORLD::remove_entity(ENTITY *ent)
{
// not in the list
if(!ent->next_entity && !ent->prev_entity && first_entity != ent)
return;
// 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;
ent->next_entity = 0;
ent->prev_entity = 0;
ent->next_type_entity = 0;
ent->prev_type_entity = 0;
}
//
void GAMEWORLD::snap(int snapping_client)
{
for(ENTITY *ent = first_entity; ent; ent = ent->next_entity)
ent->snap(snapping_client);
}
void GAMEWORLD::reset()
{
// reset all entities
for(ENTITY *ent = first_entity; ent; ent = ent->next_entity)
ent->reset();
remove_entities();
game.controller->post_reset();
remove_entities();
reset_requested = false;
}
void GAMEWORLD::remove_entities()
{
// destroy objects marked for destruction
ENTITY *ent = first_entity;
while(ent)
{
ENTITY *next = ent->next_entity;
if(ent->marked_for_destroy)
{
remove_entity(ent);
ent->destroy();
}
ent = next;
}
}
void GAMEWORLD::tick()
{
if(reset_requested)
reset();
if(!paused)
{
if(game.controller->is_force_balanced())
game.send_chat(-1, GAMECONTEXT::CHAT_ALL, "Teams have been balanced");
// update all objects
for(ENTITY *ent = first_entity; ent; ent = ent->next_entity)
ent->tick();
for(ENTITY *ent = first_entity; ent; ent = ent->next_entity)
ent->tick_defered();
}
remove_entities();
}
// TODO: should be more general
CHARACTER *GAMEWORLD::intersect_character(vec2 pos0, vec2 pos1, float radius, vec2& new_pos, ENTITY *notthis)
{
// Find other players
float closest_len = distance(pos0, pos1) * 100.0f;
vec2 line_dir = normalize(pos1-pos0);
CHARACTER *closest = 0;
CHARACTER *p = (CHARACTER *)game.world.find_first(NETOBJTYPE_CHARACTER);
for(; p; p = (CHARACTER *)p->typenext())
{
if(p == notthis)
continue;
vec2 intersect_pos = closest_point_on_line(pos0, pos1, p->pos);
float len = distance(p->pos, intersect_pos);
if(len < CHARACTER::phys_size+radius)
{
if(len < closest_len)
{
new_pos = intersect_pos;
closest_len = len;
closest = p;
}
}
}
return closest;
}
CHARACTER *GAMEWORLD::closest_character(vec2 pos, float radius, ENTITY *notthis)
{
// Find other players
float closest_range = radius*2;
CHARACTER *closest = 0;
CHARACTER *p = (CHARACTER *)game.world.find_first(NETOBJTYPE_CHARACTER);
for(; p; p = (CHARACTER *)p->typenext())
{
if(p == notthis)
continue;
float len = distance(pos, p->pos);
if(len < CHARACTER::phys_size+radius)
{
if(len < closest_range)
{
closest_range = len;
closest = p;
}
}
}
return closest;
}