int console_cmd_lose(game_state *gs, int argc, char **argv) { if(argc == 1) { game_player *player = game_state_get_player(gs, 0); object *har_obj = game_player_get_har(player); har *har = object_get_userdata(har_obj); har->health = 0; return 0; } return 1; }
int console_cmd_stun(game_state *gs, int argc, char **argv) { if(argc == 1) { game_player *player = game_state_get_player(gs, 1); object *har_obj = game_player_get_har(player); har *har = object_get_userdata(har_obj); har->endurance = 0; har->state = STATE_RECOIL; return 0; } return 1; }
// return 1 on block int ai_block_har(controller *ctrl, ctrl_event **ev) { ai *a = ctrl->data; object *o = ctrl->har; har *h = object_get_userdata(o); object *o_enemy = game_state_get_player(o->gs, h->player_id == 1 ? 0 : 1)->har; har *h_enemy = object_get_userdata(o_enemy); // XXX TODO get maximum move distance from the animation object if(fabsf(o_enemy->pos.x - o->pos.x) < 100) { if(h_enemy->executing_move && maybe(a->difficulty)) { if(har_is_crouching(h_enemy)) { a->cur_act = (o->direction == OBJECT_FACE_RIGHT ? ACT_DOWN|ACT_LEFT : ACT_DOWN|ACT_RIGHT); controller_cmd(ctrl, a->cur_act, ev); } else { a->cur_act = (o->direction == OBJECT_FACE_RIGHT ? ACT_LEFT : ACT_RIGHT); controller_cmd(ctrl, a->cur_act, ev); } return 1; } } return 0; }
int projectile_create(object *obj) { // strore the HAR in local userdata instead projectile_local *local = malloc(sizeof(projectile_local)); local->owner = obj; local->wall_bounce = 0; local->ground_freeze = 0; local->af_data = ((har*)object_get_userdata(obj))->af_data; // Set up callbacks object_set_userdata(obj, local); object_set_dynamic_tick_cb(obj, projectile_tick); object_set_free_cb(obj, projectile_free); object_set_move_cb(obj, projectile_move); projectile_bootstrap(obj); return 0; }
void projectile_move(object *obj) { projectile_local *local = object_get_userdata(obj); obj->pos.x += obj->vel.x; obj->vel.y += obj->gravity; obj->pos.y += obj->vel.y; float dampen = 0.7f; // If wall bounce flag is on, bounce the projectile on wall hit // Otherwise kill it. if(local->wall_bounce) { if(obj->pos.x < ARENA_LEFT_WALL) { obj->pos.x = ARENA_LEFT_WALL; obj->vel.x = -obj->vel.x * dampen; } if(obj->pos.x > ARENA_RIGHT_WALL) { obj->pos.x = ARENA_RIGHT_WALL; obj->vel.x = -obj->vel.x * dampen; } } else if (!local->invincible) { if(obj->pos.x < ARENA_LEFT_WALL) { obj->pos.x = ARENA_LEFT_WALL; obj->animation_state.finished = 1; } if(obj->pos.x > ARENA_RIGHT_WALL) { obj->pos.x = ARENA_RIGHT_WALL; obj->animation_state.finished = 1; } } if(obj->pos.y > ARENA_FLOOR) { obj->pos.y = ARENA_FLOOR; obj->vel.y = -obj->vel.y * dampen; obj->vel.x = obj->vel.x * dampen; } if(obj->pos.y >= (ARENA_FLOOR-5) && IS_ZERO(obj->vel.x) && obj->vel.y < obj->gravity * 1.1 && obj->vel.y > obj->gravity * -1.1 && local->ground_freeze) { object_disable_rewind_tag(obj, 1); } }
void projectile_tick(object *obj) { projectile_local *local = object_get_userdata(obj); if(obj->animation_state.finished) { af_move *move = af_get_move(local->af_data, obj->cur_animation->id); if (move->successor_id) { object_set_animation(obj, &af_get_move(local->af_data, move->successor_id)->ani); object_set_repeat(obj, 0); object_set_vel(obj, vec2f_create(0,0)); obj->animation_state.finished = 0; } } // Set effect flags if(player_frame_isset(obj, "bt")) { object_add_effects(obj, EFFECT_DARK_TINT); } else { object_del_effects(obj, EFFECT_DARK_TINT); } }
int projectile_unserialize(object *obj, serial *ser, int animation_id, game_state *gs) { uint8_t har_id = serial_read_int8(ser); game_player *player; object *o; har *h; for(int i = 0; i < 2; i++) { player = game_state_get_player(gs, i); o = game_player_get_har(player); h = object_get_userdata(o); if (h->af_data->id == har_id) { af_move *move = af_get_move(h->af_data, animation_id); object_set_animation(obj, &move->ani); object_set_userdata(obj, h); object_set_stl(obj, object_get_stl(o)); projectile_create(obj); return 0; } } DEBUG("COULD NOT FIND HAR ID %d", har_id); // could not find the right HAR... return 1; }
int projectile_serialize(object *obj, serial *ser) { projectile_local *local = object_get_userdata(obj); serial_write_int8(ser, SPECID_PROJECTILE); serial_write_int8(ser, local->af_data->id); return 0; }
void projectile_free(object *obj) { free(object_get_userdata(obj)); }
void projectile_stop_on_ground(object *obj, int stop) { projectile_local *local = object_get_userdata(obj); local->ground_freeze = stop; }
void projectile_set_invincible(object *obj) { projectile_local *local = object_get_userdata(obj); local->invincible = 1; }
void projectile_set_wall_bounce(object *obj, int bounce) { projectile_local *local = object_get_userdata(obj); local->wall_bounce = bounce; }
object *projectile_get_owner(object *obj) { return ((projectile_local*)object_get_userdata(obj))->owner; }
af *projectile_get_af_data(object *obj) { return ((projectile_local*)object_get_userdata(obj))->af_data; }
int ai_controller_poll(controller *ctrl, ctrl_event **ev) { ai *a = ctrl->data; object *o = ctrl->har; if (!o) { return 1; } har *h = object_get_userdata(o); object *o_enemy = game_state_get_player(o->gs, h->player_id == 1 ? 0 : 1)->har; // Do not run AI while the game is paused if(game_state_is_paused(o->gs)) { return 0; } // Do not run AI while match is starting or ending // XXX this prevents the AI from doing scrap/destruction moves // XXX this could be fixed by providing a "scene changed" event if(is_arena(game_state_get_scene(o->gs)->id) && arena_get_state(game_state_get_scene(o->gs)) != ARENA_STATE_FIGHTING) { // null out selected move to fix the "AI not moving problem" a->selected_move = NULL; return 0; } // Grab all projectiles on screen vector_clear(&a->active_projectiles); game_state_get_projectiles(o->gs, &a->active_projectiles); // Try to block har if(ai_block_har(ctrl, ev)) { return 0; } // Try to block projectiles if(ai_block_projectile(ctrl, ev)) { return 0; } if(a->selected_move) { // finish doing the selected move first if(a->input_lag_timer > 0) { a->input_lag_timer--; } else { a->move_str_pos--; if(a->move_str_pos <= 0) { a->move_str_pos = 0; } a->input_lag_timer = a->input_lag; } int ch = str_at(&a->selected_move->move_string, a->move_str_pos); controller_cmd(ctrl, char_to_act(ch, o->direction), ev); } else if(rand_int(100) < a->difficulty) { af_move *selected_move = NULL; int top_value = 0; // Attack for(int i = 0; i < 70; i++) { af_move *move = NULL; if((move = af_get_move(h->af_data, i))) { move_stat *ms = &a->move_stats[i]; if(is_valid_move(move, h)) { int value = ms->value + rand_int(10); if (ms->min_hit_dist != -1){ if (ms->last_dist < ms->max_hit_dist+5 && ms->last_dist > ms->min_hit_dist+5){ value += 2; } else if (ms->last_dist > ms->max_hit_dist+10){ value -= 3; } } value -= ms->attempts/2; value -= ms->consecutive*2; if (is_special_move(move) && !maybe(a->difficulty)) { DEBUG("skipping special move %s because of difficulty", str_c(&move->move_string)); continue; } if (selected_move == NULL){ selected_move = move; top_value = value; } else if (value > top_value) { selected_move = move; top_value = value; } } } } for(int i = 0; i < 70; i++) { a->move_stats[i].consecutive /= 2; } if(selected_move) { a->move_stats[selected_move->id].attempts++; a->move_stats[selected_move->id].consecutive++; // do the move a->selected_move = selected_move; a->move_str_pos = str_size(&selected_move->move_string)-1; a->move_stats[a->selected_move->id].last_dist = fabsf(o->pos.x - o_enemy->pos.x); a->blocked = 0; DEBUG("AI selected move %s", str_c(&selected_move->move_string)); } } else { // Change action after 30 ticks if(a->act_timer <= 0 && rand_int(100) > 88){ int p = rand_int(100); if(p > 40){ // walk forward a->cur_act = (o->direction == OBJECT_FACE_RIGHT ? ACT_RIGHT : ACT_LEFT); } else if(p > 20){ // walk backward a->cur_act = (o->direction == OBJECT_FACE_RIGHT ? ACT_LEFT : ACT_RIGHT); } else if(p > 10){ // do nothing a->cur_act = ACT_STOP; } else { // crouch and block a->cur_act = (o->direction == OBJECT_FACE_RIGHT ? ACT_DOWN|ACT_LEFT : ACT_DOWN|ACT_RIGHT); } a->act_timer = 30; controller_cmd(ctrl, a->cur_act, ev); } else { a->act_timer--; } // Jump once in a while if(rand_int(100) == 88){ if(o->vel.x < 0) { controller_cmd(ctrl, ACT_UP|ACT_LEFT, ev); } else if(o->vel.x > 0) { controller_cmd(ctrl, ACT_UP|ACT_RIGHT, ev); } else { controller_cmd(ctrl, ACT_UP, ev); } } } return 0; }