1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
|
#pragma once
#include "ofMain.h"
#include "ofxXmlSettings.h"
#include "Puppet.h"
//Grid for drawing
static float gridX[3]={0.3,0.5,0.7};
static float gridY[1]={0.8};
//event times are absolute integer milliseconds
//---------------------------------------------------------------------------------------------------------------------------------------------
class levelscore {
public:
void load(string filename) {
ofxXmlSettings XML;
if( !XML.loadFile(filename) ){
printf("unable to load %s check data/ folder\n",filename.c_str());
}else{
int multiplier=1000/XML.getAttribute("VFxmas", "timebase",1000,0);
if(XML.pushTag("VFxmas")) {
for (int i=0;i<XML.getNumTags("Level");i++) {
levels[XML.getAttribute("Level", "Time",0,i)*multiplier]=XML.getAttribute("Level", "Lives",0,i);
}
printf("processed %s: %i difficulty levels \n",filename.c_str(),levels.size());
}
}
}
void test() {
map<int,int>::iterator iter=levels.end();
iter--;
for (int i=0;i<iter->first;i+=500) {
printf("time %i: level %i, nextleveltime %i\n",i,getLevel(i), nextLevelTime(i));
}
}
int getLives(int time) {
map<int,int>::iterator iter;
int lives=0;
for (iter = levels.begin(); iter != levels.end(); ++iter) {
if (iter->first<=time) lives=iter->second;
else break;
}
return lives;
}
int getLevel(int time) {
map<int,int>::iterator iter;
int level=-1;
for (iter = levels.begin(); iter != levels.end(); ++iter) {
if (iter->first<=time) level++;
else break;
}
return level;
}
int getLowerBound(int level) {
map<int,int>::iterator iter=levels.begin();
int bound=0;
for (int i=0;i<=level;i++) {
bound=iter->first;
iter++;
}
return bound;
}
int nextLevelTime(int time) {
map<int,int>::iterator iter;
int level=-1;
for (iter = levels.begin(); iter != levels.end(); ++iter) {
if (iter->first>time) return iter->first-time;
}
return 2<<20; // a big number
}
private:
map<int,int> levels;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class note {
public:
note(int n,int v,int d=0) {
num=n;
velocity=v;
duration=d;
}
int num;
int velocity;
int duration; //may be needed another time?
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class flake: public note, public Puppet {
public:
flake(int n,int v,int d=0) : note(n,v,d) { activated=false; }
Puppet puppet;
bool activated;
void activate() {
activated=true;
puppet.play("shatter");
}
void draw(float x, float y,float scale) {
if (!activated||puppet.isPlaying()) puppet.draw(x,y,scale);
}
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class lyric {
public:
lyric(string s,int d) {
text=s;
duration=d;
}
string text;
int duration;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class score {
//basics of timelime
public:
long startTime;
void start() { startTime=ofGetElapsedTimeMillis(); }
void start(int _st) { startTime=_st; }
ofxXmlSettings XML;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class lyricscore: public score {
//draws lyrics to screen for a certain time
public:
lyricscore() {
font.loadFont("verdana.ttf", 30, true, true);
font.setLineHeight(34.0f);
font.setLetterSpacing(1.035);
ypos=(int)(((float)ofGetHeight())*0.97f); //set lyric position
fadeout=500; //ms
}
void load(string filename) {
if( !XML.loadFile(filename) ){
printf("unable to load %s check data/ folder\n",filename.c_str());
}else{
int multiplier=1000/XML.getAttribute("VFxmas", "timebase",1000,0);
if(XML.pushTag("VFxmas")) {
for (int i=0;i<XML.getNumTags("Lyric");i++) {
int in=XML.getAttribute("Lyric", "In",0,i)*multiplier;
lyrics[in]=new lyric(XML.getValue("Lyric","",i),(XML.getAttribute("Lyric", "Out",0,i)*multiplier)-in);
}
printf("processed %s: %i lyrics \n",filename.c_str(),lyrics.size());
}
}
}
void draw();
private:
map<int,lyric*> lyrics;
ofTrueTypeFont font;
int ypos;
int fadeout;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class musicscore: public score {
//draws notes to screen for a certain time and certain parameters, checks when they become ready
public:
musicscore();
void parseMidi(string filename);
void setTimeframe(int millis);
void setNowpoint(float pct);
void drawNotes(levelscore *levels);
void drawFlakes(levelscore *levels);
void playerControl(int key,int threshold);
void makeFlakes(int threshStart,int threshEnd,levelscore *levels);
int missedFlakes;
int missedNote;
int hitNote;
bool missedLast;
bool perfect;
private:
map<int,note*> notes;
map<int,flake*> flakes;
map<int,flake*>::iterator missedFlake;
int timeframe;
float nowpoint;
vector<Puppet> snowflakes;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class song {
public:
song(string backfile,string melfile,string musfile,string lyricfile,string levelfile);
void play();
void stop();
void preRoll(long preroll);
void setTimeframe(int millis);
void setFlakeThresh(int tS,int tE);
void setKeythresh(int millis);
void drawNotes();
void draw();
int missedNote();
int hitNote();
bool isPlaying;
void playerControl(int key);
int getLevel(long time);
private:
ofSoundPlayer backing;
ofSoundPlayer melody;
lyricscore lyrics;
musicscore notes;
levelscore levels;
long startTime;
bool isPreroll;
int fThreshStart,fThreshEnd,keyThresh;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
/*
Game
Animation & Sound Demo – NK to overlay latest version of Deck the Halls on 10 second animated sequence by COB Wednesday 7th November for visual and aural aesthetic sign-off. RM to send through latest version of Deck the Halls today (6th November).
Game Development – TR presented initial demo today. Usability looks good. NK to provide first suite of graphics by COB Wednesday 7th November.
Latency Test – TR and GK to perform end-to-end latency test next Monday 12th November once Vodafone have connected the 1800 number to the 01 number. Any issues noted in the testing to be flagged to BL.
Game Over – Players who miss a certain amount of notes in a row will be kicked out of the game early. The number of notes that can be missed in a row will decrease as the game goes on (subject to testing and tweaking):
Stage 1 – N/A (it will not be possible to be kicked out in Stage 1)
Stage 2 – 5 notes missed will mean Game Over
Stage 3 – 4 notes missed will mean Game Over
Stage 4 – 3 notes missed will mean Game Over
Scoring – Scoring will be based on the level of the game you achieve. There will be 4 scoring brackets (subject to testing and tweaking):
Scoring Bracket 1 - Those who make it to Level 2 (see above - it's not possible to be kicked out in Level 1)
Scoring Bracket 2 – Those who make it to Level 3
Scoring Bracket 3 – Those who make it to Level 4
Scoring Bracket 4 – Those who don't miss any notes in Level 4
*/
|