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