moved alot of stuff to their own cpp/hpp files

This commit is contained in:
Magnus Auvinen 2008-08-14 18:25:44 +00:00
parent 817f431377
commit a420eb543f
23 changed files with 901 additions and 813 deletions

View file

@ -1,8 +1,11 @@
#include <new>
#include <engine/e_server_interface.h>
#include <engine/e_config.h>
#include "gs_common.hpp"
#include <game/server/gs_common.hpp>
#include "character.hpp"
#include "laser.hpp"
#include "projectile.hpp"
struct INPUT_COUNT
{

View file

@ -0,0 +1,122 @@
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
#ifndef GAME_SERVER_ENTITY_CHARACTER_H
#define GAME_SERVER_ENTITY_CHARACTER_H
#include <game/server/entity.hpp>
#include <game/generated/gs_data.hpp>
#include <game/generated/g_protocol.hpp>
#include <game/g_game.hpp>
class CHARACTER : public ENTITY
{
public:
// player controlling this character
class PLAYER *player;
bool alive;
// weapon info
ENTITY *hitobjects[10];
int numobjectshit;
struct WEAPONSTAT
{
int ammoregenstart;
int ammo;
int ammocost;
bool got;
} weapons[NUM_WEAPONS];
int active_weapon;
int last_weapon;
int queued_weapon;
int reload_timer;
int attack_tick;
int damage_taken;
int emote_type;
int emote_stop;
// TODO: clean this up
char skin_name[64];
int use_custom_color;
int color_body;
int color_feet;
int last_action; // last tick that the player took any action ie some input
// these are non-heldback inputs
NETOBJ_PLAYER_INPUT latest_previnput;
NETOBJ_PLAYER_INPUT latest_input;
// input
NETOBJ_PLAYER_INPUT previnput;
NETOBJ_PLAYER_INPUT input;
int num_inputs;
int jumped;
int damage_taken_tick;
int health;
int armor;
// ninja
struct
{
vec2 activationdir;
int activationtick;
int currentcooldown;
int currentmovetime;
} ninja;
//
//int score;
int team;
int player_state; // if the client is chatting, accessing a menu or so
// the player core for the physics
CHARACTER_CORE core;
//
CHARACTER();
virtual void reset();
virtual void destroy();
bool is_grounded();
void set_weapon(int w);
void handle_weaponswitch();
void do_weaponswitch();
int handle_weapons();
int handle_ninja();
void on_predicted_input(NETOBJ_PLAYER_INPUT *new_input);
void on_direct_input(NETOBJ_PLAYER_INPUT *new_input);
void fire_weapon();
void die(int killer, int weapon);
bool take_damage(vec2 force, int dmg, int from, int weapon);
bool spawn(PLAYER *player, vec2 pos, int team);
//bool init_tryspawn(int team);
bool remove();
static const int phys_size = 28;
virtual void tick();
virtual void tick_defered();
virtual void snap(int snaping_client);
bool increase_health(int amount);
bool increase_armor(int amount);
};
#endif

View file

@ -0,0 +1,112 @@
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
#include <engine/e_server_interface.h>
#include <game/generated/g_protocol.hpp>
#include <game/server/gs_common.hpp>
#include "laser.hpp"
//////////////////////////////////////////////////
// laser
//////////////////////////////////////////////////
LASER::LASER(vec2 pos, vec2 direction, float start_energy, CHARACTER *owner)
: ENTITY(NETOBJTYPE_LASER)
{
this->pos = pos;
this->owner = owner;
energy = start_energy;
dir = direction;
bounces = 0;
do_bounce();
game.world.insert_entity(this);
}
bool LASER::hit_character(vec2 from, vec2 to)
{
vec2 at;
CHARACTER *hit = game.world.intersect_character(pos, to, 0.0f, at, owner);
if(!hit)
return false;
this->from = from;
pos = at;
energy = -1;
hit->take_damage(vec2(0,0), tuning.laser_damage, owner->player->client_id, WEAPON_RIFLE);
return true;
}
void LASER::do_bounce()
{
eval_tick = server_tick();
if(energy < 0)
{
//dbg_msg("laser", "%d removed", server_tick());
game.world.destroy_entity(this);
return;
}
vec2 to = pos + dir*energy;
if(col_intersect_line(pos, to, &to))
{
if(!hit_character(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);
pos = temp_pos;
dir = normalize(temp_dir);
energy -= distance(from, pos) + tuning.laser_bounce_cost;
bounces++;
if(bounces > tuning.laser_bounce_num)
energy = -1;
game.create_sound(pos, SOUND_RIFLE_BOUNCE);
}
}
else
{
if(!hit_character(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()
{
game.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(game.players[snapping_client].view_pos, pos) > 1000.0f)
return;
NETOBJ_LASER *obj = (NETOBJ_LASER *)snap_new_item(NETOBJTYPE_LASER, id, sizeof(NETOBJ_LASER));
obj->x = (int)pos.x;
obj->y = (int)pos.y;
obj->from_x = (int)from.x;
obj->from_y = (int)from.y;
obj->start_tick = eval_tick;
}

View file

@ -0,0 +1,31 @@
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
#ifndef GAME_SERVER_ENTITY_LASER_H
#define GAME_SERVER_ENTITY_LASER_H
#include <game/server/entity.hpp>
class CHARACTER;
class LASER : public ENTITY
{
vec2 from;
vec2 dir;
float energy;
int bounces;
int eval_tick;
CHARACTER *owner;
bool hit_character(vec2 from, vec2 to);
void do_bounce();
public:
LASER(vec2 pos, vec2 direction, float start_energy, CHARACTER *owner);
virtual void reset();
virtual void tick();
virtual void snap(int snapping_client);
};
#endif

View file

@ -1,8 +1,10 @@
#include <engine/e_server_interface.h>
#include "gs_common.hpp"
#include <game/generated/g_protocol.hpp>
#include <game/server/gs_common.hpp>
#include "pickup.hpp"
//////////////////////////////////////////////////
// powerup
// pickup
//////////////////////////////////////////////////
PICKUP::PICKUP(int _type, int _subtype)
: ENTITY(NETOBJTYPE_PICKUP)

View file

@ -0,0 +1,24 @@
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
#ifndef GAME_SERVER_ENTITY_PICKUP_H
#define GAME_SERVER_ENTITY_PICKUP_H
#include <game/server/entity.hpp>
// TODO: move to seperate file
class PICKUP : public ENTITY
{
public:
static const int phys_size = 14;
int type;
int subtype; // weapon type for instance?
int spawntick;
PICKUP(int _type, int _subtype = 0);
virtual void reset();
virtual void tick();
virtual void snap(int snapping_client);
};
#endif

View file

@ -0,0 +1,108 @@
#include <engine/e_server_interface.h>
#include <game/generated/g_protocol.hpp>
#include <game/server/gs_common.hpp>
#include "projectile.hpp"
//////////////////////////////////////////////////
// projectile
//////////////////////////////////////////////////
PROJECTILE::PROJECTILE(int type, int owner, vec2 pos, vec2 dir, int span, ENTITY* powner,
int damage, int flags, float force, int sound_impact, int weapon)
: ENTITY(NETOBJTYPE_PROJECTILE)
{
this->type = type;
this->pos = pos;
this->direction = dir;
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;
this->bounce = 0;
this->start_tick = server_tick();
game.world.insert_entity(this);
}
void PROJECTILE::reset()
{
game.world.destroy_entity(this);
}
vec2 PROJECTILE::get_pos(float time)
{
float curvature = 0;
float speed = 0;
if(type == WEAPON_GRENADE)
{
curvature = tuning.grenade_curvature;
speed = tuning.grenade_speed;
}
else if(type == WEAPON_SHOTGUN)
{
curvature = tuning.shotgun_curvature;
speed = tuning.shotgun_speed;
}
else if(type == WEAPON_GUN)
{
curvature = tuning.gun_curvature;
speed = tuning.gun_speed;
}
return calc_pos(pos, direction, curvature, speed, time);
}
void PROJECTILE::tick()
{
float pt = (server_tick()-start_tick-1)/(float)server_tickspeed();
float ct = (server_tick()-start_tick)/(float)server_tickspeed();
vec2 prevpos = get_pos(pt);
vec2 curpos = get_pos(ct);
lifespan--;
int collide = col_intersect_line(prevpos, curpos, &curpos);
//int collide = col_check_point((int)curpos.x, (int)curpos.y);
CHARACTER *targetchr = game.world.intersect_character(prevpos, curpos, 6.0f, curpos, powner);
if(targetchr || collide || lifespan < 0)
{
if(lifespan >= 0 || weapon == WEAPON_GRENADE)
game.create_sound(curpos, sound_impact);
if(flags & PROJECTILE_FLAGS_EXPLODE)
game.create_explosion(curpos, owner, weapon, false);
else if(targetchr)
{
targetchr->take_damage(direction * max(0.001f, force), damage, owner, weapon);
}
game.world.destroy_entity(this);
}
}
void PROJECTILE::fill_info(NETOBJ_PROJECTILE *proj)
{
proj->x = (int)pos.x;
proj->y = (int)pos.y;
proj->vx = (int)(direction.x*100.0f);
proj->vy = (int)(direction.y*100.0f);
proj->start_tick = start_tick;
proj->type = type;
}
void PROJECTILE::snap(int snapping_client)
{
float ct = (server_tick()-start_tick)/(float)server_tickspeed();
if(distance(game.players[snapping_client].view_pos, get_pos(ct)) > 1000.0f)
return;
NETOBJ_PROJECTILE *proj = (NETOBJ_PROJECTILE *)snap_new_item(NETOBJTYPE_PROJECTILE, id, sizeof(NETOBJ_PROJECTILE));
fill_info(proj);
}

View file

@ -0,0 +1,38 @@
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
#ifndef GAME_SERVER_ENTITY_PROJECTILE_H
#define GAME_SERVER_ENTITY_PROJECTILE_H
class PROJECTILE : public ENTITY
{
public:
enum
{
PROJECTILE_FLAGS_EXPLODE = 1 << 0,
};
vec2 direction;
ENTITY *powner; // this is nasty, could be removed when client quits
int lifespan;
int owner;
int type;
int flags;
int damage;
int sound_impact;
int weapon;
int bounce;
float force;
int start_tick;
PROJECTILE(int type, int owner, vec2 pos, vec2 vel, int span, ENTITY* powner,
int damage, int flags, float force, int sound_impact, int weapon);
vec2 get_pos(float time);
void fill_info(NETOBJ_PROJECTILE *proj);
virtual void reset();
virtual void tick();
virtual void snap(int snapping_client);
};
#endif

View file

@ -0,0 +1,83 @@
#ifndef GAME_SERVER_ENTITY_H
#define GAME_SERVER_ENTITY_H
#include <base/vmath.hpp>
/*
Class: Entity
Basic entity class.
*/
class ENTITY
{
private:
friend class GAMEWORLD; // thy these?
ENTITY *prev_entity;
ENTITY *next_entity;
ENTITY *prev_type_entity;
ENTITY *next_type_entity;
protected:
bool marked_for_destroy;
int id;
int objtype;
public:
ENTITY(int objtype);
virtual ~ENTITY();
ENTITY *typenext() { return next_type_entity; }
ENTITY *typeprev() { return prev_type_entity; }
/*
Function: destroy
Destorys the entity.
*/
virtual void destroy() { delete this; }
/*
Function: reset
Called when the game resets the map. Puts the entity
back to it's starting state or perhaps destroys it.
*/
virtual void reset() {}
/*
Function: tick
Called progress the entity to the next tick. Updates
and moves the entity to it's new state and position.
*/
virtual void tick() {}
/*
Function: tick_defered
Called after all entities tick() function has been called.
*/
virtual void tick_defered() {}
/*
Function: snap
Called when a new snapshot is being generated for a specific
client.
Arguments:
snapping_client - ID of the client which snapshot is
being generated. Could be -1 to create a complete
snapshot of everything in the game for demo
recording.
*/
virtual void snap(int snapping_client) {}
/*
Variable: proximity_radius
Contains the physical size of the entity.
*/
float proximity_radius;
/*
Variable: pos
Contains the current posititon of the entity.
*/
vec2 pos;
};
#endif

View file

@ -0,0 +1,25 @@
#ifndef GAME_SERVER_EVENTHANDLER_H
#define GAME_SERVER_EVENTHANDLER_H
//
class EVENTHANDLER
{
static const int MAX_EVENTS = 128;
static const int MAX_DATASIZE = 128*64;
int types[MAX_EVENTS]; // TODO: remove some of these arrays
int offsets[MAX_EVENTS];
int sizes[MAX_EVENTS];
int client_masks[MAX_EVENTS];
char data[MAX_DATASIZE];
int current_offset;
int num_events;
public:
EVENTHANDLER();
void *create(int type, int size, int mask = -1);
void clear();
void snap(int snapping_client);
};
#endif

View file

@ -0,0 +1,38 @@
#include "eventhandler.hpp"
#include "gamecontroller.hpp"
#include "gameworld.hpp"
class GAMECONTEXT
{
public:
GAMECONTEXT();
void clear();
EVENTHANDLER events;
PLAYER players[MAX_CLIENTS];
GAMECONTROLLER *controller;
GAMEWORLD world;
void tick();
void snap(int client_id);
// helper functions
void create_damageind(vec2 p, float angle_mod, int amount);
void create_explosion(vec2 p, int owner, int weapon, bool bnodamage);
void create_smoke(vec2 p);
void create_playerspawn(vec2 p);
void create_death(vec2 p, int who);
void create_sound(vec2 pos, int sound, int mask=-1);
void create_sound_global(int sound, int target=-1);
// network
void send_chat(int cid, int team, const char *text);
void send_emoticon(int cid, int emoticon);
void send_weapon_pickup(int cid, int weapon);
void send_broadcast(const char *text, int cid);
void send_info(int who, int to_who);
};
extern GAMECONTEXT game;

View file

@ -5,6 +5,8 @@
#include <game/g_mapitems.hpp>
#include "gs_common.hpp"
#include "entities/pickup.hpp"
GAMECONTROLLER::GAMECONTROLLER()
{
// select gametype

View file

@ -0,0 +1,97 @@
#ifndef GAME_SERVER_GAMECONTROLLER_H
#define GAME_SERVER_GAMECONTROLLER_H
#include <base/vmath.hpp>
/*
Class: Game Controller
Controls the main game logic. Keeping track of team and player score,
winning conditions and specific game logic.
*/
class GAMECONTROLLER
{
protected:
void cyclemap();
void resetgame();
int round_start_tick;
int game_over_tick;
int sudden_death;
int teamscore[2];
int warmup;
int round_count;
bool is_teamplay;
public:
int gametype;
GAMECONTROLLER();
void do_team_score_wincheck();
void do_player_score_wincheck();
void do_warmup(int seconds);
void startround();
void endround();
bool is_friendly_fire(int cid1, int cid2);
/*
*/
virtual void tick();
virtual void snap(int snapping_client);
/*
Function: on_entity
Called when the map is loaded to process an entity
in the map.
Arguments:
index - Entity index.
pos - Where the entity is located in the world.
Returns:
bool?
*/
virtual bool on_entity(int index, vec2 pos);
/*
Function: on_character_spawn
Called when a character spawns into the game world.
Arguments:
chr - The character that was spawned.
*/
virtual void on_character_spawn(class CHARACTER *chr) {}
/*
Function: on_character_death
Called when a character in the world dies.
Arguments:
victim - The character that died.
killer - The player that killed it.
weapon - What weapon that killed it. Can be -1 for undefined
weapon when switching team or player suicides.
*/
virtual int on_character_death(class CHARACTER *victim, class PLAYER *killer, int weapon);
virtual void on_player_info_change(class PLAYER *p);
/*
*/
virtual const char *get_team_name(int team);
virtual int get_auto_team(int notthisid);
virtual bool can_join_team(int team, int notthisid);
int clampteam(int team);
virtual void post_reset();
};
#endif

View file

@ -1,8 +1,10 @@
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
#include <engine/e_server_interface.h>
#include <game/g_mapitems.hpp>
#include "gs_common.hpp"
#include "gs_game_ctf.hpp"
#include <game/server/entities/character.hpp>
#include <game/server/player.hpp>
#include <game/server/gamecontext.hpp>
#include "ctf.hpp"
GAMECONTROLLER_CTF::GAMECONTROLLER_CTF()
{

View file

@ -1,6 +1,8 @@
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
// game object
#include <game/server/gamecontroller.hpp>
#include <game/server/entity.hpp>
class GAMECONTROLLER_CTF : public GAMECONTROLLER
{
public:

View file

@ -1,7 +1,5 @@
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
#include <engine/e_config.h>
#include "gs_common.hpp"
#include "gs_game_dm.hpp"
#include "dm.hpp"
void GAMECONTROLLER_DM::tick()
{

View file

@ -1,5 +1,7 @@
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
// game object
#include <game/server/gamecontroller.hpp>
class GAMECONTROLLER_DM : public GAMECONTROLLER
{
public:

View file

@ -1,7 +1,8 @@
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
#include <engine/e_config.h>
#include "gs_common.hpp"
#include "gs_game_tdm.hpp"
#include <engine/e_server_interface.h>
#include <game/server/entities/character.hpp>
#include <game/server/player.hpp>
#include "tdm.hpp"
GAMECONTROLLER_TDM::GAMECONTROLLER_TDM()
{

View file

@ -1,5 +1,7 @@
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
// game object
#include <game/server/gamecontroller.hpp>
class GAMECONTROLLER_TDM : public GAMECONTROLLER
{
public:

View file

@ -0,0 +1,126 @@
class CHARACTER;
/*
Class: Game World
Tracks all entities in the game. Propagates tick and
snap calls to all entities.
*/
class GAMEWORLD
{
void reset();
void remove_entities();
enum
{
NUM_ENT_TYPES=10, // TODO: are more exact value perhaps? :)
};
// TODO: two lists seams kinda not good, shouldn't be needed
ENTITY *first_entity;
ENTITY *first_entity_types[NUM_ENT_TYPES];
public:
bool reset_requested;
bool paused;
WORLD_CORE core;
GAMEWORLD();
~GAMEWORLD();
ENTITY *find_first() { return first_entity; }
ENTITY *find_first(int type);
/*
Function: find_entities
Finds entities close to a position and returns them in a list.
Arguments:
pos - Position.
radius - How close the entities have to be.
ents - Pointer to a list that should be filled with the pointers
to the entities.
max - Number of entities that fits into the ents array.
type - Type of the entities to find. -1 for all types.
Returns:
Number of entities found and added to the ents array.
*/
int find_entities(vec2 pos, float radius, ENTITY **ents, int max, int type = -1);
/*
Function: interserct_character
Finds the closest character that intersects the line.
Arguments:
pos0 - Start position
pos2 - End position
radius - How for from the line the character is allowed to be.
new_pos - Intersection position
notthis - Entity to ignore intersecting with
Returns:
Returns a pointer to the closest hit or NULL of there is no intersection.
*/
class CHARACTER *intersect_character(vec2 pos0, vec2 pos1, float radius, vec2 &new_pos, class ENTITY *notthis = 0);
/*
Function: closest_character
Finds the closest character to a specific point.
Arguments:
pos - The center position.
radius - How far off the character is allowed to be
notthis - Entity to ignore
Returns:
Returns a pointer to the closest character or NULL if no character is close enough.
*/
class CHARACTER *closest_character(vec2 pos, float radius, ENTITY *notthis);
/*
Function: insert_entity
Adds an entity to the world.
Arguments:
entity - Entity to add
*/
void insert_entity(ENTITY *entity);
/*
Function: remove_entity
Removes an entity from the world.
Arguments:
entity - Entity to remove
*/
void remove_entity(ENTITY *entity);
/*
Function: destroy_entity
Destroys an entity in the world.
Arguments:
entity - Entity to destroy
*/
void destroy_entity(ENTITY *entity);
/*
Function: snap
Calls snap on all the entities in the world to create
the snapshot.
Arguments:
snapping_client - ID of the client which snapshot
is being created.
*/
void snap(int snapping_client);
/*
Function: tick
Calls tick on all the entities in the world to progress
the world to the next tick.
*/
void tick();
};

View file

@ -32,590 +32,15 @@ inline bool cmask_is_set(int mask, int cid) { return (mask&cmask_one(cid)) != 0;
*/
#include "eventhandler.hpp"
//
class EVENT_HANDLER
{
static const int MAX_EVENTS = 128;
static const int MAX_DATASIZE = 128*64;
int types[MAX_EVENTS]; // TODO: remove some of these arrays
int offsets[MAX_EVENTS];
int sizes[MAX_EVENTS];
int client_masks[MAX_EVENTS];
char data[MAX_DATASIZE];
int current_offset;
int num_events;
public:
EVENT_HANDLER();
void *create(int type, int size, int mask = -1);
void clear();
void snap(int snapping_client);
};
/*
Class: Entity
Basic entity class.
*/
class ENTITY
{
private:
friend class GAMEWORLD; // thy these?
ENTITY *prev_entity;
ENTITY *next_entity;
ENTITY *prev_type_entity;
ENTITY *next_type_entity;
protected:
bool marked_for_destroy;
int id;
int objtype;
public:
ENTITY(int objtype);
virtual ~ENTITY();
ENTITY *typenext() { return next_type_entity; }
ENTITY *typeprev() { return prev_type_entity; }
/*
Function: destroy
Destorys the entity.
*/
virtual void destroy() { delete this; }
/*
Function: reset
Called when the game resets the map. Puts the entity
back to it's starting state or perhaps destroys it.
*/
virtual void reset() {}
/*
Function: tick
Called progress the entity to the next tick. Updates
and moves the entity to it's new state and position.
*/
virtual void tick() {}
/*
Function: tick_defered
Called after all entities tick() function has been called.
*/
virtual void tick_defered() {}
/*
Function: snap
Called when a new snapshot is being generated for a specific
client.
Arguments:
snapping_client - ID of the client which snapshot is
being generated. Could be -1 to create a complete
snapshot of everything in the game for demo
recording.
*/
virtual void snap(int snapping_client) {}
/*
Variable: proximity_radius
Contains the physical size of the entity.
*/
float proximity_radius;
/*
Variable: pos
Contains the current posititon of the entity.
*/
vec2 pos;
};
#include "entity.hpp"
/*
Class: Game World
Tracks all entities in the game. Propagates tick and
snap calls to all entities.
*/
class GAMEWORLD
{
void reset();
void remove_entities();
enum
{
NUM_ENT_TYPES=10, // TODO: are more exact value perhaps? :)
};
// TODO: two lists seams kinda not good, shouldn't be needed
ENTITY *first_entity;
ENTITY *first_entity_types[NUM_ENT_TYPES];
public:
bool reset_requested;
bool paused;
WORLD_CORE core;
GAMEWORLD();
~GAMEWORLD();
ENTITY *find_first() { return first_entity; }
ENTITY *find_first(int type);
/*
Function: find_entities
Finds entities close to a position and returns them in a list.
Arguments:
pos - Position.
radius - How close the entities have to be.
ents - Pointer to a list that should be filled with the pointers
to the entities.
max - Number of entities that fits into the ents array.
type - Type of the entities to find. -1 for all types.
Returns:
Number of entities found and added to the ents array.
*/
int find_entities(vec2 pos, float radius, ENTITY **ents, int max, int type = -1);
/*
Function: interserct_character
Finds the closest character that intersects the line.
Arguments:
pos0 - Start position
pos2 - End position
radius - How for from the line the character is allowed to be.
new_pos - Intersection position
notthis - Entity to ignore intersecting with
Returns:
Returns a pointer to the closest hit or NULL of there is no intersection.
*/
class CHARACTER *intersect_character(vec2 pos0, vec2 pos1, float radius, vec2 &new_pos, class ENTITY *notthis = 0);
/*
Function: closest_character
Finds the closest character to a specific point.
Arguments:
pos - The center position.
radius - How far off the character is allowed to be
notthis - Entity to ignore
Returns:
Returns a pointer to the closest character or NULL if no character is close enough.
*/
class CHARACTER *closest_character(vec2 pos, float radius, ENTITY *notthis);
/*
Function: insert_entity
Adds an entity to the world.
Arguments:
entity - Entity to add
*/
void insert_entity(ENTITY *entity);
/*
Function: remove_entity
Removes an entity from the world.
Arguments:
entity - Entity to remove
*/
void remove_entity(ENTITY *entity);
/*
Function: destroy_entity
Destroys an entity in the world.
Arguments:
entity - Entity to destroy
*/
void destroy_entity(ENTITY *entity);
/*
Function: snap
Calls snap on all the entities in the world to create
the snapshot.
Arguments:
snapping_client - ID of the client which snapshot
is being created.
*/
void snap(int snapping_client);
/*
Function: tick
Calls tick on all the entities in the world to progress
the world to the next tick.
*/
void tick();
};
/*
Class: Game Controller
Controls the main game logic. Keeping track of team and player score,
winning conditions and specific game logic.
*/
class GAMECONTROLLER
{
protected:
void cyclemap();
void resetgame();
int round_start_tick;
int game_over_tick;
int sudden_death;
int teamscore[2];
int warmup;
int round_count;
bool is_teamplay;
public:
int gametype;
GAMECONTROLLER();
void do_team_score_wincheck();
void do_player_score_wincheck();
void do_warmup(int seconds);
void startround();
void endround();
bool is_friendly_fire(int cid1, int cid2);
/*
*/
virtual void tick();
virtual void snap(int snapping_client);
/*
Function: on_entity
Called when the map is loaded to process an entity
in the map.
Arguments:
index - Entity index.
pos - Where the entity is located in the world.
Returns:
bool?
*/
virtual bool on_entity(int index, vec2 pos);
/*
Function: on_character_spawn
Called when a character spawns into the game world.
Arguments:
chr - The character that was spawned.
*/
virtual void on_character_spawn(class CHARACTER *chr) {}
/*
Function: on_character_death
Called when a character in the world dies.
Arguments:
victim - The character that died.
killer - The player that killed it.
weapon - What weapon that killed it. Can be -1 for undefined
weapon when switching team or player suicides.
*/
virtual int on_character_death(class CHARACTER *victim, class PLAYER *killer, int weapon);
virtual void on_player_info_change(class PLAYER *p);
/*
*/
virtual const char *get_team_name(int team);
virtual int get_auto_team(int notthisid);
virtual bool can_join_team(int team, int notthisid);
int clampteam(int team);
virtual void post_reset();
};
// TODO: move to seperate file
class PICKUP : public ENTITY
{
public:
static const int phys_size = 14;
int type;
int subtype; // weapon type for instance?
int spawntick;
PICKUP(int _type, int _subtype = 0);
virtual void reset();
virtual void tick();
virtual void snap(int snapping_client);
};
// projectile entity
class PROJECTILE : public ENTITY
{
public:
enum
{
PROJECTILE_FLAGS_EXPLODE = 1 << 0,
};
vec2 direction;
ENTITY *powner; // this is nasty, could be removed when client quits
int lifespan;
int owner;
int type;
int flags;
int damage;
int sound_impact;
int weapon;
int bounce;
float force;
int start_tick;
PROJECTILE(int type, int owner, vec2 pos, vec2 vel, int span, ENTITY* powner,
int damage, int flags, float force, int sound_impact, int weapon);
vec2 get_pos(float time);
void fill_info(NETOBJ_PROJECTILE *proj);
virtual void reset();
virtual void tick();
virtual void snap(int snapping_client);
};
class LASER : public ENTITY
{
vec2 from;
vec2 dir;
float energy;
int bounces;
int eval_tick;
CHARACTER *owner;
bool hit_character(vec2 from, vec2 to);
void do_bounce();
public:
LASER(vec2 pos, vec2 direction, float start_energy, CHARACTER *owner);
virtual void reset();
virtual void tick();
virtual void snap(int snapping_client);
};
class CHARACTER : public ENTITY
{
public:
// player controlling this character
class PLAYER *player;
bool alive;
// weapon info
ENTITY *hitobjects[10];
int numobjectshit;
struct WEAPONSTAT
{
int ammoregenstart;
int ammo;
int ammocost;
bool got;
} weapons[NUM_WEAPONS];
int active_weapon;
int last_weapon;
int queued_weapon;
int reload_timer;
int attack_tick;
int damage_taken;
int emote_type;
int emote_stop;
// TODO: clean this up
char skin_name[64];
int use_custom_color;
int color_body;
int color_feet;
int last_action; // last tick that the player took any action ie some input
// these are non-heldback inputs
NETOBJ_PLAYER_INPUT latest_previnput;
NETOBJ_PLAYER_INPUT latest_input;
// input
NETOBJ_PLAYER_INPUT previnput;
NETOBJ_PLAYER_INPUT input;
int num_inputs;
int jumped;
int damage_taken_tick;
int health;
int armor;
// ninja
struct
{
vec2 activationdir;
int activationtick;
int currentcooldown;
int currentmovetime;
} ninja;
//
//int score;
int team;
int player_state; // if the client is chatting, accessing a menu or so
// the player core for the physics
CHARACTER_CORE core;
//
CHARACTER();
virtual void reset();
virtual void destroy();
bool is_grounded();
void set_weapon(int w);
void handle_weaponswitch();
void do_weaponswitch();
int handle_weapons();
int handle_ninja();
void on_predicted_input(NETOBJ_PLAYER_INPUT *new_input);
void on_direct_input(NETOBJ_PLAYER_INPUT *new_input);
void fire_weapon();
void die(int killer, int weapon);
bool take_damage(vec2 force, int dmg, int from, int weapon);
bool spawn(PLAYER *player, vec2 pos, int team);
//bool init_tryspawn(int team);
bool remove();
static const int phys_size = 28;
virtual void tick();
virtual void tick_defered();
virtual void snap(int snaping_client);
bool increase_health(int amount);
bool increase_armor(int amount);
};
// player object
class PLAYER
{
public:
PLAYER();
// TODO: clean this up
char skin_name[64];
int use_custom_color;
int color_body;
int color_feet;
//
bool spawning;
int client_id;
int team;
int score;
//
int64 last_chat;
// network latency calculations
struct
{
int accum;
int accum_min;
int accum_max;
int avg;
int min;
int max;
} latency;
CHARACTER character;
// this is used for snapping so we know how we can clip the view for the player
vec2 view_pos;
void init(int client_id);
CHARACTER *get_character();
void kill_character();
void try_respawn();
void respawn();
void set_team(int team);
void tick();
void snap(int snaping_client);
void on_direct_input(NETOBJ_PLAYER_INPUT *new_input);
void on_predicted_input(NETOBJ_PLAYER_INPUT *new_input);
void on_disconnect();
};
class GAMECONTEXT
{
public:
GAMECONTEXT();
void clear();
EVENT_HANDLER events;
PLAYER players[MAX_CLIENTS];
GAMECONTROLLER *controller;
GAMEWORLD world;
void tick();
void snap(int client_id);
// helper functions
void create_damageind(vec2 p, float angle_mod, int amount);
void create_explosion(vec2 p, int owner, int weapon, bool bnodamage);
void create_smoke(vec2 p);
void create_playerspawn(vec2 p);
void create_death(vec2 p, int who);
void create_sound(vec2 pos, int sound, int mask=-1);
void create_sound_global(int sound, int target=-1);
// network
void send_chat(int cid, int team, const char *text);
void send_emoticon(int cid, int emoticon);
void send_weapon_pickup(int cid, int weapon);
void send_broadcast(const char *text, int cid);
void send_info(int who, int to_who);
};
extern GAMECONTEXT game;
#include "gamecontroller.hpp"
#include "entities/character.hpp"
#include "player.hpp"
#include "gamecontext.hpp"
enum
{

View file

@ -11,9 +11,10 @@
#include <game/g_collision.hpp>
#include <game/g_layers.hpp>
#include "gs_common.hpp"
#include "gs_game_ctf.hpp"
#include "gs_game_tdm.hpp"
#include "gs_game_dm.hpp"
#include "gamemodes/dm.hpp"
#include "gamemodes/tdm.hpp"
#include "gamemodes/ctf.hpp"
TUNING_PARAMS tuning;
GAMECONTEXT game;
@ -106,12 +107,12 @@ void send_tuning_params(int cid)
//////////////////////////////////////////////////
// Event handler
//////////////////////////////////////////////////
EVENT_HANDLER::EVENT_HANDLER()
EVENTHANDLER::EVENTHANDLER()
{
clear();
}
void *EVENT_HANDLER::create(int type, int size, int mask)
void *EVENTHANDLER::create(int type, int size, int mask)
{
if(num_events == MAX_EVENTS)
return 0;
@ -128,13 +129,13 @@ void *EVENT_HANDLER::create(int type, int size, int mask)
return p;
}
void EVENT_HANDLER::clear()
void EVENTHANDLER::clear()
{
num_events = 0;
current_offset = 0;
}
void EVENT_HANDLER::snap(int snapping_client)
void EVENTHANDLER::snap(int snapping_client)
{
for(int i = 0; i < num_events; i++)
{
@ -327,217 +328,6 @@ void GAMEWORLD::tick()
remove_entities();
}
//////////////////////////////////////////////////
// projectile
//////////////////////////////////////////////////
PROJECTILE::PROJECTILE(int type, int owner, vec2 pos, vec2 dir, int span, ENTITY* powner,
int damage, int flags, float force, int sound_impact, int weapon)
: ENTITY(NETOBJTYPE_PROJECTILE)
{
this->type = type;
this->pos = pos;
this->direction = dir;
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;
this->bounce = 0;
this->start_tick = server_tick();
game.world.insert_entity(this);
}
void PROJECTILE::reset()
{
game.world.destroy_entity(this);
}
vec2 PROJECTILE::get_pos(float time)
{
float curvature = 0;
float speed = 0;
if(type == WEAPON_GRENADE)
{
curvature = tuning.grenade_curvature;
speed = tuning.grenade_speed;
}
else if(type == WEAPON_SHOTGUN)
{
curvature = tuning.shotgun_curvature;
speed = tuning.shotgun_speed;
}
else if(type == WEAPON_GUN)
{
curvature = tuning.gun_curvature;
speed = tuning.gun_speed;
}
return calc_pos(pos, direction, curvature, speed, time);
}
void PROJECTILE::tick()
{
float pt = (server_tick()-start_tick-1)/(float)server_tickspeed();
float ct = (server_tick()-start_tick)/(float)server_tickspeed();
vec2 prevpos = get_pos(pt);
vec2 curpos = get_pos(ct);
lifespan--;
int collide = col_intersect_line(prevpos, curpos, &curpos);
//int collide = col_check_point((int)curpos.x, (int)curpos.y);
CHARACTER *targetchr = game.world.intersect_character(prevpos, curpos, 6.0f, curpos, powner);
if(targetchr || collide || lifespan < 0)
{
if(lifespan >= 0 || weapon == WEAPON_GRENADE)
game.create_sound(curpos, sound_impact);
if(flags & PROJECTILE_FLAGS_EXPLODE)
game.create_explosion(curpos, owner, weapon, false);
else if(targetchr)
{
targetchr->take_damage(direction * max(0.001f, force), damage, owner, weapon);
}
game.world.destroy_entity(this);
}
}
void PROJECTILE::fill_info(NETOBJ_PROJECTILE *proj)
{
proj->x = (int)pos.x;
proj->y = (int)pos.y;
proj->vx = (int)(direction.x*100.0f);
proj->vy = (int)(direction.y*100.0f);
proj->start_tick = start_tick;
proj->type = type;
}
void PROJECTILE::snap(int snapping_client)
{
float ct = (server_tick()-start_tick)/(float)server_tickspeed();
if(distance(game.players[snapping_client].view_pos, get_pos(ct)) > 1000.0f)
return;
NETOBJ_PROJECTILE *proj = (NETOBJ_PROJECTILE *)snap_new_item(NETOBJTYPE_PROJECTILE, id, sizeof(NETOBJ_PROJECTILE));
fill_info(proj);
}
//////////////////////////////////////////////////
// laser
//////////////////////////////////////////////////
LASER::LASER(vec2 pos, vec2 direction, float start_energy, CHARACTER *owner)
: ENTITY(NETOBJTYPE_LASER)
{
this->pos = pos;
this->owner = owner;
energy = start_energy;
dir = direction;
bounces = 0;
do_bounce();
game.world.insert_entity(this);
}
bool LASER::hit_character(vec2 from, vec2 to)
{
vec2 at;
CHARACTER *hit = game.world.intersect_character(pos, to, 0.0f, at, owner);
if(!hit)
return false;
this->from = from;
pos = at;
energy = -1;
hit->take_damage(vec2(0,0), tuning.laser_damage, owner->player->client_id, WEAPON_RIFLE);
return true;
}
void LASER::do_bounce()
{
eval_tick = server_tick();
if(energy < 0)
{
//dbg_msg("laser", "%d removed", server_tick());
game.world.destroy_entity(this);
return;
}
vec2 to = pos + dir*energy;
if(col_intersect_line(pos, to, &to))
{
if(!hit_character(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);
pos = temp_pos;
dir = normalize(temp_dir);
energy -= distance(from, pos) + tuning.laser_bounce_cost;
bounces++;
if(bounces > tuning.laser_bounce_num)
energy = -1;
game.create_sound(pos, SOUND_RIFLE_BOUNCE);
}
}
else
{
if(!hit_character(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()
{
game.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(game.players[snapping_client].view_pos, pos) > 1000.0f)
return;
NETOBJ_LASER *obj = (NETOBJ_LASER *)snap_new_item(NETOBJTYPE_LASER, id, sizeof(NETOBJ_LASER));
obj->x = (int)pos.x;
obj->y = (int)pos.y;
obj->from_x = (int)from.x;
obj->from_y = (int)from.y;
obj->start_tick = eval_tick;
}
GAMECONTEXT::GAMECONTEXT()
{
clear();

View file

@ -0,0 +1,55 @@
// player object
class PLAYER
{
public:
PLAYER();
// TODO: clean this up
char skin_name[64];
int use_custom_color;
int color_body;
int color_feet;
//
bool spawning;
int client_id;
int team;
int score;
//
int64 last_chat;
// network latency calculations
struct
{
int accum;
int accum_min;
int accum_max;
int avg;
int min;
int max;
} latency;
CHARACTER character;
// this is used for snapping so we know how we can clip the view for the player
vec2 view_pos;
void init(int client_id);
CHARACTER *get_character();
void kill_character();
void try_respawn();
void respawn();
void set_team(int team);
void tick();
void snap(int snaping_client);
void on_direct_input(NETOBJ_PLAYER_INPUT *new_input);
void on_predicted_input(NETOBJ_PLAYER_INPUT *new_input);
void on_disconnect();
};