// Copyright (c) 2006, Rodrigo Braz Monteiro // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of the Aegisub Group nor the names of its contributors // may be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // ----------------------------------------------------------------------------- // // AEGISUB // // Website: http://aegisub.cellosoft.com // Contact: mailto:zeratul@cellosoft.com // /////////// // Headers #include "game_display.h" #include "kana_table.h" #include "game_window.h" #include "game_panel.h" #include "main.h" /////////////// // Constructor GameDisplay::GameDisplay(wxWindow *parent) : wxWindow (parent,-1,wxDefaultPosition,wxSize(400,320)) { // Get status bar statusBar = ((wxFrame*)parent)->GetStatusBar(); wxMenuBar *menuBar = ((wxFrame*)parent)->GetMenuBar(); menuCheck[0] = menuBar->FindItem(Menu_Options_Hiragana); menuCheck[1] = menuBar->FindItem(Menu_Options_Katakana); EnableGame(false); // Initialize Reset(); } ////////////// // Destructor GameDisplay::~GameDisplay() { Save(); delete table; } ///////// // Reset void GameDisplay::Reset() { autoLevel = true; status = 0; levelUp = 0; level[0] = 1; level[1] = 1; enabled[0] = true; enabled[1] = false; menuCheck[0]->Check(enabled[0]); menuCheck[1]->Check(enabled[1]); table = new KanaTable(); current = NULL; ResetTable(0); ResetTable(1); GetNextKana(); UpdateStatusBar(); } ///////////////// // Get next kana void GameDisplay::GetNextKana() { // Select table int tn; if (!enabled[0]) tn = 1; else if (!enabled[1]) tn = 0; else tn = rand() % 2; curTable = tn; // Maximum number of glyphs int n = GetNAtLevel(level[curTable],curTable); // Add all valid positions to an array // Each one will be added a number of times relative to its weight (1 to 20 times) std::vector picks; int cur; for (int i=0;i 20) weight = 20; weight = weight * weight; for (int j=0;jGetEntry(curn); // Refresh Refresh(false); } //////////////// // Enter romaji void GameDisplay::EnterRomaji(wxString romaji) { // Check if it's correct bool correct = (romaji == current->hepburn); lastEntry = romaji; levelUp = 0; // Get next if (correct) { // Add 1 to score int temp = scores[curTable][curn] + 1; if (temp > 10) temp = 10; scores[curTable][curn] = temp; // Check if it's OK to level up int n = GetNAtLevel(level[curTable],curTable); bool ok = true; for (int i=0;iGetNumberEntries(); for (int i=0;iGetEntry(i).hepburn == romaji) { temp = scores[curTable][i]; if (temp == -100) break; temp -= toSub; if (temp < -10) temp = -10; scores[curTable][i] = temp; break; } } // Set status if (status == 2 || status == 4) status = 4; else if (status == 1) status = 2; else status = 1; } // Refresh Refresh(false); } // Save Save(); } ///////////////// // Reset a table void GameDisplay::ResetTable(int id) { // Get entries for this table int n = table->GetNumberEntries(); // Set size properly scores[id].resize(n); // Reset with -100 for (int i=0;iGetLevels(tablen); if (level > max) level = max; return table->GetNumberEntries(level); } /////////////// // Event table BEGIN_EVENT_TABLE(GameDisplay,wxWindow) EVT_PAINT(GameDisplay::OnPaint) EVT_LEFT_DOWN(GameDisplay::OnClick) END_EVENT_TABLE() /////////////// // Draw window void GameDisplay::OnPaint(wxPaintEvent &event) { // Begin drawing wxPaintDC dc(this); dc.BeginDrawing(); int w,h,tw,th; GetClientSize(&w,&h); // Background colours //wxColour col1(130,177,236); //wxColour col2(181,209,244); wxColour col1(220,194,105); wxColour col2(245,231,177); // Draw background dc.SetPen(*wxTRANSPARENT_PEN); dc.SetBrush(col1); dc.DrawRectangle(0,0,w,h); dc.SetBrush(col2); dc.DrawRectangle(5,5,w-10,h-10); dc.SetBrush(col1); dc.DrawRectangle(10,0,5,h); dc.DrawRectangle(w-15,0,5,h); dc.DrawRectangle(0,10,w,5); dc.DrawRectangle(0,h-15,w,5); // Enabled? if (!isOn) { dc.EndDrawing(); return; } // Set font wxFont font(128,wxDEFAULT,wxFONTSTYLE_NORMAL,wxNORMAL,0,_T("MS Mincho"),wxFONTENCODING_DEFAULT ); dc.SetFont(font); if (status == 0) dc.SetTextForeground(wxColour(0,0,0)); if (status == 1 || status == 2 || status == 4) dc.SetTextForeground(wxColour(220,10,10)); // Get text metrics wxString text; if (curTable == 0) text = current->hiragana; else text = current->katakana; dc.GetTextExtent(text,&tw,&th,NULL,NULL,&font); // Draw text dc.SetPen(wxColour(0,0,0)); dc.DrawText(text,(w-tw)/2,(h-th)/2); // Prepare status text font.SetFaceName(_T("Verdana")); font.SetPointSize(16); dc.SetFont(font); wxString topString; wxString bottomString; wxString bottomString2; wxString levelString; // Correct if (status == 3) { dc.SetTextForeground(wxColour(0,128,0)); topString = wxString(_T("Correct! \"")); if (lastTable == 0) topString += previous->hiragana; if (lastTable == 1) topString += previous->katakana; topString += wxString(_T("\" is \"")) + lastEntry + _T("\"!"); } // Wrong if (status == 1 || status == 2 || status == 4) { // Top text const KanaEntry *real = table->FindByRomaji(lastEntry); topString = wxString(_T("Wrong!")); if (real) { topString += _T(" \""); if (curTable == 0) topString += real->hiragana; if (curTable == 1) topString += real->katakana; topString += wxString(_T("\" is \"")) + lastEntry + _T("\"!"); } else topString += _T(" \"") + lastEntry + _T("\" doesn't exist!"); // Find hints wxString group = current->group; wxString vowel = current->hepburn.Right(1); if (vowel == _T("n")) { group = vowel; vowel = _T(""); } // Bottom text (hints) bottomString = wxString(_T("Hint: \"")); if (curTable == 0) bottomString += current->hiragana; if (curTable == 1) bottomString += current->katakana; if (status == 4) { bottomString += _T("\" is \"") + current->hepburn + _T("\"."); } else { if (group == _T("a")) { if (status == 1) bottomString += _T("\" is a vowel."); else bottomString += _T("\" is the vowel \"") + current->hepburn + _T("\"."); } else { bottomString += _T("\" is from the group of \"") + group + _T("\""); if (status == 1 || vowel == _T("")) bottomString += _T("."); else bottomString2 = _T("ending with the vowel \"") + vowel + _T("\"."); } } } // Asking for help if (status == 5) { dc.SetTextForeground(wxColour(96,64,0)); bottomString = wxString(_T("\"")); if (curTable == 0) bottomString += current->hiragana; if (curTable == 1) bottomString += current->katakana; bottomString += _T("\" is \"") + current->hepburn + _T("\"."); } // Level up if (levelUp) { levelString = _T("Level up on "); if (levelUp == 1) levelString += _T("hiragana!"); if (levelUp == 2) levelString += _T("katakana!"); } // Draw top text int th2=0,tw2=0; dc.GetTextExtent(topString,&tw,&th,NULL,NULL,&font); dc.DrawText(topString,(w-tw)/2,20); font.SetPointSize(14); dc.SetFont(font); dc.GetTextExtent(levelString,&tw2,&th2,NULL,NULL,&font); dc.DrawText(levelString,(w-tw2)/2,20+th); // Draw bottom text font.SetPointSize(12); dc.SetFont(font); dc.GetTextExtent(bottomString,&tw,&th,NULL,NULL,&font); if (!bottomString2.IsEmpty()) dc.GetTextExtent(bottomString2,&tw2,&th2,NULL,NULL,&font); else { tw2 = 0; th2 = 0; } dc.DrawText(bottomString,(w-tw)/2,h-20-th-th2); dc.DrawText(bottomString2,(w-tw2)/2,h-20-th2); // Done dc.EndDrawing(); } ///////////////////// // Update status bar void GameDisplay::UpdateStatusBar() { statusBar->SetStatusText(playerName,0); if (enabled[0]) statusBar->SetStatusText(wxString::Format(_T("Hiragana lvl %i"),level[0]),1); else statusBar->SetStatusText(_T("Hiragana disabled"),1); if (enabled[1]) statusBar->SetStatusText(wxString::Format(_T("Katakana lvl %i"),level[1]),2); else statusBar->SetStatusText(_T("Katakana disabled"),2); } ////////////////////////// // Enable/disable a table void GameDisplay::EnableTable(int tn,bool status) { if (enabled[tn] != status) { enabled[tn] = status; if (status == false && curTable == tn) { if (enabled[1-curTable] == false) { enabled[1-curTable] = true; menuCheck[1-curTable]->Check(true); } status = 0; GetNextKana(); } } UpdateStatusBar(); } ///////////// // Set level void GameDisplay::SetLevel(int tablen,int lvl) { // Set values int max = table->GetNumberEntries(); int n = table->GetNumberEntries(lvl); for (int i=0;ilevel > lvl) { status = 0; GetNextKana(); } // Update status UpdateStatusBar(); } /////////////// // Enable game void GameDisplay::EnableGame(bool enable) { UpdateStatusBar(); if (isOn == enable) return; isOn = enable; Refresh(false); } ///////////// // Save game void GameDisplay::Save() { // Player name set? if (playerName.IsEmpty()) return; // Open file wxString path = KanaMemo::folderName + _T("/") + playerName + _T(".usr"); FILE *fp = fopen(path.mb_str(wxConvLocal),"wb"); if (!fp) return; // Write version char buffer[128]; strcpy(buffer,"kanamemo V2"); fwrite(buffer,1,12,fp); // Write enabled status char temp; temp = enabled[0] ? 1 : 0; fwrite(&temp,1,1,fp); temp = enabled[1] ? 1 : 0; fwrite(&temp,1,1,fp); // Write levels temp = level[0]; fwrite(&temp,1,1,fp); temp = level[1]; fwrite(&temp,1,1,fp); // Write autolevel flag temp = autoLevel; fwrite(&temp,1,1,fp); // Write scores int temp2; temp2 = scores[0].size(); fwrite(&temp2,1,4,fp); for (int i=0;i= 2) { fread(&temp,1,1,fp); autoLevel = temp == 1; } // Read scores int temp2; fread(&temp2,1,4,fp); scores[0].resize(temp2); for (int i=0;iCheck(enabled[0]); menuCheck[1]->Check(enabled[1]); UpdateStatusBar(); GetNextKana(); Refresh(false); } ///////////////////////// // Click on display area void GameDisplay::OnClick(wxMouseEvent &event) { panel->enterField->SetFocus(); }