1/* world-state.js ââ é¦é ãæ¤å»çåå§ç©èªãç**å®ä¸çç¸** 2 (UMD:çè¦½å¨æ window.PS_WORLDãNode 端 require;å class-data.js / nav-data.js çæ¨¡å¼)ã 3 4 çºä»éº¼è¦ UMD:SSR èå端**é½**è¦ååä¸ä»¶äº ââ å¾ world.json ç phases æ¾åºç¶åææ®µã 5 ç®æ¥æ·æå¼ãæ id ç¿»æä¸æãçµåºé£å¹¾å¥è©±ãå ©éå寫ä¸å¥å°±æ¯éåç«è¸©éæå¤æ¬¡çå 6 (help é·ç§»é£è¼ªççµè«:å ©ç«¯å寫ä¸å¥ parser ææ¯é端æ¼ç§»ççæ£ä¾æº)ã 7 8 åå·¥: 9 worldstate.js(repo æ ¹) è®æªãå¿«åãéæå¤å® ââ åªç®¡ãæ¿å°è³æã 10 æ¬æª å¼åä¸æè¡¨ãæå¼ãçµå¥ãSSR ç HTML ââ åªç®¡ãæéº¼åç¾ã 11 static/js/index.js åç«¯åæ¸èæ ¡æ£ ââ åªç®¡ãææ°çå¼å¡å DOMã 12 13 â é裡**䏿¨ç®** season/moon/weather:é£äºæ¯ MUD 給ççµè«,ç¶²ç«ç«¯èªå·±ç®å°±ææ¼ç§» 14 (WORLD_STATE_PLAN §3-3)ãå¯ä¸ç®åºä¾çæ¯ãè·é¢ä¸ä¸åææ®µéæå¤ä¹ ã, 15 èå®åªç¨å° world.json èªå·±ç phases è day_lenã 16*/ 17(function(root, factory) { 18 if (typeof module === "object" && module.exports) module.exports = factory(); 19 else root.PS_WORLD = factory(); 20})(typeof self !== "undefined" ? self : this, function() { 21 "use strict"; 22 23 /* ================= ä¸ãæ¥æ·çééµå½±æ ¼ ================= 24 å «çµå¼ï¼å «åææ®µåèªãé·ä»éº¼æ¨£ã,ä¸éçæå»ç±æå¼è£åºä¾ã**調åå°±æ¯èª¿é張表ã** 25 26 shadow çæ¬ä½å°æ CSS:w/h/l/t = width/height/left/top(%),o = opacity, 27 sy = scaleY,kx/ky = skew çå ©åè§åº¦(deg);dial ç hue/br = filter ç 28 hue-rotate(deg) è brightnessã 29 30 â é¨é»å¨æ¯åææ®µç**æ£ä¸é**,䏿¯èµ·é» ââ çç±è¦ phaseAt/frameAt 䏿¹ç說æã 31 â å¤è£¡ opacity çº 0(æ²æå¤ªé½å°±æ²æå½±å),ä½å¹¾ä½ä»ç¶è¦å¡«:æå¼è¦ææ±è¥¿å¯ä»¥èµ°, 32 å¦åå½±åæå¨åæåå°æä¸ä¸ææ¶å¤±ã 33 34 â 任䏿¬ä½é½å¯ä»¥ä¸å¯«æ¸å¼,æ¹å¯« { 天氣id: æ¸å¼, default: æ¸å¼ } ââ frameAt æç § 35 world.weather 廿¥,æ²å°å°ç天氣ä¸å¾éå default(`default` éå key æ¯å¿ å¡«, 36 å¦åæ²å°å°ç天氣æç®åº NaN)ãè¦ noon.br:é¨å¤©/颱風天ä¸åæ²é£éº¼äº®ã 37 38 pbr = .ws-pin-highlight(æ·éåå é¢)ç filter: brightness() ââ è dial ç br æ¯ 39 å ©å±¤åèªç亮度,äºä¸å½±é¿ãå ¨ææ®µåå§å¼é½æ¯ 1(=ä¸èª¿æ´),è¦åãä¸ååå 颿¯è¼äº®ã 40 ä¹é¡çææå°±ç´æ¥æ¹å°æææ®µç pbrã */ 41 var SUNDIAL = { 42 dawn: { 43 w: 26.5, 44 h: 4, 45 l: 41, 46 t: 22, 47 o: 0.2, 48 sy: 1, 49 kx: 84, 50 ky: -26, 51 hue: { 52 "rain": 0, 53 "default": -70 54 }, 55 br: 0.8, 56 pbr: 2, 57 sat: 1, 58 gsat: 0.9, 59 ghue: { 60 "heat": -40, 61 "default": 50 62 } 63 }, 64 sunrise: { 65 w: 26.5, 66 h: 5, 67 l: 39, 68 t: 20, 69 o: { 70 "rain": 0.2, 71 "drizzle": 0.2, 72 "typhoon": 0.25, 73 "snow": 0.25, 74 "cloudy": 0.25, 75 "cold_wave": 0.25, 76 "default": 0.3, 77 "heat": 0.6 78 }, 79 sy: 1, 80 kx: 79, 81 ky: -26, 82 hue: { 83 "rain": 0, 84 "default": -4 85 }, 86 br: { 87 // "rain": 0.8, 88 "typhoon": 0.8, 89 "drizzle": 0.8, 90 "snow": 0.8, 91 "cloudy": 0.85, 92 "cold_wave": 0.85, 93 "default": 0.9, 94 "heat": 1.2 95 }, 96 pbr: { 97 // "rain": 2.1, 98 "typhoon": 2.1, 99 "drizzle": 2.2, 100 "snow": 2.2, 101 "cloudy": 2.2, 102 "cold_wave": 2.2, 103 "default": 3, 104 "heat": 3.5 105 }, 106 sat: 1, 107 gsat: 1, 108 ghue: { 109 "heat": -40, 110 "default": 0 111 } 112 }, 113 morning: { 114 w: 26.5, 115 h: 5, 116 l: 40, 117 t: 19, 118 o: { 119 "rain": 0.2, 120 "drizzle": 0.2, 121 "typhoon": 0.25, 122 "snow": 0.25, 123 "cloudy": 0.25, 124 "cold_wave": 0.25, 125 "default": 0.4, 126 "heat": 0.7 127 }, 128 sy: 1, 129 kx: 67, 130 ky: -26, 131 hue: 0, 132 br: { 133 // "rain": 0.8, 134 "typhoon": 0.8, 135 "drizzle": 0.85, 136 "snow": 0.9, 137 "cloudy": 0.9, 138 "cold_wave": 1, 139 "default": 1.1, 140 "heat": 1.5 141 }, 142 pbr: { 143 // "rain": 1.7, 144 "typhoon": 1.7, 145 "drizzle": 1.7, 146 "snow": 2, 147 "cloudy": 2, 148 "cold_wave": 2, 149 "default": 2.5, 150 "heat": 3
151 }, 152 sat: 1, 153 gsat: 1, 154 ghue: { 155 "heat": -40, 156 "default": 0 157 } 158 }, 159 noon: { 160 w: 26, 161 h: 0.1, 162 l: 41, 163 t: 26, 164 o: { 165 "rain": 0.2, 166 "drizzle": 0.25, 167 "typhoon": 0.3, 168 "snow": 0.3, 169 "cloudy": 0.3, 170 "cold_wave": 0.4, 171 "default": 0.8, 172 "heat": 0.8 173 }, 174 sy: -1, 175 kx: -89, 176 ky: 26, 177 hue: { 178 "rain": 0, 179 "default": 4 180 }, 181 br: { 182 // "rain": 0.9, 183 "typhoon": 0.9, 184 "drizzle": 0.9, 185 "snow": 1, 186 "cloudy": 1, 187 "cold_wave": 1.1, 188 "default": 1.4, 189 "heat": 1.6 190 }, 191 pbr: { 192 // "rain": 1, 193 "typhoon": 1, 194 "drizzle": 1, 195 "snow": 1, 196 "cloudy": 1, 197 "cold_wave": 1, 198 "default": 1.4, 199 "heat": 1.1 200 }, 201 sat: 1, 202 gsat: 1, 203 ghue: { 204 "heat": -40, 205 "default": 0 206 } 207 }, 208 afternoon: { 209 w: 26.5, 210 h: 3, 211 l: 41, 212 t: 23.5, 213 o: { 214 "rain": 0.2, 215 "drizzle": 0.2, 216 "typhoon": 0.25, 217 "snow": 0.25, 218 "cloudy": 0.25, 219 "cold_wave": 0.25, 220 "default": 0.4, 221 "heat": 0.7 222 }, 223 sy: -1, 224 kx: -74, 225 ky: 26, 226 hue: { 227 "rain": 0, 228 "default": -15 229 }, 230 br: { 231 "typhoon": 0.8, 232 "drizzle": 0.85, 233 "snow": 0.95, 234 "cloudy": 0.95, 235 "cold_wave": 1.05, 236 "default": 1.2, 237 "heat": 1.4 238 }, 239 pbr: 1, 240 sat: 1, 241 gsat: 1, 242 ghue: { 243 "heat": -40, 244 "default": 0 245 } 246 }, 247 evening: { 248 w: 26.5, 249 h: 15, 250 l: 41, 251 t: 11, 252 o: { 253 "rain": 0.1, 254 "drizzle": 0.1, 255 "typhoon": 0.15, 256 "snow": 0.15, 257 "cloudy": 0.15, 258 "cold_wave": 0.15, 259 "default": 0.2, 260 "heat": 0.5 261 }, 262 sy: -1, 263 kx: -37, 264 ky: 26, 265 hue: { 266 "rain": 0, 267 "default": -35 268 }, 269 br: { 270 "typhoon": 0.6, 271 "drizzle": 0.65, 272 "snow": 0.65, 273 "cloudy": 0.6, 274 "cold_wave": 0.7, 275 "default": 0.8, 276 "heat": 1 277 }, 278 pbr: 1, 279 sat: 2, 280 gsat: 0.8, 281 ghue: { 282 "heat": -40, 283 "default": 0 284 } 285 }, 286 night: { 287 w: 26.5, 288 h: 22, 289 l: 41, 290 t: 4, 291 o: 0, 292 sy: -1, 293 kx: 0, 294 ky: 26, 295 hue: { 296 "rain": 0, 297 "default": -180 298 }, 299 br: 0.4, 300 pbr: 1, 301 sat: 1, 302 gsat: 0.8, 303 ghue: { 304 "heat": -0, 305 "default": 160 306 } 307 }, 308 midnight: { 309 w: 26.5, 310 h: 4, 311 l: 41, 312 t: 22, 313 o: 0, 314 sy: 1, 315 kx: 87, 316 ky: -26, 317 hue: { 318 "rain": 0, 319 "default": -122 320 }, 321 br: 0.3, 322 pbr: 1, 323 sat: 1, 324 gsat: 0.7, 325 ghue: { 326 "heat": -0, 327 "default": 160 328 } 329 } 330 }; 331 332 var FIELDS = ['w', 'h', 'l', 't', 'o', 'sy', 'kx', 'ky', 'hue', 'br', 'pbr', 'sat', 'gsat', 'ghue']; 333 334 /* ================= äºãä¸æé¡¯ç¤ºå ================= 335 â é幾張表æ¯**ç¶²ç«ç«¯ç**,MUD åªçµ¦ ascii id;å°ä¸åå°±æå¨é é¢ä¸è®æè£¸ token 336 (WORLD_STATE_PLAN §4-4)ã */ 337 var CN_PHASE = { 338 dawn: '黿', 339 sunrise: 'æ¥åº', 340 morning: 'ä¸å', 341 noon: 'ä¸å', 342 afternoon: 'ä¸å', 343 evening: 'åæ', 344 night: '夿', 345 midnight: '忍' 346 }; 347 var CN_WEATHER = { 348 clear: 'æ´æ', 349 cloudy: 'é°å¤©', 350 breeze: '微風', 351 drizzle: 'ç´°é¨', 352 rain: '大é¨', 353 typhoon: '颱風', 354 snow: 'ä¸éª', 355 cold_wave: '坿µ', 356 heat: '髿º«' 357 }; 358 // â 䏿çãæ°æã䏿¯å¤©æå¸ç new moon(飿¯ææ),ç §é張表ä¸è¦ç §åé¢ç¿» 359 var CN_MOON = { 360 new_moon: 'ææ', 361 waxing_crescent: 'æ°æ', 362 first_quarter: 'ä¸å¼¦æ', 363 waxing_gibbous: '漸çæ', 364 full_moon: '滿æ', 365 waning_gibbous: 'è§å¸æ', 366 last_quarter: 'ä¸å¼¦æ', 367 waning_crescent: 'æ®æ' 368 }; 369 var CN_SEASON = { 370 spring: 'æ¥', 371 summer: 'å¤', 372 autumn: 'ç§', 373 winter: 'å¬' 374 }; 375 var CN_PALACE = { 376 aries: 'ç¡ç¾', 377 taurus: 'éç', 378 gemini: 'éå', 379 cancer: 'å·¨è¹', 380 leo: 'ç å', 381 virgo: 'è女', 382 libra: '天秤', 383 scorpio: '天è ', 384 sagittarius: 'å°æ', 385 capricorn: 'æ©ç¾¯', 386 aquarius: 'æ°´ç¶', 387 pisces: 'éé' 388 }; 389 var CN_NUM = ['ã', 'ä¸', 'äº', 'ä¸', 'å', 'äº', 'å ', 'ä¸', 'å «', 'ä¹', 'å', 'åä¸', 'åäº']; 390 391 /* badge åé¢ã天氣ä¹ç¨®+彩è¹+åäºæåº§+æç¸å «ç¨®+å°æ²³æ+ç«å±±å·²ææåç´ å(image/sundial/*.png,ART_STYLE_GUIDE §1-2), 392 face çç©ºãæ¹ç± CSS ä¾ data-weather / data-kind=rainbow / data-
392palace / data-moon / data-kind=ice / data-kind=volcano 393 ç¨ background-image ç«(è¦ library.css 尿鏿å¨)ãæ¥µå (aurora)åå·²åå¥½å¨ image/sundial/,ä½éæ²æå°æç 394 badge è³ææ¬ä½æ kind,å 䏿¥ââç gameplay 端ççæéåäºä»¶åç §é忍¡å¼æ¥é²ä¾ã */ 395 var FACE_WEATHER = { 396 clear: '', 397 cloudy: '', 398 breeze: '', 399 drizzle: '', 400 rain: '', 401 typhoon: '', 402 snow: '', 403 cold_wave: '', 404 heat: '' 405 }; 406 var FACE_MOON = { 407 new_moon: '', 408 waxing_crescent: '', 409 first_quarter: '', 410 waxing_gibbous: '', 411 full_moon: '', 412 waning_gibbous: '', 413 last_quarter: '', 414 waning_crescent: '' 415 }; 416 var FACE_PALACE = { 417 aries: '', 418 taurus: '', 419 gemini: '', 420 cancer: '', 421 leo: '', 422 virgo: '', 423 libra: '', 424 scorpio: '', 425 sagittarius: '', 426 capricorn: '', 427 aquarius: '', 428 pisces: '' 429 }; 430 431 /* å¤©æ°£ç¹æå±¤(é¨/éª/風å¹è½è/䏿µ®å æå ±ç¨)ç強度表:åä¸ç¨®å¤©æ°£ä¸çµæ¸å,cls 決å®å¥åªå¥è¦è¦º 432 (é¨çµ²/éªè±/è½è/å æ)ââ è¦èª¿ãä¸å¾å¤å¤§ã風å¤å¼·ãé§å¤æ¿ãæ¹é張表就好,ä¸å¿ 碰ç¢çé輯 433 (weatherParticlesHtml)ãè½ä¸è§åº¦/éªè±å¤è§/è½èå½¢ç/å æé¡è²æ¯ CSS çäº(è¦ library.css ç 434 .wx-<weather> .ws-rain-drop / .ws-snow-flake / .ws-leaf / .ws-glow),å çºé£å°åä¸ç¨®å¤©æ°£ 435 æ°¸é æ¯åä¸åå¼,ä¸å¿ éæ»´ç®ã 436 â ui.js(ç¢çé¦é çææå±¤)è sundial.html(æ²çéå¹é繪)å ©éé½è¦ç¨åä¸ä»½å¼·åº¦è¡¨, 437 å寫ä¸ä»½å°±æ¯éåæªæ¡éé 說çé£åå,æä»¥æ¾å¨é裡ç¶å¯ä¸çç¸ã 438 é¨ç¨ len/w(é¨çµ²é·åº¦/ç²ç´°);éª/å æç¨ len ç¶ç´å¾ãå¤ä¸å swayMax(å·¦å³é£çæ¯å¹ ,px); 439 è½èç¨ len ç¶èç大å°ãå¤ä¸å bobMax(é£é廿ä¸ä¸æåçæ¯å¹ ,px)ã 440 å æ(ç±æ°£)è·éªè±å ±ç¨åä¸å¥ãx 宿©«åä½ç½®+sway å·¦å³é£ãççæé輯,åªæ¯æ¹ååéä¾ 441 ç± CSS ç keyframes 決å®å¾ä¸é£,䏿¯å¾ä¸æ,æä»¥ JS ééä¸ç¨å¦å¤åæ¯ã 442 â å¼ä¹å¯ä»¥æ¯**é£å**(åä¸ç¨®å¤©æ°£çå¤å±¤ææ,weatherParticlesHtml ææ¤å¹³é£åãæ¯å±¤ 443 åèªç䏿¹ååä½µæä¸ä»½ HTML)ââç®åæ²æå¤©æ°£å¨ç¨,æ¾ç¶æ¯ rain/drizzle çæ°´è±å±¤, 444 æ¿æäºä½ç¢çé輯çè,ä¹å¾è¦çå¥ç層å¯ä»¥ç´æ¥ç¨ã 445 ç´°é¨ï¼å¤§é¨æ»´æ¸çä¸åã微風ï¼é¢±é¢¨èçæ¸ç 35%,å ©çµé½ç¨å ¬å¼å¾ä¸»å¤©æ°£ç®,ä¸å¯«æ»ç¬¬äºåæ¸åã 446 â `nightScale`(é¸å¡«)ï¼**å ¥å¤ä¹å¾éä¸å±¤ç黿¸è¦ä¹ä¸å¤å°**(è¦ heat)ãéæ¯å¼·åº¦è¡¨è£¡ 447 å¯ä¸ä¸åè·æéæéçæ¬ä½,é å¥çæ¯ weatherKey:æé忬ä½ç天氣,鵿æå¸¶æ¥å¤ã */ 448 var RAIN_N = 63; // 大é¨çæ»´æ¸(忬 42 ç 1.5 å,大é¨å¼·åº¦ +50%) 449 var LEAF_N = 12; // 颱風çèçæ¸ 450 var PARTICLE_CFG = { 451 drizzle: { 452 cls: 'ws-rain-drop', 453 n: Math.round(RAIN_N * 0.5), 454 durMin: 1.3, 455 durMax: 1.9, 456 opMin: .35, // éæåº¦/ç²ç´°è大é¨ä¸è´(使ç¨è è¦æ±),åªç¨æ»´æ¸/é·åº¦/é度åè¾¨å ©ç¨®é¨ 457 opMax: .7, 458 lenMin: 7, 459 lenMax: 13, 460 wMax: 2 461 }, 462 rain: { 463 cls: 'ws-rain-drop', 464 n: RAIN_N, 465 durMin: 0.45, 466 durMax: 0.75, 467 opMin: .35, 468 opMax: .7, 469 lenMin: 16, 470 lenMax: 28, 471 wMax: 2 472 }, 473 snow: { 474 cls: 'ws-snow-flake', 475 n: 36, 476 durMin: 3.5, 477 durMax: 6.5, 478 opMin: .5, 479 opMax: .95, 480 lenMin: 4, 481 lenMax: 9, 482 swayMax: 22 483 }, 484 breeze: { 485 cls: 'ws-leaf', 486 n: Math.round(LEAF_N * 0.4), 487 durMin: 3.2, 488 durMax: 5.0, 489 opMin: .55, 490 opMax: .85, 491 lenMin: 11, 492 lenMax: 18, 493 bobMax: 14 494 }, 495 typhoon: { 496 cls: 'ws-leaf', 497 n: LEAF_N, 498 durMin: 0.9, 499 durMax: 1.6, 500 opMin: .55, 501 opMax: .85, 502 lenMin: 11, 503 lenMax: 18, 504 bobMax: 30 505 }, 506 // ç±æ°£:æ¹æè·å¯æµä¸æ¨£å¤§ç模ç³çé¢¨æ ¼(é¡è²ä»æ¯ææ©ãæ¹å仿¯ä¸æµ®,åªæ¯é«ç©/模ç³/éæåº¦æ¯ç § 507 // PARTICLE_CFG.cold_wave é£çµã大èç³èæ·¡ãçæ¸å調,䏿¯åæ¬é£ç¨®å°é¡äº®é»å æ) 508 heat: { 509 cls: 'ws-glow', 510 n: 8, 511 durMin: 5.25, // åæ ¢ 50%(å 3.5) 512 durMax: 8.25, // åæ ¢ 50%(å 5.5) 513 opMin: .22, 514 opMax: .45, 515 lenMin: 40, // 100% åºæº 516 lenMax: 80, // 200%(å 68 調æ´çºåºæºçå ©å) 517 swayMax: 12, 518 // â å ¥å¤(夿/忍)ä¹å¾ç±æ°£éå»ä¸å ââ ç®åå¯ä¸ä¸å**æé¨ææ®µè®**ç天氣強度ã 519 // ä»»ä½ä¸çµé½å¯ä»¥å é忬ä½;å äºä¹å¾ weatherKey ææææ¥å¤å¯«é²éµ,é£ä¸å±¤ææå¨å ¥å¤æéç 520 // (æ²å ç天氣éµè£¡ä¸å¸¶æ¥å¤ ââ å¦åé¨/éªæå¨åæç½ç½éç䏿¹,æ´çé¨çµ²åææ¸é¶)ã 521 nightScale: 0.5 522 },
523 // 坿µ:å¤§çæ¨¡ç³ã徿·¡çç½é§æ©«åé£éç«é¢(éç·£æå½±çæ¬éç太ç硬,æ¹åç²å); 524 // è·è½èå ±ç¨ãy å®ç¸±åä½ç½®+左峿©«é£ãé£çµæ¬ä½(bobMax é裡æ¯é£é廿çä¸ä¸èµ·ä¼,䏿¯ç¿»æ»¾) 525 cold_wave: { 526 cls: 'ws-mist', 527 n: 8, 528 durMin: 7, 529 durMax: 11, 530 opMin: .22, 531 opMax: .45, 532 lenMin: 46, 533 lenMax: 78, 534 bobMax: 10 535 } // opMin/opMax 調é«ãn 調é«:忬 .06~.16 é 20px 鿍¡ç³,alpha 被æ¤å¾å¤ªè,å°æ¥æ·å¹¾ä¹æ²è¦è¦ºå½±é¿ 536 }; 537 538 /* è¢ç«è² ââ **ç°å¢ææ**,䏿¯å¤©æ°£ææ(2026-09-07 æ°å¢),æä»¥å¦å¤ä¸å¼µè¡¨ã 539 PARTICLE_CFG ç鵿¯å¤©æ°£ idãä¸ç¨®å¤©æ°£ä¸çµæ¸å;è¢ç«è²çåºæ²å»æ¯ä¸åæ¢ä»¶åææç«: 540 â ææ®µ:æ´åã夿ã+ã忍ãçå FIREFLY_CUT(=åå) 541 ⡠天氣:æ²æé¢¨é¨çå種(æ´æ/é°å¤©/微風/髿º«)ââ ä¸é¨é¢³é¢¨ä¸éªçå¤è£¡æ²æè¢ç«è² 542 ⢠å£ç¯:å¤å£æå¤,æ¥/ç§ 60%ãå¬å£ 30%(FIREFLY_SEASON çåç) 543 â éæ¯ç¬¬ä¸å**æå¨åä¸ç¨®å¤©æ°£è£¡é¨æéåºæ²**çææ ââ 天氣層åªå¨å¤©æ°£è®åæé建, 544 éå±¤è¦æ¯ç§æ¯å° fireflyKey(è¦ world-state-ui.js ç buildEnvFx),å ©å±¤ä¸è½æ··å¨ä¸èµ·ã 545 â 黿¸åªå¯«ä¸ååºæº FIREFLY_N,å ¶é¤å£ç¯ä¸å¾ç¨åçç®åºä¾,ä¸å¯«æ»ç¬¬äºåæ¸å 546 ââèãç´°é¨ï¼å¤§é¨çä¸åã微風ï¼é¢±é¢¨ç 35%ãåä¸ååæ³,è¦èª¿æ´åªæ¹ä¸èã 547 â å°æ²³æ(world.ice_age)ä¸å¾ä¸åºç¾:å°æ²³æç天氣å¯è½æ¯é°å¤©(ç®å¹³é),ä½ 548 ãå°æ²³æç± 罩大å°ãèæ»¿å ´è¢ç«è²æ¯ææ¶çæäºãè¦æ¾è¡å°±æ fireflyOn é£ä¸è¡æ¿æã 549 ç²åæ¬ä½èéªè±é£çµç¸è¿,å¤å ©çµ:--dx/--dy æ¯æ¼ç§»çæ¹åèè·é¢(px,æ£è² çæ), 550 --bdur/--bdelay æ¯**éç**èªå·±ç鱿 ââ æ¼ç§»èéçæ¯å ©æ¢åèªç¨ç«ç animation, 551 鱿ä¸åæ¥æåççè¢ç«è²(è¦ library.css ç wsFireflyDrift / wsFireflyBlink)ã 552 --y çæ»¿æ´å±¤çé«åº¦(yMin~yMax 幾乿¯ 0~100):第ä¸çåªçä¸å(40~92)æ³åãè²¼èèå¢é£ã, 553 實éçèµ·ä¾æ¯æ´ç¾¤æ å¨ä¸éåä¸ç䏿¢å¸¶å ââ è¢ç«è²è©²æ¯æ£å¨æ´åç«é¢è£¡çã 554 â ä¸ä¸åç 3% æ¯å çºæ¯é»éæåæ¼ç§» ±driftMax(px):è²¼èéçæçé£å¹¾é»æä¸åæé卿¡å¤ 555 (é£ä¸å±¤ overflow:hidden,䏿é²åºå»,åªæ¯ç½ç)ã */ 556 var FIREFLY_N = 18; // å¤å£ç黿¸(åºæº) 557 var FIREFLY_SEASON = { 558 summer: 1, 559 spring: 0.6, 560 autumn: 0.6, 561 winter: 0.3 562 }; 563 // å¹³é天氣:æ´æ/é°å¤©/微風/髿º«ãâ 髿º«æ¯ 9/7 è£ç ââ å®èªå·±ä¹æä¸å±¤ææ(䏿µ®çææ©å æ, 564 // PARTICLE_CFG.heat),å ©å±¤æåæå¨:å æå¨ .ws-wxfx(z-index 4)ãè¢ç«è²å¨ .ws-envfx(5),䏿äºç¸èæã 565 var FIREFLY_CALM = ['clear', 'cloudy', 'breeze', 'heat']; 566 var FIREFLY_CUT = 0.5; // 忍éäºé忝ä¾å°±æ£å» 567 var FIREFLY_CFG = { 568 cls: 'ws-firefly', 569 durMin: 6, // æ¼ç§»ä¸è¶çç§æ¸(æ ¢:è¢ç«è²æ¯é£ç,䏿¯é£ç) 570 durMax: 11, 571 opMin: .55, // éå°æäº®æçéæåº¦ 572 opMax: 1, 573 lenMin: 4.5, // ç´å¾(px)ã9/7 使ç¨è è¦æ±æ´é«æ¾å¤§ 50%(å 3~6)ââ 574 lenMax: 9, // å æ(library.css ç drop-shadow)廿æ²è·èæ¾å¤§,飿¯åºå®å¯¬åº¦çæ,æ¾å¤§æç³æ 575 driftMax: 46, // --dx/--dy çæ¯å¹ ä¸é(px) 576 yMin: 3, // 縱åç¯å(%):幾乿¯æ´å±¤çé«åº¦,䏿¯åªæä¸å 577 yMax: 97, 578 blinkMin: 1.6, // 䏿¬¡ææ» çç§æ¸ 579 blinkMax: 3.4 580 }; 581 582 /* ================= ä¸ãå°å·¥å · ================= */ 583 584 var esc = function(s) { 585 return String(s == null ? '' : s) 586 .replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); 587 }; 588 589 // ç§ â ã3 å 20 ç§ã/ã45 ç§ã/ã39 åã(è¶ éååéå°±ä¸å ±ç§,å å¾ä¸åä¸éè¦çæ¸åä¸ç´è·³) 590 var fmtDur = function(sec) { 591 sec = Math.max(0, Math.round(sec)); 592 var m = Math.floor(sec / 60), 593 s = sec % 60; 594 if (m >= 10) return m + ' å'; 595 if (m) return m + ' å' + (s ? ' ' + s + ' ç§' : ''); 596 return s + ' ç§'; 597 }; 598 599 var lerp = function(a, b, u) { 600 return a + (b - a) * u; 601 }; 602 603 // æ·ºè¤è£½ä¸çµå¼·åº¦è¨å®(è¦æ¹å ¶ä¸ä¸å ©åæ¸ååä¸è½åå°è¡¨æ¬èº«:è¡¨æ¯æ¨¡çµå±¤çå®ä¸çç¸,æ¹äºæç´¯ç©) 604 var copyCfg = function(src, over) { 605 var out = {};
606 Object.keys(src).forEach(function(k) { out[k] = src[k]; }); 607 Object.keys(over || {}).forEach(function(k) { out[k] = over[k]; }); 608 return out; 609 }; 610 611 // ä¾å®ä¸å±¤å¼·åº¦é¨æ©ç䏿¹ç²å(é¨çµ²/éªè±/è½è/å æ/é§å/æ°´è±,ç± cfg.cls 決å®)ã 612 var layerHtml = function(cfg) { 613 var html = ''; 614 for (var i = 0; i < cfg.n; i++) { 615 var dur = cfg.durMin + Math.random() * (cfg.durMax - cfg.durMin); 616 var vars = '--op:' + (cfg.opMin + Math.random() * (cfg.opMax - cfg.opMin)).toFixed(2) + ';' + 617 '--dur:' + dur.toFixed(2) + 's;' + 618 '--delay:-' + (Math.random() * dur).toFixed(2) + 's;'; 619 if (cfg.cls === 'ws-snow-flake' || cfg.cls === 'ws-glow') { 620 // éª/å æ:left% 宿©«åä½ç½®ãlen ç¶ç´å¾ãsway æ¯å·¦å³é£çæ¯å¹ (æ£è² çæå¯è½); 621 // å¾ä¸é£éæ¯å¾ä¸ææ¯ CSS keyframes çäº(è¦ wsSnowFall / wsGlowRise),éè£¡å ©è å ±ç¨åä¸çµæ¬ä½ã 622 vars += '--x:' + (Math.random() * 100).toFixed(1) + '%;' + 623 '--size:' + (cfg.lenMin + Math.random() * (cfg.lenMax - cfg.lenMin)).toFixed(1) + 'px;' + 624 '--sway:' + ((Math.random() * 2 - 1) * cfg.swayMax).toFixed(0) + 'px;'; 625 } else if (cfg.cls === 'ws-leaf' || cfg.cls === 'ws-mist') { 626 // è½è/é§å:æ©«è被風å¹éå»,top% å®ç¸±åä½ç½®;len ç¶å¤§å°ãbob æ¯é£é廿ä¸ä¸èµ·ä¼çæ¯å¹ 627 // (è½èç bob é 翻滾 rotate æ¯ãæè½ã,é§åç bob æ²æ rotate æ¯å®ç´ãèµ·ä¼ã,å·®ç°å¨ CSS) 628 vars += '--y:' + (Math.random() * 100).toFixed(1) + '%;' + 629 '--size:' + (cfg.lenMin + Math.random() * (cfg.lenMax - cfg.lenMin)).toFixed(1) + 'px;' + 630 '--bob:' + ((Math.random() * 2 - 1) * cfg.bobMax).toFixed(0) + 'px;'; 631 } else if (cfg.cls === 'ws-firefly') { 632 // è¢ç«è²:x/y å®ä½ç½®(y çç¯åè¦ FIREFLY_CFG.yMin/yMax,æ¶µèæ´å±¤é«åº¦)ãlen ç¶ç´å¾, 633 // dx/dy æ¯æ¼ç§»çæ¹åèè·é¢(æ£è² çæå¯è½),bdur/bdelay æ¯**éç**èªå·±ç鱿 ââ 634 // æ¼ç§»(--dur)èéç(--bdur)æ¯å ©æ¢ç¨ç«ç animation,ä¸åæ¥æåççè¢ç«è²ã 635 var bdur = cfg.blinkMin + Math.random() * (cfg.blinkMax - cfg.blinkMin); 636 vars += '--x:' + (Math.random() * 100).toFixed(1) + '%;' + 637 '--y:' + (cfg.yMin + Math.random() * (cfg.yMax - cfg.yMin)).toFixed(1) + '%;' + 638 '--size:' + (cfg.lenMin + Math.random() * (cfg.lenMax - cfg.lenMin)).toFixed(1) + 'px;' + 639 '--dx:' + ((Math.random() * 2 - 1) * cfg.driftMax).toFixed(0) + 'px;' + 640 '--dy:' + ((Math.random() * 2 - 1) * cfg.driftMax).toFixed(0) + 'px;' + 641 '--bdur:' + bdur.toFixed(2) + 's;' + 642 '--bdelay:-' + (Math.random() * bdur).toFixed(2) + 's;'; 643 } else { 644 // é¨:å¾ä¸é¢æä¸ä¾,left% 宿©«åä½ç½®;len/w æ¯é¨çµ²çé·åº¦èç²ç´° 645 vars += '--x:' + (Math.random() * 100).toFixed(1) + '%;' + 646 '--len:' + (cfg.lenMin + Math.random() * (cfg.lenMax - cfg.lenMin)).toFixed(0) + 'px;' + 647 '--w:' + (1 + Math.random() * (cfg.wMax - 1)).toFixed(1) + 'px;'; 648 } 649 html += '<i class="' + cfg.cls + '" style="' + vars + '"></i>'; 650 } 651 return html; 652 }; 653 654 // å¼å«ç«¯å¯è½åªçµ¦å¤©æ°£ id(è寫æ³),ä¹å¯è½çµ¦æ´å world ââ å¾è ææ¿å¾å°ææ®µ, 655 // æç¥éè¦ä¸è¦å¥ nightScaleãçµ±ä¸å¨éè£¡æ¶ææ { weather: ... }ã 656 var asWorld = function(world) { 657 return (world && typeof world === 'object') ? world : { weather: world }; 658 }; 659 660 /* ä¾ PARTICLE_CFG çå¼·åº¦é¨æ©ç䏿¹ç²å;天氣æ²å°å°ä»»ä½ä¸çµå°±åå³ç©ºå串 661 (å¼å«ç«¯æ±ºå®è¦ä¸è¦é£å®¹å¨ä¸èµ·ææ)ãå¼å¯ä»¥æ¯å®å±¤ config,ä¹å¯ä»¥æ¯**é£å** 662 (åä¸ç¨®å¤©æ°£çå¤å±¤ææ,ä¾å¦ rain/drizzle é¤äºé¨çµ²éè¦å æ°´è±),å ©ç¨®é½åã 663 â 第ä¸å忏è«çµ¦ **world ç©ä»¶**(é 第äºå忏 elapsed):åªçµ¦å¤©æ°£ id çè寫æ³ä»ç¶å¯ç¨, 664 ä½é£æ¨£æ¿ä¸å°ææ®µ,`nightScale` 就䏿çæ(髿º«å ¥å¤å¾ä¸ææ¸å)ã */ 665 var weatherParticlesHtml = function(world, elapsed) { 666 var w = asWorld(world); 667 var cfg = PARTICLE_CFG[w.weather]; 668 if (!cfg) return ''; 669 var night = (world && typeof world === 'object') && isNightPhase(w, elapsed); 670 var layers = Array.isArray(cfg) ? cfg : [cfg]; 671 return layers.map(function(one) { 672 if (!night || one.nightScale == null) return layerHtml(one); 673 return layerHtml(copyCfg(one, { n: Math.round(one.n * one.nightScale) })); 674 }).join(''); 675 }; 676 677 /* 給å¼å«ç«¯å¤æ·ã天氣éä¸å±¤è¦ä¸è¦é建ãç¨çéµ(å fireflyKey çè§è²)ã 678 â åªæ**帶 nightScale ç天氣**æææ¥å¤å¯«é²éµ ââ ä¸å¾å¯«ç話,é¨/éªä¹æå¨å ¥å¤é£ä¸ç§ 679 æ´å±¤éç,滿ç«é¢çé¨çµ²åææ¸é¶åå°èµ·é»,çå¾åºä¾ã */ 680 var weatherKey = function(world, elapsed) { 681 var w = asWorld(world); 682 var cfg = PARTICLE_CFG[w.weather]; 683 if (!cfg) return String(w.weather); 684 var layers = Array.isArray(cfg) ? cfg : [cfg]; 685 var timed = layers.some(function(one) { return one.nightScale != null; }); 686 if (!timed) return String(w.weather); 687 return w.weather + (isNightPhase(w, elapsed) ? '|night' : '|day'); 688 }; 689 690 // SUNDIAL æ¬ä½å¼æ¬ä¾ä¸å¾æ¯æ¸å¼,ç¾å¨ä¹å¯ä»¥æ¯ { 天氣: æ¸å¼, default: æ¸å¼ } ââ 691 // æ²å°å° world.weather ç天氣就éå default(§noon.br æ¯ç¬¬ä¸åä¾å:é¨å¤©/颱風天ä¸åæ¯è¼æ)ã 692 // â åæ ç¨ typeof 夿·,ä¸è½åªçææ²æéå天氣ç key ââ æ¸å¼ä¸è½ç¶ç©ä»¶ç´¢å¼ã 693 var fieldVal = function(v, weather) { 694 if (v !== null && typeof v === 'object') 695 return (weather in v) ? v[weather] : v['default']; 696 return v; 697 }; 698 699 /* ================= åãææ®µ ================= */ 700 701 /* å¾ world.phases é·åºææ®µè¡¨ã**ä¸ç¡¬ç·¨**:MUD 端é£ä»½å¸¸æ¸æ¯å°å¤çå¯ä¸çç¸(§3-3)ã 702 * â æå¾ä¸æ®µå»¶ä¼¸å° day_len ââ åæ®µèµ·é»ç總åä¸ä¸å®çæ¼ day_lenã 703 * 704 * â **æ ¡æ£**(§3-5-2):`phases` 裡çèµ·é»æ¯**åç®ç§æ¸**,è `day_len` æ¯**å¯¦æ¸¬ç§æ¸**ã 705 * éæ²çææ®µæ¯ç¨ `call_out` 䏿®µä¸æ®µæç(ä¸å¤©å «æ¬¡),æ¯æ¬¡çç§ç´é²ä½ç´¯ç©èµ·ä¾ ââ 706 * 實測 day_len=1208 å°±æ¯æ¯æ¬¡é²å°ç´ 1 ç§ Ã 8 段ã䏿 ¡æ£çè©±ç¶²ç«æä¸è·¯æ¯éæ²æ©, 707 * å°ææ¥é£ä¸å»å·®æå¤(8 ç§:ç¶²é å·²ç¶å¯«ã黿ã,éæ²éå¨åæ¨)ã 708 * 709 * `scale = day_len / day_nominal`,å ©åå¼é½ç± MUD 給,ç¶²ç«ç«¯ä¸ç¥é 1200 æ¯ä»éº¼ã 710 * â `day_nominal` æ¯å¾ä¾æå çæ¬ä½:**æ²æå®å°± scale=1**,éåæªæ ¡æ£çè¡çº ââ 711 * æä»¥ç¶²ç«å¯ä»¥å ä¸ãMUD å¾ä¸,é¨ç½²é åºä¸ææã 712 * â 被 clamp çæ¥å(éå/å´é lag)day_len ææ¯åç®å¼ â scale å好 1,èªç¶ä¸æ ¡æ£ã 713 */ 714 var dayScale = function(world) { 715 var nom = world.day_nominal; 716 if (!(nom > 0) || !(world.day_len > 0)) return 1; 717 return world.day_len / nom; 718 }; 719 720 var phases = function(world) { 721 var len = world.day_len; 722 var k = dayScale(world); 723 return world.phases.map(function(row, i, all) { 724 var start = row[0] * k; 725 var end = (i + 1 < all.length) ? all[i + 1][0] * k : len; // æå¾ä¸æ®µå»¶ä¼¸å° day_len 726 return { 727 id: row[1], 728 cn: CN_PHASE[row[1]] || row[1], 729 start: start, 730 end: end, 731 center: (start + end) / 2 732 }; 733 }); 734 }; 735 736 // â åå³ index è䏿¯ç©ä»¶:phases() æ¯æ¬¡é½æ°å»ºé£å,æ¿ç©ä»¶åå» indexOf ä¸å®æ¾ä¸å° 737 // (åå³ -1,(-1+1)%8 = 0 â ãä¸ä¸åææ®µãæ°¸é è®æç¬¬ä¸åã踩éã) 738 var idxAt = function(ps, elapsed) { 739 var i = 0; 740 for (var k = 0; k < ps.length; k++) 741 if (elapsed >= ps[k].start) i = k; 742 return i; 743 }; 744 745 /* â elapsed ä¸å¾å 忍¡åç¨ã 746 `elapsed` æ¯ãè·é¢ day_start å¹¾ç§ã,è day_start åªæææ¥ææé寫 ââ 747 æä»¥å¨ãéæ²å·²ç¶ææ¥ãä½ç¶²ç«éæ²æ¿å°æ°ç world.jsonã飿®µç©ºçª,elapsed æè¶ é day_lenã
748 ä¸å模ç話 idxAt æä¸ç´å卿å¾ä¸æ®µ(忍),`p.end - elapsed` è®æè² æ¸è¢«å¤¾æ 0, 749 **忏就åä½ä¸å**(2026-08-22 使ç¨è 實測åå ±:è·¨æ¥ä¹å¾ç§æ¸ä¸åè®)ã 750 frameAt æ¬ä¾å°±æå模æä»¥æ¥æ·ç §è½,å ©éä¸ä¸è´ææ¯éå bug çæ ¹å ââ ä¸å¾èµ°éå wrapã */ 751 var wrap = function(world, elapsed) { 752 var len = world.day_len; 753 return ((elapsed % len) + len) % len; 754 }; 755 756 var phaseAt = function(world, elapsed) { 757 var ps = phases(world); 758 return ps[idxAt(ps, wrap(world, elapsed))]; 759 }; 760 761 /* ---- è¢ç«è²çåºæ²å¤æ·(å¼·åº¦è¡¨å¨ Â§äº ç FIREFLY_CFG,é£è£¡æå®æ´èªªæ) ---- 762 æ¾å¨é裡æ¯å çºå®è¦ç¨ phaseAt/wrap ââ ä¸åæ¢ä»¶åææç«æåºç¾: 763 ææ®µ(å¤ææ´æ®µ ~ 忍åå)ã天氣平é(æ´æ/é°å¤©/微風)ãéå°æ²³æ;黿¸åçå£ç¯ã 764 765 â ææ®µä¸å¾ç¨ phaseAt ç **id** å¤,ä¸è¦æ¿ frameAt ç亮度æ²ç·å»ç ââ è moonDayNight 766 åä¸åçç±:飿¢æ²ç·ç交çé»è·ãææ®µæ¬èº«å«ä»éº¼ååãå°ä¸ä¸ã 767 â 忍çä¸åç¨**é£åææ®µèªå·±ç**èµ·è¨ç®,䏿¯å¯«æ»ç§æ¸:åæ®µé·åº¦æ¬ä¾å°±ä¸ä¸æ¨£, 768 èä¸ phases() æä¾ day_len æ ¡æ£çæ¯ç¸®æ¾(§3-5-2),寫æ»çç§æ¸ææ ¢æ ¢æ¼æã */ 769 var fireflyOn = function(world, elapsed) { 770 if (!world || world.ice_age) return false; 771 if (FIREFLY_CALM.indexOf(world.weather) < 0) return false; 772 var p = phaseAt(world, elapsed); 773 if (p.id === 'night') return true; 774 if (p.id !== 'midnight') return false; 775 return (wrap(world, elapsed) - p.start) < (p.end - p.start) * FIREFLY_CUT; 776 }; 777 778 // éä¸å¤è©²çå¹¾é»:å¤å£ FIREFLY_N,å ¶é¤å£ç¯ä¹ä¸ FIREFLY_SEASON çåçã 779 // â å¼åå¤çå£ç¯é忥ç§é£ä¸ç´ ââ ä¸è½éå 0,é£æè®ææ**é黿¶å¤±**;ä¹ä¸è©²éåæå¤§å¼ã 780 var fireflyCount = function(world) { 781 var k = (world && (world.season in FIREFLY_SEASON)) ? FIREFLY_SEASON[world.season] : FIREFLY_SEASON.spring; 782 return Math.round(FIREFLY_N * k); 783 }; 784 785 /* 給å¼å«ç«¯å¤æ·ãéä¸å±¤è¦ä¸è¦é建ãç¨çéµ:ä¸åºç¾ææ¯ç©ºå串,åºç¾ææ¯å£ç¯ 786 ââ 黿¸åªè·å£ç¯æé,æä»¥ä¸ç¨®å¹³é天氣ä¹éäºæ**ä¸å¿ **éç䏿¹(鵿²è®å°±å¥åå®, 787 é建æè®ææè¢ç«è²çéçç¸ä½æ¸é¶,çèµ·ä¾åæ´ç¾¤åæç¨ä¸ä¸ç¼)ã */ 788 var fireflyKey = function(world, elapsed) { 789 return fireflyOn(world, elapsed) ? (world.season || '?') : ''; 790 }; 791 792 // éä¸å»è©²æçè¢ç«è² HTML;ä¸è©²åºç¾å°±å空å串(å¼å«ç«¯æ±ºå®è¦ä¸è¦é£å®¹å¨ä¸èµ·ææ) 793 var fireflyHtml = function(world, elapsed) { 794 if (!fireflyOn(world, elapsed)) return ''; 795 var cfg = {}; 796 Object.keys(FIREFLY_CFG).forEach(function(k) { 797 cfg[k] = FIREFLY_CFG[k]; 798 }); 799 cfg.n = fireflyCount(world); 800 return layerHtml(cfg); 801 }; 802 803 /* æ¥æ·çæå¼ã 804 * 805 * é¨é»å¨æ¯åææ®µç**æ£ä¸é**,èä¸ u æ¯ç¨ãåæ®µé²åº¦ãæ£è¦åç: 806 * å¾å段 centerâend å°æ u 0â0.5ãååæ®µ startâcenter å°æ u 0.5â1ã 807 * 808 * çºä»éº¼ä¸ç¨å ©åä¸å¿é»ä¹éççµå°ç§æ¸:å «åææ®µé·åº¦ä¸ä¸æ¨£(90/140/140/140/150/150/210/180), 809 * ç¨çµå°ç§æ¸çè©±ææ®µäº¤ç䏿è½å¨ 0.5 ä¸ ââ é»æåªæ 90 ç§ãæ¥åºæ 140 ç§,交çæåå¨ 39%, 810 * æ¼æ¯ãåé²å ¥æ¥åºãçç«é¢åèæ´æ¥è¿é»æ,èæéçæåèªªæ³ææ¶ã 811 * æ£è¦å徿ä¸åä¹¾æ·¨çæ§è³ª:**u < 0.5 ⺠éå¨éåææ®µ**,交çåå¥½å ©å¼µååã 812 */ 813 var frameAt = function(world, elapsed) { 814 var ps = phases(world), 815 n = ps.length, 816 len = world.day_len; 817 var t = ((elapsed % len) + len) % len; 818 var i = 0; 819 for (var k = 0; k < n; k++) 820 if (t >= ps[k].start) i = k; 821 var p = ps[i], 822 a, b, u; 823 if (t >= p.center) { 824 a = SUNDIAL[p.id]; 825 b = SUNDIAL[ps[(i + 1) % n].id]; 826 u = 0.5 * (t - p.center) / (p.end - p.center); 827 } else { 828 a = SUNDIAL[ps[(i - 1 + n) % n].id]; 829 b = SUNDIAL[p.id]; 830 u = 0.5 + 0.5 * (t - p.start) / (p.center - p.start); 831 } 832 var f = {}; 833 FIELDS.forEach(function(q) { 834 f[q] = lerp(fieldVal(a[q], world.weather), fieldVal(b[q], world.weather), u); 835 }); 836 f._w = (t >= p.center) ? (1 - u) : u; // ç®åéåææ®µä½å¤å°(æ >= 0.5,æ£ä¸é = 1) 837 f._i = i; 838 return f; 839 }; 840 841 // å½±åç inline styleãscaleY 卿£åå徿éé 0 ââ 飿£å¥½æ¯å¤ªé½å¨æ£ä¸æ¹ã 842 // å½±åç¸®å°æ²æåç¿»å°å¦ä¸éçç¬é,䏿¯ bugã 843 // â |scaleY| < 0.91 æç´æ¥ display:none ââ 縮å°å¿« 0 飿®µç¨ CSS 硬æä¼¸çèµ·ä¾åè¢«å£æçåå½±å, 844 // ä¸å¦ä¹¾èèèµ·ä¾(忣 opacity/geometry ä»ç §ç®,åªæ¯ä¸ç«)ã
844 845 var shadowCss = function(f) { 846 var base = 'width:' + f.w.toFixed(2) + '%;height:' + f.h.toFixed(2) + '%;' + 847 'left:' + f.l.toFixed(2) + '%;top:' + f.t.toFixed(2) + '%;opacity:' + f.o.toFixed(3) + ';' + 848 'transform:scaleY(' + f.sy.toFixed(4) + ') skew(' + f.kx.toFixed(2) + 'deg,' + f.ky.toFixed(2) + 'deg)'; 849 if (Math.abs(f.sy) < 0.91) base += ';display:none'; 850 return base; 851 }; 852 853 var dialCss = function(f) { 854 return 'filter:hue-rotate(' + f.hue.toFixed(2) + 'deg) brightness(' + f.br.toFixed(3) + ') saturate(' + f.sat.toFixed(2) + ')'; 855 }; 856 857 // .ws-pin-highlight(æ·éåå é¢)èªå·±çä¸å±¤ filter,åªèª¿ brightness ââ 858 // è dial ç br åéå(pbr)æ¯å çºå ©å±¤è¦è½åèªèª¿,䏿¯åä¸å¡é¢æ¿å ±ç¨ä¸å亮度ã 859 var pinHighlightCss = function(f) { 860 return 'filter:brightness(' + f.pbr.toFixed(3) + ')'; 861 }; 862 863 // .ws-grass èªå·±çä¸å±¤ filter,調 saturate è· hue-rotate ââè· dial ç sat/hue åéå 864 // (gsat/ghue)æ¯å çº .ws-grass æ¯ #ws-dial çåå ç´ ,dial ç filter æ¬ä¾å°±æçå å°å® 865 // 身ä¸,éå ©åæ¯é¡å¤åå çä¸å±¤,æ¸åä¸ç¨è· dial å°é½(æä¸/åæèç飽å度éå° 0.8, 866 // å ¶é¤ 1;ghue æ¯å¤©æ°£æ±ºå®ç,䏿¯ææ®µââ髿º«å¤©èè½ -40deg åé»(æ¯èæ),å ¶é¤å¤©æ°£ 0)ã 867 var grassCss = function(f) { 868 return 'filter:saturate(' + f.gsat.toFixed(2) + ') hue-rotate(' + f.ghue.toFixed(2) + 'deg)'; 869 }; 870 871 // æäº® badge ç亮度:ç½å¤©é»¯æ·¡ãå¤è£¡ç¼äº®,åèªæ¥æ·å䏿¢æ²ç· ââ 調 SUNDIAL ç br, 872 // æäº®èªåè·èæ¹,ä¸å¿ å¨å¥èå寫ä¸çµæ¸åã 873 // â br å¯è½æ¯ { 天氣: æ¸å¼ } ç©ä»¶(§noon)ââ min/max è¦å±éææå¤©æ°£çå¼ä¸èµ·ç®, 874 // å¦åæäº®äº®åº¦æ²ç·åªçå¾å° default é£ä¸åæ¸å,é¨å¤©/颱風天ç®åºä¾ç f.br åèæè¶ åº [min,max]ã 875 var BR = (function() { 876 var v = []; 877 Object.keys(SUNDIAL).forEach(function(k) { 878 var br = SUNDIAL[k].br; 879 if (br !== null && typeof br === 'object') { 880 Object.keys(br).forEach(function(wk) { 881 v.push(br[wk]); 882 }); 883 } else { 884 v.push(br); 885 } 886 }); 887 return { 888 min: Math.min.apply(null, v), 889 max: Math.max.apply(null, v) 890 }; 891 })(); 892 var moonGlow = function(f) { 893 return (BR.max === BR.min) ? 0 : (BR.max - f.br) / (BR.max - BR.min); 894 }; 895 896 // æç¸ badge ç顯è²:ä¸é£çºæ¼¸è®,åºå®ãç½å¤©ãã夿ãå ©æ (class è¦ library.css)ââ 897 // ç´æ¥ç §ææ®µå:åªæ night/midnight ç®å¤æ,å ¶é¤å åææ®µ(å«é»æ/æ¥åº/åæ)ä¸å¾ç½å¤©ã 898 // â ä¸è½ç¨ phaseAt å §é¨æ··åç f._w/br å»å¤æ· ââ 飿¢æ²ç·æ¯çµ¦äº®åº¦æ¼¸è®ç¨ç,交çé» 899 // è·ãææ®µæ¬èº«å«ä»éº¼ååãå°ä¸ä¸(dawn/sunrise/evening ç br å¤ ä½,亮度æ²ç·ææå®å 900 // ç®æå¤æ),å ©è æ¦å¿µä¸å,è¦åéç®ã 901 var moonDayNight = function(world, elapsed) { 902 var id = phaseAt(world, elapsed).id; 903 return (id === 'night' || id === 'midnight') ? 'is-night' : 'is-day'; 904 }; 905 906 // ãç¾å¨ç®ä¸ç®å¤è£¡ãç**å¯ä¸ä¸ä»½**夿º:æç¸ badge çæ¥å¤äºæ ã天氣層ç nightScale é½èµ°éæ¯ã 907 // å坫䏿¬¡ id === 'night' || 'midnight' å°±æ¯æ¼ç§»çèµ·é»(åªå¤©å¤ä¸åææ®µ,åªææä¸é被æ¹å°)ã 908 var isNightPhase = function(world, elapsed) { 909 return moonDayNight(world, elapsed) === 'is-night'; 910 }; 911 912 /* ================= äºãæå ================= */ 913 914 var dateLine = function(world, elapsed) { 915 var c = world.calendar || {}; 916 var ps = phases(world); 917 var t = wrap(world, elapsed); // â è·¨æ¥ä¹å¾ä¸å模çè©±åæ¸æåä½,è¦ wrap ç說æ 918 var i = idxAt(ps, t); 919 var p = ps[i]; 920 var nx = ps[(i + 1) % ps.length]; 921 return { 922 age: 'åå§ä¸ç´ 第' + (CN_NUM[c.age] || c.age) + 'ç´å ', 923 date: c.year + ' å¹´ ' + c.month + ' æ ' + c.day + ' æ¥', 924 season: CN_SEASON[world.season] || world.season, 925 phase: p.cn, 926 // â å端åªå¾éåç§æ¸å¾ä¸æ¸,**ä¸å¯ä»¥**æ¿ Date.now() 廿¸ day_start ââ 927 // 使ç¨è çæéåç§»æè®ææ®µéé»é¯ä½(§2)ã 928 left: Math.max(0, p.end - t), 929 count: 'åé ' + fmtDur(p.end - t) + 'å°±é²å ¥' + nx.cn 930 }; 931 }; 932 933 /* badge æ¸ å®ãåå³å¼è䏿¯ HTML ââ SSR ç¨å®ç¢çæ¨è¨ãå端ç¨å®æ´æ° DOM,åä¸ä»½å¤æ·ã 934 text å 許帶 <b>(æ¿åè¦å¼·èª¿),å ¶é¤ä¸å¾å esc éã */ 935 var badges = function(world, starfall, elapsed) { 936 var out = []; 937 938 out.push({ 939 kind: 'weather', 940 show: true, 941 weather: world.weather, // badgeHtml ç¨å®æ data-weather,CSS 便¤é¸å(FACE_WEATHER ç¾å¨å ¨ç©º) 942 face: FACE_WEATHER[world.weather] || '', 943 label: '天氣ï¼' + (CN_WEATHER[world.weather] || world.weather), // badgeHtml ç¨å®æ aria-label 944 text: 'ä»å¤©å¤©æ°£ï¼' + esc(CN_WEATHER[world.weather] || world.weather) 945 }); 946 947 // ç½å¤©ææç¸éæ²ãéçã,ææ¡åªè¬ææ¯ä»éº¼ãä¸è£ä½çå¾å°;å ¥å¤å¾(moonDayNight)ææ¹å£ 948 // æç¾è¡çç´è¿°å¥ã夿ºè badge åé¢çæ¥å¤äºæ å ±ç¨åä¸å moonDayNight,ä¸è¦å¦éä¸å¥ã 949 out.push({ 950 kind: 'moon', 951 show: true, 952 moon: world.moon, // badgeHtml ç¨å®æ data-moon,CSS 便¤é¸å(FACE_MOON ç¾å¨å ¨ç©º) 953 face: FACE_MOON[world.moon] || '', 954 label: 'æç¸ï¼' + (CN_MOON[world.moon] || world.moon), // badgeHtml ç¨å®æ aria-label 955 text: 'ä»å¤æç¸ï¼' + esc(CN_MOON[world.moon] || world.moon) + 956 (moonDayNight(world, elapsed) === 'is-night' ? '' : 'ï¼å ¥å¤å¾é¡¯ç¾') 957 }); 958 959 /* æµæãâ åªçµ¦å ¬åè£¡çæ¿éåå ââ room pathã座æ¨ãååä¸å¾ä¸çµ¦(§5-4 ç´ ç·): 960 èµ°éæ´ååå廿¾ææ¯éåç©æ³æ¬èº«ã 961 â å ç expire_at åç state:ç£ç¢ä¸é£ä»½å¯è½æ¯ä¸ä¸é¡çæ®éª¸,è claimed çè£å¯« 962 å¨ MUD ééææéºå¤±(§5-5)ãexpired åªæ¯è®æ,badge éå¨ ââ é£é¡æå®®ä»å¤©ä»ç¶å¼ã */ 963 if (starfall) { 964 var zodiac = esc(CN_PALACE[starfall.palace] || starfall.palace) + '座'; 965 var pal = 'æè¿ä¸æ¬¡çæµæåºç¾å¨<b>' + zodiac + '</b>ï¼'; 966 var st = starfall.expired ? 'expired' : (starfall.state === 'claimed' ? 'claimed' : 'fallen'); 967 out.push({ 968 kind: 'starfall', 969 show: true, 970 state: st, 971 palace: starfall.palace, // badgeHtml ç¨å®æ data-palace,CSS 便¤é¸æåº§å(FACE_PALACE ç¾å¨å ¨ç©º) 972 face: FACE_PALACE[starfall.palace] || '', 973 label: 'æµæï¼' + zodiac, // badgeHtml ç¨å®æ aria-label 974 text: st === 'fallen' ? 975 'ä¾èª' + zodiac + 'çæµæå¢è½å¨<b>' + esc(starfall.room_name) + '</b>éè¿ï¼ææç¢çéæ ' + fmtDur(starfall.remain) + ' 徿¶éã' : 976 (st === 'claimed' ? pal + 'æµæå·²ç¶åºç¾ï¼ææç¢ç已被ç¼ç¾ã' : pal + 'æµæå·²ç¶æ¶éï¼ææç¢çç¡äººç¼ç¾ã') 977 }); 978 } else if (world.palace) { 979 /* ç¬¬åæ pending:ä»å¤©éæ²æéæµæã 980 æå®®æ¯**ç¾å¯¦æ¥**ç常æ¸(MUD 端 get_yearday() % 12),åå¤é¶é»å°±å·²ç¶å®äº ââ 981 ä½å®ä»¥ååªå¯«å¨äºä»¶é© åç starfall.json 裡,æä»¥æµææ²æå°±æ´é¡ badge ä¸åºç¾ã 982 æ¹æ world.json ä¹å¸¶ä¸ä»½(æ¯æ¬¡ææ¥é寫)ä¹å¾,éè£¡æææ±è¥¿å¯ä»¥å è¬ã 983 â ä»ç¶**䏿¨ç®**:å¼ç´æ¥è® world.palace,ç¶²ç«ç«¯èªå·±ç® yearday å°±æ¯ Â§3-3 çæ¼ç§»åã 984 â åªè¬æå®®ãä¸è¬å°é» ââ æµæéæ²æ,æ¬ä¾å°±æ²æ room_name å¯è¬(§5-4 ç´ ç·ç §è)ã */ 985 out.push({ 986 kind: 'starfall', 987 show: true,
988 state: 'pending', 989 palace: world.palace, 990 face: FACE_PALACE[world.palace] || '', 991 label: 'æµæï¼' + (CN_PALACE[world.palace] || world.palace) + '座', // badgeHtml ç¨å®æ aria-label 992 text: 'ä¸ä¸æ¬¡æµææåºç¾å¨<b>' + esc(CN_PALACE[world.palace] || world.palace) + '座</b> ââ ä»å¤©çæµæéæªåºç¾ã' 993 }); 994 } 995 996 // 彩è¹:MUD çµ¦çæ¯éç,ç¶²ç«ç«¯åªåå鿝å°(§3-4)ãçªå£å¤æ´é¡ä¸åºç¾ã 997 var rb = world.rainbow; 998 if (rb && elapsed >= rb.from && elapsed < rb.to) { 999 out.push({ 1000 kind: 'rainbow', 1001 show: true, 1002 rare: true, 1003 face: '', // å·²æåç´ å,CSS ä¾ data-kind=rainbow é¸å 1004 label: '彩è¹', // badgeHtml ç¨å®æ aria-label 1005 text: 'é¨å¾æ¾æ´ï¼å¤©éæèä¸éå½©è¹ ââ éçå¾è¦ ' + fmtDur(rb.to - elapsed) + 'ã' 1006 }); 1007 } 1008 1009 if (world.ice_age) { 1010 out.push({ 1011 kind: 'ice', 1012 show: true, 1013 rare: true, 1014 face: '', // å·²æåç´ å,CSS ä¾ data-kind=ice é¸å(/image/sundial/ice_age.png) 1015 label: 'å°æ²³æ', // badgeHtml ç¨å®æ aria-label 1016 text: 'å°æ²³æç± 罩大å°ï¼é段æ¥ååªææä¸éªã坿µèé°å¤©ã' 1017 }); 1018 } 1019 1020 // ç«å±±ï¼natured.c çãç«å±±æ´»èºæã(æ¯é±å,3 æé¤å¤)æéæä»»åãèµ·åºæ°£ã任䏿ç«å°±æ¯ trueââ 1021 // å ©åäºä»¶é½æè§¸ç¼ start_volcano_war() å¨ç¹å®æ´é»éæ°,ä½ç¢ºåæè¾°ä¸å¯«é²éå¥è©±, 1022 // åªè¬ãä¸å¤ªå¹³éãéåç©å®¶çå¾å°ã䏿é¯ççµè«(§5-4 å䏿¢ç´ ç·:å¿ å¯¦è½è¿°,䏿¨ç®ç´°ç¯)ã 1023 if (world.volcano) { 1024 out.push({ 1025 kind: 'volcano', 1026 show: true, 1027 rare: true, 1028 face: '', // å·²æåç´ å,CSS ä¾ data-kind=volcano é¸å(/image/sundial/volcano.png) 1029 label: 'ç«å±±æ´»èºæ', // badgeHtml ç¨å®æ aria-label 1030 text: 'äºå§äºå§ç«å±±æ£å¼æ´»èºæï¼é¨ææ³¨æç«å±±è¦å ±ã' 1031 }); 1032 } 1033 1034 return out; 1035 }; 1036 1037 /* ================= å ãSSR çæ¨è¨ ================= 1038 â å¼ç±å¾ç«¯å¡«å¥½åéåº,**ä¸è¦ SSR åºãè¼å ¥ä¸â¦ã**(æè¢«ç¬è²æèµ°)ã
1038 1039 â æä¸å°è³ææéª¨æ¶è¦çèãæ¸å¼ææãæ«æç¡æ³åå¾ã,å¦åçä½æè·³(§7)ââ 1040 éä¸é»èé¦é {{updates}}ãè®ä¸å°å°±æ´æ®µä¸åºãçæ £ä¾**ç¸å**,å¥é ææ¹æä¸è´ã 1041 MUD æ¯æ¬¡ééæ©å¾çåç´ 18 åéå°±æ¯éåçæ ã */ 1042 var UNAVAILABLE = 'æ«æç¡æ³åå¾'; 1043 1044 var badgeHtml = function(b) { 1045 return '<li class="ws-badge' + (b.rare ? ' is-rare' : '') + '" data-kind="' + b.kind + '"' + 1046 (b.state ? ' data-state="' + b.state + '"' : '') + 1047 (b.weather ? ' data-weather="' + b.weather + '"' : '') + 1048 (b.palace ? ' data-palace="' + b.palace + '"' : '') + 1049 (b.moon ? ' data-moon="' + b.moon + '"' : '') + '>' + 1050 '<button type="button" class="ws-badge-btn" aria-label="' + esc(b.label || b.kind) + '" aria-describedby="ws-pop-' + b.kind + '" aria-expanded="false">' + 1051 '<span class="ws-face" id="ws-face-' + b.kind + '">' + b.face + '</span>' + 1052 '</button>' + 1053 '<span class="ws-pop" id="ws-pop-' + b.kind + '" role="tooltip">' + b.text + '</span>' + 1054 '</li>'; 1055 }; 1056 1057 var renderHtml = function(st) { 1058 var ok = !!(st && st.ok); 1059 var world = ok ? st.world : null; 1060 // è®ä¸å°è³æææ²æ world.weather 坿¥,fieldVal ç第äºååæ¸å³ undefined 1061 // èªç¶è½å°æ¯åæ¬ä½ç default(ç©ä»¶æ¬ä½ä¸å®è¦æ default,å¦åéè£¡ææ¯ NaN)ã 1062 var f = ok ? frameAt(world, st.elapsed) : (function() { 1063 var r = {}; 1064 FIELDS.forEach(function(q) { 1065 r[q] = fieldVal(SUNDIAL.noon[q], undefined); 1066 }); 1067 return r; 1068 })(); 1069 var line = ok ? dateLine(world, st.elapsed) : { 1070 age: 'åå§ä¸ç´', 1071 date: UNAVAILABLE, 1072 season: '', 1073 phase: '', 1074 count: '' 1075 }; 1076 var bs = ok ? badges(world, st.starfall, st.elapsed) : []; 1077 var glow = moonGlow(f); 1078 var moonDN = ok ? moonDayNight(world, st.elapsed) : ''; 1079 1080 // å端è¦éç®,å¾ç¥é world è elapsed ââ â `</` è¦è·³è«,é份 JSON ç´æ¥å¯«é² <script>ã 1081 var data = ok ? { 1082 world: world, 1083 starfall: st.starfall || null, 1084 elapsed: st.elapsed, 1085 // ç¢çé份 HTML ç伺æå¨æå»:å端æ¿å®ç¶åæ¸çèµ·é»,ä¸ç¨èªå·±çæé廿¸ day_start 1086 served_at: st.served_at || 0 1087 } : null; 1088 1089 return '' + 1090 '<section class="worldstate' + (ok ? '' : ' is-blank') + '" id="worldstate"' + 1091 ' aria-labelledby="ws-heading">\n' + 1092 ' <h2 class="cs-heading fontsize2" id="ws-heading">â æ¤å»çåå§ç©èª â</h2>\n' + 1093 ' <div class="ws-block">\n' + 1094 // 天氣 class æå¨**å¤å±¤**:.ws-dial ç filter æ¯æå¼å¯«é²å»ç inline style, 1095 // ææå±¤è¥ä¹ç¨ filter,å¯«å¨ dial ä¸æè¢«èæ;æå¤å±¤å ©å±¤ filter æèªç¶çå ã 1096 ' <div class="ws-stage ' + (ok ? 'wx-' + world.weather + (world.ice_age ? ' is-ice' : '') : '') + '" id="ws-stage">\n' + 1097 ' <div class="ws-dial" id="ws-dial" style="' + dialCss(f) + '" aria-hidden="true">\n' + 1098 ' <div class="ws-grass" id="ws-grass" style="' + grassCss(f) + '"></div>\n' + 1099 ' <div class="ws-pin"></div>\n' + 1100 ' <div class="ws-pin-highlight" id="ws-pin-highlight" style="' + pinHighlightCss(f) + '"></div>\n' + 1101 ' <div class="ws-shadow" id="ws-shadow" style="' + shadowCss(f) + '"></div>\n' + 1102 ' <div class="ws-body"></div>\n' + 1103 ' <div class="ws-cloud-shadow"></div>\n' + 1104 ' </div>\n' + 1105 ' </div>\n' + 1106 ' <div class="ws-text">\n' + 1107 ' <h3 class="ws-date"><span class="ws-age" id="ws-age">' + esc(line.age) + '</span><br>' + 1108 '<span id="ws-date">' + esc(line.date) + '</span>' + 1109 (line.season ? '<span id="ws-season"> (' + esc(line.season) + ')</span>' : ' <span id="ws-season"></span>') + 1110 (line.phase ? ' <span id="ws-phase">' + esc(line.phase) + '</span>' : ' <span id="ws-phase"></span>') + 1111 '</h3>\n' + 1112 ' <p class="ws-next" id="ws-count">' + esc(line.count) + '</p>\n' + 1113 ' <ul class="ws-badges' + (moonDN ? ' ' + moonDN : '') + '" id="ws-badges" style="--moon:' + glow.toFixed(3) + '">' + 1114 bs.map(badgeHtml).join('') + '</ul>\n' + 1115 ' <p class="ws-foot">鿝馬é å天æå°çæ¥æ·ï¼å¯¦æåæ äºåå§ç©èªä¸çä¸çæéå天象ã' + 1116 'åå§ç©èªçä¸å¹´æ 12 åæãä¸åæåºå® 30 天ï¼éæ²è£¡çä¸å¤©å¤§ç´æ¯ç¾å¯¦ä¸çç 20 åéã<br>
1116' + 1117 ' <a href="/help/calendar">çææ³èªªæ â¸</a>' + 1118 // ç«å±± badge 亮起æå¤ä¸å¥é£å°å°å±¬èªªæé ââ/help/calendar æ²æç«å±±, 1119 // é£ç¯è¦å(確åéæ°æè¾°ç)å®å ¨å¨ /help/volcano_war 裡,平常é£çµèä¸å°ã 1120 (ok && world.volcano ? ' | <a href="/help/volcano_war">çç«å±±èµ·åºæ°£èªªæ â¸</a>' : '') + 1121 (ok && st.updated_iso ? '<br><span class="ws-upd">æ´æ°æ¼ <time datetime="' + esc(st.updated_iso) + '">' + 1122 esc(st.updated_text || '') + '</time></span>' : '') + 1123 '</p>\n' + 1124 ' </div>\n' + 1125 ' </div>\n' + 1126 (data ? ' <script>window.PS_WORLD_DATA = ' + 1127 JSON.stringify(data).replace(/<\//g, '<\\/') + ';<\/script>\n' : '') + 1128 '</section>'; 1129 }; 1130 1131 return { 1132 SUNDIAL: SUNDIAL, 1133 CN_PHASE: CN_PHASE, 1134 CN_WEATHER: CN_WEATHER, 1135 CN_MOON: CN_MOON, 1136 CN_SEASON: CN_SEASON, 1137 CN_PALACE: CN_PALACE, 1138 CN_NUM: CN_NUM, 1139 FACE_WEATHER: FACE_WEATHER, 1140 FACE_MOON: FACE_MOON, 1141 FACE_PALACE: FACE_PALACE, 1142 UNAVAILABLE: UNAVAILABLE, 1143 esc: esc, 1144 fmtDur: fmtDur, 1145 PARTICLE_CFG: PARTICLE_CFG, 1146 weatherParticlesHtml: weatherParticlesHtml, 1147 weatherKey: weatherKey, 1148 isNightPhase: isNightPhase, 1149 FIREFLY_CFG: FIREFLY_CFG, 1150 FIREFLY_SEASON: FIREFLY_SEASON, 1151 FIREFLY_CALM: FIREFLY_CALM, 1152 FIREFLY_CUT: FIREFLY_CUT, 1153 fireflyOn: fireflyOn, 1154 fireflyCount: fireflyCount, 1155 fireflyKey: fireflyKey, 1156 fireflyHtml: fireflyHtml, 1157 dayScale: dayScale, 1158 fieldVal: fieldVal, 1159 phases: phases, 1160 phaseAt: phaseAt, 1161 frameAt: frameAt, 1162 shadowCss: shadowCss, 1163 dialCss: dialCss, 1164 pinHighlightCss: pinHighlightCss, 1165 grassCss: grassCss, 1166 moonGlow: moonGlow, 1167 moonDayNight: moonDayNight, 1168 dateLine: dateLine, 1169 badges: badges, 1170 badgeHtml: badgeHtml, 1171 renderHtml: renderHtml 1172 }; 1173});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.