Merge branch 'master' into selections
This commit is contained in:
commit
5ce30f8ca4
39 changed files with 1051 additions and 335 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -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
BIN
gfx/dialog/hina.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 95 KiB |
BIN
gfx/yukkureimu.png
Normal file
BIN
gfx/yukkureimu.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 186 KiB |
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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
270
src/credits.c
Normal 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
20
src/credits.h
Normal 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
144
src/ending.c
Normal 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
42
src/ending.h
Normal 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
|
|
@ -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);
|
||||
|
|
21
src/global.c
21
src/global.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
244
src/replay.c
244
src/replay.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
28
src/replay.h
28
src/replay.h
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
134
src/stage.c
134
src/stage.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue