diff options
Diffstat (limited to 'src/game/server/game_server.cpp')
| -rw-r--r-- | src/game/server/game_server.cpp | 1680 |
1 files changed, 359 insertions, 1321 deletions
diff --git a/src/game/server/game_server.cpp b/src/game/server/game_server.cpp index df17169c..88cbb471 100644 --- a/src/game/server/game_server.cpp +++ b/src/game/server/game_server.cpp @@ -1,9 +1,13 @@ #include <stdlib.h> #include <string.h> #include "../game.h" +#include "data.h" using namespace baselib; +// --------- +const bool debug_bots = false; + // --------- PHYSICS TWEAK! -------- const float ground_control_speed = 7.0f; const float ground_control_accel = 2.0f; @@ -25,6 +29,30 @@ void create_smoke(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); +template<typename T> +T saturated_add(T min, T max, T current, T modifier) +{ + if(modifier < 0) + { + if(current < min) + return current; + current += modifier; + if(current < min) + current = min; + return current; + } + else + { + if(current > max) + return current; + current += modifier; + if(current > max) + current = max; + return current; + } +} + + // TODO: rewrite this smarter! void move_box(vec2 *inout_pos, vec2 *inout_vel, vec2 size, float elasticity) { @@ -91,27 +119,6 @@ void move_box(vec2 *inout_pos, vec2 *inout_vel, vec2 size, float elasticity) *inout_vel = vel; } -// TODO: rewrite this smarter! -bool intersect_line(vec2 pos0, vec2 pos1, vec2 *out) -{ - float d = distance(pos0, pos1); - - for(float f = 0; f < d; f++) - { - float a = f/d; - vec2 pos = mix(pos0, pos1, a); - if(col_check_point(pos)) - { - if(out) - *out = pos; - return true; - } - } - if(out) - *out = pos1; - return false; -} - // class event_handler { @@ -128,7 +135,7 @@ class event_handler public: event_handler() { - num_events = 0; + clear(); } void *create(int type, int size) @@ -159,27 +166,6 @@ public: }; static event_handler events; -/* -template<typename T, int SIZE> -class pool -{ - struct element - { - int next_free; - T data; - }; - - element elements[SIZE]; - int first_free; -public: - pool() - { - first_free = 0; - for(int i = 0; i < SIZE; i++) - elements[i].next_free = i+1; - elements[SIZE-1].next_free = -1; - } -};*/ // a basic entity class entity @@ -190,12 +176,15 @@ private: entity *prev_entity; entity *next_entity; int index; + static int current_id; +protected: + int id; public: - vec2 pos; float proximity_radius; unsigned flags; int objtype; + vec2 pos; enum { @@ -208,6 +197,9 @@ public: pos = vec2(0,0); flags = 0; proximity_radius = 0; + + current_id++; + id = current_id; } virtual ~entity() @@ -216,35 +208,14 @@ public: virtual void destroy() { delete this; } virtual void tick() {} + virtual void tick_defered() {} + virtual void snap(int snapping_client) {} virtual bool take_damage(vec2 force, int dmg, int from) { return true; } }; -class powerup : public entity -{ -public: - static const int phys_size = 14; - enum - { - POWERUP_FLAG_HOOKABLE = 1 << 0, - }; - vec2 vel; - class player* playerhooked; - int type; - int id; - int subtype; // weapon type for instance? - int numitems; // number off powerup items - int flags; - int spawntick; - powerup(int _type, int _subtype = 0, int _numitems = 0, int _flags = 0); - - static void spawnrandom(int _lifespan); - - void tick(); - - void snap(int snapping_client); -}; +int entity::current_id = 1; // game world. handles all entities class game_world @@ -283,6 +254,7 @@ public: if (ent->objtype != types[i]) continue; + // TODO: this seams like it could be done several times unnessesary if(distance(ent->pos, pos) < radius+ent->proximity_radius) { ents[num] = ent; @@ -309,9 +281,6 @@ public: void destroy_entity(entity *ent) { ent->flags |= entity::FLAG_DESTROY; - // call destroy - //remove_entity(ent); - //ent->destroy(); } void remove_entity(entity *ent) @@ -337,6 +306,9 @@ public: // 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(); // destroy objects marked for destruction entity *ent = first_entity; @@ -355,6 +327,21 @@ public: static game_world world; +// TODO: move to seperate file +class powerup : public entity +{ +public: + static const int phys_size = 14; + + int type; + int subtype; // weapon type for instance? + int spawntick; + powerup(int _type, int _subtype = 0); + + virtual void tick(); + virtual void snap(int snapping_client); +}; + // projectile entity class projectile : public entity { @@ -363,10 +350,10 @@ public: { PROJECTILE_FLAGS_EXPLODE = 1 << 0, }; + vec2 vel; - entity* powner; + entity *powner; // this is nasty, could be removed when client quits int lifespan; - int id; int owner; int type; int flags; @@ -374,11 +361,9 @@ public: int sound_impact; float force; - projectile(int type, int owner, vec2 pos, vec2 vel, int span, entity* powner, int damage, int flags = 0, float force = 0.0f, int sound_impact = -1) : - entity(OBJTYPE_PROJECTILE) + projectile(int type, int owner, vec2 pos, vec2 vel, int span, entity* powner, int damage, int flags = 0, float force = 0.0f, int sound_impact = -1) + : entity(OBJTYPE_PROJECTILE) { - static int current_id = 0; - this->id = current_id++; this->type = type; this->pos = pos; this->vel = vel; @@ -398,20 +383,19 @@ public: vel.y += 0.25f; pos += vel; lifespan--; + // check player intersection as well - entity* targetplayer = (entity*)intersect_player(oldpos, pos, oldpos, powner); + entity *targetplayer = (entity*)intersect_player(oldpos, pos, oldpos, powner); if(targetplayer || lifespan < 0 || col_check_point((int)pos.x, (int)pos.y)) { if (lifespan >= 0) create_sound(pos, sound_impact); + if (flags & PROJECTILE_FLAGS_EXPLODE) - { create_explosion(oldpos, owner); - } else if (targetplayer) - { targetplayer->take_damage(normalize(vel) * force, damage, owner); - } + world.destroy_entity(this); } } @@ -421,639 +405,85 @@ public: obj_projectile *proj = (obj_projectile *)snap_new_item(OBJTYPE_PROJECTILE, id, sizeof(obj_projectile)); proj->x = (int)pos.x; proj->y = (int)pos.y; - proj->vx = (int)vel.x; + proj->vx = (int)vel.x; // TODO: should be an angle proj->vy = (int)vel.y; proj->type = type; } }; // player entity +// TODO: move to separate file class player : public entity { public: static const int phys_size = 28; - enum + + enum // what are these? { - WEAPON_NEEDRELOAD = 1 << 0, - WEAPON_DROPONUNEQUIP = 1 << 1, - WEAPON_DRAWSAMMO = 1 << 2, - WEAPON_HASSECONDARY = 1 << 3, - WEAPON_ISACTIVE = 1 << 4, // has the item - WEAPON_AUTOFIRE = 1 << 5, - WEAPON_PROJECTILETYPE_GUN = 0, WEAPON_PROJECTILETYPE_ROCKET = 1, WEAPON_PROJECTILETYPE_SHOTGUN = 2, - - // Gun - - - // modifiers - MODIFIER_HASACTIVATIONS = 1 << 0, - MODIFIER_TIMELIMITED = 1 << 1, - MODIFIER_ISACTIVE = 1 << 2, - MODIFIER_NEEDSACTIVATION = 1 << 3, - - MODIFIER_RETURNFLAGS_OVERRIDEWEAPON = 1 << 0, - MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY = 1 << 1, - MODIFIER_RETURNFLAGS_OVERRIDEPOSITION = 1 << 2, - MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY = 1 << 3, }; - class weapon - { - public: - entity* hitobjects[10]; - int numobjectshit; // for melee, so we don't hit the same object more than once per bash - int weapontype; - int equiptime; - int unequiptime; - int numammo; - int magsize; - int nummagazines; - int flags; - int firetime; - int reloadtime; - int projectileclass; - int damage; - int sound_fire; - int sound_equip; - int sound_impact; - int sound_impact_projectile; - int visualtimeattack; - float projectilevel; - float projectilespan; - float reach; // for melee - float force; - float recoilforce; - float projoffsety; - float projoffsetx; - - weapon() - { - weapontype = 0; - numammo = 0; - flags = 0; - reloadtime = 0; - projectileclass = 0; - numobjectshit = 0; - reach = 0.0f; - force = 5.0f; - damage = 1; - sound_fire = -1; - sound_equip = -1; - sound_impact = -1; - sound_impact_projectile = -1, - visualtimeattack = 3; - recoilforce = 0.0f; - projoffsety = 0.0f; - projoffsetx = 0.0f; - } - - void setgun(int ammo = 10) - { - weapontype = WEAPON_TYPE_GUN; - flags = 0;//WEAPON_DRAWSAMMO; - numammo = ammo; - projectileclass = WEAPON_PROJECTILETYPE_GUN; - firetime = SERVER_TICK_SPEED/10; - magsize = 0; - projectilevel = 30.0f; - projectilespan = 50.0f * 1.0f; - sound_fire = SOUND_FIRE_GUN; - sound_equip = SOUND_EQUIP_GUN; - sound_impact_projectile = SOUND_IMPACT_PROJECTILE_GUN; - projoffsety = -10.0f; - projoffsetx = 24.0f; - } - - void setrocket(int ammo = 10) - { - weapontype = WEAPON_TYPE_ROCKET; - flags = WEAPON_DRAWSAMMO; - numammo = ammo; - projectileclass = WEAPON_PROJECTILETYPE_ROCKET; - projectilevel = 15.0f; - projectilespan = 50.0f * 5.0f; - firetime = SERVER_TICK_SPEED * 4/5; - magsize = 0; - recoilforce = 5.0f; - sound_fire = SOUND_FIRE_ROCKET; - sound_equip = SOUND_EQUIP_ROCKET; - sound_impact_projectile = SOUND_IMPACT_PROJECTILE_ROCKET; - projoffsety = -17.0f; - projoffsetx = 24.0f; - } - - /*void setsniper(int ammo = 10) - { - weapontype = WEAPON_TYPE_SNIPER; - flags = WEAPON_DRAWSAMMO | WEAPON_HASSECONDARY | WEAPON_NEEDRELOAD; - numammo = ammo; - projectileclass = WEAPON_PROJECTILETYPE_SNIPER; - projectilevel = 30.0f; - projectilespan = 50.0f * 5.0f; - firetime = SERVER_TICK_SPEED; - reloadtime = SERVER_TICK_SPEED/2; - magsize = 2; - recoilforce = 20.0f; - }*/ - - void setshotgun(int ammo = 10) - { - weapontype = WEAPON_TYPE_SHOTGUN; - flags = WEAPON_DRAWSAMMO | WEAPON_NEEDRELOAD; - numammo = ammo; - projectileclass = WEAPON_PROJECTILETYPE_SHOTGUN; - projectilevel = 30.0f; - projectilespan = 50.0f * 5.0f; - firetime = SERVER_TICK_SPEED/2; - reloadtime = SERVER_TICK_SPEED/2; - magsize = 2; - damage = 3; - recoilforce = 5.0f; - sound_fire = SOUND_FIRE_SHOTGUN; - sound_equip = SOUND_EQUIP_SHOTGUN; - sound_impact_projectile = SOUND_IMPACT_PROJECTILE_SHOTGUN; - projoffsety = -17.0f; - projoffsetx = 24.0f; - } - - void setmelee(int ammo = 10) - { - weapontype = WEAPON_TYPE_MELEE; - flags = 0;//WEAPON_AUTOFIRE; - numammo = ammo; - projectileclass = -1; - firetime = SERVER_TICK_SPEED/5; - reloadtime = 0; - magsize = 2; - numobjectshit = 0; - reach = 15.0f; - damage = 1; - sound_fire = SOUND_FIRE_MELEE; - sound_equip = SOUND_EQUIP_MELEE; - sound_impact = SOUND_PLAYER_IMPACT; - } - - void settype() - { - switch(weapontype) - { - case WEAPON_TYPE_GUN: - { - setgun(); - break; - } - case WEAPON_TYPE_ROCKET: - { - setrocket(); - break; - } - /*case WEAPON_TYPE_SNIPER: - { - setsniper(); - break; - }*/ - case WEAPON_TYPE_SHOTGUN: - { - setshotgun(); - break; - } - case WEAPON_TYPE_MELEE: - { - setmelee(); - break; - } - default: - break; - } - } - - int activate(player* player) - { - // create sound event for fire - int projectileflags = 0; - create_sound(player->pos, sound_fire); - - switch (weapontype) - { - case WEAPON_TYPE_ROCKET: - projectileflags |= projectile::PROJECTILE_FLAGS_EXPLODE; - case WEAPON_TYPE_GUN: - //case WEAPON_TYPE_SNIPER: - case WEAPON_TYPE_SHOTGUN: - { - if (flags & WEAPON_DRAWSAMMO) - numammo--; - // Create projectile - new projectile(projectileclass, - player->client_id, - player->pos+vec2(0,projoffsety)+player->direction*projoffsetx, - player->direction*projectilevel, - (int)projectilespan, - player, - damage, - projectileflags, - force, - sound_impact_projectile); - // recoil force if any - if (recoilforce > 0.0f) - { - vec2 dir(player->direction.x,0.5); - if (dir.x == 0.0f) - dir.x = 0.5f; - else - dir = normalize(dir); - player->vel -= dir * recoilforce; - } - return firetime; - } - case WEAPON_TYPE_MELEE: - { - // Start bash sequence - numobjectshit = 0; - return firetime; - } - default: - return 0; - } - } - - void update(player* owner, int fire_timeout) - { - switch(weapontype) - { - case WEAPON_TYPE_MELEE: - { - // No more melee - if (fire_timeout <= 0) - return; - - // 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]; - vec2 dir = owner->pos + owner->direction * reach; - float radius = length(dir * 0.5f); - vec2 center = owner->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] == owner) - 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, owner->pos) > (owner->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), damage, owner->client_id); - player* target = (player*)ents[i]; - vec2 dir; - if (length(target->pos - owner->pos) > 0.0f) - dir = normalize(target->pos - owner->pos); - else - dir = vec2(0,-1); - target->vel += dir * 10.0f + vec2(0,-10.0f); - } - break; - } - default: - break; - } - } - }; - - class modifier - { - public: - vec2 activationdir; - entity* hitobjects[10]; - int numobjectshit; - float velocity; - int modifiertype; - int duration; - int numactivations; - int activationtime; - int cooldown; - int movetime; - int visualtimeattack; - int currentactivation; - int currentmovetime; - int currentcooldown; - int damage; - int flags; - int sound_impact; - int sound_activate; - - modifier() - { - modifiertype = 0; - duration = 0; - numobjectshit = 0; - numactivations = 0; - activationtime = 0; - cooldown = 0; - movetime = 0; - currentactivation = 0; - currentmovetime = 0; - currentcooldown =0; - damage = 0; - flags = 0; - activationdir = vec2(0.0f, 1.0f); - velocity = 0.0f; - visualtimeattack = 0; - sound_impact = -1; - } - - void setninja() - { - modifiertype = MODIFIER_TYPE_NINJA; - duration = SERVER_TICK_SPEED * 15; - numactivations = -1; - movetime = SERVER_TICK_SPEED / 5; - activationtime = SERVER_TICK_SPEED / 2; - cooldown = SERVER_TICK_SPEED; - currentactivation = 0; - currentmovetime = 0; - numobjectshit = 0; - damage = 3; - flags = MODIFIER_TIMELIMITED | MODIFIER_NEEDSACTIVATION; - velocity = 50.0f; - visualtimeattack = 3; - sound_impact = SOUND_PLAYER_IMPACT_NINJA; - sound_activate = SOUND_FIRE_NINJA; - } - - void settimefield() - { - modifiertype = MODIFIER_TYPE_TIMEFIELD; - duration = SERVER_TICK_SPEED * 10; - numactivations = -1; - activationtime = SERVER_TICK_SPEED; - numobjectshit = 0; - currentactivation = 0; - flags = MODIFIER_TIMELIMITED; - velocity = 0.0f; - } - - void settype() - { - switch (modifiertype) - { - case MODIFIER_TYPE_NINJA: - { - setninja(); - break; - } - case MODIFIER_TYPE_TIMEFIELD: - { - settimefield(); - break; - } - default: - break; - } - } - - int updateninja(player* player) - { - if (currentactivation <= 0) - return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON; - currentactivation--; - currentmovetime--; - - if (currentmovetime == 0) - { - // reset player velocity - player->vel *= 0.2f; - //return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON; - } - - if (currentmovetime > 0) - { - // Set player velocity - player->vel = activationdir * velocity; - vec2 oldpos = player->pos; - move_box(&player->pos, &player->vel, vec2(player->phys_size, player->phys_size), 0.0f); - // reset velocity so the client doesn't predict stuff - player->vel = vec2(0.0f,0.0f); - if ((currentmovetime % 2) == 0) - { - create_smoke(player->pos); - } - - // check if we hit anything along the way - { - int type = OBJTYPE_PLAYER; - entity *ents[64]; - vec2 dir = player->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] == player) - 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, player->pos) > (player->phys_size * 2.0f)) - continue; - - // hit a player, give him damage and stuffs... - create_sound(ents[i]->pos, sound_impact); - // set his velocity to fast upward (for now) - hitobjects[numobjectshit++] = ents[i]; - ents[i]->take_damage(vec2(0,10.0f), damage, player->client_id); - } - } - return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON | MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY | MODIFIER_RETURNFLAGS_OVERRIDEPOSITION|MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY; - } - - - // move char, and check intersection from us to target - return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON | MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY; - } - - int activateninja(player* player) - { - // ok then, activate ninja - activationdir = player->direction; - currentactivation = activationtime; - currentmovetime = movetime; - currentcooldown = cooldown; - // reset hit objects - numobjectshit = 0; - - create_sound(player->pos, SOUND_FIRE_NINJA); - - return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON; - } - - int activate(player* player) - { - if (flags & MODIFIER_NEEDSACTIVATION) - { - if (!numactivations) - return 0; - numactivations--; - } - - switch (modifiertype) - { - case MODIFIER_TYPE_NINJA: - { - return activateninja(player); - } - /*case MODIFIER_TYPE_TIMEFIELD: - { - updatetimefield(); - break; - }*/ - default: - return 0; - } - } - int update(player* player) - { - switch (modifiertype) - { - case MODIFIER_TYPE_NINJA: - { - return updateninja(player); - } - /*case MODIFIER_TYPE_TIMEFIELD: - { - updatetimefield(); - break; - }*/ - default: - return 0; - } - } - }; - - enum + + // weapon info + struct weaponstat { - PLAYER_FLAGS_ISRELOADING = 1 << 0, - PLAYER_FLAGS_ISEQUIPPING = 1 << 1, - }; - - weapon lweapons[WEAPON_NUMWEAPONS]; - modifier modifiers[MODIFIER_NUMMODIFIERS]; - int iactiveweapon; - int inextweapon; - int equip_time; + bool got; + int ammo; + } weapons[NUM_WEAPONS]; + int active_weapon; + int reload_timer; + int attack_tick; + + // we need a defered position so we can handle the physics correctly + vec2 defered_pos; + vec2 vel; + vec2 direction; + // int client_id; - int flags; - char name[32]; + + // input player_input previnput; player_input input; - int tick_count; - int damage_taken_tick; - - vec2 vel; - vec2 direction; - int jumped; - int airjumped; - - //int firing; - int hooking; - - int fire_timeout; - int reload_timeout; + + int damage_taken_tick; int health; int armor; int score; - // sounds - int sound_player_jump; - int sound_player_land; - int sound_player_hurt_short; - int sound_player_hurt_long; - int sound_player_spawn; - int sound_player_chain_loop; - int sound_player_chain_impact; - int sound_player_impact; - int sound_player_impact_ninja; - int sound_player_die; - int sound_player_switchweapon; - - player* phookedplayer; - powerup* phookedpowerup; - int numhooked; + // hooking stuff + enum + { + HOOK_RETRACTED=-1, + HOOK_IDLE=0, + HOOK_FLYING, + HOOK_GRABBED + }; + + int hook_state; + player *hooked_player; vec2 hook_pos; vec2 hook_dir; - player() : - entity(OBJTYPE_PLAYER) + // + player() + : entity(OBJTYPE_PLAYER) { reset(); - - //firing = 0; - // setup weaponflags and stuff - lweapons[WEAPON_TYPE_GUN].setgun(); - lweapons[WEAPON_TYPE_ROCKET].setrocket(); - //lweapons[WEAPON_TYPE_SNIPER].setsniper(); - lweapons[WEAPON_TYPE_SHOTGUN].setshotgun(); - lweapons[WEAPON_TYPE_MELEE].setmelee(); - - modifiers[MODIFIER_TYPE_NINJA].setninja(); - modifiers[MODIFIER_TYPE_TIMEFIELD].settimefield(); - //modifiers[MODIFIER_TYPE_NINJA].flags |= MODIFIER_ISACTIVE; - - sound_player_jump = SOUND_PLAYER_JUMP; - sound_player_hurt_short = SOUND_PLAYER_HURT_SHORT; - sound_player_hurt_long = SOUND_PLAYER_HURT_LONG; - sound_player_spawn = SOUND_PLAYER_SPAWN; - sound_player_chain_loop = SOUND_PLAYER_CHAIN_LOOP; - sound_player_chain_impact = SOUND_PLAYER_CHAIN_IMPACT; - sound_player_impact = SOUND_PLAYER_IMPACT; - sound_player_impact_ninja = SOUND_PLAYER_IMPACT_NINJA; - sound_player_die = SOUND_PLAYER_DIE; - sound_player_switchweapon = SOUND_PLAYER_SWITCHWEAPON; - sound_player_land = SOUND_PLAYER_LAND; } void reset() { - equip_time = 0; - phookedplayer = 0; - numhooked = 0; + //equip_time = 0; + + release_hooked(); + release_hooks(); + proximity_radius = phys_size; name[0] = 'n'; name[1] = 'o'; @@ -1065,32 +495,21 @@ public: vel = vec2(0.0f, 0.0f); direction = vec2(0.0f, 1.0f); client_id = -1; - tick_count = 0; score = 0; - flags = 0; } - virtual void destroy() { flags = 0; } + virtual void destroy() { } void respawn() { health = PLAYER_MAXHEALTH; armor = 0; - - hooking = 0; - phookedplayer = 0; - phookedpowerup = 0; - numhooked = 0; - fire_timeout = 0; - reload_timeout = 0; - iactiveweapon = 0; - inextweapon = -1; - equip_time = 0; jumped = 0; - airjumped = 0; + mem_zero(&input, sizeof(input)); vel = vec2(0.0f, 0.0f); + // get spawn point int start, num; map_get_type(1, &start, &num); @@ -1101,30 +520,17 @@ public: } else pos = vec2(100.0f, -60.0f); - - // reset active flags - for (int i = 0; i < WEAPON_NUMWEAPONS; i++) - { - // reset and remove - lweapons[i].settype(); - lweapons[i].flags &= ~WEAPON_ISACTIVE; - } - - - // TEMP REMOVE + + // init weapons + mem_zero(&weapons, sizeof(weapons)); + weapons[WEAPON_HAMMER].got = true; + weapons[WEAPON_HAMMER].ammo = -1; + weapons[WEAPON_GUN].got = true; + weapons[WEAPON_GUN].ammo = 10; + active_weapon = WEAPON_GUN; + reload_timer = 0; - /*for (int i = 0; i < WEAPON_NUMWEAPONS; i++) - { - lweapons[i].settype(); - lweapons[i].flags |= WEAPON_ISACTIVE; - }*/ - lweapons[WEAPON_TYPE_MELEE].flags |= WEAPON_ISACTIVE; - // Add gun as default weapon - iactiveweapon = WEAPON_TYPE_GUN; - lweapons[WEAPON_TYPE_GUN].numammo = 10; - lweapons[WEAPON_TYPE_GUN].flags |= WEAPON_ISACTIVE; - - create_sound(pos, sound_player_spawn); + create_sound(pos, SOUND_PLAYER_SPAWN); } bool is_grounded() @@ -1136,470 +542,261 @@ public: return false; } - // Disable weapon activation if this returns true - int handlemodifiers() + // releases the hooked player + void release_hooked() { - int returnflags = 0; - for (int i = 0; i < MODIFIER_NUMMODIFIERS; i++) - { - if (modifiers[i].flags & MODIFIER_ISACTIVE) - { - modifiers[i].duration--; - modifiers[i].currentcooldown--; - - // Check if it should activate - if (modifiers[i].currentcooldown <= 0 && - (modifiers[i].flags & MODIFIER_NEEDSACTIVATION) && - input.fire && !(previnput.fire)) - { - returnflags |= modifiers[i].activate(this); - } - - returnflags |= modifiers[i].update(this); - - // remove active if timed out - if (modifiers[i].duration <= 0 && modifiers[i].currentactivation <= 0) - modifiers[i].flags &= ~MODIFIER_ISACTIVE; - } - } - return returnflags; + hook_state = HOOK_IDLE; + hooked_player = 0x0; } - void handleweapon() + // release all hooks to this player + void release_hooks() { - // handle weapon - if(input.fire && (!previnput.fire || lweapons[iactiveweapon].flags & WEAPON_AUTOFIRE) && - !(flags & PLAYER_FLAGS_ISEQUIPPING) && !reload_timeout) + // TODO: loop thru players only + for(entity *ent = world.first_entity; ent; ent = ent->next_entity) { - if(fire_timeout == 0) + if(ent && ent->objtype == OBJTYPE_PLAYER) { - if (lweapons[iactiveweapon].numammo || !(lweapons[iactiveweapon].flags & WEAPON_DRAWSAMMO)) - { - // Decrease ammo - fire_timeout = lweapons[iactiveweapon].activate(this); - } - else if ((lweapons[iactiveweapon].flags & WEAPON_NEEDRELOAD) && lweapons[iactiveweapon].nummagazines) - { - // reload - reload_timeout = lweapons[iactiveweapon].reloadtime; - lweapons[iactiveweapon].nummagazines--; - lweapons[iactiveweapon].numammo = lweapons[iactiveweapon].magsize; - } + player *p = (player*)ent; + if(p->hooked_player == this) + p->release_hooked(); } } - - // update active weapon - lweapons[iactiveweapon].update(this, fire_timeout); } - - void handlehook() + + void handle_weapons() { - // handle hook - if(input.hook) + // check reload timer + if(reload_timer) { - if(hooking == 0) - { - hooking = 1; - hook_pos = pos; - hook_dir = direction; - // Sound - create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STARTLOOP); - } - else if(hooking == 1) - { - vec2 new_pos = hook_pos+hook_dir*hook_fire_speed; - - // Check against other players and powerups first - player* targetplayer = 0; - powerup* targetpowerup = 0; - { - static const int typelist[2] = { OBJTYPE_PLAYER, OBJTYPE_POWERUP}; - entity *ents[64]; - vec2 dir = new_pos - hook_pos; - float radius = length(dir * 0.5f); - vec2 center = hook_pos + dir * 0.5f; - int num = world.find_entities(center, radius, ents, 64,typelist,2); - - for (int i = 0; i < num; i++) - { - // Check if entity is a player - if (ents[i] == this || (targetplayer && targetpowerup)) - continue; - - if (!targetplayer && ents[i]->objtype == OBJTYPE_PLAYER) - { - // temp, set hook pos to our position - if (((player*)ents[i])->phookedplayer != this) - targetplayer = (player*)ents[i]; - } - else if (!targetpowerup && ents[i]->objtype == OBJTYPE_POWERUP && - (((powerup*)ents[i])->flags & powerup::POWERUP_FLAG_HOOKABLE)) - { - targetpowerup = (powerup*)ents[i]; - } - } - } + reload_timer--; + return; + } - //player* targetplayer = intersect_player(hook_pos, hook_pos, new_pos, this); - if (targetplayer) - { - // So he can't move "normally" - new_pos = targetplayer->pos; - phookedplayer = targetplayer; - targetplayer->numhooked++; - hooking = 3; - create_sound(pos, sound_player_chain_impact); - - // stop looping chain sound - create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STOPLOOP); - } - else if (targetpowerup) - { - new_pos = targetpowerup->pos; - phookedpowerup = targetpowerup; - phookedpowerup->playerhooked = this; - hooking = 4; - create_sound(pos, sound_player_chain_impact); - - // stop looping chain sound - create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STOPLOOP); - } - else if(intersect_line(hook_pos, new_pos, &new_pos)) - { - hooking = 2; - create_sound(pos, sound_player_chain_impact); + // switch weapon if wanted + if(input.activeweapon >= 0 && input.activeweapon < NUM_WEAPONS && weapons[input.activeweapon].got) + active_weapon = input.activeweapon; - // stop looping chain sound - create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STOPLOOP); - } - else if(distance(pos, new_pos) > hook_length) - { - hooking = -1; - create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STOPLOOP); - } - - hook_pos = new_pos; - } - else if(hooking == 2) - { - 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 - } - else if (hooking == 3) + if(input.fire) + { + if(reload_timer == 0) { - // hmm, force the targetplayer towards us if possible, otherwise us towards them if they are already hooked - if (phookedplayer) + // fire! + if(weapons[active_weapon].ammo) { - if (phookedplayer->hooking > 1) + switch(active_weapon) { - // Drag us towards target player - vec2 hookvel = normalize(hook_pos-pos)*hook_drag_accel; - if((hookvel.x < 0 && input.left) || (hookvel.x > 0 && input.right)) - hookvel.x *= 0.95f; - else - hookvel.x *= 0.75f; - - // Apply the velocity - // the hook will boost it's power if the player wants to move - // in that direction. otherwise it will dampen everything abit - 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 - } - else - { - // Drag targetplayer towards us - vec2 hookvel = normalize(pos-hook_pos)*hook_drag_accel; - - // Apply the velocity - // the hook will boost it's power if the player wants to move - // in that direction. otherwise it will dampen everything abit - vec2 new_vel = phookedplayer->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)) - phookedplayer->vel = new_vel; // no problem. apply + case WEAPON_HAMMER: + break; + + case WEAPON_GUN: + new projectile(WEAPON_PROJECTILETYPE_GUN, + client_id, + pos+vec2(0,0), + direction*30.0f, + 100, + this, + 1, 0, 0, -1); + break; + case WEAPON_ROCKET: + new projectile(WEAPON_PROJECTILETYPE_ROCKET, + client_id, + pos+vec2(0,0), + direction*15.0f, + 100, + this, + 1, projectile::PROJECTILE_FLAGS_EXPLODE, 0, -1); + break; + case WEAPON_SHOTGUN: + for(int i = 0; i < 3; i++) + { + new projectile(WEAPON_PROJECTILETYPE_SHOTGUN, + client_id, + pos+vec2(0,0), + direction*(20.0f+(i+1)*2.0f), + 100, + this, + 1, 0, 0, -1); + } + break; } - hook_pos = phookedplayer->pos; - // if hooked player dies, release the hook + + weapons[active_weapon].ammo--; } else { - hooking = -1; - phookedplayer = 0; + // click!!! click } - } - else if (hooking == 4) - { - // Have a powerup, drag it towards us - vec2 hookvel = normalize(pos-hook_pos)*hook_drag_accel; - - // Apply the velocity - // the hook will boost it's power if the player wants to move - // in that direction. otherwise it will dampen everything abit - vec2 new_vel = phookedpowerup->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)) - phookedpowerup->vel = new_vel; // no problem. apply - hook_pos = phookedpowerup->pos; - } - } - else - { - hooking = 0; - hook_pos = pos; - if (phookedplayer) - { - phookedplayer->numhooked--; - phookedplayer = 0; + attack_tick = server_tick(); + reload_timer = 10; // make this variable depending on weapon } } } - - void getattackticks(int& curattack, int& attacklen, int& visualtimeattack) - { - // time left from current attack (if any) - // first check modifiers (ninja...) - for (int i = 0; i < MODIFIER_NUMMODIFIERS; i++) - { - if ((modifiers[i].flags & (MODIFIER_ISACTIVE | MODIFIER_NEEDSACTIVATION)) == (MODIFIER_ISACTIVE | MODIFIER_NEEDSACTIVATION)) - { - curattack = modifiers[i].currentactivation; - attacklen = modifiers[i].activationtime; - visualtimeattack = modifiers[i].visualtimeattack; - return; - } - } - - // otherwise current fire timeout - curattack = fire_timeout; - attacklen = lweapons[iactiveweapon].firetime; - visualtimeattack = lweapons[iactiveweapon].visualtimeattack; - } virtual void tick() { - tick_count++; + // TODO: rework the input to be more robust + // TODO: remove this tick count, it feels weird // fetch some info bool grounded = is_grounded(); direction = get_direction(input.angle); - // decrease reload timer - if(fire_timeout) - fire_timeout--; - if (reload_timeout) - reload_timeout--; - - // Switch weapons - if (flags & PLAYER_FLAGS_ISEQUIPPING) + float max_speed = grounded ? ground_control_speed : air_control_speed; + float accel = grounded ? ground_control_accel : air_control_accel; + float friction = grounded ? ground_friction : air_friction; + + // handle movement + if(input.left) + vel.x = saturated_add(-max_speed, max_speed, vel.x, -accel); + if(input.right) + vel.x = saturated_add(-max_speed, max_speed, vel.x, accel); + + if(!input.left && !input.right) + vel.x *= friction; + + // handle jumping + if(input.jump) { - equip_time--; - if (equip_time <= 0) + if(!jumped && grounded) { - if (inextweapon >= 0) - { - equip_time = SERVER_TICK_SPEED * lweapons[inextweapon].equiptime; - iactiveweapon = inextweapon; - inextweapon = -1; - - // Send switch weapon event to client? - } - else - { - flags &= ~PLAYER_FLAGS_ISEQUIPPING; - } + create_sound(pos, SOUND_PLAYER_JUMP); + vel.y = -ground_jump_speed; + jumped++; } } - else if (input.activeweapon && (unsigned int)iactiveweapon != (input.activeweapon & ~0x80000000)) + else + jumped = 0; + + // do hook + if(input.hook) { - input.activeweapon &= ~0x80000000; - // check which weapon to activate - if (input.activeweapon >= 0 && input.activeweapon < WEAPON_NUMWEAPONS && - (lweapons[input.activeweapon].flags & WEAPON_ISACTIVE)) + if(hook_state == HOOK_IDLE) { - inextweapon = input.activeweapon; - equip_time = SERVER_TICK_SPEED * lweapons[iactiveweapon].unequiptime; - // unequip current - flags |= PLAYER_FLAGS_ISEQUIPPING; - - create_sound(pos, sound_player_switchweapon); + hook_state = HOOK_FLYING; + hook_pos = pos; + hook_dir = direction; } - } - - // don't do any weapon activations if modifier is currently overriding - int modifierflags = handlemodifiers(); - if (!(modifierflags & MODIFIER_RETURNFLAGS_OVERRIDEWEAPON)) - handleweapon(); - - handlehook(); - - // handle movement - if(grounded) - { - if (airjumped) - create_sound(pos, SOUND_PLAYER_LAND); - airjumped = 0; - } - - float elast = 0.0f; - - if (!numhooked) - { - // I'm hooked by someone, so don't do any movement plz (temp) - if (!(modifierflags & MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY)) + else if(hook_state == HOOK_FLYING) { - if(grounded) + vec2 new_pos = hook_pos+hook_dir*hook_fire_speed; + + // Check against other players first + for(entity *ent = world.first_entity; ent; ent = ent->next_entity) { - // ground movement - if(input.left) - { - if(vel.x > -ground_control_speed) - { - vel.x -= ground_control_accel; - if(vel.x < -ground_control_speed) - vel.x = -ground_control_speed; - } - } - else if(input.right) + if(ent && ent->objtype == OBJTYPE_PLAYER) { - if(vel.x < ground_control_speed) + player *p = (player*)ent; + if(p != this && distance(p->pos, new_pos) < p->phys_size) { - vel.x += ground_control_accel; - if(vel.x > ground_control_speed) - vel.x = ground_control_speed; + hook_state = HOOK_GRABBED; + hooked_player = p; + break; } } - else - vel.x *= ground_friction; // ground fiction } - else + + if(hook_state == HOOK_FLYING) { - // air movement - if(input.left) + // check against ground + if(col_intersect_line(hook_pos, new_pos, &new_pos)) { - if(vel.x > -air_control_speed) - vel.x -= air_control_accel; + hook_state = HOOK_GRABBED; + hook_pos = new_pos; } - else if(input.right) + else if(distance(pos, new_pos) > hook_length) { - if(vel.x < air_control_speed) - vel.x += air_control_accel; + hook_state = HOOK_RETRACTED; } else - vel.x *= air_friction; // air fiction + hook_pos = new_pos; } - if(input.jump) + if(hook_state == HOOK_GRABBED) + create_sound(pos, SOUND_HOOK_ATTACH); + } + } + else + { + release_hooked(); + hook_pos = pos; + } + + if(hook_state == HOOK_GRABBED) + { + if(hooked_player) + hook_pos = hooked_player->pos; + + float d = distance(pos, hook_pos); + vec2 dir = normalize(pos - hook_pos); + if(d > 10.0f) // TODO: fix tweakable variable + { + 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); + } + } + + // fix influence of other players, collision + hook + // TODO: loop thru players only + for(entity *ent = world.first_entity; ent; ent = ent->next_entity) + { + if(ent && ent->objtype == OBJTYPE_PLAYER) + { + player *p = (player*)ent; + if(p == this) + continue; // make sure that we don't nudge our self + + // handle player <-> player collision + float d = distance(pos, p->pos); + vec2 dir = normalize(pos - p->pos); + if(d < phys_size*1.25f) { - if(jumped == 0) - { - if(grounded) - { - create_sound(pos, sound_player_jump); - vel.y = -ground_jump_speed; - jumped++; - } - /* - else if(airjumped == 0) - { - vel.y = -12; - airjumped++; - jumped++; - }*/ - } - else if (!grounded) - { - airjumped++; - } + float a = phys_size*1.25f - d; + vel = vel + dir*a; } - else - jumped = 0; - } - // meh, go through all players and stop their hook on me - /* - for(entity *ent = world.first_entity; ent; ent = ent->next_entity) - { - if (ent && ent->objtype == OBJTYPE_PLAYER) + // handle hook influence + if(p->hooked_player == this) { - player *p = (player*)ent; - if(p != this) + if(d > phys_size*1.50f) // TODO: fix tweakable variable { - float d = distance(pos, p->pos); - vec2 dir = normalize(pos - p->pos); - if(d < phys_size*1.5f) - { - float a = phys_size*1.5f - d; - vel = vel + dir*a; - } - - if(p->phookedplayer == this) - { - if(d > phys_size*2.5f) - { - elast = 0.0f; - vel = vel - dir*2.5f; - } - } + float accel = hook_drag_accel * (d/hook_length); + vel.x = saturated_add(-hook_drag_speed, hook_drag_speed, vel.x, -accel*dir.x); + vel.y = saturated_add(-hook_drag_speed, hook_drag_speed, vel.y, -accel*dir.y); } } - }*/ - - // gravity - if (!(modifierflags & MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY)) - vel.y += gravity; + } } - if (!(modifierflags & MODIFIER_RETURNFLAGS_OVERRIDEPOSITION)) - move_box(&pos, &vel, vec2(phys_size, phys_size), elast); + // handle weapons + handle_weapons(); + + // add gravity + vel.y += gravity; + + // do the move + defered_pos = pos; + move_box(&defered_pos, &vel, vec2(phys_size, phys_size), 0); + return; + } + + virtual void tick_defered() + { + // apply the new position + pos = defered_pos; } void die() { - create_sound(pos, sound_player_die); - // release our hooked player - if (phookedplayer) - { - phookedplayer->numhooked--; - phookedplayer = 0; - hooking = -1; - numhooked = 0; - } + create_sound(pos, SOUND_PLAYER_DIE); + + release_hooked(); + release_hooks(); + + // TODO: insert timer here respawn(); - - // meh, go through all players and stop their hook on me - for(entity *ent = world.first_entity; ent; ent = ent->next_entity) - { - if (ent && ent->objtype == OBJTYPE_PLAYER) - { - player* p = (player*)ent; - if (p->phookedplayer == this) - { - p->phookedplayer = 0; - p->hooking = -1; - //p->numhooked--; - } - } - } } virtual bool take_damage(vec2 force, int dmg, int from) @@ -1620,24 +817,11 @@ public: } else armor -= dmg; - /* - int armordmg = (dmg+1)/2; - int healthdmg = dmg-armordmg; - if(armor < armordmg) - { - healthdmg += armordmg - armor; - armor = 0; - } - else - armor -= armordmg; - - health -= healthdmg; - */ // create healthmod indicator create_healthmod(pos, dmg); - damage_taken_tick = tick_count+50; + damage_taken_tick = server_tick()+50; // check for death if(health <= 0) @@ -1659,12 +843,11 @@ public: } if (dmg > 2) - create_sound(pos, sound_player_hurt_long); + create_sound(pos, SOUND_PLAYER_PAIN_LONG); else - create_sound(pos, sound_player_hurt_short); + create_sound(pos, SOUND_PLAYER_PAIN_SHORT); // spawn blood? - return true; } @@ -1672,33 +855,20 @@ public: { obj_player *player = (obj_player *)snap_new_item(OBJTYPE_PLAYER, client_id, sizeof(obj_player)); - client_info info; - if(server_getclientinfo(client_id, &info)) - snap_encode_string(info.name, player->name, strlen(info.name), 32); - player->x = (int)pos.x; player->y = (int)pos.y; player->vx = (int)vel.x; player->vy = (int)vel.y; player->emote = EMOTE_NORMAL; - player->ammocount = lweapons[iactiveweapon].numammo; + player->ammocount = weapons[active_weapon].ammo; player->health = 0; player->armor = 0; player->local = 0; player->clientid = client_id; - player->weapon = iactiveweapon; - player->modifier = 0; - for (int i = 0; i < MODIFIER_NUMMODIFIERS; i++) - { - // add active modifiers - if (modifiers[i].flags & MODIFIER_ISACTIVE) - player->modifier |= 1 << i; - } - // get current attack ticks - getattackticks(player->attackticks, player->attacklen, player->visualtimeattack); + player->weapon = active_weapon; + player->attacktick = attack_tick; - if(client_id == snaping_client) { player->local = 1; @@ -1709,16 +879,16 @@ public: if(length(vel) > 15.0f) player->emote = EMOTE_HAPPY; - if(damage_taken_tick > tick_count) + if(damage_taken_tick > server_tick()) player->emote = EMOTE_PAIN; if(player->emote == EMOTE_NORMAL) { - if((tick_count%(50*5)) < 10) + if((server_tick()%(50*5)) < 10) player->emote = EMOTE_BLINK; } - player->hook_active = hooking>0?1:0; + player->hook_active = hook_state>0?1:0; player->hook_x = (int)hook_pos.x; player->hook_y = (int)hook_pos.y; @@ -1729,64 +899,18 @@ public: // POWERUP /////////////////////// -powerup::powerup(int _type, int _subtype, int _numitems, int _flags) : - entity(OBJTYPE_POWERUP) +powerup::powerup(int _type, int _subtype) +: entity(OBJTYPE_POWERUP) { - static int current_id = 0; - playerhooked = 0; - id = current_id++; - vel = vec2(0.0f,0.0f); + //static int current_id = 0; type = _type; subtype = _subtype; - numitems = _numitems; - flags = _flags; // set radius (so it can collide and be hooked and stuff) proximity_radius = phys_size; spawntick = -1; - world.insert_entity(this); -} - -void powerup::spawnrandom(int _lifespan) -{ - return; - /* - vec2 pos; - int start, num; - map_get_type(1, &start, &num); - if(!num) - return; - - mapres_spawnpoint *sp = (mapres_spawnpoint*)map_get_item(start + (rand()%num), NULL, NULL); - pos = vec2(sp->x, sp->y); - - // Check if there already is a powerup at that location - { - int type = OBJTYPE_POWERUP; - entity *ents[64]; - int num = world.find_entities(pos, 5.0f, ents, 64,&type,1); - for (int i = 0; i < num; i++) - { - if (ents[i]->objtype == OBJTYPE_POWERUP) - { - // location busy - return; - } - } - } - - powerup* ppower = new powerup(rand() % POWERUP_TYPE_NUMPOWERUPS,_lifespan); - ppower->pos = pos; - if (ppower->type == POWERUP_TYPE_WEAPON) - { - ppower->subtype = rand() % WEAPON_NUMWEAPONS; - ppower->numitems = 10; - } - else if (ppower->type == POWERUP_TYPE_HEALTH || ppower->type == POWERUP_TYPE_ARMOR) - { - ppower->numitems = rand() % 5; - } - ppower->flags |= POWERUP_FLAG_HOOKABLE;*/ + // TODO: should this be done here? + world.insert_entity(this); } void powerup::tick() @@ -1799,84 +923,47 @@ void powerup::tick() else return; } - - vec2 oldpos = pos; - //vel.y += 0.25f; - pos += vel; - move_box(&pos, &vel, vec2(phys_size, phys_size), 0.0f); - // Check if a player intersected us vec2 meh; player* pplayer = intersect_player(pos, pos + vec2(0,16), meh, 0); if (pplayer) { // player picked us up, is someone was hooking us, let them go - if (playerhooked) - playerhooked->hooking = -1; int respawntime = -1; switch (type) { case POWERUP_TYPE_HEALTH: + if(pplayer->health < PLAYER_MAXHEALTH) { - if(pplayer->health < PLAYER_MAXHEALTH) - { - pplayer->health = min(PLAYER_MAXHEALTH, pplayer->health + numitems); - respawntime = 20; - } - break; + pplayer->health = min((int)PLAYER_MAXHEALTH, pplayer->health + 1); + respawntime = 20; } + break; case POWERUP_TYPE_ARMOR: + if(pplayer->armor < PLAYER_MAXARMOR) { - if(pplayer->armor < PLAYER_MAXARMOR) - { - pplayer->armor = min(PLAYER_MAXARMOR, pplayer->armor + numitems); - respawntime = 20; - } - break; + pplayer->armor = min((int)PLAYER_MAXARMOR, pplayer->armor + 1); + respawntime = 20; } + break; + case POWERUP_TYPE_WEAPON: + if(subtype >= 0 && subtype < NUM_WEAPONS) { - if (pplayer->lweapons[subtype].flags & player::WEAPON_ISACTIVE) - { - // add ammo - /* - if (pplayer->lweapons[subtype].flags & player::WEAPON_NEEDRELOAD) - { - int numtoadd = min(numitems, pplayer->lweapons[subtype].magsize); - pplayer->lweapons[subtype].numammo = min(10, pplayer->lweapons[subtype].numammo + numtoadd); - pplayer->lweapons[subtype].nummagazines += (numitems - numtoadd) % pplayer->lweapons[subtype].magsize; - } - else*/ - if(pplayer->lweapons[subtype].numammo < 10) - { - respawntime = 20; - pplayer->lweapons[subtype].numammo = min(10, pplayer->lweapons[subtype].numammo + numitems); - } - } - else + if(pplayer->weapons[subtype].ammo < 10 || !pplayer->weapons[subtype].got) { - pplayer->lweapons[subtype].settype(); - pplayer->lweapons[subtype].flags |= player::WEAPON_ISACTIVE; + pplayer->weapons[subtype].got = true; + pplayer->weapons[subtype].ammo = min(10, pplayer->weapons[subtype].ammo + 5); respawntime = 20; } - break; } - case POWERUP_TYPE_NINJA: - { - respawntime = 60; - // reset and activate - pplayer->modifiers[MODIFIER_TYPE_NINJA].settype(); - pplayer->modifiers[MODIFIER_TYPE_NINJA].flags |= player::MODIFIER_ISACTIVE; - break; - } - //POWERUP_TYPE_TIMEFIELD = 4, + break; default: break; }; if(respawntime >= 0) spawntick = server_tick() + server_tickspeed() * respawntime; - //world.destroy_entity(this); } } @@ -1885,18 +972,17 @@ void powerup::snap(int snapping_client) if(spawntick != -1) return; - obj_powerup *powerup = (obj_powerup *)snap_new_item(OBJTYPE_POWERUP, id, sizeof(obj_powerup)); - powerup->x = (int)pos.x; - powerup->y = (int)pos.y; - powerup->vx = (int)vel.x; - powerup->vy = (int)vel.y; - powerup->type = type; - powerup->subtype = subtype; + obj_powerup *up = (obj_powerup *)snap_new_item(OBJTYPE_POWERUP, id, sizeof(obj_powerup)); + up->x = (int)pos.x; + up->y = (int)pos.y; + up->type = type; // TODO: two diffrent types? what gives? + up->subtype = subtype; } // POWERUP END /////////////////////// -static player players[MAX_CLIENTS]; +static const int NUM_BOTS = 1; +static player players[MAX_CLIENTS+NUM_BOTS]; player *get_player(int index) { @@ -1933,19 +1019,7 @@ void create_explosion(vec2 p, int owner, bool bnodamage) float l = length(diff); float dmg = 5 * (1 - (l/radius)); if((int)dmg) - { - ents[i]->take_damage(forcedir*dmg*2, (int)dmg, owner);/* && - ents[i]->objtype == OBJTYPE_PLAYER && - owner >= 0) - { - player *p = (player*)ents[i]; - if(p->client_id == owner) - p->score--; - else - ((player*)ents[owner])->score++; - - }*/ - } + ents[i]->take_damage(forcedir*dmg*2, (int)dmg, owner); } } } @@ -1970,6 +1044,7 @@ void create_sound(vec2 pos, int sound, int loopingflags) ev->sound = sound | loopingflags; } +// TODO: should be more general player* intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, entity* notthis) { // Find other players @@ -1993,19 +1068,26 @@ player* intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, entity* notthis) } // Server hooks -static int addtick = SERVER_TICK_SPEED * 5; void mods_tick() { // clear all events events.clear(); world.tick(); - if (addtick <= 0) + if(debug_bots) { - powerup::spawnrandom(SERVER_TICK_SPEED * 5); - addtick = SERVER_TICK_SPEED * 5; + static int count = 0; + if(count >= 0) + { + count++; + if(count == 10) + { + for(int i = 0; i < NUM_BOTS; i++) + mods_client_enter(MAX_CLIENTS+i); + count = -1; + } + } } - addtick--; } void mods_snap(int client_id) @@ -2026,7 +1108,6 @@ void mods_client_enter(int client_id) players[client_id].client_id = client_id; players[client_id].respawn(); world.insert_entity(&players[client_id]); - } void mods_client_drop(int client_id) @@ -2042,13 +1123,13 @@ void mods_init() int start, num; map_get_type(MAPRES_ITEM, &start, &num); + // TODO: this is way more complicated then it should be for(int i = 0; i < num; i++) { mapres_item *it = (mapres_item *)map_get_item(start+i, 0, 0); int type = -1; int subtype = -1; - int numitems = 1; switch(it->type) { @@ -2059,17 +1140,11 @@ void mods_init() case ITEM_WEAPON_SHOTGUN: type = POWERUP_TYPE_WEAPON; subtype = WEAPON_TYPE_SHOTGUN; - numitems = 5; break; case ITEM_WEAPON_ROCKET: type = POWERUP_TYPE_WEAPON; subtype = WEAPON_TYPE_ROCKET; - numitems = 5; break; - /*case ITEM_WEAPON_SNIPER: - type = POWERUP_TYPE_WEAPON; - subtype = WEAPON_TYPE_ROCKET; - break;*/ case ITEM_WEAPON_HAMMER: type = POWERUP_TYPE_WEAPON; subtype = WEAPON_TYPE_MELEE; @@ -2077,53 +1152,16 @@ void mods_init() case ITEM_HEALTH_1: type = POWERUP_TYPE_HEALTH; - numitems = 1; - break; - case ITEM_HEALTH_5: - type = POWERUP_TYPE_HEALTH; - numitems = 5; - break; - case ITEM_HEALTH_10: - type = POWERUP_TYPE_HEALTH; - numitems = 10; break; case ITEM_ARMOR_1: type = POWERUP_TYPE_ARMOR; - numitems = 1; - break; - case ITEM_ARMOR_5: - type = POWERUP_TYPE_ARMOR; - numitems = 5; - break; - case ITEM_ARMOR_10: - type = POWERUP_TYPE_ARMOR; - numitems = 10; break; }; - powerup* ppower = new powerup(type, subtype, numitems); - ppower->pos.x = it->x; - ppower->pos.y = it->y; + powerup *ppower = new powerup(type, subtype); + ppower->pos = vec2(it->x, it->y); } - - - /* - powerup* ppower = new powerup(rand() % POWERUP_TYPE_NUMPOWERUPS,_lifespan); - ppower->pos = pos; - if (ppower->type == POWERUP_TYPE_WEAPON) - { - ppower->subtype = rand() % WEAPON_NUMWEAPONS; - ppower->numitems = 10; - } - else if (ppower->type == POWERUP_TYPE_HEALTH || ppower->type == POWERUP_TYPE_ARMOR) - { - ppower->numitems = rand() % 5; - } - ppower->flags |= POWERUP_FLAG_HOOKABLE; - */ - - //powerup::spawnrandom(SERVER_TICK_SPEED * 5); } void mods_shutdown() {} |