#include "animation.h" #include "asset.h" #include "map.h" #include "maths.h" #include "obj.h" #include "physics.h" #include "plat.h" #include "render.h" #include "world.h" const Rect player_rect = { 5, 4, 5, 12 }; void init_player(Player* p) { p->anim = asset_id_guy_run_right_anm; p->x = 0; p->y = 0; p->vx = 0; p->vy = 0; p->frame = 0; p->grounded = 0; p->headbutted = 0; p->on_ramp = 0; p->jumping = 0; p->cooldown = 0; p->slashing = 0; p->face = face_right; p->inv = 0; p->hp = player_health; p->charge = 0; p->spec = special_gun; } void update_player_anim(Player* p) { const Animation* anim = get_animation(p->anim); update_anim(anim, &p->frame, &p->rect); } void update_player_phys(Player* p, const Map* map) { Rect r = player_rect; r.x <<= fbits; r.y <<= fbits; r.w <<= fbits; r.h <<= fbits; update_body( map, &p->x, &p->y, &p->vx, &p->vy, &p->grounded, &p->headbutted, &p->on_ramp, &r ); } void update_player_move(Player* p, const App* a, World* w) { int grounded = p->grounded < 3; int mf = player_move_force; int nanim, moving, t; int jumping = p->jumping; Face* face = &p->face; p->cooldown--; if (!grounded) { mf = player_air_move_force; } if (btn_pressed(a, btn_left)) { p->vx -= mf; *face = face_left; } if (btn_pressed(a, btn_right)) { p->vx += mf; *face = face_right; } p->vx = p->vx < -player_max_vel ? -player_max_vel: p->vx > player_max_vel ? player_max_vel: p->vx; moving = absolute(p->vx); moving = moving > player_stop_thresh; if (p->grounded == 0 || p->headbutted) { p->jumping = 0; } jumping = p->jumping; if (jumping) { if (p->grounded < 10 && btn_pressed(a, btn_jump)) { t = absolute(p->vy + 1); t = (f1 << fbits) / t; p->vy -= (player_jump_power_air * t) >> fbits; } if (p->vy < 0 && btn_just_released(a, btn_jump)) { p->vy += f1; p->jumping = 0; } } if (grounded && btn_just_pressed(a, btn_jump)) { p->vy = -player_jump_power; p->jumping = 1; play_sound(500); } if (p->cooldown <= 0 && btn_just_pressed(a, btn_shoot)) { int sx, sy = p->y >> fbits, vx; int anim; Rect dz; if (p->face == face_left) { anim = asset_id_slash_left_anm; sx = (p->x >> fbits) - 45; vx = f1 * 3; } else { anim = asset_id_slash_right_anm; sx = (p->x >> fbits) + 16; vx = -f1 * 3; } dz.x = sx; dz.y = sy; dz.w = 45; dz.h = 17; inst_particle(w, sx, sy, anim, asset_id_arms_img); inst_deathzone(w, &dz, vx, 0, player_slash_damage, 4, 1); p->cooldown = 10; p->slashing = get_animation(asset_id_guy_slash_left_anm)->fc; } if (p->slashing) { p->slashing--; } jumping = p->jumping; nanim = p->anim; switch (p->face) { case face_left: nanim = p->slashing? asset_id_guy_slash_left_anm: grounded ? moving ? asset_id_guy_run_left_anm: asset_id_guy_idle_left_anm: p->vy < 0 ? asset_id_guy_jump_left_anm: asset_id_guy_fall_left_anm; break; case face_right: nanim = p->slashing? asset_id_guy_slash_right_anm: grounded ? moving ? asset_id_guy_run_right_anm: asset_id_guy_idle_right_anm: p->vy < 0 ? asset_id_guy_jump_right_anm: asset_id_guy_fall_right_anm; break; default: break; } if (nanim != p->anim) { p->frame = 0; p->anim = nanim; } } void update_player_hurt(Player* p, World* w) { int i, cx, cy; Rect r = player_rect; r.x += p->x >> fbits; r.y += p->y >> fbits; if (p->inv) { p->inv--; return; } cx = p->x + ((player_rect.w >> 1) << fbits); cy = p->y + ((player_rect.h >> 1) << fbits); for (i = 0; i < w->deathzone_count; i++) { const Deathzone* dz = &w->deathzones[i]; if (!dz->friendly && rects_overlap(&r, &dz->r)) { p->hp -= dz->hp; p->vx -= dz->vx; p->vy -= dz->vy; inst_effect(w, cx, cy, -dz->vx, -dz->vy, 32); goto took_damage; } } for (i = 0; i < w->enemy_count; i++) { const Enemy* e = &w->enemies[i]; Rect er; get_enemy_rect(e->t, &er); er.x += e->x >> fbits; er.y += e->y >> fbits; if (rects_overlap(&r, &er)) { int ecx = e->x + ((er.w >> 1) << fbits); int ecy = e->y + ((er.h >> 1) << fbits); int tx = cx - ecx; int ty = cy - ecy; int l = fxsqrt( ((tx * tx) >> fbits) + ((ty * ty) >> fbits) ); tx <<= fbits; ty <<= fbits; tx /= l; ty /= l; p->hp -= enemy_touch_damage; inst_effect(w, cx, cy, tx, ty, 32); goto took_damage; } } return; took_damage: p->inv = player_inv_frames; w->freeze = player_hurt_freeze; play_sound(2048); } void update_player_special(Player* p, const App* a, World* w) { if (p->charge < player_special_hits) return; if (!btn_just_pressed(a, btn_special)) return; if (p->spec == special_gun) { int sx; Rect dz = { 0, 0, 500, 16 }; if (p->face == face_left) sx = (p->x >> fbits) - dz.w; else sx = (p->x >> fbits) + 16; dz.x = sx; dz.y = (p->y >> fbits); inst_deathzone(w, &dz, 0, 0, player_gun_damage, 1, 1); activate_laser(&w->laser, dz.x, dz.y); w->freeze = 3; } p->charge = 0; } void update_player( Player* p, World* w, const App* app, const Map* map ) { update_player_move(p, app, w); update_player_special(p, app, w); update_player_hurt(p, w); update_player_phys(p, map); update_player_anim(p); } void ren_player(const Player* p, struct Renderer* r) { const Bitmap* b = get_bitmap(asset_id_guy_img); if (p->inv & 5) return; ren_map(r, p->x >> fbits, p->y >> fbits, &p->rect, b); } void init_laser(Laser* l) { l->life = 0; } void activate_laser(Laser* l, int x, int y) { l->life = 10; l->x = x; l->y = y; } void update_laser(Laser* l) { l->life--; } void ren_laser(const Laser* l, struct Renderer* r) { const int h = 10; const int hr = h - l->life; const int hr2 = hr >> 1; Rect re; re.x = l->x; re.y = l->y + hr2; re.w = 500; re.h = 10 - hr; ren_rect(r, &re); re.h = 1; re.y = l->y - hr2; ren_rect(r, &re); re.h = 1; re.y = l->y + h + hr2; ren_rect(r, &re); re.h = 1; re.y = l->y - hr; ren_rect(r, &re); re.h = 1; re.y = l->y + h + hr; ren_rect(r, &re); }