static int jarhead_hit(struct foe_jarhead *f, const vector2 *hit) { const float radius = foe_data[f->common.type].radius; if (vec2_distance_squared(hit, &f->common.pos) < radius*radius) { if (f->state == JARHEAD_ALIVE) { if (irand(3) == 0) { foe_common_gen_explosion(&f->common, 1.f); kill_foe(&f->common); } else { vector2 s = ship.pos; f->state = JARHEAD_EXPLODING; vec2_mul_scalar(&s, .1f); vec2_sub_from(&f->common.dir, &s); f->hit_dir = f->common.dir; vec2_mul_scalar(&f->hit_dir, .02f/vec2_length(&f->hit_dir)); f->common.angle_speed *= -4.f; f->ttl = JARHEAD_TTL_AFTER_HIT; f->spin_angle = .2f + .2f*frand(); if (irand(2)) f->spin_angle = -f->spin_angle; } foe_common_bump_score(&f->common); } return 1; } return 0; }
static int ninja_hit(struct foe_ninja *f, const vector2 *hit) { int r = 0; const float radius = foe_data[FOE_NINJA].radius; if (vec2_distance_squared(hit, &f->common.pos) < radius*radius) { r = 1; if (--f->hit_count <= 0) { foe_common_gen_explosion(&f->common, 1.f); kill_foe(&f->common); foe_common_bump_score(&f->common); } else { vector2 s = ship.pos; f->state = NINJA_RECOVERING; vec2_mul_scalar(&s, .15f); vec2_sub_from(&f->common.dir, &s); f->hit_dir = f->common.dir; vec2_mul_scalar(&f->hit_dir, .03f/vec2_length(&f->hit_dir)); f->common.angle_speed *= -4.f; f->recover_ttl = NINJA_RECOVER_TTL; f->spin_angle = .2f + .2f*frand(); if (irand(2)) f->spin_angle = -f->spin_angle; } } return r; }
static void _control_camera(Game* G, float delta_time) { if(G->num_points == 1) { Vec2 curr = G->points[0].pos; Vec2 delta = vec2_sub(curr, G->prev_single); /* L-R rotation */ Quaternion q = quat_from_axis_anglef(0, 1, 0, delta_time*delta.x*0.2f); G->camera.orientation = quat_multiply(G->camera.orientation, q); /* U-D rotation */ q = quat_from_axis_anglef(1, 0, 0, delta_time*delta.y*0.2f); G->camera.orientation = quat_multiply(q, G->camera.orientation); G->prev_single = curr; } else if(G->num_points == 2) { float camera_speed = 0.1f; Vec3 look = quat_get_z_axis(G->camera.orientation); Vec3 right = quat_get_x_axis(G->camera.orientation); Vec2 avg = vec2_add(G->points[0].pos, G->points[1].pos); Vec2 delta; avg = vec2_mul_scalar(avg, 0.5f); delta = vec2_sub(avg, G->prev_double); look = vec3_mul_scalar(look, -delta.y*camera_speed); right = vec3_mul_scalar(right, delta.x*camera_speed); G->camera.position = vec3_add(G->camera.position, look); G->camera.position = vec3_add(G->camera.position, right); G->prev_double = avg; } }
static void foe_add_trail(const vector2 *pos, const vector2 *dir, int palette) { const int nparticles = 3 + irand(7); int i; vector2 tp = *pos, e = *dir; vec2_mul_scalar(&e, 1.02f); vec2_sub_from(&tp, &e); for (i = 0; i < nparticles; i++) { particle *p = add_particle(); if (!p) break; p->ttl = 15 + irand(15); p->t = 0; p->palette = palette; p->width = p->height = .2f + .1f*frand(); p->pos.x = tp.x + .2f*frand() - .1f; p->pos.y = tp.y + .2f*frand() - .1f; vec2_set(&p->dir, 1, 0); p->speed = 0.f; p->friction = .9f; } }
static void foe_common_spawn(struct foe_common *f, const vector2 *source, int type) { vector2 *pos = &f->pos; vector2 *dir = &f->dir; float speed; f->used = 1; *pos = *source; speed = .05f + .05f*frand(); dir->x = frand() - .5f; dir->y = frand() - .5f; vec2_mul_scalar(dir, speed/vec2_length(dir)); f->tics = 0; f->type = type; f->angle = 0; f->angle_speed = 5.f*frand(); f->rot_axis.x = frand() - .5f; f->rot_axis.y = frand() - .5f; f->rot_axis.z = frand() - .5f; vec3_normalize(&f->rot_axis); foe_data[f->type].create_fn((foe *)f); }
static void evolved_duck_create(struct foe_evolved_duck *f) { f->num_trail_segs = 1; f->trail_seg_head = 0; f->trail_seg[f->trail_seg_head] = f->common.pos; f->trail_texture_id = duck_trail; f->max_turn_angle = MAX_EVOLVED_DUCK_TURN_ANGLE; vec2_mul_scalar(&f->common.dir, .1f); }
static void brute_update(struct foe_brute *f) { vector2 *dir = &f->common.dir; vector2 s = ship.pos; vec2_sub_from(&s, &f->common.pos); vec2_mul_scalar(&s, .004f); vec2_add_to(dir, &s); foe_common_update(&f->common); hit_ship(&f->common.pos, foe_data[FOE_BRUTE].radius); if (vec2_length(dir) > foe_data[FOE_BRUTE].max_speed); vec2_mul_scalar(dir, .7); if (f->common.angle_speed > BRUTE_MAX_ANGLE_SPEED) f->common.angle_speed *= .7; if (brute_is_recovering(f)) foe_add_trail(&f->common.pos, &f->common.dir, PAL_YELLOW); }
void add_touch_points(Game* G, int num_touch_points, TouchPoint* points) { int ii; for(ii=0;ii<num_touch_points;++ii) { G->points[G->num_points++] = points[ii]; } if(G->num_points == 1) { G->prev_single = G->points[0].pos; G->tap_timer = 0.0f; } else if(G->num_points == 2) { Vec2 avg = vec2_add(G->points[0].pos, G->points[1].pos); avg = vec2_mul_scalar(avg, 0.5f); G->prev_double = avg; } }
static void jarhead_update(struct foe_jarhead *f) { switch (f->state) { case JARHEAD_ALIVE: { vector2 *dir = &f->common.dir; vector2 s = ship.pos; vec2_sub_from(&s, &f->common.pos); vec2_mul_scalar(&s, .0003f); vec2_add_to(dir, &s); foe_common_update(&f->common); hit_ship(&f->common.pos, foe_data[f->common.type].radius); vec2_clamp_length(dir, foe_data[f->common.type].max_speed); } break; case JARHEAD_EXPLODING: if (--f->ttl <= 0) { foe_common_gen_explosion(&f->common, 1.f); kill_foe(&f->common); } else { vector2 *dir = &f->common.dir; foe_common_update(&f->common); /* spiral */ vec2_rotate(dir, f->spin_angle); vec2_add_to(dir, &f->hit_dir); vec2_clamp_length(dir, JARHEAD_MAX_EXPLODING_SPEED); /* trail */ foe_add_trail(&f->common.pos, &f->common.dir, PAL_YELLOW); } break; default: assert(0); } }
static void get_foe_pos_for_border_generator(struct foe_generator *generator, vector2 *pos, int foe_type) { const int border = generator->border; const vector2 *p0 = &cur_arena->verts[border]; const vector2 *p1 = &cur_arena->verts[(border + 1)%cur_arena->nverts]; vector2 n; float t; n.x = -(p1->y - p0->y); n.y = p1->x - p0->x; vec2_mul_scalar(&n, 1.5*foe_data[foe_type].radius/vec2_length(&n)); t = frand(); pos->x = p0->x + t*(p1->x - p0->x) + n.x; pos->y = p0->y + t*(p1->y - p0->y) + n.y; }
void remove_touch_points(Game* G, int num_touch_points, TouchPoint* points) { int orig_num_points = G->num_points; int ii, jj; for(ii=0;ii<orig_num_points;++ii) { for(jj=0;jj<num_touch_points;++jj) { if(G->points[ii].index == points[jj].index) { /* This is the removed touch, swap it with the end of the list */ G->points[ii] = G->points[--G->num_points]; break; } } } if(G->num_points == 1) { G->prev_single = G->points[0].pos; } else if(G->num_points == 2) { Vec2 avg = vec2_add(G->points[0].pos, G->points[1].pos); avg = vec2_mul_scalar(avg, 0.5f); G->prev_double = avg; } else { if(G->tap_timer < 0.5f) { if(G->prev_single.x < G->width/2) { if(G->prev_single.y < G->height/2) { // Top Left cycle_renderers(G->graphics); } else { // bottom left G->dynamic_lights = !G->dynamic_lights; } } else { if(G->prev_single.y < G->height/2) { // Top right } else { // bottom right } } } } }
static int brute_hit(struct foe_brute *f, const vector2 *hit) { const vector2 *pos = &f->common.pos; const float radius = foe_data[FOE_BRUTE].radius; if (vec2_distance_squared(hit, pos) < radius*radius) { if (--f->hit_count == 0) { foe_common_gen_explosion(&f->common, 1.3f); kill_foe(&f->common); foe_common_bump_score(&f->common); } else { vector2 s, os; float t; f->last_hit_tic = gc.level_tics; s = f->common.pos; vec2_sub_from(&s, &ship.pos); vec2_normalize(&s); vec2_set(&os, -s.y, s.x); t = 5.f*(frand() - .5f); s.x += t*os.x; s.y += t*os.y; vec2_mul_scalar(&s, .3f/vec2_length(&s)); vec2_add_to(&f->common.dir, &s); f->common.angle_speed *= 2; } return 1; } return 0; }
static void gen_explosion(float x, float y) { int i, n, c; particle *p; n = 150 + irand(150); c = irand(NUM_PALETTES); for (i = 0; i < n; i++) { vector2 offs; p = add_particle(); if (!p) break; p->ttl = 20 + irand(20); p->t = 0; p->width = .3f*(.6f + .1f*frand()); p->height = .3f*(2.8f + .4f*frand()); p->pos.x = x; p->pos.y = y; p->palette = c; vec2_set(&p->dir, frand() - .5f, frand() - .5f); vec2_normalize(&p->dir); offs = p->dir; vec2_mul_scalar(&offs, 1.3f*frand()); vec2_add_to(&p->pos, &offs); p->speed = PARTICLE_SPEED + .05f*frand(); p->friction = .96f; } }
static void evolved_duck_draw(struct foe_evolved_duck *f) { float u, du; float t, s, hs; int i, j, k; glPushAttrib(GL_ALL_ATTRIB_BITS); glDisable(GL_LIGHTING); glShadeModel(GL_FLAT); glDisable(GL_CULL_FACE); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBindTexture(GL_TEXTURE_2D, gl_texture_id(f->trail_texture_id)); glDisable(GL_DEPTH_TEST); s = vec2_length(&f->common.dir); hs = .5f*foe_data[f->common.type].max_speed; if (s < hs) t = 0.f; else t = (s - hs)/hs; glColor4f(t, t, t, t); glBegin(GL_TRIANGLE_STRIP); if (f->num_trail_segs > 1) { vector2 d, n, *from, *to; /* head */ j = f->trail_seg_head; k = f->trail_seg_head - 1; if (k < 0) k = MAX_TRAIL_SEGS - 1; from = &f->trail_seg[j]; to = &f->trail_seg[k]; d.x = -(to->y - from->y); d.y = to->x - from->x; #define HS 3.f #define HL 1.5 vec2_mul_scalar(&d, .5f*HL/vec2_length(&d)); assert(from->x == f->common.pos.x); assert(from->y == f->common.pos.y); n.x = from->x + HS*f->common.dir.x; n.y = from->y + HS*f->common.dir.y; glTexCoord2f(0, 0); glVertex3f(n.x - d.x, n.y - d.y, 0); glTexCoord2f(1, 0); glVertex3f(n.x + d.x, n.y + d.y, 0); /* tail */ /* draw tail */ #define START_U .15f du = (1.f - START_U)/f->num_trail_segs; u = START_U; j = f->trail_seg_head; for (i = 0; i < f->num_trail_segs - 1; i++) { vector2 d, *from, *to; k = j - 1; if (k < 0) k = MAX_TRAIL_SEGS - 1; from = &f->trail_seg[j]; to = &f->trail_seg[k]; d.x = -(to->y - from->y); d.y = to->x - from->x; if (i < f->num_trail_segs - 2) { vector2 *next_to; int l = k - 1; if (l < 0) l = MAX_TRAIL_SEGS - 1; next_to = &f->trail_seg[l]; d.x += -(next_to->y - to->y); d.y += next_to->x - to->x; } assert(vec2_length_squared(&d) > 0.f); vec2_mul_scalar(&d, .5f*HL/vec2_length(&d)); glTexCoord2f(0, u); glVertex3f(from->x - d.x, from->y - d.y, 0.f); glTexCoord2f(1, u); glVertex3f(from->x + d.x, from->y + d.y, 0.f); j = k; u += du; } } glEnd(); glPopAttrib(); { float dir_angle = f->common.angle = 180.f + 360.f*atan2(-f->common.dir.x, f->common.dir.y)/ 2.f/M_PI; glPushMatrix(); glTranslatef(f->common.pos.x, f->common.pos.y, 0.f); glRotatef(dir_angle, 0, 0, 1); glRotatef(f->common.angle, 0, 1, 0); if (f->common.tics < SPAWN_TICS) { static const struct rgb white = { 0.f, 1.f, 1.f }; float s = (float)f->common.tics/SPAWN_TICS; mesh_render_modulate_color(foe_meshes[f->common.type], &white, s); } else { mesh_render(foe_meshes[f->common.type]); } glPopMatrix(); } }
static void evolved_duck_update(struct foe_evolved_duck *f) { vector2 d, od, t; float r; int ship_is_behind; foe_common_update(&f->common); if (foe_bounced) { f->num_trail_segs = 0; } else { if (f->num_trail_segs < MAX_TRAIL_SEGS) f->num_trail_segs++; if (++f->trail_seg_head >= MAX_TRAIL_SEGS) f->trail_seg_head = 0; f->trail_seg[f->trail_seg_head] = f->common.pos; } hit_ship(&f->common.pos, foe_data[f->common.type].radius); od.x = ship.pos.x - f->common.pos.x; od.y = ship.pos.y - f->common.pos.y; vec2_normalize(&od); t.x = -f->common.dir.y; t.y = f->common.dir.x; ship_is_behind = vec2_dot_product(&od, &t) > 0; /* accelerate if behind ship, brake otherwise */ if (ship_is_behind) vec2_mul_scalar(&f->common.dir, .99f); else vec2_mul_scalar(&f->common.dir, 1.2f); /* turn towards ship */ d.x = -(ship.pos.y - f->common.pos.y); d.y = ship.pos.x - f->common.pos.x; vec2_normalize(&d); r = 1.6f*vec2_dot_product(&d, &f->common.dir); if (r < 0) { if (ship_is_behind) r = -f->max_turn_angle; else { if (r < -f->max_turn_angle) r = -f->max_turn_angle; } } else { if (ship_is_behind) { r = f->max_turn_angle; } else { if (r > f->max_turn_angle) r = f->max_turn_angle; } } vec2_rotate(&f->common.dir, r); vec2_clamp_length(&f->common.dir, foe_data[f->common.type].max_speed); }