From cc1d80442eff4508011c8f5bb8169824bd953f1e Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Fri, 7 Aug 2026 13:24:46 +0200 Subject: [PATCH] refactor: split out game engine experiment and demo game --- programs/GNUmakefile | 12 +- .../Animals/Chicken/Chicken.png | Bin 622 -> 0 bytes .../Cute_Fantasy_Free/Animals/Cow/Cow.png | Bin 983 -> 0 bytes .../Cute_Fantasy_Free/Animals/Pig/Pig.png | Bin 735 -> 0 bytes .../Cute_Fantasy_Free/Animals/Sheep/Sheep.png | Bin 748 -> 0 bytes .../Cute_Fantasy_Free/Enemies/Skeleton.png | Bin 5356 -> 0 bytes .../Cute_Fantasy_Free/Enemies/Slime_Green.png | Bin 3967 -> 0 bytes .../Outdoor decoration/Bridge_Wood.png | Bin 1161 -> 0 bytes .../Outdoor decoration/Chest.png | Bin 386 -> 0 bytes .../Outdoor decoration/Fences.png | Bin 585 -> 0 bytes .../House_1_Wood_Base_Blue.png | Bin 2898 -> 0 bytes .../Outdoor decoration/Oak_Tree.png | Bin 1495 -> 0 bytes .../Outdoor decoration/Oak_Tree_Small.png | Bin 921 -> 0 bytes .../Outdoor decoration/Outdoor_Decor_Free.png | Bin 7431 -> 0 bytes .../Cute_Fantasy_Free/Player/Player.png | Bin 7770 -> 0 bytes .../Player/Player_Actions.png | Bin 7609 -> 0 bytes .../Cute_Fantasy_Free/Tiles/Beach_Tile.png | Bin 648 -> 0 bytes .../Cute_Fantasy_Free/Tiles/Cliff_Tile.png | Bin 1600 -> 0 bytes .../Cute_Fantasy_Free/Tiles/FarmLand_Tile.png | Bin 371 -> 0 bytes .../Cute_Fantasy_Free/Tiles/Grass_Middle.png | Bin 99 -> 0 bytes .../Cute_Fantasy_Free/Tiles/Path_Middle.png | Bin 99 -> 0 bytes .../Cute_Fantasy_Free/Tiles/Path_Tile.png | Bin 1129 -> 0 bytes .../Cute_Fantasy_Free/Tiles/Water_Middle.png | Bin 99 -> 0 bytes .../Cute_Fantasy_Free/Tiles/Water_Tile.png | Bin 1500 -> 0 bytes .../gameengine/Cute_Fantasy_Free/read_me.txt | 10 - programs/include/engine/audio.h | 81 -- programs/include/engine/collision.h | 48 - programs/include/engine/engine.h | 200 --- programs/include/engine/input.h | 87 -- programs/include/engine/sprite.h | 264 ---- programs/include/engine/tilemap.h | 134 -- programs/include/engine/ui.h | 114 -- programs/src/installer/components.cpp | 6 - programs/src/rpgdemo/Makefile | 107 -- programs/src/rpgdemo/main.cpp | 1079 ----------------- programs/src/rpgdemo/manifest.toml | 8 - programs/src/rpgdemo/stb_impl.cpp | 69 -- scripts/install_apps.sh | 1 - 38 files changed, 4 insertions(+), 2216 deletions(-) delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Animals/Chicken/Chicken.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Animals/Cow/Cow.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Animals/Pig/Pig.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Animals/Sheep/Sheep.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Enemies/Skeleton.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Enemies/Slime_Green.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/Bridge_Wood.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/Chest.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/Fences.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/House_1_Wood_Base_Blue.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/Oak_Tree.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/Oak_Tree_Small.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/Outdoor_Decor_Free.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Player/Player.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Player/Player_Actions.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Tiles/Beach_Tile.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Tiles/Cliff_Tile.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Tiles/FarmLand_Tile.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Tiles/Grass_Middle.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Tiles/Path_Middle.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Tiles/Path_Tile.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Tiles/Water_Middle.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/Tiles/Water_Tile.png delete mode 100644 programs/gameengine/Cute_Fantasy_Free/read_me.txt delete mode 100644 programs/include/engine/audio.h delete mode 100644 programs/include/engine/collision.h delete mode 100644 programs/include/engine/engine.h delete mode 100644 programs/include/engine/input.h delete mode 100644 programs/include/engine/sprite.h delete mode 100644 programs/include/engine/tilemap.h delete mode 100644 programs/include/engine/ui.h delete mode 100644 programs/src/rpgdemo/Makefile delete mode 100644 programs/src/rpgdemo/main.cpp delete mode 100644 programs/src/rpgdemo/manifest.toml delete mode 100644 programs/src/rpgdemo/stb_impl.cpp diff --git a/programs/GNUmakefile b/programs/GNUmakefile index 856c839..33c68d2 100644 --- a/programs/GNUmakefile +++ b/programs/GNUmakefile @@ -49,7 +49,7 @@ BINDIR := bin PROGRAMS := $(notdir $(wildcard src/*)) # Programs with custom Makefiles (built separately). -CUSTOM_BUILDS := 2048 doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display terminal klog procmgr powermgr calculator charmap desktop login shell rpgdemo paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs libloader crashpad +CUSTOM_BUILDS := 2048 doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display terminal klog procmgr powermgr calculator charmap desktop login shell paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs libloader crashpad SYSTEM_PROGRAMS := $(filter-out $(CUSTOM_BUILDS),$(PROGRAMS)) # Build targets: system programs go to bin/os/, apps go to bin/apps//. @@ -89,9 +89,9 @@ WPDIR := data/wallpapers WPSRC := $(wildcard $(WPDIR)/*.jpg) WPDST := $(patsubst $(WPDIR)/%,$(BINDIR)/os/wallpapers/%,$(WPSRC)) -.PHONY: all clean 2048 doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display terminal klog procmgr powermgr calculator charmap login desktop shell rpgdemo paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs icons fonts configs bearssl libc tls libjpeg libjpegwrite install-apps libloader crashpad check-syscalls gen-syscalls +.PHONY: all clean 2048 doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display terminal klog procmgr powermgr calculator charmap login desktop shell paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs icons fonts configs bearssl libc tls libjpeg libjpegwrite install-apps libloader crashpad check-syscalls gen-syscalls -all: bearssl libc libjpeg libjpegwrite tls libloader devkit $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display terminal klog procmgr powermgr calculator charmap 2048 doom rpgdemo paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs login desktop shell icons fonts install-apps crashpad $(MANDST) $(WWWDST) $(CA_CERTS) $(CONFIGDST) $(FWDST) $(LICDST) $(WPDST) +all: bearssl libc libjpeg libjpegwrite tls libloader devkit $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display terminal klog procmgr powermgr calculator charmap 2048 doom paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs login desktop shell icons fonts install-apps crashpad $(MANDST) $(WWWDST) $(CA_CERTS) $(CONFIGDST) $(FWDST) $(LICDST) $(WPDST) # Build BearSSL static library (cross-compiled for freestanding x86_64). BEARSSL_INCLUDES := -isystem $(shell cd .. && pwd)/kernel/freestnd-c-hdrs/x86_64/include -isystem $(abspath include/libc) @@ -284,9 +284,6 @@ mandelbrot: libc $(MAKE) -C src/2048 # Build RPG demo game via its own Makefile (depends on libc). -rpgdemo: libc - $(MAKE) -C src/rpgdemo - # Build doom via its own Makefile (depends on libc and the shared-lib loader, # both of which it links). doom: libc libloader @@ -337,7 +334,7 @@ crashpad: libc $(MAKE) -C src/crashpad # Install app bundles (manifests, icons, data files) into bin/apps//. -install-apps: 2048 doom rpgdemo paint spreadsheet wordprocessor weather wikipedia imageviewer fontpreview pdfviewer disks devexplorer installer audio music video bluetooth network display terminal klog procmgr powermgr calculator charmap screenshot texteditor mandelbrot printers timezone crashpad +install-apps: 2048 doom paint spreadsheet wordprocessor weather wikipedia imageviewer fontpreview pdfviewer disks devexplorer installer audio music video bluetooth network display terminal klog procmgr powermgr calculator charmap screenshot texteditor mandelbrot printers timezone crashpad ../scripts/install_apps.sh # Copy man pages into bin/man/ so mkramdisk.sh picks them up. @@ -495,7 +492,6 @@ clean: $(MAKE) -C src/printers clean $(MAKE) -C src/timezone clean $(MAKE) -C src/paint clean - $(MAKE) -C src/rpgdemo clean $(MAKE) -C src/screenshot clean $(MAKE) -C src/mandelbrot clean $(MAKE) -C src/2048 clean diff --git a/programs/gameengine/Cute_Fantasy_Free/Animals/Chicken/Chicken.png b/programs/gameengine/Cute_Fantasy_Free/Animals/Chicken/Chicken.png deleted file mode 100644 index 19163df479a87f2fed57a50f2f85d58eaefe8518..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 622 zcmV-!0+IcRP)Px%C`m*?RCt{2n!irlKpe-vtxyhSI4{Xi9aKU>EM0g5CbrIfg7{H7@C;#sS3sRu zBEi4}Z-7+AREVYafO6?@49(AS{sNi!e+JSiOp7>hqN;8$8Hw@a6SHm?~ib+E<#fc@Gd}A_;2#RSH1$GH9#xlW~mlL zepkmr#GsXNSNn(VlFQAoi zPxlvSeL6%w8e;tG&U@Pbp_OrY-mGCe*Z#NK?rSk)+tw^#36e2 z;Wl^-sEW=mLm8JNR1sn|pbS8g7opkYWh|6_%m$P}REscMj3A;*v{&5#0O$eeiAeR3 zYm+0G{wo^brSJ0==mCIMrZ4}-`Jjz_&|Z3P!<2KjE{~CH@1XVb8*p=g?%r1vHcJbe zrM~(;yC>hIPCf6BqVKzXd~Fa-C%-QGgb+dqA%qY@2qBx##@gf2++h)qX^%Il@9ho7 zw#TFD$F|3#>c_UnL+NjfJ-!zDvEA7a`ra#GQHAAW1sRvF_|Cod`mx>F*!l~DSm4eE zrD^?I@6Sa-vGxLQ)%V>AmgZzWXd^j#hFIlEYFx#h4r-1THcPcKeX-_~qvxsEeDv#m zA23P2uvwaPx&kx4{BRCt{2TEA=CKp1^)3eMzYF&ON{Efh~7Q#LQ1P5y}{lef+uJ$K90_Mb4B zvv|v7GKD~!#R5Z?R8ut=b%;OZ)9LPXXPwTbxd*~`-zj?EFCCGdfPjF2fPercTFq{1 zWB;$vYIf5!O;a&gmAx(>Z0yd-39V)~J49RE{B;)Ky^j3p@ft^mJpjPd<8`(s+S>h5 z8YfYssxvD5`Mbo?VK3!#?q?NlX#yzt^>P6qA3V+5{Sg3Qyo#W!xX!l3F-SPBzofUv5NS5$2Zsj7ip$=l^#o!6;{;1Ru89#tRpnSYuF3=fH zvcFLjK+CO9z|U`a6%Z5ge0OV|1Rn)Z{v#A8 zQKS9ktJGNv{P^SyK)&_FUHSR$76339&v1XGVv|Ex0PY9(fw;wPpaOJ;lia4POaSnD z&$gP~l#>Ck!4nxz!t>oNj!(|A;OSa}@yxjTz6zjCfDSx30Dv$rtix^-VPmX#``2A%@WroHhk>FJtFpONhkf!FbOBMB6^Uf?stWBc z`K28|Z&^k0QFMYU#V#dspZrQ?NG6Gk5a0-wkp+=@$+kvFThK%qTM7>#vLFF&}7XObe*TdCJ7{yOS`YM zCD{uH6Aiv#XXCBfU*tF8R9q^2A0RV^?*jq?0s`JL{sFT-`b-!TvXcM+002ovPDHLk FV1gEO%zpp? diff --git a/programs/gameengine/Cute_Fantasy_Free/Animals/Pig/Pig.png b/programs/gameengine/Cute_Fantasy_Free/Animals/Pig/Pig.png deleted file mode 100644 index 5312368b3220ea95e6a5753ac5e73a7b0f3825aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 735 zcmV<50wDc~P)Px%nMp)JRCt{2n!k?XFc8MS94FDyAw{Bt9*M`e=Ll3sm68WYnJOK}i`+}Bv^{i@ zkkX|~fpW#}f)3F0OnB)`mT@XQT(zX_(;IFF5%*o;YoL9M>FDOo_(NG&FOg4}jX z>l17MfDh-wBx9Yw9`=|=F(#`eZs$v5uzJzl^{{`~NS_J#&P|q89)wBO+^9eD#VKuq zK?ez zirFeUq`=ugg;>vcR{~ry27nAv|CV&rLIl97@Yv!b0lfhLuvG`-uxdbA*0;&f7WnI&?yN4t%nu5{tM#n|Fo357;8pszd(_p4 zq0Wy*Ul0UA5ClOG1VIple~3}H$9?FJwmt4kf0XTUpZbH^<6)A$q&@Cae^7fIK&O#I z+T%X;N8KL(^6s#Y?(A3VkGehXL%;Vuz@|If#n1++5B<@$$9?HrWrr(B9C}us(IS7; z2F@nuBKU|f=e+AXfU6BI7`K2f%$*IOdCvJ~z&Wp<3E;5Rw>couh*HlzOtPc;BJ!wl zuBZvnlc67o2$PJ?2^hCv@BXAmxbGl>VLY@3Y}K`G4@xM=`2ax>1VIo4jz6+})-$GW R$szy%002ovPDHLkV1j?pQ}zG= diff --git a/programs/gameengine/Cute_Fantasy_Free/Animals/Sheep/Sheep.png b/programs/gameengine/Cute_Fantasy_Free/Animals/Sheep/Sheep.png deleted file mode 100644 index 242c1a0f6e93905685df99df8ded1fffb9633ea7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 748 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 bO5^zlDUXihtMcLC00000NkvXXu0mjfHHss` diff --git a/programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/Chest.png b/programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/Chest.png deleted file mode 100644 index a0fe2b05ca0563b775cf0be9b1972fed4ead3089..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 386 zcmV-|0e$|7P)Px$JV``BR5*>DlD|sBP!xy1luJs75-^%VQ7SGCLCm(0O=~kul$?)B4aLRIe+YJDM!`+&uz7y*iP6B>9f^+oNRt zfxW|HJh#Q;^~KEF+NTNo3^~5rj2Zl= gIVvTxU&Q3>8=P5PfHh`4(EtDd07*qoM6N<$f^{dPw*UYD diff --git a/programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/Fences.png b/programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/Fences.png deleted file mode 100644 index 72e72607d7cc0b1b3c16058afe157afb949bbf95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 585 zcmV-P0=E5$P)Px%14%?dRCt{2o4roMFcgIk6%t|xu|NkFD!~*9F=p(}GlYle6Yvo2GjwO{SRr+y zQdt;)1;Jji5S9dm#&+yDj{oi_RcczF*s^_{++!Iah^X1){gIB6yn4OZthi-;*6;Jg zlkpH&H|GF=r{xO((q2~Gh696z@Z#&iV5O#nrXGa6Pef|9Vt!$tz{Vt6ipi-fT`Fd+r&%@{psIu6s z?o`UBqh#8p9zX_Qwp-5VQ=lncUCjzZzZSwgp^*nmZ21|6) z>#oxC661bAbwq6HdBo%gFp2&t(DxdklHIXJP*-20&lzAlHD(fh2v7&uZh&o!`vI=& zqn`oB`~Y9{pi4-80CRs`7BBsP(07FZ!3^N+ z@9W~6A0P?=-TnF6{VeO5G_3(fDs_qI-vp@xOjkgDfa7o%LEU5sAV0thee@wfet<}% z>j!v$UO?9m2;#gzSA=k0z;{1D{k(wdZ*iveSvpGcVl~f-PjLFCM_X0YX8QZCCxYh} X@TLY^V#x>j00000NkvXXu0mjf_+1Y) diff --git a/programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/House_1_Wood_Base_Blue.png b/programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/House_1_Wood_Base_Blue.png deleted file mode 100644 index fa216ce7bb8d31777b3d6a3947d24fbbc05e63eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2898 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 diff --git a/programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/Outdoor_Decor_Free.png b/programs/gameengine/Cute_Fantasy_Free/Outdoor decoration/Outdoor_Decor_Free.png deleted file mode 100644 index c4a82182e0c378deba5267d23fd76e0c03792b6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7431 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 diff --git a/programs/gameengine/Cute_Fantasy_Free/Player/Player.png b/programs/gameengine/Cute_Fantasy_Free/Player/Player.png deleted file mode 100644 index 56575c844428bb1e1b9115dfa251e556a9786440..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7770 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 R0$eNx40MdOYp=P){6D%-7`*@h diff --git a/programs/gameengine/Cute_Fantasy_Free/Player/Player_Actions.png b/programs/gameengine/Cute_Fantasy_Free/Player/Player_Actions.png deleted file mode 100644 index 13c5d7114d70a4faeb1c95705a3bed67cb7de0c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7609 zcma)B2T&7Rzu(Y{h!Bc&1QZ07A|is2fb=dM5h;RHDN2(Xid>{u=@LPD5s+RIP)aB& zU3y1)2{k}~x7>T*`@Z|i%$wPnP0rb5cK823zjoefX(&=rFjD{kK&7lCrwyLX0Du5a zMgo3%RrH(}JV9P-E6M_;KUh})fbF%ioQ$q#`bLJo1Km!#w zFZKrQ`o#!K>vumUls!-}I z>_|H0RMK)aW%;h^yE{A~1`M0-IN;8EszeoDd<$Dw-mXA6pi}Cwn)n^X_leW=B?3p% zcC-wiHpmw#L&XlzWnZr7%@e*AxDK^o)Bj9q++OEpa#d2Sgn#r=x`hA)j>39Ozqy?G z!LvRK$TtWiKvU#95M11p?_#vNiQ+1LF-{rtRF&l!b<|HYXP{5TL@y5DfDG=v1Msal?vk;kWZyKNyy4Z zOs;Yr0w}y-EF(N>j}{e$05?tsc`)_RgKR{XV_m_1$Kzmx&>z zA>J{Z%J!W5S@#Ie3;gY+NDf;Y*-sypRfBbj=_o=HVZP2!j|NCP619Yig9FVMJvt5r z(2^+Av=<+?JbLuOA*=K0vq%Q?Sxp8`6MVc=@@$=Z zyGojEoEY`p9-9&EL;&bJHWJ#eCILWZI)$07=uI~Q#GG=OF+7WOM7_BpDlp8&67PUK ze`;t{-ozwuKMqxu_fY&{UK{#_3j^W_-2I*Ace7{zEAbr%nS)$}t1bOfOsxC5u#;#EHKOYeOFo`fb4H(lk*)A8xbsmcJ=k^lr_2 z;o!^QMsPr)9%gpjtTWS!AH!)KVNc`Ut8x=rp~Y(Z)!zDqx#%0|9V{h_ka z!h!hc246$+rr$t<&+c@E1-+yh%+KZODp40yn3w*x@jjs(mhl7??2jykDqb4d+aa{h;eQ}I_0_! zsFWipR(xgFq?sR^R*Gt)Hf~cHQ7hfh9`lWxpj`hZX`VStG@;Un-ZEb_a}~%WmuyaC z=iIeX8s$Vw)}K$%zqGVe_x^m1yds)fVBOW8PTD zV!gCG%+u*aOeQh}0*~|yj_6|c5v4Y4?YX6d7}8P>>+3P)jLY||2tHGUxWQq>N^KkXN$Hy1@Svcc3GE&+QLV9DsqZx%^~lnsfishrEU4vh zZwA;KYK$wp{EfroFs-3M!u+IZ#=(jHP)n}2NAJGn+itZbrspaY2eDvv4uEU{8;OA4 z8ORW$uHA!7nk0Huq8Hn*>Ei;IsTs(=yd&F0ZIt{FVWomE-jEm3$igS;$+Y3=l=pGP9q0b7(iOd5!v&IGQNj(5(VoqG<8f) zCjHyCAc(gb%pVRA!{6N;26mw6P3d?hO);5@LUK#QLx_IlZ3XpICqnB`DAMCjXzXIp ze7ijiM4C#TPH~HhRUfdICd1)8vy+Ab>}%m`kx#U*w-h3Pc|I@U_nyY~!90%r>{>l} zW(@Z`l?n)G2i!R${}{{iJQ%UJ%v8<2^<^Bh)&Arfi9AO46#fR@$&uDqc_jWCulydZQqn43 z$!HJl#&ztPGxx2gJLK) zT>yp5>9cHkC~WeZDD+STI@w3M>X?udhq~SSXePczLW|-Ix2-#mT{%mTIu?g)&7n(tWh8vU zGk20FI#n=(xInw;%zxwSe{{p&-~L*I^E>cc zv&Kr1`xO&*UKMVrPkJTI4#V2BJ-olPIZ|1;dOIv(&CEWz@T`DwQGx6Q$dddtlk{3a z@9RjHv9H*|ZZzZbX|N07AXK*TlfU>DO6F7H#0wyAixKtwF!Z`=*%Ix>H%izO&7yom z8-zUEUh6>Dv5BDZL2&FS@j6_3Tj>!LFsslsfuwkRB@q1eaar2T*q#T;L31blCy1Cb zt9UCPuQ}UC)J9EriivOe)wG3F9?eztM4EO=gp$&w_;>lf=wvS|xkoF`mZ>ABiD8kg z<_E$Kf_;WArC94xX$;FuE9md4Y}|jTmp!C`GjlEKFMo5Jc?(Ut=F!ATM*J;oM4zCy zzQk!^Z4<>s)B?_<-)Zbw`OHXLl{ z)r;r3KTO*{qb9OWUn;K36&4vWtIus37A-b{T?Oah7rEs1)@BdvEz!_axu3Y-@momi zZV~|A@w@8%mie!I`4>Nkb#J@OpB|d|9+(a?N$gW1S4}N75xFIOcQcw-i_l-uFj@%E z|NUmleLA2$S1eyLOArdz2|tck{W=f*2}#p8w-meeT2P2gQuZVZtDpHE#U?;ay>K_mP$C-9D34v>D4jole`cU!dSzy!j@ycWmD7X(I1#vJJWp9D z<@dk!+`mMm;t11G$4E!t_qx3K*DB{T%0QbUVuGTcSM7yvVv78f*d6OV;8#EQGF6Uoo>gjR;0zV^mEiOfrmja1&^GTyP{} zUW9lm)FiHfKw;1E!!r1zk|2`q1h^>b0lCPU9i9(qwSNI)Bg4$(qEr6SV(J{}WKSc? z`?;SBZht|rUWb!C?0OIcT>ZrOJ28d^O@YB`)EdsG1u+Dr-kT3yDCNBCW!!c7lgU~g zeKeFktv+hqLPAKS$X%7D^0BM1r4}0FNw;7CiIte&iwj@uIi&oP*NT-M#UBvD$J4bb z^Y}I3=XC2gNwyy^W?Y&zEjK zjk$gWg>hw~sdAI;l9dDm6SuR%4k4p$uFZwU`a0Q!N8f+qTg`p?7!Pmx?Wk+z?(&J$ z{W8dXJ(lVP?89wDRZd+>T^74dYDG%YdPnC}@Cko>ROoASCHUAvNZg+rxX5!2luo6# zTk@bH$>pJ>V#f#yWjHTNFz8YDGVf!bX8=3Tki9bjjs6|AjcV;QxBWhHb&ob(!lu3F zeV6G9O#p=%I)xvmuCE(A7!rWDKb+4SBYIFml2XXg+oq%T)xhCRNb=#KRPl0EkK=Uk z%+W4kA^Arh_q*ij0HyYlVA7t9&RkbcsNHXYX(UCw`T0zDtDB=}5EN&!xtAIaP&R9wBi(PI zS|m+0&5?&oL;*Fn?ej>xY=C({flw zgEprgftl)6IkZr4+r(USYN#uR){i{S?3?mPLC)9d7O8Y7P61HW_S08+X&D!9el{NU4&5jK^QEk#43|Oq5V6X6C|{K}zatWHo@cUgkiSoe`TQLqyf-ZwJR5~qC3NG#5 zEICaxq|xi5#~R_tHgbMiVu)U|VsdZoF0hLu!u_VKSXsnUO#3J%NX~`@?yO3V(Binv zgN^(+FNY z)iZ$u1$%#iB0|QvjtE`zVGq{MsYC2vmhM4*Bf#`@# zD!`Z?xS+%^zlfx|fHtw$|3;pLfF;-K+a-GShNSS9o~!I-#aKvA9FWg_$%Atm7aMW| zXtvBuB{K5(>POdGu@xo#|MQ|mRuDZ`@8ekPmjIB_uB-;MVDTRdQ9DJ%V88nKAo6Kj z@U631yO!-m1YDh;Mu_$uMgd^twDolCVL9z<#@s#zmN>6nC`AapZ)`Gjrd=XNti5Gf zKj-=G6Cd6@ccVJ&W%ZMt&H}{V*BeMr+6hqbKaNvu|4DNEvtYP5k)_B$@o;84o#8yS z%?Pjq5e#&YnxOY>>)MHv@Hb-dq8vf%ZmAH6R5ipFI6;7?G*HQaUYo(lXzmXFvtAor z$+E8!;2o$PUjOzudPZJPe5#Glq|UUMB@XYH~&5i0_@ z%opkp`oP5B@7uGI)=Q8NXCo}**8gI^5`$xc(Xam3!io+X#tIE=da<|mK#k`q3UwZtHnct;P67hEK^e=~96*$i}R%iHk5 z)yXbNb5bQNYx($vhOdo7fDeYr<%*%-fiRygmD+G~+mCruDaZKwBy+^@Aa$!KAtVif z#RWL3w!3o>WNs6ql(87{JYAx!!-1oK!60S|YVNL})v?(njTCtDN2!fTfVYghL5xwm zx!*>}i@Z6a3j>CYzz(98JN_NkD3BV479y0^PC{vF*j z|5qjTO^m6j6B4yFFe_@IF@;fCP+MDU{$@e^q zOpfQhG& zapXp`*uT9>cTH!Xa8aGF=-1l-qm!TEH9>jSU$;!3HjktA4B)x#9@=n|K8XjuGD9;& zaWwtxF?H|nq=stmS~fd646ecdvV4IFqp5sz)nkmcdJlc>(Y-N^f$!;`Mw?l>Lo!S> zV|~Ty3IRlpkxDVLc*yDc<`>yazA!hJHpa@o*)tVreg=VXO2xV^+AU9(4-=U7Mn*f; zV;?VEq+PMJ#Bx+8fw%r5PCle{bW=#`!4@HMl&D-VpDbt2|H8^jTI{gLtUL@;)7W}t z_2hmw16cryQs+6ZUl+~(=20MWcO$__gG6*R;fIqYJ*?`-O!Wcr$_U}YbJDJMO?Ugn zmm8G*v&Q&@js*>U+1z$UU2pvV%60!W81XZPI(hfWp{)AQsvSahUg`IfvF#_nWyTON ztoIxxEhe1^J;%%T$@=ot!$x%a<#x@Bd@e)9g}KuN#6@PYl)X9 zecnI=8@)*LE`w2S0+`h#XWEGL#1BCW^FZ%#eh^JP=gr4Twemj zl?tF}#BKK&wuo@~&9>woJ5;c9vTF{(JZas)e#Qk_F803_e%#lU;Yq>qf$3YOBr5FQ zzN(F8`mIpYUo1*Qr94v2K3oF_iwrM6D76kPv4fmxzM}D!h>Ir0$)`=oWQ*!mP?$I3 zO#I078(~7r)`k_(?k`-wnm2tM-#Dp}Olro3LCosc03j-)ut8St-cBp<(!E z!))#+t^_l{Rs(wZeDOSKNHB@Q4PNrwna`9tuWSUpK zd8v1q4!r4VpSCrp{V>jC22_8}s}#Pls==Lr(!5z1ICmp2NKGv5(2PU$SR0fd+gClA zx0Y@w{N8;hw_!Q~_fffE7MA65){gMZ7?X@@S44#kZgW6tIbfX!>r)|@7g^l=BZo|j z)M z>{VtY2FJnX(q>2YBCk3$yN9B)A@ z$etjDIS9hUrMdM44K?t97PKI#h;%|j?O>x7KhYL8{l_hcdxnI?gQ9smmux8F`A0^z8&cig<%)5Yo5jccGfDSWm} z#IQ`}3SR_DU`<%SR2zzJv7FYZn75(0$a%}zipEi#zudo8q*Zi*?iCZVRg<+}3K(4*ka7I*cWCe=9& zuFWmSfg-jCa{~SH~^%cb!ff^zL?7qIc*F5 z6-YHZ;s;}#0x$MwS`?X6uh`o3>&p#ilp&wuccFg>!(0r^ywIC_u2K|cZ}^|@+%-Q{33U{}U(xqsrhtgix5a4{Vj(l}qusd7 zb5vuo+cnrFUuVzD0BGV{K~w>H>mANnd~u!8{<*hL{sNQaS724(({E4J!b1HQ+a=4u zJsDuTv*4?9PvmryKa3VX@(TPd6w4AI}$;JkH#S%2pDy4~gBH2t=!F1~yOMpt2ecw*+nQ)ITF^ zKc71K6yd7goMcr~bEbO+Kiwxbmk3bR+@I~&c}oog1~+(-VvW<0(OlRhlU&(+F_|Z3 z(V7oQ)ta5Dh=Cu^o2tufJm2xLoQJv?sT!-uES}HRYyY^pP$0NG6%qy66(#5AaDFx_ y?{<$Q{yo*lcn%b&k%{CGJM6z{qi=Nc=McNr$Zn!KA$M>u7EqSgkSmon3;Yk&LxF$* diff --git a/programs/gameengine/Cute_Fantasy_Free/Tiles/Beach_Tile.png b/programs/gameengine/Cute_Fantasy_Free/Tiles/Beach_Tile.png deleted file mode 100644 index 2a670529a52e49ae7ef2e9cbdda28209402784c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 648 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 diff --git a/programs/gameengine/Cute_Fantasy_Free/Tiles/Path_Tile.png b/programs/gameengine/Cute_Fantasy_Free/Tiles/Path_Tile.png deleted file mode 100644 index bc20df5a0919c4fc97bd3ec1bb7a17b187c7d6ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1129 zcmV-v1eW`WP)Px(BS}O-RCt{2TfJ@@F%14(7}>I9%FqHq#v+-5B3tJ^L$|y_-=a&$uHN!40h-B~ zjSL+;W$|VhXor9Y9!-k+xs!Z}za?koB=M6(illV2uRp*2!-VmnwE(3!5@?Mhf%S5$ zmTBeQ|8h`7V7=U8^StW`L}j7(`R`IB6QE9I=hjT{XDPf!J{2wjtpobIdEQ}hbJht) zLdh~-PXFWYStMcz%{}4ea@aiYaC*_NwzxUN-Q!F5EX#Pge3pGt+r01d>ytbJRFN8{ zQIo>T=d0UGJUy)T1iiYw1OPleth(O|pw}KfQ=cK>0bmy6O7JBhp$SExGFdLc-veF= z#Rv~LGhjgzCbrCLPm=MFq{Jyg<$|{#qr@fwzTsHQXDnz|%!0avr1c@;#~yuxRBnQ% z6YdhKEj;1s_A+YLRRZVNCpf*B+(p-KG{Yr@2W zxyhVmQR}`%a%wRJHT1#M0hzE$6{gl1n>hn54m5J$>VTKtwm|io>p+PqY-&dN72y&y z+FS>6%_!9!8_@wx%69@ak7uI@guW9<`F>yw1m{@0H3j(J3IM2fRUt@#?kfPVt~DQ7 zuAK6e1=zpMJ{DXplUM1jtM^*@L4=e*|Ip4_5)0-18c4EpA;DU?9+S@t9SO9?3A#%IcCUW&67nj> zKz?GFOEM(G-acR*O2iyicy&FYLW*m(9lep2oPk**AJdLUUR^@kbms_Ndc+j7bP0l+XkKXsH_! diff --git a/programs/gameengine/Cute_Fantasy_Free/Tiles/Water_Tile.png b/programs/gameengine/Cute_Fantasy_Free/Tiles/Water_Tile.png deleted file mode 100644 index 904eff2065f50d46f41bc3e65508ba5157389d92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1500 zcmV<21ta>2P)Px)mPtfGRCt{2TfJ@@IS~GQ3IYglx*!)-5>glef=I{yY^JAeHB z=YM#>_^oRKsn`nW8e0Jur#Duc&F=fI4w3|1oZjH7xHSlo&GkJ0oQh}x)TnG+dlUSB zN!}(t7G43i2I%iqaf^f9yOJ1@k~VIq@Az|?h!8=KeB|YDxGHY(WMmdQ*uBH7*!(YT z+&&o&fb*r=7S+w$e*XG#JpojZDyCkOWGBM`CIC(tF^y>X-THZ1AN@~ly2t|oL+JVI z#|C)-`1tA>KE8UU662qx&GtO6kA_tU`5*yWqbKJ}EQ)I^ifg0i$@XP_W|Xtpzs%2! z@-DF&oI?nxP9!1@0Q3FBd*ksD7R8xqTiXdXyDUE*^($@r-olQy8|B1l_*95DjOkj~ zc+|&i)ia!hCdB#%r1v@4y~AWUz@j)a$-jJi|M$n&sx8DW%Fp)?F+Dyi9RT-Ynh5U@ zqKR7pC&d5Po^jb$4)^*PJ4@+kuIoP1ifhM=SDIgwELx{W(-*k;f{nE|ZCR{Ss zbxx0uFdp@dO`qKGc?AIXW1q(0Y}Ko^O4h|>I4Hdj=V61>3tgPvl>4AA(C8%Y3dy@s zLfdXM6ixwr;&kOkecn(NAj8JCA;VG)UN=e`xwbJG4h&bSiBSDh=|T%&l7*rla!YN4 z8V>-QH?eoQ$~*o!*n;-Y(_L?9>6`d+FJ>#fN*lYY+i&Q&sX7)t&BG&jv)acEU0e~ zPB#jeXO`vB;(Br|-@LaMQi62rDF%SSx6c4JK|Hk;ayl2Z4)DpuKVKEMSiX5*5|E-a zyCl!+BhtL>|dlegR7GA@}zcdrLyxZj_NHf-;z) z@3BX7In(YDdtPUXrD$TY#L0@yJJ zCua*jh@>lUG3v@7!W1CRCOJZSU9;yrTUFNqx)bmnu4>>haL)S$)s24m{xj&7Py;XX z;rmbQ)gTvwsH4SLv~kP15#TtRuRDa=xMTP=H*<8=PcE|V93YpPGgTofb2k=kWW1vsY% zzaPi}XFwz80U@N<+Zg|VM*z=2pRIaE&+;UYS%FGG!!z4+rs{Zy5c%)D%T?va3j}H3 zyIdJ%bHWrLCbG;xC$chwg)&QQ!-X=`bLCo8htT?lk!O~3XuZnQ@&QV>S8}ZzgnbUM zYf_muKN+GVy2-3smI934mUU);|8Q6A9H*Aw1lVjPe8jVzO4ty(4UXyUR!^sGY4bK) zi|GD-AQ8W2K=Y80<({|^NQa@!E&UCoocHG_tJG&dTI3JM5J@Rp=Xoeci?xt?RN^Zi zJ%l_3gCNt->WXx5sICLr%}U6Pi?6JYlxyNDb%!rxDG7X9&xh3G5wBlx1iCS2!>RXV z0Yffs9S9{7lCfA -#include - -namespace engine { - -static constexpr int AUDIO_SAMPLE_RATE = 44100; -static constexpr int AUDIO_CHANNELS = 2; -static constexpr int AUDIO_BITS = 16; - -struct AudioEngine { - int handle = -1; - int volume = 80; - - bool init() { - handle = montauk::audio_open(AUDIO_SAMPLE_RATE, AUDIO_CHANNELS, AUDIO_BITS); - if (handle < 0) return false; - montauk::audio_set_volume(handle, volume); - return true; - } - - void shutdown() { - if (handle >= 0) { - montauk::audio_close(handle); - handle = -1; - } - } - - void set_volume(int percent) { - volume = percent; - if (handle >= 0) - montauk::audio_set_volume(handle, volume); - } - - // Write raw PCM samples to the audio device. - // data: signed 16-bit stereo PCM samples - // size: number of bytes - bool write_pcm(const void* data, uint32_t size) { - if (handle < 0) return false; - return montauk::audio_write(handle, data, size) >= 0; - } - - // Generate and play a simple tone (square wave) for duration_ms. - // Useful for basic sound effects. Non-blocking (writes samples to buffer). - void play_tone(int freq_hz, int duration_ms, int tone_volume = 50) { - if (handle < 0 || freq_hz <= 0) return; - - int total_samples = (AUDIO_SAMPLE_RATE * duration_ms) / 1000; - int half_period = AUDIO_SAMPLE_RATE / (2 * freq_hz); - if (half_period <= 0) half_period = 1; - - int16_t amp = (int16_t)(327 * tone_volume / 100); // ~1% of max - static constexpr int CHUNK = 512; - int16_t buf[CHUNK * 2]; // stereo - - int written = 0; - while (written < total_samples) { - int n = total_samples - written; - if (n > CHUNK) n = CHUNK; - - for (int i = 0; i < n; i++) { - int sample_pos = written + i; - int16_t val = ((sample_pos / half_period) % 2 == 0) ? amp : -amp; - buf[i * 2] = val; - buf[i * 2 + 1] = val; - } - - montauk::audio_write(handle, buf, n * 4); - written += n; - } - } -}; - -} // namespace engine diff --git a/programs/include/engine/collision.h b/programs/include/engine/collision.h deleted file mode 100644 index 3ba3234..0000000 --- a/programs/include/engine/collision.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * collision.h - * MontaukOS 2D Game Engine - Collision Detection - * AABB overlap testing and tile-based collision response - * Copyright (c) 2026 Daniel Hammer - */ - -#pragma once -#include -#include "engine/tilemap.h" - -namespace engine { - -struct AABB { - float x, y, w, h; - - bool overlaps(const AABB& other) const { - return x < other.x + other.w && x + w > other.x && - y < other.y + other.h && y + h > other.y; - } - - bool contains_point(float px, float py) const { - return px >= x && px < x + w && py >= y && py < y + h; - } -}; - -// Try to move an entity by (dx, dy) on the tilemap. -// Uses separate X/Y axis resolution so the entity slides along walls. -// box: the entity's collision box in world pixel coordinates. -// Returns adjusted dx, dy after collision. -inline void resolve_tilemap_collision(const Tilemap& map, - float bx, float by, float bw, float bh, - float& dx, float& dy) { - // Try X movement - float new_x = bx + dx; - if (map.collides((int)new_x, (int)by, (int)bw, (int)bh)) { - dx = 0.0f; - new_x = bx; - } - - // Try Y movement - float new_y = by + dy; - if (map.collides((int)new_x, (int)new_y, (int)bw, (int)bh)) { - dy = 0.0f; - } -} - -} // namespace engine diff --git a/programs/include/engine/engine.h b/programs/include/engine/engine.h deleted file mode 100644 index f35c6ff..0000000 --- a/programs/include/engine/engine.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * engine.h - * MontaukOS 2D Game Engine - Core - * Window management, timing, pixel buffer helpers - * Copyright (c) 2026 Daniel Hammer - */ - -#pragma once -#include -#include -#include -#include -#include -#include - -extern "C" { -#include -} - -namespace engine { - -// ============================================================================ -// Core engine -// ============================================================================ - -struct Engine { - int win_id = -1; - uint32_t* pixels = nullptr; - int screen_w = 0; - int screen_h = 0; - - // Timing - uint64_t last_time_ms = 0; - float dt = 0.016f; // delta time in seconds - uint64_t frame_count = 0; - - // Font - gui::TrueTypeFont* font = nullptr; - - bool running = true; - - // ---- Lifecycle ---- - - bool init(const char* title, int w, int h) { - screen_w = w; - screen_h = h; - - // Load font - font = (gui::TrueTypeFont*)montauk::malloc(sizeof(gui::TrueTypeFont)); - if (font) { - montauk::memset(font, 0, sizeof(gui::TrueTypeFont)); - if (!font->init("0:/fonts/Roboto-Medium.ttf")) { - montauk::mfree(font); - font = nullptr; - } - } - - // Create window - montauk::abi::WinCreateResult wres; - if (montauk::win_create(title, w, h, &wres) < 0 || wres.id < 0) - return false; - - win_id = wres.id; - pixels = (uint32_t*)(uintptr_t)wres.pixelVa; - last_time_ms = montauk::get_milliseconds(); - return true; - } - - void update_timing() { - uint64_t now = montauk::get_milliseconds(); - uint64_t elapsed = now - last_time_ms; - if (elapsed == 0) elapsed = 1; - if (elapsed > 100) elapsed = 100; // cap to avoid spiral - dt = (float)elapsed / 1000.0f; - last_time_ms = now; - frame_count++; - } - - // Poll one window event. Returns true if an event was received. - bool poll(montauk::abi::WinEvent* ev) { - int r = montauk::win_poll(win_id, ev); - if (r < 0) { running = false; return false; } - if (r == 0) return false; - if (ev->type == 3) { running = false; return false; } // close - if (ev->type == 2) { // resize - screen_w = ev->resize.w; - screen_h = ev->resize.h; - pixels = (uint32_t*)(uintptr_t)montauk::win_resize( - win_id, screen_w, screen_h); - } - return true; - } - - void present() { - montauk::win_present(win_id); - } - - void shutdown() { - if (win_id >= 0) montauk::win_destroy(win_id); - win_id = -1; - } - - // ---- Drawing helpers ---- - - void clear(uint32_t color) { - int count = screen_w * screen_h; - for (int i = 0; i < count; i++) - pixels[i] = color; - } - - void fill_rect(int x, int y, int w, int h, uint32_t color) { - int x0 = x < 0 ? 0 : x; - int y0 = y < 0 ? 0 : y; - int x1 = x + w > screen_w ? screen_w : x + w; - int y1 = y + h > screen_h ? screen_h : y + h; - for (int row = y0; row < y1; row++) - for (int col = x0; col < x1; col++) - pixels[row * screen_w + col] = color; - } - - void fill_rect_alpha(int x, int y, int w, int h, uint32_t color) { - uint8_t sa = (color >> 24) & 0xFF; - uint8_t sr = (color >> 16) & 0xFF; - uint8_t sg = (color >> 8) & 0xFF; - uint8_t sb = color & 0xFF; - if (sa == 0) return; - int x0 = x < 0 ? 0 : x; - int y0 = y < 0 ? 0 : y; - int x1 = x + w > screen_w ? screen_w : x + w; - int y1 = y + h > screen_h ? screen_h : y + h; - for (int row = y0; row < y1; row++) { - for (int col = x0; col < x1; col++) { - uint32_t dst = pixels[row * screen_w + col]; - uint8_t dr = (dst >> 16) & 0xFF; - uint8_t dg = (dst >> 8) & 0xFF; - uint8_t db = dst & 0xFF; - uint32_t inv = 255 - sa; - uint32_t rr = (sa * sr + inv * dr + 128) / 255; - uint32_t gg = (sa * sg + inv * dg + 128) / 255; - uint32_t bb = (sa * sb + inv * db + 128) / 255; - pixels[row * screen_w + col] = - 0xFF000000 | (rr << 16) | (gg << 8) | bb; - } - } - } - - void draw_rect_outline(int x, int y, int w, int h, uint32_t color) { - fill_rect(x, y, w, 1, color); - fill_rect(x, y + h - 1, w, 1, color); - fill_rect(x, y, 1, h, color); - fill_rect(x + w - 1, y, 1, h, color); - } - - void draw_text(int x, int y, const char* text, gui::Color c, int size = 16) { - if (font) - font->draw_to_buffer(pixels, screen_w, screen_h, x, y, text, c, size); - } - - int text_width(const char* text, int size = 16) { - return font ? font->measure_text(text, size) : 0; - } - - int text_height(int size = 16) { - if (!font) return size; - auto* gc = font->get_cache(size); - if (!gc) return size; - return gc->ascent - gc->descent; - } -}; - -// ============================================================================ -// File loading helper -// ============================================================================ - -struct FileData { - uint8_t* data = nullptr; - uint64_t size = 0; - - bool load(const char* vfs_path) { - int fd = montauk::open(vfs_path); - if (fd < 0) return false; - size = montauk::getsize(fd); - if (size == 0 || size > 16 * 1024 * 1024) { - montauk::close(fd); - return false; - } - data = (uint8_t*)montauk::malloc(size); - if (!data) { montauk::close(fd); return false; } - montauk::read(fd, data, 0, size); - montauk::close(fd); - return true; - } - - void free() { - if (data) { montauk::mfree(data); data = nullptr; } - size = 0; - } -}; - -} // namespace engine diff --git a/programs/include/engine/input.h b/programs/include/engine/input.h deleted file mode 100644 index 3058172..0000000 --- a/programs/include/engine/input.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * input.h - * MontaukOS 2D Game Engine - Input State - * Keyboard and mouse state tracking across frames - * Copyright (c) 2026 Daniel Hammer - */ - -#pragma once -#include -#include -#include - -namespace engine { - -// Scancode constants for common keys -namespace key { - static constexpr uint8_t ESC = 0x01; - static constexpr uint8_t W = 0x11; - static constexpr uint8_t A = 0x1E; - static constexpr uint8_t S = 0x1F; - static constexpr uint8_t D = 0x20; - static constexpr uint8_t E = 0x12; - static constexpr uint8_t SPACE = 0x39; - static constexpr uint8_t UP = 0x48; - static constexpr uint8_t DOWN = 0x50; - static constexpr uint8_t LEFT = 0x4B; - static constexpr uint8_t RIGHT = 0x4D; - static constexpr uint8_t ENTER = 0x1C; - static constexpr uint8_t TAB = 0x0F; -} - -struct InputState { - // Key states: true = currently held - bool keys[256]; - // Keys pressed this frame (edge-triggered) - bool keys_pressed[256]; - - // Mouse - int mouse_x = 0; - int mouse_y = 0; - int mouse_scroll = 0; - uint8_t mouse_buttons = 0; - uint8_t prev_mouse_buttons = 0; - - void init() { - montauk::memset(keys, 0, sizeof(keys)); - montauk::memset(keys_pressed, 0, sizeof(keys_pressed)); - } - - // Call at the start of each frame to clear per-frame state - void begin_frame() { - montauk::memset(keys_pressed, 0, sizeof(keys_pressed)); - mouse_scroll = 0; - prev_mouse_buttons = mouse_buttons; - } - - // Process a window event - void handle_event(const montauk::abi::WinEvent& ev) { - if (ev.type == 0) { // keyboard - // PS/2 scan code set 1: release codes have bit 7 set. - // Mask to base scancode so press and release map to the same index. - uint8_t sc = ev.key.scancode & 0x7F; - if (ev.key.pressed) { - if (!keys[sc]) - keys_pressed[sc] = true; - keys[sc] = true; - } else { - keys[sc] = false; - } - } else if (ev.type == 1) { // mouse - mouse_x = ev.mouse.x; - mouse_y = ev.mouse.y; - mouse_scroll = ev.mouse.scroll; - mouse_buttons = ev.mouse.buttons; - } - } - - bool key_held(uint8_t scancode) const { return keys[scancode]; } - bool key_just_pressed(uint8_t scancode) const { return keys_pressed[scancode]; } - - bool mouse_clicked() const { - return (mouse_buttons & 1) && !(prev_mouse_buttons & 1); - } - bool mouse_held() const { return mouse_buttons & 1; } -}; - -} // namespace engine diff --git a/programs/include/engine/sprite.h b/programs/include/engine/sprite.h deleted file mode 100644 index 3f38a5f..0000000 --- a/programs/include/engine/sprite.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - * sprite.h - * MontaukOS 2D Game Engine - Sprite and Animation System - * PNG spritesheet loading, frame extraction, alpha-blended rendering - * Copyright (c) 2026 Daniel Hammer - */ - -#pragma once -#include -#include -#include -#include "engine/engine.h" - -extern "C" { -#include -} - -namespace engine { - -// ============================================================================ -// Convert stb_image RGBA output to MontaukOS ARGB pixel format -// stb on little-endian x86: pixel bytes in memory are R,G,B,A -// When read as uint32_t: 0xAABBGGRR -// MontaukOS format: 0xAARRGGBB -// ============================================================================ - -inline void rgba_to_argb(uint32_t* data, int count) { - for (int i = 0; i < count; i++) { - uint32_t px = data[i]; - uint8_t r = px & 0xFF; - uint8_t g = (px >> 8) & 0xFF; - uint8_t b = (px >> 16) & 0xFF; - uint8_t a = (px >> 24) & 0xFF; - data[i] = ((uint32_t)a << 24) | ((uint32_t)r << 16) | - ((uint32_t)g << 8) | b; - } -} - -// ============================================================================ -// Spritesheet -// ============================================================================ - -struct Spritesheet { - uint32_t* pixels = nullptr; - int width = 0; - int height = 0; - int frame_w = 0; - int frame_h = 0; - int cols = 0; - int rows = 0; - - // Load a PNG spritesheet from VFS and split into frames of given size. - // If frame_w/frame_h are 0, treat the entire image as a single frame. - bool load(const char* vfs_path, int fw = 0, int fh = 0) { - FileData file; - if (!file.load(vfs_path)) return false; - - int w, h, channels; - uint32_t* img = (uint32_t*)stbi_load_from_memory( - file.data, (int)file.size, &w, &h, &channels, 4); - file.free(); - - if (!img) return false; - - // Convert RGBA to ARGB - rgba_to_argb(img, w * h); - - pixels = img; - width = w; - height = h; - frame_w = fw > 0 ? fw : w; - frame_h = fh > 0 ? fh : h; - cols = w / frame_w; - rows = h / frame_h; - return true; - } - - void unload() { - if (pixels) { - stbi_image_free(pixels); - pixels = nullptr; - } - } - - // Blit a single frame to the destination buffer with scaling and alpha. - // frame_col/frame_row select which frame from the spritesheet. - // dst_x/dst_y is the screen position. scale is the integer scale factor. - // flip_h mirrors the sprite horizontally. - void draw_frame(uint32_t* dst, int dst_w, int dst_h, - int frame_col, int frame_row, - int dst_x, int dst_y, int scale = 1, - bool flip_h = false) const { - if (!pixels) return; - if (frame_col < 0 || frame_col >= cols) return; - if (frame_row < 0 || frame_row >= rows) return; - - int src_ox = frame_col * frame_w; - int src_oy = frame_row * frame_h; - int out_w = frame_w * scale; - int out_h = frame_h * scale; - - for (int py = 0; py < out_h; py++) { - int dy = dst_y + py; - if (dy < 0 || dy >= dst_h) continue; - int sy = src_oy + py / scale; - - for (int px = 0; px < out_w; px++) { - int dx = dst_x + px; - if (dx < 0 || dx >= dst_w) continue; - - int sx_local = px / scale; - if (flip_h) sx_local = frame_w - 1 - sx_local; - int sx = src_ox + sx_local; - - uint32_t src_px = pixels[sy * width + sx]; - uint8_t sa = (src_px >> 24) & 0xFF; - if (sa == 0) continue; - - if (sa == 255) { - dst[dy * dst_w + dx] = src_px; - } else { - uint32_t d = dst[dy * dst_w + dx]; - uint8_t sr = (src_px >> 16) & 0xFF; - uint8_t sg = (src_px >> 8) & 0xFF; - uint8_t sb = src_px & 0xFF; - uint8_t dr = (d >> 16) & 0xFF; - uint8_t dg = (d >> 8) & 0xFF; - uint8_t db = d & 0xFF; - uint32_t inv = 255 - sa; - uint32_t rr = (sa * sr + inv * dr + 128) / 255; - uint32_t gg = (sa * sg + inv * dg + 128) / 255; - uint32_t bb = (sa * sb + inv * db + 128) / 255; - dst[dy * dst_w + dx] = - 0xFF000000 | (rr << 16) | (gg << 8) | bb; - } - } - } - } - - // Draw an arbitrary sub-rectangle of the spritesheet (not frame-aligned) - void draw_region(uint32_t* dst, int dst_w, int dst_h, - int src_x, int src_y, int src_w, int src_h, - int dst_x, int dst_y, int scale = 1) const { - if (!pixels) return; - - int out_w = src_w * scale; - int out_h = src_h * scale; - - for (int py = 0; py < out_h; py++) { - int dy = dst_y + py; - if (dy < 0 || dy >= dst_h) continue; - int sy = src_y + py / scale; - if (sy < 0 || sy >= height) continue; - - for (int px = 0; px < out_w; px++) { - int dx = dst_x + px; - if (dx < 0 || dx >= dst_w) continue; - int sx = src_x + px / scale; - if (sx < 0 || sx >= width) continue; - - uint32_t src_px = pixels[sy * width + sx]; - uint8_t sa = (src_px >> 24) & 0xFF; - if (sa == 0) continue; - - if (sa == 255) { - dst[dy * dst_w + dx] = src_px; - } else { - uint32_t d = dst[dy * dst_w + dx]; - uint8_t sr = (src_px >> 16) & 0xFF; - uint8_t sg = (src_px >> 8) & 0xFF; - uint8_t sb = src_px & 0xFF; - uint8_t dr = (d >> 16) & 0xFF; - uint8_t dg = (d >> 8) & 0xFF; - uint8_t db = d & 0xFF; - uint32_t inv = 255 - sa; - uint32_t rr = (sa * sr + inv * dr + 128) / 255; - uint32_t gg = (sa * sg + inv * dg + 128) / 255; - uint32_t bb = (sa * sb + inv * db + 128) / 255; - dst[dy * dst_w + dx] = - 0xFF000000 | (rr << 16) | (gg << 8) | bb; - } - } - } - } -}; - -// ============================================================================ -// Animation -// ============================================================================ - -struct Animation { - int row = 0; // spritesheet row for this animation - int start_col = 0; // first frame column - int num_frames = 1; // number of frames - float speed = 8.0f; // frames per second - - float timer = 0.0f; - int current = 0; - - void update(float dt) { - timer += dt * speed; - while (timer >= 1.0f) { - timer -= 1.0f; - current++; - if (current >= num_frames) current = 0; - } - } - - void reset() { - timer = 0.0f; - current = 0; - } - - int frame_col() const { return start_col + current; } - int frame_row() const { return row; } -}; - -// ============================================================================ -// Animated Sprite - combines a spritesheet with named animations -// ============================================================================ - -static constexpr int MAX_ANIMS = 16; - -struct AnimatedSprite { - Spritesheet* sheet = nullptr; - Animation anims[MAX_ANIMS]; - int anim_count = 0; - int current_anim = 0; - bool flip_h = false; - - int add_anim(int row, int start_col, int num_frames, float speed = 8.0f) { - if (anim_count >= MAX_ANIMS) return -1; - int idx = anim_count++; - anims[idx].row = row; - anims[idx].start_col = start_col; - anims[idx].num_frames = num_frames; - anims[idx].speed = speed; - return idx; - } - - void play(int anim_idx) { - if (anim_idx < 0 || anim_idx >= anim_count) return; - if (current_anim != anim_idx) { - current_anim = anim_idx; - anims[current_anim].reset(); - } - } - - void update(float dt) { - if (current_anim >= 0 && current_anim < anim_count) - anims[current_anim].update(dt); - } - - void draw(uint32_t* dst, int dst_w, int dst_h, - int x, int y, int scale = 1) const { - if (!sheet || current_anim < 0 || current_anim >= anim_count) return; - const Animation& a = anims[current_anim]; - sheet->draw_frame(dst, dst_w, dst_h, - a.frame_col(), a.frame_row(), - x, y, scale, flip_h); - } -}; - -} // namespace engine diff --git a/programs/include/engine/tilemap.h b/programs/include/engine/tilemap.h deleted file mode 100644 index 3df9a9f..0000000 --- a/programs/include/engine/tilemap.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * tilemap.h - * MontaukOS 2D Game Engine - Tile Map - * Grid-based terrain with per-tile rendering and collision - * Copyright (c) 2026 Daniel Hammer - */ - -#pragma once -#include -#include -#include -#include "engine/sprite.h" - -namespace engine { - -static constexpr int MAX_TILE_TYPES = 16; - -struct TileType { - Spritesheet* sheet; // tile image (may be a single-tile spritesheet) - int src_x, src_y; // source position within the sheet - int src_w, src_h; // source size (typically tile_size x tile_size) - bool solid; // blocks movement -}; - -struct Tilemap { - int* data = nullptr; - int map_w = 0; - int map_h = 0; - int tile_size = 16; // native tile size in pixels - - TileType types[MAX_TILE_TYPES]; - int type_count = 0; - - bool alloc(int w, int h, int ts = 16) { - map_w = w; - map_h = h; - tile_size = ts; - data = (int*)montauk::malloc(w * h * sizeof(int)); - if (!data) return false; - montauk::memset(data, 0, w * h * sizeof(int)); - return true; - } - - void free_map() { - if (data) { montauk::mfree(data); data = nullptr; } - } - - // Register a tile type. Returns the tile ID. - int add_type(Spritesheet* sheet, int sx, int sy, int sw, int sh, bool solid) { - if (type_count >= MAX_TILE_TYPES) return -1; - int id = type_count++; - types[id].sheet = sheet; - types[id].src_x = sx; - types[id].src_y = sy; - types[id].src_w = sw; - types[id].src_h = sh; - types[id].solid = solid; - return id; - } - - void set(int x, int y, int tile_id) { - if (x >= 0 && x < map_w && y >= 0 && y < map_h) - data[y * map_w + x] = tile_id; - } - - int get(int x, int y) const { - if (x < 0 || x >= map_w || y < 0 || y >= map_h) return -1; - return data[y * map_w + x]; - } - - bool is_solid(int x, int y) const { - int id = get(x, y); - if (id < 0 || id >= type_count) return true; // out of bounds = solid - return types[id].solid; - } - - // Check if a world-pixel rectangle collides with any solid tile. - // World coordinates are in native (unscaled) pixels. - bool collides(int wx, int wy, int ww, int wh) const { - // Negative coordinates are always solid (out of bounds) - if (wx < 0 || wy < 0) return true; - int tx0 = wx / tile_size; - int ty0 = wy / tile_size; - int tx1 = (wx + ww - 1) / tile_size; - int ty1 = (wy + wh - 1) / tile_size; - - for (int ty = ty0; ty <= ty1; ty++) - for (int tx = tx0; tx <= tx1; tx++) - if (is_solid(tx, ty)) - return true; - return false; - } - - // Draw visible tiles to the pixel buffer. - // cam_x/cam_y: camera position in world pixels (native scale). - // scale: rendering scale factor. - void draw(uint32_t* dst, int dst_w, int dst_h, - int cam_x, int cam_y, int scale) const { - if (!data) return; - - int ts = tile_size * scale; - - // Determine visible tile range - int tx0 = cam_x / tile_size; - int ty0 = cam_y / tile_size; - int tx1 = tx0 + dst_w / ts + 2; - int ty1 = ty0 + dst_h / ts + 2; - - if (tx0 < 0) tx0 = 0; - if (ty0 < 0) ty0 = 0; - if (tx1 > map_w) tx1 = map_w; - if (ty1 > map_h) ty1 = map_h; - - for (int ty = ty0; ty < ty1; ty++) { - for (int tx = tx0; tx < tx1; tx++) { - int id = data[ty * map_w + tx]; - if (id < 0 || id >= type_count) continue; - - const TileType& tt = types[id]; - if (!tt.sheet) continue; - - int sx = tx * ts - cam_x * scale; - int sy = ty * ts - cam_y * scale; - - tt.sheet->draw_region(dst, dst_w, dst_h, - tt.src_x, tt.src_y, - tt.src_w, tt.src_h, - sx, sy, scale); - } - } - } -}; - -} // namespace engine diff --git a/programs/include/engine/ui.h b/programs/include/engine/ui.h deleted file mode 100644 index 98028f2..0000000 --- a/programs/include/engine/ui.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * ui.h - * MontaukOS 2D Game Engine - UI Rendering - * Health bars, text overlays, dialog boxes, menus - * Copyright (c) 2026 Daniel Hammer - */ - -#pragma once -#include -#include "engine/engine.h" - -extern "C" { -#include -} - -namespace engine { - -// ============================================================================ -// Health / stat bar -// ============================================================================ - -inline void draw_bar(Engine& eng, int x, int y, int w, int h, - int value, int max_value, - uint32_t fill_color, uint32_t bg_color, - uint32_t border_color) { - eng.fill_rect(x, y, w, h, bg_color); - if (max_value > 0 && value > 0) { - int fw = (value * (w - 2)) / max_value; - if (fw < 1) fw = 1; - eng.fill_rect(x + 1, y + 1, fw, h - 2, fill_color); - } - eng.draw_rect_outline(x, y, w, h, border_color); -} - -// ============================================================================ -// Text box / dialog -// ============================================================================ - -inline void draw_dialog(Engine& eng, int x, int y, int w, int h, - const char* text, gui::Color text_color, - int font_size = 16) { - // Background with border - eng.fill_rect(x, y, w, h, 0xF0FFFFFF); - eng.draw_rect_outline(x, y, w, h, 0xFF333333); - eng.draw_rect_outline(x + 1, y + 1, w - 2, h - 2, 0xFFCCCCCC); - - // Text (with word wrapping) - int tx = x + 8; - int ty = y + 6; - int max_w = w - 16; - int line_h = eng.text_height(font_size) + 2; - - // Simple word wrap - char line_buf[128]; - int li = 0; - const char* p = text; - while (*p) { - li = 0; - while (*p && *p != '\n') { - // Save state before adding next word - int word_start = li; - const char* word_p = p; - - while (*p && *p != ' ' && *p != '\n' && li < 126) { - line_buf[li++] = *p++; - } - line_buf[li] = '\0'; - - // Check width - if (eng.text_width(line_buf, font_size) > max_w && word_start > 0) { - // Line too long - rewind to before this word - li = word_start; - if (li > 0 && line_buf[li - 1] == ' ') li--; - line_buf[li] = '\0'; - p = word_p; // rewind pointer to retry this word on next line - break; - } - - if (*p == ' ') { line_buf[li++] = ' '; p++; } - } - line_buf[li] = '\0'; - if (*p == '\n') p++; - - if (ty + line_h > y + h - 4) break; - eng.draw_text(tx, ty, line_buf, text_color, font_size); - ty += line_h; - } -} - -// ============================================================================ -// Prompt bar (bottom of screen) -// ============================================================================ - -inline void draw_prompt(Engine& eng, const char* text, int font_size = 14) { - int bar_h = eng.text_height(font_size) + 8; - int y = eng.screen_h - bar_h; - eng.fill_rect_alpha(0, y, eng.screen_w, bar_h, 0xCC000000); - int tw = eng.text_width(text, font_size); - eng.draw_text((eng.screen_w - tw) / 2, y + 4, text, - gui::Color::from_rgb(0xFF, 0xFF, 0xFF), font_size); -} - -// ============================================================================ -// Simple HUD text -// ============================================================================ - -inline void draw_hud_text(Engine& eng, int x, int y, - const char* text, gui::Color c, int size = 14) { - // Draw shadow first for readability - eng.draw_text(x + 1, y + 1, text, gui::Color::from_rgba(0, 0, 0, 180), size); - eng.draw_text(x, y, text, c, size); -} - -} // namespace engine diff --git a/programs/src/installer/components.cpp b/programs/src/installer/components.cpp index 8fc9651..33ab776 100644 --- a/programs/src/installer/components.cpp +++ b/programs/src/installer/components.cpp @@ -19,7 +19,6 @@ enum ComponentIndex { CI_GAMES, CI_DOOM, CI_2048, - CI_RPGDEMO, CI_MANDELBROT, CI_OFFICE, CI_WORDPROCESSOR, @@ -85,11 +84,6 @@ Component g_components[] = { CI_GAMES, "apps/2048", {"apps/2048", nullptr}, false, -1, false, false, false, false, 0, 0 }, - { "rpgdemo", "RPG demo", - "Top-down RPG game engine demo", - CI_GAMES, "apps/rpgdemo", {"apps/rpgdemo", nullptr}, false, -1, - false, false, false, false, 0, 0 }, - { "mandelbrot", "Mandelbrot", "Fractal explorer", CI_GAMES, "apps/mandelbrot", {"apps/mandelbrot", nullptr}, false, -1, diff --git a/programs/src/rpgdemo/Makefile b/programs/src/rpgdemo/Makefile deleted file mode 100644 index e89f551..0000000 --- a/programs/src/rpgdemo/Makefile +++ /dev/null @@ -1,107 +0,0 @@ -# Makefile for rpgdemo (Montauk Quest - 2D RPG demo) on MontaukOS -# Copyright (c) 2026 Daniel Hammer - -MAKEFLAGS += -rR -.SUFFIXES: - -# ---- Toolchain ---- - -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- -ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) -else - CXX := $(TOOLCHAIN_PREFIX)g++ -endif - -# ---- Paths ---- - -PROG_INC := ../../include -LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj -LIBDIR := ../../lib - -# Game asset source directory -ASSET_SRC := ../../gameengine/Cute_Fantasy_Free - -# ---- Compiler flags ---- - -CXXFLAGS := \ - -std=gnu++20 \ - -g -O2 -pipe \ - -Wall \ - -Wextra \ - -Wno-unused-parameter \ - -Wno-unused-function \ - -Wno-missing-field-initializers \ - -ffreestanding \ - -fno-stack-protector \ - -fno-stack-check \ - -fno-rtti \ - -fno-exceptions \ - -ffunction-sections \ - -fdata-sections \ - -fno-tree-loop-distribute-patterns \ - -msse \ - -msse2 \ - -I $(PROG_INC) \ - -I . \ - -isystem $(PROG_INC)/libc - -# ---- Linker flags ---- - -LDFLAGS := \ - -nostdlib \ - -Wl,--gc-sections \ - -T $(LINK_LD) - -# ---- Source files ---- - -SRCS := main.cpp stb_impl.cpp -OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) - -# ---- Target ---- - -TARGET := $(BINDIR)/apps/rpgdemo/rpgdemo.elf -APP_DIR := $(BINDIR)/apps/rpgdemo - -.PHONY: all clean assets - -all: $(TARGET) assets - -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a - mkdir -p $(APP_DIR) - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ - -$(OBJDIR)/%.o: %.cpp Makefile - mkdir -p $(OBJDIR) - $(CXX) $(CXXFLAGS) -MMD -MP -c $< -o $@ - -# Copy game assets into the app bundle -assets: - mkdir -p $(APP_DIR) - cp $(ASSET_SRC)/Player/Player.png $(APP_DIR)/Player.png - cp $(ASSET_SRC)/Player/Player_Actions.png $(APP_DIR)/Player_Actions.png - cp $(ASSET_SRC)/Enemies/Skeleton.png $(APP_DIR)/Skeleton.png - cp $(ASSET_SRC)/Enemies/Slime_Green.png $(APP_DIR)/Slime_Green.png - cp $(ASSET_SRC)/Tiles/Grass_Middle.png $(APP_DIR)/Grass_Middle.png - cp $(ASSET_SRC)/Tiles/Path_Middle.png $(APP_DIR)/Path_Middle.png - cp $(ASSET_SRC)/Tiles/Water_Middle.png $(APP_DIR)/Water_Middle.png - cp $(ASSET_SRC)/Tiles/Cliff_Tile.png $(APP_DIR)/Cliff_Tile.png - cp "$(ASSET_SRC)/Outdoor decoration/Oak_Tree.png" $(APP_DIR)/Oak_Tree.png - cp "$(ASSET_SRC)/Outdoor decoration/Oak_Tree_Small.png" $(APP_DIR)/Oak_Tree_Small.png - cp "$(ASSET_SRC)/Outdoor decoration/House_1_Wood_Base_Blue.png" $(APP_DIR)/House.png - cp "$(ASSET_SRC)/Outdoor decoration/Chest.png" $(APP_DIR)/Chest.png - cp "$(ASSET_SRC)/Outdoor decoration/Fences.png" $(APP_DIR)/Fences.png - cp "$(ASSET_SRC)/Outdoor decoration/Bridge_Wood.png" $(APP_DIR)/Bridge_Wood.png - cp "$(ASSET_SRC)/Outdoor decoration/Outdoor_Decor_Free.png" $(APP_DIR)/Outdoor_Decor.png - cp $(ASSET_SRC)/Animals/Chicken/Chicken.png $(APP_DIR)/Chicken.png - cp $(ASSET_SRC)/Animals/Cow/Cow.png $(APP_DIR)/Cow.png - cp $(ASSET_SRC)/Animals/Pig/Pig.png $(APP_DIR)/Pig.png - cp $(ASSET_SRC)/Animals/Sheep/Sheep.png $(APP_DIR)/Sheep.png - -clean: - rm -rf $(OBJDIR) $(TARGET) - -# Auto-generated header dependency tracking (-MMD -MP). --include $(OBJS:.o=.d) diff --git a/programs/src/rpgdemo/main.cpp b/programs/src/rpgdemo/main.cpp deleted file mode 100644 index 86765a6..0000000 --- a/programs/src/rpgdemo/main.cpp +++ /dev/null @@ -1,1079 +0,0 @@ -/* - * main.cpp - * MontaukOS RPG Demo - "Montauk Quest" - * A 2D fantasy RPG demonstrating the MontaukOS game engine - * Copyright (c) 2026 Daniel Hammer - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -extern "C" { -#include -#include -} - -using namespace engine; -using namespace gui; - -// ============================================================================ -// Constants -// ============================================================================ - -static constexpr int WIN_W = 800; -static constexpr int WIN_H = 600; -static constexpr int SCALE = 2; // pixel art scale -static constexpr int TILE_SIZE = 16; // native tile size -static constexpr int MAP_W = 50; // map width in tiles -static constexpr int MAP_H = 40; // map height in tiles -static constexpr float PLAYER_SPEED = 80.0f; // pixels/sec (native scale) -static constexpr float ENEMY_SPEED = 30.0f; -static constexpr int PLAYER_HP = 100; -static constexpr int MAX_ENEMIES = 8; -static constexpr int MAX_DECORATIONS = 96; -static constexpr int MAX_CHESTS = 6; - -// Player sprite layout (32x32 frames, 6 cols x 10 rows) -static constexpr int SPR_W = 32; -static constexpr int SPR_H = 32; - -// Directions -enum Dir { DIR_DOWN = 0, DIR_RIGHT = 1, DIR_UP = 2, DIR_LEFT = 3 }; - -// ============================================================================ -// Entity types -// ============================================================================ - -struct Player { - float x, y; // world position (native pixels) - int health; - int max_health; - int direction; - bool moving; - int score; - float hit_timer; // invincibility after taking damage - AnimatedSprite sprite; - int anim_walk[4]; // walk anim indices per direction - int anim_idle[4]; // idle anim indices per direction -}; - -struct Enemy { - float x, y; - int health; - int max_health; - int direction; - bool active; - float patrol_timer; - float patrol_duration; - AnimatedSprite sprite; - int anim_walk[4]; - int type; // 0 = skeleton, 1 = slime -}; - -struct Decoration { - float x, y; - Spritesheet* sheet; - bool solid; - float col_x, col_y, col_w, col_h; // collision box offset - int frame_col, frame_row; // -1 = draw full sheet -}; - -struct Chest { - float x, y; - bool opened; - bool collected; -}; - -// ============================================================================ -// Game state -// ============================================================================ - -static Engine g_engine; -static InputState g_input; -static AudioEngine g_audio; -static Tilemap g_map; - -// Spritesheets -static Spritesheet g_spr_player; -static Spritesheet g_spr_skeleton; -static Spritesheet g_spr_slime; -static Spritesheet g_spr_grass; -static Spritesheet g_spr_path; -static Spritesheet g_spr_water; -static Spritesheet g_spr_tree; -static Spritesheet g_spr_tree_small; -static Spritesheet g_spr_house; -static Spritesheet g_spr_chest; -static Spritesheet g_spr_fences; -static Spritesheet g_spr_gravestone; - -// Entities -static Player g_player; -static Enemy g_enemies[MAX_ENEMIES]; -static int g_enemy_count = 0; -static Decoration g_decor[MAX_DECORATIONS]; -static int g_decor_count = 0; -static Chest g_chests[MAX_CHESTS]; -static int g_chest_count = 0; - -// Camera -static float g_cam_x = 0; -static float g_cam_y = 0; - -// UI state -static char g_prompt[128] = {}; -static char g_dialog_text[256] = {}; -static float g_dialog_timer = 0; - -// ============================================================================ -// Asset loading -// ============================================================================ - -static bool load_assets() { - const char* base = "0:/apps/rpgdemo/"; - char path[128]; - - auto make_path = [&](const char* file) { - snprintf(path, sizeof(path), "%s%s", base, file); - }; - - // Player (32x32 frames, 6 columns x 10 rows) - make_path("Player.png"); - if (!g_spr_player.load(path, SPR_W, SPR_H)) return false; - - // Skeleton (same layout as player) - make_path("Skeleton.png"); - if (!g_spr_skeleton.load(path, SPR_W, SPR_H)) return false; - - // Slime (64x64 frames) - make_path("Slime_Green.png"); - g_spr_slime.load(path, 64, 64); // not fatal if missing - - // Tiles (single 16x16 images) - make_path("Grass_Middle.png"); - if (!g_spr_grass.load(path, TILE_SIZE, TILE_SIZE)) return false; - - make_path("Path_Middle.png"); - if (!g_spr_path.load(path, TILE_SIZE, TILE_SIZE)) return false; - - make_path("Water_Middle.png"); - if (!g_spr_water.load(path, TILE_SIZE, TILE_SIZE)) return false; - - // Decorations - make_path("Oak_Tree.png"); - g_spr_tree.load(path); - - make_path("Oak_Tree_Small.png"); - g_spr_tree_small.load(path, 32, 48); - - make_path("House.png"); - g_spr_house.load(path); - - make_path("Chest.png"); - g_spr_chest.load(path, TILE_SIZE, TILE_SIZE); - - make_path("Fences.png"); - g_spr_fences.load(path, TILE_SIZE, TILE_SIZE); - - // Procedural gravestone sprite (16x16) - { - static const uint8_t bmp[16 * 16] = { - 0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0, - 0,0,0,0,0,2,1,1,1,1,2,0,0,0,0,0, - 0,0,0,0,2,1,1,1,1,1,1,2,0,0,0,0, - 0,0,0,0,2,1,1,1,1,1,1,2,0,0,0,0, - 0,0,0,0,2,1,1,2,1,1,1,2,0,0,0,0, - 0,0,0,0,2,1,2,2,2,1,1,2,0,0,0,0, - 0,0,0,0,2,1,1,2,1,1,1,2,0,0,0,0, - 0,0,0,0,2,1,1,2,1,1,1,2,0,0,0,0, - 0,0,0,0,2,1,1,1,1,1,1,2,0,0,0,0, - 0,0,0,0,2,1,1,1,1,1,1,2,0,0,0,0, - 0,0,0,0,2,1,1,1,1,1,1,2,0,0,0,0, - 0,0,0,0,2,1,1,1,1,1,1,2,0,0,0,0, - 0,0,0,0,2,2,2,2,2,2,2,2,0,0,0,0, - 0,0,0,3,3,3,3,3,3,3,3,3,3,0,0,0, - 0,0,0,0,0,3,3,3,3,3,3,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - }; - static const uint32_t pal[4] = { - 0x00000000, 0xFF999999, 0xFF555555, 0xFF665544, - }; - g_spr_gravestone.width = 16; - g_spr_gravestone.height = 16; - g_spr_gravestone.frame_w = 16; - g_spr_gravestone.frame_h = 16; - g_spr_gravestone.cols = 1; - g_spr_gravestone.rows = 1; - g_spr_gravestone.pixels = (uint32_t*)montauk::malloc(16 * 16 * 4); - if (g_spr_gravestone.pixels) { - for (int i = 0; i < 16 * 16; i++) - g_spr_gravestone.pixels[i] = pal[bmp[i]]; - } - } - - return true; -} - -// ============================================================================ -// Entity initialization -// ============================================================================ - -enum TileId { TILE_GRASS = 0, TILE_PATH = 1, TILE_WATER = 2 }; - -static void setup_player_anims(AnimatedSprite& spr, Spritesheet* sheet) { - spr.sheet = sheet; - for (int d = 0; d < 4; d++) - spr.add_anim(d, 0, 6, 10.0f); - for (int d = 0; d < 4; d++) - spr.add_anim(d, 0, 1, 1.0f); -} - -static void init_player() { - g_player.x = 24 * TILE_SIZE; - g_player.y = 22 * TILE_SIZE; - g_player.health = PLAYER_HP; - g_player.max_health = PLAYER_HP; - g_player.direction = DIR_DOWN; - g_player.moving = false; - g_player.score = 0; - g_player.hit_timer = 0; - - setup_player_anims(g_player.sprite, &g_spr_player); - for (int d = 0; d < 4; d++) { - g_player.anim_walk[d] = d; - g_player.anim_idle[d] = 4 + d; - } - g_player.sprite.play(g_player.anim_idle[DIR_DOWN]); -} - -static void add_enemy(float x, float y, int type) { - if (g_enemy_count >= MAX_ENEMIES) return; - Enemy& e = g_enemies[g_enemy_count++]; - e.x = x; - e.y = y; - e.health = 30; - e.max_health = 30; - e.direction = DIR_DOWN; - e.active = true; - e.patrol_timer = 0; - e.patrol_duration = 2.0f; - e.type = type; - - if (type == 0) { - setup_player_anims(e.sprite, &g_spr_skeleton); - for (int d = 0; d < 4; d++) - e.anim_walk[d] = d; - } else { - e.sprite.sheet = &g_spr_slime; - e.sprite.add_anim(0, 0, 4, 6.0f); - for (int d = 0; d < 4; d++) - e.anim_walk[d] = 0; - } - e.sprite.play(0); -} - -static void add_decoration(float x, float y, Spritesheet* sheet, - bool solid, float cx, float cy, float cw, float ch, - int fcol = -1, int frow = -1) { - if (g_decor_count >= MAX_DECORATIONS) return; - Decoration& d = g_decor[g_decor_count++]; - d.x = x; - d.y = y; - d.sheet = sheet; - d.solid = solid; - d.col_x = cx; - d.col_y = cy; - d.col_w = cw; - d.col_h = ch; - d.frame_col = fcol; - d.frame_row = frow; -} - -static void add_chest(float x, float y) { - if (g_chest_count >= MAX_CHESTS) return; - Chest& c = g_chests[g_chest_count++]; - c.x = x; - c.y = y; - c.opened = false; - c.collected = false; -} - -// ============================================================================ -// World Generation -// ============================================================================ -// -// Uses an occupancy grid to prevent overlapping placements. Each tile cell -// stores bit flags indicating what occupies it. All placement functions -// validate against the grid before committing. -// -// Generation order (later phases respect earlier placements): -// 1. Water bodies -> OCC_WATER -// 2. Path network -> OCC_PATH -// 3. Houses -> OCC_VISUAL + OCC_SOLID (base) -// 4. Fences -> OCC_SOLID -// 5. Trees -> OCC_VISUAL + OCC_SOLID (trunk) -// 6. Gravestones -> OCC_VISUAL + OCC_SOLID -// 7. Chests -> OCC_SOLID -// 8. Enemies -> OCC_SPAWN -// -// ============================================================================ - -// ---- Occupancy grid ---- - -enum OccFlag : uint16_t { - OCC_WATER = 1 << 0, - OCC_PATH = 1 << 1, - OCC_SOLID = 1 << 2, - OCC_VISUAL = 1 << 3, - OCC_SPAWN = 1 << 4, -}; - -static uint16_t g_occ[MAP_W * MAP_H]; - -static uint16_t occ_at(int tx, int ty) { - if (tx < 0 || tx >= MAP_W || ty < 0 || ty >= MAP_H) return 0xFFFF; - return g_occ[ty * MAP_W + tx]; -} - -static bool occ_free(int tx, int ty, int tw, int th, uint16_t mask) { - for (int y = ty; y < ty + th; y++) - for (int x = tx; x < tx + tw; x++) - if (occ_at(x, y) & mask) return false; - return true; -} - -static void occ_mark(int tx, int ty, int tw, int th, uint16_t flags) { - for (int y = ty; y < ty + th; y++) - for (int x = tx; x < tx + tw; x++) { - if (x >= 0 && x < MAP_W && y >= 0 && y < MAP_H) - g_occ[y * MAP_W + x] |= flags; - } -} - -// ---- Terrain helpers ---- - -static void set_tiles(int x1, int y1, int x2, int y2, int tile, uint16_t occ) { - for (int y = y1; y <= y2; y++) - for (int x = x1; x <= x2; x++) { - if (x >= 0 && x < MAP_W && y >= 0 && y < MAP_H) { - g_map.set(x, y, tile); - occ_mark(x, y, 1, 1, occ); - } - } -} - -// ---- Placement functions ---- - -// Tree: 64x80px = 4w x 5h tiles -// Trunk collision at pixel (16,48) size (32,28) -> tile offset (1,3) size 2x2 -static bool place_tree(int tx, int ty) { - if (!occ_free(tx, ty, 4, 5, OCC_VISUAL | OCC_SOLID | OCC_WATER)) - return false; - if (!occ_free(tx + 1, ty + 3, 2, 2, OCC_PATH)) - return false; - add_decoration((float)tx * 16, (float)ty * 16, - &g_spr_tree, true, 16, 48, 32, 28); - occ_mark(tx, ty, 4, 5, OCC_VISUAL); - occ_mark(tx + 1, ty + 3, 2, 2, OCC_SOLID); - return true; -} - -// House: 96x128px = 6w x 8h tiles -// Base collision at pixel (8,80) size (80,44) -> tile offset (0,5) size ~6x3 -// Visual may overlap paths (roof overhang) but base must not. -static bool place_house(int tx, int ty) { - if (!occ_free(tx, ty, 6, 8, OCC_VISUAL | OCC_SOLID | OCC_WATER)) - return false; - if (!occ_free(tx, ty + 5, 6, 3, OCC_PATH)) - return false; - add_decoration((float)tx * 16, (float)ty * 16, - &g_spr_house, true, 8, 80, 80, 44); - occ_mark(tx, ty, 6, 8, OCC_VISUAL); - occ_mark(tx, ty + 5, 6, 3, OCC_SOLID); - return true; -} - -// Gravestone: 16x16px = 1x1 tile -static bool place_gravestone(int tx, int ty) { - if (!occ_free(tx, ty, 1, 1, OCC_SOLID | OCC_VISUAL | OCC_WATER)) - return false; - add_decoration((float)tx * 16, (float)ty * 16, - &g_spr_gravestone, true, 2, 2, 12, 14); - occ_mark(tx, ty, 1, 1, OCC_SOLID | OCC_VISUAL); - return true; -} - -// Chest: 1x1 tile, must be on walkable ground -static bool place_chest_at(int tx, int ty) { - if (!occ_free(tx, ty, 1, 1, OCC_SOLID | OCC_VISUAL | OCC_WATER)) - return false; - add_chest((float)tx * 16, (float)ty * 16); - occ_mark(tx, ty, 1, 1, OCC_SOLID); - return true; -} - -// Enemy: 2x2 tile footprint, needs walkable ground -static bool place_enemy_at(int tx, int ty, int type) { - if (!occ_free(tx, ty, 2, 2, OCC_SOLID | OCC_WATER)) - return false; - add_enemy((float)tx * 16, (float)ty * 16, type); - occ_mark(tx, ty, 2, 2, OCC_SPAWN); - return true; -} - -// Fence runs - each tile validated, skipped if blocked -static void gen_fence_h(int tx, int ty, int length) { - for (int i = 0; i < length; i++) { - int x = tx + i; - if (occ_at(x, ty) & (OCC_SOLID | OCC_WATER | OCC_PATH | OCC_VISUAL)) - continue; - int col = (i == 0) ? 0 : (i == length - 1) ? 3 : ((i % 2 == 1) ? 1 : 2); - add_decoration((float)x * 16, (float)ty * 16, &g_spr_fences, - true, 0, 4, 16, 12, col, 0); - occ_mark(x, ty, 1, 1, OCC_SOLID); - } -} - -static void gen_fence_v(int tx, int ty, int length) { - for (int i = 0; i < length; i++) { - int y = ty + i; - if (occ_at(tx, y) & (OCC_SOLID | OCC_WATER | OCC_PATH | OCC_VISUAL)) - continue; - int row = (i == 0) ? 0 : (i == length - 1) ? 3 : ((i % 2 == 1) ? 1 : 2); - add_decoration((float)tx * 16, (float)y * 16, &g_spr_fences, - true, 4, 0, 12, 16, 0, row); - occ_mark(tx, y, 1, 1, OCC_SOLID); - } -} - -// ---- Main world generation ---- - -static void generate_world() { - // Clear occupancy grid - for (int i = 0; i < MAP_W * MAP_H; i++) - g_occ[i] = 0; - - // Initialize tilemap - g_map.alloc(MAP_W, MAP_H, TILE_SIZE); - g_map.add_type(&g_spr_grass, 0, 0, TILE_SIZE, TILE_SIZE, false); - g_map.add_type(&g_spr_path, 0, 0, TILE_SIZE, TILE_SIZE, false); - g_map.add_type(&g_spr_water, 0, 0, TILE_SIZE, TILE_SIZE, true); - for (int i = 0; i < MAP_W * MAP_H; i++) - g_map.data[i] = TILE_GRASS; - - // ==== Phase 1: Water bodies ==== - - // Lake (top-right, ellipse centered at tile 40,7) - for (int y = 2; y < 12; y++) { - for (int x = 34; x < 47; x++) { - float dx = (float)(x - 40) / 6.0f; - float dy = (float)(y - 7) / 4.5f; - if (dx * dx + dy * dy < 1.0f) { - g_map.set(x, y, TILE_WATER); - occ_mark(x, y, 1, 1, OCC_WATER); - } - } - } - - // Pond (west side) - for (int y = 14; y < 18; y++) { - for (int x = 8; x < 13; x++) { - float dx = (float)(x - 10) / 2.5f; - float dy = (float)(y - 16) / 1.8f; - if (dx * dx + dy * dy < 1.0f) { - g_map.set(x, y, TILE_WATER); - occ_mark(x, y, 1, 1, OCC_WATER); - } - } - } - - // ==== Phase 2: Path network ==== - - set_tiles(0, 19, MAP_W - 1, 20, TILE_PATH, OCC_PATH); // main E-W road - set_tiles(24, 0, 25, MAP_H - 1, TILE_PATH, OCC_PATH); // main N-S road - set_tiles(25, 8, 42, 8, TILE_PATH, OCC_PATH); // lake spur - set_tiles(15, 19, 16, 30, TILE_PATH, OCC_PATH); // south branch - set_tiles(35, 20, 36, 26, TILE_PATH, OCC_PATH); // graveyard access - set_tiles(32, 26, 40, 33, TILE_PATH, OCC_PATH); // graveyard floor - - // ==== Phase 3: Houses ==== - // Village north of crossroads. Houses are 6x8 tiles. - // Positioned so bases (at ty+5..ty+7) don't overlap paths. - - place_house(18, 4); // left house - place_house(27, 4); // right house (gap at N-S path cols 24-25) - - // ==== Phase 4: Village fences ==== - // South boundary with gate at N-S path (cols 24-25) - - gen_fence_h(18, 16, 6); // left of gate: tiles 18-23 - gen_fence_h(26, 16, 7); // right of gate: tiles 26-32 - gen_fence_v(18, 12, 5); // left side - gen_fence_v(32, 12, 5); // right side - - // ==== Phase 5: Trees ==== - - // Northwest forest (4x5 tile spacing to prevent overlap) - place_tree(0, 0); - place_tree(5, 0); - place_tree(10, 0); - place_tree(2, 5); - place_tree(7, 5); - place_tree(12, 5); - place_tree(0, 10); - - // South wilderness - place_tree(2, 26); - place_tree(8, 30); - place_tree(28, 26); - place_tree(43, 28); - place_tree(44, 23); - - // East side - place_tree(46, 13); - place_tree(42, 21); - - // ==== Phase 6: Gravestones ==== - // Two rows of three within graveyard zone (32-40, 26-33) - - place_gravestone(34, 28); - place_gravestone(36, 28); - place_gravestone(38, 28); - place_gravestone(34, 31); - place_gravestone(36, 31); - place_gravestone(38, 31); - - // ==== Phase 7: Chests ==== - - place_chest_at(4, 3); // forest clearing - place_chest_at(43, 12); // near lake - place_chest_at(1, 32); // southern wilderness - place_chest_at(46, 35); // far corner - place_chest_at(26, 14); // village yard - - // ==== Phase 8: Enemies ==== - - // Skeletons patrol the graveyard - place_enemy_at(34, 29, 0); - place_enemy_at(37, 29, 0); - place_enemy_at(35, 32, 0); - - // Slimes in the northwest forest - place_enemy_at(4, 6, 1); - place_enemy_at(10, 6, 1); - - // Skeleton guard near lake - place_enemy_at(38, 14, 0); -} - -// ============================================================================ -// Update -// ============================================================================ - -static void update_camera() { - // Center camera on player - float target_x = g_player.x - (float)(WIN_W / SCALE) / 2.0f + SPR_W / 2.0f; - float target_y = g_player.y - (float)(WIN_H / SCALE) / 2.0f + SPR_H / 2.0f; - - // Smooth follow - g_cam_x += (target_x - g_cam_x) * 6.0f * g_engine.dt; - g_cam_y += (target_y - g_cam_y) * 6.0f * g_engine.dt; - - // Clamp to map bounds - float max_x = (float)(MAP_W * TILE_SIZE) - (float)(WIN_W / SCALE); - float max_y = (float)(MAP_H * TILE_SIZE) - (float)(WIN_H / SCALE); - if (g_cam_x < 0) g_cam_x = 0; - if (g_cam_y < 0) g_cam_y = 0; - if (g_cam_x > max_x) g_cam_x = max_x; - if (g_cam_y > max_y) g_cam_y = max_y; -} - -static bool check_decoration_collision(float x, float y, float w, float h) { - for (int i = 0; i < g_decor_count; i++) { - Decoration& d = g_decor[i]; - if (!d.solid) continue; - AABB a = { x, y, w, h }; - AABB b = { d.x + d.col_x, d.y + d.col_y, d.col_w, d.col_h }; - if (a.overlaps(b)) return true; - } - return false; -} - -static void update_player(float dt) { - float dx = 0, dy = 0; - bool moving = false; - - if (g_input.key_held(key::W) || g_input.key_held(key::UP)) { dy = -1; g_player.direction = DIR_UP; moving = true; } - if (g_input.key_held(key::S) || g_input.key_held(key::DOWN)) { dy = 1; g_player.direction = DIR_DOWN; moving = true; } - if (g_input.key_held(key::A) || g_input.key_held(key::LEFT)) { dx = -1; g_player.direction = DIR_LEFT; moving = true; } - if (g_input.key_held(key::D) || g_input.key_held(key::RIGHT)) { dx = 1; g_player.direction = DIR_RIGHT; moving = true; } - - // Normalize diagonal movement - if (dx != 0 && dy != 0) { - dx *= 0.707f; - dy *= 0.707f; - } - - dx *= PLAYER_SPEED * dt; - dy *= PLAYER_SPEED * dt; - - // Collision box: lower portion of sprite (feet area) - float bx = g_player.x + 8; - float by = g_player.y + 20; - float bw = 16; - float bh = 10; - - // Tilemap collision - resolve_tilemap_collision(g_map, bx, by, bw, bh, dx, dy); - - // Decoration collision - X axis - if (dx != 0 && check_decoration_collision(bx + dx, by, bw, bh)) - dx = 0; - // Decoration collision - Y axis - if (dy != 0 && check_decoration_collision(bx + dx, by + dy, bw, bh)) - dy = 0; - - // World bounds - float new_x = g_player.x + dx; - float new_y = g_player.y + dy; - if (new_x < 0) new_x = 0; - if (new_y < 0) new_y = 0; - if (new_x > (MAP_W - 2) * TILE_SIZE) new_x = (float)((MAP_W - 2) * TILE_SIZE); - if (new_y > (MAP_H - 2) * TILE_SIZE) new_y = (float)((MAP_H - 2) * TILE_SIZE); - - g_player.x = new_x; - g_player.y = new_y; - g_player.moving = moving; - - // Animation - if (moving) { - g_player.sprite.play(g_player.anim_walk[g_player.direction]); - } else { - g_player.sprite.play(g_player.anim_idle[g_player.direction]); - } - g_player.sprite.update(dt); - - // Invincibility timer - if (g_player.hit_timer > 0) - g_player.hit_timer -= dt; -} - -static void update_enemies(float dt) { - for (int i = 0; i < g_enemy_count; i++) { - Enemy& e = g_enemies[i]; - if (!e.active) continue; - - // Simple patrol AI - e.patrol_timer += dt; - if (e.patrol_timer >= e.patrol_duration) { - e.patrol_timer = 0; - e.direction = (e.direction + 1) % 4; - // Randomize duration slightly using frame count - e.patrol_duration = 1.5f + (float)(g_engine.frame_count % 3) * 0.5f; - } - - float dx = 0, dy = 0; - switch (e.direction) { - case DIR_DOWN: dy = ENEMY_SPEED * dt; break; - case DIR_UP: dy = -ENEMY_SPEED * dt; break; - case DIR_RIGHT: dx = ENEMY_SPEED * dt; break; - case DIR_LEFT: dx = -ENEMY_SPEED * dt; break; - } - - // Tilemap collision - float bx = e.x + 8; - float by = e.y + 20; - float bw = 16; - float bh = 10; - resolve_tilemap_collision(g_map, bx, by, bw, bh, dx, dy); - - // Reverse direction if blocked - if (dx == 0 && dy == 0) { - e.direction = (e.direction + 2) % 4; - e.patrol_timer = 0; - } - - // World bounds - float new_x = e.x + dx; - float new_y = e.y + dy; - if (new_x < 0 || new_x > (MAP_W - 2) * TILE_SIZE) { - e.direction = (e.direction + 2) % 4; - e.patrol_timer = 0; - new_x = e.x; - } - if (new_y < 0 || new_y > (MAP_H - 2) * TILE_SIZE) { - e.direction = (e.direction + 2) % 4; - e.patrol_timer = 0; - new_y = e.y; - } - - e.x = new_x; - e.y = new_y; - - // Animation - if (e.type == 0) { - e.sprite.play(e.anim_walk[e.direction]); - } - e.sprite.update(dt); - - // Damage player on contact - AABB pa = { g_player.x + 4, g_player.y + 8, 24, 22 }; - AABB ea = { e.x + 4, e.y + 8, 24, 22 }; - if (pa.overlaps(ea) && g_player.hit_timer <= 0) { - g_player.health -= 10; - g_player.hit_timer = 1.0f; // 1 second invincibility - if (g_player.health < 0) g_player.health = 0; - - // Knockback with collision checking - float kx = g_player.x - e.x; - float ky = g_player.y - e.y; - float len = 1.0f; - if (kx != 0 || ky != 0) { - float ax = kx < 0 ? -kx : kx; - float ay = ky < 0 ? -ky : ky; - len = ax > ay ? ax + ay * 0.4f : ay + ax * 0.4f; - } - float kb_dx = (kx / len) * 16.0f; - float kb_dy = (ky / len) * 16.0f; - - // Check collision before applying knockback - float bx = g_player.x + 8; - float by = g_player.y + 20; - resolve_tilemap_collision(g_map, bx, by, 16, 10, kb_dx, kb_dy); - float new_px = g_player.x + kb_dx; - float new_py = g_player.y + kb_dy; - if (new_px < 0) new_px = 0; - if (new_py < 0) new_py = 0; - if (new_px > (MAP_W - 2) * TILE_SIZE) new_px = (float)((MAP_W - 2) * TILE_SIZE); - if (new_py > (MAP_H - 2) * TILE_SIZE) new_py = (float)((MAP_H - 2) * TILE_SIZE); - g_player.x = new_px; - g_player.y = new_py; - - // Sound effect - g_audio.play_tone(200, 80, 30); - } - } -} - -static void update_interactions() { - g_prompt[0] = '\0'; - - // Check chest proximity - for (int i = 0; i < g_chest_count; i++) { - Chest& c = g_chests[i]; - if (c.collected) continue; - - float dx = g_player.x + 16 - (c.x + 8); - float dy = g_player.y + 16 - (c.y + 8); - float dist = dx * dx + dy * dy; - - if (dist < 40 * 40) { - if (!c.opened) { - snprintf(g_prompt, sizeof(g_prompt), "Press E to open chest"); - if (g_input.key_just_pressed(key::E)) { - c.opened = true; - c.collected = true; - g_player.score += 100; - snprintf(g_dialog_text, sizeof(g_dialog_text), - "You found treasure! +100 points"); - g_dialog_timer = 2.0f; - g_audio.play_tone(523, 100, 25); // C5 - g_audio.play_tone(659, 100, 25); // E5 - g_audio.play_tone(784, 150, 25); // G5 - } - } - } - } - - // Dialog timer - if (g_dialog_timer > 0) { - g_dialog_timer -= g_engine.dt; - if (g_dialog_timer <= 0) g_dialog_text[0] = '\0'; - } -} - -static void update(float dt) { - if (g_player.health <= 0) { - // Game over - respawn after pressing space - if (g_input.key_just_pressed(key::SPACE)) { - g_player.health = PLAYER_HP; - g_player.x = 24 * TILE_SIZE; - g_player.y = 22 * TILE_SIZE; - } - return; - } - - update_player(dt); - update_enemies(dt); - update_interactions(); - update_camera(); -} - -// ============================================================================ -// Rendering -// ============================================================================ - -// Y-sort helper for draw ordering -struct DrawEntry { - float y; - int type; // 0=decoration, 1=player, 2=enemy, 3=chest - int index; -}; - -static DrawEntry g_draw_list[MAX_DECORATIONS + MAX_ENEMIES + MAX_CHESTS + 1]; -static int g_draw_count = 0; - -static void sort_draw_list() { - // Simple insertion sort (small N) - for (int i = 1; i < g_draw_count; i++) { - DrawEntry tmp = g_draw_list[i]; - int j = i - 1; - while (j >= 0 && g_draw_list[j].y > tmp.y) { - g_draw_list[j + 1] = g_draw_list[j]; - j--; - } - g_draw_list[j + 1] = tmp; - } -} - -static void render() { - int cam_x = (int)g_cam_x; - int cam_y = (int)g_cam_y; - - // Draw tilemap - g_map.draw(g_engine.pixels, g_engine.screen_w, g_engine.screen_h, - cam_x, cam_y, SCALE); - - // Build Y-sorted draw list for entities and decorations - g_draw_count = 0; - - for (int i = 0; i < g_decor_count; i++) { - Decoration& dc = g_decor[i]; - float h = 0; - if (dc.sheet) { - h = (dc.frame_col >= 0) ? (float)dc.sheet->frame_h - : (float)dc.sheet->height; - } - g_draw_list[g_draw_count++] = { dc.y + h, 0, i }; - } - - for (int i = 0; i < g_chest_count; i++) { - g_draw_list[g_draw_count++] = { g_chests[i].y + TILE_SIZE, 3, i }; - } - - g_draw_list[g_draw_count++] = { g_player.y + SPR_H, 1, 0 }; - - for (int i = 0; i < g_enemy_count; i++) { - if (!g_enemies[i].active) continue; - float bottom = g_enemies[i].y + (g_enemies[i].type == 1 ? 64 : SPR_H); - g_draw_list[g_draw_count++] = { bottom, 2, i }; - } - - sort_draw_list(); - - // Render sorted entities - for (int i = 0; i < g_draw_count; i++) { - DrawEntry& de = g_draw_list[i]; - - if (de.type == 0) { - // Decoration - Decoration& d = g_decor[de.index]; - if (d.sheet && d.sheet->pixels) { - int sx = (int)(d.x * SCALE) - cam_x * SCALE; - int sy = (int)(d.y * SCALE) - cam_y * SCALE; - if (d.frame_col >= 0 && d.frame_row >= 0) { - d.sheet->draw_frame(g_engine.pixels, g_engine.screen_w, - g_engine.screen_h, d.frame_col, - d.frame_row, sx, sy, SCALE); - } else { - d.sheet->draw_region(g_engine.pixels, g_engine.screen_w, - g_engine.screen_h, 0, 0, - d.sheet->width, d.sheet->height, - sx, sy, SCALE); - } - } - } else if (de.type == 1) { - // Player - int px = (int)(g_player.x * SCALE) - cam_x * SCALE; - int py = (int)(g_player.y * SCALE) - cam_y * SCALE; - - // Flash when invincible - bool visible = true; - if (g_player.hit_timer > 0) { - visible = ((int)(g_player.hit_timer * 10) % 2 == 0); - } - - if (visible) { - g_player.sprite.draw(g_engine.pixels, g_engine.screen_w, - g_engine.screen_h, px, py, SCALE); - } - } else if (de.type == 2) { - // Enemy - Enemy& e = g_enemies[de.index]; - int ex = (int)(e.x * SCALE) - cam_x * SCALE; - int ey = (int)(e.y * SCALE) - cam_y * SCALE; - e.sprite.draw(g_engine.pixels, g_engine.screen_w, - g_engine.screen_h, ex, ey, SCALE); - - // Health bar above enemy - if (e.health < e.max_health) { - draw_bar(g_engine, ex + 4, ey - 8, 56, 6, - e.health, e.max_health, - 0xFFCC3333, 0xFF333333, 0xFF000000); - } - } else if (de.type == 3) { - // Chest - Chest& c = g_chests[de.index]; - int cx = (int)(c.x * SCALE) - cam_x * SCALE; - int cy = (int)(c.y * SCALE) - cam_y * SCALE; - - if (!c.collected && g_spr_chest.pixels) { - // Draw chest (frame 0 = closed, use tinting for opened) - g_spr_chest.draw_frame(g_engine.pixels, g_engine.screen_w, - g_engine.screen_h, 0, 0, - cx, cy, SCALE); - if (c.opened) { - // Darken opened chests slightly - g_engine.fill_rect_alpha(cx, cy, TILE_SIZE * SCALE, - TILE_SIZE * SCALE, 0x40000000); - } - } - } - } - - // ---- HUD ---- - - // Health bar - draw_bar(g_engine, 8, 8, 160, 20, - g_player.health, g_player.max_health, - 0xFFCC3333, 0xFF444444, 0xFF000000); - - char hp_text[32]; - snprintf(hp_text, sizeof(hp_text), "HP: %d/%d", g_player.health, g_player.max_health); - draw_hud_text(g_engine, 12, 9, hp_text, - Color::from_rgb(0xFF, 0xFF, 0xFF), 14); - - // Score - char score_text[32]; - snprintf(score_text, sizeof(score_text), "Score: %d", g_player.score); - draw_hud_text(g_engine, 8, 34, score_text, - Color::from_rgb(0xFF, 0xDD, 0x44), 14); - - // FPS counter - if (g_engine.dt > 0) { - char fps_text[16]; - int fps = (int)(1.0f / g_engine.dt); - snprintf(fps_text, sizeof(fps_text), "%d FPS", fps); - int fw = g_engine.text_width(fps_text, 12); - draw_hud_text(g_engine, g_engine.screen_w - fw - 8, 8, fps_text, - Color::from_rgb(0xAA, 0xAA, 0xAA), 12); - } - - // Interaction prompt - if (g_prompt[0]) { - draw_prompt(g_engine, g_prompt, 14); - } - - // Dialog text - if (g_dialog_text[0] && g_dialog_timer > 0) { - int dw = 300; - int dh = 50; - int dx = (g_engine.screen_w - dw) / 2; - int dy = g_engine.screen_h - 100; - draw_dialog(g_engine, dx, dy, dw, dh, g_dialog_text, - Color::from_rgb(0x33, 0x33, 0x33), 14); - } - - // Game over screen - if (g_player.health <= 0) { - g_engine.fill_rect_alpha(0, 0, g_engine.screen_w, g_engine.screen_h, - 0xAA000000); - const char* go_text = "Game Over"; - int tw = g_engine.text_width(go_text, 32); - g_engine.draw_text((g_engine.screen_w - tw) / 2, - g_engine.screen_h / 2 - 30, - go_text, Color::from_rgb(0xFF, 0x44, 0x44), 32); - - const char* restart_text = "Press SPACE to respawn"; - tw = g_engine.text_width(restart_text, 16); - g_engine.draw_text((g_engine.screen_w - tw) / 2, - g_engine.screen_h / 2 + 10, - restart_text, Color::from_rgb(0xCC, 0xCC, 0xCC), 16); - - char final_score[64]; - snprintf(final_score, sizeof(final_score), "Final Score: %d", g_player.score); - tw = g_engine.text_width(final_score, 18); - g_engine.draw_text((g_engine.screen_w - tw) / 2, - g_engine.screen_h / 2 + 40, - final_score, Color::from_rgb(0xFF, 0xDD, 0x44), 18); - } -} - -// ============================================================================ -// Entry point -// ============================================================================ - -extern "C" void _start() { - // Initialize engine - if (!g_engine.init("Montauk Quest", WIN_W, WIN_H)) { - montauk::print("Failed to create game window\n"); - montauk::exit(1); - } - - g_input.init(); - - // Initialize audio (non-fatal if it fails) - g_audio.init(); - - // Load assets - if (!load_assets()) { - montauk::print("Failed to load game assets\n"); - g_engine.shutdown(); - montauk::exit(1); - } - - // Initialize game world - generate_world(); - init_player(); - - // Main game loop - while (g_engine.running) { - g_engine.update_timing(); - g_input.begin_frame(); - - // Process all pending events - montauk::abi::WinEvent ev; - while (g_engine.poll(&ev)) { - g_input.handle_event(ev); - - // Escape to quit - if (ev.type == 0 && ev.key.pressed && ev.key.scancode == key::ESC) - g_engine.running = false; - } - - // Update - update(g_engine.dt); - - // Render - render(); - g_engine.present(); - - // Yield to avoid burning CPU when there's no input - montauk::sleep_ms(1); - } - - g_audio.shutdown(); - g_engine.shutdown(); - montauk::exit(0); -} diff --git a/programs/src/rpgdemo/manifest.toml b/programs/src/rpgdemo/manifest.toml deleted file mode 100644 index 69519f7..0000000 --- a/programs/src/rpgdemo/manifest.toml +++ /dev/null @@ -1,8 +0,0 @@ -[app] -name = "Montauk Quest" -binary = "rpgdemo.elf" -icon = "icon.svg" - -[menu] -category = "Games" -visible = true diff --git a/programs/src/rpgdemo/stb_impl.cpp b/programs/src/rpgdemo/stb_impl.cpp deleted file mode 100644 index 1d30d13..0000000 --- a/programs/src/rpgdemo/stb_impl.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * stb_impl.cpp - * Single compilation unit for stb_image (PNG) and stb_truetype - * for MontaukOS freestanding environment - * Copyright (c) 2026 Daniel Hammer - */ - -#include -#include -#include -#include -#include - -extern "C" { -#include -#include -} - -// ============================================================================ -// stb_image - PNG decoder -// ============================================================================ - -#define STBI_ONLY_PNG -#define STBI_NO_JPEG -#define STBI_NO_BMP -#define STBI_NO_PSD -#define STBI_NO_TGA -#define STBI_NO_GIF -#define STBI_NO_HDR -#define STBI_NO_PIC -#define STBI_NO_PNM -#define STBI_NO_LINEAR -#define STBI_NO_STDIO -#define STBI_NO_THREAD_LOCALS - -#define STBI_MALLOC(sz) malloc(sz) -#define STBI_FREE(p) free(p) -#define STBI_REALLOC(p, newsz) realloc(p, newsz) - -#define STBI_ASSERT(x) ((void)(x)) - -#define STB_IMAGE_IMPLEMENTATION -#include - -// ============================================================================ -// stb_truetype - TrueType font renderer -// ============================================================================ - -#define STBTT_ifloor(x) ((int) stb_floor(x)) -#define STBTT_iceil(x) ((int) stb_ceil(x)) -#define STBTT_sqrt(x) stb_sqrt(x) -#define STBTT_pow(x,y) stb_pow(x,y) -#define STBTT_fmod(x,y) stb_fmod(x,y) -#define STBTT_cos(x) stb_cos(x) -#define STBTT_acos(x) stb_acos(x) -#define STBTT_fabs(x) stb_fabs(x) - -#define STBTT_malloc(x,u) ((void)(u), montauk::malloc(x)) -#define STBTT_free(x,u) ((void)(u), montauk::mfree(x)) - -#define STBTT_memcpy(d,s,n) montauk::memcpy(d,s,n) -#define STBTT_memset(d,v,n) montauk::memset(d,v,n) - -#define STBTT_strlen(x) montauk::slen(x) - -#define STBTT_assert(x) ((void)(x)) - -#define STB_TRUETYPE_IMPLEMENTATION -#include diff --git a/scripts/install_apps.sh b/scripts/install_apps.sh index 8b18b79..2abee4c 100755 --- a/scripts/install_apps.sh +++ b/scripts/install_apps.sh @@ -41,7 +41,6 @@ APPS=( "charmap|apps/scalable/accessories-character-map.svg" "printers|devices/scalable/preferences-devices-printer.svg" "timezone|categories/scalable/preferences-system-time.svg" - "rpgdemo|apps/scalable/utilities-terminal.svg" "paint|apps/scalable/kolourpaint.svg" "screenshot|apps/scalable/gnome-screenshot.svg" "texteditor|apps/scalable/accessories-text-editor.svg"