HollowBond/Public/ecma/Builders/ElevatorsBuilder.ecma.js

224 lines
10 KiB
JavaScript

"use strict";
const ElevatorsBuilder = (function(){
const ElevatorsBuilder = function(hollow_bond){
const is_near_hole = (chunk, xf, yf, zf, xt, yt, zt) => {
const area_xf = xf - hollow_bond.elevator_margin_hole,
area_xt = xt + hollow_bond.elevator_margin_hole,
area_zf = zf - hollow_bond.elevator_margin_hole,
area_zt = zt + hollow_bond.elevator_margin_hole;
for(const box of chunk.occupancy)
if(box.type == "hole")
if(yf < box.yt && yt > box.yf && area_xf < box.xt && area_xt > box.xf && area_zf < box.zt && area_zt > box.zf)
return true;
return false;
};
const is_clearance_free = (chunk, x, y, z, facing, clearance_depth) => {
const size = hollow_bond.elevator_size || 2;
let cxf = x,
cxt = x + size,
czf = z,
czt = z + size;
switch(facing){
case "north":
czt = z;
czf = z - clearance_depth;
break;
case "south":
czf = z + size;
czt = czf + clearance_depth;
break;
case "west":
cxt = x;
cxf = x - clearance_depth;
break;
case "east":
cxf = x + size;
cxt = cxf + clearance_depth;
break;
};
return (
!(cxf < chunk.xf || cxt > chunk.xt || czf < chunk.zf || czt > chunk.zt) &&
!is_near_hole(chunk, cxf, y, czf, cxt, y + 1, czt, 0) &&
!chunk.is_occupied(cxf, y, czf, cxt, y + 1, czt)
);
};
const add = (chunk, inputs) => {
const id = ElevatorModel.get_id(inputs.x, inputs.y, inputs.z),
elevator = (
chunk.elevators[id] ||
hollow_bond.map.elevators[id] ||
new ElevatorModel(hollow_bond, Object.assign({}, inputs))
);
chunk.elevators[id] = elevator;
chunk.occupy(
elevator.x,
elevator.y,
elevator.z,
elevator.x + hollow_bond.elevator_size,
elevator.y + 1,
elevator.z + hollow_bond.elevator_size,
"elevator",
elevator.group_id
);
return elevator;
};
this.generate_seam = chunk => {
[[chunk.yf, "down"], [chunk.yt, "up"]].forEach(([plane_y, neighbor]) => {
if(!chunk.neighbors[neighbor])
return;
const networks = Math.floor(hollow_bond.hash.seam_elevator(chunk.xf, plane_y, chunk.zf, chunk.xt, chunk.zt, 0) * hollow_bond.elevator_networks_count); // e.g. 0 a 2 redes por frontera
for(let net_i = 0; net_i < networks; net_i ++){
const group_id = `net_${chunk.xf}_${plane_y}_${chunk.zf}_${net_i}`,
stops_count = Common.random_decay(
hollow_bond.hash.seam_elevator(chunk.xf, plane_y, chunk.zf, chunk.xt, chunk.zt, net_i * 10 + 1),
hollow_bond.elevator_minimum_floors,
hollow_bond.elevator_maximum_floors,
hollow_bond.elevator_floors_decay
),
network_stops = [];
for(let stop_i = 0; stop_i < stops_count; stop_i ++){
const hash_offset = net_i * 100 + stop_i * 6,
floor_y = plane_y - 25 + Math.floor(hollow_bond.hash.seam_elevator(chunk.xf, plane_y, chunk.zf, chunk.xt, chunk.zt, hash_offset + 2) * 50),
available_x = hollow_bond.chunk_size - hollow_bond.elevator_size - hollow_bond.elevator_margin_border * 2,
available_z = hollow_bond.chunk_size - hollow_bond.elevator_size - hollow_bond.elevator_margin_border * 2;
if(available_x <= 0 || available_z <= 0)
continue;
const elevator_x = chunk.xf + hollow_bond.elevator_margin_border + Math.floor(hollow_bond.hash.seam_elevator(chunk.xf, plane_y, chunk.zf, chunk.xt, chunk.zt, hash_offset + 3) * available_x),
elevator_z = chunk.zf + hollow_bond.elevator_margin_border + Math.floor(hollow_bond.hash.seam_elevator(chunk.xf, plane_y, chunk.zf, chunk.xt, chunk.zt, hash_offset + 4) * available_z),
facing = ["north", "south", "east", "west"][Math.floor(hollow_bond.hash.seam_elevator(chunk.xf, plane_y, chunk.zf, chunk.xt, chunk.zt, hash_offset + 5) * 4)];
network_stops.push({
group_id : group_id,
x : elevator_x,
y : floor_y,
z : elevator_z,
facing : facing,
floor : stop_i
});
floor_y >= chunk.yf && floor_y < chunk.yt &&
!is_near_hole(chunk, elevator_x, floor_y, elevator_z, elevator_x + hollow_bond.elevator_size, floor_y + 1, elevator_z + hollow_bond.elevator_size, hollow_bond.elevator_margin_hole) &&
!chunk.is_occupied(elevator_x, floor_y, elevator_z, elevator_x + hollow_bond.elevator_size, floor_y + 1, elevator_z + hollow_bond.elevator_size) &&
is_clearance_free(chunk, elevator_x, floor_y, elevator_z, facing, hollow_bond.room_minimum_size) &&
add(chunk, {
group_id : group_id,
x : elevator_x,
y : floor_y,
z : elevator_z,
facing : facing,
floors_from : Math.min(...network_stops),
floors_count : network_stops.length,
stops : network_stops,
floor : stop_i
});
};
};
});
return chunk.elevators;
};
this.generate_internal = chunk => {
const networks_count = 1 + Math.floor(hollow_bond.hash.elevator(chunk.xf, chunk.yf, chunk.zf, chunk.xt, chunk.yt, chunk.zt, 100) * (hollow_bond.elevator_internal_networks || 3));
for(let net = 0; net < networks_count; net ++){
const net_base_i = 200 + (net * 50),
stops_count = Common.random_decay(
hollow_bond.hash.elevator(chunk.xf, chunk.yf, chunk.zf, chunk.xt, chunk.yt, chunk.zt, net_base_i),
hollow_bond.elevator_minimum_floors,
hollow_bond.elevator_maximum_floors,
hollow_bond.elevator_floors_decay
),
group_id = `el_internal_${chunk.x}_${chunk.y}_${chunk.z}_${net}`,
group_cabins = [],
available_x = hollow_bond.chunk_size - hollow_bond.elevator_size - hollow_bond.elevator_margin_border * 2,
available_z = hollow_bond.chunk_size - hollow_bond.elevator_size - hollow_bond.elevator_margin_border * 2,
available_y = hollow_bond.chunk_size - 2;
if(available_x <= 0 || available_z <= 0 || available_y <= 0)
continue;
for(let stops = 0; stops < stops_count; stops ++){
const cabin_i = net_base_i + 1 + stops * 5,
elevator_x = chunk.xf + hollow_bond.elevator_margin_border + Math.floor(hollow_bond.hash.elevator(chunk.xf, chunk.yf, chunk.zf, chunk.xt, chunk.yt, chunk.zt, cabin_i + 1) * available_x),
elevator_y = chunk.yf + 1 + Math.floor(hollow_bond.hash.elevator(chunk.xf, chunk.yf, chunk.zf, chunk.xt, chunk.yt, chunk.zt, cabin_i + 2) * available_y),
elevator_z = chunk.zf + hollow_bond.elevator_margin_border + Math.floor(hollow_bond.hash.elevator(chunk.xf, chunk.yf, chunk.zf, chunk.xt, chunk.yt, chunk.zt, cabin_i + 3) * available_z),
facing = ["north", "south", "east", "west"][Math.floor(hollow_bond.hash.elevator(chunk.xf, chunk.yf, chunk.zf, chunk.xt, chunk.yt, chunk.zt, cabin_i + 4) * 4)];
if(
is_near_hole(chunk, elevator_x, elevator_y, elevator_z, elevator_x + hollow_bond.elevator_size, elevator_y + 1, elevator_z + hollow_bond.elevator_size, hollow_bond.elevator_margin_hole) ||
chunk.is_occupied(elevator_x, elevator_y, elevator_z, elevator_x + hollow_bond.elevator_size, elevator_y + 1, elevator_z + hollow_bond.elevator_size) ||
!is_clearance_free(chunk, elevator_x, elevator_y, elevator_z, facing, hollow_bond.room_minimum_size)
)
continue;
chunk.occupy(elevator_x, elevator_y, elevator_z, elevator_x + hollow_bond.elevator_size, elevator_y + 1, elevator_z + hollow_bond.elevator_size, "elevator", group_id);
group_cabins.push({
x : elevator_x,
y : elevator_y,
z : elevator_z,
facing : facing,
floor : stops
});
};
if(group_cabins.length >= 2){
const stops = group_cabins.map(cabin => cabin.y);
group_cabins.forEach(cabin => {
add(chunk, {
group_id : group_id,
x : cabin.x,
y : cabin.y,
z : cabin.z,
facing : cabin.facing,
floors_from : Math.min(...stops),
floors_count : stops.length,
stops : stops,
floor : cabin.floor
});
});
};
};
return chunk.elevators;
};
};
return ElevatorsBuilder;
})();