像素农夫物语 V0.1 愚人节恐怖限定
by BraveDragon921026 lines35.6 KB
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>像素农夫物语 V0.1 愚人节恐怖限定</title>
<style>
*{
margin:0;
padding:0;
box-sizing:border-box;
image-rendering:pixelated;
font-family:"Courier New",monospace;
}
body{
background:#0a0000;
display:flex;
flex-direction:column;
align-items:center;
padding:10px;
color:#fff;
overflow-x:hidden;
}
#gameBox{
border:4px solid #880000;
background:#120000;
width:800px;
height:500px;
position:relative;
overflow:hidden;
}
canvas{display:block;}
.ui-panel{
width:800px;
background:#1a0000;
padding:8px 12px;
display:flex;
justify-content:space-between;
align-items:center;
border:2px solid #770000;
gap:8px;
flex-wrap:wrap;
margin-bottom:6px;
}
.btn{
padding:6px 12px;
background:#990000;
color:#fff;
border:none;
font-weight:bold;
cursor:pointer;
font-size:14px;
}
.btn:hover{background:#cc0000;}
.btn-disabled{background:#333;color:#777;cursor:not-allowed;}
.shop-modal{
position:fixed;
width:620px;
height:560px;
left:50%;
top:50%;
transform:translate(-50%,-50%);
background:#0b0000;
border:3px solid #ff3333;
z-index:999999;
padding:20px;
display:none;
}
.shop-close{
position:absolute;
right:16px;
top:12px;
font-size:26px;
color:#f33;
cursor:pointer;
}
.shop-title{
color:#ff4444;
text-align:center;
font-size:22px;
margin-bottom:16px;
letter-spacing:2px;
}
.shop-item{
display:flex;
justify-content:space-between;
align-items:center;
border:1px solid #600;
padding:10px;
margin:8px 0;
}
.spring-modal{
position:fixed;
width:500px;
height:340px;
left:50%;
top:50%;
transform:translate(-50%,-50%);
background:#1c0000;
border:3px solid #ffaa00;
z-index:999999;
padding:22px;
display:none;
}
.spring-title{
color:#ffcc00;
text-align:center;
font-size:22px;
margin-bottom:16px;
}
.spring-text{
line-height:2;
font-size:15px;
color:#ffdddd;
text-align:center;
}
.load-mask{
position:fixed;
top:0;
left:0;
width:100vw;
height:100vh;
background:#000;
z-index:99999;
display:flex;
flex-direction:column;
align-items:center;
justify-content:center;
}
.garble-text{
color:#ff2222;
font-size:26px;
letter-spacing:8px;
line-height:2.2;
text-align:center;
}
.jump-scare{
position:fixed;
top:0;
left:0;
width:100vw;
height:100vh;
background:radial-gradient(circle,#500 0%,#050000 50%,#000 90%);
z-index:99998;
display:none;
align-items:center;
justify-content:center;
overflow:hidden;
}
.jump-scare .garble-layer{
position:absolute;
width:100%;
height:100%;
overflow:hidden;
z-index:1;
pointer-events:none;
}
.jump-scare .garble-text-piece{
position:absolute;
color:#ff0f0f;
font-size:13px;
font-weight:900;
text-shadow:0 0 12px #f00,0 0 26px #700;
white-space:nowrap;
animation:garbleFlash 0.05s alternate infinite,garbleMove 1.2s linear infinite;
}
.face-shadow-1,.face-shadow-2{
width:400px;
height:400px;
border-radius:50%;
position:absolute;
z-index:2;
opacity:0.25;
pointer-events:none;
}
.face-shadow-1{
background:radial-gradient(circle,#f00 0%,transparent 70%);
animation:shadow1Drift 0.06s alternate infinite;
}
.face-shadow-2{
background:radial-gradient(circle,#900 0%,transparent 70%);
animation:shadow2Drift 0.07s alternate infinite;
}
.scare-face-main{
width:400px;
height:400px;
border-radius:50%;
position:relative;
z-index:10;
pointer-events:none;
background:radial-gradient(circle,#f00 0%,#400 45%,#000 75%);
animation:faceTwist 0.05s alternate infinite,faceShake 0.03s infinite;
box-shadow:0 0 60px #f00,0 0 120px #900,0 0 180px #300,inset 0 0 80px #200;
}
.eye-left,.eye-right{
position:absolute;
top:22%;
width:22%;
height:26%;
background:#000;
border-radius:50%;
box-shadow:inset 0 0 20px #f00,0 12px 0 #f00;
}
.eye-left{left:24%;}
.eye-right{right:24%;}
.blood-tear-l,.blood-tear-r{
position:absolute;
top:48%;
width:4px;
height:90px;
background:linear-gradient(#f00,transparent);
animation:bloodDrop 0.6s linear infinite;
}
.blood-tear-l{left:34%;}
.blood-tear-r{right:34%;}
.crack-main{
position:absolute;
top:0;
left:50%;
width:4px;
height:100%;
background:#000;
transform-origin:center top;
animation:crackWobble 0.04s alternate infinite;
box-shadow:0 0 8px #f00;
}
.crack-s1{
position:absolute;
top:28%;
left:30%;
width:90px;
height:2px;
background:#000;
transform:rotate(-28deg);
box-shadow:0 0 5px #f00;
}
.crack-s2{
position:absolute;
top:30%;
right:30%;
width:90px;
height:2px;
background:#000;
transform:rotate(28deg);
box-shadow:0 0 5px #f00;
}
.crack-s3{
position:absolute;
top:55%;
left:22%;
width:60px;
height:2px;
background:#000;
transform:rotate(-18deg);
box-shadow:0 0 5px #f00;
}
.crack-s4{
position:absolute;
top:58%;
right:22%;
width:60px;
height:2px;
background:#000;
transform:rotate(18deg);
box-shadow:0 0 5px #f00;
}
.scare-mouth{
position:absolute;
bottom:8%;
left:50%;
transform:translateX(-50%);
width:68%;
height:42%;
background:#000;
border-radius:0 0 70% 70%;
box-shadow:inset 0 -20px 30px #f00,inset 0 10px 15px #300;
}
.teeth-top,.teeth-bottom{
position:absolute;
left:50%;
transform:translateX(-50%);
width:62%;
height:16%;
display:flex;
justify-content:space-between;
}
.teeth-top{top:10%;}
.teeth-bottom{bottom:10%;}
.teeth-top span{
width:14%;
height:100%;
background:#fff;
clip-path:polygon(50% 100%,0 0,100% 0);
box-shadow:0 0 10px #f00;
}
.teeth-bottom span{
width:14%;
height:100%;
background:#fff;
clip-path:polygon(50% 0,0 100%,100% 100%);
box-shadow:0 0 10px #f00;
}
.mouth-flesh{
position:absolute;
width:80%;
height:70%;
left:10%;
top:15%;
background:radial-gradient(#700,transparent);
opacity:0.6;
}
.sign-name{
position:fixed;
right:16px;
bottom:16px;
color:#ff2222;
font-size:18px;
font-weight:bold;
text-shadow:0 0 8px #f00;
z-index:9999;
letter-spacing:2px;
}
.flash-screen{
position:fixed;
inset:0;
background:#fff;
opacity:0;
pointer-events:none;
z-index:99997;
}
.blood-word{
position:absolute;
color:#f00;
font-weight:bold;
pointer-events:none;
z-index:100;
text-shadow:0 0 6px #f00;
}
.tip-desc{
color:#992222;
margin-top:10px;
font-size:13px;
}
.screen-distortion{
position:fixed;
inset:0;
background:radial-gradient(circle,transparent 40%,rgba(120,0,0,0.18) 100%);
opacity:0;
pointer-events:none;
z-index:99996;
transition:opacity 0.12s;
}
.static-noise{
position:fixed;
inset:0;
opacity:0;
pointer-events:none;
z-index:99995;
background-image:url("data:image/svg+xml,%3Csvg width='256' height='256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.12'/%3E%3C/svg%3E");
}
.warning-ui{
position:fixed;
left:18px;
top:18px;
color:#ff2222;
font-size:13px;
line-height:1.6;
text-shadow:0 0 8px #f00;
z-index:9999;
opacity:0;
transition:opacity 0.15s;
}
.soul-banner-effect{
position:fixed;
inset:0;
background:radial-gradient(circle,rgba(170,20,220,0.28) 0%,transparent 72%);
opacity:0;
pointer-events:none;
z-index:99990;
transition:opacity 0.2s;
}
@keyframes faceTwist{
0%{transform:scale(1) rotate(-6deg) skewX(-4deg);filter:blur(0px)}
100%{transform:scale(1.38) rotate(6deg) skewX(4deg);filter:blur(1.5px)}
}
@keyframes faceShake{
0%{transform:translate(-2px,-2px)}
50%{transform:translate(2px,2px)}
100%{transform:translate(-2px,-2px)}
}
@keyframes crackWobble{
0%{transform:translateX(-50%) rotate(-5deg)}
100%{transform:translateX(-50%) rotate(5deg)}
}
@keyframes bloodDrop{
0%{height:0;opacity:0}
40%{height:90px;opacity:1}
100%{height:90px;opacity:0}
}
@keyframes garbleFlash{
0%{opacity:0.4;transform:translate(-3px)}
50%{opacity:1;transform:translate(3px)}
100%{opacity:0.4;transform:translate(-3px)}
}
@keyframes garbleMove{
0%{transform:translateY(0)}
100%{transform:translateY(16px)}
}
@keyframes shadow1Drift{
0%{transform:translate(-18px,12px) scale(1.06)}
100%{transform:translate(-6px,4px) scale(0.94)}
}
@keyframes shadow2Drift{
0%{transform:translate(16px,-10px) scale(0.93)}
100%{transform:translate(4px,-6px) scale(1.09)}
}
</style>
</head>
<body>
<div class="sign-name">汪天倪</div>
<div class="soul-banner-effect" id="bannerCover"></div>
<div class="shop-modal" id="birthdayShop">
<span class="shop-close" onclick="closeBirthShop()">×</span>
<h2 class="shop-title">🎂生日永久商店(仅10月4日可购买)</h2>
<div class="shop-item"><span>玩家永久移速提升</span><button class="btn" onclick="buyItem('addSpeed',300)">300金币</button></div>
<div class="shop-item"><span>全怪物永久移速降低25%</span><button class="btn" onclick="buyItem('slowAllMonster',400)">400金币</button></div>
<div class="shop-item"><span>永久抵抗画面畸变噪点</span><button class="btn" onclick="buyItem('antiNoise',250)">250金币</button></div>
<div class="shop-item"><span>一次性清屏全部怪物(可囤次数)</span><button class="btn" onclick="buyItem('clearMonster',500)">500金币</button></div>
<div class="shop-item"><span>农作物永久瞬间成熟</span><button class="btn" onclick="buyItem('cropMature',450)">450金币</button></div>
<div class="shop-item"><span>【故人·辟邪师】帅气仙侠外观,大范围压制鬼怪</span><button class="btn" onclick="buyItem('exorcist',550)">550金币</button></div>
<div class="shop-item"><span>【万魂幡】收拢禁锢全场妖邪,可囤使用次数</span><button class="btn" onclick="buyItem('soulBanner',1200)">1200金币</button></div>
</div>
<div class="spring-modal" id="springGift">
<h2 class="spring-title">🧨新春生肖永久礼包</h2>
<div class="spring-text" id="springText"></div>
<div style="text-align:center;margin-top:24px;"><button class="btn" onclick="closeSpringModal()">确认领取</button></div>
</div>
<div class="load-mask" id="loadMask">
<div class="garble-text" id="garbleBox">
█▓▒░系统数据流损坏 █▓▒░<br>资源加载异常,请勿关闭页面<br>剩余等待时间:<span id="timeCount">10</span>
</div>
</div>
<div class="jump-scare" id="jumpScare">
<div class="garble-layer" id="garbleLayer"></div>
<div class="face-shadow-1"></div>
<div class="face-shadow-2"></div>
<div class="scare-face-main">
<div class="eye-left"></div><div class="eye-right"></div>
<div class="blood-tear-l"></div><div class="blood-tear-r"></div>
<div class="crack-main"></div><div class="crack-s1"></div><div class="crack-s2"></div><div class="crack-s3"></div><div class="crack-s4"></div>
<div class="scare-mouth">
<div class="mouth-flesh"></div>
<div class="teeth-top"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<div class="teeth-bottom"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
</div>
</div>
</div>
<div class="flash-screen" id="flashMask"></div>
<div class="screen-distortion" id="distortionMask"></div>
<div class="static-noise" id="noiseMask"></div>
<div class="warning-ui" id="warnText">检测恐怖实体靠近</div>
<h2 style="color:#ff3333;text-align:center">像素农夫物语 V0.1 愚人节恐怖限定版</h2>
<div class="ui-panel">
<div>金币:<span id="goldShow">0</span> | 田地:<span id="landShow">4</span> | 播种:<span id="plantShow">0</span>/15</div>
<div>
<button class="btn" onclick="saveGame()">存档</button>
<button class="btn" onclick="loadGame()">读档</button>
<button class="btn btn-disabled" id="shopBtn" onclick="openBirthShop()">生日商店</button>
<button class="btn" onclick="useSoulBanner()">使用万魂幡</button>
</div>
</div>
<div id="gameBox"><canvas id="gameCanvas" width="800" height="500"></canvas></div>
<p class="tip-desc">⚠ 频闪、流血鬼脸、刺耳噪音、多怪物追击,心脏病、光敏、胆小者禁止游玩</p>
<script>
function judgeWinVersion(){
const ua = navigator.userAgent.toLowerCase();
return ua.includes("windows nt 6.1") || ua.includes("windows nt 6.2") || ua.includes("windows nt 6.3");
}
if(!judgeWinVersion()){
alert("如果你是 win 7 或 win 8 的话,请找创作者修理问题。如果没有问题的话证明你不是 Win 7 或 Win 8,而是其他版本,其他版本得在 4 月份或者 4 月 1 日游玩。");
throw "非适配系统终止运行";
}
function isBirthDate(){
const now = new Date();
return now.getMonth() === 9 && now.getDate() === 4;
}
function getZodiac(year){
const zodiacList = ["马","羊","猴","鸡","狗","猪","鼠","牛","虎","兔","龙","蛇"];
const offset = (year - 2026) % 12;
const idx = offset < 0 ? offset + 12 : offset;
return zodiacList[idx];
}
function isSpringDay(){
const d = new Date();
const m = d.getMonth()+1;
const day = d.getDate();
return (m === 1 && day >= 29) || (m === 2 && day <= 20);
}
const zodiacBuff = {
"鼠":{desc:"身法灵动,移速小幅增加",addSpeed:0.3,monsterSlow:0},
"牛":{desc:"抗性更强,怪物移速降低",addSpeed:0,monsterSlow:0.15},
"虎":{desc:"威慑鬼怪,怪物更容易徘徊不追击",addSpeed:0,monsterSlow:0.25},
"兔":{desc:"身形轻盈,移动更快,闪屏变少",addSpeed:0.4,monsterSlow:0},
"龙":{desc:"鸿运加持,收割金币永久+30%",addSpeed:0,monsterSlow:0,goldPlus:1.3},
"蛇":{desc:"潜行隐匿,怪物远距离丢失视野",addSpeed:0,monsterSlow:0.2},
"马":{desc:"奔行迅捷,高额移速加成",addSpeed:0.5,monsterSlow:0},
"羊":{desc:"田园安稳,作物生长加速",addSpeed:0,monsterSlow:0,growRate:1.4},
"猴":{desc:"灵活闪避,概率自动瞬移躲怪",addSpeed:0.2,monsterSlow:0},
"鸡":{desc:"驱散阴暗,画面畸变弱化",addSpeed:0,monsterSlow:0},
"狗":{desc:"感知敏锐,危险预警更早",addSpeed:0,monsterSlow:0.1},
"猪":{desc:"沃土丰收,成熟大概率双倍收益",addSpeed:0,monsterSlow:0}
};
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
const loadMask = document.getElementById("loadMask");
const garbleBox = document.getElementById("garbleBox");
const timeCount = document.getElementById("timeCount");
const jumpScare = document.getElementById("jumpScare");
const garbleLayer = document.getElementById("garbleLayer");
const flashMask = document.getElementById("flashMask");
const distortionMask = document.getElementById("distortionMask");
const noiseMask = document.getElementById("noiseMask");
const warnUI = document.getElementById("warnText");
const birthdayShop = document.getElementById("birthdayShop");
const shopButton = document.getElementById("shopBtn");
const springGiftDom = document.getElementById("springGift");
const springTextDom = document.getElementById("springText");
const bannerCover = document.getElementById("bannerCover");
let gold = 0;
let totalPlant = 0;
let landList = [];
const player = {x:380,y:320,w:44,h:64,baseSpeed:2.6};
let tick = 0;
let flashCd = 0;
let gameOver = false;
let isScare = false;
let bloodTextArr = [];
let entityList = [];
const keyBoard = {};
let bannerLockFrame = 0;
let permanentItem = {
addSpeed: false,
slowAllMonster: false,
antiNoise: false,
clearMonsterCount: 0,
cropMature: false,
exorcist: false,
soulBannerCount: 0,
zodiacName: "",
zodiacReceived: false
};
const entityConfig = [
{name:"黑影鬼魂",w:60,h:80,speed:0.8,color:"#000",eye:"#f00",ai:"lurk"},
{name:"无面步行者",w:52,h:86,speed:1.1,color:"#111",eye:"#a00",ai:"stalk"},
{name:"爬行畸变者",w:74,h:46,speed:1.6,color:"#200505",eye:"#f44",ai:"crawl"},
{name:"高速突袭幽影",w:42,h:66,speed:2.4,color:"#050505",eye:"#f22",ai:"rush"},
{name:"沉默巨人",w:90,h:110,speed:0.45,color:"#0a0202",eye:"#b00",ai:"giant"},
{name:"裂隙血肉怪",w:66,h:72,speed:1.0,color:"#300",eye:"#f00",ai:"flesh"},
{name:"暗影低语者",w:56,h:76,speed:1.3,color:"#080808",eye:"#d00",ai:"whisper"},
{name:"瞬移灵体",w:48,h:62,speed:0.9,color:"#150000",eye:"#f33",ai:"teleport"},
{name:"伪装农夫",w:44,h:64,speed:1.0,color:"#181818",eye:"#f00",ai:"disguise"},
{name:"镜像残影",w:44,h:64,speed:1.2,color:"#222",eye:"#f44",ai:"mirror"},
{name:"活稻草人",w:38,h:70,speed:0,color:"#2b1818",eye:"#f00",ai:"scarecrow"},
{name:"血红爬行者",w:58,h:38,speed:1.9,color:"#450000",eye:"#f66",ai:"backCrawl"}
];
document.addEventListener("keydown",e=>keyBoard[e.key.toLowerCase()]=true);
document.addEventListener("keyup",e=>keyBoard[e.key.toLowerCase()]=false);
function openBirthShop(){
if(!isBirthDate()){alert("当前不是10月4日,商店锁定无法购买");return;}
birthdayShop.style.display = "block";
}
function closeBirthShop(){birthdayShop.style.display = "none";}
function buyItem(key,cost){
if(gold < cost){alert("金币不足");return;}
gold -= cost;
if(key === "clearMonster") permanentItem.clearMonsterCount += 1;
else if(key === "soulBanner") permanentItem.soulBannerCount += 1;
else permanentItem[key] = true;
document.getElementById("goldShow").innerText = gold;
alert("购买成功,道具永久存入存档,读档永久生效!");
}
function useSoulBanner(){
if(permanentItem.soulBannerCount <= 0){
alert("无万魂幡使用次数,请在生日商店囤货");
return;
}
permanentItem.soulBannerCount -= 1;
bannerLockFrame = 180;
bannerCover.style.opacity = 1;
alert("万魂幡展开!所有妖邪被收拢禁锢3秒");
}
function openSpringModal(zodiac){
const buff = zodiacBuff[zodiac];
springTextDom.innerText = `本年度生肖:${zodiac}\n专属永久效果:${buff.desc}\n效果永久绑定存档`;
permanentItem.zodiacName = zodiac;
permanentItem.zodiacReceived = true;
springGiftDom.style.display = "block";
}
function closeSpringModal(){springGiftDom.style.display = "none";}
let loadTime = 10;
const loadTimer = setInterval(()=>{
loadTime--;
timeCount.innerText = loadTime;
garbleBox.innerHTML = randomGarble(35)+"<br>资源加载异常,请勿关闭页面<br>剩余等待时间:"+loadTime;
if(loadTime <= 0){
clearInterval(loadTimer);
loadMask.style.display = "none";
if(isBirthDate()) shopButton.classList.remove("btn-disabled");
else shopButton.classList.add("btn-disabled");
if(isSpringDay() && !permanentItem.zodiacReceived){
const year = new Date().getFullYear();
openSpringModal(getZodiac(year));
}
}
},1000);
function randomGarble(len){
const chars = "█▓▒░§¶<>!@#$%&*?~";
let str = "";
for(let i=0;i<len;i++) str += chars[Math.floor(Math.random()*chars.length)];
return str;
}
function screenWhiteFlash(){
flashMask.style.opacity = 1;
setTimeout(()=>flashMask.style.opacity=0,80);
}
function buildJumpGarble(){
garbleLayer.innerHTML = "";
const strPool = "█▓▒░0123456789abcdef!@#%&";
for(let i=0;i<42;i++){
for(let j=0;j<95;j++){
const span = document.createElement("span");
span.className = "garble-text-piece";
span.innerText = strPool[Math.floor(Math.random()*strPool.length)];
span.style.left = j*12+"px";
span.style.top = i*14+"px";
span.style.animationDelay = Math.random()*0.4+"s";
garbleLayer.appendChild(span);
}
}
}
function clearJumpGarble(){garbleLayer.innerHTML="";}
function triggerScare(){
if(isScare) return;
isScare = true;
buildJumpGarble();
jumpScare.style.display = "flex";
playHorrorAudio();
const flashLoop = setInterval(screenWhiteFlash,60);
setTimeout(()=>{
clearInterval(flashLoop);
jumpScare.style.display = "none";
clearJumpGarble();
isScare = false;
},2600);
}
function playHorrorAudio(){
const audioCtx = new (window.AudioContext||window.webkitAudioContext)();
const osc1 = audioCtx.createOscillator();
osc1.type = "sawtooth";
osc1.frequency.setValueAtTime(90,audioCtx.currentTime);
osc1.frequency.exponentialRampToValueAtTime(20,audioCtx.currentTime+0.8);
const osc2 = audioCtx.createOscillator();
osc2.type = "square";
osc2.frequency.setValueAtTime(600,audioCtx.currentTime);
osc2.frequency.exponentialRampToValueAtTime(1500,audioCtx.currentTime+0.4);
const oscNoise = audioCtx.createOscillator();
oscNoise.type = "triangle";
oscNoise.frequency.setValueAtTime(220,audioCtx.currentTime);
const gain = audioCtx.createGain();
gain.gain.setValueAtTime(0,audioCtx.currentTime);
gain.gain.linearRampToValueAtTime(0.8,audioCtx.currentTime+0.04);
gain.gain.linearRampToValueAtTime(0,audioCtx.currentTime+2.6);
osc1.connect(gain);osc2.connect(gain);oscNoise.connect(gain);gain.connect(audioCtx.destination);
osc1.start();osc2.start();oscNoise.start();
osc1.stop(audioCtx.currentTime+2.6);osc2.stop(audioCtx.currentTime+2.6);oscNoise.stop(audioCtx.currentTime+2.6);
}
function playerDieReset(){
if(gameOver) return;
gameOver = true;
triggerScare();
setTimeout(()=>{
gold = 0; totalPlant = 0; player.x=380;player.y=320;
entityList = []; initFarmLand(); gameOver = false;
document.getElementById("goldShow").innerText = gold;
document.getElementById("plantShow").innerText = totalPlant;
},3200);
}
function spawnEntity(){
const type = entityConfig[Math.floor(Math.random()*entityConfig.length)];
let x,y;
const side = Math.floor(Math.random()*4);
if(side===0){x=Math.random()*800;y=-80;}
else if(side===1){x=810;y=Math.random()*500;}
else if(side===2){x=Math.random()*800;y=510;}
else {x=-80;y=Math.random()*500;}
entityList.push({
x,y,w:type.w,h:type.h,baseSpeed:type.speed,nowSpeed:type.speed,
fillColor:type.color,eyeColor:type.eye,aiType:type.ai,
timer:0,disguise:true,reveal:false,teleCd:0
});
}
function rectHit(a,b){
return a.x < b.x+b.w && a.x+a.w > b.x && a.y < b.y+b.h && a.y+a.h > b.y;
}
function refreshEntityAI(){
let globalSlow = permanentItem.slowAllMonster ? 0.75 : 1;
const zodiacNow = zodiacBuff[permanentItem.zodiacName] || {};
if(zodiacNow.monsterSlow) globalSlow *= (1-zodiacNow.monsterSlow);
const exorcistRange = 180;
for(let e of entityList){
const dx = player.x - e.x;
const dy = player.y - e.y;
const dist = Math.hypot(dx,dy);
e.timer++;
if(bannerLockFrame > 0){
e.nowSpeed = 0;
const centerX = 400, centerY = 250;
const cdx = centerX - e.x;
const cdy = centerY - e.y;
const cDist = Math.hypot(cdx,cdy);
if(cDist > 6){
e.x += cdx/cDist * 1.2;
e.y += cdy/cDist * 1.2;
}
continue;
}
let exorcistSlow = 1;
if(permanentItem.exorcist && dist < exorcistRange){
exorcistSlow = 0.6;
if(e.aiType === "teleport") e.teleCd += 120;
if(e.aiType === "rush") e.timer = 0;
}
switch(e.aiType){
case "lurk": e.nowSpeed = dist<250 ? e.baseSpeed*1.6 : e.baseSpeed*0.5; break;
case "stalk": e.nowSpeed = dist<180 ? e.baseSpeed*2.2 : e.baseSpeed*0.35; break;
case "crawl": e.nowSpeed=e.baseSpeed; if(dist<130) e.y += dy>0 ? 1.5:-1.5; break;
case "rush": e.nowSpeed=e.baseSpeed; if(e.timer>180&&dist<160){e.nowSpeed=e.baseSpeed*2.8;if(e.timer>220)e.timer=0;} break;
case "giant": e.nowSpeed = dist<220 ? e.baseSpeed*1.8:e.baseSpeed; break;
case "flesh":
e.nowSpeed=e.baseSpeed;
if(dist<160 && !permanentItem.antiNoise){distortionMask.style.opacity=0.35;noiseMask.style.opacity=0.25;}
break;
case "whisper": e.nowSpeed=e.baseSpeed; break;
case "teleport":
e.teleCd++;
if(e.teleCd>350 && Math.random()<0.008){
e.x = player.x + (Math.random()-0.5)*220;
e.y = player.y + (Math.random()-0.5)*160;
e.teleCd=0; screenWhiteFlash();
}
break;
case "disguise":
if(e.timer>200 || dist<90){e.disguise=false;e.reveal=true;e.nowSpeed=e.baseSpeed*2.4;screenWhiteFlash();}
break;
case "mirror":
e.nowSpeed=e.baseSpeed;
if(keyBoard["w"]) e.y -= e.nowSpeed;
if(keyBoard["s"]) e.y += e.nowSpeed;
if(keyBoard["a"]) e.x -= e.nowSpeed;
if(keyBoard["d"]) e.x += e.nowSpeed;
break;
case "scarecrow": e.nowSpeed=dist<120 ? e.baseSpeed*2 : 0; break;
case "backCrawl":
e.nowSpeed=e.baseSpeed;
if(dist<180){
const angle = Math.atan2(dy,dx)+Math.PI/6;
e.x += Math.cos(angle)*e.nowSpeed;
e.y += Math.sin(angle)*e.nowSpeed;
}
break;
}
e.nowSpeed *= globalSlow * exorcistSlow;
if(dist>0){e.x += (dx/dist)*e.nowSpeed; e.y += (dy/dist)*e.nowSpeed;}
if(rectHit(player,e)) playerDieReset();
}
}
function drawBlock(x,y,w,h,color){
ctx.fillStyle = color;
ctx.fillRect(Math.floor(x),Math.floor(y),w,h);
}
function drawPlayer(){
let addSpd = permanentItem.addSpeed ? 0.4 : 0;
const zodiacNow = zodiacBuff[permanentItem.zodiacName];
if(zodiacNow?.addSpeed) addSpd += zodiacNow.addSpeed;
const realSpeed = player.baseSpeed + addSpd;
if(!gameOver){
if(keyBoard["w"]||keyBoard["arrowup"]) player.y -= realSpeed;
if(keyBoard["s"]||keyBoard["arrowdown"]) player.y += realSpeed;
if(keyBoard["a"]||keyBoard["arrowleft"]) player.x -= realSpeed;
if(keyBoard["d"]||keyBoard["arrowright"]) player.x += realSpeed;
player.x = Math.max(0,Math.min(800-player.w,player.x));
player.y = Math.max(0,Math.min(500-player.h,player.y));
}
if(permanentItem.exorcist){
drawBlock(player.x+10,player.y,24,24,"#ffe9d1");
drawBlock(player.x+6,player.y-6,30,12,"#0f0f0f");
drawBlock(player.x+14,player.y-10,16,8,"#ffdd00");
drawBlock(player.x+13,player.y+7,6,6,"#000");
drawBlock(player.x+25,player.y+7,6,6,"#000");
drawBlock(player.x+15,player.y+19,10,4,"#dd2222");
drawBlock(player.x+5,player.y+24,34,28,"#f8faff");
drawBlock(player.x+7,player.y+26,30,4,"#ffcc00");
drawBlock(player.x+8,player.y+46,28,4,"#ffcc00");
drawBlock(player.x+8,player.y+28,4,18,"#ffcc00");
drawBlock(player.x+26,player.y+28,4,18,"#ffcc00");
drawBlock(player.x+9,player.y+52,13,12,"#222");
drawBlock(player.x+22,player.y+52,13,12,"#222");
drawBlock(player.x+37,player.y+27,7,24,"#cacaca");
drawBlock(player.x+36,player.y+26,9,4,"#882222");
ctx.beginPath();
ctx.arc(player.x+22,player.y+32,42,0,Math.PI*2);
ctx.strokeStyle = "rgba(255,222,70,0.25)";
ctx.lineWidth = 2;
ctx.stroke();
}else{
drawBlock(player.x+10,player.y,24,24,"#ffdab9");
drawBlock(player.x+8,player.y-4,28,10,"#8b4513");
drawBlock(player.x+12,player.y+8,5,5,"#000");
drawBlock(player.x+26,player.y+8,5,5,"#000");
drawBlock(player.x+16,player.y+18,12,3,"#cc6666");
drawBlock(player.x+6,player.y+24,32,26,"#0066cc");
drawBlock(player.x+10,player.y+26,24,8,"#f00");
drawBlock(player.x+8,player.y+50,12,14,"#333");
drawBlock(player.x+24,player.y+50,12,14,"#333");
drawBlock(player.x+36,player.y+30,10,6,"#ffdab9");
}
}
function drawAllEntity(){
ctx.globalAlpha = 0.78;
for(let e of entityList){
if(e.disguise){
drawBlock(e.x+10,e.y,24,24,"#ffdab9");
drawBlock(e.x+8,e.y-4,28,10,"#8b4513");
drawBlock(e.x+12,e.y+8,5,5,tick%120<60?"#f00":"#000");
drawBlock(e.x+26,e.y+8,5,5,tick%120<60?"#f00":"#000");
drawBlock(e.x+6,e.y+24,32,26,"#0066cc");
drawBlock(e.x+8,e.y+50,12,14,"#333");
drawBlock(e.x+24,e.y+50,12,14,"#333");
}else{
drawBlock(e.x,e.y,e.w,e.h,e.fillColor);
const eyeW = e.w*0.18;
const eyeH = e.h*0.18;
drawBlock(e.x+e.w*0.22,e.y+e.h*0.25,eyeW,eyeH,e.eyeColor);
drawBlock(e.x+e.w*0.6,e.y+e.h*0.25,eyeW,eyeH,e.eyeColor);
if(e.aiType==="flesh"){
ctx.strokeStyle="#f00";ctx.lineWidth=2;
ctx.beginPath();ctx.moveTo(e.x+e.w/2,e.y);ctx.lineTo(e.x+e.w*0.45,e.y+e.h*0.35);ctx.lineTo(e.x+e.w*0.55,e.y+e.h*0.55);ctx.stroke();
}
if(e.aiType==="backCrawl"){
for(let i=0;i<4;i++) drawBlock(e.x+e.w*0.15+i*12,e.y+e.h,5,10,e.fillColor);
}
if(e.aiType==="scarecrow"){
drawBlock(e.x+e.w*0.1,e.y+e.h*0.3,e.w*0.8,4,"#5a3838");
drawBlock(e.x+e.w*0.45,e.y+e.h*0.2,4,e.h*0.6,"#5a3838");
}
}
}
ctx.globalAlpha = 1;
}
function initFarmLand(){
landList = [];
let startX = 120;
for(let i=0;i<4;i++){
landList.push({
x:startX+i*80,y:380,w:70,h:80,
seed:false,grow:0,ripe:false,shake:Math.random()*100,bloodPlant:Math.random()<0.35
});
}
}
function drawFarmLand(){
const zodiacNow = zodiacBuff[permanentItem.zodiacName];
let growSpeed = zodiacNow?.growRate || 1;
if(permanentItem.cropMature) growSpeed = 999;
landList.forEach(land=>{
drawBlock(land.x,land.y,land.w,land.h,"#180000");
ctx.strokeStyle="#770000";ctx.lineWidth=2;
ctx.strokeRect(land.x,land.y,land.w,land.h);
if(land.seed){
const shakeOff = Math.sin(tick*0.12+land.shake)*5;
const plantH = land.ripe ? 98 : land.grow*14*growSpeed;
const stem = land.bloodPlant ? "#770000":"#442211";
const fruit = land.bloodPlant ? "#f00":"#aa2222";
drawBlock(land.x+34+shakeOff,land.y-plantH,6,plantH,stem);
drawBlock(land.x+28+shakeOff,land.y-plantH-12,14,16,fruit);
if(!land.ripe) land.grow += 0.03;
if(land.grow >=7) land.ripe = true;
}
});
}
canvas.onclick = function(e){
if(gameOver) return;
const rect = canvas.getBoundingClientRect();
const mx = e.clientX - rect.left;
const my = e.clientY - rect.top;
landList.forEach(land=>{
if(mx>land.x && mx<land.x+land.w && my>land.y && my<land.y+land.h){
if(!land.seed){
land.seed=true;land.grow=0;land.bloodPlant=Math.random()<0.35;
totalPlant++;
document.getElementById("plantShow").innerText = totalPlant;
if(totalPlant>=15){triggerScare();totalPlant=0;document.getElementById("plantShow").innerText=0;}
}else if(land.ripe){
let earn = 200;
if(zodiacBuff[permanentItem.zodiacName]?.goldPlus) earn *= zodiacBuff[permanentItem.zodiacName].goldPlus;
if(permanentItem.cropMature && Math.random()<0.5) earn *=2;
gold += earn;
document.getElementById("goldShow").innerText = gold;
land.seed=false;land.ripe=false;land.grow=0;
}
}
})
}
function saveGame(){
const saveData = {gold,totalPlant,landList,player,permanentItem};
localStorage.setItem("farmHorrorSave",JSON.stringify(saveData));
alert("存档保存完毕,辟邪师、万魂幡次数、生肖buff永久写入本地");
}
function loadGame(){
const saveStr = localStorage.getItem("farmHorrorSave");
if(!saveStr){alert("暂无存档");return;}
try{
const data = JSON.parse(saveStr);
gold = data.gold;
totalPlant = data.totalPlant;
landList = data.landList;
player.x = data.player.x;player.y=data.player.y;
permanentItem = data.permanentItem;
document.getElementById("goldShow").innerText = gold;
document.getElementById("plantShow").innerText = totalPlant;
alert("读档成功,所有生日道具、生肖效果完整恢复");
}catch(err){alert("存档文件损坏");}
}
function gameMainLoop(){
tick++;
flashCd--;
if(bannerLockFrame>0){
bannerLockFrame--;
if(bannerLockFrame<=0) bannerCover.style.opacity=0;
}
distortionMask.style.opacity = Math.max(0,Number(distortionMask.style.opacity)-0.008);
noiseMask.style.opacity = Math.max(0,Number(noiseMask.style.opacity)-0.008);
ctx.fillStyle="#0a0000";
ctx.fillRect(0,0,800,500);
if(!gameOver && tick%750===0 && entityList.length<12) spawnEntity();
if(!gameOver) refreshEntityAI();
if(tick%400===0){
const wordPool = ["田里有东西","别收割","它盯着你","逃不掉","别回头","它们从土里爬出来"];
const wordDom = document.createElement("div");
wordDom.className="blood-word";
wordDom.innerText = wordPool[Math.floor(Math.random()*wordPool.length)];
wordDom.style.left = Math.random()*720+"px";
wordDom.style.top = Math.random()*420+"px";
wordDom.style.fontSize = 12+Math.random()*14+"px";
gameBox.appendChild(wordDom);
bloodTextArr.push({dom:wordDom,life:220});
}
bloodTextArr.forEach((item,idx)=>{
item.life--;
if(item.life<=0){item.dom.remove();bloodTextArr.splice(idx,1);}
})
if(flashCd<=0 && Math.random()<0.002){screenWhiteFlash();flashCd=300;}
let minDist = 9999;
entityList.forEach(e=>{
const d = Math.hypot(player.x-e.x,player.y-e.y);
if(d<minDist) minDist=d;
})
warnUI.style.opacity = Math.max(0,Number(warnUI.style.opacity)-0.012);
if(minDist<160){warnUI.style.opacity=1;warnUI.innerText="实体靠近,注意躲避";}
if(minDist<100){warnUI.style.opacity=1;warnUI.innerText="极度危险!立刻拉开距离";screenWhiteFlash();}
drawFarmLand();
drawAllEntity();
drawPlayer();
requestAnimationFrame(gameMainLoop);
}
initFarmLand();
gameMainLoop();
</script>
</body>Game Source: 像素农夫物语 V0.1 愚人节恐怖限定
Creator: BraveDragon92
Libraries: none
Complexity: complex (1026 lines, 35.6 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: v0-1-bravedragon92-mrykx12g" to link back to the original. Then publish at arcadelab.ai/publish.