void VideoManager::loadVideo(char* filename) { FILE* fp = NULL; if ( fopen_s(&fp, filename, "rb") != 0 ) { al_trace("Movie %s is missing.\r\n", filename); return; // do NOT summon error mode for this because the application might in debugging/lite mode } // get the length of the video fseek(fp, 0, SEEK_END); long fsize = ftell(fp); fseek(fp, 0, SEEK_SET); // load the entire video into an unreasonably large memory buffer! videoBuffer = malloc(fsize); fread(videoBuffer, fsize, 1, fp); fclose(fp); // sanity check the buffer contents or else APEG may hang if ( ((char*)videoBuffer)[0] == 'O' && ((char*)videoBuffer)[1] == 'g' && ((char*)videoBuffer)[2] == 'g' && ((char*)videoBuffer)[3] == 'S' ) { cmov = apeg_open_memory_stream(videoBuffer, fsize); } else { al_trace("Video stream did not seem to contain Ogg data.\r\n"); unloadVideo(); } }
void VideoManager::loadVideoAtCurrentStep() { char filename[256] = "DATA/video/"; if ( script[currentStep].filename[0] == '*' ) { strcat_s(filename, 256, script[currentStep-1].filename); // check for videos named '*'. I think the original game used this to denote "play that video again" } else { strcat_s(filename, 256, script[currentStep].filename); } strcat_s(filename, 256, ".ogg"); // default case: show a placeholder texture unloadVideo(); clear_to_color(frameData, makecol(255,255,255)); textprintf_centre(frameData, font, 160, 90, makecol(0,0,0), "%s", script[currentStep].filename); loadVideo(filename); if ( cmov == NULL ) { al_trace("Movie %s did not open for whatever reason.\r\n", filename); return; } if ( apeg_advance_stream(cmov, true) != APEG_OK) { al_trace("Video problem! Breakpoint!\r\n"); // doesn't really matter if it fails } blit(cmov->bitmap, frameData, 0, 0, 0, 0, 320, 192); }
void print_disassembly(const word scommand) { script_command s_c = command_list[scommand]; if(s_c.args == 2) { al_trace("%14s: ", s_c.name); if(s_c.arg1_type == 0) al_trace("%10s (val = %9d), ", varToString(sarg1), get_register(sarg1)); else al_trace("%10s (val = %9d), ", "immediate", sarg1); if(s_c.arg2_type == 0) al_trace("%10s (val = %9d)\n", varToString(sarg2), get_register(sarg2)); else al_trace("%10s (val = %9d)\n", "immediate", sarg2); } else if(s_c.args == 1) { al_trace("%14s: ", s_c.name); if(s_c.arg1_type == 0) al_trace("%10s (val = %9d)\n", varToString(sarg1), get_register(sarg1)); else al_trace("%10s (val = %9d)\n", "immediate", sarg1); } else al_trace("%14s\n", s_c.name); }
void gamedata::set_dcounter(short change, byte c) { #ifdef DEBUG_GD_COUNTERS if(c==0) al_trace("Changing D counter %i from %i to %i\n", c, _dcounter[c], change); #endif if(c>=32) // Sanity check return; if(game!=NULL) { int ringID=current_item_id(itype_ring, true); _dcounter[c]=change; if(ringID!=current_item_id(itype_ring, true)) ringcolor(false); } else _dcounter[c]=change; return; }
void gamedata::change_HCpieces(short p) { #ifdef DEBUG_GD_HCP al_trace("Changing HCP by %d to %d\n",p, get_generic(0)); #endif change_generic(p, 0); return; }
void renderStepZoneDMX(int player) { int startColumn = player == 0 ? 0 : 4; if ( gs.isSingles() ) { if ( gs.player[0].centerLeft ) { startColumn = 0; } else if ( gs.player[0].centerRight ) { startColumn = 4; } else { startColumn = 2; // center play } } int endColumn = gs.isDoubles ? 8 : startColumn+4; for ( int i = startColumn; i < endColumn; i++ ) { int x = getColumnOffsetX_DMX(i); int blink = gs.player[player].stepZoneBlinkTimer > 0 ? 0 : 1; // pick the state of the step zone int hitcolor = 0x7F000000; int outlineColor = 0xFFB4B4B4; const int fadeOutLength = 100; if ( blink == 1 ) { static int colors[3] = { makeacol(41, 239, 115, 255), makeacol(239, 101, 190, 255), makeacol(76, 0, 190, 255) }; int stageColor = gs.player[player].stagesLevels[gs.currentStage] % 10; outlineColor = colors[stageColor]; } if ( gs.player[player].laneFlareColors[i] == 2 ) { blink = 2; // currently holding a hold note in this column } int color = getColorOfColumn(i); if ( im.isKeyDown(i) ) { hitcolor = color == 0 ? 0xEECC0000 : 0xEE0000CC; } else if ( im.getReleaseLength(i) <= fadeOutLength ) { int a = getValueFromRange(0xFF, 0x7F, im.getReleaseLength(i) * 100/ fadeOutLength); if ( i ==4 ) { al_trace("%d\r\n", a); } hitcolor = color == 0 ? makeacol32(0xFF, 0, 0, a) : makeacol32(0, 0, 0xFF, a); } renderStepLaneDMX(x, hitcolor, outlineColor); masked_blit(m_stepZoneSourceDMX[color], rm.m_backbuf, blink*34, 0, x, (gs.player[player].isColumnReversed(i) ? DMX_STEP_ZONE_REV_Y-34 : DMX_STEP_ZONE_Y), 34, 38); } }
void gamedata::set_HCpieces(byte p) { #ifdef DEBUG_GD_HCP al_trace("Setting HCP to %i\n",p); #endif set_generic(p, 0); return; }
bool extioManager::attemptConnection(const char* port) { isConnected = false; hSerial = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hSerial==INVALID_HANDLE_VALUE) { //al_trace("The IO board isn't on %s\n", port); return false; // it's okay - we'll try another port } //If connected we try to set the comm parameters DCB dcbSerialParams = {0}; if ( !GetCommState(hSerial, &dcbSerialParams) ) { al_trace("extioManager: failed to GET serial parameters!"); return false; } //Define serial connection parameters for the arduino board dcbSerialParams.BaudRate = CBR_9600; dcbSerialParams.ByteSize = 8; dcbSerialParams.StopBits = ONESTOPBIT; dcbSerialParams.Parity = NOPARITY; if( !SetCommState(hSerial, &dcbSerialParams) ) { al_trace("extioManager: failed to SET serial parameters!"); return false; } isConnected = true; return true; }
void VideoManager::update(UTIME dt) { if ( isStopped || haxNoVideos ) { return; } currentTime += dt; // check for a script step advance if ( (script[currentStep+1].timing != -1) && currentTime/10 >= script[currentStep+1].timing/3 ) // because there are 300 ticks per second { currentStep++; loadVideoAtCurrentStep(); } // check for the movie ending and loop the whole thing after 5 seconds if ( script[currentStep+1].timing == -1 && currentStep > 1 && (currentTime/10 + 1500 >= script[currentStep].timing/3) ) { currentStep = 1; currentTime = 0; al_trace("Restarting video script.\r\n"); loadVideoAtCurrentStep(); } if ( cmov != NULL ) { if ( apeg_advance_stream(cmov, true) != APEG_OK) { al_trace("Video problem! Breakpoint!\r\n"); // doesn't really matter if it fails } if( cmov->frame_updated > 0 && cmov->bitmap != NULL ) { //stretch_blit(cmov->bitmap, frameData, 0, 0, cmov->w, cmov->h, 0, 0, 320, 192); blit(cmov->bitmap, frameData, 0, 0, 0, 0, 320, 192); } } }
// NOTE: currently only used for calculating the end time of hold notes UTIME getMillisecondsAtBeat(float targetBeat, std::vector<struct BEAT_NOTE> *chart, int startIndex, UTIME startTime, float currentTimePerBeat) { UTIME retval = startTime; float msPerBeat = currentTimePerBeat; float lastBeatProcessed = chart->at(startIndex).beat; float overshoot = 0; unsigned int i = 0; if ( lastBeatProcessed > targetBeat ) { al_trace("Searching for a past beat. Set breakpoint.\r\n"); } for ( i = startIndex; i < chart->size(); i++ ) { // check for finishing if ( targetBeat == chart->at(i).beat ) { break; } if ( targetBeat < chart->at(i).beat ) { overshoot = chart->at(i).beat - targetBeat; // fix a bug where not taking this into account was causing holds to run until the next note! break; } if ( chart->at(i).type == BPM_CHANGE ) { retval += ((chart->at(i).beat - lastBeatProcessed) * msPerBeat); msPerBeat = BPM_TO_MSEC(chart->at(i).param); lastBeatProcessed = chart->at(i).beat; } if ( chart->at(i).type == SCROLL_STOP ) { retval += chart->at(i).param; } } if ( i == chart->size() ) { i--; } retval += ((chart->at(i).beat - lastBeatProcessed - overshoot) * msPerBeat); return retval; }
void gamedata::change_maxcounter(short change, byte c) { #ifdef DEBUG_GD_COUNTERS al_trace("Changing max counter %i from %i by +%i\n", c, _maxcounter[c], change); #endif if(c==2) { change_maxbombs(change); return; } if(c>=32) // Sanity check return; _maxcounter[c]=zc_max(0, _maxcounter[c]+change); return; }
int Win32Data::zqSetCustomCallbackProc(HWND hWnd) { Win32Mutex mutex; mutex.Lock(); memset((void*)&win32data, 0, sizeof(Win32Data)); win32data.hasFocus = true; win32data.hWnd = hWnd; if(win32data.hWnd) win32data.isValid = true; else return -1; hAllegroProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC); if(!hAllegroProc) { win32data.isValid = false; return -1; } win32data.hInstance = ::GetWindowLongPtr(hWnd, GWLP_HINSTANCE); if(!win32data.hInstance) { win32data.isValid = false; return -1; } win32data.hId = ::GetWindowLongPtr(hWnd, GWLP_ID); //assign a new callback LONG_PTR pcb = ::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)Win32Data::zqWindowsProc); if(!pcb) { al_trace("Error: Cannot Set Windows Procedure."); win32data.isValid = false; return -1; } return 0; }
void gamedata::set_maxcounter(word change, byte c) { #ifdef DEBUG_GD_COUNTERS if(c==0) al_trace("Changing max counter %i from %i to %i\n", c, _maxcounter[c], change); #endif if(c==2) { set_maxbombs(change); return; } if(c>=32) // Sanity check return; _maxcounter[c]=change; return; }
void gamedata::change_counter(short change, byte c) { #ifdef DEBUG_GD_COUNTERS al_trace("Changing counter %i from %i by %i\n", c, _counter[c], change); #endif if(c>=32) // Sanity check return; if(game!=NULL) { int ringID=current_item_id(itype_ring, true); _counter[c]=vbound(_counter[c]+change, 0, _maxcounter[c]); if(ringID!=current_item_id(itype_ring, true)) ringcolor(false); } else _counter[c]=vbound(_counter[c]+change, 0, _maxcounter[c]); return; }
void AnalyticsManager::logEventToServer(const char* serverURL, const char* eventCategory, const char* eventType, const char* eventLabel, int eventValue) { CURL* curl = curl_easy_init(); CURLcode res; // construct the postfields using much string math char postfields[512] = ""; sprintf_s(postfields, 512, "v=%d&tid=%s&an=%s&cid=%s&t=%s&ec=%s&ea=%s&debug=%d", 1, TRACKING_ID, TRACKING_APP_NAME, clientID, "event", eventCategory, eventType, isDebugMode); if ( eventLabel[0] != 0 ) { char* tempEncode = curl_easy_escape(curl, eventLabel, strlen(eventLabel)); strcat_s(postfields, 512, "&el="); strcat_s(postfields, 512, tempEncode); curl_free(tempEncode); } if ( eventValue != -1 ) { char tempEncode[128] = ""; _itoa_s(eventValue, tempEncode, 64, 10); strcat_s(postfields, 512, "&ev="); strcat_s(postfields, 512, tempEncode); } // post the data using curl if ( curl ) { // post to Google Analytics first curl_easy_setopt(curl, CURLOPT_URL, serverURL); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postfields); res = curl_easy_perform(curl); if (res != CURLE_OK) { al_trace("curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } curl_easy_cleanup(curl); } }
void gamedata::set_counter(word change, byte c) { #ifdef DEBUG_GD_COUNTERS al_trace("Changing counter %i from %i to %i\n", c, _counter[c], change); #endif if(c>=32) // Sanity check return; if(game!=NULL) { int ringID=current_item_id(itype_ring, true); _counter[c]=zc_max(change, 0); // ringcolor is very slow, so make sure the ring has actually changed if(ringID!=current_item_id(itype_ring, true)) ringcolor(false); } else _counter[c]=zc_max(change, 0); return; }
bool extioManager::updateInitialize(UTIME dt) { if ( !isConnected ) { comPort++; if ( comPort < 10 ) { char port[] = "\\\\.\\COM0"; port[7] = comPort + '0'; attemptConnection(port); connectionState = 1; } else { al_trace("Can't find the IO board on any com port.\r\n"); comPort = -1; connectionState = 0; return false; } powerOnTime = 0; } else { powerOnTime += dt; if ( connectionState == 1 ) { if ( powerOnTime >= ARDUINO_WAIT_TIME ) { WriteData("DMX", PACKET_SIZE); connectionState = 2; } } else if ( connectionState == 2 ) { if ( isPacketReady() ) { ReadData(inputBuffer, PACKET_SIZE); if ( inputBuffer[0] == 'O' && inputBuffer[1] == 'K' && inputBuffer[2] == '!' ) { isTalking = true; connectionState = 3; al_trace("Handshake accepted! Found the IO board on port %d.\r\n", comPort); WriteData("I", 1); // begin the input request loop } else { // abort - try another port powerOnTime = 0; isConnected = false; connectionState = 0; al_trace("The handshake was incorrect on port %d. Checking other ports.\r\n", comPort); } } else if ( powerOnTime >= ARDUINO_TIMEOUT ) { // abort - try another port powerOnTime = 0; isConnected = false; connectionState = 0; al_trace("IO board timeout on port %d. Checking other ports.\r\n", comPort); } } else if ( connectionState == 3 ) { al_trace("Do not call updateInitialize() after success!\r\n"); } } return true; }
void processChartString(std::vector<struct BEAT_NOTE> *chart, char* string, int side) { int currentIndex = 0; int beatDivision = 2; // 1/8 beats are the default in DWI Files float totalBeatsProcessed = 0.0; float prevBeatProcessed = 0.0; // crtical for hold notes float beatOfHold[4] = { -1, -1, -1, -1 }; // when side == 1 then add 4 to every column for the right half of a doubles chart int doublesFactor = side == 1 ? 4 : 0; while ( string[currentIndex] != 0 ) { unsigned char ch = string[currentIndex]; int columns[4] = { -1, -1, -1, -1 }; // punctuation has various meanings if ( ch == '0' ) { prevBeatProcessed = totalBeatsProcessed; totalBeatsProcessed += 1.0/beatDivision; currentIndex++; continue; } else if ( ch == '\r' || ch == '\n' ) { currentIndex++; continue; // not needed, but nice for debugging below } else if ( ch == '(' ) { beatDivision = 4; // parens mean 1/16th notes currentIndex++; continue; } else if ( ch == '[' ) { beatDivision = 6; // brackets mean 1/24th notes currentIndex++; continue; } else if ( ch == '{' ) { beatDivision = 16; // curly braces mean 1/64th notes currentIndex++; continue; } else if ( ch == '`' ) // == 96 { beatDivision = 48; // this `00000' nonsense means 192nd notes currentIndex++; continue; } else if ( ch == ')' || ch == ']' || ch == '}' || ch == 250 || ch == 39 ) { beatDivision = 2; // back to 1/8th notes currentIndex++; continue; } else if ( ch == '!' ) { // what is to the right of the bang? currentIndex++; // skip over the bang columns[0] = getColumn(string[currentIndex], 0); columns[1] = getColumn(string[currentIndex], 1); if ( columns[0] != -1 && beatOfHold[columns[0]] == -1 ) { beatOfHold[columns[0]] = prevBeatProcessed; // store when the hold starts } if ( columns[1] != -1 && beatOfHold[columns[1]] == -1 ) { beatOfHold[columns[1]] = prevBeatProcessed; // store when the hold starts } } // look for regular notes else if ( (ch >= '0' && ch <= '9') || ch == 'A' || ch == 'B' ) { columns[0] = getColumn(ch, 0); columns[1] = getColumn(ch, 1); } else if ( ch == '<' ) // this special character means "tie columns together" to make triples and quads { int currentColumn = 0; currentIndex++; bool startedHolds = false; while ( string[currentIndex] != '>' ) { ch = string[currentIndex]; if ( startedHolds == false ) { if ( ch == '!' ) { startedHolds = true; // a triple is starting a hold currentIndex++; continue; } if ( getColumn(ch, 0) != -1 ) { columns[currentColumn] = getColumn(ch, 0); currentColumn = currentColumn == 3 ? 3 : currentColumn + 1; } if ( getColumn(ch, 1) != -1 ) { columns[currentColumn] = getColumn(ch, 1); currentColumn = currentColumn == 3 ? 3 : currentColumn + 1; } } else { /* TODO: fix this crazy corner case // this hold is string from inside a < > combination tag, so use the current time int col0 = getColumn(ch, 0); int col1 = getColumn(ch, 1); if ( col0 != -1 && beatOfHold[col0] == -1 ) { beatOfHold[col0] = totalBeatsProcessed; // store when the hold starts } if ( col1 != -1 && beatOfHold[col1] == -1 ) { beatOfHold[col1] = totalBeatsProcessed; // store when the hold starts } //*/ } currentIndex++; } } else { al_trace("Unknown symbol: %c", ch); } // create a freeze note? the end of a hold is signaled by a tap note in a column that was marked as held on a previous pass if ( ch != '!' ) { for ( int d = 0; d < 4; d++ ) { if ( columns[d] != -1 && beatOfHold[columns[d]] != -1 ) { struct BEAT_NOTE a; a.beat = beatOfHold[columns[d]]; a.column = columns[d] + doublesFactor; a.type = HOLD_START; a.param = totalBeatsProcessed; beatOfHold[columns[d]] = -1; // clear the hold columns[d] = -1; // clear the tap which ended this hold chart->push_back(a); } } } // this can happen if a hold ends - sort all the -1 columns to the end of the list // for example {-1, 2, -1, -1} becomes {2, -1, -1, -1} if ( columns[0] == -1 && (columns[1] != -1 || columns[2] != -1 || columns[3] != -1) ) { columns[0] = columns[1]; columns[1] = columns[2]; columns[2] = columns[3]; columns[3] = -1; } if ( columns[1] == -1 && (columns[2] != -1 || columns[3] != -1) ) { columns[1] = columns[2]; columns[2] = columns[3]; columns[3] = -1; } if ( columns[2] == -1 && columns[3] != -1 ) { columns[2] = columns[3]; columns[3] = -1; } // create any notes that need to be made if ( string[currentIndex-1] != '!' ) // this doesn't count as a note, nor should it increment time { for ( int d = 0; d < 4; d++ ) { if ( columns[d] != -1 ) { struct BEAT_NOTE a; a.beat = totalBeatsProcessed; a.column = columns[d] + doublesFactor; a.type = TAP; chart->push_back(a); } } prevBeatProcessed = totalBeatsProcessed; totalBeatsProcessed += 1.0/beatDivision; } currentIndex++; } // finally, put an end-of-song marker here struct BEAT_NOTE endmarker; endmarker.beat = totalBeatsProcessed; endmarker.type = END_SONG; chart->push_back(endmarker); }
int readDWI(std::vector<struct ARROW> *chart, std::vector<struct FREEZE> *holds, int songID, int chartType) { char filename[] = "DATA/dwis/101.dwi"; FILE* fp = NULL; std::vector<struct BEAT_NOTE> beats; // hopefully open the target DWI file filename[10] = (songID/100 % 10) + '0'; filename[11] = (songID/10 % 10) + '0'; filename[12] = (songID % 10) + '0'; if ( fopen_s(&fp, filename, "rt") != 0 ) { // as a fall back, open a memory dump of a chart (legacy chart data) return readDMXSQ(chart, holds, songID, chartType); } // fix any potential bugs regarding data from one chart accidentally merging into the next chart chart->clear(); holds->clear(); int gap = 0; float timePerBeat = 400.0; // 150 BPM // start reading tags readNextTag(fp); while ( tagName[0] != 0 ) { if ( _strcmpi("SINGLE", tagName) == 0 ) { if ( _strcmpi("BASIC", tagValue) == 0 && chartType == SINGLE_MILD ) { processChartString(&beats, tagLeftSide, 0); } else if ( _strcmpi("ANOTHER", tagValue) == 0 && chartType == SINGLE_WILD ) { processChartString(&beats, tagLeftSide, 0); } else if ( _strcmpi("MANIAC", tagValue) == 0 && chartType == SINGLE_ANOTHER ) { processChartString(&beats, tagLeftSide, 0); } } if ( _strcmpi("DOUBLE", tagName) == 0 ) { if ( _strcmpi("BASIC", tagValue) == 0 && chartType == DOUBLE_MILD ) { processChartString(&beats, tagLeftSide, 0); processChartString(&beats, tagRightSide, 1); } else if ( _strcmpi("ANOTHER", tagValue) == 0 && chartType == DOUBLE_WILD ) { processChartString(&beats, tagLeftSide, 0); processChartString(&beats, tagRightSide, 1); } else if ( _strcmpi("MANIAC", tagValue) == 0 && chartType == DOUBLE_ANOTHER ) { processChartString(&beats, tagLeftSide, 0); processChartString(&beats, tagRightSide, 1); } } if ( _strcmpi("BPM", tagName) == 0 ) { float bpm = atof(tagValue); timePerBeat = BPM_TO_MSEC(bpm); // set the initial scroll rate // WHY DOES THIS MAKE SONG NOT END? affects end of song marker somehow? struct ARROW a; a.timing = 0; a.color = bpm; a.type = BPM_CHANGE; a.judgement = UNSET; chart->push_back(a); } if ( _strcmpi("GAP", tagName) == 0 ) { gap = atoi(tagValue); al_trace("gap = %d\r\n", gap); } if ( _strcmpi("CHANGEBPM", tagName) == 0 ) // #CHANGEBPM:992.000=95.000,1016.000=190.000; { char* token, *next; token = strtok_s(tagValue, ",;", &next); while ( token != NULL ) { char leftSide[32], rightSide[32]; char* equalsPos = strchr(token, '='); if ( equalsPos == NULL ) { continue; } strncpy_s(leftSide, token, equalsPos - token); strcpy_s(rightSide, equalsPos+1); struct BEAT_NOTE b; b.beat = atof(leftSide)/4.0; b.param = atof(rightSide); b.type = BPM_CHANGE; beats.push_back(b); token = strtok_s(NULL, ",;", &next); } } if ( _strcmpi("FREEZE", tagName) == 0 ) // #FREEZE:668.000=327.000,1292.000=967.000; { char* token, *next; token = strtok_s(tagValue, ",;", &next); while ( token != NULL ) { char leftSide[32], rightSide[32]; char* equalsPos = strchr(token, '='); if ( equalsPos == NULL ) { continue; } strncpy_s(leftSide, token, equalsPos - token); strcpy_s(rightSide, equalsPos+1); struct BEAT_NOTE b; b.beat = atof(leftSide)/4.0; b.param = atof(rightSide); b.type = SCROLL_STOP; beats.push_back(b); token = strtok_s(NULL, ",;", &next); } } // next loop readNextTag(fp); } sort(beats.begin(), beats.end(), sortNoteFunction); // for each item in the beats vector, create a struct ARROW (real chart object) and translate 'DWI beats' to milliseconds int numNotes = beats.size(); float currentTime = gap; float lastBeatProcessed = 0.0; for ( int i = 0; i < numNotes; i++ ) { struct ARROW a; struct FREEZE f; float beatsDifference = beats[i].beat - lastBeatProcessed; lastBeatProcessed = beats[i].beat; currentTime += timePerBeat*beatsDifference; if (currentTime < 0) { continue; // uh-oh; } al_trace("%f\r\n", currentTime); switch ( beats[i].type ) { case TAP: a.timing = currentTime; a.color = calculateArrowColor(a.timing, timePerBeat); a.type = TAP; a.columns[0] = beats[i].column; a.judgement = UNSET; chart->push_back(a); break; case HOLD_START: f.startTime = currentTime; f.columns[0] = beats[i].column; f.endTime1 = getMillisecondsAtBeat(beats[i].param, &beats, i, currentTime, timePerBeat); //it ends at beat beats[i].param holds->push_back(f); break; case BPM_CHANGE: a.timing = currentTime; a.color = beats[i].param; a.type = BPM_CHANGE; a.judgement = UNSET; chart->push_back(a); timePerBeat = BPM_TO_MSEC(beats[i].param); // new tempo! the length of a beat has henceforth and immediately changed break; case SCROLL_STOP: a.timing = currentTime; a.color = beats[i].param; a.type = SCROLL_STOP; chart->push_back(a); currentTime += beats[i].param; // advance the time break; case END_SONG: a.timing = currentTime + 1000; // TODO: something better than this, maybe check the mp3? a.type = END_SONG; chart->push_back(a); break; default: al_trace("IMPOSSIBLE NOTE TYPE IN readDWI() %d\r\n", beats[i].type); } } fclose(fp); // count the maximum score that this chart is worth. it is needed while the chart is being played int maxScore = 0; for ( size_t i = 0; i < chart->size(); i++ ) { if ( chart->at(i).type == TAP || chart->at(i).type == JUMP ) { maxScore += 2; } } maxScore += holds->size()*2; return maxScore; }