class_name PixelTowerArt extends RefCounted ## Small, code-native room furnishings. Coordinates use the same pixel size as ## Kenney's 16 px sprites. This renderer never changes simulation state. const INK := Color("34413b") const WOOD := Color("8e6348") const WOOD_LIGHT := Color("c39665") const CREAM := Color("eee5c9") const TEAL := Color("608d84") static func tile(canvas: CanvasItem, texture: Texture2D, index: int, target: Rect2, tint := Color.WHITE) -> void: if texture == null: return canvas.draw_texture_rect_region(texture, target, Rect2((index % 12) * 16, (index / 12) * 16, 16, 16), tint) static func room(canvas: CanvasItem, rect: Rect2, id: StringName, pixel: float, dungeon: Texture2D, town: Texture2D, back: bool, decoration_seed := 0) -> void: var p := pixel if id in [&"guest_stairs", &"service_stairs"]: stairs(canvas, rect, p, id == &"service_stairs") return if id in [&"guest_corridor", &"service_corridor"]: canvas.draw_rect(rect, Color("c6b999") if not back else Color("a6b6a0")) canvas.draw_rect(Rect2(rect.position.x,rect.end.y-4*p,rect.size.x,3*p),WOOD_LIGHT) canvas.draw_rect(Rect2(rect.position.x,rect.end.y-p,rect.size.x,p),INK) canvas.draw_rect(Rect2(rect.position.x,rect.position.y,rect.size.x,p),WOOD) if posmod(decoration_seed,3)==0: window(canvas,Vector2(rect.get_center().x-3*p,rect.position.y+5*p),p) return var dark := id in [&"tavern", &"adult_private_room", &"massage_room"] var wall := Color("d4c7a5") if not back else Color("acb9a5") if dark: wall = Color("897487") canvas.draw_rect(rect, INK) var inner := rect.grow(-p) canvas.draw_rect(inner, wall) # Plaster, dado rail and floor boards read as interiors, even at a distance. canvas.draw_rect(Rect2(inner.position, Vector2(inner.size.x, p)), Color("f1e9cb")) var floor_y := rect.end.y - 4.0 * p canvas.draw_rect(Rect2(Vector2(inner.position.x, floor_y - 4.0 * p), Vector2(inner.size.x, 4.0 * p)), Color("b39b77") if not dark else Color("615563")) canvas.draw_rect(Rect2(Vector2(inner.position.x, floor_y), Vector2(inner.size.x, 3.0 * p)), WOOD) canvas.draw_line(Vector2(inner.position.x, floor_y), Vector2(inner.end.x, floor_y), WOOD_LIGHT, p) for x in range(int(inner.position.x + 2 * p), int(inner.end.x), maxi(int(8 * p), 1)): canvas.draw_rect(Rect2(x, floor_y + p, 5 * p, p), Color("a57852")) var mid := rect.get_center().x var w := rect.size.x var top := rect.position.y if id in [&"guest_elevator", &"service_elevator"]: elevator_shaft(canvas, rect, p, back) return if id in [&"guest_corridor", &"service_corridor", &"staff_door"]: if id == &"staff_door": door(canvas, Vector2(mid-4*p, floor_y-14*p), p, Color("587f7b")) else: window(canvas, Vector2(mid-3*p, top+5*p), p) return # A window and small wall lamp leave the lower part clear for live actors. if w >= 28*p: window(canvas, Vector2(rect.position.x+5*p, top+5*p), p) window(canvas, Vector2(rect.end.x-12*p, top+5*p), p) else: window(canvas, Vector2(mid-3*p, top+4*p), p) var lamp_x := mid if w > 32*p else rect.end.x-4*p canvas.draw_rect(Rect2(lamp_x-p, top+3*p, 2*p, 3*p), WOOD) canvas.draw_rect(Rect2(lamp_x-2*p, top+5*p, 4*p, 2*p), Color("edc97c")) match id: &"reception": counter(canvas, Vector2(mid-9*p, floor_y-6*p), 18*p, p) canvas.draw_rect(Rect2(mid-6*p, floor_y-8*p, 4*p, 2*p), CREAM) canvas.draw_rect(Rect2(mid+4*p, floor_y-8*p, 2*p, 2*p), Color("d6ad52")) &"standard_room", &"adult_private_room": bed(canvas, Vector2(rect.position.x+2*p, floor_y-9*p), p, Color("709b94") if not dark else Color("a37b91"),13) if w >= 28*p: bed(canvas, Vector2(rect.end.x-15*p, floor_y-9*p), p, Color("709b94") if not dark else Color("a37b91"),13) &"cafeteria", &"tavern": for x in range(int(rect.position.x+5*p), int(rect.end.x-13*p), int(20*p)): table(canvas, Vector2(x, floor_y-7*p), p) if rect.size.y > 28*p: counter(canvas, Vector2(rect.position.x+7*p, top+13*p), w-14*p, p) for x in range(int(rect.position.x+10*p), int(rect.end.x-8*p), int(12*p)): canvas.draw_rect(Rect2(x, top+11*p, 3*p, 2*p), CREAM) &"public_bath": canvas.draw_rect(Rect2(rect.position.x+4*p, floor_y-7*p, w-8*p, 7*p), CREAM) canvas.draw_rect(Rect2(rect.position.x+6*p, floor_y-6*p, w-12*p, 4*p), Color("72b6b8")) canvas.draw_line(Vector2(rect.position.x+8*p,floor_y-5*p), Vector2(rect.end.x-10*p,floor_y-5*p), Color("c1e0d4"), p) &"kitchen": counter(canvas, Vector2(rect.position.x+3*p, floor_y-7*p), w-6*p, p) for x in range(int(rect.position.x+5*p), int(rect.end.x-9*p), int(12*p)): canvas.draw_rect(Rect2(x, floor_y-9*p, 7*p, 2*p), Color("445652")) canvas.draw_rect(Rect2(x+2*p, floor_y-11*p, 4*p, 3*p), Color("a2b2a3")) &"warehouse": for x in range(int(rect.position.x+2*p), int(rect.end.x-12*p), int(13*p)): tile(canvas, dungeon, 63, Rect2(x, floor_y-12*p, 12*p, 12*p)) &"staff_waiting_room": table(canvas, Vector2(mid-6*p, floor_y-7*p), p) tile(canvas, dungeon, 89, Rect2(rect.position.x+2*p, floor_y-12*p, 12*p, 12*p)) &"security_station": counter(canvas, Vector2(mid-8*p, floor_y-6*p), 16*p, p) tile(canvas, dungeon, 105, Rect2(rect.position.x+3*p, floor_y-17*p, 12*p, 12*p)) &"massage_room": bed(canvas, Vector2(mid-8*p, floor_y-9*p), p, Color("d3aa8f")) _: table(canvas, Vector2(mid-6*p, floor_y-7*p), p) ## The upper landing owns a short flight down to the floor below. Six square ## treads and a stepped handrail keep the shape legible at the 16 px room scale. static func stairs(canvas: CanvasItem, rect: Rect2, p: float, staff_only: bool, compact := false) -> void: if not compact: canvas.draw_rect(rect, INK) canvas.draw_rect(rect.grow(-p), Color("c7c6a6") if not staff_only else Color("a8b6aa")) canvas.draw_rect(Rect2(rect.position.x, rect.end.y-4*p, rect.size.x, 3*p), WOOD) canvas.draw_rect(Rect2(rect.position.x, rect.end.y-p, rect.size.x, p), INK) var at := Vector2(rect.get_center().x-6*p, rect.end.y-5*p) var tread := Color("d8bf89") if not staff_only else Color("aec0bf") var rise := Color("8a7155") if not staff_only else Color("617f82") for step: int in range(6): var top := at + Vector2(step*2, -step*2)*p canvas.draw_rect(Rect2(top, Vector2(2, 2+step*2)*p), rise) canvas.draw_rect(Rect2(top, Vector2(3, 1)*p), tread) canvas.draw_rect(Rect2(top+Vector2(0,-5)*p, Vector2(2,1)*p), INK) if step % 2 == 0: canvas.draw_rect(Rect2(top+Vector2(0,-4)*p, Vector2(1,4)*p), WOOD if not staff_only else TEAL) canvas.draw_rect(Rect2(at+Vector2(10,-11)*p, Vector2(3,2)*p), tread) if staff_only and not compact: canvas.draw_rect(Rect2(rect.position+Vector2(2,2)*p, Vector2(3,3)*p), TEAL) canvas.draw_rect(Rect2(rect.position+Vector2(3,3)*p, Vector2(1,1)*p), CREAM) ## Static shaft rails remain when a car is stopped or the transport service is ## unavailable. The car itself is drawn once from its authoritative trip state. static func elevator_shaft(canvas: CanvasItem, rect: Rect2, p: float, back: bool) -> void: canvas.draw_rect(rect, INK) canvas.draw_rect(rect.grow(-p), Color("3e514e") if not back else Color("404f63")) canvas.draw_rect(Rect2(rect.position.x+2*p, rect.position.y, 2*p, rect.size.y), Color("83958a")) canvas.draw_rect(Rect2(rect.end.x-4*p, rect.position.y, 2*p, rect.size.y), Color("83958a")) canvas.draw_rect(Rect2(rect.get_center().x-p, rect.position.y, 2*p, rect.size.y), Color("283a39")) for row: int in range(2): var floor_y := rect.position.y + float(row+1)*rect.size.y*0.5 canvas.draw_rect(Rect2(rect.position.x, floor_y-4*p, rect.size.x, 3*p), Color("586c62") if not back else Color("526177")) canvas.draw_rect(Rect2(rect.position.x, floor_y-p, rect.size.x, p), INK) canvas.draw_rect(Rect2(rect.position.x+p, floor_y-7*p, p, 2*p), Color("dcc08b")) canvas.draw_rect(Rect2(rect.end.x-2*p, floor_y-7*p, p, 2*p), Color("dcc08b")) static func elevator_cabin(canvas: CanvasItem, rect: Rect2, p: float, back: bool, operational: bool) -> void: canvas.draw_rect(rect, INK) canvas.draw_rect(rect.grow(-p), Color("9daa8d") if not back else Color("879eaa")) canvas.draw_rect(Rect2(rect.position+Vector2(2,3)*p,rect.size-Vector2(4,5)*p),Color("556e62") if not back else Color("4d6472")) canvas.draw_rect(Rect2(rect.position.x+p,rect.end.y-3*p,rect.size.x-2*p,2*p),WOOD_LIGHT) canvas.draw_rect(Rect2(rect.position.x+2*p,rect.position.y+p,rect.size.x-4*p,p),CREAM) canvas.draw_rect(Rect2(rect.get_center().x-p,rect.position.y-p,2*p,p),Color("e2bd6c") if operational else Color("ba7157")) static func elevator_gate(canvas: CanvasItem, rect: Rect2, p: float, doors_open: bool) -> void: # The cutaway keeps passengers visible through the iron gate during travel. var rail := Color("bfbb9a") canvas.draw_rect(Rect2(rect.position.x,rect.position.y,2*p,rect.size.y),rail) canvas.draw_rect(Rect2(rect.end.x-2*p,rect.position.y,2*p,rect.size.y),rail) if doors_open: return var gate_y := rect.end.y-7*p canvas.draw_rect(Rect2(rect.position.x+2*p,gate_y,rect.size.x-4*p,p),rail) for x: int in range(int(rect.position.x+5*p),int(rect.end.x-3*p),maxi(int(6*p),1)): canvas.draw_rect(Rect2(x,rect.position.y+4*p,p,rect.size.y-7*p),Color("a9aa91",0.8)) static func window(canvas: CanvasItem, at: Vector2, p: float) -> void: canvas.draw_rect(Rect2(at, Vector2(7,9)*p), WOOD) canvas.draw_rect(Rect2(at+Vector2.ONE*p, Vector2(5,6)*p), Color("9ab9b3")) canvas.draw_rect(Rect2(at+Vector2(2,1)*p, Vector2(2,2)*p), Color("d5e3d0")) canvas.draw_rect(Rect2(at+Vector2(3,1)*p, Vector2(1,6)*p), WOOD_LIGHT) canvas.draw_rect(Rect2(at+Vector2(1,4)*p, Vector2(5,1)*p), WOOD_LIGHT) canvas.draw_rect(Rect2(at+Vector2(-1,8)*p, Vector2(9,1)*p), WOOD_LIGHT) static func door(canvas: CanvasItem, at: Vector2, p: float, color: Color) -> void: canvas.draw_rect(Rect2(at, Vector2(8,14)*p), INK) canvas.draw_rect(Rect2(at+Vector2.ONE*p, Vector2(6,13)*p), color) canvas.draw_rect(Rect2(at+Vector2(5,8)*p, Vector2.ONE*p), Color("f2ca81")) static func bed(canvas: CanvasItem, at: Vector2, p: float, cover: Color, width := 17) -> void: canvas.draw_rect(Rect2(at+Vector2(0,2)*p, Vector2(width,7)*p), WOOD) canvas.draw_rect(Rect2(at+Vector2(1,2)*p, Vector2(width-2,4)*p), CREAM) canvas.draw_rect(Rect2(at+Vector2(5,2)*p, Vector2(width-6,5)*p), cover) canvas.draw_rect(Rect2(at, Vector2(1,10)*p), WOOD) canvas.draw_rect(Rect2(at+Vector2(width-1,5)*p, Vector2(1,5)*p), WOOD) canvas.draw_rect(Rect2(at+Vector2(2,2)*p, Vector2(3,2)*p), Color("fff0d6")) static func counter(canvas: CanvasItem, at: Vector2, width: float, p: float) -> void: canvas.draw_rect(Rect2(at, Vector2(width, 6*p)), WOOD) canvas.draw_rect(Rect2(at, Vector2(width, p)), WOOD_LIGHT) canvas.draw_rect(Rect2(at+Vector2(2,2)*p, Vector2(width-4*p, 3*p)), Color("a67c53")) static func table(canvas: CanvasItem, at: Vector2, p: float) -> void: canvas.draw_rect(Rect2(at+Vector2(2,1)*p, Vector2(9,2)*p), WOOD_LIGHT) canvas.draw_rect(Rect2(at+Vector2(3,3)*p, Vector2(1,4)*p), WOOD) canvas.draw_rect(Rect2(at+Vector2(9,3)*p, Vector2(1,4)*p), WOOD) canvas.draw_rect(Rect2(at+Vector2(0,3)*p, Vector2(2,4)*p), TEAL) canvas.draw_rect(Rect2(at+Vector2(12,3)*p, Vector2(2,4)*p), TEAL) canvas.draw_rect(Rect2(at+Vector2(5,0)*p, Vector2(3,1)*p), CREAM)