initial commit
This commit is contained in:
358
Animal.cpp
Normal file
358
Animal.cpp
Normal file
@@ -0,0 +1,358 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <SDL3/SDL_audio.h>
|
||||
|
||||
#include "Animal.h"
|
||||
|
||||
#include "embed.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
SkinsEmbed skins_embed;
|
||||
|
||||
Animal::Animal(string skin) {
|
||||
move_time = 0;
|
||||
animate_time = 0;
|
||||
random_time = 0;
|
||||
cur = 0;
|
||||
viime_event = 0;
|
||||
state_changed = false;
|
||||
|
||||
// set rand seed
|
||||
SDL_srand(0);
|
||||
|
||||
readSkin(skin);
|
||||
setSpecialState(drop);
|
||||
}
|
||||
|
||||
Animal::~Animal() {
|
||||
}
|
||||
|
||||
SDL_Surface *Animal::readImg(string skin, string state_name, int num) {
|
||||
SDL_Surface *pet;
|
||||
embed_data *img_buf = skins_embed.getSkin(skin, state_name);
|
||||
if (img_buf) { // load from embedded if exists
|
||||
SDL_IOStream *io = SDL_IOFromConstMem(img_buf[num].data, img_buf[num].len);
|
||||
if (io == NULL) {
|
||||
SDL_Log("could not open io for pet: %s\n", SDL_GetError());
|
||||
}
|
||||
pet = IMG_Load_IO(io, true);
|
||||
if (pet == NULL) {
|
||||
SDL_Log("could not create pet surface: %s\n", SDL_GetError());
|
||||
}
|
||||
} else {
|
||||
stringstream file_name;
|
||||
file_name << "skin/" << skin << "/" << state_name << "/" << (num + 1) << ".png";
|
||||
pet = IMG_Load(file_name.str().c_str());
|
||||
if (pet == NULL) {
|
||||
SDL_Log("could not create pet surface: %s\n", SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
// SDL_CreateTexture can't handle palette formats, so check if needs converting
|
||||
if (pet && pet->format <= SDL_PIXELFORMAT_INDEX8) {
|
||||
SDL_Surface *tmp = pet;
|
||||
pet = SDL_ConvertSurface(pet, SDL_GetPixelFormatForMasks(32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000));
|
||||
SDL_DestroySurface(tmp);
|
||||
}
|
||||
|
||||
if (pet && !SDL_ISPIXELFORMAT_ALPHA(pet->format)) {
|
||||
/* Set the colorkey to the top-left pixel */
|
||||
Uint8 r, g, b, a;
|
||||
|
||||
SDL_ReadSurfacePixel(pet, 0, 0, &r, &g, &b, &a);
|
||||
SDL_SetSurfaceColorKey(pet, 1, SDL_MapSurfaceRGBA(pet, r, g, b, a));
|
||||
}
|
||||
|
||||
return pet;
|
||||
}
|
||||
|
||||
void Animal::readSkin(string skin) {
|
||||
|
||||
string buf;
|
||||
string key;
|
||||
State feat;
|
||||
char prev_chr;
|
||||
|
||||
states.clear();
|
||||
special_states.clear();
|
||||
random_states.clear();
|
||||
|
||||
special_states.resize(SPECIAL_STATE_LAST);
|
||||
|
||||
string params = skins_embed.getParams(skin);
|
||||
if (params.length()) { // load from embedded if exists
|
||||
for (string::iterator it = params.begin(); it != params.end(); ++it) {
|
||||
readSkinStep(skin, *it, buf, key, feat, prev_chr);
|
||||
}
|
||||
} else {
|
||||
stringstream file_name;
|
||||
file_name << "skin/" << skin << ".tsk";
|
||||
FILE *tied = fopen(file_name.str().c_str(), "rb");
|
||||
if (!tied) {
|
||||
cout << "Skin file fail: " << file_name.str() << endl;
|
||||
}
|
||||
while(!feof(tied)) {
|
||||
char chr = fgetc(tied);
|
||||
readSkinStep(skin, chr, buf, key, feat, prev_chr);
|
||||
}
|
||||
fclose(tied);
|
||||
}
|
||||
|
||||
if (!feat.name.empty()) {
|
||||
readSkinFill(skin, feat);
|
||||
|
||||
feat.name.clear();
|
||||
feat.sound.clear();
|
||||
feat.sound_data.loop = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Animal::readSkinStep(string skin, char chr, string &buf, string &key, State &feat, char &prev_chr) {
|
||||
if (chr == '\n') {
|
||||
if (prev_chr == '\n' && !feat.name.empty()) {
|
||||
readSkinFill(skin, feat);
|
||||
|
||||
feat.name.clear();
|
||||
feat.sound.clear();
|
||||
feat.sound_data.loop = 0;
|
||||
}
|
||||
|
||||
if (key == "name")
|
||||
feat.name = buf;
|
||||
if (key == "img_name")
|
||||
feat.img_name = buf;
|
||||
if (key == "count")
|
||||
feat.count = atoi(buf.c_str());
|
||||
if (key == "interval")
|
||||
feat.interval = atoi(buf.c_str());
|
||||
if (key == "x")
|
||||
feat.x = atoi(buf.c_str());
|
||||
if (key == "y")
|
||||
feat.y = atoi(buf.c_str());
|
||||
if (key == "sound")
|
||||
feat.sound = buf.c_str();
|
||||
if (key == "loop")
|
||||
feat.sound_data.loop = atoi(buf.c_str());
|
||||
buf.clear();
|
||||
} else if (chr == '=') {
|
||||
key = buf;
|
||||
buf.clear();
|
||||
} else {
|
||||
buf.push_back(chr);
|
||||
}
|
||||
|
||||
prev_chr = chr;
|
||||
}
|
||||
|
||||
void Animal::readSkinFill(string skin, State feat) {
|
||||
states.push_back(feat);
|
||||
|
||||
// Load images to memory
|
||||
cur_state = &states.back();
|
||||
for (int x = 0; x < cur_state->count; x++) {
|
||||
cur_state->imgs.push_back(NULL);
|
||||
cur_state->imgs[x] = readImg(skin, cur_state->img_name, x);
|
||||
}
|
||||
|
||||
if (feat.sound.empty()) {
|
||||
cur_state->sound_data.len = 0;
|
||||
} else {
|
||||
pair<unsigned char*, unsigned int> buf = skins_embed.getSound(skin, cur_state->img_name);
|
||||
if (buf.first) { // load from embedded if exists
|
||||
SDL_IOStream *io = SDL_IOFromConstMem(buf.first, buf.second);
|
||||
if (io == NULL) {
|
||||
SDL_Log("could not open io for sound: %s\n", SDL_GetError());
|
||||
}
|
||||
if (!SDL_LoadWAV_IO(io, true, &cur_state->sound_data.spec, &cur_state->sound_data.buf, &cur_state->sound_data.len)) {
|
||||
SDL_Log("failed to load audio: %s", SDL_GetError());
|
||||
}
|
||||
} else {
|
||||
stringstream file_name;
|
||||
file_name << "skin/" << skin << "/" << cur_state->img_name << "/" << cur_state->sound;
|
||||
if (!SDL_LoadWAV(file_name.str().c_str(), &cur_state->sound_data.spec, &cur_state->sound_data.buf, &cur_state->sound_data.len)) {
|
||||
SDL_Log("failed to load audio %s: %s", file_name.str().c_str(), SDL_GetError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Special state cases
|
||||
cur_state->interruptable = true;
|
||||
if (cur_state->name == "stay") {
|
||||
cur_state->special = stay;
|
||||
random_states.push_back(cur_state);
|
||||
} else if (cur_state->name == "drop") {
|
||||
cur_state->special = drop;
|
||||
cur_state->interruptable = false;
|
||||
} else if (cur_state->name == "jump") {
|
||||
cur_state->special = jump;
|
||||
random_states.push_back(cur_state);
|
||||
cur_state->interruptable = false;
|
||||
} else if (cur_state->name == "jump_end") {
|
||||
cur_state->special = jump_end;
|
||||
cur_state->interruptable = false;
|
||||
} else if (cur_state->name == "flop") {
|
||||
cur_state->special = flop;
|
||||
} else if (cur_state->name == "hang") {
|
||||
cur_state->special = hang;
|
||||
cur_state->interruptable = false;
|
||||
} else if (cur_state->name == "fast_right") {
|
||||
cur_state->special = fast_right;
|
||||
random_states.push_back(cur_state);
|
||||
} else if (cur_state->name == "fast_left") {
|
||||
cur_state->special = fast_left;
|
||||
random_states.push_back(cur_state);
|
||||
} else {
|
||||
cur_state->special = NOTHING;
|
||||
random_states.push_back(cur_state);
|
||||
}
|
||||
if (cur_state->special) {
|
||||
special_states[cur_state->special] = cur_state;
|
||||
}
|
||||
}
|
||||
|
||||
void Animal::move() {
|
||||
disp_pos.x += cur_state->x;
|
||||
disp_pos.y += cur_state->y;
|
||||
|
||||
// Don't go out of display on right side
|
||||
if (disp_pos.x + getImage()->w > disp_pos.w) {
|
||||
setSpecialState(stay);
|
||||
if (disp_pos.y < getImage()->h - 150) {
|
||||
setSpecialState(drop);
|
||||
}
|
||||
disp_pos.x = disp_pos.w - getImage()->w - 2;
|
||||
}
|
||||
|
||||
// Donät fo out of display on left side
|
||||
if (disp_pos.x < 0) {
|
||||
setSpecialState(stay);
|
||||
if (disp_pos.y < disp_pos.h - 150) {
|
||||
setSpecialState(drop);
|
||||
}
|
||||
disp_pos.x = 2;
|
||||
}
|
||||
|
||||
// Check if we have jumped high enough
|
||||
if (disp_pos.y < disp_pos.h - 300 && cur_state->name == "jump") {
|
||||
setSpecialState(jump_end);
|
||||
}
|
||||
|
||||
// Check if if hit the ground
|
||||
if (disp_pos.y >= disp_pos.h - 150) {
|
||||
if (cur_state->name == "jump_end") {
|
||||
setSpecialState(stay);
|
||||
} else if (cur_state->name == "drop") {
|
||||
setSpecialState(flop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Animal::animate(bool reset){
|
||||
if (reset) {
|
||||
animation_i = 0;
|
||||
} else if (animation_i >= cur_state->count - 1) {
|
||||
animation_i = 0;
|
||||
} else {
|
||||
animation_i++;
|
||||
}
|
||||
}
|
||||
|
||||
void Animal::shuffle() {
|
||||
// Check if we are in a cur_state where we can't do anything
|
||||
if (cur_state->interruptable) {
|
||||
int lot = SDL_rand(random_states.size());
|
||||
setState(random_states[lot]);
|
||||
}
|
||||
}
|
||||
|
||||
void Animal::setState(State *s) {
|
||||
cur_state = s;
|
||||
cur_state->sound_data.is_played = false;
|
||||
animate(true);
|
||||
state_changed = true;
|
||||
}
|
||||
|
||||
void Animal::setSpecialState(SpecialState s) {
|
||||
//SDL_Log("special_state %d", s);
|
||||
cur_state = special_states[s];
|
||||
//SDL_Log("cur_state %x", cur_state);
|
||||
cur_state->sound_data.is_played = false;
|
||||
animate(true);
|
||||
state_changed = true;
|
||||
}
|
||||
|
||||
void Animal::resetTimes(Uint64 t) {
|
||||
move_time = random_time = t;
|
||||
}
|
||||
|
||||
Uint64 Animal::step(Uint64 cur, bool press) {
|
||||
if (!press && cur >= move_time) {
|
||||
move();
|
||||
move_time += 25;
|
||||
}
|
||||
|
||||
if (cur >= animate_time) {
|
||||
animate(false);
|
||||
animate_time += cur_state->interval;
|
||||
}
|
||||
|
||||
if (!press && cur >= random_time) {
|
||||
shuffle();
|
||||
random_time += 1000 * 5;
|
||||
}
|
||||
|
||||
Uint64 lowest_time = move_time;
|
||||
if (lowest_time > animate_time) lowest_time = animate_time;
|
||||
if (lowest_time > random_time) lowest_time = random_time;
|
||||
|
||||
if (lowest_time < cur) {
|
||||
lowest_time = cur;
|
||||
}
|
||||
|
||||
return lowest_time - cur;
|
||||
}
|
||||
|
||||
SDL_Surface *Animal::getImage() {
|
||||
return cur_state->imgs[animation_i];
|
||||
}
|
||||
|
||||
SoundData *Animal::getSound() {
|
||||
return &cur_state->sound_data;
|
||||
}
|
||||
|
||||
bool Animal::hasStateChanged() {
|
||||
if (state_changed) {
|
||||
state_changed = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Animal::shouldRunAway(char dir) {
|
||||
// Check if we are in a cur_state where we can't do anything
|
||||
if (cur_state->interruptable) {
|
||||
if (dir == 1) {
|
||||
if (cur_state->special != fast_right) {
|
||||
setSpecialState(fast_right);
|
||||
}
|
||||
} else {
|
||||
if (cur_state->special != fast_left) {
|
||||
setSpecialState(fast_left);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Surface *Animal::getPreviewSurface() {
|
||||
if (special_states[stay]->imgs.size()) {
|
||||
return special_states[stay]->imgs[0];
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user