1 /* 2 * This software is licensed under the terms of the MIT License. 3 * See COPYING for further information. 4 * --- 5 * Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>. 6 * Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>. 7 */ 8 9 #ifndef IGUARD_boss_h 10 #define IGUARD_boss_h 11 12 #include "taisei.h" 13 14 #include "util.h" 15 #include "difficulty.h" 16 #include "aniplayer.h" 17 #include "color.h" 18 #include "projectile.h" 19 #include "entity.h" 20 21 #define BOSS_HURT_RADIUS 16 22 23 enum { 24 ATTACK_START_DELAY = 60, 25 ATTACK_START_DELAY_EXTRA = 150, 26 ATTACK_END_DELAY = 20, 27 ATTACK_END_DELAY_MOVE = 0, 28 ATTACK_END_DELAY_SPELL = 60, 29 ATTACK_END_DELAY_SURV = 20, 30 ATTACK_END_DELAY_EXTRA = 150, 31 ATTACK_END_DELAY_PRE_EXTRA = 60, 32 BOSS_DEATH_DELAY = 120, 33 }; 34 35 struct Boss; 36 37 typedef void (*BossRule)(struct Boss*, int time) attr_nonnull(1); 38 39 typedef enum AttackType { 40 AT_Normal, 41 AT_Move, 42 AT_Spellcard, 43 AT_SurvivalSpell, 44 AT_ExtraSpell, 45 AT_Immediate, 46 } AttackType; 47 48 #define ATTACK_IS_SPELL(a) ((a) == AT_Spellcard || (a) == AT_SurvivalSpell || (a) == AT_ExtraSpell) 49 50 typedef struct AttackInfo { 51 /* 52 HOW TO SET UP THE IDMAP FOR DUMMIES 53 54 The idmap is used as a template to generate spellstage IDs in stage_init_array(). 55 It looks like this: 56 57 {id_easy, id_normal, id_hard, id_lunatic} 58 59 Where each of those IDs are in range of 0-127, and are unique within each stage-specific AttackInfo array. 60 A special value of -1 can be used to not generate a spellstage for specific difficulties. 61 This is useful if your spell is only available on Hard and Lunatic, or has a difficulty-dependent name, etc. 62 63 IDs of AT_ExtraSpell attacks may overlap with those of other types. 64 65 Most importantly DO NOT CHANGE ENSTABILISHED IDs unless you absolutely must. 66 Doing so is going to break replays, progress files, and anything that stores stage IDs permanently. 67 Stage IDs are an internal detail invisible to the player, so they don't need to have any kind of fancy ordering. 68 */ 69 schar idmap[NUM_SELECTABLE_DIFFICULTIES + 1]; 70 71 AttackType type; 72 char *name; 73 float timeout; 74 float hp; 75 76 BossRule rule; 77 BossRule draw_rule; 78 79 cmplx pos_dest; 80 int bonus_rank; 81 } AttackInfo; 82 83 typedef struct Attack { 84 char *name; 85 86 AttackType type; 87 88 int starttime; 89 int timeout; 90 int endtime; 91 int endtime_undelayed; 92 93 float bonus_base; 94 float maxhp; 95 float hp; 96 97 bool finished; 98 int failtime; 99 100 BossRule rule; 101 BossRule draw_rule; 102 103 AttackInfo *info; // NULL for attacks created directly through boss_add_attack 104 } Attack; 105 106 typedef struct Boss { 107 ENTITY_INTERFACE_NAMED(struct Boss, ent); 108 cmplx pos; 109 110 Attack *attacks; 111 Attack *current; 112 113 char *name; 114 115 int acount; 116 117 AniPlayer ani; 118 Sprite *dialog; // Used in spellcard intros 119 120 Color zoomcolor; 121 Color shadowcolor; 122 Color glowcolor; 123 124 int failed_spells; 125 int lastdamageframe; // used to make the boss blink on damage taken 126 int birthtime; 127 128 BossRule global_rule; 129 130 // These are publicly accessible damage multipliers *you* can use to buff your spells. 131 // Just change the numbers. global.shake_view style. 1.0 is the default. 132 // If a new attack starts, they are reset. Nothing can go wrong! 133 float bomb_damage_multiplier; 134 float shot_damage_multiplier; 135 136 struct { 137 float opacity; 138 float fill_total; 139 float fill_alt; 140 Color fill_color; 141 Color fill_altcolor; 142 } healthbar; 143 144 struct { 145 float global_opacity; 146 float spell_opacity; 147 float plrproximity_opacity; 148 float attack_timer; 149 } hud; 150 } Boss; 151 152 Boss* create_boss(char *name, char *ani, char *dialog, cmplx pos) attr_nonnull(1, 2) attr_returns_nonnull; 153 void free_boss(Boss *boss) attr_nonnull(1); 154 void process_boss(Boss **boss) attr_nonnull(1); 155 156 void draw_extraspell_bg(Boss *boss, int time) attr_nonnull(1); 157 void draw_boss_background(Boss *boss) attr_nonnull(1); 158 void draw_boss_overlay(Boss *boss) attr_nonnull(1); 159 void draw_boss_fake_overlay(Boss *boss) attr_nonnull(1); 160 161 Attack* boss_add_attack(Boss *boss, AttackType type, char *name, float timeout, int hp, BossRule rule, BossRule draw_rule) 162 attr_nonnull(1) attr_returns_nonnull; 163 Attack* boss_add_attack_from_info(Boss *boss, AttackInfo *info, char move) 164 attr_nonnull(1, 2) attr_returns_nonnull; 165 void boss_set_attack_bonus(Attack *a, int rank) attr_nonnull(1); 166 167 void boss_start_attack(Boss *b, Attack *a) attr_nonnull(1, 2); 168 void boss_finish_current_attack(Boss *boss) attr_nonnull(1); 169 170 bool boss_is_dying(Boss *boss) attr_nonnull(1); // true if the last attack is over but the BOSS_DEATH_DELAY has not elapsed. 171 bool boss_is_fleeing(Boss *boss) attr_nonnull(1); 172 bool boss_is_vulnerable(Boss *boss) attr_nonnull(1); 173 174 void boss_death(Boss **boss) attr_nonnull(1); 175 176 void boss_preload(void); 177 178 #define BOSS_DEFAULT_SPAWN_POS (VIEWPORT_W * 0.5 - I * VIEWPORT_H * 0.5) 179 #define BOSS_DEFAULT_GO_POS (VIEWPORT_W * 0.5 + 200.0*I) 180 #define BOSS_NOMOVE (-3142-39942.0*I) 181 182 #endif // IGUARD_boss_h 183