/contrib/games/hydracastlelabyrinth/LICENSE |
---|
0,0 → 1,339 |
GNU GENERAL PUBLIC LICENSE |
Version 2, June 1991 |
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/> |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
Everyone is permitted to copy and distribute verbatim copies |
of this license document, but changing it is not allowed. |
Preamble |
The licenses for most software are designed to take away your |
freedom to share and change it. By contrast, the GNU General Public |
License is intended to guarantee your freedom to share and change free |
software--to make sure the software is free for all its users. This |
General Public License applies to most of the Free Software |
Foundation's software and to any other program whose authors commit to |
using it. (Some other Free Software Foundation software is covered by |
the GNU Lesser General Public License instead.) You can apply it to |
your programs, too. |
When we speak of free software, we are referring to freedom, not |
price. Our General Public Licenses are designed to make sure that you |
have the freedom to distribute copies of free software (and charge for |
this service if you wish), that you receive source code or can get it |
if you want it, that you can change the software or use pieces of it |
in new free programs; and that you know you can do these things. |
To protect your rights, we need to make restrictions that forbid |
anyone to deny you these rights or to ask you to surrender the rights. |
These restrictions translate to certain responsibilities for you if you |
distribute copies of the software, or if you modify it. |
For example, if you distribute copies of such a program, whether |
gratis or for a fee, you must give the recipients all the rights that |
you have. You must make sure that they, too, receive or can get the |
source code. And you must show them these terms so they know their |
rights. |
We protect your rights with two steps: (1) copyright the software, and |
(2) offer you this license which gives you legal permission to copy, |
distribute and/or modify the software. |
Also, for each author's protection and ours, we want to make certain |
that everyone understands that there is no warranty for this free |
software. If the software is modified by someone else and passed on, we |
want its recipients to know that what they have is not the original, so |
that any problems introduced by others will not reflect on the original |
authors' reputations. |
Finally, any free program is threatened constantly by software |
patents. We wish to avoid the danger that redistributors of a free |
program will individually obtain patent licenses, in effect making the |
program proprietary. To prevent this, we have made it clear that any |
patent must be licensed for everyone's free use or not licensed at all. |
The precise terms and conditions for copying, distribution and |
modification follow. |
GNU GENERAL PUBLIC LICENSE |
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
0. This License applies to any program or other work which contains |
a notice placed by the copyright holder saying it may be distributed |
under the terms of this General Public License. The "Program", below, |
refers to any such program or work, and a "work based on the Program" |
means either the Program or any derivative work under copyright law: |
that is to say, a work containing the Program or a portion of it, |
either verbatim or with modifications and/or translated into another |
language. (Hereinafter, translation is included without limitation in |
the term "modification".) Each licensee is addressed as "you". |
Activities other than copying, distribution and modification are not |
covered by this License; they are outside its scope. The act of |
running the Program is not restricted, and the output from the Program |
is covered only if its contents constitute a work based on the |
Program (independent of having been made by running the Program). |
Whether that is true depends on what the Program does. |
1. You may copy and distribute verbatim copies of the Program's |
source code as you receive it, in any medium, provided that you |
conspicuously and appropriately publish on each copy an appropriate |
copyright notice and disclaimer of warranty; keep intact all the |
notices that refer to this License and to the absence of any warranty; |
and give any other recipients of the Program a copy of this License |
along with the Program. |
You may charge a fee for the physical act of transferring a copy, and |
you may at your option offer warranty protection in exchange for a fee. |
2. You may modify your copy or copies of the Program or any portion |
of it, thus forming a work based on the Program, and copy and |
distribute such modifications or work under the terms of Section 1 |
above, provided that you also meet all of these conditions: |
a) You must cause the modified files to carry prominent notices |
stating that you changed the files and the date of any change. |
b) You must cause any work that you distribute or publish, that in |
whole or in part contains or is derived from the Program or any |
part thereof, to be licensed as a whole at no charge to all third |
parties under the terms of this License. |
c) If the modified program normally reads commands interactively |
when run, you must cause it, when started running for such |
interactive use in the most ordinary way, to print or display an |
announcement including an appropriate copyright notice and a |
notice that there is no warranty (or else, saying that you provide |
a warranty) and that users may redistribute the program under |
these conditions, and telling the user how to view a copy of this |
License. (Exception: if the Program itself is interactive but |
does not normally print such an announcement, your work based on |
the Program is not required to print an announcement.) |
These requirements apply to the modified work as a whole. If |
identifiable sections of that work are not derived from the Program, |
and can be reasonably considered independent and separate works in |
themselves, then this License, and its terms, do not apply to those |
sections when you distribute them as separate works. But when you |
distribute the same sections as part of a whole which is a work based |
on the Program, the distribution of the whole must be on the terms of |
this License, whose permissions for other licensees extend to the |
entire whole, and thus to each and every part regardless of who wrote it. |
Thus, it is not the intent of this section to claim rights or contest |
your rights to work written entirely by you; rather, the intent is to |
exercise the right to control the distribution of derivative or |
collective works based on the Program. |
In addition, mere aggregation of another work not based on the Program |
with the Program (or with a work based on the Program) on a volume of |
a storage or distribution medium does not bring the other work under |
the scope of this License. |
3. You may copy and distribute the Program (or a work based on it, |
under Section 2) in object code or executable form under the terms of |
Sections 1 and 2 above provided that you also do one of the following: |
a) Accompany it with the complete corresponding machine-readable |
source code, which must be distributed under the terms of Sections |
1 and 2 above on a medium customarily used for software interchange; or, |
b) Accompany it with a written offer, valid for at least three |
years, to give any third party, for a charge no more than your |
cost of physically performing source distribution, a complete |
machine-readable copy of the corresponding source code, to be |
distributed under the terms of Sections 1 and 2 above on a medium |
customarily used for software interchange; or, |
c) Accompany it with the information you received as to the offer |
to distribute corresponding source code. (This alternative is |
allowed only for noncommercial distribution and only if you |
received the program in object code or executable form with such |
an offer, in accord with Subsection b above.) |
The source code for a work means the preferred form of the work for |
making modifications to it. For an executable work, complete source |
code means all the source code for all modules it contains, plus any |
associated interface definition files, plus the scripts used to |
control compilation and installation of the executable. However, as a |
special exception, the source code distributed need not include |
anything that is normally distributed (in either source or binary |
form) with the major components (compiler, kernel, and so on) of the |
operating system on which the executable runs, unless that component |
itself accompanies the executable. |
If distribution of executable or object code is made by offering |
access to copy from a designated place, then offering equivalent |
access to copy the source code from the same place counts as |
distribution of the source code, even though third parties are not |
compelled to copy the source along with the object code. |
4. You may not copy, modify, sublicense, or distribute the Program |
except as expressly provided under this License. Any attempt |
otherwise to copy, modify, sublicense or distribute the Program is |
void, and will automatically terminate your rights under this License. |
However, parties who have received copies, or rights, from you under |
this License will not have their licenses terminated so long as such |
parties remain in full compliance. |
5. You are not required to accept this License, since you have not |
signed it. However, nothing else grants you permission to modify or |
distribute the Program or its derivative works. These actions are |
prohibited by law if you do not accept this License. Therefore, by |
modifying or distributing the Program (or any work based on the |
Program), you indicate your acceptance of this License to do so, and |
all its terms and conditions for copying, distributing or modifying |
the Program or works based on it. |
6. Each time you redistribute the Program (or any work based on the |
Program), the recipient automatically receives a license from the |
original licensor to copy, distribute or modify the Program subject to |
these terms and conditions. You may not impose any further |
restrictions on the recipients' exercise of the rights granted herein. |
You are not responsible for enforcing compliance by third parties to |
this License. |
7. If, as a consequence of a court judgment or allegation of patent |
infringement or for any other reason (not limited to patent issues), |
conditions are imposed on you (whether by court order, agreement or |
otherwise) that contradict the conditions of this License, they do not |
excuse you from the conditions of this License. If you cannot |
distribute so as to satisfy simultaneously your obligations under this |
License and any other pertinent obligations, then as a consequence you |
may not distribute the Program at all. For example, if a patent |
license would not permit royalty-free redistribution of the Program by |
all those who receive copies directly or indirectly through you, then |
the only way you could satisfy both it and this License would be to |
refrain entirely from distribution of the Program. |
If any portion of this section is held invalid or unenforceable under |
any particular circumstance, the balance of the section is intended to |
apply and the section as a whole is intended to apply in other |
circumstances. |
It is not the purpose of this section to induce you to infringe any |
patents or other property right claims or to contest validity of any |
such claims; this section has the sole purpose of protecting the |
integrity of the free software distribution system, which is |
implemented by public license practices. Many people have made |
generous contributions to the wide range of software distributed |
through that system in reliance on consistent application of that |
system; it is up to the author/donor to decide if he or she is willing |
to distribute software through any other system and a licensee cannot |
impose that choice. |
This section is intended to make thoroughly clear what is believed to |
be a consequence of the rest of this License. |
8. If the distribution and/or use of the Program is restricted in |
certain countries either by patents or by copyrighted interfaces, the |
original copyright holder who places the Program under this License |
may add an explicit geographical distribution limitation excluding |
those countries, so that distribution is permitted only in or among |
countries not thus excluded. In such case, this License incorporates |
the limitation as if written in the body of this License. |
9. The Free Software Foundation may publish revised and/or new versions |
of the General Public License from time to time. Such new versions will |
be similar in spirit to the present version, but may differ in detail to |
address new problems or concerns. |
Each version is given a distinguishing version number. If the Program |
specifies a version number of this License which applies to it and "any |
later version", you have the option of following the terms and conditions |
either of that version or of any later version published by the Free |
Software Foundation. If the Program does not specify a version number of |
this License, you may choose any version ever published by the Free Software |
Foundation. |
10. If you wish to incorporate parts of the Program into other free |
programs whose distribution conditions are different, write to the author |
to ask for permission. For software which is copyrighted by the Free |
Software Foundation, write to the Free Software Foundation; we sometimes |
make exceptions for this. Our decision will be guided by the two goals |
of preserving the free status of all derivatives of our free software and |
of promoting the sharing and reuse of software generally. |
NO WARRANTY |
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY |
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN |
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES |
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED |
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS |
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE |
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, |
REPAIR OR CORRECTION. |
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR |
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, |
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING |
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED |
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY |
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER |
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE |
POSSIBILITY OF SUCH DAMAGES. |
END OF TERMS AND CONDITIONS |
How to Apply These Terms to Your New Programs |
If you develop a new program, and you want it to be of the greatest |
possible use to the public, the best way to achieve this is to make it |
free software which everyone can redistribute and change under these terms. |
To do so, attach the following notices to the program. It is safest |
to attach them to the start of each source file to most effectively |
convey the exclusion of warranty; and each file should have at least |
the "copyright" line and a pointer to where the full notice is found. |
{description} |
Copyright (C) {year} {fullname} |
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., |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
Also add information on how to contact you by electronic and paper mail. |
If the program is interactive, make it output a short notice like this |
when it starts in an interactive mode: |
Gnomovision version 69, Copyright (C) year name of author |
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. |
This is free software, and you are welcome to redistribute it |
under certain conditions; type `show c' for details. |
The hypothetical commands `show w' and `show c' should show the appropriate |
parts of the General Public License. Of course, the commands you use may |
be called something other than `show w' and `show c'; they could even be |
mouse-clicks or menu items--whatever suits your program. |
You should also get your employer (if you work as a programmer) or your |
school, if any, to sign a "copyright disclaimer" for the program, if |
necessary. Here is a sample; alter the names: |
Yoyodyne, Inc., hereby disclaims all copyright interest in the program |
`Gnomovision' (which makes passes at compilers) written by James Hacker. |
{signature of Ty Coon}, 1 April 1989 |
Ty Coon, President of Vice |
This General Public License does not permit incorporating your program into |
proprietary programs. If your program is a subroutine library, you may |
consider it more useful to permit linking proprietary applications with the |
library. If this is what you want to do, use the GNU Lesser General |
Public License instead of this License. |
/contrib/games/hydracastlelabyrinth/Makefile |
---|
0,0 → 1,94 |
CC = kos32-gcc |
LD = kos32-ld |
OBJCOPY = kos32-objcopy |
KPACK = kpack |
STRIP = kos32-strip |
HCL = hcl |
SDK_DIR = $(abspath ../../sdk) |
CFLAGS = -c -O2 -std=c11 -mpreferred-stack-boundary=2 -fno-ident -fomit-frame-pointer -fno-stack-check \ |
-fno-stack-protector -mno-stack-arg-probe -fno-exceptions -fno-asynchronous-unwind-tables \ |
-ffast-math -mno-ms-bitfields -march=pentium-mmx \ |
-U__WIN32__ -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 -D_KOLIBRI \ |
-D_GNU_SOURCE=1 -Wno-missing-field-initializers -D_SDL -DUSE_SDL=1 -DOGG_MUSIC |
LDFLAGS = -static -S -nostdlib -T $(SDK_DIR)/sources/newlib/app.lds -Map=output.map --image-base 0 --subsystem native |
INCLUDES = -I$(SDK_DIR)/sources/newlib/libc/include -I$(SDK_DIR)/sources/SDL-1.2.2_newlib/include -I$(SDK_DIR)/sources/SDL_mixer-1.2.12 -Isrc |
LIBPATH = -L$(SDK_DIR)/lib |
GAME_OBJS = \ |
src/collision.o \ |
src/effect.o \ |
src/enemy.o \ |
src/game.o \ |
src/hero.o \ |
src/ini.o \ |
src/inventory.o \ |
src/main.o \ |
src/object.o \ |
src/options.o \ |
src/PHL.o \ |
src/platform.o \ |
src/qda.o \ |
src/stagedata.o \ |
src/text.o \ |
src/titlescreen.o \ |
src/weapon.o \ |
src/enemies/batboss.o \ |
src/enemies/bat.o \ |
src/enemies/bee.o \ |
src/enemies/boar.o \ |
src/enemies/boomknight.o \ |
src/enemies/crab.o \ |
src/enemies/devil.o \ |
src/enemies/dodo.o \ |
src/enemies/dog.o \ |
src/enemies/firewheel.o \ |
src/enemies/fish.o \ |
src/enemies/garm.o \ |
src/enemies/gas.o \ |
src/enemies/ghoul.o \ |
src/enemies/golem.o \ |
src/enemies/gyra.o \ |
src/enemies/heads.o \ |
src/enemies/hydra.o \ |
src/enemies/jellyfish.o \ |
src/enemies/knight.o \ |
src/enemies/lolidra.o \ |
src/enemies/pendulum.o \ |
src/enemies/podoboo.o \ |
src/enemies/poisonknight.o \ |
src/enemies/pumpkin.o \ |
src/enemies/seal.o \ |
src/enemies/skeleton.o \ |
src/enemies/skull.o \ |
src/enemies/slime.o \ |
src/enemies/slug.o \ |
src/enemies/thwomp.o \ |
src/enemies/waterjumper.o \ |
src/enemies/wizard.o |
SDL_OBJS = src/sdl/audio.o \ |
src/sdl/input.o \ |
src/sdl/graphics.o \ |
src/sdl/system.o \ |
src/sdl/joystick_stub.o |
MISC_OBJS = src/misc.o |
LIBS = -lSDL_mixer -lvorbis -logg -lSDLn -lsound -lgcc -lc.dll |
$(HCL): $(GAME_OBJS) $(SDL_OBJS) $(MISC_OBJS) |
$(LD) $(LDFLAGS) $(LIBPATH) $(GAME_OBJS) $(SDL_OBJS) $(MISC_OBJS) -o $(HCL) $(LIBS) |
$(STRIP) -S $(HCL) |
$(OBJCOPY) $(HCL) -O binary |
$(KPACK) --nologo $(HCL) |
%.o : %.c |
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $< |
clean: |
rm $(GAME_OBJS) $(SDL_OBJS) |
/contrib/games/hydracastlelabyrinth/README.md |
---|
0,0 → 1,71 |
# Hydra Castle Labyrinth |
![HCL build status](https://api.travis-ci.org/ptitSeb/hydracastlelabyrinth.png "HCL build status") |
This version of Hydra Castle Labyrinth is based on the 3DS port (see below for original notice) |
This version use SDL (either 1.2 or 2.0) and build on Linux, OpenPandora, PocketCHIP and ODROID. |
You'll need SDL and SDL_mixer to build, either version 1.2 or 2.0. |
The SDL2 version use SDL Renderer and so is hardware accelerated. |
The SDL1.2 version use plain bitmap (no OpenGL or GLES needed). |
On Debian and friend, to prepare and build, you can do (if you never build anything before, start with `sudo apt install build-essential git`): |
For SDL1.2 |
``` |
sudo apt install libsdl-dev libsdl-mixer1.2-dev cmake |
cd ~ |
git clone https://github.com/ptitSeb/hydracastlelabyrinth.git |
cd hydracastlelabyrinth |
cmake . |
make |
``` |
For SDL2.0 |
``` |
sudo apt install libsdl2-2.0-dev libsdl2-mixer2.0-dev cmake |
cd ~ |
git clone https://github.com/ptitSeb/hydracastlelabyrinth.git |
cd hydracastlelabyrinth |
cmake . -DUSE_SDL2=ON |
make |
``` |
To hear music, you can optionnaly use timidity, but it will play OGG track by default. |
``` |
sudo apt install timidity |
``` |
And launch the game with |
``` |
./hcl |
``` |
To start windowed 640x480 game. You can have fullscreen with `./hcl -f` or `./hcl -d` to have fullscreen at current desktop resolution. |
![sreenshot on Pandora](screenshot.png "screenshot on Pandora") |
# Web Version |
You can play an Emscripten version directly on your browser here: https://ptitseb.github.io/hydracastlelabyrinth/ |
# Original Notice |
**This work has been done by an anon from /hbg/ on 4chan.org/vg/ and not me!** |
I've asked the original author about what license to use and he allowed me to use the GPLv2. |
Therefore consider each file to be licensed under the GPLv2, even if there is no disclaimer inside of each file. |
You will have gotten a copy of the license as part of the git and if not, get a copy from `https://www.gnu.org/licenses/gpl-2.0.html`. |
Original author notes: |
Source code for the fan-made port of Hydra Castle Labyrinth for 3DS |
Anything related to the PSP and Wii are unfinished. |
(Yes, it does look like a 3rd grader programmed this.) |
The game's originally done by E.Hashimoto (a.k.a. Buster). |
You can download some of his works under this [link](http://hp.vector.co.jp/authors/VA025956/). |
/contrib/games/hydracastlelabyrinth/compile_flags.txt |
---|
0,0 → 1,2 |
-D_SDL |
-D_KOLIBRI |
/contrib/games/hydracastlelabyrinth/icon.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes: |
Added: svn:mime-type |
+image/png |
\ No newline at end of property |
/contrib/games/hydracastlelabyrinth/src/PHL.c |
---|
0,0 → 1,85 |
#include "PHL.h" |
#include <stdio.h> |
#include <string.h> |
#include "qda.h" |
#include "game.h" |
int WHITE, RED, YELLOW; |
void PHL_Init() |
{ |
PHL_GraphicsInit(); |
PHL_AudioInit(); // DBG |
#ifdef _3DS |
Result rc = romfsInit(); |
/*if (rc) { |
printf("romfsInit: %08lX\n", rc); |
//while(1){} |
} |
else |
{ |
printf("\nromfs Init Successful!\n"); |
}*/ |
#endif |
WHITE = 0; |
RED = 1; |
YELLOW = 2; |
} |
void PHL_Deinit() |
{ |
PHL_AudioClose(); |
PHL_GraphicsExit(); |
#ifdef _3DS |
romfsExit(); |
#endif |
} |
//Extracts bmps from the bmp.qda archive file |
PHL_Surface PHL_LoadQDA(char* fname) |
{ |
PHL_Surface surf; |
int numofsheets = 29; |
for (int i = 0; i < numofsheets; i++) |
{ |
if (strcmp(fname, (char*)headers[i].fileName) == 0) { //Match found |
//printf("\nMatch Found: %s", fname); |
surf = PHL_LoadBMP(i); |
i = numofsheets; //End search |
} |
} |
return surf; |
} |
void PHL_DrawTextBold(char* txt, int dx, int dy, int col) |
{ |
int i, cx, cy; |
for (i = 0; i < strlen(txt); i++) |
{ |
cx = (txt[i] - 32) * 16; |
cy = 32 * col; |
while (cx >= 512) { |
cx -= 512; |
cy += 16; |
} |
PHL_DrawSurfacePart(dx + (16 * i), dy, cx, cy, 16, 16, images[imgBoldFont]); |
} |
} |
void PHL_DrawTextBoldCentered(char* txt, int dx, int dy, int col) |
{ |
if (dy < 640 && dy > -16) { |
int stringW = strlen(txt) * 16; |
PHL_DrawTextBold(txt, dx - (stringW / 2), dy, col); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/PHL.h |
---|
0,0 → 1,56 |
/* |
PHL stands for Portable Homebrew Library |
*/ |
#ifndef PHL_H |
#define PHL_H |
#ifdef _3DS |
#include "3ds/system.h" |
#include "3ds/graphics.h" |
#include "3ds/input.h" |
#include "3ds/audio.h" |
#endif |
#ifdef _WII |
#include "wii/system.h" |
#include "wii/graphics.h" |
#include "wii/input.h" |
#include "wii/audio.h" |
#endif |
#ifdef _PSP |
#include "psp/system.h" |
#include "psp/graphics.h" |
#include "psp/input.h" |
#include "psp/audio.h" |
#endif |
#ifdef _SDL |
#ifdef _SDL2 |
#include "sdl2/system.h" |
#include "sdl2/graphics.h" |
#include "sdl2/input.h" |
#include "sdl2/audio.h" |
#else |
#include "sdl/system.h" |
#include "sdl/graphics.h" |
#include "sdl/input.h" |
#include "sdl/audio.h" |
#endif |
#endif |
typedef struct { |
int x, y, w, h; |
} PHL_Rect; |
void PHL_Init(); |
void PHL_Deinit(); |
extern int WHITE, RED, YELLOW; |
PHL_Surface PHL_LoadQDA(char* fname); |
void PHL_DrawTextBold(char* txt, int dx, int dy, int col); |
void PHL_DrawTextBoldCentered(char* txt, int dx, int dy, int col); |
#endif |
/contrib/games/hydracastlelabyrinth/src/amigaos.h |
---|
0,0 → 1,15 |
#include <stdint.h> |
#include <string.h> |
inline void littleBigEndian (void *x, int sz) { |
unsigned char *toConvert = (unsigned char *)(x); |
unsigned char tmp; |
for (size_t i = 0; i < sz/2; ++i) { |
tmp = toConvert[i]; |
toConvert[i] = toConvert[sz - i - 1]; |
toConvert[sz - i - 1] = tmp; |
} |
} |
inline void BE16(uint16_t* w) {littleBigEndian(w, 2);} |
inline void BE32(uint32_t* i) {littleBigEndian(i, 4);} |
/contrib/games/hydracastlelabyrinth/src/collision.c |
---|
0,0 → 1,336 |
#include "collision.h" |
#include "math.h" |
#include "game.h" |
#include "PHL.h" |
#include "object.h" |
int checkMix(Mask r, Mask c); |
int checkRect(Mask r1, Mask r2); |
int checkCircle(Mask c1, Mask c2); |
int checkCollision(Mask m1, Mask m2) |
{ |
if (m1.unused != 1 && m2.unused != 1) { |
if (m1.circle == 0 && m2.circle == 0) { |
return checkRect(m1, m2); |
}else if (m1.circle == 1 && m2.circle == 1) { |
return checkCircle(m1, m2); |
}else if (m1.circle == 1 && m2.circle == 0) { |
return checkMix(m2, m1); |
}else if (m1.circle == 0 && m2.circle == 1) { |
return checkMix(m1, m2); |
} |
} |
return 0; |
} |
int checkCollisionXY(Mask m, int x, int y) |
{ |
int result = 0; |
if (m.unused != 1) { |
if (m.circle == 1) { |
if (sqrt( pow(x - m.x, 2) + pow(y - m.y, 2) ) <= m.w) { |
result = 1; |
} |
}else{ |
if (x < m.x || x > m.x + m.w || y < m.y || y > m.y + m.h) { |
}else{ |
result = 1; |
} |
} |
} |
return result; |
} |
//Returns 1 or 0 depending on if there is a collision with a type of tile |
int checkTileCollision(int type, Mask m) |
{ |
int result = 0; |
if (m.x < 0) { |
m.x = 0; |
}else if (m.x + m.w > 640) { |
m.x = 640 - m.w; |
} |
if (m.y < 0) { |
m.y = 0; |
}else if (m.y + m.h > 480) { |
m.y = 480 - m.h; |
} |
int i; |
for (i = 0; i < 4; i++) { |
int tileX = (int)m.x / 40; |
int tileY = (int)m.y / 40; |
if (i == 1) { |
tileX = (int)((m.x + m.w - 1) / 40); |
}else if (i == 2) { |
tileY = (int)((m.y + m.h - 1) / 40); |
}else if (i == 3) { |
tileX = (int)((m.x + m.w - 1) / 40); |
tileY = (int)((m.y + m.h - 1) / 40); |
} |
if (collisionTiles[tileX][tileY] == type) { |
result = 1; |
i = 4; |
} |
} |
return result; |
} |
//Returns a tile's demension. Overkill for a lot of situations. |
PHL_Rect getTileCollision(int type, Mask m) |
{ |
PHL_Rect result; |
result.x = -1; |
result.y = -1; |
result.w = 40; |
result.h = 40; |
//updateMask(); |
if (m.x < 0) { |
m.x = 0; |
}else if (m.x + m.w > 640) { |
m.x = 640 - m.w; |
} |
if (m.y < 0) { |
m.y = 0; |
}else if (m.y + m.h > 480) { |
m.y = 480 - m.h; |
} |
//PHL_DrawRect(mask.x, mask.y, mask.w, mask.h, PHL_NewRGB(0x00, 0x00, 0xFF)); |
int i; |
for (i = 0; i < 4; i++) { |
int tileX = (int)m.x / 40; |
int tileY = (int)m.y / 40; |
if (i == 1) { |
tileX = (int)((m.x + m.w - 1) / 40); |
}else if (i == 2) { |
tileY = (int)((m.y + m.h - 1) / 40); |
}else if (i == 3) { |
tileX = (int)((m.x + m.w - 1) / 40); |
tileY = (int)((m.y + m.h - 1) / 40); |
} |
if (collisionTiles[tileX][tileY] == type) { |
result.x = tileX * 40; |
result.y = tileY * 40; |
i = 4; |
//PHL_DrawRect(result.x, result.y, 40, 40, PHL_NewRGB(0xFF, 0x00, 0x00)); |
} |
//PHL_DrawRect(tileX * 40, tileY * 40, 40, 40, PHL_NewRGB(0x00, 0xFF, 0x00)); |
} |
//updateMask(); |
return result; |
} |
int checkTileCollisionXY(int type, int x, int y) |
{ |
int result = 0; |
if (x < 0) { |
x = 0; |
}else if (x > 640) { |
x = 640; |
} |
if (y < 0) { |
y = 0; |
}else if (y > 480) { |
y = 480; |
} |
int tileX = (int)x / 40; |
int tileY = (int)y / 40; |
if (collisionTiles[tileX][tileY] == type) { |
result = 1; |
} |
return result; |
} |
PHL_Rect getTileCollisionXY(int type, int x, int y) |
{ |
PHL_Rect result; |
result.x = -1; |
result.y = -1; |
result.w = 40; |
result.h = 40; |
if (x < 0) { |
x = 0; |
}else if (x > 640) { |
x = 640; |
} |
if (y < 0) { |
y = 0; |
}else if (y > 480) { |
y = 480; |
} |
int tileX = (int)x / 40; |
int tileY = (int)y / 40; |
if (collisionTiles[tileX][tileY] == type) { |
result.x = tileX * 40; |
result.y = tileY * 40; |
} |
return result; |
} |
void PHL_DrawMask(Mask m) |
{ |
if (m.circle == 0) { |
PHL_DrawRect(m.x, m.y, m.w, m.h, PHL_NewRGB(255, 255, 255)); |
}else if (m.circle == 1) { |
PHL_DrawRect(m.x - m.w, m.y - m.w, m.w * 2, m.w * 2, PHL_NewRGB(255, 255, 255)); |
} |
} |
int checkMix(Mask r, Mask c) |
{ |
int insidex = 0, insidey = 0; |
if (c.x >= r.x && c.x <= r.x + r.w) { |
insidex = 1; |
} |
if (c.y >= r.y && c.y <= r.y + r.h) { |
insidey = 1; |
} |
//Check if circle center is inside rectangle |
if (insidex == 1 && insidey == 1) { |
} |
else if (insidex == 1) { |
if ((c.y < r.y && r.y - c.y <= c.w) || |
(c.y > (r.y + r.h) && c.y - (r.y + r.h) <= c.w)) { |
}else{ |
return 0; |
} |
}else if (insidey == 1) { |
if ((c.x < r.x && r.x - c.x <= c.w) || |
(c.x > (r.x + r.w) && c.x - (r.x + r.w) <= c.w)) { |
}else{ |
return 0; |
} |
}else{ |
//Check points |
if (sqrt( pow(r.x - c.x, 2) + pow(r.y - c.y, 2) ) <= c.w) { |
}else if (sqrt( pow(r.x + r.w - c.x, 2) + pow(r.y - c.y, 2) ) <= c.w) { |
}else if (sqrt( pow(r.x - c.x, 2) + pow(r.y + r.h - c.y, 2) ) <= c.w) { |
}else if (sqrt( pow(r.x + r.w - c.x, 2) + pow( r.y + r.h - c.y, 2) ) <= c.w) { |
}else{ |
return 0; |
} |
} |
return 1; |
} |
int checkRect(Mask r1, Mask r2) |
{ |
if (r1.x > r2.x + r2.w || |
r1.x + r1.w < r2.x || |
r1.y > r2.y + r2.h || |
r1.y + r1.h < r2.y) |
{ |
return 0; |
} |
return 1; |
} |
int checkCircle(Mask c1, Mask c2) |
{ |
int maxdis = c1.w + c2.w; |
int dis = sqrt(pow(c2.x - c1.x, 2) + pow(c2.y - c1.y, 2)); |
if (dis <= maxdis) { |
return 1; |
} |
return 0; |
} |
//Heavier tile collision that omits destroyable blocks |
PHL_Rect getTileCollisionWeapon(int type, Mask m) |
{ |
PHL_Rect result; |
result.x = -1; |
result.y = -1; |
result.w = 40; |
result.h = 40; |
//updateMask(); |
if (m.x < 0) { |
m.x = 0; |
}else if (m.x + m.w > 640) { |
m.x = 640 - m.w; |
} |
if (m.y < 0) { |
m.y = 0; |
}else if (m.y + m.h > 480) { |
m.y = 480 - m.h; |
} |
//PHL_DrawRect(mask.x, mask.y, mask.w, mask.h, PHL_NewRGB(0x00, 0x00, 0xFF)); |
int i; |
for (i = 0; i < 4; i++) { |
int tileX = (int)m.x / 40; |
int tileY = (int)m.y / 40; |
if (i == 1) { |
tileX = (int)((m.x + m.w - 1) / 40); |
}else if (i == 2) { |
tileY = (int)((m.y + m.h - 1) / 40); |
}else if (i == 3) { |
tileX = (int)((m.x + m.w - 1) / 40); |
tileY = (int)((m.y + m.h - 1) / 40); |
} |
if (collisionTiles[tileX][tileY] == type) { |
result.x = tileX * 40; |
result.y = tileY * 40; |
//Check if destroyable block |
int a; |
for (a = 0; a < MAX_OBJECTS; a++) { |
if (objects[a] != NULL) { |
if (objects[a]->type == 3) { |
Destroyable* d = objects[a]->data; |
if (result.x == d->x && result.y == d->y) { |
result.x = -1; |
result.y = -1; |
} |
} |
} |
} |
if (result.x != -1) { |
i = 4; |
} |
} |
} |
//updateMask(); |
return result; |
} |
/contrib/games/hydracastlelabyrinth/src/collision.h |
---|
0,0 → 1,27 |
#ifndef COLLISION_H |
#define COLLISION_H |
#include "PHL.h" |
typedef struct { |
int circle; //1 if circle, 0 is rectangle |
int x, y; |
int w, h; //width is the radius if it's a circle |
int unused; |
} Mask; |
void PHL_DrawMask(Mask m); |
int checkCollision(Mask m1, Mask m2); |
int checkTileCollision(int type, Mask m); |
PHL_Rect getTileCollision(int type, Mask m); |
int checkCollisionXY(Mask m, int x, int y); |
int checkTileCollisionXY(int type, int x, int y); |
PHL_Rect getTileCollisionXY(int type, int x, int y); |
PHL_Rect getTileCollisionWeapon(int type, Mask m); |
#endif |
/contrib/games/hydracastlelabyrinth/src/effect.c |
---|
0,0 → 1,384 |
#include "effect.h" |
#include "game.h" |
#include "PHL.h" |
#include "hero.h" |
#include "collision.h" |
#include <stdlib.h> |
#include <math.h> |
void createEffect(int type, int x, int y) |
{ |
createEffectExtra(type, x, y, 0, 0, 0); |
} |
void createEffectExtra(int t, int x, int y, double hsp, double vsp, int val) |
{ |
int i; |
for (i = 0; i < MAX_EFFECTS; i++) { |
if (effects[i] == NULL) { |
Effect* e = malloc(sizeof *e); |
e->id = i; |
e->type = t; |
e->x = x; |
e->y = y; |
e->vsp = vsp; |
e->hsp = hsp; |
e->grav = 0; |
e->imageIndex = 0; |
e->imageSpeed = 0; |
e->cropx = 0; |
e->cropy = 0; |
e->width = 40; |
e->height = 40; |
e->image = imgMisc20; |
e->timer = 60; |
e->visible = 1; |
e->val1 = 0; |
e->loop = 0; |
e->frames = 0; |
e->depth = 1; |
//Sword collision |
if (e->type == 1) { |
e->cropx = 440; |
e->cropy = 40; |
e->imageSpeed = 0.25; |
e->timer = 19; |
} |
//Enemy poof |
else if (e->type == 2) { |
PHL_PlaySound(sounds[sndBom01], CHN_EFFECTS); |
e->width = 64; |
e->height = 64; |
e->imageSpeed = 0.33; |
e->timer = 30; |
e->image = imgMisc32; |
} |
//Dust after landing from a fall - left/right |
else if (e->type == 3) { |
e->cropx = 320; |
e->cropy = 80; |
e->hsp = -1; |
if (hsp > 0) { |
e->hsp = 1; |
e->cropx = 0; |
} |
e->imageSpeed = 0.33; |
e->timer = 8 * (1 / e->imageSpeed); |
} |
//Block destroy/debris |
else if (e->type == 4) { |
e->grav = 0.2; |
e->loop = 1; |
e->frames = 4; |
e->timer = 60; |
//Set flash offset |
if ((e->hsp > 0 && val == 0) || (e->hsp > 0 && val == 1)) { |
e->timer -= 1; |
} |
e->imageSpeed = 0.34; |
int size = (rand() % 2) + 1; |
e->cropx = 0; |
if (e->hsp < 0) { |
e->cropx = 160; |
} |
if (size == 1) { //Big |
e->cropy = 40; |
}else{ //Small |
e->cropy = 440; |
} |
} |
//Chest sparkle |
else if (e->type == 5) { |
/*e->x -= 20; |
e->y -= 20; |
e->x += -20 + (rand() % 40) + 1; |
e->y += -20 + (rand() % 40) + 1; |
*/ |
e->x -= 20; |
e->y -= 20; |
e->cropx = 440; |
e->cropy = 120; |
e->imageSpeed = 0.3; |
e->timer = 16; |
e->depth = 0; |
} |
//Charge orbs |
else if (e->type == 6) { |
e->x -= 20; |
e->y -= 20; |
e->cropx = 0; |
e->cropy = 200; |
e->val1 = (rand() % 360) + 1; |
e->imageSpeed = 0.3; |
e->timer = 20; |
e->depth = 0; |
} |
//Poison bubble |
else if (e->type == 7) { |
PHL_PlaySound(sounds[sndPi02], CHN_EFFECTS); |
e->x -= 30; |
e->x += (rand() % 20) + 1; |
e->cropx = 280; |
e->cropy = 120; |
e->timer = 35; |
e->vsp = -2; |
e->imageIndex = 0; |
e->imageSpeed = 0.16; |
e->depth = 0; |
} |
//Stone break free |
else if (e->type == 8) { |
e->image = imgMisc32; |
e->cropy = 64; |
e->width = 64; |
e->height = 64; |
e->imageSpeed = 0.32; |
e->timer = 18; |
} |
//Tiny stone debris |
else if (e->type == 9) { |
e->x -= 20; |
e->y -= 20; |
e->image = imgMisc20; |
e->cropy = 40; |
e->cropx = 320 + ((rand() % 3) * 40); |
e->imageSpeed = 0; |
e->vsp = -2 - (0.25 * (rand() % 8)); |
e->hsp = -1 + (0.25 * (rand() % 8)); |
e->grav = 0.1; |
e->timer = 60; |
e->depth = 0; |
} |
//Lava top animation |
else if (e->type == 10) { |
e->cropy = 40; |
e->cropx = 80; |
e->imageSpeed = 0.125; |
e->depth = -1; |
e->loop = 1; |
e->frames = 3; |
e->timer = 100; |
e->image = imgTiles; |
} |
//Water top animation |
else if (e->type == 11) { |
e->cropy = 40; |
e->cropx = 240; |
e->imageSpeed = 0.125; |
e->depth = -1; |
e->loop = 1; |
e->frames = 4; |
e->timer = 100; |
e->image = imgTiles; |
} |
//Hero Air Bubble |
else if (e->type == 12) { |
e->x -= 20; |
e->val1 = e->x; //Start x |
e->y -= 20; |
e->cropx = 440; |
e->loop = 1; |
e->frames = 2; |
e->imageSpeed = 0.2; |
e->timer = 120; |
e->vsp = -0.5; |
e->depth = 0; |
} |
//Water splash |
else if (e->type == 13) { |
e->cropx = 200; |
e->imageSpeed = 0.1; |
e->timer = 55; |
e->grav = 0.1; |
} |
//Lava splash |
else if (e->type == 14) { |
e->cropx = 400; |
e->cropy = 200; |
e->imageSpeed = 0.1; |
e->timer = 55; |
e->grav = 0.1; |
} |
effects[i] = e; |
i = MAX_EFFECTS; |
} |
} |
} |
void effectStep(Effect* e) |
{ |
e->x += e->hsp; |
e->y += e->vsp; |
e->vsp += e->grav; |
e->imageIndex += e->imageSpeed; |
if (e->loop == 1) { |
if (e->imageIndex >= e->frames) { |
e->imageIndex -= e->frames; |
} |
} |
if (e->type == 12) { //Hero Air Bubble |
e->x = e->val1 + 5 * sin((e->timer * 5) * 3.14159 / 180); |
if (checkTileCollisionXY(4, e->x + 20, e->y + 20) == 0) { |
e->timer = 0; |
} |
} |
if (e->type == 10 || e->type == 11) { //Lava top |
e->timer = 100; |
} |
if (e->type == 4 || e->type == 9 || e->type == 12) { //Stone Rubble |
if (e->timer <= 30 && e->timer % 2 != 0) { |
e->visible = 0; |
}else{ |
e->visible = 1; |
} |
} |
else if (e->type == 6) { //Charge orb |
if (e->timer % 2 == 0) { |
e->visible = 1; |
e->x = herox + ((e->timer * 3) * sin(e->val1 * 3.14159 / 180)) - 20; |
e->y = heroy + ((e->timer * 3) * cos(e->val1 * 3.14159 / 180)); |
}else{ |
e->visible = 0; |
} |
} |
e->timer -= 1; |
if (e->timer <= 0) { |
effectDestroy(e->id); |
} |
} |
void effectDraw(Effect* e) |
{ |
//if (e->type != 4 || (e->timer > 30 || e->timer % 2 == 0)) { |
if (e->visible == 1) { |
if (e->type == 7) { //Poison Bubble |
int animation[6] = {0, 1, 2, 1, 0, 3}; |
PHL_DrawSurfacePart(e->x, e->y, e->cropx + (e->width * (animation[(int)e->imageIndex])), e->cropy, e->width, e->height, images[e->image]); |
}else{ |
PHL_DrawSurfacePart(e->x, e->y, e->cropx + (e->width * ((int)e->imageIndex)), e->cropy, e->width, e->height, images[e->image]); |
} |
} |
} |
void effectDestroy(int id) |
{ |
if (effects[id] != NULL) { |
free(effects[id]); |
} |
effects[id] = NULL; |
} |
void createRockSmash(int x, int y) |
{ |
x -= 20; |
int randvsp = (rand() % 3) + 1; |
createEffectExtra(4, x, y, -1.5, -2 - randvsp, 0); |
randvsp = (rand() % 3) + 1; |
createEffectExtra(4, x, y, -1, -5 - randvsp, 1); |
randvsp = (rand() % 3) + 1; |
createEffectExtra(4, x, y, 1.5, -2 - randvsp, 0); |
randvsp = (rand() % 3) + 1; |
createEffectExtra(4, x, y, 1, -5 - randvsp, 1); |
PHL_PlaySound(sounds[sndBom02], 2); |
} |
void createSplash(int x, int y) |
{ |
double chsp = 0, |
cvsp = 0; |
x -= 20; |
chsp = -0.25 - ((rand() % 9) * 0.25); |
cvsp = -1.5 - ((rand() % 9) * 0.25); |
createEffectExtra(13, x, y, chsp, cvsp, 0); |
chsp = 0.25 + ((rand() % 9) * 0.25); |
cvsp = -1.5 - ((rand() % 9) * 0.25); |
createEffectExtra(13, x, y, chsp, cvsp, 0); |
chsp = -0.25 - ((rand() % 9) * 0.25); |
cvsp = -0.5 - ((rand() % 4) * 0.25); |
createEffectExtra(13, x, y, chsp, cvsp, 0); |
chsp = 0.25 + ((rand() % 9) * 0.25); |
cvsp = -0.5 - ((rand() % 4) * 0.25); |
createEffectExtra(13, x, y, chsp, cvsp, 0); |
PHL_PlaySound(sounds[sndWater01], CHN_EFFECTS); |
} |
void createLavaSplash(int x, int y) |
{ |
double chsp = 0, |
cvsp = 0; |
x -= 20; |
chsp = -0.25 - ((rand() % 9) * 0.25); |
cvsp = -1.5 - ((rand() % 9) * 0.25); |
createEffectExtra(14, x, y, chsp, cvsp, 0); |
chsp = 0.25 + ((rand() % 9) * 0.25); |
cvsp = -1.5 - ((rand() % 9) * 0.25); |
createEffectExtra(14, x, y, chsp, cvsp, 0); |
chsp = -0.25 - ((rand() % 9) * 0.25); |
cvsp = -0.5 - ((rand() % 4) * 0.25); |
createEffectExtra(14, x, y, chsp, cvsp, 0); |
chsp = 0.25 + ((rand() % 9) * 0.25); |
cvsp = -0.5 - ((rand() % 4) * 0.25); |
createEffectExtra(14, x, y, chsp, cvsp, 0); |
PHL_PlaySound(sounds[sndShot07], CHN_EFFECTS); |
} |
/contrib/games/hydracastlelabyrinth/src/effect.h |
---|
0,0 → 1,31 |
#ifndef EFFECTS_H |
#define EFFECTS_H |
typedef struct { |
int id, type; |
double x, y, |
vsp, hsp, grav, |
imageIndex, imageSpeed; |
int cropx, cropy; |
int width, height; |
int image, timer; |
int visible; |
int val1; |
int loop, frames; |
int depth; |
} Effect; |
void createEffect(int type, int x, int y); |
void createEffectExtra(int t, int x, int y, double hsp, double vsp, int val); |
void effectStep(Effect* e); |
void effectDraw(Effect* e); |
void effectDestroy(int id); |
void createRockSmash(int x, int y); |
void createSplash(int x, int y); |
void createLavaSplash(int x, int y); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/bat.c |
---|
0,0 → 1,172 |
#include "bat.h" |
#include "../game.h" |
#include "../PHL.h" |
#include "../hero.h" |
#include <stdlib.h> |
#include <math.h> |
void batStep(Bat* b); |
void batDraw(Bat* b); |
void createBat(int x, int y, int type) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* result = /*(Enemy*)*/malloc(sizeof *result); |
Bat* b = /*(Bat*)*/malloc(sizeof *b); |
b->id = i; |
b->x = b->xstart = x; |
b->y = b->ystart = y; |
b->type = type; |
b->imageIndex = 5; |
b->counter = 0; |
b->timer = 0; |
b->state = 0; |
b->dir = 1; |
result->data = b; |
result->enemyStep = batStep; |
result->enemyDraw = batDraw; |
result->type = 1; |
enemies[i] = result; |
i = MAX_ENEMIES; |
} |
} |
} |
void batStep(Bat* b) |
{ |
//Wait |
if (b->state == 0) |
{ |
//Animate |
{ |
b->imageIndex = 5; |
} |
//wait for hero to get near |
{ |
if (b->timer <= 0) { |
Mask area; |
area.circle = 0; |
area.unused = 0; |
area.x = b->xstart - 60; |
area.y = b->ystart; |
area.w = 160; area.h = 100; |
if (checkCollisionXY(area, herox, heroy + 20)) { |
PHL_PlaySound(sounds[sndPi07], CHN_ENEMIES); |
b->state = 1; |
b->timer = 270; |
if (b->type == 1) { |
b->counter = 1; |
if (herox < b->x + 20) { |
b->dir = -1; |
}else{ |
b->dir = 1; |
} |
} |
} |
}else{ |
b->timer -= 1; |
} |
} |
} |
//Fly |
else if (b->state == 1) |
{ |
//Animate |
{ |
b->imageIndex += 0.25; |
if (b->imageIndex >= 5) { |
b->imageIndex -= 5; |
} |
} |
//Rotation angle |
{ |
b->timer += 4; |
if (b->timer >= 360) { |
b->timer -= 360; |
} |
} |
//Movement |
{ |
b->y = b->ystart + 30 + (30 * sin(b->timer * 3.14159 / 180)); |
//Red bat |
if (b->type == 1) { |
b->x += 2 * b->dir; |
} |
} |
//Return to perch |
{ |
if (b->timer == 270) { |
if (b->type == 1 && b->counter > 0) { |
b->dir *= -1; |
b->timer = 270; |
b->counter -= 1; |
}else{ |
b->state = 0; |
b->timer = 70; |
} |
} |
} |
} |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 32; |
mask.h = 28; |
mask.x = b->x + ((40 - mask.w) / 2); |
mask.y = b->y; |
} |
//Hit Player |
{ |
if (checkCollision(mask, heroMask)) { |
heroHit(10, mask.x + (mask.w / 2)); |
} |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
//Death |
createEffect(2, b->x - 12, b->y - 6); |
spawnCollectable(b->x + 20, b->y); |
enemyDestroy(b->id); |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
void batDraw(Bat* b) |
{ |
int cropX = 0, |
cropY = 120; |
if (b->type == 1) { |
cropX = 400; |
cropY = 280; |
} |
cropX += (int)b->imageIndex * 40; |
PHL_DrawSurfacePart(b->x, b->y - 4, cropX, cropY, 40, 40, images[imgEnemies]); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/bat.h |
---|
0,0 → 1,16 |
#ifndef BAT_H |
#define BAT_H |
typedef struct { |
int id; |
double x, y; |
int xstart, ystart; |
int type; //0 = gray | 1 = red |
int dir; |
double imageIndex; |
int counter, timer, state; |
} Bat; |
void createBat(int x, int y, int type); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/batboss.c |
---|
0,0 → 1,319 |
#include "batboss.h" |
#include "../game.h" |
#include "../PHL.h" |
#include "../hero.h" |
#include "heads.h" |
#include <stdlib.h> |
#include <math.h> |
int boss2flag = 5; |
//void updateBatMask(Batboss* b); |
void batbossStep(Batboss* b); |
void batbossDraw(Batboss* b); |
void createBatboss(int x, int y) |
{ |
if (flags[boss2flag] == 0) { //have not beaten boss 2 |
PHL_FreeSurface(images[imgBoss]); |
images[imgBoss] = PHL_LoadQDA("boss03.bmp"); |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
setBossRoom(); |
Enemy* e = /*(Enemy*)*/malloc(sizeof *e); |
Batboss* b = /*(Batboss*)*/malloc(sizeof *b); |
b->id = i; |
b->x = x; |
b->y = y; |
b->vsp = 0; |
b->hsp = 0; |
b->grav = 0.1; |
b->imageIndex = 0; |
b->ypos = y; |
b->rot = 0; |
b->hp = 35; |
b->invincible = 0; |
b->state = 0; |
b->timer = 0; |
b->mode = 0; //0 for flame, 1 for tornado stomp |
/* |
b->mask.unused = b->mask.circle = 0; |
b->mask.w = 100; |
b->mask.h = 68; |
updateBatMask(b); |
*/ |
//Setup phase |
b->state = 0; |
b->hsp = 2; |
b->ypos = b->y - 24; |
b->timer = 60; |
e->data = b; |
e->enemyStep = batbossStep; |
e->enemyDraw = batbossDraw; |
e->type = 41; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
} |
void batbossStep(Batboss* b) |
{ |
char dead = 0; |
//Animate |
{ |
//Wing flap |
if (b->state == 0 || b->state == 1 || b->state == 2 || b->state == 5 || b->state == 6) { |
b->imageIndex += 0.1; |
if (b->imageIndex >= 2) { |
b->imageIndex -= 2; |
} |
} |
//Twister |
if (b->state == 3 || b->state == 4) { |
b->imageIndex += 0.2; |
if (b->imageIndex >= 5) { |
b->imageIndex -= 3; |
} |
} |
} |
//Counters |
{ |
if (b->timer > 0) { |
b->timer -= 1; |
} |
if (b->invincible > 0) { |
b->invincible -= 1; |
} |
} |
//Large vertical movement |
{ |
if (b->state == 0 || b->state == 1) { |
b->rot += 2; |
if (b->rot >= 360) { b->rot -= 360; } |
b->y = b->ypos - (40 * sin(b->rot * 3.14159 / 180)); |
} |
} |
//Small vertical movement |
{ |
if (b->state == 2) { |
b->rot += 2; |
if (b->rot >= 360) { b->rot -= 360; } |
b->y = b->ypos - (20 * sin(b->rot * 3.14159 / 180)); |
} |
} |
//Horizontal movement |
if (b->state == 0) { |
b->x += b->hsp; |
if (b->x >= 520 || b->x <= 120) { //Hit walls |
b->hsp *= -1; |
} |
if (b->timer <= 0) { |
b->state = 1; |
} |
} |
//Slow to halt |
else if (b->state == 1) { |
b->x += b->hsp; |
if (b->x >= 520 || b->x <= 120) { //Hit walls |
b->hsp *= -1; |
} |
double rate = 0.03; |
if (b->hsp > 0) { |
b->hsp -= rate; |
if (b->hsp <= 0) { b->hsp = 0; } |
} |
else if (b->hsp < 0) { |
b->hsp += rate; |
if (b->hsp >= 0) { b->hsp = 0; } |
} |
if (b->hsp == 0 && b->rot <= 2) { |
b->state = 2; |
b->timer = 60; |
} |
} |
else if (b->state == 2) { |
if (b->timer == 1) { |
//Shoot flame |
int fx = b->x; |
int fy = b->y + 24; |
int fangle = (atan2(heroy - fy, fx - (herox - 20)) * 180 / 3.14159) + 270; |
createFireball(fx, fy, fangle, b->id); |
createFireball(fx, fy, fangle - 15, b->id); |
createFireball(fx, fy, fangle + 15, b->id); |
PHL_PlaySound(sounds[sndShot03], CHN_ENEMIES); |
} |
if (b->timer <= 0 && b->rot <= 2) { |
if (b->mode == 0) { |
b->state = 0; |
b->timer = 60; |
b->hsp = 2; |
b->mode = 1; |
} |
else{ |
b->mode = 0; |
b->state = 3; |
b->imageIndex = 2; |
b->vsp = -4; |
PHL_PlaySound(sounds[sndShot06], CHN_ENEMIES); |
} |
if (herox < b->x) { |
b->hsp *= -1; |
} |
} |
} |
//Stomp |
else if (b->state == 3) { |
b->y += b->vsp; |
b->vsp += b->grav; |
if (b->vsp >= 6) { b->vsp = 6; } |
//Hit floor |
if (b->y >= 480 - 176) { |
b->y = 480 - 176; |
b->state = 4; |
b->timer = 120; |
quakeTimer = 30; |
PHL_PlaySound(sounds[sndHit04], CHN_ENEMIES); |
b->hsp = 1; |
if (b->x > herox) { |
b->hsp *= -1; |
} |
} |
} |
//Chase |
else if (b->state == 4) { |
b->x += b->hsp; |
if (b->timer <= 0 || b->x >= 520 || b->x <= 120) { |
b->state = 5; |
b->timer = 80 + (rand() % 61); |
} |
} |
//Rise |
else if (b->state == 5) { |
b->y -= 1; |
if (b->timer <= 0) { |
b->state = 0; |
b->ypos = b->y; |
b->rot = 0; |
b->timer = 60; |
b->hsp = 2; |
if (b->x > herox) { |
b->hsp *= -1; |
} |
} |
} |
//Death |
else if (b->state == 6) { |
b->y += 0.2; |
if (b->timer % 12 == 0) { |
createEffect(2, b->x - 64 + (rand() % 100), b->y + (rand() % 80)); |
} |
if (b->timer <= 0) { |
dead = 1; |
} |
} |
if (b->state != 6) { |
//Setup Mask |
Mask mask; |
{ |
mask.unused = mask.circle = 0; |
if (b->state == 3 || b->state == 4) { |
mask.w = 64; |
mask.h = 96; |
mask.y = b->y; |
}else{ |
mask.w = 100; |
mask.h = 68; |
mask.y = b->y + 18; |
} |
mask.x = b->x - (mask.w / 2); |
} |
//Hit Player |
{ |
if (checkCollision(mask, getHeroMask())) { |
heroHit(30, b->x); |
} |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
//Hit |
b->invincible = 15; |
b->hp -= 1; |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
if (b->hp <= 0) { |
b->state = 6; |
b->timer = 180; |
b->invincible = 200; |
} |
} |
//Destroy object |
{ |
if (dead == 1) { |
enemyDestroy(b->id); |
bossDefeatedFlag = 1; |
roomSecret = 1; |
flags[boss2flag] = 1; |
PHL_StopMusic(); |
} |
} |
} |
void batbossDraw(Batboss* b) |
{ |
if (b->invincible % 2 == 0) { |
PHL_DrawSurfacePart(b->x - 64, b->y, (int)b->imageIndex * 128, 0, 128, 96, images[imgBoss]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/batboss.h |
---|
0,0 → 1,18 |
#ifndef BATBOSS_H |
#define BATBOSS_H |
typedef struct { |
int id; |
double x, y; |
double hsp, vsp, grav; |
double imageIndex; |
double ypos; |
double rot; |
int hp; |
int state, timer, mode; |
int invincible; |
} Batboss; |
void createBatboss(int x, int y); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/bee.c |
---|
0,0 → 1,214 |
#include "bee.h" |
#include "../enemy.h" |
#include "../game.h" |
#include "../hero.h" |
#include <stdlib.h> |
#include <math.h> |
void beeStep(Bee* b); |
void beeDraw(Bee* b); |
void createBee(int x, int y, int dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = /*(Enemy*)*/malloc(sizeof *e); |
Bee* b = /*(Bee*)*/malloc(sizeof *b); |
b->id = i; |
b->x = x; |
b->y = y; |
b->xstart = b->x; |
b->ystart = b->y; |
b->hsp = 0; |
b->vsp = 0; |
b->timer = 0; |
b->imageIndex = 0; |
b->dir = 1; |
b->state = 0; |
b->hoverdir = 180; |
if (dir == 1) { |
b->hoverdir = 0; |
b->dir = -1; |
} |
e->data = b; |
e->enemyStep = beeStep; |
e->enemyDraw = beeDraw; |
e->type = 24; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void beeStep(Bee* b) |
{ |
//Animate |
{ |
b->imageIndex += 0.33; |
if (b->imageIndex >= 3) { |
b->imageIndex -= 3; |
} |
} |
//Mindless hovering |
if (b->state == 0) |
{ |
b->hoverdir += 2.6; |
if (b->hoverdir >= 360) { |
b->hoverdir -= 360; |
} |
b->dir = 1; |
if (b->hoverdir <= 180) { |
b->dir = -1; |
} |
b->x = b->xstart + (20 * cos(b->hoverdir * 3.14159 /180)); |
//If player is within range |
Mask area; |
area.unused = area.circle = 0; |
area.x = b->x - 80; |
area.y = b->y; |
area.w = 200; |
area.h = 100; |
if (checkCollision(area, getHeroMask())) { |
b->state = 1; |
b->dir = 1; |
if (b->x + 20 > herox) { |
b->dir = -1; |
} |
b->hsp = -5.5 * b->dir; |
PHL_PlaySound(sounds[sndBee01], CHN_ENEMIES); |
} |
} |
//Fly backwards |
else if (b->state == 1) |
{ |
b->hsp += 0.25 * b->dir; |
if ((b->dir == 1 && b->hsp >= 0) || (b->dir == -1 && b->hsp <= 0)) { |
b->hsp = 0; |
b->state = 2; |
b->vsp = 3.75; |
} |
} |
//Fly downwards |
else if (b->state == 2) |
{ |
b->vsp -= 0.1; |
if (b->vsp <= 0) { |
b->state = 3; |
b->vsp = 0; |
b->dir = 1; |
if (b->x + 20 > herox) { |
b->dir = -1; |
} |
b->hsp = 3 * b->dir; |
} |
} |
//Fly diaganal |
else if (b->state == 3) |
{ |
b->vsp -= 0.1; |
if (b->vsp < -3) { |
b->vsp = -3; |
} |
if (b->y <= b->ystart) { |
b->state = 4; |
b->vsp = 0; |
b->y = b->ystart; |
if (b->x < b->xstart) { |
b->dir = 1; |
}else{ |
b->dir = -1; |
} |
b->hsp = b->dir; |
} |
} |
//Fly back to start |
else if (b->state == 4) |
{ |
if ((b->dir == 1 && b->x >= b->xstart) || (b->dir == -1 && b->x <= b->xstart)) { |
b->state = 0; |
b->hsp = 0; |
b->hoverdir = 0; |
} |
} |
//Movement |
{ |
b->x += b->hsp; |
b->y += b->vsp; |
} |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 24; |
mask.h = 32; |
mask.y = b->y + 6; |
mask.x = b->x + 14; |
if (b->dir == -1) { |
mask.x = b->x + 2; |
} |
} |
//Hit Player |
{ |
if (checkCollision(mask, getHeroMask())) { |
heroHit(15, mask.x + (mask.w / 2)); |
} |
} |
//Weapon Collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
createEffect(2, b->x - 12, b->y - 6); |
spawnCollectable(b->x + 20, b->y); |
enemyDestroy(b->id); |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
void beeDraw(Bee* b) |
{ |
int cropx = 280; |
if (b->dir == -1) { |
cropx += 120; |
} |
cropx += (int)b->imageIndex * 40; |
PHL_DrawSurfacePart(b->x, b->y, cropx, 480, 40, 40, images[imgEnemies]); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/bee.h |
---|
0,0 → 1,16 |
#ifndef BEE_H |
#define BEE_H |
typedef struct { |
int id; |
double x, y; |
int xstart, ystart; |
double hsp, vsp; |
double imageIndex; |
int dir, state, timer; |
double hoverdir; |
} Bee; |
void createBee(int x, int y, int dir); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/boar.c |
---|
0,0 → 1,221 |
#include "boar.h" |
#include "../game.h" |
#include "../hero.h" |
#include <stdlib.h> |
void boarStep(Boar* b); |
void boarDraw(Boar* b); |
void createBoar(int x, int y) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = /*(Enemy*)*/malloc(sizeof *e); |
Boar* b = /*(Boar*)*/malloc(sizeof *b); |
b->id = i; |
b->hp = 3; |
b->x = x; |
b->y = y; |
b->hsp = 0; |
b->imageIndex = 0; |
b->dir = 1; |
b->blink = 0; |
b->state = 0; |
b->timer = 0; |
e->data = b; |
e->enemyStep = boarStep; |
e->enemyDraw = boarDraw; |
e->type = 26; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void boarStep(Boar* b) |
{ |
//Setup mask |
Mask mask; |
{ |
mask.unused = mask.circle = 0; |
mask.w = 32; |
mask.h = 28; |
mask.x = b->x + ((40 - mask.w) / 2); |
mask.y = b->y + 40 - mask.h; |
} |
//Blink animation |
{ |
if (b->blink > 0) { |
b->blink -= 1; |
} |
} |
//Patterns |
{ |
//Dance |
if (b->state == 0) |
{ |
//Animate |
b->imageIndex += 0.15; |
if (b->imageIndex >= 8) { |
b->imageIndex -= 8; |
} |
//if player gets near |
Mask area; |
area.unused = area.circle = 0; |
area.x = b->x - 80; |
area.y = b->y - 40; |
area.w = 200; |
area.h = 80; |
if (checkCollision(area, getHeroMask()) == 1) { |
b->state = 1; |
b->timer = -1; |
b->imageIndex = 0; |
b->dir = 1; |
if (herox < b->x + 20) { |
b->dir = -1; |
} |
} |
} |
//Rev up |
else if (b->state == 1) |
{ |
b->timer += 1; |
//Play sound |
if (b->timer % 10 == 0) { |
PHL_PlaySound(sounds[sndShot01], CHN_ENEMIES); |
} |
//Create effect |
if (b->timer % 16 == 0) { |
if (b->dir == 1) { |
createEffectExtra(3, b->x + 20 - 30, b->y + 8, -1, 0, 0); |
} |
if (b->dir == -1) { |
createEffectExtra(3, b->x + 20 - 10, b->y + 8, 1, 0, 0); |
} |
} |
if (b->timer >= 60) { |
b->state = 2; |
b->hsp = 3; |
} |
} |
//Running |
else if (b->state == 2) |
{ |
b->x += b->hsp * b->dir; |
mask.x = b->x + ((40 - mask.w) / 2); |
//Collide with wall |
if (checkTileCollision(1, mask) == 1) { |
b->x -= b->hsp * b->dir; |
b->dir *= -1; |
} |
//On edge |
{ |
mask.x = b->x + ((40 - mask.w) / 2); |
mask.x += mask.w * b->dir; |
mask.y += 1; |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x == -1) { |
b->dir *= -1; |
} |
mask.y -= 1; |
mask.x = b->x + ((40 - mask.w) / 2); |
} |
b->hsp -= 0.05; |
if (b->hsp <= 0) { |
b->state = 0; |
} |
} |
//Running animation |
if (b->state == 1 || b->state == 2) { |
//Animate |
b->imageIndex += 0.2; |
if (b->imageIndex >= 2) { |
b->imageIndex -= 2; |
} |
} |
} |
//Collide with hero |
{ |
if (checkCollision(mask, getHeroMask())) { |
heroHit(30, mask.x + (mask.w / 2)); |
} |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
b->hp -= 1; |
b->blink = 15; |
//Death |
if (b->hp <= 0) { |
createEffect(2, b->x - 12, b->y - 12); |
spawnCollectable(b->x + 20, b->y); |
enemyDestroy(b->id); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
} |
void boarDraw(Boar* b) |
{ |
if (b->blink % 2 == 0) |
{ |
int cropx = 0, cropy = 360; |
int drawx = b->x, drawy = b->y; |
//Dance |
if (b->state == 0) { |
int animation[8] = {0, 1, 2, 1, 0, 3, 4, 3}; |
cropx = 160 + (animation[(int)b->imageIndex] * 40); |
} |
//Charge |
else{ |
cropx = (int)b->imageIndex * 40; |
if (b->dir == -1) { |
cropx += 80; |
} |
} |
PHL_DrawSurfacePart(drawx, drawy, cropx, cropy, 40, 40, images[imgEnemies]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/boar.h |
---|
0,0 → 1,18 |
#ifndef BOAR_H |
#define BOAR_H |
typedef struct { |
int id; |
int hp; |
double x, y; |
double hsp; |
double imageIndex; |
int blink; |
int dir; |
int state; |
int timer; |
} Boar; |
void createBoar(int x, int y); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/boomknight.c |
---|
0,0 → 1,285 |
#include "boomknight.h" |
#include "../game.h" |
#include "../hero.h" |
#include <stdlib.h> |
void boomknightStep(Boomknight* b); |
void boomknightDraw(Boomknight* b); |
void boomStep(Boom* b); |
void boomDraw(Boom* b); |
void createBoomknight(int x, int y) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Boomknight* b = malloc(sizeof *b); |
b->id = i; |
b->hp = 2; |
b->blink = 0; |
b->x = x; |
b->y = y; |
b->dir = 1; |
if (herox < b->x + 20) { |
b->dir = -1; |
} |
b->imageIndex = 0; |
b->state = 0; |
b->timer = 0; |
e->data = b; |
e->enemyStep = boomknightStep; |
e->enemyDraw = boomknightDraw; |
e->type = 31; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void boomknightStep(Boomknight* b) |
{ |
//Animate |
{ |
b->imageIndex += 0.1; |
if (b->imageIndex >= 2) { |
b->imageIndex -= 2; |
} |
if (b->blink > 0) { |
b->blink -= 1; |
} |
} |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 30; |
mask.h = 32; |
mask.x = b->x + ((40 - mask.w) / 2); |
mask.y = b->y + (40 - mask.h); |
} |
//Walk |
if (b->state == 0) { |
//Movement |
{ |
double hsp = 0.5; |
b->x += hsp * b->dir; |
mask.x = b->x + ((40 - mask.w) / 2); |
} |
//Hit wall |
{ |
if (checkTileCollision(1, mask) == 1) { |
b->dir *= -1; |
} |
} |
//On edge |
{ |
mask.x += mask.w * b->dir; |
mask.y += 20; |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x == -1) { |
b->dir *= -1; |
} |
} |
//Player is close |
{ |
if (b->timer <= 0) { |
Mask area; |
{ |
area.circle = area.unused = 0; |
area.w = 120; |
area.h = 40; |
area.x = b->x + 20; |
if (b->dir == -1) { |
area.x -= area.w; |
} |
area.y = b->y; |
} |
if (checkCollision(area, getHeroMask()) == 1) { |
b->state = 1; |
b->timer = 0; |
} |
}else{ |
b->timer -= 1; |
} |
} |
} |
//Throw |
else if (b->state == 1) { |
//Animate |
{ |
b->imageIndex = 0; |
if (b->timer >= 15) { |
b->imageIndex = 2; |
} |
} |
b->timer += 1; |
if (b->timer == 15) { |
createBoom(b->x, b->y, b->dir); |
PHL_PlaySound(sounds[sndPi05], CHN_ENEMIES); |
} |
if (b->timer >= 110) { |
b->state = 0; |
b->imageIndex = 0; |
b->timer = 120; |
} |
} |
//Update Mask |
mask.x = b->x + ((40 - mask.w) / 2); |
mask.y = b->y + (40 - mask.h); |
//Hero Collision |
{ |
if (checkCollision(mask, getHeroMask()) == 1) { |
heroHit(15, mask.x + (mask.w / 2)); |
} |
} |
//Weapon Collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
b->hp -= 1; |
b->blink = 15; |
//Death |
if (b->hp <= 0) { |
createEffect(2, b->x - 12, b->y - 6); |
spawnCollectable(b->x + 20, b->y); |
enemyDestroy(b->id); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
} |
void boomknightDraw(Boomknight* b) |
{ |
if (b->blink % 2 == 0) { |
int cropX = 400 + ((int)b->imageIndex * 40); |
if (b->dir == -1) { |
cropX += 120; |
} |
PHL_DrawSurfacePart(b->x, b->y, cropX, 400, 40, 40, images[imgEnemies]); |
} |
} |
//Enemy boomerang |
void createBoom(int x, int y, int dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Boom* b = malloc(sizeof *b); |
b->id = i; |
b->dir = dir; |
b->x = x; |
b->y = y; |
b->hsp = 6 * b->dir; |
b->imageIndex = 0; |
b->timer = 90; |
e->data = b; |
e->enemyStep = boomStep; |
e->enemyDraw = boomDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void boomStep(Boom* b) |
{ |
//Animate |
{ |
b->imageIndex += 0.33; |
if (b->imageIndex >= 8) { |
b->imageIndex -= 8; |
} |
} |
//Movement |
{ |
b->x += b->hsp; |
double fric = 0.125; |
b->hsp -= fric * b->dir; |
} |
//Hero collision |
{ |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 24; |
mask.h = 24; |
mask.x = b->x + ((40 - mask.w) / 2); |
mask.y = b->y + ((40 - mask.h) / 2); |
} |
if (checkCollision(mask, getHeroMask()) == 1) { |
heroHit(10, mask.x + (mask.w / 2)); |
} |
} |
b->timer -= 1; |
if (b->timer <= 0) { |
createEffectExtra(5, b->x + 20, b->y + 20, 0, 0, 0); |
enemyDestroy(b->id); |
} |
} |
void boomDraw(Boom* b) |
{ |
int cropX = (int)b->imageIndex * 40; |
if (b->dir == -1) { |
cropX += 320; |
} |
PHL_DrawSurfacePart(b->x, b->y, cropX, 360, 40, 40, images[imgMisc20]); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/boomknight.h |
---|
0,0 → 1,27 |
#ifndef BOOMKNIGHT_H |
#define BOOMKNIGHT_H |
typedef struct { |
int id; |
int hp; |
int blink; |
double x, y; |
int dir; |
double imageIndex; |
int state, timer; |
} Boomknight; |
void createBoomknight(int x, int y); |
typedef struct { |
int id; |
int dir; |
double x, y; |
double hsp; |
double imageIndex; |
int timer; |
} Boom; |
void createBoom(int x, int y, int dir); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/crab.c |
---|
0,0 → 1,509 |
#include "crab.h" |
#include "../PHL.h" |
#include "../enemy.h" |
#include "../game.h" |
#include "../hero.h" |
#include <math.h> |
#include <stdlib.h> |
int boss3flag = 13; |
void crabStep(Crab* c); |
void crabDraw(Crab* c); |
void updateCrabMask(Crab* c); |
void crabDestroy(Crab* c); |
void electricityStep(Electricity* e); |
void electricityDraw(Electricity* e); |
void createCrab(int x, int y) |
{ |
if (flags[boss3flag] == 0) { //have not beaten boss 3 |
PHL_FreeSurface(images[imgBoss]); |
images[imgBoss] = PHL_LoadQDA("boss06.bmp"); |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
//Boss start |
setBossRoom(); |
Enemy* e = /*(Enemy*)*/malloc(sizeof(Enemy)); |
Crab* c = /*(Crab*)*/malloc(sizeof(Crab)); |
c->id = i; |
//c->hp = 1; |
c->hp = 35; |
c->invincible = 0; |
c->x = x; |
c->y = y; |
c->vsp = 0; |
c->hsp = 0; |
c->imageIndex = 0; |
c->state = 0; |
c->timer = 0; |
c->counter = 0; |
c->mask.unused = 0; |
c->mask.circle = 1; |
c->mask.w = 33; |
c->mask.h = 33; |
updateCrabMask(c); |
//Setup phase |
c->timer = 60; |
e->data = c; |
e->enemyStep = crabStep; |
e->enemyDraw = crabDraw; |
e->type = 42; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
} |
void crabStep(Crab* c) |
{ |
char dead = 0; |
double grav = 0.15; |
if (c->invincible > 0) { |
c->invincible -= 1; |
} |
//Wait |
if (c->state == 0) |
{ |
c->imageIndex = 0; |
if (c->timer <= 0) { |
c->timer = 0; |
if (c->counter == 2 || c->counter == 5) { //Goto roll |
c->state = 3; |
if (c->counter == 5) { |
c->counter = 0; |
}else{ |
c->counter = 3; |
} |
}else if (c->counter == 3) { |
c->state = 2; |
}else{ |
c->state = 1; //Goto shoot |
} |
}else{ |
c->timer -= 1; |
} |
} |
//Shoot Electric orbs |
else if (c->state == 1) |
{ |
//Create orbs |
if (c->timer == 0) { |
PHL_PlaySound(sounds[sndPi05], CHN_ENEMIES); |
double angle = (atan2(heroy + 20 - (c->y + 60), c->x - (herox - 20)) * 180 / 3.14159) + 270; |
createElectricity(c->x, c->y + 60, angle - 45, c->id); |
createElectricity(c->x, c->y + 60, angle - 22.5, c->id); |
createElectricity(c->x, c->y + 60, angle, c->id); |
createElectricity(c->x, c->y + 60, angle + 22.5, c->id); |
createElectricity(c->x, c->y + 60, angle + 45, c->id); |
} |
if (c->timer >= 20) { |
c->state = 2; |
c->timer = 0; |
}else{ |
c->timer += 1; |
} |
} |
//Leap |
else if (c->state == 2) |
{ |
c->imageIndex = 1; |
//Hopping down or hopping up |
int hopup = 1; |
if (c->counter > 2) { |
hopup = 0; |
} |
//Jump |
if (c->timer == 0) { |
PHL_PlaySound(sounds[sndJump02], CHN_ENEMIES); |
c->vsp = -6.5; |
if (hopup == 0) { |
c->vsp = -1.5; |
} |
c->timer = 1; |
} |
//Vertical velocity |
c->y += c->vsp; |
c->vsp += grav; |
if (c->vsp >= 6) { |
c->vsp = 6; |
} |
//Check if onground |
if ((hopup == 1 && c->vsp > 0) || (hopup == 0 && c->vsp >= 6)) { |
Mask area; |
area.unused = area.circle = 0; |
area.w = 40; |
area.h = 10; |
area.x = c->x - (area.w / 2); |
area.y = c->y + (80 - area.h); |
PHL_Rect collide = getTileCollision(1, area); |
if (collide.x != -1) { |
c->y = collide.y - 80; |
c->state = 0; |
c->counter += 1; |
c->timer = 25; |
if (c->counter == 2 || c->counter == 5) { |
c->timer = 3; |
} |
} |
} |
} |
//Roll hop |
else if (c->state == 3) |
{ |
//Animate |
if (c->hsp > 0) { |
c->imageIndex += 0.25; |
} |
if (c->hsp < 0) { |
c->imageIndex -= 0.25; |
} |
if (c->imageIndex < 2) { c->imageIndex += 4; } |
if (c->imageIndex >= 6) { c->imageIndex -= 4; } |
if (c->timer == 0) { |
PHL_PlaySound(sounds[sndHit04], CHN_ENEMIES); |
c->timer = 1; |
c->vsp = -1.5; |
c->imageIndex = 2; |
if (c->x > 320) { |
c->hsp = -8; |
}else{ |
c->hsp = 8; |
} |
} |
//Movement |
c->y += c->vsp; |
c->vsp += grav; |
//Check if onground |
if (c->vsp > 0) { |
Mask area; |
area.unused = area.circle = 0; |
area.w = 40; |
area.h = 10; |
area.x = c->x - (area.w / 2); |
area.y = c->y + (80 - area.h); |
PHL_Rect collide = getTileCollision(1, area); |
if (collide.x != -1) { |
c->y = collide.y - 80; |
c->state = 4; |
} |
} |
} |
//Roll |
if (c->state == 4) |
{ |
//Animate |
if (c->hsp > 0) { |
c->imageIndex += 0.25; |
} |
if (c->hsp < 0) { |
c->imageIndex -= 0.25; |
} |
if (c->imageIndex < 2) { c->imageIndex += 4; } |
if (c->imageIndex >= 6) { c->imageIndex -= 4; } |
//Movement |
c->x += c->hsp; |
//Collide with wall |
Mask area; |
area.unused = area.circle = 0; |
area.w = area.h = c->mask.w * 2; |
area.x = c->x - c->mask.w; |
area.y = c->y + (40 - c->mask.h); |
if (checkTileCollision(1, area) == 1) { |
c->state = 5; |
c->timer = 0; |
} |
} |
//Bounce off wall |
if (c->state == 5) |
{ |
if (c->timer == 0) { |
PHL_PlaySound(sounds[sndHit04], CHN_ENEMIES); |
c->timer = 1; |
c->vsp = -2; |
c->hsp = 2; |
if (c->x > 320) { |
c->hsp *= -1; |
} |
} |
c->imageIndex = 1; |
c->x += c->hsp; |
c->y += c->vsp; |
c->vsp += grav; |
//Check if onground |
if (c->vsp > 0) { |
Mask area; |
area.unused = area.circle = 0; |
area.w = 40; |
area.h = 10; |
area.x = c->x - (area.w / 2); |
area.y = c->y + (80 - area.h); |
PHL_Rect collide = getTileCollision(1, area); |
if (collide.x != -1) { |
c->y = collide.y - 80; |
c->state = 0; |
c->timer = 65; |
} |
} |
} |
//Death |
else if (c->state == 6) |
{ |
c->imageIndex = 1; |
c->y += 0.2; |
c->timer -= 1; |
if (c->timer % 12 == 0) { |
createEffect(2, c->x - 64 + (rand() % 100), c->y + (rand() % 80)); |
} |
if (c->timer <= 0) { |
crabDestroy(c); |
dead = 1; |
} |
} |
if (dead == 0) { |
if (c->state != 6) { |
//Update Mask |
c->mask.x = c->x; |
c->mask.y = c->y + 40; |
//Weapon collision |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(c->mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
c->invincible = 15; |
c->hp -= 1; |
i = MAX_WEAPONS; |
} |
} |
} |
} |
//Hit Player |
if (checkCollision(c->mask, getHeroMask())) { |
heroHit(30, c->x); |
} |
//Die |
if (c->hp <= 0) { |
c->state = 6; |
c->timer = 180; |
c->invincible = 200; |
} |
} |
} |
} |
void crabDraw(Crab* c) |
{ |
if (c->invincible % 2 == 0) { |
PHL_DrawSurfacePart(c->x - 40, c->y, (int)c->imageIndex * 80, 0, 80, 80, images[imgBoss]); |
} |
} |
void updateCrabMask(Crab* c) |
{ |
c->mask.x = c->x; |
c->mask.y = c->y + 40; |
} |
void crabDestroy(Crab* c) |
{ |
enemyDestroy(c->id); |
bossDefeatedFlag = 1; |
roomSecret = 1; |
flags[boss3flag] = 1; |
PHL_StopMusic(); |
} |
void createElectricity(int x, int y, double angle, int minid) |
{ |
int i; |
for (i = minid; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = /*(Enemy*)*/malloc(sizeof *e); |
Electricity* el = /*(Electricity*)*/malloc(sizeof *el); |
el->id = i; |
el->x = x; |
el->y = y; |
//Fix angle |
if (angle < 0) { |
angle += 360; |
} |
if (angle >= 360) { |
angle -= 360; |
} |
el->angle = angle; |
el->imageIndex = 0; |
el->mask.unused = 0; |
el->mask.circle = 1; |
el->mask.w = 16; |
el->mask.h = 16; |
el->mask.x = x; |
el->mask.y = y; |
e->data = el; |
e->enemyStep = electricityStep; |
e->enemyDraw = electricityDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
/* |
int thisid = -1; |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
if (i <= minid) { |
thisid = i; |
i = MAX_ENEMIES; |
}else{ |
i = MAX_ENEMIES; |
} |
} |
} |
if (thisid == -1) { |
for (i = minid + 1; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
enemies[i] = enemies[minid]; |
Crab* c = enemies[i]->data; |
c->id = i; |
thisid = minid; |
i = MAX_ENEMIES; |
} |
} |
} |
if (thisid != -1) { |
Enemy* e = (Enemy*)malloc(sizeof(Enemy)); |
Electricity* el = (Electricity*)malloc(sizeof(Electricity)); |
el->id = thisid; |
el->x = x; |
el->y = y; |
//Fix angle |
if (angle < 0) { |
angle += 360; |
} |
if (angle >= 360) { |
angle -= 360; |
} |
el->angle = angle; |
el->imageIndex = 0; |
el->mask.unused = 0; |
el->mask.circle = 1; |
el->mask.w = 16; |
el->mask.h = 16; |
el->mask.x = x; |
el->mask.y = y; |
e->data = el; |
e->enemyStep = electricityStep; |
e->enemyDraw = electricityDraw; |
e->type = -1; |
enemies[thisid] = e; |
} |
*/ |
} |
void electricityStep(Electricity* e) |
{ |
double spd = 3; |
e->x += spd * sin(e->angle * 3.14159 / 180); |
e->y += spd * cos(e->angle * 3.14159 / 180); |
//Update Mask |
e->mask.x = e->x; |
e->mask.y = e->y; |
//Collide with Shield |
if (checkCollision(shieldMask, e->mask) == 1) { |
createEffect(1, e->x - 20, e->y - 20); |
PHL_PlaySound(sounds[sndHit07], CHN_EFFECTS); |
enemyDestroy(e->id); |
}else{ |
//Collide with Hero |
if (checkCollision(getHeroMask(), e->mask) == 1) { |
if (heroHit(25, e->x) == 1) { |
heroStun(); |
} |
} |
} |
//Animate |
e->imageIndex += 0.25; |
if (e->imageIndex >= 3) { |
e->imageIndex -= 3; |
} |
//Outside of screen |
if (e->x < -20 || e->x > 660 || e->y < -20 || e->y > 500) { |
enemyDestroy(e->id); |
} |
} |
void electricityDraw(Electricity* e) |
{ |
PHL_DrawSurfacePart(e->x - 20, e->y - 20, 40 + ((int)e->imageIndex * 40), 0, 40, 40, images[imgMisc20]); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/crab.h |
---|
0,0 → 1,30 |
#ifndef CRAB_H |
#define CRAB_H |
#include "../collision.h" |
typedef struct { |
int id; |
int hp, invincible; |
double x, y; |
double hsp, vsp; |
double imageIndex; |
int state, timer, counter; |
Mask mask; |
} Crab; |
void createCrab(int x, int y); |
typedef struct { |
int id; |
double x, y; |
double angle; |
double imageIndex; |
Mask mask; |
} Electricity; |
void createElectricity(int x, int y, double angle, int minid); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/devil.c |
---|
0,0 → 1,458 |
#include "devil.h" |
#include "../game.h" |
#include "../PHL.h" |
#include "../hero.h" |
#include <stdlib.h> |
#include <math.h> |
int boss6flag = 31; |
void devilStep(Devil* d); |
void devilDraw(Devil* d); |
void orbStep(Orb* o); |
void orbDraw(Orb* o); |
void createDevil(int x, int y) |
{ |
if (flags[boss6flag] == 0) { //have not beaten boss 6 |
PHL_FreeSurface(images[imgBoss]); |
images[imgBoss] = PHL_LoadQDA("boss04.bmp"); |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
setBossRoom(); |
Enemy* e = /*(Enemy*)*/malloc(sizeof *e); |
Devil* d = /*(Devil*)*/malloc(sizeof *d); |
d->id = i; |
d->x = x; |
d->y = y; |
d->ystart = d->y; |
d->newystart = d->ystart; |
d->hsp = -2.5; |
d->hp = 100; |
//d->hp = 1; |
d->state = 0; |
d->timer = 0; |
d->blink = 0; |
d->boblen = 32; |
d->bobspd = 3; |
d->tailangle = 90; |
d->rotcounter = 0; |
d->bobcounter = 0; |
d->bobspd = 3; |
d->rotspd = 1; |
d->imageIndex = 0; |
e->data = d; |
e->enemyStep = devilStep; |
e->enemyDraw = devilDraw; |
e->type = 45; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
} |
void devilStep(Devil* d) |
{ |
char dead = 0; |
//Animate |
{ |
d->imageIndex += 0.1; |
if (d->imageIndex >= 2) { |
d->imageIndex -= 2; |
} |
if (d->blink > 0) { |
d->blink -= 1; |
} |
} |
//Bob |
{ |
if (d->state != 4) { |
d->bobcounter += d->bobspd; |
if (d->bobcounter >= 360) { |
d->bobcounter -= 360; |
} |
d->y = d->ystart + (d->boblen * cos(d->bobcounter * 3.14159 / 180)); |
} |
} |
//Swing tail |
{ |
d->rotcounter += d->rotspd; |
if (d->rotcounter >= 360) { |
d->rotcounter -= 360; |
} |
d->tailangle = 90 + (55 * cos(d->rotcounter * 3.14159 / 180)); |
} |
//Patterns |
{ |
//movement |
if (d->state == 0 || d->state == 2) |
{ |
d->rotspd = 1; |
d->boblen = 32; |
d->bobspd = 3; |
//Re-align ystart |
if (d->ystart > d->newystart) { |
d->ystart -= 1; |
} |
if (d->ystart < d->newystart) { |
d->ystart += 1; |
} |
d->x += d->hsp; |
//Slow Down |
double rate = 0.016; |
if (d->hsp < 0) { |
d->hsp += rate; |
if (d->hsp >= 0) { |
d->hsp = 0; |
} |
} |
if (d->hsp > 0) { |
d->hsp -= rate; |
if (d->hsp <= 0) { |
d->hsp = 0; |
} |
} |
if (d->hsp == 0) { |
d->timer = 0; |
if (d->state == 0) { |
d->state = 1; |
} |
if (d->state == 2) { |
if ((d->rotcounter >= 90 && d->rotcounter <= 90 + d->rotspd) || (d->rotcounter >= 270 && d->rotcounter <= 270 + d->rotspd)) { |
d->state = 3; |
} |
} |
} |
} |
//mid room pause |
else if (d->state == 1) |
{ |
d->timer += 1; |
if (d->timer >= 60) { |
if (d->state == 1) { |
d->hsp = 2.5; |
if (herox < d->x) { |
d->hsp *= -1; |
} |
} |
d->state = 2; |
} |
} |
//Shoot |
else if (d->state == 3) |
{ |
d->rotspd = 3; |
d->boblen = 10; |
d->bobspd = 10; |
d->timer += 1; |
//Shoot orbs |
if (d->timer == 120 || d->timer == 240 || d->timer == 360) { |
int aim = (atan2((heroy + 20) - d->y, d->x - herox) * 180 / 3.14159) + 270; |
int spawnY = d->y + 20; |
createOrb(d->x, spawnY, aim + 22); |
createOrb(d->x, spawnY, aim + 11); |
createOrb(d->x, spawnY, aim); |
createOrb(d->x, spawnY, aim - 11); |
createOrb(d->x, spawnY, aim - 22); |
PHL_PlaySound(sounds[sndShot03], CHN_ENEMIES); |
} |
if (d->timer == 360) { |
d->state = 0; |
d->hsp = 2.5; |
if (d->x > 320) { |
d->hsp *= -1; |
} |
int chaseY = heroy - d->ystart; |
if (chaseY > 52) { chaseY = 52; } |
if (chaseY < -52) { chaseY = -52; } |
d->newystart = d->ystart + chaseY; |
} |
} |
//Death |
if (d->state == 4) { |
d->rotspd = 3; |
d->y += 0.2; |
d->timer -= 1; |
if (d->timer % 12 == 0) { |
createEffect(2, d->x - 64 + (rand() % 100), d->y - 64 + (rand() % 80)); |
} |
if (d->timer <= 0) { |
dead = 1; |
} |
} |
} |
//Collisions |
if (d->state != 4) { |
//Setup masks |
Mask masks[6]; |
//Head mask |
masks[0].unused = masks[0].circle = 0; |
masks[0].w = 100; |
masks[0].h = 104; |
masks[0].x = d->x - (masks[0].w / 2); |
masks[0].y = d->y - (masks[0].h / 2); |
//Link masks |
for (int i = 1; i < 5; i++) { |
int taildis[4] = {54, 80, 108, 134}; |
int taillag[4] = {10, 15, 10, 5}; |
double newtailangle = 90 + (55 * cos((d->rotcounter - taillag[i-1]) * 3.14159 / 180)); |
masks[i].unused = 0; |
masks[i].circle = 1; |
masks[i].w = 16; |
masks[i].h = 16; |
masks[i].x = d->x + (taildis[i-1] * cos(newtailangle * 3.14159 / 180)); |
masks[i].y = d->y + (taildis[i-1] * sin(newtailangle * 3.14159 / 180)); |
} |
//Barb mask |
masks[5].unused = masks[5].circle = 0; |
masks[5].w = 40; |
masks[5].h = 40; |
masks[5].x = (d->x + (160 * cos(d->tailangle * 3.14159 / 180))) - (masks[5].w / 2); |
masks[5].y = (d->y + (160 * sin(d->tailangle * 3.14159 / 180))) - (masks[5].h / 2); |
//Collisions |
int hitHead = 0; |
for (int a = 0; a < 6; a++) |
{ |
if (a == 0 || a == 5) { |
//Hit Player |
if (checkCollision(masks[a], getHeroMask())) { |
int damage = 25; |
if (a == 0) { |
damage = 50; |
} |
if (heroHit(damage, masks[a].x + (masks[a].w / 2)) == 1) { |
if (a == 5) { //Barb |
heroStun(); |
} |
} |
} |
} |
//Weapon collision |
if (hitHead == 0) { |
for (int i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(masks[a], weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
//Head |
if (a == 0) { |
d->hp -= 1; |
d->blink = 15; |
hitHead = 1; |
if (d->hp <= 0) { |
d->state = 4; |
d->timer = 180; |
d->blink = 200; |
} |
}else{ |
PHL_PlaySound(sounds[sndHit03], CHN_WEAPONS); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
} |
} |
//Destroy |
if (dead == 1) { |
enemyDestroy(d->id); |
bossDefeatedFlag = 1; |
roomSecret = 1; |
flags[boss6flag] = 1; |
PHL_StopMusic(); |
} |
} |
void devilDraw(Devil* d) |
{ |
if (d->blink % 2 == 0) |
{ |
int dx, dy; |
//Draw tail |
int taildis[4] = {54, 80, 108, 134}; |
int taillag[4] = {10, 15, 10, 5}; |
for (int i = 0; i < 4; i++) { |
double newtailangle = 90 + (55 * cos((d->rotcounter - taillag[i]) * 3.14159 / 180)); |
dx = d->x + (taildis[i] * cos(newtailangle * 3.14159 / 180)) - 32; |
dy = d->y + (taildis[i] * sin(newtailangle * 3.14159 / 180)) - 32; |
PHL_DrawSurfacePart(dx, dy, 0, 128, 64, 64, images[imgBoss]); |
} |
//Draw Head |
dx = d->x - 64; |
dy = d->y - 64; |
PHL_DrawSurfacePart(dx, dy, (int)d->imageIndex * 128, 0, 128, 128, images[imgBoss]); |
//Draw Tail Tip |
dx = d->x + (160 * cos(d->tailangle * 3.14159 / 180)) - 32; |
dy = d->y + (160 * sin(d->tailangle * 3.14159 / 180)) - 32; |
PHL_DrawSurfacePart(dx, dy, 64, 128, 64, 64, images[imgBoss]); |
} |
} |
//Stone Orbs |
void createOrb(int x, int y, double dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = /*(Enemy*)*/malloc(sizeof *e); |
Orb* o = /*(Orb*)*/malloc(sizeof *o); |
o->id = i; |
o->x = x; |
o->y = y; |
o->dir = dir; |
o->imageIndex = 0; |
e->data = o; |
e->enemyStep = orbStep; |
e->enemyDraw = orbDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void orbStep(Orb* o) |
{ |
char dead = 0; |
//Animate |
{ |
o->imageIndex += 0.33; |
if (o->imageIndex >= 4) { |
o->imageIndex -= 4; |
} |
} |
//Movement |
{ |
int spd = 4; |
o->x += spd * sin(o->dir * 3.14159 / 180); |
o->y += spd * cos(o->dir * 3.14159 / 180); |
} |
//Collision |
{ |
Mask mask; |
mask.unused = 0; |
mask.circle = 1; |
mask.w = 6; |
mask.x = o->x; |
mask.y = o->y; |
//Collide with shield |
/*if (checkCollision(mask, shieldMask)) { |
createEffect(1, o->x - 20, o->y - 20); |
PHL_PlaySound(sounds[sndHit07], CHN_EFFECTS); |
dead = 1; |
}else{*/ |
//Hit player |
if (checkCollision(getHeroMask(), mask)) { |
heroStone(); |
heroHit(25, mask.x); |
} |
//} |
//Collide with weapon |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
createEffect(2, o->x - 32, o->y - 32); |
dead = 1; |
i = MAX_WEAPONS; |
} |
} |
} |
} |
//Destroy if outside of room |
{ |
if (o->x < -20 || o->x > 660 || o->y < -20 || o->y > 500) { |
dead = 1; |
} |
} |
//Finally erase object |
{ |
if (dead == 1) { |
enemyDestroy(o->id); |
} |
} |
} |
void orbDraw(Orb* o) |
{ |
int animation[4] = {0, 1, 0, 2}; |
PHL_DrawSurfacePart(o->x - 20, o->y - 20, 440 + (animation[(int)o->imageIndex] * 40), 480, 40, 40, images[imgMisc20]); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/devil.h |
---|
0,0 → 1,28 |
#ifndef DEVIL_H |
#define DEVIL_H |
typedef struct { |
int id; |
double x, y; |
double ystart, newystart; |
double hsp; |
int hp; |
int state, timer; |
int blink; |
int boblen, bobspd; |
double tailangle, bobcounter, rotcounter, rotspd; |
double imageIndex; |
} Devil; |
void createDevil(int x, int y); |
typedef struct { |
int id; |
double x, y; |
double dir; |
double imageIndex; |
} Orb; |
void createOrb(int x, int y, double dir); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/dodo.c |
---|
0,0 → 1,587 |
#include "dodo.h" |
#include "../game.h" |
#include "../hero.h" |
#include "../PHL.h" |
#include "../enemy.h" |
#include <stdlib.h> |
void dodoStep(Dodo* d); |
void dodoDraw(Dodo* d); |
Mask updateDodoMask(Dodo* d, Mask mask); |
int dodoWallCollision(Dodo* d, Mask mask); |
int boss1flag = 1; |
void createDodo(int x, int y, int flag) |
{ |
char miniboss = 0; |
if (flag != 0) { |
miniboss = 1; |
}else{ |
flag = boss1flag; |
} |
if (flags[flag] == 0) { |
PHL_FreeSurface(images[imgBoss]); |
images[imgBoss] = PHL_LoadQDA("boss01.bmp"); |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
if (miniboss == 0) { |
setBossRoom(); |
} |
Enemy* e = malloc(sizeof *e); |
Dodo* d = malloc(sizeof *d); |
d->id = i; |
d->x = x; |
d->y = y; |
d->vsp = -6; |
d->hsp = 0; |
d->grav = 0.2; |
d->onground = 0; |
d->dir = -1; |
if (herox > d->x) { |
d->dir = 1; |
} |
d->imageIndex = 0; |
d->timer = 0; |
d->state = 2; |
d->hp = 45; |
d->blink = 0; |
d->tojump = 1; |
d->jumptoggle = 0; |
d->flag = flag; |
e->data = d; |
e->enemyStep = dodoStep; |
e->enemyDraw = dodoDraw; |
e->type = 40; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
} |
void dodoStep(Dodo* d) |
{ |
char dead = 0; |
//Constants |
double fric = 0.06; |
//Animation vars |
double imgspd = 0; |
int frames = 0; |
//timers |
{ |
if (d->timer > 0) { |
d->timer -= 1; |
} |
if (d->blink > 0) { |
d->blink -= 1; |
} |
} |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 56; |
mask.h = 56; |
mask = updateDodoMask(d, mask); |
} |
//Idle |
if (d->state == 0) |
{ |
d->hsp = 0; |
d->vsp = 0; |
//Animate |
imgspd = 0.1; |
frames = 4; |
//End state |
if (d->timer <= 0) { |
//Go to chase |
if (d->tojump == 0) { |
d->state = 1; |
d->timer = 260; |
d->tojump = 1; |
} |
//Go to windup |
else { |
d->state = 3; |
d->timer = 30; |
} |
} |
//Fall |
{ |
if (d->onground == 0) { |
d->state = 6; |
d->imageIndex = 1; |
} |
} |
} |
//Chase |
else if (d->state == 1) |
{ |
//Animate |
imgspd = 0.2; |
frames = 4; |
//Chase |
if ( (d->dir == -1 && herox < d->x) || (d->dir == 1 && herox > d->x) ) { |
d->hsp += (fric / 2) * d->dir; |
//limit speed |
if (d->hsp > 3) { |
d->hsp = 3; |
} |
if (d->hsp < -3) { |
d->hsp = -3; |
} |
} |
//Turn around |
else{ |
d->hsp -= fric * d->dir; |
//Done slowing down |
if ( (d->dir == 1 && d->hsp <= 0) || (d->dir == -1 && d->hsp >= 0) ) { |
d->hsp = 0; |
d->state = 4; |
d->imageIndex = 0; |
} |
} |
//Stop running |
{ |
if (d->timer <= 0) { |
if (d->hsp >= 1 || d->hsp <= -1) { |
d->state = 5; |
} |
} |
} |
//Fall |
{ |
if (d->onground == 0) { |
d->state = 6; |
d->imageIndex = 1; |
} |
} |
} |
//Turn around |
else if (d->state == 4) |
{ |
//Animate |
imgspd = 0; |
d->imageIndex += 0.2; |
//Done turning around |
if (d->imageIndex >= 3) { |
d->dir *= -1; |
d->state = 1; |
d->imageIndex = 0; |
} |
//Fall |
{ |
if (d->onground == 0) { |
d->state = 6; |
d->imageIndex = 1; |
} |
} |
} |
//Jump |
if (d->state == 2) |
{ |
//Set image |
imgspd = 0; |
{ |
//Fall |
d->imageIndex = 0; |
//Jump |
if (d->vsp < 0) { |
d->imageIndex = 1; |
} |
} |
//Face hsp |
{ |
if (d->hsp > 0) { |
d->dir = 1; |
} |
if (d->hsp < 0) { |
d->dir = -1; |
} |
} |
//Land |
{ |
if (d->onground == 1) { |
d->state = 5; |
d->tojump = 0; |
PHL_PlaySound(sounds[sndHit04], CHN_ENEMIES); |
quakeTimer = 30; |
createEffectExtra(3, d->x - 30, d->y + 50, -1, 0, 0); |
createEffectExtra(3, d->x - 10, d->y + 50, 1, 0, 0); |
} |
} |
} |
//Windup |
if (d->state == 3) |
{ |
//Set image |
imgspd = 0; |
d->imageIndex = 0; |
//Jump |
if (d->timer <= 0) { |
d->state = 2; |
PHL_PlaySound(sounds[sndJump01], CHN_ENEMIES); |
if (d->jumptoggle == 0) { |
d->jumptoggle = 1; |
d->vsp = -3; |
d->hsp = 2 * d->dir; |
}else{ |
d->jumptoggle = 0; |
d->hsp = 1.5 * d->dir; |
d->vsp = -6; |
} |
} |
} |
//Slide to a stop |
else if (d->state == 5) |
{ |
//Friction |
{ |
if (d->hsp > 0) { |
d->hsp -= fric; |
if (d->hsp <= 0) { |
d->hsp = 0; |
} |
} |
else if (d->hsp < 0) { |
d->hsp += fric; |
if (d->hsp >= 0) { |
d->hsp = 0; |
} |
} |
} |
//Go to idle |
{ |
if (d->hsp == 0) { |
d->state = 0; |
d->timer = 140; |
} |
} |
} |
//Fall |
if (d->state == 6) |
{ |
//Set image |
imgspd = 0; |
d->imageIndex = 0; |
//Face hsp |
{ |
if (d->hsp > 0) { |
d->dir = 1; |
} |
if (d->hsp < 0) { |
d->dir = -1; |
} |
} |
//Land |
{ |
if (d->onground == 1) { |
d->state = 5; |
d->tojump = 1; |
} |
} |
} |
//Death |
if (d->state == 7) |
{ |
imgspd = 0.2; |
frames = 4; |
//Movement |
d->y += 0.2; |
if (d->blink % 12 == 0) { |
createEffect(2, d->x - 72 + (rand() % 80), d->y - 12 + (rand() % 76)); |
} |
if (d->blink <= 0) { |
dead = 1; |
} |
} |
else{ |
//Horizontal movement |
{ |
if (d->hsp != 0) { |
d->x += d->hsp; |
//Wall collision |
if (d->state != 6) { |
if (dodoWallCollision(d, mask) == 1) { |
d->hsp *= -1; |
if (d->state == 1) { |
d->state = 5; |
} |
} |
} |
} |
} |
//Vertical movement |
{ |
if (d->vsp != 0) { |
d->y += d->vsp; |
mask = updateDodoMask(d, mask); |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
if (d->vsp < 0) { |
d->y = collide.y + 40 - (96 - 14 - mask.h); |
} |
else if (d->vsp > 0) { |
d->y = collide.y - 96 + 14; |
} |
} |
} |
} |
//Check if onground |
mask = updateDodoMask(d, mask); |
mask.y += 1; |
if (!checkTileCollision(1, mask)) { |
d->onground = 0; |
}else{ |
d->onground = 1; |
} |
mask.y -= 1; |
//Gravity |
{ |
if (d->onground == 0) { |
d->vsp += d->grav; |
} |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
//Hit |
d->blink = 15; |
d->hp -= 1; |
//Death |
if (d->hp <= 0) { |
d->state = 7; |
d->blink = 180; |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
//Hit Player |
{ |
if (checkCollision(mask, getHeroMask())) { |
heroHit(30, d->x); |
} |
} |
} |
//Animate |
{ |
if (imgspd != 0) { |
d->imageIndex += imgspd; |
if (d->imageIndex >= frames) { |
d->imageIndex -= frames; |
} |
} |
} |
//Destroy object |
{ |
if (dead == 1) { |
//Is the level 1 boss |
if (d->flag == boss1flag) { |
bossDefeatedFlag = 1; |
PHL_StopMusic(); |
} |
roomSecret = 1; |
flags[d->flag] = 1; |
enemyDestroy(d->id); |
} |
} |
} |
void dodoDraw(Dodo* d) |
{ |
//PHL_DrawMask(d->mask); |
if (d->blink % 2 == 0) { |
int cropX = 0, |
cropY = 0; |
int dirW = 0; |
//Idle |
if (d->state == 0) { |
dirW = 0; |
int frame = 0; |
if (d->dir == 1) { |
int animation[4] = {0, 6, 7, 6}; |
frame = animation[(int)d->imageIndex]; |
}else{ |
int animation[4] = {3, 8, 9, 8}; |
frame = animation[(int)d->imageIndex]; |
} |
cropX = frame * 96; |
while (cropX >= 576) { |
cropX -= 576; |
cropY += 96; |
} |
} |
//Chase |
else if (d->state == 1 || d->state == 7) { |
dirW = 288; |
int animation[4] = {0, 1, 0, 2}; |
cropX = animation[(int)d->imageIndex] * 96; |
} |
//Jump |
else if (d->state == 2) { |
dirW = 192; |
cropY = 192; |
cropX = (int)d->imageIndex * 96; |
} |
//Turn around |
else if (d->state == 4) { |
dirW = 0; |
cropY = 288; |
if (d->dir == 1) { |
int animation[3] = {0, 1, 2}; |
cropX = animation[(int)d->imageIndex] * 96; |
}else{ |
int animation[3] = {2, 1, 0}; |
cropX = animation[(int)d->imageIndex] * 96; |
} |
} |
//Duck |
else if (d->state == 3 || d->state == 5 || d->state == 6) { |
dirW = 192; |
cropX = 0; |
cropY = 192; |
} |
//Direction offset |
{ |
if (dirW != 0 && d->dir == -1) { |
cropX += dirW; |
} |
} |
PHL_DrawSurfacePart(d->x - 48, d->y, cropX, cropY, 96, 96, images[imgBoss]); |
} |
} |
Mask updateDodoMask(Dodo* d, Mask mask) |
{ |
mask.x = d->x - (mask.w / 2); |
mask.y = d->y + (96 - 14 - mask.h); |
return mask; |
} |
int dodoWallCollision(Dodo* d, Mask mask) |
{ |
int result = 0; |
mask = updateDodoMask(d, mask); |
//Stay inside of room |
if (d->x < 24) { |
result = 1; |
d->x = 24; |
} |
else if (d->x > 616) { |
result = 1; |
d->x = 616; |
} |
else{ |
//Tile collision |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
result = 1; |
if (d->hsp > 0) { |
d->x = collide.x - (mask.w / 2); |
}else{ |
d->x = collide.x + 40 + (mask.w / 2); |
} |
} |
} |
return result; |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/dodo.h |
---|
0,0 → 1,22 |
#ifndef DODO_H |
#define DODO_H |
#include "../collision.h" |
typedef struct { |
int id; |
double x, y; |
double vsp, hsp, grav; |
int dir, onground; |
double imageIndex; |
int state, timer, hp; |
int blink; |
int tojump, jumptoggle; |
int flag; |
//Mask mask; |
} Dodo; |
void createDodo(int x, int y, int flag); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/dog.c |
---|
0,0 → 1,294 |
#include "dog.h" |
#include "../game.h" |
#include "../hero.h" |
#include <stdlib.h> |
void dogStep(Dog* d); |
void dogDraw(Dog* d); |
int hitWall(Dog* d, Mask mask); |
void createDog(int x, int y) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Dog* d = malloc(sizeof *d); |
d->id = i; |
d->hp = 3; |
d->blink = 0; |
d->x = x; |
d->y = y; |
d->hsp = 0; |
d->vsp = 0; |
d->imageIndex = 0; |
d->dir = 1; |
if (herox < d->x) { |
d->dir = -1; |
} |
d->state = 0; |
d->timer = 0; |
d->counter = 0; |
e->data = d; |
e->enemyStep = dogStep; |
e->enemyDraw = dogDraw; |
e->type = 30; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void dogStep(Dog* d) |
{ |
double grav = 0.175; |
char onground = 0; |
char wallhit = 0; |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 32; |
mask.h = 32; |
mask.x = d->x + ((40 - mask.w) / 2); |
mask.y = d->y + (40 - mask.h); |
} |
//Blink animation |
{ |
if (d->blink > 0) { |
d->blink -= 1; |
} |
} |
//Horizontal movement |
{ |
d->x += d->hsp; |
mask.x = d->x + ((40 - mask.w) / 2); |
//Wall collision |
if (hitWall(d, mask) == 1) { |
wallhit = 1; |
mask.x = d->x + ((40 - mask.w) / 2); |
} |
} |
//Vertical Movement |
{ |
d->vsp += grav; |
d->y += d->vsp; |
mask.y = d->y + (40 - mask.h); |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x != -1) { |
//Floor |
if (d->vsp >= 0) { |
onground = 1; |
d->vsp = 0; |
d->y = collide.y - 40; |
} |
//Ceiling |
if (d->vsp < 0) { |
d->y = collide.y + 40 - (40 - mask.h); |
} |
mask.y = d->y + (40 - mask.h); |
} |
} |
//Wait |
if (d->state == 0) |
{ |
double fric = 0.1; |
//Animate |
{ |
d->imageIndex += 0.1; |
if (d->imageIndex >= 2) { |
d->imageIndex -= 2; |
} |
} |
//Collide with wall |
{ |
if (wallhit == 1 && onground == 1) { |
d->hsp *= -1; |
} |
} |
//Slide to hault |
if (d->hsp > 0) { |
d->dir = 1; |
d->hsp -= fric; |
if (d->hsp <= 0) { |
d->hsp = 0; |
} |
} |
if (d->hsp < 0) { |
d->dir = -1; |
d->hsp += fric; |
if (d->hsp >= 0) { |
d->hsp = 0; |
} |
} |
//Player is close |
{ |
if (d->hsp == 0) { |
Mask area; |
area.unused = area.circle = 0; |
area.w = 220; |
area.h = 60; |
area.x = d->x - 90; |
area.y = d->y - 20; |
if (checkCollision(area, getHeroMask()) == 1) { |
d->state = 1; |
d->counter = 0; |
d->vsp = 1; |
} |
} |
} |
} |
//Hopping |
else if (d->state == 1) |
{ |
int spd = 2; |
d->hsp = spd * d->dir; |
//Land on floor |
{ |
if (onground == 1) { |
//Landed |
d->counter += 1; |
d->vsp = -1.5; |
if (d->counter == 3) { |
d->vsp = -4; |
} |
if (d->counter == 4) { |
d->state = 0; |
d->counter = 0; |
d->vsp = 0; |
d->hsp = spd * d->dir; |
}else{ |
PHL_PlaySound(sounds[sndPi05], CHN_ENEMIES); |
d->dir = 1; |
if (herox < d->x + 20) { |
d->dir = -1; |
} |
} |
} |
} |
//Animate |
{ |
d->imageIndex = 1; |
if (d->vsp < 0) { |
d->imageIndex = 2; |
} |
} |
} |
//Update mask to be safe |
mask.x = d->x + ((40 - mask.w) / 2); |
mask.y = d->y + (40 - mask.h); |
//Hit Player |
{ |
if (checkCollision(mask, getHeroMask())) { |
if (heroHit(10, mask.x + (mask.w / 2)) == 1) { |
heroStun(); |
} |
} |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
//Hit |
d->blink = 15; |
d->hp -= 1; |
//Death |
if (d->hp <= 0) { |
createEffect(2, d->x - 12, d->y - 6); |
spawnCollectable(d->x + 20, d->y); |
enemyDestroy(d->id); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
} |
void dogDraw(Dog* d) |
{ |
if (d->blink % 2 == 0) { |
int cropX = 240 + ((int)d->imageIndex * 40); |
if (d->dir == -1) { |
cropX += 120; |
} |
PHL_DrawSurfacePart(d->x, d->y, cropX, 40, 40, 40, images[imgEnemies]); |
} |
} |
int hitWall(Dog* d, Mask mask) |
{ |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x != -1) { |
int dir = 1; |
if (d->hsp < 0) { |
dir = -1; |
} |
d->x = collide.x + 20 - ((20 + (mask.w / 2)) * dir) - 20; |
return 1; |
}else{ |
if (d->x < -20) { |
d->x = -20; |
return 1; |
} |
if (d->x > 620) { |
d->x = 620; |
return 1; |
} |
} |
return 0; |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/dog.h |
---|
0,0 → 1,17 |
#ifndef DOG_H |
#define DOG_H |
typedef struct { |
int id; |
int hp; |
int blink; |
double x, y; |
double vsp, hsp; |
double imageIndex; |
int dir; |
int state, timer, counter; |
} Dog; |
void createDog(int x, int y); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/firewheel.c |
---|
0,0 → 1,272 |
#include "firewheel.h" |
#include "../game.h" |
#include "../PHL.h" |
#include "../hero.h" |
#include <stdlib.h> |
void firewheelRotate(Firewheel* f, int clockwise); |
void firewheelStep(Firewheel* f); |
void firewheelDraw(Firewheel* f); |
void createFirewheel(int x, int y, int dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Firewheel* f = malloc(sizeof *f); |
f->id = i; |
f->x = x; |
f->y = y; |
f->imageIndex = 0; |
f->hp = 2; |
f->blink = 0; |
f->hsp = 1; |
f->vsp = 0; |
f->wallx = 0; |
f->wally = 1; |
f->timer = 0; |
if (x % 40 != 0) { |
f->timer = 20; |
} |
//Start on ceiling |
{ |
Mask mask; |
mask.circle = mask.unused = 0; |
mask.w = 40; |
mask.h = 40; |
mask.x = f->x; |
mask.y = f->y + 10; |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x == -1) { |
f->wally = -1; |
f->hsp *= -1; |
} |
} |
f->dir = 1; |
if (dir == 1) { |
f->hsp *= -1; |
f->dir = -1; |
} |
e->data = f; |
e->enemyStep = firewheelStep; |
e->enemyDraw = firewheelDraw; |
e->type = 27; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void firewheelStep(Firewheel* f) |
{ |
//Animate |
{ |
f->imageIndex += 0.33; |
if (f->imageIndex >= 4) { |
f->imageIndex -= 4; |
} |
if (f->blink > 0) { |
f->blink -= 1; |
} |
} |
//Movement |
int spd = 2; |
f->x += spd * f->hsp; |
f->y += spd * f->vsp; |
//Setup mask |
Mask mask; |
mask.circle = mask.unused = 0; |
mask.w = 40; |
mask.h = 40; |
mask.x = f->x; |
mask.y = f->y; |
//Check if ready to change angle |
if ( (f->hsp != 0 && (int)f->x % 20 == 0) || (f->vsp != 0 && (int)f->y % 20 == 0) ) |
{ |
int doCheck = 1; |
while (doCheck == 1) { |
doCheck = 0; |
//Check on edge |
mask.x += (f->wallx * 10); |
mask.y += (f->wally * 10); |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
//Outside of room |
if (f->y <= -40) { |
collide.x = 1; |
} |
//On edge |
if (collide.x == -1) { |
int tempHsp = f->hsp; |
int tempVsp = f->vsp; |
f->hsp = f->wallx; |
f->vsp = f->wally; |
f->wallx = -tempHsp; |
f->wally = -tempVsp; |
doCheck = 1; |
} |
//Hit wall |
else { |
mask.x = f->x; |
mask.y = f->y; |
mask.x += f->hsp * 10; |
mask.y += f->vsp * 10; |
collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
//Outside of room |
if (collide.x == -1) { |
if (f->y <= -40 && f->vsp != 1) { |
collide.x = 1; |
} |
} |
//Did collide with wall |
if (collide.x != -1) { |
int tempWallx = f->wallx; |
int tempWally = f->wally; |
f->wallx = f->hsp; |
f->wally = f->vsp; |
f->hsp = -tempWallx; |
f->vsp = -tempWally; |
doCheck = 1; |
} |
} |
} |
/* |
mask.x += f->hsp * 10; |
mask.y += f->vsp * 10; |
//Collide with wall |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
//Outside of room |
if (collide.x == -1) { |
if (mask.y <= 0 && f->vsp < 0) { |
collide.x = f->x; |
collide.y = -40; |
collide.w = 40; |
collide.h = 40; |
} |
} |
//Did collide with wall |
if (collide.x != -1) { |
int tempWallx = f->wallx; |
int tempWally = f->wally; |
f->wallx = f->hsp; |
f->wally = f->vsp; |
f->hsp = -tempWallx; |
f->vsp = -tempWally; |
} |
//Edge rotate |
else{ |
mask.x = f->x; |
mask.y = f->y; |
mask.x += (f->wallx * 10); |
mask.y += (f->wally * 10); |
collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x == -1) { |
int tempHsp = f->hsp; |
int tempVsp = f->vsp; |
f->hsp = f->wallx; |
f->vsp = f->wally; |
f->wallx = -tempHsp; |
f->wally = -tempVsp; |
} |
} |
*/ |
} |
//Update Mask |
mask.w = 30; |
mask.h = 30; |
mask.x = f->x + 5; |
mask.y = f->y + 5; |
//Collide with hero |
if (checkCollision(mask, getHeroMask())) { |
heroHit(20, mask.x + (mask.w / 2)); |
} |
//Weapon collision |
for (int i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
f->hp -= 1; |
f->blink = 15; |
//Death |
if (f->hp <= 0) { |
createEffect(2, f->x - 12, f->y - 12); |
spawnCollectable(f->x + 20, f->y); |
enemyDestroy(f->id); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
void firewheelDraw(Firewheel* f) |
{ |
if (f->blink % 2 == 0) { |
int cy = 80; |
if (f->dir == -1) { |
cy += 40; |
} |
PHL_DrawSurfacePart(f->x, f->y, 480 + ((int)f->imageIndex * 40), cy, 40, 40, images[imgEnemies]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/firewheel.h |
---|
0,0 → 1,18 |
#ifndef FIREWHEEL_H |
#define FIREWHEEL_H |
typedef struct { |
int id; |
double x, y; |
double imageIndex; |
int hp; |
int blink; |
int dir; |
int hsp, vsp; |
int wallx, wally; |
int timer; |
} Firewheel; |
void createFirewheel(int x, int y, int dir); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/fish.c |
---|
0,0 → 1,139 |
#include "fish.h" |
#include "../game.h" |
#include "../enemy.h" |
#include "../PHL.h" |
#include "../collision.h" |
#include "../hero.h" |
#include <stdlib.h> |
void createFish(int x, int y, int dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Fish* f = malloc(sizeof *f); |
f->id = i; |
f->x = f->xstart = x; |
f->y = y; |
f->imageIndex = 0; |
f->spd = 1; |
f->turning = 0; |
f->dir = 1; |
if (dir == 1) { |
f->dir = -1; |
f->spd = -1; |
} |
f->mask.circle = f->mask.unused = 0; |
f->mask.x = x + 3; |
f->mask.y = y + 6; |
f->mask.w = 34; |
f->mask.h = 32; |
e->data = f; |
e->enemyStep = fishStep; |
e->enemyDraw = fishDraw; |
e->type = 13; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void fishStep(Fish* f) |
{ |
double fric = 0.02; |
f->x += f->spd; |
f->mask.x = f->x + 3; |
if (f->turning == 0) { |
f->imageIndex += 0.1; |
if (f->imageIndex >= 2) { |
f->imageIndex -= 2; |
} |
}else{ |
f->imageIndex += 0.25; |
if (f->imageIndex >= 3) { |
f->turning = 0; |
} |
} |
if (f->dir == 1) { |
if (f->x > f->xstart + 25) { |
f->spd -= fric; |
if (f->spd < 0) { |
f->dir = -1; |
f->turning = 1; |
f->imageIndex = 0; |
} |
}else{ |
f->spd += fric; |
if (f->spd > 1) { |
f->spd = 1; |
} |
} |
}else if (f->dir == -1) { |
if (f->x < f->xstart - 25) { |
f->spd += fric; |
if (f->spd > 0) { |
f->dir = 1; |
f->turning = 1; |
f->imageIndex = 0; |
} |
}else{ |
f->spd -= fric; |
if (f->spd < -1) { |
f->spd = -1; |
} |
} |
} |
if (checkCollision(f->mask, getHeroMask())) { |
heroHit(15, f->x + 20); |
} |
//Weapon collision |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (checkCollision(f->mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
createEffect(2, f->x - 12, f->y - 12); |
spawnCollectable(f->x + 20, f->y); |
enemyDestroy(f->id); |
i = MAX_WEAPONS; |
} |
} |
} |
} |
void fishDraw(Fish* f) |
{ |
int thisImage = 0; |
if (f->turning == 1) { |
if (f->dir == -1) { |
int animation[3] = {4, 6, 5}; |
thisImage = animation[(int)f->imageIndex]; |
}else{ |
int animation[3] = {5, 6, 4}; |
thisImage = animation[(int)f->imageIndex]; |
} |
}else{ |
thisImage = f->imageIndex; |
if (f->spd < 0) { |
thisImage += 2; |
} |
} |
PHL_DrawSurfacePart(f->x, f->y, 360 + (thisImage * 40), 360, 40, 40, images[imgEnemies]); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/fish.h |
---|
0,0 → 1,24 |
#ifndef FISH_H |
#define FISH_H |
#include "../enemy.h" |
#include "../collision.h" |
typedef struct { |
int id; |
double x, y; |
int xstart; |
double imageIndex; |
double spd; |
int dir, turning; |
Mask mask; |
} Fish; |
void createFish(int x, int y, int dir); |
void fishStep(Fish* f); |
void fishDraw(Fish* f); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/garm.c |
---|
0,0 → 1,578 |
#include "garm.h" |
#include "../game.h" |
#include "../PHL.h" |
#include "../hero.h" |
#include <stdlib.h> |
int boss7flag = 47; |
void garmStep(Garm* g); |
void garmDraw(Garm* g); |
void garmrockStep(Garmrock* g); |
void garmrockDraw(Garmrock* g); |
void createGarm(int x, int y) |
{ |
if (flags[boss7flag] == 0) { //have not beaten boss 7 |
PHL_FreeSurface(images[imgBoss]); |
images[imgBoss] = PHL_LoadQDA("boss07.bmp"); |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
setBossRoom(); |
Enemy* e = malloc(sizeof *e); |
Garm* g = malloc(sizeof *g); |
g->id = i; |
g->hp = 105; |
//g->hp = 1; |
g->x = x; |
g->y = y; |
g->hsp = 0; |
g->vsp = 0; |
g->dir = -1; |
g->imageIndex = 0; |
g->state = 0; |
g->timer = 0; |
g->blink = 0; |
g->substate = 0; |
g->wallcounter = 0; |
g->targx = 0; |
e->data = g; |
e->enemyStep = garmStep; |
e->enemyDraw = garmDraw; |
e->type = 46; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
} |
void garmStep(Garm* g) |
{ |
char dead = 0; |
//Blink animation |
{ |
if (g->blink > 0) { |
g->blink -= 1; |
} |
} |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 88; |
mask.h = 104; |
mask.x = g->x - (mask.w / 2); |
mask.y = g->y + (120 - mask.h); |
} |
//Stand still |
if (g->state == 0) |
{ |
//Animate |
{ |
g->imageIndex += 0.0625; |
if (g->imageIndex >= 2) { |
g->imageIndex -= 2; |
} |
} |
//End state |
{ |
g->timer += 1; |
if (g->timer >= 60) { |
g->state = 1; |
//g->vsp = -4.5; |
g->counter = 0; |
g->timer = 0; |
//PHL_PlaySound(sounds[sndPi09], CHN_ENEMIES); |
} |
} |
} |
//Bounce |
else if (g->state == 1) |
{ |
//Animate |
{ |
g->imageIndex += 0.33; |
if (g->imageIndex >= 3) { |
g->imageIndex -= 3; |
} |
} |
if (g->timer > 0) { |
g->vsp = 0; |
g->imageIndex = 0; |
g->timer -= 1; |
if (g->timer <= 0) { |
//End state |
if (g->counter >= 3) { |
g->state = 2; |
g->counter = 0; |
g->imageIndex = 0; |
g->vsp = -6; |
g->hsp = 8; |
if (g->x > herox) { |
g->hsp *= -1; |
} |
if (g->substate == 0) { |
g->wallcounter = 1; |
g->substate = 1; |
}else{ |
g->wallcounter = 2; |
g->substate = 0; |
} |
}else{ |
g->vsp = -5; |
} |
} |
} |
else if (g->timer == 0) { |
double grav = 0.25; |
//Movement |
if (g->timer == 0) { |
g->y += g->vsp; |
g->vsp += grav; |
mask.y = g->y + (120 - mask.h); |
} |
//Land on ground |
if (g->vsp >= 0 && g->timer == 0) { |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
g->y = collide.y - 120; |
mask.y = g->y + (120 - mask.h); |
g->vsp = 0; |
g->timer = 3; |
g->counter += 1; |
PHL_PlaySound(sounds[sndPi09], CHN_ENEMIES); |
} |
} |
} |
} |
//Leap towards wall |
else if (g->state == 2) |
{ |
double grav = 0.25; |
//Set image |
{ |
if (g->hsp > 0) { |
g->imageIndex = 0; |
} |
if (g->hsp < 0) { |
g->imageIndex = 1; |
} |
} |
//Movement |
{ |
g->y += g->vsp; |
g->vsp += grav; |
mask.y = g->y + (120 - mask.h); |
g->x += g->hsp; |
mask.x = g->x - (mask.w / 2); |
} |
if (g->wallcounter > 0) |
{ |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
g->wallcounter -= 1; |
if (g->hsp < 0) { |
g->x = collide.x + 40 + (mask.w / 2); |
} |
if (g->hsp > 0) { |
g->x = collide.x - (mask.w / 2); |
} |
g->state = 3; |
g->timer = 0; |
} |
} |
//Ground pound |
else { |
char action = 0; |
if ( (g->hsp > 0 && g->x > g->targx) || (g->hsp < 0 && g->x < g->targx) ) { |
action = 1; |
} |
//Wall collision backup |
else{ |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
if (g->hsp < 0) { |
g->x = collide.x + 40 + (mask.w / 2); |
} |
if (g->hsp > 0) { |
g->x = collide.x - (mask.w / 2); |
} |
action = 1; |
} |
} |
if (action == 1) { |
g->state = 4; |
g->vsp = -4; |
PHL_PlaySound(sounds[sndWolf01], CHN_ENEMIES); |
} |
} |
} |
//Grab wall |
else if (g->state == 3) |
{ |
g->timer += 1; |
if (g->timer > 5) { |
g->state = 2; |
g->vsp = -6; |
g->hsp *= -1; |
PHL_PlaySound(sounds[sndPi09], CHN_ENEMIES); |
g->targx = herox; |
if (g->wallcounter <= 0) { |
//Get distance from player |
int dis = g->x - g->targx; |
{ |
if (dis < 0) { |
dis *= -1; |
} |
} |
if (dis < 200 || g->substate == 1) { |
g->hsp /= 2; |
} |
} |
} |
} |
//Ground pound |
else if (g->state == 4) |
{ |
double grav = 0.2; |
//Animate |
{ |
g->imageIndex += 0.33; |
if (g->imageIndex >= 3) { |
g->imageIndex -= 3; |
} |
} |
g->y += g->vsp; |
g->vsp += grav; |
mask.y = g->y + (120 - mask.h); |
//Collide with floor |
{ |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
g->y = collide.y - 120; |
PHL_PlaySound(sounds[sndHit04], CHN_ENEMIES); |
quakeTimer = 30; |
g->state = 0; |
g->timer = -20; |
//Create rocks |
createGarmrock(g->x + 64, g->y + 100, 2, -4); |
createGarmrock(g->x + 34, g->y + 100, 1, -5); |
createGarmrock(g->x - 34, g->y + 100, -1, -5); |
createGarmrock(g->x - 64, g->y + 100, -2, -4); |
createEffectExtra(3, g->x - 50, g->y + 90, -1, 0, 0); |
createEffectExtra(3, g->x + 10, g->y + 90, 1, 0, 0); |
} |
} |
} |
//Dead |
if (g->state == 5) { |
//Animate |
{ |
g->imageIndex += 0.33; |
if (g->imageIndex >= 3) { |
g->imageIndex -= 3; |
} |
} |
g->y += 0.2; |
if (g->blink % 12 == 0) { |
createEffect(2, g->x - 64 + (rand() % 100), g->y + 60 - 64 + (rand() % 80)); |
} |
if (g->blink <= 0) { |
dead = 1; |
} |
} |
else{ |
if (dead == 0) { |
//Update Mask |
{ |
mask.x = g->x - (mask.w / 2); |
mask.y = g->y + (120 - mask.h); |
} |
//Hero collision |
{ |
if (checkCollision(getHeroMask(), mask) == 1) { |
heroHit(40, mask.x + (mask.w / 2)); |
} |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
g->hp -= 1; |
g->blink = 15; |
//Dead |
if (g->hp <= 0) { |
g->state = 5; |
g->blink = 200; |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
} |
} |
if (dead == 1) { |
//Destroy |
{ |
enemyDestroy(g->id); |
bossDefeatedFlag = 1; |
roomSecret = 1; |
flags[boss7flag] = 1; |
PHL_StopMusic(); |
} |
} |
} |
void garmDraw(Garm* g) |
{ |
if (g->blink % 2 == 0) { |
int cropX = 0, |
cropY = 0; |
//Jump Spinning |
if ((g->state == 1 && g->timer == 0) || g->state == 4 || g->state == 5) { |
cropY = 128; |
cropX = 256; |
} |
//Jump |
if (g->state == 2) { |
cropY = 128; |
} |
//Wall grab |
if (g->state == 3) { |
cropX = 384; |
} |
cropX += (int)g->imageIndex * 128; |
PHL_DrawSurfacePart(g->x - 64, g->y - 8, cropX, cropY, 128, 128, images[imgBoss]); |
} |
} |
//Rocks |
void createGarmrock(int x, int y, double hsp, double vsp) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Garmrock* g = malloc(sizeof *g); |
g->id = i; |
g->hp = 3; |
g->x = x; |
g->y = y; |
g->hsp = hsp; |
g->vsp = vsp; |
g->imageIndex = 0; |
g->counter = 0; |
g->inwall = 0; |
g->blink = 0; |
e->data = g; |
e->enemyStep = garmrockStep; |
e->enemyDraw = garmrockDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void garmrockStep(Garmrock* g) |
{ |
char dead = 0; |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 44; |
mask.h = 44; |
mask.x = g->x - (mask.w / 2); |
mask.y = g->y - (mask.h / 2); |
} |
//Animate |
{ |
g->imageIndex += 0.2; |
if (g->imageIndex >= 4) { |
g->imageIndex -= 4; |
} |
if (g->blink > 0) { |
g->blink -= 1; |
} |
} |
//Horizontal movement |
{ |
g->x += g->hsp; |
mask.x = g->x - (mask.w / 2); |
g->inwall = 0; |
if (checkTileCollision(1, mask) == 1) { |
g->inwall = 1; |
} |
} |
//Vertical movement |
{ |
double grav = 0.1; |
g->y += g->vsp; |
g->vsp += grav; |
mask.y = g->y - (mask.h / 2); |
if (g->inwall == 0 && g->counter == 0) { |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
g->counter = 1; |
g->y = collide.y - (mask.h / 2); |
g->vsp = -2; |
PHL_PlaySound(sounds[sndHit06], CHN_ENEMIES); |
} |
} |
} |
//Update mask |
{ |
mask.x = g->x - (mask.w / 2); |
mask.y = g->y - (mask.h / 2); |
} |
//Hero collision |
{ |
if (checkCollision(getHeroMask(), mask) == 1) { |
heroHit(30, mask.x + (mask.w / 2)); |
} |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
g->hp -= 1; |
g->blink = 15; |
if (g->hp <= 0) { |
dead = 1; |
createRockSmash(g->x, g->y + 20); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
//Destroy when out of room |
{ |
if (mask.y > 480) { |
dead = 1; |
} |
} |
//Destroy object |
{ |
if (dead == 1) { |
enemyDestroy(g->id); |
} |
} |
} |
void garmrockDraw(Garmrock* g) |
{ |
if (g->blink % 2 == 0) { |
int cropX = 256, |
cropY = 192; |
if (g->hsp < 0) { |
cropX = 512; |
} |
cropX += (int)g->imageIndex * 64; |
while (cropX >= 640) { |
cropX -= 640; |
cropY += 64; |
} |
PHL_DrawSurfacePart(g->x - 32, g->y - 32, cropX, cropY, 64, 64, images[imgMisc32]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/garm.h |
---|
0,0 → 1,31 |
#ifndef GARM_H |
#define GARM_H |
typedef struct { |
int id; |
int hp; |
double x, y; |
double hsp, vsp; |
int dir; |
double imageIndex; |
int state, timer, blink, counter; |
int wallcounter, substate; |
int targx; |
} Garm; |
void createGarm(int x, int y); |
typedef struct { |
int id; |
int hp; |
double x, y; |
double vsp, hsp; |
double imageIndex; |
int counter; |
int blink; |
int inwall; |
} Garmrock; |
void createGarmrock(int x, int y, double hsp, double vsp); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/gas.c |
---|
0,0 → 1,116 |
#include "gas.h" |
#include "../PHL.h" |
#include "../game.h" |
#include "../hero.h" |
#include <stdlib.h> |
void gasStep(Gas* g); |
void gasDraw(Gas* g); |
void createGas(int x, int y, int temp) |
{ |
if (temp == 0 || hasKey[7] == 0) { |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Gas* g = malloc(sizeof *g); |
g->id = i; |
g->x = x; |
g->y = y; |
g->state = 0; |
g->timer = 0; |
g->imageIndex = 0; |
/* |
g->mask.unused = g->mask.circle = 0; |
g->mask.w = g->mask.h = 24; |
g->mask.x = x + 20 - (g->mask.w / 2); |
g->mask.y = y + 40 - g->mask.h; |
*/ |
e->data = g; |
e->enemyStep = gasStep; |
e->enemyDraw = gasDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
} |
void gasStep(Gas* g) |
{ |
if (g->state != 0) { |
g->imageIndex += 0.2; |
} |
if (g->state == 0) { //Wait |
Mask tempMask; |
tempMask.circle = tempMask.unused = 0; |
tempMask.x = g->x - 100; |
tempMask.y = g->y - 20; |
tempMask.w = 240; |
tempMask.h = 60; |
if (checkCollisionXY(tempMask, herox, heroy + 20)) { |
g->state = 1; |
g->imageIndex = 3; |
g->timer = 32; |
PHL_PlaySound(sounds[sndGas01], CHN_ENEMIES); |
} |
} |
else if (g->state == 1 || g->state == 3) { //Small puff |
if (g->imageIndex >= 5) { |
g->imageIndex -= 2; |
} |
g->timer -= 1; |
if (g->timer <= 0) { |
if (g->state == 3) { |
g->state = 0; |
}else{ |
g->state = 2; |
g->imageIndex = 0; |
g->timer = 175; |
} |
} |
} |
else if (g->state == 2) { //Big puff |
if (g->imageIndex >= 3) { |
g->imageIndex -= 3; |
} |
g->timer -= 1; |
if (g->timer <= 0) { |
g->state = 3; |
g->timer = 120; |
g->imageIndex = 3; |
} |
if (hasItem[7] != 1) { //Does not have gas mask |
Mask mask; |
mask.unused = mask.circle = 0; |
mask.w = mask.h = 24; |
mask.x = g->x + 20 - (mask.w / 2); |
mask.y = g->y + 40 - mask.h; |
if (checkCollision(getHeroMask(), mask)) { |
if (heroHit(15, g->x + 20)) { |
heroPoison(); |
} |
} |
} |
} |
} |
void gasDraw(Gas* g) |
{ |
if (g->state != 0) { |
PHL_DrawSurfacePart(g->x, g->y, (int)g->imageIndex * 40, 400, 40, 40, images[imgEnemies]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/gas.h |
---|
0,0 → 1,18 |
#ifndef GAS_H |
#define GAS_H |
//#include "../enemy.h" |
//#include "../collision.h" |
typedef struct { |
int id; |
int x, y; |
int state, timer; |
double imageIndex; |
//Mask mask; |
} Gas; |
void createGas(int x, int y, int temp); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/ghoul.c |
---|
0,0 → 1,218 |
#include "ghoul.h" |
#include "../game.h" |
#include "../enemy.h" |
#include "../PHL.h" |
#include "../hero.h" |
#include <stdlib.h> |
void ghoulStep(Ghoul* g); |
void ghoulDraw(Ghoul* g); |
void createGhoul(int x, int y, int type) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Ghoul* g = malloc(sizeof *g); |
g->id = i; |
g->hp = 2; |
g->x = x; |
g->y = y; |
g->vsp = 0; |
g->grav = 0.1; |
g->dir = 0; |
g->type = type; |
g->onground = 0; |
g->timer = 0; |
g->state = 0; |
g->invincible = 0; |
g->imageIndex = 0; |
g->mask.circle = 0; |
g->mask.unused = 1; |
g->mask.w = 24; |
g->mask.h = 32; |
g->mask.x = g->x + ((40 - g->mask.w) / 2); |
g->mask.y = g->y + (40 - g->mask.h); |
e->data = g; |
e->enemyStep = ghoulStep; |
e->enemyDraw = ghoulDraw; |
e->type = 18; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void ghoulStep(Ghoul* g) |
{ |
if (g->invincible > 0) { |
g->invincible -= 1; |
} |
if (g->state == 0) { //Wait |
Mask area; |
area.unused = area.circle = 0; |
area.w = 280; |
area.h = 80; |
area.x = g->x - 120; |
area.y = g->y - 20; |
if (checkCollisionXY(area, herox, heroy + 20) == 1) { |
g->state = 1; |
g->mask.unused = 0; |
g->imageIndex = 0; |
g->dir = 1; |
if (herox < g->x + 20) { |
g->dir = -1; |
} |
} |
} |
else if (g->state == 1) { //Pop-up |
g->imageIndex += 0.16; |
if (g->imageIndex >= 4) { |
g->state = 2; |
g->vsp = -1; |
g->imageIndex = 0; |
PHL_PlaySound(sounds[sndPi05],CHN_ENEMIES); |
} |
} |
else if (g->state == 2) { //Walking |
g->mask.unused = 0; |
if (g->onground == 0) { |
//Vertical movement |
g->y += g->vsp; |
g->vsp += g->grav; |
g->mask.y = g->y + (40 - g->mask.h); |
PHL_Rect collide = getTileCollision(1, g->mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, g->mask); |
} |
if (collide.x != -1) { |
g->onground = 1; |
g->vsp = 0; |
g->y = collide.y - 40; |
g->mask.y = g->y + (40 - g->mask.h); |
} |
} |
g->imageIndex += 0.1; |
if (g->imageIndex >= 2) { |
g->imageIndex -= 2; |
} |
double hsp = 1; |
if ((int)g->imageIndex == 0) { |
hsp = 0.5; |
} |
//Purple |
if (g->type == 1) { |
hsp *= 2; |
} |
g->x += hsp * g->dir; |
g->mask.x = g->x + ((40 - g->mask.w) / 2); |
if (g->onground == 1) { |
if ((g->x < -20 || g->x > 660) || checkTileCollision(1, g->mask) == 1) { |
g->dir *= -1; |
PHL_Rect collide = getTileCollision(1, g->mask); |
if (collide.x != -1) { |
g->x = collide.x + (40 * g->dir); |
} |
} |
else { |
//check on ledge |
g->mask.w = 5; |
if (g->dir == 1) { |
g->mask.x = g->x + 30; |
} |
if (g->dir == -1) { |
g->mask.x = g->x + 5; |
} |
g->mask.y += 20; |
if (checkTileCollision(1, g->mask) == 0 && checkTileCollision(3, g->mask) == 0) { |
g->dir *= -1; |
} |
g->mask.w = 24; |
g->mask.x = g->x + ((40 - g->mask.w) / 2); |
g->mask.y = g->y + (40 - g->mask.h); |
} |
} |
} |
g->mask.x = g->x + ((40 - g->mask.w) / 2); |
g->mask.y = g->y + (40 - g->mask.h); |
//Hit Player |
{ |
if (checkCollision(g->mask, getHeroMask())) { |
if (heroHit(10, g->x + 20) == 1 && g->type == 1) { |
heroPoison(); |
} |
} |
} |
//Weapon Collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(g->mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
g->hp -= 1; |
g->invincible = 15; |
//Death |
if (g->hp <= 0) { |
createEffect(2, g->x - 12, g->y - 6); |
spawnCollectable(g->x + 20, g->y); |
enemyDestroy(g->id); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
} |
void ghoulDraw(Ghoul* g) |
{ |
if (g->state != 0 && g->invincible % 2 == 0) { |
int cx = (int)g->imageIndex * 40, |
cy = 160; |
if (g->state == 1) { |
cx += 160; |
}else{ |
if (g->dir == -1) { |
cx += 80; |
} |
} |
//Purple palette |
cy += 160 * g->type; |
PHL_DrawSurfacePart(g->x, g->y, cx, cy, 40, 40, images[imgEnemies]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/ghoul.h |
---|
0,0 → 1,22 |
#ifndef GHOUL_H |
#define GHOUL_H |
#include "../collision.h" |
typedef struct { |
int id; |
int hp; |
double x, y; |
double vsp, grav; |
int type; |
int onground; |
int dir; |
int state, timer, invincible; |
double imageIndex; |
Mask mask; |
} Ghoul; |
void createGhoul(int x, int y, int type); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/golem.c |
---|
0,0 → 1,199 |
#include "golem.h" |
#include "../PHL.h" |
#include "../hero.h" |
#include "../game.h" |
#include <stdlib.h> |
void golemStep(Golem* g); |
void golemDraw(Golem* g); |
void createGolem(int x, int y, int dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Golem* g = malloc(sizeof *g); |
g->id = i; |
g->x = x; |
g->y = y; |
g->hp = 4; |
g->dir = 1; |
if (dir == 1) { |
g->dir = -1; |
} |
g->imageIndex = 0; |
g->state = 0; |
g->blink = 0; |
e->data = g; |
e->enemyStep = golemStep; |
e->enemyDraw = golemDraw; |
e->type = 28; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void golemStep(Golem* g) |
{ |
double imageSpeed = 0.2; |
//Timers |
{ |
if (g->blink > 0) { |
g->blink -= 1; |
} |
} |
//Setup Mask |
Mask mask; |
{ |
mask.unused = mask.circle = 0; |
mask.w = 36; |
mask.h = 36; |
mask.x = g->x + ((40 - mask.w) / 2); |
mask.y = g->y + (40 - mask.h); |
} |
//Rolling |
if (g->state == 0) |
{ |
//Animate |
{ |
g->imageIndex += imageSpeed * g->dir; |
if (g->imageIndex >= 8) { |
g->imageIndex -= 8; |
} |
if (g->imageIndex < 0) { |
g->imageIndex += 8; |
} |
} |
//Movement |
double hsp = 1; |
{ |
g->x += hsp * g->dir; |
mask.x = g->x + ((40 - mask.w) / 2); |
} |
char nextState = 0; |
//Check on ledge |
{ |
mask.x += 30 * g->dir; |
mask.y += 10; |
if (checkTileCollision(1, mask) == 0 && checkTileCollision(3, mask) == 0) { |
nextState = 1; |
} |
mask.x = g->x + ((40 - mask.w) / 2); |
mask.y = g->y + (40 - mask.h); |
} |
//Collide with wall |
{ |
mask.x += hsp * g->dir; |
if (checkTileCollision(1, mask) == 1) { |
nextState = 1; |
} |
mask.x = g->x + ((40 - mask.w) / 2); |
} |
if (nextState == 1) { |
PHL_PlaySound(sounds[sndPi10], CHN_ENEMIES); |
g->state = 1; |
g->imageIndex = 0; |
} |
} |
//Forming |
else if (g->state == 1) |
{ |
//Animate |
{ |
g->imageIndex += imageSpeed; |
if (g->imageIndex >= 12) { |
g->imageIndex = 0; |
g->state = 0; |
g->dir *= -1; |
} |
} |
} |
//Hero Collision |
{ |
if (checkCollision(mask, getHeroMask())) { |
heroHit(15, mask.x + (mask.w / 2)); |
} |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
//Tink |
if (g->state == 0) { |
PHL_PlaySound(sounds[sndHit03], CHN_WEAPONS); |
}else{ |
g->hp -= 1; |
g->blink = 15; |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
//Death |
{ |
if (g->hp <= 0) { |
createRockSmash(mask.x + (mask.w / 2), mask.y + (mask.h / 2)); |
spawnCollectable(g->x + 20, g->y); |
enemyDestroy(g->id); |
} |
} |
} |
void golemDraw(Golem* g) |
{ |
if (g->blink % 2 == 0) { |
int cropX = 320, |
cropY = 160; |
int drawY = g->y; |
if (g->state == 0) { |
cropX += (int)g->imageIndex * 40; |
drawY += 2; |
}else{ |
cropY = 280; |
cropX = 240; |
int animation[12] = {0, 1, 2, 3, 3, 3, 3, 3, 3, 2, 1, 0}; |
cropX += animation[(int)g->imageIndex] * 40; |
} |
PHL_DrawSurfacePart(g->x, drawY, cropX, cropY, 40, 40, images[imgEnemies]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/golem.h |
---|
0,0 → 1,16 |
#ifndef GOLEM_H |
#define GOLEM_H |
typedef struct { |
int id; |
double x, y; |
double imageIndex; |
int hp; |
int dir; |
int state; |
int blink; |
} Golem; |
void createGolem(int x, int y, int dir); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/gyra.c |
---|
0,0 → 1,332 |
#include "gyra.h" |
#include "../game.h" |
#include "../enemy.h" |
#include "../hero.h" |
#include <stdlib.h> |
#include <math.h> |
void gyraStep(Gyra* g); |
void gyraDraw(Gyra* g); |
void gyraDestroy(Gyra* g); |
int boss4flag = 21; |
void createGyra(int x, int y) |
{ |
if (flags[boss4flag] == 0) { //have not yet beaten boss 4 |
PHL_FreeSurface(images[imgBoss]); |
images[imgBoss] = PHL_LoadQDA("boss02.bmp"); |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
//Boss start |
setBossRoom(); |
Enemy* e = malloc(sizeof *e); |
Gyra* g = malloc(sizeof *g); |
g->id = i; |
g->hp = 50; |
//g->hp = 1; |
g->x = x; |
g->y = y; |
g->targx = g->x; |
g->targy = g->y; |
g->state = 0; |
g->timer = 260; |
g->counter = 0; |
g->invincible = 0; |
g->dir = 0; |
g->imageIndex = 0; |
//Setup |
g->targx = g->x - 32; |
g->targy = g->y + 64; |
g->dir = 160; |
g->x = g->targx + (80 * sin(g->dir * 3.14159 / 180)); |
g->y = g->targy + (80 * cos(g->dir * 3.14159 / 180)); |
int a; |
for (a = 0; a < 144; a++) { |
g->xrecord[a] = g->x; |
g->yrecord[a] = g->y; |
} |
e->data = g; |
e->enemyStep = gyraStep; |
e->enemyDraw = gyraDraw; |
e->type = 43; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
} |
void gyraStep(Gyra* g) |
{ |
//Animate |
g->imageIndex += 0.1; |
if (g->imageIndex >= 2) { |
g->imageIndex -= 2; |
} |
int pattern[6] = {0, 1, 2, 1, 0, 2}; |
//Move in a circle |
if (g->state == 0) |
{ |
int len = 80; |
//Setup |
if (g->timer == 0) { |
g->targx = g->x + (len * sin((g->dir + 90) * 3.14159 / 180)); |
g->targy = g->y + (len * cos((g->dir + 90) * 3.14159 / 180)); |
g->dir -= 90; |
g->timer = 250; |
} |
g->dir += 1.5; |
if (g->dir >= 360) { |
g->dir -= 360; |
} |
g->x = g->targx + (len * sin(g->dir * 3.14159 / 180)); |
g->y = g->targy + (len * cos(g->dir * 3.14159 / 180)); |
g->timer -= 1; |
if (g->timer <= 0) { |
g->counter += 1; |
g->state = pattern[g->counter]; |
/* |
if (g->state != 1 && (g->x < 40 || g->x > 600 || g->y < 40 || g->y > 440)) { |
g->state = 1; |
}*/ |
g->timer = 0; |
} |
} |
//Attack |
else if (g->state == 1) |
{ |
//Setup |
if (g->timer == 0) { |
g->targx = herox; |
g->targy = heroy + 20; |
g->dir += 90; |
g->timer = 320; |
} |
double spd = 2; |
double diralt = 1.2; |
double targdir = (atan2(g->targy - g->y, g->x - g->targx) * 180 / 3.14159) + 270; |
targdir = g->dir - targdir; |
while (targdir >= 360) { targdir -= 360; } |
while (targdir < 0) { targdir += 360; } |
if (targdir > 180) { |
g->dir += diralt; |
} |
if (targdir < 180) { |
g->dir -= diralt; |
} |
//Movement |
g->x += spd * sin(g->dir * 3.14159 / 180); |
g->y += spd * cos(g->dir * 3.14159 / 180); |
//Get (close) to targ coords |
g->timer -= 1; |
if (g->timer <= 0 || sqrt( pow(g->x - g->targx, 2) + pow(g->y - g->targy, 2) ) <= spd * 2) { |
g->counter += 1; |
if (g->counter >= 5) { |
g->counter = 0; |
} |
g->state = pattern[g->counter]; |
g->timer = 0; |
} |
} |
//Oval movement |
else if (g->state == 2) |
{ |
int wlen = 120, |
hlen = 80; |
//Setup |
if (g->timer == 0) { |
g->targx = g->x + (wlen * sin((g->dir - 90) * 3.14159 / 180)); |
g->targy = g->y + (hlen * cos((g->dir - 90) * 3.14159 / 180)); |
g->dir += 90; |
g->timer = 200; |
} |
g->dir -= 1.5; |
if (g->dir < 0) { |
g->dir += 360; |
} |
g->x = g->targx + (wlen * sin(g->dir * 3.14159 / 180)); |
g->y = g->targy + (hlen * cos(g->dir * 3.14159 / 180)); |
g->timer -= 1; |
if (g->timer <= 0) { |
g->counter += 1; |
if (g->counter >= 5) { |
g->counter = 0; |
} |
g->state = pattern[g->counter]; |
/* |
if (g->state != 1 && (g->x < 40 || g->x > 600 || g->y < 40 || g->y > 440)) { |
g->state = 1; |
g->timer = 0; |
}*/ |
} |
} |
//Death |
if (g->state == 3) |
{ |
g->timer -= 1; |
if (g->timer <= 0) { |
g->timer = 12; |
int cx = g->xrecord[128 - (g->counter * 16)], |
cy = g->yrecord[128 - (g->counter * 16)]; |
createEffect(2, cx - 32, cy - 32); |
g->counter += 1; |
if (g->counter == 9) { |
gyraDestroy(g); |
} |
} |
}else{ |
//Update tail record |
int i; |
for (i = 142; i >= 0; i--) { |
g->xrecord[i + 1] = g->xrecord[i]; |
g->yrecord[i + 1] = g->yrecord[i]; |
} |
g->xrecord[0] = g->x; |
g->yrecord[0] = g->y; |
//for (i = 8; i >= 0; i--) { |
for (i = 0; i <= 8; i++) { |
int cx = g->x, cy = g->y; |
if (i != 0) { |
cx = g->xrecord[i * 16]; |
cy = g->yrecord[i * 16]; |
} |
Mask mask; |
mask.unused = 0; |
mask.circle = 1; |
mask.x = cx; |
mask.y = cy; |
mask.w = mask.h = 28; |
int a; |
for (a = 0; a < MAX_WEAPONS; a++) { |
if (weapons[a] != NULL) { |
if (weapons[a]->cooldown == 0) { |
if (checkCollision(mask, weapons[a]->weaponMask)) { |
g->invincible = -15; |
weaponHit(weapons[a]); |
if (i == 8) { |
g->hp -= 1; |
g->invincible = 15; |
}else{ |
PHL_PlaySound(sounds[sndHit03], CHN_WEAPONS); |
} |
a = MAX_WEAPONS; |
} |
} |
} |
} |
//Hit player |
if (checkCollision(getHeroMask(), mask)) { |
if (heroHit(30, mask.x) && i == 0) { |
heroPoison(); |
} |
} |
} |
//Death |
if (g->hp <= 0) { |
g->state = 3; |
g->timer = 0; |
g->counter = 0; |
g->invincible = 200; |
} |
} |
if (g->invincible > 0) { |
g->invincible -= 1; |
} |
if (g->invincible < 0) { |
g->invincible += 1; |
} |
} |
void gyraDraw(Gyra* g) |
{ |
if (g->invincible <= 0 || g->invincible % 2 == 0) { |
//Draw Tail Tip |
if (g->state != 3 || g->counter <= 0) { |
PHL_DrawSurfacePart(g->xrecord[126] - 40, g->yrecord[126] - 40, 320 + ((int)g->imageIndex * 80), 0, 80, 80, images[imgBoss]); |
} |
//Draw Tail |
int i; |
for (i = 7; i > 0; i--) { |
if (g->state != 3 || g->counter <= (7 - i) + 1) { |
PHL_DrawSurfacePart(g->xrecord[i * 16] - 40, g->yrecord[i * 16] - 40, 160 + ((int)g->imageIndex * 80), 0, 80, 80, images[imgBoss]); |
} |
} |
//Draw Head |
PHL_DrawSurfacePart(g->x - 40, g->y - 40, (int)g->imageIndex * 80, 0, 80, 80, images[imgBoss]); |
} |
//PHL_DrawRect(g->targx, g->targy, 10, 10, PHL_NewRGB(255, 255, 255)); |
//heroAmmo = g->state; |
/* |
int i; |
for (i = 8; i >= 0; i--) { |
int cx = g->x, cy = g->y; |
if (i != 0) { |
cx = g->xrecord[i * 16]; |
cy = g->yrecord[i * 16]; |
} |
PHL_DrawRect(cx, cy, 10, 10, PHL_NewRGB(255, 255, 255)); |
} |
*/ |
} |
void gyraDestroy(Gyra* g) |
{ |
enemyDestroy(g->id); |
bossDefeatedFlag = 1; |
roomSecret = 1; |
flags[boss4flag] = 1; |
PHL_StopMusic(); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/gyra.h |
---|
0,0 → 1,19 |
#ifndef GYRA_H |
#define GYRA_H |
typedef struct { |
int id; |
int hp; |
double x, y; |
double xrecord[144]; |
double yrecord[144]; |
int state, timer, counter; |
int targx, targy; |
int invincible; |
double dir; |
double imageIndex; |
} Gyra; |
void createGyra(int x, int y); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/heads.c |
---|
0,0 → 1,838 |
#include "heads.h" |
#include "../enemy.h" |
#include "../game.h" |
#include "../PHL.h" |
#include "../hero.h" |
#include <stdlib.h> |
#include <math.h> |
void headStep(Head* h); |
void headDraw(Head* h); |
void bulletStep(Bullet* b); |
void bulletDraw(Bullet* b); |
void fireballStep(Fireball* f); |
void fireballDraw(Fireball* f); |
void laserStep(Laser* l); |
void laserDraw(Laser* l); |
void flameStep(Flame* f); |
void flameDraw(Flame* f); |
void rockStep(Rock* r); |
void rockDraw(Rock* r); |
void airStep(Air* a); |
void airDraw(Air* a); |
void createHead(int type, int x, int y, int dir, int offset, int cooloff) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Head* h = malloc(sizeof *h); |
h->id = i; |
h->type = type; |
h->x = x; |
h->y = y; |
h->state = 0; |
h->hp = 5; |
h->invincible = 0; |
h->counter = 0; |
h->dir = 1; |
if (dir == 1) { |
h->dir = -1; |
} |
h->timer = 30 * offset; |
h->cooloff = 60; |
if (cooloff != 0) { |
h->cooloff = 30 * cooloff; |
} |
e->type = -1; |
if (h->type == 0) { |
e->type = 4; |
h->cooloff = 120; |
} |
else if (h->type == 1) { |
e->type = 6; |
} |
else if (h->type == 2) { |
e->type = 5; |
} |
else if (h->type == 3) { |
e->type = 7; |
h->cooloff = 120; |
} |
else if (h->type == 4) { |
e->type = 10; |
h->dir = 0; |
} |
else if (h->type == 5) { |
e->type = 25; |
h->dir = 0; |
} |
e->data = h; |
e->enemyStep = headStep; |
e->enemyDraw = headDraw; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void headStep(Head* h) |
{ |
int RHYNO = 0, |
MEDUSA = 1, |
DRAGON = 2, |
DEMON = 3, |
FIRE = 4, |
JAR = 5; |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.x = h->x; |
mask.y = h->y + 1; |
mask.w = 40; |
mask.h = 39; |
} |
//Timers |
{ |
if (h->invincible > 0) { |
h->invincible -= 1; |
} |
if (h->timer > 0) { |
h->timer -= 1; |
} |
} |
//Wait |
if (h->state == 0) |
{ |
char endstate = 0; |
if (h->timer <= 0) { |
//Proximity |
if (h->type == RHYNO || h->type == DEMON) { |
Mask area; |
area.circle = area.unused = 0; |
area.h = 80; |
area.w = 400; |
area.y = h->y - 20; |
area.x = h->x; |
if (h->dir == -1) { |
area.x -= area.w - 40; |
} |
if (checkCollision(area, getHeroMask()) == 1) { |
endstate = 1; |
} |
}else{ |
endstate = 1; |
} |
} |
//Move onto next state |
if (endstate == 1) { |
h->state = 1; |
h->timer = 30; |
} |
} |
//Blink |
else if (h->state == 1) |
{ |
//Shoot projectile |
if (h->timer <= 0) { |
//Play Sound |
{ |
int soundtoplay[6] = {sndShot03, sndShot04, sndFire01, sndHit06, sndShot03, sndShot06}; |
PHL_PlaySound(sounds[soundtoplay[h->type]], CHN_ENEMIES); |
} |
//Set vars |
{ |
h->state = 0; |
h->timer = h->cooloff; |
} |
//Create projectile |
{ |
//Rhyno head |
if (h->type == RHYNO) { |
createBullet(mask.x + (mask.w / 2), h->y + 24, h->dir, h->id); |
} |
//Medusa head |
if (h->type == MEDUSA) { |
createLaser(h->x, h->y, h->dir); |
} |
//Dragon head |
if (h->type == DRAGON) { |
createFlame(h->x + 20 + (20 * h->dir), h->y - 10, h->dir); |
} |
//Demon head |
if (h->type == DEMON) { |
createRock(h->x + (20 * h->dir), h->y, h->dir); |
} |
//Fireball Statue |
if (h->type == FIRE) { |
createFireball(h->x + 20, h->y + 20, (atan2(heroy - h->y, h->x - (herox - 20)) * 180 / 3.14159) + 270, h->id); |
} |
//Air Jar |
if (h->type == JAR) { |
h->state = 3; |
h->timer = 12; |
h->counter = 0; |
} |
} |
} |
} |
//Air Jar |
else if (h->state == 3) |
{ |
if (h->timer <= 0) { |
h->counter += 1; |
h->timer = 12; |
createAir(h->x, h->y - 20); |
} |
if (h->counter >= 6) { |
h->counter = 0; |
h->state = 0; |
h->timer = h->cooloff; |
} |
} |
//Hit player |
if (h->type != JAR) { |
if (checkCollision(getHeroMask(), mask)) { |
heroHit(10, mask.x + (mask.w / 2)); |
} |
} |
//Weapon collision |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
h->hp -= 1; |
h->invincible = 15; |
weaponHit(weapons[i]); |
//Death |
if (h->hp <= 0) { |
createRockSmash(h->x + 20, h->y + 20); |
spawnCollectable(h->x + 20, h->y); |
enemyDestroy(h->id); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
void headDraw(Head* h) |
{ |
if (h->invincible % 2 == 0) |
{ |
int sheetX[6] = {0, 320, 160, 240, 560, 400}; |
int sheetY[6] = {80, 80, 80, 120, 0, 120}; |
int cropX = sheetX[h->type]; |
int addx[6] = {6, 2, 0, 0, 0, 0}; |
int frames = 2; |
//Change dir |
if (h->dir == 0) { |
frames = 1; |
}else{ |
frames = 2; |
if (h->dir == -1) { |
cropX += 40; |
} |
} |
//White flash |
if (h->state == 1 && h->timer % 6 < 3) { |
cropX += 40 * frames; |
} |
PHL_DrawSurfacePart(h->x - (addx[h->type] * h->dir), h->y, cropX, sheetY[h->type], 40, 40, images[imgEnemies]); |
} |
} |
//Bullets |
void createBullet(int x, int y, int dir, int minid) |
{ |
int i; |
for (i = minid; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Bullet* b = malloc(sizeof *b); |
b->id = i; |
b->x = x; |
b->y = y; |
b->hsp = dir * 4; |
b->imageIndex = 0; |
e->data = b; |
e->enemyStep = bulletStep; |
e->enemyDraw = bulletDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void bulletStep(Bullet* b) |
{ |
char dead = 0; |
//Movement |
{ |
b->x += b->hsp; |
} |
//Create Mask |
Mask mask; |
{ |
mask.unused = 0; |
mask.circle = 1; |
mask.w = mask.h = 10; |
mask.x = b->x; |
mask.y = b->y; |
} |
//Animation |
{ |
if (b->hsp > 0) { |
b->imageIndex += 0.33; |
}else{ |
b->imageIndex -= 0.33; |
} |
if (b->imageIndex < 0) { |
b->imageIndex += 4; |
} |
if (b->imageIndex >= 4) { |
b->imageIndex -= 4; |
} |
} |
//Collide with wall |
{ |
if (checkTileCollision(1, mask) == 1) { |
createEffect(1, b->x - 20, b->y - 20); |
dead = 1; |
} |
} |
//Collide with hero |
{ |
//Shield collision |
if (checkCollision(mask, shieldMask) == 1) { |
dead = 1; |
createEffect(1, b->x - 20, b->y - 20); |
PHL_PlaySound(sounds[sndHit07], CHN_EFFECTS); |
} |
//Collide with hero |
else{ |
if (checkCollision(getHeroMask(), mask)) { |
heroHit(10, mask.x); |
} |
} |
} |
//Destroy if outside of view |
{ |
if (b->x > 660 || b->x < -20 || b->y < -20 || b->y > 520) { |
dead = 1; |
} |
} |
//Destroy |
{ |
if (dead == 1) { |
enemyDestroy(b->id); |
} |
} |
} |
void bulletDraw(Bullet* b) |
{ |
PHL_DrawSurfacePart(b->x - 20, b->y - 20, 160 + (40 * (int)b->imageIndex), 480, 40, 40, images[imgMisc20]); |
} |
//Fireball |
void createFireball(int x, int y, int angle, int minid) |
{ |
//General idea: try to place fireball over spawner |
int i; |
for (i = minid; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Fireball* f = malloc(sizeof *f); |
f->id = i; |
f->x = x; |
f->y = y; |
f->spd = 3; |
f->imageIndex = 0; |
f->angle = angle; |
f->mask.circle = 1; |
f->mask.unused = 0; |
f->mask.x = x; |
f->mask.y = y; |
f->mask.w = f->mask.h = 14; |
e->data = f; |
e->enemyStep = fireballStep; |
e->enemyDraw = fireballDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void fireballStep(Fireball* f) |
{ |
f->x += (f->spd) * sin(f->angle * 3.14159 / 180); |
f->y += (f->spd) * cos(f->angle * 3.14159 / 180); |
f->mask.x = f->x; |
f->mask.y = f->y; |
f->imageIndex += 0.5; |
if (f->imageIndex >= 8) { |
f->imageIndex -= 8; |
} |
//Collide with shield |
if (checkCollision(f->mask, shieldMask)) { |
createEffect(1, f->x - 20, f->y - 20); |
PHL_PlaySound(sounds[sndHit07], CHN_EFFECTS); |
enemyDestroy(f->id); |
}else{ |
//Hit player |
if (checkCollision(getHeroMask(), f->mask)) { |
heroHit(10, f->mask.x); |
} |
//Destroy if outside of view |
if (f->x > 660 || f->x < -20 || f->y < -20 || f->y > 520) { |
enemyDestroy(f->id); |
} |
} |
} |
void fireballDraw(Fireball* f) |
{ |
PHL_DrawSurfacePart(f->x - 20, f->y - 20, 320 + (40 * (int)f->imageIndex), 440, 40, 40, images[imgMisc20]); |
} |
//Laser |
void createLaser(int x, int y, int dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Laser* l = malloc(sizeof *l); |
l->id = i; |
l->x = x; |
l->y = y; |
l->dir = dir; |
l->imageIndex = 0; |
l->mask.circle = l->mask.unused = 0; |
l->mask.x = x; |
l->mask.y = y + 17; |
l->mask.w = 40; |
l->mask.h = 6; |
e->data = l; |
e->enemyStep = laserStep; |
e->enemyDraw = laserDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void laserStep(Laser* l) |
{ |
char dead = 0; |
l->x += l->dir * 10; |
l->mask.x = l->x; |
l->imageIndex += 0.34; |
if (l->imageIndex >= 2) { |
l->imageIndex -= 2; |
} |
if (checkCollision(shieldMask, l->mask)) { //Hit shield |
PHL_PlaySound(sounds[sndHit07], CHN_EFFECTS); |
createEffect(1, l->x + (20 * l->dir), l->y); |
enemyDestroy(l->id); |
dead = 1; |
}else if (checkCollision(getHeroMask(), l->mask)) { |
heroStone(); |
heroHit(15, l->x + 20); |
} |
if (dead == 0) { |
if (checkTileCollision(1, l->mask)) { |
createEffect(1, l->x + (20 * l->dir), l->y); |
enemyDestroy(l->id); |
dead = 1; |
} |
if (dead == 0) { |
if (l->mask.x > 640 || l->mask.x + l->mask.w <= 0) { |
enemyDestroy(l->id); |
} |
} |
} |
} |
void laserDraw(Laser* l) |
{ |
int dx = 0, |
dy = 480; |
if (l->dir == -1) { |
dx += 80; |
} |
PHL_DrawSurfacePart(l->x, l->y, dx + (((int)l->imageIndex) * 40), dy, 40, 40, images[imgMisc20]); |
} |
//Dragon Flame |
void createFlame(int x, int y, int dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Flame* f = malloc(sizeof *f); |
f->id = i; |
f->x = x; |
f->y = y; |
f->dir = dir; |
f->timer = 60; |
f->imageIndex = 0; |
e->data = f; |
e->enemyStep = flameStep; |
e->enemyDraw = flameDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void flameStep(Flame* f) |
{ |
f->imageIndex += 0.25; |
if (f->timer > 0) { |
if (f->imageIndex >= 3) { |
f->imageIndex -= 3; |
} |
} |
f->timer -= 1; |
if (f->timer == 0) { |
f->imageIndex = 3; |
} |
//Hero Collision |
{ |
Mask mask; |
mask.circle = mask.unused = 0; |
mask.x = f->x; |
mask.y = f->y + 16; |
mask.w = 120; |
mask.h = 18; |
if (f->dir == -1) { |
mask.x -= 120; |
} |
if (checkCollision(mask, getHeroMask()) == 1) { |
int centerX = mask.x + 60 - (60 * f->dir); |
//Hero is on ladder |
if (getHeroState() == 3) { |
centerX = herox; |
} |
heroHit(30, centerX); |
} |
} |
if (f->timer < 0 && f->imageIndex >= 6) { |
enemyDestroy(f->id); |
} |
} |
void flameDraw(Flame* f) |
{ |
int drawX = f->x, |
drawY = f->y; |
int cropX = 0, |
cropY = 0; |
if (f->dir == -1) { |
cropX += 720; |
drawX -= 120; |
} |
cropX += 120 * (int)f->imageIndex; |
while (cropX >= 600) { |
cropX -= 600; |
cropY += 40; |
} |
PHL_DrawSurfacePart(drawX, drawY, cropX, cropY, 120, 40, images[imgMisc6020]); |
} |
//Demon Rock |
void createRock(int x, int y, int dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Rock* r = malloc(sizeof *r); |
r->id = i; |
r->x = x; |
r->y = y; |
r->vsp = -3; |
r->dir = dir; |
r->imageIndex = 0; |
e->data = r; |
e->enemyStep = rockStep; |
e->enemyDraw = rockDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void rockStep(Rock* r) |
{ |
char dead = 0; |
//Animate |
{ |
r->imageIndex += 0.25 * r->dir; |
if (r->imageIndex >= 8) { |
r->imageIndex -= 8; |
} |
if (r->imageIndex < 0) { |
r->imageIndex += 8; |
} |
} |
//Setup Mask |
Mask mask; |
{ |
mask.unused = mask.circle = 0; |
mask.x = r->x + 2; |
mask.y = r->y + 2; |
mask.w = 36; |
mask.h = 36; |
} |
int hsp = 3; |
double grav = 0.12; |
//Movement |
{ |
r->y += r->vsp; |
r->vsp += grav; |
//Collide with floor |
{ |
mask.y = r->y + 2; |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x != -1) { |
PHL_PlaySound(sounds[sndHit06], CHN_ENEMIES); |
r->y = collide.y - mask.h - 2; |
r->vsp = -3; |
mask.y = r->y + 2; |
} |
} |
r->x += hsp * r->dir; |
//Collide with wall |
{ |
mask.x = r->x + 2; |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
dead = 1; |
} |
} |
} |
//Collision |
{ |
//Hero collision |
if (checkCollision(mask, getHeroMask()) == 1) { |
heroHit(20, mask.x + (mask.w / 2)); |
} |
//Weapon collision |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
PHL_PlaySound(sounds[sndHit03], CHN_WEAPONS); |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
//Destroy |
if (dead == 1) { |
createRockSmash(r->x + 20, r->y); |
enemyDestroy(r->id); |
} |
} |
void rockDraw(Rock* r) |
{ |
PHL_DrawSurfacePart(r->x, r->y, 320 + ((int)r->imageIndex * 40), 160, 40, 40, images[imgEnemies]); |
} |
//Air Stream |
void createAir(int x, int y) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Air* a = malloc(sizeof *a); |
a->id = i; |
a->x = x; |
a->y = y; |
a->imageIndex = 0; |
e->data = a; |
e->enemyStep = airStep; |
e->enemyDraw = airDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
//Air Puff |
void airStep(Air* a) |
{ |
Mask mask; |
mask.circle = mask.unused = 0; |
mask.w = 36; |
mask.h = 30; |
mask.x = a->x + ((40 - mask.w) / 2); |
//Animate |
a->imageIndex += 0.5; |
if (a->imageIndex >= 2) { |
a->imageIndex -= 2; |
} |
//Movement |
a->y -= 6; |
mask.y = a->y + (40 - mask.h); |
//Collide with player |
if (getHeroState() != 2) { |
if (checkCollision(mask, getHeroMask())) { |
if (hasItem[27] == 0) { |
heroHit(10, mask.x + (mask.w / 2)); |
}else{ |
//Floating stuff |
if (getHeroVsp() > -5) { |
setHeroVsp(-5); |
setHeroOnground(0); |
} |
} |
} |
} |
//destroy if outside of room |
if (mask.y + mask.h < 0) { |
enemyDestroy(a->id); |
} |
} |
void airDraw(Air* a) |
{ |
PHL_DrawSurfacePart(a->x, a->y, (int)a->imageIndex * 40, 560, 40, 40, images[imgMisc20]); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/heads.h |
---|
0,0 → 1,89 |
#ifndef HEADS_H |
#define HEADS_H |
#include "../collision.h" |
//Goblin/medusa/dragon head statues |
typedef struct { |
int id, type; //0 = Rhyno head | 1 = Goblin | 2 = Dragon | 3 = Demon | 4 = Fireball | 5 = Air Jar |
int state, timer; |
double x, y; |
int dir; |
int hp, invincible; |
int cooloff; |
int counter; |
//Mask mask; |
} Head; |
void createHead(int type, int x, int y, int dir, int offset, int cooloff); |
//Bullet from Rhyno statues |
typedef struct { |
int id; |
double x, y; |
int hsp; |
double imageIndex; |
//Mask mask; |
} Bullet; |
void createBullet(int x, int y, int dir, int minid); //Minid is the spawner's id |
//Fireball |
typedef struct { |
int id; |
double x, y; |
int angle; |
int spd; |
double imageIndex; |
Mask mask; |
} Fireball; |
void createFireball(int x, int y, int angle, int minid); |
//Medusa lazer |
typedef struct { |
int id; |
double x, y; |
int dir; |
double imageIndex; |
Mask mask; |
} Laser; |
void createLaser(int x, int y, int dir); |
//Dragon flame |
typedef struct { |
int id; |
int x, y; |
int dir; |
int timer; |
double imageIndex; |
} Flame; |
void createFlame(int x, int y, int dir); |
//Demon Boulder |
typedef struct { |
int id; |
double x, y; |
double vsp; |
int dir; |
double imageIndex; |
} Rock; |
void createRock(int x, int y, int dir); |
//Air |
typedef struct { |
int id; |
double x, y; |
double imageIndex; |
} Air; |
void createAir(int x, int y); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/hydra.c |
---|
0,0 → 1,1127 |
#include "hydra.h" |
#include "../game.h" |
#include "../hero.h" |
#include <stdlib.h> |
#include <math.h> |
const double PI = 3.14159; |
double headRot = 0; |
void hydraStep(Hydra* h); |
void hydraDraw(Hydra* h); |
void hydraDestroy(Hydra* h); |
void hydraheadStep(Hydrahead* h); |
void hydraheadDraw(Hydrahead* h); |
void hydragoopStep(Hydragoop* h); |
void hydragoopDraw(Hydragoop* h); |
void hydrarockStep(Hydrarock* h); |
void hydrarockDraw(Hydrarock* h); |
void hydrashockStep(Hydrashock* h); |
void hydrashockDraw(Hydrashock* h); |
double getHydraX(Hydrahead* h); |
double getHydraY(Hydrahead* h); |
Mask getHydraMask(Hydra* h); |
int checkWeaponCollision(Mask m); |
double lengthdir_x(double ang, double len); |
double lengthdir_y(double ang, double len); |
void setHeadState(int headid, int state); |
//#hydra |
void createHydra(int x) |
{ |
PHL_FreeSurface(images[imgBoss]); |
images[imgBoss] = PHL_LoadQDA("lboss01.bmp"); |
int i; |
for (i = 4; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
setBossRoom(); |
Enemy* e = malloc(sizeof *e); |
Hydra* h = malloc(sizeof *h); |
h->id = i; |
h->hp = 10; |
//h->hp = 1; |
h->blink = 0; |
h->x = x; |
h->y = -64; |
h->hsp = 0; |
h->vsp = 0; |
h->imageIndex = 0; |
h->state = 0; |
h->timer = 0; |
h->patternCounter = 0; |
h->onground = 0; |
h->noheads = 0; |
e->data = h; |
e->enemyStep = hydraStep; |
e->enemyDraw = hydraDraw; |
e->type = 47; |
enemies[i] = e; |
h->headid[0] = createHydrahead(-1, 0, i); |
h->headid[1] = createHydrahead(1, 0, i); |
h->headid[2] = createHydrahead(1, 1, i); |
h->headid[3] = createHydrahead(-1, 1, i); |
i = MAX_ENEMIES; |
} |
} |
} |
void hydraStep(Hydra* h) |
{ |
double grav = 0.2; |
double fric = 0.1; |
//Death |
if (h->state == 6) { |
h->y += 0.2; |
h->timer -= 1; |
h->blink -= 1; |
if (h->timer % 12 == 0) { |
createEffect(2, h->x - 64 + (rand() % 128) - 32, h->y - 64 + (rand() % 128)); |
} |
if (h->timer <= 0) { |
hydraDestroy(h); |
} |
} |
else{ |
//Setup Mask |
Mask mask = getHydraMask(h); |
//States with hydra heads |
if (h->noheads == 0) { |
//Fall in intro |
if (h->state == 0) { |
h->hsp = 0; |
h->timer += 1; |
if (h->timer >= 50) { |
h->timer = 50; |
h->imageIndex = 2; |
if (h->onground == 1) { |
h->state = 1; |
h->timer = 0; |
} |
}else{ |
grav = 0; |
} |
} |
//Wait/Pattern activate |
else if (h->state == 1) |
{ |
h->timer += 1; |
//Stop speed animation |
if (h->timer >= 120) { |
int patternSize = 9; |
int pattern[9] = {4, 0, 4, 1, 4, 2, 4, 3, 2}; |
//Head seizure |
if (pattern[h->patternCounter] == 4) { |
h->state = 4; |
h->timer = 0; |
} |
//Small hop |
if (pattern[h->patternCounter] == 0) { |
h->state = 2; |
h->timer = 0; |
} |
//Goop |
if (pattern[h->patternCounter] == 1) { |
h->timer = -120; |
setHeadState(h->headid[0], 2); |
setHeadState(h->headid[1], 2); |
} |
//Big Hop |
if (pattern[h->patternCounter] == 2) { |
h->state = 3; |
h->timer = 0; |
} |
//Electricity |
if (pattern[h->patternCounter] == 3) { |
h->timer = -40; |
setHeadState(h->headid[2], 3); |
setHeadState(h->headid[3], 3); |
} |
h->patternCounter += 1; |
if (h->patternCounter >= patternSize) { |
h->patternCounter = 0; |
} |
} |
} |
//Head seizure state |
else if (h->state == 4) { |
//Speed up head animation |
if (h->timer == 0) { |
setHeadState(h->headid[0], 1); |
setHeadState(h->headid[1], 1); |
setHeadState(h->headid[2], 1); |
setHeadState(h->headid[3], 1); |
} |
h->timer += 1; |
//Stop speed animation |
if (h->timer == 120) { |
setHeadState(h->headid[0], 0); |
setHeadState(h->headid[1], 0); |
setHeadState(h->headid[2], 0); |
setHeadState(h->headid[3], 0); |
//Pattern |
h->state = 1; |
h->timer = 120; |
} |
} |
//Switch to noheads mode |
if (h->onground == 1 && |
enemies[h->headid[0]] == NULL && |
enemies[h->headid[1]] == NULL && |
enemies[h->headid[2]] == NULL && |
enemies[h->headid[3]] == NULL) |
{ |
h->noheads = 1; |
h->state = 1; |
h->timer = -15; |
h->patternCounter = 0; |
} |
} |
//States without hydra heads |
else{ |
//Wait/pattern activate |
if (h->state == 1) { |
h->timer += 1; |
if (h->timer >= 0) { |
int patternSize = 3; |
int pattern[3] = {0, 0, 2}; |
//Small hop |
if (pattern[h->patternCounter] == 0) { |
h->state = 2; |
h->timer = 0; |
} |
//Big Hop |
if (pattern[h->patternCounter] == 2) { |
h->state = 3; |
h->timer = 0; |
} |
h->patternCounter += 1; |
if (h->patternCounter >= patternSize) { |
h->patternCounter = 0; |
} |
} |
} |
} |
//States used by both modes |
{ |
//Small hop |
if (h->state == 2) { |
//Setup |
if (h->timer == 0) { |
h->vsp = -2; |
h->onground = 0; |
h->hsp = 2.5; |
if (herox < h->x) { |
h->hsp *= -1; |
} |
} |
h->timer += 1; |
if (h->onground == 1) { |
if (h->noheads == 0 || h->hsp == 0) { |
h->state = 1; |
h->timer = 0; |
} |
} |
} |
//Large Hop |
else if (h->state == 3) { |
h->hsp = 0; |
//Setup |
if (h->timer == 0) { |
h->timer = 1; |
if (h->noheads == 0) { |
h->vsp = -8; |
}else{ |
h->vsp = -5; |
} |
h->onground = 0; |
} |
if (h->onground == 1) { |
h->timer += 1; |
if (h->timer % 20 == 0) { |
createHydrarock(); |
} |
if (h->timer >= 220) { |
h->state = 1; |
h->timer = -15; |
} |
} |
} |
} |
//Animate |
{ |
if (h->onground == 1) { |
h->imageIndex += 0.1; |
if (h->imageIndex >= 2) { |
h->imageIndex -= 2; |
} |
}else{ |
if (h->vsp < 0) { |
h->imageIndex = 3; |
} |
else { |
h->imageIndex = 2; |
} |
} |
//Blink |
if (h->blink > 0) { |
h->blink -= 1; |
} |
} |
//Movement |
{ |
//Horizontal |
if (h->hsp != 0) { |
h->x += h->hsp; |
mask = getHydraMask(h); |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
int dir = 1; |
if (h->hsp < 0) { |
dir = -1; |
} |
h->x = collide.x + 20 - ((20 + (mask.w / 2)) * dir); |
h->hsp *= -1; |
} |
} |
//Friction |
{ |
if (h->onground == 1) { |
if (h->hsp > 0) { |
h->hsp -= fric; |
if (h->hsp < 0) { |
h->hsp = 0; |
} |
} |
if (h->hsp < 0) { |
h->hsp += fric; |
if (h->hsp > 0) { |
h->hsp = 0; |
} |
} |
} |
} |
//Vertical |
{ |
int maxVsp = 9; |
if (h->onground == 0) { |
h->y += h->vsp; |
h->vsp += grav; |
mask = getHydraMask(h); |
//Limit vsp |
{ |
if (h->vsp > maxVsp) { |
h->vsp = maxVsp; |
} |
} |
//Collide with floor |
{ |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
h->y = collide.y - 64; |
h->vsp = 0; |
h->onground = 1; |
PHL_PlaySound(sounds[sndHit04], CHN_ENEMIES); |
quakeTimer = 30; |
createEffectExtra(3, h->x - 30, h->y + 32, -1, 0, 0); |
createEffectExtra(3, h->x - 10, h->y + 32, 1, 0, 0); |
} |
} |
} |
} |
} |
//Update mask |
mask = getHydraMask(h); |
//Hero Collision |
{ |
if (checkCollision(mask, getHeroMask()) == 1) { |
heroHit(25, h->x); |
} |
} |
//Weapon Collision |
{ |
int wid = checkWeaponCollision(mask); |
if (wid != -1) { |
//Pushed back |
if (h->noheads == 0) { |
h->hsp = weapons[wid]->dir; |
PHL_PlaySound(sounds[sndPi05], CHN_ENEMIES); |
}else{ |
h->hp -= 1; |
h->blink = 15; |
} |
weaponHit(weapons[wid]); |
//Die |
if (h->hp <= 0) { |
h->state = 6; |
h->timer = 180; |
h->blink = 200; |
} |
} |
} |
} |
} |
void hydraDraw(Hydra* h) |
{ |
if (h->blink % 2 == 0) { |
int cropX = (int)h->imageIndex * 128; |
int cropY = 128; |
if (h->noheads == 1) { |
cropY += 128; |
} |
PHL_DrawSurfacePart(h->x - 64, h->y - 64, cropX, cropY, 128, 128, images[imgBoss]); |
} |
} |
void hydraDestroy(Hydra* h) |
{ |
enemyDestroy(h->id); |
bossDefeatedFlag = 1; |
roomSecret = 1; |
PHL_StopMusic(); |
} |
Mask getHydraMask(Hydra* h) |
{ |
Mask mask; |
mask.unused = mask.circle = 0; |
mask.w = 84; |
mask.h = 84; |
mask.x = h->x - (mask.w / 2); |
mask.y = h->y - 64 + (128 - mask.h); |
return mask; |
} |
//#heads |
int createHydrahead(int dir, int position, int bodyid) |
{ |
int result = -1; |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Hydrahead* h = malloc(sizeof *h); |
h->id = i; |
result = i; |
h->hp = 25; |
//h->hp = 1; |
h->blink = 0; |
h->dir = dir; |
h->position = position; |
h->imageIndex = 0; |
h->neckRot = 0; |
if (position != 0) { |
h->neckRot -= 45; |
} |
h->state = 0; |
h->timer = 0; |
h->counter = 0; |
h->bodyid = bodyid; |
int a; |
for (a = 0; a < 7; a++) { |
h->bodyposX[a] = 0; |
h->bodyposY[a] = 0; |
} |
e->data = h; |
e->enemyStep = hydraheadStep; |
e->enemyDraw = hydraheadDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
return result; |
} |
void hydraheadStep(Hydrahead* h) |
{ |
char dead = 0; |
//Animate |
{ |
h->imageIndex += 0.1; |
if (h->imageIndex >= 2) { |
h->imageIndex -= 2; |
} |
if (h->blink > 0) { |
h->blink -= 1; |
} |
h->neckRot += 2; |
if (h->neckRot >= 360) { |
h->neckRot -= 360; |
} |
} |
//States |
{ |
//Death |
if (h->state == 4) { |
h->timer += 1; |
if (h->timer % 6 == 0) { |
createEffect(2, h->bodyposX[6 - h->counter] - 32, h->bodyposY[6 - h->counter] - 32); |
h->counter += 1; |
} |
if (h->counter >= 7) { |
dead = 1; |
} |
} |
else{ |
if (h->state == 0) { |
//Do nothing special |
} |
//Fast movements |
else if (h->state == 1) { |
h->neckRot += 2; |
} |
//Shoot goop |
else if (h->state == 2) { |
h->neckRot += 2; |
h->timer += 1; |
//Create Goop |
if (h->timer % 15 == 0) { |
int ghsp = -4 + (rand() % 9), |
gvsp = -6; |
createHydragoop(h->bodyposX[6], h->bodyposY[6], ghsp, gvsp); |
} |
if (h->timer >= 120) { |
h->state = 0; |
} |
} |
//Shoot electricity |
else if (h->state == 3) { |
if (h->timer == 0) { |
h->timer = 1; |
} |
if (h->timer % 20 == 0) { |
if (h->counter == 0) { |
createHydrashock(h->bodyposX[6] + (70 * h->dir), h->bodyposY[6] + 20); |
} |
h->neckRot -= 2; |
h->counter += 1; |
if (h->counter >= 20) { |
h->counter = 0; |
h->timer += 1; |
} |
}else{ |
h->neckRot += 2; |
h->timer += 1; |
} |
if (h->timer > 80) { |
h->state = 0; |
/* |
Hydra* body = enemies[h->bodyid]->data; |
body->state = 1; |
body->timer = 239; |
*/ |
} |
} |
Mask mask; |
mask.circle = mask.unused = 0; |
//Collide with player |
{ |
int i; |
for (i = 0; i < 7; i+=2) { |
//Setup mask |
{ |
mask.w = 48; |
mask.h = 48; |
//Head |
if (i == 6) { |
mask.w = 60; |
mask.h = 36; |
} |
mask.x = h->bodyposX[i] - (mask.w / 2); |
mask.y = h->bodyposY[i] - (mask.h / 2); |
} |
//Collide |
if (checkCollision(getHeroMask(), mask) == 1) { |
heroHit(25, getHydraX(h)); |
} |
} |
} |
//Weapon collision |
{ |
//Mask should still be on the head |
int wid = checkWeaponCollision(mask); |
if (wid != -1) { |
h->blink = 15; |
h->hp -= 1; |
weaponHit(weapons[wid]); |
if (h->hp <= 0) { |
h->state = 4; |
h->timer = 0; |
h->counter = 0; |
} |
} |
} |
} |
} |
//Destroy object |
if (dead == 1) { |
enemyDestroy(h->id); |
} |
} |
void hydraheadDraw(Hydrahead* h) |
{ |
/* |
char c[10]; |
sprintf(c, "%02d", h->timer); |
PHL_DrawTextBold(c, h->bodyposX[6], 0, 0); |
*/ |
h->bodyposX[0] = getHydraX(h) + 20; |
h->bodyposY[0] = getHydraY(h); |
double drawX = getHydraX(h) + 20; |
double drawY = getHydraY(h); |
int dis = 24; |
int angle = -25; |
if (h->position == 1) { |
angle = -60; |
drawX -= 5; |
drawY -= 20; |
} |
int i; |
for (i = 0; i < 7; i++) { |
double wavlen = sin((h->neckRot + (45 * i)) * PI / 180); |
double incang = 45; |
if (h->position != 0) { |
incang = 45; |
} |
if (i == 6) { |
//incang += 15; |
incang = 50; |
if (h->position == 1) { |
incang = 80; |
} |
} |
drawX += lengthdir_x(angle + (incang * wavlen), dis); |
drawY += lengthdir_y(angle + (incang * wavlen), dis); |
h->bodyposX[i] = drawX; |
h->bodyposY[i] = drawY; |
if (h->dir == -1) { |
double difference = h->bodyposX[i] - getHydraX(h); |
h->bodyposX[i] = getHydraX(h) - difference; |
} |
if (h->blink % 2 == 0) { |
if (h->state != 4 || (6 - h->counter >= i)) { |
if (i != 6) { |
int cropX = 0; |
if (h->dir == -1) { |
cropX += 64; |
} |
PHL_DrawSurfacePart(h->bodyposX[i] - 32, h->bodyposY[i] - 32, cropX, 64, 64, 64, images[imgBoss]); |
}else{ |
int cropX = 0; |
if (h->dir == -1) { |
cropX += 320; |
} |
cropX += (int)h->imageIndex * 80; |
PHL_DrawSurfacePart(h->bodyposX[i] - 40, h->bodyposY[i] - 32, cropX, 0, 80, 64, images[imgBoss]); |
} |
} |
} |
} |
} |
int checkWeaponCollision(Mask m) |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(weapons[i]->weaponMask, m) == 1) { |
return i; |
} |
} |
} |
} |
return -1; |
} |
double lengthdir_x(double ang, double len) |
{ |
return cos(ang * PI / 180) * len; |
} |
double lengthdir_y(double ang, double len) |
{ |
return sin(ang * PI / 180) * len; |
} |
double getHydraX(Hydrahead* h) |
{ |
if (enemies[h->bodyid] != NULL) { |
Hydra* hbody = enemies[h->bodyid]->data; |
return hbody->x; |
} |
return -1; |
} |
double getHydraY(Hydrahead* h) |
{ |
if (enemies[h->bodyid] != NULL) { |
Hydra* hbody = enemies[h->bodyid]->data; |
return hbody->y; |
} |
return -1; |
} |
void setHeadState(int headid, int state) |
{ |
if (enemies[headid] != NULL) { |
Hydrahead* h = enemies[headid]->data; |
if (h->state != 4) { |
h->state = state; |
h->timer = 0; |
h->counter = 0; |
} |
} |
} |
//#goop |
void createHydragoop(int x, int y, int hsp, int vsp) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Hydragoop* h = malloc(sizeof *h); |
h->id = i; |
h->x = x; |
h->y = y; |
h->hsp = hsp; |
h->vsp = vsp; |
h->inwall = 0; |
h->bounce = 0; |
h->imageIndex = 0; |
e->data = h; |
e->enemyStep = hydragoopStep; |
e->enemyDraw = hydragoopDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
PHL_PlaySound(sounds[sndPi06], CHN_ENEMIES); |
} |
} |
} |
void hydragoopStep(Hydragoop* h) |
{ |
char dead = 0; |
//Animate |
{ |
h->imageIndex += 0.16; |
if (h->imageIndex >= 3) { |
h->imageIndex -= 3; |
} |
} |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 36; |
mask.h = 36; |
mask.x = h->x - mask.w / 2; |
mask.y = h->y - mask.h / 2; |
} |
//Movement |
{ |
double grav = 0.2; |
h->x += h->hsp; |
mask.x = h->x - mask.w / 2; |
if (checkTileCollision(1, mask) == 1) { |
h->inwall = 1; |
} |
h->y += h->vsp; |
h->vsp += grav; |
mask.y = h->y - mask.h / 2; |
if (h->inwall == 0 && h->bounce == 0) { |
if (checkTileCollision(1, mask) == 1) { |
h->bounce = 1; |
h->vsp = -2; |
} |
} |
} |
//Outside of room |
{ |
if ( (h->y > 500 && h->vsp >= 0) || |
(h->x < -20 && h->hsp <= 0) || |
(h->x > 660 && h->hsp >= 0) ) |
{ |
dead = 1; |
} |
} |
//Collide with hero |
{ |
//Collide with shield |
if (checkCollision(mask, shieldMask) == 1) { |
createEffect(1, h->x - 20, h->y - 20); |
PHL_PlaySound(sounds[sndHit07], CHN_EFFECTS); |
dead = 1; |
} |
else if (checkCollision(mask, getHeroMask()) == 1) { |
if (heroHit(25, h->x) == 1) { |
heroPoison(); |
} |
} |
} |
//Destroy object |
{ |
if (dead == 1) { |
enemyDestroy(h->id); |
} |
} |
} |
void hydragoopDraw(Hydragoop* h) |
{ |
int cropX = 320; |
cropX += (int)h->imageIndex * 40; |
PHL_DrawSurfacePart(h->x - 20, h->y - 20, cropX, 480, 40, 40, images[imgMisc20]); |
} |
//#rock |
void createHydrarock() |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Hydrarock* h = malloc(sizeof *h); |
h->id = i; |
h->x = 70 + (rand() % 26) * 20; |
h->y = -24; |
h->vsp = 0; |
h->bounce = 0; |
h->imageIndex = 0; |
e->data = h; |
e->enemyStep = hydrarockStep; |
e->enemyDraw = hydrarockDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void hydrarockStep(Hydrarock* h) |
{ |
//Animate |
{ |
h->imageIndex += 0.25; |
if (h->imageIndex >= 8) { |
h->imageIndex -= 8; |
} |
} |
//Movement |
{ |
double grav = 0.15; |
h->y += h->vsp; |
h->vsp += grav; |
} |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 44; |
mask.h = 44; |
mask.x = h->x - mask.w / 2; |
mask.y = h->y - mask.h / 2; |
} |
if (h->bounce == 0) { |
if (checkTileCollision(1, mask) == 1) { |
h->bounce = 1; |
h->vsp = -2; |
PHL_PlaySound(sounds[sndHit06], CHN_ENEMIES); |
} |
} |
//Hero collision |
{ |
if (checkCollision(mask, getHeroMask()) == 1) { |
heroHit(30, h->x); |
} |
} |
//Weapon Collision |
{ |
int wid = checkWeaponCollision(mask); |
if (wid != -1) { |
weaponHit(weapons[wid]); |
PHL_PlaySound(sounds[sndHit03], CHN_WEAPONS); |
} |
} |
if (h->y >= 520) { |
enemyDestroy(h->id); |
} |
} |
void hydrarockDraw(Hydrarock* h) |
{ |
int cropX = 128; |
cropX += (int)h->imageIndex * 64; |
PHL_DrawSurfacePart(h->x - 32, h->y - 32, cropX, 128, 64, 64, images[imgMisc32]); |
} |
//#electricity |
void createHydrashock(int x, int y) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Hydrashock* h = malloc(sizeof *h); |
h->id = i; |
h->timer = 0; |
h->x = x; |
h->y = y; |
h->angle = 0; |
h->imageIndex = 0; |
e->data = h; |
e->enemyStep = hydrashockStep; |
e->enemyDraw = hydrashockDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
PHL_PlaySound(sounds[sndShot03], CHN_ENEMIES); |
} |
} |
} |
void hydrashockStep(Hydrashock* h) |
{ |
//Animate |
{ |
h->imageIndex += 0.5; |
if (h->imageIndex >= 4) { |
h->imageIndex -= 4; |
} |
} |
h->timer += 1; |
if (h->timer >= 20) { |
if (h->timer == 20) { |
//Set angle |
h->angle = (atan2(h->x - (herox), heroy + 20 - h->y) * 180 / PI) + 90; |
} |
h->timer = 22; |
//Movement |
{ |
int spd = 5; |
h->x += lengthdir_x(h->angle, spd); |
h->y += lengthdir_y(h->angle, spd); |
} |
} |
//Setup mask |
Mask mask; |
{ |
mask.unused = mask.circle = 0; |
mask.w = 28; |
mask.h = 28; |
mask.x = h->x - mask.w / 2; |
mask.y = h->y - mask.h / 2; |
} |
//Hero Collision |
{ |
if (checkCollision(mask, getHeroMask()) == 1) { |
if (heroHit(25, h->x) == 1) { |
heroStun(); |
} |
} |
} |
//Destroy if outside of room |
{ |
if (mask.x > 660 || mask.x + mask.w < -20 || mask.y > 500 || mask.y + mask.h < -20) { |
enemyDestroy(h->id); |
} |
} |
} |
void hydrashockDraw(Hydrashock* h) |
{ |
if (h->timer % 2 == 0) { |
int cropX = (int)h->imageIndex * 64; |
PHL_DrawSurfacePart(h->x - 32, h->y - 32, cropX, 192, 64, 64, images[imgMisc32]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/hydra.h |
---|
0,0 → 1,65 |
#ifndef HYDRA_H |
#define HYDRA_H |
typedef struct { |
int id; |
int hp, blink; |
double x, y; |
double hsp, vsp; |
double imageIndex; |
int state, timer; |
int patternCounter; |
char onground; |
char noheads; |
int headid[4]; |
} Hydra; |
void createHydra(int x); |
typedef struct { |
int id; |
int hp, blink; |
int dir; |
int position; //0 = lower 1 = higher |
double imageIndex; |
double neckRot; |
int state, timer, counter; |
int bodyid; |
double bodyposX[7]; |
double bodyposY[7]; |
} Hydrahead; |
int createHydrahead(int dir, int position, int bodyid); |
typedef struct { |
int id; |
double x, y; |
double hsp, vsp; |
char inwall; |
char bounce; |
double imageIndex; |
} Hydragoop; |
void createHydragoop(int x, int y, int hsp, int vsp); |
typedef struct { |
int id; |
double x, y; |
double vsp; |
char bounce; |
double imageIndex; |
} Hydrarock; |
void createHydrarock(); |
typedef struct { |
int id; |
int timer; |
double x, y; |
double angle; |
double imageIndex; |
} Hydrashock; |
void createHydrashock(int x, int y); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/jellyfish.c |
---|
0,0 → 1,195 |
#include "jellyfish.h" |
#include "../enemy.h" |
#include "../game.h" |
#include "../hero.h" |
#include <stdlib.h> |
#include <math.h> |
void jellyfishStep(Jellyfish* j); |
void jellyfishDraw(Jellyfish* j); |
void createJellyfish(int x, int y) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Jellyfish* j = malloc(sizeof *j); |
j->id = i; |
j->x = x; |
j->y = j->ystart = y; |
j->ystart += 20; |
j->spd = 0; |
j->angle = 0; |
j->state = 0; |
j->imageIndex = 0; |
e->data = j; |
e->enemyStep = jellyfishStep; |
e->enemyDraw = jellyfishDraw; |
e->type = 20; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void jellyfishStep(Jellyfish* j) |
{ |
Mask mask; |
mask.unused = mask.circle = 0; |
mask.w = mask.h = 30; |
mask.x = j->x + 20 - (mask.w / 2); |
mask.y = j->y + 20 - (mask.h / 2); |
//Idle float |
if (j->state == 0) |
{ |
//Animate |
j->imageIndex += 0.06; |
if (j->imageIndex >= 4) { |
j->imageIndex -= 4; |
} |
//Movement |
j->angle += 2.5; |
if (j->angle >= 360) { j->angle -= 360; } |
j->y = j->ystart + (20 * sin(j->angle * 3.14159 / 180)); |
//Update mask |
mask.y = j->y + 20 - (mask.h / 2); |
//if player is close enough |
Mask area; |
area.unused = area.circle = 0; |
area.w = area.h = 160; |
area.x = j->x - 60; |
area.y = j->y - 60; |
if (checkCollision(area, getHeroMask()) == 1) { |
j->state = 1; |
j->spd = 0; |
} |
} |
//Attack |
if (j->state == 1) |
{ |
//Setup |
if (j->spd == 0) { |
PHL_PlaySound(sounds[sndPi02], CHN_ENEMIES); |
j->spd = 3; |
//Move Right |
if (herox > j->x + 20) { |
//Move Up |
if (heroy < j->y) { |
j->angle = 135; |
} |
//Move Down |
else { |
j->angle = 45; |
} |
} |
//Move Left |
else{ |
//Move Up |
if (heroy < j->y) { |
j->angle = 225; |
} |
//Move Down |
else { |
j->angle = 315; |
} |
} |
} |
//Movement |
j->x += (j->spd) * sin(j->angle * 3.14159 / 180); |
j->y += (j->spd) * cos(j->angle * 3.14159 / 180); |
//Slow down |
j->spd -= 0.075; |
if (j->spd <= 0) { |
j->spd = 0; |
j->state = 2; |
} |
} |
//Stablize |
if (j->state == 2) |
{ |
//Setup |
if (j->spd == 0) { |
j->spd = 1; |
j->ystart = j->y - 20; |
j->angle = 80; |
} |
//Movement |
j->angle += 2.5; |
if (j->angle >= 360) { j->angle -= 360; } |
j->y = j->ystart + (20 * sin(j->angle * 3.14159 / 180)); |
if (j->angle >= 180) { |
j->state = 0; |
j->ystart = j->y - 20; |
j->angle = 100; |
} |
} |
//Update Mask |
mask.x = j->x + 20 - (mask.w / 2); |
mask.y = j->y + 20 - (mask.h / 2); |
//Collide with hero |
if (checkCollision(mask, getHeroMask())) { |
heroHit(15, j->x + 20); |
} |
//Sword collision |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
spawnCollectable(j->x + 20, j->y); |
weaponHit(weapons[i]); |
createEffect(2, j->x - 12, j->y - 12); |
enemyDestroy(j->id); |
i = MAX_WEAPONS; |
} |
} |
} |
} |
void jellyfishDraw(Jellyfish* j) |
{ |
int frame = 0; |
//if (j->state == 0) { |
int animation[4] = { 0, 1, 0, 2}; |
frame = animation[(int)j->imageIndex]; |
//} |
if (j->state == 1) { |
if (j->angle == 135) { |
frame = 3; |
} |
else if (j->angle == 225) { |
frame = 4; |
} |
else if (j->angle == 315) { |
frame = 5; |
} |
else { |
frame = 6; |
} |
} |
PHL_DrawSurfacePart(j->x, j->y, frame * 40, 520, 40, 40, images[imgEnemies]); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/jellyfish.h |
---|
0,0 → 1,16 |
#ifndef JELLYFISH_H |
#define JELLYFISH_H |
typedef struct { |
int id; |
double x, y; |
int ystart; |
double spd; |
double angle; |
int state; |
double imageIndex; |
} Jellyfish; |
void createJellyfish(int x, int y); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/knight.c |
---|
0,0 → 1,232 |
#include "knight.h" |
#include "../enemy.h" |
#include "../hero.h" |
#include "../PHL.h" |
#include "../game.h" |
#include <stdlib.h> |
void knightDestroy(Knight* k); |
void createKnight(int x, int y, int type) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Knight* k = malloc(sizeof *k); |
k->id = i; |
k->type = type; |
k->x = x; |
k->y = y; |
//They face the player when they are spawned |
k->dir = -1; |
if (herox > x + 20) { |
k->dir = 1; |
} |
k->vsp = 0; |
k->grav = 0.2; |
k->state = 0; |
k->timer = 60 + (((rand() % 5) + 1) * 60); |
k->imageIndex = 0; |
k->hp = 2; |
//Shield Knight |
if (k->type == 1) { |
k->hp = 3; |
} |
k->invincible = 0; |
k->shieldhit = 0; |
k->mask.circle = 0; |
k->mask.unused = 0; |
k->mask.x = x + 4; |
k->mask.y = y + 8; |
k->mask.w = 32; |
k->mask.h = 32; |
e->data = k; |
e->enemyStep = knightStep; |
e->enemyDraw = knightDraw; |
e->type = 3; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void knightStep(Knight* k) |
{ |
if (k->shieldhit > 0) { |
k->shieldhit -= 1; |
} |
if (k->invincible > 0) { |
k->invincible -= 1; |
} |
if (k->state == 0) { //Walk |
k->imageIndex += 0.1; |
if (k->imageIndex >= 2) { |
k->imageIndex -= 2; |
} |
double spd = 1; |
if (k->type == 1) { |
spd = 0.5; |
} |
spd *= k->dir; |
k->x += spd; |
k->mask.x = k->x + 4; |
k->mask.y = k->y + 8; |
Mask emask; |
emask.circle = emask.unused = 0; |
emask.w = 16; |
emask.h = 32; |
emask.x = k->x + 12; |
emask.y = k->y + 8; |
//Turn when colliding with a wall |
if (checkTileCollision(1, emask)) { |
k->dir *= -1; |
}else{ |
//Turn when on an edge |
k->mask.x += k->mask.w * k->dir; |
k->mask.y += 1; |
PHL_Rect collide = getTileCollision(1, k->mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, k->mask); |
} |
if (collide.x == -1) { |
k->dir *= -1; |
} |
} |
if (k->x + 20 >= 640 || k->x + 20 <= 0) { |
k->dir *= -1; |
} |
k->mask.x = k->x + 4; |
k->mask.y = k->y + 8; |
k->timer -= 1; |
if (k->timer <= 0) { |
k->state = 1; |
k->timer = 120; |
k->imageIndex = 0; |
} |
} |
else if (k->state == 1) { //Wait |
k->timer -= 1; |
if (k->timer <= 0) { |
k->state = 0; |
k->dir = 1; |
if (herox < k->x + 20) { |
k->dir = -1; |
} |
k->timer = 60 + (((rand() % 5) + 1) * 60); |
} |
} |
//Green Sword Knight |
if (k->type == 0) { |
//Hit player |
Mask swordMask; |
swordMask.unused = 0; |
swordMask.circle = 0; |
swordMask.x = k->x + (24 * k->dir); |
swordMask.y = k->y + 20; |
swordMask.w = 40; |
swordMask.h = 10; |
if (checkCollision(getHeroMask(), swordMask)) { |
heroHit(30, k->x + 20); |
} |
} |
if (checkCollision(getHeroMask(), k->mask)) { |
heroHit(15, k->x + 20); |
} |
//Weapon collision |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(k->mask, weapons[i]->weaponMask)) { |
char gotHit = 1; |
int weapondir = weapons[i]->dir; |
weaponHit(weapons[i]); |
//Shield Collision |
if (k->type == 1) { |
if (weapondir == k->dir * -1) { |
gotHit = 0; |
k->shieldhit = 15; |
PHL_PlaySound(sounds[sndHit03], CHN_WEAPONS); |
} |
} |
if (gotHit == 1) { |
k->hp -= 1; |
k->invincible = 15; |
i = MAX_WEAPONS; |
} |
if (k->hp <= 0) { |
knightDestroy(k); |
} |
} |
} |
} |
} |
} |
void knightDraw(Knight* k) |
{ |
if (k->invincible % 2 == 0) { |
int cx = 0, cy = 200; |
//Green Knight's Sword |
if (k->type == 0) { |
int swordimg = 0; |
if (k->dir == -1) { |
swordimg = 1; |
} |
int posx = 24, posy = 8; |
if ((int)k->imageIndex == 1) { |
posx -= 2; |
posy -= 2; |
} |
PHL_DrawSurfacePart(k->x + (posx * k->dir), k->y + posy, 160 + (swordimg * 40), 200, 40, 40, images[imgEnemies]); |
} |
//Shield Knight |
if (k->type == 1) { |
cx = 240; |
} |
if (k->dir == -1) { |
cx += 80; |
} |
PHL_DrawSurfacePart(k->x, k->y, cx + ((int)k->imageIndex * 40), cy, 40, 40, images[imgEnemies]); |
} |
} |
void knightDestroy(Knight* k) |
{ |
createEffect(2, k->x - 12, k->y - 6); |
spawnCollectable(k->x + 20, k->y); |
enemyDestroy(k->id); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/knight.h |
---|
0,0 → 1,23 |
#ifndef KNIGHT_H |
#define KNIGHT_H |
#include "../collision.h" |
typedef struct { |
int id, type; |
double x, y, |
vsp, grav; |
int dir, state, timer; |
double imageIndex; |
int hp, invincible; |
int shieldhit; |
Mask mask; |
} Knight; |
void createKnight(int x, int y, int type); |
void knightStep(Knight* k); |
void knightDraw(Knight* k); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/lolidra.c |
---|
0,0 → 1,367 |
#include "lolidra.h" |
#include "../enemy.h" |
#include "../game.h" |
#include "../hero.h" |
#include <stdlib.h> |
#include <math.h> |
int boss5flag = 38; |
void lolidraDestroy(Lolidra* l); |
int getNumOfMinions(); |
void createLolidra(int x, int y) |
{ |
if (flags[boss5flag] == 0) { //have not beaten boss 5 |
PHL_FreeSurface(images[imgBoss]); |
images[imgBoss] = PHL_LoadQDA("boss05.bmp"); |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
//Boss start |
setBossRoom(); |
Enemy* e = malloc(sizeof *e); |
Lolidra* l = malloc(sizeof *l); |
l->id = i; |
l->x = x; |
l->y = y; |
l->positionY = l->y; |
l->imageIndex = 0; |
l->hoverRot = 0; |
l->hp = 100; |
//l->hp = 1; |
l->state = 0; |
l->invincible = 0; |
l->visible = 1; |
l->timer = 0; |
l->counter = 0; |
l->mask.unused = 0; |
l->mask.circle = 1; |
l->mask.w = 46; |
l->mask.h = 0; |
l->mask.x = l->x; |
l->mask.y = l->y; |
e->data = l; |
e->enemyStep = lolidraStep; |
e->enemyDraw = lolidraDraw; |
e->type = 44; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
} |
void lolidraStep(Lolidra* l) |
{ |
char dead = 0; |
l->imageIndex += 0.1; |
if (l->imageIndex >= 3) { |
l->imageIndex -= 3; |
} |
if (l->invincible > 0) { |
l->invincible -= 1; |
} |
//Spawn minions |
if (l->state == 0) |
{ |
if (l->counter < 5) { |
l->counter += 1; |
}else{ |
if (getNumOfMinions() < 10) { |
l->counter = 0; |
PHL_PlaySound(sounds[sndPi02], CHN_ENEMIES); |
createMinion(l->x, l->y - 10); |
} |
} |
l->timer += 1; |
if (l->timer >= 600){ |
l->counter = 0; |
l->timer = 0; |
l->state = 1; |
l->invincible = 20; |
} |
} |
//Disappear |
else if (l->state == 1 || l->state == 3) |
{ |
if (l->invincible <= 0) { |
l->visible = 0; |
} |
if (l->timer == 0) { |
PHL_PlaySound(sounds[sndPi10], CHN_ENEMIES); |
} |
l->timer += 1; |
if (l->timer >= 330) { |
PHL_PlaySound(sounds[sndPi03], CHN_ENEMIES); |
l->timer = 0; |
l->visible = 1; |
l->invincible = 20; |
l->x = herox; |
l->positionY = heroy - 40; |
if (l->state == 1) { |
l->state = 2; |
} |
if (l->state == 3) { |
l->state = 0; |
} |
} |
} |
//Pop-up |
else if (l->state == 2) |
{ |
l->timer += 1; |
if (l->timer >= 180) { |
l->timer = 0; |
l->state = 3; |
l->invincible = 20; |
} |
} |
//Death |
else if (l->state == 4) |
{ |
l->y += 0.2; |
l->timer -= 1; |
l->invincible -= 1; |
if (l->timer % 12 == 0) { |
createEffect(2, l->x - 64 + (rand() % 128), l->y - 64 + (rand() % 128)); |
} |
if (l->timer <= 0) { |
lolidraDestroy(l); |
dead = 1; |
} |
} |
if (dead == 0) |
{ |
if (l->state != 4) { |
//Hover |
l->hoverRot += 5; |
if (l->hoverRot >= 360) { |
l->hoverRot -= 360; |
} |
l->y = l->positionY + (5 * sin(l->hoverRot * 3.14159 / 180)); |
//Update Mask |
l->mask.x = l->x; |
l->mask.y = l->y; |
//Collisions |
if (l->visible == 1) { |
//Collide with Hero |
if (checkCollision(getHeroMask(), l->mask) == 1) { |
heroHit(30, l->x); |
} |
//Weapon collision |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(l->mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
l->invincible = 15; |
l->hp -= 1; |
//Die |
if (l->hp <= 0) { |
l->state = 4; |
l->timer = 180; |
l->invincible = 200; |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
} |
} |
} |
void lolidraDraw(Lolidra* l) |
{ |
if (l->visible == 1 && l->invincible % 2 == 0) { |
PHL_DrawSurfacePart(l->x - 64, l->y - 74, ((int)l->imageIndex) * 128, 0, 128, 128, images[imgBoss]); |
} |
} |
void lolidraDestroy(Lolidra* l) |
{ |
enemyDestroy(l->id); |
bossDefeatedFlag = 1; |
roomSecret = 1; |
flags[boss5flag] = 1; |
PHL_StopMusic(); |
} |
//Minions |
void createMinion(int x, int y) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Minion* m = malloc(sizeof *m); |
m->id = i; |
m->state = 0; |
m->timer = 0; |
m->x = x; |
m->y = y; |
m->positionY = m->y; |
m->dir = rand() % 360; |
m->spd = 8; |
m->imageIndex = 0; |
m->mask.circle = 1; |
m->mask.unused = 0; |
m->mask.w = 10; |
m->mask.x = 0; |
m->mask.y = 0; |
e->data = m; |
e->enemyStep = minionStep; |
e->enemyDraw = minionDraw; |
e->type = 23; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void minionStep(Minion* m) |
{ |
char dead = 0; |
m->imageIndex += 0.2; |
if (m->imageIndex >= 2) { |
m->imageIndex -= 2; |
} |
//Slow down |
if (m->state == 0) |
{ |
if (m->spd > 0) { |
m->spd -= 0.3; |
} |
if (m->spd <= 0) { |
m->positionY = m->y; |
m->spd = 0; |
m->dir = 0; |
m->state = 1; |
} |
} |
//Hover |
else if (m->state == 1) |
{ |
//Hover |
m->dir += 5; |
if (m->dir >= 360) { |
m->dir -= 360; |
} |
m->y = m->positionY + (10 * sin(m->dir * 3.14159 / 180)); |
m->timer += 1; |
if (m->timer >= 120) { |
m->timer = 0; |
m->state = 2; |
m->spd = (rand() % 2) + 1; |
m->dir = (atan2(heroy + 20 - m->y, m->x - herox) * 180 / 3.14159) + 270; |
} |
} |
//Suicide |
else if (m->state == 2) |
{ |
m->timer += 1; |
if (m->timer >= 120) { |
createEffect(5, m->x, m->y); |
enemyDestroy(m->id); |
dead = 1; |
} |
} |
if (dead == 0) |
{ |
//Movement |
if (m->spd != 0) { |
m->x += m->spd * sin(m->dir * 3.14159 / 180); |
m->y += m->spd * cos(m->dir * 3.14159 / 180); |
} |
//Update Mask |
m->mask.x = m->x; |
m->mask.y = m->y; |
//Collide with Hero |
if (checkCollision(getHeroMask(), m->mask) == 1) { |
if (heroHit(10, m->x) == 1) { |
heroPoison(); |
} |
} |
//Weapon collision |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (checkCollision(m->mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
createEffect(2, m->x - 32, m->y - 32); |
enemyDestroy(m->id); |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
void minionDraw(Minion* m) |
{ |
PHL_DrawSurfacePart(m->x - 32, m->y - 32, ((int)m->imageIndex) * 64, 128, 64, 64, images[imgBoss]); |
} |
int getNumOfMinions() |
{ |
int result = 0; |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] != NULL) { |
if (enemies[i]->type == 23) { |
result += 1; |
} |
} |
} |
return result; |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/lolidra.h |
---|
0,0 → 1,40 |
#ifndef LOLIDRA_H |
#define LOLIDRA_H |
#include "../collision.h" |
typedef struct { |
int id; |
double x, y; |
double positionY; |
double imageIndex, hoverRot; |
int hp, state, invincible, |
visible, timer, counter; |
Mask mask; |
} Lolidra; |
void createLolidra(int x, int y); |
void lolidraStep(Lolidra* l); |
void lolidraDraw(Lolidra* l); |
//Minion |
typedef struct { |
int id; |
int state; |
int timer; |
double x, y; |
double positionY; |
double imageIndex; |
double dir, spd; |
Mask mask; |
} Minion; |
void createMinion(int x, int y); |
void minionStep(Minion* m); |
void minionDraw(Minion* m); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/pendulum.c |
---|
0,0 → 1,78 |
#include "pendulum.h" |
#include "../enemy.h" |
#include "../game.h" |
#include "../hero.h" |
#include <stdlib.h> |
#include <math.h> |
void createPendulum(int x, int y, int side) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Pendulum* p = malloc(sizeof *p); |
p->id = i; |
p->x = x; |
p->y = y; |
p->angle = 0; |
p->rotCounter = 180; |
if (side == 1) { |
p->rotCounter += 180; |
} |
p->mask.circle = 1; |
p->mask.unused = 0; |
p->mask.w = 24; |
p->mask.x = 0; |
p->mask.y = 0; |
e->data = p; |
e->enemyStep = pendulumStep; |
e->enemyDraw = pendulumDraw; |
e->type = 22; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void pendulumStep(Pendulum* p) |
{ |
p->rotCounter += 2; |
if (p->rotCounter >= 360) { |
p->rotCounter -= 360; |
} |
p->angle += (3.15 * cos(p->rotCounter * 3.14159 / 180)); |
//Update Mask |
p->mask.x = p->x + (96 * cos((p->angle + 90) * 3.14159 / 180)); |
p->mask.y = p->y + (96 * sin((p->angle + 90) * 3.14159 / 180)); |
//Hit Player |
if (checkCollision(p->mask, getHeroMask())) { |
heroHit(15, p->mask.x); |
} |
} |
void pendulumDraw(Pendulum* p) |
{ |
int drawX = p->x, |
drawY = p->y; |
int len[] = {0, 16, 32, 48, 66, 96}; |
int cropX[] = {64, 64, 64, 64, 0, 576}; |
int cropY[] = {128, 128, 128, 128, 128, 64}; |
int i; |
for (i = 0; i < 6; i++) { |
drawX = p->x + (len[i] * cos((p->angle + 90) * 3.14159 / 180)); |
drawY = p->y + (len[i] * sin((p->angle + 90) * 3.14159 / 180)); |
PHL_DrawSurfacePart(drawX- 32, drawY - 32, cropX[i], cropY[i], 64, 64, images[imgMisc32]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/pendulum.h |
---|
0,0 → 1,19 |
#ifndef PENDULUM_H |
#define PENDULUM_H |
#include "../collision.h" |
typedef struct { |
int id; |
double x, y; |
double rotCounter, angle; |
Mask mask; |
} Pendulum; |
void createPendulum(int x, int y, int side); |
void pendulumStep(Pendulum* p); |
void pendulumDraw(Pendulum* p); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/podoboo.c |
---|
0,0 → 1,176 |
#include "podoboo.h" |
#include "../PHL.h" |
#include "../hero.h" |
#include "../game.h" |
#include "../effect.h" |
#include <stdlib.h> |
#include <math.h> |
void podobooStep(Podoboo* p); |
void podobooDraw(Podoboo* p); |
void createPodoboo(int x, int y, int offset, int height) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Podoboo* p = malloc(sizeof *p); |
p->id = i; |
p->x = x; |
p->y = p->ystart = y; |
p->hp = 2; |
p->blink = 0; |
p->yoffset = p->rot = 0; |
p->vsp = 0; |
p->grav = 0.13; |
p->jumpheight = -5; |
/* |
if (height == 1) { |
p->jumpheight = -5.4; |
} |
*/ |
if (height == 1) { |
p->jumpheight = -7; |
} |
p->imageIndex = 0; |
p->timer = 30 * offset; |
p->state = 0; |
e->data = p; |
e->enemyStep = podobooStep; |
e->enemyDraw = podobooDraw; |
e->type = 15; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void podobooStep(Podoboo* p) |
{ |
//Blinking |
{ |
if (p->blink > 0) { |
p->blink -= 1; |
} |
} |
p->timer -= 1; |
//Patterns |
{ |
//Float in lava |
if (p->state == 0) |
{ |
//Animate |
p->imageIndex += 0.1; |
if (p->imageIndex >= 2) { |
p->imageIndex -= 2; |
} |
//Bob movement |
p->rot += 5; |
if (p->rot >= 360) { |
p->rot -= 360; |
} |
p->y = p->ystart + (5 * sin(p->rot * 3.14159 / 180)); |
//Jump |
if (p->timer <= 0) { |
p->state = 1; |
createLavaSplash(p->x + 20, p->y); |
p->y = p->ystart; |
p->vsp = p->jumpheight; |
} |
} |
//In air |
else if (p->state == 1) |
{ |
//Animate |
p->imageIndex += 0.25; |
if (p->imageIndex >= 3) { |
p->imageIndex -= 3; |
} |
//Movement |
p->y += p->vsp; |
p->vsp += p->grav; |
//Land in lava again |
if (p->vsp > 0 && p->y >= p->ystart) { |
createLavaSplash(p->x + 20, p->y); |
p->y = p->ystart; |
p->state = 0; |
p->vsp = 0; |
p->timer = 60; |
} |
} |
} |
//Create Mask |
Mask mask; |
{ |
mask.unused = mask.circle = 0; |
mask.w = mask.h = 30; |
mask.x = p->x + 5; |
mask.y = p->y + 5; |
} |
//Collide with hero |
{ |
if (checkCollision(mask, getHeroMask())) { |
heroHit(15, mask.x + (mask.w / 2)); |
} |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
p->hp -= 1; |
p->blink = 15; |
//Death |
if (p->hp <= 0) { |
createEffect(2, p->x - 12, p->y - 12); |
spawnCollectable(p->x + 20, p->y); |
enemyDestroy(p->id); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
} |
void podobooDraw(Podoboo* p) |
{ |
if (p->blink % 2 == 0) { |
int thisImage = p->imageIndex; |
if (p->state == 1) { |
thisImage += 2; |
} |
PHL_DrawSurfacePart(p->x, p->y, 280 + (40 * thisImage), 520, 40, 40, images[imgEnemies]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/podoboo.h |
---|
0,0 → 1,20 |
#ifndef PODOBOO_H |
#define PODOBOO_H |
typedef struct { |
int id; |
double x, y; |
int ystart; |
int hp; |
int blink; |
int rot; |
double yoffset; |
double vsp, grav; |
double jumpheight; |
double imageIndex; |
int timer, state; |
} Podoboo; |
void createPodoboo(int x, int y, int offset, int height); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/poisonknight.c |
---|
0,0 → 1,318 |
#include "poisonknight.h" |
#include "../game.h" |
#include "../hero.h" |
#include <stdlib.h> |
void poisonknightStep(Poisonknight* p); |
void poisonknightDraw(Poisonknight* p); |
void goopStep(Goop* g); |
void goopDraw(Goop* g); |
void createPoisonknight(int x, int y) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Poisonknight* p = malloc(sizeof *p); |
p->id = i; |
p->hp = 2; |
p->x = x; |
p->y = y; |
p->imageIndex = 0; |
p->dir = 1; |
if (herox < p->x) { |
p->dir = -1; |
} |
p->blink = 0; |
p->timer = 0; |
p->state = 0; |
e->data = p; |
e->enemyStep = poisonknightStep; |
e->enemyDraw = poisonknightDraw; |
e->type = 29; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void poisonknightStep(Poisonknight* p) |
{ |
char dead = 0; |
//Animate |
{ |
p->imageIndex += 0.1; |
if (p->imageIndex >= 2) { |
p->imageIndex -= 2; |
} |
if (p->blink > 0) { |
p->blink -= 1; |
} |
} |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 38; |
mask.h = 36; |
mask.x = p->x + ((40 - mask.w) / 2); |
mask.y = p->y + (40 - mask.h); |
} |
//Walk |
if (p->state == 0) { |
double hsp = 1; |
p->x += hsp * p->dir; |
mask.x = p->x + ((40 - mask.w) / 2); |
//Hit wall |
if (checkTileCollision(1, mask) == 1) { |
p->dir *= -1; |
} |
//On wall edge |
else { |
mask.x += mask.w * p->dir; |
mask.y += 10; |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x == -1) { |
p->dir *= -1; |
} |
} |
//Hero is close enough |
{ |
if (p->timer <= 0) { |
Mask area; |
area.circle = area.unused = 0; |
area.x = p->x - 110; |
area.y = p->y; |
area.w = 260; |
area.h = 40; |
if (checkCollision(area, getHeroMask()) == 1) { |
p->dir = 1; |
if (herox < p->x + 20) { |
p->dir = -1; |
} |
p->imageIndex = 1; |
p->timer = 0; |
p->state = 1; |
} |
}else{ |
p->timer -= 1; |
} |
} |
} |
//*beat* |
else if (p->state == 1) |
{ |
//Animate |
p->imageIndex = 1; |
p->timer += 1; |
if (p->timer >= 15) { |
p->state = 2; |
p->timer = 0; |
p->imageIndex = 2; |
} |
} |
//Shoot goop |
else if (p->state == 2) |
{ |
//Shoot goop |
if (p->timer == 0) { |
PHL_PlaySound(sounds[sndPi05], CHN_ENEMIES); |
createGoop(p->x + (20 * p->dir), p->y - 2, p->dir); |
} |
//Animate |
p->imageIndex = 2; |
p->timer += 1; |
if (p->timer >= 25) { |
p->state = 0; |
p->timer = 240; |
} |
} |
//Update Mask |
mask.x = p->x + ((40 - mask.w) / 2); |
mask.y = p->y + (40 - mask.h); |
//Collide with hero |
{ |
if (checkCollision(mask, getHeroMask()) == 1) { |
heroHit(15, mask.x + (mask.w / 2)); |
} |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
p->hp -= 1; |
p->blink = 15; |
if (p->hp <= 0) { |
dead = 1; |
createEffect(2, p->x - 12, p->y - 6); |
spawnCollectable(p->x + 20, p->y); |
} |
} |
} |
} |
} |
} |
//Destroy object |
{ |
if (dead == 1) { |
enemyDestroy(p->id); |
} |
} |
} |
void poisonknightDraw(Poisonknight* p) |
{ |
if (p->blink % 2 == 0) { |
int cropX = (int)p->imageIndex * 40; |
if (p->dir == -1) { |
cropX += 120; |
} |
PHL_DrawSurfacePart(p->x, p->y, cropX, 280, 40, 40, images[imgEnemies]); |
} |
} |
//Poison Goop |
void createGoop(int x, int y, int dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Goop* g = malloc(sizeof *g); |
g->id = i; |
g->x = x; |
g->y = y; |
g->dir = dir; |
g->imageIndex = 0; |
e->data = g; |
e->enemyStep = goopStep; |
e->enemyDraw = goopDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void goopStep(Goop* g) |
{ |
char dead = 0; |
//Animate |
{ |
g->imageIndex += 0.33; |
if (g->imageIndex >= 3) { |
g->imageIndex -= 3; |
} |
} |
//Movement |
{ |
int hsp = 4; |
g->x += hsp * g->dir; |
} |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 22; |
mask.h = 22; |
mask.x = g->x + ((40 - mask.w) / 2); |
mask.y = g->y + ((40 - mask.h) / 2); |
} |
//Collide with hero |
{ |
//Collide with shield |
if (checkCollision(mask, shieldMask) == 1) { |
dead = 1; |
PHL_PlaySound(sounds[sndHit07], CHN_EFFECTS); |
createEffect(1, g->x, g->y); |
} |
//Collide with hero |
else if (checkCollision(mask, getHeroMask()) == 1) { |
if (heroHit(10, mask.x + (mask.w / 2)) == 1) { |
heroPoison(); |
} |
} |
} |
//Collide with wall |
{ |
if (checkTileCollision(1, mask) == 1) { |
dead = 1; |
createEffect(1, g->x, g->y); |
} |
} |
//Destroy if out of room |
{ |
if (g->x + 40 < 0 || g->x > 640) { |
dead = 1; |
} |
} |
//Destroy object |
{ |
if (dead == 1) { |
enemyDestroy(g->id); |
} |
} |
} |
void goopDraw(Goop* g) |
{ |
int cropX = 400 + ((int)g->imageIndex * 40); |
if (g->dir == -1) { |
cropX += 120; |
} |
PHL_DrawSurfacePart(g->x, g->y, cropX, 520, 40, 40, images[imgMisc20]); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/poisonknight.h |
---|
0,0 → 1,26 |
#ifndef POISONKNIGHT_H |
#define POISONKNIGHT_H |
typedef struct { |
int id; |
int hp; |
double x, y; |
double imageIndex; |
int dir; |
int blink; |
int timer; |
int state; |
} Poisonknight; |
void createPoisonknight(int x, int y); |
typedef struct { |
int id; |
double x, y; |
int dir; |
double imageIndex; |
} Goop; |
void createGoop(int x, int y, int dir); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/pumpkin.c |
---|
0,0 → 1,375 |
#include "pumpkin.h" |
#include "../game.h" |
#include "../hero.h" |
#include <stdlib.h> |
void pumpkinenemyStep(Pumpkinenemy* p); |
void pumpkinenemyDraw(Pumpkinenemy* p); |
void pumpkinheadStep(Pumpkinhead* p); |
void pumpkinheadDraw(Pumpkinhead* p); |
void createPumpkinenemy(int x, int y) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Pumpkinenemy* p = malloc(sizeof *p); |
p->id = i; |
p->hp = 3; |
p->blink = 0; |
p->x = x; |
p->y = y; |
p->dir = 1; |
if (herox < p->x + 20) { |
p->dir = -1; |
} |
p->imageIndex = 0; |
p->state = 0; |
p->timer = 0; |
e->data = p; |
e->enemyStep = pumpkinenemyStep; |
e->enemyDraw = pumpkinenemyDraw; |
e->type = 32; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void pumpkinenemyStep(Pumpkinenemy* p) |
{ |
//Setup Mask |
Mask mask; |
{ |
mask.unused = mask.circle = 0; |
mask.w = 20; |
mask.h = 38; |
mask.x = p->x + ((40 - mask.w) / 2); |
mask.y = p->y + (40 - mask.h); |
} |
//Animate |
{ |
p->imageIndex += 0.1; |
if (p->imageIndex >= 2) { |
p->imageIndex -= 2; |
} |
if (p->blink > 0) { |
p->blink -= 1; |
} |
} |
//Walking |
if (p->state == 0) |
{ |
double hsp = 0.5; |
p->x += hsp * p->dir; |
mask.x = p->x + ((40 - mask.w) / 2); |
//Hit wall |
{ |
if (checkTileCollision(1, mask) == 1 || mask.x > 640 || mask.x + mask.w < 0) { |
p->dir *= -1; |
} |
} |
//On edge |
{ |
mask.x += mask.w * p->dir; |
mask.y += 20; |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x == -1) { |
p->dir *= -1; |
} |
} |
//Player is close |
{ |
if (p->timer <= 0) { |
Mask area; |
{ |
area.circle = area.unused = 0; |
area.w = 240; |
area.h = 80; |
area.x = p->x - 100; |
area.y = p->y - 40; |
} |
if (checkCollision(area, getHeroMask()) == 1) { |
p->state = 1; |
p->timer = 0; |
p->dir = 1; |
if (herox < p->x + 20) { |
p->dir = -1; |
} |
} |
}else{ |
p->timer -= 1; |
} |
} |
} |
//Deheaded |
else if (p->state == 1) { |
//Animate |
{ |
p->imageIndex = 0; |
if (p->timer >= 15) { |
p->imageIndex = 2; |
} |
} |
p->timer += 1; |
if (p->timer == 15) { |
createPumpkinhead(p->x, p->y - 6, p->dir); |
PHL_PlaySound(sounds[sndPi05], CHN_ENEMIES); |
} |
if (p->timer >= 40) { |
p->state = 0; |
p->imageIndex = 0; |
p->timer = 300; |
} |
} |
//Update Mask |
mask.x = p->x + ((40 - mask.w) / 2); |
mask.y = p->y + (40 - mask.h); |
//Hero Collision |
{ |
if (checkCollision(mask, getHeroMask()) == 1) { |
heroHit(15, mask.x + (mask.w / 2)); |
} |
} |
//Weapon Collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
p->hp -= 1; |
p->blink = 15; |
//Death |
if (p->hp <= 0) { |
createEffect(2, p->x - 12, p->y - 6); |
spawnCollectable(p->x + 20, p->y); |
enemyDestroy(p->id); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
} |
void pumpkinenemyDraw(Pumpkinenemy* p) |
{ |
if (p->blink % 2 == 0) { |
int cropX = (int)p->imageIndex * 40; |
if (p->dir == -1) { |
cropX += 120; |
} |
PHL_DrawSurfacePart(p->x, p->y, cropX, 560, 40, 40, images[imgEnemies]); |
} |
} |
//Pumpkin bomb head |
void createPumpkinhead(int x, int y, int dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Pumpkinhead* p = malloc(sizeof *p); |
p->id = i; |
p->dir = dir; |
p->x = x; |
p->y = y; |
p->vsp = -2; |
p->imageIndex = 0; |
p->state = 0; |
p->timer = 0; |
e->data = p; |
e->enemyStep = pumpkinheadStep; |
e->enemyDraw = pumpkinheadDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void pumpkinheadStep(Pumpkinhead* p) |
{ |
char dead = 0; |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 20; |
mask.h = 22; |
mask.x = p->x + ((40 - mask.w) / 2); |
mask.y = p->y + ((40 - mask.h) / 2); |
} |
//Pumpkin head |
if (p->state == 0) |
{ |
char explode = 0; |
//Animate |
{ |
p->imageIndex += 0.1; |
if (p->imageIndex >= 2) { |
p->imageIndex -= 2; |
} |
} |
//Movement |
{ |
int hsp = 3; |
p->x += hsp * p->dir; |
mask.x = p->x + ((40 - mask.w) / 2); |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
p->x = collide.x + 20 - ((20 + (mask.w / 2)) * p->dir) - 20; |
mask.x = p->x + ((40 - mask.w) / 2); |
p->dir *= -1; |
} |
double grav = 0.15; |
p->y += p->vsp; |
p->vsp += grav; |
mask.y = p->y + ((40 - mask.h) / 2); |
collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x != -1) { |
p->y = collide.y - 40; |
explode = 1; |
} |
} |
//Update Mask |
mask.x = p->x + ((40 - mask.w) / 2); |
mask.y = p->y + ((40 - mask.h) / 2); |
//Explode |
{ |
if (explode == 1) { |
PHL_PlaySound(sounds[sndBom03], CHN_ENEMIES); |
p->state = 1; |
p->imageIndex = 0; |
p->timer = 0; |
} |
} |
//Outside of room |
{ |
if (mask.y > 480 || mask.x > 640 || mask.x + mask.w < 0) { |
dead = 1; |
} |
} |
} |
//Explosion |
else if (p->state == 1) |
{ |
//Update Mask |
{ |
mask.w = 68; |
mask.h = 66; |
mask.x = p->x - 44 + 64 - (mask.w / 2); |
mask.y = p->y - 44 + (84 - mask.h); |
} |
//Animate |
{ |
p->imageIndex += 0.33; |
if (p->imageIndex >= 12) { |
dead = 1; |
} |
} |
//Hero Collision |
{ |
if (checkCollision(mask, getHeroMask()) == 1) { |
heroHit(40, mask.x + (mask.w / 2)); |
} |
} |
} |
//Destroy object |
{ |
if (dead == 1) { |
enemyDestroy(p->id); |
} |
} |
} |
void pumpkinheadDraw(Pumpkinhead* p) |
{ |
if (p->state == 0) { |
int cropX = (int)p->imageIndex * 40; |
if (p->dir == -1) { |
cropX += 80; |
} |
PHL_DrawSurfacePart(p->x, p->y, cropX, 240, 40, 40, images[imgEnemies]); |
} |
if (p->state == 1) { |
int cropX = (int)p->imageIndex * 128; |
int cropY = 0; |
while (cropX >= 640) { |
cropX -= 640; |
cropY += 96; |
} |
PHL_DrawSurfacePart(p->x - 44, p->y - 44, cropX, cropY, 128, 96, images[imgExplosion]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/pumpkin.h |
---|
0,0 → 1,27 |
#ifndef PUMPKIN_H |
#define PUMPKIN_H |
typedef struct { |
int id; |
int hp; |
int blink; |
double x, y; |
int dir; |
double imageIndex; |
int state, timer; |
} Pumpkinenemy; |
void createPumpkinenemy(int x, int y); |
typedef struct { |
int id; |
int dir; |
double x, y; |
double vsp; |
double imageIndex; |
int state, timer; |
} Pumpkinhead; |
void createPumpkinhead(int x, int y, int dir); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/seal.c |
---|
0,0 → 1,204 |
#include "seal.h" |
#include "../game.h" |
#include "../enemy.h" |
#include "../collision.h" |
#include "../hero.h" |
#include <stdlib.h> |
void sealStep(Seal* s); |
void sealDraw(Seal* s); |
void createSeal(int x, int y) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Seal* s = malloc(sizeof *s); |
s->id = i; |
s->hp = 2; |
s->x = x; |
s->y = y; |
s->imageIndex = 0; |
s->dir = 1; |
if (x + 20 > herox) { |
s->dir = -1; |
} |
s->state = 0; |
s->timer = 0; |
s->invincible = 0; |
e->data = s; |
e->enemyStep = sealStep; |
e->enemyDraw = sealDraw; |
e->type = 19; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void sealStep(Seal* s) |
{ |
if (s->invincible > 0) { |
s->invincible -= 1; |
} |
Mask mask; |
mask.unused = mask.circle = 0; |
mask.w = mask.h = 28; |
mask.x = s->x + ((40 - mask.w) / 2); |
mask.y = s->y + (40 - mask.h); |
//Walk |
if (s->state == 0) |
{ |
//Animate |
s->imageIndex += 0.1; |
if (s->imageIndex >= 2) { |
s->imageIndex -= 2; |
} |
//Check if hit a wall |
if (checkTileCollision(1, mask) == 1) { |
s->dir *= -1; |
}else{ |
//Check if on edge |
mask.x += mask.w * s->dir; |
mask.y += mask.h; |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x == -1) { |
s->dir *= -1; |
} |
mask.x = s->x + ((40 - mask.w) / 2); |
mask.y = s->y + (40 - mask.h); |
} |
//Movement |
s->x += 0.5 * s->dir; |
if (s->timer <= 0) { |
//Check if player is close enough |
Mask area; |
area.unused = area.circle = 0; |
area.x = s->x - 40; |
area.y = s->y; |
area.w = 120; |
area.h = 120; |
if (checkCollision(area, getHeroMask()) == 1) { |
s->state = 1; |
s->timer = -1; |
} |
}else{ |
s->timer -= 1; |
} |
} |
//Rear back |
else if (s->state == 1) |
{ |
//Setup |
if (s->timer == -1) { |
s->imageIndex = 4; |
s->timer = 20; |
} |
s->timer -= 1; |
if (s->timer <= 0) { |
s->state = 2; |
s->timer = -1; |
s->imageIndex = 0; |
} |
} |
//Tounge attack |
else if (s->state == 2) |
{ |
//Setup |
if (s->timer == -1) { |
s->timer = 0; |
PHL_PlaySound(sounds[sndGet01], CHN_ENEMIES); |
} |
//Animate |
int animation[41] = {0, 1, 1, 2, 2, 3, 3, 4, 4, 4, |
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
4, 4, 4, 4, 4, 4, 4, 4, 3, 3, |
2, 2, 1, 1, 0, 0, 5, 5, 5, 5, 5 }; |
s->imageIndex = animation[(int)s->timer]; |
//Update mask height to fit tounge |
int len[6] = { 18, 38, 58, 64, 66, 0}; |
mask.h += len[(int)s->imageIndex]; |
s->timer += 1; |
if (s->timer >= 41) { |
s->state = 0; |
s->timer = 120; |
s->imageIndex = 0; |
} |
} |
//Hit Player |
if (checkCollision(mask, getHeroMask())) { |
heroHit(10, s->x + 20); |
} |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
s->hp -= 1; |
s->invincible = 15; |
weaponHit(weapons[i]); |
if (s->hp <= 0) { |
enemyDestroy(s->id); |
createEffect(2, s->x - 12, s->y - 6); |
spawnCollectable(s->x + 20, s->y); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
void sealDraw(Seal* s) |
{ |
if (s->invincible % 2 == 0) { |
int cx = 400 + ((int)s->imageIndex * 40); |
if (s->state == 0) { |
if (s->dir == -1) { |
cx += 80; |
} |
} |
if (s->state == 2) { |
cx = 600; |
} |
PHL_DrawSurfacePart(s->x, s->y, cx, 200, 40, 40, images[imgEnemies]); |
//Draw tounge |
if (s->state == 2) { |
PHL_DrawSurfacePart(s->x, s->y + 28, 200 + ((int)s->imageIndex * 40), 0, 40, 80, images[imgMisc2040]); |
} |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/seal.h |
---|
0,0 → 1,14 |
#ifndef SEAL_H |
#define SEAL_H |
typedef struct { |
int id, hp; |
double x, y; |
double imageIndex; |
int dir, state, timer; |
int invincible; |
} Seal; |
void createSeal(int x, int y); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/skeleton.c |
---|
0,0 → 1,298 |
#include "skeleton.h" |
#include "../enemy.h" |
#include "../game.h" |
#include "../PHL.h" |
#include "../hero.h" |
#include <stdlib.h> |
void skeletonStep(Skeleton* s); |
void skeletonDraw(Skeleton* s); |
void boneStep(Bone* b); |
void boneDraw(Bone* b); |
void createSkeleton(int x, int y, int dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Skeleton* s = malloc(sizeof *s); |
s->id = i; |
s->x = x; |
s->y = y; |
s->imageIndex = 0; |
s->dir = 1; |
if (dir == 1) { |
s->dir = -1; |
} |
s->hsp = 0.5 * s->dir; |
s->hp = 2; |
s->state = 0; |
s->timer = 0; |
s->invincible = 0; |
s->mask.unused = s->mask.circle = 0; |
s->mask.w = 24; |
s->mask.h = 36; |
s->mask.x = s->x + 8; |
s->mask.y = s->y + 4; |
e->data = s; |
e->enemyStep = skeletonStep; |
e->enemyDraw = skeletonDraw; |
e->type = 17; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void skeletonStep(Skeleton* s) |
{ |
if (s->invincible > 0) { |
s->invincible -= 1; |
} |
//Collide with wall |
if (checkTileCollision(1, s->mask) == 1) { |
s->hsp *= -1; |
}else{ |
//Check if on ledge |
int tempdir = 1; |
if (s->hsp < 0) { |
tempdir = -1; |
} |
s->mask.x += tempdir * s->mask.w; |
s->mask.y += 10; |
if (checkTileCollision(1, s->mask) == 0 && checkTileCollision(3, s->mask) == 0) { |
s->hsp *= -1; |
} |
s->mask.y -= 10; |
s->mask.x = s->x + 8; |
} |
s->x += s->hsp; |
if (s->timer >= 0) { |
s->timer -= 1; |
} |
//Walk around |
if (s->state == 0) |
{ |
s->imageIndex += 0.1; |
if (s->hsp < 0) { |
s->dir = -1; |
s->hsp = -0.5; |
}else if (s->hsp > 0) { |
s->dir = 1; |
s->hsp = 0.5; |
}else{ |
s->hsp = 0.5 * s->dir; |
} |
if (s->timer <= 0) { |
//If hero is too close |
Mask area; |
area.unused = area.circle = 0; |
area.x = s->x - 80; |
area.y = s->y - 20; |
area.w = 200; |
area.h = 80; |
if (checkCollision(area, getHeroMask()) == 1) { |
s->state = 1; |
s->timer = 30; |
s->hsp = 0; |
s->dir = 1; |
if (herox < s->mask.x + (s->mask.w / 2)) { |
s->dir = -1; |
} |
} |
} |
} |
//Alert |
else if (s->state == 1) |
{ |
s->hsp = 0; |
s->imageIndex += 0.1; |
if (s->timer <= 0) { |
s->state = 2; |
s->hsp = 2.5 * -s->dir; |
PHL_PlaySound(sounds[sndPi05], CHN_ENEMIES); |
} |
} |
//Slide backwards |
else if (s->state == 2) |
{ |
s->imageIndex = 0; |
double fric = 0.075; |
if (s->hsp > 0) { |
s->hsp -= fric; |
if (s->hsp <= 0) { s->hsp = 0; } |
} |
else if (s->hsp < 0) { |
s->hsp += fric; |
if (s->hsp >= 0) { s->hsp = 0; } |
} |
if (s->hsp == 0) { |
s->state = 3; |
s->timer = 30; |
createBone(s->x, s->y, s->dir); |
PHL_PlaySound(sounds[sndShot05], CHN_ENEMIES); |
} |
} |
//Throw bone |
else if (s->state == 3) |
{ |
s->imageIndex += 0.1; |
if (s->timer <= 0) { |
s->timer = 0; |
s->state = 0; |
} |
} |
if (s->imageIndex >= 2) { |
s->imageIndex -= 2; |
} |
//Update mask |
s->mask.x = s->x + 8; |
//Hit Player |
if (checkCollision(s->mask, getHeroMask())) { |
heroHit(10, s->x + 20); |
} |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(s->mask, weapons[i]->weaponMask)) { |
s->hp -= 1; |
s->invincible = 15; |
weaponHit(weapons[i]); |
if (s->hp <= 0) { |
createRockSmash(s->x + 20, s->y + 20); |
spawnCollectable(s->x + 20, s->mask.y + s->mask.h - 40); |
enemyDestroy(s->id); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
void skeletonDraw(Skeleton* s) |
{ |
if (s->invincible % 2 == 0) { |
int dx = 160 + ((int)s->imageIndex * 40); |
if (s->dir == -1) { |
dx += 80; |
} |
PHL_DrawSurfacePart(s->x, s->y, dx, 240, 40, 40, images[imgEnemies]); |
} |
} |
void createBone(int x, int y, int dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Bone* b = malloc(sizeof *b); |
b->id = i; |
b->x = x; |
b->y = y; |
b->hsp = dir * 0.75; |
b->vsp = -4; |
b->grav = 0.1; |
b->imageIndex = 0; |
b->mask.unused = 0; |
b->mask.circle = 1; |
b->mask.w = 12; |
b->mask.h = 12; |
b->mask.x = b->x + 20; |
b->mask.y = b->y + 20; |
e->data = b; |
e->enemyStep = boneStep; |
e->enemyDraw = boneDraw; |
e->type = -1; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void boneStep(Bone* b) |
{ |
if (b->hsp < 0) { |
b->imageIndex += 0.25; |
if (b->imageIndex >= 4) { |
b->imageIndex -= 4; |
} |
} |
else{ |
b->imageIndex -= 0.25; |
if (b->imageIndex < 0) { |
b->imageIndex += 4; |
} |
} |
b->x += b->hsp; |
b->y += b->vsp; |
b->vsp += b->grav; |
//Update Mask |
b->mask.x = b->x + 20; |
b->mask.y = b->y + 20; |
if (b->y > 480) { |
enemyDestroy(b->id); |
} |
//Hit Player |
if (checkCollision(b->mask, shieldMask)) { |
enemyDestroy(b->id); |
PHL_PlaySound(sounds[sndHit07], CHN_EFFECTS); |
createEffect(1, b->x, b->y); |
}else{ |
if (checkCollision(b->mask, getHeroMask())) { |
heroHit(10, b->x + 20); |
} |
} |
} |
void boneDraw(Bone* b) |
{ |
int img = 320 + ((int)b->imageIndex * 40); |
if (b->hsp > 0) { |
img += 160; |
} |
PHL_DrawSurfacePart(b->x, b->y, img, 240, 40, 40, images[imgEnemies]); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/skeleton.h |
---|
0,0 → 1,31 |
#ifndef SKELETON_H |
#define SKELETON_H |
#include "../collision.h" |
typedef struct { |
int id; |
double x, y; |
double hsp; |
double imageIndex; |
int dir; |
int hp; |
int state, timer, invincible; |
Mask mask; |
} Skeleton; |
void createSkeleton(int x, int y, int dir); |
typedef struct { |
int id; |
double x, y; |
double hsp, vsp, grav; |
double imageIndex; |
Mask mask; |
} Bone; |
void createBone(int x, int y, int dir); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/skull.c |
---|
0,0 → 1,174 |
#include "skull.h" |
#include "../enemy.h" |
#include "../PHL.h" |
#include "../game.h" |
#include "../hero.h" |
#include <stdlib.h> |
#include <math.h> |
void skullStep(Skull* s); |
void skullDraw(Skull* s); |
void createSkull(int x, int y) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Skull* s = malloc(sizeof *s); |
s->id = i; |
//X/Y in center of sprite |
s->x = x + 20; |
s->y = y + 20; |
s->yoffset = 0; |
s->rot = 0; |
s->state = 0; |
s->timer = 0; |
s->imageIndex = 0; |
s->dir = 0; |
e->data = s; |
e->enemyStep = skullStep; |
e->enemyDraw = skullDraw; |
e->type = 12; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void skullStep(Skull* s) |
{ |
double imageSpeed = 0; |
//Wait |
if (s->state == 0) |
{ |
imageSpeed = 0.2; |
if (s->timer > 0) { |
s->timer -= 1; |
}else{ |
Mask tempmask; |
tempmask.unused = tempmask.circle = 0; |
tempmask.x = s->x - 100; |
tempmask.y = s->y - 100; |
tempmask.w = tempmask.h = 200; |
if (checkCollisionXY(tempmask, herox, heroy + 20)) { |
//Calculate distance |
//int dis = sqrt(pow(s->x - herox, 2) + pow(s->y - (heroy + 20), 2)); |
//if (dis <= 100) { |
s->state = 1; |
//s->dir = (rand() % 8) * 45; |
s->dir = (rand() % 360) + 1; |
PHL_PlaySound(sounds[sndPi08], CHN_ENEMIES); |
s->timer = 130; |
} |
} |
} |
//Chase |
else if (s->state == 1) |
{ |
imageSpeed = 0.3; |
int spd = 2; |
s->x += (spd * cos(s->dir * 3.14159 / 180)); |
s->y += (spd * sin(s->dir * 3.14159 / 180)); |
double herodir = ((atan2((heroy + 20) - s->y, herox - s->x) * 180) / 3.14159); |
if (herodir >= 360) { |
herodir -= 360; |
} |
if (herodir < 0) { |
herodir += 360; |
} |
double tempdir = s->dir - herodir; |
if (tempdir < 0) { |
tempdir += 360; |
} |
if (tempdir < 180) { |
s->dir -= 2; |
}else{ |
s->dir += 2; |
} |
if (s->dir >= 360) { |
s->dir -= 360; |
} |
if (s->dir < 0) { |
s->dir += 360; |
} |
s->timer -= 1; |
if (s->timer <= 0) { |
s->state = 0; |
s->timer = 10; |
} |
} |
//Animate |
{ |
s->imageIndex += imageSpeed; |
if (s->imageIndex >= 4) { |
s->imageIndex -= 4; |
} |
} |
//Hover offset |
{ |
s->rot += 5; |
if (s->rot >= 360) { |
s->rot -= 360; |
} |
s->yoffset = (5 * sin(s->rot * 3.14159 / 180)); |
} |
//Setup Mask |
Mask mask; |
{ |
mask.unused = 0; |
mask.circle = 1; |
mask.x = s->x; |
mask.y = s->y; |
mask.w = mask.h = 10; |
} |
//Hero collision |
{ |
if (checkCollision(mask, getHeroMask())) { |
heroHit(15, mask.x); |
} |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
createEffect(2, s->x - 32, s->y - 32); |
spawnCollectable(s->x, s->y - 20); |
enemyDestroy(s->id); |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
void skullDraw(Skull* s) |
{ |
PHL_DrawSurfacePart(s->x - 20, s->y + s->yoffset - 20, 480 + ((int)s->imageIndex * 40), 40, 40, 40, images[imgEnemies]); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/skull.h |
---|
0,0 → 1,15 |
#ifndef SKULL_H |
#define SKULL_H |
typedef struct { |
int id, state, timer; |
double x, y; |
double yoffset; |
int rot; |
double dir; |
double imageIndex; |
} Skull; |
void createSkull(int x, int y); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/slime.c |
---|
0,0 → 1,228 |
#include "slime.h" |
#include <stdlib.h> |
#include "../PHL.h" |
#include "../game.h" |
#include "../collision.h" |
#include "../hero.h" |
#include "../enemy.h" |
#include "../weapon.h" |
void slimeStep(Slime* s); |
void slimeDraw(Slime* s); |
void createSlime(int x, int y, int type, int offset) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* result = malloc(sizeof *result); |
Slime* s = malloc(sizeof *s); |
s->id = i; |
s->x = x + 20; |
s->y = y; |
s->type = type; |
s->offset = offset; |
s->hp = 1; |
s->state = 0; |
s->counter = 0; |
s->timer = 0; |
s->grav = 0.125; |
s->vsp = 0; |
s->hsp = 0; |
s->imageIndex = 0; |
result->data = s; |
result->enemyStep = slimeStep; |
result->enemyDraw = slimeDraw; |
result->type = 0; |
enemies[i] = result; |
i = MAX_ENEMIES; |
} |
} |
} |
void slimeStep(Slime* s) |
{ |
char dead = 0; |
//Stay within room |
{ |
if (s->x > 640) { |
s->x = 640; |
} |
if (s->x < 0) { |
s->x = 0; |
} |
} |
//Setup Rectangle Mask |
Mask mask; |
{ |
mask.unused = 0; |
mask.circle = 0; |
mask.w = 24; |
mask.h = 24; |
mask.x = s->x - (mask.w / 2); |
mask.y = s->y + 28 - (mask.h / 2); |
} |
//Idle |
if (s->state == 0) |
{ |
s->imageIndex += 0.25; |
if (s->imageIndex >= 6) { |
s->imageIndex = 0; |
if (s->offset <= 0) { |
s->state = 1; |
//Red/Yellow Slime |
if (s->type == 1 || s->type == 2) |
{ |
s->hsp = 1; |
if (s->type == 2) { |
s->hsp = 1.5; |
} |
if ((int)(rand() % 2) == 0) { |
s->hsp *= -1; |
} |
} |
if (s->counter < 2) { |
s->vsp = -2; |
s->counter += 1; |
}else{ |
s->vsp = -4; |
s->counter = 0; |
} |
}else{ |
s->offset -= 1; |
} |
} |
} |
//Jump |
else if (s->state == 1) |
{ |
//Red/Yellow Slime |
if (s->type == 1 || s->type == 2) |
{ |
s->x += s->hsp; |
mask.x = s->x - (mask.w / 2); |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
if (s->hsp > 0) { |
s->x = collide.x - (mask.w / 2); |
}else if (s->hsp < 0) { |
s->x = collide.x + 40 + (mask.w / 2); |
} |
} |
mask.x = s->x - (mask.w / 2); |
} |
s->y += s->vsp; |
s->vsp += s->grav; |
mask.y = s->y + 28 - (mask.h / 2); |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x != -1) { |
if (s->vsp >= 0) { |
s->state = 0; |
s->hsp = 0; |
s->y = collide.y - 40; |
}else{ |
s->y = collide.y + 40 - (40 - mask.h) + 1; |
} |
} |
} |
//Setup Collision Mask |
{ |
mask.unused = 0; |
mask.circle = 1; |
mask.w = 12; |
mask.x = s->x; |
mask.y = s->y + 28; |
} |
//Fell in a pit |
{ |
if (s->y > 480) { |
dead = 1; |
} |
} |
//Collide with hero |
{ |
if (checkCollision(mask, heroMask)) { |
int dmg[3] = {10, 20, 20}; |
if (heroHit(dmg[s->type], s->x) == 1 && s->type == 2) { |
heroStun(); |
} |
} |
} |
//Sword collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
spawnCollectable(s->x, s->y + 6); |
createEffect(2, s->x - 32, s->y - 12); |
dead = 1; |
i = MAX_WEAPONS; |
} |
} |
} |
} |
//Destroy object |
{ |
if (dead == 1) { |
enemyDestroy(s->id); |
} |
} |
} |
void slimeDraw(Slime* s) |
{ |
int cropX = 0, |
cropY = 0; |
//Idle |
if (s->state == 0) { |
int image[6] = { 0, 1, 2, 3, 4, 6 }; |
cropX = image[(int)s->imageIndex] * 40; |
} |
//Jump |
else if (s->state == 1) { |
cropX = 200; |
if (s->vsp >= 0) { |
cropX += 40; |
} |
} |
//Color offsets |
int addX[3] = {0, 280, 0}; |
int addY[3] = {0, 0, 480}; |
PHL_DrawSurfacePart(s->x - 20, s->y + 12, cropX + addX[s->type], cropY + addY[s->type], 40, 40, images[imgEnemies]); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/slime.h |
---|
0,0 → 1,17 |
#ifndef SLIME_H |
#define SLIME_H |
typedef struct { |
int id; |
double x, y; |
int type; //0 = blue | 1 = red | 2 = yellow |
int offset; |
double vsp, hsp, grav; |
double imageIndex; |
int counter, timer, state; |
int hp; |
} Slime; |
void createSlime(int x, int y, int type, int offset); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/slug.c |
---|
0,0 → 1,164 |
#include "slug.h" |
#include "../enemy.h" |
#include "../game.h" |
#include "../PHL.h" |
#include "../hero.h" |
#include <stdlib.h> |
void slugStep(Slug* s); |
void slugDraw(Slug* s); |
void createSlug(int x, int y, int dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Slug* s = malloc(sizeof *s); |
s->id = i; |
s->x = x; |
s->y = y; |
s->imageIndex = 0; |
s->vsp = 0; |
s->dir = 1; |
if (dir == 1) { |
s->dir = -1; |
} |
e->data = s; |
e->enemyStep = slugStep; |
e->enemyDraw = slugDraw; |
e->type = 2; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void slugStep(Slug* s) |
{ |
//Create Mask |
Mask mask; |
{ |
mask.circle = 0; |
mask.unused = 0; |
mask.w = 32; |
mask.h = 24; |
mask.x = s->x + ((40 - mask.w) / 2); |
mask.y = s->y + (40 - mask.h); |
} |
//Animate |
{ |
s->imageIndex += 0.1; |
if (s->imageIndex >= 4) { |
s->imageIndex -= 4; |
} |
} |
//Check if on ground |
int onground = 1; |
{ |
mask.y += 1; |
if (checkTileCollision(1, mask) == 0 && checkTileCollision(3, mask) == 0) { |
onground = 0; |
} |
mask.y -= 1; |
} |
if (onground == 0) { |
double grav = 0.2; |
//Fall |
{ |
s->y += s->vsp; |
s->vsp += grav; |
} |
//Land on ground |
{ |
mask.y = mask.y + (40 - mask.h); |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x != -1) { |
s->y = collide.y - 40; |
s->vsp = 0; |
} |
} |
}else{ |
//Check if on ledge |
{ |
mask.x += mask.w * s->dir; |
mask.y += 1; |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x == -1) { |
s->dir *= -1; |
} |
} |
} |
//Horizontal movement |
double hsp = 0.5; |
{ |
s->x += s->dir * hsp; |
} |
//Check if hit a wall |
{ |
mask.x = s->x + ((40 - mask.w) / 2); |
mask.y = s->y + (40 - mask.h); |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
s->dir *= -1; |
} |
} |
//Hit Player |
{ |
if (checkCollision(mask, getHeroMask()) == 1) { |
heroHit(15, mask.x + (mask.w / 2)); |
} |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (checkCollision(mask, weapons[i]->weaponMask) == 1) { |
weaponHit(weapons[i]); |
createEffect(2, s->x - 12, s->y - 6); |
spawnCollectable(s->x + 20, s->y); |
enemyDestroy(s->id); |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
void slugDraw(Slug* s) |
{ |
int anim[4] = { 1, 0, 2, 0 }; |
int cropx = anim[(int)s->imageIndex] * 40; |
if (s->dir == -1) { |
cropx += 120; |
} |
PHL_DrawSurfacePart(s->x, s->y + 10, cropx, 40, 40, 40, images[imgEnemies]); |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/slug.h |
---|
0,0 → 1,13 |
#ifndef SLUG_H |
#define SLUG_H |
typedef struct { |
int id; |
int dir; |
double x, y, vsp; |
double imageIndex; |
} Slug; |
void createSlug(int x, int y, int dir); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/thwomp.c |
---|
0,0 → 1,265 |
#include "thwomp.h" |
#include "../enemy.h" |
#include "../hero.h" |
#include "../game.h" |
#include "../PHL.h" |
#include "../effect.h" |
#include <stdlib.h> |
void thwompStep(Thwomp* t); |
void thwompDraw(Thwomp* t); |
void createThwomp(int x, int y, int type, int offset, int delay, int dir) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Thwomp* t = malloc(sizeof *t); |
t->id = i; |
t->x = x; |
t->y = y; |
t->vsp = 0; |
t->grav = 0.3; |
t->imageIndex = 0; |
t->type = type; |
t->state = 0; |
t->timer = offset * 30; |
t->delay = delay * 30; |
//default delay is 60 |
if (delay == 0) { |
t->delay = 60; |
} |
t->dir = dir; |
t->hp = 3; |
t->blink = 0; |
e->data = t; |
e->enemyStep = thwompStep; |
e->enemyDraw = thwompDraw; |
e->type = 16; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void thwompStep(Thwomp* t) |
{ |
//Animate |
{ |
t->imageIndex += 0.1; |
if (t->imageIndex >= 3) { |
t->imageIndex -= 3; |
} |
} |
//Counters |
{ |
if (t->blink > 0) { |
t->blink -= 1; |
} |
} |
//Setup Mask |
Mask mask; |
{ |
mask.unused = mask.circle = 0; |
mask.w = mask.h = 36; |
mask.x = t->x + ((40 - mask.w) / 2); |
mask.y = t->y + ((40 - mask.h) / 2); |
} |
//Wait |
if (t->state == 0) { |
t->vsp = 0; |
//Waiter |
if (t->type == 0) { |
Mask area; |
area.unused = area.circle = 0; |
area.x = t->x - 40; |
area.y = t->y; |
area.w = 120; |
area.h = 160; |
if (checkCollisionXY(area, herox, heroy)) { |
t->state = 1; |
} |
} |
//Automatic |
else{ |
t->timer -= 1; |
if (t->timer <= 0) { |
t->state = 1; |
} |
} |
} |
//Fall |
else if (t->state == 1) { |
//Down |
if (t->dir == 0) { |
t->y += t->vsp; |
} |
//Left |
if (t->dir == 1) { |
t->x -= t->vsp; |
} |
//Right |
if (t->dir == 2) { |
t->x += t->vsp; |
} |
t->vsp += t->grav; |
if (t->vsp >= 7) { |
t->vsp = 7; |
} |
//Update Mask |
mask.x = t->x + ((40 - mask.w) / 2); |
mask.y = t->y + ((40 - mask.h) / 2); |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
int effX = t->x, |
effY = t->y; |
//Down |
if (t->dir == 0) { |
t->y = collide.y - 40; |
effY = t->y + 20; |
} |
//Left |
if (t->dir == 1) { |
t->x = collide.x + 40; |
effX = t->x - 20; |
} |
//Right |
if (t->dir == 2) { |
t->x = collide.x - 40; |
effX = t->x + 20; |
} |
t->state = 2; |
t->timer = 60; |
createEffect(1, effX, effY); |
PHL_PlaySound(sounds[sndHit07], CHN_ENEMIES); |
} |
} |
else if (t->state == 2) { |
if (t->type == 1) { //Automatic |
t->timer -= 1; |
if (t->timer <= 0) { |
t->state = 3; |
} |
} |
} |
else if (t->state == 3) { //rise up |
//Down |
if (t->dir == 0) { |
t->y -= 2; |
} |
//Left |
if (t->dir == 1) { |
t->x += 2; |
} |
//Right |
if (t->dir == 2) { |
t->x -= 2; |
} |
//Update Mask |
mask.x = t->x + ((40 - mask.w) / 2); |
mask.y = t->y + ((40 - mask.h) / 2); |
if (t->dir == 0) { |
mask.y -= 4; |
} |
if (t->dir == 1) { |
mask.x += 4; |
} |
if (t->dir == 2) { |
mask.x -= 4; |
} |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x != -1) { |
//Down |
if (t->dir == 0) { |
t->y = collide.y + 40 + 2; |
} |
//Left |
if (t->dir == 1) { |
t->x = collide.x - 40 + 2; |
} |
//Right |
if (t->dir == 2) { |
t->x = collide.x + 40 + 2; |
} |
t->state = 0; |
t->timer = t->delay; |
} |
} |
//Update Mask |
{ |
mask.x = t->x + ((40 - mask.w) / 2); |
mask.y = t->y + ((40 - mask.h) / 2); |
} |
//Hit Player |
{ |
if (checkCollision(mask, getHeroMask())) { |
heroHit(15, mask.x + (mask.w / 2)); |
} |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
if (hasItem[16] == 1) { //Has blue paper |
t->hp -= 1; |
t->blink = 15; |
if (t->hp <= 0) { |
createRockSmash(t->x + 20, t->y + 20); |
spawnCollectable(t->x + 20, t->y); |
enemyDestroy(t->id); |
} |
}else{ |
//Tink |
PHL_PlaySound(sounds[sndHit03], CHN_WEAPONS); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
} |
void thwompDraw(Thwomp* t) |
{ |
if (t->blink % 2 == 0) { |
PHL_DrawSurfacePart(t->x, t->y, 240 + ((int)t->imageIndex * 40), 400, 40, 40, images[imgMisc20]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/thwomp.h |
---|
0,0 → 1,18 |
#ifndef THWOMP_H |
#define THWOMP_H |
//#include "../collision.h" |
typedef struct { |
int id; |
double x, y; |
double vsp, grav; |
double imageIndex; |
int type, state, timer, dir; |
int hp, blink; |
int delay; |
} Thwomp; |
void createThwomp(int x, int y, int type, int offset, int delay, int dir); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/waterjumper.c |
---|
0,0 → 1,356 |
#include "waterjumper.h" |
#include <math.h> |
#include <stdlib.h> |
#include "../game.h" |
#include "../enemy.h" |
#include "../hero.h" |
#include "../collision.h" |
void waterJumperStep(WaterJumper* w); |
void waterJumperDraw(WaterJumper* w); |
void createWaterJumper(int x, int y, int type, int offset, int height) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
WaterJumper* w = malloc(sizeof *w); |
w->id = i; |
w->type = type; |
w->x = x; |
w->y = w->ystart = y; |
w->hp = 1; |
w->hsp = w->vsp = 0; |
w->grav = 0.115; |
w->yoffset = 0; |
w->imageIndex = 0; |
w->blink = 0; |
w->timer = 60; |
w->timer += 60 * offset; |
w->rot = 0; |
w->state = 0; |
if (type == 1) { |
w->hp = 2; |
w->timer = 60 * offset; |
} |
//Specific offset timer |
if (offset > 10) { |
w->timer = offset; |
} |
w->height = height; |
/* |
w->mask.unused = w->mask.circle = 0; |
w->mask.x = x + 8; |
w->mask.y = y + 8; |
w->mask.w = 24; |
w->mask.h = 24; |
*/ |
e->data = w; |
e->enemyStep = waterJumperStep; |
e->enemyDraw = waterJumperDraw; |
e->type = 14; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void waterJumperStep(WaterJumper* w) |
{ |
//Counters |
{ |
if (w->blink > 0) { |
w->blink -= 1; |
} |
if (w->timer > 0) { |
w->timer -= 1; |
} |
} |
//Setup Mask |
Mask mask; |
{ |
mask.unused = mask.circle = 0; |
mask.w = 24; |
mask.h = 24; |
mask.x = w->x + ((40 - mask.w) / 2); |
mask.y = w->y + ((40 - mask.h) / 2); |
} |
//Float |
if (w->state == 0) |
{ |
//Animate |
{ |
w->imageIndex += 0.1; |
if (w->imageIndex >= 2) { |
w->imageIndex -= 2; |
} |
} |
//Movement |
{ |
w->rot += 5; |
if (w->rot >= 360) { |
w->rot -= 360; |
} |
w->y = w->ystart + (5 * sin(w->rot * 3.14159 / 180)); |
} |
//Hop out of water |
{ |
if (w->timer <= 0) { |
w->state = 1; |
w->timer = -1; |
createSplash(w->x + 20, w->y); |
w->y = w->ystart; |
} |
} |
} |
//In air |
else if (w->state == 1) |
{ |
//Animate |
{ |
w->imageIndex += 0.25; |
if (w->imageIndex >= 3) { |
w->imageIndex -= 3; |
} |
} |
//Green type |
if (w->type == 0) |
{ |
//State Start |
{ |
if (w->timer == -1) { |
w->timer = 0; |
w->vsp = -5.5; |
w->hsp = -2; |
if (w->x + 20 < herox) { |
w->hsp *= -1; |
} |
} |
} |
//Horizontal Movement |
w->x += w->hsp; |
//Land in water |
{ |
if (w->vsp > 0 && w->y >= w->ystart) { |
createSplash(w->x + 20, w->y); |
w->y = w->ystart; |
w->state = 0; |
w->hsp = w->vsp = 0; |
w->timer = 120; |
} |
} |
} |
//Blue type |
else |
{ |
//State Start |
{ |
if (w->timer == -1) { |
w->timer = 0; |
if (w->height == 2) { |
w->vsp = -5.5; |
} |
else if (w->height == 3) { |
w->vsp = -6; |
} |
else if (w->height == 4) { |
w->vsp = -7; |
} |
else if (w->height == 5) { |
w->vsp = -7.5; |
} |
} |
} |
//Land on expected ground |
{ |
if (w->vsp > 0) { |
if (w->y >= w->ystart - 22 - (w->height * 40)) { |
w->y = w->ystart - 22 - (w->height * 40); |
w->imageIndex = 5; |
w->state = 2; |
w->timer = 240; |
w->hsp = 2; |
if (herox < w->x + 20) { |
w->hsp *= -1; |
} |
} |
} |
} |
} |
//Vertical Movement |
w->y += w->vsp; |
w->vsp += w->grav; |
} |
//Walk |
else if (w->state == 2) { |
//Animate |
{ |
w->imageIndex += 0.16; |
if (w->imageIndex >= 7) { |
w->imageIndex -= 2; |
} |
} |
//Movement |
{ |
w->x += w->hsp; |
mask.x = w->x + ((40 - mask.w) / 2); |
} |
//Hit wall |
if (checkTileCollision(1, mask) == 1) { |
w->hsp *= -1; |
} |
//Turn on edge |
else{ |
mask.x += (mask.w / 2) * w->hsp; |
mask.y += mask.h; |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x == -1) { |
w->hsp *= -1; |
} |
} |
//End walk |
{ |
if (w->timer <= 0) { |
w->state = 3; |
w->timer = -1; |
} |
} |
} |
//Jump Down |
else if (w->state == 3) |
{ |
//Setup |
{ |
if (w->timer == -1) { |
w->timer = 0; |
PHL_PlaySound(sounds[sndPi02], CHN_ENEMIES); |
w->vsp = -4; |
w->imageIndex = 2; |
} |
} |
//Animate |
{ |
w->imageIndex += 0.25; |
if (w->imageIndex >= 5) { |
w->imageIndex -= 3; |
} |
} |
//Movement |
{ |
w->y += w->vsp; |
w->vsp += w->grav; |
if (w->vsp > 6) { |
w->vsp = 6; |
} |
} |
//Land in Water |
{ |
if (w->y >= w->ystart) { |
w->state = 0; |
createSplash(w->x + 20, w->y); |
w->timer = 60; |
} |
} |
} |
//Update Mask |
{ |
mask.x = w->x + ((40 - mask.w) / 2); |
mask.y = w->y + ((40 - mask.h) / 2); |
} |
//Collide with hero |
{ |
if (checkCollision(mask, getHeroMask())) { |
heroHit(15, mask.x + (mask.w / 2)); |
} |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
w->blink = 15; |
w->hp -= 1; |
if (w->hp <= 0) { |
createEffect(2, w->x - 12, w->y - 12); |
spawnCollectable(w->x + 20, w->y); |
enemyDestroy(w->id); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
} |
void waterJumperDraw(WaterJumper* w) |
{ |
if (w->blink % 2 == 0) { |
int cx = (int)w->imageIndex * 40; |
if (w->state == 1) { |
cx += 80; |
} |
if (w->type == 1) { |
cx += 200; |
if (w->state == 2 && w->hsp < 0) { |
cx += 80; |
} |
} |
PHL_DrawSurfacePart(w->x, w->y, cx, 440, 40, 40, images[imgEnemies]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/waterjumper.h |
---|
0,0 → 1,23 |
#ifndef WATERJUMPER_H |
#define WATERJUMPER_H |
#include "../enemy.h" |
typedef struct { |
int id, type; |
double x, y; |
int hp; |
int blink; |
int ystart, rot; |
double yoffset; |
double hsp, vsp, grav; |
double imageIndex; |
int state, timer; |
int height; |
} WaterJumper; |
void createWaterJumper(int x, int y, int type, int offset, int height); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemies/wizard.c |
---|
0,0 → 1,133 |
#include "wizard.h" |
#include "../enemy.h" |
#include "../game.h" |
#include "../hero.h" |
#include <stdlib.h> |
void createWizard(int x, int y) |
{ |
int i; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] == NULL) { |
Enemy* e = malloc(sizeof *e); |
Wizard* w = malloc(sizeof *w); |
w->id = i; |
w->x = x; |
w->y = y; |
w->imageIndex = 0; |
w->state = 0; |
w->timer = 50; |
w->visible = 1; |
w->mask.circle = w->mask.unused = 0; |
w->mask.w = 24; |
w->mask.h = 38; |
w->mask.x = w->x + 8; |
w->mask.y = w->y + 2; |
e->data = w; |
e->enemyStep = wizardStep; |
e->enemyDraw = wizardDraw; |
e->type = 21; |
enemies[i] = e; |
i = MAX_ENEMIES; |
} |
} |
} |
void wizardStep(Wizard* w) |
{ |
w->imageIndex += 0.3; |
if (w->imageIndex >= 3) { |
w->imageIndex -= 3; |
} |
//Stand still |
if (w->state == 0) { |
w->timer -= 1; |
if (w->timer <= 0) { |
PHL_PlaySound(sounds[sndPi10], CHN_ENEMIES); |
w->state = 1; |
w->timer = 15; |
} |
} |
//Flash |
else if (w->state == 1 || w->state == 3) { |
if (w->visible == 0) { |
w->visible = 1; |
}else{ |
w->visible = 0; |
} |
w->timer -= 1; |
if (w->timer <= 0) { |
if (w->state == 1) { |
w->state = 2; |
w->timer = 60; |
} |
else if (w->state == 3) { |
w->visible = 1; |
w->state = 0; |
w->timer = 50; |
} |
} |
} |
//Invisible |
else if (w->state == 2) { |
w->visible = 0; |
w->timer -= 1; |
if (w->timer <= 0) { |
PHL_PlaySound(sounds[sndPi03], CHN_ENEMIES); |
w->state = 3; |
w->timer = 15; |
//Horizontal Jump |
int gridX = w->x / 40, |
gridY = w->y / 40, |
lastGridX = gridX; |
do { |
gridX = (rand() % 16) + 1; |
} while (collisionTiles[gridX][gridY] != 0 || |
collisionTiles[gridX][gridY+1] != 1 || |
gridX == lastGridX); |
w->x = gridX * 40; |
w->mask.x = w->x + 8; |
} |
} |
if (w->state == 0 || w->state == 3) { |
//Hit Player |
if (checkCollision(w->mask, getHeroMask())) { |
heroHit(15, w->x + 20); |
} |
//Weapon Collision |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (checkCollision(w->mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
createEffect(2, w->x - 12, w->y - 6); |
spawnCollectable(w->x + 20, w->y); |
enemyDestroy(w->id); |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
void wizardDraw(Wizard* w) |
{ |
if (w->visible == 1) { |
PHL_DrawSurfacePart(w->x, w->y, 520 + (((int)w->imageIndex) * 40), 480, 40, 40, images[imgEnemies]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/enemies/wizard.h |
---|
0,0 → 1,20 |
#ifndef WIZARD_H |
#define WIZARD_H |
#include "../collision.h" |
typedef struct { |
int id; |
double x, y; |
double imageIndex; |
int state, timer, visible; |
Mask mask; |
} Wizard; |
void createWizard(int x, int y); |
void wizardStep(Wizard* w); |
void wizardDraw(Wizard* w); |
#endif |
/contrib/games/hydracastlelabyrinth/src/enemy.c |
---|
0,0 → 1,16 |
#include "enemy.h" |
#include "game.h" |
#include <stdlib.h> |
void enemyDestroy(int id) |
{ |
if (enemies[id] != NULL) { |
if (enemies[id]->data != NULL) { |
free(enemies[id]->data); |
} |
enemies[id]->data = NULL; |
free(enemies[id]); |
} |
enemies[id] = NULL; |
} |
/contrib/games/hydracastlelabyrinth/src/enemy.h |
---|
0,0 → 1,13 |
#ifndef ENEMY_H |
#define ENEMY_H |
typedef struct { |
void* data; //Specific enemy struct |
void (*enemyStep)(); |
void (*enemyDraw)(); |
int type; |
} Enemy; |
void enemyDestroy(int id); |
#endif |
/contrib/games/hydracastlelabyrinth/src/game.c |
---|
0,0 → 1,1976 |
#include "game.h" |
#include "hero.h" |
#include "PHL.h" |
#include "qda.h" |
#include "ini.h" |
#include "titlescreen.h" |
#include "options.h" |
#include "inventory.h" |
#include "object.h" |
#include "effect.h" |
#include "text.h" |
#include "stagedata.h" |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#ifdef EMSCRIPTEN |
#include <emscripten.h> |
#endif |
int gameStep(); |
void gameDraw(char doDrawHud); |
void freeArrays(); |
void drawHud(); |
int getTileType(int valx, int valy); |
void loadUncommonImages(); |
char forceGameExit = 0; |
int drawhp; |
int NumOfSounds = 43; |
int NumOfImages = 14; |
char autoSave = 1; |
int levelStartFlag = 0; |
char tilesetStrings[9][12] = {"stage01.bmp", |
"stage02.bmp", |
"stage02.bmp", |
"stage03.bmp", |
"stage04.bmp", |
"stage03.bmp", |
"stage02.bmp", |
"stage05.bmp", |
"stage08.bmp" }; |
char musicStrings[9][14] = { "midi/main01", |
"midi/main02", |
"midi/main02", |
"midi/main05", |
"midi/main03", |
"midi/main05", |
"midi/main02", |
"midi/main04", |
"midi/main06" }; |
int collisionTiles[16][12]; |
PHL_Surface images[15]; |
PHL_Sound sounds[43]; |
PHL_Music bgmMusic; |
PHL_Music bgmSecret; |
PHL_Music bgmGameover; |
Object* objects[MAX_OBJECTS]; |
Effect* effects[MAX_EFFECTS]; |
Weapon* weapons[MAX_WEAPONS]; |
Enemy* enemies[MAX_ENEMIES]; |
Platform* platforms[MAX_PLATFORMS]; |
int secretTimer; |
unsigned long playTime; |
Door* lastDoor; |
int quakeTimer; |
int bellFlag; |
int bossFlag; |
int bossDefeatedFlag; |
int roomSecret; |
char roomDarkness; |
int itemGotX; |
int itemGotY; |
PHL_Background background, foreground; |
unsigned char hasWeapon[5]; |
unsigned char hasItem[28]; |
unsigned char hasKey[8]; |
unsigned char flags[60]; |
double cutInTimer = 240; |
int transitionTimer = 0; |
int level = 0; |
int screenX = 5, |
screenY = 2; |
#ifdef _SDL |
char savename[4096]; |
char savemap[4096]; |
#endif |
#ifdef EMSCRIPTEN |
extern int fileSynched; |
int em_state = -2; |
void em_loop_fn(void* arg) |
{ |
if(!PHL_MainLoop()) { |
emscripten_cancel_main_loop(); |
} |
int result; |
switch (em_state) { |
case -2: if(fileSynched) em_state++; |
break; |
case -1: em_state++; |
// need to delay loading of init to let synchof files happens |
iniInit(); |
//Load Resources |
loadText(); |
loadResources(); |
break; |
case 0: |
PHL_StopMusic(); |
titleScreenSetup(); |
++em_state; |
break; |
case 1: result = titleEMStep(); |
if (result == 3) { |
em_state = 100; |
} else if(result!=-1) { |
if(result==2) |
em_state = 60; |
else { |
//Reset game state |
gameSetup(); |
//Load Game |
if (result == 1) |
{ |
if (fileExists(savename) == 1) { |
loadSave(savename); |
}else if (fileExists(savemap) == 1) { |
loadSave(savemap); |
} |
} |
++em_state; |
} |
} |
break; |
case 2: |
//Update resources, depending on level |
loadUncommonImages(); |
PHL_FreeSurface(images[imgTiles]); |
images[imgTiles] = PHL_LoadQDA(tilesetStrings[level]); |
PHL_FreeMusic(bgmMusic); |
bgmMusic = PHL_LoadMusic(musicStrings[level], 1); |
loadScreen(); |
em_state = 10; |
break; |
case 10: // main game loop |
PHL_MainLoop(); |
PHL_ScanInput(); |
result = gameStep(); |
if(!result) |
em_state = 20; |
else { |
if(result!=-1) |
em_state = result; |
else { |
PHL_StartDrawing(); |
gameDraw(1); |
PHL_EndDrawing(); |
} |
} |
break; |
case 20: // game ended |
roomDarkness = 0; |
freeArrays(); |
//Erase temp save if it exists |
if (fileExists(savename)) |
{ |
remove(savename); |
#ifdef EMSCRIPTEN |
EM_ASM( |
FS.syncfs(false,function () { |
Module.print("File sych'd") |
}); |
); |
#endif |
} |
em_state = 0; |
break; |
case 30: // option menu |
optionsSetup(0); |
++em_state; |
// fall thru |
case 31: |
result = optionsEMStep(); |
//Reset Game |
if (result == 1) |
em_state = 20; |
else if (result == 3) { |
em_state = 100; |
} else if (result!=-1) |
em_state = 10; |
break; |
case 40: |
inventorySetup(); |
++em_state; |
case 41: |
result = inventoryEMStep(); |
if(result==0) |
em_state = 10; |
break; |
case 50: |
result = getItemEMStep(); |
if(result==0) |
em_state = 10; |
break; |
case 60: // option menu |
optionsSetup(1); |
++em_state; |
// fall thru |
case 61: |
result = optionsEMStep(); |
if (result!=-1) |
em_state = 0; |
break; |
case 100: |
/* |
//Free Resources |
textFree(); |
freeResources(); |
//Deinit services |
PHL_Deinit(); |
// end |
emscripten_cancel_main_loop(); |
*/ |
em_state = 0; // no quitting, as it make no sense in a browser (just kill the tab) |
break; |
} |
} |
#endif |
void game() |
{ |
#ifdef _SDL |
#if defined(__amigaos4__) || defined(__MORPHOS__) |
const char* home = "PROGDIR:"; |
#elif defined(EMSCRIPTEN) |
const char* home = "hcl_data/"; |
#elif defined(_KOLIBRI) |
const char* home = KOS_TMP_DIR; |
#else |
const char* home = getenv("HOME"); |
#endif |
if(home) |
{ |
strcpy(savename, home); |
#if defined(__amigaos4__) || defined(__MORPHOS__) |
strcat(savename, ".hydracastlelabyrinth/"); |
#elif !defined(EMSCRIPTEN) |
strcat(savename, "/.hydracastlelabyrinth/"); |
#endif |
strcpy(savemap, savename); |
strcat(savename, "save.tmp"); |
strcat(savemap, "save.map"); |
} else { |
strcpy(savename, "data/save.tmp"); |
strcpy(savemap, savemap); |
} |
#endif |
//Setup services |
printf("DBG:0\n"); |
PHL_Init(); |
if(1!=initQDA()) |
{ |
printf("DBG:QDA FAILED\n"); |
} |
printf("DBG: 1\n"); |
textInit(); |
printf("DBG: 2\n"); |
#ifdef EMSCRIPTEN |
emscripten_set_main_loop_arg(em_loop_fn, NULL, -1, 1); |
#else |
iniInit(); |
printf("DBG: 3\n"); |
//Load Resources |
loadText(); |
printf("DBG: 4\n"); |
loadResources(); |
printf("DBG: 5\n"); |
while (PHL_MainLoop()) |
{ |
//Titlescreen |
int titleScreenResult = titleScreen(); |
printf("DBG: titleScreen()\n"); |
//Exit game |
if (titleScreenResult == 3) { |
PHL_GameQuit(); |
} |
// Options |
else if(titleScreenResult == 2) { |
int optionsResult = options(1); |
//Exit Game |
if (optionsResult == 3) { |
PHL_GameQuit(); |
} |
} |
//Game Start |
else{ |
//Reset game state |
gameSetup(); |
//Load Game |
if (titleScreenResult == 1) |
{ |
if (fileExists(savename) == 1) { |
loadSave(savename); |
}else if (fileExists(savemap) == 1) { |
loadSave(savemap); |
} |
} |
//Update resources, depending on level |
loadUncommonImages(); |
/*printf("\nTiles are "); |
if (images[imgTiles].pxdata == NULL) { |
printf("not loaded."); |
}else{ |
printf("loaded."); |
}*/ |
PHL_FreeSurface(images[imgTiles]); |
images[imgTiles] = PHL_LoadQDA(tilesetStrings[level]); |
PHL_FreeMusic(bgmMusic); |
bgmMusic = PHL_LoadMusic(musicStrings[level], 1); |
loadScreen(); |
//In game main loop |
char gameLoop = 1; |
while (PHL_MainLoop() == 1 && gameLoop == 1) { |
PHL_ScanInput(); |
int gameResult = gameStep(); |
if (gameResult != -1) { |
gameLoop = 0; |
} |
if (gameLoop == 1) { |
PHL_StartDrawing(); |
gameDraw(1); |
PHL_EndDrawing(); |
} |
} |
//Game end (return to titlescreen) |
roomDarkness = 0; |
freeArrays(); |
//Erase temp save if it exists |
if (fileExists(savename)) |
{ |
#ifdef _SDL |
remove(savename); |
#else |
char fullPath[128]; |
strcpy(fullPath, ""); |
#ifdef _3DS |
strcat(fullPath, "sdmc:/3ds/appdata/HydraCastleLabyrinth/"); |
#endif |
strcat(fullPath, savename); |
remove(fullPath); |
#endif |
#ifdef EMSCRIPTEN |
EM_ASM( |
FS.syncfs(false,function () { |
Module.print("File sych'd") |
}); |
); |
#endif |
} |
} |
} |
//Free Resources |
textFree(); |
freeResources(); |
//Deinit services |
PHL_Deinit(); |
#endif |
} |
void loadImages() |
{ |
images[imgTiles] = PHL_LoadQDA(tilesetStrings[level]); |
images[imgEnemies] = PHL_LoadQDA("ene01.bmp"); |
images[imgHud] = PHL_LoadQDA("status.bmp"); |
images[imgMisc20] = PHL_LoadQDA("chr20.BMP"); |
images[imgMisc32] = PHL_LoadQDA("chr32.BMP"); |
images[imgHero] = PHL_LoadQDA("mychr.bmp"); |
images[imgItems] = PHL_LoadQDA("items.bmp"); |
images[imgExplosion] = PHL_LoadQDA("chr64.BMP"); |
images[imgBoss] = PHL_LoadQDA("boss01.bmp"); |
//images[imgMisc2040] = PHL_LoadQDA("chr20x40.BMP"); |
images[imgFontKana] = PHL_LoadQDA("font8x8-kana.bmp"); |
images[imgBoldFont] = PHL_LoadQDA("font8x8-01.bmp"); |
//images[imgDark] = PHL_LoadQDA("dark.bmp"); |
//images[imgMisc6020] = PHL_LoadQDA("chr60x20.bmp"); |
//images[imgHud].colorKey = PHL_NewRGB(0, 0, 0); |
//PHL_SetColorKey(images[imgHud], 0, 0, 0); |
images[imgTitle01] = PHL_LoadQDA("title01.BMP"); |
} |
void loadResources() |
{ |
//Loading Images |
loadImages(); |
puts("DBG loadResources1"); |
//Load Sounds |
sounds[sndBee01] = PHL_LoadSound("wav/bee01.wav"); |
sounds[sndBell01] = PHL_LoadSound("wav/bell01.wav"); |
sounds[sndBom01] = PHL_LoadSound("wav/bom01.wav"); |
sounds[sndBom02] = PHL_LoadSound("wav/bom02.wav"); |
sounds[sndBom03] = PHL_LoadSound("wav/bom03.wav"); |
sounds[sndDoor00] = PHL_LoadSound("wav/door00.wav"); |
sounds[sndFire01] = PHL_LoadSound("wav/fire01.wav"); |
sounds[sndGas01] = PHL_LoadSound("wav/gas01.wav"); |
sounds[sndGet01] = PHL_LoadSound("wav/get01.wav"); |
sounds[sndGet02] = PHL_LoadSound("wav/get02.wav"); |
sounds[sndHit01] = PHL_LoadSound("wav/hit01.wav"); |
sounds[sndHit02] = PHL_LoadSound("wav/hit02.wav"); |
sounds[sndHit03] = PHL_LoadSound("wav/hit03.wav"); |
sounds[sndHit04] = PHL_LoadSound("wav/hit04.wav"); |
sounds[sndHit05] = PHL_LoadSound("wav/hit05.wav"); |
sounds[sndHit06] = PHL_LoadSound("wav/hit06.wav"); |
sounds[sndHit07] = PHL_LoadSound("wav/hit07.wav"); |
sounds[sndJump01] = PHL_LoadSound("wav/jump01.wav"); |
sounds[sndJump02] = PHL_LoadSound("wav/jump02.wav"); |
sounds[sndNg] = PHL_LoadSound("wav/ng.wav"); |
sounds[sndOk] = PHL_LoadSound("wav/ok.wav"); |
sounds[sndPi01] = PHL_LoadSound("wav/pi01.wav"); |
sounds[sndPi02] = PHL_LoadSound("wav/pi02.wav"); |
sounds[sndPi03] = PHL_LoadSound("wav/pi03.wav"); |
sounds[sndPi04] = PHL_LoadSound("wav/pi04.wav"); |
sounds[sndPi05] = PHL_LoadSound("wav/pi05.wav"); |
sounds[sndPi06] = PHL_LoadSound("wav/pi06.wav"); |
sounds[sndPi07] = PHL_LoadSound("wav/pi07.wav"); |
sounds[sndPi08] = PHL_LoadSound("wav/pi08.wav"); |
sounds[sndPi09] = PHL_LoadSound("wav/pi09.wav"); |
sounds[sndPi10] = PHL_LoadSound("wav/pi10.wav"); |
sounds[sndPower01] = PHL_LoadSound("wav/power01.wav"); |
sounds[sndPower02] = PHL_LoadSound("wav/power02.wav"); |
sounds[sndShot01] = PHL_LoadSound("wav/shot01.wav"); |
sounds[sndShot02] = PHL_LoadSound("wav/shot02.wav"); |
sounds[sndShot03] = PHL_LoadSound("wav/shot03.wav"); |
sounds[sndShot04] = PHL_LoadSound("wav/shot04.wav"); |
sounds[sndShot05] = PHL_LoadSound("wav/shot05.wav"); |
sounds[sndShot06] = PHL_LoadSound("wav/shot06.wav"); |
sounds[sndShot07] = PHL_LoadSound("wav/shot07.wav"); |
sounds[sndStep01] = PHL_LoadSound("wav/step01.wav"); |
sounds[sndWater01] = PHL_LoadSound("wav/water01.wav"); |
sounds[sndWolf01] = PHL_LoadSound("wav/wolf01.wav"); |
puts("DBG loadResources2"); |
//Load Music |
bgmSecret = PHL_LoadMusic("midi/nazo", 0); |
puts("DBG loadResources3"); |
bgmGameover = PHL_LoadMusic("midi/gameover", 0); |
puts("DBG loadResources4"); |
} |
void freeImages() |
{ |
int i; |
//Free graphics |
for (i = 0; i < NumOfImages; i++) { |
PHL_FreeSurface(images[i]); |
} |
} |
void freeResources() |
{ |
//Free sounds |
int i; |
for (i = 0; i < NumOfSounds; i++) { |
PHL_FreeSound(sounds[i]); |
} |
//Free Music |
PHL_FreeMusic(bgmMusic); |
PHL_FreeMusic(bgmGameover); |
PHL_FreeMusic(bgmSecret); |
freeImages(); |
} |
void gameSetup() |
{ |
//Reset Flags |
{ |
quakeTimer = 0; |
secretTimer = 0; |
roomDarkness = 0; |
bellFlag = 0; |
bossFlag = 0; |
bossDefeatedFlag = 0; |
int i; |
for (i = 0; i < 60; i++) { |
flags[i] = 0; |
} |
} |
//Save Data |
{ |
playTime = 0; |
//Inventory |
int i; |
for (i = 0; i < 5; i++) { |
hasWeapon[i] = 0; |
} |
for (i = 0; i < 28; i++) { |
hasItem[i] = 0; |
} |
for (i = 0; i< 8; i++) { |
hasKey[i] = 0; |
} |
} |
//Room Data |
{ |
roomSecret = 0; |
level = 0; |
screenX = 5; |
screenY = 2; |
} |
//Hero Setup |
{ |
heroSetup(); |
drawhp = herohp; |
} |
//Reset object arrays |
freeArrays(); |
//Setup screen transition |
cutInTimer = 240; |
} |
int gameStep() |
{ |
//Manage Timers |
{ |
playTime += 1; |
secretCountdown(); |
if (quakeTimer > 0) { |
quakeTimer -= 1; |
} |
if (cutInTimer > 0) { |
cutInTimer -= 5; |
//Play music when the transition ends |
if (cutInTimer <= 0 && bossDefeatedFlag == 0 && bossFlag == 0) { |
PHL_PlayMusic(bgmMusic); |
} |
} |
} |
//Hero step |
{ |
//End game if hero died |
if (heroStep() == 1) { |
return 0; |
} |
} |
//Menu button presses |
{ |
if (getHeroState() <= 5 && cutInTimer <= 0) { |
if (btnSelect.pressed == 1) |
{ |
#ifdef EMSCRIPTEN |
optionsSetup(0); |
return 31; |
#else |
int optionsResult = options(0); |
//Reset Game |
if (optionsResult == 1) { |
return 0; |
} |
//Exit Game |
if (optionsResult == 3) { |
PHL_GameQuit(); |
return 1; |
} |
#endif |
}else if (btnStart.pressed == 1) { |
#ifdef EMSCRIPTEN |
return 40; |
#else |
inventory(); |
#endif |
} |
} |
} |
//Objects steps |
{ |
int i; |
for (i = 0; i < MAX_PLATFORMS; i++) { |
if (platforms[i] != NULL) { |
platformStep(platforms[i]); |
} |
} |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] != NULL) { |
objects[i]->objectStep(objects[i]->data); |
} |
} |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
weaponStep(weapons[i]); |
} |
} |
for (i = 0; i < MAX_EFFECTS; i++) { |
if (effects[i] != NULL) { |
effectStep(effects[i]); |
} |
} |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] != NULL) { |
enemies[i]->enemyStep(enemies[i]->data); |
} |
} |
} |
if (forceGameExit == 1) { |
forceGameExit = 0; |
return 0; |
} |
return -1; |
} |
void gameDraw(char doDrawHud) |
{ |
PHL_DrawBackground(background, foreground); |
int i; |
//Draw water/lava top effects |
for (i = 0; i < MAX_EFFECTS; i++) { |
if (effects[i] != NULL) { |
if (effects[i]->depth == -1) { |
effectDraw(effects[i]); |
} |
} |
} |
for (i = 0; i < MAX_PLATFORMS; i++) { |
if (platforms[i] != NULL) { |
platformDraw(platforms[i]); |
} |
} |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] != NULL) { |
objects[i]->objectDraw(objects[i]->data); |
} |
} |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
weaponDraw(weapons[i]); |
} |
} |
//Draw effects under |
for (i = 0; i < MAX_EFFECTS; i++) { |
if (effects[i] != NULL) { |
if (effects[i]->depth == 0) { |
effectDraw(effects[i]); |
} |
} |
} |
//Draw enemies backwards, so bullets and such are underneath their spawners |
//for (i = MAX_ENEMIES - 1; i >= 0; i--) { |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (enemies[i] != NULL) { |
enemies[i]->enemyDraw(enemies[i]->data); |
} |
} |
//Not Death, draw death later |
if (getHeroState() != 8) { |
heroDraw(); |
} |
//Draw effects over |
for (i = 0; i < MAX_EFFECTS; i++) { |
if (effects[i] != NULL) { |
if (effects[i]->depth == 1) { |
effectDraw(effects[i]); |
} |
} |
} |
//Draw Darkness |
if (roomDarkness == 1) { |
int cornerX = herox - 160, |
cornerY = heroy + 20 - 160; |
PHL_DrawSurfacePart(cornerX, cornerY, 320 * hasItem[18], 0, 320, 320, images[imgDark]); |
//Top darkness rectangle |
if (cornerY > 0) { |
PHL_DrawRect(0, 0, 640, cornerY, PHL_NewRGB(10, 0, 0)); |
} |
//Bottom darkness rectangle |
if (cornerY + 320 < 480) { |
PHL_DrawRect(0, cornerY + 320, 640, 480, PHL_NewRGB(10, 0, 0)); |
} |
//Left rectangle |
if (cornerX > 0) { |
PHL_DrawRect(0, cornerY, cornerX, 320, PHL_NewRGB(10, 0, 0)); |
} |
//Right rectangle |
if (cornerX + 320 < 640) { |
PHL_DrawRect(cornerX + 320, cornerY, 640 - cornerX + 320, 320, PHL_NewRGB(10, 0, 0)); |
} |
} |
//Draw death over darkness |
if (getHeroState() == 8) { |
heroDraw(); |
} |
if (doDrawHud == 1) { |
drawHud(); |
} |
//cut-in transition |
{ |
if (cutInTimer > 0) { |
PHL_DrawRect(0, 0, 640, cutInTimer, PHL_NewRGB(0, 0, 0)); |
PHL_DrawRect(0, 240 + (240 - cutInTimer), 640, 480, PHL_NewRGB(0, 0, 0)); |
} |
} |
} |
#ifdef EMSCRIPTEN |
static int em_itemNum; |
static char getItemTimer; |
void getItemSetup(int itemNum) |
{ |
setHeroState(6); |
setHeroImageIndex(0); |
char getItemTimer = 0; |
} |
int getItemEMStep() |
{ |
int itemNum = em_itemNum; |
char loop = 1; |
PHL_MainLoop(); |
#else |
void getItem(int itemNum) |
{ |
setHeroState(6); |
setHeroImageIndex(0); |
char getItemTimer = 0; |
char loop = 1; |
while (PHL_MainLoop() && loop == 1) |
#endif |
{ |
secretCountdown(); |
//Get Item Step |
if (getItemTimer == 0) { |
setHeroImageIndex(getHeroImageIndex() + 0.3); |
if (getHeroImageIndex() > 3) { |
getItemTimer = 1; |
} |
}else if (getItemTimer == 1) { |
//Wait for input |
PHL_ScanInput(); |
if (btnAccept.pressed == 1 || btnFaceDown.pressed == 1 || btnFaceRight.pressed == 1 || |
btnFaceUp.pressed == 1 || btnFaceLeft.pressed == 1 || btnStart.pressed == 1) { |
getItemTimer = 2; |
} |
}else if (getItemTimer == 2) { |
setHeroImageIndex(getHeroImageIndex() + 0.3); |
if (getHeroImageIndex() >= 7) { |
loop = 0; |
setHeroState(0); |
setHeroImageIndex(0); |
} |
} |
//Get Item Draw |
{ |
PHL_StartDrawing(); |
gameDraw(1); |
if (getHeroImageIndex() >= 3) { |
char tempDarkness = roomDarkness; |
roomDarkness = 0; |
PHL_DrawRect(140, 208, 360, 64, PHL_NewRGB(255, 255, 255)); |
PHL_DrawRect(142, 210, 356, 60, PHL_NewRGB(0, 20, 0)); |
PHL_DrawRect(148, 216, 48, 48, PHL_NewRGB(255, 255, 255)); |
PHL_DrawRect(152, 220, 40, 40, PHL_NewRGB(119, 166, 219)); |
//Image |
PHL_DrawSurfacePart(152, 220, itemGotX, itemGotY, 40, 40, images[imgItems]); |
//Text |
{ |
int drawX = 196, drawY = 216; |
int twoLayers = 0; |
if (itemName[itemNum]->length + found->length + 2 > 17) { |
twoLayers = 1; |
drawY -= 8; |
} |
drawX = drawCharacter(17, 2, drawX, drawY); |
drawX = drawText(itemName[itemNum], drawX, drawY); |
drawX = drawCharacter(18, 2, drawX, drawY); |
if (twoLayers == 1) { |
drawX = 204; |
drawY += 24; |
} |
drawText(found, drawX, drawY); |
} |
roomDarkness = tempDarkness; |
} |
PHL_EndDrawing(); |
} |
} |
#ifdef EMSCRIPTEN |
return loop; |
#endif |
} |
void saveScreen() |
{ |
PHL_PlaySound(sounds[sndPower02], CHN_SOUND); |
herohp = maxhp; |
setHeroHsp(0); |
int saveTimer = 60; |
char loop = 1; |
while (PHL_MainLoop() && loop == 1) |
{ |
PHL_StartDrawing(); |
gameDraw(1); |
PHL_DrawRect(140, 208, 360, 64, PHL_NewRGB(255, 255, 255)); |
PHL_DrawRect(142, 210, 356, 60, PHL_NewRGB(0, 0, 255)); |
drawTextCentered(saving, 320, 216); |
saveTimer -= 1; |
if (saveTimer <= 0) { |
loop = 0; |
} |
PHL_EndDrawing(); |
} |
if (writeSave(savemap) == 1) |
{ |
if (fileExists(savename)) |
{ |
char fullPath[128]; |
strcpy(fullPath, ""); |
#ifdef _3DS |
strcat(fullPath, "sdmc:/3ds/appdata/HydraCastleLabyrinth/"); |
#endif |
strcat(fullPath, savename); |
remove(fullPath); |
#ifdef EMSCRIPTEN |
EM_ASM( |
FS.syncfs(false,function () { |
Module.print("File sych'd") |
}); |
); |
#endif |
} |
} |
} |
//Result screen and credits |
void gameEnding() |
{ |
int timer = 0; |
char exitLoop = 0; |
//Result screen |
{ |
PHL_StopMusic(); |
PHL_FreeMusic(bgmMusic); |
bgmMusic = PHL_LoadMusic("midi/allclear", 0); |
PHL_PlayMusic(bgmMusic); |
//Calculate completion percentage |
char treasureString[11]; |
{ |
int itemCount = 0; |
int ALLITEMS = 41; |
int i; |
for (i = 0; i < 5; i++) { |
itemCount += hasWeapon[i]; |
} |
for (i = 0; i < 28; i++) { |
itemCount += hasItem[i]; |
} |
for (i = 0; i < 8; i++) { |
itemCount += hasKey[i]; |
} |
sprintf(treasureString, "%d%%", itemCount * 100 / ALLITEMS); |
} |
//Calculate time |
char timeString[12]; |
{ |
int hours = playTime / 216000; |
int minutes = (playTime % 216000) / 3600; |
int seconds = ((playTime % 216000) % 3600) / 60; |
sprintf(timeString, "%02d:%02d:%02d", hours, minutes, seconds); |
} |
int transTimer = 0; |
while (PHL_MainLoop() && exitLoop == 0) |
{ |
timer += 1; |
if (timer >= 500) { |
transTimer += 8; |
} |
if (transTimer >= 360) { |
exitLoop = 1; |
} |
//Animate Effects |
int i; |
for (i = 0; i < MAX_EFFECTS; i++) { |
if (effects[i] != NULL) { |
effectStep(effects[i]); |
} |
} |
PHL_StartDrawing(); |
gameDraw(0); |
PHL_DrawTextBoldCentered("--- ALL CLEAR! ---", 320, 64, YELLOW); |
PHL_DrawTextBoldCentered("TIME", 320, 128, YELLOW); |
PHL_DrawTextBoldCentered(timeString, 320, 144, WHITE); |
PHL_DrawTextBoldCentered("TREASURE", 320, 192, YELLOW); |
PHL_DrawTextBoldCentered(treasureString, 320, 208, WHITE); |
//transition |
if (transTimer > 0) { |
PHL_DrawRect(0, 0, 640, transTimer, PHL_NewRGB(0, 0, 0)); |
PHL_DrawRect(0, 240 + (240 - transTimer), 640, 480, PHL_NewRGB(0, 0, 0)); |
} |
PHL_EndDrawing(); |
} |
} |
//Credits |
{ |
timer = 0; |
exitLoop = 0; |
PHL_StopMusic(); |
PHL_FreeMusic(bgmMusic); |
bgmMusic = PHL_LoadMusic("midi/ending", 0); |
PHL_PlayMusic(bgmMusic); |
int timer = 0; |
double viewY = 0; |
int maxViewY = 2200; |
double imageIndex = 0; |
while (PHL_MainLoop() && exitLoop == 0) |
{ |
timer += 1; |
if (timer >= 2220) { |
exitLoop = 1; |
} |
viewY += 1; |
if (viewY >= maxViewY - 480) { |
viewY = maxViewY - 480; |
} |
imageIndex += 0.1; |
if (imageIndex >= 2) { |
imageIndex -= 2; |
} |
PHL_StartDrawing(); |
PHL_DrawRect(0, 0, 640, 480, PHL_NewRGB(0, 0, 0)); |
if (exitLoop == 0) { |
PHL_DrawTextBoldCentered("- STAFF -", 320, 480 - viewY, YELLOW); |
PHL_DrawTextBoldCentered("SPRITES", 320, 560 - viewY, YELLOW); |
PHL_DrawTextBoldCentered("BUSTER", 320, 576 - viewY, WHITE); |
PHL_DrawTextBoldCentered("PROGRAM", 320, 640 - viewY, YELLOW); |
PHL_DrawTextBoldCentered("BUSTER", 320, 656 - viewY, WHITE); |
PHL_DrawTextBoldCentered("MUSIC", 320, 720 - viewY, YELLOW); |
PHL_DrawTextBoldCentered("MATAJUUROU", 320, 736 - viewY, WHITE); |
PHL_DrawTextBoldCentered("TEST PLAYER", 320, 800 - viewY, YELLOW); |
PHL_DrawTextBoldCentered("ZAC", 320, 816 - viewY, WHITE); |
PHL_DrawTextBoldCentered("- SPECIAL THANKS -", 320, 912 - viewY, YELLOW); |
PHL_DrawTextBoldCentered("QUADRUPLE D", 320, 992 - viewY, YELLOW); |
PHL_DrawTextBoldCentered("SANDMAN", 320, 1008 - viewY, WHITE); |
PHL_DrawTextBoldCentered("KBGM", 320, 1072 - viewY, YELLOW); |
PHL_DrawTextBoldCentered("KR.SHIN", 320, 1088 - viewY, WHITE); |
PHL_DrawTextBoldCentered("KBGMPLAYER", 320, 1152 - viewY, YELLOW); |
PHL_DrawTextBoldCentered("NARUTO", 320, 1168 - viewY, WHITE); |
PHL_DrawTextBoldCentered("SOUND EFFECT", 320, 1232 - viewY, YELLOW); |
PHL_DrawTextBoldCentered("OSABISHIYUUKI", 320, 1248 - viewY, WHITE); |
PHL_DrawTextBoldCentered("EDGE", 320, 1312 - viewY, YELLOW); |
PHL_DrawTextBoldCentered("TAKABO", 320, 1328 - viewY, WHITE); |
PHL_DrawTextBoldCentered("THE END", 320, maxViewY - 284 - viewY, YELLOW); |
PHL_DrawSurfacePart(300, maxViewY - 256 - viewY, (int)imageIndex * 40, 280, 40, 80, images[imgHero]); |
} |
PHL_EndDrawing(); |
} |
} |
forceGameExit = 1; |
} |
//Black screen between screens |
void screenTransition() |
{ |
char timer = 15; |
while (PHL_MainLoop() && timer > 0) |
{ |
PHL_StartDrawing(); |
PHL_DrawRect(0, 0, 640, 480, PHL_NewRGB(0, 0, 0)); |
timer -= 1; |
PHL_EndDrawing(); |
} |
if (autoSave == 1) { |
writeSave(savename); |
} |
} |
void enterDoor() |
{ |
//Is not leaving boss room prematurely |
bossFlag = 0; |
level = lastDoor->warplevel; |
screenX = lastDoor->warpcoords % 12; |
screenY = lastDoor->warpcoords / 12; |
herox = lastDoor->warpx; |
heroy = lastDoor->warpy; |
PHL_StopMusic(); |
PHL_FreeMusic(bgmMusic); |
if (level == 0) { |
//Free uncommon images |
PHL_FreeSurface(images[imgMisc2040]); |
PHL_FreeSurface(images[imgMisc6020]); |
PHL_FreeSurface(images[imgDark]); |
}else{ |
bgmMusic = PHL_LoadMusic("midi/start", 0); |
PHL_PlayMusic(bgmMusic); |
int timer = 125; |
while (PHL_MainLoop() && timer > 0) |
{ |
timer -= 1; |
PHL_StartDrawing(); |
PHL_DrawRect(0, 0, 640, 480, PHL_NewRGB(0, 0, 0)); |
drawTextCentered(dungeon[level - 1], 320, 216); |
PHL_EndDrawing(); |
} |
PHL_StopMusic(); |
PHL_FreeMusic(bgmMusic); |
loadUncommonImages(); |
} |
//Reload tileset |
PHL_FreeSurface(images[imgTiles]); |
images[imgTiles] = PHL_LoadQDA(tilesetStrings[level]); |
bgmMusic = PHL_LoadMusic(musicStrings[level], 1); |
changeScreen(0, 0); |
PHL_PlayMusic(bgmMusic); |
} |
void loadScreen() |
{ |
//Stop music if you leave a boss room early |
if (bossFlag == 1) { |
PHL_StopMusic(); |
PHL_FreeMusic(bgmMusic); |
bgmMusic = PHL_LoadMusic(musicStrings[level], 1); |
PHL_PlayMusic(bgmMusic); |
} |
bossDefeatedFlag = bossFlag = 0; |
roomDarkness = 0; |
screenTransition(); |
int fileNum = stage[level][(screenY * 12) + screenX]; |
//Cycle through this process twice. Once for the backgroud, and one for the foreground |
int cycle = 0; |
for (cycle = 0; cycle < 2; cycle++) |
{ |
//Build file string |
char toChar[4]; |
sprintf(toChar, "%03d", fileNum); |
char dest[80]; |
strcpy(dest, ""); |
#ifdef _3DS |
strcat(dest, "romfs:/map/"); |
#elif defined(__amigaos4__) || defined(__MORPHOS__) |
strcat(dest, "PROGDIR:data/map/"); |
#elif defined(_SDL) |
strcat(dest, "data/map/"); |
#else |
strcat(dest, "romfs/map/"); |
#endif |
strcat(dest, toChar); |
//load background on first pass |
if (cycle == 0) { |
strcat(dest, "a"); |
} |
strcat(dest, ".map"); |
//Read file |
FILE* file; |
if ((file = fopen(dest, "rb"))) |
{ |
char* memblock; |
int size; |
fseek(file, 0, SEEK_END); |
size = ftell(file); |
memblock = (char*)malloc(size); |
fseek(file, 0, SEEK_SET); |
if(fread(memblock, 1, size, file) != size) |
printf("Warning, could not read %s correctly\n", dest); |
fclose(file); |
//Load data |
int count = 162; //Level data starts 118 |
int xx, yy; |
int valx = 0, valy = 0; |
int raw; |
for (yy = 0; yy < 12; yy++) { |
for (xx = 0; xx < 16; xx++) { |
raw = (unsigned)memblock[count]; |
valx = raw & 0x0F; |
valy = raw & 0xF0; |
valy >>= 4; |
if (cycle == 0) { |
background.tileX[xx][yy] = valx; |
background.tileY[xx][yy] = valy; |
}else if (cycle == 1) { |
foreground.tileX[xx][yy] = valx; |
foreground.tileY[xx][yy] = valy; |
collisionTiles[xx][yy] = getTileType(valx, valy); |
//Breakable blocks |
if (valy == 11 && (valx == 0 || valx == 1 || valx == 2)) { |
int secret = 0; |
if (valx == 2) { |
secret = 1; |
} |
createDestroyable(xx * 40, yy * 40, secret); |
} |
//Lava |
if (valx == 2 && valy == 1) { |
createEffect(10, xx * 40, yy * 40); |
foreground.tileX[xx][yy] = 0; |
foreground.tileY[xx][yy] = 0; |
} |
//Water |
if (valx == 6 && valy == 1) { |
createEffect(11, xx * 40, yy * 40); |
foreground.tileX[xx][yy] = 0; |
foreground.tileY[xx][yy] = 0; |
} |
} |
count += 2; |
} |
count += 12; |
} |
free(memblock); |
}else{ |
PHL_ErrorScreen("Map file was not found"); |
} |
} |
PHL_UpdateBackground(background, foreground); |
//Load file |
//Build file string |
char toChar[4]; |
sprintf(toChar, "%03d", fileNum); |
char dest[30]; |
#ifdef _3DS |
strcpy(dest, "romfs:/obj/"); |
#elif defined(__amigaos4__) || defined(__MORPHOS__) |
strcpy(dest, "PROGDIR:data/obj/"); |
#elif defined(_SDL) |
strcpy(dest, "data/obj/"); |
#else |
strcpy(dest, "romfs/obj/"); |
#endif |
//Add a 0 if needed |
/* |
if (fileNum < 100) { |
strcat(dest, "0"); |
} |
*/ |
strcat(dest, toChar); |
strcat(dest, ".dat"); |
FILE* file; |
if ((file = fopen(dest, "rb"))) { |
unsigned char* memblock; |
int size; |
fseek(file, 0, SEEK_END); |
size = ftell(file); |
memblock = (unsigned char*)malloc(size); |
fseek(file, 0, SEEK_SET); |
if(fread(memblock, 1, size, file) != size) |
printf("Warning: could not read %s correctly\n", dest); |
int count = 0; |
while (count < size) { |
int type = memblock[count]; |
if (type <= 10) |
{ |
if (type == 0 || type == 9) { //Blue/Red Slime |
createSlime(memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3], memblock[count + 4]); |
} |
else if (type == 1) { //Bat (grey/red) |
createBat(memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3]); |
} |
else if (type == 2) { //Slug |
createSlug(memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3]); |
} |
else if (type == 3) { //Knight |
createKnight(memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3]); |
} |
else if (type == 4) { //Rhyno head |
createHead(0, memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3], memblock[count+4], memblock[count+5]); |
} |
else if (type == 5) { //Dragon head |
createHead(2, memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3], memblock[count+4], memblock[count+5]); |
} |
else if (type == 6) { //Goblin/medusa head |
createHead(1, memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3], memblock[count+4], memblock[count+5]); |
} |
else if (type == 7) { //Demon head |
createHead(3, memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3], memblock[count+4], memblock[count+5]); |
} |
else if (type == 10) { //Fireball head |
createHead(4, memblock[count+1] * 20, memblock[count+2] * 20, 1, memblock[count+3], memblock[count+4]); |
} |
} |
else if (type <= 20) |
{ |
if (type == 11) { //Poison Gas |
createGas(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); |
} |
else if (type == 12) { //Flying skull |
createSkull(memblock[count+1] * 20, memblock[count+2] * 20); |
} |
else if (type == 13) { //Fish |
createFish(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); |
} |
else if (type == 14) { //Water Jumper |
createWaterJumper(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3], memblock[count+4], memblock[count+5]); |
} |
else if (type == 15) { //Podoboo |
createPodoboo(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3], memblock[count+4]); |
} |
else if (type == 16) { //Thwomp |
createThwomp(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3], memblock[count+4], memblock[count+5], memblock[count+6]); |
} |
else if (type == 17) { //Skeleton |
createSkeleton(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); |
} |
else if (type == 18) { //Ghoul |
createGhoul(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); |
} |
else if (type == 19) { //Seal |
createSeal(memblock[count+1]*20, memblock[count+2]*20); |
} |
else if (type == 20) { //Jellyfish |
createJellyfish(memblock[count+1]*20, memblock[count+2]*20); |
} |
} |
else if (type <= 30) |
{ |
if (type == 21) { //Wizard |
createWizard(memblock[count+1]*20, memblock[count+2]*20); |
} |
else if (type == 22) { //Pendulum |
createPendulum(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); |
} |
else if (type == 24) { //Bee |
createBee(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); |
} |
else if (type == 25) { //Air Jar |
//createJar(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3], memblock[count+4]); |
createHead(5, memblock[count + 1] * 20, memblock[count + 2] * 20, 0, memblock[count+3], memblock[count+4]); |
} |
else if (type == 26) { //Boar |
createBoar(memblock[count+1]*20, memblock[count+2]*20); |
} |
else if (type == 27) { //Fire Wheel |
createFirewheel(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); |
} |
else if (type == 28) { //Rock Golem |
createGolem(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); |
} |
else if (type == 29) { //Poison Knight |
createPoisonknight(memblock[count+1]*20, memblock[count+2]*20); |
} |
else if (type == 30) { //Electricity doggy |
createDog(memblock[count+1]*20, memblock[count+2]*20); |
} |
} |
else if (type < 40) |
{ |
if (type == 31) { |
createBoomknight(memblock[count+1]*20, memblock[count+2]*20); |
} |
else if (type == 32) { |
createPumpkinenemy(memblock[count+1]*20, memblock[count+2]*20); |
} |
} |
else if (type < 50) |
{ |
//Bosses |
if (type == 40) { |
createDodo(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); |
} |
else if (type == 41) { |
createBatboss(memblock[count+1] * 20, memblock[count+2] * 20); |
} |
else if (type == 42) { |
createCrab(memblock[count+1] * 20, memblock[count+2] * 20); |
} |
else if (type == 43) { |
createGyra(memblock[count+1] * 20, memblock[count+2] * 20); |
} |
else if (type == 44) { |
createLolidra(memblock[count+1] * 20, memblock[count+2] * 20); |
} |
else if (type == 45) { |
createDevil(memblock[count+1] * 20, memblock[count+2] * 20); |
} |
else if (type == 46) { |
createGarm(memblock[count+1] * 20, memblock[count+2] * 20); |
} |
else if (type == 47) { |
createHydra(memblock[count+1] * 20); |
} |
} |
else if (type <= 60) |
{ |
//Objects |
if (type == 50) { //Moving platforms |
createPlatform(0, memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3] * 20, memblock[count + 4] * 20, memblock[count + 5], memblock[count+6]); |
} |
else if (type == 51) { //Loose block |
createPlatform(1, memblock[count + 1] * 20, memblock[count + 2] * 20, 0, 0, 0, memblock[count+3]); |
} |
else if (type == 52) { //Locked Block |
createLockBlock(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); |
} |
else if (type == 53) { //Gate |
createGate(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); |
} |
else if (type == 54) { //Statue |
createStatue(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); |
} |
else if (type == 55) { //Megaman block |
createPlatform(2, memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3], memblock[count + 4], 0, 0); |
} |
else if (type == 56) { //Electric gate |
createShockgate(memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3]); |
} |
else if (type == 57) { //Hydra platform |
createPlatform(3, memblock[count + 1] * 20, memblock[count + 2] * 20, 0, 0, 0, 0); |
} |
} |
else if (type < 70) |
{ |
} |
else/* if (type <= 80)*/ |
{ |
if (type == 70) { //Breakable Block |
createDestroyable(memblock[count+1] * 20, memblock[count+2] * 20, 1); |
} |
else if (type == 71) { //Secret Trigger |
createSecretTrigger(memblock[count+1], memblock[count+2], memblock[count+3]); |
} |
else if (type == 73) { //Chests |
createChest(memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3], memblock[count + 4]); |
} |
else if (type == 74) { //Save Points |
createSavePoint(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); |
} |
else if (type == 75) { //door |
createDoor(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3], memblock[count+4], memblock[count+5] * 20, memblock[count+6] * 20, memblock[count+7]); |
} |
else if (type == 76) { //Light Switch |
createSwitch(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); |
} |
else if (type == 77) { //Floor Button |
createFloorPad(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); |
} |
else if (type == 78) { |
roomDarkness = 1; |
} |
else if (type == 79) { //Ladder Spawner |
createLadder(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); |
} |
else if (type == 80) { //Generator |
createGenerator(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); |
} |
else if (type == 81) { //Crown |
createCrown(memblock[count+1] * 20, memblock[count+2] * 20); |
} |
} |
count += 16; |
} |
free(memblock); |
fclose(file); |
} |
} |
void drawHud() |
{ |
//Repress certain screen altering variables |
int tempDark = roomDarkness; |
roomDarkness = 0; |
int tempQuake = quakeTimer; |
quakeTimer = 0; |
//Change HUD position |
int drawy = 8; |
{ |
if (heroy <= 100) { |
drawy = 400; |
} |
} |
//Move scrolling health bar |
{ |
if (drawhp > herohp) { |
drawhp -= 1; |
} |
if (drawhp < herohp) { |
drawhp += 1; |
} |
} |
//Main image |
{ |
PHL_DrawSurfacePart(8, drawy, 0, 0, 368, 64, images[imgHud]); |
} |
//Health bar |
{ |
PHL_RGB hpbarc = PHL_NewRGB(128, 255, 0); |
if (getHeroPoisoned() > 0) { |
hpbarc = PHL_NewRGB(255, 128, 255); |
} |
PHL_DrawRect(76, drawy + 8, maxhp * 2, 6, PHL_NewRGB(255, 0, 0)); |
PHL_DrawRect(76, drawy + 8, drawhp * 2, 6, hpbarc); |
} |
//Ammo counter |
{ |
char c[10]; |
sprintf(c, "%02d", heroAmmo); |
PHL_DrawTextBold(c, 74, drawy + 36, WHITE); |
} |
//Draw weapon icon |
{ |
int wx = 32 * (heroWeapon + 1); |
if (hasWeapon[heroWeapon] == 0) { |
wx = 0; |
} |
PHL_DrawSurfacePart(24, drawy + 16, wx, 64, 32, 32, images[imgHud]); |
} |
//Restore screen altering variables |
{ |
quakeTimer = tempQuake; |
roomDarkness = tempDark; |
} |
} |
void freeArrays() |
{ |
int i; |
for (i = 0; i < MAX_EFFECTS; i++) { |
effectDestroy(i); |
} |
for (i = 0; i < MAX_OBJECTS; i++) { |
objectDestroy(i); |
} |
for (i = 0; i < MAX_ENEMIES; i++) { |
enemyDestroy(i); |
} |
for (i = 0; i < MAX_WEAPONS; i++) { |
weaponDestroy(i); |
} |
for (i = 0; i < MAX_PLATFORMS; i++) { |
platformDestroy(i); |
} |
} |
void changeScreen(int dx, int dy) |
{ |
roomSecret = 0; |
freeArrays(); |
screenX += dx; |
screenY += dy; |
loadScreen(); |
writeSave(savename); |
} |
int getTileType(int valx, int valy) { |
int result = 0; |
if (valy == 11 && valx == 8) { |
result = 3; //Ladder Top |
}else |
if (valy == 1 && valx == 1) { |
result = 5; //Lava |
}else |
if (valy > 7) { |
result = 1; //Solid |
}else |
//specifics |
if (valy == 0 && (valx == 3 || valx == 5)) { |
result = 2; //Ladders |
}else |
if (valy == 1 && valx == 5) { |
result = 4; //Water |
}else |
if (valx == 0 && (valy == 1 || valy == 2)) { |
result = 6; //Spikes |
}else |
if (valy == 11 && (valx == 0 || valx == 1 || valx == 2)) { |
result = 1; //Breakable solid block |
} |
if (level == 4 && valy == 3 && (valx == 0 || valx == 1 || valx == 2)) { |
result = 6; //Spikes |
} |
return result; |
} |
//Save file load/save |
int writeSave(char* fname) |
{ |
int result = 0; |
//mkdir("data"); |
FILE* f; |
char fullPath[4096]; |
strcpy(fullPath, ""); |
#ifdef _3DS |
strcat(fullPath, "sdmc:/3ds/appdata/HydraCastleLabyrinth/"); |
#elif _KOLIBRI |
strcat(fullPath, KOS_HCL_SAVES_PATH); |
#endif |
strcat(fullPath, fname); |
if ( (f = fopen(fullPath, "wb")) ) { |
int size = 4548; |
unsigned char* memblock = (unsigned char*)malloc(size); |
memset(memblock, 0, size); |
#if defined(__amigaos4__) || defined(__MORPHOS__) |
#define D 3 |
#else |
#define D 0 |
#endif |
memblock[0x0+D] = herohp; |
memblock[0x4+D] = maxhp; |
memblock[0x8+D] = heroAmmo; |
memblock[0x0C+D] = maxAmmo; |
if (heroWeapon == -1) { |
memblock[0x10] = 0; |
}else{ |
memblock[0x10] = heroWeapon; |
} |
memblock[0x14] = 1; //Unknown, but always resets to 1 |
int i; |
for (i = 0; i < 60; i++) { |
memblock[(0x3FC) + i] = flags[i]; |
} |
for (i = 0; i < 5; i++) { |
memblock[(0x7E4) + i] = hasWeapon[i]; |
} |
int itemorder[28] = { 0x7F6, 0x7FA, 0x7F9, 0x7F8, 0x7F1, 0x7F3, 0x7F2, |
0x7FB, 0x7ED, 0x7EF, 0x7EE, 0x7F0, 0x7EC, 0x7F4, |
0x7F7, 0x7F5, 0x7EA, 0x7EB, 0x7FF, 0x803, 0x804, |
0x7FE, 0x802, 0x805, 0x800, 0x7FD, 0x7FC, 0x801 }; |
for (i = 0; i < 28; i++) { |
memblock[itemorder[i]] = hasItem[i]; |
} |
for (i = 0; i < 8; i++) { |
memblock[(0x806) + i] = hasKey[i]; |
} |
int writeHerox = herox; |
int writeHeroy = heroy; |
memcpy(&memblock[0x11B0], &writeHerox, 4); |
memcpy(&memblock[0x11B4], &writeHeroy, 4); |
if (getHeroDirection() == 1) { |
memblock[0x11C0+D] = 0; |
}else{ |
memblock[0x11C0+D] = 1; |
} |
memblock[0x11B8+D] = level; |
//Screen |
memblock[0x11BC+D] = (screenX) + (screenY * 12); |
//Time |
memcpy(&memblock[0x11AC], &playTime, 4); |
fwrite(memblock, 1, size, f); |
free(memblock); |
result = 1; |
fclose(f); |
} |
#ifdef EMSCRIPTEN |
EM_ASM( |
//persist changes |
FS.syncfs(false,function (err) { |
assert(!err); |
}); |
); |
#endif |
return result; |
} |
void loadSave(char* fname) |
{ |
FILE* f; |
char fullPath[128]; |
strcpy(fullPath, ""); |
#ifdef _3DS |
strcat(fullPath, "sdmc:/3ds/appdata/HydraCastleLabyrinth/"); |
#endif |
strcat(fullPath, fname); |
if ((f = fopen(fullPath, "rb"))) { |
//Reminder: read order matters |
unsigned long loadTemp = 0; |
int tmp; |
//Hero HP |
tmp = fread(&loadTemp, 4, 1, f); |
herohp = loadTemp; |
drawhp = herohp; |
//Max HP |
tmp = fread(&loadTemp, 4, 1, f); |
maxhp = loadTemp; |
//Ammo |
tmp = fread(&loadTemp, 4, 1, f); |
heroAmmo = loadTemp; |
//Max Ammo |
tmp = fread(&loadTemp, 4, 1, f); |
maxAmmo = loadTemp; |
int loadedWeapon = 0; |
tmp = fread(&loadedWeapon, 1, 1, f); |
//Read Flags |
fseek(f, 0x3FC, SEEK_SET); |
int i; |
for (i = 0; i < 60; i++) { |
tmp = fread(&flags[i], 1, 1, f); |
} |
//Read weapons |
fseek(f, 0x7E4, SEEK_SET); |
for (i = 0; i < 5; i++) { |
tmp = fread(&hasWeapon[i], 1, 1, f); |
} |
heroWeapon = -1; |
if (hasWeapon[loadedWeapon] == 1) { |
heroWeapon = loadedWeapon; |
} |
//Read items |
int itemorder[28] = { 16, 17, 12, 8, 10, 9, 11, |
4, 6, 5, 13, 15, 0, 14, |
3, 2, 1, 7, 26, 25, 21, |
18, 24, 27, 22, 19, 20, 23 }; |
fseek(f, 0x7EA, SEEK_SET); |
for (i = 0; i < 28; i++) { |
tmp = fread(&hasItem[itemorder[i]], 1, 1, f); |
} |
//Read keys |
for (i = 0; i < 8; i++) { |
tmp = fread(&hasKey[i], 1, 1, f); |
} |
fseek(f, 0x11AC, SEEK_SET); |
tmp = fread(&playTime, 4, 1, f); |
//fseek(f, 4540, SEEK_SET); |
//Hero X and Y |
tmp = fread(&loadTemp, 4, 1, f); |
herox = loadTemp; |
tmp = fread(&loadTemp, 4, 1, f); |
heroy = loadTemp; |
//Level |
tmp = fread(&loadTemp, 4, 1, f); |
level = loadTemp; |
//Screen coords |
tmp = fread(&loadTemp, 4, 1, f); |
screenX = (loadTemp) % 12; |
screenY = ((int)(loadTemp) / 12); |
//Direction |
tmp = fread(&loadTemp, 4, 1, f); |
if (loadTemp == 0) { |
setHeroDirection(1); |
}else{ |
setHeroDirection(-1); |
} |
fclose(f); |
#undef D |
} |
} |
int fileExists(char* fpath) |
{ |
int result = 0; |
char fullPath[128]; |
strcpy(fullPath, ""); |
#ifdef _3DS |
strcat(fullPath, "sdmc:/3ds/appdata/HydraCastleLabyrinth/"); |
#endif |
strcat(fullPath, fpath); |
FILE* f; |
if ( (f = fopen(fullPath, "rb")) ) { |
result = 1; |
fclose(f); |
} |
return result; |
} |
void playSecret() |
{ |
PHL_StopMusic(); |
secretTimer = 210; |
} |
void secretCountdown() |
{ |
if (secretTimer > 0) { |
secretTimer -= 1; |
if (secretTimer <= 0) { |
PHL_StopMusic(); |
if (bossFlag == 0 && bossDefeatedFlag == 0) { |
PHL_PlayMusic(bgmMusic); |
} |
}else if (secretTimer == 180) { |
PHL_PlayMusic(bgmSecret); |
} |
} |
} |
int getDrawHP() |
{ |
return drawhp; |
} |
void setDrawHP(int val) |
{ |
drawhp = val; |
} |
int getLevel() |
{ |
return level; |
} |
void setBossRoom() |
{ |
bossFlag = 1; |
PHL_StopMusic(); |
secretTimer = 0; |
PHL_FreeMusic(bgmMusic); |
if (level != 8) { |
bgmMusic = PHL_LoadMusic("midi/boss", 1); |
}else{ |
bgmMusic = PHL_LoadMusic("midi/lastboss", 1); |
} |
PHL_PlayMusic(bgmMusic); |
} |
void setAutoSave(char val) |
{ |
autoSave = val; |
} |
char getAutoSave() |
{ |
return autoSave; |
} |
void loadUncommonImages() |
{ |
//Seal Toungs |
if (level == 4) { |
images[imgMisc2040] = PHL_LoadQDA("chr20x40.BMP"); |
} |
//Darkness |
if (level == 5) { |
images[imgDark] = PHL_LoadQDA("dark.bmp"); |
} |
//Dragon Flame |
if (level == 7 || level == 8) { |
images[imgMisc6020] = PHL_LoadQDA("chr60x20.bmp"); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/game.h |
---|
0,0 → 1,237 |
#ifndef GAME_H |
#define GAME_H |
#include "PHL.h" |
#include "enemy.h" |
#include "enemies/slime.h" |
#include "enemies/bat.h" |
#include "enemies/slug.h" |
#include "enemies/knight.h" |
#include "enemies/heads.h" |
#include "enemies/gas.h" |
#include "enemies/skull.h" |
#include "enemies/fish.h" |
#include "enemies/waterjumper.h" |
#include "enemies/podoboo.h" |
#include "enemies/thwomp.h" |
#include "enemies/dodo.h" |
#include "enemies/batboss.h" |
#include "enemies/crab.h" |
#include "enemies/skeleton.h" |
#include "enemies/ghoul.h" |
#include "enemies/seal.h" |
#include "enemies/jellyfish.h" |
#include "enemies/wizard.h" |
#include "enemies/pendulum.h" |
#include "enemies/gyra.h" |
#include "enemies/lolidra.h" |
#include "enemies/bee.h" |
#include "enemies/devil.h" |
#include "enemies/firewheel.h" |
#include "enemies/boar.h" |
#include "enemies/golem.h" |
#include "enemies/garm.h" |
#include "enemies/poisonknight.h" |
#include "enemies/dog.h" |
#include "enemies/boomknight.h" |
#include "enemies/pumpkin.h" |
#include "enemies/hydra.h" |
#include "object.h" |
#include "effect.h" |
#include "weapon.h" |
#include "platform.h" |
#define TITLE 0 |
#define GAME 1 |
#define INVENTORY 2 |
#define OPTIONS 3 |
#define SAVING 4 |
#define LEVELSTART 5 |
#define GETITEM 6 |
//Sound channels |
#define CHN_MUSIC 0 |
#define CHN_SOUND 1 //Various sounds, like menus and fanfares |
#define CHN_HERO 2 |
#define CHN_WEAPONS 3 |
#define CHN_ENEMIES 4 |
#define CHN_EFFECTS 5 |
extern Door* lastDoor; |
extern int secretTimer; |
extern int levelStartTimer; |
extern int saveTimer; |
extern int quakeTimer; |
extern int bellFlag; |
extern int bossFlag; |
extern int bossDefeatedFlag; |
extern char roomDarkness; |
//Used for item get message |
extern int itemGotX; |
extern int itemGotY; |
extern int roomSecret; |
extern int collisionTiles[16][12]; |
//Playtime in frames. At 60 frames per second can hold ~828 1/2 days worth of playtime if my math isn't shit |
extern unsigned long playTime; |
//Inventory |
extern unsigned char hasWeapon[5]; |
extern unsigned char hasItem[28]; |
extern unsigned char hasKey[8]; |
//Save data flags |
extern unsigned char flags[60]; |
extern PHL_Background background, |
foreground; |
//Game assets |
extern PHL_Surface images[15]; |
extern PHL_Music bgmMusic; |
extern PHL_Music bgmSecret; |
extern PHL_Music bgmGameover; |
extern PHL_Sound sounds[43]; |
#define MAX_WEAPONS 5 |
extern Weapon* weapons[MAX_WEAPONS]; |
#define MAX_OBJECTS 40 |
extern Object* objects[MAX_OBJECTS]; |
#define MAX_ENEMIES 20 |
extern Enemy* enemies[MAX_ENEMIES]; |
#define MAX_EFFECTS 30 |
extern Effect* effects[MAX_EFFECTS]; |
#define MAX_PLATFORMS 10 |
extern Platform* platforms[MAX_PLATFORMS]; |
//Graphic names |
#define imgTiles 0 |
#define imgEnemies 1 |
#define imgHud 2 |
#define imgMisc20 3 |
#define imgMisc32 4 |
#define imgHero 5 |
#define imgItems 6 |
#define imgExplosion 7 |
#define imgBoss 8 |
#define imgMisc2040 9 |
#define imgFontKana 10 |
#define imgBoldFont 11 |
#define imgDark 12 |
#define imgMisc6020 13 |
#define imgTitle01 14 |
//Sound names |
#define sndBee01 0 |
#define sndBell01 1 |
#define sndBom01 2 |
#define sndBom02 3 |
#define sndBom03 4 |
#define sndDoor00 5 |
#define sndFire01 6 |
#define sndGas01 7 |
#define sndGet01 8 |
#define sndGet02 9 |
#define sndHit01 10 |
#define sndHit02 11 |
#define sndHit03 12 |
#define sndHit04 13 |
#define sndHit05 14 |
#define sndHit06 15 |
#define sndHit07 16 |
#define sndJump01 17 |
#define sndJump02 18 |
#define sndNg 19 |
#define sndOk 20 |
#define sndPi01 21 |
#define sndPi02 22 |
#define sndPi03 23 |
#define sndPi04 24 |
#define sndPi05 25 |
#define sndPi06 26 |
#define sndPi07 27 |
#define sndPi08 28 |
#define sndPi09 29 |
#define sndPi10 30 |
#define sndPower01 31 |
#define sndPower02 32 |
#define sndShot01 33 |
#define sndShot02 34 |
#define sndShot03 35 |
#define sndShot04 36 |
#define sndShot05 37 |
#define sndShot06 38 |
#define sndShot07 39 |
#define sndStep01 40 |
#define sndWater01 41 |
#define sndWolf01 42 |
#ifdef _SDL |
extern char savename[4096]; |
extern char savemap[4096]; |
#else |
#define savename "data/save.tmp" |
#define savemap "map/018.map" |
#endif |
#ifdef _KOLIBRI |
#define KOS_HCL_SAVES_PATH "/tmp0/1/.hydracastlelabyrinth" |
#define KOS_TMP_DIR "/tmp0/1" |
#endif |
void loadImages(); |
void freeImages(); |
void loadResources(); |
void freeResources(); |
void game(); |
void gameSetup(); |
void gameCleanup(); |
void enterDoor(); |
#ifdef EMSCRIPTEN |
void getItemSetup(int itemNum); |
int getItemEMStep(); |
#else |
void getItem(int itemNum); |
#endif |
void saveScreen(); |
void gameEnding(); |
//void enterDoor(Door* d); |
void loadScreen(); |
void changeScreen(int dx, int dy); |
int writeSave(char* fname); |
void loadSave(char* fname); |
int fileExists(char* fpath); |
void playSecret(); |
void secretCountdown(); |
int getDrawHP(); |
void setDrawHP(int val); |
int getLevel(); |
void setBossRoom(); |
void setAutoSave(char val); |
char getAutoSave(); |
#endif |
/contrib/games/hydracastlelabyrinth/src/hero.c |
---|
0,0 → 1,1415 |
#include "hero.h" |
#include "game.h" |
#include <math.h> |
#include "weapon.h" |
#include "platform.h" |
#include <stdio.h> |
//State constants |
const char NORMAL = 0; |
const char SLASH = 1; |
const char HIT = 2; |
const char LADDER = 3; |
const char STONE = 4; |
const char CHARGE = 5; |
//#define GETITEM 6 |
const char DOOR = 7; |
const char DEATH = 8; |
const char QUAKE = 9; |
int state; |
double herox, heroy; |
double herohp, maxhp; |
int heroAmmo, maxAmmo; |
int heroWeapon; |
Mask heroMask; |
Mask shieldMask; |
void updateMask(); |
void heroChangeScreen(int dx, int dy); |
int herodir = 1; |
int canCharge = 0; |
int canJump = 0; |
int onground = 0; |
int heldUp = 0; |
const double GRAVITY = 0.3; |
const double CLIMBSPEED = 1.2; |
const double CLIMBSPEEDPOWER = 2.0; |
double vsp = 0; |
double hsp = 0; |
double imageIndex = 0; |
double jumpspd = 7.5; |
int invincible = 0; |
int timer = 0; |
int chargeTimer = 0; |
int shieldTimer = 0; //Holds up shield if this is 0 |
int stun = 0; |
int stunTimer = 0; |
int poisoned = 0; |
int stoneTimer = 0; |
int stoneState = 0; |
int stoneDir = 1; |
int inWater = 0; |
int drownTimer = 0; |
void heroSetup() |
{ |
state = NORMAL; |
herodir = 1; |
herox = 320; |
heroy = 320; |
vsp = 0; |
hsp = 0; |
imageIndex = 0; |
//climbspd = 1; |
invincible = 0; |
timer = 0; |
chargeTimer = 0; |
shieldTimer = 0; |
poisoned = 0; |
stoneTimer = 0; |
stoneState = 0; |
stoneDir = 1; |
herohp = 128; |
maxhp = 128; |
heroAmmo = 0; |
maxAmmo = 99; |
heroWeapon = -1; |
heroMask.unused = 0; |
heroMask.circle = 0; |
heroMask.w = 24; |
heroMask.h = 26; |
onground = 0; |
canJump = 0; |
heroy += 1; |
if (checkTileCollision(1, getHeroMask()) == 1 || checkTileCollision(3, getHeroMask()) == 1) { |
onground = 1; |
if (hasItem[12] == 1) { |
canJump = 1; |
} |
} |
heroy -= 1; |
shieldMask.unused = 1; |
shieldMask.circle = 0; |
shieldMask.w = 24; |
shieldMask.h = 24; |
shieldMask.x = 0; |
shieldMask.y = 0; |
inWater = -1; |
} |
int heroStep() |
{ |
int result = -1; |
//set HP limits |
{ |
if (herohp > maxhp) { |
herohp = maxhp; |
} |
if (herohp < 0) { |
herohp = 0; |
} |
} |
heldUp = btnUp.held; |
//Counters |
{ |
if (invincible > 0) { |
invincible -= 1; |
} |
} |
//Scripted states |
if (state == DOOR) { |
//Remove some status conditions |
stun = 0; |
poisoned = 0; |
inWater = 0; |
//Animate |
imageIndex += 0.2; |
//Done walking |
if (imageIndex >= 10) { |
enterDoor(); |
state = NORMAL; |
} |
} |
else if (state == DEATH) { |
stun = 0; |
stunTimer = 0; |
poisoned = 0; |
//Animate |
{ |
imageIndex += 0.3; |
if (imageIndex >= 4) { |
imageIndex -= 4; |
} |
//blinking |
if (timer >= 90) { |
invincible = 1; |
}else{ |
invincible = 0; |
} |
} |
timer += 1; |
//Poof |
if (timer == 90) { |
createEffect(2, herox - 32, heroy - 12); |
} |
//Play Music |
if (timer == 150) { |
PHL_PlayMusic(bgmGameover); |
} |
//End game over screen prematurly |
if (timer > 150 && btnStart.pressed == 1) { |
btnStart.pressed = 0; |
timer = 630; |
} |
//Reset game |
if (timer == 630) { |
/* |
FILE* f; |
if ((f = fopen("data/save.tmp", "rb"))) { |
remove("data/save.tmp"); |
} |
fclose(f); |
*/ |
PHL_StopMusic(); |
result = 1; |
} |
} |
//Uncontrollable states, but can move |
else { |
char canGrav = 1; |
double grav = GRAVITY; |
if (state == CHARGE) { |
canGrav = 0; |
shieldTimer = 10; |
vsp = 0; |
//Charge start (rear back) |
{ |
if (timer == 0) { |
imageIndex = 0; |
hsp = -2 * herodir; |
} |
} |
//Friction |
{ |
double fric = 0.3; |
if (hsp < 0) { |
hsp += fric; |
if (hsp >= 0) { |
hsp = 0; |
} |
}else if (hsp > 0) { |
hsp -= fric; |
if (hsp <= 0) { |
hsp = 0; |
} |
} |
} |
timer += 1; |
//Forward charge start |
{ |
if (timer == 15) { |
invincible = 35; |
hsp = 7 * herodir; |
PHL_PlaySound(sounds[sndShot01], CHN_WEAPONS); |
} |
} |
//Animation |
{ |
if (timer > 15) { |
imageIndex = 1; |
} |
if (timer > 19) { |
imageIndex = 2; |
} |
if (timer > 21) { |
imageIndex = 3; |
} |
if (timer == 59) { |
imageIndex = 4; |
} |
} |
//Stop |
if (timer == 30) { |
hsp = 0; |
} |
//End state |
if (timer >= 60) { |
state = NORMAL; |
} |
} |
else if (state == HIT) { |
grav = GRAVITY - 0.05; |
//timer |
{ |
timer -= 1; |
if (timer < 0) { |
timer = 0; |
} |
} |
//Animate |
{ |
imageIndex += 0.33; |
if (imageIndex >= 2) { |
imageIndex -= 2; |
} |
} |
if (onground == 1) { |
hsp = 0; |
} |
//End hit state |
{ |
if (onground == 1 && vsp == 0 && timer == 0) { |
state = NORMAL; |
invincible = 60; |
} |
} |
} |
else if (state == STONE) { |
grav = GRAVITY - 0.05; |
if (stoneState != 2) { |
stoneTimer -= 1; |
//Setup break free animation |
if (stoneTimer <= 0) { |
stoneTimer = 0; |
stoneState = 2; |
imageIndex = 0; |
createRockSmash(herox, heroy + 20); |
herodir = stoneDir; |
} |
} |
//Animate |
imageIndex += 0.16; |
//Frozen state flashes |
if (stoneState != 2 && imageIndex >= 2) { |
imageIndex = 0; |
} |
//In air |
if (stoneState == 0) { |
if (onground == 0) { |
//hsp = -(herodir * 2); |
}else{ |
stoneState = 1; |
createEffect(9, herox, heroy + 20); |
createEffect(9, herox, heroy + 20); |
} |
} |
//On ground |
else if (stoneState == 1) { |
hsp = 0; |
if (btnFaceDown.pressed == 1) { |
stoneTimer -= 30; |
createEffect(9, herox, heroy + 20); |
} |
} |
//Break free animation |
else if (stoneState == 2) { |
imageIndex += 0.16; |
if ((int)imageIndex == 3) { |
createEffect(8, herox - 32, heroy - 22); |
imageIndex += 0.5; |
} |
if (imageIndex >= 17) { |
state = NORMAL; |
stoneState = 0; |
} |
} |
} |
else if (state == QUAKE) { |
grav = GRAVITY - 0.05; |
hsp = 0; |
if (onground == 1) { |
PHL_PlaySound(sounds[sndPi02], CHN_HERO); |
if (timer == 0) { |
vsp = -2 - grav; |
onground = 0; |
} |
else if (timer == 1) { |
vsp = -1 - grav; |
onground = 0; |
} |
else if (timer == 2) { |
vsp = -0.5 - grav; |
onground = 0; |
} |
else if (timer == 3) { |
state = NORMAL; |
vsp = 0; |
} |
timer += 1; |
} |
} |
//Controllable states |
else { |
char canWalk = 1; |
if (state == NORMAL) { |
//Timers |
{ |
if (shieldTimer > 0) { |
shieldTimer -= 1; |
} |
} |
//Change direction with buttons |
{ |
if (btnLeft.held == 1) { |
herodir = -1; |
} |
if (btnRight.held == 1) { |
herodir = 1; |
} |
} |
//Jumping |
{ |
if (btnFaceDown.pressed == 1) { |
if (onground == 1 || canJump == 1) { |
if (onground == 0) { |
canJump = 0; |
} |
vsp = -jumpspd; |
onground = 0; |
PHL_PlaySound(sounds[sndJump01], CHN_HERO); |
} |
} |
//cancel jump |
if (vsp < 0 && btnFaceDown.released == 1) { |
vsp = 0; |
} |
} |
//Animate |
{ |
if (onground == 1 && hsp != 0) { |
imageIndex += 0.1; |
if (imageIndex >= 2) { |
imageIndex -= 2; |
} |
} |
} |
//Charging |
{ |
if (canCharge == 1 && btnFaceLeft.held == 1) { |
chargeTimer += 1; |
//Create Effects |
if (chargeTimer >= 10 && chargeTimer < 66 && ((chargeTimer - 10) % 8) == 0) { |
createEffect(6, herox, heroy + 20); |
} |
if (chargeTimer == 70) { |
PHL_PlaySound(sounds[sndPower01], CHN_SOUND); |
} |
} |
if (canCharge == 1 && chargeTimer >= 70 && btnFaceLeft.released == 1) { |
state = CHARGE; |
timer = 0; |
imageIndex = 0; |
addWeapon(SWORD, herox, heroy); |
} |
} |
//Attack |
{ |
if (stun == 0) { |
//Slash |
if (btnFaceLeft.pressed == 1) { |
state = SLASH; |
imageIndex = 0; |
PHL_PlaySound(sounds[sndShot01], CHN_WEAPONS); |
addWeapon(SWORD, herox, heroy); |
} |
//Weapon |
if (btnFaceRight.pressed == 1) { |
if (heroWeapon != -1) { |
addWeapon(heroWeapon, (int)herox - 20, (int)heroy); |
} |
} |
} |
} |
//Grabbing Ladder |
{ |
//Grab ladder |
if (btnUp.held == 1) { |
PHL_Rect collide = getTileCollisionXY(2, herox, heroy + 20); |
if (collide.x != -1) { |
state = LADDER; |
canWalk = 0; |
hsp = 0; |
vsp = 0; |
herox = collide.x + 20; |
} |
} |
//Climb down onto ladder |
else if (onground == 1 && btnDown.held == 1) { |
PHL_Rect collide = getTileCollisionXY(3, herox, heroy + 40); |
if (collide.x != -1) { |
state = LADDER; |
canWalk = 0; |
hsp = 0; |
vsp = 0; |
herox = collide.x + 20; |
heroy += 1; |
} |
} |
} |
} |
else if (state == SLASH) { |
shieldTimer = 10; |
//Can move in air, not on the ground |
if (onground == 1) { |
canWalk = 0; |
hsp = 0; |
} |
//Animate |
{ |
double imgspd = 0.25; |
if (imageIndex < 1) { |
imgspd = 0.25; |
}else if (imageIndex < 2) { |
imgspd = 0.34; |
}else if (imageIndex < 3) { |
imgspd = 0.34; |
}else if (imageIndex < 4) { |
imgspd = 0.125; |
}else if (imageIndex < 5) { |
imgspd = 0.5; |
} |
imageIndex += imgspd; |
} |
//Finish slash |
{ |
if (imageIndex >= 5) { |
state = NORMAL; |
canCharge = hasItem[17]; //Has red scroll |
chargeTimer = 0; |
} |
} |
} |
else if (state == LADDER) { |
onground = 0; |
canWalk = 0; |
canGrav = 0; |
hsp = 0; |
vsp = 0; |
//Generate final climb speed |
double climbspd = CLIMBSPEED; |
{ |
//Has power bracelet |
if (hasItem[4] == 1) { |
climbspd = CLIMBSPEEDPOWER; |
} |
//Stun slows climb speed |
if (stun > 0) { |
climbspd /= 2; |
} |
} |
//Get up/down axis |
int yaxis = btnDown.held - btnUp.held; |
//Animate |
if (yaxis != 0) { |
imageIndex += 0.125; |
//Limit imageIndex |
if (imageIndex >= 8) { |
imageIndex -= 8; |
} |
} |
//Movement |
heroy += climbspd * yaxis; |
//Touch ground |
{ |
if (yaxis == 1) { |
PHL_Rect collide = getTileCollision(1, getHeroMask()); |
if (collide.x != -1) { |
state = NORMAL; |
heroy = collide.y - 40; |
imageIndex = 0; |
} |
} |
} |
//Off of ladder |
{ |
if (yaxis != 0) { |
if (checkTileCollision(2, getHeroMask()) == 0 && checkTileCollision(3, getHeroMask()) == 0) { |
state = NORMAL; |
if (btnDown.held == 1) { |
onground = 0; |
} |
} |
} |
} |
} |
//Walking |
{ |
if (canWalk == 1) { |
int xaxis = btnRight.held - btnLeft.held; |
hsp = 3 * xaxis; |
} |
} |
//Cancel jump |
{ |
if (vsp < 0 && btnFaceDown.released == 1) { |
vsp = 0; |
} |
} |
//Earthquake |
{ |
if (hasItem[11] == 0) { //Does not have amulete |
if (quakeTimer > 0 && onground == 1) { |
state = QUAKE; |
vsp = -3 - grav; |
timer = 0; |
PHL_PlaySound(sounds[sndPi02], CHN_HERO); |
} |
} |
} |
} |
//Movement |
{ |
//Used to prevent glitching out on ladder tops |
int precheckladder = checkTileCollision(3, getHeroMask()); |
//Horizontal movement |
{ |
if (hsp != 0) { |
double finalhsp = hsp; |
//Slow when climbing and stunned |
{ |
if ( (inWater == 1 && hasItem[5] == 0) || stun == 1) { |
finalhsp /= 4; |
} |
} |
//Speed up movement in water |
{ |
if (inWater == 1 && hasItem[5] == 1) { //Has fins |
finalhsp = (finalhsp / 3) * 2; |
} |
} |
//Move |
herox += finalhsp; |
//Stay within screen during boss fight |
{ |
if (bossFlag == 1) { |
if (herox < 10) { |
herox = 10; |
} |
if (herox > 630) { |
herox = 630; |
} |
} |
} |
//Collide with wall |
{ |
PHL_Rect collide = getTileCollision(1, getHeroMask()); |
if (collide.x == -1 && precheckladder == 0) { |
collide = getTileCollision(3, getHeroMask()); |
} |
//Did collide |
if (collide.x != -1) { |
if (hsp > 0) { |
herox = collide.x - (heroMask.w / 2); |
}else if (hsp < 0) { |
herox = collide.x + 40 + (heroMask.w / 2); |
} |
if (state == STONE) { |
herodir *= -1; |
} |
} |
} |
//Check if walked off ledge |
if (vsp >= 0) { |
heroy += 1; |
if ( checkTileCollision(1, getHeroMask()) //Solid ground |
|| (hasItem[13] == 1 && checkTileCollision(5, getHeroMask())) //Has red shoes |
|| (precheckladder == 0 && checkTileCollision(3, getHeroMask())) ) //Ladder tops |
{}else{ |
onground = 0; |
} |
heroy -= 1; |
} |
} |
} |
//Vertical Movement |
{ |
//Gravity |
if (canGrav == 1 && onground == 0) { |
int maxVsp = 8; |
//Water slows movement |
if (inWater == 1) { |
grav *= 0.5; |
maxVsp *= 0.5; |
} |
vsp += grav; |
if (vsp > maxVsp) { |
vsp = maxVsp; |
} |
} |
//Vertical Movement |
{ |
double tempVsp = vsp; |
char landed = 0; |
//Water slows movement |
if (inWater == 1 || stun == 1) { |
tempVsp *= 0.5; |
} |
//Movement |
heroy += tempVsp; |
//Colliding with floor/ceiling |
{ |
PHL_Rect collide = getTileCollision(1, getHeroMask()); |
if (collide.x == -1&& precheckladder == 0) { |
collide = getTileCollision(3, getHeroMask()); |
} |
if (collide.x == -1 && hasItem[13] == 1) { //has red shoes |
collide = getTileCollision(5, getHeroMask()); |
} |
if (collide.x != -1) { |
//Collide with floor |
if (vsp > 0) { |
heroy = collide.y - 40; |
vsp = 0; |
onground = 1; |
if (hasItem[12] == 1) { //Has blue boots |
canJump = 1; |
} |
landed = 1; |
} |
//Collide with ceiling |
else if (vsp < 0) { |
heroy = collide.y + 40 - (40 - heroMask.h); |
} |
} |
else{ |
//Jumpthrough/moving platforms |
if (vsp >= 0) { |
int i; |
for (i = 0; i < MAX_PLATFORMS; i++) { |
if (platforms[i] != NULL) { |
int onPlatTop = 0; |
if (herox - (heroMask.w / 2) > platforms[i]->mask.x + platforms[i]->mask.w || herox + (heroMask.w / 2) < platforms[i]->mask.x) { |
} |
else{ |
if (platforms[i]->y == heroy + 40 && vsp >= 0) { |
onPlatTop = 1; |
} |
} |
if (onPlatTop == 1 || checkCollision(getHeroMask(), platforms[i]->mask) == 1) { |
heroMask.y -= vsp; |
if (onPlatTop == 1 || checkCollision(heroMask, platforms[i]->mask) == 0) { |
heroy = platforms[i]->mask.y - 40; |
if (vsp != 0) { |
landed = 1; |
} |
vsp = 0; |
onground = 1; |
if (hasItem[12] == 1) { |
canJump = 1; |
} |
} |
} |
} |
} |
} |
} |
} |
//Land on ground after a hit |
if (landed == 1 && (state == HIT || state == STONE)) { |
timer = 60; |
PHL_PlaySound(sounds[sndHit01], CHN_HERO); |
createEffectExtra(3, herox - 30, heroy + 8, -1, 0, 0); |
createEffectExtra(3, herox - 10, heroy + 8, 1, 0, 0); |
} |
} |
} |
} |
//Water stuff |
{ |
//Drown/bubble |
if (inWater == 1) { |
drownTimer -= 1; |
if (drownTimer <= 0) { |
drownTimer = 60; |
if (hasItem[6] == 0) { |
herohp -= 4; |
} |
createEffect(12, herox, heroy + 20); |
PHL_PlaySound(sounds[sndPi06], CHN_SOUND); |
} |
} |
//Splash |
if (checkTileCollision(4, getHeroMask())) { |
if (inWater == 0) { |
drownTimer = 60; |
//Splash effect |
createSplash(herox, heroy); |
} |
inWater = 1; |
}else{ |
if (checkTileCollision(6, getHeroMask()) == 0) { |
if (inWater == 1) { |
//Splash effect |
createSplash(herox, heroy); |
} |
inWater = 0; |
} |
} |
} |
//Poison |
{ |
if (poisoned > 0) { |
poisoned -= 1; |
if (poisoned % 20 == 0) { |
herohp -= 1; |
createEffect(7, herox, heroy); |
} |
} |
} |
//Switch weapon |
{ |
int axis = btnR.pressed - btnL.pressed; |
if (axis != 0) { |
PHL_PlaySound(sounds[sndPi01], CHN_SOUND); |
int i; |
for (i = 1; i <= 5; i++) { |
int thisweapon = heroWeapon + (i * axis); |
if (thisweapon >= 5) { |
thisweapon -= 5; |
} |
if (thisweapon < 0) { |
thisweapon += 5; |
} |
if (hasWeapon[thisweapon] == 1) { |
heroWeapon = thisweapon; |
i = 6; |
} |
} |
} |
} |
//Collide with lava |
{ |
heroy -= 20; |
if (checkTileCollision(5, getHeroMask())) { |
herohp = 0; |
setDrawHP(0); |
} |
heroy += 20; |
} |
//Collide with spikes |
{ |
PHL_Rect spike = getTileCollision(6, getHeroMask()); |
if (spike.x != -1) { |
Mask spikeMask; |
spikeMask.circle = spikeMask.unused = 0; |
spikeMask.x = spike.x + 10; |
spikeMask.y = spike.y + 10; |
spikeMask.w = spikeMask.h = 20; |
if (checkCollision(spikeMask, getHeroMask())) { |
heroHit(15, spike.x + 20); |
} |
} |
} |
//Death |
{ |
if (getDrawHP() <= 0) { //Based on the hud's opinion on player's health, apparently |
state = DEATH; |
timer = 0; |
imageIndex = 0; |
PHL_StopMusic(); |
PHL_PlaySound(sounds[sndHit02], CHN_HERO); |
} |
} |
} |
//Manage charge |
{ |
if (state != NORMAL) { |
canCharge = 0; |
chargeTimer = 0; |
} |
if (canCharge == 1) { |
if (btnFaceLeft.held == 0 && btnFaceLeft.pressed == 0) { |
canCharge = 0; |
} |
} |
} |
//Screen transitions |
{ |
if (herox < -20) { |
herox = 620; |
heroChangeScreen(-1, 0); |
} |
else if (herox > 660) { |
herox = 20; |
heroChangeScreen(1, 0); |
} |
else if (state == LADDER && heroy < -40) { |
heroy = 440; |
heroChangeScreen(0, -1); |
} |
else if (heroy > 480) { |
heroy = 0; |
heroChangeScreen(0, 1); |
} |
} |
return result; |
} |
void heroChangeScreen(int dx, int dy) |
{ |
vsp = 0; |
chargeTimer = 0; |
canCharge = 0; |
if (hasItem[12] == 1) { |
canJump = 1; |
} |
if (state == HIT || state == SLASH || state == CHARGE) { |
state = NORMAL; |
} |
//Force a black screen |
PHL_DrawRect(0, 0, 640, 480, PHL_NewRGB(0, 0, 0)); |
PHL_ForceScreenUpdate(); |
changeScreen(dx, dy); |
} |
void heroDraw() |
{ |
int cropX = 0, cropY = 0; |
int drawShield = 0; |
if (state == DOOR) { |
cropY = 160; |
cropX = (int)imageIndex * 40; |
} |
else if (state == GETITEM) { |
int animation[7] = {0, 1, 2, 3, 2, 0, 1}; |
cropY = 40; |
cropX = 320 + (animation[(int)imageIndex] * 40); |
} |
//Climbing |
else if (state == LADDER) { |
cropX = 80; |
cropY = 80; |
int animation[8] = {0, 1, 2, 1, 0, 3, 4, 3}; |
cropX += 40 * animation[(int)floor(imageIndex)]; |
} |
else if (state == NORMAL) |
{ |
if (onground == 1) { |
//Walking |
if (hsp != 0) { |
cropX = floor(imageIndex) * 40; |
if (herodir == -1) { |
cropX += 80; |
} |
} |
//Standing |
else{ |
imageIndex = 0; |
cropX = 0; |
cropY = 0; |
if (hasItem[14] == 1 && shieldTimer <= 0) { |
drawShield = 1; |
cropY = 120; |
if (herodir == -1) { |
cropX += 40; |
} |
if (heldUp == 1) { |
cropX += 80; |
} |
}else{ |
if (herodir == -1) { |
cropX += 80; |
} |
} |
} |
}else{ |
//Jumping/falling |
if (vsp < 0) { |
imageIndex = 0; |
}else{ |
imageIndex = 1; |
} |
cropX = 160 + (40 * imageIndex); |
if (herodir == -1) { |
cropX += 80; |
} |
} |
}else if (state == SLASH) |
{ |
//Sword Slash |
int animation[5] = {0, 1, 2, 2, 0}; |
cropY = 40; |
cropX = 40 * animation[(int)floor(imageIndex)]; |
if (herodir == -1) { |
cropX += 120; |
} |
} |
else if (state == CHARGE) { |
int animation[5] = {0, 1, 2, 2, 0}; |
cropY = 40; |
cropX = animation[(int)imageIndex] * 40; |
if (herodir == -1) { |
cropX += 120; |
} |
} |
else if (state == HIT) { |
int thisImage = 12; |
if (onground == 0) { |
thisImage = 8; |
} |
if (state == STONE) { |
thisImage = 28; |
} |
thisImage += (int)imageIndex; |
if (herodir == -1) { |
thisImage += 2; |
} |
cropX = 40 * thisImage; |
while (cropX >= 640) { |
cropX -= 640; |
cropY += 40; |
} |
} |
else if (state == STONE) { |
cropY = 40; |
if (stoneState == 0 || stoneState == 1) { //In air/on ground |
int thisImage = (int)imageIndex; |
if (stoneDir == -1) { |
thisImage += 2; |
} |
cropX = 480 + (thisImage * 40); |
} |
else if (stoneState == 2) { //Break free |
int animation[17] = {0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 1, 0}; |
cropX = 320 + (animation[(int)imageIndex] * 40); |
} |
} |
else if (state == DEATH) { |
if (timer >= 130) { |
char tempDark = roomDarkness; |
roomDarkness = 0; |
PHL_DrawTextBold("GAME OVER", 248, 240, YELLOW); |
roomDarkness = tempDark; |
}else{ |
int frame = 0; |
if (herodir == 1) { |
int animation[4] = {0, 3, 6, 9}; |
frame = animation[(int)imageIndex]; |
} |
if (herodir == -1) { |
int animation[4] = {2, 1, 4, 11}; |
frame = animation[(int)imageIndex]; |
} |
cropX = frame * 40; |
} |
} |
else if (state == QUAKE) { |
cropY = 80; |
if (herodir == -1) { |
cropX = 40; |
} |
} |
if ((state == HIT && invincible % 6 < 3) || invincible % 2 == 0) { |
PHL_DrawSurfacePart(herox - 20, heroy, cropX, cropY, 40, 40, images[imgHero]); |
if (drawShield == 1) { |
int scx = 320; //Shield crop x |
int sdx = herox - 2, sdy = heroy + 10; //Shield draw x/y |
if (herodir == -1) { |
sdx -= 36; |
scx += 40; |
} |
if (heldUp == 1) { |
scx += 80; |
sdy -= 26; |
sdx -= 8 * herodir; |
} |
PHL_DrawSurfacePart(sdx, sdy, scx, 240, 40, 40, images[imgHero]); |
} |
} |
//Draw stun effect |
if (stun == 1) { |
int frame = (int)(((300 - stunTimer) % 32) / 4); |
if (frame == 0) { |
PHL_PlaySound(sounds[sndHit05], CHN_SOUND); |
} |
int animation[8] = {0, 1, 2, 1, 0, -1, -1, -1}; |
if (animation[frame] != -1) { |
PHL_DrawSurfacePart(herox - 32, heroy - 12, 384 + (animation[frame] * 64), 64, 64, 64, images[imgMisc32]); |
} |
if (stunTimer <= 0) { |
stun = 0; |
PHL_PlaySound(sounds[sndPower01], CHN_SOUND); |
}else{ |
stunTimer -= 1; |
} |
} |
//PHL_DrawRect(mask.x, mask.y, mask.w, mask.h, PHL_NewRGB(0x00, 0x00, 0xFF)); |
updateMask(); |
//PHL_DrawMask(shieldMask); |
} |
void updateMask() |
{ |
heroMask.x = herox - 12; |
heroMask.y = heroy + 14; |
//Update shield mask |
{ |
shieldMask.unused = 1; |
if (hasItem[14] == 1) { //has shield |
if (state == NORMAL && onground == 1 && hsp == 0 && shieldTimer == 0) { |
shieldMask.unused = 0; |
//Shield held in front |
if (heldUp == 0) { |
shieldMask.w = 14; |
shieldMask.h = 20; |
shieldMask.x = herox + 10; |
shieldMask.y = heroy + 20; |
if (herodir == -1) { |
shieldMask.x -= 34; |
} |
} |
//Shield above head |
else{ |
shieldMask.w = 24; |
shieldMask.h = 8; |
shieldMask.x = herox - 2; |
shieldMask.y = heroy - 2; |
if (herodir == -1) { |
shieldMask.x -= 20; |
} |
} |
} |
} |
} |
} |
int heroHit(int damage, int centerx) |
{ |
if (state != HIT && state != DEATH && state != DOOR && (invincible <= 0 || (state == STONE && invincible == 60))) { |
if (state != STONE || (state == STONE && stoneState != 2)) { |
PHL_PlaySound(sounds[sndHit02], CHN_HERO); |
herohp -= damage; |
vsp = -4; |
onground = 0; |
if (herox - centerx > 0) { |
herodir = -1; |
hsp = herodir * -2; |
} |
if (herox - centerx < 0) { |
herodir = 1; |
hsp = herodir * -2; |
} |
if (state != STONE) { |
state = HIT; |
} |
return 1; |
} |
} |
return 0; |
} |
void heroPoison() |
{ |
if (hasItem[8] != 1) { //Does not have poison resistance ring |
if (poisoned <= 0) { |
poisoned = 300; |
} |
} |
} |
void heroStone() |
{ |
//if (((state != HIT && state != DEATH && state != DOOR ) || (state == STONE && stoneState != 2)) && invincible <= 0) { |
if (state != HIT && state != DEATH && state != DOOR && (invincible <= 0 || (state == STONE && invincible == 60))) { |
if (state != STONE || (state == STONE && stoneState != 2)) { |
if (hasItem[9] != 1) { //Does not have green ring |
if (state == STONE) { |
herodir = stoneDir; |
} |
setHeroState(STONE); |
} |
} |
} |
} |
//Get-ers and set-ers |
Mask getHeroMask() |
{ |
updateMask(); |
return heroMask; |
} |
int getHeroState() |
{ |
return state; |
} |
void setHeroState(int s) |
{ |
state = s; |
//Special cases |
if (s == GETITEM) { |
heldUp = 0; |
//timer = 0; |
//subPosition = GETITEM; |
} |
if (s == DOOR) { |
imageIndex = 0; |
} |
if (s == STONE) { |
if (stoneTimer <= 0) { |
stoneTimer = 350; |
} |
stoneState = 0; |
invincible = 60; |
stoneDir = herodir; |
} |
} |
int getHeroInvincible() |
{ |
return invincible; |
} |
int getHeroDirection() |
{ |
return herodir; |
} |
void setHeroDirection(int d) |
{ |
herodir = d; |
} |
double getHeroImageIndex() |
{ |
return imageIndex; |
} |
void setHeroImageIndex(double index) |
{ |
imageIndex = index; |
} |
double getHeroVsp() |
{ |
return vsp; |
} |
double getHeroHsp() |
{ |
return hsp; |
} |
void setHeroHsp(double newHsp) |
{ |
hsp = newHsp; |
} |
void setHeroVsp(double newVsp) |
{ |
vsp = newVsp; |
} |
int getHeroOnground() |
{ |
return onground; |
} |
void setHeroOnground(int val) |
{ |
onground = val; |
} |
void setHeroTimer(int t) |
{ |
timer = t; |
} |
int getHeroPoisoned() |
{ |
return poisoned; |
} |
void heroStun() |
{ |
if (hasItem[10] == 0) { //Does not have cloak |
stun = 1; |
if (stunTimer <= 0) { |
stunTimer = 300; |
} |
} |
} |
void setHeroCanjump(int set) |
{ |
canJump = set; |
} |
/contrib/games/hydracastlelabyrinth/src/hero.h |
---|
0,0 → 1,55 |
#ifndef HERO_H |
#define HERO_H |
#include "PHL.h" |
#include "collision.h" |
extern double herox, heroy; |
extern double herohp, maxhp; |
extern int heroAmmo, maxAmmo; |
extern int heroWeapon; |
extern Mask heroMask; |
extern Mask shieldMask; |
void heroSetup(); |
void heroCleanup(); |
int heroStep(); |
void heroDraw(); |
int heroHit(int damage, int centerx); |
void heroPoison(); |
void heroStone(); |
Mask getHeroMask(); |
int getHeroState(); |
void setHeroState(int s); |
int getHeroInvincible(); |
int getHeroDirection(); |
void setHeroDirection(int d); |
double getHeroImageIndex(); |
void setHeroImageIndex(double index); |
double getHeroVsp(); |
double getHeroHsp(); |
void setHeroHsp(double newHsp); |
void setHeroVsp(double newVsp); |
int getHeroOnground(); |
void setHeroOnground(int val); |
void setHeroTimer(int t); |
int getHeroPoisoned(); |
void heroStun(); |
void setHeroCanjump(int set); |
#endif |
/contrib/games/hydracastlelabyrinth/src/ini.c |
---|
0,0 → 1,395 |
#include "ini.h" |
#include "game.h" |
#include "options.h" |
#include "PHL.h" |
#include <stdio.h> |
#include <string.h> |
#include "text.h" |
#ifdef EMSCRIPTEN |
#include <emscripten.h> |
#endif |
//char* getFileLocation(); |
char* trimString(char* orig); |
void screenLoad(char* first, char* second); |
void sizeLoad(char* first, char* second); |
void blurLoad(char* first, char* second); |
void xbrzLoad(char* first, char* second); |
void languageLoad(char* first, char* second); |
void autosaveLoad(char* first, char* second); |
void musictypeLoad(char* first, char* second); |
void musicvolumeLoad(char* first, char* second); |
void iniInit() |
{ |
//Build filepath |
char fullPath[128]; |
{ |
#ifdef _SDL |
#if defined(__amigaos4__) || defined(__MORPHOS__) |
strcpy(fullPath, "PROGDIR:.hydracastlelabyrinth/"); |
#elif defined(EMSCRIPTEN) |
strcpy(fullPath, "hcl_data/"); |
#elif defined(_KOLIBRI) |
strcpy(fullPath, KOS_HCL_SAVES_PATH"/"); |
#else |
strcpy(fullPath, getenv("HOME")); |
strcat(fullPath, "/.hydracastlelabyrinth/"); |
#endif |
#elif defined(_3DS) |
strcpy(fullPath, "sdmc:/3ds/appdata/HydraCastleLabyrinth/"); |
#else |
strcpy(fullPath, ""); |
#endif |
strcat(fullPath, "system.ini"); |
} |
FILE* f; |
if ( (f = fopen(fullPath, "rt")) ) |
{ |
//File exists - read it |
fclose(f); |
loadSettings(); |
}else{ |
//File does not exists - create it (with default hardcoded settings) |
saveSettings(); |
} |
} |
void saveSettings() |
{ |
//Build filepath |
char fullPath[128]; |
{ |
#ifdef _SDL |
#if defined(__amigaos4__) || defined(__MORPHOS__) |
strcpy(fullPath, "PROGDIR:.hydracastlelabyrinth/"); |
#elif defined(EMSCRIPTEN) |
strcpy(fullPath, "hcl_data/"); |
#elif defined(_KOLIBRI) |
strcpy(fullPath, KOS_HCL_SAVES_PATH"/"); |
#else |
strcpy(fullPath, getenv("HOME")); |
strcat(fullPath, "/.hydracastlelabyrinth/"); |
#endif |
#elif defined(_3DS) |
strcpy(fullPath, "sdmc:/3ds/appdata/HydraCastleLabyrinth/"); |
#else |
strcpy(fullPath, ""); |
#endif |
strcat(fullPath, "system.ini"); |
} |
FILE* f; |
if ( (f = fopen(fullPath, "wt")) ) |
{ |
fprintf(f, "[disp]"); |
#ifdef _3DS |
//Screen |
fprintf(f, "\r\nscreen="); |
if (activeScreen->screen == GFX_BOTTOM) { |
fprintf(f, "bottom"); |
}else{ |
fprintf(f, "top"); |
} |
#endif |
#ifdef _PSP |
//Screen Size |
fprintf(f, "\r\nsize="); |
if (getScreenSize() == 1) { |
fprintf(f, "1"); |
} |
else if (getScreenSize() == 2) { |
fprintf(f, "2"); |
} |
else { |
fprintf(f, "0"); |
} |
//Screen Blur |
fprintf(f, "\r\nblur="); |
if (getBlur() == 1) { |
fprintf(f, "on"); |
}else{ |
fprintf(f, "off"); |
} |
#endif |
#ifdef _SDL |
//xBRZ Scaling |
fprintf(f, "\r\nxbrz="); |
if (getXBRZ() == 1) { |
fprintf(f, "on"); |
}else{ |
fprintf(f, "off"); |
} |
#endif |
fprintf(f, "\r\n[system]"); |
//Language |
fprintf(f, "\r\nlanguage="); |
if (getLanguage() == 0) { |
fprintf(f, "jp"); |
} |
if (getLanguage() == 1) { |
fprintf(f, "en"); |
} |
//Autosave |
fprintf(f, "\r\nautosave="); |
if (getAutoSave() == 1) { |
fprintf(f, "on"); |
}else{ |
fprintf(f, "off"); |
} |
#ifdef _SDL |
fprintf(f, "\r\n[audio]"); |
fprintf(f, "\r\nmusic_type=%s", getMusicType()?"ogg":"midi"); |
fprintf(f, "\r\nmusic=%d", music_volume); |
// Audio |
#endif |
fclose(f); |
} |
#ifdef EMSCRIPTEN |
EM_ASM( |
FS.syncfs(false,function () { |
Module.print("File sych'd") |
}); |
); |
#endif |
} |
void loadSettings() |
{ |
//Build filepath |
char fullPath[128]; |
{ |
#ifdef _SDL |
#if defined(__amigaos4__) || defined(__MORPHOS__) |
strcpy(fullPath, "PROGDIR:.hydracastlelabyrinth/"); |
#elif defined(EMSCRIPTEN) |
strcpy(fullPath, "hcl_data/"); |
#elif defined(_KOLIBRI) |
strcat(fullPath, KOS_HCL_SAVES_PATH"/"); |
#else |
strcpy(fullPath, getenv("HOME")); |
strcat(fullPath, "/.hydracastlelabyrinth/"); |
#endif |
#elif defined(_3DS) |
strcpy(fullPath, "sdmc:/3ds/appdata/HydraCastleLabyrinth/"); |
#else |
strcpy(fullPath, ""); |
#endif |
strcat(fullPath, "system.ini"); |
} |
FILE* f; |
if ( (f = fopen(fullPath, "rt")) ) |
{ |
char line[80]; |
while ( (fgets(line, 80, f) != NULL) ) |
{ |
char* lineptr = line; |
lineptr = trimString(lineptr); |
if (lineptr != NULL) { |
//Ignore category lines |
if (lineptr[0] != '[') |
{ |
//Check if it has a = delimiter first |
int i; |
for (i = 0; i < 80; i++) { |
if (line[i] == '=') |
{ |
//Begin line splitting |
char* half; |
if ( (half = strsep(&lineptr, "=")) != NULL) |
{ |
//first half |
char* fhalf = half; |
if ( (half = strsep(&lineptr, "=")) != NULL) { |
//Second half |
char* shalf = half; |
//Load options |
screenLoad(fhalf, shalf); |
sizeLoad(fhalf, shalf); |
blurLoad(fhalf, shalf); |
xbrzLoad(fhalf, shalf); |
languageLoad(fhalf, shalf); |
autosaveLoad(fhalf, shalf); |
musictypeLoad(fhalf, shalf); |
musicvolumeLoad(fhalf, shalf); |
} |
} |
//End |
i = 81; |
} |
} |
} |
} |
} |
fclose(f); |
} |
} |
//Build file path |
/* |
char* getFileLocation() |
{ |
char fullPath[128]; |
strcpy(fullPath, ""); |
#ifdef _CIA |
strcat(fullPath, "sdmc:/3ds/HydraCastleLabyrinth/"); |
#endif |
strcat(fullPath, "system.ini"); |
return fullPath; |
} |
*/ |
char* trimString(char* orig) |
{ |
char* output = orig; |
int i, r = 0; |
for (i = 0; i < strlen(orig); i++) { |
if (orig[i] != ' ' && orig[i] != '\n' && orig[i] != '\r') { |
output[r] = orig[i]; |
r++; |
} |
} |
orig[r] = 0; |
return output; |
} |
void screenLoad(char* first, char* second) |
{ |
#ifdef _3DS |
if (strcmp(first, "screen") == 0) { |
if (strcmp(second, "top") == 0) { |
swapScreen(GFX_TOP, GFX_LEFT); |
} |
if (strcmp(second, "bottom") == 0) { |
swapScreen(GFX_BOTTOM, GFX_LEFT); |
} |
} |
#endif |
} |
void sizeLoad(char* first, char* second) |
{ |
#ifdef _PSP |
if (strcmp(first, "size") == 0) { |
if (second[0] == '0') { |
//fprintf(debug, "\nsize is 0"); |
setScreenSize(0); |
} |
if (second[0] == '1') { |
//fprintf(debug, "\nsize is 1"); |
setScreenSize(1); |
} |
if (second[0] == '2') { |
//fprintf(debug, "\nsize is 2"); |
setScreenSize(2); |
} |
} |
#endif |
} |
void blurLoad(char* first, char* second) |
{ |
#ifdef _PSP |
if (strcmp(first, "blur") == 0) { |
if (strcmp(second, "on") == 0) { |
//fprintf(debug, "\nblur is on"); |
//oslSetBilinearFilter(1); |
setBlur(1); |
} |
if (strcmp(second, "off") == 0) { |
//fprintf(debug, "\nblur is off"); |
//oslSetBilinearFilter(0); |
setBlur(0); |
} |
} |
#endif |
} |
void xbrzLoad(char* first, char* second) |
{ |
#ifdef _SDL |
if (strcmp(first, "xbrz") == 0) { |
if (strcmp(second, "on") == 0) { |
setXBRZ(1); |
} |
if (strcmp(second, "off") == 0) { |
setXBRZ(0); |
} |
} |
#endif |
} |
void languageLoad(char* first, char* second) |
{ |
if (strcmp(first, "language") == 0) { |
if (strcmp(second, "en") == 0) { |
setLanguage(ENGLISH); |
} |
if (strcmp(second, "jp") == 0) { |
setLanguage(JAPANESE); |
} |
} |
} |
void autosaveLoad(char* first, char* second) |
{ |
if (strcmp(first, "autosave") == 0) { |
if (strcmp(second, "on") == 0) { |
//fprintf(debug, "\nautosave is on"); |
setAutoSave(1); |
} |
if (strcmp(second, "off") == 0) { |
//fprintf(debug, "\nautosave is off"); |
setAutoSave(0); |
} |
} |
} |
void musicvolumeLoad(char* first, char* second) |
{ |
#ifdef _SDL |
if (strcmp(first, "music") == 0) { |
if (second[0] >= '0' && second[0] <= '4') { |
music_volume = second[0]-'0'; |
PHL_MusicVolume(0.25f * music_volume); |
} |
} |
#endif |
} |
void musictypeLoad(char* first, char* second) |
{ |
#ifdef _SDL |
if (strcmp(first, "music_type") == 0) { |
if (strcmp(second, "ogg") == 0) { |
setMusicType(1); |
} |
if (strcmp(second, "midi") == 0) { |
setMusicType(0); |
} |
} |
#endif |
} |
/contrib/games/hydracastlelabyrinth/src/ini.h |
---|
0,0 → 1,10 |
#ifndef INI_H |
#define INI_H |
//Functions to handle the "system.ini" file |
void iniInit(); |
void saveSettings(); |
void loadSettings(); |
#endif |
/contrib/games/hydracastlelabyrinth/src/inventory.c |
---|
0,0 → 1,180 |
#include "inventory.h" |
#include "PHL.h" |
#include "game.h" |
#include "text.h" |
int cursorX = 0; |
int cursorY = 0; |
#ifdef EMSCRIPTEN |
static char tempDark; |
void inventorySetup() |
{ |
tempDark = roomDarkness; |
roomDarkness = 0; |
PHL_PlaySound(sounds[sndPi04], CHN_SOUND); |
} |
int inventoryEMStep() |
{ |
int result = -1; |
PHL_MainLoop(); |
PHL_StartDrawing(); |
PHL_ScanInput(); |
if (inventoryStep() == 1) { |
result = 0; |
} |
inventoryDraw(); |
PHL_EndDrawing(); |
if(!result) |
roomDarkness = tempDark; |
return result; |
} |
#else |
void inventory() |
{ |
char tempDark = roomDarkness; |
roomDarkness = 0; |
char loop = 1; |
PHL_PlaySound(sounds[sndPi04], CHN_SOUND); |
while (PHL_MainLoop() && loop == 1) |
{ |
PHL_StartDrawing(); |
PHL_ScanInput(); |
if (inventoryStep() == 1) { |
loop = 0; |
} |
inventoryDraw(); |
PHL_EndDrawing(); |
} |
roomDarkness = tempDark; |
} |
#endif |
int inventoryStep() |
{ |
secretCountdown(); |
//Input |
char playsnd = 0; |
if (btnRight.pressed - btnLeft.pressed != 0) { |
cursorX += btnRight.pressed - btnLeft.pressed; |
playsnd = 1; |
} |
if (btnDown.pressed - btnUp.pressed != 0) { |
cursorY += btnDown.pressed - btnUp.pressed; |
playsnd = 1; |
} |
if (playsnd == 1) { |
PHL_PlaySound(sounds[sndPi01], CHN_SOUND); |
} |
//Limit cursor |
if (cursorX < 0) { cursorX = 6; } |
if (cursorX > 6) { cursorX = 0; } |
if (cursorY < 0) { cursorY = 3; } |
if (cursorY > 3) { cursorY = 0; } |
if (btnStart.pressed == 1 || btnDecline.pressed == 1) |
{ |
return 1; |
} |
return 0; |
} |
void inventoryDraw() |
{ |
//Black background |
PHL_DrawRect(0, 0, 640, 480, PHL_NewRGB(0, 0, 0)); |
//Labels |
PHL_DrawTextBold("SUB WEAPON", 16, 16, YELLOW); |
PHL_DrawTextBold("ITEM", 16, 96, YELLOW); |
PHL_DrawTextBold("KEY", 16, 320, YELLOW); |
//Blue rectangles |
int i, a, cx, cy; |
//Weapons |
for (i = 0; i < 5; i++) { |
PHL_DrawRect(18 + (48 * i), 34, 44, 44, PHL_NewRGB(255, 255, 255)); |
PHL_DrawRect(20 + (48 * i), 36, 40, 40, PHL_NewRGB(119, 166, 219)); |
if (hasWeapon[i] == 1) { |
cx = (i + 1) * 40; |
}else{ |
cx = 0; |
} |
PHL_DrawSurfacePart(20 + (48 * i), 36, cx, 0, 40, 40, images[imgItems]); |
} |
//Items |
int count = 0; |
int imageOrder[28] = { 13, 17, 16, 15, 8, 10, 9, |
18, 4, 6, 5, 7, 3, 11, |
14, 12, 1, 2, 22, 26, 27, |
21, 25, 28, 23, 20, 19, 24 }; |
for (i = 0; i < 4; i++) { |
for (a = 0; a < 7; a++) { |
PHL_DrawRect(18 + (48 * a), 114 + (48 * i), 44, 44, PHL_NewRGB(255, 255, 255)); |
PHL_DrawRect(20 + (48 * a), 116 + (48 * i), 40, 40, PHL_NewRGB(119, 166, 219)); |
if (hasItem[count] == 0) { |
cx = 0; |
cy = 0; |
}else{ |
cy = 0; |
cx = (imageOrder[count] + 6) * 40; |
while (cx >= 640) { |
cy += 40; |
cx -= 640; |
} |
} |
PHL_DrawSurfacePart(20 + (48 * a), 116 + (48 * i), cx, cy, 40, 40, images[imgItems]); |
count++; |
} |
} |
//Keys |
for (i = 0; i < 8; i++) { |
PHL_DrawRect(18 + (48 * i), 338, 44, 44, PHL_NewRGB(255, 255, 255)); |
PHL_DrawRect(20 + (48 * i), 340, 40, 40, PHL_NewRGB(119, 166, 219)); |
if (hasKey[i] == 1) { |
cx = 120 + (i * 40); |
cy = 80; |
}else{ |
cx = 0; |
cy = 0; |
} |
PHL_DrawSurfacePart(20 + (48 * i), 340, cx, cy, 40, 40, images[imgItems]); |
} |
//Text box |
PHL_DrawRect(16, 400, 606, 46, PHL_NewRGB(255, 255, 255)); |
PHL_DrawRect(18, 402, 602, 42, PHL_NewRGB(0, 0, 255)); |
//Text |
if (hasItem[cursorX + (cursorY * 7)] == 1) { |
int drawX = 32, drawY = 402; |
//Draw item name |
drawX = drawText(itemName[cursorX + (cursorY * 7) + 5], drawX, drawY); |
//Draw item description |
drawX = drawCharacter(6, 0, drawX, drawY); |
drawText(itemDescription[cursorX + (cursorY * 7)], drawX, drawY); |
} |
//Cursor |
PHL_DrawSurfacePart(16 + (cursorX * 48), 112 + (cursorY * 48), 0, 96, 48, 48, images[imgHud]); |
} |
/contrib/games/hydracastlelabyrinth/src/inventory.h |
---|
0,0 → 1,13 |
#ifndef INVENTORY_H |
#define INVENTORY_H |
#ifdef EMSCRIPTEN |
void inventorySetup(); |
int inventoryEMStep(); |
#else |
void inventory(); |
#endif |
int inventoryStep(); |
void inventoryDraw(); |
#endif |
/contrib/games/hydracastlelabyrinth/src/main.c |
---|
0,0 → 1,182 |
#include "PHL.h" |
#include "game.h" |
#include <stdlib.h> |
#include <time.h> |
#include <sys/stat.h> |
#include <stdlib.h> |
#include <stdio.h> |
#include <string.h> |
#ifdef ODROID |
#define _XTYPEDEF_MASK |
#include <X11/Xlib.h> |
#endif |
#ifdef EMSCRIPTEN |
#include <emscripten.h> |
#endif |
#ifdef __amigaos4__ |
static const char* __attribute__((used)) stackcookie = "$STACK: 1000000"; |
#endif |
#ifdef __MORPHOS__ |
unsigned long __stack = 1000000; |
#endif |
#ifdef _KOLIBRI |
extern char* dirname(char*); |
extern void setcwd(char*); |
#endif |
void createSaveLocations() |
{ |
//Force create save data folders |
#ifdef _3DS |
//3DS builds |
mkdir("sdmc:/3ds", 0777); |
mkdir("sdmc:/3ds/appdata", 0777); |
mkdir("sdmc:/3ds/appdata/HydraCastleLabyrinth", 0777); |
mkdir("sdmc:/3ds/appdata/HydraCastleLabyrinth/data", 0777); |
mkdir("sdmc:/3ds/appdata/HydraCastleLabyrinth/map", 0777); |
#elif defined(_SDL) |
char buff[4096]; |
#if defined(__amigaos4__) || defined(__MORPHOS__) |
strcpy(buff,"PROGDIR:.hydracastlelabyrinth"); |
#elif defined(EMSCRIPTEN) |
strcpy(buff, "hcl_data"); |
#elif defined (_KOLIBRI) |
mkdir(KOS_HCL_SAVES_PATH, 777); |
#else |
strcpy(buff, getenv("HOME")); |
strcat(buff, "/.hydracastlelabyrinth"); |
#endif |
// if exist first? |
#ifndef _KOLIBRI |
struct stat sb; |
if(!(stat(buff, &sb)==0 && S_ISDIR(sb.st_mode))) |
mkdir(buff, 0777); |
#endif |
#else |
//psp, wii |
mkdir("/data", 0777); |
mkdir("/map", 0777); |
#endif |
} |
#ifdef EMSCRIPTEN |
int fileSynched = 0; |
#endif |
int main(int argc, char **argv) |
{ |
//Setup |
#ifdef _KOLIBRI |
setcwd(dirname(argv[0])); |
#endif |
#ifdef EMSCRIPTEN |
// that HEAP32 on &fileSynched looks like a hack, but I needed a way to be sure the DB is read before reading the ini files |
EM_ASM_INT({ |
FS.mkdir('hcl_data'); |
FS.mount(IDBFS,{},'hcl_data'); |
Module.print("Will import permanent storage"); |
FS.syncfs(true, function() { |
Module.print("Permanent storage imported"); |
HEAP32[$0>>2] = 1; |
}); |
}, &fileSynched); |
#endif |
#ifdef _3DS |
sdmcInit(); |
osSetSpeedupEnable(false); |
#endif |
#ifdef _SDL |
if ( SDL_Init(SDL_INIT_VIDEO) < 0) { |
SDL_Delay(5000); |
exit(EXIT_FAILURE); |
} |
#if defined(PANDORA) || defined(PYRA) || defined(CHIP) || defined(ODROID) |
wantFullscreen = 1; |
#else |
wantFullscreen = 0; |
#endif |
#ifdef CHIP |
screenScale = 1; |
#elif defined(BITTBOY) |
screenScale = 1; |
#elif defined(PYRA) |
//screenScale = 3; |
desktopFS = 1; |
#elif defined(ODROID) |
desktopFS = 1; |
#else |
screenScale = 2; |
#endif |
useJoystick = 1; |
// get command line arguments |
for (int i=1; i<argc; i++) |
{ |
if(!strcmp(argv[i], "-f")) |
wantFullscreen = 1; |
if(!strcmp(argv[i], "--fullscreen")) |
wantFullscreen = 1; |
if(!strcmp(argv[i], "-d")) |
desktopFS = 1; |
if(!strcmp(argv[i], "--desktop")) |
desktopFS = 1; |
if(!strcmp(argv[i], "-x1")) |
screenScale = 1; |
if(!strcmp(argv[i], "-x2")) |
screenScale = 2; |
if(!strcmp(argv[i], "-x3")) |
screenScale = 3; |
if(!strcmp(argv[i], "-x4")) |
screenScale = 4; |
if(!strcmp(argv[i], "-x5")) |
screenScale = 5; |
if(!strcmp(argv[i], "--xbrz")) |
setXBRZ(1); |
if(!strcmp(argv[i], "--no-xbrz")) |
setXBRZ(0); |
if(!strcmp(argv[i], "-j")) |
useJoystick = 0; |
if(!strcmp(argv[i], "--nojoy")) |
useJoystick = 0; |
if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { |
printf("Quick help\n-f|--fullscreen\tUse fullscreen\n-d|--desktop\tdesktop fullscreen\n-x1|-x2|-x3|-x4\tUse screenScale of *1..*4 (default *2 = 640x480)\n-j|-nojoy\tdo not use Joystick\n--xbrz\tUse xBRZ scaling\n--no-xbrz\tNo xBRZ scaling\n"); |
exit(0); |
} |
} |
if(desktopFS) |
{ |
#ifdef _SDL2 |
SDL_DisplayMode infos; |
SDL_GetCurrentDisplayMode(0, &infos); |
screenW = infos.w; |
screenH = infos.h; |
#else |
const SDL_VideoInfo* infos = SDL_GetVideoInfo(); |
screenH = infos->current_h; |
screenW = infos->current_w; |
#endif |
} else { |
screenW = 320 * screenScale; |
screenH = 240 * screenScale; |
} |
printf("Hydra Castle Labyrinth, %s %dx%d scale=x%d%s, using Joystick=%d\n", (wantFullscreen || desktopFS)?"Fullscreen":"Windowed", screenW, screenH, screenScale, getXBRZ()?" xBRZ":"", useJoystick); |
#endif |
srand(time(NULL)); |
createSaveLocations(); |
game(); |
//System specific cleanup |
#ifdef _PSP |
sceKernelExitGame(); |
#endif |
#ifdef _3DS |
sdmcExit(); |
#endif |
return 0; |
} |
/contrib/games/hydracastlelabyrinth/src/misc.c |
---|
0,0 → 1,92 |
#include <stdint.h> |
#include <string.h> |
void *memrchr(const void *m, int c, size_t n) |
{ |
const unsigned char *s = (const unsigned char*)m; |
c = (unsigned char)c; |
while (n--) if (s[n]==c) return (void *)(s+n); |
return 0; |
} |
void setcwd(char* path){ |
__asm__ __volatile__( |
"int $0x40" |
::"a"(30), "b"(1), "c"(path) |
:"memory" |
); |
} |
char *dirname(char *path) |
{ |
static const char dot[] = "."; |
char *last_slash; |
last_slash = path != NULL ? strrchr (path, '/') : NULL; |
if (last_slash != NULL && last_slash != path && last_slash[1] == '\0') |
{ |
char *runp; |
for (runp = last_slash; runp != path; --runp) |
if (runp[-1] != '/') |
break; |
if (runp != path) |
last_slash = (char*)memrchr((void*)path, '/', runp - path); |
} |
if (last_slash != NULL) |
{ |
char *runp; |
for (runp = last_slash; runp != path; --runp) |
if (runp[-1] != '/') |
break; |
if (runp == path) |
{ |
if (last_slash == path + 1) |
++last_slash; |
else |
last_slash = path + 1; |
} |
else |
last_slash = runp; |
last_slash[0] = '\0'; |
} |
else |
path = (char *) dot; |
return path; |
} |
#pragma pack(push,1) |
typedef struct{ |
unsigned p00; |
union{ |
uint64_t p04; |
struct { |
unsigned p04dw; |
unsigned p08dw; |
}; |
}; |
unsigned p12; |
union { |
unsigned p16; |
const char *new_name; |
void *bdfe; |
void *buf16; |
const void *cbuf16; |
}; |
char p20; |
const char *p21; |
}ksys70_t; |
int kos_mkdir(const char *path, unsigned v) |
{ |
int status; |
ksys70_t dir_opt; |
dir_opt.p00 = 9; |
dir_opt.p21 = path; |
__asm__ __volatile__( |
"int $0x40" |
:"=a"(status) |
:"a"(70), "b"(&dir_opt) |
:"memory" |
); |
return status; |
} |
/contrib/games/hydracastlelabyrinth/src/object.c |
---|
0,0 → 1,1532 |
#include "object.h" |
#include "game.h" |
#include "hero.h" |
#include <stdio.h> |
#include <stdlib.h> |
#include "enemies/slug.h" |
#include "game.h" |
#include <math.h> |
void nullFunction(void* v); |
void ammoStep(Ammo* a); |
void ammoDraw(Ammo* a); |
void destroyableStep(Destroyable* d); |
void secretTriggerStep(SecretTrigger* s); |
void chestStep(Chest* c); |
void chestDraw(Chest* c); |
void savePointStep(SavePoint* s); |
void savePointDraw(SavePoint* s); |
void doorStep(Door* d); |
void doorDraw(Door* d); |
void lockBlockStep(LockBlock* l); |
void lockBlockDraw(LockBlock* l); |
void switchStep(Switch* s); |
int switchActivate(Switch* s); |
void switchResult(Switch* s); |
void switchDraw(Switch* s); |
void gateStep(Gate* g); |
void gateDraw(Gate* g); |
void statueStep(Statue* s); |
void statueDraw(Statue* s); |
void buttonStep(FloorPad* f); |
void buttonDraw(FloorPad* f); |
void ladderStep(Ladder* l); |
void ladderActivate(int x, int y); |
void generatorStep(Generator* g); |
void generatorDraw(Generator* g); |
void shockgateStep(Shockgate* s); |
void shockgateDraw(Shockgate* s); |
void crownStep(Crown* c); |
void crownDraw(Crown* c); |
void nullFunction(void* v) |
{ |
//Wow, it's literally nothing! |
} |
void objectDestroy(int id) |
{ |
if (objects[id] != NULL) { |
if (objects[id]->data != NULL) { |
free(objects[id]->data); |
} |
objects[id]->data = NULL; |
free(objects[id]); |
} |
objects[id] = NULL; |
} |
//Ammo/Health |
void spawnCollectable(int x, int y) |
{ |
int num = (rand() % 100) + 1; |
int result = -1; |
int heartchance = 15; |
int ammochance = 10; |
if (hasItem[3] == 1) { //Has golden seed |
heartchance *= 2; |
ammochance *= 2; |
} |
if (num <= heartchance) { |
result = 1; //Heart |
} |
else if (num > heartchance && num <= heartchance + ammochance) { |
result = 0; //Ammo |
} |
//result = rand() % 2; |
if (result != -1) { |
createAmmo(x, y, result); |
} |
} |
void createAmmo(int x, int y, int type) |
{ |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
Ammo* a = malloc(sizeof *a); |
a->id = i; |
a->x = x; |
a->y = y; |
a->type = type; |
a->vsp = -2.5; |
a->grav = 0.2; |
a->blink = 30; |
a->canLand = 0; |
a->bounce = 0; |
o->data = a; |
o->objectStep = ammoStep; |
o->objectDraw = ammoDraw; |
o->type = -1; |
objects[i] = o; |
i = MAX_OBJECTS; |
} |
} |
} |
void ammoStep(Ammo* a) |
{ |
char dead = 0; |
//Flashing animation |
{ |
if (a->blink > 0) { |
a->blink -= 1; |
} |
} |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 2; |
mask.h = 1; |
mask.x = a->x - (mask.w / 2); |
mask.y = a->y + (40 - mask.h); |
} |
//Movement |
{ |
a->y += a->vsp; |
a->vsp += a->grav; |
mask.y = a->y + (40 - mask.h); |
} |
//Destroy if it falls in a pit |
{ |
if (a->y > 480) { |
dead = 1; |
} |
} |
//Falling |
if (a->vsp >= 0) { |
//Inside of a block |
if (a->canLand == 0) { |
if (checkTileCollision(1, mask) == 0 && checkTileCollision(3, mask) == 0) { |
a->canLand = 1; |
} |
} |
//Land on ground |
if (a->canLand == 1) { |
PHL_Rect collide = getTileCollision(1, mask); |
if (collide.x == -1) { |
collide = getTileCollision(3, mask); |
} |
if (collide.x != -1) { |
a->y = collide.y - 40; |
a->vsp = 0; |
//Bounce |
if (a->bounce <= 2) { |
double bounceVsp[3] = {-2, -1, 0}; |
if (a->bounce > 2) { |
a->bounce = 2; |
} |
a->vsp = bounceVsp[a->bounce]; |
a->bounce += 1; |
PHL_PlaySound(sounds[sndPi02], 2); |
} |
} |
} |
}else{ |
a->canLand = 0; |
} |
//Setup hero collision mask |
{ |
mask.w = 20; |
mask.h = 32; |
//Heart |
if (a->type == 1) { |
mask.w = 28; |
mask.h = 26; |
} |
mask.x = a->x - (mask.w / 2); |
mask.y = a->y + (40 - mask.h); |
} |
//Collect |
{ |
if (a->blink <= 0 && checkCollision(mask, heroMask)) { |
//Ammo |
if (a->type == 0) { |
heroAmmo += 5; |
if (heroAmmo > maxAmmo) { |
heroAmmo = maxAmmo; |
} |
} |
//Heart |
else if (a->type == 1) { |
herohp += 10; |
if (herohp > 128) { |
herohp = 128; |
} |
} |
dead = 1; |
PHL_PlaySound(sounds[sndGet02], 2); |
} |
} |
//Destroy object |
{ |
if (dead == 1) { |
objectDestroy(a->id); |
} |
} |
} |
void ammoDraw(Ammo* a) |
{ |
if (a->blink % 2 == 0) { |
int cropX[2] = {40, 0}; |
PHL_DrawSurfacePart(a->x - 20, a->y + 2, cropX[a->type], 120, 40, 40, images[imgMisc20]); |
} |
} |
//Destroyable Block |
void createDestroyable(int x, int y, int secret) |
{ |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
Destroyable* d = malloc(sizeof *d); |
d->id = i; |
d->x = x; |
d->y = y; |
d->secret = secret; |
d->hp = 3; |
//d->invulnerable = 0; |
d->mask.x = x; |
d->mask.y = y; |
d->mask.w = d->mask.h = 40; |
d->mask.unused = d->mask.circle = 0; |
o->data = d; |
o->objectStep = destroyableStep; |
o->objectDraw = nullFunction; |
o->type = 3; |
objects[i] = o; |
i = MAX_OBJECTS; |
} |
} |
} |
void destroyableStep(Destroyable* d) |
{ |
//if (d->invulnerable <= 0) { |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown <= 0) { |
if (checkCollision(d->mask, weapons[i]->weaponMask)) { |
if (hasItem[0] == 1) { //Has copper pick |
d->hp -= 1; |
if (hasItem[1] == 0) { |
PHL_PlaySound(sounds[sndHit03], CHN_WEAPONS); |
}else{ //Has silver pick |
d->hp -= 2; |
} |
} |
//d->invulnerable = 15; |
weaponHit(weapons[i]); |
if (d->hp <= 0) { |
createRockSmash(d->x + 20, d->y + 20); |
int sx = d->x / 40; |
int sy = d->y / 40; |
foreground.tileX[sx][sy] = 0; |
foreground.tileY[sx][sy] = 0; |
collisionTiles[sx][sy] = 0; |
PHL_UpdateBackground(background, foreground); |
if (d->secret == 0) { |
spawnCollectable(d->x + 20, d->y); |
}else if (d->secret == 1) { |
roomSecret = 1; |
} |
objectDestroy(d->id); |
} |
if (hasItem[0] == 0) { |
PHL_PlaySound(sounds[sndHit03], 1); |
} |
} |
} |
} |
} |
/*}else{ |
d->invulnerable -= 1; |
} |
*/ |
} |
//Secret Trigger |
void createSecretTrigger(int type, int enemyType, int flag) |
{ |
if (flag != 0 && flags[flag] == 1) { |
roomSecret = 1; |
}else{ |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
SecretTrigger* s = malloc(sizeof *s); |
s->id = i; |
s->flag = flag; |
s->type = type; |
s->enemyType = enemyType; |
o->data = s; |
o->objectStep = secretTriggerStep; |
o->objectDraw = nullFunction; |
o->type = -1; |
objects[i] = o; |
i = MAX_OBJECTS; |
} |
} |
} |
} |
void secretTriggerStep(SecretTrigger* s) |
{ |
int i, result = 1; |
for (i = 0; i < MAX_ENEMIES; i++) { |
if (s->type == 0) { //Destroy all enemies |
if (enemies[i] != NULL && enemies[i]->type != -1) { |
i = MAX_ENEMIES; |
result = 0; |
} |
} |
else if (s->type == 1) { //Destroy one type of enemy |
if (enemies[i] != NULL && enemies[i]->type == s->enemyType) { |
i = MAX_ENEMIES; |
result = 0; |
} |
} |
else{ //No trigger, only activate on creation |
result = 0; |
} |
} |
if (result == 1) { |
if (s->flag != 0) { |
flags[s->flag] = 1; |
} |
roomSecret = 1; |
objectDestroy(s->id); |
} |
} |
//Chest |
void createChest(int x, int y, int item, int secret) |
{ |
//Don't create if the player already has the item |
int dospawn = 1; |
if (item <= 4) { |
if (hasWeapon[item] == 1) { dospawn = 0; } |
} |
else if (item <= 32) { |
if (hasItem[item - 5] == 1) { dospawn = 0; } |
} |
else if (item <= 40) { |
if (hasKey[item - 33] == 1) { dospawn = 0; } |
} |
if (dospawn == 1) { |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
Chest* c = malloc(sizeof *c); |
c->id = i; |
c->x = x; |
c->y = y; |
c->item = item; |
c->secret = secret; |
c->timer = 10; |
c->visible = 1; |
if (secret == 1 && roomSecret == 0) { //Assume secret trigger is loaded before chest |
c->visible = 0; |
if (hasItem[2] == 1) { //Has Bell |
PHL_PlaySound(sounds[sndBell01], CHN_SOUND); |
//bellFlag = 1; |
} |
} |
c->mask.x = x; |
c->mask.y = y; |
c->mask.w = c->mask.h = 40; |
c->mask.unused = c->mask.circle = 0; |
o->data = c; |
o->objectStep = chestStep; |
o->objectDraw = chestDraw; |
o->type = 4; |
objects[i] = o; |
i = MAX_OBJECTS; |
} |
} |
} |
} |
#ifdef EMSCRIPTEN |
extern int em_state; |
#endif |
void chestStep(Chest* c) |
{ |
if (c->visible == 1) { |
c->timer -= 1; |
if (c->timer <= 0) { |
createEffectExtra(5, c->x + (rand() % 40) + 1, c->y + 4 + (rand() % 40) + 1, 0, 0, 0); |
c->timer = 12; |
} |
if (btnUp.pressed == 1) { |
if (getHeroOnground() == 1 && checkCollisionXY(c->mask, herox, heroy + 20) == 1) { |
PHL_PlaySound(sounds[sndGet02], CHN_HERO); |
if (c->item <= 4) { |
hasWeapon[c->item] = 1; |
itemGotX = 40 + (c->item * 40); |
itemGotY = 0; |
} |
else if (c->item <= 32) { |
hasItem[c->item - 5] = 1; |
int itemorder[28] = { 12, 16, 15, 14, 7, 9, 8, |
17, 3, 5, 4, 6, 2, 10, |
13, 11, 0, 1, 21, 25, 26, |
20, 24, 27, 22, 19, 18, 23 }; |
itemGotX = 280 + (itemorder[c->item - 5] * 40); |
itemGotY = 0; |
while (itemGotX >= 640) { |
itemGotX -= 640; |
itemGotY += 40; |
} |
} |
else if (c->item <= 40) { |
hasKey[c->item - 33] = 1; |
itemGotX = 120 + ((c->item - 33) * 40); |
itemGotY = 80; |
} |
//Fix no 2nd jump immediatly after getting boots |
if (c->item == 17) { |
setHeroCanjump(1); |
} |
//setHeroState(6); //Set hero state to GETITEM |
int saveItem = c->item; |
objectDestroy(c->id); |
#ifdef EMSCRIPTEN |
getItemSetup(saveItem); |
em_state = 50; |
#else |
getItem(saveItem); |
#endif |
} |
} |
} |
else { |
if (roomSecret == 1) { |
c->visible = 1; |
playSecret(); |
} |
//Visible if the boss is already defeated |
if (bossDefeatedFlag == 1) { |
c->visible = 1; |
} |
} |
} |
void chestDraw(Chest* c) |
{ |
if (c->visible == 1) { |
int dx = 520, dy = 0; |
if (c->item > 32) { |
dx = 240; |
dy = 120; |
} |
PHL_DrawSurfacePart(c->x, c->y, dx, dy, 40, 40, images[imgMisc20]); |
} |
} |
//Save point |
void createSavePoint(int x, int y, int hidden) |
{ |
if (hidden == 0 || hasKey[7] == 1) { |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
SavePoint* s = malloc(sizeof *s); |
s->id = i; |
s->x = x; |
s->y = y; |
s->imageIndex = 0; |
s->mask.x = x + 6; |
s->mask.y = y; |
s->mask.w = 28; |
s->mask.h = 40; |
s->mask.unused = s->mask.circle = 0; |
o->data = s; |
o->objectStep = savePointStep; |
o->objectDraw = savePointDraw; |
o->type = -1; |
objects[i] = o; |
i = MAX_OBJECTS; |
} |
} |
} |
} |
void savePointStep(SavePoint* s) |
{ |
s->imageIndex += 0.15; |
if (s->imageIndex >= 4) { |
s->imageIndex -= 4; |
} |
if (btnUp.pressed == 1 && getHeroOnground() == 1) { |
if (checkCollisionXY(s->mask, herox, heroy)) { |
saveScreen(); |
} |
} |
} |
void savePointDraw(SavePoint* s) |
{ |
PHL_DrawSurfacePart(s->x, s->y, (int)s->imageIndex * 40, 320, 40, 40, images[imgMisc20]); |
} |
//Door |
unsigned char unlockedDoor[8] = {0, 2, 6, 7, 32, 22, 39, 48}; |
void createDoor(int x, int y, int level, int coords, int warpx, int warpy, int secret) |
{ |
if (level != 8 || hasKey[7] == 1) { |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
Door* d = malloc(sizeof *d); |
d->id = i; |
d->x = x; |
d->y = y; |
d->visible = 1; |
d->secret = secret; |
if (d->secret == 1) { |
d->visible = 0; |
} |
d->open = 0; |
if (level == 0) { |
d->open = 1; |
}else{ |
d->open = flags[unlockedDoor[level-1]]; |
} |
d->warplevel = level; |
d->warpcoords = coords; |
d->warpx = warpx; |
d->warpy = warpy; |
d->mask.x = x + 6; |
d->mask.y = y; |
d->mask.w = 28; |
d->mask.h = 40; |
d->mask.unused = d->mask.circle = 0; |
o->data = d; |
o->objectStep = doorStep; |
o->objectDraw = doorDraw; |
o->type = -1; |
objects[i] = o; |
i = MAX_OBJECTS; |
} |
} |
} |
} |
void doorStep(Door* d) |
{ |
if (d->visible == 1) { |
if (btnUp.pressed == 1 && getHeroOnground() == 1 && getHeroState() != 6) { |
if (checkCollisionXY(d->mask, herox, heroy)) { |
if (d->open == 0) { |
if (hasKey[d->warplevel - 1] == 1) { |
d->open = 1; |
flags[unlockedDoor[d->warplevel - 1]] = 1; |
//doorUnlocked[d->warplevel-1] = 1; |
PHL_PlaySound(sounds[sndDoor00], CHN_SOUND); |
} |
}else{ |
//Setup Door event |
herox = d->x + 20; |
heroy = d->y; |
lastDoor = d; |
setHeroState(7); //Set state to DOOR |
PHL_PlaySound(sounds[sndStep01], CHN_HERO); |
} |
} |
} |
}else{ |
if (bossDefeatedFlag == 1 && hasKey[getLevel()]) { |
d->visible = 1; |
} |
//Display key and door if the boss didn't show up |
else if (d->secret == 1 && bossFlag == 0) { |
bossFlag = 1; |
bossDefeatedFlag = 1; |
PHL_StopMusic(); |
} |
} |
} |
void doorDraw(Door* d) |
{ |
if (d->visible == 1) { |
PHL_DrawSurfacePart(d->x, d->y, 600 - (40 * d->open), 0, 40, 40, images[imgMisc20]); |
} |
} |
//Lock Block |
void createLockBlock(int x, int y, int flag) |
{ |
if (flags[flag] == 0) { |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
LockBlock* l = malloc(sizeof *l); |
l->id = i; |
l->x = x; |
l->y = y; |
l->invincible = 0; |
int tx = x / 40; |
int ty = y / 40; |
l->tile = collisionTiles[tx][ty]; |
collisionTiles[tx][ty] = 1; |
l->flag = flag; |
o->data = l; |
o->objectStep = lockBlockStep; |
o->objectDraw = lockBlockDraw; |
o->type = -1; |
objects[i] = o; |
i = MAX_OBJECTS; |
} |
} |
} |
} |
void lockBlockStep(LockBlock* l) |
{ |
//Collide with weapons |
if (l->invincible <= 0) { |
Mask mask; |
mask.circle = mask.unused = 0; |
mask.x = l->x; |
mask.y = l->y; |
mask.w = mask.h = 40; |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
l->invincible = 15; |
//Sound |
weaponHit(weapons[i]); |
PHL_PlaySound(sounds[sndHit03], CHN_WEAPONS); |
i = MAX_WEAPONS; |
} |
} |
} |
}else{ |
l->invincible -= 1; |
} |
if (roomSecret == 1) { |
playSecret(); |
int tx = l->x / 40; |
int ty = l->y / 40; |
collisionTiles[tx][ty] = l->tile; |
flags[l->flag] = 1; |
//Destroy |
objectDestroy(l->id); |
/* |
free(objects[l->id]); |
objects[l->id] = NULL; |
*/ |
} |
} |
void lockBlockDraw(LockBlock* l) |
{ |
PHL_DrawSurfacePart(l->x, l->y, 120, 400, 40, 40, images[imgMisc20]); |
} |
//Green light switch |
void createSwitch(int x, int y, int flag) |
{ |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
Switch* s = malloc(sizeof *s); |
s->id = i; |
s->x = x; |
s->y = y; |
s->imageIndex = 0; |
s->flag = flag; |
s->activated = 0; |
if (flags[s->flag] == 1) { |
switchResult(s); |
s->activated = 1; |
} |
o->data = s; |
o->objectStep = switchStep; |
o->objectDraw = switchDraw; |
o->type = 76; |
objects[i] = o; |
i = MAX_OBJECTS; |
} |
} |
} |
void switchStep(Switch* s) |
{ |
if (s->activated == 0) { |
if (btnUp.pressed == 1) { |
Mask mask; |
mask.unused = mask.circle = 0; |
mask.w = 16; |
mask.h = 30; |
mask.x = s->x + 12; |
mask.y = s->y + 10; |
if (checkCollision(mask, getHeroMask())) { |
if (switchActivate(s) == 1) { |
PHL_PlaySound(sounds[sndPi02], CHN_SOUND); |
playSecret(); |
} |
} |
} |
}else{ |
s->imageIndex += 0.2; |
if (s->imageIndex >= 3) { |
s->imageIndex -= 2; |
} |
} |
} |
int switchActivate(Switch* s) |
{ |
int success = 0; |
if ((s->flag == 24 && hasItem[23] == 1) || //Switch in level 2 |
(s->flag == 26 && hasItem[24] == 1)) { //Switch in level 6 |
success = 1; |
} |
//Switches in level 7 |
if ((s->flag == 44 && hasItem[25] == 1) || //Left Switch |
(s->flag == 43 && hasItem[26] == 1)) |
{ |
PHL_PlaySound(sounds[sndPi02], CHN_SOUND); |
s->activated = 1; |
flags[s->flag] = 1; |
if (flags[44] == 1 && flags[43] == 1) { |
flags[45] = 1; |
roomSecret = 1; |
success = 1; |
} |
} |
if (success == 1) { |
switchResult(s); |
s->activated = 1; |
flags[s->flag] = 1; |
} |
return success; |
} |
void switchResult(Switch* s) |
{ |
if (s->flag == 24) { //Switch in level 2 |
createPlatform(0, 320, 240, 320, 360, 1, 0); |
flags[23] = 1; |
} |
if (s->flag == 26) { //Switch in level 6 |
roomSecret = 1; |
} |
} |
void switchDraw(Switch* s) |
{ |
PHL_DrawSurfacePart(s->x, s->y, 240 + (40 * (int)s->imageIndex), 560, 40, 40, images[imgMisc20]); |
} |
//Gates |
void createGate(int x, int y, int col) |
{ |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
Gate* g = malloc(sizeof *g); |
g->id = i; |
g->x = x; |
g->y = y; |
g->col = col; |
g->imageIndex = 0; |
g->timer = 0; |
g->open = 0; |
//g->invincible = 0; |
o->data = g; |
o->objectStep = gateStep; |
o->objectDraw = gateDraw; |
o->type = 53; |
objects[i] = o; |
i = MAX_OBJECTS; |
} |
} |
} |
void gateStep(Gate* g) |
{ |
//Animate |
{ |
if (g->open == 1) { |
if (g->imageIndex < 4) { |
g->imageIndex += 0.1; |
} |
} |
} |
//Not (fully) opened |
if (g->imageIndex < 4) |
{ |
//Setup Mask |
Mask mask; |
{ |
mask.unused = mask.circle = 0; |
mask.x = g->x + 11; |
mask.y = g->y; |
mask.w = 18; |
mask.h = 40; |
} |
//Collide with player |
{ |
if (checkCollision(mask, getHeroMask())) { |
if (getHeroHsp() < 0) { |
herox = mask.x + mask.w + (getHeroMask().w / 2); |
} |
else if (getHeroHsp() > 0) { |
herox = mask.x - (getHeroMask().w / 2); |
} |
} |
} |
//Collide with weapons |
{ |
if (g->open == 0) { |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
PHL_PlaySound(sounds[sndHit03], CHN_WEAPONS); |
//Is a sword |
if (weapons[i]->type == 5) { |
if ((g->col == 0 && hasItem[20] == 1) || (g->col == 1 && hasItem[19] == 1)) { |
g->open = 1; |
PHL_PlaySound(sounds[sndDoor00], CHN_SOUND); |
} |
} |
weaponHit(weapons[i]); |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
} |
} |
} |
void gateDraw(Gate* g) |
{ |
int cx = (int)g->imageIndex * 40, |
cy = 520; |
if (g->col == 0) { //Red Gate |
cx += 200; |
} |
PHL_DrawSurfacePart(g->x, g->y, cx, cy, 40, 40, images[imgMisc20]); |
} |
//Statue |
void createStatue(int x, int y, int type) |
{ |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
Statue* s = malloc(sizeof *s); |
s->id = i; |
s->x = x; |
s->y = y; |
s->type = type; |
s->invincible = 0; |
s->hp = 3; |
o->data = s; |
o->objectStep = statueStep; |
o->objectDraw = statueDraw; |
o->type = 54; |
objects[i] = o; |
i = MAX_OBJECTS; |
} |
} |
} |
void statueStep(Statue* s) |
{ |
Mask mask; |
mask.unused = mask.circle = 0; |
mask.w = 40; |
mask.h = 40; |
mask.x = s->x + ((40 - mask.w) / 2); |
mask.y = s->y; |
//Collide with hero |
if (checkCollision(mask, getHeroMask()) == 1) { |
if (getHeroHsp() < 0) { |
herox = mask.x + mask.w + (getHeroMask().w / 2) + 1; |
} |
if (getHeroHsp() > 0) { |
herox = mask.x - (getHeroMask().w / 2); |
} |
} |
//Collide with weapons |
if (s->invincible <= 0) { |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
s->invincible = 15; |
//Sound |
weaponHit(weapons[i]); |
//Break if you have the right item |
if ((s->type == 0 && hasItem[22] == 1) || (s->type == 1 && hasItem[21] == 1)) { |
s->hp -= 1; |
if (s->hp <= 0) { |
createRockSmash(s->x + 20, s->y + 20); |
objectDestroy(s->id); |
} |
}else{ |
PHL_PlaySound(sounds[sndHit03], CHN_WEAPONS); |
} |
i = MAX_WEAPONS; |
} |
} |
} |
}else{ |
s->invincible -= 1; |
} |
} |
void statueDraw(Statue* s) |
{ |
int cx = 200, |
cy = 400; |
if (s->type == 1) { |
cx += 200; |
} |
PHL_DrawSurfacePart(s->x, s->y, cx, cy, 40, 40, images[imgMisc20]); |
} |
//Button |
void createFloorPad(int x, int y, int flag) |
{ |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
char found = 0; |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
FloorPad* f = malloc(sizeof *f); |
f->id = i; |
f->x = x; |
f->y = y; |
f->pressed = 0; |
f->flag = flag; |
if (flag != 0 && flags[flag] == 1) { |
roomSecret = 1; |
} |
o->data = f; |
o->objectStep = buttonStep; |
o->objectDraw = buttonDraw; |
o->type = 77; |
objects[i] = o; |
i = MAX_OBJECTS; |
found = 1; |
} |
if (found == 1) { |
//Create a breakable block if it's covered by a solid block |
int roundx = x / 40, |
roundy = y / 40; |
if (collisionTiles[roundx][roundy] == 1) { |
createDestroyable(x, y, 2); |
} |
} |
} |
} |
void buttonStep(FloorPad* f) |
{ |
if (f->pressed == 0) { |
if (getHeroVsp() > 0) { |
Mask mask; |
mask.unused = mask.circle = 0; |
mask.w = 16; |
mask.h = 10; |
mask.x = f->x + ((40 - mask.w) /2); |
mask.y = f->y + (40 - mask.h); |
if (checkCollision(mask, getHeroMask()) == 1) { |
f->pressed = 1; |
PHL_PlaySound(sounds[sndHit02], CHN_SOUND); |
//Check if there are other buttons unpressed |
int found = 0; |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] != NULL) { |
if (objects[i]->type == 77) { |
FloorPad* btemp = objects[i]->data; |
if (btemp->pressed == 0) { |
found = 1; |
i = MAX_OBJECTS; |
} |
} |
} |
} |
//Activate flag |
if (found == 0) { |
roomSecret = 1; |
if (f->flag != 0 && flags[f->flag] == 0) { |
flags[f->flag] = 1; |
} |
} |
} |
} |
} |
} |
void buttonDraw(FloorPad* f) |
{ |
char covered = 0; |
int roundx = f->x / 40, |
roundy = f->y / 40; |
//Covered by breakable block |
if (collisionTiles[roundx][roundy] == 1) { |
covered = 1; |
} |
if (covered == 0) { |
PHL_DrawSurfacePart(f->x, f->y, 160 + (f->pressed * 40), 320, 40, 40, images[imgMisc20]); |
} |
} |
//Ladder |
void createLadder(int x, int y, int flag) |
{ |
if (flags[flag] == 1) { |
ladderActivate(x, y); |
}else{ |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
Ladder* l = malloc(sizeof *l); |
l->id = i; |
l->x = x; |
l->y = y; |
l->flag = flag; |
if (getLevel() != 6) { |
if (hasItem[2] == 1) { //Has Bell |
PHL_PlaySound(sounds[sndBell01], CHN_SOUND); |
} |
} |
o->data = l; |
o->objectStep = ladderStep; |
o->objectDraw = nullFunction; |
o->type = 79; |
objects[i] = o; |
i = MAX_OBJECTS; |
} |
} |
} |
} |
void ladderStep(Ladder* l) |
{ |
if (roomSecret == 1) { |
playSecret(); |
flags[l->flag] = 1; |
ladderActivate(l->x, l->y); |
objectDestroy(l->id); |
} |
} |
void ladderActivate(int x, int y) |
{ |
y = (int)(y / 40); |
x = (int)(x / 40); |
while (y >= 0) { |
foreground.tileX[x][y] = 3; |
foreground.tileY[x][y] = 0; |
collisionTiles[x][y] = 2; |
y -= 1; |
} |
PHL_UpdateBackground(background, foreground); |
} |
//Generator |
void createGenerator(int x, int y, int flag) |
{ |
if (flags[flag] == 0) { |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
Generator* g = malloc(sizeof *g); |
g->id = i; |
g->hp = 3; |
g->blink = 0; |
g->x = x; |
g->y = y; |
g->imageIndex = 0; |
g->flag = flag; |
o->data = g; |
o->objectStep = generatorStep; |
o->objectDraw = generatorDraw; |
o->type = 80; |
objects[i] = o; |
i = MAX_OBJECTS; |
} |
} |
} |
} |
void generatorStep(Generator* g) |
{ |
//Animate |
{ |
g->imageIndex += 0.33; |
if (g->imageIndex >= 2) { |
g->imageIndex -= 2; |
} |
if (g->blink > 0) { |
g->blink -= 1; |
} |
} |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 24; |
mask.h = 40; |
mask.x = g->x + ((40 - mask.w) / 2); |
mask.y = g->y; |
} |
//Weapon collision |
{ |
int i; |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->cooldown == 0) { |
if (checkCollision(mask, weapons[i]->weaponMask)) { |
weaponHit(weapons[i]); |
g->hp -= 1; |
g->blink = 15; |
i = MAX_WEAPONS; |
} |
} |
} |
} |
} |
//Destroy |
{ |
if (g->hp <= 0) { |
createRockSmash(g->x + 20, g->y + 20); |
flags[g->flag] = 1; |
//if no generators exist |
{ |
char found = 0; |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (i != g->id && objects[i] != NULL) { |
if (objects[i]->type == 80) { |
found = 1; |
i = MAX_OBJECTS; |
} |
} |
} |
if (found == 0) { |
roomSecret = 1; |
playSecret(); |
} |
} |
objectDestroy(g->id); |
} |
} |
} |
void generatorDraw(Generator* g) |
{ |
if (g->blink % 2 == 0) { |
PHL_DrawSurfacePart(g->x, g->y, 80 + ((int)g->imageIndex * 40), 600, 40, 40, images[imgMisc20]); |
} |
} |
//Electric gate |
void createShockgate(int x, int y, int flag) |
{ |
if (flags[flag] == 0) { |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
Shockgate* s = malloc(sizeof *s); |
s->id = i; |
s->x = x; |
s->y = y; |
s->imageIndex = 0; |
s->flag = flag; |
o->data = s; |
o->objectStep = shockgateStep; |
o->objectDraw = shockgateDraw; |
o->type = 56; |
objects[i] = o; |
i = MAX_OBJECTS; |
} |
} |
} |
} |
void shockgateStep(Shockgate* s) |
{ |
//Animate |
{ |
s->imageIndex += 0.33; |
if (s->imageIndex >= 4) { |
s->imageIndex -= 4; |
} |
} |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 40 * 3; |
mask.h = 8; |
mask.x = s->x; |
mask.y = s->y + ((40 - mask.h) / 2); |
} |
//Hero Collision |
{ |
if (checkCollision(mask, getHeroMask()) == 1) { |
heroy = mask.y - 40; |
setHeroVsp(0); |
} |
} |
//Destroy |
if (roomSecret == 1) { |
flags[s->flag] = 1; |
objectDestroy(s->id); |
} |
} |
void shockgateDraw(Shockgate* s) |
{ |
int i; |
for (i = 0; i < 3; i++) { |
PHL_DrawSurfacePart(s->x + (40 * i), s->y, 80 + ((int)s->imageIndex * 40), 560, 40, 40, images[imgMisc20]); |
} |
} |
//Crown |
void createCrown(int x, int y) |
{ |
int i; |
for (i = 0; i < MAX_OBJECTS; i++) { |
if (objects[i] == NULL) { |
Object* o = malloc(sizeof *o); |
Crown* c = malloc(sizeof *c); |
c->id = i; |
c->x = x; |
c->y = y; |
c->ystart = c->y; |
c->bobRot = 0; |
c->imageIndex = 0; |
c->visible = 0; |
c->timer = 0; |
o->data = c; |
o->objectStep = crownStep; |
o->objectDraw = crownDraw; |
o->type = 57; |
objects[i] = o; |
i = MAX_OBJECTS; |
} |
} |
} |
void crownStep(Crown* c) |
{ |
if (c->visible == 0) { |
if (roomSecret == 1) { |
c->visible = 1; |
playSecret(); |
} |
}else{ |
//Animate |
{ |
c->imageIndex += 0.33; |
if (c->imageIndex >= 2) { |
c->imageIndex -= 2; |
} |
//Movement |
c->bobRot += 6; |
if (c->bobRot >= 360) { |
c->bobRot -= 360; |
} |
c->y = c->ystart + sin(c->bobRot * 3.14159 / 180) * 5; |
} |
//Sparkle |
c->timer -= 1; |
if (c->timer <= 0) { |
createEffectExtra(5, c->x + (rand() % 40) + 1, c->y + 4 + (rand() % 40) + 1, 0, 0, 0); |
c->timer = 12; |
} |
//Setup Mask |
Mask mask; |
{ |
mask.circle = mask.unused = 0; |
mask.w = 15; |
mask.h = 11; |
mask.x = c->x + 20 - (mask.w / 2); |
mask.y = c->y + 20 - (mask.h / 2); |
} |
if (checkCollision(mask, getHeroMask()) == 1) { |
objectDestroy(c->id); |
gameEnding(); |
} |
} |
} |
void crownDraw(Crown* c) |
{ |
if (c->visible == 1) { |
int cropX = (int)c->imageIndex * 40; |
PHL_DrawSurfacePart(c->x, c->y, cropX, 200, 40, 40, images[imgHero]); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/object.h |
---|
0,0 → 1,181 |
#ifndef OBJECT_H |
#define OBJECT_H |
#include "collision.h" |
typedef struct { |
void* data; //Specific object struct |
void (*objectStep)(); |
void (*objectDraw)(); |
int type; |
} Object; |
void objectDestroy(int id); |
//Health/Ammo collectables |
typedef struct { |
int id, type; //0 for ammo, 1 for heart |
double x, y, |
vsp, grav; |
int blink, canLand, bounce; |
} Ammo; |
void spawnCollectable(int x, int y); |
void createAmmo(int x, int y, int type); |
//Destroyable blocks |
typedef struct { |
int id; |
int x, y; |
int hp/*, invulnerable*/; |
int secret; |
Mask mask; |
} Destroyable; |
void createDestroyable(int x, int y, int secret); |
//Secret Trigger |
typedef struct { |
int id, flag; |
int type, enemyType; |
} SecretTrigger; |
void createSecretTrigger(int type, int enemyType, int flag); |
//Chest |
typedef struct { |
int id; |
int x, y; |
int item, secret; |
int visible; |
int timer; |
Mask mask; |
} Chest; |
void createChest(int x, int y, int item, int secret); |
//Save point |
typedef struct { |
int id; |
int x, y; |
double imageIndex; |
Mask mask; |
} SavePoint; |
void createSavePoint(int x, int y, int hidden); |
//Door |
typedef struct { |
int id; |
int x, y; |
int open, secret, visible; |
int warplevel, warpcoords; |
int warpx, warpy; |
Mask mask; |
} Door; |
void createDoor(int x, int y, int level, int coords, int warpx, int warpy, int secret); |
//Lock Block |
typedef struct { |
int id, flag; |
int x, y; |
int tile; |
int invincible; |
} LockBlock; |
void createLockBlock(int x, int y, int flag); |
//Light Switch |
typedef struct { |
int id, flag; |
int x, y; |
int activated; |
double imageIndex; |
} Switch; |
void createSwitch(int x, int y, int flag); |
//Blue/Red Gates |
typedef struct { |
int id; |
int x, y; |
int col; |
int timer, open; |
//int invincible; |
double imageIndex; |
} Gate; |
void createGate(int x, int y, int col); |
//Statue |
typedef struct { |
int id; |
int x, y; |
int type; |
int invincible; |
int hp; |
} Statue; |
void createStatue(int x, int y, int type); |
//Button |
typedef struct { |
int id; |
int x, y; |
int flag; |
int pressed; |
} FloorPad; |
void createFloorPad(int x, int y, int flag); |
//Ladder |
typedef struct { |
int id; |
int x, y; |
int flag; |
} Ladder; |
void createLadder(int x, int y, int flag); |
//Generator |
typedef struct { |
int id; |
int hp; |
int blink; |
int x, y; |
double imageIndex; |
int flag; |
} Generator; |
void createGenerator(int x, int y, int flag); |
//Electric gate |
typedef struct { |
int id; |
int x, y; |
double imageIndex; |
int flag; |
} Shockgate; |
void createShockgate(int x, int y, int flag); |
//Ending crown |
typedef struct { |
int id; |
int x, ystart; |
double y; |
double bobRot; |
double imageIndex; |
int timer; |
char visible; |
} Crown; |
void createCrown(int x, int y); |
#endif |
/contrib/games/hydracastlelabyrinth/src/options.c |
---|
0,0 → 1,381 |
#include <stdio.h> |
#include "options.h" |
#include "PHL.h" |
#include "game.h" |
#include "ini.h" |
#include "text.h" |
char page = 0; |
int optCursor = 0; |
int lastOption = -1; |
#ifdef _SDL |
int musicType = 1; |
int getMusicType() |
{ |
return musicType; |
} |
void setMusicType(int t) |
{ |
#ifndef _KOLIBRI |
if(t!=musicType) |
{ |
musicType = t; |
// restart music... |
} |
#else |
musicType = 1; /* MIDI NOT WORK! */ |
#endif |
} |
#endif |
#ifdef EMSCRIPTEN |
static char tempDark; |
static int emOnly; |
void optionsSetup(int only) |
{ |
tempDark = roomDarkness; |
roomDarkness = 0; |
emOnly = only; |
page = only?1:0; |
} |
int optionsEMStep() |
{ |
int loop = 1; |
PHL_MainLoop(); |
PHL_StartDrawing(); |
optionsDraw(); |
PHL_ScanInput(); |
int result = optionsStep(); |
PHL_EndDrawing(); |
if (page == 0 && result != -1 && result != 2) { |
loop = 0; |
} |
if (emOnly && page==0) { |
loop = 0; |
} |
if(!loop) roomDarkness = tempDark; |
return (!loop)?result:-1; |
} |
#else |
int options(int only) |
{ |
char tempDark = roomDarkness; |
roomDarkness = 0; |
int result = -1; |
char loop = 1; |
if(only) page=1; |
while (PHL_MainLoop() && loop == 1) |
{ |
PHL_StartDrawing(); |
optionsDraw(); |
PHL_ScanInput(); |
result = optionsStep(); |
PHL_EndDrawing(); |
if (page == 0 && result != -1 && result != 2) { |
loop = 0; |
} |
if (only && page==0) { |
loop = 0; |
} |
} |
roomDarkness = tempDark; |
return result; |
} |
#endif |
int optionsStep() |
{ |
int result = -1; |
secretCountdown(); |
//input |
if (btnDown.pressed == 1) { |
optCursor += 1; |
PHL_PlaySound(sounds[sndPi01], CHN_SOUND); |
}else if (btnUp.pressed == 1) { |
optCursor -= 1; |
PHL_PlaySound(sounds[sndPi01], CHN_SOUND); |
} |
//First screen (continue/reset/exit) |
if (page == 0) { |
//Limit cursor |
if (optCursor >= 4) { |
optCursor = 0; |
} |
if (optCursor < 0) { |
optCursor = 3; |
} |
if (btnAccept.pressed == 1 || btnStart.pressed == 1) { |
result = optCursor; |
if (result == 1) { |
PHL_StopMusic(); |
} |
if (result == 2) { |
page = 1; |
optCursor = 0; |
} |
//No blip on game exit |
if (optCursor != 3) { |
PHL_PlaySound(sounds[sndOk], CHN_SOUND); |
} |
} |
if (btnSelect.pressed == 1) { |
result = 0; |
PHL_PlaySound(sounds[sndOk], CHN_SOUND); |
} |
} |
//Actual options screen |
else if (page == 1) { |
//Limit cursor |
if (optCursor > lastOption) { |
optCursor = 0; |
} |
if (optCursor < 0) { |
optCursor = lastOption; |
} |
if (btnAccept.pressed == 1 || btnStart.pressed == 1) { |
//Universal settings |
//Language |
if (optCursor == 0) { |
if (getLanguage() == JAPANESE) { |
setLanguage(ENGLISH); |
}else{ |
setLanguage(JAPANESE); |
} |
} |
//Autosave |
if (optCursor == 1) { |
if (getAutoSave() == 0) { |
setAutoSave(1); |
}else{ |
setAutoSave(0); |
} |
} |
#ifdef _3DS |
if (optCursor == 2) { |
if (activeScreen->screen == GFX_TOP) { |
swapScreen(GFX_BOTTOM, GFX_LEFT); |
}else{ |
swapScreen(GFX_TOP, GFX_LEFT); |
} |
} |
#endif |
#ifdef _PSP |
if (optCursor == 2) { |
if (getScreenSize() == 0) { |
setScreenSize(1); |
}else if (getScreenSize() == 1) { |
setScreenSize(2); |
}else{ |
setScreenSize(0); |
} |
} |
//Blur |
if (optCursor == 3) { |
if (getBlur() == 0) { |
setBlur(1); |
}else{ |
setBlur(0); |
} |
} |
#endif |
#ifdef _SDL |
// Music type |
if(optCursor == 2) { |
if(getMusicType() == 0) |
setMusicType(1); |
else |
setMusicType(0); |
} |
// Music volume |
if(optCursor == 3) { |
music_volume = (music_volume+1)%5; |
PHL_MusicVolume(0.25f * music_volume); |
} |
// xBRZ |
if (optCursor == 4) { |
if (getXBRZ() == 0) { |
setXBRZ(1); |
}else{ |
setXBRZ(0); |
} |
} |
#endif |
//Back |
if (optCursor == lastOption) { |
page = 0; |
} |
} |
else if (btnDecline.pressed == 1) { |
page = 0; |
} |
if (page == 0) { |
saveSettings(); |
} |
} |
return result; |
} |
void optionsDraw() |
{ |
PHL_DrawRect(0, 0, 640, 480, PHL_NewRGB(0, 0, 0)); |
if (page == 0) |
{ |
PHL_DrawTextBold("CONTINUE", 254, 144, YELLOW); |
PHL_DrawTextBold("RESET", 278, 176, YELLOW); |
PHL_DrawTextBold("OPTIONS", 262, 208, YELLOW); |
PHL_DrawTextBold("EXIT", 286, 240, YELLOW); |
PHL_DrawTextBold("<", 232, 144 + (32 * optCursor), RED); |
PHL_DrawTextBold(">", 390, 144 + (32 * optCursor), RED); |
} |
else if (page == 1) |
{ |
int xleft = 216; |
int xright = xleft + 160; |
int ydrawstart = 144; |
int ydraw = ydrawstart; |
int ystep = 32; |
int optioncount = 0; |
//Language |
PHL_DrawTextBold("LANGUAGE", xleft, ydraw, YELLOW); |
if (getLanguage() == 1) { |
PHL_DrawTextBold("EN", xright, ydraw, YELLOW); |
} |
if (getLanguage() == 0) { |
PHL_DrawTextBold("JP", xright, ydraw, YELLOW); |
} |
ydraw += ystep; |
optioncount++; |
//AutoSave |
PHL_DrawTextBold("SAFE SAVE", xleft, ydraw, YELLOW); |
if (getAutoSave() == 1) { |
PHL_DrawTextBold("ON", xright, ydraw, YELLOW); |
}else{ |
PHL_DrawTextBold("OFF", xright, ydraw, YELLOW); |
} |
ydraw += ystep; |
optioncount++; |
#ifdef _3DS |
//Screen |
PHL_DrawTextBold("SCREEN", xleft, ydraw, YELLOW); |
if (activeScreen->screen == GFX_TOP) { |
PHL_DrawTextBold("TOP", xright, ydraw, YELLOW); |
}else{ |
PHL_DrawTextBold("BOTTOM", xright, ydraw, YELLOW); |
} |
ydraw += ystep; |
optioncount++; |
#endif |
#ifdef _PSP |
//Screen Size |
PHL_DrawTextBold("SCREEN", xleft, ydraw, YELLOW); |
if (getScreenSize() == 0) { |
PHL_DrawTextBold("1:1", xright, ydraw, YELLOW); |
} |
else if (getScreenSize() == 1) { |
PHL_DrawTextBold("FILL", xright, ydraw, YELLOW); |
} |
else if (getScreenSize() == 2) { |
PHL_DrawTextBold("FULL", xright, ydraw, YELLOW); |
} |
ydraw += ystep; |
optioncount++; |
//Blur |
PHL_DrawTextBold("BLUR", xleft, ydraw, YELLOW); |
if (getBlur() == 1) { |
PHL_DrawTextBold("ON", xright, ydraw, YELLOW); |
} |
else{ |
PHL_DrawTextBold("OFF", xright, ydraw, YELLOW); |
} |
ydraw += ystep; |
optioncount++; |
#endif |
#ifdef _SDL |
// Music type |
PHL_DrawTextBold("MUSIC", xleft, ydraw, YELLOW); |
if (getMusicType() == 1) { |
PHL_DrawTextBold("OGG", xright, ydraw, YELLOW); |
} |
else{ |
PHL_DrawTextBold("MIDI", xright, ydraw, YELLOW); |
} |
ydraw += ystep; |
optioncount++; |
// Music volume |
PHL_DrawTextBold("MUSIC", xleft, ydraw, YELLOW); |
char buff[50]; |
sprintf(buff, "%d%%", music_volume*25); |
PHL_DrawTextBold(buff, xright, ydraw, YELLOW); |
ydraw += ystep; |
optioncount++; |
// xBRZ scaling |
PHL_DrawTextBold("XBRZ", xleft, ydraw, YELLOW); |
if (getXBRZ() == 1) { |
PHL_DrawTextBold("ON", xright, ydraw, YELLOW); |
} |
else{ |
PHL_DrawTextBold("OFF", xright, ydraw, YELLOW); |
} |
ydraw += ystep; |
optioncount++; |
#endif |
PHL_DrawTextBold("BACK", xleft, ydraw, YELLOW); |
if (lastOption == -1) { |
lastOption = optioncount; |
} |
PHL_DrawTextBold(">", xleft - 32, ydrawstart + (ystep * optCursor), RED); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/options.h |
---|
0,0 → 1,18 |
#ifndef OPTIONS_H |
#define OPTIONS_H |
#ifdef EMSCRIPTEN |
void optionsSetup(int only); |
int optionsEMStep(); |
#else |
int options(int only); |
#endif |
int optionsStep(); |
void optionsDraw(); |
#ifdef _SDL |
int getMusicType(); |
void setMusicType(int t); |
#endif |
#endif |
/contrib/games/hydracastlelabyrinth/src/platform.c |
---|
0,0 → 1,223 |
#include "platform.h" |
#include "game.h" |
#include "PHL.h" |
#include "hero.h" |
#include <stdlib.h> |
void createPlatform(int type, int xstart, int ystart, int xend, int yend, int spd, int secret) |
{ |
int i; |
for (i = 0; i < MAX_PLATFORMS; i++) { |
if (platforms[i] == NULL) { |
Platform* p = malloc(sizeof *p); |
p->id = i; |
p->type = type; |
p->x = p->xstart = xstart; |
p->y = p->ystart = ystart; |
p->xend = xend; |
p->yend = yend; |
p->timer = 0; |
p->secret = secret; |
if (roomSecret == 1) { |
p->secret = 0; |
} |
p->visible = 1; |
if (p->secret == 1) { |
p->visible = 0; |
} |
if (type == 1) { |
p->xend = p->x + 1; |
p->yend = p->y; |
} |
p->state = 0; |
p->spd = spd; |
p->mask.circle = 0; |
p->mask.unused = 0; |
if (p->secret == 1) { |
p->mask.unused = 1; |
} |
p->mask.x = xstart; |
p->mask.y = ystart; |
p->mask.w = p->mask.h = 40; |
platforms[i] = p; |
i = MAX_PLATFORMS; |
} |
} |
} |
void platformStep(Platform* p) |
{ |
char isSolid = p->visible; |
//Megaman blocks |
if (p->type == 2) { |
int myStep = p->xend, |
maxSteps = p->yend; |
p->timer += 1; |
if (p->timer >= maxSteps * 60 + 60) { |
p->timer = 0; |
} |
//Play sound |
if (p->timer == myStep * 60) { |
PHL_PlaySound(sounds[sndPi03], CHN_SOUND); |
} |
if (p->timer > myStep * 60 && p->timer <= (myStep * 60) + 60) { |
isSolid = 1; |
p->visible = 1; |
//Blink effect |
if (p->timer > myStep * 60 + 30) { |
p->visible = p->timer % 2; |
} |
}else{ |
isSolid = 0; |
p->mask.unused = 1; |
p->visible = 0; |
//Fall off platform |
if (getHeroMask().x > p->mask.x + p->mask.w || getHeroMask().x + getHeroMask().w < p->mask.x) { |
}else if (heroy == p->y - 40 && getHeroVsp() >= 0) { |
setHeroOnground(0); |
} |
} |
} |
if (isSolid == 1) { |
p->mask.unused = 0; |
int targx = p->xend, |
targy = p->yend; |
if (p->state == 1) { |
targx = p->xstart; |
targy = p->ystart; |
} |
//Check if the player is standing on top |
int isontop = 0; |
int isabove = 0; |
if (getHeroMask().x > p->mask.x + p->mask.w || getHeroMask().x + getHeroMask().w < p->mask.x) { |
}else if (heroy == p->y - 40 && getHeroVsp() >= 0) { |
isontop = 1; |
}else if (heroy < p->y - 40) { |
isabove = 1; |
} |
//Move platform |
if (p->y != targy) { |
if (p->y < targy) { |
p->y += p->spd; |
if (isontop == 1) { |
heroy += p->spd; |
} |
}else{ |
p->y -= p->spd; |
if (isontop == 1) { |
heroy -= p->spd; |
}else{ |
p->mask.y = p->y; |
if (checkCollision(p->mask, getHeroMask()) && isabove == 1) { |
heroy = p->y - 40; |
} |
} |
} |
} |
if (p->x != targx) { |
if (p->x < targx) { |
p->x += p->spd; |
if (isontop == 1) { |
herox += p->spd; |
} |
}else{ |
p->x -= p->spd; |
if (isontop == 1) { |
herox -= p->spd; |
} |
} |
} |
if (p->x == targx && p->y == targy) { |
if (p->state == 0) { |
p->state = 1; |
}else{ |
p->state = 0; |
} |
} |
if (p->type == 0) //Moving platform |
{ |
} |
else if (p->type == 1) { //Loose block |
if (p->spd != 0) { |
p->timer -= 1; |
if (p->timer <= 0) { |
createRockSmash(p->x + 20, p->y + 20); |
if (isontop == 1) { |
setHeroOnground(0); |
} |
platformDestroy(p->id); |
/*createEffectExtra(4, p->x, p->y, -1, 0, 0); |
createEffectExtra(4, p->x, p->y, -1, 0, 1); |
createEffectExtra(4, p->x, p->y, 1, 0, 0); |
createEffectExtra(4, p->x, p->y, 1, 0, 1); |
*/ |
} |
} |
if (p->spd == 0 && isontop == 1) { |
p->spd = 2; |
p->timer = 30; |
} |
} |
//Update Mask |
p->mask.x = p->x; |
p->mask.y = p->y; |
}else{ |
//p->mask.unused = 1; |
if (p->secret == 1) { |
if (roomSecret == 1) { |
p->mask.unused = 0; |
p->visible = 1; |
p->secret = 0; |
playSecret(); |
} |
} |
} |
} |
void platformDraw(Platform* p) |
{ |
if (p->visible == 1) { |
int cropX = p->type * 40; |
if (p->type == 3) { |
cropX = 9 * 40; |
} |
PHL_DrawSurfacePart(p->x, p->y, cropX, 400, 40, 40, images[imgMisc20]); |
} |
} |
void platformDestroy(int id) |
{ |
if (platforms[id] != NULL) { |
free(platforms[id]); |
} |
platforms[id] = NULL; |
} |
/contrib/games/hydracastlelabyrinth/src/platform.h |
---|
0,0 → 1,26 |
#ifndef PLATFORM_H |
#define PLATFORM_H |
#include "collision.h" |
typedef struct { |
int id, type; //0 = moving platform |
double x, y; |
int xstart, ystart; |
int xend, yend; |
int state; |
double spd; |
int timer; |
int secret, visible; |
Mask mask; |
} Platform; |
void createPlatform(int type, int xstart, int ystart, int xend, int yend, int spd, int secret); |
void platformStep(Platform* p); |
void platformDraw(Platform* p); |
void platformDestroy(int id); |
#endif |
/contrib/games/hydracastlelabyrinth/src/qda.c |
---|
0,0 → 1,72 |
#include "qda.h" |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#if defined(__amigaos4__) || defined(__MORPHOS__) |
#include "amigaos.h" |
#endif |
QDAHeader headers[29]; |
//Load headers for each image |
//Returns: 0 = file not found | 1 = success | 2 = Invalid file |
int initQDA() |
{ |
int result = 0; |
FILE* f; |
char fullPath[80]; |
#ifdef _SDL |
strcpy(fullPath, "data/"); |
#else |
strcpy(fullPath, ""); |
#endif |
#ifdef _3DS |
strcat(fullPath, "romfs:/"); |
#endif |
strcat(fullPath, "bmp.qda"); |
if ( (f = fopen(fullPath, "rb")) ) { |
result = 1; |
//Read header data into memory |
int allHeadersSize = 0x1F5C; |
unsigned char* QDAFile = (unsigned char*)malloc(allHeadersSize); |
int tmp = fread(QDAFile, allHeadersSize, 1, f); |
(void)tmp; |
//Check if QDA file is valid |
{ |
if (QDAFile[4] == 0x51 && QDAFile[5] == 0x44 && QDAFile[6] == 0x41 && QDAFile[7] == 0x30) { |
//Load headers separately |
{ |
int numofsheets = 29; |
int headerSize = 0x10C; |
int i; |
for (i = 0; i < numofsheets; i++) { |
//memcpy(&headers[i], &QDAFile[0x100 + (i * headerSize)], sizeof(QDAHeader)); |
int offset = 256 + (i * headerSize); |
memcpy(&headers[i].offset, &QDAFile[offset], 4); |
memcpy(&headers[i].size, &QDAFile[offset + 4], 4); |
memcpy(&headers[i].bytes, &QDAFile[offset + 8], 4); |
memcpy(&headers[i].fileName, &QDAFile[offset + 12], 0x100); |
#if defined(__amigaos4__) || defined(__MORPHOS__) |
BE32(&headers[i].offset); |
BE32(&headers[i].size); |
BE32(&headers[i].bytes); |
#endif |
} |
} |
}else{ |
result = 2; |
} |
} |
//Cleanup |
free(QDAFile); |
} |
fclose(f); |
return result; |
} |
/contrib/games/hydracastlelabyrinth/src/qda.h |
---|
0,0 → 1,14 |
#ifndef QDA_H |
#define QDA_H |
typedef struct { |
unsigned long offset; |
unsigned long size; |
unsigned long bytes; |
unsigned char* fileName[256]; |
} QDAHeader; |
extern QDAHeader headers[29]; //names, offsets, and sizes of each sheet |
int initQDA(); |
#endif |
/contrib/games/hydracastlelabyrinth/src/sdl/audio.c |
---|
0,0 → 1,83 |
#include "audio.h" |
#include "../options.h" |
#include <SDL.h> |
int music_volume = 4; |
void PHL_AudioInit() |
{ |
SDL_InitSubSystem(SDL_INIT_AUDIO); |
#ifndef __MORPHOS__ |
Mix_Init(MIX_INIT_OGG); // midi is on by default |
#endif |
Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 4096); |
PHL_MusicVolume(0.25f * music_volume); |
} |
void PHL_AudioClose() |
{ |
Mix_CloseAudio(); |
#ifndef __MORPHOS__ |
Mix_Quit(); |
#endif |
} |
//Same as PHL_LoadSound, but expects a file name without extension |
PHL_Music PHL_LoadMusic(char* fname, int loop) |
{ |
PHL_Music ret; |
ret.loop = loop; |
char buff[4096]; |
strcpy(buff, "data/"); |
strcat(buff, fname); |
strcat(buff, getMusicType()?".ogg":".mid"); |
ret.snd = Mix_LoadMUS(buff); |
return ret; |
} |
PHL_Sound PHL_LoadSound(char* fname) |
{ |
char buff[4096]; |
strcpy(buff, "data/"); |
strcat(buff, fname); |
return Mix_LoadWAV(buff); |
} |
void PHL_MusicVolume(float vol) |
{ |
Mix_VolumeMusic(SDL_MIX_MAXVOLUME*vol); |
} |
void PHL_PlayMusic(PHL_Music snd) |
{ |
if(snd.snd) |
Mix_PlayMusic(snd.snd, snd.loop?-1:0); |
} |
void PHL_PlaySound(PHL_Sound snd, int channel) |
{ |
Mix_PlayChannel(channel, snd, 0); |
} |
void PHL_StopMusic() |
{ |
Mix_HaltMusic(); |
} |
void PHL_StopSound(PHL_Sound snd, int channel) |
{ |
Mix_HaltChannel(channel); |
} |
void PHL_FreeMusic(PHL_Music snd) |
{ |
if(snd.snd) |
Mix_FreeMusic(snd.snd); |
snd.snd = NULL; |
} |
void PHL_FreeSound(PHL_Sound snd) |
{ |
Mix_FreeChunk(snd); |
} |
/contrib/games/hydracastlelabyrinth/src/sdl/audio.h |
---|
0,0 → 1,35 |
#ifndef SDLAUDIO_H |
#define SDLAUDIO_H |
#include <SDL_mixer.h> |
#include <string.h> |
//#define PHL_Music Mix_Music* |
#define PHL_Sound Mix_Chunk* |
typedef struct |
{ |
int loop; |
Mix_Music* snd; |
} PHL_Music; |
extern int music_volume; |
void PHL_AudioInit(); |
void PHL_AudioClose(); |
void PHL_MusicVolume(float vol); |
PHL_Music PHL_LoadMusic(char* fname, int loop); //Same as PHL_LoadSound, but expects a file name without extension |
PHL_Sound PHL_LoadSound(char* fname); |
void PHL_PlayMusic(PHL_Music snd); |
void PHL_PlaySound(PHL_Sound snd, int channel); |
void PHL_StopMusic(); |
void PHL_StopSound(PHL_Sound snd, int channel); |
void PHL_FreeMusic(PHL_Music snd); |
void PHL_FreeSound(PHL_Sound snd); |
#endif |
/contrib/games/hydracastlelabyrinth/src/sdl/graphics.c |
---|
0,0 → 1,352 |
#include <SDL.h> |
#include "../PHL.h" |
#include "../game.h" |
#include "../qda.h" |
#include "graphics.h" |
#include "scale.h" |
#include <stdlib.h> |
#include <string.h> |
#if defined(__amigaos4__) || defined(__MORPHOS__) |
#include "../amigaos.h" |
#endif |
SDL_Surface* screen = NULL; |
SDL_Surface* drawbuffer = NULL; |
SDL_Surface* backbuffer = NULL; |
int wantFullscreen = 0; |
int screenScale = 2; |
int desktopFS = 0; |
int deltaX = 0; |
int deltaY = 0; |
int screenW = 640; |
int screenH = 480; |
int drawscreen = 0; |
int xbrz = 0; |
static uint32_t tframe; |
extern void Input_InitJoystick(); |
extern void Input_CloseJoystick(); |
int getXBRZ() |
{ |
return xbrz; |
} |
void setXBRZ(int active) |
{ |
#ifdef _KOLIBRI |
xbrz = 0; // Problems with "xBRZ". Temporarily not used. |
#else |
if(active) active = 1; |
if(xbrz==active) return; |
xbrz = active; |
// try to reload everything, but boss ressource will not be reloaded |
freeImages(); |
loadImages(); |
#endif |
} |
SDL_Color PHL_NewRGB(uint8_t r, uint8_t g, uint8_t b) |
{ |
SDL_Color ret = {.r = r, .b = b, .g = g}; |
return ret; |
} |
void PHL_GraphicsInit() |
{ |
SDL_ShowCursor(SDL_DISABLE); |
Input_InitJoystick(); |
#ifdef __MORPHOS__ |
uint32_t flags = SDL_SWSURFACE; |
#else |
uint32_t flags = SDL_HWSURFACE|SDL_DOUBLEBUF; |
#endif |
if(wantFullscreen || desktopFS) |
flags |= SDL_FULLSCREEN; |
screen = SDL_SetVideoMode((desktopFS)?0:screenW, (desktopFS)?0:screenH, 0, flags); |
if(desktopFS) |
{ |
const SDL_VideoInfo* infos = SDL_GetVideoInfo(); |
screenH = infos->current_h; |
screenW = infos->current_w; |
if(screenW/320 < screenH/240) |
screenScale = screenW/320; |
else |
screenScale = screenH/240; // automatic guess the scale |
deltaX = (screenW-320*screenScale)/2; |
deltaY = (screenH-240*screenScale)/2; |
} |
SDL_WM_SetCaption("Hydra Castle Labyrinth", NULL); |
drawbuffer = screen; |
drawscreen = 1; |
backbuffer = SDL_CreateRGBSurface(0, 320*screenScale, 240*screenScale, 32, 0, 0, 0, 0); |
tframe = SDL_GetTicks(); |
} |
void PHL_GraphicsExit() |
{ |
Input_CloseJoystick(); |
SDL_FreeSurface(backbuffer); |
SDL_Quit(); |
} |
void PHL_StartDrawing() |
{ |
PHL_ResetDrawbuffer(); |
} |
void PHL_EndDrawing() |
{ |
//implement some crude frameskiping, limited to 2 frame skip |
static int skip = 0; |
uint32_t tnext = tframe + 1000/60; |
if (SDL_GetTicks()>tnext && skip<2) { |
tframe += 1000/60; |
skip++; |
return; |
} |
// handle black borders |
if(deltaX) { |
SDL_Rect rect = {0, 0, deltaX, screenH}; |
SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, 0, 0, 0)); |
rect.x = screenW - deltaX -1; |
SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, 0, 0, 0)); |
} |
if(deltaY) { |
SDL_Rect rect = {0, 0, screenW, deltaY}; |
SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, 0, 0, 0)); |
rect.y = screenH - deltaY -1; |
SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, 0, 0, 0)); |
} |
SDL_Flip(screen); |
while((tframe = SDL_GetTicks())<tnext) |
SDL_Delay(10); |
} |
void PHL_ForceScreenUpdate() |
{ |
} |
void PHL_SetDrawbuffer(PHL_Surface surf) |
{ |
drawbuffer = surf; |
drawscreen = (surf==screen); |
} |
void PHL_ResetDrawbuffer() |
{ |
drawbuffer = screen; |
drawscreen = 1; |
} |
//PHL_RGB PHL_NewRGB(int r, int g, int b); |
void PHL_SetColorKey(PHL_Surface surf, int r, int g, int b) |
{ |
SDL_SetColorKey(surf, SDL_SRCCOLORKEY|SDL_RLEACCEL, SDL_MapRGB(surf->format, r, g, b)); |
} |
PHL_Surface PHL_NewSurface(int w, int h) |
{ |
if(getXBRZ()) |
return SDL_CreateRGBSurface(0, w, h, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); |
else |
return SDL_CreateRGBSurface(0, w, h, 32, 0, 0, 0, 0); |
} |
void PHL_FreeSurface(PHL_Surface surf) |
{ |
SDL_FreeSurface(surf); |
} |
//PHL_Surface PHL_LoadBMP(char* fname); |
PHL_Surface PHL_LoadBMP(int index) |
{ |
SDL_Surface* surf; |
FILE* f; |
if ( (f = fopen("data/bmp.qda", "rb")) ) { |
uint8_t* QDAFile = (uint8_t*)malloc(headers[index].size); |
fseek(f, headers[index].offset, SEEK_SET); |
int tmp = fread(QDAFile, 1, headers[index].size, f); |
fclose(f); |
uint16_t w, h; |
//Read data from header |
memcpy(&w, &QDAFile[18], 2); |
memcpy(&h, &QDAFile[22], 2); |
#if defined(__amigaos4__) || defined(__MORPHOS__) |
BE16(&w); BE16(&h); |
#endif |
surf = PHL_NewSurface(w * screenScale, h * screenScale); |
//surf = PHL_NewSurface(200, 200); |
//Load Palette |
int dx, dy; |
int count = 0; |
if(getXBRZ()) { |
#ifndef _KOLIBRI |
Uint32 palette[20][18]; |
for (dx = 0; dx < 20; dx++) { |
for (dy = 0; dy < 16; dy++) { |
palette[dx][dy] = 255<<24 | ((Uint32)QDAFile[54 + count])<<0 | ((Uint32)QDAFile[54 + count + 1])<<8 | ((Uint32)QDAFile[54 + count + 2])<<16; |
count += 4; |
} |
} |
Uint32* tmp = NULL; |
tmp = (Uint32*)malloc(w*h*screenScale*4); |
Uint32 transp; |
for (dx = 0; dx < w; dx++) { |
for (dy = 0; dy < h; dy++) { |
int pix = dx + w * dy; |
int px = QDAFile[1078 + pix] / 16; |
int py = QDAFile[1078 + pix] % 16; |
//Get transparency from first palette color |
if (dx == 0 && dy == 0) { |
//Darkness special case |
if (index == 27) |
transp = 255<<24; |
else |
transp = palette[0][0]; |
} |
Uint32 c = palette[px][py]; |
if(c==transp) |
c=0; |
tmp[(h-1-dy)*w+dx] = c; |
} |
} |
xbrz_scale((void*)tmp, (void*)surf->pixels, w, h, screenScale); |
free(tmp); |
#endif |
} else { |
PHL_RGB palette[20][18]; |
for (dx = 0; dx < 20; dx++) { |
for (dy = 0; dy < 16; dy++) { |
palette[dx][dy].b = QDAFile[54 + count]; |
palette[dx][dy].g = QDAFile[54 + count + 1]; |
palette[dx][dy].r = QDAFile[54 + count + 2]; |
count += 4; |
} |
} |
for (dx = 0; dx < w; dx++) { |
for (dy = 0; dy < h; dy++) { |
int pix = dx + w * dy; |
int px = QDAFile[1078 + pix] / 16; |
int py = QDAFile[1078 + pix] % 16; |
//Get transparency from first palette color |
if (dx == 0 && dy == 0) { |
//Darkness special case |
if (index == 27) { |
SDL_SetColorKey(surf, SDL_SRCCOLORKEY|SDL_RLEACCEL, SDL_MapRGB(surf->format, 0x00, 0x00, 0x00)); |
}else{ |
SDL_SetColorKey(surf, SDL_SRCCOLORKEY|SDL_RLEACCEL, SDL_MapRGB(surf->format, palette[0][0].r, palette[0][0].g, palette[0][0].b)); |
} |
} |
PHL_RGB c = palette[px][py]; |
//PHL_DrawRect(dx * 2, dy * 2, 2, 2, c); |
SDL_Rect rect = {dx * screenScale, (h-1-dy) * screenScale, screenScale, screenScale}; |
SDL_FillRect(surf, &rect, SDL_MapRGB(surf->format, c.r, c.g, c.b)); |
} |
} |
} |
free(QDAFile); |
} |
return surf; |
} |
void PHL_DrawRect(int x, int y, int w, int h, SDL_Color col) |
{ |
SDL_Rect rect = {x*screenScale/2 + (drawscreen?deltaX:0), y*screenScale/2 + (drawscreen?deltaY:0), w*screenScale/2, h*screenScale/2}; |
SDL_FillRect(drawbuffer, &rect, SDL_MapRGB(drawbuffer->format, col.r, col.g, col.b)); |
} |
void PHL_DrawSurface(double x, double y, PHL_Surface surface) |
{ |
if (quakeTimer > 0) { |
int val = quakeTimer % 4; |
if (val == 0) { |
y -= 1; |
} else if (val == 2) { |
y += 1; |
} |
} |
SDL_Rect offset; |
offset.x = x*screenScale/2 + (drawscreen?deltaX:0); |
offset.y = y*screenScale/2 + (drawscreen?deltaY:0); |
SDL_BlitSurface(surface, NULL, drawbuffer, &offset); |
} |
void PHL_DrawSurfacePart(double x, double y, int cropx, int cropy, int cropw, int croph, PHL_Surface surface) |
{ |
if (quakeTimer > 0) { |
int val = quakeTimer % 4; |
if (val == 0) { |
y -= (screenScale==1)?2:1; |
}else if (val == 2) { |
y += (screenScale==1)?2:1; |
} |
} |
SDL_Rect crop, offset; |
crop.x = cropx*screenScale/2; |
crop.y = cropy*screenScale/2; |
crop.w = cropw*screenScale/2; |
crop.h = croph*screenScale/2; |
offset.x = x*screenScale/2 + (drawscreen?deltaX:0); |
offset.y = y*screenScale/2 + (drawscreen?deltaY:0); |
SDL_BlitSurface(surface, &crop, drawbuffer, &offset); |
} |
void PHL_DrawBackground(PHL_Background back, PHL_Background fore) |
{ |
PHL_DrawSurface(0, 0, backbuffer); |
} |
void PHL_UpdateBackground(PHL_Background back, PHL_Background fore) |
{ |
PHL_SetDrawbuffer(backbuffer); |
int xx, yy; |
for (yy = 0; yy < 12; yy++) |
{ |
for (xx = 0; xx < 16; xx++) |
{ |
//Draw Background tiles |
PHL_DrawSurfacePart(xx * 40, yy * 40, back.tileX[xx][yy] * 40, back.tileY[xx][yy] * 40, 40, 40, images[imgTiles]); |
//Only draw foreground tile if not a blank tile |
if (fore.tileX[xx][yy] != 0 || fore.tileY[xx][yy] != 0) { |
PHL_DrawSurfacePart(xx * 40, yy * 40, fore.tileX[xx][yy] * 40, fore.tileY[xx][yy] * 40, 40, 40, images[imgTiles]); |
} |
} |
} |
PHL_ResetDrawbuffer(); |
} |
/contrib/games/hydracastlelabyrinth/src/sdl/graphics.h |
---|
0,0 → 1,78 |
#ifndef GRAPHICS_H |
#define GRAPHICS_H |
#include <SDL.h> |
#define PHL_Surface SDL_Surface* |
#define PHL_RGB SDL_Color |
typedef struct { |
int tileX[16][12]; |
int tileY[16][12]; |
} PHL_Background; |
/* |
typedef struct { |
unsigned int r, g, b; |
} PHL_RGB; |
*/ |
/* |
typedef struct { |
OSL_IMAGE* pxdata; |
int width; |
int height; |
PHL_RGB colorKey; |
} PHL_Surface; |
*/ |
extern PHL_Surface screen; |
extern int wantFullscreen; |
extern int screenScale; |
extern int desktopFS; |
extern int deltaX; |
extern int deltaY; |
extern int screenW; |
extern int screenH; |
SDL_Color PHL_NewRGB(uint8_t r, uint8_t g, uint8_t b); |
/* |
{ |
SDL_Color ret = {.r = r, .b = b, .g = g}; |
return ret; |
} |
*/ |
void PHL_GraphicsInit(); |
void PHL_GraphicsExit(); |
void PHL_StartDrawing(); |
void PHL_EndDrawing(); |
void PHL_ForceScreenUpdate(); |
void PHL_SetDrawbuffer(PHL_Surface surf); |
void PHL_ResetDrawbuffer(); |
//PHL_RGB PHL_NewRGB(int r, int g, int b); |
void PHL_SetColorKey(PHL_Surface surf, int r, int g, int b); |
PHL_Surface PHL_NewSurface(int w, int h); |
void PHL_FreeSurface(PHL_Surface surf); |
//PHL_Surface PHL_LoadBMP(char* fname); |
PHL_Surface PHL_LoadBMP(int index); |
void PHL_DrawRect(int x, int y, int w, int h, SDL_Color col); |
void PHL_DrawSurface(double x, double y, PHL_Surface surface); |
void PHL_DrawSurfacePart(double x, double y, int cropx, int cropy, int cropw, int croph, PHL_Surface surface); |
void PHL_DrawBackground(PHL_Background back, PHL_Background fore); |
void PHL_UpdateBackground(PHL_Background back, PHL_Background fore); |
int getXBRZ(); |
void setXBRZ(int active); |
#endif |
/contrib/games/hydracastlelabyrinth/src/sdl/input.c |
---|
0,0 → 1,218 |
#include "input.h" |
#include <SDL.h> |
Button btnUp = {0}, btnDown = {0}, btnLeft = {0}, btnRight = {0}; |
Button btnFaceUp = {0}, btnFaceDown = {0}, btnFaceLeft = {0}, btnFaceRight = {0}; |
Button btnL = {0}, btnR = {0}; |
Button btnStart = {0}, btnSelect = {0}; |
Button btnAccept = {0}, btnDecline = {0}; |
int axisX = 0, axisY = 0; |
int bUp = 0, bDown = 0, bLeft = 0, bRight = 0; |
int bFaceUp = 0, bFaceDown = 0, bFaceLeft = 0, bFaceRight = 0; |
int bR = 0, bL = 0; |
int bStart = 0, bSelect = 0; |
int bAccept = 0, bDecline = 0; |
int jUp = 0, jDown = 0, jLeft = 0, jRight = 0; |
int jFaceUp = 0, jFaceDown = 0, jFaceLeft = 0, jFaceRight = 0; |
int jR = 0, jL = 0; |
int jStart = 0, jSelect = 0; |
int jAccept = 0, jDecline = 0; |
SDL_Joystick *joy1 = NULL; |
int useJoystick = 1; |
void Input_InitJoystick() |
{ |
int n = SDL_NumJoysticks(); |
if (n) { |
joy1 = SDL_JoystickOpen(0); |
SDL_JoystickEventState(SDL_ENABLE); |
printf("Using %s\n", SDL_JoystickName(0)); |
} else { |
joy1 = NULL; |
} |
} |
void Input_CloseJoystick() |
{ |
if(joy1) |
SDL_JoystickClose(joy1); |
joy1 = NULL; |
} |
void Input_KeyEvent(SDL_Event* evt) |
{ |
int w = (evt->type==SDL_KEYDOWN)?1:0; |
switch(evt->key.keysym.sym) |
{ |
case SDLK_UP: bUp = w; break; |
case SDLK_DOWN: bDown = w; break; |
case SDLK_LEFT: bLeft = w; break; |
case SDLK_RIGHT: bRight = w; break; |
#if defined(PANDORA) || defined(PYRA) |
case SDLK_PAGEUP: bFaceUp = w; break; |
case SDLK_PAGEDOWN: bFaceDown = w; break; |
case SDLK_END: bFaceLeft = w; break; // reversing, so (B) is sword |
case SDLK_HOME: bFaceRight = w; break; |
case SDLK_RCTRL: bR = w; break; |
case SDLK_RSHIFT: bL = w; break; |
case SDLK_LCTRL: bSelect = w; break; |
case SDLK_LALT: bStart = w; break; |
#elif defined(CHIP) |
case SDLK_MINUS: bFaceUp = w; break; |
case SDLK_o: bFaceDown = w; break; |
case SDLK_0: bFaceLeft = w; break; |
case SDLK_EQUALS: bFaceRight = w; break; |
case SDLK_1: bR = w; break; |
case SDLK_2: bL = w; break; |
case SDLK_SPACE: bSelect = w; break; |
case SDLK_RETURN: bStart = w; break; |
#elif defined(BITTBOY) |
case SDLK_MINUS: bFaceUp = w; break; |
case SDLK_LCTRL: bFaceDown = w; break; // A - jump |
case SDLK_SPACE: bFaceLeft = w; break; // B - slash |
case SDLK_LALT: bFaceRight = w; break; // TA - secondary |
case SDLK_LSHIFT: bR = w; break; // TB - switch |
case SDLK_ESCAPE: bSelect = w; break; // select - menu |
case SDLK_RETURN: bStart = w; break; // start - inventory |
case SDLK_RCTRL: bSelect = w; break; // reset - menu |
#elif defined(GAMESHELL) |
case SDLK_i: bFaceUp = w; break; |
case SDLK_k: bFaceDown = w; break; //jump |
case SDLK_j: bFaceLeft = w; break; //slash |
case SDLK_u: bFaceRight = w; break; //secondary weapon |
case SDLK_SPACE: bR = w; break; //switch weapon |
// case SDLK_w: bL = w; break; //switch weapon |
// case SDLK_SPACE: bSelect = w; break; |
case SDLK_ESCAPE: bSelect = w; break; |
case SDLK_RETURN: bStart = w; break; |
#else |
case SDLK_e: bFaceUp = w; break; |
case SDLK_x: bFaceDown = w; break; |
case SDLK_s: bFaceLeft = w; break; |
case SDLK_d: bFaceRight = w; break; |
case SDLK_r: bR = w; break; |
case SDLK_w: bL = w; break; |
case SDLK_SPACE: bSelect = w; break; |
case SDLK_ESCAPE: bSelect = w; break; |
case SDLK_RETURN: bStart = w; break; |
#endif |
} |
} |
void Input_JoyAxisEvent(SDL_Event* evt) { |
if(evt->jaxis.which!=0) |
return; |
#define DEADZONE 32 |
if(evt->jaxis.axis==0) { |
int v = (evt->jaxis.value)/256; |
if(v>-DEADZONE & v<DEADZONE) axisX = 0; |
else if(v<0) axisX = -1; |
else axisX = +1; |
} |
if(evt->jaxis.axis==1) { |
int v = (evt->jaxis.value)/256; |
if(v>-DEADZONE & v<DEADZONE) axisY = 0; |
else if(v<0) axisY = -1; |
else axisY = +1; |
} |
} |
void Input_JoyEvent(SDL_Event* evt) { |
if(evt->jbutton.which!=0) |
return; |
int w = (evt->type==SDL_JOYBUTTONDOWN)?1:0; |
/* XBox 360 based mapping here, |
(would be better to switch to SDL2.0) |
btn SDL1.2 SDL2.0 |
--------------------------- |
A 0 10 |
B 1 11 |
X 2 12 |
Y 3 13 |
Home N/A 14 |
LB 4 8 |
RB 5 9 |
LT N/A N/A (axis) |
RT N/A N/A (axis) |
Select 6 5 |
Start 7 4 |
L3 9 6 |
R3 10 7 |
DPad Up N/A 0 |
DPad Down N/A 1 |
DPad Left N/A 2 |
DPad Right N/A 3 |
*/ |
switch(evt->jbutton.button) |
{ |
case 0: jFaceDown = w; break; |
case 1: jFaceLeft = w; break; |
case 2: jFaceRight = w; break; |
case 3: jFaceUp = w; break; |
case 4: jL = w; break; |
case 5: jR = w; break; |
case 6: jSelect = w; break; |
case 7: jStart = w; break; |
/*case 12:jUp = w; break; |
case 13:jDown = w; break; |
case 14:jLeft = w; break; |
case 15:jRight = w; break;*/ |
} |
} |
void Input_JoyHatEvent(SDL_Event* evt) { |
if(evt->jhat.which!=0) |
return; |
if(evt->jhat.hat!=0) |
return; |
int v=evt->jhat.value; |
jUp = v&SDL_HAT_UP; |
jDown = v&SDL_HAT_DOWN; |
jLeft = v&SDL_HAT_LEFT; |
jRight = v&SDL_HAT_RIGHT; |
} |
void updateKey(Button* btn, int state) |
{ |
if (state) { |
if (btn->held == 1) { |
btn->pressed = 0; |
}else{ |
btn->pressed = 1; |
} |
btn->held = 1; |
btn->released = 0; |
}else{ |
if (btn->held == 1) { |
btn->released = 1; |
}else{ |
btn->released = 0; |
} |
btn->held = 0; |
btn->pressed = 0; |
} |
} |
void PHL_ScanInput() |
{ |
updateKey(&btnUp, bUp|jUp|(axisY<0)); |
updateKey(&btnDown, bDown|jDown|(axisY>0)); |
updateKey(&btnLeft, bLeft|jLeft|(axisX<0)); |
updateKey(&btnRight, bRight|jRight|(axisX>0)); |
updateKey(&btnStart, bStart|jStart); |
updateKey(&btnSelect, bSelect|jSelect); |
updateKey(&btnL, bL|jL); |
updateKey(&btnR, bR|jR); |
updateKey(&btnFaceLeft, bFaceLeft|jFaceLeft); |
updateKey(&btnFaceDown, bFaceDown|jFaceDown); |
updateKey(&btnFaceRight, bFaceRight|jFaceRight); |
updateKey(&btnAccept, bFaceLeft|jFaceLeft); |
updateKey(&btnDecline, bFaceDown|jFaceDown); |
} |
/contrib/games/hydracastlelabyrinth/src/sdl/input.h |
---|
0,0 → 1,22 |
#ifndef INPUT_H |
#define INPUT_H |
#include <SDL.h> |
typedef struct { |
int pressed, |
held, |
released; |
} Button; |
extern Button btnUp, btnDown, btnLeft, btnRight; |
extern Button btnFaceUp, btnFaceDown, btnFaceLeft, btnFaceRight; |
extern Button btnL, btnR; |
extern Button btnStart, btnSelect; |
extern Button btnAccept, btnDecline; |
extern int axisX, axisY; |
extern int useJoystick; |
void PHL_ScanInput(); |
#endif |
/contrib/games/hydracastlelabyrinth/src/sdl/joystick_stub.c |
---|
0,0 → 1,153 |
/// JOYSTICK STUB FOR Wolfenstein 3D port to KolibriOS |
/// Ported by maxcodehack and turbocat2001 |
/* Set up for C function definitions, even when using C++ */ |
#ifdef __cplusplus |
extern "C" { |
#endif |
/** @file SDL_joystick.h |
* @note In order to use these functions, SDL_Init() must have been called |
* with the SDL_INIT_JOYSTICK flag. This causes SDL to scan the system |
* for joysticks, and load appropriate drivers. |
*/ |
/** The joystick structure used to identify an SDL joystick */ |
struct _SDL_Joystick; |
typedef struct _SDL_Joystick SDL_Joystick; |
/* Function prototypes */ |
/** |
* Count the number of joysticks attached to the system |
*/ |
int SDL_NumJoysticks(void){}; |
/** |
* Get the implementation dependent name of a joystick. |
* |
* This can be called before any joysticks are opened. |
* If no name can be found, this function returns NULL. |
*/ |
const char * SDL_JoystickName(int device_index){}; |
/** |
* Open a joystick for use. |
* |
* @param[in] device_index |
* The index passed as an argument refers to |
* the N'th joystick on the system. This index is the value which will |
* identify this joystick in future joystick events. |
* |
* @return This function returns a joystick identifier, or NULL if an error occurred. |
*/ |
SDL_Joystick * SDL_JoystickOpen(int device_index){}; |
/** |
* Returns 1 if the joystick has been opened, or 0 if it has not. |
*/ |
int SDL_JoystickOpened(int device_index){}; |
/** |
* Get the device index of an opened joystick. |
*/ |
int SDL_JoystickIndex(SDL_Joystick *joystick){}; |
/** |
* Get the number of general axis controls on a joystick |
*/ |
int SDL_JoystickNumAxes(SDL_Joystick *joystick){}; |
/** |
* Get the number of trackballs on a joystick |
* |
* Joystick trackballs have only relative motion events associated |
* with them and their state cannot be polled. |
*/ |
int SDL_JoystickNumBalls(SDL_Joystick *joystick){}; |
/** |
* Get the number of POV hats on a joystick |
*/ |
int SDL_JoystickNumHats(SDL_Joystick *joystick){}; |
/** |
* Get the number of buttons on a joystick |
*/ |
int SDL_JoystickNumButtons(SDL_Joystick *joystick){}; |
/** |
* Update the current state of the open joysticks. |
* |
* This is called automatically by the event loop if any joystick |
* events are enabled. |
*/ |
void SDL_JoystickUpdate(void){}; |
/** |
* Enable/disable joystick event polling. |
* |
* If joystick events are disabled, you must call SDL_JoystickUpdate() |
* yourself and check the state of the joystick when you want joystick |
* information. |
* |
* @param[in] state The state can be one of SDL_QUERY, SDL_ENABLE or SDL_IGNORE. |
*/ |
int SDL_JoystickEventState(int state){}; |
/** |
* Get the current state of an axis control on a joystick |
* |
* @param[in] axis The axis indices start at index 0. |
* |
* @return The state is a value ranging from -32768 to 32767. |
*/ |
int SDL_JoystickGetAxis(SDL_Joystick *joystick, int axis){}; |
/** |
* @name Hat Positions |
* The return value of SDL_JoystickGetHat() is one of the following positions: |
*/ |
/*@{*/ |
#define SDL_HAT_CENTERED 0x00 |
#define SDL_HAT_UP 0x01 |
#define SDL_HAT_RIGHT 0x02 |
#define SDL_HAT_DOWN 0x04 |
#define SDL_HAT_LEFT 0x08 |
#define SDL_HAT_RIGHTUP (SDL_HAT_RIGHT|SDL_HAT_UP) |
#define SDL_HAT_RIGHTDOWN (SDL_HAT_RIGHT|SDL_HAT_DOWN) |
#define SDL_HAT_LEFTUP (SDL_HAT_LEFT|SDL_HAT_UP) |
#define SDL_HAT_LEFTDOWN (SDL_HAT_LEFT|SDL_HAT_DOWN) |
/*@}*/ |
/** |
* Get the current state of a POV hat on a joystick |
* |
* @param[in] hat The hat indices start at index 0. |
*/ |
int SDL_JoystickGetHat(SDL_Joystick *joystick, int hat){}; |
/** |
* Get the ball axis change since the last poll |
* |
* @param[in] ball The ball indices start at index 0. |
* |
* @return This returns 0, or -1 if you passed it invalid parameters. |
*/ |
int SDL_JoystickGetBall(SDL_Joystick *joystick, int ball, int *dx, int *dy){}; |
/** |
* Get the current state of a button on a joystick |
* |
* @param[in] button The button indices start at index 0. |
*/ |
int SDL_JoystickGetButton(SDL_Joystick *joystick, int button){}; |
/** |
* Close a joystick previously opened with SDL_JoystickOpen() |
*/ |
void SDL_JoystickClose(SDL_Joystick *joystick){}; |
/* Ends C function definitions when using C++ */ |
#ifdef __cplusplus |
} |
#endif |
/contrib/games/hydracastlelabyrinth/src/sdl/scale.cpp |
---|
0,0 → 1,14 |
#include "scale.h" |
#include "../xBRZ/xbrz.h" |
#include <string.h> |
void xbrz_scale(void* src, void* dst, int width, int height, int scale) |
{ |
if(scale==1) { |
memcpy(dst, src, width*height*4); |
} else if (scale>1 && scale <= 6) { |
xbrz::scale(scale, (const uint32_t*)src, (uint32_t*)dst, width, height, xbrz::ColorFormat::ARGB); |
} else { |
xbrz::nearestNeighborScale((const uint32_t*)src, width, height, (uint32_t*)dst, width*scale, height*scale); |
} |
} |
/contrib/games/hydracastlelabyrinth/src/sdl/scale.h |
---|
0,0 → 1,14 |
#ifndef _SCALE_H_ |
#define _SCALE_H_ |
#ifdef __cplusplus |
extern "C" { |
#endif |
void xbrz_scale(void* src, void* dst, int width, int height, int scale); |
#ifdef __cplusplus |
} |
#endif |
#endif //_SCALE_H_ |
/contrib/games/hydracastlelabyrinth/src/sdl/system.c |
---|
0,0 → 1,56 |
#include <SDL.h> |
#include "system.h" |
char quitGame = 0; |
void Input_KeyEvent(SDL_Event* evt); |
void Input_JoyEvent(SDL_Event* evt); |
void Input_JoyAxisEvent(SDL_Event* evt); |
void Input_JoyHatEvent(SDL_Event* evt); |
int PHL_MainLoop() |
{ |
SDL_Event evt; |
while(SDL_PollEvent(&evt)) |
{ |
switch(evt.type) |
{ |
case SDL_QUIT: |
quitGame = 1; |
return 0; |
case SDL_KEYDOWN: |
case SDL_KEYUP: |
Input_KeyEvent(&evt); |
break; |
case SDL_JOYAXISMOTION: |
Input_JoyAxisEvent(&evt); |
break; |
case SDL_JOYHATMOTION: |
Input_JoyHatEvent(&evt); |
break; |
case SDL_JOYBUTTONDOWN: |
case SDL_JOYBUTTONUP: |
Input_JoyEvent(&evt); |
break; |
} |
} |
if (quitGame == 1) |
{ |
return 0; |
} |
return 1; |
} |
void PHL_ConsoleInit() |
{ |
} |
void PHL_GameQuit() |
{ |
quitGame = 1; |
} |
void PHL_ErrorScreen(char* message) |
{ |
fprintf(stderr, "%s\n", message); |
} |
/contrib/games/hydracastlelabyrinth/src/sdl/system.h |
---|
0,0 → 1,15 |
#ifndef SYSTEM_H |
#define SYSTEM_H |
#include <SDL.h> |
#include "../PHL.h" |
extern char quitGame; |
int PHL_MainLoop(); |
void PHL_ConsoleInit(); |
void PHL_GameQuit(); |
void PHL_ErrorScreen(char* message); |
#endif |
/contrib/games/hydracastlelabyrinth/src/stagedata.c |
---|
0,0 → 1,93 |
#include "stagedata.h" |
int stage[9][96] = { |
//Overworld |
{ -1, -1, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, |
-1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, |
-1, -1, 36, 37, 38, 39, 40, 41, 42, 43, -1, -1, |
-1, -1, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, |
-1, -1, 52, 53, 54, 55, 56, 57, 58, 59, -1, -1, |
-1, -1, 60, 61, 62, 63, 64, 65, 66, 67, -1, -1, |
-1, -1, 68, 69, 70, 71, 72, 73, 74, 75, -1, -1, |
-1, -1, 76, 77, 78, 79, 80, 81, 82, 83, -1, -1 }, |
//Level 1 |
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, 84, 85, 86, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, 87, 88, 89, 90, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, 91, 92, 93, 94, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, |
//Level 2 |
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, 95, -1, -1, -1, 96, -1, -1, -1, -1, |
-1, -1, -1, 97, 98, 99, 100, 101, -1, -1, -1, -1, |
-1, -1, -1, 102, 103, 104, 105, 106, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, |
//Level 3 |
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, 108, -1, 109, 110, 111, -1, 112, -1, -1, -1, |
-1, -1, 113, 114, 115, 107, 116, 117, 118, -1, -1, -1, |
-1, -1, -1, -1, 119, 120, 121, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, 122, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, |
//Level 4 |
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, 129, 130, 131, 132, -1, 135, 136, -1, |
-1, -1, 123, 124, 125, 126, 127, 128, 133, 134, -1, -1, |
-1, -1, 137, 138, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, 139, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, 140, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, |
//Level 5 |
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, 159, -1, 162, -1, -1, -1, -1, -1, -1, |
-1, -1, 158, 160, 161, 163, 164, -1, -1, -1, -1, -1, |
-1, -1, -1, 165, 166, 167, -1, -1, -1, -1, -1, -1, |
-1, -1, 168, 169, 170, 171, 172, -1, -1, -1, -1, -1, |
-1, -1, -1, 173, -1, 174, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, |
//Level 6 |
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, 156, 157, -1, -1, -1, |
-1, -1, -1, -1, 149, 150, 154, 155, -1, -1, -1, -1, |
-1, -1, 151, -1, 152, 153, -1, -1, -1, -1, -1, -1, |
-1, -1, 141, 142, 143, 144, 145, 146, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, 147, 148, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, |
//Level 7 |
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, 188, 189, 190, 191, -1, -1, -1, -1, -1, |
-1, -1, -1, 182, 183, 184, 185, -1, -1, -1, -1, -1, |
-1, 186, 175, 176, 177, 178, 179, 180, 181, -1, -1, -1, |
-1, 187, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, |
//Level 8 |
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, 192, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, 195, 194, 193, 198, 199, -1, -1, -1, -1, |
-1, -1, -1, 196, 197, 202, 201, 200, -1, -1, -1, -1, |
-1, -1, -1, 205, 204, 203, 208, 209, -1, -1, -1, -1, |
-1, -1, -1, 206, 207, 212, 211, 210, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, 213, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, } |
}; |
/contrib/games/hydracastlelabyrinth/src/stagedata.h |
---|
0,0 → 1,6 |
#ifndef STAGEDATA_H |
#define STAGEDATA_H |
extern int stage[9][96]; |
#endif |
/contrib/games/hydracastlelabyrinth/src/template.html |
---|
0,0 → 1,79 |
<!doctype html> |
<html lang="en-us"> |
<head> |
<meta charset="utf-8"> |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
<title>Hydra Castle Labyrinth</title> |
<style type="text/css"> |
html, body { |
margin: 0; |
} |
.emscripten { |
width: 100%; |
height: 100%; |
display: flex; |
position: absolute; |
align-items: center; |
justify-content: center; |
} |
.game { |
width: auto; |
height: 100%; |
} |
.portrait{ |
width: 100%; |
height: auto; |
} |
.loading { |
position: absolute; |
} |
.game[width] + .loading { |
display: none; |
} |
</style> |
</head> |
<body> |
<div class="emscripten"> |
<canvas class="game portrait" oncontextmenu="event.preventDefault()"></canvas> |
<div class="loading">Loading...</div> |
</div> |
<script type="text/javascript"> |
const $game = document.querySelector('.game'); |
const widthToHeight = 640 / 480; |
const resize = () => { |
if(window.innerWidth / window.innerHeight > widthToHeight === $game.classList.contains('portrait')) { |
$game.classList.toggle('portrait'); |
} |
} |
var Module = { |
print(text) { |
console.log(Array.prototype.slice.call(arguments).join(' ')); |
}, |
printErr() { |
console.error(Array.prototype.slice.call(arguments).join(' ')); |
}, |
canvas: $game |
}; |
window.addEventListener('resize', resize, false); |
resize(); |
// Work-around chromium autoplay policy |
// https://github.com/emscripten-core/emscripten/issues/6511 |
function resumeAudio(e) { |
if (typeof Module === 'undefined' |
|| typeof Module.SDL2 == 'undefined' |
|| typeof Module.SDL2.audioContext == 'undefined') |
return; |
if (Module.SDL2.audioContext.state == 'suspended') { |
Module.SDL2.audioContext.resume(); |
} |
if (Module.SDL2.audioContext.state == 'running') { |
$game.removeEventListener('click', resumeAudio); |
document.removeEventListener('keydown', resumeAudio); |
} |
} |
$game.addEventListener('click', resumeAudio); |
document.addEventListener('keydown', resumeAudio); |
</script> |
{{{ SCRIPT }}} |
</body> |
</html> |
/contrib/games/hydracastlelabyrinth/src/text.c |
---|
0,0 → 1,213 |
#include "text.h" |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include "PHL.h" |
#include "game.h" |
char gameLanguage; |
Message* saving; |
Message* saveError[3]; |
Message* itemName[41]; |
Message* found; |
Message* itemDescription[28]; |
Message* dungeon[8]; |
void loadMessage(Message* m, FILE* f); |
void trimMessage(Message* m); |
void textInit() |
{ |
gameLanguage = JAPANESE; |
saving = (Message*)malloc(sizeof(Message)); |
int i; |
for (i = 0; i < 3; i++) { |
saveError[i] = (Message*)malloc(sizeof(Message)); |
} |
for (i = 0; i < 8; i++) { |
dungeon[i] = (Message*)malloc(sizeof(Message)); |
} |
for (i = 0; i < 41; i++) { |
itemName[i] = (Message*)malloc(sizeof(Message)); |
} |
found = (Message*)malloc(sizeof(Message)); |
for (i = 0; i < 28; i++) { |
itemDescription[i] = (Message*)malloc(sizeof(Message)); |
} |
//printf("\nText init"); |
} |
void textFree() |
{ |
free(saving); |
int i; |
for (i = 0; i < 3; i++) { |
free(saveError[i]); |
} |
for (i = 0; i < 8; i++) { |
free(dungeon[i]); |
} |
for (i = 0; i < 41; i++) { |
free(itemName[i]); |
} |
free(found); |
for (i = 0; i < 28; i++) { |
free(itemDescription[i]); |
} |
} |
void loadText() |
{ |
FILE* f; |
char fullPath[30]; |
#ifdef _3DS |
strcpy(fullPath, "romfs:/"); |
#elif defined(_SDL) |
strcpy(fullPath, "data/"); |
#else |
strcpy(fullPath, "romfs/"); |
#endif |
if (gameLanguage == ENGLISH) { |
strcat(fullPath, "en.dat"); |
}else{ |
strcat(fullPath, "jp.dat"); |
} |
//printf("\n"); |
//printf(fullPath); |
if ( (f = fopen(fullPath, "rb")) ) |
{ |
//printf("\ntext.dat found"); |
//Load saving message |
loadMessage(saving, f); |
//printf("\n%d", saving->length); |
//Load save error message |
int i; |
for (i = 0; i < 3; i++) { |
loadMessage(saveError[i], f); |
} |
//Load dungeon intros |
for (i = 0; i < 8; i++) { |
loadMessage(dungeon[i], f); |
} |
//Load item names |
for (i = 0; i < 41; i++) { |
loadMessage(itemName[i], f); |
} |
//Found! |
loadMessage(found, f); |
//Load item descriptions |
for (i = 0; i < 28; i++) { |
loadMessage(itemDescription[i], f); |
} |
}else{ |
//printf("\ntext.dat was not found"); |
} |
fclose(f); |
} |
//Returns the next character X position |
int drawText(Message* m, int x, int y) |
{ |
int textw = 20; |
int texth = 32; |
int dx = x; |
int i; |
for (i = 0; i < m->length; i++) { |
PHL_DrawSurfacePart(dx, y, m->x[i] * textw, m->y[i] * texth, textw, texth, images[imgFontKana]); |
dx += textw - 2; |
} |
return dx; |
} |
int drawCharacter(int cx, int cy, int x, int y) |
{ |
int textw = 20; |
int texth = 32; |
PHL_DrawSurfacePart(x, y, cx * textw, cy * texth, textw, texth, images[imgFontKana]); |
return x + textw - 2; |
} |
void drawTextCentered(Message* m, int x, int y) |
{ |
int textw = 20; |
int texth = 32; |
x -= (m->length / 2) * (textw - 2); |
int i; |
for (i = 0; i < m->length; i++) { |
PHL_DrawSurfacePart(x + (i * (textw - 2)), y, m->x[i] * textw, m->y[i] * texth, textw, texth, images[imgFontKana]); |
} |
} |
void setLanguage(char lan) |
{ |
gameLanguage = lan; |
loadText(); |
} |
char getLanguage() |
{ |
return gameLanguage; |
} |
void loadMessage(Message* m, FILE* f) |
{ |
unsigned char* buffer = (unsigned char*)malloc(sizeof(unsigned char) * 64); |
int cnt = fread(buffer, 1, 64, f); |
int i; |
for (i = 0; i < cnt; i+=2) { |
m->x[i/2] = buffer[i]; |
m->y[i/2] = buffer[i+1]; |
} |
trimMessage(m); |
free(buffer); |
} |
void trimMessage(Message* m) |
{ |
m->length = 32; |
int i; |
for (i = 31; i >= 0; i--) |
{ |
if (m->x[i] == 0 && m->y[i] == 0) { |
m->length -= 1; |
}else{ |
i = -1; |
} |
} |
} |
/contrib/games/hydracastlelabyrinth/src/text.h |
---|
0,0 → 1,34 |
#ifndef TEXT_HEADER |
#define TEXT_HEADER |
#define JAPANESE 0 |
#define ENGLISH 1 |
extern char gameLanguage; |
typedef struct { |
unsigned char x[32]; |
unsigned char y[32]; |
char length; |
} Message; |
extern Message* saving; |
extern Message* saveError[3]; |
extern Message* itemName[41]; |
extern Message* found; |
extern Message* itemDescription[28]; |
extern Message* dungeon[8]; |
void textInit(); |
void textFree(); |
void loadText(); |
int drawText(Message* m, int x, int y); |
int drawCharacter(int cx, int cy, int x, int y); |
void drawTextCentered(Message* m, int x, int y); |
void setLanguage(char lan); |
char getLanguage(); |
#endif |
/contrib/games/hydracastlelabyrinth/src/titlescreen.c |
---|
0,0 → 1,142 |
#include "titlescreen.h" |
#include "game.h" |
#include <stdio.h> |
#include "text.h" |
int tempsave = 0; |
int cursor = 0; |
void titleScreenSetup(); |
int titleScreenStep(); |
void titleScreenDraw(); |
#ifdef EMSCRIPTEN |
int titleEMStep() |
{ |
PHL_MainLoop(); |
//Get input |
PHL_ScanInput(); |
//Titlescreen step |
int result = titleScreenStep(); |
//Draw titlescreen |
PHL_StartDrawing(); |
titleScreenDraw(); |
if (result != -1) |
PHL_DrawRect(0, 0, 640, 480, PHL_NewRGB(0, 0, 0)); |
PHL_EndDrawing(); |
return result; |
} |
#endif |
int titleScreen() |
{ |
titleScreenSetup(); |
char loop = 1; |
int result = -1; |
while (PHL_MainLoop() && loop == 1) |
{ |
//__asm__("int3"); |
//Get input |
PHL_ScanInput(); |
//Titlescreen step |
result = titleScreenStep(); |
//Draw titlescreen |
PHL_StartDrawing(); |
titleScreenDraw(); |
if (result != -1) { |
loop = 0; |
//Force screen to black |
PHL_DrawRect(0, 0, 640, 480, PHL_NewRGB(0, 0, 0)); |
} |
PHL_EndDrawing(); |
} |
return result; |
} |
void titleScreenSetup() |
{ |
cursor = 0; |
//Move cursor if save file exists |
if ( fileExists(savemap) ) { |
cursor = 1; |
} |
//Check if temp save file exists |
tempsave = 0; |
if ( fileExists(savename) ) { |
#ifndef EMSCRIPTEN |
tempsave = 1; |
#endif |
cursor = 1; |
} |
} |
int titleScreenStep() |
{ |
//Move cursor |
if (btnDown.pressed == 1 || btnSelect.pressed == 1) { |
cursor += 1; |
if (cursor > 3) { |
cursor = 0; |
} |
PHL_PlaySound(sounds[sndPi01], 1); |
} |
if (btnUp.pressed == 1) { |
cursor -= 1; |
if (cursor < 0) { |
cursor = 3; |
} |
PHL_PlaySound(sounds[sndPi01], 1); |
} |
//Selection |
if (btnAccept.pressed == 1 || btnStart.pressed == 1) { |
PHL_PlaySound(sounds[sndOk], 1); |
return cursor; |
} |
return -1; |
} |
void titleScreenDraw() |
{ |
//Blackdrop |
PHL_DrawRect(0, 0, 640, 480, PHL_NewRGB(0, 0, 0)); |
if (tempsave == 0) { |
//Title image |
PHL_DrawSurfacePart(168, 72, 0, 0, 304, 168, images[imgTitle01]); |
}else{ |
//Save error message |
drawTextCentered(saveError[0], 320, 80); |
drawTextCentered(saveError[1], 320, 80 + 50); |
drawTextCentered(saveError[2], 320, 80 + 96); |
} |
//Cursor |
PHL_DrawSurfacePart(228, 264 + (cursor * 32), 4, 176, 184, 32, images[imgTitle01]); |
//Text |
PHL_DrawTextBold("NEW GAME", 256, 272, YELLOW); |
PHL_DrawTextBold("LOAD GAME", 248, 304, YELLOW); |
PHL_DrawTextBold("OPTIONS", 264, 336, YELLOW); |
PHL_DrawTextBold("EXIT", 288, 368, YELLOW); |
PHL_DrawTextBold("(C) 2011 E.HASHIMOTO", 160, 410, WHITE); |
PHL_DrawTextBold("GPL2 PTITSEB", 224, 442, WHITE); |
} |
/contrib/games/hydracastlelabyrinth/src/titlescreen.h |
---|
0,0 → 1,11 |
#ifndef TITLESCREEN_H |
#define TITLESCREEN_H |
#ifdef EMSCRIPTEN |
void titleScreenSetup(); |
int titleEMStep(); |
#else |
int titleScreen(); |
#endif |
#endif |
/contrib/games/hydracastlelabyrinth/src/weapon.c |
---|
0,0 → 1,602 |
#include "weapon.h" |
#include <stdio.h> |
#include <stdlib.h> |
#include <math.h> |
#include "hero.h" |
#include "PHL.h" |
#include "game.h" |
#include "object.h" |
void updateWeaponMask(Weapon* w); |
void addWeapon(int type, int x, int y) |
{ |
if (heroAmmo > 0 || type == SWORD) { |
int i, weaponcount = 0; |
//Count |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] != NULL) { |
if (weapons[i]->type != SWORD) { |
weaponcount += 1; |
} |
} |
} |
if (type == BOMB) { //Bombs have one lower limit |
weaponcount += 1; |
} |
if (type == SWORD || weaponcount < (2 + hasItem[15])) { //3 projectiles if have green scroll |
if (type != SWORD) { |
PHL_PlaySound(sounds[sndShot01], CHN_WEAPONS); |
} |
for (i = 0; i < MAX_WEAPONS; i++) { |
if (weapons[i] == NULL) { |
Weapon* w = malloc(sizeof *w); |
w->id = i; |
w->type = type; |
w->x = x; |
w->y = y; |
w->hsp = 0; |
w->vsp = 0; |
w->grav = 0; |
w->imageIndex = 0; |
w->power = 1; |
w->timer = 0; |
w->state = 0; |
w->cooldown = 0; |
w->hitflag = 0; |
w->dir = getHeroDirection(); |
w->weaponMask.circle = 0; |
w->weaponMask.unused = 0; |
w->weaponMask.x = 0; |
w->weaponMask.y = 0; |
w->weaponMask.w = 10; |
w->weaponMask.h = 10; |
if (w->type == SWORD) |
{ |
w->weaponMask.unused = 1; |
}else if (w->type == ARROW) |
{ |
w->hsp = 8 * getHeroDirection(); |
w->weaponMask.y += 16; |
w->weaponMask.w = 32; |
w->weaponMask.h = 6; |
}else if (w->type == AXE) |
{ |
w->hsp = 2 * getHeroDirection(); |
w->vsp = -6; |
w->grav = 0.2; |
w->weaponMask.w = w->weaponMask.h = 24; |
w->y += (40 - getHeroMask().h) - ((40 - w->weaponMask.h) / 2); |
w->weaponMask.x = w->x + ((40 - w->weaponMask.w) / 2); |
w->weaponMask.y = w->y + ((40 - w->weaponMask.h) / 2); |
}else if (w->type == BOOMERANG) |
{ |
w->x += 20; |
w->y += 20; |
updateWeaponMask(w); |
w->weaponMask.circle = 1; |
w->weaponMask.w = 16; |
w->hsp = 6 * getHeroDirection(); |
w->vsp = getHeroDirection(); //Vsp is used for starting direction |
w->timer = 120; |
}else if (w->type == FIREBALL) |
{ |
w->vsp = -2; |
w->grav = 0.1; |
w->hsp = 2 * getHeroDirection(); |
w->x += 20; |
w->y += 20; |
w->weaponMask.circle = 1; |
w->weaponMask.w = 15; |
updateWeaponMask(w); |
Mask tempMask; |
tempMask.circle = tempMask.unused = 0; |
tempMask.y = w->y - w->weaponMask.w; |
tempMask.x = w->x - w->weaponMask.w; |
tempMask.w = tempMask.h = w->weaponMask.w * 2; |
PHL_Rect collide = getTileCollision(1, tempMask); |
if (collide.x == -1) { |
collide = getTileCollision(3, tempMask); |
} |
if (collide.x != -1) { |
w->y = collide.y + 40 + w->weaponMask.w; |
} |
}else if (w->type == BOMB) |
{ |
w->dir = 0; |
w->vsp = -2; |
w->grav = 0.1; |
w->hsp = getHeroDirection(); |
w->weaponMask.unused = 1; |
Mask tempMask; |
tempMask.y = w->y + 8; |
tempMask.x = w->x + 8; |
tempMask.w = tempMask.h = 24; |
tempMask.circle = tempMask.unused = 0; |
PHL_Rect collide = getTileCollision(1, tempMask); |
if (collide.x == -1) { |
collide = getTileCollision(3, tempMask); |
} |
if (collide.x != -1) { |
w->y = collide.y + 40 - 8; |
} |
} |
updateWeaponMask(w); |
weapons[i] = w; |
i = MAX_WEAPONS; |
if (type != SWORD) { |
heroAmmo -= 1; |
} |
} |
} |
} |
} |
} |
//When a weapon lands a hit |
void weaponHit(Weapon* w) |
{ |
//w->cooldown = 15; |
w->hitflag = 1; |
if (w->type == SWORD) { |
createEffect(1, w->weaponMask.x + (w->weaponMask.w / 2) - 10 + (rand() % 20) - 10, w->weaponMask.y + (w->weaponMask.h / 2) - 10 + (rand() % 20) - 10); |
PHL_PlaySound(sounds[sndHit02], CHN_WEAPONS); |
}else if (w->type == ARROW || w->type == AXE) { |
PHL_PlaySound(sounds[sndPi02], CHN_WEAPONS); |
createEffect(1, w->x, w->y); |
weaponDestroy(w->id); |
}else if (w->type == BOOMERANG) { |
PHL_PlaySound(sounds[sndPi02], CHN_WEAPONS); |
createEffect(1, w->x, w->y - 40 + (rand() % 40) + 1); |
}else if (w->type == FIREBALL) { |
PHL_PlaySound(sounds[sndPi02], CHN_WEAPONS); |
createEffect(1, w->x - 20, w->y - 20); |
//weaponDestroy(w->id); |
}else if (w->type == BOMB) { |
} |
} |
void weaponStep(Weapon* w) |
{ |
char dead = 0; |
if (w->cooldown > 0) { |
w->cooldown -= 1; |
} |
if (w->hitflag == 1) { |
w->hitflag = 0; |
w->cooldown = 15; |
} |
if (w->type == SWORD) |
{ |
double imgind = getHeroImageIndex(); |
if ((getHeroState() != 1 && getHeroState() != 5) || imgind >= 4) { //Not slashing |
dead = 1; |
} |
w->x = herox; |
w->y = heroy; |
updateWeaponMask(w); |
}else if (w->type == ARROW) |
{ |
//Yes, this does have to be done before movement |
//Destroy if out of view or collides with wall |
if (w->x > 640 || w->x + 40 < 0 || checkTileCollision(1, w->weaponMask) == 1) { |
weaponHit(w); |
} |
w->x += w->hsp; |
updateWeaponMask(w); |
}else if (w->type == AXE) |
{ |
w->y += w->vsp; |
w->vsp += w->grav; |
updateWeaponMask(w); |
PHL_Rect collide = getTileCollisionWeapon(1, w->weaponMask); |
if (collide.x == -1) { |
collide = getTileCollision(3, w->weaponMask); |
} |
if (collide.x != -1) { |
if (w->vsp <= 0) { |
w->y = collide.y + 40 - ((40 - w->weaponMask.h) / 2); |
w->vsp = 0; |
}else{ |
weaponHit(w); |
return; |
} |
} |
w->x += w->hsp; |
updateWeaponMask(w); |
collide = getTileCollisionWeapon(1, w->weaponMask); |
if (collide.x != -1) { |
if (w->hsp > 0) { |
w->x = collide.x - 40 + ((40 - w->weaponMask.w) / 2); |
}else{ |
w->x = collide.x + 40 - ((40 - w->weaponMask.w) / 2); |
} |
} |
//Animate |
{ |
w->imageIndex += 0.33; |
if (w->imageIndex >= 8) { |
w->imageIndex -= 8; |
} |
} |
if (w->x > 640 || w->x + 40 < 0 || w->y > 520) { |
dead = 1; |
} |
}else if (w->type == BOOMERANG) |
{ |
w->x += w->hsp; |
w->hsp -= 0.125 * (w->vsp); //Vsp is recycled to be the starting direction |
if (w->hsp >= 6) { |
w->hsp = 6; |
} |
if (w->hsp <= -6) { |
w->hsp = -6; |
} |
w->dir = 1; |
if (w->hsp < 0) { |
w->dir = -1; |
} |
w->y = heroy + 20; |
updateWeaponMask(w); |
w->imageIndex -= (0.33 * w->vsp); |
if (w->imageIndex < 0) { |
w->imageIndex += 8; |
} |
if (w->imageIndex >= 8) { |
w->imageIndex -= 8; |
} |
w->timer -= 1; |
if (w->timer <= 0) { |
createEffect(5, w->x, w->y); |
dead = 1; |
} |
}else if (w->type == FIREBALL) |
{ |
//Move vertically |
w->y += w->vsp; |
w->vsp += w->grav; |
Mask tempMask; |
tempMask.circle = tempMask.unused = 0; |
tempMask.y = w->y - w->weaponMask.w; |
tempMask.w = tempMask.h = w->weaponMask.w * 2; |
tempMask.x = w->x - w->weaponMask.w; |
//Check vertical collision |
PHL_Rect collide = getTileCollisionWeapon(1, tempMask); |
if (collide.x == -1) { |
collide = getTileCollisionWeapon(3, tempMask); |
} |
if (collide.x != -1) { |
if (w->vsp <= 0) { |
w->y = collide.y + 40 + w->weaponMask.w; |
w->vsp = 0; |
}else{ |
w->y = collide.y - w->weaponMask.w; |
if (w->timer == 0) { |
w->vsp = -2; |
PHL_PlaySound(sounds[sndPi02], 2); |
}else if (w->timer == 1) { |
w->vsp = -1; |
PHL_PlaySound(sounds[sndPi02], 2); |
}else{ |
weaponHit(w); |
dead = 1; |
} |
w->timer += 1; |
} |
tempMask.y = w->y - w->weaponMask.w; |
} |
//Move horizontally |
w->x += w->hsp; |
tempMask.x = w->x - w->weaponMask.w; |
//Check horizontal collision |
collide = getTileCollisionWeapon(1, tempMask); |
if (collide.x != -1) { |
if (w->hsp > 0) { |
w->x = collide.x - (tempMask.w / 2) ; |
}else{ |
w->x = collide.x + 40 + (tempMask.w / 2); |
} |
w->hsp *= -1; |
tempMask.x = w->x - w->weaponMask.w; |
w->dir = 1; |
if (w->hsp < 0) { |
w->dir = -1; |
} |
} |
updateWeaponMask(w); |
//animate |
{ |
w->imageIndex += 0.5; |
if (w->imageIndex >= 8) { |
w->imageIndex -= 8; |
} |
} |
if (w->x > 640 || w->x + 40 < 0 || w->y > 520) { |
dead = 1; |
} |
}else if (w->type == BOMB) |
{ |
if (w->state == 0) { //Bouncing bomb |
Mask tempMask; |
tempMask.y = w->y + 8; |
tempMask.w = tempMask.h = 24; |
tempMask.circle = tempMask.unused = 0; |
w->x += w->hsp; |
tempMask.x = w->x + 8; |
PHL_Rect collide = getTileCollision(1, tempMask); |
if (collide.x != -1) { |
if (w->hsp > 0) { |
w->x = collide.x - 40 + 8; |
}else{ |
w->x = collide.x + 40 - 8; |
} |
w->hsp *= -1; |
tempMask.x = w->x + 8; |
} |
w->imageIndex -= (0.33 * w->hsp); |
if (w->imageIndex < 0) { |
w->imageIndex += 8; |
} |
if (w->imageIndex >= 8) { |
w->imageIndex -= 8; |
} |
w->y += w->vsp; |
w->vsp += w->grav; |
tempMask.y = w->y + 8; |
collide = getTileCollision(1, tempMask); |
if (collide.x == -1) { |
collide = getTileCollision(3, tempMask); |
} |
if (collide.x != -1) { |
if (w->vsp <= 0) { |
w->y = collide.y + 40 - 8; |
w->vsp = 0; |
}else{ |
w->y = collide.y - 40 + 8; |
if (w->timer == 0) { |
w->vsp = -2; |
PHL_PlaySound(sounds[sndPi02], CHN_WEAPONS); |
}else if (w->timer == 1) { |
w->vsp = -1; |
PHL_PlaySound(sounds[sndPi02], CHN_WEAPONS); |
}else{ |
w->state = 1; |
w->imageIndex = 0; |
w->weaponMask.unused = 0; |
PHL_PlaySound(sounds[sndBom03], CHN_WEAPONS); |
} |
w->timer += 1; |
} |
} |
updateWeaponMask(w); |
if (w->x > 640 || w->x + 40 < 0 || w->y > 520) { |
//weaponDestroy(w->id); |
dead = 1; |
} |
} |
else if (w->state == 1) { //Explosion |
updateWeaponMask(w); |
if (checkCollision(getHeroMask(), w->weaponMask) == 1) { |
heroHit(20, w->x + 20); |
} |
w->imageIndex += 0.34; |
if (w->imageIndex >= 11) { |
//weaponDestroy(w->id); |
dead = 1; |
} |
} |
} |
if (dead == 1) { |
weaponDestroy(w->id); |
} |
} |
void weaponDraw(Weapon* w) |
{ |
if (w->type == SWORD) { |
//PHL_DrawMask(w->weaponMask); |
//Draw Sword |
double imgind = getHeroImageIndex(); |
int dir = getHeroDirection(); |
if (imgind < 4) { |
int swordx = 0, swordy = 0; |
int scropx = 40 * (int)floor(imgind), |
scropy = 240; |
if (imgind < 1) { |
swordy = -16; |
swordx = -8; |
}else if (imgind < 2) { |
swordy = -8; |
swordx = 24; |
}else if (imgind < 4) { |
swordy = 14; |
swordx = 26; |
} |
if (dir == -1) { |
swordx *= -1; |
scropx += 160; |
} |
if (getHeroInvincible() % 2 == 0) { |
PHL_DrawSurfacePart(herox - 20 + swordx, heroy + swordy, scropx, scropy, 40, 40, images[imgHero]); |
} |
//PHL_DrawSurfacePart(w->x, w->y, 0, 240, 40, 40, images[imgHero]); |
} |
} |
else if (w->type == ARROW) |
{ |
int dx = 240; |
if (w->hsp <= 0) { |
dx += 40; |
} |
PHL_DrawSurfacePart(w->x, w->y, dx, 200, 40, 40, images[imgMisc20]); |
}else if (w->type == AXE) |
{ |
int dx = 0; |
if (w->hsp <= 0) { |
dx = 320; |
} |
PHL_DrawSurfacePart(w->x, w->y, dx + ((int)w->imageIndex * 40), 240, 40, 40, images[imgMisc20]); |
}else if (w->type == BOOMERANG) |
{ |
PHL_DrawSurfacePart(w->x - 20, w->y - 20, 320 + ((int)w->imageIndex * 40), 160, 40, 40, images[imgMisc20]); |
}else if (w->type == FIREBALL) |
{ |
int dx = 0; |
if (w->hsp <= 0) { |
dx = 320; |
} |
PHL_DrawSurfacePart(w->x - 20, w->y - 20, dx + ((int)w->imageIndex * 40), 280, 40, 40, images[imgMisc20]); |
}else if (w->type == BOMB) |
{ |
if (w->state == 0) { |
PHL_DrawSurfacePart(w->x, w->y, (int)w->imageIndex * 40, 160, 40, 40, images[imgMisc20]); |
} |
else if (w->state == 1) { |
//PHL_DrawMask(w->weaponMask); |
int cx = (int)w->imageIndex * 128; |
int cy = 0; |
while (cx >= 640) { |
cx -= 640; |
cy += 96; |
} |
PHL_DrawSurfacePart(w->weaponMask.x, w->weaponMask.y, cx, cy, 128, 96, images[imgExplosion]); |
} |
} |
//PHL_DrawMask(w->weaponMask); |
} |
void updateWeaponMask(Weapon* w) |
{ |
if (w->type == SWORD) { |
//Sword mask |
//swordMask.unused = 0; |
double imgind = getHeroImageIndex(); |
int dir = getHeroDirection(); |
w->weaponMask.unused = 0; |
if (imgind < 1) { |
/*w->weaponMask.w = 8; |
w->weaponMask.h = 24; |
w->weaponMask.x = herox - 4 + (dir * -8); //herox - 20 + (direction * -8) + 16 |
w->weaponMask.y = heroy - 8; //heroy - 16 + 8 |
*/ |
w->weaponMask.unused = 1; |
}else if (imgind < 2) { |
w->weaponMask.w = 32; |
w->weaponMask.h = 38; |
w->weaponMask.x = herox - 20 + (dir * 28) + 4; |
w->weaponMask.y = heroy - 6; |
}else if (imgind < 3) { |
w->weaponMask.w = 24; |
w->weaponMask.h = 20; |
w->weaponMask.x = herox - 20 + (dir * 26) + 8; |
w->weaponMask.y = heroy + 18; |
}else if (imgind < 4) { |
w->weaponMask.w = 24; |
w->weaponMask.h = 6; |
w->weaponMask.x = herox - 20 + (dir * 26) + 8; |
w->weaponMask.y = heroy + 30; |
} |
}else if (w->type == ARROW) { |
w->weaponMask.x = w->x; |
w->weaponMask.y = w->y + 16; |
if (w->hsp > 0) { |
w->weaponMask.x += 8; |
} |
}else if (w->type == AXE) { |
w->weaponMask.x = w->x + ((40 - w->weaponMask.w) / 2); |
w->weaponMask.y = w->y + ((40 - w->weaponMask.h) / 2); |
}else if (w->type == BOOMERANG) { |
w->weaponMask.x = w->x; |
w->weaponMask.y = w->y; |
}else if (w->type == FIREBALL) { |
w->weaponMask.x = w->x; |
w->weaponMask.y = w->y; |
}else if (w->type == BOMB) { |
if (w->state == 1) { //Update mask on explosion |
w->weaponMask.x = w->x - 44; |
w->weaponMask.y = w->y - 44 - 8; |
w->weaponMask.w = 128; |
w->weaponMask.h = 90; //Hits blocks below |
} |
} |
} |
void weaponDestroy(int id) |
{ |
if (weapons[id] != NULL) { |
free(weapons[id]); |
} |
weapons[id] = NULL; |
} |
/contrib/games/hydracastlelabyrinth/src/weapon.h |
---|
0,0 → 1,34 |
#ifndef WEAPON_H |
#define WEAPON_H |
#include "collision.h" |
#define ARROW 0 |
#define AXE 1 |
#define BOOMERANG 2 |
#define FIREBALL 3 |
#define BOMB 4 |
#define SWORD 5 |
typedef struct { |
int id, type; |
double x, y; |
double vsp, hsp; |
double grav; |
double imageIndex; |
int dir; |
int power, timer, state, cooldown, hitflag; |
Mask weaponMask; |
} Weapon; |
void addWeapon(int type, int x, int y); |
void weaponStep(Weapon* w); |
void weaponDraw(Weapon* w); |
void weaponHit(Weapon* w); |
void weaponDestroy(int id); |
#endif |
/contrib/games/hydracastlelabyrinth/src/xBRZ/Changelog.txt |
---|
0,0 → 1,51 |
=========== |
|Changelog| |
=========== |
xBRZ 1.5 [2017-08-07] |
--------------------- |
Added RGB conversion routines |
xBRZ 1.4 [2015-07-25] |
--------------------- |
Added 6xBRZ scaler |
Create color distance buffer lazily |
xBRZ 1.3 [2015-04-03] |
--------------------- |
Improved ARGB performance by 15% |
Fixed alpha channel gradient bug |
xBRZ 1.2 [2014-11-21] |
--------------------- |
Further improved performance by over 30% |
xBRZ 1.1 [2014-11-02] |
--------------------- |
Support images with alpha channel |
Improved color analysis |
xBRZ 1.0 [2013-02-11] |
--------------------- |
Fixed xBRZ scaler compiler issues for GCC |
xBRZ 0.2 [2012-12-11] |
--------------------- |
Added 5xBRZ scaler |
Optimized xBRZ scaler performance by factor 3 |
Further improved image quality of xBRZ scaler |
xBRZ 0.1 [2012-09-26] |
--------------------- |
Initial release: |
- scale while preserving small image features |
- support multithreading |
- support 64-bit architectures |
- support processing image slices |
/contrib/games/hydracastlelabyrinth/src/xBRZ/License.txt |
---|
0,0 → 1,621 |
GNU GENERAL PUBLIC LICENSE |
Version 3, 29 June 2007 |
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
Everyone is permitted to copy and distribute verbatim copies |
of this license document, but changing it is not allowed. |
Preamble |
The GNU General Public License is a free, copyleft license for |
software and other kinds of works. |
The licenses for most software and other practical works are designed |
to take away your freedom to share and change the works. By contrast, |
the GNU General Public License is intended to guarantee your freedom to |
share and change all versions of a program--to make sure it remains free |
software for all its users. We, the Free Software Foundation, use the |
GNU General Public License for most of our software; it applies also to |
any other work released this way by its authors. You can apply it to |
your programs, too. |
When we speak of free software, we are referring to freedom, not |
price. Our General Public Licenses are designed to make sure that you |
have the freedom to distribute copies of free software (and charge for |
them if you wish), that you receive source code or can get it if you |
want it, that you can change the software or use pieces of it in new |
free programs, and that you know you can do these things. |
To protect your rights, we need to prevent others from denying you |
these rights or asking you to surrender the rights. Therefore, you have |
certain responsibilities if you distribute copies of the software, or if |
you modify it: responsibilities to respect the freedom of others. |
For example, if you distribute copies of such a program, whether |
gratis or for a fee, you must pass on to the recipients the same |
freedoms that you received. You must make sure that they, too, receive |
or can get the source code. And you must show them these terms so they |
know their rights. |
Developers that use the GNU GPL protect your rights with two steps: |
(1) assert copyright on the software, and (2) offer you this License |
giving you legal permission to copy, distribute and/or modify it. |
For the developers' and authors' protection, the GPL clearly explains |
that there is no warranty for this free software. For both users' and |
authors' sake, the GPL requires that modified versions be marked as |
changed, so that their problems will not be attributed erroneously to |
authors of previous versions. |
Some devices are designed to deny users access to install or run |
modified versions of the software inside them, although the manufacturer |
can do so. This is fundamentally incompatible with the aim of |
protecting users' freedom to change the software. The systematic |
pattern of such abuse occurs in the area of products for individuals to |
use, which is precisely where it is most unacceptable. Therefore, we |
have designed this version of the GPL to prohibit the practice for those |
products. If such problems arise substantially in other domains, we |
stand ready to extend this provision to those domains in future versions |
of the GPL, as needed to protect the freedom of users. |
Finally, every program is threatened constantly by software patents. |
States should not allow patents to restrict development and use of |
software on general-purpose computers, but in those that do, we wish to |
avoid the special danger that patents applied to a free program could |
make it effectively proprietary. To prevent this, the GPL assures that |
patents cannot be used to render the program non-free. |
The precise terms and conditions for copying, distribution and |
modification follow. |
TERMS AND CONDITIONS |
0. Definitions. |
"This License" refers to version 3 of the GNU General Public License. |
"Copyright" also means copyright-like laws that apply to other kinds of |
works, such as semiconductor masks. |
"The Program" refers to any copyrightable work licensed under this |
License. Each licensee is addressed as "you". "Licensees" and |
"recipients" may be individuals or organizations. |
To "modify" a work means to copy from or adapt all or part of the work |
in a fashion requiring copyright permission, other than the making of an |
exact copy. The resulting work is called a "modified version" of the |
earlier work or a work "based on" the earlier work. |
A "covered work" means either the unmodified Program or a work based |
on the Program. |
To "propagate" a work means to do anything with it that, without |
permission, would make you directly or secondarily liable for |
infringement under applicable copyright law, except executing it on a |
computer or modifying a private copy. Propagation includes copying, |
distribution (with or without modification), making available to the |
public, and in some countries other activities as well. |
To "convey" a work means any kind of propagation that enables other |
parties to make or receive copies. Mere interaction with a user through |
a computer network, with no transfer of a copy, is not conveying. |
An interactive user interface displays "Appropriate Legal Notices" |
to the extent that it includes a convenient and prominently visible |
feature that (1) displays an appropriate copyright notice, and (2) |
tells the user that there is no warranty for the work (except to the |
extent that warranties are provided), that licensees may convey the |
work under this License, and how to view a copy of this License. If |
the interface presents a list of user commands or options, such as a |
menu, a prominent item in the list meets this criterion. |
1. Source Code. |
The "source code" for a work means the preferred form of the work |
for making modifications to it. "Object code" means any non-source |
form of a work. |
A "Standard Interface" means an interface that either is an official |
standard defined by a recognized standards body, or, in the case of |
interfaces specified for a particular programming language, one that |
is widely used among developers working in that language. |
The "System Libraries" of an executable work include anything, other |
than the work as a whole, that (a) is included in the normal form of |
packaging a Major Component, but which is not part of that Major |
Component, and (b) serves only to enable use of the work with that |
Major Component, or to implement a Standard Interface for which an |
implementation is available to the public in source code form. A |
"Major Component", in this context, means a major essential component |
(kernel, window system, and so on) of the specific operating system |
(if any) on which the executable work runs, or a compiler used to |
produce the work, or an object code interpreter used to run it. |
The "Corresponding Source" for a work in object code form means all |
the source code needed to generate, install, and (for an executable |
work) run the object code and to modify the work, including scripts to |
control those activities. However, it does not include the work's |
System Libraries, or general-purpose tools or generally available free |
programs which are used unmodified in performing those activities but |
which are not part of the work. For example, Corresponding Source |
includes interface definition files associated with source files for |
the work, and the source code for shared libraries and dynamically |
linked subprograms that the work is specifically designed to require, |
such as by intimate data communication or control flow between those |
subprograms and other parts of the work. |
The Corresponding Source need not include anything that users |
can regenerate automatically from other parts of the Corresponding |
Source. |
The Corresponding Source for a work in source code form is that |
same work. |
2. Basic Permissions. |
All rights granted under this License are granted for the term of |
copyright on the Program, and are irrevocable provided the stated |
conditions are met. This License explicitly affirms your unlimited |
permission to run the unmodified Program. The output from running a |
covered work is covered by this License only if the output, given its |
content, constitutes a covered work. This License acknowledges your |
rights of fair use or other equivalent, as provided by copyright law. |
You may make, run and propagate covered works that you do not |
convey, without conditions so long as your license otherwise remains |
in force. You may convey covered works to others for the sole purpose |
of having them make modifications exclusively for you, or provide you |
with facilities for running those works, provided that you comply with |
the terms of this License in conveying all material for which you do |
not control copyright. Those thus making or running the covered works |
for you must do so exclusively on your behalf, under your direction |
and control, on terms that prohibit them from making any copies of |
your copyrighted material outside their relationship with you. |
Conveying under any other circumstances is permitted solely under |
the conditions stated below. Sublicensing is not allowed; section 10 |
makes it unnecessary. |
3. Protecting Users' Legal Rights From Anti-Circumvention Law. |
No covered work shall be deemed part of an effective technological |
measure under any applicable law fulfilling obligations under article |
11 of the WIPO copyright treaty adopted on 20 December 1996, or |
similar laws prohibiting or restricting circumvention of such |
measures. |
When you convey a covered work, you waive any legal power to forbid |
circumvention of technological measures to the extent such circumvention |
is effected by exercising rights under this License with respect to |
the covered work, and you disclaim any intention to limit operation or |
modification of the work as a means of enforcing, against the work's |
users, your or third parties' legal rights to forbid circumvention of |
technological measures. |
4. Conveying Verbatim Copies. |
You may convey verbatim copies of the Program's source code as you |
receive it, in any medium, provided that you conspicuously and |
appropriately publish on each copy an appropriate copyright notice; |
keep intact all notices stating that this License and any |
non-permissive terms added in accord with section 7 apply to the code; |
keep intact all notices of the absence of any warranty; and give all |
recipients a copy of this License along with the Program. |
You may charge any price or no price for each copy that you convey, |
and you may offer support or warranty protection for a fee. |
5. Conveying Modified Source Versions. |
You may convey a work based on the Program, or the modifications to |
produce it from the Program, in the form of source code under the |
terms of section 4, provided that you also meet all of these conditions: |
a) The work must carry prominent notices stating that you modified |
it, and giving a relevant date. |
b) The work must carry prominent notices stating that it is |
released under this License and any conditions added under section |
7. This requirement modifies the requirement in section 4 to |
"keep intact all notices". |
c) You must license the entire work, as a whole, under this |
License to anyone who comes into possession of a copy. This |
License will therefore apply, along with any applicable section 7 |
additional terms, to the whole of the work, and all its parts, |
regardless of how they are packaged. This License gives no |
permission to license the work in any other way, but it does not |
invalidate such permission if you have separately received it. |
d) If the work has interactive user interfaces, each must display |
Appropriate Legal Notices; however, if the Program has interactive |
interfaces that do not display Appropriate Legal Notices, your |
work need not make them do so. |
A compilation of a covered work with other separate and independent |
works, which are not by their nature extensions of the covered work, |
and which are not combined with it such as to form a larger program, |
in or on a volume of a storage or distribution medium, is called an |
"aggregate" if the compilation and its resulting copyright are not |
used to limit the access or legal rights of the compilation's users |
beyond what the individual works permit. Inclusion of a covered work |
in an aggregate does not cause this License to apply to the other |
parts of the aggregate. |
6. Conveying Non-Source Forms. |
You may convey a covered work in object code form under the terms |
of sections 4 and 5, provided that you also convey the |
machine-readable Corresponding Source under the terms of this License, |
in one of these ways: |
a) Convey the object code in, or embodied in, a physical product |
(including a physical distribution medium), accompanied by the |
Corresponding Source fixed on a durable physical medium |
customarily used for software interchange. |
b) Convey the object code in, or embodied in, a physical product |
(including a physical distribution medium), accompanied by a |
written offer, valid for at least three years and valid for as |
long as you offer spare parts or customer support for that product |
model, to give anyone who possesses the object code either (1) a |
copy of the Corresponding Source for all the software in the |
product that is covered by this License, on a durable physical |
medium customarily used for software interchange, for a price no |
more than your reasonable cost of physically performing this |
conveying of source, or (2) access to copy the |
Corresponding Source from a network server at no charge. |
c) Convey individual copies of the object code with a copy of the |
written offer to provide the Corresponding Source. This |
alternative is allowed only occasionally and noncommercially, and |
only if you received the object code with such an offer, in accord |
with subsection 6b. |
d) Convey the object code by offering access from a designated |
place (gratis or for a charge), and offer equivalent access to the |
Corresponding Source in the same way through the same place at no |
further charge. You need not require recipients to copy the |
Corresponding Source along with the object code. If the place to |
copy the object code is a network server, the Corresponding Source |
may be on a different server (operated by you or a third party) |
that supports equivalent copying facilities, provided you maintain |
clear directions next to the object code saying where to find the |
Corresponding Source. Regardless of what server hosts the |
Corresponding Source, you remain obligated to ensure that it is |
available for as long as needed to satisfy these requirements. |
e) Convey the object code using peer-to-peer transmission, provided |
you inform other peers where the object code and Corresponding |
Source of the work are being offered to the general public at no |
charge under subsection 6d. |
A separable portion of the object code, whose source code is excluded |
from the Corresponding Source as a System Library, need not be |
included in conveying the object code work. |
A "User Product" is either (1) a "consumer product", which means any |
tangible personal property which is normally used for personal, family, |
or household purposes, or (2) anything designed or sold for incorporation |
into a dwelling. In determining whether a product is a consumer product, |
doubtful cases shall be resolved in favor of coverage. For a particular |
product received by a particular user, "normally used" refers to a |
typical or common use of that class of product, regardless of the status |
of the particular user or of the way in which the particular user |
actually uses, or expects or is expected to use, the product. A product |
is a consumer product regardless of whether the product has substantial |
commercial, industrial or non-consumer uses, unless such uses represent |
the only significant mode of use of the product. |
"Installation Information" for a User Product means any methods, |
procedures, authorization keys, or other information required to install |
and execute modified versions of a covered work in that User Product from |
a modified version of its Corresponding Source. The information must |
suffice to ensure that the continued functioning of the modified object |
code is in no case prevented or interfered with solely because |
modification has been made. |
If you convey an object code work under this section in, or with, or |
specifically for use in, a User Product, and the conveying occurs as |
part of a transaction in which the right of possession and use of the |
User Product is transferred to the recipient in perpetuity or for a |
fixed term (regardless of how the transaction is characterized), the |
Corresponding Source conveyed under this section must be accompanied |
by the Installation Information. But this requirement does not apply |
if neither you nor any third party retains the ability to install |
modified object code on the User Product (for example, the work has |
been installed in ROM). |
The requirement to provide Installation Information does not include a |
requirement to continue to provide support service, warranty, or updates |
for a work that has been modified or installed by the recipient, or for |
the User Product in which it has been modified or installed. Access to a |
network may be denied when the modification itself materially and |
adversely affects the operation of the network or violates the rules and |
protocols for communication across the network. |
Corresponding Source conveyed, and Installation Information provided, |
in accord with this section must be in a format that is publicly |
documented (and with an implementation available to the public in |
source code form), and must require no special password or key for |
unpacking, reading or copying. |
7. Additional Terms. |
"Additional permissions" are terms that supplement the terms of this |
License by making exceptions from one or more of its conditions. |
Additional permissions that are applicable to the entire Program shall |
be treated as though they were included in this License, to the extent |
that they are valid under applicable law. If additional permissions |
apply only to part of the Program, that part may be used separately |
under those permissions, but the entire Program remains governed by |
this License without regard to the additional permissions. |
When you convey a copy of a covered work, you may at your option |
remove any additional permissions from that copy, or from any part of |
it. (Additional permissions may be written to require their own |
removal in certain cases when you modify the work.) You may place |
additional permissions on material, added by you to a covered work, |
for which you have or can give appropriate copyright permission. |
Notwithstanding any other provision of this License, for material you |
add to a covered work, you may (if authorized by the copyright holders of |
that material) supplement the terms of this License with terms: |
a) Disclaiming warranty or limiting liability differently from the |
terms of sections 15 and 16 of this License; or |
b) Requiring preservation of specified reasonable legal notices or |
author attributions in that material or in the Appropriate Legal |
Notices displayed by works containing it; or |
c) Prohibiting misrepresentation of the origin of that material, or |
requiring that modified versions of such material be marked in |
reasonable ways as different from the original version; or |
d) Limiting the use for publicity purposes of names of licensors or |
authors of the material; or |
e) Declining to grant rights under trademark law for use of some |
trade names, trademarks, or service marks; or |
f) Requiring indemnification of licensors and authors of that |
material by anyone who conveys the material (or modified versions of |
it) with contractual assumptions of liability to the recipient, for |
any liability that these contractual assumptions directly impose on |
those licensors and authors. |
All other non-permissive additional terms are considered "further |
restrictions" within the meaning of section 10. If the Program as you |
received it, or any part of it, contains a notice stating that it is |
governed by this License along with a term that is a further |
restriction, you may remove that term. If a license document contains |
a further restriction but permits relicensing or conveying under this |
License, you may add to a covered work material governed by the terms |
of that license document, provided that the further restriction does |
not survive such relicensing or conveying. |
If you add terms to a covered work in accord with this section, you |
must place, in the relevant source files, a statement of the |
additional terms that apply to those files, or a notice indicating |
where to find the applicable terms. |
Additional terms, permissive or non-permissive, may be stated in the |
form of a separately written license, or stated as exceptions; |
the above requirements apply either way. |
8. Termination. |
You may not propagate or modify a covered work except as expressly |
provided under this License. Any attempt otherwise to propagate or |
modify it is void, and will automatically terminate your rights under |
this License (including any patent licenses granted under the third |
paragraph of section 11). |
However, if you cease all violation of this License, then your |
license from a particular copyright holder is reinstated (a) |
provisionally, unless and until the copyright holder explicitly and |
finally terminates your license, and (b) permanently, if the copyright |
holder fails to notify you of the violation by some reasonable means |
prior to 60 days after the cessation. |
Moreover, your license from a particular copyright holder is |
reinstated permanently if the copyright holder notifies you of the |
violation by some reasonable means, this is the first time you have |
received notice of violation of this License (for any work) from that |
copyright holder, and you cure the violation prior to 30 days after |
your receipt of the notice. |
Termination of your rights under this section does not terminate the |
licenses of parties who have received copies or rights from you under |
this License. If your rights have been terminated and not permanently |
reinstated, you do not qualify to receive new licenses for the same |
material under section 10. |
9. Acceptance Not Required for Having Copies. |
You are not required to accept this License in order to receive or |
run a copy of the Program. Ancillary propagation of a covered work |
occurring solely as a consequence of using peer-to-peer transmission |
to receive a copy likewise does not require acceptance. However, |
nothing other than this License grants you permission to propagate or |
modify any covered work. These actions infringe copyright if you do |
not accept this License. Therefore, by modifying or propagating a |
covered work, you indicate your acceptance of this License to do so. |
10. Automatic Licensing of Downstream Recipients. |
Each time you convey a covered work, the recipient automatically |
receives a license from the original licensors, to run, modify and |
propagate that work, subject to this License. You are not responsible |
for enforcing compliance by third parties with this License. |
An "entity transaction" is a transaction transferring control of an |
organization, or substantially all assets of one, or subdividing an |
organization, or merging organizations. If propagation of a covered |
work results from an entity transaction, each party to that |
transaction who receives a copy of the work also receives whatever |
licenses to the work the party's predecessor in interest had or could |
give under the previous paragraph, plus a right to possession of the |
Corresponding Source of the work from the predecessor in interest, if |
the predecessor has it or can get it with reasonable efforts. |
You may not impose any further restrictions on the exercise of the |
rights granted or affirmed under this License. For example, you may |
not impose a license fee, royalty, or other charge for exercise of |
rights granted under this License, and you may not initiate litigation |
(including a cross-claim or counterclaim in a lawsuit) alleging that |
any patent claim is infringed by making, using, selling, offering for |
sale, or importing the Program or any portion of it. |
11. Patents. |
A "contributor" is a copyright holder who authorizes use under this |
License of the Program or a work on which the Program is based. The |
work thus licensed is called the contributor's "contributor version". |
A contributor's "essential patent claims" are all patent claims |
owned or controlled by the contributor, whether already acquired or |
hereafter acquired, that would be infringed by some manner, permitted |
by this License, of making, using, or selling its contributor version, |
but do not include claims that would be infringed only as a |
consequence of further modification of the contributor version. For |
purposes of this definition, "control" includes the right to grant |
patent sublicenses in a manner consistent with the requirements of |
this License. |
Each contributor grants you a non-exclusive, worldwide, royalty-free |
patent license under the contributor's essential patent claims, to |
make, use, sell, offer for sale, import and otherwise run, modify and |
propagate the contents of its contributor version. |
In the following three paragraphs, a "patent license" is any express |
agreement or commitment, however denominated, not to enforce a patent |
(such as an express permission to practice a patent or covenant not to |
sue for patent infringement). To "grant" such a patent license to a |
party means to make such an agreement or commitment not to enforce a |
patent against the party. |
If you convey a covered work, knowingly relying on a patent license, |
and the Corresponding Source of the work is not available for anyone |
to copy, free of charge and under the terms of this License, through a |
publicly available network server or other readily accessible means, |
then you must either (1) cause the Corresponding Source to be so |
available, or (2) arrange to deprive yourself of the benefit of the |
patent license for this particular work, or (3) arrange, in a manner |
consistent with the requirements of this License, to extend the patent |
license to downstream recipients. "Knowingly relying" means you have |
actual knowledge that, but for the patent license, your conveying the |
covered work in a country, or your recipient's use of the covered work |
in a country, would infringe one or more identifiable patents in that |
country that you have reason to believe are valid. |
If, pursuant to or in connection with a single transaction or |
arrangement, you convey, or propagate by procuring conveyance of, a |
covered work, and grant a patent license to some of the parties |
receiving the covered work authorizing them to use, propagate, modify |
or convey a specific copy of the covered work, then the patent license |
you grant is automatically extended to all recipients of the covered |
work and works based on it. |
A patent license is "discriminatory" if it does not include within |
the scope of its coverage, prohibits the exercise of, or is |
conditioned on the non-exercise of one or more of the rights that are |
specifically granted under this License. You may not convey a covered |
work if you are a party to an arrangement with a third party that is |
in the business of distributing software, under which you make payment |
to the third party based on the extent of your activity of conveying |
the work, and under which the third party grants, to any of the |
parties who would receive the covered work from you, a discriminatory |
patent license (a) in connection with copies of the covered work |
conveyed by you (or copies made from those copies), or (b) primarily |
for and in connection with specific products or compilations that |
contain the covered work, unless you entered into that arrangement, |
or that patent license was granted, prior to 28 March 2007. |
Nothing in this License shall be construed as excluding or limiting |
any implied license or other defenses to infringement that may |
otherwise be available to you under applicable patent law. |
12. No Surrender of Others' Freedom. |
If conditions are imposed on you (whether by court order, agreement or |
otherwise) that contradict the conditions of this License, they do not |
excuse you from the conditions of this License. If you cannot convey a |
covered work so as to satisfy simultaneously your obligations under this |
License and any other pertinent obligations, then as a consequence you may |
not convey it at all. For example, if you agree to terms that obligate you |
to collect a royalty for further conveying from those to whom you convey |
the Program, the only way you could satisfy both those terms and this |
License would be to refrain entirely from conveying the Program. |
13. Use with the GNU Affero General Public License. |
Notwithstanding any other provision of this License, you have |
permission to link or combine any covered work with a work licensed |
under version 3 of the GNU Affero General Public License into a single |
combined work, and to convey the resulting work. The terms of this |
License will continue to apply to the part which is the covered work, |
but the special requirements of the GNU Affero General Public License, |
section 13, concerning interaction through a network will apply to the |
combination as such. |
14. Revised Versions of this License. |
The Free Software Foundation may publish revised and/or new versions of |
the GNU General Public License from time to time. Such new versions will |
be similar in spirit to the present version, but may differ in detail to |
address new problems or concerns. |
Each version is given a distinguishing version number. If the |
Program specifies that a certain numbered version of the GNU General |
Public License "or any later version" applies to it, you have the |
option of following the terms and conditions either of that numbered |
version or of any later version published by the Free Software |
Foundation. If the Program does not specify a version number of the |
GNU General Public License, you may choose any version ever published |
by the Free Software Foundation. |
If the Program specifies that a proxy can decide which future |
versions of the GNU General Public License can be used, that proxy's |
public statement of acceptance of a version permanently authorizes you |
to choose that version for the Program. |
Later license versions may give you additional or different |
permissions. However, no additional obligations are imposed on any |
author or copyright holder as a result of your choosing to follow a |
later version. |
15. Disclaimer of Warranty. |
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY |
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT |
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY |
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, |
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM |
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF |
ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
16. Limitation of Liability. |
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS |
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY |
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE |
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF |
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD |
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), |
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF |
SUCH DAMAGES. |
17. Interpretation of Sections 15 and 16. |
If the disclaimer of warranty and limitation of liability provided |
above cannot be given local legal effect according to their terms, |
reviewing courts shall apply local law that most closely approximates |
an absolute waiver of all civil liability in connection with the |
Program, unless a warranty or assumption of liability accompanies a |
copy of the Program in return for a fee. |
END OF TERMS AND CONDITIONS |
/contrib/games/hydracastlelabyrinth/src/xBRZ/xbrz.cpp |
---|
0,0 → 1,1174 |
// **************************************************************************** |
// * This file is part of the HqMAME project. It is distributed under * |
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 * |
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * |
// * * |
// * Additionally and as a special exception, the author gives permission * |
// * to link the code of this program with the MAME library (or with modified * |
// * versions of MAME that use the same license as MAME), and distribute * |
// * linked combinations including the two. You must obey the GNU General * |
// * Public License in all respects for all of the code used other than MAME. * |
// * If you modify this file, you may extend this exception to your version * |
// * of the file, but you are not obligated to do so. If you do not wish to * |
// * do so, delete this exception statement from your version. * |
// **************************************************************************** |
#pragma GCC diagnostic ignored "-Wunused-function" |
#include "xbrz.h" |
#include "xbrz_tools.h" |
#include <cassert> |
#include <algorithm> |
#include <vector> |
#include <cmath> |
#ifndef NDEBUG |
#define NDEBUG |
#endif |
using namespace xbrz; |
namespace |
{ |
template <unsigned int M, unsigned int N> inline |
uint32_t gradientRGB(uint32_t pixFront, uint32_t pixBack) //blend front color with opacity M / N over opaque background: http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending |
{ |
static_assert(0 < M && M < N && N <= 1000, ""); |
auto calcColor = [](unsigned char colFront, unsigned char colBack) -> unsigned char { |
return (colFront * M + colBack * (N - M)) / N; |
}; |
return makePixel(calcColor(getRed (pixFront), getRed (pixBack)), |
calcColor(getGreen(pixFront), getGreen(pixBack)), |
calcColor(getBlue (pixFront), getBlue (pixBack))); |
} |
template <unsigned int M, unsigned int N> inline |
uint32_t gradientARGB(uint32_t pixFront, uint32_t pixBack) //find intermediate color between two colors with alpha channels (=> NO alpha blending!!!) |
{ |
static_assert(0 < M && M < N && N <= 1000, ""); |
const unsigned int weightFront = getAlpha(pixFront) * M; |
const unsigned int weightBack = getAlpha(pixBack) * (N - M); |
const unsigned int weightSum = weightFront + weightBack; |
if (weightSum == 0) |
return 0; |
auto calcColor = [=](unsigned char colFront, unsigned char colBack) |
{ |
return static_cast<unsigned char>((colFront * weightFront + colBack * weightBack) / weightSum); |
}; |
return makePixel(static_cast<unsigned char>(weightSum / N), |
calcColor(getRed (pixFront), getRed (pixBack)), |
calcColor(getGreen(pixFront), getGreen(pixBack)), |
calcColor(getBlue (pixFront), getBlue (pixBack))); |
} |
//inline |
//double fastSqrt(double n) |
//{ |
// __asm //speeds up xBRZ by about 9% compared to std::sqrt which internally uses the same assembler instructions but adds some "fluff" |
// { |
// fld n |
// fsqrt |
// } |
//} |
// |
#ifdef _MSC_VER |
#define FORCE_INLINE __forceinline |
#elif defined __GNUC__ |
#define FORCE_INLINE __attribute__((always_inline)) inline |
#else |
#define FORCE_INLINE inline |
#endif |
enum RotationDegree //clock-wise |
{ |
ROT_0, |
ROT_90, |
ROT_180, |
ROT_270 |
}; |
//calculate input matrix coordinates after rotation at compile time |
template <RotationDegree rotDeg, size_t I, size_t J, size_t N> |
struct MatrixRotation; |
template <size_t I, size_t J, size_t N> |
struct MatrixRotation<ROT_0, I, J, N> |
{ |
static const size_t I_old = I; |
static const size_t J_old = J; |
}; |
template <RotationDegree rotDeg, size_t I, size_t J, size_t N> //(i, j) = (row, col) indices, N = size of (square) matrix |
struct MatrixRotation |
{ |
static const size_t I_old = N - 1 - MatrixRotation<static_cast<RotationDegree>(rotDeg - 1), I, J, N>::J_old; //old coordinates before rotation! |
static const size_t J_old = MatrixRotation<static_cast<RotationDegree>(rotDeg - 1), I, J, N>::I_old;// |
}; |
template <size_t N, RotationDegree rotDeg> |
class OutputMatrix |
{ |
public: |
OutputMatrix(uint32_t* out, int outWidth) : //access matrix area, top-left at position "out" for image with given width |
out_(out), |
outWidth_(outWidth) { |
} |
template <size_t I, size_t J> |
uint32_t& ref() const |
{ |
static const size_t I_old = MatrixRotation<rotDeg, I, J, N>::I_old; |
static const size_t J_old = MatrixRotation<rotDeg, I, J, N>::J_old; |
return *(out_ + J_old + I_old * outWidth_); |
} |
private: |
uint32_t* out_; |
const int outWidth_; |
}; |
template <class T> inline |
T square(T value) { |
return value * value; |
} |
inline |
double distRGB(uint32_t pix1, uint32_t pix2) |
{ |
const double r_diff = static_cast<int>(getRed (pix1)) - getRed (pix2); |
const double g_diff = static_cast<int>(getGreen(pix1)) - getGreen(pix2); |
const double b_diff = static_cast<int>(getBlue (pix1)) - getBlue (pix2); |
//euklidean RGB distance |
return std::sqrt(square(r_diff) + square(g_diff) + square(b_diff)); |
} |
inline |
double distYCbCr(uint32_t pix1, uint32_t pix2, double lumaWeight) |
{ |
//http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion |
//YCbCr conversion is a matrix multiplication => take advantage of linearity by subtracting first! |
const int r_diff = static_cast<int>(getRed (pix1)) - getRed (pix2);//we may delay division by 255 to after matrix multiplication |
const int g_diff = static_cast<int>(getGreen(pix1)) - getGreen(pix2); // |
const int b_diff = static_cast<int>(getBlue (pix1)) - getBlue (pix2); //substraction for int is noticeable faster than for double! |
//const double k_b = 0.0722; //ITU-R BT.709 conversion |
//const double k_r = 0.2126; // |
const double k_b = 0.0593; //ITU-R BT.2020 conversion |
const double k_r = 0.2627; // |
const double k_g = 1 - k_b - k_r; |
const double scale_b = 0.5 / (1 - k_b); |
const double scale_r = 0.5 / (1 - k_r); |
const double y = k_r * r_diff + k_g * g_diff + k_b * b_diff;//[!], analog YCbCr! |
const double c_b = scale_b * (b_diff - y); |
const double c_r = scale_r * (r_diff - y); |
//we skip division by 255 to have similar range like other distance functions |
return std::sqrt(square(lumaWeight * y) + square(c_b) + square(c_r)); |
} |
inline |
double distYCbCrBuffered(uint32_t pix1, uint32_t pix2) |
{ |
//30% perf boost compared to plain distYCbCr()! |
//consumes 64 MB memory; using double is only 2% faster, but takes 128 MB |
static const std::vector<float> diffToDist = [] |
{ |
std::vector<float> tmp; |
for (uint32_t i = 0; i < 256 * 256 * 256; ++i) //startup time: 114 ms on Intel Core i5 (four cores) |
{ |
const int r_diff = getByte<2>(i) * 2 - 0xFF; |
const int g_diff = getByte<1>(i) * 2 - 0xFF; |
const int b_diff = getByte<0>(i) * 2 - 0xFF; |
const double k_b = 0.0593; //ITU-R BT.2020 conversion |
const double k_r = 0.2627; // |
const double k_g = 1 - k_b - k_r; |
const double scale_b = 0.5 / (1 - k_b); |
const double scale_r = 0.5 / (1 - k_r); |
const double y = k_r * r_diff + k_g * g_diff + k_b * b_diff;//[!], analog YCbCr! |
const double c_b = scale_b * (b_diff - y); |
const double c_r = scale_r * (r_diff - y); |
tmp.push_back(static_cast<float>(std::sqrt(square(y) + square(c_b) + square(c_r)))); |
} |
return tmp; |
} (); |
//if (pix1 == pix2) -> 8% perf degradation! |
// return 0; |
//if (pix1 < pix2) |
// std::swap(pix1, pix2); -> 30% perf degradation!!! |
#if 1 |
const int r_diff = static_cast<int>(getRed (pix1)) - getRed (pix2); |
const int g_diff = static_cast<int>(getGreen(pix1)) - getGreen(pix2); |
const int b_diff = static_cast<int>(getBlue (pix1)) - getBlue (pix2); |
return diffToDist[(((r_diff + 0xFF) / 2) << 16) | //slightly reduce precision (division by 2) to squeeze value into single byte |
(((g_diff + 0xFF) / 2) << 8) | |
(( b_diff + 0xFF) / 2)]; |
#else //not noticeably faster: |
const int r_diff_tmp = ((pix1 & 0xFF0000) + 0xFF0000 - (pix2 & 0xFF0000)) / 2; |
const int g_diff_tmp = ((pix1 & 0x00FF00) + 0x00FF00 - (pix2 & 0x00FF00)) / 2; //slightly reduce precision (division by 2) to squeeze value into single byte |
const int b_diff_tmp = ((pix1 & 0x0000FF) + 0x0000FF - (pix2 & 0x0000FF)) / 2; |
return diffToDist[(r_diff_tmp & 0xFF0000) | (g_diff_tmp & 0x00FF00) | (b_diff_tmp & 0x0000FF)]; |
#endif |
} |
enum BlendType |
{ |
BLEND_NONE = 0, |
BLEND_NORMAL, //a normal indication to blend |
BLEND_DOMINANT, //a strong indication to blend |
//attention: BlendType must fit into the value range of 2 bit!!! |
}; |
struct BlendResult |
{ |
BlendType |
/**/ blend_f, blend_g, |
/**/ blend_j, blend_k; |
}; |
struct Kernel_4x4 //kernel for preprocessing step |
{ |
uint32_t |
/**/ a, b, c, d, |
/**/ e, f, g, h, |
/**/ i, j, k, l, |
/**/ m, n, o, p; |
}; |
/* |
input kernel area naming convention: |
----------------- |
| A | B | C | D | |
----|---|---|---| |
| E | F | G | H | //evaluate the four corners between F, G, J, K |
----|---|---|---| //input pixel is at position F |
| I | J | K | L | |
----|---|---|---| |
| M | N | O | P | |
----------------- |
*/ |
template <class ColorDistance> |
FORCE_INLINE //detect blend direction |
BlendResult preProcessCorners(const Kernel_4x4& ker, const xbrz::ScalerCfg& cfg) //result: F, G, J, K corners of "GradientType" |
{ |
BlendResult result = {}; |
if ((ker.f == ker.g && |
ker.j == ker.k) || |
(ker.f == ker.j && |
ker.g == ker.k)) |
return result; |
auto dist = [&](uint32_t pix1, uint32_t pix2) { |
return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight); |
}; |
const int weight = 4; |
double jg = dist(ker.i, ker.f) + dist(ker.f, ker.c) + dist(ker.n, ker.k) + dist(ker.k, ker.h) + weight * dist(ker.j, ker.g); |
double fk = dist(ker.e, ker.j) + dist(ker.j, ker.o) + dist(ker.b, ker.g) + dist(ker.g, ker.l) + weight * dist(ker.f, ker.k); |
if (jg < fk) //test sample: 70% of values max(jg, fk) / min(jg, fk) are between 1.1 and 3.7 with median being 1.8 |
{ |
const bool dominantGradient = cfg.dominantDirectionThreshold * jg < fk; |
if (ker.f != ker.g && ker.f != ker.j) |
result.blend_f = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; |
if (ker.k != ker.j && ker.k != ker.g) |
result.blend_k = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; |
} |
else if (fk < jg) |
{ |
const bool dominantGradient = cfg.dominantDirectionThreshold * fk < jg; |
if (ker.j != ker.f && ker.j != ker.k) |
result.blend_j = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; |
if (ker.g != ker.f && ker.g != ker.k) |
result.blend_g = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; |
} |
return result; |
} |
struct Kernel_3x3 |
{ |
uint32_t |
/**/ a, b, c, |
/**/ d, e, f, |
/**/ g, h, i; |
}; |
#define DEF_GETTER(x) template <RotationDegree rotDeg> uint32_t inline get_ ## x(const Kernel_3x3 &ker) { return ker.x; } |
//we cannot and NEED NOT write "ker.##x" since ## concatenates preprocessor tokens but "." is not a token |
DEF_GETTER(a) DEF_GETTER(b) DEF_GETTER(c) |
DEF_GETTER(d) DEF_GETTER(e) DEF_GETTER(f) |
DEF_GETTER(g) DEF_GETTER(h) DEF_GETTER(i) |
#undef DEF_GETTER |
#define DEF_GETTER(x, y) template <> inline uint32_t get_ ## x<ROT_90>(const Kernel_3x3 &ker) { return ker.y; } |
DEF_GETTER(a, g) DEF_GETTER(b, d) DEF_GETTER(c, a) |
DEF_GETTER(d, h) DEF_GETTER(e, e) DEF_GETTER(f, b) |
DEF_GETTER(g, i) DEF_GETTER(h, f) DEF_GETTER(i, c) |
#undef DEF_GETTER |
#define DEF_GETTER(x, y) template <> inline uint32_t get_ ## x<ROT_180>(const Kernel_3x3 &ker) { return ker.y; } |
DEF_GETTER(a, i) DEF_GETTER(b, h) DEF_GETTER(c, g) |
DEF_GETTER(d, f) DEF_GETTER(e, e) DEF_GETTER(f, d) |
DEF_GETTER(g, c) DEF_GETTER(h, b) DEF_GETTER(i, a) |
#undef DEF_GETTER |
#define DEF_GETTER(x, y) template <> inline uint32_t get_ ## x<ROT_270>(const Kernel_3x3 &ker) { return ker.y; } |
DEF_GETTER(a, c) DEF_GETTER(b, f) DEF_GETTER(c, i) |
DEF_GETTER(d, b) DEF_GETTER(e, e) DEF_GETTER(f, h) |
DEF_GETTER(g, a) DEF_GETTER(h, d) DEF_GETTER(i, g) |
#undef DEF_GETTER |
//compress four blend types into a single byte |
inline BlendType getTopL (unsigned char b) { |
return static_cast<BlendType>(0x3 & b); |
} |
inline BlendType getTopR (unsigned char b) { |
return static_cast<BlendType>(0x3 & (b >> 2)); |
} |
inline BlendType getBottomR(unsigned char b) { |
return static_cast<BlendType>(0x3 & (b >> 4)); |
} |
inline BlendType getBottomL(unsigned char b) { |
return static_cast<BlendType>(0x3 & (b >> 6)); |
} |
inline void setTopL (unsigned char& b, BlendType bt) { |
b |= bt; |
} //buffer is assumed to be initialized before preprocessing! |
inline void setTopR (unsigned char& b, BlendType bt) { |
b |= (bt << 2); |
} |
inline void setBottomR(unsigned char& b, BlendType bt) { |
b |= (bt << 4); |
} |
inline void setBottomL(unsigned char& b, BlendType bt) { |
b |= (bt << 6); |
} |
inline bool blendingNeeded(unsigned char b) { |
return b != 0; |
} |
template <RotationDegree rotDeg> inline |
unsigned char rotateBlendInfo(unsigned char b) { |
return b; |
} |
template <> inline unsigned char rotateBlendInfo<ROT_90 >(unsigned char b) { |
return ((b << 2) | (b >> 6)) & 0xff; |
} |
template <> inline unsigned char rotateBlendInfo<ROT_180>(unsigned char b) { |
return ((b << 4) | (b >> 4)) & 0xff; |
} |
template <> inline unsigned char rotateBlendInfo<ROT_270>(unsigned char b) { |
return ((b << 6) | (b >> 2)) & 0xff; |
} |
#ifndef NDEBUG |
int debugPixelX = -1; |
int debugPixelY = 12; |
__declspec(thread) bool breakIntoDebugger = false; |
#endif |
/* |
input kernel area naming convention: |
------------- |
| A | B | C | |
----|---|---| |
| D | E | F | //input pixel is at position E |
----|---|---| |
| G | H | I | |
------------- |
*/ |
template <class Scaler, class ColorDistance, RotationDegree rotDeg> |
FORCE_INLINE //perf: quite worth it! |
void blendPixel(const Kernel_3x3& ker, |
uint32_t* target, int trgWidth, |
unsigned char blendInfo, //result of preprocessing all four corners of pixel "e" |
const xbrz::ScalerCfg& cfg) |
{ |
#define a get_a<rotDeg>(ker) |
#define b get_b<rotDeg>(ker) |
#define c get_c<rotDeg>(ker) |
#define d get_d<rotDeg>(ker) |
#define e get_e<rotDeg>(ker) |
#define f get_f<rotDeg>(ker) |
#define g get_g<rotDeg>(ker) |
#define h get_h<rotDeg>(ker) |
#define i get_i<rotDeg>(ker) |
#ifndef NDEBUG |
if (breakIntoDebugger) |
__debugbreak(); //__asm int 3; |
#endif |
const unsigned char blend = rotateBlendInfo<rotDeg>(blendInfo); |
if (getBottomR(blend) >= BLEND_NORMAL) |
{ |
auto eq = [&](uint32_t pix1, uint32_t pix2) { |
return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight) < cfg.equalColorTolerance; |
}; |
auto dist = [&](uint32_t pix1, uint32_t pix2) { |
return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight); |
}; |
const bool doLineBlend = [&]() -> bool |
{ |
if (getBottomR(blend) >= BLEND_DOMINANT) |
return true; |
//make sure there is no second blending in an adjacent rotation for this pixel: handles insular pixels, mario eyes |
if (getTopR(blend) != BLEND_NONE && !eq(e, g)) //but support double-blending for 90� corners |
return false; |
if (getBottomL(blend) != BLEND_NONE && !eq(e, c)) |
return false; |
//no full blending for L-shapes; blend corner only (handles "mario mushroom eyes") |
if (!eq(e, i) && eq(g, h) && eq(h, i) && eq(i, f) && eq(f, c)) |
return false; |
return true; |
} (); |
const uint32_t px = dist(e, f) <= dist(e, h) ? f : h; //choose most similar color |
OutputMatrix<Scaler::scale, rotDeg> out(target, trgWidth); |
if (doLineBlend) |
{ |
const double fg = dist(f, g); //test sample: 70% of values max(fg, hc) / min(fg, hc) are between 1.1 and 3.7 with median being 1.9 |
const double hc = dist(h, c); // |
const bool haveShallowLine = cfg.steepDirectionThreshold * fg <= hc && e != g && d != g; |
const bool haveSteepLine = cfg.steepDirectionThreshold * hc <= fg && e != c && b != c; |
if (haveShallowLine) |
{ |
if (haveSteepLine) |
Scaler::blendLineSteepAndShallow(px, out); |
else |
Scaler::blendLineShallow(px, out); |
} |
else |
{ |
if (haveSteepLine) |
Scaler::blendLineSteep(px, out); |
else |
Scaler::blendLineDiagonal(px, out); |
} |
} |
else |
Scaler::blendCorner(px, out); |
} |
#undef a |
#undef b |
#undef c |
#undef d |
#undef e |
#undef f |
#undef g |
#undef h |
#undef i |
} |
template <class Scaler, class ColorDistance> //scaler policy: see "Scaler2x" reference implementation |
void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, const xbrz::ScalerCfg& cfg, int yFirst, int yLast) |
{ |
yFirst = std::max(yFirst, 0); |
yLast = std::min(yLast, srcHeight); |
if (yFirst >= yLast || srcWidth <= 0) |
return; |
const int trgWidth = srcWidth * Scaler::scale; |
//"use" space at the end of the image as temporary buffer for "on the fly preprocessing": we even could use larger area of |
//"sizeof(uint32_t) * srcWidth * (yLast - yFirst)" bytes without risk of accidental overwriting before accessing |
const int bufferSize = srcWidth; |
unsigned char* preProcBuffer = reinterpret_cast<unsigned char*>(trg + yLast * Scaler::scale * trgWidth) - bufferSize; |
std::fill(preProcBuffer, preProcBuffer + bufferSize, '\0'); |
static_assert(BLEND_NONE == 0, ""); |
//initialize preprocessing buffer for first row of current stripe: detect upper left and right corner blending |
//this cannot be optimized for adjacent processing stripes; we must not allow for a memory race condition! |
if (yFirst > 0) |
{ |
const int y = yFirst - 1; |
const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0); |
const uint32_t* s_0 = src + srcWidth * y;//center line |
const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1); |
const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1); |
for (int x = 0; x < srcWidth; ++x) |
{ |
const int x_m1 = std::max(x - 1, 0); |
const int x_p1 = std::min(x + 1, srcWidth - 1); |
const int x_p2 = std::min(x + 2, srcWidth - 1); |
Kernel_4x4 ker = {}; //perf: initialization is negligible |
ker.a = s_m1[x_m1]; //read sequentially from memory as far as possible |
ker.b = s_m1[x]; |
ker.c = s_m1[x_p1]; |
ker.d = s_m1[x_p2]; |
ker.e = s_0[x_m1]; |
ker.f = s_0[x]; |
ker.g = s_0[x_p1]; |
ker.h = s_0[x_p2]; |
ker.i = s_p1[x_m1]; |
ker.j = s_p1[x]; |
ker.k = s_p1[x_p1]; |
ker.l = s_p1[x_p2]; |
ker.m = s_p2[x_m1]; |
ker.n = s_p2[x]; |
ker.o = s_p2[x_p1]; |
ker.p = s_p2[x_p2]; |
const BlendResult res = preProcessCorners<ColorDistance>(ker, cfg); |
/* |
preprocessing blend result: |
--------- |
| F | G | //evalute corner between F, G, J, K |
----|---| //input pixel is at position F |
| J | K | |
--------- |
*/ |
setTopR(preProcBuffer[x], res.blend_j); |
if (x + 1 < bufferSize) |
setTopL(preProcBuffer[x + 1], res.blend_k); |
} |
} |
//------------------------------------------------------------------------------------ |
for (int y = yFirst; y < yLast; ++y) |
{ |
uint32_t* out = trg + Scaler::scale * y * trgWidth; //consider MT "striped" access |
const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0); |
const uint32_t* s_0 = src + srcWidth * y;//center line |
const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1); |
const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1); |
unsigned char blend_xy1 = 0; //corner blending for current (x, y + 1) position |
for (int x = 0; x < srcWidth; ++x, out += Scaler::scale) |
{ |
#ifndef NDEBUG |
breakIntoDebugger = debugPixelX == x && debugPixelY == y; |
#endif |
//all those bounds checks have only insignificant impact on performance! |
const int x_m1 = std::max(x - 1, 0); //perf: prefer array indexing to additional pointers! |
const int x_p1 = std::min(x + 1, srcWidth - 1); |
const int x_p2 = std::min(x + 2, srcWidth - 1); |
Kernel_4x4 ker4 = {}; //perf: initialization is negligible |
ker4.a = s_m1[x_m1]; //read sequentially from memory as far as possible |
ker4.b = s_m1[x]; |
ker4.c = s_m1[x_p1]; |
ker4.d = s_m1[x_p2]; |
ker4.e = s_0[x_m1]; |
ker4.f = s_0[x]; |
ker4.g = s_0[x_p1]; |
ker4.h = s_0[x_p2]; |
ker4.i = s_p1[x_m1]; |
ker4.j = s_p1[x]; |
ker4.k = s_p1[x_p1]; |
ker4.l = s_p1[x_p2]; |
ker4.m = s_p2[x_m1]; |
ker4.n = s_p2[x]; |
ker4.o = s_p2[x_p1]; |
ker4.p = s_p2[x_p2]; |
//evaluate the four corners on bottom-right of current pixel |
unsigned char blend_xy = 0; //for current (x, y) position |
{ |
const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg); |
/* |
preprocessing blend result: |
--------- |
| F | G | //evalute corner between F, G, J, K |
----|---| //current input pixel is at position F |
| J | K | |
--------- |
*/ |
blend_xy = preProcBuffer[x]; |
setBottomR(blend_xy, res.blend_f); //all four corners of (x, y) have been determined at this point due to processing sequence! |
setTopR(blend_xy1, res.blend_j); //set 2nd known corner for (x, y + 1) |
preProcBuffer[x] = blend_xy1; //store on current buffer position for use on next row |
blend_xy1 = 0; |
setTopL(blend_xy1, res.blend_k); //set 1st known corner for (x + 1, y + 1) and buffer for use on next column |
if (x + 1 < bufferSize) //set 3rd known corner for (x + 1, y) |
setBottomL(preProcBuffer[x + 1], res.blend_g); |
} |
//fill block of size scale * scale with the given color |
fillBlock(out, trgWidth * sizeof(uint32_t), ker4.f, Scaler::scale, Scaler::scale); |
//place *after* preprocessing step, to not overwrite the results while processing the the last pixel! |
//blend four corners of current pixel |
if (blendingNeeded(blend_xy)) //good 5% perf-improvement |
{ |
Kernel_3x3 ker3 = {}; //perf: initialization is negligible |
ker3.a = ker4.a; |
ker3.b = ker4.b; |
ker3.c = ker4.c; |
ker3.d = ker4.e; |
ker3.e = ker4.f; |
ker3.f = ker4.g; |
ker3.g = ker4.i; |
ker3.h = ker4.j; |
ker3.i = ker4.k; |
blendPixel<Scaler, ColorDistance, ROT_0 >(ker3, out, trgWidth, blend_xy, cfg); |
blendPixel<Scaler, ColorDistance, ROT_90 >(ker3, out, trgWidth, blend_xy, cfg); |
blendPixel<Scaler, ColorDistance, ROT_180>(ker3, out, trgWidth, blend_xy, cfg); |
blendPixel<Scaler, ColorDistance, ROT_270>(ker3, out, trgWidth, blend_xy, cfg); |
} |
} |
} |
} |
//------------------------------------------------------------------------------------ |
template <class ColorGradient> |
struct Scaler2x : public ColorGradient |
{ |
static const int scale = 2; |
template <unsigned int M, unsigned int N> //bring template function into scope for GCC |
static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { |
ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); |
} |
template <class OutputMatrix> |
static void blendLineShallow(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col); |
alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col); |
} |
template <class OutputMatrix> |
static void blendLineSteep(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); |
alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); |
} |
template <class OutputMatrix> |
static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 4>(out.template ref<1, 0>(), col); |
alphaGrad<1, 4>(out.template ref<0, 1>(), col); |
alphaGrad<5, 6>(out.template ref<1, 1>(), col); //[!] fixes 7/8 used in xBR |
} |
template <class OutputMatrix> |
static void blendLineDiagonal(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 2>(out.template ref<1, 1>(), col); |
} |
template <class OutputMatrix> |
static void blendCorner(uint32_t col, OutputMatrix& out) |
{ |
//model a round corner |
alphaGrad<21, 100>(out.template ref<1, 1>(), col); //exact: 1 - pi/4 = 0.2146018366 |
} |
}; |
template <class ColorGradient> |
struct Scaler3x : public ColorGradient |
{ |
static const int scale = 3; |
template <unsigned int M, unsigned int N> //bring template function into scope for GCC |
static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { |
ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); |
} |
template <class OutputMatrix> |
static void blendLineShallow(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col); |
alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col); |
alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col); |
out.template ref<scale - 1, 2>() = col; |
} |
template <class OutputMatrix> |
static void blendLineSteep(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); |
alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); |
alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); |
out.template ref<2, scale - 1>() = col; |
} |
template <class OutputMatrix> |
static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 4>(out.template ref<2, 0>(), col); |
alphaGrad<1, 4>(out.template ref<0, 2>(), col); |
alphaGrad<3, 4>(out.template ref<2, 1>(), col); |
alphaGrad<3, 4>(out.template ref<1, 2>(), col); |
out.template ref<2, 2>() = col; |
} |
template <class OutputMatrix> |
static void blendLineDiagonal(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 8>(out.template ref<1, 2>(), col); //conflict with other rotations for this odd scale |
alphaGrad<1, 8>(out.template ref<2, 1>(), col); |
alphaGrad<7, 8>(out.template ref<2, 2>(), col); // |
} |
template <class OutputMatrix> |
static void blendCorner(uint32_t col, OutputMatrix& out) |
{ |
//model a round corner |
alphaGrad<45, 100>(out.template ref<2, 2>(), col); //exact: 0.4545939598 |
//alphaGrad<7, 256>(out.template ref<2, 1>(), col); //0.02826017254 -> negligible + avoid conflicts with other rotations for this odd scale |
//alphaGrad<7, 256>(out.template ref<1, 2>(), col); //0.02826017254 |
} |
}; |
template <class ColorGradient> |
struct Scaler4x : public ColorGradient |
{ |
static const int scale = 4; |
template <unsigned int M, unsigned int N> //bring template function into scope for GCC |
static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { |
ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); |
} |
template <class OutputMatrix> |
static void blendLineShallow(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col); |
alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col); |
alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col); |
alphaGrad<3, 4>(out.template ref<scale - 2, 3>(), col); |
out.template ref<scale - 1, 2>() = col; |
out.template ref<scale - 1, 3>() = col; |
} |
template <class OutputMatrix> |
static void blendLineSteep(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); |
alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); |
alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); |
alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); |
out.template ref<2, scale - 1>() = col; |
out.template ref<3, scale - 1>() = col; |
} |
template <class OutputMatrix> |
static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<3, 4>(out.template ref<3, 1>(), col); |
alphaGrad<3, 4>(out.template ref<1, 3>(), col); |
alphaGrad<1, 4>(out.template ref<3, 0>(), col); |
alphaGrad<1, 4>(out.template ref<0, 3>(), col); |
alphaGrad<1, 3>(out.template ref<2, 2>(), col); //[!] fixes 1/4 used in xBR |
out.template ref<3, 3>() = col; |
out.template ref<3, 2>() = col; |
out.template ref<2, 3>() = col; |
} |
template <class OutputMatrix> |
static void blendLineDiagonal(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 2>(out.template ref<scale - 1, scale / 2 >(), col); |
alphaGrad<1, 2>(out.template ref<scale - 2, scale / 2 + 1>(), col); |
out.template ref<scale - 1, scale - 1>() = col; |
} |
template <class OutputMatrix> |
static void blendCorner(uint32_t col, OutputMatrix& out) |
{ |
//model a round corner |
alphaGrad<68, 100>(out.template ref<3, 3>(), col); //exact: 0.6848532563 |
alphaGrad< 9, 100>(out.template ref<3, 2>(), col); //0.08677704501 |
alphaGrad< 9, 100>(out.template ref<2, 3>(), col); //0.08677704501 |
} |
}; |
template <class ColorGradient> |
struct Scaler5x : public ColorGradient |
{ |
static const int scale = 5; |
template <unsigned int M, unsigned int N> //bring template function into scope for GCC |
static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { |
ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); |
} |
template <class OutputMatrix> |
static void blendLineShallow(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col); |
alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col); |
alphaGrad<1, 4>(out.template ref<scale - 3, 4>(), col); |
alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col); |
alphaGrad<3, 4>(out.template ref<scale - 2, 3>(), col); |
out.template ref<scale - 1, 2>() = col; |
out.template ref<scale - 1, 3>() = col; |
out.template ref<scale - 1, 4>() = col; |
out.template ref<scale - 2, 4>() = col; |
} |
template <class OutputMatrix> |
static void blendLineSteep(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); |
alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); |
alphaGrad<1, 4>(out.template ref<4, scale - 3>(), col); |
alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); |
alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); |
out.template ref<2, scale - 1>() = col; |
out.template ref<3, scale - 1>() = col; |
out.template ref<4, scale - 1>() = col; |
out.template ref<4, scale - 2>() = col; |
} |
template <class OutputMatrix> |
static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); |
alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); |
alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); |
alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col); |
alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col); |
alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col); |
alphaGrad<2, 3>(out.template ref<3, 3>(), col); |
out.template ref<2, scale - 1>() = col; |
out.template ref<3, scale - 1>() = col; |
out.template ref<4, scale - 1>() = col; |
out.template ref<scale - 1, 2>() = col; |
out.template ref<scale - 1, 3>() = col; |
} |
template <class OutputMatrix> |
static void blendLineDiagonal(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 8>(out.template ref<scale - 1, scale / 2 >(), col);//conflict with other rotations for this odd scale |
alphaGrad<1, 8>(out.template ref<scale - 2, scale / 2 + 1>(), col); |
alphaGrad<1, 8>(out.template ref<scale - 3, scale / 2 + 2>(), col); // |
alphaGrad<7, 8>(out.template ref<4, 3>(), col); |
alphaGrad<7, 8>(out.template ref<3, 4>(), col); |
out.template ref<4, 4>() = col; |
} |
template <class OutputMatrix> |
static void blendCorner(uint32_t col, OutputMatrix& out) |
{ |
//model a round corner |
alphaGrad<86, 100>(out.template ref<4, 4>(), col); //exact: 0.8631434088 |
alphaGrad<23, 100>(out.template ref<4, 3>(), col); //0.2306749731 |
alphaGrad<23, 100>(out.template ref<3, 4>(), col); //0.2306749731 |
//alphaGrad<1, 64>(out.template ref<4, 2>(), col); //0.01676812367 -> negligible + avoid conflicts with other rotations for this odd scale |
//alphaGrad<1, 64>(out.template ref<2, 4>(), col); //0.01676812367 |
} |
}; |
template <class ColorGradient> |
struct Scaler6x : public ColorGradient |
{ |
static const int scale = 6; |
template <unsigned int M, unsigned int N> //bring template function into scope for GCC |
static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { |
ColorGradient::template alphaGrad<M, N>(pixBack, pixFront); |
} |
template <class OutputMatrix> |
static void blendLineShallow(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col); |
alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col); |
alphaGrad<1, 4>(out.template ref<scale - 3, 4>(), col); |
alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col); |
alphaGrad<3, 4>(out.template ref<scale - 2, 3>(), col); |
alphaGrad<3, 4>(out.template ref<scale - 3, 5>(), col); |
out.template ref<scale - 1, 2>() = col; |
out.template ref<scale - 1, 3>() = col; |
out.template ref<scale - 1, 4>() = col; |
out.template ref<scale - 1, 5>() = col; |
out.template ref<scale - 2, 4>() = col; |
out.template ref<scale - 2, 5>() = col; |
} |
template <class OutputMatrix> |
static void blendLineSteep(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); |
alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); |
alphaGrad<1, 4>(out.template ref<4, scale - 3>(), col); |
alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); |
alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); |
alphaGrad<3, 4>(out.template ref<5, scale - 3>(), col); |
out.template ref<2, scale - 1>() = col; |
out.template ref<3, scale - 1>() = col; |
out.template ref<4, scale - 1>() = col; |
out.template ref<5, scale - 1>() = col; |
out.template ref<4, scale - 2>() = col; |
out.template ref<5, scale - 2>() = col; |
} |
template <class OutputMatrix> |
static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); |
alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); |
alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); |
alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); |
alphaGrad<1, 4>(out.template ref<scale - 1, 0>(), col); |
alphaGrad<1, 4>(out.template ref<scale - 2, 2>(), col); |
alphaGrad<3, 4>(out.template ref<scale - 1, 1>(), col); |
alphaGrad<3, 4>(out.template ref<scale - 2, 3>(), col); |
out.template ref<2, scale - 1>() = col; |
out.template ref<3, scale - 1>() = col; |
out.template ref<4, scale - 1>() = col; |
out.template ref<5, scale - 1>() = col; |
out.template ref<4, scale - 2>() = col; |
out.template ref<5, scale - 2>() = col; |
out.template ref<scale - 1, 2>() = col; |
out.template ref<scale - 1, 3>() = col; |
} |
template <class OutputMatrix> |
static void blendLineDiagonal(uint32_t col, OutputMatrix& out) |
{ |
alphaGrad<1, 2>(out.template ref<scale - 1, scale / 2 >(), col); |
alphaGrad<1, 2>(out.template ref<scale - 2, scale / 2 + 1>(), col); |
alphaGrad<1, 2>(out.template ref<scale - 3, scale / 2 + 2>(), col); |
out.template ref<scale - 2, scale - 1>() = col; |
out.template ref<scale - 1, scale - 1>() = col; |
out.template ref<scale - 1, scale - 2>() = col; |
} |
template <class OutputMatrix> |
static void blendCorner(uint32_t col, OutputMatrix& out) |
{ |
//model a round corner |
alphaGrad<97, 100>(out.template ref<5, 5>(), col); //exact: 0.9711013910 |
alphaGrad<42, 100>(out.template ref<4, 5>(), col); //0.4236372243 |
alphaGrad<42, 100>(out.template ref<5, 4>(), col); //0.4236372243 |
alphaGrad< 6, 100>(out.template ref<5, 3>(), col); //0.05652034508 |
alphaGrad< 6, 100>(out.template ref<3, 5>(), col); //0.05652034508 |
} |
}; |
//------------------------------------------------------------------------------------ |
struct ColorDistanceRGB |
{ |
static double dist(uint32_t pix1, uint32_t pix2, double luminanceWeight) |
{ |
return distYCbCrBuffered(pix1, pix2); |
//if (pix1 == pix2) //about 4% perf boost |
// return 0; |
//return distYCbCr(pix1, pix2, luminanceWeight); |
} |
}; |
struct ColorDistanceARGB |
{ |
static double dist(uint32_t pix1, uint32_t pix2, double luminanceWeight) |
{ |
const double a1 = getAlpha(pix1) / 255.0; |
const double a2 = getAlpha(pix2) / 255.0; |
/* |
Requirements for a color distance handling alpha channel: with a1, a2 in [0, 1] |
1. if a1 = a2, distance should be: a1 * distYCbCr() |
2. if a1 = 0, distance should be: a2 * distYCbCr(black, white) = a2 * 255 |
3. if a1 = 1, ??? maybe: 255 * (1 - a2) + a2 * distYCbCr() |
*/ |
//return std::min(a1, a2) * distYCbCrBuffered(pix1, pix2) + 255 * abs(a1 - a2); |
//=> following code is 15% faster: |
const double d = distYCbCrBuffered(pix1, pix2); |
if (a1 < a2) |
return a1 * d + 255 * (a2 - a1); |
else |
return a2 * d + 255 * (a1 - a2); |
//alternative? return std::sqrt(a1 * a2 * square(distYCbCrBuffered(pix1, pix2)) + square(255 * (a1 - a2))); |
} |
}; |
struct ColorGradientRGB |
{ |
template <unsigned int M, unsigned int N> |
static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) |
{ |
pixBack = gradientRGB<M, N>(pixFront, pixBack); |
} |
}; |
struct ColorGradientARGB |
{ |
template <unsigned int M, unsigned int N> |
static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) |
{ |
pixBack = gradientARGB<M, N>(pixFront, pixBack); |
} |
}; |
} |
void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, ColorFormat colFmt, const xbrz::ScalerCfg& cfg, int yFirst, int yLast) |
{ |
switch (colFmt) |
{ |
case ColorFormat::ARGB: |
switch (factor) |
{ |
case 2: |
return scaleImage<Scaler2x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); |
case 3: |
return scaleImage<Scaler3x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); |
case 4: |
return scaleImage<Scaler4x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); |
case 5: |
return scaleImage<Scaler5x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); |
case 6: |
return scaleImage<Scaler6x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); |
} |
break; |
case ColorFormat::RGB: |
switch (factor) |
{ |
case 2: |
return scaleImage<Scaler2x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); |
case 3: |
return scaleImage<Scaler3x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); |
case 4: |
return scaleImage<Scaler4x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); |
case 5: |
return scaleImage<Scaler5x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); |
case 6: |
return scaleImage<Scaler6x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); |
} |
break; |
} |
assert(false); |
} |
bool xbrz::equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, double luminanceWeight, double equalColorTolerance) |
{ |
switch (colFmt) |
{ |
case ColorFormat::ARGB: |
return ColorDistanceARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance; |
case ColorFormat::RGB: |
return ColorDistanceRGB::dist(col1, col2, luminanceWeight) < equalColorTolerance; |
} |
assert(false); |
return false; |
} |
void xbrz::nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, |
uint32_t* trg, int trgWidth, int trgHeight) |
{ |
nearestNeighborScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t), |
trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t), |
SliceType::TARGET, 0, trgHeight, [](uint32_t pix) { |
return pix; |
}); |
} |
/contrib/games/hydracastlelabyrinth/src/xBRZ/xbrz.h |
---|
0,0 → 1,73 |
// **************************************************************************** |
// * This file is part of the HqMAME project. It is distributed under * |
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 * |
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * |
// * * |
// * Additionally and as a special exception, the author gives permission * |
// * to link the code of this program with the MAME library (or with modified * |
// * versions of MAME that use the same license as MAME), and distribute * |
// * linked combinations including the two. You must obey the GNU General * |
// * Public License in all respects for all of the code used other than MAME. * |
// * If you modify this file, you may extend this exception to your version * |
// * of the file, but you are not obligated to do so. If you do not wish to * |
// * do so, delete this exception statement from your version. * |
// **************************************************************************** |
#ifndef XBRZ_HEADER_3847894708239054 |
#define XBRZ_HEADER_3847894708239054 |
#include <cstddef> //size_t |
#include <cstdint> //uint32_t |
#include <limits> |
#include "xbrz_config.h" |
namespace xbrz |
{ |
/* |
------------------------------------------------------------------------- |
| xBRZ: "Scale by rules" - high quality image upscaling filter by Zenju | |
------------------------------------------------------------------------- |
using a modified approach of xBR: |
http://board.byuu.org/viewtopic.php?f=10&t=2248 |
- new rule set preserving small image features |
- highly optimized for performance |
- support alpha channel |
- support multithreading |
- support 64-bit architectures |
- support processing image slices |
- support scaling up to 6xBRZ |
*/ |
enum class ColorFormat //from high bits -> low bits, 8 bit per channel |
{ |
RGB, //8 bit for each red, green, blue, upper 8 bits unused |
ARGB, //including alpha channel, BGRA byte order on little-endian machines |
}; |
/* |
-> map source (srcWidth * srcHeight) to target (scale * width x scale * height) image, optionally processing a half-open slice of rows [yFirst, yLast) only |
-> support for source/target pitch in bytes! |
-> if your emulator changes only a few image slices during each cycle (e.g. DOSBox) then there's no need to run xBRZ on the complete image: |
Just make sure you enlarge the source image slice by 2 rows on top and 2 on bottom (this is the additional range the xBRZ algorithm is using during analysis) |
CAVEAT: If there are multiple changed slices, make sure they do not overlap after adding these additional rows in order to avoid a memory race condition |
in the target image data if you are using multiple threads for processing each enlarged slice! |
THREAD-SAFETY: - parts of the same image may be scaled by multiple threads as long as the [yFirst, yLast) ranges do not overlap! |
- there is a minor inefficiency for the first row of a slice, so avoid processing single rows only; suggestion: process at least 8-16 rows |
*/ |
void scale(size_t factor, //valid range: 2 - 6 |
const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, |
ColorFormat colFmt, |
const ScalerCfg& cfg = ScalerCfg(), |
int yFirst = 0, int yLast = std::numeric_limits<int>::max()); //slice of source image |
void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, |
/**/ uint32_t* trg, int trgWidth, int trgHeight); |
//parameter tuning |
bool equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, double luminanceWeight, double equalColorTolerance); |
} |
#endif |
/contrib/games/hydracastlelabyrinth/src/xBRZ/xbrz_config.h |
---|
0,0 → 1,33 |
// **************************************************************************** |
// * This file is part of the HqMAME project. It is distributed under * |
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 * |
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * |
// * * |
// * Additionally and as a special exception, the author gives permission * |
// * to link the code of this program with the MAME library (or with modified * |
// * versions of MAME that use the same license as MAME), and distribute * |
// * linked combinations including the two. You must obey the GNU General * |
// * Public License in all respects for all of the code used other than MAME. * |
// * If you modify this file, you may extend this exception to your version * |
// * of the file, but you are not obligated to do so. If you do not wish to * |
// * do so, delete this exception statement from your version. * |
// **************************************************************************** |
#ifndef XBRZ_CONFIG_HEADER_284578425345 |
#define XBRZ_CONFIG_HEADER_284578425345 |
//do NOT include any headers here! used by xBRZ_dll!!! |
namespace xbrz |
{ |
struct ScalerCfg |
{ |
double luminanceWeight = 1; |
double equalColorTolerance = 30; |
double dominantDirectionThreshold = 3.6; |
double steepDirectionThreshold = 2.2; |
double newTestAttribute = 0;//unused; test new parameters |
}; |
} |
#endif |
/contrib/games/hydracastlelabyrinth/src/xBRZ/xbrz_tools.h |
---|
0,0 → 1,177 |
// **************************************************************************** |
// * This file is part of the HqMAME project. It is distributed under * |
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 * |
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * |
// * * |
// * Additionally and as a special exception, the author gives permission * |
// * to link the code of this program with the MAME library (or with modified * |
// * versions of MAME that use the same license as MAME), and distribute * |
// * linked combinations including the two. You must obey the GNU General * |
// * Public License in all respects for all of the code used other than MAME. * |
// * If you modify this file, you may extend this exception to your version * |
// * of the file, but you are not obligated to do so. If you do not wish to * |
// * do so, delete this exception statement from your version. * |
// **************************************************************************** |
#ifndef XBRZ_TOOLS_H_825480175091875 |
#define XBRZ_TOOLS_H_825480175091875 |
#include <cassert> |
#include <algorithm> |
#include <type_traits> |
namespace xbrz |
{ |
template <uint32_t N> inline |
unsigned char getByte(uint32_t val) { |
return static_cast<unsigned char>((val >> (8 * N)) & 0xff); |
} |
inline unsigned char getAlpha(uint32_t pix) { |
return getByte<3>(pix); |
} |
inline unsigned char getRed (uint32_t pix) { |
return getByte<2>(pix); |
} |
inline unsigned char getGreen(uint32_t pix) { |
return getByte<1>(pix); |
} |
inline unsigned char getBlue (uint32_t pix) { |
return getByte<0>(pix); |
} |
inline uint32_t makePixel(unsigned char a, unsigned char r, unsigned char g, unsigned char b) { |
return (a << 24) | (r << 16) | (g << 8) | b; |
} |
inline uint32_t makePixel( unsigned char r, unsigned char g, unsigned char b) { |
return (r << 16) | (g << 8) | b; |
} |
inline uint32_t rgb555to888(uint16_t pix) { |
return ((pix & 0x7C00) << 9) | ((pix & 0x03E0) << 6) | ((pix & 0x001F) << 3); |
} |
inline uint32_t rgb565to888(uint16_t pix) { |
return ((pix & 0xF800) << 8) | ((pix & 0x07E0) << 5) | ((pix & 0x001F) << 3); |
} |
inline uint16_t rgb888to555(uint32_t pix) { |
return static_cast<uint16_t>(((pix & 0xF80000) >> 9) | ((pix & 0x00F800) >> 6) | ((pix & 0x0000F8) >> 3)); |
} |
inline uint16_t rgb888to565(uint32_t pix) { |
return static_cast<uint16_t>(((pix & 0xF80000) >> 8) | ((pix & 0x00FC00) >> 5) | ((pix & 0x0000F8) >> 3)); |
} |
template <class Pix> inline |
Pix* byteAdvance(Pix* ptr, int bytes) |
{ |
using PixNonConst = typename std::remove_cv<Pix>::type; |
using PixByte = typename std::conditional<std::is_same<Pix, PixNonConst>::value, char, const char>::type; |
static_assert(std::is_integral<PixNonConst>::value, "Pix* is expected to be cast-able to char*"); |
return reinterpret_cast<Pix*>(reinterpret_cast<PixByte*>(ptr) + bytes); |
} |
//fill block with the given color |
template <class Pix> inline |
void fillBlock(Pix* trg, int pitch, Pix col, int blockWidth, int blockHeight) |
{ |
//for (int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch)) |
// std::fill(trg, trg + blockWidth, col); |
for (int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch)) |
for (int x = 0; x < blockWidth; ++x) |
trg[x] = col; |
} |
enum class SliceType |
{ |
SOURCE, |
TARGET, |
}; |
template <class PixSrc, class PixTrg, class PixConverter> |
void nearestNeighborScale(const PixSrc* src, int srcWidth, int srcHeight, int srcPitch, |
/**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch, |
SliceType st, int yFirst, int yLast, PixConverter pixCvrt /*convert PixSrc to PixTrg*/) |
{ |
static_assert(std::is_integral<PixSrc>::value, "PixSrc* is expected to be cast-able to char*"); |
static_assert(std::is_integral<PixTrg>::value, "PixTrg* is expected to be cast-able to char*"); |
static_assert(std::is_same<decltype(pixCvrt(PixSrc())), PixTrg>::value, "PixConverter returning wrong pixel format"); |
if (srcPitch < srcWidth * static_cast<int>(sizeof(PixSrc)) || |
trgPitch < trgWidth * static_cast<int>(sizeof(PixTrg))) |
{ |
assert(false); |
return; |
} |
switch (st) |
{ |
case SliceType::SOURCE: |
//nearest-neighbor (going over source image - fast for upscaling, since source is read only once |
yFirst = std::max(yFirst, 0); |
yLast = std::min(yLast, srcHeight); |
if (yFirst >= yLast || trgWidth <= 0 || trgHeight <= 0) return; |
for (int y = yFirst; y < yLast; ++y) |
{ |
//mathematically: ySrc = floor(srcHeight * yTrg / trgHeight) |
// => search for integers in: [ySrc, ySrc + 1) * trgHeight / srcHeight |
//keep within for loop to support MT input slices! |
const int yTrg_first = ( y * trgHeight + srcHeight - 1) / srcHeight;//=ceil(y * trgHeight / srcHeight) |
const int yTrg_last = ((y + 1) * trgHeight + srcHeight - 1) / srcHeight;//=ceil(((y + 1) * trgHeight) / srcHeight) |
const int blockHeight = yTrg_last - yTrg_first; |
if (blockHeight > 0) |
{ |
const PixSrc* srcLine = byteAdvance(src, y * srcPitch); |
/**/ PixTrg* trgLine = byteAdvance(trg, yTrg_first * trgPitch); |
int xTrg_first = 0; |
for (int x = 0; x < srcWidth; ++x) |
{ |
const int xTrg_last = ((x + 1) * trgWidth + srcWidth - 1) / srcWidth; |
const int blockWidth = xTrg_last - xTrg_first; |
if (blockWidth > 0) |
{ |
xTrg_first = xTrg_last; |
const auto trgPix = pixCvrt(srcLine[x]); |
fillBlock(trgLine, trgPitch, trgPix, blockWidth, blockHeight); |
trgLine += blockWidth; |
} |
} |
} |
} |
break; |
case SliceType::TARGET: |
//nearest-neighbor (going over target image - slow for upscaling, since source is read multiple times missing out on cache! Fast for similar image sizes!) |
yFirst = std::max(yFirst, 0); |
yLast = std::min(yLast, trgHeight); |
if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0) return; |
for (int y = yFirst; y < yLast; ++y) |
{ |
PixTrg* trgLine = byteAdvance(trg, y * trgPitch); |
const int ySrc = srcHeight * y / trgHeight; |
const PixSrc* srcLine = byteAdvance(src, ySrc * srcPitch); |
for (int x = 0; x < trgWidth; ++x) |
{ |
const int xSrc = srcWidth * x / trgWidth; |
trgLine[x] = pixCvrt(srcLine[xSrc]); |
} |
} |
break; |
} |
} |
} |
#endif //XBRZ_TOOLS_H_825480175091875 |