diff --git a/programs/games/21days/COPYING b/programs/games/21days/COPYING new file mode 100755 index 0000000000..d159169d10 --- /dev/null +++ b/programs/games/21days/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/programs/games/21days/Makefile b/programs/games/21days/Makefile new file mode 100755 index 0000000000..8b541d6131 --- /dev/null +++ b/programs/games/21days/Makefile @@ -0,0 +1,5 @@ +OUTFILE = 21days +OBJS = main.o game.o interface.o sys.o +CPPFLAGS += -Wno-write-strings -D _KOS32 + +include $(MENUETDEV)/makefiles/Makefile_for_cpp_program \ No newline at end of file diff --git a/programs/games/21days/Makefile.linux b/programs/games/21days/Makefile.linux new file mode 100755 index 0000000000..ba5eefab39 --- /dev/null +++ b/programs/games/21days/Makefile.linux @@ -0,0 +1,26 @@ +OUTFILE = bin/21days +CXX = g++ +OBJS = obj/main.o obj/game.o obj/interface.o obj/sys.o + +CXXFLAGS = -Wno-write-strings + +all: $(OUTFILE) + +dirs: + test -d bin || mkdir -p bin + test -d obj || mkdir -p obj + +$(OUTFILE): dirs $(OBJS) + $(CXX) -o $(OUTFILE) $(OBJS) + +obj/%.o: %.cpp + $(CXX) $(CXXFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJS) $(OUTFILE) + rm -rf bin + rm -rf obj + +rebuild: clean $(OUTFILE) + +.PHONY: dirs clean rebuild \ No newline at end of file diff --git a/programs/games/21days/Makefile.win b/programs/games/21days/Makefile.win new file mode 100755 index 0000000000..1175d895f2 --- /dev/null +++ b/programs/games/21days/Makefile.win @@ -0,0 +1,27 @@ +OUTFILE = bin\21days +CXX = g++ +OBJS = obj/main.o obj/game.o obj/interface.o obj/sys.o + +CXXFLAGS = -Wno-write-strings -D _WIN32 + +all: $(OUTFILE) + +dirs: + if not exist "bin" mkdir bin + if not exist "obj" mkdir obj + +$(OUTFILE): dirs $(OBJS) + $(CXX) -o $@ $(OBJS) + +obj/%.o: %.cpp + $(CXX) $(CXXFLAGS) -c $< -o $@ + +clean: + if exist "obj\*.o" del /Q obj\*.o + if exist "bin\21days.exe" del /Q bin\21days.exe + if exist "bin" rd bin + if exist "obj" rd obj + +rebuild: clean $(OUTFILE) + +.PHONY: dirs clean rebuild \ No newline at end of file diff --git a/programs/games/21days/README b/programs/games/21days/README new file mode 100755 index 0000000000..50a19f0a50 --- /dev/null +++ b/programs/games/21days/README @@ -0,0 +1,79 @@ +# 21 days: a game for programmers + +## Features + +* You start as a helpdesker. +* Work in a big company. +* Join a startup and launch a popular game (or not). +* Study new courses. +* Help your friends to repair their computer. + +* With the help of quantum space–time folder you can do all of this in 21 days! +* Jump in time to change your choice and collect all achievements! + +## License + +21 days is licensed under GPL version 2.0. See COPYING in the same directory. + +## Author + +This program developed by Maxim Grishin (igevorse) + +## Installation + +This program does not require installation. +See "Run" section below. + +## Run + +Open your favourite file manager and run the executable file. +You can also use your shell: + +* KolibriOS: + + 21days + +* Windows: + + cd bin + 21days + +* Linux (you have to use a terminal supporting IBM866 code page(CP866)): + + cd bin + ./21days + +## Building from sources + +If you want to build game from sources, you have to install GCC (Linux) and MinGW (Windows). + +* KolibriOS +You have to install menuetlibc: see "Compilers GCC, G++." section at diamond.kolibrios.org/hll/hll_eng.htm. +To build a binary file for KolibriOS under Linux type in a terminal: + + make + +Binary file would appear in current directory. + +* Linux +To build a Linux binary file: + + make -f Makefile.linux + +Binary files would appear in bin directory. + +* Windows +To build a Windows binary file you have to install MinGW (http://sourceforge.net/projects/mingw/files/) with mingw32-base, mingw32-gcc and mingw-gcc-g++ packages. +Don't forget to add a path to a folder containing MinGW binary files to the Path environment variable ("C:\MinGW\bin" for me). + + * If you don't have MSYS installed: + + mingw32-make -f Makefile.win + + * If you have MSYS installed: + + make -f Makefile.linux + +Binary files would appear in bin directory. + +Have fun! \ No newline at end of file diff --git a/programs/games/21days/Tupfile.lua b/programs/games/21days/Tupfile.lua new file mode 100755 index 0000000000..7655c042d9 --- /dev/null +++ b/programs/games/21days/Tupfile.lua @@ -0,0 +1,7 @@ +if tup.getconfig("NO_GCC") ~= "" then return end +HELPERDIR = (tup.getconfig("HELPERDIR") == "") and "../../.." or tup.getconfig("HELPERDIR") +tup.include(HELPERDIR .. "/use_gcc.lua") +tup.include(HELPERDIR .. "/use_menuetlibc.lua") +CFLAGS = CFLAGS .. " -D _KOS32 " +compile_gcc{"main.cpp", "game.cpp", "interface.cpp", "sys.cpp"} +link_gcc("21days") diff --git a/programs/games/21days/game.cpp b/programs/games/21days/game.cpp new file mode 100755 index 0000000000..0fa978839c --- /dev/null +++ b/programs/games/21days/game.cpp @@ -0,0 +1,1584 @@ +/****************************************************************** +* 21 days: a game for programmers +* Copyright (C) 2014 Maxim Grishin +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301, USA. +*******************************************************************/ + +#define DEFAULT_PATH 0 +#define WORK_PATH 1 +#define STARTUP_PATH 2 + +#include "sys.h" +#include "strings.h" +#include "interface.h" +#include "pq.h" + +#ifdef _KOS32 + #include + #define vector vector21 +extern "C" { + void *__dso_handle = 0; + void *__cxa_atexit = 0; + void *__stack_chk_fail = 0; + } +#else + #define printf2 printf + #include //srand + #include + using std::vector; + #include // usleep +#endif + +#include +#include +using std::string; + +Undo2 history; + +/************************************** +* Player +*****************************************/ +long double playerMoney = 100; +int playerSalary = 0; +int playerSalaryFirstDay = 0; +int playerPath = DEFAULT_PATH; +int playerKarma = 20; +double dt = 1.0; // days per secons +long double gameTime = 0; // Time in days +double unreadMessages = 0; +unsigned int timeHops = 0; +bool allAchievesShowed = false; +bool charityUnlocked = false; + +int playerFreelanceAttempts = 0; +bool controlFreelanceAttempts = false; + +bool sentBotsmannLetter = false; +bool astraLetterSent = false; +bool shitCodeDetected = false; +bool shitLettersSent[3] = {0,0,0}; +bool shitLettersFinished[3] = {0,0,0}; +bool showCoursesTab = false; +PQ3 pq; // events priority queue +bool noPopularity = false; +short finalCardsUnlocked = 0; +bool finalCardUnlocked[5] = {0,0,0,0,0}; +bool returnTo21HintShowed = false; +// Player Stats +time_t playerStartedPlaying; +unsigned long playerTimeHops = 0; +unsigned long playerMessagesRead = 0; +unsigned long playerHelped = 0; +unsigned long playerDidntHelped = 0; +long double playerSpentRealDays = 0; +long double playerPrevUndo = 0; +long double playerMoneyEarned = 100; +long double playerMoneySpent = 0; +double playerMoneySpentForCharity = 0; + + +void mainGameCycle(); +int showSettingsScreen(); +int chooseCourse(); +void showAchievesScreen(); + +void startNewGame(); +void initSendingMessage(); +void undo(long double toTime); + +string getStatusLine(); + +void addTimer(event e) { + if (e.type == SPECIAL_LETTER && + (e.idata == LETTER_SHITCODE_1 + || e.idata == LETTER_SHITCODE_2 + || e.idata == LETTER_SHITCODE_3) + && pq.containsType(e.type, e.idata)) + return; + if (e.type == MESSAGE && pq.containsType((int)e.type)) + return; + + pq.insert(e); + history.insert(event(e.time + gameTime, e.type, e.idata)); + } + +void unlockFinalCards(short p) { + if (!finalCardUnlocked[p]) + finalCardsUnlocked++; + + finalCardUnlocked[p] = true; + } + +void increaseMoney(long double m) { + playerMoney += m; + if (m > 0) + playerMoneyEarned += m; + if (m < 0) + playerMoneySpent -= m; + } + +void increaseKarma(int k, bool addTimerMsg = true) { + if (playerKarma <= 0 && playerKarma+k>0) + initSendingMessage(); + int oldKarma = playerKarma; + playerKarma += k; + if (playerKarma < -100) + playerKarma = -100; + + if (playerKarma > 100) + playerKarma = 100; + + if (addTimerMsg && playerKarma - oldKarma != 0) + history.insert(event(2*dt, INCREASEPOPULARITY, playerKarma - oldKarma)); + } + +void changePath(int to) { + history.insert(event(gameTime, CHANGEPATH, playerPath)); + playerPath = to; + } + +void changeSalary(int to) { + history.insert(event(gameTime, CHANGESALARY, playerSalary)); + playerSalary = to; + } + +void changeSalaryFirstDay(int to) { + history.insert(event(gameTime, CHANGESALARYFIRSTDAY, playerSalaryFirstDay)); + playerSalaryFirstDay = to; + } + +int karma() { + return playerKarma; + } + +void initSendingMessage() { + double newTime = (karma() <= 0)?0.0:0.5 ;//* karma() / 100.0; + if (newTime > 0) { + addTimer(event(newTime, MESSAGE)); + } + else { + noPopularity = true; + addTimer(event(0, NOPOPULARITY)); + } + } + +void checkAchieves() { + /// No popularity + if (!achievesPicked[1] && noPopularity) + achievesPicked[1] = true; + /// Millionaire + if (!achievesPicked[3] && playerMoney >= 1000000.0) { + achievesPicked[3] = true; + charityUnlocked = true; + } + /// Time jumper + if (!achievesPicked[8] && timeHops >= 3) + achievesPicked[8] = true; + + allAchievesShowed = true; + /// Show achieve notification + for (unsigned int i = 0; i < achievesNumber; i++) { + if (achievesPicked[i] && !achievesShowed[i]) { + drawModalWindow(achieves[i], newAchievement); + wait(); + if (i == 3) { + drawModalWindow(pressRForCharity, 0, "[R]"); + wait('r','R'); + } + achievesShowed[i] = true; + } + else if (!achievesShowed[i]) + allAchievesShowed = false; + } + } + +void showMainMenu() { + string s = days21; + s+=mainMenuText; + drawWindow(s, gameName, "", txt("%s %s", one_or_two, developer)); + char menu = getAnswer('1', '2'); + + switch(menu) { + case '1': + startNewGame(); + break; + case '2': // TODO: Save? + + break; + } + } + +void showAchievesScreen() { + string s; + for (unsigned short i = 0; i < achievesNumber; i++) + s += txt("[%c] %s \n", achievesPicked[i]?'X':' ', achieves[i]); + + s += txt(finalCardsUnlockedText, finalCardsUnlocked, 5); + char totalCoursesCount = 12; + s += txt(coursesFinishedText, (int)finishedCoursesCount, (int)totalCoursesCount); + drawWindow(s, achievementsTitle, getStatusLine(), enter); + } + +string printExactTask(int course, int task, int word) { + switch (course) { + case 1: + case 2: + return string(programmingTasks[task]); + break; + case 3: + case 4: + return string(mobileTasks[task]); + break; + case 5: + return string(webProgrammingTasks[task]); + break; + case 6: + return string(systemProgrammingTask[task]); + break; + case 7: + return string(adminTasks[task]); + break; + case 0: + default: + return txt(level1Task[task], level1TaskWords[word]); + break; + } + } + +void showLearnDialog() { + string s = selectCourseText; + for (unsigned short i = 0; i < coursesNumber; i++) { + if (!coursesUnlocked[i]) + continue; + + if (i == 2) { + s+=txt("3.%s\n", courses[2]); + for (int j = 0; j < advancedProgrammingCourses; j++) { + s+=txt(" %c.%s [%c]", (char)('a'+j), advProgCourses[j], (advProgCoursesFinished[j])?'X':' '); + if (!advProgCoursesFinished[j] && !pq.hasCourse('a'+j)) + s+=txt(takeCourseCost, advProgLearningCost[j]); + else if (pq.hasCourse('a'+j)) + s+=takingThisCourse; + else + s+="\n"; + } + continue; + } + + s+=txt("%c.%s [%c]", (char)('1'+i), courses[i], (coursesFinished[i])?'X':' '); + if (!coursesFinished[i] && !pq.hasCourse(i)) + s+=txt(takeCourseCost, learningCost[i]); + else if (pq.hasCourse(i)) { + s+=takingThisCourse; + } + else + s+="\n"; + } + + drawWindow(s, coursesTitle ,"", number_or_enter); + unsigned char answer = 0; + answer = getKey(); + + if (answer == ENTER_KEY) + return; + + else if (answer >='1' && answer <=(char)('0'+coursesNumber) && answer != '3') { + answer -- ; + answer -='0'; + + if (coursesUnlocked[answer]){ + if (coursesFinished[answer]) { + drawModalWindow(courseAlreadyPassed, errorMsg); + wait(); + showLearnDialog(); + return; + } + else if (playerMoney > learningCost[answer] && !pq.hasCourse(answer)) { + drawModalWindow(txt(successfullyEnrolled, courses[answer]).c_str(), congratsMsg); + wait(); + increaseMoney(-learningCost[answer]); + addTimer(event(learningTime[answer], COURSE, answer)); + } + else if (playerMoney <= learningCost[answer] && !pq.hasCourse(answer)){ + drawModalWindow(notEnoughMoney, errorMsg); + wait(); + showLearnDialog(); + } + else + showLearnDialog(); + return; + } + else + showLearnDialog(); + } + else if (answer == '3' && coursesUnlocked[2]) { + drawModalWindow(ae_advanced_courses,errorMsg); + wait(); + showLearnDialog(); + } + /// only small letters + else if (answer >='a' && answer <= 'e') { + answer -= 'a'; + if (coursesUnlocked[2] && playerMoney > advProgLearningCost[answer] && !advProgCoursesFinished[answer] && !pq.hasCourse('a'+answer)) { + drawModalWindow(txt(successfullyEnrolled,advProgCourses[answer]).c_str(), congratsMsg); + wait(); + + increaseMoney(-advProgLearningCost[answer]); + int learnCourseNumber = answer+'a'; + if (advProgLearningTime[answer] != 0 && learnCourseNumber != -1) + addTimer(event(advProgLearningTime[answer], COURSE, learnCourseNumber)); + return; + } + else if (coursesUnlocked[2] && playerMoney <= advProgLearningCost[answer] && !advProgCoursesFinished[answer] && !pq.hasCourse('a'+answer)) { + drawModalWindow(notEnoughMoney, errorMsg); + wait(); + showLearnDialog(); + } + else if (advProgCoursesFinished[answer]) { + drawModalWindow(courseAlreadyPassed, errorMsg); + wait(); + showLearnDialog(); + return; + } + else + showLearnDialog(); + } + else if (answer == '3') { + showLearnDialog(); + } + else if (coursesUnlocked[2]) { + drawModalWindow(ae_advanced_courses,errorMsg); + wait(); + showLearnDialog(); + } + else + showLearnDialog(); + return; + } + +void startNewGame() { + // Intro + drawWindow(gameIntroTextPart1, introTitle, "", enter, true); + wait(); + drawWindow(gameIntroTextPart2, introTitle, "", enter, true); + wait(); + drawWindow(gameIntroTextPart3, introTitle, "", enter, true); + wait(); + // Goals + drawWindow(gameIntroPlan, 0, "", enter, true); + wait(); + // Desktop + drawWindow("", introDesktop, "", enter); + wait(); + // Top line + drawWindow(introStatusLine,"", getStatusLine(), enter); + wait(); + // Keys + drawWindow("", "", "", introAllowedKeys); + wait('1'); + // Dialog window + drawModalWindow(introFinished, introLetsBegin); + wait(); + // Start game! + mainGameCycle(); + } + +void showFinalStats() { + // Show player stats + int minutesInGame = (time(NULL) - playerStartedPlaying)/60; + playerSpentRealDays += (gameTime - playerPrevUndo); + long unsigned int val[9] = { + static_cast(playerSpentRealDays), + static_cast(minutesInGame), + playerMessagesRead, + playerHelped, + playerDidntHelped, + static_cast(playerMoneyEarned), + static_cast(playerMoneySpent), + static_cast(playerMoneySpentForCharity), + playerTimeHops}; + string s = "\n"; + s += playerStatsTitle; + for (int i = 0; i < 9; i++) { + s += txt(playerStats[i], static_cast(val[i])); + if (i == 0 || i == 3 || i == 4) + s += getWordEnding(val[i], i); + } + s += playerStatsEnd; + drawWindow(s); + wait(ESCAPE_KEY, ESCAPE_KEY); + } + +bool isGameOver() { + if (noPopularity && !finalCardUnlocked[3] && !pq.containsType(SPECIAL_LETTER, LETTER_FINALPATH_NOPOPULARITY)) { + addTimer(event(2.0, SPECIAL_LETTER, LETTER_FINALPATH_NOPOPULARITY)); + return false; + } + + if ((playerPath == DEFAULT_PATH || playerPath == STARTUP_PATH) && playerMoney < 0.0 && !finalCardUnlocked[4] && !pq.containsType(SPECIAL_LETTER, LETTER_FINALPATH_NOMONEY)) { + addTimer(event(2.0, SPECIAL_LETTER, LETTER_FINALPATH_NOMONEY)); + return false; + } + // You win! + if (finishedCoursesCount >= 12 && finalCardsUnlocked >= 5 && gameTime <= 22.0 && allAchievesShowed) { + std::string s = youWin; + s += gameOver; + drawWindow(s, congratsMsg, "", pressF); + wait('f','F'); + showFinalStats(); + return true; + } + // Game over + if (playerMoney < 0 && karma() < 0 && noPopularity && floor(unreadMessages) == 0 && gameTime > 22.0 && + achievesShowed[1] && finalCardUnlocked[3] && finalCardUnlocked[4] && + !pq.containsType(SPECIAL_LETTER) && !pq.containsType(MESSAGE)) { + string s = gameOverLogo; + s += gameOverText; + drawWindow(s, gameOverTitle, "", pressF); + wait('f','F'); + showFinalStats(); + return true; + } + return false; + } + +int getAvailableCoursesCount() { + int a = 0; + for (unsigned int i = 0; i < coursesNumber; i++) { + if (i!= 2 && coursesUnlocked[i] && !coursesFinished[i]) + a++; + } + // Anvanced programming + if (coursesUnlocked[2]) { + for (int i = 0; i < advancedProgrammingCourses; i++) + if (!advProgCoursesFinished[i]) + a++; + } + return a; + } + +std::string getStatusLine() { + string s = txt(statusLine, (int)gameTime, (int)playerMoney, karma(), (int)floor(unreadMessages)); + if (showCoursesTab) + s += txt(statusLineCoursesNotFinished, getAvailableCoursesCount()); + return s; + } + +string getBottomLine() { + string s; + if (showCoursesTab) + s += bottomLineCourses; + s += bottomLineMsgAchieves; + if (charityUnlocked) { + s += charityTitle; + s += "[R] "; + } + s += bottomLineSpeedAndExit; + return s; + } + +int showUnreadMessages() { + int newTaskLevel = chooseCourse(); + + unsigned int task = rand() % taskCount[newTaskLevel]; + unsigned int word = rand() % level1TaskWordNumber; + unsigned int yes = rand() % levelYesAnswerNumber; + unsigned int no = rand() % levelNoAnswerNumber; + + string s = printExactTask(newTaskLevel, task, word); + s += txt(yourAnswer,levelYesAnswer[yes],levelNoAnswer[no]); + string buttons = one_or_two; + buttons += escToBreakReading; + drawWindow(s, unread_message, getStatusLine(), buttons); + return newTaskLevel; + } + +bool messageGetAnswer(int level) { + long double reward = taskReward[level] + rand() % 20; + char answerKey = getAnswer('1', '2', ESCAPE_KEY); + + switch (answerKey) { + case '1': + // Player Stats + playerHelped++; + increaseMoney(reward); + increaseKarma(reward/5.0, false); + if (playerPath == WORK_PATH && controlFreelanceAttempts) { + playerFreelanceAttempts++; + if (playerFreelanceAttempts > 5) { + addTimer(event(1.0, SPECIAL_LETTER, LETTER_ANGRYBOSS_2)); + controlFreelanceAttempts = false; + } + } + // Repairing computer takes 0.5 days + gameTime += 0.5; + break; + case '2': + // Player Stats + playerDidntHelped++; + increaseKarma(-reward/2.0, false); + break; + case ESCAPE_KEY: + return true; + break; + } + return false; + } + +double showChangeSpeedDialog(string e = "") { + string s; + if (dt >= 1.0) + s = txt(daysPerSecond, (int)dt); + else { + s = txt(daysPerSecond, 0); + s += txt(".%d", (int)(dt*10)%10); // Actually not the best way of printing double values + } + if (!e.empty()) + s += e; + drawModalWindow(s.c_str(), changeSpeedTitle, changeSpeedButtons); + char ch = getAnswer('+','-','Y','y'); + if (ch == 'y' || ch == 'Y') + return dt; + else if (ch == '+') { + if (dt >= 1.0) + dt += 1.0; + else + dt += 0.10; + if (dt >= 10.0) { + dt = 10.0; + return showChangeSpeedDialog(" max"); + } + return showChangeSpeedDialog(); + } + else if (ch == '-') { + if (dt >= 2.0) + dt -= 1.0; + else + dt -= 0.10; + if (dt <= 0.10) { + dt = 0.10; + return showChangeSpeedDialog(" min"); + } + return showChangeSpeedDialog(); + } + return dt; + } + +// returns 1 if program have to be closed +bool keyPressed(char k) { + switch (k) { + // Courses + case 'c': + case 'C': + if (!showCoursesTab) + break; + showLearnDialog(); + break; + // Achieves + case 'a': + case 'A': + showAchievesScreen(); + wait(); + break; + // Messages + case 'm': + case 'M': { + int oldPopularity = karma(); + // Player Stats + bool breakReading = false; + while (floor(unreadMessages) > 0) { + breakReading = messageGetAnswer(showUnreadMessages()); + if (breakReading) { + break; + } + else { + if (floor(unreadMessages) > 0.0) unreadMessages--; + playerMessagesRead++; + } + } + if (!breakReading) { + drawModalWindow(noUnreadMessages); + wait(); + } + if (karma() != oldPopularity) + history.insert(event(gameTime, INCREASEPOPULARITY, karma()-oldPopularity)); + // Hack + #ifdef _KOS32 + initSendingMessage(); + #endif + } + break; + case 'u': + case 'U': + undo(gameTime - 10); + break; + case 'r': + case 'R': { + if (!charityUnlocked) + break; + + if (playerMoney <= 0) { + drawModalWindow(notEnoughMoneyForCharity, 0, enter); + wait(); + break; + } + drawModalWindow(charityQuestion, charityTitle, yesNoDialog); + char ch = getAnswer('y', 'n', 'Y', 'N'); + if (ch == 'y' || ch == 'Y') { + // Player Stats + playerMoneySpentForCharity += (playerMoney / 2.0); + + increaseMoney(-playerMoney / 2.0); + increaseKarma(abs(karma())); + } + } + break; + case 's': + case 'S': + dt = showChangeSpeedDialog(); + break; + // Escape + case ESCAPE_KEY: { + drawModalWindow(doYouReallyWantToExit,0 , yesNoDialog); + char ans = getAnswer('y','Y','n','N'); + if (ans == 'y' || ans == 'Y') + return true; + } + break; + } + return false; + } + +void breakingNews(int newsID) { + drawWindow(news[newsID], breaking_news, getStatusLine(), enter); + wait(); + } + +void checkPq() { + vector lateEvents; + // Messages in PQ are in reverse order + for (int i = pq.n()-1; i >= 0; i--) { + event* e = pq.get(i); + if (e->time > dt) { + e->time -= dt; + continue; + } + switch (e->type) { + case COURSE: { + string s; + + if (e->idata >= 0 && e->idata < (int)coursesNumber) { + s += txt(courseSuccessfullyFinished,courses[e->idata]); + // Not the best fix for the bug with mobile dev + if (!coursesFinished[e->idata]) + finishedCoursesCount++; + coursesFinished[e->idata] = true; + } + // Advanced programming + else if (e->idata >='a' && e->idata <= 'e') { + e->idata -= 'a'; + s += txt(courseSuccessfullyFinished,advProgCourses[e->idata]); + if (!advProgCoursesFinished[e->idata]) + finishedCoursesCount++; + advProgCoursesFinished[e->idata] = true; + } + increaseKarma(+5); + + pq.delMin(); + drawModalWindow(s.c_str(), congratsMsg); + wait(); + } + break; + case SPECIAL_LETTER: + switch (e->idata) { + case LETTER_RETURN_TO_DAY_21: + drawModalWindow(returnToDay21, 0, pressP); + wait('p','P'); + returnTo21HintShowed = true; + break; + case LETTER_SHITCODE_1: + case LETTER_SHITCODE_2: + case LETTER_SHITCODE_3: { + if (playerPath == WORK_PATH) + break; + string s; + int letterIndex = e->idata*2; + s += specialLetters[letterIndex]; + s += shitCodeYourAnswer; + drawWindow(s, new_letter, getStatusLine(), one_or_two); + + char ch = getAnswer('1', '2'); + if (ch == '1') { + if (e->idata == LETTER_SHITCODE_1 && advProgCoursesFinished[0] && advProgCoursesFinished[1]) { + // sussessfull + increaseMoney(300.0); + increaseKarma(+5); + drawWindow(txt(specialLetters[24], (int)gameTime, 300), answerLetter, getStatusLine(), enter); + shitLettersFinished[0] = true; + } + else if (e->idata == LETTER_SHITCODE_2 && advProgCoursesFinished[2]) { + // sussessfull + increaseMoney(500.0); + increaseKarma(+5); + drawWindow(txt(specialLetters[24], (int)gameTime, 500), answerLetter, getStatusLine(), enter); + shitLettersFinished[1] = true; + } + else if (e->idata == LETTER_SHITCODE_3 && advProgCoursesFinished[3]) { + // sussessfull + increaseMoney(800.0); + increaseKarma(+5); + drawWindow(txt(specialLetters[24], (int)gameTime, 800), answerLetter, getStatusLine(), enter); + shitLettersFinished[2] = true; + } + else { + drawModalWindow(specialLetters[letterIndex+1], answerLetter); + coursesUnlocked[2] = true; + shitCodeDetected = true; + increaseKarma(-5); + } + + if (shitLettersFinished[0] && shitLettersFinished[1] && shitLettersFinished[2]) + achievesPicked[0] = true; + + wait(); + } + else if (ch == '2') { + increaseKarma(-2); + } + } + break; + case LETTER_BOTSMANN: + if (playerPath == DEFAULT_PATH) { + string s = specialLetters[6]; + drawWindow(s, new_letter, getStatusLine(), enter); + wait(); + lateEvents.push_back(event(10.0, SPECIAL_LETTER, LETTER_ASTRA)); + } + break; + case LETTER_ASTRA: + if (playerPath == DEFAULT_PATH) { + string s = specialLetters[7]; + s += shitCodeYourAnswer; + + drawWindow(s, new_letter, getStatusLine(), one_or_two); + char ch = getAnswer('1', '2'); + if (ch == '1') { + s = specialLetters[8]; + drawWindow(s, new_letter, getStatusLine(), enter); + increaseKarma(-10); + } + else if (ch == '2') { + s = specialLetters[9]; + drawWindow(s, new_letter, getStatusLine(), enter); + // Unlock mobile development + coursesUnlocked[3] = true; + if (!coursesFinished[3] && !pq.hasCourse(3)); + lateEvents.push_back(event(learningTime[3], COURSE, 3)); + changePath(WORK_PATH); + changeSalary(800); + changeSalaryFirstDay((int)gameTime); + increaseKarma(+5); + } + wait(); + } + break; + case LETTER_UNNAMEDSTUDIO_1: { + string s = specialLetters[10]; + if (playerPath == WORK_PATH) { + lateEvents.push_back(event(15.0, SPECIAL_LETTER, LETTER_ANGRYBOSS_1)); + drawWindow(s, new_letter, getStatusLine(), enter); + wait(); + } + else if(playerPath == DEFAULT_PATH) { + s += unnamedStudio1Answer; + drawWindow(s, new_letter, getStatusLine(), one_or_two); + char ch = getAnswer('1', '2'); + if (ch == '1') { + changePath(STARTUP_PATH); + increaseMoney(-500); + lateEvents.push_back(event(12.0, SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_2)); + } + } + } + break; + case LETTER_UNNAMEDSTUDIO_2: { + string s = specialLetters[13]; + if (coursesFinished[4]) + s+=specialLetters[27]; + else + s+=specialLetters[26]; + drawWindow(s, new_letter, getStatusLine(), enter); + // Design basics course unlocked + coursesUnlocked[4] = true; + unnamedStudioLettersSent[1] = true; + wait(); + } + break; + case LETTER_UNNAMEDSTUDIO_3: { + int needMoney = (int)(playerMoney * 0.5); + if (needMoney > 50000) + needMoney = 50000; + else if (needMoney < 0) + needMoney *= -1; + string s = txt(specialLetters[14], needMoney); + s += unnamedStudio3Answer; + drawWindow(s, new_letter, getStatusLine(), one_or_two); + + char ch = getAnswer('1', '2'); + if (ch == '1') { + increaseMoney(-needMoney); + lateEvents.push_back(event(15.0, SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_4)); + } + else if(ch == '2') { + changePath(DEFAULT_PATH); + achievesPicked[5] = true; + increaseKarma(-10); + } + } + break; + case LETTER_UNNAMEDSTUDIO_4: { + string s = specialLetters[15]; + // Creating web-sites + if (coursesFinished[5]) { + s+=specialLetters[29]; + drawWindow(s, new_letter, getStatusLine(), enter); + wait(); + // Waiting for 40 days + lateEvents.push_back(event(40.0, SPECIAL_LETTER, LETTER_WEBMASTER_CHECK_UNNAMEDSTUDIO)); + break; + } + int needMoney = (int)(playerMoney * 0.5); + if (needMoney > 50000) + needMoney = 50000; + else if (needMoney < 0) + needMoney *= -1; + s += txt(specialLetters[28], needMoney); + s += unnamedStudio4Answer; + drawWindow(s, new_letter, getStatusLine(), one_two_or_three); + char ch = getAnswer('1', '2', '3'); + if (ch == '1') { + increaseMoney(-needMoney); + increaseKarma(+5); + // Pay for the webmaster + lateEvents.push_back(event(40.0, NEWS, 3)); + } + else if (ch == '2') { + coursesUnlocked[5] = true; + lateEvents.push_back(event(40.0, SPECIAL_LETTER, LETTER_WEBMASTER_CHECK_UNNAMEDSTUDIO)); + } + else if (ch == '3') { + changePath(DEFAULT_PATH); + achievesPicked[5] = true; + increaseKarma(-5); + } + } + break; + case LETTER_WEBMASTER_CHECK_UNNAMEDSTUDIO: + if (coursesFinished[5]) { + lateEvents.push_back(event(1.0, NEWS, 3)); + } + else { + // SHow letter about fail + drawWindow(specialLetters[16], new_letter, getStatusLine(), enter); + wait(); + drawModalWindow(startupFailedTip); + wait(); + increaseMoney(1000); + achievesPicked[5] = true; + increaseKarma(-15); + } + break; + case LETTER_UNNAMEDSTUDIO_5: { + drawWindow(specialLetters[17], new_letter, getStatusLine(), enter); + increaseMoney(200000); + increaseKarma(+20); + wait(); + achievesPicked[2] = true; + lateEvents.push_back(event(5.0, SPECIAL_LETTER, LETTER_FINALPATH_STARTUP)); + } + break; + case LETTER_ANGRYBOSS_1: { + string s = specialLetters[11]; + s += angryBossAnswer; + drawWindow(s, new_letter, getStatusLine(), one_or_two); + char ch = getAnswer('1', '2'); + if (ch == '1') { + changeSalary(1200); + coursesUnlocked[5] = true; + coursesUnlocked[6] = true; + coursesUnlocked[7] = true; + playerFreelanceAttempts = 0; + controlFreelanceAttempts = true; + lateEvents.push_back(event(20.0, SPECIAL_LETTER, NO_POPULARITY_HINT)); + } + else if(ch == '2') { + changePath(STARTUP_PATH); + changeSalary(0); + lateEvents.push_back(event(9.0, SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_2)); + achievesPicked[4] = true; + increaseKarma(-10); + } + } + break; + case NO_POPULARITY_HINT: + if (!noPopularity && controlFreelanceAttempts && playerFreelanceAttempts < 5) { + drawWindow(specialLetters[25], new_letter, getStatusLine(), enter); + wait(); + } + break; + case LETTER_ANGRYBOSS_2: + drawWindow(specialLetters[12], new_letter, getStatusLine(), enter); + changePath(DEFAULT_PATH); + changeSalary(0); + wait(); + increaseKarma(-20); + break; + case LETTER_BORING_WORK: + if (playerPath == WORK_PATH) { + drawWindow(specialLetters[18], new_letter, getStatusLine(), enter); + wait(); + lateEvents.push_back(event(15.0, SPECIAL_LETTER, LETTER_PERSISTENT_AND_PATIENT)); + } + break; + case LETTER_BORING_DEFAULT_PATH: + if (playerPath == DEFAULT_PATH && !pq.containsType(SPECIAL_LETTER, LETTER_FINALPATH_DEF + && !pq.containsType(SPECIAL_LETTER, LETTER_BORING_DEFAULT_PATH))) { + drawWindow(specialLetters[19], new_letter, getStatusLine(), enter); + wait(); + lateEvents.push_back(event(5.0, SPECIAL_LETTER, LETTER_FINALPATH_DEF)); + } + break; + case LETTER_FINALPATH_DEF: + if (playerPath == DEFAULT_PATH) { + drawWindow(defaultFinalCard, finalCard, getStatusLine(), pressF); + unlockFinalCards(0); + wait('f', 'F'); + } + break; + case LETTER_FINALPATH_WORK: + if (playerPath == WORK_PATH) { + drawWindow(workFinalCard, finalCard, getStatusLine(), pressF); + unlockFinalCards(1); + wait('f', 'F'); + } + break; + case LETTER_FINALPATH_STARTUP: + if (playerPath == STARTUP_PATH) { + drawWindow(startupFinalCard, finalCard, getStatusLine(), pressF); + unlockFinalCards(2); + wait('f', 'F'); + } + break; + case LETTER_FINALPATH_NOPOPULARITY: + drawWindow(zeroKarmaFinalCard, finalCard, getStatusLine(), pressF); + unlockFinalCards(3); + wait('f', 'F'); + break; + case LETTER_FINALPATH_NOMONEY: + drawWindow(noMoneyFinalCard, finalCard, getStatusLine(), pressF); + unlockFinalCards(4); + wait('f', 'F'); + break; + case LETTER_PERSISTENT_AND_PATIENT: + achievesPicked[7] = true; + lateEvents.push_back(event(2.0, SPECIAL_LETTER, LETTER_FINALPATH_WORK)); + break; + case LETTER_TEST_OF_KNOWLEDGE: + drawWindow(specialLetters[20], new_letter, getStatusLine(), enter); + wait(); + nextKnowledgeLetterIndex = 0; + lateEvents.push_back(event(5.0, SPECIAL_LETTER, LETTER_KNOWLEDGE_QUESTION)); + break; + case LETTER_KNOWLEDGE_QUESTION: { + if (playerPath != WORK_PATH) { + break; + } + + if (klowledgeCorrectAnswers == 5) { + /// премия + drawWindow(specialLetters[21], new_letter, getStatusLine(), enter); + increaseMoney(400); + wait(); + klowledgeCorrectAnswers = 0; + } + if (klowledgeUncorrectAnswers >= 5) { + /// Didn't pass the knowledge check + drawWindow(specialLetters[22], new_letter, getStatusLine(), enter); + wait(); + changePath(DEFAULT_PATH); + changeSalary(0); + break; + } + if (nextKnowledgeLetterIndex > 27) { + /// Knowledge check finished + /// TODO: add a timer for this + drawWindow(specialLetters[23], new_letter, getStatusLine(), enter); + achievesPicked[6] = true; + wait(); + lateEvents.push_back(event(30.0, SPECIAL_LETTER, LETTER_BORING_WORK)); + } + else { + string s = knowledgeCheck[nextKnowledgeLetterIndex]; + short yes = rand() % 2 + 1; // 1 or 2 + short no = (yes == 1)?2:1; + s+=txt(yourAnswer, knowledgeCheck[nextKnowledgeLetterIndex+yes], knowledgeCheck[nextKnowledgeLetterIndex+no]); + drawWindow(s, new_letter, getStatusLine(), one_or_two); + char ch = getAnswer('1', '2');//getch(); + if ((ch - '0') == yes) { + drawModalWindow(rightAnswer, congratsMsg); + klowledgeCorrectAnswers++; + } + else { + drawModalWindow(wrongAnswer, failMsg); + klowledgeUncorrectAnswers++; + } + wait(); + nextKnowledgeLetterIndex+=3; + lateEvents.push_back(event(7.0, SPECIAL_LETTER, LETTER_KNOWLEDGE_QUESTION)); + } + } + break; + default: + break; + } + pq.delMin(); + break; + case MESSAGE: + unreadMessages+=(karma() > 0)?dt * karma()/50:0; + pq.delMin(); + lateEvents.push_back(event(2*dt, MESSAGE)); + break; + case NEWS: { + switch (e->idata) { + // Programming in the world + case 0: + showCoursesTab = true; + coursesUnlocked[1] = true; + break; + // Java programmers + case 1: + coursesUnlocked[2] = true; + break; + // Mobile development + case 2: + coursesUnlocked[3] = true; + break; + case 3: + // Your game is very popular + lateEvents.push_back(event(3.0, SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_5)); + break; + default: + break; + } + breakingNews(e->idata); + pq.delMin(); + } + break; + case NOPOPULARITY: + case INCREASEPOPULARITY: + // nop + pq.delMin(); + break; + default: + break; + } + } + // Add new messages only after checking all existing messages + for (unsigned short i = 0; i< lateEvents.size(); i++) { + event e = lateEvents[i]; + if (e.type == MESSAGE) { + initSendingMessage(); + continue; + } + else if (e.type == SPECIAL_LETTER && e.idata == LETTER_ASTRA) + astraLetterSent = true; + addTimer(e); + } + } + +void makeStory() { + switch (playerPath) { + case DEFAULT_PATH: + if (playerMoney > 200.0 && !showCoursesTab && !pq.containsType(NEWS, 0)) { // Basics of programming + addTimer(event(10.0, NEWS, 0)); + newsShowed[0] = true; + } + else if (playerMoney > 300.0 && !shitCodeDetected && !shitLettersSent[0] && coursesFinished[1]) { + addTimer(event(9.0, SPECIAL_LETTER, LETTER_SHITCODE_1)); + shitLettersSent[0] = true; + } + else if (playerMoney > 400.0 && !newsShowed[2] && coursesFinished[1] && !pq.containsType(NEWS, 2)) { // Frappy Perd + addTimer(event(9.0, NEWS, 2)); + newsShowed[2] = true; + } + else if (playerMoney > 500 && !sentBotsmannLetter && coursesFinished[1]) { // Letter from Botsmann + addTimer(event(17.0, SPECIAL_LETTER, LETTER_BOTSMANN)); + sentBotsmannLetter = true; + } + else if (playerMoney > 600.0 && !shitCodeDetected && !shitLettersSent[1] && coursesFinished[1] && !pq.containsType(SPECIAL_LETTER, LETTER_SHITCODE_1)) { + addTimer(event(13.0, SPECIAL_LETTER, LETTER_SHITCODE_2)); + shitLettersSent[1] = true; + } + else if (playerMoney > 800.0 && sentBotsmannLetter && !unnamedStudioLettersSent[0] && coursesFinished[3] && astraLetterSent && !pq.containsType(SPECIAL_LETTER, LETTER_ASTRA)) { // Startup + addTimer(event(15.0, SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_1)); + unnamedStudioLettersSent[0] = true; + } + else if (playerMoney > 1000.0 && !shitCodeDetected && !shitLettersSent[2] && coursesFinished[1] && !pq.containsType(SPECIAL_LETTER, LETTER_SHITCODE_2)) { // Send 3 letters with checking for a shit code + addTimer(event(14.0, SPECIAL_LETTER, LETTER_SHITCODE_3)); + shitLettersSent[2] = true; + } + else if (getAvailableCoursesCount() == 0 && playerMoney > 2000 && sentBotsmannLetter + && unnamedStudioLettersSent[0] && !finalCardUnlocked[0] && !pq.containsType(SPECIAL_LETTER, LETTER_BORING_DEFAULT_PATH)) { + addTimer(event(10.0, SPECIAL_LETTER, LETTER_BORING_DEFAULT_PATH)); + } + break; + case WORK_PATH: + if (playerSalary == 1200 && noPopularity && !knowledgeLetterSent && unnamedStudioLettersSent[0] && controlFreelanceAttempts && playerFreelanceAttempts <= 5) { + addTimer(event(5.0, SPECIAL_LETTER, LETTER_TEST_OF_KNOWLEDGE)); + knowledgeLetterSent = true; + } + else if (playerMoney > 500.0 && !newsShowed[2] && !pq.containsType(NEWS, 2)) { // Frappy Perd + addTimer(event(7.0, NEWS, 2)); + newsShowed[2] = true; + } + else if (playerMoney > 600.0 && !unnamedStudioLettersSent[0] && coursesFinished[3]) { // Startup + addTimer(event(14.0, SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_1)); + unnamedStudioLettersSent[0] = true; + } + break; + case STARTUP_PATH: + if (unnamedStudioLettersSent[1] && !unnamedStudioLettersSent[2] && coursesFinished[4]) { + addTimer(event(15.0, SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_3)); + unnamedStudioLettersSent[2] = true; + } + else if (playerMoney > 600.0 && !shitCodeDetected && !shitLettersSent[1] && coursesFinished[1] && !pq.containsType(SPECIAL_LETTER, LETTER_SHITCODE_1)) { + addTimer(event(14.0, SPECIAL_LETTER, LETTER_SHITCODE_2)); + shitLettersSent[1] = true; + } + else if (playerMoney > 1000.0 && !shitCodeDetected && !shitLettersSent[2] && coursesFinished[1] && !pq.containsType(SPECIAL_LETTER, LETTER_SHITCODE_2)) { // Send 3 letters with checking for a shit code + addTimer(event(19.0, SPECIAL_LETTER, LETTER_SHITCODE_3)); + shitLettersSent[2] = true; + } + break; + } + // News about JAVA programmers + if (playerMoney > 1500.0 && !newsShowed[1] && shitLettersSent[0] && shitLettersSent[1] + && shitLettersSent[2] && !shitCodeDetected && coursesFinished[1] && !coursesUnlocked[2]) { // JAVA programmers + addTimer(event(5.0, NEWS, 1)); + newsShowed[1] = true; + } + if (!returnTo21HintShowed && finishedCoursesCount == 12 && finalCardsUnlocked == 5 && gameTime > 21.0 && allAchievesShowed && !pq.containsType(SPECIAL_LETTER, LETTER_RETURN_TO_DAY_21)) { + addTimer(event(2.0, SPECIAL_LETTER, LETTER_RETURN_TO_DAY_21)); + } + } + +// Desktop is your main screen +string getDesktop(int &lines) { + string s = "\n\n"; + // Information about courses + if (!pq.hasCourses()) { + s += noCurrentCurses; + } + else { + // Check courses in pq + s += " "; + s += coursesTitle; + s += ":\n"; + for(int i = 0; i< pq.n(); i++) { + event* e = pq.get(i); + if (e->type == COURSE) { + s += " "; + if (e->idata >= 0 && e->idata <= 7) { + s += courses[e->idata]; + s += " "; + int percent = (int)(100 * (learningTime[e->idata] - e->time) / learningTime[e->idata]); + for (int i = 0; i < 20; i++) { + if (i > 2*percent/10) + s += " "; + else + s += pseudoEqual; + } + s += txt(" %d%\n", percent); + } + else if (e->idata >= 'a' && e->idata <= 'e') { + s += advProgCourses[e->idata - 'a']; + s += " "; + int percent = (int)(100 * (advProgLearningTime[e->idata-'a'] - e->time) / advProgLearningTime[e->idata - 'a']); + for (int i = 0; i < 20; i++) { + if (i > 2*percent/10) + s+=" "; + else + s+=pseudoEqual; + } + s += txt(" %d%\n", percent); + } + } + } + } + + for(unsigned int i = 0; i < s.length(); i++) + if (s[i] == '\n') + lines++; + + return s; + } + +void mainGameCycle() { + float hintBegins = 0.0; //days + unsigned short hintIndex = 0; + + playerMoney = 100; + dt = 0.5; + int update = 0; + + // Add initial letter + initSendingMessage(); + + string status = playerStatus; + status += helpDesker; + int currentPath = playerPath; + + playerStartedPlaying = time(NULL); + string buffer, oldStatusLine; + while (1) { + // We update screen 10 times a second + if (update % 10 == 0) + increaseMoney(-dt * 1.0); // Money needs per day + + int lines = 0; + + string s = getDesktop(lines); + for (int i = 0; i < 11-lines; i++) + s += "\n"; + s += " "; + s += hintOfTheMonth; + if (gameTime > hintBegins + 30) { + hintBegins = gameTime; + hintIndex++; + if (hintIndex >= hintsCount) + hintIndex = 0; + } + // This could happen when jumping in the past + else if (hintBegins > gameTime) + hintBegins = gameTime; + + s += " "; + s += hints[hintIndex]; + + if (playerPath != currentPath) { + currentPath = playerPath; + status=playerStatus; + if (playerPath == DEFAULT_PATH) status += helpDesker; + else if (playerPath == WORK_PATH) status += worker; + else if (playerPath == STARTUP_PATH) status += startupper; + } + // redraw screen only if necessary + string newStatusLine = getStatusLine(); + if (!(s == buffer) || !(oldStatusLine == newStatusLine)) + drawWindow(s, status.c_str(), newStatusLine, getBottomLine()); + buffer = s; + oldStatusLine = newStatusLine; + if (update % 10 == 0) { + checkAchieves(); + if (isGameOver()) + break; + + if (playerSalary != 0 && gameTime-playerSalaryFirstDay >= 30) { + increaseMoney(playerSalary); + changeSalaryFirstDay(playerSalaryFirstDay+30); + } + makeStory(); + checkPq(); + } + + // Some key was pressed + if (kbhit()) { + char k = getch(); + #ifdef _KOS32 + // We have to make a second call for special keys in KolibriOS + if (k == 0) + k = getch(); + #endif + if (keyPressed(k)) + return; + // Force redraw desktop + buffer = ""; + oldStatusLine = ""; + } + + if (update % 10 == 0) + gameTime += dt; + + int delayTime = 10; + #ifdef _KOS32 + __menuet__delay100(delayTime); + #else + usleep(delayTime*10000); + #endif + update++; + } + } + +// Jump in the past to a certain time +void undo(long double toTime) { + if (toTime < 0 ) + return; + + if (playerMoney < 100) { + drawModalWindow(need100ForUndo, errorMsg); + wait(); + return; + } + // Jump cost: $100 + increaseMoney(-100); + drawModalWindow(prepareForTimeJump); + wait(); + + while(!pq.empty()) + pq.delMin(); + + // Player Stats + playerTimeHops++; + playerSpentRealDays += (gameTime - playerPrevUndo); + playerPrevUndo = toTime; + + vector lateEvents; + history.prepareForUndo(); + while (!history.empty() && history.getMax().time > toTime) { + event e = history.getMax(); + switch (e.type) { + case INCREASEPOPULARITY: + increaseKarma(-e.idata, false); + break; + case NOPOPULARITY: + noPopularity = false; + break; + case CHANGEPATH: + playerPath = e.idata; // Previous path + break; + case CHANGESALARY: + playerSalary = e.idata; + break; + case CHANGESALARYFIRSTDAY: + playerSalaryFirstDay = e.idata; + break; + // Letters' time is time of sending a letter + time to end timer = time to get letter in the future + case SPECIAL_LETTER: + switch(e.idata) { + case LETTER_BOTSMANN: + sentBotsmannLetter = false; + astraLetterSent = false; + break; + case LETTER_ASTRA: + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_BOTSMANN, toTime)) + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_ASTRA)); + break; + case LETTER_UNNAMEDSTUDIO_2: + // Unnamed letter 1 -> AngryBoss -> Unnamed letter 2 + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_ANGRYBOSS_1, e.time)) { + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_ANGRYBOSS_1, toTime)) + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_2)); + } + // Unnamed letter 1 -> Unnamed letter 2 + else { + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_1, toTime)) + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_2)); + } + break; + case NO_POPULARITY_HINT: + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_ANGRYBOSS_1, toTime)) + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, NO_POPULARITY_HINT)); + break; + case LETTER_ANGRYBOSS_1: + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_1, toTime)) { + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_ANGRYBOSS_1)); + controlFreelanceAttempts = false; + } + break; + case LETTER_UNNAMEDSTUDIO_1: + unnamedStudioLettersSent[0] = false; + break; + case LETTER_WEBMASTER_CHECK_UNNAMEDSTUDIO: + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_4, toTime)) + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_WEBMASTER_CHECK_UNNAMEDSTUDIO)); + break; + case LETTER_UNNAMEDSTUDIO_4: + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_3, toTime)) + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_4)); + break; + case LETTER_UNNAMEDSTUDIO_3: + unnamedStudioLettersSent[2] = false; + break; + case LETTER_UNNAMEDSTUDIO_5: + if (history.containsTypeBefore(NEWS, 3, toTime) && !pq.containsType(SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_5)) + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_5)); + break; + case LETTER_FINALPATH_DEF: + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_BORING_DEFAULT_PATH, toTime)) + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_FINALPATH_DEF)); + break; + case LETTER_FINALPATH_STARTUP: + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_5, toTime) && !pq.containsType(SPECIAL_LETTER, LETTER_FINALPATH_STARTUP)) + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_FINALPATH_STARTUP)); + break; + case LETTER_FINALPATH_WORK: + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_PERSISTENT_AND_PATIENT, toTime)) + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_FINALPATH_WORK)); + break; + case LETTER_ANGRYBOSS_2: + if (e.time - toTime <= 1) + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_ANGRYBOSS_2)); + break; + case LETTER_PERSISTENT_AND_PATIENT: + if (history.containsTypeBefore(SPECIAL_LETTER,LETTER_BORING_WORK, toTime)) + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_PERSISTENT_AND_PATIENT)); + break; + case LETTER_BORING_WORK: + if (e.time - toTime <= 40) + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_BORING_WORK)); + break; + case LETTER_TEST_OF_KNOWLEDGE: + knowledgeLetterSent = false; + playerFreelanceAttempts = 0; + klowledgeCorrectAnswers = 0; + klowledgeUncorrectAnswers = 0; + break; + case LETTER_SHITCODE_1: + shitCodeDetected = false; + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_SHITCODE_1)); + shitLettersSent[1] = false; + shitLettersSent[2] = false; + break; + case LETTER_SHITCODE_2: + shitCodeDetected = false; + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_SHITCODE_2)); + shitLettersSent[2] = false; + break; + case LETTER_SHITCODE_3: + shitCodeDetected = false; + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_SHITCODE_3)); + break; + case LETTER_BORING_DEFAULT_PATH: + lateEvents.push_back(event(e.time - toTime, SPECIAL_LETTER, LETTER_BORING_DEFAULT_PATH)); + break; + } + break; + case NEWS: + // News about JAVA programmers + newsShowed[e.idata] = false; + if (e.idata == 3) { + // Unnamed letter 3 -> Unnamed letter 4 -> Need webmaster -> news about Java + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_WEBMASTER_CHECK_UNNAMEDSTUDIO, e.time)) { + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_WEBMASTER_CHECK_UNNAMEDSTUDIO, toTime)) + lateEvents.push_back(event(e.time - toTime, NEWS, 3)); + } + // Unnamed letter 3 -> Unnamed letter 4 -> news about Java + else { + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_UNNAMEDSTUDIO_4, toTime)) + lateEvents.push_back(event(e.time - toTime, NEWS, 3)); + } + } + break; + case COURSE: { + // e.time - course finished + // e.idata - course number + long double courseStarted = 0; + bool courseFinished = false; + if (e.idata >='a' && e.idata <= 'e') { + courseStarted = e.time - advProgLearningTime[e.idata-'a']; + courseFinished = advProgCoursesFinished[e.idata-'a']; + } + else if(e.idata >= 0 && e.idata < (int)coursesNumber) { + courseStarted = e.time - learningTime[e.idata]; + courseFinished = coursesFinished[e.idata]; + } + + if (!courseFinished && toTime >= courseStarted) + // Player is currently taking a course + lateEvents.push_back(event(e.time - toTime, COURSE, e.idata)); + } + break; + case MESSAGE: + break; + } + history.delMax(); + } + unreadMessages = 0; + gameTime = toTime; + timeHops++; + + for (unsigned short i = 0; i< lateEvents.size(); i++) + addTimer(lateEvents[i]); + + + // Messages would not arive without this: + if (!pq.containsType(MESSAGE)) + initSendingMessage(); + + // Undo shouldn't stop during the knowledge check + if (history.containsTypeBefore(SPECIAL_LETTER, LETTER_TEST_OF_KNOWLEDGE, toTime) + && !history.containsTypeBefore(SPECIAL_LETTER, LETTER_BORING_WORK, toTime)) { + double newTime = toTime-10; + for (int i = 0; i < history.n(); i++) { + event* e = history.get(i); + if (e->type == SPECIAL_LETTER && e->idata == LETTER_TEST_OF_KNOWLEDGE) { + newTime = e->time - 10; + break; + } + } + drawModalWindow(cantStopDuringKnowledgeCheck, errorMsg); + wait(); + undo(newTime); + } + } + +int chooseCourse() { + double p[coursesNumber]; + long double sum = 0.0; + for (unsigned int i = 0; i < coursesNumber; i++) { + if (coursesFinished[i]) + p[i] = probability[i]; + else + p[i] = 0.0; + sum += p[i]; + } + if (sum <= 0.001) + return 0; + int N = (int) (sum * 100); + int r = rand() % N; + + int n1 = (p[0] / sum) * N; + int n2 = (p[1] / sum) * N; + int n3 = (p[2] / sum) * N; + int n4 = (p[3] / sum) * N; + int n5 = (p[4] / sum) * N; + + if (r >= 0 && r < n1) + return 0; + else if (coursesFinished[1] && r >= n1 && r < n1+n2) + return 1; + else if (coursesFinished[2] && r >= n1+n2 && r < n1+n2+n3) + return 2; + else if (coursesFinished[3] && r >= n1+n2+n3 && r < n1+n2+n3+n4) + return 3; + else if (coursesFinished[4] && r >= n1+n2+n3+n4 && r < n1+n2+n3+n4+n5) + return 4; + else if (coursesFinished[5] && r >= n1+n2+n3+n4+n5 && r <= N) + return 5; + + return 0; + } diff --git a/programs/games/21days/interface.cpp b/programs/games/21days/interface.cpp new file mode 100755 index 0000000000..ae32bc58de --- /dev/null +++ b/programs/games/21days/interface.cpp @@ -0,0 +1,345 @@ +/****************************************************************** +* 21 days: a game for programmers +* Copyright (C) 2014 Maxim Grishin +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301, USA. +*******************************************************************/ + +#include "sys.h" + +#ifndef _KOS32 +#include // printf() +#include +#define printf2 printf +#endif + +#include // strlen +#include +using std::string; + +char getAnswer(char a1, char a2) { + while(1) { + if (kbhit()) { + char ch = getch(); + #ifdef _KOS32 + if (ch == 0) + ch = getch(); + #endif + if (ch == a1 || ch == a2) + return ch; + } + } + } + +char getAnswer(char a1, char a2, char a3) { + while(1) { + if (kbhit()) { + char ch = getch(); + #ifdef _KOS32 + if (ch == 0) + ch = getch(); + #endif + if (ch == a1 || ch == a2 || ch == a3) + return ch; + } + } + } + +char getAnswer(char a1, char a2, char a3, char a4) { + while(1) { + if (kbhit()) { + char ch = getch(); + #ifdef _KOS32 + if (ch == 0) + ch = getch(); + #endif + if (ch == a1 || ch == a2 || ch == a3 || ch == a4) + return ch; + } + } + } + +void wait(char a = ENTER_KEY, char b = ENTER_KEY) { + getAnswer(a, b); + } + +char getKey() { +#ifdef _KOS32 + while(1) { + if (kbhit()) { + char ch = getch(); + if (ch == 0) + ch = getch(); + return ch; + } + } +#else + return getch(); +#endif + } + +void blankline(int line, int width) { + printf2(" "); + consoleGoto(line, width); + printf2("\n"); + } + +void drawHBorder(int line, int left, int right, char l = '', + char c = '', char r = '', char e = '\n') { + consoleGoto(line, left); + printf2("%c", l); + for (int i = 0; i< right - left; i++) + printf2("%c", c); + consoleGoto(line, right); + printf2("%c%c", r, e); + } + +void drawStringLine(int line, int left, int right, const char* str, + int pos = -1, char border = '', bool shadow = false) { + consoleGoto(line, left); + if (pos == -1) + printf2("%c %s", border, str); + else { + printf2("%c ", border); + consoleGoto(line, pos); + printf2("%s", str); + } + consoleGoto(line, right); + if (shadow) + printf2("%c", border); + else + printf2("%c\n", border); + } + +void drawModalWindow(const char* content, const char* title, const char* buttons) { + cls(); + int winWidth, winHeight; + getWinWH(winWidth, winHeight); + int lines = winHeight/3; + int msgWidth = strlen(content)+2; + + if (msgWidth >= winWidth-4) + msgWidth = winWidth-5; + int msgLeft = winWidth/2 - msgWidth/2; + int msgRight = winWidth/2 + msgWidth/2+1; + if (msgWidth%2!=0) + msgRight++; + + int titleWidth = 0; + if (title != 0) + titleWidth = strlen(title)+2; + + drawHBorder(lines, msgLeft, msgRight,'','', ''); + + // title + if (title != 0) { + consoleGoto(lines, msgLeft+msgWidth/2-titleWidth/2); + printf2(" %s ", title); + } + + lines++; + drawHBorder(lines, msgLeft, msgRight, '',' ','',''); + lines++; + + //======Splitting content into pieces========================= + int maxTextWidth = msgRight-msgLeft; // 2 borders + 2 spaces + int start = 0; + int len = strlen(content); + + for (int i = 0; i < len; i++) { + if (content[i] == '\n') { + string tmp = content; + string t1 = tmp.substr(start, i-start+1); + drawStringLine(lines, msgLeft, msgRight, t1.c_str(), -1, '', true); + + start = i+1; + lines++; + } + else if (i - start >= maxTextWidth-3) { + string tmp = content; + string t1 = tmp.substr(start, i-start); + t1+="\n"; + drawStringLine(lines, msgLeft, msgRight, t1.c_str(), -1, '', true); + start = i; + lines++; + } + } + if (start != len) { + string tmp = content; + string t1 = tmp.substr(start, len-start); + drawStringLine(lines, msgLeft, msgRight, t1.c_str(), -1, '', true); + lines++; + } + //=============================== + drawHBorder(lines, msgLeft, msgRight, '',' ','',''); + lines++; + + consoleGoto(lines, msgLeft); + printf2(""); + if (!buttons) { + for (int q = 0; q< msgWidth/2-4;q++) + printf2(" "); + printf2("[Enter]"); + for (int i = 0; i< msgWidth/2-2; i++) + printf2(" "); + } + else { + int buttonsLen = strlen(buttons); + for (int i = 0; i < msgWidth/2-buttonsLen/2; i++) + printf2(" "); + printf2("%s", buttons); + } + consoleGoto(lines, msgRight); + printf2(""); + lines++; + + drawHBorder(lines, msgLeft, msgRight,'', '', '',''); + lines++; + + consoleGoto(lines, msgLeft+1); + for (int i = 0; i< msgWidth+2; i++) + printf2(""); + printf2(" "); + } + +void drawWindow(string content, const char* title, string topline , string bottomline, bool usePagesForLongText = false) { + cls(); + int winWidth, winHeight; + getWinWH(winWidth, winHeight); + +#ifdef _WIN32 + int deltaX = 0; +#else + int deltaX = 1; +#endif + + // Total lines +#ifdef _WIN32 + int lines = 0; +#else + int lines = 1; +#endif + + // Top + drawHBorder(lines, deltaX, winWidth); + lines++; + + if (topline != "") { + drawStringLine(lines, deltaX, winWidth, topline.c_str()); + lines++; + } + // Title + if (title != 0) { + if (topline != "") { + blankline(lines, winWidth); + lines++; + } + drawStringLine(lines, deltaX, winWidth, title, (int)(winWidth/2.0-strlen(title)/2.0)); + lines++; + blankline(lines, winWidth); + lines++; + } + + //==========Splitting content into pieces===================== + int maxTextWidth = winWidth-4; // 2 borders + 2 spaces + int start = 0; + unsigned int i = 0; + // Let's split content into pieces if it too long or doesn't fit the screen + while (i < content.length()) { + if (usePagesForLongText && lines > winHeight-3) { + consoleGoto(lines, 0); + blankline(lines, winWidth); + lines++; + drawStringLine(lines, deltaX, winWidth, " [Enter] த..."); + // Bottom line + drawHBorder(winHeight, deltaX, winWidth,'','',''); + wait(); + // Print next page + cls(); + lines = 0; + // Top line + drawHBorder(lines, deltaX, winWidth); + #ifdef _WIN32 + lines = 1; + #else + lines = 2; + #endif + } + // Use tag to place text in the center + if (content[i] == '<') { + // Checking for the tag. tag should be prepended with '\n' + if (i+2 < content.length()) { + if (content[i+1] == 'c' && content[i+2] == '>') { + // Tag found. Looking for the end of a string + int cLineEnd = content.length()-1; + for (unsigned int j = i; j < content.length(); j++) + if (content[j] == '\n') { + cLineEnd = j; + break; + } + int cLineWidth = cLineEnd - i-1; + drawStringLine(lines, deltaX, winWidth, + content.substr(i+3, cLineWidth-2).c_str(), winWidth/2-cLineWidth/2); + i = cLineEnd+1; + start = i; + lines++; + continue; + } + } + } + else if (content[i] == '\n') { + consoleGoto(lines, 0); + string t1 = content.substr(start, i-start+1); + drawStringLine(lines, deltaX, winWidth, t1.c_str()); + start = i+1; + lines++; + } + else if ((int)i - start >= maxTextWidth-1) { + consoleGoto(lines, 0); + string t1 = content.substr(start, i-start); + t1+="\n"; + drawStringLine(lines, deltaX, winWidth, t1.c_str()); + start = i; + lines++; + } + i++; + } + if (start <= (int)content.length()) { + consoleGoto(lines, 0); + string t1 = content.substr(start, content.length()-start); + drawStringLine(lines, deltaX, winWidth, t1.c_str()); + lines++; + } + //=============================== + + for (int i = lines; i< winHeight; i++) { + blankline(lines, winWidth); + lines++; + } + + if (!bottomline.empty()) { + ///Fix for long bottomline + if ((int)bottomline.length() >= winWidth) { + drawStringLine(winHeight-2, deltaX, winWidth, bottomline.substr(0, winWidth-4).c_str()); + drawStringLine(winHeight-1, deltaX, winWidth, bottomline.substr(winWidth-4).c_str()); + } + else { + drawStringLine(winHeight-1, deltaX, winWidth, bottomline.c_str()); + } + } + // Bottom + drawHBorder(winHeight, deltaX, winWidth,'','',''); + } \ No newline at end of file diff --git a/programs/games/21days/interface.h b/programs/games/21days/interface.h new file mode 100755 index 0000000000..ba691166be --- /dev/null +++ b/programs/games/21days/interface.h @@ -0,0 +1,53 @@ +/****************************************************************** +* 21 days: a game for programmers +* Copyright (C) 2014 Maxim Grishin +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301, USA. +*******************************************************************/ + +#ifndef H_INTERFACE +#define H_INTERFACE +#include + +char getAnswer(char a1, char a2); +char getAnswer(char a1, char a2, char a3); +char getAnswer(char a1, char a2, char a3, char a4); +char getKey(); +void clearBuffer(); + +#ifdef _KOS32 +using std::string; +string itos(int n); +string txt(string s, int d); +string txt(string s, string s2); +string txt(string s, string s2, string s3); + +string txt(string s, char c); +string txt(string s, char ch, string s2); +string txt(string s, char ch, string s2, char ch2); + +string txt(string s, int d1, int d2); +string txt(string s, int d1, int d2, int d3); +string txt(string s, int d1, int d2, int d3, int d4); + +#else +std::string txt(const char* s, ...); +#endif + +void wait(char a = ENTER_KEY, char b = ENTER_KEY); +void drawWindow(std::string content, const char* title = 0, std::string topline = "", std::string bottomline = "", bool usePagesForLongText = false); +void drawModalWindow(const char* content , const char* title = 0, const char* buttons = 0); +#endif diff --git a/programs/games/21days/kos_vector.h b/programs/games/21days/kos_vector.h new file mode 100755 index 0000000000..1e5d0e1dbb --- /dev/null +++ b/programs/games/21days/kos_vector.h @@ -0,0 +1,91 @@ +/****************************************************************** +* 21 days: a game for programmers +* Copyright (C) 2014 Maxim Grishin +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301, USA. +* +* +* This file contains a part of file "/include/vector" from menuetlibc +* adapted to the developer's needs. +* Changes: +* 1. "*__cdecl" replaced with "* __attribute__((cdecl))" in order +* to compile a C++ project. +* 2. Added front() methods with the following code: +* T& front() {return data[0];} +* 3. Code reformatted +* +********************************************************************/ + +#ifndef KOS_VECTOR_H +#define KOS_VECTOR_H + +extern void * __attribute__((cdecl)) operator new(size_t); +inline void * __attribute__((cdecl)) operator new(size_t, void *_P) { + return (_P); + } + +template class vector21 { + unsigned length; + unsigned allocated; + T* data; + public: + typedef unsigned size_type; + typedef T* iterator; + vector21():length(0),allocated(0),data(NULL) {} + ~vector21() {for (unsigned i=length;i--;)data[i].~T();free(data);} + unsigned size() const {return length;} + void clear() {length=0;} + T& operator[](unsigned pos) {return data[pos];} + T* begin() {return data;} + T* end() {return data+length;} + void push_back(const T& x) { + if (length==allocated){ + allocated+=16; + data=(T*)realloc(data,allocated*sizeof(T)); + } + new (data+length++) T(x); + } + bool empty() const {return length==0;} + void pop_back() {data[--length].~T();} + T& back() {return data[length-1];} + T& front() {return data[0];} + iterator erase(iterator it) { + T* a=it; + while (++a != data+length) { + a[-1] = *a; + } + length--; + return it; + } + /*iterator*/T* insert(iterator where, const T& what = T()) { + int z=where-data; + if (length==allocated) { + allocated+=16; + data=(T*)realloc(data,allocated*sizeof(T)); + } + T* a=data+length; + T* b=data+z; + length++; + while (a != b) { + *a = a[-1]; + --a; + } + *a = what; + return /*iterator*/a; + } + }; + +#endif diff --git a/programs/games/21days/main.cpp b/programs/games/21days/main.cpp new file mode 100755 index 0000000000..9234fda74f --- /dev/null +++ b/programs/games/21days/main.cpp @@ -0,0 +1,45 @@ +/****************************************************************** +* 21 days: a game for programmers +* Copyright (C) 2014 Maxim Grishin +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301, USA. +*******************************************************************/ + +#include "sys.h" + +#ifndef _KOS32 +#include // printf() +#define printf2 printf +#endif + +#include // srand() +#include // time() + +int showMainMenu(); + +int main() { + initConsole(); + hideCursor(); + srand(time(NULL)); + showMainMenu(); + showCursor(); +#ifdef _KOS32 + // Close console window and kill the main thread + con_exit(true); + kol_exit(); +#endif + return 0; + } diff --git a/programs/games/21days/pq.h b/programs/games/21days/pq.h new file mode 100755 index 0000000000..3433a5c79f --- /dev/null +++ b/programs/games/21days/pq.h @@ -0,0 +1,204 @@ +/****************************************************************** +* 21 days: a game for programmers +* Copyright (C) 2014 Maxim Grishin +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301, USA. +*******************************************************************/ + +#ifndef H_PQ +#define H_PQ + +#define LETTER_RETURN_TO_DAY_21 100001 +#define LETTER_WEBMASTER_CHECK_UNNAMEDSTUDIO 100002 +#define LETTER_BORING_WORK 100003 +#define LETTER_PERSISTENT_AND_PATIENT 100004 +#define LETTER_BORING_DEFAULT_PATH 100005 +#define LETTER_TEST_OF_KNOWLEDGE 100006 +#define LETTER_KNOWLEDGE_QUESTION 100007 + +#ifdef _KOS32 + #include "kos_vector.h" + #define vector vector21 +#else + #include + #include // std::sort + #define printf2 printf + using std::vector; +#endif + +enum Letter { LETTER_SHITCODE_1 = 0, LETTER_SHITCODE_2, LETTER_SHITCODE_3, + LETTER_BOTSMANN, LETTER_ASTRA, LETTER_UNNAMEDSTUDIO_1, LETTER_UNNAMEDSTUDIO_2, + LETTER_UNNAMEDSTUDIO_3, LETTER_UNNAMEDSTUDIO_4, LETTER_UNNAMEDSTUDIO_5, + LETTER_ANGRYBOSS_1, LETTER_ANGRYBOSS_2, NO_POPULARITY_HINT, LETTER_FINALPATH_DEF, + LETTER_FINALPATH_STARTUP, LETTER_FINALPATH_WORK, LETTER_FINALPATH_NOMONEY, LETTER_FINALPATH_NOPOPULARITY}; +enum EventType { COURSE = 1000, SPECIAL_LETTER, MESSAGE, NEWS, INCREASEPOPULARITY, + CHANGEPATH, CHANGESALARY, CHANGESALARYFIRSTDAY, NOPOPULARITY}; + +class event { + public: + double time; + EventType type; + int idata; + event() : time(0.0), idata(-1) {} + event(double t,EventType ty, int data = -1) : time(t), type(ty), idata(data) {} + bool operator>(const event a) const { + return this->time > a.time; + } + bool operator<(const event ev) const { + return time < ev.time; + } + }; + +#ifdef _KOS32 +static void exch (event* A, event* B) { + event t = *A; + *A = *B; + *B = t; + } +#endif + +static void sort21(vector* v, bool desc = false) { +#ifdef _KOS32 + // Sorry for the bubble sort + for (unsigned int i = 0; i < v->size()-1; i++) + for (unsigned int j = 0; j < v->size()-i-1; j++) { + if (desc && (*v)[j] < (*v)[j+1]) + exch(&((*v)[j]), &(*v)[j+1]); + else if (!desc && (*v)[j] > (*v)[j+1]) + exch(&(*v)[j], &(*v)[j+1]); + } +#else + if (desc) + std::sort(v->begin(), v->end(), std::greater()); + else + std::sort(v->begin(), v->end()); +#endif + } + +class PQ3 { + private: + vector v; + bool sorted; + public: + void sort() { + sort21(&v, true); + sorted = true; + } + PQ3() : sorted(false) {} + int n() { + return v.size(); + } + bool empty() const { + return v.empty(); + } + void insert(event item) { + v.push_back(item); + sorted = false; + } + event delMin() { + if (empty()) + return event(); + if (!sorted) + sort(); + event e = v.back(); + v.pop_back(); + return e; + } + event* getMin() { + if (empty()) + return 0; + if (!sorted) + sort(); + return &v.back(); + } + event* get(int i) { + if (empty() || i >= (int)v.size()) + return 0; + if (!sorted) + sort(); + return &v[i]; + } + bool hasCourse(int c) { + for(unsigned int i = 0; i < v.size(); i++) + if (v[i].type == COURSE && v[i].idata == c) + return true; + return false; + } + bool hasCourses() { + for(unsigned int i = 0; i < v.size(); i++) + if (v[i].type == COURSE) + return true; + return false; + } + bool containsType(int et) { + for (int i = v.size()-1; i >= 0; i--) + if (v[i].type == et) + return true; + return false; + } + bool containsType(int et, int data) { + for (int i = v.size()-1; i >= 0; i--) + if (v[i].type == et && v[i].idata == data) + return true; + return false; + } + }; + + +class Undo2 { +private: + vector v; +public: + Undo2() {} + int n() { + return v.size(); + } + bool empty() const { + return v.empty(); + } + void insert(event item) { + if (item.type == MESSAGE) + return; + v.push_back(item); + } + event delMax() { + if (empty()) + return event(); + event e = v.back(); + v.pop_back(); + return e; + } + event getMax() { + if (empty()) + return event(); + return v.back(); + } + event* get(int i) { + if (empty() || i >= (int)v.size()) + return 0; + return &v[i]; + } + void prepareForUndo() { + sort21(&v, false); + } + bool containsTypeBefore(EventType et, int data, long double t) { + for (unsigned int i = 0; i < v.size(); i++) + if (v[i].type == et && v[i].idata == data && v[i].time <= t) + return true; + return false; + } + }; +#endif diff --git a/programs/games/21days/strings.h b/programs/games/21days/strings.h new file mode 100755 index 0000000000..58c9fe3f58 --- /dev/null +++ b/programs/games/21days/strings.h @@ -0,0 +1,540 @@ +/****************************************************************** +* 21 days: a game for programmers +* Copyright (C) 2014 Maxim Grishin +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301, USA. +*******************************************************************/ + +#ifndef H_STRINGS +#define H_STRINGS + +/************************************************************************* +* Messages from friends +*************************************************************************/ + +const unsigned int levelYesAnswerNumber = 10; +const char* levelYesAnswer[levelYesAnswerNumber] = { + "륧!", + ", ᥩ 㤠񭭮 ᤥ.", + "뢠 .", + " .", + " 祭쪨 ? !", + "筮!", + " ⥡ -  ६", + " ࠧ ᢮.", + " ᤥ.", + " ஡." + }; + +const unsigned int levelNoAnswerNumber = 10; +const char* levelNoAnswer[levelNoAnswerNumber] = { + ", ᥣ ᬮ.", + ", .", + " ࠡ 뫠, - १ .", + "- 㣮 ࠧ.", + " । .", + " ⠪ 㬥.", + " 訡 ஬ :D", + " ?", + " , .", + "." + }; + + +const unsigned int level1TasksNumber = 6; +const char* level1Task [level1TasksNumber] = { + "ਢ! ᬮ ? , ࠡ⠥ %s.", + " ⥡ . %s 嫨, ⠭ ?", + "! ⠫! ࠡ⠥ %s. ?", + "蠩, 㣠 ࠡ⠥ %s, , . ᢮?", + "࠭, ᪠ %s, ९஡ - 祣 .", + "! ஫, ⥯ %s ࠡ⠥. 祭쪨." + }; + +const unsigned int level1TaskWordNumber = 11; +const char* level1TaskWords[level1TaskWordNumber] = { + "㤨", + " ⠭", + "㧥", + "", + "⪨ ", + "", + "", + "", + "", + " 譨", + "஥" + }; + +const unsigned short programmingTaskNumber = 5; +const char* programmingTasks[programmingTaskNumber] = { + "ਢ! Pascal, , . ?", + " 㭨 ਫ ﬨ Basic, ᤥ?", + "㦭 ⢮ , ᤠ Turbo Pascal, , . 砩!", + " ࠡ ... , ᬮ५, ⠬ QBASIC, 㬥. ᮢ ?", + "蠫, Pascal? ஥⮢ ᠭ, ⢥⢥ 祫 . - ᮢ." + }; + +const unsigned short webProgrammingTaskNumber = 4; +const char* webProgrammingTasks[webProgrammingTaskNumber] = { + "ਢ, ᠩ⠬-⪠ ? .", + "蠩, 襩 㦥 ᠩ 񢪥. ࠭ ଠ樥 . ⥡, ?", + " 襩 . 襪 㦭, ⥡ ४. , ᢮.", + ", 让 ᠩ-⠫ 襬, 筮 㦥 . ?", + }; + +const unsigned short systemProgrammingTaskNumber = 3; +const char* systemProgrammingTask[systemProgrammingTaskNumber] = { + "蠫 Arduino? ᬥ 襬, .", + " ᪠, ᬥ ? ਫ 饬, ࠡ ப஫ࠬ, 㬠, ⥡ ࠢ.", + " KolibriOS , . ?" + }; + +const unsigned short adminTasksNumber = 4; +const char* adminTasks[adminTasksNumber] = { + "ࢥ , ࠨ . ⨬ ! १.", + " Apache + nginx ᬮ ⠢ ந? 訢, 祬 :).", + " , 設 ਢ Windows Server 2003, , . 砩!", + ", ய KDE2 FreeBSD?" + }; + +const unsigned short mobileTaskNumber = 3; +const char* mobileTasks[mobileTaskNumber] = { + " ࠧࠡ Swift த, ?", + "⨬ 쭮 ਫ Java, , ᥩ . 㬥?", + " C++ ⨢ ਫ Android , 쬥?" + }; + +/************************************************************************* +* Courses +*************************************************************************/ + +const unsigned int coursesNumber = 8; +const char* courses[coursesNumber] = { + "⢮", + " ணࠬ஢", + "த⮥ ணࠬ஢:", + "ࠡ⪠ ਫ", + "᭮ ", + " ᠩ⮢", + "⥬ ணࠬ஢", + "஢ ࢥ஢", + }; +bool coursesUnlocked[coursesNumber] = {1, 0, 0, 0, 0, 0, 0, 0}; +const unsigned short advancedProgrammingCourses = 5; +char* advProgCourses[advancedProgrammingCourses] = { + "C++", + "Java", + "Assembler", + "C#", + "Delphi" + }; + +bool coursesFinished[coursesNumber] = {1, 0, 0, 0, 0, 0, 0, 0}; +bool advProgCoursesFinished[advancedProgrammingCourses] = {0, 0, 0, 0, 0}; +unsigned int learningTime[coursesNumber] = {0, 10, 80, 30, 45, 35, 45, 50}; // in days +unsigned int advProgLearningTime[advancedProgrammingCourses] = { 10, 10, 15, 10, 10}; // in days +int learningCost[coursesNumber] = {0, 100, 125, 100, 125, 120, 130, 120}; +int advProgLearningCost[advancedProgrammingCourses] = {125, 120, 150, 123, 100}; + +unsigned short finishedCoursesCount = 1; + +/************************************************************************* +* Probability of getting a message from friend related to course 0, +* 1, 2, etc. (courses). Prob. of getting a simple work is higher +* than getting a hard one. +*************************************************************************/ +double probability[coursesNumber] = { 0.7, 0.5, 0.25, 0.6, 0.25, 0.4, 0.3, 0.4}; + +int taskReward[coursesNumber] = {2, 5, 10, 13, 19, 25, 30, 35}; +int taskCount[coursesNumber] = {level1TasksNumber, programmingTaskNumber, + programmingTaskNumber, mobileTaskNumber, mobileTaskNumber, + webProgrammingTaskNumber, systemProgrammingTaskNumber, adminTasksNumber}; + +/************************************************************************* +* News +*************************************************************************/ + +const unsigned short newsCount = 4; +const char* news[newsCount] = { + "ணࠬ஢ 稭 墠뢠 ! ॥ 筨 ணࠬ஢!\n", + " ଠ樨 hh.ru ᪮ Java - ணࠬ⮢\n", + "⭮! - ࠭᪮ ࠧࠡ稪 Frappy Perd ४ ਭ᫠ $50 000 ! ୮, ᥩ ᢮ .\n", + "筮, ᥩ 梥 -. । ᯥ譠 , ࠧ Unnamed Studio, ࢮ ⮯ . 㦥 䠭⮢ ,  室 㬠!\n" + }; +bool newsShowed[newsCount] = {0, 0, 0, 0}; + +/************************************************************************* +* Special letters +*************************************************************************/ + +const unsigned short specialLetterCount = 30; +const char* specialLetters[specialLetterCount] = { + "ਢ. ⮩ ஥ C++ Java, , ᤥ?", + " ⠪? ᮢᥬ ࠫ. ! - C++, Java.", + " 蠫, ணࠬ஢ Assembler ? 㯥᫮ ப஫ , . 쬥?", + " 뢠 믮 ࠡ⮩? ⨫⭨ Assembler , 祬 ! 㯨 Asm, .", + "ਢ! 㯨, 㦭 C# . ᠬ - 祭 ᫮ ஥. ?", + ", ᮢᥬ, 뢠, ணࠬ஢ 㬥. ன ᮢ -, .", + "쬮 'Botsmann'\n ࠢ! ᮢ⮢ , ᯥ樠 ணࠬ஢. ࠧࠡ⪮ ਫ, ᥩ 뭮 ''. 墠 뭪 㦭  ஢ ᯥ樠. । ࠡ $800 . 㬠, 殮 .", + "쬮 ''\n ! - ࠧࠡ稪 ਫ, ⨬ ! 饬 ⠫⫨ ࠧࠡ稪 । $1000 . 㦥 ⢮ ⢥, ?", + "쬮 'Botsmann'\n ᮦ, ࠢ . HR-ᯥ樠 ࠢ 쬮 ७⮢. 㦭 , ⮢ - $200.", + "쬮 'Botsmann'\n ࠢ! , HR-ᯥ樠 ࠢ 쬮 ७⮢ ⢥ ஢ન. 訫, 室! ᫨ ᠫ , 稬.", + ", ਢ! - Unnamed Studio 祭  , ⠪ ᮧ . ⢮ ࠡ, ॠ쭮 ! ⫨稥 㯭 ஫ ⥩ ᠬॠ樨. ⠫, 㦥 ᪨㫨. ⥡ 㤥, ⠢ -. 㤥 , ୮? ।. , ᫨ ᮣᥭ. ", +/*11*/ "쬮 'Botsmann'\n 蠩, ௥ ६, ᥬ ।. ⢫ ᭮ ࠡ ਫ ࠡ. ।, ⥡ ᠩ ਫ. ⢥. \n筮 ࠡ? $1200 ⥡ ⥫ . , த ࠡ?", + "쬮 'Botsmann'\n ⥡ ।०: 業 ࠡ! 㬠, 㧭 ⢮ ࠡ⪥?! 㢮!", + " ࠤ, ᮥ , ⥯ 童 Unnamed Studio! ࠡ ࠧ ॥! , ᮢ. ", + " ࠡ ! ᫮, ॡ Unnamed Studio ⠪ 㬠! ..., ஡. ன ணࠬ ய 䮭, ५ 墠 ⥯ :(. ᮡࠥ $%d. , ᫥ ࠧ! !", + "쬮 Unnamed Studio:\n ! १ 40 ५, ᠩ ! 砫쭮 - 㬠 ⮬, ⮫쪮 ᥩ 㧭, - ४. ", + "쬮 Unnamed Studio:\n ? ८業 ᥡ? ਫ, ᯥ ᤥ ᠩ ६! - ⥡ 諮 , 1000 ࠧ ! ⢮ $1000 饣 室 㡨ࠩ!", + "쬮 Unnamed Studio:\n 㢠, ᬮ५ ? ?! 墠뢠, 稥 ஦! ᯥ! ᫠! ⮫ 룠! ॢ ⥡ $200 000 - ⢮ . ஥ , ᪠! ⥡ ⤮. .", + "筮? 㬠! ࠡ ᨤ ࠡ뢠 죨, ⥡ 襭. ᫨ 㦭 죨 - த ࠡ, 㦥 祣 ᭮ 㤥. ⠪, 筮, ࠡ⠥, 릪 ६ .", + "筮, ? 筮, ᠬ । ࠡ ⪠, 㦥 㤥. , ॠ筮? ᥬ । ࠡ. , 㤥 ॡ ⠭ . ᮢ ⮦ 㤥, 祬 ⥡, ᫨ ࠢ ⮫쪮 . , 뫮 , ᫨ 뫮 ⬮ ᤥ 㣮 롮!", + "쬮 'Botsmann'\n ࠢ. ४஢ 訫 । ⥫쭮 祭 ࠡ⭨. ᮪頥 室 ஢ 㤭. 訫 ꥤ . , ᥩ 㪢쭮 . 饬, 襭, '襥' 㤥 । '襬'. 㦥 ᯥ ४ ᥡ 㤭, ⠪ ⥡ 砥 ⢮ Junior' ⢥ . ᯫ⭮, 筮. 5 ࠢ ⢥⮢ 塞 ६. ᫨ 5 ࠢ, ⠥, ஢ , ⮣ ᢮. ⥡ ᮬ, ⥡ ᪠ 襭. - , ࠢ!", + "쬮 'Botsmann'\n 頫, ⢮ ६ ࠢ ⢥: $400", + "쬮 'Botsmann'\n ஢ . ⠪, ⥡ ᮬ! , 뢠, ࠡ ᨦ. ࠢ, 㢮 ⥡ 易. .", + "쬮 'Botsmann'\n 㬠, ࠭ 楤 ஢ન ⬥: Junior' ᮢᥬ , ᠬ 祬 , ⮫쪮 訢 . 㤭 ᮢ 룮. 饬, ⥯ ᯮ ࠡ, ⥡ ⢫ 㤥.", + "蠩, ! ਫ , %d 稫 ⮬! ⥡ ᪮쪮 ᮢ ⪠? ন ᢮ $%d, 㦨.", + "쬮 Andrew Johnson \n , 㢠, ᥤ ⤥. ⮦ ࠨ ஢ ࠢ쭮 , ਫ ஭. , , ⢮ ⥫䮭 誥, ⠬ ⠭ 쬠. 뫮 , 㬠, ন ⠪ 㣨 稪.", +/*un2 var1*/ " , , 㦥... , ⮬ ⮫쪮 ᮢ⮬: 뫮 ன - ᭮ .", +/*un2 var2*/ "? 㬥? ⮡ ! , ⮣ , . 㤥 ࠭稢 ⢮ 䠭⠧.", +/*un4 var1*/ " 訫 ᪨ $%d -, ண .", +/*un4 var2*/ " ⥡ ࠧ , ⮫ ᯥ樠. 㬠, ᮧ ᠩ⮢ ⥡ - 騩 ." + }; + +bool unnamedStudioLettersSent[3] = {0,0,0,}; + +bool knowledgeLetterSent = false; +short nextKnowledgeLetterIndex = 0; +short klowledgeCorrectAnswers = 0; +short klowledgeUncorrectAnswers = 0; +const unsigned short knowledgeQuestionsCount = 10*3; +const char* knowledgeCheck[knowledgeQuestionsCount] = { + " 箪, ணࠬ஢ , C++ Delphi?", " ⠢ ", "筮 C++, Delphi 㦥 ", + " ணࠬ⮢ ᪠, ⪠ UDP 諠... ?", "UDP - ⮪, ࠭騩 ⠢ ⮢.", "UDP - ⮪, ࠭騩 ⠢ , ⮬ ⪠.", + " , ᠩ C++ , 窮?", " ਭ樯, , 몥 ஢ HTML-࠭.", ", ਪ. PHP, Python, ASP.Net 㣨", + " ᯮਫ, , ᯮ짮 JavaScipt ᠩ , Java. Java - ਫ. ୮?", " நࠫ.", " , ਫ ⢮ ந Java ᠭ .", + " ४ ᪠, ࠡ 襩 ࠡ뢠 opensource-஥. ?",", ⭮ প.", ", !. Opensource-஥ ᯫ.", + "ॡ ஥ iOS. , 祬 ࠧ #include #import?", "#import ࠭, 䠩 㤥 ࠧ, ⫨稥 #include", " ⠥, #include ᯮ C, 'import' - ᥬ ⠢.", + " ஥ Ruby on Rails. 蠫, 㥬 ᮪஢, ⠪?","... , ३.", ", 㥬 , 㥬.", + " ⥯ Linux, ⠢ NTFS-ࠧ? live cd ।.", ", 㧨 ᬮ.", " ਭ樯, , 㦭 , ⠢ ⥫ ⨫... ⥡ ?", + " ७⮢, ᪠, १ PHP eval(). । ࠡ, ⪠. ࠢ쭮 ᤥ? ", "ࠢ, 뫠 '⠪'.", "ࠢ쭮, ⮬ 祣 饣 ", + "宦 㤠 ࢥ, 㦭 㧭, ᪮쪮 ப 䠩 log.txt. ⠬, , Linux ⮫쪮 ᮫... ?", "wc -l log.txt", "ls -l log.txt" + }; + +/************************************************************************* +* Tips for users when waiting for an input +*************************************************************************/ + +const char* ae_advanced_courses = " ? ⮣, ⮡ 'த' ᮢ, 'a'-'e'"; +const char* bottomLineCourses = "[C] "; +const char* bottomLineMsgAchieves = "饭[M] ⨦[A] 릮 諮[U] "; +const char* bottomLineSpeedAndExit = "[S] [Esc]\n"; +const char* changeSpeedButtons = "[+][-] ਭ[Y]"; +const char* enter = " [Enter] த..."; +const char* escToBreakReading = ", ࢠ ⥭ [Esc]"; +const char* number_or_enter = " [Enter] ⮡ "; +const char* one_or_two = "ਠ ⢥⮢: [1] [2]"; +const char* one_two_or_three = "ਠ ⢥⮢: [1], [2] [3]"; +const char* pressF = " [F] த..."; +const char* pressP = " [P] த..."; +const char* yesNoDialog = "[Y] [N]"; + + +/************************************************************************* +* Windows' title +*************************************************************************/ + +const char* achievementsTitle = "⨦"; +const char* breaking_news = "஢ "; +const char* changeSpeedTitle = " "; +const char* coursesTitle = ""; +const char* courseAlreadyPassed = " 㦥 ன!"; +const char* finalCard = ""; +const char* gameOverTitle = " நࠫ!"; +const char* introTitle = "㯫"; +const char* new_letter = " 쬮"; +const char* newAchievement = " ⨦!"; +const char* notEnoughMoney = " 筮 । :("; +const char* playerStatsTitle = "⨪ ப\n\n\n"; +const char* unread_message = "⠭ ᮮ饭"; + +/************************************************************************* +* Windows' text +*************************************************************************/ + +const char* coursesFinishedText = "\nᮢ ன: %d/%d\n \n"; +const char* finalCardsUnlockedText = "\n殢 : %d/%d\n"; +const char* gameName = "21 days"; +const char* gameOverText = "\n ⢥ ᯮᮡ ந, 諨 !\n , ९ ⠪ , । ࠡ.\n\n!\n"; +const char* helpDesker = "騪"; +const char* mainMenuText = "\n\n1. \n\n2.室\n"; +const char* noCurrentCurses = "\t 祬 砥...\n"; +const char* playerStatsEnd = "\n\n ਭ⮬ ⨪ ﬨ!\n\n [Esc] 室.\n"; +const char* playerStatus = " : "; +const char* pseudoEqual = ""; +const char* selectCourseText = "롥 ᫥ ⥣਩, ன ⥫ :\n"; +const char* startupper = "⠯"; +const char* takeCourseCost = ", ன : $%d\n"; +const char* takingThisCourse = "\t ᥩ 砥 ⮬ ..\n"; +const char* worker = "㤮஥"; + +const char* days21 = +"\n .oooo. .o .o8 \n" +".dP\"\"Y88b o888 \"888 \n" +" ]8P' 888 .oooo888 .oooo. oooo ooo .oooo.o \n" +" .d8P' 888 d88' `888 `P )88b `88. .8' d88( \"8 \n" +" .dP' 888 888 888 .oP\"888 `88..8' `\"Y88b. \n" +".oP .o 888 888 888 d8( 888 `888' o. )88b \n" +"8888888888 o888o `Y8bod88P\" `Y888\"\"8o .8' 8\"\"888P' \n" +" .o..P' \n" +" `Y8P' \n"; + +const char* youWin = +"\n.___________. __ __ _______ _______ .__ __. _______ \n" +"| || | | | | ____| | ____|| \\ | | | \\ \n" +"`---| |----`| |__| | | |__ | |__ | \\| | | .--. |\n" +" | | | __ | | __| | __| | . ` | | | | |\n" +" | | | | | | | |____ | |____ | |\\ | | '--' |\n" +" |__| |__| |__| |_______| |_______||__| \\__| |_______/ \n\n\n"; + +const char* gameOverLogo = +" __ _ __ _ _ __ ___ ___ _____ _____ _ __ \n" +" / _` |/ _` | '_ ` _ \\ / _ \\ / _ \\ \\ / / _ \\ '__|\n" +"| (_| | (_| | | | | | | __/ | (_) \\ V / __/ | \n" +" \\__, |\\__,_|_| |_| |_|\\___| \\___/ \\_/ \\___|_| \n" +" |___/ \n\n"; + +const char* playerStats[9] = { + " 뫠 ன 릪 ६ %d ", + "祭 , ஢ 宦 : %d\n", + "⠭ ᮮ饭: %d\n", + " ࠧ ஬: %d ", + " : %d ", + " ࠡ⠭: $%d\n", + " 祭: $%d\n", + " ⢮⥫쭮: $%d\n", + "襭 릪 ६: %d\n"}; + +/*const char* gameIntro = "\n ࠠ! ᯥ譮 祭 㦥 ᪮쪮 뫨 . ᪠뢠 ஬ ࠤ... ⮨ ⠪ ୮ ⬥ 砭 㭨. , '᪭ ', 騩 㦥 , 稫.\n ⠬ 宫쭨? . . , .\n\n\ +<騬 栬 ࠥ >\n-, , ⥡ ?\n- , 㦥 ᯠ!\n- -, ᠬ १ .\n- , 筮, ᪠뢠 ! ⮣䨨 ᪨, ࠡ ਤ.\n-㤠?\n-, ७쪮 ந. ணࠬ⮬.\n-, ⮦ ந?\n-... , .\n- - ந!\n-, 祬 . ஡ ந 㤠-.\n- 祣 㬥!\n-, ᬥ譮 ᪭ ... , ᠬ 祣 㬥. ਤ ᠬ ஡. 'C++ 21 ', 'Java ' .., ஡ -, ७쪮 ࠢ १ 㤠-. 쪮 .\n-祬?.\n- - , ࠧ. 祬 , ᫨ ᠬ 祣 㬥?\n-?! ᬮ, ⠪ 㬭 ࠧ ⠫, ࠡ . 뫮 廊, ᥩ ୨ !\n- , ⥡ !\n\n\ + ! 죨 , . , 㬥 ⠭ - , - த. ⮬ 堫 , 祬 21 ! ࠡ⠥ ᢮ , ᢮ . ᭮, 誨 ⮢ ᢮稢⥫ ࠭⢠ ६ ࠡ⠥? ਣ. , 㦥 ।⠢ ⮣ ਤઠ, 㢨! ⠭ ⠪ !\n\n";*/ +/*const char* gameIntroPlan = " ஡ ᥬ, 祬 , ⨣ ᥣ, ⮫쪮 㬠, , ... ࠡ ! , , 㦥 ᫨誮. 㤥 . ⮬ ன ᬮਬ, 祣 .\n\n ⠪, 楫 ⠢, ६ !\n ⠬ ᠫ? C++ 21 ? - 誠 ⠪ , ᪠. - 稭 ... 21 筮 ன. \nਤ भ १ -ன . ⮬ 誨 ⮢ ᢮稢⥫ ࠭⢠ ६ 諮, 21- , 㬠, ᥣ 3 . ⠪ ᤥ!";*/ +const char* gameIntroPlan = ":\n\n 9 ⨦\nன 12 ᮢ 祭\n 5 殢:\n 3 易 롮஬ ᢮ (⢮, ࠡ , ᢮ ⠯)\n 2 易 襣 ⢥ (ଠ / ⢮ )\n\n ஢ ࠭⢮ - ६. ࠢ 㣨 ࠬ, ᫥ ஢ ࠭⢮, 室 ᫥ ६.\n\nࠢ , 諮 㣮: ⮬ ⮢ ᢮稢⥫ ࠭⢠ ६.\n\n᫥ 믮 ୨ 砫쭮 窥: 21 . 㬠 襭쪮, ன ⠪ : 墠 ।.\n\n ⠥ 祭, 㢨 'The End'( 먣ࠫ) 'game over'(நࠫ, 믮 )."; + +const char* yourAnswer = "\n\n ⢥:\n\t1:%s\n\t2:%s\n"; +const char* shitCodeYourAnswer = "\n\n ⢥:\n\t1:, 筮.\n\t2:, ⠪ 㬥.\n"; +const char* statusLine = ": %d, $: %d, ଠ: %d, ᮮ饭: %d"; +const char* statusLineCoursesNotFinished = ", ன ᮢ: %d"; +const char* unnamedStudio1Answer = ", ன ࠧ । 㤥.\n\n ⢥:\n\t1:, ॡ, ᮣᥭ!\n\t2:.. ⠪ ᬥ, ⮡ 뢠 ᫥ 죨.\n"; +const char* unnamedStudio3Answer = "\n\n ⢥:\n\t1:, 뢠!\n\t2:, ᪮쪮 죨?\n"; +const char* unnamedStudio4Answer = "\n\n ⢥:\n\t1:, -.\n\t2:, ᠬ ७쪮 ᤥ ᠩ, ?\n\t3:, 죨? 諨 !\n"; +const char* angryBossAnswer = "\n\n ⢥:\n\t1:, ਫ.\n\t2:, . ᫥ 宬 ᢮.\n"; + +/************************************************************************* +* Modal windows' text +*************************************************************************/ + +const char* answerLetter = "⢥⭮ 쬮"; +const char* cantStopDuringKnowledgeCheck= ", ६ । ஢ન . 室 !"; +const char* charityTitle = "⢮⥫쭮"; +const char* charityQuestion = " ⢨⥫쭮 ⢮ ⢮⥫쭮?"; +const char* congratsMsg = "ࠢ塞!"; +const char* courseSuccessfullyFinished = " '%s' ᯥ譮 襭! 믮 ࠭ ࠢ."; +const char* daysPerSecond = "஢ ᥪ㭤: %d"; +const char* doYouReallyWantToExit = " ⢨⥫쭮 ?"; +const char* errorMsg = "訡!"; +const char* failMsg = "㤠!"; +const char* need100ForUndo = "릪 ६ ண. 室 $100!"; +const char* notEnoughMoneyForCharity = " 祣 ⢮ ⢮⥫쭮!"; +const char* noUnreadMessages = " ⠭ ᮮ饭!"; +const char* prepareForTimeJump = " 㤥 ந 릮 諮, ਣ⮢!"; +const char* pressRForCharity = ", 筮 ।, 죨 ⢮⥫쭮!"; +const char* returnToDay21 = " 稫 ᥬ, ᥣ, ⥫. 諮 21- , ⮡ ⠢ 楫. 㬠 襭쪮, ன ᤥ ⠪ ."; +const char* rightAnswer = "ࠢ ⢥!"; +const char* startupFailedTip = " ⠯ :(. 諮 ࠢ. 祣 ᭮ 㦥 㤥, 㯨."; +const char* successfullyEnrolled = " ᯥ譮 ᠭ '%s'!"; +const char* wrongAnswer = " ⢥ :("; + +/************************************************************************* +* Achievements +*************************************************************************/ + +const unsigned int achievesNumber = 9; +char* achieves[achievesNumber] = { + " ணࠬ஢: 믮 㯥-᫮ ஥.", + "⢥থ: ଠ ⨫ !", + "ᯥ ⠯: ਡ ⠯.", + ": $1000 000.", + "ᥤ: ᫥ 宬 ᢮.", + " ⢮ : ஬ ⨦ ࠡ ⠯ .", + "騩 ᢮ : ᯥ譮 ன ஢ .", + "⮩稢 ௥: 筮 ࠡ ࠥ.", + "⢥ ६: ᮢ 릪, ᯠ ." + }; + +bool achievesPicked[achievesNumber] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; +bool achievesShowed[achievesNumber] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; + +/************************************************************************* +* Final cards +*************************************************************************/ + +const char* defaultFinalCard = " 饬, . , 筮, த , ᮡ \ +ᮡ⨩ ।: 㤥 ⠭ ॣॢ訥 . ! \ +, ⠪ ࠧ - ࠢ: ⢥⢥ ࠡ 쭠. 墠⠥, \ + ୥ ⮦. 祬 ⠯ ࠡ 㯭 ? , ᤥ ᢮ 롮. 㦭? \ +, ࠢ, , 室 ⠢ , ⮡ , ⠪ \ + ! 쪮 , , ?\n"; + +const char* workFinalCard = " ᬮ, ௥. , ࠡ⠥. , 砥. ࠢ \ +ࠡ⠥, ஭ . 죨 㦭? , 㢮? ! , ⠪ - \ + 墠쭮. ⠪ 뢠 - ᨤ ᥡ , ࠡ, ࠡ, ⮬ १ -\ + ⠭ ࠫ묨 ४ࠬ , ன ࠡ. ⠪ ⥡ ᯥ⨢, 㦨. - \ + ࠢ ⠡쭮 , 祬 ᢮ ⠯, ࠥ ᨫ . \ +, ᢮ ⠯? , , 뫮 ࠭ 㣮 롮!\n"; + +const char* startupFinalCard = ", 뫮 ! ᪮... , ᠬ . \ + , ६, ஥ ⨫ ⠯, 祭 . , 쬨! \ + ᪠稢 . , ? - , ⢮ த 㦥 . , ⥡ 業. \ +⮬ ⠯, ன ⮫ ணࠬ⮢ - 㯭 , \ +⢮ . ᠬॠ樨 ᫨ - , ! 筮, ⭨ \ +᪠, ⥡ , - , ᪮쪮 㤠 뫮 ! ४᭮ , , \ +ࠫ - 㣮. ᤥ ࠢ 롮. , ࠢ쭮 롮. ࠢ, 㣮."; + +const char* zeroKarmaFinalCard = " ⮫쪮 ᯮ⨫ ⭮襭 쬨,  . . :(.\n\n ᠬ :D. ࠩ 묨 ᯮᮡ , , 죨, நࠥ.\n"; + +const char* noMoneyFinalCard = " , ⮡ ᫥饣 । ࠡ. ਠ - 筨 த , , .\n\n ᠬ . ࠩ - ࠡ , , ଠ 㤥 , நࠥ!\n"; + +const char* gameOver = " ⨣ ⠢ 楫 ᯥ譮 訫 ! 祭 ன, 殢 , ᪮쪮 ⨦ ६! ⠪ ᥣ 21 ! , ਮ५, 業, 롮, - ࠢ. ࠢ쭮 롮, 㣮. , 㤥 , . - 設 ६, ୮?"; + +/************************************************************************* +* Hints +*************************************************************************/ + +const char* hintOfTheMonth = "᪠ :\n"; +const int hintsCount = 12; +const char* hints[hintsCount] = { + "'ﭭ 筨 室' - ⮫쪮 樠쭠 ࠡ ᮡ⢥ , ⠪ 믮 , ᫨ ४ ᥡ ᯥ樠 ९.", + "᫨ ⪠뢠 ᥬ ⠭ 稭 , ᪮ ⠭ ᮢᥬ.", + " ⭮, .", + " ਫ: ⮡ ஬, 㦭 ᭮ ᪮쪮 ⠯. ⮫쪮 , ᪮쪮 ࠧ.", + "㣮 , ⫨. ࠡ⠫, ⨫ 죨, 稫. 稫.", + " 㣠? , 㦥 뫨 㣨 ⥩ ? 㬠, ⠩ - ᥣ ᤥ - ⨦.", + "᫨ 筠 祣 ந室, ஡ ᪮ . , ⥩.", + "᫨ ᢮ ''....., 㦥 祣 . , . , ᫨ 뫠 設 ६!", + " , 祬 ? ᯮ, , । ⠪ , ⪠.", + "⢮⥫쭮 - 訩 ᯮᮡ , ࠡ ᪮ ਥ.", + " 릪 ६ ࠭⢥-६ ⨭ 뤥ন 뢠: ⨬ ᭨ ⮩ .", + "᫥ 宦 ᮢ ⨦ 殢 諮 21- . ⠪ , : 쭮 墠." + }; + +const char* getWordEnding(int n, int k) { + int ld = n % 10; // Last digit + if (ld == 1) + return (k == 0)?"\n":"ࠧ\n"; + else if (ld == 2 || ld == 3 || ld == 4) + return (k == 0)?"\n":"ࠧ\n"; + else + return (k == 0)?"\n":"ࠧ\n"; + } + +/************************************************************************* +* Intro +*************************************************************************/ + +const char* developer = "Copyright (C) 2014 Maxim Grishin (igevorse)"; +const char* introAllowedKeys = " ᭨ - , . ਬ, [1] [Enter]"; +const char* introDesktop = " - ࠡ稩 ⮫"; +const char* introFinished = " 䥩ᮬ 襭, 稭 !"; +const char* introLetsBegin = "!"; +const char* introStatusLine = " ⮡ࠦ ଠ:\n1.騩 .\n2.⢮ ( ⠭ , 㦭 ).\n3.ଠ - ⭮襭  . \n4.饭 - ⢮ ⠭ ᮮ饭.\n"; + +const char* gameIntroTextPart1 = "1. 砩\n\n\ +- ࢨ஢? ॢ ⮬ 稫? 祬 ⮩ ஭, ?! ? ⢥砩!\n- ...\n\ +- <࣠ ࠩ 㪠> ? , ⮩ , ९⠫! ? 蠬 嫮, ਭ? ᬮ५, ?\n\ +<᭮ ࣠ 㪠> ᬮ!  , ᯮ⨫ !\n\ + !\n\n\ +, 蠣 ࠢ ᮡ, ࢠ , १ ᮡ ਦ ᯨ ⥭.\n த.\n\ +  . 祬 ⠪?\n\ + 祬 ਤࠫ ⮩ , ࠧ ᤥ , ⨫? ᠬ ᯮ⨫ ! , ⠢ ६- , ⭨, ⮬ 㬠, 뢠 ᥡ. 筮 뢠 ! 㪠 訡, 祬 ࠧ ࠨ ਪ?\n\ +ࠢ ਫ, 訥 ? ?\n\ + 楬  㣮, ⮫쪮 - 樠쭮 訡, ⠪ ⮭ 樠!\n\ + ⠪ . \n\ + ⨩ ࠧ ࠨ ਪ ⮬ ! 㣠, 㭨, 㪠뢠 . 訫, - ? ? 墠⠥ ⮫쪮 室 . ⮣ 蠥?!\n ᨫ ௥ !\n\ + 㧭, ⠪ 㣠... 㦭 ௥ . .\n\n\ +㦭 室 . , ⮬ 㢮, 㧭 ந襤襬. . ⮬ - 㫠 । ਤ饣 ... ᮩ 㬠, ௥ .\n\n\ + 㢨 ᥡ ઠ, ᥢ襬 ⨢: 뫠 - ࠭ ࠧ 뫪.\n\ +, ࢭ. ४, ⠪ ஦ ⮬ ﭭ .\n\ + ᨫ ࢠ ० .\n\ + 祭!"; + +const char* gameIntroTextPart2 = "2. \n\n\ + ᦨ , ⥡ , ! , ᫨ 宫쭨 ? , ᨬ , ᫨ 祣 . ⠪ 㬥, 頣 ⠪ 室. ᫨ 㭨᪮ 頣 뫮 室 ' ' 㤥⠬ 묨 栬, ࠪ , 㣮, ᥩ 뢠 ⮫쪮 ᥡ. 㭨 뫮 ᮢᥬ -㣮. ਫ, 멤 訬 ᯥ樠⠬, 稬 ⨦ ࠡ! \n\ + ࢭ 뫪 ᭮ ஡ . ! 뢠 ⨦ ࠡ⮩?\n\ + 㯯, ᪮쪮 , ⮫쪮 ᬮ ந 訥 , ⮬ ⢨⥫쭮 稫.\n\ + 祬 㦥?\n\ + 室 ࠡ ﬨ 砬, ⮡ 墠⠫ 㭨. ? ࠧ ? ⠪ ࠡ⮩ 㭨- । .\n\ + . 㤨⥫쭮, 祬 稫.\n\ + ࠧ ॢ , , 㦥 ᮢ 祣 .\n\ + ᪮॥ , 祬 ࠡ 樠⮬! म ᫮ ᥡ , 墮.\n㦭 - .\n\n\ +᫨ 㬠. ࠧ뢠 ᫥!\n\ + 祣 㬥!\n\ +⢥, 砥 - ᮢ. ! ࠢ ࠬ, 㧥 - ࠡ⠥. \n\ +, , ࠡ⮩. ⠪, 审. ⮣ .\n\ +㤮 ⮩稢 , 㣮 ࠡ. ᦠ .\n\n\ +諮.\n 㬠? , , ⮬ ࠡ. \n\ +...\n, ᮡ⢥, 祬 ? 㬥?\n...\n\ + - . , 㣮 室. ࠭.\n\ + 訩 ⮪ ⮫, 直 嫠, ࠭, ᠫ ਬ .\n\ +, ᫨ ⮫쪮 ⢮, 㤥 墠... ᫨ ⮬ ... ⠪, ஡ 㤭 ... ⮣ 砥...... ...\n\ +祬 㬠 ⮬ ࠭!\n\ + ᨫ ࠭ ⮫, ⪨ ᯨ 㫠. ⮣!\n\ +, 㦭 뫮 ஡ ࠭!\n\n\ + ᬮ ࠡ . ⫨筠 ᯥ⨢! , ᯥ⨢: 祬- ஬ ⢠, 㤥 㯨 ⨭. 㭨 ⠫ - 樨 ணࠬ஢. ਫ, ᪮ ⠭ 祭 ॡ.\n\ + ⠬ ? , 'C++ 21 '. ਫ ࢮ . ⮨ ஭⮩. ⮣ 楫묨 ﬨ 㦨 ⮫, ᮢ襭 뫮 ६ .\n\ + ࠧ ? 21 ᯥ.\n\ + ⠬ 冷? 'Teach Yourself Perl in 21 days'. 祣 ⭮, ᭮ . ९⥫, ⮢ , ⤠. 뢠.\n\ + ᬥ譮!\n\ +᫨ 뫮 ⠪ , 㦥 ᠫ C++ Perl, 㦭 ᥣ 21 祭!\n\ + ᭮ ࠧ񭭮 : '... ९⠫! ? 蠬 嫮, ਭ?'.\n\ +, ⠪ ਤ 祬- .\n\n\ + 室, ⮬ 21 .  業.\n\ + ."; + +const char* gameIntroTextPart3 = "3. 室\n\n\ +. - 蠫 ࠧ ' ᢮ , 冷 ᢮ '. ⠪ 뫨 , 㪨. ⮩ -ᢠ ᤥ .\n\ +㦭 - ஢ 모 ⮢ . ࠧॡ , ।⠢, ⠬ .\n\n<...>\n\n\ + ஡? ⠪. , ᮡ⢥, , 室 ⠫ ᫥ ࠡ ࠧ ᯠ? ࠭ ஬ '' ࠭.\n\ +࠭. ⠫᪠ ஡ 뢠. -, ...\n\ +誠 ⫥⥫ ⭮ ஢, ஡ 믠 - 㬠 . \n\ + ⠬ ᠭ? ' ⥡'.\n\ + ? - 堭, 奬, ஢ 騩 ...\n\n\ + . । ஢ ᪮쪮 .\n\ + . !\n\ + ⢥ ᪠뢠 ᪠ , 类 ६ ᢮ ⢨ 頫 ﬨ ࠧ ६, ⨫ ஢ ஢ ६ ᢥ᪨ . 뫨 㢫⥫ ᪠ . ⠪ ⭮ᨫ ⨬ ᪠.\n\ + ४ , ᪠ 뫨 묨, ਭ ᫮ . , ⠬ ମ 릨訩 㬠 ਪ?\n\n\ + ⮬ ய. 祧. ᥬ.\n\ + ⠪ 諨.\n\ + ⥯ ஡. ᢮ . !\n\ + ⠬ 뢠 ?\n\n\ +... ⮢ ᢮稢⥫ ࠭⢠ ६! , ⠪.\n\n\ + ⠫ 뭮ᨬ . , , ᨤ ६. 㤠 ⠬ ⫥⥫ 誠? , . ஡, .\n\n\ + 㦥 稭 - !\n\ + ⠬ 뫮... ᯥ 21 ?\n\ +맮 ਭ!"; + +#endif diff --git a/programs/games/21days/sys.cpp b/programs/games/21days/sys.cpp new file mode 100755 index 0000000000..10ed6ec9ae --- /dev/null +++ b/programs/games/21days/sys.cpp @@ -0,0 +1,400 @@ +/****************************************************************** +* 21 days: a game for programmers +* Copyright (C) 2014 Maxim Grishin +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301, USA. +*******************************************************************/ + +char* windowTitle = "21 days by igevorse"; + +#ifdef _KOS32 +#define kbhit kbhit // Prevent redeclaring kbhit() in pc.h +#include +using std::string; + +#pragma pack(push,1) +typedef struct { + char *name; + void *data; +} kol_struct_import; +#pragma pack(pop) + +void kol_exit() { + asm volatile ("int $0x40"::"a"(-1)); + } + +void kol_screen_get_size(unsigned *w, unsigned *h) { + unsigned size; + asm volatile ("int $0x40":"=a"(size):"a"(14)); + *w = size / 65536; + *h = size % 65536; + } + +void (* __attribute__((stdcall)) con_init)(unsigned w_w, unsigned w_h, unsigned s_w, unsigned s_h, const char* t); +void (* __attribute__((cdecl)) printf2)(const char* format,...); +void (* __attribute__((stdcall)) con_exit)(char bCloseWindow); + int (* __attribute__((stdcall)) getch)(); + int (* __attribute__((stdcall)) kbhit)(); +void (* __attribute__((stdcall)) con_set_cursor_pos) (int x, int y); + int (* __attribute__((stdcall)) con_set_cursor_height)(int new_height); +void (* __attribute__((stdcall)) cls)(); + +int strcmp(const char* string1, const char* string2) { + while (1) { + if (*string1<*string2) + return -1; + if (*string1>*string2) + return 1; + + if (*string1=='\0') + return 0; + string1++; + string2++; + } + } + +void* kol_cofflib_procload (kol_struct_import *imp, char *name) { + for (int i=0;;i++) + if (NULL == ((imp+i) -> name)) + break; + else + if (0 == strcmp(name, (imp+i)->name) ) + return (imp+i)->data; + return NULL; + } + +kol_struct_import* kol_cofflib_load(char *name) { + kol_struct_import* val; + asm volatile ("int $0x40":"=a"(val):"a"(68), "b"(19), "c"(name)); + return val; + } + +unsigned _kWinWidth = 100; +unsigned _kWinHeight = 30; + +void getWinWH(int& width, int& height) { + width = _kWinWidth; + height = _kWinHeight-1; + } + +void CONSOLE_INIT(char* title) { + kol_struct_import *imp = kol_cofflib_load("/sys/lib/console.obj"); + if (imp == 0) + kol_exit(); + + con_init = ( __attribute__((stdcall)) void (*)(unsigned, unsigned, unsigned, unsigned, const char*)) + kol_cofflib_procload (imp, "con_init"); + if (con_init == NULL) + kol_exit(); + + printf2 = ( __attribute__((cdecl)) void (*)(const char*,...)) + kol_cofflib_procload (imp, "con_printf"); + if (printf2 == NULL) + kol_exit(); + + con_exit = ( __attribute__((stdcall)) void (*)(char)) + kol_cofflib_procload (imp, "con_exit"); + if (con_exit == NULL) + kol_exit(); + + getch = ( __attribute__((stdcall)) int (*)()) + kol_cofflib_procload (imp, "con_getch"); + if (getch == NULL) + kol_exit(); + + cls = ( __attribute__((stdcall)) void (*)()) + kol_cofflib_procload (imp, "con_cls"); + if (cls == NULL) + kol_exit(); + + kbhit = ( __attribute__((stdcall)) int (*)()) + kol_cofflib_procload (imp, "con_kbhit"); + if (kbhit == NULL) + kol_exit(); + + con_set_cursor_pos = ( __attribute__((stdcall)) void (*) (int, int)) + kol_cofflib_procload (imp, "con_set_cursor_pos"); + if (con_set_cursor_pos == NULL) + kol_exit(); + + con_set_cursor_height = ( __attribute__((stdcall)) int (*)(int)) + kol_cofflib_procload (imp, "con_set_cursor_height"); + if (con_set_cursor_height == NULL) + kol_exit(); + + unsigned sw, sh; + + kol_screen_get_size(&sw, &sh); + // Change window w/h depending on screen w/h + // Sorry for magic numbers + if (_kWinWidth*8 >= sw) + _kWinWidth = sw / 8; + + if (_kWinHeight*17 >= sh) + _kWinHeight = sh / 17; + + con_init(_kWinWidth, _kWinHeight, _kWinWidth, _kWinHeight, title); + } + +void hideCursor() { + con_set_cursor_height(0); + } + +void showCursor() { + //nop; + } + +void consoleGoto(int line, int column) { + con_set_cursor_pos(column-1, line-1); + } + +string itos(int n) { + string s; + int i, sign; + + if ((sign = n) < 0) + n = -n; + i = 0; + do { + s[i++] = n % 10 + '0'; + } while ((n /= 10) > 0); + if (sign < 0) + s[i++] = '-'; + s[i] = '\0'; + + int j,k; + for (k = 0, j = i-1; k // system +#include +#include // printf, vsprintf +#include // get window width/height +#include +#include +#include +#include +static struct termios old, new1; + +std::string txt(const char* s, ...) { + va_list args; + va_start(args,s); + char x[100000]; + vsprintf(x, s, args); + va_end(args); + std::string str(x); + return str; + } + +void cls() { + system("clear"); + } + +void hideCursor() { + printf2("\033[?25l"); + } + +void showCursor() { + printf2("\033[?25h"); + } + +void consoleGoto(int line, int column) { + printf2("\033[%d;%dH", line, column); + } + +void consoleSetColor(short text = 30, short background = 47) { + printf2("\033[%d;%dm", text, background); + } + +/* Initialize new terminal i/o settings */ +void initTermios() { + tcgetattr(0, &old); /* grab old terminal i/o settings */ + new1 = old; /* make new settings same as old settings */ + new1.c_lflag &= ~ICANON; /* disable buffered i/o */ + new1.c_lflag &= ~ECHO; /* set echo mode */ + tcsetattr(0, TCSANOW, &new1); /* use these new terminal i/o settings now */ + } + +/* Restore old terminal i/o settings */ +void resetTermios() { + tcsetattr(0, TCSANOW, &old); + } + +int kbhit () { + struct termios oldt, newt; + int ch; + int oldf; + + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + oldf = fcntl(STDIN_FILENO, F_GETFL, 0); + fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); + + ch = getchar(); + + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + fcntl(STDIN_FILENO, F_SETFL, oldf); + + if(ch != EOF) { + ungetc(ch, stdin); + return 1; + } + return 0; + } + +/* Read 1 character without echo */ +char getch() { + char ch; + initTermios(); + ch = getchar(); + resetTermios(); + return ch; + } + +void getWinWH(int& width, int& height) { + struct winsize w; + ioctl(0, TIOCGWINSZ, &w); + width = w.ws_col; + height = w.ws_row-1; + } + +void initConsole() { + printf2("\033]0;%s\007", windowTitle); + } +#elif defined _WIN32 +#define printf2 printf +#include // printf, vsprintf +#include +#include // system +#define _NO_OLDNAMES _NO_OLDNAMES +#include // kbhit(), getch(), getche() +#include + +char getch() { + return _getch(); + } + +int kbhit (void) { + return _kbhit(); + } + +std::string txt(const char* s, ...) { + va_list args; + va_start(args,s); + char x[100000]; + vsprintf(x, s, args); + va_end(args); + std::string str(x); + return str; + } + +void cls() { + system("cls"); + } + +void showCursor() { + HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_CURSOR_INFO info; + info.bVisible = TRUE; + SetConsoleCursorInfo(consoleHandle, &info); + } + +void hideCursor() { + HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_CURSOR_INFO info; + info.bVisible = FALSE; + info.dwSize = 1; + SetConsoleCursorInfo(consoleHandle, &info); + } + +void consoleGoto(int line, int column) { + COORD coord; + coord.X = column; + coord.Y = line; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); + } + +void consoleSetColor(short text = 30, short background = 47) { + printf2("\033[%d;%dm", text, background); + } + +void getWinWH(int& width, int& height) { + CONSOLE_SCREEN_BUFFER_INFO csbi; + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); + width = csbi.srWindow.Right - csbi.srWindow.Left - 1; + height = csbi.srWindow.Bottom - csbi.srWindow.Top - 1; + } + +void initConsole() { + SetConsoleTitle(windowTitle); + system("mode 100, 30"); + } +#endif diff --git a/programs/games/21days/sys.h b/programs/games/21days/sys.h new file mode 100755 index 0000000000..2268d52c8f --- /dev/null +++ b/programs/games/21days/sys.h @@ -0,0 +1,53 @@ +/****************************************************************** +* 21 days: a game for programmers +* Copyright (C) 2014 Maxim Grishin +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301, USA. +*******************************************************************/ + +#ifndef H_SYS +#define H_SYS + +#define ESCAPE_KEY 27 + +#if defined(__linux__) && !defined(_KOS32) + #define ENTER_KEY '\n' +#else + #define ENTER_KEY 13 +#endif + +#ifdef _KOS32 +#define kbhit kbhit // Prevent redeclaring kbhit() in pc.h +void CONSOLE_INIT(char* title); +void kol_exit(); +extern void (* __attribute__((stdcall)) con_exit)(char bCloseWindow); +extern void (* __attribute__((cdecl)) printf2)(const char* format,...); +extern int (* __attribute__((stdcall)) getch)(); +extern int (* __attribute__((stdcall)) kbhit)(); +extern void (* __attribute__((stdcall)) cls)(); + +#else +void cls(); +char getch(); +int kbhit (); +#endif + +void initConsole(); +void hideCursor(); +void showCursor(); +void consoleGoto(int line, int column); +void getWinWH(int& width, int &height); +#endif