dos33fsprogs/gr-sim/tfv/tfv_battle.c

1655 lines
26 KiB
C
Raw Normal View History

2017-08-13 19:38:49 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
2018-06-30 17:44:51 +00:00
#include <math.h>
2017-08-13 19:38:49 +00:00
#include "gr-sim.h"
#include "tfv_utils.h"
#include "tfv_zp.h"
#include "tfv_defines.h"
2018-07-07 19:18:08 +00:00
#include "tfv_definitions.h"
2017-08-13 19:38:49 +00:00
#include "tfv_sprites.h"
#include "tfv_backgrounds.h"
/* Do Battle */
2017-08-16 18:46:45 +00:00
2018-07-03 01:52:33 +00:00
/* Metrocat (summon?) */
2017-08-16 18:46:45 +00:00
2018-06-28 04:19:06 +00:00
/* Environment: grass, beach, forest, ice */
/* Enemies: HP ATTACK WEAKNESS RESIST */
/* Killer Crab RND-32 PINCH MALAISE FIRE
Plain Fish BUBBLE FIRE ICE
Evil Tree RND-16 LEAVE FIRE ICE
2018-06-29 00:44:32 +00:00
Wood Elf SING MALAISE BOLT
2018-06-28 04:19:06 +00:00
Giant Bee RND-64 BUZZSAW ICE NONE
Procrastinon RND-32 PUTOFF NONE MALAISE
Ice Fish RND-32 AUGER FIRE ICE
EvilPenguin WADDLE FIRE ICE
*/
2017-08-16 18:46:45 +00:00
2017-08-13 19:38:49 +00:00
/* Battle.
Forest? Grassland? Artic? Ocean?
2018-06-28 04:19:06 +00:00
ATTACK REST
MAGIC LIMIT
SUMMON RUN
2017-08-13 19:38:49 +00:00
2018-07-12 18:04:05 +00:00
SUMMONS -> METROCAT VORTEXCN
2018-06-28 04:19:06 +00:00
MAGIC -> HEAL FIRE
ICE MALAISE
2018-06-29 00:44:32 +00:00
BOLT
2018-06-28 04:19:06 +00:00
LIMIT -> SLICE ZAP
2018-07-12 18:04:05 +00:00
DROP
2017-08-13 19:38:49 +00:00
1 2 3
0123456789012345678901234567890123456789|
----------------------------------------|
| HP LIMIT | -> FIGHT/LIMIT 21
KILLER CRAB | DEATER 128/255 128 | ZAP 22
| | REST 23
| | RUN AWAY 24
Sound effects?
List hits
****** ** **** **** ** ** ****** **** ****** ****** ******
** ** **** ** ** ** ** ** ** ** ** ** ** **
** ** ** **** **** ****** **** ****** ** ****** ******
** ** ** ** ** ** ** ** ** ** ** ** **
****** ****** ****** **** ** **** ****** ** ****** **
*/
static int battle_bar=0;
2018-07-18 04:53:38 +00:00
static int susie_out=0;
2017-08-13 19:38:49 +00:00
/* Background depend on map location? */
/* Room for guinea pig in party? */
/* Attacks -> HIT, ZAP, HEAL, RUNAWAY */
2018-06-28 04:19:06 +00:00
#define MAGIC_NONE 0
#define MAGIC_FIRE 1
#define MAGIC_ICE 2
#define MAGIC_MALAISE 4
2018-06-29 00:44:32 +00:00
#define MAGIC_BOLT 8
2018-06-29 04:02:40 +00:00
#define MAGIC_HEAL 16
2018-06-28 04:19:06 +00:00
struct enemy_type {
char *name;
int hp_base,hp_mask;
char *attack_name;
int weakness,resist;
unsigned char *sprite;
};
2018-07-18 04:53:38 +00:00
static struct enemy_type enemies[9]={
2018-06-28 04:19:06 +00:00
[0]= {
.name="Killer Crab",
2018-07-03 04:37:15 +00:00
.hp_base=50,
2018-06-28 04:19:06 +00:00
.hp_mask=0x1f,
.attack_name="Pinch",
.weakness=MAGIC_MALAISE,
.resist=MAGIC_FIRE,
.sprite=killer_crab,
},
2018-06-29 00:44:32 +00:00
[1]= {
.name="Plain Fish",
.hp_base=10,
.hp_mask=0x1f,
.attack_name="Bubble",
.weakness=MAGIC_FIRE,
.resist=MAGIC_ICE,
2018-07-09 03:50:16 +00:00
.sprite=plain_fish,
2018-06-29 00:44:32 +00:00
},
[2]= {
.name="Evil Tree",
.hp_base=10,
.hp_mask=0x1f,
.attack_name="Leaves",
.weakness=MAGIC_FIRE,
.resist=MAGIC_ICE,
2018-07-09 03:50:16 +00:00
.sprite=evil_tree,
2018-06-29 00:44:32 +00:00
},
[3]= {
.name="Wood Elf",
.hp_base=10,
.hp_mask=0x1f,
.attack_name="Song",
.weakness=MAGIC_MALAISE,
2018-06-29 04:02:40 +00:00
.resist=MAGIC_BOLT|MAGIC_HEAL,
2018-07-09 03:50:16 +00:00
.sprite=wood_elf,
2018-06-29 00:44:32 +00:00
},
[4]= {
.name="Giant Bee",
.hp_base=10,
.hp_mask=0x1f,
.attack_name="Buzzsaw",
.weakness=MAGIC_ICE,
.resist=MAGIC_NONE,
2018-07-09 03:50:16 +00:00
.sprite=giant_bee,
2018-06-29 00:44:32 +00:00
},
[5]= {
.name="Procrastinon",
.hp_base=10,
.hp_mask=0x1f,
.attack_name="Putoff",
.weakness=MAGIC_NONE,
.resist=MAGIC_MALAISE,
2018-07-09 03:50:16 +00:00
.sprite=procrastinon,
2018-06-29 00:44:32 +00:00
},
[6]= {
.name="Ice Fish",
.hp_base=10,
.hp_mask=0x1f,
.attack_name="Auger",
.weakness=MAGIC_FIRE,
.resist=MAGIC_ICE,
2018-07-09 03:50:16 +00:00
.sprite=ice_fish,
2018-06-29 00:44:32 +00:00
},
[7]= {
.name="Evil Penguin",
.hp_base=10,
.hp_mask=0x1f,
.attack_name="Waddle",
.weakness=MAGIC_FIRE,
.resist=MAGIC_ICE,
2018-07-09 03:50:16 +00:00
.sprite=evil_penguin,
2018-06-29 00:44:32 +00:00
},
2018-07-18 04:53:38 +00:00
[8]= {
.name="Act.Principl",
.hp_base=10,
.hp_mask=0x1f,
.attack_name="BIRDIE",
.weakness=MAGIC_NONE,
.resist=MAGIC_ICE|MAGIC_FIRE,
.sprite=roboknee1,
},
2018-06-28 04:19:06 +00:00
};
2018-06-30 19:38:03 +00:00
static int gr_put_num(int xx,int yy,int number) {
int xt=xx,digit,left,hundreds;
digit=number/100;
if ((digit) && (digit<10)) {
grsim_put_sprite(numbers[digit],xt,yy);
2018-07-12 18:04:05 +00:00
xt+=4;
2018-06-30 19:38:03 +00:00
}
hundreds=digit;
left=number%100;
digit=left/10;
if ((digit) || (hundreds)) {
grsim_put_sprite(numbers[digit],xt,yy);
2018-07-12 18:04:05 +00:00
xt+=4;
2018-06-30 19:38:03 +00:00
}
left=number%10;
digit=left;
grsim_put_sprite(numbers[digit],xt,yy);
return 0;
}
2018-07-03 01:52:33 +00:00
/*
ATTACK SKIP
MAGIC LIMIT
SUMMON ESCAPE
2018-07-12 18:04:05 +00:00
SUMMONS -> METROCAT VORTEXCN
2018-07-03 01:52:33 +00:00
MAGIC -> HEAL FIRE
ICE MALAISE
BOLT
LIMIT -> SLICE ZAP
2018-07-12 18:04:05 +00:00
DROP
2018-07-03 01:52:33 +00:00
State Machine
time
BOTTOM -------> MAIN_MENU ----->ATTACK
------->SKIP
------->MAGIC_MENU
------->LIMIT_MENU
------->SUMMON_MENU
------->ESCAPE
*/
#define MENU_NONE 0
#define MENU_MAIN 1
2018-07-03 03:20:21 +00:00
#define MENU_MAGIC 2
#define MENU_SUMMON 3
#define MENU_LIMIT 4
2018-07-03 03:20:21 +00:00
static int enemy_attacking=0;
static int menu_state=MENU_NONE;
static int menu_position=0;
static int battle_count=0;
2018-07-03 01:52:33 +00:00
static int draw_battle_bottom(int enemy_type) {
int i;
clear_bottom();
vtab(22);
htab(1);
move_cursor();
print(enemies[enemy_type].name);
2018-07-03 03:20:21 +00:00
if (enemy_attacking) {
vtab(24);
htab(2);
move_cursor();
print_inverse(enemies[enemy_type].attack_name);
2018-07-03 01:52:33 +00:00
}
vtab(22);
htab(15);
move_cursor();
// should print "NAMEO"
// print("DEATER");
print(nameo);
2018-07-03 03:20:21 +00:00
if (susie_out) {
vtab(23);
htab(15);
move_cursor();
print("SUSIE");
}
2018-07-18 04:53:38 +00:00
2018-07-03 03:20:21 +00:00
if (menu_state==MENU_NONE) {
2018-07-18 04:53:38 +00:00
/* TFV Stats */
2018-07-03 03:20:21 +00:00
vtab(21);
htab(25);
move_cursor();
print("HP");
vtab(21);
htab(28);
move_cursor();
print("MP");
vtab(21);
htab(31);
move_cursor();
print("TIME");
vtab(21);
htab(36);
move_cursor();
if (limit<4) {
print("LIMIT");
}
else {
/* Make if flash? set bit 0x40 */
print_flash("LIMIT");
}
2018-07-03 01:52:33 +00:00
2018-07-03 03:20:21 +00:00
vtab(22);
htab(24);
move_cursor();
print_byte(hp);
vtab(22);
htab(27);
move_cursor();
print_byte(mp);
2018-07-03 01:52:33 +00:00
2018-07-03 03:20:21 +00:00
/* Draw Time bargraph */
// printf("Battle_bar=%d Limit=%d\n",battle_bar,limit);
ram[COLOR]=0xa0;
hlin_double(ram[DRAW_PAGE],30,34,42);
ram[COLOR]=0x20;
if (battle_bar) {
hlin_double(ram[DRAW_PAGE],30,30+(battle_bar-1),42);
}
2018-07-03 01:52:33 +00:00
2018-07-03 03:20:21 +00:00
/* Draw Limit break bargraph */
ram[COLOR]=0xa0;
hlin_double(ram[DRAW_PAGE],35,39,42);
2018-07-03 01:52:33 +00:00
2018-07-03 03:20:21 +00:00
ram[COLOR]=0x20;
if (limit) hlin_double(ram[DRAW_PAGE],35,35+limit,42);
2018-07-18 04:53:38 +00:00
/* Susie Stats */
if (susie_out) {
vtab(23);
htab(24);
move_cursor();
print_byte(255);
vtab(23);
htab(27);
move_cursor();
print_byte(0);
#if 0
/* Draw Time bargraph */
ram[COLOR]=0xa0;
hlin_double(ram[DRAW_PAGE],30,34,42);
ram[COLOR]=0x20;
if (battle_bar) {
hlin_double(ram[DRAW_PAGE],30,30+(battle_bar-1),42);
}
/* Draw Limit break bargraph */
ram[COLOR]=0xa0;
hlin_double(ram[DRAW_PAGE],35,39,42);
ram[COLOR]=0x20;
if (limit) hlin_double(ram[DRAW_PAGE],35,35+limit,42);
#endif
}
2018-07-03 03:20:21 +00:00
}
if (menu_state==MENU_MAIN) {
2018-07-14 02:29:10 +00:00
if (limit>3) {
if (menu_position>5) menu_position=5;
}
else {
if (menu_position>4) menu_position=4;
}
2018-07-03 03:20:21 +00:00
vtab(21);
htab(24);
move_cursor();
if (menu_position==0) print_inverse("ATTACK");
else print("ATTACK");
vtab(22);
htab(24);
move_cursor();
if (menu_position==2) print_inverse("MAGIC");
else print("MAGIC");
vtab(23);
htab(24);
move_cursor();
if (menu_position==4) print_inverse("SUMMON");
else print("SUMMON");
vtab(21);
htab(32);
move_cursor();
if (menu_position==1) print_inverse("SKIP");
else print("SKIP");
vtab(22);
htab(32);
move_cursor();
if (menu_position==3) print_inverse("ESCAPE");
2018-07-03 03:20:21 +00:00
else print("ESCAPE");
if (limit>3) {
vtab(23);
htab(32);
move_cursor();
if (menu_position==5) print_inverse("LIMIT");
else print("LIMIT");
}
2018-07-03 03:20:21 +00:00
}
if (menu_state==MENU_SUMMON) {
2018-07-14 02:29:10 +00:00
if (menu_position>1) menu_position=1;
2018-07-03 03:20:21 +00:00
vtab(21);
htab(25);
move_cursor();
print("SUMMONS:");
vtab(22);
htab(25);
move_cursor();
if (menu_position==0) print_inverse("METROCAT");
else print("METROCAT");
2018-07-12 18:04:05 +00:00
2018-07-13 15:46:15 +00:00
vtab(23);
htab(25);
2018-07-12 18:04:05 +00:00
move_cursor();
if (menu_position==1) print_inverse("VORTEXCN");
else print("VORTEXCN");
2018-07-03 03:20:21 +00:00
}
if (menu_state==MENU_MAGIC) {
2018-07-14 02:29:10 +00:00
if (menu_position>4) menu_position=4;
2018-07-03 03:20:21 +00:00
vtab(21);
htab(24);
move_cursor();
print("MAGIC:");
vtab(22);
htab(25);
move_cursor();
if (menu_position==0) print_inverse("HEAL");
else print("HEAL");
vtab(23);
htab(25);
move_cursor();
if (menu_position==2) print_inverse("ICE");
else print("ICE");
vtab(24);
htab(25);
move_cursor();
if (menu_position==4) print_inverse("BOLT");
else print("BOLT");
vtab(22);
htab(32);
move_cursor();
if (menu_position==1) print_inverse("FIRE");
else print("FIRE");
vtab(23);
htab(32);
move_cursor();
if (menu_position==3) print_inverse("MALAISE");
else print("MALAISE");
}
if (menu_state==MENU_LIMIT) {
2018-07-14 02:29:10 +00:00
if (menu_position>2) menu_position=2;
2018-07-03 03:20:21 +00:00
vtab(21);
htab(24);
move_cursor();
print("LIMIT BREAKS:");
vtab(22);
htab(25);
move_cursor();
if (menu_position==0) print_inverse("SLICE");
else print("SLICE");
vtab(23);
htab(25);
move_cursor();
if (menu_position==2) print_inverse("DROP");
else print("DROP");
vtab(22);
htab(32);
move_cursor();
if (menu_position==1) print_inverse("ZAP");
else print("ZAP");
}
2018-07-03 01:52:33 +00:00
/* Draw inverse separator */
ram[COLOR]=0x20;
for(i=40;i<50;i+=2) {
hlin_double(ram[DRAW_PAGE],12,12,i);
}
// ram[DRAW_PAGE]=saved_page;
return 0;
}
2018-06-28 04:19:06 +00:00
2018-07-03 03:20:21 +00:00
static int enemy_hp=0,enemy_type=0,enemy_x=0;
static int damage_enemy(int value) {
if (enemy_hp>value) enemy_hp-=value;
else enemy_hp=0;
return 0;
}
2018-07-03 04:37:15 +00:00
static int heal_self(int value) {
hp+=value;
if (hp>max_hp) hp=max_hp;
return 0;
}
2018-07-03 03:20:21 +00:00
static int damage_tfv(int value) {
if (hp>value) hp-=value;
else hp=0;
return 0;
}
static int attack(void) {
2018-06-28 04:19:06 +00:00
int ax=34;
2018-06-30 19:38:03 +00:00
int damage=10;
2018-06-28 04:19:06 +00:00
while(ax>10) {
gr_copy_to_current(0xc00);
if (ax&1) {
grsim_put_sprite(tfv_stand_left,ax,20);
}
else {
grsim_put_sprite(tfv_walk_left,ax,20);
}
grsim_put_sprite(tfv_led_sword,ax-5,20);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
2018-07-03 01:52:33 +00:00
draw_battle_bottom(enemy_type);
2018-06-28 04:19:06 +00:00
page_flip();
ax-=1;
usleep(20000);
}
2018-07-03 03:20:21 +00:00
damage_enemy(damage);
2018-06-30 19:38:03 +00:00
gr_put_num(2,10,damage);
page_flip();
usleep(250000);
2018-07-03 03:20:21 +00:00
return 0;
2018-06-28 04:19:06 +00:00
}
2018-06-30 19:38:03 +00:00
2018-07-03 03:20:21 +00:00
static int enemy_attack(int tfv_x) {
2018-06-29 04:02:40 +00:00
int ax=enemy_x;
2018-06-30 19:38:03 +00:00
int damage=10;
2018-06-29 04:02:40 +00:00
2018-07-03 03:20:21 +00:00
enemy_attacking=1;
2018-06-29 04:02:40 +00:00
while(ax<30) {
// put attack name on
// occasionally attack with that enemy's power?
// occasionally heal self?
gr_copy_to_current(0xc00);
// draw first so behind enemy
grsim_put_sprite(tfv_stand_left,tfv_x,20);
grsim_put_sprite(tfv_led_sword,tfv_x-5,20);
if (ax&1) {
grsim_put_sprite(enemies[enemy_type].sprite,ax,20);
}
else {
grsim_put_sprite(enemies[enemy_type].sprite,ax,20);
}
2018-07-03 01:52:33 +00:00
draw_battle_bottom(enemy_type);
2018-06-29 04:02:40 +00:00
page_flip();
ax+=1;
usleep(20000);
}
2018-07-03 03:20:21 +00:00
enemy_attacking=0;
2018-06-29 04:02:40 +00:00
2018-07-03 03:20:21 +00:00
damage_tfv(damage);
2018-06-30 19:38:03 +00:00
gr_put_num(25,10,damage);
2018-07-03 03:20:21 +00:00
draw_battle_bottom(enemy_type);
2018-06-30 19:38:03 +00:00
page_flip();
usleep(250000);
return damage;
2018-06-29 04:02:40 +00:00
}
2018-06-28 04:19:06 +00:00
static int victory_dance(void) {
int ax=34;
int i;
int saved_drawpage;
saved_drawpage=ram[DRAW_PAGE];
ram[DRAW_PAGE]=PAGE2; // 0xc00
clear_bottom();
vtab(21);
htab(10);
move_cursor();
print("EXPERIENCE +2");
experience+=2;
vtab(22);
htab(10);
move_cursor();
print("MONEY +1");
money+=1;
ram[DRAW_PAGE]=saved_drawpage;
2018-07-01 02:37:33 +00:00
for(i=0;i<25;i++) {
2018-06-28 04:19:06 +00:00
gr_copy_to_current(0xc00);
if (i&1) {
grsim_put_sprite(tfv_stand_left,ax,20);
2018-07-01 02:37:33 +00:00
grsim_put_sprite(tfv_led_sword,ax-5,20);
2018-06-28 04:19:06 +00:00
}
else {
2018-07-01 02:37:33 +00:00
grsim_put_sprite(tfv_victory,ax,20);
grsim_put_sprite(tfv_led_sword,ax-2,14);
2018-06-28 04:19:06 +00:00
}
page_flip();
2017-08-13 19:38:49 +00:00
2018-07-01 02:37:33 +00:00
usleep(200000);
2018-06-28 04:19:06 +00:00
}
return 0;
}
2018-06-29 04:02:40 +00:00
2018-06-30 17:44:51 +00:00
static int rotate_intro(void) {
int xx,yy,color,x2,y2;
double h,theta,dx,dy,theta2,thetadiff,nx,ny;
int i;
gr_copy(0x400,0xc00);
// gr_copy_to_current(0xc00);
// page_flip();
// gr_copy_to_current(0xc00);
// page_flip();
thetadiff=0;
for(i=0;i<8;i++) {
grsim_update();
for(yy=0;yy<40;yy++) {
for(xx=0;xx<40;xx++) {
dx=(xx-20);
dy=(yy-20);
h=sqrt((dx*dx)+(dy*dy));
theta=atan2(dy,dx);
theta2=theta+thetadiff;
nx=h*cos(theta2);
ny=h*sin(theta2);
x2=nx+20;
y2=ny+20;
if ((x2<0) || (x2>39)) color=0;
else if ((y2<0) || (y2>39)) color=0;
else color=scrn_page(x2,y2,PAGE2);
color_equals(color);
plot(xx,yy);
}
}
thetadiff+=(6.28/16.0);
2018-06-30 17:44:51 +00:00
page_flip();
usleep(100000);
}
return 0;
}
2018-07-03 04:37:15 +00:00
#define MENU_MAGIC_HEAL 0
#define MENU_MAGIC_ICE 1
#define MENU_MAGIC_FIRE 2
#define MENU_MAGIC_MALAISE 3
#define MENU_MAGIC_BOLT 4
2018-07-03 03:20:21 +00:00
static void magic_attack(int which) {
2018-07-03 04:37:15 +00:00
int ax=34,ay=20;
int mx,my;
int damage=20;
int i;
unsigned char *sprite;
if (which==MENU_MAGIC_HEAL) {
sprite=magic_health;
mx=33;
2018-07-03 04:37:15 +00:00
my=20;
}
if (which==MENU_MAGIC_FIRE) {
sprite=magic_fire;
mx=2;
my=20;
}
if (which==MENU_MAGIC_ICE) {
sprite=magic_ice;
mx=2;
my=20;
}
2018-07-09 04:15:57 +00:00
if (which==MENU_MAGIC_BOLT) {
sprite=magic_bolt;
mx=2;
my=20;
}
if (which==MENU_MAGIC_MALAISE) {
sprite=magic_malaise;
mx=2;
my=20;
}
2018-07-03 04:37:15 +00:00
// FIXME: damage based on weakness of enemy
// FIXME: disallow if not enough MP
/* cast the magic */
i=0;
while(i<10) {
gr_copy_to_current(0xc00);
grsim_put_sprite(tfv_victory,34,20);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
draw_battle_bottom(enemy_type);
page_flip();
i++;
usleep(20000);
}
ax=34;
ay=20;
i=0;
/* Actually put the magic */
while(i<=20) {
gr_copy_to_current(0xc00);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
grsim_put_sprite(tfv_stand_left,ax,ay);
grsim_put_sprite(tfv_led_sword,ax-5,ay);
grsim_put_sprite(sprite,mx+(i&1),my);
draw_battle_bottom(enemy_type);
page_flip();
i++;
usleep(100000);
}
mp-=5;
gr_copy_to_current(0xc00);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
grsim_put_sprite(tfv_stand_left,ax,ay);
grsim_put_sprite(tfv_led_sword,ax-5,ay);
draw_battle_bottom(enemy_type);
if (which!=MENU_MAGIC_HEAL) {
damage_enemy(damage);
gr_put_num(2,10,damage);
}
else {
heal_self(damage);
}
draw_battle_bottom(enemy_type);
page_flip();
for(i=0;i<20;i++) {
usleep(100000);
}
2018-07-03 03:20:21 +00:00
}
2018-07-12 18:04:05 +00:00
/* Limit Break "Drop" */
/* Jump into sky, drop down and slice enemy in half */
static void limit_break_drop(void) {
int ax=34,ay=20;
int damage=100;
int i;
while(ay>0) {
gr_copy_to_current(0xc00);
grsim_put_sprite(tfv_stand_left,ax,ay);
grsim_put_sprite(tfv_led_sword,ax-5,ay);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
draw_battle_bottom(enemy_type);
page_flip();
ay-=1;
usleep(20000);
}
ax=10;
ay=0;
/* Falling */
while(ay<=20) {
gr_copy_to_current(0xc00);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
grsim_put_sprite(tfv_stand_left,ax,ay);
grsim_put_sprite(tfv_led_sword,ax-5,ay);
draw_battle_bottom(enemy_type);
color_equals(13);
vlin(0,ay,ax-5);
page_flip();
ay+=1;
usleep(100000);
}
i=0;
while(i<13) {
gr_copy_to_current(0xc00);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
grsim_put_sprite(tfv_stand_left,ax,ay);
grsim_put_sprite(tfv_led_sword,ax-5,ay);
draw_battle_bottom(enemy_type);
color_equals(COLOR_LIGHTGREEN);
vlin(ay,ay+i,ax-5);
page_flip();
i++;
usleep(100000);
}
ax=34;
ay=20;
gr_copy_to_current(0xc00);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
grsim_put_sprite(tfv_stand_left,ax,ay);
grsim_put_sprite(tfv_led_sword,ax-5,ay);
draw_battle_bottom(enemy_type);
color_equals(COLOR_LIGHTGREEN);
vlin(20,33,5);
damage_enemy(damage);
gr_put_num(2,10,damage);
page_flip();
for(i=0;i<20;i++) {
usleep(100000);
}
}
2018-07-12 18:04:05 +00:00
/* Limit Break "Slice" */
/* Run up and slap a bunch with sword */
/* TODO: cause damage value to bounce around more? */
static void limit_break_slice(void) {
2018-07-03 03:20:21 +00:00
2018-07-12 18:04:05 +00:00
int tx=34,ty=20;
int damage=5;
2018-07-03 03:55:24 +00:00
int i;
2018-07-12 18:04:05 +00:00
while(tx>10) {
2018-07-03 03:55:24 +00:00
gr_copy_to_current(0xc00);
2018-07-12 18:04:05 +00:00
grsim_put_sprite(tfv_stand_left,tx,ty);
grsim_put_sprite(tfv_led_sword,tx-5,ty);
2018-07-03 03:55:24 +00:00
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
draw_battle_bottom(enemy_type);
page_flip();
2018-07-12 18:04:05 +00:00
tx-=1;
2018-07-03 03:55:24 +00:00
usleep(20000);
}
2018-07-12 18:04:05 +00:00
/* Slicing */
for(i=0;i<20;i++) {
2018-07-03 03:55:24 +00:00
gr_copy_to_current(0xc00);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
2018-07-12 18:04:05 +00:00
if (i&1) {
grsim_put_sprite(tfv_stand_left,tx,20);
grsim_put_sprite(tfv_led_sword,tx-5,20);
}
else {
grsim_put_sprite(tfv_victory,tx,20);
grsim_put_sprite(tfv_led_sword,tx-2,14);
}
2018-07-03 03:55:24 +00:00
2018-07-12 18:04:05 +00:00
damage_enemy(damage);
gr_put_num(2+(i%2),10+((i%2)*2),damage);
2018-07-03 03:55:24 +00:00
draw_battle_bottom(enemy_type);
page_flip();
usleep(100000);
}
2018-07-12 18:04:05 +00:00
tx=34;
ty=20;
2018-07-03 03:55:24 +00:00
gr_copy_to_current(0xc00);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
2018-07-12 18:04:05 +00:00
grsim_put_sprite(tfv_stand_left,tx,ty);
grsim_put_sprite(tfv_led_sword,tx-5,ty);
2018-07-03 03:55:24 +00:00
draw_battle_bottom(enemy_type);
page_flip();
for(i=0;i<20;i++) {
usleep(100000);
}
2018-07-03 03:20:21 +00:00
}
2018-07-12 18:04:05 +00:00
/* Limit Break "Zap" */
/* Zap with a laser out of the LED sword */
static void limit_break_zap(void) {
2018-07-12 18:04:05 +00:00
int tx=34,ty=20;
int damage=100;
int i;
2018-07-12 18:04:05 +00:00
gr_copy_to_current(0xc00);
2018-07-12 18:04:05 +00:00
/* Draw background */
color_equals(COLOR_AQUA);
vlin(12,24,34);
hlin_double(ram[DRAW_PAGE],28,38,18);
2018-07-12 18:04:05 +00:00
/* Sword in air */
grsim_put_sprite(tfv_victory,tx,20);
grsim_put_sprite(tfv_led_sword,tx-2,14);
2018-07-12 18:04:05 +00:00
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
2018-07-12 18:04:05 +00:00
draw_battle_bottom(enemy_type);
2018-07-12 18:04:05 +00:00
page_flip();
2018-07-12 18:04:05 +00:00
usleep(500000);
2018-07-13 15:46:15 +00:00
for(i=0;i<32;i++) {
gr_copy_to_current(0xc00);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
2018-07-13 15:46:15 +00:00
color_equals(i%16);
2018-07-12 18:04:05 +00:00
hlin_double(ram[DRAW_PAGE],5,30,22);
2018-07-12 18:04:05 +00:00
grsim_put_sprite(tfv_stand_left,tx,ty);
grsim_put_sprite(tfv_led_sword,tx-5,ty);
draw_battle_bottom(enemy_type);
page_flip();
2018-07-13 15:46:15 +00:00
usleep(100000);
}
gr_copy_to_current(0xc00);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
2018-07-12 18:04:05 +00:00
grsim_put_sprite(tfv_stand_left,tx,ty);
grsim_put_sprite(tfv_led_sword,tx-5,ty);
draw_battle_bottom(enemy_type);
damage_enemy(damage);
gr_put_num(2,10,damage);
page_flip();
for(i=0;i<20;i++) {
usleep(100000);
}
2018-07-12 18:04:05 +00:00
}
2018-07-12 18:04:05 +00:00
#define MENU_LIMIT_SLICE 0
#define MENU_LIMIT_ZAP 1
#define MENU_LIMIT_DROP 2
2018-07-12 18:04:05 +00:00
static void limit_break(int which) {
if (which==MENU_LIMIT_DROP) limit_break_drop();
else if (which==MENU_LIMIT_SLICE) limit_break_slice();
else if (which==MENU_LIMIT_ZAP) limit_break_zap();
2018-07-12 18:04:05 +00:00
/* reset limit counter */
limit=0;
}
2018-07-14 02:29:10 +00:00
static void summon_metrocat(void) {
2018-07-03 03:20:21 +00:00
2018-07-09 16:05:24 +00:00
int tx=34,ty=20;
int damage=100;
int i;
int ax=28,ay=2;
i=0;
while(i<30) {
gr_copy_to_current(0xc00);
grsim_put_sprite(tfv_stand_left,tx,ty);
grsim_put_sprite(tfv_led_sword,tx-5,ty);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
grsim_put_sprite(metrocat,ax,ay);
draw_battle_bottom(enemy_type);
page_flip();
i++;
usleep(20000);
}
while(ax>15) {
gr_copy_to_current(0xc00);
grsim_put_sprite(tfv_stand_left,tx,ty);
grsim_put_sprite(tfv_led_sword,tx-5,ty);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
grsim_put_sprite(metrocat,ax,ay);
draw_battle_bottom(enemy_type);
page_flip();
ax-=1;
usleep(20000);
}
while(ax>5) {
gr_copy_to_current(0xc00);
grsim_put_sprite(tfv_stand_left,tx,ty);
grsim_put_sprite(tfv_led_sword,tx-5,ty);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
grsim_put_sprite(metrocat,ax,ay);
draw_battle_bottom(enemy_type);
page_flip();
ay+=1;
ax-=1;
usleep(20000);
}
i=0;
while(i<30) {
gr_copy_to_current(0xc00);
grsim_put_sprite(tfv_stand_left,tx,ty);
grsim_put_sprite(tfv_led_sword,tx-5,ty);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
grsim_put_sprite(metrocat,ax,ay);
draw_battle_bottom(enemy_type);
page_flip();
i++;
usleep(20000);
}
gr_copy_to_current(0xc00);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
grsim_put_sprite(tfv_stand_left,tx,ty);
grsim_put_sprite(tfv_led_sword,tx-5,ty);
draw_battle_bottom(enemy_type);
damage_enemy(damage);
gr_put_num(2,10,damage);
page_flip();
for(i=0;i<20;i++) {
usleep(100000);
}
2018-07-14 02:29:10 +00:00
}
static void summon_vortex_cannon(void) {
int tx=34,ty=20;
int damage=5;
int i;
int ax=20,ay=20;
/* draw the cannon */
i=0;
while(i<30) {
gr_copy_to_current(0xc00);
grsim_put_sprite(tfv_stand_left,tx,ty);
grsim_put_sprite(tfv_led_sword,tx-5,ty);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
grsim_put_sprite(vortex_cannon,ax,ay);
draw_battle_bottom(enemy_type);
page_flip();
i++;
usleep(20000);
}
/* Fire vortices */
ax=20;
for(i=0;i<5;i++) {
while(ax>5) {
gr_copy_to_current(0xc00);
grsim_put_sprite(tfv_stand_left,tx,ty);
grsim_put_sprite(tfv_led_sword,tx-5,ty);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
grsim_put_sprite(vortex_cannon,20,20);
grsim_put_sprite(vortex,ax,24);
draw_battle_bottom(enemy_type);
if (ax<10) {
gr_put_num(2,10,damage);
}
page_flip();
ax-=1;
usleep(50000);
}
damage_enemy(damage);
ax=20;
}
gr_copy_to_current(0xc00);
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
grsim_put_sprite(tfv_stand_left,tx,ty);
grsim_put_sprite(tfv_led_sword,tx-5,ty);
draw_battle_bottom(enemy_type);
page_flip();
for(i=0;i<20;i++) {
usleep(100000);
}
}
static void summon(int which) {
if (which==0) summon_metrocat();
else summon_vortex_cannon();
2018-07-03 03:20:21 +00:00
}
static void done_attack(void) {
// reset battle time
battle_count=0;
menu_state=MENU_NONE;
}
#define MENU_MAIN_ATTACK 0
#define MENU_MAIN_SKIP 1
#define MENU_MAIN_MAGIC 2
#define MENU_MAIN_ESCAPE 3
2018-07-03 03:20:21 +00:00
#define MENU_MAIN_SUMMON 4
#define MENU_MAIN_LIMIT 5
2018-07-03 03:20:21 +00:00
2018-07-12 19:27:32 +00:00
static int running=0;
2018-07-03 03:20:21 +00:00
void menu_keypress(int ch) {
if ((ch==' ') || (ch==13)) {
if (menu_state==MENU_MAIN) {
switch(menu_position) {
case MENU_MAIN_ATTACK:
// attack and decrement HP
attack();
done_attack();
break;
case MENU_MAIN_SKIP:
done_attack();
break;
case MENU_MAIN_MAGIC:
menu_state=MENU_MAGIC;
menu_position=0;
break;
case MENU_MAIN_LIMIT:
menu_state=MENU_LIMIT;
menu_position=0;
break;
case MENU_MAIN_SUMMON:
menu_state=MENU_SUMMON;
menu_position=0;
break;
case MENU_MAIN_ESCAPE:
2018-07-12 19:27:32 +00:00
running=1;
2018-07-03 03:20:21 +00:00
done_attack();
break;
}
}
else if (menu_state==MENU_MAGIC) {
magic_attack(menu_position);
done_attack();
}
else if (menu_state==MENU_LIMIT) {
limit_break(menu_position);
done_attack();
}
else if (menu_state==MENU_SUMMON) {
summon(menu_position);
done_attack();
}
}
if (ch==27) {
menu_state=MENU_MAIN;
menu_position=0;
}
if (ch==APPLE_UP) {
if (menu_position>=2) menu_position-=2;
}
if (ch==APPLE_DOWN) {
menu_position+=2;
}
if (ch==APPLE_RIGHT) {
menu_position++;
}
if (ch==APPLE_LEFT) {
if (menu_position>0) menu_position--;
}
}
2018-06-29 04:02:40 +00:00
2018-07-09 20:47:59 +00:00
int do_battle(int ground_color) {
2018-06-29 04:02:40 +00:00
int i,ch;
int saved_drawpage;
int ax=34;
int enemy_count=30;
int old;
2018-06-29 04:02:40 +00:00
rotate_intro();
2018-07-03 03:20:21 +00:00
battle_count=20;
2018-06-29 04:02:40 +00:00
/* Setup Enemy */
// enemy_type=X
// random, with weight toward proper terrain
// 50% completely random, 50% terrain based?
enemy_type=random_8()%0x7;
2018-06-29 04:02:40 +00:00
enemy_hp=enemies[enemy_type].hp_base+
(rand()&enemies[enemy_type].hp_mask);
saved_drawpage=ram[DRAW_PAGE];
ram[DRAW_PAGE]=PAGE2;
2018-07-03 01:52:33 +00:00
2018-06-28 04:19:06 +00:00
/*******************/
2018-06-28 04:19:06 +00:00
/* Draw background */
/* Draw sky */
color_equals(COLOR_MEDIUMBLUE);
for(i=0;i<10;i++) {
hlin_double(ram[DRAW_PAGE],0,39,i);
}
2018-06-28 04:19:06 +00:00
/* Draw ground */
2018-07-09 20:47:59 +00:00
color_equals(ground_color);
for(i=10;i<40;i++) {
hlin_double(ram[DRAW_PAGE],0,39,i);
}
2018-07-09 20:47:59 +00:00
/* Draw some background images for variety? */
ram[DRAW_PAGE]=saved_drawpage;
2017-08-13 19:38:49 +00:00
2018-07-03 01:52:33 +00:00
draw_battle_bottom(enemy_type);
2018-07-15 23:44:32 +00:00
while(1) {
gr_copy_to_current(0xc00);
if (hp==0) {
grsim_put_sprite(tfv_defeat,ax-2,24);
}
else if (running) {
if (battle_count%2) {
grsim_put_sprite(tfv_stand_right,ax,20);
}
else {
grsim_put_sprite(tfv_walk_right,ax,20);
}
}
else {
grsim_put_sprite(tfv_stand_left,ax,20);
grsim_put_sprite(tfv_led_sword,ax-5,20);
}
grsim_put_sprite(enemies[enemy_type].sprite,enemy_x,20);
draw_battle_bottom(enemy_type);
page_flip();
if (hp==0) {
for(i=0;i<15;i++) usleep(100000);
break;
}
usleep(100000);
ch=grsim_input();
if (ch=='q') return 0;
if (enemy_count==0) {
// attack and decrement HP
enemy_attack(ax);
// update limit count
if (limit<4) limit++;
// reset enemy time. FIXME: variable?
enemy_count=50;
}
else {
enemy_count--;
}
if (battle_count>=64) {
/* TODO: randomly fail at running? */
if (running) {
break;
}
if (menu_state==MENU_NONE) menu_state=MENU_MAIN;
menu_keypress(ch);
} else {
battle_count++;
}
old=battle_bar;
battle_bar=(battle_count/16);
if (battle_bar!=old) draw_battle_bottom(enemy_type);
if (enemy_hp==0) {
victory_dance();
break;
}
}
ram[DRAW_PAGE]=PAGE0;
clear_bottom();
ram[DRAW_PAGE]=PAGE1;
clear_bottom();
running=0;
return 0;
}
int boss_battle(void) {
int i,ch;
int saved_drawpage;
int ax=34;
int enemy_count=30;
int old;
2018-07-18 04:53:38 +00:00
susie_out=1;
2018-07-15 23:44:32 +00:00
rotate_intro();
battle_count=20;
2018-07-18 04:53:38 +00:00
enemy_type=8;
enemy_hp=255;
2018-07-15 23:44:32 +00:00
saved_drawpage=ram[DRAW_PAGE];
ram[DRAW_PAGE]=PAGE2;
/*******************/
/* Draw background */
/* Draw sky */
color_equals(COLOR_BLACK);
for(i=0;i<20;i++) {
hlin_double(ram[DRAW_PAGE],0,39,i);
}
color_equals(COLOR_ORANGE);
for(i=20;i<39;i++) {
2018-07-15 23:44:32 +00:00
hlin_double(ram[DRAW_PAGE],0,39,i);
}
/* Draw horizon */
2018-07-18 04:53:38 +00:00
// color_equals(COLOR_GREY);
// hlin_double(ram[DRAW_PAGE],0,39,10);
2018-07-15 23:44:32 +00:00
ram[DRAW_PAGE]=saved_drawpage;
draw_battle_bottom(enemy_type);
2017-08-13 19:38:49 +00:00
while(1) {
gr_copy_to_current(0xc00);
2017-08-13 19:38:49 +00:00
2018-07-14 03:36:01 +00:00
if (hp==0) {
grsim_put_sprite(tfv_defeat,ax-2,24);
}
else if (running) {
2018-07-12 19:27:32 +00:00
if (battle_count%2) {
grsim_put_sprite(tfv_stand_right,ax,20);
}
else {
grsim_put_sprite(tfv_walk_right,ax,20);
}
}
else {
grsim_put_sprite(tfv_stand_left,ax,20);
grsim_put_sprite(tfv_led_sword,ax-5,20);
}
2017-08-13 19:38:49 +00:00
grsim_put_sprite(susie_left,28,30);
2018-07-18 04:53:38 +00:00
if ((enemy_count&0xf)<4) {
grsim_put_sprite(roboknee1,enemy_x,16);
}
else {
grsim_put_sprite(roboknee2,enemy_x,16);
}
2017-08-13 19:38:49 +00:00
2018-07-03 01:52:33 +00:00
draw_battle_bottom(enemy_type);
2017-09-13 21:10:44 +00:00
page_flip();
2017-08-13 19:38:49 +00:00
2018-07-14 03:36:01 +00:00
if (hp==0) {
for(i=0;i<15;i++) usleep(100000);
break;
}
2018-06-29 04:02:40 +00:00
usleep(100000);
2017-08-13 19:38:49 +00:00
2018-06-29 04:02:40 +00:00
ch=grsim_input();
if (ch=='q') return 0;
if (enemy_count==0) {
// attack and decrement HP
2018-07-03 03:20:21 +00:00
enemy_attack(ax);
2018-06-29 04:02:40 +00:00
// update limit count
if (limit<4) limit++;
2018-07-03 01:52:33 +00:00
// reset enemy time. FIXME: variable?
2018-06-29 04:02:40 +00:00
enemy_count=50;
}
else {
enemy_count--;
}
2018-06-28 04:19:06 +00:00
if (battle_count>=64) {
2018-07-12 19:27:32 +00:00
/* TODO: randomly fail at running? */
if (running) {
break;
}
2018-07-03 03:20:21 +00:00
if (menu_state==MENU_NONE) menu_state=MENU_MAIN;
menu_keypress(ch);
2018-07-03 01:52:33 +00:00
2018-06-29 04:02:40 +00:00
} else {
battle_count++;
2018-06-29 04:02:40 +00:00
}
2018-06-28 04:19:06 +00:00
old=battle_bar;
battle_bar=(battle_count/16);
if (battle_bar!=old) draw_battle_bottom(enemy_type);
2018-07-03 03:20:21 +00:00
if (enemy_hp==0) {
2018-07-18 04:53:38 +00:00
// FIXME?
2018-06-28 04:19:06 +00:00
victory_dance();
break;
}
2018-06-29 04:02:40 +00:00
2017-08-13 19:38:49 +00:00
}
ram[DRAW_PAGE]=PAGE0;
clear_bottom();
ram[DRAW_PAGE]=PAGE1;
clear_bottom();
2017-09-13 21:10:44 +00:00
2018-07-12 19:27:32 +00:00
running=0;
2017-08-13 19:38:49 +00:00
return 0;
}