├── .github └── workflows │ ├── build.yml │ └── gh-pages.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── pictures └── good-old-gif.gif ├── resourcesRoot └── pheroes │ └── bin │ ├── GameMaps │ ├── Ancient_Lands.hmm │ ├── Arena.hmm │ ├── Armageddons_Blade.hmm │ ├── Around_The_Bay.hmm │ ├── Barbarians_Revenge.hmm │ ├── Bloody_Sands.hmm │ ├── Confrontation.hmm │ ├── Consolidation.hmm │ ├── Crossroads.hmm │ ├── Delta.hmm │ ├── Disagreements.hmm │ ├── Fire-eater.hmm │ ├── Gods_War.hmm │ ├── H2O.hmm │ ├── Harlem_War.hmm │ ├── Henry.hmm │ ├── Hostile_Neighbors.hmm │ ├── Ice_Age.hmm │ ├── Island.hmm │ ├── King_Of_The_Hill.hmm │ ├── KneeDeepInTheDead.hmm │ ├── Land_Bridge.hmm │ ├── Loose_Borders.hmm │ ├── Magic_Forests.hmm │ ├── Might_And_Magic.hmm │ ├── Quest_for_Glory.hmm │ ├── Swampy.hmm │ ├── TerritorialDivide.hmm │ ├── ThePyramid.hmm │ ├── The_Great_Nile.hmm │ ├── The_Labyrynth.hmm │ ├── The_Mystic_Valley.hmm │ ├── Tutorial.hmm │ ├── Two_by_the_river.hmm │ ├── WarLords.hmm │ ├── Winter_Assault.hmm │ ├── Winter_Wars.hmm │ └── heroes.hmm │ ├── Resources │ └── hmm │ │ ├── GFX │ │ ├── Common │ │ │ ├── CreatPerks.png │ │ │ ├── GridHex.png │ │ │ ├── ShootCursor.png │ │ │ ├── SurfTiles.png │ │ │ └── WaterSandTransTiles.png │ │ ├── Creatures │ │ │ ├── minimon.png │ │ │ ├── minimonf.png │ │ │ ├── rminimon.png │ │ │ └── rminimonf.png │ │ ├── Decorations │ │ │ ├── Battle │ │ │ │ └── moat.png │ │ │ └── Castles │ │ │ │ └── icons32x20.png │ │ ├── GUI │ │ │ ├── BackTile.png │ │ │ ├── BackTile2.png │ │ │ ├── CtrlsTile.png │ │ │ ├── DifLvl.png │ │ │ ├── DlgBtn.png │ │ │ ├── ScrBarBtns.png │ │ │ ├── btnAttack.png │ │ │ ├── btnAutoBattle.png │ │ │ ├── btnDefend.png │ │ │ ├── btnEndTurn.png │ │ │ ├── btnInfo.png │ │ │ ├── btnMainMenu.png │ │ │ ├── btnMapSize.png │ │ │ ├── btnPlayersCount.png │ │ │ ├── btnShoot.png │ │ │ ├── dlgCorners_Small.png │ │ │ ├── dlgCorners_new.png │ │ │ ├── dlgHTiles_New.png │ │ │ ├── dlgVTiles_New.png │ │ │ ├── plt_ai.png │ │ │ ├── plt_human.png │ │ │ ├── tabQuestLog.png │ │ │ └── tabSpellBook.png │ │ ├── Pix │ │ │ ├── MenuBack.png │ │ │ ├── title_hmm.png │ │ │ └── title_hmm_ny.png │ │ └── spriteset.xml │ │ └── LNG │ │ ├── french.txt │ │ ├── german.txt │ │ ├── italian.txt │ │ ├── polish.txt │ │ ├── russian.txt │ │ └── slovak.txt │ ├── fnt_big.png │ ├── fnt_med.png │ └── fnt_sml.png ├── settings.gradle.kts └── src ├── commonMain └── kotlin │ ├── com │ └── github │ │ └── servb │ │ └── pph │ │ ├── gxlib │ │ ├── Clipper.kt │ │ ├── Randomizer.kt │ │ ├── View.kt │ │ ├── application.kt │ │ ├── dialog.kt │ │ ├── dib.kt │ │ ├── dibfont.kt │ │ ├── display.kt │ │ ├── file.kt │ │ ├── iRandTable.kt │ │ ├── inc.kt │ │ ├── input.kt │ │ ├── math.kt │ │ ├── popupview.kt │ │ ├── stdctrl.kt │ │ ├── timer.kt │ │ ├── topmostview.kt │ │ ├── viewmgr.kt │ │ └── window.kt │ │ ├── iolib │ │ └── xe │ │ │ └── dib.kt │ │ ├── pheroes │ │ ├── common │ │ │ ├── IsoMetric.kt │ │ │ ├── Serialize.kt │ │ │ ├── SortArray.kt │ │ │ ├── army │ │ │ │ ├── Army.kt │ │ │ │ └── CreatGroup.kt │ │ │ ├── castle │ │ │ │ └── CastleType.kt │ │ │ ├── cnst_gfx.kt │ │ │ ├── cnst_text.kt │ │ │ ├── common │ │ │ │ ├── Common.kt │ │ │ │ ├── DifficultyLevel.kt │ │ │ │ ├── FractionCoeff.kt │ │ │ │ ├── HeroType.kt │ │ │ │ ├── IdeologyType.kt │ │ │ │ ├── MapSize.kt │ │ │ │ ├── MineralSet.kt │ │ │ │ ├── MineralType.kt │ │ │ │ ├── NationType.kt │ │ │ │ ├── PlayerId.kt │ │ │ │ ├── PlayerType.kt │ │ │ │ ├── PlayerTypeMask.kt │ │ │ │ ├── SpecialHeroFlag.kt │ │ │ │ ├── SurfaceType.kt │ │ │ │ ├── artifact │ │ │ │ │ └── ArtifactType.kt │ │ │ │ └── skill │ │ │ │ │ ├── FurtherSkill.kt │ │ │ │ │ ├── FurtherSkills.kt │ │ │ │ │ ├── PrimarySkillType.kt │ │ │ │ │ ├── PrimarySkills.kt │ │ │ │ │ └── SecondarySkillType.kt │ │ │ ├── creature │ │ │ │ ├── CreatureDescriptor.kt │ │ │ │ ├── CreatureType.kt │ │ │ │ ├── Perk.kt │ │ │ │ └── TransportationType.kt │ │ │ └── magic │ │ │ │ ├── MagicSchool.kt │ │ │ │ ├── SpellDisposition.kt │ │ │ │ ├── SpellFilter.kt │ │ │ │ ├── SpellLevel.kt │ │ │ │ └── SpellType.kt │ │ ├── game │ │ │ ├── BattleEngine.kt │ │ │ ├── BattleInfo.kt │ │ │ ├── BattleUnit.kt │ │ │ ├── BattleView.kt │ │ │ ├── CommonControls.kt │ │ │ ├── CommonDialogs.kt │ │ │ ├── Credits.kt │ │ │ ├── Dlg_HallOfFame.kt │ │ │ ├── Dlg_Save.kt │ │ │ ├── Dlg_ScenList.kt │ │ │ ├── Dlg_ScenProps.kt │ │ │ ├── Game.kt │ │ │ ├── GfxHlp.kt │ │ │ ├── GfxManager.kt │ │ │ ├── InteractBattle.kt │ │ │ ├── ItemMgr.kt │ │ │ ├── LangView.kt │ │ │ ├── Map.kt │ │ │ ├── MenuView.kt │ │ │ ├── Settings.kt │ │ │ ├── TextComposer.kt │ │ │ ├── TextManager.kt │ │ │ ├── helpers.kt │ │ │ ├── hero.kt │ │ │ ├── hmm.kt │ │ │ ├── player.kt │ │ │ └── sprite2.kt │ │ └── mapEditor │ │ │ ├── ExportDlg.kt │ │ │ └── SpriteMgr.kt │ │ └── util │ │ ├── future.kt │ │ ├── helpertype │ │ └── EnumTestingInterfaces.kt │ │ └── pointers.kt │ └── main.kt ├── jvmTest └── kotlin │ └── com │ └── github │ └── servb │ └── pph │ ├── gxlib │ └── dibTest.kt │ ├── pheroes │ └── game │ │ └── DateTest.kt │ └── util │ └── helpertype │ └── EnumTestingInterfacesTest.kt ├── main └── kotlin │ └── com │ └── github │ └── servb │ └── pph │ ├── Pph.kt │ ├── gxlib │ ├── gxlcommontpl │ │ └── Static.kt │ ├── gxlmetrics │ │ ├── Point.kt │ │ ├── Rect.kt │ │ └── Size.kt │ ├── iCircBuff.kt │ ├── memory │ │ ├── Buff.kt │ │ └── DynamicBuffer.kt │ └── string.kt │ ├── pheroes │ └── common │ │ ├── SortArray.kt │ │ ├── SpannedMap.kt │ │ ├── TreasuryVariantsContainer.kt │ │ ├── castle │ │ ├── Castle.kt │ │ ├── CastleConstruction.kt │ │ ├── CastleConstructionType.kt │ │ ├── CastleOrientation.kt │ │ ├── CastleSize.kt │ │ ├── CastleSizeMask.kt │ │ └── CastleTypeMask.kt │ │ ├── common │ │ ├── GameLanguage.kt │ │ ├── GameType.kt │ │ ├── GuardDisposition.kt │ │ ├── HeroTypeMask.kt │ │ ├── MapItemType.kt │ │ ├── ObjectType.kt │ │ ├── PathElementType.kt │ │ ├── PlayerIdMask.kt │ │ ├── RewardItem.kt │ │ ├── RewardItemType.kt │ │ ├── RewardsCtr.kt │ │ ├── SpriteLevel.kt │ │ ├── VisionLevel.kt │ │ ├── artifact │ │ │ ├── ArtifactAssign.kt │ │ │ ├── ArtifactLevel.kt │ │ │ ├── ArtifactList.kt │ │ │ ├── HeroArtifactCell.kt │ │ │ └── RandomArtifact.kt │ │ └── skill │ │ │ ├── SecondarySkillEntry.kt │ │ │ ├── SecondarySkillLevel.kt │ │ │ └── SecondarySkills.kt │ │ ├── constantsSfx.kt │ │ ├── construction │ │ ├── OwnerableConstructionType.kt │ │ └── VisitableConstructionType.kt │ │ ├── creature │ │ └── Speed.kt │ │ ├── event │ │ ├── iTimeEvent.kt │ │ └── iTimeEventMgr.kt │ │ ├── lzo.kt │ │ └── magic │ │ ├── MagicSchoolLevel.kt │ │ ├── MagicSpell.kt │ │ ├── SpellClass.kt │ │ ├── SpellDescriptor.kt │ │ ├── SpellLabel.kt │ │ ├── SpellTargetMode.kt │ │ └── SpellTargetTypeMask.kt │ └── util │ └── helpertype │ ├── Aliases.kt │ ├── Defines.kt │ ├── EnumC.kt │ └── File.kt └── test └── kotlin └── com └── github └── servb └── pph ├── gxlib ├── gxlcommondef │ └── GxlCommonDefTest.kt ├── gxlcommontpl │ └── GxlCommonTplTest.kt ├── gxlmath │ └── GxlMathTest.kt └── gxlmetrics │ ├── PointTest.kt │ ├── RectTest.kt │ └── SizeTest.kt └── pheroes └── common └── SerializeTest.kt /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: [ push, pull_request ] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | - uses: actions/setup-java@v1 9 | with: 10 | java-version: 11 11 | - run: ./gradlew :build 12 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | main: 9 | name: Deploy to GitHub Pages 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout master code 13 | uses: actions/checkout@v2 14 | with: 15 | path: master 16 | - name: Setup Java 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: '11' 20 | 21 | - name: Build project 22 | run: | 23 | cd master 24 | ./gradlew :packResources :jsBrowserProductionWebpack 25 | rm build/distributions/*.map 26 | - name: Checkout gh-pages code 27 | uses: actions/checkout@v2 28 | with: 29 | ref: gh-pages 30 | path: gh-pages 31 | - name: Copy distribution to gh-pages 32 | run: | 33 | # Remove old files: 34 | cd gh-pages 35 | git rm -r . 36 | cd - 37 | # Add new ones: 38 | cp -r master/build/distributions/* gh-pages 39 | - name: Commit and push 40 | run: | 41 | cd gh-pages 42 | git config --global user.email "servbul@yandex.ru" 43 | git config --global user.name "GH Actions Bot" 44 | git add -A 45 | git commit --allow-empty -m "Deploy revision $GITHUB_SHA" && git push 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build 4 | bundles 5 | local.properties 6 | *.iml 7 | src/commonMain/resources/resources.zip 8 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.soywiz.korge") 3 | } 4 | 5 | korge { 6 | targetJvm() 7 | targetJs() 8 | 9 | bundle("https://github.com/korlibs/korlibs-bundle-source-extensions.git::korma-rectangle-experimental-ext::696a97640bb93a66f07ca008cca84b1ae4013e57##d2d9e3eb8f9f8eb5c137e847677eb8b3e9038c30d1f4457d1bd05cafc5c3f251") 10 | } 11 | 12 | val kotestVersion: String by project 13 | val reflectionsVersion: String by project 14 | 15 | kotlin { 16 | sourceSets { 17 | all { 18 | languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn") 19 | languageSettings.useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") 20 | } 21 | 22 | getByName("jvmTest") { 23 | dependencies { 24 | implementation("io.kotest:kotest-assertions-core-jvm:$kotestVersion") 25 | implementation("io.kotest:kotest-runner-junit5:$kotestVersion") 26 | implementation("org.reflections:reflections:$reflectionsVersion") 27 | } 28 | } 29 | } 30 | } 31 | 32 | tasks.withType { 33 | useJUnitPlatform() 34 | } 35 | 36 | val compressedResourcesFile = rootProject.file("src/commonMain/resources/resources.zip") 37 | 38 | tasks.create("packResources") { 39 | doFirst { 40 | compressedResourcesFile.delete() 41 | compressedResourcesFile.parentFile.mkdirs() 42 | } 43 | 44 | from(rootProject.file("resourcesRoot")) { 45 | include("**") 46 | } 47 | 48 | archiveFileName.set(compressedResourcesFile.name) 49 | destinationDirectory.set(compressedResourcesFile.parentFile) 50 | } 51 | 52 | tasks.clean { 53 | doLast { 54 | compressedResourcesFile.delete() 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | korgePluginVersion=2.2.1.0 2 | kotestVersion=4.6.0 3 | kotlin.mpp.stability.nowarn=true 4 | reflectionsVersion=0.9.12 5 | org.gradle.jvmargs=-Xmx4096m 6 | kotlin.test.infer.jvm.variant=false 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin or MSYS, switch paths to Windows format before running java 114 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | JAVACMD=`cygpath --unix "$JAVACMD"` 119 | 120 | # We build the pattern for arguments to be converted via cygpath 121 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 122 | SEP="" 123 | for dir in $ROOTDIRSRAW ; do 124 | ROOTDIRS="$ROOTDIRS$SEP$dir" 125 | SEP="|" 126 | done 127 | OURCYGPATTERN="(^($ROOTDIRS))" 128 | # Add a user-defined pattern to the cygpath arguments 129 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 130 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 131 | fi 132 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 133 | i=0 134 | for arg in "$@" ; do 135 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 136 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 137 | 138 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 139 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 140 | else 141 | eval `echo args$i`="\"$arg\"" 142 | fi 143 | i=`expr $i + 1` 144 | done 145 | case $i in 146 | 0) set -- ;; 147 | 1) set -- "$args0" ;; 148 | 2) set -- "$args0" "$args1" ;; 149 | 3) set -- "$args0" "$args1" "$args2" ;; 150 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 151 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 152 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 153 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 154 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 155 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 156 | esac 157 | fi 158 | 159 | # Escape application args 160 | save () { 161 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 162 | echo " " 163 | } 164 | APP_ARGS=`save "$@"` 165 | 166 | # Collect all arguments for the java command, following the shell quoting and substitution rules 167 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 168 | 169 | exec "$JAVACMD" "$@" 170 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 17 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 18 | 19 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 20 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 21 | 22 | @rem Find java.exe 23 | if defined JAVA_HOME goto findJavaFromJavaHome 24 | 25 | set JAVA_EXE=java.exe 26 | %JAVA_EXE% -version >NUL 2>&1 27 | if "%ERRORLEVEL%" == "0" goto execute 28 | 29 | echo. 30 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 31 | echo. 32 | echo Please set the JAVA_HOME variable in your environment to match the 33 | echo location of your Java installation. 34 | 35 | goto fail 36 | 37 | :findJavaFromJavaHome 38 | set JAVA_HOME=%JAVA_HOME:"=% 39 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 40 | 41 | if exist "%JAVA_EXE%" goto execute 42 | 43 | echo. 44 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 45 | echo. 46 | echo Please set the JAVA_HOME variable in your environment to match the 47 | echo location of your Java installation. 48 | 49 | goto fail 50 | 51 | :execute 52 | @rem Setup the command line 53 | 54 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 55 | 56 | 57 | @rem Execute Gradle 58 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 59 | 60 | :end 61 | @rem End local scope for the variables with windows NT shell 62 | if "%ERRORLEVEL%"=="0" goto mainEnd 63 | 64 | :fail 65 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 66 | rem the _cmd.exe /c_ return code! 67 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 68 | exit /b 1 69 | 70 | :mainEnd 71 | if "%OS%"=="Windows_NT" endlocal 72 | 73 | :omega 74 | -------------------------------------------------------------------------------- /pictures/good-old-gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/pictures/good-old-gif.gif -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Ancient_Lands.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Ancient_Lands.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Arena.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Arena.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Armageddons_Blade.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Armageddons_Blade.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Around_The_Bay.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Around_The_Bay.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Barbarians_Revenge.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Barbarians_Revenge.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Bloody_Sands.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Bloody_Sands.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Confrontation.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Confrontation.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Consolidation.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Consolidation.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Crossroads.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Crossroads.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Delta.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Delta.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Disagreements.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Disagreements.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Fire-eater.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Fire-eater.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Gods_War.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Gods_War.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/H2O.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/H2O.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Harlem_War.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Harlem_War.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Henry.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Henry.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Hostile_Neighbors.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Hostile_Neighbors.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Ice_Age.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Ice_Age.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Island.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Island.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/King_Of_The_Hill.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/King_Of_The_Hill.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/KneeDeepInTheDead.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/KneeDeepInTheDead.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Land_Bridge.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Land_Bridge.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Loose_Borders.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Loose_Borders.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Magic_Forests.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Magic_Forests.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Might_And_Magic.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Might_And_Magic.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Quest_for_Glory.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Quest_for_Glory.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Swampy.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Swampy.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/TerritorialDivide.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/TerritorialDivide.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/ThePyramid.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/ThePyramid.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/The_Great_Nile.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/The_Great_Nile.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/The_Labyrynth.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/The_Labyrynth.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/The_Mystic_Valley.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/The_Mystic_Valley.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Tutorial.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Tutorial.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Two_by_the_river.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Two_by_the_river.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/WarLords.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/WarLords.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Winter_Assault.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Winter_Assault.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/Winter_Wars.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/Winter_Wars.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/GameMaps/heroes.hmm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/GameMaps/heroes.hmm -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/Common/CreatPerks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/Common/CreatPerks.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/Common/GridHex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/Common/GridHex.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/Common/ShootCursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/Common/ShootCursor.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/Common/SurfTiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/Common/SurfTiles.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/Common/WaterSandTransTiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/Common/WaterSandTransTiles.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/Creatures/minimon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/Creatures/minimon.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/Creatures/minimonf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/Creatures/minimonf.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/Creatures/rminimon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/Creatures/rminimon.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/Creatures/rminimonf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/Creatures/rminimonf.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/Decorations/Battle/moat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/Decorations/Battle/moat.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/Decorations/Castles/icons32x20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/Decorations/Castles/icons32x20.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/BackTile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/BackTile.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/BackTile2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/BackTile2.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/CtrlsTile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/CtrlsTile.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/DifLvl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/DifLvl.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/DlgBtn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/DlgBtn.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/ScrBarBtns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/ScrBarBtns.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnAttack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnAttack.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnAutoBattle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnAutoBattle.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnDefend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnDefend.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnEndTurn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnEndTurn.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnInfo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnInfo.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnMainMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnMainMenu.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnMapSize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnMapSize.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnPlayersCount.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnPlayersCount.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnShoot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/btnShoot.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/dlgCorners_Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/dlgCorners_Small.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/dlgCorners_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/dlgCorners_new.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/dlgHTiles_New.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/dlgHTiles_New.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/dlgVTiles_New.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/dlgVTiles_New.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/plt_ai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/plt_ai.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/plt_human.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/plt_human.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/tabQuestLog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/tabQuestLog.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/tabSpellBook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/GUI/tabSpellBook.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/Pix/MenuBack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/Pix/MenuBack.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/Pix/title_hmm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/Pix/title_hmm.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/Resources/hmm/GFX/Pix/title_hmm_ny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/Resources/hmm/GFX/Pix/title_hmm_ny.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/fnt_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/fnt_big.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/fnt_med.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/fnt_med.png -------------------------------------------------------------------------------- /resourcesRoot/pheroes/bin/fnt_sml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerVB/pph/b828ccfaa180a6e2adb9cea9fb9a8732efb6dc79/resourcesRoot/pheroes/bin/fnt_sml.png -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenLocal() 4 | maven("https://dl.bintray.com/korlibs/korlibs") 5 | maven("https://plugins.gradle.org/m2/") 6 | mavenCentral() 7 | google() 8 | maven("https://dl.bintray.com/kotlin/kotlin-dev") 9 | maven("https://dl.bintray.com/kotlin/kotlin-eap") 10 | } 11 | 12 | val korgePluginVersion: String by settings 13 | 14 | resolutionStrategy { 15 | eachPlugin { 16 | if (requested.id.id == "com.soywiz.korge") { 17 | useModule("com.soywiz.korlibs.korge.plugins:korge-gradle-plugin:$korgePluginVersion") 18 | } 19 | } 20 | } 21 | 22 | plugins { 23 | id("com.soywiz.korge") apply false 24 | } 25 | } 26 | 27 | rootProject.name = "PPH" 28 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/gxlib/Randomizer.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib 2 | 3 | import kotlin.properties.Delegates 4 | 5 | interface IiRandomizer { 6 | 7 | fun GetSeed(): UInt 8 | } 9 | 10 | class iRandomizer(seed: UInt = 1u) : IiRandomizer { 11 | 12 | private var m_holdrand by Delegates.notNull() 13 | 14 | init { 15 | SetNewSeed(seed) 16 | } 17 | 18 | fun SetNewSeed(seed: UInt): UInt { 19 | m_holdrand = seed 20 | return m_holdrand 21 | } 22 | 23 | override fun GetSeed(): UInt = m_holdrand 24 | 25 | fun Rand(maxVal: Int = MaxVal): Int { 26 | require(maxVal > 0) 27 | 28 | val newHoldrand = m_holdrand * 214013u + 2531011u 29 | var res = (newHoldrand shr 16).toInt() and 0x7FFF 30 | m_holdrand = newHoldrand 31 | if (maxVal != MaxVal) { 32 | res %= maxVal 33 | } 34 | return res 35 | } 36 | 37 | fun Rand(minVal: Int, maxVal: Int): Int { 38 | require(minVal < maxVal) 39 | return minVal + Rand(maxVal - minVal) 40 | } 41 | 42 | companion object { 43 | 44 | const val MaxVal = 0x7FFF 45 | } 46 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/gxlib/dialog.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib 2 | 3 | import com.github.servb.pph.util.asRectangle 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | import com.soywiz.korma.geom.IRectangleInt 6 | import com.soywiz.korma.geom.RectangleInt 7 | import com.soywiz.korma.geom.SizeInt 8 | 9 | enum class DLG_RETCODE(override val v: Int) : UniqueValueEnum { 10 | UNDEFINED(-1), 11 | OK(0), 12 | CANCEL(1), 13 | YES(2), 14 | NO(3), 15 | } 16 | 17 | abstract class iDialog : iView { 18 | 19 | private var m_retCode: Int // can't use DLG_RETCODE type because some dialogs use plain Int 20 | 21 | constructor(viewMgr: iViewMgr) : super( 22 | viewMgr, 23 | IRectangleInt(0, 0, 0, 0), 24 | VIEWCLSID.MODAL_DIALOG, 25 | 0u, 26 | ViewState.Enabled.v, 27 | ) { 28 | m_retCode = DLG_RETCODE.UNDEFINED.v 29 | } 30 | 31 | suspend fun DoModal(): Int { 32 | Center() 33 | OnCreateDlg() 34 | SetVisible() 35 | m_pMgr.pushModalDlg(this) 36 | while (m_pMgr.App().Cycle() && m_retCode == DLG_RETCODE.UNDEFINED.v) { 37 | // cycling, no body needed 38 | } 39 | val pDlg = m_pMgr.popModalDialog() 40 | check(pDlg == this) 41 | 42 | return m_retCode 43 | } 44 | 45 | abstract fun GetDialogMetrics(): SizeInt 46 | abstract suspend fun OnCreateDlg() 47 | open fun OnPlace(rect: RectangleInt) {} 48 | 49 | open fun KeyDown(key: iKbdKey): Boolean = false 50 | open fun KeyUp(key: iKbdKey): Boolean = false 51 | 52 | protected fun IsValidDialog(): Boolean = m_retCode == DLG_RETCODE.UNDEFINED.v 53 | 54 | protected fun Center() { 55 | val rect = AlignRect(GetDialogMetrics(), m_pMgr.Metrics().asRectangle(), Alignment.AlignCenter) 56 | OnPlace(rect) 57 | SetRect(rect) 58 | } 59 | 60 | protected fun EndDialog(retCode: Int): Boolean { 61 | if (m_retCode != DLG_RETCODE.UNDEFINED.v) { 62 | return false 63 | } 64 | m_retCode = retCode 65 | return true 66 | } 67 | 68 | override fun Invalidate() { 69 | m_bNeedRedraw = true 70 | m_pMgr.CurView()?.Invalidate() 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/gxlib/display.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib 2 | 3 | import com.soywiz.korge.view.Stage 4 | import com.soywiz.korge.view.image 5 | import com.soywiz.korge.view.xy 6 | import com.soywiz.korma.geom.IRectangleInt 7 | import com.soywiz.korma.geom.ISizeInt 8 | import com.soywiz.korma.geom.SizeInt 9 | import com.soywiz.korma.geom.setTo 10 | import kotlin.properties.Delegates 11 | 12 | // ported implementation from gxl.display.w32.cpp 13 | class iDisplay /*: iDispMsgHnd */ { 14 | 15 | private val m_BackBuff: iDib = iDib() 16 | private var m_gamma: Double 17 | private val m_Siz: SizeInt = SizeInt() 18 | private var m_Flags: UInt by Delegates.notNull() 19 | private var m_bInited: Boolean 20 | 21 | private fun RebuildGammaTables() { 22 | // todo 23 | } 24 | 25 | constructor() { 26 | m_gamma = 1.0 27 | m_bInited = false 28 | } 29 | 30 | fun `$destruct`() { 31 | check(!m_bInited) 32 | Destroy() 33 | } 34 | 35 | fun Init(siz: ISizeInt, flags: UInt, stage: Stage): Boolean { 36 | check(!m_bInited) 37 | 38 | m_Flags = flags 39 | m_Siz.setTo(siz) 40 | m_BackBuff.Init(m_Siz, IiDib.Type.RGB) 41 | // todo: seems like there is one more layer of abstraction. 42 | // for now we use iDib.backingBitmap but in the future can remove this property and add one more layer 43 | // and support DOUBLESIZE rendering 44 | // if (flags & GXLF_DOUBLESIZE) m_memDC.InitDC(iSize(siz.w*2,siz.h*2)); 45 | // else m_memDC.InitDC(siz); 46 | 47 | stage 48 | .image(m_BackBuff.backingBitmap) 49 | .xy(0, 0) 50 | .apply { smoothing = false } 51 | 52 | m_bInited = true 53 | 54 | return true 55 | } 56 | 57 | fun SetGamma(gamma: Double) { 58 | m_gamma = gamma 59 | RebuildGammaTables() 60 | } 61 | 62 | fun SetOrientation(bLandscape: Boolean, bLefthandler: Boolean) { 63 | // todo 64 | } 65 | 66 | fun Destroy() { 67 | check(m_bInited) 68 | m_bInited = false 69 | } 70 | 71 | // void msg_OnPaint(HDC hdc); 72 | // void msg_Suspend(); 73 | // void msg_Resume(); 74 | 75 | fun DoPaint(rc: IRectangleInt) { 76 | // skipped one more layer of abstraction for now (see comment in Init) 77 | 78 | ++m_BackBuff.backingBitmap.contentVersion 79 | } 80 | 81 | fun GetSurface(): iDib = m_BackBuff 82 | fun SurfMetrics(): SizeInt = 83 | m_BackBuff.GetSize() // the method is marked as const, but there is no const iDisplay used in sources 84 | } 85 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/gxlib/file.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib 2 | 3 | import com.soywiz.kmem.ByteArrayBuilder 4 | import com.soywiz.korio.lang.Charsets 5 | import com.soywiz.korio.lang.toByteArray 6 | import com.soywiz.korio.stream.* 7 | 8 | fun ByteArrayBuilder.Write(v: UByte) = s8(v.toInt()) 9 | fun ByteArrayBuilder.Write(v: Byte) = s8(v.toInt()) 10 | fun ByteArrayBuilder.Write(v: UShort) = s16LE(v.toInt()) 11 | fun ByteArrayBuilder.Write(v: Short) = s16LE(v.toInt()) 12 | fun ByteArrayBuilder.Write(v: UInt) = s32LE(v.toInt()) 13 | fun ByteArrayBuilder.Write(v: Int) = s32LE(v) 14 | 15 | suspend fun AsyncOutputStream.Write(v: UShort) = write16LE(v.toInt()) 16 | suspend fun AsyncOutputStream.Write(v: Short) = write16LE(v.toInt()) 17 | suspend fun AsyncOutputStream.Write(v: UInt) = write32LE(v.toInt()) 18 | suspend fun AsyncOutputStream.Write(v: Int) = write32LE(v) 19 | 20 | fun SyncInputStream.ReadU8(): UByte = readU8().toUByte() 21 | fun SyncInputStream.ReadU16(): UShort = readU16LE().toUShort() 22 | fun SyncInputStream.ReadU32(): UInt = readU32LE().toUInt() 23 | fun SyncInputStream.ReadS8(): Byte = readS8().toByte() 24 | fun SyncInputStream.ReadS16(): Short = readS16LE().toShort() 25 | fun SyncInputStream.ReadS32(): Int = readS32LE() 26 | 27 | suspend fun AsyncInputStream.ReadU8(): UByte = readU8().toUByte() 28 | suspend fun AsyncInputStream.ReadU16(): UShort = readU16LE().toUShort() 29 | suspend fun AsyncInputStream.ReadU32(): UInt = readU32LE().toUInt() 30 | suspend fun AsyncInputStream.ReadS8(): Byte = readS8().toByte() 31 | suspend fun AsyncInputStream.ReadS16(): Short = readS16LE().toShort() 32 | suspend fun AsyncInputStream.ReadS32(): Int = readS32LE() 33 | 34 | fun ByteArrayBuilder.Write(str: String) { 35 | Write(str.length) 36 | append(str.toByteArray(Charsets.UTF16_LE)) 37 | } 38 | 39 | suspend fun AsyncOutputStream.Write(str: String) { 40 | Write(str.length) 41 | writeString(str, Charsets.UTF16_LE) 42 | } 43 | 44 | suspend fun AsyncInputStream.ReadString(): String { 45 | val length = ReadS32() 46 | return readString(length * 2, Charsets.UTF16_LE) // 2 bytes in 1 char 47 | } 48 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/gxlib/iRandTable.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib 2 | 3 | val iRandTable = listOf( 4 | 0x00000000u, 0x77073096u, 0xEE0E612Cu, 0x990951BAu, 5 | 0x076DC419u, 0x706AF48Fu, 0xE963A535u, 0x9E6495A3u, 6 | 0x0EDB8832u, 0x79DCB8A4u, 0xE0D5E91Eu, 0x97D2D988u, 7 | 0x09B64C2Bu, 0x7EB17CBDu, 0xE7B82D07u, 0x90BF1D91u, 8 | 0x1DB71064u, 0x6AB020F2u, 0xF3B97148u, 0x84BE41DEu, 9 | 0x1ADAD47Du, 0x6DDDE4EBu, 0xF4D4B551u, 0x83D385C7u, 10 | 0x136C9856u, 0x646BA8C0u, 0xFD62F97Au, 0x8A65C9ECu, 11 | 0x14015C4Fu, 0x63066CD9u, 0xFA0F3D63u, 0x8D080DF5u, 12 | 0x3B6E20C8u, 0x4C69105Eu, 0xD56041E4u, 0xA2677172u, 13 | 0x3C03E4D1u, 0x4B04D447u, 0xD20D85FDu, 0xA50AB56Bu, 14 | 0x35B5A8FAu, 0x42B2986Cu, 0xDBBBC9D6u, 0xACBCF940u, 15 | 0x32D86CE3u, 0x45DF5C75u, 0xDCD60DCFu, 0xABD13D59u, 16 | 0x26D930ACu, 0x51DE003Au, 0xC8D75180u, 0xBFD06116u, 17 | 0x21B4F4B5u, 0x56B3C423u, 0xCFBA9599u, 0xB8BDA50Fu, 18 | 0x2802B89Eu, 0x5F058808u, 0xC60CD9B2u, 0xB10BE924u, 19 | 0x2F6F7C87u, 0x58684C11u, 0xC1611DABu, 0xB6662D3Du, 20 | 21 | 0x76DC4190u, 0x01DB7106u, 0x98D220BCu, 0xEFD5102Au, 22 | 0x71B18589u, 0x06B6B51Fu, 0x9FBFE4A5u, 0xE8B8D433u, 23 | 0x7807C9A2u, 0x0F00F934u, 0x9609A88Eu, 0xE10E9818u, 24 | 0x7F6A0DBBu, 0x086D3D2Du, 0x91646C97u, 0xE6635C01u, 25 | 0x6B6B51F4u, 0x1C6C6162u, 0x856530D8u, 0xF262004Eu, 26 | 0x6C0695EDu, 0x1B01A57Bu, 0x8208F4C1u, 0xF50FC457u, 27 | 0x65B0D9C6u, 0x12B7E950u, 0x8BBEB8EAu, 0xFCB9887Cu, 28 | 0x62DD1DDFu, 0x15DA2D49u, 0x8CD37CF3u, 0xFBD44C65u, 29 | 0x4DB26158u, 0x3AB551CEu, 0xA3BC0074u, 0xD4BB30E2u, 30 | 0x4ADFA541u, 0x3DD895D7u, 0xA4D1C46Du, 0xD3D6F4FBu, 31 | 0x4369E96Au, 0x346ED9FCu, 0xAD678846u, 0xDA60B8D0u, 32 | 0x44042D73u, 0x33031DE5u, 0xAA0A4C5Fu, 0xDD0D7CC9u, 33 | 0x5005713Cu, 0x270241AAu, 0xBE0B1010u, 0xC90C2086u, 34 | 0x5768B525u, 0x206F85B3u, 0xB966D409u, 0xCE61E49Fu, 35 | 0x5EDEF90Eu, 0x29D9C998u, 0xB0D09822u, 0xC7D7A8B4u, 36 | 0x59B33D17u, 0x2EB40D81u, 0xB7BD5C3Bu, 0xC0BA6CADu, 37 | 38 | 0xEDB88320u, 0x9ABFB3B6u, 0x03B6E20Cu, 0x74B1D29Au, 39 | 0xEAD54739u, 0x9DD277AFu, 0x04DB2615u, 0x73DC1683u, 40 | 0xE3630B12u, 0x94643B84u, 0x0D6D6A3Eu, 0x7A6A5AA8u, 41 | 0xE40ECF0Bu, 0x9309FF9Du, 0x0A00AE27u, 0x7D079EB1u, 42 | 0xF00F9344u, 0x8708A3D2u, 0x1E01F268u, 0x6906C2FEu, 43 | 0xF762575Du, 0x806567CBu, 0x196C3671u, 0x6E6B06E7u, 44 | 0xFED41B76u, 0x89D32BE0u, 0x10DA7A5Au, 0x67DD4ACCu, 45 | 0xF9B9DF6Fu, 0x8EBEEFF9u, 0x17B7BE43u, 0x60B08ED5u, 46 | 0xD6D6A3E8u, 0xA1D1937Eu, 0x38D8C2C4u, 0x4FDFF252u, 47 | 0xD1BB67F1u, 0xA6BC5767u, 0x3FB506DDu, 0x48B2364Bu, 48 | 0xD80D2BDAu, 0xAF0A1B4Cu, 0x36034AF6u, 0x41047A60u, 49 | 0xDF60EFC3u, 0xA867DF55u, 0x316E8EEFu, 0x4669BE79u, 50 | 0xCB61B38Cu, 0xBC66831Au, 0x256FD2A0u, 0x5268E236u, 51 | 0xCC0C7795u, 0xBB0B4703u, 0x220216B9u, 0x5505262Fu, 52 | 0xC5BA3BBEu, 0xB2BD0B28u, 0x2BB45A92u, 0x5CB36A04u, 53 | 0xC2D7FFA7u, 0xB5D0CF31u, 0x2CD99E8Bu, 0x5BDEAE1Du, 54 | 55 | 0x9B64C2B0u, 0xEC63F226u, 0x756AA39Cu, 0x026D930Au, 56 | 0x9C0906A9u, 0xEB0E363Fu, 0x72076785u, 0x05005713u, 57 | 0x95BF4A82u, 0xE2B87A14u, 0x7BB12BAEu, 0x0CB61B38u, 58 | 0x92D28E9Bu, 0xE5D5BE0Du, 0x7CDCEFB7u, 0x0BDBDF21u, 59 | 0x86D3D2D4u, 0xF1D4E242u, 0x68DDB3F8u, 0x1FDA836Eu, 60 | 0x81BE16CDu, 0xF6B9265Bu, 0x6FB077E1u, 0x18B74777u, 61 | 0x88085AE6u, 0xFF0F6A70u, 0x66063BCAu, 0x11010B5Cu, 62 | 0x8F659EFFu, 0xF862AE69u, 0x616BFFD3u, 0x166CCF45u, 63 | 0xA00AE278u, 0xD70DD2EEu, 0x4E048354u, 0x3903B3C2u, 64 | 0xA7672661u, 0xD06016F7u, 0x4969474Du, 0x3E6E77DBu, 65 | 0xAED16A4Au, 0xD9D65ADCu, 0x40DF0B66u, 0x37D83BF0u, 66 | 0xA9BCAE53u, 0xDEBB9EC5u, 0x47B2CF7Fu, 0x30B5FFE9u, 67 | 0xBDBDF21Cu, 0xCABAC28Au, 0x53B39330u, 0x24B4A3A6u, 68 | 0xBAD03605u, 0xCDD70693u, 0x54DE5729u, 0x23D967BFu, 69 | 0xB3667A2Eu, 0xC4614AB8u, 0x5D681B02u, 0x2A6F2B94u, 70 | 0xB40BBE37u, 0xC30C8EA1u, 0x5A05DF1Bu, 0x2D02EF8Du, 71 | ) 72 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/gxlib/inc.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib 2 | 3 | const val GXLF_DOUBLESIZE = 0x01u 4 | const val GXLF_LANDSCAPE = 0x02u 5 | const val GXLF_DEV_LANDSCAPE = 0x04u 6 | const val GXLF_DEV_VGARES = 0x08u 7 | const val GXLF_LHANDER = 0x10u 8 | const val GXLF_ENABLESOUND = 0x20u 9 | const val GXLF_REALVGA = 0x40u 10 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/gxlib/math.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib 2 | 3 | const val PI = 3.1415926535897932384626433832795f 4 | 5 | fun int_sqrt(n: UInt): UInt { 6 | @Suppress("NAME_SHADOWING") var n = n 7 | var root = 0u 8 | var tval: UInt 9 | 10 | for (i in 15 downTo 0) { 11 | tval = root + (1u shl i) 12 | 13 | if (n >= tval shl i) { 14 | n -= tval shl i 15 | root = root or (2u shl i) 16 | } 17 | } 18 | 19 | return root shr 1 20 | } 21 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/gxlib/popupview.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib 2 | 3 | import com.github.servb.pph.util.helpertype.and 4 | import com.soywiz.korma.geom.* 5 | 6 | abstract class iPopupView : iView { 7 | 8 | constructor(viewMgr: iViewMgr) : super( 9 | viewMgr, 10 | IRectangleInt(0, 0, 0, 0), 11 | VIEWCLSID.GENERIC_VIEWPORT, 12 | 0u, 13 | ViewState.Enabled.v 14 | ) 15 | 16 | final override fun `$destruct`() { 17 | // empty. seems like overriding behavior of the iView (of removing children). 18 | // seems logical because popup view shouldn't have children 19 | } 20 | 21 | fun TrackPopup(pos: IPointInt, bound: IRectangleInt, alignment: Alignment) { 22 | val nsiz = PopupViewSize() 23 | val msiz = PopupViewMinSize() 24 | nsiz.width = maxOf(nsiz.width, msiz.width) 25 | nsiz.height = maxOf(nsiz.height, msiz.height) 26 | 27 | val orc = RectangleInt(bound) 28 | 29 | if ((alignment and Alignment.AlignRight) != 0) { 30 | orc.width = pos.x - bound.x 31 | } else if ((alignment and Alignment.AlignLeft) != 0) { 32 | orc.x = pos.x 33 | } 34 | 35 | if ((alignment and Alignment.AlignBottom) != 0) { 36 | orc.height = pos.y - bound.y 37 | } else if ((alignment and Alignment.AlignTop) != 0) { 38 | orc.y = pos.y 39 | } 40 | 41 | m_Rect.setTo(AlignRect(nsiz, orc, alignment)) 42 | 43 | if (m_Rect.x < bound.x) { 44 | m_Rect.x = bound.x 45 | } else if (m_Rect.right > bound.right) { 46 | m_Rect.x = bound.x + (bound.width - m_Rect.width) 47 | } 48 | 49 | if (m_Rect.y < bound.y) { 50 | m_Rect.y = bound.y 51 | } else if (m_Rect.bottom > bound.bottom) { 52 | m_Rect.y = bound.y + (bound.height - m_Rect.height) 53 | } 54 | 55 | OnTrackPopup(m_Rect) 56 | SetVisible(true) 57 | } 58 | 59 | fun HidePopup() { 60 | OnHidePopup() 61 | SetVisible(false) 62 | } 63 | 64 | abstract fun PopupViewSize(): SizeInt 65 | abstract fun PopupViewMinSize(): SizeInt 66 | open fun OnTrackPopup(clRect: IRectangleInt) {} 67 | open fun OnHidePopup() {} 68 | } 69 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/gxlib/timer.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib 2 | 3 | import com.soywiz.klock.DateTime 4 | 5 | // todo: using UTC, is it OK? (can cause problems when outputting dates to screen, check it) 6 | fun GetTickCount(): UInt = DateTime.now().unixMillisLong.toUInt() 7 | 8 | class iTimer { 9 | 10 | private var m_LastTime: UInt 11 | 12 | constructor() { 13 | m_LastTime = GetTickCount() 14 | } 15 | 16 | fun Init(): Boolean { 17 | return true 18 | } 19 | 20 | fun GetCurTime(): UInt { 21 | return GetTickCount().also { m_LastTime = it } 22 | } 23 | 24 | fun GetStep(): UInt { 25 | val ntime = GetTickCount() 26 | val sval: UInt 27 | if (ntime == m_LastTime) { 28 | return 0u 29 | } else if (ntime > m_LastTime) { 30 | sval = ntime - m_LastTime 31 | } else { 32 | sval = (0xFFFF_FFFFu - m_LastTime) + ntime 33 | } 34 | m_LastTime = ntime 35 | return sval 36 | } 37 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/gxlib/topmostview.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib 2 | 3 | import com.github.servb.pph.util.asRectangle 4 | import com.github.servb.pph.util.helpertype.or 5 | import com.soywiz.korma.geom.IPointInt 6 | 7 | abstract class iTopmostView : iView { 8 | 9 | constructor(pViewMgr: iViewMgr) : super( 10 | pViewMgr, 11 | pViewMgr.Metrics().asRectangle(), 12 | VIEWCLSID.GENERIC_VIEWPORT, 13 | 0u, 14 | ViewState.Visible or ViewState.Enabled 15 | ) 16 | 17 | override fun `$destruct`() {} 18 | 19 | suspend fun ProcessMessage(msg: iInput.iEntry): Boolean { 20 | when (msg) { 21 | is iInput.iEntry.MouseMove -> MouseTrack(IPointInt(msg.px, msg.py)) 22 | is iInput.iEntry.MouseDown -> MouseDown(IPointInt(msg.px, msg.py)) 23 | is iInput.iEntry.MouseUp -> MouseUp(IPointInt(msg.px, msg.py)) 24 | is iInput.iEntry.KeyDown -> KeyDown(msg.key) 25 | is iInput.iEntry.KeyUp -> KeyUp(msg.key) 26 | } 27 | return true 28 | } 29 | 30 | fun KeyDown(key: iKbdKey): Boolean { 31 | return OnKeyDown(key) 32 | } 33 | 34 | fun KeyUp(key: iKbdKey): Boolean { 35 | return OnKeyUp(key) 36 | } 37 | 38 | open fun OnKeyDown(key: iKbdKey): Boolean = false 39 | open fun OnKeyUp(key: iKbdKey): Boolean = false 40 | } 41 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/iolib/xe/dib.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.iolib.xe 2 | 3 | import com.soywiz.korim.bitmap.Bitmap32 4 | import com.soywiz.korma.geom.PointInt 5 | import com.soywiz.korma.geom.RectangleInt 6 | 7 | fun FindSolidArea(dib: Bitmap32): RectangleInt { 8 | val ltpt = PointInt(dib.width - 1, dib.height - 1) 9 | val rbpt = PointInt(0, 0) 10 | 11 | repeat(dib.height) { yy -> 12 | repeat(dib.width) { xx -> 13 | if (dib[xx, yy].a != 0) { 14 | if (xx < ltpt.x) { 15 | ltpt.x = xx 16 | } 17 | if (yy < ltpt.y) { 18 | ltpt.y = yy 19 | } 20 | if (xx > rbpt.x) { 21 | rbpt.x = xx 22 | } 23 | if (yy > rbpt.y) { 24 | rbpt.y = yy 25 | } 26 | } 27 | } 28 | } 29 | 30 | return RectangleInt(ltpt.x, ltpt.y, rbpt.x - ltpt.x + 1, rbpt.y - ltpt.y + 1) 31 | } 32 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/IsoMetric.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common 2 | 3 | import com.github.servb.pph.util.SizeT 4 | import com.soywiz.korma.geom.IPointInt 5 | import com.soywiz.korma.geom.PointInt 6 | import com.soywiz.korma.geom.SizeInt 7 | 8 | // cf - Cell factor of isometric cell (cf = CellWidth/ATOM_WIDTH) 9 | 10 | const val ATOM_WIDTH: SizeT = 8 11 | const val ATOM_HEIGHT: SizeT = 3 12 | 13 | data class IsoMetric(private val cellFactor: SizeT) { 14 | 15 | val cellWidth: SizeT get() = getCellWidth(cellFactor) 16 | val cellHeight: SizeT get() = getCellHeight(cellFactor) 17 | 18 | val cellSize: SizeInt get() = SizeInt(cellWidth, cellHeight) 19 | 20 | val cellStepX: SizeT get() = cellWidth / 2 21 | val cellStepY: SizeT get() = (cellHeight + 1) / 2 22 | 23 | fun getScreenOffset(cellOffset: IPointInt): PointInt = PointInt( 24 | (cellOffset.x - cellOffset.y) * cellStepX, 25 | (cellOffset.x + cellOffset.y) * cellStepY, 26 | ) 27 | 28 | fun map2Screen(pos: IPointInt): PointInt { 29 | val n = cellFactor * 2 30 | 31 | return PointInt( 32 | 2 * n * (pos.x - pos.y), 33 | n * (pos.x + pos.y) 34 | ) 35 | } 36 | 37 | fun screen2Map(pos: IPointInt): PointInt { 38 | val n = 2 * cellFactor 39 | val coef = 4 * n 40 | 41 | val n2 = n * 2 42 | val n4 = n * 4 43 | 44 | val px = coef * pos.x 45 | val py = coef * (pos.y - cellHeight / 2) 46 | 47 | val px2 = px + if (px / 2 <= py) n4 else 0 48 | 49 | var nx = px / n4 + py / n2 50 | var ny = -px2 / n4 + py / n2 51 | 52 | nx += if (nx > 0) n2 else -n2 53 | ny += if (ny > 0) n2 else -n2 54 | 55 | return PointInt(nx / coef, ny / coef) 56 | } 57 | 58 | companion object { 59 | 60 | fun getCellWidth(cellFactor: SizeT) = cellFactor * ATOM_WIDTH 61 | fun getCellHeight(cellFactor: SizeT) = (getCellWidth(cellFactor) - 1) / 2 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/Serialize.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common 2 | 3 | import com.github.servb.pph.gxlib.ReadS16 4 | import com.github.servb.pph.gxlib.ReadString 5 | import com.github.servb.pph.gxlib.Write 6 | import com.soywiz.kmem.ByteArrayBuilder 7 | import com.soywiz.korio.stream.AsyncInputStream 8 | import com.soywiz.korio.stream.AsyncOutputStream 9 | import com.soywiz.korma.geom.IPointInt 10 | import com.soywiz.korma.geom.PointInt 11 | 12 | fun Serialize(buff: ByteArrayBuilder, point: IPointInt) { 13 | buff.Write(point.x.toShort()) 14 | buff.Write(point.y.toShort()) 15 | } 16 | 17 | suspend fun Serialize(buff: AsyncOutputStream, point: IPointInt) { 18 | buff.Write(point.x.toShort()) 19 | buff.Write(point.y.toShort()) 20 | } 21 | 22 | suspend fun DeserializePoint(buff: AsyncInputStream): PointInt { 23 | return PointInt( 24 | x = buff.ReadS16().toInt(), 25 | y = buff.ReadS16().toInt(), 26 | ) 27 | } 28 | 29 | fun Serialize(buff: ByteArrayBuilder, string: String) { 30 | buff.Write(string) 31 | } 32 | 33 | suspend fun Serialize(buff: AsyncOutputStream, string: String) { 34 | buff.Write(string) 35 | } 36 | 37 | suspend fun DeserializeString(buff: AsyncInputStream): String { 38 | return buff.ReadString() 39 | } 40 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/SortArray.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common 2 | 3 | import com.github.servb.pph.util.SizeT 4 | 5 | open class iSortArray { 6 | 7 | data class iEntry(val idx: Int, val value: T) 8 | 9 | protected val m_Array: MutableList> = mutableListOf() 10 | 11 | fun GetPtr(): MutableList> = m_Array 12 | 13 | fun Init(other: iSortArray) { 14 | this.setTo(other) 15 | } 16 | 17 | fun setTo(other: iSortArray) { 18 | this.m_Array.clear() 19 | this.m_Array.addAll(other.m_Array) 20 | } 21 | 22 | fun Pop(): E = m_Array.removeLast().value 23 | 24 | fun FirstIdx(): Int = m_Array.first().idx 25 | fun LastIdx(): Int = m_Array.last().idx 26 | 27 | fun Last(): E = m_Array.last().value 28 | 29 | fun RemoveAt(idx: Int) { 30 | m_Array.removeAt(idx) 31 | } 32 | 33 | // indexes: from smaller to bigger 34 | fun Insert(value: E, idx: Int) { 35 | var length: SizeT = m_Array.size 36 | if (length == 0 || m_Array[length - 1].idx <= idx) { 37 | m_Array.add(iEntry(idx, value)) 38 | return 39 | } 40 | 41 | if (idx < m_Array.first().idx) { 42 | m_Array.add(0, iEntry(idx, value)) 43 | return 44 | } 45 | 46 | var first: SizeT = 0 47 | while (length > 0) { 48 | val half: SizeT = length shr 1 49 | val middle = first + half 50 | if (m_Array[middle].idx <= idx) { 51 | first = middle + 1 52 | length = length - half - 1 53 | } else { 54 | length = half 55 | } 56 | } 57 | m_Array.add(first, iEntry(idx, value)) 58 | } 59 | 60 | fun Cleanup() { 61 | m_Array.clear() 62 | } 63 | 64 | fun Size(): SizeT = m_Array.size 65 | 66 | operator fun get(idx: SizeT): iEntry = m_Array[idx] 67 | fun Value(idx: SizeT): E = m_Array[idx].value 68 | fun Index(idx: SizeT): Int = m_Array[idx].idx 69 | 70 | // todo: create tests 71 | // fun SelfTest() 72 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/army/CreatGroup.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.army 2 | 3 | import com.github.servb.pph.pheroes.common.common.RANDOM_QUANTITY 4 | import com.github.servb.pph.pheroes.common.common.RAND_VAL 5 | import com.github.servb.pph.pheroes.common.creature.CreatureType 6 | 7 | val creatGrowthDivider = listOf(9, 9, 10, 10, 11, 12) 8 | 9 | abstract class CreatGroupC { 10 | abstract val type: CreatureType 11 | abstract val count: Int 12 | 13 | val isValid: Boolean get() = type != CreatureType.UNKNOWN 14 | val groupPower: UInt get() = (count * type.descriptor!!.pidx).toUInt() 15 | } 16 | 17 | data class CreatGroup( 18 | override var type: CreatureType = CreatureType.UNKNOWN, 19 | override var count: Int = RANDOM_QUANTITY 20 | ) : CreatGroupC() { 21 | 22 | fun reset(type: CreatureType = CreatureType.UNKNOWN, count: Int = RANDOM_QUANTITY) { 23 | this.type = type 24 | this.count = count 25 | } 26 | 27 | fun grow(weeks: UInt = 1u) { 28 | check(count != RAND_VAL) 29 | 30 | for (i in 1u..weeks) { 31 | var div = creatGrowthDivider[type.descriptor!!.level - 1] 32 | if (count < type.descriptor!!.growth * 2) { 33 | div /= 2 34 | } 35 | 36 | count += (count + (div - 1)) / 2 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/castle/CastleType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.castle 2 | 3 | import com.github.servb.pph.pheroes.common.common.HeroType 4 | import com.github.servb.pph.pheroes.common.magic.MagicSchoolMask 5 | import com.github.servb.pph.pheroes.common.magic.SpellFilter 6 | import com.github.servb.pph.pheroes.common.magic.SpellLevelMask 7 | import com.github.servb.pph.pheroes.common.magic.SpellTypeMask 8 | import com.github.servb.pph.util.helpertype.CountValueEnum 9 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 10 | 11 | enum class CastleType( 12 | override val v: Int, 13 | val heroType: HeroType? = null, 14 | val CTL_MAGE_GUILD_FILTER_0: SpellFilter? = null, 15 | val CTL_MAGE_GUILD_FILTER_1: SpellFilter? = null, 16 | val CTL_MAGE_GUILD_FILTER_2: SpellFilter? = null, 17 | val CTL_MAGE_GUILD_FILTER_3: SpellFilter? = null, 18 | val CTL_MAGE_GUILD_FILTER_4: SpellFilter? = null, 19 | val CTL_MAGE_GUILD_SPELLS_0: UByte? = null, 20 | val CTL_MAGE_GUILD_SPELLS_1: UByte? = null, 21 | val CTL_MAGE_GUILD_SPELLS_2: UByte? = null, 22 | val CTL_MAGE_GUILD_SPELLS_3: UByte? = null, 23 | val CTL_MAGE_GUILD_SPELLS_4: UByte? = null, 24 | ) : UniqueValueEnum, CountValueEnum { 25 | CITADEL( 26 | 0, 27 | HeroType.KNIGHT, 28 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.FIRST, MagicSchoolMask.GOOD), 29 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.SECOND, MagicSchoolMask.GOOD), 30 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.THIRD, MagicSchoolMask.GOOD), 31 | null, 32 | null, 33 | 5u, 34 | 4u, 35 | 3u, 36 | null, 37 | null 38 | ), 39 | STRONGHOLD( 40 | 1, 41 | HeroType.BARBARIAN, 42 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.FIRST, MagicSchoolMask.EVIL), 43 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.SECOND, MagicSchoolMask.EVIL), 44 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.THIRD, MagicSchoolMask.EVIL), 45 | null, 46 | null, 47 | 5u, 48 | 4u, 49 | 3u, 50 | null, 51 | null 52 | ), 53 | TOWER( 54 | 2, 55 | HeroType.WIZARD, 56 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.FIRST, MagicSchoolMask.GOOD), 57 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.SECOND, MagicSchoolMask.GOOD), 58 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.THIRD, MagicSchoolMask.GOOD), 59 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.FOURTH, MagicSchoolMask.GOOD), 60 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.FIFTH, MagicSchoolMask.GOOD), 61 | 5u, 62 | 4u, 63 | 3u, 64 | 2u, 65 | 1u 66 | ), 67 | DUNGEON( 68 | 3, 69 | HeroType.WARLOCK, 70 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.FIRST, MagicSchoolMask.EVIL), 71 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.SECOND, MagicSchoolMask.EVIL), 72 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.THIRD, MagicSchoolMask.EVIL), 73 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.FOURTH, MagicSchoolMask.EVIL), 74 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.FIFTH, MagicSchoolMask.EVIL), 75 | 5u, 76 | 4u, 77 | 3u, 78 | 2u, 79 | 1u 80 | ), 81 | FORTRESS( 82 | 4, 83 | HeroType.SORCERESS, 84 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.FIRST, MagicSchoolMask.GOOD), 85 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.SECOND, MagicSchoolMask.GOOD), 86 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.THIRD, MagicSchoolMask.GOOD), 87 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.FOURTH, MagicSchoolMask.GOOD), 88 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.FIFTH, MagicSchoolMask.GOOD), 89 | 5u, 90 | 4u, 91 | 3u, 92 | 2u, 93 | 1u 94 | ), 95 | NECROPOLIS( 96 | 5, 97 | HeroType.NECROMANCER, 98 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.FIRST, MagicSchoolMask.EVIL), 99 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.SECOND, MagicSchoolMask.EVIL), 100 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.THIRD, MagicSchoolMask.EVIL), 101 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.FOURTH, MagicSchoolMask.EVIL), 102 | SpellFilter(SpellTypeMask.ALL, SpellLevelMask.FIFTH, MagicSchoolMask.EVIL), 103 | 5u, 104 | 4u, 105 | 3u, 106 | 2u, 107 | 1u 108 | ), 109 | RANDOM(6), 110 | COUNT(7), 111 | INVALID(0xFF); 112 | } 113 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/cnst_gfx.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common 2 | 3 | import com.github.servb.pph.pheroes.game.SpriteId 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | /* 7 | * TODO: Use an external file. 8 | * This file is automatically generated by Pocket Heroes resource compiler. 9 | * Do not modify this file -- YOUR CHANGES WILL BE ERASED! 10 | */ 11 | 12 | enum class GfxId(override val v: Int) : UniqueValueEnum { 13 | 14 | PDGG_BANNER_POCKETLAND(0), 15 | PDGG_BKTILE(1), 16 | PDGG_BKTILE2(2), 17 | PDGG_CTILE(3), 18 | PDGG_PLTILES(4), 19 | PDGG_STONES(10), 20 | PDGG_CHECKBOX(16), 21 | PDGG_DLG_HTILES(17), 22 | PDGG_DLG_VTILES(24), 23 | PDGG_DLG_CORNERS(31), 24 | PDGG_DLG_CORNERS_SMALL(35), 25 | PDGG_DLG_BTN(42), 26 | PDGG_ART_CELLS(45), 27 | PDGG_BTN_MAINMENU(48), 28 | PDGG_BTN_DISK(49), 29 | PDGG_BTN_PUZZLEMAP(50), 30 | PDGG_BTN_CURSOR(51), 31 | PDGG_BTN_HERO(52), 32 | PDGG_BTN_CASTLE(53), 33 | PDGG_BTN_HEROPROPS(54), 34 | PDGG_BTN_CASTLEPROPS(55), 35 | PDGG_BTN_HORSE(56), 36 | PDGG_BTN_CASTSPELL(57), 37 | PDGG_BTN_DIG(58), 38 | PDGG_BTN_NEXTHERO(59), 39 | PDGG_BTN_NEXTCASTLE(60), 40 | PDGG_BTN_CENTER(61), 41 | PDGG_BTN_MINIMAP(62), 42 | PDGG_BTN_DISMISS(63), 43 | PDGG_BTN_MAPSIZE(64), 44 | PDGG_BTN_PLAYERS_COUNT(65), 45 | PDGG_BTN_ATTACK(66), 46 | PDGG_BTN_SHOOT(67), 47 | PDGG_BTN_INFO(68), 48 | PDGG_BTN_DEFEND(69), 49 | PDGG_BTN_AUTOBATTLE(70), 50 | PDGG_BTN_ENDTURN(71), 51 | PDGG_BTN_CLOSE(72), 52 | PDGG_BTN_MAX(73), 53 | PDGG_BTN_SPLIT(74), 54 | PDGG_BTN_BKSP(75), 55 | PDGG_BTN_MINUS(76), 56 | PDGG_BTN_PLUS(77), 57 | PDGG_BTN_NEXT(78), 58 | PDGG_BTN_PREV(79), 59 | PDGG_SCRBAR_BTNS(80), 60 | PDGG_MINISLD_BTNS(84), 61 | PDGG_TAB_SKILLS(86), 62 | PDGG_TAB_ARTIFACTS(87), 63 | PDGG_TAB_ARMY(88), 64 | PDGG_TAB_SPELLBOOK(89), 65 | PDGG_TAB_QUESTLOG(90), 66 | PDGG_TAB_BUILD_CTR(91), 67 | PDGG_TAB_MGUILD(92), 68 | PDGG_TAB_CHEST(93), 69 | PDGG_TAB_MARKET(94), 70 | PDGG_TAB_TAVERN(95), 71 | PDGG_ICN_MANA(96), 72 | PDGG_ICN_EXPERIENCE(97), 73 | PDGG_ICN_PSKILLS(98), 74 | PDGG_ICN_MORALE(102), 75 | PDGG_ICN_LUCK(105), 76 | PDGG_ICN_DAMAGE(108), 77 | PDGG_ICN_LIFES(109), 78 | PDGG_ICN_SPEED(110), 79 | PDGG_ICN_GROWTH(111), 80 | PDGG_ICN_BATTERY(112), 81 | PDGG_ICN_CATAPULT(113), 82 | PDGG_ICN_TURRET(114), 83 | PDGG_DGLYPH_MORALE(115), 84 | PDGG_DGLYPH_LUCK(118), 85 | PDGG_DGLYPH_MANA(121), 86 | PDGG_DGLYPH_MOVES(122), 87 | PDGG_DGLYPH_GOLD(123), 88 | PDGG_DGLYPH_EXP(124), 89 | PDGG_DGLYPH_PRSKILLS(125), 90 | PDGG_CNST_STATE_GLYPH(129), 91 | PDGG_HDOLL_WIRE(132), 92 | PDGG_HDOLL_BODY(133), 93 | PDGG_HDOLL_CAPE(134), 94 | PDGG_ICN_BUILT(135), 95 | PDGG_UNK_HERO48(136), 96 | PDGG_UNK_HERO(137), 97 | PDGG_UNK_CASTLE(138), 98 | PDGG_MSCHICN_S(139), 99 | PDGG_ICN_ALL_SCHOOLS(147), 100 | PDGG_ICN_FAVORITES(148), 101 | PDGG_ICN_DIF_LEVEL(149), 102 | PDGG_ICN_PLT_AI(154), 103 | PDGG_ICN_PLT_HUMAN(155), 104 | PDGG_FLAGS(156), 105 | PDGG_THFLAGS(168), 106 | PDGG_EMBLEMS(174), 107 | PDGG_GRID_CELL(180), 108 | PDGG_GRID_HEX(181), 109 | PDGG_HEX_CELL(182), 110 | PDGG_HEX_TARGET_CELL(183), 111 | PDGG_MELEE_CURSOR(184), 112 | PDGG_SHOOT_CURSOR(196), 113 | PDGG_SPELL_CURSOR(199), 114 | PDGG_SURF_TILES(200), 115 | PDGG_TRANS_TILES(248), 116 | PDGG_WS_TILES(262), 117 | PDGG_FOG_TILES(276), 118 | PDGG_HEROES(291), 119 | PDGG_PATH(723), 120 | PDGG_TRACK(735), 121 | PDGG_SEC_SKILLS(738), 122 | PDGG_CTL_SICONS(760), 123 | PDGG_BTL_TOMB(781), 124 | PDGG_BTL_RECDMG(782), 125 | PDGG_BTL_RESIST_SPELL(783), 126 | PDGG_SPELL_ICONS(784), 127 | PDGG_SPELLSCROLL_UNROLLED(830), 128 | PDGG_SPELLSCROLL_ROLLED(831), 129 | PDGG_EVENT(832), 130 | PDGG_ULTIMATE_ART(833), 131 | PDGG_HOLES(834), 132 | PDGG_CREAT_PERKS(839), 133 | PDGG_MAP_BORDER(860), 134 | PDGG_MINIMON(874), 135 | PDGG_MINIMONF(1054), 136 | PDGG_RMINIMON(1099), 137 | PDGG_RMINIMONF(1279), 138 | PDGG_CREAT_ICONS(1324), 139 | PDGG_RES_ICONS(1369), 140 | PDGG_RES_MINI_ICONS(1376), 141 | PDGG_RES_BIG_ICONS(1383), 142 | PDGG_RES_CMFIRE(1390), 143 | PDGG_RES_CHEST(1391), 144 | PDGG_RES_LAMP(1392), 145 | PDGG_RES_MCRYST(1393), 146 | PDGG_RES_SPELL_SCROLL(1394), 147 | PDGG_KEY_GUARDS(1395), 148 | PDGG_KEY_GUARDS_SNOW(1401), 149 | PDGG_COMBAT_MOAT(1407), 150 | PDGG_COMBAT_UWALL(1408), 151 | PDGG_COMBAT_BWALL(1411), 152 | PDGG_COMBAT_UTOWER(1414), 153 | PDGG_COMBAT_BTOWER(1417), 154 | PDGG_COMBAT_GUTOWER(1420), 155 | PDGG_COMBAT_GBTOWER(1421), 156 | PDGG_COMBAT_UTURRET(1422), 157 | PDGG_COMBAT_BTURRET(1425), 158 | PDGG_COMBAT_BRIDGE(1428), 159 | PDGG_PEL_RNDWALL(1431), 160 | PDGG_PEL_CTDWALL(1447), 161 | PDGG_PEL_STHWALL(1463), 162 | PDGG_PEL_TWRWALL(1479), 163 | PDGG_PEL_DNGWALL(1495), 164 | PDGG_PEL_FRTWALL(1511), 165 | PDGG_PEL_NCRWALL(1527), 166 | PDGG_PEL_SROAD(1543), 167 | PDGG_PEL_DROAD(1559), 168 | PDGG_PEL_SNROAD(1575), 169 | PDGG_PEL_RIVER(1591), 170 | PDGG_PEL_LRIVER(1607); 171 | 172 | operator fun invoke(offset: Int): SpriteId = v + offset 173 | } 174 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/Common.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.gxlib.iRandTable 4 | import com.soywiz.korma.geom.IPointInt 5 | 6 | const val EMAP_FILE_HDR_KEY: UInt = 0x76235278u 7 | const val EMAP_FILE_VERSION: UInt = 0x19u 8 | 9 | val GMAP_FILE_HDR_KEY: UInt = 10 | ('G'.code or ('M'.code shl 8) or ('A'.code shl 16) or ('P'.code shl 24)).toUInt() 11 | const val GMAP_FILE_VERSION: UShort = 0x39u 12 | 13 | val GOBJ_FILE_HDR_KEY: UInt = 14 | ('G'.code or ('O'.code shl 8) or ('B'.code shl 16) or ('J'.code shl 24)).toUInt() 15 | const val GOBJ_FILE_VERSION: UShort = 0x07u 16 | 17 | val GFNT_FILE_HDR_KEY: UInt = 18 | ('G'.code or ('F'.code shl 8) or ('N'.code shl 16) or ('T'.code shl 24)).toUInt() 19 | const val GFNT_FILE_VERSION: UShort = 0x01u 20 | 21 | const val RANDOM_QUANTITY = 0 22 | const val RAND_VAL = -1 23 | 24 | fun CalcCellSeqGame(pnt: IPointInt, maxv: UInt): UInt { 25 | var result = pnt.x.toUInt() 26 | result += (pnt.y.toUInt() shl 16).inv() 27 | result = result xor (pnt.x.toUInt() shr 5) 28 | result += pnt.y.toUInt() shl 3 29 | result = result xor (pnt.x.toUInt() shr 13) 30 | result += (pnt.y.toUInt() shl 9).inv() 31 | result = result xor (result shr 17) 32 | 33 | val idx = (result xor (result shr 8) xor (result shr 16) and 255u).toInt() 34 | result = iRandTable[idx] 35 | 36 | return result % maxv 37 | } 38 | 39 | fun CalcCellSeqGameInEditor(pnt: IPointInt, maxv: Int): Int { 40 | TODO("Uncomment when editor will be coded") 41 | // int result = pnt.x; 42 | // result += ~(pnt.y << 16); 43 | // result ^= (pnt.x >> 5); 44 | // result += (pnt.y << 3); 45 | // result ^= (pnt.x >> 13); 46 | // result += ~(pnt.y << 9); 47 | // result ^= (result >> 17); 48 | // 49 | // final int idx = (result ^ (result >> 8) ^ (result >> 16)) & 255; 50 | // result = iTables.crc32[idx]; // <== 51 | // 52 | // return result % maxv; 53 | } 54 | 55 | const val DEF_HERO_SCOUTING = 4 56 | const val DEF_HERO_MYSTICISM = 1 57 | const val DEF_HERO_MOVES = 60 58 | 59 | private val MINERAL_EXCH_RATE = listOf(1, 250, 250, 500, 500, 500, 500) 60 | 61 | fun MineralExchRate(from: MineralType, to: MineralType, mlvl: Int): FractionCoeff { 62 | val fromIdx = from.v 63 | val toIdx = to.v 64 | 65 | return FractionCoeff( 66 | MINERAL_EXCH_RATE[fromIdx] * (mlvl + 1), 67 | 10 * 2 * MINERAL_EXCH_RATE[toIdx] 68 | ) 69 | } 70 | 71 | val MINERALS_DIVIDER = listOf(1000, 2, 2, 1, 1, 1, 1) 72 | 73 | private infix fun Int.x(other: Int): IPointInt = IPointInt(this, other) 74 | 75 | val HERO_FLAG_ANCHOR = listOf( 76 | 4 x 7, 4 x 5, 4 x 4, 4 x 5, 4 x 7, 4 x 6, 4 x 4, 4 x 5, 4 x 6, 77 | 8 x 7, 9 x 7, 8 x 7, 9 x 8, 10 x 8, 10 x 7, 9 x 7, 8 x 7, 7 x 7, 78 | 11 x 8, 12 x 8, 11 x 8, 10 x 8, 10 x 9, 9 x 9, 10 x 8, 11 x 8, 10 x 8, 79 | 13 x 7, 14 x 7, 13 x 8, 11 x 9, 13 x 9, 14 x 10, 14 x 9, 14 x 8, 12 x 7, 80 | 32 x 8, 32 x 9, 32 x 10, 32 x 8, 32 x 9, 32 x 10, 32 x 11, 32 x 8, 32 x 9, 81 | 20 x 7, 19 x 7, 20 x 8, 19 x 9, 20 x 9, 19 x 10, 19 x 9, 19 x 8, 22 x 7, 82 | 22 x 8, 21 x 8, 22 x 8, 23 x 8, 23 x 9, 24 x 9, 23 x 8, 22 x 8, 23 x 8, 83 | 25 x 7, 24 x 7, 25 x 7, 24 x 8, 23 x 8, 23 x 7, 24 x 7, 25 x 7, 26 x 7, 84 | ) 85 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/DifficultyLevel.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.UndefinedCountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | /** TODO: Provide documentation, provide tests. */ 7 | enum class DifficultyLevel( 8 | override val v: Int, 9 | val human: MineralSetC? = null, 10 | val computer: MineralSetC? = null 11 | ) : UniqueValueEnum, UndefinedCountValueEnum { 12 | UNDEFINED(-1), 13 | 14 | EASY( 15 | 0, 16 | MineralSet(15000, 30, 30, 15, 15, 15, 15), 17 | MineralSet(2500, 5, 5, 2, 2, 2, 2) 18 | ), 19 | 20 | NORMAL( 21 | 1, 22 | MineralSet(10000, 20, 20, 10, 10, 10, 10), 23 | MineralSet(5000, 10, 10, 5, 5, 5, 5) 24 | ), 25 | 26 | HARD( 27 | 2, 28 | MineralSet(5000, 10, 10, 5, 5, 5, 5), 29 | MineralSet(15000, 30, 30, 15, 15, 15, 15) 30 | ), 31 | 32 | EXPERT( 33 | 3, 34 | MineralSet(2500, 5, 5, 2, 2, 2, 2), 35 | MineralSet(25000, 50, 50, 25, 25, 25, 25) 36 | ), 37 | 38 | IMPOSSIBLE( 39 | 4, 40 | MineralSet(0, 0, 0, 0, 0, 0, 0), 41 | MineralSet(50000, 80, 80, 40, 40, 40, 40) 42 | ), 43 | 44 | COUNT(5); 45 | } 46 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/FractionCoeff.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | data class FractionCoeff(var num: Int, var denum: Int) { 4 | constructor() : this(-1, -1) 5 | 6 | fun IsValid(): Boolean { 7 | return num != -1 && denum != -1 8 | } 9 | 10 | fun GetNormalized(): FractionCoeff { 11 | return when { 12 | num > denum -> FractionCoeff(num / denum, 1) 13 | denum > num -> FractionCoeff(1, (denum + num - 1) / num) 14 | else -> FractionCoeff(1, 1) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/IdeologyType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | /** Nations and heroes. */ 7 | enum class IdeologyType(override val v: Int) : UniqueValueEnum, CountValueEnum { 8 | NEUTRAL(0), 9 | GOOD(1), 10 | EVIL(2), 11 | COUNT(3); 12 | } 13 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/MapSize.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class MapSize(override val v: Int, val size: Int = -42) : UniqueValueEnum, CountValueEnum { 7 | SMALL(0, 32), 8 | MEDIUM(1, 64), 9 | LARGE(2, 128), 10 | EXTRA_LARGE(3, 256), 11 | COUNT(4); 12 | } 13 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/MineralSet.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | interface MineralSetC { 4 | val quant: IntArray 5 | } 6 | 7 | fun MineralSetC.Has(ms: MineralSetC): Int { 8 | var cnt = 0 9 | for (xx in 0 until MineralType.COUNT.v) { 10 | if (quant[xx] < ms.quant[xx]) { 11 | return 0 12 | } 13 | if (ms.quant[xx] != 0) { 14 | cnt = if (cnt != 0) minOf(cnt, quant[xx] / ms.quant[xx]) else quant[xx] / ms.quant[xx] 15 | } 16 | } 17 | return cnt 18 | } 19 | 20 | operator fun MineralSetC.times(`val`: Int): MineralSetC { 21 | val result = MineralSet() 22 | for (xx in 0 until MineralType.COUNT.v) { 23 | result.quant[xx] = quant[xx] * `val` 24 | } 25 | return result 26 | } 27 | 28 | fun MineralSetC.Empty(): Boolean { 29 | for (xx in 0 until MineralType.COUNT.v) { 30 | if (quant[xx] != 0) { 31 | return false 32 | } 33 | } 34 | return true 35 | } 36 | 37 | fun MineralSetC.DeficientAmount(other: MineralSetC): MineralSetC { 38 | val result = MineralSet() 39 | for (xx in 0 until MineralType.COUNT.v) { 40 | if (other.quant[xx] > quant[xx]) { 41 | result.quant[xx] = other.quant[xx] - quant[xx] 42 | } 43 | } 44 | return result 45 | } 46 | 47 | fun MineralSetC.Intersect(other: MineralSetC): MineralSetC { 48 | val result = MineralSet() 49 | for (xx in 0 until MineralType.COUNT.v) { 50 | result.quant[xx] = minOf(quant[xx], other.quant[xx]) 51 | } 52 | return result 53 | } 54 | 55 | class MineralSet : MineralSetC { 56 | 57 | override var quant: IntArray 58 | 59 | constructor() { 60 | quant = IntArray(MineralType.COUNT.v) 61 | } 62 | 63 | constructor( 64 | gold: Int = 0, 65 | ore: Int = 0, 66 | wood: Int = 0, 67 | mercury: Int = 0, 68 | gem: Int = 0, 69 | crystal: Int = 0, 70 | sulfur: Int = 0 71 | ) { 72 | this.quant = intArrayOf(gold, ore, wood, mercury, gem, crystal, sulfur) 73 | } 74 | 75 | constructor(quant: IntArray) { 76 | this.quant = quant.copyOf() 77 | } 78 | 79 | fun Reset() { 80 | quant.fill(0) 81 | } 82 | 83 | fun Normalize() { 84 | for (xx in 0 until MineralType.COUNT.v) { 85 | if (quant[xx] < 0) { 86 | quant[xx] = 0 87 | } 88 | } 89 | } 90 | 91 | fun setTo(ms: MineralSetC) { 92 | for (xx in 0 until MineralType.COUNT.v) { 93 | quant[xx] = ms.quant[xx] 94 | } 95 | } 96 | 97 | operator fun plusAssign(ms: MineralSetC) { 98 | for (xx in 0 until MineralType.COUNT.v) { 99 | quant[xx] += ms.quant[xx] 100 | } 101 | } 102 | 103 | operator fun minusAssign(ms: MineralSetC) { 104 | for (xx in 0 until MineralType.COUNT.v) { 105 | quant[xx] -= ms.quant[xx] 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/MineralType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.UndefinedCountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class MineralType(override val v: Int) : UniqueValueEnum, UndefinedCountValueEnum { 7 | UNKNOWN(-1), 8 | GOLD(0), 9 | ORE(1), 10 | WOOD(2), 11 | MERCURY(3), 12 | GEMS(4), 13 | CRYSTAL(5), 14 | SULFUR(6), 15 | COUNT(7); 16 | } 17 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/NationType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class NationType( 7 | override val v: Int, 8 | val mask: Int = -42, 9 | val ideology: IdeologyType? = null 10 | ) : UniqueValueEnum, CountValueEnum { 11 | NEUTRAL(0, ideology = IdeologyType.NEUTRAL), 12 | HIGHMEN(1, 0x1, IdeologyType.GOOD), 13 | BARBARIANS(2, 0x2, IdeologyType.EVIL), 14 | WIZARDS(3, 0x4, IdeologyType.GOOD), 15 | BEASTMEN(4, 0x8, IdeologyType.EVIL), 16 | ELVES(5, 0x10, IdeologyType.GOOD), 17 | UNDEADS(6, 0x20, IdeologyType.EVIL), 18 | COUNT(7); 19 | } 20 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/PlayerId.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.gxlib.IDibPixel 4 | import com.github.servb.pph.gxlib.cColor 5 | import com.github.servb.pph.util.helpertype.UndefinedCountValueEnum 6 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 7 | 8 | enum class PlayerId( 9 | override val v: Int, 10 | val color: IDibPixel = cColor.Gray64.pixel, 11 | val textColor: String = "#FE8E", 12 | ) : UniqueValueEnum, UndefinedCountValueEnum { 13 | NEUTRAL(-1), 14 | 15 | RED( 16 | 0, 17 | (0x1Fu shl 11).toUShort(), 18 | "#FF99", 19 | ), 20 | 21 | GREEN( 22 | 1, 23 | (0x30u shl 5).toUShort(), 24 | "#F8E8", 25 | ), 26 | 27 | BLUE( 28 | 2, 29 | 0x1Fu, 30 | "#F99F", 31 | ), 32 | 33 | CYAN( 34 | 3, 35 | ((0x30u shl 5) or 0x1Fu).toUShort(), 36 | "#F7EE", 37 | ), 38 | 39 | MAGENTA( 40 | 4, 41 | ((0x1Du shl 11) or 0x1Fu).toUShort(), 42 | "#FE7E", 43 | ), 44 | 45 | YELLOW( 46 | 5, 47 | ((0x1Du shl 11) or (0x38u shl 5)).toUShort(), 48 | "#FEE7", 49 | ), 50 | 51 | COUNT(6); 52 | } 53 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/PlayerType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class PlayerType(override val v: Int) : UniqueValueEnum, CountValueEnum { 7 | UNDEFINED(0), 8 | HUMAN(1), 9 | COMPUTER(2), 10 | COUNT(3); 11 | } 12 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/PlayerTypeMask.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class PlayerTypeMask(override val v: Int) : UniqueValueEnum, CountValueEnum { 7 | HUMAN_ONLY(0), 8 | COMPUTER_ONLY(1), 9 | HUMAN_OR_COMPUTER(2), 10 | COUNT(3); 11 | } 12 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/SpecialHeroFlag.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | 5 | enum class SpecialHeroFlag( 6 | override val v: Int, 7 | private val description: String? = null 8 | ) : UniqueValueEnum { 9 | INVALID(-1), 10 | NO_RANGE_PENALTY(0, "No range attack penalty"), 11 | SUMMON_RESURRECTION_BOUNS(1, "50% bonus for resurrection and summon spells"), 12 | MANA_RESTORE(2, "Mana restores each day"), 13 | DAMAGE_SPELL_BONUS(3, "Effect from all damage spells increased by 50%"), 14 | NECROMANCY_BONUS(4, "Necromancy skill restores mummies instead of skeletons"); 15 | } 16 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/SurfaceType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.gxlib.IDibPixel 4 | import com.github.servb.pph.gxlib.RGB16 5 | import com.github.servb.pph.util.helpertype.CountValueEnum 6 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 7 | 8 | enum class SurfaceType( 9 | override val v: Int, 10 | val mask: Int = -42, 11 | val moveCost: Int = -42, 12 | val color: IDibPixel = 42u, 13 | ) : UniqueValueEnum, CountValueEnum { 14 | WATER(0, 1 shl 0, 255, RGB16(8, 28, 128)), 15 | SAND(1, 1 shl 1, 12, RGB16(214, 182, 148)), 16 | DIRT(2, 1 shl 2, 6, RGB16(99, 48, 8)), 17 | GRASS(3, 1 shl 3, 6, RGB16(24, 97, 16)), 18 | SWAMP(4, 1 shl 4, 14, RGB16(0, 44, 0)), 19 | LAVA(5, 1 shl 5, 10, RGB16(48, 48, 48)), 20 | WASTELAND(6, 1 shl 6, 8, RGB16(165, 85, 16)), 21 | DESERT(7, 1 shl 7, 12, RGB16(181, 138, 24)), 22 | SNOW(8, 1 shl 8, 10, RGB16(220, 220, 220)), 23 | NEW_DESERT(9, 1 shl 9, 12, RGB16(192, 160, 0)), 24 | PAVEMENT(10, 1 shl 10, 4, RGB16(160, 160, 160)), 25 | NEW_WASTELAND(11, 1 shl 11, 9, RGB16(192, 192, 160)), 26 | COUNT(12); 27 | } 28 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/artifact/ArtifactType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common.artifact 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class ArtifactType(override val v: Int) : UniqueValueEnum, CountValueEnum { 7 | BASIC(0), 8 | FURTSKILL(1), 9 | NEGSPHERE(2), 10 | SHOFWAR(3), 11 | CURSWORD(4), 12 | COUNT(5), 13 | ULTIMATE(0x0F00); 14 | } 15 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/skill/FurtherSkill.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common.skill 2 | 3 | import com.github.servb.pph.pheroes.common.common.skill.FurtherSkill.FurtherSkillType.* 4 | import com.github.servb.pph.util.helpertype.UndefinedCountValueEnum 5 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 6 | 7 | /** 8 | * Further skills (don't forget to edit defines.cpp at map editor). TODO: Provide documentation, provide tests. 9 | */ 10 | enum class FurtherSkill( 11 | override val v: Int, 12 | private val type: FurtherSkillType? = null, 13 | private val description: String? = null 14 | ) : UniqueValueEnum, UndefinedCountValueEnum { 15 | INVALID(-1), 16 | 17 | ATTACK(0, ALL, "Increases Attack skill by 'n'"), 18 | DEFENCE(1, ALL, "Increases Defence skill by 'n'"), 19 | POWER(2, ALL, "Increases Spell power skill by 'n'"), 20 | KNOWLEDGE(3, ALL, "Increases Knowledge skill by 'n'"), 21 | 22 | ACTPTS(4, OVERLAND, "Hero's land movement range is increased by 'n' pts"), 23 | LOGISTICS(5, OVERLAND, "Hero's land movement range is increased by 'n'%"), 24 | PATHFINDING(6, OVERLAND, "Reduce the effects of difficult terrain by 'n'%"), 25 | SCOUTING(7, OVERLAND, "Increases Scouting level by 'n' cells"), 26 | VISION(8, OVERLAND, "Increases Vision level by 'n'"), 27 | BALLISTICS(9, COMBAT), 28 | LEARNING(10, OVERLAND, "Earned experience is increased by 'n'%"), 29 | DIPLOMACY( 30 | 11, 31 | ALL, 32 | """'n'% of creatures normally fleeing from your army offer to join. 33 | |Cost of surrendering is reduced by 'n/2'%""".trimMargin() 34 | ), 35 | NECROMANCY( 36 | 12, 37 | COMBAT, 38 | "'n'% of enemy creatures killed are resurrected as skeletons and added to the hero’s army" 39 | ), 40 | SORCERY(13, COMBAT, "Increases Magic spells power by 'n'%"), 41 | MANAPTS(14, OVERLAND, "Restores 'n' mana points each day"), 42 | INTELLIGENCE(15, OVERLAND, "Maximum spell points is increased by 'n'%"), 43 | WISDOM(16, OVERLAND, "Allows the hero to learn 'n'th level spells and below"), 44 | 45 | MAG_AIR(17, ALL, "Allows the hero to cast 'n'th level spells of Air magic and below"), 46 | MAG_EARTH(18, ALL, "Allows the hero to cast 'n'th level spells of Earth magic and below"), 47 | MAG_FIRE(19, ALL, "Allows the hero to cast 'n'th level spells of Fire magic and below"), 48 | MAG_WATER(20, ALL, "Allows the hero to cast 'n'th level spells of Water magic and below"), 49 | 50 | RES_AIR(21, COMBAT, "Damage from Air magic spells is reduced by 'n'% for target"), 51 | RES_EARTH(22, COMBAT, "Damage from Earth magic spells is reduced by 'n'% for target"), 52 | RES_FIRE(23, COMBAT, "Damage from Fire magic spells is reduced by 'n'% for target"), 53 | RES_WATER(24, COMBAT, "Damage from Water magic spells is reduced by 'n'% for target"), 54 | 55 | ARCHERY(25, COMBAT, "Increases Archery skill by 'n'% (increase range attack damage)"), 56 | OFFENCE(26, COMBAT, "Increases Offence skill by 'n'% (increase melee damage)"), 57 | 58 | AIRSHIELD(27, COMBAT, "Decrease range attack damage by 'n'%"), 59 | SHIELD(28, COMBAT, "Decrease melee damage by 'n'%"), 60 | 61 | ARMORER(29, COMBAT, "Increases Armorer skill by 'n'% (decrease damage)"), 62 | 63 | RANGEATTACK(30, COMBAT, "Increase attack skill for range attack by 'n'"), 64 | MELEEATTACK(31, COMBAT, "Increase attack skill for melee attack by 'n'"), 65 | 66 | RESIST(32, COMBAT, "Increases Magic resistance skill by 'n'%"), 67 | HITS(33, COMBAT, "Creatures hit-points is increased by 'n'"), 68 | SPEED(34, COMBAT, "Creatures speed is increased by 'n'"), 69 | MORALE(35, COMBAT, "Morale is increased by 'n'"), 70 | LUCK(36, COMBAT, "Luck is increased by 'n'"), 71 | 72 | COUNTERSTRIKE(37, COMBAT, "Counter strike"), 73 | 74 | MIN_GOLD(38, OVERLAND, "Adds 'n' units of gold each day"), 75 | MIN_ORE(39, OVERLAND, "Adds 'n' units of ore each day"), 76 | MIN_WOOD(40, OVERLAND, "Adds 'n' units of wood each day"), 77 | MIN_MERCURY(41, OVERLAND, "Adds 'n' units of mercury each day"), 78 | MIN_GEMS(42, OVERLAND, "Adds 'n' units of gems each day"), 79 | MIN_CRYSTAL(43, OVERLAND, "Adds 'n' units of crystal each day"), 80 | MIN_SULFUR(44, OVERLAND, "Adds 'n' units of sulfur each day"), 81 | 82 | COUNT(45); 83 | 84 | enum class FurtherSkillType { 85 | ALL, 86 | OVERLAND, 87 | COMBAT; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/skill/FurtherSkills.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common.skill 2 | 3 | /** TODO: Remove the class. */ 4 | interface FurtherSkillsC { 5 | val values: List 6 | 7 | fun Value(type: FurtherSkill): Int { 8 | check(type.v in FurtherSkill.INVALID.v until FurtherSkill.COUNT.v) 9 | 10 | return values[type.v] 11 | } 12 | 13 | fun Empty(): Boolean { 14 | for (xx in 0 until FurtherSkill.COUNT.v) { 15 | if (values[xx] != 0) { 16 | return false 17 | } 18 | } 19 | return true 20 | } 21 | 22 | operator fun plus(other: FurtherSkillsC): FurtherSkillsC { 23 | val result = FurtherSkills(this) 24 | 25 | result += other 26 | 27 | return result 28 | } 29 | 30 | operator fun minus(other: FurtherSkillsC): FurtherSkillsC { 31 | val result = FurtherSkills(this) 32 | 33 | result -= other 34 | 35 | return result 36 | } 37 | } 38 | 39 | class FurtherSkills : FurtherSkillsC { 40 | override val values: MutableList 41 | 42 | constructor() { 43 | values = MutableList(FurtherSkill.COUNT.v) { 0 } 44 | } 45 | 46 | constructor(other: FurtherSkillsC) { 47 | values = other.values.toMutableList() 48 | } 49 | 50 | fun Reset() { 51 | for (i in values.indices) { 52 | values[i] = 0 53 | } 54 | } 55 | 56 | fun SetValue(type: FurtherSkill, newValue: Int) { 57 | check(type.v in FurtherSkill.INVALID.v until FurtherSkill.COUNT.v) 58 | 59 | values[type.v] = newValue 60 | } 61 | 62 | operator fun plusAssign(other: FurtherSkillsC) { 63 | for (xx in 0 until FurtherSkill.COUNT.v) { 64 | values[xx] += other.values[xx] 65 | } 66 | } 67 | 68 | operator fun minusAssign(other: FurtherSkillsC) { 69 | for (xx in 0 until FurtherSkill.COUNT.v) { 70 | values[xx] -= other.values[xx] 71 | } 72 | } 73 | 74 | operator fun plusAssign(other: PrimarySkillsC) { 75 | for (xx in 0 until PrimarySkillType.COUNT.v) { 76 | values[xx + FurtherSkill.ATTACK.v] += other.values[xx] 77 | } 78 | } 79 | 80 | operator fun minusAssign(other: PrimarySkillsC) { 81 | for (xx in 0 until PrimarySkillType.COUNT.v) { 82 | values[xx + FurtherSkill.ATTACK.v] -= other.values[xx] 83 | } 84 | } 85 | 86 | fun setTo(other: FurtherSkillsC) { 87 | values.clear() 88 | other.values.mapTo(values) { it } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/skill/PrimarySkillType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common.skill 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class PrimarySkillType(override val v: Int) : UniqueValueEnum, CountValueEnum { 7 | ATTACK(0), 8 | DEFENCE(1), 9 | POWER(2), 10 | KNOWLEDGE(3), 11 | COUNT(4); 12 | } 13 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/skill/PrimarySkills.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common.skill 2 | 3 | interface PrimarySkillsC { 4 | val values: List 5 | } 6 | 7 | class PrimarySkills : PrimarySkillsC { 8 | override val values: MutableList 9 | 10 | constructor() { 11 | values = MutableList(PrimarySkillType.COUNT.v) { 0 } 12 | } 13 | 14 | constructor(attack: Int, defence: Int, power: Int, knowledge: Int) { 15 | values = mutableListOf(attack, defence, power, knowledge) 16 | } 17 | 18 | constructor(other: PrimarySkillsC) { 19 | values = other.values.toMutableList() 20 | } 21 | 22 | operator fun plusAssign(other: PrimarySkillsC) { 23 | for (i in values.indices) { 24 | values[i] += other.values[i] 25 | } 26 | } 27 | 28 | operator fun minusAssign(ps: PrimarySkillsC) { 29 | for (i in values.indices) { 30 | values[i] -= ps.values[i] 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/common/skill/SecondarySkillType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common.skill 2 | 3 | import com.github.servb.pph.util.helpertype.UndefinedCountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | // TODO: Are private comments actual? 7 | enum class SecondarySkillType( 8 | override val v: Int, 9 | val furtherSkill: FurtherSkill? = null, 10 | val basic: Int? = null, 11 | val advanced: Int? = null, 12 | val expert: Int? = null, 13 | private val valueType: String? = null, 14 | private val type: Type? = null 15 | ) : UniqueValueEnum, UndefinedCountValueEnum { 16 | NONE(-1), 17 | ESTATES(0, FurtherSkill.MIN_GOLD, 250, 500, 1000, "gold points", Type.DAY_START), 18 | LEADERSHIP(1, FurtherSkill.MORALE, 1, 2, 3, "morale", Type.ONLY_BATTLE), 19 | LUCK(2, FurtherSkill.LUCK, 1, 2, 3, "luck", Type.ONLY_BATTLE), 20 | DIPLOMACY(3, FurtherSkill.DIPLOMACY, 20, 40, 60, "%", Type.ON_DEMAND), 21 | AIRMAGIC(4, FurtherSkill.MAG_AIR, 1, 2, 3, type = Type.ON_DEMAND), 22 | EARTHMAGIC(5, FurtherSkill.MAG_EARTH, 1, 2, 3, type = Type.ON_DEMAND), 23 | FIREMAGIC(6, FurtherSkill.MAG_FIRE, 1, 2, 3, type = Type.ON_DEMAND), 24 | WATERMAGIC(7, FurtherSkill.MAG_WATER, 1, 2, 3, type = Type.ON_DEMAND), 25 | WISDOM(8, FurtherSkill.WISDOM, 1, 2, 3, type = Type.ON_DEMAND), 26 | NECROMANCY(9, FurtherSkill.NECROMANCY, 10, 20, 30, "%", Type.ON_DEMAND), 27 | MYSTICISM(10, FurtherSkill.MANAPTS, 2, 4, 6, "mana points", Type.DAY_START), 28 | INTELLIGENCE(11, FurtherSkill.INTELLIGENCE, 25, 50, 100), 29 | RESISTANCE(12, FurtherSkill.RESIST, 5, 10, 20), 30 | SORCERY(13, FurtherSkill.SORCERY, 5, 10, 15, "%", Type.ON_DEMAND), 31 | LEARNING(14, FurtherSkill.LEARNING, 5, 10, 15, "%", Type.ON_DEMAND), 32 | SCOUTING(15, FurtherSkill.SCOUTING, 2, 4, 6, "cells", Type.ON_DEMAND), 33 | LOGISTICS(16, FurtherSkill.LOGISTICS, 10, 20, 30, "action points", Type.DAY_START), 34 | PATHFINDING(17, FurtherSkill.PATHFINDING, 25, 50, 75, type = Type.ON_DEMAND), 35 | ARCHERY(18, FurtherSkill.ARCHERY, 10, 25, 50, type = Type.ONLY_BATTLE), 36 | BALLISTICS(19, FurtherSkill.BALLISTICS, 1, 2, 3, type = Type.ONLY_BATTLE), 37 | OFFENCE(20, FurtherSkill.OFFENCE, 10, 20, 30, type = Type.ONLY_BATTLE), 38 | ARMORER(21, FurtherSkill.ARMORER, 5, 10, 15, type = Type.ONLY_BATTLE), 39 | COUNT(22); 40 | 41 | private enum class Type { 42 | DAY_START, ON_DEMAND, ONLY_BATTLE; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/creature/CreatureDescriptor.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.creature 2 | 3 | import com.github.servb.pph.pheroes.common.common.MineralSetC 4 | import com.github.servb.pph.pheroes.common.common.NationType 5 | 6 | data class CreatureDescriptor( 7 | val level: Int, // unit level (1-6) 8 | val nation: NationType, // unit alignment 9 | 10 | val attack: Int, // attack skill 11 | val defence: Int, // deffence skill 12 | val speed: Int, // unit speed (1-20) 13 | val size: Int, // unit size (1 or 2 - used in battle) 14 | 15 | val transType: TransportationType, // transportation method 16 | val shots: Int, // 0 - means no range attack 17 | val hits: Int, // hit points (health) 18 | val damage_min: Int, // minimum damage 19 | val damage_max: Int, // maximum damage 20 | 21 | val cost: MineralSetC, // cost per unit 22 | val growth: Int, // growth rate 23 | val pidx: Int, // power index (used for AI) 24 | val perks: Int // creature perks 25 | ) 26 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/creature/Perk.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.creature 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | 5 | const val CREATURE_PERK_COUNT = 21 6 | 7 | enum class Perk(override val v: Int, private val description: String? = null) : UniqueValueEnum { 8 | NONE(0), 9 | DOUBLESHOT(0x00000001, "Shots twice (rangers, grand elves, etc)"), 10 | DOUBLEATTACK(0x00000002, "Attack the target twice (paladins, wolves, etc)"), 11 | NOMELEEPENALTY(0x00000004, "Scores full damage even at melee"), 12 | NONRETALATTACK(0x00000008, "Non retaliated attack (vampires, rogues, sprites, hydras, etc)"), 13 | RETALTOALL(0x00000010, "Retaliates against every attack (griffins)"), 14 | TWOHEXATTACK(0x00000020, "Two-hex attack (dragons)"), 15 | ADJACENTATTACK(0x00000040, "Attacks all adjacent enemies (hydras)"), 16 | LICHSHOOT(0x00000080, "Range attack affects adjacent hexes except undeads (Liches)"), 17 | UNDEAD(0x00000100, "All necropolis creatures + ghosts"), 18 | LIFELESS(0x00000200, "Golems, gargoyles, elementals"), 19 | REGENERATES(0x00000400, "Trolls"), 20 | JOUSTING(0x00000800, "Cavalry"), 21 | AIRMAGICIMM(0x00001000, "Air elementals"), 22 | EARTHMAGICIMM(0x00002000, "Earth elementals"), 23 | FIREMAGICIMM(0x00004000, "Fire elementals, Phoenix"), 24 | WATERMAGICIMM(0x00008000, "Water elementals"), 25 | PROCRESIST40(0x00010000, "40% magic resistance (dwarves)"), 26 | QUARTERDMG(0x00020000, "Receives only quarter damage from damage spells (golems)"), 27 | GHOST(0x00040000, "Ghost perk"), 28 | DOHALF(0x00080000, "Genie perk"), 29 | DRAINLIFES(0x00100000, "Drains life (vampires)"), 30 | ALLMAGICIMM(AIRMAGICIMM.v or EARTHMAGICIMM.v or FIREMAGICIMM.v or WATERMAGICIMM.v, "Black draggons"); 31 | } 32 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/creature/TransportationType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.creature 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | 5 | enum class TransportationType(override val v: Int) : UniqueValueEnum { 6 | WALK(0), 7 | FLY(1); 8 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/magic/MagicSchool.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.magic 2 | 3 | import com.github.servb.pph.pheroes.common.common.skill.SecondarySkillType 4 | import com.github.servb.pph.util.helpertype.CountValueEnum 5 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 6 | import com.github.servb.pph.util.helpertype.or 7 | 8 | enum class MagicSchoolType(override val v: Int) : UniqueValueEnum, CountValueEnum { 9 | AIR(0), 10 | EARTH(1), 11 | FIRE(2), 12 | WATER(3), 13 | COUNT(4), 14 | } 15 | 16 | /** Magic school secondary skills (Air, Earth, Fire, Water). Size = MST_COUNT. */ 17 | val magicSchoolSecondarySkills: List = listOf( 18 | SecondarySkillType.AIRMAGIC, 19 | SecondarySkillType.EARTHMAGIC, 20 | SecondarySkillType.FIREMAGIC, 21 | SecondarySkillType.WATERMAGIC 22 | ) 23 | 24 | enum class MagicSchoolMask(override val v: Int) : UniqueValueEnum { 25 | AIR(0b0001), 26 | EARTH(0b0010), 27 | FIRE(0b0100), 28 | WATER(0b1000), 29 | GOOD(AIR or EARTH or WATER), 30 | EVIL(AIR or EARTH or FIRE), 31 | ALL(AIR or EARTH or WATER or FIRE), 32 | } 33 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/magic/SpellDisposition.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.magic 2 | 3 | import com.github.servb.pph.util.helpertype.UndefinedCountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class SpellDisposition(override val v: Int) : UniqueValueEnum, UndefinedCountValueEnum { 7 | NONE(-1), 8 | NEUTRAL(0), 9 | POSITIVE(1), 10 | NEGATIVE(2), 11 | COUNT(3), 12 | } 13 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/magic/SpellFilter.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.magic 2 | 3 | data class SpellFilter( 4 | val typeMask: UByte, 5 | val levelMask: UByte, 6 | val schoolMask: UByte, 7 | val reserved: UByte = 0u, 8 | ) { 9 | 10 | constructor(typeMask: SpellTypeMask, levelMask: SpellLevelMask, schoolMask: MagicSchoolMask) : this( 11 | typeMask = typeMask.v.toUByte(), 12 | levelMask = levelMask.v.toUByte(), 13 | schoolMask = schoolMask.v.toUByte() 14 | ) 15 | } 16 | 17 | typealias SpellList = List 18 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/magic/SpellLevel.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.magic 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | import com.github.servb.pph.util.helpertype.or 6 | 7 | enum class SpellLevel(override val v: Int) : UniqueValueEnum, CountValueEnum { 8 | FIRST(0), 9 | SECOND(1), 10 | THIRD(2), 11 | FOURTH(3), 12 | FIFTH(4), 13 | COUNT(5), 14 | } 15 | 16 | /** Size = SPL_COUNT. */ 17 | val spellLevelMasks: List = listOf( 18 | SpellLevelMask.FIRST.v.toUInt(), 19 | SpellLevelMask.SECOND.v.toUInt(), 20 | SpellLevelMask.THIRD.v.toUInt(), 21 | SpellLevelMask.FOURTH.v.toUInt(), 22 | SpellLevelMask.FIFTH.v.toUInt() 23 | ) 24 | 25 | enum class SpellLevelMask(override val v: Int) : UniqueValueEnum { 26 | NONE(0), 27 | FIRST(0b00001), 28 | SECOND(0b00010), 29 | THIRD(0b00100), 30 | FOURTH(0b01000), 31 | FIFTH(0b10000), 32 | ALL(FIRST or SECOND or THIRD or FOURTH or FIFTH), 33 | } 34 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/common/magic/SpellType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.magic 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | import com.github.servb.pph.util.helpertype.or 6 | 7 | enum class SpellType(override val v: Int) : UniqueValueEnum, CountValueEnum { 8 | OVERLAND(0), 9 | COMBAT(1), 10 | COUNT(2); 11 | } 12 | 13 | enum class SpellTypeMask(override val v: Int) : UniqueValueEnum { 14 | OVERLAND(0b01), 15 | COMBAT(0b10), 16 | ALL(OVERLAND or COMBAT), 17 | } 18 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/game/Credits.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.game 2 | 3 | import com.github.servb.pph.gxlib.* 4 | import com.github.servb.pph.util.SizeT 5 | import com.soywiz.klock.DateTime 6 | import com.soywiz.klock.Month 7 | import com.soywiz.korim.bitmap.Bitmap32 8 | import com.soywiz.korim.color.RGBA 9 | import com.soywiz.korim.color.convertTo 10 | import com.soywiz.korim.format.readBitmap 11 | import com.soywiz.korma.geom.IPointInt 12 | import com.soywiz.korma.geom.IRectangleInt 13 | import com.soywiz.korma.geom.ISizeInt 14 | import com.soywiz.korma.geom.PointInt 15 | import rootVfs 16 | import kotlin.properties.Delegates 17 | 18 | private const val R16MASK: UInt = 0xF800u 19 | private const val G16MASK: UInt = 0x07E0u 20 | private const val B16MASK: UInt = 0x001Fu 21 | 22 | private val RB16MASK: UInt = R16MASK or B16MASK 23 | private const val RB16ROUND: UInt = 0x8010u 24 | private const val G16ROUND: UInt = 0u // 0x0400u // commented in sources 25 | 26 | private fun blend16fast(p1: UInt, p2: UInt, a: UInt): UInt { 27 | val rbdst = p2 and RB16MASK 28 | var res = (rbdst + ((((p1 and RB16MASK) - rbdst) * a + RB16ROUND) shr 5)) and RB16MASK 29 | val gdst = p2 and G16MASK 30 | res = res or ((gdst + ((((p1 and G16MASK) - gdst) * a + G16ROUND) shr 5)) and G16MASK) 31 | return res 32 | } 33 | 34 | private fun blit_16aline(src: Bitmap32, srcOffset: Int, dst: IDibPixelIPointer, npix: SizeT): Int { 35 | var srcOffset = srcOffset 36 | val pdst = dst.copy() 37 | repeat(npix) { 38 | val srcColor = src.data[srcOffset] 39 | val srcAlpha = (srcColor.a.toUInt() shr 3) and 0x1Fu 40 | val srcRGB565 = RGBA.convertTo(srcColor.value, IiDib.Type.RGB.colorFormat16) 41 | 42 | pdst[0] = blend16fast(srcRGB565.toUInt(), pdst[0].toUInt(), srcAlpha).toUShort() 43 | 44 | ++srcOffset 45 | pdst.incrementOffset(1) 46 | } 47 | return srcOffset 48 | } 49 | 50 | private fun selectLogoPath(): String { 51 | val time = DateTime.now() 52 | 53 | val isNy = (time.month == Month.December && time.dayOfMonth >= 25) || 54 | (time.month == Month.January && time.dayOfMonth <= 5) 55 | 56 | return when (isNy) { 57 | true -> "pheroes/bin/Resources/hmm/GFX/Pix/title_hmm_ny.png" 58 | false -> "pheroes/bin/Resources/hmm/GFX/Pix/title_hmm.png" 59 | } 60 | } 61 | 62 | // InitMotionBlur, InitBump, InitLight and related are deleted as unused in sources 63 | class iCreditsComposer { 64 | 65 | private val m_back: iDib = iDib() 66 | private var m_pos: SizeT by Delegates.notNull() 67 | private lateinit var m_logo: Bitmap32 68 | 69 | private var m_bEnd: Boolean = false 70 | private var m_scrPos: Int = 0 71 | private var m_bShowCredits: Boolean 72 | 73 | constructor() { 74 | m_bShowCredits = true // todo 75 | } 76 | 77 | suspend fun Init() { 78 | m_back.Init(ISizeInt(320, 720), IiDib.Type.RGB) 79 | rootVfs["pheroes/bin/Resources/hmm/GFX/Pix/MenuBack.png"].readBitmap().toBMP32().copyTo(m_back) 80 | 81 | m_logo = rootVfs[selectLogoPath()].readBitmap().toBMP32() 82 | 83 | m_pos = 0 84 | } 85 | 86 | fun Compose(surface: iDib) { 87 | val xval = ((m_pos++) / 2) % 720 88 | 89 | if (xval < 240) { 90 | m_back.CopyRectToDibXY(surface, IRectangleInt(0, 720 - xval, 320, xval), PointInt()) 91 | m_back.CopyRectToDibXY(surface, IRectangleInt(0, 0, 320, 240 - xval), IPointInt(0, xval)) 92 | } else { 93 | m_back.CopyRectToDibXY(surface, IRectangleInt(0, 720 - xval, 320, 240), PointInt()) 94 | } 95 | 96 | //Compose credits 97 | ++m_scrPos 98 | var composed: SizeT = 0 99 | if (m_bShowCredits) { 100 | val pixpos = m_scrPos 101 | var spos = 70 + (13 - pixpos % 14) 102 | var cline = pixpos / 14 - 10 103 | 104 | val crtext = creditsText // todo: use item manager (as in sources) 105 | repeat(10) { 106 | val fc = iTextComposer.FontConfig(dlgfc_plain) 107 | fc.cmpProps.decor = IiDibFont.Decor.Border 108 | fc.cmpProps.alpha = when { 109 | spos < 120 -> ((spos - 70) * 255 / 50).toUByte() 110 | spos > 160 -> ((210 - spos) * 255 / 50).toUByte() 111 | else -> 255u 112 | } 113 | 114 | if (cline in crtext.indices) { 115 | gTextComposer.TextOut( 116 | fc, 117 | surface, 118 | PointInt(), 119 | crtext[cline], 120 | IRectangleInt(0, spos, 320, 14), 121 | Alignment.AlignTop 122 | ) 123 | ++composed 124 | } 125 | 126 | spos += 14 127 | ++cline 128 | } 129 | } 130 | 131 | if (composed == 0) { 132 | m_bEnd = true 133 | } 134 | 135 | // compose 'Heroes' logo directly on surface // todo: won't work on other resolutions 136 | var srcOffset = 0 137 | val dst = surface.GetPtr() 138 | // magic position constant ;) 139 | dst.incrementOffset(320 * 4 + 45) 140 | repeat(m_logo.height) { 141 | srcOffset = blit_16aline(m_logo, srcOffset, dst, m_logo.width) 142 | dst.incrementOffset(320) 143 | } 144 | } 145 | 146 | fun StartCredits() { 147 | check(!m_bShowCredits) 148 | m_bEnd = false 149 | m_bShowCredits = true 150 | m_scrPos = 15 151 | } 152 | 153 | fun StopCredits() { 154 | check(m_bShowCredits) 155 | m_bShowCredits = false 156 | } 157 | 158 | fun IsCreaditsStarted(): Boolean = m_bShowCredits 159 | 160 | fun IsCreaditsEnd(): Boolean = m_bEnd 161 | } 162 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/game/InteractBattle.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.game 2 | 3 | import com.github.servb.pph.pheroes.common.common.SurfaceType 4 | import com.soywiz.korma.geom.IPointInt 5 | 6 | class iInteractBattle : iBattleWrapper { 7 | 8 | private var m_pBattleView: iBattleView? 9 | private lateinit var m_surfType: SurfaceType 10 | 11 | constructor() : super(false) { 12 | m_pBattleView = null 13 | } 14 | 15 | override suspend fun OnBeginBattle() { 16 | gGame.ShowView(iChildGameView.CHILD_VIEW.BATTLE) 17 | m_pBattleView = gGame.View(iChildGameView.CHILD_VIEW.BATTLE) as iBattleView 18 | checkNotNull(m_pBattleView) 19 | // todo: 20 | // val dpos = m_engine.GetBattleInfo().Defender().Pos() 21 | // iCell c = gGame.Map().GetAt(dpos.x,dpos.y); 22 | // sint32 upSurf = iMAX(iMAX(iMAX(c.SurfNode(0),c.SurfNode(1)),c.SurfNode(2)),c.SurfNode(3)); 23 | m_surfType = SurfaceType.GRASS 24 | m_pBattleView!!.BeginBattle(this, m_surfType) 25 | } 26 | 27 | override fun OnStart() { 28 | m_pBattleView!!.Start() 29 | } 30 | 31 | override suspend fun OnEndBattle() { 32 | gGame.HideView(iChildGameView.CHILD_VIEW.BATTLE) 33 | m_pBattleView = null 34 | } 35 | 36 | override fun AddLogEvent(msg: String) { 37 | m_pBattleView?.AddLogEvent(msg) 38 | } 39 | 40 | override fun AddCellEvent(msg: String, pos: IPointInt) { 41 | m_pBattleView?.AddCellEvent(msg, pos) 42 | } 43 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/game/ItemMgr.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.game 2 | 3 | val creditsText = listOf( 4 | "#FFB0SerVB #FFFFand #FFB0contributors #FFFFproudly present", 5 | "", 6 | "#FFFFa port (#F0BFhttps://github.com/SerVB/pph#FFFF)", 7 | "", 8 | "#FFFFof legendary", 9 | "", 10 | "#FFB0#S2Pocket Heroes", 11 | "#FDDDv.1.04 beta", 12 | "#FDDDby iO UPG", 13 | "", 14 | "", 15 | "#FFB0Programmers:", 16 | "#FDDDRobert Tarasov", 17 | "#FDDD(Tutankhamen/iO)", 18 | "#FDDDAnton Stuk", 19 | "#FDDDSiGMan/iO", 20 | "#FDDDAndrey Kiryushkin (Hedin)", 21 | "", 22 | "#FFB0Artists:", 23 | "#FDDDEugene Ivanov (Jim)", 24 | "#FDDDDmitry Zaitsev", 25 | "#FDDDAlek Revyako", 26 | "#FDDDMihail Chilikin", 27 | "#FDDDOleg Kirshev", 28 | "#FDDDVladimir Gulevskiy (GRAFuS)", 29 | "#FDDDKevin Brock (tekpir8)", 30 | "#FDDDStanislav (Mr.Flasher)", 31 | "#FDDDAlexey Garkushin (GAS13)", 32 | "#FDDDTutankhamen/iO", 33 | "", 34 | "#FFB0Guest artists:", 35 | "#FDDDSimon Butler", 36 | "#FDDDDanny Flexner", 37 | "#FDDDIan Schlaepfer", 38 | "#FDDDPaul Noble", 39 | "#FDDDMichael Elwin Setiadi", 40 | "#FDDDDmitry Koshelev", 41 | "#FDDDIvan Ivanov", 42 | "", 43 | "#FFB0Map designers:", 44 | "#FDDDRoman Tersky (Mongol)", 45 | "#FDDDKevin Brock (tekpir8)", 46 | "#FDDDRuslan Pantyushin (Lain)", 47 | "#FDDDTsukanov Nikita (keks-n)", 48 | "#FDDDEugene Ivanov (Jim)", 49 | "#FDDDYaroslaw Artemiev (Yaros)", 50 | "#FDDDVictor Chirea (victorash)", 51 | "#FDDDObi-Van (Stas)", 52 | "#FDDDArtem Stragnik (Starmi)", 53 | "#FDDDMihail Loktionov (Matador)", 54 | "#FDDDDraco Lockhard", 55 | "#FDDDTutankhamen/iO", 56 | "", 57 | "#FFB0WEB master:", 58 | "#FDDDSergey Indiukov (DukereD)", 59 | "#FDDDTimur Parfentsev (Basmach)", 60 | "", 61 | "#FFB0Manual and Help file:", 62 | "#FDDDAndy Young (67L48)", 63 | "#FDDDVictor Chirea (victorash)", 64 | "#FDDDSergey Indiukov", 65 | "", 66 | "#FFB0Testers:", 67 | "#FDDDYaroslaw Artemiev (Yaros)", 68 | "#FDDDStanislav (Mr.Flasher)", 69 | "#FDDDAndrew Busygin", 70 | "#FDDDSergey Indiukov (DukereD)", 71 | "#FDDDVictor Chirea (victorash)", 72 | "#FDDDEugene Ivanov (Jim)", 73 | "#FDDDObi-Van (Stas)", 74 | "#FDDDIvan Alekhin (gsvano)", 75 | "#FDDDBaRaKuDa (Alexander)", 76 | "#FDDDArtem Stragnik (Starmi)", 77 | "#FDDDChibis", 78 | "#FDDDMihail Loktionov (Matador)", 79 | "#FDDDAlexey Muratov (Till)", 80 | "#FDDDAlexander Muranov (SAS)", 81 | "#FDDDTsukanov Nikita (keks-n)", 82 | "", 83 | "#FFB0Alpha version supporters:", 84 | "#FDDDAndrey Glinsky", 85 | "#FDDDFjodor Dzjuba", 86 | "#FDDDJustin Jones", 87 | "#FDDDChibis", 88 | "#FDDDRalph Sanders", 89 | "#FDDDChris Bygrave", 90 | "#FDDDDavid Zuravel", 91 | "#FDDDArtem Stragnik (Starmi)", 92 | "#FDDDValdemar", 93 | "#FDDDRS", 94 | "#FDDDSergey Indiukov (DukereD)", 95 | "#FDDDTom Fitzpatrick", 96 | "#FDDDRoman Klyachkivsky", 97 | "#FDDDOlivier Binda", 98 | "#FDDDEmanuel Mayer", 99 | "#FDDDKonstantin Ilyin", 100 | "#FDDDPaul Cook", 101 | "#FDDDAnton Rozen", 102 | "#FDDDPetr Cermak", 103 | "#FDDDNorry Messina", 104 | "#FDDDCary Fleming", 105 | "#FDDDLjusalfheim (4PDA)", 106 | "#FDDDMarc Ruder", 107 | "#FDDDMichael Thomas", 108 | "#FDDDJean-Paul Lacombe", 109 | "#FDDDestena.ru", 110 | "#FDDDMaksim Frolov", 111 | "#FDDDMiroslav Dvoracek", 112 | "#FDDDEvgeny Kremer", 113 | "#FDDDGrulezZ", 114 | "#FDDDLSDsl", 115 | "#FDDDSergey Chalykh", 116 | "#FDDDAnton Stuk", 117 | "#FDDDDmitry Sinchilin", 118 | "#FDDDAleksander Larionov", 119 | "", 120 | "#FFB0Special thanx to:", 121 | "#FDDDJon Van Caneghem", 122 | "#FDDDDmitry Lekhno (Krondor)", 123 | ) -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/game/LangView.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.game 2 | 3 | import com.github.servb.pph.gxlib.* 4 | import com.github.servb.pph.util.asRectangle 5 | import com.github.servb.pph.util.helpertype.and 6 | import com.github.servb.pph.util.helpertype.or 7 | import com.soywiz.korma.geom.IPointInt 8 | import com.soywiz.korma.geom.IRectangleInt 9 | import com.soywiz.korma.geom.RectangleInt 10 | import com.soywiz.korma.geom.SizeInt 11 | 12 | // todo: this is a PoC for language selector, copied from iMainMenu 13 | 14 | private val menuBtnText = ushortArrayOf( 15 | RGB16(210, 190, 115), RGB16(214, 192, 110), RGB16(216, 192, 102), RGB16(219, 193, 96), RGB16(221, 193, 85), 16 | RGB16(224, 194, 76), RGB16(228, 196, 67), RGB16(231, 195, 59), RGB16(233, 196, 49), RGB16(236, 196, 40), 17 | RGB16(239, 198, 31), RGB16(242, 198, 23), RGB16(224, 198, 16), RGB16(247, 199, 0), RGB16(248, 200, 0) 18 | ) // todo: check size == 15 19 | 20 | class iLangMenuDlg : iDialog, IViewCmdHandler { 21 | 22 | class iLangMenuBtn : iButton { 23 | 24 | private val text: String 25 | 26 | constructor( 27 | pViewMgr: iViewMgr, 28 | pCmdHandler: IViewCmdHandler, 29 | rect: IRectangleInt, 30 | rawText: String, 31 | uid: UInt, 32 | state: Int = ViewState.Visible or ViewState.Enabled 33 | ) : super(pViewMgr, pCmdHandler, rect, uid, state) { 34 | text = rawText 35 | } 36 | 37 | override fun OnBtnDown() { 38 | //gSfxMgr.PlaySound(CSND_BUTTON) // commented in sources 39 | } 40 | 41 | override fun OnCompose() { 42 | // gApp.Surface().Darken50Rect(GetScrRect()) // commented in sources 43 | // Compose outer frame 44 | val rect = GetScrRect() 45 | rect.rect.inflate(1) 46 | 47 | var props = IiDibFont.ComposeProps( 48 | iGradient(IDibPixelPointer(menuBtnText, 0), 15), 49 | cColor.Black.pixel, 50 | IiDibFont.Decor.Border 51 | ) 52 | val state = GetButtonState() 53 | 54 | if (state and State.Disabled != 0) { 55 | props = IiDibFont.ComposeProps(RGB16(255, 160, 80), cColor.Black.pixel, IiDibFont.Decor.Border) 56 | } else if (state and State.Pressed != 0) { 57 | props = IiDibFont.ComposeProps(RGB16(255, 255, 255), cColor.Black.pixel, IiDibFont.Decor.Border) 58 | val cColor_Grey = RGB16(32, 32, 32) 59 | gApp.Surface().HLine(IPointInt(rect.x + 2, rect.y), rect.x + rect.width - 3, cColor_Grey) 60 | gApp.Surface() 61 | .HLine(IPointInt(rect.x + 2, rect.y + rect.height - 1), rect.x + rect.width - 3, cColor_Grey) 62 | gApp.Surface().VLine(IPointInt(rect.x, rect.y + 2), rect.y + rect.height - 2, cColor_Grey) 63 | gApp.Surface() 64 | .VLine(IPointInt(rect.x + rect.width - 1, rect.y + 2), rect.y + rect.height - 2, cColor_Grey) 65 | gApp.Surface().Darken50Rect(GetScrRect()) 66 | } 67 | 68 | val fc = iTextComposer.FontConfig(iTextComposer.FontSize.LARGE, props) 69 | gTextComposer.TextOut( 70 | fc, 71 | gApp.Surface(), 72 | IPointInt(0, 0), 73 | text, 74 | GetScrRect(), 75 | Alignment.AlignCenter 76 | ) 77 | } 78 | } 79 | 80 | constructor(pViewMgr: iViewMgr) : super(pViewMgr) 81 | 82 | override suspend fun OnCreateDlg() { 83 | val rc = RectangleInt(GetDialogMetrics().asRectangle()) 84 | rc.height = DEF_BTN_HEIGHT + 2 85 | 86 | Language.values().forEach { 87 | AddChild( 88 | iLangMenuBtn( 89 | m_pMgr, 90 | this, 91 | rc, 92 | it.displayName, 93 | (it.ordinal + 100).toUInt(), 94 | ViewState.Visible or ViewState.Enabled 95 | ) 96 | ) 97 | rc.y += DEF_BTN_HEIGHT + BTN_DIST 98 | } 99 | } 100 | 101 | override fun GetDialogMetrics(): SizeInt { 102 | return SizeInt(150, Language.values().size * (DEF_BTN_HEIGHT + 2) + 12) 103 | } 104 | 105 | override suspend fun iCMDH_ControlCommand(pView: iView, cmd: CTRL_CMD_ID, param: Int) { 106 | EndDialog(pView.GetUID().toInt()) 107 | } 108 | 109 | companion object { 110 | 111 | const val BTN_DIST = 5 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/game/TextManager.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.game 2 | 3 | import com.github.servb.pph.pheroes.common.LANG_DATA 4 | import com.github.servb.pph.pheroes.common.TextResId 5 | import rootVfs 6 | import kotlin.properties.Delegates 7 | 8 | enum class Language(val displayName: String) { 9 | 10 | ENGLISH("English"), 11 | FRENCH("Français (French)"), 12 | ITALIAN("Italiana (Italian)"), 13 | GERMAN("Deutsche (German)"), 14 | POLISH("Polskie (Polish)"), 15 | RUSSIAN("Русский (Russian)"), 16 | SLOVAK("Slovák (Slovak)"), 17 | } 18 | 19 | private const val CONSTANT_PREFIX = "TRID_" 20 | 21 | @Suppress("RegExpRedundantEscape") // https://youtrack.jetbrains.com/issue/KT-47776 22 | private const val LANGUAGE_FILE_REGEX = """\{(.+)\}.*,.*\{.*\}.*,.*\{(.*)\}""" 23 | 24 | class iTextManager { 25 | 26 | private var m_bHasLngFile: Boolean by Delegates.notNull() 27 | private val m_lngData: MutableMap = mutableMapOf() 28 | 29 | fun Init(): Boolean { 30 | m_bHasLngFile = false 31 | return true 32 | } 33 | 34 | suspend fun SetLanguage(language: Language) { 35 | m_lngData.clear() 36 | 37 | if (language == Language.ENGLISH) { 38 | m_bHasLngFile = false 39 | return 40 | } 41 | 42 | m_bHasLngFile = true 43 | 44 | val regex = LANGUAGE_FILE_REGEX.toRegex() 45 | 46 | val resourceFilePath = "pheroes/bin/Resources/hmm/LNG/${language.name.lowercase()}.txt" 47 | rootVfs[resourceFilePath].readLines().forEach { line -> 48 | regex.matchEntire(line.trim())?.let { match -> 49 | val (constant, text) = match.destructured 50 | val fqn = CONSTANT_PREFIX + constant 51 | try { 52 | val trid = TextResId.valueOf(fqn) 53 | m_lngData[trid] = text 54 | } catch (e: Exception) { // replace with IAE after https://youtrack.jetbrains.com/issue/KT-35116 55 | println("Missing $fqn for $language, using English one") 56 | // todo: add proper logging and find missing translations via tests 57 | } 58 | } 59 | } 60 | } 61 | 62 | operator fun get(resId: TextResId): String { 63 | return if (m_bHasLngFile) { 64 | m_lngData[resId] ?: LANG_DATA[resId.v] 65 | } else { 66 | LANG_DATA[resId.v] 67 | } 68 | } 69 | 70 | operator fun get(resId: Int): String { 71 | return if (m_bHasLngFile) { 72 | m_lngData[TextResId.values()[resId]] ?: LANG_DATA[resId] 73 | } else { 74 | LANG_DATA[resId] 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/game/helpers.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.game 2 | 3 | import com.github.servb.pph.pheroes.common.TextResId 4 | import com.soywiz.klock.DateTime 5 | import com.soywiz.klock.Month 6 | import com.soywiz.klock.nanoseconds 7 | import com.soywiz.korio.lang.format 8 | import kotlin.math.roundToLong 9 | 10 | /** https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime. */ 11 | private val fileTimeOrigin = DateTime(1601, Month.January, 1) 12 | private val fileTimeMultiplier = 600_000_000uL 13 | 14 | fun UInt.timestampToDateTime(): DateTime { 15 | val fileTime = (fileTimeMultiplier * this).toLong() 16 | val nanos = (fileTime * 100.0).nanoseconds // can't use integer 100 because overflow will happen 17 | return fileTimeOrigin + nanos 18 | } 19 | 20 | fun DateTime.toTimestamp(): UInt { 21 | val delta = this - fileTimeOrigin 22 | val nanos = delta.nanoseconds 23 | return ((nanos / 100).roundToLong().toULong() / fileTimeMultiplier).toUInt() 24 | } 25 | 26 | fun FormatDate(timestamp: UInt, bShowTime: Boolean): String { 27 | val dt = timestamp.timestampToDateTime() 28 | 29 | val day = dt.dayOfMonth 30 | val month = gTextMgr[TextResId.TRID_MONTH_JAN.v + dt.month0] 31 | val year = dt.yearInt 32 | 33 | return when (bShowTime) { 34 | true -> "%d %s %d (%d:%02d)".format(day, month, year, dt.hours, dt.minutes) 35 | false -> "%d %s %d".format(day, month, year) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/game/hero.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.game 2 | 3 | import com.github.servb.pph.pheroes.common.army.Army 4 | import com.github.servb.pph.pheroes.common.common.skill.FurtherSkill 5 | import com.github.servb.pph.pheroes.common.common.skill.FurtherSkills 6 | import com.github.servb.pph.pheroes.common.creature.CreatureType 7 | import com.github.servb.pph.util.SizeT 8 | import com.soywiz.kmem.ByteArrayBuilder 9 | import com.soywiz.korio.stream.AsyncInputStream 10 | 11 | class iHero { 12 | 13 | // constructor(pProto: iHeroT, fake: Int) // todo 14 | 15 | fun Serialize(dbuff: ByteArrayBuilder): Unit = TODO() 16 | suspend fun Deserialize(dbuff: AsyncInputStream, bInit: Boolean): Unit = TODO() 17 | 18 | fun Deinit(bResetArmy: Boolean): Unit = TODO() 19 | // fun Init() // todo 20 | 21 | fun army(): Army = Army().apply { 22 | // todo: write actual implementation 23 | addGroup(CreatureType.YOUNG_MAGE, 1) 24 | // addGroup(CreatureType.ARCHER, 200) 25 | // addGroup(CreatureType.MONK, 100) 26 | // addGroup(CreatureType.ORC, 200) 27 | // addGroup(CreatureType.TROLL, 50) 28 | // addGroup(CreatureType.YOUNG_MAGE, 300) 29 | // addGroup(CreatureType.MAGE, 50) 30 | // addGroup(CreatureType.THOR, 25) 31 | } 32 | 33 | fun Owner(): iPlayer = iPlayer() // todo 34 | 35 | fun Level(): SizeT = 2 // todo 36 | 37 | fun GetFullFurtSkills(): FurtherSkills = FurtherSkills().apply { // todo 38 | SetValue(FurtherSkill.ATTACK, 20) 39 | SetValue(FurtherSkill.DEFENCE, 0) 40 | SetValue(FurtherSkill.POWER, 1) 41 | SetValue(FurtherSkill.KNOWLEDGE, 1) 42 | } 43 | 44 | fun ConvExpPts(exppts: Int): Int = exppts + exppts //* FurtSkill(FurtherSkill.LEARNING) / 100 // todo 45 | 46 | fun OnEndBattle(bWin: Boolean) { 47 | println("OnEndBattle($bWin)") // todo 48 | } 49 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/game/hmm.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.game 2 | 3 | import com.github.servb.pph.gxlib.GXLF_LANDSCAPE 4 | import com.github.servb.pph.gxlib.cColor 5 | import com.github.servb.pph.gxlib.iDibReader 6 | import com.github.servb.pph.gxlib.iGXApp 7 | import com.github.servb.pph.util.SizeT 8 | import com.github.servb.pph.util.asRectangle 9 | import com.soywiz.klock.milliseconds 10 | import com.soywiz.korge.view.Stage 11 | import com.soywiz.korio.async.delay 12 | import com.soywiz.korma.geom.PointInt 13 | import com.soywiz.korma.geom.RectangleInt 14 | import com.soywiz.korma.geom.center 15 | import com.soywiz.korma.geom.topLeft2 16 | 17 | lateinit var gDataPath: String 18 | lateinit var gSavePath: String 19 | lateinit var gMapsPath: String 20 | val gApp: iGXApp = iGXApp() 21 | private val gDibReader: iDibReader = iDibReader() 22 | val gTextComposer: iTextComposer = iTextComposer() 23 | 24 | val gTextMgr: iTextManager = iTextManager() 25 | 26 | val gGfxMgr: iGfxManager = iGfxManager() 27 | 28 | //private val gSfxMgr: iSfxManager // todo 29 | val gGame: Game = Game() 30 | val gSettings: iSettings = iSettings() 31 | 32 | private suspend fun ShowProgressReport(curProg: SizeT, initial: Boolean = true) { 33 | val display = gApp.Display() 34 | val rcScreen = display.SurfMetrics().asRectangle() 35 | val ldrOrg = rcScreen.center 36 | ldrOrg.y += rcScreen.height / 3 37 | val pbarWidth = (rcScreen.width * 5) / 6 38 | val rcPbar = RectangleInt(ldrOrg.x - pbarWidth / 2, ldrOrg.y, pbarWidth, 10) 39 | val pbarColor: UShort = if (initial) { 40 | 48u 41 | } else { 42 | 127u 43 | } 44 | ComposeProgressBar(false, display.GetSurface(), rcPbar, pbarColor, curProg, 100) 45 | //gGfxMgr.Blit(12,gApp.Display().GetSurface(), iPoint(0,0) ); // commented in sources 46 | 47 | if (!initial) { 48 | rcPbar.y -= 16 49 | val loadingFC = iTextComposer.FontConfig(GetButtonFont(0)) 50 | gTextComposer.TextOut(loadingFC, display.GetSurface(), rcPbar.topLeft2, "Prepare for battle...") 51 | } 52 | 53 | display.DoPaint(display.SurfMetrics().asRectangle()) 54 | delay(1.milliseconds) 55 | } 56 | 57 | suspend fun WinMain(stage: Stage, cmdLine: String) { 58 | // skipped remaining memory check 59 | // skipped single instance mutex 60 | 61 | gDataPath = "Game/Data" 62 | gSavePath = "Game/Save" 63 | gMapsPath = "pheroes/bin/GameMaps" 64 | 65 | if (!gSettings.Init(cmdLine)) { 66 | TODO("MessageBox(NULL, _T(\"Unable to init game settings!\"), NULL, MB_OK)") 67 | } 68 | 69 | val flags = GXLF_LANDSCAPE 70 | // todo: port other flags generation 71 | 72 | if (!gApp.Init(gGame, 30u, flags, stage)) { 73 | TODO("return -1, maybe MessageBox is better?") 74 | } 75 | 76 | FillStaredRect(gApp.Display().GetSurface(), gApp.Display().GetSurface().GetSize().asRectangle(), PointInt()) 77 | ShowProgressReport(0) 78 | 79 | // ShowLogo and intro image (disabled for this version) 80 | //iIntroDlg idlg(&gApp.ViewMgr()); 81 | //idlg.DoModal(); 82 | 83 | // todo: 84 | // if (gApp.SndPlayer().Inited()) { 85 | // gApp.SndPlayer().SetVolume(gSettings.GetEntryValue(CET_SFXVOLUME)*256/10); 86 | // } 87 | 88 | gApp.Display().SetGamma(1.0 + 0.05 * gSettings.GetEntryValue(ConfigEntryType.DISPGAMMA)) 89 | 90 | ShowProgressReport(15) 91 | 92 | if (!gTextComposer.Init()) { 93 | TODO("MessageBox(NULL, _T(\"Unable to init text composer!\"), NULL, MB_OK); return -1;") 94 | } 95 | 96 | ShowProgressReport(45) 97 | 98 | if (!gTextMgr.Init()) { 99 | TODO("MessageBox(NULL, _T(\"Unable to init text manager!\"), NULL, MB_OK); return -1;") 100 | } 101 | 102 | ShowProgressReport(50) 103 | 104 | gGfxMgr.SetGamma(gSettings.GetEntryValue(ConfigEntryType.DISPGAMMA).toUInt()) 105 | if (!gGfxMgr.Load(0, "pheroes/bin/Resources/hmm/GFX/spriteset.xml")) { 106 | TODO("MessageBox(NULL, _T(\"Unable to open sprite file!\"), NULL, MB_OK); return -1;") 107 | } 108 | 109 | ShowProgressReport(95) 110 | 111 | // todo: 112 | // if (gSettings.GetEntryValue(CET_SFXVOLUME) != 0 && !gSfxMgr.Init(gDataPath+_T("game.sfx"))) { 113 | // MessageBox(NULL, _T("Unable to open sound resources file!"), NULL, MB_OK); 114 | // return -1; 115 | // } 116 | 117 | gApp.Display().GetSurface().Fill(cColor.Gray64.pixel) 118 | val mdlg = iLangMenuDlg(gApp.ViewMgr()) 119 | val res = mdlg.DoModal() 120 | val languageId = res - 100 121 | val language = Language.values()[languageId] 122 | gTextMgr.SetLanguage(language) 123 | 124 | if (!gGame.Init()) { 125 | TODO("return -1") 126 | } 127 | 128 | gApp.Run() 129 | gApp.Destroy() 130 | } 131 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/pheroes/game/player.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.game 2 | 3 | import com.github.servb.pph.pheroes.common.common.PlayerId 4 | import com.github.servb.pph.pheroes.common.common.PlayerType 5 | 6 | open class iPlayer { 7 | 8 | open fun PlayerType(): PlayerType = PlayerType.HUMAN 9 | 10 | fun PlayerId(): PlayerId = PlayerId.CYAN // todo 11 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/util/future.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.util 2 | 3 | import com.soywiz.korma.geom.* 4 | 5 | typealias SizeT = Int // in C++ sources, these types are mostly unsigned 6 | typealias SizeTArray = IntArray 7 | 8 | fun IRectangleInt.asSize(): ISizeInt = object : ISizeInt { 9 | 10 | override val width: Int get() = this@asSize.width 11 | override val height: Int get() = this@asSize.height 12 | 13 | override fun equals(other: Any?): Boolean { 14 | return ISizeInt(width, height) == other 15 | } 16 | } 17 | 18 | fun IRectangleInt.asPoint(): IPointInt = object : IPointInt { 19 | 20 | override val x: Int get() = this@asPoint.x 21 | override val y: Int get() = this@asPoint.y 22 | } 23 | 24 | // submit after https://github.com/korlibs/korma/issues/44 25 | fun ISizeInt.asRectangle(): IRectangleInt = object : IRectangleInt { 26 | 27 | override val x: Int get() = 0 28 | override val y: Int get() = 0 29 | override val width: Int get() = this@asRectangle.width 30 | override val height: Int get() = this@asRectangle.height 31 | } 32 | 33 | val IRectangleInt.isEmpty get() = width == 0 || height == 0 34 | 35 | fun RectangleInt.setToUnion(that: IRectangleInt) { 36 | if (isEmpty) { 37 | setTo(that) 38 | return 39 | } 40 | 41 | val minX = minOf(that.x, x) 42 | val minY = minOf(that.y, y) 43 | 44 | val maxX = maxOf(that.x2, x2) 45 | val maxY = maxOf(that.y2, y2) 46 | 47 | x = minX 48 | y = minY 49 | width = maxX - minX + 1 50 | height = maxY - minY + 1 51 | } 52 | 53 | fun Rectangle.deflate(left: SizeT, top: SizeT, right: SizeT, bottom: SizeT) { 54 | x += left 55 | y += top 56 | width -= left + right 57 | height -= top + bottom 58 | } 59 | 60 | operator fun PointInt.plusAssign(other: IPointInt): Unit = run { setTo(x + other.x, y + other.y) } 61 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/util/helpertype/EnumTestingInterfaces.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.util.helpertype 2 | 3 | interface EnumWithValue { 4 | val v: Int 5 | } 6 | 7 | /** [v] has to be unique. */ 8 | interface UniqueValueEnum : EnumWithValue 9 | 10 | /** Need to have an element containing "COUNT" and its value has to be a number of previous members. */ 11 | interface CountValueEnum : EnumWithValue 12 | 13 | /** 14 | * Need to have an element containing "COUNT" and its value has to be a number of previous members except "UNDEFINED" 15 | * member (if there is). 16 | */ 17 | interface UndefinedCountValueEnum : EnumWithValue 18 | 19 | infix fun EnumWithValue.or(other: EnumWithValue): Int = this.v or other.v 20 | infix fun Int.or(other: EnumWithValue): Int = this or other.v 21 | 22 | infix fun EnumWithValue.and(other: EnumWithValue): Int = this.v and other.v 23 | infix fun Int.and(other: EnumWithValue): Int = this and other.v 24 | 25 | infix fun EnumWithValue.xor(other: EnumWithValue): Int = this.v xor other.v 26 | infix fun Int.xor(other: EnumWithValue): Int = this xor other.v 27 | 28 | inline fun getByValue(v: Int): T where T : EnumWithValue, T : Enum { 29 | return enumValues().single { it.v == v } 30 | } 31 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/github/servb/pph/util/pointers.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.util 2 | 3 | class Mutable(var element: T) 4 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/main.kt: -------------------------------------------------------------------------------- 1 | import com.github.servb.pph.pheroes.game.WinMain 2 | import com.soywiz.klogger.Logger 3 | import com.soywiz.korge.Korge 4 | import com.soywiz.korio.file.VfsFile 5 | import com.soywiz.korio.file.std.openAsZip 6 | import com.soywiz.korio.file.std.resourcesVfs 7 | import com.soywiz.korio.stream.openAsync 8 | 9 | lateinit var rootVfs: VfsFile 10 | private set 11 | 12 | suspend fun main() = Korge( 13 | width = 3 * 320, height = 3 * 240, 14 | virtualWidth = 320, virtualHeight = 240, 15 | title = "Pocket Palm Heroes", 16 | ) { 17 | Logger.defaultLevel = Logger.Level.INFO 18 | 19 | rootVfs = 20 | resourcesVfs["resources.zip"].readAll().openAsync() 21 | .openAsZip(caseSensitive = false) // case insensitive to avoid strict matching 22 | 23 | WinMain(this, "") 24 | // mainDev() 25 | } 26 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/github/servb/pph/gxlib/dibTest.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib 2 | 3 | import com.soywiz.korim.color.RGBA 4 | import com.soywiz.korim.color.RGB_565 5 | import com.soywiz.korim.color.convertTo 6 | import io.kotest.assertions.withClue 7 | import io.kotest.core.spec.style.StringSpec 8 | import io.kotest.matchers.shouldBe 9 | 10 | class DibTest : StringSpec() { 11 | 12 | init { 13 | "test colors from KorGE match the gxl ones".config(enabled = false) { 14 | for (r in 0..255) { 15 | for (g in 0..255) { 16 | for (b in 0..255) { 17 | val gxlColor = RGB16(r, g, b) 18 | val korgeColor = RGBA.convertTo(RGBA(r, g, b).value, RGB_565).toUShort() 19 | 20 | withClue("RGB16($r, $g, $b)") { 21 | korgeColor shouldBe gxlColor 22 | } 23 | } 24 | } 25 | } 26 | } 27 | 28 | "test constants size" { 29 | BWPAL.size shouldBe 32 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/github/servb/pph/pheroes/game/DateTest.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.game 2 | 3 | import com.soywiz.klock.DateTime 4 | import com.soywiz.klock.Month 5 | import io.kotest.core.spec.style.StringSpec 6 | import io.kotest.matchers.shouldBe 7 | 8 | class DateTest : StringSpec() { 9 | 10 | init { 11 | "test timestamp" { 12 | val expected = DateTime(2021, Month.September, 13) 13 | val actual = expected.toTimestamp().timestampToDateTime() 14 | 15 | actual shouldBe expected 16 | } 17 | 18 | "test FormatDate" { 19 | gTextMgr.Init() 20 | val expected = "20 Feb 2019 (1:02)" 21 | val actual = FormatDate(DateTime(2019, Month.February, 20, 1, 2).toTimestamp(), bShowTime = true) 22 | 23 | actual shouldBe expected 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/jvmTest/kotlin/com/github/servb/pph/util/helpertype/EnumTestingInterfacesTest.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.util.helpertype 2 | 3 | import io.kotest.core.spec.style.StringSpec 4 | import io.kotest.matchers.shouldBe 5 | import io.kotest.matchers.shouldNotBe 6 | import org.reflections.Reflections 7 | 8 | class UniqueValueEnumTest : StringSpec() { 9 | private val appPackage = "com.github.servb.pph" 10 | 11 | init { 12 | "values in each enum should be unique" { 13 | val subjects = Reflections(appPackage).getSubTypesOf(UniqueValueEnum::class.java) 14 | 15 | println("UniqueValueEnums found: ${subjects.size}") 16 | 17 | subjects.size shouldNotBe 0 // When get rid of classes -> remove the test 18 | 19 | subjects.forEach { enumClass -> 20 | val originalSize = enumClass.enumConstants.size 21 | val distinctSize = enumClass.enumConstants.map { it.v }.toSet().size 22 | 23 | if (originalSize != distinctSize) { 24 | println("Not unique values in $enumClass") 25 | print("Not unique values: ") 26 | println(enumClass.enumConstants.map { it.v }.groupBy { it }.filter { (_, v) -> v.size > 1 }) 27 | } 28 | 29 | originalSize shouldBe distinctSize 30 | } 31 | } 32 | } 33 | } 34 | 35 | class CountValueEnumTest : StringSpec() { 36 | private val appPackage = "com.github.servb.pph" 37 | 38 | init { 39 | "COUNT value in each enum should be the number of the previous members" { 40 | val subjects = Reflections(appPackage).getSubTypesOf(CountValueEnum::class.java) 41 | 42 | println("CountValueEnums found: ${subjects.size}") 43 | 44 | subjects.size shouldNotBe 0 // When get rid of classes -> remove the test 45 | 46 | subjects.forEach { enumClass -> 47 | var hasCount = false 48 | var count = 0 49 | 50 | for (member in enumClass.enumConstants) { 51 | val name = member.toString().toLowerCase() 52 | 53 | if ("count" == name) { 54 | if (member.v != count) { 55 | println("Incorrect count in $enumClass") 56 | } 57 | 58 | member.v shouldBe count 59 | hasCount = true 60 | } else { 61 | ++count 62 | } 63 | } 64 | 65 | if (!hasCount) { 66 | println("No count value in $enumClass") 67 | } 68 | 69 | hasCount shouldBe true 70 | } 71 | } 72 | } 73 | } 74 | 75 | class UndefinedCountValueEnumTest : StringSpec() { 76 | private val appPackage = "com.github.servb.pph" 77 | 78 | private val passingMembers = setOf("undefined", "invalid", "none", "neutral", "unknown") 79 | 80 | init { 81 | "COUNT value in each enum should be the number of the previous members except passing" { 82 | val subjects = Reflections(appPackage).getSubTypesOf(UndefinedCountValueEnum::class.java) 83 | 84 | println("UndefinedCountValueEnums found: ${subjects.size}") 85 | 86 | subjects.size shouldNotBe 0 // When get rid of classes -> remove the test 87 | 88 | subjects.forEach { enumClass -> 89 | var hasCount = false 90 | var count = 0 91 | 92 | var hasPassing = false 93 | 94 | val list = mutableListOf() 95 | 96 | for (member in enumClass.enumConstants) { 97 | val name = member.toString().toLowerCase() 98 | 99 | if (!hasPassing && passingMembers.any { it == name }) { 100 | hasPassing = true 101 | continue 102 | } else if ("count" == name) { 103 | if (member.v != count) { 104 | println("Incorrect count in $enumClass") 105 | println(list.withIndex().joinToString("\n")) 106 | } 107 | 108 | member.v shouldBe count 109 | hasCount = true 110 | } else { 111 | ++count 112 | list.add(member) 113 | } 114 | } 115 | 116 | if (!hasPassing) { 117 | println("No passing in $enumClass") 118 | } 119 | 120 | hasPassing shouldBe true 121 | 122 | if (!hasCount) { 123 | println("No count value in $enumClass") 124 | } 125 | 126 | hasCount shouldBe true 127 | } 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/Pph.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph 2 | 3 | import com.badlogic.gdx.ApplicationAdapter 4 | import com.badlogic.gdx.Gdx 5 | import com.badlogic.gdx.graphics.GL20 6 | import com.badlogic.gdx.graphics.Texture 7 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 8 | 9 | class Pph : ApplicationAdapter() { 10 | private lateinit var batch: SpriteBatch 11 | private lateinit var img: Texture 12 | 13 | override fun create() { 14 | batch = SpriteBatch() 15 | img = Texture("badlogic.jpg") 16 | } 17 | 18 | override fun render() { 19 | Gdx.gl.glClearColor(1f, 0f, 0f, 1f) 20 | Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) 21 | batch.begin() 22 | batch.draw(img, 0f, 0f) 23 | batch.end() 24 | } 25 | 26 | override fun dispose() { 27 | batch.dispose() 28 | img.dispose() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/gxlib/gxlcommontpl/Static.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib.gxlcommontpl 2 | 3 | /** 4 | * "Clamps" [value] between [min] and [max]. 5 | * If [min] `<=` [value] `<=` [max] then [value] is returned. 6 | * If [value] `<` [min] then [min] is returned. 7 | * Otherwise [max] is returned. 8 | * 9 | * @param min The minimum limit. 10 | * @param max The maximum limit, should be not less than the minimum limit. 11 | * @param value The value to be clamped. 12 | * @return The clamped value. 13 | */ 14 | inline fun > iCLAMP(min: T, max: T, value: T): T { 15 | check(min <= max) { "The minimum should be not greater than the maximum" } 16 | 17 | if (value in min..max) { 18 | return value 19 | } 20 | 21 | return if (value < min) { 22 | min 23 | } else { 24 | max 25 | } 26 | } 27 | 28 | // 29 | /** 30 | * Returns the positive difference between two values. 31 | * 32 | * @param x The first value. 33 | * @param y The second value. 34 | * @return The positive difference. 35 | */ 36 | fun iDIF(x: Byte, y: Byte): Byte { 37 | return (if (x > y) x - y else y - x).toByte() 38 | } 39 | 40 | /** 41 | * Returns the positive difference between two values. 42 | * 43 | * @param x The first value. 44 | * @param y The second value. 45 | * @return The positive difference. 46 | */ 47 | fun iDIF(x: Short, y: Short): Short { 48 | return (if (x > y) x - y else y - x).toShort() 49 | } 50 | 51 | /** 52 | * Returns the positive difference between two values. 53 | * 54 | * @param x The first value. 55 | * @param y The second value. 56 | * @return The positive difference. 57 | */ 58 | fun iDIF(x: Int, y: Int): Int { 59 | return (if (x > y) x - y else y - x).toInt() 60 | } 61 | 62 | /** 63 | * Returns the positive difference between two values. 64 | * 65 | * @param x The first value. 66 | * @param y The second value. 67 | * @return The positive difference. 68 | */ 69 | fun iDIF(x: Long, y: Long): Long { 70 | return (if (x > y) x - y else y - x).toLong() 71 | } 72 | 73 | /** 74 | * Returns the positive difference between two values. 75 | * 76 | * @param x The first value. 77 | * @param y The second value. 78 | * @return The positive difference. 79 | */ 80 | fun iDIF(x: Float, y: Float): Float { 81 | return (if (x > y) x - y else y - x).toFloat() 82 | } 83 | 84 | /** 85 | * Returns the positive difference between two values. 86 | * 87 | * @param x The first value. 88 | * @param y The second value. 89 | * @return The positive difference. 90 | */ 91 | fun iDIF(x: Double, y: Double): Double { 92 | return (if (x > y) x - y else y - x).toDouble() 93 | } 94 | // 95 | 96 | /** 97 | * TODO: Provide documentation. 98 | * 99 | * @param value The value to be aligned. 100 | * @param al Should be positive. 101 | * @return Aligned value. 102 | */ 103 | @ExperimentalUnsignedTypes 104 | fun iALIGN(value: UInt, al: UInt): UInt { 105 | return (value + al - 1u) / al * al 106 | } 107 | 108 | /** 109 | * TODO: Provide documentation. 110 | * 111 | * @param value The value to be wrapped. 112 | * @param minv Should be less than [wrap]. 113 | * @param wrap 114 | * @return Wrapped value. 115 | */ 116 | fun iWRAP(value: Short, minv: Short, wrap: Short): Short { 117 | require(minv < wrap) { "minv should be less theb wrap" } 118 | 119 | if (value < minv) { 120 | return (value + wrap - minv).toShort() 121 | } 122 | return if (value >= wrap) { 123 | (value - wrap + minv).toShort() 124 | } else { 125 | value 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/gxlib/gxlmetrics/Point.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib.gxlmetrics 2 | 3 | /** Immutable (constant) Point view. */ 4 | @ExperimentalUnsignedTypes 5 | interface Pointc { 6 | val x: Int 7 | val y: Int 8 | 9 | /** TODO: Provide tests, provide documentation. */ 10 | fun GetSqDelta(other: Pointc) = maxOf(Math.abs(other.x - x), Math.abs(other.y - y)) 11 | 12 | /** TODO: Provide tests, provide documentation. */ 13 | fun GetDelta(other: Pointc): Int { 14 | val dx = other.x - x 15 | val dy = other.y - y 16 | 17 | return Math.sqrt((dx * dx + dy * dy).toDouble()).toInt() 18 | } 19 | 20 | fun toPointc(): Pointc = Point(this) 21 | fun toPoint() = Point(this) 22 | } 23 | 24 | @ExperimentalUnsignedTypes 25 | operator fun Pointc.plus(other: Pointc): Pointc = Point(x + other.x, y + other.y) 26 | 27 | @ExperimentalUnsignedTypes 28 | operator fun Pointc.minus(other: Pointc): Pointc = Point(x - other.x, y - other.y) 29 | 30 | @ExperimentalUnsignedTypes 31 | operator fun Pointc.plus(offs: Int): Pointc = Point(x + offs, y + offs) 32 | 33 | @ExperimentalUnsignedTypes 34 | operator fun Pointc.minus(offs: Int): Pointc = Point(x - offs, y - offs) 35 | 36 | @ExperimentalUnsignedTypes 37 | data class Point(override var x: Int, override var y: Int) : Pointc { 38 | constructor() : this(0, 0) 39 | 40 | constructor(other: Pointc) : this(other.x, other.y) 41 | 42 | operator fun plus(other: Point) = Point(x + other.x, y + other.y) 43 | operator fun minus(other: Point) = Point(x - other.x, y - other.y) 44 | 45 | operator fun plusAssign(other: Pointc) { 46 | x += other.x 47 | y += other.y 48 | } 49 | 50 | operator fun minusAssign(other: Pointc) { 51 | x -= other.x 52 | y -= other.y 53 | } 54 | 55 | operator fun plusAssign(siz: Sizec) { 56 | x += siz.w.toInt() 57 | y += siz.h.toInt() 58 | } 59 | 60 | operator fun minusAssign(siz: Sizec) { 61 | x -= siz.w.toInt() 62 | y -= siz.h.toInt() 63 | } 64 | 65 | operator fun plusAssign(offs: Int) { 66 | x += offs 67 | y += offs 68 | } 69 | 70 | operator fun minusAssign(offs: Int) { 71 | x -= offs 72 | y -= offs 73 | } 74 | 75 | fun MoveX(offset_x: Int) { 76 | x += offset_x 77 | } 78 | 79 | fun MoveY(offset_y: Int) { 80 | y += offset_y 81 | } 82 | 83 | fun Move(offset_x: Int, offset_y: Int) { 84 | x += offset_x 85 | y += offset_y 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/gxlib/gxlmetrics/Rect.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib.gxlmetrics 2 | 3 | /** Immutable (constant) rectangle view. */ 4 | @ExperimentalUnsignedTypes 5 | interface Rectc : Pointc, Sizec { 6 | override fun plus(offs: UInt): Rectc = Rect(x + offs.toInt(), y + offs.toInt(), w + offs, h + offs) 7 | override fun minus(offs: UInt): Rectc = Rect(x - offs.toInt(), y - offs.toInt(), w - offs, h - offs) 8 | 9 | val x1 get() = x 10 | val y1 get() = y 11 | val x2 get() = x + w.toInt() - 1 12 | val y2 get() = y + h.toInt() - 1 13 | 14 | fun Center() = Point(x + (w / 2u).toInt(), y + (h / 2u).toInt()) 15 | fun TopRight() = Point(x2, y1) 16 | fun TopLeft() = Point(x1, y1) 17 | fun BottomRight() = Point(x2, y2) 18 | fun BottomLeft() = Point(x1, y2) 19 | 20 | fun Point() = Point(x, y) 21 | fun Size() = Size(w, h) 22 | 23 | fun PtInRect(_x: Int, _y: Int) = (_x in x1..x2) && (_y in y1..y2) 24 | fun PtInRect(pnt: Pointc) = PtInRect(pnt.x, pnt.y) 25 | 26 | fun IsEmpty() = w == 0u || h == 0u 27 | 28 | operator fun plus(rect: Rectc): Rectc { 29 | val rc = Rect(this) 30 | rc += rect 31 | return Rect(rc) 32 | } 33 | 34 | fun toRectc(): Rectc = Rect(this) 35 | fun toRect(): Rect = Rect(this) 36 | } 37 | 38 | @ExperimentalUnsignedTypes 39 | operator fun Rectc.plus(offs: Int): Rectc = Rect(x + offs, y + offs, w + offs.toUInt(), h + offs.toUInt()) 40 | 41 | @ExperimentalUnsignedTypes 42 | operator fun Rectc.minus(offs: Int): Rectc = Rect(x - offs, y - offs, w - offs.toUInt(), h - offs.toUInt()) 43 | 44 | @ExperimentalUnsignedTypes 45 | data class Rect(override var x: Int, override var y: Int, override var w: UInt, override var h: UInt) : Rectc { 46 | constructor() : this(0, 0, 0u, 0u) 47 | 48 | constructor(point: Pointc, size: Sizec) : this(point.x, point.y, size.w, size.h) 49 | 50 | constructor(other: Rectc) : this(other.x, other.y, other.w, other.h) 51 | 52 | constructor(point: Pointc) : this(point.x, point.y, 0u, 0u) 53 | 54 | constructor(size: Sizec) : this(0, 0, size.w, size.h) 55 | 56 | constructor(p1: Pointc, p2: Pointc) : this(42, 42, 42u, 42u) { 57 | val minX = minOf(p1.x, p2.x) 58 | val minY = minOf(p1.y, p2.y) 59 | 60 | val maxX = maxOf(p1.x, p2.x) 61 | val maxY = maxOf(p1.y, p2.y) 62 | 63 | x = minX 64 | y = minY 65 | 66 | w = (maxX - minX + 1).toUInt() 67 | h = (maxY - minY + 1).toUInt() 68 | } 69 | 70 | fun Reset() { 71 | x = 0 72 | y = 0 73 | w = 0u 74 | h = 0u 75 | } 76 | 77 | operator fun plusAssign(rect: Rectc) { 78 | if (IsEmpty()) { 79 | x = rect.x 80 | y = rect.y 81 | w = rect.w 82 | h = rect.h 83 | } 84 | 85 | val minX = minOf(rect.x, x) 86 | val minY = minOf(rect.y, y) 87 | 88 | val maxX = maxOf(rect.x2, x2) 89 | val maxY = maxOf(rect.y2, y2) 90 | 91 | x = minX 92 | y = minY 93 | 94 | w = (maxX - minX + 1).toUInt() 95 | h = (maxY - minY + 1).toUInt() 96 | } 97 | 98 | fun InflateRect(left: UInt, top: UInt, right: UInt, bottom: UInt) { 99 | x -= left.toInt() 100 | y -= top.toInt() 101 | w += left + right 102 | h += top + bottom 103 | } 104 | 105 | fun InflateRect(x_offs: UInt, y_offs: UInt) = InflateRect(x_offs, y_offs, x_offs, y_offs) 106 | 107 | fun InflateRect(offs: UInt) = InflateRect(offs, offs, offs, offs) 108 | 109 | fun DeflateRect(left: UInt, top: UInt, right: UInt, bottom: UInt) { 110 | x += left.toInt() 111 | y += top.toInt() 112 | w -= left + right 113 | h -= top + bottom 114 | } 115 | 116 | fun DeflateRect(x_offs: UInt, y_offs: UInt) = DeflateRect(x_offs, y_offs, x_offs, y_offs) 117 | 118 | fun DeflateRect(offs: UInt) = DeflateRect(offs, offs, offs, offs) 119 | 120 | operator fun plus(rect: Rect): Rect { 121 | val rc = Rect(this) 122 | rc += rect 123 | return Rect(rc) 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/gxlib/gxlmetrics/Size.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib.gxlmetrics 2 | 3 | /** Immutable (constant) Size view. */ 4 | @ExperimentalUnsignedTypes 5 | interface Sizec { 6 | val w: UInt 7 | val h: UInt 8 | 9 | /** 10 | * Returns the aspect ratio width/height. 11 | * 12 | * @return The aspect ratio. 13 | */ 14 | // TODO: Remove toLong 15 | fun GetAspectRatio() = w.toLong().toFloat() / h.toLong().toFloat() 16 | 17 | /** 18 | * Checks if the size is equal to zero. 19 | * 20 | * @return The result of the check. 21 | */ 22 | fun IsZero() = w == 0u && h == 0u 23 | 24 | operator fun plus(other: Sizec): Sizec = Size(w + other.w, h + other.h) 25 | operator fun minus(other: Sizec): Sizec = Size(w - other.w, h - other.h) 26 | operator fun plus(offs: UInt): Sizec = Size(w + offs, h + offs) 27 | operator fun minus(offs: UInt): Sizec = Size(w - offs, h - offs) 28 | 29 | fun toSizec(): Sizec = Size(this) 30 | fun toSize() = Size(this) 31 | } 32 | 33 | @ExperimentalUnsignedTypes 34 | data class Size(override var w: UInt, override var h: UInt) : Sizec { 35 | constructor() : this(0u, 0u) 36 | 37 | constructor(other: Sizec) : this(other.w, other.h) 38 | 39 | operator fun plus(other: Size) = Size(w + other.w, h + other.h) 40 | operator fun minus(other: Size) = Size(w - other.w, h - other.h) 41 | 42 | /** 43 | * Inflates the size by the value. 44 | * 45 | * @param value The value. 46 | */ 47 | @Deprecated("Use #InflateSize instead.", ReplaceWith("InflateSize(value)")) 48 | operator fun plusAssign(value: UInt) = InflateSize(value) 49 | 50 | /** 51 | * Deflates the size by the value. 52 | * 53 | * @param value The value. 54 | */ 55 | @Deprecated("Use #DeflateSize instead.", ReplaceWith("DeflateSize(value)")) 56 | operator fun minusAssign(value: UInt) = DeflateSize(value) 57 | 58 | /** 59 | * Inflates the size by the value. 60 | * 61 | * @param w_offs The width offset. 62 | * @param h_offs The height offset. 63 | */ 64 | fun InflateSize(w_offs: UInt, h_offs: UInt) { 65 | w += w_offs 66 | h += h_offs 67 | } 68 | 69 | /** 70 | * Inflates the size by the value. 71 | * 72 | * @param offs The value. 73 | */ 74 | fun InflateSize(offs: UInt) = InflateSize(offs, offs) 75 | 76 | /** 77 | * Deflates the size by the value. 78 | * 79 | * @param w_offs The width offset. 80 | * @param h_offs The height offset. 81 | */ 82 | fun DeflateSize(w_offs: UInt, h_offs: UInt) { 83 | w -= w_offs 84 | h -= h_offs 85 | } 86 | 87 | /** 88 | * Deflates the size by the value. 89 | * 90 | * @param offs The value. 91 | */ 92 | fun DeflateSize(offs: UInt) = DeflateSize(offs, offs) 93 | 94 | /** Sets width and height to zero. */ 95 | fun Zero() { 96 | h = 0u 97 | w = 0u 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/gxlib/iCircBuff.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib 2 | 3 | class iCircBuff(private val bufferSize: Int = 64) { 4 | private var m_rCur = 0 5 | private var m_wCur = 0 6 | private var m_aT = MutableList(bufferSize) { null } 7 | 8 | fun Count(): Int { 9 | return if (m_wCur >= m_rCur) { 10 | m_wCur - m_rCur 11 | } else { 12 | bufferSize - m_rCur + m_wCur 13 | } 14 | } 15 | 16 | fun Put(t: T) { 17 | if (m_wCur == m_rCur) { 18 | check(false) { "Buffer is full" } 19 | } 20 | m_aT[m_wCur] = t 21 | ++m_wCur 22 | if (m_wCur == bufferSize) { 23 | m_wCur = 0 24 | } 25 | } 26 | 27 | fun Get(): T { 28 | check(m_rCur != m_wCur) { "Buffer is empty" } 29 | 30 | val oPos = m_rCur 31 | ++m_rCur 32 | if (m_rCur == bufferSize) { 33 | m_rCur = 0 34 | } 35 | return m_aT[oPos]!! 36 | } 37 | 38 | fun Reset() { 39 | m_rCur = 0 40 | m_wCur = 0 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/gxlib/memory/Buff.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib.memory 2 | 3 | class Buff { 4 | private var data: MutableList? 5 | 6 | var size: Int 7 | private set 8 | 9 | val ptr: List? get() = data 10 | 11 | constructor() { 12 | this.data = null 13 | this.size = 0 14 | } 15 | 16 | constructor(size: Int) : this() { 17 | allocate(null, size) 18 | } 19 | 20 | constructor(buff: List, size: Int) : this() { 21 | allocate(buff, size) 22 | } 23 | 24 | fun allocate(buff: List?, size: Int) { 25 | this.size = size 26 | val data = MutableList(size) { null } 27 | 28 | if (buff != null) { 29 | for (idx in 0 until size) { 30 | data[idx] = buff[idx] 31 | } 32 | } 33 | 34 | this.data = data 35 | } 36 | 37 | fun clean() { 38 | this.data = null 39 | this.size = 0 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/gxlib/string.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib 2 | 3 | fun textToEscSeq(str: String): String = str 4 | .replace("""\n""", "\n") 5 | .replace("""\r""", "\r") 6 | .replace("""\t""", "\t") 7 | .replace("""\\""", "\\") 8 | 9 | fun escSeqToText(str: String): String = str 10 | .replace("\n", """\n""") 11 | .replace("\r", """\r""") 12 | .replace("\t", """\t""") 13 | .replace("\\", """\\""") 14 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/SortArray.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common 2 | 3 | class SortArray { 4 | data class Entry(val idx: Int, val value: T) 5 | 6 | private val array = mutableListOf>() 7 | 8 | val ptr: MutableList> 9 | get() = TODO( 10 | "return `array` here if this val is used somewhere, otherwise, remove this val" 11 | ) 12 | 13 | fun init(other: SortArray) { 14 | this.array.clear() 15 | 16 | other.array.forEach { 17 | this.array.add(it) 18 | } 19 | } 20 | 21 | fun pop(): E = array.removeAt(array.lastIndex).value 22 | 23 | val firstIdx: Int get() = array.first().idx 24 | val lastIdx: Int get() = array.last().idx 25 | 26 | val last: E get() = array.last().value 27 | 28 | fun removeAt(idx: Int): Boolean { 29 | array.removeAt(idx) 30 | return true 31 | } 32 | 33 | /** Indices: from smaller to bigger. */ 34 | fun insert(value: E, idx: Int): Boolean { 35 | var length = array.size 36 | if (length == 0 || array.last().idx <= idx) { 37 | array.add(Entry(idx, value)) 38 | return true 39 | } 40 | 41 | if (idx < array.first().idx) { 42 | array.add(0, Entry(idx, value)) 43 | return true 44 | } 45 | 46 | var first = 0 47 | 48 | while (length > 0) { 49 | val half = length shr 1 50 | val middle = first + half 51 | if (array[middle].idx <= idx) { 52 | first = middle + 1 53 | length = length - half - 1 54 | } else { 55 | length = half 56 | } 57 | } 58 | array.add(first, Entry(idx, value)) 59 | return true 60 | } 61 | 62 | fun cleanup() = array.clear() 63 | 64 | val size: Int get() = array.size 65 | 66 | operator fun get(idx: Int): Entry = array[idx] 67 | fun value(idx: Int): E = array[idx].value 68 | fun index(idx: Int): Int = array[idx].idx 69 | 70 | fun selfTest(): Boolean { 71 | // TODO: Move to tests 72 | 73 | if (size < 2) { 74 | return true 75 | } 76 | 77 | return array.windowed(2).all { it.first().idx <= it.last().idx } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/SpannedMap.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common 2 | 3 | data class SpannedMap(val shape: Shape = Shape.SQUARE, val radius: Int = 1) { 4 | enum class Shape { 5 | CIRCLE, 6 | SQUARE, 7 | } 8 | 9 | data class Span(val ypos: Short, val begin: Short, val end: Short) { 10 | constructor(ypos: Int, begin: Int, end: Int) : this( 11 | ypos = ypos.toShort(), 12 | begin = begin.toShort(), 13 | end = end.toShort() 14 | ) 15 | } 16 | 17 | init { 18 | check(radius >= 0) 19 | } 20 | 21 | private val spanList: List = when (shape) { 22 | Shape.CIRCLE -> makeCircleSpan(radius) 23 | Shape.SQUARE -> makeSquareSpan(radius) 24 | } 25 | 26 | private fun makeCircleSpan(radius: Int): List { 27 | val spans = mutableMapOf() 28 | 29 | var cx = 0 30 | var cy = radius 31 | var df = 1 - radius 32 | var d_e = 3 33 | var d_se = -2 * radius + 5 34 | 35 | do { // Filled circle 36 | spans[radius - cx] = Span(-cx, -cy, cy) 37 | if (cx != 0) { 38 | spans[radius + cx] = Span(cx, -cy, cy) 39 | } 40 | if (df < 0) { 41 | df += d_e 42 | d_e += 2 43 | d_se += 2 44 | } else { 45 | if (cx != cy) { 46 | spans[radius - cy] = Span(-cy, -cx, cx) 47 | if (cy != 0) { 48 | spans[radius + cy] = Span(cy, -cx, cx) 49 | } 50 | } 51 | df += d_se 52 | d_e += 2 53 | d_se += 4 54 | cy-- 55 | } 56 | cx++ 57 | } while (cx <= cy) 58 | 59 | val count = radius * 2 + 1 60 | return (0 until count).map { spans[it] ?: Span(0, 0, 0) } 61 | } 62 | 63 | private fun makeSquareSpan(radius: Int): List { 64 | val count = radius * 2 + 1 65 | return (0 until count).map { 66 | Span( 67 | ypos = -radius + it, 68 | begin = -radius, 69 | end = radius 70 | ) 71 | } 72 | } 73 | 74 | val spanLinesCount: Int get() = spanList.size 75 | 76 | operator fun get(idx: Int): Span { 77 | check(idx in spanList.indices) 78 | 79 | return spanList[idx] 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/TreasuryVariantsContainer.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common 2 | 3 | import com.github.servb.pph.gxlib.memory.DynamicBuffer 4 | import com.github.servb.pph.pheroes.common.army.Army 5 | import com.github.servb.pph.pheroes.common.common.RewardsCtr 6 | 7 | @ExperimentalUnsignedTypes 8 | class TreasuryVariantsContainer { 9 | class Item(val probability: UInt) { 10 | var guards: Army? = null 11 | var rewards: RewardsCtr? = null 12 | } 13 | 14 | private val items = mutableListOf() 15 | 16 | fun addVariant(probability: UInt) { 17 | items.add(Item(probability)) 18 | } 19 | 20 | val lastVariant: Item get() = items.last() 21 | 22 | fun getVariant(idx: Int) = items[idx] 23 | 24 | val variantsCount: Int get() = items.size 25 | 26 | fun serialize(buff: DynamicBuffer) { 27 | val quantity = items.size.toUShort() 28 | buff.write(quantity) 29 | for (item in items) { 30 | buff.write(item.probability.toUByte()) 31 | serialize(buff, item.guards!!) 32 | serializeRewardsCtr(buff, item.rewards!!) 33 | } 34 | } 35 | 36 | fun unserialize(buff: DynamicBuffer) { 37 | items.clear() 38 | val quantity = buff.readShort().valueOrError.toInt() 39 | 40 | repeat(quantity) { 41 | val probability = buff.readUByte().valueOrError.toUInt() 42 | items.add(Item(probability)) 43 | items.last().guards = unserializeArmy(buff) 44 | items.last().rewards = unserializeRewardsCtr(buff) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/castle/Castle.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.castle 2 | 3 | import com.github.servb.pph.pheroes.common.common.MineralSetC 4 | 5 | const val CTL_INCOME: Int = 500 6 | 7 | @ExperimentalUnsignedTypes 8 | data class CTCNSTCAP(val siz: CastleSizeMask, val type: Int) { 9 | 10 | constructor(siz: CastleSizeMask, type: CastleTypeMask) : this(siz, type.v) 11 | 12 | fun Support(_type: CastleType, _siz: CastleSize) = 13 | (type and (1 shl _type.v)) != 0 && 14 | (siz.v and (1 shl _siz.v)) != 0 15 | } 16 | 17 | @ExperimentalUnsignedTypes 18 | data class CTLCNST_DESC_STRUCT( 19 | val name: String, 20 | val type: CastleConstructionType, 21 | val price: MineralSetC, 22 | val depend: Set, 23 | val caps: CTCNSTCAP, 24 | val fparam: Int, 25 | val sparam: Int 26 | ) 27 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/castle/CastleConstructionType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.castle 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | // Types of castle constructions 7 | enum class CastleConstructionType(override val v: Int) : UniqueValueEnum, CountValueEnum { 8 | GENERIC(0), 9 | DWELLING(1), // fparam = Creature type 10 | MAGEGUILD(2), // fparam = guild level 11 | TAVERN(3), 12 | MAGICNODE(4), 13 | MINE(5), // fparam = mineral type, sparam = quantity 14 | PERM_FSK_MOD(6), // fparam = skill, sparam = modifier 15 | DWELL_ENC(7), // fparam = dwelling id, sparam = modifier 16 | OBSERVPOST(8), 17 | LIBRARY(9), 18 | MANAVORTEX(10), 19 | TREASURY(11), 20 | MYSTICPOUND(12), 21 | NECRAMPLIFIER(13), 22 | COVEROFDARKNESS(14), 23 | COUNT(15); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/castle/CastleOrientation.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.castle 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class CastleOrientation( 7 | override val v: Int, 8 | val heroOrientation: Int? = null 9 | ) : UniqueValueEnum, CountValueEnum { 10 | LEFT(0, 1), 11 | RIGHT(1, 7), 12 | COUNT(2); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/castle/CastleSize.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.castle 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | 5 | enum class CastleSize(override val v: Int) : UniqueValueEnum { 6 | /** Village. */ 7 | SMALL(1), 8 | 9 | /** Town. */ 10 | MEDIUM(2), 11 | 12 | /** City. */ 13 | LARGE(3), 14 | 15 | COUNT(4); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/castle/CastleSizeMask.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.castle 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | 5 | enum class CastleSizeMask(override val v: Int) : UniqueValueEnum { 6 | S(1 shl CastleSize.SMALL.v), 7 | M(1 shl CastleSize.MEDIUM.v), 8 | L(1 shl CastleSize.LARGE.v), 9 | ML(M.v or L.v), 10 | SML(S.v or M.v or L.v); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/castle/CastleTypeMask.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.castle 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | 5 | @ExperimentalUnsignedTypes 6 | enum class CastleTypeMask(override val v: Int) : UniqueValueEnum { 7 | CITADEL(1 shl CastleType.CITADEL.v), 8 | STRONGHOLD(1 shl CastleType.STRONGHOLD.v), 9 | TOWER(1 shl CastleType.TOWER.v), 10 | DUNGEON(1 shl CastleType.DUNGEON.v), 11 | FORTRESS(1 shl CastleType.FORTRESS.v), 12 | NECROPOLIS(1 shl CastleType.NECROPOLIS.v), 13 | MIGHT(CITADEL.v or STRONGHOLD.v), 14 | MAGIC(TOWER.v or DUNGEON.v), 15 | MISC(FORTRESS.v or NECROPOLIS.v), 16 | ALL(MIGHT.v or MAGIC.v or MISC.v); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/GameLanguage.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | /** Game languages. TODO: provide tests, add all langs. */ 7 | enum class GameLanguage(override val v: Int) : UniqueValueEnum, CountValueEnum { 8 | ENGLISH(0), 9 | RUSSIAN(1), 10 | /*GLNG_POLISH, 11 | GLNG_SLOVAK, 12 | GLNG_GERMAN, 13 | GLNG_CZECH, 14 | GLNG_ITALIAN, 15 | GLNG_FRENCH, 16 | GLNG_SPANISH,*/ 17 | COUNT(2); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/GameType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | /** Game types. TODO: Provide documentation, provide tests. */ 7 | enum class GameType(override val v: Int) : UniqueValueEnum, CountValueEnum { 8 | SPLAYER(0), 9 | HOTSEAT(1), 10 | NETWORK(2), 11 | COUNT(3); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/GuardDisposition.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | /** Guards. TODO: Provide documentation. */ 7 | enum class GuardDisposition(override val v: Int) : UniqueValueEnum, CountValueEnum { 8 | COMPLIANT(0), 9 | AGGRESSIVE(1), 10 | SAVAGE(2), 11 | COUNT(3); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/HeroTypeMask.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | 5 | enum class HeroTypeMask(override val v: Int) : UniqueValueEnum { 6 | KNIGHT(0x1), 7 | BARBARIAN(0x2), 8 | WIZARD(0x4), 9 | WARLOCK(0x8), 10 | SORCERESS(0x10), 11 | NECROMANCER(0x20), 12 | 13 | GOOD(KNIGHT.v or WIZARD.v or SORCERESS.v), 14 | EVIL(BARBARIAN.v or WARLOCK.v or NECROMANCER.v), 15 | 16 | MIGHT(KNIGHT.v or BARBARIAN.v), 17 | MISC(SORCERESS.v or NECROMANCER.v), 18 | MAGIC(WIZARD.v or WARLOCK.v), 19 | 20 | ALL(GOOD.v or EVIL.v) 21 | } 22 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/MapItemType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class MapItemType(override val v: Int) : UniqueValueEnum, CountValueEnum { 7 | MINERAL(0), 8 | MANACRYSTAL(1), 9 | CAMPFIRE(2), 10 | CHEST(3), 11 | ARTIFACT(4), 12 | SPELLSCROLL(5), 13 | LAMP(6), 14 | KEYGUARD(7), 15 | COUNT(8); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/ObjectType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | 5 | enum class ObjectType(override val v: Int) : UniqueValueEnum { 6 | UNKNOWN(0), 7 | HERO(1), 8 | VIS_CNST(2), 9 | OWN_CNST(3), 10 | MAPOBJECT(4), 11 | DECOR(5); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/PathElementType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class PathElementType(override val v: Int) : UniqueValueEnum, CountValueEnum { 7 | WALL(0), 8 | ROAD(1), 9 | RIVER(2), 10 | COUNT(3); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/PlayerIdMask.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | 5 | enum class PlayerIdMask(override val v: Int) : UniqueValueEnum { 6 | NONE(0x00), 7 | RED(0x01), 8 | GREEN(0x02), 9 | BLUE(0x04), 10 | CYAN(0x08), 11 | MAGENTA(0x10), 12 | YELLOW(0x20), 13 | ALL( 14 | RED.v or GREEN.v or BLUE.v or CYAN.v or MAGENTA.v or YELLOW.v 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/RewardItem.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | data class RewardItem(val type: RewardItemType, val fParam: Int, val sParam: Int) 4 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/RewardItemType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.UndefinedCountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class RewardItemType( 7 | override val v: Int, 8 | private val fParam: String? = null, 9 | private val sParam: String? = null 10 | ) : UniqueValueEnum, UndefinedCountValueEnum { 11 | INVALID(-1), 12 | MINERAL(0, "Type", "Quantity"), 13 | EXPERIENCE(1, "None", "Quantity"), 14 | MANAPTS(2, "None", "Quantity"), 15 | TRAVELPTS(3, "None", "Quantity"), 16 | MORALE(4, "None", "Modifier"), 17 | LUCK(5, "None", "Modifier"), 18 | FURTSKILL(6, "Type", "Modifier (Primary skill only)"), 19 | ARTIFACT(7, "ArtifactType level or idx", "None (can be defined as random)"), 20 | MAGICSPELL(8, "Spell level or idx", "None (can be defined as random)"), 21 | CREATGROUP(9, "Type", "Quantity"), 22 | COUNT(10); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/RewardsCtr.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | typealias RewardsCtrC = List 4 | typealias RewardsCtr = MutableList 5 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/SpriteLevel.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | 5 | enum class SpriteLevel(override val v: Int) : UniqueValueEnum { 6 | GROUND(0), 7 | PLANT(1), 8 | OBJECT(2); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/VisionLevel.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | 5 | /** Vision level (information level). */ 6 | enum class VisionLevel(override val v: Int) : UniqueValueEnum { 7 | NONE(0), 8 | BASIC(1), 9 | EXPERT(2); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/artifact/ArtifactAssign.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common.artifact 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class ArtifactAssign(override val v: Int) : UniqueValueEnum, CountValueEnum { 7 | HEAD(0), 8 | NECK(1), 9 | TORSO(2), 10 | SHOULDERS(3), 11 | HANDS(4), 12 | FINGERS(5), 13 | LEGS(6), 14 | FEET(7), 15 | MISC(8), 16 | COUNT(9); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/artifact/ArtifactLevel.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common.artifact 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class ArtifactLevel(override val v: Int) : UniqueValueEnum, CountValueEnum { 7 | NONE(0), 8 | TREASURE(1), 9 | MINOR(2), 10 | MAJOR(3), 11 | RELICT(4), 12 | ULTIMATE(5), 13 | COUNT(6); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/artifact/ArtifactList.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common.artifact 2 | 3 | interface iItemC { 4 | val id: Short 5 | val assign: HeroArtifactCell 6 | } 7 | 8 | data class iItem(override var id: Short, override var assign: HeroArtifactCell) : iItemC 9 | 10 | typealias ArtifactListC = List 11 | typealias ArtifactList = MutableList 12 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/artifact/HeroArtifactCell.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common.artifact 2 | 3 | import com.github.servb.pph.util.helpertype.UndefinedCountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class HeroArtifactCell( 7 | override val v: Int, 8 | val assign: ArtifactAssign? = null 9 | ) : UniqueValueEnum, UndefinedCountValueEnum { 10 | UNDEFINED(-1), 11 | HEAD(0, ArtifactAssign.HEAD), 12 | NECK(1, ArtifactAssign.NECK), 13 | TORSO(2, ArtifactAssign.TORSO), 14 | LEFT_HAND(3, ArtifactAssign.HANDS), 15 | RIGHT_HAND(4, ArtifactAssign.HANDS), 16 | LEFT_FINGERS(5, ArtifactAssign.FINGERS), 17 | RIGHT_FINGERS(6, ArtifactAssign.FINGERS), 18 | SHOULDERS(7, ArtifactAssign.SHOULDERS), 19 | LEGS(8, ArtifactAssign.LEGS), 20 | FEET(9, ArtifactAssign.FEET), 21 | MISC1(10, ArtifactAssign.MISC), 22 | MISC2(11, ArtifactAssign.MISC), 23 | MISC3(12, ArtifactAssign.MISC), 24 | MISC4(13, ArtifactAssign.MISC), 25 | COUNT(14); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/artifact/RandomArtifact.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common.artifact 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | 5 | enum class RandomArtifact(override val v: Int) : UniqueValueEnum { 6 | RAND(0xFF00), 7 | RAND_L1(0xFF01), 8 | RAND_L2(0xFF02), 9 | RAND_L3(0xFF03), 10 | RAND_L4(0xFF04); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/skill/SecondarySkillEntry.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common.skill 2 | 3 | data class SecondarySkillEntry( 4 | val skill: SecondarySkillType = SecondarySkillType.NONE, 5 | val level: SecondarySkillLevel = SecondarySkillLevel.NONE 6 | ) 7 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/skill/SecondarySkillLevel.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common.skill 2 | 3 | import com.github.servb.pph.util.helpertype.UndefinedCountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class SecondarySkillLevel(override val v: Int) : UniqueValueEnum, UndefinedCountValueEnum { 7 | NONE(-1), 8 | BASIC(0), 9 | ADVANCED(1), 10 | EXPERT(2), 11 | COUNT(3); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/common/skill/SecondarySkills.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.common.skill 2 | 3 | typealias SecondarySkillsC = List 4 | typealias SecondarySkills = MutableList 5 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/constantsSfx.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common 2 | 3 | /* 4 | * TODO: Use an external file. 5 | * This file is automatically generated by Pocket Heroes resource compiler. 6 | * Do not modify this file -- YOUR CHANGES WILL BE ERASED! 7 | */ 8 | 9 | const val CSND_PREBATTLE = 0 10 | const val CSND_QUEST_DLG = 1 11 | const val CSND_NEW_LEVEL_DLG = 2 12 | const val CSND_TREASURE = 3 13 | const val CSND_FLAG_MINE = 4 14 | const val CSND_BUTTON = 5 15 | const val CSND_DIG = 6 16 | const val CSND_SEAWASH = 7 17 | const val CSND_PICKUP01 = 8 18 | const val CSND_PICKUP02 = 9 19 | const val CSND_PICKUP03 = 10 20 | const val CSND_PICKUP04 = 11 21 | const val CSND_PICKUP05 = 12 22 | const val CSND_DEL_GUARD = 13 23 | const val CSND_TELEPORT_OUT = 14 24 | const val CSND_HMOVE01 = 15 25 | const val CSND_HMOVE02 = 16 26 | const val CSND_HMOVE03 = 17 27 | const val CSND_HMOVE04 = 18 28 | const val CSND_HMOVE05 = 19 29 | const val CSND_HMOVE06 = 20 30 | const val CSND_ALCH_LAB = 21 31 | const val CSND_SAWMILL = 22 32 | const val CSND_MINE = 23 33 | const val CSND_SHRINE = 24 34 | const val CSND_STABLES = 25 35 | const val CSND_VOLCANO = 26 36 | const val CSND_LAKES = 27 37 | const val CSND_TELEPORT = 28 38 | const val CSND_ARENA = 29 39 | const val CSND_BLACKSMITH = 30 40 | const val CSND_HYDRA_POND = 31 41 | const val CSND_MARKETPLACE = 32 42 | const val CSND_ARCHERS_HUT = 33 43 | const val CSND_HAUNTED_HOUSE = 34 44 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/construction/OwnerableConstructionType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.construction 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class OwnerableConstructionType(override val v: Int) : UniqueValueEnum, CountValueEnum { 7 | BASIC(0), // Generic Ownerable construction 8 | FURTSKILL(1), // Modifies one or several owner's further skills 9 | COUNT(2), 10 | } 11 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/construction/VisitableConstructionType.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.construction 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class VisitableConstructionType(override val v: Int) : UniqueValueEnum, CountValueEnum { 7 | BASIC(0), // Generic Visitable construction 8 | STABLE(1), // Adds 'n' action points (end of week to each visitor) 9 | GAZEBO(2), // Adds 'n' exp points (once to each visitor) 10 | MANASOURCE(3), // Adds 'n' mana points (end of week to each visitor) 11 | MLMODIFIER(4), // Modifies morale and luck 12 | PSMODIFIER(5), // Modifies set of primary skills by mask 13 | OBELISK(6), // Opens one element of puzzle map 14 | SIGN(7), // Shows message 15 | DWELLING(8), // Dwelling 16 | WITCHHUT(9), // Witch Hut (learn random or specified secondary skill) 17 | SHRINE(10), // Magic shrine (learn random spell of specified (1-3) level) 18 | TREASURY(11), // Resource treasury 19 | TELEPORT(12), // Teleports hero 20 | KEYMASTER(13), // Gives specified key 21 | KNWLTREE(14), // Tree of Knowledge 22 | WINDMILL(15), // Windmill (gives random ammount of random mineral one time per week) 23 | WEEKLYMIN(16), // Gives fixed ammount of specified mineral(s) one time per week 24 | COUNT(17), 25 | // Windmill (2-5 of random resource (except gold) one time per week) 26 | // Water wheel (+1000gp one time per week) 27 | // University (lern one or more from 4 secondray skills for 2.000) 28 | // Dragon utopia 29 | // Altar of sacrifice (creatures and artifacts to experience) 30 | // Market 31 | // Black market 32 | // Treasures ('n' units of 'x' creature type guards 'm' mineral set) 33 | // Den of thieves (shows detailed world information) 34 | // Shrine of magic (learns random 1-3 level spell) 35 | // Keymaster's Tent 36 | // Seer's hut 37 | // Crypt/Graveyard 38 | // Corps/Skeleton 39 | } 40 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/creature/Speed.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.creature 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | 5 | enum class Speed(override val v: Int, private val description: String? = null) : UniqueValueEnum { 6 | SPEED_SUPERSLOW(1), 7 | SPEED_ULTRASLOW(2), 8 | SPEED_VERYSLOW(3), 9 | SPEED_EXTRASLOW(4), 10 | SPEED_SLOW(5), 11 | SPEED_SWIFT(6), 12 | SPEED_EXTRASWIFT(7), 13 | SPEED_VERYSWIFT(8), 14 | SPEED_ULTRASWIFT(9, "2 to 2"), 15 | SPEED_SUPERSWIFT(10, "1 to 2 or 2 to 1"), 16 | SPEED_QUICK(11, "1 to 1"), 17 | SPEED_EXTRAQUICK(12), 18 | SPEED_VERYQUICK(13), 19 | SPEED_ULTRAQUICK(14), 20 | SPEED_SUPERQUICK(15), 21 | SPEED_FAST(16), 22 | SPEED_EXTRAFAST(17), 23 | SPEED_VERYFAST(18), 24 | SPEED_ULTRAFAST(19), 25 | SPEED_SUPERFAST(20), 26 | SPEED_MAX(21); 27 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/event/iTimeEvent.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.event 2 | 3 | import com.github.servb.pph.pheroes.common.common.MineralSet 4 | import com.github.servb.pph.pheroes.common.common.MineralSetC 5 | import com.github.servb.pph.pheroes.common.common.PlayerId 6 | import com.github.servb.pph.pheroes.common.common.PlayerIdMask 7 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 8 | 9 | data class iTimeEvent( 10 | val name: String, 11 | val text: String, 12 | val playerMask: PlayerIdMask, 13 | val time: Int, 14 | val repTime: EventFreq, 15 | val minerals: MineralSetC 16 | ) { 17 | enum class EventFreq(override val v: Int, val days: Int) : UniqueValueEnum { 18 | NEVER(0, 0), 19 | DAY1(1, 1), DAYS2(2, 2), DAYS3(3, 3), DAYS4(4, 4), DAYS5(5, 5), DAYS6(6, 6), 20 | WEEK1(7, 7), WEEKS2(8, 14), WEEKS3(9, 21), MONTH1(10, 28), 21 | } 22 | 23 | constructor() : this("", "", PlayerIdMask.ALL, 1, EventFreq.NEVER, MineralSet()) 24 | 25 | fun IsConform(pid: PlayerId, curDay: Int) = when { 26 | playerMask.v and (1 shl pid.v) == 0 -> false 27 | curDay < time -> false 28 | curDay == time -> true 29 | repTime != EventFreq.NEVER -> 0 == (curDay - time) % repTime.days 30 | else -> false 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/event/iTimeEventMgr.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.event 2 | 3 | class iTimeEventMgr { 4 | fun EventsCount() = m_events.size 5 | fun Event(idx: Int) = m_events[idx] 6 | fun AddEvent(event: iTimeEvent) = m_events.add(event) 7 | fun DeleteEvent(idx: Int) { 8 | m_events.removeAt(idx) 9 | } 10 | 11 | fun DeleteAll() = m_events.clear() 12 | 13 | private val m_events = mutableListOf() 14 | } 15 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/lzo.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common 2 | 3 | import com.github.servb.pph.gxlib.memory.DynamicBuffer 4 | import io.airlift.compress.lzo.LzoCompressor 5 | import io.airlift.compress.lzo.LzoDecompressor 6 | 7 | private val LZO_BLOCK_HDR: Short = ('L' + 256 * 'Z'.toInt()).toShort() 8 | 9 | @ExperimentalUnsignedTypes 10 | fun decompress(lzoBuffer: ByteArray, lzoBufferLength: Int, rawBuffer: DynamicBuffer): Int { 11 | val hdr = (lzoBuffer[0] + 256 * lzoBuffer[1]).toShort() 12 | check(hdr == LZO_BLOCK_HDR) { "Wrong HDR: $hdr" } 13 | 14 | val rawBufferLength = lzoBuffer[2] + 256 * (lzoBuffer[3] + 256 * (lzoBuffer[4] + 256 * lzoBuffer[5])) 15 | check(rawBufferLength >= 0) { "Negative raw buffer length: $rawBufferLength" } 16 | 17 | rawBuffer.reInit(rawBufferLength) 18 | rawBuffer.incrementSize(rawBufferLength) 19 | 20 | val rawArray = ByteArray(rawBufferLength) 21 | LzoDecompressor().decompress(lzoBuffer, 6, lzoBufferLength - 6, rawArray, 0, rawBufferLength) 22 | rawBuffer.write(rawArray, 1, rawBufferLength) 23 | 24 | return rawBufferLength 25 | } 26 | 27 | @ExperimentalUnsignedTypes 28 | fun compress(rawBuffer: ByteArray, rawBufferLength: Int, lzoBuffer: DynamicBuffer): Int { 29 | val outLength = rawBufferLength + rawBufferLength / 16 + 64 + 3 30 | val outBuffer = ByteArray(outLength) 31 | 32 | LzoCompressor().compress(rawBuffer, 0, rawBufferLength, outBuffer, 0, outLength) 33 | 34 | lzoBuffer.write(LZO_BLOCK_HDR) 35 | lzoBuffer.write(rawBufferLength) 36 | lzoBuffer.write(outBuffer, 1, outLength) 37 | 38 | return lzoBuffer.size 39 | } 40 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/magic/MagicSchoolLevel.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.magic 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class MagicSchoolLevel(override val v: Int) : UniqueValueEnum, CountValueEnum { 7 | NONE(0), 8 | BASIC(1), 9 | ADVANCED(2), 10 | EXPERT(3), 11 | COUNT(4), 12 | } 13 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/magic/MagicSpell.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.magic 2 | 3 | import com.github.servb.pph.util.helpertype.UndefinedCountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | /** Spell list. */ 7 | enum class MagicSpell(override val v: Int) : UniqueValueEnum, UndefinedCountValueEnum { 8 | INVALID(-1), 9 | // Air magic 15-3 = 12 10 | MAGICARROW(0), 11 | PROTEARTH(1), 12 | HASTE(2), 13 | SHIELD(3), 14 | DISRAY(4), 15 | LIGHTNINGBOLT(5), 16 | PRECISION(6), 17 | AIRSHIELD(7), 18 | HOLYWORD(8), 19 | COUNTERSTRIKE(9), 20 | RESURRECT(10), 21 | AIRELEMENTAL(11), 22 | 23 | // Earth magic 13-3 = 10 24 | PROTAIR(12), 25 | SLOW(13), 26 | STONESKIN(14), 27 | VISIONS(15), 28 | EARTHQUAKE(16), 29 | SORROW(17), 30 | METEORSHOWER(18), 31 | TOWNPORTAL(19), 32 | IMPLOSION(20), 33 | EARTHELEMENTAL(21), 34 | 35 | // Fire magic 15-3 = 12 36 | BLOODLUST(22), 37 | PROTWATER(23), 38 | CURSE(24), 39 | BLIND(25), 40 | WEAKNESS(26), 41 | DEATHRIPPLE(27), 42 | FIREBALL(28), 43 | MISFORTUNE(29), 44 | ANIMATEDEAD(30), 45 | FIREBLAST(31), 46 | ARMAGEDDON(32), 47 | FIREELEMENTAL(33), 48 | 49 | // Water magic 15-4 = 11 50 | BLESS(34), 51 | PROTFIRE(35), 52 | DISPEL(36), 53 | CURE(37), 54 | COLDRAY(38), 55 | FORTUNE(39), 56 | MIRTH(40), 57 | COLDRING(41), 58 | ANTIMAGIC(42), 59 | PRAYER(43), 60 | WATERELEMENTAL(44), 61 | 62 | // New spells 63 | SUMMONSPRITES(45), 64 | 65 | COUNT(46), 66 | } 67 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/magic/SpellClass.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.magic 2 | 3 | import com.github.servb.pph.util.helpertype.CountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class SpellClass(override val v: Int) : UniqueValueEnum, CountValueEnum { 7 | DAMAGE(0), // fparam = damage 8 | FURTSKILL(1), // fparam = skill, sparam = modifier 9 | DISRAY(2), // fparam = defence modifier 10 | RESURRECT(3), // fparam = hit points, sparam = true/not 11 | SUMMON(4), // fparam = creature type, sparam = quantity 12 | BLESS(5), // fparam = modifier (+1, 0, -1), sparam = anti spell 13 | BLIND(6), // fparam = retail power (%), sparam = not used 14 | EARTHQUAKE(7), // fparam = walls ammount 15 | DISPEL(8), // - none - 16 | CURE(9), // fparam = hit points per spell power 17 | TOWNPORTAL(10), // fparam = (_?_) 18 | ANTIMAGIC(11), // fparam = maxLevel 19 | PRAYER(12), // fparam = value 20 | VISION(13), // fparam = radius 21 | COUNT(14), 22 | } 23 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/magic/SpellLabel.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.magic 2 | 3 | import com.github.servb.pph.util.helpertype.UndefinedCountValueEnum 4 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 5 | 6 | enum class SpellLabel(override val v: Int) : UniqueValueEnum, UndefinedCountValueEnum { 7 | NONE(0xFF), 8 | PROTEARTH(0), 9 | HASTE(1), 10 | SHIELD(2), 11 | PRECISION(3), 12 | AIRSHIELD(4), 13 | COUNTERSTRIKE(5), 14 | PROTAIR(6), 15 | SLOW(7), 16 | STONESKIN(8), 17 | SORROW(9), 18 | BLOODLUST(10), 19 | PROTWATER(11), 20 | CURSE(12), 21 | BLIND(13), 22 | WEAKNESS(14), 23 | MISFORTUNE(15), 24 | BLESS(16), 25 | PROTFIRE(17), 26 | FORTUNE(18), 27 | MIRTH(19), 28 | ANTIMAGIC(20), 29 | PRAYER(21), 30 | DISRAY(22), 31 | COUNT(23), 32 | } 33 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/magic/SpellTargetMode.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.magic 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | 5 | /** Target mode (used for combat spells). */ 6 | enum class SpellTargetMode(override val v: Int) : UniqueValueEnum { 7 | NONE(0), 8 | SUMMON(1), 9 | EARTHQUAKE(2), 10 | CREAT_GROUP(3), 11 | BALL_SET(4), 12 | BLAST_SET(5), 13 | RING_SET(6), 14 | ALL(7), 15 | } 16 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/pheroes/common/magic/SpellTargetTypeMask.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common.magic 2 | 3 | import com.github.servb.pph.util.helpertype.UniqueValueEnum 4 | import com.github.servb.pph.util.helpertype.or 5 | 6 | /** Target type mask (used for combat spells). */ 7 | enum class SpellTargetTypeMask(override val v: Int) : UniqueValueEnum { 8 | NONE(0), 9 | FRIENDLY(0b000_0001), 10 | ENEMY(0b000_0010), 11 | UNDEAD(0b000_0100), 12 | LIFELESS(0b000_1000), 13 | NORMAL(0b001_0000), 14 | TROOPS(0b010_0000), 15 | SHOOTERS(0b100_0000), 16 | FRUNDEADS(FRIENDLY or UNDEAD or TROOPS or SHOOTERS), 17 | FRNUNDEADS(FRIENDLY or LIFELESS or NORMAL or TROOPS or SHOOTERS), 18 | ENNUNDEADS(ENEMY or LIFELESS or NORMAL or TROOPS or SHOOTERS), 19 | ENNORMALS(ENEMY or NORMAL or TROOPS or SHOOTERS), 20 | ALLUNDEADS(FRIENDLY or ENEMY or UNDEAD or TROOPS or SHOOTERS), 21 | ALLNUNDEADS(FRIENDLY or ENEMY or NORMAL or LIFELESS or TROOPS or SHOOTERS), 22 | ALLNORMALS(FRIENDLY or ENEMY or NORMAL or TROOPS or SHOOTERS), 23 | FRNORMALS(FRIENDLY or NORMAL or TROOPS or SHOOTERS), 24 | FRTROOPS(FRIENDLY or UNDEAD or LIFELESS or NORMAL or TROOPS), 25 | FRSHOOTERS(FRIENDLY or UNDEAD or LIFELESS or NORMAL or SHOOTERS), 26 | ALLFRIENDLY(FRIENDLY or UNDEAD or LIFELESS or NORMAL or TROOPS or SHOOTERS), 27 | ALLENEMY(ENEMY or UNDEAD or LIFELESS or NORMAL or TROOPS or SHOOTERS), 28 | ALL(FRIENDLY or ENEMY or UNDEAD or LIFELESS or NORMAL or TROOPS or SHOOTERS), 29 | } 30 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/util/helpertype/Aliases.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.util.helpertype 2 | 3 | typealias DWORD = Int 4 | typealias HDC = Int 5 | typealias HINSTANCE = Int 6 | typealias HWND = Int 7 | typealias LPARAM = Int 8 | typealias LPCWSTR = String 9 | typealias LRESULT = Int 10 | typealias VOID_STAR = Nothing 11 | typealias WPARAM = Int 12 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/util/helpertype/Defines.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.util.helpertype 2 | 3 | const val HPC_JORNADA = false 4 | const val OS_WINCE = false 5 | const val OS_WIN32 = true 6 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/util/helpertype/EnumC.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.util.helpertype 2 | 3 | /** 4 | * C-like Enumeration interface. 5 | * 6 | * @author SerVB 7 | */ 8 | interface EnumC { 9 | 10 | /** 11 | * Returns the value of the element. 12 | * 13 | * @return The value of the element. 14 | */ 15 | val value: Int 16 | } 17 | -------------------------------------------------------------------------------- /src/main/kotlin/com/github/servb/pph/util/helpertype/File.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.util.helpertype 2 | 3 | import java.io.FileInputStream 4 | 5 | // TODO: check for correctness (LE or BE) 6 | 7 | fun FileInputStream.readShort(): Short = (read() + 256 * read()).toShort() 8 | fun FileInputStream.readInt(): Int = read() + 256 * (read() + 256 * (read() + 256 * read())) 9 | -------------------------------------------------------------------------------- /src/test/kotlin/com/github/servb/pph/gxlib/gxlcommondef/GxlCommonDefTest.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib.gxlcommondef 2 | 3 | import io.kotlintest.shouldBe 4 | import io.kotlintest.specs.StringSpec 5 | 6 | class GxlCommonDefTest : StringSpec() { 7 | init { 8 | "size of Rand table should be 256" { 9 | iRandTable.size shouldBe 256 10 | } 11 | 12 | "Rand table should have unique elements" { 13 | iRandTable.toSet().size shouldBe iRandTable.size 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/kotlin/com/github/servb/pph/gxlib/gxlcommontpl/GxlCommonTplTest.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib.gxlcommontpl 2 | 3 | import io.kotlintest.shouldBe 4 | import io.kotlintest.specs.StringSpec 5 | import io.kotlintest.tables.* 6 | 7 | @ExperimentalUnsignedTypes 8 | class GxlCommonTplTest : StringSpec() { 9 | init { 10 | "iCLAMP" { 11 | forAll( 12 | Table4( 13 | Headers4("min", "max", "value", "expected"), 14 | listOf( 15 | row(1, 2, 3, 2), 16 | row(1, 1, 1, 1), 17 | row(1, 1, 0, 1), 18 | row(10, 30, 12, 12), 19 | row(10, 30, 16, 16), 20 | row(10, 15, 10, 10), 21 | row(10, 15, 15, 15) 22 | ) 23 | ) 24 | ) { min, max, value, expected -> 25 | iCLAMP(min, max, value) shouldBe expected 26 | } 27 | } 28 | 29 | "iDIF" { 30 | // TODO: Test all overloads 31 | forAll( 32 | Table3( 33 | Headers3("a", "b", "expected"), 34 | listOf( 35 | row(2, 3, 1), 36 | row(1, 1, 0), 37 | row(1, 0, 1), 38 | row(30, 12, 18), 39 | row(30, 16, 14), 40 | row(15, 10, 5), 41 | row(15, 15, 0) 42 | ) 43 | ) 44 | ) { a, b, expected -> 45 | iDIF(a, b) shouldBe expected 46 | } 47 | } 48 | 49 | "iALIGN" { 50 | forAll( 51 | Table3( 52 | Headers3("a", "b", "expected"), 53 | listOf( 54 | row(2u, 3u, 3u), 55 | row(1u, 1u, 1u), 56 | row(1u, 10u, 10u), 57 | row(30u, 12u, 36u), 58 | row(30u, 16u, 32u), 59 | row(15u, 10u, 20u), 60 | row(15u, 15u, 15u) 61 | ) 62 | ) 63 | ) { a, b, expected -> 64 | iALIGN(a, b) shouldBe expected 65 | } 66 | } 67 | 68 | "iWRAP" { 69 | forAll( 70 | Table4( 71 | Headers4("val", "minv", "wrap", "expected"), 72 | listOf( 73 | row(2, 3, 5, 4), 74 | row(1, 1, 2, 1), 75 | row(1, 10, 34, 25), 76 | row(30, 12, 16, 26), 77 | row(30, 16, 32, 30), 78 | row(15, 10, 12, 13), 79 | row(15, 15, 16, 15) 80 | ) 81 | ) 82 | ) { value, minv, wrap, expected -> 83 | iWRAP(value.toShort(), minv.toShort(), wrap.toShort()) shouldBe expected.toShort() 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/test/kotlin/com/github/servb/pph/gxlib/gxlmath/GxlMathTest.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib.gxlmath 2 | 3 | import io.kotlintest.matchers.plusOrMinus 4 | import io.kotlintest.shouldBe 5 | import io.kotlintest.specs.StringSpec 6 | 7 | @ExperimentalUnsignedTypes 8 | class GxlMathTest : StringSpec() { 9 | init { 10 | "PI shouldn't differ extremely" { 11 | PI shouldBe (Math.PI.toFloat() plusOrMinus Math.PI.toFloat() * 1e-6f) 12 | } 13 | 14 | "int_sqrt should give sqrt" { 15 | for (i in 0u until 1000u) { 16 | // TODO: Remove toLong 17 | int_sqrt(i) shouldBe Math.sqrt(i.toLong().toDouble()).toLong().toUInt() 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/kotlin/com/github/servb/pph/gxlib/gxlmetrics/PointTest.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.gxlib.gxlmetrics 2 | 3 | import io.kotlintest.properties.Gen 4 | import io.kotlintest.properties.assertAll 5 | import io.kotlintest.shouldBe 6 | import io.kotlintest.specs.StringSpec 7 | 8 | @ExperimentalUnsignedTypes 9 | class PointcGenerator : Gen { 10 | override fun constants() = listOf(Point().toPointc()) 11 | override fun random() = generateSequence { 12 | Point(Gen.int().random().first(), Gen.int().random().first()).toPointc() 13 | } 14 | } 15 | 16 | @ExperimentalUnsignedTypes 17 | class PointGenerator : Gen { 18 | override fun constants() = listOf(Point()) 19 | override fun random() = generateSequence { 20 | Point(Gen.int().random().first(), Gen.int().random().first()) 21 | } 22 | } 23 | 24 | @ExperimentalUnsignedTypes 25 | class PointcTest : StringSpec() { 26 | init { 27 | "+ Pointc" { 28 | assertAll(PointcGenerator(), PointGenerator()) { p, other -> 29 | (p + other) shouldBe Point(p.x + other.x, p.y + other.y).toPointc() 30 | } 31 | } 32 | 33 | "- Pointc" { 34 | assertAll(PointcGenerator(), PointGenerator()) { p, other -> 35 | (p - other) shouldBe Point(p.x - other.x, p.y - other.y).toPointc() 36 | } 37 | } 38 | 39 | "+ Int offset" { 40 | assertAll(PointcGenerator(), Gen.int()) { p, offs -> 41 | (p + offs) shouldBe Point(p.x + offs, p.y + offs).toPointc() 42 | } 43 | } 44 | 45 | "- Int offset" { 46 | assertAll(PointcGenerator(), Gen.int()) { p, offs -> 47 | (p - offs) shouldBe Point(p.x - offs, p.y - offs).toPointc() 48 | } 49 | } 50 | } 51 | } 52 | 53 | @ExperimentalUnsignedTypes 54 | class PointTest : StringSpec() { 55 | init { 56 | "default constructor should give (0, 0) point" { 57 | Point() shouldBe Point(0, 0) 58 | } 59 | 60 | "copy constructor (Pointc)" { 61 | assertAll(PointcGenerator()) { other -> 62 | Point(other) shouldBe Point(other.x, other.y) 63 | } 64 | } 65 | 66 | "+ Pointc" { 67 | assertAll(PointGenerator(), PointcGenerator()) { p, other -> 68 | (p + other) shouldBe Point(p.x + other.x, p.y + other.y) 69 | } 70 | } 71 | 72 | "- Pointc" { 73 | assertAll(PointGenerator(), PointcGenerator()) { p, other -> 74 | (p - other) shouldBe Point(p.x - other.x, p.y - other.y) 75 | } 76 | } 77 | 78 | "+ Int offset" { 79 | assertAll(PointGenerator(), Gen.int()) { p, offs -> 80 | (p + offs) shouldBe Point(p.x + offs, p.y + offs) 81 | } 82 | } 83 | 84 | "- Int offset" { 85 | assertAll(PointGenerator(), Gen.int()) { p, offs -> 86 | (p - offs) shouldBe Point(p.x - offs, p.y - offs) 87 | } 88 | } 89 | 90 | "+= Pointc" { 91 | assertAll(PointGenerator(), PointcGenerator()) { p, other -> 92 | val initial = p.copy() 93 | p += other 94 | p shouldBe Point(initial.x + other.x, initial.y + other.y) 95 | } 96 | } 97 | 98 | "-= Pointc" { 99 | assertAll(PointGenerator(), PointcGenerator()) { p, other -> 100 | val initial = p.copy() 101 | p -= other 102 | p shouldBe Point(initial.x - other.x, initial.y - other.y) 103 | } 104 | } 105 | 106 | "+= Sizec" { 107 | assertAll(PointGenerator(), SizecGenerator()) { p, other -> 108 | val initial = p.copy() 109 | p += other 110 | p shouldBe Point(initial.x + other.w.toInt(), initial.y + other.h.toInt()) 111 | } 112 | } 113 | 114 | "-= Sizec" { 115 | assertAll(PointGenerator(), SizecGenerator()) { p, other -> 116 | val initial = p.copy() 117 | p -= other 118 | p shouldBe Point(initial.x - other.w.toInt(), initial.y - other.h.toInt()) 119 | } 120 | } 121 | 122 | "+= Int offset" { 123 | assertAll(PointGenerator(), Gen.int()) { p, offs -> 124 | val initial = p.copy() 125 | p += offs 126 | p shouldBe Point(initial.x + offs, initial.y + offs) 127 | } 128 | } 129 | 130 | "-= Int offset" { 131 | assertAll(PointGenerator(), Gen.int()) { p, offs -> 132 | val initial = p.copy() 133 | p -= offs 134 | p shouldBe Point(initial.x - offs, initial.y - offs) 135 | } 136 | } 137 | 138 | ".MoveX" { 139 | assertAll(PointGenerator(), Gen.int()) { p, offs -> 140 | val initial = p.copy() 141 | p.MoveX(offs) 142 | p shouldBe Point(initial.x + offs, initial.y) 143 | } 144 | } 145 | 146 | ".MoveY" { 147 | assertAll(PointGenerator(), Gen.int()) { p, offs -> 148 | val initial = p.copy() 149 | p.MoveY(offs) 150 | p shouldBe Point(initial.x, initial.y + offs) 151 | } 152 | } 153 | 154 | ".Move" { 155 | assertAll(PointGenerator(), Gen.int(), Gen.int()) { p, dx, dy -> 156 | val initial = p.copy() 157 | p.Move(dx, dy) 158 | p shouldBe Point(initial.x + dx, initial.y + dy) 159 | } 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/test/kotlin/com/github/servb/pph/pheroes/common/SerializeTest.kt: -------------------------------------------------------------------------------- 1 | package com.github.servb.pph.pheroes.common 2 | 3 | import com.github.servb.pph.gxlib.gxlmetrics.Point 4 | import com.github.servb.pph.gxlib.memory.DynamicBuffer 5 | import io.kotlintest.shouldBe 6 | import io.kotlintest.specs.StringSpec 7 | 8 | @ExperimentalUnsignedTypes 9 | class SerializeTest : StringSpec({ 10 | "point" { 11 | "DynamicBuffer serialize unserialize" { 12 | val point = Point(10, 2).toPointc() 13 | val buff = DynamicBuffer() 14 | 15 | serialize(buff, point) 16 | buff.seek(0) 17 | 18 | val actualPoint = unserializePoint(buff) 19 | actualPoint shouldBe point 20 | } 21 | 22 | // TODO: test stream version 23 | } 24 | }) 25 | --------------------------------------------------------------------------------