littlejsengine 1.4.6 → 1.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -63,7 +63,7 @@ class Medal
63
63
  this.name = name;
64
64
  this.description = description;
65
65
  this.icon = icon;
66
- this.image = new Image();
66
+ this.image = new Image;
67
67
  if (src)
68
68
  this.image.src = src;
69
69
  }
@@ -78,10 +78,7 @@ class Medal
78
78
  ASSERT(medalsSaveName); // save name must be set
79
79
  localStorage[this.storageKey()] = this.unlocked = 1;
80
80
  medalsDisplayQueue.push(this);
81
-
82
- // save for newgrounds and OS13K
83
81
  newgrounds && newgrounds.unlockMedal(this.id);
84
- localStorage['OS13kTrophy,' + this.icon + ',' + medalsSaveName + ',' + this.name] = this.description;
85
82
  }
86
83
 
87
84
  /** Render a medal
@@ -97,20 +94,19 @@ class Medal
97
94
  // draw containing rect and clip to that region
98
95
  context.save();
99
96
  context.beginPath();
100
- context.fillStyle = '#ddd'
101
- context.fill(context.rect(x, y, width, medalDisplayHeight));
102
- context.strokeStyle = '#000';
97
+ context.fillStyle = new Color(.9,.9,.9);
98
+ context.strokeStyle = new Color(0,0,0);
103
99
  context.lineWidth = 3;
100
+ context.fill(context.rect(x, y, width, medalDisplayHeight));
104
101
  context.stroke();
105
102
  context.clip();
106
103
 
107
104
  // draw the icon and text
108
- this.renderIcon(x+15+medalDisplayIconSize/2, y+medalDisplayHeight/2);
109
- context.textAlign = 'left';
110
- context.font = '38px '+ fontDefault;
111
- context.fillText(this.name, x+medalDisplayIconSize+30, y+28);
112
- context.font = '24px '+ fontDefault;
113
- context.fillText(this.description, x+medalDisplayIconSize+30, y+60);
105
+ this.renderIcon(vec2(x+15+medalDisplayIconSize/2, y+medalDisplayHeight/2));
106
+ const pos = vec2(x+medalDisplayIconSize+30, y+28);
107
+ drawTextScreen(this.name, pos, 38, new Color(0,0,0), 0, 0, 'left');
108
+ pos.y += 32;
109
+ drawTextScreen(this.description, pos, 24, new Color(0,0,0), 0, 0, 'left');
114
110
  context.restore();
115
111
  }
116
112
 
@@ -119,18 +115,13 @@ class Medal
119
115
  * @param {Number} y - Screen space Y position
120
116
  * @param {Number} [size=medalDisplayIconSize] - Screen space size
121
117
  */
122
- renderIcon(x, y, size=medalDisplayIconSize)
118
+ renderIcon(pos, size=medalDisplayIconSize)
123
119
  {
124
120
  // draw the image or icon
125
- const context = overlayContext;
126
- context.fillStyle = '#000';
127
- context.textAlign = 'center';
128
- context.textBaseline = 'middle';
129
- context.font = size*.7 + 'px '+ fontDefault;
130
- if (this.image.src)
131
- context.drawImage(this.image, x-size/2, y-size/2, size, size);
121
+ if (this.image)
122
+ overlayContext.drawImage(this.image, pos.x-size/2, pos.y-size/2, size, size);
132
123
  else
133
- context.fillText(this.icon, x, y); // show icon if there is no image
124
+ drawTextScreen(this.icon, pos, size*.7, new Color(0,0,0));
134
125
  }
135
126
 
136
127
  // Get local storage key used by the medal
@@ -188,13 +179,21 @@ class Newgrounds
188
179
  constructor(app_id, cipher)
189
180
  {
190
181
  ASSERT(!newgrounds && app_id);
182
+
183
+ // create an instance of CryptoJS for encrypted calls
184
+ if (cipher)
185
+ {
186
+ ///////////////////////////////////////////////////////////////////////////////
187
+ // Crypto-JS - https://github.com/brix/crypto-js [The MIT License (MIT)]
188
+ // Copyright (c) 2009-2013 Jeff Mott Copyright (c) 2013-2016 Evan Vosberg
189
+
190
+ this.cryptoJS = eval(Function("[M='GBMGXz^oVYPPKKbB`agTXU|LxPc_ZBcMrZvCr~wyGfWrwk@ATqlqeTp^N?p{we}jIpEnB_sEr`l?YDkDhWhprc|Er|XETG?pTl`e}dIc[_N~}fzRycIfpW{HTolvoPB_FMe_eH~BTMx]yyOhv?biWPCGc]kABencBhgERHGf{OL`Dj`c^sh@canhy[secghiyotcdOWgO{tJIE^JtdGQRNSCrwKYciZOa]Y@tcRATYKzv|sXpboHcbCBf`}SKeXPFM|RiJsSNaIb]QPc[D]Jy_O^XkOVTZep`ONmntLL`Qz~UupHBX_Ia~WX]yTRJIxG`ioZ{fefLJFhdyYoyLPvqgH?b`[TMnTwwfzDXhfM?rKs^aFr|nyBdPmVHTtAjXoYUloEziWDCw_suyYT~lSMksI~ZNCS[Bex~j]Vz?kx`gdYSEMCsHpjbyxQvw|XxX_^nQYue{sBzVWQKYndtYQMWRef{bOHSfQhiNdtR{o?cUAHQAABThwHPT}F{VvFmgN`E@FiFYS`UJmpQNM`X|tPKHlccT}z}k{sACHL?Rt@MkWplxO`ASgh?hBsuuP|xD~LSH~KBlRs]t|l|_tQAroDRqWS^SEr[sYdPB}TAROtW{mIkE|dWOuLgLmJrucGLpebrAFKWjikTUzS|j}M}szasKOmrjy[?hpwnEfX[jGpLt@^v_eNwSQHNwtOtDgWD{rk|UgASs@mziIXrsHN_|hZuxXlPJOsA^^?QY^yGoCBx{ekLuZzRqQZdsNSx@ezDAn{XNj@fRXIwrDX?{ZQHwTEfu@GhxDOykqts|n{jOeZ@c`dvTY?e^]ATvWpb?SVyg]GC?SlzteilZJAL]mlhLjYZazY__qcVFYvt@|bIQnSno@OXyt]OulzkWqH`rYFWrwGs`v|~XeTsIssLrbmHZCYHiJrX}eEzSssH}]l]IhPQhPoQ}rCXLyhFIT[clhzYOvyHqigxmjz`phKUU^TPf[GRAIhNqSOdayFP@FmKmuIzMOeoqdpxyCOwCthcLq?n`L`tLIBboNn~uXeFcPE{C~mC`h]jUUUQe^`UqvzCutYCgct|SBrAeiYQW?X~KzCz}guXbsUw?pLsg@hDArw?KeJD[BN?GD@wgFWCiHq@Ypp_QKFixEKWqRp]oJFuVIEvjDcTFu~Zz]a{IcXhWuIdMQjJ]lwmGQ|]g~c]Hl]pl`Pd^?loIcsoNir_kikBYyg?NarXZEGYspt_vLBIoj}LI[uBFvm}tbqvC|xyR~a{kob|HlctZslTGtPDhBKsNsoZPuH`U`Fqg{gKnGSHVLJ^O`zmNgMn~{rsQuoymw^JY?iUBvw_~mMr|GrPHTERS[MiNpY[Mm{ggHpzRaJaoFomtdaQ_?xuTRm}@KjU~RtPsAdxa|uHmy}n^i||FVL[eQAPrWfLm^ndczgF~Nk~aplQvTUpHvnTya]kOenZlLAQIm{lPl@CCTchvCF[fI{^zPkeYZTiamoEcKmBMfZhk_j_~Fjp|wPVZlkh_nHu]@tP|hS@^G^PdsQ~f[RqgTDqezxNFcaO}HZhb|MMiNSYSAnQWCDJukT~e|OTgc}sf[cnr?fyzTa|EwEtRG|I~|IO}O]S|rp]CQ}}DWhSjC_|z|oY|FYl@WkCOoPuWuqr{fJu?Brs^_EBI[@_OCKs}?]O`jnDiXBvaIWhhMAQDNb{U`bqVR}oqVAvR@AZHEBY@depD]OLh`kf^UsHhzKT}CS}HQKy}Q~AeMydXPQztWSSzDnghULQgMAmbWIZ|lWWeEXrE^EeNoZApooEmrXe{NAnoDf`m}UNlRdqQ@jOc~HLOMWs]IDqJHYoMziEedGBPOxOb?[X`KxkFRg@`mgFYnP{hSaxwZfBQqTm}_?RSEaQga]w[vxc]hMne}VfSlqUeMo_iqmd`ilnJXnhdj^EEFifvZyxYFRf^VaqBhLyrGlk~qowqzHOBlOwtx?i{m~`n^G?Yxzxux}b{LSlx]dS~thO^lYE}bzKmUEzwW^{rPGhbEov[Plv??xtyKJshbG`KuO?hjBdS@Ru}iGpvFXJRrvOlrKN?`I_n_tplk}kgwSXuKylXbRQ]]?a|{xiT[li?k]CJpwy^o@ebyGQrPfF`aszGKp]baIx~H?ElETtFh]dz[OjGl@C?]VDhr}OE@V]wLTc[WErXacM{We`F|utKKjgllAxvsVYBZ@HcuMgLboFHVZmi}eIXAIFhS@A@FGRbjeoJWZ_NKd^oEH`qgy`q[Tq{x?LRP|GfBFFJV|fgZs`MLbpPYUdIV^]mD@FG]pYAT^A^RNCcXVrPsgk{jTrAIQPs_`mD}rOqAZA[}RETFz]WkXFTz_m{N@{W@_fPKZLT`@aIqf|L^Mb|crNqZ{BVsijzpGPEKQQZGlApDn`ruH}cvF|iXcNqK}cxe_U~HRnKV}sCYb`D~oGvwG[Ca|UaybXea~DdD~LiIbGRxJ_VGheI{ika}KC[OZJLn^IBkPrQj_EuoFwZ}DpoBRcK]Q}?EmTv~i_Tul{bky?Iit~tgS|o}JL_VYcCQdjeJ_MfaA`FgCgc[Ii|CBHwq~nbJeYTK{e`CNstKfTKPzw{jdhp|qsZyP_FcugxCFNpKitlR~vUrx^NrSVsSTaEgnxZTmKc`R|lGJeX}ccKLsQZQhsFkeFd|ckHIVTlGMg`~uPwuHRJS_CPuN_ogXe{Ba}dO_UBhuNXby|h?JlgBIqMKx^_u{molgL[W_iavNQuOq?ap]PGB`clAicnl@k~pA?MWHEZ{HuTLsCpOxxrKlBh]FyMjLdFl|nMIvTHyGAlPogqfZ?PlvlFJvYnDQd}R@uAhtJmDfe|iJqdkYr}r@mEjjIetDl_I`TELfoR|qTBu@Tic[BaXjP?dCS~MUK[HPRI}OUOwAaf|_}HZzrwXvbnNgltjTwkBE~MztTQhtRSWoQHajMoVyBBA`kdgK~h`o[J`dm~pm]tk@i`[F~F]DBlJKklrkR]SNw@{aG~Vhl`KINsQkOy?WhcqUMTGDOM_]bUjVd|Yh_KUCCgIJ|LDIGZCPls{RzbVWVLEhHvWBzKq|^N?DyJB|__aCUjoEgsARki}j@DQXS`RNU|DJ^a~d{sh_Iu{ONcUtSrGWW@cvUjefHHi}eSSGrNtO?cTPBShLqzwMVjWQQCCFB^culBjZHEK_{dO~Q`YhJYFn]jq~XSnG@[lQr]eKrjXpG~L^h~tDgEma^AUFThlaR{xyuP@[^VFwXSeUbVetufa@dX]CLyAnDV@Bs[DnpeghJw^?UIana}r_CKGDySoRudklbgio}kIDpA@McDoPK?iYcG?_zOmnWfJp}a[JLR[stXMo?_^Ng[whQlrDbrawZeSZ~SJstIObdDSfAA{MV}?gNunLOnbMv_~KFQUAjIMj^GkoGxuYtYbGDImEYiwEMyTpMxN_LSnSMdl{bg@dtAnAMvhDTBR_FxoQgANniRqxd`pWv@rFJ|mWNWmh[GMJz_Nq`BIN@KsjMPASXORcdHjf~rJfgZYe_uulzqM_KdPlMsuvU^YJuLtofPhGonVOQxCMuXliNvJIaoC?hSxcxKVVxWlNs^ENDvCtSmO~WxI[itnjs^RDvI@KqG}YekaSbTaB]ki]XM@[ZnDAP~@|BzLRgOzmjmPkRE@_sobkT|SszXK[rZN?F]Z_u}Yue^[BZgLtR}FHzWyxWEX^wXC]MJmiVbQuBzkgRcKGUhOvUc_bga|Tx`KEM`JWEgTpFYVeXLCm|mctZR@uKTDeUONPozBeIkrY`cz]]~WPGMUf`MNUGHDbxZuO{gmsKYkAGRPqjc|_FtblEOwy}dnwCHo]PJhN~JoteaJ?dmYZeB^Xd?X^pOKDbOMF@Ugg^hETLdhwlA}PL@_ur|o{VZosP?ntJ_kG][g{Zq`Tu]dzQlSWiKfnxDnk}KOzp~tdFstMobmy[oPYjyOtUzMWdjcNSUAjRuqhLS@AwB^{BFnqjCmmlk?jpn}TksS{KcKkDboXiwK]qMVjm~V`LgWhjS^nLGwfhAYrjDSBL_{cRus~{?xar_xqPlArrYFd?pHKdMEZzzjJpfC?Hv}mAuIDkyBxFpxhstTx`IO{rp}XGuQ]VtbHerlRc_LFGWK[XluFcNGUtDYMZny[M^nVKVeMllQI[xtvwQnXFlWYqxZZFp_|]^oWX[{pOMpxXxvkbyJA[DrPzwD|LW|QcV{Nw~U^dgguSpG]ClmO@j_TENIGjPWwgdVbHganhM?ema|dBaqla|WBd`poj~klxaasKxGG^xbWquAl~_lKWxUkDFagMnE{zHug{b`A~IYcQYBF_E}wiA}K@yxWHrZ{[d~|ARsYsjeNWzkMs~IOqqp[yzDE|WFrivsidTcnbHFRoW@XpAV`lv_zj?B~tPCppRjgbbDTALeFaOf?VcjnKTQMLyp{NwdylHCqmo?oelhjWuXj~}{fpuX`fra?GNkDiChYgVSh{R[BgF~eQa^WVz}ATI_CpY?g_diae]|ijH`TyNIF}|D_xpmBq_JpKih{Ba|sWzhnAoyraiDvk`h{qbBfsylBGmRH}DRPdryEsSaKS~tIaeF[s]I~xxHVrcNe@Jjxa@jlhZueLQqHh_]twVMqG_EGuwyab{nxOF?`HCle}nBZzlTQjkLmoXbXhOtBglFoMz?eqre`HiE@vNwBulglmQjj]DB@pPkPUgA^sjOAUNdSu_`oAzar?n?eMnw{{hYmslYi[TnlJD'",...']charCodeAtUinyxpf',"for(;e<10359;c[e++]=p-=128,A=A?p-A&&A:p==34&&p)for(p=1;p<128;y=f.map((n,x)=>(U=r[n]*2+1,U=Math.log(U/(h-U)),t-=a[x]*U,U/500)),t=~-h/(1+Math.exp(t))|1,i=o%h<t,o=o%h+(i?t:h-t)*(o>>17)-!i*t,f.map((n,x)=>(U=r[n]+=(i*h/2-r[n]<<13)/((C[n]+=C[n]<5)+1/20)>>13,a[x]+=y[x]*(i-t/h))),p=p*2+i)for(f='010202103203210431053105410642065206541'.split(t=0).map((n,x)=>(U=0,[...n].map((n,x)=>(U=U*997+(c[e-n]|0)|0)),h*32-1&U*997+p+!!A*129)*12+x);o<h*32;o=o*64|M.charCodeAt(d++)&63);for(C=String.fromCharCode(...c);r=/[\0-#?@\\\\~]/.exec(C);)with(C.split(r))C=join(shift());return C")([],[],1<<17,[0,0,0,0,0,0,0,0,0,0,0,0],new Uint16Array(51e6).fill(1<<15),new Uint8Array(51e6),0,0,0,0));
191
+ }
192
+
191
193
  this.app_id = app_id;
192
194
  this.cipher = cipher;
193
195
  this.host = location ? location.hostname : '';
194
196
 
195
- // create an instance of CryptoJS for encrypted calls
196
- cipher && (this.cryptoJS = CryptoJS());
197
-
198
197
  // get session id from url search params
199
198
  const url = new URL(location.href);
200
199
  this.session_id = url.searchParams.get('ngio_session_id') || 0;
@@ -296,10 +295,4 @@ class Newgrounds
296
295
  debugMedals && console.log(xmlHttp.responseText);
297
296
  return xmlHttp.responseText && JSON.parse(xmlHttp.responseText);
298
297
  }
299
- }
300
-
301
- ///////////////////////////////////////////////////////////////////////////////
302
- // Crypto-JS - https://github.com/brix/crypto-js [The MIT License (MIT)]
303
- // Copyright (c) 2009-2013 Jeff Mott Copyright (c) 2013-2016 Evan Vosberg
304
-
305
- const CryptoJS=()=>eval(Function("[M='GBMGXz^oVYPPKKbB`agTXU|LxPc_ZBcMrZvCr~wyGfWrwk@ATqlqeTp^N?p{we}jIpEnB_sEr`l?YDkDhWhprc|Er|XETG?pTl`e}dIc[_N~}fzRycIfpW{HTolvoPB_FMe_eH~BTMx]yyOhv?biWPCGc]kABencBhgERHGf{OL`Dj`c^sh@canhy[secghiyotcdOWgO{tJIE^JtdGQRNSCrwKYciZOa]Y@tcRATYKzv|sXpboHcbCBf`}SKeXPFM|RiJsSNaIb]QPc[D]Jy_O^XkOVTZep`ONmntLL`Qz~UupHBX_Ia~WX]yTRJIxG`ioZ{fefLJFhdyYoyLPvqgH?b`[TMnTwwfzDXhfM?rKs^aFr|nyBdPmVHTtAjXoYUloEziWDCw_suyYT~lSMksI~ZNCS[Bex~j]Vz?kx`gdYSEMCsHpjbyxQvw|XxX_^nQYue{sBzVWQKYndtYQMWRef{bOHSfQhiNdtR{o?cUAHQAABThwHPT}F{VvFmgN`E@FiFYS`UJmpQNM`X|tPKHlccT}z}k{sACHL?Rt@MkWplxO`ASgh?hBsuuP|xD~LSH~KBlRs]t|l|_tQAroDRqWS^SEr[sYdPB}TAROtW{mIkE|dWOuLgLmJrucGLpebrAFKWjikTUzS|j}M}szasKOmrjy[?hpwnEfX[jGpLt@^v_eNwSQHNwtOtDgWD{rk|UgASs@mziIXrsHN_|hZuxXlPJOsA^^?QY^yGoCBx{ekLuZzRqQZdsNSx@ezDAn{XNj@fRXIwrDX?{ZQHwTEfu@GhxDOykqts|n{jOeZ@c`dvTY?e^]ATvWpb?SVyg]GC?SlzteilZJAL]mlhLjYZazY__qcVFYvt@|bIQnSno@OXyt]OulzkWqH`rYFWrwGs`v|~XeTsIssLrbmHZCYHiJrX}eEzSssH}]l]IhPQhPoQ}rCXLyhFIT[clhzYOvyHqigxmjz`phKUU^TPf[GRAIhNqSOdayFP@FmKmuIzMOeoqdpxyCOwCthcLq?n`L`tLIBboNn~uXeFcPE{C~mC`h]jUUUQe^`UqvzCutYCgct|SBrAeiYQW?X~KzCz}guXbsUw?pLsg@hDArw?KeJD[BN?GD@wgFWCiHq@Ypp_QKFixEKWqRp]oJFuVIEvjDcTFu~Zz]a{IcXhWuIdMQjJ]lwmGQ|]g~c]Hl]pl`Pd^?loIcsoNir_kikBYyg?NarXZEGYspt_vLBIoj}LI[uBFvm}tbqvC|xyR~a{kob|HlctZslTGtPDhBKsNsoZPuH`U`Fqg{gKnGSHVLJ^O`zmNgMn~{rsQuoymw^JY?iUBvw_~mMr|GrPHTERS[MiNpY[Mm{ggHpzRaJaoFomtdaQ_?xuTRm}@KjU~RtPsAdxa|uHmy}n^i||FVL[eQAPrWfLm^ndczgF~Nk~aplQvTUpHvnTya]kOenZlLAQIm{lPl@CCTchvCF[fI{^zPkeYZTiamoEcKmBMfZhk_j_~Fjp|wPVZlkh_nHu]@tP|hS@^G^PdsQ~f[RqgTDqezxNFcaO}HZhb|MMiNSYSAnQWCDJukT~e|OTgc}sf[cnr?fyzTa|EwEtRG|I~|IO}O]S|rp]CQ}}DWhSjC_|z|oY|FYl@WkCOoPuWuqr{fJu?Brs^_EBI[@_OCKs}?]O`jnDiXBvaIWhhMAQDNb{U`bqVR}oqVAvR@AZHEBY@depD]OLh`kf^UsHhzKT}CS}HQKy}Q~AeMydXPQztWSSzDnghULQgMAmbWIZ|lWWeEXrE^EeNoZApooEmrXe{NAnoDf`m}UNlRdqQ@jOc~HLOMWs]IDqJHYoMziEedGBPOxOb?[X`KxkFRg@`mgFYnP{hSaxwZfBQqTm}_?RSEaQga]w[vxc]hMne}VfSlqUeMo_iqmd`ilnJXnhdj^EEFifvZyxYFRf^VaqBhLyrGlk~qowqzHOBlOwtx?i{m~`n^G?Yxzxux}b{LSlx]dS~thO^lYE}bzKmUEzwW^{rPGhbEov[Plv??xtyKJshbG`KuO?hjBdS@Ru}iGpvFXJRrvOlrKN?`I_n_tplk}kgwSXuKylXbRQ]]?a|{xiT[li?k]CJpwy^o@ebyGQrPfF`aszGKp]baIx~H?ElETtFh]dz[OjGl@C?]VDhr}OE@V]wLTc[WErXacM{We`F|utKKjgllAxvsVYBZ@HcuMgLboFHVZmi}eIXAIFhS@A@FGRbjeoJWZ_NKd^oEH`qgy`q[Tq{x?LRP|GfBFFJV|fgZs`MLbpPYUdIV^]mD@FG]pYAT^A^RNCcXVrPsgk{jTrAIQPs_`mD}rOqAZA[}RETFz]WkXFTz_m{N@{W@_fPKZLT`@aIqf|L^Mb|crNqZ{BVsijzpGPEKQQZGlApDn`ruH}cvF|iXcNqK}cxe_U~HRnKV}sCYb`D~oGvwG[Ca|UaybXea~DdD~LiIbGRxJ_VGheI{ika}KC[OZJLn^IBkPrQj_EuoFwZ}DpoBRcK]Q}?EmTv~i_Tul{bky?Iit~tgS|o}JL_VYcCQdjeJ_MfaA`FgCgc[Ii|CBHwq~nbJeYTK{e`CNstKfTKPzw{jdhp|qsZyP_FcugxCFNpKitlR~vUrx^NrSVsSTaEgnxZTmKc`R|lGJeX}ccKLsQZQhsFkeFd|ckHIVTlGMg`~uPwuHRJS_CPuN_ogXe{Ba}dO_UBhuNXby|h?JlgBIqMKx^_u{molgL[W_iavNQuOq?ap]PGB`clAicnl@k~pA?MWHEZ{HuTLsCpOxxrKlBh]FyMjLdFl|nMIvTHyGAlPogqfZ?PlvlFJvYnDQd}R@uAhtJmDfe|iJqdkYr}r@mEjjIetDl_I`TELfoR|qTBu@Tic[BaXjP?dCS~MUK[HPRI}OUOwAaf|_}HZzrwXvbnNgltjTwkBE~MztTQhtRSWoQHajMoVyBBA`kdgK~h`o[J`dm~pm]tk@i`[F~F]DBlJKklrkR]SNw@{aG~Vhl`KINsQkOy?WhcqUMTGDOM_]bUjVd|Yh_KUCCgIJ|LDIGZCPls{RzbVWVLEhHvWBzKq|^N?DyJB|__aCUjoEgsARki}j@DQXS`RNU|DJ^a~d{sh_Iu{ONcUtSrGWW@cvUjefHHi}eSSGrNtO?cTPBShLqzwMVjWQQCCFB^culBjZHEK_{dO~Q`YhJYFn]jq~XSnG@[lQr]eKrjXpG~L^h~tDgEma^AUFThlaR{xyuP@[^VFwXSeUbVetufa@dX]CLyAnDV@Bs[DnpeghJw^?UIana}r_CKGDySoRudklbgio}kIDpA@McDoPK?iYcG?_zOmnWfJp}a[JLR[stXMo?_^Ng[whQlrDbrawZeSZ~SJstIObdDSfAA{MV}?gNunLOnbMv_~KFQUAjIMj^GkoGxuYtYbGDImEYiwEMyTpMxN_LSnSMdl{bg@dtAnAMvhDTBR_FxoQgANniRqxd`pWv@rFJ|mWNWmh[GMJz_Nq`BIN@KsjMPASXORcdHjf~rJfgZYe_uulzqM_KdPlMsuvU^YJuLtofPhGonVOQxCMuXliNvJIaoC?hSxcxKVVxWlNs^ENDvCtSmO~WxI[itnjs^RDvI@KqG}YekaSbTaB]ki]XM@[ZnDAP~@|BzLRgOzmjmPkRE@_sobkT|SszXK[rZN?F]Z_u}Yue^[BZgLtR}FHzWyxWEX^wXC]MJmiVbQuBzkgRcKGUhOvUc_bga|Tx`KEM`JWEgTpFYVeXLCm|mctZR@uKTDeUONPozBeIkrY`cz]]~WPGMUf`MNUGHDbxZuO{gmsKYkAGRPqjc|_FtblEOwy}dnwCHo]PJhN~JoteaJ?dmYZeB^Xd?X^pOKDbOMF@Ugg^hETLdhwlA}PL@_ur|o{VZosP?ntJ_kG][g{Zq`Tu]dzQlSWiKfnxDnk}KOzp~tdFstMobmy[oPYjyOtUzMWdjcNSUAjRuqhLS@AwB^{BFnqjCmmlk?jpn}TksS{KcKkDboXiwK]qMVjm~V`LgWhjS^nLGwfhAYrjDSBL_{cRus~{?xar_xqPlArrYFd?pHKdMEZzzjJpfC?Hv}mAuIDkyBxFpxhstTx`IO{rp}XGuQ]VtbHerlRc_LFGWK[XluFcNGUtDYMZny[M^nVKVeMllQI[xtvwQnXFlWYqxZZFp_|]^oWX[{pOMpxXxvkbyJA[DrPzwD|LW|QcV{Nw~U^dgguSpG]ClmO@j_TENIGjPWwgdVbHganhM?ema|dBaqla|WBd`poj~klxaasKxGG^xbWquAl~_lKWxUkDFagMnE{zHug{b`A~IYcQYBF_E}wiA}K@yxWHrZ{[d~|ARsYsjeNWzkMs~IOqqp[yzDE|WFrivsidTcnbHFRoW@XpAV`lv_zj?B~tPCppRjgbbDTALeFaOf?VcjnKTQMLyp{NwdylHCqmo?oelhjWuXj~}{fpuX`fra?GNkDiChYgVSh{R[BgF~eQa^WVz}ATI_CpY?g_diae]|ijH`TyNIF}|D_xpmBq_JpKih{Ba|sWzhnAoyraiDvk`h{qbBfsylBGmRH}DRPdryEsSaKS~tIaeF[s]I~xxHVrcNe@Jjxa@jlhZueLQqHh_]twVMqG_EGuwyab{nxOF?`HCle}nBZzlTQjkLmoXbXhOtBglFoMz?eqre`HiE@vNwBulglmQjj]DB@pPkPUgA^sjOAUNdSu_`oAzar?n?eMnw{{hYmslYi[TnlJD'",...']charCodeAtUinyxpf',"for(;e<10359;c[e++]=p-=128,A=A?p-A&&A:p==34&&p)for(p=1;p<128;y=f.map((n,x)=>(U=r[n]*2+1,U=Math.log(U/(h-U)),t-=a[x]*U,U/500)),t=~-h/(1+Math.exp(t))|1,i=o%h<t,o=o%h+(i?t:h-t)*(o>>17)-!i*t,f.map((n,x)=>(U=r[n]+=(i*h/2-r[n]<<13)/((C[n]+=C[n]<5)+1/20)>>13,a[x]+=y[x]*(i-t/h))),p=p*2+i)for(f='010202103203210431053105410642065206541'.split(t=0).map((n,x)=>(U=0,[...n].map((n,x)=>(U=U*997+(c[e-n]|0)|0)),h*32-1&U*997+p+!!A*129)*12+x);o<h*32;o=o*64|M.charCodeAt(d++)&63);for(C=String.fromCharCode(...c);r=/[\0-#?@\\\\~]/.exec(C);)with(C.split(r))C=join(shift());return C")([],[],1<<17,[0,0,0,0,0,0,0,0,0,0,0,0],new Uint16Array(51e6).fill(1<<15),new Uint8Array(51e6),0,0,0,0));
298
+ }
@@ -43,7 +43,7 @@ class EngineObject
43
43
  constructor(pos=vec2(), size=objectDefaultSize, tileIndex=-1, tileSize=tileSizeDefault, angle=0, color, renderOrder=0)
44
44
  {
45
45
  // set passed in params
46
- ASSERT(pos && pos.x != undefined && size.x != undefined); // ensure pos and size are vec2s
46
+ ASSERT(isVector2(pos) && isVector2(size)); // ensure pos and size are vec2s
47
47
 
48
48
  /** @property {Vector2} - World space position of the object */
49
49
  this.pos = pos.copy();
@@ -133,7 +133,7 @@ class EngineObject
133
133
  if (this.collideSolidObjects)
134
134
  {
135
135
  // check collisions against solid objects
136
- const epsilon = 1e-3; // necessary to push slightly outside of the collision
136
+ const epsilon = .001; // necessary to push slightly outside of the collision
137
137
  for (const o of engineObjectsCollide)
138
138
  {
139
139
  // non solid objects don't collide with eachother
@@ -155,7 +155,7 @@ class ParticleEmitter extends EngineObject
155
155
  this.parent && super.update();
156
156
 
157
157
  // update emitter
158
- if (!this.emitTime || this.getAliveTime() <= this.emitTime)
158
+ if (!this.emitTime | this.getAliveTime() <= this.emitTime)
159
159
  {
160
160
  // emit particles
161
161
  if (this.emitRate * particleEmitRateScale)
@@ -177,9 +177,9 @@ class ParticleEmitter extends EngineObject
177
177
  {
178
178
  // spawn a particle
179
179
  let pos = this.emitSize.x != undefined ? // check if vec2 was used for size
180
- (new Vector2(rand(-.5,.5), rand(-.5,.5)))
181
- .multiply(this.emitSize).rotate(this.angle) // box emitter
182
- : randInCircle(this.emitSize * .5); // circle emitter
180
+ (new Vector2(rand(-1,1), rand(-1,1)))
181
+ .multiply(this.emitSize/2).rotate(this.angle) // box emitter
182
+ : randInCircle(this.emitSize/2); // circle emitter
183
183
  let angle = rand(this.particleConeAngle, -this.particleConeAngle);
184
184
  if (!this.localSpace)
185
185
  {
@@ -222,7 +222,7 @@ class ParticleEmitter extends EngineObject
222
222
  particle.additive = this.additive;
223
223
  particle.renderOrder = this.renderOrder;
224
224
  particle.trailScale = this.trailScale;
225
- particle.mirror = rand()<.5;
225
+ particle.mirror = randInt(2);
226
226
  particle.localSpaceEmitter = this.localSpace && this;
227
227
 
228
228
  // setup callbacks for particles
@@ -251,7 +251,8 @@ class Particle extends EngineObject
251
251
  * @param {Vector2} [tileSize=tileSizeDefault] - Size of tile in source pixels
252
252
  * @param {Number} [angle=0] - Angle to rotate the particle
253
253
  */
254
- constructor(pos, tileIndex, tileSize, angle) { super(pos, new Vector2, tileIndex, tileSize, angle); }
254
+ constructor(pos, tileIndex, tileSize, angle)
255
+ { super(pos, new Vector2, tileIndex, tileSize, angle); }
255
256
 
256
257
  /** Render the particle, automatically called each frame, sorted by renderOrder */
257
258
  render()
@@ -5,6 +5,20 @@
5
5
 
6
6
  'use strict';
7
7
 
8
+ ///////////////////////////////////////////////////////////////////////////////
9
+ // Camera settings
10
+
11
+ /** Position of camera in world space
12
+ * @type {Vector2}
13
+ * @default
14
+ * @memberof Settings */
15
+ let cameraPos = vec2();
16
+
17
+ /** Scale of camera in world space
18
+ * @default
19
+ * @memberof Settings */
20
+ let cameraScale = 16;
21
+
8
22
  ///////////////////////////////////////////////////////////////////////////////
9
23
  // Display settings
10
24
 
@@ -31,6 +45,19 @@ let cavasPixelated = 1;
31
45
  * @memberof Settings */
32
46
  let fontDefault = 'arial';
33
47
 
48
+ ///////////////////////////////////////////////////////////////////////////////
49
+ // WebGL settings
50
+
51
+ /** Enable webgl rendering, webgl can be disabled and removed from build (with some features disabled)
52
+ * @default
53
+ * @memberof Settings */
54
+ let glEnable = 1;
55
+
56
+ /** Fixes slow rendering in some browsers by not compositing the WebGL canvas
57
+ * @default
58
+ * @memberof Settings */
59
+ let glOverlay = 1;
60
+
34
61
  ///////////////////////////////////////////////////////////////////////////////
35
62
  // Tile sheet settings
36
63
 
@@ -99,33 +126,6 @@ let gravity = 0;
99
126
  * @memberof Settings */
100
127
  let particleEmitRateScale = 1;
101
128
 
102
- ///////////////////////////////////////////////////////////////////////////////
103
- // Camera settings
104
-
105
- /** Position of camera in world space
106
- * @type {Vector2}
107
- * @default
108
- * @memberof Settings */
109
- let cameraPos = vec2();
110
-
111
- /** Scale of camera in world space
112
- * @default
113
- * @memberof Settings */
114
- let cameraScale = max(tileSizeDefault.x, tileSizeDefault.y);
115
-
116
- ///////////////////////////////////////////////////////////////////////////////
117
- // WebGL settings
118
-
119
- /** Enable webgl rendering, webgl can be disabled and removed from build (with some features disabled)
120
- * @default
121
- * @memberof Settings */
122
- let glEnable = 1;
123
-
124
- /** Fixes slow rendering in some browsers by not compositing the WebGL canvas
125
- * @default
126
- * @memberof Settings */
127
- let glOverlay = 1;
128
-
129
129
  ///////////////////////////////////////////////////////////////////////////////
130
130
  // Input settings
131
131
 
@@ -159,7 +159,7 @@ let touchGamepadAnalog = 1;
159
159
  /** Size of virutal gamepad for touch devices in pixels
160
160
  * @default
161
161
  * @memberof Settings */
162
- let touchGamepadSize = 80;
162
+ let touchGamepadSize = 99;
163
163
 
164
164
  /** Transparency of touch gamepad overlay
165
165
  * @default
@@ -77,14 +77,11 @@ function tileCollisionRaycast(posStart, posEnd, object)
77
77
  {
78
78
  // test if a ray collides with tiles from start to end
79
79
  // todo: a way to get the exact hit point, it must still register as inside the hit tile
80
- posStart = posStart.floor();
81
- posEnd = posEnd.floor();
82
- const posDelta = posEnd.subtract(posStart);
80
+ const posDelta = (posEnd = posEnd.floor()).subtract(posStart = posStart.floor());
83
81
  const dx = abs(posDelta.x), dy = -abs(posDelta.y);
84
82
  const sx = sign(posDelta.x), sy = sign(posDelta.y);
85
- let e = dx + dy;
86
83
 
87
- for (let x = posStart.x, y = posStart.y;;)
84
+ for (let x = posStart.x, y = posStart.y, e = dx + dy;;)
88
85
  {
89
86
  const tileData = getTileCollisionData(vec2(x,y));
90
87
  if (tileData && (object ? object.collideWithTileRaycast(tileData, new Vector2(x, y)) : tileData > 0))
@@ -176,7 +173,7 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
176
173
  // init tile data
177
174
  this.data = [];
178
175
  for (let j = this.size.area(); j--;)
179
- this.data.push(new TileLayerData());
176
+ this.data.push(new TileLayerData);
180
177
  }
181
178
 
182
179
  /** Set data at a given position in the array
@@ -232,21 +229,23 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
232
229
  * @param {Boolean} [clear=0] - Should it clear the canvas before drawing */
233
230
  redrawStart(clear = 0)
234
231
  {
235
- if (clear)
236
- {
237
- // clear and set size
238
- this.canvas.width = this.size.x * this.tileSize.x;
239
- this.canvas.height = this.size.y * this.tileSize.y;
240
- }
241
-
242
232
  // save current render settings
243
- this.savedRenderSettings = [mainCanvas, mainContext, cameraPos, cameraScale];
233
+ this.savedRenderSettings = [mainCanvas, mainContext, mainCanvasSize, cameraPos, cameraScale];
244
234
 
245
- // use normal rendering system to render the tiles
235
+ // hack: use normal rendering system to render the tiles
246
236
  mainCanvas = this.canvas;
247
237
  mainContext = this.context;
248
238
  cameraPos = this.size.scale(.5);
249
239
  cameraScale = this.tileSize.x;
240
+
241
+ if (clear)
242
+ {
243
+ // clear and set size
244
+ mainCanvas.width = this.size.x * this.tileSize.x;
245
+ mainCanvas.height = this.size.y * this.tileSize.y;
246
+ }
247
+
248
+ // begin a new render for the tile canvas
250
249
  enginePreRender();
251
250
  }
252
251
 
@@ -258,7 +257,7 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
258
257
  //debugSaveCanvas(this.canvas);
259
258
 
260
259
  // set stuff back to normal
261
- [mainCanvas, mainContext, cameraPos, cameraScale] = this.savedRenderSettings;
260
+ [mainCanvas, mainContext, mainCanvasSize, cameraPos, cameraScale] = this.savedRenderSettings;
262
261
  }
263
262
 
264
263
  /** Draw the tile at a given position
@@ -104,7 +104,7 @@ const wave = (frequency=1, amplitude=1, t=time)=> amplitude/2 * (1 - Math.cos(t*
104
104
  * @param {Number} t - time in seconds
105
105
  * @return {String}
106
106
  * @memberof Utilities */
107
- const formatTime = (t)=> (t/60|0)+':'+(t%60<10?'0':'')+(t%60|0);
107
+ const formatTime = (t)=> (t/60|0) + ':' + (t%60<10?'0':'') + (t%60|0);
108
108
 
109
109
  ///////////////////////////////////////////////////////////////////////////////
110
110
 
@@ -128,7 +128,7 @@ const randInt = (a=1, b=0)=> rand(a,b)|0;
128
128
  /** Randomly returns either -1 or 1
129
129
  * @return {Number}
130
130
  * @memberof Random */
131
- const randSign = ()=> (rand(2)|0) * 2 - 1;
131
+ const randSign = ()=> randInt(2) * 2 - 1;
132
132
 
133
133
  /** Returns a random Vector2 within a circular shape
134
134
  * @param {Number} [radius=1]
@@ -152,10 +152,15 @@ const randVector = (length=1)=> new Vector2().setAngle(rand(2*PI), length);
152
152
  const randColor = (cA = new Color, cB = new Color(0,0,0,1), linear)=>
153
153
  linear ? cA.lerp(cB, rand()) : new Color(rand(cA.r,cB.r),rand(cA.g,cB.g),rand(cA.b,cB.b),rand(cA.a,cB.a));
154
154
 
155
- /** The seed used by the randSeeded function, should not be 0
155
+ /** Seed used by the randSeeded function
156
156
  * @memberof Random */
157
157
  let randSeed = 1;
158
158
 
159
+ /** Set seed used by the randSeeded function, should not be 0
160
+ * @param {Number} seed
161
+ * @memberof Random */
162
+ const setRandSeed = (seed)=> randSeed = seed;
163
+
159
164
  /** Returns a seeded random value between the two values passed in using randSeed
160
165
  * @param {Number} [valueA=1]
161
166
  * @param {Number} [valueB=0]
@@ -183,6 +188,14 @@ const randSeeded = (a=1, b=0)=>
183
188
  */
184
189
  const vec2 = (x=0, y)=> x.x == undefined ? new Vector2(x, y == undefined? x : y) : new Vector2(x.x, x.y);
185
190
 
191
+ /**
192
+ * Check if object is a valid Vector2
193
+ * @param {Vector2} vector
194
+ * @return {Boolean}
195
+ * @memberof Utilities
196
+ */
197
+ const isVector2 = (v)=> !isNaN(v.x) && !isNaN(v.y);
198
+
186
199
  /**
187
200
  * 2D Vector object with vector math library
188
201
  * <br> - Functions do not change this so they can be chained together
@@ -212,27 +225,27 @@ class Vector2
212
225
  /** Returns a copy of this vector plus the vector passed in
213
226
  * @param {Vector2} vector
214
227
  * @return {Vector2} */
215
- add(v) { ASSERT(v.x!=undefined); return new Vector2(this.x + v.x, this.y + v.y); }
228
+ add(v) { ASSERT(isVector2(v)); return new Vector2(this.x + v.x, this.y + v.y); }
216
229
 
217
230
  /** Returns a copy of this vector minus the vector passed in
218
231
  * @param {Vector2} vector
219
232
  * @return {Vector2} */
220
- subtract(v) { ASSERT(v.x!=undefined); return new Vector2(this.x - v.x, this.y - v.y); }
233
+ subtract(v) { ASSERT(isVector2(v)); return new Vector2(this.x - v.x, this.y - v.y); }
221
234
 
222
235
  /** Returns a copy of this vector times the vector passed in
223
236
  * @param {Vector2} vector
224
237
  * @return {Vector2} */
225
- multiply(v) { ASSERT(v.x!=undefined); return new Vector2(this.x * v.x, this.y * v.y); }
238
+ multiply(v) { ASSERT(isVector2(v)); return new Vector2(this.x * v.x, this.y * v.y); }
226
239
 
227
240
  /** Returns a copy of this vector divided by the vector passed in
228
241
  * @param {Vector2} vector
229
242
  * @return {Vector2} */
230
- divide(v) { ASSERT(v.x!=undefined); return new Vector2(this.x / v.x, this.y / v.y); }
243
+ divide(v) { ASSERT(isVector2(v)); return new Vector2(this.x / v.x, this.y / v.y); }
231
244
 
232
245
  /** Returns a copy of this vector scaled by the vector passed in
233
246
  * @param {Number} scale
234
247
  * @return {Vector2} */
235
- scale(s) { ASSERT(s.x==undefined); return new Vector2(this.x * s, this.y * s); }
248
+ scale(s) { ASSERT(!isVector2(s)); return new Vector2(this.x * s, this.y * s); }
236
249
 
237
250
  /** Returns the length of this vector
238
251
  * @return {Number} */
@@ -265,12 +278,12 @@ class Vector2
265
278
  /** Returns the dot product of this and the vector passed in
266
279
  * @param {Vector2} vector
267
280
  * @return {Number} */
268
- dot(v) { ASSERT(v.x!=undefined); return this.x*v.x + this.y*v.y; }
281
+ dot(v) { ASSERT(isVector2(v)); return this.x*v.x + this.y*v.y; }
269
282
 
270
283
  /** Returns the cross product of this and the vector passed in
271
284
  * @param {Vector2} vector
272
285
  * @return {Number} */
273
- cross(v) { ASSERT(v.x!=undefined); return this.x*v.y - this.y*v.x; }
286
+ cross(v) { ASSERT(isVector2(v)); return this.x*v.y - this.y*v.x; }
274
287
 
275
288
  /** Returns the angle of this vector, up is angle 0
276
289
  * @return {Number} */
@@ -306,7 +319,7 @@ class Vector2
306
319
  * @param {Vector2} vector
307
320
  * @param {Number} percent
308
321
  * @return {Vector2} */
309
- lerp(v, p) { ASSERT(v.x!=undefined); return this.add(v.subtract(this).scale(clamp(p))); }
322
+ lerp(v, p) { ASSERT(isVector2(v)); return this.add(v.subtract(this).scale(clamp(p))); }
310
323
 
311
324
  /** Returns true if this vector is within the bounds of an array size passed in
312
325
  * @param {Vector2} arraySize
@@ -317,7 +330,7 @@ class Vector2
317
330
  * @param {float} digits - precision to display
318
331
  * @return {String} */
319
332
  toString(digits=3)
320
- { return `(${(this.x<0?'':' ') + this.x.toFixed(digits)},${(this.y<0?'':' ') + this.y.toFixed(digits)} )`; }
333
+ { if (debug) { return `(${(this.x<0?'':' ') + this.x.toFixed(digits)},${(this.y<0?'':' ') + this.y.toFixed(digits)} )`; }}
321
334
  }
322
335
 
323
336
  ///////////////////////////////////////////////////////////////////////////////
@@ -555,7 +568,7 @@ class Timer
555
568
 
556
569
  /** Returns this timer expressed as a string
557
570
  * @return {String} */
558
- toString() { if (debug) { return this.unset() ? 'unset' : Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ); } }
571
+ toString() { if (debug) { return this.unset() ? 'unset' : Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ); }}
559
572
 
560
573
  /** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
561
574
  * @return {Number} */