From: Tobias Gläßer Date: Sun, 18 Jan 2004 02:30:12 +0000 (+0000) Subject: Huge code merge. This reflects the current status of my rewrite/restructuring. A... X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=2f395aba3974db45f45a8587ed423a3abeab4cd5;p=supertux.git Huge code merge. This reflects the current status of my rewrite/restructuring. A few new FIXMEs come along with this. :) SVN-Revision: 93 --- diff --git a/src/badguy.c b/src/badguy.c new file mode 100644 index 000000000..aec60cc5e --- /dev/null +++ b/src/badguy.c @@ -0,0 +1,566 @@ +// +// C Implementation: badguy +// +// Description: +// +// +// Author: Tobias Glaesser , (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include "globals.h" +#include "defines.h" +#include "badguy.h" +#include "scene.h" +#include "screen.h" + +void badguy_create_bitmasks() +{ + /*bm_bsod = img_bsod_left[0];*/ +} + +void badguy_init(bad_guy_type* pbad) +{ + pbad->it.alive = &pbad->alive; + pbad->it.x = &pbad->x; + pbad->it.y = &pbad->y; + pbad->it.width = &pbad->width; + pbad->it.height = &pbad->height; + pbad->it.updated = &pbad->updated; + + pbad->updated = SDL_GetTicks(); + pbad->alive = NO; + + + pbad->width = 32; + pbad->height = 32; + +} + +void badguy_action(bad_guy_type* pbad) +{ + + double frame_ratio = get_frame_ratio(&pbad->it); + + if (pbad->alive) + { + if (pbad->seen) + { + if (pbad->kind == BAD_BSOD) + { + /* --- BLUE SCREEN OF DEATH MONSTER: --- */ + + /* Move left/right: */ + + if (pbad->dying == NO || + pbad->dying == FALLING) + { + if (pbad->dir == RIGHT) + pbad->x = pbad->x + pbad->xm * frame_ratio; + else if (pbad->dir == LEFT) + pbad->x = pbad->x - pbad->xm * frame_ratio; + } + + + /* Move vertically: */ + + pbad->y = pbad->y + pbad->ym * frame_ratio; + + + /* Bump into things horizontally: */ + + if (!pbad->dying) + { + if (issolid(pbad->x, pbad->y)) + pbad->dir = !pbad->dir; + } + + /* Fall if we get off the ground: */ + + if (pbad->dying != FALLING) + { + if (!issolid(pbad->x, pbad->y + 32) && + pbad->ym < MAX_YM) + { + pbad->ym = pbad->ym + GRAVITY; + } + else + { + /* Land: */ + + if (pbad->ym > 0) + { + pbad->y = (int)(pbad->y / 32) * 32; + pbad->ym = 0; + } + } + } + else + pbad->ym = pbad->ym + GRAVITY; + + if (pbad->y > screen->h) + pbad->alive = NO; + } + else if (pbad->kind == BAD_LAPTOP) + { + /* --- LAPTOP MONSTER: --- */ + + /* Move left/right: */ + + if (pbad->mode != KICK && pbad->mode != HELD) + { + if (pbad->dying == NO || + pbad->dying == FALLING) + { + if (pbad->dir == RIGHT) + pbad->x = pbad->x + pbad->xm * frame_ratio; + else if (pbad->dir == LEFT) + pbad->x = pbad->x - pbad->xm * frame_ratio; + } + } + else if (pbad->mode == KICK) + { + /* Obsolete + if (pbad->dir == RIGHT) + pbad->x = pbad->x + 16; + else if (pbad->dir == LEFT) + pbad->x = pbad->x - 16;*/ + } + else if (pbad->mode == HELD) + { /* FIXME: The pbad object shouldn't know about pplayer objects. */ + /* If we're holding the laptop */ + if(tux.dir==RIGHT) + { + pbad->x = tux.x - 16; + pbad->y = tux.y - 8 - (tux.size*16); + } + else /* facing left */ + { + pbad->x = tux.x - 16; + pbad->y = tux.y - 8 - (tux.size*16); + } + + if(tux.input.fire != DOWN) /* SHOOT! */ + { + pbad->dir=tux.dir; + pbad->mode=KICK; + pbad->ym-=8; + play_sound(sounds[SND_KICK],SOUND_CENTER_SPEAKER); + } + } + + + /* Move vertically: */ + + if(pbad->mode != HELD) + pbad->y = pbad->y + pbad->ym * frame_ratio; + + /* Bump into things horizontally: */ + + if (!pbad->dying) + { + if (issolid(pbad->x, pbad->y)) + { + pbad->dir = !pbad->dir; + + if (pbad->mode == KICK) + { + /* handle stereo sound */ + /* FIXME: In theory a badguy object doesn't know anything about player objects */ + if (tux.x > pbad->x) + play_sound(sounds[SND_RICOCHET], SOUND_LEFT_SPEAKER); + else if (tux.x < pbad->x) + play_sound(sounds[SND_RICOCHET], SOUND_RIGHT_SPEAKER); + else + play_sound(sounds[SND_RICOCHET], SOUND_CENTER_SPEAKER); + } + } + } + + + /* Fall if we get off the ground: */ + + if (pbad->dying != FALLING) + { + if (!issolid(pbad->x, pbad->y + 32) && + pbad->ym < MAX_YM) + { + if(pbad->mode != HELD) + pbad->ym = pbad->ym + GRAVITY; + } + else + { + /* Land: */ + + if (pbad->ym > 0) + { + pbad->y = (int)(pbad->y / 32) * 32; + pbad->ym = 0; + } + } + } + else + pbad->ym = pbad->ym + GRAVITY; + + if (pbad->y > screen->h) + pbad->alive = NO; + } + else if (pbad->kind == BAD_MONEY) + { + /* --- MONEY BAGS: --- */ + + + /* Move vertically: */ + + pbad->y = pbad->y + pbad->ym *frame_ratio; + + + /* Fall if we get off the ground: */ + + if (pbad->dying != FALLING) + { + if (!issolid(pbad->x, pbad->y + 32)) + { + if (pbad->ym < MAX_YM) + { + pbad->ym = pbad->ym + GRAVITY; + } + } + else + { + /* Land: */ + + if (pbad->ym > 0) + { + pbad->y = (int)(pbad->y / 32) * 32; + pbad->ym = -MAX_YM; + } + } + } + else + pbad->ym = pbad->ym + GRAVITY; + + if (pbad->y > screen->h) + pbad->alive = NO; + } + else if (pbad->kind == -1) + {} + + } + else if (pbad->kind == -1) + {} + + + } + + /* Handle mode timer: */ + + if (pbad->mode == FLAT /* && bad_guys[1].mode != HELD*/) + { + if(!timer_check(&pbad->timer)) + pbad->mode = NORMAL; + } + /* else if (pbad->mode == KICK) + { + if (pbad->timer > 0) + pbad->timer--; + }*/ + + + /* Handle dying timer: */ + + if (pbad->dying == SQUISHED) + { + /* Remove it if time's up: */ + if(!timer_check(&pbad->timer)) + pbad->alive = NO; + } + + + /* Remove if it's far off the screen: */ + + if (pbad->x < scroll_x - OFFSCREEN_DISTANCE) + pbad->alive = NO; + else /* !seen */ + { + /* Once it's on screen, it's activated! */ + + if (pbad->x <= scroll_x + screen->w + OFFSCREEN_DISTANCE) + pbad->seen = YES; + } + /*}*/ +} + +void badguy_draw(bad_guy_type* pbad) +{ + if (pbad->alive && + pbad->x > scroll_x - 32 && + pbad->x < scroll_x + screen->w) + { + if (pbad->kind == BAD_BSOD) + { + /* --- BLUE SCREEN OF DEATH MONSTER: --- */ + + if (pbad->dying == NO) + { + /* Alive: */ + + if (pbad->dir == LEFT) + { + texture_draw(&img_bsod_left[(frame / 5) % 4], + pbad->x - scroll_x, + pbad->y, + NO_UPDATE); + } + else + { + texture_draw(&img_bsod_right[(frame / 5) % 4], + pbad->x - scroll_x, + pbad->y, + NO_UPDATE); + } + } + else if (pbad->dying == FALLING) + { + /* Falling: */ + + if (pbad->dir == LEFT) + { + texture_draw(&img_bsod_falling_left, + pbad->x - scroll_x, + pbad->y, + NO_UPDATE); + } + else + { + texture_draw(&img_bsod_falling_right, + pbad->x - scroll_x, + pbad->y, + NO_UPDATE); + } + } + else if (pbad->dying == SQUISHED) + { + /* Dying - Squished: */ + + if (pbad->dir == LEFT) + { + texture_draw(&img_bsod_squished_left, + pbad->x - scroll_x, + pbad->y + 24, + NO_UPDATE); + } + else + { + texture_draw(&img_bsod_squished_right, + pbad->x - scroll_x, + pbad->y + 24, + NO_UPDATE); + } + } + } + else if (pbad->kind == BAD_LAPTOP) + { + /* --- LAPTOP MONSTER: --- */ + + if (pbad->dying == NO) + { + /* Alive: */ + + if (pbad->mode == NORMAL) + { + /* Not flat: */ + + if (pbad->dir == LEFT) + { + texture_draw(&img_laptop_left[(frame / 5) % 3], + pbad->x - scroll_x, + pbad->y, + NO_UPDATE); + } + else + { + texture_draw(&img_laptop_right[(frame / 5) % 3], + pbad->x - scroll_x, + pbad->y, + NO_UPDATE); + } + } + else + { + /* Flat: */ + + if (pbad->dir == LEFT) + { + texture_draw(&img_laptop_flat_left, + pbad->x - scroll_x, + pbad->y, + NO_UPDATE); + } + else + { + texture_draw(&img_laptop_flat_right, + pbad->x - scroll_x, + pbad->y, + NO_UPDATE); + } + } + } + else if (pbad->dying == FALLING) + { + /* Falling: */ + + if (pbad->dir == LEFT) + { + texture_draw(&img_laptop_falling_left, + pbad->x - scroll_x, + pbad->y, + NO_UPDATE); + } + else + { + texture_draw(&img_laptop_falling_right, + pbad->x - scroll_x, + pbad->y, + NO_UPDATE); + } + } + } + else if (pbad->kind == BAD_MONEY) + { + if (pbad->ym > -16) + { + if (pbad->dir == LEFT) + { + texture_draw(&img_money_left[0], + pbad->x - scroll_x, + pbad->y, + NO_UPDATE); + } + else + { + texture_draw(&img_money_right[0], + pbad->x - scroll_x, + pbad->y, + NO_UPDATE); + } + } + else + { + if (pbad->dir == LEFT) + { + texture_draw(&img_money_left[1], + pbad->x - scroll_x, + pbad->y, + NO_UPDATE); + } + else + { + texture_draw(&img_money_right[1], + pbad->x - scroll_x, + pbad->y, + NO_UPDATE); + } + } + } + else if (pbad->kind == -1) + {} + } +} + +void badguy_collision(bad_guy_type* pbad, void *p_c_object, int c_object) +{ + bad_guy_type* pbad_c = NULL; + player_type* pplayer_c = NULL; + + switch (c_object) + { + case CO_BULLET: + pbad->dying = FALLING; + pbad->ym = -8; + + /* Gain some points: */ + + if (pbad->kind == BAD_BSOD) + add_score(pbad->x - scroll_x, pbad->y, + 50 * score_multiplier); + else if (pbad->kind == BAD_LAPTOP) + add_score(pbad->x - scroll_x, pbad->y, + 25 * score_multiplier); + + /* Play death sound: */ + play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER); + break; + case CO_BADGUY: + pbad_c = p_c_object; + if (pbad->mode != KICK) + pbad->dir = !pbad->dir; + else + { + /* We're in kick mode, kill the other guy: */ + + pbad_c->dying = FALLING; + pbad_c->ym = -8; + play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER); + + add_score(pbad->x - scroll_x, + pbad->y, 100); + } + pbad->dir = !pbad->dir; + break; + case CO_PLAYER: + pplayer_c = p_c_object; + if (pbad->kind == BAD_BSOD) + { + pbad->dying = SQUISHED; + timer_start(&pbad->timer,4000); + pplayer_c->ym = -KILL_BOUNCE_YM; + + add_score(pbad->x - scroll_x, pbad->y, + 50 * score_multiplier); + + play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER); + } + else if (pbad->kind == BAD_LAPTOP) + { + if (pbad->mode != FLAT) + { + /* Flatten! */ + + play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER); + pbad->mode = FLAT; + pbad->xm = 4; + + timer_start(&pbad->timer,10000); + + pplayer_c->y = pplayer_c->y - 32; + } + else + { + /* Kick! */ + + pbad->mode = KICK; + play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER); + + if (pplayer_c->x <= pbad->x) + pbad->dir = RIGHT; + else + pbad->dir = LEFT; + + timer_start(&pbad->timer,5000); + } + + pplayer_c->ym = -KILL_BOUNCE_YM; + + add_score(pbad->x - scroll_x, + pbad->y, + 25 * score_multiplier); + + /* play_sound(sounds[SND_SQUISH]); */ + } + break; + } + +} diff --git a/src/badguy.h b/src/badguy.h index a064b48fb..5f357cca9 100644 --- a/src/badguy.h +++ b/src/badguy.h @@ -1,5 +1,5 @@ // -// Interface: enemy +// Interface: badguy // // Description: // @@ -10,21 +10,71 @@ // // +#ifndef SUPERTUX_BADGUY_H +#define SUPERTUX_BADGUY_H -/* Types: */ +#include "SDL.h" +#include "bitmask.h" +#include "type.h" +#include "collision.h" + +#define NUM_BAD_GUYS 128 + +/* Enemy modes: */ + +#define NORMAL 0 +#define FLAT 1 +#define KICK 2 +#define HELD 3 + +/* Badguy type: */ typedef struct bad_guy_type { int alive; int mode; int dying; - int timer; int kind; int seen; int dir; - int x; - int y; - int xm; - int ym; + int frame; + float x; + float y; + float xm; + float ym; + float width; + float height; + unsigned int updated; + itop_type it; + timer_type timer; } bad_guy_type; + +/* Bad guy kinds: */ + +enum { + BAD_BSOD, + BAD_LAPTOP, + BAD_MONEY +}; + +texture_type img_bsod_squished_left, img_bsod_squished_right, +img_bsod_falling_left, img_bsod_falling_right, +img_laptop_flat_left, img_laptop_flat_right, +img_laptop_falling_left, img_laptop_falling_right; +texture_type img_bsod_left[4], img_bsod_right[4], +img_laptop_left[3], img_laptop_right[3], +img_money_left[2], img_money_right[2]; + +bitmask *bm_bsod; + +void badguy_create_bitmasks(); + +void badguy_init(bad_guy_type* pbad); +void badguy_action(bad_guy_type* pbad); +void badguy_draw(bad_guy_type* pbad); +void badguy_collision(bad_guy_type* pbad, void* p_c_object, int c_object); + +#endif /*SUPERTUX_BADGUY_H*/ + + diff --git a/src/bitmask.c b/src/bitmask.c new file mode 100644 index 000000000..b3be49955 --- /dev/null +++ b/src/bitmask.c @@ -0,0 +1,553 @@ +/* + * bitmask.c 1.0 + * ------------- + * Simple and efficient bitmask collision detection routines + * Copyright (C) 2002 Ulf Ekstrom except for the bitcount function. + * + * > See the header file for more info. < + * + * Please email bugs and comments to Ulf Ekstrom, ulfek@ifm.liu.se + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include "bitmask.h" + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +bitmask *bitmask_create(int w, int h) +{ + bitmask *temp = malloc(sizeof(bitmask)); + if (! temp) + return 0; + temp->w = w; + temp->h = h; + temp->bits = calloc(h*((w - 1)/BITW_LEN + 1),sizeof(BITW)); + if (! temp->bits) + { + free(temp); + return 0; + } + else + return temp; +} + +bitmask *bitmask_create_SDL(SDL_Surface* surf) +{ + int w,h; + int bpp; + Uint8* p; + + bitmask *temp = malloc(sizeof(bitmask)); + if (! temp) + return 0; + temp->w = surf->w; + temp->h = surf->h; + temp->bits = calloc(surf->h*((surf->w - 1)/BITW_LEN + 1),sizeof(BITW)); + if (! temp->bits) + { + free(temp); + return 0; + } + else + return temp; + + bpp = surf->format->BytesPerPixel; + for(h = 0; h <= surf->h; ++h) + { + for(w = 0; w <= surf->h; ++w) + { + + p = (Uint8 *)surf->pixels + h*surf->pitch + w*bpp; + if(*p == 255) + bitmask_setbit(temp,w,h); + } + } + +} + +void bitmask_free(bitmask *m) +{ + free(m->bits); + free(m); +} + +int bitmask_overlap(const bitmask *a,const bitmask *b,int xoffset, int yoffset) +{ + BITW *a_entry,*a_end; + BITW *b_entry; + BITW *ap,*bp; + int shift,rshift,i,astripes,bstripes; + + if ((xoffset >= a->w) || (yoffset >= a->h) || (yoffset <= - b->h)) + return 0; + + if (xoffset >= 0) + { + if (yoffset >= 0) + { + a_entry = a->bits + a->h*(xoffset/BITW_LEN) + yoffset; + a_end = a_entry + MIN(b->h,a->h - yoffset); + b_entry = b->bits; + } + else + { + a_entry = a->bits + a->h*(xoffset/BITW_LEN); + a_end = a_entry + MIN(b->h + yoffset,a->h); + b_entry = b->bits - yoffset; + } + shift = xoffset & BITW_MASK; + if (shift) + { + rshift = BITW_LEN - shift; + astripes = (a->w - 1)/BITW_LEN - xoffset/BITW_LEN; + bstripes = (b->w - 1)/BITW_LEN + 1; + if (bstripes > astripes) /* zig-zag .. zig*/ + { + for (i=0;i> shift) & *bp++) + return 1; + a_entry += a->h; + a_end += a->h; + for (ap = a_entry,bp = b_entry;ap < a_end;) + if ((*ap++ << rshift) & *bp++) + return 1; + b_entry += b->h; + } + for (ap = a_entry,bp = b_entry;ap < a_end;) + if ((*ap++ >> shift) & *bp++) + return 1; + return 0; + } + else /* zig-zag */ + { + for (i=0;i> shift) & *bp++) + return 1; + a_entry += a->h; + a_end += a->h; + for (ap = a_entry,bp = b_entry;ap < a_end;) + if ((*ap++ << rshift) & *bp++) + return 1; + b_entry += b->h; + } + return 0; + } + } + else /* xoffset is a multiple of the stripe width, and the above routines wont work */ + { + astripes = (MIN(b->w,a->w - xoffset) - 1)/BITW_LEN + 1; + for (i=0;ih; + a_end += a->h; + b_entry += b->h; + } + return 0; + } + } + else + return bitmask_overlap(b,a,-xoffset,-yoffset); +} + +/* Will hang if there are no bits set in w! */ +static INLINE int firstsetbit(BITW w) +{ + int i = 0; + while ((w & 1) == 0) + { + i++; + w/=2; + } + return i; +} + +/* x and y are given in the coordinates of mask a, and are untouched if the is no overlap */ +int bitmask_overlap_pos(const bitmask *a,const bitmask *b,int xoffset, int yoffset, int *x, int *y) +{ + BITW *a_entry,*a_end; + BITW *b_entry; + BITW *ap,*bp; + int shift,rshift,i,astripes,bstripes; + + if ((xoffset >= a->w) || (yoffset >= a->h) || (yoffset <= - b->h)) + return 0; + + if (xoffset >= 0) + { + if (yoffset >= 0) + { + a_entry = a->bits + a->h*(xoffset/BITW_LEN) + yoffset; + a_end = a_entry + MIN(b->h,a->h - yoffset); + b_entry = b->bits; + } + else + { + a_entry = a->bits + a->h*(xoffset/BITW_LEN); + a_end = a_entry + MIN(b->h + yoffset,a->h); + b_entry = b->bits - yoffset; + } + shift = xoffset & BITW_MASK; + if (shift) + { + rshift = BITW_LEN - shift; + astripes = (a->w - 1)/BITW_LEN - xoffset/BITW_LEN; + bstripes = (b->w - 1)/BITW_LEN + 1; + if (bstripes > astripes) /* zig-zag .. zig*/ + { + for (i=0;ibits) % a->h; + *x = ((ap - a->bits) / a->h)*BITW_LEN + firstsetbit(*ap & (*bp << shift)); + return 1; + } + a_entry += a->h; + a_end += a->h; + for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++) + if (*ap & (*bp >> rshift)) + { + *y = (ap - a->bits) % a->h; + *x = ((ap - a->bits) / a->h)*BITW_LEN + firstsetbit(*ap & (*bp >> rshift)); + return 1; + } + b_entry += b->h; + } + for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++) + if (*ap & (*bp << shift)) + { + *y = (ap - a->bits) % a->h; + *x = ((ap - a->bits) / a->h)*BITW_LEN + firstsetbit(*ap & (*bp << shift)); + return 1; + } + return 0; + } + else /* zig-zag */ + { + for (i=0;ibits) % a->h; + *x = ((ap - a->bits) / a->h)*BITW_LEN + firstsetbit(*ap & (*bp << shift)); + return 1; + } + a_entry += a->h; + a_end += a->h; + for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++) + if (*ap & (*bp >> rshift)) + { + *y = (ap - a->bits) % a->h; + *x = ((ap - a->bits) / a->h)*BITW_LEN + firstsetbit(*ap & (*bp >> rshift)); + return 1; + } + b_entry += b->h; + } + return 0; + } + } + else /* xoffset is a multiple of the stripe width, and the above routines won't work. */ + { + astripes = (MIN(b->w,a->w - xoffset) - 1)/BITW_LEN + 1; + for (i=0;ibits) % a->h; + *x = ((ap - a->bits) / a->h)*BITW_LEN + firstsetbit(*ap & *bp); + return 1; + } + } + a_entry += a->h; + a_end += a->h; + b_entry += b->h; + } + return 0; + } + } + else + { + if (bitmask_overlap_pos(b,a,-xoffset,-yoffset,x,y)) + { + *x += xoffset; + *y += yoffset; + return 1; + } + else + return 0; + } +} + + + +/* (C) Donald W. Gillies, 1992. All rights reserved. You may reuse + this bitcount() function anywhere you please as long as you retain + this Copyright Notice. */ +static INLINE int bitcount(unsigned long n) +{ + register unsigned long tmp; + return (tmp = (n) - (((n) >> 1) & 033333333333) - (((n) >> 2) & 011111111111),\ + tmp = ((tmp + (tmp >> 3)) & 030707070707), \ + tmp = (tmp + (tmp >> 6)), \ + tmp = (tmp + (tmp >> 12) + (tmp >> 24)) & 077); +} +/* End of Donald W. Gillies bitcount code */ + + +int bitmask_overlap_area(const bitmask *a,const bitmask *b,int xoffset, int yoffset) +{ + BITW *a_entry,*a_end; + BITW *b_entry; + BITW *ap,*bp; + int shift,rshift,i,astripes,bstripes; + int count = 0; + + if ((xoffset >= a->w) || (yoffset >= a->h) || (yoffset <= - b->h)) + return 0; + + if (xoffset >= 0) + { + if (yoffset >= 0) + { + a_entry = a->bits + a->h*(xoffset/BITW_LEN) + yoffset; + a_end = a_entry + MIN(b->h,a->h - yoffset); + b_entry = b->bits; + } + else + { + a_entry = a->bits + a->h*(xoffset/BITW_LEN); + a_end = a_entry + MIN(b->h + yoffset,a->h); + b_entry = b->bits - yoffset; + } + shift = xoffset & BITW_MASK; + if (shift) + { + rshift = BITW_LEN - shift; + astripes = (a->w - 1)/BITW_LEN - xoffset/BITW_LEN; + bstripes = (b->w - 1)/BITW_LEN + 1; + if (bstripes > astripes) /* zig-zag .. zig*/ + { + for (i=0;i> shift) | (*(ap + a->h) << rshift)) & *bp); + a_entry += a->h; + a_end += a->h; + b_entry += b->h; + } + for (ap = a_entry,bp = b_entry;ap < a_end;) + count += bitcount((*ap++ >> shift) & *bp++); + return count; + } + else /* zig-zag */ + { + for (i=0;i> shift) | (*(ap + a->h) << rshift)) & *bp); + a_entry += a->h; + a_end += a->h; + b_entry += b->h; + } + return count; + } + } + else /* xoffset is a multiple of the stripe width, and the above routines wont work */ + { + astripes = (MIN(b->w,a->w - xoffset) - 1)/BITW_LEN + 1; + for (i=0;ih; + a_end += a->h; + b_entry += b->h; + } + return count; + } + } + else + return bitmask_overlap_area(b,a,-xoffset,-yoffset); +} + + +/* Draws mask b onto mask a (bitwise OR) */ +void bitmask_draw(bitmask *a,bitmask *b,int xoffset, int yoffset) +{ + BITW *a_entry,*a_end; + BITW *b_entry; + BITW *ap,*bp; + bitmask *swap; + int shift,rshift,i,astripes,bstripes; + + if ((xoffset >= a->w) || (yoffset >= a->h) || (yoffset <= - b->h)) + return; + + if (xoffset >= 0) + { + if (yoffset >= 0) + { + a_entry = a->bits + a->h*(xoffset/BITW_LEN) + yoffset; + a_end = a_entry + MIN(b->h,a->h - yoffset); + b_entry = b->bits; + } + else + { + a_entry = a->bits + a->h*(xoffset/BITW_LEN); + a_end = a_entry + MIN(b->h + yoffset,a->h); + b_entry = b->bits - yoffset; + } + shift = xoffset & BITW_MASK; + if (shift) + { + rshift = BITW_LEN - shift; + astripes = (a->w - 1)/BITW_LEN - xoffset/BITW_LEN; + bstripes = (b->w - 1)/BITW_LEN + 1; + if (bstripes > astripes) /* zig-zag .. zig*/ + { + for (i=0;ih; + a_end += a->h; + for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++) + *ap |= (*bp >> rshift); + b_entry += b->h; + } + for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++) + *ap |= (*bp << shift); + return; + } + else /* zig-zag */ + { + for (i=0;ih; + a_end += a->h; + for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++) + *ap |= (*bp >> rshift); + b_entry += b->h; + } + return; + } + } + else /* xoffset is a multiple of the stripe width, and the above routines won't work. */ + { + astripes = (MIN(b->w,a->w - xoffset) - 1)/BITW_LEN + 1; + for (i=0;ih; + a_end += a->h; + b_entry += b->h; + } + return; + } + } + else + { + /* 'Swapping' arguments to be able to almost reuse the code above */ + swap = a; + a = b; + b = swap; + xoffset *= -1; + yoffset *= -1; + + if (yoffset >= 0) + { + a_entry = a->bits + a->h*(xoffset/BITW_LEN) + yoffset; + a_end = a_entry + MIN(b->h,a->h - yoffset); + b_entry = b->bits; + } + else + { + a_entry = a->bits + a->h*(xoffset/BITW_LEN); + a_end = a_entry + MIN(b->h + yoffset,a->h); + b_entry = b->bits - yoffset; + } + shift = xoffset & BITW_MASK; + if (shift) + { + rshift = BITW_LEN - shift; + astripes = (a->w - 1)/BITW_LEN - xoffset/BITW_LEN; + bstripes = (b->w - 1)/BITW_LEN + 1; + if (bstripes > astripes) /* zig-zag .. zig*/ + { + for (i=0;i> shift); + a_entry += a->h; + a_end += a->h; + for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++) + *bp |= (*ap <h; + } + for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++) + *bp |= (*ap >> shift); + return; + } + else /* zig-zag */ + { + for (i=0;i> shift); + a_entry += a->h; + a_end += a->h; + for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++) + *bp |= (*ap << rshift); + b_entry += b->h; + } + return; + } + } + else /* xoffset is a multiple of the stripe width, and the above routines won't work. */ + { + astripes = (MIN(b->w,a->w - xoffset) - 1)/BITW_LEN + 1; + for (i=0;ih; + a_end += a->h; + b_entry += b->h; + } + return; + } + } +} diff --git a/src/bitmask.h b/src/bitmask.h new file mode 100644 index 000000000..932f8c4a5 --- /dev/null +++ b/src/bitmask.h @@ -0,0 +1,143 @@ +/* + * bitmask.c 1.0 + * ------------- + * Simple and efficient bitmask collision detection routines + * Copyright (C) 2002 Ulf Ekstrom except for the bitcount function. + * + * A bitmask is a simple array of bits, which can be used for + * 2d collision detection. Set 'unoccupied' area to zero and + * occupies areas to one and use the bitmask_overlap*() functions + * to check for collisions. + * The current implementation uses 32 bit wide stripes to hold + * the masks, but should work just as well with 64 bit sizes. + * (Note that the current bitcount function is 32 bit only!) + * + * The overlap tests uses the following offsets (which may be negative): + * + * +----+----------.. + * |A | yoffset + * | +-+----------.. + * +--|B + * |xoffset + * | | + * : : + * + * For optimal collision detection performance combine these functions + * with some kind of pre-sorting to avoid comparing objects far from + * each other. + * + * BUGS: No known bugs, even though they may certainly be in here somewhere. + * Possible performance improvements could be to remove the div in + * bitmask_overlap_pos() and to implement wider stripes if the masks used + * are wider than 64 bits on the average. + * + * Performance of the various functions goes something like: + * (relative timings, smaller is better) + * + * bitmask_overlap() 1.0 + * bitmask_overlap_pos() 1.3 + * bitmask_overlap_area() 1.6 + * + * For maximum performance on my machine I use gcc with + * -O2 -fomit-frame-pointer -funroll-loops + * + * + * If you can make these functions faster or have found any bugs please + * email Ulf Ekstrom, ulfek@ifm.liu.se + * + * + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef BITMASK_H +#define BITMASK_H + +#include + +/* Define INLINE for different compilers. */ +#ifndef INLINE +# ifdef __GNUC__ +# define INLINE __inline__ +# else +# ifdef _MSC_VER +# define INLINE __inline +# else +# define INLINE +# endif +# endif +#endif + +#define BITW unsigned long int +#define BITW_LEN 32 +#define BITW_MASK 31 +#define BITN(n) ((BITW)1 << (n)) + +typedef struct bitmask +{ + int w,h; + BITW *bits; +} bitmask; + +/* Creates a bitmask of width w and height h. + * The mask is automatically cleared when created. + */ +bitmask *bitmask_create(int w, int h); +void bitmask_free(bitmask *m); + +/* Returns nonzero if the bit at (x,y) is set. + * Coordinates start at (0,0) + */ +static INLINE int bitmask_getbit(const bitmask *m,int x,int y) +{ + return m->bits[x/BITW_LEN*m->h + y] & BITN(x & BITW_MASK); +} + + +/* Sets the bit at (x,y) */ +static INLINE void bitmask_setbit(bitmask *m,int x,int y) +{ + m->bits[x/BITW_LEN*m->h + y] |= BITN(x & BITW_MASK); +} + + +/* Clears the bit at (x,y) */ +static INLINE void bitmask_clearbit(bitmask *m,int x,int y) +{ + m->bits[x/BITW_LEN*m->h + y] &= ~BITN(x & BITW_MASK); +} + + +/* Returns nonzero if the masks overlap with the given offset. */ +int bitmask_overlap(const bitmask *a,const bitmask *b,int xoffset, int yoffset); + +/* Like bitmask_overlap(), but will also give a point of intersection. + * x and y are given in the coordinates of mask a, and are untouched if the is + * no overlap. + */ +int bitmask_overlap_pos(const bitmask *a,const bitmask *b,int xoffset, int yoffset, int *x, int *y); + +/* Returns the number of overlapping 'pixels' */ +int bitmask_overlap_area(const bitmask *a,const bitmask *b,int xoffset, int yoffset); + +/* Draws mask b onto mask a (bitwise OR) + * Can be used to compose large (game background?) mask from + * several submasks, which may speed up the testing. + */ +void bitmask_draw(bitmask *a,bitmask *b,int xoffset, int yoffset); + +/* Create a bitmask from a SDL_Surface */ +bitmask* bitmask_create_SDL(SDL_Surface* surf); + +#endif diff --git a/src/collision.c b/src/collision.c new file mode 100644 index 000000000..baa54add7 --- /dev/null +++ b/src/collision.c @@ -0,0 +1,152 @@ +// +// C Implementation: collision +// +// Description: +// +// +// Author: Tobias Glaesser , (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include "defines.h" +#include "collision.h" +#include "bitmask.h" +#include "scene.h" + +int rectcollision(itop_type* one, itop_type* two) +{ + + if (*one->x >= *two->x - *one->width && + *one->x <= *two->x + *two->width && + *one->y >= *two->y - *one->height && + *one->y <= *two->y + *two->height ) + { + return YES; + } + else + { + return NO; + } +} + +int rectcollision_offset(itop_type* one, itop_type* two, float off_x, float off_y) +{ + + if (*one->x >= *two->x - *one->width +off_x && + *one->x <= *two->x + *two->width + off_x && + *one->y >= *two->y - *one->height + off_y && + *one->y <= *two->y + *two->height + off_y ) + { + return YES; + } + else + { + return NO; + } +} + +void collision_rect_detect(int co_one, int co_two) +{ + int i,j; + + /* CO_BULLET & CO_BADGUY check */ + for(i = 0; i < NUM_BULLETS; ++i) + { + if(bullets[i].alive) + { + for(j = 0; j < NUM_BAD_GUYS; ++j) + { + if(bad_guys[j].alive) + { + if(rectcollision(&bullets[i].it,&bad_guys[j].it) == YES) + { + /* We have detected a collision and now call the collision functions of the collided objects. */ + bullet_collision(&bullets[i], CO_BADGUY); + badguy_collision(&bad_guys[j], &bullets[i], CO_BULLET); + } + } + } + } + } +} + +void collision_handler() +{ + int i,j; + + /* CO_BULLET & CO_BADGUY check */ + for(i = 0; i < NUM_BULLETS; ++i) + { + if(bullets[i].alive) + { + for(j = 0; j < NUM_BAD_GUYS; ++j) + { + if(bad_guys[j].alive) + { + if(rectcollision(&bullets[i].it,&bad_guys[j].it) == YES) + { + /* We have detected a collision and now call the collision functions of the collided objects. */ + bullet_collision(&bullets[i], CO_BADGUY); + badguy_collision(&bad_guys[j], &bullets[i], CO_BULLET); + } + } + } + } + } + + /* CO_BADGUY & CO_BADGUY check */ + for(i = 0; i < NUM_BAD_GUYS; ++i) + { + if(bad_guys[i].alive) + { + for(j = i+1; j < NUM_BAD_GUYS; ++j) + { + if(j != i && bad_guys[j].alive) + { + if(rectcollision(&bad_guys[i].it,&bad_guys[j].it) == YES) + { + /* We have detected a collision and now call the collision functions of the collided objects. */ + badguy_collision(&bad_guys[j], &bad_guys[i], CO_BADGUY); + } + } + } + } + } + + /* CO_BADGUY & CO_PLAYER check */ + for(i = 0; i < NUM_BAD_GUYS; ++i) + { + if(bad_guys[i].alive) + { + if(rectcollision_offset(&bad_guys[i].it,&tux.it,0,48) == YES && tux.ym < 0) + { + /* We have detected a collision and now call the collision functions of the collided objects. */ + badguy_collision(&bad_guys[i], &tux, CO_PLAYER); + } + if(rectcollision(&bad_guys[i].it,&tux.it) == YES) + { + player_collision(&tux, &bad_guys[i], CO_BADGUY); + } + + } + } + + /* CO_UPGRADE & CO_PLAYER check */ + for(i = 0; i < NUM_UPGRADES; ++i) + { + if(upgrades[i].alive) + { + if(rectcollision(&upgrades[i].it,&tux.it) == YES) + { + /* We have detected a collision and now call the collision functions of the collided objects. */ + upgrade_collision(&upgrades[i], &tux, CO_PLAYER); + } + + } + } + +} + + diff --git a/src/collision.h b/src/collision.h new file mode 100644 index 000000000..3836871df --- /dev/null +++ b/src/collision.h @@ -0,0 +1,34 @@ +// C Interface: collision +// +// Description: +// +// +// Author: Tobias Glaesser , (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef SUPERTUX_COLLISION_H +#define SUPERTUX_COLLISION_H + +#include "type.h" + +/* Collision objects */ +enum +{ + CO_BULLET, + CO_BADGUY, + CO_BSOD, + CO_PLAYER +}; + +int rectcollision(itop_type* one, itop_type* two); +int rectcollision_offset(itop_type* one, itop_type* two, float off_x, float off_y); + +/* Checks for all possible collisions. + And calls the collision_handlers, which the collision_objects provide for this case (or not). */ +void collision_handler(); + +#endif /*SUPERTUX_COLLISION_H*/ + diff --git a/src/defines.h b/src/defines.h index 9299b5b2a..542351e7d 100644 --- a/src/defines.h +++ b/src/defines.h @@ -6,47 +6,98 @@ by Bill Kendrick bill@newbreedsoftware.com http://www.newbreedsoftware.com/supertux/ - + April 11, 2000 - December 28, 2003 */ #if !defined( SUPERTUX_DEFINES_H ) - #define SUPERTUX_DEFINES_H - /* Version: */ +#define SUPERTUX_DEFINES_H +/* Version: */ + +#define VERSION "0.0.5" + +/* Frames per second: */ + +#define FPS (1000 / 25) + + +/* Joystick buttons and axes: */ + +#define JOY_A 0 +#define JOY_B 1 + +#define JOY_X 0 +#define JOY_Y 1 + + +/* Booleans: */ - #define VERSION "0.0.5" +#define NO 0 +#define YES 1 +/* Direction (keyboard/joystick) states: */ - /* Frames per second: */ +#define UP 0 +#define DOWN 1 - #define FPS (1000 / 25) +/* Dying types: */ +/* ---- NO 0 */ +#define SQUISHED 1 +#define FALLING 2 - /* Joystick buttons and axes: */ +/* Hurt modes: */ - #define JOY_A 0 - #define JOY_B 1 +#define KILL 0 +#define SHRINK 1 - #define JOY_X 0 - #define JOY_Y 1 +/* Directions: */ +#define LEFT 0 +#define RIGHT 1 - /* Booleans: */ +/* Sizes: */ - #define NO 0 - #define YES 1 +#define SMALL 0 +#define BIG 1 - /* Debugging */ +/* Speed constraints: */ - #ifdef DEBUG - #define DEBUG_MSG( msg ) { \ - printf( msg ); printf("\n"); \ - } +#define MAX_WALK_XM 8 +#define MAX_RUN_XM 3 +#define MAX_YM 10 +#define MAX_JUMP_TIME 1000 +#define MAX_LIVES 4 + +#define WALK_SPEED 1 +#define RUN_SPEED 1.5 +#define JUMP_SPEED 1.5 + +#define GRAVITY 1 +#define YM_FOR_JUMP 50 +#define KILL_BOUNCE_YM 8 + +#define SKID_XM 4 +#define SKID_TIME 8 + +/* Size constraints: */ + +#define OFFSCREEN_DISTANCE 256 + +#define LEVEL_WIDTH 375 + + +/* Debugging */ + +#ifdef DEBUG + #define DEBUG_MSG( msg ) { \ + printf( msg ); printf("\n"); \ + } #else - #define DEBUG_MSG( msg ) {} - #endif + #define DEBUG_MSG( msg ) {} +#endif #endif diff --git a/src/gameloop.c b/src/gameloop.c index 9c6f3acdb..0c1ee7d51 100644 --- a/src/gameloop.c +++ b/src/gameloop.c @@ -7,8 +7,8 @@ bill@newbreedsoftware.com http://www.newbreedsoftware.com/supertux/ - April 11, 2000 - December 29, 2003 -*/ + April 11, 2000 - January 1st, 2004 + */ #include #include @@ -33,8 +33,11 @@ #include "menu.h" #include "badguy.h" #include "world.h" +#include "special.h" #include "player.h" #include "level.h" +#include "scene.h" +#include "collision.h" /* extern variables */ @@ -42,88 +45,23 @@ extern char* soundfilenames[NUM_SOUNDS]; /* Local variables: */ -int score, highscore, distros, level, lives, scroll_x, next_level, game_pause, -done, quit, tux_dir, tux_size, tux_duck, tux_x, tux_xm, tux_y, tux_ym, -tux_dying, tux_safe, jumping, jump_counter, frame, score_multiplier, -tux_frame_main, tux_frame, tux_got_coffee, tux_skidding, -super_bkgd_time, tux_invincible_time, endpos, -counting_distros, distro_counter; -int left, right, up, down, fire, old_fire; -SDL_Surface * img_brick[2], * img_solid[4], * img_distro[4], -* img_waves[3], * img_water, * img_pole, * img_poletop, * img_flag[2]; -SDL_Surface * img_bkgd[2][4]; -SDL_Surface * img_golden_herring; -SDL_Surface * img_bsod_left[4], * img_bsod_right[4], -* img_laptop_left[3], * img_laptop_right[3], -* img_money_left[2], * img_money_right[2]; -SDL_Surface * img_bsod_squished_left, * img_bsod_squished_right, -* img_bsod_falling_left, * img_bsod_falling_right, -* img_laptop_flat_left, * img_laptop_flat_right, -* img_laptop_falling_left, * img_laptop_falling_right; -SDL_Surface * img_box_full, * img_box_empty, * img_mints, * img_coffee, -* img_super_bkgd, * img_bullet, * img_red_glow; -SDL_Surface * img_cloud[2][4]; -SDL_Surface * tux_life, -* tux_right[3], * tux_left[3], -* bigtux_right[3], * bigtux_left[3], -* bigtux_right_jump, * bigtux_left_jump, -* ducktux_right, * ducktux_left, -* skidtux_right, * skidtux_left, -* firetux_right[3], * firetux_left[3], -* bigfiretux_right[3], * bigfiretux_left[3], -* bigfiretux_right_jump, * bigfiretux_left_jump, -* duckfiretux_right, * duckfiretux_left, -* skidfiretux_right, * skidfiretux_left, -* cape_right[2], * cape_left[2], -* bigcape_right[2], * bigcape_left[2]; +texture_type img_waves[3], img_water, img_pole, img_poletop, img_flag[2]; +texture_type img_cloud[2][4]; SDL_Event event; -SDL_Rect src, dest; SDLKey key; -bouncy_distro_type bouncy_distros[NUM_BOUNCY_DISTROS]; -broken_brick_type broken_bricks[NUM_BROKEN_BRICKS]; -bouncy_brick_type bouncy_bricks[NUM_BOUNCY_BRICKS]; -bad_guy_type bad_guys[NUM_BAD_GUYS]; -floating_score_type floating_scores[NUM_FLOATING_SCORES]; -upgrade_type upgrades[NUM_UPGRADES]; -bullet_type bullets[NUM_BULLETS]; -st_level current_level; char level_subset[100]; char str[60]; - +timer_type time_left; /* Local function prototypes: */ void levelintro(void); -void set_default(void); void initgame(void); -void loadlevelgfx(void); void loadlevelsong(void); -void unloadlevelgfx(void); void unloadlevelsong(void); void loadshared(void); void unloadshared(void); -void drawshape(int x, int y, unsigned char c); -unsigned char shape(int x, int y, int sx); -int issolid(int x, int y, int sx); -int isbrick(int x, int y, int sx); -int isice(int x, int y, int sx); -int isfullbox(int x, int y, int sx); -void change(int x, int y, int sx, unsigned char c); -void trybreakbrick(int x, int y, int sx); -void bumpbrick(int x, int y, int sx); -void tryemptybox(int x, int y, int sx); -void trygrabdistro(int x, int y, int sx, int bounciness); -void add_bouncy_distro(int x, int y); -void add_broken_brick(int x, int y); -void add_broken_brick_piece(int x, int y, int xm, int ym); -void add_bouncy_brick(int x, int y); -void add_bad_guy(int x, int y, int kind); -void add_score(int x, int y, int s); -void trybumpbadguy(int x, int y, int sx); -void add_upgrade(int x, int y, int kind); -void killtux(int mode); -void remove_powerups(void); -void add_bullet(int x, int y, int dir, int xm); +void drawstatus(void); void drawendscreen(void); void drawresultscreen(void); @@ -139,84 +77,23 @@ void levelintro(void) sprintf(str, "%s", current_level.name); drawcenteredtext(str, 224, letters_gold, NO_UPDATE, 1); - sprintf(str, "TUX x %d", lives); + sprintf(str, "TUX x %d", tux.lives); drawcenteredtext(str, 256, letters_blue, NO_UPDATE, 1); - SDL_Flip(screen); + flipscreen(); SDL_Delay(1000); } -void set_defaults(void) +/* Reset Timers */ +void start_timers(void) { - int i; - - /* Reset arrays: */ - - for (i = 0; i < NUM_BOUNCY_DISTROS; i++) - bouncy_distros[i].alive = NO; - - for (i = 0; i < NUM_BROKEN_BRICKS; i++) - broken_bricks[i].alive = NO; - - for (i = 0; i < NUM_BOUNCY_BRICKS; i++) - bouncy_bricks[i].alive = NO; - - for (i = 0; i < NUM_BAD_GUYS; i++) - bad_guys[i].alive = NO; - - for (i = 0; i < NUM_FLOATING_SCORES; i++) - floating_scores[i].alive = NO; - - for (i = 0; i < NUM_UPGRADES; i++) - upgrades[i].alive = NO; - - for (i = 0; i < NUM_BULLETS; i++) - bullets[i].alive = NO; - - - /* Set defaults: */ - - tux_x = 0; - tux_xm = 0; - tux_y = 240; - tux_ym = 0; - tux_dir = RIGHT; - tux_invincible_time = 0; - tux_duck = NO; - - tux_dying = NO; - tux_safe = TUX_SAFE_TIME; - - jumping = NO; - jump_counter = 0; - - tux_skidding = 0; - - scroll_x = 0; - - right = UP; - left = UP; - up = UP; - down = UP; - fire = UP; - old_fire = UP; - - score_multiplier = 1; - super_bkgd_time = 0; - - counting_distros = NO; - distro_counter = 0; - - endpos = 0; - - /* set current song/music */ - current_music = LEVEL_MUSIC; + timer_start(&time_left,current_level.time_left*1000); } void activate_bad_guys(void) { -int x,y; + int x,y; /* Activate bad guys: */ @@ -231,7 +108,7 @@ int x,y; } } } - + } /* --- GAME EVENT! --- */ @@ -271,23 +148,23 @@ void game_event(void) } else if (key == SDLK_RIGHT) { - right = DOWN; + tux.input.right = DOWN; } else if (key == SDLK_LEFT) { - left = DOWN; + tux.input.left = DOWN; } else if (key == SDLK_UP) { - up = DOWN; + tux.input.up = DOWN; } else if (key == SDLK_DOWN) { - down = DOWN; + tux.input.down = DOWN; } else if (key == SDLK_LCTRL) { - fire = DOWN; + tux.input.fire = DOWN; } } else if (event.type == SDL_KEYUP) @@ -298,23 +175,23 @@ void game_event(void) if (key == SDLK_RIGHT) { - right = UP; + tux.input.right = UP; } else if (key == SDLK_LEFT) { - left = UP; + tux.input.left = UP; } else if (key == SDLK_UP) { - up = UP; + tux.input.up = UP; } else if (key == SDLK_DOWN) { - down = UP; + tux.input.down = UP; } else if (key == SDLK_LCTRL) { - fire = UP; + tux.input.fire = UP; } else if (key == SDLK_p) { @@ -328,7 +205,7 @@ void game_event(void) } else if (key == SDLK_TAB && debug_mode == YES) { - tux_size = !tux_size; + tux.size = !tux.size; } else if (key == SDLK_END && debug_mode == YES) { @@ -338,6 +215,14 @@ void game_event(void) { next_level = 1; } + else if (key == SDLK_DELETE && debug_mode == YES) + { + tux.got_coffee = 1; + } + else if (key == SDLK_INSERT && debug_mode == YES) + { + timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME); + } } #ifdef JOY_YES else if (event.type == SDL_JOYAXISMOTION) @@ -345,26 +230,26 @@ void game_event(void) if (event.jaxis.axis == JOY_X) { if (event.jaxis.value < -256) - left = DOWN; + tux.input.left = DOWN; else - left = UP; + tux.input.left = UP; if (event.jaxis.value > 256) - right = DOWN; + tux.input.right = DOWN; else - right = UP; + tux.input.right = UP; } else if (event.jaxis.axis == JOY_Y) { if (event.jaxis.value > 256) - down = DOWN; + tux.input.down = DOWN; else - down = UP; + tux.input.down = UP; /* Handle joystick for the menu */ if(show_menu) { - if(down == DOWN) + if(tux.input.down == DOWN) menuaction = MN_DOWN; else menuaction = MN_UP; @@ -374,16 +259,16 @@ void game_event(void) else if (event.type == SDL_JOYBUTTONDOWN) { if (event.jbutton.button == JOY_A) - up = DOWN; + tux.input.up = DOWN; else if (event.jbutton.button == JOY_B) - fire = DOWN; + tux.input.fire = DOWN; } else if (event.type == SDL_JOYBUTTONUP) { if (event.jbutton.button == JOY_A) - up = UP; + tux.input.up = UP; else if (event.jbutton.button == JOY_B) - fire = UP; + tux.input.fire = UP; if(show_menu) menuaction = MN_HIT; @@ -399,205 +284,10 @@ void game_event(void) int game_action(void) { - int i,j; - - /* --- HANDLE TUX! --- */ - - /* Handle key and joystick state: */ - - if (!(tux_dying || next_level)) - { - if (right == DOWN && left == UP) - { - if (jumping == NO) - { - if (tux_xm < -SKID_XM && !tux_skidding && - tux_dir == LEFT) - { - tux_skidding = SKID_TIME; - - play_sound(sounds[SND_SKID], SOUND_CENTER_SPEAKER); - - } - tux_dir = RIGHT; - } - - if (tux_xm < 0 && !isice(tux_x, tux_y + 32, scroll_x) && - !tux_skidding) - { - tux_xm = 0; - } - - if (!tux_duck) - { - if (tux_dir == RIGHT) - { - /* Facing the direction we're jumping? Go full-speed: */ - - if (fire == UP) - { - tux_xm = tux_xm + WALK_SPEED; - - if (tux_xm > MAX_WALK_XM) - tux_xm = MAX_WALK_XM; - } - else if (fire == DOWN) - { - tux_xm = tux_xm + RUN_SPEED; - - if (tux_xm > MAX_RUN_XM) - tux_xm = MAX_RUN_XM; - } - } - else - { - /* Not facing the direction we're jumping? - Go half-speed: */ - - tux_xm = tux_xm + WALK_SPEED / 2; - - if (tux_xm > MAX_WALK_XM / 2) - tux_xm = MAX_WALK_XM / 2; - } - } - } - else if (left == DOWN && right == UP) - { - if (jumping == NO) - { - if (tux_xm > SKID_XM && !tux_skidding && - tux_dir == RIGHT) - { - tux_skidding = SKID_TIME; - play_sound(sounds[SND_SKID], SOUND_CENTER_SPEAKER); - } - tux_dir = LEFT; - } - - if (tux_xm > 0 && !isice(tux_x, tux_y + 32, scroll_x) && - !tux_skidding) - { - tux_xm = 0; - } - - if (!tux_duck) - { - if (tux_dir == LEFT) - { - /* Facing the direction we're jumping? Go full-speed: */ - - if (fire == UP) - { - tux_xm = tux_xm - WALK_SPEED; - - if (tux_xm < -MAX_WALK_XM) - tux_xm = -MAX_WALK_XM; - } - else if (fire == DOWN) - { - tux_xm = tux_xm - RUN_SPEED; - - if (tux_xm < -MAX_RUN_XM) - tux_xm = -MAX_RUN_XM; - } - } - else - { - /* Not facing the direction we're jumping? - Go half-speed: */ - - tux_xm = tux_xm - WALK_SPEED / 2; - - if (tux_xm < -MAX_WALK_XM / 2) - tux_xm = -MAX_WALK_XM / 2; - } - } - } - - - /* End of level? */ - - if (tux_x >= endpos && endpos != 0) - { - next_level = 1; - } - - - /* Jump/jumping? */ - - if (up == DOWN) - { - if (jump_counter == 0) - { - /* Taking off? */ - - if (!issolid(tux_x, tux_y + 32, scroll_x) || - tux_ym != 0) - { - /* If they're not on the ground, or are currently moving - vertically, don't jump! */ - - jump_counter = MAX_JUMP_COUNT; - } - else - { - /* Make sure we're not standing back up into a solid! */ - - if (tux_size == SMALL || tux_duck == NO || - !issolid(tux_x, tux_y, scroll_x)) - { - jumping = YES; - - if (tux_size == SMALL) - play_sound(sounds[SND_JUMP], SOUND_CENTER_SPEAKER); - else - play_sound(sounds[SND_BIGJUMP], SOUND_CENTER_SPEAKER); - } - } - } - - - /* Keep jumping for a while: */ - - if (jump_counter < MAX_JUMP_COUNT) - { - tux_ym = tux_ym - JUMP_SPEED; - jump_counter++; - } - } - else - jump_counter = 0; - - - /* Shoot! */ - - if (fire == DOWN && old_fire == UP && tux_got_coffee) - { - add_bullet(tux_x + scroll_x, tux_y, tux_dir, tux_xm); - } - - - /* Duck! */ - - if (down == DOWN) - { - if (tux_size == BIG) - tux_duck = YES; - } - else - { - if (tux_size == BIG && tux_duck == YES) - { - /* Make sure we're not standing back up into a solid! */ +int i; - if (!issolid(tux_x, tux_y - 32, scroll_x)) - tux_duck = NO; - } - else - tux_duck = NO; - } - } /* (tux_dying || next_level) */ - else + /* (tux_dying || next_level) */ + if (tux.dying || next_level) { /* Tux either died, or reached the end of a level! */ @@ -616,24 +306,16 @@ int game_action(void) else { - tux_ym = tux_ym + GRAVITY; - - - - /* He died :^( */ - - --lives; - remove_powerups(); - + player_dying(&tux); + /* No more lives!? */ - if (lives < 0) + if (tux.lives < 0) { drawendscreen(); if (score > highscore) save_hs(score); - unloadlevelgfx(); unloadlevelsong(); unloadshared(); @@ -643,1658 +325,175 @@ int game_action(void) /* Either way, (re-)load the (next) level... */ + player_level_begin(&tux); set_defaults(); loadlevel(¤t_level,"default",level); activate_bad_guys(); unloadlevelgfx(); - loadlevelgfx(); + loadlevelgfx(¤t_level); unloadlevelsong(); loadlevelsong(); levelintro(); + start_timers(); } - /* Move tux: */ - - tux_x = tux_x + tux_xm; - tux_y = tux_y + tux_ym; + player_action(&tux); + /* Handle bouncy distros: */ - /* Keep tux in bounds: */ - if (tux_x < 0) - tux_x = 0; - else if (tux_x < 160 && scroll_x > 0 && debug_mode == YES) + for (i = 0; i < NUM_BOUNCY_DISTROS; i++) { - scroll_x = scroll_x - ( 160 - tux_x); - tux_x = 160; - - if(scroll_x < 0) - scroll_x = 0; - + bouncy_distro_action(&bouncy_distros[i]); } - else if (tux_x > 320 && scroll_x < ((current_level.width * 32) - 640)) - { - /* Scroll the screen in past center: */ - scroll_x = scroll_x + (tux_x - 320); - tux_x = 320; - if (scroll_x > ((current_level.width * 32) - 640)) - scroll_x = ((current_level.width * 32) - 640); - } - else if (tux_x > 608) - { - /* ... unless there's no more to scroll! */ + /* Handle broken bricks: */ - tux_x = 608; + for (i = 0; i < NUM_BROKEN_BRICKS; i++) + { + broken_brick_action(&broken_bricks[i]); } - /* Land: */ + /* Handle distro counting: */ - if (!tux_dying) + if (counting_distros == YES) { - if (issolid(tux_x, tux_y + 31, scroll_x) && - !issolid(tux_x - tux_xm, tux_y + 31, scroll_x)) - { - while (issolid(tux_x, tux_y + 31, scroll_x)) - { - if (tux_xm < 0) - tux_x++; - else if (tux_xm > 0) - tux_x--; - } + distro_counter--; - tux_xm = 0; - } + if (distro_counter <= 0) + counting_distros = -1; + } - if (issolid(tux_x, tux_y, scroll_x) && - !issolid(tux_x - tux_xm, tux_y, scroll_x)) - { - while (issolid(tux_x, tux_y, scroll_x)) - { - if (tux_xm < 0) - tux_x++; - else if (tux_xm > 0) - tux_x--; - } - tux_xm = 0; - } + /* Handle bouncy bricks: */ - if (issolid(tux_x, tux_y + 31, scroll_x)) - { - /* Set down properly: */ + for (i = 0; i < NUM_BOUNCY_BRICKS; i++) + { + bouncy_brick_action(&bouncy_bricks[i]); + } - while (issolid(tux_x, tux_y + 31, scroll_x)) - { - if (tux_ym < 0) - tux_y++; - else if (tux_ym > 0) - tux_y--; - } + /* Handle floating scores: */ - /* Reset score multiplier (for mutli-hits): */ + for (i = 0; i < NUM_FLOATING_SCORES; i++) + { + floating_score_action(&floating_scores[i]); + } - if (tux_ym > 0) - score_multiplier = 1; + /* Handle bullets: */ - /* Stop jumping! */ + for (i = 0; i < NUM_BULLETS; ++i) + { + bullet_action(&bullets[i]); + } - tux_ym = 0; - jumping = NO; - } + /* Handle background timer: */ - /* Bump into things: */ + if (super_bkgd_time) + super_bkgd_time--; - if (issolid(tux_x, tux_y, scroll_x) || - (tux_size == BIG && !tux_duck && - (issolid(tux_x, tux_y - 32, scroll_x)))) - { - if (!issolid(tux_x - tux_xm, tux_y, scroll_x) && - (tux_size == SMALL || tux_duck || - !issolid(tux_x - tux_xm, tux_y - 32, scroll_x))) - { - tux_x = tux_x - tux_xm; - tux_xm = 0; - } - else if (!issolid(tux_x, tux_y - tux_ym, scroll_x) && - (tux_size == SMALL || tux_duck || - !issolid(tux_x, tux_y - 32 - tux_ym, scroll_x))) - { - if (tux_ym <= 0) - { - /* Jumping up? */ - - if (tux_size == BIG) - { - /* Break bricks and empty boxes: */ - - if (!tux_duck) - { - if (isbrick(tux_x, tux_y - 32, scroll_x) || - isfullbox(tux_x, tux_y - 32, scroll_x)) - { - trygrabdistro(tux_x, tux_y - 64, scroll_x, - BOUNCE); - trybumpbadguy(tux_x, tux_y - 96, scroll_x); - - if (isfullbox(tux_x, tux_y - 32, - scroll_x)) - { - bumpbrick(tux_x, tux_y - 32, - scroll_x); - } - - trybreakbrick(tux_x, tux_y - 32, scroll_x); - tryemptybox(tux_x, tux_y - 32, scroll_x); - } - - if (isbrick(tux_x + 31, tux_y - 32, scroll_x) || - isfullbox(tux_x + 31, tux_y - 32, scroll_x)) - { - trygrabdistro(tux_x + 31, - tux_y - 64, - scroll_x, - BOUNCE); - trybumpbadguy(tux_x + 31, - tux_y - 96, - scroll_x); - - if (isfullbox(tux_x + 31, tux_y - 32, - scroll_x)) - { - bumpbrick(tux_x + 31, tux_y - 32, - scroll_x); - } - - trybreakbrick(tux_x + 31, - tux_y - 32, - scroll_x); - tryemptybox(tux_x + 31, - tux_y - 32, - scroll_x); - } - } - else /* ducking */ - { - if (isbrick(tux_x, tux_y, scroll_x) || - isfullbox(tux_x, tux_y, scroll_x)) - { - trygrabdistro(tux_x, tux_y - 32, scroll_x, - BOUNCE); - trybumpbadguy(tux_x, tux_y - 64, scroll_x); - if (isfullbox(tux_x, tux_y, scroll_x)) - bumpbrick(tux_x, tux_y, scroll_x); - trybreakbrick(tux_x, tux_y, scroll_x); - tryemptybox(tux_x, tux_y, scroll_x); - } - - if (isbrick(tux_x + 31, tux_y, scroll_x) || - isfullbox(tux_x + 31, tux_y, scroll_x)) - { - trygrabdistro(tux_x + 31, - tux_y - 32, - scroll_x, - BOUNCE); - trybumpbadguy(tux_x + 31, - tux_y - 64, - scroll_x); - if (isfullbox(tux_x + 31, tux_y, scroll_x)) - bumpbrick(tux_x + 31, tux_y, scroll_x); - trybreakbrick(tux_x + 31, tux_y, scroll_x); - tryemptybox(tux_x + 31, tux_y, scroll_x); - } - } - } - else - { - /* It's a brick and we're small, make the brick - bounce, and grab any distros above it: */ - - if (isbrick(tux_x, tux_y, scroll_x) || - isfullbox(tux_x, tux_y, scroll_x)) - { - trygrabdistro(tux_x, tux_y - 32, scroll_x, - BOUNCE); - trybumpbadguy(tux_x, tux_y - 64, scroll_x); - bumpbrick(tux_x, tux_y, scroll_x); - tryemptybox(tux_x, tux_y, scroll_x); - } - - if (isbrick(tux_x + 31, tux_y, scroll_x) || - isfullbox(tux_x + 31, tux_y, scroll_x)) - { - trygrabdistro(tux_x + 31, tux_y - 32, scroll_x, - BOUNCE); - trybumpbadguy(tux_x + 31, tux_y - 64, scroll_x); - bumpbrick(tux_x + 31, tux_y, scroll_x); - tryemptybox(tux_x + 31, tux_y, scroll_x); - } - - - /* Get a distro from a brick? */ - - if (shape(tux_x, tux_y, scroll_x) == 'x' || - shape(tux_x, tux_y, scroll_x) == 'y') - { - add_bouncy_distro(((tux_x + scroll_x + 1) - / 32) * 32, - (tux_y / 32) * 32); - - if (counting_distros == NO) - { - counting_distros = YES; - distro_counter = 100; - } - - if (distro_counter <= 0) - change(tux_x, tux_y, scroll_x, 'a'); - - play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER); - score = score + SCORE_DISTRO; - distros++; - } - else if (shape(tux_x + 31, tux_y, scroll_x) == 'x' || - shape(tux_x + 31, tux_y, scroll_x) == 'y') - { - add_bouncy_distro(((tux_x + scroll_x + 1 + 31) - / 32) * 32, - (tux_y / 32) * 32); - - if (counting_distros == NO) - { - counting_distros = YES; - distro_counter = 100; - } - - if (distro_counter <= 0) - change(tux_x + 31, tux_y, scroll_x, 'a'); - - play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER); - score = score + SCORE_DISTRO; - distros++; - } - } - - - /* Bump head: */ - - tux_y = (tux_y / 32) * 32 + 30; - } - else - { - /* Land on feet: */ - tux_y = (tux_y / 32) * 32 - 32; - } + /* Handle upgrades: */ - tux_ym = 0; - jumping = NO; - jump_counter = MAX_JUMP_COUNT; - } - } - } + for (i = 0; i < NUM_UPGRADES; i++) + { + upgrade_action(&upgrades[i]); + } /* for (i = 0; i < NUM_UPGRADES; i++) */ - /* Grab distros: */ + /* Handle bad guys: */ - if (!tux_dying) + for (i = 0; i < NUM_BAD_GUYS; i++) { - trygrabdistro(tux_x, tux_y, scroll_x, NO_BOUNCE); - trygrabdistro(tux_x + 31, tux_y, scroll_x, NO_BOUNCE); - - if (tux_size == BIG && !tux_duck) - { - trygrabdistro(tux_x, tux_y - 32, scroll_x, NO_BOUNCE); - trygrabdistro(tux_x + 31, tux_y - 32, scroll_x, NO_BOUNCE); - } + badguy_action(&bad_guys[i]); } + /* Handle all possible collisions. */ + collision_handler(); - /* Enough distros for a One-up? */ + return -1; +} - if (distros >= DISTROS_LIFEUP) - { - distros = distros - DISTROS_LIFEUP; - if(lives < MAX_LIVES) - lives++; - /*We want to hear the sound even, if MAX_LIVES is reached*/ - play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER); - } +/* --- GAME DRAW! --- */ +void game_draw() +{ + int x, y, i; - /* Keep in-bounds, vertically: */ + /* Draw screen: */ - if (tux_y < 0) - tux_y = 0; - else if (tux_y > 480) + if (tux.dying && (frame % 4) == 0) + clearscreen(255, 255, 255); + else { - killtux(KILL); + if (super_bkgd_time == 0) + clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); + else + texture_draw(&img_super_bkgd, 0, 0, NO_UPDATE); } + /* Draw background: */ - /* Slow down horizontally: */ - - if (!tux_dying) + for (y = 0; y < 15; y++) { - if (right == UP && left == UP) + for (x = 0; x < 21; x++) { - if (isice(tux_x, tux_y + 32, scroll_x) || - !issolid(tux_x, tux_y + 32, scroll_x)) - { - /* Slowly on ice or in air: */ - - if (tux_xm > 0) - tux_xm--; - else if (tux_xm < 0) - tux_xm++; - } - else - { - /* Quickly, otherwise: */ - - tux_xm = tux_xm / 2; - } + drawshape(x * 32 - ((int)scroll_x % 32), y * 32, + current_level.tiles[(int)y][(int)x + (int)(scroll_x / 32)]); } + } - /* Drop vertically: */ - - if (!issolid(tux_x, tux_y + 32, scroll_x)) - { - tux_ym = tux_ym + GRAVITY; + /* (Bouncy bricks): */ - if (tux_ym > MAX_YM) - tux_ym = MAX_YM; - } + for (i = 0; i < NUM_BOUNCY_BRICKS; i++) + { + bouncy_brick_draw(&bouncy_bricks[i]); } - if (tux_safe > 0) - tux_safe--; - + /* (Bad guys): */ - /* ---- DONE HANDLING TUX! --- */ + for (i = 0; i < NUM_BAD_GUYS; i++) + { + badguy_draw(&bad_guys[i]); + } + /* (Tux): */ + + player_draw(&tux); - /* Handle bouncy distros: */ + /* (Bullets): */ - for (i = 0; i < NUM_BOUNCY_DISTROS; i++) + for (i = 0; i < NUM_BULLETS; i++) { - if (bouncy_distros[i].alive) - { - bouncy_distros[i].y = bouncy_distros[i].y + bouncy_distros[i].ym; + bullet_draw(&bullets[i]); + } - bouncy_distros[i].ym++; + /* (Floating scores): */ - if (bouncy_distros[i].ym >= 0) - bouncy_distros[i].alive = NO; - } + for (i = 0; i < NUM_FLOATING_SCORES; i++) + { + floating_score_draw(&floating_scores[i]); } - /* Handle broken bricks: */ + /* (Upgrades): */ - for (i = 0; i < NUM_BROKEN_BRICKS; i++) + for (i = 0; i < NUM_UPGRADES; i++) { - if (broken_bricks[i].alive) - { - broken_bricks[i].x = broken_bricks[i].x + broken_bricks[i].xm; - broken_bricks[i].y = broken_bricks[i].y + broken_bricks[i].ym; - - broken_bricks[i].ym++; - - if (broken_bricks[i].ym >= 0) - broken_bricks[i].alive = NO; - } + upgrade_draw(&upgrades[i]); } - /* Handle distro counting: */ + /* (Bouncy distros): */ - if (counting_distros == YES) + for (i = 0; i < NUM_BOUNCY_DISTROS; i++) { - distro_counter--; - - if (distro_counter <= 0) - counting_distros = -1; - } - - - /* Handle bouncy bricks: */ - - for (i = 0; i < NUM_BOUNCY_BRICKS; i++) - { - if (bouncy_bricks[i].alive) - { - bouncy_bricks[i].offset = (bouncy_bricks[i].offset + - bouncy_bricks[i].offset_m); - - /* Go back down? */ - - if (bouncy_bricks[i].offset < -BOUNCY_BRICK_MAX_OFFSET) - bouncy_bricks[i].offset_m = BOUNCY_BRICK_SPEED; - - - /* Stop bouncing? */ - - if (bouncy_bricks[i].offset == 0) - bouncy_bricks[i].alive = NO; - } - } - - - /* Handle floating scores: */ - - for (i = 0; i < NUM_FLOATING_SCORES; i++) - { - if (floating_scores[i].alive) - { - floating_scores[i].y = floating_scores[i].y - 2; - floating_scores[i].timer--; - - if (floating_scores[i].timer <= 0) - floating_scores[i].alive = NO; - } - } - - - /* Handle bullets: */ - - for (i = 0; i < NUM_BULLETS; i++) - { - if (bullets[i].alive) - { - bullets[i].x = bullets[i].x + bullets[i].xm; - bullets[i].y = bullets[i].y + bullets[i].ym; - - if (issolid(bullets[i].x, bullets[i].y, 0)) - { - if (issolid(bullets[i].x, bullets[i].y - bullets[i].ym, 0)) - bullets[i].alive = NO; - else - { - if (bullets[i].ym >= 0) - { - bullets[i].y = (bullets[i].y / 32) * 32 - 8; - } - bullets[i].ym = -bullets[i].ym; - } - } - - bullets[i].ym = bullets[i].ym + GRAVITY; - - if (bullets[i].x < scroll_x || - bullets[i].x > scroll_x + 640) - { - bullets[i].alive = NO; - } - } - - - if (bullets[i].alive) - { - for (j = 0; j < NUM_BAD_GUYS; j++) - { - if (bad_guys[j].alive && !bad_guys[j].dying) - { - if (bullets[i].x >= bad_guys[j].x - 4 && - bullets[i].x <= bad_guys[j].x + 32 + 4 && - bullets[i].y >= bad_guys[j].y - 4 && - bullets[i].y <= bad_guys[j].y + 32 + 4) - { - /* Kill the bad guy! */ - - bullets[i].alive = 0; - bad_guys[j].dying = FALLING; - bad_guys[j].ym = -8; - - - /* Gain some points: */ - - if (bad_guys[j].kind == BAD_BSOD) - { - add_score(bad_guys[j].x - scroll_x, bad_guys[j].y, - 50 * score_multiplier); - } - else if (bad_guys[j].kind == BAD_LAPTOP) - { - add_score(bad_guys[j].x - scroll_x, bad_guys[j].y, - 25 * score_multiplier); - } - - - /* Play death sound: */ - play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER); - } - } - } - } - } - - - /* Handle background timer: */ - - if (super_bkgd_time) - super_bkgd_time--; - - - /* Handle invincibility timer: */ - - - if (tux_invincible_time > 50) - { - tux_invincible_time--; - - - if (!playing_music()) - play_music( herring_song, 1 ); - } - else - { - if (current_music == HERRING_MUSIC) - { - /* stop the herring_song, now play the level_song ! */ - current_music = LEVEL_MUSIC; - halt_music(); - } - - if (!playing_music()) - { - if (current_level.time_left <= TIME_WARNING) - play_music( level_song_fast, 1 ); - else - play_music( level_song, 1 ); - } - - if (tux_invincible_time > 0) - tux_invincible_time--; - } - - - /* Handle upgrades: */ - - for (i = 0; i < NUM_UPGRADES; i++) - { - if (upgrades[i].alive) - { - if (upgrades[i].height < 32) - { - /* Rise up! */ - - upgrades[i].height++; - } - else - { - /* Move around? */ - - if (upgrades[i].kind == UPGRADE_MINTS || - upgrades[i].kind == UPGRADE_HERRING) - { - upgrades[i].x = upgrades[i].x + upgrades[i].xm; - upgrades[i].y = upgrades[i].y + upgrades[i].ym; - - if (issolid(upgrades[i].x, upgrades[i].y + 31, 0) || - issolid(upgrades[i].x + 31, upgrades[i].y + 31, 0)) - { - if (upgrades[i].ym > 0) - { - if (upgrades[i].kind == UPGRADE_MINTS) - { - upgrades[i].ym = 0; - } - else if (upgrades[i].kind == UPGRADE_HERRING) - { - upgrades[i].ym = -24; - } - - upgrades[i].y = (upgrades[i].y / 32) * 32; - } - } - else - upgrades[i].ym = upgrades[i].ym + GRAVITY; - - if (issolid(upgrades[i].x, upgrades[i].y, 0)) - { - upgrades[i].xm = -upgrades[i].xm; - } - } - - - /* Off the screen? Kill it! */ - - if (upgrades[i].x < scroll_x) - upgrades[i].alive = NO; - - - /* Did the player grab it? */ - - if (tux_x + scroll_x >= upgrades[i].x - 32 && - tux_x + scroll_x <= upgrades[i].x + 32 && - tux_y >= upgrades[i].y - 32 && - tux_y <= upgrades[i].y + 32) - { - /* Remove the upgrade: */ - - upgrades[i].alive = NO; - - - /* Affect the player: */ - - if (upgrades[i].kind == UPGRADE_MINTS) - { - play_sound(sounds[SND_EXCELLENT], SOUND_CENTER_SPEAKER); - tux_size = BIG; - super_bkgd_time = 8; - } - else if (upgrades[i].kind == UPGRADE_COFFEE) - { - play_sound(sounds[SND_COFFEE], SOUND_CENTER_SPEAKER); - tux_got_coffee = YES; - super_bkgd_time = 4; - } - else if (upgrades[i].kind == UPGRADE_HERRING) - { - play_sound(sounds[SND_HERRING], SOUND_CENTER_SPEAKER); - tux_invincible_time = TUX_INVINCIBLE_TIME; - super_bkgd_time = 4; - /* play the herring song ^^ */ - current_music = HERRING_MUSIC; - if (playing_music()) - halt_music(); - play_music( herring_song, 1 ); - } - } - } - } - } - - - /* Handle bad guys: */ - - for (i = 0; i < NUM_BAD_GUYS; i++) - { - if (bad_guys[i].alive) - { - if (bad_guys[i].seen) - { - if (bad_guys[i].kind == BAD_BSOD) - { - /* --- BLUE SCREEN OF DEATH MONSTER: --- */ - - /* Move left/right: */ - - if (bad_guys[i].dying == NO || - bad_guys[i].dying == FALLING) - { - if (bad_guys[i].dir == RIGHT) - bad_guys[i].x = bad_guys[i].x + 4; - else if (bad_guys[i].dir == LEFT) - bad_guys[i].x = bad_guys[i].x - 4; - } - - - /* Move vertically: */ - - bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym; - - - /* Bump into things horizontally: */ - - if (!bad_guys[i].dying) - { - if (issolid(bad_guys[i].x, bad_guys[i].y, 0)) - bad_guys[i].dir = !bad_guys[i].dir; - } - - - /* Bump into other bad guys: */ - - for (j = 0; j < NUM_BAD_GUYS; j++) - { - if (j != i && bad_guys[j].alive && - !bad_guys[j].dying && !bad_guys[i].dying && - bad_guys[i].x >= bad_guys[j].x - 32 && - bad_guys[i].x <= bad_guys[j].x + 32 && - bad_guys[i].y >= bad_guys[j].y - 32 && - bad_guys[i].y <= bad_guys[j].y + 32) - { - bad_guys[i].dir = !bad_guys[i].dir; - } - } - - - /* Fall if we get off the ground: */ - - if (bad_guys[i].dying != FALLING) - { - if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0) && - bad_guys[i].ym < MAX_YM) - { - bad_guys[i].ym = bad_guys[i].ym + GRAVITY; - } - else - { - /* Land: */ - - if (bad_guys[i].ym > 0) - { - bad_guys[i].y = (bad_guys[i].y / 32) * 32; - bad_guys[i].ym = 0; - } - } - } - else - bad_guys[i].ym = bad_guys[i].ym + GRAVITY; - - if (bad_guys[i].y > 480) - bad_guys[i].alive = NO; - } - else if (bad_guys[i].kind == BAD_LAPTOP) - { - /* --- LAPTOP MONSTER: --- */ - - /* Move left/right: */ - - if (bad_guys[i].mode != FLAT && bad_guys[i].mode != KICK) - { - if (bad_guys[i].dying == NO || - bad_guys[i].dying == FALLING) - { - if (bad_guys[i].dir == RIGHT) - bad_guys[i].x = bad_guys[i].x + 4; - else if (bad_guys[i].dir == LEFT) - bad_guys[i].x = bad_guys[i].x - 4; - } - } - else if (bad_guys[i].mode == KICK) - { - if (bad_guys[i].dir == RIGHT) - bad_guys[i].x = bad_guys[i].x + 16; - else if (bad_guys[i].dir == LEFT) - bad_guys[i].x = bad_guys[i].x - 16; - } - - - /* Move vertically: */ - - bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym; - - - /* Bump into things horizontally: */ - - if (!bad_guys[i].dying) - { - if (issolid(bad_guys[i].x, bad_guys[i].y, 0)) - { - bad_guys[i].dir = !bad_guys[i].dir; - - if (bad_guys[i].mode == KICK) - { - /* handle stereo sound */ - if (tux_x + scroll_x > bad_guys[i].x) - play_sound(sounds[SND_RICOCHET], SOUND_LEFT_SPEAKER); - else if (tux_x + scroll_x < bad_guys[i].x) - play_sound(sounds[SND_RICOCHET], SOUND_RIGHT_SPEAKER); - else - play_sound(sounds[SND_RICOCHET], SOUND_CENTER_SPEAKER); - } - } - } - - - /* Bump into other bad guys: */ - - for (j = 0; j < NUM_BAD_GUYS; j++) - { - if (j != i && bad_guys[j].alive && - !bad_guys[j].dying && !bad_guys[i].dying && - bad_guys[i].x >= bad_guys[j].x - 32 && - bad_guys[i].x <= bad_guys[j].x + 32 && - bad_guys[i].y >= bad_guys[j].y - 32 && - bad_guys[i].y <= bad_guys[j].y + 32) - { - if (bad_guys[i].mode != KICK) - bad_guys[i].dir = !bad_guys[i].dir; - else - { - /* We're in kick mode, kill the other guy: */ - - bad_guys[j].dying = FALLING; - bad_guys[j].ym = -8; - play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER); - - add_score(bad_guys[i].x - scroll_x, - bad_guys[i].y, 100); - } - } - } - - - /* Fall if we get off the ground: */ - - if (bad_guys[i].dying != FALLING) - { - if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0) && - bad_guys[i].ym < MAX_YM) - { - bad_guys[i].ym = bad_guys[i].ym + GRAVITY; - } - else - { - /* Land: */ - - if (bad_guys[i].ym > 0) - { - bad_guys[i].y = (bad_guys[i].y / 32) * 32; - bad_guys[i].ym = 0; - } - } - } - else - bad_guys[i].ym = bad_guys[i].ym + GRAVITY; - - if (bad_guys[i].y > 480) - bad_guys[i].alive = NO; - } - else if (bad_guys[i].kind == BAD_MONEY) - { - /* --- MONEY BAGS: --- */ - - - /* Move vertically: */ - - bad_guys[i].y = bad_guys[i].y + bad_guys[i].ym; - - - /* Fall if we get off the ground: */ - - if (bad_guys[i].dying != FALLING) - { - if (!issolid(bad_guys[i].x, bad_guys[i].y + 32, 0)) - { - if (bad_guys[i].ym < MAX_YM) - { - bad_guys[i].ym = bad_guys[i].ym + GRAVITY; - } - } - else - { - /* Land: */ - - if (bad_guys[i].ym > 0) - { - bad_guys[i].y = (bad_guys[i].y / 32) * 32; - bad_guys[i].ym = -MAX_YM; - } - } - } - else - bad_guys[i].ym = bad_guys[i].ym + GRAVITY; - - if (bad_guys[i].y > 480) - bad_guys[i].alive = NO; - } - else if (bad_guys[i].kind == -1) - {} - - - /* Kill it if the player jumped on it: */ - - if (!bad_guys[i].dying && !tux_dying && !tux_safe && - tux_x + scroll_x >= bad_guys[i].x - 32 && - tux_x + scroll_x <= bad_guys[i].x + 32 && - tux_y >= bad_guys[i].y - 32 && - tux_y <= bad_guys[i].y - 8 - /* && - tux_ym >= 0 */) - { - if (bad_guys[i].kind == BAD_BSOD) - { - bad_guys[i].dying = SQUISHED; - bad_guys[i].timer = 16; - tux_ym = -KILL_BOUNCE_YM; - - add_score(bad_guys[i].x - scroll_x, bad_guys[i].y, - 50 * score_multiplier); - - play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER); - } - else if (bad_guys[i].kind == BAD_LAPTOP) - { - if (bad_guys[i].mode != FLAT) - { - /* Flatten! */ - - play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER); - bad_guys[i].mode = FLAT; - - bad_guys[i].timer = 64; - - tux_y = tux_y - 32; - } - else - { - /* Kick! */ - - bad_guys[i].mode = KICK; - play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER); - - if (tux_x + scroll_x <= bad_guys[i].x) - bad_guys[i].dir = RIGHT; - else - bad_guys[i].dir = LEFT; - - bad_guys[i].timer = 8; - } - - tux_ym = -KILL_BOUNCE_YM; - - add_score(bad_guys[i].x - scroll_x, - bad_guys[i].y, - 25 * score_multiplier); - - /* play_sound(sounds[SND_SQUISH]); */ - } - else if (bad_guys[i].kind == -1) - {} - - score_multiplier++; - } - - - /* Hurt the player if he just touched it: */ - - if (!bad_guys[i].dying && !tux_dying && - !tux_safe && - tux_x + scroll_x >= bad_guys[i].x - 32 && - tux_x + scroll_x <= bad_guys[i].x + 32 && - tux_y >= bad_guys[i].y - 32 && - tux_y <= bad_guys[i].y + 32) - { - if (bad_guys[i].mode == FLAT) - { - /* Kick: */ - - bad_guys[i].mode = KICK; - play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER); - - if (tux_x + scroll_x <= bad_guys[i].x) - { - bad_guys[i].dir = RIGHT; - bad_guys[i].x = bad_guys[i].x + 16; - } - else - { - bad_guys[i].dir = LEFT; - bad_guys[i].x = bad_guys[i].x - 16; - } - - bad_guys[i].timer = 8; - } - else if (bad_guys[i].mode == KICK) - { - if (tux_y < bad_guys[i].y - 16 && - bad_guys[i].timer == 0) - { - /* Step on (stop being kicked) */ - - bad_guys[i].mode = FLAT; - play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER); - bad_guys[i].timer = 64; - } - else - { - /* Hurt if you get hit by kicked laptop: */ - - if (bad_guys[i].timer == 0) - { - if (tux_invincible_time == 0) - { - killtux(SHRINK); - } - else - { - bad_guys[i].dying = FALLING; - bad_guys[i].ym = -8; - play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER); - } - } - } - } - else - { - if (tux_invincible_time == 0) - { - killtux(SHRINK); - } - else - { - bad_guys[i].dying = FALLING; - bad_guys[i].ym = -8; - play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER); - } - } - } - - - /* Handle mode timer: */ - - if (bad_guys[i].mode == FLAT) - { - bad_guys[i].timer--; - - if (bad_guys[i].timer <= 0) - bad_guys[i].mode = NORMAL; - } - else if (bad_guys[i].mode == KICK) - { - if (bad_guys[i].timer > 0) - bad_guys[i].timer--; - } - - - /* Handle dying timer: */ - - if (bad_guys[i].dying == SQUISHED) - { - bad_guys[i].timer--; - - - /* Remove it if time's up: */ - - if (bad_guys[i].timer <= 0) - bad_guys[i].alive = NO; - } - - - /* Remove if it's far off the screen: */ - - if (bad_guys[i].x < scroll_x - OFFSCREEN_DISTANCE) - bad_guys[i].alive = NO; - } - else /* !seen */ - { - /* Once it's on screen, it's activated! */ - - if (bad_guys[i].x <= scroll_x + 640 + OFFSCREEN_DISTANCE) - bad_guys[i].seen = YES; - } - } - } - - - /* Handle skidding: */ - - if (tux_skidding > 0) - { - tux_skidding--; - } - - return -1; -} - -/* --- GAME DRAW! --- */ - -void game_draw() -{ - int x, y, i; - - /* Draw screen: */ - - if (tux_dying && (frame % 4) == 0) - clearscreen(255, 255, 255); - else - { - if (super_bkgd_time == 0) - clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); - else - drawimage(img_super_bkgd, 0, 0, NO_UPDATE); - } - - - /* Draw background: */ - - for (y = 0; y < 15; y++) - { - for (x = 0; x < 21; x++) - { - drawshape(x * 32 - (scroll_x % 32), y * 32, - current_level.tiles[y][x + (scroll_x / 32)]); - } - } - - - /* (Bouncy bricks): */ - - for (i = 0; i < NUM_BOUNCY_BRICKS; i++) - { - if (bouncy_bricks[i].alive) - { - if (bouncy_bricks[i].x >= scroll_x - 32 && - bouncy_bricks[i].x <= scroll_x + 640) - { - dest.x = bouncy_bricks[i].x - scroll_x; - dest.y = bouncy_bricks[i].y; - dest.w = 32; - dest.h = 32; - - SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, - current_level.bkgd_red, - current_level.bkgd_green, - current_level.bkgd_blue)); - - drawshape(bouncy_bricks[i].x - scroll_x, - bouncy_bricks[i].y + bouncy_bricks[i].offset, - bouncy_bricks[i].shape); - } - } - } - - - /* (Bad guys): */ - - for (i = 0; i < NUM_BAD_GUYS; i++) - { - if (bad_guys[i].alive && - bad_guys[i].x > scroll_x - 32 && - bad_guys[i].x < scroll_x + 640) - { - if (bad_guys[i].kind == BAD_BSOD) - { - /* --- BLUE SCREEN OF DEATH MONSTER: --- */ - - if (bad_guys[i].dying == NO) - { - /* Alive: */ - - if (bad_guys[i].dir == LEFT) - { - drawimage(img_bsod_left[(frame / 5) % 4], - bad_guys[i].x - scroll_x, - bad_guys[i].y, - NO_UPDATE); - } - else - { - drawimage(img_bsod_right[(frame / 5) % 4], - bad_guys[i].x - scroll_x, - bad_guys[i].y, - NO_UPDATE); - } - } - else if (bad_guys[i].dying == FALLING) - { - /* Falling: */ - - if (bad_guys[i].dir == LEFT) - { - drawimage(img_bsod_falling_left, - bad_guys[i].x - scroll_x, - bad_guys[i].y, - NO_UPDATE); - } - else - { - drawimage(img_bsod_falling_right, - bad_guys[i].x - scroll_x, - bad_guys[i].y, - NO_UPDATE); - } - } - else if (bad_guys[i].dying == SQUISHED) - { - /* Dying - Squished: */ - - if (bad_guys[i].dir == LEFT) - { - drawimage(img_bsod_squished_left, - bad_guys[i].x - scroll_x, - bad_guys[i].y + 24, - NO_UPDATE); - } - else - { - drawimage(img_bsod_squished_right, - bad_guys[i].x - scroll_x, - bad_guys[i].y + 24, - NO_UPDATE); - } - } - } - else if (bad_guys[i].kind == BAD_LAPTOP) - { - /* --- LAPTOP MONSTER: --- */ - - if (bad_guys[i].dying == NO) - { - /* Alive: */ - - if (bad_guys[i].mode == NORMAL) - { - /* Not flat: */ - - if (bad_guys[i].dir == LEFT) - { - drawimage(img_laptop_left[(frame / 5) % 3], - bad_guys[i].x - scroll_x, - bad_guys[i].y, - NO_UPDATE); - } - else - { - drawimage(img_laptop_right[(frame / 5) % 3], - bad_guys[i].x - scroll_x, - bad_guys[i].y, - NO_UPDATE); - } - } - else - { - /* Flat: */ - - if (bad_guys[i].dir == LEFT) - { - drawimage(img_laptop_flat_left, - bad_guys[i].x - scroll_x, - bad_guys[i].y, - NO_UPDATE); - } - else - { - drawimage(img_laptop_flat_right, - bad_guys[i].x - scroll_x, - bad_guys[i].y, - NO_UPDATE); - } - } - } - else if (bad_guys[i].dying == FALLING) - { - /* Falling: */ - - if (bad_guys[i].dir == LEFT) - { - drawimage(img_laptop_falling_left, - bad_guys[i].x - scroll_x, - bad_guys[i].y, - NO_UPDATE); - } - else - { - drawimage(img_laptop_falling_right, - bad_guys[i].x - scroll_x, - bad_guys[i].y, - NO_UPDATE); - } - } - } - else if (bad_guys[i].kind == BAD_MONEY) - { - if (bad_guys[i].ym > -16) - { - if (bad_guys[i].dir == LEFT) - { - drawimage(img_money_left[0], - bad_guys[i].x - scroll_x, - bad_guys[i].y, - NO_UPDATE); - } - else - { - drawimage(img_money_right[0], - bad_guys[i].x - scroll_x, - bad_guys[i].y, - NO_UPDATE); - } - } - else - { - if (bad_guys[i].dir == LEFT) - { - drawimage(img_money_left[1], - bad_guys[i].x - scroll_x, - bad_guys[i].y, - NO_UPDATE); - } - else - { - drawimage(img_money_right[1], - bad_guys[i].x - scroll_x, - bad_guys[i].y, - NO_UPDATE); - } - } - } - else if (bad_guys[i].kind == -1) - {} - } - } - - - /* (Tux): */ - - if (right == UP && left == UP) - { - tux_frame_main = 1; - tux_frame = 1; - } - else - { - if ((fire == DOWN && (frame % 2) == 0) || - (frame % 4) == 0) - tux_frame_main = (tux_frame_main + 1) % 4; - - tux_frame = tux_frame_main; - - if (tux_frame == 3) - tux_frame = 1; - } - - - if (tux_safe == 0 || (frame % 2) == 0) - { - if (tux_size == SMALL) - { - if (tux_invincible_time) - { - /* Draw cape: */ - - if (tux_dir == RIGHT) - { - drawimage(cape_right[frame % 2], - tux_x, tux_y, - NO_UPDATE); - } - else - { - drawimage(cape_left[frame % 2], - tux_x, tux_y, - NO_UPDATE); - } - } - - - if (!tux_got_coffee) - { - if (tux_dir == RIGHT) - { - drawimage(tux_right[tux_frame], tux_x, tux_y, NO_UPDATE); - } - else - { - drawimage(tux_left[tux_frame], tux_x, tux_y, NO_UPDATE); - } - } - else - { - /* Tux got coffee! */ - - if (tux_dir == RIGHT) - { - drawimage(firetux_right[tux_frame], tux_x, tux_y, NO_UPDATE); - } - else - { - drawimage(firetux_left[tux_frame], tux_x, tux_y, NO_UPDATE); - } - } - } - else - { - if (tux_invincible_time) - { - /* Draw cape: */ - - if (tux_dir == RIGHT) - { - drawimage(bigcape_right[frame % 2], - tux_x - 8 - 16, tux_y - 32, - NO_UPDATE); - } - else - { - drawimage(bigcape_left[frame % 2], - tux_x - 8, tux_y - 32, - NO_UPDATE); - } - } - - if (!tux_got_coffee) - { - if (!tux_duck) - { - if (!tux_skidding) - { - if (!jumping || tux_ym > 0) - { - if (tux_dir == RIGHT) - { - drawimage(bigtux_right[tux_frame], - tux_x - 8, tux_y - 32, - NO_UPDATE); - } - else - { - drawimage(bigtux_left[tux_frame], - tux_x - 8, tux_y - 32, - NO_UPDATE); - } - } - else - { - if (tux_dir == RIGHT) - { - drawimage(bigtux_right_jump, - tux_x - 8, tux_y - 32, - NO_UPDATE); - } - else - { - drawimage(bigtux_left_jump, - tux_x - 8, tux_y - 32, - NO_UPDATE); - } - } - } - else - { - if (tux_dir == RIGHT) - { - drawimage(skidtux_right, - tux_x - 8, tux_y - 32, - NO_UPDATE); - } - else - { - drawimage(skidtux_left, - tux_x - 8, tux_y - 32, - NO_UPDATE); - } - } - } - else - { - if (tux_dir == RIGHT) - { - drawimage(ducktux_right, tux_x - 8, tux_y - 16, - NO_UPDATE); - } - else - { - drawimage(ducktux_left, tux_x - 8, tux_y - 16, - NO_UPDATE); - } - } - } - else - { - /* Tux has coffee! */ - - if (!tux_duck) - { - if (!tux_skidding) - { - if (!jumping || tux_ym > 0) - { - if (tux_dir == RIGHT) - { - drawimage(bigfiretux_right[tux_frame], - tux_x - 8, tux_y - 32, - NO_UPDATE); - } - else - { - drawimage(bigfiretux_left[tux_frame], - tux_x - 8, tux_y - 32, - NO_UPDATE); - } - } - else - { - if (tux_dir == RIGHT) - { - drawimage(bigfiretux_right_jump, - tux_x - 8, tux_y - 32, - NO_UPDATE); - } - else - { - drawimage(bigfiretux_left_jump, - tux_x - 8, tux_y - 32, - NO_UPDATE); - } - } - } - else - { - if (tux_dir == RIGHT) - { - drawimage(skidfiretux_right, - tux_x - 8, tux_y - 32, - NO_UPDATE); - } - else - { - drawimage(skidfiretux_left, - tux_x - 8, tux_y - 32, - NO_UPDATE); - } - } - } - else - { - if (tux_dir == RIGHT) - { - drawimage(duckfiretux_right, tux_x - 8, tux_y - 16, - NO_UPDATE); - } - else - { - drawimage(duckfiretux_left, tux_x - 8, tux_y - 16, - NO_UPDATE); - } - } - } - } - } - - - /* (Bullets): */ - - for (i = 0; i < NUM_BULLETS; i++) - { - if (bullets[i].alive && - bullets[i].x >= scroll_x - 4 && - bullets[i].x <= scroll_x + 640) - { - drawimage(img_bullet, bullets[i].x - scroll_x, bullets[i].y, - NO_UPDATE); - } - } - - - /* (Floating scores): */ - - for (i = 0; i < NUM_FLOATING_SCORES; i++) - { - if (floating_scores[i].alive) - { - sprintf(str, "%d", floating_scores[i].value); - drawtext(str, - floating_scores[i].x + 16 - strlen(str) * 8, - floating_scores[i].y, - letters_gold, NO_UPDATE, 1); - } - } - - - /* (Upgrades): */ - - for (i = 0; i < NUM_UPGRADES; i++) - { - if (upgrades[i].alive) - { - if (upgrades[i].height < 32) - { - /* Rising up... */ - - dest.x = upgrades[i].x - scroll_x; - dest.y = upgrades[i].y + 32 - upgrades[i].height; - dest.w = 32; - dest.h = upgrades[i].height; - - src.x = 0; - src.y = 0; - src.w = 32; - src.h = upgrades[i].height; - - if (upgrades[i].kind == UPGRADE_MINTS) - SDL_BlitSurface(img_mints, &src, screen, &dest); - else if (upgrades[i].kind == UPGRADE_COFFEE) - SDL_BlitSurface(img_coffee, &src, screen, &dest); - else if (upgrades[i].kind == UPGRADE_HERRING) - SDL_BlitSurface(img_golden_herring, &src, screen, &dest); - } - else - { - if (upgrades[i].kind == UPGRADE_MINTS) - { - drawimage(img_mints, - upgrades[i].x - scroll_x, upgrades[i].y, - NO_UPDATE); - } - else if (upgrades[i].kind == UPGRADE_COFFEE) - { - drawimage(img_coffee, - upgrades[i].x - scroll_x, upgrades[i].y, - NO_UPDATE); - } - else if (upgrades[i].kind == UPGRADE_HERRING) - { - drawimage(img_golden_herring, - upgrades[i].x - scroll_x, upgrades[i].y, - NO_UPDATE); - } - } - } - } - - - /* (Bouncy distros): */ - - for (i = 0; i < NUM_BOUNCY_DISTROS; i++) - { - if (bouncy_distros[i].alive) - { - drawimage(img_distro[0], - bouncy_distros[i].x - scroll_x, - bouncy_distros[i].y, - NO_UPDATE); - } + bouncy_distro_draw(&bouncy_distros[i]); } @@ -2302,51 +501,12 @@ void game_draw() for (i = 0; i < NUM_BROKEN_BRICKS; i++) { - if (broken_bricks[i].alive) - { - src.x = rand() % 16; - src.y = rand() % 16; - src.w = 16; - src.h = 16; - - dest.x = broken_bricks[i].x - scroll_x; - dest.y = broken_bricks[i].y; - dest.w = 16; - dest.h = 16; - - SDL_BlitSurface(img_brick[0], &src, screen, &dest); - } - } - - - /* (Status): */ - - sprintf(str, "%d", score); - drawtext("SCORE", 0, 0, letters_blue, NO_UPDATE, 1); - drawtext(str, 96, 0, letters_gold, NO_UPDATE, 1); - - sprintf(str, "%d", highscore); - drawtext("HIGH", 0, 20, letters_blue, NO_UPDATE, 1); - drawtext(str, 96, 20, letters_gold, NO_UPDATE, 1); - - if (current_level.time_left >= TIME_WARNING || (frame % 10) < 5) - { - sprintf(str, "%d", current_level.time_left); - drawtext("TIME", 224, 0, letters_blue, NO_UPDATE, 1); - drawtext(str, 304, 0, letters_gold, NO_UPDATE, 1); - } - - sprintf(str, "%d", distros); - drawtext("DISTROS", 480, 0, letters_blue, NO_UPDATE, 1); - drawtext(str, 608, 0, letters_gold, NO_UPDATE, 1); - - drawtext("LIVES", 480, 20, letters_blue, NO_UPDATE, 1); - - for(i=0; i < lives; ++i) - { - drawimage(tux_life,565+(18*i),20,NO_UPDATE); + broken_brick_draw(&broken_bricks[i]); } + drawstatus(); + + if(game_pause) drawcenteredtext("PAUSE",230,letters_red, NO_UPDATE, 1); @@ -2379,28 +539,26 @@ int gameloop(void) menumenu = MENU_GAME; initgame(); loadshared(); - - tux_size = SMALL; - tux_got_coffee = NO; - set_defaults(); + loadlevel(¤t_level,"default",level); - loadlevelgfx(); + loadlevelgfx(¤t_level); activate_bad_guys(); loadlevelsong(); highscore = load_hs(); - levelintro(); + player_init(&tux); + levelintro(); + start_timers(); + /* --- MAIN GAME LOOP!!! --- */ done = 0; quit = 0; frame = 0; - tux_frame_main = 0; - tux_frame = 0; game_pause = 0; - + game_draw(); do { @@ -2410,10 +568,11 @@ int gameloop(void) /* Handle events: */ - old_fire = fire; + tux.input.old_fire = tux.input.fire; game_event(); + /* Handle actions: */ if(!game_pause && !show_menu) @@ -2431,29 +590,6 @@ int gameloop(void) /*Draw the current scene to the screen */ game_draw(); - /* Keep playing music: */ - - - if (!playing_music()) - { - switch (current_music) - { - case LEVEL_MUSIC: - if (current_level.time_left <= TIME_WARNING) - play_music(level_song_fast, 1); - else - play_music(level_song, 1); - break; - case HERRING_MUSIC: - play_music(herring_song, 1); - break; - case HURRYUP_MUSIC: // keep the compiler happy - case NO_MUSIC: // keep the compiler happy for the moment :-) - {} - /*default:*/ - } - } - /* Time stops in pause mode */ if(game_pause || show_menu ) { @@ -2463,23 +599,40 @@ int gameloop(void) /* Pause til next frame: */ now_time = SDL_GetTicks(); - if (now_time < last_time + FPS) - SDL_Delay(last_time + FPS - now_time); + /*if (now_time < last_time + FPS) + SDL_Delay(last_time + FPS - now_time);*/ + SDL_Delay(10); /* Handle time: */ - if ((frame % 10) == 0 && current_level.time_left > 0) + if (timer_check(&time_left)) + { + /* are we low on time ? */ + if ((timer_get_left(&time_left) < TIME_WARNING) + && (current_music != HURRYUP_MUSIC)) { - current_level.time_left--; + current_music = HURRYUP_MUSIC; + /* stop the others music, prepare to play the fast music */ + if (playing_music()) + { + halt_music(); + } + } + + } + else + player_kill(&tux,KILL); + - /* Stop the music; it will start again, faster! */ - if (current_level.time_left == TIME_WARNING) - halt_music(); + /* Keep playing the correct music: */ - if (current_level.time_left <= 0) - killtux(KILL); + if (!playing_music()) + { + play_current_music(); } + + } while (!done && !quit); @@ -2501,34 +654,16 @@ void initgame(void) level = 1; score = 0; distros = 0; - lives = 3; } -/* Load graphics: */ +/* Free music data for this level: */ -void loadlevelgfx(void) +void unloadlevelsong(void) { - - img_brick[0] = load_level_image(current_level.theme,"brick0.png", IGNORE_ALPHA); - img_brick[1] = load_level_image(current_level.theme,"brick1.png", IGNORE_ALPHA); - - img_solid[0] = load_level_image(current_level.theme,"solid0.png", USE_ALPHA); - img_solid[1] = load_level_image(current_level.theme,"solid1.png", USE_ALPHA); - img_solid[2] = load_level_image(current_level.theme,"solid2.png", USE_ALPHA); - img_solid[3] = load_level_image(current_level.theme,"solid3.png", USE_ALPHA); - - img_bkgd[0][0] = load_level_image(current_level.theme,"bkgd-00.png", USE_ALPHA); - img_bkgd[0][1] = load_level_image(current_level.theme,"bkgd-01.png", USE_ALPHA); - img_bkgd[0][2] = load_level_image(current_level.theme,"bkgd-02.png", USE_ALPHA); - img_bkgd[0][3] = load_level_image(current_level.theme,"bkgd-03.png", USE_ALPHA); - - img_bkgd[1][0] = load_level_image(current_level.theme,"bkgd-10.png", USE_ALPHA); - img_bkgd[1][1] = load_level_image(current_level.theme,"bkgd-11.png", USE_ALPHA); - img_bkgd[1][2] = load_level_image(current_level.theme,"bkgd-12.png", USE_ALPHA); - img_bkgd[1][3] = load_level_image(current_level.theme,"bkgd-13.png", USE_ALPHA); + free_music(level_song); + free_music(level_song_fast); } - /* Load music: */ void loadlevelsong(void) @@ -2543,7 +678,7 @@ void loadlevelsong(void) level_song = load_song(song_path); free(song_path); - + song_path = (char *) malloc(sizeof(char) * (strlen(DATA_PREFIX) + strlen(current_level.song_title) + 8 + 5)); song_subtitle = strdup(current_level.song_title); @@ -2554,34 +689,6 @@ void loadlevelsong(void) free(song_path); } - -/* Free graphics data for this level: */ - -void unloadlevelgfx(void) -{ - int i; - - for (i = 0; i < 2; i++) - { - SDL_FreeSurface(img_brick[i]); - } - for (i = 0; i < 4; i++) - { - SDL_FreeSurface(img_solid[i]); - SDL_FreeSurface(img_bkgd[0][i]); - SDL_FreeSurface(img_bkgd[1][i]); - } -} - - -/* Free music data for this level: */ - -void unloadlevelsong(void) -{ - free_music(level_song); -} - - /* Load graphics/sounds shared between all levels: */ void loadshared(void) @@ -2591,231 +698,200 @@ void loadshared(void) /* Tuxes: */ - tux_right[0] = load_image(DATA_PREFIX "/images/shared/tux-right-0.png", - USE_ALPHA); - - tux_right[1] = load_image(DATA_PREFIX "/images/shared/tux-right-1.png", - USE_ALPHA); - - tux_right[2] = load_image(DATA_PREFIX "/images/shared/tux-right-2.png", - USE_ALPHA); - - tux_left[0] = load_image(DATA_PREFIX "/images/shared/tux-left-0.png", - USE_ALPHA); - - tux_left[1] = load_image(DATA_PREFIX "/images/shared/tux-left-1.png", - USE_ALPHA); - - tux_left[2] = load_image(DATA_PREFIX "/images/shared/tux-left-2.png", - USE_ALPHA); - - firetux_right[0] = load_image(DATA_PREFIX "/images/shared/firetux-right-0.png", - USE_ALPHA); - - firetux_right[1] = load_image(DATA_PREFIX "/images/shared/firetux-right-1.png", - USE_ALPHA); - - firetux_right[2] = load_image(DATA_PREFIX "/images/shared/firetux-right-2.png", - USE_ALPHA); + texture_load(&tux_right[0],DATA_PREFIX "/images/shared/tux-right-0.png", USE_ALPHA); + texture_load(&tux_right[1],DATA_PREFIX "/images/shared/tux-right-1.png", USE_ALPHA); + texture_load(&tux_right[2],DATA_PREFIX "/images/shared/tux-right-2.png", USE_ALPHA); - firetux_left[0] = load_image(DATA_PREFIX "/images/shared/firetux-left-0.png", - USE_ALPHA); + texture_load(&tux_left[0],DATA_PREFIX "/images/shared/tux-left-0.png", USE_ALPHA); + texture_load(&tux_left[1],DATA_PREFIX "/images/shared/tux-left-1.png", USE_ALPHA); + texture_load(&tux_left[2],DATA_PREFIX "/images/shared/tux-left-2.png", USE_ALPHA); + + texture_load(&firetux_right[0],DATA_PREFIX "/images/shared/firetux-right-0.png", USE_ALPHA); + texture_load(&firetux_right[1],DATA_PREFIX "/images/shared/firetux-right-1.png", USE_ALPHA); + texture_load(&firetux_right[2],DATA_PREFIX "/images/shared/firetux-right-2.png", USE_ALPHA); - firetux_left[1] = load_image(DATA_PREFIX "/images/shared/firetux-left-1.png", - USE_ALPHA); + texture_load(&firetux_left[0],DATA_PREFIX "/images/shared/firetux-left-0.png", USE_ALPHA); + texture_load(&firetux_left[1],DATA_PREFIX "/images/shared/firetux-left-1.png", USE_ALPHA); + texture_load(&firetux_left[2],DATA_PREFIX "/images/shared/firetux-left-2.png", USE_ALPHA); - firetux_left[2] = load_image(DATA_PREFIX "/images/shared/firetux-left-2.png", - USE_ALPHA); - cape_right[0] = load_image(DATA_PREFIX "/images/shared/cape-right-0.png", + texture_load(&cape_right[0] ,DATA_PREFIX "/images/shared/cape-right-0.png", USE_ALPHA); - cape_right[1] = load_image(DATA_PREFIX "/images/shared/cape-right-1.png", + texture_load(&cape_right[1] ,DATA_PREFIX "/images/shared/cape-right-1.png", USE_ALPHA); - cape_left[0] = load_image(DATA_PREFIX "/images/shared/cape-left-0.png", + texture_load(&cape_left[0] ,DATA_PREFIX "/images/shared/cape-left-0.png", USE_ALPHA); - cape_left[1] = load_image(DATA_PREFIX "/images/shared/cape-left-1.png", + texture_load(&cape_left[1] ,DATA_PREFIX "/images/shared/cape-left-1.png", USE_ALPHA); - bigtux_right[0] = load_image(DATA_PREFIX "/images/shared/bigtux-right-0.png", + texture_load(&bigtux_right[0] ,DATA_PREFIX "/images/shared/bigtux-right-0.png", USE_ALPHA); - bigtux_right[1] = load_image(DATA_PREFIX "/images/shared/bigtux-right-1.png", + texture_load(&bigtux_right[1] ,DATA_PREFIX "/images/shared/bigtux-right-1.png", USE_ALPHA); - bigtux_right[2] = load_image(DATA_PREFIX "/images/shared/bigtux-right-2.png", + texture_load(&bigtux_right[2] ,DATA_PREFIX "/images/shared/bigtux-right-2.png", USE_ALPHA); - bigtux_right_jump = - load_image(DATA_PREFIX "/images/shared/bigtux-right-jump.png", USE_ALPHA); + texture_load(&bigtux_right_jump ,DATA_PREFIX "/images/shared/bigtux-right-jump.png", USE_ALPHA); - bigtux_left[0] = load_image(DATA_PREFIX "/images/shared/bigtux-left-0.png", + texture_load(&bigtux_left[0] ,DATA_PREFIX "/images/shared/bigtux-left-0.png", USE_ALPHA); - bigtux_left[1] = load_image(DATA_PREFIX "/images/shared/bigtux-left-1.png", + texture_load(&bigtux_left[1] ,DATA_PREFIX "/images/shared/bigtux-left-1.png", USE_ALPHA); - bigtux_left[2] = load_image(DATA_PREFIX "/images/shared/bigtux-left-2.png", + texture_load(&bigtux_left[2] ,DATA_PREFIX "/images/shared/bigtux-left-2.png", USE_ALPHA); - bigtux_left_jump = - load_image(DATA_PREFIX "/images/shared/bigtux-left-jump.png", USE_ALPHA); + texture_load(&bigtux_left_jump ,DATA_PREFIX "/images/shared/bigtux-left-jump.png", USE_ALPHA); - bigcape_right[0] = - load_image(DATA_PREFIX "/images/shared/bigcape-right-0.png", + texture_load(&bigcape_right[0] ,DATA_PREFIX "/images/shared/bigcape-right-0.png", USE_ALPHA); - bigcape_right[1] = - load_image(DATA_PREFIX "/images/shared/bigcape-right-1.png", + texture_load(&bigcape_right[1] ,DATA_PREFIX "/images/shared/bigcape-right-1.png", USE_ALPHA); - bigcape_left[0] = - load_image(DATA_PREFIX "/images/shared/bigcape-left-0.png", + texture_load(&bigcape_left[0] ,DATA_PREFIX "/images/shared/bigcape-left-0.png", USE_ALPHA); - bigcape_left[1] = - load_image(DATA_PREFIX "/images/shared/bigcape-left-1.png", + texture_load(&bigcape_left[1] ,DATA_PREFIX "/images/shared/bigcape-left-1.png", USE_ALPHA); - bigfiretux_right[0] = load_image(DATA_PREFIX "/images/shared/bigfiretux-right-0.png", + texture_load(&bigfiretux_right[0] ,DATA_PREFIX "/images/shared/bigfiretux-right-0.png", USE_ALPHA); - bigfiretux_right[1] = load_image(DATA_PREFIX "/images/shared/bigfiretux-right-1.png", + texture_load(&bigfiretux_right[1] ,DATA_PREFIX "/images/shared/bigfiretux-right-1.png", USE_ALPHA); - bigfiretux_right[2] = load_image(DATA_PREFIX "/images/shared/bigfiretux-right-2.png", + texture_load(&bigfiretux_right[2] ,DATA_PREFIX "/images/shared/bigfiretux-right-2.png", USE_ALPHA); - bigfiretux_right_jump = - load_image(DATA_PREFIX "/images/shared/bigfiretux-right-jump.png", USE_ALPHA); + texture_load(&bigfiretux_right_jump ,DATA_PREFIX "/images/shared/bigfiretux-right-jump.png", USE_ALPHA); - bigfiretux_left[0] = load_image(DATA_PREFIX "/images/shared/bigfiretux-left-0.png", + texture_load(&bigfiretux_left[0] ,DATA_PREFIX "/images/shared/bigfiretux-left-0.png", USE_ALPHA); - bigfiretux_left[1] = load_image(DATA_PREFIX "/images/shared/bigfiretux-left-1.png", + texture_load(&bigfiretux_left[1] ,DATA_PREFIX "/images/shared/bigfiretux-left-1.png", USE_ALPHA); - bigfiretux_left[2] = load_image(DATA_PREFIX "/images/shared/bigfiretux-left-2.png", + texture_load(&bigfiretux_left[2] ,DATA_PREFIX "/images/shared/bigfiretux-left-2.png", USE_ALPHA); - bigfiretux_left_jump = - load_image(DATA_PREFIX "/images/shared/bigfiretux-left-jump.png", USE_ALPHA); + texture_load(&bigfiretux_left_jump ,DATA_PREFIX "/images/shared/bigfiretux-left-jump.png", USE_ALPHA); - bigcape_right[0] = - load_image(DATA_PREFIX "/images/shared/bigcape-right-0.png", + texture_load(&bigcape_right[0] ,DATA_PREFIX "/images/shared/bigcape-right-0.png", USE_ALPHA); - bigcape_right[1] = - load_image(DATA_PREFIX "/images/shared/bigcape-right-1.png", + texture_load(&bigcape_right[1] ,DATA_PREFIX "/images/shared/bigcape-right-1.png", USE_ALPHA); - bigcape_left[0] = - load_image(DATA_PREFIX "/images/shared/bigcape-left-0.png", + texture_load(&bigcape_left[0] ,DATA_PREFIX "/images/shared/bigcape-left-0.png", USE_ALPHA); - bigcape_left[1] = - load_image(DATA_PREFIX "/images/shared/bigcape-left-1.png", + texture_load(&bigcape_left[1] ,DATA_PREFIX "/images/shared/bigcape-left-1.png", USE_ALPHA); - ducktux_right = load_image(DATA_PREFIX + texture_load(&ducktux_right ,DATA_PREFIX "/images/shared/ducktux-right.png", USE_ALPHA); - ducktux_left = load_image(DATA_PREFIX + texture_load(&ducktux_left ,DATA_PREFIX "/images/shared/ducktux-left.png", USE_ALPHA); - skidtux_right = load_image(DATA_PREFIX + texture_load(&skidtux_right ,DATA_PREFIX "/images/shared/skidtux-right.png", USE_ALPHA); - skidtux_left = load_image(DATA_PREFIX + texture_load(&skidtux_left ,DATA_PREFIX "/images/shared/skidtux-left.png", USE_ALPHA); - duckfiretux_right = load_image(DATA_PREFIX + texture_load(&duckfiretux_right ,DATA_PREFIX "/images/shared/duckfiretux-right.png", USE_ALPHA); - duckfiretux_left = load_image(DATA_PREFIX + texture_load(&duckfiretux_left ,DATA_PREFIX "/images/shared/duckfiretux-left.png", USE_ALPHA); - skidfiretux_right = load_image(DATA_PREFIX + texture_load(&skidfiretux_right ,DATA_PREFIX "/images/shared/skidfiretux-right.png", USE_ALPHA); - skidfiretux_left = load_image(DATA_PREFIX + texture_load(&skidfiretux_left ,DATA_PREFIX "/images/shared/skidfiretux-left.png", USE_ALPHA); /* Boxes: */ - img_box_full = load_image(DATA_PREFIX "/images/shared/box-full.png", + texture_load(&img_box_full ,DATA_PREFIX "/images/shared/box-full.png", IGNORE_ALPHA); - img_box_empty = load_image(DATA_PREFIX "/images/shared/box-empty.png", + texture_load(&img_box_empty ,DATA_PREFIX "/images/shared/box-empty.png", IGNORE_ALPHA); /* Water: */ - img_water = load_image(DATA_PREFIX "/images/shared/water.png", IGNORE_ALPHA); + texture_load(&img_water ,DATA_PREFIX "/images/shared/water.png", IGNORE_ALPHA); - img_waves[0] = load_image(DATA_PREFIX "/images/shared/waves-0.png", + texture_load(&img_waves[0] ,DATA_PREFIX "/images/shared/waves-0.png", USE_ALPHA); - img_waves[1] = load_image(DATA_PREFIX "/images/shared/waves-1.png", + texture_load(&img_waves[1] ,DATA_PREFIX "/images/shared/waves-1.png", USE_ALPHA); - img_waves[2] = load_image(DATA_PREFIX "/images/shared/waves-2.png", + texture_load(&img_waves[2] ,DATA_PREFIX "/images/shared/waves-2.png", USE_ALPHA); /* Pole: */ - img_pole = load_image(DATA_PREFIX "/images/shared/pole.png", USE_ALPHA); - img_poletop = load_image(DATA_PREFIX "/images/shared/poletop.png", + texture_load(&img_pole ,DATA_PREFIX "/images/shared/pole.png", USE_ALPHA); + texture_load(&img_poletop ,DATA_PREFIX "/images/shared/poletop.png", USE_ALPHA); /* Flag: */ - img_flag[0] = load_image(DATA_PREFIX "/images/shared/flag-0.png", + texture_load(&img_flag[0] ,DATA_PREFIX "/images/shared/flag-0.png", USE_ALPHA); - img_flag[1] = load_image(DATA_PREFIX "/images/shared/flag-1.png", + texture_load(&img_flag[1] ,DATA_PREFIX "/images/shared/flag-1.png", USE_ALPHA); /* Cloud: */ - img_cloud[0][0] = load_image(DATA_PREFIX "/images/shared/cloud-00.png", + texture_load(&img_cloud[0][0] ,DATA_PREFIX "/images/shared/cloud-00.png", USE_ALPHA); - img_cloud[0][1] = load_image(DATA_PREFIX "/images/shared/cloud-01.png", + texture_load(&img_cloud[0][1] ,DATA_PREFIX "/images/shared/cloud-01.png", USE_ALPHA); - img_cloud[0][2] = load_image(DATA_PREFIX "/images/shared/cloud-02.png", + texture_load(&img_cloud[0][2] ,DATA_PREFIX "/images/shared/cloud-02.png", USE_ALPHA); - img_cloud[0][3] = load_image(DATA_PREFIX "/images/shared/cloud-03.png", + texture_load(&img_cloud[0][3] ,DATA_PREFIX "/images/shared/cloud-03.png", USE_ALPHA); - img_cloud[1][0] = load_image(DATA_PREFIX "/images/shared/cloud-10.png", + texture_load(&img_cloud[1][0] ,DATA_PREFIX "/images/shared/cloud-10.png", USE_ALPHA); - img_cloud[1][1] = load_image(DATA_PREFIX "/images/shared/cloud-11.png", + texture_load(&img_cloud[1][1] ,DATA_PREFIX "/images/shared/cloud-11.png", USE_ALPHA); - img_cloud[1][2] = load_image(DATA_PREFIX "/images/shared/cloud-12.png", + texture_load(&img_cloud[1][2] ,DATA_PREFIX "/images/shared/cloud-12.png", USE_ALPHA); - img_cloud[1][3] = load_image(DATA_PREFIX "/images/shared/cloud-13.png", + texture_load(&img_cloud[1][3] ,DATA_PREFIX "/images/shared/cloud-13.png", USE_ALPHA); @@ -2823,115 +899,113 @@ void loadshared(void) /* (BSOD) */ - img_bsod_left[0] = load_image(DATA_PREFIX + texture_load(&img_bsod_left[0] ,DATA_PREFIX "/images/shared/bsod-left-0.png", USE_ALPHA); - img_bsod_left[1] = load_image(DATA_PREFIX + texture_load(&img_bsod_left[1] ,DATA_PREFIX "/images/shared/bsod-left-1.png", USE_ALPHA); - img_bsod_left[2] = load_image(DATA_PREFIX + texture_load(&img_bsod_left[2] ,DATA_PREFIX "/images/shared/bsod-left-2.png", USE_ALPHA); - img_bsod_left[3] = load_image(DATA_PREFIX + texture_load(&img_bsod_left[3] ,DATA_PREFIX "/images/shared/bsod-left-3.png", USE_ALPHA); - img_bsod_right[0] = load_image(DATA_PREFIX + texture_load(&img_bsod_right[0] ,DATA_PREFIX "/images/shared/bsod-right-0.png", USE_ALPHA); - img_bsod_right[1] = load_image(DATA_PREFIX + texture_load(&img_bsod_right[1] ,DATA_PREFIX "/images/shared/bsod-right-1.png", USE_ALPHA); - img_bsod_right[2] = load_image(DATA_PREFIX + texture_load(&img_bsod_right[2] ,DATA_PREFIX "/images/shared/bsod-right-2.png", USE_ALPHA); - img_bsod_right[3] = load_image(DATA_PREFIX + texture_load(&img_bsod_right[3] ,DATA_PREFIX "/images/shared/bsod-right-3.png", USE_ALPHA); - img_bsod_squished_left = load_image(DATA_PREFIX + texture_load(&img_bsod_squished_left ,DATA_PREFIX "/images/shared/bsod-squished-left.png", USE_ALPHA); - img_bsod_squished_right = load_image(DATA_PREFIX + texture_load(&img_bsod_squished_right ,DATA_PREFIX "/images/shared/bsod-squished-right.png", USE_ALPHA); - img_bsod_falling_left = load_image(DATA_PREFIX + texture_load(&img_bsod_falling_left ,DATA_PREFIX "/images/shared/bsod-falling-left.png", USE_ALPHA); - img_bsod_falling_right = load_image(DATA_PREFIX + texture_load(&img_bsod_falling_right ,DATA_PREFIX "/images/shared/bsod-falling-right.png", USE_ALPHA); /* (Laptop) */ - img_laptop_left[0] = load_image(DATA_PREFIX + texture_load(&img_laptop_left[0] ,DATA_PREFIX "/images/shared/laptop-left-0.png", USE_ALPHA); - img_laptop_left[1] = load_image(DATA_PREFIX + texture_load(&img_laptop_left[1] ,DATA_PREFIX "/images/shared/laptop-left-1.png", USE_ALPHA); - img_laptop_left[2] = load_image(DATA_PREFIX + texture_load(&img_laptop_left[2] ,DATA_PREFIX "/images/shared/laptop-left-2.png", USE_ALPHA); - img_laptop_right[0] = load_image(DATA_PREFIX + texture_load(&img_laptop_right[0] ,DATA_PREFIX "/images/shared/laptop-right-0.png", USE_ALPHA); - img_laptop_right[1] = load_image(DATA_PREFIX + texture_load(&img_laptop_right[1] ,DATA_PREFIX "/images/shared/laptop-right-1.png", USE_ALPHA); - img_laptop_right[2] = load_image(DATA_PREFIX + texture_load(&img_laptop_right[2] ,DATA_PREFIX "/images/shared/laptop-right-2.png", USE_ALPHA); - img_laptop_flat_left = load_image(DATA_PREFIX + texture_load(&img_laptop_flat_left ,DATA_PREFIX "/images/shared/laptop-flat-left.png", USE_ALPHA); - img_laptop_flat_right = load_image(DATA_PREFIX + texture_load(&img_laptop_flat_right ,DATA_PREFIX "/images/shared/laptop-flat-right.png", USE_ALPHA); - img_laptop_falling_left = - load_image(DATA_PREFIX + texture_load(&img_laptop_falling_left ,DATA_PREFIX "/images/shared/laptop-falling-left.png", USE_ALPHA); - img_laptop_falling_right = - load_image(DATA_PREFIX + texture_load(&img_laptop_falling_right ,DATA_PREFIX "/images/shared/laptop-falling-right.png", USE_ALPHA); /* (Money) */ - img_money_left[0] = load_image(DATA_PREFIX + texture_load(&img_money_left[0] ,DATA_PREFIX "/images/shared/bag-left-0.png", USE_ALPHA); - img_money_left[1] = load_image(DATA_PREFIX + texture_load(&img_money_left[1] ,DATA_PREFIX "/images/shared/bag-left-1.png", USE_ALPHA); - img_money_right[0] = load_image(DATA_PREFIX + texture_load(&img_money_right[0] ,DATA_PREFIX "/images/shared/bag-right-0.png", USE_ALPHA); - img_money_right[1] = load_image(DATA_PREFIX + texture_load(&img_money_right[1] ,DATA_PREFIX "/images/shared/bag-right-1.png", USE_ALPHA); @@ -2939,49 +1013,48 @@ void loadshared(void) /* Upgrades: */ - img_mints = load_image(DATA_PREFIX "/images/shared/mints.png", USE_ALPHA); - img_coffee = load_image(DATA_PREFIX "/images/shared/coffee.png", USE_ALPHA); + texture_load(&img_mints ,DATA_PREFIX "/images/shared/mints.png", USE_ALPHA); + texture_load(&img_coffee ,DATA_PREFIX "/images/shared/coffee.png", USE_ALPHA); /* Weapons: */ - img_bullet = load_image(DATA_PREFIX "/images/shared/bullet.png", USE_ALPHA); + texture_load(&img_bullet ,DATA_PREFIX "/images/shared/bullet.png", USE_ALPHA); - img_red_glow = load_image(DATA_PREFIX "/images/shared/red-glow.png", + texture_load(&img_red_glow ,DATA_PREFIX "/images/shared/red-glow.png", USE_ALPHA); /* Distros: */ - img_distro[0] = load_image(DATA_PREFIX "/images/shared/distro-0.png", + texture_load(&img_distro[0] ,DATA_PREFIX "/images/shared/distro-0.png", USE_ALPHA); - img_distro[1] = load_image(DATA_PREFIX "/images/shared/distro-1.png", + texture_load(&img_distro[1] ,DATA_PREFIX "/images/shared/distro-1.png", USE_ALPHA); - img_distro[2] = load_image(DATA_PREFIX "/images/shared/distro-2.png", + texture_load(&img_distro[2] ,DATA_PREFIX "/images/shared/distro-2.png", USE_ALPHA); - img_distro[3] = load_image(DATA_PREFIX "/images/shared/distro-3.png", + texture_load(&img_distro[3] ,DATA_PREFIX "/images/shared/distro-3.png", USE_ALPHA); /* Tux life: */ - tux_life = load_image(DATA_PREFIX "/images/shared/tux-life.png", + texture_load(&tux_life ,DATA_PREFIX "/images/shared/tux-life.png", USE_ALPHA); /* Herring: */ - img_golden_herring = - load_image(DATA_PREFIX "/images/shared/golden-herring.png", + texture_load(&img_golden_herring, DATA_PREFIX "/images/shared/golden-herring.png", USE_ALPHA); /* Super background: */ - img_super_bkgd = load_image(DATA_PREFIX "/images/shared/super-bkgd.png", + texture_load(&img_super_bkgd ,DATA_PREFIX "/images/shared/super-bkgd.png", IGNORE_ALPHA); @@ -3018,83 +1091,83 @@ void unloadshared(void) for (i = 0; i < 3; i++) { - SDL_FreeSurface(tux_right[i]); - SDL_FreeSurface(tux_left[i]); - SDL_FreeSurface(bigtux_right[i]); - SDL_FreeSurface(bigtux_left[i]); + texture_free(&tux_right[i]); + texture_free(&tux_left[i]); + texture_free(&bigtux_right[i]); + texture_free(&bigtux_left[i]); } - SDL_FreeSurface(bigtux_right_jump); - SDL_FreeSurface(bigtux_left_jump); + texture_free(&bigtux_right_jump); + texture_free(&bigtux_left_jump); for (i = 0; i < 2; i++) { - SDL_FreeSurface(cape_right[i]); - SDL_FreeSurface(cape_left[i]); - SDL_FreeSurface(bigcape_right[i]); - SDL_FreeSurface(bigcape_left[i]); + texture_free(&cape_right[i]); + texture_free(&cape_left[i]); + texture_free(&bigcape_right[i]); + texture_free(&bigcape_left[i]); } - SDL_FreeSurface(ducktux_left); - SDL_FreeSurface(ducktux_right); + texture_free(&ducktux_left); + texture_free(&ducktux_right); - SDL_FreeSurface(skidtux_left); - SDL_FreeSurface(skidtux_right); + texture_free(&skidtux_left); + texture_free(&skidtux_right); for (i = 0; i < 4; i++) { - SDL_FreeSurface(img_bsod_left[i]); - SDL_FreeSurface(img_bsod_right[i]); + texture_free(&img_bsod_left[i]); + texture_free(&img_bsod_right[i]); } - SDL_FreeSurface(img_bsod_squished_left); - SDL_FreeSurface(img_bsod_squished_right); + texture_free(&img_bsod_squished_left); + texture_free(&img_bsod_squished_right); - SDL_FreeSurface(img_bsod_falling_left); - SDL_FreeSurface(img_bsod_falling_right); + texture_free(&img_bsod_falling_left); + texture_free(&img_bsod_falling_right); for (i = 0; i < 3; i++) { - SDL_FreeSurface(img_laptop_left[i]); - SDL_FreeSurface(img_laptop_right[i]); + texture_free(&img_laptop_left[i]); + texture_free(&img_laptop_right[i]); } - SDL_FreeSurface(img_laptop_flat_left); - SDL_FreeSurface(img_laptop_flat_right); + texture_free(&img_laptop_flat_left); + texture_free(&img_laptop_flat_right); - SDL_FreeSurface(img_laptop_falling_left); - SDL_FreeSurface(img_laptop_falling_right); + texture_free(&img_laptop_falling_left); + texture_free(&img_laptop_falling_right); for (i = 0; i < 2; i++) { - SDL_FreeSurface(img_money_left[i]); - SDL_FreeSurface(img_money_right[i]); + texture_free(&img_money_left[i]); + texture_free(&img_money_right[i]); } - SDL_FreeSurface(img_box_full); - SDL_FreeSurface(img_box_empty); + texture_free(&img_box_full); + texture_free(&img_box_empty); - SDL_FreeSurface(img_water); + texture_free(&img_water); for (i = 0; i < 3; i++) - SDL_FreeSurface(img_waves[i]); + texture_free(&img_waves[i]); - SDL_FreeSurface(img_pole); - SDL_FreeSurface(img_poletop); + texture_free(&img_pole); + texture_free(&img_poletop); for (i = 0; i < 2; i++) - SDL_FreeSurface(img_flag[i]); + texture_free(&img_flag[i]); - SDL_FreeSurface(img_mints); - SDL_FreeSurface(img_coffee); + texture_free(&img_mints); + texture_free(&img_coffee); for (i = 0; i < 4; i++) { - SDL_FreeSurface(img_distro[i]); - SDL_FreeSurface(img_cloud[0][i]); - SDL_FreeSurface(img_cloud[1][i]); + texture_free(&img_distro[i]); + texture_free(&img_cloud[0][i]); + texture_free(&img_cloud[1][i]); } - SDL_FreeSurface(img_golden_herring); + texture_free(&img_golden_herring); for (i = 0; i < NUM_SOUNDS; i++) free_chunk(sounds[i]); @@ -3106,56 +1179,57 @@ void unloadshared(void) /* Draw a tile on the screen: */ -void drawshape(int x, int y, unsigned char c) +void drawshape(float x, float y, unsigned char c) { int z; if (c == 'X' || c == 'x') - drawimage(img_brick[0], x, y, NO_UPDATE); + texture_draw(&img_brick[0], x, y, NO_UPDATE); else if (c == 'Y' || c == 'y') - drawimage(img_brick[1], x, y, NO_UPDATE); + texture_draw(&img_brick[1], x, y, NO_UPDATE); else if (c == 'A' || c =='B' || c == '!') - drawimage(img_box_full, x, y, NO_UPDATE); + texture_draw(&img_box_full, x, y, NO_UPDATE); else if (c == 'a') - drawimage(img_box_empty, x, y, NO_UPDATE); + texture_draw(&img_box_empty, x, y, NO_UPDATE); else if (c >= 'C' && c <= 'F') - drawimage(img_cloud[0][c - 'C'], x, y, NO_UPDATE); + texture_draw(&img_cloud[0][c - 'C'], x, y, NO_UPDATE); else if (c >= 'c' && c <= 'f') - drawimage(img_cloud[1][c - 'c'], x, y, NO_UPDATE); + texture_draw(&img_cloud[1][c - 'c'], x, y, NO_UPDATE); else if (c >= 'G' && c <= 'J') - drawimage(img_bkgd[0][c - 'G'], x, y, NO_UPDATE); + texture_draw(&img_bkgd[0][c - 'G'], x, y, NO_UPDATE); else if (c >= 'g' && c <= 'j') - drawimage(img_bkgd[1][c - 'g'], x, y, NO_UPDATE); + texture_draw(&img_bkgd[1][c - 'g'], x, y, NO_UPDATE); else if (c == '#') - drawimage(img_solid[0], x, y, NO_UPDATE); + texture_draw(&img_solid[0], x, y, NO_UPDATE); else if (c == '[') - drawimage(img_solid[1], x, y, NO_UPDATE); + texture_draw(&img_solid[1], x, y, NO_UPDATE); else if (c == '=') - drawimage(img_solid[2], x, y, NO_UPDATE); + texture_draw(&img_solid[2], x, y, NO_UPDATE); else if (c == ']') - drawimage(img_solid[3], x, y, NO_UPDATE); + texture_draw(&img_solid[3], x, y, NO_UPDATE); else if (c == '$') { + z = (frame / 2) % 6; if (z < 4) - drawimage(img_distro[z], x, y, NO_UPDATE); + texture_draw(&img_distro[z], x, y, NO_UPDATE); else if (z == 4) - drawimage(img_distro[2], x, y, NO_UPDATE); + texture_draw(&img_distro[2], x, y, NO_UPDATE); else if (z == 5) - drawimage(img_distro[1], x, y, NO_UPDATE); + texture_draw(&img_distro[1], x, y, NO_UPDATE); } else if (c == '^') { z = (frame / 3) % 3; - drawimage(img_waves[z], x, y, NO_UPDATE); + texture_draw(&img_waves[z], x, y, NO_UPDATE); } else if (c == '*') - drawimage(img_poletop, x, y, NO_UPDATE); + texture_draw(&img_poletop, x, y, NO_UPDATE); else if (c == '|') { - drawimage(img_pole, x, y, NO_UPDATE); + texture_draw(&img_pole, x, y, NO_UPDATE); /* Mark this as the end position of the level! */ @@ -3165,150 +1239,119 @@ void drawshape(int x, int y, unsigned char c) { z = (frame / 3) % 2; - drawimage(img_flag[z], x + 16, y, NO_UPDATE); + texture_draw(&img_flag[z], x + 16, y, NO_UPDATE); } else if (c == '&') - drawimage(img_water, x, y, NO_UPDATE); + texture_draw(&img_water, x, y, NO_UPDATE); } /* What shape is at some position? */ -unsigned char shape(int x, int y, int sx) +unsigned char shape(float x, float y) { int xx, yy; unsigned char c; - - yy = (y / 32); - xx = ((x + sx) / 32); - + + yy = ((int)y / 32); + xx = ((int)x / 32); if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width) + { c = current_level.tiles[yy][xx]; + } else c = '.'; return(c); } - /* Is is ground? */ -int issolid(int x, int y, int sx) +int issolid(float x, float y) { - int v; - - v = 0; - - if (isbrick(x, y, sx) || - isbrick(x + 31, y, sx) || - isice(x, y, sx) || - isice(x + 31, y, sx) || - (shape(x, y, sx) == '[' || - shape(x + 31, y, sx) == '[') || - (shape(x, y, sx) == '=' || - shape(x + 31, y, sx) == '=') || - (shape(x, y, sx) == ']' || - shape(x + 31, y, sx) == ']') || - (shape(x, y, sx) == 'A' || - shape(x + 31, y, sx) == 'A') || - (shape(x, y, sx) == 'B' || - shape(x + 31, y, sx) == 'B') || - (shape(x, y, sx) == '!' || - shape(x + 31, y, sx) == '!') || - (shape(x, y, sx) == 'a' || - shape(x + 31, y, sx) == 'a')) - { - v = 1; - } - - return(v); + if (isbrick(x, y) || + isbrick(x + 31, y) || + isice(x, y) || + isice(x + 31, y) || + (shape(x, y) == '[' || + shape(x + 31, y) == '[') || + (shape(x, y) == '=' || + shape(x + 31, y) == '=') || + (shape(x, y) == ']' || + shape(x + 31, y) == ']') || + (shape(x, y) == 'A' || + shape(x + 31, y) == 'A') || + (shape(x, y) == 'B' || + shape(x + 31, y) == 'B') || + (shape(x, y) == '!' || + shape(x + 31, y) == '!') || + (shape(x, y) == 'a' || + shape(x + 31, y) == 'a')) + { + return YES; + } + + return NO; } /* Is it a brick? */ -int isbrick(int x, int y, int sx) +int isbrick(float x, float y) { - int v; - - v = 0; - - if (shape(x, y, sx) == 'X' || - shape(x, y, sx) == 'x' || - shape(x, y, sx) == 'Y' || - shape(x, y, sx) == 'y') + if (shape(x, y) == 'X' || + shape(x, y) == 'x' || + shape(x, y) == 'Y' || + shape(x, y) == 'y') { - v = 1; + return YES; } - return(v); + return NO; } /* Is it ice? */ -int isice(int x, int y, int sx) +int isice(float x, float y) { - int v; - - v = 0; - - if (shape(x, y, sx) == '#') + if (shape(x, y) == '#') { - v = 1; + return YES; } - return(v); + return NO; } /* Is it a full box? */ -int isfullbox(int x, int y, int sx) +int isfullbox(float x, float y) { - int v; - - v = 0; - - if (shape(x, y, sx) == 'A' || - shape(x, y, sx) == 'B' || - shape(x, y, sx) == '!') + if (shape(x, y) == 'A' || + shape(x, y) == 'B' || + shape(x, y) == '!') { - v = 1; + return YES; } - return(v); + return NO; } - -/* Edit a piece of the map! */ - -void change(int x, int y, int sx, unsigned char c) -{ - int xx, yy; - - yy = (y / 32); - xx = ((x + sx) / 32); - - if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width) - current_level.tiles[yy][xx] = c; -} - - /* Break a brick: */ -void trybreakbrick(int x, int y, int sx) +void trybreakbrick(float x, float y) { - if (isbrick(x, y, sx)) + if (isbrick(x, y)) { - if (shape(x, y, sx) == 'x' || shape(x, y, sx) == 'y') + if (shape(x, y) == 'x' || shape(x, y) == 'y') { /* Get a distro from it: */ - add_bouncy_distro(((x + sx + 1) / 32) * 32, - (y / 32) * 32); + add_bouncy_distro(((x + 1) / 32) * 32, + (int)(y / 32) * 32); if (counting_distros == NO) { @@ -3317,7 +1360,7 @@ void trybreakbrick(int x, int y, int sx) } if (distro_counter <= 0) - change(x, y, sx, 'a'); + level_change(¤t_level,x, y, 'a'); play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER); score = score + SCORE_DISTRO; @@ -3327,14 +1370,14 @@ void trybreakbrick(int x, int y, int sx) { /* Get rid of it: */ - change(x, y, sx, '.'); + level_change(¤t_level,x, y,'.'); } /* Replace it with broken bits: */ - add_broken_brick(((x + sx + 1) / 32) * 32, - (y / 32) * 32); + add_broken_brick(((x + 1) / 32) * 32, + (int)(y / 32) * 32); /* Get some score: */ @@ -3347,10 +1390,10 @@ void trybreakbrick(int x, int y, int sx) /* Bounce a brick: */ -void bumpbrick(int x, int y, int sx) +void bumpbrick(float x, float y) { - add_bouncy_brick(((x + sx + 1) / 32) * 32, - (y / 32) * 32); + add_bouncy_brick(((int)(x + 1) / 32) * 32, + (int)(y / 32) * 32); play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER); } @@ -3358,73 +1401,73 @@ void bumpbrick(int x, int y, int sx) /* Empty a box: */ -void tryemptybox(int x, int y, int sx) +void tryemptybox(float x, float y) { - if (isfullbox(x, y, sx)) + if (isfullbox(x, y)) { - if (shape(x, y, sx) == 'A') + if (shape(x, y) == 'A') { /* Box with a distro! */ - add_bouncy_distro(((x + sx + 1) / 32) * 32, - (y / 32) * 32 - 32); + add_bouncy_distro(((x + 1) / 32) * 32, + (int)(y / 32) * 32 - 32); play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER); score = score + SCORE_DISTRO; distros++; } - else if (shape(x, y, sx) == 'B') + else if (shape(x, y) == 'B') { /* Add an upgrade! */ - if (tux_size == SMALL) + if (tux.size == SMALL) { /* Tux is small, add mints! */ - add_upgrade(((x + sx + 1) / 32) * 32, - (y / 32) * 32 - 32, + add_upgrade(((x + 1) / 32) * 32, + (int)(y / 32) * 32 - 32, UPGRADE_MINTS); } else { /* Tux is big, add coffee: */ - add_upgrade(((x + sx + 1) / 32) * 32, - (y / 32) * 32 - 32, + add_upgrade(((x + 1) / 32) * 32, + (int)(y / 32) * 32 - 32, UPGRADE_COFFEE); } play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER); } - else if (shape(x, y, sx) == '!') + else if (shape(x, y) == '!') { /* Add a golden herring */ - add_upgrade(((x + sx + 1) / 32) * 32, - (y / 32) * 32 - 32, + add_upgrade(((x + 1) / 32) * 32, + (int)(y / 32) * 32 - 32, UPGRADE_HERRING); } /* Empty the box: */ - change(x, y, sx, 'a'); + level_change(¤t_level,x, y, 'a'); } } /* Try to grab a distro: */ -void trygrabdistro(int x, int y, int sx, int bounciness) +void trygrabdistro(float x, float y, int bounciness) { - if (shape(x, y, sx) == '$') + if (shape(x, y) == '$') { - change(x, y, sx, '.'); + level_change(¤t_level,x, y, '.'); play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER); if (bounciness == BOUNCE) { - add_bouncy_distro(((x + sx + 1) / 32) * 32, - (y / 32) * 32); + add_bouncy_distro(((x + 1) / 32) * 32, + (int)(y / 32) * 32); } score = score + SCORE_DISTRO; @@ -3432,162 +1475,9 @@ void trygrabdistro(int x, int y, int sx, int bounciness) } } - -/* Add a bouncy distro: */ - -void add_bouncy_distro(int x, int y) -{ - int i, found; - - found = -1; - - for (i = 0; i < NUM_BOUNCY_DISTROS && found == -1; i++) - { - if (!bouncy_distros[i].alive) - found = i; - } - - if (found != -1) - { - bouncy_distros[found].alive = YES; - bouncy_distros[found].x = x; - bouncy_distros[found].y = y; - bouncy_distros[found].ym = -6; - } -} - - -/* Add broken brick pieces: */ - -void add_broken_brick(int x, int y) -{ - add_broken_brick_piece(x, y, -4, -16); - add_broken_brick_piece(x, y + 16, -6, -12); - - add_broken_brick_piece(x + 16, y, 4, -16); - add_broken_brick_piece(x + 16, y + 16, 6, -12); -} - - -/* Add a broken brick piece: */ - -void add_broken_brick_piece(int x, int y, int xm, int ym) -{ - int i, found; - - found = -1; - - for (i = 0; i < NUM_BROKEN_BRICKS && found == -1; i++) - { - if (!broken_bricks[i].alive) - found = i; - } - - if (found != -1) - { - broken_bricks[found].alive = YES; - broken_bricks[found].x = x; - broken_bricks[found].y = y; - broken_bricks[found].xm = xm; - broken_bricks[found].ym = ym; - } -} - - -/* Add a bouncy brick piece: */ - -void add_bouncy_brick(int x, int y) -{ - int i, found; - - found = -1; - - for (i = 0; i < NUM_BOUNCY_BRICKS && found == -1; i++) - { - if (!bouncy_bricks[i].alive) - found = i; - } - - if (found != -1) - { - bouncy_bricks[found].alive = YES; - bouncy_bricks[found].x = x; - bouncy_bricks[found].y = y; - bouncy_bricks[found].offset = 0; - bouncy_bricks[found].offset_m = -BOUNCY_BRICK_SPEED; - bouncy_bricks[found].shape = shape(x, y, 0); - } -} - - -/* Add a bad guy: */ - -void add_bad_guy(int x, int y, int kind) -{ - int i, found; - - found = -1; - - for (i = 0; i < NUM_BAD_GUYS && found == -1; i++) - { - if (!bad_guys[i].alive) - found = i; - } - - if (found != -1) - { - bad_guys[found].alive = YES; - bad_guys[found].mode = NORMAL; - bad_guys[found].dying = NO; - bad_guys[found].timer = 0; - bad_guys[found].kind = kind; - bad_guys[found].x = x; - bad_guys[found].y = y; - bad_guys[found].xm = 0; - bad_guys[found].ym = 0; - bad_guys[found].dir = LEFT; - bad_guys[found].seen = NO; - } -} - - -/* Add score: */ - -void add_score(int x, int y, int s) -{ - int i, found; - - - /* Add the score: */ - - score = score + s; - - - /* Add a floating score thing to the game: */ - - found = -1; - - for (i = 0; i < NUM_FLOATING_SCORES && found == -1; i++) - { - if (!floating_scores[i].alive) - found = i; - } - - - if (found != -1) - { - floating_scores[found].alive = YES; - floating_scores[found].x = x; - floating_scores[found].y = y - 16; - floating_scores[found].timer = 8; - floating_scores[found].value = s; - } -} - - /* Try to bump a bad guy from below: */ -void trybumpbadguy(int x, int y, int sx) +void trybumpbadguy(float x, float y) { int i; @@ -3597,7 +1487,7 @@ void trybumpbadguy(int x, int y, int sx) for (i = 0; i < NUM_BAD_GUYS; i++) { if (bad_guys[i].alive && - bad_guys[i].x >= x + sx - 32 && bad_guys[i].x <= x + sx + 32 && + bad_guys[i].x >= x - 32 && bad_guys[i].x <= x + 32 && bad_guys[i].y >= y - 16 && bad_guys[i].y <= y + 16) { if (bad_guys[i].kind == BAD_BSOD || @@ -3616,7 +1506,7 @@ void trybumpbadguy(int x, int y, int sx) for (i = 0; i < NUM_UPGRADES; i++) { if (upgrades[i].alive && upgrades[i].height == 32 && - upgrades[i].x >= x + sx - 32 && upgrades[i].x <= x + sx + 32 && + upgrades[i].x >= x - 32 && upgrades[i].x <= x + 32 && upgrades[i].y >= y - 16 && upgrades[i].y <= y + 16) { upgrades[i].xm = -upgrades[i].xm; @@ -3629,7 +1519,7 @@ void trybumpbadguy(int x, int y, int sx) /* Add an upgrade: */ -void add_upgrade(int x, int y, int kind) +void add_upgrade(float x, float y, int kind) { int i, found; @@ -3647,54 +1537,19 @@ void add_upgrade(int x, int y, int kind) upgrades[found].kind = kind; upgrades[found].x = x; upgrades[found].y = y; - upgrades[found].xm = 4; - upgrades[found].ym = -4; + upgrades[found].xm = 2; + upgrades[found].ym = -2; upgrades[found].height = 0; } } -/* Remove Tux's power ups */ -void remove_powerups(void) -{ - tux_got_coffee = NO; - tux_size = SMALL; -} - - -/* Kill tux! */ - -void killtux(int mode) -{ - tux_ym = -16; - - play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER); - - if (tux_dir == RIGHT) - tux_xm = -8; - else if (tux_dir == LEFT) - tux_xm = 8; - - if (mode == SHRINK && tux_size == BIG) - { - if (tux_got_coffee) - tux_got_coffee = NO; - - tux_size = SMALL; - - tux_safe = TUX_SAFE_TIME; - } - else - { - tux_dying = 1; - } -} - - /* Add a bullet: */ -void add_bullet(int x, int y, int dir, int xm) +void add_bullet(float x, float y, float xm, int dir) { int i, found; + + printf("X: %f Y: %f -- YOOYOYOYO\n",x,y); found = -1; @@ -3727,6 +1582,39 @@ void add_bullet(int x, int y, int dir, int xm) } +/* (Status): */ +void drawstatus(void) +{ +int i; + + sprintf(str, "%d", score); + drawtext("SCORE", 0, 0, letters_blue, NO_UPDATE, 1); + drawtext(str, 96, 0, letters_gold, NO_UPDATE, 1); + + sprintf(str, "%d", highscore); + drawtext("HIGH", 0, 20, letters_blue, NO_UPDATE, 1); + drawtext(str, 96, 20, letters_gold, NO_UPDATE, 1); + + if (timer_get_left(&time_left) > TIME_WARNING || (frame % 10) < 5) + { + sprintf(str, "%d", timer_get_left(&time_left) / 1000 ); + drawtext("TIME", 224, 0, letters_blue, NO_UPDATE, 1); + drawtext(str, 304, 0, letters_gold, NO_UPDATE, 1); + } + + sprintf(str, "%d", distros); + drawtext("DISTROS", screen->h, 0, letters_blue, NO_UPDATE, 1); + drawtext(str, 608, 0, letters_gold, NO_UPDATE, 1); + + drawtext("LIVES", screen->h, 20, letters_blue, NO_UPDATE, 1); + + for(i=0; i < tux.lives; ++i) + { + texture_draw(&tux_life,565+(18*i),20,NO_UPDATE); + } +} + + void drawendscreen(void) { char str[80]; @@ -3741,7 +1629,7 @@ void drawendscreen(void) sprintf(str, "DISTROS: %d", distros); drawcenteredtext(str, 256, letters_blue, NO_UPDATE, 1); - SDL_Flip(screen); + flipscreen(); SDL_Delay(2000); } @@ -3759,7 +1647,7 @@ void drawresultscreen(void) sprintf(str, "DISTROS: %d", distros); drawcenteredtext(str, 256, letters_blue, NO_UPDATE, 1); - SDL_Flip(screen); + flipscreen(); SDL_Delay(2000); } @@ -3783,15 +1671,15 @@ void savegame(void) } else - { - fwrite(&level,4,1,fi); - fwrite(&score,4,1,fi); - fwrite(&distros,4,1,fi); - fwrite(&tux_x,4,1,fi); - fwrite(&tux_y,4,1,fi); - fwrite(&scroll_x,4,1,fi); - fwrite(¤t_level.time_left,4,1,fi); - } + { + fwrite(&level,4,1,fi); + fwrite(&score,4,1,fi); + fwrite(&distros,4,1,fi); + fwrite(&tux.x,4,1,fi); + fwrite(&tux.y,4,1,fi); + fwrite(&scroll_x,4,1,fi); + fwrite(¤t_level.time_left,4,1,fi); + } fclose(fi); } @@ -3802,7 +1690,7 @@ void loadgame(char* filename) FILE* fi; time_t current_time = time(NULL); struct tm* time_struct; - + time_struct = localtime(¤t_time); sprintf(savefile,"%s/%d-%d-%d-%d.save",st_save_dir,time_struct->tm_year+1900,time_struct->tm_mon,time_struct->tm_mday,time_struct->tm_hour); printf("%s",savefile); @@ -3816,24 +1704,26 @@ void loadgame(char* filename) } else - { - set_defaults(); - loadlevel(¤t_level,"default",level); - activate_bad_guys(); + { + player_level_begin(&tux); + set_defaults(); + loadlevel(¤t_level,"default",level); + activate_bad_guys(); unloadlevelgfx(); - loadlevelgfx(); + loadlevelgfx(¤t_level); unloadlevelsong(); loadlevelsong(); levelintro(); - - fread(&level,4,1,fi); - fread(&score,4,1,fi); - fread(&distros,4,1,fi); - fread(&tux_x,4,1,fi); - fread(&tux_y,4,1,fi); - fread(&scroll_x,4,1,fi); - fread(¤t_level.time_left,4,1,fi); - fclose(fi); - } + start_timers(); + + fread(&level,4,1,fi); + fread(&score,4,1,fi); + fread(&distros,4,1,fi); + fread(&tux.x,4,1,fi); + fread(&tux.y,4,1,fi); + fread(&scroll_x,4,1,fi); + fread(¤t_level.time_left,4,1,fi); + fclose(fi); + } } diff --git a/src/gameloop.h b/src/gameloop.h index 256430ecf..f7464a116 100644 --- a/src/gameloop.h +++ b/src/gameloop.h @@ -7,145 +7,71 @@ bill@newbreedsoftware.com http://www.newbreedsoftware.com/supertux/ - April 11, 2000 - December 28, 2003 + April 11, 2000 - Junuary 1st, 2004 */ #if !defined( SUPERTUX_GAMELOOP_H ) #define SUPERTUX_GAMELOOP_H 1 - #include "sound.h" +#include "sound.h" +#include "type.h" - /* Direction (keyboard/joystick) states: */ +/* Bounciness of distros: */ - #define UP 0 - #define DOWN 1 +#define NO_BOUNCE 0 +#define BOUNCE 1 - /* Directions: */ +/* One-ups... */ - #define LEFT 0 - #define RIGHT 1 +#define DISTROS_LIFEUP 100 - /* Sizes: */ +/* Upgrade types: */ - #define SMALL 0 - #define BIG 1 +enum { + UPGRADE_MINTS, + UPGRADE_COFFEE, + UPGRADE_HERRING +}; +/* Array sizes: */ - /* Bounciness of distros: */ +#define NUM_BOUNCY_DISTROS 8 +#define NUM_BROKEN_BRICKS 32 +#define NUM_BOUNCY_BRICKS 4 +#define NUM_FLOATING_SCORES 6 +#define NUM_UPGRADES 2 - #define NO_BOUNCE 0 - #define BOUNCE 1 +/* Scores: */ - /* One-ups... */ +#define SCORE_BRICK 5 +#define SCORE_DISTRO 25 - #define DISTROS_LIFEUP 100 +/* Function prototypes: */ - - /* When to alert player they're low on time! */ - - #define TIME_WARNING 50 - - - /* Dying types: */ - - /* ---- NO 0 */ - #define SQUISHED 1 - #define FALLING 2 - - - /* Enemy modes: */ - - #define NORMAL 0 - #define FLAT 1 - #define KICK 2 - - - /* Hurt modes: */ - - #define KILL 0 - #define SHRINK 1 - - - /* Upgrade types: */ - - enum { - UPGRADE_MINTS, - UPGRADE_COFFEE, - UPGRADE_HERRING - }; - - - /* Bad guy kinds: */ - - enum { - BAD_BSOD, - BAD_LAPTOP, - BAD_MONEY - }; - - - /* Speed constraints: */ - - #define MAX_WALK_XM 16 - #define MAX_RUN_XM 24 - #define MAX_YM 24 - #define MAX_JUMP_COUNT 3 - #define MAX_LIVES 4 - - #define WALK_SPEED 2 - #define RUN_SPEED 4 - #define JUMP_SPEED 8 - #define BULLET_STARTING_YM 8 - #define BULLET_XM 16 - - #define GRAVITY 2 - #define YM_FOR_JUMP 40 - #define KILL_BOUNCE_YM 8 - - #define SKID_XM 8 - #define SKID_TIME 8 - - - #define BOUNCY_BRICK_MAX_OFFSET 8 - #define BOUNCY_BRICK_SPEED 4 - - - /* Times: */ - - #define TUX_SAFE_TIME 16 - #define TUX_INVINCIBLE_TIME 200 - - /* Size constraints: */ - - #define OFFSCREEN_DISTANCE 256 - - #define LEVEL_WIDTH 375 - - - /* Array sizes: */ - - #define NUM_BOUNCY_DISTROS 8 - #define NUM_BROKEN_BRICKS 32 - #define NUM_BOUNCY_BRICKS 4 - #define NUM_BAD_GUYS 128 - #define NUM_FLOATING_SCORES 6 - #define NUM_UPGRADES 2 - #define NUM_BULLETS 3 - - - /* Scores: */ - - #define SCORE_BRICK 5 - #define SCORE_DISTRO 25 - - /* Function prototypes: */ - - int gameloop(void); - void savegame(void); - void loadgame(char* filename); - +int gameloop(void); +void savegame(void); +void loadgame(char* filename); +int issolid(float x, float y); +int isbrick(float x, float y); +int isice(float x, float y); +int isfullbox(float x, float y); +int rectcollision(itop_type* one, itop_type* two); +void drawshape(float x, float y, unsigned char c); +unsigned char shape(float x, float y); +void bumpbrick(float x, float y); +void trygrabdistro(float x, float y, int bounciness); +void trybreakbrick(float x, float y); +void tryemptybox(float x, float y); +void trybumpbadguy(float x, float y); +void add_bouncy_distro(float x, float y); +void add_broken_brick(float x, float y); +void add_broken_brick_piece(float x, float y, float xm, float ym); +void add_bouncy_brick(float x, float y); +void add_bad_guy(float x, float y, int kind); +void add_upgrade(float x, float y, int kind); +void add_bullet(float x, float y, float xm, int dir); #endif diff --git a/src/globals.h b/src/globals.h index ffcd5d0fe..cf9664d5a 100644 --- a/src/globals.h +++ b/src/globals.h @@ -19,7 +19,7 @@ SDL_Surface * screen; SDL_Surface * letters_black, * letters_gold, * letters_blue, * letters_red; -int use_joystick, use_fullscreen, debug_mode; +int use_gl, use_joystick, use_fullscreen, debug_mode; int game_started, level_editor_started; diff --git a/src/high_scores.c b/src/high_scores.c index 6cf9ab454..d84dcabf6 100644 --- a/src/high_scores.c +++ b/src/high_scores.c @@ -19,27 +19,26 @@ FILE * opendata(char * mode) FILE * fi; -#ifdef LINUX - - /* Create the buffer for the filename: */ - filename = (char *) malloc(sizeof(char) * (strlen(st_dir) + - strlen("/highscore") + 1)); + strlen("/st_highscore.dat") + 1)); strcpy(filename, st_dir); /* Open the high score file: */ - + +#ifdef LINUX strcat(filename, "/highscore"); #else - - filename = "st_highscore.dat"; +#ifdef WIN32 + strcat(filename, "/st_highscore.dat"); + #endif #endif /* Try opening the file: */ fi = fopen(filename, mode); - + free( filename ); + if (fi == NULL) { fprintf(stderr, "Warning: I could not open the high score file "); diff --git a/src/intro.c b/src/intro.c index b6ea153b4..9568cc01f 100644 --- a/src/intro.c +++ b/src/intro.c @@ -28,7 +28,7 @@ #include "globals.h" #include "intro.h" #include "screen.h" - +#include "type.h" char * intro_text[] = { "Tux and Gown were having a nice picnic..", @@ -43,68 +43,61 @@ char * intro_text[] = { int intro(void) { SDL_Event event; - SDL_Surface * bkgd, * copter_squish, * copter_stretch, * beam, - * gown_sit, * gown_lookup, * gown_upset, - * tux_sit, * tux_upset, * tux_mad; - SDL_Surface * copter[2]; + texture_type bkgd, copter_squish, copter_stretch, beam, + gown_sit, gown_lookup, gown_upset, + tux_sit, tux_upset, tux_mad; + texture_type copter[2]; SDL_Rect src, dest; - int done, i, quit, j; + int done, i, quit, j, scene; int * height, * height_speed; + timer_type timer; /* Load sprite images: */ - - bkgd = load_image(DATA_PREFIX "/images/intro/intro.png", IGNORE_ALPHA); - - gown_sit = load_image(DATA_PREFIX "/images/intro/gown-sit.png", USE_ALPHA); - gown_lookup = load_image(DATA_PREFIX "/images/intro/gown-lookup.png", - USE_ALPHA); - gown_upset = load_image(DATA_PREFIX "/images/intro/gown-upset.png", - USE_ALPHA); - - tux_sit = load_image(DATA_PREFIX "/images/intro/tux-sit.png", USE_ALPHA); - tux_upset = load_image(DATA_PREFIX "/images/intro/tux-upset.png", - USE_ALPHA); - tux_mad = load_image(DATA_PREFIX "/images/intro/tux-mad.png", USE_ALPHA); - - copter[0] = load_image(DATA_PREFIX "/images/intro/copter1.png", USE_ALPHA); - copter[1] = load_image(DATA_PREFIX "/images/intro/copter2.png", USE_ALPHA); - copter_squish = load_image(DATA_PREFIX "/images/intro/copter-squish.png", - USE_ALPHA); - copter_stretch = load_image(DATA_PREFIX "/images/intro/copter-stretch.png", - USE_ALPHA); - - beam = load_image(DATA_PREFIX "/images/intro/beam.png", USE_ALPHA); - + texture_load(&bkgd, DATA_PREFIX "/images/intro/intro.png", IGNORE_ALPHA); + texture_load(&gown_sit, DATA_PREFIX "/images/intro/gown-sit.png", USE_ALPHA); + texture_load(&gown_lookup, DATA_PREFIX "/images/intro/gown-lookup.png", USE_ALPHA); + texture_load(&gown_upset, DATA_PREFIX "/images/intro/gown-upset.png", USE_ALPHA); + texture_load(&tux_sit, DATA_PREFIX "/images/intro/tux-sit.png", USE_ALPHA); + texture_load(&tux_upset, DATA_PREFIX "/images/intro/tux-upset.png", USE_ALPHA); + texture_load(&tux_mad, DATA_PREFIX "/images/intro/tux-mad.png", USE_ALPHA); + texture_load(&copter[0], DATA_PREFIX "/images/intro/copter1.png", USE_ALPHA); + texture_load(&copter[1], DATA_PREFIX "/images/intro/copter2.png", USE_ALPHA); + texture_load(&copter_squish, DATA_PREFIX "/images/intro/copter-squish.png", USE_ALPHA); + texture_load(&copter_stretch, DATA_PREFIX "/images/intro/copter-stretch.png", USE_ALPHA); + texture_load(&beam, DATA_PREFIX "/images/intro/beam.png", USE_ALPHA); /* Allocate buffer for height array: */ - height = malloc(sizeof(int) * (gown_upset -> w)); - height_speed = malloc(sizeof(int) * (gown_upset -> w)); + height = malloc(sizeof(int) * (gown_upset.w)); + height_speed = malloc(sizeof(int) * (gown_upset.w)); /* Initialize height arrays: */ - for (j = 0; j < (gown_upset -> w); j++) + for (j = 0; j < (gown_upset.w); j++) { height[j] = 400; height_speed[j] = (rand() % 10) + 1; } + /* Display background: */ - /* Display background: */ - - drawimage(bkgd, 0, 0, UPDATE); - + texture_draw_bg(&bkgd, UPDATE); /* Animation: */ done = 0; quit = 0; + scene = 0; + i = 0; + + timer_start(&timer,10000); - for (i = 0; i < (10000 / FPS) && !done && !quit; i++) + while (timer_check(&timer) && !done && !quit) { + /* Handle events: */ while (SDL_PollEvent(&event)) @@ -132,188 +125,190 @@ int intro(void) } + /* Display background: */ + /* Draw things: */ - if (i == 0) + if (timer_get_gone(&timer) < 2000 && scene == 0) { + ++scene; /* Gown and tux sitting: */ - drawimage(tux_sit, 270, 400, UPDATE); - drawimage(gown_sit, 320, 400, UPDATE); + texture_draw(&tux_sit, 270, 400, UPDATE); + texture_draw(&gown_sit, 320, 400, UPDATE); drawcenteredtext(intro_text[0], 456, letters_blue, UPDATE, 1); } - if (i == (2000 / FPS)) + if (timer_get_gone(&timer) >= 2000 && scene == 1) { + ++scene; /* Helicopter begins to fly in: */ - erasecenteredtext(intro_text[0], 456, bkgd, UPDATE, 1); - drawcenteredtext(intro_text[1], 456, letters_red, UPDATE, 1); + erasecenteredtext(intro_text[0], 456, bkgd.sdl_surface, NO_UPDATE, 1); + drawcenteredtext(intro_text[1], 456, letters_red, NO_UPDATE, 1); } - if (i > (2000 / FPS) && i < (4000 / FPS)) + if (timer_get_gone(&timer) >= 2000 && timer_get_gone(&timer) < 4000) { /* Helicopter flying in: */ + texture_draw_part(&bkgd, 0, 32, screen->w, (copter[0].h), NO_UPDATE); - drawpart(bkgd, 0, 32, 640, (copter[0] -> h), NO_UPDATE); - - drawimage(copter[i % 2], - (i - (2000 / FPS)) * (FPS / 5) - (copter[0] -> w), 32, + texture_draw(&copter[i % 2], + (float)(timer_get_gone(&timer) - 2000) / 5 - (copter[0].w), 32, NO_UPDATE); - - SDL_UpdateRect(screen, 0, 32, 640, (copter[0] -> h)); + + update_rect(screen, 0, 32, screen->w, (copter[0].h)); } - if (i == (2500 / FPS)) + if (timer_get_gone(&timer) >= 2500 && scene == 2) { + ++scene; /* Gown notices something... */ - drawimage(gown_lookup, 320, 400, UPDATE); + texture_draw(&gown_lookup, 320, 400, UPDATE); } - if (i == (3500 / FPS)) + if (timer_get_gone(&timer) >= 3500 && scene == 3) { + ++scene; /* Gown realizes it's bad! */ - drawimage(gown_upset, 320, 400, UPDATE); + texture_draw(&gown_upset, 320, 400, UPDATE); } - if (i > (4000 / FPS) && i < (8000 / FPS)) + if (timer_get_gone(&timer) >= 4000 && timer_get_gone(&timer) < 8000) { /* Helicopter sits: */ + texture_draw_part(&bkgd, 0, 32, screen->w, (copter[0].h), NO_UPDATE); - drawpart(bkgd, 0, 32, 640, (copter[0] -> h), NO_UPDATE); - - drawimage(copter[i % 2], 400 - (copter[0] -> w), 32, NO_UPDATE); - - SDL_UpdateRect(screen, 0, 32, 640, (copter[0] -> h)); + texture_draw(&copter[i % 2], 400 - (copter[0].w), 32, NO_UPDATE); + update_rect(screen, 0, 32, screen->w, (copter[0].h)); } - if (i == (5000 / FPS)) + if (timer_get_gone(&timer) >= 5000 && scene == 4) { + ++scene; /* Tux realizes something's happening: */ - drawimage(tux_upset, 270, 400, UPDATE); + texture_draw(&tux_upset, 270, 400, UPDATE); - erasecenteredtext(intro_text[1], 456, bkgd, UPDATE, 1); + erasecenteredtext(intro_text[1], 456, bkgd.sdl_surface, UPDATE, 1); drawcenteredtext(intro_text[2], 456, letters_red, UPDATE, 1); } - if (i > (5000 / FPS)) + if (timer_get_gone(&timer) >= 5000) { /* Beam gown up! */ - drawpart(bkgd, + texture_draw_part(&bkgd, 320, - 32 + (copter[0] -> h), - (gown_upset -> w), - 368 + (gown_upset -> h) - (copter[0] -> h), NO_UPDATE); + 32 + (copter[0].h), + (gown_upset.w), + 368 + (gown_upset.h) - (copter[0].h), NO_UPDATE); - for (j = 0; j < (gown_upset -> w); j++) + for (j = 0; j < (gown_upset.sdl_surface -> w); j++) { - drawimage(beam, 320 + j - ((beam -> w) / 2), height[j], + texture_draw(&beam, 320 + j - ((beam.w) / 2), height[j], NO_UPDATE); src.x = j; src.y = 0; src.w = 1; - src.h = (gown_upset -> h); + src.h = (gown_upset.h); dest.x = 320 + j; dest.y = height[j]; dest.w = src.w; dest.h = src.h; - SDL_BlitSurface(gown_upset, &src, screen, &dest); + SDL_BlitSurface(gown_upset.sdl_surface, &src, screen, &dest); height[j] = height[j] - height_speed[j]; if ((i % 2) == 0) height_speed[j]++; } - - SDL_UpdateRect(screen, + + update_rect(screen, 320, - 32 + (copter[0] -> h), - (gown_upset -> w), - 400 + (gown_upset -> h) - (copter[0] -> h)); + 32 + (copter[0].h), + (gown_upset.w), + 400 + (gown_upset.h) - (copter[0].h)); } - if (i == (8000 / FPS)) + if (timer_get_gone(&timer) >= 8000 && scene == 5) { + ++scene; /* Tux gets mad! */ - drawimage(tux_mad, 270, 400, UPDATE); + texture_draw(&tux_mad, 270, 400, UPDATE); - erasecenteredtext(intro_text[2], 456, bkgd, UPDATE, 1); + erasecenteredtext(intro_text[2], 456, bkgd.sdl_surface, UPDATE, 1); drawcenteredtext(intro_text[3], 456, letters_gold, UPDATE, 1); } - if (i > (8000 / FPS) && i < (8250 / FPS)) + if (timer_get_gone(&timer) >= 8000 && timer_get_gone(&timer) <= 8250) { /* Helicopter starting to speed off: */ - drawpart(bkgd, 0, 32, 640, (copter_squish -> h), NO_UPDATE); + texture_draw_part(&bkgd, 0, 32, screen->w, (copter_squish.h), NO_UPDATE); - drawimage(copter_squish, - 400 - (copter[0] -> w), 32, + texture_draw(&copter_squish, + 400 - (copter[0].w), 32, NO_UPDATE); - - SDL_UpdateRect(screen, 0, 32, 640, (copter_squish -> h)); + + update_rect(screen, 0, 32, screen->w, (copter_squish.h)); } - if (i > (8250 / FPS)) + if (timer_get_gone(&timer) >= 8250) { /* Helicopter speeding off: */ - drawpart(bkgd, 0, 32, 640, (copter_stretch -> h), NO_UPDATE); + texture_draw_part(&bkgd, 0, 32, screen->w, (copter_stretch.h), NO_UPDATE); - drawimage(copter_stretch, - (i - (8250 / FPS)) * 30 + 400 - (copter[0] -> w), + texture_draw(&copter_stretch, + (timer_get_gone(&timer) - 8250) /*(i - (8250 / FPS)) * 30*/ + 400 - (copter[0].w), 32, NO_UPDATE); - - SDL_UpdateRect(screen, 0, 32, 640, (copter_stretch -> h)); + + update_rect(screen, 0, 32, screen->w, (copter_stretch.h)); } - + + flipscreen(); + + ++i; /* Pause: */ - - SDL_Delay(FPS); + SDL_Delay(20); } /* Free surfaces: */ - SDL_FreeSurface(bkgd); - - SDL_FreeSurface(gown_sit); - SDL_FreeSurface(gown_lookup); - SDL_FreeSurface(gown_upset); - - SDL_FreeSurface(tux_sit); - SDL_FreeSurface(tux_upset); - SDL_FreeSurface(tux_mad); - - SDL_FreeSurface(copter[0]); - SDL_FreeSurface(copter[1]); - - SDL_FreeSurface(copter_squish); - SDL_FreeSurface(copter_stretch); - - SDL_FreeSurface(beam); + texture_free(&bkgd); + texture_free(&gown_sit); + texture_free(&gown_lookup); + texture_free(&gown_upset); + texture_free(&tux_sit); + texture_free(&tux_upset); + texture_free(&tux_mad); + texture_free(&copter[0]); + texture_free(&copter[1]); + texture_free(&copter_squish); + texture_free(&copter_stretch); + texture_free(&beam); /* Free array buffers: */ diff --git a/src/level.c b/src/level.c index 6df811d24..f24012d25 100644 --- a/src/level.c +++ b/src/level.c @@ -1,7 +1,7 @@ // // C Implementation: level // -// Description: +// Description: // // // Author: Tobias Glaesser , (C) 2003 @@ -13,6 +13,7 @@ #include #include #include +#include "globals.h" #include "setup.h" #include "screen.h" #include "level.h" @@ -87,6 +88,7 @@ void loadlevel(st_level* plevel, char *subset, int level) if (line == NULL) { fprintf(stderr, "Couldn't allocate space to load level data!"); + fclose(fi); exit(1); } @@ -98,23 +100,84 @@ void loadlevel(st_level* plevel, char *subset, int level) if(fgets(line, plevel->width + 5, fi) == NULL) { fprintf(stderr, "Level %s isn't complete!\n",plevel->name); + free(line); + fclose(fi); exit(1); } line[strlen(line) - 1] = '\0'; plevel->tiles[y] = strdup(line); } + free(line); fclose(fi); - + +} + +/* Load graphics: */ + +void loadlevelgfx(st_level *plevel) +{ + + load_level_image(&img_brick[0],plevel->theme,"brick0.png", IGNORE_ALPHA); + load_level_image(&img_brick[1],plevel->theme,"brick1.png", IGNORE_ALPHA); + + load_level_image(&img_solid[0],plevel->theme,"solid0.png", USE_ALPHA); + load_level_image(&img_solid[1],plevel->theme,"solid1.png", USE_ALPHA); + load_level_image(&img_solid[2],plevel->theme,"solid2.png", USE_ALPHA); + load_level_image(&img_solid[3],plevel->theme,"solid3.png", USE_ALPHA); + + load_level_image(&img_bkgd[0][0],plevel->theme,"bkgd-00.png", USE_ALPHA); + load_level_image(&img_bkgd[0][1],plevel->theme,"bkgd-01.png", USE_ALPHA); + load_level_image(&img_bkgd[0][2],plevel->theme,"bkgd-02.png", USE_ALPHA); + load_level_image(&img_bkgd[0][3],plevel->theme,"bkgd-03.png", USE_ALPHA); + + load_level_image(&img_bkgd[1][0],plevel->theme,"bkgd-10.png", USE_ALPHA); + load_level_image(&img_bkgd[1][1],plevel->theme,"bkgd-11.png", USE_ALPHA); + load_level_image(&img_bkgd[1][2],plevel->theme,"bkgd-12.png", USE_ALPHA); + load_level_image(&img_bkgd[1][3],plevel->theme,"bkgd-13.png", USE_ALPHA); +} + +/* Free graphics data for this level: */ + +void unloadlevelgfx(void) +{ + int i; + + for (i = 0; i < 2; i++) + { + texture_free(&img_brick[i]); + } + for (i = 0; i < 4; i++) + { + texture_free(&img_solid[i]); + texture_free(&img_bkgd[0][i]); + texture_free(&img_bkgd[1][i]); + } } /* Load a level-specific graphic... */ -SDL_Surface * load_level_image(char* theme, char * file, int use_alpha) +void load_level_image(texture_type* ptexture, char* theme, char * file, int use_alpha) { - char fname[2024]; + char fname[1024]; - snprintf(fname, 21024, "%simages/themes/%s/%s", DATA_PREFIX, theme, file); + snprintf(fname, 1024, "%s/themes/%s/%s", st_dir, theme, file); + if(!faccessible(fname)) + snprintf(fname, 1024, "%s/images/themes/%s/%s", DATA_PREFIX, theme, file); - return(load_image(fname, use_alpha)); + texture_load(ptexture, fname, use_alpha); } + +/* Edit a piece of the map! */ + +void level_change(st_level* plevel, float x, float y, unsigned char c) +{ + int xx, yy; + + yy = (y / 32); + xx = (x / 32); + + if (yy >= 0 && yy < 15 && xx >= 0 && xx <= plevel->width) + plevel->tiles[yy][xx] = c; +} + diff --git a/src/level.h b/src/level.h index 4d9f14b42..ac1ebee8b 100644 --- a/src/level.h +++ b/src/level.h @@ -10,9 +10,16 @@ // // +#ifndef SUPERTUX_LEVEL_H +#define SUPERTUX_LEVEL_H + +#include "type.h" + +#define LEVEL_NAME_MAX 20 + typedef struct st_level /*It is easier to read the sources IMHO, if we don't write something like int a,b,c; */ { - char name[100]; + char name[LEVEL_NAME_MAX]; char theme[100]; char song_title[100]; unsigned char* tiles[15]; @@ -23,7 +30,12 @@ typedef struct st_level /*It is easier to read the sources IMHO, if we don't wri int width; } st_level; +texture_type img_bkgd[2][4], img_solid[4], img_brick[2]; + void loadlevel(st_level* plevel, char * subset, int level); -SDL_Surface * load_level_image(char* theme, char * file, int use_alpha); - +void loadlevelgfx(st_level* plevel); +void unloadlevelgfx(); +void load_level_image(texture_type* ptexture, char* theme, char * file, int use_alpha); +void level_change(st_level* plevel, float x, float y, unsigned char c); +#endif /*SUPERTUX_LEVEL_H*/ diff --git a/src/leveleditor.c b/src/leveleditor.c index ee6f73a28..a713a4700 100644 --- a/src/leveleditor.c +++ b/src/leveleditor.c @@ -7,9 +7,9 @@ * (at your option) any later version. * * * ***************************************************************************/ - -/* December 28, 2003 - December 30, 2003 */ - + +/* December 28, 2003 - January 1st, 2004 */ + /* leveleditor.c - A built-in level editor for SuperTux by Ricardo Cruz */ @@ -20,9 +20,8 @@ #include #include #include - #include "leveleditor.h" -#include "gameloop.h" + #include "screen.h" #include "defines.h" #include "globals.h" @@ -30,6 +29,8 @@ #include "menu.h" #include "level.h" #include "badguy.h" +#include "gameloop.h" +#include "scene.h" /* definitions to aid development */ #define DONE_LEVELEDITOR 1 @@ -39,60 +40,57 @@ /* definitions that affect gameplay */ #define KEY_CURSOR_SPEED 32 #define KEY_CURSOR_FASTSPEED 64 -#define KEY_LEFT_MARGIN 160 -#define KEY_RIGHT_MARGIN 480 + +#define CURSOR_LEFT_MARGIN 96 +#define CURSOR_RIGHT_MARGIN 512 +/* right_margin should noticed that the cursor is 32 pixels, + so it should subtract that value */ #define MOUSE_LEFT_MARGIN 32 #define MOUSE_RIGHT_MARGIN 608 #define MOUSE_POS_SPEED 32 - /* Level Intro: */ +/* Level Intro: */ /* clearscreen(0, 0, 0); - + sprintf(str, "Editing Level %s", levelfilename); drawcenteredtext(str, 200, letters_red, NO_UPDATE, 1); - + sprintf(str, "%s", levelname); drawcenteredtext(str, 224, letters_gold, NO_UPDATE, 1); - - SDL_Flip(screen); - + + flipscreen(); + SDL_Delay(1000); */ -/* global variables (based on the gameloop ones) */ - -bad_guy_type bad_guys[NUM_BAD_GUYS]; -SDL_Surface *img_bsod_left[4], *img_laptop_left[3], *img_money_left[2]; -int level; -st_level current_level; -char level_subset[100]; - -int frame; -SDL_Surface *selection; - /* gameloop funcs declerations */ -void loadlevelgfx(void); -void unloadlevelgfx(void); -void add_bad_guy(int x, int y, int kind); void loadshared(void); void unloadshared(void); -void drawshape(int x, int y, unsigned char c); /* own declerations */ void savelevel(); -void le_loadlevel(void); -void le_change(int x, int y, int sx, unsigned char c); +void le_change(float x, float y, unsigned char c); void showhelp(); void le_set_defaults(void); void le_activate_bad_guys(void); +/* global variables (based on the gameloop ones) */ + +int level; +st_level current_level; +char level_subset[100]; + +int frame; +texture_type selection; +int last_time, now_time; + void le_activate_bad_guys(void) { -int x,y; + int x,y; /* Activate bad guys: */ @@ -115,25 +113,22 @@ void le_set_defaults() /* FIXME: Needs to be implemented. It should ask the user for the level(file)name and then let him create a new level based on this. */ void newlevel() -{ -} +{} /* FIXME: It should let select the user a level, which is in the leveldirectory and then load it. */ void selectlevel() -{ -} +{} int leveleditor() { - char str[10]; + char str[LEVEL_NAME_MAX]; int done; int x, y, i; /* for cicles */ - int pos_x, cursor_x, cursor_y, old_cursor_x, fire; + int pos_x, cursor_x, cursor_y, fire; SDL_Event event; SDLKey key; SDLMod keymod; - int last_time, now_time; - + strcpy(level_subset,"default"); level = 1; @@ -143,20 +138,21 @@ int leveleditor() show_menu = YES; frame = 0; /* support for frames in some tiles, like waves and bad guys */ - + loadshared(); + set_defaults(); + loadlevel(¤t_level,"default",level); - loadlevelgfx(); + loadlevelgfx(¤t_level); le_activate_bad_guys(); le_set_defaults(); - - selection = load_image(DATA_PREFIX "/images/leveleditor/select.png", USE_ALPHA); + + texture_load(&selection,DATA_PREFIX "/images/leveleditor/select.png", USE_ALPHA); done = 0; pos_x = 0; cursor_x = 3*32; - old_cursor_x = cursor_x; cursor_y = 2*32; fire = DOWN; @@ -164,11 +160,11 @@ int leveleditor() while(1) { - SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue)); + clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); last_time = SDL_GetTicks(); frame++; - + keymod = SDL_GetModState(); while(SDL_PollEvent(&event)) @@ -218,11 +214,11 @@ int leveleditor() else cursor_y += KEY_CURSOR_FASTSPEED; - if(cursor_y > 480-32) - cursor_y = 480-32; + if(cursor_y > screen->h-32) + cursor_y = screen->h-32; break; case SDLK_LCTRL: - fire = UP; + fire =UP; break; case SDLK_F1: showhelp(); @@ -234,114 +230,114 @@ int leveleditor() cursor_x = (current_level.width * 32) - 32; break; case SDLK_PERIOD: - le_change(cursor_x, cursor_y, 0, '.'); + le_change(cursor_x, cursor_y, '.'); break; case SDLK_a: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, 'A'); + le_change(cursor_x, cursor_y, 'A'); else - le_change(cursor_x, cursor_y, 0, 'a'); + le_change(cursor_x, cursor_y, 'a'); break; case SDLK_b: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, 'B'); + le_change(cursor_x, cursor_y, 'B'); break; case SDLK_c: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, 'C'); + le_change(cursor_x, cursor_y, 'C'); else - le_change(cursor_x, cursor_y, 0, 'c'); + le_change(cursor_x, cursor_y, 'c'); break; case SDLK_d: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, 'D'); + le_change(cursor_x, cursor_y, 'D'); else - le_change(cursor_x, cursor_y, 0, 'd'); + le_change(cursor_x, cursor_y, 'd'); break; case SDLK_e: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, 'E'); + le_change(cursor_x, cursor_y, 'E'); else - le_change(cursor_x, cursor_y, 0, 'e'); + le_change(cursor_x, cursor_y, 'e'); break; case SDLK_f: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, 'F'); + le_change(cursor_x, cursor_y, 'F'); else - le_change(cursor_x, cursor_y, 0, 'f'); + le_change(cursor_x, cursor_y, 'f'); break; case SDLK_g: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, 'G'); + le_change(cursor_x, cursor_y, 'G'); else - le_change(cursor_x, cursor_y, 0, 'g'); + le_change(cursor_x, cursor_y, 'g'); break; case SDLK_h: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, 'H'); + le_change(cursor_x, cursor_y, 'H'); else - le_change(cursor_x, cursor_y, 0, 'h'); + le_change(cursor_x, cursor_y, 'h'); break; case SDLK_i: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, 'I'); + le_change(cursor_x, cursor_y, 'I'); else - le_change(cursor_x, cursor_y, 0, 'i'); + le_change(cursor_x, cursor_y, 'i'); break; case SDLK_j: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, 'J'); + le_change(cursor_x, cursor_y, 'J'); else - le_change(cursor_x, cursor_y, 0, 'j'); + le_change(cursor_x, cursor_y, 'j'); break; case SDLK_x: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, 'X'); + le_change(cursor_x, cursor_y, 'X'); else - le_change(cursor_x, cursor_y, 0, 'x'); + le_change(cursor_x, cursor_y, 'x'); break; case SDLK_y: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, 'Y'); + le_change(cursor_x, cursor_y, 'Y'); else - le_change(cursor_x, cursor_y, 0, 'y'); + le_change(cursor_x, cursor_y, 'y'); break; case SDLK_LEFTBRACKET: - le_change(cursor_x, cursor_y, 0, '['); + le_change(cursor_x, cursor_y, '['); break; case SDLK_RIGHTBRACKET: - le_change(cursor_x, cursor_y, 0, ']'); + le_change(cursor_x, cursor_y, ']'); break; case SDLK_HASH: case SDLK_3: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, '#'); + le_change(cursor_x, cursor_y, '#'); break; case SDLK_DOLLAR: case SDLK_4: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, '$'); + le_change(cursor_x, cursor_y, '$'); break; case SDLK_BACKSLASH: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, '|'); + le_change(cursor_x, cursor_y, '|'); else - le_change(cursor_x, cursor_y, 0, '\\'); + le_change(cursor_x, cursor_y, '\\'); break; case SDLK_CARET: - le_change(cursor_x, cursor_y, 0, '^'); + le_change(cursor_x, cursor_y, '^'); break; case SDLK_AMPERSAND: case SDLK_6: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, '&'); + le_change(cursor_x, cursor_y, '&'); break; case SDLK_EQUALS: case SDLK_0: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, '='); + le_change(cursor_x, cursor_y, '='); else /* let's add a bad guy */ - le_change(cursor_x, cursor_y, 0, '0'); + le_change(cursor_x, cursor_y, '0'); for(i = 0; i < NUM_BAD_GUYS; ++i) if (bad_guys[i].alive == NO) @@ -355,9 +351,9 @@ int leveleditor() break; case SDLK_1: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, '!'); + le_change(cursor_x, cursor_y, '!'); else /* let's add a bad guy */ - le_change(cursor_x, cursor_y, 0, '1'); + le_change(cursor_x, cursor_y, '1'); for(i = 0; i < NUM_BAD_GUYS; ++i) if (bad_guys[i].alive == NO) @@ -370,7 +366,7 @@ int leveleditor() } break; case SDLK_2: - le_change(cursor_x, cursor_y, 0, '2'); + le_change(cursor_x, cursor_y, '2'); for(i = 0; i < NUM_BAD_GUYS; ++i) if (bad_guys[i].alive == NO) @@ -384,7 +380,7 @@ int leveleditor() break; case SDLK_PLUS: if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS) - le_change(cursor_x, cursor_y, 0, '*'); + le_change(cursor_x, cursor_y, '*'); break; default: break; @@ -406,8 +402,14 @@ int leveleditor() break; } break; - case SDL_MOUSEBUTTONDOWN: - if(event.button.button == SDL_BUTTON_LEFT) + /* case SDL_MOUSEBUTTONDOWN: + if(event.button.button == SDL_BUTTON_LEFT) + { + This will draw current tile in the cursor position, when the interface is done. + } + break;*/ + case SDL_MOUSEMOTION: + if(!show_menu) { x = event.motion.x; y = event.motion.y; @@ -416,13 +418,6 @@ int leveleditor() cursor_y = ((int) y / 32) * 32; } break; - case SDL_MOUSEMOTION: - x = event.motion.x; - y = event.motion.y; - - cursor_x = ((int)(pos_x + x) / 32) * 32; - cursor_y = ((int) y / 32) * 32; - break; case SDL_QUIT: // window closed done = DONE_QUIT; break; @@ -432,27 +427,23 @@ int leveleditor() } /* mouse movements */ - x = event.motion.x; - if(x < MOUSE_LEFT_MARGIN) - pos_x -= MOUSE_POS_SPEED; - else if(x > MOUSE_RIGHT_MARGIN) - pos_x += MOUSE_POS_SPEED; + /* x = event.motion.x; + if(x < MOUSE_LEFT_MARGIN) + pos_x -= MOUSE_POS_SPEED; + else if(x > MOUSE_RIGHT_MARGIN) + pos_x += MOUSE_POS_SPEED;*/ - if(old_cursor_x != cursor_x) - { - if(cursor_x < pos_x + KEY_LEFT_MARGIN) - pos_x = cursor_x - KEY_LEFT_MARGIN; - if(cursor_x > pos_x + KEY_RIGHT_MARGIN) - pos_x = cursor_x - KEY_RIGHT_MARGIN; - } + if(cursor_x < pos_x + CURSOR_LEFT_MARGIN) + pos_x = cursor_x - CURSOR_LEFT_MARGIN; + + if(cursor_x > pos_x + CURSOR_RIGHT_MARGIN) + pos_x = cursor_x - CURSOR_RIGHT_MARGIN; if(pos_x < 0) pos_x = 0; - if(pos_x > (current_level.width * 32) - 640) - pos_x = (current_level.width * 32) - 640; - - old_cursor_x = cursor_x; + if(pos_x > (current_level.width * 32) - screen->w) + pos_x = (current_level.width * 32) - screen->w; for (y = 0; y < 15; ++y) for (x = 0; x < 21; ++x) @@ -466,15 +457,15 @@ int leveleditor() continue; /* to support frames: img_bsod_left[(frame / 5) % 4] */ if(bad_guys[i].kind == BAD_BSOD) - drawimage(img_bsod_left[(frame / 5) % 4], ((int)(bad_guys[i].x - pos_x)/32)*32, bad_guys[i].y, NO_UPDATE); + texture_draw(&img_bsod_left[(frame / 5) % 4], ((int)(bad_guys[i].x - pos_x)/32)*32, bad_guys[i].y, NO_UPDATE); else if(bad_guys[i].kind == BAD_LAPTOP) - drawimage(img_laptop_left[(frame / 5) % 3], ((int)(bad_guys[i].x - pos_x)/32)*32, bad_guys[i].y, NO_UPDATE); + texture_draw(&img_laptop_left[(frame / 5) % 3], ((int)(bad_guys[i].x - pos_x)/32)*32, bad_guys[i].y, NO_UPDATE); else if (bad_guys[i].kind == BAD_MONEY) - drawimage(img_money_left[(frame / 5) % 2], ((int)(bad_guys[i].x - pos_x)/32)*32, bad_guys[i].y, NO_UPDATE); + texture_draw(&img_money_left[(frame / 5) % 2], ((int)(bad_guys[i].x - pos_x)/32)*32, bad_guys[i].y, NO_UPDATE); } - drawimage(selection, ((int)(cursor_x - pos_x)/32)*32, cursor_y, NO_UPDATE); + texture_draw(&selection, ((int)(cursor_x - pos_x)/32)*32, cursor_y, NO_UPDATE); sprintf(str, "%d", current_level.time_left); drawtext("TIME", 324, 0, letters_blue, NO_UPDATE, 1); @@ -496,38 +487,36 @@ int leveleditor() return 1; SDL_Delay(50); - now_time = SDL_GetTicks(); - if (now_time < last_time + FPS) - SDL_Delay(last_time + FPS - now_time); /* delay some time */ + now_time = SDL_GetTicks(); + if (now_time < last_time + FPS) + SDL_Delay(last_time + FPS - now_time); /* delay some time */ - SDL_Flip(screen); + flipscreen(); } unloadlevelgfx(); unloadshared(); - SDL_FreeSurface(selection); + texture_free(&selection); return done; } -void le_change(int x, int y, int sx, unsigned char c) +void le_change(float x, float y, unsigned char c) { - int xx, yy; - int i; +int i; +int xx, yy; + + level_change(¤t_level,x,y,c); yy = (y / 32); - xx = ((x + sx) / 32); + xx = (x / 32); /* if there is a bad guy over there, remove it */ for(i = 0; i < NUM_BAD_GUYS; ++i) if (bad_guys[i].alive) if(xx == bad_guys[i].x/32 && yy == bad_guys[i].y/32) bad_guys[i].alive = NO; - - - if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width) - current_level.tiles[yy][xx] = c; } /* Save data for this level: */ @@ -580,7 +569,7 @@ void savelevel(void) fclose(fi); drawcenteredtext("SAVED!", 240, letters_gold, NO_UPDATE, 1); - SDL_Flip(screen); + flipscreen(); SDL_Delay(1000); } @@ -610,16 +599,18 @@ void showhelp() "0-2 - BadGuys", "./Del - Remove tile", "Esc - Menu"}; - int i; - drawcenteredtext("- Help -", 30, letters_red, NO_UPDATE, 1); + drawcenteredtext("- Help -", 30, letters_red, NO_UPDATE, 2); drawtext("Keys:", 80, 60, letters_gold, NO_UPDATE, 1); + int i; for(i = 0; i < sizeof(text)/sizeof(char *); i++) drawtext(text[i], 40, 90+(i*16), letters_blue, NO_UPDATE, 1); - SDL_Flip(screen); + drawcenteredtext("Press Any Key to Continue", 460, letters_gold, NO_UPDATE, 1); + + flipscreen(); done = 0; @@ -627,6 +618,7 @@ void showhelp() while(SDL_PollEvent(&event)) switch(event.type) { + case SDL_MOUSEBUTTONDOWN: // mouse pressed case SDL_KEYDOWN: // key pressed done = 1; break; diff --git a/src/menu.c b/src/menu.c index 6d2042ab3..b16670b62 100644 --- a/src/menu.c +++ b/src/menu.c @@ -115,19 +115,7 @@ void menu_option_music() use_music = YES; if (!playing_music()) { - switch (current_music) - { - case LEVEL_MUSIC: - play_music(level_song, 2); - break; - case HERRING_MUSIC: - play_music(herring_song, 2); - break; - case HURRYUP_MUSIC: // keep the compiler happy - case NO_MUSIC: // keep the compiler happy for the moment :-) - {} - /*default:*/ - } + play_current_music(); } } menu_change = YES; diff --git a/src/player.c b/src/player.c new file mode 100644 index 000000000..b7543763e --- /dev/null +++ b/src/player.c @@ -0,0 +1,1043 @@ +// +// C Implementation: player/tux +// +// Description: +// +// +// Author: Tobias Glaesser , (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include "gameloop.h" +#include "globals.h" +#include "player.h" +#include "defines.h" +#include "scene.h" +#include "screen.h" + +void player_init(player_type* pplayer) +{ + pplayer->it.alive = NULL; + pplayer->it.x = &pplayer->x; + pplayer->it.y = &pplayer->y; + pplayer->it.width = &pplayer->width; + pplayer->it.height = &pplayer->height; + pplayer->it.updated = &pplayer->updated; + + pplayer->width = 32; + pplayer->height = 32; + + pplayer->updated = SDL_GetTicks(); + pplayer->size = SMALL; + pplayer->got_coffee = NO; + + pplayer->x = 0; + pplayer->xm = 0; + pplayer->y = 240; + pplayer->ym = 0; + pplayer->dir = RIGHT; + pplayer->duck = NO; + + pplayer->dying = NO; + pplayer->safe = TUX_SAFE_TIME; + + pplayer->jumping = NO; + pplayer->skidding = 0; + + pplayer->frame_main = 0; + pplayer->frame = 0; + pplayer->lives = 3; + + pplayer->input.down = UP; + pplayer->input.fire = UP; + pplayer->input.left = UP; + pplayer->input.old_fire = UP; + pplayer->input.right = UP; + pplayer->input.up = UP; + + timer_init(&pplayer->invincible_timer); +} + +void player_level_begin(player_type* pplayer) +{ + pplayer->x = 0; + pplayer->xm = 0; + pplayer->y = 240; + pplayer->ym = 0; +} + +void player_action(player_type* pplayer) +{ + + double frame_ratio = get_frame_ratio(&pplayer->it); + + /* --- HANDLE TUX! --- */ + + player_input(pplayer); + + /* Move tux: */ + + pplayer->x = pplayer->x + pplayer->xm * frame_ratio; + pplayer->y = pplayer->y + pplayer->ym * frame_ratio; + + player_keep_in_bounds(pplayer); + + /* Land: */ + + if (!pplayer->dying) + { + if (issolid(pplayer->x, pplayer->y + 31) && + !issolid(pplayer->x - pplayer->xm, pplayer->y + 31)) + { + while (issolid(pplayer->x, pplayer->y + 31)) + { + if (pplayer->xm < 0) + pplayer->x++; + else if (pplayer->xm > 0) + pplayer->x--; + } + + pplayer->xm = 0; + } + + if (issolid(pplayer->x, pplayer->y) && + !issolid(pplayer->x - pplayer->xm, pplayer->y)) + { + while (issolid(pplayer->x, (pplayer->y))) + { + if (pplayer->xm < 0) + pplayer->x++; + else if (pplayer->xm > 0) + pplayer->x--; + } + + pplayer->xm = 0; + } + + if (issolid(pplayer->x, pplayer->y + 31)) + { + /* Set down properly: */ + + int debug_int = 0; + while (issolid(pplayer->x, pplayer->y + 31)) + { + ++debug_int; + if(debug_int > 32) + DEBUG_MSG("FIXME - UNDER certain circumstances I'm hanging in a loop here!"); + + if (pplayer->ym < 0) + pplayer->y++; + else if (pplayer->ym > 0) + pplayer->y--; + } + + + /* Reset score multiplier (for multi-hits): */ + + if (pplayer->ym > 0) + score_multiplier = 1; + + + /* Stop jumping! */ + + pplayer->ym = 0; + pplayer->jumping = NO; + } + + + /* Bump into things: */ + + if (issolid(pplayer->x, pplayer->y) || + (pplayer->size == BIG && !pplayer->duck && + (issolid(pplayer->x, pplayer->y - 32)))) + { + if (!issolid(pplayer->x - pplayer->xm, pplayer->y) && + (pplayer->size == SMALL || pplayer->duck || + !issolid(pplayer->x - pplayer->xm, pplayer->y - 32))) + { + pplayer->x = pplayer->x - pplayer->xm; + pplayer->xm = 0; + } + else if (!issolid(pplayer->x, pplayer->y - pplayer->ym) && + (pplayer->size == SMALL || pplayer->duck || + !issolid(pplayer->x, pplayer->y - 32 - pplayer->ym))) + { + if (pplayer->ym <= 0) + { + /* Jumping up? */ + + if (pplayer->size == BIG) + { + /* Break bricks and empty boxes: */ + + if (!pplayer->duck) + { + if (isbrick(pplayer->x, pplayer->y - 32) || + isfullbox(pplayer->x, pplayer->y - 32)) + { + trygrabdistro(pplayer->x, pplayer->y - 64, BOUNCE); + trybumpbadguy(pplayer->x, pplayer->y - 96); + + if (isfullbox(pplayer->x, pplayer->y - 32)) + { + bumpbrick(pplayer->x, pplayer->y - 32); + } + + trybreakbrick(pplayer->x, pplayer->y - 32); + tryemptybox(pplayer->x, pplayer->y - 32); + } + + if (isbrick(pplayer->x + 31, pplayer->y - 32) || + isfullbox(pplayer->x + 31, pplayer->y - 32)) + { + trygrabdistro(pplayer->x + 31, + pplayer->y - 64, + BOUNCE); + trybumpbadguy(pplayer->x + 31, + pplayer->y - 96); + + if (isfullbox(pplayer->x + 31, pplayer->y - 32)) + { + bumpbrick(pplayer->x + 31, pplayer->y - 32); + } + + trybreakbrick(pplayer->x + 31, + pplayer->y - 32); + tryemptybox(pplayer->x + 31, + pplayer->y - 32); + } + } + else /* ducking */ + { + if (isbrick(pplayer->x, pplayer->y) || + isfullbox(pplayer->x, pplayer->y)) + { + trygrabdistro(pplayer->x, pplayer->y - 32,BOUNCE); + trybumpbadguy(pplayer->x, pplayer->y - 64); + if (isfullbox(pplayer->x, pplayer->y)) + bumpbrick(pplayer->x, pplayer->y); + trybreakbrick(pplayer->x, pplayer->y); + tryemptybox(pplayer->x, pplayer->y); + } + + if (isbrick(pplayer->x + 31, pplayer->y) || + isfullbox(pplayer->x + 31, pplayer->y)) + { + trygrabdistro(pplayer->x + 31, + pplayer->y - 32, + BOUNCE); + trybumpbadguy(pplayer->x + 31, + pplayer->y - 64); + if (isfullbox(pplayer->x + 31, pplayer->y)) + bumpbrick(pplayer->x + 31, pplayer->y); + trybreakbrick(pplayer->x + 31, pplayer->y); + tryemptybox(pplayer->x + 31, pplayer->y); + } + } + } + else + { + /* It's a brick and we're small, make the brick + bounce, and grab any distros above it: */ + + if (isbrick(pplayer->x, pplayer->y) || + isfullbox(pplayer->x, pplayer->y)) + { + trygrabdistro(pplayer->x, pplayer->y - 32,BOUNCE); + trybumpbadguy(pplayer->x, pplayer->y - 64); + bumpbrick(pplayer->x, pplayer->y); + tryemptybox(pplayer->x, pplayer->y); + } + + if (isbrick(pplayer->x + 31, pplayer->y) || + isfullbox(pplayer->x + 31, pplayer->y)) + { + trygrabdistro(pplayer->x + 31, pplayer->y - 32,BOUNCE); + trybumpbadguy(pplayer->x + 31, pplayer->y - 64); + bumpbrick(pplayer->x + 31, pplayer->y); + tryemptybox(pplayer->x + 31, pplayer->y); + } + + + /* Get a distro from a brick? */ + + if (shape(pplayer->x, pplayer->y) == 'x' || + shape(pplayer->x, pplayer->y) == 'y') + { + add_bouncy_distro(((pplayer->x + 1) + / 32) * 32, + (int)(pplayer->y / 32) * 32); + + if (counting_distros == NO) + { + counting_distros = YES; + distro_counter = 100; + } + + if (distro_counter <= 0) + level_change(¤t_level,pplayer->x, pplayer->y, 'a'); + + play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER); + score = score + SCORE_DISTRO; + distros++; + } + else if (shape(pplayer->x + 31, pplayer->y) == 'x' || + shape(pplayer->x + 31, pplayer->y) == 'y') + { + add_bouncy_distro(((pplayer->x + 1 + 31) + / 32) * 32, + (int)(pplayer->y / 32) * 32); + + if (counting_distros == NO) + { + counting_distros = YES; + distro_counter = 100; + } + + if (distro_counter <= 0) + level_change(¤t_level,pplayer->x + 31 + scroll_x, pplayer->y, 'a'); + + play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER); + score = score + SCORE_DISTRO; + distros++; + } + } + + + /* Bump head: */ + + pplayer->y = (int)(pplayer->y / 32) * 32 + 30; + } + else + { + /* Land on feet: */ + + pplayer->y = (int)(pplayer->y / 32) * 32 - 32; + } + + pplayer->ym = 0; + pplayer->jumping = NO; + /*pplayer->jump_counter = MAX_JUMP_COUNT;*/ + /*timer_init(&pplayer->jump_timer);*/ + timer_start(&pplayer->jump_timer,MAX_JUMP_TIME); + } + } + } + + + + player_grabdistros(pplayer); + + + /* Slow down horizontally: */ + + if (!pplayer->dying) + { + if (pplayer->input.right == UP && pplayer->input.left == UP) + { + if (isice(pplayer->x, pplayer->y + 32) || + !issolid(pplayer->x, pplayer->y + 32)) + { + /* Slowly on ice or in air: */ + + if (pplayer->xm > 0) + pplayer->xm--; + else if (pplayer->xm < 0) + pplayer->xm++; + } + else + { + /* Quickly, otherwise: */ + + pplayer->xm = pplayer->xm / 2; + } + } + + + /* Drop vertically: */ + + if (!issolid(pplayer->x, pplayer->y + 32)) + { + pplayer->ym = pplayer->ym + GRAVITY; + + if (pplayer->ym > MAX_YM) + pplayer->ym = MAX_YM; + } + } + + + + if (pplayer->safe > 0) + pplayer->safe--; + + /* ---- DONE HANDLING TUX! --- */ + + /* Handle invincibility timer: */ + + + if (timer_check(&pplayer->invincible_timer)) + { + if (current_music == HERRING_MUSIC) + { + if (current_level.time_left <= TIME_WARNING) + { + /* stop the herring_song, prepare to play the correct + * fast level_song ! + */ + current_music = HURRYUP_MUSIC; + } + else + { + current_music = LEVEL_MUSIC; + } + /* stop the old music if it's being played */ + if (playing_music()) + halt_music(); + } + } + + /* Handle skidding: */ + + if (pplayer->skidding > 0) + { + pplayer->skidding--; + } + + /* End of level? */ + + if (pplayer->x >= endpos && endpos != 0) + { + next_level = 1; + } + +} + +void player_input(player_type *pplayer) +{ + /* Handle key and joystick state: */ + + + if (pplayer->input.right == DOWN && pplayer->input.left == UP) + { + if (pplayer->jumping == NO) + { + if (pplayer->xm < -SKID_XM && !pplayer->skidding && + pplayer->dir == LEFT) + { + pplayer->skidding = SKID_TIME; + + play_sound(sounds[SND_SKID], SOUND_CENTER_SPEAKER); + + } + pplayer->dir = RIGHT; + } + + if (pplayer->xm < 0 && !isice(pplayer->x, pplayer->y + 32) && + !pplayer->skidding) + { + pplayer->xm = 0; + } + + if (!pplayer->duck) + { + if (pplayer->dir == RIGHT) + { + /* Facing the direction we're jumping? Go full-speed: */ + + if (pplayer->input.fire == UP) + { + pplayer->xm = pplayer->xm + WALK_SPEED; + + if (pplayer->xm > MAX_WALK_XM) + pplayer->xm = MAX_WALK_XM; + } + else if ( pplayer->input.fire == DOWN) + { + pplayer->xm = pplayer->xm + RUN_SPEED; + + if (pplayer->xm > MAX_RUN_XM) + pplayer->xm = MAX_RUN_XM; + } + } + else + { + /* Not facing the direction we're jumping? + Go half-speed: */ + + pplayer->xm = pplayer->xm + WALK_SPEED / 2; + + if (pplayer->xm > MAX_WALK_XM / 2) + pplayer->xm = MAX_WALK_XM / 2; + } + } + } + else if (pplayer->input.left == DOWN && pplayer->input.right == UP) + { + if (pplayer->jumping == NO) + { + if (pplayer->xm > SKID_XM && !pplayer->skidding && + pplayer->dir == RIGHT) + { + pplayer->skidding = SKID_TIME; + play_sound(sounds[SND_SKID], SOUND_CENTER_SPEAKER); + } + pplayer->dir = LEFT; + } + + if (pplayer->xm > 0 && !isice(pplayer->x, pplayer->y + 32) && + !pplayer->skidding) + { + pplayer->xm = 0; + } + + if (!pplayer->duck) + { + if (pplayer->dir == LEFT) + { + /* Facing the direction we're jumping? Go full-speed: */ + + if (pplayer->input.fire == UP) + { + pplayer->xm = pplayer->xm - WALK_SPEED; + + if (pplayer->xm < -MAX_WALK_XM) + pplayer->xm = -MAX_WALK_XM; + } + else if (pplayer->input.fire == DOWN) + { + pplayer->xm = pplayer->xm - RUN_SPEED; + + if (pplayer->xm < -MAX_RUN_XM) + pplayer->xm = -MAX_RUN_XM; + } + } + else + { + /* Not facing the direction we're jumping? + Go half-speed: */ + + pplayer->xm = pplayer->xm - WALK_SPEED / 2; + + if (pplayer->xm < -MAX_WALK_XM / 2) + pplayer->xm = -MAX_WALK_XM / 2; + } + } + } + + /* Jump/jumping? */ + + if ( pplayer->input.up == DOWN) + { + if(!timer_started(&pplayer->jump_timer)) + { + timer_start(&pplayer->jump_timer,MAX_JUMP_TIME); + + + /* Taking off? */ + + if (!issolid(pplayer->x, pplayer->y + 32) || + pplayer->ym != 0) + { + /* If they're not on the ground, or are currently moving + vertically, don't jump! */ + + pplayer->jumping = NO; + timer_stop(&pplayer->jump_timer); + } + else + { + /* Make sure we're not standing back up into a solid! */ + + if (pplayer->size == SMALL || pplayer->duck == NO || + !issolid(pplayer->x, pplayer->y)) + { + pplayer->jumping = YES; + + if (pplayer->size == SMALL) + play_sound(sounds[SND_JUMP], SOUND_CENTER_SPEAKER); + else + play_sound(sounds[SND_BIGJUMP], SOUND_CENTER_SPEAKER); + } + } + } + + /* Keep jumping for a while: */ + + if (timer_check(&pplayer->jump_timer)) + { + pplayer->ym = pplayer->ym - JUMP_SPEED; + } + } + else + timer_stop(&pplayer->jump_timer); + + + /* Shoot! */ + + if (pplayer->input.fire == DOWN && pplayer->input.old_fire == UP && pplayer->got_coffee) + { + add_bullet(pplayer->x, pplayer->y, pplayer->xm, pplayer->dir); + } + + + /* Duck! */ + + if (pplayer->input.down == DOWN) + { + if (pplayer->size == BIG) + pplayer->duck = YES; + } + else + { + if (pplayer->size == BIG && pplayer->duck == YES) + { + /* Make sure we're not standing back up into a solid! */ + + if (!issolid(pplayer->x, pplayer->y - 32)) + pplayer->duck = NO; + } + else + pplayer->duck = NO; + } + + /* (Tux): */ + + if (pplayer->input.right == UP && pplayer->input.left == UP) + { + pplayer->frame_main = 1; + pplayer->frame = 1; + } + else + { + if ((pplayer->input.fire == DOWN && (frame % 2) == 0) || + (frame % 4) == 0) + pplayer->frame_main = (pplayer->frame_main + 1) % 4; + + pplayer->frame = pplayer->frame_main; + + if (pplayer->frame == 3) + pplayer->frame = 1; + } + +} + +void player_grabdistros(player_type *pplayer) +{ + /* Grab distros: */ + if (!pplayer->dying) + { + trygrabdistro(pplayer->x , pplayer->y, NO_BOUNCE); + trygrabdistro(pplayer->x + 31, pplayer->y, NO_BOUNCE); + + if (pplayer->size == BIG && !pplayer->duck) + { + trygrabdistro(pplayer->x, pplayer->y - 32, NO_BOUNCE); + trygrabdistro(pplayer->x + 31, pplayer->y - 32, NO_BOUNCE); + } + } + + + /* Enough distros for a One-up? */ + + if (distros >= DISTROS_LIFEUP) + { + distros = distros - DISTROS_LIFEUP; + if(pplayer->lives < MAX_LIVES) + pplayer->lives++; + /*We want to hear the sound even, if MAX_LIVES is reached*/ + play_sound(sounds[SND_LIFEUP], SOUND_CENTER_SPEAKER); + } +} + +void player_draw(player_type* pplayer) +{ + + if (pplayer->safe == 0 || (frame % 2) == 0) + { + if (pplayer->size == SMALL) + { + if (timer_started(&pplayer->invincible_timer)) + { + /* Draw cape: */ + + if (pplayer->dir == RIGHT) + { + texture_draw(&cape_right[frame % 2], + pplayer->x - scroll_x, pplayer->y, + NO_UPDATE); + } + else + { + texture_draw(&cape_left[frame % 2], + pplayer->x - scroll_x, pplayer->y, + NO_UPDATE); + } + } + + + if (!pplayer->got_coffee) + { + if (pplayer->dir == RIGHT) + { + texture_draw(&tux_right[pplayer->frame], pplayer->x - scroll_x, pplayer->y, NO_UPDATE); + } + else + { + texture_draw(&tux_left[pplayer->frame], pplayer->x - scroll_x, pplayer->y, NO_UPDATE); + } + } + else + { + /* Tux got coffee! */ + + if (pplayer->dir == RIGHT) + { + texture_draw(&firetux_right[pplayer->frame], pplayer->x - scroll_x, pplayer->y, NO_UPDATE); + } + else + { + texture_draw(&firetux_left[pplayer->frame], pplayer->x - scroll_x, pplayer->y, NO_UPDATE); + } + } + } + else + { + if (timer_started(&pplayer->invincible_timer)) + { + /* Draw cape: */ + + if (pplayer->dir == RIGHT) + { + texture_draw(&bigcape_right[frame % 2], + pplayer->x - scroll_x - 8 - 16, pplayer->y - 32, + NO_UPDATE); + } + else + { + texture_draw(&bigcape_left[frame % 2], + pplayer->x -scroll_x - 8, pplayer->y - 32, + NO_UPDATE); + } + } + + if (!pplayer->got_coffee) + { + if (!pplayer->duck) + { + if (!pplayer->skidding) + { + if (!pplayer->jumping || pplayer->ym > 0) + { + if (pplayer->dir == RIGHT) + { + texture_draw(&bigtux_right[pplayer->frame], + pplayer->x - scroll_x - 8, pplayer->y - 32, + NO_UPDATE); + } + else + { + texture_draw(&bigtux_left[pplayer->frame], + pplayer->x - scroll_x - 8, pplayer->y - 32, + NO_UPDATE); + } + } + else + { + if (pplayer->dir == RIGHT) + { + texture_draw(&bigtux_right_jump, + pplayer->x - scroll_x - 8, pplayer->y - 32, + NO_UPDATE); + } + else + { + texture_draw(&bigtux_left_jump, + pplayer->x - scroll_x - 8, pplayer->y - 32, + NO_UPDATE); + } + } + } + else + { + if (pplayer->dir == RIGHT) + { + texture_draw(&skidtux_right, + pplayer->x - scroll_x - 8, pplayer->y - 32, + NO_UPDATE); + } + else + { + texture_draw(&skidtux_left, + pplayer->x - scroll_x - 8, pplayer->y - 32, + NO_UPDATE); + } + } + } + else + { + if (pplayer->dir == RIGHT) + { + texture_draw(&ducktux_right, pplayer->x - scroll_x - 8, pplayer->y - 16, + NO_UPDATE); + } + else + { + texture_draw(&ducktux_left, pplayer->x - scroll_x - 8, pplayer->y - 16, + NO_UPDATE); + } + } + } + else + { + /* Tux has coffee! */ + + if (!pplayer->duck) + { + if (!pplayer->skidding) + { + if (!pplayer->jumping || pplayer->ym > 0) + { + if (pplayer->dir == RIGHT) + { + texture_draw(&bigfiretux_right[pplayer->frame], + pplayer->x - scroll_x - 8, pplayer->y - 32, + NO_UPDATE); + } + else + { + texture_draw(&bigfiretux_left[pplayer->frame], + pplayer->x - scroll_x - 8, pplayer->y - 32, + NO_UPDATE); + } + } + else + { + if (pplayer->dir == RIGHT) + { + texture_draw(&bigfiretux_right_jump, + pplayer->x - scroll_x - 8, pplayer->y - 32, + NO_UPDATE); + } + else + { + texture_draw(&bigfiretux_left_jump, + pplayer->x - scroll_x - 8, pplayer->y - 32, + NO_UPDATE); + } + } + } + else + { + if (pplayer->dir == RIGHT) + { + texture_draw(&skidfiretux_right, + pplayer->x - scroll_x - 8, pplayer->y - 32, + NO_UPDATE); + } + else + { + texture_draw(&skidfiretux_left, + pplayer->x - scroll_x - 8, pplayer->y - 32, + NO_UPDATE); + } + } + } + else + { + if (pplayer->dir == RIGHT) + { + texture_draw(&duckfiretux_right, pplayer->x - scroll_x - 8, pplayer->y - 16, + NO_UPDATE); + } + else + { + texture_draw(&duckfiretux_left, pplayer->x - scroll_x - 8, pplayer->y - 16, + NO_UPDATE); + } + } + } + } + } + +} + +void player_collision(player_type* pplayer, void* p_c_object, int c_object) +{ + bad_guy_type* pbad_c = NULL; + + switch (c_object) + { + case CO_BADGUY: + pbad_c = p_c_object; + /* Hurt the player if he just touched it: */ + + if (!pbad_c->dying && !pplayer->dying && + !pplayer->safe && + pbad_c->mode != HELD) + { + if (pbad_c->mode == FLAT && pplayer->input.fire != DOWN) + { + /* Kick: */ + + pbad_c->mode = KICK; + play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER); + + if (pplayer->x <= pbad_c->x) + { + pbad_c->dir = RIGHT; + pbad_c->x = pbad_c->x + 16; + } + else + { + pbad_c->dir = LEFT; + pbad_c->x = pbad_c->x - 16; + } + + timer_start(&pbad_c->timer,5000); + } + else if (pbad_c->mode == FLAT && pplayer->input.fire == DOWN) + { + pbad_c->mode = HELD; + pbad_c->y-=8; + } + else if (pbad_c->mode == KICK) + { + if (pplayer->y < pbad_c->y - 16 && + timer_started(&pbad_c->timer)) + { + /* Step on (stop being kicked) */ + + pbad_c->mode = FLAT; + play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER); + timer_start(&pbad_c->timer, 10000); + } + else + { + /* Hurt if you get hit by kicked laptop: */ + + if (timer_started(&pbad_c->timer)) + { + if (!timer_started(&pplayer->invincible_timer)) + { + player_kill(pplayer,SHRINK); + } + else + { + pbad_c->dying = FALLING; + pbad_c->ym = -8; + play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER); + } + } + } + } + else + { + if (!timer_started(&pplayer->invincible_timer )) + { + player_kill(pplayer,SHRINK); + } + else + { + pbad_c->dying = FALLING; + pbad_c->ym = -8; + play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER); + } + } + } + score_multiplier++; + break; + } + +} + +/* Kill Player! */ + +void player_kill(player_type* pplayer, int mode) +{ + pplayer->ym = -5; + + play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER); + + if (pplayer->dir == RIGHT) + pplayer->xm = -8; + else if (tux.dir == LEFT) + pplayer->xm = 8; + + if (mode == SHRINK && pplayer->size == BIG) + { + if (pplayer->got_coffee) + pplayer->got_coffee = NO; + + pplayer->size = SMALL; + + pplayer->safe = TUX_SAFE_TIME; + } + else + { + pplayer->dying = 1; + } +} + +void player_dying(player_type *pplayer) +{ + pplayer->ym = pplayer->ym + GRAVITY; + + /* He died :^( */ + + --pplayer->lives; + player_remove_powerups(pplayer); + pplayer->dying = 0; + +} + +/* Remove Tux's power ups */ +void player_remove_powerups(player_type* pplayer) +{ + pplayer->got_coffee = NO; + pplayer->size = SMALL; +} + +void player_keep_in_bounds(player_type* pplayer) +{ + /* Keep tux in bounds: */ + if (pplayer->x < 0) + pplayer->x = 0; + else if(pplayer->x < scroll_x) + pplayer->x = scroll_x; + else if (pplayer->x < 160 + scroll_x && scroll_x > 0 && debug_mode == YES) + { + scroll_x = pplayer->x - 160; + /*pplayer->x += 160;*/ + + if(scroll_x < 0) + scroll_x = 0; + + } + else if (pplayer->x > screen->w / 2 + scroll_x && scroll_x < ((current_level.width * 32) - screen->w)) + { + /* Scroll the screen in past center: */ + + scroll_x = pplayer->x - screen->w / 2; + /*pplayer->x = 320 + scroll_x;*/ + + if (scroll_x > ((current_level.width * 32) - screen->w)) + scroll_x = ((current_level.width * 32) - screen->w); + } + else if (pplayer->x > 608 + scroll_x) + { + /* ... unless there's no more to scroll! */ + + /*pplayer->x = 608 + scroll_x;*/ + } + + /* Keep in-bounds, vertically: */ + + if (pplayer->y < 0) + pplayer->y = 0; + else if (pplayer->y > screen->h) + { + player_kill(&tux,KILL); + } +} diff --git a/src/player.h b/src/player.h index 74e17ba35..c3f05e6e0 100644 --- a/src/player.h +++ b/src/player.h @@ -1,5 +1,5 @@ // -// Interface: tux +// Interface: player/tux // // Description: // @@ -10,25 +10,82 @@ // // -typedef struct upgrade_type - { - int alive; - int kind; - int height; - int x; - int y; - int xm; - int ym; - } -upgrade_type; - -typedef struct bullet_type - { - int alive; - int x; - int y; - int xm; - int ym; - } -bullet_type; +#ifndef SUPERTUX_PLAYER_H +#define SUPERTUX_PLAYER_H +#include +#include "bitmask.h" +#include "type.h" +#include "collision.h" + +/* Times: */ + +#define TUX_SAFE_TIME 16 +#define TUX_INVINCIBLE_TIME 10000 +#define TIME_WARNING 20000 /* When to alert player they're low on time! */ + +typedef struct player_input_type +{ + int right; + int left; + int up; + int down; + int fire; + int old_fire; +} +player_input_type; + +typedef struct player_type +{ + player_input_type input; + int got_coffee; + int size; + int skidding; + int safe; + int duck; + int dying; + int dir; + int jumping; + int frame_main; + int frame; + int lives; + float x; + float y; + float xm; + float ym; + float width; + float height; + timer_type invincible_timer; + timer_type jump_timer; + unsigned int updated; + itop_type it; +} +player_type; + +texture_type tux_life, + tux_right[3], tux_left[3], + bigtux_right[3], bigtux_left[3], + bigtux_right_jump, bigtux_left_jump, + ducktux_right, ducktux_left, + skidtux_right, skidtux_left, + firetux_right[3], firetux_left[3], + bigfiretux_right[3], bigfiretux_left[3], + bigfiretux_right_jump, bigfiretux_left_jump, + duckfiretux_right, duckfiretux_left, + skidfiretux_right, skidfiretux_left, + cape_right[2], cape_left[2], + bigcape_right[2], bigcape_left[2]; + +void player_init(player_type* pplayer); +void player_level_begin(player_type* pplayer); +void player_action(player_type* pplayer); +void player_input(player_type* pplayer); +void player_grabdistros(player_type *pplayer); +void player_draw(player_type* pplayer); +void player_collision(player_type* pplayer,void* p_c_object, int c_object); +void player_kill(player_type *pplayer, int mode); +void player_dying(player_type *pplayer); +void player_remove_powerups(player_type *pplayer); +void player_keep_in_bounds(player_type *pplayer); + +#endif /*SUPERTUX_PLAYER_H*/ diff --git a/src/scene.c b/src/scene.c new file mode 100644 index 000000000..a8f77ee7f --- /dev/null +++ b/src/scene.c @@ -0,0 +1,212 @@ +// +// C Implementation: scene +// +// Description: +// +// +// Author: Tobias Glaesser , (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include "scene.h" + +void set_defaults(void) +{ + int i; + + /* Reset arrays: */ + + for (i = 0; i < NUM_BOUNCY_DISTROS; i++) + bouncy_distros[i].alive = NO; + + for (i = 0; i < NUM_BROKEN_BRICKS; i++) + broken_bricks[i].alive = NO; + + for (i = 0; i < NUM_BOUNCY_BRICKS; i++) + bouncy_bricks[i].alive = NO; + + for (i = 0; i < NUM_BAD_GUYS; i++) + { + /*bad_guys[i].alive = NO;*/ + badguy_init(&bad_guys[i]); + } + + for (i = 0; i < NUM_FLOATING_SCORES; i++) + floating_scores[i].alive = NO; + + for (i = 0; i < NUM_UPGRADES; i++) + { + /*upgrades[i].alive = NO;*/ + upgrade_init(&upgrades[i]); + } + + for (i = 0; i < NUM_BULLETS; i++) + { + /*bullets[i].alive = NO;*/ + bullet_init(&bullets[i]); + } + + + /* Set defaults: */ + + scroll_x = 0; + + score_multiplier = 1; + super_bkgd_time = 0; + + counting_distros = NO; + distro_counter = 0; + + endpos = 0; + + /* set current song/music */ + current_music = LEVEL_MUSIC; +} + +/* Add score: */ + +void add_score(int x, int y, int s) +{ + int i, found; + + + /* Add the score: */ + + score = score + s; + + + /* Add a floating score thing to the game: */ + + found = -1; + + for (i = 0; i < NUM_FLOATING_SCORES && found == -1; i++) + { + if (!floating_scores[i].alive) + found = i; + } + + + if (found != -1) + { + floating_score_init(&floating_scores[i],x,y,s); + } +} + +/* Add a bouncy distro: */ + +void add_bouncy_distro(float x, float y) +{ + int i, found; + + found = -1; + + for (i = 0; i < NUM_BOUNCY_DISTROS && found == -1; i++) + { + if (!bouncy_distros[i].alive) + found = i; + } + + if (found != -1) + { + bouncy_distros[found].alive = YES; + bouncy_distros[found].x = x; + bouncy_distros[found].y = y; + bouncy_distros[found].ym = -6; + } +} + + +/* Add broken brick pieces: */ + +void add_broken_brick(float x, float y) +{ + add_broken_brick_piece(x, y, -4, -16); + add_broken_brick_piece(x, y + 16, -6, -12); + + add_broken_brick_piece(x + 16, y, 4, -16); + add_broken_brick_piece(x + 16, y + 16, 6, -12); +} + + +/* Add a broken brick piece: */ + +void add_broken_brick_piece(float x, float y, float xm, float ym) +{ + int i, found; + + found = -1; + + for (i = 0; i < NUM_BROKEN_BRICKS && found == -1; i++) + { + if (!broken_bricks[i].alive) + found = i; + } + + if (found != -1) + { + broken_bricks[found].alive = YES; + broken_bricks[found].x = x; + broken_bricks[found].y = y; + broken_bricks[found].xm = xm; + broken_bricks[found].ym = ym; + } +} + + +/* Add a bouncy brick piece: */ + +void add_bouncy_brick(float x, float y) +{ + int i, found; + + found = -1; + + for (i = 0; i < NUM_BOUNCY_BRICKS && found == -1; i++) + { + if (!bouncy_bricks[i].alive) + found = i; + } + + if (found != -1) + { + bouncy_bricks[found].alive = YES; + bouncy_bricks[found].x = x; + bouncy_bricks[found].y = y; + bouncy_bricks[found].offset = 0; + bouncy_bricks[found].offset_m = -BOUNCY_BRICK_SPEED; + bouncy_bricks[found].shape = shape(x, y); + } +} + + +/* Add a bad guy: */ + +void add_bad_guy(float x, float y, int kind) +{ + int i, found; + + found = -1; + + for (i = 0; i < NUM_BAD_GUYS && found == -1; i++) + { + if (!bad_guys[i].alive) + found = i; + } + + if (found != -1) + { + bad_guys[found].alive = YES; + bad_guys[found].mode = NORMAL; + bad_guys[found].dying = NO; + bad_guys[found].kind = kind; + bad_guys[found].x = x; + bad_guys[found].y = y; + bad_guys[found].xm = 1.3; + bad_guys[found].ym = 1.5; + bad_guys[found].dir = LEFT; + bad_guys[found].seen = NO; + timer_init(&bad_guys[found].timer); + } +} diff --git a/src/scene.h b/src/scene.h new file mode 100644 index 000000000..46cf0b610 --- /dev/null +++ b/src/scene.h @@ -0,0 +1,45 @@ +// +// C Interface: scene +// +// Description: +// +// +// Author: Tobias Glaesser , (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef SUPERTUX_SCENE_H +#define SUPERTUX_SCENE_H + +#include "defines.h" +#include "gameloop.h" +#include "player.h" +#include "badguy.h" +#include "world.h" +#include "special.h" +#include "level.h" + +#define FRAME_RATE 10 // 100 Frames per second (10ms) +int score, highscore, distros, level, next_level, game_pause, +done, quit, score_multiplier, super_bkgd_time, endpos, +counting_distros, distro_counter; +float scroll_x; +int frame; +bouncy_distro_type bouncy_distros[NUM_BOUNCY_DISTROS]; +broken_brick_type broken_bricks[NUM_BROKEN_BRICKS]; +bouncy_brick_type bouncy_bricks[NUM_BOUNCY_BRICKS]; +bad_guy_type bad_guys[NUM_BAD_GUYS]; +floating_score_type floating_scores[NUM_FLOATING_SCORES]; +upgrade_type upgrades[NUM_UPGRADES]; +bullet_type bullets[NUM_BULLETS]; +player_type tux; +SDL_Rect src, dest; +texture_type img_box_full, img_box_empty, img_mints, img_coffee, img_super_bkgd, img_red_glow; +st_level current_level; + +void add_score(int x, int y, int s); +void set_defaults(void); + +#endif /*SUPERTUX_SCENE_H*/ diff --git a/src/screen.c b/src/screen.c index aebb7aaa7..bd83792c4 100644 --- a/src/screen.c +++ b/src/screen.c @@ -28,7 +28,7 @@ #include "globals.h" #include "screen.h" #include "setup.h" - +#include "type.h" /* --- LOAD AND DISPLAY AN IMAGE --- */ @@ -44,9 +44,16 @@ void load_and_display_image(char * file) /* --- CLEAR SCREEN --- */ -void clearscreen(int r, int g, int b) +void clearscreen(float r, float g, float b) { + if(use_gl) + { + glClearColor(r/256, g/256, b/256, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + } + else SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, r, g, b)); + } @@ -54,14 +61,29 @@ void clearscreen(int r, int g, int b) void updatescreen(void) { - SDL_UpdateRect(screen, 0, 0, 640, 480); + if(use_gl) /*clearscreen(0,0,0);*/ + SDL_GL_SwapBuffers(); + else + SDL_UpdateRect(screen, 0, 0, screen->w, screen->h); } +void flipscreen(void) +{ +if(use_gl) +SDL_GL_SwapBuffers(); +else +SDL_Flip(screen); +} /* --- LOAD AN IMAGE --- */ SDL_Surface * load_image(char * file, int use_alpha) { +/* +if(!faccessible(file)) +{ +if(!faccessible(st_dir, +*/ SDL_Surface * temp, * surf; @@ -83,10 +105,54 @@ SDL_Surface * load_image(char * file, int use_alpha) return(surf); } +void create_gl_texture(SDL_Surface * surf, GLint * tex) +{ +SDL_Surface *conv; +conv = SDL_CreateRGBSurface(SDL_SWSURFACE , surf->w, surf->h, 32, +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); +#else + 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); +#endif + SDL_BlitSurface(surf, 0, conv, 0); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glGenTextures(1, &*tex); + + glBindTexture(GL_TEXTURE_RECTANGLE_NV , *tex); + glEnable(GL_TEXTURE_RECTANGLE_NV); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glPixelStorei(GL_UNPACK_ROW_LENGTH, conv->pitch / conv->format->BytesPerPixel); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 3, conv->w, conv->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, conv->pixels); + //glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 0, 0, 0, 0, conv->w, conv->h); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + SDL_FreeSurface(conv); +} /* --- DRAW AN IMAGE ONTO THE SCREEN --- */ - -void drawimage(SDL_Surface * surf, int x, int y, int update) +/* +void drawimage(SDL_Surface * surf, float x, float y, int update) +{ +if(use_gl) +{ +GLint gl_tex; +create_gl_texture(surf,&gl_tex); + glColor4ub(255, 255, 255,255); +glBlendFunc (GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); +glEnable (GL_BLEND); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, gl_tex); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(x, y); + glTexCoord2f((float)surf->w, 0); glVertex2f((float)surf->w+x, y); + glTexCoord2f((float)surf->w, (float)surf->h); glVertex2f((float)surf->w+x, (float)surf->h+y); + glTexCoord2f(0, (float)surf->h); glVertex2f(x, (float)surf->h+y); + glEnd(); + glDeleteTextures(1, &gl_tex); + } +else { SDL_Rect dest; @@ -100,11 +166,74 @@ void drawimage(SDL_Surface * surf, int x, int y, int update) if (update == UPDATE) SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); } +} +*/ +/* +drawbgimage(SDL_Surface * surf, int update) +{ +if(use_gl) +{ +GLint gl_tex; +create_gl_texture(surf,&gl_tex); + //glColor3ub(255, 255, 255); + + glEnable(GL_TEXTURE_RECTANGLE_NV); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, gl_tex); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(0, 0); + glTexCoord2f((float)surf->w, 0); glVertex2f(screen->w, 0); + glTexCoord2f((float)surf->w, (float)surf->h); glVertex2f(screen->w, screen->h); + glTexCoord2f(0, (float)surf->h); glVertex2f(0, screen->h); + glEnd(); + glDeleteTextures(1, &gl_tex); + +} +else +{ + SDL_Rect dest; + + dest.x = 0; + dest.y = 0; + dest.w = screen->w; + dest.h = screen->h; + + SDL_BlitSurface(surf, NULL, screen, &dest); + + if (update == UPDATE) + SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); +} +} +*/ +void update_rect(SDL_Surface *scr, Sint32 x, Sint32 y, Sint32 w, Sint32 h) +{ +if(!use_gl) +SDL_UpdateRect(scr, x, y, w, h); +} /* --- DRAW PART OF AN IMAGE ONTO THE SCREEN --- */ - -void drawpart(SDL_Surface * surf, int x, int y, int w, int h, int update) +/* +void drawpart(SDL_Surface * surf, float x, float y, float w, float h, int update) +{ +if(use_gl) +{ +GLint gl_tex; +create_gl_texture(surf,&gl_tex); + glColor3ub(255, 255, 255); + + glEnable(GL_TEXTURE_RECTANGLE_NV); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, gl_tex); + + glBegin(GL_QUADS); + glTexCoord2f(x, y); glVertex2f(x, y); + glTexCoord2f(x+w, y); glVertex2f(w+x, y); + glTexCoord2f(x+w, y+h); glVertex2f(w+x, h+y); + glTexCoord2f(x, y+h); glVertex2f(x, h+y); + glEnd(); + glDeleteTextures(1, &gl_tex); + } +else { SDL_Rect src, dest; @@ -118,12 +247,14 @@ void drawpart(SDL_Surface * surf, int x, int y, int w, int h, int update) dest.w = w; dest.h = h; + SDL_BlitSurface(surf, &src, screen, &dest); if (update == UPDATE) - SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); + update_rect(screen, dest.x, dest.y, dest.w, dest.h); + } } - +*/ /* --- DRAW TEXT ONTO THE SCREEN --- */ void drawtext(char * text, int x, int y, SDL_Surface * surf, int update, int shadowsize) @@ -211,6 +342,42 @@ void drawtext(char * text, int x, int y, SDL_Surface * surf, int update, int sha /* Shadow: */ SDL_BlitSurface(surf, &src, screen, &dest); + + +/* FIXME: Text doesn't work in OpenGL mode, below is experimental code */ +/* + + dest.x = 0; + dest.y = 0; + dest.w = src.w; + + dest.h = src.h; + + temp = SDL_CreateRGBSurface(SDL_SWSURFACE, dest.w, dest.h, 32, +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); +#else + 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); +#endif + SDL_BlitSurface(letters_black, &src, temp, NULL); + texture_type xyz; + texture_from_sdl_surface(&xyz,temp,IGNORE_ALPHA); + texture_draw(&xyz,x + (i * 16) + shadowsize,y + shadowsize, update); + texture_free(&xyz); + / * Set destination rectangle for text: * / + + dest.x = x + (i * 16); + dest.y = y; + dest.w = src.w; + dest.h = src.h; + + / * Text: * / + + SDL_BlitSurface(surf, &src, temp, NULL); + texture_from_sdl_surface(&xyz,temp,IGNORE_ALPHA); + SDL_FreeSurface(temp); + texture_draw(&xyz,x + (i * 16) + shadowsize,y + shadowsize, update); + texture_free(&xyz);*/ } } @@ -221,10 +388,10 @@ void drawtext(char * text, int x, int y, SDL_Surface * surf, int update, int sha { dest.w = strlen(text) * 16 + 1; - if (dest.w > 640) - dest.w = 640; + if (dest.w > screen->w) + dest.w = screen->w; - SDL_UpdateRect(screen, x, y, dest.w, 17); + update_rect(screen, x, y, dest.w, 17); } } @@ -234,7 +401,7 @@ void drawtext(char * text, int x, int y, SDL_Surface * surf, int update, int sha void drawcenteredtext(char * text, int y, SDL_Surface * surf, int update, int shadowsize) { - drawtext(text, 320 - (strlen(text) * 8), y, surf, update, shadowsize); + drawtext(text, screen->w / 2 - (strlen(text) * 8), y, surf, update, shadowsize); } /* --- ERASE TEXT: --- */ @@ -249,13 +416,13 @@ void erasetext(char * text, int x, int y, SDL_Surface * surf, int update, int sh dest.w = strlen(text) * 16 + shadowsize; dest.h = 17; - if (dest.w > 640) - dest.w = 640; + if (dest.w > screen->w) + dest.w = screen->w; SDL_BlitSurface(surf, &dest, screen, &dest); if (update == UPDATE) - SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); + update_rect(screen, dest.x, dest.y, dest.w, dest.h); } @@ -263,5 +430,5 @@ void erasetext(char * text, int x, int y, SDL_Surface * surf, int update, int sh void erasecenteredtext(char * text, int y, SDL_Surface * surf, int update, int shadowsize) { - erasetext(text, 320 - (strlen(text) * 8), y, surf, update, shadowsize); + erasetext(text, screen->w / 2 - (strlen(text) * 8), y, surf, update, shadowsize); } diff --git a/src/screen.h b/src/screen.h index ee319d2df..fc13c7bf4 100644 --- a/src/screen.h +++ b/src/screen.h @@ -11,19 +11,33 @@ */ #include +#include #define NO_UPDATE 0 #define UPDATE 1 #define USE_ALPHA 0 #define IGNORE_ALPHA 1 +#ifndef GL_NV_texture_rectangle +#define GL_TEXTURE_RECTANGLE_NV 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 +#endif + void load_and_display_image(char * file); -void clearscreen(int r, int g, int b); +void clearscreen(float r, float g, float b); void updatescreen(void); +void flipscreen(void); SDL_Surface * load_image(char * file, int use_alpha); -void drawimage(SDL_Surface * surf, int x, int y, int update); -void drawpart(SDL_Surface * surf, int x, int y, int w, int h, int update); +/* +void drawimage(SDL_Surface * surf, float x, float y, int update); +void drawpart(SDL_Surface * surf, float x, float y, float w, float h, int update); +*/ void drawtext(char * text, int x, int y, SDL_Surface * surf, int update, int shadowsize); void drawcenteredtext(char * text, int y, SDL_Surface * surf, int update, int shadowsize); void erasetext(char * text, int x, int y, SDL_Surface * surf, int update, int shadowsize); void erasecenteredtext(char * text, int y, SDL_Surface * surf, int update, int shadowsize); +void create_gl_texture(SDL_Surface * surf, GLint * tex); +void update_rect(SDL_Surface *scr, Sint32 x, Sint32 y, Sint32 w, Sint32 h); + diff --git a/src/setup.c b/src/setup.c index 0175fb8f2..985e0c8dc 100644 --- a/src/setup.c +++ b/src/setup.c @@ -7,7 +7,7 @@ bill@newbreedsoftware.com http://www.newbreedsoftware.com/supertux/ - April 11, 2000 - November 7, 2001 + April 11, 2000 - January 1st, 2004 */ #include @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef LINUX #include @@ -30,12 +31,21 @@ #include "setup.h" #include "screen.h" - /* Local function prototypes: */ void seticon(void); void usage(char * prog, int ret); +/* Does the given file exist and is it accessible? */ +int faccessible(char *filename) +{ + struct stat filestat; + if (stat(filename, &filestat) == -1) + return NO; + else + return YES; +} + /* --- SETUP --- */ @@ -63,8 +73,17 @@ void st_directory_setup(void) strcat(st_save_dir,"/save"); /* Create them. In the case they exist it won't destroy anything. */ +#ifdef LINUX + mkdir(st_dir, 0755); mkdir(st_save_dir, 0755); +#else + #ifdef WIN32 + + mkdir(st_dir); + mkdir(st_save_dir); +#endif +#endif } void st_general_setup(void) @@ -72,7 +91,7 @@ void st_general_setup(void) /* Seed random number generator: */ srand(SDL_GetTicks()); - + /* Load global images: */ letters_black = load_image(DATA_PREFIX "/images/status/letters-black.png", @@ -80,8 +99,8 @@ void st_general_setup(void) letters_gold = load_image(DATA_PREFIX "/images/status/letters-gold.png", USE_ALPHA);/* - if (tux_x < 0) - tux_x = 0;*/ + if (tux_x < 0) + tux_x = 0;*/ letters_blue = load_image(DATA_PREFIX "/images/status/letters-blue.png", USE_ALPHA); @@ -99,6 +118,9 @@ void st_general_setup(void) void st_video_setup(void) { +if(screen != NULL) + SDL_FreeSurface(screen); + /* Init SDL Video: */ if (SDL_Init(SDL_INIT_VIDEO) < 0) @@ -112,6 +134,19 @@ void st_video_setup(void) /* Open display: */ + if(use_gl) + st_video_setup_gl(); + else + st_video_setup_sdl(); + + /* Set window manager stuff: */ + + SDL_WM_SetCaption("Super Tux", "Super Tux"); + +} + +void st_video_setup_sdl(void) +{ if (use_fullscreen == YES) { screen = SDL_SetVideoMode(640, 480, 16, SDL_FULLSCREEN ) ; /* | SDL_HWSURFACE); */ @@ -125,10 +160,9 @@ void st_video_setup(void) use_fullscreen = NO; } } - - if (use_fullscreen == NO) + else { - screen = SDL_SetVideoMode(640, 480, 16, SDL_HWSURFACE | SDL_DOUBLEBUF); + screen = SDL_SetVideoMode(640, 480, 16, SDL_HWSURFACE | SDL_DOUBLEBUF ); if (screen == NULL) { @@ -139,11 +173,68 @@ void st_video_setup(void) exit(1); } } +} - /* Set window manager stuff: */ +void st_video_setup_gl(void) +{ - SDL_WM_SetCaption("Super Tux", "Super Tux"); + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + if (use_fullscreen == YES) + { + screen = SDL_SetVideoMode(640, 480, 32, SDL_FULLSCREEN | SDL_OPENGL ) ; /* | SDL_HWSURFACE); */ + if (screen == NULL) + { + fprintf(stderr, + "\nWarning: I could not set up fullscreen video for " + "640x480 mode.\n" + "The Simple DirectMedia error that occured was:\n" + "%s\n\n", SDL_GetError()); + use_fullscreen = NO; + } + } + else + { + screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_OPENGL | SDL_OPENGLBLIT ); + + if (screen == NULL) + { + fprintf(stderr, + "\nError: I could not set up video for 640x480 mode.\n" + "The Simple DirectMedia error that occured was:\n" + "%s\n\n", SDL_GetError()); + exit(1); + } + } + /* Initialisierung von OpenGL * / + glViewport(0, 0, screen->w, screen->h); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, screen->w, screen->h, 0, -1.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +*/ + /* + * Set up OpenGL for 2D rendering. + */ + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + glViewport(0, 0, screen->w, screen->h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, screen->w, screen->h, 0, -1.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0f, 0.0f, 0.0f); } void st_joystick_setup(void) @@ -363,6 +454,13 @@ void parseargs(int argc, char * argv[]) use_fullscreen = YES; } + if (strcmp(argv[i], "--opengl") == 0 || + strcmp(argv[i], "-g") == 0) + { + /* Use full screen: */ + + use_gl = YES; + } else if (strcmp(argv[i], "--usage") == 0) { /* Show usage: */ @@ -383,8 +481,10 @@ void parseargs(int argc, char * argv[]) printf("Sounds disabled \n"); use_sound = NO; #else + printf("Warning: Sounds feature is not compiled in \n"); #endif + } else if (strcmp(argv[i], "--disable-music") == 0) { @@ -393,13 +493,15 @@ void parseargs(int argc, char * argv[]) printf("Music disabled \n"); use_music = NO; #else + printf("Warning: Music feature is not compiled in \n"); #endif + } else if (strcmp(argv[i], "--debug-mode") == 0) { /* Enable the debug-mode */ - debug_mode = YES; + debug_mode = YES; } else if (strcmp(argv[i], "--help") == 0) @@ -416,7 +518,7 @@ void parseargs(int argc, char * argv[]) printf(" --fullscreen - Run in fullscreen mode.\n\n"); printf(" --debug-mode - Enables the debug-mode, which is useful for developers.\n\n"); - + printf(" --help - Display a help message summarizing command-line\n options, license and game controls.\n\n"); printf(" --usage - Display a brief message summarizing command-line options.\n\n"); @@ -463,10 +565,11 @@ void usage(char * prog, int ret) /* Display the usage message: */ fprintf(fi, "Usage: %s [--fullscreen] [--disable-sound] [--disable-music] [--debug-mode] | [--usage | --help | --version]\n", - prog); + prog); /* Quit! */ exit(ret); } + diff --git a/src/setup.h b/src/setup.h index 1fa4706ff..db406ade3 100644 --- a/src/setup.h +++ b/src/setup.h @@ -15,10 +15,13 @@ #include "sound.h" + int faccessible(char *filename); void st_directory_setup(void); void st_general_setup(void); + void st_video_setup_sdl(void); + void st_video_setup_gl(void); void st_video_setup(void); - void st_audio_setup(void); + void st_audio_setup(void); void st_joystick_setup(void); void st_shutdown(void); void st_abort(char * reason, char * details); diff --git a/src/sound.c b/src/sound.c index 4cca05bdc..8750dcd36 100644 --- a/src/sound.c +++ b/src/sound.c @@ -207,6 +207,25 @@ void free_music(Mix_Music *music) } } +void play_current_music(void) +{ + switch (current_music) + { + case LEVEL_MUSIC: + play_music(level_song, 1); + break; + case HERRING_MUSIC: + play_music(herring_song, 1); + break; + case HURRYUP_MUSIC: // keep the compiler happy + play_music(level_song_fast, 1); + break; + case NO_MUSIC: // keep the compiler happy for the moment :-) + {} + /*default:*/ + } +} + #else int open_audio (int frequency, int format, int channels, int chunksize) @@ -258,4 +277,7 @@ void free_music(void *music) void free_chunk(void *chunk) {} +void play_current_music(void) +{} + #endif diff --git a/src/sound.h b/src/sound.h index 14feafa97..600d217cb 100644 --- a/src/sound.h +++ b/src/sound.h @@ -86,6 +86,8 @@ int play_music(Mix_Music*music, int loops); void free_music(Mix_Music*music); void free_chunk(Mix_Chunk*chunk); +void play_current_music(void); + #else /* fake variables */ @@ -106,6 +108,8 @@ int play_music(void *music, int loops); void free_music(void *music); void free_chunk(void *chunk); +void play_current_music(void); + #endif #endif /*SUPERTUX_SOUND_H*/ diff --git a/src/special.c b/src/special.c new file mode 100644 index 000000000..496328764 --- /dev/null +++ b/src/special.c @@ -0,0 +1,263 @@ +// +// C Implementation: special +// +// Description: +// +// +// Author: Tobias Glaesser , (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include "SDL.h" +#include "defines.h" +#include "special.h" +#include "gameloop.h" +#include "screen.h" +#include "sound.h" +#include "scene.h" +#include "globals.h" +#include "player.h" + +void create_special_bitmasks() +{ + bm_bullet = bitmask_create_SDL(img_bullet.sdl_surface); +} + +void bullet_init(bullet_type* pbullet) +{ + pbullet->it.alive = &pbullet->alive; + pbullet->it.x = &pbullet->x; + pbullet->it.y = &pbullet->y; + pbullet->it.width = &pbullet->width; + pbullet->it.height = &pbullet->height; + pbullet->it.updated = &pbullet->updated; + + pbullet->width = 4; + pbullet->height = 4; + pbullet->updated = SDL_GetTicks(); + pbullet->alive = NO; +} + +void bullet_action(bullet_type* pbullet) +{ + + double frame_ratio = get_frame_ratio(&pbullet->it); + + if (pbullet->alive) + { + pbullet->x = pbullet->x + pbullet->xm * frame_ratio; + pbullet->y = pbullet->y + pbullet->ym * frame_ratio; + + if (issolid(pbullet->x, pbullet->y)) + { + if (issolid(pbullet->x, pbullet->y - pbullet->ym)) + pbullet->alive = NO; + else + { + if (pbullet->ym >= 0) + { + pbullet->y = (int)(pbullet->y / 32) * 32 - 8; + } + pbullet->ym = -pbullet->ym; + } + } + + pbullet->ym = pbullet->ym + GRAVITY; + + if (pbullet->x < scroll_x || + pbullet->x > scroll_x + screen->w) + { + pbullet->alive = NO; + } + } + +} + +void bullet_draw(bullet_type* pbullet) +{ + if (pbullet->alive && + pbullet->x >= scroll_x - pbullet->width && + pbullet->x <= scroll_x + screen->w) + { + texture_draw(&img_bullet, pbullet->x - scroll_x, pbullet->y, + NO_UPDATE); + } +} + +void bullet_collision(bullet_type* pbullet, int c_object) +{ + + if(c_object == CO_BADGUY) + pbullet->alive = NO; + +} + +void upgrade_init(upgrade_type *pupgrade) +{ + pupgrade->it.alive = &pupgrade->alive; + pupgrade->it.x = &pupgrade->x; + pupgrade->it.y = &pupgrade->y; + pupgrade->it.width = &pupgrade->width; + pupgrade->it.height = &pupgrade->height; + pupgrade->it.updated = &pupgrade->updated; + + pupgrade->width = 32; + pupgrade->height = 0; + pupgrade->updated = SDL_GetTicks(); + pupgrade->alive = NO; +} + +void upgrade_action(upgrade_type *pupgrade) +{ + double frame_ratio = get_frame_ratio(&pupgrade->it); + + if (pupgrade->alive) + { + if (pupgrade->height < 32) + { + /* Rise up! */ + + pupgrade->height++; + } + else + { + /* Move around? */ + + if (pupgrade->kind == UPGRADE_MINTS || + pupgrade->kind == UPGRADE_HERRING) + { + pupgrade->x = pupgrade->x + pupgrade->xm * frame_ratio; + pupgrade->y = pupgrade->y + pupgrade->ym * frame_ratio; + + if (issolid(pupgrade->x, pupgrade->y + 31) || + issolid(pupgrade->x + 31, pupgrade->y + 31)) + { + if (pupgrade->ym > 0) + { + if (pupgrade->kind == UPGRADE_MINTS) + { + pupgrade->ym = 0; + } + else if (pupgrade->kind == UPGRADE_HERRING) + { + pupgrade->ym = -24; + } + + pupgrade->y = (int)(pupgrade->y / 32) * 32; + } + } + else + pupgrade->ym = pupgrade->ym + GRAVITY; + + if (issolid(pupgrade->x, pupgrade->y)) + { + pupgrade->xm = -pupgrade->xm; + } + } + + + /* Off the screen? Kill it! */ + + if (pupgrade->x < scroll_x) + pupgrade->alive = NO; + + } + } +} + +void upgrade_draw(upgrade_type* pupgrade) +{ + if (pupgrade->alive) + { + if (pupgrade->height < 32) + { + /* Rising up... */ + + dest.x = pupgrade->x - scroll_x; + dest.y = pupgrade->y + 32 - pupgrade->height; + dest.w = 32; + dest.h = pupgrade->height; + + src.x = 0; + src.y = 0; + src.w = 32; + src.h = pupgrade->height; + + if (pupgrade->kind == UPGRADE_MINTS) + SDL_BlitSurface(img_mints.sdl_surface, &src, screen, &dest); + else if (pupgrade->kind == UPGRADE_COFFEE) + SDL_BlitSurface(img_coffee.sdl_surface, &src, screen, &dest); + else if (pupgrade->kind == UPGRADE_HERRING) + SDL_BlitSurface(img_golden_herring.sdl_surface, &src, screen, &dest); + } + else + { + if (pupgrade->kind == UPGRADE_MINTS) + { + texture_draw(&img_mints, + pupgrade->x - scroll_x, pupgrade->y, + NO_UPDATE); + } + else if (pupgrade->kind == UPGRADE_COFFEE) + { + texture_draw(&img_coffee, + pupgrade->x - scroll_x, pupgrade->y, + NO_UPDATE); + } + else if (pupgrade->kind == UPGRADE_HERRING) + { + texture_draw(&img_golden_herring, + pupgrade->x - scroll_x, pupgrade->y, + NO_UPDATE); + } + } + } +} + +void upgrade_collision(upgrade_type* pupgrade, void* p_c_object, int c_object) +{ +player_type* pplayer = NULL; + + switch (c_object) + { + case CO_PLAYER: + /* Remove the upgrade: */ + + /* p_c_object is CO_PLAYER, so assign it to pplayer */ + pplayer = p_c_object; + + pupgrade->alive = NO; + + /* Affect the player: */ + + if (pupgrade->kind == UPGRADE_MINTS) + { + play_sound(sounds[SND_EXCELLENT], SOUND_CENTER_SPEAKER); + pplayer->size = BIG; + super_bkgd_time = 8; + } + else if (pupgrade->kind == UPGRADE_COFFEE) + { + play_sound(sounds[SND_COFFEE], SOUND_CENTER_SPEAKER); + pplayer->got_coffee = YES; + super_bkgd_time = 4; + } + else if (pupgrade->kind == UPGRADE_HERRING) + { + play_sound(sounds[SND_HERRING], SOUND_CENTER_SPEAKER); + timer_start(&tux.invincible_timer,TUX_INVINCIBLE_TIME); + super_bkgd_time = 4; + /* play the herring song ^^ */ + if (current_music != HURRYUP_MUSIC) + { + current_music = HERRING_MUSIC; + if (playing_music()) + halt_music(); + } + } + break; + } +} + diff --git a/src/special.h b/src/special.h new file mode 100644 index 000000000..3ad4da880 --- /dev/null +++ b/src/special.h @@ -0,0 +1,71 @@ +// +// C Interface: special +// +// Description: +// +// +// Author: Tobias Glaesser , (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#define BULLET_STARTING_YM 1 +#define BULLET_XM 5 +#define NUM_BULLETS 3 + +#ifndef SUPERTUX_SPECIAL_H +#define SUPERTUX_SPECIAL_H + +#include +#include "bitmask.h" +#include "type.h" +#include "collision.h" + +typedef struct upgrade_type + { + int alive; + int kind; + float x; + float y; + float xm; + float ym; + float width; + float height; + unsigned int updated; + itop_type it; + } +upgrade_type; + +typedef struct bullet_type + { + int alive; + float x; + float y; + float xm; + float ym; + float width; + float height; + unsigned int updated; + itop_type it; + } +bullet_type; + +texture_type img_bullet; +bitmask* bm_bullet; + +void create_special_bitmasks(); + +texture_type img_golden_herring; + +void upgrade_init(upgrade_type *pupgrade); +void upgrade_action(upgrade_type *pupgrade); +void upgrade_draw(upgrade_type *pupgrade); +void upgrade_collision(upgrade_type *pupgrade, void* p_c_object, int c_object); + +void bullet_init(bullet_type *pbullet); +void bullet_action(bullet_type *pbullet); +void bullet_draw(bullet_type *pbullet); +void bullet_collision(bullet_type *pbullet, int c_object); + +#endif /*SUPERTUX_SPECIAL_H*/ diff --git a/src/supertux.c b/src/supertux.c index bcfd35d16..ad86fd69d 100644 --- a/src/supertux.c +++ b/src/supertux.c @@ -31,7 +31,7 @@ int main(int argc, char * argv[]) st_video_setup(); st_joystick_setup(); st_general_setup(); - + done = intro(); done = 0; diff --git a/src/title.c b/src/title.c index 2fc933dee..0c66575a9 100644 --- a/src/title.c +++ b/src/title.c @@ -30,13 +30,14 @@ #include "screen.h" #include "high_scores.h" #include "menu.h" +#include "type.h" /* --- TITLE SCREEN --- */ int title(void) { - SDL_Surface * title, * anim1, * anim2; + texture_type title, anim1, anim2; SDL_Event event; SDLKey key; int done, quit, frame, pict, last_highscore; @@ -48,16 +49,14 @@ int title(void) /* Init menu variables */ initmenu(); + clearscreen(0, 0, 0); updatescreen(); - /* Load images: */ - title = load_image(DATA_PREFIX "/images/title/title.png", IGNORE_ALPHA); - anim1 = load_image(DATA_PREFIX "/images/title/title-anim2.png", - IGNORE_ALPHA); - anim2 = load_image(DATA_PREFIX "/images/title/title-anim1.png", - IGNORE_ALPHA); + texture_load(&title,DATA_PREFIX "/images/title/title.png", IGNORE_ALPHA); + texture_load(&anim1,DATA_PREFIX "/images/title/title-anim2.png", IGNORE_ALPHA); + texture_load(&anim2,DATA_PREFIX "/images/title/title-anim1.png", IGNORE_ALPHA); /* --- Main title loop: --- */ @@ -70,7 +69,7 @@ int title(void) /* Draw the title background: */ - drawimage(title, 0, 0, NO_UPDATE); + texture_draw(&title, 0, 0, NO_UPDATE); /* Draw the high score: */ @@ -80,6 +79,7 @@ int title(void) while (!done && !quit) { + frame++; @@ -90,7 +90,6 @@ int title(void) if (event.type == SDL_QUIT) { /* Quit event - quit: */ - quit = 1; } else if (event.type == SDL_KEYDOWN) @@ -128,11 +127,11 @@ int title(void) } - if(menu_change) + if(use_gl || menu_change) { /* Draw the title background: */ - drawimage(title, 0, 0, NO_UPDATE); + texture_draw_bg(&title, NO_UPDATE); /* Draw the high score: */ sprintf(str, "High score: %d", last_highscore); @@ -151,14 +150,13 @@ int title(void) pict = (frame / 5) % 3; if (pict == 0) - drawpart(title, 560, 270, 80, 75, NO_UPDATE); + texture_draw_part(&title, 560, 270, 80, 75, NO_UPDATE); else if (pict == 1) - drawimage(anim1, 560, 270, NO_UPDATE); + texture_draw(&anim1, 560, 270, NO_UPDATE); else if (pict == 2) - drawimage(anim2, 560, 270, NO_UPDATE); - + texture_draw(&anim2, 560, 270, NO_UPDATE); - SDL_Flip(screen); + flipscreen(); /* Pause: */ @@ -169,9 +167,9 @@ int title(void) /* Free surfaces: */ - SDL_FreeSurface(title); - SDL_FreeSurface(anim1); - SDL_FreeSurface(anim2); + texture_free(&title); + texture_free(&anim1); + texture_free(&anim2); /* Return to main! */ diff --git a/src/type.c b/src/type.c new file mode 100644 index 000000000..59b5adb46 --- /dev/null +++ b/src/type.c @@ -0,0 +1,246 @@ +// +// C Implementation: type +// +// Description: +// +// +// Author: Tobias Glaesser , (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include +#include "setup.h" +#include "globals.h" +#include "screen.h" +#include "defines.h" +#include "type.h" +#include "scene.h" + +double get_frame_ratio(itop_type* pit) +{ + unsigned int cur_time = SDL_GetTicks(); + double frame_ratio = (float)(cur_time-*pit->updated)/(float)(FRAME_RATE); + *pit->updated = cur_time; + return frame_ratio; +} + +void timer_init(timer_type* ptimer) +{ + ptimer->period = 0; + ptimer->time = 0; +} + +void timer_start(timer_type* ptimer, unsigned int period) +{ + ptimer->time = SDL_GetTicks(); + ptimer->period = period; +} + +void timer_stop(timer_type* ptimer) +{ + timer_init(ptimer); +} + +int timer_check(timer_type* ptimer) +{ + if(ptimer->time != 0 && ptimer->time + ptimer->period > SDL_GetTicks()) + return YES; + else + { + ptimer->time = 0; + return NO; + } +} + +int timer_started(timer_type* ptimer) +{ + if(ptimer->time != 0) + return YES; + else + return NO; +} + +int timer_get_left(timer_type* ptimer) +{ + return (ptimer->period - (SDL_GetTicks() - ptimer->time)); +} + +int timer_get_gone(timer_type* ptimer) +{ + return (SDL_GetTicks() - ptimer->time); +} + +void texture_load(texture_type* ptexture, char * file, int use_alpha) +{ + SDL_Surface * temp; + + temp = IMG_Load(file); + + if (temp == NULL) + st_abort("Can't load", file); + + ptexture->sdl_surface = SDL_DisplayFormatAlpha(temp); + + if (ptexture->sdl_surface == NULL) + st_abort("Can't covert to display format", file); + + if (use_alpha == IGNORE_ALPHA) + SDL_SetAlpha(ptexture->sdl_surface, 0, 0); + + SDL_FreeSurface(temp); + + ptexture->w = ptexture->sdl_surface->w; + ptexture->h = ptexture->sdl_surface->h; + + if(use_gl) + { + create_gl_texture(ptexture->sdl_surface,&ptexture->gl_texture); + } +} + +void texture_from_sdl_surface(texture_type* ptexture, SDL_Surface* sdl_surf, int use_alpha) +{ + /* SDL_Surface * temp; + + temp = IMG_Load(file); + + if (temp == NULL) + st_abort("Can't load", file);*/ + + ptexture->sdl_surface = SDL_DisplayFormatAlpha(sdl_surf); + + if (ptexture->sdl_surface == NULL) + st_abort("Can't covert to display format", "SURFACE"); + + if (use_alpha == IGNORE_ALPHA) + SDL_SetAlpha(ptexture->sdl_surface, 0, 0); + + ptexture->w = ptexture->sdl_surface->w; + ptexture->h = ptexture->sdl_surface->h; + + if(use_gl) + { + create_gl_texture(ptexture->sdl_surface,&ptexture->gl_texture); + } +} + +void texture_draw(texture_type* ptexture, float x, float y, int update) +{ + if(use_gl) + { + glColor4ub(255, 255, 255,255); + glBlendFunc (GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + glEnable (GL_BLEND); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexture->gl_texture); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(x, y); + glTexCoord2f((float)ptexture->w, 0); + glVertex2f((float)ptexture->w+x, y); + glTexCoord2f((float)ptexture->w, (float)ptexture->h); + glVertex2f((float)ptexture->w+x, (float)ptexture->h+y); + glTexCoord2f(0, (float)ptexture->h); + glVertex2f(x, (float)ptexture->h+y); + glEnd(); + } + else + { + SDL_Rect dest; + + dest.x = x; + dest.y = y; + dest.w = ptexture->w; + dest.h = ptexture->h; + + SDL_BlitSurface(ptexture->sdl_surface, NULL, screen, &dest); + + if (update == UPDATE) + SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); + } +} + +void texture_draw_bg(texture_type* ptexture, int update) +{ +if(use_gl) +{ + //glColor3ub(255, 255, 255); + + glEnable(GL_TEXTURE_RECTANGLE_NV); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexture->gl_texture); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(0, 0); + glTexCoord2f((float)ptexture->w, 0); glVertex2f(screen->w, 0); + glTexCoord2f((float)ptexture->w, (float)ptexture->h); glVertex2f(screen->w, screen->h); + glTexCoord2f(0, (float)ptexture->h); glVertex2f(0, screen->h); + glEnd(); + +} +else +{ + SDL_Rect dest; + + dest.x = 0; + dest.y = 0; + dest.w = screen->w; + dest.h = screen->h; + + SDL_BlitSurface(ptexture->sdl_surface, NULL, screen, &dest); + + if (update == UPDATE) + SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); +} +} + +void texture_draw_part(texture_type* ptexture, float x, float y, float w, float h, int update) +{ + if(use_gl) + { + glColor3ub(255, 255, 255); + + glEnable(GL_TEXTURE_RECTANGLE_NV); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexture->gl_texture); + + glBegin(GL_QUADS); + glTexCoord2f(x, y); + glVertex2f(x, y); + glTexCoord2f(x+w, y); + glVertex2f(w+x, y); + glTexCoord2f(x+w, y+h); + glVertex2f(w+x, h+y); + glTexCoord2f(x, y+h); + glVertex2f(x, h+y); + glEnd(); + } + else + { + SDL_Rect src, dest; + + src.x = x; + src.y = y; + src.w = w; + src.h = h; + + dest.x = x; + dest.y = y; + dest.w = w; + dest.h = h; + + + SDL_BlitSurface(ptexture->sdl_surface, &src, screen, &dest); + + if (update == UPDATE) + update_rect(screen, dest.x, dest.y, dest.w, dest.h); + } +} + +void texture_free(texture_type* ptexture) +{ + SDL_FreeSurface(ptexture->sdl_surface); + if(use_gl) + glDeleteTextures(1, &ptexture->gl_texture); +} + diff --git a/src/type.h b/src/type.h new file mode 100644 index 000000000..b6614e98a --- /dev/null +++ b/src/type.h @@ -0,0 +1,67 @@ +// +// C Interface: type +// +// Description: +// +// +// Author: Tobias Glaesser , (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef SUPERTUX_TYPE_H +#define SUPERTUX_TYPE_H + +#include + +/* 'Interoperability' type */ + +typedef struct itop_type + { + int* alive; + float* x; + float* y; + float* width; + float* height; + int* updated; + } +itop_type; + +double get_frame_ratio(itop_type* pit); + +/* Timer type */ +typedef struct timer_type + { + unsigned int period; + unsigned int time; + } +timer_type; + +void timer_init(timer_type* ptimer); +void timer_start(timer_type* ptimer, unsigned int period); +void timer_stop(timer_type* ptimer); +int timer_check(timer_type* ptimer); +int timer_started(timer_type* ptimer); +int timer_get_left(timer_type* ptimer); +int timer_get_gone(timer_type* ptimer); + +/* Texture type */ +typedef struct texture_type + { + SDL_Surface* sdl_surface; + unsigned gl_texture; + int w; + int h; + } +texture_type; + +void texture_load(texture_type* ptexture, char * file, int use_alpha); +void texture_from_sdl_surface(texture_type* ptexture, SDL_Surface * sdl_surf, int use_alpha); +void texture_free(texture_type* ptexture); +void texture_draw(texture_type* ptexture, float x, float y, int update); +void texture_draw_bg(texture_type* ptexture, int update); +void texture_draw_part(texture_type* ptexture, float x, float y, float w, float h, int update); + +#endif /*SUPERTUX_TYPE_H*/ + diff --git a/src/world.c b/src/world.c new file mode 100644 index 000000000..eae8516d5 --- /dev/null +++ b/src/world.c @@ -0,0 +1,153 @@ +// +// C Implementation: world +// +// Description: +// +// +// Author: Tobias Glaesser , (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include +#include +#include "globals.h" +#include "scene.h" +#include "screen.h" +#include "defines.h" +#include "world.h" + +void bouncy_distro_action(bouncy_distro_type* pbouncy_distro) +{ + if (pbouncy_distro->alive) + { + pbouncy_distro->y = pbouncy_distro->y + pbouncy_distro->ym; + + pbouncy_distro->ym++; + + if (pbouncy_distro->ym >= 0) + pbouncy_distro->alive = NO; + } +} + +void bouncy_distro_draw(bouncy_distro_type* pbouncy_distro) +{ + if (pbouncy_distro->alive) + { + texture_draw(&img_distro[0], + pbouncy_distro->x - scroll_x, + pbouncy_distro->y, + NO_UPDATE); + } +} + +void broken_brick_action(broken_brick_type* pbroken_brick) +{ + if (pbroken_brick->alive) + { + pbroken_brick->x = pbroken_brick->x + pbroken_brick->xm; + pbroken_brick->y = pbroken_brick->y + pbroken_brick->ym; + + pbroken_brick->ym++; + + if (pbroken_brick->ym >= 0) + pbroken_brick->alive = NO; + } +} + +void broken_brick_draw(broken_brick_type* pbroken_brick) +{ + if (pbroken_brick->alive) + { + src.x = rand() % 16; + src.y = rand() % 16; + src.w = 16; + src.h = 16; + + dest.x = pbroken_brick->x - scroll_x; + dest.y = pbroken_brick->y; + dest.w = 16; + dest.h = 16; + + SDL_BlitSurface(img_brick[0].sdl_surface, &src, screen, &dest); + } +} + +void bouncy_brick_action(bouncy_brick_type* pbouncy_brick) +{ + if (pbouncy_brick->alive) + { + pbouncy_brick->offset = (pbouncy_brick->offset + + pbouncy_brick->offset_m); + + /* Go back down? */ + + if (pbouncy_brick->offset < -BOUNCY_BRICK_MAX_OFFSET) + pbouncy_brick->offset_m = BOUNCY_BRICK_SPEED; + + + /* Stop bouncing? */ + + if (pbouncy_brick->offset == 0) + pbouncy_brick->alive = NO; + } +} + +void bouncy_brick_draw(bouncy_brick_type* pbouncy_brick) +{ + if (pbouncy_brick->alive) + { + if (pbouncy_brick->x >= scroll_x - 32 && + pbouncy_brick->x <= scroll_x + screen->w) + { + dest.x = pbouncy_brick->x - scroll_x; + dest.y = pbouncy_brick->y; + dest.w = 32; + dest.h = 32; + + SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, + current_level.bkgd_red, + current_level.bkgd_green, + current_level.bkgd_blue)); + + drawshape(pbouncy_brick->x - scroll_x, + pbouncy_brick->y + pbouncy_brick->offset, + pbouncy_brick->shape); + } + } +} + +void floating_score_init(floating_score_type* pfloating_score, int x, int y, int s) +{ + pfloating_score->alive = YES; + pfloating_score->x = x; + pfloating_score->y = y - 16; + timer_start(&pfloating_score->timer,1000); + pfloating_score->value = s; +} + +void floating_score_action(floating_score_type* pfloating_score) +{ + if (pfloating_score->alive) + { + pfloating_score->y = pfloating_score->y - 2; + + if(!timer_check(&pfloating_score->timer)) + pfloating_score->alive = NO; + } +} + +void floating_score_draw(floating_score_type* pfloating_score) +{ + if (pfloating_score->alive) + { + char str[10]; + sprintf(str, "%d", pfloating_score->value); + drawtext(str, + pfloating_score->x + 16 - strlen(str) * 8, + pfloating_score->y, + letters_gold, NO_UPDATE, 1); + } +} + diff --git a/src/world.h b/src/world.h index 30d1b3948..cecd274fa 100644 --- a/src/world.h +++ b/src/world.h @@ -10,43 +10,71 @@ // // +#ifndef SUPERTUX_WORLD_H +#define SUPERTUX_WORLD_H + +#include +#include "type.h" + typedef struct bouncy_distro_type /*It is easier to read the sources IMHO, if we don't write something like int a,b,c; */ { int alive; - int x; - int y; - int ym; + float x; + float y; + float ym; } bouncy_distro_type; +texture_type img_distro[4]; + +void bouncy_distro_init(bouncy_distro_type* pbouncy_distro); +void bouncy_distro_action(bouncy_distro_type* pbouncy_distro); +void bouncy_distro_draw(bouncy_distro_type* pbouncy_distro); +void bouncy_distro_collision(bouncy_distro_type* pbouncy_distro, int c_object); + +#define BOUNCY_BRICK_MAX_OFFSET 8 +#define BOUNCY_BRICK_SPEED 4 + typedef struct broken_brick_type { int alive; - int x; - int y; - int xm; - int ym; + float x; + float y; + float xm; + float ym; } broken_brick_type; +void broken_brick_action(broken_brick_type* pbroken_brick); +void broken_brick_draw(broken_brick_type* pbroken_brick); + typedef struct bouncy_brick_type { int alive; - int x; - int y; - int offset; - int offset_m; + float x; + float y; + float offset; + float offset_m; int shape; } bouncy_brick_type; +void bouncy_brick_action(bouncy_brick_type* pbouncy_brick); +void bouncy_brick_draw(bouncy_brick_type* pbouncy_brick); + typedef struct floating_score_type { int alive; - int timer; - int x; - int y; + float x; + float y; int value; + timer_type timer; } floating_score_type; +void floating_score_init(floating_score_type* pfloating_score, int x, int y, int s); +void floating_score_action(floating_score_type* pfloating_score); +void floating_score_draw(floating_score_type* pfloating_score); + +#endif /*SUPERTUX_WORLD_H*/ +