Basic spell bonuses

This commit is contained in:
Andrei "Akari" Alexeyev 2017-04-04 03:57:38 +03:00
parent f3b3e8b16a
commit 32144640c1
8 changed files with 128 additions and 53 deletions

View file

@ -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;
}

View file

@ -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);

View file

@ -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]);

View file

@ -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,

View file

@ -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)

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);