diff --git a/.gitignore b/.gitignore index f9c749a5..8f887476 100644 --- a/.gitignore +++ b/.gitignore @@ -383,3 +383,15 @@ Crawler/out /Adventures in Lestoria/x64 /Adventures in Lestoria/saves /Adventures in Lestoria/assets/tmpsaves +a.out +build/CMakeCache.txt +build/.cmake/api/v1/query/client-vscode/query.json +build/CMakeFiles/cmake.check_cache +build/CMakeFiles/3.16.3/CMakeCCompiler.cmake +build/CMakeFiles/3.16.3/CMakeCXXCompiler.cmake +build/CMakeFiles/3.16.3/CMakeDetermineCompilerABI_C.bin +build/CMakeFiles/3.16.3/CMakeDetermineCompilerABI_CXX.bin +build/CMakeFiles/3.16.3/CMakeSystem.cmake +build/CMakeFiles/3.16.3/CompilerIdC/CMakeCCompilerId.c +build/CMakeFiles/3.16.3/CompilerIdCXX/CMakeCXXCompilerId.cpp +test.cpp diff --git a/.vscode/settings.json b/.vscode/settings.json index 8bbfb646..a4efd077 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -89,6 +89,8 @@ "regex": "cpp", "valarray": "cpp", "*.inc": "cpp", - "future": "cpp" + "future": "cpp", + "any": "cpp", + "source_location": "cpp" } } \ No newline at end of file diff --git a/Adventures in Lestoria/Adventures in Lestoria.data b/Adventures in Lestoria/Adventures in Lestoria.data new file mode 100644 index 00000000..69619502 Binary files /dev/null and b/Adventures in Lestoria/Adventures in Lestoria.data differ diff --git a/Adventures in Lestoria/Adventures in Lestoria.html b/Adventures in Lestoria/Adventures in Lestoria.html new file mode 100644 index 00000000..0db68c58 --- /dev/null +++ b/Adventures in Lestoria/Adventures in Lestoria.html @@ -0,0 +1,75 @@ + + + + + + + + Emscripten-Generated Code + + + + + + + + + + diff --git a/Adventures in Lestoria/Adventures in Lestoria.js b/Adventures in Lestoria/Adventures in Lestoria.js new file mode 100644 index 00000000..f157aa00 --- /dev/null +++ b/Adventures in Lestoria/Adventures in Lestoria.js @@ -0,0 +1 @@ +var Module=typeof Module!="undefined"?Module:{};if(!Module.expectedDataFileDownloads){Module.expectedDataFileDownloads=0}Module.expectedDataFileDownloads++;(function(){if(Module["ENVIRONMENT_IS_PTHREAD"]||Module["$ww"])return;var loadPackage=function(metadata){var PACKAGE_PATH="";if(typeof window==="object"){PACKAGE_PATH=window["encodeURIComponent"](window.location.pathname.toString().substring(0,window.location.pathname.toString().lastIndexOf("/"))+"/")}else if(typeof process==="undefined"&&typeof location!=="undefined"){PACKAGE_PATH=encodeURIComponent(location.pathname.toString().substring(0,location.pathname.toString().lastIndexOf("/"))+"/")}var PACKAGE_NAME="Adventures in Lestoria.data";var REMOTE_PACKAGE_BASE="Adventures in Lestoria.data";if(typeof Module["locateFilePackage"]==="function"&&!Module["locateFile"]){Module["locateFile"]=Module["locateFilePackage"];err("warning: you defined Module.locateFilePackage, that has been renamed to Module.locateFile (using your locateFilePackage for now)")}var REMOTE_PACKAGE_NAME=Module["locateFile"]?Module["locateFile"](REMOTE_PACKAGE_BASE,""):REMOTE_PACKAGE_BASE;var REMOTE_PACKAGE_SIZE=metadata["remote_package_size"];function fetchRemotePackage(packageName,packageSize,callback,errback){if(typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string"){require("fs").readFile(packageName,function(err,contents){if(err){errback(err)}else{callback(contents.buffer)}});return}var xhr=new XMLHttpRequest;xhr.open("GET",packageName,true);xhr.responseType="arraybuffer";xhr.onprogress=function(event){var url=packageName;var size=packageSize;if(event.total)size=event.total;if(event.loaded){if(!xhr.addedTotal){xhr.addedTotal=true;if(!Module.dataFileDownloads)Module.dataFileDownloads={};Module.dataFileDownloads[url]={loaded:event.loaded,total:size}}else{Module.dataFileDownloads[url].loaded=event.loaded}var total=0;var loaded=0;var num=0;for(var download in Module.dataFileDownloads){var data=Module.dataFileDownloads[download];total+=data.total;loaded+=data.loaded;num++}total=Math.ceil(total*Module.expectedDataFileDownloads/num);if(Module["setStatus"])Module["setStatus"](`Downloading data... (${loaded}/${total})`)}else if(!Module.dataFileDownloads){if(Module["setStatus"])Module["setStatus"]("Downloading data...")}};xhr.onerror=function(event){throw new Error("NetworkError for: "+packageName)};xhr.onload=function(event){if(xhr.status==200||xhr.status==304||xhr.status==206||xhr.status==0&&xhr.response){var packageData=xhr.response;callback(packageData)}else{throw new Error(xhr.statusText+" : "+xhr.responseURL)}};xhr.send(null)}function handleError(error){console.error("package error:",error)}var fetchedCallback=null;var fetched=Module["getPreloadedPackage"]?Module["getPreloadedPackage"](REMOTE_PACKAGE_NAME,REMOTE_PACKAGE_SIZE):null;if(!fetched)fetchRemotePackage(REMOTE_PACKAGE_NAME,REMOTE_PACKAGE_SIZE,function(data){if(fetchedCallback){fetchedCallback(data);fetchedCallback=null}else{fetched=data}},handleError);function runWithFS(){function assert(check,msg){if(!check)throw msg+(new Error).stack}Module["FS_createPath"]("/","assets",true,true);Module["FS_createPath"]("/assets","Ability Icons",true,true);Module["FS_createPath"]("/assets","Campaigns",true,true);Module["FS_createPath"]("/assets","backgrounds",true,true);Module["FS_createPath"]("/assets","characters",true,true);Module["FS_createPath"]("/assets","config",true,true);Module["FS_createPath"]("/assets/config","audio",true,true);Module["FS_createPath"]("/assets/config","classes",true,true);Module["FS_createPath"]("/assets/config","gfx",true,true);Module["FS_createPath"]("/assets/config","items",true,true);Module["FS_createPath"]("/assets/config","shops",true,true);Module["FS_createPath"]("/assets/config","story",true,true);Module["FS_createPath"]("/assets","items",true,true);Module["FS_createPath"]("/assets","maps",true,true);Module["FS_createPath"]("/assets","menus",true,true);Module["FS_createPath"]("/assets","monsters",true,true);Module["FS_createPath"]("/assets","music",true,true);Module["FS_createPath"]("/assets/music","loop1",true,true);Module["FS_createPath"]("/assets/music","loop2",true,true);Module["FS_createPath"]("/assets","sounds",true,true);Module["FS_createPath"]("/assets","themes",true,true);function DataRequest(start,end,audio){this.start=start;this.end=end;this.audio=audio}DataRequest.prototype={requests:{},open:function(mode,name){this.name=name;this.requests[name]=this;Module["addRunDependency"](`fp ${this.name}`)},send:function(){},onload:function(){var byteArray=this.byteArray.subarray(this.start,this.end);this.finish(byteArray)},finish:function(byteArray){var that=this;Module["FS_createDataFile"](this.name,null,byteArray,true,true,true);Module["removeRunDependency"](`fp ${that.name}`);this.requests[this.name]=null}};var files=metadata["files"];for(var i=0;i{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");if(ENVIRONMENT_IS_WORKER){scriptDirectory=nodePath.dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=(filename,binary)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)onerror(err);else onload(binary?data.buffer:data)})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);if(typeof module!="undefined"){module["exports"]=Module}process.on("uncaughtException",ex=>{if(ex!=="unwind"&&!(ex instanceof ExitStatus)&&!(ex.context instanceof ExitStatus)){throw ex}});quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow};Module["inspect"]=()=>"[Emscripten Module object]"}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(typeof WebAssembly!="object"){abort("no native wasm support detected")}function intArrayFromBase64(s){if(typeof ENVIRONMENT_IS_NODE!="undefined"&&ENVIRONMENT_IS_NODE){var buf=Buffer.from(s,"base64");return new Uint8Array(buf.buffer,buf.byteOffset,buf.length)}var decoded=atob(s);var bytes=new Uint8Array(decoded.length);for(var i=0;ifilename.startsWith(dataURIPrefix);var isFileURI=filename=>filename.startsWith("file://");var wasmBinaryFile;wasmBinaryFile="Adventures in Lestoria.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch=="function"&&!isFileURI(binaryFile)){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{if(!response["ok"]){throw"failed to load wasm binary file at '"+binaryFile+"'"}return response["arrayBuffer"]()}).catch(()=>getBinarySync(binaryFile))}else if(readAsync){return new Promise((resolve,reject)=>{readAsync(binaryFile,response=>resolve(new Uint8Array(response)),reject)})}}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(instance=>instance).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function createWasm(){var info={"env":wasmImports,"wasi_snapshot_preview1":wasmImports};function receiveInstance(instance,module){wasmExports=instance.exports;wasmExports=applySignatureConversions(wasmExports);wasmMemory=wasmExports["memory"];updateMemoryViews();wasmTable=wasmExports["__indirect_function_table"];addOnInit(wasmExports["__wasm_call_ctors"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);return false}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult);return{}}var tempDouble;var tempI64;var ASM_CONSTS={391956:()=>{if(requestResp&&requestResp!==""){var newPtr=stringToNewUTF8(requestResp);requestResp="";return newPtr}return 0},392079:($0,$1,$2,$3,$4)=>{if(typeof window==="undefined"||(window.AudioContext||window.webkitAudioContext)===undefined){return 0}if(typeof window.miniaudio==="undefined"){window.miniaudio={referenceCount:0};window.miniaudio.device_type={};window.miniaudio.device_type.playback=$0;window.miniaudio.device_type.capture=$1;window.miniaudio.device_type.duplex=$2;window.miniaudio.device_state={};window.miniaudio.device_state.stopped=$3;window.miniaudio.device_state.started=$4;miniaudio.devices=[];miniaudio.track_device=function(device){for(var iDevice=0;iDevice0){if(miniaudio.devices[miniaudio.devices.length-1]==null){miniaudio.devices.pop()}else{break}}};miniaudio.untrack_device=function(device){for(var iDevice=0;iDevice{if(typeof window.miniaudio!=="undefined"){window.miniaudio.referenceCount-=1;if(window.miniaudio.referenceCount===0){delete window.miniaudio}}},394233:()=>navigator.mediaDevices!==undefined&&navigator.mediaDevices.getUserMedia!==undefined,394337:()=>{try{var temp=new(window.AudioContext||window.webkitAudioContext);var sampleRate=temp.sampleRate;temp.close();return sampleRate}catch(e){return 0}},394508:($0,$1,$2,$3,$4,$5)=>{var deviceType=$0;var channels=$1;var sampleRate=$2;var bufferSize=$3;var pIntermediaryBuffer=$4;var pDevice=$5;if(typeof window.miniaudio==="undefined"){return-1}var device={};var audioContextOptions={};if(deviceType==window.miniaudio.device_type.playback){audioContextOptions.sampleRate=sampleRate}device.webaudio=new(window.AudioContext||window.webkitAudioContext)(audioContextOptions);device.webaudio.suspend();device.state=window.miniaudio.device_state.stopped;var channelCountIn=0;var channelCountOut=channels;if(deviceType!=window.miniaudio.device_type.playback){channelCountIn=channels}device.scriptNode=device.webaudio.createScriptProcessor(bufferSize,channelCountIn,channelCountOut);device.scriptNode.onaudioprocess=function(e){if(device.intermediaryBufferView==null||device.intermediaryBufferView.length==0){device.intermediaryBufferView=new Float32Array(Module.HEAPF32.buffer,pIntermediaryBuffer,bufferSize*channels)}if(deviceType==miniaudio.device_type.capture||deviceType==miniaudio.device_type.duplex){for(var iChannel=0;iChannelminiaudio.get_device_by_index($0).webaudio.sampleRate,397357:$0=>{var device=miniaudio.get_device_by_index($0);if(device.scriptNode!==undefined){device.scriptNode.onaudioprocess=function(e){};device.scriptNode.disconnect();device.scriptNode=undefined}if(device.streamNode!==undefined){device.streamNode.disconnect();device.streamNode=undefined}device.webaudio.close();device.webaudio=undefined},397722:$0=>{miniaudio.untrack_device_by_index($0)},397765:$0=>{var device=miniaudio.get_device_by_index($0);device.webaudio.resume();device.state=miniaudio.device_state.started},397890:$0=>{var device=miniaudio.get_device_by_index($0);device.webaudio.suspend();device.state=miniaudio.device_state.stopped},398016:()=>{window.onunload=Module._olc_OnPageUnload},398060:($0,$1)=>{requestResp="";Module.olc_AspectRatio=$0/$1;Module.olc_AssumeDefaultShells=document.querySelectorAll(".emscripten").length>=3?true:false;oncontextmenu=function(e){return false};var olc_ResizeHandler=function(){let isFullscreen=document.fullscreenElement!=null;let width=isFullscreen?window.innerWidth:Module.canvas.parentNode.clientWidth;let height=isFullscreen?window.innerHeight:Module.canvas.parentNode.clientHeight;let viewWidth=width;let viewHeight=width/Module.olc_AspectRatio;if(viewHeight>height){viewWidth=height*Module.olc_AspectRatio;viewHeight=height}viewWidth=parseInt(viewWidth);viewHeight=parseInt(viewHeight);setTimeout(function(){if(Module.olc_AssumeDefaultShells)Module.canvas.parentNode.setAttribute("style","width: 100%; height: 70vh; margin-left: auto; margin-right: auto;");Module.canvas.setAttribute("width",viewWidth);Module.canvas.setAttribute("height",viewHeight);Module.canvas.setAttribute("style",`width: ${viewWidth}px; height: ${viewHeight}px;`);Module._olc_PGE_UpdateWindowSize(viewWidth,viewHeight);Module.canvas.focus()},200)};var olc_Init=function(){if(Module.olc_AspectRatio===undefined){setTimeout(function(){Module.olc_Init()},50);return}let resizeObserver=new ResizeObserver(function(entries){Module.olc_ResizeHandler()}).observe(Module.canvas.parentNode);let mutationObserver=new MutationObserver(function(mutationsList,observer){setTimeout(function(){Module.olc_ResizeHandler()},200)}).observe(Module.canvas.parentNode,{attributes:false,childList:true,subtree:false});window.addEventListener("fullscreenchange",function(e){setTimeout(function(){Module.olc_ResizeHandler()},200)})};Module.olc_ResizeHandler=Module.olc_ResizeHandler!=undefined?Module.olc_ResizeHandler:olc_ResizeHandler;Module.olc_Init=Module.olc_Init!=undefined?Module.olc_Init:olc_Init;Module.olc_Init()},400049:()=>window.scrollX,400073:()=>window.scrollY,400097:()=>window.scrollX,400121:()=>window.scrollY,400145:()=>window.scrollX,400169:()=>window.scrollY,400193:()=>Module.canvas.getBoundingClientRect().left,400245:()=>Module.canvas.getBoundingClientRect().top,400296:()=>Module.canvas.getBoundingClientRect().left,400348:()=>Module.canvas.getBoundingClientRect().top,400399:($0,$1)=>{requestResp="";fetch(UTF8ToString($0),{headers:{"Content-Type":"application/json"},method:"POST",body:UTF8ToString($1)}).then(resp=>{if(resp.ok){return resp.text()}else{throw new Error(resp.text())}}).then(data=>{requestResp=data}).catch(err=>{requestResp="ERR"})}};function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status}var listenOnce=(object,event,func)=>{object.addEventListener(event,func,{"once":true})};var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var dynCallLegacy=(sig,ptr,args)=>{var f=Module["dynCall_"+sig];return args&&args.length?f.apply(null,[ptr].concat(args)):f.call(null,ptr)};var wasmTableMirror=[];var wasmTable;var getWasmTableEntry=funcPtr=>{var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func};var noExitRuntime=Module["noExitRuntime"]||true;var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):undefined;var UTF8ArrayToString=(heapOrArray,idx,maxBytesToRead)=>{idx>>>=0;var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>{ptr>>>=0;return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""};function ___assert_fail(condition,filename,line,func){condition>>>=0;filename>>>=0;func>>>=0;abort(`Assertion failed: ${UTF8ToString(condition)}, at: `+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24;this.set_type=function(type){HEAPU32[this.ptr+4>>>2>>>0]=type};this.get_type=function(){return HEAPU32[this.ptr+4>>>2>>>0]};this.set_destructor=function(destructor){HEAPU32[this.ptr+8>>>2>>>0]=destructor};this.get_destructor=function(){return HEAPU32[this.ptr+8>>>2>>>0]};this.set_caught=function(caught){caught=caught?1:0;HEAP8[this.ptr+12>>>0>>>0]=caught};this.get_caught=function(){return HEAP8[this.ptr+12>>>0>>>0]!=0};this.set_rethrown=function(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>>0>>>0]=rethrown};this.get_rethrown=function(){return HEAP8[this.ptr+13>>>0>>>0]!=0};this.init=function(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)};this.set_adjusted_ptr=function(adjustedPtr){HEAPU32[this.ptr+16>>>2>>>0]=adjustedPtr};this.get_adjusted_ptr=function(){return HEAPU32[this.ptr+16>>>2>>>0]};this.get_exception_ptr=function(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return HEAPU32[this.excPtr>>>2>>>0]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}var exceptionLast=0;var uncaughtExceptionCount=0;function ___cxa_throw(ptr,type,destructor){ptr>>>=0;type>>>=0;destructor>>>=0;var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast}var setErrNo=value=>{HEAP32[___errno_location()>>>2>>>0]=value;return value};var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:function(){var paths=Array.prototype.slice.call(arguments);return PATH.normalize(paths.join("/"))},join2:(l,r)=>PATH.normalize(l+"/"+r)};var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");var randomFillSync=crypto_module["randomFillSync"];if(randomFillSync){return view=>crypto_module["randomFillSync"](view)}var randomBytes=crypto_module["randomBytes"];return view=>(view.set(randomBytes(view.byteLength)),view)}catch(e){}}abort("initRandomDevice")};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{outIdx>>>=0;if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++>>>0]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++>>>0]=192|u>>6;heap[outIdx++>>>0]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++>>>0]=224|u>>12;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++>>>0]=240|u>>18;heap[outIdx++>>>0]=128|u>>12&63;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}}heap[outIdx>>>0]=0;return outIdx-startIdx};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(ENVIRONMENT_IS_NODE){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;var fd=process.stdin.fd;try{bytesRead=fs.readSync(fd,buf)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};var mmapAlloc=size=>{abort()};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir(node){var entries=[".",".."];for(var key of Object.keys(node.contents)){entries.push(key)}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length>>0)}return{ptr:ptr,allocated:allocated}},msync(stream,buffer,offset,length,mmapFlags){MEMFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};var asyncLoad=(url,onload,onerror,noRunDep)=>{var dep=!noRunDep?getUniqueRunDependency(`al ${url}`):"";readAsync(url,arrayBuffer=>{assert(arrayBuffer,`Loading data file "${url}" failed (no arrayBuffer).`);onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},event=>{if(onerror){onerror()}else{throw`Loading data file "${url}" failed.`}});if(dep)addRunDependency(dep)};var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>{FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn)};var preloadPlugins=Module["preloadPlugins"]||[];var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}onload?.();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,byteArray=>processData(byteArray),onerror)}else{processData(url)}};var FS_modeStringToFlags=str=>{var flagModes={"r":0,"r+":2,"w":512|64|1,"w+":512|64|2,"a":1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath(path,opts={}){path=PATH_FS.resolve(path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent}},hashName(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){if(!FS.FSStream){FS.FSStream=function(){this.shared={}};FS.FSStream.prototype={};Object.defineProperties(FS.FSStream.prototype,{object:{get(){return this.node},set(val){this.node=val}},isRead:{get(){return(this.flags&2097155)!==1}},isWrite:{get(){return(this.flags&2097155)!==0}},isAppend:{get(){return this.flags&1024}},flags:{get(){return this.shared.flags},set(val){this.shared.flags=val}},position:{get(){return this.shared.position},set(val){this.shared.position=val}}})}stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;i0,ioctl(stream,cmd,arg){if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile(path,opts={}){opts.flags=opts.flags||0;opts.encoding=opts.encoding||"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){throw new Error(`Invalid encoding type "${opts.encoding}"`)}var ret;var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){ret=UTF8ArrayToString(buf,0)}else if(opts.encoding==="binary"){ret=buf}FS.close(stream);return ret},writeFile(path,data,opts={}){opts.flags=opts.flags||577;var stream=FS.open(path,opts.flags,opts.mode);if(typeof data=="string"){var buf=new Uint8Array(lengthBytesUTF8(data)+1);var actualNumBytes=stringToUTF8Array(data,buf,0,buf.length);FS.write(stream,buf,0,actualNumBytes,undefined,opts.canOwn)}else if(ArrayBuffer.isView(data)){FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn)}else{throw new Error("Unsupported data type")}FS.close(stream)},cwd:()=>FS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams(){if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"])}else{FS.symlink("/dev/tty","/dev/stdin")}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"])}else{FS.symlink("/dev/tty","/dev/stdout")}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"])}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},ensureErrnoError(){if(FS.ErrnoError)return;FS.ErrnoError=function ErrnoError(errno,node){this.name="ErrnoError";this.node=node;this.setErrno=function(errno){this.errno=errno};this.setErrno(errno);this.message="FS error"};FS.ErrnoError.prototype=new Error;FS.ErrnoError.prototype.constructor=FS.ErrnoError;[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""})},staticInit(){FS.ensureErrnoError();FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS}},init(input,output,error){FS.init.initialized=true;FS.ensureErrnoError();Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit(){FS.init.initialized=false;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat(func,path,buf){try{var stat=func(path)}catch(e){if(e&&e.node&&PATH.normalize(path)!==PATH.normalize(FS.getPath(e.node))){return-54}throw e}HEAP32[buf>>>2>>>0]=stat.dev;HEAP32[buf+4>>>2>>>0]=stat.mode;HEAPU32[buf+8>>>2>>>0]=stat.nlink;HEAP32[buf+12>>>2>>>0]=stat.uid;HEAP32[buf+16>>>2>>>0]=stat.gid;HEAP32[buf+20>>>2>>>0]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+24>>>2>>>0]=tempI64[0],HEAP32[buf+28>>>2>>>0]=tempI64[1];HEAP32[buf+32>>>2>>>0]=4096;HEAP32[buf+36>>>2>>>0]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>>2>>>0]=tempI64[0],HEAP32[buf+44>>>2>>>0]=tempI64[1];HEAPU32[buf+48>>>2>>>0]=atime%1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>>2>>>0]=tempI64[0],HEAP32[buf+60>>>2>>>0]=tempI64[1];HEAPU32[buf+64>>>2>>>0]=mtime%1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>>2>>>0]=tempI64[0],HEAP32[buf+76>>>2>>>0]=tempI64[1];HEAPU32[buf+80>>>2>>>0]=ctime%1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>>2>>>0]=tempI64[0],HEAP32[buf+92>>>2>>>0]=tempI64[1];return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},varargs:undefined,get(){var ret=HEAP32[+SYSCALLS.varargs>>>2>>>0];SYSCALLS.varargs+=4;return ret},getp(){return SYSCALLS.get()},getStr(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream}};function ___syscall_fcntl64(fd,cmd,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.createStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 5:{var arg=SYSCALLS.getp();var offset=0;HEAP16[arg+offset>>>1>>>0]=2;return 0}case 6:case 7:return 0;case 16:case 8:return-28;case 9:setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fstat64(fd,buf){buf>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=SYSCALLS.getp();HEAP32[argp>>>2>>>0]=termios.c_iflag||0;HEAP32[argp+4>>>2>>>0]=termios.c_oflag||0;HEAP32[argp+8>>>2>>>0]=termios.c_cflag||0;HEAP32[argp+12>>>2>>>0]=termios.c_lflag||0;for(var i=0;i<32;i++){HEAP8[argp+i+17>>>0>>>0]=termios.c_cc[i]||0}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=SYSCALLS.getp();var c_iflag=HEAP32[argp>>>2>>>0];var c_oflag=HEAP32[argp+4>>>2>>>0];var c_cflag=HEAP32[argp+8>>>2>>>0];var c_lflag=HEAP32[argp+12>>>2>>>0];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(HEAP8[argp+i+17>>>0>>>0])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag:c_iflag,c_oflag:c_oflag,c_cflag:c_cflag,c_lflag:c_lflag,c_cc:c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.getp();HEAP32[argp>>>2>>>0]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.getp();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=SYSCALLS.getp();HEAP16[argp>>>1>>>0]=winsize[0];HEAP16[argp+2>>>1>>>0]=winsize[1]}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_lstat64(path,buf){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.lstat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_mkdirat(dirfd,path,mode){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_newfstatat(dirfd,path,buf,flags){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);var nofollow=flags&256;var allowEmpty=flags&4096;flags=flags&~6400;path=SYSCALLS.calculateAt(dirfd,path,allowEmpty);return SYSCALLS.doStat(nofollow?FS.lstat:FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){path>>>=0;varargs>>>=0;SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?SYSCALLS.get():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_stat64(path,buf){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var nowIsMonotonic=1;var __emscripten_get_now_is_monotonic=()=>nowIsMonotonic;var __emscripten_throw_longjmp=()=>{throw Infinity};var _abort=()=>{abort("")};var _emscripten_set_main_loop_timing=(mode,value)=>{Browser.mainLoop.timingMode=mode;Browser.mainLoop.timingValue=value;if(!Browser.mainLoop.func){return 1}if(!Browser.mainLoop.running){Browser.mainLoop.running=true}if(mode==0){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setTimeout(){var timeUntilNextTick=Math.max(0,Browser.mainLoop.tickStartTime+value-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,timeUntilNextTick)};Browser.mainLoop.method="timeout"}else if(mode==1){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_rAF(){Browser.requestAnimationFrame(Browser.mainLoop.runner)};Browser.mainLoop.method="rAF"}else if(mode==2){if(typeof Browser.setImmediate=="undefined"){if(typeof setImmediate=="undefined"){var setImmediates=[];var emscriptenMainLoopMessageId="setimmediate";var Browser_setImmediate_messageHandler=event=>{if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",Browser_setImmediate_messageHandler,true);Browser.setImmediate=function Browser_emulated_setImmediate(func){setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){if(Module["setImmediates"]===undefined)Module["setImmediates"]=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}else{Browser.setImmediate=setImmediate}}Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setImmediate(){Browser.setImmediate(Browser.mainLoop.runner)};Browser.mainLoop.method="immediate"}return 0};var _emscripten_get_now;_emscripten_get_now=()=>performance.now();var setMainLoop=(browserIterationFunc,fps,simulateInfiniteLoop,arg,noSetTiming)=>{assert(!Browser.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.");Browser.mainLoop.func=browserIterationFunc;Browser.mainLoop.arg=arg;var thisMainLoopId=Browser.mainLoop.currentlyRunningMainloop;function checkIsRunning(){if(thisMainLoopId0){var start=Date.now();var blocker=Browser.mainLoop.queue.shift();blocker.func(blocker.arg);if(Browser.mainLoop.remainingBlockers){var remaining=Browser.mainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){Browser.mainLoop.remainingBlockers=next}else{next=next+.5;Browser.mainLoop.remainingBlockers=(8*remaining+next)/9}}Browser.mainLoop.updateStatus();if(!checkIsRunning())return;setTimeout(Browser.mainLoop.runner,0);return}if(!checkIsRunning())return;Browser.mainLoop.currentFrameNumber=Browser.mainLoop.currentFrameNumber+1|0;if(Browser.mainLoop.timingMode==1&&Browser.mainLoop.timingValue>1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else if(Browser.mainLoop.timingMode==0){Browser.mainLoop.tickStartTime=_emscripten_get_now()}Browser.mainLoop.runIter(browserIterationFunc);if(!checkIsRunning())return;if(typeof SDL=="object")SDL.audio?.queueNewAudioData?.();Browser.mainLoop.scheduler()};if(!noSetTiming){if(fps&&fps>0){_emscripten_set_main_loop_timing(0,1e3/fps)}else{_emscripten_set_main_loop_timing(1,1)}Browser.mainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}};var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};var runtimeKeepaliveCounter=0;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true}quit_(code,new ExitStatus(code))};var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status)};var _exit=exitJS;var maybeExit=()=>{if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}};var callUserCallback=func=>{if(ABORT){return}try{func();maybeExit()}catch(e){handleException(e)}};var safeSetTimeout=(func,timeout)=>setTimeout(()=>{callUserCallback(func)},timeout);var warnOnce=text=>{warnOnce.shown||={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;if(ENVIRONMENT_IS_NODE)text="warning: "+text;err(text)}};var Browser={mainLoop:{running:false,scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause(){Browser.mainLoop.scheduler=null;Browser.mainLoop.currentlyRunningMainloop++},resume(){Browser.mainLoop.currentlyRunningMainloop++;var timingMode=Browser.mainLoop.timingMode;var timingValue=Browser.mainLoop.timingValue;var func=Browser.mainLoop.func;Browser.mainLoop.func=null;setMainLoop(func,0,false,Browser.mainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);Browser.mainLoop.scheduler()},updateStatus(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=Browser.mainLoop.remainingBlockers;var expected=Browser.mainLoop.expectedBlockers;if(remaining){if(remaining{assert(img.complete,`Image ${name} could not be decoded`);var canvas=document.createElement("canvas");canvas.width=img.width;canvas.height=img.height;var ctx=canvas.getContext("2d");ctx.drawImage(img,0,0);preloadedImages[name]=canvas;URL.revokeObjectURL(url);onload?.(byteArray)};img.onerror=event=>{err(`Image ${url} could not be decoded`);onerror?.()};img.src=url};preloadPlugins.push(imagePlugin);var audioPlugin={};audioPlugin["canHandle"]=function audioPlugin_canHandle(name){return!Module.noAudioDecoding&&name.substr(-4)in{".ogg":1,".wav":1,".mp3":1}};audioPlugin["handle"]=function audioPlugin_handle(byteArray,name,onload,onerror){var done=false;function finish(audio){if(done)return;done=true;preloadedAudios[name]=audio;onload?.(byteArray)}var b=new Blob([byteArray],{type:Browser.getMimetype(name)});var url=URL.createObjectURL(b);var audio=new Audio;audio.addEventListener("canplaythrough",()=>finish(audio),false);audio.onerror=function audio_onerror(event){if(done)return;err(`warning: browser could not fully decode audio ${name}, trying slower base64 approach`);function encode64(data){var BASE="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var PAD="=";var ret="";var leftchar=0;var leftbits=0;for(var i=0;i=6){var curr=leftchar>>leftbits-6&63;leftbits-=6;ret+=BASE[curr]}}if(leftbits==2){ret+=BASE[(leftchar&3)<<4];ret+=PAD+PAD}else if(leftbits==4){ret+=BASE[(leftchar&15)<<2];ret+=PAD}return ret}audio.src="data:audio/x-"+name.substr(-3)+";base64,"+encode64(byteArray);finish(audio)};audio.src=url;safeSetTimeout(()=>{finish(audio)},1e4)};preloadPlugins.push(audioPlugin);function pointerLockChange(){Browser.pointerLock=document["pointerLockElement"]===Module["canvas"]||document["mozPointerLockElement"]===Module["canvas"]||document["webkitPointerLockElement"]===Module["canvas"]||document["msPointerLockElement"]===Module["canvas"]}var canvas=Module["canvas"];if(canvas){canvas.requestPointerLock=canvas["requestPointerLock"]||canvas["mozRequestPointerLock"]||canvas["webkitRequestPointerLock"]||canvas["msRequestPointerLock"]||(()=>{});canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||(()=>{});canvas.exitPointerLock=canvas.exitPointerLock.bind(document);document.addEventListener("pointerlockchange",pointerLockChange,false);document.addEventListener("mozpointerlockchange",pointerLockChange,false);document.addEventListener("webkitpointerlockchange",pointerLockChange,false);document.addEventListener("mspointerlockchange",pointerLockChange,false);if(Module["elementPointerLock"]){canvas.addEventListener("click",ev=>{if(!Browser.pointerLock&&Module["canvas"].requestPointerLock){Module["canvas"].requestPointerLock();ev.preventDefault()}},false)}}},createContext(canvas,useWebGL,setInModule,webGLContextAttributes){if(useWebGL&&Module.ctx&&canvas==Module.canvas)return Module.ctx;var ctx;var contextHandle;if(useWebGL){var contextAttributes={antialias:false,alpha:false,majorVersion:2};if(webGLContextAttributes){for(var attribute in webGLContextAttributes){contextAttributes[attribute]=webGLContextAttributes[attribute]}}if(typeof GL!="undefined"){contextHandle=GL.createContext(canvas,contextAttributes);if(contextHandle){ctx=GL.getContext(contextHandle).GLctx}}}else{ctx=canvas.getContext("2d")}if(!ctx)return null;if(setInModule){if(!useWebGL)assert(typeof GLctx=="undefined","cannot set in module if GLctx is used, but we are a non-GL context that would replace it");Module.ctx=ctx;if(useWebGL)GL.makeContextCurrent(contextHandle);Module.useWebGL=useWebGL;Browser.moduleContextCreatedCallbacks.forEach(callback=>callback());Browser.init()}return ctx},destroyContext(canvas,useWebGL,setInModule){},fullscreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullscreen(lockPointer,resizeCanvas){Browser.lockPointer=lockPointer;Browser.resizeCanvas=resizeCanvas;if(typeof Browser.lockPointer=="undefined")Browser.lockPointer=true;if(typeof Browser.resizeCanvas=="undefined")Browser.resizeCanvas=false;var canvas=Module["canvas"];function fullscreenChange(){Browser.isFullscreen=false;var canvasContainer=canvas.parentNode;if((document["fullscreenElement"]||document["mozFullScreenElement"]||document["msFullscreenElement"]||document["webkitFullscreenElement"]||document["webkitCurrentFullScreenElement"])===canvasContainer){canvas.exitFullscreen=Browser.exitFullscreen;if(Browser.lockPointer)canvas.requestPointerLock();Browser.isFullscreen=true;if(Browser.resizeCanvas){Browser.setFullscreenCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}else{canvasContainer.parentNode.insertBefore(canvas,canvasContainer);canvasContainer.parentNode.removeChild(canvasContainer);if(Browser.resizeCanvas){Browser.setWindowedCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}Module["onFullScreen"]?.(Browser.isFullscreen);Module["onFullscreen"]?.(Browser.isFullscreen)}if(!Browser.fullscreenHandlersInstalled){Browser.fullscreenHandlersInstalled=true;document.addEventListener("fullscreenchange",fullscreenChange,false);document.addEventListener("mozfullscreenchange",fullscreenChange,false);document.addEventListener("webkitfullscreenchange",fullscreenChange,false);document.addEventListener("MSFullscreenChange",fullscreenChange,false)}var canvasContainer=document.createElement("div");canvas.parentNode.insertBefore(canvasContainer,canvas);canvasContainer.appendChild(canvas);canvasContainer.requestFullscreen=canvasContainer["requestFullscreen"]||canvasContainer["mozRequestFullScreen"]||canvasContainer["msRequestFullscreen"]||(canvasContainer["webkitRequestFullscreen"]?()=>canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"]):null)||(canvasContainer["webkitRequestFullScreen"]?()=>canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"]):null);canvasContainer.requestFullscreen()},exitFullscreen(){if(!Browser.isFullscreen){return false}var CFS=document["exitFullscreen"]||document["cancelFullScreen"]||document["mozCancelFullScreen"]||document["msExitFullscreen"]||document["webkitCancelFullScreen"]||(()=>{});CFS.apply(document,[]);return true},nextRAF:0,fakeRequestAnimationFrame(func){var now=Date.now();if(Browser.nextRAF===0){Browser.nextRAF=now+1e3/60}else{while(now+2>=Browser.nextRAF){Browser.nextRAF+=1e3/60}}var delay=Math.max(Browser.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame(func){if(typeof requestAnimationFrame=="function"){requestAnimationFrame(func);return}var RAF=Browser.fakeRequestAnimationFrame;RAF(func)},safeSetTimeout(func,timeout){return safeSetTimeout(func,timeout)},safeRequestAnimationFrame(func){return Browser.requestAnimationFrame(()=>{callUserCallback(func)})},getMimetype(name){return{"jpg":"image/jpeg","jpeg":"image/jpeg","png":"image/png","bmp":"image/bmp","ogg":"audio/ogg","wav":"audio/wav","mp3":"audio/mpeg"}[name.substr(name.lastIndexOf(".")+1)]},getUserMedia(func){window.getUserMedia||=navigator["getUserMedia"]||navigator["mozGetUserMedia"];window.getUserMedia(func)},getMovementX(event){return event["movementX"]||event["mozMovementX"]||event["webkitMovementX"]||0},getMovementY(event){return event["movementY"]||event["mozMovementY"]||event["webkitMovementY"]||0},getMouseWheelDelta(event){var delta=0;switch(event.type){case"DOMMouseScroll":delta=event.detail/3;break;case"mousewheel":delta=event.wheelDelta/120;break;case"wheel":delta=event.deltaY;switch(event.deltaMode){case 0:delta/=100;break;case 1:delta/=3;break;case 2:delta*=80;break;default:throw"unrecognized mouse wheel delta mode: "+event.deltaMode}break;default:throw"unrecognized mouse wheel event: "+event.type}return delta},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseCoords(pageX,pageY){var rect=Module["canvas"].getBoundingClientRect();var cw=Module["canvas"].width;var ch=Module["canvas"].height;var scrollX=typeof window.scrollX!="undefined"?window.scrollX:window.pageXOffset;var scrollY=typeof window.scrollY!="undefined"?window.scrollY:window.pageYOffset;var adjustedX=pageX-(scrollX+rect.left);var adjustedY=pageY-(scrollY+rect.top);adjustedX=adjustedX*(cw/rect.width);adjustedY=adjustedY*(ch/rect.height);return{x:adjustedX,y:adjustedY}},setMouseCoords(pageX,pageY){const{x:x,y:y}=Browser.calculateMouseCoords(pageX,pageY);Browser.mouseMovementX=x-Browser.mouseX;Browser.mouseMovementY=y-Browser.mouseY;Browser.mouseX=x;Browser.mouseY=y},calculateMouseEvent(event){if(Browser.pointerLock){if(event.type!="mousemove"&&"mozMovementX"in event){Browser.mouseMovementX=Browser.mouseMovementY=0}else{Browser.mouseMovementX=Browser.getMovementX(event);Browser.mouseMovementY=Browser.getMovementY(event)}if(typeof SDL!="undefined"){Browser.mouseX=SDL.mouseX+Browser.mouseMovementX;Browser.mouseY=SDL.mouseY+Browser.mouseMovementY}else{Browser.mouseX+=Browser.mouseMovementX;Browser.mouseY+=Browser.mouseMovementY}}else{if(event.type==="touchstart"||event.type==="touchend"||event.type==="touchmove"){var touch=event.touch;if(touch===undefined){return}var coords=Browser.calculateMouseCoords(touch.pageX,touch.pageY);if(event.type==="touchstart"){Browser.lastTouches[touch.identifier]=coords;Browser.touches[touch.identifier]=coords}else if(event.type==="touchend"||event.type==="touchmove"){var last=Browser.touches[touch.identifier];last||=coords;Browser.lastTouches[touch.identifier]=last;Browser.touches[touch.identifier]=coords}return}Browser.setMouseCoords(event.pageX,event.pageY)}},resizeListeners:[],updateResizeListeners(){var canvas=Module["canvas"];Browser.resizeListeners.forEach(listener=>listener(canvas.width,canvas.height))},setCanvasSize(width,height,noUpdates){var canvas=Module["canvas"];Browser.updateCanvasDimensions(canvas,width,height);if(!noUpdates)Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>>2>>>0];flags=flags|8388608;HEAP32[SDL.screen>>>2>>>0]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},setWindowedCanvasSize(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>>2>>>0];flags=flags&~8388608;HEAP32[SDL.screen>>>2>>>0]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},updateCanvasDimensions(canvas,wNative,hNative){if(wNative&&hNative){canvas.widthNative=wNative;canvas.heightNative=hNative}else{wNative=canvas.widthNative;hNative=canvas.heightNative}var w=wNative;var h=hNative;if(Module["forcedAspectRatio"]&&Module["forcedAspectRatio"]>0){if(w/h>>2>>>0];if(param==12321){var alphaSize=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.alpha=alphaSize>0}else if(param==12325){var depthSize=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.depth=depthSize>0}else if(param==12326){var stencilSize=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.stencil=stencilSize>0}else if(param==12337){var samples=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.antialias=samples>0}else if(param==12338){var samples=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.antialias=samples==1}else if(param==12544){var requestedPriority=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.lowLatency=requestedPriority!=12547}else if(param==12344){break}attribList+=8}}if((!config||!config_size)&&!numConfigs){EGL.setErrorCode(12300);return 0}if(numConfigs){HEAP32[numConfigs>>>2>>>0]=1}if(config&&config_size>0){HEAPU32[config>>>2>>>0]=62002}EGL.setErrorCode(12288);return 1}};function _eglChooseConfig(display,attrib_list,configs,config_size,numConfigs){display>>>=0;attrib_list>>>=0;configs>>>=0;numConfigs>>>=0;return EGL.chooseConfig(display,attrib_list,configs,config_size,numConfigs)}var webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance=ctx=>!!(ctx.dibvbi=ctx.getExtension("WEBGL_draw_instanced_base_vertex_base_instance"));var webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance=ctx=>!!(ctx.mdibvbi=ctx.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance"));var webgl_enable_WEBGL_multi_draw=ctx=>!!(ctx.multiDrawWebgl=ctx.getExtension("WEBGL_multi_draw"));var GL={counter:1,buffers:[],programs:[],framebuffers:[],renderbuffers:[],textures:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},queries:[],samplers:[],transformFeedbacks:[],syncs:[],stringCache:{},stringiCache:{},unpackAlignment:4,recordError:function recordError(errorCode){if(!GL.lastError){GL.lastError=errorCode}},getNewId:table=>{var ret=GL.counter++;for(var i=table.length;i{var source="";for(var i=0;i>>2>>>0]:-1;source+=UTF8ToString(HEAP32[string+i*4>>>2>>>0],len<0?undefined:len)}return source},createContext:(canvas,webGLContextAttributes)=>{if(!canvas.getContextSafariWebGL2Fixed){canvas.getContextSafariWebGL2Fixed=canvas.getContext;function fixedGetContext(ver,attrs){var gl=canvas.getContextSafariWebGL2Fixed(ver,attrs);return ver=="webgl"==gl instanceof WebGLRenderingContext?gl:null}canvas.getContext=fixedGetContext}var ctx=canvas.getContext("webgl2",webGLContextAttributes);if(!ctx)return 0;var handle=GL.registerContext(ctx,webGLContextAttributes);var _allSupportedExtensions=ctx.getSupportedExtensions;var supportedExtensionsForGetProcAddress=["EXT_color_buffer_float","EXT_disjoint_timer_query_webgl2","EXT_texture_norm16","WEBGL_clip_cull_distance","EXT_color_buffer_half_float","EXT_float_blend","EXT_texture_compression_bptc","EXT_texture_compression_rgtc","EXT_texture_filter_anisotropic","KHR_parallel_shader_compile","OES_texture_float_linear","WEBGL_compressed_texture_s3tc","WEBGL_compressed_texture_s3tc_srgb","WEBGL_debug_renderer_info","WEBGL_debug_shaders","WEBGL_lose_context","WEBGL_multi_draw"];ctx.getSupportedExtensions=function(){return(_allSupportedExtensions.apply(this)||[]).filter(ext=>supportedExtensionsForGetProcAddress.includes(ext))};return handle},registerContext:(ctx,webGLContextAttributes)=>{var handle=GL.getNewId(GL.contexts);var context={handle:handle,attributes:webGLContextAttributes,version:webGLContextAttributes.majorVersion,GLctx:ctx};if(ctx.canvas)ctx.canvas.GLctxObject=context;GL.contexts[handle]=context;if(typeof webGLContextAttributes.enableExtensionsByDefault=="undefined"||webGLContextAttributes.enableExtensionsByDefault){GL.initExtensions(context)}return handle},makeContextCurrent:contextHandle=>{GL.currentContext=GL.contexts[contextHandle];Module.ctx=GLctx=GL.currentContext?.GLctx;return!(contextHandle&&!GLctx)},getContext:contextHandle=>GL.contexts[contextHandle],deleteContext:contextHandle=>{if(GL.currentContext===GL.contexts[contextHandle]){GL.currentContext=null}if(typeof JSEvents=="object"){JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas)}if(GL.contexts[contextHandle]&&GL.contexts[contextHandle].GLctx.canvas){GL.contexts[contextHandle].GLctx.canvas.GLctxObject=undefined}GL.contexts[contextHandle]=null},initExtensions:context=>{context||=GL.currentContext;if(context.initExtensionsDone)return;context.initExtensionsDone=true;var GLctx=context.GLctx;webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);if(context.version>=2){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query_webgl2")}if(context.version<2||!GLctx.disjointTimerQueryExt){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query")}webgl_enable_WEBGL_multi_draw(GLctx);var exts=GLctx.getSupportedExtensions()||[];exts.forEach(ext=>{if(!ext.includes("lose_context")&&!ext.includes("debug")){GLctx.getExtension(ext)}})},getExtensions(){var exts=GLctx.getSupportedExtensions()||[];exts=exts.concat(exts.map(e=>"GL_"+e));return exts}};function _eglCreateContext(display,config,hmm,contextAttribs){display>>>=0;config>>>=0;hmm>>>=0;contextAttribs>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}var glesContextVersion=1;for(;;){var param=HEAP32[contextAttribs>>>2>>>0];if(param==12440){glesContextVersion=HEAP32[contextAttribs+4>>>2>>>0]}else if(param==12344){break}else{EGL.setErrorCode(12292);return 0}contextAttribs+=8}if(glesContextVersion<2||glesContextVersion>3){EGL.setErrorCode(12293);return 0}EGL.contextAttributes.majorVersion=glesContextVersion-1;EGL.contextAttributes.minorVersion=0;EGL.context=GL.createContext(Module["canvas"],EGL.contextAttributes);if(EGL.context!=0){EGL.setErrorCode(12288);GL.makeContextCurrent(EGL.context);Module.useWebGL=true;Browser.moduleContextCreatedCallbacks.forEach(function(callback){callback()});GL.makeContextCurrent(null);return 62004}else{EGL.setErrorCode(12297);return 0}}function _eglCreateWindowSurface(display,config,win,attrib_list){display>>>=0;config>>>=0;attrib_list>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(config!=62002){EGL.setErrorCode(12293);return 0}EGL.setErrorCode(12288);return 62006}function _eglDestroyContext(display,context){display>>>=0;context>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=62004){EGL.setErrorCode(12294);return 0}GL.deleteContext(EGL.context);EGL.setErrorCode(12288);if(EGL.currentContext==context){EGL.currentContext=0}return 1}function _eglDestroySurface(display,surface){display>>>=0;surface>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(surface!=62006){EGL.setErrorCode(12301);return 1}if(EGL.currentReadSurface==surface){EGL.currentReadSurface=0}if(EGL.currentDrawSurface==surface){EGL.currentDrawSurface=0}EGL.setErrorCode(12288);return 1}function _eglGetDisplay(nativeDisplayType){nativeDisplayType>>>=0;EGL.setErrorCode(12288);if(nativeDisplayType!=0&&nativeDisplayType!=1){return 0}return 62e3}function _eglInitialize(display,majorVersion,minorVersion){display>>>=0;majorVersion>>>=0;minorVersion>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(majorVersion){HEAP32[majorVersion>>>2>>>0]=1}if(minorVersion){HEAP32[minorVersion>>>2>>>0]=4}EGL.defaultDisplayInitialized=true;EGL.setErrorCode(12288);return 1}function _eglMakeCurrent(display,draw,read,context){display>>>=0;draw>>>=0;read>>>=0;context>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=0&&context!=62004){EGL.setErrorCode(12294);return 0}if(read!=0&&read!=62006||draw!=0&&draw!=62006){EGL.setErrorCode(12301);return 0}GL.makeContextCurrent(context?EGL.context:null);EGL.currentContext=context;EGL.currentDrawSurface=draw;EGL.currentReadSurface=read;EGL.setErrorCode(12288);return 1}function _eglSwapBuffers(dpy,surface){dpy>>>=0;surface>>>=0;if(!EGL.defaultDisplayInitialized){EGL.setErrorCode(12289)}else if(!Module.ctx){EGL.setErrorCode(12290)}else if(Module.ctx.isContextLost()){EGL.setErrorCode(12302)}else{EGL.setErrorCode(12288);return 1}return 0}function _eglSwapInterval(display,interval){display>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(interval==0)_emscripten_set_main_loop_timing(0,0);else _emscripten_set_main_loop_timing(1,interval);EGL.setErrorCode(12288);return 1}function _eglTerminate(display){display>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}EGL.currentContext=0;EGL.currentReadSurface=0;EGL.currentDrawSurface=0;EGL.defaultDisplayInitialized=false;EGL.setErrorCode(12288);return 1}var readEmAsmArgsArray=[];var readEmAsmArgs=(sigPtr,buf)=>{readEmAsmArgsArray.length=0;var ch;while(ch=HEAPU8[sigPtr++>>>0]){var wide=ch!=105;wide&=ch!=112;buf+=wide&&buf%8?4:0;readEmAsmArgsArray.push(ch==112?HEAPU32[buf>>>2>>>0]:ch==105?HEAP32[buf>>>2>>>0]:HEAPF64[buf>>>3>>>0]);buf+=wide?8:4}return readEmAsmArgsArray};var runEmAsmFunction=(code,sigPtr,argbuf)=>{var args=readEmAsmArgs(sigPtr,argbuf);return ASM_CONSTS[code].apply(null,args)};function _emscripten_asm_const_int(code,sigPtr,argbuf){code>>>=0;sigPtr>>>=0;argbuf>>>=0;return runEmAsmFunction(code,sigPtr,argbuf)}function _emscripten_asm_const_ptr(code,sigPtr,argbuf){code>>>=0;sigPtr>>>=0;argbuf>>>=0;return runEmAsmFunction(code,sigPtr,argbuf)}var _emscripten_cancel_main_loop=()=>{Browser.mainLoop.pause();Browser.mainLoop.func=null};var _emscripten_date_now=()=>Date.now();var JSEvents={inEventHandler:0,removeAllEventListeners(){for(var i=JSEvents.eventHandlers.length-1;i>=0;--i){JSEvents._removeHandler(i)}JSEvents.eventHandlers=[];JSEvents.deferredCalls=[]},registerRemoveEventListeners(){if(!JSEvents.removeEventListenersRegistered){__ATEXIT__.push(JSEvents.removeAllEventListeners);JSEvents.removeEventListenersRegistered=true}},deferredCalls:[],deferCall(targetFunction,precedence,argsList){function arraysHaveEqualContent(arrA,arrB){if(arrA.length!=arrB.length)return false;for(var i in arrA){if(arrA[i]!=arrB[i])return false}return true}for(var i in JSEvents.deferredCalls){var call=JSEvents.deferredCalls[i];if(call.targetFunction==targetFunction&&arraysHaveEqualContent(call.argsList,argsList)){return}}JSEvents.deferredCalls.push({targetFunction:targetFunction,precedence:precedence,argsList:argsList});JSEvents.deferredCalls.sort((x,y)=>x.precedence{for(var i=0;istringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var fillGamepadEventData=(eventStruct,e)=>{HEAPF64[eventStruct>>>3>>>0]=e.timestamp;for(var i=0;i>>3>>>0]=e.axes[i]}for(var i=0;i>>3>>>0]=e.buttons[i].value}else{HEAPF64[eventStruct+i*8+528>>>3>>>0]=e.buttons[i]}}for(var i=0;i>>2>>>0]=e.buttons[i].pressed}else{HEAP32[eventStruct+i*4+1040>>>2>>>0]=e.buttons[i]==1}}HEAP32[eventStruct+1296>>>2>>>0]=e.connected;HEAP32[eventStruct+1300>>>2>>>0]=e.index;HEAP32[eventStruct+8>>>2>>>0]=e.axes.length;HEAP32[eventStruct+12>>>2>>>0]=e.buttons.length;stringToUTF8(e.id,eventStruct+1304,64);stringToUTF8(e.mapping,eventStruct+1368,64)};function _emscripten_get_gamepad_status(index,gamepadState){gamepadState>>>=0;if(index<0||index>=JSEvents.lastGamepadState.length)return-5;if(!JSEvents.lastGamepadState[index])return-7;fillGamepadEventData(gamepadState,JSEvents.lastGamepadState[index]);return 0}function _emscripten_memcpy_js(dest,src,num){dest>>>=0;src>>>=0;num>>>=0;return HEAPU8.copyWithin(dest>>>0,src>>>0,src+num>>>0)}var getHeapMax=()=>4294901760;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};function _emscripten_resize_heap(requestedSize){requestedSize>>>=0;var oldSize=HEAPU8.length;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false}var disableGamepadApiIfItThrows=()=>{try{navigator.getGamepads()}catch(e){navigator.getGamepads=null;return 1}};var _emscripten_sample_gamepad_data=()=>{if(!navigator.getGamepads||disableGamepadApiIfItThrows())return-1;return(JSEvents.lastGamepadState=navigator.getGamepads())?0:-1};var maybeCStringToJsString=cString=>cString>2?UTF8ToString(cString):cString;var specialHTMLTargets=[0,typeof document!="undefined"?document:0,typeof window!="undefined"?window:0];var findEventTarget=target=>{target=maybeCStringToJsString(target);var domElement=specialHTMLTargets[target]||(typeof document!="undefined"?document.querySelector(target):undefined);return domElement};var registerFocusEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.focusEvent)JSEvents.focusEvent=_malloc(256);var focusEventHandlerFunc=(e=event)=>{var nodeName=JSEvents.getNodeNameForTarget(e.target);var id=e.target.id?e.target.id:"";var focusEvent=JSEvents.focusEvent;stringToUTF8(nodeName,focusEvent+0,128);stringToUTF8(id,focusEvent+128,128);if(getWasmTableEntry(callbackfunc)(eventTypeId,focusEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:focusEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_blur_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerFocusEventCallback(target,userData,useCapture,callbackfunc,12,"blur",targetThread)}var findCanvasEventTarget=target=>findEventTarget(target);function _emscripten_set_canvas_element_size(target,width,height){target>>>=0;var canvas=findCanvasEventTarget(target);if(!canvas)return-4;canvas.width=width;canvas.height=height;return 0}function _emscripten_set_focus_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerFocusEventCallback(target,userData,useCapture,callbackfunc,13,"focus",targetThread)}var registerGamepadEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.gamepadEvent)JSEvents.gamepadEvent=_malloc(1432);var gamepadEventHandlerFunc=(e=event)=>{var gamepadEvent=JSEvents.gamepadEvent;fillGamepadEventData(gamepadEvent,e["gamepad"]);if(getWasmTableEntry(callbackfunc)(eventTypeId,gamepadEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:gamepadEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_gamepadconnected_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!navigator.getGamepads||disableGamepadApiIfItThrows())return-1;return registerGamepadEventCallback(2,userData,useCapture,callbackfunc,26,"gamepadconnected",targetThread)}function _emscripten_set_gamepaddisconnected_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!navigator.getGamepads||disableGamepadApiIfItThrows())return-1;return registerGamepadEventCallback(2,userData,useCapture,callbackfunc,27,"gamepaddisconnected",targetThread)}var registerKeyEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.keyEvent)JSEvents.keyEvent=_malloc(176);var keyEventHandlerFunc=e=>{var keyEventData=JSEvents.keyEvent;HEAPF64[keyEventData>>>3>>>0]=e.timeStamp;var idx=keyEventData>>>2;HEAP32[idx+2>>>0]=e.location;HEAP32[idx+3>>>0]=e.ctrlKey;HEAP32[idx+4>>>0]=e.shiftKey;HEAP32[idx+5>>>0]=e.altKey;HEAP32[idx+6>>>0]=e.metaKey;HEAP32[idx+7>>>0]=e.repeat;HEAP32[idx+8>>>0]=e.charCode;HEAP32[idx+9>>>0]=e.keyCode;HEAP32[idx+10>>>0]=e.which;stringToUTF8(e.key||"",keyEventData+44,32);stringToUTF8(e.code||"",keyEventData+76,32);stringToUTF8(e.char||"",keyEventData+108,32);stringToUTF8(e.locale||"",keyEventData+140,32);if(getWasmTableEntry(callbackfunc)(eventTypeId,keyEventData,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:keyEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_keydown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerKeyEventCallback(target,userData,useCapture,callbackfunc,2,"keydown",targetThread)}function _emscripten_set_keyup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerKeyEventCallback(target,userData,useCapture,callbackfunc,3,"keyup",targetThread)}function _emscripten_set_main_loop(func,fps,simulateInfiniteLoop){func>>>=0;var browserIterationFunc=getWasmTableEntry(func);setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop)}var getBoundingClientRect=e=>specialHTMLTargets.indexOf(e)<0?e.getBoundingClientRect():{"left":0,"top":0};var fillMouseEventData=(eventStruct,e,target)=>{HEAPF64[eventStruct>>>3>>>0]=e.timeStamp;var idx=eventStruct>>>2;HEAP32[idx+2>>>0]=e.screenX;HEAP32[idx+3>>>0]=e.screenY;HEAP32[idx+4>>>0]=e.clientX;HEAP32[idx+5>>>0]=e.clientY;HEAP32[idx+6>>>0]=e.ctrlKey;HEAP32[idx+7>>>0]=e.shiftKey;HEAP32[idx+8>>>0]=e.altKey;HEAP32[idx+9>>>0]=e.metaKey;HEAP16[idx*2+20>>>0]=e.button;HEAP16[idx*2+21>>>0]=e.buttons;HEAP32[idx+11>>>0]=e["movementX"];HEAP32[idx+12>>>0]=e["movementY"];var rect=getBoundingClientRect(target);HEAP32[idx+13>>>0]=e.clientX-rect.left;HEAP32[idx+14>>>0]=e.clientY-rect.top};var registerMouseEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.mouseEvent)JSEvents.mouseEvent=_malloc(72);target=findEventTarget(target);var mouseEventHandlerFunc=(e=event)=>{fillMouseEventData(JSEvents.mouseEvent,e,target);if(getWasmTableEntry(callbackfunc)(eventTypeId,JSEvents.mouseEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:eventTypeString!="mousemove"&&eventTypeString!="mouseenter"&&eventTypeString!="mouseleave",eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:mouseEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_mousedown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,5,"mousedown",targetThread)}function _emscripten_set_mousemove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,8,"mousemove",targetThread)}function _emscripten_set_mouseup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,6,"mouseup",targetThread)}var registerTouchEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.touchEvent)JSEvents.touchEvent=_malloc(1696);target=findEventTarget(target);var touchEventHandlerFunc=e=>{var t,touches={},et=e.touches;for(var i=0;i>>3>>>0]=e.timeStamp;var idx=touchEvent>>>2;HEAP32[idx+3>>>0]=e.ctrlKey;HEAP32[idx+4>>>0]=e.shiftKey;HEAP32[idx+5>>>0]=e.altKey;HEAP32[idx+6>>>0]=e.metaKey;idx+=7;var targetRect=getBoundingClientRect(target);var numTouches=0;for(var i in touches){t=touches[i];HEAP32[idx+0>>>0]=t.identifier;HEAP32[idx+1>>>0]=t.screenX;HEAP32[idx+2>>>0]=t.screenY;HEAP32[idx+3>>>0]=t.clientX;HEAP32[idx+4>>>0]=t.clientY;HEAP32[idx+5>>>0]=t.pageX;HEAP32[idx+6>>>0]=t.pageY;HEAP32[idx+7>>>0]=t.isChanged;HEAP32[idx+8>>>0]=t.onTarget;HEAP32[idx+9>>>0]=t.clientX-targetRect.left;HEAP32[idx+10>>>0]=t.clientY-targetRect.top;idx+=13;if(++numTouches>31){break}}HEAP32[touchEvent+8>>>2>>>0]=numTouches;if(getWasmTableEntry(callbackfunc)(eventTypeId,touchEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:eventTypeString=="touchstart"||eventTypeString=="touchend",eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:touchEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_touchend_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,23,"touchend",targetThread)}function _emscripten_set_touchmove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,24,"touchmove",targetThread)}function _emscripten_set_touchstart_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,22,"touchstart",targetThread)}var registerWheelEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.wheelEvent)JSEvents.wheelEvent=_malloc(104);var wheelHandlerFunc=(e=event)=>{var wheelEvent=JSEvents.wheelEvent;fillMouseEventData(wheelEvent,e,target);HEAPF64[wheelEvent+72>>>3>>>0]=e["deltaX"];HEAPF64[wheelEvent+80>>>3>>>0]=e["deltaY"];HEAPF64[wheelEvent+88>>>3>>>0]=e["deltaZ"];HEAP32[wheelEvent+96>>>2>>>0]=e["deltaMode"];if(getWasmTableEntry(callbackfunc)(eventTypeId,wheelEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:wheelHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};function _emscripten_set_wheel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;target=findEventTarget(target);if(!target)return-4;if(typeof target.onwheel!="undefined"){return registerWheelEventCallback(target,userData,useCapture,callbackfunc,9,"wheel",targetThread)}else{return-1}}function _emscripten_set_window_title(title){title>>>=0;return document.title=UTF8ToString(title)}var ENV={};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i>>0>>>0]=str.charCodeAt(i)}HEAP8[buffer>>>0>>>0]=0};var _environ_get=function(__environ,environ_buf){__environ>>>=0;environ_buf>>>=0;var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>>2>>>0]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0};var _environ_sizes_get=function(penviron_count,penviron_buf_size){penviron_count>>>=0;penviron_buf_size>>>=0;var strings=getEnvStrings();HEAPU32[penviron_count>>>2>>>0]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>>2>>>0]=bufSize;return 0};function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doReadv(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);newOffset>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>>2>>>0]=tempI64[0],HEAP32[newOffset+4>>>2>>>0]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(typeof offset!=="undefined"){offset+=curr}}return ret};function _fd_write(fd,iov,iovcnt,pnum){iov>>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _getentropy(buffer,size){buffer>>>=0;size>>>=0;randomFill(HEAPU8.subarray(buffer>>>0,buffer+size>>>0));return 0}var _glAttachShader=(program,shader)=>{GLctx.attachShader(GL.programs[program],GL.shaders[shader])};var _glBindBuffer=(target,buffer)=>{if(target==35051){GLctx.currentPixelPackBufferBinding=buffer}else if(target==35052){GLctx.currentPixelUnpackBufferBinding=buffer}GLctx.bindBuffer(target,GL.buffers[buffer])};var _glBindTexture=(target,texture)=>{GLctx.bindTexture(target,GL.textures[texture])};var _glBindVertexArray=vao=>{GLctx.bindVertexArray(GL.vaos[vao])};var _glBindVertexArrayOES=_glBindVertexArray;function _glBlendFunc(x0,x1){GLctx.blendFunc(x0,x1)}function _glBufferData(target,size,data,usage){size>>>=0;data>>>=0;if(true){if(data&&size){GLctx.bufferData(target,HEAPU8,usage,data,size)}else{GLctx.bufferData(target,size,usage)}}else{GLctx.bufferData(target,data?HEAPU8.subarray(data>>>0,data+size>>>0):size,usage)}}function _glClear(x0){GLctx.clear(x0)}function _glClearColor(x0,x1,x2,x3){GLctx.clearColor(x0,x1,x2,x3)}var _glCompileShader=shader=>{GLctx.compileShader(GL.shaders[shader])};var _glCreateProgram=()=>{var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;program.maxUniformLength=program.maxAttributeLength=program.maxUniformBlockNameLength=0;program.uniformIdCounter=1;GL.programs[id]=program;return id};var _glCreateShader=shaderType=>{var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id};var _glDeleteProgram=id=>{if(!id)return;var program=GL.programs[id];if(!program){GL.recordError(1281);return}GLctx.deleteProgram(program);program.name=0;GL.programs[id]=null};var _glDeleteShader=id=>{if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null};function _glDeleteTextures(n,textures){textures>>>=0;for(var i=0;i>>2>>>0];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}var _glDrawArrays=(mode,first,count)=>{GLctx.drawArrays(mode,first,count)};function _glEnable(x0){GLctx.enable(x0)}var _glEnableVertexAttribArray=index=>{GLctx.enableVertexAttribArray(index)};var __glGenObject=(n,buffers,createFunction,objectTable)=>{for(var i=0;i>>2>>>0]=id}};function _glGenBuffers(n,buffers){buffers>>>=0;__glGenObject(n,buffers,"createBuffer",GL.buffers)}function _glGenTextures(n,textures){textures>>>=0;__glGenObject(n,textures,"createTexture",GL.textures)}function _glGenVertexArrays(n,arrays){arrays>>>=0;__glGenObject(n,arrays,"createVertexArray",GL.vaos)}var _glGenVertexArraysOES=_glGenVertexArrays;function _glGetShaderInfoLog(shader,maxLength,length,infoLog){length>>>=0;infoLog>>>=0;var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}var _glLinkProgram=program=>{program=GL.programs[program];GLctx.linkProgram(program);program.uniformLocsById=0;program.uniformSizeAndIdsByName={}};var computeUnpackAlignedImageSize=(width,height,sizePerPixel,alignment)=>{function roundedToNextMultipleOf(x,y){return x+y-1&-y}var plainRowSize=width*sizePerPixel;var alignedRowSize=roundedToNextMultipleOf(plainRowSize,alignment);return height*alignedRowSize};var colorChannelsInGlTextureFormat=format=>{var colorChannels={5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4};return colorChannels[format-6402]||1};var heapObjectForWebGLType=type=>{type-=5120;if(type==0)return HEAP8;if(type==1)return HEAPU8;if(type==2)return HEAP16;if(type==4)return HEAP32;if(type==6)return HEAPF32;if(type==5||type==28922||type==28520||type==30779||type==30782)return HEAPU32;return HEAPU16};var heapAccessShiftForWebGLHeap=heap=>31-Math.clz32(heap.BYTES_PER_ELEMENT);var emscriptenWebGLGetTexPixelData=(type,format,width,height,pixels,internalFormat)=>{var heap=heapObjectForWebGLType(type);var shift=heapAccessShiftForWebGLHeap(heap);var byteSize=1<>>shift,pixels+bytes>>>shift)};function _glReadPixels(x,y,width,height,format,type,pixels){pixels>>>=0;if(true){if(GLctx.currentPixelPackBufferBinding){GLctx.readPixels(x,y,width,height,format,type,pixels)}else{var heap=heapObjectForWebGLType(type);GLctx.readPixels(x,y,width,height,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}return}var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,format);if(!pixelData){GL.recordError(1280);return}GLctx.readPixels(x,y,width,height,format,type,pixelData)}function _glShaderSource(shader,count,string,length){string>>>=0;length>>>=0;var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}function _glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){pixels>>>=0;if(true){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,null)}return}GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null)}function _glTexParameteri(x0,x1,x2){GLctx.texParameteri(x0,x1,x2)}var _glUseProgram=program=>{program=GL.programs[program];GLctx.useProgram(program);GLctx.currentProgram=program};function _glVertexAttribPointer(index,size,type,normalized,stride,ptr){ptr>>>=0;GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}function _glViewport(x0,x1,x2,x3){GLctx.viewport(x0,x1,x2,x3)}var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var arraySum=(array,index)=>{var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum};var MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];var addDays=(date,days)=>{var newDate=new Date(date.getTime());while(days>0){var leap=isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer>>>0)};function _strftime(s,maxsize,format,tm){s>>>=0;maxsize>>>=0;format>>>=0;tm>>>=0;var tm_zone=HEAPU32[tm+40>>>2>>>0];var date={tm_sec:HEAP32[tm>>>2>>>0],tm_min:HEAP32[tm+4>>>2>>>0],tm_hour:HEAP32[tm+8>>>2>>>0],tm_mday:HEAP32[tm+12>>>2>>>0],tm_mon:HEAP32[tm+16>>>2>>>0],tm_year:HEAP32[tm+20>>>2>>>0],tm_wday:HEAP32[tm+24>>>2>>>0],tm_yday:HEAP32[tm+28>>>2>>>0],tm_isdst:HEAP32[tm+32>>>2>>>0],tm_gmtoff:HEAP32[tm+36>>>2>>>0],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value=="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}return thisDate.getFullYear()}return thisDate.getFullYear()-1}var EXPANSION_RULES_2={"%a":date=>WEEKDAYS[date.tm_wday].substring(0,3),"%A":date=>WEEKDAYS[date.tm_wday],"%b":date=>MONTHS[date.tm_mon].substring(0,3),"%B":date=>MONTHS[date.tm_mon],"%C":date=>{var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":date=>leadingNulls(date.tm_mday,2),"%e":date=>leadingSomething(date.tm_mday,2," "),"%g":date=>getWeekBasedYear(date).toString().substring(2),"%G":date=>getWeekBasedYear(date),"%H":date=>leadingNulls(date.tm_hour,2),"%I":date=>{var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":date=>leadingNulls(date.tm_mday+arraySum(isLeapYear(date.tm_year+1900)?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,date.tm_mon-1),3),"%m":date=>leadingNulls(date.tm_mon+1,2),"%M":date=>leadingNulls(date.tm_min,2),"%n":()=>"\n","%p":date=>{if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}return"PM"},"%S":date=>leadingNulls(date.tm_sec,2),"%t":()=>"\t","%u":date=>date.tm_wday||7,"%U":date=>{var days=date.tm_yday+7-date.tm_wday;return leadingNulls(Math.floor(days/7),2)},"%V":date=>{var val=Math.floor((date.tm_yday+7-(date.tm_wday+6)%7)/7);if((date.tm_wday+371-date.tm_yday-2)%7<=2){val++}if(!val){val=52;var dec31=(date.tm_wday+7-date.tm_yday-1)%7;if(dec31==4||dec31==5&&isLeapYear(date.tm_year%400-1)){val++}}else if(val==53){var jan1=(date.tm_wday+371-date.tm_yday)%7;if(jan1!=4&&(jan1!=3||!isLeapYear(date.tm_year)))val=1}return leadingNulls(val,2)},"%w":date=>date.tm_wday,"%W":date=>{var days=date.tm_yday+7-(date.tm_wday+6)%7;return leadingNulls(Math.floor(days/7),2)},"%y":date=>(date.tm_year+1900).toString().substring(2),"%Y":date=>date.tm_year+1900,"%z":date=>{var off=date.tm_gmtoff;var ahead=off>=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":date=>date.tm_zone,"%%":()=>"%"};pattern=pattern.replace(/%%/g,"\0\0");for(var rule in EXPANSION_RULES_2){if(pattern.includes(rule)){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}pattern=pattern.replace(/\0\0/g,"%");var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm,loc){s>>>=0;maxsize>>>=0;format>>>=0;tm>>>=0;loc>>>=0;return _strftime(s,maxsize,format,tm)}var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();Module["FS_createPath"]=FS.createPath;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_unlink"]=FS.unlink;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createDevice"]=FS.createDevice;Module["requestFullscreen"]=Browser.requestFullscreen;Module["requestAnimationFrame"]=Browser.requestAnimationFrame;Module["setCanvasSize"]=Browser.setCanvasSize;Module["pauseMainLoop"]=Browser.mainLoop.pause;Module["resumeMainLoop"]=Browser.mainLoop.resume;Module["getUserMedia"]=Browser.getUserMedia;Module["createContext"]=Browser.createContext;var preloadedImages={};var preloadedAudios={};var GLctx;var wasmImports={__assert_fail:___assert_fail,__cxa_throw:___cxa_throw,__syscall_fcntl64:___syscall_fcntl64,__syscall_fstat64:___syscall_fstat64,__syscall_ioctl:___syscall_ioctl,__syscall_lstat64:___syscall_lstat64,__syscall_mkdirat:___syscall_mkdirat,__syscall_newfstatat:___syscall_newfstatat,__syscall_openat:___syscall_openat,__syscall_stat64:___syscall_stat64,_emscripten_get_now_is_monotonic:__emscripten_get_now_is_monotonic,_emscripten_throw_longjmp:__emscripten_throw_longjmp,abort:_abort,eglChooseConfig:_eglChooseConfig,eglCreateContext:_eglCreateContext,eglCreateWindowSurface:_eglCreateWindowSurface,eglDestroyContext:_eglDestroyContext,eglDestroySurface:_eglDestroySurface,eglGetDisplay:_eglGetDisplay,eglInitialize:_eglInitialize,eglMakeCurrent:_eglMakeCurrent,eglSwapBuffers:_eglSwapBuffers,eglSwapInterval:_eglSwapInterval,eglTerminate:_eglTerminate,emscripten_asm_const_int:_emscripten_asm_const_int,emscripten_asm_const_ptr:_emscripten_asm_const_ptr,emscripten_cancel_main_loop:_emscripten_cancel_main_loop,emscripten_date_now:_emscripten_date_now,emscripten_get_gamepad_status:_emscripten_get_gamepad_status,emscripten_get_now:_emscripten_get_now,emscripten_memcpy_js:_emscripten_memcpy_js,emscripten_resize_heap:_emscripten_resize_heap,emscripten_sample_gamepad_data:_emscripten_sample_gamepad_data,emscripten_set_blur_callback_on_thread:_emscripten_set_blur_callback_on_thread,emscripten_set_canvas_element_size:_emscripten_set_canvas_element_size,emscripten_set_focus_callback_on_thread:_emscripten_set_focus_callback_on_thread,emscripten_set_gamepadconnected_callback_on_thread:_emscripten_set_gamepadconnected_callback_on_thread,emscripten_set_gamepaddisconnected_callback_on_thread:_emscripten_set_gamepaddisconnected_callback_on_thread,emscripten_set_keydown_callback_on_thread:_emscripten_set_keydown_callback_on_thread,emscripten_set_keyup_callback_on_thread:_emscripten_set_keyup_callback_on_thread,emscripten_set_main_loop:_emscripten_set_main_loop,emscripten_set_mousedown_callback_on_thread:_emscripten_set_mousedown_callback_on_thread,emscripten_set_mousemove_callback_on_thread:_emscripten_set_mousemove_callback_on_thread,emscripten_set_mouseup_callback_on_thread:_emscripten_set_mouseup_callback_on_thread,emscripten_set_touchend_callback_on_thread:_emscripten_set_touchend_callback_on_thread,emscripten_set_touchmove_callback_on_thread:_emscripten_set_touchmove_callback_on_thread,emscripten_set_touchstart_callback_on_thread:_emscripten_set_touchstart_callback_on_thread,emscripten_set_wheel_callback_on_thread:_emscripten_set_wheel_callback_on_thread,emscripten_set_window_title:_emscripten_set_window_title,environ_get:_environ_get,environ_sizes_get:_environ_sizes_get,fd_close:_fd_close,fd_read:_fd_read,fd_seek:_fd_seek,fd_write:_fd_write,getentropy:_getentropy,glAttachShader:_glAttachShader,glBindBuffer:_glBindBuffer,glBindTexture:_glBindTexture,glBindVertexArrayOES:_glBindVertexArrayOES,glBlendFunc:_glBlendFunc,glBufferData:_glBufferData,glClear:_glClear,glClearColor:_glClearColor,glCompileShader:_glCompileShader,glCreateProgram:_glCreateProgram,glCreateShader:_glCreateShader,glDeleteProgram:_glDeleteProgram,glDeleteShader:_glDeleteShader,glDeleteTextures:_glDeleteTextures,glDrawArrays:_glDrawArrays,glEnable:_glEnable,glEnableVertexAttribArray:_glEnableVertexAttribArray,glGenBuffers:_glGenBuffers,glGenTextures:_glGenTextures,glGenVertexArraysOES:_glGenVertexArraysOES,glGetShaderInfoLog:_glGetShaderInfoLog,glLinkProgram:_glLinkProgram,glReadPixels:_glReadPixels,glShaderSource:_glShaderSource,glTexImage2D:_glTexImage2D,glTexParameteri:_glTexParameteri,glUseProgram:_glUseProgram,glVertexAttribPointer:_glVertexAttribPointer,glViewport:_glViewport,invoke_ii:invoke_ii,invoke_iii:invoke_iii,invoke_iiii:invoke_iiii,invoke_iiiii:invoke_iiiii,invoke_vi:invoke_vi,invoke_vii:invoke_vii,invoke_viii:invoke_viii,invoke_viiii:invoke_viiii,invoke_viiiiii:invoke_viiiiii,strftime_l:_strftime_l};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["__wasm_call_ctors"])();var _malloc=a0=>(_malloc=wasmExports["malloc"])(a0);var _main=Module["_main"]=(a0,a1)=>(_main=Module["_main"]=wasmExports["main"])(a0,a1);var _olc_OnPageUnload=Module["_olc_OnPageUnload"]=()=>(_olc_OnPageUnload=Module["_olc_OnPageUnload"]=wasmExports["olc_OnPageUnload"])();var _olc_PGE_UpdateWindowSize=Module["_olc_PGE_UpdateWindowSize"]=(a0,a1)=>(_olc_PGE_UpdateWindowSize=Module["_olc_PGE_UpdateWindowSize"]=wasmExports["olc_PGE_UpdateWindowSize"])(a0,a1);var ___errno_location=()=>(___errno_location=wasmExports["__errno_location"])();var _ma_malloc_emscripten=Module["_ma_malloc_emscripten"]=(a0,a1)=>(_ma_malloc_emscripten=Module["_ma_malloc_emscripten"]=wasmExports["ma_malloc_emscripten"])(a0,a1);var _ma_free_emscripten=Module["_ma_free_emscripten"]=(a0,a1)=>(_ma_free_emscripten=Module["_ma_free_emscripten"]=wasmExports["ma_free_emscripten"])(a0,a1);var _ma_device_process_pcm_frames_capture__webaudio=Module["_ma_device_process_pcm_frames_capture__webaudio"]=(a0,a1,a2)=>(_ma_device_process_pcm_frames_capture__webaudio=Module["_ma_device_process_pcm_frames_capture__webaudio"]=wasmExports["ma_device_process_pcm_frames_capture__webaudio"])(a0,a1,a2);var _ma_device_process_pcm_frames_playback__webaudio=Module["_ma_device_process_pcm_frames_playback__webaudio"]=(a0,a1,a2)=>(_ma_device_process_pcm_frames_playback__webaudio=Module["_ma_device_process_pcm_frames_playback__webaudio"]=wasmExports["ma_device_process_pcm_frames_playback__webaudio"])(a0,a1,a2);var setTempRet0=a0=>(setTempRet0=wasmExports["setTempRet0"])(a0);var _setThrew=(a0,a1)=>(_setThrew=wasmExports["setThrew"])(a0,a1);var stackSave=()=>(stackSave=wasmExports["stackSave"])();var stackRestore=a0=>(stackRestore=wasmExports["stackRestore"])(a0);var stackAlloc=a0=>(stackAlloc=wasmExports["stackAlloc"])(a0);var ___cxa_is_pointer_type=a0=>(___cxa_is_pointer_type=wasmExports["__cxa_is_pointer_type"])(a0);var dynCall_iiji=Module["dynCall_iiji"]=(a0,a1,a2,a3,a4)=>(dynCall_iiji=Module["dynCall_iiji"]=wasmExports["dynCall_iiji"])(a0,a1,a2,a3,a4);var dynCall_iiiji=Module["dynCall_iiiji"]=(a0,a1,a2,a3,a4,a5)=>(dynCall_iiiji=Module["dynCall_iiiji"]=wasmExports["dynCall_iiiji"])(a0,a1,a2,a3,a4,a5);var dynCall_viijii=Module["dynCall_viijii"]=(a0,a1,a2,a3,a4,a5,a6)=>(dynCall_viijii=Module["dynCall_viijii"]=wasmExports["dynCall_viijii"])(a0,a1,a2,a3,a4,a5,a6);var dynCall_iij=Module["dynCall_iij"]=(a0,a1,a2,a3)=>(dynCall_iij=Module["dynCall_iij"]=wasmExports["dynCall_iij"])(a0,a1,a2,a3);var dynCall_jii=Module["dynCall_jii"]=(a0,a1,a2)=>(dynCall_jii=Module["dynCall_jii"]=wasmExports["dynCall_jii"])(a0,a1,a2);var dynCall_jiji=Module["dynCall_jiji"]=(a0,a1,a2,a3,a4)=>(dynCall_jiji=Module["dynCall_jiji"]=wasmExports["dynCall_jiji"])(a0,a1,a2,a3,a4);var dynCall_iiiiij=Module["dynCall_iiiiij"]=(a0,a1,a2,a3,a4,a5,a6)=>(dynCall_iiiiij=Module["dynCall_iiiiij"]=wasmExports["dynCall_iiiiij"])(a0,a1,a2,a3,a4,a5,a6);var dynCall_iiiiijj=Module["dynCall_iiiiijj"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(dynCall_iiiiijj=Module["dynCall_iiiiijj"]=wasmExports["dynCall_iiiiijj"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)=>(dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=wasmExports["dynCall_iiiiiijj"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);function invoke_iiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_ii(index,a1){var sp=stackSave();try{return getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iii(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vii(index,a1,a2){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vi(index,a1){var sp=stackSave();try{getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viii(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiii(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function applySignatureConversions(wasmExports){wasmExports=Object.assign({},wasmExports);var makeWrapper_pp=f=>a0=>f(a0)>>>0;var makeWrapper_p=f=>()=>f()>>>0;wasmExports["malloc"]=makeWrapper_pp(wasmExports["malloc"]);wasmExports["__errno_location"]=makeWrapper_p(wasmExports["__errno_location"]);wasmExports["stackSave"]=makeWrapper_p(wasmExports["stackSave"]);wasmExports["stackAlloc"]=makeWrapper_pp(wasmExports["stackAlloc"]);return wasmExports}Module["addRunDependency"]=addRunDependency;Module["removeRunDependency"]=removeRunDependency;Module["FS_createPath"]=FS.createPath;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createDevice"]=FS.createDevice;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_unlink"]=FS.unlink;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(){var entryFunction=_main;var argc=0;var argv=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(shouldRunNow)callMain();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run(); diff --git a/Adventures in Lestoria/Adventures in Lestoria.wasm b/Adventures in Lestoria/Adventures in Lestoria.wasm new file mode 100755 index 00000000..0c4f7e9d Binary files /dev/null and b/Adventures in Lestoria/Adventures in Lestoria.wasm differ diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp index f5a7fb59..b37b22d4 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.cpp +++ b/Adventures in Lestoria/AdventuresInLestoria.cpp @@ -1462,7 +1462,6 @@ void AiL::RenderHud(){ if(!ISBLANK(GetLoadoutItem(0))){ DrawShadowStringDecal({0,92},"Loadout Slot 1 Qty: "+std::to_string(GetLoadoutItem(0).lock()->Amt())); } - DrawShadowStringDecal({0,1},"Selection: "+Menu::menus[INVENTORY_CONSUMABLES]->selection.str()); DrawShadowStringDecal({0,12},"Button Hold Time: "+std::to_string(Menu::menus[INVENTORY_CONSUMABLES]->buttonHoldTime)); } #endif @@ -2077,7 +2076,7 @@ void AiL::ChangePlayerClass(Class cl){ uint8_t levelCap=player->levelCap; uint32_t totalXPEarned=player->totalXPEarned; uint32_t currentLevelXP=player->currentLevelXP; - std::setmoneyListeners=Player::moneyListeners; + std::vector>moneyListeners=Player::moneyListeners; EntityStats previousStats=player->stats; size_t cooldownSoundInstance=player->cooldownSoundInstance; switch(cl){ @@ -2549,12 +2548,6 @@ const MapName&AiL::GetCurrentMapName()const{ } void AiL::ValidateGameStatus(){ - if(IToggleable::uninitializedToggleGroupItems.size()>0){ - for(IToggleable*item:IToggleable::uninitializedToggleGroupItems){ - std::cout<<"\tUninitialized Toggle Item Ptr: 0x"<chapter=chapter; - for(MenuComponent*component:Menu::chapterListeners){ - component->OnChapterUpdate(chapter); + for(std::weak_ptrcomponent:Menu::chapterListeners){ + component.lock()->OnChapterUpdate(chapter); } } diff --git a/Adventures in Lestoria/BlacksmithCraftingWindow.cpp b/Adventures in Lestoria/BlacksmithCraftingWindow.cpp index 5bb0c090..587fcfab 100644 --- a/Adventures in Lestoria/BlacksmithCraftingWindow.cpp +++ b/Adventures in Lestoria/BlacksmithCraftingWindow.cpp @@ -30,7 +30,7 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -Portions of this software are copyright © 2023 The FreeType +Portions of this software are copyright � 2023 The FreeType Project (www.freetype.org). Please see LICENSE_FT.txt for more information. All rights reserved. */ @@ -72,29 +72,29 @@ void Menu::InitializeBlacksmithCraftingWindow(){ }); #pragma endregion - auto weaponTab=blacksmithWindow->ADD("Weapon Tab",MenuComponent)({{2,0},{blacksmithWindow->size.x/2-4,24}},"Weapon",[](MenuFuncData data){ + auto weaponTab=blacksmithWindow->ADD("Weapon Tab",MenuComponent)(geom2d::rect{{2,0},{blacksmithWindow->size.x/2-4,24}},"Weapon",[](MenuFuncData data){ Component(BLACKSMITH,"Armor Tab")->selected=false; Component(BLACKSMITH,"Weapon Inventory Display")->Enable(true); Component(BLACKSMITH,"Armor Inventory Display")->Enable(false); - data.component->selected=true; + data.component.lock()->selected=true; return true; })END; weaponTab->selected=true; weaponTab->selectionType=SelectionType::HIGHLIGHT; - auto armorTab=blacksmithWindow->ADD("Armor Tab",MenuComponent)({{blacksmithWindow->size.x/2+2,0},{blacksmithWindow->size.x/2-4,24}},"Armor",[](MenuFuncData data){ + auto armorTab=blacksmithWindow->ADD("Armor Tab",MenuComponent)(geom2d::rect{{blacksmithWindow->size.x/2+2,0},{blacksmithWindow->size.x/2-4,24}},"Armor",[](MenuFuncData data){ Component(BLACKSMITH,"Weapon Tab")->selected=false; Component(BLACKSMITH,"Weapon Inventory Display")->Enable(false); Component(BLACKSMITH,"Armor Inventory Display")->Enable(true); - data.component->selected=true; + data.component.lock()->selected=true; return true; })END; armorTab->selectionType=SelectionType::HIGHLIGHT; #pragma region Weapon Inventory Display - auto weaponsDisplay=blacksmithWindow->ADD("Weapon Inventory Display",RowInventoryScrollableWindowComponent)({{2,28},{220,blacksmithWindow->size.y-44}},"Item Name Label","Item Description Label", + auto weaponsDisplay=blacksmithWindow->ADD("Weapon Inventory Display",RowInventoryScrollableWindowComponent)(geom2d::rect{{2,28},{220,blacksmithWindow->size.y-44}},"Item Name Label","Item Description Label", [](MenuFuncData data){ - RowItemDisplay*comp=DYNAMIC_CAST(data.component); - const std::weak_ptritem=comp->GetItem(); + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(data.component.lock()); + const std::weak_ptritem=comp.lock()->GetItem(); std::string label=""; if(item.lock()->EnhancementIsPossible()&&item.lock()->GetEnhancementInfo().size()>item.lock()->EnhancementLevel()+1){ @@ -109,8 +109,8 @@ void Menu::InitializeBlacksmithCraftingWindow(){ return true; }, [](MenuFuncData data){ - RowItemDisplay*rowItem=DYNAMIC_CAST(data.component); - Component(BLACKSMITH,"Item Icon")->SetItem(rowItem->GetItem()); + std::weak_ptrrowItem=DYNAMIC_POINTER_CAST(data.component.lock()); + Component(BLACKSMITH,"Item Icon")->SetItem(rowItem.lock()->GetItem()); return true; }, [](MenuFuncData data){ @@ -118,18 +118,18 @@ void Menu::InitializeBlacksmithCraftingWindow(){ return true; }, InventoryCreator::RowPlayerWeapons_InventoryUpdate, - {.padding=1,.size={207,28}} + InventoryWindowOptions{.padding=1,.size={207,28}} )END; AddInventoryListener(weaponsDisplay,"Equipment"); weaponsDisplay->SetCompactDescriptions(CRAFTING_INFO); #pragma endregion #pragma region Armor Inventory Display - auto armorDisplay=blacksmithWindow->ADD("Armor Inventory Display",RowInventoryScrollableWindowComponent)({{2,28},{220,blacksmithWindow->size.y-44}},"Item Name Label","Item Description Label", + auto armorDisplay=blacksmithWindow->ADD("Armor Inventory Display",RowInventoryScrollableWindowComponent)(geom2d::rect{{2,28},{220,blacksmithWindow->size.y-44}},"Item Name Label","Item Description Label", [](MenuFuncData data){ Menu::OpenMenu(CRAFT_ITEM); - RowItemDisplay*comp=DYNAMIC_CAST(data.component); - const std::weak_ptritem=comp->GetItem(); + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(data.component.lock()); + const std::weak_ptritem=comp.lock()->GetItem(); std::string label=""; if(item.lock()->EnhancementIsPossible()&&item.lock()->GetEnhancementInfo().size()>item.lock()->EnhancementLevel()+1){ @@ -143,8 +143,8 @@ void Menu::InitializeBlacksmithCraftingWindow(){ return true; }, [](MenuFuncData data){ - RowItemDisplay*rowItem=DYNAMIC_CAST(data.component); - Component(BLACKSMITH,"Item Icon")->SetItem(rowItem->GetItem()); + std::weak_ptrrowItem=DYNAMIC_POINTER_CAST(data.component.lock()); + Component(BLACKSMITH,"Item Icon")->SetItem(rowItem.lock()->GetItem()); return true; }, [](MenuFuncData data){ @@ -152,7 +152,7 @@ void Menu::InitializeBlacksmithCraftingWindow(){ return true; }, InventoryCreator::RowPlayerArmor_InventoryUpdate, - {.padding=1,.size={207,28}} + InventoryWindowOptions{.padding=1,.size={207,28}} )END; AddInventoryListener(armorDisplay,"Equipment"); armorDisplay->Enable(false); @@ -161,25 +161,25 @@ void Menu::InitializeBlacksmithCraftingWindow(){ #pragma region Inventory Description float inventoryDescriptionWidth=blacksmithWindow->pos.x+blacksmithWindow->size.x-26-224; - blacksmithWindow->ADD("Item Description Outline",MenuLabel)({{224,28},{inventoryDescriptionWidth,blacksmithWindow->size.y-44}},"",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - blacksmithWindow->ADD("Item Icon",MenuItemItemButton)({{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END; - blacksmithWindow->ADD("Item Name Label",MenuLabel)({{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - blacksmithWindow->ADD("Item Description Label",MenuLabel)({{226,94},{inventoryDescriptionWidth-6,blacksmithWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + blacksmithWindow->ADD("Item Description Outline",MenuLabel)(geom2d::rect{{224,28},{inventoryDescriptionWidth,blacksmithWindow->size.y-44}},"",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + blacksmithWindow->ADD("Item Icon",MenuItemItemButton)(geom2d::rect{{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END; + blacksmithWindow->ADD("Item Name Label",MenuLabel)(geom2d::rect{{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + blacksmithWindow->ADD("Item Description Label",MenuLabel)(geom2d::rect{{226,94},{inventoryDescriptionWidth-6,blacksmithWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; #pragma endregion #pragma region Money Display vf2d moneyIconPos={224+inventoryDescriptionWidth-24,28+blacksmithWindow->size.y-44+6}; - auto moneyIcon=blacksmithWindow->ADD("Money Icon",MenuIconButton)({moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END; + auto moneyIcon=blacksmithWindow->ADD("Money Icon",MenuIconButton)(geom2d::rect{moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END; std::string moneyText=std::to_string(game->GetPlayer()->GetMoney()); vf2d moneyTextSize=game->GetTextSizeProp(moneyText)*2; - auto moneyDisplay=blacksmithWindow->ADD("Money Label",PlayerMoneyLabel)({moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN|ComponentAttr::FIT_TO_LABEL)END; + auto moneyDisplay=blacksmithWindow->ADD("Money Label",PlayerMoneyLabel)(geom2d::rect{moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN|ComponentAttr::FIT_TO_LABEL)END; moneyDisplay->SetRightAlignment(true); Player::AddMoneyListener(moneyDisplay); #pragma endregion - blacksmithWindow->ADD("Leave Button",MenuComponent)({{blacksmithWindow->size.x/2-48,28+blacksmithWindow->size.y-44+6},{96,24}},"Leave",MenuType::ENUM_END, + blacksmithWindow->ADD("Leave Button",MenuComponent)(geom2d::rect{{blacksmithWindow->size.x/2-48,28+blacksmithWindow->size.y-44+6},{96,24}},"Leave",MenuType::ENUM_END, [](MenuFuncData data){ Menu::CloseMenu(); return true; - },{2,2})END; + },vf2d{2,2})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/BuyItemWindow.cpp b/Adventures in Lestoria/BuyItemWindow.cpp index a640fad0..7c1456fc 100644 --- a/Adventures in Lestoria/BuyItemWindow.cpp +++ b/Adventures in Lestoria/BuyItemWindow.cpp @@ -62,27 +62,27 @@ void Menu::InitializeBuyItemWindow(){ Component(BUY_ITEM,"Purchase Button")->SetGrayedOut(!canPurchase); }; - buyItemWindow->ADD("Item Purchase Header",MenuLabel)({{2,2},{188,12}},"Buying ",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; + buyItemWindow->ADD("Item Purchase Header",MenuLabel)(geom2d::rect{{2,2},{188,12}},"Buying ",1.f,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; - buyItemWindow->ADD("Price Per Item Label",MenuLabel)({{4,18},{188,12}},"Price Per Item",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - buyItemWindow->ADD("Amount to Buy Label",MenuLabel)({{4,34},{188,12}},"Amount to Buy",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - buyItemWindow->ADD("Price Label",MenuLabel)({{4,50},{188,12}},"Total Cost",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + buyItemWindow->ADD("Price Per Item Label",MenuLabel)(geom2d::rect{{4,18},{188,12}},"Price Per Item",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + buyItemWindow->ADD("Amount to Buy Label",MenuLabel)(geom2d::rect{{4,34},{188,12}},"Amount to Buy",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + buyItemWindow->ADD("Price Label",MenuLabel)(geom2d::rect{{4,50},{188,12}},"Total Cost",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - buyItemWindow->ADD("Price per item Amount Label",MenuLabel)({{buyItemWindow->size.x/2+28,18},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; - buyItemWindow->ADD("Amount to buy Amount Label",MenuLabel)({{buyItemWindow->size.x/2+48,34},{32,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::FIT_TO_LABEL)END; + buyItemWindow->ADD("Price per item Amount Label",MenuLabel)(geom2d::rect{{buyItemWindow->size.x/2+28,18},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; + buyItemWindow->ADD("Amount to buy Amount Label",MenuLabel)(geom2d::rect{{buyItemWindow->size.x/2+48,34},{32,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::FIT_TO_LABEL)END; - buyItemWindow->ADD("Increase buy amount Button",MenuComponent)({{buyItemWindow->size.x/2+80+2,34},{12,12}},"+",[&](MenuFuncData data){ + buyItemWindow->ADD("Increase buy amount Button",MenuComponent)(geom2d::rect{{buyItemWindow->size.x/2+80+2,34},{12,12}},"+",[&](MenuFuncData data){ UpdateMenu(GetQuantity()+1); return true; })END; - buyItemWindow->ADD("Decrease buy amount Button",MenuComponent)({{buyItemWindow->size.x/2+48-14,34},{12,12}},"-",[](MenuFuncData data){ + buyItemWindow->ADD("Decrease buy amount Button",MenuComponent)(geom2d::rect{{buyItemWindow->size.x/2+48-14,34},{12,12}},"-",[](MenuFuncData data){ UpdateMenu(GetQuantity()-1); return true; })END; - buyItemWindow->ADD("Total Price Amount Label",MenuLabel)({{buyItemWindow->size.x/2+28,50},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; + buyItemWindow->ADD("Total Price Amount Label",MenuLabel)(geom2d::rect{{buyItemWindow->size.x/2+28,50},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; - buyItemWindow->ADD("Purchase Button",MenuComponent)({{buyItemWindow->size.x/2+18,70},{64,12}},"Purchase",[&](MenuFuncData data){ + buyItemWindow->ADD("Purchase Button",MenuComponent)(geom2d::rect{{buyItemWindow->size.x/2+18,70},{64,12}},"Purchase",[&](MenuFuncData data){ Merchant&merchant=Merchant::GetCurrentTravelingMerchant(); const std::string&item=Component(BUY_ITEM,"Item Purchase Header")->GetString(A::ITEM_NAME); merchant.PurchaseItem(item,GetQuantity()); @@ -90,7 +90,7 @@ void Menu::InitializeBuyItemWindow(){ Menu::CloseMenu(); return true; })END; - buyItemWindow->ADD("Cancel Button",MenuComponent)({{buyItemWindow->size.x/2-82,70},{64,12}},"Cancel",[](MenuFuncData data){ + buyItemWindow->ADD("Cancel Button",MenuComponent)(geom2d::rect{{buyItemWindow->size.x/2-82,70},{64,12}},"Cancel",[](MenuFuncData data){ Menu::CloseMenu(); return true; })END; diff --git a/Adventures in Lestoria/C++/scripts/web.sh b/Adventures in Lestoria/C++/scripts/web.sh index 5122584d..5cf29534 100755 --- a/Adventures in Lestoria/C++/scripts/web.sh +++ b/Adventures in Lestoria/C++/scripts/web.sh @@ -15,19 +15,19 @@ then em++ -std=c++20 -O2 ${EMSCRIPTEN_CUSTOM_PARAMS} -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 -s USE_FREETYPE=1 -c pixelGameEngine.cpp -o pixelGameEngine_wasm.o fi if [ -d "assets" ]; then - em++ -std=c++20 -O2 ${EMSCRIPTEN_CUSTOM_PARAMS} -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 -s USE_FREETYPE=1 $(find . -type f -name "*.cpp" -not -path "./test/*" -not -name "pixelGameEngine.cpp") pixelGameEngine_wasm.o -o ${PROJECT_NAME}.html --preload-file ./assets + em++ -std=c++20 -O2 ${EMSCRIPTEN_CUSTOM_PARAMS} -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 -s USE_FREETYPE=1 $(find . -type f -name "*.cpp" -not -path "./discord-files/*" -not -path "./test/*" -not -name "pixelGameEngine.cpp") pixelGameEngine_wasm.o -o "${PROJECT_NAME}.html" --preload-file ./assets else - em++ -std=c++20 -O2 ${EMSCRIPTEN_CUSTOM_PARAMS} -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 -s USE_FREETYPE=1 $(find . -type f -name "*.cpp" -not -path "./test/*" -not -name "pixelGameEngine.cpp") pixelGameEngine_wasm.o -o ${PROJECT_NAME}.html + em++ -std=c++20 -O2 ${EMSCRIPTEN_CUSTOM_PARAMS} -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 -s USE_FREETYPE=1 $(find . -type f -name "*.cpp" -not -path "./discord-files/*" -not -path "./test/*" -not -name "pixelGameEngine.cpp") pixelGameEngine_wasm.o -o "${PROJECT_NAME}.html" fi -cp buildtemplate.html ${PROJECT_NAME}.html -sed -i "s/_REPLACEME_/$PROJECT_NAME.js/" ${PROJECT_NAME}.html +cp buildtemplate.html "${PROJECT_NAME}.html" +sed -i "s/_REPLACEME_/$PROJECT_NAME.js/" "${PROJECT_NAME}.html" if [[ "$1" == "headless" || "$2" == "headless" ]]; then echo "Running as headless web server" - emrun --no_browser ${PROJECT_NAME}.html + emrun --no_browser "${PROJECT_NAME}.html" else - emrun --serve_after_close ${PROJECT_NAME}.html + emrun --serve_after_close "${PROJECT_NAME}.html" fi if [ $? -eq 127 ] diff --git a/Adventures in Lestoria/CharacterInfoWindow.cpp b/Adventures in Lestoria/CharacterInfoWindow.cpp index 57c16b48..6ab52082 100644 --- a/Adventures in Lestoria/CharacterInfoWindow.cpp +++ b/Adventures in Lestoria/CharacterInfoWindow.cpp @@ -53,23 +53,23 @@ void Menu::InitializeClassInfoWindow(){ Menu*classSelectionWindow=Menu::menus[CLASS_SELECTION]; ClassInfo data=classutils::GetClassInfo(classSelectionWindow->S(A::CLASS_SELECTION)); - auto label=classInfoWindow->ADD("Class Name",MenuLabel)({{0,0},{classInfoWindow->size.x-1,24}},data.className,2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + auto label=classInfoWindow->ADD("Class Name",MenuLabel)(geom2d::rect{{0,0},{classInfoWindow->size.x-1,24}},data.className,2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - classInfoWindow->ADD("Rotating Character Display",CharacterRotatingDisplay)({{15,48},{72,120}},GFX[data.classFullImgName].Decal())END; + classInfoWindow->ADD("Rotating Character Display",CharacterRotatingDisplay)(geom2d::rect{{15,48},{72,120}},GFX[data.classFullImgName].Decal())END; vf2d healthDisplayLabelPos={classInfoWindow->size.x/3,label->GetPos().y+24}; vf2d labelSize={2*classInfoWindow->size.x/3-1,16}; - classInfoWindow->ADD("Base Stats Text",MenuLabel)({{0,label->GetPos().y+24},{classInfoWindow->size.x/3,labelSize.y}},"Base Stats",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; - classInfoWindow->ADD("Health Display Text",MenuLabel)({healthDisplayLabelPos+vf2d{0,16*0},labelSize},"Health: "+std::to_string(data.baseHealth)+" + "+std::to_string(data.healthGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; - classInfoWindow->ADD("Attack Display Text",MenuLabel)({healthDisplayLabelPos+vf2d{0,16*1},labelSize},"Attack: "+std::to_string(data.baseAtk)+" + "+std::to_string(data.atkGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; + classInfoWindow->ADD("Base Stats Text",MenuLabel)(geom2d::rect{{0,label->GetPos().y+24},{classInfoWindow->size.x/3,labelSize.y}},"Base Stats",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; + classInfoWindow->ADD("Health Display Text",MenuLabel)(geom2d::rect{healthDisplayLabelPos+vf2d{0,16*0},labelSize},"Health: "+std::to_string(data.baseHealth)+" + "+std::to_string(data.healthGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; + classInfoWindow->ADD("Attack Display Text",MenuLabel)(geom2d::rect{healthDisplayLabelPos+vf2d{0,16*1},labelSize},"Attack: "+std::to_string(data.baseAtk)+" + "+std::to_string(data.atkGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; vf2d abilityIconOffsets = {0,32}; - classInfoWindow->ADD("Ability 1 Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*0}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability1)END; - classInfoWindow->ADD("Ability 2 Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*1}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability2)END; - classInfoWindow->ADD("Ability 3 Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*2}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability3)END; - classInfoWindow->ADD("Right Click Ability Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*3}+abilityIconOffsets,labelSize*vf2d{1,2}},data.rightClickAbility)END; + classInfoWindow->ADD("Ability 1 Display",CharacterAbilityPreviewComponent)(geom2d::rect{healthDisplayLabelPos+vf2d{0,32*0}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability1)END; + classInfoWindow->ADD("Ability 2 Display",CharacterAbilityPreviewComponent)(geom2d::rect{healthDisplayLabelPos+vf2d{0,32*1}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability2)END; + classInfoWindow->ADD("Ability 3 Display",CharacterAbilityPreviewComponent)(geom2d::rect{healthDisplayLabelPos+vf2d{0,32*2}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability3)END; + classInfoWindow->ADD("Right Click Ability Display",CharacterAbilityPreviewComponent)(geom2d::rect{healthDisplayLabelPos+vf2d{0,32*3}+abilityIconOffsets,labelSize*vf2d{1,2}},data.rightClickAbility)END; - classInfoWindow->ADD("Back Button",MenuComponent)({{classInfoWindow->center().x/2,healthDisplayLabelPos.y+32*4+abilityIconOffsets.y+12},{classInfoWindow->size.x/2,16}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; + classInfoWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{classInfoWindow->center().x/2,healthDisplayLabelPos.y+32*4+abilityIconOffsets.y+12},{classInfoWindow->size.x/2,16}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/CharacterMenuWindow.cpp b/Adventures in Lestoria/CharacterMenuWindow.cpp index b160a4c4..b3d6c4c1 100644 --- a/Adventures in Lestoria/CharacterMenuWindow.cpp +++ b/Adventures in Lestoria/CharacterMenuWindow.cpp @@ -30,7 +30,7 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -Portions of this software are copyright © 2023 The FreeType +Portions of this software are copyright � 2023 The FreeType Project (www.freetype.org). Please see LICENSE_FT.txt for more information. All rights reserved. */ @@ -58,9 +58,9 @@ void Menu::InitializeCharacterMenuWindow(){ vf2d windowSize=game->GetScreenSize()-vf2d{52,52}; Menu*characterMenuWindow=CreateMenu(CHARACTER_MENU,CENTERED,windowSize); - characterMenuWindow->ADD("Character Label",MenuLabel)({{0,-4},{float(windowSize.x)-1,24}},"Character",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - characterMenuWindow->ADD("Equip Slot Outline",MenuComponent)({{0,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; - characterMenuWindow->ADD("Character Rotating Display",CharacterRotatingDisplay)({{135,28},{90,windowSize.y-48}},GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal())END; + characterMenuWindow->ADD("Character Label",MenuLabel)(geom2d::rect{{0,-4},{float(windowSize.x)-1,24}},"Character",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + characterMenuWindow->ADD("Equip Slot Outline",MenuComponent)(geom2d::rect{{0,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + characterMenuWindow->ADD("Character Rotating Display",CharacterRotatingDisplay)(geom2d::rect{{135,28},{90,windowSize.y-48}},GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal())END; const static std::arraydisplayAttrs{ "Health", @@ -73,22 +73,22 @@ void Menu::InitializeCharacterMenuWindow(){ }; - characterMenuWindow->ADD("Equip Selection Outline",MenuComponent)({{123,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END + characterMenuWindow->ADD("Equip Selection Outline",MenuComponent)(geom2d::rect{{123,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END ->Enable(false); - characterMenuWindow->ADD("Equip List",ScrollableWindowComponent)({{123,28},{120,windowSize.y-37-24}})DEPTH -1 END + characterMenuWindow->ADD("Equip List",ScrollableWindowComponent)(geom2d::rect{{123,28},{120,windowSize.y-37-24}})DEPTH -1 END ->Enable(false); - characterMenuWindow->ADD("Equip Selection Bottom Outline",MenuComponent)({{123,28+(windowSize.y-37-24)},{120,24}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END + characterMenuWindow->ADD("Equip Selection Bottom Outline",MenuComponent)(geom2d::rect{{123,28+(windowSize.y-37-24)},{120,24}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END ->Enable(false); - auto equipSelectionSelectButton=characterMenuWindow->ADD("Equip Selection Select Button",MenuComponent)({{123+12,28+(windowSize.y-37-24)+6},{96,12}},"Select", + auto equipSelectionSelectButton=characterMenuWindow->ADD("Equip Selection Select Button",MenuComponent)(geom2d::rect{{123+12,28+(windowSize.y-37-24)+6},{96,12}},"Select", [](MenuFuncData data){ - Component(data.component->parentMenu,"Equip Selection Outline")->Enable(false); - Component(data.component->parentMenu,"Equip List")->Enable(false); - Component(data.component->parentMenu,"Equip Selection Bottom Outline")->Enable(false); - Component(data.component->parentMenu,"Equip Selection Select Button")->Enable(false); - Component(data.component->parentMenu,"Character Rotating Display")->Enable(true); + Component(data.component.lock()->parentMenu,"Equip Selection Outline")->Enable(false); + Component(data.component.lock()->parentMenu,"Equip List")->Enable(false); + Component(data.component.lock()->parentMenu,"Equip Selection Bottom Outline")->Enable(false); + Component(data.component.lock()->parentMenu,"Equip Selection Select Button")->Enable(false); + Component(data.component.lock()->parentMenu,"Character Rotating Display")->Enable(true); for(int counter=0;const std::string&attribute:displayAttrs){ - StatLabel*statDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); - statDisplayLabel->SetStatChangeAmt(0); + std::weak_ptrstatDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); + statDisplayLabel.lock()->SetStatChangeAmt(0); } equipmentWindowOpened=false; return true; @@ -117,9 +117,9 @@ void Menu::InitializeCharacterMenuWindow(){ } const static std::arrayslotNames{"Helmet","Weapon","Armor","Gloves","Pants","Shoes","Ring 1","Ring 2"}; EquipSlot slot=EquipSlot(equipSlot); - auto equipmentSlot=characterMenuWindow->ADD("Equip Slot "+slotNames[i],EquipSlotButton)({{x,y+28},{24,24}},slot,MenuType::ENUM_END, + auto equipmentSlot=characterMenuWindow->ADD("Equip Slot "+slotNames[i],EquipSlotButton)(geom2d::rect{{x,y+28},{24,24}},slot,MenuType::ENUM_END, [&](MenuFuncData data){ - EquipSlot slot=EquipSlot(data.component->I(Attribute::EQUIP_TYPE)); + EquipSlot slot=EquipSlot(data.component.lock()->I(Attribute::EQUIP_TYPE)); const std::vector>&equips=Inventory::get("Equipment"); const std::vector>&accessories=Inventory::get("Accessories"); @@ -131,40 +131,36 @@ void Menu::InitializeCharacterMenuWindow(){ return it->GetEquipSlot()&slot; }); - ScrollableWindowComponent*equipList=Component(data.component->parentMenu,"Equip List"); + std::shared_ptrequipList=Component(data.component.lock()->parentMenu,"Equip List"); equipList->RemoveAllComponents(); for(int counter=0;const std::weak_ptrit:availableEquipment){ - const static auto OppositeRingSlotDoesNotMatchCurrentEquip=[](RowItemDisplay*comp){ - EquipSlot slot=EquipSlot(comp->I(Attribute::EQUIP_TYPE)); + const static auto OppositeRingSlotDoesNotMatchCurrentEquip=[](std::weak_ptrcomp){ + EquipSlot slot=EquipSlot(comp.lock()->I(Attribute::EQUIP_TYPE)); std::weak_ptrotherItem; if(slot&EquipSlot::RING1)otherItem=Inventory::GetEquip(EquipSlot::RING2); else if(slot&EquipSlot::RING2)otherItem=Inventory::GetEquip(EquipSlot::RING1); - return ISBLANK(otherItem)||(&*comp->GetItem().lock()!=&*otherItem.lock()); + return ISBLANK(otherItem)||(&*comp.lock()->GetItem().lock()!=&*otherItem.lock()); }; - auto equip=equipList->ADD("Equip Item "+std::to_string(counter),RowItemDisplay)({{2,2+counter*29.f},{120-15,28}},it, + auto equip=equipList->ADD("Equip Item "+std::to_string(counter),RowItemDisplay)(geom2d::rect{{2,2+counter*29.f},{120-15,28}},it, [](MenuFuncData data){ - RowItemDisplay*comp=DYNAMIC_CAST(data.component); - if(comp!=nullptr){ - if(OppositeRingSlotDoesNotMatchCurrentEquip(comp)){ //If we find that the opposite ring slot is equipped to us, this would be an item swap or the exact same ring, therefore no stat calculations apply. - Inventory::EquipItem(comp->GetItem(),EquipSlot(comp->I(Attribute::EQUIP_TYPE))); - SoundEffect::PlaySFX(comp->GetItem().lock()->UseSound(),SoundEffect::CENTERED); - for(MenuComponent*button:((ScrollableWindowComponent*)data.parentComponent)->GetComponents()){ - RowItemDisplay*comp=DYNAMIC_CAST(button); - if(comp!=nullptr){ - comp->SetSelected(false); - }else{ - ERR("WARNING! Attempting to cast a button that isn't a RowItemDisplay!"); - } + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(data.component.lock()); + if(!comp.expired()){ + if(OppositeRingSlotDoesNotMatchCurrentEquip(comp.lock())){ //If we find that the opposite ring slot is equipped to us, this would be an item swap or the exact same ring, therefore no stat calculations apply. + Inventory::EquipItem(comp.lock()->GetItem(),EquipSlot(comp.lock()->I(Attribute::EQUIP_TYPE))); + SoundEffect::PlaySFX(comp.lock()->GetItem().lock()->UseSound(),SoundEffect::CENTERED); + for(std::weak_ptrbutton:DYNAMIC_POINTER_CAST(data.parentComponent.lock())->GetComponents()){ + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(button.lock()); + comp.lock()->SetSelected(false); } - comp->SetSelected(true); + comp.lock()->SetSelected(true); for(int counter=0;const std::string&attribute:displayAttrs){ - StatLabel*statDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); + std::shared_ptrstatDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); statDisplayLabel->SetStatChangeAmt(0); } - MenuItemItemButton*equipButton=Component(CHARACTER_MENU,"Equip Slot "+slotNames[data.parentComponent->I(A::INDEXED_THEME)]); - equipButton->SetItem(comp->GetItem(),false); + std::shared_ptrequipButton=Component(CHARACTER_MENU,"Equip Slot "+slotNames[data.parentComponent.lock()->I(A::INDEXED_THEME)]); + equipButton->SetItem(comp.lock()->GetItem(),false); } }else{ ERR("WARNING! Attempting to cast a button that isn't a RowItemDisplay!"); @@ -174,11 +170,11 @@ void Menu::InitializeCharacterMenuWindow(){ equip->SetHoverFunc( [&](MenuFuncData data){ - RowItemDisplay*button=DYNAMIC_CAST(data.component); - if(button!=nullptr){ - const std::weak_ptrbuttonItem=button->GetItem(); + std::weak_ptrbutton=DYNAMIC_POINTER_CAST(data.component.lock()); + if(!button.expired()){ + const std::weak_ptrbuttonItem=button.lock()->GetItem(); std::vectorstatsBeforeEquip; - EquipSlot slot=EquipSlot(button->I(Attribute::EQUIP_TYPE)); + EquipSlot slot=EquipSlot(button.lock()->I(Attribute::EQUIP_TYPE)); for(const std::string&attribute:displayAttrs){ statsBeforeEquip.push_back(game->GetPlayer()->GetStat(attribute)); } @@ -188,12 +184,12 @@ void Menu::InitializeCharacterMenuWindow(){ if(slot==EquipSlot::RING1)otherItem=Inventory::GetEquip(EquipSlot::RING2); else if(slot==EquipSlot::RING2)otherItem=Inventory::GetEquip(EquipSlot::RING1); - if(OppositeRingSlotDoesNotMatchCurrentEquip(button)){ //If we find that the opposite ring slot is equipped to us, this would be an item swap or the exact same ring, therefore no stat calculations apply. + if(OppositeRingSlotDoesNotMatchCurrentEquip(button.lock())){ //If we find that the opposite ring slot is equipped to us, this would be an item swap or the exact same ring, therefore no stat calculations apply. Inventory::EquipItem(buttonItem,slot); for(int counter=0;const std::string&attribute:displayAttrs){ - StatLabel*statDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); + std::weak_ptrstatDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); int statChangeAmt=game->GetPlayer()->GetStat(attribute)-statsBeforeEquip[counter]; - statDisplayLabel->SetStatChangeAmt(statChangeAmt); + statDisplayLabel.lock()->SetStatChangeAmt(statChangeAmt); counter++; } Inventory::UnequipItem(slot); @@ -214,8 +210,8 @@ void Menu::InitializeCharacterMenuWindow(){ equip->SetMouseOutFunc( [](MenuFuncData data){ for(int counter=0;const std::string&attribute:displayAttrs){ - StatLabel*statDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); - statDisplayLabel->SetStatChangeAmt(0); + std::weak_ptrstatDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); + statDisplayLabel.lock()->SetStatChangeAmt(0); counter++; } return true; @@ -232,27 +228,27 @@ void Menu::InitializeCharacterMenuWindow(){ counter++; } - equipList->I(Attribute::INDEXED_THEME)=data.component->I(Attribute::INDEXED_THEME); - Component(data.component->parentMenu,"Equip Selection Outline")->Enable(true); + equipList->I(Attribute::INDEXED_THEME)=data.component.lock()->I(Attribute::INDEXED_THEME); + Component(data.component.lock()->parentMenu,"Equip Selection Outline")->Enable(true); equipList->Enable(true); - Component(data.component->parentMenu,"Equip Selection Bottom Outline")->Enable(true); - Component(data.component->parentMenu,"Equip Selection Select Button")->Enable(true); - Component(data.component->parentMenu,"Character Rotating Display")->Enable(false); + Component(data.component.lock()->parentMenu,"Equip Selection Bottom Outline")->Enable(true); + Component(data.component.lock()->parentMenu,"Equip Selection Select Button")->Enable(true); + Component(data.component.lock()->parentMenu,"Character Rotating Display")->Enable(false); equipmentWindowOpened=true; return true; },[](MenuFuncData data){//On Mouse Hover - EquipSlot slot=DYNAMIC_CAST(data.component)->GetSlot(); + EquipSlot slot=DYNAMIC_POINTER_CAST(data.component.lock())->GetSlot(); const std::weak_ptrequip=Inventory::GetEquip(slot); if(!ISBLANK(equip)){ - Component(data.component->parentMenu,"Character Rotating Display")->Enable(false); + Component(data.component.lock()->parentMenu,"Character Rotating Display")->Enable(false); } return true; },[](MenuFuncData data){//On Mouse Out if(!equipmentWindowOpened){ - Component(data.component->parentMenu,"Item Equip Description")->SetLabel(""); - Component(data.component->parentMenu,"Item Equip Name")->Enable(false); - Component(data.component->parentMenu,"Item Equip Description")->Enable(false); - Component(data.component->parentMenu,"Character Rotating Display")->Enable(true); + Component(data.component.lock()->parentMenu,"Item Equip Description")->SetLabel(""); + Component(data.component.lock()->parentMenu,"Item Equip Name")->Enable(false); + Component(data.component.lock()->parentMenu,"Item Equip Description")->Enable(false); + Component(data.component.lock()->parentMenu,"Character Rotating Display")->Enable(true); } return true; },"Item Equip Name","Item Equip Description")END; @@ -262,26 +258,26 @@ void Menu::InitializeCharacterMenuWindow(){ equipmentSlot->SetShowQuantity(false); equipmentSlot->SetCompactDescriptions(false); equipSlot<<=1; - characterMenuWindow->ADD("Equip Label "+slotNames[i],PopupMenuLabel)({{labelX,labelY},{24,16}},slotNames[i],{0.5,1},ComponentAttr::SHADOW)END; + characterMenuWindow->ADD("Equip Label "+slotNames[i],PopupMenuLabel)(geom2d::rect{{labelX,labelY},{24,16}},slotNames[i],vf2d{0.5,1.f},ComponentAttr::SHADOW)END; Menu::AddEquipStatListener(equipmentSlot); } - characterMenuWindow->ADD("Stat Display Outline",MenuComponent)({{245,28},{62,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + characterMenuWindow->ADD("Stat Display Outline",MenuComponent)(geom2d::rect{{245,28},{62,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; int yOffset=0; for(const std::string&attribute:displayAttrs){ std::string attrStr=GetLabelText(ItemAttribute::Get(attribute)); - auto attrLabel=characterMenuWindow->ADD("Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label",StatLabel)({{245,28+2+float(yOffset)},{62,18}},ItemAttribute::Get(attribute),1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END; + auto attrLabel=characterMenuWindow->ADD("Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label",StatLabel)(geom2d::rect{{245,28+2+float(yOffset)},{62,18}},ItemAttribute::Get(attribute),1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END; Menu::AddEquipStatListener(attrLabel); yOffset+=20; } - characterMenuWindow->ADD("Back button",MenuComponent)({{windowSize.x/2-64,windowSize.y},{128,12}},"Back",[](MenuFuncData data){Menu::stack.pop_back();return true;})END; + characterMenuWindow->ADD("Back button",MenuComponent)(geom2d::rect{{windowSize.x/2-64,windowSize.y},{128,12}},"Back",[](MenuFuncData data){Menu::stack.pop_back();return true;})END; - auto itemNameDisplay=characterMenuWindow->ADD("Item Name",MenuLabel)({{0,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; - auto itemDescriptionDisplay=characterMenuWindow->ADD("Item Description",MenuLabel)({{0,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END; - auto itemEquipNameDisplay=characterMenuWindow->ADD("Item Equip Name",MenuLabel)({{123,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; - auto itemEquipDescriptionDisplay=characterMenuWindow->ADD("Item Equip Description",MenuLabel)({{123,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END; + auto itemNameDisplay=characterMenuWindow->ADD("Item Name",MenuLabel)(geom2d::rect{{0,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; + auto itemDescriptionDisplay=characterMenuWindow->ADD("Item Description",MenuLabel)(geom2d::rect{{0,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END; + auto itemEquipNameDisplay=characterMenuWindow->ADD("Item Equip Name",MenuLabel)(geom2d::rect{{123,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; + auto itemEquipDescriptionDisplay=characterMenuWindow->ADD("Item Equip Description",MenuLabel)(geom2d::rect{{123,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END; itemNameDisplay->Enable(false); itemDescriptionDisplay->Enable(false); diff --git a/Adventures in Lestoria/ClassSelectionWindow.cpp b/Adventures in Lestoria/ClassSelectionWindow.cpp index d7d4fdf4..98ffd2d6 100644 --- a/Adventures in Lestoria/ClassSelectionWindow.cpp +++ b/Adventures in Lestoria/ClassSelectionWindow.cpp @@ -53,16 +53,16 @@ void Menu::InitializeClassSelectionWindow(){ vf2d outlineSize=classSelectionWindow->size-vf2d{13,13}; - classSelectionWindow->ADD("Class Selection Title Label",MenuLabel)({{4,20},{outlineSize.x,32}},"Choose a Character Class",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + classSelectionWindow->ADD("Class Selection Title Label",MenuLabel)(geom2d::rect{{4,20},{outlineSize.x,32}},"Choose a Character Class",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - auto outline=classSelectionWindow->ADD("Outline Border",MenuLabel)({{4,4},outlineSize},"",1,ComponentAttr::OUTLINE)END; + auto outline=classSelectionWindow->ADD("Outline Border",MenuLabel)(geom2d::rect{{4,4},outlineSize},"",1,ComponentAttr::OUTLINE)END; vf2d navigationButtonSize={24*2.5f,16}; - classSelectionWindow->ADD("Back Button",MenuComponent)({{4+2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; + classSelectionWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{4+2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; - classSelectionWindow->ADD("Confirm",MenuComponent)({{outlineSize.x+4-navigationButtonSize.x-2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Confirm",[](MenuFuncData data){ - std::string selectedClass=data.component->S(A::CLASS_SELECTION); + classSelectionWindow->ADD("Confirm",MenuComponent)(geom2d::rect{{outlineSize.x+4-navigationButtonSize.x-2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Confirm",[](MenuFuncData data){ + std::string selectedClass=data.component.lock()->S(A::CLASS_SELECTION); data.game->ChangePlayerClass(classutils::StringToClass(selectedClass)); GameState::ChangeState(States::OVERWORLD_MAP); return true; @@ -93,7 +93,7 @@ void Menu::InitializeClassSelectionWindow(){ Witch::walk_s, }; - std::vectortoggleGroup; + std::vector>toggleGroup; for(int i=0;i<6;i++){ std::string className=classNames[i]; @@ -109,19 +109,19 @@ void Menu::InitializeClassSelectionWindow(){ vf2d backgroundSize={floor(outlineSize.y/3-buttonPadding.y*3),outlineSize.y/3-buttonPadding.y*3}; //The floor is for fixing a small pixel rounding bug. - classSelectionWindow->ADD(className+" Background",MenuLabel)({backgroundOffsetPos,backgroundSize},"",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - classSelectionWindow->ADD(className+" Button",MenuComponent)({offsetPos,buttonSize},"Info",CLASS_INFO, + classSelectionWindow->ADD(className+" Background",MenuLabel)(geom2d::rect{backgroundOffsetPos,backgroundSize},"",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + classSelectionWindow->ADD(className+" Button",MenuComponent)(geom2d::rect{offsetPos,buttonSize},"Info",CLASS_INFO, [](MenuFuncData data){ - data.menu.S(A::CLASS_SELECTION)=data.component->S(A::CLASS_SELECTION); + data.menu.S(A::CLASS_SELECTION)=data.component.lock()->S(A::CLASS_SELECTION); delete Menu::menus[CLASS_INFO]; Menu::InitializeClassInfoWindow(); return true; })END ->S(A::CLASS_SELECTION)=className; - classSelectionWindow->ADD(className+" Label",MenuLabel)({backgroundOffsetPos,buttonSize},className,1,ComponentAttr::SHADOW)END; - auto classSprite=classSelectionWindow->ADD(className+" Icon",MenuAnimatedIconToggleButton)({backgroundOffsetPos+vf2d{0,12},backgroundSize+vf2d{0,-buttonSize.y-12}},classAnimationName,[](MenuFuncData data){ + classSelectionWindow->ADD(className+" Label",MenuLabel)(geom2d::rect{backgroundOffsetPos,buttonSize},className,1,ComponentAttr::SHADOW)END; + auto classSprite=classSelectionWindow->ADD(className+" Icon",MenuAnimatedIconToggleButton)(geom2d::rect{backgroundOffsetPos+vf2d{0,12},backgroundSize+vf2d{0,-buttonSize.y-12}},classAnimationName,[](MenuFuncData data){ data.menu.components["Confirm"]->Enable(true); - data.menu.components["Confirm"]->S(A::CLASS_SELECTION)=data.component->S(A::CLASS_SELECTION); + data.menu.components["Confirm"]->S(A::CLASS_SELECTION)=data.component.lock()->S(A::CLASS_SELECTION); return true; })END; @@ -130,7 +130,7 @@ void Menu::InitializeClassSelectionWindow(){ toggleGroup.push_back(classSprite); } - for(IToggleable*item:toggleGroup){ - item->SetToggleGroup(toggleGroup); + for(std::weak_ptritem:toggleGroup){ + item.lock()->SetToggleGroup(toggleGroup); } } \ No newline at end of file diff --git a/Adventures in Lestoria/ConsumableCraftItemWindow.cpp b/Adventures in Lestoria/ConsumableCraftItemWindow.cpp index 0a25ad48..ec1d4801 100644 --- a/Adventures in Lestoria/ConsumableCraftItemWindow.cpp +++ b/Adventures in Lestoria/ConsumableCraftItemWindow.cpp @@ -47,7 +47,7 @@ using A=Attribute; void Menu::InitializeConsumableCraftItemWindow(){ Menu*consumableCraftItemWindow=CreateMenu(CONSUMABLE_CRAFT_ITEM,CENTERED,{240,96}); - consumableCraftItemWindow->ADD("Item Name Header",MenuLabel)({{2,-4},{consumableCraftItemWindow->size.x-4,12}},"Item Name",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + consumableCraftItemWindow->ADD("Item Name Header",MenuLabel)(geom2d::rect{{2,-4},{consumableCraftItemWindow->size.x-4,12}},"Item Name",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; static auto GetQuantity=[&](){ return std::stoi(Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->GetLabel()); @@ -65,28 +65,28 @@ void Menu::InitializeConsumableCraftItemWindow(){ Component(CONSUMABLE_CRAFT_ITEM,"Craft Button")->SetGrayedOut(!canCraft); }; - consumableCraftItemWindow->ADD("Amount to Craft Label",MenuLabel)({{4,34},{188,12}},"Craft Amount",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - consumableCraftItemWindow->ADD("Amount to Craft Amount Label",MenuLabel)({{consumableCraftItemWindow->size.x/2+48,34},{32,12}},"1" + consumableCraftItemWindow->ADD("Amount to Craft Label",MenuLabel)(geom2d::rect{{4,34},{188,12}},"Craft Amount",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + consumableCraftItemWindow->ADD("Amount to Craft Amount Label",MenuLabel)(geom2d::rect{{consumableCraftItemWindow->size.x/2+48,34},{32,12}},"1" ,UpdateMenu,1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::FIT_TO_LABEL)END; - consumableCraftItemWindow->ADD("Increase Craft amount Button",MenuComponent)({{consumableCraftItemWindow->size.x/2+80+2,34},{12,12}},"+",[&](MenuFuncData data){ + consumableCraftItemWindow->ADD("Increase Craft amount Button",MenuComponent)(geom2d::rect{{consumableCraftItemWindow->size.x/2+80+2,34},{12,12}},"+",[&](MenuFuncData data){ uint8_t qty=std::clamp(GetQuantity()+1,1,99); Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->SetLabel(std::to_string(qty)); return true; })END; - consumableCraftItemWindow->ADD("Decrease Craft amount Button",MenuComponent)({{consumableCraftItemWindow->size.x/2+48-14,34},{12,12}},"-",[](MenuFuncData data){ + consumableCraftItemWindow->ADD("Decrease Craft amount Button",MenuComponent)(geom2d::rect{{consumableCraftItemWindow->size.x/2+48-14,34},{12,12}},"-",[](MenuFuncData data){ uint8_t qty=std::clamp(GetQuantity()-1,1,99); Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->SetLabel(std::to_string(qty)); return true; })END; - consumableCraftItemWindow->ADD("Materials Requirement Outline",MenuComponent)({{2,86-18},{consumableCraftItemWindow->size.x-4,26}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; - consumableCraftItemWindow->ADD("Required Materials Label",MenuLabel)({{4,80-18},{consumableCraftItemWindow->size.x-8,0}},"Required Materials",1.0f,ComponentAttr::SHADOW)END; + consumableCraftItemWindow->ADD("Materials Requirement Outline",MenuComponent)(geom2d::rect{{2,86-18},{consumableCraftItemWindow->size.x-4,26}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + consumableCraftItemWindow->ADD("Required Materials Label",MenuLabel)(geom2d::rect{{4,80-18},{consumableCraftItemWindow->size.x-8,0}},"Required Materials",1.0f,ComponentAttr::SHADOW)END; - consumableCraftItemWindow->ADD("Required Materials List",RequiredMaterialsList)({{4,88-18},{consumableCraftItemWindow->size.x-8,22}},Item::BLANK)END; + consumableCraftItemWindow->ADD("Required Materials List",RequiredMaterialsList)(geom2d::rect{{4,88-18},{consumableCraftItemWindow->size.x-8,22}},Item::BLANK)END; - consumableCraftItemWindow->ADD("Back Button",MenuComponent)({{36,116-18},{48,12}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; - consumableCraftItemWindow->ADD("Craft Button",MenuComponent)({{consumableCraftItemWindow->size.x-84,116-18},{48,12}},"Craft",[](MenuFuncData data){ + consumableCraftItemWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{36,116-18},{48,12}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; + consumableCraftItemWindow->ADD("Craft Button",MenuComponent)(geom2d::rect{{consumableCraftItemWindow->size.x-84,116-18},{48,12}},"Craft",[](MenuFuncData data){ const std::weak_ptritem=Component(CONSUMABLE_CRAFT_ITEM,"Required Materials List")->GetItem(); uint8_t qty=stoi(Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->GetLabel()); @@ -95,7 +95,7 @@ void Menu::InitializeConsumableCraftItemWindow(){ item.lock()->EnhanceItem(qty); } } - data.component->SetGrayedOut(!item.lock()->CanEnhanceItem(qty)); + data.component.lock()->SetGrayedOut(!item.lock()->CanEnhanceItem(qty)); return true; })END; } \ No newline at end of file diff --git a/Adventures in Lestoria/ConsumableCraftingWindow.cpp b/Adventures in Lestoria/ConsumableCraftingWindow.cpp index 5f4052fe..641fad42 100644 --- a/Adventures in Lestoria/ConsumableCraftingWindow.cpp +++ b/Adventures in Lestoria/ConsumableCraftingWindow.cpp @@ -30,7 +30,7 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -Portions of this software are copyright © 2023 The FreeType +Portions of this software are copyright � 2023 The FreeType Project (www.freetype.org). Please see LICENSE_FT.txt for more information. All rights reserved. */ @@ -53,10 +53,10 @@ void Menu::InitializeConsumableCraftingWindow(){ Menu*consumableCraftingWindow=CreateMenu(CRAFT_CONSUMABLE,CENTERED,game->GetScreenSize()-vi2d{52,52}); #pragma region Craftables Inventory Display - auto craftingItemsDisplay=consumableCraftingWindow->ADD("Crafting Inventory Display",RowInventoryScrollableWindowComponent)({{2,28},{220,consumableCraftingWindow->size.y-44}},"Item Name Label","Item Description Label", + auto craftingItemsDisplay=consumableCraftingWindow->ADD("Crafting Inventory Display",RowInventoryScrollableWindowComponent)(geom2d::rect{{2,28},{220,consumableCraftingWindow->size.y-44}},"Item Name Label","Item Description Label", [](MenuFuncData data){ - RowItemDisplay*comp=DYNAMIC_CAST(data.component); - const std::weak_ptritem=comp->GetItem(); + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(data.component.lock()); + const std::weak_ptritem=comp.lock()->GetItem(); Component(CONSUMABLE_CRAFT_ITEM,"Item Name Header")->GetString(A::ITEM_NAME)=item.lock()->ActualName(); Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->SetLabel("1"); Component(CONSUMABLE_CRAFT_ITEM,"Item Name Header")->SetLabel(std::format("Crafting {}",item.lock()->DisplayName())); @@ -68,13 +68,13 @@ void Menu::InitializeConsumableCraftingWindow(){ return true; }, [](MenuFuncData data){ - RowItemDisplay*rowItem=DYNAMIC_CAST(data.component); - if(rowItem->GetItem().lock()->GetEnhancementInfo().AvailableChapter()<=game->GetCurrentChapter()){ + std::weak_ptrrowItem=DYNAMIC_POINTER_CAST(data.component.lock()); + if(rowItem.lock()->GetItem().lock()->GetEnhancementInfo().AvailableChapter()<=game->GetCurrentChapter()){ Component(CRAFT_CONSUMABLE,"Item Icon")->SetHideDetails(false); }else{ Component(CRAFT_CONSUMABLE,"Item Icon")->SetHideDetails(true); } - Component(CRAFT_CONSUMABLE,"Item Icon")->SetItem(rowItem->GetItem()); + Component(CRAFT_CONSUMABLE,"Item Icon")->SetItem(rowItem.lock()->GetItem()); return true; }, [](MenuFuncData data){ @@ -82,7 +82,7 @@ void Menu::InitializeConsumableCraftingWindow(){ return true; }, InventoryCreator::RowPlayerWeapons_InventoryUpdate, - {.padding=1,.size={207,28}} + InventoryWindowOptions{.padding=1,.size={207,28}} )END; craftingItemsDisplay->SetCompactDescriptions(CRAFTING_INFO); @@ -96,7 +96,7 @@ void Menu::InitializeConsumableCraftingWindow(){ int x=int((invSize-1)%invWidth); int y=int((invSize-1)/invWidth); int itemIndex=y*invWidth+x; - auto newItem=craftingItemsDisplay->ADD("item_Craftables_"+std::to_string(itemIndex),RowItemDisplay)({totalSpacing*vf2d{float(x),float(y)},buttonSize},item,craftingItemsDisplay->inventoryButtonClickAction,craftingItemsDisplay->itemNameLabelName,craftingItemsDisplay->itemDescriptionLabelName,craftingItemsDisplay->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; + auto newItem=craftingItemsDisplay->ADD("item_Craftables_"+std::to_string(itemIndex),RowItemDisplay)(geom2d::rect{totalSpacing*vf2d{float(x),float(y)},buttonSize},item,craftingItemsDisplay->inventoryButtonClickAction,craftingItemsDisplay->itemNameLabelName,craftingItemsDisplay->itemDescriptionLabelName,craftingItemsDisplay->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; newItem->SetShowQuantity(false); newItem->SetCompactDescriptions(craftingItemsDisplay->compact); newItem->SetPriceLabelType(craftingItemsDisplay->priceLabel); @@ -111,26 +111,26 @@ void Menu::InitializeConsumableCraftingWindow(){ #pragma region Inventory Description float inventoryDescriptionWidth=consumableCraftingWindow->pos.x+consumableCraftingWindow->size.x-26-224; - consumableCraftingWindow->ADD("Item Description Outline",MenuLabel)({{224,28},{inventoryDescriptionWidth,consumableCraftingWindow->size.y-44}},"",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - consumableCraftingWindow->ADD("Item Icon",MenuItemItemButton)({{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END + consumableCraftingWindow->ADD("Item Description Outline",MenuLabel)(geom2d::rect{{224,28},{inventoryDescriptionWidth,consumableCraftingWindow->size.y-44}},"",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + consumableCraftingWindow->ADD("Item Icon",MenuItemItemButton)(geom2d::rect{{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END ->SetShowQuantity(false); - consumableCraftingWindow->ADD("Item Name Label",MenuLabel)({{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - consumableCraftingWindow->ADD("Item Description Label",MenuLabel)({{226,94},{inventoryDescriptionWidth-6,consumableCraftingWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + consumableCraftingWindow->ADD("Item Name Label",MenuLabel)(geom2d::rect{{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + consumableCraftingWindow->ADD("Item Description Label",MenuLabel)(geom2d::rect{{226,94},{inventoryDescriptionWidth-6,consumableCraftingWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; #pragma endregion #pragma region Money Display vf2d moneyIconPos={224+inventoryDescriptionWidth-24,28+consumableCraftingWindow->size.y-44+6}; - auto moneyIcon=consumableCraftingWindow->ADD("Money Icon",MenuIconButton)({moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END; + auto moneyIcon=consumableCraftingWindow->ADD("Money Icon",MenuIconButton)(geom2d::rect{moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END; std::string moneyText=std::to_string(game->GetPlayer()->GetMoney()); vf2d moneyTextSize=game->GetTextSizeProp(moneyText)*2; - auto moneyDisplay=consumableCraftingWindow->ADD("Money Label",PlayerMoneyLabel)({moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN|ComponentAttr::FIT_TO_LABEL)END; + auto moneyDisplay=consumableCraftingWindow->ADD("Money Label",PlayerMoneyLabel)(geom2d::rect{moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN|ComponentAttr::FIT_TO_LABEL)END; moneyDisplay->SetRightAlignment(true); Player::AddMoneyListener(moneyDisplay); #pragma endregion - consumableCraftingWindow->ADD("Leave Button",MenuComponent)({{consumableCraftingWindow->size.x/2-48,28+consumableCraftingWindow->size.y-44+6},{96,24}},"Leave",MenuType::ENUM_END, + consumableCraftingWindow->ADD("Leave Button",MenuComponent)(geom2d::rect{{consumableCraftingWindow->size.x/2-48,28+consumableCraftingWindow->size.y-44+6},{96,24}},"Leave",MenuType::ENUM_END, [](MenuFuncData data){ Menu::CloseMenu(); return true; - },{2,2})END; + },vf2d{2.f,2.f})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/CraftItemWindow.cpp b/Adventures in Lestoria/CraftItemWindow.cpp index b17d3e2d..2d5dffcc 100644 --- a/Adventures in Lestoria/CraftItemWindow.cpp +++ b/Adventures in Lestoria/CraftItemWindow.cpp @@ -43,19 +43,19 @@ All rights reserved. void Menu::InitializeCraftItemWindow(){ Menu*craftItemWindow=CreateMenu(CRAFT_ITEM,CENTERED,{240,120}); - craftItemWindow->ADD("Item Name Header",MenuLabel)({{2,-16},{craftItemWindow->size.x-4,12}},"Item Name",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + craftItemWindow->ADD("Item Name Header",MenuLabel)(geom2d::rect{{2,-16},{craftItemWindow->size.x-4,12}},"Item Name",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - craftItemWindow->ADD("Enhancement Level Header",MenuLabel)({{2,0},{craftItemWindow->size.x-4,12}},"Level X ->#00AA00 Y",1.f,ComponentAttr::SHADOW|ComponentAttr::FIXED_WIDTH_FONT)END; + craftItemWindow->ADD("Enhancement Level Header",MenuLabel)(geom2d::rect{{2,0},{craftItemWindow->size.x-4,12}},"Level X ->#00AA00 Y",1.f,ComponentAttr::SHADOW|ComponentAttr::FIXED_WIDTH_FONT)END; - craftItemWindow->ADD("Enhancement Stats Label",EnhancementStatsLabel)({{2,16},{craftItemWindow->size.x-4,72}},Item::BLANK,1.f)END; + craftItemWindow->ADD("Enhancement Stats Label",EnhancementStatsLabel)(geom2d::rect{{2,16},{craftItemWindow->size.x-4,72}},Item::BLANK,1.f)END; - craftItemWindow->ADD("Materials Requirement Outline",MenuComponent)({{2,86},{craftItemWindow->size.x-4,26}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; - craftItemWindow->ADD("Required Materials Label",MenuLabel)({{4,80},{craftItemWindow->size.x-8,0}},"Required Materials",1.0f,ComponentAttr::SHADOW)END; + craftItemWindow->ADD("Materials Requirement Outline",MenuComponent)(geom2d::rect{{2,86},{craftItemWindow->size.x-4,26}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + craftItemWindow->ADD("Required Materials Label",MenuLabel)(geom2d::rect{{4,80},{craftItemWindow->size.x-8,0}},"Required Materials",1.0f,ComponentAttr::SHADOW)END; - craftItemWindow->ADD("Required Materials List",RequiredMaterialsList)({{4,88},{craftItemWindow->size.x-8,22}},Item::BLANK)END; + craftItemWindow->ADD("Required Materials List",RequiredMaterialsList)(geom2d::rect{{4,88},{craftItemWindow->size.x-8,22}},Item::BLANK)END; - craftItemWindow->ADD("Back Button",MenuComponent)({{36,116},{48,12}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; - craftItemWindow->ADD("Craft Button",MenuComponent)({{craftItemWindow->size.x-84,116},{48,12}},"Craft",[](MenuFuncData data){ + craftItemWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{36,116},{48,12}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; + craftItemWindow->ADD("Craft Button",MenuComponent)(geom2d::rect{{craftItemWindow->size.x-84,116},{48,12}},"Craft",[](MenuFuncData data){ const std::weak_ptritem=Component(data.menu.GetType(),"Enhancement Stats Label")->GetItem(); if(item.lock()->CanEnhanceItem()){ item.lock()->EnhanceItem(); @@ -65,7 +65,7 @@ void Menu::InitializeCraftItemWindow(){ label=std::format("Level {} ->#00AA00 {}",item.lock()->EnhancementLevel(),item.lock()->EnhancementLevel()+1); } Component(data.menu.GetType(),"Enhancement Level Header")->SetLabel(label); - data.component->SetGrayedOut(!item.lock()->CanEnhanceItem()); + data.component.lock()->SetGrayedOut(!item.lock()->CanEnhanceItem()); return true; })END; } \ No newline at end of file diff --git a/Adventures in Lestoria/EncountersSpawnListScrollableWindowComponent.h b/Adventures in Lestoria/EncountersSpawnListScrollableWindowComponent.h index 23fde223..2ae83294 100644 --- a/Adventures in Lestoria/EncountersSpawnListScrollableWindowComponent.h +++ b/Adventures in Lestoria/EncountersSpawnListScrollableWindowComponent.h @@ -54,15 +54,14 @@ public: virtual inline void UpdateSpawns(std::vector&spawns){ Menu::menus.at(parentMenu)->components.erase_if([&](auto key){ if(key.first.starts_with("Spawn ")){ - std::erase_if(components,[&](MenuComponent*component){return key.second==component;}); - delete key.second; + std::erase_if(components,[&](std::weak_ptrcomponent){return &*key.second==&*component.lock();}); return true; } return false;}); int offsetY=0; vf2d parentSize=Menu::menus.at(OVERWORLD_LEVEL_SELECT)->size; for(std::string spawn:spawns){ - ADD("Spawn "+spawn,SpawnEncounterLabel)({vf2d{0,float(offsetY)},{parentSize.x,12}},MONSTER_DATA.at(spawn).GetDisplayName(),spawn)END; + ADD("Spawn "+spawn,SpawnEncounterLabel)(geom2d::rect{vf2d{0,float(offsetY)},{parentSize.x,12}},MONSTER_DATA.at(spawn).GetDisplayName(),spawn)END; offsetY+=14; } } diff --git a/Adventures in Lestoria/Error.h b/Adventures in Lestoria/Error.h index 66e8124c..47190b9c 100644 --- a/Adventures in Lestoria/Error.h +++ b/Adventures in Lestoria/Error.h @@ -40,6 +40,7 @@ All rights reserved. #include #include #include +#include #ifndef __EMSCRIPTEN__ #include #endif @@ -82,4 +83,18 @@ type DYNAMIC_CAST(auto variable){ type pointer=dynamic_cast(variable); if(pointer==nullptr)ERR("Could not dynamic cast to type "< +std::shared_ptrDYNAMIC_POINTER_CAST(const std::shared_ptr&variable){ + std::shared_ptr newVariable=dynamic_pointer_cast(variable); + if(!newVariable)ERR("Could not dynamic cast to pointer type "< +std::shared_ptrDYNAMIC_POINTER_CAST(const std::weak_ptr&variable){ + std::shared_ptr newVariable=dynamic_pointer_cast(variable.lock()); + if(!newVariable)ERR("Could not dynamic cast to pointer type "<I(A::LOADOUT_SLOT)=0; - auto consumableWindow=inventoryWindow->ADD("inventory",InventoryScrollableWindowComponent)({{0,15},{windowSize.x,96.f}},"itemName","itemDescription", + auto consumableWindow=inventoryWindow->ADD("inventory",InventoryScrollableWindowComponent)(geom2d::rect{{0,15},{windowSize.x,96.f}},"itemName","itemDescription", [&](MenuFuncData data){ - MenuItemButton*button=(MenuItemButton*)data.component; + std::weak_ptrbutton=DYNAMIC_POINTER_CAST(data.component.lock()); data.game->ClearLoadoutItem(data.menu.I(A::LOADOUT_SLOT)); - for(MenuComponent*component:data.parentComponent->GetComponents()){ //HACK ALERT! If we are accessing a parent component, it's because we are dealing with a scrolling window component, which has sub-components. So this should be a safe cast to make. - if(component->GetName().starts_with("item")){ - MenuItemButton*button2=DYNAMIC_CAST(component);//HACK ALERT! This is probably an item since we populated item lists using this name for the components. So we assume these are MenuItemButton classes. - if(button2==nullptr)ERR("Could not cast item to a MenuItemButton*!"); - if(button2==button){ - if(button2->selected!=-1){ - data.game->ClearLoadoutItem(button2->selected); + for(std::weak_ptrcomponent:data.parentComponent.lock()->GetComponents()){ //HACK ALERT! If we are accessing a parent component, it's because we are dealing with a scrolling window component, which has sub-components. So this should be a safe cast to make. + if(component.lock()->GetName().starts_with("item")){ + std::weak_ptrbutton2=DYNAMIC_POINTER_CAST(component.lock());//HACK ALERT! This is probably an item since we populated item lists using this name for the components. So we assume these are MenuItemButton classes. + if(button2.expired())ERR("Could not cast item to a MenuItemButton*!"); + if(&*button2.lock()==&*button.lock()){ + if(button2.lock()->selected!=-1){ + data.game->ClearLoadoutItem(button2.lock()->selected); } - button2->selected=-1; + button2.lock()->selected=-1; } - if(button2->selected==data.menu.I(A::LOADOUT_SLOT)){ - button2->selected=-1; + if(button2.lock()->selected==data.menu.I(A::LOADOUT_SLOT)){ + button2.lock()->selected=-1; } } } - button->selected=data.menu.I(A::LOADOUT_SLOT); - data.game->SetLoadoutItem(button->selected,button->GetItem().lock()->ActualName()); + button.lock()->selected=data.menu.I(A::LOADOUT_SLOT); + data.game->SetLoadoutItem(button.lock()->selected,button.lock()->GetItem().lock()->ActualName()); return true; },InventoryCreator::Player_InventoryUpdate)END; Menu::AddInventoryListener(consumableWindow,"Consumables"); //We don't have to actually populate the inventory list because now when an item gets added, it will automatically add the correct component in for us. - inventoryWindow->ADD("Inventory Type Label",MenuLabel)({{0,-5},{windowSize.x-1,18}},"Consumables",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; + inventoryWindow->ADD("Inventory Type Label",MenuLabel)(geom2d::rect{{0,-5},{windowSize.x-1,18}},"Consumables",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; inventoryWindow->ADD("itemName",MenuLabel)(geom2d::rect(vf2d{2,90.f},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW)END; inventoryWindow->ADD("itemDescription",MenuLabel)(geom2d::rect(vf2d{2,117.f},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW)END; - auto okButton=inventoryWindow->ADD("OK Button",MenuComponent)({{windowSize.x/2-24,173.f},{48,12}},"Ok",[](MenuFuncData data){Menu::CloseMenu();return true;})END; + auto okButton=inventoryWindow->ADD("OK Button",MenuComponent)(geom2d::rect{{windowSize.x/2-24,173.f},{48,12}},"Ok",[](MenuFuncData data){Menu::CloseMenu();return true;})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/InventoryCreator.cpp b/Adventures in Lestoria/InventoryCreator.cpp index 8c7e27c7..edc88a95 100644 --- a/Adventures in Lestoria/InventoryCreator.cpp +++ b/Adventures in Lestoria/InventoryCreator.cpp @@ -72,7 +72,7 @@ std::function vf2d buttonSize=component.options.size; int totalSpacing=component.options.padding+buttonSize.x; - component.ADD("item_"+cat+"_"+std::to_string(itemIndex),MenuItemButton)({{float(totalSpacing*x),float(totalSpacing*y)},buttonSize},Inventory::get(cat),itemIndex,component.inventoryButtonClickAction,component.inventoryButtonHoverAction,component.inventoryButtonMouseOutAction,component.parentMenu,component.itemNameLabelName,component.itemDescriptionLabelName,component.inventoryButtonsActive?IconButtonAttr::SELECTABLE:IconButtonAttr::NOT_SELECTABLE)END + component.ADD("item_"+cat+"_"+std::to_string(itemIndex),MenuItemButton)(geom2d::rect{{float(totalSpacing*x),float(totalSpacing*y)},buttonSize},Inventory::get(cat),itemIndex,component.inventoryButtonClickAction,component.inventoryButtonHoverAction,component.inventoryButtonMouseOutAction,component.parentMenu,component.itemNameLabelName,component.itemDescriptionLabelName,component.inventoryButtonsActive?IconButtonAttr::SELECTABLE:IconButtonAttr::NOT_SELECTABLE)END ->SetCompactDescriptions(component.compact); }; #pragma endregion @@ -91,7 +91,7 @@ std::function vf2d buttonSize=c->options.size; vf2d totalSpacing={c->options.padding+buttonSize.x,c->options.padding+buttonSize.y}; - auto newItem=c->ADD("item_"+cat+"_"+std::to_string(itemIndex),RowItemDisplay)({totalSpacing*vf2d{float(x),float(y)},buttonSize},Inventory::GetInventorySlot(cat,itemIndex),c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; + auto newItem=c->ADD("item_"+cat+"_"+std::to_string(itemIndex),RowItemDisplay)(geom2d::rect{totalSpacing*vf2d{float(x),float(y)},buttonSize},Inventory::GetInventorySlot(cat,itemIndex),c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; newItem->SetCompactDescriptions(c->compact); newItem->SetPriceLabelType(c->priceLabel); newItem->SetHoverFunc(c->inventoryButtonHoverAction); @@ -128,7 +128,7 @@ std::function vf2d buttonSize=c->options.size; vf2d totalSpacing={c->options.padding+buttonSize.x,c->options.padding+buttonSize.y}; - auto newItem=c->ADD("merchant_item_"+cat+"_"+std::to_string(itemIndex),RowItemDisplay)({totalSpacing*vf2d{float(x),float(y)},buttonSize},Merchant::GetCurrentTravelingMerchant().GetShopItems()[itemIndex],c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; + auto newItem=c->ADD("merchant_item_"+cat+"_"+std::to_string(itemIndex),RowItemDisplay)(geom2d::rect{totalSpacing*vf2d{float(x),float(y)},buttonSize},Merchant::GetCurrentTravelingMerchant().GetShopItems()[itemIndex],c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; newItem->SetCompactDescriptions(c->compact); newItem->SetPriceLabelType(c->priceLabel); newItem->SetHoverFunc(c->inventoryButtonHoverAction); @@ -139,15 +139,13 @@ std::function #pragma region Row Player Weapons Updates std::function InventoryCreator::RowPlayerWeapons_InventorySlotsUpdate= [](InventoryScrollableWindowComponent&component,ITCategory cat){ - std::vector>weapons; - std::copy_if(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),std::back_inserter(weapons),[](std::weak_ptr item){return item.lock()->IsWeapon();}); component.RemoveAllComponents(); component.AddButtonOnSlotUpdate(cat); }; std::function InventoryCreator::RowPlayerWeapons_AddButtonOnSlotUpdate= [](InventoryScrollableWindowComponent&component,ITCategory cat){ std::vector>weapons; - std::copy_if(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),std::back_inserter(weapons),[](std::weak_ptr item){return item.lock()->IsWeapon();}); + std::copy_if(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),std::back_inserter(weapons),[](std::shared_ptritem){return item->IsWeapon();}); RowInventoryScrollableWindowComponent*c=DYNAMIC_CAST(&component); @@ -160,7 +158,7 @@ std::function int x=int((invSize-1)%invWidth); int y=int((invSize-1)/invWidth); int itemIndex=y*invWidth+x; - auto newItem=c->ADD("item_Weapon_"+std::to_string(itemIndex),RowItemDisplay)({totalSpacing*vf2d{float(x),float(y)},buttonSize},weapon,c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; + auto newItem=c->ADD("item_Weapon_"+std::to_string(itemIndex),RowItemDisplay)(geom2d::rect{totalSpacing*vf2d{float(x),float(y)},buttonSize},weapon,c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; newItem->SetCompactDescriptions(c->compact); newItem->SetPriceLabelType(c->priceLabel); newItem->SetHoverFunc(c->inventoryButtonHoverAction); @@ -173,15 +171,13 @@ std::function #pragma region Row Player Armor Updates std::function InventoryCreator::RowPlayerArmor_InventorySlotsUpdate= [](InventoryScrollableWindowComponent&component,ITCategory cat){ - std::vector>armor; - std::copy_if(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),std::back_inserter(armor),[](std::weak_ptr item){return item.lock()->IsArmor();}); component.RemoveAllComponents(); component.AddButtonOnSlotUpdate(cat); }; std::function InventoryCreator::RowPlayerArmor_AddButtonOnSlotUpdate= [](InventoryScrollableWindowComponent&component,ITCategory cat){ std::vector>armor; - std::copy_if(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),std::back_inserter(armor),[](std::weak_ptr item){return item.lock()->IsArmor();}); + std::copy_if(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),std::back_inserter(armor),[](std::shared_ptritem){return item->IsArmor();}); RowInventoryScrollableWindowComponent*c=DYNAMIC_CAST(&component); @@ -194,7 +190,7 @@ std::function int x=int((invSize-1)%invWidth); int y=int((invSize-1)/invWidth); int itemIndex=y*invWidth+x; - auto newItem=c->ADD("item_Armor_"+std::to_string(itemIndex),RowItemDisplay)({totalSpacing*vf2d{float(x),float(y)},buttonSize},armor,c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; + auto newItem=c->ADD("item_Armor_"+std::to_string(itemIndex),RowItemDisplay)(geom2d::rect{totalSpacing*vf2d{float(x),float(y)},buttonSize},armor,c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; newItem->SetCompactDescriptions(c->compact); newItem->SetPriceLabelType(c->priceLabel); newItem->SetHoverFunc(c->inventoryButtonHoverAction); diff --git a/Adventures in Lestoria/InventoryScrollableWindowComponent.h b/Adventures in Lestoria/InventoryScrollableWindowComponent.h index 71777c7a..2b82d84d 100644 --- a/Adventures in Lestoria/InventoryScrollableWindowComponent.h +++ b/Adventures in Lestoria/InventoryScrollableWindowComponent.h @@ -80,8 +80,8 @@ public: virtual inline void Update(AiL*game)override{ ScrollableWindowComponent::Update(game); bool noneHovered=true; - for(MenuComponent*component:components){ - if(component->hovered){ + for(std::weak_ptrcomponent:components){ + if(component.lock()->hovered){ noneHovered=false; break; } @@ -93,9 +93,9 @@ public: } virtual inline void SetCompactDescriptions(CompactText compact){ this->compact=compact; - for(MenuComponent*component:components){ - MenuItemButton*itemButton=DYNAMIC_CAST(component); - itemButton->SetCompactDescriptions(compact); + for(std::weak_ptrcomponent:components){ + std::weak_ptritemButton=DYNAMIC_POINTER_CAST(component.lock()); + itemButton.lock()->SetCompactDescriptions(compact); } } protected: diff --git a/Adventures in Lestoria/InventoryWindow.cpp b/Adventures in Lestoria/InventoryWindow.cpp index 0e2fd053..fcf47e73 100644 --- a/Adventures in Lestoria/InventoryWindow.cpp +++ b/Adventures in Lestoria/InventoryWindow.cpp @@ -30,7 +30,7 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -Portions of this software are copyright © 2023 The FreeType +Portions of this software are copyright � 2023 The FreeType Project (www.freetype.org). Please see LICENSE_FT.txt for more information. All rights reserved. */ @@ -58,8 +58,8 @@ using ButtonAttr::UNSELECTABLE_VIA_KEYBOARD; void Menu::InitializeInventoryWindow(){ Menu*inventoryWindow=CreateMenu(INVENTORY,CENTERED,game->GetScreenSize()-vi2d{52,52}); - inventoryWindow->ADD("Inventory Label",MenuLabel)({{0,0},{inventoryWindow->size.x-1,24}},"Inventory",2,SHADOW|OUTLINE|BACKGROUND)END; - inventoryWindow->ADD("Inventory Tabs Outline",MenuComponent)({{0,28},{72,inventoryWindow->size.y-44}},"",DO_NOTHING,UNSELECTABLE)END; + inventoryWindow->ADD("Inventory Label",MenuLabel)(geom2d::rect{{0,0},{inventoryWindow->size.x-1,24}},"Inventory",2,SHADOW|OUTLINE|BACKGROUND)END; + inventoryWindow->ADD("Inventory Tabs Outline",MenuComponent)(geom2d::rect{{0,28},{72,inventoryWindow->size.y-44}},"",DO_NOTHING,UNSELECTABLE)END; std::vector>categories; for(auto&[category,items]:ITEM_CATEGORIES){ @@ -75,22 +75,22 @@ void Menu::InitializeInventoryWindow(){ float buttonWidth=64; float textScaling=std::min(1.f,buttonWidth/textWidth); - auto button=inventoryWindow->ADD(category+" Inventory Tab",MenuComponent)({{2,30+yOffset},{68,16}},category,MenuType::ENUM_END, + auto button=inventoryWindow->ADD(category+" Inventory Tab",MenuComponent)(geom2d::rect{{2,30+yOffset},{68,16}},category,MenuType::ENUM_END, [&](MenuFuncData data){ //Close the old inventory window and show the proper one. Component(data.menu.GetType(),"Inventory Display - "+data.menu.S(A::LAST_INVENTORY_TYPE_OPENED))->Enable(false); Component(data.menu.GetType(),data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)+" Inventory Tab")->SetSelected(false); - Component(data.menu.GetType(),"Inventory Display - "+data.component->S(A::CATEGORY_NAME))->Enable(true); - Component(data.menu.GetType(),data.component->S(A::CATEGORY_NAME)+" Inventory Tab")->SetSelected(true); - data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)=data.component->S(A::CATEGORY_NAME); + Component(data.menu.GetType(),"Inventory Display - "+data.component.lock()->S(A::CATEGORY_NAME))->Enable(true); + Component(data.menu.GetType(),data.component.lock()->S(A::CATEGORY_NAME)+" Inventory Tab")->SetSelected(true); + data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)=data.component.lock()->S(A::CATEGORY_NAME); return true; - },{textScaling,1.f})END; + },vf2d{textScaling,1.f})END; button->SetSelectionType(HIGHLIGHT); button->S(A::CATEGORY_NAME)=category; - auto inventoryDisplay=inventoryWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)({{72,28},{150,inventoryWindow->size.y-44}},"Item Name Label","Item Description Label",DO_NOTHING, + auto inventoryDisplay=inventoryWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)(geom2d::rect{{72,28},{150,inventoryWindow->size.y-44}},"Item Name Label","Item Description Label",DO_NOTHING, [](MenuFuncData data){ - Component(data.menu.GetType(),"Item Icon")->SetItem(DYNAMIC_CAST(data.component)->GetItem()); + Component(data.menu.GetType(),"Item Icon")->SetItem(DYNAMIC_POINTER_CAST(data.component.lock())->GetItem()); return true; }, [](MenuFuncData data){ @@ -98,7 +98,7 @@ void Menu::InitializeInventoryWindow(){ return true; }, InventoryCreator::RowPlayer_InventoryUpdate, - {.padding=1,.size={137,28}})END; + InventoryWindowOptions{.padding=1,.size={137,28}})END; if(first){ inventoryWindow->S(A::LAST_INVENTORY_TYPE_OPENED)=category; @@ -116,25 +116,25 @@ void Menu::InitializeInventoryWindow(){ #pragma region Inventory Description float inventoryDescriptionWidth=inventoryWindow->pos.x+inventoryWindow->size.x-26-224; - inventoryWindow->ADD("Item Description Outline",MenuLabel)({{224,28},{inventoryDescriptionWidth,inventoryWindow->size.y-44}},"",1,LEFT_ALIGN|OUTLINE|BACKGROUND)END; - inventoryWindow->ADD("Item Icon",MenuItemItemButton)({{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END; - inventoryWindow->ADD("Item Name Label",MenuLabel)({{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,LEFT_ALIGN|SHADOW)END; - inventoryWindow->ADD("Item Description Label",MenuLabel)({{226,94},{inventoryDescriptionWidth-6,inventoryWindow->size.y-44-66}},"",0.5f,LEFT_ALIGN|SHADOW)END; + inventoryWindow->ADD("Item Description Outline",MenuLabel)(geom2d::rect{{224,28},{inventoryDescriptionWidth,inventoryWindow->size.y-44}},"",1,LEFT_ALIGN|OUTLINE|BACKGROUND)END; + inventoryWindow->ADD("Item Icon",MenuItemItemButton)(geom2d::rect{{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END; + inventoryWindow->ADD("Item Name Label",MenuLabel)(geom2d::rect{{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,LEFT_ALIGN|SHADOW)END; + inventoryWindow->ADD("Item Description Label",MenuLabel)(geom2d::rect{{226,94},{inventoryDescriptionWidth-6,inventoryWindow->size.y-44-66}},"",0.5f,LEFT_ALIGN|SHADOW)END; #pragma endregion #pragma region Money Display vf2d moneyIconPos={224+inventoryDescriptionWidth-24,28+inventoryWindow->size.y-44+6}; - auto moneyIcon=inventoryWindow->ADD("Money Icon",MenuIconButton)({moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END; + auto moneyIcon=inventoryWindow->ADD("Money Icon",MenuIconButton)(geom2d::rect{moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END; std::string moneyText=std::to_string(game->GetPlayer()->GetMoney()); vf2d moneyTextSize=game->GetTextSizeProp(moneyText)*2; - auto moneyDisplay=inventoryWindow->ADD("Money Label",PlayerMoneyLabel)({moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,SHADOW|LEFT_ALIGN|FIT_TO_LABEL)END; + auto moneyDisplay=inventoryWindow->ADD("Money Label",PlayerMoneyLabel)(geom2d::rect{moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,SHADOW|LEFT_ALIGN|FIT_TO_LABEL)END; moneyDisplay->SetRightAlignment(true); Player::AddMoneyListener(moneyDisplay); #pragma endregion - inventoryWindow->ADD("Back Button",MenuComponent)({{inventoryWindow->size.x/2-48,28+inventoryWindow->size.y-44+6},{96,24}},"Back",MenuType::ENUM_END, + inventoryWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{inventoryWindow->size.x/2-48,28+inventoryWindow->size.y-44+6},{96,24}},"Back",MenuType::ENUM_END, [](MenuFuncData data){ Menu::CloseMenu(); return true; - },{2,2})END; + },vf2d{2.f,2.f})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/ItemLoadoutWindow.cpp b/Adventures in Lestoria/ItemLoadoutWindow.cpp index 7be5001e..682104d4 100644 --- a/Adventures in Lestoria/ItemLoadoutWindow.cpp +++ b/Adventures in Lestoria/ItemLoadoutWindow.cpp @@ -50,29 +50,29 @@ void Menu::InitializeItemLoadoutWindow(){ float itemLoadoutWindowWidth=(game->GetScreenSize().x-5.f); - itemLoadoutWindow->ADD("Loadout Label",MenuLabel)({{0,24},{itemLoadoutWindowWidth,24}},"Loadout",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; + itemLoadoutWindow->ADD("Loadout Label",MenuLabel)(geom2d::rect{{0,24},{itemLoadoutWindowWidth,24}},"Loadout",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; float buttonBorderPadding=64; - itemLoadoutWindow->ADD("Loadout Item 1",MenuItemItemButton)({{64,96},{48,48}},game->GetLoadoutItem(0),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=0; return true;},[](MenuFuncData data){return true;},[](MenuFuncData data){ + itemLoadoutWindow->ADD("Loadout Item 1",MenuItemItemButton)(geom2d::rect{{64,96},{48,48}},game->GetLoadoutItem(0),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=0; return true;},[](MenuFuncData data){return true;},[](MenuFuncData data){ Component(ITEM_LOADOUT,"Item Name Label")->SetLabel(""); Component(ITEM_LOADOUT,"Item Description")->SetLabel(""); return true; },"Item Name Label","Item Description")END; - itemLoadoutWindow->ADD("Loadout Item 2",MenuItemItemButton)({{itemLoadoutWindowWidth/2-24,96},{48,48}},game->GetLoadoutItem(1),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=1;return true;},[](MenuFuncData data){return true;},[](MenuFuncData data){ + itemLoadoutWindow->ADD("Loadout Item 2",MenuItemItemButton)(geom2d::rect{{itemLoadoutWindowWidth/2-24,96},{48,48}},game->GetLoadoutItem(1),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=1;return true;},[](MenuFuncData data){return true;},[](MenuFuncData data){ Component(ITEM_LOADOUT,"Item Name Label")->SetLabel(""); Component(ITEM_LOADOUT,"Item Description")->SetLabel(""); return true; },"Item Name Label","Item Description")END; - itemLoadoutWindow->ADD("Loadout Item 3",MenuItemItemButton)({{itemLoadoutWindowWidth-48-64,96},{48,48}},game->GetLoadoutItem(2),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=2;return true;},[](MenuFuncData data){return true;},[](MenuFuncData data){ + itemLoadoutWindow->ADD("Loadout Item 3",MenuItemItemButton)(geom2d::rect{{itemLoadoutWindowWidth-48-64,96},{48,48}},game->GetLoadoutItem(2),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=2;return true;},[](MenuFuncData data){return true;},[](MenuFuncData data){ Component(ITEM_LOADOUT,"Item Name Label")->SetLabel(""); Component(ITEM_LOADOUT,"Item Description")->SetLabel(""); return true; },"Item Name Label","Item Description")END; - itemLoadoutWindow->ADD("Item Name Label",MenuLabel)({{0,158},{itemLoadoutWindowWidth,12}},"",1,ComponentAttr::SHADOW)END; - itemLoadoutWindow->ADD("Item Description",MenuLabel)({{0,170},{itemLoadoutWindowWidth,24}},"",1,ComponentAttr::SHADOW)END; + itemLoadoutWindow->ADD("Item Name Label",MenuLabel)(geom2d::rect{{0,158},{itemLoadoutWindowWidth,12}},"",1,ComponentAttr::SHADOW)END; + itemLoadoutWindow->ADD("Item Description",MenuLabel)(geom2d::rect{{0,170},{itemLoadoutWindowWidth,24}},"",1,ComponentAttr::SHADOW)END; - itemLoadoutWindow->ADD("Start Level Button",MenuComponent)({{itemLoadoutWindowWidth/2-32,214},{64,16}},"Start",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;})END; + itemLoadoutWindow->ADD("Start Level Button",MenuComponent)(geom2d::rect{{itemLoadoutWindowWidth/2-32,214},{64,16}},"Start",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/LevelCompleteWindow.cpp b/Adventures in Lestoria/LevelCompleteWindow.cpp index 16bf286a..8858645d 100644 --- a/Adventures in Lestoria/LevelCompleteWindow.cpp +++ b/Adventures in Lestoria/LevelCompleteWindow.cpp @@ -51,16 +51,16 @@ void Menu::InitializeLevelCompleteWindow(){ Menu*levelCompleteWindow=Menu::CreateMenu(LEVEL_COMPLETE,windowSize.pos,windowSize.size); - levelCompleteWindow->ADD("Stage Complete Label",MenuLabel)({{0,4},{windowSize.size.x-1.f,20}},"Stage Completed",2,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW)END; + levelCompleteWindow->ADD("Stage Complete Label",MenuLabel)(geom2d::rect{{0,4},{windowSize.size.x-1.f,20}},"Stage Completed",2,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW)END; - levelCompleteWindow->ADD("Monster Loot Outline",MenuComponent)({{0,32},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; - levelCompleteWindow->ADD("Monster Loot Label",MenuLabel)({{0,32},{windowSize.size.x-80.f,12}},"Monster Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; - auto monsterLootWindow=levelCompleteWindow->ADD("Monster Loot Window",InventoryScrollableWindowComponent)({{0,44},{windowSize.size.x-80.f,60}},"Monster Loot Popup Item Name","Monster Loot Popup Item Description",DO_NOTHING,InventoryCreator::Player_InventoryUpdate)END; + levelCompleteWindow->ADD("Monster Loot Outline",MenuComponent)(geom2d::rect{{0,32},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + levelCompleteWindow->ADD("Monster Loot Label",MenuLabel)(geom2d::rect{{0,32},{windowSize.size.x-80.f,12}},"Monster Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; + auto monsterLootWindow=levelCompleteWindow->ADD("Monster Loot Window",InventoryScrollableWindowComponent)(geom2d::rect{{0,44},{windowSize.size.x-80.f,60}},"Monster Loot Popup Item Name","Monster Loot Popup Item Description",DO_NOTHING,InventoryCreator::Player_InventoryUpdate)END; Menu::AddInventoryListener(monsterLootWindow,"Monster Loot"); - levelCompleteWindow->ADD("Stage Loot Outline",MenuComponent)({{0,108},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; - levelCompleteWindow->ADD("Stage Loot Label",MenuLabel)({{0,108},{windowSize.size.x-80.f,12}},"Stage Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; - auto stageLootWindow=levelCompleteWindow->ADD("Stage Loot Window",InventoryScrollableWindowComponent)({{0,120},{windowSize.size.x-80.f,60}},"Stage Loot Popup Item Name","Stage Loot Popup Item Description",DO_NOTHING,InventoryCreator::Player_InventoryUpdate)END; + levelCompleteWindow->ADD("Stage Loot Outline",MenuComponent)(geom2d::rect{{0,108},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + levelCompleteWindow->ADD("Stage Loot Label",MenuLabel)(geom2d::rect{{0,108},{windowSize.size.x-80.f,12}},"Stage Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; + auto stageLootWindow=levelCompleteWindow->ADD("Stage Loot Window",InventoryScrollableWindowComponent)(geom2d::rect{{0,120},{windowSize.size.x-80.f,60}},"Stage Loot Popup Item Name","Stage Loot Popup Item Description",DO_NOTHING,InventoryCreator::Player_InventoryUpdate)END; Menu::AddInventoryListener(stageLootWindow,"Stage Loot"); auto nextButtonAction=[](MenuFuncData data){ @@ -69,13 +69,13 @@ void Menu::InitializeLevelCompleteWindow(){ return true; }; - levelCompleteWindow->ADD("Level Details Outline",MenuComponent)({{windowSize.size.x-72.f,32},{71,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; - levelCompleteWindow->ADD("Level EXP Gain Outline",MenuLabel)({{windowSize.size.x-72.f,104},{71,36}},"+ Exp",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - levelCompleteWindow->ADD("Next Button",MenuComponent)({{windowSize.size.x-72.f,144},{71,32}},"Next",nextButtonAction)END; + levelCompleteWindow->ADD("Level Details Outline",MenuComponent)(geom2d::rect{{windowSize.size.x-72.f,32},{71,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + levelCompleteWindow->ADD("Level EXP Gain Outline",MenuLabel)(geom2d::rect{{windowSize.size.x-72.f,104},{71,36}},"+ Exp",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + levelCompleteWindow->ADD("Next Button",MenuComponent)(geom2d::rect{{windowSize.size.x-72.f,144},{71,32}},"Next",nextButtonAction)END; - levelCompleteWindow->ADD("Monster Loot Popup Item Name",PopupMenuLabel)({{0,108},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - levelCompleteWindow->ADD("Monster Loot Popup Item Description",PopupMenuLabel)({{0,120},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + levelCompleteWindow->ADD("Monster Loot Popup Item Name",PopupMenuLabel)(geom2d::rect{{0,108},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + levelCompleteWindow->ADD("Monster Loot Popup Item Description",PopupMenuLabel)(geom2d::rect{{0,120},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - levelCompleteWindow->ADD("Stage Loot Popup Item Name",PopupMenuLabel)({{0,32},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - levelCompleteWindow->ADD("Stage Loot Popup Item Description",PopupMenuLabel)({{0,44},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + levelCompleteWindow->ADD("Stage Loot Popup Item Name",PopupMenuLabel)(geom2d::rect{{0,32},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + levelCompleteWindow->ADD("Stage Loot Popup Item Description",PopupMenuLabel)(geom2d::rect{{0,44},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; } \ No newline at end of file diff --git a/Adventures in Lestoria/LoadGameWindow.cpp b/Adventures in Lestoria/LoadGameWindow.cpp index 200ba9a2..faeaf73f 100644 --- a/Adventures in Lestoria/LoadGameWindow.cpp +++ b/Adventures in Lestoria/LoadGameWindow.cpp @@ -42,7 +42,7 @@ All rights reserved. void Menu::InitializeLoadGameWindow(){ Menu*loadGameWindow=CreateMenu(LOAD_GAME,CENTERED,vi2d{96,120}); - loadGameWindow->ADD("Game Files Label",MenuLabel)({{-8,-12},{112,12}},"Load Game",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - loadGameWindow->ADD("Game Files List",ScrollableWindowComponent)({{-8,4},{112,116}})END; - loadGameWindow->ADD("Go Back Button",MenuComponent)({{24,124},{48,12}},"Back",[](MenuFuncData menu){Menu::CloseMenu();return true;})END; + loadGameWindow->ADD("Game Files Label",MenuLabel)(geom2d::rect{{-8,-12},{112,12}},"Load Game",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + loadGameWindow->ADD("Game Files List",ScrollableWindowComponent)(geom2d::rect{{-8,4},{112,116}})END; + loadGameWindow->ADD("Go Back Button",MenuComponent)(geom2d::rect{{24,124},{48,12}},"Back",[](MenuFuncData menu){Menu::CloseMenu();return true;})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/MainMenuWindow.cpp b/Adventures in Lestoria/MainMenuWindow.cpp index 89578e58..e06b9f34 100644 --- a/Adventures in Lestoria/MainMenuWindow.cpp +++ b/Adventures in Lestoria/MainMenuWindow.cpp @@ -47,7 +47,7 @@ using A=Attribute; void Menu::InitializeMainMenuWindow(){ Menu*mainMenuWindow=CreateMenu(MAIN_MENU,vi2d{132,120},vi2d{96,96}); - mainMenuWindow->ADD("New Game Button",MenuComponent)({{12,4},{72,24}},"New Game",[&](MenuFuncData data){ + mainMenuWindow->ADD("New Game Button",MenuComponent)(geom2d::rect{{12,4},{72,24}},"New Game",[&](MenuFuncData data){ game->TextEntryEnable(true); #ifdef __EMSCRIPTEN__ data.menu.S(A::NEXT_MENU)="New Game"; @@ -61,7 +61,7 @@ void Menu::InitializeMainMenuWindow(){ #endif return true; })END; - mainMenuWindow->ADD("Load Game Button",MenuComponent)({{12,36},{72,24}},"Load Game",[](MenuFuncData data){ + mainMenuWindow->ADD("Load Game Button",MenuComponent)(geom2d::rect{{12,36},{72,24}},"Load Game",[](MenuFuncData data){ #ifdef __EMSCRIPTEN__ data.menu.S(A::NEXT_MENU)="Load Game"; if(SaveFile::GetUserID().length()==0){ @@ -77,7 +77,7 @@ void Menu::InitializeMainMenuWindow(){ #endif return true; })END; - mainMenuWindow->ADD("Quit Game Button",MenuComponent)({{12,68},{72,24}},"Quit Game",[](MenuFuncData data){ + mainMenuWindow->ADD("Quit Game Button",MenuComponent)(geom2d::rect{{12,68},{72,24}},"Quit Game",[](MenuFuncData data){ game->EndGame(); return true; })END; diff --git a/Adventures in Lestoria/Menu.cpp b/Adventures in Lestoria/Menu.cpp index 1daa3da9..a2cff2ed 100644 --- a/Adventures in Lestoria/Menu.cpp +++ b/Adventures in Lestoria/Menu.cpp @@ -53,12 +53,11 @@ std::vectorMenu::stack; std::mapMenu::menus; std::string Menu::themeSelection="BlueDefault"; safeunorderedmapMenu::themes; -safemap>Menu::inventoryListeners; -safemap>Menu::merchantInventoryListeners; -std::vectorMenu::equipStatListeners; -std::vectorMenu::chapterListeners; +safemap>>Menu::inventoryListeners; +safemap>>Menu::merchantInventoryListeners; +std::vector>Menu::equipStatListeners; +std::vector>Menu::chapterListeners; const vf2d Menu::CENTERED = {-456,-456}; -std::vectorMenu::unhandledComponents; ////////////////////////////////////////////////////////////////////////////////////////////////// ///__///////////////////////////////////////////////////////////////////////////////////////////// //| |//////////////////////////////////////////////////////////////////////////////////////////// @@ -85,12 +84,6 @@ Menu::Menu(vf2d pos,vf2d size) this->window=ViewPort::rectViewPort({-24,-24},this->size+vi2d{48,48},this->pos); } -Menu::~Menu(){ - for(auto&[key,value]:components){ - delete value; - } -} - void Menu::InitializeMenus(){ #define MAX_MENUS 32 stack.reserve(MAX_MENUS); @@ -119,28 +112,11 @@ void Menu::InitializeMenus(){ if(menus.count(type)==0){ ERR("WARNING! Menu Type "<buttons.SetInitialized(); - menus[type]->keyboardButtons.SetInitialized(); for(auto&[key,value]:menus[type]->components){ - MenuComponent*component=value; - component->AfterCreate(); + value->AfterCreate(); } if(menus.size()>MAX_MENUS)ERR("WARNING! Exceeded maximum expected menu count of "<0){ - std::cout<<"WARNING! There are "<parentMenu<<" Label: "<label<memoryLeakInfo.first<<" // Last Component: "<memoryLeakInfo.second<IsFocused()||selection==vi2d{-1,-1}||buttons[selection.y][selection.x]->disabled)return; - if(buttons[selection.y][selection.x]->draggable){ + if(!game->IsFocused()||selection.expired()||selection.lock()->disabled)return; + + if(selection.lock()->draggable){ if(buttonHoldTime<"ThemeGlobal.MenuHoldTime"_F){ CheckClickAndPerformMenuSelect(game); }else{ - draggingComponent=buttons[selection.y][selection.x]->PickUpDraggableItem(); + draggingComponent=std::move(selection.lock()->PickUpDraggableItem()); buttonHoldTime=0; } }else{ @@ -171,12 +148,12 @@ void Menu::HoverMenuSelect(AiL*game){ } void Menu::MenuSelect(AiL*game){ - if(!game->IsFocused()||selection==vi2d{-1,-1}||(buttons[selection.y][selection.x]->disabled||buttons[selection.y][selection.x]->grayedOut))return; - bool buttonStillValid=buttons[selection.y][selection.x]->onClick(MenuFuncData{*this,game,buttons[selection.y][selection.x],(ScrollableWindowComponent*)buttons[selection.y][selection.x]->parentComponent}); + if(!game->IsFocused()||selection.expired()||selection.lock()->disabled||selection.lock()->grayedOut)return; + bool buttonStillValid=selection.lock()->onClick(MenuFuncData{*this,game,selection,dynamic_pointer_cast(selection.lock()->parentComponent.lock())}); if(buttonStillValid){ - if(buttons[selection.y][selection.x]->menuDest!=MenuType::ENUM_END){ + if(selection.lock()->menuDest!=MenuType::ENUM_END){ if(stack.size()<32){ - stack.push_back(menus[buttons[selection.y][selection.x]->menuDest]);//Navigate to the next menu. + stack.push_back(menus[selection.lock()->menuDest]);//Navigate to the next menu. }else{ ERR("WARNING! Exceeded menu stack size limit!") } @@ -185,10 +162,7 @@ void Menu::MenuSelect(AiL*game){ } void Menu::Update(AiL*game){ - if(buttons.count(selection.y)==0)selection={-1,-1}; - if(selection.x<0||selection.x>=buttons[selection.y].size()){selection={-1,-1};} - - if(draggingComponent==nullptr){ + if(!draggingComponent){ HoverMenuSelect(game); } @@ -196,11 +170,9 @@ void Menu::Update(AiL*game){ SetMouseNavigation(true); } - for(auto&[key,value]:buttons){ - for(auto&button:value){ - if(!button->disabled){ - button->hovered=false; - } + for(auto&[key,button]:components){ + if(!button->disabled){ + button->hovered=false; } } @@ -208,64 +180,54 @@ void Menu::Update(AiL*game){ if(!UsingMouseNavigation()){ if(!game->IsTextEntryEnabled()){ - if(selection!=vi2d{-1,-1}){ - buttons[selection.y][selection.x]->hovered=true; + if(!selection.expired()){ + selection.lock()->hovered=true; itemHovered=true; } } }else{ - selection={-1,-1}; - for(auto&[key,value]:buttons){ - int index=0; - for(auto&button:value){ - if(!button->disabled&&!button->grayedOut){ - if(button->GetHoverState(game)){ - button->hovered=true; + selection={}; + for(auto&[key,component]:components){ + if(component->selectable){ + if(!component->disabled&&!component->grayedOut){ + if(component->GetHoverState(game)){ + component->hovered=true; itemHovered=true; - selection.y=key; - selection.x=index; + selection=component; } } - index++; } } } - if(itemHovered&&draggingComponent==nullptr&&selection!=vi2d{-1,-1}&&!UsingMouseNavigation()&&(game->KEY_CONFIRM.Held())){ + if(itemHovered&&draggingComponent&&!selection.expired()&&!UsingMouseNavigation()&&(game->KEY_CONFIRM.Held())){ buttonHoldTime+=game->GetElapsedTime(); }else{ buttonHoldTime=0; } - if(draggingComponent!=nullptr){ - MenuComponent*selectedComponent=nullptr; - if(selection!=vi2d{-1,-1}){ - selectedComponent=buttons[selection.y][selection.x]; - } - - + if(draggingComponent){ auto ClearDraggingComponent=[&](){ - delete draggingComponent; //We know we allocated a new instance of this, so we will now free it. - draggingComponent=nullptr; + draggingComponent={}; }; if(!UsingMouseNavigation()){ if(!game->IsTextEntryEnabled()){ if(game->KEY_CONFIRM.Released()){ - if(selectedComponent==nullptr){//Dropping over an empty area. + if(selection.expired()){//Dropping over an empty area. ClearDraggingComponent(); }else - if(selectedComponent->DropDraggableItem(draggingComponent)){ + if(selection.lock()->DropDraggableItem(std::move(draggingComponent))){ ClearDraggingComponent(); } } } }else{ if(game->KEY_CONFIRM.Released()){ - if(selectedComponent==nullptr){//Dropping over an empty area. + if(selection.expired()){//Dropping over an empty area. ClearDraggingComponent(); }else - if(selectedComponent->DropDraggableItem(draggingComponent)){ + if(selection.lock()->DropDraggableItem(std::move(draggingComponent))){ ClearDraggingComponent(); } } @@ -276,29 +238,11 @@ void Menu::Update(AiL*game){ KeyboardButtonNavigation(game,pos); } - for(auto&[key,value]:buttons){ - for(auto&button:value){ - if(button->renderInMain){ - button->_BeforeUpdate(game); - } - } - } - for(auto&component:displayComponents){ - if(component->renderInMain){ - component->_BeforeUpdate(game); - } + for(auto&[key,component]:components){ + component->_BeforeUpdate(game); } - for(auto&[key,value]:buttons){ - for(auto&button:value){ - if(button->renderInMain){ - button->_Update(game); - } - } - } - for(auto&component:displayComponents){ - if(component->renderInMain){ - component->_Update(game); - } + for(auto&[key,component]:components){ + component->_Update(game); } }; @@ -309,10 +253,9 @@ void Menu::Draw(AiL*game){ DrawTiledWindowBackground(game,pos,size,GetRenderColor()); } - std::vectorallComponents; - std::copy(displayComponents.begin(),displayComponents.end(),std::back_inserter(allComponents)); - std::for_each(buttons.begin(),buttons.end(),[&](auto&pair){std::copy(pair.second.begin(),pair.second.end(),std::back_inserter(allComponents));}); - std::sort(allComponents.begin(),allComponents.end(),[](MenuComponent*c1,MenuComponent*c2){return c1->depth>c2->depth;}); + std::vector>allComponents; + std::for_each(components.begin(),components.end(),[&](auto&pair){allComponents.push_back(pair.second);}); + std::sort(allComponents.begin(),allComponents.end(),[](std::weak_ptrc1,std::weak_ptrc2){return c1.lock()->depth>c2.lock()->depth;}); if(GetCurrentTheme().IsScaled()){ DrawScaledWindowBorder(game,pos,size,GetRenderColor()); @@ -321,23 +264,22 @@ void Menu::Draw(AiL*game){ } for(const auto&component:allComponents){ - if(component->renderInMain){ - component->_DrawDecal(window,this==Menu::stack.back()); + if(!component.expired()&&component.lock()->renderInMain){ + component.lock()->_DrawDecal(window,this==Menu::stack.back()); } } - if(draggingComponent!=nullptr){ + if(draggingComponent){ vf2d offsetPos=draggingComponent->rect.pos; if(!UsingMouseNavigation()){ - MenuComponent*selectedComponent=buttons[selection.y][selection.x]; vf2d drawOffset{}; - if(selectedComponent->parentComponent!=nullptr){ - ScrollableWindowComponent*scrollableComponent=DYNAMIC_CAST(selectedComponent->parentComponent); - if(scrollableComponent!=nullptr){ - drawOffset+=scrollableComponent->GetScrollAmount(); + if(!selection.expired()){ + if(!selection.lock()->parentComponent.expired()){ + std::weak_ptrscrollableComponent=DYNAMIC_POINTER_CAST(selection.lock()->parentComponent.lock()); + drawOffset+=scrollableComponent.lock()->GetScrollAmount(); } + draggingComponent->V(A::DRAW_OFFSET)=drawOffset+pos-offsetPos+selection.lock()->rect.pos+vi2d{1,-4}; } - draggingComponent->V(A::DRAW_OFFSET)=drawOffset+pos-offsetPos+selectedComponent->rect.pos+vi2d{1,-4}; draggingComponent->DrawDecal(window,this==Menu::stack.back()); }else{ draggingComponent->V(A::DRAW_OFFSET)-offsetPos+game->GetMousePos(); @@ -352,132 +294,19 @@ void Menu::OpenMenu(MenuType menu,bool cover){ } void Menu::KeyboardButtonNavigation(AiL*game,vf2d menuPos){ - vi2d prevSelection=selection; - if(game->RightPressed()){ - if(selection==vi2d{-1,-1})return; - SetMouseNavigation(false); - selection.x=(size_t(selection.x)+1)%keyboardButtons[selection.y].size(); - } - if(game->LeftPressed()){ - if(selection==vi2d{-1,-1})return; - selection.x--; - SetMouseNavigation(false); - if(selection.x<0)selection.x+=int32_t(keyboardButtons[selection.y].size()); - } - if(game->DownPressed()||game->UpPressed()){ - if(game->DownPressed()){ - SetMouseNavigation(false); - bool found=false; - bool selectedItem=false; - if(selection==vi2d{-1,-1}){ - //Highlight first item. - for(auto&[key,value]:keyboardButtons){ - selection.y=key; - break; - } - }else{ - for(auto&[key,value]:keyboardButtons){ - if(found){ //Once we discover the previous element, the next element becomes our next selection. - int previousButtonX=int(keyboardButtons[selection.y][selection.x]->rect.pos.x); - selection.y=key; - int index=0; - for(auto&button:value){ //Try to match a button in the same column as this button first. - if(previousButtonX==button->rect.pos.x){ - selection.x=index; - break; - } - index++; - } - selectedItem=true; - break; - } - if(key==selection.y - //It's entirely possible this button was selected from the button selection list and may be out-of-bounds here. - &&selection.x>=0&&selection.xUpPressed()){ - SetMouseNavigation(false); - if(selection==vi2d{-1,-1}){ - //Highlight last item. - for(auto&[key,value]:keyboardButtons){ - selection.y=key; - } - }else{ - int prevInd=-1; - for(auto&[key,value]:keyboardButtons){ - if(key==selection.y&& - //It's entirely possible this button was selected from the button selection list and may be out-of-bounds here. - selection.x>=0&&selection.xrect.pos.x); - selection.y=prevInd; - int index=0; - for(auto&button:keyboardButtons[prevInd]){ //Try to match a button in the same column as this button first. - if(previousButtonX==button->rect.pos.x){ - selection.x=index; - break; - } - index++; - } - }else{ //Since we didn't find it, it means we're at the top of the list or the list is empty. Go to the last element and use that one. - int lastInd=-1; - for(auto&[key,value]:keyboardButtons){ - lastInd=key; - } - selection.y=lastInd; - } - } - } - //In both cases, we should clamp the X index to make sure it's still valid. - if(selection.y!=-1){ - selection.x=std::clamp(selection.x,0,int(keyboardButtons[selection.y].size())-1); - }else{ - selection.x=-1; - } - } + std::weak_ptrprevSelection=selection; + if(game->KEY_CONFIRM.Pressed()){ SetMouseNavigation(game->GetMouse(0).bPressed); //If a click occurs we use mouse controls. - if(!UsingMouseNavigation()){ - buttonHoldTime=0; - //Key presses automatically highlight the first button if it's not highlighted. - if(selection==vi2d{-1,-1}&&buttons.size()>0){ - //Find the first possible button entry in the map... - int firstInd=-1; - for(auto&[key,value]:buttons){ - if(buttons[key].size()>0){ - firstInd=key; - break; - } - } - if(firstInd!=-1){ //This means we found a valid menu item. If we didn't find one don't highlight any menu item... - selection={0,firstInd}; - } - } - }else{ - buttonHoldTime=0; - } + buttonHoldTime=0; } - if(prevSelection!=selection){ - if(selection!=vi2d{-1,-1}&&(buttons[selection.y][selection.x]->disabled||buttons[selection.y][selection.x]->grayedOut)){ + if(&*prevSelection.lock()!=&*selection.lock()){ + if(!selection.expired()&&(selection.lock()->disabled||selection.lock()->grayedOut)){ bool handled=false; if(!UsingMouseNavigation()){ //Let's transfer some information about our selection being off the screen. Our intention with keyboard controls is that the screen will scroll to the correct location instead. //If we return false, then we handled it ourselves, no need to go back to the previous selection. - if(HandleOutsideDisabledButtonSelection(buttons[selection.y][selection.x])){ + if(HandleOutsideDisabledButtonSelection(selection)){ handled=true; } } @@ -572,9 +401,9 @@ Pixel Menu::GetRenderColor(){ return col; } -bool Menu::HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton){ - if(disabledButton->parentComponent!=nullptr){ - return disabledButton->parentComponent->HandleOutsideDisabledButtonSelection(disabledButton); +bool Menu::HandleOutsideDisabledButtonSelection(std::weak_ptrdisabledButton){ + if(!disabledButton.expired()){ + return disabledButton.lock()->parentComponent.lock()->HandleOutsideDisabledButtonSelection(disabledButton); }else{ return false; } @@ -595,25 +424,25 @@ void Menu::SetMouseNavigation(bool mouseNavigation){ void Menu::InventorySlotsUpdated(ITCategory cat){ //Update the inventory with a new inventory slot, since there's one additional item to interact with now. - for(MenuComponent*component:inventoryListeners.at(cat)){ - InventoryScrollableWindowComponent*comp=DYNAMIC_CAST(component); //HACK ALERT! We're assuming that these must be these classes otherwise they have no reason to even be using these listeners. Make sure that the lowest base class that requires these implements these functions!!! - comp->OnInventorySlotsUpdate(cat); + for(std::weak_ptrcomponent:inventoryListeners.at(cat)){ + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(component.lock()); //HACK ALERT! We're assuming that these must be these classes otherwise they have no reason to even be using these listeners. Make sure that the lowest base class that requires these implements these functions!!! + comp.lock()->OnInventorySlotsUpdate(cat); } } void Menu::MerchantInventorySlotsUpdated(ITCategory cat){ //Update the inventory with a new inventory slot, since there's one additional item to interact with now. - for(MenuComponent*component:merchantInventoryListeners.at(cat)){ - InventoryScrollableWindowComponent*comp=DYNAMIC_CAST(component); //HACK ALERT! We're assuming that these must be these classes otherwise they have no reason to even be using these listeners. Make sure that the lowest base class that requires these implements these functions!!! - comp->OnInventorySlotsUpdate(cat); + for(std::weak_ptrcomponent:merchantInventoryListeners.at(cat)){ + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(component.lock()); //HACK ALERT! We're assuming that these must be these classes otherwise they have no reason to even be using these listeners. Make sure that the lowest base class that requires these implements these functions!!! + comp.lock()->OnInventorySlotsUpdate(cat); } } -void Menu::AddInventoryListener(MenuComponent*component,ITCategory category){ +void Menu::AddInventoryListener(std::weak_ptrcomponent,ITCategory category){ if(inventoryListeners.count(category)){ - std::vector&listenerList=inventoryListeners.at(category); - if(std::find(listenerList.begin(),listenerList.end(),component)!=listenerList.end()){ - ERR("WARNING! Component "<name<<" has already been added to the "<>&listenerList=inventoryListeners.at(category); + if(std::find_if(listenerList.begin(),listenerList.end(),[&](auto&ptr){return &*ptr.lock()==&*component.lock();})!=listenerList.end()){ + ERR("WARNING! Component "<name<<" has already been added to the "<component,ITCategory category){ if(merchantInventoryListeners.count(category)){ - std::vector&listenerList=merchantInventoryListeners.at(category); - if(std::find(listenerList.begin(),listenerList.end(),component)!=listenerList.end()){ - ERR("WARNING! Component "<name<<" has already been added to the "<>&listenerList=merchantInventoryListeners.at(category); + if(std::find_if(listenerList.begin(),listenerList.end(),[&](auto&ptr){return &*ptr.lock()==&*component.lock();})!=listenerList.end()){ + ERR("WARNING! Component "<name<<" has already been added to the "<name<<" has already been added to the Equip Stat listener list! There should not be any duplicates!!") +void Menu::AddEquipStatListener(std::weak_ptrcomponent){ + if(std::find_if(equipStatListeners.begin(),equipStatListeners.end(),[&](auto&ptr){return &*ptr.lock()==&*component.lock();})!=equipStatListeners.end()){ + ERR("WARNING! Component "<name<<" has already been added to the Equip Stat listener list! There should not be any duplicates!!") } equipStatListeners.push_back(component); } @@ -676,10 +505,8 @@ bool Menu::IsMenuOpen(){ void Menu::CleanupAllMenus(){ for(auto&[key,value]:Menu::menus){ Menu*menu=value; - for(auto&componentKey:menu->components){ - MenuComponent*component=componentKey.second; + for(auto&[name,component]:menu->components){ component->Cleanup(); - delete component; } menu->components.Reset(); menu->Cleanup(); @@ -702,7 +529,7 @@ void Menu::DrawThemedWindow(vf2d menuPos,vf2d size,Pixel renderColor){ void Menu::RecalculateComponentCount(){ - componentCount=displayComponents.size()+buttons.size(); + componentCount=components.size(); } const MenuType Menu::GetType()const{ @@ -714,13 +541,13 @@ void Menu::LockInListeners(){ merchantInventoryListeners.SetInitialized(); } -void Menu::AddChapterListener(MenuComponent*component){ - if(std::find(chapterListeners.begin(),chapterListeners.end(),component)!=chapterListeners.end()){ - ERR("WARNING! Component "<name<<" has already been added to the Chapter listener list! There should not be any duplicates!!") +void Menu::AddChapterListener(std::weak_ptrcomponent){ + if(std::find_if(chapterListeners.begin(),chapterListeners.end(),[&](auto&ptr){return &*ptr.lock()==&*component.lock();})!=chapterListeners.end()){ + ERR("WARNING! Component "<name<<" has already been added to the Chapter listener list! There should not be any duplicates!!") } chapterListeners.push_back(component); } -MenuFuncData::MenuFuncData(Menu&menu,AiL*const game,MenuComponent*const component,ScrollableWindowComponent*const parentComponent) +MenuFuncData::MenuFuncData(Menu&menu,AiL*const game,std::weak_ptrcomponent,std::weak_ptrparentComponent) :menu(menu),game(game),component(component),parentComponent(parentComponent){} \ No newline at end of file diff --git a/Adventures in Lestoria/Menu.h b/Adventures in Lestoria/Menu.h index b5fca742..90282157 100644 --- a/Adventures in Lestoria/Menu.h +++ b/Adventures in Lestoria/Menu.h @@ -49,7 +49,7 @@ class MenuComponent; class ScrollableWindowComponent; //Add a component to a menu using this macro. Follow-up with END at the end of it. -#define ADD(key,componentType) _AddComponent(key,NEW componentType +#define ADD(key,componentType) _AddComponent(key,std::make_shared #define END ) #define DEPTH , @@ -112,62 +112,28 @@ class Menu:public IAttributable{ friend class EntityStats; float buttonHoldTime=0; - vi2d selection={-1,-1}; + std::weak_ptrselection; vi2d lastActiveMousePos={}; int componentCount=0; - MenuComponent*draggingComponent=nullptr; + std::unique_ptrdraggingComponent; ViewPort window; - static safemap>inventoryListeners; //All menu components that care about inventory updates subscribe to this list indirectly (See Menu::AddInventoryListener()). - static safemap>merchantInventoryListeners; //All menu components that care about merchant inventory updates subscribe to this list indirectly (See Menu::AddMerchantInventoryListener()). - static std::vectorequipStatListeners; //All menu components that care about stat/equip updates subscribe to this list indirectly (See Menu::AddStatListener()). - static std::vectorchapterListeners; //All menu components that care about story chapter updates subscribe to this list indirectly (See Menu::AddChapterListener()). + static safemap>>inventoryListeners; //All menu components that care about inventory updates subscribe to this list indirectly (See Menu::AddInventoryListener()). + static safemap>>merchantInventoryListeners; //All menu components that care about merchant inventory updates subscribe to this list indirectly (See Menu::AddMerchantInventoryListener()). + static std::vector>equipStatListeners; //All menu components that care about stat/equip updates subscribe to this list indirectly (See Menu::AddStatListener()). + static std::vector>chapterListeners; //All menu components that care about story chapter updates subscribe to this list indirectly (See Menu::AddChapterListener()). public: //The constructor is private. Use CreateMenu() instead! Menu()=default; - ~Menu(); //DO NOT USE DIRECTLY! You should be utilizing the ADD macro for adding components. template - T*_AddComponent(std::string componentKey,T*component,int depth=DEFAULT_DEPTH){ + std::shared_ptr_AddComponent(std::string componentKey,std::shared_ptrcomponent,int depth=DEFAULT_DEPTH){ component->parentMenu=type; if(depth==DEFAULT_DEPTH){ component->depth=STARTING_DEPTH-componentCount; }else{ component->depth=depth; } - if(component->selectable){ - buttons.Unlock(); - if(buttons.count(int(component->rect.pos.y))){ - buttons.at(int(component->rect.pos.y)).push_back(component); - }else{ - buttons[int(component->rect.pos.y)].push_back(component); - } - if(component->selectableViaKeyboard){ - keyboardButtons.Unlock(); - if(keyboardButtons.count(int(component->rect.pos.y))){ - keyboardButtons.at(int(component->rect.pos.y)).push_back(component); - }else{ - keyboardButtons[int(component->rect.pos.y)].push_back(component); - } - } - - //We must lock the values before calling sort. Sort seems to try and create new accesses. - buttons.SetInitialized(); - keyboardButtons.SetInitialized(); - - //We make an assumption that menu components are supposed to be in left-to-right order. Sometimes we may add things out-of-order, so this fixes the problem by sorting the items afterwards. - std::sort(buttons[int(component->rect.pos.y)].begin(),buttons[int(component->rect.pos.y)].end(),[](auto c1,auto c2){ - return c1->GetPos().xGetPos().x; - }); - if(keyboardButtons.count(int(component->rect.pos.y))){ //Keyboard buttons may not necessarily contain this key...Let's be sure. - std::sort(keyboardButtons[int(component->rect.pos.y)].begin(),keyboardButtons[int(component->rect.pos.y)].end(),[](auto c1,auto c2){ - return c1->GetPos().xGetPos().x; - }); - } - }else{ - displayComponents.push_back(component); - } - RecalculateComponentCount(); if(components.count(componentKey)){ @@ -178,7 +144,6 @@ public: components[componentKey]=component; components.SetInitialized(); lastRegisteredComponent=componentKey; - std::erase_if(Menu::unhandledComponents,[&](auto b1){return b1==component;}); return component; } @@ -194,27 +159,23 @@ public: static std::vectorstack; static std::string themeSelection; static safeunorderedmapthemes; - static std::vectorunhandledComponents; //This list contains MenuComponents that are created and haven't been assigned via _AddComponent. If we get to the end of menu initialization and there are any components in this vector, we have leaked memory and will report this. static const vf2d CENTERED; static bool IsMenuOpen(); const MenuType GetType()const; - safemapcomponents; //A friendly way to interrogate any component we are interested in. - std::vectordisplayComponents; //Components that are only for displaying purposes. + safemap>components; //A friendly way to interrogate any component we are interested in. static std::mapmenus; vf2d pos; //Specify the upper-left corner of the window. Using CENTERED will always put this where the upper-left corner would center the window. vf2d size; //Size in tiles (24x24), every menu will be tile-based - safemap>buttons; //Buttons are stored in rows followed by their column order. - safemap>keyboardButtons; //Button ordered storage for keyboard/menu static Theme&GetCurrentTheme(); static bool UsingMouseNavigation(); void SetMouseNavigation(bool mouseNavigation); static void InventorySlotsUpdated(ITCategory cat); //Called whenever the player's inventory gets modified. static void MerchantInventorySlotsUpdated(ITCategory cat); //Called whenever a traveling merchant's inventory item gets updated. - static void AddInventoryListener(MenuComponent*component,ITCategory category); //Adds a component to be in a given listener category. - static void AddMerchantInventoryListener(MenuComponent*component,ITCategory category); //Adds a component to be in a given listener category. - static void AddEquipStatListener(MenuComponent*component); //Adds a component to be in an equip stat listener. Will receive updates whenever stats are updated via equips. - static void AddChapterListener(MenuComponent*component); //Adds a component to be in a chapter listener. Will receive updates anytime the chapter in-game changes. + static void AddInventoryListener(std::weak_ptrcomponent,ITCategory category); //Adds a component to be in a given listener category. + static void AddMerchantInventoryListener(std::weak_ptrcomponent,ITCategory category); //Adds a component to be in a given listener category. + static void AddEquipStatListener(std::weak_ptrcomponent); //Adds a component to be in an equip stat listener. Will receive updates whenever stats are updated via equips. + static void AddChapterListener(std::weak_ptrcomponent); //Adds a component to be in a chapter listener. Will receive updates anytime the chapter in-game changes. vf2d center(); //Returns the last menu type created and last registered component, in case a component is detected as memory leaking, provides this information to each component for safety. static std::pairGetMemoryLeakReportInfo(); @@ -242,7 +203,7 @@ private: static void DrawTiledWindowBorder(AiL*game,vf2d menuPos,vf2d size,Pixel renderColor); //This triggers if we use a keyboard/controller input to try and select some off-screen menu item. We should ideally follow the menu cursor. - bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton); + bool HandleOutsideDisabledButtonSelection(std::weak_ptrdisabledButton); Pixel GetRenderColor(); MenuType type; @@ -252,17 +213,16 @@ private: }; template -T*Component(MenuType menu,std::string componentName){ - T*tmp=DYNAMIC_CAST(Menu::menus[menu]->components[componentName]); - return tmp; +std::shared_ptrComponent(MenuType menu,std::string componentName){ + return DYNAMIC_POINTER_CAST(Menu::menus[menu]->components[componentName]); } struct MenuFuncData{ Menu&menu; AiL*const game; - MenuComponent*const component; - ScrollableWindowComponent*const parentComponent=nullptr; - MenuFuncData(Menu&menu,AiL*const game,MenuComponent*const component,ScrollableWindowComponent*const parentComponent=nullptr); + const std::weak_ptr component; + const std::weak_ptr parentComponent={}; + MenuFuncData(Menu&menu,AiL*const game,std::weak_ptr component,std::weak_ptrparentComponent={}); }; using MenuFunc=std::function; \ No newline at end of file diff --git a/Adventures in Lestoria/MenuAnimatedIconToggleButton.h b/Adventures in Lestoria/MenuAnimatedIconToggleButton.h index 213d025a..17b46f27 100644 --- a/Adventures in Lestoria/MenuAnimatedIconToggleButton.h +++ b/Adventures in Lestoria/MenuAnimatedIconToggleButton.h @@ -51,9 +51,9 @@ private: public: inline MenuAnimatedIconToggleButton(geom2d::rectrect,std::string animation,MenuFunc onClick) :MenuAnimatedIconButton(rect,animation,[](MenuFuncData data){ - MenuAnimatedIconToggleButton*button=(MenuAnimatedIconToggleButton*)data.component; - button->Select(); - button->_onClick(data); + std::weak_ptrbutton=DYNAMIC_POINTER_CAST(data.component.lock()); + button.lock()->Select(); + button.lock()->_onClick(data); return true; }),_onClick(onClick){} protected: diff --git a/Adventures in Lestoria/MenuComponent.cpp b/Adventures in Lestoria/MenuComponent.cpp index e4834552..a174567a 100644 --- a/Adventures in Lestoria/MenuComponent.cpp +++ b/Adventures in Lestoria/MenuComponent.cpp @@ -39,15 +39,14 @@ All rights reserved. #include "MenuComponent.h" #include "drawutil.h" #include "util.h" +#include "ScrollableWindowComponent.h" INCLUDE_game using A=Attribute; MenuComponent::MenuComponent(geom2d::rectrect,std::string label,MenuFunc onClick,ButtonAttr attributes) - :rect(rect),originalPos(rect.pos),label(label),menuDest(MenuType::ENUM_END),onClick(onClick),hoverEffect(0),selectable(!(attributes&ButtonAttr::UNSELECTABLE)),selectableViaKeyboard(!(attributes&ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)),memoryLeakInfo(Menu::GetMemoryLeakReportInfo()),fitToLabel(attributes&ButtonAttr::FIT_TO_LABEL){ - Menu::unhandledComponents.push_back(this); -} + :rect(rect),originalPos(rect.pos),label(label),menuDest(MenuType::ENUM_END),onClick(onClick),hoverEffect(0),selectable(!(attributes&ButtonAttr::UNSELECTABLE)),selectableViaKeyboard(!(attributes&ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)),memoryLeakInfo(Menu::GetMemoryLeakReportInfo()),fitToLabel(attributes&ButtonAttr::FIT_TO_LABEL){} MenuComponent::MenuComponent(geom2d::rectrect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes) :MenuComponent(rect,label,onClick,attributes){ @@ -61,19 +60,7 @@ MenuComponent::MenuComponent(geom2d::rectrect,std::string label,MenuType this->labelScaling=labelScaling; } -MenuComponent::~MenuComponent(){ - Menu*pMenu=Menu::menus[parentMenu]; - for(auto key:pMenu->buttons){ - std::vector&components=key.second; - std::erase_if(components,[&](MenuComponent*component){return component==this;}); - } - for(auto key:pMenu->keyboardButtons){ - std::vector&components=key.second; - std::erase_if(components,[&](MenuComponent*component){return component==this;}); - } - std::erase_if(pMenu->displayComponents,[&](MenuComponent*component){return component==this;}); - //pMenu->components.erase(this->name); //We're not going to do this here because we are in the middle of a loop for another menu component when cleaning up. -} +MenuComponent::~MenuComponent(){} void MenuComponent::AfterCreate(){} @@ -146,17 +133,17 @@ void MenuComponent::_DrawDecal(ViewPort&window,bool focused){ } } -MenuComponent*MenuComponent::PickUpDraggableItem(){ - return nullptr; +std::unique_ptrMenuComponent::PickUpDraggableItem(){ + return {}; } -bool MenuComponent::DropDraggableItem(MenuComponent*draggable){ +bool MenuComponent::DropDraggableItem(std::unique_ptrdraggable){ return false; } bool MenuComponent::GetHoverState(AiL*game){ - if(parentComponent!=nullptr){ - return parentComponent->GetHoverState(game,this); + if(!parentComponent.expired()){ + return parentComponent.lock()->GetHoverState(game,this); }else{ vf2d parentWindowPos=Menu::menus[parentMenu]->pos; return geom2d::overlaps(geom2d::rect{rect.pos+parentWindowPos,rect.size},game->GetMousePos()); @@ -168,22 +155,22 @@ bool MenuComponent::GetHoverState(AiL*game,MenuComponent*child){ } bool MenuComponent::PointWithinParent(MenuComponent*child,vi2d drawPos){ - if(parentComponent!=nullptr){ - return parentComponent->PointWithinParent(child,drawPos); + if(!parentComponent.expired()){ + return parentComponent.lock()->PointWithinParent(child,drawPos); }else{ return true; } } bool MenuComponent::PointWithinParent(MenuComponent*child,geom2d::rect drawRect){ - if(parentComponent!=nullptr){ - return parentComponent->PointWithinParent(child,drawRect); + if(!parentComponent.expired()){ + return parentComponent.lock()->PointWithinParent(child,drawRect); }else{ return true; } } -bool MenuComponent::HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton){ +bool MenuComponent::HandleOutsideDisabledButtonSelection(std::weak_ptrdisabledButton){ return false; }; @@ -225,7 +212,7 @@ void MenuComponent::_OnMouseOut(){ if(runHoverFunctions){ if(hoverState){ hoverState=false; - onMouseOut(MenuFuncData{*Menu::menus[parentMenu],game,this,(ScrollableWindowComponent*)(parentComponent)}); + onMouseOut(MenuFuncData{*Menu::menus[parentMenu],game,std::make_shared(*this),DYNAMIC_POINTER_CAST(parentComponent.lock())}); OnMouseOut(); } } @@ -235,7 +222,7 @@ void MenuComponent::_OnHover(){ if(hovered){ if(runHoverFunctions&&!hoverState){ hoverState=true; - onHover(MenuFuncData{*Menu::menus[parentMenu],game,this,(ScrollableWindowComponent*)(parentComponent)}); + onHover(MenuFuncData{*Menu::menus[parentMenu],game,std::make_shared(*this),DYNAMIC_POINTER_CAST(parentComponent.lock())}); OnHover(); } } @@ -259,5 +246,5 @@ void MenuComponent::OnPlayerMoneyUpdate(uint32_t newMoney){} void MenuComponent::OnChapterUpdate(uint8_t newChapter){} void MenuComponent::Click(){ - onClick(MenuFuncData{*Menu::menus[parentMenu],game,this}); + onClick(MenuFuncData{*Menu::menus[parentMenu],game,std::make_shared(*this)}); } \ No newline at end of file diff --git a/Adventures in Lestoria/MenuComponent.h b/Adventures in Lestoria/MenuComponent.h index f421c23e..c846219b 100644 --- a/Adventures in Lestoria/MenuComponent.h +++ b/Adventures in Lestoria/MenuComponent.h @@ -126,7 +126,7 @@ protected: virtual void OnHover(); public: MenuType parentMenu=MenuType::ENUM_END; - MenuComponent*parentComponent=nullptr; + std::weak_ptrparentComponent{}; MenuComponent(geom2d::rectrect,std::string label,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE); MenuComponent(geom2d::rectrect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE); MenuComponent(geom2d::rectrect,std::string label,MenuType menuDest,MenuFunc onClick,vf2d labelScaling,ButtonAttr attributes=ButtonAttr::NONE); @@ -135,11 +135,11 @@ public: const vf2d&GetSize()const; //We picked up a draggable component, we should make a copy and return it here. If a nullptr is returned here, the pickup is not allowed. //WARNING!!! This allocates a brand new component when successful!!! Be prepared to clear it! - virtual MenuComponent*PickUpDraggableItem(); + virtual std::unique_ptrPickUpDraggableItem(); //We are attempting to drop draggable onto this item. If it's not allowed, return false. - virtual bool DropDraggableItem(MenuComponent*draggable); + virtual bool DropDraggableItem(std::unique_ptrdraggable); //A notification that a button outside the region has been selected. Return false if it's not allowed. - virtual bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton); + virtual bool HandleOutsideDisabledButtonSelection(std::weak_ptrdisabledButton); //Called whenever equipment and base stats are updated, notifying a component that numbers that may be displayed have changed. virtual void OnEquipStatsUpdate(); virtual const std::string&GetLabel()const; diff --git a/Adventures in Lestoria/MenuItemButton.h b/Adventures in Lestoria/MenuItemButton.h index 7c024169..3eb9db3c 100644 --- a/Adventures in Lestoria/MenuItemButton.h +++ b/Adventures in Lestoria/MenuItemButton.h @@ -147,9 +147,9 @@ protected: } } } - inline MenuComponent*PickUpDraggableItem()override final{ + inline std::unique_ptrPickUpDraggableItem()override final{ if(valid){ - MenuItemButton*pickUp=NEW MenuItemButton(rect,invRef,inventoryIndex,onClick,itemDescriptionMenu,itemNameLabelName,itemDescriptionLabelName); + std::unique_ptrpickUp=std::make_unique(rect,invRef,inventoryIndex,onClick,itemDescriptionMenu,itemNameLabelName,itemDescriptionLabelName); valid=false; return pickUp; }else{ @@ -157,9 +157,9 @@ protected: } } - inline bool DropDraggableItem(MenuComponent*draggable)override final{ + inline bool DropDraggableItem(std::unique_ptrdraggable)override final{ //HACK Warning! We're making a bold assumption that every component that is draggable is of the same type! This may change in the future.... - MenuItemButton*draggedItem=(MenuItemButton*)draggable; + MenuItemButton*draggedItem=DYNAMIC_CAST(draggable.get()); ITCategory cat=draggedItem->invRef.at(draggedItem->inventoryIndex)->Category(); return Inventory::SwapItems(cat,draggedItem->inventoryIndex,inventoryIndex); } diff --git a/Adventures in Lestoria/MerchantWindow.cpp b/Adventures in Lestoria/MerchantWindow.cpp index 218fe2e2..98d195eb 100644 --- a/Adventures in Lestoria/MerchantWindow.cpp +++ b/Adventures in Lestoria/MerchantWindow.cpp @@ -30,7 +30,7 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -Portions of this software are copyright © 2023 The FreeType +Portions of this software are copyright � 2023 The FreeType Project (www.freetype.org). Please see LICENSE_FT.txt for more information. All rights reserved. */ @@ -61,7 +61,7 @@ void Menu::InitializeMerchantWindow(){ } std::sort(categories.begin(),categories.end(),[](std::pair&cat1,std::pair&cat2){return cat1.secondADD("Buy Tab",MenuComponent)({{2,0},{merchantWindow->size.x/2-4,24}},"Buy",[](MenuFuncData data){ + auto buyTab=merchantWindow->ADD("Buy Tab",MenuComponent)(geom2d::rect{{2,0},{merchantWindow->size.x/2-4,24}},"Buy",[](MenuFuncData data){ Component(MERCHANT,"Merchant Inventory Display")->Enable(true); Component(MERCHANT,"Sell Tab")->selected=false; Component(MERCHANT,"Inventory Tabs Outline")->Enable(false); @@ -71,13 +71,13 @@ void Menu::InitializeMerchantWindow(){ } Component(data.menu.GetType(),"Inventory Display - "+data.menu.S(A::LAST_INVENTORY_TYPE_OPENED))->Enable(false); Component(data.menu.GetType(),data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)+" Inventory Tab")->Enable(false); - data.component->selected=true; + data.component.lock()->selected=true; return true; })END; buyTab->selected=true; buyTab->selectionType=SelectionType::HIGHLIGHT; - auto sellTab=merchantWindow->ADD("Sell Tab",MenuComponent)({{merchantWindow->size.x/2+2,0},{merchantWindow->size.x/2-4,24}},"Sell",[](MenuFuncData data){ + auto sellTab=merchantWindow->ADD("Sell Tab",MenuComponent)(geom2d::rect{{merchantWindow->size.x/2+2,0},{merchantWindow->size.x/2-4,24}},"Sell",[](MenuFuncData data){ Component(MERCHANT,"Merchant Inventory Display")->Enable(false); Component(MERCHANT,"Buy Tab")->selected=false; Component(MERCHANT,"Inventory Tabs Outline")->Enable(true); @@ -87,31 +87,31 @@ void Menu::InitializeMerchantWindow(){ } Component(data.menu.GetType(),"Inventory Display - "+data.menu.S(A::LAST_INVENTORY_TYPE_OPENED))->Enable(true); Component(data.menu.GetType(),data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)+" Inventory Tab")->Enable(true); - data.component->selected=true; + data.component.lock()->selected=true; return true; })END; sellTab->selectionType=SelectionType::HIGHLIGHT; - auto inventoryDisplay=merchantWindow->ADD("Merchant Inventory Display",RowInventoryScrollableWindowComponent)({{2,28},{220,merchantWindow->size.y-44}},"Item Name Label","Item Description Label", + auto inventoryDisplay=merchantWindow->ADD("Merchant Inventory Display",RowInventoryScrollableWindowComponent)(geom2d::rect{{2,28},{220,merchantWindow->size.y-44}},"Item Name Label","Item Description Label", [](MenuFuncData data){ - RowItemDisplay*item=DYNAMIC_CAST(data.component); - Component(BUY_ITEM,"Item Purchase Header")->S(A::ITEM_NAME)=item->GetItem().lock()->ActualName(); - Component(BUY_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->BuyValue())); + std::weak_ptritem=DYNAMIC_POINTER_CAST(data.component.lock()); + Component(BUY_ITEM,"Item Purchase Header")->S(A::ITEM_NAME)=item.lock()->GetItem().lock()->ActualName(); + Component(BUY_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item.lock()->GetItem().lock()->BuyValue())); Component(BUY_ITEM,"Amount to buy Amount Label")->SetLabel("1"); - Component(BUY_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->BuyValue())); + Component(BUY_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item.lock()->GetItem().lock()->BuyValue())); Merchant&merchant=Merchant::GetCurrentTravelingMerchant(); - bool canPurchase=merchant.CanPurchaseItem(item->GetItem().lock()->ActualName(),1); + bool canPurchase=merchant.CanPurchaseItem(item.lock()->GetItem().lock()->ActualName(),1); std::string colorCode=""; if(!canPurchase)colorCode="#FF0000"; - Component(BUY_ITEM,"Total Price Amount Label")->SetLabel(colorCode+std::to_string(item->GetItem().lock()->BuyValue())); - Component(BUY_ITEM,"Item Purchase Header")->SetLabel("Buying "+item->GetItem().lock()->DisplayName()); - Component(BUY_ITEM,"Purchase Button")->SetGrayedOut(!merchant.CanPurchaseItem(item->GetItem().lock()->ActualName(),1)); + Component(BUY_ITEM,"Total Price Amount Label")->SetLabel(colorCode+std::to_string(item.lock()->GetItem().lock()->BuyValue())); + Component(BUY_ITEM,"Item Purchase Header")->SetLabel("Buying "+item.lock()->GetItem().lock()->DisplayName()); + Component(BUY_ITEM,"Purchase Button")->SetGrayedOut(!merchant.CanPurchaseItem(item.lock()->GetItem().lock()->ActualName(),1)); Menu::OpenMenu(BUY_ITEM); return true; }, [](MenuFuncData data){ - Component(data.menu.GetType(),"Item Icon")->SetItem(DYNAMIC_CAST(data.component)->GetItem()); + Component(data.menu.GetType(),"Item Icon")->SetItem(DYNAMIC_POINTER_CAST(data.component.lock())->GetItem()); return true; }, [](MenuFuncData data){ @@ -119,14 +119,14 @@ void Menu::InitializeMerchantWindow(){ return true; }, InventoryCreator::RowMerchant_InventoryUpdate, - {.padding=1,.size={220-13,28}})END; + InventoryWindowOptions{.padding=1,.size={220-13,28}})END; inventoryDisplay->SetPriceLabelType(PriceLabel::BUY_LABEL); for(auto&[category,items]:ITEM_CATEGORIES){ Menu::AddMerchantInventoryListener(inventoryDisplay,category); } - merchantWindow->ADD("Inventory Tabs Outline",MenuComponent)({{0,28},{72,merchantWindow->size.y-44}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + merchantWindow->ADD("Inventory Tabs Outline",MenuComponent)(geom2d::rect{{0,28},{72,merchantWindow->size.y-44}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; std::sort(categories.begin(),categories.end(),[](std::pair&cat1,std::pair&cat2){return cat1.secondADD(category+" Inventory Tab",MenuComponent)({{2,30+yOffset},{68,16}},category,MenuType::ENUM_END, + auto button=merchantWindow->ADD(category+" Inventory Tab",MenuComponent)(geom2d::rect{{2,30+yOffset},{68,16}},category,MenuType::ENUM_END, [&](MenuFuncData data){ //Close the old inventory window and show the proper one. Component(data.menu.GetType(),"Inventory Display - "+data.menu.S(A::LAST_INVENTORY_TYPE_OPENED))->Enable(false); Component(data.menu.GetType(),data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)+" Inventory Tab")->SetSelected(false); - Component(data.menu.GetType(),"Inventory Display - "+data.component->S(A::CATEGORY_NAME))->Enable(true); - Component(data.menu.GetType(),data.component->S(A::CATEGORY_NAME)+" Inventory Tab")->SetSelected(true); - data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)=data.component->S(A::CATEGORY_NAME); + Component(data.menu.GetType(),"Inventory Display - "+data.component.lock()->S(A::CATEGORY_NAME))->Enable(true); + Component(data.menu.GetType(),data.component.lock()->S(A::CATEGORY_NAME)+" Inventory Tab")->SetSelected(true); + data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)=data.component.lock()->S(A::CATEGORY_NAME); return true; - },{textScaling,1.f})END; + },vf2d{textScaling,1.f})END; button->SetSelectionType(HIGHLIGHT); button->S(A::CATEGORY_NAME)=category; - auto inventoryDisplay=merchantWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)({{72,28},{150,merchantWindow->size.y-44}},"Item Name Label","Item Description Label", + auto inventoryDisplay=merchantWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)(geom2d::rect{{72,28},{150,merchantWindow->size.y-44}},"Item Name Label","Item Description Label", [](MenuFuncData data){ - RowItemDisplay*item=DYNAMIC_CAST(data.component); - if(item->GetItem().lock()->CanBeSold()){ - Component(SELL_ITEM,"Item Sell Header")->SetItem(item->GetItem()); - Component(SELL_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->SellValue())); + std::weak_ptritem=DYNAMIC_POINTER_CAST(data.component.lock()); + if(item.lock()->GetItem().lock()->CanBeSold()){ + Component(SELL_ITEM,"Item Sell Header")->SetItem(item.lock()->GetItem()); + Component(SELL_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item.lock()->GetItem().lock()->SellValue())); Component(SELL_ITEM,"Amount to sell Amount Label")->SetLabel("1"); - Component(SELL_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->SellValue())); + Component(SELL_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item.lock()->GetItem().lock()->SellValue())); Merchant&merchant=Merchant::GetCurrentTravelingMerchant(); - bool canPurchase=merchant.CanSellItem(item->GetItem(),1); + bool canPurchase=merchant.CanSellItem(item.lock()->GetItem(),1); std::string colorCode=""; if(!canPurchase)colorCode="#FF0000"; - Component(SELL_ITEM,"Total Price Amount Label")->SetLabel(colorCode+std::to_string(item->GetItem().lock()->SellValue())); - Component(SELL_ITEM,"Item Sell Header")->SetLabel("Selling "+item->GetItem().lock()->DisplayName()); - Component(SELL_ITEM,"Sell Button")->SetGrayedOut(!merchant.CanSellItem(item->GetItem(),1)); + Component(SELL_ITEM,"Total Price Amount Label")->SetLabel(colorCode+std::to_string(item.lock()->GetItem().lock()->SellValue())); + Component(SELL_ITEM,"Item Sell Header")->SetLabel("Selling "+item.lock()->GetItem().lock()->DisplayName()); + Component(SELL_ITEM,"Sell Button")->SetGrayedOut(!merchant.CanSellItem(item.lock()->GetItem(),1)); Menu::OpenMenu(SELL_ITEM); } return true; }, [](MenuFuncData data){ - Component(data.menu.GetType(),"Item Icon")->SetItem(DYNAMIC_CAST(data.component)->GetItem()); + Component(data.menu.GetType(),"Item Icon")->SetItem(DYNAMIC_POINTER_CAST(data.component.lock())->GetItem()); return true; }, [](MenuFuncData data){ @@ -179,7 +179,7 @@ void Menu::InitializeMerchantWindow(){ return true; }, InventoryCreator::RowPlayer_InventoryUpdate, - {.padding=1,.size={137,28}})END; + InventoryWindowOptions{.padding=1,.size={137,28}})END; inventoryDisplay->SetPriceLabelType(PriceLabel::SELL_LABEL); if(first){ @@ -198,27 +198,27 @@ void Menu::InitializeMerchantWindow(){ #pragma region Inventory Description float inventoryDescriptionWidth=merchantWindow->pos.x+merchantWindow->size.x-26-224; - merchantWindow->ADD("Item Description Outline",MenuLabel)({{224,28},{inventoryDescriptionWidth,merchantWindow->size.y-44}},"",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - merchantWindow->ADD("Item Icon",MenuItemItemButton)({{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END; - merchantWindow->ADD("Item Name Label",MenuLabel)({{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - merchantWindow->ADD("Item Description Label",MenuLabel)({{226,94},{inventoryDescriptionWidth-6,merchantWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + merchantWindow->ADD("Item Description Outline",MenuLabel)(geom2d::rect{{224,28},{inventoryDescriptionWidth,merchantWindow->size.y-44}},"",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + merchantWindow->ADD("Item Icon",MenuItemItemButton)(geom2d::rect{{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END; + merchantWindow->ADD("Item Name Label",MenuLabel)(geom2d::rect{{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + merchantWindow->ADD("Item Description Label",MenuLabel)(geom2d::rect{{226,94},{inventoryDescriptionWidth-6,merchantWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; #pragma endregion #pragma region Money Display vf2d moneyIconPos={224+inventoryDescriptionWidth-24,28+merchantWindow->size.y-44+6}; - auto moneyIcon=merchantWindow->ADD("Money Icon",MenuIconButton)({moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END; + auto moneyIcon=merchantWindow->ADD("Money Icon",MenuIconButton)(geom2d::rect{moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END; std::string moneyText=std::to_string(game->GetPlayer()->GetMoney()); vf2d moneyTextSize=game->GetTextSizeProp(moneyText)*2; - auto moneyDisplay=merchantWindow->ADD("Money Label",PlayerMoneyLabel)({moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN|ComponentAttr::FIT_TO_LABEL)END; + auto moneyDisplay=merchantWindow->ADD("Money Label",PlayerMoneyLabel)(geom2d::rect{moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN|ComponentAttr::FIT_TO_LABEL)END; moneyDisplay->SetRightAlignment(true); Player::AddMoneyListener(moneyDisplay); #pragma endregion - merchantWindow->ADD("Leave Button",MenuComponent)({{merchantWindow->size.x/2-48,28+merchantWindow->size.y-44+6},{96,24}},"Leave",MenuType::ENUM_END, + merchantWindow->ADD("Leave Button",MenuComponent)(geom2d::rect{{merchantWindow->size.x/2-48,28+merchantWindow->size.y-44+6},{96,24}},"Leave",MenuType::ENUM_END, [](MenuFuncData data){ Menu::CloseMenu(); return true; - },{2,2})END; + },vf2d{2,2})END; buyTab->onClick(MenuFuncData{*merchantWindow,game,buyTab}); } \ No newline at end of file diff --git a/Adventures in Lestoria/OverworldMapLevelWindow.cpp b/Adventures in Lestoria/OverworldMapLevelWindow.cpp index dfac481a..e9c8ea3d 100644 --- a/Adventures in Lestoria/OverworldMapLevelWindow.cpp +++ b/Adventures in Lestoria/OverworldMapLevelWindow.cpp @@ -52,14 +52,14 @@ void Menu::InitializeOverworldMapLevelWindow(){ vf2d windowSize={game->GetScreenSize().x/3.f-24,float(game->GetScreenSize().y)-48}; Menu*levelSelectWindow=CreateMenu(OVERWORLD_LEVEL_SELECT,{game->GetScreenSize().x-game->GetScreenSize().x/3.f,24},windowSize); - levelSelectWindow->ADD("Panel 1 Back",MenuLabel)({{0,0},{windowSize.x-1,44}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; - levelSelectWindow->ADD("Chapter Label",MenuLabel)({{0,4},{windowSize.x,16}},"Chapter",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)DEPTH -1 END; - levelSelectWindow->ADD("Stage Label",MenuLabel)({{0,24},{windowSize.x,16}},"Stage",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)DEPTH -1 END; + levelSelectWindow->ADD("Panel 1 Back",MenuLabel)(geom2d::rect{{0,0},{windowSize.x-1,44}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; + levelSelectWindow->ADD("Chapter Label",MenuLabel)(geom2d::rect{{0,4},{windowSize.x,16}},"Chapter",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)DEPTH -1 END; + levelSelectWindow->ADD("Stage Label",MenuLabel)(geom2d::rect{{0,24},{windowSize.x,16}},"Stage",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)DEPTH -1 END; - levelSelectWindow->ADD("Panel 2 Back",MenuLabel)({{0,52},{windowSize.x-1,96}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; - levelSelectWindow->ADD("Encounters Label",MenuLabel)({{0,52},{windowSize.x-1,12}},"Encounters:",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END; - levelSelectWindow->ADD("Spawns List",EncountersSpawnListScrollableWindowComponent)({{1,64},{windowSize.x-2,84}},ComponentAttr::BACKGROUND)END; + levelSelectWindow->ADD("Panel 2 Back",MenuLabel)(geom2d::rect{{0,52},{windowSize.x-1,96}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; + levelSelectWindow->ADD("Encounters Label",MenuLabel)(geom2d::rect{{0,52},{windowSize.x-1,12}},"Encounters:",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END; + levelSelectWindow->ADD("Spawns List",EncountersSpawnListScrollableWindowComponent)(geom2d::rect{{1,64},{windowSize.x-2,84}},ComponentAttr::BACKGROUND)END; - levelSelectWindow->ADD("Change Loadout Button",MenuComponent)({{0,152},{windowSize.x-1,12}},"Change Loadout",ITEM_LOADOUT,[](MenuFuncData data){return true;})END; - levelSelectWindow->ADD("Enter Button",MenuComponent)({{0,166},{windowSize.x-1,16}},"Enter",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;})END; + levelSelectWindow->ADD("Change Loadout Button",MenuComponent)(geom2d::rect{{0,152},{windowSize.x-1,12}},"Change Loadout",ITEM_LOADOUT,[](MenuFuncData data){return true;})END; + levelSelectWindow->ADD("Enter Button",MenuComponent)(geom2d::rect{{0,166},{windowSize.x-1,16}},"Enter",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/OverworldMenuWindow.cpp b/Adventures in Lestoria/OverworldMenuWindow.cpp index 57fc7975..450c63f5 100644 --- a/Adventures in Lestoria/OverworldMenuWindow.cpp +++ b/Adventures in Lestoria/OverworldMenuWindow.cpp @@ -48,16 +48,16 @@ INCLUDE_GFX void Menu::InitializeOverworldMenuWindow(){ Menu*overworldMenuWindow=CreateMenu(OVERWORLD_MENU,CENTERED,vi2d{96,164}); - overworldMenuWindow->ADD("Resume Button",MenuComponent)({{4,12+28*0},{88,24}},"Resume",[](MenuFuncData data){Menu::CloseMenu();return true;})END; - overworldMenuWindow->ADD("Character Button",MenuComponent)({{4,12+28*1},{88,24}},"Character", + overworldMenuWindow->ADD("Resume Button",MenuComponent)(geom2d::rect{{4,12+28*0},{88,24}},"Resume",[](MenuFuncData data){Menu::CloseMenu();return true;})END; + overworldMenuWindow->ADD("Character Button",MenuComponent)(geom2d::rect{{4,12+28*1},{88,24}},"Character", [](MenuFuncData data){ Component(CHARACTER_MENU,"Character Rotating Display")->SetIcon(GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal()); Menu::OpenMenu(CHARACTER_MENU); return true; })END; - overworldMenuWindow->ADD("Inventory Button",MenuComponent)({{4,12+28*2},{88,24}},"Inventory",[](MenuFuncData data){Menu::OpenMenu(INVENTORY);return true;})END; - overworldMenuWindow->ADD("Settings Button",MenuComponent)({{4,12+28*3},{88,24}},"Settings",[](MenuFuncData data){/*Menu::OpenMenu(SETTINGS_MENU);*/return true;})END; - overworldMenuWindow->ADD("Quit Button",MenuComponent)({{4,12+28*4},{88,24}},"Quit Game",[](MenuFuncData data){ + overworldMenuWindow->ADD("Inventory Button",MenuComponent)(geom2d::rect{{4,12+28*2},{88,24}},"Inventory",[](MenuFuncData data){Menu::OpenMenu(INVENTORY);return true;})END; + overworldMenuWindow->ADD("Settings Button",MenuComponent)(geom2d::rect{{4,12+28*3},{88,24}},"Settings",[](MenuFuncData data){/*Menu::OpenMenu(SETTINGS_MENU);*/return true;})END; + overworldMenuWindow->ADD("Quit Button",MenuComponent)(geom2d::rect{{4,12+28*4},{88,24}},"Quit Game",[](MenuFuncData data){ Menu::CloseAllMenus(); SaveFile::SaveGame(); game->ResetGame(); diff --git a/Adventures in Lestoria/Player.cpp b/Adventures in Lestoria/Player.cpp index ae25ca6e..b14fdcbb 100644 --- a/Adventures in Lestoria/Player.cpp +++ b/Adventures in Lestoria/Player.cpp @@ -73,7 +73,7 @@ InputGroup Player::KEY_ITEM1; InputGroup Player::KEY_ITEM2; InputGroup Player::KEY_ITEM3; -std::setPlayer::moneyListeners; +std::vector>Player::moneyListeners; Player::Player() :lastReleasedMovementKey(DOWN),facingDirection(DOWN),state(State::NORMAL){ @@ -1020,8 +1020,8 @@ void EntityStats::RecalculateEquipStats(){ equipStats.A(key)+=setStats.A_Read(key); } } - for(MenuComponent*component:Menu::equipStatListeners){ - component->OnEquipStatsUpdate(); + for(std::weak_ptrcomponent:Menu::equipStatListeners){ + component.lock()->OnEquipStatsUpdate(); } } @@ -1065,12 +1065,14 @@ uint32_t Player::GetMoney()const{ void Player::SetMoney(uint32_t newMoney){ money=newMoney; for(auto&component:moneyListeners){ - component->OnPlayerMoneyUpdate(newMoney); + component.lock()->OnPlayerMoneyUpdate(newMoney); } } -void Player::AddMoneyListener(MenuComponent*component){ - if(moneyListeners.count(component))ERR("WARNING! Trying to add a second copy of component "<GetName())); - moneyListeners.insert(component); +void Player::AddMoneyListener(std::weak_ptrcomponent){ + if(std::find_if(moneyListeners.begin(),moneyListeners.end(),[&](auto&ptr){return &*ptr.lock()==&*component.lock();})!=moneyListeners.end()){ + ERR("WARNING! Component "<GetName()<<" has already been added to the Chapter listener list! There should not be any duplicates!!") + } + moneyListeners.push_back(component); } diff --git a/Adventures in Lestoria/Player.h b/Adventures in Lestoria/Player.h index e45ef650..cd3919a3 100644 --- a/Adventures in Lestoria/Player.h +++ b/Adventures in Lestoria/Player.h @@ -217,9 +217,9 @@ public: void PerformHPRecovery(); static InputGroup KEY_ABILITY1, KEY_ABILITY2, KEY_ABILITY3, KEY_ABILITY4, KEY_DEFENSIVE, KEY_ITEM1, KEY_ITEM2, KEY_ITEM3; - static std::setmoneyListeners; + static std::vector>moneyListeners; - static void AddMoneyListener(MenuComponent*component); + static void AddMoneyListener(std::weak_ptrcomponent); uint32_t GetMoney()const; void SetMoney(uint32_t newMoney); void AddXP(const uint32_t xpGain); diff --git a/Adventures in Lestoria/RowInventoryScrollableWindowComponent.h b/Adventures in Lestoria/RowInventoryScrollableWindowComponent.h index f8212bcd..b8cd90be 100644 --- a/Adventures in Lestoria/RowInventoryScrollableWindowComponent.h +++ b/Adventures in Lestoria/RowInventoryScrollableWindowComponent.h @@ -30,7 +30,7 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -Portions of this software are copyright © 2023 The FreeType +Portions of this software are copyright � 2023 The FreeType Project (www.freetype.org). Please see LICENSE_FT.txt for more information. All rights reserved. */ @@ -51,17 +51,17 @@ public: virtual inline void SetCompactDescriptions(CompactText compact)override final{ this->compact=compact; - for(MenuComponent*component:components){ - RowItemDisplay*itemButton=DYNAMIC_CAST(component); - itemButton->SetCompactDescriptions(compact); + for(std::weak_ptrcomponent:components){ + std::weak_ptritemButton=DYNAMIC_POINTER_CAST(component.lock()); + itemButton.lock()->SetCompactDescriptions(compact); } } virtual inline void SetPriceLabelType(PriceLabel::PriceLabel labelType)final{ this->priceLabel=labelType; - for(MenuComponent*component:components){ - RowItemDisplay*itemButton=DYNAMIC_CAST(component); - itemButton->SetPriceLabelType(labelType); + for(std::weak_ptrcomponent:components){ + std::weak_ptritemButton=DYNAMIC_POINTER_CAST(component.lock()); + itemButton.lock()->SetPriceLabelType(labelType); } } }; \ No newline at end of file diff --git a/Adventures in Lestoria/SaveFile.cpp b/Adventures in Lestoria/SaveFile.cpp index df178431..bb0be149 100644 --- a/Adventures in Lestoria/SaveFile.cpp +++ b/Adventures in Lestoria/SaveFile.cpp @@ -223,9 +223,9 @@ const void SaveFile::UpdateSaveGameData(){ float offsetY=0; for(size_t i=0;iADD(std::format("Load File Button - Save {}",i),LoadFileButton)({{0,offsetY},{gameFilesList->GetSize().x-13,48}},metadata[std::format("save{}",i)],i,[](MenuFuncData data){ - LoadFileButton*comp=DYNAMIC_CAST(data.component); - saveFileID=comp->getSaveFileID(); + gameFilesList->ADD(std::format("Load File Button - Save {}",i),LoadFileButton)(geom2d::rect{{0,offsetY},{gameFilesList->GetSize().x-13,48}},metadata[std::format("save{}",i)],i,[](MenuFuncData data){ + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(data.component.lock()); + saveFileID=comp.lock()->getSaveFileID(); SaveFile::LoadGame(); return true; },ButtonAttr::NONE)END; diff --git a/Adventures in Lestoria/SaveFileWindow.cpp b/Adventures in Lestoria/SaveFileWindow.cpp index e34553b3..5112ebe1 100644 --- a/Adventures in Lestoria/SaveFileWindow.cpp +++ b/Adventures in Lestoria/SaveFileWindow.cpp @@ -42,10 +42,10 @@ All rights reserved. void Menu::InitializeSaveFileWindow(){ Menu*saveFileWindow=CreateMenu(SAVE_FILE_NAME,CENTERED,vi2d{96,96}); - saveFileWindow->ADD("Save File Name Entry Label",MenuLabel)({{-8,0},{112,36}},"Save File Name:",1.0f,ComponentAttr::SHADOW)END; - saveFileWindow->ADD("Save File Name Text Entry",TextEntryLabel)({{-8,36},{112,24}},TEXTCHANGE_DONOTHING,false,16U,2.f,ComponentAttr::FIT_TO_LABEL|ComponentAttr::OUTLINE|ComponentAttr::SHADOW|ComponentAttr::BACKGROUND)END; - saveFileWindow->ADD("Back Button",MenuComponent)({{-8,68},{48,12}},"Back",[](MenuFuncData data){Menu::CloseMenu();game->TextEntryEnable(false);return true;})END; - saveFileWindow->ADD("Continue Button",MenuComponent)({{56,68},{48,12}},"Begin",MenuType::CLASS_SELECTION,[](MenuFuncData data){ + saveFileWindow->ADD("Save File Name Entry Label",MenuLabel)(geom2d::rect{{-8,0},{112,36}},"Save File Name:",1.0f,ComponentAttr::SHADOW)END; + saveFileWindow->ADD("Save File Name Text Entry",TextEntryLabel)(geom2d::rect{{-8,36},{112,24}},TEXTCHANGE_DONOTHING,false,16U,2.f,ComponentAttr::FIT_TO_LABEL|ComponentAttr::OUTLINE|ComponentAttr::SHADOW|ComponentAttr::BACKGROUND)END; + saveFileWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{-8,68},{48,12}},"Back",[](MenuFuncData data){Menu::CloseMenu();game->TextEntryEnable(false);return true;})END; + saveFileWindow->ADD("Continue Button",MenuComponent)(geom2d::rect{{56,68},{48,12}},"Begin",MenuType::CLASS_SELECTION,[](MenuFuncData data){ SaveFile::SetSaveFileName(game->TextEntryGetString()); SaveFile::SetSaveFileID(SaveFile::GetSaveFileCount()); game->TextEntryEnable(false); diff --git a/Adventures in Lestoria/ScrollableWindowComponent.h b/Adventures in Lestoria/ScrollableWindowComponent.h index 67d2df58..b8d11a05 100644 --- a/Adventures in Lestoria/ScrollableWindowComponent.h +++ b/Adventures in Lestoria/ScrollableWindowComponent.h @@ -46,9 +46,9 @@ using A=Attribute; class ScrollableWindowComponent:public MenuComponent{ protected: ViewPort subWindow; - std::vectorcomponents; - MenuComponent*upButton=nullptr; - MenuComponent*downButton=nullptr; + std::vector>components; + std::weak_ptrupButton; + std::weak_ptrdownButton; geom2d::rectbounds; //It's for the scrollbar. float scrollBarHeight=0; float scrollBarTop=0; @@ -56,8 +56,8 @@ protected: float scrollBarHoverTime=0; vf2d scrollOffset; protected: - inline bool OnScreen(MenuComponent*component){ - return geom2d::overlaps(geom2d::rect{{},rect.size},geom2d::rect{component->rect.pos+vf2d{2,2},component->rect.size-vf2d{2,2}}); + inline bool OnScreen(std::weak_ptrcomponent){ + return geom2d::overlaps(geom2d::rect{{},rect.size},geom2d::rect{component.lock()->rect.pos+vf2d{2,2},component.lock()->rect.size-vf2d{2,2}}); } public: inline ScrollableWindowComponent(geom2d::rectrect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE) @@ -70,37 +70,25 @@ public: RemoveButton(components.back()); } } - virtual inline void RemoveButton(MenuComponent*button){ - std::vector&buttonList=Menu::menus[button->parentMenu]->buttons.at(int(button->originalPos.y)); - std::vector&keyboardButtonList=Menu::menus[button->parentMenu]->keyboardButtons.at(int(button->originalPos.y)); + virtual inline void RemoveButton(std::weak_ptrbutton){ + auto componentSearchResults=std::find_if(components.begin(),components.end(),[&](std::weak_ptrptr){return &*ptr.lock()==&*button.lock();}); + if(componentSearchResults==components.end())ERR("Could not find Component"<GetName())<<" inside the component list!"); + components.erase(componentSearchResults); size_t removedCount=0; - removedCount+=std::erase(buttonList,button); - removedCount+=std::erase(keyboardButtonList,button); - removedCount+=Menu::menus[button->parentMenu]->components.erase(button->GetName()); - if(removedCount!=3){ + + MenuType parentMenu=button.lock()->parentMenu; + + removedCount+=Menu::menus[parentMenu]->components.erase(button.lock()->GetName()); + if(removedCount!=1){ std::cout<<"WARNING! Attempted to remove buttons from button listing, but not found!"; } - if(buttonList.size()==0){ - if(!Menu::menus[button->parentMenu]->buttons.erase(int(button->originalPos.y))){ - ERR("WARNING! Attempted to erase key "<originalPos.y<<" from button map, but the list still exists!") - } - } - if(keyboardButtonList.size()==0){ - if(!Menu::menus[button->parentMenu]->keyboardButtons.erase(int(button->originalPos.y))){ - ERR("WARNING! Attempted to erase key "<originalPos.y<<" from button map, but the list still exists!") - } - } - auto componentSearchResults=std::find(components.begin(),components.end(),button); - if(componentSearchResults==components.end())ERR("Could not find Component"<GetName())<<" inside the component list!"); - components.erase(componentSearchResults); - Menu::menus[button->parentMenu]->RecalculateComponentCount(); - delete button; + Menu::menus[parentMenu]->RecalculateComponentCount(); CalculateBounds(); } virtual inline void SetScrollAmount(vf2d scrollOffset){ this->scrollOffset=scrollOffset; - for(MenuComponent*component:components){ - component->rect.pos=component->originalPos+scrollOffset; + for(std::weak_ptrcomponent:components){ + component.lock()->rect.pos=component.lock()->originalPos+scrollOffset; } } virtual inline vf2d GetScrollAmount(){ @@ -109,16 +97,16 @@ public: protected: virtual inline void AfterCreate()override{ //Let's use the internal name of this component to add unique names for sub-components. - upButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+vf2d{rect.size.x-12,0}).str()+"_"+vf2d(12,12).str(),MenuComponent)({rect.pos+vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){SetScrollAmount(GetScrollAmount()+vf2d{0,"ThemeGlobal.MenuButtonScrollSpeed"_F});return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH depth-1 END; - downButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+rect.size-vf2d{12,12}).str()+"_"+vf2d(12,12).str(),MenuComponent)({rect.pos+rect.size-vf2d{12,12},{12,12}},"v",[&](MenuFuncData dat){SetScrollAmount(GetScrollAmount()-vf2d{0,"ThemeGlobal.MenuButtonScrollSpeed"_F});return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH depth-1 END; + upButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+vf2d{rect.size.x-12,0}).str()+"_"+vf2d(12,12).str(),MenuComponent)(geom2d::rect{rect.pos+vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){SetScrollAmount(GetScrollAmount()+vf2d{0,"ThemeGlobal.MenuButtonScrollSpeed"_F});return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH depth-1 END; + downButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+rect.size-vf2d{12,12}).str()+"_"+vf2d(12,12).str(),MenuComponent)(geom2d::rect{rect.pos+rect.size-vf2d{12,12},{12,12}},"v",[&](MenuFuncData dat){SetScrollAmount(GetScrollAmount()-vf2d{0,"ThemeGlobal.MenuButtonScrollSpeed"_F});return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH depth-1 END; subWindow=ViewPort::rectViewPort({},rect.size,Menu::menus[parentMenu]->pos+rect.pos); - if(upButton){upButton->Enable(!disabled);} - if(downButton){downButton->Enable(!disabled);} + if(!upButton.expired()){upButton.lock()->Enable(!disabled);} + if(!downButton.expired()){downButton.lock()->Enable(!disabled);} } virtual inline void BeforeUpdate(AiL*game)override{ MenuComponent::BeforeUpdate(game); - for(MenuComponent*component:components){ - component->_BeforeUpdate(game); + for(std::weak_ptrcomponent:components){ + component.lock()->_BeforeUpdate(game); } } virtual inline void Update(AiL*game)override{ @@ -165,17 +153,17 @@ protected: SetScrollAmount({GetScrollAmount().x,0}); } - std::sort(components.begin(),components.end(),[](MenuComponent*c1,MenuComponent*c2){return c1->depth>c2->depth;}); - for(MenuComponent*component:components){ - component->disabled=!OnScreen(component); - component->_Update(game); + std::sort(components.begin(),components.end(),[](std::weak_ptrc1,std::weak_ptrc2){return c1.lock()->depth>c2.lock()->depth;}); + for(std::weak_ptrcomponent:components){ + component.lock()->disabled=!OnScreen(component.lock()); + component.lock()->_Update(game); } - upButton->disabled=false; - downButton->disabled=false; + upButton.lock()->disabled=false; + downButton.lock()->disabled=false; if(geom2d::contains(rect,bounds)){//This means we have no reason to show a scrollbar. - upButton->disabled=true; - downButton->disabled=true; + upButton.lock()->disabled=true; + downButton.lock()->disabled=true; } } inline void DrawScrollbar(ViewPort&window,vf2d parentPos,bool focused){ @@ -198,8 +186,8 @@ protected: if(border){ window.DrawRectDecal(rect.pos,rect.size); } - for(MenuComponent*component:components){ - component->_DrawDecal(subWindow,focused); + for(std::weak_ptrcomponent:components){ + component.lock()->_DrawDecal(subWindow,focused); } if(!geom2d::contains(rect,bounds)){ DrawScrollbar(window,{},focused); @@ -212,33 +200,33 @@ protected: //Calculates the bounds of all components. inline void CalculateBounds(){ bounds={}; - for(MenuComponent*component:components){ - if(component->rect.pos.xrect.pos.x; + for(std::weak_ptrcomponent:components){ + if(component.lock()->rect.pos.xrect.pos.x; bounds.size.x+=sizeIncrease; - bounds.pos.x=component->rect.pos.x; + bounds.pos.x=component.lock()->rect.pos.x; } - if(component->rect.right().start.x>bounds.right().start.x){ - float sizeIncrease=component->rect.right().start.x-bounds.right().start.x; + if(component.lock()->rect.right().start.x>bounds.right().start.x){ + float sizeIncrease=component.lock()->rect.right().start.x-bounds.right().start.x; bounds.size.x+=sizeIncrease; } - if(component->rect.pos.yrect.pos.y; + if(component.lock()->rect.pos.yrect.pos.y; bounds.size.y+=sizeIncrease; - bounds.pos.y=component->rect.pos.y; + bounds.pos.y=component.lock()->rect.pos.y; } - if(component->rect.bottom().start.y>bounds.bottom().start.y){ - float sizeIncrease=component->rect.bottom().start.y-bounds.bottom().start.y; + if(component.lock()->rect.bottom().start.y>bounds.bottom().start.y){ + float sizeIncrease=component.lock()->rect.bottom().start.y-bounds.bottom().start.y; bounds.size.y+=sizeIncrease; } } } public: template - T* _AddComponent(std::string key,T*button){ + std::shared_ptr _AddComponent(std::string key,std::shared_ptrbutton){ components.push_back(button); button->renderInMain=false; //Now we are in control! - button->parentComponent=this; + button->parentComponent=Menu::menus[parentMenu]->components[this->GetName()]; button->disabled=disabled; CalculateBounds(); @@ -252,21 +240,21 @@ public: virtual inline bool PointWithinParent(MenuComponent*child,geom2d::rect drawRect)override{ return geom2d::overlaps(geom2d::rect{Menu::menus[parentMenu]->pos+rect.pos,rect.size},drawRect); } - virtual inline bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton)override{ + virtual inline bool HandleOutsideDisabledButtonSelection(std::weak_ptrdisabledButton)override{ //Set the offset so the center is highlighted by this button. - SetScrollAmount(vf2d{GetScrollAmount().x,-disabledButton->rect.pos.y+disabledButton->rect.size.y}); + SetScrollAmount(vf2d{GetScrollAmount().x,-disabledButton.lock()->rect.pos.y+disabledButton.lock()->rect.size.y}); return true; }; virtual void Cleanup()override{} - inline std::vector&GetComponents(){ + inline std::vector>&GetComponents(){ return components; } virtual inline void Enable(bool enabled)override final{ disabled=!enabled; - for(MenuComponent*component:components){ - component->Enable(enabled); + for(std::weak_ptrcomponent:components){ + component.lock()->Enable(enabled); } - if(upButton){upButton->Enable(enabled);} - if(downButton){downButton->Enable(enabled);} + if(upButton.lock()){upButton.lock()->Enable(enabled);} + if(downButton.lock()){downButton.lock()->Enable(enabled);} }; }; \ No newline at end of file diff --git a/Adventures in Lestoria/SellItemWindow.cpp b/Adventures in Lestoria/SellItemWindow.cpp index 1e768cdc..cc9a2888 100644 --- a/Adventures in Lestoria/SellItemWindow.cpp +++ b/Adventures in Lestoria/SellItemWindow.cpp @@ -62,34 +62,34 @@ void Menu::InitializeSellItemWindow(){ Component(SELL_ITEM,"Sell Button")->SetGrayedOut(!canSell); }; - sellItemWindow->ADD("Item Sell Header",ItemMenuLabel)({{2,2},{188,12}},"Selling {}",Item::BLANK,1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; + sellItemWindow->ADD("Item Sell Header",ItemMenuLabel)(geom2d::rect{{2,2},{188,12}},"Selling {}",Item::BLANK,1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; - sellItemWindow->ADD("Price Per Item Label",MenuLabel)({{4,18},{188,12}},"Price Per Item",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - sellItemWindow->ADD("Amount to Sell Label",MenuLabel)({{4,34},{188,12}},"Amount to Sell",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - sellItemWindow->ADD("Price Label",MenuLabel)({{4,50},{188,12}},"Total Price",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + sellItemWindow->ADD("Price Per Item Label",MenuLabel)(geom2d::rect{{4,18},{188,12}},"Price Per Item",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + sellItemWindow->ADD("Amount to Sell Label",MenuLabel)(geom2d::rect{{4,34},{188,12}},"Amount to Sell",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + sellItemWindow->ADD("Price Label",MenuLabel)(geom2d::rect{{4,50},{188,12}},"Total Price",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - sellItemWindow->ADD("Price per item Amount Label",MenuLabel)({{sellItemWindow->size.x/2+28,18},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; - sellItemWindow->ADD("Amount to sell Amount Label",MenuLabel)({{sellItemWindow->size.x/2+48,34},{32,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::FIT_TO_LABEL)END; + sellItemWindow->ADD("Price per item Amount Label",MenuLabel)(geom2d::rect{{sellItemWindow->size.x/2+28,18},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; + sellItemWindow->ADD("Amount to sell Amount Label",MenuLabel)(geom2d::rect{{sellItemWindow->size.x/2+48,34},{32,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::FIT_TO_LABEL)END; - sellItemWindow->ADD("Increase sell amount Button",MenuComponent)({{sellItemWindow->size.x/2+80+2,34},{12,12}},"+",[&](MenuFuncData data){ + sellItemWindow->ADD("Increase sell amount Button",MenuComponent)(geom2d::rect{{sellItemWindow->size.x/2+80+2,34},{12,12}},"+",[&](MenuFuncData data){ UpdateMenu(GetQuantity()+1); return true; })END; - sellItemWindow->ADD("Decrease sell amount Button",MenuComponent)({{sellItemWindow->size.x/2+48-14,34},{12,12}},"-",[](MenuFuncData data){ + sellItemWindow->ADD("Decrease sell amount Button",MenuComponent)(geom2d::rect{{sellItemWindow->size.x/2+48-14,34},{12,12}},"-",[](MenuFuncData data){ UpdateMenu(GetQuantity()-1); return true; })END; - sellItemWindow->ADD("Total Price Amount Label",MenuLabel)({{sellItemWindow->size.x/2+28,50},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; + sellItemWindow->ADD("Total Price Amount Label",MenuLabel)(geom2d::rect{{sellItemWindow->size.x/2+28,50},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; - sellItemWindow->ADD("Sell Button",MenuComponent)({{sellItemWindow->size.x/2+18,70},{64,12}},"Sell",[&](MenuFuncData data){ + sellItemWindow->ADD("Sell Button",MenuComponent)(geom2d::rect{{sellItemWindow->size.x/2+18,70},{64,12}},"Sell",[&](MenuFuncData data){ Merchant&merchant=Merchant::GetCurrentTravelingMerchant(); merchant.SellItem(Component(SELL_ITEM,"Item Sell Header")->GetItem(),GetQuantity()); SoundEffect::PlaySFX("Sell Item",SoundEffect::CENTERED); Menu::CloseMenu(); return true; })END; - sellItemWindow->ADD("Cancel Button",MenuComponent)({{sellItemWindow->size.x/2-82,70},{64,12}},"Cancel",[](MenuFuncData data){ + sellItemWindow->ADD("Cancel Button",MenuComponent)(geom2d::rect{{sellItemWindow->size.x/2-82,70},{64,12}},"Cancel",[](MenuFuncData data){ Menu::CloseMenu(); return true; })END; diff --git a/Adventures in Lestoria/TODO.txt b/Adventures in Lestoria/TODO.txt index 66385e0f..bc699c08 100644 --- a/Adventures in Lestoria/TODO.txt +++ b/Adventures in Lestoria/TODO.txt @@ -1,5 +1,6 @@ January 1st =========== +Fix Listeners so they do not leak! (Add a proper listener class and have all listeners inherit from it.) The Hub / NPC Interactions Settings Menu - Any settings should be saved to the save file! diff --git a/Adventures in Lestoria/Toggleable.h b/Adventures in Lestoria/Toggleable.h index aec2648d..172263ac 100644 --- a/Adventures in Lestoria/Toggleable.h +++ b/Adventures in Lestoria/Toggleable.h @@ -37,15 +37,15 @@ All rights reserved. #pragma endregion #pragma once -class IToggleable{ +class IToggleable:public std::enable_shared_from_this{ friend class AiL; public: - inline std::vectorGetToggleGroup(){ + inline std::vector>GetToggleGroup(){ return toggleGroup; } inline void Select(){ - for(IToggleable*item:toggleGroup){ - item->selected=false; + for(std::weak_ptritem:toggleGroup){ + item.lock()->selected=false; } selected=true; } @@ -57,24 +57,14 @@ public: ERR("WARNING! Toggle group for this component was set twice for some reason! THIS SHOULD NOT BE HAPPENING!") } toggleGroupInitialized=true; - std::erase_if(uninitializedToggleGroupItems,[&](IToggleable*item){return this==item;}); } - inline void SetToggleGroup(std::vectortoggleGroup){ + inline void SetToggleGroup(std::vector>toggleGroup){ this->toggleGroup=toggleGroup; SetToggleGroup(); } - inline IToggleable(){ - uninitializedToggleGroupItems.push_back(this); - #ifdef _DEBUG - if("debug_toggleable_items"_I){ - std::cout<<"\tInitialized Toggle Item Ptr: 0x"<toggleGroup; + std::vector>toggleGroup; private: bool selected=false; bool toggleGroupInitialized=false; - inline static std::vectoruninitializedToggleGroupItems; }; \ No newline at end of file diff --git a/Adventures in Lestoria/UserIDMenu.cpp b/Adventures in Lestoria/UserIDMenu.cpp index 7825b4f4..d95e37db 100644 --- a/Adventures in Lestoria/UserIDMenu.cpp +++ b/Adventures in Lestoria/UserIDMenu.cpp @@ -46,15 +46,15 @@ using A=Attribute; void Menu::InitializeUserIDWindow(){ Menu*userIDWindow=CreateMenu(USER_ID,CENTERED,vi2d{168,120}); - userIDWindow->ADD("User ID Creation Explanation",MenuLabel)({{0,-4},{168,92}},"user_id_message"_FS+"\n\n"+"user_id_message2"_FS,1.f,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; - userIDWindow->ADD("User ID Input",TextEntryLabel)({{36,94},{96,12}},[](std::string_view newLabel){ + userIDWindow->ADD("User ID Creation Explanation",MenuLabel)(geom2d::rect{{0,-4},{168,92}},"user_id_message"_FS+"\n\n"+"user_id_message2"_FS,1.f,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; + userIDWindow->ADD("User ID Input",TextEntryLabel)(geom2d::rect{{36,94},{96,12}},[](std::string_view newLabel){ Component(USER_ID,"Submit Button")->SetGrayedOut(newLabel.length()==0); },true,24U,1.f,ComponentAttr::BACKGROUND|ComponentAttr::FIT_TO_LABEL|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END; - userIDWindow->ADD("Back Button",MenuComponent)({{18,110},{48,12}},"Back",[](MenuFuncData data){ + userIDWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{18,110},{48,12}},"Back",[](MenuFuncData data){ Menu::CloseMenu(); return true; })END; - userIDWindow->ADD("Submit Button",MenuComponent)({{102,110},{48,12}},"Submit",[](MenuFuncData data){ + userIDWindow->ADD("Submit Button",MenuComponent)(geom2d::rect{{102,110},{48,12}},"Submit",[](MenuFuncData data){ SaveFile::SetUserID(Component(USER_ID,"User ID Input")->GetLabel()); if(Menu::menus[MAIN_MENU]->S(A::NEXT_MENU)=="New Game"){ Menu::CloseMenu(); diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 5efbaa46..fcd8522e 100644 --- a/Adventures in Lestoria/Version.h +++ b/Adventures in Lestoria/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 0 #define VERSION_MINOR 2 #define VERSION_PATCH 1 -#define VERSION_BUILD 5870 +#define VERSION_BUILD 5947 #define stringify(a) stringify_(a) #define stringify_(a) #a