diff --git a/src/assets/warpdrive/lua/power/startup b/src/assets/warpdrive/lua/power/startup new file mode 100644 index 00000000..38d5e6f0 --- /dev/null +++ b/src/assets/warpdrive/lua/power/startup @@ -0,0 +1,2035 @@ +monitor_textScale = 0.5 + +-- set alarm side if you need this +alarm_side = "top" + +Style = { + CDefault = colors.white, + BGDefault = colors.blue, + + CTitle = colors.black, + BGTitle = colors.cyan, + + CWarning = colors.white, + BGWarning = colors.red, + + CSuccess = colors.white, + BGSuccess = colors.lime, + + CDisabled = colors.gray, + BGDisabled = colors.blue, + + CRadarmap = colors.gray, + BGRadarmap = colors.green, + + CRadarborder = colors.white, + BGRadarborder = colors.black, + + CRadarself = colors.white, + BGRadarself = colors.lime, + TextRadarself = "R", + + CRadarother = colors.black, + BGRadarother = colors.red, + TextRadarother = "#" +} + +if not term.isColor() then + print("Advanced computer required") + exit() +end + +----------- Monitor support + +function SetMonitorColorFrontBack(frontColor, backgroundColor) + term.setBackgroundColor(backgroundColor) + term.setTextColor(frontColor) + if monitors ~= nil then + for key,monitor in pairs(monitors) do + monitor.setTextColor(frontColor) + monitor.setBackgroundColor(backgroundColor) + end + end +end + +function Write(text) + term.write(text) + if monitors ~= nil then + for key,monitor in pairs(monitors) do + if key ~= data.radar_monitorIndex then + monitor.write(text) + end + end + end +end + +function SetCursorPos(x, y) + term.setCursorPos(x, y) + if monitors ~= nil then + for key,monitor in pairs(monitors) do + if key ~= data.radar_monitorIndex then + monitor.setCursorPos(x, y) + end + end + end +end + +function SetColorDefault() + SetMonitorColorFrontBack(Style.CDefault, Style.BGDefault) +end + +function SetColorTitle() + SetMonitorColorFrontBack(Style.CTitle, Style.BGTitle) +end + +function SetColorWarning() + SetMonitorColorFrontBack(Style.CWarning, Style.BGWarning) +end + +function SetColorSuccess() + SetMonitorColorFrontBack(Style.CSuccess, Style.BGSuccess) +end + +function SetColorDisabled() + SetMonitorColorFrontBack(Style.CDisabled, Style.BGDisabled) +end + +function SetColorRadarmap() + SetMonitorColorFrontBack(Style.CRadarmap, Style.BGRadarmap) +end + +function SetColorRadarborder() + SetMonitorColorFrontBack(Style.CRadarborder, Style.BGRadarborder) +end + +function Clear() + clearWarningTick = -1 + SetColorDefault() + term.clear() + if monitors ~= nil then + for key,monitor in pairs(monitors) do + if key ~= data.radar_monitorIndex then + monitor.clear() + end + end + end + SetCursorPos(1, 1) +end + +function ClearLine() + SetColorDefault() + term.clearLine() + if monitors ~= nil then + for key,monitor in pairs(monitors) do + if key ~= data.radar_monitorIndex then + monitor.clearLine() + end + end + end + SetCursorPos(1, 1) +end + +function WriteLn(Text) + Write(Text) + local x, y = term.getCursorPos() + local width, height = term.getSize() + if y > height - 1 then + y = 1 + end + SetCursorPos(1, y + 1) +end + +function WriteCentered(y, text) + SetCursorPos((51 - text:len()) / 2, y) + term.write(text) + if monitors ~= nil then + for key,monitor in pairs(monitors) do + if key ~= data.radar_monitorIndex then + local sizeX, sizeY = monitor.getSize() + monitor.setCursorPos((sizeX - text:len()) / 2, y) + monitor.write(text) + end + end + end + local xt, yt = term.getCursorPos() + SetCursorPos(1, yt + 1) +end + +function ShowTitle(text) + Clear() + SetColorTitle() + WriteCentered(1, text) + SetColorDefault() +end + +function ShowMenu(Text) + Write(Text) + local xt, yt = term.getCursorPos() + for i = xt, 51 do + Write(" ") + end + SetCursorPos(1, yt+1) +end + +local clearWarningTick = -1 +function ShowWarning(Text) + SetColorWarning() + SetCursorPos((51 - Text:len() - 2) / 2, 19) + Write(" "..Text.." ") + SetColorDefault() + clearWarningTick = 5 +end +function ClearWarning(Text) + if clearWarningTick > 0 then + clearWarningTick = clearWarningTick - 1 + elseif clearWarningTick == 0 then + SetColorDefault() + SetCursorPos(1, 19) + ClearLine() + end +end + +----------- Formatting & popups + +function FormatFloat(value, nbchar) + local str = "?" + if value ~= nil then + str = string.format("%f", value) + end + if nbchar ~= nil then + str = string.sub(" " .. str, -nbchar) + end + return str +end +function FormatInteger(value, nbchar) + local str = "?" + if value ~= nil then + str = string.format("%d", value) + end + if nbchar ~= nil then + str = string.sub(" " .. str, -nbchar) + end + return str +end + +function boolToYesNo(bool) + if bool then + return "YES" + else + return "no" + end +end + +function readInputNumber(currentValue) + local inputAbort = false + local input = string.format(currentValue) + if input == "0" then + input = "" + end + local x, y = term.getCursorPos() + repeat + ClearWarning() + SetColorDefault() + SetCursorPos(x, y) + Write(input .. " ") + input = string.sub(input, -9) + + local params = { os.pullEventRaw() } + local eventName = params[1] + local side = params[2] + if side == nil then side = "none" end + if eventName == "key" then + local keycode = params[2] + if keycode >= 2 and keycode <= 10 then -- 1 to 9 + input = input .. string.format(keycode - 1) + elseif keycode == 11 or keycode == 82 then -- 0 & keypad 0 + input = input .. "0" + elseif keycode >= 79 and keycode <= 81 then -- keypad 1 to 3 + input = input .. string.format(keycode - 78) + elseif keycode >= 75 and keycode <= 87 then -- keypad 4 to 6 + input = input .. string.format(keycode - 71) + elseif keycode >= 71 and keycode <= 73 then -- keypad 7 to 9 + input = input .. string.format(keycode - 64) + elseif keycode == 14 then -- Backspace + input = string.sub(input, 1, string.len(input) - 1) + elseif keycode == 211 then -- Delete + input = "" + elseif keycode == 28 then -- Enter + inputAbort = true + else + ShowWarning("Key " .. keycode .. " is invalid") + end + elseif eventName == "char" then + -- drop it + elseif eventName == "terminate" then + inputAbort = true + elseif not common_event(eventName, params[2]) then + ShowWarning("Event '" .. eventName .. "', " .. side .. " is unsupported") + end + until inputAbort + SetCursorPos(1, y + 1) + if input == "" then + return currentValue + else + return tonumber(input) + end +end + +function readInputText(currentValue) + local inputAbort = false + local input = string.format(currentValue) + local x, y = term.getCursorPos() + repeat + ClearWarning() + SetColorDefault() + SetCursorPos(x, y) + Write(input .. " ") + input = string.sub(input, -30) + + local params = { os.pullEventRaw() } + local eventName = params[1] + local side = params[2] + if side == nil then side = "none" end + if eventName == "key" then + local keycode = params[2] + if keycode == 14 then -- Backspace + input = string.sub(input, 1, string.len(input) - 1) + elseif keycode == 211 then -- Delete + input = "" + elseif keycode == 28 then -- Enter + inputAbort = true + else + -- ShowWarning("Key " .. keycode .. " is invalid") + end + elseif eventName == "char" then + local char = params[2] + if char >= ' ' and char <= '~' then -- 1 to 9 + input = input .. char + else + ShowWarning("Char #" .. string.byte(char) .. " is invalid") + end + elseif eventName == "terminate" then + inputAbort = true + elseif not common_event(eventName, params[2]) then + ShowWarning("Event '" .. eventName .. "', " .. side .. " is unsupported") + end + until inputAbort + SetCursorPos(1, y + 1) + if input == "" then + return currentValue + else + return input + end +end + +function readConfirmation() + ShowWarning("Are you sure? (y/n)") + repeat + local params = { os.pullEventRaw() } + local eventName = params[1] + local side = params[2] + if side == nil then side = "none" end + if eventName == "key" then + local keycode = params[2] + if keycode == 21 then -- Y + return true + else + return false + end + elseif eventName == "char" then + elseif eventName == "terminate" then + return false + elseif not common_event(eventName, params[2]) then + ShowWarning("Event '" .. eventName .. "', " .. side .. " is unsupported") + end + until false +end + +----------- commons: menu, event handlers, etc. + +function common_event(eventName, param) + if eventName == "redstone" then + redstone_event(param) + elseif eventName == "timer" then + if param == radar_timerId then + radar_timerEvent() + end + elseif eventName == "reactorPulse" then + reactor_pulse(param) +-- elseif eventName == "reactorDeactivation" then +-- ShowWarning("Reactor deactivated") +-- elseif eventName == "reactorActivation" then +-- ShowWarning("Reactor activated") + else + return false + end + return true +end + +function menu_common() + SetCursorPos(1, 18) + SetColorTitle() + ShowMenu("1 Reactor, 2 Cloak, 3 Mining, 4 Core, 5 Radar, eXit") +end + +----------- Redstone support + +local tblRedstoneState = {-- Remember redstone state on each side + ["top"] = rs.getInput("top"), + ["front"] = rs.getInput("front"), + ["left"] = rs.getInput("left"), + ["right"] = rs.getInput("right"), + ["back"] = rs.getInput("back"), + ["bottom"] = rs.getInput("bottom"), +} +local tblSides = {-- list all sides and offset coordinates + ["top" ] = { 3, 1}, + ["front" ] = { 1, 3}, + ["left" ] = { 3, 3}, + ["right" ] = { 5, 3}, + ["back" ] = { 5, 5}, + ["bottom"] = { 3, 5}, +} + +function redstone_event() + -- Event only returns nil so we need to check sides manually + local message = "" + for side, state in pairs(tblRedstoneState) do + if rs.getInput(side) ~= state then + -- print(side .. " is now " .. tostring(rs.getInput(side))) + message = message .. side .. " " + tblRedstoneState[side] = rs.getInput(side) + end + end + if message ~= "" then + message = "Redstone changed on " .. message + showWarning(message) + end +end + +----------- Cloaking support + +cloaking_highTier = false +cloaking_currentKey = 1 +function cloaking_key(keycode) + if keycode == 31 then -- S + cloaking_start() + return true + elseif keycode == 25 then -- P + cloaking_stop() + return true + elseif keycode == 20 then -- T + cloaking_highTier = not cloaking_highTier + return true + end + return false +end + +function cloaking_page() + ShowTitle(label .. " - Cloaking status") + + local cloakingcore = nil + if cloakingcores ~= nil then + if cloaking_currentKey > #cloakingcores then + cloaking_currentKey = 1 + end + cloakingcore = cloakingcores[cloaking_currentKey] + end + + SetCursorPos(1, 2) + if #cloakingcores == 0 then + SetColorDisabled() + Write("No cloaking core detected...") + elseif cloakingcore == nil then + SetColorWarning() + Write("Cloaking core " .. cloaking_currentKey .. " of " .. #cloakingcores .. " is invalid") + else + SetColorDefault() + Write("Cloaking core " .. cloaking_currentKey .. " of " .. #cloakingcores) + local isAssemblyValid = cloakingcore.isAssemblyValid() + local energy, energyMax = cloakingcore.getEnergyLevel() + local isEnabled = cloakingcore.enable() + + if not isAssemblyValid then + SetColorWarning() + SetCursorPos(1, 3) + Write("Invalid assembly!") + SetColorDefault() + SetCursorPos(1, 4) + print("In each direction, you need to place exactly 2 Cloaking device coils, for a total of 12 coils.") + print("The 6 inner coils shall be exactly one block away from the core.") + print("The cloaking field will extend 5 blocks past the outer 6 coils.") + print("Power consumption scales with the amount of cloaked blocks.") + else + SetCursorPos(1, 4) + Write("Assembly is valid") + + if energy < 50000 then + SetColorWarning() + else + SetColorDefault() + end + SetCursorPos(1, 6) + Write("Energy level is " .. energy .. " EU") + + SetCursorPos(1, 8) + if isEnabled then + if energy <= 100 then + SetColorWarning() + else + SetColorSuccess() + end + Write("Cloak is enabled") + else + SetColorNormal() + Write("Cloak is disabled") + end + end + end + sleep(0.1) + cloaking_currentKey = cloaking_currentKey + 1 + + SetColorDefault() + SetCursorPos(1, 12) + Write(" -----------------------------------------------") + SetCursorPos(1, 13) + if cloaking_highTier then + Write("Cloak tier: HIGH") + else + Write("Cloak tier: low") + end + + SetColorTitle() + SetCursorPos(1, 16) + ShowMenu("S - Start cloaking, P - stoP cloaking") + SetCursorPos(1, 17) + ShowMenu("T - change low/high Tier") +end + +function cloaking_start() + for key,cloakingcore in pairs(cloakingcores) do + cloakingcore.enable(false) + if cloaking_highTier then + cloakingcore.tier(2) + else + cloakingcore.tier(1) + end + cloakingcore.enable(true) + end +end + +function cloaking_stop() + for key,cloakingcore in pairs(cloakingcores) do + cloakingcore.enable(false) + end +end + +----------- Mining lasers support + +mining_currentKey = 1 +mining_layerOffset = 1 +mining_mineAll = true +mining_useDeuterium = false +function mining_key(keycode) + if keycode == 31 then -- S + mining_start() + return true + elseif keycode == 25 then -- P + mining_stop() + return true + elseif keycode == 30 then -- A + mining_mineAll = not mining_mineAll + return true + elseif keycode == 32 then -- D + mining_useDeuterium = not mining_useDeuterium + return true + elseif keycode == 74 then -- - + mining_layerOffset = mining_layerOffset - 1 + if mining_layerOffset < 1 then + mining_layerOffset = 1 + end + return true + elseif keycode == 78 then -- + + mining_layerOffset = mining_layerOffset + 1 + return true + elseif keycode == 46 then -- C + mining_page_config() + return true + end + return false +end + +function mining_page() + ShowTitle(label .. " - Mining status") + + local mininglaser = nil + if mininglasers ~= nil then + if mining_currentKey > #mininglasers then + mining_currentKey = 1 + end + mininglaser = mininglasers[mining_currentKey] + end + + SetCursorPos(1, 2) + if #mininglasers == 0 then + SetColorDisabled() + Write("No mining laser detected...") + elseif mininglaser == nil then + SetColorWarning() + Write("Mining laser " .. mining_currentKey .. " of " .. #mininglasers .. " is invalid") + else + SetColorDefault() + Write("Mining laser " .. mining_currentKey .. " of " .. #mininglasers) + local status, energy, currentLayer, mined, total = mininglaser.state() + SetCursorPos(1, 3) + Write("Status: " .. status .. " ") + SetCursorPos(1, 5) + Write("Energy level is " .. energy .. " EU") + SetCursorPos(1, 7) + Write("Mined " .. mined .. " out of " .. total .. " blocks at layer " .. currentLayer .. " ") + end + sleep(0.1) + mining_currentKey = mining_currentKey + 1 + + SetColorDefault() + SetCursorPos(1, 11) + Write(" -----------------------------------------------") + SetCursorPos(1, 12) + Write("Layer offset: " .. mining_layerOffset) + SetCursorPos(1, 13) + Write("Mine all: " .. boolToYesNo(mining_mineAll)) + SetCursorPos(1, 14) + Write("Use Deuterium: " .. boolToYesNo(mining_useDeuterium)) + + SetColorTitle() + SetCursorPos(1, 16) + ShowMenu("S - Start mining, P - stoP mining, A - mine All") + SetCursorPos(1, 17) + ShowMenu("D - use Deuterium, +/-/C - adjust offset") +end + +function mining_page_config() + ShowTitle(label .. " - Mining configuration") + Write(" Layer offset (".. mining_layerOffset ..") : ") + mining_layerOffset = readInputNumber(mining_layerOffset) + if mining_layerOffset < 1 then + mining_layerOffset = 1 + end +end + +function mining_start() + for key,mininglaser in pairs(mininglasers) do + if not mininglaser.isMining() then + mininglaser.offset(mining_layerOffset) + if mining_mineAll then + if mining_useDeuterium then + mininglaser.quarry(mining_useDeuterium) + else + mininglaser.quarry() + end + else + if mining_useDeuterium then + mininglaser.mine(mining_useDeuterium) + else + mininglaser.mine() + end + end + end + end +end + +function mining_stop() + if #mininglasers == 0 then + SetColorWarning() + Write("No mining laser detected") + else + for key,mininglaser in pairs(mininglasers) do + SetCursorPos(1, 2 + key) + if not mininglaser.isMining() then + SetColorDisabled() + Write("Mining laser " .. key .. " of " .. #mininglasers .. " is already stopped") + else + mininglaser.stop() + SetColorSuccess() + Write("Mining laser " .. key .. " of " .. #mininglasers .. " has been stopped") + end + end + end +end + +----------- Configuration + +function data_save() + local file = fs.open("shipdata.txt", "w") + file.writeLine(textutils.serialize(data)) + file.close() +end + +function data_read() + if fs.exists("shipdata.txt") then + local file = fs.open("shipdata.txt", "r") + data = textutils.unserialize(file.readAll()) + file.close() + else + data = { } + end + if data.core_summon == nil then data.core_summon = false; end + if data.core_distance == nil then data.core_distance = 0; end + if data.core_direction == nil then data.core_direction = 0; end + if data.reactor_mode == nil then data.reactor_mode = 0; end + if data.reactor_rate == nil then data.reactor_rate = 100; end + if data.reactor_targetStability == nil then data.reactor_targetStability = 50; end + if data.reactor_laserAmount == nil then data.reactor_laserAmount = 10000; end + if data.radar_monitorIndex == nil then data.radar_monitorIndex = 0; end + if data.radar_radius == nil then data.radar_radius = 500; end + if data.radar_autoscan == nil then data.radar_autoscan = false; end + if data.radar_autoscanDelay == nil then data.radar_autoscanDelay = 3; end + if data.radar_results == nil then data.radar_results = {}; end + if data.radar_scale == nil then data.radar_scale = 500; end + if data.radar_offsetX == nil then data.radar_offsetX = 0; end + if data.radar_offsetY == nil then data.radar_offsetY = 0; end +end + +function data_explode(separator, data) + local result, iCurrent, iNext + result = {} + iCurrent = 0 + if(#data == 1) then return {data} end + while true do + iNext = string.find(data, separator, iCurrent, true) + if iNext ~= nil then + table.insert(result, string.sub(data, iCurrent, iNext - 1)) + iCurrent = iNext + 1 + else + table.insert(result, string.sub(data, iCurrent)) + break + end + end + return result +end + +function data_setName() + if warpcore ~= nil then + ShowTitle("<==== Set ship name ====>") + else + ShowTitle("<==== Set name ====>") + end + + SetCursorPos(1, 2) + Write("Enter ship name: ") + label = readInputText(label) + os.setComputerLabel(label) + if warpcore ~= nil then + warpcore.coreFrequency(label) + end + os.reboot() +end + +----------- Warpcore support + +core_front = 0 +core_right = 0 +core_up = 0 +core_back = 0 +core_left = 0 +core_down = 0 +core_isInHyper = false +core_shipLength = 0 +core_realDistance = 0 +core_jumpCost = 0 +core_shipSize = 0 + +function core_boot() + if warpcore == nil then + return + end + + Write("Booting Warpdrive Core") + + if data.core_summon then + warpcore.summon_all() + end + + Write(".") + core_front, core_right, core_up = warpcore.dim_positive() + core_back, core_left, core_down = warpcore.dim_negative() + core_isInHyper = warpcore.isInHyperspace() + + Write(".") + repeat + pos = warpcore.pos() + sleep(0.3) + until pos ~= nil + X, Y, Z = warpcore.pos() + Write(".") + repeat + isAttached = warpcore.isAttached() + sleep(0.3) + until isAttached ~= false + + Write(".") + repeat + core_shipSize = warpcore.getShipSize() + sleep(0.3) + until core_shipSize ~= nil + + Write(".") + core_computeRealDistance() + + Write(".") + warpcore.mode(1) + WriteLn("") +end + +function core_writeDirection() + if data.core_direction == 1 then + WriteLn(" Direction = Up") + elseif data.core_direction == 2 then + WriteLn(" Direction = Down") + elseif data.core_direction == 0 then + WriteLn(" Direction = Front") + elseif data.core_direction == 180 then + WriteLn(" Direction = Back") + elseif data.core_direction == 90 then + WriteLn(" Direction = Left") + elseif data.core_direction == 255 then + WriteLn(" Direction = Right") + end +end + +function core_computeRealDistance() + if core_isInHyper then + core_shipLength = 0 + core_realDistance = data.core_distance * 100 + core_shipLength + core_jumpCost = (1000 * core_shipSize) + (1000 * data.core_distance) + else + if data.core_direction == 1 or data.core_direction == 2 then + core_shipLength = core_up + core_down + 1 + elseif data.core_direction == 0 or data.core_direction == 180 then + core_shipLength = core_front + core_back + 1 + elseif data.core_direction == 90 or data.core_direction == 255 then + core_shipLength = core_left + core_right + 1 + end + core_realDistance = data.core_distance + core_shipLength - 1 + core_jumpCost = (10 * core_shipSize) + (100 * data.core_distance) + end +end + +function core_computeNewCoordinates(cx, cy, cz) + local res = { x = cx, y = cy, z = cz } + if data.core_direction == 1 then + res.y = res.y + core_realDistance + elseif data.core_direction == 2 then + res.y = res.y - core_realDistance + end + local dx, dy, dz = warpcore.getOrientation() + if dx ~= 0 then + if data.core_direction == 0 then + res.x = res.x + (core_realDistance * dx) + elseif data.core_direction == 180 then + res.x = res.x - (core_realDistance * dx) + elseif data.core_direction == 90 then + res.z = res.z + (core_realDistance * dx) + elseif data.core_direction == 255 then + res.z = res.z - (core_realDistance * dx) + end + else + if data.core_direction == 0 then + res.z = res.z + (core_realDistance * dz) + elseif data.core_direction == 180 then + res.z = res.z - (core_realDistance * dz) + elseif data.core_direction == 90 then + res.x = res.x + (core_realDistance * dz) + elseif data.core_direction == 255 then + res.x = res.x - (core_realDistance * dz) + end + end + return res +end + +function core_warp() + rs.setOutput(alarm_side, true) + if readConfirmation() then + rs.setOutput(alarm_side, false) + warpcore.direction(data.core_direction) + warpcore.distance(data.core_distance) + if core_isInHyper then + warpcore.mode(2) + else + warpcore.mode(1) + end + warpcore.jump() + end + rs.setOutput(alarm_side, false) +end + +function core_page_setDistance() + ShowTitle("<==== Set distance ====>") + + core_computeRealDistance() + local maximumDistance = core_shipLength + 127 + local userEntry = core_realDistance + if userEntry <= 1 then + userEntry = 0 + end + repeat + SetCursorPos(1, 2) + if core_isInHyper then + Write("Distance * 100 (min " .. core_shipLength .. ", max " .. maximumDistance .. "): ") + else + Write("Distance (min " .. (core_shipLength + 1) .. ", max " .. maximumDistance .. "): ") + end + userEntry = readInputNumber(userEntry) + if userEntry <= core_shipLength or userEntry > maximumDistance then + ShowWarning("Wrong distance. Try again.") + end + until userEntry > core_shipLength and userEntry <= maximumDistance + + data.core_distance = userEntry - core_shipLength + 1 + core_computeRealDistance() +end + +function core_page_setDirection() + local drun = true + while(drun) do + ShowTitle("<==== Set direction ====>") + core_writeDirection() + term.setCursorPos(1, 16) + SetColorTitle() + ShowMenu("Use directional keys") + ShowMenu("W/S keys for Up/Down") + ShowMenu("Enter - confirm") + SetColorDefault() + local event, keycode = os.pullEvent("key") + if keycode == 200 then + data.core_direction = 0 + elseif keycode == 17 then + data.core_direction = 1 + elseif keycode == 203 then + data.core_direction = 90 + elseif keycode == 205 then + data.core_direction = 255 + elseif keycode == 208 then + data.core_direction = 180 + elseif keycode == 31 then + data.core_direction = 2 + elseif keycode == 28 then + drun = false + end + end +end + +function core_page_setDimensions() + ShowTitle("<==== Set dimensions ====>") + Write(" Front (".. core_front ..") : ") + core_front = readInputNumber(core_front) + Write(" Right (".. core_right ..") : ") + core_right = readInputNumber(core_right) + Write(" Up (".. core_up ..") : ") + core_up = readInputNumber(core_up) + Write(" Back (".. core_back ..") : ") + core_back = readInputNumber(core_back) + Write(" Left (".. core_left ..") : ") + core_left = readInputNumber(core_left) + Write(" Down (".. core_down ..") : ") + core_down = readInputNumber(core_down) + Write("Setting dimensions...") + warpcore.dim_positive(core_front, core_right, core_up) + warpcore.dim_negative(core_back, core_left, core_down) + core_shipSize = warpcore.getShipSize() + if core_shipSize == nil then core_shipSize = 0 end +end + +function core_page_summon() + ShowTitle("<==== Summon players ====>") + local playersString, playersArray = warpcore.getAttachedPlayers() + for i = 1, #playersArray do + Show(i..". "..playersArray[i]) + end + SetColorTitle() + ShowMenu("Enter player number") + ShowMenu("or press enter to summon everyone") + SetColorDefault() + + Write(":") + local input = readInputNumber("") + if input == "" then + warpcore.summon_all() + else + input = tonumber(input) + warpcore.summon(input - 1) + end +end + +function core_page_jumpToBeacon() + ShowTitle("<==== Jump to beacon ====>") + + Write("Enter beacon frequency: ") + local freq = readInputText("") + rs.setOutput(alarm_side, true) + if readConfirmation() then + rs.setOutput(alarm_side, false) + warpcore.mode(4) + warpcore.beaconFrequency(freq) + warpcore.jump() + end + rs.setOutput(alarm_side, false) +end + +function core_page_jumpToGate() + ShowTitle("<==== Jump to Jumpgate ====>") + + Write("Enter jumpgate name: ") + local name = readInputText("") + rs.setOutput(alarm_side, true) + if readConfirmation() then + rs.setOutput(alarm_side, false) + warpcore.mode(6) + warpcore.targetJumpgate(name) + warpcore.jump() + end + rs.setOutput(alarm_side, false) +end + +function core_page() + ShowTitle(label .. " - Warpcore status") + if warpcore ~= nil then + WriteLn("Core:") + WriteLn(" x, y, z = " .. X .. ", " .. Y .. ", " .. Z) + local energy, energyMax = warpcore.getEnergyLevel() + if energy == nil then energy = 0 end + if energyMax == nil then energyMax = 1 end + WriteLn(" Energy = " .. math.floor(energy / energyMax * 100) .. " % (" .. energy .. "EU)") + local playersString, playersArray = warpcore.getAttachedPlayers() + if playersString == "" then players = "-" end + WriteLn(" Attached players = " .. playersString) + WriteLn("Dimensions:") + WriteLn(" Front, Right, Up = " .. FormatInteger(core_front) .. ", " .. FormatInteger(core_right) .. ", " .. FormatInteger(core_up)) + WriteLn(" Back, Left, Down = " .. FormatInteger(core_back) .. ", " .. FormatInteger(core_left) .. ", " .. FormatInteger(core_down)) + WriteLn(" Size = " .. core_shipSize .. " blocks") + WriteLn("Warp data:") + core_writeDirection() + local dest = core_computeNewCoordinates(X, Y, Z) + WriteLn(" Distance = " .. core_realDistance .. " (" .. core_jumpCost .. "EU, " .. math.floor(energy / core_jumpCost) .. " jumps)") + WriteLn(" Dest.coordinates = " .. FormatInteger(dest.x) .. ", " .. FormatInteger(dest.y) .. ", " .. FormatInteger(dest.z)) + if data.core_summon then + WriteLn(" Summon after = Yes") + else + WriteLn(" Summon after = No") + end + else + ShowWarning("No warpcore controller detected") + end + + SetCursorPos(1, 15) + SetColorTitle() + ShowMenu("D - Dimensions, M - Toggle summon, N - Ship name") + ShowMenu("S - Set Warp Data, J - Jump, G - Jump to JumpGate") + ShowMenu("B - Jump to Beacon, H - Jump to Hyperspace") + ShowMenu("C - core_page_summon crew") +end + +function core_key(keycode) + if keycode == 31 then -- S + core_page_setDirection() + core_page_setDistance() + data_save() + return true + elseif keycode == 50 then -- M + if data.core_summon then + data.core_summon = false + else + data.core_summon = true + end + data_save() + return true + elseif keycode == 32 then -- D + core_page_setDimensions() + data_save() + return true + elseif keycode == 36 then -- J + core_warp() + return true + elseif keycode == 46 then -- C + core_page_summon() + return true + elseif keycode == 48 then -- B + core_page_jumpToBeacon() + return true + elseif keycode == 34 then -- G + core_page_jumpToGate() + return true + elseif keycode == 35 then -- H + rs.setOutput(alarm_side, true) + if readConfirmation() then + rs.setOutput(alarm_side, false) + warpcore.mode(5) + warpcore.jump() + end + rs.setOutput(alarm_side, false) + return true + elseif keycode == 49 then + data_setName() + return true + end + return false +end + +----------- Reactor support + +reactor_output = 0 + +function reactor_boot() + if reactor ~= nil then + WriteLn("Booting Reactor...") + local isActive, strMode, releaseRate = reactor.active() + if strMode == "OFF" then + data.reactor_mode = 0 + elseif strMode == "MANUAL" then + data.reactor_mode = 1 + elseif strMode == "ABOVE" then + data.reactor_mode = 2 + elseif strMode == "RATE" then + data.reactor_mode = 3 + else + data.reactor_mode = 0 + end + end +end + +function reactor_key(keycode) + if keycode == 31 then -- S + reactor_start() + return true + elseif keycode == 25 then -- P + reactor_stop() + return true + elseif keycode == 38 then -- L + reactor_laser() + return true + elseif keycode == 24 then -- O + data.reactor_mode = (data.reactor_mode + 1) % 4 + reactor_setMode() + data_save() + return true + elseif keycode == 34 then -- G + data.reactor_rate = data.reactor_rate / 10 + reactor_setMode() + data_save() + return true + elseif keycode == 20 then -- T + data.reactor_rate = data.reactor_rate * 10 + reactor_setMode() + data_save() + return true + elseif keycode == 36 then -- J + data.reactor_laserAmount = data.reactor_laserAmount / 10 + reactor_setLaser() + data_save() + return true + elseif keycode == 22 then -- U + data.reactor_laserAmount = data.reactor_laserAmount * 10 + reactor_setLaser() + data_save() + return true + elseif keycode == 74 then -- - + data.reactor_targetStability = data.reactor_targetStability - 1 + reactor_setTargetStability() + data_save() + return true + elseif keycode == 78 then -- + + data.reactor_targetStability = data.reactor_targetStability + 1 + reactor_setTargetStability() + data_save() + return true + elseif keycode == 46 then -- C + reactor_config() + data_save() + return true + end + return false +end + +function reactor_page() + ShowTitle(label .. " - Reactor status") + + SetCursorPos(1, 2) + if reactor == nil then + SetColorDisabled() + Write("Reactor not detected") + else + SetColorDefault() + Write("Reactor stability") + instabilities = { reactor.instability() } + average = 0 + for key,instability in pairs(instabilities) do + SetCursorPos(12, 2 + key) + stability = math.floor((100.0 - instability) * 10) / 10 + if stability >= data.reactor_targetStability then + SetColorSuccess() + else + SetColorWarning() + end + Write(FormatFloat(stability, 5) .. " %") + average = average + instability + end + average = average / #instabilities + + SetColorDefault() + local energy = { reactor.energy() } + SetCursorPos(1, 7) + Write("Energy : ") + if energy[1] ~= nil then + Write(FormatInteger(energy[1], 10) .. " / " .. energy[2] .. " RF +" .. FormatInteger(reactor_output, 5) .. " RF/t") + else + Write("???") + end + SetCursorPos(1, 8) + Write("Outputing: ") + if energy[1] ~= nil then + Write(energy[3] .. " RF/t") + end + + SetColorDefault() + SetCursorPos(1, 9) + Write("Activated: ") + isActive = reactor.active() + if isActive then SetColorSuccess() else SetColorDefault() end + Write(boolToYesNo(isActive)) + end + + if #reactorlasers == 0 then + SetColorDisabled() + SetCursorPos(30, 2) + Write("Lasers not detected") + else + SetColorDefault() + SetCursorPos(30, 2) + Write("Lasers") + + for key,reactorlaser in pairs(reactorlasers) do + local side = reactorlaser.side() + if side ~= nil then + side = side % 4 + SetColorDefault() + SetCursorPos(4, 3 + side) + Write("Side " .. side .. ":") + SetCursorPos(30, 3 + side) + local energy = reactorlaser.energy() + if not reactorlaser.hasReactor() then + SetColorDisabled() + elseif energy > 3 * data.reactor_laserAmount then + SetColorSuccess() + else + SetColorWarning() + end + Write(FormatInteger(reactorlaser.energy(), 6)) + end + end + end + + SetColorDefault() + SetCursorPos(1, 10) + Write(" -----------------------------------------------") + SetCursorPos(1, 11) + Write("Output mode : ") + if data.reactor_mode == 0 then + SetColorDisabled() + Write("hold") + elseif data.reactor_mode == 1 then + Write("manual/unlimited") + elseif data.reactor_mode == 2 then + Write("surplus above " .. data.reactor_rate .. " RF") + else + Write("rated at " .. data.reactor_rate .. " RF") + end + SetColorDefault() + SetCursorPos( 1, 12) + Write("Target stability: " .. data.reactor_targetStability .. "%") + SetCursorPos(30, 12) + Write("Laser amount: " .. data.reactor_laserAmount) + + SetColorTitle() + SetCursorPos(1, 14) + ShowMenu("S - Start reactor, P - Stop reactor, L - Use lasers") + SetCursorPos(1, 15) + ShowMenu("O - Output mode, C - Configuration") + SetCursorPos(1, 16) + ShowMenu("+/- - Target stability, U/J - Laser amount") + SetCursorPos(1, 17) + ShowMenu("G/T - Output rate/threshold") +end + +function reactor_setMode() + if data.reactor_rate < 1 then + data.reactor_rate = 1 + elseif data.reactor_rate > 100000 then + data.reactor_rate = 100000 + end + if reactor ~= nil then + if data.reactor_mode == 0 then + reactor.release(false) + elseif data.reactor_mode == 1 then + reactor.release(true) + elseif data.reactor_mode == 2 then + reactor.releaseAbove(data.reactor_rate) + else + reactor.releaseRate(data.reactor_rate) + end + end +end + +function reactor_setLaser() + if data.reactor_laserAmount < 1 then + data.reactor_laserAmount = 1 + elseif data.reactor_laserAmount > 100000 then + data.reactor_laserAmount = 100000 + end +end + +function reactor_setTargetStability() + if data.reactor_targetStability < 1 then + data.reactor_targetStability = 1 + elseif data.reactor_targetStability > 100 then + data.reactor_targetStability = 100 + end +end + +function reactor_start() + if reactor ~= nil then + reactor_setMode() + reactor.active(true) + end +end + +function reactor_stop() + if reactor ~= nil then + reactor.active(false) + end +end + +function reactor_laser(side) + for key,reactorlaser in pairs(reactorlasers) do + if (side == nil) or (reactorlaser.side() == side) then + reactorlaser.sendLaser(data.reactor_laserAmount) + end + end +end + +function reactor_pulse(output) + reactor_output = output + if reactor == nil then + os.reboot() + end + local instabilities = { reactor.instability() } + for key,instability in pairs(instabilities) do + local stability = math.floor((100.0 - instability) * 10) / 10 + if stability < data.reactor_targetStability then + reactor_laser(key - 1) + end + end +end + +function reactor_config() + ShowTitle(label .. " - Reactor configuration") + + SetCursorPos(1, 2) + if reactor == nil then + SetColorDisabled() + Write("Reactor not detected") + else + SetColorDefault() + SetCursorPos(1, 4) + Write("Reactor output rate (" .. data.reactor_rate .. " RF): ") + data.reactor_rate = readInputNumber(data.reactor_rate) + reactor_setMode() + SetCursorPos(1, 5) + Write("Reactor output rate set") + + SetCursorPos(1, 7) + Write("Laser energy level (" .. data.reactor_laserAmount .. "): ") + data.reactor_laserAmount = readInputNumber(data.reactor_laserAmount) + reactor_setLaser() + SetCursorPos(1, 8) + Write("Laser energy level set") + + SetCursorPos(1, 10) + Write("Reactor target stability (" .. data.reactor_targetStability .. "%): ") + data.reactor_targetStability = readInputNumber(data.reactor_targetStability) + reactor_setTargetStability() + SetCursorPos(1, 11) + Write("Reactor target stability set") + end +end + +----------- Radar support + +radar_listOffset = 0 +radar_timerId = -1 +radar_timerLength = 1 +radar_x = 0 +radar_y = 0 +radar_z = 0 + +function radar_boot() + if radar ~= nil then + WriteLn("Booting Radar...") + if data.radar_monitorIndex > 0 then + radar_x, radar_y, radar_z = radar.pos() + radar_drawMap() + end + if data.radar_autoscan then + radar_scan() + end + end +end + +function radar_key(keycode) + if keycode == 31 then -- S + data.radar_autoscan = false + radar_scan() + return true + elseif keycode == 30 then -- A + data.radar_autoscan = true + radar_scan() + return true + elseif keycode == 25 then -- P + data.radar_autoscan = false + return true + elseif keycode == 49 then -- N + radar_setMonitorIndex(data.radar_monitorIndex + 1) + data_save() + radar_drawMap() + return true + elseif keycode == 34 then -- G + radar_setRadius(data.radar_radius - 100) + data_save() + return true + elseif keycode == 20 then -- T + if data.radar_radius < 100 then + radar_setRadius(100) + else + radar_setRadius(data.radar_radius + 100) + end + data_save() + return true + elseif keycode == 36 then -- J + radar_listOffset = math.max(0, radar_listOffset - 3) + return true + elseif keycode == 22 then -- U + radar_listOffset = math.min(#data.radar_results - 1, radar_listOffset + 3) + return true + elseif keycode == 74 then -- - + data.radar_scale = math.min(10000, math.floor(data.radar_scale * 1.2 + 0.5)) + data_save() + radar_drawMap() + return true + elseif keycode == 78 then -- + + data.radar_scale = math.max(20, math.floor(data.radar_scale * 0.8 + 0.5)) + data_save() + radar_drawMap() + return true + elseif keycode == 199 then -- home + data.radar_offsetX = 0; + data.radar_offsetY = 0; + data.radar_scale = 20 + for i = 0, #data.radar_results - 1 do + data.radar_scale = math.max(data.radar_scale, math.max(math.abs(radar_x - data.radar_results[i].x), math.abs(radar_z - data.radar_results[i].z))) + end + data.radar_scale = math.min(10000, math.floor(data.radar_scale * 1.1 + 0.5)) + data_save() + radar_drawMap() + return true + elseif keycode == 203 then -- left + data.radar_offsetX = data.radar_offsetX - 0.20 * data.radar_scale; + data_save() + radar_drawMap() + return true + elseif keycode == 205 then -- right + data.radar_offsetX = data.radar_offsetX + 0.20 * data.radar_scale; + data_save() + radar_drawMap() + return true + elseif keycode == 200 then -- up + data.radar_offsetY = data.radar_offsetY - 0.20 * data.radar_scale; + data_save() + radar_drawMap() + return true + elseif keycode == 208 then -- down + data.radar_offsetY = data.radar_offsetY + 0.20 * data.radar_scale; + data_save() + radar_drawMap() + return true + elseif keycode == 46 then -- C + radar_page_config() + data_save() + return true + end + return false +end + +function radar_page() + local radar_resultsPerPage = 9 + + ShowTitle(label .. " - Radar map") + + SetCursorPos(1, 2) + if radar == nil then + SetColorDisabled() + Write("Radar not detected") + else + SetColorDefault() + if #data.radar_results == 0 then + Write("No contacts in range...") + else + local lastResultShown = radar_listOffset + radar_resultsPerPage - 1 + if lastResultShown >= #data.radar_results then + lastResultShown = #data.radar_results - 1 + end + Write("Displaying results " .. (radar_listOffset + 1) .. " to " .. (lastResultShown + 1) .. " of " .. #data.radar_results) + for i = radar_listOffset, lastResultShown do + SetCursorPos(4, 3 + i - radar_listOffset) + if data.radar_results ~= nil then + Write(FormatInteger(data.radar_results[i].x, 7) .. ", " .. FormatInteger(data.radar_results[i].y, 4) .. ", " .. FormatInteger(data.radar_results[i].z, 7)) + Write(": " .. data.radar_results[i].frequency) + else + Write("~nil~") + end + end + end + + SetColorDefault() + local energy = { radar.getEnergyLevel() } + SetCursorPos(1, 12) + Write("Energy: ") + if energy ~= nil then + if energy[1] > (data.radar_radius * data.radar_radius) then + SetColorSuccess() + else + SetColorWarning() + end + Write(FormatInteger(energy[1], 10) .. " EU") + else + SetColorDisabled() + Write("???") + end + SetColorDefault() + SetCursorPos(1, 13) + Write("Radius: " .. data.radar_radius) + + SetCursorPos(30, 13) + Write("Monitor# " .. data.radar_monitorIndex .. "/" .. #monitors) + + SetCursorPos(1, 14) + Write("Autoscan: ") + if data.radar_autoscan then SetColorSuccess() else SetColorDefault() end + Write(boolToYesNo(data.radar_autoscan)) + + SetColorDefault() + SetCursorPos(30, 14) + Write("Delay " .. data.radar_autoscanDelay .. "s") + end + + SetColorTitle() + SetCursorPos(1, 15) + ShowMenu("S - Scan once, A - Autoscan, P - Stop autoscan") + SetCursorPos(1, 16) + ShowMenu("T/G - Scan radius, U/J - Scroll list") + SetCursorPos(1, 17) + ShowMenu("+/- - Scale, N - Next monitor, C - Configuration") +end + +function radar_page_config() + ShowTitle(label .. " - Radar configuration") + + SetCursorPos(1, 2) + if radar == nil then + SetColorDisabled() + Write("No radar detected") + else + SetColorDefault() + SetCursorPos(1, 3) + Write("Radar scan radius (" .. data.radar_radius .. " blocks): ") + radar_setRadius(readInputNumber(data.radar_radius)) + + SetCursorPos(1, 5) + Write("Autoscan delay in seconds (" .. data.radar_autoscanDelay .. "): ") + radar_setAutoscanDelay(readInputNumber(data.radar_autoscanDelay)) + + SetCursorPos(1, 7) + Write("Output monitor (" .. data.radar_monitorIndex .. "/" .. #monitors .. "): ") + radar_setMonitorIndex(readInputNumber(data.radar_monitorIndex)) + + data_save() + end +end + +function radar_setRadius(newRadius) + if newRadius < 1 then + data.radar_radius = 1 + elseif newRadius >= 10000 then + data.radar_radius = 10000 + else + data.radar_radius = newRadius + end +end + +function radar_setAutoscanDelay(newAutoscanDelay) + if newAutoscanDelay < 1 then + data.radar_autoscanDelay = 1 + elseif newAutoscanDelay >= 3600 then -- 1 hour + data.radar_autoscanDelay = 3600 + else + data.radar_autoscanDelay = newAutoscanDelay + end +end + +function radar_setMonitorIndex(newIndex) + if #monitors == 0 or newIndex < 0 or newIndex > #monitors then + data.radar_monitorIndex = 0 + else + data.radar_monitorIndex = newIndex + end +end + +function radar_getMonitor() + if data.radar_monitorIndex > 0 and data.radar_monitorIndex <= #monitors then + return monitors[data.radar_monitorIndex] + else + return nil + end +end + +function radar_scan() + local monitor = radar_getMonitor() + if radar == nil then + draw_warning(monitor, "No radar") + return false + end + if radar.getEnergyLevel() < (data.radar_radius * data.radar_radius) then + draw_warning(monitor, "LOW POWER") + return false + end + if radar_timerId ~= -1 and radar.getResultsCount() == -1 then + draw_warning(monitor, "Already scanning...") + return false + end + radar_timerId = os.startTimer(radar_timerLength) + + radar.scanRadius(data.radar_radius); + draw_warning(monitor, "Scanning...") + return false +end + +function radar_scanDone() + local numResults = radar.getResultsCount(); + data.radar_results = {} + if (numResults ~= 0) then + for i = 0, numResults do + local frequency, x, y, z = radar.getResult(i) + if frequency == "default" then + frequency = "?" + end + data.radar_results[i] = { x = x, y = y, z = z, frequency = frequency, kind = "core" } + end + data.radar_scale = data.radar_radius + end + data_save() + radar_drawMap() +end + +function draw_text(monitor, x, y, text, textColor, backgroundColor) + if monitor == nil then + term.setCursorPos(x, y) + if textColor ~= nil then term.setTextColor(textColor) end + if backgroundColor ~= nil then term.setBackgroundColor(backgroundColor) end + term.write(text) + local xt, yt = term.getCursorPos() + term.setCursorPos(1, yt + 1) + else + monitor.setCursorPos(x, y) + if textColor ~= nil then monitor.setTextColor(textColor) end + if backgroundColor ~= nil then monitor.setBackgroundColor(backgroundColor) end + monitor.write(text) + local xt, yt = monitor.getCursorPos() + monitor.setCursorPos(1, yt + 1) + end +end + +function draw_warning(monitor, text) + local screenWidth, screenHeight + if monitor == nil then + screenWidth, screenHeight = term.getSize() + else + screenWidth, screenHeight = monitor.getSize() + end + local centerX = math.floor(screenWidth / 2); + local centerY = math.floor(screenHeight / 2); + local halfWidth = math.ceil(string.len(text) / 2); + local blank = string.sub(" ", - (string.len(text) + 2)) + + draw_text(monitor, centerX - halfWidth - 1, centerY - 1, blank, colors.white, colors.red); + draw_text(monitor, centerX - halfWidth - 1, centerY , " " .. text .. " ", colors.white, colors.red); + draw_text(monitor, centerX - halfWidth - 1, centerY + 1, blank, colors.white, colors.red); +end + +function draw_centeredText(monitor, y, text) + local screenWidth, screenHeight + if monitor == nil then + screenWidth, screenHeight = term.getSize() + else + screenWidth, screenHeight = monitor.getSize() + end + local x = math.floor(screenWidth / 2 - string.len(text) / 2 + 0.5); + + draw_text(monitor, x, y, text, nil, nil); +end + +function radar_drawContact(monitor, contact) + local screenWidth, screenHeight + if monitor == nil then + screenWidth, screenHeight = term.getSize() + else + screenWidth, screenHeight = monitor.getSize() + end + + local screenX = (radar_x + data.radar_offsetX - contact.x) / data.radar_scale + local screenY = (radar_z + data.radar_offsetY - contact.z) / data.radar_scale + local visible = true + + if screenX <= -1 or screenX >= 1 or screenY <= -1 or screenY >= 1 then + screenX = math.min(1, math.max(-1, screenX)) + screenY = math.min(1, math.max(-1, screenY)) + visible = false + end + + screenX = math.floor(screenX * (screenWidth - 3) / 2 + ((screenWidth - 1) / 2) + 1.5) + screenY = math.floor(screenY * (screenHeight - 3) / 2 + ((screenHeight - 1) / 2) + 1.5) + + if contact.kind == "self" then + draw_text(monitor, screenX, screenY, Style.TextRadarself, Style.CRadarself, Style.BGRadarself) + else + draw_text(monitor, screenX, screenY, Style.TextRadarother, Style.CRadarother, Style.BGRadarother) + end + if visible then + local text = contact.frequency + screenX = math.min(screenWidth - 1 - string.len(text), math.max(2, math.floor(screenX - string.len(text) / 2 + 0.5))) + if screenY == (screenHeight - 1) then + screenY = screenY - 1 + else + screenY = screenY + 1 + end + draw_text(monitor, screenX, screenY, text, Style.CRadarother, Style.BGRadarother) + end +end + +function radar_drawMap() + local screenWidth, screenHeight, x, y + local monitor = radar_getMonitor() + -- center area + SetColorRadarmap() + if monitor == nil then + term.clear() + screenWidth, screenHeight = term.getSize() + else + monitor.clear() + screenWidth, screenHeight = monitor.getSize() + end + -- borders + SetColorRadarborder() + for x = 1, screenWidth do + if monitor == nil then + term.setCursorPos(x, 1) + term.write(" ") + term.setCursorPos(x, screenHeight) + term.write(" ") + else + monitor.setCursorPos(x, 1) + monitor.write(" ") + monitor.setCursorPos(x, screenHeight) + monitor.write(" ") + end + end + for y = 2, screenHeight - 1 do + if monitor == nil then + term.setCursorPos(1, y) + term.write(" ") + term.setCursorPos(screenWidth, y) + term.write(" ") + else + monitor.setCursorPos(1, y) + monitor.write(" ") + monitor.setCursorPos(screenWidth, y) + monitor.write(" ") + end + end + -- title + local text = label .. " - Radar map" + if #data.radar_results == 0 then + text = text .. " (no contacts)" + else + text = text .. " (" .. #data.radar_results .. " contacts)" + end + draw_centeredText(monitor, 1, text) + -- status + local text = "Scan radius: " .. data.radar_radius + if radar ~= nil then + text = text .. " | Energy: " .. radar.getEnergyLevel() .. " EU" + end + text = text .. " | Scale: " .. data.radar_scale + draw_centeredText(monitor, screenHeight, text) + -- results + SetCursorPos(1, 12) + radar_drawContact(monitor, {x = radar_x, y = radar_y, z = radar_z, frequency = "", kind = "self"}) + for i = 0, #data.radar_results - 1 do + radar_drawContact(monitor, data.radar_results[i]) + end + + -- restore defaults + SetColorDefault() +end + +radar_waitingNextScan = false +function radar_timerEvent() + radar_timerId = -1 + if radar_waitingNextScan then + radar_waitingNextScan = false + radar_scan() -- will restart timer + else + local numResults = radar.getResultsCount(); + if numResults ~= -1 then + radar_scanDone() + if data.radar_autoscan then + radar_waitingNextScan = true + radar_timerId = os.startTimer(data.radar_autoscanDelay) + end + else -- still scanning + radar_timerId = os.startTimer(radar_timerLength) + end + end +end + +----------- Boot sequence +label = os.getComputerLabel() +if not label then + label = "" .. os.getComputerID() +end + +-- read configuration +data_read() + +-- initial scanning +monitors = {} +ShowTitle(label .. " - Connecting...") +WriteLn("") + +sides = peripheral.getNames() +reactor = nil +mininglasers = {} +reactorlasers = {} +cloakingcores = {} +warpcore = nil +radar = nil +for key,side in pairs(sides) do + sleep(0) + if peripheral.getType(side) == "monitor" then + WriteLn("Wrapping " .. side) + lmonitor = peripheral.wrap(side) + table.insert(monitors, lmonitor) + lmonitor.setTextScale(monitor_textScale) + elseif peripheral.getType(side) == "warpcore" then + WriteLn("Wrapping " .. side) + warpcore = peripheral.wrap(side) + elseif peripheral.getType(side) == "warpdriveReactor" then + WriteLn("Wrapping " .. side) + reactor = peripheral.wrap(side) + elseif peripheral.getType(side) == "warpdriveReactorLaser" then + WriteLn("Wrapping " .. side) + table.insert(reactorlasers, peripheral.wrap(side)) + elseif peripheral.getType(side) == "mininglaser" then + WriteLn("Wrapping " .. side) + table.insert(mininglasers, peripheral.wrap(side)) + elseif peripheral.getType(side) == "cloakingdevicecore" then + WriteLn("Wrapping " .. side) + table.insert(cloakingcores, peripheral.wrap(side)) + elseif peripheral.getType(side) == "radar" then + WriteLn("Wrapping " .. side) + radar = peripheral.wrap(side); + end +end +-- sleep(1) + +if not os.getComputerLabel() and (warpcore ~= nil or reactor ~= nil) then + data_setName() +end + +-- peripherals status +function connections_page() + ShowTitle(label .. " - Connections") + + WriteLn("") + if #monitors == 0 then + SetColorDisabled() + WriteLn("No Monitor detected") + elseif #monitors == 1 then + SetColorSuccess() + WriteLn("1 monitor detected") + else + SetColorSuccess() + WriteLn(#monitors .. " Monitors detected") + end + + if warpcore == nil then + SetColorDisabled() + WriteLn("No warpcore controller detected") + else + SetColorSuccess() + WriteLn("Warpcore controller detected") + end + + if reactor == nil then + SetColorDisabled() + WriteLn("No reactor detected") + else + SetColorSuccess() + WriteLn("Warpcore reactor detected") + end + + if #reactorlasers == 0 then + SetColorDisabled() + WriteLn("No reactor stabilisation laser detected") + elseif #reactorlasers == 1 then + SetColorSuccess() + WriteLn("1 reactor stabilisation laser detected") + else + SetColorSuccess() + WriteLn(#reactorlasers .. " reactor stabilisation lasers detected") + end + + if #mininglasers == 0 then + SetColorDisabled() + WriteLn("No mining laser detected") + elseif #mininglasers == 1 then + SetColorSuccess() + WriteLn("1 mining laser detected") + else + SetColorSuccess() + WriteLn(#mininglasers .. " mining lasers detected") + end + + if #cloakingcores == 0 then + SetColorDisabled() + WriteLn("No cloaking core detected") + elseif #cloakingcores == 1 then + SetColorSuccess() + WriteLn("1 cloaking core detected") + else + SetColorSuccess() + WriteLn(#cloakingcores .. " cloaking cores detected") + end + + if radar == nil then + SetColorDisabled() + WriteLn("No radar detected") + else + SetColorSuccess() + WriteLn("Warpcore radar detected") + end +end + +-- peripheral boot up +Clear() +connections_page() +SetColorDefault() +WriteLn("") +sleep(0) +radar_boot() +core_boot() +reactor_boot() +sleep(0) + +-- main loop +abort = false +refresh = true +page = connections_page +keyHandler = nil +repeat + ClearWarning() + if refresh then + Clear() + page() + menu_common() + refresh = false + end + params = { os.pullEventRaw() } + eventName = params[1] + side = params[2] + if side == nil then side = "none" end + if eventName == "key" then + keycode = params[2] + if keycode == 45 then -- x for eXit + os.pullEventRaw() + abort = true + elseif keycode == 11 or keycode == 82 then -- 0 + page = connections_page + keyHandler = nil + refresh = true + elseif keycode == 2 or keycode == 79 then -- 1 + page = reactor_page + keyHandler = reactor_key + refresh = true + elseif keycode == 3 or keycode == 80 then -- 2 + page = cloaking_page + keyHandler = cloaking_key + refresh = true + elseif keycode == 4 or keycode == 81 then -- 3 + page = mining_page + keyHandler = mining_key + refresh = true + elseif keycode == 5 or keycode == 75 then -- 4 + page = core_page + keyHandler = core_key + refresh = true + elseif keycode == 6 or keycode == 76 then -- 5 + page = radar_page + keyHandler = radar_key + refresh = true + elseif keyHandler ~= nil and keyHandler(keycode) then + refresh = true + os.sleep(0) + else + ShowWarning("Key " .. keycode .. " is invalid") + os.sleep(0.2) + end + -- func(unpack(params)) + -- abort, refresh = false, false + elseif eventName == "char" then + -- drop it + elseif eventName == "reactorPulse" then + reactor_pulse(params[2]) + refresh = (page == reactor_page) + elseif eventName == "terminate" then + abort = true + elseif not common_event(eventName, params[2]) then + ShowWarning("Event '" .. eventName .. "', " .. side .. " is unsupported") + refresh = true + os.sleep(0.2) + end +until abort + +-- deactivate summon all on exit +if data.core_summon then + data.core_summon = false + data_save() +end + +-- clear screens on exit +SetMonitorColorFrontBack(colors.white, colors.black) +term.clear() +if monitors ~= nil then + for key,monitor in pairs(monitors) do + monitor.clear() + end +end +SetCursorPos(1, 1) +Write("") diff --git a/src/cr0s/WarpDrive/EntityJump.java b/src/cr0s/WarpDrive/EntityJump.java new file mode 100644 index 00000000..e3daa6f0 --- /dev/null +++ b/src/cr0s/WarpDrive/EntityJump.java @@ -0,0 +1,1230 @@ +package cr0s.WarpDrive; + +import cpw.mods.fml.common.FMLCommonHandler; +import cr0s.WarpDrive.data.JumpBlock; +import cr0s.WarpDrive.data.MovingEntity; +import cr0s.WarpDrive.data.TransitionPlane; +import cr0s.WarpDrive.data.Vector3; +import cr0s.WarpDrive.machines.TileEntityReactor; +import cr0s.WarpDrive.world.SpaceTeleporter; +import dan200.computercraft.api.peripheral.IPeripheral; +import ic2.api.network.NetworkHelper; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.MathHelper; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import net.minecraftforge.common.DimensionManager; +import net.minecraftforge.common.ForgeChunkManager; +import net.minecraftforge.common.ForgeChunkManager.Ticket; +import net.minecraftforge.common.ForgeChunkManager.Type; + +public class EntityJump extends Entity +{ + // Jump vector + private int moveX; + private int moveY; + private int moveZ; + + private int xCoord; + private int yCoord; + private int zCoord; + private int dx; + private int dz; + private int distance; + private int direction; + public int shipLength; + public int maxX; + public int maxZ; + public int maxY; + public int minX; + public int minZ; + public int minY; + + private boolean isHyperspaceJump; + + private World targetWorld; + private Ticket sourceWorldTicket; + private Ticket targetWorldTicket; + + private boolean collisionDetected = false; + private ArrayList collisionAtSource; + private ArrayList collisionAtTarget; + private float collisionStrength = 0; + + public boolean on = false; + private JumpBlock ship[]; + private TileEntityReactor reactor; + + private final static int STATE_IDLE = 0; + private final static int STATE_JUMPING = 1; + private final static int STATE_REMOVING = 2; + private int state = STATE_IDLE; + private int currentIndexInShip = 0; + + private List entitiesOnShip; + private List ASTurbines; + + private boolean betweenWorlds; + + private int destX, destY, destZ; + private boolean isCoordJump; + + private long msCounter = 0; + private int ticks = 0; + + public EntityJump(World world) + { + super(world); + targetWorld = worldObj; + WarpDrive.debugPrint("" + this + " Entity created (empty) in dimension " + worldObj.getProviderName() + " - " + worldObj.getWorldInfo().getWorldName() + + " " + (FMLCommonHandler.instance().getEffectiveSide().isClient() ? "Client":"Server")); + } + + public EntityJump(World world, int x, int y, int z, int _dx, int _dz, TileEntityReactor _reactor, + boolean _isHyperspaceJump, int _distance, int _direction, boolean _isCoordJump, int _destX, int _destY, int _destZ) { + super(world); + this.posX = x + 0.5D; + this.posY = y + 0.5D; + this.posZ = z + 0.5D; + this.xCoord = x; + this.yCoord = y; + this.zCoord = z; + this.dx = _dx; + this.dz = _dz; + this.reactor = _reactor; + this.isHyperspaceJump = _isHyperspaceJump; + this.distance = _distance; + this.direction = _direction; + this.isCoordJump = _isCoordJump; + this.destX = _destX; + this.destY = _destY; + this.destZ = _destZ; + + // set by reactor + maxX = maxZ = maxY = minX = minZ = minY = 0; + shipLength = 0; + + // set when preparing jump + targetWorld = null; + + WarpDrive.debugPrint("" + this + " Entity created"); + } + + public void killEntity(String reason) { + if (!on) { + return; + } + + on = false; + + if (reason == null || reason.isEmpty()) { + WarpDrive.debugPrint("" + this + " Killing jump entity..."); + } else { + WarpDrive.debugPrint("" + this + " Killing jump entity... (" + reason + ")"); + } + + unforceChunks(); + worldObj.removeEntity(this); + } + + @Override + public boolean isEntityInvulnerable() { + return true; + } + + @Override + public void onUpdate() { + if (FMLCommonHandler.instance().getEffectiveSide().isClient()) { + return; + } + + if (!on) { + WarpDrive.print(this + " Removing from onUpdate..."); + worldObj.removeEntity(this); + return; + } + + if (minY < 0 || maxY > 256) { + String msg = "Invalid Y coordinate(s), check ship dimensions..."; + messageToAllPlayersOnShip(msg); + killEntity(msg); + return; + } + + ticks++; + if (state == STATE_IDLE) { + WarpDrive.debugPrint(this + " Preparing to jump..."); + prepareToJump(); + if (on) { + state = STATE_JUMPING; + } + } else if (state == STATE_JUMPING) { + if (currentIndexInShip < ship.length - 1) { + //moveEntities(true); + moveShip(); + } else { + moveEntities(false); + currentIndexInShip = 0; + state = STATE_REMOVING; + } + } else if (state == STATE_REMOVING) { + ASTurbines = new ArrayList(); + removeShip(); + + if (currentIndexInShip >= ship.length - 1) { + finishJump(); + state = STATE_IDLE; + } + } else { + String msg = "Invalid state, aborting jump..."; + messageToAllPlayersOnShip(msg); + killEntity(msg); + return; + } + } + + private boolean forceChunks(StringBuilder reason) + { + LocalProfiler.start("EntityJump.forceChunks"); + WarpDrive.debugPrint("" + this + " Forcing chunks in " + worldObj.provider.getDimensionName() + " and " + targetWorld.provider.getDimensionName()); + sourceWorldTicket = ForgeChunkManager.requestTicket(WarpDrive.instance, worldObj, Type.NORMAL); // Type.ENTITY); + if (sourceWorldTicket == null) { + reason.append("Chunkloading rejected in S:" + worldObj.getWorldInfo().getWorldName() + ". Aborting."); + return false; + } + targetWorldTicket = ForgeChunkManager.requestTicket(WarpDrive.instance, targetWorld, Type.NORMAL); + if (targetWorldTicket == null) { + reason.append("Chunkloading rejected in T:" + worldObj.getWorldInfo().getWorldName() + ". Aborting."); + return false; + } +// sourceWorldTicket.bindEntity(this); + int x1 = minX >> 4; + int x2 = maxX >> 4; + int z1 = minZ >> 4; + int z2 = maxZ >> 4; + int chunkCount = 0; + for (int x = x1; x <= x2; x++) + { + for (int z = z1; z <= z2; z++) + { + chunkCount++; + if (chunkCount > sourceWorldTicket.getMaxChunkListDepth()) { + reason.append("Ship is extending over too many chunks, max is S:" + sourceWorldTicket.getMaxChunkListDepth() + ". Aborting."); + return false; + } + ForgeChunkManager.forceChunk(sourceWorldTicket, new ChunkCoordIntPair(x, z)); + } + } + + x1 = (minX + moveX) >> 4; + x2 = (maxX + moveX) >> 4; + z1 = (minZ + moveZ) >> 4; + z2 = (maxZ + moveZ) >> 4; + chunkCount = 0; + for (int x = x1; x <= x2; x++) + { + for (int z = z1; z <= z2; z++) + { + chunkCount++; + if (chunkCount > targetWorldTicket.getMaxChunkListDepth()) { + reason.append("Ship is extending over too many chunks, max is T:" + sourceWorldTicket.getMaxChunkListDepth() + ". Aborting."); + return false; + } + ForgeChunkManager.forceChunk(targetWorldTicket, new ChunkCoordIntPair(x, z)); + } + } + LocalProfiler.stop(); + return true; + } + + private void unforceChunks() + { + LocalProfiler.start("EntityJump.unforceChunks"); + WarpDrive.debugPrint("" + this + " Unforcing chunks"); + + int x1, x2, z1, z2; + if (sourceWorldTicket != null) { + x1 = minX >> 4; + x2 = maxX >> 4; + z1 = minZ >> 4; + z2 = maxZ >> 4; + for (int x = x1; x <= x2; x++) { + for (int z = z1; z <= z2; z++) { + ForgeChunkManager.unforceChunk(sourceWorldTicket, new ChunkCoordIntPair(x, z)); + } + } + ForgeChunkManager.releaseTicket(sourceWorldTicket); + sourceWorldTicket = null; + } + + if (targetWorldTicket != null) { + x1 = (minX + moveX) >> 4; + x2 = (maxX + moveX) >> 4; + z1 = (minZ + moveZ) >> 4; + z2 = (maxZ + moveZ) >> 4; + for (int x = x1; x <= x2; x++) { + for (int z = z1; z <= z2; z++) { + ForgeChunkManager.unforceChunk(targetWorldTicket, new ChunkCoordIntPair(x, z)); + } + } + ForgeChunkManager.releaseTicket(targetWorldTicket); + targetWorldTicket = null; + } + + LocalProfiler.stop(); + } + + private void messageToAllPlayersOnShip(String msg) { + if (entitiesOnShip == null) { + reactor.messageToAllPlayersOnShip(msg); + } else { + WarpDrive.print("" + this + " messageToAllPlayersOnShip: " + msg); + for (MovingEntity me : entitiesOnShip) { + if (me.entity instanceof EntityPlayer) { + ((EntityPlayer)me.entity).addChatMessage("[" + ((reactor != null && reactor.coreFrequency.length() > 0) ? reactor.coreFrequency : "WarpCore") + "] " + msg); + } + } + } + } + + public static String getDirectionLabel(int direction) { + switch (direction) { + case -1: return "UP"; + case -2: return "DOWN"; + case 0: return "FRONT"; + case 180: return "BACK"; + case 90: return "LEFT"; + case 255: return "RIGHT"; + default: return direction + " degrees"; + } + } + + private void prepareToJump() { + StringBuilder reason = new StringBuilder(); + + LocalProfiler.start("EntityJump.prepareToJump"); + boolean isInSpace = (worldObj.provider.dimensionId == WarpDriveConfig.G_SPACE_DIMENSION_ID); + boolean isInHyperSpace = (worldObj.provider.dimensionId == WarpDriveConfig.G_HYPERSPACE_DIMENSION_ID); + + boolean toSpace = (direction == -1) && (maxY + distance > 255) && (!isInSpace) && (!isInHyperSpace); + boolean fromSpace = (direction == -2) && (minY - distance < 0) && isInSpace; + betweenWorlds = fromSpace || toSpace || isHyperspaceJump; + moveX = moveY = moveZ = 0; + + if (toSpace) { + Boolean planeFound = false; + Boolean planeValid = false; + int closestPlaneDistance = Integer.MAX_VALUE; + TransitionPlane closestTransitionPlane = null; + for (int iPlane = 0; (!planeValid) && iPlane < WarpDriveConfig.G_TRANSITIONPLANES.length; iPlane++) { + TransitionPlane transitionPlane = WarpDriveConfig.G_TRANSITIONPLANES[iPlane]; + if (worldObj.provider.dimensionId == transitionPlane.dimensionId) { + planeFound = true; + int planeDistance = transitionPlane.isValidToSpace(new Vector3(this)); + if (planeDistance == 0) { + planeValid = true; + moveX = transitionPlane.spaceCenterX - transitionPlane.dimensionCenterX; + moveZ = transitionPlane.spaceCenterZ - transitionPlane.dimensionCenterZ; + targetWorld = DimensionManager.getWorld(WarpDriveConfig.G_SPACE_DIMENSION_ID); + } else if (closestPlaneDistance > planeDistance) { + closestPlaneDistance = planeDistance; + closestTransitionPlane = transitionPlane; + } + } + } + if (!planeFound) { + LocalProfiler.stop(); + String msg = "Unable to reach space!\nThere's no valid transition plane for current dimension " + worldObj.provider.getDimensionName() + " (" + worldObj.provider.dimensionId + ")"; + messageToAllPlayersOnShip(msg); + killEntity(msg); + return; + } + if (!planeValid) { + LocalProfiler.stop(); + @SuppressWarnings("null") + String msg = "Ship is outside border, unable to reach space!\nClosest transition plane is ~" + closestPlaneDistance + " m away (" + + (closestTransitionPlane.dimensionCenterX - closestTransitionPlane.borderSizeX) + ", 250," + + (closestTransitionPlane.dimensionCenterZ - closestTransitionPlane.borderSizeZ) + ") to (" + + (closestTransitionPlane.dimensionCenterX + closestTransitionPlane.borderSizeX) + ", 255," + + (closestTransitionPlane.dimensionCenterZ + closestTransitionPlane.borderSizeZ) + ")"; + messageToAllPlayersOnShip(msg); + killEntity(msg); + return; + } + } else if (fromSpace) { + Boolean planeFound = false; + int closestPlaneDistance = Integer.MAX_VALUE; + TransitionPlane closestTransitionPlane = null; + for (int iPlane = 0; (!planeFound) && iPlane < WarpDriveConfig.G_TRANSITIONPLANES.length; iPlane++) { + TransitionPlane transitionPlane = WarpDriveConfig.G_TRANSITIONPLANES[iPlane]; + int planeDistance = transitionPlane.isValidFromSpace(new Vector3(this)); + if (planeDistance == 0) { + planeFound = true; + moveX = transitionPlane.dimensionCenterX - transitionPlane.spaceCenterX; + moveZ = transitionPlane.dimensionCenterZ - transitionPlane.spaceCenterZ; + targetWorld = DimensionManager.getWorld(transitionPlane.dimensionId); + } else if (closestPlaneDistance > planeDistance) { + closestPlaneDistance = planeDistance; + closestTransitionPlane = transitionPlane; + } + } + if (!planeFound) { + LocalProfiler.stop(); + String msg = ""; + if (closestTransitionPlane == null) { + msg = "No transition plane defined, unable to enter atmosphere!"; + } else { + msg = "No planet in range, unable to enter atmosphere!\nClosest transition plane is " + closestPlaneDistance + " m away (" + + (closestTransitionPlane.dimensionCenterX - closestTransitionPlane.borderSizeX) + ", 250," + + (closestTransitionPlane.dimensionCenterZ - closestTransitionPlane.borderSizeZ) + ") to (" + + (closestTransitionPlane.dimensionCenterX + closestTransitionPlane.borderSizeX) + ", 255," + + (closestTransitionPlane.dimensionCenterZ + closestTransitionPlane.borderSizeZ) + ")"; + } + messageToAllPlayersOnShip(msg); + killEntity(msg); + return; + } + } else if (isHyperspaceJump && isInHyperSpace) { + targetWorld = DimensionManager.getWorld(WarpDriveConfig.G_SPACE_DIMENSION_ID); + } else if (isHyperspaceJump && isInSpace) { + targetWorld = DimensionManager.getWorld(WarpDriveConfig.G_HYPERSPACE_DIMENSION_ID); + } else { + targetWorld = worldObj; + } + + // FIXME + //turnOffModems(); + + // Calculate jump vector + if (isCoordJump) { + moveX = destX - xCoord; + moveZ = destZ - zCoord; + moveY = destY - yCoord; + distance = 0; // FIXME: check collision in straight path, starting with getPossibleJumpDistance() ? + } else if (isHyperspaceJump) { + distance = 0; + } else { + if (toSpace) { + // enter space at current altitude + moveY = 0; + } else if (fromSpace) { + // re-enter atmosphere at max altitude + moveY = 245 - maxY; + } else { + // Do not check in long jumps + if (distance < 256) { + distance = getPossibleJumpDistance(); + } + + int movementVector[] = getVector(direction); + moveX = movementVector[0] * distance; + moveY = movementVector[1] * distance; + moveZ = movementVector[2] * distance; + + if ((maxY + moveY) > 255) { + moveY = 255 - maxY; + } + + if ((minY + moveY) < 5) { + moveY = 5 - minY; + } + } + } + + if (betweenWorlds) { + WarpDrive.debugPrint("" + this + " Worlds: " + worldObj.provider.getDimensionName() + " -> " + targetWorld.provider.getDimensionName()); + } + + // Validate positions aren't overlapping + if (!betweenWorlds) { + if ( Math.abs(moveX) <= (maxX - minX + 1) && Math.abs(moveY) <= (maxY - minY + 1) && Math.abs(moveZ) <= (maxZ - minZ + 1) ) { + // render fake explosions + doCollisionDamage(false); + + // cancel jump + LocalProfiler.stop(); + String msg = "Not enough space for jump!"; + messageToAllPlayersOnShip(msg); + killEntity(msg); + return; + } + } + + if (!forceChunks(reason)) { + String msg = reason.toString(); + killEntity(msg); + messageToAllPlayersOnShip(msg); + LocalProfiler.stop(); + return; + } +// lockWorlds(); + saveEntities(); + WarpDrive.debugPrint("" + this + " Saved " + entitiesOnShip.size() + " entities from ship"); + + if (isHyperspaceJump && isInSpace) { + messageToAllPlayersOnShip("Entering HYPERSPACE..."); + } else if (isHyperspaceJump && isInHyperSpace) { + messageToAllPlayersOnShip("Leaving HYPERSPACE.."); + } else if (isCoordJump) { + messageToAllPlayersOnShip("Jumping to coordinates (" + destX + "; " + yCoord + "; " + destZ + ")!"); + } else { + messageToAllPlayersOnShip("Jumping " + getDirectionLabel(direction) + " by " + distance + " blocks"); + } + + // validate ship content + int shipVolume = getRealShipVolume_checkBedrock(reason); + if (shipVolume == -1) { + String msg = reason.toString(); + killEntity(msg); + messageToAllPlayersOnShip(msg); + LocalProfiler.stop(); + return; + } + + saveShip(shipVolume); + this.currentIndexInShip = 0; + msCounter = System.currentTimeMillis(); + LocalProfiler.stop(); + WarpDrive.debugPrint("Removing TE duplicates: tileEntities in target world before jump: " + targetWorld.loadedTileEntityList.size()); + } + + /** + * Finish jump: move entities, unlock worlds and delete self + */ + private void finishJump() { + WarpDrive.debugPrint("" + this + " Jump done in " + ((System.currentTimeMillis() - msCounter) / 1000F) + " seconds and " + ticks + " ticks"); + //FIXME TileEntity duplication workaround + WarpDrive.debugPrint("Removing TE duplicates: tileEntities in target world after jump, before cleanup: " + targetWorld.loadedTileEntityList.size()); + LocalProfiler.start("EntityJump.removeDuplicates()"); + + try { + targetWorld.loadedTileEntityList = this.removeDuplicates(targetWorld.loadedTileEntityList); + } catch (Exception e) { + WarpDrive.debugPrint("TE Duplicates removing exception: " + e.getMessage()); + } + FixASTurbines(); + doCollisionDamage(true); + + LocalProfiler.stop(); + WarpDrive.debugPrint("Removing TE duplicates: tileEntities in target world after jump, after cleanup: " + targetWorld.loadedTileEntityList.size()); + killEntity("Jump done"); + } + + /** + * Removing ship from world + * + */ + private void removeShip() { + LocalProfiler.start("EntityJump.removeShip"); + int blocksToMove = Math.min(WarpDriveConfig.G_BLOCKS_PER_TICK, ship.length - currentIndexInShip); + WarpDrive.debugPrint("" + this + " Removing ship blocks " + currentIndexInShip + " to " + (currentIndexInShip + blocksToMove - 1) + " / " + (ship.length - 1)); + TileEntity te; + Class teClass; + Class teSuperclass; + for (int index = 0; index < blocksToMove; index++) { + if (currentIndexInShip >= ship.length) { + break; + } + JumpBlock jb = ship[ship.length - currentIndexInShip - 1]; + if (jb == null) { + WarpDrive.debugPrint("" + this + " Removing ship part: unexpected null found at ship[" + currentIndexInShip + "]"); + currentIndexInShip++; + continue; + } + + if (jb.blockTileEntity != null) { + // WarpDrive.debugPrint("Removing tile entity at " + jb.x + ", " + jb.y + ", " + jb.z); + worldObj.removeBlockTileEntity(jb.x, jb.y, jb.z); + } + worldObj.setBlock(jb.x, jb.y, jb.z, 0, 0, 2); + + te = targetWorld.getBlockTileEntity(jb.x + moveX, jb.y + moveY, jb.z + moveZ); + if (te != null) { + teClass = te.getClass(); + // WarpDrive.debugPrint("Tile at " + jb.x + ", " + jb.y + ", " + jb.z + " is " + teClass + " derived from " + teClass.getSuperclass()); + if (teClass.getName().equals("atomicscience.jiqi.TTurbine")) { + try { + if (teClass.getField("shiDa").getBoolean(te)) + ASTurbines.add(te); + } catch (Exception e) { + WarpDrive.print("Exception involving TileEntity '" + teClass.getName() + "' at " + jb.x + ", " + jb.y + ", " + jb.z); + e.printStackTrace(); + } + } else if (te instanceof TileEntityReactor) { + WarpDrive.warpCores.removeFromRegistry((TileEntityReactor)te); + } + + teSuperclass = teClass.getSuperclass(); + if ( teSuperclass.getName().equals("ic2.core.block.wiring.TileEntityElectricBlock") + || teSuperclass.getName().equals("ic2.core.block.TileEntityBlock") + || teSuperclass.getName().contains("ic2.core.block.generator")) { + try { + Method onUnloaded = teSuperclass.getDeclaredMethod("onUnloaded"); + Method onLoaded = teSuperclass.getDeclaredMethod("onLoaded"); + if (onUnloaded != null && onLoaded != null) { + onUnloaded.invoke(te); + onLoaded.invoke(te); + } + } catch (Exception e) { + WarpDrive.print("Exception involving TileEntity '" + teClass.getName() + "' at " + jb.x + ", " + jb.y + ", " + jb.z); + e.printStackTrace(); + } + te.updateContainingBlockInfo(); + try { + NetworkHelper.updateTileEntityField(te, "facing"); + } catch (Exception e) { + WarpDrive.print("Exception involving TileEntity '" + teClass.getName() + "' at " + jb.x + ", " + jb.y + ", " + jb.z); + e.printStackTrace(); + } + } + } + + currentIndexInShip++; + } + LocalProfiler.stop(); + } + + /** + * Saving ship to memory + * + * @param shipSize + */ + private void saveShip(int shipSize) { + LocalProfiler.start("EntityJump.saveShip"); + try { + int reactorChamber = WarpDriveConfig.isICLoaded ? WarpDriveConfig.getIC2Item("reactorChamber").itemID : 0; + + ship = new JumpBlock[shipSize]; + JumpBlock placeAfter[] = new JumpBlock[shipSize]; // blocks and tile entities to be placed at the end, and removed first + + int indexPlaceNormal = 0; + int indexPlaceAfter = 0; + int xc1 = minX >> 4; + int xc2 = maxX >> 4; + int zc1 = minZ >> 4; + int zc2 = maxZ >> 4; + + for (int xc = xc1; xc <= xc2; xc++) { + int x1 = Math.max(minX, xc << 4); + int x2 = Math.min(maxX, (xc << 4) + 15); + + for (int zc = zc1; zc <= zc2; zc++) { + int z1 = Math.max(minZ, zc << 4); + int z2 = Math.min(maxZ, (zc << 4) + 15); + + for (int y = minY; y <= maxY; y++) { + for (int x = x1; x <= x2; x++) { + for (int z = z1; z <= z2; z++) { + int blockID = worldObj.getBlockId(x, y, z); + + // Skip air blocks + if (worldObj.isAirBlock(x, y, z) && (blockID != WarpDriveConfig.airID)) { + continue; + } + + int blockMeta = worldObj.getBlockMetadata(x, y, z); + TileEntity tileEntity = worldObj.getBlockTileEntity(x, y, z); + JumpBlock jumpBlock = new JumpBlock(blockID, blockMeta, tileEntity, x, y, z); + + if (tileEntity == null || blockID != reactorChamber) { + ship[indexPlaceNormal] = jumpBlock; + indexPlaceNormal++; + } else { + placeAfter[indexPlaceAfter] = jumpBlock; + indexPlaceAfter++; + } + } + } + } + } + } + + for (int index = 0; index < indexPlaceAfter; index++) { + ship[indexPlaceNormal] = placeAfter[index]; + indexPlaceNormal++; + } + } catch (Exception e) { + e.printStackTrace(); + killEntity("Exception during jump preparation (saveShip)!"); + LocalProfiler.stop(); + return; + } + + WarpDrive.debugPrint("" + this + " Ship saved as " + ship.length + " blocks"); + LocalProfiler.stop(); + } + + /** + *Ship moving + */ + private void moveShip() { + LocalProfiler.start("EntityJump.moveShip"); + int blocksToMove = Math.min(WarpDriveConfig.G_BLOCKS_PER_TICK, ship.length - currentIndexInShip); + WarpDrive.debugPrint("" + this + " Moving ship blocks " + currentIndexInShip + " to " + (currentIndexInShip + blocksToMove - 1) + " / " + (ship.length - 1)); + + for (int index = 0; index < blocksToMove; index++) { + if (currentIndexInShip >= ship.length) { + break; + } + + JumpBlock jb = ship[currentIndexInShip]; + if (jb != null) { + jb.deploy(targetWorld, moveX, moveY, moveZ); + if (jb.blockID != WarpDriveConfig.CC_peripheral || (jb.blockMeta != 2 && jb.blockMeta != 4)) { + worldObj.removeBlockTileEntity(jb.x, jb.y, jb.z); + } + } + currentIndexInShip++; + } + + LocalProfiler.stop(); + } + + /** + * Checking jump possibility + * + * @return possible jump distance or -1 + */ + private int getPossibleJumpDistance() { + WarpDrive.debugPrint("" + this + " Calculating possible jump distance..."); + int testDistance = this.distance; + int blowPoints = 0; + collisionDetected = false; + + CheckMovementResult result = null; + while (testDistance >= 0) { + // Is there enough space in destination point? + result = checkMovement(testDistance, false); + + if (result == null) { + break; + } + + if (result.isCollision) { + blowPoints++; + } + testDistance--; + } + + if (distance != testDistance) { + WarpDrive.debugPrint("" + this + " Jump distance adjusted to " + testDistance + " after " + blowPoints + " collisions"); + } + + // Register explosion(s) at collision point + if (blowPoints > WarpDriveConfig.WC_COLLISION_TOLERANCE_BLOCKS) { + result = checkMovement(Math.max(1, testDistance + 1), true); + if (result != null) { + /* + * Strength scaling: + * Creeper = 3 or 6 + * Wither skull = 1 + * Wither boom = 5 + * Endercrystal = 6 + * TNTcart = 4 to 11.5 + * TNT = 4 + */ + float massCorrection = 0.5F + (float)Math.sqrt( + Math.min(1.0D, Math.max(0.0D, reactor.shipVolume - WarpDriveConfig.WC_MAX_SHIP_VOLUME_ON_SURFACE) / WarpDriveConfig.WC_MIN_SHIP_VOLUME_FOR_HYPERSPACE)); + collisionDetected = true; + collisionStrength = (4.0F + blowPoints - WarpDriveConfig.WC_COLLISION_TOLERANCE_BLOCKS) * massCorrection; + collisionAtSource = result.atSource; + collisionAtTarget = result.atTarget; + WarpDrive.debugPrint("" + this + " Reporting " + collisionAtTarget.size() + " collisions coordinates " + + blowPoints + " blowPoints with massCorrection of " + String.format("%.2f", massCorrection) + " => strength " + String.format("%.2f", collisionStrength) ); + } else { + WarpDrive.print("WarpDrive error: unable to compute collision points, ignoring..."); + } + } + + return testDistance; + } + + private void doCollisionDamage(boolean atTarget) { + if (!collisionDetected) { + WarpDrive.debugPrint("" + this + " doCollisionDamage No collision detected..."); + return; + } + ArrayList collisionPoints = atTarget ? collisionAtTarget : collisionAtSource; + Vector3 min = collisionPoints.get(0); + Vector3 max = collisionPoints.get(0); + for (Vector3 v : collisionPoints) { + if (min.x > v.x) { + min.x = v.x; + } else if (max.x < v.x) { + max.x = v.x; + } + if (min.y > v.y) { + min.y = v.y; + } else if (max.y < v.y) { + max.y = v.y; + } + if (min.z > v.z) { + min.z = v.z; + } else if (max.z < v.z) { + max.z = v.z; + } + } + + // inform players on board + double rx = Math.round(min.x + worldObj.rand.nextInt( Math.max(1, (int) (max.x - min.x)) )); + double ry = Math.round(min.y + worldObj.rand.nextInt( Math.max(1, (int) (max.y - min.y)) )); + double rz = Math.round(min.z + worldObj.rand.nextInt( Math.max(1, (int) (max.z - min.z)) )); +// WarpDrive.debugPrint("doCollisionDamage msg " + rx + ", " + ry + ", " + rz + " atTarget " + atTarget + " min " + min + " max " + max); + messageToAllPlayersOnShip("Ship collision detected around " + (int)rx + ", " + (int)ry + ", " + (int)rz + ". Damage report pending..."); + + // randomize if too many collision points + int nbExplosions = Math.min(5, collisionPoints.size()); + WarpDrive.debugPrint("doCollisionDamage nbExplosions " + nbExplosions + "/" + collisionPoints.size()); + for (int i = 0; i < nbExplosions; i++) { + // get location + Vector3 current; + if (nbExplosions < collisionPoints.size()) { + WarpDrive.debugPrint("doCollisionDamage random #" + i); + current = collisionPoints.get(worldObj.rand.nextInt(collisionPoints.size())); + } else { + WarpDrive.debugPrint("doCollisionDamage get " + i); + current = collisionPoints.get(i); + } + + // compute explosion strength with a jitter, at least 1 TNT + float strength = Math.max(4.0F, collisionStrength / nbExplosions - 2.0F + 2.0F * worldObj.rand.nextFloat()); + + (atTarget ? targetWorld : worldObj).newExplosion((Entity) null, current.x, current.y, current.z, strength, atTarget, atTarget); + WarpDrive.debugPrint("doCollisionDamage explosion at " + current.x + ", " + current.y + ", " + current.z + " with strength " + strength); + } + } + + private int getRealShipVolume_checkBedrock(StringBuilder reason) { + LocalProfiler.start("EntityJump.getRealShipVolume_checkBedrock"); + int shipVolume = 0; + + for (int x = minX; x <= maxX; x++) { + for (int z = minZ; z <= maxZ; z++) { + for (int y = minY; y <= maxY; y++) { + int blockID = worldObj.getBlockId(x, y, z); + + // Skipping vanilla air & WarpDrive gas blocks, keep WarpDrive air block + if (worldObj.isAirBlock(x, y, z) && (blockID != WarpDriveConfig.airID)) {// whitelist + continue; + } + + shipVolume++; + + /* + Item item = Item.itemsList[blockID]; + if (item == null) + WarpDrive.debugPrint("Block(" + x + ", " + y + ", " + z + ") is undefined#" + blockID + ":" + worldObj.getBlockMetadata(x, y, z)); + else + WarpDrive.debugPrint("Block(" + x + ", " + y + ", " + z + ") is " + item.getUnlocalizedName() + ":" + worldObj.getBlockMetadata(x, y, z)); + /**/ + + if ((blockID == Block.bedrock.blockID) || (blockID == 2702)) {// Blacklist + reason.append("Bedrock detected onboard at " + x + ", " + y + ", " + z + ". Aborting."); + LocalProfiler.stop(); + return -1; + } + } + } + } + + // Lem: abort jump if blocks with TE are connecting to the ship (avoid crash when splitting multi-blocks) + for (int x = minX - 1; x <= maxX + 1; x++) { + boolean xBorder = (x == minX - 1) || (x == maxX + 1); + for (int z = minZ - 1; z <= maxZ + 1; z++) { + boolean zBorder = (z == minZ - 1) || (z == maxZ + 1); + for (int y = minY - 1; y <= maxY + 1; y++) { + boolean yBorder = (y == minY - 1) || (y == maxY + 1); + if ((y < 0) || (y > 255)) + continue; + if (!(xBorder || yBorder || zBorder)) + continue; + + int blockID = worldObj.getBlockId(x, y, z); + + // Skipping air blocks + if (worldObj.isAirBlock(x, y, z)) { + continue; + } + + // Skipping unmovable blocks + if ((blockID == Block.bedrock.blockID) || (blockID == 2702)) {// Blacklist + continue; + } + + TileEntity te = worldObj.getBlockTileEntity(x, y, z); + if (te == null) { + continue; + } + + reason.append("Ship snagged at " + x + ", " + y + ", " + z + ". Damage report pending..."); + worldObj.createExplosion((Entity) null, x, y, z, Math.min(4F * 30, 4F * (shipVolume / 50)), false); + LocalProfiler.stop(); + return -1; + } + } + } + + LocalProfiler.stop(); + return shipVolume; + } + + + private void saveEntities() { + entitiesOnShip = new ArrayList(); + + AxisAlignedBB axisalignedbb = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX + 0.99D, maxY + 0.99D, maxZ + 0.99D); + + List list = worldObj.getEntitiesWithinAABBExcludingEntity(null, axisalignedbb); + + for (Object o : list) { + if (o == null || !(o instanceof Entity) || (o instanceof EntityJump)) { + continue; + } + + Entity entity = (Entity)o; + MovingEntity movingEntity = new MovingEntity(entity); + entitiesOnShip.add(movingEntity); + } + } + + + private boolean moveEntities(boolean restorePositions) { + WarpDrive.debugPrint("" + this + " Moving entities"); + LocalProfiler.start("EntityJump.moveEntities"); + + if (entitiesOnShip != null) { + for (MovingEntity me : entitiesOnShip) { + Entity entity = me.entity; + + if (entity == null) { + continue; + } + + double oldEntityX = me.oldX; + double oldEntityY = me.oldY; + double oldEntityZ = me.oldZ; + double newEntityX; + double newEntityY; + double newEntityZ; + + if (restorePositions) { + newEntityX = oldEntityX; + newEntityY = oldEntityY; + newEntityZ = oldEntityZ; + } else { + newEntityX = oldEntityX + moveX; + newEntityY = oldEntityY + moveY; + newEntityZ = oldEntityZ + moveZ; + } + + //WarpDrive.debugPrint("Entity moving: old (" + oldEntityX + " " + oldEntityY + " " + oldEntityZ + ") -> new (" + newEntityX + " " + newEntityY + " " + newEntityZ); + + // Travel to another dimension if needed + if (betweenWorlds && !restorePositions) { + MinecraftServer server = MinecraftServer.getServer(); + WorldServer from = server.worldServerForDimension(worldObj.provider.dimensionId); + WorldServer to = server.worldServerForDimension(targetWorld.provider.dimensionId); + SpaceTeleporter teleporter = new SpaceTeleporter(to, 0, MathHelper.floor_double(newEntityX), MathHelper.floor_double(newEntityY), MathHelper.floor_double(newEntityZ)); + + if (entity instanceof EntityPlayerMP) { + EntityPlayerMP player = (EntityPlayerMP) entity; + server.getConfigurationManager().transferPlayerToDimension(player, targetWorld.provider.dimensionId, teleporter); + } else { + server.getConfigurationManager().transferEntityToWorld(entity, worldObj.provider.dimensionId, from, to, teleporter); + } + } + + // Update position + if (entity instanceof EntityPlayerMP) { + EntityPlayerMP player = (EntityPlayerMP) entity; + + ChunkCoordinates bedLocation = player.getBedLocation(player.worldObj.provider.dimensionId); + + if (bedLocation != null + && minX <= bedLocation.posX && maxX >= bedLocation.posX + && minY <= bedLocation.posY && maxY >= bedLocation.posY + && minZ <= bedLocation.posZ && maxZ >= bedLocation.posZ) { + bedLocation.posX = bedLocation.posX + moveX; + bedLocation.posY = bedLocation.posY + moveY; + bedLocation.posZ = bedLocation.posZ + moveZ; + player.setSpawnChunk(bedLocation, false); + } + + player.setPositionAndUpdate(newEntityX, newEntityY, newEntityZ); + } else { + entity.setPosition(newEntityX, newEntityY, newEntityZ); + } + } + } + + LocalProfiler.stop(); + return true; + } + + + + public int[] getVector(int i) + { + int v[] = + { + 0, 0, 0 + }; + + switch (i) + { + case -1: + v[1] = 1; + break; + + case -2: + v[1] = -1; + break; + + case 0: + v[0] = dx; + v[2] = dz; + break; + + case 180: + v[0] = -dx; + v[2] = -dz; + break; + + case 90: + v[0] = dz; + v[2] = -dx; + break; + + case 270: + v[0] = -dz; + v[2] = dx; + } + + return v; + } + + class CheckMovementResult { + public ArrayList atSource; + public ArrayList atTarget; + public boolean isCollision = false; + public String reason = ""; + + CheckMovementResult() { + this.atSource = new ArrayList(1); + this.atTarget = new ArrayList(1); + this.isCollision = false; + this.reason = "Unknown reason"; + } + + public void add(double sx, double sy, double sz, double tx, double ty, double tz, boolean pisCollision, String preason) { + atSource.add(new Vector3(sx, sy, sz)); + atTarget.add(new Vector3(tx, ty, tz)); + isCollision = isCollision || pisCollision; + reason = preason; + WarpDrive.debugPrint("CheckMovementResult " + sx + ", " + sy + ", " + sz + " -> " + tx + ", " + ty + ", " + tz + " " + isCollision + " '" + reason + "'"); + } + }; + private CheckMovementResult checkMovement(int testDistance, boolean fullCollisionDetails) { + CheckMovementResult result = new CheckMovementResult(); + if ((direction == -1 && maxY + testDistance > 255) && !betweenWorlds) { + result.add(xCoord, maxY + testDistance, zCoord, xCoord + 0.5D, maxY + testDistance + 1.0D, zCoord + 0.5D, + false, "Reactor will blow due +high limit"); + return result; + } + + if ((direction == -2 && minY - testDistance <= 8) && !betweenWorlds) { + result.add(xCoord, minY - testDistance, zCoord, xCoord + 0.5D, maxY - testDistance, zCoord + 0.5D, + false, "Reactor will blow due -low limit"); + return result; + } + + int movementVector[] = getVector(direction); + int lmoveX = movementVector[0] * testDistance; + int lmoveY = movementVector[1] * testDistance; + int lmoveZ = movementVector[2] * testDistance; + + int x, y, z, newX, newY, newZ, blockOnShipID, blockID; + for (y = minY; y <= maxY; y++) { + newY = y + lmoveY; + for (x = minX; x <= maxX; x++) { + newX = x + lmoveX; + for (z = minZ; z <= maxZ; z++) { + newZ = z + lmoveZ; + + blockID = worldObj.getBlockId(newX, newY, newZ); + if ((blockID == Block.bedrock.blockID) || (blockID == 2702)) {// Blacklist + result.add(x, y, z, + newX + 0.5D - movementVector[0] * 1.0D, + newY + 0.5D - movementVector[1] * 1.0D, + newZ + 0.5D - movementVector[2] * 1.0D, + true, "Unpassable block " + blockID + " detected at destination (" + newX + ";" + newY + ";" + newZ + ")"); + if (!fullCollisionDetails) { + return result; + } + } + + blockOnShipID = worldObj.getBlockId(x, y, z); + if (blockOnShipID != 0 && blockID != 0 && blockID != WarpDriveConfig.airID && blockID != WarpDriveConfig.gasID && blockID != 18) { + result.add(x, y, z, + newX + 0.5D + movementVector[0] * 0.1D, + newY + 0.5D + movementVector[1] * 0.1D, + newZ + 0.5D + movementVector[2] * 0.1D, + true, "Obstacle block #" + blockID + " detected at (" + newX + ", " + newY + ", " + newZ + ")"); + if (!fullCollisionDetails) { + return result; + } + } + } + } + } + + if (fullCollisionDetails && result.isCollision) { + return result; + } else { + return null; + } + } +/* + private void turnOffModem(IPeripheral p) + { + // FIXME + if (p.getType() == "modem") { + String[] methods = p.getMethodNames(); + for(int i = 0; i < methods.length; i++) { + if (methods[i] == "closeAll") { + try { + p.callMethod(null, i, null); // FIXME + } catch (Exception e) { + // ignore iy + } + return; + } + } + } + } + + private void turnOffModems() + { + // FIXME + for (int x = minX; x <= maxX; x++) { + for (int z = minZ; z <= maxZ; z++) { + for (int y = minY; y <= maxY; y++) { + int blockID = worldObj.getBlockId(x, y, z); + if (blockID == 0 || blockID == WarpDriveConfig.airID || blockID == WarpDriveConfig.gasID) { + continue; + } + + TileEntity tileEntity = worldObj.getBlockTileEntity(x, y, z); + if (tileEntity == null) continue; + + if (tileEntity instanceof IPeripheral) { + IPeripheral p = (IPeripheral)tileEntity; + turnOffModem(p); + } + if (tileEntity instanceof ITurtleAccess) { + ITurtleAccess a = (ITurtleAccess)tileEntity; + IPeripheral pl = a.getPeripheral(TurtleSide.Left); + if (pl != null) turnOffModem(pl); + IPeripheral pr = a.getPeripheral(TurtleSide.Right); + if (pr != null) turnOffModem(pr); + } + } + } + } + }/**/ + + private static ArrayList removeDuplicates(List l) + { + Set s = new TreeSet(new Comparator() + { + @Override + public int compare(TileEntity o1, TileEntity o2) + { + if (o1.xCoord == o2.xCoord && o1.yCoord == o2.yCoord && o1.zCoord == o2.zCoord) + { + WarpDrive.debugPrint("Removed duplicated TE: " + o1 + ", " + o2); + return 0; + } + else + { + return 1; + } + } + }); + s.addAll(l); + return new ArrayList(Arrays.asList(s.toArray())); + } + + @Override + protected void readEntityFromNBT(NBTTagCompound nbttagcompound) + { + //WarpDrive.debugPrint("" + this + " readEntityFromNBT()"); + } + + @Override + protected void entityInit() { + //WarpDrive.debugPrint("" + this + " entityInit()"); + } + + @Override + protected void writeEntityToNBT(NBTTagCompound var1) { + //WarpDrive.debugPrint("" + this + " writeEntityToNBT()"); + } + + private void FixASTurbines() + { + Class c; + for (TileEntity t : ASTurbines) + try + { + c = t.getClass(); + Method method = c.getDeclaredMethod("bianDa", (Class[])null); + method.invoke(t, (Object[])null); + method.invoke(t, (Object[])null); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + public void setMinMaxes(int minXV,int maxXV,int minYV,int maxYV,int minZV,int maxZV) + { + minX = minXV; + maxX = maxXV; + minY = minYV; + maxY = maxYV; + minZ = minZV; + maxZ = maxZV; + } + + @Override + public String toString() { + return String.format("%s/%d \'%s\' @ \'%s\' %.2f, %.2f, %.2f", new Object[] { + getClass().getSimpleName(), + Integer.valueOf(entityId), + reactor == null ? "~NULL~" : reactor.coreFrequency, + worldObj == null ? "~NULL~" : worldObj.getWorldInfo().getWorldName(), + Double.valueOf(posX), Double.valueOf(posY), Double.valueOf(posZ)}); + } +} \ No newline at end of file diff --git a/src/cr0s/WarpDrive/WarpDrive.java b/src/cr0s/WarpDrive/WarpDrive.java new file mode 100644 index 00000000..c99e35b7 --- /dev/null +++ b/src/cr0s/WarpDrive/WarpDrive.java @@ -0,0 +1,818 @@ +package cr0s.WarpDrive; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.Mod.EventHandler; +import cpw.mods.fml.common.Mod.Instance; +import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.event.FMLServerStartingEvent; +import cpw.mods.fml.common.network.NetworkMod; +import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import cr0s.WarpDrive.block.*; +import cr0s.WarpDrive.command.*; +import cr0s.WarpDrive.data.*; +import cr0s.WarpDrive.item.*; +import cr0s.WarpDrive.machines.*; +import cr0s.WarpDrive.render.*; +import cr0s.WarpDrive.world.*; +import dan200.computercraft.api.ComputerCraftAPI; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.Minecraft; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.EnumArmorMaterial; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.packet.Packet250CustomPayload; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraftforge.common.Configuration; +import net.minecraftforge.common.DimensionManager; +import net.minecraftforge.common.EnumHelper; +import net.minecraftforge.common.ForgeChunkManager; +import net.minecraftforge.common.ForgeChunkManager.LoadingCallback; +import net.minecraftforge.common.ForgeChunkManager.Ticket; +import net.minecraftforge.common.ForgeChunkManager.Type; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.oredict.ShapedOreRecipe; +import net.minecraftforge.oredict.ShapelessOreRecipe; + +@Mod(modid = "WarpDrive", name = "WarpDrive", version = "1.2.7.0", + dependencies = "required-after:IC2;" + + " required-after:CoFHCore;" + + " after:ComputerCraft;" + + " after:OpenComputer;" + + " after:CCTurtle;" + + " after:gregtech_addon;" + + " required-after:AppliedEnergistics;" + + " after:AdvancedSolarPanel;" + + " after:AtomicScience;" + + " after:ICBM|Explosion;" + + " after:MFFS;" + + " after:GraviSuite;" + + " after:UndergroundBiomes;" + + " after:NetherOres") +@NetworkMod(clientSideRequired = true, serverSideRequired = true, channels = { + "WarpDriveBeam", + "WarpDriveFreq", + "WarpDriveLaserT", + "WarpDriveCloaks" }, packetHandler = PacketHandler.class) +/** + * @author Cr0s + */ +public class WarpDrive implements LoadingCallback { + public static Block warpCore; + public static Block protocolBlock; + public static Block radarBlock; + public static Block isolationBlock; + public static Block airgenBlock; + public static Block laserBlock; + public static Block laserCamBlock; + public static Block cameraBlock; + public static Block monitorBlock; + public static Block boosterBlock; + public static Block miningLaserBlock; + public static Block laserTreeFarmBlock; + public static Block liftBlock; + public static Block scannerBlock; + public static Block cloakBlock; + public static Block cloakCoilBlock; + public static Block transporterBlock; + public static Block reactorMonitorBlock; + public static Block powerReactorBlock; + public static Block powerLaserBlock; + public static Block powerStoreBlock; + public static Block airBlock; + public static Block gasBlock; + public static Block iridiumBlock; + public static Block transportBeaconBlock; + public static Block chunkLoaderBlock; + public static BlockDecorative decorativeBlock; + + public static Item reactorLaserFocusItem; + public static ItemWarpComponent componentItem; + public static ItemWarpUpgrade upgradeItem; + + public static EnumArmorMaterial armorMaterial = EnumHelper.addArmorMaterial("WARP", 5, new int[]{1, 3, 2, 1}, 15); + public static ItemWarpArmor helmetItem; + public static ItemWarpAirCanister airCanisterItem; + + public static BiomeGenBase spaceBiome; + public World space; + public SpaceWorldGenerator spaceWorldGenerator; + public HyperSpaceWorldGenerator hyperSpaceWorldGenerator; + public World hyperSpace; + + // Client settings + public static float normalFOV = 70.0F; + public static float normalSensitivity = 1.0F; + + public static CreativeTabs warpdriveTab = new WarpDriveCreativeTab("Warpdrive", "Warpdrive").setBackgroundImageName("warpdrive:creativeTab"); + + @Instance("WarpDrive") + public static WarpDrive instance; + @SidedProxy(clientSide = "cr0s.WarpDrive.client.ClientProxy", serverSide = "cr0s.WarpDrive.CommonProxy") + public static CommonProxy proxy; + + public static WarpCoresRegistry warpCores; + public static JumpgatesRegistry jumpgates; + public static CloakManager cloaks; + + public static CamRegistry cams; + public boolean isOverlayEnabled = false; + public int overlayType = 0; + public String debugMessage = ""; + + public static WarpDrivePeripheralHandler peripheralHandler = null; + + public static String defHelpStr = "help(\"functionName\"): returns help for the function specified"; + public static String defEnergyStr = "getEnergyLevel(): returns currently contained energy, max contained energy"; + public static String defUpgradeStr = "upgrades(): returns a list of currently installed upgrades"; + + @EventHandler + public void preInit(FMLPreInitializationEvent event) { + WarpDriveConfig.preInit(new Configuration(event.getSuggestedConfigurationFile())); + + if (FMLCommonHandler.instance().getSide().isClient()) { + Minecraft mc = Minecraft.getMinecraft(); + + // System.out.println("[WarpDrive] Registering sounds event handler..."); + MinecraftForge.EVENT_BUS.register(new SoundHandler()); + + normalFOV = mc.gameSettings.fovSetting; + normalSensitivity = mc.gameSettings.mouseSensitivity; + WarpDrive.print("[WarpDrive] FOV is " + normalFOV + " Sensitivity is " + normalSensitivity); + } + } + + @SideOnly(Side.CLIENT) + @EventHandler + public void init(FMLInitializationEvent event) { +// FIXME FMLInterModComms.sendMessage("Waila", "register", "cr0s.WarpDrive.client.WailaHandler.callbackRegister"); + } + + public static void print(String out) { + System.out.println((FMLCommonHandler.instance().getEffectiveSide().isClient() ? "Client ":"Server ") + out); + } + + public static void debugPrint(String out) { + if (WarpDriveConfig.G_DEBUGMODE) { + print(out); + } + } + + @EventHandler + public void load(FMLInitializationEvent event) { + WarpDriveConfig.load(); + + // CORE CONTROLLER + protocolBlock = new BlockProtocol(WarpDriveConfig.controllerID,0, Material.rock); + + GameRegistry.registerBlock(protocolBlock, "protocolBlock"); + GameRegistry.registerTileEntity(TileEntityProtocol.class, "protocolBlock"); + + // WARP CORE + warpCore = new BlockReactor(WarpDriveConfig.coreID, 0, Material.rock); + + GameRegistry.registerBlock(warpCore, "warpCore"); + GameRegistry.registerTileEntity(TileEntityReactor.class, "warpCore"); + + // WARP RADAR + radarBlock = new BlockRadar(WarpDriveConfig.radarID, 0, Material.rock); + + GameRegistry.registerBlock(radarBlock, "radarBlock"); + GameRegistry.registerTileEntity(TileEntityRadar.class, "radarBlock"); + + // WARP ISOLATION + isolationBlock = new BlockWarpIsolation( WarpDriveConfig.isolationID, 0, Material.rock); + + GameRegistry.registerBlock(isolationBlock, "isolationBlock"); + + // AIR GENERATOR + airgenBlock = new BlockAirGenerator(WarpDriveConfig.airgenID, 0,Material.rock); + + GameRegistry.registerBlock(airgenBlock, "airgenBlock"); + GameRegistry.registerTileEntity(TileEntityAirGenerator.class, "airgenBlock"); + + + // AIR BLOCK + airBlock = (new BlockAir(WarpDriveConfig.airID)); + + GameRegistry.registerBlock(airBlock, "airBlock"); + + // GAS BLOCK + gasBlock = (new BlockGas(WarpDriveConfig.gasID)); + + GameRegistry.registerBlock(gasBlock, "gasBlock"); + + // LASER EMITTER + laserBlock = new BlockLaser(WarpDriveConfig.laserID, 0,Material.rock); + + GameRegistry.registerBlock(laserBlock, "laserBlock"); + GameRegistry.registerTileEntity(TileEntityLaser.class, "laserBlock"); + + // LASER EMITTER WITH CAMERA + laserCamBlock = new BlockLaserCam(WarpDriveConfig.laserCamID, 0, Material.rock); + + GameRegistry.registerBlock(laserCamBlock, "laserCamBlock"); + + // CAMERA + cameraBlock = new BlockCamera(WarpDriveConfig.camID, 0,Material.rock); + + GameRegistry.registerBlock(cameraBlock, "cameraBlock"); + GameRegistry.registerTileEntity(TileEntityCamera.class, "cameraBlock"); + + // MONITOR + monitorBlock = new BlockMonitor(WarpDriveConfig.monitorID); + + GameRegistry.registerBlock(monitorBlock, "monitorBlock"); + GameRegistry.registerTileEntity(TileEntityMonitor.class, "monitorBlock"); + + + // MINING LASER + miningLaserBlock = new BlockMiningLaser(WarpDriveConfig.miningLaserID, 0, Material.rock); + + GameRegistry.registerBlock(miningLaserBlock, "miningLaserBlock"); + GameRegistry.registerTileEntity(TileEntityMiningLaser.class, "miningLaserBlock"); + + // LASER TREE FARM + laserTreeFarmBlock = new BlockLaserTreeFarm(WarpDriveConfig.laserTreeFarmID, 0, Material.rock); + + GameRegistry.registerBlock(laserTreeFarmBlock, "laserTreeFarmBlock"); + GameRegistry.registerTileEntity(TileEntityLaserTreeFarm.class,"laserTreeFarmBlock"); + + // PARTICLE BOOSTER + boosterBlock = new BlockParticleBooster(WarpDriveConfig.particleBoosterID, 0, Material.rock); + + GameRegistry.registerBlock(boosterBlock, "boosterBlock"); + GameRegistry.registerTileEntity(TileEntityParticleBooster.class, "boosterBlock"); + + // LASER LIFT + liftBlock = new BlockLift(WarpDriveConfig.liftID, 0, Material.rock); + + GameRegistry.registerBlock(liftBlock, "liftBlock"); + GameRegistry.registerTileEntity(TileEntityLift.class, "liftBlock"); + + // IRIDIUM BLOCK + iridiumBlock = new BlockIridium(WarpDriveConfig.iridiumBlockID); + + GameRegistry.registerBlock(iridiumBlock, "iridiumBlock"); + + // SHIP SCANNER + scannerBlock = new BlockShipScanner(WarpDriveConfig.shipScannerID, 0, Material.rock); + + GameRegistry.registerBlock(scannerBlock, "scannerBlock"); + GameRegistry.registerTileEntity(TileEntityShipScanner.class, "scannerBlock"); + + // CLOAKING DEVICE CORE + cloakBlock = new BlockCloakingDeviceCore(WarpDriveConfig.cloakCoreID, 0, Material.rock); + + GameRegistry.registerBlock(cloakBlock, "cloakBlock"); + GameRegistry.registerTileEntity(TileEntityCloakingDeviceCore.class, "cloakBlock"); + + // CLOAKING DEVICE COIL + cloakCoilBlock = new BlockCloakingCoil(WarpDriveConfig.cloakCoilID, 0, Material.rock); + + GameRegistry.registerBlock(cloakCoilBlock, "cloakCoilBlock"); + + // TRANSPORTER + transporterBlock = new BlockTransporter(WarpDriveConfig.transporterID,Material.rock); + + GameRegistry.registerBlock(transporterBlock, "transporter"); + GameRegistry.registerTileEntity(TileEntityTransporter.class,"transporter"); + + // REACTOR MONITOR + reactorMonitorBlock = new BlockLaserReactorMonitor(WarpDriveConfig.reactorMonitorID, Material.rock); + + GameRegistry.registerBlock(reactorMonitorBlock, "reactorMonitor"); + GameRegistry.registerTileEntity(TileEntityLaserReactorMonitor.class,"reactorMonitor"); + + // TRANSPORT BEACON + transportBeaconBlock = new BlockTransportBeacon(WarpDriveConfig.transportBeaconID); + + GameRegistry.registerBlock(transportBeaconBlock, "transportBeacon"); + + // POWER REACTOR, LASER, STORE + powerReactorBlock = new BlockPowerReactor(WarpDriveConfig.powerReactorID); + GameRegistry.registerBlock(powerReactorBlock,"powerReactor"); + GameRegistry.registerTileEntity(TileEntityPowerReactor.class, "powerReactor"); + + powerLaserBlock = new BlockPowerLaser(WarpDriveConfig.powerLaserID); + GameRegistry.registerBlock(powerLaserBlock, "powerLaser"); + GameRegistry.registerTileEntity(TileEntityPowerLaser.class, "powerLaser"); + + powerStoreBlock = new BlockPowerStore(WarpDriveConfig.powerStoreID); + GameRegistry.registerBlock(powerStoreBlock,"powerStore"); + GameRegistry.registerTileEntity(TileEntityPowerStore.class, "powerStore"); + + // CHUNK LOADER + chunkLoaderBlock = new BlockChunkLoader(WarpDriveConfig.chunkLoaderID); + GameRegistry.registerBlock(chunkLoaderBlock, "chunkLoader"); + GameRegistry.registerTileEntity(TileEntityChunkLoader.class, "chunkLoader"); + + // DECORATIVE + decorativeBlock = new BlockDecorative(WarpDriveConfig.decorativeID); + GameRegistry.registerBlock(decorativeBlock, ItemBlockDecorative.class, "decorative"); + + // REACTOR LASER FOCUS + reactorLaserFocusItem = new ItemReactorLaserFocus(WarpDriveConfig.reactorLaserFocusID); + GameRegistry.registerItem(reactorLaserFocusItem, "reactorLaserFocus"); + + // COMPONENT ITEMS + componentItem = new ItemWarpComponent(WarpDriveConfig.componentID); + GameRegistry.registerItem(componentItem, "component"); + + helmetItem = new ItemWarpArmor(WarpDriveConfig.helmetID, 0); + GameRegistry.registerItem(helmetItem, "helmet"); + + airCanisterItem = new ItemWarpAirCanister(WarpDriveConfig.airCanisterID); + GameRegistry.registerItem(airCanisterItem, "airCanisterFull"); + + upgradeItem = new ItemWarpUpgrade(WarpDriveConfig.upgradeID); + GameRegistry.registerItem(upgradeItem, "upgrade"); + + proxy.registerEntities(); + ForgeChunkManager.setForcedChunkLoadingCallback(instance, instance); + + spaceWorldGenerator = new SpaceWorldGenerator(); + GameRegistry.registerWorldGenerator(spaceWorldGenerator); + hyperSpaceWorldGenerator = new HyperSpaceWorldGenerator(); + GameRegistry.registerWorldGenerator(hyperSpaceWorldGenerator); + + registerSpaceDimension(); + registerHyperSpaceDimension(); + + MinecraftForge.EVENT_BUS.register(new SpaceEventHandler()); + + if (FMLCommonHandler.instance().getEffectiveSide().isClient()) { + warpdriveTab.setBackgroundImageName("items.png"); + MinecraftForge.EVENT_BUS.register(new CameraOverlay(Minecraft.getMinecraft())); + } + + if (WarpDriveConfig.isCCLoaded) { + peripheralHandler = new WarpDrivePeripheralHandler(); + ComputerCraftAPI.registerPeripheralProvider(peripheralHandler); + } + } + + @EventHandler + public void postInit(FMLPostInitializationEvent event) { + space = DimensionManager.getWorld(WarpDriveConfig.G_SPACE_DIMENSION_ID); + hyperSpace = DimensionManager.getWorld(WarpDriveConfig.G_HYPERSPACE_DIMENSION_ID); + + WarpDriveConfig.postInit(); + + if (WarpDriveConfig.isICLoaded && WarpDriveConfig.G_ENABLE_IC2_RECIPES) { + initIC2Recipes(); + } + if (WarpDriveConfig.isAppliedEnergisticsLoaded && WarpDriveConfig.isThermalExpansionLoaded && WarpDriveConfig.isAtomicScienceLoaded && WarpDriveConfig.G_ENABLE_TDK_RECIPES) { + initAETERecipes(); + } + if (WarpDriveConfig.G_ENABLE_VANILLA_RECIPES) { + initVanillaRecipes(); + } + + warpCores = new WarpCoresRegistry(); + jumpgates = new JumpgatesRegistry(); + cams = new CamRegistry(); + } + + private static void initVanillaRecipes() { + componentItem.registerRecipes(); + decorativeBlock.initRecipes(); + upgradeItem.initRecipes(); + + //WarpCore + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(warpCore), false, "ipi", "ici", "idi", + 'i', Item.ingotIron, + 'p', componentItem.getIS(6), + 'c', componentItem.getIS(2), + 'd', Item.diamond)); + + //Controller + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(protocolBlock), false, "ici", "idi", "iii", + 'i', Item.ingotIron, + 'c', componentItem.getIS(5), + 'd', Item.diamond)); + + //Radar + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(radarBlock), false, "ggg", "pdc", "iii", + 'i', Item.ingotIron, + 'c', componentItem.getIS(5), + 'p', componentItem.getIS(6), + 'g', Block.glass, + 'd', Item.diamond)); + + //Isolation Block + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(isolationBlock), false, "igi", "geg", "igi", + 'i', Item.ingotIron, + 'g', Block.glass, + 'e', Item.enderPearl)); + + //Air generator + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(airgenBlock), false, "ibi", "i i", "ipi", + 'i', Item.ingotIron, + 'b', Block.fenceIron, + 'p', componentItem.getIS(6))); + + //Laser + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(laserBlock), false, "ili", "iri", "ici", + 'i', Item.ingotIron, + 'r', Item.redstone, + 'c', componentItem.getIS(5), + 'l', componentItem.getIS(3), + 'p', componentItem.getIS(6))); + + //Mining laser + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(miningLaserBlock), false, "ici", "iti", "ili", + 'i', Item.ingotIron, + 'r', Item.redstone, + 't', componentItem.getIS(1), + 'c', componentItem.getIS(5), + 'l', componentItem.getIS(3))); + + //Tree farm laser + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(laserTreeFarmBlock), false, "ili", "sts", "ici", + 'i', Item.ingotIron, + 's', "treeSapling", + 't', componentItem.getIS(1), + 'c', componentItem.getIS(5), + 'l', componentItem.getIS(3))); + + //Laser Lift + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(liftBlock), false, "ipi", "rtr", "ili", + 'i', Item.ingotIron, + 'r', Item.redstone, + 't', componentItem.getIS(1), + 'l', componentItem.getIS(3), + 'p', componentItem.getIS(6))); + + //Transporter + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(transporterBlock), false, "iii", "ptc", "iii", + 'i', Item.ingotIron, + 't', componentItem.getIS(1), + 'c', componentItem.getIS(5), + 'p', componentItem.getIS(6))); + + //Particle Booster + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(boosterBlock), false, "ipi", "rgr", "iii", + 'i', Item.ingotIron, + 'r', Item.redstone, + 'g', Block.glass, + 'p', componentItem.getIS(6))); + + //Camera + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(cameraBlock), false, "ngn", "i i", "ici", + 'i', Item.ingotIron, + 'n', Item.goldNugget, + 'g', Block.glass, + 'c', componentItem.getIS(5))); + + //LaserCamera + GameRegistry.addRecipe(new ShapelessOreRecipe(new ItemStack(laserCamBlock), cameraBlock, laserBlock)); + + //Monitor + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(monitorBlock), false, "ggg", "iti", "ici", + 'i', Item.ingotIron, + 't', Block.torchWood, + 'g', Block.glass, + 'c', componentItem.getIS(5))); + + //Cloaking device + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(cloakBlock), false, "ipi", "lrl", "ici", + 'i', Item.ingotIron, + 'r', Item.redstone, + 'l', componentItem.getIS(3), + 'c', componentItem.getIS(5), + 'p', componentItem.getIS(6))); + + //Cloaking coil + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(cloakCoilBlock), false, "ini", "rdr", "ini", + 'i', Item.ingotIron, + 'd', Item.diamond, + 'r', Item.redstone, + 'n', Item.goldNugget)); + + //Power Laser + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(powerLaserBlock), false, "iii", "ilg", "ici", + 'i', Item.ingotIron, + 'g', Block.glass, + 'c', componentItem.getIS(5), + 'l', componentItem.getIS(3))); + + //Power Reactor + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(powerReactorBlock), false, "ipi", "gog", "ici", + 'i', Item.ingotIron, + 'g', Block.glass, + 'o', componentItem.getIS(4), + 'c', componentItem.getIS(5), + 'p', componentItem.getIS(6))); + + //Power Store + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(powerStoreBlock), false, "ipi", "isi", "ici", + 'i', Item.ingotIron, + 's', componentItem.getIS(7), + 'c', componentItem.getIS(5), + 'p', componentItem.getIS(6))); + + //Transport Beacon + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(transportBeaconBlock), false, " e ", "ldl", " s ", + 'e', Item.enderPearl, + 'l', "dyeBlue", + 'd', Item.diamond, + 's', Item.stick)); + + //Chunk Loader + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(chunkLoaderBlock), false, "ipi", "ici", "ifi", + 'i', Item.ingotIron, + 'p', componentItem.getIS(6), + 'c', componentItem.getIS(0), + 'f', componentItem.getIS(5))); + + //Helmet + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(helmetItem), false, "iii", "iwi", "gcg", + 'i', Item.ingotIron, + 'w', Block.cloth, + 'g', Block.glass, + 'c', componentItem.getIS(8))); + } + + private static void initAETERecipes() { + ItemStack redstoneEnergycell = GameRegistry.findItemStack("ThermalExpansion", "cellReinforced", 1); + ItemStack resonantEnergycell = GameRegistry.findItemStack("ThermalExpansion", "cellResonant", 1); + ItemStack bucketEnder = GameRegistry.findItemStack("ThermalExpansion", "bucketEnder", 1); + ItemStack fluixCrystal = WarpDriveConfig.getAEMaterial("matFluxCrystal"); + ItemStack quantumEntangledSingularity = WarpDriveConfig.getAEMaterial("matQuantumEntangledSingularity"); + ItemStack vibrantQuartzGlass = WarpDriveConfig.getAEBlock("blkQuartzLamp"); + vibrantQuartzGlass.setItemDamage(4); + ItemStack antimatter = GameRegistry.findItemStack("ResonantInduction|Atomic", "antimatter", 1); + antimatter.setItemDamage(0); + ItemStack floppy = GameRegistry.findItemStack("ComputerCraft", "disk", 1); + ItemStack ultimateLappack = new ItemStack(WarpDriveConfig.GS_ultimateLappack, 1, 1); + + // top = advancedCircuit, redstoneEnergycell, advancedCircuit + // middle = fluix crystal, advancedMachine, fluix crystal + // bottom = advancedCircuit, bucket Resonant ender, advancedCircuit + GameRegistry.addRecipe(new ItemStack(warpCore), "crc", "fmf", "cec", + 'm', WarpDriveConfig.getIC2Item("advancedMachine"), + 'c', WarpDriveConfig.getIC2Item("advancedCircuit"), + 'r', redstoneEnergycell, + 'e', bucketEnder, + 'f', fluixCrystal); + + // top = advancedCircuit, floppy, advancedCircuit + // middle = advancedCircuit, advancedMachine, advancedCircuit + // bottom = advancedCircuit, fluix crystal, advancedCircuit + GameRegistry.addRecipe(new ItemStack(protocolBlock), "coc", "cmc", "cfc", + 'm', WarpDriveConfig.getIC2Item("advancedMachine"), + 'c', WarpDriveConfig.getIC2Item("advancedCircuit"), + 'o', floppy, + 'f', fluixCrystal); + + // top = Iridium plate, Resonant Energycell, Iridium plate + // middle = Singularity, 125 milligram antimatter, Singularity + // bottom = Iridium plate, Ultimate lappack, Iridium plate + GameRegistry.addRecipe(new ItemStack(powerReactorBlock), "iri", "sas", "ili", + 'i', WarpDriveConfig.getIC2Item("iridiumPlate"), + 's', quantumEntangledSingularity, + 'a', antimatter, + 'l', ultimateLappack, + 'r', resonantEnergycell); + + // top = Advanced circuit, Advanced alloy, Advanced alloy + // middle = Advanced circuit, Warp drive laser, Vibrant quartz glass + // bottom = Advanced circuit, Certus quartz tank, Advanced alloy + ItemStack isMiningLaserBlock = new ItemStack(miningLaserBlock.blockID, 1, 0); + ItemStack isCertusQuartzTank = new ItemStack(WarpDriveConfig.AEExtra_certusQuartzTank.blockID, 1, 0); + + GameRegistry.addRecipe(new ItemStack(powerLaserBlock), "caa", "czg", "cta", + 'c', WarpDriveConfig.getIC2Item("advancedCircuit"), + 'a', WarpDriveConfig.getIC2Item("advancedAlloy"), + 'z', isMiningLaserBlock, + 't', isCertusQuartzTank, + 'g', vibrantQuartzGlass); + } + + private static void initIC2Recipes() { + GameRegistry.addRecipe(new ItemStack(warpCore), "ici", "cmc", "ici", + 'i', WarpDriveConfig.getIC2Item("iridiumPlate"), + 'm', WarpDriveConfig.getIC2Item("advancedMachine"), + 'c', WarpDriveConfig.getIC2Item("advancedCircuit")); + + GameRegistry.addRecipe(new ItemStack(protocolBlock), "iic", "imi", "cii", + 'i', WarpDriveConfig.getIC2Item("iridiumPlate"), + 'm', WarpDriveConfig.getIC2Item("advancedMachine"), + 'c', WarpDriveConfig.getIC2Item("advancedCircuit")); + + GameRegistry.addRecipe(new ItemStack(radarBlock), "ifi", "imi", "imi", + 'i', WarpDriveConfig.getIC2Item("iridiumPlate"), + 'm', WarpDriveConfig.getIC2Item("advancedMachine"), + 'f', WarpDriveConfig.getIC2Item("frequencyTransmitter")); + + GameRegistry.addRecipe(new ItemStack(isolationBlock), "iii", "idi", "iii", + 'i', WarpDriveConfig.getIC2Item("iridiumPlate"), + 'm', WarpDriveConfig.getIC2Item("advancedMachine"), + 'd', Block.blockDiamond); + + GameRegistry.addRecipe(new ItemStack(airgenBlock), "lcl", "lml", "lll", + 'l', Block.leaves, + 'm', WarpDriveConfig.getIC2Item("advancedMachine"), + 'c', WarpDriveConfig.getIC2Item("advancedCircuit")); + + GameRegistry.addRecipe(new ItemStack(laserBlock), "sss", "ama", "aaa", + 'm', WarpDriveConfig.getIC2Item("advancedMachine"), + 'a', WarpDriveConfig.getIC2Item("advancedAlloy"), + 's', WarpDriveConfig.getIC2Item("advancedCircuit")); + + GameRegistry.addRecipe(new ItemStack(miningLaserBlock), "aaa", "ama", "ccc", + 'c', WarpDriveConfig.getIC2Item("advancedCircuit"), + 'a', WarpDriveConfig.getIC2Item("advancedAlloy"), + 'm', WarpDriveConfig.getIC2Item("miner")); + + GameRegistry.addRecipe(new ItemStack(boosterBlock), "afc", "ama", "cfa", + 'c', WarpDriveConfig.getIC2Item("advancedCircuit"), + 'a', WarpDriveConfig.getIC2Item("advancedAlloy"), + 'f', WarpDriveConfig.getIC2Item("glassFiberCableItem"), + 'm', WarpDriveConfig.getIC2Item("mfeUnit")); + + GameRegistry.addRecipe(new ItemStack(liftBlock), "aca", "ama", "a#a", + 'c', WarpDriveConfig.getIC2Item("advancedCircuit"), + 'a', WarpDriveConfig.getIC2Item("advancedAlloy"), + 'm', WarpDriveConfig.getIC2Item("magnetizer")); + + GameRegistry.addRecipe(new ItemStack(iridiumBlock), "iii", "iii", "iii", + 'i', WarpDriveConfig.getIC2Item("iridiumPlate")); + + GameRegistry.addShapelessRecipe( + new ItemStack(WarpDriveConfig.getIC2Item("iridiumPlate").getItem(), 9), + new ItemStack(iridiumBlock)); + + GameRegistry.addRecipe(new ItemStack(laserCamBlock), "imi", "cec", "#k#", + 'i', WarpDriveConfig.getIC2Item("iridiumPlate"), + 'm', WarpDriveConfig.getIC2Item("advancedMachine"), + 'c', WarpDriveConfig.getIC2Item("advancedCircuit"), + 'e', laserBlock, + 'k', cameraBlock); + + GameRegistry.addRecipe(new ItemStack(cameraBlock), "cgc", "gmg", "cgc", + 'm', WarpDriveConfig.getIC2Item("advancedMachine"), + 'c', WarpDriveConfig.getIC2Item("advancedCircuit"), + 'g', Block.glass); + + GameRegistry.addRecipe(new ItemStack(monitorBlock), "gcg", "gmg", "ggg", + 'm', WarpDriveConfig.getIC2Item("advancedMachine"), + 'c', WarpDriveConfig.getIC2Item("advancedCircuit"), + 'g', Block.glass); + + GameRegistry.addRecipe(new ItemStack(scannerBlock), "sgs", "mma", "amm", + 'm', WarpDriveConfig.getIC2Item("advancedMachine"), + 'a', WarpDriveConfig.getIC2Item("advancedAlloy"), + 's', WarpDriveConfig.getIC2Item("advancedCircuit"), + 'g', Block.glass); + + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(laserTreeFarmBlock),false,new Object[] { + "cwc", "wmw", "cwc", + 'c', WarpDriveConfig.getIC2Item("electronicCircuit"), + 'w', "logWood", + 'm', miningLaserBlock })); + + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(transporterBlock), false, new Object[] { + "ece", "imi", "iei", + 'e', Item.enderPearl, + 'c', WarpDriveConfig.getIC2Item("electronicCircuit"), + 'i', WarpDriveConfig.getIC2Item("plateiron"), + 'm', WarpDriveConfig.getIC2Item("machine") })); + + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(reactorLaserFocusItem),false,new Object[] { + " p ", "pdp", " p ", + 'p', WarpDriveConfig.getIC2Item("plateiron"), + 'd', "gemDiamond"})); + + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(reactorMonitorBlock), false, new Object[] { + "pdp", "dmd", "pdp", + 'p', WarpDriveConfig.getIC2Item("plateiron"), + 'd', "gemDiamond", + 'm', WarpDriveConfig.getIC2Item("mfeUnit")})); + + GameRegistry.addRecipe(new ItemStack(cloakBlock), "imi", "mcm", "imi", + 'i', iridiumBlock, + 'c', cloakCoilBlock, + 'm', WarpDriveConfig.getIC2Item("advancedMachine")); + + GameRegistry.addRecipe(new ItemStack(cloakCoilBlock), "iai", "aca", "iai", + 'i', WarpDriveConfig.getIC2Item("iridiumPlate"), + 'c', WarpDriveConfig.getIC2Item("advancedCircuit"), + 'a', WarpDriveConfig.getIC2Item("advancedAlloy")); + } + + private static void registerSpaceDimension() { + spaceBiome = (new BiomeSpace(24)) + .setColor(0) + .setDisableRain() + .setBiomeName("Space"); + DimensionManager.registerProviderType(WarpDriveConfig.G_SPACE_PROVIDER_ID, SpaceProvider.class, true); + DimensionManager.registerDimension(WarpDriveConfig.G_SPACE_DIMENSION_ID, WarpDriveConfig.G_SPACE_PROVIDER_ID); + } + + private static void registerHyperSpaceDimension() { + DimensionManager.registerProviderType(WarpDriveConfig.G_HYPERSPACE_PROVIDER_ID, HyperSpaceProvider.class, true); + DimensionManager.registerDimension(WarpDriveConfig.G_HYPERSPACE_DIMENSION_ID, WarpDriveConfig.G_HYPERSPACE_PROVIDER_ID); + } + + @EventHandler + public void serverLoad(FMLServerStartingEvent event) { + cloaks = new CloakManager(); + MinecraftForge.EVENT_BUS.register(new CloakChunkWatcher()); + + event.registerServerCommand(new GenerateCommand()); + event.registerServerCommand(new SpaceTpCommand()); + event.registerServerCommand(new InvisibleCommand()); + event.registerServerCommand(new JumpgateCommand()); + event.registerServerCommand(new DebugCommand()); + } + + public Ticket registerChunkLoadTE(WarpChunkTE te, boolean refreshLoading) { + World worldObj = te.worldObj; + if (ForgeChunkManager.ticketCountAvailableFor(this, worldObj) > 0) + { + Ticket t = ForgeChunkManager.requestTicket(this, worldObj, Type.NORMAL); + if (t != null) { + te.giveTicket(t); // FIXME calling the caller is a bad idea + if(refreshLoading) + te.refreshLoading(); + return t; + } + else + { + WarpDrive.debugPrint("Ticket not granted"); + } + } + else + { + WarpDrive.debugPrint("No tickets left!"); + } + return null; + } + + public Ticket registerChunkLoadTE(WarpChunkTE te) + { + return registerChunkLoadTE(te, true); + } + + public Ticket getTicket(WarpChunkTE te) + { + return registerChunkLoadTE(te, false); + } + + @Override + public void ticketsLoaded(List tickets, World world) + { + for (Ticket ticket : tickets) + { + NBTTagCompound data = ticket.getModData(); + if(data != null) + { + int w = data.getInteger("ticketWorldObj"); + int x = data.getInteger("ticketX"); + int y = data.getInteger("ticketY"); + int z = data.getInteger("ticketZ"); + if(w != 0 || x != 0 || y != 0 || z != 0) + { + WorldServer ws = DimensionManager.getWorld(w); + if(ws != null) + { + TileEntity te = ws.getBlockTileEntity(x, y, z); + if(te != null && te instanceof WarpChunkTE) + { + if(((WarpChunkTE)te).shouldChunkLoad()) + { + WarpDrive.debugPrint("[TicketCallback] Regiving Ticket!"); + ((WarpChunkTE)te).giveTicket(ticket); + ((WarpChunkTE)te).refreshLoading(true); + return; + } + } + } + } + } + + ForgeChunkManager.releaseTicket(ticket); + } + } +} diff --git a/src/cr0s/WarpDrive/WarpDriveConfig.java b/src/cr0s/WarpDrive/WarpDriveConfig.java new file mode 100644 index 00000000..80714008 --- /dev/null +++ b/src/cr0s/WarpDrive/WarpDriveConfig.java @@ -0,0 +1,1086 @@ +package cr0s.WarpDrive; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.Random; + +import cpw.mods.fml.common.Loader; +import cr0s.WarpDrive.data.TransitionPlane; +import net.minecraftforge.common.Configuration; +import net.minecraftforge.common.Property; +import net.minecraftforge.oredict.OreDictionary; +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import ic2.api.item.Items; + +public class WarpDriveConfig +{ + private static Configuration config; + // Blocks + public static int coreID; + public static int controllerID; + public static int radarID; + public static int isolationID; + public static int airID; + public static int airgenID; + public static int gasID; + public static int laserID; + public static int miningLaserID; + public static int particleBoosterID; + public static int liftID; + public static int laserCamID; + public static int camID; + public static int monitorID; + public static int iridiumBlockID; + public static int shipScannerID; + public static int cloakCoreID; + public static int cloakCoilID; + public static int laserTreeFarmID; + public static int transporterID; + public static int transportBeaconID; + public static int reactorLaserFocusID; + public static int reactorMonitorID; + public static int powerReactorID; + public static int powerLaserID; + public static int powerStoreID; + public static int chunkLoaderID; + public static int decorativeID; + + // Items + public static int componentID; + public static int helmetID; + public static int chestID; + public static int pantsID; + public static int bootsID; + public static int airCanisterID; + public static int upgradeID; + + /* + * The variables which store whether or not individual mods are loaded + */ + public static boolean isForgeMultipartLoaded = false; + public static boolean isGregLoaded = false; + public static boolean isAppliedEnergisticsLoaded = false; + public static boolean isAdvSolPanelLoaded = false; + public static boolean isAtomicScienceLoaded = false; + public static boolean isAEExtraLoaded = false; + public static boolean isICBMLoaded = false; + public static boolean isMFFSLoaded = false; + public static boolean isGraviSuiteLoaded = false; + public static boolean isICLoaded = false; + public static boolean isCCLoaded = false; + public static boolean isUndergroundBiomesLoaded = false; + public static boolean isNetherOresLoaded = false; + public static boolean isThermalExpansionLoaded = false; + public static boolean isMetallurgyLoaded = false; + public static boolean isAdvancedRepulsionSystemsLoaded = false; + public static boolean isMagicalCropsLoaded = false; + + // ForgeMultipart (microblocks) support + public static Method forgeMultipart_helper_createTileFromNBT = null; + public static Method forgeMultipart_helper_sendDescPacket = null; + public static Method forgeMultipart_tileMultipart_onChunkLoad = null; + + public static int[] IC2_Air; + public static int[] IC2_Empty; + public static int IC2_RubberWood; + public static ItemStack IC2_Resin; + public static Item IC2_fluidCell; + public static int CC_Computer = 0, CC_peripheral = 0, CC_Floppy = 0, CCT_Turtle = 0, CCT_Upgraded = 0, CCT_Advanced = 0; + public static int GT_Ores = 0, GT_Granite = 0, GT_Machine = 0; + public static int ASP = 0; + public static int AS_Turbine = 0, AS_deuteriumCell = 0; + public static int ICBM_Machine = 0, ICBM_Missile = 0, ICBM_Explosive = 0; + public static int GS_ultimateLappack = 0; + public static int UB_igneousStone = 0, UB_igneousCobblestone = 0, UB_metamorphicStone = 0, UB_metamorphicCobblestone = 0, UB_sedimentaryStone = 0; + public static int NetherOres_count; + public static int[] NetherOres_block; + public static int[][] Metallurgy_overworldOresBlock; + public static int[][] Metallurgy_netherOresBlock; + public static int[][] Metallurgy_endOresBlock; + public static ArrayList forceFieldBlocks; + + public static Set SpaceHelmets, Jetpacks, MinerOres, MinerLogs, MinerLeaves, scannerIgnoreBlocks; + private static Class AEBlocks; + private static Class AEMaterials; + private static Class AEItems; + public static ArrayList CommonWorldGenOres; + public static Item AEExtra_fluidDrive; + public static Block AEExtra_certusQuartzTank; + + // Mod configuration (see loadWarpDriveConfig() for comments/definitions) + // General + public static int G_SPACE_PROVIDER_ID = 14; + public static int G_SPACE_DIMENSION_ID = -2; + public static int G_HYPERSPACE_PROVIDER_ID = 15; + public static int G_HYPERSPACE_DIMENSION_ID = -3; + public static int G_SPACE_WORLDBORDER_BLOCKS = 100000; + public static final int LUA_SCRIPTS_NONE = 0; + public static final int LUA_SCRIPTS_TEMPLATES = 1; + public static final int LUA_SCRIPTS_ALL = 2; + public static int G_LUA_SCRIPTS = LUA_SCRIPTS_ALL; + public static boolean G_DEBUGMODE = false; + public static String G_SCHEMALOCATION = "warpDrive_schematics"; + public static int G_BLOCKS_PER_TICK = 3500; + + public static boolean G_ENABLE_IC2_RECIPES = true; + public static boolean G_ENABLE_VANILLA_RECIPES = false; + public static boolean G_ENABLE_TDK_RECIPES = false; + + // Transition planes + public static TransitionPlane[] G_TRANSITIONPLANES = null; + + // Warp Drive Core + public static int WC_MAX_ENERGY_VALUE = 100000000; + public static int WC_ENERGY_PER_BLOCK_MODE1 = 10; + public static int WC_ENERGY_PER_DISTANCE_MODE1 = 100; + public static int WC_ENERGY_PER_BLOCK_MODE2 = 1000; + public static int WC_ENERGY_PER_DISTANCE_MODE2 = 1000; + public static int WC_ENERGY_PER_ENTITY_TO_SPACE = 1000000; + public static int WC_MAX_JUMP_DISTANCE = 128; + public static int WC_MAX_SHIP_VOLUME_ON_SURFACE = 3000; + public static int WC_MIN_SHIP_VOLUME_FOR_HYPERSPACE = 1200; + public static int WC_MAX_SHIP_SIDE = 127; + public static int WC_COOLDOWN_INTERVAL_SECONDS = 30; + public static int WC_COLLISION_TOLERANCE_BLOCKS = 3; + public static int WC_WARMUP_SHORTJUMP_SECONDS = 10; + public static int WC_WARMUP_LONGJUMP_SECONDS = 30; + public static int WC_WARMUP_RANDOM_TICKS = 60; + public static int WC_CORES_REGISTRY_UPDATE_INTERVAL_SECONDS = 10; + public static int WC_ISOLATION_UPDATE_INTERVAL_SECONDS = 10; + public static String[] WC_UNLIMITED_PLAYERNAMES = { "notch", "someone" }; + + // Warp Radar + public static int WR_MAX_ENERGY_VALUE = 100000000; // 100kk eU + public static int WR_MAX_ISOLATION_RANGE = 2; + public static int WR_MIN_ISOLATION_BLOCKS = 5; + public static int WR_MAX_ISOLATION_BLOCKS = 132; + public static double WR_MIN_ISOLATION_EFFECT = 0.12; + public static double WR_MAX_ISOLATION_EFFECT = 1.00; + + // Ship Scanner + public static int SS_MAX_ENERGY_VALUE = 500000000; + public static int SS_EU_PER_BLOCK_SCAN = 100; // eU per block of ship volume (including air) + public static int SS_EU_PER_BLOCK_DEPLOY = 5000; + public static int SS_MAX_DEPLOY_RADIUS_BLOCKS = 50; + + // Particle Booster + public static int PB_MAX_ENERGY_VALUE = 100000; + + // Laser Emitter + public static int LE_MAX_BOOSTERS_NUMBER = 10; + public static int LE_MAX_LASER_ENERGY = 4000000; + public static int LE_EMIT_DELAY_TICKS = 20 * 3; + public static int LE_EMIT_SCAN_DELAY_TICKS = 10; + + public static double LE_COLLECT_ENERGY_MULTIPLIER = 0.60D; + public static int LE_BEAM_LENGTH_PER_ENERGY_DIVIDER = 5000; + public static int LE_ENTITY_HIT_SET_ON_FIRE_TIME = 100; + public static int LE_ENTITY_HIT_DAMAGE_PER_ENERGY_DIVIDER = 10000; + public static int LE_ENTITY_HIT_EXPLOSION_LASER_ENERGY = 1000000; + public static int LE_BLOCK_HIT_CONSUME_ENERGY = 70000; + public static int LE_BLOCK_HIT_CONSUME_ENERGY_PER_BLOCK_RESISTANCE = 1000; + public static int LE_BLOCK_HIT_CONSUME_ENERGY_PER_DISTANCE = 10; + + // Mining Laser + // BuildCraft quarry values for reference + // - harvesting one block is 60 MJ/block = 600 RF/block = ~145 EU/block + // - maximum speed is 3.846 ticks per blocks + // - overall consumption varies from 81.801 to 184.608 MJ/block (depending on speed) = up to 1846.08 RF/block = up to ~448 EU/block + // - at radius 5, one layer takes ~465 ticks ((ML_MAX_RADIUS * 2 + 1) ^ 2 * 3.846) + // - overall consumption is ((ML_MAX_RADIUS * 2 + 1) ^ 2) * 448 => ~ 54208 EU/layer + // WarpDrive mining laser in comparison + // - each mined layer is scanned twice + // - default ore generation: 1 ore out of 25 blocks + // - overall consumption in 'all, space' is ML_EU_PER_LAYER_SPACE / ((ML_MAX_RADIUS * 2 + 1) ^ 2) + ML_EU_PER_BLOCK_SPACE => ~ 356 EU/block + // - overall consumption in 'all, space' is ML_EU_PER_LAYER_SPACE + ((ML_MAX_RADIUS * 2 + 1) ^ 2) * ML_EU_PER_BLOCK_SPACE => ~ 43150 EU/layer + // - overall consumption in 'ores, space' is ML_EU_PER_LAYER_SPACE + ((ML_MAX_RADIUS * 2 + 1) ^ 2) * ML_EU_PER_BLOCK_SPACE * ML_EU_MUL_ORESONLY / 25 => ~ 28630 EU/layer + // - at radius 5, one layer takes 403 ticks (2 * ML_SCAN_DELAY_TICKS + ML_MINE_DELAY_TICKS * (ML_MAX_RADIUS * 2 + 1) ^ 2) + public static int ML_MAX_BOOSTERS_NUMBER = 1; + public static int ML_WARMUP_DELAY_TICKS = 20; + public static int ML_SCAN_DELAY_TICKS = 20; + public static int ML_MINE_DELAY_TICKS = 3; + public static int ML_EU_PER_LAYER_SPACE = 25000; + public static int ML_EU_PER_LAYER_EARTH = 35000; + public static int ML_EU_PER_BLOCK_SPACE = 150; + public static int ML_EU_PER_BLOCK_EARTH = 300; + public static double ML_EU_MUL_ORESONLY = 5.0; // lower value encourages to keep the land 'clean' + public static double ML_EU_MUL_SILKTOUCH = 2.5; + public static double ML_DEUTERIUM_MUL_SILKTOUCH = 1.0; + public static double ML_EU_MUL_FORTUNE = 2.5; + public static int ML_MAX_RADIUS = 5; + + // Tree farm + public static int TF_MAX_SIZE = 16; + + // Cloaking device core + public static int CD_MAX_CLOAKING_FIELD_SIDE = 100; + public static int CD_ENERGY_PER_BLOCK_TIER1 = 125; + public static int CD_ENERGY_PER_BLOCK_TIER2 = 500; + public static int CD_FIELD_REFRESH_INTERVAL_SECONDS = 3; + public static int CD_COIL_CAPTURE_BLOCKS = 5; + + // Air generator + public static int AG_RF_PER_CANISTER = 20; + + // Reactor monitor + public static int RM_MAX_ENERGY = 1000000; + public static double RM_EU_PER_HEAT = 2; + + // Transporter + public static int TR_MAX_ENERGY = 1000000; + public static boolean TR_RELATIVE_COORDS = true; + public static double TR_EU_PER_METRE = 100; + // public static double TR_MAX_SCAN_RANGE = 4; FIXME: not used ?!? + public static double TR_MAX_BOOST_MUL = 4; + + // Power reactor + public static int PR_MAX_ENERGY = 100000000; + public static int PR_TICK_TIME = 5; + public static int PR_MAX_LASERS = 6; + + // Power store + public static int PS_MAX_ENERGY = 1000000; + + // Laser Lift + public static int LL_MAX_ENERGY = 2400; + public static int LL_LIFT_ENERGY = 800; + public static int LL_TICK_RATE = 10; + + // Chunk Loader + public static int CL_MAX_ENERGY = 1000000; + public static int CL_MAX_DISTANCE = 2; + public static int CL_RF_PER_CHUNKTICK = 320; + + public static ItemStack getIC2Item(String id) { + return Items.getItem(id); + } + + public static ItemStack getAEBlock(String id) { + try { + Object ret = AEBlocks.getField(id).get(null); + if (ret instanceof ItemStack) + return (ItemStack)ret; + } catch (Exception e) { + WarpDrive.debugPrint("WarpDriveConfig Call getAEBlock failed for " + id); + } + return null; + } + + public static ItemStack getAEMaterial(String id) { + try { + Object ret = AEMaterials.getField(id).get(null); + if (ret instanceof ItemStack) + return (ItemStack)ret; + } catch (Exception e) { + WarpDrive.debugPrint("WarpDriveConfig Call getAEMaterial failed for " + id); + } + return null; + } + + public static ItemStack getAEItem(String id) { + try { + Object ret = AEItems.getField(id).get(null); + if (ret instanceof ItemStack) + return (ItemStack)ret; + } catch (Exception e) { + WarpDrive.debugPrint("WarpDriveConfig Call getAEItem failed for " + id); + } + return null; + } + + public static void preInit(Configuration configIn) { + config = configIn; + } + + public static void loadWarpDriveConfig() { + // General + G_SPACE_PROVIDER_ID = config.get("General", "space_provider_id", G_SPACE_PROVIDER_ID, "Space dimension provider ID").getInt(); + G_SPACE_DIMENSION_ID = config.get("General", "space_dimension_id", G_SPACE_DIMENSION_ID, "Space dimension world ID").getInt(); + G_HYPERSPACE_PROVIDER_ID = config.get("General", "hyperspace_provider_id", G_HYPERSPACE_PROVIDER_ID, "Hyperspace dimension provider ID").getInt(); + G_HYPERSPACE_DIMENSION_ID = config.get("General", "hyperspace_dimension_id", G_HYPERSPACE_DIMENSION_ID, "Hyperspace dimension world ID").getInt(); + G_SPACE_WORLDBORDER_BLOCKS = config.get("General", "space_worldborder_blocks", G_SPACE_WORLDBORDER_BLOCKS, "World border applied to hyperspace & space, set to 0 to disable it").getInt(); + G_LUA_SCRIPTS = config.get("General", "lua_scripts", G_LUA_SCRIPTS, "LUA scripts to load when connecting machines: 0 = none, 1 = templates in a subfolder, 2 = ready to roll (templates are still provided)").getInt(); + G_DEBUGMODE = config.get("General", "debug_mode", G_DEBUGMODE, "Detailled logs to help debug the mod, enable it before reporting a bug").getBoolean(false); + G_SCHEMALOCATION = config.get("General", "schematic_location", G_SCHEMALOCATION, "Folder where to save ship schematics").getString(); + G_BLOCKS_PER_TICK = config.get("General", "blocks_per_tick", G_BLOCKS_PER_TICK, "Number of blocks to move per ticks, too high will cause lag spikes on ship jumping or deployment, too low may break the ship wirings").getInt(); + + G_ENABLE_IC2_RECIPES = config.get("General", "enable_ic2_recipes", G_ENABLE_IC2_RECIPES, "Original recipes based on IndustrialCrat2 by Cr0s").getBoolean(true); + G_ENABLE_VANILLA_RECIPES = config.get("General", "enable_vanilla_recipes", G_ENABLE_VANILLA_RECIPES, "Vanilla recipes by DarkholmeTenk").getBoolean(false); + G_ENABLE_TDK_RECIPES = config.get("General", "enable_TDK_recipes", G_ENABLE_TDK_RECIPES, "Mixed recipes for TDK packs by Lem'ADEC (currently requires at least AppliedEnergistics, Extracells, AtomicScience, IndustrialCraft2, GraviSuite and ThermalExpansion").getBoolean(false); + + // TransitionPlane + config.addCustomCategoryComment("TransitionPlane", "Transition planes defines which region in space allows to go to other dimensions, default is overworld with 100k radius.\n" + + "Each plane is square shaped and defined as a list of 7 integers (all measured in blocks, border is the radius from center)"); + String[] transitionNames = { "overworld" }; + transitionNames = config.get("TransitionPlane", "names", transitionNames, "this is the list of transition planes defined hereafter").getStringList(); + int[] defaultPlane = {0, 0, 0, 30000000, 30000000, 0, 0}; // 30000000 is Minecraft limit for SetBlock + G_TRANSITIONPLANES = new TransitionPlane[transitionNames.length]; + int index = 0; + for (String name : transitionNames) { + int[] plane = config.get("TransitionPlane", name, defaultPlane, "dimensionId, dimensionCenterX, dimensionCenterZ, borderSizeX, borderSizeZ, SpaceCenterX, SpaceCenterZ").getIntList(); + if (plane.length != 7) { + WarpDrive.print("Invalid transition plane definition '" + name + "' (exactly 7 integers are expected), using default instead"); + plane = defaultPlane.clone(); + } + TransitionPlane newPlane = new TransitionPlane(plane[0], plane[1], plane[2], plane[3], plane[4], plane[5], plane[6]); + WarpDrive.print("Adding '" + name + "' as " + newPlane.toString()); + G_TRANSITIONPLANES[index] = newPlane; + } + // FIXME: check transition planes aren't overlapping + // FIXME: check transition planes have valid dimension id + + // Warp Core + WC_MAX_ENERGY_VALUE = config.get("WarpCore", "max_energy_value", WC_MAX_ENERGY_VALUE, "Maximum energy storage").getInt(); + WC_ENERGY_PER_BLOCK_MODE1 = config.get("WarpCore", "energy_per_block_mode1", WC_ENERGY_PER_BLOCK_MODE1).getInt(); + WC_ENERGY_PER_DISTANCE_MODE1 = config.get("WarpCore", "energy_per_distance_mode1", WC_ENERGY_PER_DISTANCE_MODE1).getInt(); + WC_ENERGY_PER_DISTANCE_MODE2 = config.get("WarpCore", "energy_per_distance_mode2", WC_ENERGY_PER_DISTANCE_MODE2).getInt(); + WC_ENERGY_PER_BLOCK_MODE2 = config.get("WarpCore", "energy_per_block_mode2", WC_ENERGY_PER_BLOCK_MODE2).getInt(); + WC_ENERGY_PER_ENTITY_TO_SPACE = config.get("WarpCore", "energy_per_entity_to_space", WC_ENERGY_PER_ENTITY_TO_SPACE).getInt(); + WC_MAX_JUMP_DISTANCE = config.get("WarpCore", "max_jump_distance", WC_MAX_JUMP_DISTANCE, "Maximum jump lenght value in blocks").getInt(); + WC_MAX_SHIP_VOLUME_ON_SURFACE = config.get("WarpCore", "max_ship_volume_on_surface", WC_MAX_SHIP_VOLUME_ON_SURFACE, "Maximum ship mass (in blocks) to jump on earth").getInt(); + WC_MIN_SHIP_VOLUME_FOR_HYPERSPACE = config.get("WarpCore", "min_ship_volume_for_hyperspace", WC_MIN_SHIP_VOLUME_FOR_HYPERSPACE, "Minimum ship mass (in blocks) to enter or exit hyperspace without a jumpgate").getInt(); + WC_MAX_SHIP_SIDE = config.get("WarpCore", "max_ship_side", WC_MAX_SHIP_SIDE, "Maximum ship size on each axis in blocks").getInt(); + WC_COLLISION_TOLERANCE_BLOCKS = config.get("WarpCore", "collision_tolerance_blocks", WC_COLLISION_TOLERANCE_BLOCKS, "Tolerance in block in case of collision before causing damages...").getInt(); + WC_COOLDOWN_INTERVAL_SECONDS = config.get("WarpCore", "cooldown_interval_seconds", WC_COOLDOWN_INTERVAL_SECONDS, "Cooldown seconds to wait after jumping").getInt(); + WC_WARMUP_SHORTJUMP_SECONDS = config.get("WarpCore", "warmup_shortjump_seconds", WC_WARMUP_SHORTJUMP_SECONDS, "Short jump means less than 50 blocks").getInt(); + WC_WARMUP_LONGJUMP_SECONDS = config.get("WarpCore", "warmup_longjump_seconds", WC_WARMUP_LONGJUMP_SECONDS, "Long jump means more than 50 blocks").getInt(); + + WC_CORES_REGISTRY_UPDATE_INTERVAL_SECONDS = config.get("WarpCore", "cores_registry_update_interval", WC_CORES_REGISTRY_UPDATE_INTERVAL_SECONDS, "(measured in seconds)").getInt(); + WC_ISOLATION_UPDATE_INTERVAL_SECONDS = config.get("WarpCore", "isolation_update_interval", WC_ISOLATION_UPDATE_INTERVAL_SECONDS, "(measured in seconds)").getInt(); + WC_UNLIMITED_PLAYERNAMES = config.get("WarpCore", "unlimited_playernames", WC_UNLIMITED_PLAYERNAMES, "List of player names which gives unlimited block counts to their ship").getStringList(); + + // Warp Radar + WR_MAX_ENERGY_VALUE = config.get("WarpRadar", "max_energy_value", WR_MAX_ENERGY_VALUE).getInt(); + WR_MAX_ISOLATION_RANGE = config.get("WarpRadar", "max_isolation_range", WR_MAX_ISOLATION_RANGE, "radius around core where isolation blocks count (2 to 8), higher is lagger").getInt(); + WR_MAX_ISOLATION_RANGE = Math.min(8, Math.max(WR_MAX_ISOLATION_RANGE, 2)); + WR_MIN_ISOLATION_BLOCKS = config.get("WarpRadar", "min_isolation_blocks", WR_MIN_ISOLATION_BLOCKS, "number of isolation blocks required to get some isolation (0 to 20)").getInt(); + WR_MIN_ISOLATION_BLOCKS = Math.min(20, Math.max(WR_MIN_ISOLATION_BLOCKS, 0)); + WR_MAX_ISOLATION_BLOCKS = config.get("WarpRadar", "max_isolation_blocks", WR_MAX_ISOLATION_BLOCKS, "number of isolation blocks required to reach maximum effect (5 to 100)").getInt(); + WR_MAX_ISOLATION_BLOCKS = Math.min(100, Math.max(WR_MAX_ISOLATION_BLOCKS, 5)); + WR_MIN_ISOLATION_EFFECT = config.get("WarpRadar", "min_isolation_effect", WR_MIN_ISOLATION_EFFECT, "isolation effect achieved with min number of isolation blocks (0.01 to 0.95)").getDouble(0.12D); + WR_MIN_ISOLATION_EFFECT = Math.min(0.95D, Math.max(WR_MIN_ISOLATION_EFFECT, 0.01D)); + WR_MAX_ISOLATION_EFFECT = config.get("WarpRadar", "max_isolation_effect", WR_MAX_ISOLATION_EFFECT, "isolation effect achieved with max number of isolation blocks (0.01 to 1.00)").getDouble(1.00D); + WR_MAX_ISOLATION_EFFECT = Math.min(1.0D, Math.max(WR_MAX_ISOLATION_EFFECT, 0.01D)); + + // Ship Scanner + SS_MAX_ENERGY_VALUE = config.get("WarpCore", "max_energy_value", SS_MAX_ENERGY_VALUE, "Maximum energy storage").getInt(); + SS_EU_PER_BLOCK_SCAN = config.get("ShipScanner", "energy_per_block_when_scanning", SS_EU_PER_BLOCK_SCAN, "Energy consummed per block when scanning a ship (use -1 to consume everything)").getInt(); + if (SS_EU_PER_BLOCK_SCAN != -1) { + SS_EU_PER_BLOCK_SCAN = Math.min(SS_MAX_ENERGY_VALUE, Math.max(SS_EU_PER_BLOCK_SCAN, 1)); + } + SS_EU_PER_BLOCK_DEPLOY = config.get("ShipScanner", "energy_per_block_when_deploying", SS_EU_PER_BLOCK_DEPLOY, "Energy consummed per block when deploying a ship (use -1 to consume everything)").getInt(); + if (SS_EU_PER_BLOCK_DEPLOY != -1) { + SS_EU_PER_BLOCK_DEPLOY = Math.min(SS_MAX_ENERGY_VALUE, Math.max(SS_EU_PER_BLOCK_DEPLOY, 1)); + } + SS_MAX_DEPLOY_RADIUS_BLOCKS = config.get("ShipScanner", "max_deploy_radius_blocks", SS_MAX_DEPLOY_RADIUS_BLOCKS, "Max distance from ship scanner to ship core, measured in blocks").getInt(); + + // Particle Booster + PB_MAX_ENERGY_VALUE = config.get("ParticleBooster", "max_energy_value", PB_MAX_ENERGY_VALUE).getInt(); + + // Laser Emitter + LE_MAX_BOOSTERS_NUMBER = config.get("LaserEmitter", "max_boosters_number", LE_MAX_BOOSTERS_NUMBER).getInt(); + LE_MAX_LASER_ENERGY = config.get("LaserEmitter", "max_laser_energy", LE_MAX_LASER_ENERGY).getInt(); + LE_EMIT_DELAY_TICKS = config.get("LaserEmitter", "emit_delay_ticks", LE_EMIT_DELAY_TICKS).getInt(); + LE_EMIT_SCAN_DELAY_TICKS = config.get("LaserEmitter", "emit_scan_delay_ticks", LE_EMIT_SCAN_DELAY_TICKS).getInt(); + + // Laser Emitter tweaks + LE_COLLECT_ENERGY_MULTIPLIER = config.get("LaserEmitterTweaks", "collect_energy_multiplier", LE_COLLECT_ENERGY_MULTIPLIER).getDouble(0.6D); + LE_BEAM_LENGTH_PER_ENERGY_DIVIDER = config.get("LaserEmitterTweaks", "beam_length_per_energy_divider", LE_BEAM_LENGTH_PER_ENERGY_DIVIDER).getInt(); + LE_ENTITY_HIT_SET_ON_FIRE_TIME = config.get("LaserEmitterTweaks", "entity_hit_set_on_fire_time", LE_ENTITY_HIT_SET_ON_FIRE_TIME).getInt(); + LE_ENTITY_HIT_DAMAGE_PER_ENERGY_DIVIDER = config.get("LaserEmitterTweaks", "entity_hit_damage_per_energy_divider", LE_ENTITY_HIT_DAMAGE_PER_ENERGY_DIVIDER).getInt(); + LE_ENTITY_HIT_EXPLOSION_LASER_ENERGY = config.get("LaserEmitterTweaks", "entity_hit_explosion_laser_energy", LE_ENTITY_HIT_EXPLOSION_LASER_ENERGY).getInt(); + LE_BLOCK_HIT_CONSUME_ENERGY = config.get("LaserEmitterTweaks", "block_hit_consume_energy", LE_BLOCK_HIT_CONSUME_ENERGY).getInt(); + LE_BLOCK_HIT_CONSUME_ENERGY_PER_BLOCK_RESISTANCE = config.get("LaserEmitterTweaks", "block_hit_consume_energy_per_block_resistance", LE_BLOCK_HIT_CONSUME_ENERGY_PER_BLOCK_RESISTANCE).getInt(); + LE_BLOCK_HIT_CONSUME_ENERGY_PER_DISTANCE = config.get("LaserEmitterTweaks", "block_hit_consume_energy_per_distance", LE_BLOCK_HIT_CONSUME_ENERGY_PER_DISTANCE).getInt(); + + // Mining Laser + ML_MAX_BOOSTERS_NUMBER = config.get("MiningLaser", "max_boosters_number", ML_MAX_BOOSTERS_NUMBER).getInt(); + ML_WARMUP_DELAY_TICKS = config.get("MiningLaser", "warmup_delay_ticks", ML_WARMUP_DELAY_TICKS).getInt(); + ML_SCAN_DELAY_TICKS = config.get("MiningLaser", "scan_delay_ticks", ML_SCAN_DELAY_TICKS).getInt(); + ML_MINE_DELAY_TICKS = config.get("MiningLaser", "mine_delay_ticks", ML_MINE_DELAY_TICKS).getInt(); + ML_EU_PER_LAYER_SPACE = config.get("MiningLaser", "eu_per_layer_space", ML_EU_PER_LAYER_SPACE).getInt(); + ML_EU_PER_LAYER_EARTH = config.get("MiningLaser", "eu_per_layer_earth", ML_EU_PER_LAYER_EARTH).getInt(); + ML_EU_PER_BLOCK_SPACE = config.get("MiningLaser", "eu_per_block_space", ML_EU_PER_BLOCK_SPACE).getInt(); + ML_EU_PER_BLOCK_EARTH = config.get("MiningLaser", "eu_per_block_earth", ML_EU_PER_BLOCK_EARTH).getInt(); + ML_EU_MUL_ORESONLY = config.get("MiningLaser", "oresonly_power_mul", ML_EU_MUL_ORESONLY).getDouble(4.0); + ML_EU_MUL_SILKTOUCH = config.get("MiningLaser", "silktouch_power_mul", ML_EU_MUL_SILKTOUCH).getDouble(2.5); + ML_DEUTERIUM_MUL_SILKTOUCH = config.get("MiningLaser", "silktouch_deuterium_mul", ML_DEUTERIUM_MUL_SILKTOUCH).getDouble(1.0); + ML_EU_MUL_FORTUNE = config.get("MiningLaser", "fortune_power_base", ML_EU_MUL_FORTUNE).getDouble(2.5); + ML_MAX_RADIUS = config.get("MiningLaser", "max_radius", ML_MAX_RADIUS).getInt(); + + // Tree Farm + TF_MAX_SIZE = config.get("TreeFarm", "max_treefarm_size", TF_MAX_SIZE).getInt(); + + // Cloaking device core + CD_MAX_CLOAKING_FIELD_SIDE = config.get("CloakingDevice", "max_cloaking_field_side", CD_MAX_CLOAKING_FIELD_SIDE).getInt(); + CD_ENERGY_PER_BLOCK_TIER1 = config.get("CloakingDevice", "energy_per_block_tier1", CD_ENERGY_PER_BLOCK_TIER1).getInt(); + CD_ENERGY_PER_BLOCK_TIER2 = config.get("CloakingDevice", "energy_per_block_tier2", CD_ENERGY_PER_BLOCK_TIER2).getInt(); + CD_FIELD_REFRESH_INTERVAL_SECONDS = config.get("CloakingDevice", "field_refresh_interval_seconds", CD_FIELD_REFRESH_INTERVAL_SECONDS).getInt(); + CD_COIL_CAPTURE_BLOCKS = config.get("CloakingDevice", "coil_capture_blocks", CD_COIL_CAPTURE_BLOCKS, "Extra blocks covered after the outer coils").getInt(); + + // Air generator + AG_RF_PER_CANISTER = config.get("Air Generator", "energy_per_canister", AG_RF_PER_CANISTER).getInt(); + + // Reactor monitor + RM_MAX_ENERGY = config.get("Reactor Monitor", "max_rm_energy", RM_MAX_ENERGY).getInt(); + RM_EU_PER_HEAT = config.get("Reactor Monitor", "eu_per_heat", RM_EU_PER_HEAT).getDouble(2); + + // Transporter + TR_MAX_ENERGY = config.get("Transporter", "max_energy", TR_MAX_ENERGY).getInt(); + TR_RELATIVE_COORDS = config.get("Transporter", "relative_coords", TR_RELATIVE_COORDS).getBoolean(true); + TR_EU_PER_METRE = config.get("Transporter", "eu_per_ent_per_metre", TR_EU_PER_METRE).getDouble(100); + TR_MAX_BOOST_MUL = config.get("Transporter", "max_boost", TR_MAX_BOOST_MUL).getInt(); + + // Power reactor + PR_MAX_ENERGY = config.get("Reactor", "max_energy", PR_MAX_ENERGY).getInt(); + PR_TICK_TIME = config.get("Reactor", "ticks_per_update", PR_TICK_TIME).getInt(); + PR_MAX_LASERS = config.get("Reactor", "max_lasers", PR_MAX_LASERS).getInt(); + + // Power store + PS_MAX_ENERGY = config.get("PowerStore", "max_energy", PS_MAX_ENERGY).getInt(); + + // Laser lift + LL_MAX_ENERGY = config.get("LaserLift", "max_energy", LL_MAX_ENERGY).getInt(); + LL_LIFT_ENERGY = config.get("LaserLift", "lift_energy", LL_LIFT_ENERGY, "Energy consummed per entity moved").getInt(); + LL_TICK_RATE = config.get("LaserLift", "tick_rate", LL_TICK_RATE).getInt(); + } + + public static void load() { + CommonWorldGenOres = new ArrayList(30); + CommonWorldGenOres.add(new int[] {Block.oreIron.blockID, 0}); + CommonWorldGenOres.add(new int[] {Block.oreGold.blockID, 0}); + CommonWorldGenOres.add(new int[] {Block.oreCoal.blockID, 0}); + CommonWorldGenOres.add(new int[] {Block.oreEmerald.blockID, 0}); + CommonWorldGenOres.add(new int[] {Block.oreLapis.blockID, 0}); + CommonWorldGenOres.add(new int[] {Block.oreRedstoneGlowing.blockID, 0}); + CommonWorldGenOres.add(new int[] {Block.oreRedstone.blockID, 0}); + + forceFieldBlocks = new ArrayList(); + + SpaceHelmets = new HashSet(); + Jetpacks = new HashSet(); + MinerOres = new HashSet(); + MinerLogs = new HashSet(); + MinerLeaves = new HashSet(); + scannerIgnoreBlocks = new HashSet(); + config.load(); + coreID = config.getBlock("core", 500).getInt(); + controllerID = config.getBlock("controller", 501).getInt(); + radarID = config.getBlock("radar", 502).getInt(); + isolationID = config.getBlock("isolation", 503).getInt(); + airID = config.getBlock("air", 504).getInt(); + airgenID = config.getBlock("airgen", 505).getInt(); + gasID = config.getBlock("gas", 506).getInt(); + laserID = config.getBlock("laser", 507).getInt(); + miningLaserID = config.getBlock("mininglaser", 508).getInt(); + particleBoosterID = config.getBlock("particlebooster", 509).getInt(); + liftID = config.getBlock("lift", 510).getInt(); + laserCamID = config.getBlock("lasercam", 512).getInt(); + camID = config.getBlock("camera", 513).getInt(); + monitorID = config.getBlock("monitor", 514).getInt(); + iridiumBlockID = config.getBlock("iridium", 515).getInt(); + shipScannerID = config.getBlock("shipscanner", 516).getInt(); + cloakCoreID = config.getBlock("cloakcore", 517).getInt(); + cloakCoilID = config.getBlock("cloakcoil", 518).getInt(); + laserTreeFarmID = config.getBlock("lasertreefarm", 519).getInt(); + transporterID = config.getBlock("transporter", 520).getInt(); + transportBeaconID = config.getBlock("transportBeacon", 521).getInt(); + reactorMonitorID = config.getBlock("reactorMonitor", 522).getInt(); + powerLaserID = config.getBlock("powerLaser", 523).getInt(); + powerReactorID = config.getBlock("powerReactor", 524).getInt(); + powerStoreID = config.getBlock("powerStore", 525).getInt(); + chunkLoaderID = config.getBlock("chunkLoader", 526).getInt(); + decorativeID = config.getBlock("decorative",527).getInt(); + + reactorLaserFocusID = config.getItem("reactorLaserFocus", 8700).getInt(); + componentID = config.getItem("component", 8701).getInt(); + helmetID = config.getItem("helmet", 8702).getInt(); + chestID = config.getItem("chest", 8703).getInt(); + pantsID = config.getItem("pants", 8704).getInt(); + bootsID = config.getItem("boots", 8705).getInt(); + airCanisterID = config.getItem("airCanisterFull", 8706).getInt(); + upgradeID = config.getItem("upgrade", 8707).getInt(); + + isForgeMultipartLoaded = Loader.isModLoaded("ForgeMultipart"); + if (isForgeMultipartLoaded) { + loadForgeMultipart(); + } + + isICLoaded = Loader.isModLoaded("IC2"); + if (isICLoaded) + loadIC2(); + + isCCLoaded = Loader.isModLoaded("ComputerCraft"); + if (isCCLoaded) + loadCC(); + + isGregLoaded = Loader.isModLoaded("gregtech_addon"); + if (isGregLoaded) + loadGT(); + + isAppliedEnergisticsLoaded = Loader.isModLoaded("AppliedEnergistics"); + if (isAppliedEnergisticsLoaded) + loadAppliedEnergistics(); + + isAEExtraLoaded = Loader.isModLoaded("extracells"); + if (isAEExtraLoaded) + loadAEExtra(); + + isAdvSolPanelLoaded = Loader.isModLoaded("AdvancedSolarPanel"); + if (isAdvSolPanelLoaded) + loadASP(); + + isAtomicScienceLoaded = Loader.isModLoaded("ResonantInduction|Atomic"); + if (isAtomicScienceLoaded) + loadAtomicScience(); + + isICBMLoaded = Loader.isModLoaded("ICBM|Explosion"); + if (isICBMLoaded) + loadICBM(); + + isMFFSLoaded = Loader.isModLoaded("MFFS"); + if (isMFFSLoaded) + loadMFFS(); + + isGraviSuiteLoaded = Loader.isModLoaded("GraviSuite"); + if (isGraviSuiteLoaded) + loadGraviSuite(); + + isUndergroundBiomesLoaded = Loader.isModLoaded("UndergroundBiomes"); + if (isUndergroundBiomesLoaded) + loadUndergroundBiomes(); + + isNetherOresLoaded = Loader.isModLoaded("NetherOres"); + if (isNetherOresLoaded) + loadNetherOres(); + + isThermalExpansionLoaded = Loader.isModLoaded("ThermalExpansion"); + if (isThermalExpansionLoaded) + loadThermalExpansion(); + + isMetallurgyLoaded = Loader.isModLoaded("Metallurgy3Core"); + if (isMetallurgyLoaded) { + loadMetallurgy(); + } + + isAdvancedRepulsionSystemsLoaded = Loader.isModLoaded("AdvancedRepulsionSystems"); + if (isAdvancedRepulsionSystemsLoaded) { + loadAdvancedRepulsionSystems(); + } + + isMagicalCropsLoaded = Loader.isModLoaded("MagicalCrops"); +// + MinerOres.add(iridiumBlockID); + MinerOres.add(Block.oreCoal.blockID); + MinerOres.add(Block.oreNetherQuartz.blockID); + MinerOres.add(Block.obsidian.blockID); + MinerOres.add(Block.web.blockID); + MinerOres.add(Block.fence.blockID); + MinerOres.add(Block.torchWood.blockID); + MinerOres.add(Block.glowStone.blockID); + MinerOres.add(Block.blockRedstone.blockID); + + // Ignore WarpDrive blocks (which potentially will be duplicated by cheaters using ship scan/deploy) + scannerIgnoreBlocks.add(coreID); + scannerIgnoreBlocks.add(controllerID); + scannerIgnoreBlocks.add(iridiumBlockID); + + if (isICLoaded) { + scannerIgnoreBlocks.add(Items.getItem("mfsUnit").itemID); + scannerIgnoreBlocks.add(Items.getItem("mfeUnit").itemID); + scannerIgnoreBlocks.add(Items.getItem("cesuUnit").itemID); + scannerIgnoreBlocks.add(Items.getItem("batBox").itemID); + } + if (isICBMLoaded) { + scannerIgnoreBlocks.add(ICBM_Explosive); + } + if (isCCLoaded) { + scannerIgnoreBlocks.add(CC_Computer); + scannerIgnoreBlocks.add(CCT_Turtle); + scannerIgnoreBlocks.add(CCT_Upgraded); + scannerIgnoreBlocks.add(CCT_Advanced); + } + // Do not deploy ores and valuables + for (int[] t : CommonWorldGenOres) {// each element of this set is pair [id, meta] + scannerIgnoreBlocks.add(t[0]); // we adding ID only + } + + loadWarpDriveConfig(); + config.save(); + } + + public static void postInit() { + LoadOreDict(); + } + + private static void LoadOreDict() { + String[] oreNames = OreDictionary.getOreNames(); + for(String oreName: oreNames) { + String lowerOreName = oreName.toLowerCase(); + if (oreName.substring(0,3).equals("ore")) { + ArrayList item = OreDictionary.getOres(oreName); + for(ItemStack i: item) { + MinerOres.add(i.itemID); + WarpDrive.debugPrint("WD: Added ore ID: "+i.itemID); + } + } + if (lowerOreName.contains("log")) { + ArrayList item = OreDictionary.getOres(oreName); + for(ItemStack i: item) { + MinerLogs.add(i.itemID); + WarpDrive.debugPrint("WD: Added log ID: "+i.itemID); + } + } + if (lowerOreName.contains("leave") || lowerOreName.contains("leaf")) { + ArrayList item = OreDictionary.getOres(oreName); + for(ItemStack i: item) { + MinerLeaves.add(i.itemID); + WarpDrive.debugPrint("WD: Added leaf ID: "+i.itemID); + } + } + } + } + + private static void loadForgeMultipart() { + try { + Class forgeMultipart_helper = Class.forName("codechicken.multipart.MultipartHelper"); + forgeMultipart_helper_createTileFromNBT = forgeMultipart_helper.getDeclaredMethod("createTileFromNBT", World.class, NBTTagCompound.class); + forgeMultipart_helper_sendDescPacket = forgeMultipart_helper.getDeclaredMethod("sendDescPacket", World.class, TileEntity.class); + Class forgeMultipart_tileMultipart = Class.forName("codechicken.multipart.TileMultipart"); + forgeMultipart_tileMultipart_onChunkLoad = forgeMultipart_tileMultipart.getDeclaredMethod("onChunkLoad"); + } catch (Exception e) { + isForgeMultipartLoaded = false; + WarpDrive.debugPrint("WarpDriveConfig Error loading ForgeMultipart classes"); + e.printStackTrace(); + } + } + + private static void loadIC2() + { + ASP = Items.getItem("solarPanel").itemID; + SpaceHelmets.add(Items.getItem("hazmatHelmet").itemID); + SpaceHelmets.add(Items.getItem("quantumHelmet").itemID); + Jetpacks.add(Items.getItem("jetpack").itemID); + Jetpacks.add(Items.getItem("electricJetpack").itemID); + IC2_Air = new int[] {Items.getItem("airCell").itemID, Items.getItem("airCell").getItemDamage()}; + IC2_Empty = new int[] {Items.getItem("cell").itemID, Items.getItem("cell").getItemDamage()}; + ItemStack rubberWood = Items.getItem("rubberWood"); + IC2_Resin = Items.getItem("resin"); + if(rubberWood != null) { + IC2_RubberWood = rubberWood.itemID; + } + ItemStack ore = Items.getItem("uraniumOre"); + if (ore != null) CommonWorldGenOres.add(new int[] {ore.itemID, ore.getItemDamage()}); + ore = Items.getItem("copperOre"); + if (ore != null) CommonWorldGenOres.add(new int[] {ore.itemID, ore.getItemDamage()}); + ore = Items.getItem("tinOre"); + if (ore != null) CommonWorldGenOres.add(new int[] {ore.itemID, ore.getItemDamage()}); + ore = Items.getItem("leadOre"); + if (ore != null) CommonWorldGenOres.add(new int[] {ore.itemID, ore.getItemDamage()}); + + MinerOres.add(Items.getItem("rubberWood").itemID); + IC2_fluidCell = Items.getItem("FluidCell").getItem(); + } + + private static void loadCC() + { + try + { + Class z = Class.forName("dan200.computercraft.ComputerCraft"); + CC_Computer = z.getField("computerBlockID").getInt(null); + CC_peripheral = z.getField("peripheralBlockID").getInt(null); + CC_Floppy = z.getField("diskItemID").getInt(null); + CCT_Turtle = z.getField("turtleBlockID").getInt(null); + CCT_Upgraded = z.getField("turtleUpgradedBlockID").getInt(null); + CCT_Advanced = z.getField("turtleAdvancedBlockID").getInt(null); + } + catch (Exception e) + { + WarpDrive.debugPrint("WarpDriveConfig Error loading ComputerCraft classes"); + e.printStackTrace(); + } + } + + private static void loadGT() + { + try + { + Class z = Class.forName("gregtechmod.GT_Mod"); + int[] t = (int[])z.getField("sBlockIDs").get(null); + GT_Machine = t[1]; + GT_Ores = t[2]; // meta 1-15 = ores + GT_Granite = t[5]; // 0 - black, 1 - black cobble, 8 - red, 9 - red cobble + MinerOres.add(GT_Ores); + //MinerOres.add(GT_Granite); + } + catch (Exception e) + { + WarpDrive.debugPrint("WarpDriveConfig Error loading GT classes"); + e.printStackTrace(); + isGregLoaded = false; + } + } + + private static void loadAppliedEnergistics() + { + try + { + AEBlocks = Class.forName("appeng.api.Blocks"); + AEMaterials = Class.forName("appeng.api.Materials"); + AEItems = Class.forName("appeng.api.Items"); + MinerOres.add(((ItemStack)AEBlocks.getField("blkQuartzOre").get(null)).itemID); + } + catch (Exception e) + { + WarpDrive.debugPrint("WarpDriveConfig Error loading AppliedEnergistics classes"); + e.printStackTrace(); + isAppliedEnergisticsLoaded = false; + } + } + + private static void loadAEExtra() + { + try + { + Class z = Class.forName("extracells.ItemEnum"); + Object z1 = z.getEnumConstants()[6]; + AEExtra_fluidDrive = (Item)z1.getClass().getDeclaredMethod("getItemInstance").invoke(z1); + z = Class.forName("extracells.BlockEnum"); + z1 = z.getEnumConstants()[9]; + AEExtra_certusQuartzTank = (Block)z1.getClass().getDeclaredMethod("getBlockInstance").invoke(z1); + } + catch (Exception e) + { + WarpDrive.debugPrint("WarpDriveConfig Error loading AEExtra classes"); + e.printStackTrace(); + isAEExtraLoaded = false; + } + } + + private static void loadASP() + { + try + { + Class z = Class.forName("advsolar.common.AdvancedSolarPanel"); + ASP = z.getField("idAdv").getInt(null); + SpaceHelmets.add(((Item)z.getField("advancedSolarHelmet").get(null)).itemID); + SpaceHelmets.add(((Item)z.getField("hybridSolarHelmet").get(null)).itemID); + SpaceHelmets.add(((Item)z.getField("ultimateSolarHelmet").get(null)).itemID); + } + catch (Exception e) + { + WarpDrive.debugPrint("WarpDriveConfig Error loading ASP classes"); + e.printStackTrace(); + isAdvSolPanelLoaded = false; + } + } + + private static void loadAtomicScience() { + try { + Class z = Class.forName("resonantinduction.atomic.Atomic"); + CommonWorldGenOres.add(new int[] {((Block)z.getField("blockUraniumOre").get(null)).blockID, 0}); + AS_Turbine = ((Block)z.getField("blockElectricTurbine").get(null)).blockID; + AS_deuteriumCell = ((Item)z.getField("itemDeuteriumCell").get(null)).itemID; + } catch (Exception e) { + WarpDrive.debugPrint("WarpDriveConfig Error loading AS classes"); + isAtomicScienceLoaded = false; + } + } + + private static void loadICBM() { + try { + Class z = Class.forName("icbm.core.ICBMCore"); + CommonWorldGenOres.add(new int[] {((Block)z.getField("blockSulfurOre").get(null)).blockID, 0}); + z = Class.forName("icbm.explosion.ICBMExplosion"); + ICBM_Machine = ((Block)z.getField("blockMachine").get(null)).blockID; + ICBM_Missile = ((Item)z.getField("itemMissile").get(null)).itemID; + ICBM_Explosive = ((Block)z.getField("blockExplosive").get(null)).blockID; + } catch (Exception e) { + WarpDrive.debugPrint("WarpDriveConfig Error loading ICBM classes"); + e.printStackTrace(); + isICBMLoaded = false; + } + } + + private static void loadMFFS() { + try { + Class z = Class.forName("mffs.ModularForceFieldSystem"); + int blockId = ((Block)z.getField("blockForceField").get(null)).blockID; + forceFieldBlocks.add(blockId); + } catch (Exception e) { + WarpDrive.debugPrint("WarpDriveConfig Error loading MFFS classes"); + e.printStackTrace(); + isICBMLoaded = false; + } + } + + private static void loadGraviSuite() { + try { + Class z = Class.forName("gravisuite.GraviSuite"); + if (z.getField("ultimateSolarHelmet").get(null) != null) + SpaceHelmets.add(((Item)z.getField("ultimateSolarHelmet").get(null)).itemID); + Jetpacks.add(z.getField("advJetpackID").getInt(null) + 256); + Jetpacks.add(z.getField("graviChestPlateID").getInt(null) + 256); + GS_ultimateLappack = z.getField("ultimateLappackID").getInt(null) + 256; + } catch (Exception e) { + WarpDrive.debugPrint("WarpDriveConfig Error loading GS classes"); + e.printStackTrace(); + isGraviSuiteLoaded = false; + } + } + + private static void loadUndergroundBiomes() { + try { + Class z = Class.forName("exterminatorJeff.undergroundBiomes.common.UndergroundBiomes"); + UB_igneousStone = ((Block)z.getField("igneousStone").get(null)).blockID; + UB_igneousCobblestone = ((Block)z.getField("igneousCobblestone").get(null)).blockID; + UB_metamorphicStone = ((Block)z.getField("metamorphicStone").get(null)).blockID; + UB_metamorphicCobblestone = ((Block)z.getField("metamorphicCobblestone").get(null)).blockID; + UB_sedimentaryStone = ((Block)z.getField("sedimentaryStone").get(null)).blockID; + WarpDrive.debugPrint("WarpDriveConfig found UndergroundBiomes blocks " + UB_igneousStone + ", " + UB_igneousCobblestone + ", " + UB_metamorphicStone + ", " + UB_metamorphicCobblestone + ", " + UB_sedimentaryStone); + } catch (Exception e) { + WarpDrive.debugPrint("WarpDriveConfig Error loading UndergroundBiomes classes"); + e.printStackTrace(); + isUndergroundBiomesLoaded = false; + } + } + + private static void loadNetherOres() { + try { + NetherOres_count = 21; // FIXME: extract it properly +/* Class z = Class.forName("powercrystals.netherores.ores.Ores"); + NO_netherOresCount = z.getField("values").get(null).length; + WarpDrive.debugPrint("WarpDriveConfig found NetherOres count " + NO_netherOresCount); + + z = Class.forName("powercrystals.netherores.NetherOresCore"); + for (int i = 0; i < (NO_netherOresCount + 15) / 16; i++) + { + NO_netherOresBlock[i] = ((Block[])z.getDeclaredField("blockNetherOres").get(null))[i].blockID; + WarpDrive.debugPrint("WarpDriveConfig found NetherOres blockId " + NO_netherOresBlock[i]); + }*/ + NetherOres_block = new int[(NetherOres_count + 15) / 16]; + NetherOres_block[0] = 1440; + NetherOres_block[1] = 1442; + WarpDrive.debugPrint("WarpDriveConfig found " + NetherOres_count + " NetherOres"); + } + catch (Exception e) + { + WarpDrive.print("WarpDriveConfig Error loading NetherOres classes"); + e.printStackTrace(); + isNetherOresLoaded = false; + } + } + + private static void loadThermalExpansion() { + try { +// TEEnergyCell = Class.forName("thermalexpansion.block.energycell.BlockEnergyCell"); +// TEFluids = Class.forName("thermalexpansion.fluid.TEFluids"); + } catch (Exception e) { + WarpDrive.print("WarpDriveConfig Error loading ThermalExpansion classes"); + e.printStackTrace(); + isThermalExpansionLoaded = false; + } + } + + private static void loadMetallurgy() { + try { + Metallurgy_overworldOresBlock = new int[][] { { 905, 7}, { 905, 8}, { 905, 9}, { 905, 10}, { 905, 11}, { 905, 12}, { 906, 0}, { 906, 1}, { 906, 2}, { 906, 4}, { 906, 5}, { 906, 6}, { 906, 7}, { 906, 8}, { 906, 11}, { 906, 13}, { 906, 14} }; + Metallurgy_netherOresBlock = new int[][] { { 903, 0}, { 903, 1}, { 903, 2}, { 903, 3}, { 903, 4}, { 903, 5}, { 903, 6}, { 903, 7}, { 903, 8}, { 903, 9} }; + Metallurgy_endOresBlock = new int[][] { { 900, 5}, { 900, 6} }; + } catch (Exception e) { + WarpDrive.print("WarpDriveConfig Error loading Metallurgy classes"); + e.printStackTrace(); + isMetallurgyLoaded = false; + } + } + + private static void loadAdvancedRepulsionSystems() { + try { + Class z = Class.forName("mods.immibis.ars.ARSMod"); + int fieldBlockId = ((Block)z.getField("MFFSFieldblock").get(null)).blockID; + forceFieldBlocks.add(fieldBlockId); + } catch (Exception e) { + WarpDrive.print("WarpDriveConfig Error loading AdvancedRepulsionSystems classes"); + e.printStackTrace(); + isAdvancedRepulsionSystemsLoaded = false; + } + } + + public static int[] getDefaultSurfaceBlock(Random random, boolean corrupted, boolean isMoon) { + if (isMoon) { + if (isGregLoaded && (random.nextInt(100) == 1)) { + if (random.nextBoolean()) { + return new int[] {GT_Granite, (corrupted && random.nextBoolean())?1:0}; + } else { + return new int[] {GT_Granite, (corrupted && random.nextBoolean())?9:8}; + } + } else if (random.nextInt(5) == 1) { + return new int[] {Block.netherrack.blockID, 0}; + } else if (random.nextInt(15) == 1) { + return new int[] {Block.whiteStone.blockID, 0}; + } + } else { + if (isGregLoaded && (random.nextInt(25) == 1)) { + if (random.nextBoolean()) { + return new int[] {GT_Granite, (corrupted && random.nextBoolean())?1:0}; + } else { + return new int[] {GT_Granite, (corrupted && random.nextBoolean())?9:8}; + } + } else if (random.nextInt(6) == 1) { + return new int[] {Block.netherrack.blockID, 0}; + } else if (random.nextInt(50) == 1) { + return new int[] {Block.whiteStone.blockID, 0}; + } + } + if (corrupted && random.nextBoolean()) { + if (isUndergroundBiomesLoaded) { + int rnd = random.nextInt(8 + 8 + 2); + if (rnd < 8) { + return new int[] {UB_igneousCobblestone, rnd}; + } else if (rnd < (8 + 8)) { + return new int[] {UB_metamorphicCobblestone, rnd - 8}; + } + } + return new int[] {Block.cobblestone.blockID, 0}; + } + if (isUndergroundBiomesLoaded) { + int rnd = random.nextInt(8 + 8 + 8 + 3); + if (rnd < 8) { + return new int[] {UB_igneousStone, rnd}; + } else if (rnd < (8 + 8)) { + return new int[] {UB_metamorphicStone, rnd - 8}; + } + else if (rnd < (8 + 8 + 8)) { + if (rnd == 8 + 8 + 8) { + return new int[] {205, 0}; // emasher Limestone + } else { + return new int[] {UB_sedimentaryStone, rnd - 8 - 8}; + } + } + } + return new int[] {Block.stone.blockID, 0}; + } + + public static int[] getRandomSurfaceBlock(Random random, int blockID, int blockMeta, boolean bedrock) { + if (bedrock && (random.nextInt(1000) == 1)) { + return new int[] {Block.bedrock.blockID, 0}; + } else if (blockID == GT_Granite) { + if ((blockMeta == 0) || (blockMeta == 1)) { + int[] t; + t = getRandomOverworldBlock(random, blockID, blockMeta); + if (t[0] == blockID) + t = getRandomOverworldBlock(random, blockID, blockMeta); + if (t[0] == blockID) + t = getRandomEndBlock(random, blockID, blockMeta); + return t; + } else if ((blockMeta == 8) || (blockMeta == 9)) { + int[] t; + t = getRandomOverworldBlock(random, blockID, blockMeta); + if (t[0] == blockID) + t = getRandomEndBlock(random, blockID, blockMeta); + if (t[0] == blockID) + t = getRandomOverworldBlock(random, blockID, blockMeta); + return t; + } + } else if (blockID == Block.whiteStone.blockID) { + return getRandomEndBlock(random, blockID, blockMeta); + } else if (blockID == Block.netherrack.blockID) { + return getRandomNetherBlock(random, blockID, blockMeta); + } + return getRandomOverworldBlock(random, blockID, blockMeta); + } + + public static int[] getRandomOverworldBlock(Random random, int blockID, int blockMeta) + { + if (random.nextInt(25) == 5) { + return CommonWorldGenOres.get(random.nextInt(CommonWorldGenOres.size())); + } else if (isMetallurgyLoaded && (random.nextInt(25) == 1)) { + return Metallurgy_overworldOresBlock[random.nextInt(Metallurgy_overworldOresBlock.length)]; + } else if (isAppliedEnergisticsLoaded && random.nextInt(750) == 1) { + return new int[] {getAEBlock("blkQuartzOre").itemID, getAEBlock("blkQuartzOre").getItemDamage()}; + } else if (random.nextInt(250) == 1) { + return new int[] {Block.oreDiamond.blockID, 0}; + } else if (!isNetherOresLoaded && (random.nextInt(10000) == 42)) { + return new int[] {iridiumBlockID, 0}; + } else if (!isMagicalCropsLoaded && (random.nextInt(100) == 56)) { + return new int[] {3108, 0}; // Essence ore + } else if (isGregLoaded) { + if (random.nextInt(50) == 1) + return new int[] {GT_Ores, 5}; //Bauxite S /* Stone/Iron/Diamod pick | +S = Silktouch recommended */ + else if (random.nextInt(50) == 1) + return new int[] {GT_Ores, 1}; //Galena S + else if (random.nextInt(100) == 1) + return new int[] {GT_Ores, 8}; //Sphalerite S+S + else if (random.nextInt(250) == 1) + return new int[] {GT_Ores, 13}; //Tetrahedrite I + else if (random.nextInt(250) == 1) + return new int[] {GT_Ores, 14}; //Cassiterite I + else if (random.nextInt(250) == 1) + return new int[] {GT_Ores, 15}; //Nickel I + else if (random.nextInt(500) == 1) + return new int[] {GT_Ores, 3}; //Ruby I+S + else if (random.nextInt(500) == 1) + return new int[] {GT_Ores, 4}; //Sapphire I+S + else if (random.nextInt(2000) == 1) + return new int[] {GT_Ores, 2}; //Iridium D+S + } + return new int[] {blockID, blockMeta}; + } + + public static int[] getRandomNetherBlock(Random random, int blockID, int blockMeta) { + if (isICLoaded && (!isNetherOresLoaded) && (random.nextInt(10000) == 42)) { + return new int[] {iridiumBlockID, 0}; + } else if (isNetherOresLoaded && (random.nextInt(25) == 1)) { + int rnd = random.nextInt(NetherOres_count); + return new int[] {NetherOres_block[rnd / 16], rnd % 16}; + } else if (isMetallurgyLoaded && (random.nextInt(25) == 1)) { + return Metallurgy_netherOresBlock[random.nextInt(Metallurgy_netherOresBlock.length)]; + } else if (random.nextInt(25) == 1) { + return new int[] {Block.oreNetherQuartz.blockID, 0}; + } else if (!isMagicalCropsLoaded && (random.nextInt(100) == 56)) { + return new int[] {3109, 0}; // Nether essence ore + } else if (isGregLoaded) { + if (random.nextInt(100) == 1) + return new int[] {GT_Ores, 6}; //Pyrite S+S + else if (random.nextInt(100) == 1) + return new int[] {GT_Ores, 8}; //Sphalerite S+S + else if (random.nextInt(500) == 1) + return new int[] {GT_Ores, 7}; //Cinnabar I+S + } else if ((!isNetherOresLoaded) && (random.nextInt(100) == 13)) + return CommonWorldGenOres.get(random.nextInt(CommonWorldGenOres.size())); + return new int[] {blockID, blockMeta}; + } + + public static int[] getRandomEndBlock(Random random, int blockID, int blockMeta) + { + if (isICLoaded && random.nextInt(10000) == 42) { + return new int[] { iridiumBlockID, 0 }; + } else if (isGregLoaded) { + if (random.nextInt(250) == 1) + return new int[] {GT_Ores, 9}; //Tungstate I + else if (random.nextInt(500) == 1) + return new int[] {GT_Ores, 12}; //Sodalite I+S + else if (random.nextInt(500) == 1) + return new int[] {GT_Ores, 10}; //Cooperite=Sheldonite D + else if (random.nextInt(1000) == 1) + return new int[] {GT_Ores, 11}; //Olivine D+S + } else if (isMetallurgyLoaded && (random.nextInt(25) == 1)) { + return Metallurgy_endOresBlock[random.nextInt(Metallurgy_endOresBlock.length)]; + } else if (random.nextInt(200) == 13) { + return CommonWorldGenOres.get(random.nextInt(CommonWorldGenOres.size())); + } + return new int[] {blockID, blockMeta}; + } + + public static boolean isAirBlock(World worldObj, int id, int x, int y, int z) { + return id == 0 || Block.blocksList[id] == null || Block.blocksList[id].isAirBlock(worldObj, x, y, z); + } +} diff --git a/src/cr0s/WarpDrive/block/BlockDecorative.java b/src/cr0s/WarpDrive/block/BlockDecorative.java new file mode 100644 index 00000000..6ee13676 --- /dev/null +++ b/src/cr0s/WarpDrive/block/BlockDecorative.java @@ -0,0 +1,98 @@ +package cr0s.WarpDrive.block; + +import java.util.List; + +import cpw.mods.fml.common.registry.GameRegistry; + +import cr0s.WarpDrive.WarpDrive; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Icon; +import net.minecraftforge.oredict.ShapedOreRecipe; + +public class BlockDecorative extends Block +{ + public static enum decorativeTypes { Plain , Energized , Network }; + private ItemStack[] isCache = new ItemStack[decorativeTypes.values().length]; + private Icon[] iconBuffer = new Icon[decorativeTypes.values().length]; + + public BlockDecorative(int par1) + { + super(par1, Material.iron); + setHardness(0.5f); + setStepSound(Block.soundMetalFootstep); + setCreativeTab(WarpDrive.warpdriveTab); + } + + public boolean isValidDamage(int damage) + { + return damage >= 0 && damage < decorativeTypes.values().length; + } + + @Override + public void getSubBlocks(int par1, CreativeTabs par2CreativeTabs, List par3List) + { + for(decorativeTypes val: decorativeTypes.values()) + par3List.add(new ItemStack(par1, 1, val.ordinal())); + } + + @Override + public void registerIcons(IconRegister ir) + { + for(decorativeTypes val: decorativeTypes.values()) + iconBuffer[val.ordinal()] = ir.registerIcon("warpdrive:decorative" + val.toString()); + } + + @Override + public Icon getIcon(int side, int damage) + { + if(isValidDamage(damage)) + return iconBuffer[damage]; + return iconBuffer[0]; + } + + @Override + public int damageDropped(int damage) + { + return damage; + } + + public ItemStack getIS(int damage) + { + if(!isValidDamage(damage)) + return null; + + if(isCache[damage] == null) + isCache[damage] = getISNoCache(damage); + return isCache[damage]; + } + + public ItemStack getISNoCache(int damage, int amount) + { + if(!isValidDamage(damage)) + return null; + + return new ItemStack(WarpDrive.decorativeBlock,amount,damage); + } + + public ItemStack getISNoCache(int damage) + { + return getISNoCache(damage,1); + } + + public void initRecipes() + { + GameRegistry.addRecipe(new ShapedOreRecipe(getISNoCache(0,8),false, "sss","scs","sss", + 's', Block.stone, + 'c', WarpDrive.componentItem.getIS(0))); + + GameRegistry.addRecipe(new ShapedOreRecipe(getISNoCache(2,8),false, "sss","scs","sss", + 's', getIS(0), + 'c', WarpDrive.componentItem.getIS(5))); + } + +} diff --git a/src/cr0s/WarpDrive/block/BlockTransportBeacon.java b/src/cr0s/WarpDrive/block/BlockTransportBeacon.java new file mode 100644 index 00000000..468c9738 --- /dev/null +++ b/src/cr0s/WarpDrive/block/BlockTransportBeacon.java @@ -0,0 +1,57 @@ +package cr0s.WarpDrive.block; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import cr0s.WarpDrive.WarpDrive; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; + +public class BlockTransportBeacon extends Block { + public BlockTransportBeacon(int par1) { + super(par1, Material.iron); + setHardness(0.5F); + setStepSound(Block.soundMetalFootstep); + setCreativeTab(WarpDrive.warpdriveTab); + setUnlocalizedName("warpdrive.blocks.transportBeacon"); + } + + @Override + public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4) { + return null; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IconRegister par1IconRegister) { + this.blockIcon = par1IconRegister.registerIcon("warpdrive:transportBeacon"); + } + + @Override + public boolean isOpaqueCube() { + return false; + } + + @Override + public boolean renderAsNormalBlock() { + return false; + } + + @Override + public int getRenderType() { + return 2; + } + + @Override + public MovingObjectPosition collisionRayTrace(World par1World, int par2, int par3, int par4, Vec3 par5Vec3, Vec3 par6Vec3) { + float f = 0.065F; + this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.6F, 0.5F + f); + + return super.collisionRayTrace(par1World, par2, par3, par4, par5Vec3, par6Vec3); + } +} diff --git a/src/cr0s/WarpDrive/block/ItemBlockDecorative.java b/src/cr0s/WarpDrive/block/ItemBlockDecorative.java new file mode 100644 index 00000000..45c1c4c8 --- /dev/null +++ b/src/cr0s/WarpDrive/block/ItemBlockDecorative.java @@ -0,0 +1,40 @@ +package cr0s.WarpDrive.block; + +import java.util.List; + +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; + +public class ItemBlockDecorative extends ItemBlock +{ + + public ItemBlockDecorative(int par1) + { + super(par1); + setHasSubtypes(true); + setUnlocalizedName("warpdrive.block.decorative"); + } + + @Override + public int getMetadata (int damage) + { + return damage; + } + + @Override + public void getSubItems(int par1, CreativeTabs par2CreativeTabs, List par3List) + { + for(int i = 0; i < BlockDecorative.decorativeTypes.values().length;i++) + par3List.add(new ItemStack(par1,1,i)); + } + + @Override + public String getUnlocalizedName(ItemStack itemstack) + { + if(itemstack == null) + return getUnlocalizedName(); + return "tile.warpdrive.decorative." + BlockDecorative.decorativeTypes.values()[itemstack.getItemDamage()].toString(); + } + +} diff --git a/src/cr0s/WarpDrive/command/DebugCommand.java b/src/cr0s/WarpDrive/command/DebugCommand.java new file mode 100644 index 00000000..de21f75e --- /dev/null +++ b/src/cr0s/WarpDrive/command/DebugCommand.java @@ -0,0 +1,151 @@ +package cr0s.WarpDrive.command; + +import cpw.mods.fml.common.FMLCommonHandler; +import cr0s.WarpDrive.WarpDriveConfig; +import net.minecraft.command.CommandBase; +import net.minecraft.command.ICommandSender; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.DimensionManager; + +/* +* /wdebug +*/ + +public class DebugCommand extends CommandBase +{ + @Override + public String getCommandName() + { + return "wdebug"; + } + + @Override + public int getRequiredPermissionLevel() + { + return 2; + } + + @Override + public String getCommandUsage(ICommandSender par1ICommandSender) + { + return "/" + getCommandName() + " ...\n" + + "dimension: 0/world, 2/space, 3/hyperspace\n" + + "coordinates: x,y,z\n" + + "action: I(nvalidate), V(alidate), A(set air), R(emoveEntity), P(setBlock), S(etEntity)"; + } + + @Override + public void processCommand(ICommandSender icommandsender, String[] params) + { + EntityPlayerMP player = (EntityPlayerMP)icommandsender; + if(params.length > 6 ) + { + int dim, x, y, z, blockId, metadata; + String actions; + try + { + String par = params[0].toLowerCase(); + if (par.equals("world") || par.equals("overworld") || par.equals("0")) + { + dim = 0; + } + else if (par.equals("nether") || par.equals("thenether") || par.equals("-1")) + { + dim = -1; + } + else if (par.equals("s") || par.equals("space")) + { + dim = WarpDriveConfig.G_SPACE_DIMENSION_ID; + } + else if (par.equals("h") || par.equals("hyper") || par.equals("hyperspace")) + { + dim = WarpDriveConfig.G_HYPERSPACE_DIMENSION_ID; + } + else + { + dim = Integer.parseInt(par); + } + + x = Integer.parseInt(params[1]); + y = Integer.parseInt(params[2]); + z = Integer.parseInt(params[3]); + blockId = Integer.parseInt(params[4]); + metadata = Integer.parseInt(params[5]); + actions = params[6]; + } + catch (Exception e) + { + e.printStackTrace(); + player.addChatMessage(getCommandUsage(icommandsender)); + return; + } + + notifyAdmins(icommandsender, "/" + getCommandName() + " " + dim + " " + x + "," + y + "," + z + " " + blockId + ":" + metadata + " " + actions); + World worldObj = DimensionManager.getWorld(dim); + TileEntity te = worldObj.getBlockTileEntity(x, y, z); + notifyAdmins(icommandsender, "[" + getCommandName() + "] In dimension " + worldObj.getProviderName() + " - " + worldObj.getWorldInfo().getWorldName() + ", Current block is " + worldObj.getBlockId(x, y, z) + ":" + worldObj.getBlockMetadata(x, y, z) + ", tile entity is " + ((te == null) ? "undefined" : "defined")); + String side = FMLCommonHandler.instance().getEffectiveSide().isClient() ? "Client":"Server"; + + // I(nvalidate), V(alidate), A(set air), R(emoveEntity), P(setBlock), S(etEntity) + boolean bReturn = false; + for (char ch: actions.toUpperCase().toCharArray()) { + switch (ch) { + case 'I': + notifyAdmins(icommandsender, "[" + getCommandName() + "] " + side + ": invalidating"); + if (te != null) { + te.invalidate(); + } + break; + case 'V': + notifyAdmins(icommandsender, "[" + getCommandName() + "] " + side + ": validating"); + if (te != null) { + te.validate(); + } + break; + case 'A': + notifyAdmins(icommandsender, "[" + getCommandName() + "] " + side + ": setting to Air"); + bReturn = worldObj.setBlockToAir(x, y, z); + notifyAdmins(icommandsender, "[" + getCommandName() + "] " + side + ": returned " + bReturn); + break; + case 'R': + notifyAdmins(icommandsender, "[" + getCommandName() + "] " + side + ": remove entity"); + worldObj.removeBlockTileEntity(x, y, z); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + notifyAdmins(icommandsender, "[" + getCommandName() + "] " + side + ": set block " + x + ", " + y + ", " + z + " to " + blockId + ":" + metadata); + bReturn = worldObj.setBlock(x, y, z, blockId, metadata, ch - '0'); + notifyAdmins(icommandsender, "[" + getCommandName() + "] " + side + ": returned " + bReturn); + break; + case 'P': + notifyAdmins(icommandsender, "[" + getCommandName() + "] " + side + ": set block " + x + ", " + y + ", " + z + " to " + blockId + ":" + metadata); + bReturn = worldObj.setBlock(x, y, z, blockId, metadata, 2); + notifyAdmins(icommandsender, "[" + getCommandName() + "] " + side + ": returned " + bReturn); + break; + case 'S': + notifyAdmins(icommandsender, "[" + getCommandName() + "] " + side + ": set entity"); + worldObj.setBlockTileEntity(x, y, z, te); + break; + case 'C': + notifyAdmins(icommandsender, "[" + getCommandName() + "] " + side + ": update containing block info"); + if (te != null) { + te.updateContainingBlockInfo(); + } + break; + } + } + } + else + { + player.addChatMessage(getCommandUsage(icommandsender)); + } + } +} diff --git a/src/cr0s/WarpDrive/item/ItemWarpUpgrade.java b/src/cr0s/WarpDrive/item/ItemWarpUpgrade.java new file mode 100644 index 00000000..179d295d --- /dev/null +++ b/src/cr0s/WarpDrive/item/ItemWarpUpgrade.java @@ -0,0 +1,137 @@ +package cr0s.WarpDrive.item; + +import java.util.List; + +import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import cr0s.WarpDrive.WarpDrive; +import cr0s.WarpDrive.data.EnumUpgradeTypes; + +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Icon; +import net.minecraftforge.oredict.ShapedOreRecipe; + +public class ItemWarpUpgrade extends Item +{ + private ItemStack[] isCache = new ItemStack[EnumUpgradeTypes.values().length]; + private Icon[] iconBuffer = new Icon[EnumUpgradeTypes.values().length]; + + public ItemWarpUpgrade(int par1) + { + super(par1); + setHasSubtypes(true); + setUnlocalizedName("warpdrive.upgrade.Malformed"); + setCreativeTab(WarpDrive.warpdriveTab); + } + + private boolean isValidDamage(int damage) + { + return damage >= 0 && damage < EnumUpgradeTypes.values().length; + } + + public ItemStack getIS(int damage) + { + if(!isValidDamage(damage)) + return null; + + if(isCache[damage] == null) + isCache[damage] = getISNoCache(damage); + return isCache[damage]; + } + + public ItemStack getISNoCache(int damage) + { + if(!isValidDamage(damage)) + return null; + + return new ItemStack(WarpDrive.upgradeItem,1,damage); + } + + @Override + public String getUnlocalizedName(ItemStack is) + { + if(is == null) + return null; + + int damage = is.getItemDamage(); + if(isValidDamage(damage)) + return "item.warpdrive.upgrade." + EnumUpgradeTypes.values()[damage].toString(); + + return null; + } + + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(int par1, CreativeTabs par2CreativeTabs, List par3List) + { + for(int i=0;i= 0 && damage < EnumUpgradeTypes.values().length) + return iconBuffer[damage]; + return iconBuffer[0]; + } + +} diff --git a/src/cr0s/WarpDrive/machines/BlockChunkLoader.java b/src/cr0s/WarpDrive/machines/BlockChunkLoader.java new file mode 100644 index 00000000..7a9e1c97 --- /dev/null +++ b/src/cr0s/WarpDrive/machines/BlockChunkLoader.java @@ -0,0 +1,37 @@ +package cr0s.WarpDrive.machines; + +import cr0s.WarpDrive.machines.WarpBlockContainer; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Icon; +import net.minecraft.world.World; + +public class BlockChunkLoader extends WarpBlockContainer +{ + Icon iconBuffer; + + public BlockChunkLoader(int par1) + { + super(par1); + setUnlocalizedName("warpdrive.machines.ChunkLoader"); + } + + @Override + public TileEntity createNewTileEntity(World world) + { + return new TileEntityChunkLoader(); + } + + @Override + public void registerIcons(IconRegister ir) + { + iconBuffer = ir.registerIcon("warpdrive:chunkLoader"); + } + + @Override + public Icon getIcon(int side, int damage) + { + return iconBuffer; + } + +} diff --git a/src/cr0s/WarpDrive/machines/BlockLaserReactorMonitor.java b/src/cr0s/WarpDrive/machines/BlockLaserReactorMonitor.java new file mode 100644 index 00000000..63b46418 --- /dev/null +++ b/src/cr0s/WarpDrive/machines/BlockLaserReactorMonitor.java @@ -0,0 +1,38 @@ +package cr0s.WarpDrive.machines; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockContainer; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import cr0s.WarpDrive.WarpDrive; + +public class BlockLaserReactorMonitor extends BlockContainer { + public BlockLaserReactorMonitor(int id, int texture, Material material) { + super(id, material); + setHardness(0.5F); + setStepSound(Block.soundMetalFootstep); + setCreativeTab(WarpDrive.warpdriveTab); + setUnlocalizedName("warpdrive.machines.LaserReactorMonitor"); + } + + public BlockLaserReactorMonitor(int id, Material material) { + this(id, 0, material); + } + + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IconRegister par1IconRegister) { + // Solid textures + blockIcon = par1IconRegister.registerIcon("warpdrive:reactorMonitor"); + } + + @Override + public TileEntity createNewTileEntity(World var1) { + return new TileEntityLaserReactorMonitor(); + } +} diff --git a/src/cr0s/WarpDrive/machines/BlockLaserTreeFarm.java b/src/cr0s/WarpDrive/machines/BlockLaserTreeFarm.java new file mode 100644 index 00000000..e163cd26 --- /dev/null +++ b/src/cr0s/WarpDrive/machines/BlockLaserTreeFarm.java @@ -0,0 +1,66 @@ +package cr0s.WarpDrive.machines; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import cr0s.WarpDrive.WarpDrive; + +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockContainer; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Icon; +import net.minecraft.world.World; + +public class BlockLaserTreeFarm extends BlockContainer { + private Icon[] iconBuffer; + + public BlockLaserTreeFarm(int id, int texture, Material material) { + super(id, material); + setHardness(0.5F); + setStepSound(Block.soundMetalFootstep); + setCreativeTab(WarpDrive.warpdriveTab); + setUnlocalizedName("warpdrive.machines.LaserTreeFarm"); + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IconRegister par1IconRegister) { + iconBuffer = new Icon[2]; + // Solid textures + iconBuffer[0] = par1IconRegister.registerIcon("warpdrive:particleBoosterTopBottom"); + iconBuffer[1] = par1IconRegister.registerIcon("warpdrive:laserTreeFarmSide0"); + } + + @Override + public Icon getIcon(int side, int metadata) { + if (side == 0 || side == 1) { + return iconBuffer[0]; + } + + return iconBuffer[1]; + } + + @Override + public TileEntity createNewTileEntity(World var1) { + return new TileEntityLaserTreeFarm(); + } + + /** + * Returns the quantity of items to drop on block destruction. + */ + @Override + public int quantityDropped(Random par1Random) { + return 1; + } + + /** + * Returns the ID of the items to drop on destruction. + */ + @Override + public int idDropped(int par1, Random par2Random, int par3) { + return this.blockID; + } +} \ No newline at end of file diff --git a/src/cr0s/WarpDrive/machines/BlockPowerLaser.java b/src/cr0s/WarpDrive/machines/BlockPowerLaser.java new file mode 100644 index 00000000..9fe0be60 --- /dev/null +++ b/src/cr0s/WarpDrive/machines/BlockPowerLaser.java @@ -0,0 +1,63 @@ +package cr0s.WarpDrive.machines; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Icon; +import net.minecraft.world.World; + +public class BlockPowerLaser extends WarpBlockContainer { + static Icon[] iconBuffer = new Icon[16]; + public BlockPowerLaser(int id) { + super(id); + setUnlocalizedName("warpdrive.power.Laser"); + setResistance(100.0F); + } + + @Override + public TileEntity createNewTileEntity(World world) { + return new TileEntityPowerLaser(); + } + + private static boolean isActive(int side, int meta) { + if (side == 3 && meta == 1) { + return true; + } + + if (side == 2 && meta == 2) { + return true; + } + + if (side == 4 && meta == 4) { + return true; + } + + if (side == 5 && meta == 3) { + return true; + } + return false; + } + + @Override + @SideOnly(Side.CLIENT) + public Icon getIcon(int side, int meta) { + if (side == 0 || side == 1) { + return iconBuffer[0]; + } + + if(isActive(side,meta)) { + return iconBuffer[2]; + } + + return iconBuffer[1]; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IconRegister par1IconRegister) { + iconBuffer[0] = par1IconRegister.registerIcon("warpdrive:powerLaserTopBottom"); + iconBuffer[1] = par1IconRegister.registerIcon("warpdrive:powerLaserSides"); + iconBuffer[2] = par1IconRegister.registerIcon("warpdrive:powerLaserActive"); + } +} \ No newline at end of file diff --git a/src/cr0s/WarpDrive/machines/BlockPowerReactor.java b/src/cr0s/WarpDrive/machines/BlockPowerReactor.java new file mode 100644 index 00000000..0b1a39dd --- /dev/null +++ b/src/cr0s/WarpDrive/machines/BlockPowerReactor.java @@ -0,0 +1,70 @@ +package cr0s.WarpDrive.machines; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Icon; +import net.minecraft.world.World; + +public class BlockPowerReactor extends WarpBlockContainer { + Icon[] iconBuffer = new Icon[17]; + + public BlockPowerReactor(int id) { + super(id); + setUnlocalizedName("warpdrive.power.Reactor"); + } + + @Override + public TileEntity createNewTileEntity(World world) { + return new TileEntityPowerReactor(); + } + + @Override + public void breakBlock(World w,int x,int y,int z, int oid,int om) { + super.breakBlock(w, x, y, z, oid, om); + + int[] xo = {-2, 2, 0, 0}; + int[] zo = { 0, 0,-2, 2}; + for(int i = 0; i < 4; i++) { + TileEntity te = w.getBlockTileEntity(x+xo[i], y, z+zo[i]); + if(te instanceof TileEntityPowerLaser) { + ((TileEntityPowerLaser)te).unlink(); + } + } + } + + @Override + @SideOnly(Side.CLIENT) + public Icon getIcon(int side, int meta) { + if (side == 0 || side == 1) { + return iconBuffer[16]; + } + if (meta >= 0 && meta < 16) { + return iconBuffer[meta]; + } + return iconBuffer[0]; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IconRegister par1IconRegister) { + iconBuffer[16] = par1IconRegister.registerIcon("warpdrive:reactorTB"); + iconBuffer[0] = par1IconRegister.registerIcon("warpdrive:reactorSide00"); + iconBuffer[1] = par1IconRegister.registerIcon("warpdrive:reactorSide01"); + iconBuffer[2] = par1IconRegister.registerIcon("warpdrive:reactorSide02"); + iconBuffer[3] = par1IconRegister.registerIcon("warpdrive:reactorSide03"); + iconBuffer[4] = par1IconRegister.registerIcon("warpdrive:reactorSide10"); + iconBuffer[5] = par1IconRegister.registerIcon("warpdrive:reactorSide11"); + iconBuffer[6] = par1IconRegister.registerIcon("warpdrive:reactorSide12"); + iconBuffer[7] = par1IconRegister.registerIcon("warpdrive:reactorSide13"); + iconBuffer[8] = par1IconRegister.registerIcon("warpdrive:reactorSide20"); + iconBuffer[9] = par1IconRegister.registerIcon("warpdrive:reactorSide21"); + iconBuffer[10] = par1IconRegister.registerIcon("warpdrive:reactorSide22"); + iconBuffer[11] = par1IconRegister.registerIcon("warpdrive:reactorSide23"); + iconBuffer[12] = par1IconRegister.registerIcon("warpdrive:reactorSide30"); + iconBuffer[13] = par1IconRegister.registerIcon("warpdrive:reactorSide31"); + iconBuffer[14] = par1IconRegister.registerIcon("warpdrive:reactorSide32"); + iconBuffer[15] = par1IconRegister.registerIcon("warpdrive:reactorSide33"); + } +} \ No newline at end of file diff --git a/src/cr0s/WarpDrive/machines/BlockPowerStore.java b/src/cr0s/WarpDrive/machines/BlockPowerStore.java new file mode 100644 index 00000000..48f84ffe --- /dev/null +++ b/src/cr0s/WarpDrive/machines/BlockPowerStore.java @@ -0,0 +1,54 @@ +package cr0s.WarpDrive.machines; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Icon; +import net.minecraft.world.World; + +public class BlockPowerStore extends WarpBlockContainer { + private Icon iconBuffer; + + public BlockPowerStore(int par1) { + super(par1); + setUnlocalizedName("warpdrive.power.Store"); + } + + @Override + public TileEntity createNewTileEntity(World world) { + return new TileEntityPowerStore(); + } + + @Override + @SideOnly(Side.CLIENT) + public Icon getIcon(int side, int meta) { + return iconBuffer; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IconRegister par1IconRegister) { + iconBuffer = par1IconRegister.registerIcon("warpdrive:powerStore"); + } + + /** + * Called upon block activation (right click on the block.) + */ + @Override + public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) { + if (FMLCommonHandler.instance().getEffectiveSide().isClient()) { + return false; + } + + WarpEnergyTE te = (WarpEnergyTE)par1World.getBlockTileEntity(par2, par3, par4); + if (te != null && (par5EntityPlayer.getHeldItem() == null)) { + par5EntityPlayer.addChatMessage(te.getStatus()); + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/src/cr0s/WarpDrive/machines/BlockTransporter.java b/src/cr0s/WarpDrive/machines/BlockTransporter.java new file mode 100644 index 00000000..35b0c219 --- /dev/null +++ b/src/cr0s/WarpDrive/machines/BlockTransporter.java @@ -0,0 +1,47 @@ +package cr0s.WarpDrive.machines; + +import java.util.Random; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import cr0s.WarpDrive.WarpDrive; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Icon; +import net.minecraft.world.World; + +public class BlockTransporter extends WarpBlockContainer { + + private Icon[] iconBuffer; + + public BlockTransporter(int par1, Material par2Material) { + super(par1, par2Material); + setUnlocalizedName("warpdrive.machines.Transporter"); + } + + @Override + public TileEntity createNewTileEntity(World world) { + return new TileEntityTransporter(); + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IconRegister par1IconRegister) { + iconBuffer = new Icon[3]; + // Solid textures + iconBuffer[0] = par1IconRegister.registerIcon("warpdrive:transporterBottom"); + iconBuffer[1] = par1IconRegister.registerIcon("warpdrive:transporterTop"); + iconBuffer[2] = par1IconRegister.registerIcon("warpdrive:transporterSide"); + } + + @Override + public Icon getIcon(int side, int metadata) { + if (side == 0 || side == 1) { + return iconBuffer[side]; + } + + return iconBuffer[2]; + } +} \ No newline at end of file diff --git a/src/cr0s/WarpDrive/machines/TileEntityAbstractLaser.java b/src/cr0s/WarpDrive/machines/TileEntityAbstractLaser.java new file mode 100644 index 00000000..87fd4d5b --- /dev/null +++ b/src/cr0s/WarpDrive/machines/TileEntityAbstractLaser.java @@ -0,0 +1,8 @@ +package cr0s.WarpDrive.machines; + + + +public abstract class TileEntityAbstractLaser extends WarpChunkTE +{ + +} diff --git a/src/cr0s/WarpDrive/machines/TileEntityAbstractMiner.java b/src/cr0s/WarpDrive/machines/TileEntityAbstractMiner.java new file mode 100644 index 00000000..824e68af --- /dev/null +++ b/src/cr0s/WarpDrive/machines/TileEntityAbstractMiner.java @@ -0,0 +1,540 @@ +package cr0s.WarpDrive.machines; + +import java.util.ArrayList; +import java.util.List; + +import appeng.api.IAEItemStack; +import appeng.api.Util; +import appeng.api.WorldCoord; +import appeng.api.events.GridTileLoadEvent; +import appeng.api.events.GridTileUnloadEvent; +import appeng.api.me.tiles.IGridMachine; +import appeng.api.me.tiles.ITileCable; +import appeng.api.me.util.IGridInterface; +import appeng.api.me.util.IMEInventoryHandler; +import net.minecraft.block.Block; +import net.minecraft.block.BlockFluid; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; +import cr0s.WarpDrive.data.Vector3; +import cr0s.WarpDrive.PacketHandler; +import cr0s.WarpDrive.WarpDrive; +import cr0s.WarpDrive.WarpDriveConfig; + +public abstract class TileEntityAbstractMiner extends TileEntityAbstractLaser implements IGridMachine, ITileCable +{ + //FOR STORAGE + private boolean silkTouch = false; + private int fortuneLevel = 0; + + private TileEntityParticleBooster booster = null; + private Vector3 minerVector; + + Boolean powerStatus = false; + private IGridInterface grid; + private boolean isMEReady = false; + + abstract boolean canSilkTouch(); + abstract int minFortune(); + abstract int maxFortune(); + abstract double laserBelow(); + + abstract float getColorR(); + abstract float getColorG(); + abstract float getColorB(); + + public TileEntityAbstractMiner() + { + super(); + fixMinerVector(); + } + + private void fixMinerVector() + { + if(minerVector == null) + minerVector = new Vector3(xCoord,yCoord-laserBelow(),zCoord); + minerVector.x = xCoord; + minerVector.y = yCoord - (laserBelow()); + minerVector.z = zCoord; + minerVector.translate(0.5); + } + + private List getItemStackFromBlock(int i, int j, int k, int blockID, int blockMeta) + { + Block block = Block.blocksList[blockID]; + if (block == null) + return null; + if (silkTouch(blockID)) + { + if (block.canSilkHarvest(worldObj, null, i, j, k, blockMeta)) + { + ArrayList t = new ArrayList(); + t.add(new ItemStack(blockID, 1, blockMeta)); + return t; + } + } + return block.getBlockDropped(worldObj, i, j, k, blockMeta, fortuneLevel); + } + + protected boolean isOnEarth() + { + return worldObj.provider.dimensionId == 0; + } + + private IInventory findChest() { + TileEntity result = null; + + for(int i = 0; i < 6; i++) { + Vector3 sideOffset = adjacentSideOffsets[i]; + result = worldObj.getBlockTileEntity(xCoord + sideOffset.intX(), yCoord + sideOffset.intY(), zCoord + sideOffset.intZ()); + if (result != null && !(result instanceof TileEntityAbstractMiner) && (result instanceof IInventory)) { + return (IInventory) result; + } + } + return null; + } + + //GETTERSETTERS + + protected int fortune() + { + return fortuneLevel; + } + + protected boolean silkTouch() + { + return silkTouch; + } + + protected boolean silkTouch(int blockID) + { + return silkTouch(); + } + + protected boolean silkTouch(boolean b) + { + silkTouch = canSilkTouch() && b; + return silkTouch(); + } + + protected boolean silkTouch(Object o) + { + return silkTouch(toBool(o)); + } + + protected int fortune(int f) + { + try + { + fortuneLevel = clamp(f,minFortune(),maxFortune()); + } + catch(NumberFormatException e) + { + fortuneLevel = minFortune(); + } + return fortune(); + } + + protected TileEntityParticleBooster booster() + { + if(booster == null) + findFirstBooster(); + return booster; + } + + protected int energy() { + TileEntityParticleBooster te = booster(); + if (te != null) { + return te.getEnergyStored(); + } + return 0; + } + + //DATA RET + + protected int calculateLayerCost() + { + return isOnEarth() ? WarpDriveConfig.ML_EU_PER_LAYER_EARTH : WarpDriveConfig.ML_EU_PER_LAYER_SPACE; + } + + protected int calculateBlockCost() + { + return calculateBlockCost(0); + } + + protected int calculateBlockCost(int blockID) + { + int enPerBlock = isOnEarth() ? WarpDriveConfig.ML_EU_PER_BLOCK_EARTH : WarpDriveConfig.ML_EU_PER_BLOCK_SPACE; + if(silkTouch(blockID)) + return (int) Math.round(enPerBlock * WarpDriveConfig.ML_EU_MUL_SILKTOUCH); + return (int) Math.round(enPerBlock * (Math.pow(WarpDriveConfig.ML_EU_MUL_FORTUNE, fortune()))); + } + + protected boolean isRoomForHarvest() + { + if(isMEReady && grid != null) + return true; + + IInventory inv = findChest(); + if(inv != null) + { + int size = inv.getSizeInventory(); + for(int i=0;i stacks = getItemStackFromBlock(valuable.intX(), valuable.intY(), valuable.intZ(), blockID, blockMeta); + if (stacks != null) + { + for (ItemStack stack : stacks) + { + didPlace = didPlace && dumpToInv(stack) == stack.stackSize; + } + } + mineBlock(valuable,blockID,blockMeta); + return didPlace; + } + else if (blockID == Block.waterMoving.blockID || blockID == Block.waterStill.blockID) + // Evaporate water + worldObj.playSoundEffect(valuable.intX() + 0.5D, valuable.intY() + 0.5D, valuable.intZ() + 0.5D, "random.fizz", 0.5F, 2.6F + (worldObj.rand.nextFloat() - worldObj.rand.nextFloat()) * 0.8F); + worldObj.setBlockToAir(valuable.intX(), valuable.intY(), valuable.intZ()); + return true; + } + + protected int dumpToInv(ItemStack item) + { + if (grid != null) + return putInGrid(item); + else + return putInChest(findChest(), item); + } + + private int putInGrid(ItemStack itemStackSource) + { + int transferred = 0; + if(isMEReady && grid != null) + { + IMEInventoryHandler cellArray = grid.getCellArray(); + if (cellArray != null) + { + IAEItemStack ret = cellArray.addItems(Util.createItemStack(itemStackSource)); + if (ret != null) + transferred = (int) ret.getStackSize(); + } + } + return transferred; + } + + private static int putInChest(IInventory inventory, ItemStack itemStackSource) + { + if (inventory == null || itemStackSource == null) + { + return 0; + } + + int transferred = 0; + + for (int i = 0; i < inventory.getSizeInventory(); i++) + { + if (!inventory.isItemValidForSlot(i, itemStackSource)) + { + continue; + } + + ItemStack itemStack = inventory.getStackInSlot(i); + + if (itemStack == null || !itemStack.isItemEqual(itemStackSource)) + { + continue; + } + + int transfer = Math.min(itemStackSource.stackSize - transferred, itemStack.getMaxStackSize() - itemStack.stackSize); + itemStack.stackSize += transfer; + transferred += transfer; + + if (transferred == itemStackSource.stackSize) + { + return transferred; + } + } + + for (int i = 0; i < inventory.getSizeInventory(); i++) + { + if (!inventory.isItemValidForSlot(i, itemStackSource)) + { + continue; + } + + ItemStack itemStack = inventory.getStackInSlot(i); + + if (itemStack != null) + { + continue; + } + + int transfer = Math.min(itemStackSource.stackSize - transferred, itemStackSource.getMaxStackSize()); + ItemStack dest = copyWithSize(itemStackSource, transfer); + inventory.setInventorySlotContents(i, dest); + transferred += transfer; + + if (transferred == itemStackSource.stackSize) + { + return transferred; + } + } + + return transferred; + } + + protected boolean consumeEnergyFromBooster(int requiredEnergy, boolean simulate) + { + TileEntityParticleBooster te = booster(); + if (te != null) { + return te.consumeEnergy(requiredEnergy, simulate); + } + return false; + } + + private TileEntityParticleBooster findFirstBooster() + { + TileEntity result; + int[] xPos = {1,-1,0,0,0,0}; + int[] yPos = {0,0,-1,1,0,0}; + int[] zPos = {0,0,0,0,-1,1}; + + for(int i=0;i<6;i++) + { + result = worldObj.getBlockTileEntity(xCoord + xPos[i], yCoord + yPos[i], zCoord + zPos[i]); + + if (result != null && result instanceof TileEntityParticleBooster) + { + booster = (TileEntityParticleBooster) result; + return (TileEntityParticleBooster) result; + } + } + booster = null; + return null; + } + + protected void defineMiningArea(int xSize,int zSize) + { + int xmax, zmax, x1, x2, z1, z2; + int xmin, zmin; + x1 = xCoord + xSize / 2; + x2 = xCoord - xSize / 2; + + if (x1 < x2) + { + xmin = x1; + xmax = x2; + } + else + { + xmin = x2; + xmax = x1; + } + + z1 = zCoord + zSize / 2; + z2 = zCoord - zSize / 2; + + if (z1 < z2) + { + zmin = z1; + zmax = z2; + } + else + { + zmin = z2; + zmax = z1; + } + + defineMiningArea(xmin,zmin,xmax,zmax); + } + + protected void defineMiningArea(int minX, int minZ, int maxX, int maxZ) + { + if(worldObj == null) + return; + ChunkCoordIntPair a = worldObj.getChunkFromBlockCoords(minX, minZ).getChunkCoordIntPair(); + ChunkCoordIntPair b = worldObj.getChunkFromBlockCoords(maxX, maxZ).getChunkCoordIntPair(); + if(minChunk != null && a.equals(minChunk)) + if(maxChunk != null && b.equals(maxChunk)) + return; + if(minChunk != null && b.equals(minChunk)) + if(maxChunk != null && a.equals(maxChunk)) + return; + minChunk = a; + maxChunk = b; + refreshLoading(true); + } + + private static ItemStack copyWithSize(ItemStack itemStack, int newSize) + { + ItemStack ret = itemStack.copy(); + ret.stackSize = newSize; + return ret; + } + + //NBT DATA + @Override + public void readFromNBT(NBTTagCompound tag) + { + super.readFromNBT(tag); + silkTouch = tag.getBoolean("silkTouch"); + fortuneLevel = tag.getInteger("fortuneLevel"); + + minerVector.x = xCoord; + minerVector.y = yCoord - (laserBelow()); + minerVector.z = zCoord; + minerVector = minerVector.translate(0.5); + } + + @Override + public void writeToNBT(NBTTagCompound tag) + { + super.writeToNBT(tag); + tag.setBoolean("silkTouch", silkTouch); + tag.setInteger("fortuneLevel", fortuneLevel); + } + + //AE INTERFACE + @Override + public void setNetworkReady( boolean isReady ) + { + isMEReady = isReady; + } + + @Override + public boolean isMachineActive() + { + return isMEReady; + } + + @Override + public float getPowerDrainPerTick() + { + return 1; + } + + @Override + public void validate() + { + super.validate(); + MinecraftForge.EVENT_BUS.post(new GridTileLoadEvent(this, worldObj, getLocation())); + } + + @Override + public void invalidate() + { + super.invalidate(); + MinecraftForge.EVENT_BUS.post(new GridTileUnloadEvent(this, worldObj, getLocation())); + } + + @Override + public WorldCoord getLocation() + { + return new WorldCoord(xCoord, yCoord, zCoord); + } + + @Override + public boolean isValid() + { + return true; + } + + @Override + public void setPowerStatus(boolean hasPower) + { + powerStatus = hasPower; + } + + @Override + public boolean isPowered() + { + return powerStatus; + } + + @Override + public IGridInterface getGrid() + { + return grid; + } + + @Override + public void setGrid(IGridInterface gi) + { + grid = gi; + } + + @Override + public boolean coveredConnections() + { + return true; + } + + @Override + public World getWorld() + { + return worldObj; + } + +} diff --git a/src/cr0s/WarpDrive/machines/TileEntityChunkLoader.java b/src/cr0s/WarpDrive/machines/TileEntityChunkLoader.java new file mode 100644 index 00000000..09c88e72 --- /dev/null +++ b/src/cr0s/WarpDrive/machines/TileEntityChunkLoader.java @@ -0,0 +1,231 @@ +package cr0s.WarpDrive.machines; + +import java.util.Map; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.chunk.Chunk; +import cr0s.WarpDrive.data.EnumUpgradeTypes; +import cr0s.WarpDrive.WarpDrive; +import cr0s.WarpDrive.WarpDriveConfig; +import cr0s.WarpDrive.api.IUpgradable; +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.peripheral.IComputerAccess; + +public class TileEntityChunkLoader extends WarpChunkTE implements IUpgradable +{ + private boolean canLoad = false; + private boolean shouldLoad = false; + + private boolean inited = false; + private ChunkCoordIntPair myChunk; + + int negDX, posDX, negDZ, posDZ; + int area = 1; + + public TileEntityChunkLoader() { + super(); + negDX = 0; + negDZ = 0; + posDX = 0; + posDZ = 0; + peripheralName = "warpdriveChunkloader"; + methodsArray = new String[] { + "getEnergyLevel", + "radius", + "bounds", + "active", + "upgrades", + "help" + }; + } + + @Override + public int getMaxEnergyStored() { + return WarpDriveConfig.CL_MAX_ENERGY; + } + + @Override + public boolean shouldChunkLoad() + { + return shouldLoad && canLoad; + } + + @Override + public void updateEntity() + { + super.updateEntity(); + + if(!inited) + { + inited = true; + myChunk = worldObj.getChunkFromBlockCoords(xCoord, zCoord).getChunkCoordIntPair(); + changedDistance(); + } + + if(shouldLoad) + { + canLoad = consumeEnergy(area * WarpDriveConfig.CL_RF_PER_CHUNKTICK, false); + } + else + { + canLoad = consumeEnergy(area * WarpDriveConfig.CL_RF_PER_CHUNKTICK, true); + } + } + + private int clampDistance(int dis) + { + return clamp(dis,0,WarpDriveConfig.CL_MAX_DISTANCE); + } + + private void changedDistance() + { + if(worldObj == null) { + return; + } + if (myChunk == null) { + Chunk aChunk = worldObj.getChunkFromBlockCoords(xCoord, zCoord); + if (aChunk != null) { + myChunk = aChunk.getChunkCoordIntPair(); + } else { + return; + } + } + negDX = -clampDistance(negDX); + posDX = clampDistance(posDX); + negDZ = -clampDistance(negDZ); + posDZ = clampDistance(posDZ); + minChunk = new ChunkCoordIntPair(myChunk.chunkXPos+negDX,myChunk.chunkZPos+negDZ); + maxChunk = new ChunkCoordIntPair(myChunk.chunkXPos+posDX,myChunk.chunkZPos+posDZ); + area = (posDX - negDX + 1) * (posDZ - negDZ + 1); + refreshLoading(true); + } + + @Override + public void readFromNBT(NBTTagCompound nbt) + { + super.readFromNBT(nbt); + negDX = nbt.getInteger("negDX"); + negDZ = nbt.getInteger("negDZ"); + posDX = nbt.getInteger("posDX"); + posDZ = nbt.getInteger("posDZ"); + + changedDistance(); + } + + @Override + public void writeToNBT(NBTTagCompound nbt) + { + super.writeToNBT(nbt); + nbt.setInteger("negDX", negDX); + nbt.setInteger("negDZ", negDZ); + nbt.setInteger("posDX", posDX); + nbt.setInteger("posDZ", posDZ); + } + + // OpenComputer callback methods + // FIXME: implement OpenComputers... + + // ComputerCraft IPeripheral methods implementation + private String helpStr(Object[] args) + { + if(args.length == 1) + { + String m = args[0].toString().toLowerCase(); + if(m.equals("energy")) + return WarpDrive.defEnergyStr; + else if(m.equals("radius")) + return "radius(int): sets the radius in chunks"; + else if(m.equals("bounds")) + return "bounds(int,int,int,int): sets the bounds of chunks to load\nbounds(): returns the 4 bounds\nFormat is -X, +X, -Z, +Z"; + else if(m.equals("active")) + return "active(): returns whether active or not\nactive(boolean): sets whether it should be active or not"; + else if(m.equals("upgrades")) + return WarpDrive.defUpgradeStr; + } + return WarpDrive.defHelpStr; + } + + @Override + public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws Exception { + String meth = methodsArray[method]; + + if(meth.equals("getEnergyLevel")) { + return getEnergyLevel(); + } else if(meth.equals("radius")) + { + if(arguments.length == 1) + { + int dist = toInt(arguments[0]); + negDX = dist; + negDZ = dist; + posDX = dist; + posDZ = dist; + changedDistance(); + return new Object[] { true }; + } + return new Object[] { false }; + } + else if(meth.equals("bounds")) + { + if(arguments.length == 4) + { + negDX = toInt(arguments[0]); + posDX = toInt(arguments[1]); + negDZ = toInt(arguments[2]); + posDZ = toInt(arguments[3]); + changedDistance(); + } + return new Object[] { negDX, posDX, negDZ, posDZ }; + } + else if(meth.equals("active")) + { + if(arguments.length == 1) + shouldLoad = toBool(arguments[0]); + return new Object[] { shouldChunkLoad() }; + } + else if(meth.equals("upgrades")) + { + return getUpgrades(); + } + else if(meth.equals("help")) + { + return new Object[] {helpStr(arguments) }; + } + + return null; + } + + @Override + public boolean takeUpgrade(EnumUpgradeTypes upgradeType, boolean simulate) + { + int max = 0; + if(upgradeType == EnumUpgradeTypes.Energy) + max = 2; + else if(upgradeType == EnumUpgradeTypes.Power) + max = 2; + + if(max == 0) + return false; + + if(upgrades.containsKey(upgradeType)) + if(upgrades.get(upgradeType) >= max) + return false; + + if(!simulate) + { + int c = 0; + if(upgrades.containsKey(upgradeType)) + c = upgrades.get(upgradeType); + upgrades.put(upgradeType, c+1); + } + return true; + } + + @Override + public Map getInstalledUpgrades() + { + return upgrades; + } + +} diff --git a/src/cr0s/WarpDrive/machines/TileEntityLaserReactorMonitor.java b/src/cr0s/WarpDrive/machines/TileEntityLaserReactorMonitor.java new file mode 100644 index 00000000..a620e704 --- /dev/null +++ b/src/cr0s/WarpDrive/machines/TileEntityLaserReactorMonitor.java @@ -0,0 +1,147 @@ +package cr0s.WarpDrive.machines; + +import ic2.api.reactor.IReactor; +import ic2.api.reactor.IReactorChamber; + +import java.util.HashSet; +import java.util.Set; + +import cpw.mods.fml.common.FMLCommonHandler; +import cr0s.WarpDrive.data.Vector3; +import cr0s.WarpDrive.PacketHandler; +import cr0s.WarpDrive.WarpDrive; +import cr0s.WarpDrive.WarpDriveConfig; +import cr0s.WarpDrive.item.ItemReactorLaserFocus; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraftforge.common.ForgeDirection; + +public class TileEntityLaserReactorMonitor extends TileEntityAbstractLaser { + private final int workRate = 10; + private int ticks = 0; + + private Set findReactors() {//returns either IReactor or IReactorChamber tile entity + int[] xD = {-2, 2, 0, 0, 0, 0}; + int[] yD = { 0, 0,-2, 2, 0, 0}; + int[] zD = { 0, 0, 0, 0,-2, 2}; + Set output = new HashSet(); + for(int i = 0; i < xD.length; i++) { + int xO = xCoord + xD[i]; + int yO = yCoord + yD[i]; + int zO = zCoord + zD[i]; + TileEntity te = worldObj.getBlockTileEntity(xO, yO, zO); + if(te == null) + continue; + + if (te instanceof IReactor) { + output.add(te); + } else if(te instanceof IReactorChamber) { + IReactor reactor = ((IReactorChamber)te).getReactor(); + if(reactor == null) + continue; + + ChunkCoordinates coords = reactor.getPosition(); + + if(Math.abs(coords.posX - xCoord) == 1) + continue; + if(Math.abs(coords.posY - yCoord) == 1) + continue; + if(Math.abs(coords.posZ - zCoord) == 1) + continue; + + output.add(te); + } + } + return output; + } + + private boolean coolReactor(IReactor react) { + boolean didCoolReactor = false; + for(int x = 0; x < 9; x++) { + for(int y = 0; y < 6; y++) { + ItemStack item = react.getItemAt(x, y); + if (item != null) { + if(item.getItem() instanceof ItemReactorLaserFocus) { + int heat = item.getItemDamage(); + int heatRemoval = (int) Math.floor(Math.min(getEnergyStored() / WarpDriveConfig.RM_EU_PER_HEAT, heat)); + if (heatRemoval > 0) { + didCoolReactor = true; + consumeEnergy((int) Math.ceil(heatRemoval * WarpDriveConfig.RM_EU_PER_HEAT), false); + item.setItemDamage(heat - heatRemoval); + } + } + } + } + } + return didCoolReactor; + } + + @Override + public void updateEntity() { + if (FMLCommonHandler.instance().getEffectiveSide().isClient()) { + return; + } + super.updateEntity(); + + ticks++; + if (ticks > workRate) { + ticks = 0; + Vector3 myPos = new Vector3(this).translate(0.5); + Set reactors = findReactors(); + if(reactors.size() == 0) + return; + + for(Object o : reactors) + { + IReactor react = null; + if(o instanceof TileEntity) + { + if(o instanceof IReactor) + react = (IReactor)o; + else if(o instanceof IReactorChamber) + react = ((IReactorChamber)o).getReactor(); + if(react != null) + { + if(coolReactor(react)) + { + TileEntity te = (TileEntity)o; + PacketHandler.sendBeamPacket(worldObj, myPos, new Vector3(te.xCoord,te.yCoord,te.zCoord).translate(0.5D), 0f, 0.8f, 1f, 20, 0, 20); + } + } + } + } + } + } + + @Override + public void writeToNBT(NBTTagCompound tag) { + super.writeToNBT(tag); + } + + @Override + public void readFromNBT(NBTTagCompound tag) { + super.readFromNBT(tag); + } + + @Override + public boolean shouldChunkLoad() { + return false; + } + + @Override + public int getMaxEnergyStored() { + return WarpDriveConfig.RM_MAX_ENERGY; + } + + @Override + public int getMaxSafeInput() { + return Integer.MAX_VALUE; + } + + @Override + public boolean canInputEnergy(ForgeDirection from) { + return true; + } +} diff --git a/src/cr0s/WarpDrive/machines/TileEntityLaserTreeFarm.java b/src/cr0s/WarpDrive/machines/TileEntityLaserTreeFarm.java new file mode 100644 index 00000000..5e87fdcc --- /dev/null +++ b/src/cr0s/WarpDrive/machines/TileEntityLaserTreeFarm.java @@ -0,0 +1,350 @@ +package cr0s.WarpDrive.machines; + +import java.util.LinkedList; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import cr0s.WarpDrive.data.Vector3; +import cr0s.WarpDrive.WarpDrive; +import cr0s.WarpDrive.WarpDriveConfig; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.lua.ILuaContext; + +public class TileEntityLaserTreeFarm extends TileEntityAbstractMiner { + Boolean active = false; + + private int mode = 0; + private boolean doLeaves = false; + private boolean silkTouchLeaves = false; + private boolean treeTap = false; + + private final int defSize = 8; + private final int scanWait = 40; + private final int mineWait = 4; + private int delayMul = 4; + + private int totalHarvested=0; + + private int scan = 0; + private int xSize = defSize; + private int zSize = defSize; + + LinkedList logs; + private int logIndex = 0; + + public TileEntityLaserTreeFarm() { + super(); + peripheralName = "treefarmLaser"; + methodsArray = new String[] { + "start", + "stop", + "area", + "leaves", + "silkTouch", + "silkTouchLeaves", + "treetap", + "state" + }; + } + + @Override + public void updateEntity() { + super.updateEntity(); + + if (active) { + scan++; + if (mode == 0) { + if (scan >= scanWait) { + scan = 0; + logs = scanTrees(); + if(logs.size() > 0) + mode = treeTap ? 2 : 1; + logIndex = 0; + } + } else { + if (scan >= mineWait * delayMul) { + scan = 0; + + if (logIndex >= logs.size()) { + mode = 0; + return; + } + Vector3 pos = logs.get(logIndex); + int blockID = worldObj.getBlockId(pos.intX(), pos.intY(), pos.intZ()); + + if (mode == 1) { + int cost = calculateBlockCost(blockID); + if (consumeEnergyFromBooster(cost, true)) { + if (isLog(blockID) || (doLeaves && isLeaf(blockID))) { + delayMul = 1; + if (isRoomForHarvest()) { + if (consumeEnergyFromBooster(cost, false)) { + if (isLog(blockID)) { + delayMul = 4; + totalHarvested++; + } + harvestBlock(pos); + } else { + return; + } + } else { + return; + } + } + logIndex++; + } + } else if(mode == 2) { + int cost = calculateBlockCost(blockID); + if (consumeEnergyFromBooster(cost, true)) { + if (isRoomForHarvest()) { + if (blockID == WarpDriveConfig.IC2_RubberWood) { + int metadata = worldObj.getBlockMetadata(pos.intX(), pos.intY(), pos.intZ()); + if (metadata >= 2 && metadata <= 5) { + WarpDrive.debugPrint("wetspot found"); + if (consumeEnergyFromBooster(cost, false)) { + ItemStack resin = WarpDriveConfig.IC2_Resin.copy(); + resin.stackSize = (int) Math.round(Math.random() * 4); + dumpToInv(resin); + worldObj.setBlockMetadataWithNotify(pos.intX(), pos.intY(), pos.intZ(), metadata+6, 3); + laserBlock(pos); + totalHarvested++; + delayMul = 4; + } else { + return; + } + } else { + delayMul = 1; + } + } else if(isLog(blockID)) { + if (consumeEnergyFromBooster(cost, false)) { + delayMul = 4; + totalHarvested++; + harvestBlock(pos); + } else { + return; + } + } else if(isLeaf(blockID)) { + if (consumeEnergyFromBooster(cost, true)) { + delayMul = 1; + harvestBlock(pos); + } else { + return; + } + } + } else { + return; + } + logIndex++; + } + } + } + } + } + } + + private static boolean isLog(int blockID) { + return WarpDriveConfig.MinerLogs.contains(blockID); + } + + private static boolean isLeaf(int blockID) { + return WarpDriveConfig.MinerLeaves.contains(blockID); + } + + private static void addTree(LinkedList list, Vector3 newTree) { + WarpDrive.debugPrint("Adding tree position:" + newTree.x + "," + newTree.y + "," + newTree.z); + list.add(newTree); + } + + private LinkedList scanTrees() { + int xmax, zmax, x1, x2, z1, z2; + int xmin, zmin; + x1 = xCoord + xSize / 2; + x2 = xCoord - xSize / 2; + xmin = Math.min(x1, x2); + xmax = Math.max(x1, x2); + + z1 = zCoord + zSize / 2; + z2 = zCoord - zSize / 2; + zmin = Math.min(z1, z2); + zmax = Math.max(z1, z2); + + LinkedList logPositions = new LinkedList(); + + for(int x = xmin; x <= xmax; x++) { + for(int z = zmin; z <= zmax; z++) { + int blockID = worldObj.getBlockId(x, yCoord, z); + if (isLog(blockID)) { + Vector3 pos = new Vector3(x, yCoord, z); + logPositions.add(pos); + scanNearby(logPositions, x, yCoord, z, 0); + } + } + } + return logPositions; + } + + private void scanNearby(LinkedList current, int x, int y, int z, int d) { + int[] deltas = {0, -1, 1}; + for(int dx : deltas) { + for(int dy = 1; dy >= 0; dy--) { + for(int dz : deltas) { + int blockID = worldObj.getBlockId(x+dx, y+dy, z+dz); + if (isLog(blockID) || (doLeaves && isLeaf(blockID))) { + Vector3 pos = new Vector3(x + dx, y + dy, z + dz); + if (!current.contains(pos)) { + addTree(current, pos); + if (d < 35) { + scanNearby(current,x+dx,y+dy,z+dz,d+1); + } + } + } + } + } + } + } + + @Override + public void writeToNBT(NBTTagCompound tag) { + super.writeToNBT(tag); + tag.setInteger("xSize", xSize); + tag.setInteger("zSize", zSize); + tag.setBoolean("doLeaves", doLeaves); + tag.setBoolean("active", active); + tag.setBoolean("treetap", treeTap); + tag.setBoolean("silkTouchLeaves", silkTouchLeaves); + } + + @Override + public void readFromNBT(NBTTagCompound tag) { + super.readFromNBT(tag); + xSize = tag.getInteger("xSize"); + zSize = tag.getInteger("zSize"); + defineMiningArea(xSize,zSize); + + doLeaves = tag.getBoolean("doLeaves"); + active = tag.getBoolean("active"); + treeTap = tag.getBoolean("treetap"); + silkTouchLeaves = tag.getBoolean("silkTouchLeaves"); + } + + @Override + public boolean shouldChunkLoad() { + return active; + } + + // OpenComputer callback methods + // FIXME: implement OpenComputers... + + // ComputerCraft IPeripheral methods implementation + @Override + public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws Exception { + String methodName = methodsArray[method]; + if (methodName.equals("start")) { + if (!active) { + mode = 0; + totalHarvested = 0; + active = true; + } + return new Boolean[] { true }; + } else if (methodName.equals("stop")) { + active = false; + } else if (methodName.equals("area")) { + try { + if (arguments.length == 1) { + xSize = clamp(toInt(arguments[0]),3,WarpDriveConfig.TF_MAX_SIZE); + zSize = xSize; + } else if (arguments.length == 2) { + xSize = clamp(toInt(arguments[0]),3,WarpDriveConfig.TF_MAX_SIZE); + zSize = clamp(toInt(arguments[1]),3,WarpDriveConfig.TF_MAX_SIZE); + } + } catch(NumberFormatException e) { + xSize = defSize; + zSize = defSize; + } + defineMiningArea(xSize,zSize); + return new Integer[] { xSize , zSize }; + } else if (methodName.equals("leaves")) { + try { + if (arguments.length > 0) { + doLeaves = toBool(arguments[0]); + } + } catch(Exception e) { + + } + return new Boolean[] { doLeaves }; + } else if (methodName.equals("silkTouch")) { + try { + silkTouch(arguments[0]); + } catch(Exception e) { + silkTouch(false); + } + return new Object[] { silkTouch() }; + } else if (methodName.equals("silkTouchLeaves")) { + try { + if (arguments.length >= 1) { + silkTouchLeaves = toBool(arguments[0]); + } + } catch(Exception e) { + silkTouchLeaves = false; + } + return new Object[] { silkTouchLeaves }; + } else if (methodName.equals("treetap")) { + try { + if (arguments.length >= 1) { + treeTap = toBool(arguments[0]); + } + } catch(Exception e) { + treeTap = false; + } + return new Object[] { treeTap }; + } else if (methodName.equals("state")) { + String state = active ? (mode==0?"scanning" : (mode == 1 ? "harvesting" : "tapping")) : "inactive"; + return new Object[] { state, xSize, zSize, energy(), totalHarvested }; + } + return null; + } + + //ABSTRACT LASER IMPLEMENTATION + @Override + protected boolean silkTouch(int blockID) { + if (isLeaf(blockID)) { + return silkTouchLeaves; + } + return silkTouch(); + } + + @Override + protected boolean canSilkTouch() { + return true; + } + + @Override + protected int minFortune() { + return 0; + } + + @Override + protected int maxFortune() { + return 0; + } + + @Override + protected double laserBelow() { + return -0.5; + } + + @Override + protected float getColorR() { + return 0.2f; + } + + @Override + protected float getColorG() { + return 0.7f; + } + + @Override + protected float getColorB() { + return 0.4f; + } +} diff --git a/src/cr0s/WarpDrive/machines/TileEntityPowerLaser.java b/src/cr0s/WarpDrive/machines/TileEntityPowerLaser.java new file mode 100644 index 00000000..0276664e --- /dev/null +++ b/src/cr0s/WarpDrive/machines/TileEntityPowerLaser.java @@ -0,0 +1,219 @@ +package cr0s.WarpDrive.machines; + +import cr0s.WarpDrive.api.IBlockUpdateDetector; +import cr0s.WarpDrive.data.Vector3; +import cr0s.WarpDrive.PacketHandler; +import cr0s.WarpDrive.WarpDrive; +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IPeripheral; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; + +public class TileEntityPowerLaser extends TileEntityAbstractLaser implements IPeripheral, IBlockUpdateDetector { + Vector3 myVec; + Vector3 reactorVec; + ForgeDirection side = ForgeDirection.UNKNOWN; + TileEntityParticleBooster booster; + TileEntityPowerReactor reactor; + + boolean useLaser = false; + boolean doOnce = false; + + String[] methodArray = { + "energy", + "hasReactor", + "side", + "sendLaser", + "help" + }; + + @Override + public boolean shouldChunkLoad() { + return false; + } + + public TileEntityPowerReactor scanForReactor() { + reactor = null; + TileEntity te; + //I AM ON THE NORTH SIDE + side = ForgeDirection.UNKNOWN; + te = worldObj.getBlockTileEntity(xCoord, yCoord, zCoord + 2); + if (te instanceof TileEntityPowerReactor && worldObj.isAirBlock(xCoord, yCoord, zCoord + 1)) { + side = ForgeDirection.NORTH; + reactor = (TileEntityPowerReactor) te; + } + + //I AM ON THE SOUTH SIDE + te = worldObj.getBlockTileEntity(xCoord, yCoord, zCoord - 2); + if (te instanceof TileEntityPowerReactor && worldObj.isAirBlock(xCoord, yCoord, zCoord - 1)) { + side = ForgeDirection.SOUTH; + reactor = (TileEntityPowerReactor) te; + } + + //I AM ON THE WEST SIDE + te = worldObj.getBlockTileEntity(xCoord + 2, yCoord, zCoord); + if (te instanceof TileEntityPowerReactor && worldObj.isAirBlock(xCoord + 1, yCoord, zCoord)) { + side = ForgeDirection.WEST; + reactor = (TileEntityPowerReactor) te; + } + + //I AM ON THE EAST SIDE + te = worldObj.getBlockTileEntity(xCoord - 2, yCoord, zCoord); + if (te instanceof TileEntityPowerReactor && worldObj.isAirBlock(xCoord - 1, yCoord, zCoord)) { + side = ForgeDirection.EAST; + reactor = (TileEntityPowerReactor) te; + } + + setMetadata(); + + if (reactor != null) { + reactorVec = new Vector3(reactor).translate(0.5); + } + return reactor; + } + + private void setMetadata() { + int metadata = 0; + if (side != ForgeDirection.UNKNOWN) { + metadata = side.ordinal() - 1; + } + if (getBlockMetadata() != metadata) { + worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, metadata, 3); + } + } + + public TileEntityParticleBooster scanForBooster() { + booster = null; + TileEntity te; + te = worldObj.getBlockTileEntity(xCoord, yCoord + 1, zCoord); + if (te != null && te instanceof TileEntityParticleBooster) { + booster = (TileEntityParticleBooster)te; + } + + te = worldObj.getBlockTileEntity(xCoord, yCoord - 1, zCoord); + if (te != null && te instanceof TileEntityParticleBooster) { + booster = (TileEntityParticleBooster)te; + } + + return booster; + } + + @Override + public void updateEntity() { + if (doOnce == false) { + scanForReactor(); + scanForBooster(); + myVec = new Vector3(this).translate(0.5); + doOnce = true; + } + + if (useLaser == true) { + PacketHandler.sendBeamPacket(worldObj, myVec, reactorVec, 0.1F, 0.2F, 1.0F, 25, 50, 100); + useLaser = false; + } + } + + public void unlink() { + side = ForgeDirection.UNKNOWN; + setMetadata(); + } + + @Override + public void updatedNeighbours() { + scanForBooster(); + scanForReactor(); + } + + private void laserReactor(int energy) { + if (energy <= 0) { + return; + } + + scanForBooster(); + scanForReactor(); + if(booster == null) + return; + if(reactor == null) + return; + if (booster.consumeEnergy(energy, false)) { + // WarpDrive.debugPrint("ReactorLaser on " + side.toString() +" side sending " + amount); + useLaser = true; + reactor.decreaseInstability(side, energy); + } + } + + @Override + public void writeToNBT(NBTTagCompound nbt) { + super.writeToNBT(nbt); + } + + @Override + public void readFromNBT(NBTTagCompound nbt) { + super.readFromNBT(nbt); + } + + @Override + public String getType() { + return "warpdriveReactorLaser"; + } + + @Override + public String[] getMethodNames() { + return methodArray; + } + + private static String helpStr(Object[] args) { + if (args.length > 0) { + String arg = args[0].toString().toLowerCase(); + if (arg.equals("energy")) { + return WarpDrive.defEnergyStr; + } else if(arg.equals("hasReactor")) { + return "hasReactor(): returns true if the laser can see a reactor and false otherwise"; + } else if(arg.equals("sendlaser")) { + return "sendLaser(int): sends a laser of energy int to the reactor"; + } else if(arg.equals("side")) { + return "side(): returns 0-3 depending on which side of the reactor its on"; + } + } + return WarpDrive.defHelpStr; + } + + @Override + public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws Exception { + String methodName = methodArray[method]; + if (methodName.equals("energy")) { + scanForBooster(); + if (booster == null) { + return new Object[] { 0,0 }; + } else { + return new Object[] { booster.getEnergyStored(), booster.getMaxEnergyStored() }; + } + } else if (methodName.equals("hasReactor")) { + return new Object[] { scanForReactor() != null }; + } else if (methodName.equals("sendLaser")) { + if (arguments.length >= 1) { + laserReactor(toInt(arguments[0])); + } + } else if (methodName.equals("help")) { + return new Object[] {helpStr(arguments)}; + } else if (methodName.equals("side")) { + return new Object[] { side.ordinal() - 2 }; + } + return null; + } + + @Override + public void attach(IComputerAccess computer) { + } + + @Override + public void detach(IComputerAccess computer) { + } + + @Override + public boolean equals(IPeripheral other) { + return other == this; + } +} \ No newline at end of file diff --git a/src/cr0s/WarpDrive/machines/TileEntityPowerReactor.java b/src/cr0s/WarpDrive/machines/TileEntityPowerReactor.java new file mode 100644 index 00000000..755c1778 --- /dev/null +++ b/src/cr0s/WarpDrive/machines/TileEntityPowerReactor.java @@ -0,0 +1,523 @@ +package cr0s.WarpDrive.machines; + +import java.util.HashMap; +import java.util.Random; +import java.util.Set; + +import cpw.mods.fml.common.FMLCommonHandler; +import cr0s.WarpDrive.WarpDrive; +import cr0s.WarpDrive.WarpDriveConfig; +import cr0s.WarpDrive.api.IBlockUpdateDetector; +import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.peripheral.IComputerAccess; +import net.minecraft.entity.Entity; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; + +public class TileEntityPowerReactor extends WarpEnergyTE implements IBlockUpdateDetector { + private int containedEnergy = 0; + + // generation & instability is 'per tick' + private static final int PR_MIN_GENERATION = 4; + private static final int PR_MAX_GENERATION = 64000; + private static final double PR_MIN_INSTABILITY = 0.004D; + private static final double PR_MAX_INSTABILITY = 0.060D; + + // explosion parameters + private static final int PR_MAX_EXPLOSION_RADIUS = 6; + private static final double PR_MAX_EXPLOSION_REMOVAL_CHANCE = 0.1D; + + // laser stabilization is per shot + // target is to consume 10% max output power every second, hence 2.5% per side + // laser efficiency is 33% at 16% power (target spot), 50% at 24% power, 84% at 50% power, etc. + // 10% * 20 * PR_MAX_GENERATION / (4 * 0.16) => ~200kRF => ~ max laser energy + private static final double PR_MAX_LASER_ENERGY = 200000.0D; + private static final double PR_MAX_LASER_EFFECT = PR_MAX_INSTABILITY * 20 / 0.33D; + + private int tickCount = 0; + + private double[] instabilityValues = { 0.0D, 0.0D, 0.0D, 0.0D }; // no instability = 0, explosion = 100 + private float lasersReceived = 0; + private int lastGenerationRate = 0; + private int releasedThisTick = 0; // amount of energy released during current tick update + private int releasedThisCycle = 0; // amount of energy released during current cycle + private int releasedLastCycle = 0; + + private boolean hold = true; // hold updates and power output until reactor is controlled (i.e. don't explode on chunk-loading while computer is booting) + private boolean active = false; + private static final int MODE_DONT_RELEASE = 0; + private static final int MODE_MANUAL_RELEASE = 1; + private static final int MODE_RELEASE_ABOVE = 2; + private static final int MODE_RELEASE_AT_RATE = 3; + private static final String[] MODE_STRING = {"OFF", "MANUAL", "ABOVE", "RATE"}; + private int releaseMode = 0; + private int releaseRate = 0; + private int releaseAbove = 0; + + private boolean init = false; + + public TileEntityPowerReactor() { + super(); + peripheralName = "warpdriveReactor"; + methodsArray = new String[] { + "active", + "energy", // returns energy, max energy, energy rate + "instability", // returns ins0,1,2,3 + "release", // releases all energy + "releaseRate", // releases energy when more than arg0 is produced + "releaseAbove", // releases any energy above arg0 amount + "help" // returns help on arg0 function + }; + } + + private void increaseInstability(ForgeDirection from, boolean isNatural) { + if (canOutputEnergy(from) || hold) { + return; + } + + int side = from.ordinal() - 2; + if (containedEnergy > WarpDriveConfig.PR_TICK_TIME * PR_MIN_GENERATION * 100) { + double amountToIncrease = WarpDriveConfig.PR_TICK_TIME * Math.max(PR_MIN_INSTABILITY, PR_MAX_INSTABILITY * Math.pow((worldObj.rand.nextDouble() * containedEnergy) / WarpDriveConfig.PR_MAX_ENERGY, 0.1)); + // WarpDrive.debugPrint("InsInc" + amountToIncrease); + instabilityValues[side] += amountToIncrease * (isNatural ? 1.0D : 0.25D); + } else { + double amountToDecrease = WarpDriveConfig.PR_TICK_TIME * Math.max(PR_MIN_INSTABILITY, instabilityValues[side] * 0.02D); + instabilityValues[side] = Math.max(0.0D, instabilityValues[side] - amountToDecrease); + } + } + + private void increaseInstability(boolean isNatural) { + increaseInstability(ForgeDirection.NORTH, isNatural); + increaseInstability(ForgeDirection.SOUTH, isNatural); + increaseInstability(ForgeDirection.EAST, isNatural); + increaseInstability(ForgeDirection.WEST, isNatural); + } + + public void decreaseInstability(ForgeDirection from, int energy) { + if (canOutputEnergy(from)) { + return; + } + + // laser is active => start updating reactor + hold = false; + + int amount = convertInternalToRF(energy); + if (amount <= 1) { + return; + } + + lasersReceived = Math.min(10.0F, lasersReceived + 1F / WarpDriveConfig.PR_MAX_LASERS); + double nospamFactor = 1.0; + if (lasersReceived > 1.0F) { + nospamFactor = 0.5; + worldObj.newExplosion((Entity) null, xCoord + from.offsetX, yCoord + from.offsetY, zCoord + from.offsetZ, 1, false, false); + // increaseInstability(from, false); + // increaseInstability(false); + } + double normalisedAmount = Math.min(1.0D, Math.max(0.0D, amount / PR_MAX_LASER_ENERGY)); // 0.0 to 1.0 + double baseLaserEffect = 0.5D + 0.5D * Math.cos(Math.PI - (1.0D + Math.log10(0.1D + 0.9D * normalisedAmount)) * Math.PI); // 0.0 to 1.0 + double randomVariation = 0.8D + 0.4D * worldObj.rand.nextDouble(); // ~1.0 + double amountToRemove = PR_MAX_LASER_EFFECT * baseLaserEffect * randomVariation * nospamFactor; + + int side = from.ordinal() - 2; + + /* + if (side == 3) WarpDrive.debugPrint("Instability on " + from.toString() + " decreased by " + String.format("%.1f", amountToRemove) + "/" + String.format("%.1f", PR_MAX_LASER_EFFECT) + + " after consuming " + amount + "/" + PR_MAX_LASER_ENERGY + " lasersReceived is " + String.format("%.1f", lasersReceived) + " hence nospamFactor is " + nospamFactor); + /**/ + + instabilityValues[side] = Math.max(0, instabilityValues[side] - amountToRemove); + + updateSideTextures(); + } + + private void generateEnergy() { + double stabilityOffset = 0.5; + for(int i = 0; i < 4; i++) { + stabilityOffset *= Math.max(0.01D, instabilityValues[i] / 100.0D); + } + + if (active) {// producing, instability increase output, you want to take the risk + int amountToGenerate = (int)Math.ceil( WarpDriveConfig.PR_TICK_TIME * (0.5D + stabilityOffset) * (PR_MIN_GENERATION + PR_MAX_GENERATION * Math.pow(containedEnergy / (double) WarpDriveConfig.PR_MAX_ENERGY, 0.6D))); + containedEnergy = Math.min(containedEnergy + amountToGenerate, WarpDriveConfig.PR_MAX_ENERGY); + lastGenerationRate = amountToGenerate / WarpDriveConfig.PR_TICK_TIME; + // WarpDrive.debugPrint("Generated " + amountToGenerate); + } else {// decaying over 20s without producing power, you better have power for those lasers + int amountToDecay = (int)( WarpDriveConfig.PR_TICK_TIME * (1.0D - stabilityOffset) * (PR_MIN_GENERATION + containedEnergy * 0.01D) ); + containedEnergy = Math.max(0, containedEnergy - amountToDecay); + lastGenerationRate = 0; + // WarpDrive.debugPrint("Decayed " + amountToDecay); + } + } + + @Override + public void updateEntity() { + if (FMLCommonHandler.instance().getEffectiveSide().isClient()) { + return; + } + super.updateEntity(); + + // WarpDrive.debugPrint("tickCount " + tickCount + " releasedThisTick " + releasedThisTick + " lasersReceived " + lasersReceived + " releasedThisCycle " + releasedThisCycle + " containedEnergy " + containedEnergy); + releasedThisTick = 0; + + lasersReceived = Math.max(0.0F, lasersReceived - 0.05F); + tickCount++; + if (tickCount < WarpDriveConfig.PR_TICK_TIME) { + return; + } + tickCount = 0; + releasedLastCycle = releasedThisCycle; + releasedThisCycle = 0; + + if (!init) { + init = true; + updatedNeighbours(); + } + + updateSideTextures(); + + // unstable at all time + if (shouldExplode()) { + explode(); + } + increaseInstability(true); + + generateEnergy(); + + sendEvent("reactorPulse", new Object[] { lastGenerationRate }); + } + + private void explode() { + // remove blocks randomly up to x blocks around (breaking whatever protection is there) + double normalizedEnergy = containedEnergy / (double)WarpDriveConfig.PR_MAX_ENERGY; + int radius = (int) Math.round(PR_MAX_EXPLOSION_RADIUS * Math.pow(normalizedEnergy, 0.125)); + double c = PR_MAX_EXPLOSION_REMOVAL_CHANCE * Math.pow(normalizedEnergy, 0.125); + WarpDrive.debugPrint(this + " Explosion radius is " + radius + ", Chance of removal is " + c); + if (radius > 1) { + for(int x = xCoord - radius; x <= xCoord + radius; x++) { + for(int y = yCoord - radius; y <= yCoord + radius; y++) { + for(int z = zCoord - radius; z <= zCoord + radius; z++) { + if (z != zCoord || y != yCoord || x != xCoord) { + if (worldObj.rand.nextDouble() < c) { + worldObj.setBlockToAir(x, y, z); + } + } + } + } + } + } + // remove reactor + worldObj.setBlockToAir(xCoord, yCoord, zCoord); + // set a few TnT augmented around reactor + for (int i = 0; i < 3; i++) { + worldObj.newExplosion((Entity) null, + xCoord + worldObj.rand.nextInt(3) - 0.5D, + yCoord + worldObj.rand.nextInt(3) - 0.5D, + zCoord + worldObj.rand.nextInt(3) - 0.5D, + 4.0F + worldObj.rand.nextInt(3), + true, true); + } + } + + private void updateSideTextures() { + double maxInstability = 0.0D; + for (Double ins:instabilityValues) { + if (ins > maxInstability) { + maxInstability = ins; + } + } + int instabilityNibble = (int) Math.max(0, Math.min(3, Math.round( maxInstability / 25.0D))); + int energyNibble = (int) Math.max(0, Math.min(3, Math.round(4.0D * containedEnergy / WarpDriveConfig.PR_MAX_ENERGY))); + + int metadata = 4 * instabilityNibble + energyNibble; + if (getBlockMetadata() != metadata) { + worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, metadata, 3); + } + } + + private boolean shouldExplode() { + boolean exploding = false; + for(int i = 0; i < 4; i++) { + exploding = exploding || (instabilityValues[i] >= 100); + } + exploding &= (worldObj.rand.nextInt(4) == 2); + + if (exploding) { + WarpDrive.print(this + String.format(" Explosion trigerred, Instability is [%.2f, %.2f, %.2f, %.2f], Energy stored is %d, Laser received is %.2f, %s", new Object[] { + instabilityValues[0], instabilityValues[1], instabilityValues[2], instabilityValues[3], + this.containedEnergy, + this.lasersReceived, + this.active ? "ACTIVE" : "INACTIVE" })); + active = false; + } + return exploding; + } + + //Takes the arguments passed by function call and returns an appropriate string + private static String helpStr(Object[] args) { + if (args.length > 0) { + String arg = args[0].toString().toLowerCase(); + if (arg.equals("getactive")) { + return "getActive(): returns true if the reactor is active and false otherwise"; + } else if (arg.equals("setactive")) { + return "setActive(bool): activates the reactor if passed true and deactivates if passed false"; + } else if (arg.equals("energy")) { + return WarpDrive.defEnergyStr; + } else if (arg.equals("instability")) { + return "instability(): returns the 4 instability values (100 is the point when the reactor explodes)"; + } else if (arg.equals("release")) { + return "release(bool): sets the reactor to output all energy or disables outputting of energy"; + } else if (arg.equals("releaserate")) { + return "releaseRate(int): sets the reactor to try to release exactly int/tick"; + } else if (arg.equals("releaseabove")) { + return "releaseAbove(int): releases all energy above stored int"; + } + } + return WarpDrive.defHelpStr; + } + + @Override + public void updatedNeighbours() { + TileEntity te; + super.updatedNeighbours(); + + int[] xo = { 0, 0,-2, 2}; + int[] zo = { 2,-2, 0, 0}; + + for(int i = 0; i < 4; i++) { + te = worldObj.getBlockTileEntity(xCoord + xo[i], yCoord, zCoord + zo[i]); + if (te instanceof TileEntityPowerLaser) { + ((TileEntityPowerLaser)te).scanForReactor(); + } + } + } + + // OpenComputer callback methods + // FIXME: implement OpenComputers... + + public Object[] active(Object[] arguments) throws Exception { + if (arguments.length == 1) { + boolean activate = false; + try { + activate = toBool(arguments[0]); + } catch(Exception e) { + throw new Exception("Function expects an boolean value"); + } + if (active && !activate) { + sendEvent("reactorDeactivation", null); + } else if(!active && activate) { + sendEvent("reactorActivation", null); + } + active = activate; + } + if (releaseMode == MODE_DONT_RELEASE || releaseMode == MODE_MANUAL_RELEASE) { + return new Object[] { active, MODE_STRING[releaseMode], 0 }; + } else if (releaseMode == MODE_RELEASE_ABOVE) { + return new Object[] { active, MODE_STRING[releaseMode], releaseAbove }; + } else { + return new Object[] { active, MODE_STRING[releaseMode], releaseRate }; + } + } + + private Object[] release(Object[] arguments) throws Exception { + boolean doRelease = false; + if (arguments.length > 0) { + try { + doRelease = toBool(arguments[0]); + } catch(Exception e) { + throw new Exception("Function expects an boolean value"); + } + + releaseMode = doRelease ? MODE_MANUAL_RELEASE : MODE_DONT_RELEASE; + releaseAbove = 0; + releaseRate = 0; + } + return new Object[] { releaseMode != MODE_DONT_RELEASE }; + } + + private Object[] releaseRate(Object[] arguments) throws Exception { + int rate = -1; + try { + rate = toInt(arguments[0]); + } catch(Exception e) { + throw new Exception("Function expects an integer value"); + } + + if (rate <= 0) { + releaseMode = MODE_DONT_RELEASE; + releaseRate = 0; + } else { +/* releaseAbove = (int)Math.ceil(Math.pow(rate, 1.0 / 0.6)); + WarpDrive.debugPrint("releaseAbove " + releaseAbove); + releaseMode = MODE_RELEASE_ABOVE;/**/ + // player has to adjust it + releaseRate = rate; + releaseMode = MODE_RELEASE_AT_RATE; + } + + return new Object[] { MODE_STRING[releaseMode], releaseRate }; + } + + private Object[] releaseAbove(Object[] arguments) throws Exception { + int above = -1; + try { + above = toInt(arguments[0]); + } catch(Exception e) { + throw new Exception("Function expects an integer value"); + } + + if (above <= 0) { + releaseMode = 0; + releaseAbove = MODE_DONT_RELEASE; + } else { + releaseMode = MODE_RELEASE_ABOVE; + releaseAbove = above; + } + + return new Object[] { MODE_STRING[releaseMode], releaseAbove }; + } + + // ComputerCraft IPeripheral methods implementation + @Override + public void attach(IComputerAccess computer) { + super.attach(computer); + int id = computer.getID(); + connectedComputers.put(id, computer); + if (WarpDriveConfig.G_LUA_SCRIPTS != WarpDriveConfig.LUA_SCRIPTS_NONE) { + computer.mount("/power", ComputerCraftAPI.createResourceMount(WarpDrive.class, "warpdrive", "lua/power")); + computer.mount("/warpupdater", ComputerCraftAPI.createResourceMount(WarpDrive.class, "warpdrive", "lua/common/updater")); + if (WarpDriveConfig.G_LUA_SCRIPTS == WarpDriveConfig.LUA_SCRIPTS_ALL) { + computer.mount("/startup", ComputerCraftAPI.createResourceMount(WarpDrive.class, "warpdrive", "lua/power/startup")); + } + } + } + + @Override + public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws Exception { + // computer is alive => start updating reactor + hold = false; + + String methodName = methodsArray[method]; + + if (methodName.equals("active")) { + return active(arguments); + + } else if (methodName.equals("energy")) { + return new Object[] { containedEnergy, WarpDriveConfig.PR_MAX_ENERGY, releasedLastCycle / WarpDriveConfig.PR_TICK_TIME }; + + } else if (methodName.equals("instability")) { + Object[] retVal = new Object[4]; + for(int i = 0; i < 4; i++) { + retVal[i] = instabilityValues[i]; + } + return retVal; + + } else if (methodName.equals("release")) { + return release(arguments); + + } else if (methodName.equals("releaseRate")) { + return releaseRate(arguments); + + } else if (methodName.equals("releaseAbove")) { + return releaseAbove(arguments); + + } else if (methodName.equals("help")) { + return new Object[] { helpStr(arguments) }; + } + + return null; + } + + // POWER INTERFACES + @Override + public int getPotentialEnergyOutput() { + if (hold) {// still loading/booting => hold output + return 0; + } + int result = 0; + int capacity = Math.max(0, 2 * lastGenerationRate - releasedThisTick); + if (releaseMode == MODE_MANUAL_RELEASE) { + result = Math.min(Math.max(0, containedEnergy ), capacity); + // WarpDrive.debugPrint("PotentialOutput Manual " + result + " RF (" + convertRFtoInternal(result) + " internal) capacity " + capacity); + } else if (releaseMode == MODE_RELEASE_ABOVE) { + result = Math.min(Math.max(0, containedEnergy - releaseAbove), capacity); + // WarpDrive.debugPrint("PotentialOutput Above " + result + " RF (" + convertRFtoInternal(result) + " internal) capacity " + capacity); + } else if (releaseMode == MODE_RELEASE_AT_RATE) { + int remainingRate = Math.max(0, releaseRate - releasedThisTick); + result = Math.min(Math.max(0, containedEnergy ), Math.min(remainingRate, capacity)); + // WarpDrive.debugPrint("PotentialOutput Rated " + result + " RF (" + convertRFtoInternal(result) + " internal) remainingRate " + remainingRate + " RF/t capacity " + capacity); + } + return convertRFtoInternal(result); + } + + @Override + public boolean canOutputEnergy(ForgeDirection from) { + if (from.equals(ForgeDirection.UP) || from.equals(ForgeDirection.DOWN)) { + return true; + } + return false; + } + + @Override + protected void energyOutputDone(int energyOutput_internal) { + int energyOutput_RF = convertInternalToRF(energyOutput_internal); + containedEnergy -= energyOutput_RF; + if (containedEnergy < 0) { + containedEnergy = 0; + } + releasedThisTick += energyOutput_RF; + releasedThisCycle += energyOutput_RF; + // WarpDrive.debugPrint("OutputDone " + energyOutput_internal + " (" + energyOutput_RF + " RF)"); + } + + @Override + public int getEnergyStored() { + return convertRFtoInternal(containedEnergy); + } + + @Override + public int getMaxEnergyStored() { + return convertRFtoInternal(WarpDriveConfig.PR_MAX_ENERGY); + } + + + // Forge overrides + @Override + public void writeToNBT(NBTTagCompound nbt) { + super.writeToNBT(nbt); + nbt.setInteger("energy", containedEnergy); + nbt.setInteger("releaseMode", releaseMode); + nbt.setInteger("releaseRate", releaseRate); + nbt.setInteger("releaseAbove", releaseAbove); + nbt.setDouble("i0", instabilityValues[0]); + nbt.setDouble("i1", instabilityValues[1]); + nbt.setDouble("i2", instabilityValues[2]); + nbt.setDouble("i3", instabilityValues[3]); + nbt.setBoolean("active", active); + } + + @Override + public void readFromNBT(NBTTagCompound nbt) { + super.readFromNBT(nbt); + containedEnergy = nbt.getInteger("energy"); + releaseMode = nbt.getInteger("releaseMode"); + releaseRate = nbt.getInteger("releaseRate"); + releaseAbove = nbt.getInteger("releaseAbove"); + instabilityValues[0] = nbt.getDouble("i0"); + instabilityValues[1] = nbt.getDouble("i1"); + instabilityValues[2] = nbt.getDouble("i2"); + instabilityValues[3] = nbt.getDouble("i3"); + active = nbt.getBoolean("active"); + } + + @Override + public String toString() { + return String.format("%s \'%s\' @ \'%s\' %.2f, %.2f, %.2f", new Object[] { + getClass().getSimpleName(), + this.connectedComputers == null ? "~NULL~" : this.connectedComputers, + worldObj == null ? "~NULL~" : worldObj.getWorldInfo().getWorldName(), + Double.valueOf(xCoord), Double.valueOf(yCoord), Double.valueOf(zCoord)}); + } +} \ No newline at end of file diff --git a/src/cr0s/WarpDrive/machines/TileEntityPowerStore.java b/src/cr0s/WarpDrive/machines/TileEntityPowerStore.java new file mode 100644 index 00000000..bfe15a81 --- /dev/null +++ b/src/cr0s/WarpDrive/machines/TileEntityPowerStore.java @@ -0,0 +1,63 @@ +package cr0s.WarpDrive.machines; + +import cpw.mods.fml.common.Optional; +import cr0s.WarpDrive.WarpDriveConfig; +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.peripheral.IComputerAccess; +import net.minecraftforge.common.ForgeDirection; + +public class TileEntityPowerStore extends WarpEnergyTE { + + public TileEntityPowerStore() { + super(); + peripheralName = "warpdrivePowerStore"; + methodsArray = new String[] { + "getEnergyLevel" + }; + } + + @Override + public int getPotentialEnergyOutput() { + return getEnergyStored(); + } + + @Override + protected void energyOutputDone(int energyOutput) { + consumeEnergy(energyOutput, false); + } + + @Override + public int getMaxEnergyStored() { + return WarpDriveConfig.PS_MAX_ENERGY; + } + + @Override + public boolean canInputEnergy(ForgeDirection from) { + return true; + } + + @Override + public boolean canOutputEnergy(ForgeDirection to) { + return true; + } + + // ComputerCraft IPeripheral methods implementation + @Override + public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws Exception { + String methodName = methodsArray[method]; + if (methodName == "getEnergyLevel") { + return getEnergyLevel(); + } + return null; + } + + @Override + public void attach(IComputerAccess computer) { + // nothing to see here + } + + @Override + public void detach(IComputerAccess computer) { + // nothing to see here + } +} \ No newline at end of file diff --git a/src/cr0s/WarpDrive/machines/TileEntityReactor.java b/src/cr0s/WarpDrive/machines/TileEntityReactor.java new file mode 100644 index 00000000..464bdf3c --- /dev/null +++ b/src/cr0s/WarpDrive/machines/TileEntityReactor.java @@ -0,0 +1,1121 @@ +package cr0s.WarpDrive.machines; + +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityChest; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.MathHelper; +import net.minecraft.world.WorldServer; +import net.minecraftforge.common.DimensionManager; +import net.minecraftforge.common.ForgeDirection; +import cpw.mods.fml.common.FMLCommonHandler; +import cr0s.WarpDrive.*; +import cr0s.WarpDrive.data.Jumpgate; +import cr0s.WarpDrive.data.MovingEntity; +import cr0s.WarpDrive.world.SpaceTeleporter; + +/** + * @author Cr0s + */ +public class TileEntityReactor extends WarpEnergyTE +{ + public Boolean ready; + + public Boolean launchState = false; + + public final int JUMP_UP = -1; + public final int JUMP_DOWN = -2; + public int dx, dz; + private int direction; + + public int maxX, maxY, maxZ; + public int minX, minY, minZ; + + public int shipFront, shipBack; + public int shipLeft, shipRight; + public int shipUp, shipDown; + public int shipLength; + public int shipVolume; + private ReactorMode currentMode = ReactorMode.IDLE; + + public enum ReactorMode { + IDLE ( 0 ), + BASIC_JUMP ( 1 ), // 0-128 + LONG_JUMP ( 2 ), // 0-12800 + TELEPORT ( 3 ), + BEACON_JUMP ( 4 ), // Jump ship by beacon + HYPERSPACE ( 5 ), // Jump to/from Hyperspace + GATE_JUMP ( 6 ); // Jump via jumpgate + + private final int code; + ReactorMode(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + } + + private int warmupTime = 0; + private int cooldownTime = 0; + public int randomWarmupAddition = 0; + + private int chestTeleportUpdateTicks = 0; + private int registryUpdateTicks = 15; + public String coreFrequency = "default"; + + public int isolationBlocksCount = 0; + public double isolationRate = 0.0D; + public int isolationUpdateTicks = 0; + + public TileEntityProtocol controller; + + private boolean soundPlayed = false; + + @Override + public void updateEntity() { + if (FMLCommonHandler.instance().getEffectiveSide().isClient()) { + return; + } + super.updateEntity(); + + // Always cooldown + if (cooldownTime > 0) { + cooldownTime--; + warmupTime = 0; + } + + // Update state + if (cooldownTime > 0) { // cooling down (2) + if (getBlockMetadata() != 2) { + worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, 2, 1 + 2); + } + } else if (controller == null) { // not connected (0) + if (getBlockMetadata() != 0) { + worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, 0, 1 + 2); + } + } else if (controller.isJumpFlag() || this.controller.isSummonAllFlag() || !this.controller.getToSummon().isEmpty()) { // active (1) + if (getBlockMetadata() != 1) { + worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, 1, 1 + 2); + } + } else { // inactive + if (getBlockMetadata() != 0) { + worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, 0, 1 + 2); + } + } + + // Update warp core in cores registry + registryUpdateTicks++; + if (registryUpdateTicks > WarpDriveConfig.WC_CORES_REGISTRY_UPDATE_INTERVAL_SECONDS * 20) { + registryUpdateTicks = 0; + WarpDrive.warpCores.updateInRegistry(this); +// WarpDrive.warpCores.printRegistry(); +// WarpDrive.debugPrint("" + this + " controller is " + controller + ", warmupTime " + warmupTime + ", currentMode " + currentMode + ", jumpFlag " + (controller == null ? "NA" : controller.isJumpFlag()) + ", cooldownTime " + cooldownTime); + + TileEntity c = findControllerBlock(); + if (c == null) { + controller = null; + warmupTime = 0; + soundPlayed = false; + return; + } + controller = (TileEntityProtocol)c; + } + + isolationUpdateTicks++; + if (isolationUpdateTicks > WarpDriveConfig.WC_ISOLATION_UPDATE_INTERVAL_SECONDS * 20) { + isolationUpdateTicks = 0; + updateIsolationState(); + } + + if (controller == null) { + return; + } + + currentMode = controller.getMode(); + + StringBuilder reason = new StringBuilder(); + + if ((controller.isJumpFlag() && (isolationUpdateTicks == 1)) || this.controller.isSummonAllFlag() || !this.controller.getToSummon().isEmpty()) { + if (!validateShipSpatialParameters(reason)) { + if (controller.isJumpFlag()) { + controller.setJumpFlag(false); + messageToAllPlayersOnShip(reason.toString()); + } + warmupTime = 0; + soundPlayed = false; + return; + } + + if (this.controller.isSummonAllFlag()) { + summonPlayers(); + controller.setSummonAllFlag(false); + } else if (!this.controller.getToSummon().isEmpty()) { + summonSinglePlayer(this.controller.getToSummon()); + this.controller.setToSummon(""); + } + } + + switch (currentMode) { + case TELEPORT: + if (worldObj.isBlockIndirectlyGettingPowered(xCoord, yCoord, zCoord)) { + if (isChestSummonMode()) { + chestTeleportUpdateTicks++; + if (chestTeleportUpdateTicks >= 20) { + summonPlayersByChestCode(); + chestTeleportUpdateTicks = 0; + } + } else { + teleportPlayersToSpace(); + } + } else { + chestTeleportUpdateTicks = 0; + } + break; + + case BASIC_JUMP: + case LONG_JUMP: + case BEACON_JUMP: + case HYPERSPACE: + case GATE_JUMP: + if (controller.isJumpFlag()) { + // Compute warm-up time + int targetWarmup = 0; + switch (currentMode) { + case BASIC_JUMP: + case LONG_JUMP: + if (controller.getDistance() < 50) { + targetWarmup = WarpDriveConfig.WC_WARMUP_SHORTJUMP_SECONDS * 20; + } else { + targetWarmup = WarpDriveConfig.WC_WARMUP_LONGJUMP_SECONDS * 20; + } + break; + + case BEACON_JUMP: + case HYPERSPACE: + case GATE_JUMP: + default: + targetWarmup = WarpDriveConfig.WC_WARMUP_LONGJUMP_SECONDS * 20; + break; + } + // Select best sound file and adjust offset + int soundThreshold = 0; + String soundFile = ""; + if (targetWarmup < 10 * 20) { + soundThreshold = targetWarmup - 4 * 20; + soundFile = "warpdrive:warp_4s"; + } else if (targetWarmup > 29 * 20) { + soundThreshold = targetWarmup - 30 * 20; + soundFile = "warpdrive:warp_30s"; + } else { + soundThreshold = targetWarmup - 10 * 20; + soundFile = "warpdrive:warp_10s"; + } + // Add random duration + soundThreshold += randomWarmupAddition; + + // Check cooldown time + if (cooldownTime > 0) { + if (cooldownTime % 20 == 0) { + int seconds = cooldownTime / 20; + if ((seconds < 5) || ((seconds < 30) && (seconds % 5 == 0)) || (seconds % 10 == 0)) { + messageToAllPlayersOnShip("Warp core is cooling down... " + cooldownTime / 20 + "s to go..."); + } + } + return; + } + + // Set up activated animation + if (warmupTime == 0) { + messageToAllPlayersOnShip("Running pre-jump checklist..."); + + // update ship parameters + if (!validateShipSpatialParameters(reason)) { + controller.setJumpFlag(false); + messageToAllPlayersOnShip(reason.toString()); + return; + } + // WarpDrive.debugPrint(this + " Giving warp sickness targetWarmup " + targetWarmup + " distance " + controller.getDistance()); + makePlayersOnShipDrunk(targetWarmup + WarpDriveConfig.WC_WARMUP_RANDOM_TICKS); + } + + if (!soundPlayed && (soundThreshold > warmupTime)) { + // WarpDrive.debugPrint(this + " Playing sound effect '" + soundFile + "' soundThreshold " + soundThreshold + " warmupTime " + warmupTime); + worldObj.playSoundEffect(xCoord + 0.5f, yCoord + 0.5f, zCoord + 0.5f, soundFile, 4F, 1F); + soundPlayed = true; + } + + // Awaiting cool-down time + if (warmupTime < (targetWarmup + randomWarmupAddition)) { + warmupTime++; + return; + } + + warmupTime = 0; + soundPlayed = false; + + if (!validateShipSpatialParameters(reason)) { + controller.setJumpFlag(false); + messageToAllPlayersOnShip(reason.toString()); + return; + } + + if (WarpDrive.warpCores.isWarpCoreIntersectsWithOthers(this)) { + controller.setJumpFlag(false); + messageToAllPlayersOnShip("Warp field intersects with other ship's field. Cannot jump."); + return; + } + + if (WarpDrive.cloaks.isCloaked(worldObj.provider.dimensionId, xCoord, yCoord, zCoord)) { + controller.setJumpFlag(false); + messageToAllPlayersOnShip("Core is inside a cloaking field. Aborting. Disable cloaking field to jump!"); + return; + } + + doJump(); + cooldownTime = WarpDriveConfig.WC_COOLDOWN_INTERVAL_SECONDS * 20; + controller.setJumpFlag(false); + } else { + warmupTime = 0; + } + break; + } + } + + public void messageToAllPlayersOnShip(String msg) { + AxisAlignedBB axisalignedbb = AxisAlignedBB.getBoundingBox(this.minX, this.minY, this.minZ, this.maxX + 0.99D, this.maxY + 0.99D, this.maxZ + 0.99D); + List list = worldObj.getEntitiesWithinAABBExcludingEntity(null, axisalignedbb); + + WarpDrive.print("" + (FMLCommonHandler.instance().getEffectiveSide().isClient() ? "Client":"Server") + this + " messageToAllPlayersOnShip: " + msg); + for (Object o : list) { + if (o == null || !(o instanceof EntityPlayer)) { + continue; + } + + ((EntityPlayer)o).addChatMessage("[" + (coreFrequency.length() > 0 ? coreFrequency : "WarpCore") + "] " + msg); + } + } + + private void updateIsolationState() { + // Search block in cube around core + int xmax, ymax, zmax; + int xmin, ymin, zmin; + xmin = xCoord - WarpDriveConfig.WR_MAX_ISOLATION_RANGE; + xmax = xCoord + WarpDriveConfig.WR_MAX_ISOLATION_RANGE; + + zmin = zCoord - WarpDriveConfig.WR_MAX_ISOLATION_RANGE; + zmax = zCoord + WarpDriveConfig.WR_MAX_ISOLATION_RANGE; + + // scan 1 block higher to encourage putting isolation block on both ground and ceiling + ymin = Math.max( 0, yCoord - WarpDriveConfig.WR_MAX_ISOLATION_RANGE + 1); + ymax = Math.min(255, yCoord + WarpDriveConfig.WR_MAX_ISOLATION_RANGE + 1); + + int newCount = 0; + + // Search for warp isolation blocks + for (int y = ymin; y <= ymax; y++) { + for (int x = xmin; x <= xmax; x++) { + for (int z = zmin; z <= zmax; z++) { + if (worldObj.getBlockId(x, y, z) == WarpDriveConfig.isolationID) { + newCount++; + } + } + } + } + isolationBlocksCount = newCount; + if (isolationBlocksCount >= WarpDriveConfig.WR_MIN_ISOLATION_BLOCKS) { + isolationRate = WarpDriveConfig.WR_MIN_ISOLATION_EFFECT + + (isolationBlocksCount - WarpDriveConfig.WR_MIN_ISOLATION_BLOCKS) // bonus blocks + * (WarpDriveConfig.WR_MAX_ISOLATION_EFFECT - WarpDriveConfig.WR_MIN_ISOLATION_EFFECT) + / (WarpDriveConfig.WR_MAX_ISOLATION_BLOCKS - WarpDriveConfig.WR_MIN_ISOLATION_BLOCKS); + } else { + isolationRate = 0.0D; + } + // WarpDrive.debugPrint(this + " Isolation updated to " + isolationBlocksCount + " (" + String.format("%.1f", isolationRate * 100) + "%)"); + } + + private void makePlayersOnShipDrunk(int tickDuration) { + AxisAlignedBB axisalignedbb = AxisAlignedBB.getBoundingBox(this.minX, this.minY, this.minZ, this.maxX, this.maxY, this.maxZ); + List list = worldObj.getEntitiesWithinAABBExcludingEntity(null, axisalignedbb); + + for (Object o : list) { + if (o == null || !(o instanceof EntityPlayer)) { + continue; + } + + // Set "drunk" effect + ((EntityPlayer)o).addPotionEffect(new PotionEffect(Potion.confusion.id, tickDuration, 0, true)); + } + } + + private void summonPlayers() + { + AxisAlignedBB aabb = AxisAlignedBB.getBoundingBox(this.minX, this.minY, this.minZ, this.maxX, this.maxY, this.maxZ); + + for (int i = 0; i < controller.players.size(); i++) + { + String nick = controller.players.get(i); + EntityPlayerMP player = MinecraftServer.getServer().getConfigurationManager().getPlayerForUsername(nick); + + if (player != null && !testBB(aabb, MathHelper.floor_double(player.posX), MathHelper.floor_double(player.posY), MathHelper.floor_double(player.posZ))) + { + summonPlayer(player, xCoord + dx, yCoord, zCoord + dz); + } + } + } + + private void summonSinglePlayer(String nickname) + { + AxisAlignedBB aabb = AxisAlignedBB.getBoundingBox(this.minX, this.minY, this.minZ, this.maxX, this.maxY, this.maxZ); + + for (int i = 0; i < controller.players.size(); i++) + { + String nick = controller.players.get(i); + EntityPlayerMP player = MinecraftServer.getServer().getConfigurationManager().getPlayerForUsername(nick); + + if (player != null && nick.equals(nickname) && !testBB(aabb, MathHelper.floor_double(player.posX), MathHelper.floor_double(player.posY), MathHelper.floor_double(player.posZ))) + { + summonPlayer(player, xCoord + dx, yCoord, zCoord + dz); + return; + } + } + } + + private void summonPlayer(EntityPlayerMP player, int x, int y, int z) { + if (consumeEnergy(WarpDriveConfig.WC_ENERGY_PER_ENTITY_TO_SPACE, false)) { + player.setPositionAndUpdate(x, y, z); + + if (player.dimension != worldObj.provider.dimensionId) { + player.mcServer.getConfigurationManager().transferPlayerToDimension(player, this.worldObj.provider.dimensionId, new SpaceTeleporter(DimensionManager.getWorld(this.worldObj.provider.dimensionId), 0, MathHelper.floor_double(player.posX), MathHelper.floor_double(player.posY), MathHelper.floor_double(player.posZ))); + } + } + } + + public boolean validateShipSpatialParameters(StringBuilder reason) { + if (controller == null) { + reason.append("TileEntityReactor.validateShipSpatialParameters: no controller detected!"); + return false; + } + direction = controller.getDirection(); + shipFront = controller.getFront(); + shipRight = controller.getRight(); + shipUp = controller.getUp(); + shipBack = controller.getBack(); + shipLeft = controller.getLeft(); + shipDown = controller.getDown(); + + int x1 = 0, x2 = 0, z1 = 0, z2 = 0; + + if (Math.abs(dx) > 0) { + if (dx == 1) { + x1 = xCoord - shipBack; + x2 = xCoord + shipFront; + z1 = zCoord - shipLeft; + z2 = zCoord + shipRight; + } else { + x1 = xCoord - shipFront; + x2 = xCoord + shipBack; + z1 = zCoord - shipRight; + z2 = zCoord + shipLeft; + } + } else if (Math.abs(dz) > 0) { + if (dz == 1) { + z1 = zCoord - shipBack; + z2 = zCoord + shipFront; + x1 = xCoord - shipRight; + x2 = xCoord + shipLeft; + } else { + z1 = zCoord - shipFront; + z2 = zCoord + shipBack; + x1 = xCoord - shipLeft; + x2 = xCoord + shipRight; + } + } + + if (x1 < x2) { + minX = x1; + maxX = x2; + } else { + minX = x2; + maxX = x1; + } + + if (z1 < z2) { + minZ = z1; + maxZ = z2; + } else { + minZ = z2; + maxZ = z1; + } + + minY = yCoord - shipDown; + maxY = yCoord + shipUp; + shipLength = 0; + + switch (direction) { + case 0: + case 180: + shipLength = shipBack + shipFront; + break; + + case 90: + case 270: + shipLength = shipLeft + shipRight; + break; + + case -1: + case -2: + shipLength = shipDown + shipUp; + break; + + default: + reason.append("Invalid jump direction " + direction); + return false; + } + + // Ship side is too big + if ((shipBack + shipFront) > WarpDriveConfig.WC_MAX_SHIP_SIDE || (shipLeft + shipRight) > WarpDriveConfig.WC_MAX_SHIP_SIDE || (shipDown + shipUp) > WarpDriveConfig.WC_MAX_SHIP_SIDE) { + reason.append("Ship is too big (max is " + WarpDriveConfig.WC_MAX_SHIP_SIDE + " per side)"); + return false; + } + + boolean isUnlimited = false; + AxisAlignedBB axisalignedbb = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX + 0.99D, maxY + 0.99D, maxZ + 0.99D); + List list = worldObj.getEntitiesWithinAABBExcludingEntity(null, axisalignedbb); + for (Object o : list) { + if (o == null || !(o instanceof EntityPlayer)) { + continue; + } + + String playerName = ((EntityPlayer)o).username; + for (String unlimiteName : WarpDriveConfig.WC_UNLIMITED_PLAYERNAMES) { + isUnlimited = isUnlimited || unlimiteName.equals(playerName); + } + } + + shipVolume = computeRealShipVolume(); + if (!isUnlimited && shipVolume > WarpDriveConfig.WC_MAX_SHIP_VOLUME_ON_SURFACE && worldObj.provider.dimensionId == 0) { + reason.append("Ship is too big for the overworld (max is " + WarpDriveConfig.WC_MAX_SHIP_VOLUME_ON_SURFACE + " blocks)"); + return false; + } + + return true; + } + + private void doBeaconJump() + { + // Search beacon coordinates + String freq = controller.getBeaconFrequency(); + int beaconX = 0, beaconZ = 0; + boolean isBeaconFound = false; + EntityPlayerMP player; + + for (int i = 0; i < MinecraftServer.getServer().getConfigurationManager().playerEntityList.size(); i++) + { + player = (EntityPlayerMP)MinecraftServer.getServer().getConfigurationManager().playerEntityList.get(i); + + // Skip players from other dimensions + if (player.dimension != worldObj.provider.dimensionId) + { + continue; + } + + TileEntity te = worldObj.getBlockTileEntity(MathHelper.floor_double(player.posX), MathHelper.floor_double(player.posY) - 1, MathHelper.floor_double(player.posZ)); + + if (te != null && (te instanceof TileEntityProtocol)) + { + if (((TileEntityProtocol)te).getBeaconFrequency().equals(freq)) + { + beaconX = te.xCoord; + beaconZ = te.zCoord; + isBeaconFound = true; + break; + } + } + } + + // Now make jump to a beacon + if (isBeaconFound) { + // Consume energy + if (consumeEnergy(calculateRequiredEnergy(currentMode, shipVolume, controller.getDistance()), false)) { + WarpDrive.print(this + " Moving ship to beacon (" + beaconX + "; " + yCoord + "; " + beaconZ + ")"); + EntityJump jump = new EntityJump(worldObj, xCoord, yCoord, zCoord, dx, dz, this, false, 1, 0, true, beaconX, yCoord, beaconZ); + jump.maxX = maxX; + jump.minX = minX; + jump.maxZ = maxZ; + jump.minZ = minZ; + jump.maxY = maxY; + jump.minY = minY; + jump.shipLength = shipLength; + jump.on = true; + worldObj.spawnEntityInWorld(jump); + } else { + messageToAllPlayersOnShip("Insufficient energy level"); + } + } else { + WarpDrive.print(this + " Beacon '" + freq + "' is unknown."); + } + } + + private boolean isShipInJumpgate(Jumpgate jg, StringBuilder reason) + { + AxisAlignedBB aabb = jg.getGateAABB(); + WarpDrive.debugPrint("[TEWarpCore] Jumpgate " + jg.name + " AABB is " + aabb); + int countBlocksInside = 0; + int countBlocksTotal = 0; + + if (aabb.isVecInside(worldObj.getWorldVec3Pool().getVecFromPool(maxX - minX, maxY - minY, maxZ - minZ))) + { + return true; + } + + for (int x = minX; x <= maxX; x++) + { + for (int z = minZ; z <= maxZ; z++) + { + for (int y = minY; y <= maxY; y++) + { + int blockID = worldObj.getBlockId(x, y, z); + + if (worldObj.isAirBlock(x, y, z) && (blockID != WarpDriveConfig.airID)) + { + continue; + } + if (aabb.minX <= x && aabb.maxX >= x && aabb.minY <= y && aabb.maxY >= y && aabb.minZ <= z && aabb.maxZ >= z) + { + countBlocksInside++; + } + countBlocksTotal++; + } + } + } + + float percent = 0F; + if (shipVolume != 0) + { + percent = Math.round((((countBlocksInside * 1.0F) / shipVolume) * 100.0F) * 10.0F) / 10.0F; + } + if (shipVolume != countBlocksTotal) + { + WarpDrive.print(this + " Ship volume has changed from " + shipVolume + " to " + countBlocksTotal + " blocks"); + } + WarpDrive.debugPrint("Ship has " + countBlocksInside + " / " + shipVolume + " blocks (" + percent + "%) in jumpgate '" + jg.name + "'"); + // At least 80% of ship must be inside jumpgate + if (percent > 80F) + { + return true; + } + else if (percent <= 0.001) + { + reason.append("Ship is not inside a jumpgate. Jump rejected. Nearest jumpgate is " + jg.toNiceString()); + return false; + } + else + { + reason.append("Ship is only " + percent + "% inside a jumpgate. Sorry, we'll loose too much crew as is, jump rejected."); + return false; + } + } + + private boolean isFreePlaceForShip(int destX, int destY, int destZ) + { + int newX, newY, newZ; + + if (destY + shipUp > 255 || destY - shipDown < 5) + { + return false; + } + + int moveX = destX - xCoord; + int moveY = destY - yCoord; + int moveZ = destZ - zCoord; + + for (int x = minX; x <= maxX; x++) + { + for (int z = minZ; z <= maxZ; z++) + { + for (int y = minY; y <= maxY; y++) + { + if (!worldObj.isAirBlock(x, y, z)) + { + newX = moveX + x; + newY = moveY + y; + newZ = moveZ + z; + + if (!worldObj.isAirBlock(newX, newY, newZ)) + { + return false; + } + } + } + } + } + + return true; + } + + private void doGateJump() + { + // Search nearest jump-gate + String gateName = controller.getTargetJumpgateName(); + Jumpgate targetGate = WarpDrive.jumpgates.findGateByName(gateName); + + if (targetGate == null) + { + messageToAllPlayersOnShip("Destination jumpgate '" + gateName + "' is unknown. Check jumpgate name."); + this.controller.setJumpFlag(false); + return; + } + + // Now make jump to a beacon + int gateX = targetGate.xCoord; + int gateY = targetGate.yCoord; + int gateZ = targetGate.zCoord; + int destX = gateX; + int destY = gateY; + int destZ = gateZ; + Jumpgate nearestGate = WarpDrive.jumpgates.findNearestGate(xCoord, yCoord, zCoord); + + StringBuilder reason = new StringBuilder(); + if (!isShipInJumpgate(nearestGate, reason)) + { + messageToAllPlayersOnShip(reason.toString()); + this.controller.setJumpFlag(false); + return; + } + + // If gate is blocked by obstacle + if (!isFreePlaceForShip(gateX, gateY, gateZ)) + { + // Randomize destination coordinates and check for collision with obstacles around jumpgate + // Try to find good place for ship + int numTries = 10; // num tries to check for collision + boolean placeFound = false; + + for (; numTries > 0; numTries--) + { + // randomize destination coordinates around jumpgate + destX = gateX + ((worldObj.rand.nextBoolean()) ? -1 : 1) * (20 + worldObj.rand.nextInt(100)); + destZ = gateZ + ((worldObj.rand.nextBoolean()) ? -1 : 1) * (20 + worldObj.rand.nextInt(100)); + destY = gateY + ((worldObj.rand.nextBoolean()) ? -1 : 1) * (20 + worldObj.rand.nextInt(50)); + + // check for collision + if (isFreePlaceForShip(destX, destY, destZ)) + { + placeFound = true; + break; + } + } + + if (!placeFound) + { + messageToAllPlayersOnShip("Destination gate is blocked by obstacles. Aborting..."); + this.controller.setJumpFlag(false); + return; + } + + WarpDrive.print("[GATE] Place found over " + (10 - numTries) + " tries."); + } + + // Consume energy + if (consumeEnergy(calculateRequiredEnergy(currentMode, shipVolume, controller.getDistance()), false)) { + WarpDrive.print(this + " Moving ship to a place around gate '" + targetGate.name + "' (" + destX + "; " + destY + "; " + destZ + ")"); + EntityJump jump = new EntityJump(worldObj, xCoord, yCoord, zCoord, dx, dz, this, false, 1, 0, true, destX, destY, destZ); + jump.maxX = maxX; + jump.minX = minX; + jump.maxZ = maxZ; + jump.minZ = minZ; + jump.maxY = maxY; + jump.minY = minY; + jump.shipLength = shipLength; + jump.on = true; + worldObj.spawnEntityInWorld(jump); + } else { + messageToAllPlayersOnShip("Insufficient energy level"); + } + } + + private void doJump() { + int distance = controller.getDistance(); + int requiredEnergy = calculateRequiredEnergy(currentMode, shipVolume, distance); + + if (!consumeEnergy(requiredEnergy, true)) { + messageToAllPlayersOnShip("Insufficient energy to jump! Core is currently charged with " + getEnergyStored() + " EU while jump requires " + requiredEnergy + " EU"); + this.controller.setJumpFlag(false); + return; + } + + String shipInfo = "" + shipVolume + " blocks inside (" + minX + ", " + minY + ", " + minZ + ") to (" + maxX + ", " + maxY + ", " + maxZ + ")"; + if (currentMode == ReactorMode.GATE_JUMP) { + WarpDrive.print(this + " Performing gate jump of " + shipInfo); + doGateJump(); + return; + } else if (currentMode == ReactorMode.BEACON_JUMP) { + WarpDrive.print(this + " Performing beacon jump of " + shipInfo); + doBeaconJump(); + return; + } else if (currentMode == ReactorMode.HYPERSPACE) { + WarpDrive.print(this + " Performing hyperspace jump of " + shipInfo); + + // Check ship size for hyper-space jump + if (shipVolume < WarpDriveConfig.WC_MIN_SHIP_VOLUME_FOR_HYPERSPACE) { + Jumpgate nearestGate = null; + if (WarpDrive.jumpgates == null) { + WarpDrive.print(this + " WarpDrive.instance.jumpGates is NULL!"); + } else { + nearestGate = WarpDrive.jumpgates.findNearestGate(xCoord, yCoord, zCoord); + } + + StringBuilder reason = new StringBuilder(); + if (nearestGate == null || !isShipInJumpgate(nearestGate, reason)) { + this.messageToAllPlayersOnShip("Ship is too small (" + shipVolume + "/" + WarpDriveConfig.WC_MIN_SHIP_VOLUME_FOR_HYPERSPACE + "). Insufficient ship mass to open hyperspace portal. Use a jumpgate to reach or exit hyperspace."); + this.controller.setJumpFlag(false); + return; + } + } + } else if (currentMode == ReactorMode.BASIC_JUMP) { + WarpDrive.print(this + " Performing basic jump of " + shipInfo + " toward direction " + direction + " over " + distance + " blocks."); + } else if (currentMode == ReactorMode.LONG_JUMP) { + WarpDrive.print(this + " Performing long jump of " + shipInfo + " toward direction " + direction + " over " + distance + " blocks."); + } else { + WarpDrive.print(this + " Performing some jump #" + currentMode + " of " + shipInfo); + } + + if (currentMode == ReactorMode.BASIC_JUMP || currentMode == ReactorMode.LONG_JUMP || currentMode == ReactorMode.HYPERSPACE) { + if (!consumeEnergy(requiredEnergy, false)) { + messageToAllPlayersOnShip("Insufficient energy level"); + return; + } + + if (this.currentMode == ReactorMode.BASIC_JUMP) { + distance += shipLength; + } + + if (currentMode == ReactorMode.LONG_JUMP && (direction != -1) && (direction != -2)) { + if (worldObj.provider.dimensionId == WarpDriveConfig.G_HYPERSPACE_DIMENSION_ID) { + distance *= 100; + } + } + + WarpDrive.debugPrint("" + this + " Distance adjusted to " + distance + " blocks."); + EntityJump jump = new EntityJump(worldObj, xCoord, yCoord, zCoord, dx, dz, this, (currentMode == ReactorMode.HYPERSPACE), distance, direction, false, 0, 0, 0); + jump.maxX = maxX; + jump.minX = minX; + jump.maxZ = maxZ; + jump.minZ = minZ; + jump.maxY = maxY; + jump.minY = minY; + jump.shipLength = shipLength; + jump.on = true; + worldObj.spawnEntityInWorld(jump); + } + } + + private void teleportPlayersToSpace() { + if (worldObj.provider.dimensionId != WarpDriveConfig.G_SPACE_DIMENSION_ID) { + AxisAlignedBB axisalignedbb = AxisAlignedBB.getBoundingBox(xCoord - 2, yCoord - 1, zCoord - 2, xCoord + 2, yCoord + 4, zCoord + 2); + List list = worldObj.getEntitiesWithinAABBExcludingEntity(null, axisalignedbb); + + WorldServer spaceWorld = DimensionManager.getWorld(WarpDriveConfig.G_SPACE_DIMENSION_ID); + for (Object o : list) { + if (!consumeEnergy(WarpDriveConfig.WC_ENERGY_PER_ENTITY_TO_SPACE, false)) { + return; + } + + Entity entity = (Entity) o; + int x = MathHelper.floor_double(entity.posX); + int z = MathHelper.floor_double(entity.posZ); + //int y = MathHelper.floor_double(entity.posY); + final int WOOL_BLOCK_ID = 35; + int newY; + + for (newY = 254; newY > 0; newY--) { + if (spaceWorld.getBlockId(x, newY, z) == WOOL_BLOCK_ID) { + break; + } + } + + if (newY <= 0) { + newY = 254; + } + + if (entity instanceof EntityPlayerMP) { + ((EntityPlayerMP) entity).mcServer.getConfigurationManager().transferPlayerToDimension(((EntityPlayerMP) entity), WarpDriveConfig.G_SPACE_DIMENSION_ID, new SpaceTeleporter(DimensionManager.getWorld(WarpDriveConfig.G_SPACE_DIMENSION_ID), 0, x, 256, z)); + + if (spaceWorld.isAirBlock(x, newY, z)) { + spaceWorld.setBlock(x , newY, z , Block.stone.blockID, 0, 2); + spaceWorld.setBlock(x + 1, newY, z , Block.stone.blockID, 0, 2); + spaceWorld.setBlock(x - 1, newY, z , Block.stone.blockID, 0, 2); + spaceWorld.setBlock(x , newY, z + 1, Block.stone.blockID, 0, 2); + spaceWorld.setBlock(x , newY, z - 1, Block.stone.blockID, 0, 2); + spaceWorld.setBlock(x + 1, newY, z + 1, Block.stone.blockID, 0, 2); + spaceWorld.setBlock(x - 1, newY, z - 1, Block.stone.blockID, 0, 2); + spaceWorld.setBlock(x + 1, newY, z - 1, Block.stone.blockID, 0, 2); + spaceWorld.setBlock(x - 1, newY, z + 1, Block.stone.blockID, 0, 2); + } + + ((EntityPlayerMP) entity).setPositionAndUpdate(x + 0.5D, newY + 2.0D, z + 0.5D); + } + } + } + } + + private void summonPlayersByChestCode() + { + if (worldObj.getBlockTileEntity(xCoord, yCoord + 1, zCoord) == null) + { + return; + } + + TileEntityChest chest = (TileEntityChest)worldObj.getBlockTileEntity(xCoord, yCoord + 1, zCoord); + EntityPlayerMP player; + + for (int i = 0; i < MinecraftServer.getServer().getConfigurationManager().playerEntityList.size(); i++) + { + player = (EntityPlayerMP)MinecraftServer.getServer().getConfigurationManager().playerEntityList.get(i); + + if (checkPlayerInventory(chest, player)) + { + WarpDrive.print(this + " Summoning " + player.username); + summonPlayer(player, xCoord, yCoord + 2, zCoord); + } + } + } + + private static boolean checkPlayerInventory(TileEntityChest chest, EntityPlayerMP player) { + Boolean result = false; + final int MIN_KEY_LENGTH = 5; + int keyLength = 0; + + for (int index = 0; index < chest.getSizeInventory(); index++) { + ItemStack chestItem = chest.getStackInSlot(index); + ItemStack playerItem = player.inventory.getStackInSlot(9 + index); + + if (chestItem == null) { + continue; + } + + if (playerItem == null || chestItem.itemID != playerItem.itemID || chestItem.getItemDamage() != playerItem.getItemDamage() || chestItem.stackSize != playerItem.stackSize) { + return false; + } else { + result = true; + } + + keyLength++; + } + + if (keyLength < MIN_KEY_LENGTH) { + WarpDrive.print("[ChestCode] Key is too short: " + keyLength + " < " + MIN_KEY_LENGTH); + return false; + } + + return result; + } + + private Boolean isChestSummonMode() + { + TileEntity te = worldObj.getBlockTileEntity(xCoord, yCoord + 1, zCoord); + + if (te != null) + { + return (te instanceof TileEntityChest); + } + + return false; + } + + private static boolean testBB(AxisAlignedBB axisalignedbb, int x, int y, int z) + { + return axisalignedbb.minX <= x && axisalignedbb.maxX >= x && axisalignedbb.minY <= y && axisalignedbb.maxY >= y && axisalignedbb.minZ <= z && axisalignedbb.maxZ >= z; + } + + @Override + public String getStatus() { + return getBlockType().getLocalizedName() + String.format(" '%s' energy level is %.0f/%.0f EU.", coreFrequency, convertInternalToEU(getEnergyStored()), convertInternalToEU(getMaxEnergyStored())) + + ((cooldownTime > 0) ? ("\n" + (cooldownTime / 20) + " s left of cooldown.") : ((isolationBlocksCount > 0) ? ("\n" + isolationBlocksCount + " active isolation blocks") : "")); + } + + public static int calculateRequiredEnergy(ReactorMode currentMode, int shipVolume, int jumpDistance) { + switch (currentMode) { + case TELEPORT: + return WarpDriveConfig.WC_ENERGY_PER_ENTITY_TO_SPACE; + + case BASIC_JUMP: + return (WarpDriveConfig.WC_ENERGY_PER_BLOCK_MODE1 * shipVolume) + (WarpDriveConfig.WC_ENERGY_PER_DISTANCE_MODE1 * jumpDistance); + + case LONG_JUMP: + return (WarpDriveConfig.WC_ENERGY_PER_BLOCK_MODE2 * shipVolume) + (WarpDriveConfig.WC_ENERGY_PER_DISTANCE_MODE2 * jumpDistance); + + case HYPERSPACE: + return WarpDriveConfig.WC_MAX_ENERGY_VALUE / 10; // 10% of maximum + + case BEACON_JUMP: + return WarpDriveConfig.WC_MAX_ENERGY_VALUE / 2; // half of maximum + + case GATE_JUMP: + return 2 * shipVolume; + } + + return WarpDriveConfig.WC_MAX_ENERGY_VALUE; + } + + private int computeRealShipVolume() { + int realShipVolume = 0; + + try { + for (int x = minX; x <= maxX; x++) { + for (int z = minZ; z <= maxZ; z++) { + for (int y = minY; y <= maxY; y++) { + int blockID = worldObj.getBlockId(x, y, z); + + if (WarpDriveConfig.isAirBlock(worldObj, blockID, x, y, z) && (blockID != WarpDriveConfig.airID)) { + continue; + } + + realShipVolume++; + } + } + } + } catch(Exception e) { + e.printStackTrace(); + } + + return realShipVolume; + } + + private TileEntity findControllerBlock() + { + TileEntity result; + result = worldObj.getBlockTileEntity(xCoord + 1, yCoord, zCoord); + + if (result != null && result instanceof TileEntityProtocol) + { + dx = 1; + dz = 0; + return result; + } + + result = worldObj.getBlockTileEntity(xCoord - 1, yCoord, zCoord); + + if (result != null && result instanceof TileEntityProtocol) + { + dx = -1; + dz = 0; + return result; + } + + result = worldObj.getBlockTileEntity(xCoord, yCoord, zCoord + 1); + + if (result != null && result instanceof TileEntityProtocol) + { + dx = 0; + dz = 1; + return result; + } + + result = worldObj.getBlockTileEntity(xCoord, yCoord, zCoord - 1); + + if (result != null && result instanceof TileEntityProtocol) + { + dx = 0; + dz = -1; + return result; + } + + return null; + } + + public int getCooldown() { + return cooldownTime; + } + + public boolean isHidden() { + if (cooldownTime <= 0 && worldObj.rand.nextDouble() < isolationRate) { + // WarpDrive.debugPrint(this + " Core '" + coreFrequency + "' is hidden"); + return true; + } + + return false; + } + + @Override + public int getMaxEnergyStored() { + return WarpDriveConfig.WC_MAX_ENERGY_VALUE; + } + + @Override + public double demandedEnergyUnits() { + if (this.controller != null && controller.getMode() == ReactorMode.IDLE) { + return 0.0D; + } + + return super.demandedEnergyUnits(); + } + + @Override + public int getMaxSafeInput() { + return Integer.MAX_VALUE; + } + + @Override + public boolean canInputEnergy(ForgeDirection from) { + return true; + } + + @Override + public void readFromNBT(NBTTagCompound tag) + { + super.readFromNBT(tag); + coreFrequency = tag.getString("corefrequency"); + isolationBlocksCount = tag.getInteger("isolation"); + cooldownTime = tag.getInteger("cooldownTime"); + WarpDrive.warpCores.updateInRegistry(this); + } + + @Override + public void writeToNBT(NBTTagCompound tag) + { + super.writeToNBT(tag); + tag.setString("corefrequency", coreFrequency); + tag.setInteger("isolation", isolationBlocksCount); + tag.setInteger("cooldownTime", cooldownTime); + } + + @Override + public void onChunkUnload() { + WarpDrive.warpCores.removeFromRegistry(this); + super.onChunkUnload(); + } + + @Override + public void validate() { + super.validate(); + WarpDrive.warpCores.updateInRegistry(this); + } + + @Override + public void invalidate() { + WarpDrive.warpCores.removeFromRegistry(this); + super.invalidate(); + } + + @Override + public String toString() { + return String.format("%s \'%s\' @ \'%s\' %d, %d, %d", new Object[] { + getClass().getSimpleName(), + coreFrequency, + worldObj == null ? "~NULL~" : worldObj.getWorldInfo().getWorldName(), + Integer.valueOf(xCoord), Integer.valueOf(yCoord), Integer.valueOf(zCoord)}); + } +} diff --git a/src/cr0s/WarpDrive/machines/TileEntityTransporter.java b/src/cr0s/WarpDrive/machines/TileEntityTransporter.java new file mode 100644 index 00000000..eea2ca2a --- /dev/null +++ b/src/cr0s/WarpDrive/machines/TileEntityTransporter.java @@ -0,0 +1,482 @@ +package cr0s.WarpDrive.machines; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import cr0s.WarpDrive.api.IUpgradable; +import cr0s.WarpDrive.data.EnumUpgradeTypes; +import cr0s.WarpDrive.data.Vector3; +import cr0s.WarpDrive.WarpDrive; +import cr0s.WarpDrive.WarpDriveConfig; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.ChatMessageComponent; +import net.minecraft.util.DamageSource; +import net.minecraftforge.common.ForgeDirection; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.lua.ILuaContext; + +public class TileEntityTransporter extends WarpEnergyTE implements IUpgradable +{ + private double scanRange=2; + + private int scanDist = 4; + + private double beaconEffect = 0; + private double powerBoost = 1; + private double baseLockStrength=-1; + private double lockStrengthMul = 1; + private boolean isLocked=false; + + private final static Vector3 centreOnMe = new Vector3(0.5D, 1.0D, 0.5D); + private Vector3 sourceVec = new Vector3(); + private Vector3 destVec = new Vector3(); + + private TeleporterDamage teleDam = new TeleporterDamage("teleporter"); + + public TileEntityTransporter() { + super(); + peripheralName = "transporter"; + methodsArray = new String[] { + "source", + "dest", + "lock", + "release", + "lockStrength", + "energize", + "getEnergyLevel", + "powerBoost", + "energyCost", + "upgrades", + "help" }; + } + + @Override + public void updateEntity() { + super.updateEntity(); + + if(isLocked) { + if(lockStrengthMul > 0.8) { + lockStrengthMul *= 0.995; + } else { + lockStrengthMul*= 0.98; + } + } + } + + // OpenComputer callback methods + // FIXME: implement OpenComputers... + + // ComputerCraft IPeripheral methods implementation + private static String helpStr(Object[] function) { + if (function != null && function.length > 0) { + String fun = function[0].toString().toLowerCase(); + if(fun.equals("source")) { + if(WarpDriveConfig.TR_RELATIVE_COORDS) { + return "source(x,y,z): sets the coordinates (relative to the transporter) to teleport from\ndest(): returns the relative x,y,z coordinates of the source"; + } else { + return "source(x,y,z): sets the absolute coordinates to teleport from\ndest(): returns the x,y,z coordinates of the source"; + } + } else if(fun.equals("dest")) { + if(WarpDriveConfig.TR_RELATIVE_COORDS) { + return "dest(x,y,z): sets the coordinates (relative to the transporter) to teleport to\ndest(): returns the relative x,y,z coordinates of the destination"; + } else { + return "dest(x,y,z): sets the absolute coordinates to teleport to\ndest(): returns the x,y,z coordinates of the destination"; + } + } else if(fun.equals("lock")) { + return "lock(): locks the source and dest coordinates in and returns the lock strength (float)"; + } else if(fun.equals("release")) { + return "release(): releases the current lock"; + } else if(fun.equals("lockstrength")) { + return "lockStrength(): returns the current lock strength (float)"; + } else if(fun.equals("energize")) { + return "energize(): attempts to teleport all entities at source to dest. Returns the number of entities transported (-1 indicates a problem)."; + } else if(fun.equals("powerboost")) { + return "powerBoost(boostAmount): sets the level of power to use (1 being default), returns the level of power\npowerBoost(): returns the level of power"; + } else if(fun.equals("energycost")) { + return "energyCost(): returns the amount of energy it will take for a single entity to transport with the current settings"; + } else if(fun.equals("upgrades")) { + return WarpDrive.defUpgradeStr; + } else if(fun.equals("getEnergyLevel")) { + return WarpDrive.defEnergyStr; + } + } + return WarpDrive.defHelpStr; + } + + private Object[] setVec3(boolean src,Object... arguments) { + Vector3 vec = src ? sourceVec : destVec; + + if (vec == null) { + Vector3 sV = WarpDriveConfig.TR_RELATIVE_COORDS ? new Vector3(this) : new Vector3(0,0,0); + if(src) + sourceVec = sV; + else + destVec = sV; + vec = src ? sourceVec : destVec; + } + + try { + if (arguments.length >= 3) { + unlock(); + vec.x = toDouble(arguments[0]); + vec.y = toDouble(arguments[1]); + vec.z = toDouble(arguments[2]); + } else if(arguments.length == 1) { + unlock(); + if(WarpDriveConfig.TR_RELATIVE_COORDS) { + vec.x = centreOnMe.x; + vec.y = centreOnMe.y; + vec.z = centreOnMe.z; + } else { + vec.x = xCoord + centreOnMe.x; + vec.y = yCoord + centreOnMe.y; + vec.z = zCoord + centreOnMe.z; + } + } + } catch(NumberFormatException e) { + return setVec3(src,"this"); + } + return new Object[] { vec.x, vec.y, vec.z }; + } + + @Override + public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws Exception { + String methodName = methodsArray[method]; + if (methodName.equals("getEnergyLevel")) { + return new Object[] { getEnergyStored(), getMaxEnergyStored() }; + } else if (methodName.equals("source")) { + return setVec3(true,arguments); + } else if (methodName.equals("dest")) { + return setVec3(false,arguments); + } else if (methodName.equals("lock")) { + return new Object[] { lock(sourceVec, destVec) }; + } else if (methodName.equals("release")) { + unlock(); + return null; + } else if (methodName.equals("lockStrength")) { + return new Object[] { getLockStrength() }; + } else if (methodName.equals("energize")) { + return new Object[] { energize () }; + } else if (methodName.equals("powerBoost")) { + try { + if (arguments.length >= 1) { + powerBoost = clamp(toDouble(arguments[0]),1,WarpDriveConfig.TR_MAX_BOOST_MUL); + } + } catch(NumberFormatException e) { + powerBoost = 1; + } + return new Object[] { powerBoost }; + } else if (methodName.equals("energyCost")) { + return new Object[] { energyCost() }; + } else if (methodName.equals("help")) { + return new Object[] { helpStr(arguments) }; + } + + return null; + } + + private Integer energyCost() { + if (sourceVec != null && destVec != null) { + return (int) Math.ceil(Math.pow(3, powerBoost - 1) * WarpDriveConfig.TR_EU_PER_METRE * sourceVec.distanceTo(destVec)); + } + return null; + } + + private int energize() { + if (isLocked) { + int count = 0; + double ls = getLockStrength(); + WarpDrive.debugPrint("LS:" + getLockStrength()); + ArrayList entitiesToTransport = findEntities(sourceVec, ls); + Integer energyReq = energyCost(); + if (energyReq == null) { + return -1; + } + Vector3 modDest = destVec.clone().translate(centreOnMe); + for(Entity ent : entitiesToTransport) { + WarpDrive.debugPrint("" + this + " Handling entity " + ent.getEntityName()); + if (consumeEnergy(energyReq, false)) { + WarpDrive.debugPrint("" + this + " Energy taken"); + inflictNegativeEffect(ent, ls); + transportEnt(ent, modDest); + count++; + } else { + break; + } + } + return count; + } + return -1; + } + + private void transportEnt(Entity ent, Vector3 dest) { + if (ent instanceof EntityLivingBase) { + EntityLivingBase livingEnt = (EntityLivingBase) ent; + if (WarpDriveConfig.TR_RELATIVE_COORDS) { + livingEnt.setPositionAndUpdate(xCoord+dest.x, yCoord+dest.y, zCoord+dest.z); + } else { + livingEnt.setPositionAndUpdate(dest.x, dest.y, dest.z); + } + } else { + if (WarpDriveConfig.TR_RELATIVE_COORDS) { + ent.setPosition(xCoord+dest.x, yCoord+dest.y, zCoord+dest.z); + } else { + ent.setPosition(dest.x, dest.y, dest.z); + } + } + } + + private void inflictNegativeEffect(Entity ent, double lockStrength) { + double value = Math.random() + lockStrength; + + WarpDrive.debugPrint("TRANSPORTER INFLICTION: " + value); + if (value < 0.1) { + ent.attackEntityFrom(teleDam, 1000); + } + + if (value < 0.2) { + ent.attackEntityFrom(teleDam, 10); + } + + if (value < 0.5) { + ent.attackEntityFrom(teleDam, 1); + } + } + + private double beaconScan(int xV, int yV, int zV) + { + WarpDrive.debugPrint("BeaconScan:" + xV + ","+yV + "," + zV); + double beacon = 0; + int beaconCount = 0; + int xL = xV - scanDist; + int xU = xV + scanDist; + int yL = yV - scanDist; + int yU = yV + scanDist; + int zL = zV - scanDist; + int zU = zV + scanDist; + for(int x=xL;x<=xU;x++) + { + for(int y=yL;y<=yU;y++) + { + if(y < 0 || y > 254) { + continue; + } + + for(int z=zL;z<=zU;z++) + { + if(worldObj.getBlockId(x, y, z) != WarpDriveConfig.transportBeaconID) { + continue; + } + double dist = 1 + Math.abs(x - xV) + Math.abs(y - yV) + Math.abs(z - zV); + beaconCount++; + if (worldObj.getBlockMetadata(x, y, z) == 0) { + beacon += 1/dist; + } else { + beacon -= 1/dist; + } + } + } + } + if (beaconCount > 0) { + beacon /= Math.sqrt(beaconCount); + } + return beacon; + } + + private double beaconScan(Vector3 s, Vector3 d) + { + s = absoluteVector(s); + d = absoluteVector(d); + return beaconScan(toInt(s.x), toInt(s.y), toInt(s.z)) + beaconScan(toInt(d.x), toInt(d.y), toInt(d.z)); + } + + private Vector3 absoluteVector(Vector3 a) + { + if(WarpDriveConfig.TR_RELATIVE_COORDS) + return a.clone().translate(new Vector3(this)); + else + return a; + } + + private double calculatePower(Vector3 d) + { + Vector3 myCoords; + if(WarpDriveConfig.TR_RELATIVE_COORDS) + myCoords = centreOnMe; + else + myCoords = new Vector3(this).translate(centreOnMe); + return calculatePower(myCoords,d); + } + + private static double calculatePower(Vector3 s, Vector3 d) + { + double dist = s.distanceTo(d); + return clamp(Math.pow(Math.E, -dist / 300), 0, 1); + } + + private static double min(double... ds) + { + double curMin = Double.MAX_VALUE; + for(double d: ds) + curMin = Math.min(curMin, d); + return curMin; + } + + private double getLockStrength() { + if (isLocked) { + double upgradeBoost = 1; + if (upgrades.containsKey(EnumUpgradeTypes.Range)) + upgradeBoost = Math.pow(1.2, upgrades.get(EnumUpgradeTypes.Range)); + return clamp(baseLockStrength * lockStrengthMul * Math.pow(2, powerBoost-1) * upgradeBoost * (1 + beaconEffect), 0, 1); + } + return -1; + } + + private void unlock() { + isLocked = false; + baseLockStrength = 0; + } + + private double lock(Vector3 source,Vector3 dest) { + if (source != null && dest != null) { + double basePower = min(calculatePower(source), calculatePower(dest), calculatePower(source,dest)); + beaconEffect = beaconScan(source, dest); + WarpDrive.debugPrint("BEACON:" + beaconEffect); + baseLockStrength = basePower; + lockStrengthMul = 1; + isLocked = true; + WarpDrive.debugPrint(baseLockStrength + "," + getLockStrength()); + return getLockStrength(); + } else { + unlock(); + return 0; + } + } + + private AxisAlignedBB getAABB() { + Vector3 tS = new Vector3(this); + Vector3 bS = new Vector3(this); + Vector3 scanPos = new Vector3( scanRange/2, 2, scanRange/2); + Vector3 scanNeg = new Vector3(-scanRange/2,-1,-scanRange/2); + if(WarpDriveConfig.TR_RELATIVE_COORDS) { + tS.translate(sourceVec).translate(scanPos); + bS.translate(sourceVec).translate(scanNeg); + } else { + tS = sourceVec.clone().translate(scanPos); + bS = sourceVec.clone().translate(scanNeg); + } + return AxisAlignedBB.getBoundingBox(bS.x,bS.y,bS.z,tS.x,tS.y,tS.z); + } + + private ArrayList findEntities(Vector3 source, double lockStrength) { + AxisAlignedBB bb = getAABB(); + WarpDrive.debugPrint("Transporter:" +bb.toString()); + List data = worldObj.getEntitiesWithinAABBExcludingEntity(null, bb); + ArrayList output = new ArrayList(data.size()); + for(Object ent : data) { + if (lockStrength >= 1 || worldObj.rand.nextDouble() < lockStrength) {// If weak lock, don't transport + WarpDrive.debugPrint("" + this + " Entity '" + ent.toString() + "' found and added"); + if (ent instanceof Entity) { + output.add((Entity) ent); + } + } else { + WarpDrive.debugPrint("" + this + " Entity '" + ent.toString() + "' discarded"); + } + } + return output; + } + + @Override + public int getMaxEnergyStored() { + int max = WarpDriveConfig.TR_MAX_ENERGY; + if (upgrades.containsKey(EnumUpgradeTypes.Energy)) { + max = (int) Math.floor(max * Math.pow(1.2, upgrades.get(EnumUpgradeTypes.Energy))); + } + return max; + } + + @Override + public boolean canInputEnergy(ForgeDirection from) { + if (from == ForgeDirection.UP) { + return false; + } + return true; + } + + @Override + public int getMaxSafeInput() { + return Integer.MAX_VALUE; + } + + @Override + public void writeToNBT(NBTTagCompound tag) { + super.writeToNBT(tag); + tag.setDouble("powerBoost", powerBoost); + } + + @Override + public void readFromNBT(NBTTagCompound tag) { + super.readFromNBT(tag); + powerBoost = tag.getDouble("powerBoost"); + } + + class TeleporterDamage extends DamageSource { + protected TeleporterDamage(String par1Str) { + super(par1Str); + } + + @Override + public ChatMessageComponent getDeathMessage(EntityLivingBase e) { + String mess = ""; + if(e instanceof EntityPlayer || e instanceof EntityPlayerMP) { + mess = ((EntityPlayer) e).username + " was killed by a teleporter malfunction"; + } else { + mess = e.getEntityName() + " was killed by a teleporter malfunction"; + } + + WarpDrive.debugPrint(mess); + return ChatMessageComponent.createFromText(mess); + } + } + + @Override + public boolean takeUpgrade(EnumUpgradeTypes upgradeType, boolean simulate) + { + int max = 0; + if(upgradeType == EnumUpgradeTypes.Energy) + max = 2; + else if(upgradeType == EnumUpgradeTypes.Power) + max = 4; + else if(upgradeType == EnumUpgradeTypes.Range) + max = 4; + + if(max == 0) + return false; + + if(upgrades.containsKey(upgradeType)) + if(upgrades.get(upgradeType) >= max) + return false; + + if(!simulate) + { + int c = 0; + if(upgrades.containsKey(upgradeType)) + c = upgrades.get(upgradeType); + upgrades.put(upgradeType, c+1); + } + return true; + } + + @Override + public Map getInstalledUpgrades() + { + return upgrades; + } +} diff --git a/src/cr0s/WarpDrive/machines/WarpBlockContainer.java b/src/cr0s/WarpDrive/machines/WarpBlockContainer.java new file mode 100644 index 00000000..df15dbf2 --- /dev/null +++ b/src/cr0s/WarpDrive/machines/WarpBlockContainer.java @@ -0,0 +1,85 @@ +package cr0s.WarpDrive.machines; + +import cpw.mods.fml.common.FMLCommonHandler; +import cr0s.WarpDrive.WarpDrive; +import cr0s.WarpDrive.api.IBlockUpdateDetector; +import cr0s.WarpDrive.api.IUpgradable; +import cr0s.WarpDrive.data.EnumUpgradeTypes; +import cr0s.WarpDrive.item.ItemWarpUpgrade; +import net.minecraft.block.Block; +import net.minecraft.block.BlockContainer; +import net.minecraft.block.material.Material; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public abstract class WarpBlockContainer extends BlockContainer { + protected WarpBlockContainer(int par1) { + super(par1, Material.iron); + } + + protected WarpBlockContainer(int par1, Material m) { + super(par1, m); + setHardness(0.5F); + setStepSound(Block.soundMetalFootstep); + setCreativeTab(WarpDrive.warpdriveTab); + } + + @Override + public void onBlockAdded(World w, int x, int y, int z) { + super.onBlockAdded(w, x, y, z); + TileEntity te = w.getBlockTileEntity(x, y, z); + if (te instanceof IBlockUpdateDetector) { + ((IBlockUpdateDetector)te).updatedNeighbours(); + } + } + + /* FIXME untested + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, float par8, float par9) + { + if (FMLCommonHandler.instance().getEffectiveSide().isClient()) { + return false; + } + + boolean hasResponse = false; + TileEntity te = world.getBlockTileEntity(x, y, z); + if(te != null && te instanceof IUpgradable) + { + IUpgradable upgradable = (IUpgradable)te; + ItemStack is = player.inventory.getCurrentItem(); + if(is != null) + { + Item i = is.getItem(); + if(i instanceof ItemWarpUpgrade) + { + if(upgradable.takeUpgrade(EnumUpgradeTypes.values()[is.getItemDamage()],false)) + { + if(!player.capabilities.isCreativeMode) + player.inventory.decrStackSize(player.inventory.currentItem, 1); + player.addChatMessage("Upgrade accepted"); + } + else + { + player.addChatMessage("Upgrade declined"); + } + hasResponse = true; + } + } + } + + return hasResponse; + } + /**/ + + @Override + public void onNeighborBlockChange(World w, int x, int y, int z, int b) { + super.onNeighborBlockChange(w, x, y, z, b); + TileEntity te = w.getBlockTileEntity(x, y, z); + if (te instanceof IBlockUpdateDetector) { + ((IBlockUpdateDetector)te).updatedNeighbours(); + } + } +}