Merge branch 'master' into selections

This commit is contained in:
Andrew "Akari" Alexeyew 2012-08-07 17:14:59 +03:00
commit 5ce30f8ca4
39 changed files with 1051 additions and 335 deletions

4
.gitignore vendored
View file

@ -1,7 +1,3 @@
build/
winbuild/
src/parser.c
src/parser.h
src/lexer.h
src/lexer.c
.ctagsdb

BIN
gfx/dialog/hina.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

BIN
gfx/yukkureimu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

View file

@ -25,4 +25,4 @@ void main(void) {
gl_FragColor += texture2D(tex, pos + r*vec2(cos(a*dot(pos, vec2(10.0,3.0))),sin(a*a)))*0.1;
gl_FragColor *= sqrt(gl_FragColor)*pow(vec4(0.4,0.5,0.6,1), vec4(rad*25.0));
}
}

View file

@ -14,6 +14,7 @@ void main(void) {
#version 110
uniform sampler2D tex;
uniform float lendiv;
varying vec4 d;
varying vec4 TexCoord0;
@ -22,4 +23,4 @@ void main(void) {
vec4 texel = texture2D(tex, TexCoord0.xy);
float f = min(1.0, length(d)/3000.0);
gl_FragColor = mix(vec4(1.0), texel, 1.0-f);
}
}

View file

@ -36,7 +36,6 @@ set(SRCs
menu/options.c
menu/stageselect.c
menu/replayview.c
menu/replayover.c
menu/ingamemenu.c
menu/gameovermenu.c
menu/savereplay.c
@ -53,6 +52,8 @@ set(SRCs
stages/stage5_events.c
stages/stage6.c
stages/stage6_events.c
ending.c
credits.c
resource/resource.c
resource/texture.c
resource/animation.c
@ -72,12 +73,16 @@ if(WIN32)
set(SRCs ${SRCs} taisei_err.c)
endif()
add_definitions(-DPREFIX="${CMAKE_INSTALL_PREFIX}" -Wall)
add_definitions(-DPREFIX="${CMAKE_INSTALL_PREFIX}" -Wall -Wno-parentheses)
if(TAISEI_DEBUG)
add_definitions(-DDEBUG)
endif()
if(WERROR)
add_definitions(-Werror)
endif()
set(LIBs ${LIBs}
${SDL_LIBRARY}
${PNG_LIBRARY}
@ -97,7 +102,7 @@ if(ZLIB_FOUND)
endif()
if(WIN32)
set(LIBs ${LIBs} -ldxguid -limm32 -lversion)
set(LIBs ${LIBs} -ldxguid -lwinmm)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${SDL_INCLUDE_DIR} ${ALUT_INCLUDE_DIR})

View file

@ -10,7 +10,6 @@
#define CONFIG_H
#include <SDL/SDL_keysym.h>
#include "parser.h"
typedef struct Config {
int intval[64];

270
src/credits.c Normal file
View file

@ -0,0 +1,270 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#include "credits.h"
#include "global.h"
#include "stageutils.h"
#include "video.h"
static Stage3D bgcontext;
typedef struct CreditsEntry {
char **data;
int lines;
int time;
} CreditsEntry;
static struct {
CreditsEntry *entries;
int ecount;
float panelalpha;
float fadeout;
int end;
} credits;
void credits_fill(void) {
credits_add("Taisei Project\nbrought to you by...", 200);
credits_add("laochailan\nLukas Weber\nlaochailan@web.de", 300);
credits_add("Akari\nAndrew Alexeyew\nhttp://akari.thebadasschoobs.org/", 300);
credits_add("lachs0r\nMartin Herkt\nlachs0r@hong-mailing.de", 300);
credits_add("Special Thanks", 300);
credits_add("ZUN\nfor Touhou Project\nhttp://www16.big.or.jp/~zun/", 300);
// credits_add("Burj Khalifa\nfor the Burj Khalifa photo\nhttp://www.burjkhalifa.ae/", 300);
credits_add("Mochizuki Ado\nfor a nice yukkuri image", 300);
credits_add("...and You!\nfor playing", 300);
credits_add("Visit Us\nhttp://taisei-project.org/\n \nAnd join our IRC channel\n#taisei-project at irc.freenode.net", 500);
credits_add("*", 150);
}
void credits_add(char *data, int time) {
CreditsEntry *e;
char *c, buf[256];
int l = 0, i = 0;
credits.entries = realloc(credits.entries, (++credits.ecount) * sizeof(CreditsEntry));
e = &(credits.entries[credits.ecount-1]);
e->time = time;
e->lines = 1;
for(c = data; *c; ++c)
if(*c == '\n') e->lines++;
e->data = malloc(e->lines * sizeof(char**));
for(c = data; *c; ++c) {
if(*c == '\n') {
buf[i] = 0;
e->data[l] = malloc(strlen(buf) + 1);
strcpy(e->data[l], buf);
i = 0;
++l;
} else {
buf[i++] = *c;
}
}
buf[i] = 0;
e->data[l] = malloc(strlen(buf) + 1);
strcpy(e->data[l], buf);
credits.end += time + CREDITS_ENTRY_FADEOUT;
}
Vector **stage6_towerwall_pos(Vector pos, float maxrange);
void stage6_towerwall_draw(Vector pos);
void credits_skysphere_draw(Vector pos) {
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glBindTexture(GL_TEXTURE_2D, get_tex("stage6/sky")->gltex);
glPushMatrix();
glTranslatef(pos[0], pos[1], pos[2]-30);
float s = 370;
glScalef(s, s, s);
draw_model("skysphere");
glPopMatrix();
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
}
void credits_towerwall_draw(Vector pos) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, get_tex("stage6/towerwall")->gltex);
if(!tconfig.intval[NO_SHADER]) {
Shader *s = get_shader("tower_wall");
glUseProgram(s->prog);
glUniform1i(uniloc(s, "lendiv"), 2800.0 + 300.0 * sin(global.frames / 77.7));
}
glPushMatrix();
glTranslatef(pos[0], pos[1], pos[2]);
// glRotatef(90, 1,0,0);
glScalef(30,30,30);
draw_model("towerwall");
glPopMatrix();
glUseProgram(0);
glDisable(GL_TEXTURE_2D);
}
Vector **credits_skysphere_pos(Vector pos, float maxrange) {
return single3dpos(pos, maxrange, bgcontext.cx);
}
void credits_init(void) {
memset(&credits, 0, sizeof(credits));
init_stage3d(&bgcontext);
add_model(&bgcontext, credits_skysphere_draw, credits_skysphere_pos);
add_model(&bgcontext, credits_towerwall_draw, stage6_towerwall_pos);
bgcontext.cx[0] = 0;
bgcontext.cx[1] = 600;
bgcontext.crot[0] = 0;
bgcontext.crot[1] = 10;
global.frames = 0;
credits_fill();
credits.end += 500 + CREDITS_ENTRY_FADEOUT;
}
void credits_draw_entry(CreditsEntry *e) {
int time = global.frames - 400, i, yukkuri = False;
float first, other = 0, fadein = 1, fadeout = 1;
CreditsEntry *o;
Texture *ytex;
for(o = credits.entries; o != e; ++o)
time -= o->time + CREDITS_ENTRY_FADEOUT;
if(time < 0)
return;
if(time <= CREDITS_ENTRY_FADEIN)
fadein = time / CREDITS_ENTRY_FADEIN;
if(time - e->time - CREDITS_ENTRY_FADEIN > 0)
fadeout = max(0, 1 - (time - e->time - CREDITS_ENTRY_FADEIN) / CREDITS_ENTRY_FADEOUT);
if(!fadein || !fadeout)
return;
if(*(e->data[0]) == '*') {
yukkuri = True;
ytex = get_tex("yukkureimu");
}
first = yukkuri? ytex->trueh * CREDITS_YUKKURI_SCALE : (stringheight(e->data[0], _fonts.mainmenu) * 1.2);
if(e->lines > 1)
other = stringheight(e->data[1], _fonts.standard) * 1.3;
glPushMatrix();
if(fadein < 1)
glTranslatef(0, SCREEN_W * pow(1 - fadein, 2) * 0.5, 0);
else if(fadeout < 1)
glTranslatef(0, SCREEN_W * pow(1 - fadeout, 2) * -0.5, 0);
glColor4f(1, 1, 1, fadein * fadeout);
for(i = 0; i < e->lines; ++i) {
if(yukkuri && !i) {
glPushMatrix();
glScalef(CREDITS_YUKKURI_SCALE, CREDITS_YUKKURI_SCALE, 1.0);
draw_texture_p(0, (first + other * (e->lines-1)) / -8 + 10 * sin(global.frames / 10.0) * fadeout * fadein, ytex);
glPopMatrix();
} else draw_text(AL_Center, 0,
(first + other * (e->lines-1)) * -0.25 + (i? first/4 + other/2 * i : 0) + (yukkuri? other*2.5 : 0), e->data[i],
(i? _fonts.standard : _fonts.mainmenu));
}
glPopMatrix();
glColor4f(1, 1, 1, 1);
}
void credits_draw(void) {
//glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(-SCREEN_W/2, 0, 0);
glEnable(GL_DEPTH_TEST);
set_perspective_viewport(&bgcontext, 100, 9000, 0, 0, SCREEN_W, SCREEN_H);
draw_stage3d(&bgcontext, 10000);
glPopMatrix();
set_ortho();
glPushMatrix();
glColor4f(0, 0, 0, credits.panelalpha * 0.7);
glTranslatef(SCREEN_W/4*3, SCREEN_H/2, 0);
glScalef(300, SCREEN_H, 1);
draw_quad();
glPopMatrix();
glPushMatrix();
glColor4f(1, 1, 1, credits.panelalpha * 0.7);
glTranslatef(SCREEN_W/4*3, SCREEN_H/2, 0);
glColor4f(1, 1, 1, 1);
int i; for(i = 0; i < credits.ecount; ++i)
credits_draw_entry(&(credits.entries[i]));
glPopMatrix();
colorfill(1, 1, 1, 1 - (global.frames / 300.0));
colorfill(1, 1, 1, credits.fadeout);
}
void credits_process(void) {
TIMER(&global.frames);
bgcontext.cx[2] = 200 - global.frames * 50;
bgcontext.cx[1] = 500 + 100 * psin(global.frames / 100.0) * psin(global.frames / 200.0 + M_PI);
//bgcontext.cx[0] += nfrand();
bgcontext.cx[0] = 25 * sin(global.frames / 75.7) * cos(global.frames / 99.3);
FROM_TO(200, 300, 1)
credits.panelalpha += 0.01;
if(global.frames >= credits.end - CREDITS_ENTRY_FADEOUT) {
credits.panelalpha -= 1 / 120.0;
}
if(global.frames >= credits.end) {
credits.fadeout += 1 / 120.0;
}
}
void credits_input(void) {
SDL_Event event;
while(SDL_PollEvent(&event))
global_processevent(&event);
}
void credits_free(void) {
int i, j;
for(i = 0; i < credits.ecount; ++i) {
CreditsEntry *e = &(credits.entries[i]);
for(j = 0; j < e->lines; ++j)
free(e->data[j]);
free(e->data);
}
free(credits.entries);
}
void credits_loop(void) {
credits_init();
while(credits.fadeout <= 1) {
credits_input();
credits_process();
credits_draw();
global.frames++;
SDL_GL_SwapBuffers();
frame_rate(&global.lasttime);
}
global.whitefade = 1.0;
credits_free();
}

20
src/credits.h Normal file
View file

@ -0,0 +1,20 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#ifndef CREDITS_H
#define CREDITS_H
void credits_input(void);
void credits_loop(void);
void credits_add(char*, int);
#define CREDITS_ENTRY_FADEIN 200.0
#define CREDITS_ENTRY_FADEOUT 100.0
#define CREDITS_YUKKURI_SCALE 0.5
#endif

144
src/ending.c Normal file
View file

@ -0,0 +1,144 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#include "ending.h"
#include "global.h"
#include "credits.h"
void add_ending_entry(Ending *e, int dur, char *msg, char *tex) {
EndingEntry *entry;
e->entries = realloc(e->entries, (++e->count)*sizeof(EndingEntry));
entry = &e->entries[e->count-1];
entry->time = e->duration;
e->duration += dur;
entry->msg = strdup(msg);
if(tex)
entry->tex = get_tex(tex);
else
entry->tex = NULL;
}
void bad_ending_marisa(Ending *e) {
add_ending_entry(e, 300, "After her consciousness had faded while she was falling down the tower,\nMarisa found herself waking up in a clearing of the magical forest.", NULL);
add_ending_entry(e, 300, "She saw the sun set.", NULL);
add_ending_entry(e, 300, "Maybe all of this was just a day dream.", NULL);
add_ending_entry(e, 300, "But nevertheless, she won the fight, that's all what counts ... isn't it?", NULL);
add_ending_entry(e, 200, "[Bad Ending 1]", NULL);
}
void bad_ending_youmu(Ending *e) {
add_ending_entry(e, 400, "After getting unconscious from falling the tower,\nYoumu only remembered how she rushed back to Hakugyokuro.", NULL);
add_ending_entry(e, 300, "The anomalies were gone, everything went back to normal.", NULL);
add_ending_entry(e, 400, "Youmu was relieved, but she felt that the real mystery of the land\nbehind the tunnel was left unsolved forever.", NULL);
add_ending_entry(e, 300, "This left her unsatisfied ...", NULL);
add_ending_entry(e, 200, "[Bad Ending 2]", NULL);
}
void good_ending_marisa(Ending *e) {
add_ending_entry(e, 400, "As soon as Elly was defeated, the room they were in\nbegan to fade and they landed softly on a wide plain of grass.", NULL);
add_ending_entry(e, 350, "Elly and her friend promised that they won't cause any more trouble,\nbut Marisa was curious to explore the rest of this unknown land.", NULL);
add_ending_entry(e, 350, "Who was the real culprit? What were their motives?", NULL);
add_ending_entry(e, 350, "She craved to find out ...", NULL);
add_ending_entry(e, 200, "[Good Ending 1]", NULL);
}
void good_ending_youmu(Ending *e) {
add_ending_entry(e, 300, "When they reached the ground, the tower and everything in that world\nbegan to fade to a endless plain of grass.", NULL);
add_ending_entry(e, 550, "\"Always consider what trouble you cause others when you plan a mega project like that\"\nsaid Youmu confidently,\n\"that's the first rule in Gensokyo, if you don't want people to come for you and fight.\"", NULL);
add_ending_entry(e, 320, "Elly would fix up the the border as soon as possible as she promised.", NULL);
add_ending_entry(e, 350, "But before the way to this unknown place was sealed forever,\nYoumu decided travel it once more ...", NULL);
add_ending_entry(e, 200, "[Good Ending 2]", NULL);
}
void create_ending(Ending *e) {
memset(e, 0, sizeof(Ending));
if(global.plr.continues || global.diff == D_Easy) {
switch(global.plr.cha) {
case Marisa:
bad_ending_marisa(e);
break;
case Youmu:
bad_ending_youmu(e);
break;
}
add_ending_entry(e, 400, "Try a no continue run on higher difficulties. You can do it!", NULL);
} else {
switch(global.plr.cha) {
case Marisa:
good_ending_marisa(e);
break;
case Youmu:
good_ending_youmu(e);
break;
}
add_ending_entry(e, 400, "Sorry, extra stage isn't done yet. ^^", NULL);
}
if(global.diff == D_Lunatic)
add_ending_entry(e, 400, "Lunatic? Didn't know this was even possible. Cheater.", NULL);
add_ending_entry(e, 400, "", NULL);
}
void free_ending(Ending *e) {
int i;
for(i = 0; i < e->count; i++)
free(e->entries[i].msg);
free(e->entries);
}
void ending_draw(Ending *e) {
float s, d;
int t1 = global.frames-e->entries[e->pos].time;
int t2 = e->entries[e->pos+1].time-global.frames;
d = 1.0/ENDING_FADE_TIME;
if(t1 < ENDING_FADE_TIME)
s = clamp(d*t1, 0.0, 1.0);
else
s = clamp(d*t2, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor4f(1,1,1,s);
if(e->entries[e->pos].tex)
draw_texture_p(SCREEN_W/2, SCREEN_H/2, e->entries[e->pos].tex);
draw_text(AL_Center, SCREEN_W/2, SCREEN_H/5*4, e->entries[e->pos].msg, _fonts.standard);
glColor4f(1,1,1,1);
if(global.frames > - e->entries[e->count-1].time-ENDING_FADE_OUT)
colorfill(1, 1, 1, (global.frames - e->entries[e->count-1].time + ENDING_FADE_OUT)/(float)ENDING_FADE_OUT);
// colorfill(1, 1, 1, 1);
}
void ending_loop(void) {
Ending e;
create_ending(&e);
global.frames = 0;
set_ortho();
while(e.pos < e.count-1) {
credits_input();
ending_draw(&e);
global.frames++;
SDL_GL_SwapBuffers();
frame_rate(&global.lasttime);
if(global.frames >= e.entries[e.pos+1].time)
e.pos++;
}
}

42
src/ending.h Normal file
View file

@ -0,0 +1,42 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#ifndef ENDING_H
#define ENDING_H
#include "resource/texture.h"
enum {
ENDING_FADE_OUT = 200,
ENDING_FADE_TIME = 60,
};
typedef struct EndingEntry EndingEntry;
struct EndingEntry {
char *msg;
Texture *tex;
int time;
};
typedef struct Ending Ending;
struct Ending {
EndingEntry *entries;
int count;
int duration;
int pos;
};
void add_ending_entry(Ending *e, int time, char *msg, char *tex);
void create_ending(Ending *e);
void ending_loop(void);
void free_ending(Ending *e);
#endif

View file

@ -36,7 +36,6 @@ Enemy *create_enemy_p(Enemy **enemies, complex pos, int hp, EnemyDrawRule draw_r
e->args[3] = a4;
e->logic_rule(e, EVENT_BIRTH);
return e;
}
@ -45,13 +44,15 @@ void _delete_enemy(void **enemies, void* enemy) {
if(e->hp <= 0 && e->hp > ENEMY_IMMUNE) {
int i;
for(i = 0; i < 10; i++)
create_particle2c("flare", e->pos, NULL, Fade, timeout_linear, 10, (3+frand()*10)*cexp(I*frand()*2*M_PI));
for(i = 0; i < 10; i++) {
tsrand_fill(2);
create_particle2c("flare", e->pos, NULL, Fade, timeout_linear, 10, (3+afrand(0)*10)*cexp(I*afrand(1)*2*M_PI));
}
create_particle1c("blast", e->pos, NULL, Blast, timeout, 20);
create_particle1c("blast", e->pos, NULL, Blast, timeout, 20);
create_particle2c("blast", e->pos, NULL, GrowFade, timeout, 15,0);
e->logic_rule(enemy, EVENT_DEATH);
}
e->logic_rule(enemy, EVENT_DEATH);
del_ref(enemy);
delete_element((void **)enemies, enemy);

View file

@ -87,10 +87,10 @@ void set_ortho() {
glDisable(GL_DEPTH_TEST);
}
void fade_out(float f) {
if(f == 0) return;
void colorfill(float r, float g, float b, float a) {
if(a <= 0) return;
glColor4f(0,0,0,f);
glColor4f(r,g,b,a);
glPushMatrix();
glScalef(SCREEN_W,SCREEN_H,1);
@ -102,6 +102,10 @@ void fade_out(float f) {
glColor4f(1,1,1,1);
}
void fade_out(float f) {
colorfill(0, 0, 0, f);
}
inline double psin(double x) {
return 0.5 + 0.5 * sin(x);
}
@ -114,6 +118,15 @@ inline double min(double a, double b) {
return (a < b)? a : b;
}
inline double clamp(double f, double lower, double upper) {
if(f < lower)
return lower;
if(f > upper)
return upper;
return f;
}
void take_screenshot()
{
FILE *out;
@ -196,6 +209,8 @@ void global_processevent(SDL_Event *event)
take_screenshot();
if((sym == SDLK_RETURN && (keys[SDLK_LALT] || keys[SDLK_RALT])) || sym == tconfig.intval[KEY_FULLSCREEN])
video_toggle_fullscreen();
} else if(event->type == SDL_QUIT) {
exit(0);
}
}

View file

@ -121,6 +121,8 @@ typedef struct {
RandomState rand_game;
RandomState rand_visual;
float whitefade; // hack for credits --> main transition
} Global;
extern Global global;
@ -131,6 +133,7 @@ void game_over();
void frame_rate(int *lasttime);
void calc_fps(FPSCounter *fps);
void set_ortho();
void colorfill(float r, float g, float b, float a);
void fade_out(float f);
void global_processevent(SDL_Event*);
@ -147,6 +150,7 @@ double psin();
// min(huge_costly_expression, another_huge_costly_expression)
double min(double, double);
double max(double, double);
double clamp(double, double, double);
double approach(double v, double t, double d);
int strendswith(char *s, char *e);
char* difficulty_name(Difficulty diff);
@ -159,6 +163,4 @@ enum {
EV_OVER // replay-only
};
#define REPLAY_ASKSAVE (tconfig.intval[SAVE_RPY] == 2 && global.replay.active && global.replaymode == REPLAY_RECORD)
#endif

View file

@ -110,7 +110,7 @@ int main(int argc, char** argv) {
printf("** Invalid stage number. Quitting stage skip mode.\n");
}
#endif
MenuData menu;
create_main_menu(&menu);
printf("-- menu\n");

View file

@ -37,22 +37,13 @@ void ingame_menu_logic(MenuData **menu) {
void draw_ingame_menu(MenuData *menu) {
float rad = IMENU_BLUR;
float fade = menu->fade;
if( // horrible hacks because we have no sane transitions between ingame menus
REPLAY_ASKSAVE && (
(menu->selected != 0 && menu->quit == 1 && !menu->context) ||
(!menu->quit && menu->context)
)
) fade = 0;
if(menu->selected != 1 || (global.game_over && global.replaymode == REPLAY_PLAY)) // hardly hardcoded. 1 -> "Return to Title"
if(menu->selected != 1) // hardly hardcoded. 1 -> "Return to Title"
rad = IMENU_BLUR * (1.0-fade);
if(!tconfig.intval[NO_SHADER]) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Shader *shader = get_shader("ingame_menu");
glUseProgram(shader->prog);

View file

@ -13,9 +13,12 @@
#include "options.h"
#include "stageselect.h"
#include "replayview.h"
#include "savereplay.h"
#include "global.h"
#include "stage.h"
#include "ending.h"
#include "credits.h"
#include "paths/native.h"
void quit_menu(void *arg) {
@ -37,6 +40,8 @@ troll:
if(char_menu_loop(&m) == -1)
goto troll;
replay_init(&global.replay);
if(arg)
((StageInfo*)arg)->loop();
else {
@ -45,6 +50,30 @@ troll:
stages[i].loop();
}
if(global.replay.active) {
switch(tconfig.intval[SAVE_RPY]) {
case 0: break;
case 1: {
save_rpy(NULL);
break;
}
case 2: {
MenuData m;
create_saverpy_menu(&m);
saverpy_menu_loop(&m);
break;
}
}
}
if(global.game_over == GAMEOVER_WIN && !arg) {
ending_loop();
credits_loop();
}
replay_destroy(&global.replay);
global.game_over = 0;
}
@ -134,6 +163,10 @@ void draw_main_menu(MenuData *menu) {
fade_out(menu->fade);
if(global.whitefade > 0) {
colorfill(1, 1, 1, global.whitefade);
global.whitefade -= 1 / 300.0;
} else global.whitefade = 0;
}
void main_menu_loop(MenuData *menu) {

View file

@ -51,12 +51,16 @@ void create_menu(MenuData *menu) {
static void key_action(MenuData *menu, int sym) {
Uint8 *keys = SDL_GetKeyState(NULL);
if(sym == tconfig.intval[KEY_DOWN] || sym == SDLK_DOWN) {
int look_i_can_hardcode_annoying_menu_hacks_too = menu->title && !strcmp(menu->title, "Save replay?");
if(sym == tconfig.intval[KEY_DOWN] || sym == SDLK_DOWN || look_i_can_hardcode_annoying_menu_hacks_too &&
(sym == tconfig.intval[KEY_RIGHT] || sym == SDLK_RIGHT)) {
do {
if(++menu->cursor >= menu->ecount)
menu->cursor = 0;
} while(menu->entries[menu->cursor].action == NULL);
} else if(sym == tconfig.intval[KEY_UP] || sym == SDLK_UP) {
} else if(sym == tconfig.intval[KEY_UP] || sym == SDLK_UP || look_i_can_hardcode_annoying_menu_hacks_too &&
(sym == tconfig.intval[KEY_LEFT] || sym == SDLK_LEFT)) {
do {
if(--menu->cursor < 0)
menu->cursor = menu->ecount - 1;
@ -64,8 +68,9 @@ static void key_action(MenuData *menu, int sym) {
} else if((sym == tconfig.intval[KEY_SHOT] || (sym == SDLK_RETURN && !keys[SDLK_LALT] && !keys[SDLK_LALT])) && menu->entries[menu->cursor].action) {
menu->quit = 1;
menu->selected = menu->cursor;
} else if(sym == SDLK_ESCAPE && menu->type == MT_Transient) {
} else if(sym == SDLK_ESCAPE && (menu->type == MT_Transient || menu->abortable)) {
menu->quit = 1;
menu->abort = 1;
}
}
@ -76,16 +81,15 @@ void menu_input(MenuData *menu) {
int sym = event.key.keysym.sym;
global_processevent(&event);
if(event.type == SDL_KEYDOWN) {
if(event.type == SDL_KEYDOWN)
key_action(menu,sym);
} else if(event.type == SDL_QUIT) {
exit(1);
}
}
}
void menu_logic(MenuData *menu) {
int hax;
menu->frames++;
if(menu->quit == 1 && menu->fade < 1.0)
menu->fade += 1.0/FADE_TIME;
if(menu->quit == 0 && menu->fade > 0)
@ -95,10 +99,16 @@ void menu_logic(MenuData *menu) {
menu->fade = 0;
if(menu->fade > 1)
menu->fade = 1;
if(menu->quit == 1 && menu->fade >= 1.0) {
if(menu->quit == 1 && (menu->fade >= 1.0 || (hax = (!menu->abort && menu->instantselect)))) {
if(hax)
menu->fade = 0;
global.whitefade = 0;
menu->quit = menu->type == MT_Transient ? 2 : 0;
if(menu->selected != -1 && menu->entries[menu->selected].action != NULL)
if(menu->abort && menu->abortaction)
menu->abortaction(menu->abortarg);
else if(menu->selected != -1 && menu->entries[menu->selected].action != NULL)
menu->entries[menu->selected].action(menu->entries[menu->selected].arg);
}
}

View file

@ -41,6 +41,11 @@ typedef struct MenuData{
int quit;
float fade;
int abort;
int abortable;
void (*abortaction)(void *arg);
void *abortarg;
int instantselect;
float drawdata[4];

View file

@ -641,8 +641,6 @@ void bind_input(MenuData *menu, OptionBinding *b)
} else
b->blockinput = False;
} else if(event.type == SDL_QUIT) {
exit(1);
}
}
SDL_EnableUNICODE(False);
@ -717,11 +715,8 @@ void options_menu_input(MenuData *menu) {
int sym = event.key.keysym.sym;
global_processevent(&event);
if(event.type == SDL_KEYDOWN) {
if(event.type == SDL_KEYDOWN)
options_key_action(menu, sym);
} else if(event.type == SDL_QUIT) {
exit(1);
}
}
}

View file

@ -1,28 +0,0 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
* Copyright (C) 2012, Alexeyew Andrew <https://github.com/nexAkari>
*/
#include "replayover.h"
#include "global.h"
static void rewatch(void *arg) {
global.game_over = GAMEOVER_REWATCH;
}
static void backtotitle(void *arg) {
((MenuData*)arg)->quit = 2;
}
MenuData* create_replayover_menu() {
MenuData *m = malloc(sizeof(MenuData));
create_menu(m);
add_menu_entry(m, "Rewatch", rewatch, NULL);
add_menu_entry(m, "Return to Title", backtotitle, m);
m->selected = 1;
return m;
}

View file

@ -1,16 +0,0 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
* Copyright (C) 2012, Alexeyew Andrew <https://github.com/nexAkari>
*/
#ifndef RPYOVERMENU_H
#define RPYOVERMENU_H
#include "menu.h"
MenuData *create_replayover_menu();
#endif

View file

@ -16,32 +16,68 @@
#include "paths/native.h"
#include "plrmodes.h"
#include "video.h"
#include "stageselect.h"
void backtomain(void*);
// I give up.
static MenuData *replayview;
static int pickedstage;
void start_replay(void *arg) {
ReplayStage *rstg;
StageInfo *gstg;
int i;
replay_copy(&global.replay, (Replay*)arg);
global.replaymode = REPLAY_PLAY;
StageInfo *s = stage_get(global.replay.stage);
if(!s) {
printf("Invalid stage %d in replay... wtf?!\n", global.replay.stage);
return;
}
if(global.replay.stgcount == 1)
pickedstage = 0;
init_player(&global.plr);
global.replaymode = REPLAY_PLAY;
s->loop();
if(global.game_over == GAMEOVER_REWATCH) {
for(i = pickedstage; i < global.replay.stgcount; ++i) {
replay_select(&global.replay, i);
rstg = global.replay.current;
gstg = stage_get(rstg->stage);
if(!gstg) {
printf("start_replay(): Invalid stage %d in replay at %i skipped.\n", rstg->stage, i);
continue;
}
gstg->loop();
if(global.game_over == GAMEOVER_ABORT)
break;
global.game_over = 0;
start_replay(arg);
return;
}
global.replaymode = REPLAY_RECORD;
global.game_over = 0;
global.replaymode = REPLAY_RECORD;
replay_destroy(&global.replay);
replayview->instantselect = False;
}
MenuData* replayview_stageselect(Replay *rpy) {
MenuData *m = malloc(sizeof(MenuData));
int i;
create_menu(m);
m->context = rpy;
for(i = 0; i < rpy->stgcount; ++i) {
add_menu_entry(m, stage_get(rpy->stages[i].stage)->title, start_replay, rpy);
}
return m;
}
void replayview_run(void *arg) {
Replay *rpy = arg;
if(rpy->stgcount > 1)
replayview->context = replayview_stageselect(rpy);
else
start_replay(rpy);
}
static void replayview_freearg(void *a) {
@ -65,10 +101,66 @@ static void shorten(char *s, int width) {
s[c - i] = '.';
}
static void replayview_draw_stagemenu(MenuData *m) {
float alpha = 1 - m->fade;
int i;
float height = (1+m->ecount) * 20;
float width = 100;
glPushMatrix();
glTranslatef(SCREEN_W*0.5, SCREEN_H*0.5, 0);
glScalef(width, height, 1);
glColor4f(0.1, 0.1, 0.1, 0.7 * alpha);
draw_quad();
glPopMatrix();
glPushMatrix();
glTranslatef(SCREEN_W*0.5, (SCREEN_H-(m->ecount-1)*20)*0.5, 0);
for(i = 0; i < m->ecount; ++i) {
MenuEntry *e = &(m->entries[i]);
float a = e->drawdata += 0.2 * ((i == m->cursor) - e->drawdata);
if(e->action == NULL)
glColor4f(0.5, 0.5, 0.5, 0.5 * alpha);
else {
float ia = 1-a;
glColor4f(0.9 + ia * 0.1, 0.6 + ia * 0.4, 0.2 + ia * 0.8, (0.7 + 0.3 * a) * alpha);
}
if(i == m->cursor)
pickedstage = i;
draw_text(AL_Center, 0, 20*i, e->name, _fonts.standard);
}
glPopMatrix();
}
static void replayview_draw(MenuData *m) {
draw_stage_menu(m);
if(m->context) {
MenuData *sm = m->context;
menu_logic(sm);
if(sm->quit == 2) {
destroy_menu(sm);
m->context = NULL;
} else {
fade_out(0.3 * (1 - sm->fade));
replayview_draw_stagemenu(sm);
if(!sm->abort && sm->quit == 1)
m->fade = sm->fade;
}
}
}
static void replayview_drawitem(void *n, int item, int cnt) {
MenuEntry *e = (MenuEntry*)n;
Replay *rpy = (Replay*)e->arg;
float sizes[] = {1.2, 1.5, 0.8, 0.8, 0.6};
float sizes[] = {1.2, 1.45, 0.8, 0.8, 0.65};
int columns = 5, i, j;
for(i = 0; i < columns; ++i) {
@ -85,7 +177,7 @@ static void replayview_drawitem(void *n, int item, int cnt) {
switch(i) {
case 0:
a = AL_Left;
time_t t = rpy->seed;
time_t t = rpy->stages[0].seed;
struct tm* timeinfo = localtime(&t);
strftime(tmp, 128, "%Y-%m-%d %H:%M", timeinfo);
break;
@ -96,17 +188,20 @@ static void replayview_drawitem(void *n, int item, int cnt) {
break;
case 2:
plrmode_repr(tmp, 128, rpy->plr_char, rpy->plr_shot);
plrmode_repr(tmp, 128, rpy->stages[0].plr_char, rpy->stages[0].plr_shot);
tmp[0] = tmp[0] - 'a' + 'A';
break;
case 3:
snprintf(tmp, 128, difficulty_name(rpy->diff));
snprintf(tmp, 128, difficulty_name(rpy->stages[0].diff));
break;
case 4:
a = AL_Right;
snprintf(tmp, 128, "Stage %i", rpy->stage);
if(rpy->stgcount == 1)
snprintf(tmp, 128, "Stage %i", rpy->stages[0].stage);
else
snprintf(tmp, 128, "%i stages", rpy->stgcount);
break;
}
@ -122,7 +217,7 @@ static void replayview_drawitem(void *n, int item, int cnt) {
}
int replayview_cmp(const void *a, const void *b) {
return ((Replay*)(((MenuEntry*)b)->arg))->seed - ((Replay*)(((MenuEntry*)a)->arg))->seed;
return ((Replay*)(((MenuEntry*)b)->arg))->stages[0].seed - ((Replay*)(((MenuEntry*)a)->arg))->stages[0].seed;
}
int fill_replayview_menu(MenuData *m) {
@ -148,14 +243,7 @@ int fill_replayview_menu(MenuData *m) {
continue;
}
/*
int size = strlen(e->d_name) - strlen(ext) + 1;
char *s = (char*)malloc(size);
strncpy(s, e->d_name, size);
s[size-1] = 0;
*/
add_menu_entry(m, " ", start_replay, rpy);
add_menu_entry(m, " ", replayview_run, rpy);
m->entries[m->ecount-1].freearg = replayview_freearg;
m->entries[m->ecount-1].draw = replayview_drawitem;
++rpys;
@ -167,27 +255,51 @@ int fill_replayview_menu(MenuData *m) {
return rpys;
}
void replayview_abort(void *a) {
MenuData *m = a;
m->quit = 2;
if(m->context) { // will unlikely get here
MenuData *sm = m->context;
destroy_menu(sm);
m->context = NULL;
}
}
void create_replayview_menu(MenuData *m) {
create_menu(m);
m->type = MT_Transient;
m->type = MT_Persistent;
m->abortable = True;
m->abortaction = replayview_abort;
m->abortarg = m;
m->title = "Replays";
replayview = m;
int r = fill_replayview_menu(m);
if(!r) {
add_menu_entry(m, "No replays available. Play the game and record some!", backtomain, m);
add_menu_entry(m, "No replays available. Play the game and record some!", replayview_abort, m);
} else if(r < 0) {
add_menu_entry(m, "There was a problem getting the replay list :(", backtomain, m);
add_menu_entry(m, "There was a problem getting the replay list :(", replayview_abort, m);
} else {
add_menu_separator(m);
add_menu_entry(m, "Back", backtomain, m);
add_menu_entry(m, "Back", replayview_abort, m);
}
printf("create_replayview_menu()\n");
}
void draw_stage_menu(MenuData *m);
int replayview_menu_loop(MenuData *m) {
return menu_loop(m, NULL, draw_stage_menu);
void replayview_menu_input(MenuData *m) {
if(m->context)
menu_input((MenuData*)m->context);
else
menu_input(m);
if(m->selected >= 0)
m->instantselect = m->selected != m->ecount-1 && (((Replay*)m->entries[m->selected].arg)->stgcount > 1);
}
int replayview_menu_loop(MenuData *m) {
return menu_loop(m, replayview_menu_input, replayview_draw);
}

View file

@ -8,6 +8,7 @@
#include <time.h>
#include "savereplay.h"
#include "options.h"
#include "global.h"
#include "replay.h"
#include "plrmodes.h"
@ -19,29 +20,67 @@ void save_rpy(void *a) {
struct tm * timeinfo;
// time when the game was *initiated*
rawtime = (time_t)rpy->seed;
rawtime = (time_t)rpy->stages[0].seed;
timeinfo = localtime(&rawtime);
strftime(strtime, 128, "%Y%m%d_%H-%M-%S_%Z", timeinfo);
char prepr[16];
plrmode_repr(prepr, 16, rpy->plr_char, rpy->plr_shot);
snprintf(name, 128, "taisei_stg%d_%s_%s", rpy->stage, prepr, strtime);
char prepr[16], drepr[16];
plrmode_repr(prepr, 16, rpy->stages[0].plr_char, rpy->stages[0].plr_shot);
strncpy(drepr, difficulty_name(rpy->stages[0].diff), 16);
drepr[0] += 'a' - 'A';
if(rpy->stgcount > 1)
snprintf(name, 128, "taisei_%s_%s_%s", strtime, prepr, drepr);
else
snprintf(name, 128, "taisei_%s_stg%d_%s_%s", strtime, rpy->stages[0].stage, prepr, drepr);
replay_save(rpy, name);
if(a) ((MenuData*)a)->quit = 2;
}
void dont_save_rpy(void *a) {
//((MenuData*)a)->quit = 2;
((MenuData*)a)->selected = 0;
((MenuData*)a)->quit = 2;
}
MenuData* create_saverpy_menu() {
MenuData *m = malloc(sizeof(MenuData));
void create_saverpy_menu(MenuData *m) {
create_menu(m);
m->context = "Save replay?";
m->type = MT_Persistent;
m->title = "Save replay?";
add_menu_entry(m, "Yes", save_rpy, m);
add_menu_entry(m, "No", dont_save_rpy, m);
return m;
}
void draw_saverpy_menu(MenuData *m) {
draw_options_menu_bg(m);
glPushMatrix();
glTranslatef(SCREEN_W/2, SCREEN_H/2 - 100, 0);
draw_text(AL_Center, 0, 0, m->title, _fonts.mainmenu);
glTranslatef(0, 100, 0);
int i; for(i = 0; i < m->ecount; i++) {
MenuEntry *e = &(m->entries[i]);
e->drawdata += 0.2 * (10*(i == m->cursor) - e->drawdata);
float a = e->drawdata * 0.1;
if(e->action == NULL)
glColor4f(0.5, 0.5, 0.5, 0.5);
else {
float ia = 1-a;
glColor4f(0.9 + ia * 0.1, 0.6 + ia * 0.4, 0.2 + ia * 0.8, 0.7 + 0.3 * a);
}
if(e->name)
draw_text(AL_Center, -50 + 100 * i, 0, e->name, _fonts.mainmenu);
}
glPopMatrix();
fade_out(m->fade);
}
int saverpy_menu_loop(MenuData *m) {
return menu_loop(m, NULL, draw_saverpy_menu);
}

View file

@ -12,6 +12,7 @@
#include "menu.h"
void save_rpy(void*);
MenuData *create_saverpy_menu();
void create_saverpy_menu(MenuData*);
int saverpy_menu_loop(MenuData*);
#endif

View file

@ -20,7 +20,10 @@ void create_stage_menu(MenuData *m) {
int i;
create_menu(m);
m->type = MT_Transient;
m->type = MT_Persistent;
m->abortable = True;
m->abortaction = backtomain;
m->abortarg = m;
// TODO: I think ALL menus should use the title field, but I don't want to screw with it right now.
m->title = "Stage Select";
@ -38,7 +41,7 @@ void draw_stage_menu(MenuData *m) {
draw_text(AL_Right, (stringwidth(m->title, _fonts.mainmenu) + 10) * (1-m->fade), 30, m->title, _fonts.mainmenu);
glPushMatrix();
glTranslatef(100, 100 + ((m->ecount * 20 + 140 > SCREEN_W)? min(0, SCREEN_H * 0.7 - 100 - m->drawdata[2]) : 0), 0);
glTranslatef(100, 100 + (((m->ecount * 20 + 290) > SCREEN_W)? min(0, SCREEN_H * 0.7 - 100 - m->drawdata[2]) : 0), 0);
/*
glPushMatrix();

View file

@ -22,7 +22,6 @@ void init_player(Player* plr) {
plr->bombs = PLR_START_BOMBS;
plr->deathtime = -1;
plr->continues = 0;
}
@ -222,8 +221,10 @@ void player_realdeath(Player *plr) {
void player_death(Player *plr) {
if(plr->deathtime == -1 && global.frames - abs(plr->recovery) > 0) {
int i;
for(i = 0; i < 20; i++)
create_particle2c("flare", plr->pos, NULL, Shrink, timeout_linear, 40, (3+frand()*7)*cexp(I*tsrand()));
for(i = 0; i < 20; i++) {
tsrand_fill(2);
create_particle2c("flare", plr->pos, NULL, Shrink, timeout_linear, 40, (3+afrand(0)*7)*cexp(I*tsrand_a(1)));
}
create_particle2c("blast", plr->pos, rgb(1,0.5,0.3), GrowFade, timeout, 35, 2.4);
plr->deathtime = global.frames + DEATHBOMB_TIME;
}

View file

@ -230,6 +230,8 @@ void youmu_bomb(Player *plr) {
}
void youmu_power(Player *plr, float npow) {
if(plr->shot == YoumuOpposite && plr->slaves == NULL)
create_enemy_p(&plr->slaves, 40I, ENEMY_IMMUNE, YoumuOppositeMyon, youmu_opposite_myon, 0, 0, 0, 0);
}
/* Marisa */

View file

@ -15,53 +15,88 @@
#include "global.h"
#include "paths/native.h"
void replay_init(Replay *rpy, StageInfo *stage, int seed, Player *plr) {
void replay_init(Replay *rpy) {
memset(rpy, 0, sizeof(Replay));
rpy->active = True;
rpy->capacity = REPLAY_ALLOC_INITIAL;
rpy->events = (ReplayEvent*)malloc(sizeof(ReplayEvent) * rpy->capacity);
printf("replay_init(): replay initialized for writting\n");
}
ReplayStage* replay_init_stage(Replay *rpy, StageInfo *stage, int seed, Player *plr) {
ReplayStage *s;
rpy->stage = stage->id;
rpy->seed = seed;
rpy->diff = global.diff;
rpy->points = global.points;
rpy->stages = (ReplayStage*)realloc(rpy->stages, sizeof(ReplayStage) * (++rpy->stgcount));
s = &(rpy->stages[rpy->stgcount-1]);
memset(s, 0, sizeof(ReplayStage));
rpy->plr_pos = plr->pos;
rpy->plr_char = plr->cha;
rpy->plr_shot = plr->shot;
rpy->plr_lifes = plr->lifes;
rpy->plr_bombs = plr->bombs;
rpy->plr_power = plr->power;
s->capacity = REPLAY_ALLOC_INITIAL;
s->events = (ReplayEvent*)malloc(sizeof(ReplayEvent) * s->capacity);
rpy->active = True;
s->stage = stage->id;
s->seed = seed;
s->diff = global.diff;
s->points = global.points;
printf("Replay initialized with capacity of %d\n", rpy->capacity);
s->plr_pos = plr->pos;
s->plr_focus = plr->focus;
s->plr_fire = plr->fire;
s->plr_char = plr->cha;
s->plr_shot = plr->shot;
s->plr_lifes = plr->lifes;
s->plr_bombs = plr->bombs;
s->plr_power = plr->power;
s->plr_mflags = plr->moveflags;
printf("replay_init_stage(): created a new stage for writting\n");
replay_select(rpy, rpy->stgcount-1);
return s;
}
void replay_destroy_stage(ReplayStage *stage) {
if(stage->events)
free(stage->events);
memset(stage, 0, sizeof(ReplayStage));
}
void replay_destroy(Replay *rpy) {
if(rpy->events)
free(rpy->events);
if(rpy->stages) {
int i; for(i = 0; i < rpy->stgcount; ++i)
replay_destroy_stage(&(rpy->stages[i]));
free(rpy->stages);
}
if(rpy->playername)
free(rpy->playername);
memset(rpy, 0, sizeof(Replay));
printf("Replay destroyed.\n");
}
ReplayStage* replay_select(Replay *rpy, int stage) {
if(stage < 0 || stage >= rpy->stgcount)
return NULL;
rpy->current = &(rpy->stages[stage]);
rpy->currentidx = stage;
return rpy->current;
}
void replay_event(Replay *rpy, int type, int key) {
if(!rpy->active)
return;
ReplayEvent *e = &(rpy->events[rpy->ecount]);
ReplayStage *s = rpy->current;
ReplayEvent *e = &(s->events[s->ecount]);
e->frame = global.frames;
e->type = (char)type;
e->key = (char)key;
rpy->ecount++;
s->ecount++;
if(rpy->ecount >= rpy->capacity) {
printf("Replay reached it's capacity of %d, reallocating\n", rpy->capacity);
rpy->capacity += REPLAY_ALLOC_ADDITIONAL;
rpy->events = (ReplayEvent*)realloc(rpy->events, sizeof(ReplayEvent) * rpy->capacity);
printf("The new capacity is %d\n", rpy->capacity);
if(s->ecount >= s->capacity) {
printf("Replay reached it's capacity of %d, reallocating\n", s->capacity);
s->capacity += REPLAY_ALLOC_ADDITIONAL;
s->events = (ReplayEvent*)realloc(s->events, sizeof(ReplayEvent) * s->capacity);
printf("The new capacity is %d\n", s->capacity);
}
if(type == EV_OVER)
@ -93,36 +128,43 @@ void replay_write_complex(FILE *file, complex val) {
}
int replay_write(Replay *rpy, FILE *file) {
int i;
int i, j;
// header
replay_write_int(file, REPLAY_MAGICNUMBER);
replay_write_string(file, tconfig.strval[PLAYERNAME]);
replay_write_string(file, "This file is not for your eyes, move on");
replay_write_int(file, 1);
replay_write_string(file, "Get out of here, you nasty cheater!");
replay_write_int(file, rpy->stgcount);
// initial game settings
replay_write_int(file, rpy->stage);
replay_write_int(file, rpy->seed);
replay_write_int(file, rpy->diff);
replay_write_int(file, rpy->points);
// initial player settings
replay_write_int(file, rpy->plr_char);
replay_write_int(file, rpy->plr_shot);
replay_write_complex(file, rpy->plr_pos);
replay_write_double(file, rpy->plr_power);
replay_write_int(file, rpy->plr_lifes);
replay_write_int(file, rpy->plr_bombs);
// events
replay_write_int(file, rpy->ecount);
for(i = 0; i < rpy->ecount; ++i) {
ReplayEvent *e = &(rpy->events[i]);
replay_write_int(file, e->frame);
replay_write_int(file, e->type);
replay_write_int(file, e->key);
for(j = 0; j < rpy->stgcount; ++j) {
ReplayStage *stg = &(rpy->stages[j]);
// initial game settings
replay_write_int(file, stg->stage);
replay_write_int(file, stg->seed);
replay_write_int(file, stg->diff);
replay_write_int(file, stg->points);
// initial player settings
replay_write_int(file, stg->plr_char);
replay_write_int(file, stg->plr_shot);
replay_write_complex(file, stg->plr_pos);
replay_write_int(file, stg->plr_focus);
replay_write_int(file, stg->plr_fire);
replay_write_double(file, stg->plr_power);
replay_write_int(file, stg->plr_lifes);
replay_write_int(file, stg->plr_bombs);
replay_write_int(file, stg->plr_mflags);
// events
replay_write_int(file, stg->ecount);
for(i = 0; i < stg->ecount; ++i) {
ReplayEvent *e = &(stg->events[i]);
replay_write_int(file, e->frame);
replay_write_int(file, e->type);
replay_write_int(file, e->key);
}
}
return True;
@ -134,7 +176,7 @@ enum {
RPY_H_MAGIC = 0,
RPY_H_META1,
RPY_H_META2,
RPY_H_REPLAYCOUNT,
RPY_H_STAGECOUNT,
// initial game settings
RPY_G_STAGE,
@ -147,9 +189,12 @@ enum {
RPY_P_SHOT,
RPY_P_POSREAL,
RPY_P_POSIMAG,
RPY_P_FOCUS,
RPY_P_FIRE,
RPY_P_POWER,
RPY_P_LIFES,
RPY_P_BOMBS,
RPY_P_MFLAGS,
// events
RPY_E_COUNT,
@ -165,6 +210,8 @@ int replay_read(Replay *rpy, FILE *file) {
int readstate = RPY_H_MAGIC;
int bufidx = 0, eidx = 0;
char buf[REPLAY_READ_MAXSTRLEN], c;
ReplayStage *s;
int stgnum = 0;
memset(rpy, 0, sizeof(Replay));
while((c = fgetc(file)) != EOF) {
@ -189,40 +236,65 @@ int replay_read(Replay *rpy, FILE *file) {
printf("replay_read(): replay META1 is: %s\n", buf);
break;
case RPY_H_META2: case RPY_H_REPLAYCOUNT: // skip
case RPY_H_META2: // skip
break;
case RPY_G_STAGE: rpy->stage = INTOF(buf); break;
case RPY_G_SEED: rpy->seed = INTOF(buf); break;
case RPY_G_DIFF: rpy->diff = INTOF(buf); break;
case RPY_G_PTS: rpy->points = INTOF(buf); break;
case RPY_P_CHAR: rpy->plr_char = INTOF(buf); break;
case RPY_P_SHOT: rpy->plr_shot = INTOF(buf); break;
case RPY_P_POSREAL: rpy->plr_pos = INTOF(buf); break;
case RPY_P_POSIMAG: rpy->plr_pos += INTOF(buf) * I; break;
case RPY_P_POWER: rpy->plr_power = FLOATOF(buf); break;
case RPY_P_LIFES: rpy->plr_lifes = INTOF(buf); break;
case RPY_P_BOMBS: rpy->plr_bombs = INTOF(buf); break;
case RPY_E_COUNT:
rpy->capacity = rpy->ecount = INTOF(buf);
if(rpy->capacity <= 0) {
printf("replay_read(): insane capacity: %i\n", rpy->capacity);
case RPY_H_STAGECOUNT:
rpy->stgcount = INTOF(buf);
if(rpy->stgcount <= 0) {
printf("replay_read(): insane stage count: %i\n", rpy->stgcount);
replay_destroy(rpy);
return False;
}
rpy->events = (ReplayEvent*)malloc(sizeof(ReplayEvent) * rpy->capacity);
rpy->stages = (ReplayStage*)malloc(sizeof(ReplayStage) * rpy->stgcount);
s = &(rpy->stages[0]);
memset(s, 0, sizeof(ReplayStage));
break;
case RPY_E_FRAME: rpy->events[eidx].frame = INTOF(buf); break;
case RPY_E_TYPE: rpy->events[eidx].type = INTOF(buf); break;
case RPY_E_KEY: rpy->events[eidx].key = INTOF(buf); eidx++; break;
case RPY_G_STAGE: s->stage = INTOF(buf); break;
case RPY_G_SEED: s->seed = INTOF(buf); break;
case RPY_G_DIFF: s->diff = INTOF(buf); break;
case RPY_G_PTS: s->points = INTOF(buf); break;
case RPY_P_CHAR: s->plr_char = INTOF(buf); break;
case RPY_P_SHOT: s->plr_shot = INTOF(buf); break;
case RPY_P_POSREAL: s->plr_pos = INTOF(buf); break;
case RPY_P_POSIMAG: s->plr_pos += INTOF(buf) * I; break;
case RPY_P_FOCUS: s->plr_focus = INTOF(buf); break;
case RPY_P_FIRE: s->plr_fire = INTOF(buf); break;
case RPY_P_POWER: s->plr_power = FLOATOF(buf); break;
case RPY_P_LIFES: s->plr_lifes = INTOF(buf); break;
case RPY_P_BOMBS: s->plr_bombs = INTOF(buf); break;
case RPY_P_MFLAGS: s->plr_mflags = INTOF(buf); break;
case RPY_E_COUNT:
s->capacity = s->ecount = INTOF(buf);
if(s->capacity <= 0) {
printf("replay_read(): insane capacity in stage %i: %i\n", stgnum, s->capacity);
replay_destroy(rpy);
return False;
}
s->events = (ReplayEvent*)malloc(sizeof(ReplayEvent) * s->capacity);
break;
case RPY_E_FRAME: s->events[eidx].frame = INTOF(buf); break;
case RPY_E_TYPE: s->events[eidx].type = INTOF(buf); break;
case RPY_E_KEY:
s->events[eidx].key = INTOF(buf);
eidx++;
if(eidx == s->capacity) {
if((++stgnum) >= rpy->stgcount)
return True;
s = &(rpy->stages[stgnum]);
readstate = RPY_G_STAGE;
eidx = 0;
continue;
}
break;
}
if(rpy->capacity && eidx == rpy->capacity)
return True;
if(readstate == RPY_E_KEY)
readstate = RPY_E_FRAME;
else
@ -237,7 +309,9 @@ int replay_read(Replay *rpy, FILE *file) {
}
}
return True;
printf("replay_read(): replay isn't properly terminated\n");
replay_destroy(rpy);
return False;
}
#undef FLOATOF
@ -290,11 +364,23 @@ int replay_load(Replay *rpy, char *name) {
}
void replay_copy(Replay *dst, Replay *src) {
int i;
replay_destroy(dst);
memcpy(dst, src, sizeof(Replay));
dst->capacity = dst->ecount;
dst->events = (ReplayEvent*)malloc(sizeof(ReplayEvent) * dst->capacity);
memcpy(dst->events, src->events, dst->capacity * sizeof(ReplayEvent));
dst->playername = (char*)malloc(strlen(src->playername)+1);
strcpy(dst->playername, src->playername);
dst->stages = (ReplayStage*)malloc(sizeof(ReplayStage) * src->stgcount);
memcpy(dst->stages, src->stages, sizeof(ReplayStage) * src->stgcount);
for(i = 0; i < src->stgcount; ++i) {
ReplayStage *s, *d;
s = &(src->stages[i]);
d = &(dst->stages[i]);
d->capacity = s->ecount;
d->events = (ReplayEvent*)malloc(sizeof(ReplayEvent) * d->capacity);
memcpy(d->events, s->events, sizeof(ReplayEvent) * d->capacity);
}
}

View file

@ -18,10 +18,7 @@ typedef struct ReplayEvent {
char key;
} ReplayEvent;
typedef struct Replay {
// metadata
char *playername;
typedef struct ReplayStage {
// initial game settings
int stage;
int seed; // this also happens to be the game initiation time - and we use this property, don't break it please
@ -32,9 +29,12 @@ typedef struct Replay {
Character plr_char;
ShotMode plr_shot;
complex plr_pos;
short plr_focus;
short plr_fire;
float plr_power;
int plr_lifes;
int plr_bombs;
int plr_mflags;
// events
ReplayEvent *events;
@ -42,8 +42,21 @@ typedef struct Replay {
// The fields below should not be stored
int capacity;
int active;
int playpos;
} ReplayStage;
typedef struct Replay {
// metadata
char *playername;
// stages (NOTE FOR FUTURE: stages do not represent stage runs in particular, they can and should be used to store stuff like spell practice runs, too)
ReplayStage *stages;
int stgcount;
// The fields below should not be stored
int active;
ReplayStage *current;
int currentidx;
} Replay;
enum {
@ -51,8 +64,11 @@ enum {
REPLAY_PLAY
};
void replay_init(Replay *rpy, StageInfo *stage, int seed, Player *plr);
void replay_init(Replay *rpy);
ReplayStage* replay_init_stage(Replay *rpy, StageInfo *stage, int seed, Player *plr);
void replay_destroy(Replay *rpy);
void replay_destroy_stage(ReplayStage *stage);
ReplayStage* replay_select(Replay *rpy, int stage);
void replay_event(Replay *rpy, int type, int key);
int replay_write(Replay *rpy, FILE *file);

View file

@ -82,6 +82,12 @@ int stringwidth(char *s, TTF_Font *font) {
return w;
}
int stringheight(char *s, TTF_Font *font) {
int h;
TTF_SizeText(font, s, NULL, &h);
return h;
}
int charwidth(char c, TTF_Font *font) {
char s[2];
s[0] = c;

View file

@ -22,6 +22,7 @@ Texture *load_text(const char *text, TTF_Font *font);
void draw_text(Alignment align, float x, float y, const char *text, TTF_Font *font);
void init_fonts();
int stringwidth(char *s, TTF_Font *font);
int stringheight(char *s, TTF_Font *font);
int charwidth(char c, TTF_Font *font);
struct Fonts {

View file

@ -15,8 +15,6 @@
#include "config.h"
#include "player.h"
#include "menu/ingamemenu.h"
#include "menu/savereplay.h"
#include "menu/replayover.h"
StageInfo stages[] = {
{1, stage1_loop, False, "Stage 1", "Misty Lake", {1, 1, 1}},
@ -69,24 +67,21 @@ void replay_input() {
int sym = event.key.keysym.sym;
global_processevent(&event);
switch(event.type) {
case SDL_KEYDOWN:
if(sym == SDLK_ESCAPE)
stage_ingamemenu();
break;
case SDL_QUIT:
exit(1);
break;
if(event.type == SDL_KEYDOWN) {
if(sym == SDLK_ESCAPE)
stage_ingamemenu();
break;
}
}
if(global.menu)
return;
ReplayStage *s = global.replay.current;
int i;
for(i = global.replay.playpos; i < global.replay.ecount; ++i) {
ReplayEvent *e = &(global.replay.events[i]);
for(i = s->playpos; i < s->ecount; ++i) {
ReplayEvent *e = &(s->events[i]);
if(e->frame != global.frames)
break;
@ -107,7 +102,7 @@ void replay_input() {
}
}
global.replay.playpos = i;
s->playpos = i;
player_applymovement(&global.plr);
}
@ -147,10 +142,6 @@ void stage_input() {
if(key == KEY_SKIP && global.dialog)
global.dialog->skip = False;
break;
case SDL_QUIT:
exit(1);
break;
}
}
@ -307,18 +298,13 @@ void stage_draw(StageInfo *info, StageRule bgdraw, ShaderRule *shaderrules, int
draw_hud();
if(global.menu) {
// horrible hacks because we have no sane transitions between ingame menus
if(REPLAY_ASKSAVE) {
if(global.menu->context && global.menu->quit == 1) {
fade_out(global.menu->fade);
}
} else {
if(global.replaymode != REPLAY_PLAY || (global.menu->quit && global.game_over))
fade_out(global.menu->fade);
}
}
// I don't remember how did it work before the massive transition hacking - and neither do I want to.
// So I'll just leave these new hacks here. At least they are not AS horrible as the old ones.
// They are still horrible, though. I hate them. HATE HATE HATE HATE HATE HATE HATE HATE HATE.
if(global.menu && !global.menu->abort && global.menu->quit == 1 && global.menu->selected == 1)
fade_out(global.menu->fade);
else if(global.game_over == GAMEOVER_ABORT)
fade_out(1);
}
int apply_shaderrules(ShaderRule *shaderrules, int fbonum) {
@ -472,33 +458,49 @@ void stage_loop(StageInfo* info, StageRule start, StageRule end, StageRule draw,
}
int seed = time(0);
tsrand_switch(&global.rand_game);
tsrand_seed_p(&global.rand_game, seed);
stage_start();
if(global.replaymode == REPLAY_RECORD) {
if(!global.plr.continues)
replay_init(&global.replay, info, seed, &global.plr);
if(global.replay.active)
replay_init_stage(&global.replay, info, seed, &global.plr);
printf("Random seed: %d\n", seed);
} else {
printf("REPLAY_PLAY mode: %d events\n", global.replay.ecount);
ReplayStage *stg = global.replay.current;
printf("REPLAY_PLAY mode: %d events, stage: \"%s\"\n", stg->ecount, stage_get(stg->stage)->title);
tsrand_seed_p(&global.rand_game, global.replay.seed);
printf("Random seed: %d\n", global.replay.seed);
tsrand_seed_p(&global.rand_game, stg->seed);
printf("Random seed: %d\n", stg->seed);
global.diff = global.replay.diff;
global.points = global.replay.points;
global.diff = stg->diff;
global.points = stg->points;
global.plr.shot = global.replay.plr_shot;
global.plr.cha = global.replay.plr_char;
global.plr.pos = global.replay.plr_pos;
global.plr.lifes = global.replay.plr_lifes;
global.plr.bombs = global.replay.plr_bombs;
global.plr.power = global.replay.plr_power;
global.plr.shot = stg->plr_shot;
global.plr.cha = stg->plr_char;
global.plr.pos = stg->plr_pos;
global.plr.focus = stg->plr_focus;
global.plr.fire = stg->plr_fire;
global.plr.lifes = stg->plr_lifes;
global.plr.bombs = stg->plr_bombs;
global.plr.power = stg->plr_power;
global.plr.moveflags = stg->plr_mflags;
global.replay.playpos = 0;
stg->playpos = 0;
}
tsrand_switch(&global.rand_game);
stage_start();
Enemy *e = global.plr.slaves, *tmp;
float power = global.plr.power;
global.plr.power = -1;
while(e != 0) {
tmp = e;
e = e->next;
delete_enemy(&global.plr.slaves, tmp);
}
player_set_power(&global.plr, power);
start();
SDL_EnableKeyRepeat(0, 0);
@ -520,49 +522,13 @@ void stage_loop(StageInfo* info, StageRule start, StageRule end, StageRule draw,
if(global.replaymode == REPLAY_RECORD) {
replay_event(&global.replay, EV_OVER, 0);
if(REPLAY_ASKSAVE) {
global.menu = create_saverpy_menu();
while(global.menu) {
stage_draw(info, draw, shaderrules, endtime);
ingame_menu_logic(&global.menu);
if(!global.menu)
break;
menu_input(global.menu);
SDL_GL_SwapBuffers();
frame_rate(&global.lasttime);
}
}
if(global.replay.active && tconfig.intval[SAVE_RPY] == 1)
save_rpy(NULL);
} else if(global.game_over != GAMEOVER_ABORT) {
global.menu = create_replayover_menu();
while(global.menu) {
stage_draw(info, draw, shaderrules, endtime);
ingame_menu_logic(&global.menu);
if(!global.menu)
break;
else if(global.menu->quit == 2) { // a hack that semi-fixes problems caused by another hack
destroy_menu(global.menu);
free(global.menu);
global.menu = NULL;
break;
}
menu_input(global.menu);
SDL_GL_SwapBuffers();
frame_rate(&global.lasttime);
}
}
end();
stage_end();
tsrand_switch(&global.rand_visual);
replay_destroy(&global.replay);
// if(global.replaymode != REPLAY_PLAY)
// replay_destroy(&global.replay);
SDL_EnableKeyRepeat(TS_KR_DELAY, TS_KR_INTERVAL);
}

View file

@ -203,7 +203,7 @@ void cirno_pfreeze_bg(Boss *c, int time) {
}
Boss *create_cirno_mid() {
Boss* cirno = create_boss("Cirno", "cirno", VIEWPORT_W + 150 + 30I);
Boss* cirno = create_boss("Cirno", "cirno", VIEWPORT_W + 220 + 30I);
boss_add_attack(cirno, AT_Move, "Introduction", 2, 0, cirno_intro, NULL);
boss_add_attack(cirno, AT_Normal, "Icy Storm", 20, 20000, cirno_icy, NULL);
boss_add_attack(cirno, AT_Spellcard, "Freeze Sign ~ Perfect Freeze", 32, 20000, cirno_perfect_freeze, cirno_pfreeze_bg);
@ -339,7 +339,7 @@ void cirno_icicle_fall(Boss *c, int time) {
}
Boss *create_cirno() {
Boss* cirno = create_boss("Cirno", "cirno", -150 + 100I);
Boss* cirno = create_boss("Cirno", "cirno", -230 + 100I);
boss_add_attack(cirno, AT_Move, "Introduction", 2, 0, cirno_intro_boss, NULL);
boss_add_attack(cirno, AT_Normal, "Iceplosion 0", 20, 20000, cirno_iceplosion0, NULL);
boss_add_attack(cirno, AT_Spellcard, "Freeze Sign ~ Crystal Rain", 28, 28000, cirno_crystal_rain, cirno_pfreeze_bg);
@ -634,7 +634,6 @@ void stage1_start() {
init_stage3d(&bgcontext);
add_model(&bgcontext, stage1_bg_draw, stage1_bg_pos);
add_model(&bgcontext, stage1_smoke_draw, stage1_smoke_pos);
bgcontext.crot[0] = 60;
bgcontext.cx[2] = 700;

View file

@ -11,7 +11,7 @@
#include "enemy.h"
Dialog *stage2_dialog() {
Dialog *d = create_dialog(global.plr.cha == Marisa ? "dialog/marisa" : "dialog/youmu", "masterspark");
Dialog *d = create_dialog(global.plr.cha == Marisa ? "dialog/marisa" : "dialog/youmu", "dialog/hina");
if(global.plr.cha == Marisa) {
dadd_msg(d, Left, "Ha! What are you doing here?\nYou the culprit?");
@ -461,7 +461,7 @@ void stage2_events() {
global.boss = create_hina();
}
AT(5120) {
AT(5180) {
global.dialog = stage2_post_dialog();
}
}

View file

@ -55,15 +55,6 @@ void stage5_stairs_draw(Vector pos) {
glUseProgram(0);
}
float clamp(float f, float lower, float upper) {
if(f < lower)
return lower;
if(f > upper)
return upper;
return f;
}
void stage5_draw() {
set_perspective(&bgcontext, 100, 20000);
draw_stage3d(&bgcontext, 30000);

View file

@ -37,8 +37,11 @@ void stage6_towerwall_draw(Vector pos) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, get_tex("stage6/towerwall")->gltex);
if(!tconfig.intval[NO_SHADER])
glUseProgram(get_shader("tower_wall")->prog);
if(!tconfig.intval[NO_SHADER]) {
Shader *s = get_shader("tower_wall");
glUseProgram(s->prog);
glUniform1i(uniloc(s, "lendiv"), 3000.0);
}
glPushMatrix();
glTranslatef(pos[0], pos[1], pos[2]);
@ -173,4 +176,4 @@ void stage6_end() {
void stage6_loop() {
// ShaderRule shaderrules[] = { stage6_bloom, NULL };
stage_loop(stage_get(6), stage6_start, stage6_end, stage6_draw, stage6_events, NULL, 3900);
}
}

View file

@ -23,15 +23,19 @@ void add_model(Stage3D *s, SegmentDrawRule draw, SegmentPositionRule pos) {
s->models[s->msize - 1].pos = pos;
}
void set_perspective(Stage3D *s, float n, float f) {
void set_perspective_viewport(Stage3D *s, float n, float f, int vx, int vy, int vw, int vh) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glTranslatef(-(VIEWPORT_W/2.0)/SCREEN_W, 0, 0);
glTranslatef(-(vw/2.0)/SCREEN_W, 0, 0);
gluPerspective(s->projangle, 1, n, f);
glTranslatef(VIEWPORT_X+VIEWPORT_W/2.0, VIEWPORT_Y+VIEWPORT_H/2.0, 0);
glTranslatef(vx+vw/2.0, vy+vh/2.0, 0);
glMatrixMode(GL_MODELVIEW);
glMatrixMode(GL_MODELVIEW);
}
inline void set_perspective(Stage3D *s, float n, float f) {
set_perspective_viewport(s, n, f, VIEWPORT_X, VIEWPORT_Y, VIEWPORT_W, VIEWPORT_H);
}
void draw_stage3d(Stage3D *s, float maxrange) {

View file

@ -38,7 +38,8 @@ void init_stage3d(Stage3D *s);
void add_model(Stage3D *s, SegmentDrawRule draw, SegmentPositionRule pos);
void set_perspective(Stage3D *s, float near, float far);
void set_perspective_viewport(Stage3D *s, float n, float f, int vx, int vy, int vw, int vh);
inline void set_perspective(Stage3D *s, float near, float far);
void draw_stage3d(Stage3D *s, float maxrange);
void free_stage3d(Stage3D *s);
@ -46,4 +47,4 @@ void free_stage3d(Stage3D *s);
Vector **linear3dpos(Vector q, float maxrange, Vector p, Vector r);
Vector **single3dpos(Vector q, float maxrange, Vector p);
#endif
#endif