Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions mods/CsC.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
runAfterLoad(function(){
const patternCache = {};
let currentPatternID = null;
let nextPatternID = 1;
const undoStack = [];
const redoStack = [];
const maxHistory = 50;

function saveAction(pixels){
undoStack.push(pixels.map(px=>({x:px.x,y:px.y,element:px.element,color:px.color,patternID:px.patternID})));
if(undoStack.length>maxHistory) undoStack.shift();
redoStack.length=0;
}

function undo(){
if(!undoStack.length) return;
const action = undoStack.pop();
const redoPixels = [];
action.forEach(a=>{
const px = pixelMap[a.x][a.y];
redoPixels.push({x:a.x,y:a.y,element:px.element,color:px.color,patternID:px.patternID});
px.element=a.element; px.color=a.color; px.patternID=a.patternID;
});
redoStack.push(redoPixels);
}

function redo(){
if(!redoStack.length) return;
const action = redoStack.pop();
const undoPixels = [];
action.forEach(a=>{
const px = pixelMap[a.x][a.y];
undoPixels.push({x:a.x,y:a.y,element:px.element,color:px.color,patternID:px.patternID});
px.element=a.element; px.color=a.color; px.patternID=a.patternID;
});
undoStack.push(undoPixels);
}

elements.undo_tool = {
color:"#f00", tool:undo, category:"tools", description:"Undo last action"
};
elements.redo_tool = {
color:"#0f0", tool:redo, category:"tools", description:"Redo last undone action"
};

elements.pattern_painter = {
color:"#888", tool:function(pixel,x,y){
if(!currentPatternID){
currentPatternID="pattern_"+(nextPatternID++);
patternCache[currentPatternID]=Array(8).fill().map(()=>Array(8).fill(0));
}
const pat = patternCache[currentPatternID];
const mx=Math.floor((x*8)%8), my=Math.floor((y*8)%8);
pat[my][mx]=1-pat[my][mx];
}, category:"tools", description:"Pattern painter (8x8)"
};

function drawPattern(ctx, pat, dx, dy, s){
for(let py=0;py<8;py++)for(let px=0;px<8;px++){
if(pat[py][px]){
ctx.fillStyle="#444";
ctx.fillRect(dx+px*s/8, dy+py*s/8, s/8, s/8);
}
}
}

elements.decor_block={
color:"#fff", behavior:behaviors.WALL, category:"solids",
onPlace:p=>{if(currentPatternID)p.patternID=currentPatternID; saveAction([p]);},
renderer:function(p,ctx,dx,dy,s){
if(p.patternID) drawPattern(ctx, patternCache[p.patternID], dx, dy, s);
else { ctx.fillStyle=p.color; ctx.fillRect(dx,dy,s,s); }
}
};

elements.batch_filler={
color:"#66f",
tool:function(pixel){
const area=[];
for(let dx=-2;dx<=2;dx++)for(let dy=-2;dy<=2;dy++){
const px=pixelMap[pixel.x+dx]?.[pixel.y+dy];
if(px){px.element="decor_block"; if(currentPatternID) px.patternID=currentPatternID; area.push(px);}
}
saveAction(area);
},
category:"tools",
description:"Fill 5x5 area with pattern"
};

elements.stamp_tool={
color:"#ff0",
tool:function(pixel){
if(!currentPatternID) return;
const area=[];
for(let dx=0;dx<8;dx++)for(let dy=0;dy<8;dy++){
const px=pixelMap[pixel.x+dx]?.[pixel.y+dy];
if(px){px.element="decor_block"; px.patternID=currentPatternID; area.push(px);}
}
saveAction(area);
},
category:"tools",
description:"Stamp 8x8 pattern"
};

elements.gradient_tool={
color:"#0ff",
tool:function(pixel){
const area=[];
for(let dx=0;dx<5;dx++)for(let dy=0;dy<5;dy++){
const px=pixelMap[pixel.x+dx]?.[pixel.y+dy];
if(px){
const r=Math.floor(255*dx/4), b=Math.floor(255*dy/4);
px.element="decor_block";
px.color=`rgb(${r},0,${b})`;
area.push(px);
}
}
saveAction(area);
},
category:"tools",
description:"Paint 5x5 gradient"
};

elements.curve_tool={
color:"#f0f",
tool:function(pixel){
const area=[];
for(let i=0;i<5;i++){
const px=pixelMap[pixel.x+i]?.[pixel.y+Math.floor(Math.sin(i/4*Math.PI)*4)];
if(px){px.element="decor_block"; if(currentPatternID) px.patternID=currentPatternID; area.push(px);}
}
saveAction(area);
},
category:"tools",
description:"Draw sine curve with pattern"
};

});
100 changes: 100 additions & 0 deletions mods/Decor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
runAfterLoad(function(){
const patternCache = {};
let currentPatternID = null;
let nextPatternID = 1;

elements.pattern_painter = {
color:"#888", tool:function(pixel,x,y){
if(!currentPatternID){
currentPatternID = "pattern_"+(nextPatternID++);
patternCache[currentPatternID] = Array(8).fill().map(()=>Array(8).fill(0));
}
const pat = patternCache[currentPatternID];
const mx = Math.floor((x*8)%8), my = Math.floor((y*8)%8);
pat[my][mx] = 1 - pat[my][mx];
},
category:"tools",
description:"Pattern painter (8x8)"
};

function drawPattern(ctx, pat, dx, dy, s){
for(let py=0;py<8;py++){
for(let px=0;px<8;px++){
if(pat[py][px]){
ctx.fillStyle = "#444";
ctx.fillRect(dx + px*s/8, dy + py*s/8, s/8, s/8);
}
}
}
}

function blendColors(c1,c2,t){
const parse = c=>parseInt(c.slice(1),16);
const r1=((parse(c1)>>16)&255), g1=((parse(c1)>>8)&255), b1=(parse(c1)&255);
const r2=((parse(c2)>>16)&255), g2=((parse(c2)>>8)&255), b2=(parse(c2)&255);
const r=Math.floor(r1*(1-t)+r2*t), g=Math.floor(g1*(1-t)+g2*t), b=Math.floor(b1*(1-t)+b2*t);
return "#"+((1<<24)+(r<<16)+(g<<8)+b).toString(16).slice(1);
}

elements.decor_block = {
color:"#fff", behavior:behaviors.WALL, category:"solids",
onPlace: p=>{ if(currentPatternID) p.patternID=currentPatternID; },
renderer: function(p, ctx, dx, dy, s){
if(p.patternID){
drawPattern(ctx, patternCache[p.patternID], dx, dy, s);
} else { ctx.fillStyle=p.color; ctx.fillRect(dx, dy, s, s); }
}
};

elements.fader_block = {
color:"#fff", behavior:behaviors.WALL, category:"solids",
onPlace: p=>{ if(currentPatternID) p.patternID=currentPatternID; },
renderer: function(p, ctx, dx, dy, s){
const pat = p.patternID ? patternCache[p.patternID] : null;
if(!pat){ ctx.fillStyle=p.color; ctx.fillRect(dx, dy, s, s); return; }
for(let py=0;py<8;py++){
const t = py/7;
for(let px=0;px<8;px++){
const c = pat[py][px] ? blendColors("#000","#555",t) : blendColors("#ccc","#eee",t);
ctx.fillStyle=c;
ctx.fillRect(dx+px*s/8, dy+py*s/8, s/8, s/8);
}
}
}
};

elements.cloth = {
color:"#aaa", behavior:behaviors.POWDER, category:"solids",
onPlace: p=>{ if(currentPatternID) p.patternID=currentPatternID; p.vy=0; },
tick: function(p){
if(p.y+1>=pixelGridHeight) return;
const below = pixelMap[p.x][p.y+1];
if(!below||elements[below.element].behavior!==behaviors.WALL) p.y++;
},
renderer: function(p, ctx, dx, dy, s){
if(p.patternID) drawPattern(ctx, patternCache[p.patternID], dx, dy, s);
else ctx.fillStyle=p.color; ctx.fillRect(dx, dy, s, s);
}
};

elements.fence_block = {
color:"#666", behavior:behaviors.WALL, category:"solids",
onPlace: p=>{ if(currentPatternID) p.patternID=currentPatternID; },
renderer: function(p, ctx, dx, dy, s){
if(p.patternID) drawPattern(ctx, patternCache[p.patternID], dx, dy, s);
else ctx.fillStyle=p.color; ctx.fillRect(dx, dy, s, s);
}
};

runEveryTick(function(){
renderPrePixel(function(p, ctx, dx, dy, s){
if(p.element==="decor_block"||p.element==="fader_block"||p.element==="cloth"||p.element==="fence_block"){
const shade = ctx.createLinearGradient(dx, dy, dx, dy+s);
shade.addColorStop(0,"rgba(0,0,0,0)");
shade.addColorStop(1,"rgba(0,0,0,0.3)");
ctx.fillStyle=shade;
ctx.fillRect(dx, dy, s, s);
}
});
});
});