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