Basic spell bonuses
This commit is contained in:
parent
f3b3e8b16a
commit
32144640c1
8 changed files with 128 additions and 53 deletions
117
src/boss.c
117
src/boss.c
|
@ -8,8 +8,7 @@
|
|||
#include "boss.h"
|
||||
#include "global.h"
|
||||
#include "stage.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "stagetext.h"
|
||||
|
||||
Boss* create_boss(char *name, char *ani, char *dialog, complex pos) {
|
||||
Boss *buf = malloc(sizeof(Boss));
|
||||
|
@ -34,7 +33,7 @@ void draw_boss_text(Alignment align, float x, float y, const char *text) {
|
|||
}
|
||||
|
||||
void spell_opening(Boss *b, int time) {
|
||||
complex x0 = VIEWPORT_W/2+I*VIEWPORT_H/2;
|
||||
complex x0 = VIEWPORT_W/2+I*VIEWPORT_H/3.5;
|
||||
float f = clamp((time-40.)/60.,0,1);
|
||||
|
||||
complex x = x0 + (VIEWPORT_W+I*35 - x0) * f*(f+1)*0.5;
|
||||
|
@ -70,6 +69,15 @@ void draw_extraspell_bg(Boss *boss, int time) {
|
|||
glBlendEquation(GL_FUNC_ADD);
|
||||
}
|
||||
|
||||
Color boss_healthbar_color(AttackType atype) {
|
||||
switch(atype) {
|
||||
default: case AT_Normal: return rgb(1.00, 1.00, 1.00);
|
||||
case AT_Spellcard: return rgb(1.00, 0.65, 0.65);
|
||||
case AT_SurvivalSpell: return rgb(0.50, 0.50, 1.00);
|
||||
case AT_ExtraSpell: return rgb(1.00, 0.30, 0.20);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_boss(Boss *boss) {
|
||||
draw_animation_p(creal(boss->pos), cimag(boss->pos) + 6*sin(global.frames/25.0), boss->anirow, boss->ani);
|
||||
draw_boss_text(AL_Left, 10, 20, boss->name);
|
||||
|
@ -120,21 +128,7 @@ void draw_boss(Boss *boss) {
|
|||
if(boss->dmg > boss->attacks[i].dmglimit)
|
||||
continue;
|
||||
|
||||
switch(boss->attacks[i].type) {
|
||||
case AT_Normal:
|
||||
glColor3f(1,1,1);
|
||||
break;
|
||||
case AT_Spellcard:
|
||||
glColor3f(1,0.65,0.65);
|
||||
break;
|
||||
case AT_SurvivalSpell:
|
||||
glColor3f(0.5,0.5,1);
|
||||
case AT_ExtraSpell:
|
||||
glColor3f(1.0, 0.3, 0.2);
|
||||
break;
|
||||
default:
|
||||
break; // never happens
|
||||
}
|
||||
parse_color_call(boss_healthbar_color(boss->attacks[i].type), glColor4f);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(-(boss->attacks[i].dmglimit+boss->dmg)*0.5, 1, 0);
|
||||
|
@ -202,6 +196,62 @@ bool boss_is_dying(Boss *boss) {
|
|||
return boss->current && boss->current->endtime && boss->current->type != AT_Move && boss->current - boss->attacks >= boss->acount-1;
|
||||
}
|
||||
|
||||
static void boss_give_spell_bonus(Boss *boss, Attack *a, Player *plr) {
|
||||
bool fail = a->failtime;
|
||||
const char *title = fail ? "Spell failed..." : "Spell cleared!";
|
||||
|
||||
int time_left = max(0, a->starttime + a->timeout - global.frames);
|
||||
|
||||
double sv = a->scorevalue;
|
||||
|
||||
int clear_bonus = 0.5 * sv * !fail;
|
||||
int time_bonus = sv * (time_left / (double)a->timeout);
|
||||
int endurance_bonus = 0;
|
||||
|
||||
if(fail) {
|
||||
time_bonus /= 4;
|
||||
endurance_bonus = sv * 0.1 * ((a->failtime - a->starttime) / (double)a->timeout);
|
||||
}
|
||||
|
||||
int total = time_bonus + endurance_bonus + clear_bonus;
|
||||
player_add_points(plr, total);
|
||||
|
||||
StageTextTable tbl;
|
||||
stagetext_begin_table(&tbl, title, rgb(1, 1, 1), rgb(1, 1, 1), VIEWPORT_W/2, 0,
|
||||
ATTACK_END_DELAY_SPELL * 2, ATTACK_END_DELAY_SPELL / 2, ATTACK_END_DELAY_SPELL);
|
||||
stagetext_table_add_numeric_nonzero(&tbl, "Clear bonus", clear_bonus);
|
||||
stagetext_table_add_numeric(&tbl, "Time bonus", time_bonus);
|
||||
stagetext_table_add_numeric_nonzero(&tbl, "Endurance bonus", endurance_bonus);
|
||||
stagetext_table_add_separator(&tbl);
|
||||
stagetext_table_add_numeric(&tbl, "Total", total);
|
||||
stagetext_end_table(&tbl);
|
||||
}
|
||||
|
||||
void boss_finish_current_attack(Boss *boss) {
|
||||
int delay;
|
||||
|
||||
if(boss->current-boss->attacks >= boss->acount-1) {
|
||||
delay = BOSS_DEATH_DELAY;
|
||||
} else switch(boss->current->type) {
|
||||
// FIXME: what should it be for AT_SurvivalSpell?
|
||||
case AT_Spellcard: delay = ATTACK_END_DELAY_SPELL; break;
|
||||
case AT_ExtraSpell: delay = ATTACK_END_DELAY_EXTRA; break;
|
||||
case AT_Move: delay = 0; break;
|
||||
default: delay = ATTACK_END_DELAY; break;
|
||||
}
|
||||
|
||||
boss->current->endtime = global.frames + delay;
|
||||
boss->current->finished = true;
|
||||
boss->current->rule(boss, EVENT_DEATH);
|
||||
|
||||
boss_kill_projectiles();
|
||||
|
||||
AttackType t = boss->current->type;
|
||||
if(t == AT_Spellcard || t == AT_ExtraSpell || t == AT_SurvivalSpell) {
|
||||
boss_give_spell_bonus(boss, boss->current, &global.plr);
|
||||
}
|
||||
}
|
||||
|
||||
void process_boss(Boss **pboss) {
|
||||
Boss *boss = *pboss;
|
||||
|
||||
|
@ -262,16 +312,14 @@ void process_boss(Boss **pboss) {
|
|||
}
|
||||
}
|
||||
|
||||
if(!boss->current->endtime && (boss->current->type != AT_Move && boss->dmg >= boss->current->dmglimit || time > boss->current->timeout)) {
|
||||
int delay = extra ? ATTACK_END_DELAY_EXTRA : ATTACK_END_DELAY;
|
||||
if(boss->current-boss->attacks >= boss->acount-1)
|
||||
delay = BOSS_DEATH_DELAY;
|
||||
if(boss->current->type == AT_Move) // do not delay if the boss is running away at the end
|
||||
delay = 0;
|
||||
boss->current->endtime = global.frames + delay;
|
||||
boss->current->finished = FINISH_WIN;
|
||||
boss->current->rule(boss, EVENT_DEATH);
|
||||
boss_kill_projectiles();
|
||||
bool timedout = time > boss->current->timeout;
|
||||
|
||||
if(!boss->current->endtime && (boss->current->type != AT_Move && boss->dmg >= boss->current->dmglimit || timedout)) {
|
||||
if(timedout) {
|
||||
boss->current->failtime = global.frames;
|
||||
}
|
||||
|
||||
boss_finish_current_attack(boss);
|
||||
}
|
||||
|
||||
if(boss_is_dying(boss)) {
|
||||
|
@ -284,7 +332,11 @@ void process_boss(Boss **pboss) {
|
|||
}
|
||||
|
||||
if(over) {
|
||||
if(extra && boss->current->finished == FINISH_WIN)
|
||||
if(global.stage->type == STAGE_SPELL && boss->current->type != AT_Move) {
|
||||
stage_gameover();
|
||||
}
|
||||
|
||||
if(extra && boss->current->finished && !boss->current->failtime)
|
||||
spawn_items(boss->pos, Life, 1, NULL);
|
||||
|
||||
boss->dmg = boss->current->dmglimit + 1;
|
||||
|
@ -296,7 +348,6 @@ void process_boss(Boss **pboss) {
|
|||
boss_death(pboss);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void boss_death(Boss **boss) {
|
||||
|
@ -379,8 +430,10 @@ Attack* boss_add_attack(Boss *boss, AttackType type, char *name, float timeout,
|
|||
a->draw_rule = draw_rule;
|
||||
|
||||
a->starttime = global.frames;
|
||||
a->endtime = 0;
|
||||
a->finished = FINISH_NOPE;
|
||||
|
||||
// FIXME: figure out a better value/formula, i pulled this out of my ass
|
||||
a->scorevalue = 500.0 + hp * 0.2;
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
|
13
src/boss.h
13
src/boss.h
|
@ -57,12 +57,6 @@ typedef struct AttackInfo {
|
|||
complex pos_dest;
|
||||
} AttackInfo;
|
||||
|
||||
typedef enum {
|
||||
FINISH_NOPE,
|
||||
FINISH_WIN,
|
||||
FINISH_FAIL
|
||||
} FinishType;
|
||||
|
||||
typedef struct Attack {
|
||||
char *name;
|
||||
|
||||
|
@ -72,9 +66,12 @@ typedef struct Attack {
|
|||
|
||||
int timeout;
|
||||
int dmglimit;
|
||||
FinishType finished;
|
||||
int endtime;
|
||||
|
||||
bool finished;
|
||||
int failtime;
|
||||
double scorevalue;
|
||||
|
||||
BossRule rule;
|
||||
BossRule draw_rule;
|
||||
|
||||
|
@ -112,6 +109,8 @@ void start_attack(Boss *b, Attack *a);
|
|||
Attack* boss_add_attack(Boss *boss, AttackType type, char *name, float timeout, int hp, BossRule rule, BossRule draw_rule);
|
||||
Attack* boss_add_attack_from_info(Boss *boss, AttackInfo *info, char move);
|
||||
|
||||
void boss_finish_current_attack(Boss *boss);
|
||||
|
||||
bool boss_is_dying(Boss *boss); // true if the last attack is over but the BOSS_DEATH_DELAY has not elapsed.
|
||||
void boss_death(Boss **boss);
|
||||
void boss_kill_projectiles(void);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include "taiseigl.h"
|
||||
#include "util.h"
|
||||
|
||||
#define CLR_R 48LL
|
||||
#define CLR_G 32LL
|
||||
|
@ -28,8 +29,9 @@
|
|||
typedef uint64_t Color;
|
||||
typedef int16_t ColorComponent;
|
||||
|
||||
Color rgba(float r, float g, float b, float a);
|
||||
Color rgb(float r, float g, float b);
|
||||
Color rgba(float r, float g, float b, float a) __attribute__((const));
|
||||
Color rgb(float r, float g, float b) __attribute__((const));
|
||||
|
||||
void parse_color(Color clr, float *r, float *g, float *b, float *a);
|
||||
void parse_color_call(Color clr, tsglColor4f_ptr func);
|
||||
void parse_color_array(Color clr, float array[4]);
|
||||
|
|
|
@ -66,6 +66,7 @@ enum {
|
|||
ATTACK_START_DELAY = 60,
|
||||
ATTACK_START_DELAY_EXTRA = 150,
|
||||
ATTACK_END_DELAY = 20,
|
||||
ATTACK_END_DELAY_SPELL = 60,
|
||||
ATTACK_END_DELAY_EXTRA = 150,
|
||||
BOSS_DEATH_DELAY = 150,
|
||||
BOMB_RECOVERY = 300,
|
||||
|
|
30
src/player.c
30
src/player.c
|
@ -153,6 +153,23 @@ void player_draw(Player* plr) {
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
static void player_fail_spell(Player *plr) {
|
||||
if( !global.boss ||
|
||||
!global.boss->current ||
|
||||
global.boss->current->finished ||
|
||||
global.boss->current->failtime ||
|
||||
global.stage->type == STAGE_SPELL
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
global.boss->current->failtime = global.frames;
|
||||
|
||||
if(global.boss->current->type == AT_ExtraSpell) {
|
||||
boss_finish_current_attack(global.boss);
|
||||
}
|
||||
}
|
||||
|
||||
void player_logic(Player* plr) {
|
||||
process_enemies(&plr->slaves);
|
||||
if(plr->deathtime < -1) {
|
||||
|
@ -191,6 +208,8 @@ void player_logic(Player* plr) {
|
|||
if(at != AT_Move && at != AT_SurvivalSpell)
|
||||
global.boss->dmg += 30;
|
||||
}
|
||||
|
||||
player_fail_spell(plr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,6 +218,7 @@ void player_bomb(Player *plr) {
|
|||
return;
|
||||
|
||||
if(global.frames - plr->recovery >= 0 && (plr->bombs > 0 || plr->iddqd) && global.frames - plr->respawntime >= 60) {
|
||||
player_fail_spell(plr);
|
||||
delete_projectiles(&global.projs);
|
||||
|
||||
switch(plr->cha) {
|
||||
|
@ -245,18 +265,10 @@ void player_realdeath(Player *plr) {
|
|||
plr->bombs = PLR_START_BOMBS;
|
||||
plr->bomb_fragments = 0;
|
||||
|
||||
if(global.boss && global.boss->current && global.boss->current->type == AT_ExtraSpell && global.stage->type != STAGE_SPELL) {
|
||||
if(!global.boss->current->finished) {
|
||||
global.boss->current->endtime = global.frames + ATTACK_END_DELAY_EXTRA;
|
||||
global.boss->current->finished = FINISH_FAIL;
|
||||
boss_kill_projectiles();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(plr->iddqd)
|
||||
return;
|
||||
|
||||
player_fail_spell(plr);
|
||||
player_set_power(plr, plr->power * 0.7);
|
||||
|
||||
if(plr->lives-- == 0 && global.replaymode != REPLAY_PLAY)
|
||||
|
|
|
@ -421,7 +421,7 @@ void draw_hud(void) {
|
|||
|
||||
if(global.boss && global.boss->current && global.boss->current->type == AT_ExtraSpell) {
|
||||
fadein = min(1, -min(0, global.frames - global.boss->current->starttime) / (float)ATTACK_START_DELAY);
|
||||
fadeout = (!!global.boss->current->finished) * (1 - (global.boss->current->endtime - global.frames) / (float)ATTACK_END_DELAY_EXTRA) / 0.74;
|
||||
fadeout = global.boss->current->finished * (1 - (global.boss->current->endtime - global.frames) / (float)ATTACK_END_DELAY_EXTRA) / 0.74;
|
||||
fade = max(fadein, fadeout);
|
||||
|
||||
s = 1 - fade;
|
||||
|
@ -443,7 +443,7 @@ void draw_hud(void) {
|
|||
draw_text(AL_Center, -1, -1, "Extra Spell!", _fonts.mainmenu);
|
||||
glColor4f(1, 1, 1, s);
|
||||
draw_text(AL_Center, 0, 0, "Extra Spell!", _fonts.mainmenu);
|
||||
glColor4f(1, 1, 1, 1);
|
||||
glColor4f(1, 1, 1, 1);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
@ -956,7 +956,7 @@ void stage_loop(StageInfo *stage) {
|
|||
stage->procs->event();
|
||||
}
|
||||
|
||||
if(stage->type == STAGE_SPELL && !global.boss) {
|
||||
if(stage->type == STAGE_SPELL && !global.boss && global.game_over != GAMEOVER_RESTART) {
|
||||
stage_finish(GAMEOVER_WIN);
|
||||
transition_delay = 60;
|
||||
}
|
||||
|
|
|
@ -137,6 +137,12 @@ void stagetext_table_add_numeric(StageTextTable *tbl, const char *title, int n)
|
|||
stagetext_table_push(tbl, txt, true);
|
||||
}
|
||||
|
||||
void stagetext_table_add_numeric_nonzero(StageTextTable *tbl, const char *title, int n) {
|
||||
if(n) {
|
||||
stagetext_table_add_numeric(tbl, title, n);
|
||||
}
|
||||
}
|
||||
|
||||
void stagetext_table_add_separator(StageTextTable *tbl) {
|
||||
tbl->pos += I * 0.5 * stringheight("Love Live", _fonts.standard);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,8 @@ void stagetext_begin_table(StageTextTable *tbl, const char *title, Color titlecl
|
|||
void stagetext_end_table(StageTextTable *tbl);
|
||||
void stagetext_table_add(StageTextTable *tbl, const char *title, const char *val);
|
||||
void stagetext_table_add_numeric(StageTextTable *tbl, const char *title, int n);
|
||||
void stagetext_table_add_numeric_nonzero(StageTextTable *tbl, const char *title, int n);
|
||||
void stagetext_table_add_separator(StageTextTable *tbl);
|
||||
|
||||
void stagetext_table_test(void);
|
||||
|
||||
|
|
Loading…
Reference in a new issue