looping sounds and stage1 shot soundification

This commit is contained in:
laochailan 2017-09-30 19:33:07 +02:00
parent 0d1eff8591
commit 683e0b3274
No known key found for this signature in database
GPG key ID: 49BE98017AFBC943
11 changed files with 238 additions and 107 deletions

Binary file not shown.

View file

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

View file

@ -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(&current_bgm.name, name);
stralloc(&current_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);
}
}

View file

@ -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
View 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 doesnt 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;

View file

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

View file

@ -12,6 +12,7 @@
typedef struct Sound {
int lastplayframe;
bool islooping;
void *impl;
} Sound;

View file

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

View file

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

View file

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

View file

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