").replace(/~/g,"disp").replace(/ß/g,"butt").replace(/@/g,"labl").replace(/\|/g,"
"),c="är^1,äg^1,äb^1,öh^1,öh?1,öh?2,ös?1,öv?1,üh^1,üh?1,üh?2,üs?1,ül?1,.no-rgb-r är?2,.no-rgb-r är?3,.no-rgb-r är?4,.no-rgb-g äg?2,.no-rgb-g äg?3,.no-rgb-g äg?4,.no-rgb-b äb?2,.no-rgb-b äb?3,.no-rgb-b äb?4{visibility:hidden}är^2,är^3,äg^2,äg^3,äb^2,äb^3{@-image:url(_patches.png)}.§slds div{@-image:url(_vertical.png)}öh^2,ös^1,öv^1,üh^2,üs^1,ül^1{@-image:url(_horizontal.png)}ös?4,öv^3,üs?4,ül^3{@:#000}üs?3,ül^4{@:#fff}är?1{@-color:#f00}äg?1{@-color:#0f0}äb?1{@-color:#00f}är^2{@|-1664px 0}är^3{@|-896px 0}är?1,äg?1,äb?1,öh^3,ös^2,öv?2Ü-2432Öär?2Ü-2944Öär?3Ü-4480Öär?4Ü-3202Öäg^2Äöh^2{@|-640px 0}äg^3{@|-384px 0}äg?2Ü-4736Öäg?3Ü-3968Öäg?4Ü-3712Öäb^2{@|-1152px 0}äb^3{@|-1408px 0}äb?2Ü-3456Öäb?3Ü-4224Öäb?4Ü-2688Ööh^2Äär^3Ääb?4Ü0}öh?4,üh?4Ü-1664Öös^1,öv^1,üs^1,ül^1Ääg^3{@|-256px 0}ös^3,öv?4,üs^3,ül?4Ü-2176Öös?2,öv^2Ü-1920Öüh^2{@|-768px 0}üh^3,üs^2,ül?2Ü-5184Öüs?2,ül^2Ü-5824Ö.S är^2{@|-128px -128Ö.S är?1Ääg?1Ääb?1Äöh^3Äös^2Äöv?2Ü-1408Ö.S är?2Ääb^3Ü-128Ö.S är?3Ü-896Ö.S är?4Ü-256Ö.S äg^2{@|-256px -128Ö.S äg?2Ü-1024Ö.S äg?3Ü-640Ö.S äg?4Ü-512Ö.S äb^2{@|-128px 0}.S äb?2Ü-384Ö.S äb?3Ü-768Ö.S öh?4Äüh?4Ü-1536Ö.S ös^1Äöv^1Äüs^1Äül^1{@|-512px 0}.S ös^3Äöv?4Äüs^3Äül?4Ü-1280Ö.S ös?2Äöv^2Ü-1152Ö.S üh^2{@|-1024px 0}.S üh^3Äüs^2Äül?2Ü-5440Ö.S üs?2Äül^2Ü-5696Ö.XXS ös^2,.XXS öv?2Ü-5120Ö.XXS ös^3,.XXS öv?4,.XXS üs^3,.XXS ül^3,.XXS ül?4Ü-5056Ö.XXS ös?2,.XXS öv^2Ü-4992Ö.XXS üs^2,.XXS ül?2Ü-5568Ö.XXS üs?2,.XXS ül^2Ü-5632Ö".replace(/Ü/g,"{@|0 ").replace(/Ö/g,"px}").replace(/Ä/g,",.S ").replace(/\|/g,"-position:").replace(/@/g,"background").replace(/ü/g,".hsl-").replace(/ö/g,".hsv-").replace(/ä/g,".rgb-").replace(/~/g," .no-rgb-}").replace(/\?/g," .§sldr-").replace(/\^/g," .§sldl-"),d='∑{@#bbb;font-family:monospace, "Courier New", Courier, mono;font-size:12¥line-ä15¥font-weight:bold;cursor:default;~412¥ä323¥?top-left-radius:7¥?top-Ü-radius:7¥?bottom-Ü-radius:7¥?bottom-left-radius:7¥ö@#444}.S{~266¥ä177px}.XS{~158¥ä173px}.XXS{ä105¥~154px}.no-alpha{ä308px}.no-alpha .§opacity,.no-alpha .§alpha{display:none}.S.no-alpha{ä162px}.XS.no-alpha{ä158px}.XXS.no-alpha{ä90px}∑,∑ div{border:none;padding:0¥float:none;margin:0¥outline:none;box-sizing:content-box}∑ div{|absolute}^s .§curm,«§disp,«§nsarrow,∑ .§exit,∑ ø-cursor,∑ .§resize{öimage:url(_icons.png)}∑ .do-drag div{cursor:none}∑ .§opacity,ø .§raster-bg,∑ .§raster{öimage:url(_bgs.png)}∑ ^s{~287¥ä256¥top:10¥left:10¥overflow:hidden;cursor:crosshair}.S ^s{~143¥ä128¥left:9¥top:9px}.XS ^s{left:7¥top:7px}.XXS ^s{left:5¥top:5px}^s div{~256¥ä256¥left:0px}.S ^l-1,.S ^l-2,.S ^l-3,.S ^l-4{~128¥ä128px}.XXS ^s,.XXS ^s ^l-1,.XXS ^s ^l-2,.XXS ^s ^l-3,.XXS ^s ^l-4{ä64px}^s ^r-1,^s ^r-2,^s ^r-3,^s ^r-4{~31¥left:256¥cursor:default}.S ^r-1,.S ^r-2,.S ^r-3,.S ^r-4{~15¥ä128¥left:128px}^s .§curm{margin:-5¥~11¥ä11¥ö|-36px -30px}.light .§curm{ö|-7px -30px}^s .§curl,^s .§curr{~0¥ä0¥margin:-3px -4¥border:4px solid;cursor:default;left:auto;öimage:none}^s .§curl,∑ ^s .§curl-dark,.hue-dark div.§curl{Ü:27¥?@† † † #fff}.light .§curl,∑ ^s .§curl-light,.hue-light .§curl{?@† † † #000}.S ^s .§curl,.S ^s .§curr{?~3px}.S ^s .§curl-light,.S ^s .§curl{Ü:13px}^s .§curr,∑ ^s .§curr-dark{Ü:4¥?@† #fff † †}.light .§curr,∑ ^s .§curr-light{?@† #000 † †}∑ .§opacity{bottom:44¥left:10¥ä10¥~287¥ö|0 -87px}.S .§opacity{bottom:27¥left:9¥~143¥ö|0 -100px}.XS .§opacity{left:7¥bottom:25px}.XXS .§opacity{left:5¥bottom:23px}.§opacity div{~100%;ä16¥margin-top:-3¥overflow:hidden}.§opacity .§opacity-slider{margin:0 -4¥~0¥ä8¥?~4¥?style:solid;?@#eee †}∑ ø{bottom:10¥left:10¥~288¥ä31¥ö@#fff}.S ø{ä15¥~144¥left:9¥bottom:9px}.XS ø{left:7¥bottom:7px}.XXS ø{left:5¥bottom:5px}ø div{|relative;float:left;~31¥ä31¥margin-Ü:1px}.S ø div{~15¥ä15px}∑ .§raster,ø .§raster-bg,.S ø .§raster,.S ø .§raster-bg{|absolute;top:0¥Ü:0¥bottom:0¥left:0¥~100%}.S ø .§raster-bg{ö|0 -31px}∑ .§raster{opacity:0.2;ö|0 -49px}.alpha-bg-b ø{ö@#333}.alpha-bg-b .§raster{opacity:1}ø ø-cursor{|absolute;Ü:0¥ö|-26px -87px}∑ .light ø-cursor{ö|3px -87px}.S ø-cursor{ö|-34px -95px}.S .light ø-cursor{ö|-5px -95px}∑ .§panel{|absolute;top:10¥Ü:10¥bottom:10¥~94¥?~1¥?style:solid;?@#222 #555 #555 #222;overflow:hidden;ö@#333}.S .§panel{top:9¥Ü:9¥bottom:9px}.XS .§panel{display:none}.§panel div{|relative}«§hsv,«§hsl,«§rgb,«§cmyk,«§Lab,«§alpha,.no-alpha «§HEX,«§HEX{~86¥margin:-1px 0px 1px 4¥padding:1px 0px 3¥?top-~1¥?top-style:solid;?top-@#444;?bottom-~1¥?bottom-style:solid;?bottom-@#222;float:Ö«§hsv,«§hsl{padding-top:2px}.S .§hsv,.S .§hsl{padding-top:1px}«§HEX{?bottom-style:none;?top-~0¥margin-top:-4¥padding-top:0px}.no-alpha «§HEX{?bottom-style:none}«§alpha{?bottom-style:none}.S .rgb-r .§hsv,.S .rgb-g .§hsv,.S .rgb-b .§hsv,.S .rgb-r .§hsl,.S .rgb-g .§hsl,.S .rgb-b .§hsl,.S .hsv-h .§rgb,.S .hsv-s .§rgb,.S .hsv-v .§rgb,.S .hsl-h .§rgb,.S .hsl-s .§rgb,.S .hsl-l .§rgb,.S .§cmyk,.S .§Lab{display:none}«§butt,«§labl{float:left;~14¥ä14¥margin-top:2¥text-align:center;border:1px solid}«§butt{?@#555 #222 #222 #555}«§butt:active{ö@#444}«§labl{?@†}«Lab-mode,«cmyk-mode,«hsv-mode,«hsl-mode{|absolute;Ü:0¥top:1¥ä50px}«hsv-mode,«hsl-mode{top:2px}«cmyk-mode{ä68px}.hsl-h .hsl-h-labl,.hsl-s .hsl-s-labl,.hsl-l .hsl-l-labl,.hsv-h .hsv-h-labl,.hsv-s .hsv-s-labl,.hsv-v .hsv-v-labl{@#f90}«cmyk-mode,«hsv-mode,.rgb-r .rgb-r-butt,.rgb-g .rgb-g-butt,.rgb-b .rgb-b-butt,.hsv-h .hsv-h-butt,.hsv-s .hsv-s-butt,.hsv-v .hsv-v-butt,.hsl-h .hsl-h-butt,.hsl-s .hsl-s-butt,.hsl-l .hsl-l-butt,«rgb-r-labl,«rgb-g-labl,«rgb-b-labl,«alpha-butt,«HEX-butt,«Lab-x-labl{?@#222 #555 #555 #222;ö@#444}.no-rgb-r .rgb-r-labl,.no-rgb-g .rgb-g-labl,.no-rgb-b .rgb-b-labl,.mute-alpha .alpha-butt,.no-HEX .HEX-butt,.cmy-only .Lab-x-labl{?@#555 #222 #222 #555;ö@#333}.Lab-x-disp,.cmy-only .cmyk-k-disp,.cmy-only .cmyk-k-butt{visibility:hidden}«HEX-disp{öimage:none}«§disp{float:left;~48¥ä14¥margin:2px 2px 0¥cursor:text;text-align:left;text-indent:3¥?~1¥?style:solid;?@#222 #555 #555 #222}∑ .§nsarrow{|absolute;top:0¥left:-13¥~8¥ä16¥display:none;ö|-87px -23px}∑ .start-change .§nsarrow{display:block}∑ .do-change .§nsarrow{display:block;ö|-87px -36px}.do-change .§disp{cursor:default}«§hide{display:none}«§cont,«§cold{|absolute;top:-5¥left:0¥ä3¥border:1px solid #333}«§cold{z-index:1;ö@#c00}«§cont{margin-Ü:-1¥z-index:2}«contrast .§cont{z-index:1;ö@#ccc}«orange .§cold{ö@#f90}«green .§cold{ö@#4d0}«§ctrl{|absolute;bottom:0¥left:0¥~100%;ö@#fff}.alpha-bg-b .§ctrl,«§bres,«§bsav{ö@#333}«§col1,«§col2,«§bres,«§bsav{?~1¥?style:solid;?@#555 #222 #222 #555;float:left;~45¥line-ä28¥text-align:center;top:0px}.§panel div div{ä100%}.S .§ctrl div{line-ä25px}.S «§bres,.S «§bsav{line-ä26px}∑ .§exit,∑ .§resize{Ü:3¥top:3¥~15¥ä15¥ö|0 -52px}∑ .§resize{top:auto;bottom:3¥cursor:nwse-resize;ö|-15px -52px}.S .§exit{ö|1px -52px}.XS .§resize,.XS .§exit{~10¥ä10¥Ü:0¥öimage:none}.XS .§exit{top:0px}.XS .§resize{bottom:0px}∑ .§resizer,∑ .§resizer div{|absolute;border:1px solid #888;top:-1¥Ü:-1¥bottom:-1¥left:-1¥z-index:2;display:none;cursor:nwse-resize}∑ .§resizer div{border:1px dashed #333;opacity:0.3;display:block;ö@#bbb}'.replace(/Ü/g,"right").replace(/Ö/g,"left}").replace(/∑/g,".§app").replace(/«/g,".§panel .").replace(/¥/g,"px;").replace(/\|/g,"position:").replace(/@/g,"color:").replace(/ö/g,"background-").replace(/ä/g,"height:").replace(/ø/g,".§memo").replace(/†/g,"transparent").replace(/\~/g,"width:").replace(/\?/g,"border-").replace(/\^/g,".§sld"),e="iVBORw0KGgoAAAANSUhEUgAABIAAAAABCAYAAACmC9U0AAABT0lEQVR4Xu2S3Y6CMBCFhyqIsjGBO1/B9/F5DC/pK3DHhVkUgc7Zqus2DVlGU/cnQZKTjznttNPJBABA149HyRf1iN//4mIBCg0jV4In+j9xJiuihly1V/Z9X88v//kNeDXVvyO/lK+IPR76B019+1Riab3H1zkmeqerKnL+Bzwxx6PAgZxaSQU8vB62T28pxcQeRQ2sHw6GxCOWHvP78zwHAARBABOfdYtd30rwxXOEPDF+dj2+91r6vV/id3k+/brrXmaGUkqKhX3i+ffSt16HQ/dorTGZTHrs7ev7Tl7XdZhOpzc651nfsm1bRFF0YRiGaJoGs9nsQuN/xafTCXEco65rzOdzHI9HJEmCqqqwXC6x3++RZRnKssRqtUJRFFiv19jtdthutyAi5Hl+Jo9VZg7+7f3yXuvZf5c3KaXYzByb+WIzO5ymKW82G/0BNcFhO/tOuuMAAAAASUVORK5CYII=",f="iVBORw0KGgoAAAANSUhEUgAAAAEAABfACAYAAABn2KvYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABHtJREFUeNrtnN9SqzAQxpOF1to6zuiVvoI+j6/gva/lA/kKeqUzjtX+QTi7SzSYBg49xdIzfL34+e1usoQQklCnmLwoCjImNwDQA2xRGMqNAYB+gPEH9IdCgIUA6Aem0P1fLoMQAPYNHYDoCKAv8OMHFgKgX2AjDPQDXn4t1l+gt/1fId//yWgE/hUJ+mAn8EyY5wCwXxhrbaHzn8E9iPlv79DdHxXTqciZ4KROnXRVZMF/6U2OPhcEavtAbZH1SM7wRDD7VoHZItCiyEQf4t6+MW9UOxaZybmdCGKqNrB9Eb5SfMg3wTyiagMtigTmWofiSDCOYNTSNz6sLDIoaCU9GWDd0tdhoMMsRm+r8U/EfB0GfjmLXiqzimDd0tdhoLMsI7la45+I+ToM/HIW0kfGVQTrlr7tA91kaUr//fxrKo8jUFB7VAn6AKpHJf+EKwAAAIYD/f7F7/8MVgMo7P+gBqDKr57Lf72V8x8AAMDgYIuvH4EAAAAMDQX6AACAQcI9GGMjDADA4MA/P2KlP8IEAAAYFCz6AACAgaLA8y8AAIN+CMYXoQAADA7u/UPYCAMAMDjI7z9S+SdwDFQX2C9Gh9GMEOWriz8/Pw1lWQZsi/L3R4czzP678Ve+P8f9nCv/C7hwLq99ah8NfKrU15zPB5pVcwtiJt9qGy0IfEE+jQa+Fn0VtI/fkxUPqBlEfRENeF+tqUpbGpi1iu8epwJzvV5XA4GpWC6XGz7F+/u766EgwJ+ckiTJKU3TnI6OjnI6OzvLZf6zMggt3dzckPhIoiTlSGpQ+eEsVegdz0fbCCi4fRs+Po+4yWdeDXiT+6pBSTeHple1pkz3FZ+avpyavoiPxgLN0B7yprY08PlyQTTm0+PWmkH7ynedNKraar4F/lRj1WpTtYh+ozL/cY2sAvZl0gcbZm0gSLBLvkxGoaogiy/HDXemQk2t5pUm8OAhH8/HH6e0mkJ9q9XKKQXfb07xfZnJbZrRxcVFVt6/t7e3Kc1ms5RGo1Eq5VIZuyl9fHw4k/M5xYeoKj64A7eqCt1ZeqWFVSl8NV9OTV3fmvP5qE9VmzSoEcsXpArK1UHen/hZbgL53BZSdyEXalGau/hU8TEW0u3VcoFPy3EDFrTgT+njydeZ0+l0UV7fu7u7iVzziQQmUm4iqRw4n/NxMxw4s/Mp1NSALxf4NEtQ10cjMDwSl+b+/j6hp6enVGb+jUvrn05iKobm6PboOt8vPISY5Pr6OqGXlxe3fOokoGtAbMUJZmqvYmaLQDP+sdrecOjtO/SXeH69P8Imutm5urqy9PDwYOny8tLS4+OjpfPzc0vPz8+WTk9PLb2+vlpZbCzN53NLx8fHVtYZS5PJxMoEZWWqsjKULY3HYytTi1Pex5OMldXKRVXxuLcy/20onmms3BBOxcr5qCrZtsrd45SPel8sGlOxGoGy0neynQ6VL9fsa1YtWlCrtj9G83G7PjdVush5n5q1iJWLZW6u21a1bUvbVnVzlru0pe3RdmlV1/23fZtbZv4Dx+7FBypx77kAAAAASUVORK5CYII=",g="iVBORw0KGgo^NSUhEUgAAB4^EACAI#DdoPxz#L0UlEQVR4Xu3cQWrDQBREwR7FF8/BPR3wXktnQL+KvxfypuEhvLJXcp06d/bXd71OPt+trIw95zr33Z1bk1/fudEv79wa++7OfayZ59wrO2PBzklcGQmAZggAAOBYgAYBmpWRAGg^BGgRofAENgAAN#I0CBA6w8AG^ECABgEa/QH§AI0CNDoDwAY^QIAGAVp/AM§AjQI0OgPAAY^QoEGARn8Aw§CNAjQ+gMABg#BCgQYCmGQmABgAAEKBBgEZ/AM§AjQI0PoDAAY^QoEGARn8AM^IAADQI0+gMABg#BCgQYDWHwAw^gAANAjT6A4AB^BGgQoNEfAD^C#0CtP4AgAE^EaBCgaUYCoAE#RoEKDRHwAw^gAANArT+AIAB^BGgQoNEfAAw^gQIMAjf4AgAE^EaBCg9QcAD^CBAgwCN/gBg§EaBGj0BwAM^IECDAK0/AG§ARoEaJqRAGg^BGgRo9AcAD^CBAgwCtPwBg§EaBGj0BwAD^CNAgQKM/AG§ARoEaP0BAAM^I0CBAoz8AG^ECABgEa/QEAAw^jQIEDrDwAY^QIAGAZpmJACaBw^RoEKD1BwAM^IECDAK0/AG§ARoEaPQHAAw^gQIMArT8AY§BGgRo/QEAAw^jQIECjPwBg§EaBGj9AQAD^CNAgQOsPABg#BAgAYBGv0BAANwCwAAGB6gYeckmpEAa^AEaBGj0BwAM^IECDAK0/AG§ARoEaPQHAAM^I0CBAoz8AY§BGgRo/QEAAw^jQIECjPwAY^QIAGARr9AQAD^CNAgQOsPABg#BAgAYBmmYkABoAAECABgEa/QEAAw^jQIEDrDwAY^QIAGARr9Ac§AjQI0OgPABg#BAgAYBWn8Aw§CNAjQ6A8ABg#BCgQYBGfwD§AI0CND6AwAG^EKBBgKYZCYAG#QoEGARn8Aw§CNAjQ+gMABg#BCgQYBGfwAw^gAANAjT6AwAG^EKBBgNYfAD^C#0CNPoDgAE^EaBCg0R8AM^IAADQK0/gCAAQ^RoEKBpRgKgAQAABGgQoNEfAD^C#0CtP4AgAE^EaBCg0R8AD^CBAgwCN/gCAAQ^RoEKD1BwAM^IECDAI3+AG§ARoEaPQHAAw^gQIMArT8AY§BGgRomsMAM^IAADQK0/gCAAQ^RoEKDRHwAw^gAANO7fQHwAw^gAANArT+AIAB^BGgQoNEfAGg^BGgRo9AcAD^CBAgwCtPwBg§EaBGj0BwAD^RIB+Ntg5iea5AD^DAIwI0CND6AwAG^EKBBgEZ/AKAB#EaBCg0R8AM^IAADQK0/gCAAQ^RoEKDRHwAM^IECDAI3+AIAB^BGgQoPUHAAw^gQIMAjf4AY§BGgRo9AcAD^CBAgwCtPwBg§EaBGiakQBo^ARoEaPQHAAw^gQIMArT8AY§BGgRo9AcAAw^jQIECjPwBg§EaBGj9AQAD^CNAgQKM/ABg#BAgAYBGv0BAAM^I0CBA6w8AG^ECABgGaZiQAGgAAQIAGARr9AQAD^CNAgQOsPABg#BAgAYBGv0Bw§CNAjQ6A8AG^ECABgFafwD§AI0CNDoDwAG^EKBBgEZ/AM§AjQI0PoDAAY^QoEGApjkMAAM^I0CBA6w8AG^ECABgEa/QEAAw^jQsIP+AIAB^BGgQoPUHAAw^gQIMAjf4AgAE#Bea/fK+3P5/3PJOvh8t1cO4nflmQAQoAEAAF9Aw/7JHfQHAAw^gQIMArT8AY§BGvwHNPoDAA0AACBAgwCN/gCAAQ^RoEKD1BwAM^IECDAI3+AG§ARoEaPQHAAw^gQIMArT8AY§BGgRo9AcAAw^jQIECjPwBg§EaBGj9AQAD^CNAgQNOMBEAD#I0CBAoz8AY§BGgRo/QEAAw^jQIECjPwAY^QIAGARr9AQAD^CNAgQOsPABg#BAgAYBGv0Bw§CNAjQ6A8AG^ECABgFafwD§AI0CNA0IwHQ^AjQI0OgPABg#BAgAYBWn8Aw§CNAjQ6A8ABg#BCgQYBGfwD§AI0CND6AwAG^EKBBgEZ/AD^C#0CNPoDAAY^QoEGA1h8AM^IAADQI0DQAG^EKBBgEZ/AM§AjQI0PoDAAY^QoEGA1h8AM^IAADQI0+gMABg#BCgQYDWHwAw^gAANArT+AIAB^BGgQoNEfAD^C#0CtP4AgAE^EaBCg9QcAD^CBAgwCN/gCAAQ^RoEKD1BwAM^IECDAK0/AG§ARoEaPQHAAw^gQIMArT8AY§BGgRo/QEAAw^jQIECjPwBgACDhFgC#07t9AfAD^C#0CtP4AgAE^EaBCg0R8Aa^AEaBGj0BwAM^IECDAK0/AG§ARoEaPQHAAM^I0CBAoz8AY§BGgRo/QEAAw^jQIECjPwAY^QIAGARr9AQAD^CNAgQOsPABg#BAgAYBmmYkABoAAECABgEa/QEAAw^jQIEDrDwAY^QIAGARr9Ac§AjQI0OgPABg#BAgAYBWn8Aw§CNAjQ6A8ABg#BCgQYBGfwD§AI0CND6AwAG^EKBBgKYZCYAG#QoEGARn8Aw§CNAjQ+gMABg#BCgQYBGfwAw^gAANAjT6AwAG^EKBBgNYfAD^C#0CNPoDgAE^EaBCg0R8AM^IAADQK0/gCAAQ^RoEKBpRgKgAQAABGgQoNEfAD^C#0CtP4AgAE^EaBCg0R8AD^CBAgwCN/gCAAQ^RoEKD1BwAM^IECDAI3+AG§ARoEaPQHAAw^gQIMArT8AY§BGgRommEAM^CBAgwCN/gCAAQ^RoEKD1BwAM^IECDAI3+AIAB^ARoEaPQHAAw^gQIMArT8AY§BGgRo9AcAGgAAQICGCNBfRfNcABg#BgeICGnVvoDwAY^QIAGAVp/AM§AjQI0OgPADQAAIAADQI0+gMABg#BCgQYDWHwAw^gAANAjT6A4AB^BGgQoNEfAD^C#0CtP4AgAE^EaBCg0R8AD^CBAgwCN/gCAAQ^RoEKD1BwAM^IECDAE0zEgAN#gQIMAjf4AgAE^EaBCg9QcAD^CBAgwCN/gBg§EaBGj0BwAM^IECDAK0/AG§ARoEaPQHAAM^I0CBAoz8AY§BGgRo/QEAAw^jQIEDTjARAAwAACNAgQKM/AG§ARoEaP0BAAM^I0CBAoz8AG^ECABgEa/QEAAw^jQIEDrDwAY^QIAGARr9Ac§AjQI0OgPABg#BAgAYBWn8Aw§CNAjQNIcBY§BGgRo/QEAAw^jQIECjPwBg§EadtAfAD^C#0CtP4AgAE^EaBCgAQABGgAA+AO2TAbHupOgH^ABJRU5ErkJggg==".replace(/§/g,"AAAAAA").replace(/\^/g,"AAAA").replace(/#/g,"AAA"),h="iVBORw0KGgoAAAANSUhEUgAAAGEAAABDCAMAAAC7vJusAAAAkFBMVEUAAAAvLy9ERERubm7///8AAAD///9EREREREREREREREQAAAD///8AAAD///8AAAD///8AAAD///8AAAD///8AAAD///8AAAD///8AAAD///8AAAD///8cHBwkJCQnJycoKCgpKSkqKiouLi4vLy8/Pz9AQEBCQkJDQ0NdXV1ubm58fHykpKRERERVVVUzMzPx7Ab+AAAAHXRSTlMAAAAAAAQEBQ4QGR4eIyMtLUVFVVVqapKSnJy7u9JKTggAAAFUSURBVHja7dXbUoMwEAbgSICqLYeW88F6KIogqe//dpoYZ0W4AXbv8g9TwkxmvtndZMrEwlw/F8YIRjCCEYxgBCOsFmzqGMEI28J5zzmt0Pc9rdDL0NYgMxIYC5KiKpKAzZphWtZlGm4SjlnkOV6UHeeEUx77rh/npw1dCrI9k9lnwUwF+UG9D3m4ftJJxH4SJdPtaawXcbr+tBaeFrxiur309cIv19+4ytGCU0031a5euPVigLYGqjlAqM4ShOQ+QAYQUO80AMMAAkUGGfMfR9Ul+kmvPq2QGxXKOQBAKdjUgk0t2NiCGEVP+rHT3/iCUMBT90YrPMsKsIWP3x/VolaonJEETchHCS8AYAmaUICQQwaAQnjoXgHAES7jLkEFaHO4bdq/k25HAIpgWY34FwAE5xjCffM+D2DV8B0gRsAZT7hr5gE8wdrJcU+CJqhcqQD7Cx5L7Ph4WnrKAAAAAElFTkSuQmCC",i="iVBORw0KGgoAAAANSUhEUgAAASAAAABvCAYAAABM+h2NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABORJREFUeNrs3VtTW1UYBuCEcxAI4YydWqTWdqr1V7T/2QsvvPDCCy9qjxZbamsrhZIQUHsCEtfafpmJe8qFjpUxfZ4Zuvt2feydJvAOARZUut1u5bRerl692nV913f99/f6QxWAU6KAAAUEKCAABQQoIAAFBCggAAUEKCAABQQoIAAFBCggAAUEKCAABQQoIEABASggQAEBKCBAAQEoIEABASggQAEBKCBAAQEoIGBQC+jatWvd07zxrv9+Xx8fAQEoIEABASggQAEBKCBAAQEoIEABAQoIQAEBCghAAQEKCEABAQOk2u36kS6AAgLetwJKL29toFRM1be+QrVq3rx58//KvM8BAadGAQEKCFBAAAoIGHwnfhneZ+/Nmzf/LufzrI+AAE/BAAUEoIAABQTwztgLZt68eXvBAE/BABQQoIAAFBAweOwFM2/evL1ggKdgAAoIUEAACggYPPaCmTdv3l4wwFMwAAUEKCAABQQMHnvBzJs3by8Y4CkYgAICFBCAAgIGz4lfBQNQQMDgFlCtVisaaHV1tThubW1VInciD0U+ysdnz54N5+PKysphOnRTHsvHlN9EHo/1l5FrkV9Enoz8W87b29tTOS8vLx9EnoncjlyPvBe5EbkZeT4fU96NvBDr2znv7Ows57y0tLQVeSXy08gf5mNfPhPrjyOfrVarlcXFxZ9yfv78+bl8TPlh5LU8n/KDyOuxfj/y+VjfyHl3d/dCKv28fi/yp/m4sLDwQ+SLke9GvhT5Tinfjnw5f4/F/Pz8rZybzeZn+ZjyzVK+EfnzUr4S+Xopf9/L+fxzc3M5d1qt1hf531Mu5k/IxzGf85VYL+fefHH+RqNRrO/t7RW3L+UbkS9Hvhk5/386Kd/qW8/5duRLMV/OdyJfzNebnZ0t7t92u53v/07K9yJfiLwROT9+ef7HyOux/iDyWuSHkT+K+eLtZX9//2xer9frjyOfyY9/Wn8S86v59qT1p7Ge315zLt4RU16K19+O9YXIu5HnYn435hux3opcj9yOPB3z+5E/iPXf43y1yMX778HBQS3f3pTz+28l5bHIr2N+LN3+zszMzGHkoh/S+mHMF98XlNaP8zHd/0W/pMe943NAwKlSQIACAhQQgAICFBCAAgIUEIACAhQQgAIC/n9GqtXqYbfbHa38+RtSu32llPdqdNL6aOSj+LfxyMVekLTem39Ryr/mPDQ0NBznzXtROikPRW6W8k7k3m9rzXthOsPDw73bUuylGRkZ6cR63nvTSfko8oPIr+Pnz96P/DLW816ezujoaN6DdtyX9+P8eS9QZ2xs7Hxf7qa8Xlr/JO6Ljcjrcf6cj1P+OO+N6V1/fHz8XLz+/Tjfubh+sZcorZ+N9Ycxfybyo8ircf6fc56YmFiJ1/8l8mLk7cjzkfP92U15Ns63G+u9nPcKdWq12lQ8Xu3Ixd6f9Pd8P3UmJycnUszzL2N9LM7/anNzs9V7Q2q32395w/q7ubdH6L/KrVbrpPxlKX9Vyl+X8jel/G0pf5f/aDabvXy9tH6ztH63lDdKebOUH5Xyk1LeKuWd/ry2tlap9P125Onp6Zf9eWpq6lW3b8f6zMzM6/71er3+ppSP+u/XNN/pz41Go+sjIMBTMEABASggQAEBKCBAAQEoIEABASggQAEB/CN/CDAAw78uW9AVDw4AAAAASUVORK5CYII=";a.ColorPicker={_html:b,_cssFunc:c,_cssMain:d,_horizontalPng:e,_verticalPng:f,_patchesPng:g,_iconsPng:h,_bgsPng:i}}(window),function(a,b){"use strict";function c(c,e){var j,k="",l="";for(var m in e)c.options[m]=e[m];Q=document.createStyleSheet!==b&&document.getElementById||!!a.MSInputMethodContext,R="undefined"!=typeof document.body.style.opacity,_=new Colors(c.options),delete c.options,bb=_.options,bb.scale=1,l=bb.CSSPrefix,c.color=_,S=bb.valueRanges,c.nodes=cb=g(f(c),c),q(bb.mode),d(c),u(),k=" "+bb.mode.type+"-"+bb.mode.z,cb.slds.className+=k,cb.panel.className+=k,bb.noHexButton&&C(cb.HEX_butt,l+"butt",l+"labl"),bb.size!==b&&p(b,bb.size),j={alphaBG:cb.alpha_labl,cmyOnly:cb.HEX_labl};for(var n in j)bb[n]!==b&&o({target:j[n],data:bb[n]});bb.noAlpha&&(cb.colorPicker.className+=" no-alpha"),c.renderMemory(bb.memoryColors),h(c),I=!0,i(b,"init"),N&&(d(N),w())}function d(a){Y=!0,M!==a&&(M=a,ab=a.color.colors,bb=a.color.options,cb=a.nodes,_=a.color,$={},v(ab))}function e(){var a=["L","S","XS","XXS"];bb.sizes={},cb.testNode.style.cssText="position:absolute;left:-1000px;top:-1000px;",document.body.appendChild(cb.testNode);for(var b=a.length;b--;)cb.testNode.className=bb.CSSPrefix+"app "+a[b],bb.sizes[a[b]]=[cb.testNode.offsetWidth,cb.testNode.offsetHeight];cb.testNode.removeNode?cb.testNode.removeNode(!0):document.body.removeChild(cb.testNode)}function f(a){var b=document.createElement("div"),c=bb.CSSPrefix,d="data:image/png;base64,",e=function(a,b){var c=document.createElement("style");c.setAttribute("type","text/css"),b&&c.setAttribute("id",b),c.styleSheet||c.appendChild(document.createTextNode(a)),document.getElementsByTagName("head")[0].appendChild(c),c.styleSheet&&(document.styleSheets[document.styleSheets.length-1].cssText=a)},f=function(a){O._cssFunc=O._cssFunc.replace(/§/g,c).replace("_patches.png",a?d+O._patchesPng:bb.imagePath+"_patches.png").replace("_vertical.png",a?d+O._verticalPng:bb.imagePath+"_vertical.png").replace("_horizontal.png",a?d+O._horizontalPng:bb.imagePath+"_horizontal.png"),e(O._cssFunc,"colorPickerCSS"),bb.customCSS||(O._cssMain=O._cssMain.replace(/§/g,c).replace("_bgs.png",a?d+O._bgsPng:bb.imagePath+"_bgs.png").replace("_icons.png",a?d+O._iconsPng:bb.imagePath+"_icons.png").replace(/opacity:(\d*\.*(\d+))/g,function(a,b){return R?"-moz-opacity: "+b+"; -khtml-opacity: "+b+"; opacity: "+b:'-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity='+db.round(100*+b)+')";filter: alpha(opacity='+db.round(100*+b)+")"}),e(O._cssMain))},g=document.createElement("img");return P?a.color.options.devPicker:(document.getElementById("colorPickerCSS")?a.cssIsReady=!0:(g.onload=g.onerror=function(){O._cssFunc&&f(1===this.width&&1===this.height),a.cssIsReady=!0},g.src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="),(N=M)&&r(),b.insertAdjacentHTML("afterbegin",M?M.nodes.colorPicker.outerHTML||(new XMLSerializer).serializeToString(M.nodes.colorPicker):O._html.replace(/§/g,c)),b=b.children[0],b.style.cssText=bb.initStyle||"",(bb.appendTo||document.body).appendChild(b))}function g(a){var b,c,d=a.getElementsByTagName("*"),e={colorPicker:a},f=new RegExp(bb.CSSPrefix);e.styles={},e.textNodes={},e.memos=[],e.testNode=document.createElement("div");for(var g=0,h=d.length;h>g;g++)b=d[g],(c=b.className)&&f.test(c)?(c=c.split(" ")[0].replace(bb.CSSPrefix,"").replace(/-/g,"_"),/_disp/.test(c)?(c=c.replace("_disp",""),e.styles[c]=b.style,e.textNodes[c]=b.firstChild,b.contentEditable=!0):(/(?:hs|cmyk|Lab).*?(?:butt|labl)/.test(c)||(e[c]=b),/(?:cur|sld[^s]|opacity|cont|col)/.test(c)&&(e.styles[c]=/(?:col\d)/.test(c)?b.children[0].style:b.style))):/memo/.test(b.parentNode.className)&&e.memos.push(b);return e.panelCover=e.panel.appendChild(document.createElement("div")),e}function h(c,f){var g=f?G:F;g(cb.colorPicker,"mousedown",function(f){var g=f||a.event,h=E(g),n=(g.button||g.which)<2?g.target||g.srcElement:{},o=n.className;return d(c),J=n,i(b,"resetEventListener"),U="",n===cb.sldl_3||n===cb.curm?(J=cb.sldl_3,I=j,U="changeXYValue",C(cb.slds,"do-drag")):/sldr/.test(o)||n===cb.curl||n===cb.curr?(J=cb.sldr_4,I=k,U="changeZValue"):n===cb.opacity.children[0]||n===cb.opacity_slider?(J=cb.opacity,I=l,U="changeOpacityValue"):/-disp/.test(o)&&!/HEX-/.test(o)?(I=m,U="changeInputValue",(3===n.nextSibling.nodeType?n.nextSibling.nextSibling:n.nextSibling).appendChild(cb.nsarrow),K=o.split("-disp")[0].split("-"),K={type:K[0],z:K[1]||""},C(cb.panel,"start-change"),V=0):n!==cb.resize||bb.noResize?I=b:(bb.sizes||e(),J=cb.resizer,I=p,U="resizeApp"),I&&(W={pageX:h.X,pageY:h.Y},J.style.display="block",X=D(J),X.width=cb.opacity.offsetWidth,X.childWidth=cb.opacity_slider.offsetWidth,J.style.display="",I(g),F(Q?document.body:a,"mousemove",I),L=a[fb](w)),/-disp/.test(o)?void 0:B(g)}),g(cb.colorPicker,"click",function(a){d(c),o(a)}),g(cb.colorPicker,"dblclick",o),g(cb.colorPicker,"keydown",function(a){d(c),n(a)}),g(cb.colorPicker,"keypress",n),g(cb.colorPicker,"paste",function(a){return a.target.firstChild.data=a.clipboardData.getData("Text"),B(a)})}function i(c,d){var e=I;I&&(a[gb](L),G(Q?document.body:a,"mousemove",I),V&&(K={type:"alpha"},w()),("function"==typeof I||"number"==typeof I)&&delete bb.webUnsave,V=1,I=b,C(cb.slds,"do-drag",""),C(cb.panel,"(?:start-change|do-change)",""),cb.resizer.style.cssText="",cb.panelCover.style.cssText="",cb.memo_store.style.cssText="background-color: "+y(ab.RND.rgb)+"; "+A(ab.alpha),cb.memo.className=cb.memo.className.replace(/\s+(?:dark|light)/,"")+(ab["rgbaMix"+T[bb.alphaBG]].luminance<.22?" dark":" light"),K=b,s(),bb.actionCallback&&bb.actionCallback(c,U||e.name||d||"external"))}function j(b){var c=b||a.event,d=bb.scale,e=E(c),f=(e.X-X.left)*(4===d?2:d),g=(e.Y-X.top)*d,h=bb.mode;return ab[h.type][h.x]=z(f/255,0,1),ab[h.type][h.y]=1-z(g/255,0,1),t(),B(c)}function k(b){var c=b||a.event,d=E(c),e=(d.Y-X.top)*bb.scale,f=bb.mode;return ab[f.type][f.z]=1-z(e/255,0,1),t(),B(c)}function l(b){var c=b||a.event,d=E(c);return Y=!0,ab.alpha=z(db.round((d.X-X.left)/X.width*100),0,100)/100,t("alpha"),B(c)}function m(b){var c,d=b||a.event,e=E(d),f=W.pageY-e.Y,g=bb.delayOffset,h=K.type,i="alpha"===h;return V||db.abs(f)>=g?(V||(V=(f>0?-g:g)+ +J.firstChild.data*(i?100:1),W.pageY+=V,f+=V,V=1,C(cb.panel,"start-change","do-change"),cb.panelCover.style.cssText="position:absolute;left:0;top:0;right:0;bottom:0",document.activeElement.blur(),L=a[fb](w)),"cmyk"===h&&bb.cmyOnly&&(h="cmy"),i?(Y=!0,ab.alpha=z(f/100,0,1)):(c=S[h][K.z],ab[h][K.z]="Lab"===h?z(f,c[0],c[1]):z(f/c[1],0,1)),t(i?"alpha":h),B(d)):void 0
+}function n(c){var d,e=c||a.event,f=e.which||e.keyCode,g=String.fromCharCode(f),h=document.activeElement,j=h.className.replace(bb.CSSPrefix,"").split("-"),k=j[0],l=j[1],m="alpha"===k,n="HEX"===k,o={k40:-1,k38:1,k34:-10,k33:10}["k"+f]/(m?100:1),p={HEX:/[0-9a-fA-F]/,Lab:/[\-0-9]/,alpha:/[\.0-9]/}[k]||/[0-9]/,q=S[k][k]||S[k][l],r=h.firstChild,s=H(h),u=r.data,w="0"!==u||n?u.split(""):[];return/^(?:27|13)$/.test(f)?(B(e),h.blur()):"keydown"===e.type?(o?d=z(db.round(1e6*(+u+o))/1e6,q[0],q[1]):/^(?:8|46)$/.test(f)&&(s.range||(s.range++,s.start-=8===f?1:0),w.splice(s.start,s.range),d=w.join("")||"0"),d!==b&&B(e,!0)):"keypress"===e.type&&(/^(?:37|39|8|46|9)$/.test(f)||B(e,!0),p.test(g)&&(w.splice(s.start,s.range,g),d=w.join("")),s.start++),13===f&&n?r.data.length%3===0||"0"===r.data?M.setColor("0"===r.data?"000":r.data,"rgb",ab.alpha,!0):(B(e,!0),h.focus()):(n&&d!==b&&(d=/^0+/.test(d)?d:parseInt(""+d,16)||0),void(d!==b&&""!==d&&+d>=q[0]&&+d<=q[1]&&(n&&(d=d.toString(16).toUpperCase()||"0"),m?ab[k]=+d:n||(ab[k][l]=+d/("Lab"===k?1:q[1])),t(m?"alpha":k),v(ab),I=!0,i(c,e.type),r.data=d,H(h,db.min(h.firstChild.data.length,s.start<0?0:s.start)))))}function o(c){var d,e,f=c||a.event,g=f.target||f.srcElement,h=g.className,j=g.parentNode,k=bb,l=ab.RND.rgb,m=bb.mode,n="",o=k.CSSPrefix,p=/(?:hs|rgb)/.test(j.className)&&/^[HSBLRG]$/.test(g.firstChild?g.firstChild.data:""),q=/dblc/.test(f.type),r="";if(!q||p){if(-1!==h.indexOf("-labl "+o+"labl"))C(cb[h.split("-")[0]],o+"hide",""),C(cb[j.className.split("-")[1]],o+"hide");else if(-1!==h.indexOf(o+"butt"))if(p)q&&2===bb.scale&&(n=/hs/.test(m.type)?"rgb":/hide/.test(cb.hsl.className)?"hsv":"hsl",n=n+"-"+n[m.type.indexOf(m.z)]),M.setMode(n?n:h.replace("-butt","").split(" ")[0]),r="modeChange";else if(/^[rgb]/.test(h))n=h.split("-")[1],C(cb.colorPicker,"no-rgb-"+n,(k["noRGB"+n]=!k["noRGB"+n])?b:""),r="noRGB"+n;else if(g===cb.alpha_labl)d=k.customBG,e=k.alphaBG,C(cb.colorPicker,"alpha-bg-"+e,"alpha-bg-"+(e=k.alphaBG=c.data||("w"===e?d?"c":"b":"c"===e?"b":"w"))),g.firstChild.data=e.toUpperCase(),cb.ctrl.style.backgroundColor=cb.memo.style.backgroundColor="c"!==e?"":"rgb("+db.round(255*d.r)+", "+db.round(255*d.g)+", "+db.round(255*d.b)+")",cb.raster.style.cssText=cb.raster_bg.previousSibling.style.cssText="c"!==e?"":A(d.luminance<.22?.5:.4),r="alphaBackground";else if(g===cb.alpha_butt)C(cb.colorPicker,"mute-alpha",(k.muteAlpha=!k.muteAlpha)?b:""),r="alphaState";else if(g===cb.HEX_butt)C(cb.colorPicker,"no-HEX",(k.HEXState=!k.HEXState)?b:""),r="HEXState";else if(g===cb.HEX_labl){var s="web save"===ab.saveColor;"web smart"===ab.saveColor||s?s?M.setColor(k.webUnsave,"rgb"):(k.webUnsave||(k.webUnsave=x(l)),M.setColor(ab.webSave,"rgb")):(k.webUnsave=x(l),M.setColor(ab.webSmart,"rgb")),r="webColorState"}else/Lab-x-labl/.test(h)&&(C(cb.colorPicker,"cmy-only",(k.cmyOnly=!k.cmyOnly)?b:""),r="cmykState");else if(g===cb.bsav)u(),r="saveAsBackground";else if(g===cb.bres){var w=x(l),y=ab.alpha;M.setColor(k.color),u(),M.setColor(w,"rgb",y),r="resetColor"}else if(j===cb.col1)ab.hsv.h-=ab.hsv.h>.5?.5:-.5,t("hsv"),r="shiftColor";else if(j===cb.col2)M.setColor(g.style.backgroundColor,"rgb",ab.background.alpha),r="setSavedColor";else if(j===cb.memo){var z=function(){cb.memos.blinker&&(cb.memos.blinker.style.cssText=cb.memos.cssText)},B=function(b){cb.memos.blinker=b,b.style.cssText="background-color:"+(ab.RGBLuminance>.22?"#333":"#DDD"),a.setTimeout(z,200)};if(g===cb.memo_cursor){z(),cb.memos.blinker=b,cb.testNode.style.cssText=cb.memo_store.style.cssText,cb.memos.cssText=cb.testNode.style.cssText;for(var D=cb.memos.length-1;D--;)if(cb.memos.cssText===cb.memos[D].style.cssText){B(cb.memos[D]);break}if(!cb.memos.blinker){for(var D=cb.memos.length-1;D--;)cb.memos[D+1].style.cssText=cb.memos[D].style.cssText;cb.memos[0].style.cssText=cb.memo_store.style.cssText}r="toMemory"}else z(),M.setColor(g.style.backgroundColor,"rgb",g.style.opacity||1),cb.memos.cssText=g.style.cssText,B(g),I=1,r="fromMemory"}r&&(v(ab),I=I||!0,i(c,r))}}function p(c,d){var e,f=c||a.event,g=f?E(f):{},h=d!==b,i=h?d:g.X-X.left+8,j=h?d:g.Y-X.top+8,k=[" S XS XXS"," S XS"," S",""],l=bb.sizes,m=h?d:j
10?i:10)+"px;height: "+(j>10?j:10)+"px;"}function q(a){var b={rgb_r:{x:"b",y:"g"},rgb_g:{x:"b",y:"r"},rgb_b:{x:"r",y:"g"},hsv_h:{x:"s",y:"v"},hsv_s:{x:"h",y:"v"},hsv_v:{x:"h",y:"s"},hsl_h:{x:"s",y:"l"},hsl_s:{x:"h",y:"l"},hsl_l:{x:"h",y:"s"}},c=a.replace("-","_"),d="\\b(?:rg|hs)\\w\\-\\w\\b";return C(cb.panel,d,a),C(cb.slds,d,a),a=a.split("-"),bb.mode={type:a[0],x:b[c].x,y:b[c].y,z:a[1]}}function r(){var a=/\s+(?:hue-)*(?:dark|light)/g,b="className";cb.curl[b]=cb.curl[b].replace(a,""),cb.curr[b]=cb.curr[b].replace(a,""),cb.slds[b]=cb.slds[b].replace(a,""),cb.sldr_2[b]=bb.CSSPrefix+"sldr-2",cb.sldr_4[b]=bb.CSSPrefix+"sldr-4",cb.sldl_3[b]=bb.CSSPrefix+"sldl-3";for(var c in cb.styles)c.indexOf("sld")||(cb.styles[c].cssText="");$={}}function s(){cb.styles.curr.cssText=cb.styles.curl.cssText,cb.curl.className=bb.CSSPrefix+"curl"+(Z.noRGBZ?" "+bb.CSSPrefix+"curl-"+Z.noRGBZ:""),cb.curr.className=bb.CSSPrefix+"curr "+bb.CSSPrefix+"curr-"+("h"===bb.mode.z?Z.HUEContrast:Z.noRGBZ?Z.noRGBZ:Z.RGBLuminance)}function t(a){v(_.setColor(b,a||bb.mode.type)),Y=!0}function u(a){return _.saveAsBackground(),cb.styles.col2.cssText="background-color: "+y(ab.background.RGB)+";"+A(ab.background.alpha),a&&v(ab),ab}function v(a){var c=db,d=Z,e=T[bb.alphaBG];d.hueDelta=c.round(100*a["rgbaMixBGMix"+e].hueDelta),d.luminanceDelta=c.round(100*a["rgbaMixBGMix"+e].luminanceDelta),d.RGBLuminance=a.RGBLuminance>.22?"light":"dark",d.HUEContrast=a.HUELuminance>.22?"light":"dark",d.contrast=d.luminanceDelta>d.hueDelta?"contrast":"",d.readabiltiy=a["rgbaMixBGMix"+e].WCAG2Ratio>=7?"green":a["rgbaMixBGMix"+e].WCAG2Ratio>=4.5?"orange":"",d.noRGBZ=bb["no"+bb.mode.type.toUpperCase()+bb.mode.z]?"g"===bb.mode.z&&a.rgb.g<.59||"b"===bb.mode.z||"r"===bb.mode.z?"dark":"light":b}function w(){if(I){if(!Y)return L=a[fb](w);Y=!1}var c,d,e,f,g=bb,h=g.mode,i=g.scale,l=g.CSSPrefix,m=ab,n=cb,o=n.styles,p=n.textNodes,q=S,r=K,s=Z,t=$,u=db,v=A,x=y,z=0,B=0,C=m[h.type][h.x],D=u.round(255*C/(4===i?2:i)),E=m[h.type][h.y],F=1-E,G=u.round(255*F/i),H=1-m[h.type][h.z],M=u.round(255*H/i),N=[C,E],O="rgb"===h.type,P="h"===h.z,Q="hsl"===h.type,R=Q&&"s"===h.z,T=I===j,U=I===k;O&&(N[0]>=N[1]?B=1:z=1,t.sliderSwap!==z&&(n.sldr_2.className=g.CSSPrefix+"sldr-"+(3-z),t.sliderSwap=z)),(O&&!U||P&&!T||!P&&!U)&&(o[P?"sldl_2":"sldr_2"][O?"cssText":"backgroundColor"]=O?v((N[z]-N[B])/(1-N[B]||0)):x(m.hueRGB)),P||(U||(o.sldr_4.cssText=v(O?N[B]:R?u.abs(1-2*F):F)),T||(o.sldl_3.cssText=v(Q&&"l"===h.z?u.abs(1-2*H):H)),Q&&(f=R?"sldr_4":"sldl_3",d=R?"r-":"l-",e=R?F>.5?4:3:H>.5?3:4,t[f]!==e&&(n[f].className=g.CSSPrefix+"sld"+d+e,t[f]=e))),U||(o.curm.cssText="left: "+D+"px; top: "+G+"px;"),T||(o.curl.top=M+"px"),r&&(o.curr.top=M+"px"),(r&&"alpha"===r.type||J===n.opacity)&&(o.opacity_slider.left=g.opacityPositionRelative?m.alpha*((X.width||n.opacity.offsetWidth)-(X.childWidth||n.opacity_slider.offsetWidth))+"px":100*m.alpha+"%"),o.col1.cssText="background-color: "+x(m.RND.rgb)+"; "+(g.muteAlpha?"":v(m.alpha)),o.opacity.backgroundColor=x(m.RND.rgb),o.cold.width=s.hueDelta+"%",o.cont.width=s.luminanceDelta+"%";for(c in p)d=c.split("_"),g.cmyOnly&&(d[0]=d[0].replace("k","")),e=d[1]?m.RND[d[0]][d[1]]:m.RND[d[0]]||m[d[0]],t[c]!==e&&(t[c]=e,p[c].data=e>359.5&&"HEX"!==c?0:e,"HEX"===c||g.noRangeBackground||(e=m[d[0]][d[1]]!==b?m[d[0]][d[1]]:m[d[0]],"Lab"===d[0]&&(e=(e-q[d[0]][d[1]][0])/(q[d[0]][d[1]][1]-q[d[0]][d[1]][0])),o[c].backgroundPosition=u.round(100*(1-e))+"% 0%"));d=m._rgb?[m._rgb.r!==m.rgb.r,m._rgb.g!==m.rgb.g,m._rgb.b!==m.rgb.b]:[],d.join("")!==t.outOfGammut&&(n.rgb_r_labl.firstChild.data=d[0]?"!":" ",n.rgb_g_labl.firstChild.data=d[1]?"!":" ",n.rgb_b_labl.firstChild.data=d[2]?"!":" ",t.outOfGammut=d.join("")),s.noRGBZ&&t.noRGBZ!==s.noRGBZ&&(n.curl.className=l+"curl "+l+"curl-"+s.noRGBZ,U||(n.curr.className=l+"curr "+l+"curr-"+s.noRGBZ),t.noRGBZ=s.noRGBZ),t.HUEContrast!==s.HUEContrast&&"h"===h.z?(n.slds.className=n.slds.className.replace(/\s+hue-(?:dark|light)/,"")+" hue-"+s.HUEContrast,U||(n.curr.className=l+"curr "+l+"curr-"+s.HUEContrast),t.HUEContrast=s.HUEContrast):t.RGBLuminance!==s.RGBLuminance&&(n.colorPicker.className=n.colorPicker.className.replace(/\s+(?:dark|light)/,"")+" "+s.RGBLuminance,U||"h"===h.z||s.noRGBZ||(n.curr.className=l+"curr "+l+"curr-"+s.RGBLuminance),t.RGBLuminance=s.RGBLuminance),(t.contrast!==s.contrast||t.readabiltiy!==s.readabiltiy)&&(n.ctrl.className=n.ctrl.className.replace(" contrast","").replace(/\s*(?:orange|green)/,"")+(s.contrast?" "+s.contrast:"")+(s.readabiltiy?" "+s.readabiltiy:""),t.contrast=s.contrast,t.readabiltiy=s.readabiltiy),t.saveColor!==m.saveColor&&(n.HEX_labl.firstChild.data=m.saveColor?"web save"===m.saveColor?"W":"M":"!",t.saveColor=m.saveColor),g.renderCallback&&g.renderCallback(m,h),I&&(L=a[fb](w))}function x(a){var b={};for(var c in a)b[c]=a[c];return b}function y(a,b){for(var c="",d=(b||"rgb").split(""),e=d.length;e--;)c=", "+a[d[e]]+c;return(b||"rgb")+"("+c.substr(2)+")"}function z(a,b,c){return a>c?c:b>a?b:a}function A(a){return a===b&&(a=1),R?"opacity: "+db.round(1e10*a)/1e10+";":"filter: alpha(opacity="+db.round(100*a)+");"}function B(b,c){return b.preventDefault?b.preventDefault():b.returnValue=!1,c||(a.getSelection?a.getSelection().removeAllRanges():document.selection.empty()),!1}function C(a,c,d){return a?a.className=d!==b?a.className.replace(new RegExp("\\s+?"+c,"g"),d?" "+d:""):a.className+" "+c:!1}function D(b){var c=b.getBoundingClientRect?b.getBoundingClientRect():{top:0,left:0},d=b&&b.ownerDocument,e=d.body,f=d.defaultView||d.parentWindow||a,g=d.documentElement||e.parentNode,h=g.clientTop||e.clientTop||0,i=g.clientLeft||e.clientLeft||0;return{left:c.left+(f.pageXOffset||g.scrollLeft)-i,top:c.top+(f.pageYOffset||g.scrollTop)-h}}function E(b){var c=a.document;return{X:b.pageX||b.clientX+c.body.scrollLeft+c.documentElement.scrollLeft,Y:b.pageY||b.clientY+c.body.scrollTop+c.documentElement.scrollTop}}function F(a,b,c){F.cache=F.cache||{_get:function(a,b,c,d){for(var e=F.cache[b]||[],f=e.length;f--;)if(a===e[f].obj&&""+c==""+e[f].func)return c=e[f].func,d||(e[f]=e[f].obj=e[f].func=null,e.splice(f,1)),c},_set:function(a,b,c){var d=F.cache[b]=F.cache[b]||[];return F.cache._get(a,b,c,!0)?!0:void d.push({func:c,obj:a})}},!c.name&&F.cache._set(a,b,c)||"function"!=typeof c||(a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,c))}function G(a,b,c){"function"==typeof c&&(c.name||(c=F.cache._get(a,b,c)||c),a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent("on"+b,c))}function H(c,d){var e={};if(d===b){if(a.getSelection){c.focus();var f=a.getSelection().getRangeAt(0),g=f.cloneRange();g.selectNodeContents(c),g.setEnd(f.endContainer,f.endOffset),e={end:g.toString().length,range:f.toString().length}}else{c.focus();var f=document.selection.createRange(),g=document.body.createTextRange();g.moveToElementText(c),g.setEndPoint("EndToEnd",f),e={end:g.text.length,range:f.text.length}}return e.start=e.end-e.range,e}if(-1==d&&(d=c.text().length),a.getSelection)c.focus(),a.getSelection().collapse(c.firstChild,d);else{var h=document.body.createTextRange();h.moveToElementText(c),h.moveStart("character",d),h.collapse(!0),h.select()}return d}var I,J,K,L,M,N,O=a.ColorPicker,P=!O,Q=!1,R=!1,S={},T={w:"White",b:"Black",c:"Custom"},U="",V=1,W={},X={},Y=!0,Z={},$={},_={},ab={},bb={},cb={},db=Math,eb="AnimationFrame",fb="request"+eb,gb="cancel"+eb,hb=["ms","moz","webkit","o"],ib=function(a){this.options={color:"rgba(204, 82, 37, 0.8)",mode:"rgb-b",fps:60,delayOffset:8,CSSPrefix:"cp-",allMixDetails:!0,alphaBG:"w",imagePath:""},c(this,a||{})};a.ColorPicker=ib,ib.addEvent=F,ib.removeEvent=G,ib.getOrigin=D,ib.limitValue=z,ib.changeClass=C,ib.prototype.setColor=function(a,b,c,e){d(this),K=!0,v(_.setColor.apply(_,arguments)),e&&this.startRender(!0)},ib.prototype.saveAsBackground=function(){return d(this),u(!0)},ib.prototype.setCustomBackground=function(a){return d(this),_.setCustomBackground(a)},ib.prototype.startRender=function(b){d(this),b?(I=!1,w(),this.stopRender()):(I=1,L=a[fb](w))},ib.prototype.stopRender=function(){d(this),a[gb](L),K&&(I=1,i(b,"external"))},ib.prototype.setMode=function(a){d(this),q(a),r(),w()},ib.prototype.destroyAll=function(){var a=this.nodes.colorPicker,b=function(a){for(var c in a)(a[c]&&"[object Object]"===a[c].toString()||a[c]instanceof Array)&&b(a[c]),a[c]=null,delete a[c]};this.stopRender(),h(this,!0),b(this),a.parentNode.removeChild(a),a=null},ib.prototype.renderMemory=function(a){var c=this.nodes.memos,d=[];"string"==typeof a&&(a=a.replace(/^'|'$/g,"").replace(/\s*/,"").split("','"));for(var e=c.length;e--;)a&&"string"==typeof a[e]&&(d=a[e].replace("rgba(","").replace(")","").split(","),a[e]={r:d[0],g:d[1],b:d[2],a:d[3]}),c[e].style.cssText="background-color: "+(a&&a[e]!==b?y(a[e])+";"+A(a[e].a||1):"rgb(0,0,0);")},F(Q?document.body:a,"mouseup",i);for(var jb=hb.length;jb--&&!a[fb];)a[fb]=a[hb[jb]+"Request"+eb],a[gb]=a[hb[jb]+"Cancel"+eb]||a[hb[jb]+"CancelRequest"+eb];a[fb]=a[fb]||function(b){return a.setTimeout(b,1e3/bb.fps)},a[gb]=a[gb]||function(b){return a.clearTimeout(b),L=null}}(window);
\ No newline at end of file
diff --git a/_server/thirdparty/jsColor.js b/_server/thirdparty/jsColor.js
new file mode 100644
index 0000000..0d85e92
--- /dev/null
+++ b/_server/thirdparty/jsColor.js
@@ -0,0 +1,305 @@
+// ------ ColorPicker ------ //
+
+(function (window) {
+ window.jsColorPicker = function(selectors, config) {
+ var renderCallback = function(colors, mode) {
+ var options = this,
+ input = options.input,
+ patch = options.patch,
+ RGB = colors.RND.rgb,
+ HSL = colors.RND.hsl,
+ AHEX = options.isIE8 ? (colors.alpha < 0.16 ? '0' : '') +
+ (Math.round(colors.alpha * 100)).toString(16).toUpperCase() + colors.HEX : '',
+ RGBInnerText = RGB.r + ',' + RGB.g + ',' + RGB.b,
+ RGBAText = RGBInnerText + ',' + colors.alpha,
+ isAlpha = colors.alpha !== 1 && !options.isIE8,
+ colorMode = input.getAttribute('data-colorMode');
+
+ patch.style.cssText =
+ 'color:' + (colors.rgbaMixCustom.luminance > 0.22 ? '#222' : '#ddd') + ';' + // Black...???
+ 'background-color: rgba(' + RGBAText + ');' +
+ 'filter:' + (options.isIE8 ? 'progid:DXImageTransform.Microsoft.gradient(' + // IE<9
+ 'startColorstr=#' + AHEX + ',' + 'endColorstr=#' + AHEX + ')' : '');
+
+ input.value = RGBAText;
+
+ if (options.displayCallback) {
+ options.displayCallback(colors, mode, options);
+ }
+ },
+ extractValue = function(elm) {
+ var val = elm.value || elm.getAttribute('value') || elm.style.backgroundColor || "0,0,0,1";
+ if (/^[0-9 ]+,[0-9 ]+,[0-9 ]+,[0-9. ]+$/.test(val)) return "rgba("+val+")";
+ if (/^[0-9 ]+,[0-9 ]+,[0-9 ]+$/.test(val)) return "rgba("+val+",1)";
+ return null;
+ },
+ actionCallback = function(event, action) {
+ var options = this,
+ colorPicker = colorPickers.current;
+
+ if (action === 'toMemory') {
+ var memos = colorPicker.nodes.memos,
+ backgroundColor = '',
+ opacity = 0,
+ cookieTXT = [];
+
+ for (var n = 0, m = memos.length; n < m; n++) {
+ backgroundColor = memos[n].style.backgroundColor;
+ opacity = memos[n].style.opacity;
+ opacity = Math.round((opacity === '' ? 1 : opacity) * 100) / 100;
+ cookieTXT.push(backgroundColor.
+ replace(/, /g, ',').
+ replace('rgb(', 'rgba(').
+ replace(')', ',' + opacity + ')')
+ );
+ }
+ cookieTXT = '\'' + cookieTXT.join('\',\'') + '\'';
+ ColorPicker.docCookies('colorPickerMemos' + (options.noAlpha ? 'NoAlpha' : ''), cookieTXT);
+ } else if (action === 'resizeApp') {
+ ColorPicker.docCookies('colorPickerSize', colorPicker.color.options.currentSize);
+ } else if (action === 'modeChange') {
+ var mode = colorPicker.color.options.mode;
+
+ ColorPicker.docCookies('colorPickerMode', mode.type + '-' + mode.z);
+ }
+ },
+ createInstance = function(elm, config) {
+ var initConfig = {
+ klass: window.ColorPicker,
+ input: elm,
+ patch: elm,
+ isIE8: !!document.all && !document.addEventListener, // Opera???
+ // *** animationSpeed: 200,
+ // *** draggable: true,
+ margin: {left: -1, top: 2},
+ customBG: '#FFFFFF',
+ // displayCallback: displayCallback,
+ /* --- regular colorPicker options from this point --- */
+ color: extractValue(elm),
+ initStyle: 'display: none',
+ mode: ColorPicker.docCookies('colorPickerMode') || 'hsv-h',
+ // memoryColors: (function(colors, config) {
+ // return config.noAlpha ?
+ // colors.replace(/\,\d*\.*\d*\)/g, ',1)') : colors;
+ // })($.docCookies('colorPickerMemos'), config || {}),
+ memoryColors: ColorPicker.docCookies('colorPickerMemos' +
+ ((config || {}).noAlpha ? 'NoAlpha' : '')),
+ size: ColorPicker.docCookies('colorPickerSize') || 1,
+ renderCallback: renderCallback,
+ actionCallback: actionCallback
+ };
+
+ for (var n in config) {
+ initConfig[n] = config[n];
+ }
+ return new initConfig.klass(initConfig);
+ },
+ doEventListeners = function(elm, multiple, off) {
+ var onOff = off ? 'removeEventListener' : 'addEventListener',
+ inputListener = function(e) {
+ var index = multiple ? Array.prototype.indexOf.call(elms, this) : 0,
+ colorPicker = colorPickers[index] ||
+ (colorPickers[index] = createInstance(this, config)),
+ options = colorPicker.color.options;
+
+ options.color = extractValue(elm); // brings color to default on reset
+ //检查颜色合法性
+ if (options.color != null && options.color == options.color.match(/rgba\([0-9 ]+,[0-9 ]+,[0-9 ]+,[0-9. ]+\)/)[0]) {
+ var chec = options.color.match(/[0-9.]+/g);
+ if (chec.length != 4)
+ return;
+ for (var i = 0; i < 3; i++) {
+ if (chec[i] != chec[i].match(/\d+/)[0] || +chec[i] < 0 || +chec[i] > 255)
+ return;
+ }
+ if (chec[3] != chec[3].match(/\d+(\.\d+)?/)[0] || parseFloat(chec[3]) > 1 || parseFloat(chec[3] < 0))
+ return;
+ if (!multiple) {
+ colorPicker.setColor(extractValue(elm), undefined, undefined, true);
+ colorPicker.saveAsBackground();
+ }
+ colorPickers.current = colorPickers[index];
+ }
+ },
+ createListener = function() {
+ elm = document.getElementById("colorPicker");
+ var input = elm,
+ position = window.ColorPicker.getOrigin(input),
+ index = multiple ? Array.prototype.indexOf.call(elms, elm) : 0,
+ colorPicker = colorPickers[index] ||
+ (colorPickers[index] = createInstance(elm, config)),
+ options = colorPicker.color.options,
+ colorPickerUI = colorPicker.nodes.colorPicker,
+ appendTo = (options.appendTo || document.body),
+ isStatic = /static/.test(window.getComputedStyle(appendTo).position),
+ atrect = isStatic ? {left: 0, top: 0} : appendTo.getBoundingClientRect(),
+ waitTimer = 0;
+
+ options.color = extractValue(elm); // brings color to default on reset
+ colorPickerUI.style.cssText =
+ 'position: absolute;' + (!colorPickers[index].cssIsReady ? 'display: none;' : '') +
+ 'left:' + (position.left + options.margin.left - atrect.left) + 'px;' +
+ 'top:' + (position.top + +input.offsetHeight + options.margin.top - atrect.top) + 'px;';
+
+ if (!multiple) {
+ options.input = elm;
+ options.patch = elm; // check again???
+ colorPicker.setColor(extractValue(elm), undefined, undefined, true);
+ colorPicker.saveAsBackground();
+ }
+ colorPickers.current = colorPickers[index];
+ appendTo.appendChild(colorPickerUI);
+ waitTimer = setInterval(function() { // compensating late style on onload in colorPicker
+ if (colorPickers.current.cssIsReady) {
+ waitTimer = clearInterval(waitTimer);
+ colorPickerUI.style.display = 'block';
+ }
+ }, 10);
+ },
+ hideListener = function(e) {
+ var colorPicker = colorPickers.current,
+ colorPickerUI = (colorPicker ? colorPicker.nodes.colorPicker : undefined),
+ animationSpeed = colorPicker ? colorPicker.color.options.animationSpeed : 0,
+ isColorPicker = colorPicker && (function(elm) {
+ while (elm) {
+ if ((elm.className || '').indexOf('cpPanel') !== -1) return elm;
+ elm = elm.parentNode;
+ }
+ return false;
+ })(e.target),
+ inputIndex = Array.prototype.indexOf.call(elms, e.target);
+
+ if (isColorPicker && Array.prototype.indexOf.call(colorPickers, isColorPicker)) {
+ if (e.target === colorPicker.nodes.exit) {
+ colorPickerUI.parentNode.style.display = 'none';
+ document.activeElement.blur();
+ } else {
+ // ...
+ }
+ } else if (inputIndex !== -1) {
+ // ...
+ } else if (colorPickerUI) {
+ colorPickerUI.parentNode.style.display = 'none';
+ }
+ };
+ elm[onOff]('input', inputListener);
+ window.jsColorPicker.create = createListener;
+ },
+ // this is a way to prevent data binding on HTMLElements
+ colorPickers = window.jsColorPicker.colorPickers || [],
+ elms = document.querySelectorAll(selectors),
+ testColors = new window.Colors({customBG: config.customBG, allMixDetails: true});
+
+ window.jsColorPicker.colorPickers = colorPickers;
+
+ for (var n = 0, m = elms.length; n < m; n++) {
+ var elm = elms[n];
+
+ if (config === 'destroy') {
+ doEventListeners(elm, (config && config.multipleInstances), true);
+ if (colorPickers[n]) {
+ colorPickers[n].destroyAll();
+ }
+ } else {
+ var color = extractValue(elm);
+ var value = color.split('(');
+
+ testColors.setColor(color);
+ if (config && config.init) {
+ config.init(elm, testColors.colors);
+ }
+ elm.setAttribute('data-colorMode', value[1] ? value[0].substr(0, 3) : 'HEX');
+ doEventListeners(elm, (config && config.multipleInstances), false);
+ if (config && config.readOnly) {
+ elm.readOnly = true;
+ }
+ }
+ };
+
+ return window.jsColorPicker.colorPickers;
+ };
+
+ window.ColorPicker.docCookies = function(key, val, options) {
+ var encode = encodeURIComponent, decode = decodeURIComponent,
+ cookies, n, tmp, cache = {},
+ days;
+
+ if (val === undefined) { // all about reading cookies
+ cookies = document.cookie.split(/;\s*/) || [];
+ for (n = cookies.length; n--; ) {
+ tmp = cookies[n].split('=');
+ if (tmp[0]) cache[decode(tmp.shift())] = decode(tmp.join('=')); // there might be '='s in the value...
+ }
+
+ if (!key) return cache; // return Json for easy access to all cookies
+ else return cache[key]; // easy access to cookies from here
+ } else { // write/delete cookie
+ options = options || {};
+
+ if (val === '' || options.expires < 0) { // prepare deleteing the cookie
+ options.expires = -1;
+ // options.path = options.domain = options.secure = undefined; // to make shure the cookie gets deleted...
+ }
+
+ if (options.expires !== undefined) { // prepare date if any
+ days = new Date();
+ days.setDate(days.getDate() + options.expires);
+ }
+
+ document.cookie = encode(key) + '=' + encode(val) +
+ (days ? '; expires=' + days.toUTCString() : '') +
+ (options.path ? '; path=' + options.path : '') +
+ (options.domain ? '; domain=' + options.domain : '') +
+ (options.secure ? '; secure' : '');
+ }
+ };
+})(this);
+
+// Added
+jsColorPicker('input.color', {
+ customBG: '#222',
+ readOnly: false,
+ // patch: false,
+ init: function(elm, colors) { // colors is a different instance (not connected to colorPicker)
+ elm.style.backgroundColor = elm.value;
+ elm.style.color = colors.rgbaMixCustom.luminance > 0.22 ? '#222' : '#ddd';
+ },
+ appendTo: document.getElementById("colorPanel"),
+ size: 1,
+});
+
+function openColorPicker(px, py, callback) {
+ window.jsColorPicker.confirm = callback;
+ var colorPanel = document.getElementById('colorPanel');
+ if (colorPanel.style.display=='none' && px != null && py != null) {
+ colorPanel.style.display = "inline-block";
+ colorPanel.style.left = px + 'px';
+ colorPanel.style.top = py + 'px';
+ window.jsColorPicker.create();
+ }
+ else {
+ colorPanel.style.display = 'none';
+ delete window.jsColorPicker.confirm;
+ }
+}
+
+function confirmColor() {
+ var colorPicker = document.getElementById("colorPicker");
+ if (window.jsColorPicker.confirm) { /* 存在块 */
+ // 检测需要是合法数值
+ var val = colorPicker.value;
+ if (/^[0-9 ]+,[0-9 ]+,[0-9 ]+,[0-9. ]+$/.test(val)) val = "rgba("+val+")";
+ else if (/^[0-9 ]+,[0-9 ]+,[0-9 ]+$/.test(val)) val = "rgba("+val+",1)";
+ else val = null;
+ if (val) window.jsColorPicker.confirm(val);
+ }
+ else {
+ colorPicker.select();
+ document.execCommand("Copy");
+ }
+ colorPanel.style.display = 'none';
+ delete window.jsColorPicker.confirm;
+}
+
+// ------ AutoCompletion ------
+
diff --git a/editor-mobile.html b/editor-mobile.html
new file mode 100644
index 0000000..ed4c344
--- /dev/null
+++ b/editor-mobile.html
@@ -0,0 +1,501 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/editor.html b/editor.html
new file mode 100644
index 0000000..31332e0
--- /dev/null
+++ b/editor.html
@@ -0,0 +1,485 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
(Ctrl+滚轮放缩,右键置顶)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/extensions/dynamicMapEditor.js b/extensions/dynamicMapEditor.js
new file mode 100644
index 0000000..7b996d7
--- /dev/null
+++ b/extensions/dynamicMapEditor.js
@@ -0,0 +1,514 @@
+/**
+ * 运行时可编辑地图的扩展,By fux2(黄鸡)
+ */
+
+"use strict";
+
+function dynamicMapEditor() {
+ // 所有显示的ID
+ this.displayIds = [
+ 'none', 'yellowWall', 'blueWall', 'whiteWall', 'yellowDoor', 'blueDoor', 'redDoor', 'star', 'lava', 'lavaNet',
+ 'yellowKey', 'blueKey', 'redKey', 'redGem', 'blueGem', 'greenGem', 'yellowGem',
+ 'redPotion', 'bluePotion', 'yellowPotion', 'greenPotion', 'pickaxe', 'bomb', 'centerFly',
+ 'cls:autotile', 'cls:enemys', 'cls:enemy48'
+ ];
+ this.items = [];
+ this.userChanged = [];
+ this.savedItems = [];
+ this.dom = null;
+ this.canvas = null;
+ this.mapRecord = {};
+ this.enemyModified = false;
+ this.valueModified = false;
+ this.pageId = 0;
+ this.pageMaxItems = 21;
+ this.pageMax = 0;
+ this.selectedIndex = 0;
+ this.selectedItem = null;
+ this._init();
+}
+
+// ------ init
+
+dynamicMapEditor.prototype._init = function () {
+ this.dom = document.createElement("canvas");
+ this.dom.id = 'dynamicMapEditor';
+ this.dom.style.display = 'none';
+ this.dom.style.position = 'absolute';
+ this.dom.style.left = '3px';
+ this.dom.style.top = '3px';
+ this.dom.style.zIndex = 99999;
+ this.canvas = this.dom.getContext("2d");
+ core.dom.gameGroup.appendChild(this.dom);
+
+ this.initInfos();
+ this.pageMax = Math.ceil(this.items.length / this.pageMaxItems);
+ core.registerAction('onkeyUp', 'plugin_dme_keydown', this.onKeyUp.bind(this), 200);
+ core.registerAction('onclick', 'plugin_dme_click', this.onMapClick.bind(this), 200);
+ this.dom.addEventListener("click",this.onBoxClick.bind(this));
+ this.showInitHelp();
+}
+
+dynamicMapEditor.prototype.initInfos = function () {
+ this.items = [];
+ var ids = {};
+ this.displayIds.forEach(function (v) {
+ if (v.startsWith("cls:")) {
+ var cls = v.substr(4);
+ for (var id in core.maps.blocksInfo) {
+ var u = core.maps.blocksInfo[id];
+ if (u && u.cls == cls) {
+ if (ids[u.id]) continue;
+ this.items.push(core.getBlockInfo(u.id));
+ ids[u.id] = true;
+ }
+ }
+ } else if (v == 'none') {
+ this.items.push({"number": 0, "id": "none", "name": "清除块"});
+ } else {
+ this.items.push(core.getBlockInfo(v));
+ }
+ }, this);
+ this.items = this.items.filter(function (v) { return v && v.id && v.number >= 0; });
+ this.savedItems = core.getLocalStorage('_dynamicMapEditor_savedItems', []);
+}
+
+// ------ bind actions
+
+dynamicMapEditor.prototype.isValid = function () {
+ return main.mode == 'play' && core.isPlaying() && !core.isReplaying() && !core.status.lockControl;
+}
+
+dynamicMapEditor.prototype.onKeyUp = function(e) {
+ if (!this.isValid()) return false;
+ if (e.keyCode == 219) {
+ this.openToolBox();
+ return true;
+ }
+ if (!this.isUsingTool) return false;
+
+ if (e.keyCode == 220) {
+ this.undo();
+ return true;
+ } else if (e.keyCode == 221) {
+ this.applyCurrentChange();
+ return true;
+ } else if (e.keyCode >= 48 && e.keyCode <= 57) {
+ // 0-9
+ if (e.altKey) {
+ this.savedItem(e.keyCode - 48);
+ } else {
+ this.loadItem(e.keyCode - 48);
+ }
+ return true;
+ }
+ return false;
+}
+
+dynamicMapEditor.prototype.onMapClick = function(x, y) {
+ if (!this.isValid()) return false;
+ if (!this.isUsingTool || !this.selectedItem) return false;
+ x += parseInt(core.bigmap.offsetX / 32);
+ y += parseInt(core.bigmap.offsetY / 32);
+ var number = this.selectedItem.number;
+ this.addOperation('put', number, x, y, core.status.floorId);
+ return true;
+}
+
+dynamicMapEditor.prototype.getClickLoc = function (e) {
+ return {
+ x: (e.clientX - core.dom.gameGroup.offsetLeft - 3) / core.domStyle.scale,
+ y: (e.clientY - core.dom.gameGroup.offsetTop - 3) / core.domStyle.scale,
+ };
+}
+
+dynamicMapEditor.prototype.onBoxClick = function (e) {
+ if (!this.isValid() || !this.isUsingTool) return false;
+ var loc = this.getClickLoc(e), x = loc.x, y = loc.y;
+ for(var i = 0; i < this.pageMaxItems; i++) {
+ var rect = this.itemRect(i);
+ if(x >= rect.x && x <= rect.x + rect.w && y >= rect.y && y <= rect.y + rect.h) {
+ this.onItemClick(i);
+ return;
+ }
+ }
+ if(y>=350 && y <= 370) {
+ if (x >= this.offsetX && x <= this.offsetX + 40) {
+ this.changePage(-1);
+ } else if (x >= this.offsetX + 40 && x <= this.offsetX + 80) {
+ this.showHelp(true);
+ } else if (x >= this.offsetX + 80 && x <= this.offsetX + 120) {
+ this.changePage(1);
+ }
+ }
+}
+
+dynamicMapEditor.prototype.onItemClick = function(index) {
+ var startIndex = this.pageId * this.pageMaxItems;
+ var item = this.items[startIndex + index];
+ if(!item) return;
+ if(index == this.selectedIndex) {
+ if (core.material.enemys[item.id]) {
+ var enemy = core.material.enemys[item.id];
+ var nowData = [enemy.hp, enemy.atk, enemy.def, enemy.special].join(';');
+ core.myprompt("请输入新怪物属性\n血;攻;防;能力,以分号分隔", nowData, function (result) {
+ if (result) {
+ try {
+ var finalData = result.split(';');
+ if (finalData.length < 4) throw "";
+ var hp = parseInt(finalData[0]) || 0;
+ var atk = parseInt(finalData[1]) || 0;
+ var def = parseInt(finalData[2]) || 0;
+ var special = finalData[3].replace(/[\[\]]/g, "")
+ .split(',').map(function (x) { return parseInt(x); });
+ if (special.length == 0) special = 0;
+ else if (special.length == 1) special = special[0];
+ dynamicMapEditor.addOperation('modify', item.id, hp, atk, def, special);
+ core.drawTip('已更新' + enemy.name + '的数据');
+ return;
+ } catch (e) {}
+ }
+ core.drawTip('无效的输入数据');
+ });
+ return;
+ }
+ if (core.values[item.id] != null) {
+ var nowData = core.values[item.id];
+ core.myprompt("请输入新" + (item.name || "") + "数值:", core.values[item.id], function (result) {
+ if (result) {
+ dynamicMapEditor.addOperation('value', item.id, parseInt(result) || 0, item.name || "");
+ core.drawTip('已更新' + (item.name || "") + "的数值");
+ return;
+ }
+ core.drawTip('无效的输入数据');
+ });
+ return;
+ }
+ } else {
+ this.selectedIndex = index;
+ this.selectedItem = item;
+ this.refreshToolBox();
+ }
+}
+
+// ------ methods
+
+dynamicMapEditor.prototype.openToolBox = function() {
+ if (!this.isUsingTool && core.domStyle.isVertical) {
+ core.drawTip("竖屏模式下暂不支持此功能。");
+ return;
+ }
+ this.isUsingTool = !this.isUsingTool;
+ this.selectedItem = null;
+ this.selectedIndex = -1;
+ this.dom.style.display = this.isUsingTool ? 'block' : 'none';
+ this.dom.style.width = core.dom.statusCanvas.style.width;
+ this.dom.width = core.dom.statusCanvas.width / core.domStyle.ratio;
+ this.dom.style.height = core.dom.statusCanvas.style.height;
+ this.dom.height = core.dom.statusCanvas.height / core.domStyle.ratio;
+ this.offsetX = this.dom.width / 2 - 60;
+ this.refreshToolBox();
+ if (this.isUsingTool) this.showHelp();
+}
+
+dynamicMapEditor.prototype.addOperation = function() {
+ var operation = {};
+ var type = arguments[0];
+ operation.type = type;
+ if (type == 'put') {
+ operation.number = arguments[1];
+ operation.x = arguments[2];
+ operation.y = arguments[3];
+ operation.floorId = arguments[4];
+ operation.originNumber = core.floors[operation.floorId].map[operation.y][operation.x];
+ core.floors[operation.floorId].map[operation.y][operation.x] = operation.number;
+ core.setBlock(operation.number, operation.x, operation.y, operation.floorId);
+ this.mapRecord[operation.floorId] = true;
+ } else if (type == 'modify') {
+ operation.enemyId = arguments[1];
+ operation.hp = arguments[2];
+ operation.atk = arguments[3];
+ operation.def = arguments[4];
+ operation.special = arguments[5];
+ var enemy = core.material.enemys[operation.enemyId];
+ operation.originHp = enemy.hp;
+ operation.originAtk = enemy.atk;
+ operation.originDef = enemy.def;
+ operation.originSpecial = enemy.special;
+ enemy.hp = operation.hp;
+ enemy.atk = operation.atk;
+ enemy.def = operation.def;
+ enemy.special = operation.special;
+ this.enemyModified = true;
+ } else if (type == 'value') {
+ operation.id = arguments[1];
+ operation.value = arguments[2];
+ operation.name = arguments[3];
+ operation.originValue = core.values[operation.id];
+ core.values[operation.id] = operation.value;
+ this.valueModified = true;
+ }
+ this.userChanged.push(operation);
+}
+
+dynamicMapEditor.prototype.undo = function() {
+ var operation = this.userChanged.pop();
+ if(!operation) {
+ core.drawTip('没有动作可以撤销');
+ return;
+ }
+ var type = operation.type;
+ if(type == 'put') { // {originNumber, x, y, floorId}
+ var originNumber = operation.originNumber;
+ var x = operation.x;
+ var y = operation.y;
+ var floorId = operation.floorId;
+ core.floors[floorId].map[y][x] = originNumber;
+ core.setBlock(originNumber, x, y, floorId);
+ this.mapRecord[floorId] = true;
+ core.drawTip('已撤销' + floorId + '在(' + x + ',' + y + ')的图块操作');
+ } else if (type == 'modify') { // {enemyId, originHp, originAtk, originDef, originSpecial}
+ var enemyId = operation.enemyId;
+ var hp = operation.originHp;
+ var atk = operation.originAtk;
+ var def = operation.originDef;
+ var special = operation.originSpecial;
+ var enemy = core.material.enemys[enemyId];
+ enemy.hp = hp;
+ enemy.atk = atk;
+ enemy.def = def;
+ enemy.special = special;
+ core.drawTip('已撤销对' + enemy.name + '的属性修改');
+ this.enemyModified = true;
+ } else if (type == 'value') { // {id, value, originValue}
+ var id = operation.id;
+ var value = operation.originValue;
+ core.values[operation.id] = operation.originValue;
+ core.drawTip('已撤销对' + operation.name + "数值的修改");
+ this.valueModified = true;
+ }
+}
+
+dynamicMapEditor.prototype.changePage = function(delta) {
+ var newId = this.pageId + delta;
+ if (newId < 0 || newId >= this.pageMax) return;
+ this.pageId = newId;
+ this.selectedItem = null;
+ this.selectedIndex = -1;
+ this.refreshToolBox();
+}
+
+dynamicMapEditor.prototype.savedItem = function (number) {
+ if (!this.isUsingTool || this.selectedItem < 0) return;
+ this.savedItems[number] = [this.pageId, this.selectedIndex];
+ core.setLocalStorage('_dynamicMapEditor_savedItems', this.savedItems);
+ core.drawTip("已保存此图块");
+}
+
+dynamicMapEditor.prototype.loadItem = function (number) {
+ if (!this.isUsingTool) return;
+ var u = this.savedItems[number];
+ if (!u) return core.drawTip("没有保存的图块!");
+ this.pageId = u[0];
+ this.selectedIndex = u[1];
+ this.selectedItem = this.items[this.pageId * this.pageMaxItems + this.selectedIndex];
+ this.refreshToolBox();
+}
+
+// ------ draw
+
+dynamicMapEditor.prototype.itemRect = function(index) {
+ return {
+ 'x' : this.offsetX + (index % 3) * 40,
+ 'y' : Math.floor(index / 3) * 50,
+ 'w' : 40,
+ 'h' : 50
+ };
+}
+
+dynamicMapEditor.prototype.refreshToolBox = function() {
+ if (!this.isUsingTool) return;
+ core.fillRect(this.canvas, 0, 0, this.dom.width, this.dom.height, '#000000');
+ var startIndex = this.pageId * this.pageMaxItems;
+ for (var i = 0; i < this.pageMaxItems; ++i) {
+ var item = this.items[startIndex + i];
+ if (!item) break;
+ var rect = this.itemRect(i);
+ if (item.image) core.drawImage(this.canvas, item.image, 0, item.height * item.posY, 32, 32, rect.x + 4, rect.y, 32, 32);
+ if (item.name) {
+ this.canvas.textAlign = 'center';
+ core.fillText(this.canvas, item.name, rect.x + 20, rect.y + 44, '#FFFFFF', '11px Verdana', 40);
+ }
+ if (core.material.enemys[item.id]) {
+ this.canvas.textAlign = 'left';
+ var damageString = core.enemys.getDamageString(item.id);
+ core.fillBoldText(this.canvas, damageString.damage, rect.x + 5, rect.y + 31, damageString.color, null, '11px Verdana');
+ var critical = core.enemys.nextCriticals(item.id, 1);
+ critical = core.formatBigNumber((critical[0]||[])[0], true);
+ if (critical == '???') critical = '?';
+ core.fillBoldText(this.canvas, critical, rect.x+5, rect.y+21, '#FFFFFF');
+ }
+ }
+
+ this.canvas.textAlign = 'center';
+ this.canvas.fillStyle = '#FFFFFF';
+ if(this.pageId > 0) core.fillText(this.canvas, '上一页', this.offsetX + 20, 365, '#FFFFFF', '11px Verdana');
+ if(this.pageId < this.pageMax-1) core.fillText(this.canvas, '下一页',this.offsetX + 100, 365, '#FFFFFF', '11px Verdana');
+ core.fillText(this.canvas, '帮助', this.offsetX + 60, 365, '#FFFFFF');
+ var text1 = core.formatBigNumber(core.getRealStatus('hp'), true) + "/" +
+ core.formatBigNumber(core.getRealStatus('atk'), true) + "/" +
+ core.formatBigNumber(core.getRealStatus("def"), true) + "/" +
+ core.formatBigNumber(core.getRealStatus("mdef"), true);
+ core.fillText(this.canvas, text1, this.offsetX + 60, 380, '#FF7F00', '11px Verdana', 120);
+ var text2 = core.formatBigNumber(core.getRealStatus('money', true)) + "/" +
+ core.formatBigNumber(core.getRealStatus('exp'), true) + "/" +
+ core.itemCount('yellowKey') + '/' + core.itemCount('blueKey') + '/' +
+ core.itemCount('redKey');
+ core.fillText(this.canvas, text2, this.offsetX + 60, 395, '#FF7F00', '11px Verdana', 120);
+ var text3 = core.itemCount('pickaxe') + '/' + core.itemCount('bomb') + '/' +
+ core.itemCount('centerFly');
+ if (core.hasFlag('poison')) text3 += "/毒";
+ if (core.hasFlag('weak')) text3 += "/衰";
+ if (core.hasFlag('curse')) text3 += "/咒";
+ core.fillText(this.canvas, text3, this.offsetX + 60, 410, '#FF7F00', '11px Verdana', 120);
+ if(this.selectedItem) {
+ var rect = this.itemRect(this.selectedIndex);
+ core.strokeRect(this.canvas, rect.x, rect.y, rect.w, rect.h, '#FF7F00', 4);
+ }
+}
+
+dynamicMapEditor.prototype.showInitHelp = function () {
+ if (main.mode != 'play' || core.getLocalStorage('_dynamicMapEditor_init')) return;
+ var text = "新拓展:运行时动态编辑地图!\n\n在此状态下你可以一边游戏一边编辑地图或者修改数据。\n\n";
+ text += "进游戏后按 [ 键可以激活,快来尝试吧!\n\n";
+ text += "点取消后将不再提示本页面。";
+ core.myconfirm(text, null, function () {
+ core.setLocalStorage('_dynamicMapEditor_init', true);
+ if (core.firstData.name != 'template') {
+ localStorage.removeItem('template__dynamicMapEditor_init');
+ localStorage.removeItem('template__dynamicMapEditor_help');
+ }
+ });
+}
+
+dynamicMapEditor.prototype.showHelp = function (fromButton) {
+ if (main.mode != 'play' || (!fromButton && core.getLocalStorage('_dynamicMapEditor_help'))) return;
+ var text = "欢迎使用黄鸡编写的运行时编辑拓展!你可以一边游戏一边编辑地图或者修改数据。\n\n";
+ text += "基本操作:\n - 点击图块再点地图可以放置;\n - 双击图块可以编辑数据;\n";
+ text += " - [ 键将开关此模式;\n - ] 键将会把改动保存到文件;\n - \\ 键将撤销上步操作。\n";
+ text += " - Alt+0~9 保存当前图块 \n - 0~9 读取当前图块\n";
+ text += "最下面三行数据分别是:\n"
+ text += "血攻防护盾;金经黄蓝红;破炸飞和debuff。";
+ if (!fromButton) text += "\n\n点取消将不再提示本页面。";
+ core.myconfirm(text, null, function () {
+ if (!fromButton) core.setLocalStorage("_dynamicMapEditor_help", true);
+ })
+}
+
+// ------ save
+
+dynamicMapEditor.prototype.applyCurrentChange = function() {
+ this.saveEnemys();
+ this.saveValues();
+ this.saveFloors();
+ this.enemyModified = false;
+ this.valueModified = false;
+ this.mapRecord = {};
+ core.drawTip('已将所有改动应用到文件,记得刷新编辑器哦');
+}
+
+dynamicMapEditor.prototype.saveEnemys = function () {
+ if (!this.enemyModified) return;
+ core.enemys.enemys = core.clone(core.material.enemys);
+ var datastr = 'var enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 = \n';
+ var emap = {};
+ var estr = JSON.stringify(core.enemys.enemys, function (k, v) {
+ var t = core.clone(v);
+ if (t.hp != null) {
+ delete t.id;
+ var id_ = ":" + k + ":";
+ emap[id_] = JSON.stringify(t);
+ return id_;
+ } else return t;
+ }, '\t');
+ for (var id_ in emap) {
+ estr = estr.replace('"' + id_ + '"', emap[id_])
+ }
+ datastr += estr;
+ fs.writeFile('project/enemys.js', core.encodeBase64(datastr), 'base64', function (e, d) {});
+}
+
+dynamicMapEditor.prototype.saveValues = function () {
+ if (!this.valueModified) return;
+ core.data.values = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.values = core.clone(core.values);
+ var datastr = 'var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = \n' +
+ JSON.stringify(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d, null, '\t');
+ fs.writeFile('project/data.js', core.encodeBase64(datastr), 'base64', function (e, d) {});
+}
+
+dynamicMapEditor.prototype.saveFloors = function () {
+ if (Object.keys(this.mapRecord).length == 0) return;
+ core.initStatus.maps = core.maps._initMaps();
+ for (var floorId in this.mapRecord) {
+ if (this.mapRecord[floorId]) {
+ this.saveFloor(floorId);
+ }
+ }
+}
+
+dynamicMapEditor.prototype.saveFloor = function (floorId) {
+ var floorData = core.floors[floorId];
+ var filename = 'project/floors/' + floorId + '.js';
+ var datastr = ['main.floors.', floorId, '=\n'];
+
+ var tempJsonObj = core.clone(floorData);
+ var tempMap = [['map', ':map:'], ['bgmap', ':bgmap:'], ['fgmap', ':fgmap:']];
+ tempMap.forEach(function (v) {
+ v[2] = tempJsonObj[v[0]];
+ tempJsonObj[v[0]] = v[1];
+ });
+ var tempJson = JSON.stringify(tempJsonObj, null, 4);
+ tempMap.forEach(function (v) {
+ tempJson = tempJson.replace('"' + v[1] + '"', '[\n' + this.formatMap(v[2], v[0] != 'map') + '\n]')
+ }, this);
+ datastr = datastr.concat([tempJson]);
+ datastr = datastr.join('');
+ fs.writeFile(filename, core.encodeBase64(datastr), 'base64', function (e, d) {});
+}
+
+dynamicMapEditor.prototype.formatMap = function (mapArr, trySimplify) {
+ if (!mapArr || JSON.stringify(mapArr) == JSON.stringify([])) return '';
+ if (trySimplify) {
+ //检查是否是全0二维数组
+ var jsoncheck = JSON.stringify(mapArr).replace(/\D/g, '');
+ if (jsoncheck == Array(jsoncheck.length + 1).join('0')) return '';
+ }
+ //把二维数组格式化
+ var formatArrStr = '';
+ var si = mapArr.length - 1, sk = mapArr[0].length - 1;
+ for (var i = 0; i <= si; i++) {
+ formatArrStr += ' [';
+ for (var k = 0; k <= sk; k++) {
+ var num = parseInt(mapArr[i][k]);
+ formatArrStr += Array(Math.max(4 - String(num).length, 0)).join(' ') + num + (k == sk ? '' : ',');
+ }
+ formatArrStr += ']' + (i == si ? '' : ',\n');
+ }
+ return formatArrStr;
+}
+
+// ------ rewrite
+
+var dynamicMapEditor = new dynamicMapEditor();
+
+dynamicMapEditor._resize_statusBar = core.control._resize_statusBar;
+core.control._resize_statusBar = function (obj) {
+ dynamicMapEditor._resize_statusBar.call(this,obj);
+ dynamicMapEditor.refreshToolBox();
+}
+
+dynamicMapEditor.updateStatusBar = core.control.updateStatusBar;
+core.control.updateStatusBar = function () {
+ dynamicMapEditor.refreshToolBox();
+ dynamicMapEditor.updateStatusBar.apply(core.control, Array.prototype.slice.call(arguments));
+}
\ No newline at end of file
diff --git a/extensions/localSave.js b/extensions/localSave.js
new file mode 100644
index 0000000..061d5c1
--- /dev/null
+++ b/extensions/localSave.js
@@ -0,0 +1,110 @@
+/**
+ * 离线游戏使用本地存储扩展。
+ * 开启本拓展后,将会把所有存档存至 _saves 目录下。
+ * 需配合样板V2.8.2+使用
+ */
+
+"use strict";
+
+(function () {
+ // 将这一行改成 false 可以禁用本拓展
+ var __enabled = true;
+
+ if (window.jsinterface || !window.fs || !__enabled) return;
+
+ function rewrite() {
+ core.utils._setLocalForage_set = function (name, str, callback) {
+ var data = LZString.compressToBase64(str);
+ core.saves.cache[name] = data;
+ fs.writeFile('_saves/' + name, data, 'utf-8', callback);
+ }
+
+ core.utils._getLocalForage_get = function (name, callback) {
+ fs.readFile('_saves/' + name, 'utf-8', function (err, data) {
+ if (err) return callback(err);
+ callback(null, data);
+ });
+ }
+
+ core.utils.decompress = function (data) {
+ try {
+ return JSON.parse(LZString.decompressFromBase64(data))
+ } catch (e) {
+ return null;
+ }
+ }
+
+ core.utils._removeLocalForage_remove = function (name, callback) {
+ fs.deleteFile('_saves/' + name, callback);
+ }
+
+ core.utils.clearLocalForage = function (callback) {
+ fs.deleteFile('_saves', function () {
+ fs.mkdir('_saves', callback);
+ })
+ }
+
+ core.utils.iterateLocalForage = function (iter, callback) {
+ fs.readdir('_saves', function (err, data) {
+ if (err) callback(err);
+ else {
+ data.forEach(function (one) {
+ iter(null, one, null);
+ });
+ callback();
+ }
+ });
+ }
+
+ core.utils.keysLocalForage = function (callback) {
+ fs.readdir('_saves', callback);
+ }
+
+ core.utils.lengthLocalForage = function (callback) {
+ fs.readdir('_saves', function (err, data) {
+ if (err) callback(err);
+ else callback(null, data.length);
+ });
+ }
+ }
+
+
+ var _export = function () {
+ var toExport = [];
+
+ localforage.iterate(function (value, key, n) {
+ if (value == null || !key.startsWith(core.firstData.name)) return;
+ value = core.decompress(value);
+ if (value == null) return;
+ var str = JSON.stringify(value).replace(/[\u007F-\uFFFF]/g, function (chr) {
+ return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4)
+ });
+ str = LZString.compressToBase64(str);
+ toExport.push(key);
+ core.saves.cache[key] = str;
+ fs.writeFile('_saves/' + key, str, 'utf-8', function () {});
+ }, function () {
+ if (toExport.length > 0) {
+ alert('提示!本塔已开启存档本地化!原始存档已全部导出至 _saves/ 目录下。');
+ }
+ fs.writeFile('_saves/.exported', '1', 'utf-8', function () {});
+ rewrite();
+ core.control.getSaveIndexes(function (indexes) { core.saves.ids = indexes; });
+ });
+ }
+
+ fs.mkdir('_saves', function (err) {
+ if (err) return;
+
+ fs.readFile('_saves/.exported', 'utf-8', function(err, data) {
+ if (!err && data) {
+ rewrite();
+ core.control.getSaveIndexes(function (indexes) { core.saves.ids = indexes; });
+ return;
+ }
+ _export();
+ });
+ });
+})();
+
+
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..8db0234
--- /dev/null
+++ b/index.html
@@ -0,0 +1,204 @@
+
+
+
+
+
+
+
+
+ HTML5魔塔
+
+
+
+
+
+
+
+
+
+
+
+
+
+
![]()
+
+
+
+
+
请稍候...
+
![]()
+
+
+
+
资源即将开始加载
+
HTML5魔塔游戏平台,享受更多魔塔游戏:
https://h5mota.com/
+
+
![]()
+
+
+
+
+
+
+
![]()
+
+
+
+
![]()
+
+
+
+
![]()
+
+
+
+
![]()
+
+
+
+
![]()
+
+
+
+
![]()
+
+
+
+
![]()
+
+
+
+
![]()
+
+
+
+
![]()
+
+
+
+
![]()
+
+
+
+
![]()
+
+
+
+
![]()
+
+
+
+
![]()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/actions.js b/libs/actions.js
new file mode 100644
index 0000000..e25afb8
--- /dev/null
+++ b/libs/actions.js
@@ -0,0 +1,3165 @@
+
+/*
+actions.js:用户交互的事件的处理
+键盘、鼠标、触摸屏事件相关
+ */
+
+"use strict";
+
+function actions () {
+ this._init();
+ this._HX_ = core._HALF_WIDTH_;
+ this._HY_ = core._HALF_HEIGHT_;
+ this._out = function (x) { return x < this._HX_ - 2 || this._HX_ + 2 < x; };
+ this.LAST = core._WIDTH_ - 1;
+}
+
+actions.prototype._init = function () {
+ this.actionsdata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.actions;
+ this.actions = {};
+ // --- onkeyDown注册
+ this.registerAction('onkeyDown', '_sys_checkReplay', this._sys_checkReplay, 100);
+ this.registerAction('onkeyDown', '_sys_onkeyDown', this._sys_onkeyDown, 0);
+ // --- onkeyUp注册
+ this.registerAction('onkeyUp', '_sys_onkeyUp_replay', this._sys_onkeyUp_replay, 100);
+ this.registerAction('onkeyUp', '_sys_onkeyUp', this._sys_onkeyUp, 0);
+ // --- pressKey注册
+ this.registerAction('pressKey', '_sys_checkReplay', this._sys_checkReplay, 100);
+ this.registerAction('pressKey', '_sys_pressKey', this._sys_pressKey, 0);
+ // --- keyDown注册
+ this.registerAction('keyDown', '_sys_checkReplay', this._sys_checkReplay, 100);
+ this.registerAction('keyDown', '_sys_keyDown_lockControl', this._sys_keyDown_lockControl, 50);
+ this.registerAction('keyDown', '_sys_keyDown', this._sys_keyDown, 0);
+ // --- keyUp注册
+ this.registerAction('keyUp', '_sys_keyUp_replay', this._sys_keyUp_replay, 100);
+ this.registerAction('keyUp', '_sys_keyUp_lockControl', this._sys_keyUp_lockControl, 50);
+ this.registerAction('keyUp', '_sys_keyUp', this._sys_keyUp, 0);
+ // --- ondown注册
+ this.registerAction('ondown', '_sys_checkReplay', this._sys_checkReplay, 100);
+ this.registerAction('ondown', '_sys_ondown_lockControl', this._sys_ondown_lockControl, 30);
+ this.registerAction('ondown', '_sys_ondown', this._sys_ondown, 0);
+ // --- onmove注册
+ this.registerAction('onmove', '_sys_checkReplay', this._sys_checkReplay, 100);
+ this.registerAction('onmove', '_sys_onmove_choices', this._sys_onmove_choices, 30);
+ this.registerAction('onmove', '_sys_onmove', this._sys_onmove, 0);
+ // --- onup注册
+ this.registerAction('onup', '_sys_checkReplay', this._sys_checkReplay, 100);
+ this.registerAction('onup', '_sys_onup', this._sys_onup, 0);
+ // --- onclick已废弃,将视为ondown
+ // --- onmousewheel注册
+ this.registerAction('onmousewheel', '_sys_onmousewheel', this._sys_onmousewheel, 0);
+ // --- keyDownCtrl注册
+ this.registerAction('keyDownCtrl', '_sys_keyDownCtrl', this._sys_keyDownCtrl, 0);
+ // --- longClick注册
+ this.registerAction('longClick', '_sys_longClick_lockControl', this._sys_longClick_lockControl, 50);
+ // --- onStatusBarClick注册
+ this.registerAction('onStatusBarClick', '_sys_onStatusBarClick', this._sys_onStatusBarClick, 0);
+
+}
+
+////// 注册一个用户交互行为 //////
+/*
+ * 此函数将注册一个用户交互行为。
+ * action:要注册的交互类型,如 ondown, onup, keyDown 等等。
+ * name:你的自定义名称,可被注销使用;同名重复注册将后者覆盖前者。
+ * func:执行函数。
+ * priority:优先级;优先级高的将会被执行。此项可不填,默认为0。
+ * 返回:如果func返回true,则不会再继续执行其他的交互函数;否则会继续执行其他的交互函数。
+ */
+actions.prototype.registerAction = function (action, name, func, priority) {
+ if (!name || !func)
+ return;
+ // 将onclick视为ondown处理
+ if (action == 'onclick') action = 'ondown';
+ priority = priority || 0;
+ if (!this.actions[action]) {
+ this.actions[action] = [];
+ }
+ this.unregisterAction(action, name);
+ this.actions[action].push(
+ { "action": action, "name": name, "func": func, "priority": priority }
+ );
+ this.actions[action] = this.actions[action].sort(function (a, b) {
+ return b.priority - a.priority;
+ });
+}
+
+////// 注销一个用户交互行为 //////
+actions.prototype.unregisterAction = function (action, name) {
+ // 将onclick视为ondown处理
+ if (action == 'onclick') action = 'ondown';
+ if (!this.actions[action]) return;
+ this.actions[action] = this.actions[action].filter(function (x) {
+ return x.name != name;
+ });
+}
+
+////// 执行一个用户交互行为 //////
+actions.prototype.doRegisteredAction = function (action) {
+ var actions = this.actions[action];
+ if (!actions) return false;
+ for (var i = 0; i < actions.length; ++i) {
+ try {
+ if (core.doFunc.apply(core, [actions[i].func, this].concat(Array.prototype.slice.call(arguments, 1))))
+ return true;
+ }
+ catch (e) {
+ console.error(e);
+ console.error("ERROR in actions[" + actions[i].name + "].");
+ }
+ }
+ return false;
+}
+
+actions.prototype._checkReplaying = function () {
+ if (core.isReplaying() &&
+ ['save', 'book', 'book-detail', 'viewMaps', 'toolbox', 'equipbox', 'text'].indexOf(core.status.event.id) < 0)
+ return true;
+ return false;
+}
+
+////// 检查是否在录像播放中,如果是,则停止交互
+actions.prototype._sys_checkReplay = function () {
+ if (this._checkReplaying()) return true;
+}
+
+////// 检查左手模式
+actions.prototype.__checkLeftHandPrefer = function (e) {
+ if (!core.flags.leftHandPrefer) return e;
+ var map = {
+ 87: 38, // W -> up
+ 83: 40, // S -> down
+ 65: 37, // A -> left
+ 68: 39, // D -> right
+ 73: 87, // I -> W
+ 74: 65, // J -> A
+ 75: 83, // K -> S
+ 76: 68, // L -> D
+ }
+ var newEvent = {};
+ for (var one in e) {
+ if (!(e[one] instanceof Function)) {
+ newEvent[one] = e[one];
+ }
+ };
+ ["stopPropagation", "stopImmediatePropagation", "preventDefault"].forEach(function (one) {
+ newEvent[one] = function () {
+ return e[one]();
+ }
+ });
+ newEvent.keyCode = map[e.keyCode] || e.keyCode;
+ return newEvent;
+}
+
+////// 按下某个键时 //////
+actions.prototype.onkeyDown = function (e) {
+ this.doRegisteredAction('onkeyDown', this.__checkLeftHandPrefer(e));
+}
+
+actions.prototype._sys_onkeyDown = function (e) {
+ core.status.holdingKeys = core.status.holdingKeys || []
+ var isArrow = { 37: true, 38: true, 39: true, 40: true }[e.keyCode]
+ if (isArrow && !core.status.lockControl) {
+ for (var ii = 0; ii < core.status.holdingKeys.length; ii++) {
+ if (core.status.holdingKeys[ii] === e.keyCode) {
+ return;
+ }
+ }
+ if (e.preventDefault) e.preventDefault();
+ core.status.holdingKeys.push(e.keyCode);
+ this.pressKey(e.keyCode);
+ } else {
+ if (e.keyCode == 17) core.status.ctrlDown = true;
+ this.keyDown(e.keyCode);
+ }
+}
+
+////// 放开某个键时 //////
+actions.prototype.onkeyUp = function (e) {
+ this.doRegisteredAction('onkeyUp', this.__checkLeftHandPrefer(e));
+}
+
+actions.prototype._sys_onkeyUp_replay = function (e) {
+ if (this._checkReplaying()) {
+ if (e.keyCode == 27) // ESCAPE
+ core.stopReplay();
+ else if (e.keyCode == 90) // Z
+ core.speedDownReplay();
+ else if (e.keyCode == 67) // C
+ core.speedUpReplay();
+ else if (e.keyCode == 32) // SPACE
+ core.triggerReplay();
+ else if (e.keyCode == 65) // A
+ core.rewindReplay();
+ else if (e.keyCode == 83) // S
+ core.control._replay_SL();
+ else if (e.keyCode == 88) // X
+ core.control._replay_book();
+ else if (e.keyCode == 33 || e.keyCode == 34) // PgUp/PgDn
+ core.control._replay_viewMap();
+ else if (e.keyCode == 78) // N
+ core.stepReplay();
+ else if (e.keyCode == 84) // T
+ core.control._replay_toolbox();
+ else if (e.keyCode == 81) // Q
+ core.control._replay_equipbox();
+ else if (e.keyCode == 66) // B
+ core.ui._drawStatistics();
+ else if (e.keyCode >= 49 && e.keyCode <= 51) // 1-3
+ core.setReplaySpeed(e.keyCode - 48);
+ else if (e.keyCode == 52) // 4
+ core.setReplaySpeed(6);
+ else if (e.keyCode == 53) // 5
+ core.setReplaySpeed(12);
+ else if (e.keyCode == 54) // 6
+ core.setReplaySpeed(24);
+ return true;
+ }
+}
+
+actions.prototype._sys_onkeyUp = function (e) {
+ var isArrow = { 37: true, 38: true, 39: true, 40: true }[e.keyCode]
+ if (isArrow && !core.status.lockControl) {
+ for (var ii = 0; ii < core.status.holdingKeys.length; ii++) {
+ if (core.status.holdingKeys[ii] === e.keyCode) {
+ core.status.holdingKeys = core.status.holdingKeys.slice(0, ii).concat(core.status.holdingKeys.slice(ii + 1));
+ if (ii === core.status.holdingKeys.length && core.status.holdingKeys.length !== 0) core.pressKey(core.status.holdingKeys.slice(-1)[0]);
+ break;
+ }
+ }
+ if (e.preventDefault) e.preventDefault();
+ this.keyUp(e.keyCode, e.altKey);
+ } else {
+ if (e.keyCode == 17) core.status.ctrlDown = false;
+ this.keyUp(e.keyCode, e.altKey);
+ }
+}
+
+////// 按住某个键时 //////
+actions.prototype.pressKey = function (keyCode) {
+ this.doRegisteredAction('pressKey', keyCode);
+}
+
+actions.prototype._sys_pressKey = function (keyCode) {
+ if (keyCode === core.status.holdingKeys.slice(-1)[0]) {
+ this.keyDown(keyCode);
+ window.setTimeout(function () {
+ core.pressKey(keyCode);
+ }, 30);
+ }
+}
+
+////// 根据按下键的code来执行一系列操作 //////
+actions.prototype.keyDown = function (keyCode) {
+ this.doRegisteredAction('keyDown', keyCode);
+}
+
+actions.prototype._sys_keyDown_lockControl = function (keyCode) {
+ if (!core.status.lockControl) return false;
+ // Ctrl跳过对话
+ if (keyCode == 17) {
+ this.keyDownCtrl();
+ return true;
+ }
+ switch (core.status.event.id) {
+ case 'action':
+ this._keyDownAction(keyCode);
+ break;
+ case 'book':
+ this._keyDownBook(keyCode);
+ break;
+ case 'fly':
+ this._keyDownFly(keyCode);
+ break;
+ case 'viewMaps':
+ this._keyDownViewMaps(keyCode);
+ break;
+ case 'equipbox':
+ this._keyDownEquipbox(keyCode);
+ break;
+ case 'toolbox':
+ this._keyDownToolbox(keyCode);
+ break;
+ case 'save':
+ case 'load':
+ case 'replayLoad':
+ case 'replayRemain':
+ case 'replaySince':
+ this._keyDownSL(keyCode);
+ break;
+ case 'selectShop':
+ case 'switchs':
+ case 'switchs-sounds':
+ case 'switchs-display':
+ case 'switchs-action':
+ case 'notes':
+ case 'settings':
+ case 'syncSave':
+ case 'syncSelect':
+ case 'localSaveSelect':
+ case 'storageRemove':
+ case 'replay':
+ case 'gameInfo':
+ this._keyDownChoices(keyCode);
+ break;
+ case 'cursor':
+ this._keyDownCursor(keyCode);
+ break;
+ }
+ return true;
+}
+
+actions.prototype._sys_keyDown = function (keyCode) {
+ if (!core.status.played)
+ return true;
+ switch (keyCode) {
+ case 37:
+ core.moveHero('left');
+ break;
+ case 38:
+ core.moveHero('up');
+ break;
+ case 39:
+ core.moveHero('right');
+ break;
+ case 40:
+ core.moveHero('down');
+ break;
+ }
+ return true;
+}
+
+////// 根据放开键的code来执行一系列操作 //////
+actions.prototype.keyUp = function (keyCode, altKey, fromReplay) {
+ this.doRegisteredAction('keyUp', keyCode, altKey, fromReplay);
+}
+
+actions.prototype._sys_keyUp_replay = function (keyCode, altKey, fromReplay) {
+ if (!fromReplay && this._checkReplaying()) return true;
+}
+
+actions.prototype._sys_keyUp_lockControl = function (keyCode, altKey) {
+ if (!core.status.lockControl) return false;
+
+ var ok = function () {
+ return keyCode == 27 || keyCode == 88 || keyCode == 13 || keyCode == 32 || keyCode == 67;
+ }
+
+ core.status.holdingKeys = [];
+ switch (core.status.event.id) {
+ case 'text':
+ ok() && core.drawText();
+ break;
+ case 'confirmBox':
+ this._keyUpConfirmBox(keyCode);
+ break;
+ case 'action':
+ this._keyUpAction(keyCode);
+ break;
+ case 'about':
+ ok() && core.closePanel();
+ break;
+ case 'help':
+ ok() && core.closePanel();
+ break;
+ case 'book':
+ this._keyUpBook(keyCode);
+ break;
+ case 'book-detail':
+ ok() && this._clickBookDetail();
+ break;
+ case 'fly':
+ this._keyUpFly(keyCode);
+ break;
+ case 'viewMaps':
+ this._keyUpViewMaps(keyCode);
+ break;
+ case 'selectShop':
+ this._keyUpQuickShop(keyCode);
+ break;
+ case 'toolbox':
+ this._keyUpToolbox(keyCode);
+ break;
+ case 'equipbox':
+ this._keyUpEquipbox(keyCode, altKey);
+ break;
+ case 'save':
+ case 'load':
+ case 'replayLoad':
+ case 'replayRemain':
+ case 'replaySince':
+ this._keyUpSL(keyCode);
+ break;
+ case 'keyBoard':
+ ok() && core.closePanel();
+ break;
+ case 'switchs':
+ this._keyUpSwitchs(keyCode);
+ break;
+ case 'switchs-sounds':
+ this._keyUpSwitchs_sounds(keyCode);
+ break;
+ case 'switchs-display':
+ this._keyUpSwitchs_display(keyCode);
+ break;
+ case 'switchs-action':
+ this._keyUpSwitchs_action(keyCode);
+ break;
+ case 'settings':
+ this._keyUpSettings(keyCode);
+ break;
+ case 'notes':
+ this._keyUpNotes(keyCode);
+ break;
+ case 'syncSave':
+ this._keyUpSyncSave(keyCode);
+ break;
+ case 'syncSelect':
+ this._keyUpSyncSelect(keyCode);
+ break;
+ case 'localSaveSelect':
+ this._keyUpLocalSaveSelect(keyCode);
+ break;
+ case 'storageRemove':
+ this._keyUpStorageRemove(keyCode);
+ break;
+ case 'cursor':
+ this._keyUpCursor(keyCode);
+ break;
+ case 'replay':
+ this._keyUpReplay(keyCode);
+ break;
+ case 'gameInfo':
+ this._keyUpGameInfo(keyCode);
+ break;
+ case 'centerFly':
+ this._keyUpCenterFly(keyCode);
+ break;
+ }
+ return true;
+}
+
+actions.prototype._sys_keyUp = function (keyCode, altKey) {
+ if (!core.status.played)
+ return true;
+ this.actionsdata.onKeyUp(keyCode, altKey);
+ if (core.status.automaticRoute && core.status.automaticRoute.autoHeroMove) {
+ core.stopAutomaticRoute();
+ }
+ core.status.heroStop = true;
+ return true;
+}
+
+////// 点击(触摸)事件按下时 //////
+actions.prototype.ondown = function (loc) {
+ var x = parseInt(loc.x / loc.size), y = parseInt(loc.y / loc.size);
+ var px = parseInt(loc.x / core.domStyle.scale), py = parseInt(loc.y / core.domStyle.scale);
+ this.doRegisteredAction('ondown', x, y, px, py);
+}
+
+actions.prototype._sys_ondown_lockControl = function (x, y, px, py) {
+ if (core.status.played && !core.status.lockControl) return false;
+
+ switch (core.status.event.id) {
+ case 'centerFly':
+ this._clickCenterFly(x, y, px, py);
+ break;
+ case 'book':
+ this._clickBook(x, y, px, py);
+ break;
+ case 'book-detail':
+ this._clickBookDetail(x, y, px, py);
+ break;
+ case 'fly':
+ this._clickFly(x, y, px, py);
+ break;
+ case 'viewMaps':
+ this._clickViewMaps(x, y, px, py);
+ break;
+ case 'switchs':
+ this._clickSwitchs(x, y, px, py);
+ break;
+ case 'switchs-sounds':
+ this._clickSwitchs_sounds(x, y, px, py);
+ break;
+ case 'switchs-display':
+ this._clickSwitchs_display(x, y, px, py);
+ break;
+ case 'switchs-action':
+ this._clickSwitchs_action(x, y, px, py);
+ break;
+ case 'settings':
+ this._clickSettings(x, y, px, py);
+ break;
+ case 'selectShop':
+ this._clickQuickShop(x, y, px, py);
+ break;
+ case 'equipbox':
+ this._clickEquipbox(x, y, px, py);
+ break;
+ case 'toolbox':
+ this._clickToolbox(x, y, px, py);
+ break;
+ case 'save':
+ case 'load':
+ case 'replayLoad':
+ case 'replayRemain':
+ case 'replaySince':
+ this._clickSL(x, y, px, py);
+ break;
+ case 'confirmBox':
+ this._clickConfirmBox(x, y, px, py);
+ break;
+ case 'keyBoard':
+ this._clickKeyBoard(x, y, px, py);
+ break;
+ case 'action':
+ this._clickAction(x, y, px, py);
+ break;
+ case 'text':
+ core.drawText();
+ break;
+ case 'notes':
+ this._clickNotes(x, y, px, py);
+ break;
+ case 'syncSave':
+ this._clickSyncSave(x, y, px, py);
+ break;
+ case 'syncSelect':
+ this._clickSyncSelect(x, y, px, py);
+ break;
+ case 'localSaveSelect':
+ this._clickLocalSaveSelect(x, y, px, py);
+ break;
+ case 'storageRemove':
+ this._clickStorageRemove(x, y, px, py);
+ break;
+ case 'cursor':
+ this._clickCursor(x, y, px, py);
+ break;
+ case 'replay':
+ this._clickReplay(x, y, px, py);
+ break;
+ case 'gameInfo':
+ this._clickGameInfo(x, y, px, py);
+ break;
+ case 'about':
+ case 'help':
+ core.ui.closePanel();
+ break;
+ }
+
+ // --- 长按判定
+ if (core.timeout.onDownTimeout == null) {
+ core.timeout.onDownTimeout = setTimeout(function () {
+ if (core.interval.onDownInterval == null) {
+ core.interval.onDownInterval = setInterval(function () {
+ if (!core.actions.longClick(x, y, px, py)) {
+ clearInterval(core.interval.onDownInterval);
+ core.interval.onDownInterval = null;
+ }
+ }, 40)
+ }
+ }, 500);
+ }
+ return true;
+}
+
+actions.prototype._sys_ondown = function (x, y, px, py) {
+ if (core.status.lockControl) return false;
+ core.status.downTime = new Date();
+ core.deleteCanvas('route');
+ var pos = { 'x': parseInt((px + core.bigmap.offsetX) / 32), 'y': parseInt((py + core.bigmap.offsetY) / 32) };
+ core.status.stepPostfix = [];
+ core.status.stepPostfix.push(pos);
+ core.fillRect('ui', pos.x * 32 + 12 - core.bigmap.offsetX, pos.y * 32 + 12 - core.bigmap.offsetY, 8, 8, '#bfbfbf');
+
+ clearTimeout(core.timeout.onDownTimeout);
+ core.timeout.onDownTimeout = null;
+ core.status.preview.prepareDragging = false;
+ if (!core.hasFlag('__lockViewport__') && (core.status.thisMap.width > core._WIDTH_ || core.status.thisMap.height > core._HEIGHT_)) {
+ core.status.preview.prepareDragging = true;
+ core.status.preview.px = px;
+ core.status.preview.py = py;
+ core.timeout.onDownTimeout = setTimeout(function () {
+ core.clearMap('ui');
+ core.status.preview.prepareDragging = false;
+ core.status.preview.enabled = true;
+ core.status.preview.dragging = true;
+ core.drawTip('已进入预览模式,可直接拖动大地图');
+ core.status.stepPostfix = [];
+ }, 500);
+ }
+}
+
+////// 当在触摸屏上滑动时 //////
+actions.prototype.onmove = function (loc) {
+ var x = parseInt(loc.x / loc.size), y = parseInt(loc.y / loc.size);
+ var px = parseInt(loc.x / core.domStyle.scale), py = parseInt(loc.y / core.domStyle.scale);
+ this.doRegisteredAction('onmove', x, y, px, py);
+}
+
+actions.prototype._sys_onmove_choices = function (x, y, px, py) {
+ if (!core.status.lockControl) return false;
+
+ switch (core.status.event.id) {
+ case 'action':
+ if (core.status.event.data.type == 'choices') {
+ this._onMoveChoices(x, y);
+ return true;
+ }
+ if (core.status.event.data.type == 'confirm') {
+ this._onMoveConfirmBox(x, y, px, py);
+ return true;
+ }
+ break;
+ case 'selectShop':
+ case 'switchs':
+ case 'switchs-sounds':
+ case 'switchs-display':
+ case 'switchs-action':
+ case 'notes':
+ case 'settings':
+ case 'syncSave':
+ case 'syncSelect':
+ case 'localSaveSelect':
+ case 'storageRemove':
+ case 'replay':
+ case 'gameInfo':
+ this._onMoveChoices(x, y);
+ return true;
+ case 'confirmBox':
+ this._onMoveConfirmBox(x, y, px, py);
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+actions.prototype._sys_onmove = function (x, y, px, py) {
+ if (core.status.lockControl) return false;
+
+ if (core.status.preview.dragging) {
+ core.setViewport(core.bigmap.offsetX - px + core.status.preview.px, core.bigmap.offsetY - py + core.status.preview.py);
+ core.status.preview.px = px;
+ core.status.preview.py = py;
+ return true;
+ }
+ if (core.status.preview.prepareDragging) {
+ if (Math.abs(px - core.status.preview.px) <= 20 && Math.abs(py - core.status.preview.py) <= 20)
+ return true;
+ else core.status.preview.prepareDragging = false;
+ }
+
+ clearTimeout(core.timeout.onDownTimeout);
+ core.timeout.onDownTimeout = null;
+
+ if ((core.status.stepPostfix || []).length > 0) {
+ var pos = { 'x': parseInt((px + core.bigmap.offsetX) / 32), 'y': parseInt((py + core.bigmap.offsetY) / 32) };
+ var pos0 = core.status.stepPostfix[core.status.stepPostfix.length - 1];
+ var directionDistance = [pos.y - pos0.y, pos0.x - pos.x, pos0.y - pos.y, pos.x - pos0.x];
+ var max = 0, index = 4;
+ for (var ii = 0; ii < 4; ii++) {
+ if (directionDistance[ii] > max) {
+ index = ii;
+ max = directionDistance[ii];
+ }
+ }
+ pos = [{ 'x': 0, 'y': 1 }, { 'x': -1, 'y': 0 }, { 'x': 0, 'y': -1 }, { 'x': 1, 'y': 0 }, false][index]
+ if (pos) {
+ pos.x += pos0.x;
+ pos.y += pos0.y;
+ core.status.stepPostfix.push(pos);
+ core.fillRect('ui', pos.x * 32 + 12 - core.bigmap.offsetX, pos.y * 32 + 12 - core.bigmap.offsetY, 8, 8, '#bfbfbf');
+ }
+ }
+ return true;
+}
+
+////// 当点击(触摸)事件放开时 //////
+actions.prototype.onup = function (loc) {
+ var x = parseInt(loc.x / loc.size), y = parseInt(loc.y / loc.size);
+ var px = parseInt(loc.x / core.domStyle.scale), py = parseInt(loc.y / core.domStyle.scale);
+ this.doRegisteredAction('onup', x, y, px, py);
+}
+
+actions.prototype._sys_onup = function (x, y, px, py) {
+ clearTimeout(core.timeout.onDownTimeout);
+ core.timeout.onDownTimeout = null;
+ clearInterval(core.interval.onDownInterval);
+ core.interval.onDownInterval = null;
+
+ if (core.isPlaying()) {
+ core.status.preview.prepareDragging = false;
+ if (core.status.preview.dragging) {
+ core.status.preview.dragging = false;
+ return true;
+ }
+ }
+
+ if ((core.status.stepPostfix || []).length == 0) return false;
+
+ var stepPostfix = [];
+ var direction = { '0': { '1': 'down', '-1': 'up' }, '-1': { '0': 'left' }, '1': { '0': 'right' } };
+ for (var ii = 1; ii < core.status.stepPostfix.length; ii++) {
+ var pos0 = core.status.stepPostfix[ii - 1];
+ var pos = core.status.stepPostfix[ii];
+ stepPostfix.push({
+ 'direction': direction[pos.x - pos0.x][pos.y - pos0.y],
+ 'x': pos.x,
+ 'y': pos.y
+ });
+ }
+ var posx = core.status.stepPostfix[0].x;
+ var posy = core.status.stepPostfix[0].y;
+ core.status.stepPostfix = [];
+ if (!core.status.lockControl) {
+ core.clearMap('ui');
+ }
+
+ // 长按
+ if (!core.status.lockControl && stepPostfix.length == 0 && core.status.downTime != null && new Date() - core.status.downTime >= 1000) {
+ core.actions.longClick(x, y, px, py);
+ }
+ else {
+ //posx,posy是寻路的目标点,stepPostfix是后续的移动
+ core.setAutomaticRoute(posx, posy, stepPostfix);
+ }
+ core.status.downTime = null;
+ return true;
+}
+
+////// 获得点击事件相对左上角的坐标 //////
+actions.prototype._getClickLoc = function (x, y) {
+
+ var statusBar = { 'x': 0, 'y': 0 };
+ var size = 32;
+ size = size * core.domStyle.scale;
+
+ if (core.domStyle.isVertical) {
+ statusBar.x = 3;
+ statusBar.y = core.dom.statusBar.offsetHeight + 3;
+ }
+ else {
+ statusBar.x = core.dom.statusBar.offsetWidth + 3;
+ statusBar.y = 3;
+ }
+
+ var left = core.dom.gameGroup.offsetLeft + statusBar.x;
+ var top = core.dom.gameGroup.offsetTop + statusBar.y;
+ var loc = { 'x': Math.max(x - left), 'y': Math.max(y - top, 0), 'size': size };
+ return loc;
+}
+
+
+////// 滑动鼠标滚轮时的操作 //////
+actions.prototype.onmousewheel = function (direct) {
+ this.doRegisteredAction('onmousewheel', direct);
+}
+
+actions.prototype._sys_onmousewheel = function (direct) {
+ // 向下滚动是 -1 ,向上是 1
+
+ if (this._checkReplaying()) {
+ // 滚轮控制速度
+ if (direct == 1) core.speedUpReplay();
+ if (direct == -1) core.speedDownReplay();
+ return;
+ }
+
+ // 楼层飞行器
+ if (core.status.lockControl && core.status.event.id == 'fly') {
+ if (direct == 1) core.ui.drawFly(this._getNextFlyFloor(1));
+ if (direct == -1) core.ui.drawFly(this._getNextFlyFloor(-1));
+ return;
+ }
+
+ // 怪物手册
+ if (core.status.lockControl && core.status.event.id == 'book') {
+ var pageinfo = core.ui._drawBook_pageinfo();
+ if (direct == 1) core.ui.drawBook(core.status.event.data - pageinfo.per_page);
+ if (direct == -1) core.ui.drawBook(core.status.event.data + pageinfo.per_page);
+ return;
+ }
+
+ // 存读档
+ if (core.status.lockControl && (core.status.event.id == 'save' || core.status.event.id == 'load')) {
+ var index = core.status.event.data.page * 10 + core.status.event.data.offset;
+ if (direct == 1) core.ui._drawSLPanel(index - 10);
+ if (direct == -1) core.ui._drawSLPanel(index + 10);
+ return;
+ }
+
+ // 浏览地图
+ if (core.status.lockControl && core.status.event.id == 'viewMaps') {
+ if (direct == 1) this._clickViewMaps(this._HX_, this._HY_ - 3, core._PX_ / 2, core._PY_ / 5 * 1.5);
+ if (direct == -1) this._clickViewMaps(this._HX_, this._HY_ + 3, core._PX_ / 2, core._PY_ / 5 * 3.5);
+ return;
+ }
+
+ // wait事件
+ if (core.status.lockControl && core.status.event.id == 'action' && core.status.event.data.type == 'wait') {
+ var timeout = Math.max(0, core.status.event.timeout - new Date().getTime()) || 0;
+ core.setFlag('type', 0);
+ var keycode = direct == 1 ? 33 : 34;
+ core.setFlag('keycode', keycode);
+ core.setFlag('timeout', timeout);
+ var executed = core.events.__action_wait_afterGet(core.status.event.data.current);
+ if (executed || !core.status.event.data.current.forceChild) {
+ core.status.route.push("input:" + (1e8 * timeout + keycode));
+ clearTimeout(core.status.event.interval);
+ delete core.status.event.timeout;
+ core.doAction();
+ }
+ return;
+ }
+
+}
+
+////// 长按Ctrl键时 //////
+actions.prototype.keyDownCtrl = function () {
+ this.doRegisteredAction('keyDownCtrl');
+}
+
+actions.prototype._sys_keyDownCtrl = function () {
+ if (core.status.event.id == 'text') {
+ core.drawText();
+ return true;
+ }
+ if (core.status.event.id == 'action' && core.status.event.data.type == 'text') {
+ core.doAction();
+ return true;
+ }
+ if (core.status.event.id == 'action' && core.status.event.data.type == 'sleep'
+ && !core.status.event.data.current.noSkip) {
+ if (core.timeout.sleepTimeout && !core.hasAsync()) {
+ clearTimeout(core.timeout.sleepTimeout);
+ core.timeout.sleepTimeout = null;
+ core.doAction();
+ }
+ return true;
+ }
+}
+
+////// 长按 //////
+actions.prototype.longClick = function (x, y, px, py) {
+ if (!core.isPlaying()) return false;
+ return this.doRegisteredAction('longClick', x, y, px, py);
+}
+
+actions.prototype._sys_longClick_lockControl = function (x, y, px, py) {
+ if (!core.status.lockControl) return false;
+ if (core.status.event.id == 'text') {
+ core.drawText();
+ return true;
+ }
+ if (core.status.event.id == 'action' && core.status.event.data.type == 'text') {
+ core.doAction();
+ return true;
+ }
+ // 长按楼传器的箭头可以快速翻页
+ if (core.status.event.id == 'fly') {
+ if ((x == core._WIDTH_ - 2 || x == core._WIDTH_ - 3) && (y == this._HY_ - 1 || y == this._HY_ + 3)) {
+ this._clickFly(x, y);
+ return true;
+ }
+ }
+ // 长按SL上下页快速翻页
+ if (["save", "load", "replayLoad", "replayRemain", "replaySince"].indexOf(core.status.event.id) >= 0) {
+ if ([this._HX_ - 2, this._HX_ - 3, this._HX_ + 2, this._HX_ + 3].indexOf(x) >= 0 && y===core._HEIGHT_-1) {
+ this._clickSL(x, y);
+ return true;
+ }
+ }
+ // 长按可以跳过等待事件
+ if (core.status.event.id == 'action' && core.status.event.data.type == 'sleep'
+ && !core.status.event.data.current.noSkip) {
+ if (core.timeout.sleepTimeout && !core.hasAsync()) {
+ clearTimeout(core.timeout.sleepTimeout);
+ core.timeout.sleepTimeout = null;
+ core.doAction();
+ return true;
+ }
+ }
+ return false;
+}
+
+actions.prototype.onStatusBarClick = function (e) {
+ if (!core.isPlaying()) return false;
+ var left = core.dom.gameGroup.offsetLeft + 3;
+ var top = core.dom.gameGroup.offsetTop + 3;
+ var px = parseInt((e.clientX - left) / core.domStyle.scale), py = parseInt((e.clientY - top) / core.domStyle.scale);
+ return this.doRegisteredAction('onStatusBarClick', Math.max(px, 0), Math.max(py, 0));
+}
+
+actions.prototype._sys_onStatusBarClick = function (px, py, vertical) {
+ if (this.actionsdata.onStatusBarClick)
+ return this.actionsdata.onStatusBarClick(px, py, vertical);
+}
+
+/////////////////// 在某个界面时的按键点击效果 ///////////////////
+
+actions.prototype._getChoicesTopIndex = function (length) {
+ return this._HY_ - parseInt((length - 1) / 2) + (core.status.event.ui.offset || 0);
+}
+
+// 数字键快速选择选项
+actions.prototype._selectChoices = function (length, keycode, callback) {
+ var topIndex = this._getChoicesTopIndex(length);
+ if (keycode == 13 || keycode == 32 || keycode == 67) {
+ callback.apply(this, [this._HX_, topIndex + core.status.event.selection]);
+ }
+
+ if (keycode >= 49 && keycode <= 57) {
+ var index = keycode - 49;
+ if (index < length) {
+ callback.apply(this, [this._HX_, topIndex + index]);
+ }
+ }
+}
+
+// 上下键调整选项
+actions.prototype._keyDownChoices = function (keycode) {
+ if (keycode == 38) {
+ core.status.event.selection--;
+ core.playSound('光标移动');
+ core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices, core.status.event.ui.width);
+ }
+ if (keycode == 40) {
+ core.status.event.selection++;
+ core.playSound('光标移动');
+ core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices, core.status.event.ui.width);
+ }
+}
+
+// 移动光标
+actions.prototype._onMoveChoices = function (x, y) {
+ if (this._out(x)) return;
+ var choices = core.status.event.ui.choices;
+ var topIndex = this._getChoicesTopIndex(choices.length);
+ if (y >= topIndex && y < topIndex + choices.length) {
+ var selection = y - topIndex;
+ if (selection == core.status.event.selection) return;
+ core.status.event.selection = selection;
+ core.playSound('光标移动');
+ core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices, core.status.event.ui.width);
+ }
+}
+
+////// 点击中心对称飞行器时
+actions.prototype._clickCenterFly = function (x, y) {
+ var posX = core.status.event.data.posX, posY = core.status.event.data.posY;
+ core.ui.closePanel();
+ if (x == posX && y == posY) {
+ if (core.canUseItem('centerFly')) {
+ core.useItem('centerFly');
+ }
+ else {
+ core.playSound('操作失败');
+ core.drawTip('当前不能使用' + core.material.items['centerFly'].name, 'centerFly');
+ }
+ }
+}
+
+actions.prototype._keyUpCenterFly = function (keycode) {
+ core.ui.closePanel();
+ if (keycode == 51 || keycode == 13 || keycode == 32 || keycode == 67) {
+ if (core.canUseItem('centerFly')) {
+ core.useItem('centerFly');
+ }
+ else {
+ core.playSound('操作失败');
+ core.drawTip('当前不能使用' + core.material.items['centerFly'].name, 'centerFly');
+ }
+ }
+}
+
+////// 点击确认框时 //////
+actions.prototype._clickConfirmBox = function (x, y, px, py) {
+ if (px >= core._PX_ / 2 - 70 && px <= core._PX_ / 2 - 10
+ && py >= core._PY_ / 2 && py <= core._PY_ / 2 + 64 && core.status.event.data.yes)
+ core.status.event.data.yes();
+ if (px >= core._PX_ / 2 + 10 && px <= core._PX_ / 2 + 70
+ && py >= core._PY_ / 2 && py <= core._PY_ / 2 + 64 && core.status.event.data.no)
+ core.status.event.data.no();
+}
+
+////// 键盘操作确认框时 //////
+actions.prototype._keyUpConfirmBox = function (keycode) {
+ if (keycode == 37 || keycode == 39) {
+ core.status.event.selection = 1 - core.status.event.selection;
+ core.playSound('光标移动');
+ core.ui.drawConfirmBox(core.status.event.ui, core.status.event.data.yes, core.status.event.data.no);
+ return;
+ }
+ if (keycode == 13 || keycode == 32 || keycode == 67) {
+ if (core.status.event.selection == 0 && core.status.event.data.yes) {
+ // core.playSound('确定');
+ core.status.event.selection = null;
+ core.status.event.data.yes();
+ return;
+ }
+ if (core.status.event.selection == 1 && core.status.event.data.no) {
+ // core.playSound('确定');
+ core.status.event.selection = null;
+ core.status.event.data.no();
+ return;
+ }
+ }
+}
+
+////// 鼠标在确认框上移动时 //////
+actions.prototype._onMoveConfirmBox = function (x, y, px, py) {
+ if (py >= core._PY_ / 2 && py <= core._PY_ / 2 + 64) {
+ if (px >= core._PX_ / 2 - 70 && px <= core._PX_ / 2 - 10) {
+ if (core.status.event.selection != 0) {
+ core.status.event.selection = 0;
+ core.playSound('光标移动');
+ if (core.status.event.id == 'action') {
+ core.ui.drawConfirmBox(core.status.event.ui.text);
+ } else {
+ core.ui.drawConfirmBox(core.status.event.ui, core.status.event.data.yes, core.status.event.data.no);
+ }
+ }
+ return;
+ }
+ if (px >= core._PX_ / 2 + 10 && px <= core._PX_ / 2 + 70) {
+ if (core.status.event.selection != 1) {
+ core.status.event.selection = 1;
+ core.playSound('光标移动');
+ if (core.status.event.id == 'action') {
+ core.ui.drawConfirmBox(core.status.event.ui.text);
+ } else {
+ core.ui.drawConfirmBox(core.status.event.ui, core.status.event.data.yes, core.status.event.data.no);
+ }
+ }
+ return;
+ }
+ }
+}
+
+actions.prototype._clickAction_text = function () {
+ // 正在淡入淡出的话不执行
+ if (core.status.event.animateUI) return;
+
+ var data = core.clone(core.status.event.data.current);
+ if (typeof data == 'string') data = { "type": "text", "text": data };
+
+ // 打字机效果显示全部文字
+ if (core.status.event.interval != null) {
+ data.showAll = true;
+ core.insertAction(data);
+ core.doAction();
+ return;
+ }
+
+ if (!data.code) {
+ core.ui._animateUI('hide', null, core.doAction);
+ } else {
+ // 不清除对话框
+ core.doAction();
+ }
+}
+
+////// 自定义事件时的点击操作 //////
+actions.prototype._clickAction = function (x, y, px, py) {
+ if (core.status.event.data.type == 'text') {
+ return this._clickAction_text();
+ }
+
+ if (core.status.event.data.type == 'wait') {
+ var timeout = Math.max(0, core.status.event.timeout - new Date().getTime()) || 0;
+ core.setFlag('type', 1);
+ core.setFlag('x', x);
+ core.setFlag('y', y);
+ core.setFlag('px', px);
+ core.setFlag('py', py);
+ core.setFlag('timeout', timeout);
+ var executed = core.events.__action_wait_afterGet(core.status.event.data.current);
+ if (executed || !core.status.event.data.current.forceChild) {
+ core.status.route.push("input:" + (1e8 * timeout + 1000000 + 1000 * px + py));
+ clearTimeout(core.status.event.interval);
+ delete core.status.event.timeout;
+ core.doAction();
+ }
+ return;
+ }
+
+ if (core.status.event.data.type == 'choices') {
+ // 选项
+ var data = core.status.event.data.current;
+ var choices = data.choices;
+ if (choices.length == 0) return;
+ if (this._out(x)) return;
+ var topIndex = this._getChoicesTopIndex(choices.length);
+ if (y >= topIndex && y < topIndex + choices.length) {
+ var choice = choices[y - topIndex];
+ if (choice.need != null && choice.need != '' && !core.calValue(choice.need)) {
+ core.playSound('操作失败');
+ core.drawTip("无法选择此项");
+ return;
+ }
+ clearTimeout(core.status.event.interval);
+ var timeout = Math.max(0, core.status.event.timeout - new Date().getTime()) || 0;
+ delete core.status.event.timeout;
+ core.setFlag('timeout', timeout);
+ // 对全局商店特殊处理
+ var index = y - topIndex;
+ if (index == choices.length - 1 && core.hasFlag('@temp@shop')) {
+ index = -1;
+ }
+ core.status.route.push("choices:" + (100 * timeout + index));
+ core.insertAction(choice.action);
+ core.doAction();
+ }
+ return;
+ }
+
+ if (core.status.event.data.type == 'confirm') {
+ if ((x == this._HX_ - 2 || x == this._HX_ - 1) && y == this._HY_ + 1) {
+ clearTimeout(core.status.event.interval);
+ var timeout = Math.max(0, core.status.event.timeout - new Date().getTime()) || 0;
+ delete core.status.event.timeout;
+ core.setFlag('timeout', timeout);
+ core.status.route.push("choices:" + 100 * timeout);
+ core.insertAction(core.status.event.ui.yes);
+ core.doAction();
+ }
+ else if ((x == this._HX_ + 2 || x == this._HX_ + 1) && y == this._HY_ + 1) {
+ clearTimeout(core.status.event.interval);
+ var timeout = Math.max(0, core.status.event.timeout - new Date().getTime()) || 0;
+ delete core.status.event.timeout;
+ core.setFlag('timeout', timeout);
+ core.status.route.push("choices:" + (100 * timeout + 1));
+ core.insertAction(core.status.event.ui.no);
+ core.doAction();
+ }
+ return;
+ }
+}
+
+////// 自定义事件时,按下某个键的操作 //////
+actions.prototype._keyDownAction = function (keycode) {
+ if (core.status.event.data.type == 'choices') {
+ this._keyDownChoices(keycode);
+ return;
+ }
+ if (core.status.event.data.type == 'confirm' && (keycode == 37 || keycode == 39)) {
+ core.status.event.selection = 1 - core.status.event.selection;
+ core.playSound('光标移动');
+ core.drawConfirmBox(core.status.event.ui.text);
+ return;
+ }
+}
+
+////// 自定义事件时,放开某个键的操作 //////
+actions.prototype._keyUpAction = function (keycode) {
+ if (core.status.event.data.type == 'text' && (keycode == 13 || keycode == 32 || keycode == 67)) {
+ return this._clickAction_text();
+ }
+ if (core.status.event.data.type == 'wait') {
+ var timeout = Math.max(0, core.status.event.timeout - new Date().getTime()) || 0;
+ core.setFlag('type', 0);
+ core.setFlag('keycode', keycode);
+ core.setFlag('timeout', timeout);
+ var executed = core.events.__action_wait_afterGet(core.status.event.data.current);
+ if (executed || !core.status.event.data.current.forceChild) {
+ core.status.route.push("input:" + (1e8 * timeout + keycode));
+ clearTimeout(core.status.event.interval);
+ delete core.status.event.timeout;
+ core.doAction();
+ }
+ return;
+ }
+ if (core.status.event.data.type == 'choices') {
+ var data = core.status.event.data.current;
+ var choices = data.choices;
+ if (choices.length > 0) {
+ this._selectChoices(choices.length, keycode, this._clickAction);
+ }
+ return;
+ }
+ if (core.status.event.data.type == 'confirm' && (keycode == 13 || keycode == 32 || keycode == 67)) {
+ var timeout = Math.max(0, core.status.event.timeout - new Date().getTime()) || 0;
+ delete core.status.event.timeout;
+ core.setFlag('timeout', timeout);
+ core.status.route.push("choices:" + (100 * timeout + core.status.event.selection));
+ if (core.status.event.selection == 0)
+ core.insertAction(core.status.event.ui.yes);
+ else core.insertAction(core.status.event.ui.no);
+ core.doAction();
+ return;
+ }
+}
+
+////// 怪物手册界面的点击操作 //////
+actions.prototype._clickBook = function (x, y) {
+ var pageinfo = core.ui._drawBook_pageinfo();
+ // 上一页
+ if ((x == this._HX_ - 2 || x == this._HX_ - 3) && y===core._HEIGHT_-1) {
+ core.playSound('光标移动');
+ core.ui.drawBook(core.status.event.data - pageinfo.per_page);
+ return;
+ }
+ // 下一页
+ if ((x == this._HX_ + 2 || x == this._HX_ + 3) && y===core._HEIGHT_-1) {
+ core.playSound('光标移动');
+ core.ui.drawBook(core.status.event.data + pageinfo.per_page);
+ return;
+ }
+ // 返回
+ if (x >= this.LAST - 2 && y===core._HEIGHT_-1) {
+ core.playSound('取消');
+ if (core.events.recoverEvents(core.status.event.interval)) {
+ return;
+ }
+ else if (core.status.event.ui != null) {
+ core.status.boxAnimateObjs = [];
+ core.ui._drawViewMaps(core.status.event.ui);
+ }
+ else core.ui.closePanel();
+ return;
+ }
+ // 怪物信息
+ var data = core.status.event.data;
+ if (data != null && y < core._HEIGHT_-1) {
+ var per_page = pageinfo.per_page, page = parseInt(data / per_page);
+ var u = (core._HEIGHT_ - 1) / per_page;
+ for (var i = 0; i < per_page; ++i) {
+ if (y >= u * i && y < u * (i + 1)) {
+ var index = per_page * page + i;
+ core.ui.drawBook(index);
+ core.ui._drawBookDetail(index);
+ break;
+ }
+ }
+ return;
+ }
+ return;
+}
+
+////// 怪物手册界面时,按下某个键的操作 //////
+actions.prototype._keyDownBook = function (keycode) {
+ var pageinfo = core.ui._drawBook_pageinfo();
+ if (keycode == 37) { core.playSound('光标移动'); core.ui.drawBook(core.status.event.data - pageinfo.per_page); }
+ if (keycode == 38) { core.playSound('光标移动'); core.ui.drawBook(core.status.event.data - 1); }
+ if (keycode == 39) { core.playSound('光标移动'); core.ui.drawBook(core.status.event.data + pageinfo.per_page); }
+ if (keycode == 40) { core.playSound('光标移动'); core.ui.drawBook(core.status.event.data + 1); }
+ if (keycode == 33) { core.playSound('光标移动'); core.ui.drawBook(core.status.event.data - pageinfo.per_page); }
+ if (keycode == 34) { core.playSound('光标移动'); core.ui.drawBook(core.status.event.data + pageinfo.per_page); }
+ return;
+}
+
+////// 怪物手册界面时,放开某个键的操作 //////
+actions.prototype._keyUpBook = function (keycode) {
+ if (keycode == 27 || keycode == 88) {
+ core.playSound('取消');
+ if (core.events.recoverEvents(core.status.event.interval)) {
+ return;
+ }
+ else if (core.status.event.ui != null) {
+ core.status.boxAnimateObjs = [];
+ core.ui._drawViewMaps(core.status.event.ui);
+ }
+ else core.ui.closePanel();
+ return;
+ }
+ if (keycode == 13 || keycode == 32 || keycode == 67) {
+ var data = core.status.event.data;
+ if (data != null) {
+ core.ui._drawBookDetail(data);
+ }
+ return;
+ }
+}
+
+////// 怪物手册属性显示界面时的点击操作 //////
+actions.prototype._clickBookDetail = function () {
+ core.clearMap('data');
+ core.playSound('取消');
+ core.status.event.id = 'book';
+}
+
+////// 楼层传送器界面时的点击操作 //////
+actions.prototype._clickFly = function (x, y) {
+ if ((x == core._WIDTH_ - 2 || x == core._WIDTH_ - 3) && y == this._HY_ + 3) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(-1)); }
+ if ((x == core._WIDTH_ - 2 || x == core._WIDTH_ - 3) && y == this._HY_ - 1) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(1)); }
+ if ((x == core._WIDTH_ - 2 || x == core._WIDTH_ - 3) && y == this._HY_ + 4) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(-10)); }
+ if ((x == core._WIDTH_ - 2 || x == core._WIDTH_ - 3) && y == this._HY_ - 2) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(10)); }
+ if (x >= this._HX_ - 1 && x <= this._HX_ + 1 && y===core._HEIGHT_-1) { core.playSound('取消'); core.ui.closePanel(); }
+ if (x >= 0 && x <= this._HX_ + 3 && y >= 3 && y <= core._HEIGHT_-1 - 1)
+ core.flyTo(core.floorIds[core.status.event.data]);
+ return;
+}
+
+////// 楼层传送器界面时,按下某个键的操作 //////
+actions.prototype._keyDownFly = function (keycode) {
+ if (keycode == 37) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(-10)); }
+ else if (keycode == 38) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(1)); }
+ else if (keycode == 39) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(10)); }
+ else if (keycode == 40) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(-1)); }
+ return;
+}
+
+actions.prototype._getNextFlyFloor = function (delta, index) {
+ if (index == null) index = core.status.event.data;
+ if (delta == 0) return index;
+ var sign = Math.sign(delta);
+ delta = Math.abs(delta);
+ var ans = index;
+ while (true) {
+ index += sign;
+ if (index < 0 || index >= core.floorIds.length) break;
+ var floorId = core.floorIds[index];
+ if (core.status.maps[floorId].canFlyTo && core.hasVisitedFloor(floorId)) {
+ delta--;
+ ans = index;
+ }
+ if (delta == 0) break;
+ }
+ return ans;
+}
+
+////// 楼层传送器界面时,放开某个键的操作 //////
+actions.prototype._keyUpFly = function (keycode) {
+ if (keycode == 71 || keycode == 27 || keycode == 88) {
+ core.playSound('取消');
+ core.ui.closePanel();
+ }
+ if (keycode == 13 || keycode == 32 || keycode == 67)
+ this._clickFly(this._HX_ - 1, this._HY_ - 1);
+ return;
+}
+
+////// 查看地图界面时的点击操作 //////
+actions.prototype._clickViewMaps = function (x, y, px, py) {
+ if (core.status.event.data == null) {
+ core.ui._drawViewMaps(core.floorIds.indexOf(core.status.floorId));
+ return;
+ }
+ var now = core.floorIds.indexOf(core.status.floorId);
+ var index = core.status.event.data.index;
+ var cx = core.status.event.data.x, cy = core.status.event.data.y;
+ var floorId = core.floorIds[index], mh = core.floors[floorId].height;
+ var perpx = core._PX_ / 5, cornerpx = perpx * 3 / 4, perpy = core._PY_ / 5, cornerpy = perpy * 3 / 4;
+
+ if (px <= cornerpx && py <= cornerpy) {
+ core.status.event.data.damage = !core.status.event.data.damage;
+ core.playSound('光标移动');
+ core.ui._drawViewMaps(index, cx, cy);
+ return;
+ }
+ if (px <= cornerpx && py >= core._PY_ - cornerpy) {
+ if (core.markedFloorIds[floorId]) delete core.markedFloorIds[floorId];
+ else core.markedFloorIds[floorId] = true;
+ core.playSound('光标移动');
+ core.ui._drawViewMaps(index, cx, cy);
+ return;
+ }
+ if (px >= core._PX_ - cornerpx && py <= cornerpy) {
+ core.status.event.data.all = !core.status.event.data.all;
+ core.playSound('光标移动');
+ core.ui._drawViewMaps(index, cx, cy);
+ return;
+ }
+
+ if (px >= perpx && px <= core._PX_ - perpx && py <= perpy && (!core.status.event.data.all && mh > core._HEIGHT_)) {
+ core.playSound('光标移动');
+ core.ui._drawViewMaps(index, cx, cy - 1);
+ return;
+ }
+ if (px >= perpx && px <= core._PX_ - perpx && py >= core._PY_ - perpy && (!core.status.event.data.all && mh > core._HEIGHT_)) {
+ core.playSound('光标移动');
+ core.ui._drawViewMaps(index, cx, cy + 1);
+ return;
+ }
+ if (px <= perpx && py >= perpy && py <= core._PY_ - perpy) {
+ core.playSound('光标移动');
+ core.ui._drawViewMaps(index, cx - 1, cy);
+ return;
+ }
+ if (px >= core._PX_ - perpx && py >= perpy && py <= core._PY_ - perpy) {
+ core.playSound('光标移动');
+ core.ui._drawViewMaps(index, cx + 1, cy);
+ return;
+ }
+
+ if (py <= 2 * perpy && (mh == core._HEIGHT_ || (px >= perpx && px <= core._PX_ - perpx))) {
+ core.playSound('光标移动');
+ index++;
+ while (index < core.floorIds.length && index != now && core.status.maps[core.floorIds[index]].cannotViewMap)
+ index++;
+ if (index < core.floorIds.length)
+ core.ui._drawViewMaps(index);
+ return;
+ }
+ if (py >= 3 * perpy && (mh == core._HEIGHT_ || (px >= perpx && px <= core._PX_ - perpx))) {
+ core.playSound('光标移动');
+ index--;
+ while (index >= 0 && index != now && core.status.maps[core.floorIds[index]].cannotViewMap)
+ index--;
+ if (index >= 0)
+ core.ui._drawViewMaps(index);
+ return;
+ }
+ if (px >= perpx && px <= core._PX_ - perpx && py >= perpy * 2 && py <= perpy * 3) {
+ core.clearMap('data');
+ core.playSound('取消');
+ core.ui.closePanel();
+ return;
+ }
+}
+
+////// 查看地图界面时,按下某个键的操作 //////
+actions.prototype._keyDownViewMaps = function (keycode) {
+ if (core.status.event.data == null) return;
+
+ var floorId = core.floorIds[core.status.event.data.index], mh = core.floors[floorId].height;
+
+ if (keycode == 38 || keycode == 33) this._clickViewMaps(this._HX_ , this._HY_ - 3 , core._PX_ / 2, core._PY_ / 5 * 1.5);
+ if (keycode == 40 || keycode == 34) this._clickViewMaps(this._HX_ , this._HY_ + 3 , core._PX_ / 2, core._PY_ / 5 * 3.5);
+ if (keycode == 87 && mh > core._HEIGHT_) this._clickViewMaps(this._HX_ , 0 , core._PX_ / 2, 1 );
+ if (keycode == 65) this._clickViewMaps(0 , this._HY_ , 1 , core._PY_ / 2 );
+ if (keycode == 83 && mh > core._HEIGHT_) this._clickViewMaps(this._HX_ , core._HEIGHT_ - 1, core._PX_ / 2, core._PY_ - 1 );
+ if (keycode == 68) this._clickViewMaps(core._WIDTH_ - 1, this._HY_ , core._PX_ , core._PY_ / 2 - 1 );
+ return;
+}
+
+////// 查看地图界面时,放开某个键的操作 //////
+actions.prototype._keyUpViewMaps = function (keycode) {
+ if (core.status.event.data == null) {
+ core.ui._drawViewMaps(core.floorIds.indexOf(core.status.floorId));
+ return;
+ }
+ var floorId = core.floorIds[core.status.event.data.index];
+
+ if (keycode == 27 || keycode == 13 || keycode == 32 || (!core.isReplaying() && keycode == 67)) {
+ core.clearMap('data');
+ core.playSound('取消');
+ core.ui.closePanel();
+ return;
+ }
+ if (keycode == 86) {
+ core.status.event.data.damage = !core.status.event.data.damage;
+ core.playSound('光标移动');
+ core.ui._drawViewMaps(core.status.event.data);
+ return;
+ }
+ if (keycode == 90) {
+ core.status.event.data.all = !core.status.event.data.all;
+ core.playSound('光标移动');
+ core.ui._drawViewMaps(core.status.event.data);
+ return;
+ }
+ if (keycode == 66) {
+ if (core.markedFloorIds[floorId]) delete core.markedFloorIds[floorId];
+ else core.markedFloorIds[floorId] = true;
+ core.playSound('光标移动');
+ core.ui._drawViewMaps(core.status.event.data);
+ return;
+ }
+ if (keycode == 88 || (core.isReplaying() && keycode == 67)) {
+ if (core.isReplaying()) {
+ core.control._replay_book();
+ } else {
+ core.openBook(false);
+ }
+ return;
+ }
+ if (keycode == 71 && !core.isReplaying()) {
+ core.useFly(false);
+ return;
+ }
+ return;
+}
+
+////// 快捷商店界面时的点击操作 //////
+actions.prototype._clickQuickShop = function (x, y) {
+ var shopIds = core.listShopIds();
+ if (this._out(x)) return;
+ var topIndex = this._HY_ - parseInt(shopIds.length / 2) + (core.status.event.ui.offset || 0);
+ if (y >= topIndex && y < topIndex + shopIds.length) {
+ var shopId = shopIds[y - topIndex];
+ if (!core.canOpenShop(shopId)) {
+ core.playSound('操作失败');
+ core.drawTip('当前项尚未开启');
+ return;
+ }
+ var message = core.canUseQuickShop(shopId);
+ if (message == null) {
+ // core.ui.closePanel();
+ core.openShop(shopIds[y - topIndex], false);
+ } else {
+ core.playSound('操作失败');
+ core.drawTip(message);
+ }
+ }
+ // 离开
+ else if (y == topIndex + shopIds.length) {
+ core.playSound('取消');
+ core.ui.closePanel();
+ }
+}
+
+////// 快捷商店界面时,放开某个键的操作 //////
+actions.prototype._keyUpQuickShop = function (keycode) {
+ if (keycode == 27 || keycode == 75 || keycode == 88 || keycode == 86) {
+ core.playSound('取消');
+ core.ui.closePanel();
+ return;
+ }
+ this._selectChoices(core.listShopIds().length + 1, keycode, this._clickQuickShop);
+ return;
+}
+
+////// 工具栏界面时的点击操作 //////
+actions.prototype._clickToolbox = function (x, y) {
+ var tools = core.getToolboxItems('tools'),
+ constants = core.getToolboxItems('constants');
+
+ // 装备栏
+ if (x >= this.LAST - 2 && y == 0) {
+ core.ui.closePanel();
+ if (core.isReplaying())
+ core.control._replay_equipbox();
+ else
+ core.openEquipbox();
+ return;
+ }
+ if (x >= this.LAST - 2 && y===core._HEIGHT_-1) {
+ core.playSound('取消');
+ core.ui.closePanel();
+ var last = core.status.route[core.status.route.length - 1] || '';
+ if (last.startsWith('equip:') || last.startsWith('unEquip:')) {
+ core.status.route.push('no');
+ }
+ core.checkAutoEvents();
+ return;
+ }
+
+ var toolsPage = core.status.event.data.toolsPage;
+ var constantsPage = core.status.event.data.constantsPage;
+ // 上一页
+ if (x == this._HX_ - 2 || x == this._HX_ - 3) {
+ if (y===core._HEIGHT_-1 - 5 && toolsPage > 1) {
+ core.status.event.data.toolsPage--;
+ core.playSound('光标移动');
+ core.ui._drawToolbox(core.status.event.selection);
+ }
+ if (y===core._HEIGHT_-1 && constantsPage > 1) {
+ core.status.event.data.constantsPage--;
+ core.playSound('光标移动');
+ core.ui._drawToolbox(core.status.event.selection);
+ }
+ }
+ // 下一页
+ if (x == this._HX_ + 2 || x == this._HX_ + 3) {
+ if (y===core._HEIGHT_-1 - 5 && toolsPage < Math.ceil(tools.length / this.LAST)) {
+ core.status.event.data.toolsPage++;
+ core.playSound('光标移动');
+ core.ui._drawToolbox(core.status.event.selection);
+ }
+ if (y===core._HEIGHT_-1 && constantsPage < Math.ceil(constants.length / this.LAST)) {
+ core.status.event.data.constantsPage++;
+ core.playSound('光标移动');
+ core.ui._drawToolbox(core.status.event.selection);
+ }
+ }
+
+ var index = parseInt(x / 2);
+ if (y===core._HEIGHT_-1 - 8) index += 0;
+ else if (y===core._HEIGHT_-1 - 6) index += this._HX_;
+ else if (y===core._HEIGHT_-1 - 3) index += this.LAST;
+ else if (y===core._HEIGHT_-1 - 1) index += this.LAST + this._HX_;
+ else index = -1;
+ if (index >= 0)
+ this._clickToolboxIndex(index);
+}
+
+////// 选择工具栏界面中某个Index后的操作 //////
+actions.prototype._clickToolboxIndex = function (index) {
+ var tools = core.getToolboxItems('tools'),
+ constants = core.getToolboxItems('constants');
+
+ var items = null;
+ var select;
+ if (index < this.LAST) {
+ select = index + this.LAST * (core.status.event.data.toolsPage - 1);
+ items = tools;
+ }
+ else {
+ select = index % this.LAST + this.LAST * (core.status.event.data.constantsPage - 1);
+ items = constants;
+ }
+ if (items == null) return;
+ if (select >= items.length) return;
+ var itemId = items[select];
+ if (itemId == core.status.event.data.selectId) {
+ if (core.isReplaying()) return;
+ core.events.tryUseItem(itemId);
+ }
+ else {
+ core.playSound('光标移动');
+ core.ui._drawToolbox(index);
+ }
+}
+
+////// 工具栏界面时,按下某个键的操作 //////
+actions.prototype._keyDownToolbox = function (keycode) {
+ if (core.status.event.data == null) return;
+
+ var last_index = this.LAST - 1;
+
+ var tools = core.getToolboxItems('tools'),
+ constants = core.getToolboxItems('constants');
+ var index = core.status.event.selection;
+ var toolsPage = core.status.event.data.toolsPage;
+ var constantsPage = core.status.event.data.constantsPage;
+ var toolsTotalPage = Math.ceil(tools.length / this.LAST);
+ var constantsTotalPage = Math.ceil(constants.length / this.LAST);
+ var toolsLastIndex = toolsPage < toolsTotalPage ? last_index : (tools.length + last_index) % this.LAST;
+ var constantsLastIndex = this.LAST + (constantsPage < constantsTotalPage ? last_index : (constants.length + last_index) % this.LAST);
+
+ if (keycode == 37) { // left
+ if (index == 0) { // 处理向前翻页
+ if (toolsPage > 1) {
+ core.status.event.data.toolsPage--;
+ index = last_index;
+ }
+ else return; // 第一页不向前翻
+ }
+ else if (index == this.LAST) {
+ if (constantsPage == 1) {
+ if (toolsTotalPage == 0) return;
+ core.status.event.data.toolsPage = toolsTotalPage;
+ index = (tools.length + last_index) % this.LAST;
+ }
+ else {
+ core.status.event.data.constantsPage--;
+ index = 2 * this.LAST - 1;
+ }
+ }
+ else index -= 1;
+ this._clickToolboxIndex(index);
+ return;
+ }
+ if (keycode == 38) { // up
+ if (index >= this.LAST && index < this.LAST + this._HX_) { // 进入tools
+ if (toolsTotalPage == 0) return;
+ if (toolsLastIndex >= this._HX_) index = Math.min(toolsLastIndex, index - this._HX_);
+ else index = Math.min(toolsLastIndex, index - this.LAST);
+ }
+ else if (index < this._HX_) return; // 第一行没有向上
+ else index -= this._HX_;
+ this._clickToolboxIndex(index);
+ return;
+ }
+ if (keycode == 39) { // right
+ if (toolsPage < toolsTotalPage && index == last_index) {
+ core.status.event.data.toolsPage++;
+ index = 0;
+ }
+ else if (constantsPage < constantsTotalPage && index == 2 * this.LAST - 1) {
+ core.status.event.data.constantsPage++;
+ index = this.LAST;
+ }
+ else if (index == toolsLastIndex) {
+ if (constantsTotalPage == 0) return;
+ core.status.event.data.constantsPage = 1;
+ index = this.LAST;
+ }
+ else if (index == constantsLastIndex) // 一个物品无操作
+ return;
+ else index++;
+ this._clickToolboxIndex(index);
+ return;
+ }
+ if (keycode == 40) { // down
+ var nextIndex = null;
+ if (index < this._HX_) {
+ if (toolsLastIndex >= this._HX_) nextIndex = Math.min(toolsLastIndex, index + this._HX_);
+ else index += this._HX_;
+ }
+ if (nextIndex == null && index < this.LAST) {
+ if (constantsTotalPage == 0) return;
+ nextIndex = Math.min(index + this._HX_, constantsLastIndex);
+ }
+ if (nextIndex == null && index < this.LAST + this._HX_) {
+ if (constantsLastIndex >= this.LAST + this._HX_)
+ nextIndex = Math.min(constantsLastIndex, index + this._HX_);
+ }
+ if (nextIndex != null) {
+ this._clickToolboxIndex(nextIndex);
+ }
+ return;
+ }
+}
+
+////// 工具栏界面时,放开某个键的操作 //////
+actions.prototype._keyUpToolbox = function (keycode) {
+ if (keycode == 81) {
+ core.playSound('确定');
+ core.ui.closePanel();
+ if (core.isReplaying())
+ core.control._replay_equipbox();
+ else
+ core.openEquipbox();
+ return;
+ }
+ if (keycode == 84 || keycode == 27 || keycode == 88) {
+ core.playSound('取消');
+ core.ui.closePanel();
+ var last = core.status.route[core.status.route.length - 1] || '';
+ if (last.startsWith('equip:') || last.startsWith('unEquip:')) {
+ core.status.route.push('no');
+ }
+ core.checkAutoEvents();
+ return;
+ }
+ if (core.status.event.data == null) return;
+
+ if (keycode == 13 || keycode == 32 || keycode == 67) {
+ this._clickToolboxIndex(core.status.event.selection);
+ return;
+ }
+}
+
+////// 装备栏界面时的点击操作 //////
+actions.prototype._clickEquipbox = function (x, y, px, py) {
+ if (x >= this.LAST - 2 && y == 0) {
+ core.playSound('确定');
+ core.ui.closePanel();
+ if (core.isReplaying())
+ core.control._replay_toolbox();
+ else
+ core.openToolbox();
+ return;
+ }
+ if (x >= this.LAST - 2 && y===core._HEIGHT_-1) {
+ core.playSound('取消');
+ core.ui.closePanel();
+ var last = core.status.route[core.status.route.length - 1] || '';
+ if (last.startsWith('equip:') || last.startsWith('unEquip:')) {
+ core.status.route.push('no');
+ }
+ core.checkAutoEvents();
+ return;
+ }
+ if ((x == this._HX_ - 2 || x == this._HX_ - 3) && y===core._HEIGHT_-1) {
+ if (core.status.event.data.page > 1) {
+ core.status.event.data.page--;
+ core.playSound('光标移动');
+ core.ui._drawEquipbox(core.status.event.selection);
+ }
+ return;
+ }
+ if ((x == this._HX_ + 2 || x == this._HX_ + 3) && y===core._HEIGHT_-1) {
+ var lastPage = Math.ceil(core.getToolboxItems('equips').length / this.LAST);
+ if (core.status.event.data.page < lastPage) {
+ core.status.event.data.page++;
+ core.playSound('光标移动');
+ core.ui._drawEquipbox(core.status.event.selection);
+ }
+ return;
+ }
+ var per_page = this._HX_ - 3, v = core._WIDTH_ / per_page;
+ if (y === core._HEIGHT_ - 9) {
+ for (var i = 0; i < per_page; ++i) if (x >= i * v && x <= (i + 1) * v) return this._clickEquipboxIndex(i);
+ } else if (y === core._HEIGHT_ - 7) {
+ for (var i = 0; i < per_page; ++i) if (x >= i * v && x <= (i + 1) * v) return this._clickEquipboxIndex(per_page + i);
+ } else if (Math.abs(core._HEIGHT_ - 5 - py / 32) < 0.5) {
+ for (var i = 0; i < per_page; ++i) if (x >= i * v && x <= (i + 1) * v) return this._clickEquipboxIndex(2 * per_page + i);
+ } else if (y === core._HEIGHT_ - 4) this._clickEquipboxIndex(this.LAST + parseInt(x / 2))
+ else if (y === core._HEIGHT_ - 2) this._clickEquipboxIndex(this.LAST + this._HX_ + parseInt(x / 2));
+}
+
+////// 选择装备栏界面中某个Index后的操作 //////
+actions.prototype._clickEquipboxIndex = function (index) {
+ if (index < this.LAST) {
+ if (index >= core.status.globalAttribute.equipName.length) return;
+ if (index == core.status.event.selection && core.status.hero.equipment[index]) {
+ if (core.isReplaying()) return;
+ core.unloadEquip(index);
+ core.status.route.push("unEquip:" + index);
+ } else core.playSound('光标移动');
+ }
+ else {
+ var equips = core.getToolboxItems('equips');
+ if (index == core.status.event.selection) {
+ if (core.isReplaying()) return;
+ var equipId = equips[index - this.LAST + (core.status.event.data.page - 1) * this.LAST];
+ core.loadEquip(equipId);
+ core.status.route.push("equip:" + equipId);
+ } else core.playSound('光标移动');
+ }
+ core.ui._drawEquipbox(index);
+}
+
+////// 装备栏界面时,按下某个键的操作 //////
+actions.prototype._keyDownEquipbox = function (keycode) {
+ if (core.status.event.data == null) return;
+
+ var last_index = this.LAST - 1;
+ var per_line = this._HX_ - 3;
+ var equipCapacity = core.status.globalAttribute.equipName.length;
+ var ownEquipment = core.getToolboxItems('equips');
+ var index = core.status.event.selection;
+ var page = core.status.event.data.page;
+ var totalPage = Math.ceil(ownEquipment.length / this.LAST);
+ var totalLastIndex = this.LAST + (page < totalPage ? last_index : (ownEquipment.length + last_index) % this.LAST);
+
+ if (keycode == 37) { // left
+ if (index == 0) return;
+ if (index == this.LAST) {
+ if (page > 1) {
+ core.status.event.data.page--;
+ core.playSound('光标移动');
+ index = this.LAST + last_index;
+ }
+ else if (page == 1)
+ index = equipCapacity - 1;
+ else return;
+ }
+ else index -= 1;
+ this._clickEquipboxIndex(index);
+ return;
+ }
+ if (keycode == 38) { // up
+ if (index < per_line) return;
+ else if (index < 2 * per_line) index -= per_line;
+ else if (index < this.LAST + this._HX_) {
+ index = parseInt((index - this.LAST) / 2);
+ if (equipCapacity > per_line) index = Math.min(equipCapacity - 1, index + per_line);
+ else index = Math.min(equipCapacity - 1, index);
+ }
+ else index -= this._HX_;
+ this._clickEquipboxIndex(index);
+ return;
+ }
+ if (keycode == 39) { // right
+ if (page < totalPage && index == this.LAST + last_index) {
+ core.status.event.data.page++;
+ core.playSound('光标移动');
+ index = this.LAST;
+ }
+ else if (index == equipCapacity - 1) {
+ if (totalPage == 0) return;
+ index = this.LAST;
+ }
+ else if (index == totalLastIndex)
+ return;
+ else index++;
+ this._clickEquipboxIndex(index);
+ return;
+ }
+ if (keycode == 40) { // down
+ if (index < per_line) {
+ if (equipCapacity > per_line) index = Math.min(index + per_line, equipCapacity - 1);
+ else {
+ if (totalPage == 0) return;
+ index = Math.min(2 * index + 1 + this.LAST, totalLastIndex);
+ }
+ }
+ else if (index < 2 * per_line) {
+ if (totalPage == 0) return;
+ index = Math.min(2 * (index - per_line) + 1 + this.LAST, totalLastIndex);
+ }
+ else if (index < this.LAST + this._HX_)
+ index = Math.min(index + this._HX_, totalLastIndex);
+ else return;
+ this._clickEquipboxIndex(index);
+ return;
+ }
+}
+
+////// 装备栏界面时,放开某个键的操作 //////
+actions.prototype._keyUpEquipbox = function (keycode, altKey) {
+ if (altKey && keycode >= 48 && keycode <= 57) {
+ core.items.quickSaveEquip(keycode - 48);
+ return;
+ }
+ if (keycode == 84) {
+ core.playSound('确定');
+ core.ui.closePanel();
+ if (core.isReplaying())
+ core.control._replay_toolbox();
+ else
+ core.openToolbox();
+ return;
+ }
+ if (keycode == 81 || keycode == 27 || keycode == 88) {
+ core.playSound('取消');
+ core.ui.closePanel();
+ var last = core.status.route[core.status.route.length - 1] || '';
+ if (last.startsWith('equip:') || last.startsWith('unEquip:')) {
+ core.status.route.push('no');
+ }
+ core.checkAutoEvents();
+ return;
+ }
+ if (!core.status.event.data.selectId) return;
+
+ if (keycode == 13 || keycode == 32 || keycode == 67) {
+ this._clickEquipboxIndex(core.status.event.selection);
+ return;
+ }
+}
+
+////// 存读档界面时的点击操作 //////
+actions.prototype._clickSL = function (x, y) {
+ var page = core.status.event.data.page, offset = core.status.event.data.offset;
+ var index = page * 10 + offset;
+
+ // 上一页
+ if ((x == this._HX_ - 2 || x == this._HX_ - 3) && y===core._HEIGHT_-1) {
+ core.playSound('光标移动');
+ core.ui._drawSLPanel(10 * (page - 1) + offset);
+ return;
+ }
+ // 下一页
+ if ((x == this._HX_ + 2 || x == this._HX_ + 3) && y===core._HEIGHT_-1) {
+ core.playSound('光标移动');
+ core.ui._drawSLPanel(10 * (page + 1) + offset);
+ return;
+ }
+ // 返回
+ if (x >= this.LAST - 2 && y===core._HEIGHT_-1) {
+ core.playSound('取消');
+ if (core.events.recoverEvents(core.status.event.interval))
+ return;
+ core.ui.closePanel();
+ delete core.status.tempRoute;
+ if (!core.isPlaying())
+ core.showStartAnimate(true);
+ return;
+ }
+ // 删除
+ if (x >= 0 && x <= 2 && y===core._HEIGHT_-1) {
+ if (core.status.event.id == 'save') {
+ core.status.event.selection = !core.status.event.selection;
+ core.ui._drawSLPanel(index);
+ }
+ else { // 显示收藏
+ core.status.event.data.mode = core.status.event.data.mode == 'all' ? 'fav' : 'all';
+ if (core.status.event.data.mode == 'fav')
+ core.ui._drawSLPanel(1, true);
+ else {
+ page = parseInt((core.saves.saveIndex - 1) / 5);
+ offset = core.saves.saveIndex - 5 * page;
+ core.ui._drawSLPanel(10 * page + offset, true);
+ }
+ }
+ return;
+ }
+ // 点存档名
+ var xLeft = parseInt(core._WIDTH_ / 3), xRight = parseInt(core._WIDTH_ * 2 / 3);
+ var topY1 = 0, topY2 = this._HY_;
+ if (y >= topY1 && y <= topY1 + 1) {
+ if (x >= xLeft && x < xRight) return this._clickSL_favorite(page, 1);
+ if (x >= xRight) return this._clickSL_favorite(page, 2);
+ }
+ if (y >= topY2 && y <= topY2 + 1) {
+ if (x < xLeft) return this._clickSL_favorite(page, 3);
+ if (x >= xLeft && x < xRight) return this._clickSL_favorite(page, 4);
+ if (x >= xRight) return this._clickSL_favorite(page, 5);
+ }
+
+ var id = null;
+ if (y >= topY1 + 2 && y < this._HY_ - 1) {
+ if (x < xLeft) id = "autoSave";
+ if (x >= xLeft && x < xRight) id = 5 * page + 1;
+ if (x >= xRight) id = 5 * page + 2;
+ }
+ if (y >= topY2 + 2 && y < core._HEIGHT_ - 1) {
+ if (x < xLeft) id = 5 * page + 3;
+ if (x >= xLeft && x < xRight) id = 5 * page + 4;
+ if (x >= xRight) id = 5 * page + 5;
+ }
+ if (id != null) {
+ if (core.status.event.selection) {
+ if (id == 'autoSave') {
+ core.playSound('操作失败');
+ core.drawTip("无法删除自动存档!");
+ } else {
+ core.removeSave(id, function () {
+ core.ui._drawSLPanel(index, true);
+ });
+ }
+ }
+ else {
+ if (core.status.event.data.mode == 'fav' && id != 'autoSave')
+ id = core.saves.favorite[id - 1];
+ core.doSL(id, core.status.event.id);
+ }
+ }
+}
+
+actions.prototype._clickSL_favorite = function (page, offset) {
+ if (offset == 0) return;
+ var index = 5 * page + offset;
+ if (core.status.event.data.mode == 'fav') { // 收藏模式下点击的下标直接对应favorite
+ index = core.saves.favorite[index - 1];
+ core.myprompt("请输入想要显示的存档名(长度不超过5字符)", null, function (value) {
+ if (value && value.length <= 5) {
+ core.saves.favoriteName[index] = value;
+ core.control._updateFavoriteSaves();
+ core.ui._drawSLPanel(10 * page + offset);
+ } else if (value) {
+ alert("无效的输入!");
+ }
+ });
+ } else {
+ var v = core.saves.favorite.indexOf(index);
+ core.playSound('确定');
+ if (v >= 0) { // 已经处于收藏状态:取消收藏
+ core.saves.favorite.splice(v, 1);
+ delete core.saves.favoriteName[index];
+ }
+ else if (core.hasSave(index)) { // 存在存档则进行收藏
+ core.saves.favorite.push(index);
+ core.saves.favorite = core.saves.favorite.sort(function (a, b) { return a - b; }); // 保证有序
+ core.drawTip("收藏成功!");
+ }
+ core.control._updateFavoriteSaves();
+ core.ui._drawSLPanel(10 * page + offset);
+ }
+}
+
+////// 存读档界面时,按下某个键的操作 //////
+actions.prototype._keyDownSL = function (keycode) {
+
+ var page = core.status.event.data.page, offset = core.status.event.data.offset;
+ var index = page * 10 + offset;
+
+ if (keycode == 37) { // left
+ core.playSound('光标移动');
+ if (offset == 0) {
+ core.ui._drawSLPanel(10 * (page - 1) + 5);
+ }
+ else {
+ core.ui._drawSLPanel(index - 1);
+ }
+ return;
+ }
+ if (keycode == 38) { // up
+ core.playSound('光标移动');
+ if (offset < 3) {
+ core.ui._drawSLPanel(10 * (page - 1) + offset + 3);
+ }
+ else {
+ core.ui._drawSLPanel(index - 3);
+ }
+ return;
+ }
+ if (keycode == 39) { // right
+ core.playSound('光标移动');
+ if (offset == 5) {
+ core.ui._drawSLPanel(10 * (page + 1) + 1);
+ }
+ else {
+ core.ui._drawSLPanel(index + 1);
+ }
+ return;
+ }
+ if (keycode == 40) { // down
+ core.playSound('光标移动');
+ if (offset >= 3) {
+ core.ui._drawSLPanel(10 * (page + 1) + offset - 3);
+ }
+ else {
+ core.ui._drawSLPanel(index + 3);
+ }
+ return;
+ }
+ if (keycode == 33) { // PAGEUP
+ core.playSound('光标移动');
+ core.ui._drawSLPanel(10 * (page - 1) + offset);
+ return;
+ }
+ if (keycode == 34) { // PAGEDOWN
+ core.playSound('光标移动');
+ core.ui._drawSLPanel(10 * (page + 1) + offset);
+ return;
+ }
+}
+
+////// 存读档界面时,放开某个键的操作 //////
+actions.prototype._keyUpSL = function (keycode) {
+ var page = core.status.event.data.page, offset = core.status.event.data.offset;
+ var index = page * 10 + offset;
+
+ if (keycode == 27 || keycode == 88 || (core.status.event.id == 'save' && keycode == 83)
+ || (core.status.event.id == 'load' && keycode == 68)) {
+ this._clickSL(core._WIDTH_ - 1, core._HEIGHT_ - 1);
+ return;
+ }
+ if (keycode >= 48 && keycode <= 57) {
+ if (keycode == 48) keycode = 58;
+ core.ui._drawSLPanel((keycode - 49) * 1000 + 1);
+ return;
+ }
+ if (keycode == 13 || keycode == 32 || keycode == 67) {
+ if (offset == 0)
+ core.doSL("autoSave", core.status.event.id);
+ else {
+ var id = 5 * page + offset;
+ if (core.status.event.data.mode == 'fav') id = core.saves.favorite[id - 1];
+ core.doSL(id, core.status.event.id);
+ }
+ return;
+ }
+ if (keycode == 69 && core.status.event.id != 'save') { // E 收藏切换
+ this._clickSL(0, core._HEIGHT_ - 1);
+ return;
+ }
+ if (keycode == 46) {
+ if (offset == 0) {
+ core.playSound('操作失败');
+ core.drawTip("无法删除自动存档!");
+ }
+ else {
+ var id = 5 * page + offset;
+ if (core.status.event.data.mode == 'fav') id = core.saves.favorite[id - 1];
+ core.removeSave(id, function () {
+ core.ui._drawSLPanel(index, true);
+ });
+ }
+ }
+ if (keycode == 70 && core.status.event.data.mode == 'all') { // F
+ this._clickSL_favorite(page, offset);
+ }
+}
+
+
+////// 系统设置界面时的点击操作 //////
+actions.prototype._clickSwitchs = function (x, y) {
+ var choices = core.status.event.ui.choices;
+ var topIndex = this._getChoicesTopIndex(choices.length);
+ var selection = y - topIndex;
+ if (this._out(x)) return;
+ if (selection >= 0 && selection < choices.length) {
+ core.status.event.selection = selection;
+ switch (selection) {
+ case 0:
+ core.status.event.selection = 0;
+ core.playSound('确定');
+ return core.ui._drawSwitchs_sounds();
+ case 1:
+ core.status.event.selection = 0;
+ core.playSound('确定');
+ return core.ui._drawSwitchs_display();
+ case 2:
+ core.status.event.selection = 0;
+ core.playSound('确定');
+ return core.ui._drawSwitchs_action();
+ case 3:
+ core.status.event.selection = 0;
+ core.playSound('取消');
+ return core.ui._drawSettings();
+ }
+ }
+}
+
+////// 系统设置界面时,放开某个键的操作 //////
+actions.prototype._keyUpSwitchs = function (keycode) {
+ if (keycode == 27 || keycode == 88) {
+ core.status.event.selection = 0;
+ core.playSound('取消');
+ core.ui._drawSettings();
+ return;
+ }
+ this._selectChoices(core.status.event.ui.choices.length, keycode, this._clickSwitchs);
+}
+
+actions.prototype._clickSwitchs_sounds = function (x, y) {
+ var choices = core.status.event.ui.choices;
+ var topIndex = this._getChoicesTopIndex(choices.length);
+ var selection = y - topIndex;
+ if (this._out(x)) {
+ if (selection != 2) return;
+ }
+ if (selection >= 0 && selection < choices.length) {
+ var width = choices[selection].width;
+ var leftPos = (core._PX_ - width) / 2, rightPos = (core._PX_ + width) / 2;
+ var leftGrid = parseInt(leftPos / 32), rightGrid = parseInt(rightPos / 32) - 1;
+ core.status.event.selection = selection;
+ switch (selection) {
+ case 0:
+ return this._clickSwitchs_sounds_bgm();
+ case 1:
+ return this._clickSwitchs_sounds_se();
+ case 2:
+ if (x == leftGrid || x == leftGrid + 1) return this._clickSwitchs_sounds_userVolume(-1);
+ if (x == rightGrid || x == rightGrid + 1) return this._clickSwitchs_sounds_userVolume(1);
+ return;
+ case 3:
+ core.status.event.selection = 0;
+ core.playSound('取消');
+ core.ui._drawSwitchs();
+ return;
+ }
+ }
+}
+
+actions.prototype._clickSwitchs_sounds_bgm = function () {
+ core.triggerBgm();
+ core.playSound('确定');
+ core.ui._drawSwitchs_sounds();
+}
+
+actions.prototype._clickSwitchs_sounds_se = function () {
+ core.musicStatus.soundStatus = !core.musicStatus.soundStatus;
+ core.setLocalStorage('soundStatus', core.musicStatus.soundStatus);
+ core.playSound('确定');
+ core.ui._drawSwitchs_sounds();
+}
+
+actions.prototype._clickSwitchs_sounds_userVolume = function (delta) {
+ var value = Math.round(Math.sqrt(100 * core.musicStatus.userVolume));
+ if (value == 0 && delta < 0) return;
+ core.musicStatus.userVolume = core.clamp(Math.pow(value + delta, 2) / 100, 0, 1);
+ //audioContext 音效 不受designVolume 影响
+ if (core.musicStatus.gainNode != null) core.musicStatus.gainNode.gain.value = core.musicStatus.userVolume;
+ if (core.musicStatus.playingBgm) core.material.bgms[core.musicStatus.playingBgm].volume = core.musicStatus.userVolume * core.musicStatus.designVolume;
+ core.setLocalStorage('userVolume', core.musicStatus.userVolume);
+ core.playSound('确定');
+ core.ui._drawSwitchs_sounds();
+}
+
+actions.prototype._keyUpSwitchs_sounds = function (keycode) {
+ if (keycode == 27 || keycode == 88) {
+ core.status.event.selection = 0;
+ core.playSound('取消');
+ core.ui._drawSwitchs();
+ return;
+ }
+ if (keycode == 37) {
+ switch (core.status.event.selection) {
+ case 2: core.playSound('确定'); return this._clickSwitchs_sounds_userVolume(-1);
+ }
+ } else if (keycode == 39) {
+ switch (core.status.event.selection) {
+ case 2: core.playSound('确定'); return this._clickSwitchs_sounds_userVolume(1);
+ }
+ }
+ this._selectChoices(core.status.event.ui.choices.length, keycode, this._clickSwitchs_sounds);
+}
+
+actions.prototype._clickSwitchs_display = function (x, y) {
+ var choices = core.status.event.ui.choices;
+ var topIndex = this._getChoicesTopIndex(choices.length);
+ var selection = y - topIndex;
+ if (this._out(x)) {
+ if (selection != 0) return;
+ }
+ if (selection >= 0 && selection < choices.length) {
+ var width = choices[selection].width;
+ var leftPos = (core._PX_ - width) / 2, rightPos = (core._PX_ + width) / 2;
+ var leftGrid = parseInt(leftPos / 32), rightGrid = parseInt(rightPos / 32) - 1;
+ core.status.event.selection = selection;
+ switch (selection) {
+ case 0:
+ if (x == leftGrid || x == leftGrid + 1) return this._clickSwitchs_display_setSize(-1);
+ if (x == rightGrid || x == rightGrid + 1) return this._clickSwitchs_display_setSize(1);
+ return;
+ case 1:
+ core.playSound('确定');
+ return this._clickSwitchs_display_enableHDCanvas();
+ case 2:
+ core.playSound('确定');
+ return this._clickSwitchs_display_enableEnemyPoint();
+ case 3:
+ core.playSound('确定');
+ return this._clickSwitchs_display_enemyDamage();
+ case 4:
+ core.playSound('确定');
+ return this._clickSwitchs_display_critical();
+ case 5:
+ core.playSound('确定');
+ return this._clickSwitchs_display_extraDamage();
+ case 6:
+ core.playSound('确定');
+ return this._clickSwitchs_display_extraDamageType();
+ case 7:
+ core.playSound('确定');
+ core.setLocalStorage('autoScale', core.getLocalStorage('autoScale') ? false : true);
+ core.ui._drawSwitchs_display();
+ break;
+ case 8:
+ core.status.event.selection = 1;
+ core.playSound('取消');
+ core.ui._drawSwitchs();
+ return;
+ }
+ }
+}
+
+actions.prototype._clickSwitchs_display_setSize = function (delta) {
+ core.setDisplayScale(delta);
+ var currentRatio = Math.max(window.devicePixelRatio || 1, core.domStyle.scale);
+ if (currentRatio > core.domStyle.ratio) {
+ core.drawTip("需刷新页面以调整UI清晰度");
+ }
+ core.ui._drawSwitchs_display();
+}
+
+actions.prototype._clickSwitchs_display_enableHDCanvas = function () {
+ core.flags.enableHDCanvas = !core.flags.enableHDCanvas;
+ core.setLocalStorage('enableHDCanvas', core.flags.enableHDCanvas);
+ core.drawTip("开关高清UI,需刷新页面方可生效");
+ core.ui._drawSwitchs_display();
+}
+
+actions.prototype._clickSwitchs_display_enableEnemyPoint = function () {
+ core.flags.enableEnemyPoint = !core.flags.enableEnemyPoint;
+ core.setLocalStorage('enableEnemyPoint', core.flags.enableEnemyPoint);
+ core.ui._drawSwitchs_display();
+}
+
+actions.prototype._clickSwitchs_display_enemyDamage = function () {
+ core.flags.displayEnemyDamage = !core.flags.displayEnemyDamage;
+ core.updateDamage();
+ core.setLocalStorage('enemyDamage', core.flags.displayEnemyDamage);
+ core.ui._drawSwitchs_display();
+}
+
+actions.prototype._clickSwitchs_display_critical = function () {
+ core.flags.displayCritical = !core.flags.displayCritical;
+ core.updateDamage();
+ core.setLocalStorage('critical', core.flags.displayCritical);
+ core.ui._drawSwitchs_display();
+}
+
+actions.prototype._clickSwitchs_display_extraDamage = function () {
+ core.flags.displayExtraDamage = !core.flags.displayExtraDamage;
+ core.updateDamage();
+ core.setLocalStorage('extraDamage', core.flags.displayExtraDamage);
+ core.ui._drawSwitchs_display();
+}
+
+actions.prototype._clickSwitchs_display_extraDamageType = function () {
+ core.flags.extraDamageType = (core.flags.extraDamageType + 1) % 3;
+ core.updateDamage();
+ core.setLocalStorage('extraDamageType', core.flags.extraDamageType);
+ core.ui._drawSwitchs_display();
+}
+
+actions.prototype._keyUpSwitchs_display = function (keycode) {
+ if (keycode == 27 || keycode == 88) {
+ core.status.event.selection = 1;
+ core.playSound('取消');
+ core.ui._drawSwitchs();
+ return;
+ }
+ if (keycode == 37) {
+ switch (core.status.event.selection) {
+ case 0: core.playSound('确定'); return this._clickSwitchs_display_setSize(-1);
+ }
+ } else if (keycode == 39) {
+ switch (core.status.event.selection) {
+ case 0: core.playSound('确定'); return this._clickSwitchs_display_setSize(1);
+ }
+ }
+ this._selectChoices(core.status.event.ui.choices.length, keycode, this._clickSwitchs_display);
+}
+
+actions.prototype._clickSwitchs_action = function (x, y) {
+ var choices = core.status.event.ui.choices;
+ var topIndex = this._getChoicesTopIndex(choices.length);
+ var selection = y - topIndex;
+ if (this._out(x)) {
+ if (selection != 0 && selection != 1) return;
+ }
+ if (selection >= 0 && selection < choices.length) {
+ var width = choices[selection].width;
+ var leftPos = (core._PX_ - width) / 2, rightPos = (core._PX_ + width) / 2;
+ var leftGrid = parseInt(leftPos / 32), rightGrid = parseInt(rightPos / 32) - 1;
+ core.status.event.selection = selection;
+ switch (selection) {
+ case 0:
+ if (x == leftGrid || x == leftGrid + 1) { core.playSound('确定'); return this._clickSwitchs_action_moveSpeed(-10); }
+ if (x == rightGrid || x == rightGrid + 1) { core.playSound('确定'); return this._clickSwitchs_action_moveSpeed(10); }
+ return;
+ case 1:
+ if (x == leftGrid || x == leftGrid + 1) { core.playSound('确定'); return this._clickSwitchs_action_floorChangeTime(-100); }
+ if (x == rightGrid || x == rightGrid + 1) { core.playSound('确定'); return this._clickSwitchs_action_floorChangeTime(100); }
+ case 2:
+ core.playSound('确定');
+ return this._clickSwitchs_action_potionNoRouting();
+ case 3:
+ core.playSound('确定');
+ return this._clickSwitchs_action_clickMove();
+ case 4:
+ core.playSound('确定');
+ return this._clickSwitchs_action_leftHandPrefer();
+ case 5:
+ core.status.event.selection = 2;
+ core.playSound('取消');
+ core.ui._drawSwitchs();
+ return;
+ }
+ }
+}
+
+actions.prototype._clickSwitchs_action_moveSpeed = function (delta) {
+ core.values.moveSpeed = core.clamp(core.values.moveSpeed + delta, 50, 200);
+ core.setLocalStorage("moveSpeed", core.values.moveSpeed);
+ core.ui._drawSwitchs_action();
+}
+
+actions.prototype._clickSwitchs_action_floorChangeTime = function (delta) {
+ core.values.floorChangeTime = core.clamp(core.values.floorChangeTime + delta, 0, 2000);
+ core.setLocalStorage("floorChangeTime", core.values.floorChangeTime);
+ core.ui._drawSwitchs_action();
+}
+
+actions.prototype._clickSwitchs_action_potionNoRouting = function () {
+ if (core.hasFlag('__potionNoRouting__')) core.removeFlag('__potionNoRouting__');
+ else core.setFlag('__potionNoRouting__', true);
+ core.ui._drawSwitchs_action();
+}
+
+actions.prototype._clickSwitchs_action_clickMove = function () {
+ if (core.hasFlag('__noClickMove__')) core.removeFlag('__noClickMove__');
+ else core.setFlag('__noClickMove__', true);
+ core.ui._drawSwitchs_action();
+}
+
+actions.prototype._clickSwitchs_action_leftHandPrefer = function () {
+ core.flags.leftHandPrefer = !core.flags.leftHandPrefer;
+ core.setLocalStorage('leftHandPrefer', core.flags.leftHandPrefer);
+ if (core.flags.leftHandPrefer) {
+ core.myconfirm("左手模式已开启!\n此模式下WASD将用于移动勇士,IJKL对应于原始的WASD进行存读档等操作。")
+ }
+ core.ui._drawSwitchs_action();
+}
+
+actions.prototype._keyUpSwitchs_action = function (keycode) {
+ if (keycode == 27 || keycode == 88) {
+ core.status.event.selection = 2;
+ core.playSound('取消');
+ core.ui._drawSwitchs();
+ return;
+ }
+ if (keycode == 37) {
+ switch (core.status.event.selection) {
+ case 0: core.playSound('确定'); return this._clickSwitchs_action_moveSpeed(-10);
+ case 1: core.playSound('确定'); return this._clickSwitchs_action_floorChangeTime(-100);
+ }
+ } else if (keycode == 39) {
+ switch (core.status.event.selection) {
+ case 0: core.playSound('确定'); return this._clickSwitchs_action_moveSpeed(10);
+ case 1: core.playSound('确定'); return this._clickSwitchs_action_floorChangeTime(100);
+ }
+ }
+ this._selectChoices(core.status.event.ui.choices.length, keycode, this._clickSwitchs_action);
+}
+
+////// 系统菜单栏界面时的点击操作 //////
+actions.prototype._clickSettings = function (x, y) {
+ if (this._out(x)) return;
+ var choices = core.status.event.ui.choices;
+ var topIndex = this._getChoicesTopIndex(choices.length);
+ if (y >= topIndex && y < topIndex + choices.length) {
+ var selection = y - topIndex;
+ core.status.event.selection = selection;
+ switch (selection) {
+ case 0:
+ core.status.event.selection = 0;
+ core.playSound('确定');
+ core.ui._drawSwitchs();
+ break;
+ case 1:
+ // core.playSound('确定');
+ core.ui._drawKeyBoard();
+ break;
+ case 2:
+ // core.playSound('确定');
+ core.clearUI();
+ core.ui._drawViewMaps();
+ break;
+ case 3:
+ core.status.event.selection = 0;
+ core.playSound('确定');
+ core.ui._drawNotes();
+ break;
+ case 4:
+ core.status.event.selection = 0;
+ core.playSound('确定');
+ core.ui._drawSyncSave();
+ break;
+ case 5:
+ core.status.event.selection = 0;
+ core.playSound('确定');
+ core.ui._drawGameInfo();
+ break;
+ case 6:
+ return core.confirmRestart();
+ case 7:
+ core.playSound('取消');
+ core.ui.closePanel();
+ break;
+ }
+ }
+ return;
+}
+
+////// 系统菜单栏界面时,放开某个键的操作 //////
+actions.prototype._keyUpSettings = function (keycode) {
+ if (keycode == 27 || keycode == 88) {
+ core.playSound('取消');
+ core.ui.closePanel();
+ return;
+ }
+ this._selectChoices(core.status.event.ui.choices.length, keycode, this._clickSettings);
+}
+
+////// 存档笔记页面时的点击操作 //////
+actions.prototype._clickNotes = function (x, y) {
+ if (this._out(x)) return;
+ var choices = core.status.event.ui.choices;
+
+ var topIndex = this._getChoicesTopIndex(choices.length);
+ if (y >= topIndex && y < topIndex + choices.length) {
+ var selection = y - topIndex;
+ core.status.event.selection = selection;
+ switch (selection) {
+ case 0:
+ core.playSound('确定');
+ this._clickNotes_new();
+ break;
+ case 1:
+ // core.playSound('确定');
+ this._clickNotes_show();
+ break;
+ case 2:
+ core.playSound('确定');
+ this._clickNotes_edit();
+ break;
+ case 3:
+ core.playSound('确定');
+ this._clickNotes_delete();
+ break;
+ case 4:
+ core.status.event.selection = 3;
+ core.playSound('取消');
+ core.ui._drawSettings();
+ break;
+ }
+ }
+}
+
+actions.prototype.__clickNotes_replaceText = function (data) {
+ data = (data || "").replace(/[\${}]/g, "_")
+ .replace(/(\t|\\t)\[.*?\]/g, "")
+ .replace("\b", "\\b")
+ .replace(/\\b\[.*?\]/g, "")
+ .replace(/\n|\\n/g, " ");
+ if (data.length > 45) data = data.substring(0, 43) + "...";
+ return data;
+}
+
+actions.prototype._clickNotes_new = function () {
+ core.status.hero.notes = core.status.hero.notes || [];
+ core.myprompt("请输入一段笔记,不超过45字", null, function (data) {
+ data = core.actions.__clickNotes_replaceText(data);
+ if (data) {
+ core.status.hero.notes.push(data);
+ core.drawText("存档笔记新增成功!");
+ } else {
+ core.ui.closePanel();
+ }
+ });
+}
+
+actions.prototype._clickNotes_show = function () {
+ core.playSound('确定');
+ core.status.hero.notes = core.status.hero.notes || [];
+ var result = [];
+ for (var i = 0; i < core.status.hero.notes.length; i += 5) {
+ var v = [];
+ for (var j = i; j < i + 5 && j < core.status.hero.notes.length; ++j) {
+ v.push(j + 1 + ". " + this.__clickNotes_replaceText(core.status.hero.notes[j]));
+ }
+ result.push("\t[存档笔记]" + v.join("\n"));
+ }
+ if (result.length == 0) result.push("当前没有存档笔记,试着新增一个吧!\n(菜单栏 -> 存档笔记 -> 新增存档笔记)");
+ core.drawText(result);
+}
+
+actions.prototype._clickNotes_edit = function () {
+ core.status.hero.notes = core.status.hero.notes || [];
+ if (core.status.hero.notes.length == 0) {
+ core.drawText("当前没有存档笔记,试着新增一个吧!");
+ } else {
+ core.myprompt("请输入要编辑的存档笔记编号(1 - " + core.status.hero.notes.length + ")", "1", function (data) {
+ if (!data) core.ui.closePanel();
+ var value = parseInt(data) || 0;
+ if (!value || value <= 0 || value > core.status.hero.notes.length) {
+ core.drawText("不合法的输入!");
+ } else {
+ core.myprompt("请输入新内容,不超过45字", core.status.hero.notes[value - 1], function (data) {
+ data = core.actions.__clickNotes_replaceText(data);
+ if (data) {
+ core.status.hero.notes[value - 1] = data;
+ core.drawText("存档笔记编辑成功!");
+ } else {
+ core.ui.closePanel();
+ }
+ });
+ }
+ })
+ }
+}
+
+actions.prototype._clickNotes_delete = function () {
+ core.status.hero.notes = core.status.hero.notes || [];
+ if (core.status.hero.notes.length == 0) {
+ core.stopSound();
+ core.playSound('操作失败');
+ core.drawText("当前没有存档笔记,无法删除!");
+ } else {
+ core.myprompt("请输入要删除的所有存档笔记编号,以逗号分隔。不填则代表删除全部笔记。", null, function (data) {
+ if (data == null) {
+ core.ui.closePanel();
+ return;
+ }
+ else if (!data) {
+ core.status.hero.notes = [];
+ core.drawText("所有存档笔记删除成功!");
+ } else {
+ data = data.split(",").map(function (one) { return parseInt(one); })
+ .filter(function (one) { return one && one > 0 && one <= core.status.hero.notes.length });
+ if (data.length == 0) {
+ core.drawText("没有要删除的笔记!");
+ } else {
+ data.sort(function (a, b) { return b - a; })
+ .forEach(function (index) {
+ core.status.hero.notes.splice(index - 1, 1);
+ });
+ core.drawText("已删除 " + data.sort().join(",") + " 号笔记");
+ }
+ }
+ })
+ }
+}
+
+////// 存档笔记页面时,放开某个键的操作 //////
+actions.prototype._keyUpNotes = function (keycode) {
+ if (keycode == 27 || keycode == 88) {
+ core.status.event.selection = 3;
+ core.playSound('取消');
+ core.ui._drawSettings();
+ return;
+ }
+ this._selectChoices(core.status.event.ui.choices.length, keycode, this._clickNotes);
+}
+
+////// 同步存档界面时的点击操作 //////
+actions.prototype._clickSyncSave = function (x, y) {
+ if (this._out(x)) return;
+ var choices = core.status.event.ui.choices;
+ var topIndex = this._getChoicesTopIndex(choices.length);
+ if (y >= topIndex && y < topIndex + choices.length) {
+ var selection = y - topIndex;
+ core.status.event.selection = selection;
+ switch (selection) {
+ case 0:
+ core.status.event.selection = 0;
+ core.playSound('确定');
+ core.ui._drawSyncSelect();
+ break;
+ case 1:
+ core.playSound('确定');
+ core.syncLoad();
+ break;
+ case 2:
+ core.playSound('确定');
+ core.status.event.selection = 0;
+ core.ui._drawLocalSaveSelect();
+ break;
+ case 3:
+ core.playSound('确定');
+ return this._clickSyncSave_readFile();
+ case 4:
+ // core.playSound('确定');
+ return this._clickSyncSave_replay();
+ case 5:
+ core.status.event.selection = 0;
+ core.playSound('确定');
+ core.ui._drawStorageRemove();
+ break;
+ case 6:
+ core.status.event.selection = 4;
+ core.playSound('取消');
+ core.ui._drawSettings();
+ break;
+
+ }
+ }
+ return;
+}
+
+actions.prototype._clickSyncSave_readFile = function () {
+ core.readFile(function (obj) {
+ if (obj.name != core.firstData.name) return alert("存档和游戏不一致!");
+ if (obj.version != core.firstData.version) return alert("游戏版本不一致!");
+ if (!obj.data) return alert("无效的存档!");
+ core.control._syncLoad_write(obj.data);
+ }, null, ".h5save");
+}
+
+actions.prototype._clickSyncSave_replay = function () {
+ core.ui._drawReplay();
+}
+
+////// 同步存档界面时,放开某个键的操作 //////
+actions.prototype._keyUpSyncSave = function (keycode) {
+ if (keycode == 27 || keycode == 88) {
+ core.status.event.selection = 4;
+ core.playSound('取消');
+ core.ui._drawSettings();
+ return;
+ }
+ this._selectChoices(core.status.event.ui.choices.length, keycode, this._clickSyncSave);
+}
+
+////// 同步存档选择界面时的点击操作 //////
+actions.prototype._clickSyncSelect = function (x, y) {
+ if (this._out(x)) return;
+ var choices = core.status.event.ui.choices;
+
+ var topIndex = this._getChoicesTopIndex(choices.length);
+ if (y >= topIndex && y < topIndex + choices.length) {
+ var selection = y - topIndex;
+ core.status.event.selection = selection;
+ switch (selection) {
+ case 0:
+ core.playSound('确定');
+ core.myconfirm('你确定要同步全部存档么?\n这可能在存档较多的时候比较慢。', function () {
+ core.syncSave('all');
+ });
+ break;
+ case 1:
+ core.playSound('确定');
+ core.syncSave();
+ break;
+ case 2:
+ core.status.event.selection = 0;
+ core.playSound('取消');
+ core.ui._drawSyncSave();
+ break;
+ }
+ }
+}
+
+////// 同步存档选择界面时,放开某个键的操作 //////
+actions.prototype._keyUpSyncSelect = function (keycode) {
+ if (keycode == 27 || keycode == 88) {
+ core.status.event.selection = 0;
+ core.playSound('取消');
+ core.ui._drawSyncSave();
+ return;
+ }
+ this._selectChoices(core.status.event.ui.choices.length, keycode, this._clickSyncSelect);
+}
+
+////// 存档下载界面时的点击操作 //////
+actions.prototype._clickLocalSaveSelect = function (x, y) {
+ if (this._out(x)) return;
+ var choices = core.status.event.ui.choices;
+
+ var topIndex = this._getChoicesTopIndex(choices.length);
+
+ if (y >= topIndex && y < topIndex + choices.length) {
+ var selection = y - topIndex;
+ core.status.event.selection = selection;
+ if (selection < 2) {
+ var callback = function (saves) {
+ if (saves) {
+ var content = {
+ "name": core.firstData.name,
+ "version": core.firstData.version,
+ "data": saves
+ }
+ core.download(core.firstData.name + "_" + core.formatDate2(new Date()) + ".h5save",
+ LZString.compressToBase64(JSON.stringify(content)));
+ }
+ };
+ if (selection == 0) core.getAllSaves(callback);
+ else core.getSave(core.saves.saveIndex, callback);
+ }
+
+ core.status.event.selection = 2;
+ core.playSound('取消');
+ core.ui._drawSyncSave();
+ }
+}
+
+////// 存档下载界面时,放开某个键的操作 //////
+actions.prototype._keyUpLocalSaveSelect = function (keycode) {
+ if (keycode == 27 || keycode == 88) {
+ core.status.event.selection = 2;
+ core.playSound('取消');
+ core.ui._drawSyncSave();
+ return;
+ }
+ this._selectChoices(core.status.event.ui.choices.length, keycode, this._clickLocalSaveSelect);
+}
+
+////// 存档删除界面时的点击操作 //////
+actions.prototype._clickStorageRemove = function (x, y) {
+ if (this._out(x)) return;
+ var choices = core.status.event.ui.choices;
+
+ var topIndex = this._getChoicesTopIndex(choices.length);
+
+ if (y >= topIndex && y < topIndex + choices.length) {
+ var selection = y - topIndex;
+ core.status.event.selection = selection;
+ switch (selection) {
+ case 0:
+ return this._clickStorageRemove_all();
+ case 1:
+ return this._clickStorageRemove_current();
+ case 2:
+ core.status.event.selection = 5;
+ core.playSound('取消');
+ core.ui._drawSyncSave();
+ break;
+ }
+ }
+}
+
+actions.prototype._clickStorageRemove_all = function () {
+ core.myconfirm("你确定要清除【全部游戏】的所有本地存档?\n此行为不可逆!!!", function () {
+ core.ui.drawWaiting("正在清空,请稍候...");
+ core.clearLocalForage(function () {
+ core.saves.ids = {};
+ core.saves.autosave.data = null;
+ core.saves.autosave.updated = false;
+ core.saves.autosave.now = 0;
+ core.saves.cache = {};
+ core.ui.closePanel();
+ core.saves.saveIndex = 1;
+ core.saves.favorite = [];
+ core.saves.favoriteName = {};
+ core.control._updateFavoriteSaves();
+ core.removeLocalStorage('saveIndex');
+ core.drawText("\t[操作成功]你的所有存档已被清空。");
+ });
+ });
+}
+
+actions.prototype._clickStorageRemove_current = function () {
+ core.myconfirm("你确定要清除本游戏的所有本地存档?\n此行为不可逆!!!", function () {
+ var done = function () {
+ core.saves.ids = {};
+ core.saves.autosave.data = null;
+ core.saves.autosave.updated = false;
+ core.saves.autosave.now = 0;
+ core.ui.closePanel();
+ core.saves.saveIndex = 1;
+ core.saves.favorite = [];
+ core.saves.favoriteName = {};
+ core.control._updateFavoriteSaves();
+ core.removeLocalStorage('saveIndex');
+ core.drawText("\t[操作成功]当前塔的存档已被清空。");
+ }
+ core.ui.drawWaiting("正在清空,请稍候...");
+ Object.keys(core.saves.ids).forEach(function (v) {
+ core.removeLocalForage("save" + v);
+ });
+ core.removeLocalForage("autoSave", done);
+ });
+}
+
+////// 存档删除界面时,放开某个键的操作 //////
+actions.prototype._keyUpStorageRemove = function (keycode) {
+ if (keycode == 27 || keycode == 88) {
+ core.status.event.selection = 5;
+ core.playSound('取消');
+ core.ui._drawSyncSave();
+ return;
+ }
+ this._selectChoices(core.status.event.ui.choices.length, keycode, this._clickStorageRemove);
+}
+
+////// 回放选择界面时的点击操作 //////
+actions.prototype._clickReplay = function (x, y) {
+ if (this._out(x)) return;
+ var choices = core.status.event.ui.choices;
+
+ var topIndex = this._getChoicesTopIndex(choices.length);
+
+ if (y >= topIndex && y < topIndex + choices.length) {
+ var selection = y - topIndex;
+ core.status.event.selection = selection;
+ switch (selection) {
+ case 0: core.playSound('确定'); return this._clickReplay_fromBeginning();
+ case 1: core.playSound('确定'); return this._clickReplay_fromLoad();
+ case 2: core.playSound('确定'); return this._clickReplay_replayRemain();
+ case 3: core.playSound('确定'); return this._clickReplay_replaySince();
+ case 4: core.playSound('确定'); return core.chooseReplayFile();
+ case 5: core.playSound('确定'); return this._clickReplay_download();
+ case 6: core.playSound('取消'); return core.ui.closePanel();
+ }
+ }
+}
+
+actions.prototype._clickReplay_fromBeginning = function () {
+ core.ui.closePanel();
+ core.startGame(core.status.hard, core.getFlag('__seed__'), core.cloneArray(core.status.route));
+}
+
+actions.prototype._clickReplay_fromLoad = function () {
+ core.status.event.id = 'replayLoad';
+ core.status.event.selection = null;
+ core.clearUI();
+ var saveIndex = core.saves.saveIndex;
+ var page = parseInt((saveIndex - 1) / 5), offset = saveIndex - 5 * page;
+ core.ui._drawSLPanel(10 * page + offset);
+}
+
+actions.prototype._clickReplay_replayRemain = function () {
+ core.closePanel();
+ core.drawText([
+ "\t[接续播放录像]该功能允许你播放\r[yellow]两个存档之间的录像\r,常常用于\r[yellow]区域优化\r。\n" +
+ "例如,有若干个区,已经全部通关;之后重打一区并进行了优化,则可以对剩余区域直接播放录像而无需全部重打。\n\n" +
+ "详细使用方法参见露珠录制的视频教程:\n\r[yellow]https://bilibili.com/video/BV1az4y1C78x",
+ "\t[步骤1]请选择一个存档。\n\r[yellow]该存档的坐标必须和当前勇士坐标完全相同。\r\n将尝试从此处开始回放。",
+ ], function () {
+ core.status.event.id = 'replayRemain';
+ core.lockControl();
+ var saveIndex = core.saves.saveIndex;
+ var page = parseInt((saveIndex - 1) / 5), offset = saveIndex - 5 * page;
+ core.ui._drawSLPanel(10 * page + offset);
+ });
+}
+
+actions.prototype._clickReplay_replaySince = function () {
+ core.closePanel();
+ core.drawText([
+ "\t[播放存档剩余录像]该功能为【接续播放录像】的简化版本,允许你播放\r[yellow]一个存档中剩余的录像\r,常常用于\r[yellow]录像局部优化\r。\n" +
+ "在录像正常播放中,你随时可以暂停并按S键进行存档;此时\r[yellow]剩余录像\r也会被记在存档中(在读档界面用\r[yellow][R]\r标识。)\n" +
+ "之后,你可以选择在路线优化后直接播放该存档的\r[yellow]剩余录像\r,而无需再像接续播放一样选择录像起点和终点。\n\n" +
+ "详细使用方法参见露珠录制的视频教程:\n\r[yellow]https://bilibili.com/video/BV1az4y1C78x",
+ "请选择一个存档。\n\n\r[yellow]该存档需为录像播放中存的,且坐标必须和当前勇士坐标完全相同。\r\n将尝试播放此存档的剩余录像。",
+ ], function () {
+ core.status.event.id = 'replaySince';
+ core.lockControl();
+ var saveIndex = core.saves.saveIndex;
+ var page = parseInt((saveIndex - 1) / 5), offset = saveIndex - 5 * page;
+ core.ui._drawSLPanel(10 * page + offset);
+ });
+}
+
+actions.prototype._clickReplay_download = function () {
+ // if (core.hasFlag('debug')) return core.drawText("\t[系统提示]调试模式下无法下载录像");
+ core.download(core.firstData.name + "_" + core.formatDate2() + ".h5route",
+ LZString.compressToBase64(JSON.stringify({
+ 'name': core.firstData.name,
+ 'hard': core.status.hard,
+ 'seed': core.getFlag('__seed__'),
+ 'route': core.encodeRoute(core.status.route)
+ })));
+
+}
+
+////// 回放选择界面时,放开某个键的操作 //////
+actions.prototype._keyUpReplay = function (keycode) {
+ if (keycode == 27 || keycode == 88) {
+ core.playSound('取消');
+ core.ui.closePanel();
+ return;
+ }
+ this._selectChoices(core.status.event.ui.choices.length, keycode, this._clickReplay);
+}
+
+////// 游戏信息界面时的点击操作 //////
+actions.prototype._clickGameInfo = function (x, y) {
+ if (this._out(x)) return;
+ var choices = core.status.event.ui.choices;
+
+ var topIndex = this._getChoicesTopIndex(choices.length);
+
+ if (y >= topIndex && y < topIndex + choices.length) {
+ var selection = y - topIndex;
+ core.status.event.selection = selection;
+ switch (selection) {
+ case 0: return core.ui._drawStatistics();
+ case 1: return this._clickGameInfo_openProject();
+ case 2: return this._clickGameInfo_openComments();
+ case 3: return core.ui._drawHelp();
+ case 4: return core.ui._drawAbout();
+ case 5: return this._clickGameInfo_download();
+ case 6:
+ core.status.event.selection = 5;
+ core.playSound('取消');
+ core.ui._drawSettings();
+ break;
+ }
+ }
+}
+
+actions.prototype._clickGameInfo_openProject = function () {
+ if (core.platform.isPC)
+ window.open("editor.html", "_blank");
+ else {
+ core.myconfirm("即将离开本游戏,跳转至工程页面,确认?", function () {
+ window.location.href = "editor-mobile.html";
+ });
+ }
+}
+
+actions.prototype._clickGameInfo_openComments = function () {
+ if (core.platform.isPC) {
+ window.open("/score.php?name=" + core.firstData.name, "_blank");
+ }
+ else {
+ core.myconfirm("即将离开本游戏,跳转至评论页面,确认?", function () {
+ window.location.href = "/score.php?name=" + core.firstData.name;
+ });
+ }
+}
+
+actions.prototype._clickGameInfo_download = function () {
+ if (core.platform.isPC)
+ window.open(core.firstData.name + ".zip");
+ else
+ window.location.href = core.firstData.name + ".zip";
+}
+
+////// 游戏信息界面时,放开某个键的操作 //////
+actions.prototype._keyUpGameInfo = function (keycode) {
+ if (keycode == 27 || keycode == 88) {
+ core.status.event.selection = 5;
+ core.playSound('取消');
+ return core.ui._drawSettings();
+ }
+ this._selectChoices(core.status.event.ui.choices.length, keycode, this._clickGameInfo);
+}
+
+////// “虚拟键盘”界面时的点击操作 //////
+actions.prototype._clickKeyBoard = function (x, y) {
+ var m = this._HX_;
+ if (y == this._HY_ - 3 && x >= m - 5 && x <= m + 5) {
+ core.ui.closePanel();
+ core.keyUp(112 + x + 5 - m);
+ }
+ if (y == this._HY_ - 2 && x >= m - 5 && x <= m + 4) {
+ core.ui.closePanel();
+ core.keyUp(x == m + 4 ? 48 : 49 + x + 5 - m); // 1-9: 49-57; 0: 48
+ }
+ // 字母
+ var lines = [
+ ["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"],
+ ["A", "S", "D", "F", "G", "H", "J", "K", "L"],
+ ["Z", "X", "C", "V", "B", "N", "M"],
+ ];
+ if (y == this._HY_ - 1 && x >= m - 5 && x <= m + 4) {
+ core.ui.closePanel();
+ core.keyUp(lines[0][x + 5 - m].charCodeAt(0));
+ }
+ if (y == this._HY_ && x >= m - 5 && x <= m + 3) {
+ core.ui.closePanel();
+ core.keyUp(lines[1][x + 5 - m].charCodeAt(0));
+ }
+ if (y == this._HY_ + 1 && x >= m - 5 && x <= m + 1) {
+ core.ui.closePanel();
+ core.keyUp(lines[2][x + 5 - m].charCodeAt(0));
+ }
+ if (y == this._HY_ + 2 && x >= m - 5 && x <= m + 5) {
+ core.ui.closePanel();
+ if (x == m - 5) core.keyUp(189); // -
+ if (x == m - 4) core.keyUp(187); // =
+ if (x == m - 3) core.keyUp(219); // [
+ if (x == m - 2) core.keyUp(221); // ]
+ if (x == m - 1) core.keyUp(220); // \
+ if (x == m) core.keyUp(186); // ;
+ if (x == m + 1) core.keyUp(222); // '
+ if (x == m + 2) core.keyUp(188); // ,
+ if (x == m + 3) core.keyUp(190); // .
+ if (x == m + 4) core.keyUp(191); // /
+ if (x == m + 5) core.keyUp(192); // `
+ }
+ if (y == this._HY_ + 3 && x >= m - 5 && x <= m + 4) {
+ core.ui.closePanel();
+ if (x == m - 5) core.keyUp(27); // ESC
+ if (x == m - 4) core.keyUp(9); // TAB
+ if (x == m - 3) core.keyUp(20); // CAPS
+ if (x == m - 2) core.keyUp(16); // SHIFT
+ if (x == m - 1) core.keyUp(17); // CTRL
+ if (x == m) core.keyUp(18); // ALT
+ if (x == m + 1) core.keyUp(32); // SPACE
+ if (x == m + 2) core.keyUp(8); // BACKSPACE
+ if (x == m + 3) core.keyUp(13); // ENTER
+ if (x == m + 4) core.keyUp(46); // DEL
+ }
+ if (y == this._HY_ + 4 && x >= m + 3 && x <= m + 5) {
+ core.playSound('取消');
+ core.ui.closePanel();
+ }
+}
+
+////// 光标界面时的点击操作 //////
+actions.prototype._clickCursor = function (x, y, px, py) {
+ if (x == core.status.automaticRoute.cursorX && y == core.status.automaticRoute.cursorY) {
+ core.ui.closePanel();
+ // 视为按下再放起
+ this.doRegisteredAction('ondown', x, y, px, py);
+ this.doRegisteredAction('onup', x, y, px, py);
+ return;
+ }
+ core.status.automaticRoute.cursorX = x;
+ core.status.automaticRoute.cursorY = y;
+ core.ui._drawCursor();
+}
+
+////// 光标界面时,按下某个键的操作 //////
+actions.prototype._keyDownCursor = function (keycode) {
+ if (keycode == 37) { // left
+ core.status.automaticRoute.cursorX--;
+ core.playSound('光标移动');
+ core.ui._drawCursor();
+ return;
+ }
+ if (keycode == 38) { // up
+ core.status.automaticRoute.cursorY--;
+ core.playSound('光标移动');
+ core.ui._drawCursor();
+ return;
+ }
+ if (keycode == 39) { // right
+ core.status.automaticRoute.cursorX++;
+ core.playSound('光标移动');
+ core.ui._drawCursor();
+ return;
+ }
+ if (keycode == 40) { // down
+ core.status.automaticRoute.cursorY++;
+ core.playSound('光标移动');
+ core.ui._drawCursor();
+ return;
+ }
+}
+
+////// 光标界面时,放开某个键的操作 //////
+actions.prototype._keyUpCursor = function (keycode) {
+ if (keycode == 27 || keycode == 88) {
+ core.playSound('取消');
+ core.ui.closePanel();
+ return;
+ }
+ if (keycode == 13 || keycode == 32 || keycode == 67 || keycode == 69) {
+ core.playSound('确定');
+ core.ui.closePanel();
+ var x = core.status.automaticRoute.cursorX;
+ var y = core.status.automaticRoute.cursorY;
+ // 视为按下再放起
+ this.doRegisteredAction('ondown', x, y, 32 * x + 16, 32 * y + 16);
+ this.doRegisteredAction('onup', x, y, 32 * x + 16, 32 * y + 16);
+ return;
+ }
+}
diff --git a/libs/control.js b/libs/control.js
new file mode 100644
index 0000000..c6e4f30
--- /dev/null
+++ b/libs/control.js
@@ -0,0 +1,3565 @@
+
+/*
+control.js:游戏主要逻辑控制
+主要负责status相关内容,以及各种变量获取/存储
+寻路算法和人物行走也在此文件内
+ */
+
+"use strict";
+
+function control () {
+ this._init();
+}
+
+control.prototype._init = function () {
+ this.controldata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.control;
+ this.renderFrameFuncs = [];
+ this.replayActions = [];
+ this.weathers = {};
+ this.resizes = [];
+ this.noAutoEvents = true;
+ this.updateNextFrame = false;
+ // --- 注册系统的animationFrame
+ this.registerAnimationFrame("totalTime", false, this._animationFrame_totalTime);
+ this.registerAnimationFrame("autoSave", true, this._animationFrame_autoSave);
+ this.registerAnimationFrame("globalAnimate", true, this._animationFrame_globalAnimate);
+ this.registerAnimationFrame("animate", true, this._animationFrame_animate);
+ this.registerAnimationFrame("heroMoving", true, this._animationFrame_heroMoving);
+ this.registerAnimationFrame("weather", true, this._animationFrame_weather);
+ this.registerAnimationFrame("tip", true, this._animateFrame_tip);
+ this.registerAnimationFrame("parallelDo", false, this._animationFrame_parallelDo);
+ // --- 注册系统的天气
+ this.registerWeather("rain", this._weather_rain, this._animationFrame_weather_rain);
+ this.registerWeather("snow", this._weather_snow, this._animationFrame_weather_snow);
+ this.registerWeather("fog", this._weather_fog, this.__animateFrame_weather_image);
+ this.registerWeather("cloud", this._weather_cloud, this.__animateFrame_weather_image);
+ this.registerWeather("sun", this._weather_sun, this._animationFrame_weather_sun);
+ // --- 注册系统的replay
+ this.registerReplayAction("move", this._replayAction_move);
+ this.registerReplayAction("item", this._replayAction_item);
+ this.registerReplayAction("equip", this._replayAction_equip);
+ this.registerReplayAction("unEquip", this._replayAction_unEquip);
+ this.registerReplayAction("saveEquip", this._replayAction_saveEquip);
+ this.registerReplayAction("loadEquip", this._replayAction_loadEquip);
+ this.registerReplayAction("fly", this._replayAction_fly);
+ this.registerReplayAction("shop", this._replayAction_shop);
+ this.registerReplayAction("turn", this._replayAction_turn);
+ this.registerReplayAction("getNext", this._replayAction_getNext);
+ this.registerReplayAction("moveDirectly", this._replayAction_moveDirectly);
+ this.registerReplayAction("key", this._replayAction_key);
+ this.registerReplayAction("click", this._replayAction_click);
+ this.registerReplayAction("ignoreInput", this._replayAction_ignoreInput);
+ this.registerReplayAction("no", this._replayAction_no);
+ // --- 注册系统的resize
+ this.registerResize("gameGroup", this._resize_gameGroup);
+ this.registerResize("canvas", this._resize_canvas);
+ this.registerResize("statusBar", this._resize_statusBar);
+ this.registerResize("status", this._resize_status);
+ this.registerResize("toolBar", this._resize_toolBar);
+ this.registerResize("tools", this._resize_tools);
+}
+
+// ------ requestAnimationFrame 相关 ------ //
+
+////// 注册一个 animationFrame //////
+// name:名称,可用来作为注销使用;needPlaying:是否只在游戏运行时才执行(在标题界面不执行)
+// func:要执行的函数,或插件中的函数名;可接受timestamp(从页面加载完毕到当前所经过的时间)作为参数
+control.prototype.registerAnimationFrame = function (name, needPlaying, func) {
+ this.unregisterAnimationFrame(name);
+ this.renderFrameFuncs.push({ name: name, needPlaying: needPlaying, func: func });
+}
+
+////// 注销一个 animationFrame //////
+control.prototype.unregisterAnimationFrame = function (name) {
+ this.renderFrameFuncs = this.renderFrameFuncs.filter(function (x) { return x.name != name; });
+}
+
+////// 设置requestAnimationFrame //////
+control.prototype._setRequestAnimationFrame = function () {
+ this._checkRequestAnimationFrame();
+ core.animateFrame.totalTime = Math.max(core.animateFrame.totalTime, core.getLocalStorage('totalTime', 0));
+ var loop = function (timestamp) {
+ core.control.renderFrameFuncs.forEach(function (b) {
+ if (b.func) {
+ try {
+ if (core.isPlaying() || !b.needPlaying)
+ core.doFunc(b.func, core.control, timestamp);
+ }
+ catch (e) {
+ console.error(e);
+ console.error("ERROR in requestAnimationFrame[" + b.name + "]:已自动注销该项。");
+ core.unregisterAnimationFrame(b.name);
+ }
+ }
+ })
+ window.requestAnimationFrame(loop);
+ }
+ window.requestAnimationFrame(loop);
+}
+
+control.prototype._checkRequestAnimationFrame = function () {
+ (function () {
+ var lastTime = 0;
+ var vendors = ['webkit', 'moz'];
+ for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
+ window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
+ window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || // Webkit中此取消方法的名字变了
+ window[vendors[x] + 'CancelRequestAnimationFrame'];
+ }
+
+ if (!window.requestAnimationFrame) {
+ window.requestAnimationFrame = function (callback, element) {
+ var currTime = new Date().getTime();
+ var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
+ var id = window.setTimeout(function () {
+ callback(currTime + timeToCall);
+ }, timeToCall);
+ lastTime = currTime + timeToCall;
+ return id;
+ };
+ }
+ if (!window.cancelAnimationFrame) {
+ window.cancelAnimationFrame = function (id) {
+ clearTimeout(id);
+ };
+ }
+ }());
+}
+
+control.prototype._animationFrame_totalTime = function (timestamp) {
+ core.animateFrame.totalTime += timestamp - core.animateFrame.totalTimeStart;
+ core.animateFrame.totalTimeStart = timestamp;
+ if (core.isPlaying()) {
+ core.status.hero.statistics.totalTime = core.animateFrame.totalTime;
+ core.status.hero.statistics.currTime += timestamp - (core.status.hero.statistics.start || timestamp);
+ core.status.hero.statistics.start = timestamp;
+ }
+}
+
+control.prototype._animationFrame_autoSave = function (timestamp) {
+ if (timestamp - core.saves.autosave.time <= 5000) return;
+ core.control.checkAutosave();
+ core.saves.autosave.time = timestamp;
+}
+
+control.prototype._animationFrame_globalAnimate = function (timestamp) {
+ if (timestamp - core.animateFrame.globalTime <= core.values.animateSpeed) return;
+ core.status.globalAnimateStatus++;
+ if (core.status.floorId) {
+ // Global Animate
+ core.status.globalAnimateObjs.forEach(function (block) {
+ core.drawBlock(block, core.status.globalAnimateStatus);
+ });
+
+ // Global floor images
+ core.maps._drawFloorImages(core.status.floorId, core.canvas.bg, 'bg', core.status.floorAnimateObjs || [], core.status.globalAnimateStatus);
+ core.maps._drawFloorImages(core.status.floorId, core.canvas.fg, 'fg', core.status.floorAnimateObjs || [], core.status.globalAnimateStatus);
+
+ // Global Autotile Animate
+ core.status.autotileAnimateObjs.forEach(function (block) {
+ core.maps._drawAutotileAnimate(block, core.status.globalAnimateStatus);
+ });
+
+ // Global hero animate
+ if ((core.status.hero || {}).animate && core.status.heroMoving == 0 && main.mode == 'play' && !core.status.preview.enabled) {
+ core.drawHero('stop', null, core.status.globalAnimateStatus);
+ }
+ }
+ // Box animate
+ core.drawBoxAnimate();
+ core.animateFrame.globalTime = timestamp;
+}
+
+control.prototype._animationFrame_animate = function (timestamp) {
+ if (timestamp - core.animateFrame.animateTime < 50 || !core.status.animateObjs || core.status.animateObjs.length == 0) return;
+ core.clearMap('animate');
+ // 更新帧
+ for (var i = 0; i < core.status.animateObjs.length; i++) {
+ var obj = core.status.animateObjs[i];
+ if (obj.index == obj.animate.frames.length) {
+ (function (callback) {
+ setTimeout(function () {
+ if (callback) callback();
+ });
+ })(obj.callback);
+ }
+ }
+ core.status.animateObjs = core.status.animateObjs.filter(function (obj) {
+ return obj.index < obj.animate.frames.length;
+ });
+ core.status.animateObjs.forEach(function (obj) {
+ if (obj.hero) {
+ core.maps._drawAnimateFrame('animate', obj.animate, core.status.heroCenter.px, core.status.heroCenter.py, obj.index++);
+ } else {
+ core.maps._drawAnimateFrame('animate', obj.animate, obj.centerX, obj.centerY, obj.index++);
+ }
+ });
+ core.animateFrame.animateTime = timestamp;
+}
+
+control.prototype._animationFrame_heroMoving = function (timestamp) {
+ if (core.status.heroMoving <= 0) return;
+ // 换腿
+ if (timestamp - core.animateFrame.moveTime > core.values.moveSpeed) {
+ core.animateFrame.leftLeg = !core.animateFrame.leftLeg;
+ core.animateFrame.moveTime = timestamp;
+ }
+ core.drawHero(core.animateFrame.leftLeg ? 'leftFoot' : 'rightFoot', 4 * core.status.heroMoving);
+}
+
+control.prototype._animationFrame_weather = function (timestamp) {
+ var weather = core.animateFrame.weather, type = weather.type;
+ if (!core.dymCanvas.weather || !core.control.weathers[type] || !core.control.weathers[type].frameFunc) return;
+ try {
+ core.doFunc(core.control.weathers[type].frameFunc, core.control, timestamp, core.animateFrame.weather.level);
+ } catch (e) {
+ console.error(e);
+ console.error("ERROR in weather[" + type + "]:已自动注销该项。");
+ core.unregisterWeather(type);
+ }
+}
+
+control.prototype._animationFrame_weather_rain = function (timestamp, level) {
+ if (timestamp - core.animateFrame.weather.time < 30) return;
+ var ctx = core.dymCanvas.weather, ox = core.bigmap.offsetX, oy = core.bigmap.offsetY;
+ core.clearMap('weather');
+ ctx.strokeStyle = 'rgba(174,194,224,0.8)';
+ ctx.lineWidth = 1;
+ ctx.lineCap = 'round';
+
+ core.animateFrame.weather.nodes.forEach(function (p) {
+ ctx.beginPath();
+ ctx.moveTo(p.x - ox, p.y - oy);
+ ctx.lineTo(p.x + p.l * p.xs - ox, p.y + p.l * p.ys - oy);
+ ctx.stroke();
+
+ p.x += p.xs;
+ p.y += p.ys;
+ if (p.x > core.bigmap.width * 32 || p.y > core.bigmap.height * 32) {
+ p.x = Math.random() * core.bigmap.width * 32;
+ p.y = -10;
+ }
+
+ });
+
+ ctx.fill();
+ core.animateFrame.weather.time = timestamp;
+}
+
+control.prototype._animationFrame_weather_snow = function (timestamp, level) {
+ if (timestamp - core.animateFrame.weather.time < 30) return;
+ var ctx = core.dymCanvas.weather, ox = core.bigmap.offsetX, oy = core.bigmap.offsetY;
+ core.clearMap('weather');
+ ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
+ ctx.beginPath();
+ core.animateFrame.weather.data = core.animateFrame.weather.data || 0;
+ core.animateFrame.weather.data += 0.01;
+
+ var angle = core.animateFrame.weather.data;
+ core.animateFrame.weather.nodes.forEach(function (p) {
+ ctx.moveTo(p.x - ox, p.y - oy);
+ ctx.arc(p.x - ox, p.y - oy, p.r, 0, Math.PI * 2, true);
+ // update
+ p.x += Math.sin(angle) * core.animateFrame.weather.level;
+ p.y += Math.cos(angle + p.d) + 1 + p.r / 2;
+ if (p.x > core.bigmap.width * 32 + 5 || p.x < -5 || p.y > core.bigmap.height * 32) {
+ if (Math.random() > 1 / 3) {
+ p.x = Math.random() * core.bigmap.width * 32;
+ p.y = -10;
+ }
+ else {
+ if (Math.sin(angle) > 0)
+ p.x = -5;
+ else
+ p.x = core.bigmap.width * 32 + 5;
+ p.y = Math.random() * core.bigmap.height * 32;
+ }
+ }
+ });
+ ctx.fill();
+ core.animateFrame.weather.time = timestamp;
+}
+
+control.prototype.__animateFrame_weather_image = function (timestamp, level) {
+ if (timestamp - core.animateFrame.weather.time < 30) return;
+ var node = core.animateFrame.weather.nodes[0];
+ var image = node.image;
+ if (!image) return;
+ core.clearMap('weather');
+ core.setAlpha('weather', node.level / 500);
+ var wind = 1.5;
+ var width = image.width, height = image.height;
+ node.x += node.dx * wind;
+ node.y += (2 * node.dy - 1) * wind;
+ if (node.x + 3 * width <= core._PX_) {
+ node.x += 4 * width;
+ while (node.x > 0) node.x -= width;
+ }
+ node.dy += node.delta;
+ if (node.dy >= 1) {
+ node.delta = -0.001;
+ } else if (node.dy <= 0) {
+ node.delta = 0.001;
+ }
+ if (node.y + 3 * height <= core._PY_) {
+ node.y += 4 * height;
+ while (node.y > 0) node.y -= height;
+ }
+ else if (node.y >= 0) {
+ node.y -= height;
+ }
+ for (var i = 0; i < 3; ++i) {
+ for (var j = 0; j < 3; ++j) {
+ if (node.x + (i + 1) * width <= 0 || node.x + i * width >= core._PX_
+ || node.y + (j + 1) * height <= 0 || node.y + j * height >= core._PY_)
+ continue;
+ core.drawImage('weather', image, node.x + i * width, node.y + j * height);
+ }
+ }
+ core.setAlpha('weather', 1);
+ core.animateFrame.weather.time = timestamp;
+}
+
+control.prototype._animationFrame_weather_sun = function (timestamp, level) {
+ if (timestamp - core.animateFrame.weather.time < 30) return;
+ var node = core.animateFrame.weather.nodes[0];
+ var opacity = node.opacity + node.delta;
+ if (opacity > level / 10 + 0.3 || opacity < level / 10 - 0.3)
+ node.delta = -node.delta;
+ node.opacity = opacity;
+ core.setOpacity('weather', core.clamp(opacity, 0, 1));
+ core.animateFrame.weather.time = timestamp;
+}
+
+control.prototype._animateFrame_tip = function (timestamp) {
+ if (core.animateFrame.tip == null) return;
+ var tip = core.animateFrame.tip;
+ if (timestamp - tip.time <= 30) return;
+ var delta = timestamp - tip.time;
+ tip.time = timestamp;
+
+ core.setFont('data', "16px Arial");
+ core.setTextAlign('data', 'left');
+ core.clearMap('data', 0, 0, core._PX_, 50);
+ core.ui._drawTip_drawOne(tip);
+ if (tip.stage == 1) {
+ tip.opacity += 0.05;
+ if (tip.opacity >= 0.6) {
+ tip.stage = 2;
+ tip.displayTime = 0;
+ }
+ } else if (tip.stage == 2) {
+ tip.displayTime += delta;
+ if (tip.displayTime >= 1000) tip.stage = 3;
+ } else tip.opacity -= 0.05;
+
+ if (tip.opacity <= 0) {
+ core.animateFrame.tip = null;
+ }
+}
+
+control.prototype._animationFrame_parallelDo = function (timestamp) {
+ core.control.controldata.parallelDo(timestamp);
+}
+
+// ------ 标题界面的处理 ------ //
+
+////// 显示游戏开始界面 //////
+control.prototype.showStartAnimate = function (noAnimate, callback) {
+ this._showStartAnimate_resetDom();
+ if (core.flags.startUsingCanvas || noAnimate)
+ return this._showStartAnimate_finished(core.flags.startUsingCanvas, callback);
+ core.hideWithAnimate(core.dom.startTop, 20, function () {
+ core.control._showStartAnimate_finished(false, callback);
+ });
+}
+
+control.prototype._showStartAnimate_resetDom = function () {
+ core.dom.startPanel.style.opacity = 1;
+ core.dom.startPanel.style.display = "block";
+ core.dom.startTop.style.opacity = 1;
+ core.dom.startTop.style.display = "block";
+ core.dom.startButtonGroup.style.display = 'none';
+ core.dom.startButtons.style.display = 'block';
+ core.dom.levelChooseButtons.style.display = 'none';
+ core.status.played = false;
+ core.clearStatus();
+ core.clearMap('all');
+ core.dom.musicBtn.style.display = 'block';
+ core.setMusicBtn();
+ // 重置音量
+ core.events.setVolume(1, 0);
+ core.updateStatusBar();
+}
+
+control.prototype._showStartAnimate_finished = function (start, callback) {
+ core.dom.startTop.style.display = 'none';
+ core.dom.startButtonGroup.style.display = 'block';
+ main.selectedButton = null;
+ main.selectButton(0);
+ if (start) core.startGame();
+ if (callback) callback();
+}
+
+////// 隐藏游戏开始界面 //////
+control.prototype.hideStartAnimate = function (callback) {
+ core.hideWithAnimate(core.dom.startPanel, 20, callback);
+}
+
+////// 游戏是否已经开始 //////
+control.prototype.isPlaying = function () {
+ return core.status.played;
+}
+
+////// 清除游戏状态和数据 //////
+control.prototype.clearStatus = function () {
+ // 停止各个Timeout和Interval
+ for (var i in core.timeout) {
+ clearTimeout(core.timeout[i]);
+ core.timeout[i] = null;
+ }
+ for (var i in core.interval) {
+ clearInterval(core.interval[i]);
+ core.interval[i] = null;
+ }
+ core.status = {};
+ core.clearStatusBar();
+ core.deleteAllCanvas();
+ core.status.played = false;
+}
+
+control.prototype._initStatistics = function (totalTime) {
+ if (!core.isset(core.status.hero.statistics))
+ core.status.hero.statistics = {
+ 'totalTime': totalTime,
+ 'currTime': 0,
+ 'hp': 0,
+ "battle": 0,
+ 'money': 0,
+ 'exp': 0,
+ 'battleDamage': 0,
+ 'poisonDamage': 0,
+ 'extraDamage': 0,
+ 'moveDirectly': 0,
+ 'ignoreSteps': 0,
+ }
+}
+
+// ------ 自动寻路,人物行走 ------ //
+
+////// 清除自动寻路路线 //////
+control.prototype.clearAutomaticRouteNode = function (x, y) {
+ core.clearMap('route', x * 32 + 5 - core.status.automaticRoute.offsetX, y * 32 + 5 - core.status.automaticRoute.offsetY, 27, 27);
+}
+
+////// 停止自动寻路操作 //////
+control.prototype.stopAutomaticRoute = function () {
+ if (!core.status.played) return;
+ core.status.automaticRoute.autoHeroMove = false;
+ core.status.automaticRoute.autoStep = 0;
+ core.status.automaticRoute.destStep = 0;
+ core.status.automaticRoute.movedStep = 0;
+ core.status.automaticRoute.autoStepRoutes = [];
+ core.status.automaticRoute.destX = null;
+ core.status.automaticRoute.destY = null;
+ core.status.automaticRoute.lastDirection = null;
+ core.status.heroStop = true;
+ if (core.status.automaticRoute.moveStepBeforeStop.length == 0)
+ core.deleteCanvas('route');
+}
+
+////// 保存剩下的寻路,并停止 //////
+control.prototype.saveAndStopAutomaticRoute = function () {
+ var automaticRoute = core.status.automaticRoute;
+ if (automaticRoute.moveStepBeforeStop.length == 0) {
+ automaticRoute.moveStepBeforeStop = automaticRoute.autoStepRoutes.slice(automaticRoute.autoStep - 1);
+ if (automaticRoute.moveStepBeforeStop.length >= 1)
+ automaticRoute.moveStepBeforeStop[0].step -= automaticRoute.movedStep;
+ }
+ this.stopAutomaticRoute();
+}
+
+////// 继续剩下的自动寻路操作 //////
+control.prototype.continueAutomaticRoute = function () {
+ // 此函数只应由events.afterOpenDoor和events.afterBattle调用
+ var moveStep = core.status.automaticRoute.moveStepBeforeStop;
+ //core.status.automaticRoute.moveStepBeforeStop = [];
+ if (moveStep.length === 0 || (moveStep.length === 1 && moveStep[0].step === 1)) {
+ core.status.automaticRoute.moveStepBeforeStop = [];
+ }
+ else {
+ core.setAutoHeroMove(moveStep);
+ }
+}
+
+////// 清空剩下的自动寻路列表 //////
+control.prototype.clearContinueAutomaticRoute = function (callback) {
+ core.deleteCanvas('route');
+ core.status.automaticRoute.moveStepBeforeStop = [];
+ if (callback) callback();
+}
+
+////// 设置自动寻路路线 //////
+control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) {
+ if (!core.status.played || core.status.lockControl) return;
+ if (this._setAutomaticRoute_isMoving(destX, destY)) return;
+ if (this._setAutomaticRoute_isTurning(destX, destY, stepPostfix)) return;
+ if (this._setAutomaticRoute_clickMoveDirectly(destX, destY, stepPostfix)) return;
+ // 找寻自动寻路路线
+ var moveStep = core.automaticRoute(destX, destY);
+ if (moveStep.length == 0 && (destX != core.status.hero.loc.x || destY != core.status.hero.loc.y || stepPostfix.length == 0))
+ return;
+ moveStep = moveStep.concat(stepPostfix);
+ core.status.automaticRoute.destX = destX;
+ core.status.automaticRoute.destY = destY;
+ this._setAutomaticRoute_drawRoute(moveStep);
+ this._setAutomaticRoute_setAutoSteps(moveStep);
+ // 立刻移动
+ core.setAutoHeroMove();
+}
+
+control.prototype._setAutomaticRoute_isMoving = function (destX, destY) {
+ if (core.status.automaticRoute.autoHeroMove) {
+ var lastX = core.status.automaticRoute.destX, lastY = core.status.automaticRoute.destY;
+ core.stopAutomaticRoute();
+ // 双击瞬移
+ if (lastX == destX && lastY == destY) {
+ core.status.automaticRoute.moveDirectly = true;
+ setTimeout(function () {
+ if (core.status.automaticRoute.moveDirectly && core.status.heroMoving == 0) {
+ core.control.tryMoveDirectly(destX, destY);
+ }
+ core.status.automaticRoute.moveDirectly = false;
+ }, core.values.moveSpeed);
+ }
+ return true;
+ }
+ return false;
+}
+
+control.prototype._setAutomaticRoute_isTurning = function (destX, destY, stepPostfix) {
+ if (destX == core.status.hero.loc.x && destY == core.status.hero.loc.y && stepPostfix.length == 0) {
+ if (core.timeout.turnHeroTimeout == null) {
+ var routeLength = core.status.route.length;
+ core.timeout.turnHeroTimeout = setTimeout(function () {
+ if (core.status.route.length == routeLength) core.turnHero();
+ clearTimeout(core.timeout.turnHeroTimeout);
+ core.timeout.turnHeroTimeout = null;
+ }, 250);
+ }
+ else {
+ clearTimeout(core.timeout.turnHeroTimeout);
+ core.timeout.turnHeroTimeout = null;
+ core.getNextItem();
+ }
+ return true;
+ }
+ if (core.timeout.turnHeroTimeout != null) return true;
+ return false;
+}
+
+control.prototype._setAutomaticRoute_clickMoveDirectly = function (destX, destY, stepPostfix) {
+ // 单击瞬间移动
+ if (core.status.heroStop && core.status.heroMoving == 0) {
+ if (stepPostfix.length <= 1 && !core.hasFlag('__noClickMove__') && core.control.tryMoveDirectly(destX, destY))
+ return true;
+ }
+ return false;
+}
+
+control.prototype._setAutomaticRoute_drawRoute = function (moveStep) {
+ // 计算绘制区域的宽高,并尽可能小的创建route层
+ var sx = core.bigmap.width * 32, sy = core.bigmap.height * 32, dx = 0, dy = 0;
+ moveStep.forEach(function (t) {
+ sx = Math.min(sx, t.x * 32); dx = Math.max(dx, t.x * 32);
+ sy = Math.min(sy, t.y * 32); dy = Math.max(dy, t.y * 32);
+ });
+ core.status.automaticRoute.offsetX = sx;
+ core.status.automaticRoute.offsetY = sy;
+ var ctx = core.createCanvas('route', sx - core.bigmap.offsetX, sy - core.bigmap.offsetY, dx - sx + 32, dy - sy + 32, 95);
+ ctx.fillStyle = '#bfbfbf';
+ ctx.strokeStyle = '#bfbfbf';
+ ctx.lineWidth = 8;
+ for (var m = 0; m < moveStep.length; m++) {
+ if (m == moveStep.length - 1) {
+ ctx.fillRect(moveStep[m].x * 32 + 10 - sx, moveStep[m].y * 32 + 10 - sy, 12, 12);
+ }
+ else {
+ ctx.beginPath();
+ var cx = moveStep[m].x * 32 + 16 - sx, cy = moveStep[m].y * 32 + 16 - sy;
+ var currDir = moveStep[m].direction, nextDir = moveStep[m + 1].direction;
+ ctx.moveTo(cx - core.utils.scan[currDir].x * 11, cy - core.utils.scan[currDir].y * 11);
+ ctx.lineTo(cx, cy);
+ ctx.lineTo(cx + core.utils.scan[nextDir].x * 11, cy + core.utils.scan[nextDir].y * 11);
+ ctx.stroke();
+ }
+ }
+}
+
+control.prototype._setAutomaticRoute_setAutoSteps = function (moveStep) {
+ // 路线转autoStepRoutes
+ var step = 0, currStep = null;
+ moveStep.forEach(function (t) {
+ var dir = t.direction;
+ if (currStep == null || currStep == dir)
+ step++;
+ else {
+ core.status.automaticRoute.autoStepRoutes.push({ 'direction': currStep, 'step': step });
+ step = 1;
+ }
+ currStep = dir;
+ });
+ core.status.automaticRoute.autoStepRoutes.push({ 'direction': currStep, 'step': step });
+}
+
+////// 设置勇士的自动行走路线 //////
+control.prototype.setAutoHeroMove = function (steps) {
+ steps = steps || core.status.automaticRoute.autoStepRoutes;
+ if (steps.length == 0) return;
+ core.status.automaticRoute.autoStepRoutes = steps;
+ core.status.automaticRoute.autoHeroMove = true;
+ core.status.automaticRoute.autoStep = 1;
+ core.status.automaticRoute.destStep = steps[0].step;
+ core.moveHero(steps[0].direction);
+}
+
+////// 设置行走的效果动画 //////
+control.prototype.setHeroMoveInterval = function (callback) {
+ if (core.status.heroMoving > 0) return;
+ if (core.status.replay.speed == 24) {
+ if (callback) callback();
+ return;
+ }
+
+ core.status.heroMoving = 1;
+
+ var toAdd = 1;
+ if (core.status.replay.speed > 3) toAdd = 2;
+ if (core.status.replay.speed > 6) toAdd = 4;
+ if (core.status.replay.speed > 12) toAdd = 8;
+
+ core.interval.heroMoveInterval = window.setInterval(function () {
+ core.status.heroMoving += toAdd;
+ if (core.status.heroMoving >= 8) {
+ clearInterval(core.interval.heroMoveInterval);
+ core.status.heroMoving = 0;
+ if (callback) callback();
+ }
+ }, core.values.moveSpeed / 8 * toAdd / core.status.replay.speed);
+}
+
+////// 每移动一格后执行的事件 //////
+control.prototype.moveOneStep = function (callback) {
+ return this.controldata.moveOneStep(callback);
+}
+
+////// 实际每一步的行走过程 //////
+control.prototype.moveAction = function (callback) {
+ if (core.status.heroMoving > 0) return;
+ var noPass = core.noPass(core.nextX(), core.nextY()), canMove = core.canMoveHero();
+ // 下一个点如果不能走
+ if (noPass || !canMove) return this._moveAction_noPass(canMove, callback);
+ this._moveAction_moving(callback);
+}
+
+control.prototype._moveAction_noPass = function (canMove, callback) {
+ core.status.route.push(core.getHeroLoc('direction'));
+ core.status.automaticRoute.moveStepBeforeStop = [];
+ core.status.automaticRoute.lastDirection = core.getHeroLoc('direction');
+ if (canMove) core.trigger(core.nextX(), core.nextY());
+ core.drawHero();
+
+ if (core.status.automaticRoute.moveStepBeforeStop.length == 0) {
+ core.clearContinueAutomaticRoute();
+ core.stopAutomaticRoute();
+ }
+ if (callback) callback();
+}
+
+control.prototype._moveAction_moving = function (callback) {
+ core.setHeroMoveInterval(function () {
+ core.setHeroLoc('x', core.nextX(), true);
+ core.setHeroLoc('y', core.nextY(), true);
+
+ var direction = core.getHeroLoc('direction');
+ core.control._moveAction_popAutomaticRoute();
+ core.status.route.push(direction);
+
+ core.moveOneStep();
+ core.checkRouteFolding();
+ if (callback) callback();
+ });
+}
+
+control.prototype._moveAction_popAutomaticRoute = function () {
+ var automaticRoute = core.status.automaticRoute;
+ // 检查自动寻路是否被弹出
+ if (automaticRoute.autoHeroMove) {
+ automaticRoute.movedStep++;
+ automaticRoute.lastDirection = core.getHeroLoc('direction');
+ if (automaticRoute.destStep == automaticRoute.movedStep) {
+ if (automaticRoute.autoStep == automaticRoute.autoStepRoutes.length) {
+ core.clearContinueAutomaticRoute();
+ core.stopAutomaticRoute();
+ }
+ else {
+ automaticRoute.movedStep = 0;
+ automaticRoute.destStep = automaticRoute.autoStepRoutes[automaticRoute.autoStep].step;
+ core.setHeroLoc('direction', automaticRoute.autoStepRoutes[automaticRoute.autoStep].direction);
+ core.status.automaticRoute.autoStep++;
+ }
+ }
+ }
+}
+
+////// 让勇士开始移动 //////
+control.prototype.moveHero = function (direction, callback) {
+ // 如果正在移动,直接return
+ if (core.status.heroMoving != 0) return;
+ if (core.isset(direction))
+ core.setHeroLoc('direction', direction);
+
+ if (callback) return this.moveAction(callback);
+ this._moveHero_moving();
+}
+
+control.prototype._moveHero_moving = function () {
+ // ------ 我已经看不懂这个函数了,反正好用就行23333333
+ core.status.heroStop = false;
+ core.status.automaticRoute.moveDirectly = false;
+ var move = function () {
+ if (!core.status.heroStop) {
+ if (core.hasFlag('debug') && core.status.ctrlDown) {
+ if (core.status.heroMoving != 0) return;
+ // 检测是否穿出去
+ var nx = core.nextX(), ny = core.nextY();
+ if (nx < 0 || nx >= core.bigmap.width || ny < 0 || ny >= core.bigmap.height) return;
+ core.eventMoveHero([core.getHeroLoc('direction')], core.values.moveSpeed, move);
+ }
+ else {
+ core.moveAction();
+ setTimeout(move, 50);
+ }
+ }
+ }
+ move();
+}
+
+////// 当前是否正在移动 //////
+control.prototype.isMoving = function () {
+ return !core.status.heroStop || core.status.heroMoving > 0;
+}
+
+////// 停止勇士的一切行动,等待勇士行动结束后,再执行callback //////
+control.prototype.waitHeroToStop = function (callback) {
+ var lastDirection = core.status.automaticRoute.lastDirection;
+ core.stopAutomaticRoute();
+ core.clearContinueAutomaticRoute();
+ if (callback) {
+ core.status.replay.animate = true;
+ core.lockControl();
+ core.status.automaticRoute.moveDirectly = false;
+ setTimeout(function () {
+ core.status.replay.animate = false;
+ if (core.isset(lastDirection))
+ core.setHeroLoc('direction', lastDirection);
+ core.drawHero();
+ callback();
+ }, core.status.replay.speed == 24 ? 1 : 30);
+ }
+}
+
+////// 转向 //////
+control.prototype.turnHero = function (direction) {
+ if (direction) {
+ core.setHeroLoc('direction', direction);
+ core.drawHero();
+ core.status.route.push("turn:" + direction);
+ return;
+ }
+ core.setHeroLoc('direction', core.turnDirection(':right'));
+ core.drawHero();
+ core.status.route.push("turn");
+ core.checkRouteFolding();
+}
+
+////// 瞬间移动 //////
+control.prototype.moveDirectly = function (destX, destY, ignoreSteps) {
+ return this.controldata.moveDirectly(destX, destY, ignoreSteps);
+}
+
+////// 尝试瞬间移动 //////
+control.prototype.tryMoveDirectly = function (destX, destY) {
+ if (this.nearHero(destX, destY)) return false;
+ var canMoveArray = core.maps.generateMovableArray();
+ var dirs = [[destX, destY], [destX - 1, destY, "right"], [destX, destY - 1, "down"], [destX, destY + 1, "up"], [destX + 1, destY, "left"]];
+ var canMoveDirectlyArray = core.canMoveDirectlyArray(dirs, canMoveArray);
+
+ for (var i = 0; i < dirs.length; ++i) {
+ var d = dirs[i], dx = d[0], dy = d[1], dir = d[2];
+ if (dx < 0 || dx >= core.bigmap.width || dy < 0 || dy >= core.bigmap.height) continue;
+ if (dir && !core.inArray(canMoveArray[dx][dy], dir)) continue;
+ if (canMoveDirectlyArray[i] < 0) continue;
+ if (core.control.moveDirectly(dx, dy, canMoveDirectlyArray[i])) {
+ if (dir) core.moveHero(dir, function () { });
+ return true;
+ }
+ }
+ return false;
+}
+
+////// 绘制勇士 //////
+control.prototype.drawHero = function (status, offset, frame) {
+ if (!core.isPlaying() || !core.status.floorId || core.status.gameOver) return;
+ var x = core.getHeroLoc('x'), y = core.getHeroLoc('y'), direction = core.getHeroLoc('direction');
+ status = status || 'stop';
+ if (!offset) offset = 0;
+
+ var way = core.utils.scan2[direction];
+ var dx = way.x, dy = way.y;
+ var offsetX = typeof offset == 'number' ? dx * offset : (offset.x || 0);
+ var offsetY = typeof offset == 'number' ? dy * offset : (offset.y || 0);
+ offset = { x: offsetX, y: offsetY, offset: offset };
+
+ core.clearAutomaticRouteNode(x + dx, y + dy);
+ core.clearMap('hero');
+ core.status.heroCenter.px = 32 * x + offsetX + 16;
+ core.status.heroCenter.py = 32 * y + offsetY + 32 - core.material.icons.hero.height / 2;
+
+ // 重置hero层画布
+ core.setGameCanvasTranslate('hero', 0, 0);
+ delete core.canvas.hero._px;
+ delete core.canvas.hero._py;
+ core.status.preview.enabled = false;
+ if (!core.hasFlag('__lockViewport__')) {
+ this._drawHero_updateViewport(x, y, offset);
+ }
+
+ this._drawHero_draw(direction, x, y, status, offset, frame);
+}
+
+control.prototype._drawHero_updateViewport = function (x, y, offset) {
+ core.bigmap.offsetX = core.clamp((x - core._HALF_WIDTH_) * 32 + offset.x, 0, Math.max(32 * core.bigmap.width - core._PX_, 0));
+ core.bigmap.offsetY = core.clamp((y - core._HALF_HEIGHT_) * 32 + offset.y, 0, Math.max(32 * core.bigmap.height - core._PY_, 0));
+ core.control.updateViewport();
+}
+
+control.prototype._drawHero_draw = function (direction, x, y, status, offset, frame) {
+ offset = offset || { x: 0, y: 0, offset: 0, px: 0, py: 0 };
+ var opacity = core.setAlpha('hero', core.getFlag('__heroOpacity__', 1))
+ this._drawHero_getDrawObjs(direction, x, y, status, offset).forEach(function (block) {
+ core.drawImage('hero', block.img, (block.heroIcon[block.status] + (frame || 0)) % 4 * block.width,
+ block.heroIcon.loc * block.height, block.width, block.height,
+ block.posx + (32 - block.width) / 2, block.posy + 32 - block.height, block.width, block.height);
+ });
+ core.setAlpha('hero', opacity);
+}
+
+control.prototype._drawHero_getDrawObjs = function (direction, x, y, status, offset) {
+ var heroIconArr = core.material.icons.hero, drawObjs = [], index = 0;
+ drawObjs.push({
+ "img": core.material.images.hero,
+ "width": core.material.icons.hero.width || 32,
+ "height": core.material.icons.hero.height,
+ "heroIcon": heroIconArr[direction],
+ "posx": x * 32 - core.bigmap.offsetX + offset.x,
+ "posy": y * 32 - core.bigmap.offsetY + offset.y,
+ "status": status,
+ "index": index++,
+ });
+ if (typeof offset.offset == 'number') {
+ core.status.hero.followers.forEach(function (t) {
+ drawObjs.push({
+ "img": core.material.images.images[t.name],
+ "width": core.material.images.images[t.name].width / 4,
+ "height": core.material.images.images[t.name].height / 4,
+ "heroIcon": heroIconArr[t.direction],
+ "posx": 32 * t.x - core.bigmap.offsetX + (t.stop ? 0 : core.utils.scan2[t.direction].x * Math.abs(offset.offset)),
+ "posy": 32 * t.y - core.bigmap.offsetY + (t.stop ? 0 : core.utils.scan2[t.direction].y * Math.abs(offset.offset)),
+ "status": t.stop ? "stop" : status,
+ "index": index++
+ });
+ });
+ }
+ return drawObjs.sort(function (a, b) {
+ return a.posy == b.posy ? b.index - a.index : a.posy - b.posy;
+ });
+}
+
+control.prototype.setHeroOpacity = function (opacity, moveMode, time, callback) {
+ time = time || 0;
+ if (time == 0) {
+ core.setFlag('__heroOpacity__', opacity);
+ core.drawHero();
+ if (callback) callback();
+ return;
+ }
+ time /= Math.max(core.status.replay.speed, 1)
+
+ var fromOpacity = core.getFlag('__heroOpacity__', 1);
+ var step = 0, steps = parseInt(time / 10);
+ if (steps <= 0) steps = 1;
+ var moveFunc = core.applyEasing(moveMode);
+
+ var animate = setInterval(function () {
+ step++;
+ core.setFlag('__heroOpacity__', fromOpacity + (opacity - fromOpacity) * moveFunc(step / steps));
+ core.drawHero();
+ if (step == steps) {
+ delete core.animateFrame.asyncId[animate];
+ clearInterval(animate);
+ if (callback) callback();
+ }
+ }, 10);
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = callback;
+}
+
+// ------ 画布、位置、阻激夹域,显伤 ------ //
+
+////// 设置画布偏移
+control.prototype.setGameCanvasTranslate = function (canvas, x, y) {
+ var c = core.dom.gameCanvas[canvas];
+ x = x * core.domStyle.scale;
+ y = y * core.domStyle.scale;
+ c.style.transform = 'translate(' + x + 'px,' + y + 'px)';
+ c.style.webkitTransform = 'translate(' + x + 'px,' + y + 'px)';
+ c.style.OTransform = 'translate(' + x + 'px,' + y + 'px)';
+ c.style.MozTransform = 'translate(' + x + 'px,' + y + 'px)';
+ if (main.mode === 'editor' && editor.isMobile) {
+ c.style.transform = 'translate(' + (x / core._PX_ * 96) + 'vw,' + (y / core._PY_ * 96) + 'vw)';
+ c.style.webkitTransform = 'translate(' + (x / core._PX_ * 96) + 'vw,' + (y / core._PY_ * 96) + 'vw)';
+ c.style.OTransform = 'translate(' + (x / core._PX_ * 96) + 'vw,' + (y / core._PY_ * 96) + 'vw)';
+ c.style.MozTransform = 'translate(' + (x / core._PX_ * 96) + 'vw,' + (y / core._PY_ * 96) + 'vw)';
+ }
+};
+
+////// 加减画布偏移
+control.prototype.addGameCanvasTranslate = function (x, y) {
+ for (var ii = 0, canvas; canvas = core.dom.gameCanvas[ii]; ii++) {
+ var id = canvas.getAttribute('id');
+ if (id == 'ui' || id == 'data') continue; // UI层和data层不移动
+ var offsetX = x, offsetY = y;
+ if (core.bigmap.canvas.indexOf(id) >= 0) {
+ if (core.bigmap.v2) {
+ offsetX -= (core.bigmap.offsetX - 32 * core.bigmap.posX) + 32;
+ offsetY -= (core.bigmap.offsetY - 32 * core.bigmap.posY) + 32;
+ } else {
+ offsetX -= core.bigmap.offsetX;
+ offsetY -= core.bigmap.offsetY;
+ }
+ }
+ core.control.setGameCanvasTranslate(id, offsetX, offsetY);
+ }
+}
+
+////// 更新视野范围 //////
+control.prototype.updateViewport = function () {
+ // 当前是否应该重绘?
+ if (core.bigmap.v2) {
+ if (core.bigmap.offsetX >= core.bigmap.posX * 32 + 32
+ || core.bigmap.offsetX <= core.bigmap.posX * 32 - 32
+ || core.bigmap.offsetY >= core.bigmap.posY * 32 + 32
+ || core.bigmap.offsetY <= core.bigmap.posY * 32 - 32) {
+ core.bigmap.posX = parseInt(core.bigmap.offsetX / 32);
+ core.bigmap.posY = parseInt(core.bigmap.offsetY / 32);
+ core.redrawMap();
+ }
+ } else {
+ core.bigmap.posX = core.bigmap.posY = 0;
+ }
+ var offsetX = core.bigmap.v2 ? -(core.bigmap.offsetX - 32 * core.bigmap.posX) - 32 : -core.bigmap.offsetX;
+ var offsetY = core.bigmap.v2 ? -(core.bigmap.offsetY - 32 * core.bigmap.posY) - 32 : -core.bigmap.offsetY;
+
+ core.bigmap.canvas.forEach(function (cn) {
+ core.control.setGameCanvasTranslate(cn, offsetX, offsetY);
+ });
+ // ------ 路线
+ core.relocateCanvas('route', core.status.automaticRoute.offsetX - core.bigmap.offsetX, core.status.automaticRoute.offsetY - core.bigmap.offsetY);
+ // ------ 所有的大怪物也都需要重定位
+ for (var one in core.dymCanvas) {
+ if (one.startsWith('_bigImage_')) {
+ var ox = core.dymCanvas[one].canvas.getAttribute('_ox');
+ var oy = core.dymCanvas[one].canvas.getAttribute('_oy');
+ if (ox != null && oy != null) {
+ core.relocateCanvas(one, parseInt(ox) - core.bigmap.offsetX, parseInt(oy) - core.bigmap.offsetY);
+ }
+ }
+ }
+
+}
+
+////// 设置视野范围 //////
+control.prototype.setViewport = function (px, py) {
+ var originOffsetX = core.bigmap.offsetX, originOffsetY = core.bigmap.offsetY;
+ core.bigmap.offsetX = core.clamp(px, 0, 32 * core.bigmap.width - core._PX_);
+ core.bigmap.offsetY = core.clamp(py, 0, 32 * core.bigmap.height - core._PY_);
+ this.updateViewport();
+ // ------ hero层也需要!
+ var px = parseFloat(core.canvas.hero._px) || 0;
+ var py = parseFloat(core.canvas.hero._py) || 0;
+ px += originOffsetX - core.bigmap.offsetX;
+ py += originOffsetY - core.bigmap.offsetY;
+ core.control.setGameCanvasTranslate('hero', px, py);
+ core.canvas.hero._px = px;
+ core.canvas.hero._py = py;
+}
+
+////// 移动视野范围 //////
+control.prototype.moveViewport = function (x, y, moveMode, time, callback) {
+ time = time || 0;
+ time /= Math.max(core.status.replay.speed, 1)
+ var per_time = 10, step = 0, steps = parseInt(time / per_time);
+ if (steps <= 0) {
+ this.setViewport(32 * x, 32 * y);
+ if (callback) callback();
+ return;
+ }
+ var px = core.clamp(32 * x, 0, 32 * core.bigmap.width - core._PX_);
+ var py = core.clamp(32 * y, 0, 32 * core.bigmap.height - core._PY_);
+ var cx = core.bigmap.offsetX;
+ var cy = core.bigmap.offsetY;
+ var moveFunc = core.applyEasing(moveMode);
+
+ var animate = window.setInterval(function () {
+ step++;
+ core.setViewport(cx + moveFunc(step / steps) * (px - cx), cy + moveFunc(step / steps) * (py - cy));
+ if (step == steps) {
+ delete core.animateFrame.asyncId[animate];
+ clearInterval(animate);
+ core.setViewport(px, py);
+ if (callback) callback();
+ }
+ }, per_time);
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = callback;
+}
+
+////// 获得勇士面对位置的x坐标 //////
+control.prototype.nextX = function (n) {
+ if (n == null) n = 1;
+ return core.getHeroLoc('x') + core.utils.scan[core.getHeroLoc('direction')].x * n;
+}
+
+////// 获得勇士面对位置的y坐标 //////
+control.prototype.nextY = function (n) {
+ if (n == null) n = 1;
+ return core.getHeroLoc('y') + core.utils.scan[core.getHeroLoc('direction')].y * n;
+}
+
+////// 某个点是否在勇士旁边 //////
+control.prototype.nearHero = function (x, y, n) {
+ if (n == null) n = 1;
+ return Math.abs(x - core.getHeroLoc('x')) + Math.abs(y - core.getHeroLoc('y')) <= n;
+}
+
+////// 聚集跟随者 //////
+control.prototype.gatherFollowers = function () {
+ var x = core.getHeroLoc('x'), y = core.getHeroLoc('y'), dir = core.getHeroLoc('direction');
+ core.status.hero.followers.forEach(function (t) {
+ t.x = x;
+ t.y = y;
+ t.stop = true;
+ t.direction = dir;
+ });
+}
+
+////// 更新跟随者坐标 //////
+control.prototype.updateFollowers = function () {
+ core.status.hero.followers.forEach(function (t) {
+ if (!t.stop) {
+ t.x += core.utils.scan2[t.direction].x;
+ t.y += core.utils.scan2[t.direction].y;
+ }
+ })
+
+ var nowx = core.getHeroLoc('x'), nowy = core.getHeroLoc('y');
+ core.status.hero.followers.forEach(function (t) {
+ t.stop = true;
+ var dx = nowx - t.x, dy = nowy - t.y;
+ for (var dir in core.utils.scan2) {
+ if (core.utils.scan2[dir].x == dx && core.utils.scan2[dir].y == dy) {
+ t.stop = false;
+ t.direction = dir;
+ }
+ }
+ nowx = t.x; nowy = t.y;
+ })
+}
+
+////// 瞬移更新跟随者坐标 //////
+control.prototype._moveDirectyFollowers = function (x, y) {
+ var route = core.automaticRoute(x, y);
+ if (route.length == 0) route = [{ x: x, y: y, direction: core.getHeroLoc('direction') }];
+
+ var nowx = x, nowy = y;
+ for (var i = 0; i < core.status.hero.followers.length; ++i) {
+ var t = core.status.hero.followers[i];
+ var index = route.length - i - 2;
+ if (index < 0) index = 0;
+ t.stop = true;
+ t.x = route[index].x;
+ t.y = route[index].y;
+ t.direction = route[index].direction;
+ var dx = nowx - t.x, dy = nowy - t.y;
+ for (var dir in core.utils.scan2) {
+ if (core.utils.scan2[dir].x == dx && core.utils.scan2[dir].y == dy) {
+ t.stop = false;
+ t.direction = dir;
+ }
+ }
+ nowx = t.x; nowy = t.y;
+ }
+}
+
+////// 更新领域、夹击、阻击的伤害地图 //////
+control.prototype.updateCheckBlock = function (floorId) {
+ return this.controldata.updateCheckBlock(floorId);
+}
+
+////// 检查并执行领域、夹击、阻击事件 //////
+control.prototype.checkBlock = function () {
+ var x = core.getHeroLoc('x'), y = core.getHeroLoc('y'), loc = x + "," + y;
+ var damage = core.status.checkBlock.damage[loc];
+ if (damage) {
+ core.status.hero.hp -= damage;
+ var text = (Object.keys(core.status.checkBlock.type[loc] || {}).join(",")) || "伤害";
+ core.drawTip("受到" + text + damage + "点");
+ core.drawHeroAnimate("zone");
+ this._checkBlock_disableQuickShop();
+ core.status.hero.statistics.extraDamage += damage;
+ if (core.status.hero.hp <= 0) {
+ core.status.hero.hp = 0;
+ core.updateStatusBar(false, true);
+ core.events.lose();
+ return;
+ } else {
+ core.updateStatusBar(false, true);
+ }
+ }
+ this._checkBlock_ambush(core.status.checkBlock.ambush[loc]);
+ this._checkBlock_repulse(core.status.checkBlock.repulse[loc]);
+}
+
+control.prototype._checkBlock_disableQuickShop = function () {
+ // 禁用快捷商店
+ if (core.flags.disableShopOnDamage) {
+ Object.keys(core.status.shops).forEach(function (shopId) {
+ core.setShopVisited(shopId, false);
+ });
+ }
+}
+
+////// 阻击 //////
+control.prototype._checkBlock_repulse = function (repulse) {
+ if (!repulse || repulse.length == 0) return;
+ var actions = [];
+ repulse.forEach(function (t) {
+ actions.push({ "type": "move", "loc": [t[0], t[1]], "steps": [t[3]], "time": 250, "keep": true, "async": true });
+ });
+ actions.push({ "type": "waitAsync" });
+ core.insertAction(actions);
+}
+
+////// 捕捉 //////
+control.prototype._checkBlock_ambush = function (ambush) {
+ if (!ambush || ambush.length == 0) return;
+ // 捕捉效果
+ var actions = [];
+ ambush.forEach(function (t) {
+ actions.push({ "type": "move", "loc": [t[0], t[1]], "steps": [t[3]], "time": 250, "keep": false, "async": true });
+ });
+ actions.push({ "type": "waitAsync" });
+ // 强制战斗
+ ambush.forEach(function (t) {
+ actions.push({
+ "type": "function", "function": "function() { " +
+ "core.battle('" + t[2] + "', " + t[0] + "," + t[1] + ", true, core.doAction); " +
+ "}", "async": true
+ });
+ });
+ core.insertAction(actions);
+}
+
+////// 更新全地图显伤 //////
+control.prototype.updateDamage = function (floorId, ctx) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId || core.status.gameOver || main.mode != 'play') return;
+ var onMap = ctx == null;
+
+ // 没有怪物手册
+ if (!core.hasItem('book')) return;
+ core.status.damage.posX = core.bigmap.posX;
+ core.status.damage.posY = core.bigmap.posY;
+ if (!onMap) {
+ var width = core.floors[floorId].width, height = core.floors[floorId].height;
+ // 地图过大的缩略图不绘制显伤
+ if (width * height > core.bigmap.threshold) return;
+ }
+ this._updateDamage_damage(floorId, onMap);
+ this._updateDamage_extraDamage(floorId, onMap);
+ this.drawDamage(ctx);
+}
+
+control.prototype._updateDamage_damage = function (floorId, onMap) {
+ core.status.damage.data = [];
+ if (!core.flags.displayEnemyDamage && !core.flags.displayExtraDamage) return;
+
+ core.extractBlocks(floorId);
+ core.status.maps[floorId].blocks.forEach(function (block) {
+ var x = block.x, y = block.y;
+
+ // v2优化,只绘制范围内的部分
+ if (onMap && core.bigmap.v2) {
+ if (x < core.bigmap.posX - core.bigmap.extend || x > core.bigmap.posX + core._WIDTH_ + core.bigmap.extend
+ || y < core.bigmap.posY - core.bigmap.extend || y > core.bigmap.posY + core._HEIGHT_ + core.bigmap.extend) {
+ return;
+ }
+ }
+
+ if (!block.disable && block.event.cls.indexOf('enemy') == 0 && block.event.displayDamage !== false) {
+ if (core.flags.displayEnemyDamage) {
+ var damageString = core.enemys.getDamageString(block.event.id, x, y, floorId);
+ core.status.damage.data.push({ text: damageString.damage, px: 32 * x + 1, py: 32 * (y + 1) - 1, color: damageString.color });
+ }
+ if (core.flags.displayCritical) {
+ var critical = core.enemys.nextCriticals(block.event.id, 1, x, y, floorId);
+ critical = core.formatBigNumber((critical[0] || [])[0], true);
+ if (critical == '???') critical = '?';
+ core.status.damage.data.push({ text: critical, px: 32 * x + 1, py: 32 * (y + 1) - 11, color: '#FFFFFF' });
+ }
+ }
+ });
+}
+
+control.prototype._updateDamage_extraDamage = function (floorId, onMap) {
+ core.status.damage.extraData = [];
+ if (!core.flags.displayExtraDamage) return;
+
+ var width = core.floors[floorId].width, height = core.floors[floorId].height;
+ var startX = onMap && core.bigmap.v2 ? Math.max(0, core.bigmap.posX - core.bigmap.extend) : 0;
+ var endX = onMap && core.bigmap.v2 ? Math.min(width, core.bigmap.posX + core._WIDTH_ + core.bigmap.extend + 1) : width;
+ var startY = onMap && core.bigmap.v2 ? Math.max(0, core.bigmap.posY - core.bigmap.extend) : 0;
+ var endY = onMap && core.bigmap.v2 ? Math.min(height, core.bigmap.posY + core._HEIGHT_ + core.bigmap.extend + 1) : height;
+
+ for (var x = startX; x < endX; x++) {
+ for (var y = startY; y < endY; y++) {
+ var alpha = 1;
+ if (core.noPass(x, y, floorId)) {
+ if (core.flags.extraDamageType == 2) alpha = 0;
+ else if (core.flags.extraDamageType == 1) alpha = 0.6;
+ }
+ var damage = core.status.checkBlock.damage[x + "," + y] || 0;
+ if (damage > 0) { // 该点伤害
+ damage = core.formatBigNumber(damage, true);
+ core.status.damage.extraData.push({ text: damage, px: 32 * x + 16, py: 32 * (y + 1) - 14, color: '#ffaa33', alpha: alpha });
+ }
+ else { // 检查捕捉
+ if (core.status.checkBlock.ambush[x + "," + y]) {
+ core.status.damage.extraData.push({ text: '!', px: 32 * x + 16, py: 32 * (y + 1) - 14, color: '#ffaa33', alpha: alpha });
+ }
+ }
+ }
+ }
+}
+
+////// 重绘地图显伤 //////
+control.prototype.drawDamage = function (ctx) {
+ if (core.status.gameOver || !core.status.damage || main.mode != 'play') return;
+ var onMap = false;
+ if (ctx == null) {
+ ctx = core.canvas.damage;
+ core.clearMap('damage');
+ onMap = true;
+ }
+
+ if (onMap && core.bigmap.v2) {
+ // 检查是否需要重算...
+ if (Math.abs(core.bigmap.posX - core.status.damage.posX) >= core.bigmap.extend - 1
+ || Math.abs(core.bigmap.posY - core.status.damage.posY) >= core.bigmap.extend - 1) {
+ return this.updateDamage();
+ }
+ }
+ return this._drawDamage_draw(ctx, onMap);
+}
+
+control.prototype._drawDamage_draw = function (ctx, onMap) {
+ if (!core.hasItem('book')) return;
+
+ core.setFont(ctx, "bold 11px Arial");
+ core.setTextAlign(ctx, 'left');
+ core.status.damage.data.forEach(function (one) {
+ var px = one.px, py = one.py;
+ if (onMap && core.bigmap.v2) {
+ px -= core.bigmap.posX * 32;
+ py -= core.bigmap.posY * 32;
+ if (px < -32 * 2 || px > core._PX_ + 32 || py < -32 || py > core._PY_ + 32)
+ return;
+ }
+ core.fillBoldText(ctx, one.text, px, py, one.color);
+ });
+
+ core.setTextAlign(ctx, 'center');
+ core.status.damage.extraData.forEach(function (one) {
+ var px = one.px, py = one.py;
+ if (onMap && core.bigmap.v2) {
+ px -= core.bigmap.posX * 32;
+ py -= core.bigmap.posY * 32;
+ if (px < -32 || px > core._PX_ + 32 || py < -32 || py > core._PY_ + 32)
+ return;
+ }
+ var alpha = core.setAlpha(ctx, one.alpha);
+ core.fillBoldText(ctx, one.text, px, py, one.color);
+ core.setAlpha(ctx, alpha);
+ });
+}
+
+// ------ 录像相关 ------ //
+
+////// 选择录像文件 //////
+control.prototype.chooseReplayFile = function () {
+ core.readFile(function (obj) {
+ if (obj.name != core.firstData.name) return alert("存档和游戏不一致!");
+ if (!obj.route) return alert("无效的录像!");
+ var _replay = function () {
+ core.startGame(core.flags.startUsingCanvas ? '' : obj.hard || '', obj.seed, core.decodeRoute(obj.route));
+ }
+ if (obj.version && obj.version != core.firstData.version) {
+ core.myconfirm("游戏版本不一致!\n你仍然想播放录像吗?", _replay);
+ return;
+ }
+ _replay();
+ }, null, ".h5route");
+}
+
+////// 开始播放 //////
+control.prototype.startReplay = function (list) {
+ if (!core.isPlaying()) return;
+ core.status.replay.replaying = true;
+ core.status.replay.pausing = true;
+ core.status.replay.failed = false;
+ core.status.replay.speed = 1.0;
+ core.status.replay.toReplay = core.cloneArray(list);
+ core.status.replay.totalList = core.status.route.concat(list);
+ core.status.replay.steps = 0;
+ core.status.replay.save = [];
+ core.createCanvas('replay', 0, core._PY_ - 40, core._PX_, 40, 199);
+ core.setOpacity('replay', 0.6);
+ this._replay_drawProgress();
+ core.updateStatusBar(false, true);
+ core.drawTip("开始播放");
+ this.replay();
+}
+
+////// 更改播放状态 //////
+control.prototype.triggerReplay = function () {
+ if (core.status.replay.pausing) this.resumeReplay();
+ else this.pauseReplay();
+}
+
+////// 暂停播放 //////
+control.prototype.pauseReplay = function () {
+ if (!core.isPlaying() || !core.isReplaying()) return;
+ core.status.replay.pausing = true;
+ core.updateStatusBar(false, true);
+ core.drawTip("暂停播放");
+}
+
+////// 恢复播放 //////
+control.prototype.resumeReplay = function () {
+ if (!core.isPlaying() || !core.isReplaying()) return;
+ if (core.isMoving() || core.status.replay.animate || core.status.event.id) {
+ core.playSound('操作失败');
+ return core.drawTip("请等待当前事件的处理结束");
+ }
+ core.status.replay.pausing = false;
+ core.updateStatusBar(false, true);
+ core.drawTip("恢复播放");
+ core.replay();
+}
+
+////// 单步播放 //////
+control.prototype.stepReplay = function () {
+ if (!core.isPlaying() || !core.isReplaying()) return;
+ if (!core.status.replay.pausing) {
+ core.playSound('操作失败');
+ return core.drawTip("请先暂停录像");
+ }
+ if (core.isMoving() || core.status.replay.animate || core.status.event.id) {
+ core.playSound('操作失败');
+ return core.drawTip("请等待当前事件的处理结束");
+ }
+ core.replay(true);
+}
+
+////// 加速播放 //////
+control.prototype.speedUpReplay = function () {
+ if (!core.isPlaying() || !core.isReplaying()) return;
+ var speeds = [0.2, 0.5, 1, 2, 3, 6, 12, 24];
+ for (var i = speeds.length - 2; i >= 0; i--) {
+ if (speeds[i] <= core.status.replay.speed) {
+ core.status.replay.speed = speeds[i + 1];
+ break;
+ }
+ }
+ core.drawTip("x" + core.status.replay.speed + "倍");
+}
+
+////// 减速播放 //////
+control.prototype.speedDownReplay = function () {
+ if (!core.isPlaying() || !core.isReplaying()) return;
+ var speeds = [0.2, 0.5, 1, 2, 3, 6, 12, 24];
+ for (var i = 1; i <= speeds.length; i++) {
+ if (speeds[i] >= core.status.replay.speed) {
+ core.status.replay.speed = speeds[i - 1];
+ break;
+ }
+ }
+ core.drawTip("x" + core.status.replay.speed + "倍");
+}
+
+////// 设置播放速度 //////
+control.prototype.setReplaySpeed = function (speed) {
+ if (!core.isPlaying() || !core.isReplaying()) return;
+ core.status.replay.speed = speed;
+ core.drawTip("x" + core.status.replay.speed + "倍");
+}
+
+////// 停止播放 //////
+control.prototype.stopReplay = function (force) {
+ if (!core.isPlaying()) return;
+ if (!core.isReplaying() && !force) return;
+ core.status.replay.toReplay = [];
+ core.status.replay.totalList = [];
+ core.status.replay.replaying = false;
+ core.status.replay.pausing = false;
+ core.status.replay.failed = false;
+ core.status.replay.speed = 1.0;
+ core.status.replay.steps = 0;
+ core.status.replay.save = [];
+ core.deleteCanvas('replay');
+ core.updateStatusBar(false, true);
+ core.drawTip("停止播放并恢复游戏");
+}
+
+////// 回退 //////
+control.prototype.rewindReplay = function () {
+ if (!core.isPlaying() || !core.isReplaying()) return;
+ if (!core.status.replay.pausing) {
+ core.playSound('操作失败');
+ return core.drawTip("请先暂停录像");
+ }
+ if (core.isMoving() || core.status.replay.animate || core.status.event.id) {
+ core.playSound('操作失败');
+ return core.drawTip("请等待当前事件的处理结束");
+ }
+ if (core.status.replay.save.length == 0) {
+ core.playSound('操作失败');
+ return core.drawTip("无法再回到上一个节点");
+ }
+ var save = core.status.replay.save, data = save.pop();
+ core.loadData(data.data, function () {
+ core.removeFlag('__fromLoad__');
+ core.status.replay = {
+ "replaying": true,
+ "pausing": true,
+ "animate": false,
+ "toReplay": data.replay.toReplay,
+ "totalList": data.replay.totalList,
+ "speed": core.status.replay.speed,
+ "steps": data.replay.steps,
+ "save": save
+ }
+ core.createCanvas('replay', 0, core._PY_ - 40, core._PX_, 40, 199);
+ core.setOpacity('replay', 0.6);
+ core.control._replay_drawProgress();
+ core.updateStatusBar(false, true);
+ core.drawTip("成功回退到上一个节点");
+ });
+}
+
+////// 回放时存档 //////
+control.prototype._replay_SL = function () {
+ if (!core.isPlaying() || !core.isReplaying()) return;
+ if (!core.status.replay.pausing) {
+ core.playSound('操作失败');
+ return core.drawTip("请先暂停录像");
+ }
+ if (core.isMoving() || core.status.replay.animate || core.status.event.id) {
+ core.playSound('操作失败');
+ return core.drawTip("请等待当前事件的处理结束");
+ }
+ if (core.hasFlag('__forbidSave__')) {
+ core.playSound('操作失败');
+ return core.drawTip('当前禁止存档');
+ }
+ this._replay_hideProgress();
+
+ core.lockControl();
+ core.status.event.id = 'save';
+ var saveIndex = core.saves.saveIndex;
+ var page = parseInt((saveIndex - 1) / 5), offset = saveIndex - 5 * page;
+
+ core.ui._drawSLPanel(10 * page + offset);
+}
+
+////// 回放时查看怪物手册 //////
+control.prototype._replay_book = function () {
+ if (!core.isPlaying() || !core.isReplaying()) return;
+ if (!core.status.replay.pausing) {
+ core.playSound('操作失败');
+ return core.drawTip("请先暂停录像");
+ }
+ if (core.isMoving() || core.status.replay.animate || (core.status.event.id && core.status.event.id != 'viewMaps')) {
+ core.playSound('操作失败');
+ return core.drawTip("请等待当前事件的处理结束");
+ }
+ if (!core.hasItem('book')) {
+ core.playSound('操作失败');
+ return core.drawTip('你没有' + core.material.items['book'].name, 'book');
+ }
+ this._replay_hideProgress();
+
+ // 从“浏览地图”页面打开
+ if (core.status.event.id == 'viewMaps')
+ core.status.event.ui = core.status.event.data;
+
+ core.lockControl();
+ core.status.event.id = 'book';
+ core.useItem('book', true);
+}
+
+////// 回放录像时浏览地图 //////
+control.prototype._replay_viewMap = function () {
+ if (!core.isPlaying() || !core.isReplaying()) return;
+ if (!core.status.replay.pausing) {
+ core.playSound('操作失败');
+ return core.drawTip("请先暂停录像");
+ }
+ if (core.isMoving() || core.status.replay.animate || core.status.event.id) {
+ core.playSound('操作失败');
+ return core.drawTip("请等待当前事件的处理结束");
+ }
+ this._replay_hideProgress();
+
+ core.lockControl();
+ core.status.event.id = 'viewMaps';
+ core.ui._drawViewMaps();
+}
+
+control.prototype._replay_toolbox = function () {
+ if (!core.isPlaying() || !core.isReplaying()) return;
+ if (!core.status.replay.pausing) {
+ core.playSound('操作失败');
+ return core.drawTip("请先暂停录像");
+ }
+ if (core.isMoving() || core.status.replay.animate || core.status.event.id) {
+ core.playSound('操作失败');
+ return core.drawTip("请等待当前事件的处理结束");
+ }
+ this._replay_hideProgress();
+
+ core.lockControl();
+ core.status.event.id = 'toolbox';
+ core.ui._drawToolbox();
+}
+
+control.prototype._replay_equipbox = function () {
+ if (!core.isPlaying() || !core.isReplaying()) return;
+ if (!core.status.replay.pausing) {
+ core.playSound('操作失败');
+ return core.drawTip("请先暂停录像");
+ }
+ if (core.isMoving() || core.status.replay.animate || core.status.event.id) {
+ core.playSound('操作失败');
+ return core.drawTip("请等待当前事件的处理结束");
+ }
+ this._replay_hideProgress();
+
+ core.lockControl();
+ core.status.event.id = 'equipbox';
+ core.ui._drawEquipbox();
+}
+
+////// 是否正在播放录像 //////
+control.prototype.isReplaying = function () {
+ return (core.status.replay || {}).replaying;
+}
+
+////// 回放 //////
+control.prototype.replay = function (force) {
+ if (!core.isPlaying() || !core.isReplaying()
+ || core.status.replay.animate || core.status.event.id || core.status.replay.failed) return;
+ if (core.status.replay.pausing && !force) return;
+ this._replay_drawProgress();
+ if (core.status.replay.toReplay.length == 0)
+ return this._replay_finished();
+ this._replay_save();
+ var action = core.status.replay.toReplay.shift();
+ if (this._doReplayAction(action)) return;
+ this._replay_error(action);
+}
+
+////// 注册一个录像行为 //////
+// name:自定义名称,可用于注销使用
+// func:具体执行录像的函数,可为一个函数或插件中的函数名;
+// 需要接受一个action参数,代表录像回放时的下一个操作
+// func返回true代表成功处理了此录像行为,false代表没有处理此录像行为。
+control.prototype.registerReplayAction = function (name, func) {
+ this.unregisterReplayAction(name);
+ this.replayActions.push({ name: name, func: func });
+}
+
+////// 注销一个录像行为 //////
+control.prototype.unregisterReplayAction = function (name) {
+ this.replayActions = this.replayActions.filter(function (b) { return b.name != name; });
+}
+
+////// 执行录像行为,会在注册的函数中依次执行直到得到true为止 //////
+control.prototype._doReplayAction = function (action) {
+ for (var i in this.replayActions) {
+ try {
+ if (core.doFunc(this.replayActions[i].func, this, action)) return true;
+ } catch (e) {
+ console.error(e);
+ console.error("ERROR in replayActions[" + this.replayActions[i].name + "]:已自动注销该项。");
+ core.unregisterReplayAction(this.replayActions[i].name);
+ }
+ }
+ return false;
+}
+
+control.prototype._replay_finished = function () {
+ core.status.replay.replaying = false;
+ core.status.replay.failed = false;
+ core.status.event.selection = 0;
+ var str = "录像播放完毕,你想退出播放吗?";
+ if (core.status.route.length != core.status.replay.totalList.length
+ || core.subarray(core.status.route, core.status.replay.totalList) == null) {
+ str = "录像播放完毕,但记录不一致。\n请检查录像播放时的二次记录问题。\n你想退出播放吗?";
+ }
+ core.ui.drawConfirmBox(str, function () {
+ core.ui.closePanel();
+ core.stopReplay(true);
+ }, function () {
+ core.status.replay.replaying = true;
+ core.ui.closePanel();
+ core.pauseReplay();
+ });
+}
+
+control.prototype._replay_save = function () {
+ core.status.replay.steps++;
+ if (core.status.replay.steps % 40 == 1) {
+ if (core.status.replay.save.length == 30)
+ core.status.replay.save.shift();
+ core.status.replay.save.push({
+ "data": core.saveData(), "replay": {
+ "totalList": core.cloneArray(core.status.replay.totalList),
+ "toReplay": core.cloneArray(core.status.replay.toReplay),
+ "steps": core.status.replay.steps
+ }
+ });
+ }
+}
+
+control.prototype._replay_error = function (action, callback) {
+ core.ui.closePanel();
+ core.status.replay.replaying = false;
+ core.status.replay.failed = true;
+ var len = core.status.replay.toReplay.length;
+ var prevList = core.status.replay.totalList.slice(-len - 11, -len - 1);
+ var nextList = core.status.replay.toReplay.slice(0, 10);
+ console.log("录像文件出错,当前操作:" + action);
+ console.log("之前的10个操作是:\n" + prevList.toString());
+ console.log("接下来10个操作是:\n" + nextList.toString());
+ core.ui.drawConfirmBox("录像文件出错,你想回到上个节点吗?", function () {
+ core.status.replay.failed = false;
+ core.ui.closePanel();
+ if (core.status.replay.save.length > 0) {
+ core.status.replay.replaying = true;
+ core.status.replay.pausing = true;
+ core.rewindReplay();
+ }
+ else {
+ core.playSound('操作失败');
+ core.stopReplay(true);
+ core.drawTip("无法回到上一个节点");
+ if (callback) callback();
+ }
+ }, function () {
+ core.status.replay.failed = false;
+ core.ui.closePanel();
+ core.stopReplay(true);
+ if (callback) callback();
+ });
+}
+
+control.prototype._replay_hideProgress = function () {
+ if (core.dymCanvas.replay) core.dymCanvas.replay.canvas.style.display = 'none';
+}
+
+control.prototype._replay_drawProgress = function () {
+ if (!core.dymCanvas.replay) return;
+ if (core.dymCanvas.replay.canvas.style.display == 'none') core.dymCanvas.replay.canvas.style.display = 'block';
+ var total = core.status.replay.totalList.length, left = total - core.status.replay.toReplay.length;
+ var content = '播放进度:' + left + ' / ' + total + '(' + (left / total * 100).toFixed(2) + '%)';
+ var width = 26 + core.calWidth('replay', content, "16px Arial");
+ core.clearMap('replay');
+ core.fillRect('replay', 0, 0, width, 40, '#000000');
+ core.fillText('replay', content, 16, 27, '#FFFFFF');
+}
+
+control.prototype.__replay_getTimeout = function () {
+ if (core.status.replay.speed == 24) return 0;
+ return 750 / Math.max(1, core.status.replay.speed);
+}
+
+control.prototype._replayAction_move = function (action) {
+ if (["up", "down", "left", "right"].indexOf(action) < 0) return false;
+ core.moveHero(action, core.replay);
+ return true;
+}
+
+control.prototype._replayAction_item = function (action) {
+ if (action.indexOf("item:") != 0) return false;
+ var itemId = action.substring(5);
+ if (!core.canUseItem(itemId)) return false;
+ if (core.material.items[itemId].hideInReplay || core.status.replay.speed == 24) {
+ core.useItem(itemId, false, core.replay);
+ return true;
+ }
+ var tools = core.getToolboxItems('tools'),
+ constants = core.getToolboxItems('constants');
+ var index, per = core._WIDTH_ - 1;
+ if ((index = tools.indexOf(itemId)) >= 0) {
+ core.status.event.data = { "toolsPage": Math.floor(index / per) + 1, "constantsPage": 1 };
+ index = index % per;
+ }
+ else if ((index = constants.indexOf(itemId)) >= 0) {
+ core.status.event.data = { "toolsPage": 1, "constantsPage": Math.floor(index / per) + 1 };
+ index = index % per + per;
+ }
+ if (index < 0) return false;
+ core.ui._drawToolbox(index);
+ setTimeout(function () {
+ core.ui.closePanel();
+ core.useItem(itemId, false, core.replay);
+ }, core.control.__replay_getTimeout());
+ return true;
+}
+
+control.prototype._replayAction_equip = function (action) {
+ if (action.indexOf("equip:") != 0) return false;
+ var equipId = action.substring(6);
+ var ownEquipment = core.getToolboxItems('equips');
+ var index = ownEquipment.indexOf(equipId), per = core._WIDTH_ - 1;
+ if (index < 0) {
+ core.removeFlag('__doNotCheckAutoEvents__');
+ return false;
+ }
+
+ var cb = function () {
+ var next = core.status.replay.toReplay[0] || "";
+ if (!next.startsWith('equip:') && !next.startsWith('unEquip:')) {
+ core.removeFlag('__doNotCheckAutoEvents__');
+ core.checkAutoEvents();
+ }
+ core.replay();
+ }
+ core.setFlag('__doNotCheckAutoEvents__', true);
+
+ core.status.route.push(action);
+ if (core.material.items[equipId].hideInReplay || core.status.replay.speed == 24) {
+ core.loadEquip(equipId, cb);
+ return true;
+ }
+ core.status.event.data = { "page": Math.floor(index / per) + 1, "selectId": null };
+ index = index % per + per;
+ core.ui._drawEquipbox(index);
+ setTimeout(function () {
+ core.ui.closePanel();
+ core.loadEquip(equipId, cb);
+ }, core.control.__replay_getTimeout());
+ return true;
+}
+
+control.prototype._replayAction_unEquip = function (action) {
+ if (action.indexOf("unEquip:") != 0) return false;
+ var equipType = parseInt(action.substring(8));
+ if (!core.isset(equipType)) {
+ core.removeFlag('__doNotCheckAutoEvents__');
+ return false;
+ }
+
+ var cb = function () {
+ var next = core.status.replay.toReplay[0] || "";
+ if (!next.startsWith('equip:') && !next.startsWith('unEquip:')) {
+ core.removeFlag('__doNotCheckAutoEvents__');
+ core.checkAutoEvents();
+ }
+ core.replay();
+ }
+ core.setFlag('__doNotCheckAutoEvents__', true);
+
+ core.ui._drawEquipbox(equipType);
+ core.status.route.push(action);
+ if (core.status.replay.speed == 24) {
+ core.unloadEquip(equipType, cb);
+ return true;
+ }
+ setTimeout(function () {
+ core.ui.closePanel();
+ core.unloadEquip(equipType, cb);
+ }, core.control.__replay_getTimeout());
+ return true;
+}
+
+control.prototype._replayAction_saveEquip = function (action) {
+ if (action.indexOf('saveEquip:') != 0) return false;
+ core.quickSaveEquip(parseInt(action.substring(10)));
+ core.replay();
+ return true;
+}
+
+control.prototype._replayAction_loadEquip = function (action) {
+ if (action.indexOf('loadEquip:') != 0) return false;
+ core.quickLoadEquip(parseInt(action.substring(10)));
+ core.replay();
+ return true;
+}
+
+control.prototype._replayAction_fly = function (action) {
+ if (action.indexOf("fly:") != 0) return false;
+ var floorId = action.substring(4);
+ var toIndex = core.floorIds.indexOf(floorId);
+ if (!core.canUseItem('fly') || (core.flags.flyNearStair && !core.nearStair())) return false;
+ core.ui.drawFly(toIndex);
+ if (core.status.replay.speed == 24) {
+ if (!core.flyTo(floorId, core.replay))
+ core.control._replay_error(action);
+ return true;
+ }
+ setTimeout(function () {
+ if (!core.flyTo(floorId, core.replay))
+ core.control._replay_error(action);
+ }, core.control.__replay_getTimeout());
+ return true;
+}
+
+control.prototype._replayAction_shop = function (action) {
+ if (action.indexOf("shop:") != 0) return false;
+ var shopId = action.substring(5);
+ if (core.canUseQuickShop(shopId) != null || !core.canOpenShop(shopId)) {
+ this._replay_error(shopId);
+ return true;
+ }
+ core.openShop(shopId, false);
+ core.replay();
+ return true;
+}
+
+control.prototype._replayAction_turn = function (action) {
+ if (action != 'turn' && action.indexOf('turn:') != 0) return false;
+ if (action == 'turn') core.turnHero();
+ else core.turnHero(action.substring(5));
+ core.replay();
+ return true;
+}
+
+control.prototype._replayAction_getNext = function (action) {
+ if (action != "getNext") return false;
+ core.getNextItem();
+ core.replay();
+ return true;
+}
+
+control.prototype._replayAction_moveDirectly = function (action) {
+ if (action.indexOf("move:") != 0) return false;
+ // 忽略连续的瞬移事件;如果大地图某一边超过计算范围则不合并
+ if (!core.hasFlag('poison') && core.status.thisMap.width < 2 * core.bigmap.extend + core._WIDTH_
+ && core.status.thisMap.height < 2 * core.bigmap.extend + core._HEIGHT_) {
+ while (core.status.replay.toReplay.length > 0 &&
+ core.status.replay.toReplay[0].indexOf('move:') == 0) {
+ core.status.route.push(action);
+ action = core.status.replay.toReplay.shift();
+ }
+ }
+
+ var pos = action.substring(5).split(":");
+ var x = parseInt(pos[0]), y = parseInt(pos[1]);
+ var nowx = core.getHeroLoc('x'), nowy = core.getHeroLoc('y');
+ var ignoreSteps = core.canMoveDirectly(x, y);
+ if (!core.moveDirectly(x, y, ignoreSteps)) return false;
+ if (core.status.replay.speed == 24) {
+ core.replay();
+ return true;
+ }
+
+ core.ui.drawArrow('ui', 32 * nowx + 16 - core.bigmap.offsetX, 32 * nowy + 16 - core.bigmap.offsetY,
+ 32 * x + 16 - core.bigmap.offsetX, 32 * y + 16 - core.bigmap.offsetY, '#FF0000', 3);
+ var timeout = this.__replay_getTimeout();
+ if (ignoreSteps < 10) timeout = timeout * ignoreSteps / 10;
+ setTimeout(function () {
+ core.clearMap('ui');
+ core.replay();
+ }, timeout);
+ return true;
+}
+
+control.prototype._replayAction_key = function (action) {
+ if (action.indexOf("key:") != 0) return false;
+ core.actions.keyUp(parseInt(action.substring(4)), false, true);
+ core.replay();
+ return true;
+}
+
+control.prototype._replayAction_click = function (action) {
+ if (action.indexOf("click:") != 0) return false;
+ var p = action.split(":");
+ if (p.length != 4) return false;
+ core.actions.doRegisteredAction("onStatusBarClick", parseInt(p[2]), parseInt(p[3]), parseInt(p[1]));
+ core.replay();
+ return true;
+}
+
+control.prototype._replayAction_ignoreInput = function (action) {
+ if (action.indexOf('input:') == 0 || action.indexOf('input2:') == 0 || action.indexOf('choices:') == 0 || action.indexOf('random:') == 0) {
+ console.warn('警告!录像播放中出现了未知的 ' + action + '!');
+ core.replay();
+ return true;
+ }
+ return false;
+}
+
+control.prototype._replayAction_no = function (action) {
+ if (action != 'no') return false;
+ core.status.route.push(action);
+ core.replay();
+ return true;
+}
+
+// ------ 存读档相关 ------ //
+
+////// 自动存档 //////
+control.prototype.autosave = function (removeLast) {
+ if (core.hasFlag('__forbidSave__')) return;
+ var x = null;
+ if (removeLast) {
+ x = core.status.route.pop();
+ core.status.route.push("turn:" + core.getHeroLoc('direction'));
+ }
+ if (core.status.event.id == 'action' && !removeLast) // 事件中自动存档,读档后是否回到事件触发前
+ core.setFlag("__events__", core.clone(core.status.event.data));
+ if (core.saves.autosave.data == null) {
+ core.saves.autosave.data = [];
+ }
+ core.saves.autosave.data.splice(core.saves.autosave.now, 0, core.saveData());
+ core.saves.autosave.now += 1;
+ if (core.saves.autosave.data.length > core.saves.autosave.max) {
+ if (core.saves.autosave.now < core.saves.autosave.max / 2)
+ core.saves.autosave.data.pop();
+ else {
+ core.saves.autosave.data.shift();
+ core.saves.autosave.now = core.saves.autosave.now - 1;
+ }
+ }
+ core.saves.autosave.updated = true;
+ core.saves.ids[0] = true;
+ core.removeFlag("__events__");
+ if (removeLast) {
+ core.status.route.pop();
+ if (x) core.status.route.push(x);
+ }
+}
+
+/////// 实际进行自动存档 //////
+control.prototype.checkAutosave = function () {
+ if (!core.animateFrame || !core.saves || !core.saves.autosave) return;
+ core.setLocalStorage('totalTime', core.animateFrame.totalTime);
+ var autosave = core.saves.autosave;
+ if (autosave.data == null || !autosave.updated || !autosave.storage) return;
+ autosave.updated = false;
+ if (autosave.data.length >= 1) {
+ core.setLocalForage("autoSave", autosave.data[autosave.now - 1]);
+ }
+}
+
+////// 实际进行存读档事件 //////
+control.prototype.doSL = function (id, type) {
+ switch (type) {
+ case 'save': this._doSL_save(id); break;
+ case 'load': this._doSL_load(id, this._doSL_load_afterGet); break;
+ case 'reload': this._doSL_reload(id, this._doSL_load_afterGet); break;
+ case 'replayLoad': this._doSL_load(id, this._doSL_replayLoad_afterGet); break;
+ case 'replayRemain': this._doSL_load(id, this._doSL_replayRemain_afterGet); break;
+ case 'replaySince': this._doSL_load(id, this._doSL_replaySince_afterGet); break;
+ }
+}
+
+control.prototype._doSL_save = function (id) {
+ if (id == 'autoSave') {
+ core.playSound('操作失败');
+ return core.drawTip('不能覆盖自动存档!');
+ }
+ // 在事件中的存档
+ if (core.status.event.interval != null)
+ core.setFlag("__events__", core.status.event.interval);
+ var data = core.saveData();
+ if (core.isReplaying() && core.status.replay.toReplay.length > 0) {
+ data.__toReplay__ = core.encodeRoute(core.status.replay.toReplay);
+ }
+ core.setLocalForage("save" + id, data, function () {
+ core.saves.saveIndex = id;
+ core.setLocalStorage('saveIndex', core.saves.saveIndex);
+ // 恢复事件
+ if (!core.events.recoverEvents(core.status.event.interval))
+ core.ui.closePanel();
+ core.playSound('存档');
+ core.drawTip('存档成功!');
+ }, function (err) {
+ console.error(err);
+ alert("存档失败,错误信息:\n" + err);
+ });
+ core.removeFlag("__events__");
+ return;
+}
+
+control.prototype._doSL_load = function (id, callback) {
+ if (id == 'autoSave' && core.saves.autosave.data != null) {
+ core.saves.autosave.now -= 1;
+ var data = core.saves.autosave.data.splice(core.saves.autosave.now, 1)[0];
+ if (core.isPlaying() && !core.status.gameOver) {
+ core.control.autosave(0);
+ core.saves.autosave.now -= 1;
+ }
+ if (core.saves.autosave.now == 0) {
+ core.saves.autosave.data.unshift(core.clone(data));
+ core.saves.autosave.now += 1;
+ }
+ callback(id, data);
+ }
+ else {
+ core.getLocalForage(id == 'autoSave' ? id : "save" + id, null, function (data) {
+ if (id == 'autoSave' && data != null) {
+ core.saves.autosave.data = data;
+ if (!(core.saves.autosave.data instanceof Array)) {
+ core.saves.autosave.data = [core.saves.autosave.data];
+ }
+ core.saves.autosave.now = core.saves.autosave.data.length;
+ return core.control._doSL_load(id, callback);
+ }
+ callback(id, data);
+ }, function (err) {
+ console.error(err);
+ alert("无效的存档");
+ })
+ }
+ return;
+}
+
+control.prototype._doSL_reload = function (id, callback) {
+ if (core.saves.autosave.data != null && core.saves.autosave.now < core.saves.autosave.data.length) {
+ var data = core.saves.autosave.data.splice(core.saves.autosave.now, 1)[0];
+ core.control.autosave(false);
+ callback(id, data);
+ }
+ return;
+}
+
+control.prototype._doSL_load_afterGet = function (id, data) {
+ if (!data) return alert("无效的存档");
+ var _replay = function () {
+ core.startGame(data.hard, data.hero.flags.__seed__, core.decodeRoute(data.route));
+ };
+ if (data.version != core.firstData.version) {
+ core.myconfirm("存档版本不匹配!\n你想回放此存档的录像吗?\n可以随时停止录像播放以继续游戏。", _replay);
+ return;
+ }
+ if (data.hero.flags.__events__ && data.guid != core.getGuid()) {
+ core.myconfirm("此存档可能存在风险,你想要播放录像么?", _replay);
+ return;
+ }
+ core.ui.closePanel();
+ core.loadData(data, function () {
+ core.removeFlag('__fromLoad__');
+ core.drawTip("读档成功");
+ if (id != "autoSave") {
+ core.saves.saveIndex = id;
+ core.setLocalStorage('saveIndex', core.saves.saveIndex);
+ }
+ });
+}
+
+control.prototype._doSL_replayLoad_afterGet = function (id, data) {
+ if (!data) {
+ core.playSound('操作失败');
+ return core.drawTip("无效的存档");
+ }
+ if (data.version != core.firstData.version) {
+ core.playSound('操作失败');
+ return core.drawTip("存档版本不匹配");
+ }
+ if (data.hero.flags.__events__ && data.guid != core.getGuid()) {
+ core.playSound('操作失败');
+ return core.drawTip("此存档可能存在风险,无法读档");
+ }
+ var route = core.subarray(core.status.route, core.decodeRoute(data.route));
+ if (route == null) {
+ core.playSound('操作失败');
+ return core.drawTip("无法从此存档回放录像");
+ }
+ core.loadData(data, function () {
+ core.removeFlag('__fromLoad__');
+ core.startReplay(route);
+ core.drawTip("回退到存档节点");
+ });
+}
+
+control.prototype._doSL_replayRemain_afterGet = function (id, data) {
+ if (!data) {
+ core.playSound('操作失败');
+ return core.drawTip("无效的存档");
+ }
+ var route = core.decodeRoute(data.route);
+ if (core.status.tempRoute) {
+ var remainRoute = core.subarray(route, core.status.tempRoute);
+ if (remainRoute == null)
+ return alert("无法接续播放录像!\n该存档必须是前一个选择的存档的后续内容。");
+ delete core.status.tempRoute;
+ core.ui.closePanel();
+ core.startReplay(remainRoute);
+ core.drawTip("接续播放录像");
+ return;
+ }
+ else if (data.floorId != core.status.floorId || data.hero.loc.x != core.getHeroLoc('x') || data.hero.loc.y != core.getHeroLoc('y'))
+ return alert("楼层或坐标不一致!");
+
+ core.status.tempRoute = route;
+ core.ui.closePanel();
+ core.drawText("\t[步骤2]请选择第二个存档。\n\r[yellow]该存档必须是前一个存档的后续。\r\n将尝试播放到此存档。", function () {
+ core.status.event.id = 'replayRemain';
+ core.lockControl();
+ var saveIndex = core.saves.saveIndex;
+ var page = parseInt((saveIndex - 1) / 5), offset = saveIndex - 5 * page;
+ core.ui._drawSLPanel(10 * page + offset);
+ });
+}
+
+control.prototype._doSL_replaySince_afterGet = function (id, data) {
+ if (data.floorId != core.status.floorId || data.hero.loc.x != core.getHeroLoc('x') || data.hero.loc.y != core.getHeroLoc('y'))
+ return alert("楼层或坐标不一致!");
+ if (!data.__toReplay__) return alert('该存档没有剩余录像!');
+ core.ui.closePanel();
+ core.startReplay(core.decodeRoute(data.__toReplay__));
+ core.drawTip("播放存档剩余录像");
+ return;
+}
+
+////// 同步存档到服务器 //////
+control.prototype.syncSave = function (type) {
+ core.ui.drawWaiting("正在同步,请稍候...");
+ var callback = function (saves) {
+ core.control._syncSave_http(type, saves);
+ }
+ if (type == 'all') core.getAllSaves(callback);
+ else core.getSave(core.saves.saveIndex, callback);
+}
+
+control.prototype._syncSave_http = function (type, saves) {
+ if (!saves) return core.drawText("没有要同步的存档");
+ var formData = new FormData();
+ formData.append('type', 'save');
+ formData.append('name', core.firstData.name);
+ formData.append('data', LZString.compressToBase64(JSON.stringify(saves)));
+ formData.append('shorten', '1');
+
+ core.http("POST", "/games/sync.php", formData, function (data) {
+ var response = JSON.parse(data);
+ if (response.code < 0) {
+ core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:" + response.msg);
+ }
+ else {
+ core.drawText((type == 'all' ? "所有存档" : "存档" + core.saves.saveIndex) + "同步成功!\n\n您的存档编号+密码: \r[yellow]"
+ + response.code + response.msg
+ + "\r\n\n请牢记以上信息(如截图等),在从服务器\n同步存档时使用。\n\r[yellow]另外请注意,存档同步只会保存一个月的时间。\r")
+ }
+ }, function (e) {
+ core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:" + e);
+ })
+}
+
+////// 从服务器加载存档 //////
+control.prototype.syncLoad = function () {
+ core.myprompt("请输入存档编号+密码", null, function (idpassword) {
+ if (!idpassword) return core.ui._drawSyncSave();
+ if (!/^\d{6}\w{4}$/.test(idpassword) && !/^\d{4}\w{3}$/.test(idpassword)) {
+ core.drawText("不合法的存档编号+密码!");
+ return;
+ }
+ core.ui.drawWaiting("正在同步,请稍候...");
+ if (idpassword.length == 7) {
+ core.control._syncLoad_http(idpassword.substring(0, 4), idpassword.substring(4));
+ } else {
+ core.control._syncLoad_http(idpassword.substring(0, 6), idpassword.substring(6));
+ }
+ });
+}
+
+control.prototype._syncLoad_http = function (id, password) {
+ var formData = new FormData();
+ formData.append('type', 'load');
+ formData.append('name', core.firstData.name);
+ formData.append('id', id);
+ formData.append('password', password);
+
+ core.http("POST", "/games/sync.php", formData, function (data) {
+ var response = JSON.parse(data);
+ if (response.code == 0) {
+ var msg = null;
+ try {
+ msg = JSON.parse(LZString.decompressFromBase64(response.msg));
+ } catch (e) { }
+ if (!msg) {
+ try {
+ msg = JSON.parse(response.msg);
+ } catch (e) { }
+ }
+ if (msg) {
+ core.control._syncLoad_write(msg);
+ } else {
+ core.drawText("出错啦!\n存档解析失败!");
+ }
+ }
+ else {
+ core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:" + response.msg);
+ }
+ }, function (e) {
+ core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:" + e);
+ });
+}
+
+control.prototype._syncLoad_write = function (data) {
+ if (data instanceof Array) {
+ core.status.event.selection = 1;
+ core.ui.drawConfirmBox("所有本地存档都将被覆盖,确认?", function () {
+ for (var i = 1; i <= 5 * (main.savePages || 30); i++) {
+ if (i <= data.length)
+ core.setLocalForage("save" + i, data[i - 1]);
+ else if (core.saves.ids[i])
+ core.removeLocalForage("save" + i);
+ }
+ core.ui.closePanel();
+ core.drawText("同步成功!\n你的本地所有存档均已被覆盖。");
+ }, function () {
+ core.status.event.selection = 0;
+ core.ui._drawSyncSave();
+ });
+ }
+ else {
+ // 只覆盖单存档
+ core.setLocalForage("save" + core.saves.saveIndex, data, function () {
+ core.drawText("同步成功!\n单存档已覆盖至存档" + core.saves.saveIndex);
+ });
+ }
+}
+
+////// 存档到本地 //////
+control.prototype.saveData = function () {
+ return this.controldata.saveData();
+}
+
+////// 从本地读档 //////
+control.prototype.loadData = function (data, callback) {
+ return this.controldata.loadData(data, callback);
+}
+
+control.prototype.getSave = function (index, callback) {
+ if (index == 0) {
+ // --- 自动存档先从缓存中获取
+ if (core.saves.autosave.data != null)
+ callback(core.saves.autosave.data);
+ else {
+ core.getLocalForage("autoSave", null, function (data) {
+ if (data != null) {
+ core.saves.autosave.data = data;
+ if (!(core.saves.autosave.data instanceof Array)) {
+ core.saves.autosave.data = [core.saves.autosave.data];
+ }
+ core.saves.autosave.now = core.saves.autosave.data.length;
+ }
+ callback(core.saves.autosave.data);
+ }, function (err) {
+ console.error(err);
+ callback(null);
+ });
+ }
+ return;
+ }
+ core.getLocalForage("save" + index, null, function (data) {
+ if (callback) callback(data);
+ }, function (err) {
+ console.error(err);
+ if (callback) callback(null);
+ });
+}
+
+control.prototype.getSaves = function (ids, callback) {
+ if (!(ids instanceof Array)) return this.getSave(ids, callback);
+ var count = ids.length, data = {};
+ for (var i = 0; i < ids.length; ++i) {
+ (function (i) {
+ core.getSave(ids[i], function (result) {
+ data[i] = result;
+ if (Object.keys(data).length == count)
+ callback(data);
+ })
+ })(i);
+ }
+}
+
+control.prototype.getAllSaves = function (callback) {
+ var ids = Object.keys(core.saves.ids).filter(function (x) { return x != 0; })
+ .sort(function (a, b) { return a - b; }), saves = [];
+ this.getSaves(ids, function (data) {
+ for (var i = 0; i < ids.length; ++i) {
+ if (data[i] != null)
+ saves.push(data[i]);
+ }
+ callback(saves);
+ });
+}
+
+////// 获得所有存在存档的存档位 //////
+control.prototype.getSaveIndexes = function (callback) {
+ var indexes = {};
+ core.keysLocalForage(function (err, keys) {
+ if (err) {
+ console.error(err);
+ return callback(indexes);
+ }
+ keys.forEach(function (key) {
+ core.control._getSaveIndexes_getIndex(indexes, key);
+ });
+ callback(indexes);
+ });
+}
+
+control.prototype._getSaveIndexes_getIndex = function (indexes, name) {
+ var e = new RegExp('^' + core.firstData.name + "_(save\\d+|autoSave)$").exec(name);
+ if (e) {
+ if (e[1] == 'autoSave') indexes[0] = true;
+ else indexes[parseInt(e[1].substring(4))] = true;
+ }
+}
+
+////// 判断某个存档位是否存在存档 //////
+control.prototype.hasSave = function (index) {
+ return core.saves.ids[index] || false;
+}
+
+////// 删除某个存档
+control.prototype.removeSave = function (index, callback) {
+ if (index == 0 || index == "autoSave") {
+ index = "autoSave";
+ core.removeLocalForage(index, function () {
+ core.saves.autosave.data = null;
+ core.saves.autosave.updated = false;
+ if (callback) callback();
+ });
+ return;
+ }
+ core.removeLocalForage("save" + index, function () {
+ core.saves.favorite = core.saves.favorite.filter(function (i) { return core.hasSave(i); });
+ delete core.saves.favoriteName[index];
+ core.control._updateFavoriteSaves();
+ if (callback) callback();
+ }, function () {
+ core.playSound('操作失败');
+ core.drawTip("无法删除存档!");
+ if (callback) callback();
+ });
+}
+
+////// 读取收藏信息
+control.prototype._loadFavoriteSaves = function () {
+ core.saves.favorite = core.getLocalStorage("favorite", []);
+ // --- 移除不存在的收藏
+ core.saves.favorite = core.saves.favorite.filter(function (i) { return core.hasSave(i); });
+ core.saves.favoriteName = core.getLocalStorage("favoriteName", {});
+}
+
+control.prototype._updateFavoriteSaves = function () {
+ core.setLocalStorage("favorite", core.saves.favorite);
+ core.setLocalStorage("favoriteName", core.saves.favoriteName);
+}
+
+// ------ 属性,状态,位置,buff,变量,锁定控制等 ------ //
+
+////// 设置勇士属性 //////
+control.prototype.setStatus = function (name, value) {
+ if (!core.status.hero) return;
+ if (name == 'x' || name == 'y' || name == 'direction')
+ this.setHeroLoc(name, value);
+ else
+ core.status.hero[name] = value;
+}
+
+////// 增减勇士属性 //////
+control.prototype.addStatus = function (name, value) {
+ this.setStatus(name, this.getStatus(name) + value);
+}
+
+////// 获得勇士属性 //////
+control.prototype.getStatus = function (name) {
+ if (!core.status.hero) return null;
+ if (name == 'x' || name == 'y' || name == 'direction')
+ return this.getHeroLoc(name);
+ if (main.mode == 'editor' && !core.hasFlag('__statistics__')) {
+ return data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.hero[name];
+ }
+ return core.status.hero[name];
+}
+
+////// 从status中获得属性,如果不存在则从勇士属性中获取 //////
+control.prototype.getStatusOrDefault = function (status, name) {
+ if (status && name in status)
+ return Math.floor(status[name]);
+ return Math.floor(this.getStatus(name));
+}
+
+////// 获得勇士实际属性(增幅后的) //////
+control.prototype.getRealStatus = function (name) {
+ return this.getRealStatusOrDefault(null, name);
+}
+
+////// 从status中获得实际属性(增幅后的),如果不存在则从勇士属性中获取 //////
+control.prototype.getRealStatusOrDefault = function (status, name) {
+ return Math.floor(this.getStatusOrDefault(status, name) * this.getBuff(name));
+}
+
+////// 获得勇士原始属性(无装备和衰弱影响) //////
+control.prototype.getNakedStatus = function (name) {
+ var value = this.getStatus(name);
+ if (value == null) return value;
+ // 装备增幅
+ core.status.hero.equipment.forEach(function (v) {
+ if (!v || !(core.material.items[v] || {}).equip) return;
+ value -= core.material.items[v].equip.value[name] || 0;
+ });
+ // 衰弱扣除
+ if (core.hasFlag('weak') && core.values.weakValue >= 1 && (name == 'atk' || name == 'def')) {
+ value += core.values.weakValue;
+ }
+ return value;
+}
+
+////// 获得某个属性的名字 //////
+control.prototype.getStatusLabel = function (name) {
+ if (this.controldata.getStatusLabel) {
+ return this.controldata.getStatusLabel(name) || name;
+ }
+ return {
+ name: "名称", lv: "等级", hpmax: "生命上限", hp: "生命", manamax: "魔力上限", mana: "魔力",
+ atk: "攻击", def: "防御", mdef: "护盾", money: "金币", exp: "经验", point: "加点", steps: "步数"
+ }[name] || name;
+}
+
+////// 设置某个属性的增幅值 //////
+control.prototype.setBuff = function (name, value) {
+ // 仅保留三位有效buff值
+ value = parseFloat(value.toFixed(3));
+ this.setFlag('__' + name + '_buff__', value);
+}
+
+////// 加减某个属性的增幅值 //////
+control.prototype.addBuff = function (name, value) {
+ var buff = this.getBuff(name) + value;
+ // 仅保留三位有效buff值
+ buff = parseFloat(buff.toFixed(3));
+ this.setFlag('__' + name + '_buff__', buff);
+}
+
+////// 获得某个属性的增幅值 //////
+control.prototype.getBuff = function (name) {
+ return core.getFlag('__' + name + '_buff__', 1);
+}
+
+////// 获得或移除毒衰咒效果 //////
+control.prototype.triggerDebuff = function (action, type) {
+ return this.controldata.triggerDebuff(action, type);
+}
+
+////// 设置勇士的位置 //////
+control.prototype.setHeroLoc = function (name, value, noGather) {
+ if (!core.status.hero) return;
+ core.status.hero.loc[name] = value;
+ if ((name == 'x' || name == 'y') && !noGather) {
+ this.gatherFollowers();
+ }
+ core.ui.drawStatusBar();
+}
+
+////// 获得勇士的位置 //////
+control.prototype.getHeroLoc = function (name) {
+ if (!core.status.hero) return;
+ if (main.mode == 'editor') {
+ if (name == null) return data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.hero.loc;
+ return data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.hero.loc[name];
+ }
+ if (name == null) return core.status.hero.loc;
+ return core.status.hero.loc[name];
+}
+
+////// 获得某个等级的名称 //////
+control.prototype.getLvName = function (lv) {
+ if (!core.status.hero) return null;
+ if (lv == null) lv = core.status.hero.lv;
+ return ((core.firstData.levelUp || [])[lv - 1] || {}).title || lv;
+}
+
+////// 获得下个等级所需经验;如果不存在下个等级,返回null。 //////
+control.prototype.getNextLvUpNeed = function () {
+ if (!core.status.hero) return null;
+ if (core.status.hero.lv >= core.firstData.levelUp.length) return null;
+ var need = core.calValue(core.firstData.levelUp[core.status.hero.lv].need);
+ if (core.flags.statusBarItems.indexOf('levelUpLeftMode') >= 0)
+ return Math.max(need - core.getStatus('exp'), 0);
+ else return need;
+}
+
+////// 设置某个自定义变量或flag //////
+control.prototype.setFlag = function (name, value) {
+ if (value == null) return this.removeFlag(name);
+ if (!core.status.hero) return;
+ core.status.hero.flags[name] = value;
+}
+
+////// 增加某个flag数值 //////
+control.prototype.addFlag = function (name, value) {
+ if (!core.status.hero) return;
+ core.setFlag(name, core.getFlag(name, 0) + value);
+}
+
+////// 获得某个自定义变量或flag //////
+control.prototype.getFlag = function (name, defaultValue) {
+ if (!core.status.hero) return defaultValue;
+ var value = core.status.hero.flags[name];
+ return value != null ? value : defaultValue;
+}
+
+////// 是否存在某个自定义变量或flag,且值为true //////
+control.prototype.hasFlag = function (name) {
+ return !!core.getFlag(name);
+}
+
+////// 删除某个自定义变量或flag //////
+control.prototype.removeFlag = function (name) {
+ if (!core.status.hero) return;
+ delete core.status.hero.flags[name];
+}
+
+////// 获得某个点的独立开关 //////
+control.prototype.getSwitch = function (x, y, floorId, name, defaultValue) {
+ var prefix = [floorId || core.status.floorId || ":f", x != null ? x : "x", y != null ? y : "y"].join("@");
+ return this.getFlag(prefix + "@" + name, defaultValue);
+}
+
+////// 设置某个点的独立开关 //////
+control.prototype.setSwitch = function (x, y, floorId, name, value) {
+ var prefix = [floorId || core.status.floorId || ":f", x != null ? x : "x", y != null ? y : "y"].join("@");
+ return this.setFlag(prefix + "@" + name, value);
+}
+
+////// 增加某个点的独立开关 //////
+control.prototype.addSwitch = function (x, y, floorId, name, value) {
+ var prefix = [floorId || core.status.floorId || ":f", x != null ? x : "x", y != null ? y : "y"].join("@");
+ return this.addFlag(prefix + "@" + name, value);
+}
+
+////// 判定某个点的独立开关 //////
+control.prototype.hasSwitch = function (x, y, floorId, name) {
+ var prefix = [floorId || core.status.floorId || ":f", x != null ? x : "x", y != null ? y : "y"].join("@");
+ return this.hasFlag(prefix + "@" + name);
+}
+
+////// 删除某个点的独立开关 //////
+control.prototype.removeSwitch = function (x, y, floorId, name) {
+ var prefix = [floorId || core.status.floorId || ":f", x != null ? x : "x", y != null ? y : "y"].join("@");
+ return this.removeFlag(prefix + "@" + name);
+}
+
+////// 锁定状态栏,常常用于事件处理 //////
+control.prototype.lockControl = function () {
+ core.status.lockControl = true;
+}
+
+////// 解锁状态栏 //////
+control.prototype.unlockControl = function () {
+ core.status.lockControl = false;
+}
+
+////// 开启debug模式 //////
+control.prototype.debug = function () {
+ core.setFlag('debug', true);
+ core.drawText("\t[调试模式开启]此模式下按住Ctrl键(或Ctrl+Shift键)可以穿墙并忽略一切事件。\n此模式下将无法上传成绩。");
+}
+
+control.prototype._bindRoutePush = function () {
+ core.status.route.push = function (element) {
+ // 忽视移动、转向、瞬移
+ if (["up", "down", "left", "right", "turn"].indexOf(element) < 0 && !element.startsWith("move:")) {
+ core.clearRouteFolding();
+ }
+ Array.prototype.push.call(core.status.route, element);
+ }
+}
+
+////// 清除录像折叠信息 //////
+control.prototype.clearRouteFolding = function () {
+ core.status.routeFolding = {};
+}
+
+////// 检查录像折叠 //////
+control.prototype.checkRouteFolding = function () {
+ // 未开启、未开始游戏、录像播放中、正在事件中:不执行
+ if (!core.flags.enableRouteFolding || !core.isPlaying() || core.isReplaying() || core.status.event.id) {
+ return this.clearRouteFolding();
+ }
+ var hero = core.clone(core.status.hero, function (name, value) {
+ return name != 'steps' && typeof value == 'number';
+ });
+ var index = [core.getHeroLoc('x'), core.getHeroLoc('y'), core.getHeroLoc('direction').charAt(0)].join(',');
+ core.status.routeFolding = core.status.routeFolding || {};
+ if (core.status.routeFolding[index]) {
+ var one = core.status.routeFolding[index];
+ if (core.same(one.hero, hero) && one.length < core.status.route.length) {
+ Object.keys(core.status.routeFolding).forEach(function (v) {
+ if (core.status.routeFolding[v].length >= one.length) delete core.status.routeFolding[v];
+ });
+ core.status.route = core.status.route.slice(0, one.length);
+ this._bindRoutePush();
+ }
+ }
+ core.status.routeFolding[index] = { hero: hero, length: core.status.route.length };
+}
+
+// ------ 天气,色调,BGM ------ //
+
+control.prototype.getMappedName = function (name) {
+ return core.getFlag('__nameMap__', {})[name] || (main.nameMap || {})[name] || name;
+}
+
+////// 更改天气效果 //////
+control.prototype.setWeather = function (type, level) {
+ // 非雨雪
+ if (type == null || !this.weathers[type]) {
+ core.deleteCanvas('weather')
+ core.animateFrame.weather.type = null;
+ core.animateFrame.weather.nodes = [];
+ return;
+ }
+ if (level == null) level = core.animateFrame.weather.level;
+ level = core.clamp(parseInt(level) || 5, 1, 10);
+ // 当前天气:则忽略
+ if (type == core.animateFrame.weather.type && level == core.animateFrame.weather.level) return;
+
+ // 计算当前的宽高
+ core.createCanvas('weather', 0, 0, core._PX_, core._PY_, 80);
+ core.setOpacity('weather', 1.0);
+ core.animateFrame.weather.type = type;
+ core.animateFrame.weather.level = level;
+ core.animateFrame.weather.nodes = [];
+ try {
+ core.doFunc(this.weathers[type].initFunc, this, level);
+ } catch (e) {
+ console.error(e);
+ console.error("ERROR in weather[" + type + "]:已自动注销该项。");
+ core.unregisterWeather(type);
+ }
+}
+
+////// 注册一个天气 //////
+// name为天气类型,如 sun, rain, snow 等
+// initFunc 为设置为此天气时的初始化,接受level参数
+// frameFunc 为该天气下每帧的效果,接受和timestamp参数(从页面加载完毕到当前经过的时间)
+control.prototype.registerWeather = function (name, initFunc, frameFunc) {
+ this.unregisterWeather(name);
+ this.weathers[name] = { initFunc: initFunc, frameFunc: frameFunc };
+}
+
+////// 取消注册一个天气 //////
+control.prototype.unregisterWeather = function (name) {
+ delete this.weathers[name];
+ if (core.animateFrame.weather.type == name) {
+ this.setWeather(null);
+ }
+}
+
+control.prototype._weather_rain = function (level) {
+ var number = level * parseInt(20 * core.bigmap.width * core.bigmap.height / (core._WIDTH_ * core._HEIGHT_));
+ for (var a = 0; a < number; a++) {
+ core.animateFrame.weather.nodes.push({
+ 'x': Math.random() * core.bigmap.width * 32,
+ 'y': Math.random() * core.bigmap.height * 32,
+ 'l': Math.random() * 2.5,
+ 'xs': -4 + Math.random() * 4 + 2,
+ 'ys': Math.random() * 10 + 10
+ })
+ }
+}
+
+control.prototype._weather_snow = function (level) {
+ var number = level * parseInt(20 * core.bigmap.width * core.bigmap.height / (core._WIDTH_ * core._HEIGHT_));
+ for (var a = 0; a < number; a++) {
+ core.animateFrame.weather.nodes.push({
+ 'x': Math.random() * core.bigmap.width * 32,
+ 'y': Math.random() * core.bigmap.height * 32,
+ 'r': Math.random() * 5 + 1,
+ 'd': Math.random() * Math.min(level, 200),
+ })
+ }
+}
+
+control.prototype._weather_fog = function (level) {
+ if (!core.animateFrame.weather.fog) return;
+ core.animateFrame.weather.nodes = [{
+ 'image': core.animateFrame.weather.fog,
+ 'level': 40 * level,
+ 'x': 0,
+ 'y': -core._PY_ / 2,
+ 'dx': -Math.random() * 1.5,
+ 'dy': Math.random(),
+ 'delta': 0.001,
+ }];
+}
+
+control.prototype._weather_cloud = function (level) {
+ if (!core.animateFrame.weather.cloud) return;
+ core.animateFrame.weather.nodes = [{
+ 'image': core.animateFrame.weather.cloud,
+ 'level': 40 * level,
+ 'x': 0,
+ 'y': -core._PY_ / 2,
+ 'dx': -Math.random() * 1.5,
+ 'dy': Math.random(),
+ 'delta': 0.001,
+ }];
+}
+
+control.prototype._weather_sun = function (level) {
+ if (!core.animateFrame.weather.sun) return;
+ // 直接绘制
+ core.clearMap('weather');
+ core.drawImage(
+ 'weather', core.animateFrame.weather.sun, 0, 0, core.animateFrame.weather.sun.width, core.animateFrame.weather.sun.height, 0, 0, core._PX_, core._PY_
+ );
+ core.setOpacity('weather', level / 10);
+ core.animateFrame.weather.nodes = [{ opacity: level / 10, delta: 0.01 }];
+}
+
+////// 更改画面色调 //////
+control.prototype.setCurtain = function (color, time, moveMode, callback) {
+ if (time == null) time = 750;
+ if (time <= 0) time = 0;
+ if (!core.status.curtainColor)
+ core.status.curtainColor = [0, 0, 0, 0];
+ if (!color) color = [0, 0, 0, 0];
+ if (color[3] == null) color[3] = 1;
+ color[3] = core.clamp(color[3], 0, 1);
+
+ if (time == 0) {
+ // 直接变色
+ core.clearMap('curtain');
+ core.fillRect('curtain', 0, 0, core._PX_, core._PY_, core.arrayToRGBA(color));
+ core.status.curtainColor = color;
+ if (callback) callback();
+ return;
+ }
+
+ this._setCurtain_animate(core.status.curtainColor, color, time, moveMode, callback);
+}
+
+control.prototype._setCurtain_animate = function (nowColor, color, time, moveMode, callback) {
+ time /= Math.max(core.status.replay.speed, 1)
+ var per_time = 10, step = 0, steps = parseInt(time / per_time);
+ if (steps <= 0) steps = 1;
+ var curr = nowColor;
+ var moveFunc = core.applyEasing(moveMode);
+
+ var cb = function () {
+ core.status.curtainColor = curr;
+ if (callback) callback();
+ }
+ var animate = setInterval(function () {
+ step++;
+ curr = [
+ nowColor[0] + (color[0] - nowColor[0]) * moveFunc(step / steps),
+ nowColor[1] + (color[1] - nowColor[1]) * moveFunc(step / steps),
+ nowColor[2] + (color[2] - nowColor[2]) * moveFunc(step / steps),
+ nowColor[3] + (color[3] - nowColor[3]) * moveFunc(step / steps),
+ ]
+ core.clearMap('curtain');
+ core.fillRect('curtain', 0, 0, core._PX_, core._PY_, core.arrayToRGBA(curr));
+ if (step == steps) {
+ delete core.animateFrame.asyncId[animate];
+ clearInterval(animate);
+ cb();
+ }
+ }, per_time);
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = cb;
+}
+
+////// 画面闪烁 //////
+control.prototype.screenFlash = function (color, time, times, moveMode, callback) {
+ times = times || 1;
+ time = time / 3;
+ var nowColor = core.clone(core.status.curtainColor);
+ core.setCurtain(color, time, moveMode, function () {
+ core.setCurtain(nowColor, time * 2, moveMode, function () {
+ if (times > 1)
+ core.screenFlash(color, time * 3, times - 1, moveMode, callback);
+ else {
+ if (callback) callback();
+ }
+ });
+ });
+}
+
+////// 播放背景音乐 //////
+control.prototype.playBgm = function (bgm, startTime) {
+ bgm = core.getMappedName(bgm);
+ if (main.mode != 'play' || !core.material.bgms[bgm]) return;
+ // 如果不允许播放
+ if (!core.musicStatus.bgmStatus) {
+ try {
+ core.musicStatus.playingBgm = bgm;
+ core.musicStatus.lastBgm = bgm;
+ core.material.bgms[bgm].pause();
+ }
+ catch (e) {
+ console.error(e);
+ }
+ return;
+ }
+ this.setMusicBtn();
+
+ try {
+ this._playBgm_play(bgm, startTime);
+ }
+ catch (e) {
+ console.log("无法播放BGM " + bgm);
+ console.error(e);
+ core.musicStatus.playingBgm = null;
+ }
+}
+
+control.prototype._playBgm_play = function (bgm, startTime) {
+ // 如果当前正在播放,且和本BGM相同,直接忽略
+ if (core.musicStatus.playingBgm == bgm && !core.material.bgms[core.musicStatus.playingBgm].paused) {
+ return;
+ }
+ // 如果正在播放中,暂停
+ if (core.musicStatus.playingBgm) {
+ core.material.bgms[core.musicStatus.playingBgm].pause();
+ }
+ // 缓存BGM
+ core.loader.loadBgm(bgm);
+ // 播放当前BGM
+ core.material.bgms[bgm].volume = core.musicStatus.userVolume * core.musicStatus.designVolume;
+ core.material.bgms[bgm].currentTime = startTime || 0;
+ core.material.bgms[bgm].play();
+ core.musicStatus.playingBgm = bgm;
+ core.musicStatus.lastBgm = bgm;
+ core.setBgmSpeed(100);
+}
+
+///// 设置当前背景音乐的播放速度 //////
+control.prototype.setBgmSpeed = function (speed, usePitch) {
+ var bgm = core.musicStatus.playingBgm;
+ if (main.mode != 'play' || !core.material.bgms[bgm]) return;
+ bgm = core.material.bgms[bgm];
+ if (speed < 30 || speed > 300) return;
+ bgm.playbackRate = speed / 100;
+ core.musicStatus.bgmSpeed = speed;
+
+ if (bgm.preservesPitch != null) {
+ if (bgm.__preservesPitch == null) bgm.__preservesPitch = bgm.preservesPitch;
+ if (usePitch == null) bgm.preservesPitch = bgm.__preservesPitch;
+ else if (usePitch) bgm.preservesPitch = false;
+ else bgm.preservesPitch = true;
+ core.musicStatus.bgmUsePitch = usePitch;
+ }
+}
+
+////// 暂停背景音乐的播放 //////
+control.prototype.pauseBgm = function () {
+ if (main.mode != 'play') return;
+ try {
+ if (core.musicStatus.playingBgm) {
+ core.musicStatus.pauseTime = core.material.bgms[core.musicStatus.playingBgm].currentTime;
+ core.material.bgms[core.musicStatus.playingBgm].pause();
+ core.musicStatus.playingBgm = null;
+ }
+ }
+ catch (e) {
+ console.log("无法暂停BGM");
+ console.error(e);
+ }
+ this.setMusicBtn();
+}
+
+////// 恢复背景音乐的播放 //////
+control.prototype.resumeBgm = function (resumeTime) {
+ if (main.mode != 'play') return;
+ try {
+ var speed = core.musicStatus.bgmSpeed;
+ var usePitch = core.musicStatus.bgmUsePitch;
+ core.playBgm(core.musicStatus.playingBgm || core.musicStatus.lastBgm || main.startBgm,
+ resumeTime ? core.musicStatus.pauseTime : 0);
+ if (resumeTime) {
+ core.setBgmSpeed(speed, usePitch);
+ }
+ }
+ catch (e) {
+ console.log("无法恢复BGM");
+ console.error(e);
+ }
+ this.setMusicBtn();
+}
+
+control.prototype.setMusicBtn = function () {
+ if (core.musicStatus.bgmStatus)
+ core.dom.musicBtn.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAABWVBMVEX///9iYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmL///8AAAC5ubn+/v6xsbEtLS0MDAxmZmZoaGhvb2/c3Nzd3d38/Pz9/f0oKCgpKSl0dHR1dXW6urrb29v7+/v09PTv7+/39/cgICACAgImJibh4eGFhYWGhoaHh4eOjo5paWm7u7vDw8PMzMwyMjI7OztAQEDe3t5FRUVMTEzj4+Pl5eXm5ubp6enr6+tcXFzi4uL19fVeXl74+PgjIyNkZGQGBgaSkpKYmJiampqenp4DAwMwMDBnZ2cICAivr68eHh63t7cLCwsSEhLw8PBhYWEUFBQVFRXNzc3Pz8/Z2dna2toaGhqkpKSlpaWpqamrq6tFOUNAAAAAc3RSTlMAAwQFBhUWGxwkJSYyO0dISVBRUmpvj5CSk5SVoaOlpqiysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKyA0IuUgAAAVdJREFUeF5NkVVbw0AQRTcQrLR4IIEGcidJoaUuQHF3d3d3+P/CkuxCzss8nG++mbnDBJXhNt2CpbeFK1kQpSEKidlc8S9qdATRa6UIdQMoxEpDA0Ov3wUAPfW+qLWACydNv9zMrzkJwPK6FB3oHyOfXfuNxvoBQ+GmBYinhHB77TmiVBxoYUw1AYcEq332AS8OYKosAuTT0nza9uU2USYPRJgGxEiSOFywJ3mNARozgBJJzkfLvfu8JgGDWcC9FEsjWzR+y80gYDEAA8QZ3N6kmP1Fs3fEASB7pob7Hh+Wz5L0ci17Or05J7bH6B6dZv05XWK3rG+myV05Ert592Qo55sPuoIr7hEZHHtieIPWy0RU9DLwc3Mnck/vi8/E8XNrDWQtEVnL/ySKMrv0jPwPp870fprcyYifmiEmqGpHkI5q9ofSFIUk2qiwIGpEMyxYhhZRRcMPz89RJ2s9W8wAAAAASUVORK5CYII=";
+ else
+ core.dom.musicBtn.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAABYlBMVEX///9iYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmL////8/PwAAABmZmZoaGihoaGioqKxsbG5ubnb29vc3Nzd3d3h4eHi4uL9/f3+/v4tLS1nZ2d0dHSUlJSenp66uroMDAz7+/spKSkoKCgUFBRpaWkVFRVvb291dXU7OzuVlZWYmJhkZGQgICAjIyOkpKQCAgK3t7cGBgbv7++pqamrq6seHh4mJiZhYWGamprp6enr6+saGhpeXl7j4+Pl5eXm5uZKSkrw8PD09PT19fW7u7vDw8PMzMwICAgwMDAyMjILCwtAQECGhoaHh4eBgYGFhYUSEhJXV1dZWVlcXFyOjo6SkpLNzc339/fPz8/Z2dna2tqTk5OlpaWxOPeTAAAAdnRSTlMAAwQFBhUWGxwkJSYyO0dISVBRUmpvj5CSk5SVoaOlpqiysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKyNuo+uwAAAWJJREFUeF5NkmV34zAQReUm7WbTuJBNunY3bvXGDjNTkZkZlpn5/9eR5FPfbzr3jGb0RkwRiMQMDm7EIgHmRxtLwMOaHHoQjwz4MUKeCM8AWMrmd7u7f/aXAMyOShHiQD1n04DtN5e5FMBFlSauIsm585dKi4CpuSYKJIv1tBDVmvOSqJgEoowFLSBHaQh10XHWiCgHWEGmAw2blPrvOK/KRJUGoLM4kCVSKrWz7HwgoiwQZyaQJ0+9PvxV23BNATAZB25IqX9b3+jTW9fcApwB6NLgUD5NY3mPXnwmFwBezff1ztzRFzTp94FXMy36HDuCa2RafdnnmZqtL818Gl9/qNnEeyrUk2aTPiKj3qMyWBVi/YSuWq5qiwxkbtX3vYWzdz/l8M0k8ERlvViiB1Ygslb7SbVtJezncj+Cx5bYaeGuonZqhZlieAp+no74/s5EAh6JcY35Cepxk4ObcT3IJPe/1lKsDpFCFQAAAABJRU5ErkJggg==";
+}
+
+////// 更改背景音乐的播放 //////
+control.prototype.triggerBgm = function () {
+ if (main.mode != 'play') return;
+
+ core.musicStatus.bgmStatus = !core.musicStatus.bgmStatus;
+ if (core.musicStatus.bgmStatus)
+ this.resumeBgm();
+ else
+ this.pauseBgm();
+ core.setLocalStorage('bgmStatus', core.musicStatus.bgmStatus);
+}
+
+////// 播放音频 //////
+control.prototype.playSound = function (sound, pitch, callback) {
+ sound = core.getMappedName(sound);
+ if (main.mode != 'play' || !core.musicStatus.soundStatus || !core.material.sounds[sound]) return;
+ try {
+ if (core.musicStatus.audioContext != null) {
+ var source = core.musicStatus.audioContext.createBufferSource();
+ source.__name = sound;
+ source.buffer = core.material.sounds[sound];
+ source.connect(core.musicStatus.gainNode);
+ var id = setTimeout(null);
+ if (pitch && pitch >= 30 && pitch <= 300) {
+ source.playbackRate.setValueAtTime(pitch / 100, 0);
+ }
+ source.onended = function () {
+ delete core.musicStatus.playingSounds[id];
+ if (callback) callback();
+ }
+ core.musicStatus.playingSounds[id] = source;
+ if (source.start) source.start(0);
+ else if (source.noteOn) source.noteOn(0);
+ return id;
+ }
+ else {
+ core.material.sounds[sound].volume = core.musicStatus.userVolume;
+ core.material.sounds[sound].play();
+ if (callback) callback();
+ }
+ }
+ catch (e) {
+ console.log("无法播放SE " + sound);
+ console.error(e);
+ }
+}
+
+////// 停止所有音频 //////
+control.prototype.stopSound = function (id) {
+ if (id == null) {
+ Object.keys(core.musicStatus.playingSounds).forEach(function (id) {
+ core.control.stopSound(id);
+ });
+ return;
+ }
+ var source = core.musicStatus.playingSounds[id];
+ if (!source) return;
+ try {
+ if (source.stop) source.stop();
+ else if (source.noteOff) source.noteOff();
+ }
+ catch (e) {
+ console.error(e);
+ }
+ delete core.musicStatus.playingSounds[id];
+}
+
+////// 获得当前正在播放的所有(指定)音效的id列表 //////
+control.prototype.getPlayingSounds = function (name) {
+ name = core.getMappedName(name);
+ return Object.keys(core.musicStatus.playingSounds).filter(function (one) {
+ return name == null || core.musicStatus.playingSounds[one].__name == name
+ });
+}
+
+////// 检查bgm状态 //////
+control.prototype.checkBgm = function () {
+ core.playBgm(core.musicStatus.playingBgm || main.startBgm);
+}
+
+///// 设置屏幕放缩 //////
+control.prototype.setDisplayScale = function (delta) {
+ var index = core.domStyle.availableScale.indexOf(core.domStyle.scale);
+ if (index < 0) return;
+ index = (index + delta + core.domStyle.availableScale.length) % core.domStyle.availableScale.length;
+ core.domStyle.scale = core.domStyle.availableScale[index];
+ core.setLocalStorage('scale', core.domStyle.scale);
+ core.resize();
+}
+
+// ------ 状态栏,工具栏等相关 ------ //
+
+////// 清空状态栏 //////
+control.prototype.clearStatusBar = function () {
+ Object.keys(core.statusBar).forEach(function (e) {
+ if (core.statusBar[e].innerHTML != null) {
+ core.statusBar[e].innerHTML = " ";
+ core.statusBar[e].removeAttribute('_style');
+ core.statusBar[e].removeAttribute('_value');
+ }
+ })
+ core.statusBar.image.book.style.opacity = 0.3;
+ if (!core.flags.equipboxButton)
+ core.statusBar.image.fly.style.opacity = 0.3;
+}
+
+////// 更新状态栏 //////
+control.prototype.updateStatusBar = function (doNotCheckAutoEvents, immediate) {
+ if (!core.isPlaying()) return;
+ if (immediate) {
+ return this.updateStatusBar_update();
+ }
+ if (!doNotCheckAutoEvents) this.noAutoEvents = false;
+ if (core.isReplaying()) return this.updateStatusBar_update();
+ if (!core.control.updateNextFrame) {
+ core.control.updateNextFrame = true;
+ requestAnimationFrame(this.updateStatusBar_update);
+ }
+};
+
+control.prototype.updateStatusBar_update = function () {
+ core.control.updateNextFrame = false;
+ if (!core.isPlaying() || core.hasFlag('__statistics__')) return;
+ core.control.controldata.updateStatusBar();
+ if (!core.control.noAutoEvents) core.checkAutoEvents();
+ core.control._updateStatusBar_setToolboxIcon();
+ core.clearRouteFolding();
+ core.control.noAutoEvents = true;
+};
+
+control.prototype._updateStatusBar_setToolboxIcon = function () {
+ if (core.isReplaying()) {
+ core.statusBar.image.book.src = core.status.replay.pausing ? core.statusBar.icons.play.src : core.statusBar.icons.pause.src;
+ core.statusBar.image.book.style.opacity = 1;
+ core.statusBar.image.fly.src = core.statusBar.icons.stop.src;
+ core.statusBar.image.fly.style.opacity = 1;
+ core.statusBar.image.toolbox.src = core.statusBar.icons.rewind.src;
+ core.statusBar.image.keyboard.src = core.statusBar.icons.book.src;
+ core.statusBar.image.shop.src = core.statusBar.icons.floor.src;
+ core.statusBar.image.save.src = core.statusBar.icons.speedDown.src;
+ core.statusBar.image.save.style.opacity = 1;
+ core.statusBar.image.load.src = core.statusBar.icons.speedUp.src;
+ core.statusBar.image.settings.src = core.statusBar.icons.save.src;
+ }
+ else {
+ core.statusBar.image.book.src = core.statusBar.icons.book.src;
+ core.statusBar.image.book.style.opacity = core.hasItem('book') ? 1 : 0.3;
+ if (!core.flags.equipboxButton) {
+ core.statusBar.image.fly.src = core.statusBar.icons.fly.src;
+ core.statusBar.image.fly.style.opacity = core.hasItem('fly') ? 1 : 0.3;
+ }
+ else {
+ core.statusBar.image.fly.src = core.statusBar.icons.equipbox.src;
+ core.statusBar.image.fly.style.opacity = 1;
+ }
+ core.statusBar.image.toolbox.src = core.statusBar.icons.toolbox.src;
+ core.statusBar.image.keyboard.src = core.statusBar.icons.keyboard.src;
+ core.statusBar.image.shop.src = core.statusBar.icons.shop.src;
+ core.statusBar.image.save.src = core.statusBar.icons.save.src;
+ core.statusBar.image.save.style.opacity = core.hasFlag('__forbidSave__') ? 0.3 : 1;
+ core.statusBar.image.load.src = core.statusBar.icons.load.src;
+ core.statusBar.image.settings.src = core.statusBar.icons.settings.src;
+ }
+}
+
+control.prototype.showStatusBar = function () {
+ if (main.mode == 'editor') return;
+ if (core.domStyle.showStatusBar) return;
+ var statusItems = core.dom.status;
+ core.domStyle.showStatusBar = true;
+ core.removeFlag('hideStatusBar');
+ // 显示
+ for (var i = 0; i < statusItems.length; ++i)
+ statusItems[i].style.opacity = 1;
+ this.setToolbarButton(false);
+ core.dom.tools.hard.style.display = 'block';
+ core.dom.toolBar.style.display = 'block';
+}
+
+control.prototype.hideStatusBar = function (showToolbox) {
+ if (main.mode == 'editor') return;
+
+ // 如果原本就是隐藏的,则先显示
+ if (!core.domStyle.showStatusBar)
+ this.showStatusBar();
+ if (core.isReplaying()) showToolbox = true;
+
+ var statusItems = core.dom.status, toolItems = core.dom.tools;
+ core.domStyle.showStatusBar = false;
+ core.setFlag('hideStatusBar', true);
+ core.setFlag('showToolbox', showToolbox || null);
+ // 隐藏
+ for (var i = 0; i < statusItems.length; ++i)
+ statusItems[i].style.opacity = 0;
+ if ((!core.domStyle.isVertical && !core.flags.extendToolbar) || !showToolbox) {
+ for (var i = 0; i < toolItems.length; ++i)
+ toolItems[i].style.display = 'none';
+ }
+ if (!core.domStyle.isVertical && !core.flags.extendToolbar) {
+ core.dom.toolBar.style.display = 'none';
+ }
+}
+
+////// 更新状态栏的勇士图标 //////
+control.prototype.updateHeroIcon = function (name) {
+ name = name || "hero.png";
+ if (core.statusBar.icons.name == name) return;
+ core.statusBar.icons.name = name;
+
+ var image = core.material.images.hero;
+ // 全身图
+ var w = core.material.icons.hero.width || 32;
+ var h = core.material.icons.hero.height || 48;
+ var ratio = Math.min(w / h, 1), width = 32 * ratio, left = 16 - width / 2;
+
+ var canvas = document.createElement("canvas");
+ var ctx = canvas.getContext("2d");
+ canvas.width = 32;
+ canvas.height = 32;
+ core.drawImage(ctx, image, 0, 0, w, h, left, 0, width, 32);
+
+ core.statusBar.image.name.src = canvas.toDataURL("image/png");
+}
+
+////// 改变工具栏为按钮1-8 //////
+control.prototype.setToolbarButton = function (useButton) {
+ if (!core.domStyle.showStatusBar) {
+ // 隐藏状态栏时检查竖屏
+ if (!core.domStyle.isVertical && !core.flags.extendToolbar) {
+ for (var i = 0; i < core.dom.tools.length; ++i)
+ core.dom.tools[i].style.display = 'none';
+ return;
+ }
+ if (!core.hasFlag('showToolbox')) return;
+ else core.dom.tools.hard.style.display = 'block';
+ }
+
+ if (useButton == null) useButton = core.domStyle.toolbarBtn;
+ if ((!core.domStyle.isVertical && !core.flags.extendToolbar)) useButton = false;
+ core.domStyle.toolbarBtn = useButton;
+
+ if (useButton) {
+ ["book", "fly", "toolbox", "keyboard", "shop", "save", "load", "settings"].forEach(function (t) {
+ core.statusBar.image[t].style.display = 'none';
+ });
+ ["btn1", "btn2", "btn3", "btn4", "btn5", "btn6", "btn7", "btn8"].forEach(function (t) {
+ core.statusBar.image[t].style.display = 'block';
+ })
+ main.statusBar.image.btn8.style.filter = core.getLocalStorage('altKey') ? 'sepia(1) contrast(1.5)' : '';
+ }
+ else {
+ ["btn1", "btn2", "btn3", "btn4", "btn5", "btn6", "btn7", "btn8"].forEach(function (t) {
+ core.statusBar.image[t].style.display = 'none';
+ });
+ ["book", "fly", "toolbox", "save", "load", "settings"].forEach(function (t) {
+ core.statusBar.image[t].style.display = 'block';
+ });
+ core.statusBar.image.keyboard.style.display
+ = core.statusBar.image.shop.style.display
+ = core.domStyle.isVertical || core.flags.extendToolbar ? "block" : "none";
+ }
+}
+
+////// ------ resize处理 ------ //
+
+control.prototype._shouldDisplayStatus = function (id) {
+ if (id == null) {
+ var toDraw = [], status = core.dom.status;
+ for (var i = 0; i < status.length; ++i) {
+ var dom = core.dom.status[i], idCol = dom.id;
+ if (idCol.indexOf("Col") != idCol.length - 3) continue;
+ var id = idCol.substring(0, idCol.length - 3);
+ if (!this._shouldDisplayStatus(id)) continue;
+ toDraw.push(id);
+ }
+ return toDraw;
+ }
+ var obj = {};
+ core.flags.statusBarItems.forEach(function (v) { obj[v] = true; })
+ switch (id) {
+ case 'floor': return obj.enableFloor;
+ case 'name': return obj.enableName;
+ case 'lv': return obj.enableLv;
+ case 'hp': return obj.enableHP;
+ case 'hpmax': return obj.enableHPMax;
+ case 'mana': return obj.enableMana;
+ case 'atk': return obj.enableAtk;
+ case 'def': return obj.enableDef;
+ case 'mdef': return obj.enableMDef;
+ case 'money': return obj.enableMoney;
+ case 'exp': return obj.enableExp && !obj.levelUpLeftMode;
+ case 'up': return obj.enableLevelUp;
+ case 'skill': return obj.enableSkill;
+ case 'key': return obj.enableKeys;
+ case 'pzf': return obj.enablePZF;
+ case 'debuff': return obj.enableDebuff;
+ default: return true;
+ }
+}
+
+////// 注册一个resize函数 //////
+// name为名称,可供注销使用
+// func可以是一个函数,或者是插件中的函数名;可以接受obj参数,详见resize函数。
+control.prototype.registerResize = function (name, func) {
+ this.unregisterResize(name);
+ this.resizes.push({ name: name, func: func });
+}
+
+////// 注销一个resize函数 //////
+control.prototype.unregisterResize = function (name) {
+ this.resizes = this.resizes.filter(function (b) { return b.name != name; });
+}
+
+control.prototype._doResize = function (obj) {
+ for (var i in this.resizes) {
+ try {
+ if (core.doFunc(this.resizes[i].func, this, obj)) return true;
+ } catch (e) {
+ console.error(e);
+ console.error("ERROR in resizes[" + this.resizes[i].name + "]:已自动注销该项。");
+ this.unregisterResize(this.resizes[i].name);
+ }
+ }
+ return false;
+}
+
+////// 屏幕分辨率改变后重新自适应 //////
+control.prototype.resize = function () {
+ if (main.mode == 'editor') return;
+ var clientWidth = main.dom.body.clientWidth, clientHeight = main.dom.body.clientHeight;
+ var BORDER = 3;
+ var extendToolbar = core.flags.extendToolbar;
+ let hideLeftStatusBar = core.flags.hideLeftStatusBar;
+ var BAR_WIDTH = hideLeftStatusBar ? 0 : Math.round(core._PY_ * 0.31);
+
+ var horizontalMaxRatio = (clientHeight - 2 * BORDER - (hideLeftStatusBar ? BORDER : 0)) / (core._PY_ + (hideLeftStatusBar ? 38 : 0));
+
+ if (clientWidth - 3 * BORDER >= core._PX_ + BAR_WIDTH || (clientWidth > clientHeight && horizontalMaxRatio < 1)) {
+ // 横屏
+ core.domStyle.isVertical = false;
+
+ core.domStyle.availableScale = [];
+ [1, 1.25, 1.5, 1.75, 2, 2.25, 2.5].forEach(function (v) {
+ if (clientWidth - 3 * BORDER >= v * (core._PX_ + BAR_WIDTH) && horizontalMaxRatio >= v) {
+ core.domStyle.availableScale.push(v);
+ }
+ });
+ if (core.domStyle.availableScale.indexOf(core.domStyle.scale) < 0) {
+ core.domStyle.scale = Math.min(1, horizontalMaxRatio);
+ }
+ }
+ else {
+ // 竖屏
+ core.domStyle.isVertical = true;
+ core.domStyle.scale = Math.min((clientWidth - 2 * BORDER) / core._PX_);
+ core.domStyle.availableScale = [];
+ extendToolbar = false;
+ hideLeftStatusBar = false;
+ BAR_WIDTH = Math.round(core._PX_ * 0.3);
+ }
+
+ var statusDisplayArr = this._shouldDisplayStatus(), count = statusDisplayArr.length;
+ var statusCanvas = core.flags.statusCanvas, statusCanvasRows = core.values.statusCanvasRowsOnMobile || 3;
+ var col = statusCanvas ? statusCanvasRows : Math.ceil(count / 3);
+ if (col > 5) {
+ if (statusCanvas) alert("自绘状态栏的在竖屏下的行数应不超过5!");
+ else alert("当前状态栏数目(" + count + ")大于15,请调整到不超过15以避免手机端出现显示问题。");
+ }
+ var globalAttribute = core.status.globalAttribute || core.initStatus.globalAttribute;
+
+ var obj = {
+ clientWidth: clientWidth,
+ clientHeight: clientHeight,
+ BORDER: BORDER,
+ BAR_WIDTH: BAR_WIDTH,
+ TOOLBAR_HEIGHT: 38,
+ outerWidth: core._PX_ * core.domStyle.scale + 2 * BORDER,
+ outerHeight: core._PY_ * core.domStyle.scale + 2 * BORDER,
+ globalAttribute: globalAttribute,
+ border: '3px ' + core.arrayToRGBA(globalAttribute.borderColor) + ' solid',
+ statusDisplayArr: statusDisplayArr,
+ count: count,
+ col: col,
+ statusBarHeightInVertical: core.domStyle.isVertical ? (32 * col + 6) * core.domStyle.scale + 2 * BORDER : 0,
+ toolbarHeightInVertical: core.domStyle.isVertical ? 38 * core.domStyle.scale + 2 * BORDER : 0,
+ extendToolbar: extendToolbar,
+ is15x15: false,
+ hideLeftStatusBar
+ };
+
+ this._doResize(obj);
+ this.setToolbarButton();
+ core.updateStatusBar();
+}
+
+control.prototype._resize_gameGroup = function (obj) {
+ var startBackground = core.domStyle.isVertical ? (main.styles.startVerticalBackground || main.styles.startBackground) : main.styles.startBackground;
+ if (main.dom.startBackground.getAttribute('__src__') != startBackground) {
+ main.dom.startBackground.setAttribute('__src__', startBackground);
+ main.dom.startBackground.src = startBackground;
+ }
+
+ var gameGroup = core.dom.gameGroup;
+ var totalWidth, totalHeight;
+ if (core.domStyle.isVertical) {
+ totalWidth = obj.outerWidth;
+ totalHeight = obj.outerHeight + obj.statusBarHeightInVertical + obj.toolbarHeightInVertical
+ }
+ else {
+ totalWidth = obj.outerWidth + obj.BAR_WIDTH * core.domStyle.scale + (obj.hideLeftStatusBar ? 0 : obj.BORDER);
+ totalHeight = obj.outerHeight + (obj.extendToolbar ? obj.TOOLBAR_HEIGHT * core.domStyle.scale + obj.BORDER : 0);
+ }
+ gameGroup.style.width = totalWidth + "px";
+ gameGroup.style.height = totalHeight + "px";
+ gameGroup.style.left = (obj.clientWidth - totalWidth) / 2 + "px";
+ gameGroup.style.top = (obj.clientHeight - totalHeight) / 2 + "px";
+ // floorMsgGroup
+ var floorMsgGroup = core.dom.floorMsgGroup;
+ floorMsgGroup.style = obj.globalAttribute.floorChangingStyle;
+ floorMsgGroup.style.width = obj.outerWidth - 2 * obj.BORDER + "px";
+ floorMsgGroup.style.height = totalHeight - 2 * obj.BORDER + "px";
+ floorMsgGroup.style.fontSize = 16 * core.domStyle.scale + "px";
+ // startPanel
+ core.dom.startPanel.style.fontSize = 16 * core.domStyle.scale + "px";
+ // musicBtn
+ if (core.domStyle.isVertical || core.domStyle.scale < 1) {
+ core.dom.musicBtn.style.right = core.dom.musicBtn.style.bottom = "3px";
+ }
+ else {
+ core.dom.musicBtn.style.right = (obj.clientWidth - totalWidth) / 2 + "px";
+ core.dom.musicBtn.style.bottom = (obj.clientHeight - totalHeight) / 2 - 27 + "px";
+ }
+}
+
+control.prototype._resize_canvas = function (obj) {
+ var innerWidth = (core._PX_ * core.domStyle.scale) + "px", innerHeight = (core._PY_ * core.domStyle.scale) + "px";
+ if (!core.isPlaying()) {
+ for (var i = 0; i < core.dom.gameCanvas.length; ++i) {
+ var ctx = core.dom.gameCanvas[i].getContext('2d');
+ core.resizeCanvas(ctx, core._PX_, core._PY_);
+ core.dom.gameCanvas[i].style.width = innerWidth;
+ core.dom.gameCanvas[i].style.height = innerHeight;
+ }
+ } else {
+ requestAnimationFrame(function () {
+ for (var i = 0; i < core.dom.gameCanvas.length; ++i) {
+ core.dom.gameCanvas[i].style.width = innerWidth;
+ core.dom.gameCanvas[i].style.height = innerHeight;
+ }
+ });
+ }
+ core.dom.gif.style.width = innerWidth;
+ core.dom.gif.style.height = innerHeight;
+ core.dom.gif2.style.width = innerWidth;
+ core.dom.gif2.style.height = innerHeight;
+ core.dom.gameDraw.style.width = innerWidth;
+ core.dom.gameDraw.style.height = innerHeight;
+ core.dom.gameDraw.style.top = obj.statusBarHeightInVertical + "px";
+ core.dom.gameDraw.style.right = 0;
+ core.dom.gameDraw.style.border = obj.border;
+ // resize bigmap
+ core.bigmap.canvas.forEach(function (cn) {
+ var ratio = core.canvas[cn].canvas.hasAttribute('isHD') ? core.domStyle.ratio : 1;
+ core.canvas[cn].canvas.style.width = core.canvas[cn].canvas.width / ratio * core.domStyle.scale + "px";
+ core.canvas[cn].canvas.style.height = core.canvas[cn].canvas.height / ratio * core.domStyle.scale + "px";
+ });
+ // resize dynamic canvas
+ if (!core.isPlaying()) {
+ for (var name in core.dymCanvas) {
+ var ctx = core.dymCanvas[name], canvas = ctx.canvas;
+ // core.maps._setHDCanvasSize(ctx, parseFloat(canvas.getAttribute('_width')), parseFloat(canvas.getAttribute('_height')));
+ canvas.style.left = parseFloat(canvas.getAttribute("_left")) * core.domStyle.scale + "px";
+ canvas.style.top = parseFloat(canvas.getAttribute("_top")) * core.domStyle.scale + "px";
+ var scale = canvas.getAttribute('_scale') || 1;
+ core.resizeCanvas(canvas, canvas.width * scale / core.domStyle.scale, canvas.height * scale / core.domStyle.scale);
+ }
+ } else {
+ for (var name in core.dymCanvas) {
+ var ctx = core.dymCanvas[name], canvas = ctx.canvas;
+ core.resizeCanvas(ctx, parseFloat(canvas.getAttribute("_width")), parseFloat(canvas.getAttribute("_height")))
+ canvas.style.left = parseFloat(canvas.getAttribute("_left")) * core.domStyle.scale + "px";
+ canvas.style.top = parseFloat(canvas.getAttribute("_top")) * core.domStyle.scale + "px";
+ }
+ }
+ // resize next
+ main.dom.next.style.width = main.dom.next.style.height = 5 * core.domStyle.scale + "px";
+ main.dom.next.style.borderBottomWidth = main.dom.next.style.borderRightWidth = 4 * core.domStyle.scale + "px";
+}
+
+control.prototype._resize_statusBar = function (obj) {
+ // statusBar
+ var statusBar = core.dom.statusBar;
+ if (core.domStyle.isVertical) {
+ statusBar.style.width = obj.outerWidth + "px";
+ statusBar.style.height = obj.statusBarHeightInVertical + "px";
+ statusBar.style.background = obj.globalAttribute.statusTopBackground;
+ statusBar.style.fontSize = 16 * core.domStyle.scale + "px";
+ }
+ else {
+ statusBar.style.width = (obj.BAR_WIDTH * core.domStyle.scale + obj.BORDER) + "px";
+ statusBar.style.height = obj.outerHeight + (obj.extendToolbar ? obj.TOOLBAR_HEIGHT * core.domStyle.scale + obj.BORDER : 0) + "px";
+ statusBar.style.background = obj.globalAttribute.statusLeftBackground;
+ // --- 计算文字大小
+ if (obj.hideLeftStatusBar) {
+ statusBar.style.fontSize = 16 * core.domStyle.scale + "px";
+ } else {
+ statusBar.style.fontSize = 16 * Math.min(1, (core._HEIGHT_ - 4) / obj.count) * core.domStyle.scale + "px";
+ }
+ }
+ statusBar.style.display = obj.hideLeftStatusBar ? 'none' : 'block';
+ statusBar.style.borderTop = statusBar.style.borderLeft = obj.border;
+ statusBar.style.borderRight = core.domStyle.isVertical ? obj.border : '';
+ statusBar.style.borderBottom = core.domStyle.isVertical ? '' : obj.border;
+ // 自绘状态栏
+ if (core.domStyle.isVertical) {
+ core.dom.statusCanvas.style.width = core._PX_ * core.domStyle.scale + "px";
+ core.dom.statusCanvas.style.height = obj.statusBarHeightInVertical - 3 + "px";
+ core.maps._setHDCanvasSize(core.dom.statusCanvasCtx, core._PX_, obj.col * 32 + 9);
+ }
+ else {
+ core.dom.statusCanvas.style.width = obj.BAR_WIDTH * core.domStyle.scale + "px";
+ core.dom.statusCanvas.style.height = obj.outerHeight - 2 * obj.BORDER + (obj.extendToolbar ? obj.TOOLBAR_HEIGHT * core.domStyle.scale + obj.BORDER : 0) + "px";
+ core.maps._setHDCanvasSize(core.dom.statusCanvasCtx, obj.BAR_WIDTH, core._PY_ + (obj.extendToolbar ? obj.TOOLBAR_HEIGHT + obj.BORDER : 0));
+ }
+ core.dom.statusCanvas.style.display = core.flags.statusCanvas && !obj.hideLeftStatusBar ? "block" : "none";
+}
+
+control.prototype._resize_status = function (obj) {
+ var statusHeight;
+ if (core.domStyle.isVertical) {
+ statusHeight = 32 * core.domStyle.scale * 0.8;
+ } else {
+ statusHeight = (obj.hideLeftStatusBar ? core._HEIGHT_ : core._HEIGHT_ - 4) / obj.count * 32 * core.domStyle.scale * 0.8;
+ }
+ // status
+ for (var i = 0; i < core.dom.status.length; ++i) {
+ var id = core.dom.status[i].id, style = core.dom.status[i].style;
+ if (id.endsWith("Col")) id = id.substring(0, id.length - 3);
+ style.display = core.flags.statusCanvas || obj.statusDisplayArr.indexOf(id) < 0 ? 'none' : 'block';
+ style.margin = 3 * core.domStyle.scale + "px";
+ style.height = statusHeight + "px";
+ style.maxWidth = obj.BAR_WIDTH * core.domStyle.scale * (core.domStyle.isVertical ? 0.95 : 1) + obj.BORDER + "px";
+ if (obj.is15x15 && !core.domStyle.isVertical)
+ style.marginLeft = 11 * core.domStyle.scale + "px";
+ }
+ // statusLabels, statusTexts
+ for (var i = 0; i < core.dom.statusLabels.length; ++i) {
+ core.dom.statusLabels[i].style.lineHeight = statusHeight + "px";
+ core.dom.statusLabels[i].style.marginLeft = 6 * core.domStyle.scale + "px";
+ }
+ for (var i = 0; i < core.dom.statusTexts.length; ++i) {
+ core.dom.statusTexts[i].style.color = core.arrayToRGBA(obj.globalAttribute.statusBarColor);
+ }
+ // keys
+ if (core.flags.statusBarItems.indexOf('enableGreenKey') >= 0) {
+ core.dom.keyCol.style.fontSize = '0.75em';
+ core.statusBar.greenKey.style.display = '';
+ } else {
+ core.dom.keyCol.style.fontSize = '';
+ core.statusBar.greenKey.style.display = 'none';
+ }
+}
+
+control.prototype._resize_toolBar = function (obj) {
+ // toolBar
+ var toolBar = core.dom.toolBar;
+ if (core.domStyle.isVertical) {
+ toolBar.style.left = 0;
+ toolBar.style.right = "";
+ toolBar.style.width = obj.outerWidth + "px";
+ toolBar.style.top = obj.statusBarHeightInVertical + obj.outerHeight + "px";
+ toolBar.style.height = obj.toolbarHeightInVertical + "px";
+ toolBar.style.background = obj.globalAttribute.toolsBackground;
+ }
+ else {
+ if (obj.extendToolbar || obj.hideLeftStatusBar) {
+ toolBar.style.left = "";
+ toolBar.style.right = 0;
+ toolBar.style.width = obj.outerWidth + "px";
+ toolBar.style.top = obj.outerHeight + "px";
+ toolBar.style.height = obj.TOOLBAR_HEIGHT * core.domStyle.scale + obj.BORDER + "px";
+ toolBar.style.background = obj.globalAttribute.toolsBackground;
+ } else {
+ toolBar.style.left = 0;
+ toolBar.style.right = "";
+ toolBar.style.width = obj.BAR_WIDTH * core.domStyle.scale + obj.BORDER + "px";
+ toolBar.style.top = 0.75 * obj.outerHeight + "px";
+ toolBar.style.height = 0.25 * obj.outerHeight + "px";
+ toolBar.style.background = 'transparent';
+ }
+ }
+ toolBar.style.borderLeft = obj.border;
+ toolBar.style.borderRight = toolBar.style.borderBottom = core.domStyle.isVertical || obj.extendToolbar ? obj.border : '';
+ toolBar.style.fontSize = 16 * core.domStyle.scale + "px";
+
+ if (!core.domStyle.showStatusBar && !core.domStyle.isVertical && !obj.extendToolbar) {
+ toolBar.style.display = 'none';
+ } else {
+ toolBar.style.display = 'block';
+ }
+}
+
+control.prototype._resize_tools = function (obj) {
+ var toolsHeight = 32 * core.domStyle.scale * ((core.domStyle.isVertical || obj.extendToolbar) && !obj.is15x15 ? 0.95 : 1);
+ var toolsMarginLeft;
+ if (core.domStyle.isVertical || obj.extendToolbar)
+ toolsMarginLeft = (core._HALF_WIDTH_ - 3) * 3 * core.domStyle.scale;
+ else
+ toolsMarginLeft = (obj.BAR_WIDTH * core.domStyle.scale - 9 - toolsHeight * 3) / 4;
+ for (var i = 0; i < core.dom.tools.length; ++i) {
+ var style = core.dom.tools[i].style;
+ style.height = toolsHeight + "px";
+ style.marginLeft = toolsMarginLeft + "px";
+ style.marginTop = 3 * core.domStyle.scale + "px"
+ }
+ core.dom.hard.style.lineHeight = toolsHeight + "px";
+ if (core.domStyle.isVertical || obj.extendToolbar) {
+ core.dom.hard.style.width = obj.outerWidth - 9 * toolsMarginLeft - 8.5 * toolsHeight - 12 + "px";
+ }
+ else {
+ core.dom.hard.style.width = obj.BAR_WIDTH * core.domStyle.scale - 9 - 2 * toolsMarginLeft + "px";
+ if (!obj.is15x15) core.dom.hard.style.marginTop = 0;
+ }
+}
diff --git a/libs/core.js b/libs/core.js
new file mode 100644
index 0000000..55d0bd2
--- /dev/null
+++ b/libs/core.js
@@ -0,0 +1,547 @@
+
+/**
+ * 初始化 start
+ */
+
+"use strict";
+
+// /**
+// * @type {CoreMixin}
+// */
+// const core = (() => {
+
+function core () {
+ this._WIDTH_ = 15;
+ this._HEIGHT_ = 15;
+ this._PX_ = this._WIDTH_ * 32;
+ this._PY_ = this._HEIGHT_ * 32;
+ this._HALF_WIDTH_ = Math.floor(this._WIDTH_ / 2);
+ this._HALF_HEIGHT_ = Math.floor(this._HEIGHT_ / 2);
+
+ this.__SIZE__ = main.mode == 'editor' ? 15 : this._HEIGHT_;
+ this.__PIXELS__ = this.__SIZE__ * 32;
+ this.__HALF_SIZE__ = Math.floor(this.__SIZE__ / 2);
+ this.material = {
+ 'animates': {},
+ 'images': {},
+ 'bgms': {},
+ 'sounds': {},
+ 'items': {},
+ 'enemys': {},
+ 'icons': {},
+ 'ground': null,
+ 'grundCanvas': null,
+ 'groundPattern': null,
+ 'autotileEdges': {},
+ }
+ this.timeout = {
+ 'turnHeroTimeout': null,
+ 'onDownTimeout': null,
+ 'sleepTimeout': null,
+ }
+ this.interval = {
+ 'heroMoveInterval': null,
+ 'onDownInterval': null,
+ }
+ this.animateFrame = {
+ 'totalTime': 0,
+ 'totalTimeStart': 0,
+ 'globalAnimate': false,
+ 'globalTime': 0,
+ 'selectorTime': 0,
+ 'selectorUp': true,
+ 'animateTime': 0,
+ 'moveTime': 0,
+ 'lastLegTime': 0,
+ 'leftLeg': true,
+ 'weather': {
+ 'time': 0,
+ 'type': null,
+ 'level': 1,
+ 'nodes': [],
+ 'data': null,
+ 'fog': null,
+ 'cloud': null,
+ 'sun': null
+ },
+ "tip": null,
+ "asyncId": {},
+ "lastAsyncId": null
+ }
+ this.musicStatus = {
+ 'audioContext': null, // WebAudioContext
+ 'bgmStatus': false, // 是否播放BGM
+ 'soundStatus': true, // 是否播放SE
+ 'playingBgm': null, // 正在播放的BGM
+ 'pauseTime': 0, // 上次暂停的时间
+ 'lastBgm': null, // 上次播放的bgm
+ 'gainNode': null,
+ 'playingSounds': {}, // 正在播放的SE
+ 'userVolume': 1.0, // 用户音量
+ 'designVolume': 1.0, //设计音量
+ 'bgmSpeed': 100, // 背景音乐速度
+ 'bgmUsePitch': null, // 是否同时修改音调
+ 'cachedBgms': [], // 缓存BGM内容
+ 'cachedBgmCount': 8, // 缓存的bgm数量
+ }
+ this.platform = {
+ 'isOnline': true, // 是否http
+ 'isPC': true, // 是否是PC
+ 'isAndroid': false, // 是否是Android
+ 'isIOS': false, // 是否是iOS
+ 'string': 'PC',
+ 'isWeChat': false, // 是否是微信
+ 'isQQ': false, // 是否是QQ
+ 'isChrome': false, // 是否是Chrome
+ 'supportCopy': false, // 是否支持复制到剪切板
+
+ 'fileInput': null, // FileInput
+ 'fileReader': null, // 是否支持FileReader
+ 'successCallback': null, // 读取成功
+ 'errorCallback': null, // 读取失败
+ }
+ // 样式
+ this.domStyle = {
+ scale: 1.0,
+ ratio: 1.0,
+ hdCanvas: ["damage", "ui", "data"],
+ availableScale: [],
+ isVertical: false,
+ showStatusBar: true,
+ toolbarBtn: false,
+ }
+ this.bigmap = {
+ canvas: ["bg", "event", "event2", "fg", "damage"],
+ offsetX: 0, // in pixel
+ offsetY: 0,
+ posX: 0, //
+ posY: 0,
+ width: main.mode == 'editor' ? this.__SIZE__ : this._WIDTH_, // map width and height
+ height: main.mode == 'editor' ? this.__SIZE__ : this._HEIGHT_,
+ v2: false,
+ threshold: 1024,
+ extend: 10,
+ scale: 1.0,
+ tempCanvas: null, // A temp canvas for drawing
+ cacheCanvas: null, // A cache canvas
+ }
+ this.saves = {
+ "saveIndex": null,
+ "ids": {},
+ "autosave": {
+ "data": null,
+ "time": 0,
+ "updated": false,
+ "storage": true, // 是否把自动存档写入文件a
+ "max": 20, // 自动存档最大回退数
+ "now": 0,
+ },
+ "favorite": [],
+ "favoriteName": {},
+ "cache": {}
+ }
+ this.initStatus = {
+ 'played': false,
+ 'gameOver': false,
+
+ // 勇士属性
+ 'hero': {},
+ 'heroCenter': { 'px': null, 'py': null },
+
+ // 当前地图
+ 'floorId': null,
+ 'thisMap': null,
+ 'maps': null,
+ 'bgmaps': {},
+ 'fgmaps': {},
+ 'mapBlockObjs': {},
+ 'checkBlock': {}, // 每个点的阻激夹域信息
+ 'damage': { // 每个点的显伤绘制
+ 'posX': 0,
+ 'posY': 0,
+ 'data': [],
+ 'extraData': [],
+ },
+
+ 'lockControl': false,
+
+ // 勇士移动状态
+ 'heroMoving': 0,
+ 'heroStop': true,
+
+ // 自动寻路相关
+ 'automaticRoute': {
+ 'autoHeroMove': false,
+ 'autoStep': 0,
+ 'movedStep': 0,
+ 'destStep': 0,
+ 'destX': null,
+ 'destY': null,
+ 'offsetX': null,
+ 'offsetY': null,
+ 'autoStepRoutes': [],
+ 'moveStepBeforeStop': [],
+ 'lastDirection': null,
+ 'cursorX': 0,
+ 'cursorY': 0,
+ "moveDirectly": false,
+ },
+
+ // 按下键的时间:为了判定双击
+ 'downTime': null,
+ 'ctrlDown': false,
+ 'preview': {
+ 'enabled': false,
+ 'prepareDragging': false,
+ 'dragging': false,
+ 'px': 0,
+ 'py': 0,
+ },
+
+ // 路线&回放
+ 'route': [],
+ 'replay': {
+ 'replaying': false,
+ 'pausing': false,
+ 'animate': false, // 正在某段动画中
+ 'failed': false,
+ 'toReplay': [],
+ 'totalList': [],
+ 'speed': 1.0,
+ 'steps': 0,
+ 'save': [],
+ },
+ // 录像折叠
+ 'routeFolding': {},
+
+ // event事件
+ 'shops': {},
+ 'event': {
+ 'id': null,
+ 'data': null,
+ 'selection': null,
+ 'ui': null,
+ 'interval': null,
+ },
+ 'autoEvents': [],
+ 'textAttribute': {
+ 'position': "center",
+ "offset": 0,
+ "title": [255, 215, 0, 1],
+ "background": [0, 0, 0, 0.85],
+ "text": [255, 255, 255, 1],
+ "titlefont": 22,
+ "textfont": 16,
+ "bold": false,
+ "time": 0,
+ "letterSpacing": 0,
+ "animateTime": 0,
+ },
+ "globalAttribute": {
+ 'equipName': main.equipName || [],
+ "statusLeftBackground": main.styles.statusLeftBackground || "url(project/materials/ground.png) repeat",
+ "statusTopBackground": main.styles.statusTopBackground || "url(project/materials/ground.png) repeat",
+ "toolsBackground": main.styles.toolsBackground || "url(project/materials/ground.png) repeat",
+ "borderColor": main.styles.borderColor || [204, 204, 204, 1],
+ "statusBarColor": main.styles.statusBarColor || [255, 255, 255, 1],
+ "floorChangingStyle": main.styles.floorChangingStyle || "background-color: black; color: white",
+ "selectColor": main.styles.selectColor || [255, 215, 0, 1],
+ "font": main.styles.font || "Verdana"
+ },
+ 'curtainColor': null,
+
+ // 动画
+ 'globalAnimateObjs': [],
+ 'floorAnimateObjs': [],
+ 'boxAnimateObjs': [],
+ 'autotileAnimateObjs': [],
+ "globalAnimateStatus": 0,
+ 'animateObjs': [],
+ };
+ // 标记的楼层列表,用于数据统计
+ this.markedFloorIds = {};
+ this.status = {};
+ this.dymCanvas = {};
+
+ if (main.mode == 'editor') {
+ document.documentElement.style.setProperty('--size', this.__SIZE__);
+ document.documentElement.style.setProperty('--pixel', this.__PIXELS__ + 'px');
+ }
+}
+
+/////////// 系统事件相关 ///////////
+
+////// 初始化 //////
+core.prototype.init = function (coreData, callback) {
+ this._forwardFuncs();
+ for (var key in coreData)
+ core[key] = coreData[key];
+ this._init_flags();
+ this._init_platform();
+ this._init_others();
+ this._init_plugins();
+ var b = main.mode == 'editor';
+ // 初始化画布
+ for (var name in core.canvas) {
+ if (core.domStyle.hdCanvas.indexOf(name) >= 0)
+ core.maps._setHDCanvasSize(core.canvas[name], b ? core.__PIXELS__ : core._PX_, b ? core.__PIXELS__ : core._PY_);
+ else {
+ core.canvas[name].canvas.width = (b ? core.__PIXELS__ : core._PX_);
+ core.canvas[name].canvas.height = (b ? core.__PIXELS__ : core._PY_);
+ }
+ }
+
+ core.loader._load(function () {
+ core.extensions._load(function () {
+ core._afterLoadResources(callback);
+ });
+ });
+ core.dom.musicBtn.style.display = 'block';
+ core.setMusicBtn();
+}
+
+core.prototype._init_flags = function () {
+ core.flags = core.clone(core.data.flags);
+ core.values = core.clone(core.data.values);
+ core.firstData = core.clone(core.data.firstData);
+ this._init_sys_flags();
+
+ // 让你总是拼错!
+ window.on = true;
+ window.off = false;
+ window.ture = true;
+ window.flase = false;
+
+ core.dom.versionLabel.innerText = core.firstData.version;
+ core.dom.logoLabel.innerText = core.firstData.title;
+ document.title = core.firstData.title + " - HTML5魔塔";
+ document.getElementById("startLogo").innerText = core.firstData.title;
+ (core.firstData.shops || []).forEach(function (t) { core.initStatus.shops[t.id] = t; });
+
+ core.maps._initFloors();
+ // 初始化怪物、道具等
+ core.material.enemys = core.enemys.getEnemys();
+ core.material.items = core.items.getItems();
+ core.material.icons = core.icons.getIcons();
+
+ // 初始化自动事件
+ for (var floorId in core.floors) {
+ var autoEvents = core.floors[floorId].autoEvent || {};
+ for (var loc in autoEvents) {
+ var locs = loc.split(","), x = parseInt(locs[0]), y = parseInt(locs[1]);
+ for (var index in autoEvents[loc]) {
+ var autoEvent = core.clone(autoEvents[loc][index]);
+ if (autoEvent && autoEvent.condition && autoEvent.data) {
+ autoEvent.floorId = floorId;
+ autoEvent.x = x;
+ autoEvent.y = y;
+ autoEvent.index = index;
+ autoEvent.symbol = floorId + "@" + x + "@" + y + "@" + index;
+ autoEvent.condition = core.replaceValue(autoEvent.condition);
+ autoEvent.data = core.precompile(autoEvent.data);
+ core.initStatus.autoEvents.push(autoEvent);
+ }
+ }
+ }
+ }
+ // 道具的穿上/脱下,视为自动事件
+ for (var equipId in core.material.items) {
+ var equip = core.material.items[equipId];
+ if (equip.cls != 'equips' || !equip.equip) continue;
+ if (!equip.equip.equipEvent && !equip.equip.unequipEvent) continue;
+ var equipFlag = '_equipEvent_' + equipId;
+ var autoEvent1 = {
+ symbol: "_equipEvent_" + equipId,
+ currentFloor: false,
+ multiExecute: true,
+ condition: "core.hasEquip('" + equipId + "') && !core.hasFlag('" + equipFlag + "')",
+ data: core.precompile([{ "type": "setValue", "name": "flag:" + equipFlag, "value": "true" }].concat(equip.equip.equipEvent || [])),
+ };
+ var autoEvent2 = {
+ symbol: "_unequipEvent_" + equipId,
+ currentFloor: false,
+ multiExecute: true,
+ condition: "!core.hasEquip('" + equipId + "') && core.hasFlag('" + equipFlag + "')",
+ data: core.precompile([{ "type": "setValue", "name": "flag:" + equipFlag, "value": "null" }].concat(equip.equip.unequipEvent || [])),
+ };
+ core.initStatus.autoEvents.push(autoEvent1);
+ core.initStatus.autoEvents.push(autoEvent2);
+ }
+
+ core.initStatus.autoEvents.sort(function (e1, e2) {
+ if (e1.floorId == null) return 1;
+ if (e2.floorId == null) return -1;
+ if (e1.priority != e2.priority) return e2.priority - e1.priority;
+ if (e1.floorId != e2.floorId) return core.floorIds.indexOf(e1.floorId) - core.floorIds.indexOf(e2.floorId);
+ if (e1.x != e2.x) return e1.x - e2.x;
+ if (e1.y != e2.y) return e1.y - e2.y;
+ return e1.index - e2.index;
+ })
+
+}
+
+core.prototype._init_sys_flags = function () {
+ if (core.flags.equipboxButton) core.flags.equipment = true;
+ core.flags.displayEnemyDamage = core.getLocalStorage('enemyDamage', true);
+ core.flags.displayCritical = core.getLocalStorage('critical', true);
+ core.flags.displayExtraDamage = core.getLocalStorage('extraDamage', true);
+ core.flags.enableEnemyPoint = core.getLocalStorage('enableEnemyPoint', core.flags.enableEnemyPoint);
+ core.flags.leftHandPrefer = core.getLocalStorage('leftHandPrefer', false);
+ core.flags.extraDamageType = core.getLocalStorage('extraDamageType', 2);
+ // 行走速度
+ core.values.moveSpeed = core.getLocalStorage('moveSpeed', core.values.moveSpeed || 100);
+ core.values.floorChangeTime = core.getLocalStorage('floorChangeTime', core.values.floorChangeTime);
+ if (core.values.floorChangeTime == null) core.values.floorChangeTime = 500;
+ core.flags.enableHDCanvas = core.getLocalStorage('enableHDCanvas', !core.platform.isIOS);
+}
+
+core.prototype._init_platform = function () {
+ core.platform.isOnline = location.protocol.indexOf("http") == 0;
+ if (!core.platform.isOnline) alert("请勿直接打开html文件!使用启动服务或者APP进行离线游戏。");
+ window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext;
+ core.musicStatus.bgmStatus = core.getLocalStorage('bgmStatus', true);
+ core.musicStatus.soundStatus = core.getLocalStorage('soundStatus', true);
+ //新增 userVolume 默认值0.7
+ core.musicStatus.userVolume = core.getLocalStorage('userVolume', 0.7);
+ try {
+ core.musicStatus.audioContext = new window.AudioContext();
+ core.musicStatus.gainNode = core.musicStatus.audioContext.createGain();
+ core.musicStatus.gainNode.gain.value = core.musicStatus.userVolume;
+ core.musicStatus.gainNode.connect(core.musicStatus.audioContext.destination);
+ } catch (e) {
+ console.log("该浏览器不支持AudioContext");
+ core.musicStatus.audioContext = null;
+ }
+ ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"].forEach(function (t) {
+ if (navigator.userAgent.indexOf(t) >= 0) {
+ if (t == 'iPhone' || t == 'iPad' || t == 'iPod') core.platform.isIOS = true;
+ if (t == 'Android') core.platform.isAndroid = true;
+ core.platform.isPC = false;
+ }
+ });
+ core.platform.string = core.platform.isPC ? "PC" : core.platform.isAndroid ? "Android" : core.platform.isIOS ? "iOS" : "";
+ core.platform.supportCopy = document.queryCommandSupported && document.queryCommandSupported("copy");
+ var chrome = /Chrome\/(\d+)\./i.exec(navigator.userAgent);
+ if (chrome && parseInt(chrome[1]) >= 50) core.platform.isChrome = true;
+ core.platform.isSafari = /Safari/i.test(navigator.userAgent) && !/Chrome/i.test(navigator.userAgent);
+ core.platform.isQQ = /QQ/i.test(navigator.userAgent);
+ core.platform.isWeChat = /MicroMessenger/i.test(navigator.userAgent);
+ if (window.FileReader) {
+ core.platform.fileReader = new FileReader();
+ core.platform.fileReader.onload = function () {
+ core.readFileContent(core.platform.fileReader.result);
+ };
+ core.platform.fileReader.onerror = function () {
+ if (core.platform.errorCallback)
+ core.platform.errorCallback();
+ }
+ }
+
+ core.flags.enableHDCanvas = core.getLocalStorage('enableHDCanvas', !core.platform.isIOS);
+ if (main.mode != 'editor') {
+ core.domStyle.scale = core.getLocalStorage('scale', 1);
+ if (core.flags.enableHDCanvas) core.domStyle.ratio = Math.max(window.devicePixelRatio || 1, core.domStyle.scale);
+ }
+}
+
+core.prototype._init_others = function () {
+ // 一些额外的东西
+ core.material.groundCanvas = document.createElement('canvas').getContext('2d');
+ core.material.groundCanvas.canvas.width = core.material.groundCanvas.canvas.height = 32;
+ core.material.groundPattern = core.material.groundCanvas.createPattern(core.material.groundCanvas.canvas, 'repeat');
+ core.bigmap.tempCanvas = document.createElement('canvas').getContext('2d');
+ core.bigmap.cacheCanvas = document.createElement('canvas').getContext('2d');
+ core.loadImage("materials", 'fog', function (name, img) { core.animateFrame.weather.fog = img; });
+ core.loadImage("materials", "cloud", function (name, img) { core.animateFrame.weather.cloud = img; })
+ core.loadImage("materials", "sun", function (name, img) { core.animateFrame.weather.sun = img; })
+ core.loadImage("materials", 'keyboard', function (name, img) { core.material.images.keyboard = img; });
+ // 记录存档编号
+ core.saves.saveIndex = core.getLocalStorage('saveIndex', 1);
+ core.control.getSaveIndexes(function (indexes) { core.saves.ids = indexes; });
+}
+
+core.prototype._afterLoadResources = function (callback) {
+ // 初始化地图
+ core.initStatus.maps = core.maps._initMaps();
+ core.control._setRequestAnimationFrame();
+ // 图片裁剪
+ (main.splitImages || []).forEach(function (one) {
+ var name = core.getMappedName(one.name);
+ if (!core.material.images.images[name]) {
+ console.warn('找不到图片:' + name + ',无法裁剪');
+ return;
+ }
+ if (!name.endsWith('.png')) {
+ console.warn('无法裁剪非png格式图片:' + name);
+ return;
+ }
+ var arr = core.splitImage(core.material.images.images[name], one.width, one.height);
+ for (var i = 0; i < arr.length; ++i) {
+ core.material.images.images[(one.prefix || "") + i + '.png'] = arr[i];
+ }
+ });
+
+ if (core.plugin._afterLoadResources)
+ core.plugin._afterLoadResources();
+ core.showStartAnimate();
+ if (callback) callback();
+}
+
+core.prototype._init_plugins = function () {
+ core.plugin = new function () { };
+
+ for (var name in plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1) {
+ if (plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1[name] instanceof Function) {
+ try {
+ plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1[name].apply(core.plugin);
+ }
+ catch (e) {
+ console.error(e);
+ console.error("无法初始化插件" + name);
+ }
+ }
+ }
+
+ core._forwardFunc("plugin");
+}
+
+core.prototype._forwardFuncs = function () {
+ for (var i = 0; i < main.loadList.length; ++i) {
+ var name = main.loadList[i];
+ if (name == 'core') continue;
+ this._forwardFunc(name);
+ }
+}
+
+core.prototype._forwardFunc = function (name, funcname) {
+ if (funcname == null) {
+ for (funcname in core[name]) {
+ if (funcname.charAt(0) != "_" && core[name][funcname] instanceof Function) {
+ this._forwardFunc(name, funcname);
+ }
+ }
+ return;
+ }
+
+ if (core[funcname]) {
+ console.error("ERROR: 无法转发 " + name + " 中的函数 " + funcname + " 到 core 中!同名函数已存在。");
+ return;
+ }
+ var parameterInfo = /^\s*function\s*[\w_$]*\(([\w_,$\s]*)\)\s*\{/.exec(core[name][funcname].toString());
+ var parameters = (parameterInfo == null ? "" : parameterInfo[1]).replace(/\s*/g, '').replace(/,/g, ', ');
+ // core[funcname] = new Function(parameters, "return core."+name+"."+funcname+"("+parameters+");");
+ eval("core." + funcname + " = function (" + parameters + ") {\n\treturn core." + name + "." + funcname + ".apply(core." + name + ", arguments);\n}");
+}
+
+core.prototype.doFunc = function (func, _this) {
+ if (typeof func == 'string') {
+ func = core.plugin[func];
+ _this = core.plugin;
+ }
+ return func.apply(_this, Array.prototype.slice.call(arguments, 2));
+}
+
+// return new Core();
+
+// })();
+var core = new core();
diff --git a/libs/data.js b/libs/data.js
new file mode 100644
index 0000000..8fbc63f
--- /dev/null
+++ b/libs/data.js
@@ -0,0 +1,13 @@
+
+"use strict";
+
+function data () {
+ this._init();
+}
+
+data.prototype._init = function () {
+ this.firstData = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData;
+ this.values = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.values;
+ this.flags = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.flags;
+ //delete(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d);
+}
\ No newline at end of file
diff --git a/libs/enemys.js b/libs/enemys.js
new file mode 100644
index 0000000..122657a
--- /dev/null
+++ b/libs/enemys.js
@@ -0,0 +1,523 @@
+
+"use strict";
+
+function enemys () {
+ this._init();
+}
+
+////// 初始化 //////
+enemys.prototype._init = function () {
+ this.enemys = enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80;
+ this.enemydata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.enemys;
+ for (var enemyId in this.enemys) {
+ this.enemys[enemyId].id = enemyId;
+ }
+ if (main.mode == 'play') {
+ this.enemydata.hasSpecial = function (a, b) {
+ return core.enemys.hasSpecial(a, b)
+ };
+ }
+}
+
+enemys.prototype.getEnemys = function () {
+ var enemys = core.clone(this.enemys);
+ var enemyInfo = core.getFlag('enemyInfo');
+ if (enemyInfo) {
+ for (var id in enemyInfo) {
+ for (var name in enemyInfo[id]) {
+ enemys[id][name] = core.clone(enemyInfo[id][name]);
+ }
+ }
+ }
+ // 将所有怪物的各项属性映射到朝下的
+ for (var id in enemys) {
+ if (enemys[id].faceIds) {
+ var downId = enemys[id].faceIds.down;
+ if (downId != null && downId != id && enemys[downId]) {
+ enemys[id] = { id: id };
+ for (var property in enemys[downId]) {
+ if (property != 'id' && enemys[downId].hasOwnProperty(property)) {
+ (function (id, downId, property) {
+ Object.defineProperty(enemys[id], property, {
+ get: function () { return enemys[downId][property] },
+ set: function (v) { enemys[downId][property] = v },
+ enumerable: true
+ })
+ })(id, downId, property);
+ }
+ }
+ }
+ }
+ }
+ return enemys;
+}
+
+////// 判断是否含有某特殊属性 //////
+enemys.prototype.hasSpecial = function (special, test) {
+ if (special == null) return false;
+
+ if (special instanceof Array) {
+ return special.indexOf(test) >= 0;
+ }
+
+ if (typeof special == 'number') {
+ return special === test;
+ }
+
+ if (typeof special == 'string') {
+ return this.hasSpecial(core.material.enemys[special], test);
+ }
+
+ if (special.special != null) {
+ return this.hasSpecial(special.special, test);
+ }
+
+ return false;
+}
+
+enemys.prototype.getSpecials = function () {
+ return this.enemydata.getSpecials();
+}
+
+////// 获得所有特殊属性的名称 //////
+enemys.prototype.getSpecialText = function (enemy) {
+ if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
+ if (!enemy) return [];
+ var special = enemy.special;
+ var text = [];
+
+ var specials = this.getSpecials();
+ if (specials) {
+ for (var i = 0; i < specials.length; i++) {
+ if (this.hasSpecial(special, specials[i][0]))
+ text.push(this._calSpecialContent(enemy, specials[i][1]));
+ }
+ }
+ return text;
+}
+
+////// 获得所有特殊属性的颜色 //////
+enemys.prototype.getSpecialColor = function (enemy) {
+ if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
+ if (!enemy) return [];
+ var special = enemy.special;
+ var colors = [];
+
+ var specials = this.getSpecials();
+ if (specials) {
+ for (var i = 0; i < specials.length; i++) {
+ if (this.hasSpecial(special, specials[i][0]))
+ colors.push(specials[i][3] || null);
+ }
+ }
+ return colors;
+
+}
+
+////// 获得所有特殊属性的额外标记 //////
+enemys.prototype.getSpecialFlag = function (enemy) {
+ if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
+ if (!enemy) return [];
+ var special = enemy.special;
+ var flag = 0;
+
+ var specials = this.getSpecials();
+ if (specials) {
+ for (var i = 0; i < specials.length; i++) {
+ if (this.hasSpecial(special, specials[i][0]))
+ flag |= (specials[i][4] || 0);
+ }
+ }
+ return flag;
+}
+
+////// 获得每个特殊属性的说明 //////
+enemys.prototype.getSpecialHint = function (enemy, special) {
+ var specials = this.getSpecials();
+
+ if (special == null) {
+ if (specials == null) return [];
+ var hints = [];
+ for (var i = 0; i < specials.length; i++) {
+ if (this.hasSpecial(enemy, specials[i][0]))
+ hints.push("\r[" + core.arrayToRGBA(specials[i][3] || "#FF6A6A") + "]\\d" + this._calSpecialContent(enemy, specials[i][1]) +
+ ":\\d\r[]" + this._calSpecialContent(enemy, specials[i][2]));
+ }
+ return hints;
+ }
+
+ if (specials == null) return "";
+ for (var i = 0; i < specials.length; i++) {
+ if (special == specials[i][0])
+ return "\r[#FF6A6A]\\d" + this._calSpecialContent(enemy, specials[i][1]) + ":\\d\r[]" + this._calSpecialContent(enemy, specials[i][2]);
+ }
+ return "";
+}
+
+enemys.prototype._calSpecialContent = function (enemy, content) {
+ if (typeof content == 'string') return content;
+ if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
+ if (content instanceof Function) {
+ return content(enemy);
+ }
+ return "";
+}
+
+////// 获得某个点上某个怪物的某项属性 //////
+enemys.prototype.getEnemyValue = function (enemy, name, x, y, floorId) {
+ floorId = floorId || core.status.floorId;
+ if ((((flags.enemyOnPoint || {})[floorId] || {})[x + "," + y] || {})[name] != null) {
+ return flags.enemyOnPoint[floorId][x + "," + y][name];
+ }
+ if (enemy == null) {
+ var block = core.getBlock(x, y, floorId);
+ if (block == null) return null;
+ enemy = core.material.enemys[block.event.id];
+ }
+ if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
+ if (enemy == null) return null;
+ return enemy[name];
+}
+
+////// 能否获胜 //////
+enemys.prototype.canBattle = function (enemy, x, y, floorId) {
+ if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
+ var damage = this.getDamage(enemy, x, y, floorId);
+ return damage != null && damage < core.status.hero.hp;
+}
+
+enemys.prototype.getDamageString = function (enemy, x, y, floorId) {
+ if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
+ var damage = this.getDamage(enemy, x, y, floorId);
+
+ var color = '#000000';
+
+ if (damage == null) {
+ damage = "???";
+ color = '#FF2222';
+ }
+ else {
+ if (damage <= 0) color = '#11FF11';
+ else if (damage < core.status.hero.hp / 3) color = '#FFFFFF';
+ else if (damage < core.status.hero.hp * 2 / 3) color = '#FFFF00';
+ else if (damage < core.status.hero.hp) color = '#FF9933';
+ else color = '#FF2222';
+
+ damage = core.formatBigNumber(damage, true);
+ if (core.enemys.hasSpecial(enemy, 19))
+ damage += "+";
+ if (core.enemys.hasSpecial(enemy, 21))
+ damage += "-";
+ if (core.enemys.hasSpecial(enemy, 11))
+ damage += "^";
+ }
+
+ return {
+ "damage": damage,
+ "color": color
+ };
+}
+
+////// 接下来N个临界值和临界减伤计算 //////
+enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId) {
+ if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
+ number = number || 1;
+
+ var specialCriticals = this._nextCriticals_special(enemy, number, x, y, floorId);
+ if (specialCriticals != null) return specialCriticals;
+ var info = this.getDamageInfo(enemy, null, x, y, floorId);
+ if (info == null) { // 如果未破防...
+ var overAtk = this._nextCriticals_overAtk(enemy, x, y, floorId);
+ if (overAtk == null) return [];
+ if (typeof overAtk[1] == 'number') return [[overAtk[0], -overAtk[1]]];
+ info = overAtk[1];
+ info.__over__ = true;
+ info.__overAtk__ = overAtk[0];
+ }
+
+ if (typeof info == 'number') return [[0, 0]];
+ if (info.damage <= 0 && !core.flags.enableNegativeDamage) {
+ return [[info.__overAtk__ || 0, 0]];
+ }
+
+ if (core.flags.useLoop) {
+ if (core.status.hero.atk <= (main.criticalUseLoop || 1)) {
+ return this._nextCriticals_useLoop(enemy, info, number, x, y, floorId);
+ }
+ else {
+ return this._nextCriticals_useBinarySearch(enemy, info, number, x, y, floorId);
+ }
+ }
+ else {
+ return this._nextCriticals_useTurn(enemy, info, number, x, y, floorId);
+ }
+}
+
+/// 未破防临界采用二分计算
+enemys.prototype._nextCriticals_overAtk = function (enemy, x, y, floorId) {
+ var calNext = function (currAtk, maxAtk) {
+ var start = currAtk, end = maxAtk;
+ if (start > end) return null;
+
+ while (start < end) {
+ var mid = Math.floor((start + end) / 2);
+ if (mid - start > end - mid) mid--;
+ var nextInfo = core.enemys.getDamageInfo(enemy, { "atk": mid }, x, y, floorId);
+ if (nextInfo != null) end = mid;
+ else start = mid + 1;
+ }
+ var nextInfo = core.enemys.getDamageInfo(enemy, { "atk": start }, x, y, floorId);
+ return nextInfo == null ? null : [start - core.status.hero.atk, nextInfo];
+ }
+ return calNext(core.status.hero.atk + 1,
+ core.getEnemyValue(enemy, 'hp', x, y, floorId) + core.getEnemyValue(enemy, 'def', x, y, floorId));
+}
+
+enemys.prototype._nextCriticals_special = function (enemy, number, x, y, floorId) {
+ if (this.hasSpecial(enemy.special, 10) || this.hasSpecial(enemy.special, 3))
+ return []; // 模仿or坚固临界
+ return null;
+}
+
+enemys.prototype._nextCriticals_useLoop = function (enemy, info, number, x, y, floorId) {
+ var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = info.mon_def, pre = info.damage;
+ var list = [];
+ var start_atk = hero_atk;
+ if (info.__over__) {
+ start_atk += info.__overAtk__;
+ list.push([info.__overAtk__, -info.damage]);
+ }
+ for (var atk = start_atk + 1; atk <= mon_hp + mon_def; atk++) {
+ var nextInfo = this.getDamageInfo(enemy, { "atk": atk }, x, y, floorId);
+ if (nextInfo == null || (typeof nextInfo == 'number')) break;
+ if (pre > nextInfo.damage) {
+ pre = nextInfo.damage;
+ list.push([atk - hero_atk, info.damage - nextInfo.damage]);
+ if (nextInfo.damage <= 0 && !core.flags.enableNegativeDamage) break;
+ if (list.length >= number) break;
+ }
+ }
+ if (list.length == 0) list.push([0, 0]);
+ return list;
+}
+
+enemys.prototype._nextCriticals_useBinarySearch = function (enemy, info, number, x, y, floorId) {
+ var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = info.mon_def, pre = info.damage;
+ var list = [];
+ var start_atk = hero_atk;
+ if (info.__over__) {
+ start_atk += info.__overAtk__;
+ list.push([info.__overAtk__, -info.damage]);
+ }
+ var calNext = function (currAtk, maxAtk) {
+ var start = Math.floor(currAtk), end = Math.floor(maxAtk);
+ if (start > end) return null;
+
+ while (start < end) {
+ var mid = Math.floor((start + end) / 2);
+ if (mid - start > end - mid) mid--;
+ var nextInfo = core.enemys.getDamageInfo(enemy, { "atk": mid }, x, y, floorId);
+ if (nextInfo == null || (typeof nextInfo == 'number')) return null;
+ if (pre > nextInfo.damage) end = mid;
+ else start = mid + 1;
+ }
+ var nextInfo = core.enemys.getDamageInfo(enemy, { "atk": start }, x, y, floorId);
+ return nextInfo == null || (typeof nextInfo == 'number') || nextInfo.damage >= pre ? null : [start, nextInfo.damage];
+ }
+ var currAtk = start_atk;
+ while (true) {
+ var next = calNext(currAtk + 1, mon_hp + mon_def, pre);
+ if (next == null) break;
+ currAtk = next[0];
+ pre = next[1];
+ list.push([currAtk - hero_atk, info.damage - pre]);
+ if (pre <= 0 && !core.flags.enableNegativeDamage) break;
+ if (list.length >= number) break;
+ }
+ if (list.length == 0) list.push([0, 0]);
+ return list;
+}
+
+enemys.prototype._nextCriticals_useTurn = function (enemy, info, number, x, y, floorId) {
+ var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = info.mon_def, turn = info.turn;
+ // ------ 超大回合数强制使用二分算临界
+ // 以避免1攻10e回合,2攻5e回合导致下述循环卡死问题
+ if (turn >= 1e6) { // 100w回合以上强制二分计算临界
+ return this._nextCriticals_useBinarySearch(enemy, info, number, x, y, floorId);
+ }
+ var list = [], pre = null;
+ var start_atk = hero_atk;
+ if (info.__over__) {
+ start_atk += info.__overAtk__;
+ list.push([info.__overAtk__, -info.damage]);
+ }
+ for (var t = turn - 1; t >= 1; t--) {
+ var nextAtk = Math.ceil(mon_hp / t) + mon_def;
+ // 装备提升比例的计算临界
+ nextAtk = Math.ceil(nextAtk / core.getBuff('atk'));
+ if (nextAtk <= start_atk) break;
+ if (nextAtk != pre) {
+ var nextInfo = this.getDamageInfo(enemy, { "atk": nextAtk }, x, y, floorId);
+ if (nextInfo == null || (typeof nextInfo == 'number')) break;
+ list.push([nextAtk - hero_atk, Math.floor(info.damage - nextInfo.damage)]);
+ if (nextInfo.damage <= 0 && !core.flags.enableNegativeDamage) break;
+ pre = nextAtk;
+ }
+ if (list.length >= number)
+ break;
+ }
+ if (list.length == 0) list.push([0, 0]);
+ return list;
+}
+
+////// N防减伤计算 //////
+enemys.prototype.getDefDamage = function (enemy, k, x, y, floorId) {
+ if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
+ k = k || 1;
+ var nowDamage = this._getDamage(enemy, null, x, y, floorId);
+ var nextDamage = this._getDamage(enemy, { "def": core.status.hero.def + k }, x, y, floorId);
+ if (nowDamage == null || nextDamage == null) return "???";
+ return nowDamage - nextDamage;
+}
+
+enemys.prototype.getEnemyInfo = function (enemy, hero, x, y, floorId) {
+ if (enemy == null) return null;
+ if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
+ return this.enemydata.getEnemyInfo(enemy, hero, x, y, floorId)
+}
+
+////// 获得战斗伤害信息(实际伤害计算函数) //////
+enemys.prototype.getDamageInfo = function (enemy, hero, x, y, floorId) {
+ if (enemy == null) return null;
+ // 移动到了脚本编辑 - getDamageInfo中
+ if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
+ return this.enemydata.getDamageInfo(enemy, hero, x, y, floorId);
+}
+
+////// 获得在某个勇士属性下怪物伤害 //////
+enemys.prototype.getDamage = function (enemy, x, y, floorId) {
+ return this._getDamage(enemy, null, x, y, floorId);
+}
+
+enemys.prototype._getDamage = function (enemy, hero, x, y, floorId) {
+ if (enemy == null) enemy = core.getBlockId(x, y, floorId);
+ if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
+ if (enemy == null) return null;
+
+ var info = this.getDamageInfo(enemy, hero, x, y, floorId);
+ if (info == null) return null;
+ if (typeof info == 'number') return info;
+ return info.damage;
+}
+
+////// 获得当前楼层的怪物列表 //////
+enemys.prototype.getCurrentEnemys = function (floorId) {
+ floorId = floorId || core.status.floorId;
+ var enemys = [], used = {};
+ core.extractBlocks(floorId);
+ core.status.maps[floorId].blocks.forEach(function (block) {
+ if (!block.disable && block.event.cls.indexOf('enemy') == 0) {
+ this._getCurrentEnemys_addEnemy(block.event.id, enemys, used, block.x, block.y, floorId);
+ }
+ }, this);
+ return this._getCurrentEnemys_sort(enemys);
+}
+
+enemys.prototype._getCurrentEnemys_getEnemy = function (enemyId) {
+ var enemy = core.material.enemys[enemyId];
+ if (!enemy) return null;
+
+ // 检查朝向;displayIdInBook
+ return core.material.enemys[enemy.displayIdInBook] || core.material.enemys[(enemy.faceIds || {}).down] || enemy;
+}
+
+enemys.prototype._getCurrentEnemys_addEnemy = function (enemyId, enemys, used, x, y, floorId) {
+ var enemy = this._getCurrentEnemys_getEnemy(enemyId);
+ if (enemy == null) return;
+
+ var id = enemy.id;
+
+ var enemyInfo = this.getEnemyInfo(enemy, null, null, null, floorId);
+ var locEnemyInfo = this.getEnemyInfo(enemy, null, x, y, floorId);
+
+ if (!core.flags.enableEnemyPoint ||
+ (locEnemyInfo.atk == enemyInfo.atk && locEnemyInfo.def == enemyInfo.def && locEnemyInfo.hp == enemyInfo.hp)) {
+ x = null;
+ y = null;
+ } else {
+ // 检查enemys里面是否使用了存在的内容
+ for (var i = 0; i < enemys.length; ++i) {
+ var one = enemys[i];
+ if (id == one.id && one.locs != null &&
+ locEnemyInfo.atk == one.atk && locEnemyInfo.def == one.def && locEnemyInfo.hp == one.hp) {
+ one.locs.push([x, y]);
+ return;
+ }
+ }
+ enemyInfo = locEnemyInfo;
+ }
+ var id = enemy.id + ":" + x + ":" + y;
+ if (used[id]) return;
+ used[id] = true;
+
+ var specialText = core.enemys.getSpecialText(enemy);
+ var specialColor = core.enemys.getSpecialColor(enemy);
+
+ var critical = this.nextCriticals(enemy, 1, x, y, floorId);
+ if (critical.length > 0) critical = critical[0];
+
+ var e = core.clone(enemy);
+ for (var v in enemyInfo) {
+ e[v] = enemyInfo[v];
+ }
+ if (x != null && y != null) {
+ e.locs = [[x, y]];
+ }
+ e.name = core.getEnemyValue(enemy, 'name', x, y, floorId);
+ e.specialText = specialText;
+ e.specialColor = specialColor;
+ e.damage = this.getDamage(enemy, x, y, floorId);
+ e.critical = critical[0];
+ e.criticalDamage = critical[1];
+ e.defDamage = this._getCurrentEnemys_addEnemy_defDamage(enemy, x, y, floorId);
+ enemys.push(e);
+}
+
+enemys.prototype._getCurrentEnemys_addEnemy_defDamage = function (enemy, x, y, floorId) {
+ var ratio = core.status.maps[floorId || core.status.floorId].ratio || 1;
+ return this.getDefDamage(enemy, ratio, x, y, floorId);
+}
+
+enemys.prototype._getCurrentEnemys_sort = function (enemys) {
+ return enemys.sort(function (a, b) {
+ if (a.damage == b.damage) {
+ return a.money - b.money;
+ }
+ if (a.damage == null) {
+ return 1;
+ }
+ if (b.damage == null) {
+ return -1;
+ }
+ return a.damage - b.damage;
+ });
+}
+
+enemys.prototype.hasEnemyLeft = function (enemyId, floorId) {
+ if (floorId == null) floorId = core.status.floorId;
+ if (!(floorId instanceof Array)) floorId = [floorId];
+ var enemyMap = {};
+ if (enemyId instanceof Array) enemyId.forEach(function (v) { enemyMap[v] = true; });
+ else if (enemyId) enemyMap[enemyId] = true;
+ else enemyMap = null;
+ for (var i = 0; i < floorId.length; i++) {
+ core.extractBlocks(floorId[i]);
+ var mapBlocks = core.status.maps[floorId[i]].blocks;
+ for (var b = 0; b < mapBlocks.length; b++) {
+ if (!mapBlocks[b].disable && mapBlocks[b].event.cls.indexOf('enemy') === 0) {
+ if (enemyMap === null || enemyMap[core.getFaceDownId(mapBlocks[b])]) return true;
+ }
+ }
+ }
+ return false;
+}
diff --git a/libs/events.js b/libs/events.js
new file mode 100644
index 0000000..66d9954
--- /dev/null
+++ b/libs/events.js
@@ -0,0 +1,3788 @@
+
+"use strict";
+
+function events () {
+ this._init();
+}
+
+////// 初始化 //////
+events.prototype._init = function () {
+ this.eventdata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.events;
+ this.commonEvent = events_c12a15a8_c380_4b28_8144_256cba95f760.commonEvent;
+ this.systemEvents = {};
+ this.actions = {};
+}
+
+// ------ 初始化,开始和结束 ------ //
+
+/// 初始化游戏
+events.prototype.resetGame = function (hero, hard, floorId, maps, values) {
+ this.eventdata.resetGame(hero, hard, floorId, maps, values);
+}
+
+////// 游戏开始事件 //////
+events.prototype.startGame = function (hard, seed, route, callback) {
+ main.dom.levelChooseButtons.style.display = 'none';
+ main.dom.startButtonGroup.style.display = 'none';
+ hard = hard || "";
+
+ if (main.mode != 'play') return;
+
+ // 无动画的开始游戏
+ if (core.flags.startUsingCanvas || route != null) {
+ core.dom.startPanel.style.display = 'none';
+ this._startGame_start(hard, seed, route, callback);
+ }
+ else {
+ core.hideStartAnimate(function () {
+ core.events._startGame_start(hard, seed, route, callback);
+ });
+ }
+}
+
+events.prototype._startGame_start = function (hard, seed, route, callback) {
+ core.resetGame(core.firstData.hero, hard, null, core.cloneArray(core.initStatus.maps));
+ core.setHeroLoc('x', -1);
+ core.setHeroLoc('y', -1);
+
+ if (seed != null && seed > 0) {
+ core.setFlag('__seed__', seed);
+ core.setFlag('__rand__', seed);
+ }
+ else core.utils.__init_seed();
+ core.clearStatusBar();
+
+ var todo = [];
+ if (core.flags.startUsingCanvas) {
+ core.hideStatusBar();
+ core.dom.musicBtn.style.display = 'block';
+ core.push(todo, core.firstData.startCanvas);
+ }
+ core.push(todo, { "type": "function", "function": "function() { core.events._startGame_setHard(); }" })
+ core.push(todo, core.firstData.startText);
+ this.insertAction(todo, null, null, function () {
+ core.events._startGame_afterStart(callback);
+ });
+
+ if (route != null) core.startReplay(route);
+}
+
+events.prototype._startGame_setHard = function () {
+ // 根据难度设置flag:hard
+ // 这一段应当在startCanvas之后,startText之前做
+ var hardValue = 0;
+ var hardColor = 'red';
+ main.levelChoose.forEach(function (one) {
+ if (one.name == core.status.hard) {
+ hardValue = one.hard;
+ hardColor = core.arrayToRGBA(one.color || [255, 0, 0, 1]);
+ core.insertAction(one.action);
+ }
+ });
+ core.setFlag('hard', hardValue || 0);
+ core.setFlag('__hardColor__', hardColor);
+}
+
+events.prototype._startGame_afterStart = function (callback) {
+ core.ui.closePanel();
+ core.changeFloor(core.firstData.floorId, null, core.firstData.hero.loc, null, function () {
+ // 插入一个空事件避免直接回放录像出错
+ core.insertAction([]);
+ if (callback) callback();
+ });
+ this._startGame_upload();
+}
+
+events.prototype._startGame_upload = function () {
+ // Upload
+ var formData = new FormData();
+ formData.append('type', 'people');
+ formData.append('name', core.firstData.name);
+ formData.append('version', core.firstData.version);
+ formData.append('platform', core.platform.string);
+ formData.append('hard', core.encodeBase64(core.status.hard));
+ formData.append('hardCode', core.getFlag('hard', 0));
+ formData.append('base64', 1);
+
+ core.utils.http("POST", "/games/upload.php", formData);
+}
+
+////// 游戏获胜事件 //////
+events.prototype.win = function (reason, norank, noexit) {
+ if (!noexit) core.status.gameOver = true;
+ return this.eventdata.win(reason, norank, noexit);
+}
+
+////// 游戏失败事件 //////
+events.prototype.lose = function (reason) {
+ if (core.isReplaying()) return core.control._replay_error(reason, function () { core.lose(reason); });
+ core.status.gameOver = true;
+ return this.eventdata.lose(reason);
+}
+
+////// 游戏结束 //////
+events.prototype.gameOver = function (ending, fromReplay, norank) {
+ if (!core.status.extraEvent) {
+ core.clearMap('all');
+ core.deleteAllCanvas();
+ core.dom.gif2.innerHTML = "";
+ core.setWeather();
+ }
+ core.ui.closePanel();
+
+ if (main.isCompetition && ending != null) {
+ if (ending == "") ending = "恭喜通关";
+ ending += "[比赛]";
+ }
+
+ var reason = null;
+ if (fromReplay) reason = "录像回放完毕!";
+ else if (core.hasFlag("debug")) reason = "\t[系统提示]调试模式下无法上传成绩";
+
+ if (reason != null)
+ core.drawText(reason, core.restart);
+ else
+ this._gameOver_confirmUpload(ending, norank);
+}
+
+events.prototype._gameOver_confirmUpload = function (ending, norank) {
+ core.ui.closePanel();
+
+ if (ending == null) {
+ this._gameOver_confirmDownload(ending);
+ return;
+ }
+ core.ui.drawConfirmBox("你想记录你的ID和成绩吗?", function () {
+ if (main.isCompetition) {
+ core.events._gameOver_doUpload("", ending, norank);
+ }
+ else {
+ var id = core.getCookie('id') || "";
+ var hint = "请输入你的ID:\n(登录状态下输入数字用户编号可成为蓝名成绩并计入用户通关数)";
+ if (id) hint = "请输入你的ID:\n(输入数字用户编号" + id + "可成为蓝名成绩并计入用户通关数)";
+ core.myprompt(hint, id, function (username) {
+ core.events._gameOver_doUpload(username, ending, norank);
+ });
+ }
+ }, function () {
+ if (main.isCompetition)
+ core.events._gameOver_confirmDownload(ending);
+ else
+ core.events._gameOver_doUpload(null, ending, norank);
+ })
+}
+
+events.prototype._gameOver_doUpload = function (username, ending, norank) {
+ var hp = core.status.hero.hp;
+ if (username == null) hp = 1;
+ core.ui.closePanel();
+ // upload
+ var formData = new FormData();
+ formData.append('type', 'score');
+ formData.append('name', core.firstData.name);
+ formData.append('version', core.firstData.version);
+ formData.append('platform', core.platform.string);
+ formData.append('hard', core.encodeBase64(core.status.hard));
+ formData.append('username', core.encodeBase64(username || ""));
+ formData.append('ending', core.encodeBase64(ending));
+ formData.append('lv', core.status.hero.lv);
+ formData.append('hp', Math.min(hp, Math.pow(2, 63)));
+ formData.append('atk', core.status.hero.atk);
+ formData.append('def', core.status.hero.def);
+ formData.append('mdef', core.status.hero.mdef);
+ formData.append('money', core.status.hero.money);
+ formData.append('experience', core.status.hero.exp);
+ formData.append('steps', core.status.hero.steps);
+ formData.append('norank', norank ? 1 : 0);
+ formData.append('seed', core.getFlag('__seed__'));
+ formData.append('totalTime', Math.floor(core.status.hero.statistics.totalTime / 1000));
+ formData.append('route', core.encodeRoute(core.status.route));
+ formData.append('base64', 1);
+
+ if (main.isCompetition)
+ core.http("POST", "/games/competition/upload.php", formData);
+ else
+ core.http("POST", "/games/upload.php", formData);
+
+ core.events._gameOver_confirmDownload(ending);
+}
+
+events.prototype._gameOver_confirmDownload = function (ending) {
+ core.ui.closePanel();
+ core.ui.drawConfirmBox("你想下载录像吗?", function () {
+ var obj = {
+ 'name': core.firstData.name,
+ 'version': core.firstData.version,
+ 'hard': core.status.hard,
+ 'seed': core.getFlag('__seed__'),
+ 'route': core.encodeRoute(core.status.route)
+ }
+ core.download(core.firstData.name + "_" + core.formatDate2(new Date()) + ".h5route",
+ LZString.compressToBase64(JSON.stringify(obj)));
+ core.events._gameOver_askRate(ending);
+ }, function () {
+ core.events._gameOver_askRate(ending);
+ });
+}
+
+events.prototype._gameOver_askRate = function (ending) {
+ core.ui.closePanel();
+
+ // 继续接下来的事件
+ if (core.status.extraEvent) {
+ core.status.event = core.status.extraEvent;
+ delete core.status.extraEvent;
+ core.lockControl();
+ core.doAction();
+ return;
+ }
+
+ if (ending == null) {
+ if (!core.hasSave(0)) {
+ core.ui.closePanel();
+ core.restart();
+ return;
+ }
+
+ core.status.event.selection = 0;
+ core.ui.drawConfirmBox("你想读取自动存档么?", function () {
+ core.ui.closePanel();
+ core.doSL("autoSave", "load");
+ }, function () {
+ core.ui.closePanel();
+ core.restart();
+ });
+ return;
+ }
+
+ core.ui.drawConfirmBox("恭喜通关!你想查看榜单、评论,\n以及评分和标色投票吗?", function () {
+ if (core.platform.isPC) {
+ window.open("/tower/?name=" + core.firstData.name, "_blank");
+ core.restart();
+ }
+ else {
+ window.location.href = "/tower/?name=" + core.firstData.name;
+ }
+ }, function () {
+ core.restart();
+ });
+}
+
+////// 重新开始游戏;此函数将回到标题页面 //////
+events.prototype.restart = function () {
+ core.showStartAnimate();
+ core.playBgm(main.startBgm);
+}
+
+////// 询问是否需要重新开始 //////
+events.prototype.confirmRestart = function () {
+ core.playSound('打开界面');
+ core.status.event.selection = 1;
+ core.ui.drawConfirmBox("你确定要返回标题页面吗?", function () {
+ core.playSound('确定');
+ core.ui.closePanel();
+ core.restart();
+ }, function () {
+ core.playSound('取消');
+ core.ui.closePanel();
+ });
+}
+
+// ------ 系统事件的处理 ------ //
+
+////// 注册一个系统事件 //////
+// type为事件名,func为事件的处理函数,可接受(data, callback)参数
+events.prototype.registerSystemEvent = function (type, func) {
+ this.systemEvents[type] = func;
+}
+
+////// 注销一个系统事件 //////
+events.prototype.unregisterSystemEvent = function (type) {
+ delete this.systemEvents[type];
+}
+
+////// 执行一个系统事件 //////
+events.prototype.doSystemEvent = function (type, data, callback) {
+ core.clearRouteFolding();
+ if (this.systemEvents[type]) {
+ try {
+ return core.doFunc(this.systemEvents[type], this, data, callback);
+ }
+ catch (e) {
+ console.error(e);
+ console.error("ERROR in systemEvents[" + type + "]");
+ }
+ }
+ if (this["_sys_" + type]) return this["_sys_" + type](data, callback);
+ console.error("未知的系统事件: " + type + "!");
+ if (callback) callback();
+}
+
+////// 触发(x,y)点的事件 //////
+events.prototype.trigger = function (x, y, callback) {
+ var _executeCallback = function () {
+ // 因为trigger之后还有可能触发其他同步脚本(比如阻激夹域检测)
+ // 所以这里强制callback被异步触发
+ if (callback) {
+ setTimeout(callback, 1); // +1是为了录像检测系统
+ }
+ return;
+ }
+ if (core.status.gameOver) return _executeCallback();
+ if (core.status.event.id == 'action') {
+ core.insertAction({ "type": "function", "function": "function () { core.events._trigger_inAction(" + x + "," + y + "); }", "async": true },
+ null, null, null, true);
+ return _executeCallback();
+ }
+ if (core.status.event.id) return _executeCallback();
+
+ var block = core.getBlock(x, y);
+ if (block == null) return _executeCallback();
+
+ // 执行该点的脚本
+ if (block.event.script) {
+ core.clearRouteFolding();
+ try {
+ eval(block.event.script);
+ } catch (ee) { console.error(ee) }
+ }
+
+ // 碰触事件
+ if (block.event.event) {
+ core.clearRouteFolding();
+ core.insertAction(block.event.event, block.x, block.y);
+ // 不再执行该点的系统事件
+ return _executeCallback();
+ }
+
+ if (block.event.trigger && block.event.trigger != 'null') {
+ var noPass = block.event.noPass, trigger = block.event.trigger;
+ if (noPass) core.clearAutomaticRouteNode(x, y);
+
+ // 转换楼层能否穿透
+ if (trigger == 'changeFloor' && !noPass && this._trigger_ignoreChangeFloor(block))
+ return _executeCallback();
+ core.status.automaticRoute.moveDirectly = false;
+ this.doSystemEvent(trigger, block);
+ }
+ return _executeCallback();
+}
+
+events.prototype._trigger_inAction = function (x, y) {
+ if (core.status.gameOver || core.status.event.id != 'action') return;
+
+ var block = core.getBlock(x, y);
+ if (block == null) return core.doAction();
+
+ // 执行该点的脚本
+ try {
+ eval(block.event.script);
+ } catch (ee) { console.error(ee) }
+
+ // 碰触事件
+ if (block.event.event) {
+ core.clearRouteFolding();
+ core.insertAction(block.event.event, block.x, block.y);
+ // 不再执行该点的系统事件
+ return core.doAction();
+ }
+
+ if (block.event.trigger && block.event.trigger != 'null') {
+ this.setEvents(null, x, y);
+ if (block.event.trigger == 'action') {
+ this.insertAction(block.event.data);
+ }
+ else {
+ this.doSystemEvent(block.event.trigger, block, core.doAction);
+ return;
+ }
+ }
+ return core.doAction();
+}
+
+events.prototype._trigger_ignoreChangeFloor = function (block) {
+ var able = core.flags.ignoreChangeFloor;
+ if (block.event.data && block.event.data.ignoreChangeFloor != null)
+ able = block.event.data.ignoreChangeFloor;
+ if (able) {
+ if (core.isReplaying()) {
+ if (core.status.replay.toReplay[0] == 'no') {
+ core.status.replay.toReplay.shift();
+ core.status.route.push("no");
+ return true;
+ }
+ }
+ else if (core.status.automaticRoute.autoHeroMove
+ || core.status.automaticRoute.autoStep < core.status.automaticRoute.autoStepRoutes.length) {
+ core.status.route.push("no");
+ return true;
+ }
+ }
+ return false;
+}
+
+events.prototype._sys_battle = function (data, callback) {
+ // 检查是否需要改变朝向
+ /* if (data.x == core.nextX() && data.y == core.nextY()) {
+ var dir = core.turnDirection(":back");
+ var id = data.event.id, toId = (data.event.faceIds || {})[dir];
+ if (toId && id != toId) {
+ var number = core.getNumberById(toId);
+ if (number > 0)
+ core.setBlock(number, data.x, data.y);
+ }
+ } */
+
+ // 检查战前事件
+ var beforeBattle = [];
+ core.push(beforeBattle, core.floors[core.status.floorId].beforeBattle[data.x + "," + data.y]);
+ core.push(beforeBattle, (core.material.enemys[data.event.id] || {}).beforeBattle);
+ if (beforeBattle.length > 0) {
+ core.push(beforeBattle, [{ "type": "battle", "x": data.x, "y": data.y }]);
+ core.clearContinueAutomaticRoute();
+
+ // 自动存档
+ var inAction = core.status.event.id == 'action';
+ if (inAction) {
+ core.insertAction(beforeBattle, data.x, data.y);
+ core.doAction();
+ } else {
+ core.autosave(true);
+ core.insertAction(beforeBattle, data.x, data.y, callback);
+ }
+ } else {
+ this.battle(data.event.id, data.x, data.y, false, callback);
+ }
+}
+
+////// 战斗 //////
+events.prototype.battle = function (id, x, y, force, callback) {
+ core.saveAndStopAutomaticRoute();
+ id = id || core.getBlockId(x, y);
+ if (!id) return core.clearContinueAutomaticRoute(callback);
+ // 非强制战斗
+ if (!core.enemys.canBattle(id, x, y) && !force && !core.status.event.id) {
+ core.stopSound();
+ core.playSound('操作失败');
+ core.drawTip("你打不过此怪物!", id);
+ return core.clearContinueAutomaticRoute(callback);
+ }
+ // 自动存档
+ if (!core.status.event.id) core.autosave(true);
+ // 战前事件
+ if (!this.beforeBattle(id, x, y))
+ return core.clearContinueAutomaticRoute(callback);
+ // 战后事件
+ this.afterBattle(id, x, y);
+ if (callback) callback();
+}
+
+////// 战斗前触发的事件 //////
+events.prototype.beforeBattle = function (enemyId, x, y) {
+ return this.eventdata.beforeBattle(enemyId, x, y)
+}
+
+////// 战斗结束后触发的事件 //////
+events.prototype.afterBattle = function (enemyId, x, y) {
+ return this.eventdata.afterBattle(enemyId, x, y);
+}
+
+events.prototype._sys_openDoor = function (data, callback) {
+ this.openDoor(data.x, data.y, true, function () {
+ core.replay();
+ if (callback) callback();
+ });
+}
+
+////// 开门 //////
+events.prototype.openDoor = function (x, y, needKey, callback) {
+ var block = core.getBlock(x, y);
+ core.saveAndStopAutomaticRoute();
+ if (!this._openDoor_check(block, x, y, needKey)) {
+ var locked = core.status.lockControl;
+ core.waitHeroToStop(function () {
+ if (!locked) core.unlockControl();
+ if (callback) callback();
+ });
+ return;
+ }
+ if (core.status.replay.speed == 24) {
+ core.status.replay.animate = true;
+ core.removeBlock(x, y);
+ setTimeout(function () {
+ core.status.replay.animate = false;
+ core.events.afterOpenDoor(block.event.id, x, y);
+ if (callback) callback();
+ }, 1); // +1是为了录像检测系统
+ } else {
+ this._openDoor_animate(block, x, y, callback);
+ }
+}
+
+events.prototype._openDoor_check = function (block, x, y, needKey) {
+ var clearAndReturn = function () {
+ core.clearContinueAutomaticRoute();
+ return false;
+ }
+
+ if (block == null || block.event == null) return clearAndReturn();
+ var id = block.event.id;
+
+ // 是否存在门或暗墙
+ if (core.material.icons.animates[id] == null && core.material.icons.npc48[id] == null) {
+ return clearAndReturn();
+ }
+
+ if (id == 'steelDoor' && core.flags.steelDoorWithoutKey)
+ needKey = false;
+ var doorInfo = block.event.doorInfo;
+ if (doorInfo == null) return clearAndReturn();
+ // Check all keys
+ var keyInfo = doorInfo.keys || {};
+ if (needKey) {
+ for (var keyName in keyInfo) {
+ var keyValue = keyInfo[keyName];
+ if (keyName.endsWith(':o')) keyName = keyName.substring(0, keyName.length - 2);
+
+ // --- 如果是一个不存在的道具,则直接认为无法开启
+ if (!core.material.items[keyName]) {
+ core.stopSound();
+ core.playSound('操作失败');
+ core.drawTip("无法开启此门");
+ return clearAndReturn();
+ }
+ if (core.itemCount(keyName) < keyValue) {
+ core.stopSound();
+ core.playSound('操作失败');
+ core.drawTip("你的" + ((core.material.items[keyName] || {}).name || "钥匙") + "不足!", null, true);
+ return false;
+ }
+ }
+ if (!core.status.event.id) core.autosave(true);
+ for (var keyName in keyInfo) {
+ if (!keyName.endsWith(':o')) core.removeItem(keyName, keyInfo[keyName]);
+ }
+ }
+ core.playSound(doorInfo.openSound);
+ return true;
+}
+
+events.prototype._openDoor_animate = function (block, x, y, callback) {
+ var blockInfo = core.getBlockInfo(block);
+ blockInfo.opacity = block.opacity;
+ blockInfo.filter = block.filter;
+
+ var speed = (block.event.doorInfo.time || 160) / 4;
+
+ var locked = core.status.lockControl;
+ core.lockControl();
+ core.status.replay.animate = true;
+ core.removeBlock(x, y);
+
+ blockInfo.posX = 0;
+ core.maps._drawBlockInfo(blockInfo, x, y);
+
+ var cb = function () {
+ core.maps._removeBlockFromMap(core.status.floorId, block);
+ if (!locked) core.unlockControl();
+ core.status.replay.animate = false;
+ core.events.afterOpenDoor(block.event.id, x, y);
+ if (callback) callback();
+ }
+
+ var animate = window.setInterval(function () {
+ blockInfo.posX++;
+ if (blockInfo.posX == 4) {
+ clearInterval(animate);
+ delete core.animateFrame.asyncId[animate];
+ cb();
+ return;
+ }
+ core.maps._drawBlockInfo(blockInfo, x, y);
+ }, core.status.replay.speed == 24 ? 1 : speed / Math.max(core.status.replay.speed, 1));
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = cb;
+}
+
+////// 开一个门后触发的事件 //////
+events.prototype.afterOpenDoor = function (doorId, x, y) {
+ return this.eventdata.afterOpenDoor(doorId, x, y);
+}
+
+events.prototype._sys_getItem = function (data, callback) {
+ this.getItem(data.event.id, 1, data.x, data.y, false, callback);
+}
+
+////// 获得某个物品 //////
+events.prototype.getItem = function (id, num, x, y, isGentleClick, callback) {
+ if (num == null) num = 1;
+ var itemCls = core.material.items[id].cls;
+ core.removeBlock(x, y);
+ core.items.getItemEffect(id, num);
+ var text = '获得 ' + core.material.items[id].name;
+ if (num > 1) text += "x" + num;
+ if (itemCls === 'items' && num == 1) text += core.items.getItemEffectTip(id);
+ core.drawTip(text, id);
+
+ // --- 首次获得道具的提示
+ if (!core.hasFlag("__itemHint__")) core.setFlag("__itemHint__", []);
+ var itemHint = core.getFlag("__itemHint__");
+ if (core.flags.itemFirstText && itemHint.indexOf(id) < 0 && itemCls != 'items') {
+ var hint = core.material.items[id].text || "该道具暂无描述";
+ try {
+ hint = core.replaceText(hint);
+ } catch (e) { }
+ if (!core.status.event.id || core.status.event.id == 'action') {
+ core.insertAction("\t[" + core.material.items[id].name + "," + id + "]" + hint + "\n"
+ + (id.endsWith('Key') ? "(钥匙类道具,遇到对应的门时自动打开)"
+ : itemCls == 'tools' ? "(消耗类道具,请按T在道具栏使用)"
+ : itemCls == 'constants' ? "(永久类道具,请按T在道具栏使用)"
+ : itemCls == 'equips' ? "(装备类道具,请按Q在装备栏进行装备)" : ""));
+ }
+ itemHint.push(id);
+ }
+
+ this.afterGetItem(id, x, y, isGentleClick);
+ if (callback) callback();
+}
+
+events.prototype.afterGetItem = function (id, x, y, isGentleClick) {
+ this.eventdata.afterGetItem(id, x, y, isGentleClick);
+}
+
+////// 获得面前的物品(轻按) //////
+events.prototype.getNextItem = function (noRoute) {
+ if (core.isMoving() || !core.flags.enableGentleClick) return false;
+ if (this._canGetNextItem()) return this._getNextItem(null, noRoute);
+
+ var directions = ["up", "down", "left", "right"].filter(function (dir) {
+ return core.events._canGetNextItem(dir);
+ });
+ return directions.length > 0 ? this._getNextItem(directions[0], noRoute) : false;
+}
+
+events.prototype._canGetNextItem = function (direction) {
+ direction = direction || core.getHeroLoc('direction');
+ if (!core.canMoveHero(null, null, direction)) return;
+ var nx = core.getHeroLoc('x') + core.utils.scan[direction].x;
+ var ny = core.getHeroLoc('y') + core.utils.scan[direction].y;
+ var block = core.getBlock(nx, ny);
+ return block != null && !block.event.script && !block.event.event && block.event.trigger == 'getItem';
+}
+
+events.prototype._getNextItem = function (direction, noRoute) {
+ direction = direction || core.getHeroLoc('direction');
+ var nx = core.getHeroLoc('x') + core.utils.scan[direction].x;
+ var ny = core.getHeroLoc('y') + core.utils.scan[direction].y;
+ if (!noRoute) core.status.route.push("getNext");
+ this.getItem(core.getBlockId(nx, ny), 1, nx, ny, true);
+ return true;
+}
+
+events.prototype._sys_changeFloor = function (data, callback) {
+ data = data.event.data;
+ var heroLoc = {};
+ if (data.loc) heroLoc = { 'x': data.loc[0], 'y': data.loc[1] };
+ if (data.direction) heroLoc.direction = data.direction;
+ if (core.status.event.id != 'action') core.status.event.id = null;
+ core.changeFloor(data.floorId, data.stair, heroLoc, data.time, function () {
+ core.replay();
+ if (callback) callback();
+ });
+}
+
+////// 楼层切换 //////
+events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback) {
+ var info = this._changeFloor_getInfo(floorId, stair, heroLoc, time);
+ if (info == null) {
+ if (callback) callback();
+ return;
+ }
+ floorId = info.floorId;
+ info.locked = core.status.lockControl;
+
+ core.dom.floorNameLabel.innerText = core.status.maps[floorId].title;
+ core.lockControl();
+ core.stopAutomaticRoute();
+ core.clearContinueAutomaticRoute();
+ core.status.replay.animate = true;
+ clearInterval(core.interval.onDownInterval);
+ core.interval.onDownInterval = 'tmp';
+
+ this._changeFloor_beforeChange(info, callback);
+}
+
+events.prototype._changeFloor_getInfo = function (floorId, stair, heroLoc, time) {
+ floorId = floorId || core.status.floorId;
+ if (floorId == ':before') {
+ var index = core.floorIds.indexOf(core.status.floorId);
+ if (index > 0) floorId = core.floorIds[index - 1];
+ else floorId = core.status.floorId;
+ }
+ else if (floorId == ':next') {
+ var index = core.floorIds.indexOf(core.status.floorId);
+ if (index < core.floorIds.length - 1) floorId = core.floorIds[index + 1];
+ else floorId = core.status.floorId;
+ } else if (floorId == ':now') {
+ floorId = core.status.floorId;
+ }
+ if (!core.status.maps[floorId]) {
+ console.error("不存在的楼层:" + floorId);
+ return null;
+ }
+
+ if (main.mode != 'play' || core.isReplaying()) time = 0;
+ if (time == null) time = core.values.floorChangeTime;
+ time /= 20;
+
+ return {
+ floorId: floorId,
+ time: time,
+ heroLoc: core.clone(this._changeFloor_getHeroLoc(floorId, stair, heroLoc))
+ };
+}
+
+events.prototype._changeFloor_getHeroLoc = function (floorId, stair, heroLoc) {
+ if (!heroLoc)
+ heroLoc = core.clone(core.status.hero.loc);
+ if (stair) {
+ // --- 对称
+ if (stair == ':now')
+ heroLoc = core.clone(core.status.hero.loc);
+ else if (stair == ':symmetry') {
+ heroLoc.x = core.bigmap.width - 1 - core.getHeroLoc('x');
+ heroLoc.y = core.bigmap.height - 1 - core.getHeroLoc('y');
+ }
+ else if (stair == ':symmetry_x')
+ heroLoc.x = core.bigmap.width - 1 - core.getHeroLoc('x');
+ else if (stair == ':symmetry_y')
+ heroLoc.y = core.bigmap.height - 1 - core.getHeroLoc('y');
+ // 检查该层地图的 upFloor & downFloor & flyPoint
+ else if (core.status.maps[floorId][stair]) {
+ heroLoc.x = core.status.maps[floorId][stair][0];
+ heroLoc.y = core.status.maps[floorId][stair][1];
+ }
+ else {
+ core.extractBlocks(floorId);
+ var blocks = core.status.maps[floorId].blocks;
+ for (var i in blocks) {
+ if (!blocks[i].disable && blocks[i].event.id === stair) {
+ heroLoc.x = blocks[i].x;
+ heroLoc.y = blocks[i].y;
+ break;
+ }
+ }
+ }
+ }
+ ['x', 'y', 'direction'].forEach(function (name) {
+ if (heroLoc[name] == null)
+ heroLoc[name] = core.getHeroLoc(name);
+ });
+ return heroLoc;
+}
+
+events.prototype._changeFloor_beforeChange = function (info, callback) {
+ this._changeFloor_playSound();
+ // 需要 setTimeout 执行,不然会出错
+ window.setTimeout(function () {
+ if (info.time == 0)
+ core.events._changeFloor_changing(info, callback);
+ else
+ core.showWithAnimate(core.dom.floorMsgGroup, info.time / 2, function () {
+ core.events._changeFloor_changing(info, callback);
+ });
+ }, 25)
+}
+
+events.prototype._changeFloor_playSound = function () {
+ // 播放换层音效
+ if (core.hasFlag('__fromLoad__')) // 是否是读档造成的切换
+ core.playSound('读档');
+ else if (core.hasFlag('__isFlying__')) // 是否是楼传造成的切换
+ core.playSound('飞行器');
+ else
+ core.playSound('上下楼');
+}
+
+events.prototype._changeFloor_changing = function (info, callback) {
+ this.changingFloor(info.floorId, info.heroLoc);
+ // 回归视角
+ var __lockViewport__ = flags.__lockViewport__;
+ core.setFlag('__lockViewport__', null);
+ core.drawHero();
+ core.setFlag('__lockViewport__', __lockViewport__);
+
+ if (info.time == 0)
+ this._changeFloor_afterChange(info, callback);
+ else
+ core.hideWithAnimate(core.dom.floorMsgGroup, info.time / 4, function () {
+ core.events._changeFloor_afterChange(info, callback);
+ });
+}
+
+events.prototype._changeFloor_afterChange = function (info, callback) {
+ if (!info.locked) core.unlockControl();
+ core.status.replay.animate = false;
+ core.events.afterChangeFloor(info.floorId);
+
+ if (callback) callback();
+}
+
+events.prototype.changingFloor = function (floorId, heroLoc) {
+ this.eventdata.changingFloor(floorId, heroLoc);
+}
+
+////// 转换楼层结束的事件 //////
+events.prototype.afterChangeFloor = function (floorId) {
+ if (main.mode != 'play') return;
+ return this.eventdata.afterChangeFloor(floorId);
+}
+
+////// 是否到达过某个楼层 //////
+events.prototype.hasVisitedFloor = function (floorId) {
+ if (!core.hasFlag("__visited__")) core.setFlag("__visited__", {});
+ return core.getFlag("__visited__")[floorId] || false;
+}
+
+////// 到达某楼层 //////
+events.prototype.visitFloor = function (floorId) {
+ if (!core.hasFlag("__visited__")) core.setFlag("__visited__", {});
+ core.getFlag("__visited__")[floorId] = true;
+}
+
+events.prototype._sys_pushBox = function (data, callback) {
+ this.pushBox(data);
+ if (callback) callback();
+}
+
+////// 推箱子 //////
+events.prototype.pushBox = function (data) {
+ if (data.event.id != 'box' && data.event.id != 'boxed') return;
+
+ // 判断还能否前进,看看是否存在事件
+ var direction = core.getHeroLoc('direction'),
+ nx = data.x + core.utils.scan[direction].x, ny = data.y + core.utils.scan[direction].y;
+
+ // 检测能否推上去
+ if (!core.canMoveHero()) return;
+ var canGoDeadZone = core.flags.canGoDeadZone;
+ core.flags.canGoDeadZone = true;
+ if (!core.canMoveHero(data.x, data.y, direction)) {
+ core.flags.canGoDeadZone = canGoDeadZone;
+ return;
+ }
+ core.flags.canGoDeadZone = canGoDeadZone;
+
+ var nextId = core.getBlockId(nx, ny);
+ if (nextId != null && nextId != 'flower') return;
+
+ core.setBlock(nextId == null ? 'box' : 'boxed', nx, ny);
+
+ if (data.event.id == 'box')
+ core.removeBlock(data.x, data.y);
+ else
+ core.setBlock('flower', data.x, data.y);
+ // 勇士前进一格,然后触发推箱子后事件
+ core.insertAction([
+ { "type": "moveAction" },
+ { "type": "function", "function": "function() { core.afterPushBox(); }" }
+ ]);
+}
+
+////// 推箱子后的事件 //////
+events.prototype.afterPushBox = function () {
+ return this.eventdata.afterPushBox();
+}
+
+events.prototype._sys_ski = function (data, callback) {
+ core.insertAction(["V2.6后,请将滑冰放在背景层!"], data.x, data.y);
+ if (callback) callback();
+}
+
+/// 当前是否在冰上
+events.prototype.onSki = function (number) {
+ if (number == null) number = core.getBgNumber();
+ var block = core.getBlockByNumber(number);
+ return block && block.event && block.event.trigger == 'ski';
+}
+
+events.prototype._sys_action = function (data, callback) {
+ var ev = core.clone(data.event.data), ex = data.x, ey = data.y;
+ // 检查是否需要改变朝向
+ if (ex == core.nextX() && ey == core.nextY()) {
+ var dir = core.turnDirection(":back");
+ var id = data.event.id, toId = (data.event.faceIds || {})[dir];
+ if (toId && id != toId) {
+ var number = core.getNumberById(toId);
+ if (number > 0)
+ core.setBlock(number, ex, ey);
+ }
+ }
+ this.insertAction(ev, ex, ey, callback);
+}
+
+events.prototype._sys_custom = function (data, callback) {
+ core.insertAction(["请使用\r[yellow]core.registerSystemEvent('custom', func)\r来处理自己添加的系统触发器!"],
+ data.x, data.y, callback);
+}
+
+// ------ 自定义事件的处理 ------ //
+
+////// 注册一个自定义事件 //////
+// type为事件名,func为事件的处理函数,可接受(data, x, y, prefix)参数
+// data为事件内容,x和y为当前点坐标(可为null),prefix为当前点前缀
+events.prototype.registerEvent = function (type, func) {
+ this.actions[type] = func;
+}
+
+////// 注销一个自定义事件
+events.prototype.unregisterEvent = function (type) {
+ delete this.actions[type];
+}
+
+////// 执行一个自定义事件
+events.prototype.doEvent = function (data, x, y, prefix) {
+ var type = data.type;
+ if (this.actions[type]) {
+ try {
+ return core.doFunc(this.actions[type], this, data, x, y, prefix);
+ }
+ catch (e) {
+ console.error(e);
+ console.error("ERROR in actions[" + type + "]");
+ }
+ }
+ if (this["_action_" + type]) return this["_action_" + type](data, x, y, prefix);
+ core.insertAction("未知的自定义事件: " + type + "!");
+ core.doAction();
+}
+
+events.prototype.setEvents = function (list, x, y, callback) {
+ var data = core.status.event.data || {};
+ if (list) {
+ var l = core.clone(list);
+ if (!(l instanceof Array)) l = [l];
+ l.push({ "type": "_label" });
+ data.list = [{ todo: l, total: core.clone(l), condition: "false" }];
+ // 结束所有正在执行的自动事件
+ if (list.length == 0) {
+ core.status.autoEvents.forEach(function (autoEvent) {
+ core.autoEventExecuting(autoEvent.symbol, false);
+ });
+ }
+ }
+ if (x != null) data.x = x;
+ if (y != null) data.y = y;
+ if (callback) data.callback = callback;
+ if (!data.appendingEvents) data.appendingEvents = [];
+ if (!data.locStack) data.locStack = [];
+ core.status.event.id = 'action';
+ core.status.event.data = data;
+}
+
+////// 开始执行一系列自定义事件 //////
+events.prototype.startEvents = function (list, x, y, callback) {
+ if (!list) return;
+ if (!(list instanceof Array)) {
+ list = [list];
+ }
+ this.setEvents(list, x, y, callback);
+ // 停止勇士
+ core.waitHeroToStop(function () {
+ core.lockControl();
+ core.doAction();
+ });
+}
+
+////// 执行当前自定义事件列表中的下一个事件 //////
+events.prototype.doAction = function () {
+ // 清空boxAnimate和UI层
+ clearInterval(core.status.event.interval);
+ clearTimeout(core.status.event.interval);
+ clearInterval(core.status.event.animateUI);
+ core.status.event.interval = null;
+ delete core.status.event.aniamteUI;
+ if (core.status.gameOver || core.status.replay.failed) return;
+ // 判定是否执行完毕
+ if (this._doAction_finishEvents()) return;
+ core.clearUI();
+ var floorId = core.status.event.data.floorId || core.status.floorId;
+ // 当前点坐标和前缀
+ var x = core.status.event.data.x, y = core.status.event.data.y;
+ var prefix = [floorId || ":f", x != null ? x : "x", y != null ? y : "y"].join("@");
+ var current = core.status.event.data.list[0];
+ if (this._popEvents(current, prefix)) return;
+ // 当前要执行的事件
+ var data = current.todo.shift();
+ core.status.event.data.current = data;
+ if (typeof data == "string")
+ data = { "type": "text", "text": data };
+ // 该事件块已经被禁用
+ if (data._disabled) return core.doAction();
+ data.floorId = data.floorId || floorId;
+ core.status.event.data.type = data.type;
+ this.doEvent(data, x, y, prefix);
+ return;
+}
+
+events.prototype._doAction_finishEvents = function () {
+ if (core.status.event.id != 'action') return true;
+ // 事件处理完毕
+ if (core.status.event.data.list.length == 0) {
+ // 检测并执行延迟自动事件
+ if (core.status.event.data.appendingEvents.length > 0) {
+ this.setEvents(core.status.event.data.appendingEvents.shift());
+ return false;
+ }
+ var callback = core.status.event.data.callback;
+ core.ui.closePanel();
+ if (callback) callback();
+ core.replay();
+ return true;
+ }
+ return false;
+}
+
+events.prototype._popEvents = function (current, prefix) {
+ if (current.todo.length == 0) { // current list is empty
+ if (core.calValue(current.condition, prefix)) { // check condition
+ current.todo = core.clone(current.total);
+ }
+ else {
+ core.status.event.data.list.shift(); // remove stack
+ }
+ core.doAction();
+ return true;
+ }
+ return false;
+}
+
+////// 往当前事件列表之前或之后添加一个或多个事件 //////
+events.prototype.insertAction = function (action, x, y, callback, addToLast) {
+ if (core.hasFlag("__statistics__")) return;
+ if (core.status.gameOver) return;
+ if (!action) return;
+ core.clearRouteFolding();
+
+ action = this.precompile(action);
+
+ if (core.status.event.id != 'action') {
+ this.startEvents(action, x, y, callback);
+ }
+ else {
+ if (addToLast) {
+ var list = core.status.event.data.list[0].todo;
+ var index = 0;
+ for (var index = 0; index < list.length; index++) {
+ if (list[index].type == '_label') {
+ list.splice(index, 0, action);
+ break;
+ }
+ }
+ }
+ else core.unshift(core.status.event.data.list[0].todo, action);
+ this.setEvents(null, x, y, callback);
+ }
+}
+
+////// 往当前事件列表之前或之后添加一个公共事件 //////
+events.prototype.insertCommonEvent = function (name, args, x, y, callback, addToLast) {
+ var commonEvent = this.getCommonEvent(name);
+ if (!commonEvent) {
+ if (callback) callback();
+ return;
+ }
+
+ // 设置参数
+ core.setFlag('arg0', name);
+ if (args instanceof Array) {
+ for (var i = 0; i < args.length; ++i) {
+ try {
+ if (args[i] != null)
+ core.setFlag('arg' + (i + 1), args[i]);
+ } catch (ee) { console.error(ee) }
+ }
+ }
+
+ this.insertAction({ "type": "dowhile", "condition": "false", "data": commonEvent }, x, y, callback, addToLast);
+}
+
+////// 获得一个公共事件 //////
+events.prototype.getCommonEvent = function (name) {
+ if (!name || typeof name !== 'string') return null;
+ return this.commonEvent[name] || null;
+}
+
+////// 恢复一个事件 //////
+events.prototype.recoverEvents = function (data) {
+ if (data) {
+ core.ui.closePanel();
+ core.lockControl();
+ core.status.event.id = 'action';
+ core.status.event.data = data;
+ setTimeout(function () {
+ core.doAction();
+ }, 30);
+ return true;
+ }
+ return false;
+}
+
+////// 检测自动事件 //////
+events.prototype.checkAutoEvents = function () {
+ // 只有在无操作或事件流中才能执行自动事件!
+ if (!core.isPlaying() || (core.status.lockControl && core.status.event.id != 'action')) return;
+ if (core.hasFlag('__doNotCheckAutoEvents__')) return;
+ var todo = [], delay = [];
+ core.status.autoEvents.forEach(function (autoEvent) {
+ var symbol = autoEvent.symbol, x = autoEvent.x, y = autoEvent.y, floorId = autoEvent.floorId;
+ // 不在当前楼层 or 已经执行过 or 已被分区 or 正在执行中
+ if (autoEvent.currentFloor && floorId != core.status.floorId) return;
+ if (!autoEvent.multiExecute && core.autoEventExecuted(symbol)) return;
+ if ((flags.__removed__ || []).indexOf(floorId) >= 0) return;
+ if (core.autoEventExecuting(symbol)) return;
+ var prefix = floorId + "@" + x + "@" + y;
+ try {
+ if (!core.calValue(autoEvent.condition, prefix)) return;
+ } catch (e) {
+ return;
+ }
+
+ core.autoEventExecuting(symbol, true);
+ core.autoEventExecuted(symbol, true);
+
+ var event;
+ if (x == null && y == null) {
+ event = [
+ // 用do-while(0)包一层防止break影响事件流
+ { "type": "dowhile", "condition": "false", "data": autoEvent.data },
+ {
+ "type": "function", "function":
+ "function() { core.autoEventExecuting('" + symbol + "', false); }"
+ }
+ ];
+ } else {
+ event = [
+ {
+ "type": "function", "function":
+ "function() { core.pushEventLoc(" + x + ", " + y + ", '" + floorId + "' ); }"
+ },
+ // 用do-while(0)包一层防止break影响事件流
+ { "type": "dowhile", "condition": "false", "data": autoEvent.data },
+ {
+ "type": "function", "function":
+ "function() { core.popEventLoc(); core.autoEventExecuting('" + symbol + "', false); }"
+ }
+ ];
+ }
+
+ if (autoEvent.delayExecute)
+ delay.push(event);
+ else
+ core.push(todo, event);
+ });
+
+ if (todo.length == 0 && delay.length == 0) return;
+
+ if (core.status.event.id == 'action' || todo.length > 0) {
+ core.insertAction(todo);
+ core.push(core.status.event.data.appendingEvents, delay);
+ } else {
+ core.insertAction(delay[0]);
+ if (delay.length > 0) {
+ core.insertAction(delay.slice(1));
+ }
+ }
+
+}
+
+events.prototype.autoEventExecuting = function (symbol, value) {
+ var aei = core.getFlag('__aei__', []);
+ if (value == null) return aei.indexOf(symbol) >= 0;
+ else {
+ aei = aei.filter(function (one) { return one != symbol; });
+ if (value) aei.push(symbol);
+ core.setFlag('__aei__', aei);
+ }
+}
+
+events.prototype.autoEventExecuted = function (symbol, value) {
+ var aed = core.getFlag('__aed__', []);
+ if (value == null) return aed.indexOf(symbol) >= 0;
+ else {
+ aed = aed.filter(function (one) { return one != symbol; });
+ if (value) aed.push(symbol);
+ core.setFlag('__aed__', aed);
+ }
+}
+
+events.prototype.pushEventLoc = function (x, y, floorId) {
+ if (core.status.event.id != 'action') return;
+ core.status.event.data.locStack.push({
+ x: core.status.event.data.x,
+ y: core.status.event.data.y,
+ floorId: core.status.event.data.floorId
+ });
+ core.status.event.data.x = x;
+ core.status.event.data.y = y;
+ core.status.event.data.floorId = floorId;
+}
+
+events.prototype.popEventLoc = function () {
+ if (core.status.event.id != 'action') return;
+ var loc = core.status.event.data.locStack.shift();
+ if (loc) {
+ core.status.event.data.x = loc.x;
+ core.status.event.data.y = loc.y;
+ core.status.event.data.floorId = loc.floorId;
+ }
+}
+
+events.prototype.precompile = function (data) {
+ var array = this.__precompile_getArray();
+ if (typeof data == 'string') {
+ return this.__precompile_text(data);
+ }
+ if (data instanceof Array) {
+ for (var i = 0; i < data.length; ++i) {
+ data[i] = this.precompile(data[i]);
+ }
+ return data;
+ }
+ if (data && data.type) {
+ if (this["_precompile_" + data.type]) {
+ data = this["_precompile_" + data.type](data);
+ }
+ if (array.texts.indexOf(data.type) >= 0) {
+ data.text = this.__precompile_text(data.text);
+ }
+ if (array.locs.indexOf(data.type) >= 0) {
+ data.loc = this.__precompile_array(data.loc);
+ }
+ if (array.values.indexOf(data.type) >= 0) {
+ data.value = core.replaceValue(data.value);
+ }
+ if (array.uievents.indexOf(data.type) >= 0) {
+ data.x = core.replaceValue(data.x);
+ data.y = core.replaceValue(data.y);
+ data.width = core.replaceValue(data.width);
+ data.height = core.replaceValue(data.height);
+ }
+ if (data.type in array.others) {
+ array.others[data.type].forEach(function (field) {
+ data[field] = core.replaceValue(data[field]);
+ })
+ }
+ }
+ return data;
+}
+
+events.prototype.__precompile_getArray = function () {
+ var texts = [
+ "text", "autoText", "scrollText", "tip", "textImage", "input", "input2",
+ "choices", "confirm", "fillText", "fillBoldText", "drawTextContent"
+ ];
+ var locs = [
+ "show", "hide", "setBlock", "setBlockOpacity", "showFloorImg", "hideFloorImg", "showBgFgMap",
+ "hideBgFgMap", "setBgFgBlock", "animate", "setViewport", "move", "jumoHero",
+ "changeFloor", "changePos", "showTextImage", "showGif", "openDoor",
+ "closeDoor", "battle", "trigger", "insert", "setEnemyOnPoint", "resetEnemyOnPoint"
+ ];
+ var values = [
+ "setValue", "setEnemy", "setEnemyOnPoint", "setEquip", "setFloor", "setGlobalValue",
+ ];
+ var uievents = [
+ "clearMap", "fillText", "fillBoldText", "fillRect", "strokeRect", "fillEllipse", "strokeEllipse",
+ "fillArc", "strokeArc", "drawIcon", "drawSelector", "drawBackground",
+ ];
+ var others = {
+ "fillEllipse": ["a", "b", "angle"],
+ "strokeEllipse": ["a", "b", "angle"],
+ "fillRect": ["radius", "angle"],
+ "strokeRect": ["radius", "angle"],
+ "fillArc": ["r", "start", "end"],
+ "strokeArc": ["r", "start", "end"],
+ "drawLine": ["x1", "y1", "x2", "y2"],
+ "drawArrow": ["x1", "y1", "x2", "y2"],
+ "drawImage": ["x", "y", "w", "h", "x1", "y1", "w1", "h1", "angle"],
+ "drawTextContent": ["left", "top"],
+ };
+ return {
+ texts: texts,
+ locs: locs,
+ values: values,
+ uievents: uievents,
+ others: others
+ };
+}
+
+events.prototype.__precompile_text = function (text) {
+ if (typeof text != 'string') return text;
+ return text.replace(/\${(.*?)}/g, function (word, value) {
+ return "${" + core.replaceValue(value) + "}";
+ });
+}
+
+events.prototype.__precompile_array = function (value) {
+ if (typeof value == 'string') {
+ value = core.replaceValue(value);
+ return value;
+ }
+ if (value instanceof Array) {
+ for (var i = 0; i < value.length; ++i) {
+ value[i] = this.__precompile_array(value[i]);
+ }
+ }
+ return value;
+}
+
+// ------ 样板提供的的自定义事件 ------ //
+
+events.prototype.__action_checkReplaying = function () {
+ if (core.isReplaying()) {
+ core.doAction();
+ return true;
+ }
+ return false;
+}
+
+events.prototype.__action_getLoc = function (loc, x, y, prefix) {
+ if (loc) {
+ x = core.calValue(loc[0], prefix);
+ y = core.calValue(loc[1], prefix);
+ }
+ return [x, y];
+}
+
+events.prototype.__action_getHeroLoc = function (loc, prefix) {
+ return this.__action_getLoc(loc, core.getHeroLoc('x'), core.getHeroLoc('y'), prefix);
+}
+
+events.prototype.__action_getLoc2D = function (loc, x, y, prefix) {
+ if (!(loc && loc[0] instanceof Array))
+ loc = [this.__action_getLoc(loc, x, y, prefix)];
+ return loc;
+}
+
+events.prototype.__action_doAsyncFunc = function (isAsync, func) {
+ var parameters = Array.prototype.slice.call(arguments, 2);
+ if (isAsync) {
+ func.apply(this, parameters);
+ core.doAction();
+ }
+ else {
+ func.apply(this, parameters.concat(core.doAction));
+ }
+}
+
+events.prototype._action_text = function (data, x, y, prefix) {
+ if (this.__action_checkReplaying()) return;
+ data.text = core.replaceText(data.text, prefix);
+ var ctx = data.code ? ('__text__' + data.code) : null;;
+ data.ctx = ctx;
+ if (core.getContextByName(ctx) && !data.showAll) {
+ core.ui._animateUI('hide', ctx, function () {
+ core.ui.drawTextBox(data.text, data);
+ core.ui._animateUI('show', ctx, function () {
+ if (data.async) core.doAction();
+ });
+ });
+ return;
+ }
+ core.ui.drawTextBox(data.text, data);
+ if (!data.showAll) {
+ core.ui._animateUI('show', ctx, function () {
+ if (data.async) core.doAction();
+ });
+ }
+}
+
+events.prototype._action_moveTextBox = function (data, x, y, prefix) {
+ if (this.__action_checkReplaying()) return;
+ this.__action_doAsyncFunc(data.async, core.moveTextBox,
+ data.code, this.__action_getLoc(data.loc, x, y, prefix), data.relative, data.moveMode, data.time);
+}
+
+events.prototype._action_clearTextBox = function (data, x, y, prefix) {
+ if (this.__action_checkReplaying()) return;
+ core.clearTextBox(data.code, core.doAction);
+}
+
+events.prototype._action_autoText = function (data, x, y, prefix) {
+ if (this.__action_checkReplaying()) return;
+ data.text = core.replaceText(data.text, prefix);
+ core.ui.drawTextBox(data.text);
+ setTimeout(core.doAction, data.time || 3000);
+}
+
+events.prototype._action_scrollText = function (data, x, y, prefix) {
+ if (this.__action_checkReplaying()) return;
+ data.text = core.replaceText(data.text, prefix);
+ this.__action_doAsyncFunc(data.async, core.drawScrollText, data.text, data.time || 5000, data.lineHeight || 1.4);
+}
+
+events.prototype._action_comment = function (data, x, y, prefix) {
+ core.doAction();
+}
+
+events.prototype._action__label = function (data, x, y, prefix) {
+ core.doAction();
+}
+
+events.prototype._action_setText = function (data, x, y, prefix) {
+ this.setTextAttribute(data);
+ core.doAction();
+}
+
+events.prototype._action_tip = function (data, x, y, prefix) {
+ core.drawTip(core.replaceText(data.text, prefix), data.icon);
+ core.doAction();
+}
+
+events.prototype._action_show = function (data, x, y, prefix) {
+ data.loc = this.__action_getLoc2D(data.loc, x, y, prefix);
+ if (data.time > 0 && data.floorId == core.status.floorId) {
+ this.__action_doAsyncFunc(data.async, core.animateBlock, data.loc, 'show', data.time);
+ }
+ else {
+ data.loc.forEach(function (t) {
+ core.showBlock(t[0], t[1], data.floorId);
+ });
+ core.doAction();
+ }
+}
+
+events.prototype._action_hide = function (data, x, y, prefix) {
+ data.loc = this.__action_getLoc2D(data.loc, x, y, prefix);
+ if (data.time > 0 && data.floorId == core.status.floorId) {
+ this.__action_doAsyncFunc(data.async, core.animateBlock, data.loc, data.remove ? 'remove' : 'hide', data.time);
+ }
+ else {
+ data.loc.forEach(function (t) {
+ if (data.remove) core.removeBlock(t[0], t[1], data.floorId);
+ else core.hideBlock(t[0], t[1], data.floorId);
+ });
+ core.doAction();
+ }
+}
+
+events.prototype._action_setBlock = function (data, x, y, prefix) {
+ data.loc = this.__action_getLoc2D(data.loc, x, y, prefix);
+ data.time = data.time || 0;
+ data.floorId = data.floorId || core.status.floorId;
+ if (data.time > 0 && data.floorId == core.status.floorId) {
+ this.__action_doAsyncFunc(data.async, core.animateSetBlocks, data.number, data.loc, data.floorId, data.time);
+ } else {
+ data.loc.forEach(function (loc) {
+ core.setBlock(data.number, loc[0], loc[1], data.floorId);
+ });
+ core.doAction();
+ }
+}
+
+events.prototype._action_setBlockOpacity = function (data, x, y, prefix) {
+ data.loc = this.__action_getLoc2D(data.loc, x, y, prefix);
+ if (data.time > 0 && data.floorId == core.status.floorId) {
+ this.__action_doAsyncFunc(data.async, core.animateBlock, data.loc, data.opacity, data.time);
+ }
+ else {
+ data.loc.forEach(function (t) {
+ core.setBlockOpacity(data.opacity, t[0], t[1], data.floorId);
+ });
+ core.doAction();
+ }
+}
+
+events.prototype._action_setBlockFilter = function (data, x, y, prefix) {
+ data.loc = this.__action_getLoc2D(data.loc, x, y, prefix);
+ data.loc.forEach(function (t) {
+ core.setBlockFilter(data, t[0], t[1], data.floorId);
+ });
+ core.doAction();
+}
+
+events.prototype._action_turnBlock = function (data, x, y, prefix) {
+ data.loc = this.__action_getLoc2D(data.loc, x, y, prefix);
+ data.loc.forEach(function (t) {
+ core.turnBlock(data.direction, t[0], t[1], data.floorId);
+ });
+ core.doAction();
+}
+
+events.prototype._action_showFloorImg = function (data, x, y, prefix) {
+ core.maps.showFloorImage(this.__action_getLoc2D(data.loc, x, y, prefix), data.floorId, core.doAction);
+}
+
+events.prototype._action_hideFloorImg = function (data, x, y, prefix) {
+ core.maps.hideFloorImage(this.__action_getLoc2D(data.loc, x, y, prefix), data.floorId, core.doAction);
+}
+
+events.prototype._action_showBgFgMap = function (data, x, y, prefix) {
+ core.maps.showBgFgMap(data.name, this.__action_getLoc2D(data.loc, x, y, prefix), data.floorId, core.doAction)
+}
+
+events.prototype._action_hideBgFgMap = function (data, x, y, prefix) {
+ core.maps.hideBgFgMap(data.name, this.__action_getLoc2D(data.loc, x, y, prefix), data.floorId, core.doAction);
+}
+
+events.prototype._action_setBgFgBlock = function (data, x, y, prefix) {
+ data.loc = this.__action_getLoc2D(data.loc, x, y, prefix);
+ data.loc.forEach(function (t) {
+ core.setBgFgBlock(data.name, data.number, t[0], t[1], data.floorId);
+ });
+ core.doAction();
+}
+
+events.prototype._action_follow = function (data, x, y, prefix) {
+ this.follow(data.name);
+ core.doAction();
+}
+
+events.prototype._action_unfollow = function (data, x, y, prefix) {
+ this.unfollow(data.name);
+ core.doAction();
+}
+
+events.prototype._action_animate = function (data, x, y, prefix) {
+ if (data.loc == 'hero') {
+ this.__action_doAsyncFunc(data.async, core.drawHeroAnimate, data.name);
+ } else {
+ data.loc = this.__action_getLoc(data.loc, x, y, prefix);
+ this.__action_doAsyncFunc(data.async, core.drawAnimate, data.name, data.loc[0], data.loc[1], data.alignWindow);
+ }
+}
+
+events.prototype._action_stopAnimate = function (data, x, y, prefix) {
+ core.stopAnimate(null, data.doCallback);
+ core.doAction();
+}
+
+events.prototype._action_setViewport = function (data, x, y, prefix) {
+ if (data.dxy != null) {
+ data.loc = [core.bigmap.offsetX / 32 + (core.calValue(data.dxy[0], prefix) || 0), core.bigmap.offsetY / 32 + (core.calValue(data.dxy[1], prefix) || 0)];
+ } else if (data.loc == null) {
+ data.loc = [core.getHeroLoc('x') - core._HALF_WIDTH_, core.getHeroLoc('y') - core._HALF_HEIGHT_];
+ } else {
+ data.loc = this.__action_getLoc(data.loc, x, y, prefix);
+ }
+ this.__action_doAsyncFunc(data.async, core.moveViewport, data.loc[0], data.loc[1], data.moveMode, data.time);
+}
+
+events.prototype._action_lockViewport = function (data, x, y, prefix) {
+ core.setFlag('__lockViewport__', data.lock || null);
+ core.doAction();
+}
+
+events.prototype._action_move = function (data, x, y, prefix) {
+ var loc = this.__action_getLoc(data.loc, x, y, prefix);
+ this.__action_doAsyncFunc(data.async, core.moveBlock, loc[0], loc[1], data.steps, data.time, data.keep);
+}
+
+events.prototype._action_moveAction = function (data, x, y, prefix) {
+ // 检查下一个点是否可通行
+ if (core.canMoveHero()) {
+ var nx = core.nextX(), ny = core.nextY();
+ // 检查noPass决定是撞击还是移动
+ if (core.noPass(nx, ny)) {
+ core.insertAction([
+ { "type": "trigger", "loc": [nx, ny] }
+ ]);
+ } else {
+ // 先移动一格,然后尝试触发事件
+ core.insertAction([
+ { "type": "moveHero", "steps": ["forward"] },
+ { "type": "function", "function": "function() { core.moveOneStep(core.doAction); }", "async": true },
+ { "type": "_label" },
+ ]);
+ }
+ }
+ core.doAction();
+}
+
+events.prototype._action_moveHero = function (data, x, y, prefix) {
+ this.__action_doAsyncFunc(data.async, core.eventMoveHero, data.steps, data.time);
+}
+
+events.prototype._action_jump = function (data, x, y, prefix) {
+ var from = this.__action_getLoc(data.from, x, y, prefix), to;
+ if (data.dxy) {
+ to = [from[0] + (core.calValue(data.dxy[0], prefix) || 0), from[1] + (core.calValue(data.dxy[1], prefix) || 0)];
+ } else {
+ to = this.__action_getLoc(data.to, x, y, prefix);
+ }
+ this.__action_doAsyncFunc(data.async, core.jumpBlock, from[0], from[1], to[0], to[1], data.time, data.keep);
+}
+
+events.prototype._precompile_jump = function (data) {
+ data.from = this.__precompile_array(data.from);
+ data.to = this.__precompile_array(data.to);
+ data.dxy = this.__precompile_array(data.dxy);
+ return data;
+}
+
+events.prototype._action_jumpHero = function (data, x, y, prefix) {
+ var loc;
+ if (data.dxy) {
+ loc = [core.getHeroLoc('x') + (core.calValue(data.dxy[0], prefix) || 0), core.getHeroLoc('y') + (core.calValue(data.dxy[1], prefix) || 0)];
+ } else {
+ loc = this.__action_getHeroLoc(data.loc, prefix);
+ }
+ this.__action_doAsyncFunc(data.async, core.jumpHero, loc[0], loc[1], data.time);
+}
+
+events.prototype._action_changeFloor = function (data, x, y, prefix) {
+ var loc = this.__action_getHeroLoc(data.loc, prefix);
+ var heroLoc = { x: loc[0], y: loc[1], direction: data.direction };
+ core.changeFloor(data.floorId, data.stair, heroLoc, data.time, core.doAction);
+}
+
+events.prototype._action_changePos = function (data, x, y, prefix) {
+ core.clearMap('hero');
+ if (!data.loc && data.direction) {
+ core.setHeroLoc('direction', core.turnDirection(data.direction), true);
+ core.drawHero();
+ return core.doAction();
+ }
+
+ var loc = this.__action_getHeroLoc(data.loc, prefix);
+ core.setHeroLoc('x', loc[0]);
+ core.setHeroLoc('y', loc[1]);
+ if (data.direction) core.setHeroLoc('direction', core.turnDirection(data.direction));
+ core.drawHero();
+ core.doAction();
+}
+
+events.prototype._action_showImage = function (data, x, y, prefix) {
+ if (core.isReplaying()) data.time = 0;
+ this.__action_doAsyncFunc(data.async || data.time == 0, core.showImage,
+ data.code, data.image + (data.reverse || ''), data.sloc, data.loc, data.opacity, data.time);
+}
+
+events.prototype._precompile_showImage = function (data) {
+ data.sloc = this.__precompile_array(data.sloc);
+ data.loc = this.__precompile_array(data.loc);
+ return data;
+}
+
+events.prototype._action_showTextImage = function (data, x, y, prefix) {
+ var loc = this.__action_getLoc(data.loc, 0, 0, prefix);
+ if (core.isReplaying()) data.time = 0;
+ data.text = core.replaceText(data.text, prefix);
+ var __tmpName = (Math.random() + "_" + Math.random()).replace(/\./g, "") + ".png";
+ core.material.images.images[__tmpName] = core.ui.textImage(data.text);
+ this.__action_doAsyncFunc(data.async || data.time == 0, core.showImage,
+ data.code, __tmpName + (data.reverse || ""), null, loc, data.opacity, data.time);
+ delete core.material.images.images[__tmpName];
+}
+
+events.prototype._action_hideImage = function (data, x, y, prefix) {
+ if (core.isReplaying()) data.time = 0;
+ this.__action_doAsyncFunc(data.async || data.time == 0, core.hideImage, data.code, data.time);
+}
+
+events.prototype._action_showGif = function (data, x, y, prefix) {
+ var loc = this.__action_getLoc(data.loc, 0, 0, prefix);
+ this.showGif(data.name, loc[0], loc[1]);
+ core.doAction();
+}
+
+events.prototype._action_moveImage = function (data, x, y, prefix) {
+ if (this.__action_checkReplaying()) return;
+ this.__action_doAsyncFunc(data.async, core.moveImage, data.code, data.to, data.opacity, data.moveMode, data.time);
+}
+
+events.prototype._precompile_moveImage = function (data) {
+ data.to = this.__precompile_array(data.to);
+ return data;
+}
+
+events.prototype._action_rotateImage = function (data, x, y, prefix) {
+ if (this.__action_checkReplaying()) return;
+ this.__action_doAsyncFunc(data.async, core.rotateImage, data.code, data.center, data.angle, data.moveMode, data.time);
+}
+
+events.prototype._precompile_rotateImage = function (data) {
+ data.center = this.__precompile_array(data.center);
+ return data;
+}
+
+events.prototype._action_scaleImage = function (data, x, y, prefix) {
+ if (this.__action_checkReplaying()) return;
+ this.__action_doAsyncFunc(data.async, core.scaleImage, data.code, data.center, data.scale, data.moveMode, data.time);
+}
+
+events.prototype._precompile_scaleImage = function (data) {
+ data.center = this.__precompile_array(data.center);
+ return data;
+}
+
+events.prototype._action_setCurtain = function (data, x, y, prefix) {
+ if (data.async) {
+ core.setCurtain(data.color || core.status.thisMap.color, data.time, data.moveMode);
+ if (data.color == null || data.keep) core.setFlag('__color__', data.color || null);
+ core.doAction();
+ }
+ else {
+ core.setCurtain(data.color || core.status.thisMap.color, data.time, data.moveMode, function () {
+ if (data.color == null || data.keep) core.setFlag('__color__', data.color || null);
+ core.doAction();
+ });
+ }
+}
+
+events.prototype._action_screenFlash = function (data, x, y, prefix) {
+ this.__action_doAsyncFunc(data.async, core.screenFlash, data.color, data.time, data.times, data.moveMode);
+}
+
+events.prototype._action_setWeather = function (data, x, y, prefix) {
+ core.setWeather(data.name, data.level);
+ if (data.keep && ['rain', 'snow', 'sun', 'fog', 'cloud'].indexOf(data.name) >= 0)
+ core.setFlag('__weather__', [data.name, data.level]);
+ else core.removeFlag('__weather__');
+ core.doAction();
+}
+
+events.prototype._action_openDoor = function (data, x, y, prefix) {
+ var loc = this.__action_getLoc(data.loc, x, y, prefix);
+ var floorId = data.floorId;
+ if (floorId == core.status.floorId) {
+ this.__action_doAsyncFunc(data.async, core.openDoor, loc[0], loc[1], data.needKey);
+ }
+ else {
+ core.removeBlock(loc[0], loc[1], floorId);
+ core.doAction();
+ }
+}
+
+events.prototype._action_closeDoor = function (data, x, y, prefix) {
+ var loc = this.__action_getLoc(data.loc, x, y, prefix);
+ this.__action_doAsyncFunc(data.async, core.closeDoor, loc[0], loc[1], data.id);
+}
+
+events.prototype._action_useItem = function (data, x, y, prefix) {
+ // 考虑到可能覆盖楼传事件的问题,这里不对fly进行检查。
+ if (data.id != 'book' && core.canUseItem(data.id)) {
+ core.useItem(data.id, true, core.doAction);
+ }
+ else {
+ core.playSound('操作失败');
+ core.drawTip("当前无法使用" + ((core.material.items[data.id] || {}).name || "未知道具"));
+ core.doAction();
+ }
+}
+
+events.prototype._action_loadEquip = function (data, x, y, prefix) {
+ core.loadEquip(data.id);
+ core.doAction();
+}
+
+events.prototype._action_unloadEquip = function (data, x, y, prefix) {
+ core.unloadEquip(data.pos);
+ core.doAction();
+}
+
+events.prototype._action_openShop = function (data, x, y, prefix) {
+ core.setShopVisited(data.id, true);
+ if (data.open) core.openShop(data.id, true);
+ core.doAction();
+}
+
+events.prototype._action_disableShop = function (data, x, y, prefix) {
+ core.setShopVisited(data.id, false);
+ core.doAction();
+}
+
+events.prototype._action_battle = function (data, x, y, prefix) {
+ if (data.id) {
+ this.battle(data.id, null, null, true, core.doAction);
+ }
+ else {
+ if (data.floorId != core.status.floorId) {
+ core.doAction();
+ return;
+ }
+ var loc = this.__action_getLoc(data.loc, x, y, prefix);
+ this.battle(null, loc[0], loc[1], true, core.doAction);
+ }
+}
+
+events.prototype._action_trigger = function (data, x, y, prefix) {
+ var loc = this.__action_getLoc(data.loc, x, y, prefix);
+ this._trigger_inAction(loc[0], loc[1]);
+}
+
+events.prototype._action_insert = function (data, x, y, prefix) {
+ if (data.name) { // 公共事件
+ core.insertCommonEvent(data.name, data.args);
+ }
+ else {
+ // 设置参数
+ if (data.args instanceof Array) {
+ for (var i = 0; i < data.args.length; ++i) {
+ try {
+ if (data.args[i] != null)
+ core.setFlag('arg' + (i + 1), data.args[i]);
+ } catch (ee) { console.error(ee) }
+ }
+ }
+ var loc = this.__action_getLoc(data.loc, x, y, prefix);
+ core.setFlag('arg0', loc);
+ var floorId = data.floorId;
+ var which = data.which || "events";
+ var event = (core.floors[floorId][which] || [])[loc[0] + "," + loc[1]];
+ if (event) this.insertAction(event.data || event);
+ }
+ core.doAction();
+}
+
+events.prototype._action_playBgm = function (data, x, y, prefix) {
+ core.playBgm(data.name, data.startTime || 0);
+ core.setFlag("__bgm__", data.keep ? data.name : null);
+ core.doAction();
+}
+
+events.prototype._action_pauseBgm = function (data, x, y, prefix) {
+ core.pauseBgm();
+ core.doAction();
+}
+
+events.prototype._action_resumeBgm = function (data, x, y, prefix) {
+ core.resumeBgm(data.resume);
+ core.doAction();
+}
+
+events.prototype._action_loadBgm = function (data, x, y, prefix) {
+ core.loadBgm(data.name);
+ core.doAction();
+}
+
+events.prototype._action_freeBgm = function (data, x, y, prefix) {
+ core.freeBgm(data.name);
+ core.doAction();
+}
+
+events.prototype._action_playSound = function (data, x, y, prefix) {
+ if (data.stop) core.stopSound();
+ if (data.sync) {
+ core.playSound(data.name, data.pitch, core.doAction);
+ } else {
+ core.playSound(data.name, data.pitch);
+ core.doAction();
+ }
+}
+
+events.prototype._action_stopSound = function (data, x, y, prefix) {
+ core.stopSound();
+ core.doAction();
+}
+
+events.prototype._action_setVolume = function (data, x, y, prefix) {
+ data.value = core.clamp(parseInt(data.value) / 100, 0, 1);
+ core.setFlag("__volume__", data.value);
+ this.__action_doAsyncFunc(data.async, core.setVolume, data.value, data.time || 0);
+}
+
+events.prototype._action_setBgmSpeed = function (data, x, y, prefix) {
+ core.setBgmSpeed(data.value, data.pitch || false);
+ core.doAction();
+}
+
+events.prototype._action_setValue = function (data, x, y, prefix) {
+ this.setValue(data.name, data.operator, data.value, prefix);
+ if (!data.norefresh) {
+ if (core.status.hero.hp <= 0) {
+ core.status.hero.hp = 0;
+ core.updateStatusBar();
+ core.events.lose();
+ } else {
+ core.updateStatusBar();
+ }
+ }
+ core.doAction();
+}
+
+events.prototype._action_addValue = function (data, x, y, prefix) {
+ data.operator = '+=';
+ this._action_setValue(data, x, y, prefix);
+}
+
+events.prototype._action_setEnemy = function (data, x, y, prefix) {
+ this.setEnemy(data.id, data.name, data.value, data.operator, prefix, data.norefresh);
+ core.doAction();
+}
+
+events.prototype._action_setEnemyOnPoint = function (data, x, y, prefix) {
+ var loc = this.__action_getLoc2D(data.loc, x, y, prefix);
+ loc.forEach(function (one) {
+ core.setEnemyOnPoint(one[0], one[1], data.floorId, data.name, data.value, data.operator, prefix, data.norefresh);
+ });
+ core.doAction();
+}
+
+events.prototype._action_resetEnemyOnPoint = function (data, x, y, prefix) {
+ var loc = this.__action_getLoc2D(data.loc, x, y, prefix);
+ loc.forEach(function (one) {
+ core.resetEnemyOnPoint(one[0], one[1], data.floorId, data.norefresh);
+ });
+ core.doAction();
+}
+
+events.prototype._precompile_moveEnemyOnPoint = function (data) {
+ data.from = this.__precompile_array(data.from);
+ data.to = this.__precompile_array(data.to);
+ data.dxy = this.__precompile_array(data.dxy);
+ return data;
+}
+
+events.prototype._action_moveEnemyOnPoint = function (data, x, y, prefix) {
+ var from = this.__action_getLoc(data.from, x, y, prefix), to;
+ if (data.dxy) {
+ to = [from[0] + (core.calValue(data.dxy[0], prefix) || 0), from[1] + (core.calValue(data.dxy[1], prefix) || 0)];
+ } else {
+ to = this.__action_getLoc(data.to, x, y, prefix);
+ }
+ this.moveEnemyOnPoint(from[0], from[1], to[0], to[1], data.floorId, data.norefresh);
+ core.doAction();
+}
+
+events.prototype._action_setEquip = function (data, x, y, prefix) {
+ core.setEquip(data.id, data.valueType, data.name, data.value, data.operator, prefix);
+ core.doAction();
+}
+
+events.prototype._action_setFloor = function (data, x, y, prefix) {
+ this.setFloorInfo(data.name, data.value, data.floorId, prefix);
+ core.doAction();
+}
+
+events.prototype._action_setGlobalAttribute = function (data, x, y, prefix) {
+ this.setGlobalAttribute(data.name, data.value);
+ core.doAction();
+}
+
+events.prototype._action_setGlobalValue = function (data, x, y, prefix) {
+ core.values[data.name] = data.value;
+ core.doAction();
+}
+
+events.prototype._action_setGlobalFlag = function (data, x, y, prefix) {
+ this.setGlobalFlag(data.name, data.value);
+ core.doAction();
+}
+
+events.prototype._action_setNameMap = function (data, x, y, floorId) {
+ this.setNameMap(data.name, data.value);
+ core.doAction();
+}
+
+events.prototype._action_setHeroIcon = function (data, x, y, prefix) {
+ this.setHeroIcon(data.name, data.noDraw);
+ core.doAction();
+}
+
+events.prototype._action_input = function (data, x, y, prefix) {
+ this.__action_getInput(core.replaceText(data.text, prefix), false, function (value) {
+ value = parseInt(value) || 0; // 允许负整数
+ core.status.route.push("input:" + value);
+ core.setFlag("input", value);
+ core.doAction();
+ });
+}
+
+events.prototype._action_input2 = function (data, x, y, prefix) {
+ this.__action_getInput(core.replaceText(data.text, prefix), true, function (value) {
+ value = value || "";
+ core.status.route.push("input2:" + core.encodeBase64(value));
+ core.setFlag("input", value);
+ core.doAction();
+ });
+}
+
+events.prototype.__action_getInput = function (hint, isText, callback) {
+ var value, prefix = isText ? "input2:" : "input:";
+ if (core.isReplaying()) {
+ var action = core.status.replay.toReplay.shift();
+ try {
+ if (action.indexOf(prefix) != 0) {
+ console.warn("警告!当前需要一个 " + prefix + " 项,实际为 " + action);
+ core.status.replay.toReplay.unshift(action);
+ return callback(isText ? '' : 0);
+ }
+ if (isText) value = core.decodeBase64(action.substring(7));
+ else value = parseInt(action.substring(6));
+ callback(value);
+ }
+ catch (e) {
+ core.control._replay_error(action);
+ return;
+ }
+ }
+ else {
+ core.myprompt(core.replaceText(hint), null, callback);
+ }
+}
+
+events.prototype._action_if = function (data, x, y, prefix) {
+ if (core.calValue(data.condition, prefix))
+ core.events.insertAction(data["true"])
+ else
+ core.events.insertAction(data["false"])
+ core.doAction();
+}
+
+events.prototype._precompile_if = function (data) {
+ data.condition = core.replaceValue(data.condition);
+ data["true"] = this.precompile(data["true"]);
+ data["false"] = this.precompile(data["false"]);
+ return data;
+}
+
+events.prototype._action_switch = function (data, x, y, prefix) {
+ var key = core.calValue(data.condition, prefix)
+ var list = [];
+ for (var i = 0; i < data.caseList.length; i++) {
+ if (data.caseList[i]._disabled) continue;
+ var condition = data.caseList[i]["case"];
+ if (condition == "default" || core.calValue(condition, prefix) === key) {
+ core.push(list, data.caseList[i].action);
+ if (!data.caseList[i].nobreak)
+ break;
+ }
+ }
+ core.insertAction(list);
+ core.doAction();
+}
+
+events.prototype._precompile_switch = function (data) {
+ data.condition = core.replaceValue(data.condition);
+ for (var i = 0; i < data.caseList.length; i++) {
+ data.caseList[i]["case"] = core.replaceValue(data.caseList[i]["case"]);
+ data.caseList[i].action = this.precompile(data.caseList[i].action);
+ }
+ return data;
+}
+
+events.prototype._action_choices = function (data, x, y, prefix) {
+ data.choices = data.choices.filter(function (x) {
+ if (x._disabled) return false;
+ if (x.condition == null || x.condition == '') return true;
+ try { return core.calValue(x.condition, prefix); } catch (e) { return true; }
+ })
+ if (data.choices.length == 0) return this.doAction();
+ if (core.isReplaying()) {
+ var action = core.status.replay.toReplay.shift();
+ if (action.indexOf('choices:') == 0 && !(action == 'choices:none' && !data.timeout)) {
+ var index = action.substring(8);
+ if (!this.__action_choices_replaying(data, index)) {
+ core.control._replay_error(action);
+ return;
+ }
+ } else {
+ // 容错录像
+ if (main.replayChecking) {
+ // 录像验证系统中选最后一项
+ if (action != 'choices:none') core.status.replay.toReplay.unshift(action); // 首先归还刚才读出的下一步操作
+ core.events.__action_choices_replaying(data, -1);
+ } else {
+ // 正常游戏中弹窗选择
+ core.myprompt('录像回放出错!当前需要执行选择项但录像中未记录。\n如需修复请输入您要选的项(从0起),点击取消将不会修复。', 0, function (value) {
+ if (value == null) {
+ core.control._replay_error(action);
+ return;
+ }
+ if (action != 'choices:none') core.status.replay.toReplay.unshift(action); // 首先归还刚才读出的下一步操作
+ core.events.__action_choices_replaying(data, ((parseInt(value) || 0) + data.choices.length) % data.choices.length);
+ });
+ }
+ }
+ } else {
+ if (data.timeout) {
+ core.status.event.interval = setTimeout(function () {
+ core.status.route.push("choices:none");
+ core.setFlag('timeout', 0);
+ core.doAction();
+ }, data.timeout);
+ }
+ core.status.event.timeout = new Date().getTime() + (data.timeout || 0);
+ }
+ for (var i = 0; i < data.choices.length; i++) {
+ if (typeof data.choices[i] === 'string')
+ data.choices[i] = { "text": data.choices[i] };
+ data.choices[i].text = core.replaceText(data.choices[i].text, prefix);
+ }
+ core.ui.drawChoices(core.replaceText(data.text, prefix), data.choices, data.width);
+}
+
+events.prototype.__action_choices_replaying = function (data, index) {
+ var selection = index;
+ if (index != 'none') {
+ selection = parseInt(index);
+ if (isNaN(selection)) return false;
+ if (selection < 0) selection += data.choices.length;
+ if (selection < 0) return false;
+ if (selection % 100 > 50) selection += data.choices.length;
+ if (selection % 100 > data.choices.length) return false;
+ var timeout = Math.floor(selection / 100) || 0;
+ core.setFlag('timeout', timeout);
+ selection %= 100;
+ } else core.setFlag('timeout', 0);
+ core.status.event.selection = selection;
+ setTimeout(function () {
+ core.status.route.push("choices:" + index);
+ if (selection != 'none') {
+ // 检查
+ var choice = data.choices[selection];
+ if (choice.need != null && choice.need != '' && !core.calValue(choice.need)) {
+ // 无法选择此项
+ core.control._replay_error("无法选择项:" + index);
+ return;
+ } else {
+ core.insertAction(choice.action);
+ }
+ }
+ core.doAction();
+ }, core.status.replay.speed == 24 ? 1 : 750 / Math.max(1, core.status.replay.speed));
+ return true;
+}
+
+events.prototype._precompile_choices = function (data) {
+ if (!(data.choices instanceof Array)) return data;
+ for (var i = 0; i < data.choices.length; ++i) {
+ data.choices[i].condition = core.replaceValue(data.choices[i].condition);
+ data.choices[i].text = this.__precompile_text(data.choices[i].text);
+ data.choices[i].action = this.precompile(data.choices[i].action);
+ }
+ return data;
+}
+
+events.prototype._action_confirm = function (data, x, y, prefix) {
+ data.text = core.replaceText(data.text, prefix);
+ core.status.event.ui = { "text": data.text, "yes": data.yes, "no": data.no };
+ if (core.isReplaying()) {
+ var action = core.status.replay.toReplay.shift();
+ if (action.indexOf('choices:') == 0 && !(action == 'choices:none' && !data.timeout)) {
+ var index = action.substring(8);
+ if (index == 'none' || ((index = parseInt(index)) >= 0) && index % 100 < 2) {
+ this.__action_confirm_replaying(data, index);
+ } else {
+ core.control._replay_error(action);
+ return;
+ }
+ } else {
+ // 录像中未记录选了哪个,则选默认值,而不是直接报错
+ if (action != 'choices:none') core.status.replay.toReplay.unshift(action);
+ this.__action_confirm_replaying(data, data["default"] ? 0 : 1);
+ }
+ }
+ else {
+ core.status.event.selection = data["default"] ? 0 : 1;
+ if (data.timeout) {
+ core.status.event.interval = setTimeout(function () {
+ core.status.route.push("choices:none");
+ core.setFlag('timeout', 0);
+ core.doAction();
+ }, data.timeout);
+ }
+ core.status.event.timeout = new Date().getTime() + (data.timeout || 0);
+ }
+ core.ui.drawConfirmBox(data.text);
+}
+
+events.prototype.__action_confirm_replaying = function (data, index) {
+ if (index != 'none') {
+ var timeout = Math.floor(index / 100) || 0;
+ core.setFlag('timeout', timeout);
+ index %= 100;
+ } else core.setFlag('timeout', 0);
+ core.status.event.selection = index;
+ setTimeout(function () {
+ core.status.route.push("choices:" + index);
+ if (index != 'none') {
+ if (index == 0) core.insertAction(data.yes);
+ else core.insertAction(data.no);
+ }
+ core.doAction();
+ }, core.status.replay.speed == 24 ? 1 : 750 / Math.max(1, core.status.replay.speed));
+}
+
+events.prototype._precompile_confirm = function (data) {
+ data.yes = this.precompile(data.yes);
+ data.no = this.precompile(data.no);
+ return data;
+}
+
+events.prototype._action_for = function (data, x, y, prefix) {
+ // Only support temp:A
+ if (!/^temp:[A-Z]$/.test(data.name)) {
+ core.insertAction('循环遍历事件只支持临时变量!');
+ return core.doAction();
+ }
+ var from = core.calValue(data.from);
+ var to = core.calValue(data.to);
+ var step = core.calValue(data.step);
+ if (typeof from != 'number' || typeof to != 'number' || typeof step != 'number') {
+ core.insertAction('循环遍历事件要求【起始点】【终止点】【每步】仅能是数字!');
+ return core.doAction();
+ }
+ // 首次判定
+ if ((step > 0 && from > to) || (step < 0 && from < to)) {
+ core.doAction();
+ return;
+ }
+
+ var letter = data.name.substring(5);
+ core.setFlag('@temp@' + letter, from);
+ var toName = '@temp@for-to@' + letter;
+ var stepName = '@temp@for-step@' + letter;
+ core.setFlag(toName, data.to);
+ core.setFlag(stepName, data.step);
+ var condition = "(function () {" +
+ "var to = core.calValue(core.getFlag('" + toName + "'));" +
+ "var step = core.calValue(core.getFlag('" + stepName + "'));" +
+ "if (typeof step != 'number' || typeof to != 'number') return false;" +
+ "if (step == 0) return true;" +
+ "var currentValue = core.getFlag('@temp@" + letter + "');" +
+ "currentValue += step;" +
+ "core.setFlag('@temp@" + letter + "', currentValue);" +
+ "if (step > 0) { return currentValue <= to; }" +
+ "else { return currentValue >= to; }" +
+ "})()";
+ return this._action_dowhile({ "condition": condition, "data": data.data }, x, y, prefix);
+}
+
+events.prototype._precompile_for = function (data) {
+ data.from = core.replaceValue(data.from);
+ data.to = core.replaceValue(data.to);
+ data.step = core.replaceValue(data.step);
+ data.data = this.precompile(data.data);
+ return data;
+}
+
+events.prototype._action_forEach = function (data, x, y, prefix) {
+ // Only support temp:A
+ if (!/^temp:[A-Z]$/.test(data.name)) {
+ core.insertAction(['循环遍历事件只支持临时变量!']);
+ return core.doAction();
+ }
+ var listName = '@temp@forEach@' + data.name.substring(5);
+ core.setFlag(listName, core.clone(data.list));
+ var condition = "(function () {" +
+ "var list = core.getFlag('" + listName + "', []);" +
+ "if (list.length == 0) return false;" +
+ "core.setFlag('@temp@'+'" + data.name.substring(5) + "', list.shift());" +
+ "return true;" +
+ "})()";
+ return this._action_while({ "condition": condition, "data": data.data }, x, y, prefix);
+}
+
+events.prototype._precompile_forEach = function (data) {
+ data.data = this.precompile(data.data);
+ return data;
+}
+
+events.prototype._action_while = function (data, x, y, prefix) {
+ if (core.calValue(data.condition, prefix)) {
+ var list = core.clone(data.data);
+ if (!(list instanceof Array)) list = [list];
+ list.push({ "type": "_label" });
+ core.unshift(core.status.event.data.list,
+ { "todo": list, "total": core.clone(list), "condition": data.condition }
+ );
+ }
+ core.doAction();
+}
+
+events.prototype._precompile_while = function (data) {
+ data.condition = core.replaceValue(data.condition);
+ data.data = this.precompile(data.data);
+ return data;
+}
+
+events.prototype._action_dowhile = function (data, x, y, prefix) {
+ var list = core.clone(data.data);
+ if (!(list instanceof Array)) list = [list];
+ list.push({ "type": "_label" });
+ core.unshift(core.status.event.data.list,
+ { "todo": list, "total": core.clone(list), "condition": data.condition }
+ );
+ core.doAction();
+}
+
+events.prototype._precompile_dowhile = function (data) {
+ data.condition = core.replaceValue(data.condition);
+ data.data = this.precompile(data.data);
+ return data;
+}
+
+events.prototype._action_break = function (data, x, y, prefix) {
+ var n = data.n || 1;
+ while (n--) {
+ if (core.status.event.data.list.length > 1)
+ core.status.event.data.list.shift();
+ }
+ core.doAction();
+}
+
+events.prototype._action_continue = function (data, x, y, prefix) {
+ var n = data.n || 1;
+ while (n-- > 1) {
+ if (core.status.event.data.list.length > 1)
+ core.status.event.data.list.shift();
+ }
+ if (core.status.event.data.list.length > 1) {
+ if (core.calValue(core.status.event.data.list[0].condition, prefix)) {
+ core.status.event.data.list[0].todo = core.clone(core.status.event.data.list[0].total);
+ }
+ else {
+ core.status.event.data.list.shift();
+ }
+ }
+ core.doAction();
+}
+
+events.prototype._action_win = function (data, x, y, prefix) {
+ this.win(core.replaceText(data.reason, prefix), data.norank, data.noexit);
+}
+
+events.prototype._action_lose = function (data, x, y, prefix) {
+ this.lose(core.replaceText(data.reason, prefix));
+}
+
+events.prototype._action_restart = function (data, x, y, prefix) {
+ core.restart();
+}
+
+events.prototype._action_function = function (data, x, y, prefix) {
+ var func = data["function"];
+ try {
+ if (typeof func == "string" && func.indexOf("function") == 0) {
+ eval('(' + func + ')()');
+ }
+ } catch (e) {
+ console.error(e);
+ }
+ if (!data.async)
+ core.doAction();
+}
+
+events.prototype._action_update = function (data, x, y, prefix) {
+ core.updateStatusBar(data.doNotCheckAutoEvents, true);
+ core.doAction();
+}
+
+events.prototype._action_showStatusBar = function (data, x, y, prefix) {
+ core.showStatusBar();
+ core.doAction();
+}
+
+events.prototype._action_hideStatusBar = function (data, x, y, prefix) {
+ core.hideStatusBar(data.toolbox);
+ core.doAction();
+}
+
+events.prototype._action_showHero = function (data, x, y, prefix) {
+ data.opacity = 1;
+ return this._action_setHeroOpacity(data, x, y, prefix);
+}
+
+events.prototype._action_hideHero = function (data, x, y, prefix) {
+ data.opacity = 0;
+ return this._action_setHeroOpacity(data, x, y, prefix);
+}
+
+events.prototype._action_setHeroOpacity = function (data, x, y, prefix) {
+ data.time = data.time || 0;
+ if (data.opacity == null) data.opacity = 1;
+ if (data.time > 0) {
+ this.__action_doAsyncFunc(data.async, core.setHeroOpacity, data.opacity, data.moveMode, data.time);
+ } else {
+ core.setFlag('__heroOpacity__', data.opacity);
+ core.drawHero();
+ core.doAction();
+ }
+}
+
+events.prototype._action_vibrate = function (data, x, y, prefix) {
+ this.__action_doAsyncFunc(data.async, core.vibrate, data.direction, data.time, data.speed, data.power);
+}
+
+events.prototype._action_sleep = function (data, x, y, prefix) {
+ core.timeout.sleepTimeout = setTimeout(function () {
+ core.timeout.sleepTimeout = null;
+ core.doAction();
+ }, core.isReplaying() ? Math.min(data.time, 20) : data.time);
+}
+
+events.prototype._action_wait = function (data, x, y, prefix) {
+ if (core.isReplaying()) {
+ var code = core.status.replay.toReplay.shift();
+ if (code.indexOf("input:") == 0 && !(code == "input:none" && !data.timeout)) {
+ if (code == "input:none") {
+ core.status.route.push("input:none");
+ core.setFlag("type", -1);
+ core.setFlag("timeout", 0);
+ this.__action_wait_afterGet(data);
+ return core.doAction();
+ } else {
+ var value = parseInt(code.substring(6));
+ core.status.route.push("input:" + value);
+ this.__action_wait_getValue(value);
+ if (this.__action_wait_afterGet(data) || !data.forceChild) return core.doAction();
+ }
+ }
+ core.control._replay_error(code);
+ return;
+ } else if (data.timeout) {
+ core.status.event.interval = setTimeout(function () {
+ core.status.route.push("input:none");
+ core.setFlag("type", -1);
+ core.setFlag("timeout", 0);
+ core.events.__action_wait_afterGet(data);
+ core.doAction();
+ }, data.timeout);
+ }
+ core.status.event.timeout = new Date().getTime() + (data.timeout || 0);
+}
+
+events.prototype.__action_wait_getValue = function (value) {
+ core.setFlag("timeout", Math.floor(value / 1e8) || 0);
+ value %= 1e8;
+ if (value >= 1000000) {
+ core.setFlag('type', 1);
+ var px = parseInt((value - 1000000) / 1000), py = value % 1000;
+ core.setFlag('px', px);
+ core.setFlag('py', py);
+ core.setFlag('x', parseInt(px / 32));
+ core.setFlag('y', parseInt(py / 32));
+ }
+ else if (value >= 10000) {
+ core.setFlag('type', 1);
+ var x = parseInt((value - 10000) / 100), y = value % 100;
+ core.setFlag('px', 32 * x + 16);
+ core.setFlag('py', 32 * y + 16);
+ core.setFlag('x', x);
+ core.setFlag('y', y);
+ }
+ else if (value > 0) {
+ core.setFlag('type', 0);
+ core.setFlag('keycode', value);
+ }
+}
+
+events.prototype.__action_wait_afterGet = function (data) {
+ if (!data.data) return false;
+ var todo = [];
+ var stop = false;
+ var found = false;
+ data.data.forEach(function (one) {
+ if (one._disabled || stop) return;
+ if (one["case"] == "keyboard" && core.getFlag("type") == 0) {
+ (one.keycode + "").split(",").forEach(function (keycode) {
+ if (core.getFlag("keycode", 0) == keycode) {
+ found = true;
+ core.push(todo, one.action);
+ if (one["break"]) stop = true;
+ }
+ });
+ }
+ if (one["case"] == "mouse" && one.px instanceof Array
+ && one.py instanceof Array && core.getFlag("type") == 1) {
+ var pxmin = core.calValue(one.px[0]);
+ var pxmax = core.calValue(one.px[1]);
+ var pymin = core.calValue(one.py[0]);
+ var pymax = core.calValue(one.py[1]);
+ var px = core.getFlag("px", 0), py = core.getFlag("py", 0);
+ if (px >= pxmin && px <= pxmax && py >= pymin && py <= pymax) {
+ found = true;
+ core.push(todo, one.action);
+ if (one["break"]) stop = true;
+ }
+ }
+ if (one["case"] == "condition") {
+ var condition = false;
+ try { condition = core.calValue(one.condition); } catch (e) { }
+ if (condition) {
+ found = true;
+ core.push(todo, one.action);
+ if (one["break"]) stop = true;
+ }
+ }
+ if (one["case"] == "timeout" && core.getFlag("type") == -1) {
+ found = true;
+ core.push(todo, one.action);
+ if (one["break"]) stop = true;
+ }
+ })
+ if (found) {
+ core.insertAction(todo);
+ return true;
+ }
+ return false;
+}
+
+events.prototype._precompile_wait = function (data) {
+ if (data.data) {
+ data.data.forEach(function (v) {
+ if (v.px != null) v.px = this.__precompile_array(v.px);
+ if (v.py != null) v.py = this.__precompile_array(v.py);
+ if (v.condition != null) v.condition = this.__precompile_array(v.condition);
+ v.action = this.precompile(v.action);
+ }, this);
+ }
+ return data;
+}
+
+events.prototype._action_waitAsync = function (data, x, y, prefix) {
+ var test = window.setInterval(function () {
+ if (!core.hasAsync()
+ && (data.excludeAnimates || core.isReplaying() || core.getPlayingAnimates().length == 0)
+ && (!data.includeSounds || core.isReplaying() || core.getPlayingSounds().length == 0)) {
+ clearInterval(test);
+ core.doAction();
+ }
+ }, 50 / core.status.replay.speed);
+}
+
+events.prototype._action_stopAsync = function (data, x, y, prefix) {
+ core.stopAsync();
+ core.doAction();
+}
+
+events.prototype._action_callBook = function (data, x, y, prefix) {
+ if (core.isReplaying() || !core.hasItem('book')) {
+ core.doAction();
+ }
+ else {
+ var e = core.clone(core.status.event.data);
+ core.ui.closePanel();
+ core.openBook();
+ core.status.event.interval = e;
+ }
+}
+
+events.prototype._action_callSave = function (data, x, y, prefix) {
+ if (core.isReplaying() || core.hasFlag("__events__")) {
+ core.removeFlag("__events__");
+ core.doAction();
+ }
+ else {
+ var e = core.clone(core.status.event.data);
+ core.ui.closePanel();
+ var forbidSave = core.hasFlag('__forbidSave__');
+ core.removeFlag('__forbidSave__');
+ core.save();
+ if (forbidSave) core.setFlag('__forbidSave__', true);
+ core.status.event.interval = e;
+ }
+}
+
+events.prototype._action_autoSave = function (data, x, y, prefix) {
+ var forbidSave = core.hasFlag('__forbidSave__');
+ core.removeFlag('__forbidSave__');
+ core.autosave(data.removeLast);
+ if (forbidSave) core.setFlag('__forbidSave__', true);
+ core.doAction();
+}
+
+events.prototype._action_forbidSave = function (data, x, y, prefix) {
+ core.setFlag('__forbidSave__', data.forbid || null);
+ core.doAction();
+}
+
+events.prototype._action_callLoad = function (data, x, y, prefix) {
+ if (this.__action_checkReplaying()) return;
+ var e = core.clone(core.status.event.data);
+ core.ui.closePanel();
+ core.load();
+ core.status.event.interval = e;
+}
+
+events.prototype._action_exit = function (data, x, y, prefix) {
+ this.setEvents([]);
+ core.doAction();
+}
+
+events.prototype._action_previewUI = function (data, x, y, prefix) {
+ this.insertAction(data.action);
+ core.doAction();
+}
+
+events.prototype._precompile_previewUI = function (data) {
+ data.action = this.precompile(data.action);
+ return data;
+}
+
+events.prototype.__action_doUIEvent = function (data) {
+ this.__action_doUIEvent_doOne(data);
+ var current = core.status.event.data.list[0];
+ while (current.todo.length > 0) {
+ data = current.todo[0];
+ if (this.__action_doUIEvent_doOne(current.todo[0]))
+ current.todo.shift();
+ else break;
+ }
+ core.doAction();
+}
+
+events.prototype.__action_doUIEvent_doOne = function (data) {
+ if (core.ui['_uievent_' + data.type]) {
+ core.ui['_uievent_' + data.type](data);
+ return true;
+ }
+ return false;
+}
+
+events.prototype._action_clearMap = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_fillText = function (data, x, y, prefix) {
+ data.text = core.replaceText(data.text, prefix);
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_fillBoldText = function (data, x, y, prefix) {
+ data.text = core.replaceText(data.text, prefix);
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_fillRect = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_fillPolygon = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._precompile_fillPolygon = function (data) {
+ data.nodes = this.__precompile_array(data.nodes);
+ return data;
+}
+
+events.prototype._action_strokeRect = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_strokePolygon = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._precompile_strokePolygon = function (data) {
+ data.nodes = this.__precompile_array(data.nodes);
+ return data;
+}
+
+events.prototype._action_fillEllipse = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_strokeEllipse = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_fillArc = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_strokeArc = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_drawLine = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_drawArrow = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_setAttribute = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_setFilter = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_drawImage = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_drawIcon = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_drawSelector = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_drawBackground = function (data, x, y, prefix) {
+ this.__action_doUIEvent(data);
+}
+
+events.prototype._action_drawTextContent = function (data, x, y, prefix) {
+ data.text = core.replaceText(data.text, prefix);
+ this.__action_doUIEvent(data);
+}
+
+// ------ 点击状态栏图标所进行的一些操作 ------ //
+
+////// 判断当前能否进入某个事件 //////
+events.prototype._checkStatus = function (name, fromUserAction, checkItem) {
+ if (fromUserAction && core.status.event.id == name) {
+ core.ui.closePanel();
+ return false;
+ }
+ if (fromUserAction && core.status.lockControl) return false;
+ if (checkItem && !core.hasItem(name)) {
+ core.playSound('操作失败');
+ core.drawTip("你没有" + core.material.items[name].name, name);
+ return false;
+ }
+ if (core.isMoving()) {
+ core.playSound('操作失败');
+ core.drawTip("请先停止勇士行动");
+ return false;
+ }
+ core.lockControl();
+ core.status.event.id = name;
+ return true;
+}
+
+////// 点击怪物手册时的打开操作 //////
+events.prototype.openBook = function (fromUserAction) {
+ if (core.isReplaying()) return;
+ // 如果能恢复事件(从callBook事件触发)
+ if (core.status.event.id == 'book' && core.events.recoverEvents(core.status.event.interval))
+ return;
+ // 当前是book,且从“浏览地图”打开
+ if (core.status.event.id == 'book' && core.status.event.ui) {
+ core.status.boxAnimateObjs = [];
+ core.ui._drawViewMaps(core.status.event.ui);
+ return;
+ }
+ // 从“浏览地图”页面打开
+ if (core.status.event.id == 'viewMaps') {
+ fromUserAction = false;
+ core.status.event.ui = core.status.event.data;
+ }
+ if (!this._checkStatus('book', fromUserAction, true)) return;
+ core.playSound('打开界面');
+ core.useItem('book', true);
+}
+
+////// 点击楼层传送器时的打开操作 //////
+events.prototype.useFly = function (fromUserAction) {
+ if (core.isReplaying()) return;
+ // 从“浏览地图”页面:尝试直接传送到该层
+ if (core.status.event.id == 'viewMaps') {
+ if (!core.hasItem('fly')) {
+ core.playSound('操作失败');
+ core.drawTip('你没有' + core.material.items['fly'].name, 'fly');
+ } else if (!core.canUseItem('fly') || (core.flags.flyNearStair && !core.nearStair())) {
+ core.playSound('操作失败');
+ core.drawTip('无法传送到当前层', 'fly');
+ } else {
+ core.flyTo(core.status.event.data.floorId);
+ }
+ return;
+ }
+
+ if (!this._checkStatus('fly', fromUserAction, true)) return;
+ if (core.flags.flyNearStair && !core.nearStair()) {
+ core.playSound('操作失败');
+ core.drawTip("只有在楼梯边才能使用" + core.material.items['fly'].name, 'fly');
+ core.unlockControl();
+ core.status.event.data = null;
+ core.status.event.id = null;
+ return;
+ }
+ if (!core.canUseItem('fly')) {
+ core.playSound('操作失败');
+ core.drawTip(core.material.items['fly'].name + "好像失效了", 'fly');
+ core.unlockControl();
+ core.status.event.data = null;
+ core.status.event.id = null;
+ return;
+ }
+ core.playSound('打开界面');
+ core.useItem('fly', true);
+ return;
+}
+
+events.prototype.flyTo = function (toId, callback) {
+ return this.eventdata.flyTo(toId, callback);
+}
+
+////// 点击装备栏时的打开操作 //////
+events.prototype.openEquipbox = function (fromUserAction) {
+ if (core.isReplaying()) return;
+ if (!this._checkStatus('equipbox', fromUserAction)) return;
+ core.playSound('打开界面');
+ core.ui._drawEquipbox();
+}
+
+////// 点击工具栏时的打开操作 //////
+events.prototype.openToolbox = function (fromUserAction) {
+ if (core.isReplaying()) return;
+ if (!this._checkStatus('toolbox', fromUserAction)) return;
+ core.playSound('打开界面');
+ core.ui._drawToolbox();
+}
+
+////// 点击快捷商店按钮时的打开操作 //////
+events.prototype.openQuickShop = function (fromUserAction) {
+ if (core.isReplaying()) return;
+
+ if (Object.keys(core.status.shops).length == 0) {
+ core.playSound('操作失败');
+ core.drawTip("本游戏没有快捷商店!");
+ return;
+ }
+
+ // --- 如果只有一个商店,则直接打开之
+ if (Object.keys(core.status.shops).length == 1) {
+ var shopId = Object.keys(core.status.shops)[0];
+ if (core.status.event.id != null) return;
+ if (!core.canOpenShop(shopId)) {
+ core.playSound('操作失败');
+ core.drawTip("当前无法打开快捷商店!");
+ return;
+ }
+ var message = core.canUseQuickShop(shopId);
+ if (message != null) {
+ core.playSound('操作失败');
+ core.drawTip(message);
+ return;
+ }
+ core.openShop(shopId, false);
+ return;
+ }
+
+ if (!this._checkStatus('selectShop', fromUserAction)) return;
+ core.ui._drawQuickShop();
+}
+
+events.prototype.openKeyBoard = function (fromUserAction) {
+ if (core.isReplaying()) return;
+ if (!this._checkStatus('keyBoard', fromUserAction)) return;
+ core.ui._drawKeyBoard();
+}
+
+////// 点击保存按钮时的打开操作 //////
+events.prototype.save = function (fromUserAction) {
+ if (core.isReplaying()) return;
+ if (core.hasFlag('__forbidSave__')) {
+ core.playSound('操作失败');
+ core.drawTip('当前禁止存档');
+ return;
+ }
+ if (core.status.event.id == 'save' && core.events.recoverEvents(core.status.event.interval))
+ return;
+ if (!this._checkStatus('save', fromUserAction)) return;
+ var saveIndex = core.saves.saveIndex;
+ var page = parseInt((saveIndex - 1) / 5), offset = saveIndex - 5 * page;
+ core.playSound('打开界面');
+ core.ui._drawSLPanel(10 * page + offset);
+}
+
+////// 点击读取按钮时的打开操作 //////
+events.prototype.load = function (fromUserAction) {
+ if (core.isReplaying()) return;
+ var saveIndex = core.saves.saveIndex;
+ var page = parseInt((saveIndex - 1) / 5), offset = saveIndex - 5 * page;
+ // 游戏开始前读档
+ if (!core.isPlaying()) {
+ core.dom.startPanel.style.display = 'none';
+ core.clearStatus();
+ core.clearMap('all');
+ core.status.event = { 'id': 'load', 'data': null };
+ core.status.lockControl = true;
+ core.playSound('打开界面');
+ core.ui._drawSLPanel(10 * page + offset);
+ return;
+ }
+ if (core.status.event.id == 'load' && core.events.recoverEvents(core.status.event.interval))
+ return;
+ if (!this._checkStatus('load', fromUserAction)) return;
+ core.playSound('打开界面');
+ core.ui._drawSLPanel(10 * page + offset);
+}
+
+////// 点击设置按钮时的操作 //////
+events.prototype.openSettings = function (fromUserAction) {
+ if (core.isReplaying()) return;
+ if (!this._checkStatus('settings', fromUserAction))
+ return;
+ core.playSound('打开界面');
+ core.ui._drawSettings();
+}
+
+// ------ 一些事件的具体执行过程 ------ //
+
+events.prototype.hasAsync = function () {
+ return Object.keys(core.animateFrame.asyncId).length > 0;
+}
+
+////// 立刻停止所有异步事件 //////
+events.prototype.stopAsync = function () {
+ var callbacks = [];
+ for (var id in core.animateFrame.asyncId) {
+ clearInterval(id);
+ callbacks.push(core.animateFrame.asyncId[id]);
+ }
+ core.animateFrame.asyncId = {};
+ callbacks.forEach(function (cb) {
+ if (cb && cb instanceof Function) cb();
+ });
+}
+
+events.prototype.hasAsyncAnimate = function () {
+ return (core.status.animateObjs || []).length > 0;
+}
+
+////// 跟随 //////
+events.prototype.follow = function (name) {
+ name = core.getMappedName(name);
+ if (core.material.images.images[name]) {
+ core.status.hero.followers.push({ "name": name });
+ core.gatherFollowers();
+ core.clearMap('hero');
+ core.drawHero();
+ }
+ core.clearRouteFolding();
+}
+
+////// 取消跟随 //////
+events.prototype.unfollow = function (name) {
+ if (!name) {
+ core.status.hero.followers = [];
+ }
+ else {
+ name = core.getMappedName(name);
+ for (var i = 0; i < core.status.hero.followers.length; i++) {
+ if (core.status.hero.followers[i].name == name) {
+ core.status.hero.followers.splice(i, 1);
+ break;
+ }
+ }
+ }
+ core.gatherFollowers();
+ core.clearMap('hero');
+ core.drawHero();
+ core.clearRouteFolding();
+}
+
+events.prototype._updateValueByOperator = function (value, originValue, operator) {
+ switch (operator) {
+ case '+=': value = originValue + value; break;
+ case '-=': value = originValue - value; break;
+ case '*=': value = originValue * value; break;
+ case '/=': value = originValue / value; break;
+ case '**=': value = Math.pow(originValue, value); break;
+ case '//=': value = Math.trunc(originValue / value); break;
+ case '%=': value = originValue % value; break;
+ case 'min=': value = Math.min(originValue, value); break;
+ case 'max=': value = Math.max(originValue, value); break;
+ default: break;
+ }
+ return value;
+}
+
+////// 数值操作 //////
+events.prototype.setValue = function (name, operator, value, prefix) {
+ value = this._updateValueByOperator(core.calValue(value, prefix), core.calValue(name, prefix), operator);
+ this._setValue_setStatus(name, value);
+ this._setValue_setBuff(name, value);
+ this._setValue_setItem(name, value);
+ this._setValue_setFlag(name, value);
+ this._setValue_setSwitch(name, value, prefix);
+ this._setValue_setTemp(name, value, prefix);
+ this._setValue_setGlobal(name, value);
+}
+
+events.prototype._setValue_setStatus = function (name, value) {
+ if (name.indexOf("status:") !== 0) return;
+ core.setStatus(name.substring(7), value);
+}
+
+events.prototype._setValue_setBuff = function (name, value) {
+ if (name.indexOf('buff:') !== 0) return;
+ core.setBuff(name.substring(5), value);
+}
+
+events.prototype._setValue_setItem = function (name, value) {
+ if (name.indexOf("item:") !== 0) return;
+ var itemId = name.substring(5), count = core.itemCount(itemId);
+ if (value > count) core.getItem(itemId, value - count);
+ else core.setItem(itemId, value);
+}
+
+events.prototype._setValue_setFlag = function (name, value) {
+ if (name.indexOf("flag:") !== 0) return;
+ core.setFlag(name.substring(5), value);
+}
+
+events.prototype._setValue_setSwitch = function (name, value, prefix) {
+ if (name.indexOf("switch:") !== 0) return;
+ core.setFlag((prefix || ":f@x@y") + "@" + name.substring(7), value);
+}
+
+events.prototype._setValue_setTemp = function (name, value) {
+ if (name.indexOf("temp:") !== 0) return;
+ core.setFlag("@temp@" + name.substring(5), value);
+}
+
+events.prototype._setValue_setGlobal = function (name, value) {
+ if (name.indexOf("global:") !== 0) return;
+ core.setGlobal(name.substring(7), value);
+}
+
+////// 设置一个怪物属性 //////
+events.prototype.setEnemy = function (id, name, value, operator, prefix, norefresh) {
+ if (!core.hasFlag('enemyInfo')) {
+ core.setFlag('enemyInfo', {});
+ }
+ var enemyInfo = core.getFlag('enemyInfo');
+ if (!enemyInfo[id]) enemyInfo[id] = {};
+ if (typeof value === 'string' && name == 'name') value = value.replace(/\r/g, '\\r');
+ value = this._updateValueByOperator(core.calValue(value, prefix), (core.material.enemys[id] || {})[name], operator);
+ enemyInfo[id][name] = value;
+ (core.material.enemys[id] || {})[name] = core.clone(value);
+ if (!norefresh) core.updateStatusBar();
+}
+
+////// 设置某个点上的怪物属性 //////
+events.prototype.setEnemyOnPoint = function (x, y, floorId, name, value, operator, prefix, norefresh) {
+ floorId = floorId || core.status.floorId;
+ var block = core.getBlock(x, y, floorId);
+ if (block == null) return;
+ if (block.event.cls.indexOf('enemy') != 0) return;
+ var enemy = core.material.enemys[block.event.id];
+ if (enemy == null) return;
+ if (typeof value === 'string' && name == 'name') value = value.replaceAll(/\r/g, '\\r');
+ value = this._updateValueByOperator(core.calValue(value, prefix), core.getEnemyValue(enemy, name, x, y, floorId), operator);
+ flags.enemyOnPoint = flags.enemyOnPoint || {};
+ flags.enemyOnPoint[floorId] = flags.enemyOnPoint[floorId] || {};
+ flags.enemyOnPoint[floorId][x + "," + y] = flags.enemyOnPoint[floorId][x + "," + y] || {};
+ flags.enemyOnPoint[floorId][x + "," + y][name] = value;
+ if (!norefresh) core.updateStatusBar();
+}
+
+////// 重置某个点上的怪物属性 //////
+events.prototype.resetEnemyOnPoint = function (x, y, floorId, norefresh) {
+ delete ((flags.enemyOnPoint || {})[floorId || core.status.floorId] || {})[x + "," + y];
+ if (!norefresh) core.updateStatusBar();
+}
+
+////// 将某个点上已经设置的怪物属性移动到其他点 //////
+events.prototype.moveEnemyOnPoint = function (fromX, fromY, toX, toY, floorId, norefresh) {
+ floorId = floorId || core.status.floorId;
+ if (((flags.enemyOnPoint || {})[floorId] || {})[fromX + "," + fromY]) {
+ flags.enemyOnPoint[floorId][toX + "," + toY] = flags.enemyOnPoint[floorId][fromX + "," + fromY];
+ delete flags.enemyOnPoint[floorId][fromX + "," + fromY];
+ if (!norefresh) core.updateStatusBar();
+ }
+}
+
+////// 设置楼层属性 //////
+events.prototype.setFloorInfo = function (name, value, floorId, prefix) {
+ floorId = floorId || core.status.floorId;
+ core.status.maps[floorId][name] = value;
+ core.updateStatusBar();
+}
+
+////// 设置全塔属性 //////
+events.prototype.setGlobalAttribute = function (name, value) {
+ if (typeof value == 'string') {
+ if ((value.charAt(0) == '"' && value.charAt(value.length - 1) == '"')
+ || (value.charAt(0) == "'" && value.charAt(value.length - 1) == "'"))
+ value = value.substring(1, value.length - 1);
+ // --- 检查 []
+ if (value.charAt(0) == '[' && value.charAt(value.length - 1) == ']')
+ value = eval(value);
+ // --- 检查颜色
+ if (/^[0-9 ]+,[0-9 ]+,[0-9 ]+(,[0-9. ]+)?$/.test(value)) {
+ value = 'rgba(' + value + ')';
+ }
+ }
+ core.status.globalAttribute[name] = value;
+ core.setFlag('globalAttribute', core.status.globalAttribute);
+ core.resize();
+}
+
+////// 设置全局开关 //////
+events.prototype.setGlobalFlag = function (name, value) {
+ var flags = core.getFlag("globalFlags", {});
+ if (name.startsWith('s:')) {
+ name = name.substring(2);
+ var statusBarItems = core.flags.statusBarItems.filter(function (v) { return v != name; });
+ if (value) statusBarItems.push(name);
+ core.flags.statusBarItems = statusBarItems;
+ flags.statusBarItems = core.clone(statusBarItems);
+ } else {
+ flags[name] = core.flags[name] = value;
+ }
+ core.setFlag("globalFlags", flags);
+ core.resize();
+ if (name == 'blurFg')
+ core.redrawMap();
+}
+
+////// 设置文件别名 //////
+events.prototype.setNameMap = function (name, value) {
+ if (!core.hasFlag('__nameMap__')) core.setFlag('__nameMap__', {});
+ flags.__nameMap__[name] = value;
+}
+
+////// 设置剧情文本的属性 //////
+events.prototype.setTextAttribute = function (data) {
+ if (!core.isPlaying()) return;
+ ["position", "offset", "align", "bold", "titlefont", "textfont", "lineHeight", "time", "letterSpacing", "animateTime"].forEach(function (t) {
+ if (data[t] != null) core.status.textAttribute[t] = data[t];
+ });
+ ["background", "title", "text"].forEach(function (t) {
+ if ((data[t] instanceof Array) && data[t].length >= 3) {
+ if (data[t].length == 3) data[t].push(1);
+ core.status.textAttribute[t] = data[t];
+ }
+ if (t == 'background') {
+ var name = core.getMappedName(data[t]);
+ var img = core.material.images.images[name];
+ if (img && img.width == 192 && img.height == 128) {
+ core.status.textAttribute[t] = name;
+ }
+ }
+ });
+ if (main.mode == 'play') core.setFlag('textAttribute', core.status.textAttribute);
+}
+
+events.prototype.moveTextBox = function (code, loc, relative, moveMode, time, callback) {
+ var ctx = core.getContextByName('__text__' + code);
+ if (!ctx) {
+ if (callback) callback();
+ return;
+ }
+ var sx = parseInt(ctx.canvas.getAttribute('_text_left')) || 0;
+ var sy = parseInt(ctx.canvas.getAttribute('_text_top')) || 0;
+ var dx = relative ? loc[0] : (loc[0] - sx);
+ var dy = relative ? loc[1] : (loc[1] - sy);
+ var ox = parseInt(ctx.canvas.getAttribute('_left')) || 0;
+ var oy = parseInt(ctx.canvas.getAttribute('_top')) || 0;
+
+ if (!time) {
+ core.relocateCanvas(ctx, ox + dx, oy + dy);
+ ctx.canvas.setAttribute('_text_left', loc[0]);
+ ctx.canvas.setAttribute('_text_top', loc[1]);
+ if (callback) callback();
+ return;
+ }
+
+ var moveInfo = {
+ sx: sx, sy: sy, dx: dx, dy: dy, ox: ox, oy: oy,
+ moveMode: moveMode, time: time / Math.max(core.status.replay.speed, 1)
+ };
+ this._moveTextBox_moving(ctx, moveInfo, callback);
+}
+
+events.prototype._moveTextBox_moving = function (ctx, moveInfo, callback) {
+ var step = 0, steps = moveInfo.time / 10;
+ if (steps <= 0) steps = 1;
+ var moveFunc = core.applyEasing(moveInfo.moveMode);
+ var animate = setInterval(function () {
+ step++;
+ var dx = moveInfo.dx * moveFunc(step / steps);
+ var dy = moveInfo.dy * moveFunc(step / steps);
+ core.relocateCanvas(ctx, parseInt(moveInfo.ox + dx), parseInt(moveInfo.oy + dy));
+ ctx.canvas.setAttribute('_text_left', moveInfo.sx + dx);
+ ctx.canvas.setAttribute('_text_top', moveInfo.sy + dy);
+ if (step == steps) {
+ delete core.animateFrame.asyncId[animate];
+ clearInterval(animate);
+ if (callback) callback();
+ }
+ }, 10);
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = callback;
+}
+
+////// 清除对话框 //////
+events.prototype.clearTextBox = function (code, callback) {
+ if (code == null) {
+ code = Object.keys(core.dymCanvas).filter(function (one) { return one.startsWith('__text__') })
+ .map(function (one) { return one.substring('__text__'.length); })
+ }
+
+ if (!(code instanceof Array)) code = [code];
+ var index = 0;
+ var _work = function () {
+ if (index == code.length) {
+ if (callback) callback();
+ return;
+ }
+ var ctx = '__text__' + code[index++];
+ if (!core.getContextByName(ctx)) return _work();
+ core.ui._animateUI('hide', ctx, function () {
+ core.deleteCanvas(ctx);
+ _work();
+ });
+ };
+ _work();
+}
+
+////// 关门 //////
+events.prototype.closeDoor = function (x, y, id, callback) {
+ id = id || "";
+ if ((core.material.icons.animates[id] == null && core.material.icons.npc48[id] == null)
+ || core.getBlock(x, y) != null) {
+ if (callback) callback();
+ return;
+ }
+ var block = core.getBlockById(id);
+ var doorInfo = (block.event || {}).doorInfo;
+ if (!doorInfo) {
+ if (callback) callback();
+ return;
+ }
+
+ core.playSound(doorInfo.closeSound);
+ var blockInfo = core.getBlockInfo(block);
+ var speed = (doorInfo.time || 160) / 4;
+ blockInfo.posX = 3;
+ core.maps._drawBlockInfo(blockInfo, x, y);
+
+ var cb = function () {
+ core.setBlock(id, x, y);
+ core.showBlock(x, y);
+ if (callback) callback();
+ }
+
+ var animate = window.setInterval(function () {
+ blockInfo.posX--;
+ if (blockInfo.posX < 0) {
+ clearInterval(animate);
+ delete core.animateFrame.asyncId[animate];
+ cb();
+ return;
+ }
+ core.maps._drawBlockInfo(blockInfo, x, y);
+ }, core.status.replay.speed == 24 ? 1 : speed / Math.max(core.status.replay.speed, 1));
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = cb;
+}
+
+////// 显示图片 //////
+events.prototype.showImage = function (code, image, sloc, loc, opacityVal, time, callback) {
+ var imageName = null;
+ if (typeof image == 'string') {
+ imageName = image;
+ if (image.endsWith(':x') || image.endsWith(':y') || image.endsWith(':o')) {
+ image = image.substring(0, image.length - 2);
+ }
+ image = core.getMappedName(image);
+ image = core.material.images.images[image];
+ }
+ if (!image) {
+ if (callback) callback();
+ return;
+ }
+ sloc = sloc || [];
+ var sx = core.calValue(sloc[0]) || 0, sy = core.calValue(sloc[1]) || 0;
+ var sw = core.calValue(sloc[2]), sh = core.calValue(sloc[3]);
+ if (sw == null) sw = image.width;
+ if (sh == null) sh = image.height;
+ loc = loc || [];
+ var x = core.calValue(loc[0]) || 0, y = core.calValue(loc[1]) || 0;
+ var w = core.calValue(loc[2]), h = core.calValue(loc[3]);
+ if (w == null) w = sw;
+ if (h == null) h = sh;
+ var zIndex = code + 100;
+ time = time || 0;
+ var name = "image" + zIndex;
+ var ctx = core.createCanvas(name, x, y, w, h, zIndex);
+ core.drawImage(ctx, imageName == null ? image : imageName, sx, sy, sw, sh, 0, 0, w, h);
+ if (time == 0) {
+ core.setOpacity(name, opacityVal);
+ if (callback) callback();
+ return;
+ }
+ core.setOpacity(name, 0);
+ this.moveImage(code, null, opacityVal, null, time, callback);
+}
+
+////// 隐藏图片 //////
+events.prototype.hideImage = function (code, time, callback) {
+ time = time || 0;
+ var name = "image" + (code + 100);
+ if (time == 0 || !core.dymCanvas[name]) {
+ core.deleteCanvas(name);
+ if (callback) callback();
+ return;
+ }
+ this.moveImage(code, null, 0, null, time, function () {
+ core.deleteCanvas(name);
+ if (callback) callback();
+ });
+}
+
+////// 移动图片 //////
+events.prototype.moveImage = function (code, to, opacityVal, moveMode, time, callback) {
+ to = to || [];
+ var name = "image" + (code + 100);
+ if (!core.dymCanvas[name]) {
+ if (callback) callback();
+ return;
+ }
+ var getOrDefault = function (a, b) {
+ a = core.calValue(a);
+ return a != null ? a : b;
+ }
+ var canvas = core.dymCanvas[name].canvas;
+ var fromX = parseFloat(canvas.getAttribute("_left")),
+ fromY = parseFloat(canvas.getAttribute("_top")),
+ toX = getOrDefault(to[0], fromX), toY = getOrDefault(to[1], fromY);
+
+ var opacity = parseFloat(canvas.style.opacity), toOpacity = getOrDefault(opacityVal, opacity);
+
+ if (!time) {
+ core.relocateCanvas(name, toX, toY);
+ core.setOpacity(toOpacity);
+ if (callback) callback();
+ return;
+ }
+
+ this._moveImage_moving(name, {
+ fromX: fromX, fromY: fromY, toX: toX, toY: toY, opacity: opacity, toOpacity: toOpacity,
+ moveMode: moveMode, time: time / Math.max(core.status.replay.speed, 1)
+ }, callback)
+}
+
+events.prototype._moveImage_moving = function (name, moveInfo, callback) {
+ var per_time = 10, step = 0, steps = parseInt(moveInfo.time / per_time);
+ if (steps <= 0) steps = 1;
+ var fromX = moveInfo.fromX, fromY = moveInfo.fromY, toX = moveInfo.toX, toY = moveInfo.toY,
+ opacity = moveInfo.opacity, toOpacity = moveInfo.toOpacity;
+ var currX = fromX, currY = fromY, currOpacity = opacity;
+ var moveFunc = core.applyEasing(moveInfo.moveMode);
+ var animate = setInterval(function () {
+ step++;
+ currOpacity = opacity + (toOpacity - opacity) * moveFunc(step / steps);
+ currX = parseInt(fromX + (toX - fromX) * moveFunc(step / steps));
+ currY = parseInt(fromY + (toY - fromY) * moveFunc(step / steps));
+ core.setOpacity(name, currOpacity);
+ core.relocateCanvas(name, currX, currY);
+ if (step == steps) {
+ delete core.animateFrame.asyncId[animate];
+ clearInterval(animate);
+ if (callback) callback();
+ }
+ }, per_time);
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = callback;
+}
+
+////// 旋转图片 //////
+events.prototype.rotateImage = function (code, center, angle, moveMode, time, callback) {
+ center = center || [];
+ var name = "image" + (code + 100);
+ if (!core.dymCanvas[name]) {
+ if (callback) callback();
+ return;
+ }
+ var canvas = core.dymCanvas[name].canvas;
+ var centerX = core.calValue(center[0]), centerY = core.calValue(center[1]);
+
+ var fromAngle = parseFloat(canvas.getAttribute('_angle')) || 0;
+
+ if (!time) {
+ core.rotateCanvas(name, fromAngle + angle, centerX, centerY);
+ if (callback) callback();
+ return;
+ }
+
+ var rotateInfo = {
+ fromAngle: fromAngle, angle: angle, centerX: centerX, centerY: centerY,
+ moveMode: moveMode, time: time / Math.max(core.status.replay.speed, 1)
+ }
+ this._rotateImage_rotating(name, rotateInfo, callback);
+}
+
+events.prototype._rotateImage_rotating = function (name, rotateInfo, callback) {
+ var per_time = 10, step = 0, steps = parseInt(rotateInfo.time / per_time);
+ if (steps <= 0) steps = 1;
+ var moveFunc = core.applyEasing(rotateInfo.moveMode);
+ var animate = setInterval(function () {
+ step++;
+ var currAngle = rotateInfo.fromAngle + rotateInfo.angle * moveFunc(step / steps);
+ core.rotateCanvas(name, currAngle, rotateInfo.centerX, rotateInfo.centerY);
+ if (step == steps) {
+ delete core.animateFrame.asyncId[animate];
+ clearInterval(animate);
+ if (callback) callback();
+ }
+ }, per_time);
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = callback;
+}
+
+////// 放缩一张图片 //////
+events.prototype.scaleImage = function (code, center, scale, moveMode, time, callback) {
+ center = center || [];
+ var name = "image" + (code + 100);
+ if (!core.dymCanvas[name]) {
+ if (callback) callback();
+ return;
+ }
+ var ctx = core.dymCanvas[name];
+ var currScale = 1.0;
+ if (ctx.canvas.hasAttribute('_scale')) {
+ currScale = parseFloat(ctx.canvas.getAttribute('_scale'));
+ }
+ var ratio = ctx.canvas.hasAttribute('isHD') ? core.domStyle.ratio : 1;
+ var width = ctx.canvas.width / ratio, height = ctx.canvas.height / ratio;
+ var currLeft = parseFloat(ctx.canvas.getAttribute("_left"));
+ var currTop = parseFloat(ctx.canvas.getAttribute("_top"));
+ var centerX = core.calValue(center[0]), centerY = core.calValue(center[1]);
+ if (centerX == null || centerY == null) {
+ centerX = currLeft + width * currScale / 2;
+ centerY = currTop + height * currScale / 2;
+ }
+ var scaleInfo = {
+ x: (currLeft - centerX) / currScale, y: (currTop - centerY) / currScale, centerX: centerX, centerY: centerY,
+ width: width, height: height, currScale: currScale, scale: scale, moveMode: moveMode, time: time
+ }
+ this._scaleImage_scale(ctx, scaleInfo, callback);
+}
+
+events.prototype._scaleInfo_scale = function (ctx, scaleInfo, scale) {
+ core.resizeCanvas(ctx, scaleInfo.width * scale, scaleInfo.height * scale, true);
+ core.relocateCanvas(ctx, scaleInfo.centerX + scaleInfo.x * scale, scaleInfo.centerY + scaleInfo.y * scale);
+ ctx.canvas.setAttribute('_scale', scale);
+}
+
+events.prototype._scaleImage_scale = function (ctx, scaleInfo, callback) {
+ if (!scaleInfo.time) {
+ this._scaleInfo_scale(ctx, scaleInfo, scaleInfo.scale);
+ if (callback) callback();
+ return;
+ }
+
+ var per_time = 10, step = 0, steps = parseInt(scaleInfo.time / per_time);
+ if (steps <= 0) steps = 1;
+ var moveFunc = core.applyEasing(scaleInfo.moveMode);
+
+ var animate = setInterval(function () {
+ step++;
+ var scale = scaleInfo.currScale + (scaleInfo.scale - scaleInfo.currScale) * moveFunc(step / steps);
+ core.events._scaleInfo_scale(ctx, scaleInfo, scale);
+ if (step == steps) {
+ delete core.animateFrame.asyncId[animate];
+ clearInterval(animate);
+ if (callback) callback();
+ }
+ }, per_time);
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = callback;
+}
+
+////// 绘制或取消一张gif图片 //////
+events.prototype.showGif = function (name, x, y) {
+ name = core.getMappedName(name);
+ var image = core.material.images.images[name];
+ if (image) {
+ var gif = new Image();
+ gif.src = image.src;
+ gif.style.position = 'absolute';
+ gif.style.left = x * core.domStyle.scale + "px";
+ gif.style.top = y * core.domStyle.scale + "px";
+ gif.style.width = image.width * core.domStyle.scale + "px";
+ gif.style.height = image.height * core.domStyle.scale + "px";
+ core.dom.gif2.appendChild(gif);
+ }
+ else {
+ core.dom.gif2.innerHTML = "";
+ }
+}
+
+////// 淡入淡出音乐 //////
+events.prototype.setVolume = function (value, time, callback) {
+ var set = function (value) {
+ core.musicStatus.designVolume = value;
+ if (core.musicStatus.playingBgm)
+ core.material.bgms[core.musicStatus.playingBgm].volume = core.musicStatus.userVolume * core.musicStatus.designVolume;
+ }
+ if (!time || time < 100) {
+ set(value);
+ if (callback) callback();
+ return;
+ }
+ var currVolume = core.musicStatus.designVolume;
+ time /= Math.max(core.status.replay.speed, 1);
+ var per_time = 10, step = 0, steps = parseInt(time / per_time);
+ if (steps <= 0) steps = 1;
+ var animate = setInterval(function () {
+ step++;
+ set(currVolume + (value - currVolume) * step / steps);
+ if (step >= steps) {
+ delete core.animateFrame.asyncId[animate];
+ clearInterval(animate);
+ if (callback) callback();
+ }
+ }, per_time);
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = callback;
+}
+
+////// 画面震动 //////
+events.prototype.vibrate = function (direction, time, speed, power, callback) {
+ if (core.isReplaying()) {
+ if (callback) callback();
+ return;
+ }
+ if (!time) time = 1000;
+ speed = speed || 10;
+ power = power || 10;
+ var shakeInfo = { duration: parseInt(time / 10), speed: speed, power: power, direction: 1, shake: 0 };
+ if (direction == 'random') {
+ direction = ['horizontal', 'vertical', 'diagonal1', 'diagonal2'][Math.floor(Math.random() * 4)];
+ }
+ var cb = function () {
+ core.addGameCanvasTranslate(0, 0);
+ if (callback) callback();
+ }
+ var animate = setInterval(function () {
+ core.events._vibrate_update(shakeInfo);
+ switch (direction) {
+ case 'vertical': core.addGameCanvasTranslate(0, shakeInfo.shake); break;
+ case 'diagonal1': core.addGameCanvasTranslate(shakeInfo.shake, shakeInfo.shake); break;
+ case 'diagonal2': core.addGameCanvasTranslate(-shakeInfo.shake, shakeInfo.shake); break;
+ default: core.addGameCanvasTranslate(shakeInfo.shake, 0);
+ }
+ if (shakeInfo.duration === 0 && shakeInfo.shake == 0) {
+ delete core.animateFrame.asyncId[animate];
+ clearInterval(animate);
+ cb();
+ }
+ }, 10);
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = cb;
+}
+
+events.prototype._vibrate_update = function (shakeInfo) {
+ if (shakeInfo.duration >= 1 || shakeInfo.shake != 0) {
+ var delta = shakeInfo.speed * shakeInfo.direction / 6;
+ if (shakeInfo.duration <= 1 && shakeInfo.shake * (shakeInfo.shake + delta) < 0) {
+ shakeInfo.shake = 0;
+ } else {
+ shakeInfo.shake += delta;
+ }
+ if (shakeInfo.shake > shakeInfo.power) {
+ shakeInfo.direction = -1;
+ }
+ if (shakeInfo.shake < -shakeInfo.power) {
+ shakeInfo.direction = 1;
+ }
+ if (shakeInfo.duration >= 1) {
+ shakeInfo.duration -= 1
+ }
+ }
+}
+
+/////// 使用事件让勇士移动。这个函数将不会触发任何事件 //////
+events.prototype.eventMoveHero = function (steps, time, callback) {
+ time = time || core.values.moveSpeed;
+ var step = 0, moveSteps = (steps || []).map(function (t) {
+ return [t.split(':')[0], parseInt(t.split(':')[1] || "1")];
+ }).filter(function (t) {
+ return ['up', 'down', 'left', 'right', 'forward', 'backward', 'leftup', 'leftdown', 'rightup', 'rightdown', 'speed'].indexOf(t[0]) >= 0
+ && !(t[0] == 'speed' && t[1] < 16);
+ });
+ core.status.heroMoving = -1;
+ var _run = function () {
+ var cb = function () {
+ core.status.heroMoving = 0;
+ core.drawHero();
+ if (callback) callback();
+ }
+
+ var animate = window.setInterval(function () {
+ if (moveSteps.length == 0) {
+ delete core.animateFrame.asyncId[animate];
+ clearInterval(animate);
+ cb();
+ }
+ else {
+ if (step == 0 && moveSteps[0][0] == 'speed' && moveSteps[0][1] >= 16) {
+ time = moveSteps[0][1];
+ moveSteps.shift();
+ clearInterval(animate);
+ delete core.animateFrame.asyncId[animate];
+ _run();
+ }
+ else if (core.events._eventMoveHero_moving(++step, moveSteps))
+ step = 0;
+ }
+ }, core.status.replay.speed == 24 ? 1 : time / 8 / core.status.replay.speed);
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = cb;
+ }
+ _run();
+}
+
+events.prototype._eventMoveHero_moving = function (step, moveSteps) {
+ var curr = moveSteps[0];
+ var direction = curr[0], x = core.getHeroLoc('x'), y = core.getHeroLoc('y');
+ // ------ 前进/后退
+ var o = direction == 'backward' ? -1 : 1;
+ if (direction == 'forward' || direction == 'backward') direction = core.getHeroLoc('direction');
+ var faceDirection = direction;
+ if (direction == 'leftup' || direction == 'leftdown') faceDirection = 'left';
+ if (direction == 'rightup' || direction == 'rightdown') faceDirection = 'right';
+ core.setHeroLoc('direction', direction);
+ if (curr[1] <= 0) {
+ core.setHeroLoc('direction', faceDirection);
+ moveSteps.shift();
+ return true;
+ }
+ if (step <= 4) {
+ core.drawHero('leftFoot', 4 * o * step);
+ }
+ else if (step <= 8) {
+ core.drawHero('rightFoot', 4 * o * step);
+ }
+ if (step == 8) {
+ core.setHeroLoc('x', x + o * core.utils.scan2[direction].x, true);
+ core.setHeroLoc('y', y + o * core.utils.scan2[direction].y, true);
+ core.updateFollowers();
+ curr[1]--;
+ if (curr[1] <= 0) moveSteps.shift();
+ core.setHeroLoc('direction', faceDirection);
+ return true;
+ }
+ return false;
+}
+
+////// 勇士跳跃事件 //////
+events.prototype.jumpHero = function (ex, ey, time, callback) {
+ var sx = core.getHeroLoc('x'), sy = core.getHeroLoc('y');
+ if (ex == null) ex = sx;
+ if (ey == null) ey = sy;
+ var sx = core.status.hero.loc.x, sy = core.status.hero.loc.y;
+ if (!core.isset(ex)) ex = sx;
+ if (!core.isset(ey)) ey = sy;
+ var jumpInfo = core.maps.__generateJumpInfo(sx, sy, ex, ey, time || 500);
+ jumpInfo.icon = core.material.icons.hero[core.getHeroLoc('direction')];
+ jumpInfo.width = core.material.icons.hero.width || 32;
+ jumpInfo.height = core.material.icons.hero.height;
+
+ this._jumpHero_doJump(jumpInfo, callback);
+}
+
+events.prototype._jumpHero_doJump = function (jumpInfo, callback) {
+ var cb = function () {
+ core.setHeroLoc('x', jumpInfo.ex);
+ core.setHeroLoc('y', jumpInfo.ey);
+ core.status.heroMoving = 0;
+ core.drawHero();
+ if (callback) callback();
+ }
+
+ core.status.heroMoving = -1;
+ var animate = window.setInterval(function () {
+ if (jumpInfo.jump_count > 0)
+ core.events._jumpHero_jumping(jumpInfo)
+ else {
+ delete core.animateFrame.asyncId[animate];
+ clearInterval(animate);
+ cb();
+ }
+ }, jumpInfo.per_time);
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = cb;
+}
+
+events.prototype._jumpHero_jumping = function (jumpInfo) {
+ core.clearMap('hero');
+ core.maps.__updateJumpInfo(jumpInfo);
+ var x = core.getHeroLoc('x'),
+ y = core.getHeroLoc('y');
+ var nowx = jumpInfo.px, nowy = jumpInfo.py, width = jumpInfo.width || 32, height = jumpInfo.height;
+ core.drawHero('stop', { x: nowx - 32 * x, y: nowy - 32 * y });
+}
+
+////// 设置角色行走图 //////
+events.prototype.setHeroIcon = function (name, noDraw) {
+ name = core.getMappedName(name);
+ var img = core.material.images.images[name];
+ if (!img) {
+ console.error("找不到图片: " + img);
+ return;
+ }
+ if (core.material.images.hero == img) return;
+ core.status.hero.image = name;
+ core.material.images.hero = img;
+ core.material.icons.hero.width = img.width / 4;
+ core.material.icons.hero.height = img.height / 4;
+ core.control.updateHeroIcon(name);
+ if (!noDraw) core.drawHero();
+}
+
+////// 检查升级事件 //////
+events.prototype.checkLvUp = function () {
+ var actions = [];
+ while (true) {
+ var next = this._checkLvUp_check();
+ if (next == null) break;
+ actions = actions.concat(next);
+ }
+ if (actions.length > 0) core.insertAction(actions);
+}
+
+events.prototype._checkLvUp_check = function () {
+ if (core.flags.statusBarItems.indexOf('enableLevelUp') < 0 || !core.firstData.levelUp
+ || core.status.hero.lv >= core.firstData.levelUp.length) return null;
+ // 计算下一个所需要的数值
+ var next = (core.firstData.levelUp[core.status.hero.lv] || {});
+ var need = core.calValue(next.need);
+ if (need == null) return null;
+ if (core.status.hero.exp >= need) {
+ // 升级
+ core.status.hero.lv++;
+ if (next.clear) core.status.hero.exp -= need;
+ return next.action || [];
+ }
+ return null;
+}
+
+////// 尝试使用道具 //////
+events.prototype.tryUseItem = function (itemId) {
+ if (itemId == 'book') {
+ core.ui.closePanel();
+ return core.openBook(false);
+ }
+ if (itemId == 'fly') {
+ core.ui.closePanel();
+ return core.useFly(false);
+ }
+ if (itemId == 'centerFly') {
+ core.ui.closePanel();
+ return core.ui._drawCenterFly();
+ }
+ if (core.canUseItem(itemId)) {
+ core.ui.closePanel();
+ core.useItem(itemId);
+ } else {
+ core.playSound('操作失败');
+ core.drawTip("当前无法使用" + core.material.items[itemId].name, itemId);
+ }
+}
diff --git a/libs/extensions.js b/libs/extensions.js
new file mode 100644
index 0000000..873e70d
--- /dev/null
+++ b/libs/extensions.js
@@ -0,0 +1,51 @@
+
+/*
+extensions.js:负责拓展插件
+ */
+
+"use strict";
+
+function extensions () {
+
+}
+
+extensions.prototype._load = function (callback) {
+ if (main.replayChecking) return callback();
+ if (!window.fs) {
+ this._loadJs('_server/fs.js', function () {
+ core.extensions._listExtensions(callback);
+ }, callback);
+ } else this._listExtensions(callback);
+}
+
+extensions.prototype._loadJs = function (file, callback, onerror) {
+ var script = document.createElement('script');
+ script.src = file + '?v=' + main.version;
+ script.onload = callback;
+ script.onerror = onerror;
+ main.dom.body.appendChild(script);
+}
+
+extensions.prototype._listExtensions = function (callback) {
+ if (!window.fs) return callback();
+ fs.readdir('extensions', function (error, data) {
+ if (error || !(data instanceof Array)) return callback();
+ var list = [];
+ data.forEach(function (name) {
+ if (/^[\w.-]+\.js$/.test(name)) {
+ list.push(name);
+ }
+ });
+ list.sort();
+ core.extensions._loadExtensions(list, callback);
+ });
+}
+
+extensions.prototype._loadExtensions = function (list, callback) {
+ var i = 0;
+ var load = function () {
+ if (i == list.length) return callback();
+ core.extensions._loadJs('extensions/' + list[i++], load, load);
+ }
+ load();
+}
diff --git a/libs/icons.js b/libs/icons.js
new file mode 100644
index 0000000..7efd6ef
--- /dev/null
+++ b/libs/icons.js
@@ -0,0 +1,77 @@
+
+"use strict";
+
+function icons () {
+ this._init();
+}
+
+icons.prototype._init = function () {
+ this.icons = icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1;
+ //delete(icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1);
+
+ // tileset的起点
+ this.tilesetStartOffset = 10000;
+}
+
+icons.prototype.getIcons = function () {
+ var icons = core.clone(this.icons);
+ icons.hero.leftup = icons.hero.leftdown = icons.hero.left;
+ icons.hero.rightup = icons.hero.rightdown = icons.hero.right;
+ return icons;
+}
+
+////// 根据道具ID获得其cls //////
+icons.prototype.getClsFromId = function (id) {
+ for (var cls in core.material.icons) {
+ if (cls != 'hero' && id in core.material.icons[cls])
+ return cls;
+ }
+ return null;
+}
+
+icons.prototype.getAllIconIds = function () {
+ if (this.allIconIds) return this.allIconIds;
+ this.allIconIds = [];
+ for (var type in this.icons) {
+ this.allIconIds = this.allIconIds.concat(Object.keys(this.icons[type]));
+ }
+ return this.allIconIds;
+}
+
+icons.prototype._getAnimateFrames = function (cls) {
+ if (cls == 'enemys' || cls == 'npcs') {
+ return 2;
+ }
+ if (cls == 'animates' || cls == 'enemy48' || cls == 'npc48') {
+ return 4;
+ }
+ return 1;
+}
+
+////// 根据图块数字或ID获得所在的tileset和坐标信息 //////
+icons.prototype.getTilesetOffset = function (id) {
+
+ if (typeof id == 'string') {
+ id = core.getIdOfThis(id);
+ // Tileset的ID必须是 X+数字 的形式
+ if (!/^X\d+$/.test(id)) return null;
+ id = parseInt(id.substring(1));
+ }
+ else if (typeof id != 'number') {
+ return null;
+ }
+
+ core.tilesets = core.tilesets || [];
+ var startOffset = this.tilesetStartOffset;
+ for (var i in core.tilesets) {
+ var imgName = core.tilesets[i];
+ var img = core.material.images.tilesets[imgName];
+ var width = Math.floor(parseInt(img.getAttribute('_width')) / 32), height = Math.floor(parseInt(img.getAttribute('_height')) / 32);
+ if (id >= startOffset && id < startOffset + width * height) {
+ var x = (id - startOffset) % width, y = parseInt((id - startOffset) / width);
+ return { "image": imgName, "x": x, "y": y };
+ }
+ startOffset += this.tilesetStartOffset;
+ }
+ return null;
+}
diff --git a/libs/items.js b/libs/items.js
new file mode 100644
index 0000000..593631a
--- /dev/null
+++ b/libs/items.js
@@ -0,0 +1,434 @@
+
+"use strict";
+
+function items () {
+ this._init();
+}
+
+////// 初始化 //////
+items.prototype._init = function () {
+ this.items = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a;
+ for (var itemId in this.items) {
+ this.items[itemId].id = itemId;
+ }
+}
+
+////// 获得所有道具 //////
+items.prototype.getItems = function () {
+ var items = core.clone(this.items);
+ var equipInfo = core.getFlag('equipInfo');
+ if (equipInfo) {
+ for (var id in equipInfo) {
+ items[id].equip = core.clone(equipInfo[id]);
+ }
+ }
+ return items;
+}
+
+////// “即捡即用类”道具的使用效果 //////
+items.prototype.getItemEffect = function (itemId, itemNum) {
+ var itemCls = core.material.items[itemId].cls;
+ // 消耗品
+ if (itemCls === 'items') {
+ var curr_hp = core.status.hero.hp;
+ var itemEffect = core.material.items[itemId].itemEffect;
+ if (itemEffect) {
+ try {
+ for (var i = 0; i < itemNum; ++i)
+ eval(itemEffect);
+ }
+ catch (e) {
+ console.error(e);
+ }
+ }
+ core.status.hero.statistics.hp += core.status.hero.hp - curr_hp;
+
+ var useItemEvent = core.material.items[itemId].useItemEvent;
+ if (useItemEvent) {
+ try {
+ core.insertAction(useItemEvent);
+ }
+ catch (e) {
+ console.error(e);
+ }
+ }
+ core.updateStatusBar(false, true);
+ }
+ else {
+ core.addItem(itemId, itemNum);
+ }
+}
+
+////// “即捡即用类”道具的文字提示 //////
+items.prototype.getItemEffectTip = function (itemId) {
+ var itemCls = core.material.items[itemId].cls;
+ // 消耗品
+ if (itemCls === 'items') {
+ var itemEffectTip = core.material.items[itemId].itemEffectTip;
+ if (itemEffectTip) {
+ try {
+ return core.replaceText(itemEffectTip) || "";
+ } catch (e) {
+ console.error(e);
+ return "";
+ }
+ }
+ }
+ return "";
+}
+
+////// 使用道具 //////
+items.prototype.useItem = function (itemId, noRoute, callback) {
+ if (!this.canUseItem(itemId)) {
+ if (callback) callback();
+ return;
+ }
+ // 执行道具效果
+ this._useItemEffect(itemId);
+ // 执行完毕
+ this._afterUseItem(itemId);
+ // 记录路线
+ if (!noRoute) core.status.route.push("item:" + itemId);
+ if (callback) callback();
+}
+
+items.prototype._useItemEffect = function (itemId) {
+ var useItemEffect = core.material.items[itemId].useItemEffect;
+ if (useItemEffect) {
+ try {
+ eval(useItemEffect);
+ }
+ catch (e) {
+ console.error(e);
+ }
+ }
+ var useItemEvent = core.material.items[itemId].useItemEvent;
+ if (useItemEvent) {
+ try {
+ core.insertAction(useItemEvent);
+ }
+ catch (e) {
+ console.error(e);
+ }
+ }
+}
+
+items.prototype._afterUseItem = function (itemId) {
+ // 道具使用完毕:删除
+ var itemCls = core.material.items[itemId].cls;
+ if (itemCls == 'tools')
+ core.status.hero.items[itemCls][itemId]--;
+ if (core.status.hero.items[itemCls][itemId] <= 0)
+ delete core.status.hero.items[itemCls][itemId];
+ core.updateStatusBar(false, true);
+}
+
+////// 当前能否使用道具 //////
+items.prototype.canUseItem = function (itemId) {
+ // 没有道具
+ if (!core.hasItem(itemId)) return false;
+
+ var canUseItemEffect = core.material.items[itemId].canUseItemEffect;
+ if (canUseItemEffect) {
+ try {
+ return eval(canUseItemEffect);
+ }
+ catch (e) {
+ console.error(e);
+ return false;
+ }
+ }
+}
+
+////// 获得某个物品的个数 //////
+items.prototype.itemCount = function (itemId) {
+ if (!core.material.items[itemId] || !core.isPlaying()) return 0;
+ var itemCls = core.material.items[itemId].cls;
+ if (itemCls == "items") return 0;
+ return core.status.hero.items[itemCls][itemId] || 0;
+}
+
+////// 是否存在某个物品 //////
+items.prototype.hasItem = function (itemId) {
+ return this.itemCount(itemId) > 0;
+}
+
+////// 是否装备某件装备 //////
+items.prototype.hasEquip = function (itemId) {
+ if (!(core.material.items[itemId] || {}).equip || !core.isPlaying()) return null;
+
+ for (var i in core.status.hero.equipment)
+ if (core.status.hero.equipment[i] == itemId)
+ return true;
+ return false
+}
+
+////// 获得某个装备类型的当前装备 //////
+items.prototype.getEquip = function (equipType) {
+ return core.status.hero.equipment[equipType] || null;
+}
+
+////// 设置某个物品的个数 //////
+items.prototype.setItem = function (itemId, itemNum) {
+ itemNum = itemNum || 0;
+ var itemCls = core.material.items[itemId].cls;
+ if (itemCls == 'items') return;
+
+ core.status.hero.items[itemCls][itemId] = itemNum;
+ if (core.status.hero.items[itemCls][itemId] <= 0) {
+ delete core.status.hero.items[itemCls][itemId];
+ }
+ core.updateStatusBar();
+}
+
+////// 增加某个物品的个数 //////
+items.prototype.addItem = function (itemId, itemNum) {
+ if (itemNum == null) itemNum = 1;
+ var itemData = core.material.items[itemId];
+ var itemCls = itemData.cls;
+ if (itemCls == 'items') return;
+ if (core.status.hero.items[itemCls][itemId] == null) {
+ core.status.hero.items[itemCls][itemId] = 0;
+ }
+ core.status.hero.items[itemCls][itemId] += itemNum;
+ if (core.status.hero.items[itemCls][itemId] <= 0) {
+ delete core.status.hero.items[itemCls][itemId];
+ }
+ // 永久道具只能有一个
+ if (itemCls == 'constants' && core.status.hero.items[itemCls][itemId] > 1)
+ core.status.hero.items[itemCls][itemId] = 1;
+ core.updateStatusBar();
+}
+
+////// 删除某个物品 //////
+items.prototype.removeItem = function (itemId, itemNum) {
+ if (itemNum == null) itemNum = 1;
+ if (!core.hasItem(itemId)) return false;
+ var itemCls = core.material.items[itemId].cls;
+ core.status.hero.items[itemCls][itemId] -= itemNum;
+ if (core.status.hero.items[itemCls][itemId] <= 0) {
+ delete core.status.hero.items[itemCls][itemId];
+ }
+ core.updateStatusBar();
+ return true;
+}
+
+// ---------- 装备相关 ------------ //
+
+items.prototype.getEquipTypeByName = function (name) {
+ var names = core.status.globalAttribute.equipName;
+ var types = [];
+ for (var i = 0; i < names.length; ++i) {
+ if (names[i] === name) {
+ types.push(i);
+ if (!core.status.hero.equipment[i]) return i;
+ }
+ }
+ return types.length == 1 ? types[0] : -1;
+}
+
+items.prototype.getEquipTypeById = function (equipId) {
+ var type = core.material.items[equipId].equip.type;
+ if (typeof type == 'string')
+ type = this.getEquipTypeByName(type);
+ return type;
+}
+
+// 当前能否撞上某装备
+items.prototype.canEquip = function (equipId, hint) {
+ // 装备是否合法
+ var equip = core.material.items[equipId] || {};
+ if (!equip.equip) {
+ if (hint) {
+ core.playSound('操作失败');
+ core.drawTip("不合法的装备!");
+ }
+ return false;
+ }
+
+ // 是否拥有该装备
+ if (!core.hasItem(equipId) && !core.hasEquip(equipId)) {
+ if (hint) {
+ core.playSound('操作失败');
+ core.drawTip("你当前没有" + equip.name + ",无法换装");
+ }
+ return false;
+ }
+
+ // 可装备条件
+ var canUseItemEffect = core.material.items[equipId].canUseItemEffect;
+ if (canUseItemEffect) {
+ try {
+ if (!eval(canUseItemEffect)) {
+ if (hint) {
+ core.playSound('操作失败');
+ core.drawTip("当前不可换上" + equip.name);
+ }
+ return false;
+ }
+ }
+ catch (e) {
+ console.error(e);
+ return false;
+ }
+ }
+ return true;
+}
+
+////// 换上 //////
+items.prototype.loadEquip = function (equipId, callback) {
+ if (!this.canEquip(equipId, true)) {
+ if (callback) callback();
+ return;
+ }
+
+ var loadEquip = core.material.items[equipId] || {};
+ var type = this.getEquipTypeById(equipId);
+ if (type < 0) {
+ core.playSound('操作失败');
+ core.drawTip("当前没有" + loadEquip.equip.type + "的空位!");
+ if (callback) callback();
+ return;
+ }
+
+ this._realLoadEquip(type, equipId, core.status.hero.equipment[type], callback);
+}
+
+////// 卸下 //////
+items.prototype.unloadEquip = function (equipType, callback) {
+ var unloadEquipId = core.status.hero.equipment[equipType];
+ if (!unloadEquipId) {
+ if (callback) callback();
+ return;
+ }
+
+ this._realLoadEquip(equipType, null, unloadEquipId, callback);
+}
+
+items.prototype.compareEquipment = function (compareEquipId, beComparedEquipId) {
+ var result = { "value": {}, "percentage": {} };
+ var first = core.material.items[compareEquipId], second = core.material.items[beComparedEquipId];
+ for (var one in result) {
+ for (var name in core.status.hero) {
+ if (typeof core.status.hero[name] == 'number') {
+ var ans = 0;
+ if (first) ans += ((first.equip || {})[one] || {})[name] || 0;
+ if (second) ans -= ((second.equip || {})[one] || {})[name] || 0;
+ if (ans != 0) result[one][name] = ans;
+ }
+ }
+ }
+ return result;
+}
+
+////// 实际换装的效果 //////
+items.prototype._loadEquipEffect = function (equipId, unloadEquipId) {
+ // 比较能力值
+ var result = core.compareEquipment(equipId, unloadEquipId);
+
+ for (var name in result.percentage)
+ core.addBuff(name, result.percentage[name] / 100);
+
+ for (var name in result.value)
+ core.status.hero[name] += result.value[name];
+}
+
+items.prototype._realLoadEquip = function (type, loadId, unloadId, callback) {
+ var loadEquip = core.material.items[loadId] || {}, unloadEquip = core.material.items[unloadId] || {};
+
+ // --- 音效
+ this._realLoadEquip_playSound();
+
+ // --- 实际换装
+ this._loadEquipEffect(loadId, unloadId);
+
+ // --- 加减
+ if (loadId) core.removeItem(loadId);
+ if (unloadId) core.addItem(unloadId);
+ core.status.hero.equipment[type] = loadId || null;
+
+ // --- 提示
+ if (loadId) core.drawTip("已装备上" + loadEquip.name, loadId);
+ else if (unloadId) core.drawTip("已卸下" + unloadEquip.name, unloadId);
+
+ if (callback) callback();
+}
+
+items.prototype._realLoadEquip_playSound = function () {
+ if (core.hasFlag("__quickLoadEquip__")) return;
+ core.stopSound();
+ core.playSound('穿脱装备');
+}
+
+////// 保存装备 //////
+items.prototype.quickSaveEquip = function (index) {
+ var saveEquips = core.getFlag("saveEquips", []);
+ saveEquips[index] = core.clone(core.status.hero.equipment);
+ core.setFlag("saveEquips", saveEquips);
+ core.status.route.push("saveEquip:" + index);
+ core.drawTip("已保存" + index + "号套装");
+}
+
+////// 读取装备 //////
+items.prototype.quickLoadEquip = function (index) {
+ var current = core.getFlag("saveEquips", [])[index];
+ if (!current) {
+ core.playSound('操作失败');
+ core.drawTip(index + "号套装不存在");
+ return;
+ }
+ // 检查所有的装备
+ var equipSize = core.status.globalAttribute.equipName.length;
+ for (var i = 0; i < equipSize; i++) {
+ var v = current[i];
+ if (v && !this.canEquip(v, true))
+ return;
+ }
+ core.status.route.push("loadEquip:" + index);
+ core.setFlag("__quickLoadEquip__", true);
+ // 快速换装
+ var toEquip = [];
+ for (var i = 0; i < equipSize; i++) {
+ var now = core.status.hero.equipment[i];
+ // --- 只考虑diff的装备
+ var to = current[i];
+ if (now != to) {
+ toEquip.push(to || null);
+ if (now) {
+ this.unloadEquip(i);
+ }
+ }
+ }
+ for (var i in toEquip) {
+ var to = toEquip[i];
+ if (to) {
+ this.loadEquip(to);
+ }
+ }
+ core.removeFlag("__quickLoadEquip__");
+ this._realLoadEquip_playSound();
+
+ core.drawTip("成功换上" + index + "号套装");
+}
+
+////// 设置装备属性 //////
+items.prototype.setEquip = function (equipId, valueType, name, value, operator, prefix) {
+ var equip = core.material.items[equipId];
+ if (!equip || equip.cls != 'equips') return;
+ var equipInfo = equip.equip || {};
+ if (!equipInfo[valueType]) equipInfo[valueType] = {};
+ var toEquipInfo = core.clone(equipInfo);
+ toEquipInfo[valueType][name] = core.events._updateValueByOperator(core.calValue(value, prefix), equipInfo[valueType][name], operator);
+ // 如果是穿上状态,则还需要直接修改当前数值
+ if (core.hasEquip(equipId)) {
+ // 设置一个临时装备,然后模拟换装操作
+ var tempId = 'temp:' + equipId;
+ core.material.items[tempId] = { 'cls': 'equips', 'equip': core.clone(toEquipInfo) };
+ this._loadEquipEffect(tempId, equipId);
+ delete core.material.items[tempId];
+ core.updateStatusBar();
+ }
+ equip.equip = core.clone(toEquipInfo);
+ flags.equipInfo = flags.equipInfo || {};
+ flags.equipInfo[equipId] = core.clone(toEquipInfo);
+}
diff --git a/libs/loader.js b/libs/loader.js
new file mode 100644
index 0000000..2b3b538
--- /dev/null
+++ b/libs/loader.js
@@ -0,0 +1,516 @@
+
+/*
+loader.js:负责对资源的加载
+
+ */
+"use strict";
+
+function loader () {
+ this._init();
+}
+
+loader.prototype._init = function () {
+
+}
+
+////// 设置加载进度条进度 //////
+loader.prototype._setStartProgressVal = function (val) {
+ core.dom.startTopProgress.style.width = val + '%';
+}
+
+////// 设置加载进度条提示文字 //////
+loader.prototype._setStartLoadTipText = function (text) {
+ core.dom.startTopLoadTips.innerText = text;
+}
+
+loader.prototype._load = function (callback) {
+ if (main.useCompress) {
+ this._load_async(callback);
+ } else {
+ this._load_sync(callback);
+ }
+}
+
+loader.prototype._load_sync = function (callback) {
+ this._loadAnimates_sync();
+ this._loadMusic_sync();
+ core.loader._loadMaterials_sync(function () {
+ core.loader._loadExtraImages_sync(function () {
+ core.loader._loadAutotiles_sync(function () {
+ core.loader._loadTilesets_sync(callback);
+ })
+ })
+ });
+}
+
+loader.prototype._load_async = function (callback) {
+ core.loader._setStartLoadTipText('正在加载资源文件...');
+ var all = {};
+
+ var _makeOnProgress = function (name) {
+ if (!all[name]) all[name] = { loaded: 0, total: 0, finished: false };
+ return function (loaded, total) {
+ all[name].loaded = loaded;
+ all[name].total = total;
+ var allLoaded = 0, allTotal = 0;
+ for (var one in all) {
+ allLoaded += all[one].loaded;
+ allTotal += all[one].total;
+ }
+ if (allTotal > 0) {
+ if (allLoaded == allTotal) {
+ core.loader._setStartLoadTipText("正在处理资源文件... 请稍候...");
+ } else {
+ core.loader._setStartLoadTipText('正在加载资源文件... ' +
+ core.formatSize(allLoaded) + " / " + core.formatSize(allTotal) +
+ " (" + (allLoaded / allTotal * 100).toFixed(2) + "%)");
+ }
+ core.loader._setStartProgressVal(allLoaded / allTotal * 100);
+ }
+ };
+ }
+ var _makeOnFinished = function (name) {
+ return function () {
+ setTimeout(function () {
+ all[name].finished = true;
+ for (var one in all) {
+ if (!all[one].finished) return;
+ }
+ callback();
+ });
+ }
+ }
+
+ this._loadAnimates_async(_makeOnProgress('animates'), _makeOnFinished('animates'));
+ this._loadMusic_async(_makeOnProgress('sounds'), _makeOnFinished('sounds'));
+ this._loadMaterials_async(_makeOnProgress('materials'), _makeOnFinished('materials'));
+ this._loadExtraImages_async(_makeOnProgress('images'), _makeOnFinished('images'));
+ this._loadAutotiles_async(_makeOnProgress('autotiles'), _makeOnFinished('autotiles'));
+ this._loadTilesets_async(_makeOnProgress('tilesets'), _makeOnFinished('tilesets'));
+}
+
+// ----- 加载资源文件 ------ //
+
+loader.prototype._loadMaterials_sync = function (callback) {
+ this._setStartLoadTipText("正在加载资源文件...");
+ this.loadImages("materials", core.materials, core.material.images, function () {
+ core.loader._loadMaterials_afterLoad();
+ callback();
+ });
+}
+
+loader.prototype._loadMaterials_async = function (onprogress, onfinished) {
+ this.loadImagesFromZip('project/materials/materials.h5data', core.materials, core.material.images, onprogress, function () {
+ core.loader._loadMaterials_afterLoad();
+ onfinished();
+ });
+}
+
+loader.prototype._loadMaterials_afterLoad = function () {
+ var images = core.splitImage(core.material.images['icons']);
+ for (var key in core.statusBar.icons) {
+ if (typeof core.statusBar.icons[key] == 'number') {
+ core.statusBar.icons[key] = images[core.statusBar.icons[key]];
+ if (core.statusBar.image[key] != null)
+ core.statusBar.image[key].src = core.statusBar.icons[key].src;
+ }
+ }
+}
+
+// ------ 加载使用的图片 ------ //
+
+loader.prototype._loadExtraImages_sync = function (callback) {
+ core.material.images.images = {};
+ this._setStartLoadTipText("正在加载图片文件...");
+ core.loadImages("images", core.images, core.material.images.images, callback);
+}
+
+loader.prototype._loadExtraImages_async = function (onprogress, onfinished) {
+ core.material.images.images = {};
+ var images = core.images;
+
+ // Check .gif
+ var gifs = images.filter(function (name) {
+ return name.toLowerCase().endsWith('.gif');
+ });
+ images = images.filter(function (name) {
+ return !name.toLowerCase().endsWith('.gif');
+ });
+
+ this.loadImagesFromZip('project/images/images.h5data', images, core.material.images.images, onprogress, onfinished);
+ // gif没有被压缩在zip中,延迟加载...
+ gifs.forEach(function (gif) {
+ this.loadImage("images", gif, function (id, image) {
+ if (image != null) {
+ core.material.images.images[gif] = image;
+ }
+ });
+ }, this);
+}
+
+// ------ 加载自动元件 ------ //
+
+loader.prototype._loadAutotiles_sync = function (callback) {
+ core.material.images.autotile = {};
+ var keys = Object.keys(core.material.icons.autotile);
+ var autotiles = {};
+
+ this._setStartLoadTipText("正在加载自动元件...");
+ this.loadImages("autotiles", keys, autotiles, function () {
+ core.loader._loadAutotiles_afterLoad(keys, autotiles);
+ callback();
+ });
+}
+
+loader.prototype._loadAutotiles_async = function (onprogress, onfinished) {
+ core.material.images.autotile = {};
+ var keys = Object.keys(core.material.icons.autotile);
+ var autotiles = {};
+
+ this.loadImagesFromZip('project/autotiles/autotiles.h5data', keys, autotiles, onprogress, function () {
+ core.loader._loadAutotiles_afterLoad(keys, autotiles);
+ onfinished();
+ });
+}
+
+loader.prototype._loadAutotiles_afterLoad = function (keys, autotiles) {
+ // autotile需要保证顺序
+ keys.forEach(function (v) {
+ core.material.images.autotile[v] = autotiles[v];
+ });
+
+ setTimeout(function () {
+ core.maps._makeAutotileEdges();
+ });
+
+}
+
+// ------ 加载额外素材 ------ //
+
+loader.prototype._loadTilesets_sync = function (callback) {
+ core.material.images.tilesets = {};
+ this._setStartLoadTipText("正在加载额外素材...");
+ this.loadImages("tilesets", core.tilesets, core.material.images.tilesets, function () {
+ core.loader._loadTilesets_afterLoad();
+ callback();
+ });
+}
+
+loader.prototype._loadTilesets_async = function (onprogress, onfinished) {
+ core.material.images.tilesets = {};
+ this.loadImagesFromZip('project/tilesets/tilesets.h5data', core.tilesets, core.material.images.tilesets, onprogress, function () {
+ core.loader._loadTilesets_afterLoad();
+ onfinished();
+ });
+}
+
+loader.prototype._loadTilesets_afterLoad = function () {
+ // 检查宽高是32倍数,如果出错在控制台报错
+ for (var imgName in core.material.images.tilesets) {
+ var img = core.material.images.tilesets[imgName];
+ if (img.width % 32 != 0 || img.height % 32 != 0) {
+ console.warn("警告!" + imgName + "的宽或高不是32的倍数!");
+ }
+ if (img.width * img.height > 32 * 32 * 3000) {
+ console.warn("警告!" + imgName + "上的图块素材个数大于3000!");
+ }
+ }
+}
+
+// ------ 实际加载一系列图片 ------ //
+
+loader.prototype.loadImages = function (dir, names, toSave, callback) {
+ if (!names || names.length == 0) {
+ if (callback) callback();
+ return;
+ }
+ var items = 0;
+ for (var i = 0; i < names.length; i++) {
+ this.loadImage(dir, names[i], function (id, image) {
+ core.loader._setStartLoadTipText('正在加载图片 ' + id + "...");
+ if (toSave[id] !== undefined) {
+ if (image != null)
+ toSave[id] = image;
+ return;
+ }
+ toSave[id] = image;
+ items++;
+ core.loader._setStartProgressVal(items * (100 / names.length));
+ if (items == names.length) {
+ if (callback) callback();
+ }
+ })
+ }
+}
+
+loader.prototype.loadImage = function (dir, imgName, callback) {
+ try {
+ var name = imgName;
+ if (name.indexOf(".") < 0)
+ name = name + ".png";
+ var image = new Image();
+ image.onload = function () {
+ image.setAttribute('_width', image.width);
+ image.setAttribute('_height', image.height);
+ callback(imgName, image);
+ }
+ image.onerror = function () {
+ callback(imgName, null);
+ }
+ image.src = 'project/' + dir + '/' + name + "?v=" + main.version;
+ if (name.endsWith('.gif'))
+ callback(imgName, null);
+ }
+ catch (e) {
+ console.error(e);
+ }
+}
+
+// ------ 从zip中加载一系列图片 ------ //
+
+loader.prototype.loadImagesFromZip = function (url, names, toSave, onprogress, onfinished) {
+ if (!names || names.length == 0) {
+ if (onfinished) onfinished();
+ return;
+ }
+
+ core.unzip(url + "?v=" + main.version, function (data) {
+ var cnt = 1;
+ names.forEach(function (name) {
+ var imgName = name;
+ if (imgName.indexOf('.') < 0) imgName += '.png';
+ if (imgName in data) {
+ var img = new Image();
+ var url = URL.createObjectURL(data[imgName]);
+ cnt++;
+ img.onload = function () {
+ cnt--;
+ URL.revokeObjectURL(url);
+ img.setAttribute('_width', img.width);
+ img.setAttribute('_height', img.height);
+ if (cnt == 0 && onfinished) onfinished();
+ }
+ img.src = url;
+ toSave[name] = img;
+ }
+ });
+ cnt--;
+ if (cnt == 0 && onfinished) onfinished();
+ }, null, false, onprogress);
+}
+
+// ------ 加载动画文件 ------ //
+
+loader.prototype._loadAnimates_sync = function () {
+ this._setStartLoadTipText("正在加载动画文件...");
+
+ if (main.supportBunch) {
+ if (core.animates.length > 0) {
+ core.http('GET', '__all_animates__?v=' + main.version + '&id=' + core.animates.join(','), null, function (content) {
+ var u = content.split('@@@~~~###~~~@@@');
+ for (var i = 0; i < core.animates.length; ++i) {
+ if (u[i] != '') {
+ core.material.animates[core.animates[i]] = core.loader._loadAnimate(u[i]);
+ } else {
+ console.error('无法找到动画文件' + core.animates[i] + '!');
+ }
+ }
+ }, "text/plain; charset=x-user-defined");
+ }
+ return;
+ }
+
+ core.animates.forEach(function (t) {
+ core.http('GET', 'project/animates/' + t + ".animate?v=" + main.version, null, function (content) {
+ core.material.animates[t] = core.loader._loadAnimate(content);
+ }, function (e) {
+ console.error(e);
+ core.material.animates[t] = null;
+ }, "text/plain; charset=x-user-defined")
+ });
+}
+
+loader.prototype._loadAnimates_async = function (onprogress, onfinished) {
+ core.unzip('project/animates/animates.h5data?v=' + main.version, function (animates) {
+ for (var name in animates) {
+ if (name.endsWith(".animate")) {
+ var t = name.substring(0, name.length - 8);
+ if (core.animates.indexOf(t) >= 0)
+ core.material.animates[t] = core.loader._loadAnimate(animates[name]);
+ }
+ }
+ onfinished();
+ }, null, true, onprogress);
+}
+
+loader.prototype._loadAnimate = function (content) {
+ try {
+ content = JSON.parse(content);
+ var data = {};
+ data.ratio = content.ratio;
+ data.se = content.se;
+ data.pitch = content.pitch;
+ data.images = [];
+ content.bitmaps.forEach(function (t2) {
+ if (!t2) {
+ data.images.push(null);
+ }
+ else {
+ try {
+ var image = new Image();
+ image.src = t2;
+ data.images.push(image);
+ } catch (e) {
+ console.error(e);
+ data.images.push(null);
+ }
+ }
+ })
+ data.frame = content.frame_max;
+ data.frames = [];
+ content.frames.forEach(function (t2) {
+ var info = [];
+ t2.forEach(function (t3) {
+ info.push({
+ 'index': t3[0],
+ 'x': t3[1],
+ 'y': t3[2],
+ 'zoom': t3[3],
+ 'opacity': t3[4],
+ 'mirror': t3[5] || 0,
+ 'angle': t3[6] || 0,
+ })
+ })
+ data.frames.push(info);
+ });
+ return data;
+ }
+ catch (e) {
+ console.error(e);
+ return null;
+ }
+}
+
+// ------ 加载音乐和音效 ------ //
+
+loader.prototype._loadMusic_sync = function () {
+ this._setStartLoadTipText("正在加载音效文件...");
+ core.bgms.forEach(function (t) {
+ core.loader.loadOneMusic(t);
+ });
+ core.sounds.forEach(function (t) {
+ core.loader.loadOneSound(t);
+ });
+ // 直接开始播放
+ core.playBgm(main.startBgm);
+}
+
+loader.prototype._loadMusic_async = function (onprogress, onfinished) {
+ core.bgms.forEach(function (t) {
+ core.loader.loadOneMusic(t);
+ });
+ core.unzip('project/sounds/sounds.h5data?v=' + main.version, function (data) {
+ // 延迟解析
+ setTimeout(function () {
+ for (var name in data) {
+ if (core.sounds.indexOf(name) >= 0) {
+ core.loader._loadOneSound_decodeData(name, data[name]);
+ }
+ }
+ });
+ onfinished();
+ }, null, false, onprogress);
+
+ // 直接开始播放
+ core.playBgm(main.startBgm);
+}
+
+loader.prototype.loadOneMusic = function (name) {
+ var music = new Audio();
+ music.preload = 'none';
+ if (main.bgmRemote) music.src = main.bgmRemoteRoot + core.firstData.name + '/' + name;
+ else music.src = 'project/bgms/' + name;
+ music.loop = 'loop';
+ core.material.bgms[name] = music;
+}
+
+loader.prototype.loadOneSound = function (name) {
+ core.http('GET', 'project/sounds/' + name + "?v=" + main.version, null, function (data) {
+ core.loader._loadOneSound_decodeData(name, data);
+ }, function (e) {
+ console.error(e);
+ core.material.sounds[name] = null;
+ }, null, 'arraybuffer');
+}
+
+loader.prototype._loadOneSound_decodeData = function (name, data) {
+ if (data instanceof Blob) {
+ var blobReader = new zip.BlobReader(data);
+ blobReader.init(function () {
+ blobReader.readUint8Array(0, blobReader.size, function (uint8) {
+ core.loader._loadOneSound_decodeData(name, uint8.buffer);
+ })
+ });
+ return;
+ }
+ try {
+ core.musicStatus.audioContext.decodeAudioData(data, function (buffer) {
+ core.material.sounds[name] = buffer;
+ }, function (e) {
+ console.error(e);
+ core.material.sounds[name] = null;
+ })
+ }
+ catch (e) {
+ console.error(e);
+ core.material.sounds[name] = null;
+ }
+}
+
+loader.prototype.loadBgm = function (name) {
+ name = core.getMappedName(name);
+ if (!core.material.bgms[name]) return;
+ // 如果没开启音乐,则不预加载
+ if (!core.musicStatus.bgmStatus) return;
+ // 是否已经预加载过
+ var index = core.musicStatus.cachedBgms.indexOf(name);
+ if (index >= 0) {
+ core.musicStatus.cachedBgms.splice(index, 1);
+ }
+ else {
+ // 预加载BGM
+ this._preloadBgm(core.material.bgms[name]);
+ // core.material.bgms[name].load();
+ // 清理尾巴
+ if (core.musicStatus.cachedBgms.length == core.musicStatus.cachedBgmCount) {
+ this.freeBgm(core.musicStatus.cachedBgms.pop());
+ }
+ }
+ // 移动到缓存最前方
+ core.musicStatus.cachedBgms.unshift(name);
+}
+
+loader.prototype._preloadBgm = function (bgm) {
+ bgm.volume = 0;
+ bgm.play();
+}
+
+loader.prototype.freeBgm = function (name) {
+ name = core.getMappedName(name);
+ if (!core.material.bgms[name]) return;
+ // 从cachedBgms中删除
+ core.musicStatus.cachedBgms = core.musicStatus.cachedBgms.filter(function (t) {
+ return t != name;
+ });
+ // 清掉缓存
+ core.material.bgms[name].removeAttribute("src");
+ core.material.bgms[name].load();
+ core.material.bgms[name] = null;
+ if (name == core.musicStatus.playingBgm) {
+ core.musicStatus.playingBgm = null;
+ }
+ // 三秒后重新加载
+ setTimeout(function () {
+ core.loader.loadOneMusic(name);
+ }, 3000);
+}
\ No newline at end of file
diff --git a/libs/maps.js b/libs/maps.js
new file mode 100644
index 0000000..4fbbb8b
--- /dev/null
+++ b/libs/maps.js
@@ -0,0 +1,3112 @@
+
+"use strict";
+
+function maps () {
+ this._init();
+}
+
+maps.prototype._init = function () {
+ this.blocksInfo = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
+ //delete(maps_90f36752_8815_4be8_b32b_d7fad1d0542e);
+}
+
+maps.prototype._initFloors = function (floorId) {
+ if (!floorId) {
+ core.floorIds.forEach(function (floorId) {
+ core.maps._initFloors(floorId);
+ });
+ return;
+ }
+ // 战前事件兼容性
+ if (!core.floors[floorId].beforeBattle) core.floors[floorId].beforeBattle = {}
+ // cannotMoveIn兼容性
+ if (!core.floors[floorId].cannotMoveIn) core.floors[floorId].cannotMoveIn = {}
+}
+
+maps.prototype._resetFloorImages = function () {
+ for (var floorId in core.status.maps) {
+ (core.status.maps[floorId].images || []).forEach(function (one) {
+ var flag = "__floorImg__" + floorId + "_" + one.x + "_" + one.y;
+ if (core.getFlag(flag) == null) {
+ if (one.disabled) core.setFlag(flag, true);
+ }
+ })
+ }
+}
+
+maps.prototype._setHDCanvasSize = function (ctx, width, height) {
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ var ratio = core.domStyle.scale;
+ ratio *= devicePixelRatio;
+ if (width != null) ctx.canvas.width = width * ratio;
+ if (height != null) ctx.canvas.height = height * ratio;
+ ctx.scale(ratio, ratio);
+ ctx.canvas.setAttribute('isHD', 1);
+}
+
+// ------ 加载地图与地图的存档读档(压缩与解压缩) ------ //
+
+////// 加载某个楼层(从剧本或存档中) //////
+maps.prototype.loadFloor = function (floorId, map) {
+ var floor = core.floors[floorId];
+ if (!map) map = core.cloneArray(floor.map);
+ if (map instanceof Array) {
+ map = { "map": map };
+ }
+ if (!map.map) map.map = core.cloneArray(floor.map);
+ var content = {};
+ var notCopy = this._loadFloor_doNotCopy();
+ for (var name in floor) {
+ if (notCopy.indexOf(name) == -1 && floor[name] != null)
+ content[name] = core.clone(floor[name]);
+ }
+ for (var name in map) {
+ if (notCopy.indexOf(name) == -1 && map[name] != null)
+ content[name] = core.clone(map[name]);
+ }
+ content.map = map.map;
+ if (main.mode == 'editor') {
+ this.extractBlocks(content);
+ }
+ return content;
+}
+
+maps.prototype._loadFloor_doNotCopy = function () {
+ return [
+ "firstArrive", "eachArrive", "blocks", "parallelDo", "map", "bgmap", "fgmap",
+ "events", "changeFloor", "beforeBattle", "afterBattle", "afterGetItem", "afterOpenDoor",
+ "cannotMove", "cannotMoveIn"
+ ];
+}
+
+/// 根据需求解析出blocks
+maps.prototype.extractBlocks = function (map) {
+ map = map || core.status.floorId;
+ if (typeof map == 'string') map = (core.status.maps || {})[map];
+ if (!map) return;
+ if (map.blocks) return;
+ if (map.deleted) {
+ map.blocks = [];
+ return;
+ }
+ var floorId = map.floorId;
+ map.blocks = this._mapIntoBlocks(this.decompressMap(map.map, floorId), core.floors[floorId], floorId);
+}
+
+maps.prototype._mapIntoBlocks = function (map, floor, floorId) {
+ var blocks = [];
+ var mw = core.floors[floorId].width;
+ var mh = core.floors[floorId].height;
+ for (var i = 0; i < mh; i++) {
+ for (var j = 0; j < mw; j++) {
+ var number = (map[i] || [])[j] || 0, block;
+ if (main.mode == 'editor') {
+ if (!number) continue;
+ block = { x: j, y: i, id: number, event: this.getBlockByNumber(number).event };
+ } else {
+ block = this.initBlock(j, i, number, true, floor);
+ }
+ if (block.id != 0 || block.event.trigger)
+ blocks.push(block);
+ }
+ }
+ return blocks;
+}
+
+maps.prototype.extractBlocksForUI = function (map, flags) {
+ if (!map || map.blocks) return;
+ if (map.deleted) return map.blocks = [];
+ var floorId = map.floorId;
+ var decompressed = this.decompressMap(map.map, floorId);
+ map.blocks = [];
+ var floor = core.floors[floorId];
+ var mw = floor.width;
+ var mh = floor.height;
+ for (var i = 0; i < mh; i++) {
+ for (var j = 0; j < mw; j++) {
+ var number = (decompressed[i] || [])[j] || 0;
+ if (!number || number == 17) continue;
+ var isDisabled = this.isMapBlockDisabled(floorId, j, i, flags);
+ if (isDisabled) continue;
+ if (isDisabled == null) {
+ // 检查是否初始禁用
+ var event = (floor.events || {})[j + "," + i];
+ if (event != null && event.enable === false) continue;
+ }
+ var opacity = this._getBlockOpacityFromFlag(floorId, j, i, flags);
+ if (opacity == null) {
+ // 检查初始不透明度
+ var event = (floor.events || {})[j + "," + i];
+ if (event != null && event.opacity != null) opacity = event.opacity;
+ }
+ var filter = this._getBlockFilterFromFlag(floorId, j, i, flags);
+ if (filter == null) {
+ // 检查初始filter
+ var event = (floor.events || {})[j + "," + i];
+ if (event != null && event.filter != null) filter = core.clone(event.filter);
+ }
+ map.blocks.push(Object.assign({}, this.getBlockByNumber(number), { x: j, y: i, opacity: opacity, filter: filter }));
+ }
+ }
+}
+
+////// 从ID获得数字 //////
+maps.prototype.getNumberById = function (id) {
+ id = this.getIdOfThis(id);
+ core.status.id2number = core.status.id2number || {};
+ if (core.status.id2number[id] != null) return core.status.id2number[id];
+ return core.status.id2number[id] = this._getNumberById(id);
+}
+
+maps.prototype._getNumberById = function (id) {
+ for (var number in this.blocksInfo) {
+ if ((this.blocksInfo[number] || {}).id == id)
+ return parseInt(number) || 0;
+ }
+ // tilesets
+ if (/^X\d+$/.test(id)) {
+ if (core.icons.getTilesetOffset(id)) return parseInt(id.substring(1));
+ }
+ // 特殊ID
+ if (id == 'none') return 0;
+ if (id == 'airwall') return 17;
+ return 0;
+}
+
+maps.prototype.getBlockByNumber = function (number) {
+ core.status.number2Block = core.status.number2Block || {};
+ if (core.status.number2Block[number] != null) return core.status.number2Block[number];
+ return core.status.number2Block[number] = this.initBlock(null, null, number, true);
+}
+
+maps.prototype.getBlockById = function (id) {
+ return this.getBlockByNumber(this.getNumberById(id));
+}
+
+maps.prototype.getIdOfThis = function (id) {
+ if (id != 'this') return id;
+ if (core.status.event.id != 'action') return id;
+ if (!core.status.event.data || core.status.event.data.x == null || core.status.event.data.y == null) return id;
+ return core.getBlockId(core.status.event.data.x, core.status.event.data.y) || id;
+}
+
+////// 数字和ID的对应关系 //////
+maps.prototype.initBlock = function (x, y, id, addInfo, eventFloor) {
+ var disable = null;
+ var opacity = null;
+ var filter = null;
+ if (eventFloor != null) {
+ disable = this.isMapBlockDisabled(eventFloor.floorId, x, y);
+ opacity = this._getBlockOpacityFromFlag(eventFloor.floorId, x, y);
+ filter = this._getBlockFilterFromFlag(eventFloor.floorId, x, y);
+ }
+ var block = { 'x': x, 'y': y, 'id': id };
+ if (disable != null) block.disable = disable;
+ if (opacity != null) block.opacity = opacity;
+ if (filter != null) block.filter = filter;
+
+ if (id == 17) block.event = { "cls": "terrains", "id": "airwall", "cannotIn": ["up", "down", "left", "right"] };
+ else if (id in this.blocksInfo) block.event = JSON.parse(JSON.stringify(this.blocksInfo[id]));
+ else if (core.icons.getTilesetOffset(id)) block.event = { "cls": "tileset", "id": "X" + id };
+ else block.event = { 'cls': 'terrains', 'id': 'none', 'noPass': false };
+
+ if (block.event.noPass == null) {
+ if (block.event.canPass == null) {
+ block.event.noPass = block.event.cls != 'items';
+ } else {
+ block.event.noPass = !block.event.canPass;
+ }
+ }
+ delete block.event.canPass;
+
+ // 增加怪物的faceIds
+ if (block.event.cls.indexOf("enemy") == 0) {
+ var enemy = core.material.enemys[block.event.id];
+ if (enemy && enemy.faceIds) {
+ block.event.faceIds = enemy.faceIds;
+ }
+ }
+
+ if (addInfo) this._addInfo(block);
+ if (eventFloor) {
+ this._addEvent(block, x, y, (eventFloor.events || {})[x + "," + y]);
+ var changeFloor = (eventFloor.changeFloor || {})[x + "," + y];
+ if (changeFloor) this._addEvent(block, x, y, { "trigger": "changeFloor", "data": changeFloor });
+ }
+ if (main.mode == 'editor') delete block.disable;
+ return block;
+}
+
+////// 添加一些信息到block上 //////
+maps.prototype._addInfo = function (block) {
+ if (block.event.cls.indexOf("enemy") == 0 && !block.event.trigger) {
+ block.event.trigger = 'battle';
+ }
+ if (block.event.cls == 'items' && !block.event.trigger) {
+ block.event.trigger = 'getItem';
+ }
+ if (block.event.animate == null) {
+ block.event.animate = core.icons._getAnimateFrames(block.event.cls);
+ }
+ block.event.height = 32;
+ if (block.event.cls == 'enemy48' || block.event.cls == 'npc48')
+ block.event.height = 48;
+}
+
+////// 向该楼层添加剧本的自定义事件 //////
+maps.prototype._addEvent = function (block, x, y, event) {
+ if (!event) return;
+ // event是字符串或数组?
+ if (typeof event == "string") {
+ event = { "data": [event] };
+ }
+ else if (event instanceof Array) {
+ event = { "data": event };
+ }
+ event.data = event.data || [];
+
+ // 覆盖enable
+ if (block.disable == null && event.enable != null) {
+ block.disable = !event.enable;
+ }
+ // 覆盖opacity
+ if (block.opacity == null && event.opacity != null) {
+ block.opacity = event.opacity;
+ }
+ if (block.filter == null && event.filter != null) {
+ block.filter = core.clone(event.filter);
+ }
+ // 覆盖animate
+ if (event.animate === false) {
+ block.event.animate = 1;
+ }
+ // 覆盖所有属性
+ for (var key in event) {
+ if (key != "enable" && key != "animate" && key != "opacity" && key != "filter" && event[key] != null) {
+ block.event[key] = core.clone(event[key]);
+ }
+ }
+ // 给无trigger的增加trigger:action
+ if (!block.event.trigger) {
+ block.event.trigger = 'action';
+ }
+}
+
+////// 初始化所有地图 //////
+maps.prototype._initMaps = function () {
+ var floorIds = core.floorIds;
+ var maps = {};
+ for (var i = 0; i < floorIds.length; i++) {
+ var floorId = floorIds[i];
+ maps[floorId] = this.loadFloor(floorId);
+ }
+ return maps;
+}
+
+////// 压缩地图
+maps.prototype.compressMap = function (mapArr, floorId) {
+ var floorMap = core.floors[floorId].map;
+ if (core.utils.same(mapArr, floorMap)) return null;
+
+ var mw = core.floors[floorId].width;
+ var mh = core.floors[floorId].height;
+ for (var x = 0; x < mh; x++) {
+ if (core.utils.same(mapArr[x], floorMap[x])) {
+ // 没有改变的行直接删掉记成0
+ mapArr[x] = 0;
+ }
+ else {
+ for (var y = 0; y < mw; y++) {
+ if (mapArr[x][y] === floorMap[x][y]) {
+ // 没有改变的数据记成-1
+ mapArr[x][y] = -1;
+ }
+ }
+ }
+ }
+ return mapArr;
+}
+
+maps.prototype._processInvalidMap = function (mapArr, width, height) {
+ if (mapArr.length == height && mapArr[0].length == width) return mapArr;
+ var map = [];
+ for (var i = 0; i < height; ++i) {
+ map.push(Array(width).fill(0));
+ }
+ for (var j = 0; j < height; ++j) {
+ for (var i = 0; i < width; ++i) {
+ if (j < mapArr.length && i < mapArr[j].length)
+ map[j][i] = mapArr[j][i];
+ }
+ }
+ return map;
+}
+
+maps.prototype._getBlockOpacityFromFlag = function (floorId, x, y, flags) {
+ if (flags == null) flags = (core.status.hero || {}).flags;
+ if (flags == null) return null;
+ var __opacity__ = flags.__opacity__ || {};
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return null;
+ if ((flags.__removed__ || []).indexOf(floorId) >= 0) return null;
+ var index = x + y * core.floors[floorId].width;
+ return (__opacity__[floorId] || {})[index];
+}
+
+maps.prototype._getBlockFilterFromFlag = function (floorId, x, y, flags) {
+ if (flags == null) flags = (core.status.hero || {}).flags;
+ if (flags == null) return null;
+ var __filter__ = flags.__filter__ || {};
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return null;
+ if ((flags.__removed__ || []).indexOf(floorId) >= 0) return null;
+ var index = x + y * core.floors[floorId].width;
+ return core.clone((__filter__[floorId] || {})[index]);
+}
+
+////// 设置某个点的不透明度 //////
+maps.prototype.setBlockOpacity = function (opacity, x, y, floorId) {
+ if (window.flags == null) return;
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return;
+ if (!window.flags.__opacity__) window.flags.__opacity__ = {};
+ if ((window.flags.__removed__ || []).indexOf(floorId) >= 0) return;
+ var index = x + y * core.floors[floorId].width;
+ var __opacity__ = window.flags.__opacity__;
+ if (!__opacity__[floorId]) __opacity__[floorId] = {};
+ if (opacity == null) delete __opacity__[floorId][index];
+ else __opacity__[floorId][index] = opacity;
+
+ ////// 重绘该点图块
+ var block = core.getBlock(x, y, floorId, true);
+ if (block != null) {
+ block.opacity = opacity;
+ if (floorId == core.status.floorId && !block.disable) {
+ if (block.event.cls == 'autotile') {
+ core.redrawMap();
+ } else {
+ core.drawBlock(block);
+ core.addGlobalAnimate(block);
+ }
+ }
+ }
+}
+
+maps.prototype.setBlockFilter = function (filter, x, y, floorId) {
+ if (window.flags == null) return;
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return;
+ if (!window.flags.__filter__) window.flags.__filter__ = {};
+ if ((window.flags.__removed__ || []).indexOf(floorId) >= 0) return;
+ var index = x + y * core.floors[floorId].width;
+ var __filter__ = window.flags.__filter__;
+ if (!__filter__[floorId]) __filter__[floorId] = {};
+ if (filter == null) delete __filter__[floorId][index];
+ else {
+ if (!filter.blur && !filter.hue && !filter.shadow && !filter.grayscale && !filter.invert)
+ delete __filter__[floorId][index];
+ else __filter__[floorId][index] = core.clone(filter);
+ }
+
+ ////// 重绘该点图块
+ var block = core.getBlock(x, y, floorId, true);
+ if (block != null) {
+ block.filter = core.clone(filter);
+ if (floorId == core.status.floorId && !block.disable) {
+ if (block.event.cls == 'autotile') {
+ core.redrawMap();
+ } else {
+ core.drawBlock(block);
+ core.addGlobalAnimate(block);
+ }
+ }
+ }
+}
+
+////// 某个点图块是否被强制启用或禁用
+maps.prototype.isMapBlockDisabled = function (floorId, x, y, flags) {
+ if (flags == null) flags = (core.status.hero || {}).flags;
+ if (flags == null) return null;
+ var __disabled__ = flags.__disabled__ || {};
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return null;
+ if ((flags.__removed__ || []).indexOf(floorId) >= 0) return null;
+ var index = x + y * core.floors[floorId].width;
+ if (!__disabled__[floorId]) return null;
+ if (__disabled__[floorId][0].indexOf(index) >= 0) return true;
+ if (__disabled__[floorId][1].indexOf(index) >= 0) return false;
+}
+
+////// 设置某个点的图块强制启用/禁用状态
+maps.prototype.setMapBlockDisabled = function (floorId, x, y, disabled) {
+ if (window.flags == null) return;
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return null;
+ if (!window.flags.__disabled__) window.flags.__disabled__ = {};
+ if ((window.flags.__removed__ || []).indexOf(floorId) >= 0) return;
+ var __disabled__ = window.flags.__disabled__ || {};
+ if (!__disabled__[floorId]) __disabled__[floorId] = [[], []];
+ var index = x + y * core.floors[floorId].width;
+ __disabled__[floorId][0] = __disabled__[floorId][0].filter(function (x) { return x != index });
+ __disabled__[floorId][1] = __disabled__[floorId][1].filter(function (x) { return x != index });
+ if (disabled == null) return;
+ if (disabled) __disabled__[floorId][0].push(index);
+ else __disabled__[floorId][1].push(index);
+}
+
+////// 解压缩地图
+maps.prototype.decompressMap = function (mapArr, floorId) {
+ var mw = core.floors[floorId].width;
+ var mh = core.floors[floorId].height;
+ var floorMap = this._processInvalidMap(core.floors[floorId].map, mw, mh);
+
+ if (!mapArr) return core.cloneArray(floorMap);
+
+ for (var x = 0; x < mh; x++) {
+ if (x >= mapArr.length) {
+ mapArr.push(0);
+ }
+ if (mapArr[x] === 0) {
+ mapArr[x] = core.cloneArray(floorMap[x]);
+ }
+ else {
+ for (var y = 0; y < mw; y++) {
+ if (y >= mapArr[x].length) mapArr[x].push(-1);
+ if (mapArr[x][y] === -1) {
+ mapArr[x][y] = floorMap[x][y];
+ }
+ }
+ }
+ }
+ return mapArr;
+}
+
+////// 将当前地图重新变成数字,以便于存档 //////
+maps.prototype.saveMap = function (floorId) {
+ var maps = core.status.maps;
+ if (!floorId) {
+ var map = {};
+ for (var id in maps) {
+ var obj = this.saveMap(id);
+ if (Object.keys(obj).length > 0) map[id] = obj;
+ }
+ return map;
+ }
+ // 砍层状态:直接返回
+ if ((flags.__removed__ || []).indexOf(floorId) >= 0) {
+ return {};
+ }
+
+ var map = maps[floorId];
+ var thisFloor = this._compressFloorData(map, core.floors[floorId]);
+ var mapArr = this.compressMap(map.blocks ? this._getMapArrayFromBlocks(map.blocks, map.width, map.height, true) : map.map, floorId);
+ if (mapArr != null) thisFloor.map = mapArr;
+ return thisFloor;
+}
+
+maps.prototype._compressFloorData = function (map, floor) {
+ var thisFloor = {};
+ var notCopy = this._loadFloor_doNotCopy();
+ for (var name in map) {
+ if (notCopy.indexOf(name) == -1) {
+ var floorData = floor[name];
+ if (!core.utils.same(map[name], floorData)) {
+ thisFloor[name] = core.clone(map[name]);
+ }
+ }
+ }
+ return thisFloor;
+}
+
+////// 将存档中的地图信息重新读取出来 //////
+maps.prototype.loadMap = function (data, floorId, flags) {
+ if (!floorId) {
+ var map = {};
+ core.floorIds.forEach(function (id) {
+ if (core.inArray((flags || {}).__removed__, id)) {
+ data[id] = { deleted: true, canFlyTo: false, canFlyFrom: false, cannotViewMap: true };
+ }
+ map[id] = core.maps.loadFloor(id, data[id]);
+ })
+ return map;
+ }
+ return this.loadFloor(floorId, data[floorId]);
+}
+
+////// 更改地图画布的尺寸
+maps.prototype.resizeMap = function (floorId) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return;
+ core.bigmap.width = core.floors[floorId].width;
+ core.bigmap.height = core.floors[floorId].height;
+ core.bigmap.posX = core.bigmap.posY = 0;
+
+ core.bigmap.v2 = core.bigmap.width * core.bigmap.height > core.bigmap.threshold;
+ var width = core.bigmap.v2 ? core._PX_ + 64 : core.bigmap.width * 32;
+ var height = core.bigmap.v2 ? core._PY_ + 64 : core.bigmap.height * 32;
+
+ core.bigmap.canvas.forEach(function (cn) {
+ if (core.domStyle.hdCanvas.indexOf(cn) >= 0)
+ core.maps._setHDCanvasSize(core.canvas[cn], width, height);
+ else {
+ core.canvas[cn].canvas.width = width;
+ core.canvas[cn].canvas.height = height;
+ }
+ core.canvas[cn].canvas.style.width = width * core.domStyle.scale + "px";
+ core.canvas[cn].canvas.style.height = height * core.domStyle.scale + "px";
+ core.canvas[cn].translate(core.bigmap.v2 ? 32 : 0, core.bigmap.v2 ? 32 : 0);
+ if (main.mode === 'editor' && editor.isMobile) {
+ core.canvas[cn].canvas.style.width = width / core._PX_ * 96 + "vw";
+ core.canvas[cn].canvas.style.height = height / core._PY_ * 96 + "vw";
+ }
+ });
+}
+
+////// 将当前地图重新变成二维数组形式 //////
+maps.prototype.getMapArray = function (floorId, noCache) {
+ floorId = floorId || core.status.floorId;
+ var map = core.status.maps[floorId];
+ if (!map.blocks || !noCache) return map.map;
+ return map.map = this._getMapArrayFromBlocks(map.blocks, map.width, map.height);
+}
+
+////// 获得地图上某点的数字
+maps.prototype.getMapNumber = function (x, y, floorId, noCache) {
+ return this.getMapArray(floorId, noCache)[y][x];
+}
+
+maps.prototype._updateMapArray = function (floorId, x, y) {
+ floorId = floorId || core.status.floorId;
+ var map = core.status.maps[floorId];
+ if (!map.blocks) return;
+ if (x == null || y == null) return this.getMapArray(floorId, true);
+ var block = this.getBlock(x, y, floorId, true);
+ if (block == null || block.disable) map.map[y][x] = 0;
+ else map.map[y][x] = block.id;
+}
+
+maps.prototype._getMapArrayFromBlocks = function (blockArray, width, height, showDisable) {
+ var blocks = [];
+ for (var x = 0; x < height; x++) blocks.push(Array(width).fill(0));
+
+ blockArray.forEach(function (block) {
+ if (showDisable || !block.disable)
+ blocks[block.y][block.x] = block.id;
+ });
+ return blocks;
+}
+
+////// 以x,y的形式返回每个点的事件 //////
+maps.prototype.getMapBlocksObj = function (floorId, noCache) {
+ floorId = floorId || core.status.floorId;
+ if (core.status.mapBlockObjs[floorId] && !noCache)
+ return core.status.mapBlockObjs[floorId];
+
+ var obj = {};
+ core.extractBlocks(floorId);
+ core.status.maps[floorId].blocks.forEach(function (block) {
+ obj[block.x + "," + block.y] = block;
+ });
+ return core.status.mapBlockObjs[floorId] = obj;
+}
+
+////// 将背景前景层变成二维数组的形式 //////
+maps.prototype._getBgFgMapArray = function (name, floorId, noCache) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return [];
+ var width = core.floors[floorId].width;
+ var height = core.floors[floorId].height;
+
+ if (!noCache && core.status[name + "maps"][floorId])
+ return core.status[name + "maps"][floorId];
+
+ var arr = (main.mode == 'editor' && !(window.editor && editor.uievent && editor.uievent.isOpen))
+ ? core.cloneArray(editor[name + 'map']) : null;
+ if (arr == null)
+ arr = core.cloneArray(core.floors[floorId][name + "map"] || []);
+
+ for (var y = 0; y < height; ++y) {
+ if (arr[y] == null) arr[y] = Array(width).fill(0);
+ }
+ (core.getFlag('__' + name + 'v__', {})[floorId] || []).forEach(function (one) {
+ arr[one[1]][one[0]] = one[2] || 0;
+ });
+ (core.getFlag('__' + name + 'd__', {})[floorId] || []).forEach(function (one) {
+ arr[one[1]][one[0]] = 0;
+ });
+ if (main.mode == 'editor') {
+ for (var x = 0; x < width; x++) {
+ for (var y = 0; y < height; y++) {
+ arr[y][x] = arr[y][x].idnum || arr[y][x] || 0;
+ }
+ }
+ }
+ if (core.status[name + "maps"])
+ core.status[name + "maps"][floorId] = arr;
+ return arr;
+}
+
+maps.prototype.getBgMapArray = function (floorId) {
+ return this._getBgFgMapArray('bg', floorId);
+}
+
+maps.prototype.getFgMapArray = function (floorId) {
+ return this._getBgFgMapArray('fg', floorId);
+}
+
+maps.prototype._getBgFgNumber = function (name, x, y, floorId) {
+ if (x == null) x = core.getHeroLoc('x');
+ if (y == null) y = core.getHeroLoc('y');
+ return this._getBgFgMapArray(name, floorId)[y][x];
+}
+
+maps.prototype.getBgNumber = function (x, y, floorId) {
+ return this._getBgFgNumber('bg', x, y, floorId);
+}
+
+maps.prototype.getFgNumber = function (x, y, floorId) {
+ return this._getBgFgNumber('fg', x, y, floorId);
+}
+
+// ------ 当前能否朝某方向移动,能否瞬间移动 ------ //
+
+////// 生成全图的当前可移动信息 //////
+maps.prototype.generateMovableArray = function (floorId) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return null;
+ var arrays = this._generateMovableArray_arrays(floorId);
+
+ var width = core.floors[floorId].width, height = core.floors[floorId].height;
+ var array = [];
+ for (var x = 0; x < width; ++x) {
+ array[x] = Array(height).fill([]);
+ }
+ var v2 = floorId == core.status.floorId && core.bigmap.v2;
+ var startX = v2 ? Math.max(0, core.bigmap.posX - core.bigmap.extend) : 0;
+ var endX = v2 ? Math.min(width, core.bigmap.posX + core._WIDTH_ + core.bigmap.extend + 1) : width;
+ var startY = v2 ? Math.max(0, core.bigmap.posY - core.bigmap.extend) : 0;
+ var endY = v2 ? Math.min(height, core.bigmap.posY + core._HEIGHT_ + core.bigmap.extend + 1) : height;
+
+ for (var x = startX; x < endX; x++) {
+ for (var y = startY; y < endY; y++) {
+ array[x][y] = ["left", "down", "up", "right"].filter(function (direction) {
+ return core.maps._canMoveHero_checkPoint(x, y, direction, floorId, arrays);
+ });
+ }
+ }
+ return array;
+}
+
+maps.prototype._generateMovableArray_arrays = function (floorId) {
+ return {
+ bgArray: this.getBgMapArray(floorId),
+ fgArray: this.getFgMapArray(floorId),
+ eventArray: this.getMapArray(floorId)
+ };
+}
+
+////// 勇士能否前往某方向 //////
+maps.prototype.canMoveHero = function (x, y, direction, floorId) {
+ if (x == null) x = core.getHeroLoc('x');
+ if (y == null) y = core.getHeroLoc('y');
+ direction = direction || core.getHeroLoc('direction');
+ return this._canMoveHero_checkPoint(x, y, direction, floorId);
+}
+
+maps.prototype._canMoveHero_checkPoint = function (x, y, direction, floorId, arrays) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return false;
+ arrays = arrays || this._generateMovableArray_arrays(floorId);
+
+ // 1. 检查该点 cannotMove
+ if (core.inArray((core.floors[floorId].cannotMove || {})[x + "," + y], direction))
+ return false;
+
+ var nx = x + core.utils.scan[direction].x, ny = y + core.utils.scan[direction].y;
+ if (nx < 0 || ny < 0 || nx >= core.floors[floorId].width || ny >= core.floors[floorId].height)
+ return false;
+
+ // 2. 检查下个点的 cannotMoveIn
+ if (core.inArray((core.floors[floorId].cannotMoveIn || {})[nx + "," + ny], core.turnDirection(":back", direction)))
+ return false;
+
+ // 3. 检查该点素材的 cannotOut 和下一个点的 cannotIn
+ if (this._canMoveHero_checkCannotInOut(Object.keys(arrays).map(function (name) { return arrays[name][y][x]; }), "cannotOut", direction))
+ return false;
+ if (this._canMoveHero_checkCannotInOut(Object.keys(arrays).map(function (name) { return arrays[name][ny][nx]; }), "cannotIn", direction))
+ return false;
+
+ // 4. 检查是否能进将死的领域
+ if (floorId == core.status.floorId && !core.flags.canGoDeadZone && !core.status.lockControl &&
+ Math.max(core.status.hero.hp, 1) <= ((core.status.checkBlock.damage || {})[nx + "," + ny] || 0) && arrays.eventArray[ny][nx] == 0)
+ return false;
+
+ return true;
+}
+
+maps.prototype._canMoveHero_checkCannotInOut = function (number, name, direction) {
+ if (number instanceof Array) {
+ for (var x in number) {
+ if (this._canMoveHero_checkCannotInOut(number[x], name, direction))
+ return true;
+ }
+ return false;
+ }
+ if (name == 'cannotIn') direction = core.turnDirection(":back", direction);
+ return core.inArray((this.getBlockByNumber(number).event || {})[name], direction);
+}
+
+////// 能否瞬间移动 //////
+maps.prototype.canMoveDirectly = function (destX, destY) {
+ return this.canMoveDirectlyArray([[destX, destY]])[0];
+}
+
+maps.prototype.canMoveDirectlyArray = function (locs, canMoveArray) {
+ var ans = [], number = locs.length;
+
+ var fromX = core.getHeroLoc('x'), fromY = core.getHeroLoc('y');
+ if (!this._canMoveDirectly_checkGlobal()) {
+ for (var i = 0; i < number; ++i) ans.push(-1);
+ return ans;
+ }
+ for (var i = 0; i < number; ++i) {
+ if (locs[i][0] == fromX && locs[i][1] == fromY) {
+ ans.push(0);
+ number--;
+ }
+ else if (locs[i][0] < 0 || locs[i][0] >= core.bigmap.width || locs[i][1] < 0 || locs[i][1] >= core.bigmap.height) {
+ ans.push(-1);
+ number--;
+ }
+ else ans.push(null);
+ }
+ if (number == 0) return ans;
+
+ // 检查起点事件
+ if (!this._canMoveDirectly_checkStartPoint(fromX, fromY)) {
+ for (var i in ans) {
+ if (ans[i] == null) ans[i] = -1;
+ }
+ return ans;
+ }
+
+ return this._canMoveDirectly_bfs(fromX, fromY, locs, number, ans, canMoveArray);
+}
+
+maps.prototype._canMoveDirectly_checkGlobal = function () {
+ // 检查全塔是否禁止瞬间移动
+ if (!core.flags.enableMoveDirectly) return false;
+ // 检查该楼层是否不可瞬间移动
+ if (core.status.thisMap.cannotMoveDirectly) return false;
+ // flag:cannotMoveDirectly为true:不能
+ if (core.hasFlag('cannotMoveDirectly')) return false;
+
+ return true;
+}
+
+maps.prototype._canMoveDirectly_checkStartPoint = function (sx, sy) {
+ if (core.status.checkBlock.damage[sx + "," + sy]) return false;
+ var block = core.getBlock(sx, sy);
+ if (block != null) {
+ // 只有起点是传送点才是能无视
+ return block.event.trigger == 'changeFloor';
+ }
+ return true;
+}
+
+maps.prototype._canMoveDirectly_bfs = function (sx, sy, locs, number, ans, canMoveArray) {
+ canMoveArray = canMoveArray || this.generateMovableArray();
+ var blocksObj = this.getMapBlocksObj();
+ // 滑冰
+ var bgMap = this.getBgMapArray();
+
+ var visited = [], queue = [];
+ visited[sx + "," + sy] = 0;
+ queue.push(sx + "," + sy);
+
+ while (queue.length > 0) {
+ var now = queue.shift().split(","), x = parseInt(now[0]), y = parseInt(now[1]);
+ for (var direction in core.utils.scan) {
+ if (!core.inArray(canMoveArray[x][y], direction)) continue;
+ var nx = x + core.utils.scan[direction].x, ny = y + core.utils.scan[direction].y, nindex = nx + "," + ny;
+ if (visited[nindex]) continue;
+ if (core.onSki(bgMap[ny][nx])) continue;
+ if (!this._canMoveDirectly_checkNextPoint(blocksObj, nx, ny)) continue;
+ visited[nindex] = visited[now] + 1;
+ // if (nx == ex && ny == ey) return visited[nindex];
+ for (var i in ans) {
+ if (locs[i][0] == nx && locs[i][1] == ny && ans[i] == null) {
+ // 不可以绿点为终点
+ var block = blocksObj[nx + "," + ny];
+ if (block && !block.disable && block.event.trigger) {
+ ans[i] = -1;
+ } else {
+ ans[i] = visited[nindex];
+ }
+ number--;
+ if (number == 0) return ans;
+ }
+ }
+ queue.push(nindex);
+ }
+ }
+
+ for (var i in ans) {
+ if (ans[i] == null) ans[i] = -1;
+ }
+ return ans;
+}
+
+maps.prototype._canMoveDirectly_checkNextPoint = function (blocksObj, x, y) {
+ var index = x + "," + y;
+ var block = blocksObj[index];
+ // 该点是否不可通行或有脚本
+ if (block && !block.disable && (block.event.noPass || block.event.script || block.event.event))
+ return false;
+ // 该点是否是绿点可触发
+ if (block && !block.disable && block.event.trigger) {
+ if (block.event.trigger != 'changeFloor') return false;
+ var ignore = core.flags.ignoreChangeFloor;
+ if (block.event.data && block.event.data.ignoreChangeFloor != null)
+ ignore = block.event.data.ignoreChangeFloor;
+ if (!ignore) return false;
+ }
+ // 是否存在阻激夹域伤害
+ if (core.status.checkBlock.damage[index]) return false;
+ if (core.status.checkBlock.repulse[index]) return false;
+ // 是否存在捕捉
+ if (core.status.checkBlock.ambush[index]) return false;
+
+ return true;
+}
+
+////// 自动寻路找寻最优路径 //////
+maps.prototype.automaticRoute = function (destX, destY) {
+ var startX = core.getHeroLoc('x'), startY = core.getHeroLoc('y');
+ if (destX == startX && destY == startY) return [];
+ // BFS找寻最短路径
+ var route = this._automaticRoute_bfs(startX, startY, destX, destY);
+ if (route[destX + "," + destY] == null) return [];
+ // 路径数组转换
+ var ans = [], nowX = destX, nowY = destY;
+ while (nowX != startX || nowY != startY) {
+ var dir = route[nowX + "," + nowY];
+ ans.push({ 'direction': dir, 'x': nowX, 'y': nowY });
+ nowX -= core.utils.scan[dir].x;
+ nowY -= core.utils.scan[dir].y;
+ }
+ ans.reverse();
+ return ans;
+}
+
+maps.prototype._automaticRoute_bfs = function (startX, startY, destX, destY) {
+ var route = {}, canMoveArray = this.generateMovableArray();
+ // 使用优先队列
+ var queue = new PriorityQueue({ comparator: function (a, b) { return a.depth - b.depth; } });
+ route[startX + "," + startY] = '';
+ queue.queue({ depth: 0, x: startX, y: startY });
+ var blocks = core.getMapBlocksObj();
+ while (queue.length != 0) {
+ var curr = queue.dequeue(), deep = curr.depth, nowX = curr.x, nowY = curr.y;
+ for (var direction in core.utils.scan) {
+ if (!core.inArray(canMoveArray[nowX][nowY], direction)) continue;
+ var nx = nowX + core.utils.scan[direction].x;
+ var ny = nowY + core.utils.scan[direction].y;
+ if (nx < 0 || nx >= core.bigmap.width || ny < 0 || ny >= core.bigmap.height || route[nx + "," + ny] != null) continue;
+ // 重点
+ if (nx == destX && ny == destY) {
+ route[nx + "," + ny] = direction;
+ break;
+ }
+ // 不可通行
+ if (core.noPass(nx, ny)) continue;
+ route[nx + "," + ny] = direction;
+ queue.queue({ depth: deep + this._automaticRoute_deepAdd(nx, ny, blocks), x: nx, y: ny });
+ }
+ if (route[destX + "," + destY] != null) break;
+ }
+ return route;
+}
+
+maps.prototype._automaticRoute_deepAdd = function (x, y, blocks) {
+ // 判定每个可通行点的损耗值,越高越应该绕路
+ var deepAdd = 1;
+ var block = blocks[x + "," + y];
+ if (block && !block.disable) {
+ var id = block.event.id;
+ // 绕过亮灯
+ if (id == "light") deepAdd += 100;
+ // 绕过路障
+ if (id.endsWith("Net") && !core.hasFlag(id.substring(0, id.length - 3))) deepAdd += 100;
+ // 绕过血瓶和绿宝石
+ if (core.hasFlag('__potionNoRouting__') && (id.endsWith("Potion") || id == 'greenGem')) deepAdd += 100;
+ // 绕过传送点
+ // if (block.event.trigger == 'changeFloor') deepAdd+=10;
+ }
+ // 绕过存在伤害的地方
+ deepAdd += (core.status.checkBlock.damage[x + "," + y] || 0) * 100;
+ // 绕过捕捉
+ if (core.status.checkBlock.ambush[x + "," + y]) deepAdd += 1000;
+ return deepAdd;
+}
+
+// -------- 绘制地图,各层图块,楼层贴图,Autotile -------- //
+
+maps.prototype._getBigImageInfo = function (bigImage, face, animate) {
+ face = face || "down";
+ if (["up", "down", "left", "right"].indexOf(face) < 0) face = "down";
+ var per_width = bigImage.width / 4;
+ var per_height = bigImage.height / 4;
+ var sx = animate * per_width, sy;
+ if (per_height <= per_width / 2) { // 强制视为 1*4 的怪物
+ per_height = bigImage.height;
+ sy = 0;
+ } else {
+ sy = core.material.icons.hero[face].loc * per_height;
+ }
+ var dx, dy;
+ switch (face) {
+ case "down": case "up": case "left": case "right": dx = 16 - per_width / 2; dy = 32 - per_height; break;
+ // case "left": dx = 0; dy = 32 - per_height; break;
+ // case "right": dx = 32 - per_width; dy = 32 - per_height; break;
+ }
+
+ return { sx: sx, sy: sy, per_width: per_width, per_height: per_height, face: face, dx: dx, dy: dy };
+}
+
+////// 绘制一个图块 //////
+maps.prototype.drawBlock = function (block, animate, ctx) {
+ if (block.event.id == 'none') return;
+ var redraw = animate != null;
+ if (!redraw) animate = 0;
+ var x = block.x, y = block.y;
+ // --- 在界面外的动画不绘制
+
+ // 判定是否绘制
+ if (core.bigmap.v2) {
+ var posX = core.bigmap.posX, posY = core.bigmap.posY;
+ if (x < posX - 1 || y < posY - 1 || x > posX + core._WIDTH_ || y > posY + core._HEIGHT_ + 1) { // +1 for 48 height
+ return;
+ }
+ } else {
+ if (redraw && block.event.animate > 1 &&
+ (32 * x < core.bigmap.offsetX - 64 || 32 * x > core.bigmap.offsetX + core._PX_ + 32
+ || 32 * y < core.bigmap.offsetY - 64 || 32 * y > core.bigmap.offsetY + core._PY_ + 32 + 16)) {
+ return;
+ }
+ }
+
+ var blockInfo = this.getBlockInfo(block);
+ if (blockInfo == null) return;
+ if (blockInfo.cls != 'tileset') blockInfo.posX = animate % blockInfo.animate;
+ blockInfo.opacity = block.opacity;
+ blockInfo.filter = block.filter;
+ if (!block.name)
+ this._drawBlockInfo(blockInfo, block.x, block.y, ctx);
+ else
+ this._drawBlockInfo_bgfg(blockInfo, block.name, block.x, block.y, ctx);
+}
+
+maps.prototype._drawBlockInfo_bigImage = function (blockInfo, x, y, ctx) {
+ var bigImageInfo = this._getBigImageInfo(blockInfo.bigImage, blockInfo.face, blockInfo.posX);
+ var per_width = bigImageInfo.per_width, per_height = bigImageInfo.per_height, sx = bigImageInfo.sx, sy = bigImageInfo.sy;
+ var bigImage = blockInfo.bigImage;
+
+ if (main.mode == 'editor') {
+ var px = 32 * x - 32 * core.bigmap.posX;
+ var py = 32 * y - 32 * core.bigmap.posY;
+ if (ctx == null) ctx = 'event';
+ core.clearMap(ctx, px, py, 32, 32);
+ core.drawImage(ctx, bigImage, sx, sy, per_width, per_height, px, py, 32, 32);
+ return;
+ }
+
+ var px = 32 * x - core.bigmap.offsetX;
+ var py = 32 * y - core.bigmap.offsetY;
+
+ // 上半部分 - 会遮挡勇士;z值高于event2,为51
+ var header = "_bigImage_header_" + x + "_" + y;
+ // 下半部分 - 会被勇士遮挡;z值高于event,为31
+ var body = "_bigImage_body_" + x + "_" + y;
+ var dx = bigImageInfo.dx, dy = bigImageInfo.dy;
+
+ switch (bigImageInfo.face) {
+ case "down": case "up": case "left": case "right":
+ core.createCanvas(header, px + dx, py + dy, per_width, -dy, 51);
+ this._drawBlockInfo_drawWithFilter(blockInfo, header, function () {
+ core.drawImage(header, bigImage, sx, sy, per_width, -dy, 0, 0, per_width, -dy);
+ });
+ core.createCanvas(body, px + dx, py, per_width, 32, 31);
+ this._drawBlockInfo_drawWithFilter(blockInfo, body, function () {
+ core.drawImage(body, bigImage, sx, sy - dy, per_width, 32, 0, 0, per_width, 32);
+ })
+ break;
+ /*case "left":
+ core.createCanvas(header, px + dx, py + dy, per_width, -dy, 51);
+ this._drawBlockInfo_drawWithFilter(blockInfo, header, function () {
+ core.drawImage(header, bigImage, sx, sy, per_width, -dy, 0, 0, per_width, -dy);
+ });
+ core.createCanvas(body, px + dx, py, per_width, 32, 31);
+ this._drawBlockInfo_drawWithFilter(blockInfo, body, function () {
+ core.drawImage(body, bigImage, sx, sy - dy, per_width, 32, 0, 0, per_width, 32);
+ });
+ break;
+ case "right":
+ core.createCanvas(header, px + dx, py + dy, per_width, -dy, 51);
+ this._drawBlockInfo_drawWithFilter(blockInfo, header, function () {
+ core.drawImage(header, bigImage, sx, sy, per_width, -dy, 0, 0, per_width, -dy);
+ });
+ core.createCanvas(body, px + dx, py, per_width, per_height / 2 + 16, 31);
+ this._drawBlockInfo_drawWithFilter(blockInfo, body, function () {
+ core.drawImage(body, bigImage, sx, sy - dy, per_width, 32, 0, 0, per_width, 32);
+ });
+ break;*/
+ }
+ if (core.dymCanvas[header]) {
+ core.dymCanvas[header].canvas.setAttribute('_ox', 32 * x + dx);
+ core.dymCanvas[header].canvas.setAttribute('_oy', 32 * y + dy);
+ }
+ if (core.dymCanvas[body]) {
+ core.dymCanvas[body].canvas.setAttribute('_ox', 32 * x + dx);
+ core.dymCanvas[body].canvas.setAttribute('_oy', 32 * y);
+ }
+}
+
+maps.prototype._drawBlockInfo_drawWithFilter = function (blockInfo, ctx, func) {
+ var alpha = null;
+ if (blockInfo.opacity != null) alpha = core.setAlpha(ctx, blockInfo.opacity);
+ core.setFilter(ctx, blockInfo.filter);
+ func();
+ core.setFilter(ctx, null);
+ if (alpha != null) core.setAlpha(ctx, alpha);
+}
+
+maps.prototype._drawBlockInfo = function (blockInfo, x, y, ctx) {
+ if (blockInfo.bigImage) return this._drawBlockInfo_bigImage(blockInfo, x, y, ctx);
+
+ var image = blockInfo.image, posX = blockInfo.posX, posY = blockInfo.posY, height = blockInfo.height;
+ var px = 32 * x - 32 * core.bigmap.posX;
+ var py = 32 * y - 32 * core.bigmap.posY;
+ if (ctx == null) ctx = 'event';
+
+ this._drawBlockInfo_drawWithFilter(blockInfo, ctx, function () {
+ core.clearMap(ctx, px, py, 32, 32);
+ core.drawImage(ctx, image, posX * 32, posY * height + height - 32, 32, 32, px, py, 32, 32);
+ });
+ if (height > 32) {
+ this._drawBlockInfo_drawWithFilter(blockInfo, 'event2', function () {
+ core.clearMap('event2', px, py + 32 - height, 32, height - 32);
+ core.drawImage('event2', image, posX * 32, posY * height, 32, height - 32, px, py + 32 - height, 32, height - 32);
+ });
+ }
+}
+
+maps.prototype._drawBlockInfo_bgfg = function (blockInfo, name, x, y, ctx) {
+ var image = blockInfo.image, posX = blockInfo.posX, posY = blockInfo.posY, height = blockInfo.height;
+ var px = 32 * x - 32 * core.bigmap.posX;
+ var py = 32 * y - 32 * core.bigmap.posY;
+ if (ctx == null) ctx = name;
+
+ core.clearMap(ctx, px, py + 32 - height, 32, height);
+ if (name == 'bg') {
+ if (height > 32) {
+ core.clearMap(ctx, px, py - 32, 32, 32);
+ core.drawImage(ctx, core.material.groundCanvas.canvas, px, py - 32);
+ }
+ core.drawImage(ctx, core.material.groundCanvas.canvas, px, py);
+ }
+ var alpha = null;
+ if (blockInfo.opacity != null) alpha = core.setAlpha(ctx, blockInfo.opacity);
+ else if (name == 'fg' && this._drawBlockInfo_shouldBlurFg(x, y)) alpha = core.setAlpha(ctx, 0.6);
+ core.setFilter(ctx, blockInfo.filter);
+ core.drawImage(ctx, image, posX * 32, posY * height, 32, height, px, py + 32 - height, 32, height);
+ core.setFilter(ctx, null);
+ if (alpha != null) core.setAlpha(ctx, alpha);
+}
+
+////// 是否应当存在事件时虚化前景层 //////
+maps.prototype._drawBlockInfo_shouldBlurFg = function (x, y) {
+ if (main.mode == 'play' && !core.flags.blurFg) return false;
+ var block = this.getBlock(x, y);
+ if (block == null || block.id == 0) return false;
+ if (block.event.cls == 'autotile' || block.event.cls == 'tileset') return block.event.script || block.event.event;
+ return true;
+}
+
+////// 生成groundPattern //////
+maps.prototype.generateGroundPattern = function (floorId) {
+ // 生成floorId层的groundPattern(盒子内的怪物动画)
+ var groundId = ((core.status.maps || core.floors)[floorId || core.status.floorId] || {}).defaultGround || "ground";
+ var groundInfo = core.getBlockInfo(groundId);
+ if (groundInfo == null) return;
+ core.material.groundCanvas.clearRect(0, 0, 32, 32);
+ core.material.groundCanvas.drawImage(groundInfo.image, 32 * groundInfo.posX, groundInfo.height * groundInfo.posY, 32, 32, 0, 0, 32, 32);
+ core.material.groundPattern = core.material.groundCanvas.createPattern(core.material.groundCanvas.canvas, 'repeat');
+ // 如果需要用纯色可以直接将下面代码改成改成
+ // core.material.groundPattern = '#000000';
+}
+
+////// 绘制某张地图 //////
+maps.prototype.drawMap = function (floorId) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return;
+ core.clearMap('all');
+ this.generateGroundPattern(floorId);
+ core.status.floorId = floorId;
+ core.extractBlocks(floorId);
+ core.status.thisMap = core.status.maps[floorId];
+
+ this._drawMap_drawAll();
+ if (core.status.curtainColor) {
+ core.fillRect('curtain', 0, 0, core._PX_, core._PY_, core.arrayToRGBA(core.status.curtainColor));
+ }
+ core.drawHero();
+ core.updateStatusBar();
+}
+
+////// 重绘某张地图 //////
+maps.prototype.redrawMap = function () {
+ core.bigmap.canvas.forEach(function (one) {
+ core.clearMap(one);
+ });
+ this._drawMap_drawAll(null, { redraw: true });
+ core.drawDamage();
+}
+
+maps.prototype._drawMap_drawAll = function (floorId, config) {
+ floorId = floorId || core.status.floorId;
+ this.drawBg(floorId, config);
+ this.drawEvents(floorId);
+ this.drawFg(floorId, config);
+}
+
+maps.prototype._drawMap_drawBlockInfo = function (ctx, block, blockInfo, arr, config) {
+ if (blockInfo == null) return;
+ var onMap = config.onMap;
+ if (onMap && core.bigmap.v2) {
+ // 判定是否绘制
+ var posX = core.bigmap.posX, posY = core.bigmap.posY;
+ if (block.x < posX - 1 || block.y < posY - 1 || block.x > posX + core._WIDTH_ || block.y > posY + core._HEIGHT_ + 1) { // +1 for 48 height
+ return;
+ }
+ }
+
+ if (blockInfo.cls == 'autotile') { // Autotile单独处理
+ var alpha = null;
+ if (block.opacity != null) alpha = core.setAlpha(ctx, block.opacity);
+ core.setFilter(ctx, block.filter);
+ this._drawAutotile(ctx, arr, block, 32, 0, 0, 0, onMap);
+ core.setFilter(ctx, null);
+ if (alpha != null) core.setAlpha(ctx, alpha);
+ if (onMap) this.addGlobalAnimate(block);
+ return;
+ }
+ if (!onMap) {
+ var height = blockInfo.height;
+ if (blockInfo.bigImage) {
+ config.postDraw.push(function () {
+ var bigImageInfo = core.maps._getBigImageInfo(blockInfo.bigImage, blockInfo.face, 0);
+ var per_width = bigImageInfo.per_width, per_height = bigImageInfo.per_height;
+ core.maps._drawBlockInfo_drawWithFilter(block, ctx, function () {
+ core.drawImage(ctx, blockInfo.bigImage, bigImageInfo.sx, bigImageInfo.sy, per_width, per_height,
+ 32 * block.x + bigImageInfo.dx, 32 * block.y + bigImageInfo.dy, per_width, per_height);
+ });
+ });
+ return;
+ }
+ this._drawBlockInfo_drawWithFilter(block, ctx, function () {
+ core.drawImage(ctx, blockInfo.image, 32 * blockInfo.posX, height * blockInfo.posY, 32, height, 32 * block.x, 32 * block.y + 32 - height, 32, height);
+ });
+ return;
+ }
+ this.drawBlock(block, null, ctx);
+ this.addGlobalAnimate(block);
+}
+
+////// 绘制背景层 //////
+// config:绘制的参数,可包含如下项:
+// redraw - 是否是重绘;ctx - 要绘制到的画布(仅限缩略图使用);
+maps.prototype.drawBg = function (floorId, config) {
+ floorId = floorId || core.status.floorId;
+ if (config == null) config = {};
+ if (typeof config == 'string' || config.canvas) config = { ctx: config };
+ config = Object.assign({}, config);
+ if (config.ctx == null) {
+ config.onMap = true;
+ config.ctx = 'bg';
+ core.clearMap('bg');
+ core.status.floorAnimateObjs = this._getFloorImages(floorId);
+ }
+ var toDrawCtx = core.getContextByName(config.ctx);
+ if (!toDrawCtx) return;
+
+ var cacheCtx = toDrawCtx;
+ if (config.onMap) {
+ cacheCtx = core.bigmap.cacheCanvas;
+ cacheCtx.canvas.width = toDrawCtx.canvas.width;
+ cacheCtx.canvas.height = toDrawCtx.canvas.height;
+ if (core.bigmap.v2) cacheCtx.translate(32, 32);
+ }
+ this._drawBg_draw(floorId, toDrawCtx, cacheCtx, config);
+ if (config.onMap) cacheCtx.translate(0, 0);
+}
+
+maps.prototype._drawBg_draw = function (floorId, toDrawCtx, cacheCtx, config) {
+ config.ctx = cacheCtx;
+ core.maps._drawBg_drawBackground(floorId, config);
+ // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。
+ core.maps._drawFloorImages(floorId, config.ctx, 'bg', null, null, config.onMap);
+ core.maps._drawBgFgMap(floorId, 'bg', config);
+ if (config.onMap) core.drawImage(toDrawCtx, cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0);
+ config.ctx = toDrawCtx;
+}
+
+maps.prototype._drawBg_drawBackground = function (floorId, config) {
+ var groundId = (core.status.maps || core.floors)[floorId].defaultGround || "ground";
+ var groundInfo = core.getBlockInfo(groundId);
+ var onMap = config.onMap;
+ if (groundInfo != null) {
+ var start = onMap && core.bigmap.v2 ? -1 : 0;
+ var endX = onMap && core.bigmap.v2 ? core._WIDTH_ + 1 : core.floors[floorId].width;
+ var endY = onMap && core.bigmap.v2 ? core._HEIGHT_ + 1 : core.floors[floorId].height;
+
+ var patternCanvas = document.createElement('canvas');
+ patternCanvas.width = patternCanvas.height = 32;
+ var patternCtx = patternCanvas.getContext('2d');
+ core.drawImage(patternCtx, groundInfo.image, 32 * groundInfo.posX, groundInfo.height * groundInfo.posY, 32, 32, 0, 0, 32, 32)
+
+ core.fillRect(config.ctx, 32 * start, 32 * start, 32 * (endX - start), 32 * (endY - start), patternCtx.createPattern(patternCanvas, 'repeat'));
+ }
+}
+
+////// 绘制事件层 //////
+maps.prototype.drawEvents = function (floorId, blocks, config) {
+ floorId = floorId || core.status.floorId;
+ if (config == null) config = {};
+ if (typeof config == 'string' || config.canvas) config = { ctx: config };
+ config = Object.assign({}, config);
+ if (config.ctx == null) {
+ config.onMap = true;
+ config.ctx = 'event';
+ core.clearMap('event');
+ core.clearMap('event2');
+ }
+ var toDrawCtx = core.getContextByName(config.ctx);
+ if (!toDrawCtx) return;
+
+ var cacheCtx = toDrawCtx;
+ if (config.onMap) {
+ cacheCtx = core.bigmap.cacheCanvas;
+ cacheCtx.canvas.width = toDrawCtx.canvas.width;
+ cacheCtx.canvas.height = toDrawCtx.canvas.height;
+ if (core.bigmap.v2) cacheCtx.translate(32, 32);
+ }
+
+ var arr = null;
+ if (!blocks) {
+ core.extractBlocks(floorId);
+ blocks = core.status.maps[floorId].blocks;
+ arr = this.getMapArray(floorId, !config.redraw)
+ } else {
+ arr = this._getMapArrayFromBlocks(blocks, core.floors[floorId].width, core.floors[floorId].height);
+ }
+ config.postDraw = [];
+
+ blocks.filter(function (block) {
+ if (config.onMap && core.bigmap.v2) {
+ // 判定是否绘制
+ var posX = core.bigmap.posX, posY = core.bigmap.posY;
+ if (block.x < posX - 1 || block.y < posY - 1 || block.x > posX + core._WIDTH_ || block.y > posY + core._HEIGHT_ + 1) { // +1 for 48 height
+ return false;
+ }
+ }
+ return block.event && !block.disable;
+ }).forEach(function (block) {
+ core.maps._drawMap_drawBlockInfo(cacheCtx, block, core.maps.getBlockInfo(block), arr, config);
+ });
+ config.postDraw.forEach(function (v) { v(); });
+ delete config.postDraw;
+
+ if (config.onMap) {
+ core.drawImage(toDrawCtx, cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0);
+ cacheCtx.translate(0, 0);
+ }
+}
+
+////// 绘制前景层 //////
+// config:绘制的参数,可包含如下项:
+// redraw - 是否是重绘;ctx - 要绘制到的画布(仅限缩略图使用);
+maps.prototype.drawFg = function (floorId, config) {
+ floorId = floorId || core.status.floorId;
+ if (config == null) config = {};
+ if (typeof config == 'string' || config.canvas) config = { ctx: config };
+ config = Object.assign({}, config);
+ if (config.ctx == null) {
+ config.onMap = true;
+ config.ctx = 'fg';
+ core.clearMap('fg');
+ }
+ var toDrawCtx = core.getContextByName(config.ctx);
+ if (!toDrawCtx) return;
+
+ var cacheCtx = toDrawCtx;
+ if (config.onMap) {
+ cacheCtx = core.bigmap.cacheCanvas;
+ cacheCtx.canvas.width = toDrawCtx.canvas.width;
+ cacheCtx.canvas.height = toDrawCtx.canvas.height;
+ if (core.bigmap.v2) cacheCtx.translate(32, 32);
+ }
+ this._drawFg_draw(floorId, toDrawCtx, cacheCtx, config);
+ if (config.onMap) cacheCtx.translate(0, 0);
+}
+
+maps.prototype._drawFg_draw = function (floorId, toDrawCtx, cacheCtx, config) {
+ config.ctx = cacheCtx;
+ // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制前景图块;后绘制的覆盖先绘制的。
+ core.maps._drawFloorImages(floorId, config.ctx, 'fg', null, null, config.onMap);
+ core.maps._drawBgFgMap(floorId, 'fg', config);
+ if (config.onMap) core.drawImage(toDrawCtx, cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0);
+ config.ctx = toDrawCtx;
+}
+
+////// 实际的背景/前景图块的绘制 //////
+maps.prototype._drawBgFgMap = function (floorId, name, config) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return;
+ var width = core.floors[floorId].width;
+ var height = core.floors[floorId].height;
+
+ if (!core.status[name + "maps"])
+ core.status[name + "maps"] = {};
+
+ var startX = config.onMap && core.bigmap.v2 ? Math.max(0, core.bigmap.posX - 1) : 0;
+ var endX = config.onMap && core.bigmap.v2 ? Math.min(width, core.bigmap.posX + core._WIDTH_ + 1) : width;
+ var startY = config.onMap && core.bigmap.v2 ? Math.max(0, core.bigmap.posY - 1) : 0;
+ var endY = config.onMap && core.bigmap.v2 ? Math.min(height, core.bigmap.posY + core._HEIGHT_ + 2) : height;
+
+ var arr = this._getBgFgMapArray(name, floorId, !config.redraw);
+ config.postDraw = [];
+ for (var x = startX; x < endX; x++) {
+ for (var y = startY; y < endY; y++) {
+ if (arr[y][x] == 0) continue;
+ var block = this.initBlock(x, y, arr[y][x], true);
+ block.name = name;
+ var blockInfo = this.getBlockInfo(block);
+ if (!blockInfo) continue;
+ this._drawMap_drawBlockInfo(config.ctx, block, blockInfo, arr, config);
+ }
+ }
+ config.postDraw.forEach(function (v) { v(); });
+ delete config.postDraw;
+}
+
+////// 绘制楼层贴图 //////
+maps.prototype._drawFloorImages = function (floorId, ctx, name, images, currStatus, onMap) {
+ floorId = floorId || core.status.floorId;
+ if (!images) images = this._getFloorImages(floorId);
+ var redraw = currStatus != null;
+ images.forEach(function (one) {
+ var image = core.material.images.images[core.getMappedName(one.name)];
+ var frame = one.frame || 1;
+ if (!image) return;
+ var flag = "__floorImg__" + floorId + "_" + one.x + "_" + one.y;
+ if (core.hasFlag(flag)) return;
+ if (redraw && frame == 1) return; // 不重绘
+
+ if (/.*\.gif/i.test(one.name)) {
+ if (redraw) return;
+ this._drawFloorImages_gif(image, one.x, one.y);
+ return;
+ }
+ this._drawFloorImage(ctx, name, one, image, currStatus, onMap);
+ }, this);
+}
+
+maps.prototype._getFloorImages = function (floorId) {
+ return ((core.status.maps || core.floors)[floorId || core.status.floorId] || {}).images || [];
+}
+
+maps.prototype._drawFloorImages_gif = function (image, dx, dy) {
+ core.dom.gif.innerHTML = "";
+ var gif = new Image();
+ gif.src = image.src;
+ gif.style.position = 'absolute';
+ gif.style.left = (dx * core.domStyle.scale) + "px";
+ gif.style.top = (dy * core.domStyle.scale) + "px";
+ gif.style.width = image.width * core.domStyle.scale + "px";
+ gif.style.height = image.height * core.domStyle.scale + "px";
+ core.dom.gif.appendChild(gif);
+ return;
+}
+
+maps.prototype._drawFloorImage = function (ctx, name, one, image, currStatus, onMap) {
+ var height = image.height;
+ var imageName = one.name + (one.reverse || '');
+ var width = parseInt((one.w == null ? image.width : one.w) / (one.frame || 1));
+ var height = one.h == null ? image.height : one.h;
+ var sx = (one.sx || 0) + (currStatus || 0) % (one.frame || 1) * width;
+ var sy = one.sy || 0;
+ var x = one.x || 0, y = one.y || 0;
+ if (onMap && core.bigmap.v2) {
+ if (x > 32 * core.bigmap.posX + core._PX_ + 32 || x + width < 32 * core.bigmap.posX - 32
+ || y > 32 * core.bigmap.posX + core._PY_ + 32 || y + height < 32 * core.bigmap.posY - 32) {
+ return;
+ }
+ x -= 32 * core.bigmap.posX;
+ y -= 32 * core.bigmap.posY;
+ }
+
+ if (one.canvas != 'auto' && one.canvas != name) return;
+ if (one.canvas != 'auto') {
+ if (currStatus != null) core.clearMap(ctx, x, y, width, height);
+ core.drawImage(ctx, imageName, sx, sy, width, height, x, y, width, height);
+ } else {
+ if (name == 'bg') {
+ if (currStatus != null) core.clearMap(ctx, x, y + height - 32, width, 32);
+ core.drawImage(ctx, imageName, sx, sy + height - 32, width, 32, x, y + height - 32, width, 32);
+ } else if (name == 'fg') {
+ if (currStatus != null) core.clearMap(ctx, x, y, width, height - 32);
+ core.drawImage(ctx, imageName, sx, sy, width, height - 32, x, y, width, height - 32);
+ }
+ }
+}
+
+////// 绘制Autotile //////
+
+
+maps.prototype._drawAutotile = function (ctx, mapArr, block, size, left, top, status, onMap) {
+ var xx = block.x, yy = block.y;
+ var autotile = core.material.images['autotile'][block.event.id];
+ status = status || 0;
+ status %= parseInt(autotile.width / 96);
+ var done = {};
+ var isGrass = function (x, y) {
+ if (core.maps._drawAutotile_getAutotileAroundId(mapArr[yy][xx], x, y, mapArr)) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ var iG = [];
+ [-1, 0, 1].forEach(function (_x) {
+ iG[_x] = [];
+ [-1, 0, 1].forEach(function (_y) {
+ iG[_x][_y] = isGrass(xx + _x, yy + _y);
+ })
+ });
+ if (iG[-1][-1] + iG[0][-1] + iG[0][0] + iG[-1][0] == 3 && !iG[-1][-1]) {
+ this._drawAutotile_render(ctx, xx * size + left, yy * size + top, size, autotile, status, 16, null, onMap);
+ done[0] = true;
+ }
+ if (iG[0][-1] + iG[1][-1] + iG[1][0] + iG[0][0] == 3 && !iG[1][-1]) {
+ this._drawAutotile_render(ctx, xx * size + left + size / 2, yy * size + top, size, autotile, status, 17, null, onMap);
+ done[1] = true;
+ }
+ if (iG[0][0] + iG[1][0] + iG[1][1] + iG[0][1] == 3 && !iG[1][1]) {
+ this._drawAutotile_render(ctx, xx * size + left + size / 2, yy * size + top + size / 2, size, autotile, status, 18, null, onMap);
+ done[3] = true;
+ }
+ if (iG[0 - 1][0] + iG[0][0] + iG[0][1] + iG[-1][1] == 3 && !iG[-1][1]) {
+ this._drawAutotile_render(ctx, xx * size + left, yy * size + top + size / 2, size, autotile, status, 19, null, onMap);
+ done[2] = true;
+ }
+ var _id = iG[0][-1] + 2 * iG[-1][0] + 4 * iG[0][1] + 8 * iG[1][0];
+
+ this._drawAutotile_render(ctx, xx * size, yy * size, size, autotile, status, _id, done, onMap);
+}
+
+
+maps.prototype._drawAutotile_render = function (canvas, x, y, size, autotile, status, index, done, onMap) {
+ if (onMap) {
+ x -= 32 * core.bigmap.posX;
+ y -= 32 * core.bigmap.posY;
+ }
+ var indexData = [[[96 * status, 0, 32, 32, x, y, size, size],],
+ [[96 * status, 3 * 32, 16, 32, x, y, size / 2, size], [96 * status + 2 * 32 + 16, 3 * 32, 16, 32, x + size / 2, y, size / 2, size],],
+ [[96 * status + 2 * 32, 32, 32, 16, x, y, size, size / 2], [96 * status + 2 * 32, 3 * 32 + 16, 32, 16, x, y + size / 2, size, size / 2],],
+ [[96 * status + 2 * 32, 3 * 32, 32, 32, x, y, size, size],],
+ [[96 * status, 32, 16, 32, x, y, size / 2, size], [96 * status + 2 * 32 + 16, 32, 16, 32, x + size / 2, y, size / 2, size],],
+ [[96 * status, 2 * 32, 16, 32, x, y, size / 2, size], [96 * status + 2 * 32 + 16, 2 * 32, 16, 32, x + size / 2, y, size / 2, size],],
+ [[96 * status + 2 * 32, 32, 32, 32, x, y, size, size],],
+ [[96 * status + 2 * 32, 2 * 32, 32, 32, x, y, size, size],],
+ [[96 * status, 32, 32, 16, x, y, size, size / 2], [96 * status, 3 * 32 + 16, 32, 16, x, y + size / 2, size, size / 2],],
+ [[96 * status, 3 * 32, 32, 32, x, y, size, size],],
+ [[96 * status + 32, 32, 32, 16, x, y, size, size / 2], [96 * status + 32, 3 * 32 + 16, 32, 16, x, y + size / 2, size, size / 2],],
+ [[96 * status + 32, 3 * 32, 32, 32, x, y, size, size],],
+ [[96 * status, 32, 32, 32, x, y, size, size],],
+ [[96 * status, 2 * 32, 32, 32, x, y, size, size],],
+ [[96 * status + 32, 32, 32, 32, x, y, size, size],],
+ [[96 * status + 32, 2 * 32, 32, 32, x, y, size, size],],
+ [[96 * status + 2 * 32, 0, 16, 16, x, y, size / 2, size / 2],],
+ [[96 * status + 2 * 32 + 16, 0, 16, 16, x, y, size / 2, size / 2],],
+ [[96 * status + 2 * 32 + 16, 16, 16, 16, x, y, size / 2, size / 2],],
+ [[96 * status + 2 * 32, 16, 16, 16, x, y, size / 2, size / 2],],
+ ];
+ var data = indexData[index];
+ if (index >= 16) { // 拐角直接绘制
+ core.drawImage(canvas, autotile, data[0][0], data[0][1], data[0][2], data[0][3], data[0][4], data[0][5], size / 2, size / 2);
+ } else { // 非拐角要根据是否已经绘制进行切分后绘制
+ this._drawAutotile_renderCut(canvas, autotile, x, y, size, data, done);
+ }
+}
+
+maps.prototype._drawAutotile_renderCut = function (canvas, autotile, x, y, size, data, done) {
+ var drawData = [];
+ done = done || {};
+ if (data.length == 2) {
+ var idx = 0;
+ var cut = 0;
+ for (var i in data) {
+ if (data[i][2] % 32) { // 是否纵切
+ cut = 0;
+ }
+ else if (data[i][3] % 32) { // 是否横切
+ cut = 1;
+ }
+ if (data[i][0] % 32 || data[i][1] % 32) { // right down
+ idx = 1;
+ } else { // left top
+ idx = 0;
+ }
+ if (cut) {
+ idx *= 2;
+ if (!done[idx]) drawData[idx] = [data[i][0], data[i][1]];
+ if (!done[idx + 1]) drawData[idx + 1] = [parseInt(data[i][0]) + 16, data[i][1]];
+ } else {
+ if (!done[idx]) drawData[idx] = [data[i][0], data[i][1]];
+ if (!done[idx + 2]) drawData[idx + 2] = [data[i][0], parseInt(data[i][1]) + 16];
+ }
+ }
+ } else {
+ if (!done[0]) drawData[0] = [data[0][0], data[0][1]];
+ if (!done[1]) drawData[1] = [data[0][0] + 16, data[0][1]];
+ if (!done[2]) drawData[2] = [data[0][0], data[0][1] + 16];
+ if (!done[3]) drawData[3] = [data[0][0] + 16, data[0][1] + 16];
+ }
+ for (var i = 0; i < 4; i++) {
+ var dt = drawData[i]; if (!dt) continue;
+ core.drawImage(canvas, autotile, dt[0], dt[1], 16, 16, x + (i % 2) * size / 2, y + parseInt(i / 2) * size / 2, size / 2, size / 2);
+ };
+}
+
+
+maps.prototype._drawAutotile_drawBlockByIndex = function (ctx, dx, dy, autotileImg, index, size, status) {
+ //index为autotile的图块索引1-48
+ var sx = 16 * ((index - 1) % 6), sy = 16 * (~~((index - 1) / 6));
+ status = status || 0;
+ status %= parseInt(autotileImg.width / 96);
+ core.drawImage(ctx, autotileImg, sx + 96 * status, sy, 16, 16, dx, dy, size / 2, size / 2);
+}
+
+maps.prototype._drawAutotile_getAutotileAroundId = function (currId, x, y, mapArr) {
+ if (x < 0 || y < 0 || x >= mapArr[0].length || y >= mapArr.length) return 1;
+ else return (core.material.autotileEdges[currId] || []).indexOf(mapArr[y][x]) >= 0;
+}
+
+maps.prototype._drawAutotile_checkAround = function (x, y, mapArr) {
+ // 得到周围四个32*32块(周围每块都包含当前块的1/4,不清楚的话画下图你就明白)的数组索引
+ var currId = mapArr[y][x];
+ var pointBlock = [];
+ for (var i = 0; i < 4; i++) {
+ var bsum = 0;
+ var offsetx = i % 2, offsety = ~~(i / 2);
+ for (var j = 0; j < 4; j++) {
+ var mx = j % 2, my = ~~(j / 2);
+ var b = this._drawAutotile_getAutotileAroundId(currId, x + offsetx + mx - 1, y + offsety + my - 1, mapArr);
+ bsum += b * (Math.pow(2, 3 - j));
+ }
+ pointBlock.push(bsum);
+ }
+ return pointBlock;
+}
+
+maps.prototype._drawAutotile_getAutotileIndexs = function (x, y, mapArr, indexArrs) {
+ var indexArr = [];
+ var pointBlocks = this._drawAutotile_checkAround(x, y, mapArr);
+ for (var i = 0; i < 4; i++) {
+ var arr = indexArrs[pointBlocks[i]]
+ indexArr.push(arr[3 - i]);
+ }
+ return indexArr;
+}
+
+maps.prototype._drawAutotileAnimate = function (block, animate) {
+ var x = block.x, y = block.y;
+ // ------ 界面外的动画不绘制
+ if (core.bigmap.v2) {
+ var posX = core.bigmap.posX, posY = core.bigmap.posY;
+ if (x < posX - 1 || y < posY - 1 || x > posX + core._WIDTH_ || y > posY + core._HEIGHT_) {
+ return;
+ }
+ } else {
+ if (32 * x < core.bigmap.offsetX - 64 || 32 * x > core.bigmap.offsetX + core._PX_ + 32
+ || 32 * y < core.bigmap.offsetY - 64 || 32 * y > core.bigmap.offsetY + core._PY_ + 32 + 16) {
+ return;
+ }
+ }
+
+ var cv = block.name ? core.canvas[block.name] : core.canvas.event;
+ cv.clearRect(32 * x - 32 * core.bigmap.posX, 32 * y - 32 * core.bigmap.posY, 32, 32);
+ var alpha = null;
+ if (block.opacity != null) alpha = core.setAlpha(cv, block.opacity);
+ core.setFilter(cv, block.filter);
+ if (block.name) {
+ if (block.name == 'bg')
+ core.drawImage('bg', core.material.groundCanvas.canvas, 32 * x - 32 * core.bigmap.posX, 32 * y - 32 * core.bigmap.posY);
+ this._drawAutotile(cv, this._getBgFgMapArray(block.name), block, 32, 0, 0, animate, true);
+ }
+ else {
+ this._drawAutotile(cv, this.getMapArray(), block, 32, 0, 0, animate, true);
+ }
+ core.setFilter(cv, null);
+ if (alpha != null) core.setAlpha(cv, alpha);
+}
+
+////// 为autotile判定边界 //////
+maps.prototype._makeAutotileEdges = function () {
+ var autotileIds = Object.keys(core.material.images.autotile);
+ core.material.autotileEdges = {};
+
+ var canvas = document.createElement("canvas"), ctx = canvas.getContext('2d');
+ canvas.width = canvas.height = 32;
+ ctx.mozImageSmoothingEnabled = false;
+ ctx.webkitImageSmoothingEnabled = false;
+ ctx.msImageSmoothingEnabled = false;
+ ctx.imageSmoothingEnabled = false;
+
+ var first = {}, second = {};
+ autotileIds.forEach(function (t) {
+ var n = core.maps.getNumberById(t);
+ core.clearMap(ctx, 0, 0, 32, 32);
+ core.drawImage(ctx, core.material.images.autotile[t], 0, 0, 32, 32, 0, 0, 32, 32);
+ first[n] = canvas.toDataURL("image/png");
+ core.clearMap(ctx, 0, 0, 32, 32);
+ core.drawImage(ctx, core.material.images.autotile[t], 32, 0, 32, 32, 0, 0, 32, 32);
+ second[n] = canvas.toDataURL("image/png");
+ });
+
+ for (var n in first) {
+ n = parseInt(n);
+ core.material.autotileEdges[n] = [n];
+ for (var n2 in second) {
+ n2 = parseInt(n2);
+ if (n == n2) continue;
+ if (first[n] == second[n2]) {
+ core.material.autotileEdges[n].push(n2);
+ }
+ }
+ }
+}
+
+////// 绘制缩略图 //////
+// 此函数将绘制一个缩略图,floorId为目标floorId,blocks为地图的图块(可为null使用floorId对应默认的)
+// options为绘制选项(可为null),包括:
+// heroLoc: 勇士位置;heroIcon:勇士图标(默认当前勇士);damage:是否绘制显伤;flags:当前的flags(存读档时使用)
+// ctx:要绘制到的画布(名);x,y:起点横纵坐标(默认0);size:大小(默认416/480);
+// all:是否绘制全图(默认false);centerX,centerY:截取中心(默认为地图正中心)
+// noHD:不使用高清绘制,避免存读档界面出问题
+maps.prototype.drawThumbnail = function (floorId, blocks, options) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return;
+ options = options || {};
+ if (typeof options == 'string' || options.canvas) options = { ctx: options };
+ var ctx = options.ctx;
+ // Step1:绘制到tempCanvas上
+ this._drawThumbnail_drawTempCanvas(floorId, blocks, options);
+ options.ctx = ctx;
+ // Step2:从tempCanvas绘制到对应的画布上
+ this._drawThumbnail_drawToTarget(floorId, options);
+}
+
+maps.prototype._drawThumbnail_drawTempCanvas = function (floorId, blocks, options) {
+ var width = core.floors[floorId].width;
+ var height = core.floors[floorId].height;
+ // 绘制到tempCanvas上面
+ var tempCanvas = core.bigmap.tempCanvas;
+
+ // 如果是大地图模式?
+ if (options.all) {
+ // 计算比例
+ if (options.noHD) {
+ tempCanvas.canvas.width = width * 32;
+ tempCanvas.canvas.height = height * 32;
+ tempCanvas.canvas.removeAttribute('isHD');
+ } else {
+ core.maps._setHDCanvasSize(tempCanvas, width * 32, height * 32);
+ }
+ } else if (width * height > core.bigmap.threshold) {
+ options.v2 = true;
+ if (options.noHD) {
+ tempCanvas.canvas.width = core._PX_;
+ tempCanvas.canvas.height = core._PY_;
+ tempCanvas.canvas.removeAttribute('isHD');
+ } else core.maps._setHDCanvasSize(tempCanvas, width * 32, height * 32);
+ var centerX = options.centerX, centerY = options.centerY;
+ if (centerX == null) centerX = Math.floor(width / 2);
+ if (centerY == null) centerY = Math.floor(height / 2);
+ var offsetX = core.clamp(centerX - core._HALF_WIDTH_, 0, width - core._WIDTH_),
+ offsetY = core.clamp(centerY - core._HALF_HEIGHT_, 0, height - core._HEIGHT_);
+ tempCanvas.translate(-32 * offsetX, -32 * offsetY, false, true);
+ } else {
+ options.v2 = false;
+ if (options.noHD) {
+ tempCanvas.canvas.width = width * 32;
+ tempCanvas.canvas.height = height * 32;
+ tempCanvas.canvas.removeAttribute('isHD');
+ } else core.maps._setHDCanvasSize(tempCanvas, width * 32, height * 32);
+ }
+ options.ctx = tempCanvas;
+
+ // 地图过大的缩略图不绘制显伤
+ if (width * height > core.bigmap.threshold)
+ options.damage = false;
+
+ // --- 暂存 flags
+ var hasHero = core.status.hero != null, flags = null;
+ if (options.flags) {
+ if (!hasHero) core.status.hero = {};
+ flags = core.status.hero.flags;
+ core.status.hero.flags = options.flags;
+ }
+
+ this._drawThumbnail_realDrawTempCanvas(floorId, blocks, options);
+
+ // --- 恢复 flags
+ if (!hasHero) delete core.status.hero;
+ else if (flags != null) core.status.hero.flags = flags;
+ tempCanvas.setTransform(1, 0, 0, 1, 0, 0);
+}
+
+maps.prototype._drawThumbnail_realDrawTempCanvas = function (floorId, blocks, options) {
+ // 缩略图:背景
+ this.drawBg(floorId, options);
+ // 缩略图:事件
+ this.drawEvents(floorId, blocks, options);
+ // 缩略图:勇士
+ if (options.heroLoc) {
+ options.heroIcon = options.heroIcon || core.status.hero.image || 'hero.png';
+ options.heroIcon = core.getMappedName(options.heroIcon);
+ var icon = core.material.icons.hero[options.heroLoc.direction];
+ var height = core.material.images.images[options.heroIcon].height / 4;
+ var width = (core.material.images.images[options.heroIcon].width || 128) / 4;
+ core.drawImage(options.ctx, core.material.images.images[options.heroIcon], icon.stop * width, icon.loc * height, width, height,
+ 32 * options.heroLoc.x + 32 - width, 32 * options.heroLoc.y + 32 - height, width, height);
+ }
+ // 缩略图:前景
+ this.drawFg(floorId, options);
+ // 缩略图:显伤
+ if (options.damage && core.hasItem('book')) {
+ core.updateCheckBlock(floorId);
+ core.control.updateDamage(floorId, options.ctx);
+ }
+}
+
+maps.prototype._drawThumbnail_drawToTarget = function (floorId, options) {
+ var ctx = core.getContextByName(options.ctx);
+ if (ctx == null) return;
+ var x = options.x || 0, y = options.y || 0, size = options.size || 1;
+ // size的含义改为(0,1]范围的系数以适配长方形,默认为1,楼传为3/4,SL界面为0.3
+ var w = Math.ceil(size * core._PX_), h = Math.ceil(size * core._PY_);
+ // 特判是否为编辑器,编辑器中长宽均采用core.js的遗留正方形像素边长,以保证下面的绘制正常
+ if (main.mode == 'editor') w = h = size * core.__PIXELS__;
+ var width = core.floors[floorId].width, height = core.floors[floorId].height;
+ var centerX = options.centerX, centerY = options.centerY;
+ if (centerX == null) centerX = Math.floor(width / 2);
+ if (centerY == null) centerY = Math.floor(height / 2);
+ var tempCanvas = core.bigmap.tempCanvas;
+
+ const scale = core.domStyle.scale * devicePixelRatio;
+ if (options.all) {
+ var tempWidth = tempCanvas.canvas.width, tempHeight = tempCanvas.canvas.height;
+ // 绘制全景图
+ if (tempWidth <= tempHeight) {
+ var realHeight = h, realWidth = realHeight * tempWidth / tempHeight;
+ var side = (w - realWidth) / 2;
+ core.fillRect(ctx, x, y, side, realHeight, '#000000');
+ core.fillRect(ctx, x + w - side, y, side, realHeight);
+ core.drawImage(ctx, tempCanvas.canvas, 0, 0, tempWidth, tempHeight, x + side, y, realWidth, realHeight);
+ }
+ else {
+ var realWidth = w, realHeight = realWidth * tempHeight / tempWidth;
+ var side = (h - realHeight) / 2;
+ core.fillRect(ctx, x, y, realWidth, side, '#000000');
+ core.fillRect(ctx, x, y + h - side, realWidth, side);
+ core.drawImage(ctx, tempCanvas.canvas, 0, 0, tempWidth, tempHeight, x, y + side, realWidth, realHeight);
+ }
+ }
+ else {
+ // 只绘制可见窗口
+ var pw = core._PX_,
+ ph = core._PY_,
+ hw = core._HALF_WIDTH_,
+ hh = core._HALF_HEIGHT_,
+ W = core._WIDTH_,
+ H = core._HEIGHT_;
+ if (main.mode == 'editor') {
+ pw = ph = core.__PIXELS__;
+ hw = hh = core.__HALF_SIZE__;
+ W = H = core.__SIZE__;
+ }
+ if (options.v2) {
+ if (options.noHD) core.drawImage(ctx, tempCanvas.canvas, 0, 0, pw, ph, x, y, w, h);
+ else core.drawImage(ctx, tempCanvas.canvas, 0, 0, pw * scale, ph * scale, x, y, w, h);
+ } else {
+ var offsetX = core.clamp(centerX - hw, 0, width - W),
+ offsetY = core.clamp(centerY - hh, 0, height - H);
+ if (options.noHD) {
+ core.drawImage(ctx, tempCanvas.canvas, offsetX * 32, offsetY * 32, pw, ph, x, y, w, h);
+ } else {
+ core.drawImage(ctx, tempCanvas.canvas, offsetX * 32 * scale, offsetY * 32 * scale, pw * scale, ph * scale, x, y, w, h);
+ }
+ }
+ }
+}
+
+// -------- 获得某个点的图块信息 -------- //
+
+////// 某个点是否不可通行 //////
+maps.prototype.noPass = function (x, y, floorId) {
+ var block = core.getBlock(x, y, floorId);
+ if (block == null) return false;
+ return block.event.noPass;
+}
+
+////// 某个点是否存在NPC //////
+maps.prototype.npcExists = function (x, y, floorId) {
+ var block = this.getBlock(x, y, floorId);
+ if (block == null) return false;
+ return block.event.cls.indexOf('npc') == 0;
+}
+
+////// 某个点是否存在(指定的)地形 //////
+maps.prototype.terrainExists = function (x, y, id, floorId) {
+ var block = this.getBlock(x, y, floorId);
+ if (block == null) return false;
+ return block.event.cls == 'terrains' && (id ? block.event.id == id : true);
+}
+
+////// 某个点是否存在楼梯 //////
+maps.prototype.stairExists = function (x, y, floorId) {
+ var blockId = this.getBlockId(x, y, floorId);
+ if (blockId == null) return false;
+ var ids = ['upFloor', 'downFloor'];
+ ids = ids.concat(['leftPortal', 'rightPortal', 'upPortal', 'downPortal', 'portal', 'starPortal']);
+ return ids.indexOf(blockId) >= 0;
+}
+
+////// 当前位置是否在楼梯边 //////
+maps.prototype.nearStair = function () {
+ var x = core.getHeroLoc('x'), y = core.getHeroLoc('y');
+ return this.stairExists(x, y) || this.stairExists(x - 1, y) || this.stairExists(x, y - 1) || this.stairExists(x + 1, y) || this.stairExists(x, y + 1);
+}
+
+////// 某个点是否存在(指定的)怪物 //////
+maps.prototype.enemyExists = function (x, y, id, floorId) {
+ var block = this.getBlock(x, y, floorId);
+ if (block == null) return false;
+ return block.event.cls.indexOf('enemy') == 0 && (id ? block.event.id == id : true);
+}
+
+////// 获得某个点的block //////
+maps.prototype.getBlock = function (x, y, floorId, showDisable) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return null;
+ core.extractBlocks(floorId);
+ var blockObjs = this.getMapBlocksObj(floorId);
+ var block = blockObjs[x + "," + y];
+ if (block && (showDisable || !block.disable)) return block;
+ return null;
+}
+
+////// 获得某个点的blockId //////
+maps.prototype.getBlockId = function (x, y, floorId, showDisable) {
+ var block = core.getBlock(x, y, floorId, showDisable);
+ return block == null ? null : block.event.id;
+}
+
+////// 获得某个点的数字 //////
+maps.prototype.getBlockNumber = function (x, y, floorId, showDisable) {
+ var block = core.getBlock(x, y, floorId, showDisable);
+ return block == null ? null : block.id;
+}
+
+////// 获得某个点的blockCls //////
+maps.prototype.getBlockCls = function (x, y, floorId, showDisable) {
+ var block = core.getBlock(x, y, floorId, showDisable);
+ return block == null ? null : block.event.cls;
+}
+
+////// 获得某个点的不透明度 //////
+maps.prototype.getBlockOpacity = function (x, y, floorId, showDisable) {
+ var block = core.getBlock(x, y, floorId, showDisable);
+ if (block == null) return null;
+ if (block.opacity == null) return 1.0;
+ return block.opacity == null ? 1.0 : block.opacity;
+}
+
+////// 获得某个点的filter //////
+maps.prototype.getBlockFilter = function (x, y, floorId, showDisable) {
+ var block = core.getBlock(x, y, floorId, showDisable);
+ if (block == null) return null;
+ if (block.filter == null) return { blur: 0, hue: 0, grayscale: 0, invert: false, shadow: 0 };
+ return core.clone(block.filter);
+}
+
+////// 获得某个图块或素材的信息,包括 ID,cls,图片,坐标,faceIds 等等 //////
+maps.prototype.getBlockInfo = function (block) {
+ if (!block) return null;
+ if (typeof block == 'string') { // 参数是ID
+ block = this.getNumberById(block);
+ }
+ if (typeof block == 'number') { // 参数是数字
+ if (block == 0) return null;
+ block = this.getBlockByNumber(block);
+ }
+ var number = block.id, id = block.event.id, cls = block.event.cls, name = block.event.name,
+ image = null, posX = 0, posY = 0, animate = block.event.animate, doorInfo = block.event.doorInfo,
+ height = block.event.height || 32, faceIds = {}, face = 'down', bigImage = null;
+
+ if (id == 'none') return null;
+ else if (id == 'airwall') {
+ if (!core.material.images.airwall) return null;
+ image = core.material.images.airwall;
+ name = "空气墙";
+ }
+ else if (cls == 'tileset') {
+ var offset = core.icons.getTilesetOffset(id);
+ if (offset == null) return null;
+ posX = offset.x;
+ posY = offset.y;
+ image = core.material.images.tilesets[offset.image];
+ }
+ else if (cls == 'autotile') {
+ image = core.material.images.autotile[id];
+ }
+ else {
+ image = core.material.images[cls];
+ posY = core.material.icons[cls][id];
+ faceIds = block.event.faceIds || {};
+ for (var f in faceIds) {
+ if (faceIds[f] == id) {
+ face = f;
+ break;
+ }
+ }
+ if (block.event.bigImage) bigImage = core.material.images.images[block.event.bigImage];
+ if (core.material.enemys[id]) {
+ name = core.material.enemys[id].name;
+ bigImage = core.material.images.images[core.material.enemys[id].bigImage];
+ } else if (core.material.items[id]) {
+ name = core.material.items[id].name;
+ }
+ // 非门效果则强制变成四帧动画
+ if (!doorInfo && bigImage != null) animate = 4;
+ }
+
+ return {
+ number: number, id: id, cls: cls, name: name, image: image, posX: posX, doorInfo: doorInfo,
+ posY: posY, height: height, faceIds: faceIds, animate: animate, face: face, bigImage: bigImage
+ };
+}
+
+////// 搜索某个图块出现的所有位置 //////
+maps.prototype.searchBlock = function (id, floorId, showDisable) {
+ if (typeof id == 'number') id = this.getBlockByNumber(id).event.id;
+ floorId = floorId || core.status.floorId;
+ var result = [];
+ if (floorId instanceof Array) {
+ floorId.forEach(function (floorId) {
+ result = result.concat(core.searchBlock(id, floorId, showDisable));
+ });
+ return result;
+ }
+ core.extractBlocks(floorId);
+ for (var i = 0; i < core.status.maps[floorId].blocks.length; ++i) {
+ var block = core.status.maps[floorId].blocks[i];
+ if ((showDisable || !block.disable) && (core.matchWildcard(id, block.event.id) || core.matchRegex(id, block.event.id))) {
+ result.push({ floorId: floorId, x: block.x, y: block.y, block: block });
+ }
+ }
+ return result;
+}
+
+////// 给定筛选函数,搜索某个图块出现的所有位置 //////
+maps.prototype.searchBlockWithFilter = function (blockFilter, floorId, showDisable) {
+ floorId = floorId || core.status.floorId;
+ var result = [];
+ if (floorId instanceof Array) {
+ floorId.forEach(function (floorId) {
+ result = result.concat(core.searchBlockWithFilter(blockFilter, floorId, showDisable));
+ });
+ return result;
+ }
+ core.extractBlocks(floorId);
+ for (var i = 0; i < core.status.maps[floorId].blocks.length; ++i) {
+ var block = core.status.maps[floorId].blocks[i];
+ if ((showDisable || !block.disable) && blockFilter(block)) {
+ result.push({ floorId: floorId, x: block.x, y: block.y, block: block });
+ }
+ }
+ return result;
+}
+
+////// 获得某个图块,其行走图朝向朝下的图块ID //////
+maps.prototype.getFaceDownId = function (block) {
+ if (block == null) return null;
+ if (typeof block == 'string') { // 参数是ID
+ block = this.getNumberById(block);
+ }
+ if (typeof block == 'number') { // 参数是数字
+ if (block == 0) return null;
+ block = this.getBlockByNumber(block);
+ }
+ if (!block.event) return null;
+ return (block.event.faceIds || {}).down || block.event.id;
+}
+
+// -------- 启用/禁用图块,楼层贴图 -------- //
+
+////// 将某个块从禁用变成启用状态 //////
+maps.prototype.showBlock = function (x, y, floorId) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return;
+ var block = core.getBlock(x, y, floorId, true);
+ if (block == null) return; // 不存在
+ // 本身是禁用事件,启用之
+ if (block.disable) {
+ block.disable = false;
+ core.setMapBlockDisabled(floorId, x, y, false);
+ this._updateMapArray(floorId, block.x, block.y);
+ // 在本层,添加动画
+ if (floorId == core.status.floorId) {
+ if (block.event.cls == 'autotile') {
+ core.redrawMap();
+ } else {
+ core.drawBlock(block);
+ core.addGlobalAnimate(block);
+ core.updateStatusBar(false, true);
+ }
+ }
+ }
+}
+
+////// 只隐藏但不删除某块 //////
+maps.prototype.hideBlock = function (x, y, floorId) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return;
+
+ var block = core.getBlock(x, y, floorId, true);
+ if (block == null) return; // 不存在
+
+ block.disable = true;
+ core.setMapBlockDisabled(floorId, block.x, block.y, true);
+ this._updateMapArray(floorId, block.x, block.y);
+
+ // 删除动画,清除地图
+ this._removeBlockFromMap(floorId, block);
+}
+
+////// 根据图块的索引来隐藏图块 //////
+maps.prototype.hideBlockByIndex = function (index, floorId) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return;
+ core.extractBlocks(floorId);
+ var blocks = core.status.maps[floorId].blocks, block = blocks[index];
+ block.disable = true;
+ core.setMapBlockDisabled(floorId, block.x, block.y, true);
+ this._updateMapArray(floorId, block.x, block.y);
+}
+
+////// 一次性隐藏多个block //////
+maps.prototype.hideBlockByIndexes = function (indexes, floorId) {
+ indexes.sort(function (a, b) {
+ return b - a;
+ }).forEach(function (index) {
+ core.hideBlockByIndex(index, floorId);
+ });
+}
+
+maps.prototype._removeBlockFromMap = function (floorId, block) {
+ if (floorId != core.status.floorId) return;
+ var filter = block.filter || {};
+ if (block.event.cls == 'autotile' || filter.blur > 0 || filter.shadow > 0) {
+ core.redrawMap();
+ } else {
+ var x = block.x, y = block.y;
+ var px = 32 * x - core.bigmap.posX * 32;
+ var py = 32 * y - core.bigmap.posY * 32;
+ core.removeGlobalAnimate(x, y);
+ core.clearMap('event', px, py, 32, 32);
+ var height = block.event.height || 32;
+ if (height > 32) core.clearMap('event2', px, py + 32 - height, 32, height - 32);
+ // 删除大怪物
+ core.deleteCanvas("_bigImage_header_" + x + "_" + y);
+ core.deleteCanvas("_bigImage_body_" + x + "_" + y);
+ core.updateStatusBar();
+ }
+}
+
+////// 删除某个图块 //////
+maps.prototype.removeBlock = function (x, y, floorId) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return false;
+
+ core.extractBlocks(floorId);
+ for (var i in core.status.maps[floorId].blocks) {
+ var block = core.status.maps[floorId].blocks[i];
+ if (block.x == x && block.y == y) {
+ this.removeBlockByIndex(i, floorId);
+ this._removeBlockFromMap(floorId, block);
+ return true;
+ }
+ }
+ return false;
+}
+
+////// 根据block的索引(尽可能)删除该块 //////
+maps.prototype.removeBlockByIndex = function (index, floorId) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return;
+ core.extractBlocks(floorId);
+ var blocks = core.status.maps[floorId].blocks, block = blocks[index];
+ blocks.splice(index, 1);
+ if (core.status.mapBlockObjs[floorId])
+ delete core.status.mapBlockObjs[floorId][block.x + "," + block.y];
+ core.setMapBlockDisabled(floorId, block.x, block.y, true);
+ this._updateMapArray(floorId, block.x, block.y);
+}
+
+////// 一次性删除多个block //////
+maps.prototype.removeBlockByIndexes = function (indexes, floorId) {
+ indexes.sort(function (a, b) {
+ return b - a;
+ }).forEach(function (index) {
+ core.removeBlockByIndex(index, floorId);
+ });
+}
+
+////// 显示前景/背景地图 //////
+maps.prototype.showBgFgMap = function (name, loc, floorId, callback) {
+ this._triggerBgFgMap('show', name, loc, floorId, callback);
+}
+
+////// 隐藏前景/背景地图 //////
+maps.prototype.hideBgFgMap = function (name, loc, floorId, callback) {
+ this._triggerBgFgMap('hide', name, loc, floorId, callback);
+}
+
+////// 设置前景/背景地图的显示状态 //////
+maps.prototype._triggerBgFgMap = function (type, name, loc, floorId, callback) {
+ if (type != 'show') type = 'hide';
+ if (!name || (!name.startsWith('bg') && !name.startsWith('fg'))) return;
+ if (typeof loc[0] == 'number' && typeof loc[1] == 'number')
+ loc = [loc];
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return;
+
+ if (loc.length == 0) return;
+ var disabled = core.getFlag('__' + name + 'd__', {});
+ disabled[floorId] = disabled[floorId] || [];
+ loc.forEach(function (t) {
+ if (type == 'hide') {
+ disabled[floorId].push([t[0], t[1]]);
+ } else {
+ disabled[floorId] = disabled[floorId].filter(function (one) { return one[0] != t[0] || one[1] != t[1] });
+ }
+ })
+ core.setFlag('__' + name + 'd__', disabled);
+
+ core.status[name + "maps"][floorId] = null;
+
+ if (floorId == core.status.floorId) {
+ core.redrawMap();
+ }
+ if (callback) callback();
+}
+
+////// 显示一个楼层贴图 //////
+maps.prototype.showFloorImage = function (loc, floorId, callback) {
+ this._triggerFloorImage('show', loc, floorId, callback);
+}
+
+////// 隐藏一个楼层贴图 //////
+maps.prototype.hideFloorImage = function (loc, floorId, callback) {
+ this._triggerFloorImage('hide', loc, floorId, callback);
+}
+
+///// 设置贴图显示状态 //////
+maps.prototype._triggerFloorImage = function (type, loc, floorId, callback) {
+ if (type != 'show') type = 'hide';
+ if (typeof loc[0] == 'number' && typeof loc[1] == 'number')
+ loc = [loc];
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return;
+
+ if (loc.length == 0) return;
+ loc.forEach(function (t) {
+ var x = t[0], y = t[1];
+ var flag = "__floorImg__" + floorId + "_" + x + "_" + y;
+ if (type == 'hide') core.setFlag(flag, true);
+ else core.removeFlag(flag);
+ })
+
+ if (floorId == core.status.floorId) {
+ core.redrawMap();
+ }
+ if (callback) callback();
+}
+
+////// 改变图块 //////
+maps.prototype.setBlock = function (number, x, y, floorId) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId || number == null || x == null || y == null) return;
+ if (x < 0 || x >= core.floors[floorId].width || y < 0 || y >= core.floors[floorId].height) return;
+ if (typeof number == 'string') {
+ if (/^\d+$/.test(number)) number = parseInt(number);
+ else number = core.getNumberById(number);
+ }
+
+ var block = this.initBlock(x, y, number, true, core.floors[floorId]);
+ if (block.id == 0 && !block.event.trigger) {
+ // 转变图块为0且该点无事件,视为删除
+ core.removeBlock(x, y, floorId);
+ return;
+ }
+ var originBlock = core.getBlock(x, y, floorId, true);
+ var originEvent = originBlock == null ? null : originBlock.event;
+ if (originBlock == null) {
+ core.status.maps[floorId].blocks.push(block);
+ if (core.status.mapBlockObjs[floorId])
+ core.status.mapBlockObjs[floorId][block.x + "," + block.y] = block;
+ core.setMapBlockDisabled(floorId, block.x, block.y, false);
+ delete block.disable;
+ }
+ else {
+ originBlock.id = number;
+ originBlock.event = block.event;
+ block = originBlock;
+ }
+ this._updateMapArray(floorId, x, y);
+ if (floorId == core.status.floorId) {
+ // 有任何一个是autotile直接重绘地图
+ if ((originEvent != null && originEvent.cls == 'autotile') || block.event.cls == 'autotile') {
+ core.redrawMap();
+ } else {
+ if (originEvent != null) {
+ this._removeBlockFromMap(floorId, { x: x, y: y, event: originEvent });
+ }
+ if (!block.disable) {
+ core.drawBlock(block);
+ core.addGlobalAnimate(block);
+ core.updateStatusBar();
+ }
+ }
+ }
+}
+
+maps.prototype.animateSetBlock = function (number, x, y, floorId, time, callback) {
+ floorId = floorId || core.status.floorId;
+ time = time || 0;
+ if (floorId != core.status.floorId || time == 0) {
+ // 不在当前楼层,直接忽略
+ this.setBlock(number, x, y, floorId);
+ if (callback) callback();
+ return;
+ }
+ if (typeof number == 'string') {
+ if (/^\d+$/.test(number)) number = parseInt(number);
+ else number = core.getNumberById(number);
+ }
+ var originBlock = core.getBlock(x, y, floorId, true);
+ var block = this.initBlock(x, y, number, true, core.floors[floorId]);
+
+ // 如果原本是启用的
+ if (originBlock != null && !originBlock.disable) {
+ return this._animateSetBlock_originEnabled(block, number, x, y, floorId, time, callback);
+ }
+
+ // 如果原本不存在
+ if (originBlock == null) {
+ return this._animateSetBlock_originNotExists(block, number, x, y, floorId, time, callback);
+ }
+
+ // 如果原本存在且禁用;应当直接设置,没有动画
+ if (originBlock != null && originBlock.disable) {
+ return this._animateSetBlock_originDisabled(number, x, y, floorId, callback);
+ }
+ if (callback) callback();
+}
+
+maps.prototype._animateSetBlock_originEnabled = function (block, number, x, y, floorId, time, callback) {
+ // 情况1:设置到0
+ if (block.id == 0) {
+ // 如果该点红点没有事件 - 直接删除
+ if (!block.event.trigger) {
+ return this.animateBlock([x, y], 'remove', time, callback);
+ } else {
+ // 如果该点红点有事件;则设置到0,但是需启用
+ return this.animateBlock([x, y], 'hide', time, function () {
+ core.setBlock(0, x, y, floorId);
+ core.showBlock(x, y, floorId);
+ if (callback) callback();
+ });
+ }
+ }
+ // 情况2:设置到非0
+ else {
+ return this.animateBlock([x, y], 'hide', time / 2, function () {
+ core.setBlock(number, x, y, floorId);
+ core.animateBlock([x, y], 'show', time / 2, callback);
+ })
+ }
+}
+
+maps.prototype._animateSetBlock_originNotExists = function (block, number, x, y, floorId, time, callback) {
+ // 情况1:设置到0;没有动画效果
+ if (block.id == 0) {
+ core.setBlock(number, x, y, floorId);
+ if (callback) callback();
+ }
+ else {
+ // 情况2:设置到非0,有淡入动画
+ core.setBlock(number, x, y, floorId);
+ core.hideBlock(x, y, floorId);
+ core.animateBlock([x, y], 'show', time, callback);
+ return;
+ }
+}
+
+maps.prototype._animateSetBlock_originDisabled = function (number, x, y, floorId, callback) {
+ core.setBlock(number, x, y, floorId);
+ if (callback) callback();
+}
+
+maps.prototype.animateSetBlocks = function (number, locs, floorId, time, callback) {
+ if (!(locs instanceof Array)) {
+ if (callback) callback();
+ return;
+ }
+ if (typeof locs[0] == 'number' && typeof locs[1] == 'number')
+ locs = [locs];
+
+ var count = locs.length;
+ var _afterSet = function () {
+ count--;
+ if (count == 0) {
+ if (callback) callback();
+ }
+ }
+ locs.forEach(function (loc) {
+ core.animateSetBlock(number, loc[0], loc[1], floorId, time, _afterSet);
+ });
+}
+
+////// 事件转向 //////
+maps.prototype.turnBlock = function (direction, x, y, floorId) {
+ var id = core.getBlockId(x, y, floorId, true);
+ var blockInfo = core.getBlockInfo(id);
+ if (blockInfo == null) return;
+ var faceIds = blockInfo.faceIds || {};
+ var currDirection = null;
+ for (var dir in core.utils.scan) {
+ if (faceIds[dir] == id) {
+ currDirection = dir;
+ }
+ }
+ if (currDirection == null) return;
+ var nextDirection = core.turnDirection(direction, currDirection);
+ var nextId = faceIds[nextDirection];
+ if (nextId != null && nextId != id) {
+ this.setBlock(nextId, x, y, floorId);
+ }
+}
+
+////// 将地图中所有某个图块替换成另一个图块 //////
+maps.prototype.replaceBlock = function (fromNumber, toNumber, floorId) {
+ floorId = floorId || core.status.floorId;
+ if (floorId instanceof Array) {
+ floorId.forEach(function (floorId) {
+ core.replaceBlock(fromNumber, toNumber, floorId);
+ });
+ return;
+ }
+ var toBlock = this.getBlockByNumber(toNumber, true);
+ core.extractBlocks(floorId);
+ core.status.maps[floorId].blocks.forEach(function (block) {
+ if (block.id == fromNumber) {
+ block.id = toNumber;
+ for (var one in toBlock.event) {
+ block.event[one] = core.clone(toBlock.event[one]);
+ }
+ this._updateMapArray(floorId, block.x, block.y);
+ }
+ }, this);
+ if (floorId == core.status.floorId) core.redrawMap();
+}
+
+////// 改变前景背景的图块 //////
+maps.prototype.setBgFgBlock = function (name, number, x, y, floorId) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId || number == null || x == null || y == null) return;
+ if (x < 0 || x >= core.floors[floorId].width || y < 0 || y >= core.floors[floorId].height) return;
+ if (!name || (!name.startsWith('bg') && !name.startsWith('fg'))) return;
+
+ if (typeof number == 'string') {
+ if (/^\d+$/.test(number)) number = parseInt(number);
+ else number = core.getNumberById(number);
+ }
+
+ var values = core.getFlag('__' + name + 'v__', {});
+ values[floorId] = (values[floorId] || []).filter(function (one) { return one[0] != x || one[1] != y });
+ values[floorId].push([x, y, number]);
+ core.setFlag('__' + name + 'v__', values);
+
+ core.status[name + "maps"][floorId] = null;
+
+ this._getBgFgMapArray(name, floorId, true);
+
+ if (floorId == core.status.floorId) {
+ core.clearMap(name);
+ if (name.startsWith('bg')) core.drawBg(floorId);
+ else core.drawFg(floorId);
+ }
+}
+
+////// 重置地图 //////
+maps.prototype.resetMap = function (floorId) {
+ floorId = floorId || core.status.floorId;
+ if (!floorId) return;
+ if (typeof floorId == 'string') floorId = [floorId];
+ var needRefresh = false;
+ floorId.forEach(function (t) {
+ core.status.maps[t] = core.maps.loadFloor(t);
+ // 重置本层的全部独立事件
+ Object.keys(core.status.hero.flags).forEach(function (one) {
+ if (one.startsWith(floorId + '@')) delete core.status.hero.flags[one];
+ })
+ // 重置本层的图块删除信息
+ delete (flags.__disabled__ || {})[t];
+ delete (core.status.mapBlockObjs || {})[t];
+ if (t == core.status.floorId) needRefresh = true;
+ });
+ if (needRefresh) this.redrawMap();
+ core.drawTip("地图重置成功");
+}
+
+// -------- 移动/跳跃图块,图块的淡入淡出 -------- //
+
+////// 初始化独立的block canvas //////
+maps.prototype._initDetachedBlock = function (blockInfo, x, y, displayDamage) {
+ var headCanvas = null, bodyCanvas = '__body_' + x + "_" + y, damageCanvas = null;
+ // head
+ if (!blockInfo.bigImage && blockInfo.height > 32) {
+ headCanvas = "__head_" + x + "_" + y;
+ core.createCanvas(headCanvas, 0, 0, 32, blockInfo.height - 32, 55);
+ }
+ // body
+ if (blockInfo.bigImage) {
+ var bigImageInfo = this._getBigImageInfo(blockInfo.bigImage, blockInfo.face, blockInfo.posX);
+ core.createCanvas(bodyCanvas, 0, 0, bigImageInfo.per_width, bigImageInfo.per_height, 35);
+ } else {
+ core.createCanvas(bodyCanvas, 0, 0, 32, 32, 35);
+ }
+ // damage
+ var damage = null, damageColor = null;
+ if (blockInfo.cls.indexOf('enemy') == 0 && core.hasItem('book') && displayDamage) {
+ var damageString = core.enemys.getDamageString(blockInfo.id, x, y);
+ damage = damageString.damage;
+ damageColor = damageString.color;
+ }
+ if (damage != null) {
+ damageCanvas = "__damage_" + x + "_" + y;
+ var ctx = core.createCanvas(damageCanvas, 0, 0, 32, 32, 65);
+ ctx.textAlign = 'left';
+ ctx.font = "bold 11px Arial";
+ core.fillBoldText(ctx, damage, 1, 31, damageColor);
+ if (core.flags.displayCritical) {
+ var critical = core.enemys.nextCriticals(blockInfo.id);
+ if (critical.length > 0) critical = critical[0];
+ critical = core.formatBigNumber(critical[0], true);
+ if (critical == '???') critical = '?';
+ core.fillBoldText(ctx, critical, 1, 21, '#FFFFFF');
+ }
+ }
+ return {
+ "headCanvas": headCanvas,
+ "bodyCanvas": bodyCanvas,
+ "damageCanvas": damageCanvas
+ }
+}
+
+////// 移动独立的block canvas //////
+maps.prototype._moveDetachedBlock = function (blockInfo, nowX, nowY, opacity, canvases) {
+ var height = blockInfo.height, posX = blockInfo.posX, posY = blockInfo.posY, image = blockInfo.image;
+ var headCanvas = canvases.headCanvas, bodyCanvas = canvases.bodyCanvas, damageCanvas = canvases.damageCanvas;
+ if (headCanvas) {
+ core.dymCanvas[headCanvas].clearRect(0, 0, 32, height);
+ core.dymCanvas[headCanvas].drawImage(image, posX * 32, posY * height, 32, height - 32, 0, 0, 32, height - 32);
+ core.relocateCanvas(headCanvas, nowX - core.bigmap.offsetX, nowY + 32 - height - core.bigmap.offsetY);
+ core.setOpacity(headCanvas, opacity);
+ }
+ if (bodyCanvas) {
+ if (blockInfo.bigImage) {
+ var face = blockInfo.face;
+ if (!blockInfo.faceIds) face = 'down';
+ else if (!blockInfo.faceIds[face]) {
+ // 维持此时朝向
+ face = 'down';
+ for (var f in blockInfo.faceIds) {
+ if (blockInfo.faceIds[f] == blockInfo.id) {
+ face = f;
+ }
+ }
+ }
+ var bigImageInfo = this._getBigImageInfo(blockInfo.bigImage, face, blockInfo.posX);
+ var per_width = bigImageInfo.per_width, per_height = bigImageInfo.per_height;
+ core.dymCanvas[bodyCanvas].clearRect(0, 0, bigImageInfo.per_width, bigImageInfo.per_height);
+ core.dymCanvas[bodyCanvas].drawImage(blockInfo.bigImage, bigImageInfo.sx, bigImageInfo.sy, per_width, per_height, 0, 0, per_width, per_height);
+ core.relocateCanvas(bodyCanvas, nowX - core.bigmap.offsetX + bigImageInfo.dx, nowY - core.bigmap.offsetY + bigImageInfo.dy);
+ core.setOpacity(bodyCanvas, opacity);
+ } else {
+ core.dymCanvas[bodyCanvas].clearRect(0, 0, 32, 32);
+ core.dymCanvas[bodyCanvas].drawImage(image, posX * 32, posY * height + height - 32, 32, 32, 0, 0, 32, 32);
+ core.relocateCanvas(bodyCanvas, nowX - core.bigmap.offsetX, nowY - core.bigmap.offsetY);
+ core.setOpacity(bodyCanvas, opacity);
+ }
+ }
+ if (damageCanvas) {
+ core.relocateCanvas(damageCanvas, nowX - core.bigmap.offsetX, nowY - core.bigmap.offsetY);
+ core.setOpacity(damageCanvas, opacity);
+ }
+}
+
+////// 删除独立的block canvas //////
+maps.prototype._deleteDetachedBlock = function (canvases) {
+ core.deleteCanvas(canvases.headCanvas);
+ core.deleteCanvas(canvases.bodyCanvas);
+ core.deleteCanvas(canvases.damageCanvas);
+}
+
+maps.prototype._getAndRemoveBlock = function (x, y) {
+ var block = core.getBlock(x, y);
+ if (block == null) return null;
+ var blockInfo = this.getBlockInfo(block);
+ if (blockInfo == null) return;
+ core.removeBlock(x, y);
+ return [block, blockInfo];
+}
+
+////// 显示移动某块的动画,达到{“type”:”move”}的效果 //////
+maps.prototype.moveBlock = function (x, y, steps, time, keep, callback) {
+ if (core.status.replay.speed == 24) time = 1;
+ time = time || 500;
+ var blockArr = this._getAndRemoveBlock(x, y);
+ if (blockArr == null) {
+ if (callback) callback();
+ return;
+ }
+ var block = blockArr[0], blockInfo = blockArr[1];
+ var moveSteps = (steps || []).map(function (t) {
+ return [t.split(':')[0], parseInt(t.split(':')[1] || "1")];
+ }).filter(function (t) {
+ return ['up', 'down', 'left', 'right', 'forward', 'backward', 'leftup', 'leftdown', 'rightup', 'rightdown', 'speed'].indexOf(t[0]) >= 0
+ && !(t[0] == 'speed' && t[1] < 16)
+ });
+ var canvases = this._initDetachedBlock(blockInfo, x, y, block.event.animate !== false);
+ this._moveDetachedBlock(blockInfo, 32 * x, 32 * y, 1, canvases);
+
+ var moveInfo = {
+ sx: x, sy: y, x: x, y: y, px: 32 * x, py: 32 * y, opacity: 1, keep: keep, lastDirection: null, offset: 1,
+ moveSteps: moveSteps, step: 0, per_time: time / 16 / core.status.replay.speed
+ }
+ this._moveBlock_doMove(blockInfo, canvases, moveInfo, callback);
+}
+
+maps.prototype._moveBlock_doMove = function (blockInfo, canvases, moveInfo, callback) {
+ var animateTotal = blockInfo.animate, animateTime = 0;
+ // 强制npc48行走时使用四帧动画
+ if (!blockInfo.doorInfo && !blockInfo.bigImage && blockInfo.cls == 'npc48') animateTotal = 4;
+ var _run = function () {
+ var cb = function () {
+ core.maps._deleteDetachedBlock(canvases);
+ // 不消失
+ if (moveInfo.keep) {
+ core.setBlock(blockInfo.number, moveInfo.x, moveInfo.y);
+ core.showBlock(moveInfo.x, moveInfo.y);
+ core.moveEnemyOnPoint(moveInfo.sx, moveInfo.sy, moveInfo.x, moveInfo.y);
+ }
+ if (callback) callback();
+ }
+
+ var animate = window.setInterval(function () {
+ if (blockInfo.cls != 'tileset') {
+ animateTime += moveInfo.per_time;
+ if (animateTime > core.values.animateSpeed) {
+ animateTime = 0;
+ blockInfo.posX = (blockInfo.posX + 1) % animateTotal;
+ }
+ }
+ if (moveInfo.moveSteps.length != 0) {
+ if (core.maps._moveBlock_updateSpeed(moveInfo)) {
+ clearInterval(animate);
+ delete core.animateFrame.asyncId[animate];
+ _run();
+ }
+ else core.maps._moveBlock_moving(blockInfo, canvases, moveInfo);
+ }
+ else
+ core.maps._moveJumpBlock_finished(blockInfo, canvases, moveInfo, animate, cb);
+ }, moveInfo.per_time);
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = cb;
+ }
+ _run();
+}
+
+maps.prototype._moveBlock_updateSpeed = function (moveInfo) {
+ if (moveInfo.step == 0 && moveInfo.moveSteps[0][0] == 'speed' && moveInfo.moveSteps[0][1] >= 16) {
+ moveInfo.per_time = moveInfo.moveSteps[0][1] / 16 / core.status.replay.speed;
+ moveInfo.moveSteps.shift();
+ return true;
+ }
+ return false;
+}
+
+maps.prototype._moveBlock_updateDirection = function (blockInfo, moveInfo) {
+ moveInfo.offset = 1;
+ var curr = moveInfo.moveSteps[0];
+ // 展开forward和backward
+ if ((curr[0] == 'backward' || curr[0] == 'forward') && curr[1] > 1) {
+ moveInfo.moveSteps.shift();
+ for (var i = 0; i < curr[1]; ++i) {
+ moveInfo.moveSteps.unshift([curr[0], 1]);
+ }
+ return this._moveBlock_updateDirection(blockInfo, moveInfo);
+ }
+ if (moveInfo.lastDirection == null) {
+ for (var d in blockInfo.faceIds) {
+ if (blockInfo.faceIds[d] == blockInfo.id) {
+ moveInfo.lastDirection = d;
+ break;
+ }
+ }
+ }
+ if (curr[0] == 'forward' || curr[0] == 'backward') {
+ if (moveInfo.lastDirection == null) {
+ moveInfo.moveSteps.shift();
+ return false;
+ }
+ if (curr[0] == 'backward')
+ moveInfo.offset = -1;
+ curr[0] = moveInfo.lastDirection;
+ }
+ moveInfo.lastDirection = curr[0];
+
+ // 根据faceIds修改朝向
+ var faceDirection = curr[0];
+ if (faceDirection == 'leftup' || faceDirection == 'leftdown') faceDirection = 'left';
+ if (faceDirection == 'rightup' || faceDirection == 'rightdown') faceDirection = 'right';
+ var currid = blockInfo.faceIds[faceDirection];
+ blockInfo.face = faceDirection;
+ if (currid) {
+ var posY = core.material.icons[blockInfo.cls][currid];
+ if (posY != null) {
+ blockInfo.number = core.getNumberById(currid) || blockInfo.number;
+ blockInfo.posY = posY;
+ }
+ }
+ // 处理 left:0 的情况,仅转向
+ if (curr[1] <= 0) {
+ moveInfo.moveSteps.shift();
+ return false;
+ }
+ moveInfo.x += core.utils.scan2[curr[0]].x * moveInfo.offset;
+ moveInfo.y += core.utils.scan2[curr[0]].y * moveInfo.offset;
+ return true;
+}
+
+maps.prototype._moveBlock_moving = function (blockInfo, canvases, moveInfo) {
+ if (moveInfo.step == 0) {
+ if (!this._moveBlock_updateDirection(blockInfo, moveInfo)) return;
+ }
+ var curr = moveInfo.moveSteps[0];
+ moveInfo.step++;
+ moveInfo.px += core.utils.scan2[curr[0]].x * 2 * moveInfo.offset;
+ moveInfo.py += core.utils.scan2[curr[0]].y * 2 * moveInfo.offset;
+ this._moveDetachedBlock(blockInfo, moveInfo.px, moveInfo.py, moveInfo.opacity, canvases);
+ if (moveInfo.step == 16) {
+ moveInfo.step = 0;
+ moveInfo.moveSteps[0][1]--;
+ if (moveInfo.moveSteps[0][1] <= 0) {
+ moveInfo.moveSteps.shift();
+ }
+ }
+}
+
+////// 显示跳跃某块的动画,达到{"type":"jump"}的效果 //////
+maps.prototype.jumpBlock = function (sx, sy, ex, ey, time, keep, callback) {
+ time = time || 500;
+ var blockArr = this._getAndRemoveBlock(sx, sy);
+ if (blockArr == null) {
+ if (callback) callback();
+ return;
+ }
+ var block = blockArr[0], blockInfo = blockArr[1];
+ var canvases = this._initDetachedBlock(blockInfo, sx, sy, block.event.animate !== false);
+ this._moveDetachedBlock(blockInfo, 32 * sx, 32 * sy, 1, canvases);
+ var jumpInfo = this.__generateJumpInfo(sx, sy, ex, ey, time);
+ jumpInfo.keep = keep;
+
+ this._jumpBlock_doJump(blockInfo, canvases, jumpInfo, callback);
+}
+
+maps.prototype.__generateJumpInfo = function (sx, sy, ex, ey, time) {
+ var dx = ex - sx, dy = ey - sy, distance = Math.round(Math.sqrt(dx * dx + dy * dy));
+ var jump_peak = 6 + distance, jump_count = jump_peak * 2;
+ time /= Math.max(core.status.replay.speed, 1)
+ return {
+ sx: sx, sy: sy, x: sx, y: sy, ex: ex, ey: ey, px: 32 * sx, py: 32 * sy, opacity: 1,
+ jump_peak: jump_peak, jump_count: jump_count,
+ step: 0, per_time: time / jump_count
+ };
+}
+
+maps.prototype._jumpBlock_doJump = function (blockInfo, canvases, jumpInfo, callback) {
+ var cb = function () {
+ core.maps._deleteDetachedBlock(canvases);
+ // 不消失
+ if (jumpInfo.keep) {
+ core.setBlock(blockInfo.number, jumpInfo.ex, jumpInfo.ey);
+ core.showBlock(jumpInfo.ex, jumpInfo.ey);
+ core.moveEnemyOnPoint(jumpInfo.sx, jumpInfo.sy, jumpInfo.ex, jumpInfo.ey);
+ }
+ if (callback) callback();
+ }
+
+ var animate = window.setInterval(function () {
+ if (jumpInfo.jump_count > 0)
+ core.maps._jumpBlock_jumping(blockInfo, canvases, jumpInfo)
+ else
+ core.maps._moveJumpBlock_finished(blockInfo, canvases, jumpInfo, animate, cb);
+ }, jumpInfo.per_time);
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = cb;
+}
+
+maps.prototype.__updateJumpInfo = function (jumpInfo) {
+ jumpInfo.jump_count--;
+ jumpInfo.x = (jumpInfo.x * jumpInfo.jump_count + jumpInfo.ex) / (jumpInfo.jump_count + 1.0);
+ jumpInfo.y = (jumpInfo.y * jumpInfo.jump_count + jumpInfo.ey) / (jumpInfo.jump_count + 1.0);
+ jumpInfo.px = 32 * jumpInfo.x;
+ var delta = Math.abs(jumpInfo.jump_count - jumpInfo.jump_peak);
+ jumpInfo.py = 32 * jumpInfo.y - (jumpInfo.jump_peak * jumpInfo.jump_peak - delta * delta) / 2;
+}
+
+maps.prototype._jumpBlock_jumping = function (blockInfo, canvases, jumpInfo) {
+ this.__updateJumpInfo(jumpInfo);
+ core.maps._moveDetachedBlock(blockInfo, jumpInfo.px, jumpInfo.py, jumpInfo.opacity, canvases);
+}
+
+maps.prototype._moveJumpBlock_finished = function (blockInfo, canvases, info, animate, cb) {
+ if (info.keep) info.opacity = 0;
+ else info.opacity -= 0.06;
+ if (info.opacity <= 0) {
+ delete core.animateFrame.asyncId[animate];
+ clearInterval(animate);
+ cb();
+ }
+ else {
+ this._moveDetachedBlock(blockInfo, info.px, info.py, info.opacity, canvases);
+ }
+}
+
+////// 显示/隐藏某个块时的动画效果 //////
+maps.prototype.animateBlock = function (loc, type, time, callback) {
+ if (core.status.replay.speed == 24) time = 1;
+ if (typeof loc[0] == 'number' && typeof loc[1] == 'number')
+ loc = [loc];
+ if (type != 'show' && type != 'hide' && type != 'remove' && typeof type != 'number') {
+ if (callback) callback();
+ }
+ // --- 检测所有是0的点
+ var list = this._animateBlock_getList(loc, type);
+ if (list.length == 0) {
+ if (callback) callback();
+ return;
+ }
+ this._animateBlock_drawList(list, 0);
+ time /= Math.max(core.status.replay.speed, 1)
+ this._animateBlock_doAnimate(loc, list, type, time, callback);
+}
+
+maps.prototype._animateBlock_doAnimate = function (loc, list, type, time, callback) {
+ var step = 0, steps = Math.max(parseInt(time / 10), 1);
+ var cb = function () {
+ list.forEach(function (t) {
+ if (t.blockInfo)
+ core.maps._deleteDetachedBlock(t.canvases);
+ });
+ loc.forEach(function (t) {
+ if (type == 'show') core.showBlock(t[0], t[1]);
+ else if (type == 'hide') core.hideBlock(t[0], t[1]);
+ else if (type == 'remove') core.removeBlock(t[0], t[1]);
+ else {
+ core.setBlockOpacity(type, t[0], t[1]);
+ core.showBlock(t[0], t[1]);
+ }
+ });
+ if (callback) callback();
+ }
+
+ var animate = setInterval(function () {
+ step++;
+ core.maps._animateBlock_drawList(list, step / steps);
+ if (step == steps) {
+ delete core.animateFrame.asyncId[animate];
+ clearInterval(animate);
+ cb();
+ }
+ }, 10);
+
+ core.animateFrame.lastAsyncId = animate;
+ core.animateFrame.asyncId[animate] = cb;
+}
+
+maps.prototype._animateBlock_getList = function (loc, type) {
+ var list = [];
+ loc.forEach(function (t) {
+ var block = core.getBlock(t[0], t[1], null, true);
+ if (block == null) return;
+
+ var fromOpacity = block.opacity;
+ if (fromOpacity == null) fromOpacity = 1.0;
+
+ var blockInfo = core.maps.getBlockInfo(block);
+ if (blockInfo == null) {
+ list.push({ 'x': t[0], 'y': t[1] });
+ return;
+ }
+ if (typeof type == 'number' && block.disable) return;
+ // 该点是否已经被启用/删除
+ if ((type == 'show' && !block.disable) || ((type == 'hide' || type == 'remove') && block.disable)) {
+ list.push({ 'x': t[0], 'y': t[1] });
+ return;
+ }
+
+ var toOpacity = type;
+ if (type == 'show') {
+ toOpacity = fromOpacity;
+ fromOpacity = 0.0;
+ }
+ else if (type == 'hide' || type == 'remove') {
+ core.hideBlock(t[0], t[1]); // 暂时先隐藏
+ toOpacity = 0.0;
+ }
+ else {
+ core.hideBlock(t[0], t[1]); // 暂时先隐藏
+ }
+
+ var canvases = core.maps._initDetachedBlock(blockInfo, t[0], t[1], block.event.displayDamage !== false);
+
+ list.push({
+ 'x': t[0], 'y': t[1], 'blockInfo': blockInfo, 'canvases': canvases,
+ 'fromOpacity': fromOpacity, 'toOpacity': toOpacity,
+ });
+
+ });
+ return list;
+}
+
+maps.prototype._animateBlock_drawList = function (list, progress) {
+ list.forEach(function (t) {
+ if (t.blockInfo)
+ core.maps._moveDetachedBlock(t.blockInfo, t.x * 32, t.y * 32, t.fromOpacity + progress * (t.toOpacity - t.fromOpacity), t.canvases);
+ });
+}
+
+// ------ 全局动画控制,动画绘制 ------ //
+
+////// 添加一个全局动画 //////
+maps.prototype.addGlobalAnimate = function (block) {
+ if (!block || !block.event) return;
+ this.removeGlobalAnimate(block.x, block.y, block.name);
+ if (block.event.cls == 'autotile') {
+ var id = block.event.id, img = core.material.images.autotile[id];
+ if (!img || img.width == 96) return;
+ core.status.autotileAnimateObjs.push(block);
+ }
+ else {
+ if (!block.event.bigImage && (!block.event.animate || block.event.animate == 1)) return;
+ core.status.globalAnimateObjs.push(block);
+ }
+}
+
+////// 删除一个或所有全局动画 //////
+maps.prototype.removeGlobalAnimate = function (x, y, name) {
+ // 没有定义xy,则全部删除
+ if (x == null || y == null) {
+ core.status.globalAnimateStatus = 0;
+ core.status.globalAnimateObjs = [];
+ core.status.autotileAnimateObjs = [];
+ core.status.floorAnimateObjs = [];
+ return;
+ }
+
+ core.status.globalAnimateObjs = core.status.globalAnimateObjs.filter(function (block) {
+ return block.x != x || block.y != y || block.name != name;
+ });
+
+ // 检查Autotile
+ core.status.autotileAnimateObjs = core.status.autotileAnimateObjs.filter(function (block) {
+ return block.x != x || block.y != y || block.name != name;
+ });
+}
+
+////// 绘制UI层的box动画 //////
+maps.prototype.drawBoxAnimate = function () {
+ if (core.status.boxAnimateObjs.length == 0) return;
+ // check ui2
+ if (main.mode == 'play' && core.status.boxAnimateObjs.filter(function (one) { return one.bigImage }).length > 0 && !core.dymCanvas.ui2) {
+ core.createCanvas('ui2', 0, 0, core._PX_, core._PY_, 142);
+ }
+ core.clearMap('ui2');
+
+ core.status.boxAnimateObjs.forEach(function (obj) {
+ if (obj.bigImage) {
+ var ctx = obj.ctx || 'ui2';
+ var bigImageInfo = core.maps._getBigImageInfo(obj.bigImage, obj.face, core.status.globalAnimateStatus % 4);
+ var sx = bigImageInfo.sx, sy = bigImageInfo.sy, per_width = bigImageInfo.per_width, per_height = bigImageInfo.per_height;
+ var actual_width = Math.min(per_width, obj.max_width || per_width), actual_height = per_height * actual_width / per_width;
+ var x = obj.centerX - actual_width / 2, y = obj.centerY - actual_height / 2;
+ core.clearMap(ctx, x, y, actual_width, actual_height);
+ core.fillRect(ctx, x, y, actual_width, actual_height, core.material.groundPattern);
+ core.strokeRect(ctx, x, y, actual_width, actual_height, 'gold', 2);
+ core.drawImage(ctx, obj.bigImage, sx, sy, per_width, per_height,
+ obj.centerX - actual_width / 2, obj.centerY - actual_height / 2, actual_width, actual_height);
+ } else {
+ var ctx = obj.ctx || 'ui';
+ core.clearMap(ctx, obj.bgx, obj.bgy, obj.bgWidth, obj.bgHeight);
+ core.fillRect(ctx, obj.bgx, obj.bgy, obj.bgWidth, obj.bgHeight, core.material.groundPattern);
+ core.drawImage(ctx, obj.image, core.status.globalAnimateStatus % obj.animate * 32, obj.pos,
+ 32, obj.height, obj.x, obj.y, obj.dw || 32, obj.dh || obj.height);
+ }
+ });
+ if (main.mode != 'play') core.status.boxAnimateObjs = [];
+}
+
+////// 绘制动画 //////
+maps.prototype.drawAnimate = function (name, x, y, alignWindow, callback) {
+ name = core.getMappedName(name);
+
+ // 正在播放录像:不显示动画
+ if (core.isReplaying() || !core.material.animates[name] || x == null || y == null) {
+ if (callback) callback();
+ return -1;
+ }
+
+ // 开始绘制
+ var animate = core.material.animates[name], centerX = 32 * x + 16, centerY = 32 * y + 16;
+ if (alignWindow) {
+ centerX += core.bigmap.offsetX;
+ centerY += core.bigmap.offsetY;
+ }
+ animate.se = animate.se || {};
+ if (typeof animate.se == 'string') animate.se = { 1: animate.se };
+
+ var id = setTimeout(null);
+ core.status.animateObjs.push({
+ "name": name,
+ "id": id,
+ "animate": animate,
+ "centerX": centerX,
+ "centerY": centerY,
+ "index": 0,
+ "callback": callback
+ });
+
+ return id;
+}
+
+////// 绘制一个跟随勇士的动画 //////
+maps.prototype.drawHeroAnimate = function (name, callback) {
+ name = core.getMappedName(name);
+
+ // 正在播放录像或动画不存在:不显示动画
+ if (core.isReplaying() || !core.material.animates[name]) {
+ if (callback) callback();
+ return -1;
+ }
+
+ // 开始绘制
+ var animate = core.material.animates[name];
+ animate.se = animate.se || {};
+ if (typeof animate.se == 'string') animate.se = { 1: animate.se };
+
+ var id = setTimeout(null);
+ core.status.animateObjs.push({
+ "name": name,
+ "id": id,
+ "animate": animate,
+ "hero": true,
+ "index": 0,
+ "callback": callback
+ });
+
+ return id;
+}
+
+////// 获得当前正在播放的所有(指定)动画的id列表 //////
+maps.prototype.getPlayingAnimates = function (name) {
+ return (core.status.animateObjs || []).filter(function (one) {
+ return name == null || one.name == name;
+ }).map(function (one) { return one.id });
+}
+
+////// 绘制动画的某一帧 //////
+maps.prototype._drawAnimateFrame = function (name, animate, centerX, centerY, index) {
+ var ctx = core.getContextByName(name);
+ if (!ctx) return;
+ var frame = animate.frames[index % animate.frame];
+ core.playSound((animate.se || {})[index % animate.frame + 1], (animate.pitch || {})[index % animate.frame + 1]);
+ var ratio = animate.ratio;
+ frame.forEach(function (t) {
+ var image = animate.images[t.index];
+ if (!image) return;
+
+ var realWidth = image.width * ratio * t.zoom / 100;
+ var realHeight = image.height * ratio * t.zoom / 100;
+ core.setAlpha(ctx, t.opacity / 255);
+
+ var cx = centerX + t.x, cy = centerY + t.y;
+
+ var ix = cx - realWidth / 2 - core.bigmap.offsetX,
+ iy = cy - realHeight / 2 - core.bigmap.offsetY;
+
+ var mirror = t.mirror ? 'x' : null;
+ var angle = t.angle ? -t.angle * Math.PI / 180 : null;
+ core.drawImage(ctx, image, ix, iy, realWidth, realHeight, null, null, null, null, angle, mirror);
+
+ core.setAlpha(ctx, 1);
+ })
+}
+
+////// 停止动画 //////
+maps.prototype.stopAnimate = function (id, doCallback) {
+ for (var i = 0; i < core.status.animateObjs.length; i++) {
+ var obj = core.status.animateObjs[i];
+ if (id == null || obj.id == id) {
+ if (doCallback) {
+ (function (callback) {
+ setTimeout(function () {
+ if (callback) callback();
+ });
+ })(obj.callback);
+ }
+ }
+ }
+ core.status.animateObjs = core.status.animateObjs.filter(function (x) { return id != null && x.id != id });
+ if (core.status.animateObjs.length == 0)
+ core.clearMap('animate');
+}
diff --git a/libs/thirdparty/LICENSE.md b/libs/thirdparty/LICENSE.md
new file mode 100644
index 0000000..2d1241c
--- /dev/null
+++ b/libs/thirdparty/LICENSE.md
@@ -0,0 +1,254 @@
+lzstring
+============
+
+MIT License
+
+Copyright (c) 2013 pieroxy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+localforage
+============
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2014 Mozilla
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+zip
+============
+
+ Copyright (c) 2013 Gildas Lormeau. All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/libs/thirdparty/corejs.min.js b/libs/thirdparty/corejs.min.js
new file mode 100644
index 0000000..7ee4914
--- /dev/null
+++ b/libs/thirdparty/corejs.min.js
@@ -0,0 +1,13 @@
+/**
+ * core-js 3.25.0
+ * © 2014-2022 Denis Pushkarev (zloirock.ru)
+ * license: https://github.com/zloirock/core-js/blob/v3.25.0/LICENSE
+ * source: https://github.com/zloirock/core-js
+ */
+ !function(t){"use strict";var r,e,n;r=[function(t,r,e){e(1),e(96),e(97),e(98),e(99),e(100),e(101),e(102),e(103),e(104),e(105),e(106),e(107),e(108),e(109),e(110),e(120),e(122),e(132),e(133),e(135),e(138),e(141),e(143),e(145),e(146),e(147),e(148),e(150),e(151),e(153),e(154),e(156),e(160),e(161),e(162),e(163),e(167),e(168),e(170),e(171),e(172),e(174),e(177),e(178),e(179),e(180),e(181),e(186),e(188),e(189),e(190),e(191),e(192),e(199),e(201),e(204),e(206),e(207),e(208),e(209),e(210),e(214),e(215),e(217),e(218),e(219),e(221),e(222),e(223),e(92),e(224),e(225),e(233),e(235),e(236),e(237),e(239),e(240),e(242),e(243),e(245),e(246),e(247),e(249),e(250),e(251),e(252),e(253),e(254),e(255),e(256),e(260),e(261),e(263),e(265),e(266),e(267),e(268),e(269),e(271),e(273),e(274),e(275),e(276),e(278),e(279),e(281),e(282),e(283),e(284),e(286),e(287),e(288),e(289),e(290),e(291),e(292),e(293),e(295),e(296),e(297),e(298),e(299),e(300),e(301),e(302),e(304),e(305),e(306),e(308),e(309),e(310),e(311),e(334),e(335),e(336),e(337),e(338),e(339),e(340),e(341),e(343),e(344),e(345),e(346),e(347),e(348),e(349),e(350),e(351),e(352),e(359),e(360),e(362),e(363),e(364),e(365),e(366),e(368),e(369),e(371),e(374),e(375),e(376),e(377),e(381),e(382),e(384),e(385),e(386),e(387),e(389),e(390),e(391),e(392),e(393),e(394),e(396),e(399),e(402),e(405),e(406),e(407),e(408),e(409),e(410),e(411),e(412),e(413),e(414),e(415),e(416),e(417),e(423),e(424),e(425),e(426),e(427),e(428),e(429),e(430),e(431),e(432),e(433),e(434),e(436),e(440),e(441),e(442),e(443),e(444),e(445),e(446),e(447),e(448),e(449),e(450),e(451),e(452),e(453),e(454),e(455),e(456),e(457),e(458),e(459),e(460),e(461),e(462),e(463),e(464),e(467),e(469),e(478),e(479),e(480),e(482),e(483),e(485),e(486),e(487),e(488),e(489),e(491),e(492),e(493),e(495),e(497),e(498),e(501),e(503),e(504),e(505),e(506),e(507),e(508),e(510),e(511),e(512),e(513),e(514),e(515),e(516),e(518),e(520),e(521),e(522),e(523),e(524),e(525),e(528),e(529),e(530),e(531),e(532),e(533),e(534),e(535),e(536),e(537),e(538),e(539),e(540),e(541),e(542),e(544),e(546),e(548),e(549),e(550),e(551),e(553),e(554),e(556),e(557),e(558),e(559),e(560),e(561),e(563),e(564),e(565),e(566),e(568),e(569),e(570),e(571),e(572),e(574),e(575),e(576),e(577),e(578),e(579),e(580),e(581),e(582),e(583),e(584),e(585),e(587),e(588),e(589),e(594),e(595),e(597),e(598),e(599),e(600),e(601),e(602),e(603),e(604),e(605),e(607),e(608),e(609),e(611),e(612),e(613),e(614),e(615),e(616),e(617),e(618),e(619),e(620),e(621),e(622),e(623),e(624),e(625),e(626),e(627),e(628),e(629),e(630),e(631),e(632),e(633),e(634),e(635),e(636),e(637),e(638),e(639),e(640),e(641),e(642),e(643),e(644),e(646),e(647),e(648),e(649),e(650),e(651),e(652),e(653),e(654),e(655),e(657),e(658),e(661),e(662),e(665),e(666),e(667),e(670),e(671),e(672),e(676),e(681),t.exports=e(682)},function(t,r,e){e(2),e(89),e(91),e(92),e(95)},function(r,e,n){var o=n(3),i=n(4),a=n(8),u=n(14),c=n(35),f=n(6),s=n(26),l=n(7),h=n(38),p=n(24),g=n(46),v=n(12),d=n(18),y=n(68),m=n(11),b=n(71),x=n(73),w=n(57),E=n(75),S=n(66),A=n(5),I=n(44),R=n(72),O=n(10),T=n(47),M=n(34),P=n(53),j=n(54),k=n(40),_=n(33),N=n(78),C=n(79),D=n(81),U=n(82),L=n(51),B=n(83).forEach,W=P("hidden"),z="Symbol",V=L.set,q=L.getterFor(z),G=Object.prototype,H=i.Symbol,K=H&&H.prototype,Y=i.TypeError,$=i.QObject,J=A.f,X=I.f,Q=E.f,Z=O.f,tt=u([].push),rt=M("symbols"),et=M("op-symbols"),nt=M("wks"),ot=!$||!$.prototype||!$.prototype.findChild,it=f&&l((function(){return 7!=b(X({},"a",{get:function(){return X(this,"a",{value:7}).a}})).a}))?function(t,r,e){var n=J(G,r);n&&delete G[r],X(t,r,e),n&&t!==G&&X(G,r,n)}:X,wrap=function(t,r){var e=rt[t]=b(K);return V(e,{type:z,tag:t,description:r}),f||(e.description=r),e},ut=function defineProperty(t,r,e){t===G&&ut(et,r,e),g(t);var n=d(r);return g(e),h(rt,n)?(e.enumerable?(h(t,W)&&t[W][n]&&(t[W][n]=!1),e=b(e,{enumerable:m(0,!1)})):(h(t,W)||X(t,W,m(1,{})),t[W][n]=!0),it(t,n,e)):X(t,n,e)},ct=function defineProperties(t,r){var e,n;return g(t),e=v(r),n=x(e).concat($getOwnPropertySymbols(e)),B(n,(function(r){f&&!a(ft,e,r)||ut(t,r,e[r])})),t},ft=function propertyIsEnumerable(t){var r=d(t),e=a(Z,this,r);return!(this===G&&h(rt,r)&&!h(et,r))&&(!(e||!h(this,r)||!h(rt,r)||h(this,W)&&this[W][r])||e)},st=function getOwnPropertyDescriptor(t,r){var e,n=v(t),o=d(r);if(n!==G||!h(rt,o)||h(et,o))return!(e=J(n,o))||!h(rt,o)||h(n,W)&&n[W][o]||(e.enumerable=!0),e},lt=function getOwnPropertyNames(t){var r=Q(v(t)),e=[];return B(r,(function(t){h(rt,t)||h(j,t)||tt(e,t)})),e},$getOwnPropertySymbols=function(t){var r=t===G,e=Q(r?et:v(t)),n=[];return B(e,(function(t){!h(rt,t)||r&&!h(G,t)||tt(n,rt[t])})),n};s||(H=function Symbol(){var r,e,n;if(p(K,this))throw Y("Symbol is not a constructor");return r=arguments.length&&arguments[0]!==t?y(arguments[0]):t,e=k(r),n=function(t){this===G&&a(n,et,t),h(this,W)&&h(this[W],e)&&(this[W][e]=!1),it(this,e,m(1,t))},f&&ot&&it(G,e,{configurable:!0,set:n}),wrap(e,r)},T(K=H.prototype,"toString",(function toString(){return q(this).tag})),T(H,"withoutSetter",(function(t){return wrap(k(t),t)})),O.f=ft,I.f=ut,R.f=ct,A.f=st,w.f=E.f=lt,S.f=$getOwnPropertySymbols,N.f=function(t){return wrap(_(t),t)},f&&(X(K,"description",{configurable:!0,get:function description(){return q(this).description}}),c||T(G,"propertyIsEnumerable",ft,{unsafe:!0}))),o({global:!0,constructor:!0,wrap:!0,forced:!s,sham:!s},{Symbol:H}),B(x(nt),(function(t){C(t)})),o({target:z,stat:!0,forced:!s},{useSetter:function(){ot=!0},useSimple:function(){ot=!1}}),o({target:"Object",stat:!0,forced:!s,sham:!f},{create:function create(r,e){return e===t?b(r):ct(b(r),e)},defineProperty:ut,defineProperties:ct,getOwnPropertyDescriptor:st}),o({target:"Object",stat:!0,forced:!s},{getOwnPropertyNames:lt}),D(),U(H,z),j[W]=!0},function(r,e,n){var o=n(4),i=n(5).f,a=n(43),u=n(47),c=n(37),f=n(55),s=n(67);r.exports=function(r,e){var n,l,h,p,g,v=r.target,d=r.global,y=r.stat;if(n=d?o:y?o[v]||c(v,{}):(o[v]||{}).prototype)for(l in e){if(p=e[l],h=r.dontCallGetSet?(g=i(n,l))&&g.value:n[l],!s(d?l:v+(y?".":"#")+l,r.forced)&&h!==t){if(typeof p==typeof h)continue;f(p,h)}(r.sham||h&&h.sham)&&a(p,"sham",!0),u(n,l,p,r)}}},function(t,r){var check=function(t){return t&&t.Math==Math&&t};t.exports=check("object"==typeof globalThis&&globalThis)||check("object"==typeof window&&window)||check("object"==typeof self&&self)||check("object"==typeof global&&global)||function(){return this}()||Function("return this")()},function(t,r,e){var n=e(6),o=e(8),i=e(10),a=e(11),u=e(12),c=e(18),f=e(38),s=e(41),l=Object.getOwnPropertyDescriptor;r.f=n?l:function getOwnPropertyDescriptor(t,r){if(t=u(t),r=c(r),s)try{return l(t,r)}catch(e){}if(f(t,r))return a(!o(i.f,t,r),t[r])}},function(t,r,e){var n=e(7);t.exports=!n((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},function(t,r){t.exports=function(t){try{return!!t()}catch(r){return!0}}},function(t,r,e){var n=e(9),o=function(){}.call;t.exports=n?o.bind(o):function(){return o.apply(o,arguments)}},function(t,r,e){var n=e(7);t.exports=!n((function(){var t=function(){}.bind();return"function"!=typeof t||t.hasOwnProperty("prototype")}))},function(t,r,e){var n={}.propertyIsEnumerable,o=Object.getOwnPropertyDescriptor,i=o&&!n.call({1:2},1);r.f=i?function propertyIsEnumerable(t){var r=o(this,t);return!!r&&r.enumerable}:n},function(t,r){t.exports=function(t,r){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:r}}},function(t,r,e){var n=e(13),o=e(16);t.exports=function(t){return n(o(t))}},function(t,r,e){var n=e(14),o=e(7),i=e(15),a=Object,u=n("".split);t.exports=o((function(){return!a("z").propertyIsEnumerable(0)}))?function(t){return"String"==i(t)?u(t,""):a(t)}:a},function(t,r,e){var n=e(9),o=Function.prototype,i=o.call,a=n&&o.bind.bind(i,i);t.exports=n?function(t){return t&&a(t)}:function(t){return t&&function(){return i.apply(t,arguments)}}},function(t,r,e){var n=e(14),o=n({}.toString),i=n("".slice);t.exports=function(t){return i(o(t),8,-1)}},function(t,r,e){var n=e(17),o=TypeError;t.exports=function(t){if(n(t))throw o("Can't call method on "+t);return t}},function(r,e){r.exports=function(r){return null===r||r===t}},function(t,r,e){var n=e(19),o=e(22);t.exports=function(t){var r=n(t,"string");return o(r)?r:r+""}},function(r,e,n){var o=n(8),i=n(20),a=n(22),u=n(29),c=n(32),f=n(33),s=TypeError,l=f("toPrimitive");r.exports=function(r,e){var n,f;if(!i(r)||a(r))return r;if(n=u(r,l)){if(e===t&&(e="default"),f=o(n,r,e),!i(f)||a(f))return f;throw s("Can't convert object to primitive value")}return e===t&&(e="number"),c(r,e)}},function(r,e,n){var o=n(21),i="object"==typeof document&&document.all;r.exports=t===i&&i!==t?function(t){return"object"==typeof t?null!==t:o(t)||t===i}:function(t){return"object"==typeof t?null!==t:o(t)}},function(t,r){t.exports=function(t){return"function"==typeof t}},function(t,r,e){var n=e(23),o=e(21),i=e(24),a=e(25),u=Object;t.exports=a?function(t){return"symbol"==typeof t}:function(t){var r=n("Symbol");return o(r)&&i(r.prototype,u(t))}},function(r,e,n){var o=n(4),i=n(21),aFunction=function(r){return i(r)?r:t};r.exports=function(t,r){return arguments.length<2?aFunction(o[t]):o[t]&&o[t][r]}},function(t,r,e){var n=e(14);t.exports=n({}.isPrototypeOf)},function(t,r,e){var n=e(26);t.exports=n&&!Symbol.sham&&"symbol"==typeof Symbol.iterator},function(t,r,e){var n=e(27),o=e(7);t.exports=!!Object.getOwnPropertySymbols&&!o((function(){var t=Symbol();return!String(t)||!(Object(t)instanceof Symbol)||!Symbol.sham&&n&&n<41}))},function(t,r,e){var n,o,i=e(4),a=e(28),u=i.process,c=i.Deno,f=u&&u.versions||c&&c.version,s=f&&f.v8;s&&(o=(n=s.split("."))[0]>0&&n[0]<4?1:+(n[0]+n[1])),!o&&a&&(!(n=a.match(/Edge\/(\d+)/))||n[1]>=74)&&(n=a.match(/Chrome\/(\d+)/))&&(o=+n[1]),t.exports=o},function(t,r,e){var n=e(23);t.exports=n("navigator","userAgent")||""},function(r,e,n){var o=n(30),i=n(17);r.exports=function(r,e){var n=r[e];return i(n)?t:o(n)}},function(t,r,e){var n=e(21),o=e(31),i=TypeError;t.exports=function(t){if(n(t))return t;throw i(o(t)+" is not a function")}},function(t,r){var e=String;t.exports=function(t){try{return e(t)}catch(r){return"Object"}}},function(t,r,e){var n=e(8),o=e(21),i=e(20),a=TypeError;t.exports=function(t,r){var e,u;if("string"===r&&o(e=t.toString)&&!i(u=n(e,t)))return u;if(o(e=t.valueOf)&&!i(u=n(e,t)))return u;if("string"!==r&&o(e=t.toString)&&!i(u=n(e,t)))return u;throw a("Can't convert object to primitive value")}},function(t,r,e){var n=e(4),o=e(34),i=e(38),a=e(40),u=e(26),c=e(25),f=o("wks"),s=n.Symbol,l=s&&s["for"],h=c?s:s&&s.withoutSetter||a;t.exports=function(t){if(!i(f,t)||!u&&"string"!=typeof f[t]){var r="Symbol."+t;f[t]=u&&i(s,t)?s[t]:c&&l?l(r):h(r)}return f[t]}},function(r,e,n){var o=n(35),i=n(36);(r.exports=function(r,e){return i[r]||(i[r]=e!==t?e:{})})("versions",[]).push({version:"3.25.0",mode:o?"pure":"global",copyright:"© 2014-2022 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.25.0/LICENSE",source:"https://github.com/zloirock/core-js"})},function(t,r){t.exports=!1},function(t,r,e){var n=e(4),o=e(37),i="__core-js_shared__",a=n[i]||o(i,{});t.exports=a},function(t,r,e){var n=e(4),o=Object.defineProperty;t.exports=function(t,r){try{o(n,t,{value:r,configurable:!0,writable:!0})}catch(e){n[t]=r}return r}},function(t,r,e){var n=e(14),o=e(39),i=n({}.hasOwnProperty);t.exports=Object.hasOwn||function hasOwn(t,r){return i(o(t),r)}},function(t,r,e){var n=e(16),o=Object;t.exports=function(t){return o(n(t))}},function(r,e,n){var o=n(14),i=0,a=Math.random(),u=o(1..toString);r.exports=function(r){return"Symbol("+(r===t?"":r)+")_"+u(++i+a,36)}},function(t,r,e){var n=e(6),o=e(7),i=e(42);t.exports=!n&&!o((function(){return 7!=Object.defineProperty(i("div"),"a",{get:function(){return 7}}).a}))},function(t,r,e){var n=e(4),o=e(20),i=n.document,a=o(i)&&o(i.createElement);t.exports=function(t){return a?i.createElement(t):{}}},function(t,r,e){var n=e(6),o=e(44),i=e(11);t.exports=n?function(t,r,e){return o.f(t,r,i(1,e))}:function(t,r,e){return t[r]=e,t}},function(t,r,e){var n=e(6),o=e(41),i=e(45),a=e(46),u=e(18),c=TypeError,f=Object.defineProperty,s=Object.getOwnPropertyDescriptor;r.f=n?i?function defineProperty(t,r,e){if(a(t),r=u(r),a(e),"function"==typeof t&&"prototype"===r&&"value"in e&&"writable"in e&&!e.writable){var n=s(t,r);n&&n.writable&&(t[r]=e.value,e={configurable:"configurable"in e?e.configurable:n.configurable,enumerable:"enumerable"in e?e.enumerable:n.enumerable,writable:!1})}return f(t,r,e)}:f:function defineProperty(t,r,e){if(a(t),r=u(r),a(e),o)try{return f(t,r,e)}catch(n){}if("get"in e||"set"in e)throw c("Accessors not supported");return"value"in e&&(t[r]=e.value),t}},function(t,r,e){var n=e(6),o=e(7);t.exports=n&&o((function(){return 42!=Object.defineProperty((function(){}),"prototype",{value:42,writable:!1}).prototype}))},function(t,r,e){var n=e(20),o=String,i=TypeError;t.exports=function(t){if(n(t))return t;throw i(o(t)+" is not an object")}},function(r,e,n){var o=n(21),i=n(44),a=n(48),u=n(37);r.exports=function(r,e,n,c){var f,s;if(c||(c={}),f=c.enumerable,s=c.name!==t?c.name:e,o(n)&&a(n,s,c),c.global)f?r[e]=n:u(e,n);else{try{c.unsafe?r[e]&&(f=!0):delete r[e]}catch(l){}f?r[e]=n:i.f(r,e,{value:n,enumerable:!1,configurable:!c.nonConfigurable,writable:!c.nonWritable})}return r}},function(r,e,n){var o=n(7),i=n(21),a=n(38),u=n(6),c=n(49).CONFIGURABLE,f=n(50),s=n(51),l=s.enforce,h=s.get,p=Object.defineProperty,g=u&&!o((function(){return 8!==p((function(){}),"length",{value:8}).length})),v=String(String).split("String"),d=r.exports=function(r,e,n){"Symbol("===String(e).slice(0,7)&&(e="["+String(e).replace(/^Symbol\(([^)]*)\)/,"$1")+"]"),n&&n.getter&&(e="get "+e),n&&n.setter&&(e="set "+e),(!a(r,"name")||c&&r.name!==e)&&(u?p(r,"name",{value:e,configurable:!0}):r.name=e),g&&n&&a(n,"arity")&&r.length!==n.arity&&p(r,"length",{value:n.arity});try{n&&a(n,"constructor")&&n.constructor?u&&p(r,"prototype",{writable:!1}):r.prototype&&(r.prototype=t)}catch(i){}var o=l(r);return a(o,"source")||(o.source=v.join("string"==typeof e?e:"")),r};Function.prototype.toString=d((function toString(){return i(this)&&h(this).source||f(this)}),"toString")},function(t,r,e){var n=e(6),o=e(38),i=Function.prototype,a=n&&Object.getOwnPropertyDescriptor,u=o(i,"name"),c=u&&"something"===function something(){}.name,f=u&&(!n||n&&a(i,"name").configurable);t.exports={EXISTS:u,PROPER:c,CONFIGURABLE:f}},function(t,r,e){var n=e(14),o=e(21),i=e(36),a=n(Function.toString);o(i.inspectSource)||(i.inspectSource=function(t){return a(t)}),t.exports=i.inspectSource},function(t,r,e){var n,o,i,a,u,c,f,s,l=e(52),h=e(4),p=e(14),g=e(20),v=e(43),d=e(38),y=e(36),m=e(53),b=e(54),x="Object already initialized",w=h.TypeError;l||y.state?(a=y.state||(y.state=new(0,h.WeakMap)),u=p(a.get),c=p(a.has),f=p(a.set),n=function(t,r){if(c(a,t))throw w(x);return r.facade=t,f(a,t,r),r},o=function(t){return u(a,t)||{}},i=function(t){return c(a,t)}):(b[s=m("state")]=!0,n=function(t,r){if(d(t,s))throw w(x);return r.facade=t,v(t,s,r),r},o=function(t){return d(t,s)?t[s]:{}},i=function(t){return d(t,s)}),t.exports={set:n,get:o,has:i,enforce:function(t){return i(t)?o(t):n(t,{})},getterFor:function(t){return function(r){var e;if(!g(r)||(e=o(r)).type!==t)throw w("Incompatible receiver, "+t+" required");return e}}}},function(t,r,e){var n=e(4),o=e(21),i=n.WeakMap;t.exports=o(i)&&/native code/.test(String(i))},function(t,r,e){var n=e(34),o=e(40),i=n("keys");t.exports=function(t){return i[t]||(i[t]=o(t))}},function(t,r){t.exports={}},function(t,r,e){var n=e(38),o=e(56),i=e(5),a=e(44);t.exports=function(t,r,e){var u,c,f=o(r),s=a.f,l=i.f;for(u=0;uf;)o(n,e=r[f++])&&(~a(s,e)||c(s,e));return s}},function(t,r,e){var n=e(12),o=e(60),i=e(63),createMethod=function(t){return function(r,e,a){var u,c=n(r),f=i(c),s=o(a,f);if(t&&e!=e){for(;f>s;)if((u=c[s++])!=u)return!0}else for(;f>s;s++)if((t||s in c)&&c[s]===e)return t||s||0;return!t&&-1}};t.exports={includes:createMethod(!0),indexOf:createMethod(!1)}},function(t,r,e){var n=e(61),o=Math.max,i=Math.min;t.exports=function(t,r){var e=n(t);return e<0?o(e+r,0):i(e,r)}},function(t,r,e){var n=e(62);t.exports=function(t){var r=+t;return r!=r||0===r?0:n(r)}},function(t,r){var e=Math.ceil,n=Math.floor;t.exports=Math.trunc||function trunc(t){var r=+t;return(r>0?n:e)(r)}},function(t,r,e){var n=e(64);t.exports=function(t){return n(t.length)}},function(t,r,e){var n=e(61),o=Math.min;t.exports=function(t){return t>0?o(n(t),9007199254740991):0}},function(t,r){t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},function(t,r){r.f=Object.getOwnPropertySymbols},function(t,r,e){var n=e(7),o=e(21),i=/#|\.prototype\./,isForced=function(t,r){var e=u[a(t)];return e==f||e!=c&&(o(r)?n(r):!!r)},a=isForced.normalize=function(t){return String(t).replace(i,".").toLowerCase()},u=isForced.data={},c=isForced.NATIVE="N",f=isForced.POLYFILL="P";t.exports=isForced},function(t,r,e){var n=e(69),o=String;t.exports=function(t){if("Symbol"===n(t))throw TypeError("Cannot convert a Symbol value to a string");return o(t)}},function(r,e,n){var o=n(70),i=n(21),a=n(15),u=n(33)("toStringTag"),c=Object,f="Arguments"==a(function(){return arguments}());r.exports=o?a:function(r){var e,n,o;return r===t?"Undefined":null===r?"Null":"string"==typeof(n=function(t,r){try{return t[r]}catch(e){}}(e=c(r),u))?n:f?a(e):"Object"==(o=a(e))&&i(e.callee)?"Arguments":o}},function(t,r,e){var n={};n[e(33)("toStringTag")]="z",t.exports="[object z]"===String(n)},function(r,e,n){var o,i=n(46),a=n(72),u=n(65),c=n(54),f=n(74),s=n(42),l=n(53)("IE_PROTO"),EmptyConstructor=function(){},scriptTag=function(t){return"