looping sounds and stage1 shot soundification
This commit is contained in:
parent
0d1eff8591
commit
683e0b3274
11 changed files with 238 additions and 107 deletions
BIN
resources/sfx/shot1_loop.wav
Normal file
BIN
resources/sfx/shot1_loop.wav
Normal file
Binary file not shown.
|
@ -11,6 +11,8 @@
|
|||
#include "resource/sfx.h"
|
||||
#include "resource/bgm.h"
|
||||
|
||||
#define LOOPTIMEOUTFRAMES 10
|
||||
|
||||
typedef struct CurrentBGM {
|
||||
char *name;
|
||||
char *title;
|
||||
|
@ -34,13 +36,19 @@ void audio_backend_music_pause(void);
|
|||
bool audio_backend_music_play(void *impl);
|
||||
bool audio_backend_sound_play(void *impl);
|
||||
|
||||
bool audio_backend_sound_loop(void *impl);
|
||||
bool audio_backend_sound_stop_loop(void *impl);
|
||||
|
||||
void audio_init(void);
|
||||
void audio_shutdown(void);
|
||||
|
||||
void play_sound(const char *name);
|
||||
void play_loop(const char *name);
|
||||
void play_ui_sound(const char *name);
|
||||
void reset_sounds(void);
|
||||
|
||||
void update_sounds(void); // checks if loops need to be stopped
|
||||
|
||||
Sound* get_sound(const char *name);
|
||||
Music* get_music(const char *music);
|
||||
|
||||
|
|
|
@ -18,153 +18,187 @@ static Hashtable *bgm_descriptions;
|
|||
CurrentBGM current_bgm = { .name = NULL };
|
||||
|
||||
static void play_sound_internal(const char *name, bool unconditional) {
|
||||
if(!audio_backend_initialized() || global.frameskip) {
|
||||
return;
|
||||
}
|
||||
if(!audio_backend_initialized() || global.frameskip) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sound *snd = get_sound(name);
|
||||
Sound *snd = get_sound(name);
|
||||
|
||||
if(!snd || (!unconditional && snd->lastplayframe == global.frames)) {
|
||||
return;
|
||||
}
|
||||
if(!snd || (!unconditional && snd->lastplayframe + LOOPTIMEOUTFRAMES/2 <= global.frames) || snd->islooping) {
|
||||
return;
|
||||
}
|
||||
|
||||
snd->lastplayframe = global.frames;
|
||||
audio_backend_sound_play(snd->impl);
|
||||
snd->lastplayframe = global.frames;
|
||||
audio_backend_sound_play(snd->impl);
|
||||
}
|
||||
|
||||
void play_sound(const char *name) {
|
||||
play_sound_internal(name, false);
|
||||
play_sound_internal(name, false);
|
||||
}
|
||||
|
||||
void play_ui_sound(const char *name) {
|
||||
play_sound_internal(name, true);
|
||||
play_sound_internal(name, true);
|
||||
}
|
||||
|
||||
void play_loop(const char *name) {
|
||||
if(!audio_backend_initialized() || global.frameskip) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sound *snd = get_sound(name);
|
||||
|
||||
if(!snd) {
|
||||
return;
|
||||
}
|
||||
snd->lastplayframe = global.frames;
|
||||
if(!snd->islooping) {
|
||||
audio_backend_sound_loop(snd->impl);
|
||||
snd->islooping = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void reset_sounds(void) {
|
||||
Resource *snd;
|
||||
for(HashtableIterator *i = hashtable_iter(resources.handlers[RES_SFX].mapping);
|
||||
hashtable_iter_next(i, NULL, (void**)&snd);) {
|
||||
snd->sound->lastplayframe = 0;
|
||||
}
|
||||
Resource *snd;
|
||||
for(HashtableIterator *i = hashtable_iter(resources.handlers[RES_SFX].mapping);
|
||||
hashtable_iter_next(i, 0, (void**)&snd);) {
|
||||
snd->sound->lastplayframe = 0;
|
||||
if(snd->sound->islooping) {
|
||||
audio_backend_sound_stop_loop(snd->sound->impl);
|
||||
snd->sound->islooping = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update_sounds(void) {
|
||||
Resource *snd;
|
||||
for(HashtableIterator *i = hashtable_iter(resources.handlers[RES_SFX].mapping);
|
||||
hashtable_iter_next(i, 0, (void**)&snd);) {
|
||||
if(snd->sound->islooping && global.frames > snd->sound->lastplayframe + LOOPTIMEOUTFRAMES) {
|
||||
snd->sound->islooping = false;
|
||||
audio_backend_sound_stop_loop(snd->sound->impl);
|
||||
log_debug("channel stopped");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Sound* get_sound(const char *name) {
|
||||
Resource *res = get_resource(RES_SFX, name, RESF_OPTIONAL);
|
||||
return res ? res->sound : NULL;
|
||||
Resource *res = get_resource(RES_SFX, name, RESF_OPTIONAL);
|
||||
return res ? res->sound : NULL;
|
||||
}
|
||||
|
||||
Music* get_music(const char *name) {
|
||||
Resource *res = get_resource(RES_BGM, name, RESF_OPTIONAL);
|
||||
return res ? res->music : NULL;
|
||||
Resource *res = get_resource(RES_BGM, name, RESF_OPTIONAL);
|
||||
return res ? res->music : NULL;
|
||||
}
|
||||
|
||||
static void sfx_cfg_volume_callback(ConfigIndex idx, ConfigValue v) {
|
||||
audio_backend_set_sfx_volume(config_set_float(idx, v.f));
|
||||
audio_backend_set_sfx_volume(config_set_float(idx, v.f));
|
||||
}
|
||||
|
||||
static void bgm_cfg_volume_callback(ConfigIndex idx, ConfigValue v) {
|
||||
audio_backend_set_bgm_volume(config_set_float(idx, v.f));
|
||||
audio_backend_set_bgm_volume(config_set_float(idx, v.f));
|
||||
}
|
||||
|
||||
static void load_bgm_descriptions(void) {
|
||||
bgm_descriptions = parse_keyvalue_file(BGM_PATH_PREFIX "bgm.conf", HT_DYNAMIC_SIZE);
|
||||
return;
|
||||
bgm_descriptions = parse_keyvalue_file(BGM_PATH_PREFIX "bgm.conf", HT_DYNAMIC_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
static inline char* get_bgm_desc(char *name) {
|
||||
return bgm_descriptions ? (char*)hashtable_get_string(bgm_descriptions, name) : NULL;
|
||||
return bgm_descriptions ? (char*)hashtable_get_string(bgm_descriptions, name) : NULL;
|
||||
}
|
||||
|
||||
void resume_bgm(void) {
|
||||
start_bgm(current_bgm.name); // In most cases it just unpauses existing music.
|
||||
start_bgm(current_bgm.name); // In most cases it just unpauses existing music.
|
||||
}
|
||||
|
||||
void stop_bgm(bool force) {
|
||||
if(!current_bgm.name) {
|
||||
return;
|
||||
}
|
||||
if(!current_bgm.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(audio_backend_music_is_playing() && !audio_backend_music_is_paused()) {
|
||||
if(force) {
|
||||
audio_backend_music_stop();
|
||||
} else {
|
||||
audio_backend_music_pause();
|
||||
}
|
||||
if(audio_backend_music_is_playing() && !audio_backend_music_is_paused()) {
|
||||
if(force) {
|
||||
audio_backend_music_stop();
|
||||
} else {
|
||||
audio_backend_music_pause();
|
||||
}
|
||||
|
||||
log_info("BGM stopped");
|
||||
} else {
|
||||
log_info("No BGM was playing");
|
||||
}
|
||||
log_info("BGM stopped");
|
||||
} else {
|
||||
log_info("No BGM was playing");
|
||||
}
|
||||
}
|
||||
|
||||
void save_bgm(void) {
|
||||
// Deal with consequent saves without restore.
|
||||
stralloc(&saved_bgm, current_bgm.name);
|
||||
// Deal with consequent saves without restore.
|
||||
stralloc(&saved_bgm, current_bgm.name);
|
||||
}
|
||||
|
||||
void restore_bgm(void) {
|
||||
start_bgm(saved_bgm);
|
||||
free(saved_bgm);
|
||||
saved_bgm = NULL;
|
||||
start_bgm(saved_bgm);
|
||||
free(saved_bgm);
|
||||
saved_bgm = NULL;
|
||||
}
|
||||
|
||||
void start_bgm(const char *name) {
|
||||
if(!name || !*name) {
|
||||
stop_bgm(false);
|
||||
return;
|
||||
}
|
||||
if(!name || !*name) {
|
||||
stop_bgm(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// if BGM has changed, change it and start from beginning
|
||||
if(!current_bgm.name || strcmp(name, current_bgm.name)) {
|
||||
audio_backend_music_stop();
|
||||
// if BGM has changed, change it and start from beginning
|
||||
if(!current_bgm.name || strcmp(name, current_bgm.name)) {
|
||||
audio_backend_music_stop();
|
||||
|
||||
stralloc(¤t_bgm.name, name);
|
||||
stralloc(¤t_bgm.name, name);
|
||||
|
||||
if((current_bgm.music = get_music(name)) == NULL) {
|
||||
log_warn("BGM '%s' does not exist", current_bgm.name);
|
||||
stop_bgm(true);
|
||||
free(current_bgm.name);
|
||||
current_bgm.name = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if((current_bgm.music = get_music(name)) == NULL) {
|
||||
log_warn("BGM '%s' does not exist", current_bgm.name);
|
||||
stop_bgm(true);
|
||||
free(current_bgm.name);
|
||||
current_bgm.name = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(audio_backend_music_is_paused()) {
|
||||
audio_backend_music_resume();
|
||||
}
|
||||
if(audio_backend_music_is_paused()) {
|
||||
audio_backend_music_resume();
|
||||
}
|
||||
|
||||
if(audio_backend_music_is_playing()) {
|
||||
return;
|
||||
}
|
||||
if(audio_backend_music_is_playing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!audio_backend_music_play(current_bgm.music->impl)) {
|
||||
return;
|
||||
}
|
||||
if(!audio_backend_music_play(current_bgm.music->impl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Support drawing BGM title in game loop (only when music changed!)
|
||||
if((current_bgm.title = get_bgm_desc(current_bgm.name)) != NULL) {
|
||||
current_bgm.started_at = global.frames;
|
||||
// Boss BGM title color may differ from the one at beginning of stage
|
||||
current_bgm.isboss = strendswith(current_bgm.name, "boss");
|
||||
} else {
|
||||
current_bgm.started_at = -1;
|
||||
}
|
||||
// Support drawing BGM title in game loop (only when music changed!)
|
||||
if((current_bgm.title = get_bgm_desc(current_bgm.name)) != NULL) {
|
||||
current_bgm.started_at = global.frames;
|
||||
// Boss BGM title color may differ from the one at beginning of stage
|
||||
current_bgm.isboss = strendswith(current_bgm.name, "boss");
|
||||
} else {
|
||||
current_bgm.started_at = -1;
|
||||
}
|
||||
|
||||
log_info("Started %s", (current_bgm.title ? current_bgm.title : current_bgm.name));
|
||||
log_info("Started %s", (current_bgm.title ? current_bgm.title : current_bgm.name));
|
||||
}
|
||||
|
||||
void audio_init(void) {
|
||||
audio_backend_init();
|
||||
load_bgm_descriptions();
|
||||
config_set_callback(CONFIG_SFX_VOLUME, sfx_cfg_volume_callback);
|
||||
config_set_callback(CONFIG_BGM_VOLUME, bgm_cfg_volume_callback);
|
||||
audio_backend_init();
|
||||
load_bgm_descriptions();
|
||||
config_set_callback(CONFIG_SFX_VOLUME, sfx_cfg_volume_callback);
|
||||
config_set_callback(CONFIG_BGM_VOLUME, bgm_cfg_volume_callback);
|
||||
}
|
||||
|
||||
void audio_shutdown(void) {
|
||||
audio_backend_shutdown();
|
||||
audio_backend_shutdown();
|
||||
|
||||
if(bgm_descriptions) {
|
||||
hashtable_foreach(bgm_descriptions, hashtable_iter_free_data, NULL);
|
||||
hashtable_free(bgm_descriptions);
|
||||
}
|
||||
if(bgm_descriptions) {
|
||||
hashtable_foreach(bgm_descriptions, hashtable_iter_free_data, NULL);
|
||||
hashtable_free(bgm_descriptions);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <SDL_mixer.h>
|
||||
|
||||
#include "audio.h"
|
||||
#include "audio_mixer.h"
|
||||
#include "global.h"
|
||||
#include "list.h"
|
||||
|
||||
|
@ -22,6 +23,7 @@ const char *mixer_audio_exts[] = { ".wav", ".ogg", ".mp3", ".mod", ".xm", ".s3m"
|
|||
".669", ".it", ".med", ".mid", ".flac", ".aiff", ".voc",
|
||||
NULL };
|
||||
|
||||
|
||||
void audio_backend_init(void) {
|
||||
if(mixer_loaded) {
|
||||
return;
|
||||
|
@ -169,7 +171,7 @@ bool audio_backend_sound_play(void *impl) {
|
|||
if(!mixer_loaded)
|
||||
return false;
|
||||
|
||||
bool result = (Mix_PlayChannel(-1, (Mix_Chunk*)impl, 0) != -1);
|
||||
bool result = (Mix_PlayChannel(-1, ((MixerInternalSound*)impl)->ch, 0) != -1);
|
||||
|
||||
if(!result) {
|
||||
log_warn("Mix_PlayChannel() failed: %s", Mix_GetError());
|
||||
|
@ -177,3 +179,32 @@ bool audio_backend_sound_play(void *impl) {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool audio_backend_sound_loop(void *impl) {
|
||||
if(!mixer_loaded)
|
||||
return false;
|
||||
|
||||
MixerInternalSound *snd = (MixerInternalSound *)impl;
|
||||
snd->loopchan = Mix_PlayChannel(-1, snd->ch, -1);
|
||||
|
||||
if(snd->loopchan == -1) {
|
||||
log_warn("Mix_PlayChannel() failed: %s", Mix_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool audio_backend_sound_stop_loop(void *impl) {
|
||||
if(!mixer_loaded)
|
||||
return false;
|
||||
|
||||
MixerInternalSound *snd = (MixerInternalSound *)impl;
|
||||
if(snd->loopchan == -1)
|
||||
return false;
|
||||
Mix_HaltChannel(snd->loopchan);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
|
18
src/audio_mixer.h
Normal file
18
src/audio_mixer.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT-License
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2017, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2017, Andrei Alexeyev <akari@alienslab.net>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// I needed to add this for supporting loop sounds since Mixer doesn’t remember
|
||||
// what channel a sound is playing on.
|
||||
|
||||
typedef struct {
|
||||
Mix_Chunk *ch;
|
||||
int loopchan; // channel the sound may be looping on. -1 if not looping
|
||||
} MixerInternalSound;
|
||||
|
|
@ -20,3 +20,6 @@ void audio_backend_music_stop(void) {}
|
|||
void audio_backend_music_pause(void) {}
|
||||
bool audio_backend_music_play(void *impl) { return false; }
|
||||
bool audio_backend_sound_play(void *impl) { return false; }
|
||||
|
||||
bool audio_backend_sound_loop(void *impl) {return false;}
|
||||
bool audio_backend_sound_stop_loop(void *impl) {return false;}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
typedef struct Sound {
|
||||
int lastplayframe;
|
||||
bool islooping;
|
||||
void *impl;
|
||||
} Sound;
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "resource.h"
|
||||
#include "sfx.h"
|
||||
#include "audio_mixer.h"
|
||||
|
||||
char* audio_mixer_sound_path(const char *prefix, const char *name);
|
||||
bool audio_mixer_check_sound_path(const char *path, bool isbgm);
|
||||
|
@ -39,8 +40,9 @@ void* load_sound_begin(const char *path, unsigned int flags) {
|
|||
}
|
||||
|
||||
Sound *snd = calloc(1, sizeof(Sound));
|
||||
snd->impl = sound;
|
||||
|
||||
snd->impl = calloc(1,sizeof(MixerInternalSound));
|
||||
((MixerInternalSound*)snd->impl)->ch = sound;
|
||||
((MixerInternalSound*)snd->impl)->loopchan = -1;
|
||||
return snd;
|
||||
}
|
||||
|
||||
|
@ -50,6 +52,7 @@ void* load_sound_end(void *opaque, const char *path, unsigned int flags) {
|
|||
|
||||
void unload_sound(void *vsnd) {
|
||||
Sound *snd = vsnd;
|
||||
Mix_FreeChunk((Mix_Chunk*)snd->impl);
|
||||
Mix_FreeChunk(((MixerInternalSound *)snd->impl)->ch);
|
||||
free(snd->impl);
|
||||
free(snd);
|
||||
}
|
||||
|
|
|
@ -340,6 +340,8 @@ static void stage_logic(void) {
|
|||
process_lasers();
|
||||
process_projectiles(&global.particles, false);
|
||||
|
||||
update_sounds();
|
||||
|
||||
if(global.boss && !global.dialog)
|
||||
process_boss(&global.boss);
|
||||
|
||||
|
|
|
@ -47,6 +47,14 @@
|
|||
#define GO_AT(obj, start, end, vel) if(*__timep >= (start) && *__timep <= (end)) (obj)->pos += (vel);
|
||||
#define GO_TO(obj, p, f) (obj)->pos += (f)*((p) - (obj)->pos);
|
||||
|
||||
// This is newest addition to the macro zoo! It allows you to loop a sound like
|
||||
// you loop your French- I mean your danmaku code. Nothing strange going on here.
|
||||
#define PLAY_FOR(name,start, end) FROM_TO(start,end,2) { play_loop(name); }
|
||||
|
||||
// easy to soundify versions of FROM_TO and friends. Note how I made FROM_TO_INT even more complicated!
|
||||
#define FROM_TO_SND(snd,start,end,step) PLAY_FOR(snd,start,end); FROM_TO(start,end,step)
|
||||
#define FROM_TO_INT_SND(snd,start,end,step,dur,istep) FROM_TO_INT(start,end,step,dur,2) { play_loop(snd); }FROM_TO_INT(start,end,step,dur,istep)
|
||||
|
||||
typedef void (*StageProc)(void);
|
||||
typedef void (*ShaderRule)(FBO*);
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ void cirno_icy(Boss *b, int time) {
|
|||
int c = 6;
|
||||
double dr = 15;
|
||||
|
||||
FROM_TO(0,3*size,3) {
|
||||
FROM_TO_SND("shot1_loop",0,3*size,3) {
|
||||
for(int i = 0; i < c; i++) {
|
||||
double ang = 2*M_PI/c*i+run*515;
|
||||
complex phase = cexp(I*ang);
|
||||
|
@ -137,7 +137,7 @@ void cirno_perfect_freeze(Boss *c, int time) {
|
|||
FROM_TO(-40, 0, 1)
|
||||
GO_TO(c, VIEWPORT_W/2.0 + 100.0*I, 0.04);
|
||||
|
||||
FROM_TO(20,80,1) {
|
||||
FROM_TO_SND("shot1_loop",20,80,1) {
|
||||
float r = frand();
|
||||
float g = frand();
|
||||
float b = frand();
|
||||
|
@ -152,7 +152,7 @@ void cirno_perfect_freeze(Boss *c, int time) {
|
|||
|
||||
int d = max(0, global.diff - D_Normal);
|
||||
|
||||
FROM_TO(160 - 50*d, 220 + 30*d, 6-global.diff/2) {
|
||||
FROM_TO_SND("shot1_loop", 160 - 50*d, 220 + 30*d, 6-global.diff/2) {
|
||||
float r1, r2;
|
||||
|
||||
if(global.diff > D_Normal) {
|
||||
|
@ -219,7 +219,7 @@ void cirno_iceplosion0(Boss *c, int time) {
|
|||
if(time < 0)
|
||||
return;
|
||||
|
||||
FROM_TO(20,30,2) {
|
||||
FROM_TO_SND("shot1_loop",20,30,2) {
|
||||
int i;
|
||||
int n = 8+global.diff;
|
||||
for(i = 0; i < n; i++) {
|
||||
|
@ -227,13 +227,14 @@ void cirno_iceplosion0(Boss *c, int time) {
|
|||
}
|
||||
}
|
||||
|
||||
FROM_TO(40,100,1+2*(global.diff<D_Hard)) {
|
||||
FROM_TO_SND("shot1_loop",40,100,1+2*(global.diff<D_Hard)) {
|
||||
create_projectile2c("crystal", c->pos, rgb(0.3,0.3,0.8), accelerated, global.diff/4.*cexp(2.0*I*M_PI*frand()) + 2.0*I, 0.002*cexp(I*(M_PI/10.0*(_i%20))));
|
||||
}
|
||||
|
||||
FROM_TO(150, 300, 30-5*global.diff) {
|
||||
float dif = M_PI*2*frand();
|
||||
int i;
|
||||
play_sound("shot1");
|
||||
for(i = 0; i < 20; i++) {
|
||||
create_projectile2c("plainball", c->pos, rgb(0.04*_i,0.04*_i,0.4+0.04*_i), asymptotic, (3+_i/4.0)*cexp(I*(2*M_PI/8.0*i + dif)), 2.5);
|
||||
}
|
||||
|
@ -247,6 +248,7 @@ void cirno_crystal_rain(Boss *c, int time) {
|
|||
if(time < 0)
|
||||
return;
|
||||
|
||||
PLAY_FOR("shot1_loop",0,499);
|
||||
int hdiff = max(0, (int)global.diff - D_Normal);
|
||||
|
||||
if(frand() > 0.95-0.1*global.diff) {
|
||||
|
@ -259,6 +261,7 @@ void cirno_crystal_rain(Boss *c, int time) {
|
|||
bool odd = (hdiff? (_i&1) : 0);
|
||||
float n = (global.diff-1+hdiff*4 + odd)/2.0;
|
||||
|
||||
play_sound("shot1");
|
||||
for(i = -n; i <= n; i++) {
|
||||
create_projectile2c(odd? "plainball" : "bigball", c->pos, rgb(0.2,0.2,0.9), asymptotic, 2*cexp(I*carg(global.plr.pos-c->pos)+0.3*I*i), 2.3);
|
||||
}
|
||||
|
@ -279,14 +282,14 @@ void cirno_iceplosion1(Boss *c, int time) {
|
|||
if(time < 0)
|
||||
GO_TO(c, VIEWPORT_W/2.0 + 100.0*I, 0.02);
|
||||
|
||||
FROM_TO(20,30,2) {
|
||||
FROM_TO_SND("shot1_loop",20,30,2) {
|
||||
int i;
|
||||
for(i = 0; i < 15+global.diff; i++) {
|
||||
create_projectile2c("plainball", c->pos, rgb(0,0,0.5), asymptotic, (3+_i/3.0)*cexp(I*((2)*M_PI/8.0*i + (0.1+0.03*global.diff)*(1 - 2*frand()))), _i*0.7);
|
||||
}
|
||||
}
|
||||
|
||||
FROM_TO(40,100,2+2*(global.diff<D_Hard)) {
|
||||
FROM_TO_SND("shot1_loop",40,100,2+2*(global.diff<D_Hard)) {
|
||||
create_projectile2c("crystal", c->pos + 100, rgb(0.3,0.3,0.8), accelerated, 1.5*cexp(2.0*I*M_PI*frand()) - 0.4 + 2.0*I*global.diff/4., 0.002*cexp(I*(M_PI/10.0*(_i%20))));
|
||||
create_projectile2c("crystal", c->pos - 100, rgb(0.3,0.3,0.8), accelerated, 1.5*cexp(2.0*I*M_PI*frand()) + 0.4 + 2.0*I*global.diff/4., 0.002*cexp(I*(M_PI/10.0*(_i%20))));
|
||||
}
|
||||
|
@ -294,6 +297,8 @@ void cirno_iceplosion1(Boss *c, int time) {
|
|||
FROM_TO(150, 300, 30) {
|
||||
float dif = M_PI*2*frand();
|
||||
int i;
|
||||
|
||||
play_sound("shot1");
|
||||
for(i = 0; i < 20; i++) {
|
||||
create_projectile2c("plainball", c->pos, rgb(0.04*_i,0.04*_i,0.4+0.04*_i), asymptotic, (3+_i/3.0)*cexp(I*(2*M_PI/8.0*i + dif)), 2.5);
|
||||
}
|
||||
|
@ -331,6 +336,7 @@ void cirno_icicle_fall(Boss *c, int time) {
|
|||
GO_TO(c, VIEWPORT_W/2.0+120.0*I, 0.01);
|
||||
|
||||
FROM_TO(20,200,30-3*global.diff) {
|
||||
play_sound("shot1");
|
||||
for(float i = 2-0.2*global.diff; i < 5; i+=1./(1+global.diff)) {
|
||||
create_projectile1c("crystal", c->pos, rgb(0.3,0.3,0.9), cirno_icicles, 6*i*cexp(I*(-0.1+0.1*_i)));
|
||||
create_projectile1c("crystal", c->pos, rgb(0.3,0.3,0.9), cirno_icicles, 6*i*cexp(I*(M_PI+0.1-0.1*_i)));
|
||||
|
@ -338,7 +344,7 @@ void cirno_icicle_fall(Boss *c, int time) {
|
|||
}
|
||||
|
||||
if(global.diff > D_Easy) {
|
||||
FROM_TO(120,200,3) {
|
||||
FROM_TO_SND("shot1_loop",120,200,3) {
|
||||
float f = frand()*_i;
|
||||
|
||||
create_projectile2c("ball", c->pos, rgb(0.,0.,0.3), accelerated, 0.2*(-2*I-1.5+f),-0.02*I);
|
||||
|
@ -347,6 +353,7 @@ void cirno_icicle_fall(Boss *c, int time) {
|
|||
}
|
||||
if(global.diff > D_Normal) {
|
||||
FROM_TO(300,400,10) {
|
||||
play_sound("shot1");
|
||||
float x = VIEWPORT_W/2+VIEWPORT_W/2*(0.3+_i/10.);
|
||||
float angle1 = M_PI/10*frand();
|
||||
float angle2 = M_PI/10*frand();
|
||||
|
@ -380,13 +387,14 @@ void cirno_crystal_blizzard(Boss *c, int time) {
|
|||
}
|
||||
|
||||
FROM_TO(60, 360, 10) {
|
||||
play_sound("shot1");
|
||||
int i, cnt = 14 + global.diff * 3;
|
||||
for(i = 0; i < cnt; ++i) {
|
||||
create_projectile2c("crystal", i*VIEWPORT_W/cnt, i % 2? rgb(0.2,0.2,0.4) : rgb(0.5,0.5,0.5), accelerated, 0, 0.02*I + 0.01*I * (i % 2? 1 : -1) * sin((i*3+global.frames)/30.0));
|
||||
}
|
||||
}
|
||||
|
||||
FROM_TO(330, 700, 1) {
|
||||
FROM_TO_SND("shot1_loop",330, 700, 1) {
|
||||
GO_TO(c, global.plr.pos, 0.01);
|
||||
|
||||
if(!(time % (1 + D_Lunatic - global.diff))) {
|
||||
|
@ -397,6 +405,7 @@ void cirno_crystal_blizzard(Boss *c, int time) {
|
|||
}
|
||||
|
||||
if(!(time % 7)) {
|
||||
play_sound("shot1");
|
||||
int i, cnt = global.diff - 1;
|
||||
for(i = 0; i < cnt; ++i)
|
||||
create_projectile2c("ball", c->pos, rgb(0.1, 0.1, 0.5), accelerated, 0, 0.01 * cexp(I*(global.frames/20.0 + 2*i*M_PI/cnt)))->draw = ProjDrawAdd;
|
||||
|
@ -442,6 +451,7 @@ int stage1_burst(Enemy *e, int time) {
|
|||
int i = 0;
|
||||
int n = 1.5*global.diff-1;
|
||||
|
||||
play_sound("shot1");
|
||||
for(i = -n; i <= n; i++) {
|
||||
create_projectile2c("crystal", e->pos, rgb(0.2, 0.3, 0.5), asymptotic, (2+0.1*global.diff)*cexp(I*(carg(global.plr.pos - e->pos) + 0.2*i)), 5);
|
||||
}
|
||||
|
@ -468,14 +478,16 @@ int stage1_circletoss(Enemy *e, int time) {
|
|||
|
||||
e->pos += e->args[0];
|
||||
|
||||
FROM_TO(60,100,2+(global.diff<D_Hard)) {
|
||||
int inter = 2+(global.diff<D_Hard);
|
||||
int dur = 40;
|
||||
FROM_TO_SND("shot1_loop",60,60+dur,inter) {
|
||||
e->args[0] = 0.5*e->args[0];
|
||||
create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, 2*cexp(I*M_PI/10*_i), _i/2.0);
|
||||
create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, 2*cexp(I*2*M_PI*inter/dur*_i), _i/2.0);
|
||||
}
|
||||
|
||||
|
||||
if(global.diff > D_Easy) {
|
||||
FROM_TO_INT(90,500,150,5+7*global.diff,1) {
|
||||
FROM_TO_INT_SND("shot1_loop",90,500,150,5+7*global.diff,1) {
|
||||
tsrand_fill(2);
|
||||
create_projectile2c("thickrice", e->pos, rgb(0.2, 0.4, 0.8), asymptotic, (1+afrand(0)*2)*cexp(I*carg(global.plr.pos - e->pos)+0.05*I*global.diff*anfrand(1)), 3);
|
||||
}
|
||||
|
@ -498,8 +510,10 @@ int stage1_sinepass(Enemy *e, int time) {
|
|||
e->args[1] -= cimag(e->pos-e->pos0)*0.03*I;
|
||||
e->pos += e->args[1]*0.4 + e->args[0];
|
||||
|
||||
if(frand() > 0.997-0.005*(global.diff-1))
|
||||
if(frand() > 0.997-0.005*(global.diff-1)) {
|
||||
play_sound("shot1");
|
||||
create_projectile1c("ball", e->pos, rgb(0.8,0.8,0.4), linear, (1+0.2*global.diff+frand())*cexp(I*carg(global.plr.pos - e->pos)));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -515,9 +529,12 @@ int stage1_drop(Enemy *e, int t) {
|
|||
|
||||
e->pos = e->pos0 + e->args[0]*t + e->args[1]*t*t;
|
||||
|
||||
FROM_TO(10,1000,1)
|
||||
if(frand() > 0.997-0.007*(global.diff-1))
|
||||
FROM_TO(10,1000,1) {
|
||||
if(frand() > 0.997-0.007*(global.diff-1)) {
|
||||
play_sound("shot1");
|
||||
create_projectile1c("ball", e->pos, rgb(0.8,0.8,0.4), linear, (1+0.3*global.diff+frand())*cexp(I*carg(global.plr.pos - e->pos)));
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -532,8 +549,9 @@ int stage1_circle(Enemy *e, int t) {
|
|||
FROM_TO(0, 150, 1)
|
||||
e->pos += (e->args[0] - e->pos)*0.02;
|
||||
|
||||
FROM_TO_INT(150, 550, 40, 40, 2+2*(global.diff<D_Hard))
|
||||
FROM_TO_INT_SND("shot1_loop",150, 550, 40, 40, 2+2*(global.diff<D_Hard)) {
|
||||
create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, (1.7+0.2*global.diff)*cexp(I*M_PI/10*_ni), _ni/2.0);
|
||||
}
|
||||
|
||||
FROM_TO(560,1000,1)
|
||||
e->pos += e->args[1];
|
||||
|
@ -552,6 +570,7 @@ int stage1_multiburst(Enemy *e, int t) {
|
|||
e->pos += 2.0*I;
|
||||
|
||||
FROM_TO_INT(60, 300, 70, 40, 18-2*global.diff) {
|
||||
play_sound("shot1");
|
||||
int i;
|
||||
int n = global.diff-1;
|
||||
for(i = -n; i <= n; i++)
|
||||
|
@ -580,11 +599,13 @@ int stage1_instantcircle(Enemy *e, int t) {
|
|||
int i;
|
||||
|
||||
AT(150) {
|
||||
play_sound("shot1");
|
||||
for(i = 0; i < 20+2*global.diff; i++)
|
||||
create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, 1.5*cexp(I*2*M_PI/(20.0+global.diff)*i), 2.0);
|
||||
}
|
||||
|
||||
AT(170) {
|
||||
play_sound("shot1");
|
||||
if(global.diff > D_Easy) {
|
||||
for(i = 0; i < 20+3*global.diff; i++)
|
||||
create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, 3*cexp(I*2*M_PI/(20.0+global.diff)*i), 3.0);
|
||||
|
@ -609,6 +630,7 @@ int stage1_tritoss(Enemy *e, int t) {
|
|||
}
|
||||
|
||||
FROM_TO(120, 800,8-global.diff) {
|
||||
play_sound("shot1");
|
||||
float a = M_PI/30.0*((_i/7)%30)+0.1*nfrand();
|
||||
int i;
|
||||
int n = 3+global.diff/2;
|
||||
|
@ -618,6 +640,7 @@ int stage1_tritoss(Enemy *e, int t) {
|
|||
}
|
||||
|
||||
FROM_TO(480, 800, 300) {
|
||||
play_sound("shot1");
|
||||
int i, n = 15 + global.diff*3;
|
||||
for(i = 0; i < n; i++) {
|
||||
create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, 1.5*cexp(I*2*M_PI/n*i), 2.0);
|
||||
|
|
Loading…
Reference in a new issue