about summary refs log tree commit diff
path: root/src/game/server/gs_common.hpp
blob: ff939116483108f5a7db013c3156e6c4608285ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
#include "../g_game.hpp"
#include "../generated/gs_data.hpp"

extern TUNING_PARAMS tuning;

inline int cmask_all() { return -1; }
inline int cmask_one(int cid) { return 1<<cid; }
inline int cmask_all_except_one(int cid) { return 0x7fffffff^cmask_one(cid); }
inline bool cmask_is_set(int mask, int cid) { return (mask&cmask_one(cid)) != 0; }



//
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
		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;
};


/*
	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;

enum
{
	CHAT_ALL=-2,
	CHAT_SPEC=-1,
	CHAT_RED=0,
	CHAT_BLUE=1
};