Added OpenTyrian sources - it does not work yet

This commit is contained in:
pelya
2010-07-30 13:10:35 +03:00
parent 0974a79a6d
commit fb4801bb59
127 changed files with 48194 additions and 26 deletions

View File

@@ -3,5 +3,5 @@
# Set here your own NDK path if needed
# export PATH=$PATH:~/src/endless_space/android-ndk-r4
cd project && nice -n5 ndk-build V=1 -j2 && ant debug && cd bin && adb install -r DemoActivity-debug.apk
cd project && nice -n5 ndk-build V=1 && ant debug && cd bin && adb install -r DemoActivity-debug.apk

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.sourceforge.jooleem"
android:versionCode="01404"
android:versionName="0.1.4.04"
package="com.googlecode.opentyrian"
android:versionCode="2101"
android:versionName="2.1.01"
>
<application android:label="@string/app_name"
android:icon="@drawable/icon"

View File

@@ -1,6 +1,6 @@
# The namespace in Java file, with dots replaced with underscores
SDL_JAVA_PACKAGE_PATH := net_sourceforge_jooleem
SDL_JAVA_PACKAGE_PATH := com_googlecode_opentyrian
# Path to shared libraries - Android 1.6 cannot load them properly, thus we have to specify absolute path here
# SDL_SHARED_LIBRARIES_PATH := /data/data/de.schwardtnet.alienblaster/lib
@@ -10,7 +10,7 @@ SDL_JAVA_PACKAGE_PATH := net_sourceforge_jooleem
# Typically /sdcard/alienblaster
# Or /data/data/de.schwardtnet.alienblaster/files if you're planning to unpack data in application private folder
# Your application will just set current directory there
SDL_CURDIR_PATH := net.sourceforge.jooleem
SDL_CURDIR_PATH := com.googlecode.opentyrian
# Android Dev Phone G1 has trackball instead of cursor keys, and
# sends trackball movement events as rapid KeyDown/KeyUp events,
@@ -23,7 +23,7 @@ SDL_TRACKBALL_KEYUP_DELAY := 1
# resized in HW-accelerated way, however it eats a tiny bit of CPU
SDL_VIDEO_RENDER_RESIZE := 1
COMPILED_LIBRARIES := sdl_mixer sdl_image sdl_ttf
COMPILED_LIBRARIES := sdl_net
APPLICATION_ADDITIONAL_CFLAGS := -finline-functions -O2

View File

@@ -5,6 +5,6 @@ APP_PROJECT_PATH := $(call my-dir)/..
# sdl_image depends on png and jpeg
# sdl_ttf depends on freetype
APP_MODULES := application sdl sdl_main stlport tremor png jpeg freetype sdl_mixer sdl_image sdl_ttf
APP_MODULES := application sdl sdl_main stlport tremor png jpeg freetype sdl_net
APP_ABI := armeabi

View File

@@ -48,7 +48,7 @@ SdlCompat_AcceleratedSurface *Video::init(){
__android_log_print(ANDROID_LOG_ERROR, "Alien Blaster", "Couldn't initialize SDL video subsystem: %s\n", SDL_GetError());
exit(1);
}
SDL_Surface * screen2 = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, BIT_DEPTH, SDL_DOUBLEBUF /* | SDL_FULLSCREEN */ );
SDL_Surface * screen2 = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, BIT_DEPTH, SDL_DOUBLEBUF | SDL_HWSURFACE );
if (!screen2) {
printf("Couldn't set %dx%d, %dbit video mode: %s\n", SCREEN_WIDTH, SCREEN_HEIGHT, BIT_DEPTH, SDL_GetError());
__android_log_print(ANDROID_LOG_ERROR, "Alien Blaster", "Couldn't set %dx%d, %dbit video mode: %s\n", SCREEN_WIDTH, SCREEN_HEIGHT, BIT_DEPTH, SDL_GetError());

View File

@@ -0,0 +1,16 @@
LibSdlVersion=1.2
AppName="OpenTyrian"
AppFullName=com.googlecode.opentyrian
ScreenOrientation=h
AppDataDownloadUrl="http://sites.google.com/site/xpelyax/Home/tyrian21-data.zip?attredirects=0&d=1|http://sitesproxy.goapk.com/site/xpelyax/Home/tyrian21-data.zip"
SdlVideoResize=y
NeedDepthBuffer=n
AppUsesMouse=n
AppNeedsArrowKeys=y
AppUsesJoystick=n
MultiABI=n
AppVersionCode=2101
AppVersionName="2.1.01"
CompiledLibraries="sdl_net"
AppCflags='-finline-functions -O2'
ReadmeText='^You may press "Home" now - the data will be downloaded in background'

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.

View File

@@ -0,0 +1,31 @@
OpenTyrian Classic Development Team
================================================================================
Carl W. Reinke <mindless2112\100gmail\056com> (Mindless)
Yuri K. Schlesner <yuriks.br@gmail.com> (yuriks)
Casey A. McCann <syntaxglitch@gmail.com> (syntaxglitch)
== Contributors ================================================================
awoodland patch that fixed 64-bit support
simx added Mac OS X support
filmor updated Mac OS X support
Tony Vroon patch that made Makefile more packager-friendly
jeff250 patch that fixed a buffer overflow
a.h.vandijk patch that fixed a buffer overflow,
patch that fixed an input handling bug,
patch that fixed some handling of unprintable characters
ECA Destruct rewrite
spudd86.2 patch that fixed an audio bug
Jan "heftig" Steffens clean-up patches
== Further Thanks ==============================================================
Jason Emery
* Tyrian source code
MAME and DOSBox
* FM emulator code
AdPlug
* Loudness player

View File

@@ -0,0 +1,15 @@
06/02/2007
HOLOVID RELEASE ALPHA 01
Breaking News
Authorities report that a Gencore special task force, working from a secret
lab at Deliani, are engaged in a project to reimplent the historically
significant "videogame" entitled ~Tyrian~, a work regarded by historians as
a cultural artifact of utmost importance, and by the Church of Zinglon as a
holy prophecy. News of this effort have caused uproar through the galaxy,
but Gencore remains silent on the matter and officially-released details are
sparse. When approached for comment, Gencore Chancellor Transon Lohk
replied, "Who are you and what are you doing in my house? Get out!"
Stay tuned for updates to this galaxy-shaking event!

View File

@@ -0,0 +1,49 @@
OpenTyrian Classic
================================================================================
OpenTyrian is an open-source port of the DOS game Tyrian.
Tyrian is an arcade-style vertical scrolling shooter. The story is set
in 20,031 where you play as Trent Hawkins, a skilled fighter-pilot employed
to fight MicroSol and save the galaxy.
Tyrian features a story mode, one- and two-player arcade modes, and networked
multiplayer.
== Additional Necessary Files ==================================================
Tyrian 2.1 data files which have been released as freeware:
http://camanis.net/tyrian/tyrian21.zip
== Keyboard Controls ===========================================================
ctrl-backspace -- kill OpenTyrian
alt-enter -- fullscreen
ctrl-f10 -- ungrab mouse
arrow keys -- ship movement
space -- fire weapons
enter -- toggle rear weapon mode
ctrl/alt -- fire left/right sidekick
== Network Multiplayer =========================================================
Currently OpenTyrian does not have an arena; as such, networked games must be
initiated manually via the command line simultaniously by both players.
syntax:
opentyrian --net HOSTNAME --net-player-name NAME --net-player-number NUMBER
where HOSTNAME is the IP address of your opponent, NUMBER is either 1 or 2
depending on which ship you intend to pilot, and NAME is your alias
OpenTyrian uses UDP port 1333 for multiplayer, but in most cases players will
not need to open any ports because OpenTyrian makes use of UDP hole punching.
== Links =======================================================================
project: http://opentyrian.googlecode.com/
irc: irc://irc.freenode.net/#tyrian
forums: http://tyrian2k.proboards.com/index.cgi?board=opentyriangeneral
README: AshTR

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -0,0 +1,431 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "animlib.h"
#include "file.h"
#include "keyboard.h"
#include "network.h"
#include "nortsong.h"
#include "palette.h"
#include "sizebuf.h"
#include "video.h"
#include <assert.h>
/*** Structs ***/
/* The actual header has a lot of fields that are basically useless to us since
* we both set our own framerate and the format itself only allows for
* 320x200x8. Should a (nonexistent) ani be played that doesn't have the same
* assumed values we are going to use, TOO BAD. It'll just be treated as
* corrupt in playback.
*/
#define PALETTE_OFFSET 0x100 // 128 + sizeof(header)
#define PAGEHEADER_OFFSET 0x500 // PALETTE_OFFSET + sizeof(palette)
#define ANIM_OFFSET 0x0B00 // PAGEHEADER_OFFSET + sizeof(largepageheader) * 256
#define ANI_PAGE_SIZE 0x10000 // 65536.
typedef struct anim_FileHeader_s
{
unsigned int nlps; /* Number of 'pages', max 256. */
unsigned int nRecords; /* Number of 'records', max 65535 */
} anim_FileHeader_t;
typedef struct anim_LargePageHeader_s
{
unsigned int baseRecord; /* The first record's number */
unsigned int nRecords; /* Number of records. Supposedly there are bit flags but I saw no such code */
unsigned int nBytes; /* Number of bytes used, excluding headers */
} anim_LargePageHeader_t;
/*** Globals ***/
Uint8 CurrentPageBuffer[65536];
anim_LargePageHeader_t PageHeader[256];
unsigned int CurrentPageRecordSizes[256];
anim_LargePageHeader_t CurrentPageHeader;
anim_FileHeader_t FileHeader;
unsigned int Curlpnum;
FILE * InFile;
/*** Function decs ***/
int JE_playRunSkipDump( Uint8 *, unsigned int );
void JE_closeAnim( void );
int JE_loadAnim( const char * );
int JE_renderFrame( unsigned int );
int JE_findPage ( unsigned int );
int JE_drawFrame( unsigned int );
int JE_loadPage( unsigned int );
/*** Implementation ***/
/* Loads the given page into memory.
*
* Returns 0 on success or nonzero on failure (bad data)
*/
int JE_loadPage( unsigned int pagenumber )
{
unsigned int i, pageSize;
if (Curlpnum == pagenumber) { return(0); } /* Already loaded */
Curlpnum = pagenumber;
/* We need to seek to the page and load it into our buffer.
* Pages have a fixed size of 0x10000; any left over space is padded
* unless it's the end of the file.
*
* Pages repeat their headers for some reason. They then have two bytes of
* padding folowed by a word for every record. THEN the data starts.
*/
fseek(InFile, ANIM_OFFSET + (pagenumber * ANI_PAGE_SIZE), SEEK_SET);
efread(&CurrentPageHeader.baseRecord, 2, 1, InFile);
efread(&CurrentPageHeader.nRecords, 2, 1, InFile);
efread(&CurrentPageHeader.nBytes, 2, 1, InFile);
fseek(InFile, 2, SEEK_CUR);
for (i = 0; i < CurrentPageHeader.nRecords; i++)
{
efread(&CurrentPageRecordSizes[i], 2, 1, InFile);
}
/* What remains is the 'compressed' data */
efread(CurrentPageBuffer, 1, CurrentPageHeader.nBytes, InFile);
/* Okay, we've succeeded in all our IO checks. Now, make sure the
* headers aren't lying or damaged or something.
*/
pageSize = 0;
for (i = 0; i < CurrentPageHeader.nRecords; i++)
{
pageSize += CurrentPageRecordSizes[i];
}
if(pageSize != CurrentPageHeader.nBytes) { return(-1); }
/* So far, so good */
return(0);
}
int JE_drawFrame( unsigned int framenumber )
{
int ret;
ret = JE_loadPage(framenumber);
if (ret) { return(ret); }
ret = JE_renderFrame (framenumber);
if (ret) { return(ret); }
return(0);
}
int JE_findPage( unsigned int framenumber )
{
unsigned int i;
for (i = 0; i < FileHeader.nlps; i++)
{
if (PageHeader[i].baseRecord <= framenumber
&& PageHeader[i].baseRecord + PageHeader[i].nRecords > framenumber)
{
return(i);
}
}
return(-1); /* Did not find */
}
int JE_renderFrame( unsigned int framenumber )
{
unsigned int i, offset, destframe;
destframe = framenumber - CurrentPageHeader.baseRecord;
offset = 0;
for (i = 0; i < destframe; i++)
{
offset += CurrentPageRecordSizes[i];
}
return (JE_playRunSkipDump(CurrentPageBuffer + offset + 4, CurrentPageRecordSizes[destframe] - 4));
}
void JE_playAnim( const char *animfile, JE_byte startingframe, JE_byte speed )
{
unsigned int i;
int pageNum;
if (JE_loadAnim(animfile) != 0)
{
return; /* Failed to open or process file */
}
/* Blank screen */
JE_clr256(VGAScreen);
JE_showVGA();
/* re FileHeader.nRecords-1: It's -1 in the pascal too.
* The final frame is a delta of the first, and we don't need that.
* We could also, if we ever ended up needing to loop anis, check
* the bools in the header to see if we should render the last
* frame. But that's never going to be encessary :)
*/
for (i = startingframe; i < FileHeader.nRecords-1; i++)
{
/* Handle boring crap */
setjasondelay(speed);
/* Load required frame. The loading function is smart enough to not re-load an already loaded frame */
pageNum = JE_findPage(i);
if(pageNum == -1) { break; }
if (JE_loadPage(pageNum) != 0) { break; }
/* render frame. */
if (JE_renderFrame(i) != 0) { break; }
JE_showVGA();
/* Return early if user presses a key */
service_SDL_events(true);
if (newkey)
{
break;
}
/* Wait until we need the next frame */
NETWORK_KEEP_ALIVE();
wait_delay();
}
JE_closeAnim();
}
/* loadAnim opens the file and loads data from it into the header structs.
* It should take care to clean up after itself should an error occur.
*/
int JE_loadAnim( const char *filename )
{
unsigned int i, fileSize;
char temp[4];
Curlpnum = -1;
InFile = dir_fopen(data_dir(), filename, "rb");
if(InFile == NULL)
{
return(-1);
}
fileSize = ftell_eof(InFile);
if(fileSize < ANIM_OFFSET)
{
/* We don't know the exact size our file should be yet,
* but we do know it should be way more than this */
fclose(InFile);
return(-1);
}
/* Read in the header. The header is 256 bytes long or so,
* but that includes a lot of padding as well as several
* vars we really don't care about. We shall check the ID and extract
* the handful of vars we care about. Every value in the header that
* is constant will be ignored.
*/
efread(&temp, 1, 4, InFile); /* The ID, should equal "LPF " */
fseek(InFile, 2, SEEK_CUR); /* skip over this word */
efread(&FileHeader.nlps, 2, 1, InFile); /* Number of pages */
efread(&FileHeader.nRecords, 4, 1, InFile); /* Number of records */
if (memcmp(temp, "LPF ", 4) != 0
|| FileHeader.nlps == 0 || FileHeader.nRecords == 0
|| FileHeader.nlps > 256 || FileHeader.nRecords > 65535)
{
fclose(InFile);
return(-1);
}
/* Read in headers */
fseek(InFile, PAGEHEADER_OFFSET, SEEK_SET);
for (i = 0; i < FileHeader.nlps; i++)
{
efread(&PageHeader[i].baseRecord, 2, 1, InFile);
efread(&PageHeader[i].nRecords, 2, 1, InFile);
efread(&PageHeader[i].nBytes, 2, 1, InFile);
}
/* Now we have enough information to calculate the 'expected' file size.
* Our calculation SHOULD be equal to fileSize, but we won't begrudge
* padding */
if (fileSize < (FileHeader.nlps-1) * ANI_PAGE_SIZE + ANIM_OFFSET
+ PageHeader[FileHeader.nlps-1].nBytes
+ PageHeader[FileHeader.nlps-1].nRecords * 2 + 8)
{
fclose(InFile);
return(-1);
}
/* Now read in the palette. */
fseek(InFile, PALETTE_OFFSET, SEEK_SET);
for (i = 0; i < 256; i++)
{
efread(&colors[i].b, 1, 1, InFile);
efread(&colors[i].g, 1, 1, InFile);
efread(&colors[i].r, 1, 1, InFile);
efread(&colors[i].unused, 1, 1, InFile);
}
set_palette(colors, 0, 255);
/* Whew! That was hard. Let's go grab some beers! */
return(0);
}
void JE_closeAnim( void )
{
fclose(InFile);
}
/* RunSkipDump decompresses the video. There are three operations, run, skip,
* and dump. They can be used in either byte or word variations, making six
* possible actions, and there's a seventh 'stop' action, which looks
* like 0x80 0x00 0x00.
*
* Run is a memset.
* Dump is a memcpy.
* Skip leaves the old data intact and simply increments the pointers.
*
* returns 0 on success or 1 if decompressing failed. Failure to decompress
* indicates a broken or malicious file; playback should terminate.
*/
int JE_playRunSkipDump( Uint8 *incomingBuffer, unsigned int IncomingBufferLength )
{
sizebuf_t Buffer_IN, Buffer_OUT;
sizebuf_t * pBuffer_IN = &Buffer_IN, * pBuffer_OUT = &Buffer_OUT;
#define ANI_SHORT_RLE 0x00
#define ANI_SHORT_SKIP 0x80
#define ANI_LONG_OP 0x80
#define ANI_LONG_COPY_OR_RLE 0x8000
#define ANI_LONG_RLE 0x4000
#define ANI_STOP 0x0000
SZ_Init(pBuffer_IN, incomingBuffer, IncomingBufferLength);
SZ_Init(pBuffer_OUT, (Uint8 *)VGAScreen->pixels, VGAScreen->h * VGAScreen->pitch);
/* 320x200 is the only supported format.
* Assert is here as a hint should our screen size ever changes.
* As for how to decompress to the wrong screen size... */
assert(VGAScreen->h * VGAScreen->pitch == 320 * 200);
while (1)
{
/* Get one byte. This byte may have flags that tell us more */
unsigned int opcode = MSG_ReadByte(pBuffer_IN);
/* Before we continue, check the error states/
* We should *probably* check these after every read and write, but
* I've rigged it so that the buffers will never go out of bounds.
* So we can afford to be lazy; if the buffer overflows below it will
* silently fail its writes and we'll catch the failure on our next
* run through the loop. A failure means we should be
* leaving ANYWAY. The contents of our buffers doesn't matter.
*/
if (SZ_Error(pBuffer_IN) || SZ_Error(pBuffer_OUT))
{
return(-1);
}
/* Divide into 'short' and 'long' */
if (opcode == ANI_LONG_OP) /* long ops */
{
opcode = MSG_ReadWord(pBuffer_IN);
if (opcode == ANI_STOP) /* We are done decompressing. Leave */
{
break;
}
else if (!(opcode & ANI_LONG_COPY_OR_RLE)) /* If it's not those two, it's a skip */
{
unsigned int count = opcode;
SZ_Seek(pBuffer_OUT, count, SEEK_CUR);
}
else /* Now things get a bit more interesting... */
{
opcode &= ~ANI_LONG_COPY_OR_RLE; /* Clear that flag */
if (opcode & ANI_LONG_RLE) /* RLE */
{
unsigned int count = opcode & ~ANI_LONG_RLE; /* Clear flag */
/* Extract another byte */
unsigned int value = MSG_ReadByte(pBuffer_IN);
/* The actual run */
SZ_Memset(pBuffer_OUT, value, count);
}
else
{ /* Long copy */
unsigned int count = opcode;
/* Copy */
SZ_Memcpy2(pBuffer_OUT, pBuffer_IN, count);
}
}
} /* End of long ops */
else /* short ops */
{
if (opcode & ANI_SHORT_SKIP) /* Short skip, move pointer only */
{
unsigned int count = opcode & ~ANI_SHORT_SKIP; /* clear flag to get count */
SZ_Seek(pBuffer_OUT, count, SEEK_CUR);
}
else if (opcode == ANI_SHORT_RLE) /* Short RLE, memset the destination */
{
/* Extract a few more bytes */
unsigned int count = MSG_ReadByte(pBuffer_IN);
unsigned int value = MSG_ReadByte(pBuffer_IN);
/* Run */
SZ_Memset(pBuffer_OUT, value, count);
}
else /* Short copy, memcpy from src to dest. */
{
unsigned int count = opcode;
/* Dump */
SZ_Memcpy2(pBuffer_OUT, pBuffer_IN, count);
}
} /* End of short ops */
}
/* And that's that */
return(0);
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,28 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef ANIMLIB_H
#define ANIMLIB_H
#include "opentyr.h"
void JE_playAnim( const char *animfile, JE_byte startingframe, JE_byte speed );
#endif /* ANIMLIB_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,247 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "arg_parse.h"
#include "mingw_fixes.h"
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void permute( const char *argv[], int *first_nonopt, int *first_opt, int after_opt );
static int parse_short_opt( int argc, const char *const argv[], const Options *options, Option *option );
static int parse_long_opt( int argc, const char *const argv[], const Options *options, Option *option );
Option parse_args( int argc, const char *argv[], const Options *options )
{
static int argn = 1;
static bool no_more_options = false;
static int first_nonopt = 1;
Option option = { NOT_OPTION, NULL, 0 };
option.argn = first_nonopt;
while (argn < argc)
{
size_t arg_len = strlen(argv[argn]);
if (!no_more_options &&
argv[argn][0] == '-' && // first char is '-'
arg_len > 1) // option is not "-"
{
option.argn = argn;
if (argv[argn][1] == '-') // string begins with "--"
{
if (arg_len == 2) // "--" alone indicates end of options
{
++argn;
no_more_options = true;
}
else
{
argn = parse_long_opt(argc, argv, options, &option);
}
}
else
{
argn = parse_short_opt(argc, argv, options, &option);
}
// shift option in front of non-options
permute(argv, &first_nonopt, &option.argn, argn);
// don't include "--" in non-options
if (no_more_options)
++option.argn;
break;
}
else
{
// skip non-options, permute later when option encountered
++argn;
}
}
return option;
}
static void permute( const char *argv[], int *first_nonopt, int *first_opt, int after_opt )
{
const int nonopts = *first_opt - *first_nonopt;
// slide each of the options in front of the non-options
for (int i = *first_opt; i < after_opt; ++i)
{
for (int j = i; j > *first_nonopt; --j)
{
// swap argv[j] and argv[j - 1]
const char *temp = argv[j];
argv[j] = argv[j - 1];
argv[j - 1] = temp;
}
// position of first non-option shifts right once for each option
++(*first_nonopt);
}
// position of first option is initial position of first non-option
*first_opt -= nonopts;
}
static int parse_short_opt( int argc, const char *const argv[], const Options *options, Option *option )
{
static size_t offset = 1; // ignore the "-"
int argn = option->argn;
const char *arg = argv[argn];
const size_t arg_len = strlen(arg);
const bool arg_attached = (offset + 1 < arg_len), // possible argument attached?
last_in_argv = (argn == argc - 1);
option->value = INVALID_OPTION;
for (; !(options->short_opt == 0 &&
options->long_opt == NULL); ++options)
{
if (options->short_opt != 0 &&
options->short_opt == arg[offset])
{
option->value = options->value;
if (options->has_arg)
{
if (arg_attached) // arg direclty follows option
{
option->arg = arg + offset + 1;
offset = arg_len;
}
else if (!last_in_argv) // arg is next in argv
{
option->arg = argv[++argn];
offset = arg_len;
}
else
{
option->value = OPTION_MISSING_ARG;
break;
}
}
break;
}
}
switch (option->value)
{
case INVALID_OPTION:
fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], argv[option->argn][offset]);
break;
case OPTION_MISSING_ARG:
fprintf(stderr, "%s: option requires an argument -- '%c'\n", argv[0], argv[option->argn][offset]);
break;
}
if (++offset >= arg_len)
{
++argn;
offset = 1;
}
return argn; // which arg in argv that parse_args() should examine when called again
}
static int parse_long_opt( int argc, const char *const argv[], const Options *options, Option *option )
{
int argn = option->argn;
const char *arg = argv[argn] + 2; // ignore the "--"
const size_t arg_len = strlen(arg),
arg_opt_len = strchrnul(arg, '=') - arg; // length before "="
const bool arg_attached = (arg_opt_len < arg_len), // argument attached using "="?
last_in_argv = (argn == argc - 1);
option->value = INVALID_OPTION;
for (; !(options->short_opt == 0 &&
options->long_opt == NULL); ++options)
{
if (options->long_opt != NULL &&
strncmp(options->long_opt, arg, arg_opt_len) == 0) // matches (partially, at least)
{
if (option->value != INVALID_OPTION) // other match already found
{
option->value = AMBIGUOUS_OPTION;
break;
}
option->value = options->value;
if (options->has_arg)
{
if (arg_attached) // arg is after "="
{
option->arg = arg + arg_opt_len + 1;
}
else if (!last_in_argv) // arg is next in argv
{
option->arg = argv[++argn];
}
else // arg is missing
{
option->value = OPTION_MISSING_ARG;
// can't break, gotta check for ambiguity
}
}
if (arg_opt_len == strlen(options->long_opt)) // exact match
break;
// can't break for partial match, gotta check for ambiguity
}
}
switch (option->value)
{
case INVALID_OPTION:
fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[option->argn]);
break;
case AMBIGUOUS_OPTION:
fprintf(stderr, "%s: option '%s' is ambiguous\n", argv[0], argv[option->argn]);
break;
case OPTION_MISSING_ARG:
fprintf(stderr, "%s: option '%s' requires an argument\n", argv[0], argv[option->argn]);
break;
}
++argn;
return argn; // which arg in argv that parse_args() should examine when called again
}

View File

@@ -0,0 +1,58 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef ARG_PARSE_H
#define ARG_PARSE_H
#include <stdbool.h>
// this is essentially a reimplementation of getopt_long()
typedef struct
{
int value;
char short_opt;
const char *long_opt;
bool has_arg;
}
Options;
enum
{
// indicates that argv[argn..argc) are not options
NOT_OPTION = 0,
/* behavior of parse_args() is undefined after
it has returned any of the following values */
INVALID_OPTION = -1,
AMBIGUOUS_OPTION = -2,
OPTION_MISSING_ARG = -3
};
typedef struct
{
int value;
const char *arg;
int argn;
}
Option;
Option parse_args( int argc, const char *argv[], const Options *options );
#endif /* ARG_PARSE_H */

View File

@@ -0,0 +1,468 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "opentyr.h"
#include "backgrnd.h"
#include "config.h"
#include "varz.h"
#include "video.h"
#include <assert.h>
/*Special Background 2 and Background 3*/
/*Back Pos 3*/
JE_word backPos, backPos2, backPos3;
JE_word backMove, backMove2, backMove3;
/*Main Maps*/
JE_word mapX, mapY, mapX2, mapX3, mapY2, mapY3;
JE_byte **mapYPos, **mapY2Pos, **mapY3Pos;
JE_word mapXPos, oldMapXOfs, mapXOfs, mapX2Ofs, mapX2Pos, mapX3Pos, oldMapX3Ofs, mapX3Ofs, tempMapXOfs;
intptr_t mapXbpPos, mapX2bpPos, mapX3bpPos;
JE_byte map1YDelay, map1YDelayMax, map2YDelay, map2YDelayMax;
JE_boolean anySmoothies;
JE_byte smoothie_data[9]; /* [1..9] */
void JE_darkenBackground( JE_word neat ) /* wild detail level */
{
Uint8 *s = (Uint8 *)VGAScreen->pixels; /* screen pointer, 8-bit specific */
int x, y;
s += 24;
for (y = 184; y; y--)
{
for (x = 264; x; x--)
{
*s = ((((*s & 0x0f) << 4) - (*s & 0x0f) + ((((x - neat - y) >> 2) + *(s-2) + (y == 184 ? 0 : *(s-(VGAScreen->pitch-1)))) & 0x0f)) >> 4) | (*s & 0xf0);
s++;
}
s += VGAScreen->pitch - 264;
}
}
void blit_background_row( SDL_Surface *surface, int x, int y, Uint8 **map )
{
assert(surface->format->BitsPerPixel == 8);
Uint8 *pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x,
*pixels_ll = (Uint8 *)surface->pixels, // lower limit
*pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
for (int y = 0; y < 28; y++)
{
// not drawing on screen yet; skip y
if ((pixels + (12 * 24)) < pixels_ll)
{
pixels += surface->pitch;
continue;
}
for (int tile = 0; tile < 12; tile++)
{
Uint8 *data = *(map + tile);
// no tile; skip tile
if (data == NULL)
{
pixels += 24;
continue;
}
data += y * 24;
for (int x = 24; x; x--)
{
if (pixels >= pixels_ul)
return;
if (pixels >= pixels_ll && *data != 0)
*pixels = *data;
pixels++;
data++;
}
}
pixels += surface->pitch - 12 * 24;
}
}
void blit_background_row_blend( SDL_Surface *surface, int x, int y, Uint8 **map )
{
assert(surface->format->BitsPerPixel == 8);
Uint8 *pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x,
*pixels_ll = (Uint8 *)surface->pixels, // lower limit
*pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
for (int y = 0; y < 28; y++)
{
// not drawing on screen yet; skip y
if ((pixels + (12 * 24)) < pixels_ll)
{
pixels += surface->pitch;
continue;
}
for (int tile = 0; tile < 12; tile++)
{
Uint8 *data = *(map + tile);
// no tile; skip tile
if (data == NULL)
{
pixels += 24;
continue;
}
data += y * 24;
for (int x = 24; x; x--)
{
if (pixels >= pixels_ul)
return;
if (pixels >= pixels_ll && *data != 0)
*pixels = (*data & 0xf0) | (((*pixels & 0x0f) + (*data & 0x0f)) / 2);
pixels++;
data++;
}
}
pixels += surface->pitch - 12 * 24;
}
}
void draw_background_1( SDL_Surface *surface )
{
SDL_FillRect(surface, NULL, 0);
Uint8 **map = (Uint8 **)mapYPos + mapXbpPos - 12;
for (int i = -1; i < 7; i++)
{
blit_background_row(surface, mapXPos, (i * 28) + backPos, map);
map += 14;
}
}
void draw_background_2( SDL_Surface *surface )
{
if (map2YDelayMax > 1 && backMove2 < 2)
backMove2 = (map2YDelay == 1) ? 1 : 0;
if (background2 != 0)
{
// water effect combines background 1 and 2 by syncronizing the x coordinate
int x = smoothies[1] ? mapXPos : mapX2Pos;
Uint8 **map = (Uint8 **)mapY2Pos + (smoothies[1] ? mapXbpPos : mapX2bpPos) - 12;
for (int i = -1; i < 7; i++)
{
blit_background_row(surface, x, (i * 28) + backPos2, map);
map += 14;
}
}
/*Set Movement of background*/
if (--map2YDelay == 0)
{
map2YDelay = map2YDelayMax;
backPos2 += backMove2;
if (backPos2 > 27)
{
backPos2 -= 28;
mapY2--;
mapY2Pos -= 14; /*Map Width*/
}
}
}
void draw_background_2_blend( SDL_Surface *surface )
{
if (map2YDelayMax > 1 && backMove2 < 2)
backMove2 = (map2YDelay == 1) ? 1 : 0;
Uint8 **map = (Uint8 **)mapY2Pos + mapX2bpPos - 12;
for (int i = -1; i < 7; i++)
{
blit_background_row_blend(surface, mapX2Pos, (i * 28) + backPos2, map);
map += 14;
}
/*Set Movement of background*/
if (--map2YDelay == 0)
{
map2YDelay = map2YDelayMax;
backPos2 += backMove2;
if (backPos2 > 27)
{
backPos2 -= 28;
mapY2--;
mapY2Pos -= 14; /*Map Width*/
}
}
}
void draw_background_3( SDL_Surface *surface )
{
/* Movement of background */
backPos3 += backMove3;
if (backPos3 > 27)
{
backPos3 -= 28;
mapY3--;
mapY3Pos -= 15; /*Map Width*/
}
Uint8 **map = (Uint8 **)mapY3Pos + mapX3bpPos - 12;
for (int i = -1; i < 7; i++)
{
blit_background_row(surface, mapX3Pos, (i * 28) + backPos3, map);
map += 15;
}
}
void JE_filterScreen( JE_shortint col, JE_shortint int_)
{
Uint8 *s = NULL; /* screen pointer, 8-bit specific */
int x, y;
unsigned int temp;
if (filterFade)
{
levelBrightness += levelBrightnessChg;
if ((filterFadeStart && levelBrightness < -14) || levelBrightness > 14)
{
levelBrightnessChg = -levelBrightnessChg;
filterFadeStart = false;
levelFilter = levelFilterNew;
}
if (!filterFadeStart && levelBrightness == 0)
{
filterFade = false;
levelBrightness = -99;
}
}
if (col != -99 && filtrationAvail)
{
s = (Uint8 *)VGAScreen->pixels;
s += 24;
col <<= 4;
for (y = 184; y; y--)
{
for (x = 264; x; x--)
{
*s = col | (*s & 0x0f);
s++;
}
s += VGAScreen->pitch - 264;
}
}
if (int_ != -99 && explosionTransparent)
{
s = (Uint8 *)VGAScreen->pixels;
s += 24;
for (y = 184; y; y--)
{
for (x = 264; x; x--)
{
temp = (*s & 0x0f) + int_;
*s = (*s & 0xf0) | (temp >= 0x1f ? 0 : (temp >= 0x0f ? 0x0f : temp));
s++;
}
s += VGAScreen->pitch - 264;
}
}
}
void JE_checkSmoothies( void )
{
anySmoothies = (processorType > 2 && (smoothies[1-1] || smoothies[2-1])) || (processorType > 1 && (smoothies[3-1] || smoothies[4-1] || smoothies[5-1]));
}
void lava_filter( SDL_Surface *dst, SDL_Surface *src )
{
assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
/* we don't need to check for over-reading the pixel surfaces since we only
* read from the top 185+1 scanlines, and there should be 320 */
const int dst_pitch = dst->pitch;
Uint8 *dst_pixel = (Uint8 *)dst->pixels + (185 * dst_pitch);
const Uint8 * const dst_pixel_ll = (Uint8 *)dst->pixels; // lower limit
const int src_pitch = src->pitch;
const Uint8 *src_pixel = (Uint8 *)src->pixels + (185 * src->pitch);
const Uint8 * const src_pixel_ll = (Uint8 *)src->pixels; // lower limit
int w = 320 * 185 - 1;
for (int y = 185 - 1; y >= 0; --y)
{
dst_pixel -= (dst_pitch - 320); // in case pitch is not 320
src_pixel -= (src_pitch - 320); // in case pitch is not 320
for (int x = 320 - 1; x >= 0; x -= 8)
{
int waver = abs(((w >> 9) & 0x0f) - 8) - 1;
w -= 8;
for (int xi = 8 - 1; xi >= 0; --xi)
{
--dst_pixel;
--src_pixel;
// value is average value of source pixel (2x), destination pixel above, and destination pixel below (all with waver)
// hue is red
Uint8 value = 0;
if (src_pixel + waver >= src_pixel_ll)
value += (*(src_pixel + waver) & 0x0f) * 2;
value += *(dst_pixel + waver + dst_pitch) & 0x0f;
if (dst_pixel + waver - dst_pitch >= dst_pixel_ll)
value += *(dst_pixel + waver - dst_pitch) & 0x0f;
*dst_pixel = (value / 4) | 0x70;
}
}
}
}
void water_filter( SDL_Surface *dst, SDL_Surface *src )
{
assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
Uint8 hue = smoothie_data[1] << 4;
/* we don't need to check for over-reading the pixel surfaces since we only
* read from the top 185+1 scanlines, and there should be 320 */
const int dst_pitch = dst->pitch;
Uint8 *dst_pixel = (Uint8 *)dst->pixels + (185 * dst_pitch);
const Uint8 *src_pixel = (Uint8 *)src->pixels + (185 * src->pitch);
int w = 320 * 185 - 1;
for (int y = 185 - 1; y >= 0; --y)
{
dst_pixel -= (dst_pitch - 320); // in case pitch is not 320
src_pixel -= (src->pitch - 320); // in case pitch is not 320
for (int x = 320 - 1; x >= 0; x -= 8)
{
int waver = abs(((w >> 10) & 0x07) - 4) - 1;
w -= 8;
for (int xi = 8 - 1; xi >= 0; --xi)
{
--dst_pixel;
--src_pixel;
// pixel is copied from source if not blue
// otherwise, value is average of value of source pixel and destination pixel below (with waver)
if ((*src_pixel & 0x30) == 0)
{
*dst_pixel = *src_pixel;
}
else
{
Uint8 value = *src_pixel & 0x0f;
value += *(dst_pixel + waver + dst_pitch) & 0x0f;
*dst_pixel = (value / 2) | hue;
}
}
}
}
}
void iced_blur_filter( SDL_Surface *dst, SDL_Surface *src )
{
assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
Uint8 *dst_pixel = (Uint8 *)dst->pixels;
const Uint8 *src_pixel = (Uint8 *)src->pixels;
for (int y = 0; y < 184; ++y)
{
for (int x = 0; x < 320; ++x)
{
// value is average value of source pixel and destination pixel
// hue is icy blue
const Uint8 value = (*src_pixel & 0x0f) + (*dst_pixel & 0x0f);
*dst_pixel = (value / 2) | 0x80;
++dst_pixel;
++src_pixel;
}
dst_pixel += (dst->pitch - 320); // in case pitch is not 320
src_pixel += (src->pitch - 320); // in case pitch is not 320
}
}
void blur_filter( SDL_Surface *dst, SDL_Surface *src )
{
assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
Uint8 *dst_pixel = (Uint8 *)dst->pixels;
const Uint8 *src_pixel = (Uint8 *)src->pixels;
for (int y = 0; y < 184; ++y)
{
for (int x = 0; x < 320; ++x)
{
// value is average value of source pixel and destination pixel
// hue is source pixel hue
const Uint8 value = (*src_pixel & 0x0f) + (*dst_pixel & 0x0f);
*dst_pixel = (value / 2) | (*src_pixel & 0xf0);
++dst_pixel;
++src_pixel;
}
dst_pixel += (dst->pitch - 320); // in case pitch is not 320
src_pixel += (src->pitch - 320); // in case pitch is not 320
}
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,59 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef BACKGRND_H
#define BACKGRND_H
#include "opentyr.h"
#include <stdint.h>
#include "SDL.h"
extern JE_word backPos, backPos2, backPos3;
extern JE_word backMove, backMove2, backMove3;
extern JE_word mapX, mapY, mapX2, mapX3, mapY2, mapY3;
extern JE_byte **mapYPos, **mapY2Pos, **mapY3Pos;
extern JE_word mapXPos, oldMapXOfs, mapXOfs, mapX2Ofs, mapX2Pos, mapX3Pos, oldMapX3Ofs, mapX3Ofs, tempMapXOfs;
extern intptr_t mapXbpPos, mapX2bpPos, mapX3bpPos;
extern JE_byte map1YDelay, map1YDelayMax, map2YDelay, map2YDelayMax;
extern JE_boolean anySmoothies; // if yes, I want one :D
extern JE_byte smoothie_data[9];
void JE_darkenBackground( JE_word neat );
void blit_background_row( SDL_Surface *surface, int x, int y, Uint8 **map );
void blit_background_row_blend( SDL_Surface *surface, int x, int y, Uint8 **map );
void draw_background_1( SDL_Surface *surface );
void draw_background_2( SDL_Surface *surface );
void draw_background_2_blend( SDL_Surface *surface );
void draw_background_3( SDL_Surface *surface );
void JE_filterScreen( JE_shortint col, JE_shortint generic_int );
void JE_checkSmoothies( void );
void lava_filter( SDL_Surface *dst, SDL_Surface *src );
void water_filter( SDL_Surface *dst, SDL_Surface *src );
void iced_blur_filter( SDL_Surface *dst, SDL_Surface *src );
void blur_filter( SDL_Surface *dst, SDL_Surface *src );
/*smoothies #5 is used for 3*/
/*smoothies #9 is a vertical flip*/
#endif /* BACKGRND_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,680 @@
/*
Copyright (c) 2009 Dave Gamble
Copyright (c) 2009 The OpenTyrian Development Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// cJSON
// JSON parser in C.
#include "cJSON.h"
#include "mingw_fixes.h"
#include <assert.h>
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void *(*cJSON_malloc)( size_t ) = malloc;
static void *(*cJSON_realloc)( void *, size_t ) = realloc;
static void (*cJSON_free)( void *ptr ) = free;
// helper for compilers without strdup
static char *cJSON_strdup( const char *str )
{
size_t size = strlen(str) + 1;
char *copy = (char *)cJSON_malloc(size);
if (copy != NULL)
memcpy(copy, str, size);
return copy;
}
// helper for compilers without strcasecmp
static int cJSON_strcasecmp( const char *s1, const char *s2 )
{
for(; tolower(*(const unsigned char *)s1) == tolower(*(const unsigned char *)s2); ++s1, ++s2)
if (*s1 == 0)
return 0;
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
}
// construct empty item
static cJSON *cJSON_NewItem( cJSON_Type type )
{
cJSON *node = (cJSON *)cJSON_malloc(sizeof(cJSON));
if (node != NULL)
{
node->type = type;
node->child =
node->prev =
node->next = NULL;
node->string = NULL;
node->valuestring = NULL;
node->valueint =
node->valuedouble = 0;
}
return node;
}
// destroy item chain
void cJSON_Delete( cJSON *item )
{
while (item != NULL)
{
if (item->child)
cJSON_Delete(item->child);
cJSON *next = item->next;
if (item->string)
cJSON_free(item->string);
if (item->valuestring)
cJSON_free(item->valuestring);
cJSON_free(item);
item = next;
}
}
// parser/emitter prototypes
static const char *parse_value( cJSON *item, const char *in );
static char *print_value(cJSON *item,int depth);
static const char *parse_number( cJSON *item, const char *in );
static char *print_number( cJSON *item );
static const char *parse_string(cJSON *item,const char *str);
static char *print_string(cJSON *item);
static const char *parse_array_or_object( cJSON *item, const char *in, cJSON_Type type );
static char *print_array(cJSON *item,int depth);
static char *print_object(cJSON *item,int depth);
static inline const char *parse_array( cJSON *item, const char *in )
{
return parse_array_or_object(item, in, cJSON_Array);
}
static inline const char *parse_object( cJSON *item, const char *in )
{
return parse_array_or_object(item, in, cJSON_Object);
}
// helper to skip whitespace
static inline const char *skip_space( const char *str )
{
if (str != NULL)
while (isspace(*str))
++str;
return str;
}
// parse root of JSON into cJSON item
cJSON *cJSON_Parse( const char *in )
{
cJSON *item = cJSON_NewItem(cJSON_NULL);
if (item != NULL)
{
if (parse_value(item, skip_space(in)) == NULL) // if malformed or out-of-memory
{
cJSON_Delete(item);
item = NULL;
}
}
return item;
}
// emit cJSON item as JSON value
char *cJSON_Print( cJSON *item )
{
return print_value(item, 0);
}
// parse JSON value into cJSON item
static const char *parse_value( cJSON *item, const char *in )
{
if (in == NULL)
return in;
if (!strncmp(in, "null", 4))
{
item->type = cJSON_NULL;
return in + 4;
}
if (!strncmp(in, "false", 5))
{
item->type = cJSON_False;
return in + 5;
}
if (!strncmp(in, "true", 4))
{
item->type = cJSON_True;
return in + 4;
}
if (*in == '\"')
return parse_string(item, in);
if (*in == '-' || (*in >= '0' && *in <= '9'))
return parse_number(item, in);
if (*in == '[')
return parse_array(item, in);
if (*in == '{')
return parse_object(item, in);
return NULL; // malformed: expected value
}
// emit cJSON item as JSON value
static char *print_value( cJSON *item, int depth )
{
char *out = NULL;
switch (item->type)
{
case cJSON_NULL:
out = cJSON_strdup("null");
break;
case cJSON_False:
out = cJSON_strdup("false");
break;
case cJSON_True:
out = cJSON_strdup("true");
break;
case cJSON_Number:
out = print_number(item);
break;
case cJSON_String:
out = print_string(item);
break;
case cJSON_Array:
out = print_array(item, depth);
break;
case cJSON_Object:
out = print_object(item, depth);
break;
}
return out;
}
// parse JSON number value into cJSON item
static const char *parse_number( cJSON *item, const char *in )
{
double n = 0;
int sign = 1, decimal_shift = 0;
int exponent_sign = 1, exponent = 0;
if (*in == '-')
sign = -1, ++in;
// integer part
if (*in == '0')
++in;
else if (*in >= '1' && *in <= '9')
do
n = (n * 10.0) + (*(in++) - '0');
while (*in >= '0' && *in <= '9');
// fractional part
if (*in == '.')
{
++in;
while (*in >= '0' && *in <= '9')
n = (n * 10.0) + (*(in++) - '0'), decimal_shift--;
}
// exponent part
if (*in == 'e' || *in == 'E')
{
++in;
if (*in == '+')
++in;
else if (*in == '-')
exponent_sign = -1, ++in;
while (*in >= '0' && *in <= '9')
exponent = (exponent * 10) + (*(in++) - '0');
}
// number = +/- number.fraction * (10 ^ +/- exponent)
n = sign * n * pow(10.0, decimal_shift + exponent_sign * exponent);
item->valuedouble = n;
item->valueint = n;
item->type = cJSON_Number;
return in;
}
// emit string containing numeric value of cJSON item
static char *print_number( cJSON *item )
{
char *str = (char *)cJSON_malloc(DBL_DIG + 10);
snprintf(str, DBL_DIG + 10, "%.*g", DBL_DIG, item->valuedouble);
return str;
}
// Parse the input text into an unescaped cstring, and populate item.
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
static const char *parse_string(cJSON *item,const char *str)
{
const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc;
if (*str!='\"') return 0; // not a string!
while (*ptr!='\"' && *ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // skip escaped quotes.
out=(char*)cJSON_malloc(len+1); // This is how long we need for the string, roughly.
if (!out) return 0;
ptr=str+1;ptr2=out;
while (*ptr!='\"' && *ptr>31)
{
if (*ptr!='\\') *ptr2++=*ptr++;
else
{
ptr++;
switch (*ptr)
{
case 'b': *ptr2++='\b'; break;
case 'f': *ptr2++='\f'; break;
case 'n': *ptr2++='\n'; break;
case 'r': *ptr2++='\r'; break;
case 't': *ptr2++='\t'; break;
case 'u': // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY.
sscanf(ptr+1,"%4x",&uc); // get the unicode char.
len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len;
switch (len) {
case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
case 1: *--ptr2 =(uc | firstByteMark[len]);
}
ptr2+=len;ptr+=4;
break;
default: *ptr2++=*ptr; break;
}
ptr++;
}
}
*ptr2=0;
if (*ptr=='\"') ptr++;
item->valuestring=out;
item->type=cJSON_String;
return ptr;
}
// Render the cstring provided to an escaped version that can be printed.
static char *print_string_ptr(const char *str)
{
const char *ptr;char *ptr2,*out;int len=0;
ptr=str;while (*ptr && ++len) {if (*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;}
out=(char*)cJSON_malloc(len+3);
ptr2=out;ptr=str;
*ptr2++='\"';
while (*ptr)
{
if (*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
else
{
*ptr2++='\\';
switch (*ptr++)
{
case '\\': *ptr2++='\\'; break;
case '\"': *ptr2++='\"'; break;
case '\b': *ptr2++='b'; break;
case '\f': *ptr2++='f'; break;
case '\n': *ptr2++='n'; break;
case '\r': *ptr2++='r'; break;
case '\t': *ptr2++='t'; break;
default: ptr2--; break; // eviscerate with prejudice.
}
}
}
*ptr2++='\"';*ptr2++=0;
return out;
}
// Invote print_string_ptr (which is useful) on an item.
static char *print_string(cJSON *item)
{
return (item->valuestring != NULL) ? print_string_ptr(item->valuestring) : cJSON_strdup("");
}
// parse JSON array/object into cJSON item chain
static const char *parse_array_or_object( cJSON *const item, const char *in, cJSON_Type type )
{
assert(type == cJSON_Array || type == cJSON_Object);
const char opening = (type == cJSON_Object) ? '{' : '[',
closing = (type == cJSON_Object) ? '}' : ']';
if (*in != opening) // not an array/object!
return NULL;
else
in = skip_space(++in);
item->type = type;
if (*in == closing) // empty array/object
return ++in;
cJSON *prev_child = NULL;
for (; ; )
{
cJSON *child = cJSON_NewItem(cJSON_NULL);
if (child == NULL) // memory fail
return NULL;
if (prev_child == NULL)
{
// attach first child to parent
item->child = child;
}
else
{
// attach other children to older sibling
prev_child->next = child;
child->prev = prev_child;
}
if (type == cJSON_Object)
{
// object children have identifier string
in = skip_space(parse_string(child, skip_space(in)));
if (in == NULL) // malformed or memory fail
return NULL;
// parse_string parses into the item's value; we can use it to parse the identifier string, we just have to move the results
child->string = child->valuestring;
child->valuestring = NULL;
if (*in != ':') // malformed
return NULL;
else
++in;
}
in = skip_space(parse_value(child, skip_space(in)));
if (in == NULL) // malformed or memory fail
return NULL;
prev_child = child;
if (*in == ',')
++in;
else
break;
}
if (*in == closing) // end of array/object
return ++in;
return NULL; // malformed
}
// Render an array to text
static char *print_array(cJSON *item,int depth)
{
char *out, *ptr;
size_t len = 3; // minimum needed to print empty array
ptr = out = (char*)cJSON_malloc(len);
strcpy(ptr, "[");
ptr += 1;
cJSON *child = item->child;
while (child)
{
char *ret = print_value(child, depth + 1);
if (!ret)
{
cJSON_free(out);
return NULL;
}
size_t ret_len = strlen(ret);
len += ret_len + 2;
ptr = out = (char*)cJSON_realloc(out, len);
ptr += strlen(out);
strcpy(ptr, ret); // strcat(out, ret);
ptr += ret_len;
cJSON_free(ret);
if (child->next)
{
strcpy(ptr, ", "); // strcat(out, ", ");
ptr += 2;
}
child = child->next;
}
strcpy(ptr, "]"); // strcat(out, "]");
return out;
}
// Render an object to text.
static char *print_object(cJSON *item,int depth)
{
char *out, *ptr;
size_t len = 4 + depth; // minimum needed to print empty object
++depth;
ptr = out = (char*)cJSON_malloc(len);
strcpy(ptr, "{\n");
ptr += 2;
cJSON *child = item->child;
while (child)
{
char *str = print_string_ptr(child->string);
if (!str)
{
cJSON_free(out);
return NULL;
}
size_t str_len = strlen(str);
char *ret = print_value(child, depth);
if (!ret)
{
cJSON_free(str);
cJSON_free(out);
return NULL;
}
size_t ret_len = strlen(ret);
len += depth + str_len + ret_len + 4;
out = (char*)cJSON_realloc(out, len);
ptr = out + strlen(out);
for (int i = 0; i < depth; ++i)
*(ptr++) = '\t';
strcpy(ptr, str); // strcat(out, str);
ptr += str_len;
cJSON_free(str);
strcpy(ptr, ":\t"); // strcat(out, ":\t");
ptr += 2;
strcpy(ptr, ret); // strcat(out, ret);
ptr += ret_len;
cJSON_free(ret);
if (child->next)
{
strcpy(ptr, ",\n"); // strcat(out, ",\n");
ptr += 2;
}
else
{
strcpy(ptr, "\n"); // strcat(out, "\n");
ptr += 1;
}
child = child->next;
}
--depth;
for (int i = 0; i < depth; ++i)
*(ptr++) = '\t';
strcpy(ptr, "}"); // strcat(out, "}");
return out;
}
// Get Array size/item / object item.
int cJSON_GetArraySize( cJSON *array )
{
int size = 0;
cJSON *item = array->child;
while (item != NULL)
item = item->next, ++size;
return size;
}
cJSON *cJSON_GetArrayItem( cJSON *array, int index )
{
cJSON *item = array->child;
while (item != NULL && index > 0)
item = item->next, --index;
return item;
}
cJSON *cJSON_GetObjectItem( cJSON *object, const char *string)
{
cJSON *item=object->child;
while (item != NULL && cJSON_strcasecmp(item->string, string) != 0)
item = item->next;
return item;
}
cJSON *cJSON_CreateOrGetObjectItem( cJSON *object, const char *string )
{
cJSON *child = cJSON_GetObjectItem(object, string);
if (child == NULL)
cJSON_AddItemToObject(object, string, child = cJSON_CreateNull());
return child;
}
// Utility for array list handling.
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
// Add item to array/object.
void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
// remove all items from array/object
void cJSON_ClearArray( cJSON *array )
{
cJSON_Delete(array->child);
array->child = NULL;
}
// create basic types
cJSON *cJSON_CreateNull( void )
{
return cJSON_NewItem(cJSON_NULL);
}
cJSON *cJSON_CreateBoolean( bool value )
{
return cJSON_NewItem(value ? cJSON_True : cJSON_False);
}
cJSON *cJSON_CreateNumber( double value )
{
cJSON *item = cJSON_NewItem(cJSON_Number);
item->valueint = item->valuedouble = value;
return item;
}
cJSON *cJSON_CreateString( const char *value )
{
cJSON *item = cJSON_NewItem(cJSON_String);
item->valuestring = cJSON_strdup(value);
return item;
}
cJSON *cJSON_CreateArray( void )
{
return cJSON_NewItem(cJSON_Array);
}
cJSON *cJSON_CreateObject( void )
{
return cJSON_NewItem(cJSON_Object);
}
void cJSON_ForceType( cJSON *item, cJSON_Type type )
{
if (item->type != type)
{
cJSON_Delete(item->child);
item->child = NULL;
item->type = type;
}
}
void cJSON_SetBoolean( cJSON *item, bool value )
{
cJSON_ForceType(item, value ? cJSON_True : cJSON_False);
}
void cJSON_SetNumber( cJSON *item, double value )
{
cJSON_ForceType(item, cJSON_Number);
item->valueint = item->valuedouble = value;
}
void cJSON_SetString( cJSON *item, const char *value )
{
cJSON_ForceType(item, cJSON_String);
cJSON_free(item->valuestring);
item->valuestring = cJSON_strdup(value);
}
// Create Arrays:
cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}

View File

@@ -0,0 +1,117 @@
/*
Copyright (c) 2009 Dave Gamble
Copyright (c) 2009 The OpenTyrian Development Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef cJSON__h
#define cJSON__h
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdbool.h>
#include <stdlib.h>
typedef enum
{
cJSON_NULL,
cJSON_False,
cJSON_True,
cJSON_Number,
cJSON_String,
cJSON_Array,
cJSON_Object
}
cJSON_Type;
typedef struct cJSON
{
cJSON_Type type; // type of this item
// next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem
struct cJSON *next, *prev; // sibling items in chain (parent item is array or object)
struct cJSON *child; // chain of child items (this item is array or object)
char *string; // identifying string of this item (parent item is object)
char *valuestring; // The item's string, if type==cJSON_String
int valueint; // The item's number, if type==cJSON_Number
double valuedouble; // The item's number, if type==cJSON_Number
}
cJSON;
// Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished.
cJSON *cJSON_Parse(const char *value);
// Render a cJSON entity to text for transfer/storage. Free the char* when finished.
char *cJSON_Print(cJSON *item);
// Delete a cJSON entity and all subentities.
void cJSON_Delete(cJSON *c);
// Returns the number of items in an array (or object).
int cJSON_GetArraySize(cJSON *array);
// Retrieve item number "item" from array "array". Returns NULL if unsuccessful.
cJSON *cJSON_GetArrayItem(cJSON *array,int item);
// Get item "string" from object. Case insensitive.
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
cJSON *cJSON_CreateOrGetObjectItem( cJSON *object, const char *string );
// These calls create a cJSON item of the appropriate type.
cJSON *cJSON_CreateNull( void );
cJSON *cJSON_CreateBoolean( bool );
cJSON *cJSON_CreateNumber( double );
cJSON *cJSON_CreateString( const char * );
cJSON *cJSON_CreateArray( void );
cJSON *cJSON_CreateObject( void );
void cJSON_ForceType( cJSON *, cJSON_Type );
void cJSON_SetBoolean( cJSON *, bool );
void cJSON_SetNumber( cJSON *, double );
void cJSON_SetString( cJSON *, const char * );
// These utilities create an Array of count items.
cJSON *cJSON_CreateIntArray(int *numbers,int count);
cJSON *cJSON_CreateFloatArray(float *numbers,int count);
cJSON *cJSON_CreateDoubleArray(double *numbers,int count);
cJSON *cJSON_CreateStringArray(const char **strings,int count);
// Append item to the specified array/object.
void cJSON_AddItemToArray(cJSON *array, cJSON *item);
void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
void cJSON_ClearArray( cJSON *array );
#define cJSON_ClearObject( object ) cJSON_ClearArray(object)
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,163 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef CONFIG_H
#define CONFIG_H
#include "cJSON.h"
#include "opentyr.h"
#include <stdio.h>
#include "SDL.h"
#define SAVE_FILES_NUM (11 * 2)
#define MAX_STARS 100
/* These are necessary because the size of the structure has changed from the original, but we
need to know the original sizes in order to find things in TYRIAN.SAV */
#define SAVE_FILES_SIZE 2398
#define SIZEOF_SAVEGAMETEMP SAVE_FILES_SIZE + 4 + 100
#define SAVE_FILE_SIZE (SIZEOF_SAVEGAMETEMP - 4)
/*#define SAVE_FILES_SIZE (2502 - 4)
#define SAVE_FILE_SIZE (SAVE_FILES_SIZE)*/
typedef SDLKey JE_KeySettingType[8]; /* [1..8] */
typedef JE_byte JE_PItemsType[12]; /* [1..12] */
typedef JE_byte JE_EditorItemAvailType[100]; /* [1..100] */
typedef struct
{
JE_word encode;
JE_word level;
JE_PItemsType items;
JE_longint score;
JE_longint score2;
char levelName[11]; /* string [9]; */ /* SYN: Added one more byte to match lastLevelName below */
JE_char name[15]; /* [1..14] */ /* SYN: Added extra byte for null */
JE_byte cubes;
JE_byte power[2]; /* [1..2] */
JE_byte episode;
JE_PItemsType lastItems;
JE_byte difficulty;
JE_byte secretHint;
JE_byte input1;
JE_byte input2;
JE_boolean gameHasRepeated; /*See if you went from one episode to another*/
JE_byte initialDifficulty;
/* High Scores - Each episode has both sets of 1&2 player selections - with 3 in each */
JE_longint highScore1,
highScore2;
char highScoreName[30]; /* string [29] */
JE_byte highScoreDiff;
} JE_SaveFileType;
typedef JE_SaveFileType JE_SaveFilesType[SAVE_FILES_NUM]; /* [1..savefilesnum] */
typedef JE_byte JE_SaveGameTemp[SAVE_FILES_SIZE + 4 + 100]; /* [1..sizeof(savefilestype) + 4 + 100] */
typedef struct
{
JE_byte sC;
JE_word sLoc;
JE_word sMov;
} StarDatType;
extern const JE_byte cryptKey[10];
extern const JE_KeySettingType defaultKeySettings;
extern const char defaultHighScoreNames[34][23];
extern const char defaultTeamNames[22][25];
extern const JE_EditorItemAvailType initialItemAvail;
extern JE_boolean smoothies[9];
extern JE_byte starShowVGASpecialCode;
extern StarDatType starDat[MAX_STARS];
extern JE_word starY;
extern JE_word lastCubeMax, cubeMax;
extern JE_word cubeList[4];
extern JE_boolean gameHasRepeated;
extern JE_shortint difficultyLevel, oldDifficultyLevel, initialDifficulty;
extern uint power, lastPower, powerAdd;
extern JE_byte shieldWait, shieldT;
enum
{
SHOT_FRONT,
SHOT_REAR,
SHOT_LEFT_SIDEKICK,
SHOT_RIGHT_SIDEKICK,
SHOT_MISC,
SHOT_P2_CHARGE,
SHOT_P1_SUPERBOMB,
SHOT_P2_SUPERBOMB,
SHOT_SPECIAL,
SHOT_NORTSPARKS,
SHOT_SPECIAL2
};
extern JE_byte shotRepeat[11], shotMultiPos[11];
extern JE_boolean portConfigChange, portConfigDone;
extern char lastLevelName[11], levelName[11];
extern JE_byte mainLevel, nextLevel, saveLevel;
extern JE_KeySettingType keySettings;
extern JE_shortint levelFilter, levelFilterNew, levelBrightness, levelBrightnessChg;
extern JE_boolean filtrationAvail, filterActive, filterFade, filterFadeStart;
extern JE_boolean gameJustLoaded;
extern JE_boolean galagaMode;
extern JE_boolean extraGame;
extern JE_boolean twoPlayerMode, twoPlayerLinked, onePlayerAction, superTyrian, trentWin;
extern JE_byte superArcadeMode;
extern JE_byte superArcadePowerUp;
extern JE_real linkGunDirec;
extern JE_byte inputDevice[2];
extern JE_byte secretHint;
extern JE_byte background3over;
extern JE_byte background2over;
extern JE_byte gammaCorrection;
extern JE_boolean superPause, explosionTransparent, youAreCheating, displayScore, background2, smoothScroll, wild, superWild, starActive, topEnemyOver, skyEnemyOverAll, background2notTransparent;
extern JE_byte versionNum;
extern JE_byte fastPlay;
extern JE_boolean pentiumMode;
extern JE_byte gameSpeed;
extern JE_byte processorType;
extern JE_SaveFilesType saveFiles;
extern JE_SaveGameTemp saveTemp;
extern JE_word editorLevel;
void JE_initProcessorType( void );
void JE_setNewGameSpeed( void );
const char *get_user_directory( void );
void JE_loadConfiguration( void );
void JE_saveConfiguration( void );
void JE_setupStars( void );
void JE_saveGame( JE_byte slot, const char *name );
void JE_loadGame( JE_byte slot );
void JE_encryptSaveTemp( void );
void JE_decryptSaveTemp( void );
cJSON *load_json( const char *filename );
void save_json( cJSON *root, const char *filename );
#endif /* CONFIG_H */
// kate: tab-width 4; vim: set noet:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef DESTRUCT_H
#define DESTRUCT_H
#include "opentyr.h"
void JE_destructGame( void );
#endif /* DESTRUCT_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,92 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "config.h"
#include "editship.h"
#include "file.h"
#include "opentyr.h"
#define SAS (sizeof(JE_ShipsType) - 4)
const JE_byte extraCryptKey[10] = { 58, 23, 16, 192, 254, 82, 113, 147, 62, 99 };
JE_boolean extraAvail;
JE_ShipsType extraShips;
void *extraShapes;
JE_word extraShapeSize;
void JE_decryptShips( void )
{
JE_boolean correct = true;
JE_ShipsType s2;
JE_byte y;
for (int x = SAS - 1; x >= 0; x--)
{
s2[x] = extraShips[x] ^ extraCryptKey[(x + 1) % 10];
if (x > 0)
s2[x] ^= extraShips[x - 1];
} /* <= Key Decryption Test (Reversed key) */
y = 0;
for (uint x = 0; x < SAS; x++)
y += s2[x];
if (extraShips[SAS + 0] != y)
correct = false;
y = 0;
for (uint x = 0; x < SAS; x++)
y -= s2[x];
if (extraShips[SAS + 1] != y)
correct = false;
y = 1;
for (uint x = 0; x < SAS; x++)
y = y * s2[x] + 1;
if (extraShips[SAS + 2] != y)
correct = false;
y = 0;
for (uint x = 0; x < SAS; x++)
y ^= s2[x];
if (extraShips[SAS + 3] != y)
correct = false;
if (!correct)
exit(255);
memcpy(extraShips, s2, sizeof(extraShips));
}
void JE_loadExtraShapes( void )
{
FILE *f = dir_fopen(get_user_directory(), "newsh$.shp", "rb");
if (f)
{
extraAvail = true;
extraShapeSize = ftell_eof(f) - sizeof(extraShips);
extraShapes = malloc(extraShapeSize);
efread(extraShapes, extraShapeSize, 1, f);
efread(extraShips, sizeof(extraShips), 1, f);
JE_decryptShips();
fclose(f);
}
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,37 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef EDITSHIP_H
#define EDITSHIP_H
#include "opentyr.h"
typedef JE_byte JE_ShipsType[154]; /* [1..154] */
extern JE_boolean extraAvail;
extern JE_ShipsType extraShips;
extern void *extraShapes;
extern JE_word extraShapeSize;
void JE_decryptShips( void );
void JE_loadExtraShapes( void );
#endif /* EDITSHIP_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,267 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "config.h"
#include "episodes.h"
#include "file.h"
#include "lvllib.h"
#include "lvlmast.h"
#include "opentyr.h"
/* MAIN Weapons Data */
JE_WeaponPortType weaponPort;
JE_WeaponType weapons;
/* Items */
JE_PowerType powerSys;
JE_ShipType ships;
JE_OptionType options[OPTION_NUM + 1]; /* [0..optionnum] */
JE_ShieldType shields;
JE_SpecialType special;
/* Enemy data */
JE_EnemyDatType enemyDat;
/* EPISODE variables */
JE_byte initial_episode_num, episodeNum = 0;
JE_boolean episodeAvail[EPISODE_MAX]; /* [1..episodemax] */
char episode_file[13], cube_file[13];
JE_longint episode1DataLoc;
/* Tells the game whether the level currently loaded is a bonus level. */
JE_boolean bonusLevel;
/* Tells if the game jumped back to Episode 1 */
JE_boolean jumpBackToEpisode1;
void JE_loadItemDat( void )
{
FILE *f = NULL;
if (episodeNum <= 3)
{
f = dir_fopen_die(data_dir(), "tyrian.hdt", "rb");
efread(&episode1DataLoc, sizeof(JE_longint), 1, f);
fseek(f, episode1DataLoc, SEEK_SET);
}
else
{
// episode 4 stores item data in the level file
f = dir_fopen_die(data_dir(), levelFile, "rb");
fseek(f, lvlPos[lvlNum-1], SEEK_SET);
}
JE_word itemNum[7]; /* [1..7] */
efread(&itemNum, sizeof(JE_word), 7, f);
for (int i = 0; i < WEAP_NUM + 1; ++i)
{
efread(&weapons[i].drain, sizeof(JE_word), 1, f);
efread(&weapons[i].shotrepeat, sizeof(JE_byte), 1, f);
efread(&weapons[i].multi, sizeof(JE_byte), 1, f);
efread(&weapons[i].weapani, sizeof(JE_word), 1, f);
efread(&weapons[i].max, sizeof(JE_byte), 1, f);
efread(&weapons[i].tx, sizeof(JE_byte), 1, f);
efread(&weapons[i].ty, sizeof(JE_byte), 1, f);
efread(&weapons[i].aim, sizeof(JE_byte), 1, f);
efread(&weapons[i].attack, sizeof(JE_byte), 8, f);
efread(&weapons[i].del, sizeof(JE_byte), 8, f);
efread(&weapons[i].sx, sizeof(JE_shortint), 8, f);
efread(&weapons[i].sy, sizeof(JE_shortint), 8, f);
efread(&weapons[i].bx, sizeof(JE_shortint), 8, f);
efread(&weapons[i].by, sizeof(JE_shortint), 8, f);
efread(&weapons[i].sg, sizeof(JE_word), 8, f);
efread(&weapons[i].acceleration, sizeof(JE_shortint), 1, f);
efread(&weapons[i].accelerationx, sizeof(JE_shortint), 1, f);
efread(&weapons[i].circlesize, sizeof(JE_byte), 1, f);
efread(&weapons[i].sound, sizeof(JE_byte), 1, f);
efread(&weapons[i].trail, sizeof(JE_byte), 1, f);
efread(&weapons[i].shipblastfilter, sizeof(JE_byte), 1, f);
}
for (int i = 0; i < PORT_NUM + 1; ++i)
{
fseek(f, 1, SEEK_CUR); /* skip string length */
efread(&weaponPort[i].name, 1, 30, f);
weaponPort[i].name[30] = '\0';
efread(&weaponPort[i].opnum, sizeof(JE_byte), 1, f);
for (int j = 0; j < 2; ++j)
{
efread(&weaponPort[i].op[j], sizeof(JE_word), 11, f);
}
efread(&weaponPort[i].cost, sizeof(JE_word), 1, f);
efread(&weaponPort[i].itemgraphic, sizeof(JE_word), 1, f);
efread(&weaponPort[i].poweruse, sizeof(JE_word), 1, f);
}
for (int i = 0; i < SPECIAL_NUM + 1; ++i)
{
fseek(f, 1, SEEK_CUR); /* skip string length */
efread(&special[i].name, 1, 30, f);
special[i].name[30] = '\0';
efread(&special[i].itemgraphic, sizeof(JE_word), 1, f);
efread(&special[i].pwr, sizeof(JE_byte), 1, f);
efread(&special[i].stype, sizeof(JE_byte), 1, f);
efread(&special[i].wpn, sizeof(JE_word), 1, f);
}
for (int i = 0; i < POWER_NUM + 1; ++i)
{
fseek(f, 1, SEEK_CUR); /* skip string length */
efread(&powerSys[i].name, 1, 30, f);
powerSys[i].name[30] = '\0';
efread(&powerSys[i].itemgraphic, sizeof(JE_word), 1, f);
efread(&powerSys[i].power, sizeof(JE_shortint), 1, f);
efread(&powerSys[i].speed, sizeof(JE_byte), 1, f);
efread(&powerSys[i].cost, sizeof(JE_word), 1, f);
}
for (int i = 0; i < SHIP_NUM + 1; ++i)
{
fseek(f, 1, SEEK_CUR); /* skip string length */
efread(&ships[i].name, 1, 30, f);
ships[i].name[30] = '\0';
efread(&ships[i].shipgraphic, sizeof(JE_word), 1, f);
efread(&ships[i].itemgraphic, sizeof(JE_word), 1, f);
efread(&ships[i].ani, sizeof(JE_byte), 1, f);
efread(&ships[i].spd, sizeof(JE_shortint), 1, f);
efread(&ships[i].dmg, sizeof(JE_byte), 1, f);
efread(&ships[i].cost, sizeof(JE_word), 1, f);
efread(&ships[i].bigshipgraphic, sizeof(JE_byte), 1, f);
}
for (int i = 0; i < OPTION_NUM + 1; ++i)
{
fseek(f, 1, SEEK_CUR); /* skip string length */
efread(&options[i].name, 1, 30, f);
options[i].name[30] = '\0';
efread(&options[i].pwr, sizeof(JE_byte), 1, f);
efread(&options[i].itemgraphic, sizeof(JE_word), 1, f);
efread(&options[i].cost, sizeof(JE_word), 1, f);
efread(&options[i].tr, sizeof(JE_byte), 1, f);
efread(&options[i].option, sizeof(JE_byte), 1, f);
efread(&options[i].opspd, sizeof(JE_shortint), 1, f);
efread(&options[i].ani, sizeof(JE_byte), 1, f);
efread(&options[i].gr, sizeof(JE_word), 20, f);
efread(&options[i].wport, sizeof(JE_byte), 1, f);
efread(&options[i].wpnum, sizeof(JE_word), 1, f);
efread(&options[i].ammo, sizeof(JE_byte), 1, f);
efread(&options[i].stop, 1, 1, f); /* override sizeof(JE_boolean) */
efread(&options[i].icongr, sizeof(JE_byte), 1, f);
}
for (int i = 0; i < SHIELD_NUM + 1; ++i)
{
fseek(f, 1, SEEK_CUR); /* skip string length */
efread(&shields[i].name, 1, 30, f);
shields[i].name[30] = '\0';
efread(&shields[i].tpwr, sizeof(JE_byte), 1, f);
efread(&shields[i].mpwr, sizeof(JE_byte), 1, f);
efread(&shields[i].itemgraphic, sizeof(JE_word), 1, f);
efread(&shields[i].cost, sizeof(JE_word), 1, f);
}
for (int i = 0; i < ENEMY_NUM + 1; ++i)
{
efread(&enemyDat[i].ani, sizeof(JE_byte), 1, f);
efread(&enemyDat[i].tur, sizeof(JE_byte), 3, f);
efread(&enemyDat[i].freq, sizeof(JE_byte), 3, f);
efread(&enemyDat[i].xmove, sizeof(JE_shortint), 1, f);
efread(&enemyDat[i].ymove, sizeof(JE_shortint), 1, f);
efread(&enemyDat[i].xaccel, sizeof(JE_shortint), 1, f);
efread(&enemyDat[i].yaccel, sizeof(JE_shortint), 1, f);
efread(&enemyDat[i].xcaccel, sizeof(JE_shortint), 1, f);
efread(&enemyDat[i].ycaccel, sizeof(JE_shortint), 1, f);
efread(&enemyDat[i].startx, sizeof(JE_integer), 1, f);
efread(&enemyDat[i].starty, sizeof(JE_integer), 1, f);
efread(&enemyDat[i].startxc, sizeof(JE_shortint), 1, f);
efread(&enemyDat[i].startyc, sizeof(JE_shortint), 1, f);
efread(&enemyDat[i].armor, sizeof(JE_byte), 1, f);
efread(&enemyDat[i].esize, sizeof(JE_byte), 1, f);
efread(&enemyDat[i].egraphic, sizeof(JE_word), 20, f);
efread(&enemyDat[i].explosiontype, sizeof(JE_byte), 1, f);
efread(&enemyDat[i].animate, sizeof(JE_byte), 1, f);
efread(&enemyDat[i].shapebank, sizeof(JE_byte), 1, f);
efread(&enemyDat[i].xrev, sizeof(JE_shortint), 1, f);
efread(&enemyDat[i].yrev, sizeof(JE_shortint), 1, f);
efread(&enemyDat[i].dgr, sizeof(JE_word), 1, f);
efread(&enemyDat[i].dlevel, sizeof(JE_shortint), 1, f);
efread(&enemyDat[i].dani, sizeof(JE_shortint), 1, f);
efread(&enemyDat[i].elaunchfreq, sizeof(JE_byte), 1, f);
efread(&enemyDat[i].elaunchtype, sizeof(JE_word), 1, f);
efread(&enemyDat[i].value, sizeof(JE_integer), 1, f);
efread(&enemyDat[i].eenemydie, sizeof(JE_word), 1, f);
}
fclose(f);
}
void JE_initEpisode( JE_byte newEpisode )
{
if (newEpisode == episodeNum)
return;
episodeNum = newEpisode;
sprintf(levelFile, "tyrian%d.lvl", episodeNum);
sprintf(cube_file, "cubetxt%d.dat", episodeNum);
sprintf(episode_file, "levels%d.dat", episodeNum);
JE_analyzeLevel();
JE_loadItemDat();
}
void JE_scanForEpisodes( void )
{
for (int i = 0; i < EPISODE_MAX; ++i)
{
char ep_file[20];
snprintf(ep_file, sizeof(ep_file), "tyrian%d.lvl", i + 1);
episodeAvail[i] = dir_file_exists(data_dir(), ep_file);
}
}
unsigned int JE_findNextEpisode( void )
{
unsigned int newEpisode = episodeNum;
jumpBackToEpisode1 = false;
while (true)
{
newEpisode++;
if (newEpisode > EPISODE_MAX)
{
newEpisode = 1;
jumpBackToEpisode1 = true;
gameHasRepeated = true;
}
if (episodeAvail[newEpisode-1] || newEpisode == episodeNum)
{
break;
}
}
return newEpisode;
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,173 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef EPISODES_H
#define EPISODES_H
#include "opentyr.h"
#include "lvlmast.h"
/* Episodes and general data */
#define FIRST_LEVEL 1
#define EPISODE_MAX 5
typedef struct
{
JE_word drain;
JE_byte shotrepeat;
JE_byte multi;
JE_word weapani;
JE_byte max;
JE_byte tx, ty, aim;
JE_byte attack[8], del[8]; /* [1..8] */
JE_shortint sx[8], sy[8]; /* [1..8] */
JE_shortint bx[8], by[8]; /* [1..8] */
JE_word sg[8]; /* [1..8] */
JE_shortint acceleration, accelerationx;
JE_byte circlesize;
JE_byte sound;
JE_byte trail;
JE_byte shipblastfilter;
} JE_WeaponType[WEAP_NUM + 1]; /* [0..weapnum] */
typedef struct
{
char name[31]; /* string [30] */
JE_byte opnum;
JE_word op[2][11]; /* [1..2, 1..11] */
JE_word cost;
JE_word itemgraphic;
JE_word poweruse;
} JE_WeaponPortType[PORT_NUM + 1]; /* [0..portnum] */
typedef struct
{
char name[31]; /* string [30] */
JE_word itemgraphic;
JE_byte power;
JE_shortint speed;
JE_word cost;
} JE_PowerType[POWER_NUM + 1]; /* [0..powernum] */
typedef struct
{
char name[31]; /* string [30] */
JE_word itemgraphic;
JE_byte pwr;
JE_byte stype;
JE_word wpn;
} JE_SpecialType[SPECIAL_NUM + 1]; /* [0..specialnum] */
typedef struct
{
char name[31]; /* string [30] */
JE_byte pwr;
JE_word itemgraphic;
JE_word cost;
JE_byte tr, option;
JE_shortint opspd;
JE_byte ani;
JE_word gr[20]; /* [1..20] */
JE_byte wport;
JE_word wpnum;
JE_byte ammo;
JE_boolean stop;
JE_byte icongr;
} JE_OptionType;
typedef struct
{
char name[31]; /* string [30] */
JE_byte tpwr;
JE_byte mpwr;
JE_word itemgraphic;
JE_word cost;
} JE_ShieldType[SHIELD_NUM + 1]; /* [0..shieldnum] */
typedef struct
{
char name[31]; /* string [30] */
JE_word shipgraphic;
JE_word itemgraphic;
JE_byte ani;
JE_shortint spd;
JE_byte dmg;
JE_word cost;
JE_byte bigshipgraphic;
} JE_ShipType[SHIP_NUM + 1]; /* [0..shipnum] */
/* EnemyData */
typedef struct
{
JE_byte ani;
JE_byte tur[3]; /* [1..3] */
JE_byte freq[3]; /* [1..3] */
JE_shortint xmove;
JE_shortint ymove;
JE_shortint xaccel;
JE_shortint yaccel;
JE_shortint xcaccel;
JE_shortint ycaccel;
JE_integer startx;
JE_integer starty;
JE_shortint startxc;
JE_shortint startyc;
JE_byte armor;
JE_byte esize;
JE_word egraphic[20]; /* [1..20] */
JE_byte explosiontype;
JE_byte animate; /* 0:Not Yet 1:Always 2:When Firing Only */
JE_byte shapebank; /* See LEVELMAK.DOC */
JE_shortint xrev, yrev;
JE_word dgr;
JE_shortint dlevel;
JE_shortint dani;
JE_byte elaunchfreq;
JE_word elaunchtype;
JE_integer value;
JE_word eenemydie;
} JE_EnemyDatType[ENEMY_NUM + 1]; /* [0..enemynum] */
extern JE_WeaponPortType weaponPort;
extern JE_WeaponType weapons;
extern JE_PowerType powerSys;
extern JE_ShipType ships;
extern JE_OptionType options[OPTION_NUM + 1]; /* [0..optionnum] */
extern JE_ShieldType shields;
extern JE_SpecialType special;
extern JE_EnemyDatType enemyDat;
extern JE_byte initial_episode_num, episodeNum;
extern JE_boolean episodeAvail[EPISODE_MAX];
extern char episode_file[13], cube_file[13];
extern JE_longint episode1DataLoc;
extern JE_boolean bonusLevel;
extern JE_boolean jumpBackToEpisode1;
void JE_loadItemDat( void );
void JE_initEpisode( JE_byte newEpisode );
unsigned int JE_findNextEpisode( void );
void JE_scanForEpisodes( void );
#endif /* EPISODES_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,192 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "file.h"
#include "opentyr.h"
#include "SDL.h"
#include <errno.h>
const char *custom_data_dir = ".";
// finds the Tyrian data directory
const char *data_dir( void )
{
const char *dirs[] =
{
custom_data_dir,
"data",
#ifdef TARGET_MACOSX
tyrian_game_folder(),
#endif
"/usr/share/opentyrian/data"
};
static const char *dir = NULL;
if (dir != NULL)
return dir;
for (uint i = 0; i < COUNTOF(dirs); ++i)
{
FILE *f = dir_fopen(dirs[i], "tyrian1.lvl", "rb");
if (f)
{
fclose(f);
dir = dirs[i];
break;
}
}
if (dir == NULL) // data not found
dir = "";
return dir;
}
// prepend directory and fopen
FILE *dir_fopen( const char *dir, const char *file, const char *mode )
{
char *path = (char *)malloc(strlen(dir) + 1 + strlen(file) + 1);
sprintf(path, "%s/%s", dir, file);
FILE *f = fopen(path, mode);
free(path);
return f;
}
// warn when dir_fopen fails
FILE *dir_fopen_warn( const char *dir, const char *file, const char *mode )
{
errno = 0;
FILE *f = dir_fopen(dir, file, mode);
if (!f)
fprintf(stderr, "warning: failed to open '%s': %s\n", file, strerror(errno));
return f;
}
// die when dir_fopen fails
FILE *dir_fopen_die( const char *dir, const char *file, const char *mode )
{
errno = 0;
FILE *f = dir_fopen(dir, file, mode);
if (f == NULL)
{
fprintf(stderr, "error: failed to open '%s': %s\n", file, strerror(errno));
fprintf(stderr, "error: One or more of the required Tyrian 2.1 data files could not be found.\n"
" Please read the README file.\n");
exit(1);
}
return f;
}
// check if file can be opened for reading
bool dir_file_exists( const char *dir, const char *file )
{
FILE *f = dir_fopen(dir, file, "rb");
if (f != NULL)
fclose(f);
return (f != NULL);
}
// returns end-of-file position
long ftell_eof( FILE *f )
{
long pos = ftell(f);
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, pos, SEEK_SET);
return size;
}
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
// endian-swapping fread
size_t efread( void *buffer, size_t size, size_t num, FILE *stream )
{
size_t f = fread(buffer, size, num, stream);
switch (size)
{
case 2:
for (size_t i = 0; i < num; i++)
((Uint16 *)buffer)[i] = SDL_Swap16(((Uint16 *)buffer)[i]);
break;
case 4:
for (size_t i = 0; i < num; i++)
((Uint32 *)buffer)[i] = SDL_Swap32(((Uint32 *)buffer)[i]);
break;
case 8:
for (size_t i = 0; i < num; i++)
((Uint64 *)buffer)[i] = SDL_Swap64(((Uint64 *)buffer)[i]);
break;
default:
break;
}
return f;
}
// endian-swapping fwrite
size_t efwrite( void *buffer, size_t size, size_t num, FILE *stream )
{
void *swap_buffer;
switch (size)
{
case 2:
swap_buffer = malloc(size * num);
for (size_t i = 0; i < num; i++)
((Uint16 *)swap_buffer)[i] = SDL_SwapLE16(((Uint16 *)buffer)[i]);
break;
case 4:
swap_buffer = malloc(size * num);
for (size_t i = 0; i < num; i++)
((Uint32 *)swap_buffer)[i] = SDL_SwapLE32(((Uint32 *)buffer)[i]);
break;
case 8:
swap_buffer = malloc(size * num);
for (size_t i = 0; i < num; i++)
((Uint64 *)swap_buffer)[i] = SDL_SwapLE64(((Uint64 *)buffer)[i]);
break;
default:
swap_buffer = buffer;
break;
}
size_t f = fwrite(swap_buffer, size, num, stream);
if (swap_buffer != buffer)
free(swap_buffer);
return f;
}
#endif
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,53 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef FILE_H
#define FILE_H
#include "SDL_endian.h"
#include <stdbool.h>
#include <stdio.h>
extern const char *custom_data_dir;
#ifdef TARGET_MACOSX
const char *tyrian_game_folder();
#endif // TARGET_MACOSX
const char *data_dir( void );
FILE *dir_fopen( const char *dir, const char *file, const char *mode );
FILE *dir_fopen_warn( const char *dir, const char *file, const char *mode );
FILE *dir_fopen_die( const char *dir, const char *file, const char *mode );
bool dir_file_exists( const char *dir, const char *file );
long ftell_eof( FILE *f );
// endian-swapping fread/fwrite
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
size_t efread( void *buffer, size_t size, size_t num, FILE *stream );
size_t efwrite( void *buffer, size_t size, size_t num, FILE *stream );
#else
#define efread fread
#define efwrite fwrite
#endif
#endif // FILE_H
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,54 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "fmopl.h"
#include "fm_synth.h"
#include "loudness.h"
#include "opentyr.h"
const unsigned char op_table[9] = {0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12};
#define opl 0
void opl_update( OPLSAMPLE *buf, int samples )
{
YM3812UpdateOne(opl, buf, samples);
}
void opl_init( void )
{
YM3812Init(1, 3579545, 11025 * OUTPUT_QUALITY);
}
void opl_deinit( void )
{
YM3812Shutdown();
}
void opl_reset( void )
{
YM3812ResetChip(opl);
}
void opl_write(int reg, int val)
{
YM3812Write(opl, 0, reg);
YM3812Write(opl, 1, val);
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,35 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef FM_SYNTH_H
#define FM_SYNTH_H
#include "fmopl.h"
#include "opentyr.h"
extern const unsigned char op_table[9]; /* the 9 operators as expected by the OPL2 */
void opl_update( OPLSAMPLE *buf, int samples );
void opl_init( void );
void opl_deinit( void );
void opl_reset( void );
void opl_write( int, int );
#endif /* FM_SYNTH_H */
// kate: tab-width 4; vim: set noet:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,253 @@
#ifndef __FMOPL_H_
#define __FMOPL_H_
/* --- select emulation chips --- */
#define BUILD_YM3812 1 /* (HAS_YM3812) */
#define BUILD_YM3526 (HAS_YM3526)
#define BUILD_Y8950 (HAS_Y8950)
/* select output bits size of output : 8 or 16 */
#define OPL_SAMPLE_BITS 16
/* compiler dependence */
#ifndef OSD_CPU_H
#define OSD_CPU_H
typedef unsigned char UINT8; /* unsigned 8bit */
typedef unsigned short UINT16; /* unsigned 16bit */
typedef unsigned int UINT32; /* unsigned 32bit */
typedef signed char INT8; /* signed 8bit */
typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */
#endif
#if (OPL_SAMPLE_BITS==16)
typedef INT16 OPLSAMPLE;
#endif
#if (OPL_SAMPLE_BITS==8)
typedef INT8 OPLSAMPLE;
#endif
typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
typedef void (*OPL_IRQHANDLER)(int param,int irq);
typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
typedef struct{
UINT32 ar; /* attack rate: AR<<2 */
UINT32 dr; /* decay rate: DR<<2 */
UINT32 rr; /* release rate:RR<<2 */
UINT8 KSR; /* key scale rate */
UINT8 ksl; /* keyscale level */
UINT8 ksr; /* key scale rate: kcode>>KSR */
UINT8 mul; /* multiple: mul_tab[ML] */
/* Phase Generator */
UINT32 Cnt; /* frequency counter */
UINT32 Incr; /* frequency counter step */
UINT8 FB; /* feedback shift value */
INT32 *connect1; /* slot1 output pointer */
INT32 op1_out[2]; /* slot1 output for feedback */
UINT8 CON; /* connection (algorithm) type */
/* Envelope Generator */
UINT8 eg_type; /* percussive/non-percussive mode */
UINT8 state; /* phase type */
UINT32 TL; /* total level: TL << 2 */
INT32 TLL; /* adjusted now TL */
INT32 volume; /* envelope counter */
UINT32 sl; /* sustain level: sl_tab[SL] */
UINT8 eg_sh_ar; /* (attack state) */
UINT8 eg_sel_ar; /* (attack state) */
UINT8 eg_sh_dr; /* (decay state) */
UINT8 eg_sel_dr; /* (decay state) */
UINT8 eg_sh_rr; /* (release state) */
UINT8 eg_sel_rr; /* (release state) */
UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */
/* LFO */
UINT32 AMmask; /* LFO Amplitude Modulation enable mask */
UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/
/* waveform select */
unsigned int wavetable;
} OPL_SLOT;
typedef struct{
OPL_SLOT SLOT[2];
/* phase generator state */
UINT32 block_fnum; /* block+fnum */
UINT32 fc; /* Freq. Increment base */
UINT32 ksl_base; /* KeyScaleLevel Base step */
UINT8 kcode; /* key code (for key scaling) */
} OPL_CH;
/* OPL state */
typedef struct fm_opl_f {
/* FM channel slots */
OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/
UINT32 eg_cnt; /* global envelope generator counter */
UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */
UINT32 eg_timer_add; /* step of eg_timer */
UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */
UINT8 rhythm; /* Rhythm mode */
UINT32 fn_tab[1024]; /* fnumber->increment counter */
/* LFO */
UINT8 lfo_am_depth;
UINT8 lfo_pm_depth_range;
UINT32 lfo_am_cnt;
UINT32 lfo_am_inc;
UINT32 lfo_pm_cnt;
UINT32 lfo_pm_inc;
UINT32 noise_rng; /* 23 bit noise shift register */
UINT32 noise_p; /* current noise 'phase' */
UINT32 noise_f; /* current noise period */
UINT8 wavesel; /* waveform select enable flag */
int T[2]; /* timer counters */
int TC[2];
UINT8 st[2]; /* timer enable */
#if BUILD_Y8950
/* Delta-T ADPCM unit (Y8950) */
YM_DELTAT *deltat;
/* Keyboard and I/O ports interface */
UINT8 portDirection;
UINT8 portLatch;
OPL_PORTHANDLER_R porthandler_r;
OPL_PORTHANDLER_W porthandler_w;
int port_param;
OPL_PORTHANDLER_R keyboardhandler_r;
OPL_PORTHANDLER_W keyboardhandler_w;
int keyboard_param;
#endif
/* external event callback handlers */
OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
int TimerParam; /* TIMER parameter */
OPL_IRQHANDLER IRQHandler; /* IRQ handler */
int IRQParam; /* IRQ parameter */
OPL_UPDATEHANDLER UpdateHandler;/* stream update handler */
int UpdateParam; /* stream update parameter */
UINT8 type; /* chip type */
UINT8 address; /* address register */
UINT8 status; /* status flag */
UINT8 statusmask; /* status mask */
UINT8 mode; /* Reg.08 : CSM,notesel,etc. */
int clock; /* master clock (Hz) */
int rate; /* sampling rate (Hz) */
double freqbase; /* frequency base */
double TimerBase; /* Timer base time (==sampling time)*/
} FM_OPL;
#if BUILD_YM3812
int YM3812Init(int num, int clock, int rate);
void YM3812Shutdown(void);
void YM3812ResetChip(int which);
int YM3812Write(int which, int a, int v);
unsigned char YM3812Read(int which, int a);
int YM3812TimerOver(int which, int c);
void YM3812UpdateOne(int which, OPLSAMPLE *buffer, int length);
void YM3812SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset);
void YM3812SetIRQHandler(int which, OPL_IRQHANDLER IRQHandler, int param);
void YM3812SetUpdateHandler(int which, OPL_UPDATEHANDLER UpdateHandler, int param);
#endif
#if BUILD_YM3526
/*
** Initialize YM3526 emulator(s).
**
** 'num' is the number of virtual YM3526's to allocate
** 'clock' is the chip clock in Hz
** 'rate' is sampling rate
*/
int YM3526Init(int num, int clock, int rate);
/* shutdown the YM3526 emulators*/
void YM3526Shutdown(void);
void YM3526ResetChip(int which);
int YM3526Write(int which, int a, int v);
unsigned char YM3526Read(int which, int a);
int YM3526TimerOver(int which, int c);
/*
** Generate samples for one of the YM3526's
**
** 'which' is the virtual YM3526 number
** '*buffer' is the output buffer pointer
** 'length' is the number of samples that should be generated
*/
void YM3526UpdateOne(int which, INT16 *buffer, int length);
void YM3526SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset);
void YM3526SetIRQHandler(int which, OPL_IRQHANDLER IRQHandler, int param);
void YM3526SetUpdateHandler(int which, OPL_UPDATEHANDLER UpdateHandler, int param);
#endif
#if BUILD_Y8950
#include "ymdeltat.h"
/* Y8950 port handlers */
void Y8950SetPortHandler(int which, OPL_PORTHANDLER_W PortHandler_w, OPL_PORTHANDLER_R PortHandler_r, int param);
void Y8950SetKeyboardHandler(int which, OPL_PORTHANDLER_W KeyboardHandler_w, OPL_PORTHANDLER_R KeyboardHandler_r, int param);
void Y8950SetDeltaTMemory(int which, void * deltat_mem_ptr, int deltat_mem_size );
int Y8950Init (int num, int clock, int rate);
void Y8950Shutdown (void);
void Y8950ResetChip (int which);
int Y8950Write (int which, int a, int v);
unsigned char Y8950Read (int which, int a);
int Y8950TimerOver (int which, int c);
void Y8950UpdateOne (int which, INT16 *buffer, int length);
void Y8950SetTimerHandler (int which, OPL_TIMERHANDLER TimerHandler, int channelOffset);
void Y8950SetIRQHandler (int which, OPL_IRQHANDLER IRQHandler, int param);
void Y8950SetUpdateHandler (int which, OPL_UPDATEHANDLER UpdateHandler, int param);
#endif
int limit( int val, int max, int min );
void OPL_STATUS_SET(FM_OPL *OPL,int flag);
void OPL_STATUS_RESET(FM_OPL *OPL,int flag);
void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag);
void advance_lfo(FM_OPL *OPL);
void advance(FM_OPL *OPL);
signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab);
signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab);
void OPL_CALC_CH( OPL_CH *CH );
void OPL_CALC_RH( OPL_CH *CH, unsigned int noise );
void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set);
void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr);
void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT);
void set_mul(FM_OPL *OPL,int slot,int v);
void set_ksl_tl(FM_OPL *OPL,int slot,int v);
void set_ar_dr(FM_OPL *OPL,int slot,int v);
void set_sl_rr(FM_OPL *OPL,int slot,int v);
void CSMKeyControll(OPL_CH *CH);
#endif
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,171 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "font.h"
#include "fonthand.h"
#include "sprite.h"
// like JE_dString() if (black == false && shadow_dist == 2 && hue == 15)
// like JE_textShade() with PART_SHADE if (black == true && shadow_dist == 1)
// like JE_outTextAndDarken() if (black == false && shadow_dist == 1)
// like JE_outTextAdjust() with shadow if (black == false && shadow_dist == 2)
void draw_font_hv_shadow( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, Uint8 hue, Sint8 value, bool black, int shadow_dist )
{
draw_font_dark(surface, x + shadow_dist, y + shadow_dist, text, font, alignment, black);
draw_font_hv(surface, x, y, text, font, alignment, hue, value);
}
// like JE_textShade() with FULL_SHADE if (black == true && shadow_dist == 1)
void draw_font_hv_full_shadow( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, Uint8 hue, Sint8 value, bool black, int shadow_dist )
{
draw_font_dark(surface, x, y - shadow_dist, text, font, alignment, black);
draw_font_dark(surface, x + shadow_dist, y, text, font, alignment, black);
draw_font_dark(surface, x, y + shadow_dist, text, font, alignment, black);
draw_font_dark(surface, x - shadow_dist, y, text, font, alignment, black);
draw_font_hv(surface, x, y, text, font, alignment, hue, value);
}
// like JE_outText() with (brightness >= 0)
// like JE_outTextAdjust() without shadow
void draw_font_hv( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, Uint8 hue, Sint8 value )
{
switch (alignment)
{
case left_aligned:
break;
case centered:
x -= JE_textWidth(text, font) / 2;
break;
case right_aligned:
x -= JE_textWidth(text, font);
break;
}
bool highlight = false;
for (; *text != '\0'; ++text)
{
int sprite_id = font_ascii[(unsigned char)*text];
switch (*text)
{
case ' ':
x += 6;
break;
case '~':
highlight = !highlight;
if (highlight)
value += 4;
else
value -= 4;
break;
default:
if (sprite_id != -1 && sprite_exists(font, sprite_id))
{
blit_sprite_hv(surface, x, y, font, sprite_id, hue, value);
x += sprite(font, sprite_id)->width + 1;
}
break;
}
}
}
// like JE_outTextModify()
void draw_font_hv_blend( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, Uint8 hue, Sint8 value )
{
switch (alignment)
{
case left_aligned:
break;
case centered:
x -= JE_textWidth(text, font) / 2;
break;
case right_aligned:
x -= JE_textWidth(text, font);
break;
}
for (; *text != '\0'; ++text)
{
int sprite_id = font_ascii[(unsigned char)*text];
switch (*text)
{
case ' ':
x += 6;
break;
case '~':
break;
default:
if (sprite_id != -1 && sprite_exists(font, sprite_id))
{
blit_sprite_hv_blend(surface, x, y, font, sprite_id, hue, value);
x += sprite(font, sprite_id)->width + 1;
}
break;
}
}
}
// like JE_outText() with (brightness < 0) if (black == true)
void draw_font_dark( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, bool black )
{
switch (alignment)
{
case left_aligned:
break;
case centered:
x -= JE_textWidth(text, font) / 2;
break;
case right_aligned:
x -= JE_textWidth(text, font);
break;
}
for (; *text != '\0'; ++text)
{
int sprite_id = font_ascii[(unsigned char)*text];
switch (*text)
{
case ' ':
x += 6;
break;
case '~':
break;
default:
if (sprite_id != -1 && sprite_exists(font, sprite_id))
{
blit_sprite_dark(surface, x, y, font, sprite_id, black);
x += sprite(font, sprite_id)->width + 1;
}
break;
}
}
}

View File

@@ -0,0 +1,48 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef FONT_H
#define FONT_H
#include "SDL.h"
#include <stdbool.h>
typedef enum
{
large_font = 0,
normal_font = 1,
small_font = 2
}
Font;
typedef enum
{
left_aligned,
centered,
right_aligned
}
FontAlignment;
void draw_font_hv_shadow( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, Uint8 hue, Sint8 value, bool black, int shadow_dist );
void draw_font_hv_full_shadow( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, Uint8 hue, Sint8 value, bool black, int shadow_dist );
void draw_font_hv( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, Uint8 hue, Sint8 value );
void draw_font_hv_blend( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, Uint8 hue, Sint8 value );
void draw_font_dark( SDL_Surface *, int x, int y, const char *text, Font, FontAlignment, bool black );
#endif // FONT_H

View File

@@ -0,0 +1,333 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "fonthand.h"
#include "network.h"
#include "nortsong.h"
#include "nortvars.h"
#include "opentyr.h"
#include "params.h"
#include "sprite.h"
#include "vga256d.h"
#include "video.h"
const int font_ascii[256] =
{
-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, 26, 33, 60, 61, 62, -1, 32, 64, 65, 63, 84, 29, 83, 28, 80, // !"#$%&'()*+,-./
79, 70, 71, 72, 73, 74, 75, 76, 77, 78, 31, 30, -1, 85, -1, 27, // 0123456789:;<=>?
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // @ABCDEFGHIJKLMNO
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 68, 82, 69, -1, -1, // PQRSTUVWXYZ[\]^_
-1, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // `abcdefghijklmno
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 66, 81, 67, -1, -1, // pqrstuvwxyz{|}~⌂
86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, // ÇüéâäàåçêëèïîìÄÅ
102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, // ÉæÆôöòûùÿÖÜ¢£¥₧ƒ
118, 119, 120, 121, 122, 123, 124, 125, 126, -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, -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, -1, -1, -1, -1, -1, -1, -1,
};
/* shape constants included in newshape.h */
JE_integer defaultBrightness = -3;
JE_byte textGlowFont, textGlowBrightness = 6;
JE_boolean levelWarningDisplay;
JE_byte levelWarningLines;
char levelWarningText[10][61]; /* [1..10] of string [60] */
JE_boolean warningRed;
JE_byte warningSoundDelay;
JE_word armorShipDelay;
JE_byte warningCol;
JE_shortint warningColChange;
void JE_dString( SDL_Surface * screen, int x, int y, const char *s, unsigned int font )
{
int bright = 0;
for (int i = 0; s[i] != '\0'; ++i)
{
int sprite_id = font_ascii[(unsigned char)s[i]];
switch (s[i])
{
case ' ':
x += 6;
break;
case '~':
bright = (bright == 0) ? 2 : 0;
break;
default:
if (sprite_id != -1)
{
blit_sprite_dark(screen, x + 2, y + 2, font, sprite_id, false);
blit_sprite_hv_unsafe(screen, x, y, font, sprite_id, 0xf, defaultBrightness + bright);
x += sprite(font, sprite_id)->width + 1;
}
break;
}
}
}
int JE_fontCenter( const char *s, unsigned int font )
{
return 160 - (JE_textWidth(s, font) / 2);
}
int JE_textWidth( const char *s, unsigned int font )
{
int x = 0;
for (int i = 0; s[i] != '\0'; ++i)
{
int sprite_id = font_ascii[(unsigned char)s[i]];
if (s[i] == ' ')
x += 6;
else if (sprite_id != -1)
x += sprite(font, sprite_id)->width + 1;
}
return x;
}
void JE_textShade( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, int brightness, unsigned int shadetype )
{
switch (shadetype)
{
case PART_SHADE:
JE_outText(screen, x+1, y+1, s, 0, -1);
JE_outText(screen, x, y, s, colorbank, brightness);
break;
case FULL_SHADE:
JE_outText(screen, x-1, y, s, 0, -1);
JE_outText(screen, x+1, y, s, 0, -1);
JE_outText(screen, x, y-1, s, 0, -1);
JE_outText(screen, x, y+1, s, 0, -1);
JE_outText(screen, x, y, s, colorbank, brightness);
break;
case DARKEN:
JE_outTextAndDarken(screen, x+1, y+1, s, colorbank, brightness, TINY_FONT);
break;
case TRICK:
JE_outTextModify(screen, x, y, s, colorbank, brightness, TINY_FONT);
break;
}
}
void JE_outText( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, int brightness )
{
int bright = 0;
for (int i = 0; s[i] != '\0'; ++i)
{
int sprite_id = font_ascii[(unsigned char)s[i]];
switch (s[i])
{
case ' ':
x += 6;
break;
case '~':
bright = (bright == 0) ? 4 : 0;
break;
default:
if (sprite_id != -1 && sprite_exists(TINY_FONT, sprite_id))
{
if (brightness >= 0)
blit_sprite_hv_unsafe(screen, x, y, TINY_FONT, sprite_id, colorbank, brightness + bright);
else
blit_sprite_dark(screen, x, y, TINY_FONT, sprite_id, true);
x += sprite(TINY_FONT, sprite_id)->width + 1;
}
break;
}
}
}
void JE_outTextModify( SDL_Surface * screen, int x, int y, const char *s, unsigned int filter, unsigned int brightness, unsigned int font )
{
for (int i = 0; s[i] != '\0'; ++i)
{
int sprite_id = font_ascii[(unsigned char)s[i]];
if (s[i] == ' ')
{
x += 6;
}
else if (sprite_id != -1)
{
blit_sprite_hv_blend(screen, x, y, font, sprite_id, filter, brightness);
x += sprite(font, sprite_id)->width + 1;
}
}
}
void JE_outTextAdjust( SDL_Surface * screen, int x, int y, const char *s, unsigned int filter, int brightness, unsigned int font, JE_boolean shadow )
{
int bright = 0;
for (int i = 0; s[i] != '\0'; ++i)
{
int sprite_id = font_ascii[(unsigned char)s[i]];
switch (s[i])
{
case ' ':
x += 6;
break;
case '~':
bright = (bright == 0) ? 4 : 0;
break;
default:
if (sprite_id != -1 && sprite_exists(TINY_FONT, sprite_id))
{
if (shadow)
blit_sprite_dark(screen, x + 2, y + 2, font, sprite_id, false);
blit_sprite_hv(screen, x, y, font, sprite_id, filter, brightness + bright);
x += sprite(font, sprite_id)->width + 1;
}
break;
}
}
}
void JE_outTextAndDarken( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, unsigned int brightness, unsigned int font )
{
int bright = 0;
for (int i = 0; s[i] != '\0'; ++i)
{
int sprite_id = font_ascii[(unsigned char)s[i]];
switch (s[i])
{
case ' ':
x += 6;
break;
case '~':
bright = (bright == 0) ? 4 : 0;
break;
default:
if (sprite_id != -1 && sprite_exists(TINY_FONT, sprite_id))
{
blit_sprite_dark(screen, x + 1, y + 1, font, sprite_id, false);
blit_sprite_hv_unsafe(screen, x, y, font, sprite_id, colorbank, brightness + bright);
x += sprite(font, sprite_id)->width + 1;
}
break;
}
}
}
void JE_updateWarning( SDL_Surface * screen )
{
if (delaycount2() == 0)
{ /*Update Color Bars*/
warningCol += warningColChange;
if (warningCol > 14 * 16 + 10 || warningCol < 14 * 16 + 4)
{
warningColChange = -warningColChange;
}
fill_rectangle_xy(screen, 0, 0, 319, 5, warningCol);
fill_rectangle_xy(screen, 0, 194, 319, 199, warningCol);
JE_showVGA();
setjasondelay2(6);
if (warningSoundDelay > 0)
{
warningSoundDelay--;
}
else
{
warningSoundDelay = 14;
JE_playSampleNum(17);
}
}
}
void JE_outTextGlow( SDL_Surface * screen, int x, int y, const char *s )
{
JE_integer z;
JE_byte c = 15;
if (warningRed)
{
c = 7;
}
JE_outTextAdjust(screen, x - 1, y, s, 0, -12, textGlowFont, false);
JE_outTextAdjust(screen, x, y - 1, s, 0, -12, textGlowFont, false);
JE_outTextAdjust(screen, x + 1, y, s, 0, -12, textGlowFont, false);
JE_outTextAdjust(screen, x, y + 1, s, 0, -12, textGlowFont, false);
if (frameCountMax > 0)
for (z = 1; z <= 12; z++)
{
setjasondelay(frameCountMax);
JE_outTextAdjust(screen, x, y, s, c, z - 10, textGlowFont, false);
if (JE_anyButton())
{
frameCountMax = 0;
}
NETWORK_KEEP_ALIVE();
JE_showVGA();
wait_delay();
}
for (z = (frameCountMax == 0) ? 6 : 12; z >= textGlowBrightness; z--)
{
setjasondelay(frameCountMax);
JE_outTextAdjust(screen, x, y, s, c, z - 10, textGlowFont, false);
if (JE_anyButton())
{
frameCountMax = 0;
}
NETWORK_KEEP_ALIVE();
JE_showVGA();
wait_delay();
}
textGlowBrightness = 6;
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,60 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef FONTHAND_H
#define FONTHAND_H
#include "opentyr.h"
#include "SDL.h"
#define PART_SHADE 0
#define FULL_SHADE 1
#define DARKEN 2
#define TRICK 3
#define NO_SHADE 255
extern const int font_ascii[256];
extern JE_integer defaultBrightness;
extern JE_byte textGlowFont, textGlowBrightness;
extern JE_boolean levelWarningDisplay;
extern JE_byte levelWarningLines;
extern char levelWarningText[10][61];
extern JE_boolean warningRed;
extern JE_byte warningSoundDelay;
extern JE_word armorShipDelay;
extern JE_byte warningCol;
extern JE_shortint warningColChange;
void JE_dString( SDL_Surface * screen, int x, int y, const char *s, unsigned int font );
int JE_fontCenter( const char *s, unsigned int font );
int JE_textWidth( const char *s, unsigned int font );
void JE_textShade( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, int brightness, unsigned int shadetype );
void JE_outText( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, int brightness );
void JE_outTextModify( SDL_Surface * screen, int x, int y, const char *s, unsigned int filter, unsigned int brightness, unsigned int font );
void JE_outTextAdjust( SDL_Surface * screen, int x, int y, const char *s, unsigned int filter, int brightness, unsigned int font, bool shadow );
void JE_outTextAndDarken( SDL_Surface * screen, int x, int y, const char *s, unsigned int colorbank, unsigned int brightness, unsigned int font );
void JE_updateWarning( SDL_Surface * screen );
void JE_outTextGlow( SDL_Surface * screen, int x, int y, const char *s );
#endif /* FONTHAND_H */
// kate: tab-width 4; vim: set noet:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef GAME_MENU_H
#define GAME_MENU_H
#include "helptext.h"
#include "opentyr.h"
typedef JE_byte JE_MenuChoiceType[MAX_MENU];
JE_longint JE_cashLeft( void );
void JE_itemScreen( void );
void load_cubes( void );
bool load_cube( int cube_slot, int cube_index );
void JE_drawItem( JE_byte itemType, JE_word itemNum, JE_word x, JE_word y );
void JE_drawMenuHeader( void );
void JE_drawMenuChoices( void );
void JE_updateNavScreen( void );
void JE_drawNavLines( JE_boolean dark );
void JE_drawLines( SDL_Surface *surface, JE_boolean dark );
void JE_drawDots( void );
void JE_drawPlanet( JE_byte planetNum );
void draw_ship_illustration( void );
void JE_scaleBitmap( SDL_Surface *dst, const SDL_Surface *src, int x1, int y1, int x2, int y2 );
void JE_initWeaponView( void );
void JE_computeDots( void );
JE_integer JE_partWay( JE_integer start, JE_integer finish, JE_byte dots, JE_byte dist );
void JE_doShipSpecs( void );
void JE_drawMainMenuHelpText( void );
JE_boolean JE_quitRequest( void );
void JE_genItemMenu( JE_byte itemnum );
void JE_scaleInPicture( SDL_Surface *dst, const SDL_Surface *src );
void JE_drawScore( void );
void JE_menuFunction( JE_byte select );
void JE_drawShipSpecs( SDL_Surface *, SDL_Surface * );
void JE_weaponSimUpdate( void );
void JE_weaponViewFrame( void );
#endif // GAME_MENU_H
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,383 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "config.h"
#include "episodes.h"
#include "file.h"
#include "fonthand.h"
#include "helptext.h"
#include "menus.h"
#include "opentyr.h"
#include "video.h"
#include <assert.h>
#include <string.h>
const JE_byte menuHelp[MAX_MENU][11] = /* [1..maxmenu, 1..11] */
{
{ 1, 34, 2, 3, 4, 5, 0, 0, 0, 0, 0 },
{ 6, 7, 8, 9, 10, 11, 11, 12, 0, 0, 0 },
{ 13, 14, 15, 15, 16, 17, 12, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 4, 30, 30, 3, 5, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 16, 17, 15, 15, 12, 0, 0, 0, 0, 0, 0 },
{ 31, 31, 31, 31, 32, 12, 0, 0, 0, 0, 0 },
{ 4, 34, 3, 5, 0, 0, 0, 0, 0, 0, 0 }
};
JE_byte verticalHeight = 7;
JE_byte helpBoxColor = 12;
JE_byte helpBoxBrightness = 1;
JE_byte helpBoxShadeType = FULL_SHADE;
char helpTxt[MAX_HELP_MESSAGE][231]; /* [1..maxhelpmessage] of string [230]; */
char pName[21][16]; /* [1..21] of string [15] */
char miscText[68][42]; /* [1..68] of string [41] */
char miscTextB[5][11]; /* [1..5] of string [10] */
char keyName[8][18]; /* [1..8] of string [17] */
char menuText[7][21]; /* [1..7] of string [20] */
char outputs[9][31]; /* [1..9] of string [30] */
char topicName[6][21]; /* [1..6] of string [20] */
char mainMenuHelp[34][66];
char inGameText[6][21]; /* [1..6] of string [20] */
char detailLevel[6][13]; /* [1..6] of string [12] */
char gameSpeedText[5][13]; /* [1..5] of string [12] */
char inputDevices[3][13]; /* [1..3] of string [12] */
char networkText[4][22]; /* [1..4] of string [20] */
char difficultyNameB[11][21]; /* [0..9] of string [20] */
char joyButtonNames[5][21]; /* [1..5] of string [20] */
char superShips[11][26]; /* [0..10] of string [25] */
char specialName[9][10]; /* [1..9] of string [9] */
char destructHelp[25][22];
char weaponNames[17][17]; /* [1..17] of string [16] */
char destructModeName[DESTRUCT_MODES][13]; /* [1..destructmodes] of string [12] */
char shipInfo[13][2][256];
char menuInt[MAX_MENU + 1][11][18]; /* [0..maxmenu, 1..11] of string [17] */
void decrypt_pascal_string( char *s, int len )
{
static const unsigned char crypt_key[] = { 204, 129, 63, 255, 71, 19, 25, 62, 1, 99 };
for (int i = len - 1; i >= 0; --i)
{
s[i] ^= crypt_key[i % sizeof(crypt_key)];
if (i > 0)
s[i] ^= s[i - 1];
}
}
void read_encrypted_pascal_string( char *s, int size, FILE *f )
{
int len = getc(f);
if (len != EOF)
{
int skip = MAX((len + 1) - size, 0);
assert(skip == 0);
len -= skip;
efread(s, 1, len, f);
if (size > 0)
s[len] = '\0';
fseek(f, skip, SEEK_CUR);
decrypt_pascal_string(s, len);
}
}
void skip_pascal_string( FILE *f )
{
int len = getc(f);
fseek(f, len, SEEK_CUR);
}
void JE_helpBox( SDL_Surface *screen, int x, int y, const char *message, unsigned int boxwidth )
{
JE_byte startpos, endpos, pos;
JE_boolean endstring;
char substring[256];
if (strlen(message) == 0)
{
return;
}
pos = 1;
endpos = 0;
endstring = false;
do
{
startpos = endpos + 1;
do
{
endpos = pos;
do
{
pos++;
if (pos == strlen(message))
{
endstring = true;
if ((unsigned)(pos - startpos) < boxwidth)
{
endpos = pos + 1;
}
}
} while (!(message[pos-1] == ' ' || endstring));
} while (!((unsigned)(pos - startpos) > boxwidth || endstring));
JE_textShade(screen, x, y, strnztcpy(substring, message + startpos - 1, endpos - startpos), helpBoxColor, helpBoxBrightness, helpBoxShadeType);
y += verticalHeight;
} while (!endstring);
if (endpos != pos + 1)
{
JE_textShade(screen, x, y, message + endpos, helpBoxColor, helpBoxBrightness, helpBoxShadeType);
}
helpBoxColor = 12;
helpBoxShadeType = FULL_SHADE;
}
void JE_HBox( SDL_Surface *screen, int x, int y, unsigned int messagenum, unsigned int boxwidth )
{
JE_helpBox(screen, x, y, helpTxt[messagenum-1], boxwidth);
}
void JE_loadHelpText( void )
{
FILE *f = dir_fopen_die(data_dir(), "tyrian.hdt", "rb");
efread(&episode1DataLoc, sizeof(JE_longint), 1, f);
/*Online Help*/
skip_pascal_string(f);
for (int i = 0; i < MAX_HELP_MESSAGE; ++i)
read_encrypted_pascal_string(helpTxt[i], sizeof(helpTxt[i]), f);
skip_pascal_string(f);
/*Planet names*/
skip_pascal_string(f);
for (int i = 0; i < 21; ++i)
read_encrypted_pascal_string(pName[i], sizeof(pName[i]), f);
skip_pascal_string(f);
/*Miscellaneous text*/
skip_pascal_string(f);
for (int i = 0; i < 68; ++i)
read_encrypted_pascal_string(miscText[i], sizeof(miscText[i]), f);
skip_pascal_string(f);
/*Little Miscellaneous text*/
skip_pascal_string(f);
for (int i = 0; i < 5; ++i)
read_encrypted_pascal_string(miscTextB[i], sizeof(miscTextB[i]), f);
skip_pascal_string(f);
/*Key names*/
skip_pascal_string(f);
for (int i = 0; i < 11; ++i)
read_encrypted_pascal_string(menuInt[6][i], sizeof(menuInt[6][i]), f);
skip_pascal_string(f);
/*Main Menu*/
skip_pascal_string(f);
for (int i = 0; i < 7; ++i)
read_encrypted_pascal_string(menuText[i], sizeof(menuText[i]), f);
skip_pascal_string(f);
/*Event text*/
skip_pascal_string(f);
for (int i = 0; i < 9; ++i)
read_encrypted_pascal_string(outputs[i], sizeof(outputs[i]), f);
skip_pascal_string(f);
/*Help topics*/
skip_pascal_string(f);
for (int i = 0; i < 6; ++i)
read_encrypted_pascal_string(topicName[i], sizeof(topicName[i]), f);
skip_pascal_string(f);
/*Main Menu Help*/
skip_pascal_string(f);
for (int i = 0; i < 34; ++i)
read_encrypted_pascal_string(mainMenuHelp[i], sizeof(mainMenuHelp[i]), f);
skip_pascal_string(f);
/*Menu 1 - Main*/
skip_pascal_string(f);
for (int i = 0; i < 7; ++i)
read_encrypted_pascal_string(menuInt[1][i], sizeof(menuInt[1][i]), f);
skip_pascal_string(f);
/*Menu 2 - Items*/
skip_pascal_string(f);
for (int i = 0; i < 9; ++i)
read_encrypted_pascal_string(menuInt[2][i], sizeof(menuInt[2][i]), f);
skip_pascal_string(f);
/*Menu 3 - Options*/
skip_pascal_string(f);
for (int i = 0; i < 8; ++i)
read_encrypted_pascal_string(menuInt[3][i], sizeof(menuInt[3][i]), f);
skip_pascal_string(f);
/*InGame Menu*/
skip_pascal_string(f);
for (int i = 0; i < 6; ++i)
read_encrypted_pascal_string(inGameText[i], sizeof(inGameText[i]), f);
skip_pascal_string(f);
/*Detail Level*/
skip_pascal_string(f);
for (int i = 0; i < 6; ++i)
read_encrypted_pascal_string(detailLevel[i], sizeof(detailLevel[i]), f);
skip_pascal_string(f);
/*Game speed text*/
skip_pascal_string(f);
for (int i = 0; i < 5; ++i)
read_encrypted_pascal_string(gameSpeedText[i], sizeof(gameSpeedText[i]), f);
skip_pascal_string(f);
// episode names
skip_pascal_string(f);
for (int i = 0; i <= 5; ++i)
read_encrypted_pascal_string(episode_name[i], sizeof(episode_name[i]), f);
skip_pascal_string(f);
// difficulty names
skip_pascal_string(f);
for (int i = 0; i <= 6; ++i)
read_encrypted_pascal_string(difficulty_name[i], sizeof(difficulty_name[i]), f);
skip_pascal_string(f);
// gameplay mode names
skip_pascal_string(f);
for (int i = 0; i <= 4; ++i)
read_encrypted_pascal_string(gameplay_name[i], sizeof(gameplay_name[i]), f);
skip_pascal_string(f);
/*Menu 10 - 2Player Main*/
skip_pascal_string(f);
for (int i = 0; i < 6; ++i)
read_encrypted_pascal_string(menuInt[10][i], sizeof(menuInt[10][i]), f);
skip_pascal_string(f);
/*Input Devices*/
skip_pascal_string(f);
for (int i = 0; i < 3; ++i)
read_encrypted_pascal_string(inputDevices[i], sizeof(inputDevices[i]), f);
skip_pascal_string(f);
/*Network text*/
skip_pascal_string(f);
for (int i = 0; i < 4; ++i)
read_encrypted_pascal_string(networkText[i], sizeof(networkText[i]), f);
skip_pascal_string(f);
/*Menu 11 - 2Player Network*/
skip_pascal_string(f);
for (int i = 0; i < 4; ++i)
read_encrypted_pascal_string(menuInt[11][i], sizeof(menuInt[11][i]), f);
skip_pascal_string(f);
/*HighScore Difficulty Names*/
skip_pascal_string(f);
for (int i = 0; i <= 10; ++i)
read_encrypted_pascal_string(difficultyNameB[i], sizeof(difficultyNameB[i]), f);
skip_pascal_string(f);
/*Menu 12 - Network Options*/
skip_pascal_string(f);
for (int i = 0; i < 6; ++i)
read_encrypted_pascal_string(menuInt[12][i], sizeof(menuInt[12][i]), f);
skip_pascal_string(f);
/*Menu 13 - Joystick*/
skip_pascal_string(f);
for (int i = 0; i < 7; ++i)
read_encrypted_pascal_string(menuInt[13][i], sizeof(menuInt[13][i]), f);
skip_pascal_string(f);
/*Joystick Button Assignments*/
skip_pascal_string(f);
for (int i = 0; i < 5; ++i)
read_encrypted_pascal_string(joyButtonNames[i], sizeof(joyButtonNames[i]), f);
skip_pascal_string(f);
/*SuperShips - For Super Arcade Mode*/
skip_pascal_string(f);
for (int i = 0; i <= 10; ++i)
read_encrypted_pascal_string(superShips[i], sizeof(superShips[i]), f);
skip_pascal_string(f);
/*SuperShips - For Super Arcade Mode*/
skip_pascal_string(f);
for (int i = 0; i < 9; ++i)
read_encrypted_pascal_string(specialName[i], sizeof(specialName[i]), f);
skip_pascal_string(f);
/*Secret DESTRUCT game*/
skip_pascal_string(f);
for (int i = 0; i < 25; ++i)
read_encrypted_pascal_string(destructHelp[i], sizeof(destructHelp[i]), f);
skip_pascal_string(f);
/*Secret DESTRUCT weapons*/
skip_pascal_string(f);
for (int i = 0; i < 17; ++i)
read_encrypted_pascal_string(weaponNames[i], sizeof(weaponNames[i]), f);
skip_pascal_string(f);
/*Secret DESTRUCT modes*/
skip_pascal_string(f);
for (int i = 0; i < DESTRUCT_MODES; ++i)
read_encrypted_pascal_string(destructModeName[i], sizeof(destructModeName[i]), f);
skip_pascal_string(f);
/*NEW: Ship Info*/
skip_pascal_string(f);
for (int i = 0; i < 13; ++i)
{
read_encrypted_pascal_string(shipInfo[i][0], sizeof(shipInfo[i][0]), f);
read_encrypted_pascal_string(shipInfo[i][1], sizeof(shipInfo[i][1]), f);
}
skip_pascal_string(f);
/*Menu 12 - Network Options*/
skip_pascal_string(f);
for (int i = 0; i < 5; ++i)
read_encrypted_pascal_string(menuInt[14][i], sizeof(menuInt[14][i]), f);
fclose(f);
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,66 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef HELPTEXT_H
#define HELPTEXT_H
#include "opentyr.h"
#define MAX_HELP_MESSAGE 39
#define MAX_MENU 14
#define DESTRUCT_MODES 5
extern JE_byte verticalHeight;
extern JE_byte helpBoxColor, helpBoxBrightness, helpBoxShadeType;
extern char helpTxt[MAX_HELP_MESSAGE][231];
extern char pName[21][16]; /* [1..21] of string [15] */
extern char miscText[68][42]; /* [1..68] of string [41] */
extern char miscTextB[5][11]; /* [1..5] of string [10] */
extern char keyName[8][18]; /* [1..8] of string [17] */
extern char menuText[7][21]; /* [1..7] of string [20] */
extern char outputs[9][31]; /* [1..9] of string [30] */
extern char topicName[6][21]; /* [1..6] of string [20] */
extern char mainMenuHelp[34][66];
extern char inGameText[6][21]; /* [1..6] of string [20] */
extern char detailLevel[6][13]; /* [1..6] of string [12] */
extern char gameSpeedText[5][13]; /* [1..5] of string [12] */
extern char inputDevices[3][13]; /* [1..3] of string [12] */
extern char networkText[4][22]; /* [1..4] of string [20] */
extern char difficultyNameB[11][21]; /* [0..9] of string [20] */
extern char joyButtonNames[5][21]; /* [1..5] of string [20] */
extern char superShips[11][26]; /* [0..10] of string [25] */
extern char specialName[9][10]; /* [1..9] of string [9] */
extern char destructHelp[25][22];
extern char weaponNames[17][17]; /* [1..17] of string [16] */
extern char destructModeName[DESTRUCT_MODES][13]; /* [1..destructmodes] of string [12] */
extern char shipInfo[13][2][256];
extern char menuInt[MAX_MENU+1][11][18]; /* [0..maxmenu, 1..11] of string [17] */
extern const JE_byte menuHelp[MAX_MENU][11]; /* [1..maxmenu, 1..11] */
void read_encrypted_pascal_string( char *s, int size, FILE *f );
void skip_pascal_string( FILE *f );
void JE_helpBox( SDL_Surface *screen, int x, int y, const char *message, unsigned int boxwidth );
void JE_HBox( SDL_Surface *screen, int x, int y, unsigned int messagenum, unsigned int boxwidth );
void JE_loadHelpText( void );
#endif /* HELPTEXT_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,8 @@
#ifndef HG_REVISION_H
#define HG_REVISION_H
#ifndef HG_REV
#define HG_REV "8e4c1be1b53f default"
#endif
#endif // HG_REVISION_H

View File

@@ -0,0 +1,659 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "cJSON.h"
#include "config.h"
#include "file.h"
#include "joystick.h"
#include "keyboard.h"
#include "nortsong.h"
#include "opentyr.h"
#include "params.h"
#include "varz.h"
#include "video.h"
#include <assert.h>
int joystick_axis_threshold( int j, int value );
int check_assigned( SDL_Joystick *joystick_handle, const Joystick_assignment assignment[2] );
const char *assignment_to_code( const Joystick_assignment *assignment );
void code_to_assignment( Joystick_assignment *assignment, const char *buffer );
int joystick_repeat_delay = 300; // milliseconds, repeat delay for buttons
bool joydown = false; // any joystick buttons down, updated by poll_joysticks()
bool ignore_joystick = false;
int joysticks = 0;
Joystick *joystick = NULL;
static const char joystick_cfg_version = 1;
static const int joystick_analog_max = 32767;
// eliminates axis movement below the threshold
int joystick_axis_threshold( int j, int value )
{
assert(j < joysticks);
bool negative = value < 0;
if (negative)
value = -value;
if (value <= joystick[j].threshold * 1000)
return 0;
value -= joystick[j].threshold * 1000;
return negative ? -value : value;
}
// converts joystick axis to sane Tyrian-usable value (based on sensitivity)
int joystick_axis_reduce( int j, int value )
{
assert(j < joysticks);
value = joystick_axis_threshold(j, value);
if (value == 0)
return 0;
return value / (3000 - 200 * joystick[j].sensitivity);
}
// converts analog joystick axes to an angle
// returns false if axes are centered (there is no angle)
bool joystick_analog_angle( int j, float *angle )
{
assert(j < joysticks);
float x = joystick_axis_threshold(j, joystick[j].x), y = joystick_axis_threshold(j, joystick[j].y);
if (x != 0)
{
*angle += atanf(-y / x);
*angle += (x < 0) ? -M_PI_2 : M_PI_2;
return true;
}
else if (y != 0)
{
*angle += y < 0 ? M_PI : 0;
return true;
}
return false;
}
/* gives back value 0..joystick_analog_max indicating that one of the assigned
* buttons has been pressed or that one of the assigned axes/hats has been moved
* in the assigned direction
*/
int check_assigned( SDL_Joystick *joystick_handle, const Joystick_assignment assignment[2] )
{
int result = 0;
for (int i = 0; i < 2; i++)
{
int temp = 0;
switch (assignment[i].type)
{
case NONE:
continue;
case AXIS:
temp = SDL_JoystickGetAxis(joystick_handle, assignment[i].num);
if (assignment[i].negative_axis)
temp = -temp;
break;
case BUTTON:
temp = SDL_JoystickGetButton(joystick_handle, assignment[i].num) == 1 ? joystick_analog_max : 0;
break;
case HAT:
temp = SDL_JoystickGetHat(joystick_handle, assignment[i].num);
if (assignment[i].x_axis)
temp &= SDL_HAT_LEFT | SDL_HAT_RIGHT;
else
temp &= SDL_HAT_UP | SDL_HAT_DOWN;
if (assignment[i].negative_axis)
temp &= SDL_HAT_LEFT | SDL_HAT_UP;
else
temp &= SDL_HAT_RIGHT | SDL_HAT_DOWN;
temp = temp ? joystick_analog_max : 0;
break;
}
if (temp > result)
result = temp;
}
return result;
}
// updates joystick state
void poll_joystick( int j )
{
assert(j < joysticks);
if (joystick[j].handle == NULL)
return;
SDL_JoystickUpdate();
// indicates that a direction/action was pressed since last poll
joystick[j].input_pressed = false;
// indicates that an direction/action has been held long enough to fake a repeat press
bool repeat = joystick[j].joystick_delay < SDL_GetTicks();
// update direction state
for (uint d = 0; d < COUNTOF(joystick[j].direction); d++)
{
bool old = joystick[j].direction[d];
joystick[j].analog_direction[d] = check_assigned(joystick[j].handle, joystick[j].assignment[d]);
joystick[j].direction[d] = joystick[j].analog_direction[d] > (joystick_analog_max / 2);
joydown |= joystick[j].direction[d];
joystick[j].direction_pressed[d] = joystick[j].direction[d] && (!old || repeat);
joystick[j].input_pressed |= joystick[j].direction_pressed[d];
}
joystick[j].x = -joystick[j].analog_direction[3] + joystick[j].analog_direction[1];
joystick[j].y = -joystick[j].analog_direction[0] + joystick[j].analog_direction[2];
// update action state
for (uint d = 0; d < COUNTOF(joystick[j].action); d++)
{
bool old = joystick[j].action[d];
joystick[j].action[d] = check_assigned(joystick[j].handle, joystick[j].assignment[d + COUNTOF(joystick[j].direction)]);
joydown |= joystick[j].action[d];
joystick[j].action_pressed[d] = joystick[j].action[d] && (!old || repeat);
joystick[j].input_pressed |= joystick[j].action_pressed[d];
}
joystick[j].confirm = joystick[j].action[0] || joystick[j].action[4];
joystick[j].cancel = joystick[j].action[1] || joystick[j].action[5];
// if new input, reset press-repeat delay
if (joystick[j].input_pressed)
joystick[j].joystick_delay = SDL_GetTicks() + joystick_repeat_delay;
}
// updates all joystick states
void poll_joysticks( void )
{
joydown = false;
for (int j = 0; j < joysticks; j++)
poll_joystick(j);
}
// sends SDL KEYDOWN and KEYUP events for a key
void push_key( SDLKey key )
{
SDL_Event e;
memset(&e.key.keysym, 0, sizeof(e.key.keysym));
e.key.keysym.sym = key;
e.key.keysym.unicode = key;
e.key.state = SDL_RELEASED;
e.type = SDL_KEYDOWN;
SDL_PushEvent(&e);
e.type = SDL_KEYUP;
SDL_PushEvent(&e);
}
// helps us be lazy by pretending joysticks are a keyboard (useful for menus)
void push_joysticks_as_keyboard( void )
{
const SDLKey confirm = SDLK_RETURN, cancel = SDLK_ESCAPE;
const SDLKey direction[4] = { SDLK_UP, SDLK_RIGHT, SDLK_DOWN, SDLK_LEFT };
poll_joysticks();
for (int j = 0; j < joysticks; j++)
{
if (!joystick[j].input_pressed)
continue;
if (joystick[j].confirm)
push_key(confirm);
if (joystick[j].cancel)
push_key(cancel);
for (uint d = 0; d < COUNTOF(joystick[j].direction_pressed); d++)
{
if (joystick[j].direction_pressed[d])
push_key(direction[d]);
}
}
}
// initializes SDL joystick system and loads assignments for joysticks found
void init_joysticks( void )
{
if (ignore_joystick)
return;
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK))
{
fprintf(stderr, "warning: failed to initialize joystick system: %s\n", SDL_GetError());
ignore_joystick = true;
return;
}
SDL_JoystickEventState(SDL_IGNORE);
joysticks = SDL_NumJoysticks();
joystick = (Joystick *)malloc(joysticks * sizeof(*joystick));
for (int j = 0; j < joysticks; j++)
{
memset(&joystick[j], 0, sizeof(*joystick));
joystick[j].handle = SDL_JoystickOpen(j);
if (joystick[j].handle != NULL)
{
printf("joystick detected: %s ", SDL_JoystickName(j));
printf("(%d axes, %d buttons, %d hats)\n",
SDL_JoystickNumAxes(joystick[j].handle),
SDL_JoystickNumButtons(joystick[j].handle),
SDL_JoystickNumHats(joystick[j].handle));
if (!load_joystick_assignments(j))
reset_joystick_assignments(j);
}
}
if (joysticks == 0)
printf("no joysticks detected\n");
}
// deinitializes SDL joystick system and saves joystick assignments
void deinit_joysticks( void )
{
if (ignore_joystick)
return;
for (int j = 0; j < joysticks; j++)
{
if (joystick[j].handle != NULL)
{
save_joystick_assignments(j);
SDL_JoystickClose(joystick[j].handle);
}
}
free(joystick);
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
}
void reset_joystick_assignments( int j )
{
assert(j < joysticks);
// defaults: first 2 axes, first hat, first 6 buttons
for (uint a = 0; a < COUNTOF(joystick[j].assignment); a++)
{
// clear assignments
for (uint i = 0; i < COUNTOF(joystick[j].assignment[a]); i++)
joystick[j].assignment[a][i].type = NONE;
if (a < 4)
{
if (SDL_JoystickNumAxes(joystick[j].handle) >= 2)
{
joystick[j].assignment[a][0].type = AXIS;
joystick[j].assignment[a][0].num = (a + 1) % 2;
joystick[j].assignment[a][0].negative_axis = (a == 0 || a == 3);
}
if (SDL_JoystickNumHats(joystick[j].handle) >= 1)
{
joystick[j].assignment[a][1].type = HAT;
joystick[j].assignment[a][1].num = 0;
joystick[j].assignment[a][1].x_axis = (a == 1 || a == 3);
joystick[j].assignment[a][1].negative_axis = (a == 0 || a == 3);
}
}
else
{
if (a - 4 < (unsigned)SDL_JoystickNumButtons(joystick[j].handle))
{
joystick[j].assignment[a][0].type = BUTTON;
joystick[j].assignment[a][0].num = a - 4;
}
}
}
joystick[j].analog = false;
joystick[j].sensitivity = 5;
joystick[j].threshold = 5;
}
bool load_joystick_assignments( int j )
{
cJSON *root = load_json("joystick.conf");
if (root == NULL)
return false;
cJSON *config = cJSON_GetObjectItem(root, SDL_JoystickName(j));
if (config == NULL)
{
cJSON_Delete(root);
return false;
}
cJSON *setting;
if ((setting = cJSON_GetObjectItem(config, "analog")))
joystick[j].analog = (setting->type == cJSON_True);
if ((setting = cJSON_GetObjectItem(config, "sensitivity")))
joystick[j].sensitivity = setting->valueint;
if ((setting = cJSON_GetObjectItem(config, "threshold")))
joystick[j].threshold = setting->valueint;
if ((setting = cJSON_GetObjectItem(config, "assignments")))
{
for (uint i = 0; i < COUNTOF(joystick->assignment); ++i)
{
cJSON *assignments = cJSON_GetArrayItem(setting, i);
if (assignments == NULL)
break;
for (uint k = 0; k < COUNTOF(*joystick->assignment); ++k)
{
cJSON *assignment = cJSON_GetArrayItem(assignments, k);
if (assignment)
code_to_assignment(&joystick[j].assignment[i][k], assignment->valuestring);
}
}
}
cJSON_Delete(root);
return true;
}
bool save_joystick_assignments( int j )
{
cJSON *root = load_json("joystick.conf");
if (root == NULL)
root = cJSON_CreateObject();
cJSON *config = cJSON_CreateOrGetObjectItem(root, SDL_JoystickName(j));
cJSON_ForceType(config, cJSON_Object);
cJSON *setting;
setting = cJSON_CreateOrGetObjectItem(config, "analog");
cJSON_SetBoolean(setting, joystick[j].analog);
setting = cJSON_CreateOrGetObjectItem(config, "sensitivity");
cJSON_SetNumber(setting, joystick[j].sensitivity);
setting = cJSON_CreateOrGetObjectItem(config, "threshold");
cJSON_SetNumber(setting, joystick[j].threshold);
setting = cJSON_CreateOrGetObjectItem(config, "assignments");
cJSON_ForceType(setting, cJSON_Array);
cJSON_ClearArray(setting);
for (uint i = 0; i < COUNTOF(joystick->assignment); ++i)
{
cJSON *assignments;
cJSON_AddItemToArray(setting, assignments = cJSON_CreateArray());
for (uint k = 0; k < COUNTOF(*joystick->assignment); ++k)
{
if (joystick[j].assignment[i][k].type == NONE)
continue;
cJSON_AddItemToArray(assignments, cJSON_CreateString(assignment_to_code(&joystick[j].assignment[i][k])));
}
}
save_json(root, "joystick.conf");
cJSON_Delete(root);
return true;
}
// fills buffer with comma separated list of assigned joystick functions
void joystick_assignments_to_string( char *buffer, size_t buffer_len, const Joystick_assignment *assignments )
{
strncpy(buffer, "", buffer_len);
bool comma = false;
for (uint i = 0; i < COUNTOF(*joystick->assignment); ++i)
{
if (assignments[i].type == NONE)
continue;
size_t len = snprintf(buffer, buffer_len, "%s%s",
comma ? ", " : "",
assignment_to_code(&assignments[i]));
buffer += len;
buffer_len -= len;
comma = true;
}
}
// reverse of assignment_to_code()
void code_to_assignment( Joystick_assignment *assignment, const char *buffer )
{
memset(assignment, 0, sizeof(*assignment));
char axis = 0, direction = 0;
if (sscanf(buffer, " AX %d%c", &assignment->num, &direction) == 2)
assignment->type = AXIS;
else if (sscanf(buffer, " BTN %d", &assignment->num) == 1)
assignment->type = BUTTON;
else if (sscanf(buffer, " H %d%c%c", &assignment->num, &axis, &direction) == 3)
assignment->type = HAT;
if (assignment->num == 0)
assignment->type = NONE;
else
--assignment->num;
assignment->x_axis = (toupper(axis) == 'X');
assignment->negative_axis = (toupper(direction) == '-');
}
/* gives the short (6 or less characters) identifier for a joystick assignment
*
* two of these per direction/action is all that can fit on the joystick config screen,
* assuming two digits for the axis/button/hat number
*/
const char *assignment_to_code( const Joystick_assignment *assignment )
{
static char name[7];
switch (assignment->type)
{
case NONE:
strcpy(name, "");
break;
case AXIS:
snprintf(name, sizeof(name), "AX %d%c",
assignment->num + 1,
assignment->negative_axis ? '-' : '+');
break;
case BUTTON:
snprintf(name, sizeof(name), "BTN %d",
assignment->num + 1);
break;
case HAT:
snprintf(name, sizeof(name), "H %d%c%c",
assignment->num + 1,
assignment->x_axis ? 'X' : 'Y',
assignment->negative_axis ? '-' : '+');
break;
}
return name;
}
// captures joystick input for configuring assignments
// returns false if non-joystick input was detected
// TODO: input from joystick other than the one being configured probably should not be ignored
bool detect_joystick_assignment( int j, Joystick_assignment *assignment )
{
// get initial joystick state to compare against to see if anything was pressed
const int axes = SDL_JoystickNumAxes(joystick[j].handle);
Sint16 *axis = (Sint16 *)malloc(axes * sizeof(*axis));
for (int i = 0; i < axes; i++)
axis[i] = SDL_JoystickGetAxis(joystick[j].handle, i);
const int buttons = SDL_JoystickNumButtons(joystick[j].handle);
Uint8 *button = (Uint8 *)malloc(buttons * sizeof(*button));
for (int i = 0; i < buttons; i++)
button[i] = SDL_JoystickGetButton(joystick[j].handle, i);
const int hats = SDL_JoystickNumHats(joystick[j].handle);
Uint8 *hat = (Uint8 *)malloc(hats * sizeof(*hat));
for (int i = 0; i < hats; i++)
hat[i] = SDL_JoystickGetHat(joystick[j].handle, i);
bool detected = false;
do
{
setjasondelay(1);
SDL_JoystickUpdate();
for (int i = 0; i < axes; ++i)
{
Sint16 temp = SDL_JoystickGetAxis(joystick[j].handle, i);
if (abs(temp - axis[i]) > joystick_analog_max * 2 / 3)
{
assignment->type = AXIS;
assignment->num = i;
assignment->negative_axis = temp < axis[i];
detected = true;
break;
}
}
for (int i = 0; i < buttons; ++i)
{
Uint8 new_button = SDL_JoystickGetButton(joystick[j].handle, i),
changed = button[i] ^ new_button;
if (!changed)
continue;
if (new_button == 0) // button was released
{
button[i] = new_button;
}
else // button was pressed
{
assignment->type = BUTTON;
assignment->num = i;
detected = true;
break;
}
}
for (int i = 0; i < hats; ++i)
{
Uint8 new_hat = SDL_JoystickGetHat(joystick[j].handle, i),
changed = hat[i] ^ new_hat;
if (!changed)
continue;
if ((new_hat & changed) == SDL_HAT_CENTERED) // hat was centered
{
hat[i] = new_hat;
}
else
{
assignment->type = HAT;
assignment->num = i;
assignment->x_axis = changed & (SDL_HAT_LEFT | SDL_HAT_RIGHT);
assignment->negative_axis = changed & (SDL_HAT_LEFT | SDL_HAT_UP);
detected = true;
}
}
service_SDL_events(true);
JE_showVGA();
wait_delay();
}
while (!detected && !newkey && !newmouse);
free(axis);
free(button);
free(hat);
return detected;
}
// compares relevant parts of joystick assignments for equality
bool joystick_assignment_cmp( const Joystick_assignment *a, const Joystick_assignment *b )
{
if (a->type == b->type)
{
switch (a->type)
{
case NONE:
return true;
case AXIS:
return (a->num == b->num) &&
(a->negative_axis == b->negative_axis);
case BUTTON:
return (a->num == b->num);
case HAT:
return (a->num == b->num) &&
(a->x_axis == b->x_axis) &&
(a->negative_axis == b->negative_axis);
}
}
return false;
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,98 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef JOYSTICK_H
#define JOYSTICK_H
#include "opentyr.h"
#include "SDL.h"
typedef enum
{
NONE,
AXIS,
BUTTON,
HAT
}
Joystick_assignment_types;
typedef struct
{
Joystick_assignment_types type;
int num;
// if hat
bool x_axis; // else y_axis
// if hat or axis
bool negative_axis; // else positive
}
Joystick_assignment;
typedef struct
{
SDL_Joystick *handle;
Joystick_assignment assignment[10][2]; // 0-3: directions, 4-9: actions
bool analog;
int sensitivity, threshold;
signed int x, y;
int analog_direction[4];
bool direction[4], direction_pressed[4]; // up, right, down, left (_pressed, for emulating key presses)
bool confirm, cancel;
bool action[6], action_pressed[6]; // fire, mode swap, left fire, right fire, menu, pause
Uint32 joystick_delay;
bool input_pressed;
}
Joystick;
extern int joystick_repeat_delay;
extern bool joydown;
extern bool ignore_joystick;
extern int joysticks;
extern Joystick *joystick;
int joystick_axis_reduce( int j, int value );
bool joystick_analog_angle( int j, float *angle );
void poll_joystick( int j );
void poll_joysticks( void );
void push_key( SDLKey key );
void push_joysticks_as_keyboard( void );
void init_joysticks( void );
void deinit_joysticks( void );
void reset_joystick_assignments( int j );
bool load_joystick_assignments( int j );
bool save_joystick_assignments( int j );
void joystick_assignments_to_string( char *buffer, size_t buffer_len, const Joystick_assignment *assignments );
bool detect_joystick_assignment( int j, Joystick_assignment *assignment );
bool joystick_assignment_cmp( const Joystick_assignment *, const Joystick_assignment * );
#endif /* JOYSTICK_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,201 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "font.h"
#include "joystick.h"
#include "jukebox.h"
#include "keyboard.h"
#include "lds_play.h"
#include "loudness.h"
#include "mtrand.h"
#include "nortsong.h"
#include "opentyr.h"
#include "palette.h"
#include "sprite.h"
#include "starlib.h"
#include "vga_palette.h"
#include "video.h"
void jukebox( void )
{
bool trigger_quit = false, // true when user wants to quit
quitting = false;
bool hide_text = false;
bool fade_looped_songs = true, fading_song = false;
bool stopped = false;
bool fx = false;
int fx_num = 0;
int palette_fade_steps = 15;
int diff[256][3];
init_step_fade_palette(diff, vga_palette, 0, 255);
JE_starlib_init();
int fade_volume = tyrMusicVolume;
for (; ; )
{
if (!stopped && !audio_disabled)
{
if (songlooped && fade_looped_songs)
fading_song = true;
if (fading_song)
{
if (fade_volume > 5)
{
fade_volume -= 2;
}
else
{
fade_volume = tyrMusicVolume;
fading_song = false;
}
set_volume(fade_volume, fxVolume);
}
if (!playing || (songlooped && fade_looped_songs && !fading_song))
play_song(mt_rand() % MUSIC_NUM);
}
setdelay(1);
SDL_FillRect(VGAScreenSeg, NULL, 0);
// starlib input needs to be rewritten
JE_starlib_main();
push_joysticks_as_keyboard();
service_SDL_events(true);
if (!hide_text)
{
char buffer[60];
if (fx)
snprintf(buffer, sizeof(buffer), "%d %s", fx_num + 1, soundTitle[fx_num]);
else
snprintf(buffer, sizeof(buffer), "%d %s", song_playing + 1, musicTitle[song_playing]);
const int x = VGAScreen->w / 2;
draw_font_hv(VGAScreen, x, 170, "Press ESC to quit the jukebox.", small_font, centered, 1, 0);
draw_font_hv(VGAScreen, x, 180, "Arrow keys change the song being played.", small_font, centered, 1, 0);
draw_font_hv(VGAScreen, x, 190, buffer, small_font, centered, 1, 4);
}
if (palette_fade_steps > 0)
step_fade_palette(diff, palette_fade_steps--, 0, 255);
JE_showVGA();
wait_delay();
// quit on mouse click
Uint16 x, y;
if (JE_mousePosition(&x, &y) > 0)
trigger_quit = true;
if (newkey)
{
switch (lastkey_sym)
{
case SDLK_ESCAPE: // quit jukebox
case SDLK_q:
trigger_quit = true;
break;
case SDLK_SPACE:
hide_text = !hide_text;
break;
case SDLK_f:
fading_song = !fading_song;
break;
case SDLK_n:
fade_looped_songs = !fade_looped_songs;
break;
case SDLK_SLASH: // switch to sfx mode
fx = !fx;
break;
case SDLK_COMMA:
if (fx && --fx_num < 0)
fx_num = SAMPLE_COUNT - 1;
break;
case SDLK_PERIOD:
if (fx && ++fx_num >= SAMPLE_COUNT)
fx_num = 0;
break;
case SDLK_SEMICOLON:
if (fx)
JE_playSampleNum(fx_num + 1);
break;
case SDLK_LEFT:
case SDLK_UP:
play_song((song_playing > 0 ? song_playing : MUSIC_NUM) - 1);
stopped = false;
break;
case SDLK_RETURN:
case SDLK_RIGHT:
case SDLK_DOWN:
play_song((song_playing + 1) % MUSIC_NUM);
stopped = false;
break;
case SDLK_s: // stop song
stop_song();
stopped = true;
break;
case SDLK_r: // restart song
restart_song();
stopped = false;
break;
default:
break;
}
}
// user wants to quit, start fade-out
if (trigger_quit && !quitting)
{
palette_fade_steps = 15;
SDL_Color black = { 0, 0, 0 };
init_step_fade_solid(diff, black, 0, 255);
quitting = true;
}
// if fade-out finished, we can finally quit
if (quitting && palette_fade_steps == 0)
break;
}
set_volume(tyrMusicVolume, fxVolume);
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,28 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef JUKEBOX_H
#define JUKEBOX_H
#include "opentyr.h"
void jukebox( void );
#endif /* JUKEBOX_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,246 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "joystick.h"
#include "keyboard.h"
#include "network.h"
#include "opentyr.h"
#include "video.h"
#include "video_scale.h"
#include "SDL.h"
JE_boolean ESCPressed;
JE_boolean newkey, newmouse, keydown, mousedown;
SDLKey lastkey_sym;
SDLMod lastkey_mod;
unsigned char lastkey_char;
Uint8 lastmouse_but;
Uint16 lastmouse_x, lastmouse_y;
JE_boolean mouse_pressed[3] = {false, false, false};
Uint16 mouse_x, mouse_y;
int numkeys;
Uint8 *keysactive;
#ifdef NDEBUG
bool input_grab_enabled = true,
#else
bool input_grab_enabled = false,
#endif
input_grabbed = false;
void flush_events_buffer( void )
{
SDL_Event ev;
while (SDL_PollEvent(&ev));
}
void wait_input( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick )
{
service_SDL_events(false);
while (!((keyboard && keydown) || (mouse && mousedown) || (joystick && joydown)))
{
SDL_Delay(SDL_POLL_INTERVAL);
push_joysticks_as_keyboard();
service_SDL_events(false);
if (isNetworkGame)
network_check();
}
}
void wait_noinput( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick )
{
service_SDL_events(false);
while ((keyboard && keydown) || (mouse && mousedown) || (joystick && joydown))
{
SDL_Delay(SDL_POLL_INTERVAL);
poll_joysticks();
service_SDL_events(false);
if (isNetworkGame)
network_check();
}
}
void init_keyboard( void )
{
keysactive = SDL_GetKeyState(&numkeys);
SDL_EnableKeyRepeat(500, 60);
newkey = newmouse = false;
keydown = mousedown = false;
SDL_EnableUNICODE(1);
}
void input_grab( void )
{
#if defined(TARGET_GP2X) || defined(TARGET_DINGUX) || defined(ANDROID)
input_grabbed = true;
#else
input_grabbed = input_grab_enabled || fullscreen_enabled;
#endif
SDL_ShowCursor(input_grabbed ? SDL_DISABLE : SDL_ENABLE);
#ifdef NDEBUG
SDL_WM_GrabInput(input_grabbed ? SDL_GRAB_ON : SDL_GRAB_OFF);
#endif
}
JE_word JE_mousePosition( JE_word *mouseX, JE_word *mouseY )
{
service_SDL_events(false);
*mouseX = mouse_x;
*mouseY = mouse_y;
return mousedown ? lastmouse_but : 0;
}
void set_mouse_position( int x, int y )
{
if (input_grabbed)
{
SDL_WarpMouse(x * scalers[scaler].width / vga_width, y * scalers[scaler].height / vga_height);
mouse_x = x;
mouse_y = y;
}
}
void service_SDL_events( JE_boolean clear_new )
{
SDL_Event ev;
if (clear_new)
newkey = newmouse = false;
while (SDL_PollEvent(&ev))
{
switch (ev.type)
{
case SDL_MOUSEMOTION:
mouse_x = ev.motion.x * vga_width / scalers[scaler].width;
mouse_y = ev.motion.y * vga_height / scalers[scaler].height;
break;
case SDL_KEYDOWN:
if (ev.key.keysym.mod & KMOD_CTRL)
{
/* <ctrl><bksp> emergency kill */
if (ev.key.keysym.sym == SDLK_BACKSPACE)
{
puts("\n\n\nCtrl+Backspace pressed. Doing emergency quit.\n");
SDL_Quit();
exit(1);
}
/* <ctrl><f10> toggle input grab */
if (ev.key.keysym.sym == SDLK_F10)
{
input_grab_enabled = !input_grab_enabled;
input_grab();
break;
}
}
if (ev.key.keysym.mod & KMOD_ALT)
{
/* <alt><enter> toggle fullscreen */
if (ev.key.keysym.sym == SDLK_RETURN)
{
if (!init_scaler(scaler, !fullscreen_enabled) && // try new fullscreen state
!init_any_scaler(!fullscreen_enabled) && // try any scaler in new fullscreen state
!init_scaler(scaler, fullscreen_enabled)) // revert on fail
{
exit(EXIT_FAILURE);
}
break;
}
/* <alt><tab> disable input grab and fullscreen */
if (ev.key.keysym.sym == SDLK_TAB)
{
input_grab_enabled = false;
input_grab();
if (!init_scaler(scaler, false) && // try windowed
!init_any_scaler(false) && // try any scaler windowed
!init_scaler(scaler, fullscreen_enabled)) // revert on fail
{
exit(EXIT_FAILURE);
}
break;
}
}
newkey = true;
lastkey_sym = ev.key.keysym.sym;
lastkey_mod = ev.key.keysym.mod;
lastkey_char = ev.key.keysym.unicode;
keydown = true;
return;
case SDL_KEYUP:
keydown = false;
return;
case SDL_MOUSEBUTTONDOWN:
if (!input_grabbed)
{
input_grab_enabled = !input_grab_enabled;
input_grab();
break;
}
case SDL_MOUSEBUTTONUP:
if (ev.type == SDL_MOUSEBUTTONDOWN)
{
newmouse = true;
lastmouse_but = ev.button.button;
lastmouse_x = ev.button.x * vga_width / scalers[scaler].width;
lastmouse_y = ev.button.y * vga_height / scalers[scaler].height;
mousedown = true;
}
else
{
mousedown = false;
}
switch (ev.button.button)
{
case SDL_BUTTON_LEFT:
mouse_pressed[0] = mousedown; break;
case SDL_BUTTON_RIGHT:
mouse_pressed[1] = mousedown; break;
case SDL_BUTTON_MIDDLE:
mouse_pressed[2] = mousedown; break;
}
break;
case SDL_QUIT:
/* TODO: Call the cleanup code here. */
exit(0);
break;
}
}
}
void JE_clearKeyboard( void )
{
// /!\ Doesn't seems important. I think. D:
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,59 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef KEYBOARD_H
#define KEYBOARD_H
#include "opentyr.h"
#include "SDL.h"
#define SDL_POLL_INTERVAL 5
extern JE_boolean ESCPressed;
extern JE_boolean newkey, newmouse, keydown, mousedown;
extern SDLKey lastkey_sym;
extern SDLMod lastkey_mod;
extern unsigned char lastkey_char;
extern Uint8 lastmouse_but;
extern Uint16 lastmouse_x, lastmouse_y;
extern JE_boolean mouse_pressed[3];
extern Uint16 mouse_x, mouse_y;
extern int numkeys;
extern Uint8 *keysactive;
extern bool input_grab_enabled, input_grabbed;
void flush_events_buffer( void );
void wait_input( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick );
void wait_noinput( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick );
void init_keyboard( void );
void input_grab( void );
JE_word JE_mousePosition( JE_word *mouseX, JE_word *mouseY );
void set_mouse_position( int x, int y );
void service_SDL_events( JE_boolean clear_new );
void sleep_game( void );
void JE_clearKeyboard( void );
#endif /* KEYBOARD_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,768 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "file.h"
#include "fm_synth.h"
#include "lds_play.h"
#include "loudness.h"
#include "opentyr.h"
#include <assert.h>
/* A substantial amount of this code has been copied and adapted from adplug.
Thanks, guys! Adplug is awesome! :D */
/* Note frequency table (16 notes / octave) */
static const Uint16 frequency[(13 * 15) - 3] = {
343, 344, 345, 347, 348, 349, 350, 352, 353, 354, 356, 357, 358,
359, 361, 362, 363, 365, 366, 367, 369, 370, 371, 373, 374, 375,
377, 378, 379, 381, 382, 384, 385, 386, 388, 389, 391, 392, 393,
395, 396, 398, 399, 401, 402, 403, 405, 406, 408, 409, 411, 412,
414, 415, 417, 418, 420, 421, 423, 424, 426, 427, 429, 430, 432,
434, 435, 437, 438, 440, 442, 443, 445, 446, 448, 450, 451, 453,
454, 456, 458, 459, 461, 463, 464, 466, 468, 469, 471, 473, 475,
476, 478, 480, 481, 483, 485, 487, 488, 490, 492, 494, 496, 497,
499, 501, 503, 505, 506, 508, 510, 512, 514, 516, 518, 519, 521,
523, 525, 527, 529, 531, 533, 535, 537, 538, 540, 542, 544, 546,
548, 550, 552, 554, 556, 558, 560, 562, 564, 566, 568, 571, 573,
575, 577, 579, 581, 583, 585, 587, 589, 591, 594, 596, 598, 600,
602, 604, 607, 609, 611, 613, 615, 618, 620, 622, 624, 627, 629,
631, 633, 636, 638, 640, 643, 645, 647, 650, 652, 654, 657, 659,
662, 664, 666, 669, 671, 674, 676, 678, 681, 683
};
/* Vibrato (sine) table */
static const Uint8 vibtab[25 + (13 * 3)] = {
0, 13, 25, 37, 50, 62, 74, 86, 98, 109, 120, 131, 142, 152, 162,
171, 180, 189, 197, 205, 212, 219, 225, 231, 236, 240, 244, 247,
250, 252, 254, 255, 255, 255, 254, 252, 250, 247, 244, 240, 236,
231, 225, 219, 212, 205, 197, 189, 180, 171, 162, 152, 142, 131,
120, 109, 98, 86, 74, 62, 50, 37, 25, 13
};
/* Tremolo (sine * sine) table */
static const Uint8 tremtab[128] = {
0, 0, 1, 1, 2, 4, 5, 7, 10, 12, 15, 18, 21, 25, 29, 33, 37, 42, 47,
52, 57, 62, 67, 73, 79, 85, 90, 97, 103, 109, 115, 121, 128, 134,
140, 146, 152, 158, 165, 170, 176, 182, 188, 193, 198, 203, 208,
213, 218, 222, 226, 230, 234, 237, 240, 243, 245, 248, 250, 251,
253, 254, 254, 255, 255, 255, 254, 254, 253, 251, 250, 248, 245,
243, 240, 237, 234, 230, 226, 222, 218, 213, 208, 203, 198, 193,
188, 182, 176, 170, 165, 158, 152, 146, 140, 134, 127, 121, 115,
109, 103, 97, 90, 85, 79, 73, 67, 62, 57, 52, 47, 42, 37, 33, 29,
25, 21, 18, 15, 12, 10, 7, 5, 4, 2, 1, 1, 0
};
static const Uint16 maxsound = 0x3f, maxpos = 0xff;
static SoundBank *soundbank = NULL;
static Channel channel[9];
static Position *positions = NULL;
static Uint8 fmchip[0xff], jumping, fadeonoff, allvolume, hardfade, tempo_now, pattplay, tempo, regbd, chandelay[9], mode, pattlen;
static Uint16 posplay, jumppos, speed;
static Uint16 *patterns = NULL;
static Uint16 numpatch, numposi, mainvolume;
bool playing, songlooped;
bool lds_load( FILE *f, unsigned int music_offset, unsigned int music_size )
{
SoundBank *sb;
fseek(f, music_offset, SEEK_SET);
/* load header */
mode = fgetc(f);
if (mode > 2)
{
fprintf(stderr, "error: failed to load music\n");
return false;
}
efread(&speed, 2, 1, f);
tempo = fgetc(f);
pattlen = fgetc(f);
for (unsigned int i = 0; i < 9; i++)
chandelay[i] = fgetc(f);
regbd = fgetc(f);
/* load patches */
efread(&numpatch, 2, 1, f);
free(soundbank);
soundbank = (SoundBank *)malloc(sizeof(SoundBank) * numpatch);
for (unsigned int i = 0; i < numpatch; i++)
{
sb = &soundbank[i];
sb->mod_misc = fgetc(f);
sb->mod_vol = fgetc(f);
sb->mod_ad = fgetc(f);
sb->mod_sr = fgetc(f);
sb->mod_wave = fgetc(f);
sb->car_misc = fgetc(f);
sb->car_vol = fgetc(f);
sb->car_ad = fgetc(f);
sb->car_sr = fgetc(f);
sb->car_wave = fgetc(f);
sb->feedback = fgetc(f);
sb->keyoff = fgetc(f);
sb->portamento = fgetc(f);
sb->glide = fgetc(f);
sb->finetune = fgetc(f);
sb->vibrato = fgetc(f);
sb->vibdelay = fgetc(f);
sb->mod_trem = fgetc(f);
sb->car_trem = fgetc(f);
sb->tremwait = fgetc(f);
sb->arpeggio = fgetc(f);
for (unsigned int j = 0; j < 12; j++)
sb->arp_tab[j] = fgetc(f);
efread(&sb->start, 2, 1, f);
efread(&sb->size, 2, 1, f);
sb->fms = fgetc(f);
efread(&sb->transp, 2, 1, f);
sb->midinst = fgetc(f);
sb->midvelo = fgetc(f);
sb->midkey = fgetc(f);
sb->midtrans = fgetc(f);
sb->middum1 = fgetc(f);
sb->middum2 = fgetc(f);
}
/* load positions */
efread(&numposi, 2, 1, f);
free(positions);
positions = (Position *)malloc(sizeof(Position) * 9 * numposi);
for (unsigned int i = 0; i < numposi; i++)
{
for (unsigned int j = 0; j < 9; j++)
{
/*
* patnum is a pointer inside the pattern space, but patterns are 16bit
* word fields anyway, so it ought to be an even number (hopefully) and
* we can just divide it by 2 to get our array index of 16bit words.
*/
Uint16 temp;
efread(&temp, 2, 1, f);
positions[i * 9 + j].patnum = temp / 2;
positions[i * 9 + j].transpose = fgetc(f);
}
}
/* load patterns */
fseek(f, 2, SEEK_CUR); /* ignore # of digital sounds (dunno what this is for) */
unsigned int remaining = music_size - (ftell(f) - music_offset);
free(patterns);
patterns = (Uint16 *)malloc(sizeof(Uint16) * (remaining / 2));
for (unsigned int i = 0; i < remaining / 2; i++)
efread(&patterns[i], 2, 1, f);
lds_rewind();
return true;
}
void lds_free( void )
{
free(soundbank);
soundbank = NULL;
free(positions);
positions = NULL;
free(patterns);
patterns = NULL;
}
void lds_rewind( void )
{
int i;
/* init all with 0 */
tempo_now = 3;
playing = true; songlooped = false;
jumping = fadeonoff = allvolume = hardfade = pattplay = posplay = jumppos = mainvolume = 0;
memset(channel, 0, sizeof(channel));
memset(fmchip, 0, sizeof(fmchip));
/* OPL2 init */
opl_reset(); /* Reset OPL chip */
opl_write(1, 0x20);
opl_write(8, 0);
opl_write(0xbd, regbd);
for(i = 0; i < 9; i++) {
opl_write(0x20 + op_table[i], 0);
opl_write(0x23 + op_table[i], 0);
opl_write(0x40 + op_table[i], 0x3f);
opl_write(0x43 + op_table[i], 0x3f);
opl_write(0x60 + op_table[i], 0xff);
opl_write(0x63 + op_table[i], 0xff);
opl_write(0x80 + op_table[i], 0xff);
opl_write(0x83 + op_table[i], 0xff);
opl_write(0xe0 + op_table[i], 0);
opl_write(0xe3 + op_table[i], 0);
opl_write(0xa0 + i, 0);
opl_write(0xb0 + i, 0);
opl_write(0xc0 + i, 0);
}
}
void lds_setregs(Uint8 reg, Uint8 val)
{
if(fmchip[reg] == val) return;
fmchip[reg] = val;
opl_write(reg, val);
}
void lds_setregs_adv(Uint8 reg, Uint8 mask, Uint8 val)
{
lds_setregs(reg, (fmchip[reg] & mask) | val);
}
int lds_update( void )
{
Uint16 comword, freq, octave, chan, tune, wibc, tremc, arpreg;
int vbreak;
Uint8 level, regnum, comhi, comlo;
int i;
Channel *c;
if(!playing) return false;
/* handle fading */
if(fadeonoff)
{
if(fadeonoff <= 128) {
if(allvolume > fadeonoff || allvolume == 0)
{
allvolume -= fadeonoff;
} else {
allvolume = 1;
fadeonoff = 0;
if(hardfade != 0) {
playing = false;
hardfade = 0;
for(i = 0; i < 9; i++)
{
channel[i].keycount = 1;
}
}
}
} else {
if( (Uint8) ((allvolume + (0x100 - fadeonoff)) & 0xff) <= mainvolume)
{
allvolume += 0x100 - fadeonoff;
} else {
allvolume = mainvolume;
fadeonoff = 0;
}
}
}
/* handle channel delay */
for(chan = 0; chan < 9; chan++) {
c = &channel[chan];
if(c->chancheat.chandelay) {
if(!(--c->chancheat.chandelay)) {
lds_playsound(c->chancheat.sound, chan, c->chancheat.high);
}
}
}
/* handle notes */
if(!tempo_now && positions)
{
vbreak = false;
for(chan = 0; chan < 9; chan++)
{
c = &channel[chan];
if(!c->packwait) {
Uint16 patnum = positions[posplay * 9 + chan].patnum;
Uint8 transpose = positions[posplay * 9 + chan].transpose;
/*printf("> %p", positions);*/
comword = patterns[patnum + c->packpos];
comhi = comword >> 8; comlo = comword & 0xff;
if(comword) {
if(comhi == 0x80)
{
c->packwait = comlo;
} else {
if(comhi >= 0x80)
{
switch(comhi)
{
case 0xff:
c->volcar = (((c->volcar & 0x3f) * comlo) >> 6) & 0x3f;
if(fmchip[0xc0 + chan] & 1)
c->volmod = (((c->volmod & 0x3f) * comlo) >> 6) & 0x3f;
break;
case 0xfe:
tempo = comword & 0x3f;
break;
case 0xfd:
c->nextvol = comlo;
break;
case 0xfc:
playing = false;
/* in real player there's also full keyoff here, but we don't need it */
break;
case 0xfb:
c->keycount = 1;
break;
case 0xfa:
vbreak = true;
jumppos = (posplay + 1) & maxpos;
break;
case 0xf9:
vbreak = true;
jumppos = comlo & maxpos;
jumping = 1;
if(jumppos < posplay)
{
songlooped = true;
}
break;
case 0xf8:
c->lasttune = 0;
break;
case 0xf7:
c->vibwait = 0;
/* PASCAL: c->vibspeed = ((comlo >> 4) & 15) + 2; */
c->vibspeed = (comlo >> 4) + 2;
c->vibrate = (comlo & 15) + 1;
break;
case 0xf6:
c->glideto = comlo;
break;
case 0xf5:
c->finetune = comlo;
break;
case 0xf4:
if(!hardfade)
{
allvolume = mainvolume = comlo;
fadeonoff = 0;
}
break;
case 0xf3:
if(!hardfade)
{
fadeonoff = comlo;
}
break;
case 0xf2:
c->trmstay = comlo;
break;
case 0xf1: /* panorama */
case 0xf0: /* progch */
/* MIDI commands (unhandled) */
/*AdPlug_LogWrite("CldsPlayer(): not handling MIDI command 0x%x, "
"value = 0x%x\n", comhi);*/
break;
default:
if(comhi < 0xa0)
{
c->glideto = comhi & 0x1f;
} else {
/*AdPlug_LogWrite("CldsPlayer(): unknown command 0x%x encountered!"
" value = 0x%x\n", comhi, comlo);*/
}
break;
}
} else {
Uint8 sound;
Uint16 high;
Sint8 transp = transpose & 127;
/*
* Originally, in assembler code, the player first shifted
* logically left the transpose byte by 1 and then shifted
* arithmetically right the same byte to achieve the final,
* signed transpose value. Since we can't do arithmetic shifts
* in C, we just duplicate the 7th bit into the 8th one and
* discard the 8th one completely.
*/
if(transpose & 64)
{
transp |= 128;
}
if(transpose & 128)
{
sound = (comlo + transp) & maxsound;
high = comhi << 4;
} else {
sound = comlo & maxsound;
high = (comhi + transp) << 4;
}
/*
PASCAL:
sound = comlo & maxsound;
high = (comhi + (((transpose + 0x24) & 0xff) - 0x24)) << 4;
*/
if(!chandelay[chan]) {
lds_playsound(sound, chan, high);
} else {
c->chancheat.chandelay = chandelay[chan];
c->chancheat.sound = sound;
c->chancheat.high = high;
}
}
}
}
c->packpos++;
} else {
c->packwait--;
}
}
tempo_now = tempo;
/*
The continue table is updated here, but this is only used in the
original player, which can be paused in the middle of a song and then
unpaused. Since AdPlug does all this for us automatically, we don't
have a continue table here. The continue table update code is noted
here for reference only.
if(!pattplay) {
conttab[speed & maxcont].position = posplay & 0xff;
conttab[speed & maxcont].tempo = tempo;
}
*/
pattplay++;
if(vbreak)
{
pattplay = 0;
for(i = 0; i < 9; i++)
{
channel[i].packpos = channel[i].packwait = 0;
}
posplay = jumppos;
} else {
if(pattplay >= pattlen) {
pattplay = 0;
for(i = 0; i < 9; i++)
{
channel[i].packpos = channel[i].packwait = 0;
}
posplay = (posplay + 1) & maxpos;
}
}
} else {
tempo_now--;
}
/* make effects */
for(chan = 0; chan < 9; chan++) {
c = &channel[chan];
regnum = op_table[chan];
if(c->keycount > 0) {
if(c->keycount == 1)
lds_setregs_adv(0xb0 + chan, 0xdf, 0);
c->keycount--;
}
/* arpeggio */
if(c->arp_size == 0)
arpreg = 0;
else {
arpreg = c->arp_tab[c->arp_pos] << 4;
if(arpreg == 0x800) {
if(c->arp_pos > 0) c->arp_tab[0] = c->arp_tab[c->arp_pos - 1];
c->arp_size = 1; c->arp_pos = 0;
arpreg = c->arp_tab[0] << 4;
}
if(c->arp_count == c->arp_speed) {
c->arp_pos++;
if(c->arp_pos >= c->arp_size) c->arp_pos = 0;
c->arp_count = 0;
} else
c->arp_count++;
}
/* glide & portamento */
if(c->lasttune && (c->lasttune != c->gototune)) {
if(c->lasttune > c->gototune) {
if(c->lasttune - c->gototune < c->portspeed)
c->lasttune = c->gototune;
else
c->lasttune -= c->portspeed;
} else {
if(c->gototune - c->lasttune < c->portspeed)
c->lasttune = c->gototune;
else
c->lasttune += c->portspeed;
}
if(arpreg >= 0x800)
arpreg = c->lasttune - (arpreg ^ 0xff0) - 16;
else
arpreg += c->lasttune;
freq = frequency[arpreg % (12 * 16)];
octave = arpreg / (12 * 16) - 1;
lds_setregs(0xa0 + chan, freq & 0xff);
lds_setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf);
} else {
/* vibrato */
if(!c->vibwait) {
if(c->vibrate) {
wibc = vibtab[c->vibcount & 0x3f] * c->vibrate;
if((c->vibcount & 0x40) == 0)
tune = c->lasttune + (wibc >> 8);
else
tune = c->lasttune - (wibc >> 8);
if(arpreg >= 0x800)
tune = tune - (arpreg ^ 0xff0) - 16;
else
tune += arpreg;
freq = frequency[tune % (12 * 16)];
octave = tune / (12 * 16) - 1;
lds_setregs(0xa0 + chan, freq & 0xff);
lds_setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf);
c->vibcount += c->vibspeed;
} else if(c->arp_size != 0) { /* no vibrato, just arpeggio */
if(arpreg >= 0x800)
tune = c->lasttune - (arpreg ^ 0xff0) - 16;
else
tune = c->lasttune + arpreg;
freq = frequency[tune % (12 * 16)];
octave = tune / (12 * 16) - 1;
lds_setregs(0xa0 + chan, freq & 0xff);
lds_setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf);
}
} else { /* no vibrato, just arpeggio */
c->vibwait--;
if(c->arp_size != 0) {
if(arpreg >= 0x800)
tune = c->lasttune - (arpreg ^ 0xff0) - 16;
else
tune = c->lasttune + arpreg;
freq = frequency[tune % (12 * 16)];
octave = tune / (12 * 16) - 1;
lds_setregs(0xa0 + chan, freq & 0xff);
lds_setregs_adv(0xb0 + chan, 0x20, ((octave << 2) + (freq >> 8)) & 0xdf);
}
}
}
/* tremolo (modulator) */
if(!c->trmwait) {
if(c->trmrate) {
tremc = tremtab[c->trmcount & 0x7f] * c->trmrate;
if((tremc >> 8) <= (c->volmod & 0x3f))
level = (c->volmod & 0x3f) - (tremc >> 8);
else
level = 0;
if(allvolume != 0 && (fmchip[0xc0 + chan] & 1))
lds_setregs_adv(0x40 + regnum, 0xc0, ((level * allvolume) >> 8) ^ 0x3f);
else
lds_setregs_adv(0x40 + regnum, 0xc0, level ^ 0x3f);
c->trmcount += c->trmspeed;
} else if(allvolume != 0 && (fmchip[0xc0 + chan] & 1))
lds_setregs_adv(0x40 + regnum, 0xc0, ((((c->volmod & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f);
else
lds_setregs_adv(0x40 + regnum, 0xc0, (c->volmod ^ 0x3f) & 0x3f);
} else {
c->trmwait--;
if(allvolume != 0 && (fmchip[0xc0 + chan] & 1))
lds_setregs_adv(0x40 + regnum, 0xc0, ((((c->volmod & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f);
}
/* tremolo (carrier) */
if(!c->trcwait) {
if(c->trcrate) {
tremc = tremtab[c->trccount & 0x7f] * c->trcrate;
if((tremc >> 8) <= (c->volcar & 0x3f))
level = (c->volcar & 0x3f) - (tremc >> 8);
else
level = 0;
if(allvolume != 0)
lds_setregs_adv(0x43 + regnum, 0xc0, ((level * allvolume) >> 8) ^ 0x3f);
else
lds_setregs_adv(0x43 + regnum, 0xc0, level ^ 0x3f);
c->trccount += c->trcspeed;
} else if(allvolume != 0)
lds_setregs_adv(0x43 + regnum, 0xc0, ((((c->volcar & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f);
else
lds_setregs_adv(0x43 + regnum, 0xc0, (c->volcar ^ 0x3f) & 0x3f);
} else {
c->trcwait--;
if(allvolume != 0)
lds_setregs_adv(0x43 + regnum, 0xc0, ((((c->volcar & 0x3f) * allvolume) >> 8) ^ 0x3f) & 0x3f);
}
}
return (!playing || songlooped) ? false : true;
}
void lds_playsound(int inst_number, int channel_number, int tunehigh)
{
Channel *c = &channel[channel_number]; /* current channel */
SoundBank *i = &soundbank[inst_number]; /* current instrument */
Uint32 regnum = op_table[channel_number]; /* channel's OPL2 register */
Uint8 volcalc, octave;
Uint16 freq;
/* set fine tune */
tunehigh += ((i->finetune + c->finetune + 0x80) & 0xff) - 0x80;
/* arpeggio handling */
if(!i->arpeggio) {
Uint16 arpcalc = i->arp_tab[0] << 4;
if(arpcalc > 0x800)
tunehigh = tunehigh - (arpcalc ^ 0xff0) - 16;
else
tunehigh += arpcalc;
}
/* glide handling */
if(c->glideto != 0) {
c->gototune = tunehigh;
c->portspeed = c->glideto;
c->glideto = c->finetune = 0;
return;
}
/* set modulator registers */
lds_setregs(0x20 + regnum, i->mod_misc);
volcalc = i->mod_vol;
if(!c->nextvol || !(i->feedback & 1))
c->volmod = volcalc;
else
c->volmod = (volcalc & 0xc0) | ((((volcalc & 0x3f) * c->nextvol) >> 6));
if((i->feedback & 1) == 1 && allvolume != 0)
lds_setregs(0x40 + regnum, ((c->volmod & 0xc0) | (((c->volmod & 0x3f) * allvolume) >> 8)) ^ 0x3f);
else
lds_setregs(0x40 + regnum, c->volmod ^ 0x3f);
lds_setregs(0x60 + regnum, i->mod_ad);
lds_setregs(0x80 + regnum, i->mod_sr);
lds_setregs(0xe0 + regnum, i->mod_wave);
/* Set carrier registers */
lds_setregs(0x23 + regnum, i->car_misc);
volcalc = i->car_vol;
if(!c->nextvol)
c->volcar = volcalc;
else
c->volcar = (volcalc & 0xc0) | ((((volcalc & 0x3f) * c->nextvol) >> 6));
if(allvolume)
lds_setregs(0x43 + regnum, ((c->volcar & 0xc0) | (((c->volcar & 0x3f) * allvolume) >> 8)) ^ 0x3f);
else
lds_setregs(0x43 + regnum, c->volcar ^ 0x3f);
lds_setregs(0x63 + regnum, i->car_ad);
lds_setregs(0x83 + regnum, i->car_sr);
lds_setregs(0xe3 + regnum, i->car_wave);
lds_setregs(0xc0 + channel_number, i->feedback);
lds_setregs_adv(0xb0 + channel_number, 0xdf, 0); /* key off */
freq = frequency[tunehigh % (12 * 16)];
octave = tunehigh / (12 * 16) - 1;
if(!i->glide) {
if(!i->portamento || !c->lasttune) {
lds_setregs(0xa0 + channel_number, freq & 0xff);
lds_setregs(0xb0 + channel_number, (octave << 2) + 0x20 + (freq >> 8));
c->lasttune = c->gototune = tunehigh;
} else {
c->gototune = tunehigh;
c->portspeed = i->portamento;
lds_setregs_adv(0xb0 + channel_number, 0xdf, 0x20); /* key on */
}
} else {
lds_setregs(0xa0 + channel_number, freq & 0xff);
lds_setregs(0xb0 + channel_number, (octave << 2) + 0x20 + (freq >> 8));
c->lasttune = tunehigh;
c->gototune = tunehigh + ((i->glide + 0x80) & 0xff) - 0x80; /* set destination */
c->portspeed = i->portamento;
}
if(!i->vibrato)
c->vibwait = c->vibspeed = c->vibrate = 0;
else {
c->vibwait = i->vibdelay;
/* PASCAL: c->vibspeed = ((i->vibrato >> 4) & 15) + 1; */
c->vibspeed = (i->vibrato >> 4) + 2;
c->vibrate = (i->vibrato & 15) + 1;
}
if(!(c->trmstay & 0xf0)) {
c->trmwait = (i->tremwait & 0xf0) >> 3;
/* PASCAL: c->trmspeed = (i->mod_trem >> 4) & 15; */
c->trmspeed = i->mod_trem >> 4;
c->trmrate = i->mod_trem & 15;
c->trmcount = 0;
}
if(!(c->trmstay & 0x0f)) {
c->trcwait = (i->tremwait & 15) << 1;
/* PASCAL: c->trcspeed = (i->car_trem >> 4) & 15; */
c->trcspeed = i->car_trem >> 4;
c->trcrate = i->car_trem & 15;
c->trccount = 0;
}
c->arp_size = i->arpeggio & 15;
c->arp_speed = i->arpeggio >> 4;
memcpy(c->arp_tab, i->arp_tab, 12);
c->keycount = i->keyoff;
c->nextvol = c->glideto = c->finetune = c->vibcount = c->arp_pos = c->arp_count = 0;
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,73 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef LDS_PLAY_H
#define LDS_PLAY_H
#include "opentyr.h"
extern bool playing, songlooped;
int lds_update( void );
bool lds_load( FILE *f, unsigned int music_offset, unsigned int music_size );
void lds_free( void );
void lds_rewind( void );
#define REFRESH 70.0f
/*unsigned int getorders() { return numposi; }
unsigned int getorder() { return posplay; }
unsigned int getrow() { return pattplay; }
unsigned int getspeed() { return speed; }
unsigned int getinstruments() { return numpatch; }*/
typedef struct {
unsigned char mod_misc, mod_vol, mod_ad, mod_sr, mod_wave,
car_misc, car_vol, car_ad, car_sr, car_wave, feedback, keyoff,
portamento, glide, finetune, vibrato, vibdelay, mod_trem, car_trem,
tremwait, arpeggio, arp_tab[12];
unsigned short start, size;
unsigned char fms;
unsigned short transp;
unsigned char midinst, midvelo, midkey, midtrans, middum1, middum2;
} SoundBank;
typedef struct {
unsigned short gototune, lasttune, packpos;
unsigned char finetune, glideto, portspeed, nextvol, volmod, volcar,
vibwait, vibspeed, vibrate, trmstay, trmwait, trmspeed, trmrate, trmcount,
trcwait, trcspeed, trcrate, trccount, arp_size, arp_speed, keycount,
vibcount, arp_pos, arp_count, packwait, arp_tab[12];
struct {
unsigned char chandelay, sound;
unsigned short high;
} chancheat;
} Channel;
typedef struct {
unsigned short patnum;
unsigned char transpose;
} Position;
void lds_playsound(int inst_number, int channel_number, int tunehigh);
void lds_setregs(unsigned char reg, unsigned char val);
void lds_setregs_adv(unsigned char reg, unsigned char mask, unsigned char val);
#endif /* LDS_PLAY_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,293 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "file.h"
#include "fm_synth.h"
#include "lds_play.h"
#include "loudness.h"
#include "nortsong.h"
#include "opentyr.h"
#include "params.h"
float music_volume = 0, sample_volume = 0;
bool music_stopped = true;
unsigned int song_playing = 0;
bool audio_disabled = false, music_disabled = false, samples_disabled = false;
/* SYN: These shouldn't be used outside this file. Hands off! */
FILE *music_file = NULL;
Uint32 *song_offset;
Uint16 song_count = 0;
SAMPLE_TYPE *channel_buffer[SFX_CHANNELS] = { NULL };
SAMPLE_TYPE *channel_pos[SFX_CHANNELS] = { NULL };
Uint32 channel_len[SFX_CHANNELS] = { 0 };
Uint8 channel_vol[SFX_CHANNELS];
int sound_init_state = false;
int freq = 11025 * OUTPUT_QUALITY;
static SDL_AudioCVT audio_cvt; // used for format conversion
void audio_cb( void *userdata, unsigned char *feedme, int howmuch );
void load_song( unsigned int song_num );
bool init_audio( void )
{
if (audio_disabled)
return false;
SDL_AudioSpec ask, got;
ask.freq = freq;
ask.format = (BYTES_PER_SAMPLE == 2) ? AUDIO_S16SYS : AUDIO_S8;
ask.channels = 1;
ask.samples = 512;
ask.callback = audio_cb;
printf("\trequested %d Hz, %d channels, %d samples\n", ask.freq, ask.channels, ask.samples);
if (SDL_OpenAudio(&ask, &got) == -1)
{
fprintf(stderr, "error: failed to initialize SDL audio: %s\n", SDL_GetError());
audio_disabled = true;
return false;
}
printf("\tobtained %d Hz, %d channels, %d samples\n", got.freq, got.channels, got.samples);
SDL_BuildAudioCVT(&audio_cvt, ask.format, ask.channels, ask.freq, got.format, got.channels, got.freq);
opl_init();
SDL_PauseAudio(0); // unpause
return true;
}
void audio_cb( void *user_data, unsigned char *sdl_buffer, int howmuch )
{
(void)user_data;
// prepare for conversion
howmuch /= audio_cvt.len_mult;
audio_cvt.buf = sdl_buffer;
audio_cvt.len = howmuch;
static long ct = 0;
SAMPLE_TYPE *feedme = (SAMPLE_TYPE *)sdl_buffer;
if (!music_disabled && !music_stopped)
{
/* SYN: Simulate the fm synth chip */
SAMPLE_TYPE *music_pos = feedme;
long remaining = howmuch / BYTES_PER_SAMPLE;
while (remaining > 0)
{
while (ct < 0)
{
ct += freq;
lds_update(); /* SYN: Do I need to use the return value for anything here? */
}
/* SYN: Okay, about the calculations below. I still don't 100% get what's going on, but...
- freq is samples/time as output by SDL.
- REFRESH is how often the play proc would have been called in Tyrian. Standard speed is
70Hz, which is the default value of 70.0f
- ct represents the margin between play time (representing # of samples) and tick speed of
the songs (70Hz by default). It keeps track of which one is ahead, because they don't
synch perfectly. */
/* set i to smaller of data requested by SDL and a value calculated from the refresh rate */
long i = (long)((ct / REFRESH) + 4) & ~3;
i = (i > remaining) ? remaining : i; /* i should now equal the number of samples we get */
opl_update((SAMPLE_TYPE *)music_pos, i);
music_pos += i;
remaining -= i;
ct -= (long)(REFRESH * i);
}
/* Reduce the music volume. */
int qu = howmuch / BYTES_PER_SAMPLE;
for (int smp = 0; smp < qu; smp++)
{
feedme[smp] *= music_volume;
}
}
if (!samples_disabled)
{
/* SYN: Mix sound channels and shove into audio buffer */
for (int ch = 0; ch < SFX_CHANNELS; ch++)
{
float volume = sample_volume * (channel_vol[ch] / (float)SFX_CHANNELS);
/* SYN: Don't copy more data than is in the channel! */
unsigned int qu = ((unsigned)howmuch > channel_len[ch] ? channel_len[ch] : (unsigned)howmuch) / BYTES_PER_SAMPLE;
for (unsigned int smp = 0; smp < qu; smp++)
{
#if (BYTES_PER_SAMPLE == 2)
Sint32 clip = (Sint32)feedme[smp] + (Sint32)(channel_pos[ch][smp] * volume);
feedme[smp] = (clip > 0x7fff) ? 0x7fff : (clip <= -0x8000) ? -0x8000 : (Sint16)clip;
#else /* BYTES_PER_SAMPLE */
Sint16 clip = (Sint16)feedme[smp] + (Sint16)(channel_pos[ch][smp] * volume);
feedme[smp] = (clip > 0x7f) ? 0x7f : (clip <= -0x80) ? -0x80 : (Sint8)clip;
#endif /* BYTES_PER_SAMPLE */
}
channel_pos[ch] += qu;
channel_len[ch] -= qu * BYTES_PER_SAMPLE;
/* SYN: If we've emptied a channel buffer, let's free the memory and clear the channel. */
if (channel_len[ch] == 0)
{
free(channel_buffer[ch]);
channel_buffer[ch] = channel_pos[ch] = NULL;
}
}
}
// do conversion
SDL_ConvertAudio(&audio_cvt);
}
void deinit_audio( void )
{
if (audio_disabled)
return;
SDL_PauseAudio(1); // pause
SDL_CloseAudio();
for (unsigned int i = 0; i < SFX_CHANNELS; i++)
{
free(channel_buffer[i]);
channel_buffer[i] = channel_pos[i] = NULL;
channel_len[i] = 0;
}
opl_deinit();
lds_free();
}
void load_music( void )
{
if (music_file == NULL)
{
music_file = dir_fopen_die(data_dir(), "music.mus", "rb");
efread(&song_count, sizeof(song_count), 1, music_file);
song_offset = (Uint32*)malloc((song_count + 1) * sizeof(song_offset));
efread(song_offset, 4, song_count, music_file);
song_offset[song_count] = ftell_eof(music_file);
}
}
void load_song( unsigned int song_num )
{
if (audio_disabled)
return;
SDL_LockAudio();
if (song_num < song_count)
{
unsigned int song_size = song_offset[song_num + 1] - song_offset[song_num];
lds_load(music_file, song_offset[song_num], song_size);
}
else
{
fprintf(stderr, "warning: failed to load song %d\n", song_num + 1);
}
SDL_UnlockAudio();
}
void play_song( unsigned int song_num )
{
if (song_num != song_playing)
{
load_song(song_num);
song_playing = song_num;
}
music_stopped = false;
}
void restart_song( void )
{
unsigned int temp = song_playing;
song_playing = -1;
play_song(temp);
}
void stop_song( void )
{
music_stopped = true;
}
void fade_song( void )
{
printf("TODO: %s\n", __FUNCTION__);
}
void set_volume( unsigned int music, unsigned int sample )
{
music_volume = music * (1.5f / 255.0f);
sample_volume = sample * (1.0f / 255.0f);
}
void JE_multiSamplePlay(JE_byte *buffer, JE_word size, JE_byte chan, JE_byte vol)
{
if (audio_disabled || samples_disabled)
return;
SDL_LockAudio();
free(channel_buffer[chan]);
channel_len[chan] = size * BYTES_PER_SAMPLE * SAMPLE_SCALING;
channel_buffer[chan] = (OPLSAMPLE*)malloc(channel_len[chan]);
channel_pos[chan] = channel_buffer[chan];
channel_vol[chan] = vol + 1;
for (int i = 0; i < size; i++)
{
for (int ex = 0; ex < SAMPLE_SCALING; ex++)
{
#if (BYTES_PER_SAMPLE == 2)
channel_buffer[chan][(i * SAMPLE_SCALING) + ex] = (Sint8)buffer[i] << 8;
#else /* BYTES_PER_SAMPLE */
channel_buffer[chan][(i * SAMPLE_SCALING) + ex] = (Sint8)buffer[i];
#endif /* BYTES_PER_SAMPLE */
}
}
SDL_UnlockAudio();
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,60 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef LOUDNESS_H
#define LOUDNESS_H
#include "fmopl.h"
#include "opentyr.h"
#include "SDL.h"
#define SFX_CHANNELS 8
#if defined(TARGET_GP2X) || defined(TARGET_DINGUX) || defined(ANDROID)
#define OUTPUT_QUALITY 2 // 22 kHz
#else
#define OUTPUT_QUALITY 4 // 44 kHz
#endif
#define SAMPLE_SCALING OUTPUT_QUALITY
#define SAMPLE_TYPE OPLSAMPLE
#define BYTES_PER_SAMPLE (OPL_SAMPLE_BITS / 8)
extern float music_volume, sample_volume;
extern unsigned int song_playing;
extern bool audio_disabled, music_disabled, samples_disabled;
bool init_audio( void );
void deinit_audio( void );
void load_music( void );
void play_song( unsigned int song_num );
void restart_song( void );
void stop_song( void );
void fade_song( void );
void set_volume( unsigned int music, unsigned int sample );
void JE_multiSamplePlay(JE_byte *buffer, JE_word size, JE_byte chan, JE_byte vol);
#endif /* LOUDNESS_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,42 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "file.h"
#include "lvllib.h"
#include "opentyr.h"
JE_LvlPosType lvlPos;
char levelFile[13]; /* string [12] */
JE_word lvlNum;
void JE_analyzeLevel( void )
{
FILE *f = dir_fopen_die(data_dir(), levelFile, "rb");
efread(&lvlNum, sizeof(JE_word), 1, f);
for (int x = 0; x < lvlNum; x++)
efread(&lvlPos[x], sizeof(JE_longint), 1, f);
lvlPos[lvlNum] = ftell_eof(f);
fclose(f);
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,35 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef LVLLIB_H
#define LVLLIB_H
#include "opentyr.h"
typedef JE_longint JE_LvlPosType[43]; /* [1..42 + 1] */
extern JE_LvlPosType lvlPos;
extern char levelFile[13]; /* string [12] */
extern JE_word lvlNum;
void JE_analyzeLevel( void );
#endif /* LVLLIB_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,174 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "opentyr.h"
#include "lvlmast.h"
const JE_char shapeFile[34] = /* [1..34] */
{
'2', '4', '7', '8', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', '5', '#', 'V', '0', '@', '3', '^', '5', '9'
};
const char lvlFile[LVL_NUM][9] = /* [1..LVLnum] of string [8] */
{
/* 1*/ "ASTROID4", "MAINMAPE",
/* 2*/ "ASTROID5", "MAINMAPD",
/* 3*/ "ASTROID7", "MAINMAPC",
/* 4*/ "BUBBLES", "MAINMAPT",
/* 5*/ "DELI", "MAINMAPS",
/* 6*/ "MINES2", "MAINMAPQ",
/* 7*/ "MINES", "MAINMAPI",
/* 8*/ "SAVARA", "MAINMAPY",
/* 9*/ "TYRLEV", "MAINMAPZ",
/*10*/ "BONUS1-1", "MAINMAP0",
/*11*/ "HOLES", "MAINMAP8",
/*12*/ "SAVARA3", "MAINMAP3",
/*13*/ "DESERT", "MAINMAAA",
/*14*/ "WINDY", "MAINMAAB",
/*15*/ "TYRLEV3", "MAINMAPZ",
/*16*/ "UNDERTYR", "MAINMAAU",
/*17*/ "SAVARA5", "MAINMAAW",
/*18*/ "BEER", "MAINMAAX"
};
const char lvlFile2[LVL_NUM_2][9] = /* [1..LVLnum2] of string [8] */
{
"JUNGLE", "MAINMAPF",
"GIGER", "MAINMAPR",
"BONUS1-2", "MAINMAP0",
"ASTCITY2", "MAINMAP1",
"SPACEATK", "MAINMAPH",
"STATION", "MAINMAPV",
"GEMWAR", "MAINMAPH",
"MARKERS", "MAINMAPH",
"PATHS", "MAINMAPH",
"JUNGLE2", "MAINMAP5",
"JUNGLE3", "MAINMAP7",
"JUNGLE4", "MAINMAAP"
};
const char lvlFile3[LVL_NUM_3][9] = /* [1..LVLnum3] of string [8] */
{
"ICE", "MAINMAPX",
"ASTCITY", "MAINMAPP",
"MINES3", "MAINMAPO",
"TUNNEL", "MAINMAPW",
"DELI2", "MAINMAPU", /*Bonus 3*/
"FLEET", "MAINMAPB",
"STARGATE", "MAINMAP2", /*Bubbly*/
"TYRLEV2", "MAINMAPZ",
"TUNNEL2", "MAINMAPA", /*Tunnel*/
"SAVARA2", "MAINMAPY",
"DELI3", "MAINMAPS",
"MACES", "MAINMAP9" /*Bonus Maces*/
};
const char lvlFile4[LVL_NUM_4][9] = /* [1..LVLnum4] of string [8] */
{
"HARVEST", "MAINMAAC", /*Harvest World ooooo */
"MAZE", "MAINMAAD", /*Windy 2 ooooo */
"SAVARA4", "MAINMAAF", /*Savara IV ooooo */
"DESERT3", "MAINMAAG", /*Desert ooooo */
"LAVA1", "MAINMAAH", /*Lava Core ooooo */
"LAVA2", "MAINMAAJ", /*Lava Center ooooo */
"CORE", "MAINMAAI", /*Tec tiles ooooo */
"ICE1", "MAINMAAK", /*Ice exit ooooo */
"LAVA3", "MAINMAAL", /*Lava Exit ooooo */
"DESERT4", "MAINMAAM", /*Desert Run ooooo */
"TUNNEL3", "MAINMAAN", /*Secret Tunnel ooooo */
"LAVA4", "MAINMAAO", /*Lava Run ooooo */
"EYESPY", "MAINMAAQ", /*Giger Eye ooooo */
"FLEET2", "MAINMAPH", /*Dread Not ooooo */
"BRAIN", "MAINMAAR", /*Brainiac ooooo */
"NOSE", "MAINMAAS", /*Nose ooooo */
"DESERT5", "MAINMAAT", /*Time War ooooo */
"GALAGA", "MAINMAAV", /*Galaga ooooo */
/*19*/ "SAVARA6", "MAINMAAY", /*Savara Approach ooooo */
/*20*/ "SPACEAT2", "MAINMABB" /*Camanis Go ooooo */
};
const char lvlFile5[LVL_NUM_5][9] = /* [1..lvlnum5] of string [8] */
{
/* 1*/ "E5LVL01", "MAINMA51" /*FogWalls ----- */
};
/*! JE_LvlPosType lvlPos;*/
/*
Episode 4 uses...
NEWSH(.SHP
NEWSH^.SHP
NEWSH7.SHP
NEWSHP.SHP
NEWSH&.SHP
NEWSHE.SHP
NEWSHV.SHP
NEWSH#.SHP
NEWSHJ.SHP
NEWSH{.SHP
NEWSHK.SHP
SHAPESZ.DAT
SHAPESW.DAT
SHAPESX.DAT
SHAPES}.DAT
*/
/*
TYPE 5: Shape Files
SHAPES1.DAT o - - - - Items
SHAPES3.DAT o - - - - Shots
SHAPES6.DAT o - - - - Explosions
SHAPES9.DAT o - - - - Player ships/options
1 SHAPES2.DAT - o - - - Tyrian ships
2 SHAPES4.DAT - o - - - TyrianBoss
3 SHAPES7.DAT - - - - - Iceships
4 SHAPES8.DAT - - - - - Tunnel World
5 SHAPESA.DAT o - - - - Mine Stuff
6 SHAPESB.DAT - - - - - IceBoss
7 SHAPESC.DAT - o - - - Deliani Stuff
8 SHAPESD.DAT o - - - - Asteroid Stuff I
9 SHAPESE.DAT - o - - - Tyrian Bonus Rock + Bubbles
10 SHAPESF.DAT - o - - - Savara Stuff I
11 SHAPESG.DAT - - - - - Giger Stuff
12 SHAPESH.DAT - - - - - Giger Stuff
13 SHAPESI.DAT - o - - - Savara Stuff II + Savara Boss
14 SHAPESJ.DAT - - - - - Jungle Stuff
15 SHAPESK.DAT - - - - - Snowballs
16 SHAPESL.DAT - - - - o Satellites
17 SHAPESM.DAT o - - - - Asteroid Stuff IV
18 SHAPESN.DAT - - - - - Giger Boss
19 SHAPESO.DAT - o - - - Savara Boss
20 SHAPESP.DAT o - - - - Asteroid Stuff III
21 SHAPESQ.DAT o - - - - Coins and Gems
22 SHAPESR.DAT - - - - - TunnelWorld Boss
23 SHAPESS.DAT o - - - - Asteroid Stuff II
24 SHAPEST.DAT - o - - - Deli Boss
25 SHAPESU.DAT - - - - - Deli Stuff II
28 SHAPESV.DAT - - o - o Misc Stuff/Cars
27 SHAPES#.DAT - - - o o Sawblades
31 SHAPES(.DAT - - - - o Desert/Lava
M 1 2 3 4 episode
*/
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,49 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef LVLMAST_H
#define LVLMAST_H
#include "opentyr.h"
#define EVENT_MAXIMUM 2500
#define WEAP_NUM 780
#define PORT_NUM 42
#define ARMOR_NUM 4
#define POWER_NUM 6
#define ENGINE_NUM 6
#define OPTION_NUM 30
#define SHIP_NUM 13
#define SHIELD_NUM 10
#define SPECIAL_NUM 46
#define ENEMY_NUM 850
#define LVL_NUM (18 * 2)
#define LVL_NUM_2 (12 * 2)
#define LVL_NUM_3 (12 * 2)
#define LVL_NUM_4 (20 * 2)
#define LVL_NUM_5 (1 * 2)
extern const JE_char shapeFile[34]; /* [1..34] */
#endif /* LVLMAST_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,101 @@
/* vim: set noet:
*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2008 The OpenTyrian Development Team
*
* 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.
*/
#include "config.h"
#include "opentyr.h"
#import <Cocoa/Cocoa.h>
#import <SDL/SDL.h>
#import <SDL_net/SDL_net.h>
// SDL_main.h (included by SDL.h) redefines main to SDL_main. As we are
// implementing the "real" main here we must undef this preprocessor symbol.
#undef main
@interface TyrianStartupClass : NSObject
@end
@implementation TyrianStartupClass
- (void)awakeFromNib
{
// Copied and modified from SDLMain.m from the "SDL Application" template
NSArray *argv_objc = [[NSProcessInfo processInfo] arguments];
int argc = [argv_objc count];
char ** argv;
BOOL finderLaunch;
if ( argc >= 2 && strncmp ([[argv_objc objectAtIndex:1] cString], "-psn", 4) == 0 ) {
argv = (char **) SDL_malloc(sizeof (char *) * 2);
argv[0] = (char *)[[argv_objc objectAtIndex:0] cString];
argv[1] = NULL;
argc = 1;
finderLaunch = YES;
} else {
int i;
argv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
for (i = 0; i < argc; i++) {
argv[i] = (char *)[[argv_objc objectAtIndex:i] cString];
}
finderLaunch = NO;
}
NSLog(@"%@",argv_objc);
SDL_main(argc, argv);
}
@end
const char* tyrian_game_folder()
{
return [[[[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:@"data"]
stringByAppendingString:@"/"]
cStringUsingEncoding:NSASCIIStringEncoding];
}
const char* get_user_directory()
{
// Get Application Support folder
NSArray* paths =
NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory,
NSUserDomainMask, YES);
if ([paths count] > 0)
{
NSString* path = [
[paths objectAtIndex:0]
stringByAppendingPathComponent:@"OpenTyrian"
];
// Create OpenTyrian if it doesn't already exist
[[NSFileManager defaultManager]
createDirectoryAtPath:path attributes:nil];
// The return value is expected to end with a /
return [[path stringByAppendingString:@"/"] cStringUsingEncoding:NSASCIIStringEncoding];
}
return "";
}
int main(int argc, char** argv)
{
return NSApplicationMain(argc, (const char **) argv);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,94 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef MAININT_H
#define MAININT_H
#include "config.h"
#include "opentyr.h"
#include "palette.h"
#include "player.h"
#include "sprite.h"
extern bool button[4]; // fire, left fire, right fire, mode swap
extern JE_shortint constantLastX;
extern JE_word textErase;
extern JE_word upgradeCost;
extern JE_word downgradeCost;
extern JE_boolean performSave;
extern JE_boolean jumpSection;
extern JE_boolean useLastBank;
extern bool pause_pressed, ingamemenu_pressed;
/*void JE_textMenuWait ( JE_word waittime, JE_boolean dogamma );*/
void JE_drawTextWindow( const char *text );
void JE_initPlayerData( void );
void JE_highScoreScreen( void );
void JE_gammaCorrect_func( JE_byte *col, JE_real r );
void JE_gammaCorrect( Palette *colorBuffer, JE_byte gamma );
JE_boolean JE_gammaCheck( void );
/* void JE_textMenuWait( JE_word *waitTime, JE_boolean doGamma ); /!\ In setup.h */
void JE_loadOrderingInfo( void );
void JE_nextEpisode( void );
void JE_helpSystem( JE_byte startTopic );
void JE_doInGameSetup( void );
JE_boolean JE_inGameSetup( void );
void JE_inGameHelp( void );
void JE_sortHighScores( void );
void JE_highScoreCheck( void );
void adjust_difficulty( void );
bool load_next_demo( void );
bool replay_demo_keys( void );
bool read_demo_keys( void );
void JE_SFCodes( JE_byte playerNum_, JE_integer PX_, JE_integer PY_, JE_integer mouseX_, JE_integer mouseY_ );
void JE_sort( void );
long weapon_upgrade_cost( long base_cost, unsigned int power );
ulong JE_getCost( JE_byte itemType, JE_word itemNum );
JE_longint JE_getValue( JE_byte itemType, JE_word itemNum );
ulong JE_totalScore( const Player * );
void JE_drawPortConfigButtons( void );
void JE_outCharGlow( JE_word x, JE_word y, const char *s );
void JE_playCredits( void );
void JE_endLevelAni( void );
void JE_drawCube( SDL_Surface * screen, JE_word x, JE_word y, JE_byte filter, JE_byte brightness );
void JE_handleChat( void );
bool str_pop_int( char *str, int *val );
void JE_loadScreen( void );
void JE_operation( JE_byte slot );
void JE_inGameDisplays( void );
void JE_mainKeyboardInput( void );
void JE_pauseGame( void );
void JE_playerMovement( Player *this_player, JE_byte inputDevice, JE_byte playerNum, JE_word shipGr, Sprite2_array *shapes9ptr_, JE_word *mouseX, JE_word *mouseY );
void JE_mainGamePlayerFunctions( void );
const char *JE_getName( JE_byte pnum );
void JE_playerCollide( Player *this_player, JE_byte playerNum );
#endif /* MAININT_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,269 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "config.h"
#include "episodes.h"
#include "fonthand.h"
#include "keyboard.h"
#include "menus.h"
#include "nortsong.h"
#include "opentyr.h"
#include "palette.h"
#include "picload.h"
#include "setup.h"
#include "sprite.h"
#include "video.h"
char episode_name[6][31], difficulty_name[7][21], gameplay_name[5][26];
bool select_gameplay( void )
{
JE_loadPic(VGAScreen, 2, false);
JE_dString(VGAScreen, JE_fontCenter(gameplay_name[0], FONT_SHAPES), 20, gameplay_name[0], FONT_SHAPES);
int gameplay = 1,
gameplay_max = 4;
bool fade_in = true;
for (; ; )
{
for (int i = 1; i <= gameplay_max; i++)
{
JE_outTextAdjust(VGAScreen, JE_fontCenter(gameplay_name[i], SMALL_FONT_SHAPES), i * 24 + 30, gameplay_name[i], 15, - 4 + (i == gameplay ? 2 : 0) - (i == 4 ? 4 : 0), SMALL_FONT_SHAPES, true);
}
JE_showVGA();
if (fade_in)
{
fade_palette(colors, 10, 0, 255);
fade_in = false;
}
JE_word temp = 0;
JE_textMenuWait(&temp, false);
if (newkey)
{
switch (lastkey_sym)
{
case SDLK_UP:
gameplay--;
if (gameplay < 1)
{
gameplay = gameplay_max;
}
JE_playSampleNum(S_CURSOR);
break;
case SDLK_DOWN:
gameplay++;
if (gameplay > gameplay_max)
{
gameplay = 1;
}
JE_playSampleNum(S_CURSOR);
break;
case SDLK_RETURN:
if (gameplay == 4)
{
JE_playSampleNum(S_SPRING);
/* TODO: NETWORK */
fprintf(stderr, "error: networking via menu not implemented\n");
break;
}
JE_playSampleNum(S_SELECT);
fade_black(10);
onePlayerAction = (gameplay == 2);
twoPlayerMode = (gameplay == 3);
return true;
case SDLK_ESCAPE:
JE_playSampleNum(S_SPRING);
/* fading handled elsewhere
fade_black(10); */
return false;
default:
break;
}
}
}
}
bool select_episode( void )
{
JE_loadPic(VGAScreen, 2, false);
JE_dString(VGAScreen, JE_fontCenter(episode_name[0], FONT_SHAPES), 20, episode_name[0], FONT_SHAPES);
int episode = 1,
episode_max = EPISODE_MAX - 1;
bool fade_in = true;
for (; ; )
{
for (int i = 1; i <= episode_max; i++)
{
JE_outTextAdjust(VGAScreen, 20, i * 30 + 20, episode_name[i], 15, -4 + (i == episode ? 2 : 0) - (!episodeAvail[i - 1] ? 4 : 0), SMALL_FONT_SHAPES, true);
}
JE_showVGA();
if (fade_in)
{
fade_palette(colors, 10, 0, 255);
fade_in = false;
}
JE_word temp = 0;
JE_textMenuWait(&temp, false);
if (newkey)
{
switch (lastkey_sym)
{
case SDLK_UP:
episode--;
if (episode < 1)
{
episode = episode_max;
}
JE_playSampleNum(S_CURSOR);
break;
case SDLK_DOWN:
episode++;
if (episode > episode_max)
{
episode = 1;
}
JE_playSampleNum(S_CURSOR);
break;
case SDLK_RETURN:
if (!episodeAvail[episode - 1])
{
JE_playSampleNum(S_SPRING);
break;
}
JE_playSampleNum(S_SELECT);
fade_black(10);
JE_initEpisode(episode);
initial_episode_num = episodeNum;
return true;
case SDLK_ESCAPE:
JE_playSampleNum(S_SPRING);
/* fading handled elsewhere
fade_black(10); */
return false;
default:
break;
}
}
}
}
bool select_difficulty( void )
{
JE_loadPic(VGAScreen, 2, false);
JE_dString(VGAScreen, JE_fontCenter(difficulty_name[0], FONT_SHAPES), 20, difficulty_name[0], FONT_SHAPES);
difficultyLevel = 2;
int difficulty_max = 3;
bool fade_in = true;
for (; ; )
{
for (int i = 1; i <= difficulty_max; i++)
{
JE_outTextAdjust(VGAScreen, JE_fontCenter(difficulty_name[i], SMALL_FONT_SHAPES), i * 24 + 30, difficulty_name[i], 15, -4 + (i == difficultyLevel ? 2 : 0), SMALL_FONT_SHAPES, true);
}
JE_showVGA();
if (fade_in)
{
fade_palette(colors, 10, 0, 255);
fade_in = false;
}
JE_word temp = 0;
JE_textMenuWait(&temp, false);
if (SDL_GetModState() & KMOD_SHIFT)
{
if ((difficulty_max < 4 && keysactive[SDLK_g]) ||
(difficulty_max == 4 && keysactive[SDLK_RIGHTBRACKET]))
{
difficulty_max++;
}
} else if (difficulty_max == 5 && keysactive[SDLK_l] && keysactive[SDLK_o] && keysactive[SDLK_r] && keysactive[SDLK_d]) {
difficulty_max++;
}
if (newkey)
{
switch (lastkey_sym)
{
case SDLK_UP:
difficultyLevel--;
if (difficultyLevel < 1)
{
difficultyLevel = difficulty_max;
}
JE_playSampleNum(S_CURSOR);
break;
case SDLK_DOWN:
difficultyLevel++;
if (difficultyLevel > difficulty_max)
{
difficultyLevel = 1;
}
JE_playSampleNum(S_CURSOR);
break;
case SDLK_RETURN:
JE_playSampleNum(S_SELECT);
/* fading handled elsewhere
fade_black(10); */
if (difficultyLevel == 6)
{
difficultyLevel = 8;
} else if (difficultyLevel == 5) {
difficultyLevel = 6;
}
return true;
case SDLK_ESCAPE:
JE_playSampleNum(S_SPRING);
/* fading handled elsewhere
fade_black(10); */
return false;
default:
break;
}
}
}
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,32 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef MENUS_H
#define MENUS_H
#include "opentyr.h"
extern char episode_name[6][31], difficulty_name[7][21], gameplay_name[5][26];
bool select_gameplay( void );
bool select_episode( void );
bool select_difficulty( void );
#endif /* MENUS_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,26 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "mingw_fixes.h"
char *strchrnul( const char *s, int c )
{
for (; *s != c && *s != '\0'; ++s)
;
return (char *)s;
}

View File

@@ -0,0 +1,24 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef MINGW_FIXES_H
#define MINGW_FIXES_H
char *strchrnul( const char *s, int c );
#endif // MINGW_FIXES_H

View File

@@ -0,0 +1,114 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "keyboard.h"
#include "nortvars.h"
#include "sprite.h"
#include "video.h"
#include "vga256d.h"
#if defined(TARGET_GP2X) || defined(TARGET_DINGUX) || defined(ANDROID)
bool has_mouse = false;
#else
bool has_mouse = true;
#endif
bool mouse_has_three_buttons = true;
JE_word lastMouseX, lastMouseY;
JE_byte mouseCursor;
JE_word mouseX, mouseY, mouseButton;
JE_word mouseXB, mouseYB;
JE_byte mouseGrabShape[24 * 28]; /* [1..24*28] */
void JE_drawShapeTypeOne( JE_word x, JE_word y, JE_byte *shape )
{
JE_word xloop = 0, yloop = 0;
JE_byte *p = shape; /* shape pointer */
Uint8 *s; /* screen pointer, 8-bit specific */
Uint8 *s_limit; /* buffer boundary */
s = (Uint8 *)VGAScreen->pixels;
s += y * VGAScreen->pitch + x;
s_limit = (Uint8 *)VGAScreen->pixels;
s_limit += VGAScreen->h * VGAScreen->pitch;
for (yloop = 0; yloop < 28; yloop++)
{
for (xloop = 0; xloop < 24; xloop++)
{
if (s >= s_limit) return;
*s = *p;
s++; p++;
}
s -= 24;
s += VGAScreen->pitch;
}
}
void JE_grabShapeTypeOne( JE_word x, JE_word y, JE_byte *shape )
{
JE_word xloop = 0, yloop = 0;
JE_byte *p = shape; /* shape pointer */
Uint8 *s; /* screen pointer, 8-bit specific */
Uint8 *s_limit; /* buffer boundary */
s = (Uint8 *)VGAScreen->pixels;
s += y * VGAScreen->pitch + x;
s_limit = (Uint8 *)VGAScreen->pixels;
s_limit += VGAScreen->h * VGAScreen->pitch;
for (yloop = 0; yloop < 28; yloop++)
{
for (xloop = 0; xloop < 24; xloop++)
{
if (s >= s_limit) return;
*p = *s;
s++; p++;
}
s -= 24;
s += VGAScreen->pitch;
}
}
void JE_mouseStart( void )
{
const JE_word mouseCursorGr[3] /* [1..3] */ = {273, 275, 277};
if (has_mouse)
{
service_SDL_events(false);
mouseButton = mousedown ? lastmouse_but : 0; /* incorrect, possibly unimportant */
lastMouseX = MIN(mouse_x, 320 - 13);
lastMouseY = MIN(mouse_y, 200 - 16);
JE_grabShapeTypeOne(lastMouseX, lastMouseY, mouseGrabShape);
blit_sprite2x2(VGAScreen, lastMouseX, lastMouseY, shapes6, mouseCursorGr[mouseCursor]);
}
}
void JE_mouseReplace( void )
{
if (has_mouse)
JE_drawShapeTypeOne(lastMouseX, lastMouseY, mouseGrabShape);
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,44 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef MOUSE_H
#define MOUSE_H
#include "opentyr.h"
#include "SDL.h"
extern bool has_mouse;
extern bool mouse_has_three_buttons;
extern JE_word lastMouseX, lastMouseY;
extern JE_byte mouseCursor;
extern JE_word mouseX, mouseY, mouseButton;
extern JE_word mouseXB, mouseYB;
extern JE_byte mouseGrabShape[24 * 28];
void JE_drawShapeTypeOne( JE_word x, JE_word y, JE_byte *shape );
void JE_grabShapeTypeOne( JE_word x, JE_word y, JE_byte *shape );
void JE_mouseStart( void );
void JE_mouseReplace( void );
#endif /* MOUSE_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,108 @@
/*
Copyright (C) 1997--2004, Makoto Matsumoto, Takuji Nishimura, and
Eric Landry; All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
3. The names of its contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Any feedback is very welcome.
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
Reference: M. Matsumoto and T. Nishimura, "Mersenne Twister:
A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number
Generator", ACM Transactions on Modeling and Computer Simulation,
Vol. 8, No. 1, January 1998, pp 3--30.
*/
#include "mtrand.h"
/* Period parameters */
#define N 624
#define M 397
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
static unsigned long x[N]; /* the array for the state vector */
static unsigned long *p0, *p1, *pm;
void mt_srand( unsigned long s )
{
int i;
x[0] = s & 0xffffffffUL;
for (i = 1; i < N; ++i) {
x[i] = (1812433253UL * (x[i - 1] ^ (x[i - 1] >> 30)) + i)
& 0xffffffffUL; /* for >32 bit machines */
}
p0 = x;
p1 = x + 1;
pm = x + M;
}
/* generates a random number on the interval [0,0xffffffff] */
unsigned long mt_rand( void )
{
unsigned long y;
if (!p0) {
/* Default seed */
mt_srand(5489UL);
}
/* Twisted feedback */
y = *p0 = *pm++ ^ (((*p0 & UPPER_MASK) | (*p1 & LOWER_MASK)) >> 1) ^ ((~(*p1 & 1)+1) & MATRIX_A);
p0 = p1++;
if (pm == x + N) {
pm = x;
}
if (p1 == x + N) {
p1 = x;
}
/* Temper */
y ^= y >> 11;
y ^= y << 7 & 0x9d2c5680UL;
y ^= y << 15 & 0xefc60000UL;
y ^= y >> 18;
return y;
}
/* generates a random number on the interval [0,1]. */
float mt_rand_1( void )
{
return ((float)mt_rand() / (float)MT_RAND_MAX);
}
/* generates a random number on the interval [0,1). */
float mt_rand_lt1( void )
{
/* MT_RAND_MAX must be a float before adding one to it! */
return ((float)mt_rand() / ((float)MT_RAND_MAX + 1.0f));
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,31 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef MTRAND_H
#define MTRAND_H
#define MT_RAND_MAX 0xffffffffUL
void mt_srand( unsigned long s );
unsigned long mt_rand( void );
float mt_rand_1( void );
float mt_rand_lt1( void );
#endif /* MTRAND_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,117 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "opentyr.h"
#include "musmast.h"
JE_byte songBuy;
const char musicFile[MUSIC_NUM][13] =
{
/* 1 */ "ASTEROI2.DAT",
/* 2 */ "ASTEROID.DAT",
/* 3 */ "BUY.DAT",
/* 4 */ "CAMANIS.DAT",
/* 5 */ "CAMANISE.DAT",
/* 6 */ "DELIANI.DAT",
/* 7 */ "DELIANI2.DAT",
/* 8 */ "ENDING1.DAT",
/* 9 */ "ENDING2.DAT",
/* 10 */ "ENDLEVEL.DAT",
/* 11 */ "GAMEOVER.DAT",
/* 12 */ "GRYPHON.DAT",
/* 13 */ "GRYPHONE.DAT",
/* 14 */ "GYGES.DAT",
/* 15 */ "GYGESE.DAT",
/* 16 */ "HALLOWS.DAT",
/* 17 */ "ZICA.DAT",
/* 18 */ "TYRSONG2.DAT",
/* 19 */ "LOUDNESS.DAT",
/* 20 */ "NAVC.DAT",
/* 21 */ "SAVARA.DAT",
/* 22 */ "SAVARAE.DAT",
/* 23 */ "SPACE1.DAT",
/* 24 */ "SPACE2.DAT",
/* 25 */ "STARENDB.DAT",
/* 26 */ "START5.DAT",
/* 27 */ "TALK.DAT",
/* 28 */ "TORM.DAT",
/* 29 */ "TRANSON.DAT",
/* 30 */ "TYRSONG.DAT",
/* 31 */ "ZANAC3.DAT",
/* 32 */ "ZANACS.DAT",
/* 33 */ "SAVARA2.DAT",
/* 34 */ "HISCORE.DAT",
/* 35 */ "TYR4-1.DAT", /* OMF */
/* 36 */ "TYR4-3.DAT", /* SARAH */
/* 37 */ "TYR4-2.DAT", /* MAGFIELD */
/* 38 */ "TYR4-0.DAT", /* ROCKME */
/* 39 */ "TYR4-4.DAT", /* quiet music */
/* 40 */ "TYR4-5.DAT", /* piano */
/* 41 */ "TYR-BEER.DAT" /* BEER */
};
const char musicTitle[MUSIC_NUM][48] =
{
"Asteroid Dance Part 2",
"Asteroid Dance Part 1",
"Buy/Sell Music",
"CAMANIS",
"CAMANISE",
"Deli Shop Quartet",
"Deli Shop Quartet No. 2",
"Ending Number 1",
"Ending Number 2",
"End of Level",
"Game Over Solo",
"Gryphons of the West",
"Somebody pick up the Gryphone",
"Gyges, Will You Please Help Me?",
"I speak Gygese",
"Halloween Ramble",
"Tunneling Trolls",
"Tyrian, The Level",
"The MusicMan",
"The Navigator",
"Come Back to Me, Savara",
"Come Back again to Savara",
"Space Journey 1",
"Space Journey 2",
"The final edge",
"START5",
"Parlance",
"Torm - The Gathering",
"TRANSON",
"Tyrian: The Song",
"ZANAC3",
"ZANACS",
"Return me to Savara",
"High Score Table",
"One Mustn't Fall",
"Sarah's Song",
"A Field for Mag",
"Rock Garden",
"Quest for Peace",
"Composition in Q",
"BEER"
};
JE_boolean musicFade;
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,42 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef MUSMAST_H
#define MUSMAST_H
#include "opentyr.h"
#define DEFAULT_SONG_BUY 2
#define SONG_LEVELEND 9
#define SONG_GAMEOVER 10
#define SONG_MAPVIEW 19
#define SONG_ENDGAME1 7
#define SONG_ZANAC 31
#define SONG_TITLE 29
#define MUSIC_NUM 41
extern JE_byte songBuy;
extern const char musicFile[MUSIC_NUM][13];
extern const char musicTitle[MUSIC_NUM][48];
extern JE_boolean musicFade;
#endif /* MUSMAST_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,788 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "episodes.h"
#include "fonthand.h"
#include "helptext.h"
#include "joystick.h"
#include "keyboard.h"
#include "mainint.h"
#include "network.h"
#include "nortvars.h"
#include "opentyr.h"
#include "picload.h"
#include "sprite.h"
#include "varz.h"
#include "video.h"
#include "SDL.h"
#include "SDL_net.h"
#include <assert.h>
/* HERE BE DRAGONS!
*
* When I wrote this code I thought it was wonderful... that thought was very
* wrong. It works, but good luck understanding how... I don't anymore.
*
* Hopefully it'll be rewritten some day.
*/
#define NET_VERSION 2 // increment whenever networking changes might create incompatability
#define NET_PORT 1333 // UDP
#define NET_PACKET_SIZE 256
#define NET_PACKET_QUEUE 16
#define NET_RETRY 640 // ticks to wait for packet acknowledgement before resending
#define NET_RESEND 320 // ticks to wait before requesting unreceived game packet
#define NET_KEEP_ALIVE 1600 // ticks to wait between keep-alive packets
#define NET_TIME_OUT 16000 // ticks to wait before considering connection dead
bool isNetworkGame = false;
int network_delay = 1 + 1; // minimum is 1 + 0
char *network_opponent_host = NULL;
Uint16 network_player_port = NET_PORT,
network_opponent_port = NET_PORT;
static char empty_string[] = "";
char *network_player_name = empty_string,
*network_opponent_name = empty_string;
UDPsocket socket;
IPaddress ip;
UDPpacket *packet_out_temp, *packet_temp;
UDPpacket *packet_in[NET_PACKET_QUEUE] = { NULL },
*packet_out[NET_PACKET_QUEUE] = { NULL };
Uint16 last_out_sync = 0, queue_in_sync = 0, queue_out_sync = 0, last_ack_sync = 0;
Uint32 last_in_tick = 0, last_out_tick = 0;
UDPpacket *packet_state_in[NET_PACKET_QUEUE] = { NULL },
*packet_state_in_xor[NET_PACKET_QUEUE] = { NULL },
*packet_state_out[NET_PACKET_QUEUE] = { NULL };
Uint16 last_state_in_sync = 0, last_state_out_sync = 0;
Uint32 last_state_in_tick = 0;
bool net_initialized = false;
static bool connected = false, quit = false;
uint thisPlayerNum = 0; /* Player number on this PC (1 or 2) */
JE_boolean haltGame = false;
JE_boolean moveOk;
/* Special Requests */
JE_boolean pauseRequest, skipLevelRequest, helpRequest, nortShipRequest;
JE_boolean yourInGameMenuRequest, inGameMenuRequest;
// prepare new packet for sending
void network_prepare( Uint16 type )
{
SDLNet_Write16(type, &packet_out_temp->data[0]);
SDLNet_Write16(last_out_sync, &packet_out_temp->data[2]);
}
// send packet and place it in queue to be acknowledged
bool network_send( int len )
{
bool temp = network_send_no_ack(len);
Uint16 i = last_out_sync - queue_out_sync;
if (i < NET_PACKET_QUEUE)
{
packet_out[i] = SDLNet_AllocPacket(NET_PACKET_SIZE);
packet_copy(packet_out[i], packet_out_temp);
} else {
// connection is probably bad now
fprintf(stderr, "warning: outbound packet queue overflow\n");
return false;
}
last_out_sync++;
if (network_is_sync())
last_out_tick = SDL_GetTicks();
return temp;
}
// send packet but don't expect acknoledgment of delivery
bool network_send_no_ack( int len )
{
packet_out_temp->len = len;
if (!SDLNet_UDP_Send(socket, 0, packet_out_temp))
{
printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
return false;
}
return true;
}
// poll for new packets received, check that connection is alive, resend queued packets if necessary
int network_check( void )
{
if (!net_initialized)
return -1;
if (connected)
{
// timeout
if (!network_is_alive())
{
if (!quit)
network_tyrian_halt(2, false);
}
// keep-alive
static Uint32 keep_alive_tick = 0;
if (SDL_GetTicks() - keep_alive_tick > NET_KEEP_ALIVE)
{
network_prepare(PACKET_KEEP_ALIVE);
network_send_no_ack(4);
keep_alive_tick = SDL_GetTicks();
}
}
// retry
if (packet_out[0] && SDL_GetTicks() - last_out_tick > NET_RETRY)
{
if (!SDLNet_UDP_Send(socket, 0, packet_out[0]))
{
printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
return -1;
}
last_out_tick = SDL_GetTicks();
}
switch (SDLNet_UDP_Recv(socket, packet_temp))
{
case -1:
printf("SDLNet_UDP_Recv: %s\n", SDL_GetError());
return -1;
break;
case 0:
break;
default:
if (packet_temp->channel == 0 && packet_temp->len >= 4)
{
switch (SDLNet_Read16(&packet_temp->data[0]))
{
case PACKET_ACKNOWLEDGE:
if ((Uint16)(SDLNet_Read16(&packet_temp->data[2]) - last_ack_sync) < NET_PACKET_QUEUE)
{
last_ack_sync = SDLNet_Read16(&packet_temp->data[2]);
}
{
Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - queue_out_sync;
if (i < NET_PACKET_QUEUE)
{
if (packet_out[i])
{
SDLNet_FreePacket(packet_out[i]);
packet_out[i] = NULL;
}
}
}
// remove acknowledged packets from queue
while (packet_out[0] == NULL && (Uint16)(last_ack_sync - queue_out_sync) < NET_PACKET_QUEUE)
{
packets_shift_up(packet_out, NET_PACKET_QUEUE);
queue_out_sync++;
}
last_in_tick = SDL_GetTicks();
break;
case PACKET_CONNECT:
queue_in_sync = SDLNet_Read16(&packet_temp->data[2]);
for (int i = 0; i < NET_PACKET_QUEUE; i++)
{
if (packet_in[i])
{
SDLNet_FreePacket(packet_in[i]);
packet_in[i] = NULL;
}
}
case PACKET_DETAILS:
case PACKET_WAITING:
case PACKET_BUSY:
case PACKET_GAME_QUIT:
case PACKET_GAME_PAUSE:
case PACKET_GAME_MENU:
{
Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - queue_in_sync;
if (i < NET_PACKET_QUEUE)
{
if (packet_in[i] == NULL)
packet_in[i] = SDLNet_AllocPacket(NET_PACKET_SIZE);
packet_copy(packet_in[i], packet_temp);
} else {
// inbound packet queue overflow/underflow
// under normal circumstances, this is okay
}
}
network_acknowledge(SDLNet_Read16(&packet_temp->data[2]));
case PACKET_KEEP_ALIVE:
last_in_tick = SDL_GetTicks();
break;
case PACKET_QUIT:
if (!quit)
{
network_prepare(PACKET_QUIT);
network_send(4); // PACKET_QUIT
}
network_acknowledge(SDLNet_Read16(&packet_temp->data[2]));
if (!quit)
network_tyrian_halt(1, true);
break;
case PACKET_STATE:
// place packet in queue if within limits
{
Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - last_state_in_sync + 1;
if (i < NET_PACKET_QUEUE)
{
if (packet_state_in[i] == NULL)
packet_state_in[i] = SDLNet_AllocPacket(NET_PACKET_SIZE);
packet_copy(packet_state_in[i], packet_temp);
}
}
break;
case PACKET_STATE_XOR:
// place packet in queue if within limits
{
Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - last_state_in_sync + 1;
if (i < NET_PACKET_QUEUE)
{
if (packet_state_in_xor[i] == NULL)
{
packet_state_in_xor[i] = SDLNet_AllocPacket(NET_PACKET_SIZE);
packet_copy(packet_state_in_xor[i], packet_temp);
} else if (SDLNet_Read16(&packet_state_in_xor[i]->data[0]) != PACKET_STATE_XOR) {
for (int j = 4; j < packet_state_in_xor[i]->len; j++)
packet_state_in_xor[i]->data[j] ^= packet_temp->data[j];
SDLNet_Write16(PACKET_STATE_XOR, &packet_state_in_xor[i]->data[0]);
}
}
}
break;
case PACKET_STATE_RESEND:
// resend requested state packet if still available
{
Uint16 i = last_state_out_sync - SDLNet_Read16(&packet_temp->data[2]);
if (i > 0 && i < NET_PACKET_QUEUE)
{
if (packet_state_out[i])
{
if (!SDLNet_UDP_Send(socket, 0, packet_state_out[i]))
{
printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
return -1;
}
}
}
}
break;
default:
fprintf(stderr, "warning: bad packet %d received\n", SDLNet_Read16(&packet_temp->data[0]));
return 0;
break;
}
return 1;
}
break;
}
return 0;
}
// send acknowledgement packet
int network_acknowledge( Uint16 sync )
{
SDLNet_Write16(PACKET_ACKNOWLEDGE, &packet_out_temp->data[0]);
SDLNet_Write16(sync, &packet_out_temp->data[2]);
network_send_no_ack(4);
return 0;
}
// discard working packet, now processing next packet in queue
bool network_update( void )
{
if (packet_in[0])
{
packets_shift_up(packet_in, NET_PACKET_QUEUE);
queue_in_sync++;
return true;
}
return false;
}
// has opponent gotten all the packets we've sent?
bool network_is_sync( void )
{
return (queue_out_sync - last_ack_sync == 1);
}
// activity lately?
bool network_is_alive( void )
{
return (SDL_GetTicks() - last_in_tick < NET_TIME_OUT || SDL_GetTicks() - last_state_in_tick < NET_TIME_OUT);
}
// prepare new state for sending
void network_state_prepare( void )
{
if (packet_state_out[0])
{
fprintf(stderr, "warning: state packet overwritten (previous packet remains unsent)\n");
} else {
packet_state_out[0] = SDLNet_AllocPacket(NET_PACKET_SIZE);
packet_state_out[0]->len = 28;
}
SDLNet_Write16(PACKET_STATE, &packet_state_out[0]->data[0]);
SDLNet_Write16(last_state_out_sync, &packet_state_out[0]->data[2]);
memset(&packet_state_out[0]->data[4], 0, 28 - 4);
}
// send state packet, xor packet if applicable
int network_state_send( void )
{
if (!SDLNet_UDP_Send(socket, 0, packet_state_out[0]))
{
printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
return -1;
}
// send xor of last network_delay packets
if (network_delay > 1 && (last_state_out_sync + 1) % network_delay == 0 && packet_state_out[network_delay - 1] != NULL)
{
packet_copy(packet_temp, packet_state_out[0]);
SDLNet_Write16(PACKET_STATE_XOR, &packet_temp->data[0]);
for (int i = 1; i < network_delay; i++)
for (int j = 4; j < packet_temp->len; j++)
packet_temp->data[j] ^= packet_state_out[i]->data[j];
if (!SDLNet_UDP_Send(socket, 0, packet_temp))
{
printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
return -1;
}
}
packets_shift_down(packet_state_out, NET_PACKET_QUEUE);
last_state_out_sync++;
return 0;
}
// receive state packet, wait until received
bool network_state_update( void )
{
if (network_state_is_reset())
{
return 0;
} else {
packets_shift_up(packet_state_in, NET_PACKET_QUEUE);
packets_shift_up(packet_state_in_xor, NET_PACKET_QUEUE);
last_state_in_sync++;
// current xor packet index
int x = network_delay - (last_state_in_sync - 1) % network_delay - 1;
// loop until needed packet is available
while (!packet_state_in[0])
{
// xor the packet from thin air, if possible
if (packet_state_in_xor[x] && SDLNet_Read16(&packet_state_in_xor[x]->data[0]) == PACKET_STATE_XOR)
{
// check for all other required packets
bool okay = true;
for (int i = 1; i <= x; i++)
{
if (packet_state_in[i] == NULL)
{
okay = false;
break;
}
}
if (okay)
{
packet_state_in[0] = SDLNet_AllocPacket(NET_PACKET_SIZE);
packet_copy(packet_state_in[0], packet_state_in_xor[x]);
for (int i = 1; i <= x; i++)
for (int j = 4; j < packet_state_in[0]->len; j++)
packet_state_in[0]->data[j] ^= packet_state_in[i]->data[j];
break;
}
}
static Uint32 resend_tick = 0;
if (SDL_GetTicks() - last_state_in_tick > NET_RESEND && SDL_GetTicks() - resend_tick > NET_RESEND)
{
SDLNet_Write16(PACKET_STATE_RESEND, &packet_out_temp->data[0]);
SDLNet_Write16(last_state_in_sync - 1, &packet_out_temp->data[2]);
network_send_no_ack(4); // PACKET_RESEND
resend_tick = SDL_GetTicks();
}
if (network_check() == 0)
SDL_Delay(1);
}
if (network_delay > 1)
{
// process the current in packet against the xor queue
if (packet_state_in_xor[x] == NULL)
{
packet_state_in_xor[x] = SDLNet_AllocPacket(NET_PACKET_SIZE);
packet_copy(packet_state_in_xor[x], packet_state_in[0]);
packet_state_in_xor[x]->status = 0;
} else {
for (int j = 4; j < packet_state_in_xor[x]->len; j++)
packet_state_in_xor[x]->data[j] ^= packet_state_in[0]->data[j];
}
}
last_state_in_tick = SDL_GetTicks();
}
return 1;
}
// ignore first network_delay states of level
bool network_state_is_reset( void )
{
return (last_state_out_sync < network_delay);
}
// reset queues for new level
void network_state_reset( void )
{
last_state_in_sync = last_state_out_sync = 0;
for (int i = 0; i < NET_PACKET_QUEUE; i++)
{
if (packet_state_in[i])
{
SDLNet_FreePacket(packet_state_in[i]);
packet_state_in[i] = NULL;
}
}
for (int i = 0; i < NET_PACKET_QUEUE; i++)
{
if (packet_state_in_xor[i])
{
SDLNet_FreePacket(packet_state_in_xor[i]);
packet_state_in_xor[i] = NULL;
}
}
for (int i = 0; i < NET_PACKET_QUEUE; i++)
{
if (packet_state_out[i])
{
SDLNet_FreePacket(packet_state_out[i]);
packet_state_out[i] = NULL;
}
}
last_state_in_tick = SDL_GetTicks();
}
// attempt to punch through firewall by firing off UDP packets at the opponent
// exchange game information
int network_connect( void )
{
SDLNet_ResolveHost(&ip, network_opponent_host, network_opponent_port);
SDLNet_UDP_Bind(socket, 0, &ip);
Uint16 episodes = 0, episodes_local = 0;
assert(EPISODE_MAX <= 16);
for (int i = EPISODE_MAX - 1; i >= 0; i--)
{
episodes <<= 1;
episodes |= (episodeAvail[i] != 0);
}
episodes_local = episodes;
assert(NET_PACKET_SIZE - 12 >= 20 + 1);
if (strlen(network_player_name) > 20)
network_player_name[20] = '\0';
connect_reset:
network_prepare(PACKET_CONNECT);
SDLNet_Write16(NET_VERSION, &packet_out_temp->data[4]);
SDLNet_Write16(network_delay, &packet_out_temp->data[6]);
SDLNet_Write16(episodes_local, &packet_out_temp->data[8]);
SDLNet_Write16(thisPlayerNum, &packet_out_temp->data[10]);
strcpy((char *)&packet_out_temp->data[12], network_player_name);
network_send(12 + strlen(network_player_name) + 1); // PACKET_CONNECT
// until opponent sends connect packet
while (true)
{
push_joysticks_as_keyboard();
service_SDL_events(false);
if (newkey && lastkey_sym == SDLK_ESCAPE)
network_tyrian_halt(0, false);
// never timeout
last_in_tick = SDL_GetTicks();
if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_CONNECT)
break;
network_update();
network_check();
SDL_Delay(16);
}
connect_again:
if (SDLNet_Read16(&packet_in[0]->data[4]) != NET_VERSION)
{
fprintf(stderr, "error: network version did not match opponent's\n");
network_tyrian_halt(4, true);
}
if (SDLNet_Read16(&packet_in[0]->data[6]) != network_delay)
{
fprintf(stderr, "error: network delay did not match opponent's\n");
network_tyrian_halt(5, true);
}
if (SDLNet_Read16(&packet_in[0]->data[10]) == thisPlayerNum)
{
fprintf(stderr, "error: player number conflicts with opponent's\n");
network_tyrian_halt(6, true);
}
episodes = SDLNet_Read16(&packet_in[0]->data[8]);
for (int i = 0; i < EPISODE_MAX; i++) {
episodeAvail[i] &= (episodes & 1);
episodes >>= 1;
}
network_opponent_name = (char *)malloc(packet_in[0]->len - 12 + 1);
strcpy(network_opponent_name, (char *)&packet_in[0]->data[12]);
network_update();
// until opponent has acknowledged
while (!network_is_sync())
{
service_SDL_events(false);
// got a duplicate packet; process it again (but why?)
if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_CONNECT)
goto connect_again;
network_check();
// maybe opponent didn't get our packet
if (SDL_GetTicks() - last_out_tick > NET_RETRY)
goto connect_reset;
SDL_Delay(16);
}
// send another packet since sometimes the network syncs without both connect packets exchanged
// there should be a better way to handle this
network_prepare(PACKET_CONNECT);
SDLNet_Write16(NET_VERSION, &packet_out_temp->data[4]);
SDLNet_Write16(network_delay, &packet_out_temp->data[6]);
SDLNet_Write16(episodes_local, &packet_out_temp->data[8]);
SDLNet_Write16(thisPlayerNum, &packet_out_temp->data[10]);
strcpy((char *)&packet_out_temp->data[12], network_player_name);
network_send(12 + strlen(network_player_name) + 1); // PACKET_CONNECT
connected = true;
return 0;
}
// something has gone wrong :(
void network_tyrian_halt( unsigned int err, bool attempt_sync )
{
const char *err_msg[] = {
"Quitting...",
"Other player quit the game.",
"Network connection was lost.",
"Network connection failed.",
"Network version mismatch.",
"Network delay mismatch.",
"Network player number conflict.",
};
quit = true;
if (err >= COUNTOF(err_msg))
err = 0;
fade_black(10);
VGAScreen = VGAScreenSeg;
JE_loadPic(VGAScreen, 2, false);
JE_dString(VGAScreen, JE_fontCenter(err_msg[err], SMALL_FONT_SHAPES), 140, err_msg[err], SMALL_FONT_SHAPES);
JE_showVGA();
fade_palette(colors, 10, 0, 255);
if (attempt_sync)
{
while (!network_is_sync() && network_is_alive())
{
service_SDL_events(false);
network_check();
SDL_Delay(16);
}
}
if (err)
{
while (!JE_anyButton())
SDL_Delay(16);
}
fade_black(10);
SDLNet_Quit();
JE_tyrianHalt(5);
}
int network_init( void )
{
printf("Initializing network...\n");
if (network_delay * 2 > NET_PACKET_QUEUE - 2)
{
fprintf(stderr, "error: network delay would overflow packet queue\n");
return -4;
}
if (SDLNet_Init() == -1)
{
fprintf(stderr, "error: SDLNet_Init: %s\n", SDLNet_GetError());
return -1;
}
socket = SDLNet_UDP_Open(network_player_port);
if (!socket)
{
fprintf(stderr, "error: SDLNet_UDP_Open: %s\n", SDLNet_GetError());
return -2;
}
packet_temp = SDLNet_AllocPacket(NET_PACKET_SIZE);
packet_out_temp = SDLNet_AllocPacket(NET_PACKET_SIZE);
if (!packet_temp || !packet_out_temp)
{
printf("SDLNet_AllocPacket: %s\n", SDLNet_GetError());
return -3;
}
net_initialized = true;
return 0;
}
void packet_copy( UDPpacket *dst, UDPpacket *src )
{
void *temp = dst->data;
memcpy(dst, src, sizeof(*dst));
dst->data = (Uint8*)temp;
memcpy(dst->data, src->data, src->len);
}
void packets_shift_up( UDPpacket **packet, int max_packets )
{
if (packet[0])
{
SDLNet_FreePacket(packet[0]);
}
for (int i = 0; i < max_packets - 1; i++)
{
packet[i] = packet[i + 1];
}
packet[max_packets - 1] = NULL;
}
void packets_shift_down( UDPpacket **packet, int max_packets )
{
if (packet[max_packets - 1])
{
SDLNet_FreePacket(packet[max_packets - 1]);
}
for (int i = max_packets - 1; i > 0; i--)
{
packet[i] = packet[i - 1];
}
packet[0] = NULL;
}
void JE_clearSpecialRequests( void )
{
pauseRequest = false;
inGameMenuRequest = false;
skipLevelRequest = false;
helpRequest = false;
nortShipRequest = false;
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,100 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef NETWORK_H
#define NETWORK_H
#include "opentyr.h"
#include "SDL.h"
#include "SDL_net.h"
#define PACKET_ACKNOWLEDGE 0x00 //
#define PACKET_KEEP_ALIVE 0x01 //
#define PACKET_CONNECT 0x10 // version, delay, episodes, player_number, name
#define PACKET_DETAILS 0x11 // episode, difficulty
#define PACKET_QUIT 0x20 //
#define PACKET_WAITING 0x21 //
#define PACKET_BUSY 0x22 //
#define PACKET_GAME_QUIT 0x30 //
#define PACKET_GAME_PAUSE 0x31 //
#define PACKET_GAME_MENU 0x32 //
#define PACKET_STATE_RESEND 0x40 // state_id
#define PACKET_STATE 0x41 // <state> (not acknowledged)
#define PACKET_STATE_XOR 0x42 // <xor state> (not acknowledged)
extern bool isNetworkGame;
extern int network_delay;
extern char *network_opponent_host;
extern Uint16 network_player_port, network_opponent_port;
extern char *network_player_name, *network_opponent_name;
extern UDPpacket *packet_out_temp;
extern UDPpacket *packet_in[], *packet_out[],
*packet_state_in[], *packet_state_out[];
extern uint thisPlayerNum;
extern JE_boolean haltGame;
extern JE_boolean moveOk;
extern JE_boolean pauseRequest, skipLevelRequest, helpRequest, nortShipRequest;
extern JE_boolean yourInGameMenuRequest, inGameMenuRequest;
extern JE_boolean portConfigChange, portConfigDone;
void network_prepare( Uint16 type );
bool network_send( int len );
bool network_send_no_ack( int len );
int network_check( void );
int network_acknowledge( Uint16 sync );
bool network_update( void );
bool network_is_sync( void );
bool network_is_alive( void );
void network_state_prepare( void );
int network_state_send( void );
bool network_state_update( void );
bool network_state_is_reset( void );
void network_state_reset( void );
int network_connect( void );
void network_tyrian_halt( unsigned int err, bool attempt_sync );
int network_init( void );
void packet_copy( UDPpacket *dst, UDPpacket *src );
void packets_shift_up( UDPpacket **packet, int max_packets );
void packets_shift_down( UDPpacket **packet, int max_packets );
void JE_clearSpecialRequests( void );
#define NETWORK_KEEP_ALIVE() \
if (isNetworkGame) \
network_check();
#endif /* NETWORK_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,225 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "file.h"
#include "joystick.h"
#include "keyboard.h"
#include "loudness.h"
#include "musmast.h"
#include "nortsong.h"
#include "opentyr.h"
#include "params.h"
#include "sndmast.h"
#include "vga256d.h"
#include "SDL.h"
Uint32 target, target2;
JE_boolean notYetLoadedSound = true;
JE_word frameCount, frameCount2, frameCountMax;
JE_byte *digiFx[SAMPLE_COUNT] = { NULL }; /* [1..soundnum + 9] */
JE_word fxSize[SAMPLE_COUNT]; /* [1..soundnum + 9] */
JE_word tyrMusicVolume, fxVolume;
JE_word fxPlayVol;
JE_word tempVolume;
JE_word speed; /* JE: holds timer speed for 70Hz */
float jasondelay = 1000.0f / (1193180.0f / 0x4300);
void setdelay( JE_byte delay )
{
target = (delay * 16) + SDL_GetTicks();
}
void setjasondelay( int delay )
{
target = SDL_GetTicks() + delay * jasondelay;
}
void setjasondelay2( int delay )
{
target2 = SDL_GetTicks() + delay * jasondelay;
}
int delaycount( void )
{
return (SDL_GetTicks() < target ? target - SDL_GetTicks() : 0);
}
int delaycount2( void )
{
return (SDL_GetTicks() < target2 ? target2 - SDL_GetTicks() : 0);
}
void wait_delay( void )
{
Sint32 delay = target - SDL_GetTicks();
if (delay > 0)
SDL_Delay(delay);
}
void service_wait_delay( void )
{
while (SDL_GetTicks() < target)
{
SDL_Delay(SDL_GetTicks() - target > SDL_POLL_INTERVAL ? SDL_POLL_INTERVAL : SDL_GetTicks() - target);
service_SDL_events(false);
}
}
void wait_delayorinput( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick )
{
service_SDL_events(true);
while (SDL_GetTicks() < target && !((keyboard && keydown) || (mouse && mousedown) || (joystick && joydown)))
{
SDL_Delay(SDL_GetTicks() - target > SDL_POLL_INTERVAL ? SDL_POLL_INTERVAL : SDL_GetTicks() - target);
push_joysticks_as_keyboard();
service_SDL_events(false);
}
}
void JE_loadSndFile( const char *effects_sndfile, const char *voices_sndfile )
{
JE_byte y, z;
JE_word x;
JE_longint templ;
JE_longint sndPos[2][SAMPLE_COUNT + 1];
JE_word sndNum;
FILE *fi;
/* SYN: Loading offsets into TYRIAN.SND */
fi = dir_fopen_die(data_dir(), effects_sndfile, "rb");
efread(&sndNum, sizeof(sndNum), 1, fi);
for (x = 0; x < sndNum; x++)
{
efread(&sndPos[0][x], sizeof(sndPos[0][x]), 1, fi);
}
fseek(fi, 0, SEEK_END);
sndPos[1][sndNum] = ftell(fi); /* Store file size */
for (z = 0; z < sndNum; z++)
{
fseek(fi, sndPos[0][z], SEEK_SET);
fxSize[z] = (sndPos[0][z+1] - sndPos[0][z]); /* Store sample sizes */
free(digiFx[z]);
digiFx[z] = (JE_byte*)malloc(fxSize[z]);
efread(digiFx[z], 1, fxSize[z], fi); /* JE: Load sample to buffer */
}
fclose(fi);
/* SYN: Loading offsets into VOICES.SND */
fi = dir_fopen_die(data_dir(), voices_sndfile, "rb");
efread(&sndNum, sizeof(sndNum), 1, fi);
for (x = 0; x < sndNum; x++)
{
efread(&sndPos[1][x], sizeof(sndPos[1][x]), 1, fi);
}
fseek(fi, 0, SEEK_END);
sndPos[1][sndNum] = ftell(fi); /* Store file size */
z = SAMPLE_COUNT - 9;
for (y = 0; y < sndNum; y++)
{
fseek(fi, sndPos[1][y], SEEK_SET);
templ = (sndPos[1][y+1] - sndPos[1][y]) - 100; /* SYN: I'm not entirely sure what's going on here. */
if (templ < 1) templ = 1;
fxSize[z + y] = templ; /* Store sample sizes */
digiFx[z + y] = (JE_byte*)malloc(fxSize[z + y]);
efread(digiFx[z + y], 1, fxSize[z + y], fi); /* JE: Load sample to buffer */
}
fclose(fi);
notYetLoadedSound = false;
}
void JE_playSampleNum( JE_byte samplenum )
{
JE_multiSamplePlay(digiFx[samplenum-1], fxSize[samplenum-1], 0, fxPlayVol);
}
void JE_calcFXVol( void ) // TODO: not sure *exactly* what this does
{
fxPlayVol = (fxVolume - 1) >> 5;
}
void JE_setTimerInt( void )
{
jasondelay = 1000.0f / (1193180.0f / speed);
}
void JE_resetTimerInt( void )
{
jasondelay = 1000.0f / (1193180.0f / 0x4300);
}
void JE_changeVolume( JE_word *music, int music_delta, JE_word *sample, int sample_delta )
{
int music_temp = *music + music_delta,
sample_temp = *sample + sample_delta;
if (music_delta)
{
if (music_temp > 255)
{
music_temp = 255;
JE_playSampleNum(S_CLINK);
}
else if (music_temp < 0)
{
music_temp = 0;
JE_playSampleNum(S_CLINK);
}
}
if (sample_delta)
{
if (sample_temp > 255)
{
sample_temp = 255;
JE_playSampleNum(S_CLINK);
}
else if (sample_temp < 0)
{
sample_temp = 0;
JE_playSampleNum(S_CLINK);
}
}
*music = music_temp;
*sample = sample_temp;
JE_calcFXVol();
set_volume(*music, *sample);
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,65 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef NORTSONG_H
#define NORTSONG_H
#include "opentyr.h"
#include "musmast.h"
#include "sndmast.h"
#include "SDL.h"
extern Uint32 target, target2;
extern JE_word frameCount, frameCount2, frameCountMax;
extern JE_byte *digiFx[SAMPLE_COUNT];
extern JE_word fxSize[SAMPLE_COUNT];
extern JE_word tyrMusicVolume, fxVolume;
extern JE_word fxPlayVol;
extern JE_word tempVolume;
extern JE_word speed;
extern float jasondelay;
void setdelay( JE_byte delay );
void setjasondelay( int delay );
void setjasondelay2( int delay );
int delaycount( void );
int delaycount2( void );
void wait_delay( void );
void service_wait_delay( void );
void wait_delayorinput( JE_boolean keyboard, JE_boolean mouse, JE_boolean joystick );
void JE_resetTimerInt( void );
void JE_setTimerInt( void );
void JE_calcFXVol( void );
void JE_changeVolume( JE_word *music, int music_delta, JE_word *sample, int sample_delta );
void JE_loadSndFile( const char *effects_sndfile, const char *voices_sndfile );
void JE_playSampleNum( JE_byte samplenum );
#endif /* NORTSONG_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,88 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "file.h"
#include "joystick.h"
#include "keyboard.h"
#include "nortvars.h"
#include "opentyr.h"
#include "vga256d.h"
#include "video.h"
#include <assert.h>
#include <ctype.h>
JE_boolean inputDetected;
JE_boolean JE_anyButton( void )
{
poll_joysticks();
service_SDL_events(true);
return newkey || mousedown || joydown;
}
void JE_dBar3( SDL_Surface *surface, JE_integer x, JE_integer y, JE_integer num, JE_integer col )
{
JE_byte z;
JE_byte zWait = 2;
col += 2;
for (z = 0; z <= num; z++)
{
JE_rectangle(surface, x, y - 1, x + 8, y, col); /* <MXD> SEGa000 */
if (zWait > 0)
{
zWait--;
} else {
col++;
zWait = 1;
}
y -= 2;
}
}
void JE_barDrawShadow( SDL_Surface *surface, JE_word x, JE_word y, JE_word res, JE_word col, JE_word amt, JE_word xsize, JE_word ysize )
{
xsize--;
ysize--;
for (int z = 1; z <= amt / res; z++)
{
JE_barShade(surface, x+2, y+2, x+xsize+2, y+ysize+2);
fill_rectangle_xy(surface, x, y, x+xsize, y+ysize, col+12);
fill_rectangle_xy(surface, x, y, x+xsize, y, col+13);
JE_pix(surface, x, y, col+15);
fill_rectangle_xy(surface, x, y+ysize, x+xsize, y+ysize, col+11);
x += xsize + 2;
}
amt %= res;
if (amt > 0)
{
JE_barShade(surface, x+2, y+2, x+xsize+2, y+ysize+2);
fill_rectangle_xy(surface, x,y, x+xsize, y+ysize, col+(12 / res * amt));
}
}
void JE_wipeKey( void )
{
// /!\ Doesn't seems to affect anything.
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,36 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef NORTVARS_H
#define NORTVARS_H
#include "opentyr.h"
extern JE_boolean inputDetected;
JE_boolean JE_buttonPressed( void );
JE_boolean JE_anyButton( void );
void JE_dBar3( SDL_Surface *surface, JE_integer x, JE_integer y, JE_integer num, JE_integer col );
void JE_barDrawShadow( SDL_Surface *surface, JE_word x, JE_word y, JE_word res, JE_word col, JE_word amt, JE_word xsize, JE_word ysize );
void JE_wipeKey( void );
#endif /* NORTVARS_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,349 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "config.h"
#include "destruct.h"
#include "editship.h"
#include "episodes.h"
#include "file.h"
#include "font.h"
#include "helptext.h"
#include "hg_revision.h"
#include "joystick.h"
#include "jukebox.h"
#include "keyboard.h"
#include "loudness.h"
#include "mainint.h"
#include "mtrand.h"
#include "musmast.h"
#include "network.h"
#include "nortsong.h"
#include "opentyr.h"
#include "params.h"
#include "picload.h"
#include "scroller.h"
#include "setup.h"
#include "sprite.h"
#include "tyrian2.h"
#include "xmas.h"
#include "varz.h"
#include "vga256d.h"
#include "video.h"
#include "video_scale.h"
#include "SDL.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
const char *opentyrian_str = "OpenTyrian",
*opentyrian_version = "Classic (" HG_REV ")";
const char *opentyrian_menu_items[] =
{
"About OpenTyrian",
"Toggle Fullscreen",
"Scaler: None",
/* "Play Destruct", */
"Jukebox",
"Return to Main Menu"
};
/* zero-terminated strncpy */
char *strnztcpy( char *to, const char *from, size_t count )
{
to[count] = '\0';
return strncpy(to, from, count);
}
void opentyrian_menu( void )
{
int sel = 0;
const int maxSel = COUNTOF(opentyrian_menu_items) - 1;
bool quit = false, fade_in = true;
uint temp_scaler = scaler;
fade_black(10);
JE_loadPic(VGAScreen, 13, false);
draw_font_hv(VGAScreen, VGAScreen->w / 2, 5, opentyrian_str, large_font, centered, 15, -3);
memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
JE_showVGA();
play_song(36); // A Field for Mag
do
{
memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
for (int i = 0; i <= maxSel; i++)
{
const char *text = opentyrian_menu_items[i];
char buffer[100];
if (i == 2) /* Scaler */
{
snprintf(buffer, sizeof(buffer), "Scaler: %s", scalers[temp_scaler].name);
text = buffer;
}
draw_font_hv_shadow(VGAScreen, VGAScreen->w / 2, (i != maxSel) ? i * 16 + 32 : 118, text, normal_font, centered, 15, (i != sel) ? -4 : -2, false, 2);
}
JE_showVGA();
if (fade_in)
{
fade_in = false;
fade_palette(colors, 20, 0, 255);
wait_noinput(true, false, false);
}
tempW = 0;
JE_textMenuWait(&tempW, false);
if (newkey)
{
switch (lastkey_sym)
{
case SDLK_UP:
sel--;
if (sel < 0)
{
sel = maxSel;
}
JE_playSampleNum(S_CURSOR);
break;
case SDLK_DOWN:
sel++;
if (sel > maxSel)
{
sel = 0;
}
JE_playSampleNum(S_CURSOR);
break;
case SDLK_LEFT:
if (sel == 2)
{
do
{
if (temp_scaler == 0)
temp_scaler = scalers_count;
temp_scaler--;
}
while (!can_init_scaler(temp_scaler, fullscreen_enabled));
JE_playSampleNum(S_CURSOR);
}
break;
case SDLK_RIGHT:
if (sel == 2)
{
do
{
temp_scaler++;
if (temp_scaler == scalers_count)
temp_scaler = 0;
}
while (!can_init_scaler(temp_scaler, fullscreen_enabled));
JE_playSampleNum(S_CURSOR);
}
break;
case SDLK_RETURN:
switch (sel)
{
case 0: /* About */
JE_playSampleNum(S_SELECT);
scroller_sine(about_text);
memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
JE_showVGA();
fade_in = true;
break;
case 1: /* Fullscreen */
JE_playSampleNum(S_SELECT);
if (!init_scaler(scaler, !fullscreen_enabled) && // try new fullscreen state
!init_any_scaler(!fullscreen_enabled) && // try any scaler in new fullscreen state
!init_scaler(scaler, fullscreen_enabled)) // revert on fail
{
exit(EXIT_FAILURE);
}
set_palette(colors, 0, 255); // for switching between 8 bpp scalers
break;
case 2: /* Scaler */
JE_playSampleNum(S_SELECT);
if (scaler != temp_scaler)
{
if (!init_scaler(temp_scaler, fullscreen_enabled) && // try new scaler
!init_scaler(temp_scaler, !fullscreen_enabled) && // try other fullscreen state
!init_scaler(scaler, fullscreen_enabled)) // revert on fail
{
exit(EXIT_FAILURE);
}
set_palette(colors, 0, 255); // for switching between 8 bpp scalers
}
break;
case 3: /* Jukebox */
JE_playSampleNum(S_SELECT);
fade_black(10);
jukebox();
memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
JE_showVGA();
fade_in = true;
break;
default: /* Return to main menu */
quit = true;
JE_playSampleNum(S_SPRING);
break;
}
break;
case SDLK_ESCAPE:
quit = true;
JE_playSampleNum(S_SPRING);
break;
default:
break;
}
}
} while (!quit);
}
int main( int argc, char *argv[] )
{
mt_srand(time(NULL));
printf("\nWelcome to... >> %s %s <<\n\n", opentyrian_str, opentyrian_version);
printf("Copyright (C) 2007-2009 The OpenTyrian Development Team\n\n");
printf("This program comes with ABSOLUTELY NO WARRANTY.\n");
printf("This is free software, and you are welcome to redistribute it\n");
printf("under certain conditions. See the file GPL.txt for details.\n\n");
if (SDL_Init(0))
{
printf("Failed to initialize SDL: %s\n", SDL_GetError());
return -1;
}
JE_loadConfiguration();
xmas = xmas_time(); // arg handler may override
JE_paramCheck(argc, argv);
JE_scanForEpisodes();
init_video();
init_keyboard();
init_joysticks();
printf("assuming mouse detected\n"); // SDL can't tell us if there isn't one
if (xmas && (!dir_file_exists(data_dir(), "tyrianc.shp") || !dir_file_exists(data_dir(), "voicesc.snd")))
{
xmas = false;
fprintf(stderr, "warning: Christmas is missing.\n");
}
JE_loadPals();
JE_loadMainShapeTables(xmas ? "tyrianc.shp" : "tyrian.shp");
if (xmas && !xmas_prompt())
{
xmas = false;
free_main_shape_tables();
JE_loadMainShapeTables("tyrian.shp");
}
/* Default Options */
youAreCheating = false;
smoothScroll = true;
loadDestruct = false;
if (!audio_disabled)
{
printf("initializing SDL audio...\n");
init_audio();
load_music();
JE_loadSndFile("tyrian.snd", xmas ? "voicesc.snd" : "voices.snd");
}
else
{
printf("audio disabled\n");
}
if (record_demo)
printf("demo recording enabled (input limited to keyboard)\n");
JE_loadExtraShapes(); /*Editship*/
JE_loadHelpText();
/*debuginfo("Help text complete");*/
if (isNetworkGame)
{
if (network_init())
{
network_tyrian_halt(3, false);
}
}
#ifdef NDEBUG
if (!isNetworkGame)
intro_logos();
#endif
for (; ; )
{
JE_initPlayerData();
JE_sortHighScores();
if (JE_titleScreen(true))
break; // user quit from title screen
if (loadDestruct)
{
JE_destructGame();
loadDestruct = false;
}
else
{
JE_main();
}
}
JE_tyrianHalt(0);
return 0;
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,61 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef OPENTYR_H
#define OPENTYR_H
#include "SDL_types.h"
#include <math.h>
#include <stdbool.h>
#define COUNTOF(x) ((unsigned)(sizeof(x) / sizeof *(x))) // use only on arrays!
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#ifndef M_PI
#define M_PI 3.14159265358979323846 // pi
#endif
#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923 // pi/2
#endif
#ifndef M_PI_4
#define M_PI_4 0.78539816339744830962 // pi/4
#endif
typedef unsigned int uint;
typedef unsigned long ulong;
// Pascal types, yuck.
typedef Sint32 JE_longint;
typedef Sint16 JE_integer;
typedef Sint8 JE_shortint;
typedef Uint16 JE_word;
typedef Uint8 JE_byte;
typedef bool JE_boolean;
typedef char JE_char;
typedef float JE_real;
char *strnztcpy( char *to, const char *from, size_t count );
extern const char *opentyrian_str, *opentyrian_version;
void opentyrian_menu( void );
#endif /* OPENTYR_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,214 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "file.h"
#include "nortsong.h"
#include "opentyr.h"
#include "palette.h"
#include "video.h"
#include <assert.h>
static Uint32 rgb_to_yuv( int r, int g, int b );
Palette palettes[23];
int palette_count;
static Palette palette;
Uint32 rgb_palette[256], yuv_palette[256];
Palette colors;
void JE_loadPals( void )
{
FILE *f = dir_fopen_die(data_dir(), "palette.dat", "rb");
palette_count = ftell_eof(f) / (256 * 3);
assert(palette_count == 23); // game assumes 23 palettes
for (int p = 0; p < palette_count; ++p)
{
for (int i = 0; i < 256; ++i)
{
palettes[p][i].r = getc(f) << 2;
palettes[p][i].g = getc(f) << 2;
palettes[p][i].b = getc(f) << 2;
}
}
fclose(f);
}
void set_palette( Palette colors, unsigned int first_color, unsigned int last_color )
{
SDL_Surface *const surface = SDL_GetVideoSurface();
const uint bpp = surface->format->BitsPerPixel;
for (uint i = first_color; i <= last_color; ++i)
{
palette[i] = colors[i];
if (bpp != 8)
{
rgb_palette[i] = SDL_MapRGB(surface->format, palette[i].r, palette[i].g, palette[i].b);
yuv_palette[i] = rgb_to_yuv(palette[i].r, palette[i].g, palette[i].b);
}
}
if (bpp == 8)
SDL_SetColors(surface, palette, first_color, last_color - first_color + 1);
}
void set_colors( SDL_Color color, unsigned int first_color, unsigned int last_color )
{
SDL_Surface *const surface = SDL_GetVideoSurface();
const uint bpp = surface->format->BitsPerPixel;
for (uint i = first_color; i <= last_color; ++i)
{
palette[i] = color;
if (bpp != 8)
{
rgb_palette[i] = SDL_MapRGB(surface->format, palette[i].r, palette[i].g, palette[i].b);
yuv_palette[i] = rgb_to_yuv(palette[i].r, palette[i].g, palette[i].b);
}
}
if (bpp == 8)
SDL_SetColors(surface, palette, first_color, last_color - first_color + 1);
}
void init_step_fade_palette( int diff[256][3], Palette colors, unsigned int first_color, unsigned int last_color )
{
for (unsigned int i = first_color; i <= last_color; i++)
{
diff[i][0] = (int)colors[i].r - palette[i].r;
diff[i][1] = (int)colors[i].g - palette[i].g;
diff[i][2] = (int)colors[i].b - palette[i].b;
}
}
void init_step_fade_solid( int diff[256][3], SDL_Color color, unsigned int first_color, unsigned int last_color )
{
for (unsigned int i = first_color; i <= last_color; i++)
{
diff[i][0] = (int)color.r - palette[i].r;
diff[i][1] = (int)color.g - palette[i].g;
diff[i][2] = (int)color.b - palette[i].b;
}
}
void step_fade_palette( int diff[256][3], int steps, unsigned int first_color, unsigned int last_color )
{
assert(steps > 0);
SDL_Surface *const surface = SDL_GetVideoSurface();
const uint bpp = surface->format->BitsPerPixel;
for (unsigned int i = first_color; i <= last_color; i++)
{
int delta[3] = { diff[i][0] / steps, diff[i][1] / steps, diff[i][2] / steps };
diff[i][0] -= delta[0];
diff[i][1] -= delta[1];
diff[i][2] -= delta[2];
palette[i].r += delta[0];
palette[i].g += delta[1];
palette[i].b += delta[2];
if (bpp != 8)
{
rgb_palette[i] = SDL_MapRGB(surface->format, palette[i].r, palette[i].g, palette[i].b);
yuv_palette[i] = rgb_to_yuv(palette[i].r, palette[i].g, palette[i].b);
}
}
if (bpp == 8)
SDL_SetColors(surface, palette, 0, 256);
}
void fade_palette( Palette colors, int steps, unsigned int first_color, unsigned int last_color )
{
assert(steps > 0);
SDL_Surface *const surface = SDL_GetVideoSurface();
const uint bpp = surface->format->BitsPerPixel;
static int diff[256][3];
init_step_fade_palette(diff, colors, first_color, last_color);
for (; steps > 0; steps--)
{
setdelay(1);
step_fade_palette(diff, steps, first_color, last_color);
if (bpp != 8)
JE_showVGA();
wait_delay();
}
}
void fade_solid( SDL_Color color, int steps, unsigned int first_color, unsigned int last_color )
{
assert(steps > 0);
SDL_Surface *const surface = SDL_GetVideoSurface();
const uint bpp = surface->format->BitsPerPixel;
static int diff[256][3];
init_step_fade_solid(diff, color, first_color, last_color);
for (; steps > 0; steps--)
{
setdelay(1);
step_fade_palette(diff, steps, first_color, last_color);
if (bpp != 8)
JE_showVGA();
wait_delay();
}
}
void fade_black( int steps )
{
SDL_Color black = { 0, 0, 0 };
fade_solid(black, steps, 0, 255);
}
void fade_white( int steps )
{
SDL_Color white = { 255, 255, 255 };
fade_solid(white, steps, 0, 255);
}
static Uint32 rgb_to_yuv( int r, int g, int b )
{
int y = (r + g + b) >> 2,
u = 128 + ((r - b) >> 2),
v = 128 + ((-r + 2 * g - b) >> 3);
return (y << 16) + (u << 8) + v;
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,52 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef PALETTE_H
#define PALETTE_H
#include "opentyr.h"
#include "SDL.h"
typedef SDL_Color Palette[256];
extern Palette palettes[];
extern int palette_count;
extern Uint32 rgb_palette[256], yuv_palette[256];
extern Palette colors; // TODO: get rid of this
void JE_loadPals( void );
void set_palette( Palette colors, unsigned int first_color, unsigned int last_color );
void set_colors( SDL_Color color, unsigned int first_color, unsigned int last_color );
void init_step_fade_palette( int diff[256][3], Palette colors, unsigned int first_color, unsigned int last_color );
void init_step_fade_solid( int diff[256][3], SDL_Color color, unsigned int first_color, unsigned int last_color );
void step_fade_palette( int diff[256][3], int steps, unsigned int first_color, unsigned int last_color );
void fade_palette( Palette colors, int steps, unsigned int first_color, unsigned int last_color );
void fade_solid( SDL_Color color, int steps, unsigned int first_color, unsigned int last_color );
void fade_black( int steps );
void fade_white( int steps );
#endif /* PALETTE_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,268 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "arg_parse.h"
#include "file.h"
#include "joystick.h"
#include "loudness.h"
#include "network.h"
#include "opentyr.h"
#include "params.h"
#include "varz.h"
#include "xmas.h"
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdint.h>
#include <string.h>
JE_boolean richMode = false, constantPlay = false, constantDie = false;
/* YKS: Note: LOOT cheat had non letters removed. */
const char pars[][9] = {
"LOOT", "RECORD", "NOJOY", "CONSTANT", "DEATH", "NOSOUND", "NOXMAS", "YESXMAS"
};
void JE_paramCheck( int argc, char *argv[] )
{
const Options options[] =
{
{ 'h', 'h', "help", false },
{ 's', 's', "no-sound", false },
{ 'j', 'j', "no-joystick", false },
{ 'x', 'x', "no-xmas", false },
{ 't', 't', "data", true },
{ 'n', 'n', "net", true },
{ 256, 0, "net-player-name", true }, // TODO: no short codes because there should
{ 257, 0, "net-player-number", true }, // be a menu for entering these in the future
{ 'p', 'p', "net-port", true },
{ 'd', 'd', "net-delay", true },
{ 'X', 'X', "xmas", false },
{ 'c', 'c', "constant", false },
{ 'k', 'k', "death", false },
{ 'r', 'r', "record", false },
{ 'l', 'l', "loot", false },
{ 0, 0, NULL, false}
};
Option option = { 0, NULL, 0 };
for (; ; )
{
option = parse_args(argc, (const char **)argv, options);
if (option.value == NOT_OPTION)
break;
switch (option.value)
{
case INVALID_OPTION:
case AMBIGUOUS_OPTION:
case OPTION_MISSING_ARG:
fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]);
exit(EXIT_FAILURE);
break;
case 'h':
printf("Usage: %s [OPTION...]\n\n"
"Options:\n"
" -h, --help Show help about options\n\n"
" -s, --no-sound Disable audio\n"
" -j, --no-joystick Disable joystick/gamepad input\n"
" -x, --no-xmas Disable Christmas mode\n\n"
" -t, --data=DIR Set Tyrian data directory\n\n"
" -n, --net=HOST[:PORT] Start a networked game\n"
" --net-player-name=NAME Sets local player name in a networked game\n"
" --net-player-number=NUMBER Sets local player number in a networked game\n"
" (1 or 2)\n"
" -p, --net-port=PORT Local port to bind (default is 1333)\n"
" -d, --net-delay=FRAMES Set lag-compensation delay (default is 1)\n", argv[0]);
exit(0);
break;
case 's':
// Disables sound/music usage
audio_disabled = true;
break;
case 'j':
// Disables joystick detection
ignore_joystick = true;
break;
case 'x':
xmas = false;
break;
// set custom Tyrian data directory
case 't':
custom_data_dir = option.arg;
break;
case 'n':
{
isNetworkGame = true;
intptr_t temp = (intptr_t)strchr(option.arg, ':');
if (temp)
{
temp -= (intptr_t)option.arg;
int temp_port = atoi(&option.arg[temp + 1]);
if (temp_port > 0 && temp_port < 49152)
network_opponent_port = temp_port;
else
{
fprintf(stderr, "%s: error: invalid network port number\n", argv[0]);
exit(EXIT_FAILURE);
}
network_opponent_host = (char *)malloc(temp + 1);
strnztcpy(network_opponent_host, option.arg, temp);
}
else
{
network_opponent_host = (char *)malloc(strlen(option.arg) + 1);
strcpy(network_opponent_host, option.arg);
}
}
break;
case 256: // --net-player-name
network_player_name = (char *)malloc(strlen(option.arg) + 1);
strcpy(network_player_name, option.arg);
break;
case 257: // --net-player-number
{
int temp = atoi(option.arg);
if (temp >= 1 && temp <= 2)
thisPlayerNum = temp;
else
{
fprintf(stderr, "%s: error: invalid network player number\n", argv[0]);
exit(EXIT_FAILURE);
}
break;
}
case 'p':
{
int temp = atoi(option.arg);
if (temp > 0 && temp < 49152)
network_player_port = temp;
else
{
fprintf(stderr, "%s: error: invalid network port number\n", argv[0]);
exit(EXIT_FAILURE);
}
break;
}
case 'd':
{
int temp;
if (sscanf(option.arg, "%d", &temp) == 1)
network_delay = 1 + temp;
else
{
fprintf(stderr, "%s: error: invalid network delay value\n", argv[0]);
exit(EXIT_FAILURE);
}
break;
}
case 'X':
xmas = true;
break;
case 'c':
/* Constant play for testing purposes (C key activates invincibility)
This might be useful for publishers to see everything - especially
those who can't play it */
constantPlay = true;
break;
case 'k':
constantDie = true;
break;
case 'r':
record_demo = true;
break;
case 'l':
// Gives you mucho bucks
richMode = true;
break;
default:
assert(false);
break;
}
}
// legacy parameter support
for (int i = option.argn; i < argc; ++i)
{
for (uint j = 0; j < strlen(argv[i]); ++j)
argv[i][j] = toupper((unsigned char)argv[i][j]);
for (uint j = 0; j < COUNTOF(pars); ++j)
{
if (strcmp(argv[i], pars[j]) == 0)
{
switch (j)
{
case 0:
richMode = true;
break;
case 1:
record_demo = true;
break;
case 2:
ignore_joystick = true;
break;
case 3:
constantPlay = true;
break;
case 4:
constantDie = true;
break;
case 5:
audio_disabled = true;
break;
case 6:
xmas = false;
break;
case 7:
xmas = true;
break;
default:
assert(false);
break;
}
}
}
}
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,30 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef PARAMS_H
#define PARAMS_H
#include "opentyr.h"
extern JE_boolean richMode, constantPlay, constantDie;
void JE_paramCheck( int argc, char *argv[] );
#endif /* PARAMS_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,67 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "file.h"
#include "opentyr.h"
#include "palette.h"
#include "pcxload.h"
#include "video.h"
void JE_loadPCX( const char *file ) // this is only meant to load tshp2.pcx
{
Uint8 *s = (Uint8 *)VGAScreen->pixels; /* 8-bit specific */
FILE *f = dir_fopen_die(data_dir(), file, "rb");
fseek(f, -769, SEEK_END);
if (fgetc(f) == 12)
{
for (int i = 0; i < 256; i++)
{
efread(&colors[i].r, 1, 1, f);
efread(&colors[i].g, 1, 1, f);
efread(&colors[i].b, 1, 1, f);
}
}
fseek(f, 128, SEEK_SET);
for (int i = 0; i < 320 * 200; )
{
Uint8 p = fgetc(f);
if ((p & 0xc0) == 0xc0)
{
i += (p & 0x3f);
memset(s, fgetc(f), (p & 0x3f));
s += (p & 0x3f);
} else {
i++;
*s = p;
s++;
}
if (i && (i % 320 == 0))
{
s += VGAScreen->pitch - 320;
}
}
fclose(f);
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,28 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef PCXLOAD_H
#define PCXLOAD_H
#include "opentyr.h"
void JE_loadPCX( const char *file );
#endif /* PCXLOAD_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,49 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "opentyr.h"
#include "pcxmast.h"
const char *pcxfile[PCX_NUM] = /* [1..PCXnum] */
{
"INTSHPB.PCX",
"SETUP2.PCX",
"TYRPLAY.PCX",
"TYRLOG2.PCX",
"P1.PCX",
"TYRPLAY2.PCX",
"BUC4.PCX",
"GMOVR4a.PCX",
"GMOVR4b.PCX",
"EPICSKY.PCX",
"DESTRUCT.PCX",
"ECLIPSE.PCX",
"FIREPICA.PCX"
};
const JE_byte pcxpal[PCX_NUM] = /* [1..PCXnum] */
{ 0, 7, 5, 8, 10, 5, 18, 19, 19, 20, 21, 22, 5};
/*FACEMAX*/
const JE_byte facepal[12] = /* [1..12] */
{ 1, 2, 3, 4, 6, 9, 11, 12, 16, 13, 14, 15};
JE_pcxpostype pcxpos;
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,36 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef PCXMAST_H
#define PCXMAST_H
#include "opentyr.h"
#define PCX_NUM 13
typedef JE_longint JE_pcxpostype[PCX_NUM + 1]; /* [1..PCXnum + 1] */
extern const char *pcxfile[PCX_NUM]; /* [1..PCXnum] */
extern const JE_byte pcxpal[PCX_NUM]; /* [1..PCXnum] */
extern const JE_byte facepal[12]; /* [1..12] */
extern JE_pcxpostype pcxpos;
#endif /* PCXMAST_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,87 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "file.h"
#include "opentyr.h"
#include "palette.h"
#include "pcxmast.h"
#include "picload.h"
#include "video.h"
#include <string.h>
void JE_loadPic(SDL_Surface *screen, JE_byte PCXnumber, JE_boolean storepal )
{
PCXnumber--;
FILE *f = dir_fopen_die(data_dir(), "tyrian.pic", "rb");
static bool first = true;
if (first)
{
first = false;
Uint16 temp;
efread(&temp, sizeof(Uint16), 1, f);
for (int i = 0; i < PCX_NUM; i++)
{
efread(&pcxpos[i], sizeof(JE_longint), 1, f);
}
pcxpos[PCX_NUM] = ftell_eof(f);
}
unsigned int size = pcxpos[PCXnumber + 1] - pcxpos[PCXnumber];
Uint8 *buffer = (Uint8 *)malloc(size);
fseek(f, pcxpos[PCXnumber], SEEK_SET);
efread(buffer, sizeof(Uint8), size, f);
fclose(f);
Uint8 *p = buffer;
Uint8 *s; /* screen pointer, 8-bit specific */
s = (Uint8 *)screen->pixels;
for (int i = 0; i < 320 * 200; )
{
if ((*p & 0xc0) == 0xc0)
{
i += (*p & 0x3f);
memset(s, *(p + 1), (*p & 0x3f));
s += (*p & 0x3f); p += 2;
} else {
i++;
*s = *p;
s++; p++;
}
if (i && (i % 320 == 0))
{
s += screen->pitch - 320;
}
}
free(buffer);
memcpy(colors, palettes[pcxpal[PCXnumber]], sizeof(colors));
if (storepal)
set_palette(colors, 0, 255);
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,28 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef PICLOAD_H
#define PICLOAD_H
#include "opentyr.h"
void JE_loadPic(SDL_Surface *screen, JE_byte PCXnumber, JE_boolean storepal );
#endif /* PICLOAD_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,55 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "player.h"
Player player[2];
void calc_purple_balls_needed( Player *this_player )
{
static const uint purple_balls_required[12] = { 1, 1, 2, 4, 8, 12, 16, 20, 25, 30, 40, 50 };
this_player->purple_balls_needed = purple_balls_required[*this_player->lives];
}
bool power_up_weapon( Player *this_player, uint port )
{
const bool can_power_up = this_player->items.weapon[port].id != 0 && // not None
this_player->items.weapon[port].power < 11; // not at max power
if (can_power_up)
{
++this_player->items.weapon[port].power;
shotMultiPos[port] = 0; // TODO: should be part of Player structure
calc_purple_balls_needed(this_player);
}
else // cash consolation prize
{
this_player->cash += 1000;
}
return can_power_up;
}
void handle_got_purple_ball( Player *this_player )
{
if (this_player->purple_balls_needed > 1)
--this_player->purple_balls_needed;
else
power_up_weapon(this_player, this_player->is_dragonwing ? REAR_WEAPON : FRONT_WEAPON);
}

View File

@@ -0,0 +1,129 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef PLAYER_H
#define PLAYER_H
#include "config.h"
#include "opentyr.h"
enum
{
FRONT_WEAPON = 0,
REAR_WEAPON = 1
};
enum
{
LEFT_SIDEKICK = 0,
RIGHT_SIDEKICK = 1
};
typedef struct
{
uint ship;
uint generator;
uint shield;
struct { uint id; uint power; } weapon[2];
uint sidekick[2];
uint special;
// Dragonwing only:
// repeatedly collecting the same powerup gives a series of sidekick upgrades
uint sidekick_series;
uint sidekick_level;
// Single-player only
uint super_arcade_mode; // stored as an item for compatibility :(
}
PlayerItems;
typedef struct
{
ulong cash;
PlayerItems items, last_items;
bool is_dragonwing; // i.e., is player 2
uint *lives;
// calculatable
uint shield_max;
uint initial_armor;
uint shot_hit_area_x, shot_hit_area_y;
// state
bool is_alive;
uint invulnerable_ticks; // ticks until ship can be damaged
uint exploding_ticks; // ticks until ship done exploding
uint shield;
uint armor;
uint weapon_mode;
uint superbombs;
uint purple_balls_needed;
int x, y;
int old_x[20], old_y[20];
int x_velocity, y_velocity;
uint x_friction_ticks, y_friction_ticks; // ticks until friction is applied
int delta_x_shot_move, delta_y_shot_move;
int last_x_shot_move, last_y_shot_move;
int last_x_explosion_follow, last_y_explosion_follow;
struct
{
// calculatable
int ammo_max;
uint ammo_refill_ticks_max;
uint style; // affects movement and size
// state
int x, y;
int ammo;
uint ammo_refill_ticks;
bool animation_enabled;
uint animation_frame;
uint charge;
uint charge_ticks;
}
sidekick[2];
}
Player;
extern Player player[2];
static inline bool all_players_dead( void )
{
return (!player[0].is_alive && (!twoPlayerMode || !player[1].is_alive));
}
static inline bool all_players_alive( void )
{
return (player[0].is_alive && (!twoPlayerMode || player[1].is_alive));
}
void calc_purple_balls_needed( Player * );
bool power_up_weapon( Player *, uint port );
void handle_got_purple_ball( Player * );
#endif // PLAYER_H

View File

@@ -0,0 +1,313 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "font.h"
#include "joystick.h"
#include "jukebox.h"
#include "keyboard.h"
#include "loudness.h"
#include "mtrand.h"
#include "nortsong.h"
#include "nortvars.h"
#include "opentyr.h"
#include "palette.h"
#include "scroller.h"
#include "sprite.h"
#include "varz.h"
#include "vga256d.h"
#include "video.h"
const struct about_text_type about_text[] =
{
{0x30, "----- ~OpenTyrian~ -----"},
{0x00, ""},
{0x0b, "...eliminating Microsol,"},
{0x0b, "one planet at a time..."},
{0x00, ""},
{0x00, ""},
{0x30, "----- ~Developers~ -----"},
{0x00, ""},
{0x03, "Carl Reinke // Mindless"},
{0x07, "Yuri Schlesner // yuriks"},
{0x04, "Casey McCann // syntaxglitch"},
{0x00, ""},
{0x00, ""},
{0x30, "----- ~Thanks~ -----"},
{0x00, ""},
{0x0e, "Thanks to everyone who has"},
{0x0e, "assisted the developers by testing"},
{0x0e, "the game and reporting bugs."},
{0x00, ""},
{0x00, ""},
{0x05, "Thanks to ~MAME~ and ~DOSBox~"},
{0x05, "for the FM emulator and"},
{0x05, "~AdPlug~ for the Loudness code."},
{0x00, ""},
{0x00, ""},
{0x32, "And special thanks to ~Jason Emery~"},
{0x32, "for making all this possible"},
{0x32, "by giving Tyrian to its fans."},
{0x00, ""},
{0x00, ""},
/* {0x00, "This is line color test ~0~."},
{0x01, "This is line color test ~1~."},
{0x02, "This is line color test ~2~."},
{0x03, "This is line color test ~3~."},
{0x04, "This is line color test ~4~."},
{0x05, "This is line color test ~5~."},
{0x06, "This is line color test ~6~."},
{0x07, "This is line color test ~7~."},
{0x08, "This is line color test ~8~."},
{0x09, "This is line color test ~9~."},
{0x0a, "This is line color test ~A~."},
{0x0b, "This is line color test ~B~."},
{0x0c, "This is line color test ~C~."},
{0x0d, "This is line color test ~D~."},
{0x0e, "This is line color test ~E~."},
{0x0f, "This is line color test ~F~."},*/
{0x00, ""},
{0x00, ""},
{0x00, ""},
{0x00, ""},
{0x00, ""},
{0x00, ""},
{0x00, "Press a key to leave."},
{0x00, NULL}
};
#define LINE_HEIGHT 15
#define MAX_BEER 5
#define BEER_SHAPE 241
struct coin_def_type {
int shape_num;
int frame_count;
bool reverse_anim;
};
#define MAX_COINS 20
struct coin_def_type coin_defs[] =
{
{1, 6}, {7, 6}, {20, 6}, {26, 6}, // Coins
{14, 5, true}, {32, 5, true}, {51, 5, true} // Gems
};
/* Text is an array of strings terminated by a NULL */
void scroller_sine( const struct about_text_type text[] )
{
bool ale = mt_rand() % 2;
int visible_lines = vga_height / LINE_HEIGHT + 1;
int current_line = -visible_lines;
int y = 0;
bool fade_in = true;
struct coin_type { int x, y, vel, type, cur_frame; bool backwards; } coins[MAX_COINS];
struct { int x, y, ay, vx, vy; } beer[MAX_BEER];
if (ale)
{
memset(beer, 0, sizeof(beer));
} else {
for (int i = 0; i < MAX_COINS; i++)
{
coins[i].x = mt_rand() % (vga_width - 12);
coins[i].y = mt_rand() % (vga_height - 20 - 14);
coins[i].vel = (mt_rand() % 4) + 1;
coins[i].type = mt_rand() % COUNTOF(coin_defs);
coins[i].cur_frame = mt_rand() % coin_defs[coins[i].type].frame_count;
coins[i].backwards = false;
}
}
fade_black(10);
wait_noinput(true, true, true);
play_song(40); // BEER
while (!JE_anyButton())
{
setdelay(3);
JE_clr256(VGAScreen);
if (!ale)
{
for (int i = 0; i < MAX_COINS/2; i++)
{
struct coin_type *coin = &coins[i];
blit_sprite2(VGAScreen, coin->x, coin->y, eShapes5, coin_defs[coin->type].shape_num + coin->cur_frame);
}
}
for (int i = 0; i < visible_lines; i++)
{
if (current_line + i >= 0)
{
if (text[current_line + i].text == NULL)
{
break;
}
int line_x = VGAScreen->w / 2;
int line_y = i * LINE_HEIGHT - y;
// smooths edges on sine-wave text
if (text[i + current_line].effect & 0x20)
{
draw_font_hv(VGAScreen, line_x + 1, line_y, text[i + current_line].text, normal_font, centered, text[i + current_line].effect & 0x0f, -10);
draw_font_hv(VGAScreen, line_x - 1, line_y, text[i + current_line].text, normal_font, centered, text[i + current_line].effect & 0x0f, -10);
}
draw_font_hv(VGAScreen, line_x, line_y, text[i + current_line].text, normal_font, centered, text[i + current_line].effect & 0x0f, -4);
if (text[i + current_line].effect & 0x10)
{
for (int j = 0; j < LINE_HEIGHT; j++)
{
if (line_y + j >= 10 && line_y + j <= vga_height - 10)
{
int waver = sinf((((line_y + j) / 2) % 10) / 5.0f * M_PI) * 3;
memmove(&((Uint8 *)VGAScreen->pixels)[VGAScreen->pitch * (line_y + j) + waver],
&((Uint8 *)VGAScreen->pixels)[VGAScreen->pitch * (line_y + j)],
VGAScreen->pitch);
}
}
}
}
}
if (++y == LINE_HEIGHT)
{
y = 0;
if (current_line < 0 || text[current_line].text != NULL)
++current_line;
else
current_line = -visible_lines;
}
if (!ale)
{
for (int i = MAX_COINS/2; i < MAX_COINS; i++)
{
struct coin_type *coin = &coins[i];
blit_sprite2(VGAScreen, coin->x, coin->y, eShapes5, coin_defs[coin->type].shape_num + coin->cur_frame);
}
}
fill_rectangle_xy(VGAScreen, 0, 0, vga_width - 1, 14, 0);
fill_rectangle_xy(VGAScreen, 0, vga_height - 14, vga_width - 1, vga_height - 1, 0);
if (!ale)
{
for (int i = 0; i < MAX_COINS; i++)
{
struct coin_type *coin = &coins[i];
if (coin->backwards)
{
coin->cur_frame--;
} else {
coin->cur_frame++;
}
if (coin->cur_frame == coin_defs[coin->type].frame_count)
{
if (coin_defs[coin->type].reverse_anim)
{
coin->backwards = true;
coin->cur_frame -= 2;
} else {
coin->cur_frame = 0;
}
}
if (coin->cur_frame == -1)
{
coin->cur_frame = 1;
coin->backwards = false;
}
coin->y += coin->vel;
if (coin->y > vga_height - 14)
{
coin->x = mt_rand() % (vga_width - 12);
coin->y = 0;
coin->vel = (mt_rand() % 4) + 1;
coin->type = mt_rand() % COUNTOF(coin_defs);
coin->cur_frame = mt_rand() % coin_defs[coin->type].frame_count;
}
}
} else {
for (uint i = 0; i < COUNTOF(beer); i++)
{
while (beer[i].vx == 0)
{
beer[i].x = mt_rand() % (vga_width - 24);
beer[i].y = mt_rand() % (vga_height - 28 - 50);
beer[i].vx = (mt_rand() % 5) - 2;
}
beer[i].vy++;
if (beer[i].x + beer[i].vx > vga_width - 24 || beer[i].x + beer[i].vx < 0) // check if the beer hit the sides
{
beer[i].vx = -beer[i].vx;
}
beer[i].x += beer[i].vx;
if (beer[i].y + beer[i].vy > vga_height - 28) // check if the beer hit the bottom
{
if ((beer[i].vy) < 8) // make sure the beer bounces!
{
beer[i].vy += mt_rand() % 2;
} else if (beer[i].vy > 16) { // make sure the beer doesn't bounce too high
beer[i].vy = 16;
}
beer[i].vy = -beer[i].vy + (mt_rand() % 3 - 1);
beer[i].x += (beer[i].vx > 0 ? 1 : -1) * (i % 2 ? 1 : -1);
}
beer[i].y += beer[i].vy;
blit_sprite2x2(VGAScreen, beer[i].x, beer[i].y, eShapes5, BEER_SHAPE);
}
}
JE_showVGA();
if (fade_in)
{
fade_in = false;
fade_palette(colors, 10, 0, 255);
SDL_Color white = { 255, 255, 255 };
set_colors(white, 254, 254);
}
wait_delay();
}
fade_black(10);
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,33 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef SCROLLER_H
#define SCROLLER_H
#include "opentyr.h"
extern const struct about_text_type {
int effect;
const char *text;
} about_text[];
void scroller_sine( const struct about_text_type text[] );
#endif /* SCROLLER_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,96 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "joystick.h"
#include "keyboard.h"
#include "network.h"
#include "nortvars.h"
#include "opentyr.h"
#include "mainint.h"
#include "mouse.h"
#include "setup.h"
#include "video.h"
#include "SDL.h"
void JE_textMenuWait( JE_word *waitTime, JE_boolean doGamma )
{
set_mouse_position(160, 100);
do
{
JE_showVGA();
push_joysticks_as_keyboard();
service_SDL_events(true);
if (doGamma)
JE_gammaCheck();
inputDetected = newkey | mousedown;
if (lastkey_sym == SDLK_SPACE)
{
lastkey_sym = SDLK_RETURN;
}
if (mousedown)
{
newkey = true;
lastkey_sym = SDLK_RETURN;
}
if (has_mouse && input_grabbed)
{
if (abs(mouse_y - 100) > 10)
{
inputDetected = true;
if (mouse_y - 100 < 0)
{
lastkey_sym = SDLK_UP;
} else {
lastkey_sym = SDLK_DOWN;
}
newkey = true;
}
if (abs(mouse_x - 160) > 10)
{
inputDetected = true;
if (mouse_x - 160 < 0)
{
lastkey_sym = SDLK_LEFT;
} else {
lastkey_sym = SDLK_RIGHT;
}
newkey = true;
}
}
NETWORK_KEEP_ALIVE();
SDL_Delay(16);
if (*waitTime > 0)
{
(*waitTime)--;
}
} while (!(inputDetected || *waitTime == 1 || haltGame));
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,28 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef SETUP_H
#define SETUP_H
#include "opentyr.h"
void JE_textMenuWait( JE_word *waitTime, JE_boolean doGamma );
#endif /* SETUP_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,222 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
/*
* This file is largely based on (and named after) a set of common reading/
* writing functions used in Quake engines. Its purpose is to allow extraction
* of bytes, words, and dwords in a safe, endian adjused environment and should
* probably be used in any situation where checking for buffer overflows
* manually makes the code a godawful mess.
*
* Currently this is only used by the animation decoding.
*
* This file is written with the intention of being easily converted into a
* class capable of throwing exceptions if data is out of range.
*
* If an operation fails, subsequent operations will also fail. The sizebuf
* is assumed to be in an invalid state. This COULD be changed pretty easily
* and in normal Quake IIRC it is. But our MO is to bail on failure, not
* figure out what went wrong (making throws perfect).
*/
#include "sizebuf.h"
#include <assert.h>
#include "SDL_endian.h"
/* Construct buffer with the passed array and size */
void SZ_Init(sizebuf_t * sz, Uint8 * buf, unsigned int size)
{
sz->data = buf;
sz->bufferLen = size;
sz->bufferPos = 0;
sz->error = false;
}
/* Check error flags */
bool SZ_Error(sizebuf_t * sz)
{
return(sz->error);
}
/* mimic memset */
void SZ_Memset(sizebuf_t * sz, int value, size_t count)
{
/* Do bounds checking before writing */
if (sz->error || sz->bufferPos + count > sz->bufferLen)
{
sz->error = true;
return;
}
/* Memset and increment pointer */
memset(sz->data + sz->bufferPos, value, count);
sz->bufferPos += count;
}
/* Mimic memcpy. Two versions, one for buffers, one for sizebuf objects.
* Overload in C++. */
void SZ_Memcpy(sizebuf_t * sz, const Uint8 * buf, size_t count)
{
/* State checking */
if (sz->error || sz->bufferPos + count > sz->bufferLen)
{
sz->error = true;
return;
}
/* Memcpy & increment */
memcpy(sz->data + sz->bufferPos, buf, count);
sz->bufferPos += count;
}
void SZ_Memcpy2(sizebuf_t * sz, sizebuf_t * bf, size_t count)
{
/* State checking */
if (sz->error || sz->bufferPos + count > sz->bufferLen)
{
sz->error = true;
return;
}
if (bf->error || bf->bufferPos + count > bf->bufferLen)
{
bf->error = true;
return;
}
/* Memcpy & increment */
memcpy(sz->data + sz->bufferPos, bf->data + bf->bufferPos, count);
sz->bufferPos += count;
bf->bufferPos += count;
}
/* Reposition buffer pointer */
void SZ_Seek(sizebuf_t * sz, long count, int mode)
{
/* Okay, it's reasonable to reset the error bool on seeking... */
switch(mode)
{
case SEEK_SET:
sz->bufferPos = count;
break;
case SEEK_CUR:
sz->bufferPos += count;
break;
case SEEK_END:
sz->bufferPos = sz->bufferLen - count;
break;
default:
assert(false);
}
/* Check errors */
if (sz->bufferPos > sz->bufferLen)
{
sz->error = true;
} else {
sz->error = false;
}
}
const Uint8 * SZ_GetCurBufferPtr (sizebuf_t * sz)
{
return(sz->data);
}
/* The code below makes use of pointer casts, similar to what is in efread.
* It's not the ONLY way to write ints to a stream, but it's probably the
* cleanest of the lot. Better to have it here than littered all over the code.
*/
void MSG_WriteByte(sizebuf_t * sz, unsigned int value)
{
if (sz->error || sz->bufferPos + 1 > sz->bufferLen)
{
sz->error = true;
return;
}
sz->data[sz->bufferPos] = value;
sz->bufferPos++;
}
void MSG_WriteWord(sizebuf_t * sz, unsigned int value)
{
if (sz->error || sz->bufferPos + 2 > sz->bufferLen)
{
sz->error = true;
return;
}
*((Uint16 *)(sz->data + sz->bufferPos)) = SDL_SwapLE16( ((Uint16)value) );
sz->bufferPos += 2;
}
void MSG_WriteDWord(sizebuf_t * sz, unsigned int value)
{
if (sz->error || sz->bufferPos + 4 > sz->bufferLen)
{
sz->error = true;
return;
}
*((Uint32 *)(sz->data + sz->bufferPos)) = SDL_SwapLE32( ((Uint32)value) );
sz->bufferPos += 4;
}
unsigned int MSG_ReadByte(sizebuf_t * sz)
{
unsigned int ret;
if (sz->error || sz->bufferPos + 1 > sz->bufferLen)
{
sz->error = true;
return(0);
}
ret = sz->data[sz->bufferPos];
sz->bufferPos += 1;
return(ret);
}
unsigned int MSG_ReadWord(sizebuf_t * sz)
{
unsigned int ret;
if (sz->error || sz->bufferPos + 2 > sz->bufferLen)
{
sz->error = true;
return(0);
}
ret = SDL_SwapLE16(*((Uint16 *)(sz->data + sz->bufferPos)));
sz->bufferPos += 2;
return(ret);
}
unsigned int MSG_ReadDWord(sizebuf_t * sz)
{
unsigned int ret;
if (sz->error || sz->bufferPos + 4 > sz->bufferLen)
{
sz->error = true;
return(0);
}
ret = SDL_SwapLE32(*((Uint32 *)(sz->data + sz->bufferPos)));
sz->bufferPos += 4;
return(ret);
}

View File

@@ -0,0 +1,50 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef SIZEBUF_H
#define SIZEBUF_H
#include "opentyr.h"
typedef struct sizebuf_s
{
Uint8 *data;
unsigned int bufferLen;
unsigned int bufferPos;
bool error;
} sizebuf_t;
void SZ_Init ( sizebuf_t *, Uint8 *, unsigned int ); /* C style constructor */
bool SZ_Error ( sizebuf_t * );
void SZ_Memset ( sizebuf_t *, int, size_t ); /* memset with a sizebuf */
void SZ_Memcpy ( sizebuf_t *, const Uint8 *, size_t ); /* memcpy with a normal buffer */
void SZ_Memcpy2 ( sizebuf_t *, sizebuf_t *, size_t ); /* memcpy with a sizebuf */
void SZ_Seek ( sizebuf_t *, long, int ); /* fseek with a sizebuf. */
const Uint8 * SZ_GetCurBufferPtr ( sizebuf_t * ); /* Mimic private member, const return */
void MSG_WriteByte ( sizebuf_t *, unsigned int );
void MSG_WriteWord ( sizebuf_t *, unsigned int );
void MSG_WriteDWord ( sizebuf_t *, unsigned int );
unsigned int MSG_ReadByte ( sizebuf_t * );
unsigned int MSG_ReadWord ( sizebuf_t * );
unsigned int MSG_ReadDWord ( sizebuf_t * );
#endif

View File

@@ -0,0 +1,78 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "opentyr.h"
#include "sndmast.h"
const char soundTitle[SAMPLE_COUNT][9] = /* [1..soundnum + 9] of string [8] */
{
"SCALEDN2", /*1*/
"F2", /*2*/
"TEMP10",
"EXPLSM",
"PASS3", /*5*/
"TEMP2",
"BYPASS1",
"EXP1RT",
"EXPLLOW",
"TEMP13", /*10*/
"EXPRETAP",
"MT2BOOM",
"TEMP3",
"LAZB", /*28K*/
"LAZGUN2", /*15*/
"SPRING",
"WARNING",
"ITEM",
"HIT2", /*14K*/
"MACHNGUN", /*20*/
"HYPERD2",
"EXPLHUG",
"CLINK1",
"CLICK",
"SCALEDN1", /*25*/
"TEMP11",
"TEMP16",
"SMALL1",
"POWERUP",
"VOICE1",
"VOICE2",
"VOICE3",
"VOICE4",
"VOICE5",
"VOICE6",
"VOICE7",
"VOICE8",
"VOICE9"
};
const JE_byte windowTextSamples[9] = /* [1..9] */
{
V_DANGER,
V_BOSS,
V_ENEMIES,
V_CLEARED_PLATFORM,
V_DANGER,
V_SPIKES,
V_ACCELERATE,
V_DANGER,
V_ENEMIES
};
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,76 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef SNDMAST_H
#define SNDMAST_H
#include "opentyr.h"
#define SAMPLE_COUNT 38
enum
{
S_NONE = 0,
S_WEAPON_1,
S_WEAPON_2,
S_ENEMY_HIT,
S_EXPLOSION_4,
S_WEAPON_5,
S_WEAPON_6,
S_WEAPON_7,
S_SELECT, // S_EXPLOSION_8
S_EXPLOSION_9,
S_WEAPON_10,
S_EXPLOSION_11,
S_EXPLOSION_12,
S_WEAPON_13,
S_WEAPON_14,
S_WEAPON_15,
S_SPRING,
S_WARNING,
S_ITEM,
S_HULL_HIT,
S_MACHINE_GUN,
S_SOUL_OF_ZINGLON,
S_EXPLOSION_22,
S_CLINK,
S_CLICK,
S_WEAPON_25,
S_WEAPON_26,
S_SHIELD_HIT,
S_CURSOR,
S_POWERUP,
V_CLEARED_PLATFORM, // 30
V_BOSS,
V_ENEMIES,
V_GOOD_LUCK,
V_LEVEL_END,
V_DANGER,
V_SPIKES,
V_DATA_CUBE,
V_ACCELERATE
};
extern const char soundTitle[SAMPLE_COUNT][9];
extern const JE_byte windowTextSamples[9];
#endif /* SNDMAST_H */
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,732 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "file.h"
#include "opentyr.h"
#include "sprite.h"
#include "video.h"
#include <assert.h>
Sprite_array sprite_table[SPRITE_TABLES_MAX];
Sprite2_array eShapes1, eShapes2, eShapes3, eShapes4, eShapes5, eShapes6;
Sprite2_array shapesC1, shapes6, shapes9, shapesW2;
void load_sprites_file( unsigned int table, const char *filename )
{
free_sprites(table);
FILE *f = dir_fopen_die(data_dir(), filename, "rb");
load_sprites(table, f);
fclose(f);
}
void load_sprites( unsigned int table, FILE *f )
{
free_sprites(table);
Uint16 temp;
efread(&temp, sizeof(Uint16), 1, f);
sprite_table[table].count = temp;
for (unsigned int i = 0; i < sprite_table[table].count; ++i)
{
Sprite * const cur_sprite = sprite(table, i);
if (!getc(f)) // sprite is empty
continue;
efread(&cur_sprite->width, sizeof(Uint16), 1, f);
efread(&cur_sprite->height, sizeof(Uint16), 1, f);
efread(&cur_sprite->size, sizeof(Uint16), 1, f);
cur_sprite->data = (Uint8 *)malloc(cur_sprite->size);
efread(cur_sprite->data, sizeof(Uint8), cur_sprite->size, f);
}
}
void free_sprites( unsigned int table )
{
for (unsigned int i = 0; i < sprite_table[table].count; ++i)
{
Sprite * const cur_sprite = sprite(table, i);
cur_sprite->width = 0;
cur_sprite->height = 0;
cur_sprite->size = 0;
free(cur_sprite->data);
cur_sprite->data = NULL;
}
sprite_table[table].count = 0;
}
// does not clip on left or right edges of surface
void blit_sprite( SDL_Surface *surface, int x, int y, unsigned int table, unsigned int index )
{
if (index >= sprite_table[table].count || !sprite_exists(table, index))
{
assert(false);
return;
}
const Sprite * const cur_sprite = sprite(table, index);
const Uint8 *data = cur_sprite->data;
const Uint8 * const data_ul = data + cur_sprite->size;
const unsigned int width = cur_sprite->width;
unsigned int x_offset = 0;
assert(surface->format->BitsPerPixel == 8);
Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x;
const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit
* const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
for (; data < data_ul; ++data)
{
switch (*data)
{
case 255: // transparent pixels
data++; // next byte tells how many
pixels += *data;
x_offset += *data;
break;
case 254: // next pixel row
pixels += width - x_offset;
x_offset = width;
break;
case 253: // 1 transparent pixel
pixels++;
x_offset++;
break;
default: // set a pixel
if (pixels >= pixels_ul)
return;
if (pixels >= pixels_ll)
*pixels = *data;
pixels++;
x_offset++;
break;
}
if (x_offset >= width)
{
pixels += surface->pitch - x_offset;
x_offset = 0;
}
}
}
// does not clip on left or right edges of surface
void blit_sprite_blend( SDL_Surface *surface, int x, int y, unsigned int table, unsigned int index )
{
if (index >= sprite_table[table].count || !sprite_exists(table, index))
{
assert(false);
return;
}
const Sprite * const cur_sprite = sprite(table, index);
const Uint8 *data = cur_sprite->data;
const Uint8 * const data_ul = data + cur_sprite->size;
const unsigned int width = cur_sprite->width;
unsigned int x_offset = 0;
assert(surface->format->BitsPerPixel == 8);
Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x;
const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit
* const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
for (; data < data_ul; ++data)
{
switch (*data)
{
case 255: // transparent pixels
data++; // next byte tells how many
pixels += *data;
x_offset += *data;
break;
case 254: // next pixel row
pixels += width - x_offset;
x_offset = width;
break;
case 253: // 1 transparent pixel
pixels++;
x_offset++;
break;
default: // set a pixel
if (pixels >= pixels_ul)
return;
if (pixels >= pixels_ll)
*pixels = (*data & 0xf0) | (((*pixels & 0x0f) + (*data & 0x0f)) / 2);
pixels++;
x_offset++;
break;
}
if (x_offset >= width)
{
pixels += surface->pitch - x_offset;
x_offset = 0;
}
}
}
// does not clip on left or right edges of surface
// unsafe because it doesn't check that value won't overflow into hue
// we can replace it when we know that we don't rely on that 'feature'
void blit_sprite_hv_unsafe( SDL_Surface *surface, int x, int y, unsigned int table, unsigned int index, Uint8 hue, Sint8 value )
{
if (index >= sprite_table[table].count || !sprite_exists(table, index))
{
assert(false);
return;
}
hue <<= 4;
const Sprite * const cur_sprite = sprite(table, index);
const Uint8 *data = cur_sprite->data;
const Uint8 * const data_ul = data + cur_sprite->size;
const unsigned int width = cur_sprite->width;
unsigned int x_offset = 0;
assert(surface->format->BitsPerPixel == 8);
Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x;
const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit
* const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
for (; data < data_ul; ++data)
{
switch (*data)
{
case 255: // transparent pixels
data++; // next byte tells how many
pixels += *data;
x_offset += *data;
break;
case 254: // next pixel row
pixels += width - x_offset;
x_offset = width;
break;
case 253: // 1 transparent pixel
pixels++;
x_offset++;
break;
default: // set a pixel
if (pixels >= pixels_ul)
return;
if (pixels >= pixels_ll)
*pixels = hue | ((*data & 0x0f) + value);
pixels++;
x_offset++;
break;
}
if (x_offset >= width)
{
pixels += surface->pitch - x_offset;
x_offset = 0;
}
}
}
// does not clip on left or right edges of surface
void blit_sprite_hv( SDL_Surface *surface, int x, int y, unsigned int table, unsigned int index, Uint8 hue, Sint8 value )
{
if (index >= sprite_table[table].count || !sprite_exists(table, index))
{
assert(false);
return;
}
hue <<= 4;
const Sprite * const cur_sprite = sprite(table, index);
const Uint8 *data = cur_sprite->data;
const Uint8 * const data_ul = data + cur_sprite->size;
const unsigned int width = cur_sprite->width;
unsigned int x_offset = 0;
assert(surface->format->BitsPerPixel == 8);
Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x;
const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit
* const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
for (; data < data_ul; ++data)
{
switch (*data)
{
case 255: // transparent pixels
data++; // next byte tells how many
pixels += *data;
x_offset += *data;
break;
case 254: // next pixel row
pixels += width - x_offset;
x_offset = width;
break;
case 253: // 1 transparent pixel
pixels++;
x_offset++;
break;
default: // set a pixel
if (pixels >= pixels_ul)
return;
if (pixels >= pixels_ll)
{
Uint8 temp_value = (*data & 0x0f) + value;
if (temp_value > 0xf)
temp_value = (temp_value >= 0x1f) ? 0x0 : 0xf;
*pixels = hue | temp_value;
}
pixels++;
x_offset++;
break;
}
if (x_offset >= width)
{
pixels += surface->pitch - x_offset;
x_offset = 0;
}
}
}
// does not clip on left or right edges of surface
void blit_sprite_hv_blend( SDL_Surface *surface, int x, int y, unsigned int table, unsigned int index, Uint8 hue, Sint8 value )
{
if (index >= sprite_table[table].count || !sprite_exists(table, index))
{
assert(false);
return;
}
hue <<= 4;
const Sprite * const cur_sprite = sprite(table, index);
const Uint8 *data = cur_sprite->data;
const Uint8 * const data_ul = data + cur_sprite->size;
const unsigned int width = cur_sprite->width;
unsigned int x_offset = 0;
assert(surface->format->BitsPerPixel == 8);
Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x;
const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit
* const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
for (; data < data_ul; ++data)
{
switch (*data)
{
case 255: // transparent pixels
data++; // next byte tells how many
pixels += *data;
x_offset += *data;
break;
case 254: // next pixel row
pixels += width - x_offset;
x_offset = width;
break;
case 253: // 1 transparent pixel
pixels++;
x_offset++;
break;
default: // set a pixel
if (pixels >= pixels_ul)
return;
if (pixels >= pixels_ll)
{
Uint8 temp_value = (*data & 0x0f) + value;
if (temp_value > 0xf)
temp_value = (temp_value >= 0x1f) ? 0x0 : 0xf;
*pixels = hue | (((*pixels & 0x0f) + temp_value) / 2);
}
pixels++;
x_offset++;
break;
}
if (x_offset >= width)
{
pixels += surface->pitch - x_offset;
x_offset = 0;
}
}
}
// does not clip on left or right edges of surface
void blit_sprite_dark( SDL_Surface *surface, int x, int y, unsigned int table, unsigned int index, bool black )
{
if (index >= sprite_table[table].count || !sprite_exists(table, index))
{
assert(false);
return;
}
const Sprite * const cur_sprite = sprite(table, index);
const Uint8 *data = cur_sprite->data;
const Uint8 * const data_ul = data + cur_sprite->size;
const unsigned int width = cur_sprite->width;
unsigned int x_offset = 0;
assert(surface->format->BitsPerPixel == 8);
Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x;
const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit
* const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
for (; data < data_ul; ++data)
{
switch (*data)
{
case 255: // transparent pixels
data++; // next byte tells how many
pixels += *data;
x_offset += *data;
break;
case 254: // next pixel row
pixels += width - x_offset;
x_offset = width;
break;
case 253: // 1 transparent pixel
pixels++;
x_offset++;
break;
default: // set a pixel
if (pixels >= pixels_ul)
return;
if (pixels >= pixels_ll)
*pixels = black ? 0x00 : ((*pixels & 0xf0) | ((*pixels & 0x0f) / 2));
pixels++;
x_offset++;
break;
}
if (x_offset >= width)
{
pixels += surface->pitch - x_offset;
x_offset = 0;
}
}
}
void JE_loadCompShapes( Sprite2_array *sprite2s, char s )
{
char buffer[20];
snprintf(buffer, sizeof(buffer), "newsh%c.shp", tolower((unsigned char)s));
FILE *f = dir_fopen_die(data_dir(), buffer, "rb");
sprite2s->size = ftell_eof(f);
JE_loadCompShapesB(sprite2s, f);
fclose(f);
}
void JE_loadCompShapesB( Sprite2_array *sprite2s, FILE *f )
{
free_sprite2s(sprite2s);
sprite2s->data = (Uint8 *)malloc(sizeof(Uint8) * sprite2s->size);
efread(sprite2s->data, sizeof(Uint8), sprite2s->size, f);
}
void free_sprite2s( Sprite2_array *sprite2s )
{
free(sprite2s->data);
sprite2s->data = NULL;
}
// does not clip on left or right edges of surface
void blit_sprite2( SDL_Surface *surface, int x, int y, Sprite2_array sprite2s, unsigned int index )
{
assert(surface->format->BitsPerPixel == 8);
Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x;
const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit
* const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
const Uint8 *data = sprite2s.data + SDL_SwapLE16(((Uint16 *)sprite2s.data)[index - 1]);
for (; *data != 0x0f; ++data)
{
pixels += *data & 0x0f; // second nibble: transparent pixel count
unsigned int count = (*data & 0xf0) >> 4; // first nibble: opaque pixel count
if (count == 0) // move to next pixel row
{
pixels += VGAScreen->pitch - 12;
}
else
{
while (count--)
{
++data;
if (pixels >= pixels_ul)
return;
if (pixels >= pixels_ll)
*pixels = *data;
++pixels;
}
}
}
}
// does not clip on left or right edges of surface
void blit_sprite2_blend( SDL_Surface *surface, int x, int y, Sprite2_array sprite2s, unsigned int index )
{
assert(surface->format->BitsPerPixel == 8);
Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x;
const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit
* const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
const Uint8 *data = sprite2s.data + SDL_SwapLE16(((Uint16 *)sprite2s.data)[index - 1]);
for (; *data != 0x0f; ++data)
{
pixels += *data & 0x0f; // second nibble: transparent pixel count
unsigned int count = (*data & 0xf0) >> 4; // first nibble: opaque pixel count
if (count == 0) // move to next pixel row
{
pixels += VGAScreen->pitch - 12;
}
else
{
while (count--)
{
++data;
if (pixels >= pixels_ul)
return;
if (pixels >= pixels_ll)
*pixels = (((*data & 0x0f) + (*pixels & 0x0f)) / 2) | (*data & 0xf0);
++pixels;
}
}
}
}
// does not clip on left or right edges of surface
void blit_sprite2_darken( SDL_Surface *surface, int x, int y, Sprite2_array sprite2s, unsigned int index )
{
assert(surface->format->BitsPerPixel == 8);
Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x;
const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit
* const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
const Uint8 *data = sprite2s.data + SDL_SwapLE16(((Uint16 *)sprite2s.data)[index - 1]);
for (; *data != 0x0f; ++data)
{
pixels += *data & 0x0f; // second nibble: transparent pixel count
unsigned int count = (*data & 0xf0) >> 4; // first nibble: opaque pixel count
if (count == 0) // move to next pixel row
{
pixels += VGAScreen->pitch - 12;
}
else
{
while (count--)
{
++data;
if (pixels >= pixels_ul)
return;
if (pixels >= pixels_ll)
*pixels = ((*pixels & 0x0f) / 2) + (*pixels & 0xf0);
++pixels;
}
}
}
}
// does not clip on left or right edges of surface
void blit_sprite2_filter( SDL_Surface *surface, int x, int y, Sprite2_array sprite2s, unsigned int index, Uint8 filter )
{
assert(surface->format->BitsPerPixel == 8);
Uint8 * pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x;
const Uint8 * const pixels_ll = (Uint8 *)surface->pixels, // lower limit
* const pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
const Uint8 *data = sprite2s.data + SDL_SwapLE16(((Uint16 *)sprite2s.data)[index - 1]);
for (; *data != 0x0f; ++data)
{
pixels += *data & 0x0f; // second nibble: transparent pixel count
unsigned int count = (*data & 0xf0) >> 4; // first nibble: opaque pixel count
if (count == 0) // move to next pixel row
{
pixels += VGAScreen->pitch - 12;
}
else
{
while (count--)
{
++data;
if (pixels >= pixels_ul)
return;
if (pixels >= pixels_ll)
*pixels = filter | (*data & 0x0f);
++pixels;
}
}
}
}
// does not clip on left or right edges of surface
void blit_sprite2x2( SDL_Surface *surface, int x, int y, Sprite2_array sprite2s, unsigned int index )
{
blit_sprite2(surface, x, y, sprite2s, index);
blit_sprite2(surface, x + 12, y, sprite2s, index + 1);
blit_sprite2(surface, x, y + 14, sprite2s, index + 19);
blit_sprite2(surface, x + 12, y + 14, sprite2s, index + 20);
}
// does not clip on left or right edges of surface
void blit_sprite2x2_blend( SDL_Surface *surface, int x, int y, Sprite2_array sprite2s, unsigned int index )
{
blit_sprite2_blend(surface, x, y, sprite2s, index);
blit_sprite2_blend(surface, x + 12, y, sprite2s, index + 1);
blit_sprite2_blend(surface, x, y + 14, sprite2s, index + 19);
blit_sprite2_blend(surface, x + 12, y + 14, sprite2s, index + 20);
}
// does not clip on left or right edges of surface
void blit_sprite2x2_darken( SDL_Surface *surface, int x, int y, Sprite2_array sprite2s, unsigned int index )
{
blit_sprite2_darken(surface, x, y, sprite2s, index);
blit_sprite2_darken(surface, x + 12, y, sprite2s, index + 1);
blit_sprite2_darken(surface, x, y + 14, sprite2s, index + 19);
blit_sprite2_darken(surface, x + 12, y + 14, sprite2s, index + 20);
}
void JE_loadMainShapeTables( const char *shpfile )
{
const int SHP_NUM = 12;
FILE *f = dir_fopen_die(data_dir(), shpfile, "rb");
JE_word shpNumb;
JE_longint shpPos[SHP_NUM + 1]; // +1 for storing file length
efread(&shpNumb, sizeof(JE_word), 1, f);
assert(shpNumb + 1u <= COUNTOF(shpPos));
for (int i = 0; i < shpNumb; i++)
{
efread(&shpPos[i], sizeof(JE_longint), 1, f);
}
fseek(f, 0, SEEK_END);
shpPos[shpNumb] = ftell(f);
int i;
// fonts, interface, option sprites
for (i = 0; i < 7; i++)
{
fseek(f, shpPos[i], SEEK_SET);
load_sprites(i, f);
}
// player shot sprites
shapesC1.size = shpPos[i + 1] - shpPos[i];
JE_loadCompShapesB(&shapesC1, f);
i++;
// player ship sprites
shapes9.size = shpPos[i + 1] - shpPos[i];
JE_loadCompShapesB(&shapes9 , f);
i++;
// power-up sprites
eShapes6.size = shpPos[i + 1] - shpPos[i];
JE_loadCompShapesB(&eShapes6, f);
i++;
// coins, datacubes, etc sprites
eShapes5.size = shpPos[i + 1] - shpPos[i];
JE_loadCompShapesB(&eShapes5, f);
i++;
// more player shot sprites
shapesW2.size = shpPos[i + 1] - shpPos[i];
JE_loadCompShapesB(&shapesW2, f);
fclose(f);
}
void free_main_shape_tables( void )
{
for (uint i = 0; i < COUNTOF(sprite_table); ++i)
free_sprites(i);
free_sprite2s(&shapesC1);
free_sprite2s(&shapes9);
free_sprite2s(&eShapes6);
free_sprite2s(&eShapes5);
free_sprite2s(&shapesW2);
}
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,115 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#ifndef SPRITE_H
#define SPRITE_H
#include "opentyr.h"
#include "SDL.h"
#include <assert.h>
#define FONT_SHAPES 0
#define SMALL_FONT_SHAPES 1
#define TINY_FONT 2
#define PLANET_SHAPES 3
#define FACE_SHAPES 4
#define OPTION_SHAPES 5 /*Also contains help shapes*/
#define WEAPON_SHAPES 6
#define EXTRA_SHAPES 7 /*Used for Ending pics*/
#define SPRITE_TABLES_MAX 8
#define SPRITES_PER_TABLE_MAX 151
typedef struct
{
Uint16 width, height;
Uint16 size;
Uint8 *data;
}
Sprite;
typedef struct
{
unsigned int count;
Sprite sprite[SPRITES_PER_TABLE_MAX];
}
Sprite_array;
extern Sprite_array sprite_table[SPRITE_TABLES_MAX];
static inline Sprite *sprite( unsigned int table, unsigned int index )
{
assert(table < COUNTOF(sprite_table));
assert(index < COUNTOF(sprite_table->sprite));
return &sprite_table[table].sprite[index];
}
static inline bool sprite_exists( unsigned int table, unsigned int index )
{
return (sprite(table, index)->data != NULL);
}
static inline Uint16 get_sprite_width( unsigned int table, unsigned int index )
{
return (sprite_exists(table, index) ? sprite(table, index)->width : 0);
}
static inline Uint16 get_sprite_height( unsigned int table, unsigned int index )
{
return (sprite_exists(table, index) ? sprite(table, index)->height : 0);
}
void load_sprites_file( unsigned table, const char *filename );
void load_sprites( unsigned int table, FILE *f );
void free_sprites( unsigned int table );
void blit_sprite( SDL_Surface *, int x, int y, unsigned int table, unsigned int index ); // JE_newDrawCShapeNum
void blit_sprite_blend( SDL_Surface *, int x, int y, unsigned int table, unsigned int index ); // JE_newDrawCShapeTrick
void blit_sprite_hv_unsafe( SDL_Surface *, int x, int y, unsigned int table, unsigned int index, Uint8 hue, Sint8 value ); // JE_newDrawCShapeBright
void blit_sprite_hv( SDL_Surface *, int x, int y, unsigned int table, unsigned int index, Uint8 hue, Sint8 value ); // JE_newDrawCShapeAdjust
void blit_sprite_hv_blend( SDL_Surface *, int x, int y, unsigned int table, unsigned int index, Uint8 hue, Sint8 value ); // JE_newDrawCShapeModify
void blit_sprite_dark( SDL_Surface *, int x, int y, unsigned int table, unsigned int index, bool black ); // JE_newDrawCShapeDarken, JE_newDrawCShapeShadow
typedef struct
{
unsigned int size;
Uint8 *data;
}
Sprite2_array;
extern Sprite2_array eShapes1, eShapes2, eShapes3, eShapes4, eShapes5, eShapes6;
extern Sprite2_array shapesC1, shapes6, shapes9, shapesW2;
void JE_loadCompShapes( Sprite2_array *, JE_char s );
void JE_loadCompShapesB( Sprite2_array *, FILE *f );
void free_sprite2s( Sprite2_array * );
void blit_sprite2( SDL_Surface *, int x, int y, Sprite2_array, unsigned int index );
void blit_sprite2_blend( SDL_Surface *, int x, int y, Sprite2_array, unsigned int index );
void blit_sprite2_darken( SDL_Surface *, int x, int y, Sprite2_array, unsigned int index );
void blit_sprite2_filter( SDL_Surface *, int x, int y, Sprite2_array, unsigned int index, Uint8 filter );
void blit_sprite2x2( SDL_Surface *, int x, int y, Sprite2_array, unsigned int index );
void blit_sprite2x2_blend( SDL_Surface *, int x, int y, Sprite2_array, unsigned int index );
void blit_sprite2x2_darken( SDL_Surface *, int x, int y, Sprite2_array, unsigned int index );
void JE_loadMainShapeTables( const char *shpfile );
void free_main_shape_tables( void );
#endif // SPRITE_H
// kate: tab-width 4; vim: set noet:

View File

@@ -0,0 +1,432 @@
/*
* OpenTyrian Classic: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development Team
*
* 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.
*/
#include "opentyr.h"
#include "starlib.h"
#include "keyboard.h"
#include "mtrand.h"
#include "video.h"
#include <ctype.h>
#define starlib_MAX_STARS 1000
#define MAX_TYPES 14
struct JE_StarType
{
JE_integer spX, spY, spZ;
JE_integer lastX, lastY;
};
static int tempX, tempY;
static JE_boolean run;
static struct JE_StarType star[starlib_MAX_STARS];
static JE_byte setup;
static JE_word stepCounter;
static JE_word nsp2;
static JE_shortint nspVar2Inc;
/* JE: new sprite pointer */
static JE_real nsp;
static JE_real nspVarInc;
static JE_real nspVarVarInc;
static JE_word changeTime;
static JE_boolean doChange;
static JE_boolean grayB;
static JE_integer starlib_speed;
static JE_shortint speedChange;
static JE_byte pColor;
void JE_starlib_main( void )
{
int off;
JE_word i;
JE_integer tempZ;
JE_byte tempCol;
struct JE_StarType *stars;
Uint8 *surf;
JE_wackyCol();
grayB = false;
starlib_speed += speedChange;
for(stars = star, i = starlib_MAX_STARS; i > 0; stars++, i--)
{
/* Make a pointer to the screen... */
surf = (Uint8 *)VGAScreen->pixels;
/* Calculate the offset to where we wish to draw */
off = (stars->lastX)+(stars->lastY)*320;
/* We don't want trails in our star field. Erase the old graphic */
if (off >= 640 && off < (320*200)-640)
{
surf[off] = 0; /* Shade Level 0 */
surf[off-1] = 0; /* Shade Level 1, 2 */
surf[off+1] = 0;
surf[off-2] = 0;
surf[off+2] = 0;
surf[off-320] = 0;
surf[off+320] = 0;
surf[off-640] = 0;
surf[off+640] = 0;
}
/* Move star */
tempZ = stars->spZ;
tempX = (stars->spX / tempZ) + 160;
tempY = (stars->spY / tempZ) + 100;
tempZ -= starlib_speed;
/* If star is out of range, make a new one */
if (tempZ <= 0 ||
tempY == 0 || tempY > 198 ||
tempX > 318 || tempX < 1)
{
stars->spZ = 500;
JE_newStar();
stars->spX = tempX;
stars->spY = tempY;
}
else /* Otherwise, update & draw it */
{
stars->lastX = tempX;
stars->lastY = tempY;
stars->spZ = tempZ;
off = tempX+tempY*320;
if (grayB)
{
tempCol = tempZ >> 1;
} else {
tempCol = pColor+((tempZ >> 4) & 31);
}
/* Draw the pixel! */
if (off >= 640 && off < (320*200)-640)
{
surf[off] = tempCol;
tempCol += 72;
surf[off-1] = tempCol;
surf[off+1] = tempCol;
surf[off-320] = tempCol;
surf[off+320] = tempCol;
tempCol += 72;
surf[off-2] = tempCol;
surf[off+2] = tempCol;
surf[off-640] = tempCol;
surf[off+640] = tempCol;
}
}
}
if (newkey)
{
switch (toupper(lastkey_char))
{
case '+':
starlib_speed++;
speedChange = 0;
break;
case '-':
starlib_speed--;
speedChange = 0;
break;
case '1':
JE_changeSetup(1);
break;
case '2':
JE_changeSetup(2);
break;
case '3':
JE_changeSetup(3);
break;
case '4':
JE_changeSetup(4);
break;
case '5':
JE_changeSetup(5);
break;
case '6':
JE_changeSetup(6);
break;
case '7':
JE_changeSetup(7);
break;
case '8':
JE_changeSetup(8);
break;
case '9':
JE_changeSetup(9);
break;
case '0':
JE_changeSetup(10);
break;
case '!':
JE_changeSetup(11);
break;
case '@':
JE_changeSetup(12);
break;
case '#':
JE_changeSetup(13);
break;
case '$':
JE_changeSetup(14);
break;
case 'C':
JE_resetValues();
break;
case 'S':
nspVarVarInc = mt_rand_1() * 0.01f - 0.005f;
break;
case 'X':
case 27:
run = false;
break;
case '[':
pColor--;
break;
case ']':
pColor++;
break;
case '{':
pColor -= 72;
break;
case '}':
pColor += 72;
break;
case '`': /* ` */
doChange = !doChange;
break;
case 'P':
wait_noinput(true, false, false);
wait_input(true, false, false);
break;
default:
break;
}
}
if (doChange)
{
stepCounter++;
if (stepCounter > changeTime)
{
JE_changeSetup(0);
}
}
if ((mt_rand() % 1000) == 1)
{
nspVarVarInc = mt_rand_1() * 0.01f - 0.005f;
}
nspVarInc += nspVarVarInc;
}
void JE_wackyCol( void )
{
/* YKS: Does nothing */
}
void JE_starlib_init( void )
{
static JE_boolean initialized = false;
if (!initialized)
{
initialized = true;
JE_resetValues();
JE_changeSetup(2);
doChange = true;
/* RANDOMIZE; */
for (int x = 0; x < starlib_MAX_STARS; x++)
{
star[x].spX = (mt_rand() % 64000) - 32000;
star[x].spY = (mt_rand() % 40000) - 20000;
star[x].spZ = x+1;
}
}
}
void JE_resetValues( void )
{
nsp2 = 1;
nspVar2Inc = 1;
nspVarInc = 0.1f;
nspVarVarInc = 0.0001f;
nsp = 0;
pColor = 32;
starlib_speed = 2;
speedChange = 0;
}
void JE_changeSetup( JE_byte setupType )
{
stepCounter = 0;
changeTime = (mt_rand() % 1000);
if (setupType > 0)
{
setup = setupType;
} else {
setup = mt_rand() % (MAX_TYPES + 1);
}
if (setup == 1)
{
nspVarInc = 0.1f;
}
if (nspVarInc > 2.2f)
{
nspVarInc = 0.1f;
}
}
void JE_newStar( void )
{
if (setup == 0)
{
tempX = (mt_rand() % 64000) - 32000;
tempY = (mt_rand() % 40000) - 20000;
} else {
nsp = nsp + nspVarInc; /* YKS: < lol */
switch (setup)
{
case 1:
tempX = (int)(sinf(nsp / 30) * 20000);
tempY = (mt_rand() % 40000) - 20000;
break;
case 2:
tempX = (int)(cosf(nsp) * 20000);
tempY = (int)(sinf(nsp) * 20000);
break;
case 3:
tempX = (int)(cosf(nsp * 15) * 100) * ((int)(nsp / 6) % 200);
tempY = (int)(sinf(nsp * 15) * 100) * ((int)(nsp / 6) % 200);
break;
case 4:
tempX = (int)(sinf(nsp / 60) * 20000);
tempY = (int)(cosf(nsp) * (int)(sinf(nsp / 200) * 300) * 100);
break;
case 5:
tempX = (int)(sinf(nsp / 2) * 20000);
tempY = (int)(cosf(nsp) * (int)(sinf(nsp / 200) * 300) * 100);
break;
case 6:
tempX = (int)(sinf(nsp) * 40000);
tempY = (int)(cosf(nsp) * 20000);
break;
case 8:
tempX = (int)(sinf(nsp / 2) * 40000);
tempY = (int)(cosf(nsp) * 20000);
break;
case 7:
tempX = mt_rand() % 65535;
if ((mt_rand() % 2) == 0)
{
tempY = (int)(cosf(nsp / 80) * 10000) + 15000;
} else {
tempY = 50000 - (int)(cosf(nsp / 80) * 13000);
}
break;
case 9:
nsp2 += nspVar2Inc;
if ((nsp2 == 65535) || (nsp2 == 0))
{
nspVar2Inc = -nspVar2Inc;
}
tempX = (int)(cosf(sinf(nsp2 / 10.0f) + (nsp / 500)) * 32000);
tempY = (int)(sinf(cosf(nsp2 / 10.0f) + (nsp / 500)) * 30000);
break;
case 10:
nsp2 += nspVar2Inc;
if ((nsp2 == 65535) || (nsp2 == 0))
{
nspVar2Inc = -nspVar2Inc;
}
tempX = (int)(cosf(sinf(nsp2 / 5.0f) + (nsp / 100)) * 32000);
tempY = (int)(sinf(cosf(nsp2 / 5.0f) + (nsp / 100)) * 30000);
break;;
case 11:
nsp2 += nspVar2Inc;
if ((nsp2 == 65535) || (nsp2 == 0))
{
nspVar2Inc = -nspVar2Inc;
}
tempX = (int)(cosf(sinf(nsp2 / 1000.0f) + (nsp / 2)) * 32000);
tempY = (int)(sinf(cosf(nsp2 / 1000.0f) + (nsp / 2)) * 30000);
break;
case 12:
if (nsp != 0)
{
nsp2 += nspVar2Inc;
if ((nsp2 == 65535) || (nsp2 == 0))
{
nspVar2Inc = -nspVar2Inc;
}
tempX = (int)(cosf(sinf(nsp2 / 2.0f) / (sqrtf(fabsf(nsp)) / 10.0f + 1) + (nsp2 / 100.0f)) * 32000);
tempY = (int)(sinf(cosf(nsp2 / 2.0f) / (sqrtf(fabsf(nsp)) / 10.0f + 1) + (nsp2 / 100.0f)) * 30000);
}
break;
case 13:
if (nsp != 0)
{
nsp2 += nspVar2Inc;
if ((nsp2 == 65535) || (nsp2 == 0))
{
nspVar2Inc = -nspVar2Inc;
}
tempX = (int)(cosf(sinf(nsp2 / 10.0f) / 2 + (nsp / 20)) * 32000);
tempY = (int)(sinf(sinf(nsp2 / 11.0f) / 2 + (nsp / 20)) * 30000);
}
break;
case 14:
nsp2 += nspVar2Inc;
tempX = (int)((sinf(nsp) + cosf(nsp2 / 1000.0f) * 3) * 12000);
tempY = (int)(cosf(nsp) * 10000) + nsp2;
break;
}
}
}
// kate: tab-width 4; vim: set noet:

Some files were not shown because too many files have changed in this diff Show More