1 /*! \file 2 * \brief Animation string parser 3 * \details Functions and structs for reading, writing and modifying OMF:2097 animation strings. 4 * \copyright MIT license. 5 * \date 2013-2014 6 * \author Andrew Thompson 7 * \author Tuomas Virtanen 8 */ 9 10 #ifndef _SD_SCRIPT_H 11 #define _SD_SCRIPT_H 12 13 #include "shadowdive/taglist.h" 14 15 #ifdef __cplusplus 16 extern "C" { 17 #endif 18 19 /*! \brief Animation tag 20 * 21 * Describes a single tag in animation frame. 22 */ 23 typedef struct { 24 const char* key; ///< Tag name 25 const char* desc; ///< Tag description 26 int has_param; ///< Tells if the tag has a parameter 27 int value; ///< Tag parameter value. Only valid if has_param = 1. 28 } sd_script_tag; 29 30 /*! \brief Animation frame 31 * 32 * Describes a single frame in animation string. 33 */ 34 typedef struct { 35 int sprite; ///< Sprite ID that the frame relates to 36 int tick_len; ///< Length of the frame in ticks 37 int tag_count; ///< Amount of tags in this frame 38 sd_script_tag *tags; ///< A list of tags in this frame 39 } sd_script_frame; 40 41 /*! \brief Animation script 42 * 43 * A single animation string. Contains multiple frames, which then contain tags. 44 * A valid string must contain at least a single frame. 45 */ 46 typedef struct { 47 int frame_count; ///< Amount of frames in the string 48 sd_script_frame *frames; ///< List of frames in this string 49 } sd_script; 50 51 /*! \brief Initialize script parser 52 * 53 * Initializes the script parser with empty values. 54 * 55 * \retval SD_INVALID_INPUT Script struct pointer was NULL 56 * \retval SD_SUCCESS Success. 57 * 58 * \param script Allocated script struct pointer. 59 */ 60 int sd_script_create(sd_script *script); 61 62 /*! \brief Free script parser 63 * 64 * Frees up all memory reserved by the script parser structure. 65 * All contents will be freed, all pointers to contents will be invalid. 66 * 67 * \param script Script struct to free. 68 */ 69 void sd_script_free(sd_script *script); 70 71 /*! \brief Decode animation string 72 * 73 * Decodes an animation string to frames and tags. There must be at least 74 * a single full frame, which means a frame number and length in ticks. 75 * 76 * \retval SD_ANIM_INVALID_STRING String is invalid; eg. doesn't have enough complete frames. 77 * \retval SD_INVALID_TAG There was an invalid tag in string. invalid_pos will contain problematic position. 78 * \retval SD_SUCCESS Decoding was successful. 79 * 80 * \param script Script structure to fill. Must be formatted using sd_script_create(). 81 * \param str Animation string to parse 82 * \param invalid_pos Will contain problematic position in string if SD_INVALID_TAG is returned. Will be ignored if set to NULL. 83 */ 84 int sd_script_decode(sd_script *script, const char* str, int *invalid_pos); 85 86 /*! \brief Encode animation string 87 * 88 * Encodes the animation script structure back to an animation string. 89 * Note that if the decoded string contained oddities like prefixed zeroes in 90 * front of numbers, those will be automatically fixed. Therefore the output 91 * string may not be exactly like the input string. Filler tags (u,c,p,o,z) 92 * will also be removed. 93 * 94 * Note that the target str buffer needs to be large enough for the encoding operation. 95 * It is possible to find the encoded string buffer size by using sd_script_encoded_lenghth() function. 96 * 97 * \sa sd_script_encoded_length 98 * 99 * \retval SD_INVALID_INPUT Script or str parameter was NULL 100 * \retval SD_SUCCESS Successful operation 101 * 102 * \param script Script structure to encode 103 * \param str Target string buffer. Make sure it's large enough! 104 */ 105 int sd_script_encode(const sd_script *script, char* str); 106 107 /*! \brief Find the encoded length of a script 108 * 109 * Returns the encoded length of the animation script. The length will be the EXACT size 110 * of the string, so you may need to add +1 to compensate for a trailing zero. 111 * 112 * The function will return 0 if there are no frames in the script, the frames are invalid, 113 * or the script variable is NULL. 114 * 115 * \sa sd_script_decode 116 * 117 * \param script Script structure to check 118 * \return Length of the encoded animation string. 119 */ 120 int sd_script_encoded_length(const sd_script *script); 121 122 /*! \brief Find the total duration of the script 123 * 124 * Finds the total duration of the script in game ticks. Essentially 125 * just adds up all the frame lengths. 126 * 127 * \param script Script structure to check 128 * \return The total duration of the script in game ticks 129 */ 130 int sd_script_get_total_ticks(const sd_script *script); 131 132 /*! \brief Find the tick position at the start of the given frame. 133 * 134 * \param script Script structure to check 135 * \param frame_id Frame ID to search 136 * \return Tick position at the frame 137 */ 138 int sd_script_get_tick_pos_at_frame(const sd_script *script, int frame_id); 139 140 /*! \brief Find the tick length of the given frame 141 * 142 * \param script Script structure to check 143 * \param frame_id Frame ID to search 144 * \return Tick length of the frame, 0 if frame_id does not exist. 145 */ 146 int sd_script_get_tick_len_at_frame(const sd_script *script, int frame_id); 147 148 /*! \brief Find the sprite ID of the given frame 149 * 150 * \param script Script structure to check 151 * \param frame_id Frame ID to search 152 * \return Sprite ID of the given frame, 0 if frame_id does not exist. 153 */ 154 int sd_script_get_sprite_at_frame(const sd_script *script, int frame_id); 155 156 /*! \brief Returns the frame at a given tick 157 * 158 * Finds the frame at the given moment in time (tick). If the ticks value is either 159 * larger than the total duration of the script or a negative value, the function will return NULL. 160 * If script variable is NULL, the function will also return NULL. Otherwise the function will 161 * return the frame at the moment of the given tick. 162 * 163 * The tick values will start at 0, so if the tick length of a frame is 140, the last tick will be 139. 164 * 165 * The returned frame is owned by the library; do not attempt to free it. 166 * 167 * \param script The script structure to read 168 * \param ticks A position in time in game ticks 169 * \return Frame pointer or NULL 170 */ 171 const sd_script_frame* sd_script_get_frame_at(const sd_script *script, int ticks); 172 173 /*! \brief Returns the frame at a given position 174 * 175 * Returns the frame at a given position. If the frame number given is less than 0 176 * or larger or equal than the number of frames, NULL will be returned. A NULL value 177 * for the script pointer will also cause a NULL to be returned. Otherwise the function 178 * will return the frame at the given position. 179 * 180 * The returned frame is owned by the library; do not attempt to free it. 181 * 182 * \param script The script structure to read 183 * \param frame_number Frame number to get 184 * \return Frame pointer or NULL 185 */ 186 const sd_script_frame* sd_script_get_frame(const sd_script *script, int frame_number); 187 188 /*! \brief Returns the information of a tag in a frame. 189 * 190 * Returns the tag descriptor for the instance of a tag in frame. A NULL for either 191 * parameter will result in a NULL being returned. If the requested tag does not 192 * exist in the frame, a NULL will be also returned. 193 * 194 * The returned tag information struct is owned by the library; do not attempt to free it. 195 * 196 * \param frame Frame structure to read 197 * \param tag Tag to look for. Must have a trailing zero. 198 * \return Tag descriptor pointer or NULL 199 */ 200 const sd_script_tag* sd_script_get_tag(const sd_script_frame* frame, const char* tag); 201 202 /*! \brief Tells if the frame changed between two points in time 203 * 204 * Tells if the frame changed between two game ticks. If the tick times are equal, 205 * if frame struct pointer is null, or if the frame didn't change, 0 will be returned. 206 * If the frame changed, 1 will be returned. 207 * 208 * Note that a change between zero and negative value will also count as a frame change. 209 * Eg. switching between "animation not started" and first frame wil lcause 1. 210 * Also, change from a tick in animation range to a tick outside of animation will cause 211 * 1 to be returned. However, a change from "not started" (-1) to "finished" (tick > total_ticks) 212 * will cause 0 to be returned. 213 * 214 * \param script The script structure to inspect 215 * \param tick_start Position 1 216 * \param tick_stop Position 2 217 * \return 1 or 0, whether the frame changed or not. 218 */ 219 int sd_script_frame_changed(const sd_script *script, int tick_start, int tick_stop); 220 221 /*! \brief Returns the array index of frame 222 * 223 * This simply returns the array index of the given frame. Comparison to the frames 224 * in the script will be done by pointer. If the frame does not exist in the animation, 225 * -1 will be returned. 226 * 227 * \param script The script structure to inspect 228 * \param frame Frame structure to find the index of 229 * \return Index of the frame 230 */ 231 int sd_script_get_frame_index(const sd_script *script, const sd_script_frame *frame); 232 233 /*! \brief Returns the array index of frame at given tick position 234 * 235 * Returns the array index of the frame at a given tick position. If the tick is valid 236 * and in the range of the animation, an index will be returned. If the tick is outside 237 * the animation range, -1 will be returned. 238 * 239 * \param script The script structure to inspect 240 * \param ticks Tick position to find 241 * \return Index of the frame 242 */ 243 int sd_script_get_frame_index_at(const sd_script *script, int ticks); 244 245 /*! \brief Tells if the frame is the last frame in animation. 246 * 247 * Tells if the given frame pointer is the last frame in the given animation. 248 * If script or frame pointer is null, or frame is not the last frame, 0 will be returned. 249 * Otherwise 1 will be returned. 250 * 251 * \param script The script structure to inspect 252 * \param frame Frame structure to find 253 * \return 1 or 0 254 */ 255 int sd_script_is_last_frame(const sd_script *script, const sd_script_frame *frame); 256 257 /*! \brief Tells if the frame index is the last frame in animation. 258 * 259 * Tells if the given frame index is the last frame in the given animation. 260 * If script pointer is null, or frame is not the last frame, 0 will be returned. 261 * Otherwise 1 will be returned. 262 * 263 * \param script The script structure to inspect 264 * \param ticks Tick position to find 265 * \return 1 or 0 266 */ 267 int sd_script_is_last_frame_at(const sd_script *script, int ticks); 268 269 /*! \brief Tells if the frame is the first frame in animation. 270 * 271 * Tells if the given frame pointer is the first frame in the given animation. 272 * If script or frame pointer is null, or frame is not the first frame, 0 will be returned. 273 * Otherwise 1 will be returned. 274 * 275 * \param script The script structure to inspect 276 * \param frame Frame structure to find 277 * \return 1 or 0 278 */ 279 int sd_script_is_first_frame(const sd_script *script, const sd_script_frame *frame); 280 281 /*! \brief Tells if the frame index is the first frame in animation. 282 * 283 * Tells if the given frame index is the first frame in the given animation. 284 * If script pointer is null, or frame is not the first frame, 0 will be returned. 285 * Otherwise 1 will be returned. 286 * 287 * \param script The script structure to inspect 288 * \param ticks Tick position to find 289 * \return 1 or 0 290 */ 291 int sd_script_is_first_frame_at(const sd_script *script, int ticks); 292 293 /*! \brief Tells if the tag is set in frame 294 * 295 * Tells if the given tag is set in the given frame, Returns 1 if tag is set, 296 * otherwise 0. 297 * 298 * \param frame The frame structure to inspect 299 * \param tag Tag name to find 300 * \return 1 or 0 301 */ 302 int sd_script_isset(const sd_script_frame *frame, const char* tag); 303 304 /*! \brief Returns the tag value in frame 305 * 306 * Returns the parameter value of a tag in a given frame. Note that if the tag doesn't 307 * exist in frame, or tag doesn't have a parameter value, 0 will be returned. Otherwise 308 * the tag parameter value will be returned. 309 * 310 * \param frame The frame structure to inspect 311 * \param tag Tag name to find 312 * \return Tag parameter value or 0. 313 */ 314 int sd_script_get(const sd_script_frame *frame, const char* tag); 315 316 /*! \brief Returns the next frame number with a given sprite ID 317 * 318 * Returns the next frame number with the given sprite number. Sprite numbers start from 0 and go to 319 * the amount of sprites in the frame. 320 * 321 * If script is NULL, sprite_id is smaller than 0 or larger than the amount of sprites in the 322 * script, or current_tick is larger than the length of the script animation, or sprite frame 323 * with the sprite_id does not exist in script, -1 value will be returned. Otherwise 324 * the frame number will be returned. 325 * 326 * The search will start from the next frame from the one that current_tick is pointing at. 327 * 328 * \param script Script structure to search through 329 * \param sprite_id Sprite ID to search for 330 * \param current_tick Current tick time 331 * \return Frame ID or -1 on error 332 */ 333 int sd_script_next_frame_with_sprite(const sd_script *script, int sprite_id, int current_tick); 334 335 /*! \brief Returns the next frame number with a given tag 336 * 337 * Returns the next frame number with the given tag. 338 * 339 * If script or tag is NULL, current_tick is larger than the length of the script animation, 340 * or sprite frame with the tag does not exist in script, -1 value will be returned. Otherwise 341 * the frame number will be returned. 342 * 343 * The search will start from the next frame from the one that current_tick is pointing at. 344 * 345 * \param script Script structure to search through 346 * \param tag Tag to search for 347 * \param current_tick Current tick time 348 * \return Frame ID or -1 on error 349 */ 350 int sd_script_next_frame_with_tag(const sd_script *script, const char* tag, int current_tick); 351 352 /*! \brief Sets a tag for the given frame 353 * 354 * Sets the tag for the given frame. If the tag has not been set previously, a new tag 355 * entry will be created. If the tag has been set previously, and the tag accepts value 356 * parameters, a new parameter will be set for the tag. Otherwise this function does nothing. 357 * 358 * \retval SD_SUCCESS On succesful tag set operation 359 * \retval SD_INVALID_INPUT if script or tag is NULL, tag does not exist or frame does not exist. 360 * 361 * \param script Script to modify 362 * \param frame_id Frame ID to modify 363 * \param tag Tag to add 364 * \param value Value to set, if tag allows values. 365 */ 366 int sd_script_set_tag(sd_script *script, int frame_id, const char* tag, int value); 367 368 /*! \brief Deletes a tag from the given frame 369 * 370 * Deletes the tag from the given frame. If the tag does not exist, does nothing. 371 * 372 * \retval SD_SUCCESS On succesful tag set operation 373 * \retval SD_INVALID_INPUT if script or tag is NULL or the frame does not exist. 374 * 375 * \param script Script to modify 376 * \param frame_id Frame ID to modify 377 * \param tag Tag to delete 378 */ 379 int sd_script_delete_tag(sd_script *script, int frame_id, const char* tag); 380 381 /*! \brief Append a new frame to the end of the frame list 382 * 383 * Appends a new frame to the end of the frame list, and sets its tick length and sprite ID. 384 * Tag list will be empty after creation. 385 * 386 * \retval SD_SUCCESS on successful frame creation 387 * \retval SD_INVALID_INPUT if script is NULL 388 * 389 * \param script Script to modify 390 * \param tick_len Tick length of the new frame 391 * \param sprite_id Sprite ID for the new frame 392 */ 393 int sd_script_append_frame(sd_script *script, int tick_len, int sprite_id); 394 395 /*! \brief Clear frame tags 396 * 397 * Clears all tags from the given frame. 398 * 399 * \retval SD_SUCCESS on successful removal 400 * \retval SD_INVALID_INPUT if script is NULL or if frame_id is nonexistent 401 * 402 * \param script Script to modify 403 * \param frame_id Valid frame ID with tags to clear 404 */ 405 int sd_script_clear_tags(sd_script *script, int frame_id); 406 407 /*! \brief Set frame tick length 408 * 409 * Sets a new tick length for the given frame. 410 * 411 * \retval SD_SUCCESS on successful operation 412 * \retval SD_INVALID_INPUT if script is NULL or frame_id is nonexistent 413 * 414 * \param script Script to modify 415 * \param frame_id Frame ID to set tick length to 416 * \param duration Tick length to set 417 */ 418 int sd_script_set_tick_len_at_frame(sd_script *script, int frame_id, int duration); 419 420 /*! \brief Set frame sprite ID 421 * 422 * Sets the sprite ID of the given frame. 423 * 424 * \retval SD_SUCCESS on successful operation 425 * \retval SD_INVALID_INPUT if script is NULL, frame_id is invalid or sprite_id is invalid. 426 * 427 * \param script Script to modify 428 * \param frame_id Frame ID to set sprite ID to 429 * \param sprite_id Sprite ID to set 430 */ 431 int sd_script_set_sprite_at_frame(sd_script *script, int frame_id, int sprite_id); 432 433 /** \brief Returns the frame ID by frame letter. 434 * 435 * \param letter Frame letter ('A', 'B', etc.) 436 * \return Frame ID ('A' => 0, ...) 437 */ 438 int sd_script_letter_to_frame(char letter); 439 440 /** \brief Returns the frame letter by frame ID. 441 * 442 * \param frame_id Frame ID (0 ... n) 443 * \return Frame letter (0 => 'A', ...) 444 */ 445 char sd_script_frame_to_letter(int frame_id); 446 447 #ifdef __cplusplus 448 } 449 #endif 450 451 #endif // _SD_SCRIPT_H