home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GameStar Special 2004 August
/
GSSH0804.iso
/
Rollenspiele
/
SwordOfFargoal
/
fargoal20030731b.exe
/
fargoal
/
src
/
game.c
< prev
next >
Wrap
C/C++ Source or Header
|
2003-07-31
|
19KB
|
815 lines
/*
TODO:
- Faster healing
- Play in SLOW speed mode, and see how the rendering messes up.
+ Full original gameplay compliance
+ Pass key
- Lets you pass over monsters
+ Instant chest open
+ Instant pit climb
* Pass key is available in Original and Enhanced modes
+ Overlapped character attacking
+ Hide floating damage
+ Free movement on high levels, 18 and lower, the monster sound is
constantly going. It needs to be shut off, or the moves need to be
slowed down a bit for Free mode, or something
+ I guess you already fixed it? I see no problem in level 20.
- Smoother character/tile interaction
DONE:
+ Joystick support
+ Monster movement timing, on DL 1 it seems to be more like 12 of the
player's steps instead of 19. How come? steptime/global_steps timing is
wrong somehow
+ OK, I think I found a good compromise between synchronized and
flexible, and it still gives you 19 steps like it should. Please
verify.
+ Monsters pick up gold
- Does it just disappear?
395 ifp=47andm2=0orp=0thenp=32:goto397
- I think this is just for the screen, to hide the gold so the monster
sprite is clear
+ Monsters who steal gold should run from you
+ Improve battles
+ Adjust level generation to match original, adjust if necessary
+ Add sword level
+ Better random monster movement, walk longer in one direction
+ go through basic monster movement code and check if it does the same,
+ number of mnsters spawned at level creation
+ Light spell can be turned off and on with 'o':
121 gosub113:ifl1=1thenl1=2:print"(home)light off":gosub112:goto42
122 l1=1:gosub211:print"(home)light on":gosub112:goto42
294 gosub113:ifsf=1thensf=0:print"(home)the sword is stolen!!":gosub112:goto296
+ light spell nullifies invisibility spell
377 ifv1=0orl1=1then379
+ Remove rendering related calls from game frame logic
+ Include monster movement sound somehow? It sounds cool, and it indicates
the general speed of the monsters
+ There's some really wonky stuff going on in the window if I use GFX_GDI
under Win32. Something to do with dirty rectangles? It's choppy, and it
glitches the graphics as well. Can't debug without crashing in non-GDI
though
+ C64 code:
- Tag relevent portions of code with the associated C64 code, using a
searchable "C64:" tag. We can then convert this C64 code to C and have
all of the original Sword of Fargoal gameplay rules
+ Smarter monster movement
+ Lateral movement when behind a wall, don't just bunch up in a corner
+ creatures fall into traps
+ rule of spawning humans/creatures. spawn from 1 level below
+ Proper function of Beacon spell, IE:
+ "Beacons are an added tool. When you find a mystical BEACON, pick a
convenient spot and place it there by pressing "+'. Within the BEACON's
square you are invisible to the monsters. From there you can TELEPORT to
the TEMPLE by pressing the FIRE BUTTON ... without wasting a TELEPORT! ANY
other time you TELEPORT using your spells, you will appear at the BEACON
that you placed on that level!!"
+ Should be invisible on a Beacon, monsters shouldn't crowd around
+ Cumulative 0-HP attacks... IE, if you lose zero during a round
then add the current damage you did to the next round and attack all at
once. This will allow for more instant slayings.
+ General game/message timing
+ No escape from being attacked
+ Can't escape in the same direction, or into a wall
OBSOLETE:
- Dice rolling... multiple d6 rolls to determine stats for everything?
- Game Research
- Hitpoints increases per level
- From Lv 1 to Lv 2, test game increased from max of 12HP to 27HP,
and 38HP at Lv 3 (3d6?)
- Rate of health recovery
- Lv 1-3: With 13 HP max, looks like about 10 or 12 seconds per
point near the top of health, and 5 seconds near the middle,
and what at the bottom?
- Rate of monster movement
- Monster strength, damage, amount and type per level, frequency of
spawning
-Types seen
- Lv 1: Werebear, Barbarian, Hobgoblin (blue), Dwarf, Elf
- Speed
- Lv 1: 19 player moves per 1 monster move
- Count
- Lv 1: 4 monsters
- Effect of Skill points
- How do they increase?
- Battle Skill 57 after finishing Lv 1 and defeating about
7 monsters
- Effect of Enchanted Weapon
- Trap damage
- Level generation
- Treasure
- On level 1, counted 5 Golds, 3 Secrets
- Gold added directly to EXP at Temple
- Healing potion doesn't heal fully... looks more like 10-15 HP after
one test on dungeon Lv 2
CONSIDERATIONS:
- Assassins stay visible after fight?
- Don't think so
- Battle adjustments
- Slaying a weak or inferior foe should not add any BS,
or perhaps just 1 BS
- Slaying a monster could add only 1-3 instead of 1-5, maybe even only
1-2
- Slaying a strong or superior foe would allow the full BS range of
1-5
- Advancing an experience level should maybe only add 1-6 BS, or 1-8 BS
NOTES:
Legend of C64 Sword of Fargoal variables: (add more)
a
a() Monster map marker?
a% human monster count
a%() Monster health array?
a$() Creature preposition
a1 Counter for monster spawning?
b Joystick direction
b() Human map marker?
b% Creature monster count
b%() Human health array?
b$() Creature name
b1 Beacon is placed
be Beacon spell count
bs Battle skill
c Monster ID?
c() sword level positions
c$() Human preposition
cl clear map after teleport
d
d() Directions <-> Number conversion
d%
d%()
d$() Human name
de
e Experience
el Level
ep Experience peak (for next level)
f
fa Drift spell count
fl
fr Fire button
g% hidden gold stashes
gd gold stashes count
h% Currently fighting monster health
h() sword level dirs
h1 Temporary, hit damage, starting HP, etc.
hi
hp Healing potions
ht Hit points
i1 Counter for treasure maps
iv Invisible spell count
j
j%()
jv Joystick value
k Current tile
l Dungeon level
l% Monster level?
l%() Monster level array?
l1 Light spell active
lg Light spell count
lo
m
m%() Monster position (creatures)
m2 1 = creature, 0 = human
mk Monsters killed
n
n%() Monster position (humans)
o
o%() Monster colour array
p
pt pit depth
q Player position
p1
pl Enchanted weapon count
ql Quest Level, the level the sword is on
r trap type
r() room positions
r%
rg Regeneration spell count
r1
r2
s Spawn time?
s% Monster Skill
s%() Monster Skill Array
s1 Shield spell active
so sound related?
s2 "
s3 "
s4 "
s5 "
s6 "
sa%() "
sb%() "
sf Have the Sword of Fargoal
sh Shield spell count
sk
sn sprite number?
sp Healing counter
sr Start game
sr%
ss%()
st%()
t%() Map array
t Treasure(=gold)
t1 Max gold carry (increases by 100 per sack)
t2 Timer?
t3 Timer?
th Total hit points
ti Timer?
tm Total map count
tn%()
tp Teleport spell count
tr%(,)
u% number of spawnpoints - 1
v() Opposite directions
v% Spawning monster level
v%() Spawn positions
v% general variable?
v1 Invisible spell active
v3
w%
x Temporary
x%
x()
x2 Temporary?
y
y%
y()
y1
z
*/
#include "main.h"
#include "map.h"
#include "game.h"
#include "gfx.h"
#include "scroller.h"
SAMPLE *human[7];
SAMPLE *creature[7];
SAMPLE *boom;
SAMPLE *crash;
SAMPLE *gold;
SAMPLE *pit;
SAMPLE *spell;
SAMPLE *step;
SAMPLE *attack;
SAMPLE *teleport;
SAMPLE *beacon;
SAMPLE *potion;
SAMPLE *ding;
SAMPLE *victory;
SAMPLE *up;
SAMPLE *down;
SAMPLE *climb;
SAMPLE *fight;
SAMPLE *item;
SAMPLE *levelup;
SAMPLE *intro;
SAMPLE *sacrifice;
SAMPLE *slain;
SAMPLE *crunch;
SAMPLE *monstermove;
int extensions_nomonsterpause = 1;
int extensions_balance = 1;
int extensions_monsteraction = 1;
int extensions_controls = 1;
int extensions_overlapfight = 1;
int extensions_dungeons = 1;
int extensions_speed = 1;
int notrunning = 1;
int won = 0;
int gameover = 0;
int spiral_map = 0;
int swordrun = 0;
int global_steps = 0; /* Step counter to trigger monster movement. */
int stepcount = 0;
int quest_number = 0;
/* The global paused state, to halt the game during messages. */
int paused = 0;
static int stats_redraw = 1;
#define try_load_sample(__s, __n) \
__s = load_sample (__n); \
if (!__s) \
{ \
printf ("Could not find %s.\n", __n); \
return 1; \
}
void
game_alt_tab (void)
{
update_stats ();
DR_add (0, -8, MAP_W - 1, MAP_H - 1);
}
int
game_init (void)
{
try_load_sample (human[0], "sfx/chop.wav");
try_load_sample (human[1], "sfx/clang.wav");
try_load_sample (human[2], "sfx/ugh.wav"); //ouch
try_load_sample (human[3], "sfx/thump.wav"); //thud
try_load_sample (human[4], "sfx/clink.wav");
try_load_sample (human[5], "sfx/shriek.wav");
try_load_sample (human[6], "sfx/slash.wav");
creature[0] = human[2]; //ugh
try_load_sample (creature[1], "sfx/claw.wav");
try_load_sample (creature[2], "sfx/crunch.wav");
try_load_sample (creature[3], "sfx/gnarl.wav");
creature[4] = creature[3]; //growl
try_load_sample (creature[5], "sfx/shred.wav");
creature[6] = human[3]; //thump
try_load_sample (boom, "sfx/boom.wav");
try_load_sample (crash, "sfx/crash.wav");
try_load_sample (gold, "sfx/gold.wav");
try_load_sample (pit, "sfx/pit.wav");
try_load_sample (spell, "sfx/spell.wav");
try_load_sample (step, "sfx/step.wav");
try_load_sample (attack, "sfx/attack.wav");
try_load_sample (teleport, "sfx/teleport.wav");
try_load_sample (beacon, "sfx/beacon.wav");
try_load_sample (potion, "sfx/potion.wav");
try_load_sample (ding, "sfx/ding.wav");
try_load_sample (victory, "sfx/victory.wav");
try_load_sample (up, "sfx/up.wav");
try_load_sample (down, "sfx/down.wav");
try_load_sample (climb, "sfx/climb.wav");
try_load_sample (fight, "sfx/fight.wav");
try_load_sample (item, "sfx/item.wav");
try_load_sample (levelup, "sfx/levelup.wav");
try_load_sample (intro, "sfx/intro.wav");
try_load_sample (sacrifice, "sfx/sacrifice.wav");
try_load_sample (slain, "sfx/slain.wav");
try_load_sample (monstermove, "sfx/move.wav");
crunch = creature[2];
if (graphics_init ())
return 1;
chars_init ();
map_init ();
return 0;
}
void
game_original (int health, int skill)
{
// 26 next:w%=0:gosub175:ifsr=1thensr=0:print"your quest begins!!";:goto28
char_num = 1;
player_create (0, 0, health, skill);
swordlev = rnd (15, 20);
game_start_new ();
}
/*
void
game_enhanced1 (void)
{
swordlev = rnd (40, 50);
game_start_new ();
}
void
game_enhanced2 (void)
{
swordlev = 100;
game_start_new ();
}
*/
void
game_start_new (void)
{
list[1].current_level = 1;
list[1].lev = 1;
paused = 0;
messages_init (NULL);
message (FPS * 1, intro, "Your quest begins!!");
gameover = 0;
won = 0;
notrunning = 0;
swordrun = 0;
monster_strength = 0;
map_enter (SPOT_VOID, 0);
}
void
game_continue (void)
{
// 27 print"your quest continues!"
{
paused = 0;
if (gameover)
message (FPS * 1, NULL, "Thou hast already failed in thy quest.");
else if (won)
message (FPS * 1, NULL, "Thou hast already completed thy quest!!");
else
message (FPS * 1, NULL, "Your quest continues!");
update_stats ();
DR_add (0, -6, MAP_W - 1, MAP_H - 1);
}
}
void
game_exit (void)
{
}
static int hitx[10], hity[10];
static int hitv[10], hitt[10];
void
add_hit (int mx, int my, int v)
{
int i;
if (!extensions_overlapfight)
return;
for (i = 0; i < 10; i++)
{
if (!hitt[i])
{
hitx[i] = mx * tw + tw / 2;
hity[i] = TOP + my * th - th;
hitv[i] = v;
hitt[i] = FPS;
return;
}
}
return;
}
static void
_fly_hits (void)
{
int i;
for (i = 0; i < 10; i++)
{
if (hitt[i])
{
hity[i]--;
hitt[i]--;
DR_add (hitx[i] / tw - 1, (hity[i] - TOP) / th - 1, hitx[i] / tw + 1, (hity[i] - TOP) / th + 1);
}
}
}
static void
_draw_hits (void)
{
int i;
text_mode (-1);
for (i = 0; i < 10; i++)
{
if (hitt[i])
{
if (hitv[i])
textprintf_centre (page, font, hitx[i], hity[i], hitv[i] < 0 ? makecol (255, 0, 0) : makecol (0, 200, 0), "%i", abs (hitv[i]));
}
}
}
void
update_stats (void)
{
stats_redraw = 1;
}
int get_steptime()
{
if(extensions_speed)
return STEPTIME;
return STEPTIME*2;
}
void
game_frame (void)
{
int i;
#if defined(DEBUGMODE) || defined(_DEBUG)
if (key[KEY_F1])
clear_to_color (screen, makecol (255, 0, 0));
if (key[KEY_F2])
clear_to_color (page, makecol (0, 255, 0));
if (key[KEY_F3])
{
gameover = 1;
spiral_map = MAP_W * MAP_H / 2;
}
if (key[KEY_F4])
{
map_hide_completely ();
gameover = 0;
}
if (key[KEY_F5])
{
swordrun=5 * FPS;
}
if (key[KEY_F6])
{
swordrun=SWORD_TIME;
}
#endif
messages_update ();
if (!gameover && !won)
{
player_process (1); /* 1 = id of player object */
}
else
{
if (spiral_map && frames % 2 == 0)
{
int x = 0, y = MAP_H;
int dx = 0, dy = -1;
int spiral_steps = MAP_W * MAP_H / 2 - spiral_map;
int w = MAP_W - 1, h = MAP_H;
int row = w, column = h;
for (i = 0; i <= spiral_steps; i++)
{
if (dx)
{
if (row)
row--;
else
{
dy = dx;
dx = 0;
h -= 2;
column = h;
}
}
if (dy)
{
if (column)
column--;
else
{
dx = -dy;
dy = 0;
w -= 2;
row = w;
}
}
x += dx;
y += dy;
}
map_seen (x, y, 0);
map_seen (MAP_W - 1 - x, MAP_H - 1 - y, 0);
spiral_map--;
}
}
if (won)
{
won++;
if (won > FPS * 5)
{
won = 1;
scroller_init ();
}
}
if (stepcount)
{
if (!list[1].fighting && !paused)
stepcount--;
}
else
{
stepcount = get_steptime();
if (global_steps)
global_steps--;
}
if (!global_steps)
{
monsters_spawn ();
if(monster_count())
message(extensions_nomonsterpause ? 0 : get_steptime()*2, monstermove, NULL);
}
for (i = 2; i < char_num; i++)
{
monster_process (i);
}
if (!global_steps)
{
global_steps = MAX (1, 20 - list[1].current_level);
stepcount = extensions_nomonsterpause ?
(extensions_speed ? FPS : FPS*2) :
get_steptime();
}
if (!won && !gameover && swordrun)
{
swordrun--;
if ((swordrun % FPS) == 0)
update_stats();
if (!swordrun)
{
// 411 print"(down)(down)out of time!"
map_hide_completely();
message (FPS*3.5, crash, "Out of time!");
map_crash();
message(FPS, slain, "Game Over");
player_die (1);
}
}
_fly_hits ();
}
void
game_render (void)
{
int spellbook_x = 500;
int spellbook_y = SCREEN_H - 90 + 15;
int inventory_x = 340;
int inventory_y = SCREEN_H - 90 + 15;
int stats_x = 10;
int stats_y = SCREEN_H - 90 + 15;
int info_x = 180;
int info_y = SCREEN_H - 90 + 15;
text_mode (-1);
messages_render ();
map_draw ();
if (stats_redraw || map_check_DRs (0, -3, MAP_W - 1, -3))
{
blit (title, page, 30, TOP - 3 * th, 30, TOP - 3 * th, 120, 8);
textprintf (page, font, 30, 54,
list[1].hit < list[1].maxhit ?
list[1].hit < list[1].maxhit / 3 ?
layout_color (LC_HURT) :
layout_color (LC_HEALTH) :
layout_color (LC_HEALTHY),
"Hits: %i/%i", list[1].hit, list[1].maxhit);
blit (title, page, 280, 54, 280, 54, 80, 8);
textprintf_centre (page, font, 320, 54, layout_color (LC_GOLD),
"Gold: %i", list[1].gold);
if (swordrun)
{
int seconds = (swordrun - 1) / FPS;
int blink = seconds & 1;
blit (title, page, 0, 40, 0, 40, SCREEN_W, 8);
blit (title, page, 480, 54, 480, 54, 130, 8);
textprintf_right (page, font, SCREEN_W - 30, 40,
blink ? layout_color (LC_TIME) :
layout_color (LC_BLINK), "%s", list[1].sword ? "Carrying sword"
: "Sword stolen");
textprintf_right (page, font, SCREEN_W - 30, 54,
blink ? layout_color (LC_TIME) :
layout_color (LC_BLINK), "Time left %02i:%02i", seconds / 60, seconds % 60);
}
}
_draw_hits ();
if (stats_redraw)
{
blit (title, page, 0, SCREEN_H - 90, 0, SCREEN_H - 90, SCREEN_W, 90);
/* Print stats. */
textprintf (page, font, stats_x, stats_y, layout_color (LC_STATS),
"Experience %i", list[1].exp);
textprintf (page, font, stats_x, stats_y + 22, layout_color (LC_STATS),
"Level %i (%i)", list[1].lev, list[1].next);
textprintf (page, font, stats_x, stats_y + 44, layout_color (LC_STATS),
"Skill %i", list[1].dex);
/* Print additional info. */
textprintf (page, font, info_x, info_y, layout_color (LC_INFO),
"Slain foes %7i", list[1].slain_foes[0]);
textprintf (page, font, info_x, info_y + 11, layout_color (LC_INFO),
"Enchanted Sword+%2i", list[1].weapon);
textprintf (page, font, info_x, info_y + 44, layout_color (LC_DUNGEON),
"Dungeon level %3i", list[1].current_level);
textprintf (page, font, info_x, info_y + 55, layout_color (LC_DUNGEON),
"Deepest Descent%3i", list[1].deepest_level);
/* Display spellbook. */
{
int i;
for (i = 0; i < 6; i++)
{
int c = list[1].spells[i].amount ? layout_color (LC_SPELL) : layout_color (LC_NOSPELL);
if (list[1].spells[i].active)
c =layout_color (LC_CAST);
if (i == SPELL_REGENERATION && list[1].amulets_of_healing)
textprintf (page, font, spellbook_x, spellbook_y + i * 11, c,
"%-12s %2i+%i", spell_names[i], list[1].spells[i].amount,
list[1].amulets_of_healing);
else
if (i == SPELL_LIGHT && list[1].amulets_of_light)
textprintf (page, font, spellbook_x, spellbook_y + i * 11, c,
"%-12s %2i+%i", spell_names[i], list[1].spells[i].amount,
list[1].amulets_of_light);
else
textprintf (page, font, spellbook_x, spellbook_y + i * 11, c,
"%-12s %2i", spell_names[i], list[1].spells[i].amount);
}
}
/* Display inventory. */
textprintf (page, font, inventory_x, inventory_y, list[1].beaconx ? layout_color (LC_BEACON) : list[1].beacons ? layout_color (LC_BEACON) : layout_color (LC_EMPTY),
"Beacons %2i", list[1].beacons);
textprintf (page, font, inventory_x, inventory_y + 22, list[1].sacks ? layout_color (LC_SACKS) : layout_color (LC_EMPTY),
"Magic sacks %2i", list[1].sacks);
textprintf (page, font, inventory_x, inventory_y + 44, list[1].potions ? layout_color (LC_POTIONS) : layout_color (LC_NOPOTIONS),
"Healing potions %2i", list[1].potions);
}
if (USE_DRS)
{
acquire_screen ();
map_blit_DRs ();
if (messages_updated ())
{
blit (page, screen, 0, 0, 0, 0, SCREEN_W, 18);
}
if (stats_redraw)
{
if (swordrun)
blit (page, screen, 0, 40, 0, 40, SCREEN_W, 8);
blit (page, screen, 0, 54, 0, 54, SCREEN_W, 8);
blit (page, screen, 0, SCREEN_H - 90, 0, SCREEN_H - 90, SCREEN_W, 90);
stats_redraw = 0;
}
release_screen ();
}
else
{
DR_n = 0;
blit (page, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
}
}