/*
* item.c -- Implementa los objetos (y enemigos) que aparecen en el juego.
* Copyright (C) 2018 Juan MarĂn Noguera
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (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
* along with this program. If not, see .
*/
#include
#include
#include "block.h"
#include "collision_type.h"
#include "error.h"
#include "item.h"
#include "player.h"
#include "screen.h"
#define ITEM_GRAVITY 0.15
#define ITEM_VELOCITY_X 1.2
#define ITEM_KOOPA_MAX_STILL 300
#define ITEM_TEMPCOIN_LIFETIME 5
#define ITEM_ANIM_TICKS 3
#define ITEM_ANIM_X_SHIFT 16
#define ITEM_GOOMBA_ANIM_NO 2
#define ITEM_KOOPA_ANIM_NO 4
#define ITEM_FLOWER_ANIM_NO 4
#define ITEM_GOOMBA_X 0
#define ITEM_GOOMBA_Y 16
#define ITEM_GOOMBA_W 16
#define ITEM_GOOMBA_H 16
#define ITEM_KOOPA_GROUND_X 160
#define ITEM_KOOPA_GROUND_Y 24
#define ITEM_KOOPA_GROUND_W 16
#define ITEM_KOOPA_GROUND_H 8
#define ITEM_KOOPA_X 96
#define ITEM_KOOPA_Y 10
#define ITEM_KOOPA_W 15
#define ITEM_KOOPA_H 22
#define ITEM_MUSHROOM_X 0
#define ITEM_MUSHROOM_Y 0
#define ITEM_FLOWER_X 0
#define ITEM_FLOWER_Y 32
#define ITEM_COIN_X 0
#define ITEM_COIN_Y 96
#define ITEM_UPGRADE_W 16
#define ITEM_UPGRADE_H 16
#define ITEM_ENEMIES_FILE "52570.bmp"
#define ITEM_UPGRADES_FILE "52569.bmp"
struct Item {
ItemType type;
int dir;
int cnt;
double x;
double y;
double vy;
};
Picture item_enemies_pict = NULL, item_upgrades_pict = NULL;
Item item_create(ItemType type, double x, double y)
{
Item i = malloc(sizeof(struct Item));
if (i == NULL)
error_libc_exit();
i->type = type;
i->x = x;
i->y = y;
i->vy = 0;
if (type == ITEM_TYPE_GOOMBA || type == ITEM_TYPE_KOOPA)
i->dir = -1;
else if (type == ITEM_TYPE_MUSHROOM)
i->dir = 2 * (rand() % 1) - 1;
else
i->dir = 0;
i->cnt = 0;
return i;
}
void item_free(Item i)
{
if (i == NULL)
error_exit(ERR_NULL_PARAM);
free(i);
}
void item_end()
{
if (item_enemies_pict != NULL)
screen_free_picture(item_enemies_pict);
if (item_upgrades_pict != NULL)
screen_free_picture(item_upgrades_pict);
}
double item_x(Item i)
{
return i->x;
}
double item_y(Item i)
{
return i->y;
}
double item_vx(Item i)
{
return i->dir * ITEM_VELOCITY_X;
}
double item_vy(Item i)
{
return i->vy;
}
int item_height(Item i)
{
switch (i->type) {
case ITEM_TYPE_GOOMBA:
return ITEM_GOOMBA_H;
case ITEM_TYPE_KOOPA:
return i->dir == 0 ? ITEM_KOOPA_GROUND_H : ITEM_KOOPA_H;
default:
return ITEM_UPGRADE_H;
}
}
int item_width(Item i)
{
switch (i->type) {
case ITEM_TYPE_GOOMBA:
return ITEM_GOOMBA_W;
case ITEM_TYPE_KOOPA:
return i->dir == 0 ? ITEM_KOOPA_GROUND_W : ITEM_KOOPA_W;
default:
return ITEM_UPGRADE_W;
}
}
int item_update(Item i)
{
i->vy -= ITEM_GRAVITY;
i->y += i->vy;
i->x += i->dir * ITEM_VELOCITY_X;
i->cnt++;
if (i->type == ITEM_TYPE_KOOPA && i->dir == 0 &&
i->cnt >= ITEM_KOOPA_MAX_STILL) {
i->cnt = 0;
i->dir = 1;
}
return i->type == ITEM_TYPE_TEMPCOIN && i->cnt > ITEM_TEMPCOIN_LIFETIME;
}
void item_correct_on_block_collision(Item i, CollisionType dir)
{
if (dir & COLLISION_TOP) {
i->vy = 0;
i->y = i->y - 2 * (((int)i->y) % BLOCK_SIZE);
}
if (dir & COLLISION_BOTTOM) {
i->vy = 0;
i->y = ((int)(i->y + BLOCK_SIZE) / BLOCK_SIZE) * BLOCK_SIZE;
}
if (dir & COLLISION_LEFT) {
i->x = (((int)(i->x + BLOCK_SIZE)) / BLOCK_SIZE) * BLOCK_SIZE;
if (i->dir != 0)
i->dir = 1;
}
if (dir & COLLISION_RIGHT) {
i->x = (((int)i->x) / BLOCK_SIZE) * BLOCK_SIZE;
if (i->dir != 0)
i->dir = -1;
}
}
int item_player_collide(Item i, Player p, CollisionType dir)
{
switch (i->type) {
case ITEM_TYPE_GOOMBA:
if (dir & COLLISION_BOTTOM) {
return 1;
} else {
if (player_vulnerable(p))
player_downgrade(p);
return 0;
}
case ITEM_TYPE_KOOPA:
if (dir & COLLISION_BOTTOM && i->dir == 0) {
return 1;
} else if (dir & COLLISION_BOTTOM) {
i->dir = 0;
i->cnt = 0;
return 0;
} else {
if (player_vulnerable(p))
player_downgrade(p);
return 0;
}
case ITEM_TYPE_MUSHROOM:
player_upgrade_to(p, PLAYER_ST_BIG);
return 1;
case ITEM_TYPE_FLOWER:
player_upgrade_to(p, PLAYER_ST_FLOWER);
return 1;
case ITEM_TYPE_COIN:
player_add_coin(p);
return 1;
case ITEM_TYPE_TEMPCOIN:
return 0;
default:
error_exit(ERR_OUT_OF_RANGE);
return 0; // Execution will never reach this point.
}
}
void item_render(Screen scr, Item i, int scroll)
{
Picture pict;
int x, y, w = item_width(i), h = item_height(i);
if (item_enemies_pict == NULL)
item_enemies_pict = screen_get_picture(ITEM_ENEMIES_FILE);
if (item_upgrades_pict == NULL)
item_upgrades_pict = screen_get_picture(ITEM_UPGRADES_FILE);
switch (i->type) {
case ITEM_TYPE_GOOMBA:
pict = item_enemies_pict;
x = ITEM_GOOMBA_X +
((i->cnt / ITEM_ANIM_TICKS) % ITEM_GOOMBA_ANIM_NO)
* ITEM_ANIM_X_SHIFT;
y = ITEM_GOOMBA_Y;
break;
case ITEM_TYPE_KOOPA:
pict = item_enemies_pict;
if (i->dir == 0) {
x = ITEM_KOOPA_GROUND_X;
y = ITEM_KOOPA_GROUND_Y;
} else {
x = ITEM_KOOPA_X +
((i->cnt / ITEM_ANIM_TICKS) %
ITEM_KOOPA_ANIM_NO)
* ITEM_ANIM_X_SHIFT;
y = ITEM_KOOPA_Y;
}
break;
case ITEM_TYPE_MUSHROOM:
pict = item_upgrades_pict;
x = ITEM_MUSHROOM_X;
y = ITEM_MUSHROOM_Y;
break;
case ITEM_TYPE_FLOWER:
pict = item_upgrades_pict;
x = ITEM_FLOWER_X +
((i->cnt / ITEM_ANIM_TICKS) % ITEM_FLOWER_ANIM_NO)
* ITEM_ANIM_X_SHIFT;
y = ITEM_FLOWER_Y;
break;
case ITEM_TYPE_COIN:
case ITEM_TYPE_TEMPCOIN:
pict = item_upgrades_pict;
x = ITEM_COIN_X;
y = ITEM_COIN_Y;
break;
default:
error_exit(ERR_OUT_OF_RANGE);
return; // Execution will never reach this point
}
screen_place(
scr,
pict,
i->x - scroll,
screen_height(scr) - i->y - h,
x,
y,
w,
h,
i->dir == 1);
}