2016-07-04 00:56:45 +02:00
|
|
|
/*! \file character.c
|
|
|
|
* \brief Character and spritesheet functions.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* Copyright (c) Sebastian Krzyszkowiak <dos@dosowisko.net>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
2017-07-22 18:22:12 +02:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2016-07-04 00:56:45 +02:00
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2017-07-22 18:22:12 +02:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2016-07-04 00:56:45 +02:00
|
|
|
*/
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
#include "internal.h"
|
|
|
|
#include "utils.h"
|
2016-07-04 00:56:45 +02:00
|
|
|
#include <allegro5/allegro_primitives.h>
|
|
|
|
#include <allegro5/allegro_ttf.h>
|
2016-09-08 00:32:21 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2016-07-04 00:56:45 +02:00
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void SelectSpritesheet(struct Game* game, struct Character* character, char* name) {
|
|
|
|
struct Spritesheet* tmp = character->spritesheets;
|
2016-07-04 00:56:45 +02:00
|
|
|
PrintConsole(game, "Selecting spritesheet for %s: %s", character->name, name);
|
|
|
|
if (!tmp) {
|
|
|
|
PrintConsole(game, "ERROR: No spritesheets registered for %s!", character->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
while (tmp) {
|
|
|
|
if (!strcmp(tmp->name, name)) {
|
|
|
|
character->spritesheet = tmp;
|
2017-09-10 21:35:14 +02:00
|
|
|
if (character->successor) {
|
|
|
|
free(character->successor);
|
|
|
|
}
|
2016-07-04 00:56:45 +02:00
|
|
|
if (tmp->successor) {
|
|
|
|
character->successor = strdup(tmp->successor);
|
|
|
|
} else {
|
|
|
|
character->successor = NULL;
|
|
|
|
}
|
2017-03-04 19:54:48 +01:00
|
|
|
character->repeat = tmp->repeat;
|
2016-07-04 00:56:45 +02:00
|
|
|
character->pos = 0;
|
|
|
|
if (character->bitmap) {
|
|
|
|
if ((al_get_bitmap_width(character->bitmap) != tmp->width / tmp->cols) || (al_get_bitmap_height(character->bitmap) != tmp->height / tmp->rows)) {
|
|
|
|
al_destroy_bitmap(character->bitmap);
|
|
|
|
character->bitmap = al_create_bitmap(tmp->width / tmp->cols, tmp->height / tmp->rows);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
character->bitmap = al_create_bitmap(tmp->width / tmp->cols, tmp->height / tmp->rows);
|
|
|
|
}
|
|
|
|
PrintConsole(game, "SUCCESS: Spritesheet for %s activated: %s (%dx%d)", character->name, character->spritesheet->name, al_get_bitmap_width(character->bitmap), al_get_bitmap_height(character->bitmap));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
PrintConsole(game, "ERROR: No spritesheets registered for %s with given name: %s", character->name, name);
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void ChangeSpritesheet(struct Game* game, struct Character* character, char* name) {
|
|
|
|
if (character->successor) {
|
|
|
|
free(character->successor);
|
|
|
|
}
|
2016-07-04 00:56:45 +02:00
|
|
|
character->successor = strdup(name);
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void LoadSpritesheets(struct Game* game, struct Character* character) {
|
2016-07-04 00:56:45 +02:00
|
|
|
PrintConsole(game, "Loading spritesheets for character %s...", character->name);
|
2017-09-10 21:35:14 +02:00
|
|
|
struct Spritesheet* tmp = character->spritesheets;
|
2016-07-04 00:56:45 +02:00
|
|
|
while (tmp) {
|
|
|
|
if (!tmp->bitmap) {
|
2017-09-10 22:07:02 +02:00
|
|
|
char filename[255] = {0};
|
2016-07-04 00:56:45 +02:00
|
|
|
snprintf(filename, 255, "sprites/%s/%s.png", character->name, tmp->name);
|
|
|
|
tmp->bitmap = al_load_bitmap(GetDataFilePath(game, filename));
|
|
|
|
tmp->width = al_get_bitmap_width(tmp->bitmap);
|
|
|
|
tmp->height = al_get_bitmap_height(tmp->bitmap);
|
|
|
|
}
|
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void UnloadSpritesheets(struct Game* game, struct Character* character) {
|
2016-07-04 00:56:45 +02:00
|
|
|
PrintConsole(game, "Unloading spritesheets for character %s...", character->name);
|
2017-09-10 21:35:14 +02:00
|
|
|
struct Spritesheet* tmp = character->spritesheets;
|
2016-07-04 00:56:45 +02:00
|
|
|
while (tmp) {
|
2017-09-10 21:35:14 +02:00
|
|
|
if (tmp->bitmap) {
|
|
|
|
al_destroy_bitmap(tmp->bitmap);
|
|
|
|
}
|
2016-07-04 00:56:45 +02:00
|
|
|
tmp->bitmap = NULL;
|
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void RegisterSpritesheet(struct Game* game, struct Character* character, char* name) {
|
|
|
|
struct Spritesheet* s = character->spritesheets;
|
2016-07-04 00:56:45 +02:00
|
|
|
while (s) {
|
|
|
|
if (!strcmp(s->name, name)) {
|
|
|
|
//PrintConsole(game, "%s spritesheet %s already registered!", character->name, name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
s = s->next;
|
|
|
|
}
|
|
|
|
PrintConsole(game, "Registering %s spritesheet: %s", character->name, name);
|
2017-09-10 22:07:02 +02:00
|
|
|
char filename[255] = {0};
|
2016-07-04 00:56:45 +02:00
|
|
|
snprintf(filename, 255, "sprites/%s/%s.ini", character->name, name);
|
2017-09-10 21:35:14 +02:00
|
|
|
ALLEGRO_CONFIG* config = al_load_config_file(GetDataFilePath(game, filename));
|
2016-07-04 00:56:45 +02:00
|
|
|
s = malloc(sizeof(struct Spritesheet));
|
|
|
|
s->name = strdup(name);
|
|
|
|
s->bitmap = NULL;
|
2017-09-10 21:35:14 +02:00
|
|
|
s->cols = strtol(al_get_config_value(config, "", "cols"), NULL, 10);
|
|
|
|
s->rows = strtol(al_get_config_value(config, "", "rows"), NULL, 10);
|
|
|
|
s->blanks = strtol(al_get_config_value(config, "", "blanks"), NULL, 10);
|
|
|
|
s->delay = strtod(al_get_config_value(config, "", "delay"), NULL);
|
2018-02-03 03:46:33 +01:00
|
|
|
s->flip = false;
|
2017-03-07 01:00:27 +01:00
|
|
|
const char* val = al_get_config_value(config, "", "repeat");
|
2017-03-04 19:54:48 +01:00
|
|
|
if (val) {
|
2017-09-10 21:35:14 +02:00
|
|
|
s->repeat = strtod(val, NULL);
|
2017-03-04 19:54:48 +01:00
|
|
|
} else {
|
|
|
|
s->repeat = 0;
|
|
|
|
}
|
2016-07-04 00:56:45 +02:00
|
|
|
s->kill = false;
|
2017-09-10 21:35:14 +02:00
|
|
|
const char* kill = al_get_config_value(config, "", "kill");
|
|
|
|
if (kill) {
|
|
|
|
s->kill = strtol(kill, NULL, 10);
|
|
|
|
}
|
|
|
|
s->successor = NULL;
|
2016-07-04 00:56:45 +02:00
|
|
|
const char* successor = al_get_config_value(config, "", "successor");
|
|
|
|
if (successor) {
|
2017-09-10 21:35:14 +02:00
|
|
|
s->successor = malloc(255 * sizeof(char));
|
2016-07-04 00:56:45 +02:00
|
|
|
strncpy(s->successor, successor, 255);
|
|
|
|
}
|
|
|
|
s->next = character->spritesheets;
|
|
|
|
character->spritesheets = s;
|
|
|
|
al_destroy_config(config);
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT struct Character* CreateCharacter(struct Game* game, char* name) {
|
2016-07-04 00:56:45 +02:00
|
|
|
PrintConsole(game, "Creating character %s...", name);
|
2017-09-10 21:35:14 +02:00
|
|
|
struct Character* character = malloc(sizeof(struct Character));
|
2016-07-04 00:56:45 +02:00
|
|
|
character->name = strdup(name);
|
|
|
|
character->angle = 0;
|
|
|
|
character->bitmap = NULL;
|
|
|
|
character->data = NULL;
|
|
|
|
character->pos = 0;
|
|
|
|
character->pos_tmp = 0;
|
|
|
|
character->x = -1;
|
|
|
|
character->y = -1;
|
2018-02-03 03:17:36 +01:00
|
|
|
character->pivotX = 0.5;
|
|
|
|
character->pivotY = 0.5;
|
|
|
|
character->confineX = -1;
|
|
|
|
character->confineY = -1;
|
2016-07-04 00:56:45 +02:00
|
|
|
character->spritesheets = NULL;
|
|
|
|
character->spritesheet = NULL;
|
|
|
|
character->successor = NULL;
|
2017-03-04 19:54:48 +01:00
|
|
|
character->repeat = 0;
|
2016-07-04 00:56:45 +02:00
|
|
|
character->shared = false;
|
|
|
|
character->dead = false;
|
|
|
|
return character;
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void DestroyCharacter(struct Game* game, struct Character* character) {
|
2016-07-04 00:56:45 +02:00
|
|
|
PrintConsole(game, "Destroying character %s...", character->name);
|
|
|
|
if (!character->shared) {
|
|
|
|
struct Spritesheet *tmp, *s = character->spritesheets;
|
|
|
|
while (s) {
|
|
|
|
tmp = s;
|
|
|
|
s = s->next;
|
2017-09-10 21:35:14 +02:00
|
|
|
if (tmp->bitmap) {
|
|
|
|
al_destroy_bitmap(tmp->bitmap);
|
|
|
|
}
|
|
|
|
if (tmp->successor) {
|
|
|
|
free(tmp->successor);
|
|
|
|
}
|
2016-07-04 00:56:45 +02:00
|
|
|
free(tmp->name);
|
|
|
|
free(tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
if (character->bitmap) {
|
|
|
|
al_destroy_bitmap(character->bitmap);
|
|
|
|
}
|
|
|
|
if (character->successor) {
|
|
|
|
free(character->successor);
|
|
|
|
}
|
2016-07-04 00:56:45 +02:00
|
|
|
free(character->name);
|
|
|
|
free(character);
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void AnimateCharacter(struct Game* game, struct Character* character, float speed_modifier) {
|
|
|
|
if (character->dead) { return; }
|
2016-07-04 00:56:45 +02:00
|
|
|
if (speed_modifier) {
|
|
|
|
character->pos_tmp++;
|
|
|
|
if (character->pos_tmp >= character->spritesheet->delay / speed_modifier) {
|
|
|
|
character->pos_tmp = 0;
|
|
|
|
character->pos++;
|
|
|
|
}
|
2017-09-10 21:35:14 +02:00
|
|
|
if (character->pos >= character->spritesheet->cols * character->spritesheet->rows - character->spritesheet->blanks) {
|
|
|
|
character->pos = 0;
|
2017-03-04 19:54:48 +01:00
|
|
|
if (character->repeat) {
|
|
|
|
character->repeat--;
|
|
|
|
} else {
|
|
|
|
if (character->spritesheet->kill) {
|
|
|
|
character->dead = true;
|
|
|
|
} else if (character->successor) {
|
|
|
|
SelectSpritesheet(game, character, character->successor);
|
|
|
|
}
|
2016-07-04 00:56:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void MoveCharacter(struct Game* game, struct Character* character, float x, float y, float angle) {
|
2018-02-03 03:17:36 +01:00
|
|
|
MoveCharacterF(game, character, x / (float)GetCharacterConfineX(game, character), y / (float)GetCharacterConfineY(game, character), angle);
|
2016-08-26 23:52:32 +02:00
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void MoveCharacterF(struct Game* game, struct Character* character, float x, float y, float angle) {
|
|
|
|
if (character->dead) { return; }
|
2016-07-04 00:56:45 +02:00
|
|
|
character->x += x;
|
|
|
|
character->y += y;
|
|
|
|
character->angle += angle;
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void SetCharacterPositionF(struct Game* game, struct Character* character, float x, float y, float angle) {
|
|
|
|
if (character->dead) { return; }
|
2016-07-04 00:56:45 +02:00
|
|
|
character->x = x;
|
|
|
|
character->y = y;
|
|
|
|
character->angle = angle;
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void SetCharacterPosition(struct Game* game, struct Character* character, float x, float y, float angle) {
|
2018-02-03 03:17:36 +01:00
|
|
|
SetCharacterPositionF(game, character, x / (float)GetCharacterConfineX(game, character), y / (float)GetCharacterConfineY(game, character), angle);
|
2016-08-26 23:52:32 +02:00
|
|
|
}
|
|
|
|
|
2017-09-15 23:44:44 +02:00
|
|
|
SYMBOL_EXPORT void SetCharacterPivotPoint(struct Game* game, struct Character* character, float x, float y) {
|
2018-02-03 03:17:36 +01:00
|
|
|
character->pivotX = x;
|
|
|
|
character->pivotY = y;
|
2017-09-15 23:44:44 +02:00
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void DrawScaledCharacterF(struct Game* game, struct Character* character, ALLEGRO_COLOR tint, float scalex, float scaley, int flags) {
|
|
|
|
if (character->dead) { return; }
|
|
|
|
int spritesheetX = al_get_bitmap_width(character->bitmap) * (character->pos % character->spritesheet->cols);
|
|
|
|
int spritesheetY = al_get_bitmap_height(character->bitmap) * (character->pos / character->spritesheet->cols);
|
2018-02-03 03:17:36 +01:00
|
|
|
al_draw_tinted_scaled_rotated_bitmap_region(character->spritesheet->bitmap, spritesheetX, spritesheetY, al_get_bitmap_width(character->bitmap), al_get_bitmap_height(character->bitmap), tint, al_get_bitmap_width(character->bitmap) * character->pivotX, al_get_bitmap_height(character->bitmap) * character->pivotY, GetCharacterX(game, character) + al_get_bitmap_width(character->bitmap) * scalex * character->pivotX, GetCharacterY(game, character) + al_get_bitmap_height(character->bitmap) * scaley * character->pivotY, scalex, scaley, character->angle, flags);
|
2016-08-26 23:52:32 +02:00
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void DrawCharacterF(struct Game* game, struct Character* character, ALLEGRO_COLOR tint, int flags) {
|
2016-12-06 02:54:31 +01:00
|
|
|
DrawScaledCharacterF(game, character, tint, 1, 1, flags);
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void DrawScaledCharacter(struct Game* game, struct Character* character, ALLEGRO_COLOR tint, float scalex, float scaley, int flags) {
|
|
|
|
if (character->dead) { return; }
|
|
|
|
int spritesheetX = al_get_bitmap_width(character->bitmap) * (character->pos % character->spritesheet->cols);
|
|
|
|
int spritesheetY = al_get_bitmap_height(character->bitmap) * (character->pos / character->spritesheet->cols);
|
2018-02-03 03:17:36 +01:00
|
|
|
al_draw_tinted_scaled_rotated_bitmap_region(character->spritesheet->bitmap, spritesheetX, spritesheetY, al_get_bitmap_width(character->bitmap), al_get_bitmap_height(character->bitmap), tint, al_get_bitmap_width(character->bitmap) * character->pivotX, al_get_bitmap_height(character->bitmap) * character->pivotY, (int)(GetCharacterX(game, character) + al_get_bitmap_width(character->bitmap) * scalex * character->pivotX), (int)(GetCharacterY(game, character) + al_get_bitmap_height(character->bitmap) * scaley * character->pivotY), scalex, scaley, character->angle, flags);
|
2016-12-06 02:54:31 +01:00
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT void DrawCharacter(struct Game* game, struct Character* character, ALLEGRO_COLOR tint, int flags) {
|
2018-02-03 03:46:33 +01:00
|
|
|
if (character->spritesheet->flip) {
|
|
|
|
flags = flags | ALLEGRO_FLIP_HORIZONTAL | ALLEGRO_FLIP_VERTICAL;
|
|
|
|
}
|
2016-12-06 02:54:31 +01:00
|
|
|
DrawScaledCharacter(game, character, tint, 1, 1, flags);
|
2016-08-26 23:52:32 +02:00
|
|
|
}
|
|
|
|
|
2018-02-03 03:17:36 +01:00
|
|
|
SYMBOL_EXPORT void SetCharacterConfines(struct Game* game, struct Character* character, int x, int y) {
|
|
|
|
character->confineX = x;
|
|
|
|
character->confineY = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
SYMBOL_EXPORT int GetCharacterConfineX(struct Game* game, struct Character* character) {
|
|
|
|
return (character->confineX >= 0) ? character->confineX : game->viewport.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
SYMBOL_EXPORT int GetCharacterConfineY(struct Game* game, struct Character* character) {
|
|
|
|
return (character->confineY >= 0) ? character->confineY : game->viewport.height;
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT int GetCharacterX(struct Game* game, struct Character* character) {
|
2018-02-03 03:17:36 +01:00
|
|
|
return character->x * GetCharacterConfineX(game, character);
|
2016-08-26 23:52:32 +02:00
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT int GetCharacterY(struct Game* game, struct Character* character) {
|
2018-02-03 03:17:36 +01:00
|
|
|
return character->y * GetCharacterConfineY(game, character);
|
2016-08-26 23:52:32 +02:00
|
|
|
}
|
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT float GetCharacterAngle(struct Game* game, struct Character* character) {
|
2016-08-26 23:52:32 +02:00
|
|
|
return character->angle;
|
2016-07-04 00:56:45 +02:00
|
|
|
}
|
2016-08-29 23:44:15 +02:00
|
|
|
|
2017-09-10 21:35:14 +02:00
|
|
|
SYMBOL_EXPORT bool IsOnCharacter(struct Game* game, struct Character* character, int x, int y) {
|
2016-08-29 23:44:15 +02:00
|
|
|
int x1 = GetCharacterX(game, character), y1 = GetCharacterY(game, character);
|
|
|
|
int x2 = x1 + al_get_bitmap_width(character->bitmap), y2 = y1 + al_get_bitmap_height(character->bitmap);
|
|
|
|
|
|
|
|
return ((x >= x1) && (x <= x2) && (y >= y1) && (y <= y2));
|
|
|
|
}
|