about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorOlle Rosenquist <phobos99@gmail.com>2007-07-21 19:03:50 +0000
committerOlle Rosenquist <phobos99@gmail.com>2007-07-21 19:03:50 +0000
commit4ef0a10bf9990816f60cfe0f0d4d5131ba08b5cd (patch)
tree8bfad3e79a9ef24ba7194fabc8078ff8b0b89384 /src
parent0c786f6002380ea8fe8ecc459962d91844965a24 (diff)
downloadzcatch-4ef0a10bf9990816f60cfe0f0d4d5131ba08b5cd.tar.gz
zcatch-4ef0a10bf9990816f60cfe0f0d4d5131ba08b5cd.zip
Updated stuff
Diffstat (limited to 'src')
-rw-r--r--src/game/client/game_client.cpp98
-rw-r--r--src/game/game.h13
-rw-r--r--src/game/server/game_server.cpp264
-rw-r--r--src/game/server/game_server.h24
4 files changed, 367 insertions, 32 deletions
diff --git a/src/game/client/game_client.cpp b/src/game/client/game_client.cpp
index 359bb880..b1071b76 100644
--- a/src/game/client/game_client.cpp
+++ b/src/game/client/game_client.cpp
@@ -479,6 +479,31 @@ void modc_newsnapshot()
 				temp_system.new_particle(p, v, 0.5f+0.5f*frandom(), 16.0f, 128.0f, 0.985f);
 			}
 		}
+		else if(item.type == EVENT_SPAWN)
+		{
+			ev_explosion *ev = (ev_explosion *)data;
+			vec2 p(ev->x, ev->y);
+			
+			// center explosion
+			vec2 v = normalize(vec2(frandom()-0.5f, -frandom()))*(32.0f+frandom()*32.0f);
+			temp_system.new_particle(p, v, 1.2f, 64.0f, 0, 0.95f);
+			v = normalize(vec2(frandom()-0.5f, -frandom()))*(128.0f+frandom()*128.0f);
+			temp_system.new_particle(p, v, 1.2f, 32.0f, 0, 0.95f);
+			v = normalize(vec2(frandom()-0.5f, -frandom()))*(128.0f+frandom()*128.0f);
+			temp_system.new_particle(p, v, 1.2f, 16.0f, 0, 0.95f);
+			
+			for(int i = 0; i < 8; i++)
+			{
+				vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(64.0f+frandom()*64.0f);
+				temp_system.new_particle(p, v, 0.5f+0.5f*frandom(), 16.0f, 0, 0.985f);
+			}
+			
+			for(int i = 0; i < 8; i++)
+			{
+				vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(128.0f+frandom()*256.0f);
+				temp_system.new_particle(p, v, 0.5f+0.5f*frandom(), 16.0f, 128.0f, 0.985f);
+			}
+		}
 		else if(item.type == EVENT_SOUND)
 		{
 			ev_sound *ev = (ev_sound *)data;
@@ -715,9 +740,14 @@ static void render_player(obj_player *prev, obj_player *player)
 
 	if (player->weapon == WEAPON_HAMMER)
 	{
-		float a = clamp((client_tick()-player->attacktick+client_intratick())/7.5f, 0.0f, 1.0f);
+		float a = clamp((client_tick()-player->attacktick+client_intratick())/10.0f, 0.0f, 1.0f);
 		anim_eval_add(&state, &data->animations[ANIM_HAMMER_SWING], a, 1.0f);
 	}
+	if (player->weapon == WEAPON_NINJA)
+	{
+		float a = clamp((client_tick()-player->attacktick+client_intratick())/40.0f, 0.0f, 1.0f);
+		anim_eval_add(&state, &data->animations[ANIM_NINJA_SWING], a, 1.0f);
+	}
 
 		
 	// draw hook
@@ -763,13 +793,39 @@ static void render_player(obj_player *prev, obj_player *player)
 
 		vec2 dir = direction;
 		float recoil = 0.0f;
+		vec2 p;
 		if (player->weapon == WEAPON_HAMMER)
 		{
+			// Static position for hammer
+			p = position;
+			p.y += data->weapons[iw].offsety;
 			// if attack is under way, bash stuffs
 			if(direction.x < 0)
+			{
 				gfx_quads_setrotation(-pi/2-state.attach.angle*pi*2);
+				p.x -= data->weapons[iw].offsetx;
+			}
 			else
+			{
 				gfx_quads_setrotation(-pi/2+state.attach.angle*pi*2);
+			}
+			draw_sprite(p.x, p.y, data->weapons[iw].visual_size);
+		}
+		else if (player->weapon == WEAPON_NINJA)
+		{
+			p = position;
+			p.y += data->weapons[iw].offsety;
+			
+			if(direction.x < 0)
+			{
+				gfx_quads_setrotation(-pi/2-state.attach.angle*pi*2);
+				p.x -= data->weapons[iw].offsetx;
+			}
+			else
+			{
+				gfx_quads_setrotation(-pi/2+state.attach.angle*pi*2);
+			}
+			draw_sprite(p.x, p.y, data->weapons[iw].visual_size);
 		}
 		else
 		{
@@ -778,12 +834,44 @@ static void render_player(obj_player *prev, obj_player *player)
 			float a = (client_tick()-player->attacktick+client_intratick())/5.0f;
 			if(a < 1)
 				recoil = sinf(a*pi);
+			p = position + dir * data->weapons[iw].offsetx - dir*recoil*10.0f;
+			p.y += data->weapons[iw].offsety;
+			draw_sprite(p.x, p.y, data->weapons[iw].visual_size);
 		}
-
-		vec2 p = position + dir*20.0f - dir*recoil*10.0f;
-		draw_sprite(p.x, p.y, data->weapons[iw].visual_size);
 		
-		// TODO: draw muzzleflare
+		if (player->weapon == WEAPON_TYPE_GUN || player->weapon == WEAPON_TYPE_SHOTGUN)
+		{
+			// check if we're firing stuff
+			if (true)///prev->attackticks)
+			{
+				float alpha = 0.0f;
+				int phase1tick = (client_tick() - player->attacktick);
+				if (phase1tick < (data->weapons[iw].muzzleduration + 3))
+				{
+					float intratick = client_intratick();
+					float t = ((((float)phase1tick) + intratick)/(float)data->weapons[iw].muzzleduration);
+					alpha = LERP(2.0, 0.0f, min(1.0f,max(0.0f,t)));
+				}
+
+				int itex = rand() % data->weapons[iw].nummuzzlesprites;
+				if (alpha > 0.0f && data->weapons[iw].sprite_muzzle[itex].psprite)
+				{
+					float offsety = -data->weapons[iw].muzzleoffsety;
+					select_sprite(data->weapons[iw].sprite_muzzle[itex].psprite, direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0);
+					if(direction.x < 0)
+						offsety = -offsety;
+
+					vec2 diry(-dir.y,dir.x);
+					p += dir * data->weapons[iw].muzzleoffsetx + diry * offsety;
+
+					draw_sprite(p.x, p.y, data->weapons[iw].visual_size);
+					/*gfx_quads_setcolor(1.0f,1.0f,1.0f,alpha);
+					vec2 diry(-dir.y,dir.x);
+					p += dir * muzzleparams[player->weapon].offsetx + diry * offsety;
+					gfx_quads_draw(p.x,p.y,muzzleparams[player->weapon].sizex, muzzleparams[player->weapon].sizey);*/
+				}
+			}
+		}
 		gfx_quads_end();
 	}
 
diff --git a/src/game/game.h b/src/game/game.h
index 5f69ef9e..64dcc685 100644
--- a/src/game/game.h
+++ b/src/game/game.h
@@ -18,6 +18,10 @@ inline float get_angle(baselib::vec2 dir)
 	return a;
 }
 
+#define LERP(a,b,t) (a + (b-a) * t)
+#define min(a, b) ( a > b ? b : a)
+#define max(a, b) ( a > b ? a : b)
+
 inline bool col_check_point(float x, float y) { return col_check_point((int)x, (int)y) != 0; }
 inline bool col_check_point(baselib::vec2 p) { return col_check_point(p.x, p.y); }
 
@@ -34,6 +38,7 @@ enum
 	EVENT_DAMAGEINDICATION,
 	EVENT_SOUND,
 	EVENT_SMOKE,
+	EVENT_SPAWN,
 };
 
 enum
@@ -75,6 +80,11 @@ struct ev_explosion
 	int x, y;
 };
 
+struct ev_spawn
+{
+	int x, y;
+};
+
 struct ev_sound
 {
 	int x, y;
@@ -152,9 +162,6 @@ enum
 	POWERUP_TYPE_TIMEFIELD		= 4,
 	POWERUP_TYPE_NUMPOWERUPS,
 
-	PLAYER_MAXHEALTH			= 10,
-	PLAYER_MAXARMOR				= 10,
-
 	MODIFIER_TYPE_NINJA			= 0,
 	MODIFIER_TYPE_TIMEFIELD		= 1,
 	MODIFIER_NUMMODIFIERS,
diff --git a/src/game/server/game_server.cpp b/src/game/server/game_server.cpp
index 12685fe8..795e9941 100644
--- a/src/game/server/game_server.cpp
+++ b/src/game/server/game_server.cpp
@@ -5,6 +5,8 @@
 #include "data.h"
 #include "game_server.h"
 
+data_container *data = 0x0;
+
 using namespace baselib;
 
 // --------- DEBUG STUFF ---------
@@ -28,6 +30,7 @@ class player* get_player(int index);
 void create_damageind(vec2 p, vec2 dir, int amount);
 void create_explosion(vec2 p, int owner, int weapon, bool bnodamage);
 void create_smoke(vec2 p);
+void create_spawn(vec2 p);
 void create_sound(vec2 pos, int sound, int loopflags = 0);
 class player *intersect_player(vec2 pos0, vec2 pos1, vec2 &new_pos, class entity *notthis = 0);
 
@@ -339,6 +342,7 @@ game_world world;
 gameobject::gameobject()
 : entity(OBJTYPE_GAME)
 {
+	gametype = GAMETYPE_DM;
 	game_over_tick = -1;
 	sudden_death = 0;
 	round_start_tick = server_tick();
@@ -577,6 +581,8 @@ void player::init()
 	name[3] = 'b';
 	name[4] = 0;
 	client_id = -1;
+	extrapowerflags = 0;
+	ninjaactivationtick = 0;
 	reset();
 }
 
@@ -597,7 +603,7 @@ void player::destroy() {  }
 	
 void player::respawn()
 {
-	health = PLAYER_MAXHEALTH;
+	health = data->playerinfo[gameobj.gametype].maxhealth;
 	armor = 0;
 	jumped = 0;
 	dead = false;
@@ -624,7 +630,7 @@ void player::respawn()
 	weapons[WEAPON_HAMMER].got = true;
 	weapons[WEAPON_HAMMER].ammo = -1;
 	weapons[WEAPON_GUN].got = true;
-	weapons[WEAPON_GUN].ammo = 10;
+	weapons[WEAPON_GUN].ammo = data->weapons[active_weapon].maxammo;
 
 	// TEMP DEBUG
 	weapons[WEAPON_ROCKET_BACKPACK].got = true;
@@ -632,8 +638,15 @@ void player::respawn()
 
 	active_weapon = WEAPON_GUN;
 	reload_timer = 0;
+
+	// TEMP TEMP TEMP
+	/*ninjaactivationtick = server_tick();
+	weapons[WEAPON_NINJA].got = 1;
+	active_weapon = WEAPON_NINJA;*/
 	
+	// Create sound and spawn effects
 	create_sound(pos, SOUND_PLAYER_SPAWN);
+	create_spawn(pos);
 }
 
 bool player::is_grounded()
@@ -667,20 +680,111 @@ void player::release_hooks()
 	}
 }
 
-void player::handle_weapons()
+int player::handle_ninja()
+{
+	if ((server_tick() - ninjaactivationtick) > (data->weapons[WEAPON_NINJA].duration * server_tickspeed() / 1000))
+	{
+		// time's up, return
+		active_weapon = WEAPON_GUN;
+		return 0;
+	}
+	
+	// Check if it should activate
+	if ((input.fire && !(previnput.fire)) && (server_tick() > currentcooldown))
+	{
+		// ok then, activate ninja
+		attack_tick = server_tick();
+		activationdir = direction;
+		currentmovetime = data->weapons[WEAPON_NINJA].movetime * server_tickspeed() / 1000;
+		currentcooldown = data->weapons[WEAPON_NINJA].firedelay * server_tickspeed() / 1000 + server_tick();
+		// reset hit objects
+		numobjectshit = 0;
+
+		create_sound(pos, SOUND_NINJA_FIRE);
+	}
+
+	currentmovetime--;
+	
+	if (currentmovetime == 0)
+	{	
+		// reset player velocity
+		vel *= 0.2f;
+		//return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON;
+	}
+	
+	if (currentmovetime > 0)
+	{
+		// Set player velocity
+		vel = activationdir * data->weapons[WEAPON_NINJA].velocity;
+		vec2 oldpos = pos;
+		move_box(&defered_pos, &vel, vec2(phys_size, phys_size), 0.0f);
+		// reset velocity so the client doesn't predict stuff
+		vel = vec2(0.0f,0.0f);
+		if ((currentmovetime % 2) == 0)
+		{
+			create_smoke(pos);
+		}
+		
+		// check if we hit anything along the way
+		{
+			int type = OBJTYPE_PLAYER;
+			entity *ents[64];
+			vec2 dir = pos - oldpos;
+			float radius = length(dir * 0.5f);
+			vec2 center = oldpos + dir * 0.5f;
+			int num = world.find_entities(center, radius, ents, 64, &type, 1);
+			
+			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;
+			
+				// hit a player, give him damage and stuffs...
+				create_sound(ents[i]->pos, SOUND_NINJA_HIT);
+				// set his velocity to fast upward (for now)
+				hitobjects[numobjectshit++] = ents[i];
+				ents[i]->take_damage(vec2(0,10.0f), data->weapons[WEAPON_NINJA].meleedamage, client_id,-1);
+			}
+		}
+		return MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY | MODIFIER_RETURNFLAGS_OVERRIDEPOSITION | MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY;
+	}
+	return 0;
+}
+
+int player::handle_weapons()
 {
 	// check reload timer
 	if(reload_timer)
 	{
 		reload_timer--;
-		return;
+		return 0;
+	}
+	if (active_weapon == WEAPON_NINJA)
+	{
+		// don't update other weapons while ninja is active
+		return handle_ninja();
 	}
 
 	// switch weapon if wanted		
-	if(input.activeweapon >= 0 && input.activeweapon < NUM_WEAPONS && weapons[input.activeweapon].got)
+	if(input.activeweapon >= 0 && input.activeweapon < NUM_WEAPONS && weapons[input.activeweapon].got && 
+		data->weapons[active_weapon].duration <= 0)
 		active_weapon = input.activeweapon;
 
-	if(input.fire)
+	if(!previnput.fire && input.fire)
 	{
 		if(reload_timer == 0)
 		{
@@ -690,6 +794,8 @@ void player::handle_weapons()
 				switch(active_weapon)
 				{
 					case WEAPON_HAMMER:
+						// reset objects hit
+						numobjectshit = 0;
 						create_sound(pos, SOUND_HAMMER_FIRE);
 						break;
 
@@ -739,17 +845,89 @@ void player::handle_weapons()
 				}
 				
 				weapons[active_weapon].ammo--;
+				attack_tick = server_tick();
+				reload_timer = data->weapons[active_weapon].firedelay * server_tickspeed() / 1000;
 			}
 			else
 			{
 				// click!!! click
 				// TODO: make sound here
 			}
-			
-			attack_tick = server_tick();
-			reload_timer = 10; // TODO: make this variable depending on weapon
 		}
 	}
+	// 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
+		int type = OBJTYPE_PLAYER;
+		entity *ents[64];
+		float reach = 20.0f;
+		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;
+		int num = world.find_entities(center, radius, ents, 64, &type, 1);
+		
+		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;
+		
+			// hit a player, give him damage and stuffs...
+			// create sound for bash
+			//create_sound(ents[i]->pos, sound_impact);
+
+			// set his velocity to fast upward (for now)
+			create_smoke(ents[i]->pos);
+			hitobjects[numobjectshit++] = ents[i];
+			ents[i]->take_damage(vec2(0,10.0f), data->weapons[active_weapon].meleedamage, client_id, active_weapon);
+			player* target = (player*)ents[i];
+			vec2 dir;
+			if (length(target->pos - pos) > 0.0f)
+				dir = normalize(target->pos - pos);
+			else
+				dir = vec2(0,-1);
+			target->vel += dir * 10.0f + vec2(0,-10.0f);
+		}
+	}
+	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;
+		}
+	}
+	return 0;
 }
 
 void player::tick()
@@ -851,7 +1029,7 @@ void player::tick()
 		
 	if(hook_state == HOOK_GRABBED)
 	{
-		if(hooked_player)
+		/*if(hooked_player)
 			hook_pos = hooked_player->pos;
 
 		float d = distance(pos, hook_pos);
@@ -861,7 +1039,25 @@ void player::tick()
 			float accel = hook_drag_accel * (d/hook_length);
 			vel.x = saturated_add(-hook_drag_speed, hook_drag_speed, vel.x, -accel*dir.x*0.75f);
 			vel.y = saturated_add(-hook_drag_speed, hook_drag_speed, vel.y, -accel*dir.y);
-		}
+		}*/
+		// Old version feels much better (to me atleast)
+		vec2 hookvel = normalize(hook_pos-pos)*hook_drag_accel;
+		// the hook as more power to drag you up then down.
+		// this makes it easier to get on top of an platform
+		if(hookvel.y > 0)
+			hookvel.y *= 0.3f;
+		
+		// the hook will boost it's power if the player wants to move
+		// in that direction. otherwise it will dampen everything abit
+		if((hookvel.x < 0 && input.left) || (hookvel.x > 0 && input.right)) 
+			hookvel.x *= 0.95f;
+		else
+			hookvel.x *= 0.75f;
+		vec2 new_vel = vel+hookvel;
+		
+		// check if we are under the legal limit for the hook
+		if(length(new_vel) < hook_drag_speed || length(new_vel) < length(vel))
+			vel = new_vel; // no problem. apply
 	}
 		
 	// fix influence of other players, collision + hook
@@ -897,14 +1093,20 @@ void player::tick()
 	}
 	
 	// handle weapons
-	handle_weapons();
+	int retflags = handle_weapons();
+	if (!(retflags & (MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY | MODIFIER_RETURNFLAGS_OVERRIDEPOSITION)))
+	{
+		// add gravity
+		if (!(retflags & MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY))
+			vel.y += gravity;
 	
-	// add gravity
-	vel.y += gravity;
+		// do the move
+		defered_pos = pos;
+		move_box(&defered_pos, &vel, vec2(phys_size, phys_size), 0);
+	}
 	
-	// do the move
-	defered_pos = pos;
-	move_box(&defered_pos, &vel, vec2(phys_size, phys_size), 0);
+	// Previnput
+	previnput = input;
 	return;
 }
 
@@ -1085,16 +1287,16 @@ void powerup::tick()
 		switch (type)
 		{
 		case POWERUP_TYPE_HEALTH:
-			if(pplayer->health < PLAYER_MAXHEALTH)
+			if(pplayer->health < data->playerinfo[gameobj.gametype].maxhealth)
 			{
-				pplayer->health = min((int)PLAYER_MAXHEALTH, pplayer->health + 1);
+				pplayer->health = min((int)data->playerinfo[gameobj.gametype].maxhealth, pplayer->health + 1);
 				respawntime = 20;
 			}
 			break;
 		case POWERUP_TYPE_ARMOR:
-			if(pplayer->armor < PLAYER_MAXARMOR)
+			if(pplayer->armor < data->playerinfo[gameobj.gametype].maxarmor)
 			{
-				pplayer->armor = min((int)PLAYER_MAXARMOR, pplayer->armor + 1);
+				pplayer->armor = min((int)data->playerinfo[gameobj.gametype].maxarmor, pplayer->armor + 1);
 				respawntime = 20;
 			}
 			break;
@@ -1110,6 +1312,15 @@ void powerup::tick()
 				}
 			}
 			break;
+		case POWERUP_TYPE_NINJA:
+			{
+				// activate ninja on target player
+				pplayer->ninjaactivationtick = server_tick();
+				pplayer->weapons[WEAPON_NINJA].got = true;
+				pplayer->active_weapon = WEAPON_NINJA;
+				respawntime = 20;
+				break;
+			}
 		default:
 			break;
 		};
@@ -1191,6 +1402,14 @@ void create_smoke(vec2 p)
 	ev->y = (int)p.y;
 }
 
+void create_spawn(vec2 p)
+{
+	// create the event
+	ev_spawn *ev = (ev_spawn *)events.create(EVENT_SPAWN, sizeof(ev_spawn));
+	ev->x = (int)p.x;
+	ev->y = (int)p.y;
+}
+
 void create_sound(vec2 pos, int sound, int loopingflags)
 {
 	if (sound < 0)
@@ -1265,7 +1484,7 @@ void mods_client_input(int client_id, void *input)
 {
 	if(!world.paused)
 	{
-		players[client_id].previnput = players[client_id].input;
+		//players[client_id].previnput = players[client_id].input;
 		players[client_id].input = *(player_input*)input;
 	}
 }
@@ -1323,6 +1542,7 @@ void mods_message(int msg, int client_id)
 
 void mods_init()
 {
+	data = load_data_container("data/server.dat");
 	col_init(32);
 
 	int start, num;
diff --git a/src/game/server/game_server.h b/src/game/server/game_server.h
index ec3d597a..46b451e1 100644
--- a/src/game/server/game_server.h
+++ b/src/game/server/game_server.h
@@ -112,6 +112,7 @@ class gameobject : public entity
 	int sudden_death;
 	
 public:
+	int gametype;
 	gameobject();
 	virtual void post_reset();
 	virtual void tick();
@@ -190,11 +191,21 @@ class player : public entity
 public:
 	static const int phys_size = 28;
 	
+	enum // what are these?
+	{
+		MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY		= 1 << 0,
+		MODIFIER_RETURNFLAGS_OVERRIDEPOSITION		= 1 << 1,
+		MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY		= 1 << 2,
+	};
+
 	// weapon info
+	entity* hitobjects[10];
+	int numobjectshit;
 	struct weaponstat
 	{
-		bool got;
+		int ammoregenstart;
 		int ammo;
+		bool got;
 	} weapons[NUM_WEAPONS];
 	int active_weapon;
 	int reload_timer;
@@ -219,6 +230,14 @@ public:
 	int health;
 	int armor;
 
+	// ninja
+	baselib::vec2 activationdir;
+	int ninjaactivationtick;
+	int extrapowerflags;
+	int currentcooldown;
+	int currentactivation;
+	int currentmovetime;
+
 	int score;
 	
 	bool dead;
@@ -251,7 +270,8 @@ public:
 	void release_hooked();
 	void release_hooks();
 	
-	void handle_weapons();
+	int handle_weapons();
+	int handle_ninja();
 
 	virtual void tick();
 	virtual void tick_defered();