1 #include <stdlib.h>
2 #include "game/objects/projectile.h"
3 #include "game/protos/object_specializer.h"
4 #include "game/game_state.h"
5 #include "game/game_player.h"
6 #include "utils/log.h"
7 #include "game/objects/arena_constraints.h"
8 
9 #define IS_ZERO(n) (n < 0.1 && n > -0.1)
10 
11 typedef struct projectile_local_t {
12     object *owner;
13     af *af_data;
14     int wall_bounce;
15     int ground_freeze;
16     int invincible;
17 } projectile_local;
18 
projectile_tick(object * obj)19 void projectile_tick(object *obj) {
20     projectile_local *local = object_get_userdata(obj);
21 
22     if(obj->animation_state.finished) {
23         af_move *move = af_get_move(local->af_data, obj->cur_animation->id);
24         if (move->successor_id) {
25             object_set_animation(obj, &af_get_move(local->af_data, move->successor_id)->ani);
26             object_set_repeat(obj, 0);
27             object_set_vel(obj, vec2f_create(0,0));
28             obj->animation_state.finished = 0;
29         }
30     }
31 
32     // Set effect flags
33     if(player_frame_isset(obj, "bt")) {
34         object_add_effects(obj, EFFECT_DARK_TINT);
35     } else {
36         object_del_effects(obj, EFFECT_DARK_TINT);
37     }
38 }
39 
projectile_free(object * obj)40 void projectile_free(object *obj) {
41     free(object_get_userdata(obj));
42 }
43 
projectile_move(object * obj)44 void projectile_move(object *obj) {
45     projectile_local *local = object_get_userdata(obj);
46 
47     obj->pos.x += obj->vel.x;
48     obj->vel.y += obj->gravity;
49     obj->pos.y += obj->vel.y;
50 
51     float dampen = 0.7f;
52 
53     // If wall bounce flag is on, bounce the projectile on wall hit
54     // Otherwise kill it.
55     if(local->wall_bounce) {
56         if(obj->pos.x <  ARENA_LEFT_WALL) {
57             obj->pos.x = ARENA_LEFT_WALL;
58             obj->vel.x = -obj->vel.x * dampen;
59         }
60         if(obj->pos.x > ARENA_RIGHT_WALL) {
61             obj->pos.x = ARENA_RIGHT_WALL;
62             obj->vel.x = -obj->vel.x * dampen;
63         }
64     } else if (!local->invincible) {
65         if(obj->pos.x < ARENA_LEFT_WALL) {
66             obj->pos.x = ARENA_LEFT_WALL;
67             obj->animation_state.finished = 1;
68         }
69         if(obj->pos.x > ARENA_RIGHT_WALL) {
70             obj->pos.x = ARENA_RIGHT_WALL;
71             obj->animation_state.finished = 1;
72         }
73     }
74     if(obj->pos.y > ARENA_FLOOR) {
75         obj->pos.y = ARENA_FLOOR;
76         obj->vel.y = -obj->vel.y * dampen;
77         obj->vel.x = obj->vel.x * dampen;
78     }
79     if(obj->pos.y >= (ARENA_FLOOR-5)
80         && IS_ZERO(obj->vel.x)
81         && obj->vel.y < obj->gravity * 1.1
82         && obj->vel.y > obj->gravity * -1.1
83         && local->ground_freeze) {
84 
85         object_disable_rewind_tag(obj, 1);
86     }
87 }
88 
projectile_serialize(object * obj,serial * ser)89 int projectile_serialize(object *obj, serial *ser) {
90     projectile_local *local = object_get_userdata(obj);
91     serial_write_int8(ser, SPECID_PROJECTILE);
92     serial_write_int8(ser, local->af_data->id);
93     return 0;
94 }
95 
projectile_unserialize(object * obj,serial * ser,int animation_id,game_state * gs)96 int projectile_unserialize(object *obj, serial *ser, int animation_id, game_state *gs) {
97     uint8_t har_id = serial_read_int8(ser);
98 
99     game_player *player;
100     object *o;
101     har *h;
102 
103     for(int i = 0; i < 2; i++) {
104         player = game_state_get_player(gs, i);
105         o = game_player_get_har(player);
106         h = object_get_userdata(o);
107         if (h->af_data->id == har_id) {
108             af_move *move = af_get_move(h->af_data, animation_id);
109             object_set_animation(obj, &move->ani);
110             object_set_userdata(obj, h);
111             object_set_stl(obj, object_get_stl(o));
112             projectile_create(obj);
113             return 0;
114         }
115     }
116     DEBUG("COULD NOT FIND HAR ID %d", har_id);
117     // could not find the right HAR...
118     return 1;
119 }
120 
projectile_bootstrap(object * obj)121 void projectile_bootstrap(object *obj) {
122     object_set_serialize_cb(obj, projectile_serialize);
123     object_set_unserialize_cb(obj, projectile_unserialize);
124 }
125 
projectile_create(object * obj)126 int projectile_create(object *obj) {
127     // strore the HAR in local userdata instead
128     projectile_local *local = malloc(sizeof(projectile_local));
129     local->owner = obj;
130     local->wall_bounce = 0;
131     local->ground_freeze = 0;
132     local->af_data = ((har*)object_get_userdata(obj))->af_data;
133 
134     // Set up callbacks
135     object_set_userdata(obj, local);
136     object_set_dynamic_tick_cb(obj, projectile_tick);
137     object_set_free_cb(obj, projectile_free);
138     object_set_move_cb(obj, projectile_move);
139     projectile_bootstrap(obj);
140     return 0;
141 }
142 
projectile_get_af_data(object * obj)143 af *projectile_get_af_data(object *obj) {
144     return ((projectile_local*)object_get_userdata(obj))->af_data;
145 }
146 
projectile_get_owner(object * obj)147 object *projectile_get_owner(object *obj) {
148     return ((projectile_local*)object_get_userdata(obj))->owner;
149 }
150 
projectile_set_wall_bounce(object * obj,int bounce)151 void projectile_set_wall_bounce(object *obj, int bounce) {
152     projectile_local *local = object_get_userdata(obj);
153     local->wall_bounce = bounce;
154 }
155 
projectile_set_invincible(object * obj)156 void projectile_set_invincible(object *obj) {
157     projectile_local *local = object_get_userdata(obj);
158     local->invincible = 1;
159 }
160 
projectile_stop_on_ground(object * obj,int stop)161 void projectile_stop_on_ground(object *obj, int stop) {
162     projectile_local *local = object_get_userdata(obj);
163     local->ground_freeze = stop;
164 }
165