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); vec2 speed = curpos - prevpos; if (lifespan>-1) lifespan--; vec2 col_pos; vec2 new_pos; int collide = col_intersect_line(prevpos, curpos, &col_pos, &new_pos); CHARACTER *ownerchar; if (owner>=0) ownerchar = game.get_player_char(owner); CHARACTER *targetchr; if (freeze) targetchr = game.world.intersect_character(prevpos, col_pos, 1.0f, col_pos, ownerchar); else targetchr = game.world.intersect_character(prevpos, col_pos, 6.0f, col_pos, ownerchar); if(targetchr || collide) { if((flags & PROJECTILE_FLAGS_EXPLODE) && (!targetchr || (targetchr && !freeze))) { game.create_explosion(col_pos, owner, weapon, false); game.create_sound(col_pos, sound_impact); } else if(targetchr && freeze && targetchr->adminfreeze==false) targetchr->freeze(server_tickspeed()*3); if (collide && bouncing!=0) { start_tick=server_tick(); pos=new_pos; if (bouncing==1) direction.x=-direction.x; else if (bouncing==2) direction.y=-direction.y; pos+=direction; } else if (weapon==WEAPON_GUN) { game.create_damageind(curpos, -atan2(direction.x,direction.y), 10); game.world.destroy_entity(this); } else if (!freeze) game.world.destroy_entity(this); } if (lifespan == -1) { game.world.destroy_entity(this); } }
CHARACTER *CRATE::get_nearest(int maxdist) { CHARACTER *close_characters[MAX_CLIENTS]; int num = game.world.find_entities(pos, maxdist, (ENTITY**)close_characters, MAX_CLIENTS, NETOBJTYPE_CHARACTER); int disti = -1; float dist = 10000000.0f; for(int i = 0; i < num; i++) { if(col_intersect_line(pos, close_characters[i]->pos, 0x0, 0x0)) { continue; } float d = distance(close_characters[i]->pos, pos); if(d < dist) { disti = i; dist = d; } } if(disti == -1) { return 0; } return close_characters[disti]; }
void GUN::fire() { CHARACTER *ents[16]; int num = -1; num = game.world.find_entities(pos,RANGE, (ENTITY**)ents, 16, NETOBJTYPE_CHARACTER); int id=-1; int minlen=0; for (int i = 0; i < num; i++) { CHARACTER *target = ents[i]; int res; vec2 coltile; res = col_intersect_line(pos, target->pos,0,0); if (!res) { int len=length(ents[i]->pos - pos); if (minlen==0) { minlen=len; id=i; } else if(minlen>len) { minlen=len; id=i; } } } if (id!=-1) { CHARACTER *target = ents[id]; vec2 fdir = normalize(target->pos - pos); new PLASMA(pos,fdir); } }
void CHARACTER_CORE::tick(bool use_input) { float phys_size = 28.0f; triggered_events = 0; // get ground state bool grounded = false; if(col_check_point(pos.x+phys_size/2, pos.y+phys_size/2+5)) grounded = true; if(col_check_point(pos.x-phys_size/2, pos.y+phys_size/2+5)) grounded = true; //platte if(col_check_platte(pos.x+phys_size/2, pos.y+phys_size/2+5)) grounded = true; if(col_check_platte(pos.x-phys_size/2, pos.y+phys_size/2+5)) grounded = true; vec2 target_direction = normalize(vec2(input.target_x, input.target_y)); vel.y += world->tuning.gravity; float max_speed = grounded ? world->tuning.ground_control_speed : world->tuning.air_control_speed; float accel = grounded ? world->tuning.ground_control_accel : world->tuning.air_control_accel; float friction = grounded ? world->tuning.ground_friction : world->tuning.air_friction; // handle input if(use_input) { direction = input.direction; // setup angle float a = 0; if(input.target_x == 0) a = atan((float)input.target_y); else a = atan((float)input.target_y/(float)input.target_x); if(input.target_x < 0) a = a+pi; angle = (int)(a*256.0f); // handle jump if(input.jump) { if(!(jumped&1)) { if(grounded) { triggered_events |= COREEVENT_GROUND_JUMP; vel.y = -world->tuning.ground_jump_impulse; jumped |= 1; } else if(!(jumped&2)) { triggered_events |= COREEVENT_AIR_JUMP; vel.y = -world->tuning.air_jump_impulse; jumped |= 3; } } } else jumped &= ~1; // handle hook if(input.hook) { if(hook_state == HOOK_IDLE) { hook_state = HOOK_FLYING; hook_pos = pos+target_direction*phys_size*1.5f; hook_dir = target_direction; hooked_player = -1; hook_tick = 0; triggered_events |= COREEVENT_HOOK_LAUNCH; } } else { hooked_player = -1; hook_state = HOOK_IDLE; hook_pos = pos; } } // add the speed modification according to players wanted direction if(direction < 0) vel.x = saturated_add(-max_speed, max_speed, vel.x, -accel); if(direction > 0) vel.x = saturated_add(-max_speed, max_speed, vel.x, accel); if(direction == 0) vel.x *= friction; // handle jumping // 1 bit = to keep track if a jump has been made on this input // 2 bit = to keep track if a air-jump has been made if(grounded) jumped &= ~2; // do hook if(hook_state == HOOK_IDLE) { hooked_player = -1; hook_state = HOOK_IDLE; hook_pos = pos; } else if(hook_state >= HOOK_RETRACT_START && hook_state < HOOK_RETRACT_END) { hook_state++; } else if(hook_state == HOOK_RETRACT_END) { hook_state = HOOK_RETRACTED; triggered_events |= COREEVENT_HOOK_RETRACT; hook_state = HOOK_RETRACTED; } else if(hook_state == HOOK_FLYING) { vec2 new_pos = hook_pos+hook_dir*world->tuning.hook_fire_speed; if(distance(pos, new_pos) > world->tuning.hook_length) { hook_state = HOOK_RETRACT_START; new_pos = pos + normalize(new_pos-pos) * world->tuning.hook_length; } // make sure that the hook doesn't go though the ground bool going_to_hit_ground = false; bool going_to_retract = false; int hit = col_intersect_line(hook_pos, new_pos, &new_pos, 0); if(hit) { if(hit&COLFLAG_NOHOOK) going_to_retract = true; else going_to_hit_ground = true; } // Check against other players first if(world && world->tuning.player_hooking) { float dist = 0.0f; for(int i = 0; i < MAX_CLIENTS; i++) { CHARACTER_CORE *p = world->characters[i]; if(!p || p == this) continue; vec2 closest_point = closest_point_on_line(hook_pos, new_pos, p->pos); if(distance(p->pos, closest_point) < phys_size+2.0f) { if (hooked_player == -1 || distance (hook_pos, p->pos) < dist) { triggered_events |= COREEVENT_HOOK_ATTACH_PLAYER; hook_state = HOOK_GRABBED; hooked_player = i; dist = distance (hook_pos, p->pos); } } } } if(hook_state == HOOK_FLYING) { // check against ground if(going_to_hit_ground) { triggered_events |= COREEVENT_HOOK_ATTACH_GROUND; hook_state = HOOK_GRABBED; } else if(going_to_retract) { triggered_events |= COREEVENT_HOOK_HIT_NOHOOK; hook_state = HOOK_RETRACT_START; } hook_pos = new_pos; } } if(hook_state == HOOK_GRABBED) { if(hooked_player != -1) { CHARACTER_CORE *p = world->characters[hooked_player]; if(p) hook_pos = p->pos; else { // release hook hooked_player = -1; hook_state = HOOK_RETRACTED; hook_pos = pos; } // keep players hooked for a max of 1.5sec //if(server_tick() > hook_tick+(server_tickspeed()*3)/2) //release_hooked(); } // don't do this hook rutine when we are hook to a player if(hooked_player == -1 && distance(hook_pos, pos) > 46.0f) { vec2 hookvel = normalize(hook_pos-pos)*world->tuning.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 && direction < 0) || (hookvel.x > 0 && direction > 0)) 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) < world->tuning.hook_drag_speed || length(new_vel) < length(vel)) vel = new_vel; // no problem. apply } // release hook (max hook time is 1.25 hook_tick++; if(hooked_player != -1 && (hook_tick > SERVER_TICK_SPEED+SERVER_TICK_SPEED/5 || !world->characters[hooked_player])) { hooked_player = -1; hook_state = HOOK_RETRACTED; hook_pos = pos; } } if(world && world->tuning.player_collision) { for(int i = 0; i < MAX_CLIENTS; i++) { CHARACTER_CORE *p = world->characters[i]; if(!p) continue; //player *p = (player*)ent; if(p == this) // || !(p->flags&FLAG_ALIVE) 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 && d > 1.0f) { float a = (phys_size*1.45f - d); // make sure that we don't add excess force by checking the // direction against the current velocity vec2 veldir = normalize(vel); float v = 1-(dot(veldir, dir)+1)/2; vel = vel + dir*a*(v*0.75f); vel = vel * 0.85f; } // handle hook influence if(hooked_player == i) { if(d > phys_size*1.50f) // TODO: fix tweakable variable { float accel = world->tuning.hook_drag_accel * (d/world->tuning.hook_length); float drag_speed = world->tuning.hook_drag_speed; // add force to the hooked player p->vel.x = saturated_add(-drag_speed, drag_speed, p->vel.x, accel*dir.x*1.5f); p->vel.y = saturated_add(-drag_speed, drag_speed, p->vel.y, accel*dir.y*1.5f); // add a little bit force to the guy who has the grip vel.x = saturated_add(-drag_speed, drag_speed, vel.x, -accel*dir.x*0.25f); vel.y = saturated_add(-drag_speed, drag_speed, vel.y, -accel*dir.y*0.25f); } } } } // clamp the velocity to something sane if(length(vel) > 6000) vel = normalize(vel) * 6000; }
void GAMECONTROLLER_CTF::tick() { GAMECONTROLLER::tick(); do_team_score_wincheck(); do_race_time_check(); for(int fi = 0; fi < 2; fi++) { FLAG *f = flags[fi]; if(!f) continue; // flag hits death-tile, reset it if(col_get((int)f->pos.x, (int)f->pos.y)&COLFLAG_DEATH) { game.create_sound_global(SOUND_CTF_RETURN); f->reset(); continue; } // if(f->carrying_character) { // update flag position f->pos = f->carrying_character->pos; if(flags[fi^1] && flags[fi^1]->at_stand) { if(distance(f->pos, flags[fi^1]->pos) < 32) { // CAPTURE! \o/ teamscore[fi^1] += 100; f->carrying_character->player->score += 500; dbg_msg("game", "flag_capture player='%d:%s'", f->carrying_character->player->client_id, server_clientname(f->carrying_character->player->client_id)); char buf[512]; float capture_time = (server_tick() - f->grab_tick)/(float)server_tickspeed(); if(capture_time <= 60) { str_format(buf, sizeof(buf), "the %s flag was captured by %s (%d.%s%d seconds)", fi ? "blue" : "red", server_clientname(f->carrying_character->player->client_id), (int)capture_time%60, ((int)(capture_time*100)%100)<10?"0":"", (int)(capture_time*100)%100); } else { str_format(buf, sizeof(buf), "the %s flag was captured by %s", fi ? "blue" : "red", server_clientname(f->carrying_character->player->client_id)); } game.send_chat(-1, -2, buf); for(int i = 0; i < 2; i++) flags[i]->reset(); game.create_sound_global(SOUND_CTF_CAPTURE); } } } else { CHARACTER *close_characters[MAX_CLIENTS]; int num = game.world.find_entities(f->pos, 32.0f, (ENTITY**)close_characters, MAX_CLIENTS, NETOBJTYPE_CHARACTER); for(int i = 0; i < num; i++) { if(!close_characters[i]->alive || close_characters[i]->player->team == -1 || col_intersect_line(f->pos, close_characters[i]->pos, NULL, NULL)) continue; if(close_characters[i]->team == f->team) { // return the flag if(!f->at_stand) { CHARACTER *chr = close_characters[i]; chr->player->score += 100; dbg_msg("game", "flag_return player='%d:%s'", chr->player->client_id, server_clientname(chr->player->client_id)); game.create_sound_global(SOUND_CTF_RETURN); f->reset(); } } else { // take the flag if(f->at_stand) { teamscore[fi^1]++; f->grab_tick = server_tick(); } f->at_stand = 0; f->carrying_character = close_characters[i]; f->carrying_character->player->score += 300; dbg_msg("game", "flag_grab player='%d:%s'", f->carrying_character->player->client_id, server_clientname(f->carrying_character->player->client_id)); for(int c = 0; c < MAX_CLIENTS; c++) { if(!game.players[c]) continue; if(game.players[c]->team == fi) game.create_sound_global(SOUND_CTF_GRAB_EN, game.players[c]->client_id); else game.create_sound_global(SOUND_CTF_GRAB_PL, game.players[c]->client_id); } break; } } if(!f->carrying_character && !f->at_stand) { if(server_tick() > f->drop_tick + server_tickspeed()*30) { game.create_sound_global(SOUND_CTF_RETURN); f->reset(); } else { f->vel.y += game.world.core.tuning.gravity; move_box(&f->pos, &f->vel, vec2(f->phys_size, f->phys_size), 0.5f); } } } } }