From 42401c0a45a22a535417777bc4bbe9f476b1817a Mon Sep 17 00:00:00 2001 From: Shadow_Man <56026280+Astorin@users.noreply.github.com> Date: Fri, 9 May 2025 16:40:37 +0200 Subject: [PATCH 1/2] Update for Factorio 2.0 Warptorio2 fully passable in the Factorio 2.0 Need some cosmetic and locale checking ATM. --- changelog.txt | 14 +- control.lua | 8 +- control_class_harvester.lua | 1035 ++++--- control_class_rails.lua | 361 ++- control_class_teleporter.lua | 951 ++++--- control_main.lua | 2480 ++++++++++------- control_main_helpers.lua | 1901 +++++++------ control_main_remotes.lua | 288 +- control_platform_classic.lua | 1908 ++++++------- data-updates.lua | 4 +- data.lua | 22 +- data_warptorio.lua | 2221 ++++++++++----- info.json | 26 +- lib/lib.lua | 282 +- lib/lib_control.lua | 893 +++--- lib/lib_control_cache.lua | 1324 ++++----- lib/lib_control_grid.lua | 80 +- lib/lib_control_logic.lua | 108 +- lib/lib_data.lua | 436 +-- lib/lib_data_logic.lua | 1032 +++---- lib/lib_data_resize.lua | 484 ++-- lib/lib_global.lua | 508 ++-- lib/lib_hide.lua | 122 +- lib/lib_planets.lua | 184 +- lib/lib_settings.lua | 80 +- lib/license.txt | 70 +- locale/en/config.cfg | 83 +- migrations/warptorio_1.3.10.lua | 8 +- migrations/warptorio_1.3.9.lua | 12 +- prototypes-updates/data_accumulators.lua | 475 ++-- .../data_warptorio-harvester.lua | 416 +-- prototypes/data_warpnuke.lua | 702 +++-- prototypes/data_warptorio-combinator.lua | 418 ++- prototypes/data_warptorio-heatpipe.lua | 2178 ++++++--------- prototypes/data_warptorio-logistics-pipe.lua | 462 ++- prototypes/data_warptorio-townportal.lua | 161 +- prototypes/data_warptorio-warploader.lua | 246 +- prototypes/data_warptorio-warpport.lua | 673 ++--- prototypes/data_warptorio-warpspider.lua | 266 +- prototypes/data_warptorio-warpstation.lua | 519 ++-- settings.lua | 604 ++-- sound/sound.lua | 1 - 42 files changed, 12775 insertions(+), 11271 deletions(-) diff --git a/changelog.txt b/changelog.txt index 8e3810a..496397f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,13 @@ +--------------------------------------------------------------------------------------------------- +Version: 2.0.0 +Date: 09.05.2025 + Major changes: + - Updated to Factorio 2.0 (thanks to Shadow_Man) + - Space Age is not supported. Elevated Rails and Quality is supported. + - New game recommended. No migration support for previous savegames. + Changes: + - Added Warptorio welcome text on game start. + --------------------------------------------------------------------------------------------------- Version: 1.3.11 Date: 18.2.2024 @@ -8,7 +18,6 @@ Date: 18.2.2024 - Changed warp reactor specific heat from 10MJ to 1MJ to address heat distribution issues - Updated heat related code to better respect specific heats (Thanks chingis_khagan!) - --------------------------------------------------------------------------------------------------- Version: 1.3.10 Date: 8.5.2023 @@ -36,14 +45,12 @@ Date: 8.4.2022 Changes: - Typo - --------------------------------------------------------------------------------------------------- Version: 1.3.7 Date: 7.4.2022 Changes: - Lib bugfix related to cloning spider legs - --------------------------------------------------------------------------------------------------- Version: 1.3.6 Date: 7.3.2022 @@ -59,7 +66,6 @@ Date: 13.3.2021 Changes: - Fixed multiplayer crash, missing nil check on updating ownership and connection of cloned spidertrons to the remotes in players inventories between warps. - --------------------------------------------------------------------------------------------------- Version: 1.3.4 Date: 30.12.2020 diff --git a/control.lua b/control.lua index 54d8b9c..155639a 100644 --- a/control.lua +++ b/control.lua @@ -19,13 +19,11 @@ Status bar wastes screen space, don't use it. Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. -]]--------------------------------------- +]] --------------------------------------- ---[[ Environment ]]-- -lib={PLANETORIO=true,REMOTES=true} +--[[ Environment ]] -- +lib = { PLANETORIO = true, REMOTES = true } require("lib/lib") require("control_main") lib.lua() - - diff --git a/control_class_harvester.lua b/control_class_harvester.lua index c453875..c2020a6 100644 --- a/control_class_harvester.lua +++ b/control_class_harvester.lua @@ -1,428 +1,607 @@ - - ---[[ -harvestpad item on upgrade - - local lv=research.level("warptorio-harvester-"..self.name) - local cls="warptorio-harvestpad-"..lv - for k,v in pairs(game.players)do if(v and v.valid)then local iv=v.get_main_inventory() if(iv)then for i,x in pairs(iv.get_contents())do - if(i:sub(1,20)=="warptorio-harvestpad" and i:sub(22,22+self.name:len())==self.name)then local lvx=tonumber(i:sub(-1,-1)) - if(lvx1)then iv.remove{name=i,count=(x-1)} end - end - end end end end - -]] - - ---[[ Harvesters ]]-- - -warptorio.HarvesterSizes={12,20,26,32,38,46} -function warptorio.GetHarvesterLevelSize(lv) local z=warptorio.HarvesterSizes[lv] return vector(z,z) end -function warptorio.GetHarvesterLevelSizeNum(lv) local z=warptorio.HarvesterSizes[lv] return z end - -local HARV={} HARV.__index=HARV warptorio.HarvesterMeta=HARV setmetatable(HARV,warptorio.TeleporterMeta) -function HARV.__init(self,tbl) - self.key=tbl.key - self.rank=1 - local t={} - table.merge(t,table.deepcopy(warptorio.platform.harvesters[self.key])) - table.merge(t,table.deepcopy(warptorio.platform.HarvesterPointData)) - self.gdata=t - warptorio.TeleporterMeta.__init(self,self) - self.position=tbl.position - - self.pipes=self.pipes or {{},{}} - self.loaders=self.loaders or {{},{}} - self.loaderFilter=self.loaderFilter or {{},{}} - self.combos=self.combos or {nil,nil} - if(not self.dir)then self.dir={{},{}} for i=1,6,1 do self.dir[1][i]="input" self.dir[2][i]="output" end end - - self.deployed=self.deployed or false - self.deploy_position=self.deploy_position or nil - self.gdata.pair[2].position=self.gdata.pair[2].position or self.deploy_position or self.position - self.gdata.pair[1].position=self.gdata.pair[1].position or self.position - self.chests=nil - - global.Harvesters[tbl.key]=self -end -function HARV:Data() return self.gdata end - -function HARV:GetSize(brank) - local tps=self:Data() - if(tps.fixed_level)then return warptorio.GetHarvesterLevelSizeNum(tps.fixed_level) end - local tcn=tps.tech - local lv=(brank and self.rank or warptorio.GetPlatformTechLevel(tcn)) - return warptorio.GetHarvesterLevelSize(lv) -end -function HARV:GetBaseArea(z,rank) z=z or self:GetSize(rank)-1 return vector.square(self.position,vector(z,z)) end -function HARV:GetDeployArea(z,rank) z=z or self:GetSize(rank)-2 return vector.square(vector.pos(self.deploy_position),vector(z,z)) end - - -function HARV:CheckTeleporterPairs(bSound) -- Call updates and stuff. Automatically deals with logistics, upgrades and cleaning as-needed with good accuracy - local tps=self:Data() - local wps=warptorio.platform.HarvesterPointData - self:MakePointTeleporter(wps,1,wps.pair[1],self.position) - if(self.deployed)then - self:MakePointTeleporter(wps,2,wps.pair[2],self.deploy_position) - end - self:CheckPointLogistics(1) - self:CheckPointLogistics(2) -end - -function HARV:UpgradePlayerInventories() - for k,v in pairs(game.players)do if(v and v.valid)then local iv=v.get_main_inventory() if(iv)then for i,x in pairs(iv.get_contents())do - if(i:sub(1,20)=="warptorio-harvestpad" and i:sub(22,22+self.key:len())==self.key)then local lvx=tonumber(i:sub(-1,-1)) - if(lvx1)then iv.remove{name=i,count=(x-1)} end - end - end end end end -end - - -function HARV:MakePointTeleporter(tps,i,t,pos) - local p=self.points[i] - local f=global.floor[t.floor].host - - local epos - if(t.prototype)then - local vproto=t.prototype - if(tps.energy)then vproto=vproto.."-"..(warptorio.GetPlatformTechLevel(tps.energy)) end - local e=p.ent - if(isvalid(e))then - if(e.surface~=f)then self:DestroyPointTeleporter(i) self:DestroyPointLogistics(i) - elseif(e.name~=vproto)then epos=e.position self:DestroyPointTeleporter(i) - end - end - if(not isvalid(e))then - local vepos=epos or (pos or t.position) - if(not vepos)then return end - local vpos=((t.gate and not epos) and f.find_non_colliding_position(vproto,vepos,0,1,1) or vepos) - local varea - if(not t.gate)then varea=vector.square(vpos,vector(2,2)) vector.clean(f,varea) end - e=entity.protect(entity.create(f,vproto,vpos),t.minable~=nil and t.minable or false,t.destructible~=nil and t.destructible or false) - if(not t.gate)then vector.cleanplayers(f,varea) end - p.ent=e - end - if(p.energy)then e.energy=e.energy+p.energy p.energy=nil end - if(t.sprites)then self:MakePointSprites(tps,i,t.sprites) end - if(t.sprite_arrow)then self:MakePointArrow(tps,i,t.sprite_arrow) end - end - if(epos or not t.gate)then self:CheckPointLogistics(i) end - - cache.force_entity(p.ent,"Harvesters",self.key,"points",i) - -end - -function HARV:RunUpgrade() - local tps=self:Data() - local vz=self:GetSize() - local lv=warptorio.GetPlatformTechLevel(tps.tech) - - local f=global.floor[tps.pair[1].floor].host - - local pos=tps.position - if(not self.deployed)then - local bh=warptorio.platform.floors.harvester.BuildHarvester -- bridges first - if(bh[self.key])then bh[self.key](f) end - - local lvm=math.max(lv*2,2) -- Makes buffer area around the harvesters - vector.LayTiles("warp-tile-concrete",f,vector.square(tps.position,vector(vz+lvm,vz+lvm))) - vector.LayTiles("warptorio-red-concrete",f,vector.square(tps.position,vector(vz-2,vz-2))) - - self:CheckTeleporterPairs(true) - end - if(research.has("warptorio-logistics-1"))then - self:DestroyPointLogistics(1) - self:CheckPointLogistics(1) - if(not self.deployed)then self:DestroyPointLogistics(2) self:CheckPointLogistics(2) end - end - self:DestroyCombos() - self:CheckCombo() - - self:UpgradePlayerInventories() -- upgrade their harvestpads for this harvester (if needed) - - self.rank=lv -end - - -function HARV:Upgrade() self.ReadyUpgrade=true if(not self.deployed)then self:DoUpgrade() end end -function HARV:DoUpgrade() if(self.ReadyUpgrade)then self.ReadyUpgrade=false self:RunUpgrade() end end - - ---[[ Harvester Combinator ]]-- - - -function HARV:ConnectCombo() if(not self.deployed and self:ValidCombos())then - self.combos[1].connect_neighbour({target_entity=self.combos[2],wire=defines.wire_type.red}) self.combos[1].connect_neighbour({target_entity=self.combos[2],wire=defines.wire_type.green}) -end end -function HARV:ValidCombos() return isvalid(self.combos[1]) and isvalid(self.combos[2]) end -function HARV:CheckCombo() if(research.has("warptorio-alt-combinator"))then self:MakeComboA() self:MakeComboB() self:ConnectCombo() end end -function HARV:DestroyComboA() if(isvalid(self.combos[1]))then entity.destroy(self.combos[1]) end self.combos[1]=nil end -function HARV:DestroyComboB() if(isvalid(self.combos[2]))then entity.destroy(self.combos[2]) end self.combos[2]=nil end -function HARV:DestroyCombos() self:DestroyComboA() self:DestroyComboB() end - -function HARV:MakeComboA() local vx=self.points[1].ent - local cfg=settings.global.warptorio_combinator_offset.value local ofv if(cfg)then ofv=(self.key=="east" and 1 or 1.5) else ofv=0 end - local vpos=vector.pos(vx.position)+vector(self:GetSize().x/2*(self.key=="east" and 1 or -1)+ofv,0) - vector.clean(vx.surface,vector.square(vpos,vector(0.5,0.5))) - local e=entity.protect(entity.create(vx.surface,"warptorio-alt-combinator",vpos),false,false) - self.combos[1]=e - - cache.force_entity(e,"Harvesters",self.key,"combos",1) -end -function HARV:MakeComboB() local vx=(isvalid(self.points[2].ent) and self.points[2].ent or self.points[1].ent) - local cfg=settings.global.warptorio_combinator_offset.value local ofv if(cfg)then ofv=(self.key=="east" and -2 or -1) else ofv=(self.key=="east" and -1 or 1) end - local vpos=vector.pos(vx.position)+vector(self:GetSize().x/2*(self.key=="east" and 1 or -1)+ofv,0) - vector.clean(vx.surface,vector.square(vpos,vector(0.5,0.5))) - local e=entity.protect(entity.create(vx.surface,"warptorio-alt-combinator",vpos),false,false) - self.combos[2]=e - - cache.force_entity(e,"Harvesters",self.key,"combos",2) -end - ---[[ Harvester Logistics ]]-- - -function HARV:MakePointPipes(tps,i,id,pos,f,lddir,belty,vexdir) - local pipe="warptorio-logistics-pipe" - local v=self.pipes[i][id] - local vpos=vector(pos)+vector(vexdir)+vector(belty) - if(isvalid(v) and (v.surface~=f or v.position.x~=vpos.x or v.position.y~=vpos.y))then entity.destroy(v) end - if(not isvalid(v))then - local varea=vector.square(vpos,vector(0.5,0.5)) - vector.clean(f,varea) - v=entity.protect(entity.create(f,pipe,vpos,lddir),false,false) - self.pipes[i][id]=v - end - - cache.force_entity(v,"Harvesters",self.key,"pipes",i,id) -end - -function HARV:MakePointLoader(tps,i,id,pos,f,belt,lddir,belty,beltsquare,vexdir) - local v=self.loaders[i][id] - if(isvalid(v) and v.name~=belt)then v.destroy{raise_destroy=true} end - if(not isvalid(v))then - local vpos=vector(pos)+vector(vexdir)+vector(belty) - local varea=vector.square(vpos,beltsquare) - vector.clean(f,varea) - v=entity.protect(entity.create(f,belt,vpos,lddir),false,false) - v.loader_type=self.dir[i][id] - self.loaders[i][id]=v - local inv=self.loaderFilter[i][id] if(inv)then for invx,invy in pairs(inv)do v.set_filter(invx,invy) end end - end - cache.force_entity(v,"Harvesters",self.key,"loaders",i,id) - -end - -function HARV:CheckPointLogistics(i) - local tps=self:Data() - local t=tps.pair[i] - if(self.maxloader==0 or not tps.logs_pattern)then return end - local belt=warptorio.GetBelt() - local pos=tps.position - local f=global.floor.harvester.host - if(i==2 and self.deployed)then f=global.floor.main.host pos=self.deploy_position end - - local ldl=0 - local lvLogs=research.level("warptorio-logistics") - if(tps.logs and lvLogs>0)then ldl=ldl+1 end - if(tps.dualloader and research.has("warptorio-dualloader-1"))then ldl=ldl+1 end - if(tps.triloader and research.has("warptorio-triloader"))then ldl=ldl+1 end - if(ldl<=0)then return end - - local lddir=(i==2 and string.compassdef[tps.logs_pattern] or string.compassdef[string.compassopp[tps.logs_pattern]]) - local ldodir=(i==1 and string.compassdef[tps.logs_pattern] or string.compassdef[string.compassopp[tps.logs_pattern]]) - local vcomp=vector.compass[tps.logs_pattern] - --game.print(tps.logs_pattern .. " , lddir: " .. lddir) - local vdir=vcomp*(self:GetSize()/2) + vcomp*(i==2 and -1 or 1) - - local beltsquare=vector(1,0.5) - local pipe=vector(0,(id==1 and 2 or -2) ) - if(tps.logs_pattern=="north" or tps.logs_pattern=="south")then beltsquare=vector(0.5,1) end - for id=1,ldl do - local belty=vector( 0,(id%2==0 and 1 or 0)+(id%3==0 and -1 or 0) ) - self:MakePointLoader(tps,i,id,pos,f,belt,lddir,belty,beltsquare,vdir-vcomp*0.5) - end - - if(tps.dopipes and lvLogs>0)then - for id=1,math.min(lvLogs,2),1 do - local belty=vector( 0,(id==1 and 2 or -2) ) + (i==1 and vcomp*-1 or 0) - self:MakePointPipes(tps,i,id,pos,f,ldodir,belty,vdir) - end - end -end - - - ---[[ DEPLOY/RECALL ]]-- ---cleanlanding() - - -function HARV:Recall(bply) -- recall after portal is mined - if(self.recalling)then return end self.recalling=true - local tps=self:Data() - if(not self.deployed)then self:DestroyPointTeleporter(1,false) self:CheckTeleporterPairs() - self:DoUpgrade() - self:CheckCombo() - self:ConnectCombo() - self.recalling=false - return true - end - local t=tps.pair[i] - --self:CleanLanding() -- clean for loaders and combinators -- done automatically now - --if(isvalid(self.points[2].ent))then self.points[2].ent.destroy() end - --self.points[2].ent=nil - - - - local f=global.floor.main.host - local ebs={} - for k,v in pairs(f.find_entities_filtered{type="character",invert=true,area=self:GetDeployArea(nil,true)})do - if(v.type~="resource" and v~=self.points[1].ent)then table.insert(ebs,v) end - --v~=self.b and v~=self.a and (v.name=="warptorio-combinator" or v.name:sub(1,9)~="warptorio") )then table.insert(ebs,v) end - end - - local hf=global.floor.harvester.host - local harvArea=self:GetBaseArea(nil,true) - - - local tbs={} - local tcs={} for k,v in pairs(hf.find_tiles_filtered{area=harvArea})do - local vpos=vector.add(vector.sub(v.position,self.position),self.deploy_position) - table.insert(tcs,{name=v.name,position=vpos}) - table.insert(tbs,{name="warptorio-red-concrete",position=v.position}) - end - local dcs={} for k,v in pairs(hf.find_decoratives_filtered{area=self:GetBaseArea(nil,true)})do - local vpos=vector.add(vector.sub(v.position,self.position),self.deploy_position) - table.insert(dcs,{name=v.decorative.name,position=vpos,amount=v.amount}) - end - - - local ecs={} for k,v in pairs(hf.find_entities_filtered{area=harvArea,type="character",invert=true})do - if(v and v.valid and v~=self.points[1].ent and v~=self.points[2].ent and not entity.shouldClean(v) and not cache.get_entity(v) and v.type~="resource")then table.insert(ecs,v) end - end - - - - local blacktbl={} - for k,v in pairs(ebs)do if(table.HasValue(warptorio.GetWarpBlacklist(),v.name))then table.insert(blacktbl,v) ebs[k]=nil end end - for k,v in pairs(ebs)do if(table.HasValue(warptorio.GetModTable("harvester_blacklist"),v.name))then table.insert(blacktbl,v) ebs[k]=nil end end - - for k,v in pairs(ecs)do if(table.HasValue(warptorio.GetWarpBlacklist(),v.name))then table.insert(blacktbl,v) ecs[k]=nil end end - for k,v in pairs(ecs)do if(table.HasValue(warptorio.GetModTable("harvester_blacklist"),v.name))then table.insert(blacktbl,v) ecs[k]=nil end end - - - warptorio.Cloned_Entities={} warptorio.IsCloning=true - hf.clone_entities{entities=ecs,destination_surface=f,destination_offset=vector.add(vector.mul(self.position,-1),self.deploy_position),snap_to_grid=false} - local hfe=warptorio.Cloned_Entities warptorio.IsCloning=false warptorio.Cloned_Entities=nil - - - if(#ebs>0)then for i=#ebs,1,-1 do if(not ebs[i] or not ebs[i].valid)then table.remove(ebs,i) end end end -- bad ents in table ? - - warptorio.Cloned_Entities={} warptorio.IsCloning=true - f.clone_entities{entities=ebs,destination_surface=hf,destination_offset=vector.add(vector.mul(self.deploy_position,-1),self.position),snap_to_grid=false} - local fe=warptorio.Cloned_Entities warptorio.IsCloning=false warptorio.Cloned_Entities=nil - - local hfm={} for k,v in pairs(hfe)do if(isvalid(v.source) and isvalid(v.destination) and table.HasValue(ecs,v.source))then table.insert(hfm,v.source) end end - local fm={} for k,v in pairs(fe)do if(isvalid(v.source) and isvalid(v.destination) and table.HasValue(ebs,v.source))then table.insert(fm,v.source) end end - - for k,v in pairs(fm)do entity.destroy(v) end - for k,v in pairs(hfm)do entity.destroy(v) end - - f.set_tiles(tcs,true) - f.create_decoratives{decoratives=dcs} - - hf.destroy_decoratives{area=harvArea} - - if(bply)then -- players now - local tpply={} - for k,v in pairs(game.players)do if(v.character==nil or (v.surface==f and vector.inarea(v.position,self:GetDeployArea(nil,true))) )then - table.insert(tpply,{v,vector.add(vector.add(vector.mul(self.deploy_position,-1),vector.pos(v.position)),self.position)}) - end end - for k,v in pairs(tpply)do v[1].teleport(f.find_non_colliding_position("character",{v[2][1],v[2][2]},0,1),hf) end - end - - --vector.LayTiles("warp-tile-concrete",hf,self:GetBaseArea(self:GetSize()+2)) - --vector.LayTiles("warptorio-red-concrete",hf,self:GetBaseArea()) - hf.set_tiles(tbs,true) - self.deployed=false - self:DestroyComboB() - self:DestroyPointTeleporter(1,false) self:DestroyPointTeleporter(2,false) - self:CheckTeleporterPairs() - - self:DoUpgrade() - self:CheckCombo() - self:ConnectCombo() - self.recalling=false - -end - - - -function HARV:Deploy(surf,pos) -- deploy over a harvester platform - if(self.deployed)then return false end - local f=surf if(f~=warptorio.GetMainSurface())then game.print("Harvesters can only be placed on the planet") return false end - --game.print("deployed at: " .. serpent.line(pos)) - self.deploy_position=vector.pos(pos) - local hf=global.floor.harvester.host - - local ebs=hf.find_entities_filtered{type="character",invert=true,area=self:GetBaseArea()} - - local planetArea=self:GetDeployArea() - - local tcs={} for x=planetArea[1][1],planetArea[2][1] do for y=planetArea[1][2],planetArea[2][2]do local v=f.get_tile(x,y) - local vpos=vector.add(vector.sub(vector(x,y),self.deploy_position),self.position) - table.insert(tcs,{name=v.name,position=vpos}) - end end - local dcs={} for k,v in pairs(f.find_decoratives_filtered{area=self:GetDeployArea(self:GetSize()-3)})do - local vpos=vector.add(vector.sub(v.position,self.deploy_position),self.position) - table.insert(dcs,{name=v.decorative.name,position=vpos,amount=v.amount}) - end - local ecs={} for k,v in pairs(f.find_entities_filtered{area=planetArea,type={"construction-robot","logistic-robot","character"},invert=true})do if(v.type~="resource" and v.name:sub(1,9)~=("warptorio"))then table.insert(ecs,v) end end - - hf.set_tiles(tcs,true) - hf.create_decoratives{decoratives=dcs} - - local ebsc=#ebs - local ecsc=#ecs - - - local blacktbl={} - --for k,v in pairs(ebs)do if(isvalid(v))then if(table.HasValue(warptorio.GetWarpBlacklist(),v.name))then table.insert(blacktbl,v) ebs[k]=nil end end end - --for k,v in pairs(ebs)do if(isvalid(v))then if(table.HasValue(warptorio.GetModTable("harvester_blacklist"),v.name))then table.insert(blacktbl,v) ebs[k]=nil end end end - - --for k,v in pairs(ecs)do if(isvalid(v))then if(table.HasValue(warptorio.GetWarpBlacklist(),v.name))then table.insert(blacktbl,v) ecs[k]=nil end end end - --for k,v in pairs(ecs)do if(isvalid(v))then if(table.HasValue(warptorio.GetModTable("harvester_blacklist"),v.name))then table.insert(blacktbl,v) ecs[k]=nil end end end - - - if(ecsc>0)then for i=ecsc,1,-1 do if(not ecs[i] or not ecs[i].valid)then table.remove(ecs,i) end end end -- bad ents in table ? - - warptorio.Cloned_Entities={} warptorio.IsCloning=true - f.clone_entities{entities=ecs,destination_surface=hf,destination_offset=vector.mul(vector.sub(self.deploy_position,self.position),-1),snap_to_grid=false} - local fe=warptorio.Cloned_Entities warptorio.IsCloning=false warptorio.Cloned_Entities=nil - - - if(ebsc>0)then for i=ebsc,1,-1 do if(not ebs[i] or not ebs[i].valid)then table.remove(ebs,i) end end end -- bad ents in table ? - - vector.LayTiles("warptorio-red-concrete",f,self:GetDeployArea()) - - -- this doesnt really work - - warptorio.Cloned_Entities={} warptorio.IsCloning=true - hf.clone_entities{entities=ebs,destination_surface=f,destination_offset=vector.mul(vector.sub(self.position,self.deploy_position),-1),snap_to_grid=false} - local hfe=warptorio.Cloned_Entities warptorio.IsCloning=false warptorio.Cloned_Entities=nil - - local hfm={} for k,v in pairs(hfe)do if(isvalid(v.source) and isvalid(v.destination) and table.HasValue(ebs,v.source))then table.insert(hfm,v.source) end end - local fm={} for k,v in pairs(fe)do if(isvalid(v.source) and isvalid(v.destination) and table.HasValue(ecs,v.source))then table.insert(fm,v.source) end end - - for k,v in pairs(fm)do if(isvalid(v) and v~=self.points[1].ent and v~=self.points[2].ent)then entity.destroy(v) end end - for k,v in pairs(hfm)do if(isvalid(v) and v~=self.points[1].ent and v~=self.points[2].ent)then entity.destroy(v) end end - - for k,v in pairs(blacktbl)do if(v and v.valid)then v.destroy{raise_destroy=true} end end -- cleanup past entities - - vector.clearplayers(f,planetArea) - - self.deployed=true - -- game.print("deployed") - self:CheckTeleporterPairs() -end - - +--[[ +harvestpad item on upgrade + + local lv=research.level("warptorio-harvester-"..self.name) + local cls="warptorio-harvestpad-"..lv + for k,v in pairs(game.players)do if(v and v.valid)then local iv=v.get_main_inventory() if(iv)then for i,x in pairs(iv.get_contents())do + if(i:sub(1,20)=="warptorio-harvestpad" and i:sub(22,22+self.name:len())==self.name)then local lvx=tonumber(i:sub(-1,-1)) + if(lvx1)then iv.remove{name=i,count=(x-1)} end + end + end end end end + +]] + + +--[[ Harvesters ]] -- + +warptorio.HarvesterSizes = { 12, 20, 26, 32, 38, 46 } +function warptorio.GetHarvesterLevelSize(lv) + local z = warptorio.HarvesterSizes[lv] + return vector(z, z) +end + +function warptorio.GetHarvesterLevelSizeNum(lv) + local z = warptorio.HarvesterSizes[lv] + return z +end + +local HARV = {} +HARV.__index = HARV +warptorio.HarvesterMeta = HARV +setmetatable(HARV, warptorio.TeleporterMeta) +function HARV.__init(self, tbl) + self.key = tbl.key + self.rank = 1 + local t = {} + table.merge(t, table.deepcopy(warptorio.platform.harvesters[self.key])) + table.merge(t, table.deepcopy(warptorio.platform.HarvesterPointData)) + self.gdata = t + warptorio.TeleporterMeta.__init(self, self) + self.position = tbl.position + + self.pipes = self.pipes or { {}, {} } + self.loaders = self.loaders or { {}, {} } + self.loaderFilter = self.loaderFilter or { {}, {} } + self.combos = self.combos or { nil, nil } + if (not self.dir) then + self.dir = { {}, {} } + for i = 1, 6, 1 do + self.dir[1][i] = "input" + self.dir[2][i] = "output" + end + end + + self.deployed = self.deployed or false + self.deploy_position = self.deploy_position or nil + self.gdata.pair[2].position = self.gdata.pair[2].position or self.deploy_position or self.position + self.gdata.pair[1].position = self.gdata.pair[1].position or self.position + self.chests = nil + + storage.Harvesters[tbl.key] = self +end + +function HARV:Data() return self.gdata end + +function HARV:GetSize(brank) + local tps = self:Data() + if (tps.fixed_level) then return warptorio.GetHarvesterLevelSizeNum(tps.fixed_level) end + local tcn = tps.tech + local lv = (brank and self.rank or warptorio.GetPlatformTechLevel(tcn)) + return warptorio.GetHarvesterLevelSize(lv) +end + +function HARV:GetBaseArea(z, rank) + z = z or self:GetSize(rank) - 1 + return vector.square(self.position, vector(z, z)) +end + +function HARV:GetDeployArea(z, rank) + z = z or self:GetSize(rank) - 2 + return vector.square(vector.pos(self.deploy_position), vector(z, z)) +end + +function HARV:CheckTeleporterPairs(bSound) -- Call updates and stuff. Automatically deals with logistics, upgrades and cleaning as-needed with good accuracy + local tps = self:Data() + local wps = warptorio.platform.HarvesterPointData + self:MakePointTeleporter(wps, 1, wps.pair[1], self.position) + if (self.deployed) then + self:MakePointTeleporter(wps, 2, wps.pair[2], self.deploy_position) + end + self:CheckPointLogistics(1) + self:CheckPointLogistics(2) +end + +function HARV:UpgradePlayerInventories() + for k, v in pairs(game.players) do + if (v and v.valid) then + local iv = v.get_main_inventory() + if (iv) then + for i, x in pairs(iv.get_contents()) do + if (x.name:sub(1, 20) == "warptorio-harvestpad" and x.name:sub(22, 22 + self.key:len()) == self.key) then + local lvx = tonumber(x.name:sub(-1, -1)) + if (lvx < lv) then + iv.remove { name = x.name, count = x.count } + iv.insert { name = cls, count = 1 } + elseif (x > 1) then + iv.remove { name = x.name, count = (x.count - 1) } + end + end + end + end + end + end +end + +function HARV:MakePointTeleporter(tps, i, t, pos) + local p = self.points[i] + local f = storage.floor[t.floor].host + + local epos + if (t.prototype) then + local vproto = t.prototype + if (tps.energy) then vproto = vproto .. "-" .. (warptorio.GetPlatformTechLevel(tps.energy)) end + local e = p.ent + if (isvalid(e)) then + if (e.surface ~= f) then + self:DestroyPointTeleporter(i) + self:DestroyPointLogistics(i) + elseif (e.name ~= vproto) then + epos = e.position + self:DestroyPointTeleporter(i) + end + end + if (not isvalid(e)) then + local vepos = epos or (pos or t.position) + if (not vepos) then return end + local vpos = ((t.gate and not epos) and f.find_non_colliding_position(vproto, vepos, 0, 1, 1) or vepos) + local varea + if (not t.gate) then + varea = vector.square(vpos, vector(2, 2)) + vector.clean(f, varea) + end + e = entity.protect(entity.create(f, vproto, vpos), t.minable ~= nil and t.minable or false, + t.destructible ~= nil and t.destructible or false) + if (not t.gate) then vector.cleanplayers(f, varea) end + p.ent = e + end + if (p.energy) then + e.energy = e.energy + p.energy + p.energy = nil + end + if (t.sprites) then self:MakePointSprites(tps, i, t.sprites) end + if (t.sprite_arrow) then self:MakePointArrow(tps, i, t.sprite_arrow) end + end + if (epos or not t.gate) then self:CheckPointLogistics(i) end + + cache.force_entity(p.ent, "Harvesters", self.key, "points", i) +end + +function HARV:RunUpgrade() + local tps = self:Data() + local vz = self:GetSize() + local lv = warptorio.GetPlatformTechLevel(tps.tech) + + local f = storage.floor[tps.pair[1].floor].host + + local pos = tps.position + if (not self.deployed) then + local bh = warptorio.platform.floors.harvester.BuildHarvester -- bridges first + if (bh[self.key]) then bh[self.key](f) end + + local lvm = math.max(lv * 2, 2) -- Makes buffer area around the harvesters + vector.LayTiles("warp-tile-concrete", f, vector.square(tps.position, vector(vz + lvm, vz + lvm))) + vector.LayTiles("warptorio-red-concrete", f, vector.square(tps.position, vector(vz - 2, vz - 2))) + + self:CheckTeleporterPairs(true) + end + if (research.has("warptorio-logistics-1")) then + self:DestroyPointLogistics(1) + self:CheckPointLogistics(1) + if (not self.deployed) then + self:DestroyPointLogistics(2) + self:CheckPointLogistics(2) + end + end + self:DestroyCombos() + self:CheckCombo() + + self:UpgradePlayerInventories() -- upgrade their harvestpads for this harvester (if needed) + + self.rank = lv +end + +function HARV:Upgrade() + self.ReadyUpgrade = true + if (not self.deployed) then self:DoUpgrade() end +end + +function HARV:DoUpgrade() + if (self.ReadyUpgrade) then + self.ReadyUpgrade = false + self:RunUpgrade() + end +end + +--[[ Harvester Combinator ]] -- + +function HARV:ConnectCombo() + if (not self.deployed and self:ValidCombos()) then + local red1 = self.combos[1].get_wire_connector(defines.wire_connector_id.circuit_red, true) + local red2 = self.combos[2].get_wire_connector(defines.wire_connector_id.circuit_red, true) + red1.connect_to(red2) + local green1 = self.combos[1].get_wire_connector(defines.wire_connector_id.circuit_green, true) + local green2 = self.combos[2].get_wire_connector(defines.wire_connector_id.circuit_green, true) + green1.connect_to(green2) + -- self.combos[1].connect_neighbour({target_entity=self.combos[2],wire=defines.wire_type.red}) + -- self.combos[1].connect_neighbour({target_entity=self.combos[2],wire=defines.wire_type.green}) + end +end + +function HARV:ValidCombos() return isvalid(self.combos[1]) and isvalid(self.combos[2]) end + +function HARV:CheckCombo() + if (research.has("warptorio-alt-combinator")) then + self:MakeComboA() + self:MakeComboB() + self:ConnectCombo() + end +end + +function HARV:DestroyComboA() + if (isvalid(self.combos[1])) then entity.destroy(self.combos[1]) end + self.combos[1] = nil +end + +function HARV:DestroyComboB() + if (isvalid(self.combos[2])) then entity.destroy(self.combos[2]) end + self.combos[2] = nil +end + +function HARV:DestroyCombos() + self:DestroyComboA() + self:DestroyComboB() +end + +function HARV:MakeComboA() + local vx = self.points[1].ent + local cfg = settings.global.warptorio_combinator_offset.value + local ofv + if (cfg) then ofv = (self.key == "east" and 1 or 1.5) else ofv = 0 end + local vpos = vector.pos(vx.position) + vector(self:GetSize().x / 2 * (self.key == "east" and 1 or -1) + ofv, 0) + vector.clean(vx.surface, vector.square(vpos, vector(0.5, 0.5))) + local e = entity.protect(entity.create(vx.surface, "warptorio-alt-combinator", vpos), false, false) + self.combos[1] = e + + cache.force_entity(e, "Harvesters", self.key, "combos", 1) +end + +function HARV:MakeComboB() + local vx = (isvalid(self.points[2].ent) and self.points[2].ent or self.points[1].ent) + local cfg = settings.global.warptorio_combinator_offset.value + local ofv + if (cfg) then ofv = (self.key == "east" and -2 or -1) else ofv = (self.key == "east" and -1 or 1) end + local vpos = vector.pos(vx.position) + vector(self:GetSize().x / 2 * (self.key == "east" and 1 or -1) + ofv, 0) + vector.clean(vx.surface, vector.square(vpos, vector(0.5, 0.5))) + local e = entity.protect(entity.create(vx.surface, "warptorio-alt-combinator", vpos), false, false) + self.combos[2] = e + + cache.force_entity(e, "Harvesters", self.key, "combos", 2) +end + +--[[ Harvester Logistics ]] -- + +function HARV:MakePointPipes(tps, i, id, pos, f, lddir, belty, vexdir) + local pipe = "warptorio-logistics-pipe" + local v = self.pipes[i][id] + local vpos = vector(pos) + vector(vexdir) + vector(belty) + if (isvalid(v) and (v.surface ~= f or v.position.x ~= vpos.x or v.position.y ~= vpos.y)) then entity.destroy(v) end + if (not isvalid(v)) then + local varea = vector.square(vpos, vector(0.5, 0.5)) + vector.clean(f, varea) + v = entity.protect(entity.create(f, pipe, vpos, lddir), false, false) + self.pipes[i][id] = v + end + + cache.force_entity(v, "Harvesters", self.key, "pipes", i, id) +end + +function HARV:MakePointLoader(tps, i, id, pos, f, belt, lddir, belty, beltsquare, vexdir) + local v = self.loaders[i][id] + if (isvalid(v) and v.name ~= belt) then v.destroy { raise_destroy = true } end + if (not isvalid(v)) then + local vpos = vector(pos) + vector(vexdir) + vector(belty) + local varea = vector.square(vpos, beltsquare) + vector.clean(f, varea) + v = entity.protect(entity.create(f, belt, vpos, lddir), false, false) + v.loader_type = self.dir[i][id] + if v.loader_type == "output" then + v.loader_type = "input" + elseif v.loader_type == "input" then + v.loader_type = "output" + end + self.loaders[i][id] = v + local inv = self.loaderFilter[i][id] + if (inv) then for invx, invy in pairs(inv) do v.set_filter(invx, invy) end end + end + cache.force_entity(v, "Harvesters", self.key, "loaders", i, id) +end + +function HARV:CheckPointLogistics(i) + local tps = self:Data() + local t = tps.pair[i] + if (self.maxloader == 0 or not tps.logs_pattern) then return end + local belt = warptorio.GetBelt() + local pos = tps.position + local f = storage.floor.harvester.host + if (i == 2 and self.deployed) then + f = storage.floor.main.host + pos = self.deploy_position + end + + local ldl = 0 + local lvLogs = research.level("warptorio-logistics") + if (tps.logs and lvLogs > 0) then ldl = ldl + 1 end + if (tps.dualloader and research.has("warptorio-dualloader-1")) then ldl = ldl + 1 end + if (tps.triloader and research.has("warptorio-triloader")) then ldl = ldl + 1 end + if (ldl <= 0) then return end + + local ldodir = (i == 2 and string.compassdef[tps.logs_pattern] or string.compassdef[string.compassopp[tps.logs_pattern]]) + local lddir = (i == 1 and string.compassdef[tps.logs_pattern] or string.compassdef[string.compassopp[tps.logs_pattern]]) + local vcomp = vector.compass[tps.logs_pattern] + --game.print(tps.logs_pattern .. " , lddir: " .. lddir) + local vdir = vcomp * (self:GetSize() / 2) + vcomp * (i == 2 and -1 or 1) + + local beltsquare = vector(1, 0.5) + local pipe = vector(0, (id == 1 and 2 or -2)) + if (tps.logs_pattern == "north" or tps.logs_pattern == "south") then beltsquare = vector(0.5, 1) end + for id = 1, ldl do + local belty = vector(0, (id % 2 == 0 and 1 or 0) + (id % 3 == 0 and -1 or 0)) + self:MakePointLoader(tps, i, id, pos, f, belt, lddir, belty, beltsquare, vdir - vcomp * 0.5) + end + + if (tps.dopipes and lvLogs > 0) then + for id = 1, math.min(lvLogs, 2), 1 do + local belty = vector(0, (id == 1 and 2 or -2)) + (i == 1 and vcomp * -1 or 0) + self:MakePointPipes(tps, i, id, pos, f, lddir, belty, vdir) + end + end +end + +--[[ DEPLOY/RECALL ]] -- +--cleanlanding() + + +function HARV:Recall(bply) -- recall after portal is mined + if (self.recalling) then return end + self.recalling = true + local tps = self:Data() + if (not self.deployed) then + self:DestroyPointTeleporter(1, false) + self:CheckTeleporterPairs() + self:DoUpgrade() + self:CheckCombo() + self:ConnectCombo() + self.recalling = false + return true + end + local t = tps.pair[i] + --self:CleanLanding() -- clean for loaders and combinators -- done automatically now + --if(isvalid(self.points[2].ent))then self.points[2].ent.destroy() end + --self.points[2].ent=nil + + + + local f = storage.floor.main.host + local ebs = {} + for k, v in pairs(f.find_entities_filtered { type = "character", invert = true, area = self:GetDeployArea(nil, true) }) do + if (v.type ~= "resource" and v ~= self.points[1].ent) then table.insert(ebs, v) end + --v~=self.b and v~=self.a and (v.name=="warptorio-combinator" or v.name:sub(1,9)~="warptorio") )then table.insert(ebs,v) end + end + + local hf = storage.floor.harvester.host + local harvArea = self:GetBaseArea(nil, true) + + + local tbs = {} + local tcs = {} + for k, v in pairs(hf.find_tiles_filtered { area = harvArea }) do + local vpos = vector.add(vector.sub(v.position, self.position), self.deploy_position) + table.insert(tcs, { name = v.name, position = vpos }) + table.insert(tbs, { name = "warptorio-red-concrete", position = v.position }) + end + local dcs = {} + for k, v in pairs(hf.find_decoratives_filtered { area = self:GetBaseArea(nil, true) }) do + local vpos = vector.add(vector.sub(v.position, self.position), self.deploy_position) + table.insert(dcs, { name = v.decorative.name, position = vpos, amount = v.amount }) + end + + + local ecs = {} + for k, v in pairs(hf.find_entities_filtered { area = harvArea, type = "character", invert = true }) do + if (v and v.valid and v ~= self.points[1].ent and v ~= self.points[2].ent and not entity.shouldClean(v) and not cache.get_entity(v) and v.type ~= "resource") then + table.insert(ecs, v) + end + end + + + + local blacktbl = {} + for k, v in pairs(ebs) do + if (table.HasValue(warptorio.GetWarpBlacklist(), v.name)) then + table.insert(blacktbl, v) + ebs[k] = nil + end + end + for k, v in pairs(ebs) do + if (table.HasValue(warptorio.GetModTable("harvester_blacklist"), v.name)) then + table.insert(blacktbl, v) + ebs[k] = nil + end + end + + for k, v in pairs(ecs) do + if (table.HasValue(warptorio.GetWarpBlacklist(), v.name)) then + table.insert(blacktbl, v) + ecs[k] = nil + end + end + for k, v in pairs(ecs) do + if (table.HasValue(warptorio.GetModTable("harvester_blacklist"), v.name)) then + table.insert(blacktbl, v) + ecs[k] = nil + end + end + + + warptorio.Cloned_Entities = {} + warptorio.IsCloning = true + hf.clone_entities { entities = ecs, destination_surface = f, destination_offset = { self.deploy_position.x - self.position.x, self.deploy_position.y - self.position.y }, snap_to_grid = false } + local hfe = warptorio.Cloned_Entities + warptorio.IsCloning = false + warptorio.Cloned_Entities = nil + + + if (#ebs > 0) then for i = #ebs, 1, -1 do if (not ebs[i] or not ebs[i].valid) then table.remove(ebs, i) end end end -- bad ents in table ? + + warptorio.Cloned_Entities = {} + warptorio.IsCloning = true + f.clone_entities { entities = ebs, destination_surface = hf, destination_offset = { self.position.x - self.deploy_position.x, self.position.y - self.deploy_position.y }, snap_to_grid = false } + local fe = warptorio.Cloned_Entities + warptorio.IsCloning = false + warptorio.Cloned_Entities = nil + + local hfm = {} + for k, v in pairs(hfe) do + if (isvalid(v.source) and isvalid(v.destination) and table.HasValue(ecs, v.source)) then + table.insert(hfm, v.source) + end + end + local fm = {} + for k, v in pairs(fe) do + if (isvalid(v.source) and isvalid(v.destination) and table.HasValue(ebs, v.source)) then + table.insert(fm, v.source) + end + end + + for k, v in pairs(fm) do entity.destroy(v) end + for k, v in pairs(hfm) do entity.destroy(v) end + + f.set_tiles(tcs, true) + f.create_decoratives { decoratives = dcs } + + hf.destroy_decoratives { area = harvArea } + + if (bply) then -- players now + local tpply = {} + for k, v in pairs(game.players) do + if (v.character == nil or (v.surface == f and vector.inarea(v.position, self:GetDeployArea(nil, true)))) then + table.insert(tpply, + { v, vector.add(vector.add(vector.mul(self.deploy_position, -1), vector.pos(v.position)), + self.position) }) + end + end + for k, v in pairs(tpply) do + v[1].teleport(f.find_non_colliding_position("character", { v[2][1], v[2][2] }, 0, 1), + hf) + end + end + + --vector.LayTiles("warp-tile-concrete",hf,self:GetBaseArea(self:GetSize()+2)) + --vector.LayTiles("warptorio-red-concrete",hf,self:GetBaseArea()) + hf.set_tiles(tbs, true) + self.deployed = false + self:DestroyComboB() + self:DestroyPointTeleporter(1, false) + self:DestroyPointTeleporter(2, false) + self:CheckTeleporterPairs() + + self:DoUpgrade() + self:CheckCombo() + self:ConnectCombo() + self.recalling = false +end + +function HARV:Deploy(surf, pos) -- deploy over a harvester platform + if (self.deployed) then return false end + local f = surf + if (f ~= warptorio.GetMainSurface()) then + game.print({ "warptorio.harvester-placement-error" }) + return false + end + --game.print("deployed at: " .. serpent.line(pos)) + self.deploy_position = vector.pos(pos) + local hf = storage.floor.harvester.host + + local ebs = hf.find_entities_filtered { type = "character", invert = true, area = self:GetBaseArea() } + + local planetArea = self:GetDeployArea() + + local tcs = {} + for x = planetArea[1][1], planetArea[2][1] do + for y = planetArea[1][2], planetArea[2][2] do + local v = f.get_tile(x, y) + local vpos = vector.add(vector.sub(vector(x, y), self.deploy_position), self.position) + table.insert(tcs, { name = v.name, position = vpos }) + end + end + local dcs = {} + for k, v in pairs(f.find_decoratives_filtered { area = self:GetDeployArea(self:GetSize() - 3) }) do + local vpos = vector.add(vector.sub(v.position, self.deploy_position), self.position) + table.insert(dcs, { name = v.decorative.name, position = vpos, amount = v.amount }) + end + local ecs = {} + for k, v in pairs(f.find_entities_filtered { area = planetArea, type = { "construction-robot", "logistic-robot", "character" }, invert = true }) do + if (v.type ~= "resource" and v.name:sub(1, 9) ~= ("warptorio")) then + table.insert(ecs, v) + end + end + + hf.set_tiles(tcs, true) + hf.create_decoratives { decoratives = dcs } + + local ebsc = #ebs + local ecsc = #ecs + + local blacktbl = {} + --for k,v in pairs(ebs)do if(isvalid(v))then if(table.HasValue(warptorio.GetWarpBlacklist(),v.name))then table.insert(blacktbl,v) ebs[k]=nil end end end + --for k,v in pairs(ebs)do if(isvalid(v))then if(table.HasValue(warptorio.GetModTable("harvester_blacklist"),v.name))then table.insert(blacktbl,v) ebs[k]=nil end end end + + --for k,v in pairs(ecs)do if(isvalid(v))then if(table.HasValue(warptorio.GetWarpBlacklist(),v.name))then table.insert(blacktbl,v) ecs[k]=nil end end end + --for k,v in pairs(ecs)do if(isvalid(v))then if(table.HasValue(warptorio.GetModTable("harvester_blacklist"),v.name))then table.insert(blacktbl,v) ecs[k]=nil end end end + + if (ecsc > 0) then for i = ecsc, 1, -1 do if (not ecs[i] or not ecs[i].valid) then table.remove(ecs, i) end end end -- bad ents in table ? + + warptorio.Cloned_Entities = {} + warptorio.IsCloning = true + -- f.clone_entities { entities = ecs, destination_surface = hf, destination_offset = vector.mul(vector.sub(self.position, self.deploy_position), -1), snap_to_grid = false } + f.clone_entities { entities = ecs, destination_surface = hf, destination_offset = { self.deploy_position.x - self.position.x, self.deploy_position.y - self.position.y }, snap_to_grid = false } + local fe = warptorio.Cloned_Entities + warptorio.IsCloning = false + warptorio.Cloned_Entities = nil + + if (ebsc > 0) then for i = ebsc, 1, -1 do if (not ebs[i] or not ebs[i].valid) then table.remove(ebs, i) end end end -- bad ents in table ? + + vector.LayTiles("warptorio-red-concrete", f, self:GetDeployArea()) + + -- this doesnt really work + + warptorio.Cloned_Entities = {} + warptorio.IsCloning = true + -- hf.clone_entities { entities = ebs, destination_surface = f, destination_offset = vector.mul(vector.sub(self.position, self.deploy_position), -1), snap_to_grid = false } + hf.clone_entities { entities = ebs, destination_surface = f, destination_offset = { self.deploy_position.x - self.position.x, self.deploy_position.y - self.position.y }, snap_to_grid = false } + local hfe = warptorio.Cloned_Entities + warptorio.IsCloning = false + warptorio.Cloned_Entities = nil + + local hfm = {} + for k, v in pairs(hfe) do + if (isvalid(v.source) and isvalid(v.destination) and table.HasValue(ebs, v.source)) then + table.insert(hfm, v.source) + end + end + local fm = {} + for k, v in pairs(fe) do + if (isvalid(v.source) and isvalid(v.destination) and table.HasValue(ecs, v.source)) then + table.insert(fm, v.source) + end + end + + for k, v in pairs(fm) do + if (isvalid(v) and v ~= self.points[1].ent and v ~= self.points[2].ent) then + entity.destroy(v) + end + end + for k, v in pairs(hfm) do + if (isvalid(v) and v ~= self.points[1].ent and v ~= self.points[2].ent) then + entity.destroy(v) + end + end + + for k, v in pairs(blacktbl) do if (v and v.valid) then v.destroy { raise_destroy = true } end end -- cleanup past entities + + vector.clearplayers(f, planetArea) + + self.deployed = true + -- game.print("deployed") + self:CheckTeleporterPairs() +end diff --git a/control_class_rails.lua b/control_class_rails.lua index 5690098..bcae97c 100644 --- a/control_class_rails.lua +++ b/control_class_rails.lua @@ -1,129 +1,232 @@ - -local TRAIL={} TRAIL.__index=TRAIL warptorio.RailMeta=TRAIL -function TRAIL.__init(self,tbl) - self.key=self.key or tbl.key - self.chests={{}} - self.rails={} - self.loaders={{},{},{},{}} - self.chestcontents={} - self.dir="output" - global.Rails[self.key]=self -end - -function TRAIL:Data() return warptorio.platform.rails[self.key] end - -function TRAIL:MakeRails() - local f=warptorio.GetMainSurface() - local tps=self:Data() - if(not isvalid(self.rails[1]) or not isvalid(self.rails[2]))then vector.clean(f,vector.square(tps.railpos,vector(1,1))) end - if(not isvalid(self.rails[1]))then self.rails[1]=entity.protect(entity.spawn(f,"straight-rail",tps.railpos,defines.direction.south),false,false) end - if(not isvalid(self.rails[2]))then self.rails[2]=entity.protect(entity.spawn(f,"straight-rail",tps.railpos,defines.direction.east),false,false) end -end - -function TRAIL:MakeChests() - local ccls=warptorio.GetChest(self.dir) - local tps=self:Data() - local f=global.floor[tps.floor].host - for i,px in pairs(vector.compasscorn)do - local v=self.chests[1][i] - if(isvalid(v) and v.name~=ccls)then self.chestcontents[i]=v.get_inventory(defines.inventory.chest).get_contents() v.destroy{raise_destroy=true} end - if(not isvalid(v))then - local vpos=tps.chestpos+px*0.5 - local varea=vector.square(vpos,vector(0.5,0.5)) - vector.clean(f,varea) - v=entity.protect(entity.create(f,ccls,vpos),false,false) - self.chests[1][i]=v - local inv=self.chestcontents[i] - if(inv)then local cv=v.get_inventory(defines.inventory.chest) for x,y in pairs(inv)do cv.insert{name=x,count=y} end self.chestcontents[i]=nil end - end - cache.get_raise_type("types",v.type,v,"Rails",self.key,"chests",1,i) - end -end - -function TRAIL:Rotate() self:MakeChests() for i,tbl in pairs(self.loaders)do for k,v in pairs(tbl)do v.loader_type=self.dir end end end - - -function TRAIL:MakeLoaders() - local tps=self:Data() - local f=global.floor[tps.floor].host - local bcls=warptorio.GetBelt(self.dir) - for i,b in pairs(tps.logs)do if(b)then - local cd=vector.compass[string.compass[i]]*2 - - for x=1,2,1 do - local v=self.loaders[i][x] - if(isvalid(v) and v.name~=bcls)then entity.destroy(v) end - if(not isvalid(v))then - local vang=(((i-1)*2)+4)%8 - local vpos=tps.chestpos+cd+vector.compassall[string.compassall[((vang+2)%8)+1]]*(x==1 and 0.5 or -0.5) - local varea=vector.square(vpos,vector((i==1 or i==3) and 0.5 or 1,(i==1 or i==3) and 1 or 0.5)) - vector.clean(f,varea) - v=entity.protect(entity.create(f,bcls,vpos,vang),false,false) - v.loader_type=self.dir - self.loaders[i][x]=v - end - cache.force_entity(v,"Rails",self.key,"loaders",i,x) - end - end end -end - - -function TRAIL:DoMakes() self:MakeRails() self:MakeChests() self:MakeLoaders() end - --- Warp Rail Logistics - - -function TRAIL:SplitItem(u,n) local c=n local cx=0 local cinv={} local ui={name=k,count=n} - for k,v in pairs(self.chests[1])do local iv=v.get_inventory(defines.inventory.chest) if(iv.can_insert(u))then cinv[k]=iv end end local tcn=table_size(cinv) - for k,v in pairs(cinv)do if(c>0)then local w=v.insert{name=u,count=math.ceil(c/tcn)} cx=cx+w c=c-w tcn=tcn-1 end end - return cx -end - -function TRAIL:UnloadLogistics(e) for _,r in pairs(e)do - local inv=r.get_inventory(defines.inventory.cargo_wagon) for k,v in pairs(inv.get_contents())do local ct=self:SplitItem(k,v) if(ct>0)then inv.remove({name=k,count=ct}) end end -end end - -function TRAIL:LoadLogistics(e) - local inv={} for k,v in pairs(self.chests[1])do inv[k]=v.get_inventory(defines.inventory.chest) end - local ct={} for k,v in pairs(inv)do for a,b in pairs(v.get_contents())do ct[a]=(ct[a] or 0)+b end v.clear() end - for _,r in pairs(e)do local tr=r.get_inventory(defines.inventory.cargo_wagon) for k,v in pairs(ct)do ct[k]=v-(tr.insert{name=k,count=v}) end end - local ci for a,b in pairs(ct)do local g=b ci=#inv - for k,v in pairs(inv)do if(ci>0)then local gci=math.ceil(g/ci) if(gci>0)then local w=v.insert{name=a,count=math.ceil(g/ci)} ci=ci-1 g=g-w end end end - end -end -function TRAIL:BalanceChests() local inv={} for k,v in pairs(self.chests[1])do if(isvalid(v))then inv[k]=v.get_inventory(defines.inventory.chest) end end if(table_size(inv)>0)then - local ct={} for k,v in pairs(inv)do for a,b in pairs(v.get_contents())do ct[a]=(ct[a] or 0)+b end v.clear() end - local ci for a,b in pairs(ct)do local g=b ci=table_size(inv) for k,v in pairs(inv)do - local gci=math.ceil(g/ci) if(gci>0)then local w=v.insert{name=a,count=math.ceil(g/ci)} ci=ci-1 g=g-w end - end end -end end - -function TRAIL:TickLogistics() local f=global.floor.main.host if(not f.valid)then return end local c=self:Data().railpos - local e=f.find_entities_filtered{name="cargo-wagon",area={{c.x-1,c.y-1},{c.x+1,c.y+1}} } - if(table_size(e)>0)then if(self.dir=="output")then self:UnloadLogistics(e) self:BalanceChests() else self:LoadLogistics(e) end else self:BalanceChests() end -end - - -events.on_tick(3,0,"TickRails",function(ev) for k,v in pairs(global.Rails)do v:TickLogistics() end end) ---[[ old stuff - - --- Warp Rail Constructor - -function warptorio.BuildRailCorner(cn) local r=gwarptorio.Rails[cn] --if(true) then return end - if(not r)then r=trail(cn) - local f,fp=warptorio.GetFactorySurface(),warptorio.GetMainSurface() local c,co,cl=platform.railCorner[cn],platform.railOffset[cn],platform.railLoader[cn] - local vec,cx=vector(2,2),c+co - local sq=vector.square(cx,vec) - vector.clear(fp,sq) vector.clear(f,sq) cx=c+vector(-1,-1) vector.clear(f,vector.square(cx,vec)) vector.clear(f,vector.square(cx+cl[1],vec)) vector.clear(f,vector.square(cx+cl[2],vec)) - end - r:DoMakes() -end - -function warptorio.BuildRails() warptorio.BuildRailCorner("nw") warptorio.BuildRailCorner("sw") warptorio.BuildRailCorner("ne") warptorio.BuildRailCorner("se") end --for k,v in pairs(warptorio.railCorn)do warptorio.BuildRailCorner(k) end end - - - -]] - - +local TRAIL = {} +TRAIL.__index = TRAIL +warptorio.RailMeta = TRAIL +function TRAIL.__init(self, tbl) + self.key = self.key or tbl.key + self.chests = { {} } + self.rails = {} + self.loaders = { {}, {}, {}, {} } + self.chestcontents = {} + self.dir = "output" + storage.Rails[self.key] = self +end + +function TRAIL:Data() + return warptorio.platform.rails[self.key] +end + +function TRAIL:MakeRails() + local f = warptorio.GetMainSurface() + local tps = self:Data() + if (not isvalid(self.rails[1]) or not isvalid(self.rails[2])) then + vector.clean(f, + vector.square(tps.railpos, vector(1, 1))) + end + if (not isvalid(self.rails[1])) then + self.rails[1] = entity.protect( + entity.spawn(f, "straight-rail", tps.railpos, defines.direction.south), false, false) + end + if (not isvalid(self.rails[2])) then + self.rails[2] = entity.protect( + entity.spawn(f, "straight-rail", tps.railpos, defines.direction.east), false, false) + end +end + +function TRAIL:MakeChests() + local ccls = warptorio.GetChest(self.dir) + local tps = self:Data() + local f = storage.floor[tps.floor].host + for i, px in pairs(vector.compasscorn) do + local v = self.chests[1][i] + if (isvalid(v) and v.name ~= ccls) then + self.chestcontents[i] = v.get_inventory(defines.inventory.chest).get_contents() + v.destroy { raise_destroy = true } + end + if (not isvalid(v)) then + local vpos = tps.chestpos + px * 0.5 + local varea = vector.square(vpos, vector(0.5, 0.5)) + vector.clean(f, varea) + v = entity.protect(entity.create(f, ccls, vpos), false, false) + self.chests[1][i] = v + local inv = self.chestcontents[i] + if (inv) then + local cv = v.get_inventory(defines.inventory.chest) + for x, y in pairs(inv) do cv.insert { name = x, count = y } end + self.chestcontents[i] = nil + end + end + cache.get_raise_type("types", v.type, v, "Rails", self.key, "chests", 1, i) + end +end + +function TRAIL:Rotate() + self:MakeChests() + for i, tbl in pairs(self.loaders) do + for k, v in pairs(tbl) do + v.loader_type = self.dir + end + end +end + +function TRAIL:MakeLoaders() + local tps = self:Data() + local f = storage.floor[tps.floor].host + local bcls = warptorio.GetBelt(self.dir) + for i, b in pairs(tps.logs) do + if (b) then + local cd = vector.compass[string.compass[i]] * 2 + for x = 1, 2, 1 do + local v = self.loaders[i][x] + if (isvalid(v) and v.name ~= bcls) then + entity.destroy(v) + end + if (not isvalid(v)) then + local vang = (((i - 1) * 2) + 4) % 8 + local vpos = tps.chestpos + cd + + vector.compassall[string.compassall[((vang + 2) % 8) + 1]] * (x == 1 and 0.5 or -0.5) + local varea = vector.square(vpos, vector((i == 1 or i == 3) and 0.5 or 1, (i == 1 or i == 3) and 1 or + 0.5)) + vector.clean(f, varea) + v = entity.protect(entity.create(f, bcls, vpos, (vang * 2 + 8) % 16), false, false) + v.loader_type = self.dir + self.loaders[i][x] = v + end + cache.force_entity(v, "Rails", self.key, "loaders", i, x) + end + end + end +end + +function TRAIL:DoMakes() + self:MakeRails() + self:MakeChests() + self:MakeLoaders() +end + +-- Warp Rail Logistics + +function TRAIL:SplitItem(u, n) + local c = n + local cx = 0 + local cinv = {} + local ui = { name = k, count = n } + for k, v in pairs(self.chests[1]) do + local iv = v.get_inventory(defines.inventory.chest) + if (iv.can_insert(u)) then + cinv[k] = iv + end + end + local tcn = table_size(cinv) + for k, v in pairs(cinv) do + if (c > 0) then + local w = v.insert { name = u, count = math.ceil(c / tcn) } + cx = cx + w + c = c - w + tcn = tcn - 1 + end + end + return cx +end + +function TRAIL:UnloadLogistics(e) + for _, r in pairs(e) do + local inv = r.get_inventory(defines.inventory.cargo_wagon) + for k, v in pairs(inv.get_contents()) do + local ct = self:SplitItem(v.name, v.count) + if (ct > 0) then inv.remove({ name = v.name, count = ct }) end + end + end +end + +function TRAIL:LoadLogistics(e) + local inv = {} + for k, v in pairs(self.chests[1]) do inv[k] = v.get_inventory(defines.inventory.chest) end + local ct = {} + for k, v in pairs(inv) do + for a, b in pairs(v.get_contents()) do ct[a] = (ct[a] or 0) + b end + v.clear() + end + for _, r in pairs(e) do + local tr = r.get_inventory(defines.inventory.cargo_wagon) + for k, v in pairs(ct) do ct[k] = v - (tr.insert { name = k, count = v }) end + end + local ci + for a, b in pairs(ct) do + local g = b + ci = #inv + for k, v in pairs(inv) do + if (ci > 0) then + local gci = math.ceil(g / ci) + if (gci > 0) then + local w = v.insert { name = a, count = math.ceil(g / ci) } + ci = ci - 1 + g = g - w + end + end + end + end +end + +function TRAIL:BalanceChests() + local inv = {} + for k, v in pairs(self.chests[1]) do if (isvalid(v)) then inv[k] = v.get_inventory(defines.inventory.chest) end end + if (table_size(inv) > 0) then + local ct = {} + for k, v in pairs(inv) do + for a, b in pairs(v.get_contents()) do ct[b] = (ct[b] or 0) + b.count end + v.clear() + end + local ci + for a, b in pairs(ct) do + local g = b + ci = table_size(inv) + for k, v in pairs(inv) do + local gci = math.ceil(g / ci) + if (gci > 0) then + local w = v.insert { name = a.name, count = math.ceil(g / ci) } + ci = ci - 1 + g = g - w + end + end + end + end +end + +function TRAIL:TickLogistics() + local f = storage.floor.main.host + if (not f.valid) then return end + local c = self:Data().railpos + local e = f.find_entities_filtered { name = "cargo-wagon", area = { { c.x - 1, c.y - 1 }, { c.x + 1, c.y + 1 } } } + if (table_size(e) > 0) then + if (self.dir == "output") then + self:UnloadLogistics(e) + self:BalanceChests() + else + self:LoadLogistics(e) + end + else + self:BalanceChests() + end +end + +events.on_tick(3, 0, "TickRails", function(ev) for k, v in pairs(storage.Rails) do v:TickLogistics() end end) +--[[ old stuff + + +-- Warp Rail Constructor + +function warptorio.BuildRailCorner(cn) local r=gwarptorio.Rails[cn] --if(true) then return end + if(not r)then r=trail(cn) + local f,fp=warptorio.GetFactorySurface(),warptorio.GetMainSurface() local c,co,cl=platform.railCorner[cn],platform.railOffset[cn],platform.railLoader[cn] + local vec,cx=vector(2,2),c+co + local sq=vector.square(cx,vec) + vector.clear(fp,sq) vector.clear(f,sq) cx=c+vector(-1,-1) vector.clear(f,vector.square(cx,vec)) vector.clear(f,vector.square(cx+cl[1],vec)) vector.clear(f,vector.square(cx+cl[2],vec)) + end + r:DoMakes() +end + +function warptorio.BuildRails() warptorio.BuildRailCorner("nw") warptorio.BuildRailCorner("sw") warptorio.BuildRailCorner("ne") warptorio.BuildRailCorner("se") end --for k,v in pairs(warptorio.railCorn)do warptorio.BuildRailCorner(k) end end + + + +]] diff --git a/control_class_teleporter.lua b/control_class_teleporter.lua index 9bf5d13..66d04c0 100644 --- a/control_class_teleporter.lua +++ b/control_class_teleporter.lua @@ -1,404 +1,547 @@ - - -function warptorio.GetPlatformTechLevel(nm) local tc=warptorio.platform.techs[nm] if(not tc)then return false end - if(tc.level_range or tc.levels)then return research.level(tc.tech) else return research.has(tc.tech) end -end -function warptorio.GetPlatformTechAmount(nm) local tc=warptorio.platform.techs[nm] if(not tc)then return false end - local lv=warptorio.GetPlatformTechLevel(nm) or 0 - if(tc.levels)then return tc.levels[lv] end -end - -function warptorio.GetPlatformResearches() -- cache stuff - if(warptorio.PlatformResearches)then return warptorio.PlatformResearches end - warptorio.PlatformResearches={} - for vi,v in pairs(warptorio.platform.techs)do - v.key=v.key or vi - if(v.levels)then for k in pairs(v.levels)do warptorio.PlatformResearches[v.tech.."-"..k]=v end - elseif(v.level_range)then for i=v.level_range[1],v.level_range[2] do warptorio.PlatformResearches[v.tech.."-"..i]=v end - else warptorio.PlatformResearches[v.tech]=v - end - end - return warptorio.PlatformResearches -end - -function warptorio.GetPlatformResearch(nm) return warptorio.GetPlatformResearches()[nm] end - -warptorio.ResearchEffects={} - - -function warptorio.ResearchEffects.retile(floors) - for k,v in pairs(floors)do warptorio.ConstructFloor(v,true) end -end -function warptorio.ResearchEffects.rehazard(floors) - for k,v in pairs(floors)do warptorio.ConstructFloorHazard(v) end -end -function warptorio.ResearchEffects.unlock_teleporters(tpt) if(not istable(tpt))then tpt={tpt} end - for i,nm in pairs(tpt)do - local tpx=warptorio.platform.teleporters[nm] - local gps=global.Teleporters[nm] - if(not gps)then - --game.print("New teleporter: " .. tostring(nm)) - gps=new(warptorio.TeleporterMeta,tpx) - end - gps:CheckTeleporterPairs(true) - end -end -function warptorio.ResearchEffects.unlock_rails(tpt) if(not istable(tpt))then tpt={tpt} end - for i,nm in pairs(tpt)do - local tpx=warptorio.platform.rails[nm] - local gps=global.Rails[nm] - if(not gps)then - --game.print("New Rails: " .. tostring(nm)) - gps=new(warptorio.RailMeta,tpx) - end - gps:DoMakes() - end -end - -function warptorio.ResearchEffects.harvesters(hvt) - for i,nm in pairs(hvt)do - local tpx=warptorio.platform.harvesters[nm] - local gps=global.Harvesters[nm] - if(not gps)then - gps=new(warptorio.HarvesterMeta,tpx) - end - gps:Upgrade() - end -end -function warptorio.ResearchEffects.upgrade_energy(tgt) - if(tgt==true)then - for k,v in pairs(global.Teleporters)do v:CheckTeleporterPairs(true) end - for k,v in pairs(global.Harvesters)do v:CheckTeleporterPairs(true) end - else - for k,v in pairs(tgt)do if(global.Teleporters[v])then global.Teleporters[v]:CheckTeleporterPairs(true) end end - end -end -function warptorio.ResearchEffects.upgrade_logistics(tgt) - if(tgt==true)then - for k,v in pairs(global.Teleporters)do v:CheckTeleporterPairs(true) end - for k,v in pairs(global.Harvesters)do v:CheckTeleporterPairs(true) end - for k,v in pairs(global.Rails)do v:DoMakes() end - else - for k,v in pairs(tgt)do if(global.Teleporters[v])then global.Teleporters[v]:CheckTeleporterPairs(true) end end - end -end -function warptorio.ResearchEffects.do_combinators() - for k,v in pairs(global.Harvesters)do v:CheckCombo(true) end -end -function warptorio.ResearchEffects.special(spt) - for k,v in pairs(spt)do warptorio.CheckPlatformSpecials(global.floor[v]) end -end -function warptorio.ResearchEffects.reactor(b,lv) - local m=global.floor.main players.playsound("warp_in",m.host) - for i=1,3,1 do for x,ply in pairs(game.players)do ply.print{"warptorio_lore."..lv .."_"..i} end end - - if(lv<6)then global.warp_auto_time=global.warp_auto_time+60*10 end - - if(lv>=8)then warptorio.ResetHUD() end - - --warptorio.CheckPlatformSpecials(global.floor.main) -end -function warptorio.ResearchEffects.ability(tgt) - warptorio.ResetHUD() -end -function warptorio.ResearchEffects.unlock_homeworld() - warptorio.ResetHUD() -end -function warptorio.ResearchEffects.unlock_toolbar() - warptorio.ResetHUD() -end - - -function warptorio.DoResearchEffects(fx,lv) - for k,v in pairs(fx)do - if(warptorio.ResearchEffects[k])then warptorio.ResearchEffects[k](v,lv) end - end -end -function warptorio.ResearchFinished(ev) - local rs=ev.research - --game.print("researched_finished: " .. rs.name) - local u=warptorio.GetPlatformResearch(rs.name) - if(u)then - local lv=warptorio.GetPlatformTechLevel(u.key) or 0 - --if(u.first_effect)then game.print("testing: " .. tostring(lv) .. " , " .. serpent.line(u)) end - - if(u.first_effect and (u.levels and (u.levels[0] and lv==0 or lv==1) or (u.level_range and lv==u.level_range[1])) )then - warptorio.DoResearchEffects(u.first_effect,lv) - --game.print("first effect") - end - if(u.effect)then warptorio.DoResearchEffects(u.effect,lv) end - if(u.lv_effect)then local lvt=u.lv_effect[lv] if(lvt)then warptorio.DoResearchEffects(lvt,lv) end end - - end - - warptorio.ConstructHazards() -end - - -events.on_event(defines.events.on_research_finished,warptorio.ResearchFinished) - - -local platform=warptorio.platform - ---[[ Warp Teleporters ]]-- - -local TELL={} TELL.__index=TELL warptorio.TeleporterMeta=TELL -function TELL.__init(self,tbl,bHarvester) - self.key=self.key or tbl.key - --self.maxloader=(tbl.logs and 1 or 0)+(tbl.dualloader and 1 or 0)+(tbl.triloader and 1 or 0) - --if(not tbl.prototype)then error(serpent.block(self)) end - self.offloader=(tbl.prototype and 1 or 0) - - self.points=self.points or {{},{}} - self.chestcontents=self.chestcontents or {{},{}} - self.loaders=self.loaders or {{},{}} - self.pipes=self.pipes or {{},{}} - self.chests=self.chests or {{},{}} - if(not self.dir)then self.dir={{},{}} for i=1,6,1 do self.dir[1][i]="input" self.dir[2][i]="output" end end - self.loaderFilter=self.loaderFilter or {{},{}} - self.sprites=self.sprites or {{},{}} - self.sprite_arrows=self.sprite_arrows or {nil,nil} - if(not bHarvester)then global.Teleporters[self.key]=self end -end -function TELL:Data() return warptorio.platform.teleporters[self.key] end - -function TELL:ValidA() return isvalid(self.points[1].ent) end -function TELL:ValidB() return isvalid(self.points[2].ent) end - -function TELL:ConnectCircuit() local p=self.points - if(self:ValidA() and self:ValidB())then - p[1].ent.connect_neighbour({target_entity=p[2].ent,wire=defines.wire_type.red}) - p[1].ent.connect_neighbour({target_entity=p[2].ent,wire=defines.wire_type.green}) - end -end - -function TELL:CheckTeleporterPairs(bSound) -- Call updates and stuff. Automatically deals with logistics, upgrades and cleaning as-needed with good accuracy - local tps=self:Data() - if(tps.pair)then for i,t in pairs(tps.pair)do local pi=self.points[i] self:MakePointTeleporter(tps,i,t,(t.gate and isvalid(pi.ent)) and pi.ent.position or nil) end end - local ca=cache.get_entity(self.points[1].ent) - local cb=cache.get_entity(self.points[2].ent) - if(ca and cb)then ca.teleport_dest=cb.host cb.teleport_dest=ca.host else if(ca)then ca.teleport_dest=nil end if(cb)then cb.teleport_dest=nil end end - if(tps.circuit)then self:ConnectCircuit() end -end - - - ---[[ Teleporter Logistics & Spawning Stuff ]]-- - - -function TELL:DestroyPointTeleporter(i,rd) - local e=self.points[i].ent if(isvalid(e))then self.points[i].energy=e.energy entity.destroy(e,rd) end - self:DestroyPointSprites(i) -end -function TELL:DestroyPointSprites(i) - if(self.sprites and self.sprites[i])then for k,v in pairs(self.sprites[i])do if(rendering.is_valid(v))then rendering.destroy(v) self.sprites[i][k]=nil end end end - if(self.sprite_arrows and self.sprite_arrows[i])then if(rendering.is_valid(self.sprite_arrows[i]))then rendering.destroy(self.sprite_arrows[i]) self.sprite_arrows[i]=nil end end -end -function TELL:CheckPointSprites(i) - local tps=self:Data() local t=tps.pair[i] - if(warptorio.setting("hide_sprites"))then self:DestroyPointSprites(i) else - if(t.sprites)then self:MakePointSprites(tps,i,t.sprites) end - if(t.sprite_arrow)then self:MakePointArrow(tps,i,t.sprite_arrow) end - end -end - -function TELL:MakePointTeleporter(tps,i,t,pos) - local p=self.points[i] - local f=global.floor[t.floor].host - - local epos - if(t.prototype)then - local vproto=t.prototype - if(tps.energy)then vproto=vproto.."-"..warptorio.GetPlatformTechLevel(tps.energy) end - local e=p.ent - if(isvalid(e))then - if(e.surface~=f)then self:DestroyPointTeleporter(i) self:DestroyPointLogistics(i) - elseif(e.name~=vproto)then epos=e.position self:DestroyPointTeleporter(i) - end - end - if(not isvalid(e))then - local vepos=epos or (pos or t.position) - if(not vepos)then return end - local vpos=((t.gate and not epos) and f.find_non_colliding_position(vproto,vepos,0,1,1) or vepos) - --error(serpent.line(vpos)) - local varea - if(not t.gate)then varea=vector.square(vpos+vector(0.5,0.5),vector(2,2)) vector.clean(f,varea) end - e=entity.protect(entity.create(f,vproto,vpos),t.minable~=nil and t.minable or false,t.destructible~=nil and t.destructible or false) - if(not t.gate)then vector.cleanplayers(f,varea) end - p.ent=e - end - if(p.energy)then e.energy=e.energy+p.energy p.energy=nil end - if(t.sprites)then self:MakePointSprites(tps,i,t.sprites) end - if(t.sprite_arrow)then self:MakePointArrow(tps,i,t.sprite_arrow) end - end - if(epos or not t.gate)then self:CheckPointLogistics(i) end - - local ce=cache.force_entity(p.ent,"Teleporters",self.key,"points",i) -end - - -warptorio.arrowSprite={sprite="utility/medium_gui_arrow",target_offset={0.75,-0.75},x_scale=0.4,y_scale=0.4} - -function TELL:MakePointArrow(tps,i,arrow) - local spid=self.sprite_arrows[i] - if(spid and rendering.is_valid(spid))then return end - local tp=self.points[i].ent - local t=table.deepcopy(warptorio.arrowSprite) - t.surface=tp.surface - t.target=tp - t.only_in_alt_mode=true - t.render_layer="higher-object-above" - t.orientation=(arrow=="down" and 0.5 or 0) - self.sprite_arrows[i]=rendering.draw_sprite(t) -end - -function TELL:MakePointSprites(tps,i,sprites) - for k,v in pairs(sprites)do - local spid=self.sprites[i][k] - if(not (spid and rendering.is_valid(spid)))then - local tp=self.points[i].ent - local t=table.deepcopy(v) - t.surface=tp.surface t.target=tp t.only_in_alt_mode=true t.render_layer="higher-object-under" - self.sprites[i][k]=rendering.draw_sprite(t) - end - end -end - - -function TELL:GetLoaderDirection() local tps=self:Data() - if(tps.dirsetting)then return warptorio.setting(tps.dirsetting) end - return (tps.staticdir and tps.staticdir or (tps.top and warptorio.setting("loader_top") or warptorio.setting("loader_bottom"))) or "up" -end - -function TELL:DestroyPointLogistics(o) - if(self.chests)then for k,v in pairs(self.chests[o])do self.chestcontents[o][k]=v.get_inventory(defines.inventory.chest).get_contents() entity.destroy(v) self.chests[o][k]=nil end end - for k,v in pairs(self.loaders[o])do if(v and isvalid(v))then - self.loaderFilter[o][k]={} for i=1,v.filter_slot_count,1 do self.loaderFilter[o][k][i]=v.get_filter(i) end entity.destroy(v) - end self.loaders[o][k]=nil end - for k,v in pairs(self.pipes[o])do entity.destroy(v) self.pipes[o][k]=nil end -end - -function TELL:RemakeChestPair(o,k) local e=self.chests[o][k] local ex=warptorio.GetChest(self.dir[o][k]) - if(e and e.name~=ex)then - local v=entity.protect(entity.create(e.surface,ex,e.position),false,false) entity.copy.chest(e,v) - entity.destroy(e) self.chests[o][k]=v if(self.dir[o][k]=="input")then entity.ChestRequestMode(v) end - cache.get_raise_type("types",v.type,v,"Teleporters",self.key,"chests",o,k) - end -end -function TELL:SwapLoaderChests(id) self:RemakeChestPair(1,id) self:RemakeChestPair(2,id) end -function TELL:UpgradeChests() for i=1,6,1 do self:SwapLoaderChests(i) end end - -function TELL:GetTeleporterSize() local d=self:Data() return warptorio.GetTeleporterSize(d.logs,d.dualloader,d.triloader) end -function TELL:GetLogisticsArea(o) return vector.square(o or self:Data().position,self:GetTeleporterSize()) end - - - - -function TELL:MakePointLoader(tps,i,id,ido,pos,f,belt,lddir,chesty,belty,vexdir) - local offld=tps.pair[i].prototype and 1 or 0 - - local v=self.loaders[i][id] - if(isvalid(v) and v.name~=belt)then v.destroy{raise_destroy=true} end - if(not isvalid(v))then - local vpos=vector(pos)+vector((offld+ido)*vexdir,belty) - local varea=vector.square(vpos+vector(0,0.5),vector(1,1)) - vector.clean(f,varea) - v=entity.protect(entity.create(f,belt,vpos,lddir),false,false) - vector.cleanplayers(f,varea) - v.loader_type=self.dir[i][id] - self.loaders[i][id]=v - local inv=self.loaderFilter[i][id] if(inv)then for invx,invy in pairs(inv)do v.set_filter(invx,invy) end end - end - cache.force_entity(v,"Teleporters",self.key,"loaders",i,id) - - local v=self.chests[i][id] - local chest=warptorio.GetChest(self.dir[i][id]) - if(isvalid(v) and v.name~=chest)then self.chestcontents[i][id]=v.get_inventory(defines.inventory.chest).get_contents() v.destroy{raise_destroy=true} end - if(not isvalid(v))then - local vpos=vector(pos)+vector((offld+ido)*vexdir,chesty) - local varea=vector.square(vpos,vector(0.5,0.5)) - vector.clean(f,varea) - v=entity.protect(entity.create(f,chest,vpos),false,false) - vector.cleanplayers(f,varea) - self.chests[i][id]=v - local inv=self.chestcontents[i][id] - if(inv)then local cv=v.get_inventory(defines.inventory.chest) for x,y in pairs(inv)do cv.insert{name=x,count=y} end self.chestcontents[i][id]=nil end - --if(v.type=="logistic-container")then entity.ChestRequestMode(r) end - end - cache.get_raise_type("types",v.type,v,"Teleporters",self.key,"chests",i,id) - - -end -function TELL:MakePointLoaders(tps,i,id,pos,f,belt,lddir,chesty,belty) - if(not tps.oneside or tps.oneside=="right")then self:MakePointLoader(tps,i,id,id,pos,f,belt,lddir,chesty,belty,1) end - if(not tps.oneside or tps.oneside=="left")then self:MakePointLoader(tps,i,id+3,id,pos,f,belt,lddir,chesty,belty,-1) end -end -function TELL:MakePointPipes(tps,i,id,pos,f,dist,vexdir,ido) -- TODO: Initial pipe dir & remember direction - local pipe="warptorio-logistics-pipe" - local v=self.pipes[i][id] - local vpos=vector(pos)+vector(dist*vexdir,2-ido) - local pipedir=(vexdir==1 and 2 or 6) - if(isvalid(v) and (v.surface~=f or v.position.x~=vpos.x or v.position.y~=vpos.y))then pipedir=v.direction entity.destroy(v) end - if(not isvalid(v))then - local varea=vector.square(vpos,vector(0.5,0.5)) - vector.clean(f,varea) - v=entity.protect(entity.create(f,pipe,vpos,pipedir),false,false) - vector.cleanplayers(f,varea) - self.pipes[i][id]=v - end - - cache.force_entity(v,"Teleporters",self.key,"pipes",i,id) -end -function TELL:CheckEmptyPipes() - local ppr={} for a,b in pairs(self.pipes)do for k,v in pairs(b)do if(isvalid(v) and table_size(v.neighbours[1])>=1)then ppr[k]=true end end end - for a,b in pairs(self.pipes)do for k,v in pairs(b)do if(isvalid(v) and not ppr[k])then v.clear_fluid_inside() end end end -end - -function TELL:CheckPointLogistics(i,vxpos) - local tps=self:Data() - local t=tps.pair[i] - if(not tps.logs and not tps.dualloader and not tps.triloader)then return end - local belt=warptorio.GetBelt() - local pos=vxpos or t.position+vector(0.5,0.5) - if(t.gate and not vxpos)then if(not isvalid(self.points[i].ent))then return end pos=vector(self.points[i].ent.position) end - local f=global.floor[t.floor].host - local offld=tps.pair[i].prototype and 1 or 0 - local lddir,chesty,belty - if(self:GetLoaderDirection()=="up")then lddir=defines.direction.north chesty=-1 belty=0 else lddir=defines.direction.south chesty=1 belty=-1 end - local ldl=0 - local lvLogs=research.level("warptorio-logistics") - if(tps.logs and lvLogs>0)then ldl=ldl+1 end - if(tps.dualloader and research.has("warptorio-dualloader-1"))then ldl=ldl+1 end - if(tps.triloader and research.has("warptorio-triloader"))then ldl=ldl+1 end - local can=true - if(t.gate)then -- check if placement area is clear - local vsize=offld+ldl+(tps.dopipes and 1 or 0) - local varea=vector.square(pos,vector(vsize*2,3)) - if(f.count_entities_filtered{area=varea,collision_mask={"object-layer"}} >1)then - f.create_entity{name="flying-text", position=pos, text="Logistics blocked - Needs more space", color={r=1,g=0.5,b=0.5}} - f.play_sound{path="utility/cannot_build",position=pos} - --game.print("Planet Teleporter Gate Logistics were blocked by nearby obstructions") - can=false - end - end - if(can and ldl>0)then for id=1,ldl,1 do - self:MakePointLoaders(tps,i,id,pos,f,belt,lddir,chesty,belty) - end end - if(can and tps.dopipes and lvLogs>0)then for id=1,math.min(lvLogs,3),1 do -- pipes first, it removes the old ones - if(not tps.oneside or tps.oneside=="right")then self:MakePointPipes(tps,i,id,pos,f,ldl+offld+1,1,id) end - if(not tps.oneside or tps.oneside=="left")then self:MakePointPipes(tps,i,id+3,pos,f,ldl+offld+1,-1,id) end - end end -end - ---[[ -function events.on_tick("logistics_teleporters",function(ev) for k,v in pairs(global.Teleporters)do v:TickLogistics() end end end) - -function TELL:TickLogistics() - for k,v in pairs(self.chests[1])do if(isvalid(self.chests[2][k]))then - if(self.dir[1][k]=="input")then warptorio.BalanceLogistics(v,self.chests[2][k]) else warptorio.BalanceLogistics(self.chests[2][k],v) end - end end - for k,v in pairs(self.pipes[1])do if(isvalid(self.pipes[2][k]))then - warptorio.BalanceLogistics(v,self.pipes[2][k]) - end end -end]] - +function warptorio.GetPlatformTechLevel(nm) + local tc = warptorio.platform.techs[nm] + if (not tc) then return false end + if (tc.level_range or tc.levels) then return research.level(tc.tech) else return research.has(tc.tech) end +end + +function warptorio.GetPlatformTechAmount(nm) + local tc = warptorio.platform.techs[nm] + if (not tc) then return false end + local lv = warptorio.GetPlatformTechLevel(nm) or 0 + if (tc.levels) then return tc.levels[lv] end +end + +function warptorio.GetPlatformResearches() -- cache stuff + if (warptorio.PlatformResearches) then return warptorio.PlatformResearches end + warptorio.PlatformResearches = {} + for vi, v in pairs(warptorio.platform.techs) do + v.key = v.key or vi + if (v.levels) then + for k in pairs(v.levels) do warptorio.PlatformResearches[v.tech .. "-" .. k] = v end + elseif (v.level_range) then + for i = v.level_range[1], v.level_range[2] do warptorio.PlatformResearches[v.tech .. "-" .. i] = v end + else + warptorio.PlatformResearches[v.tech] = v + end + end + return warptorio.PlatformResearches +end + +function warptorio.GetPlatformResearch(nm) return warptorio.GetPlatformResearches()[nm] end + +warptorio.ResearchEffects = {} + + +function warptorio.ResearchEffects.retile(floors) + for k, v in pairs(floors) do warptorio.ConstructFloor(v, true) end +end + +function warptorio.ResearchEffects.rehazard(floors) + for k, v in pairs(floors) do warptorio.ConstructFloorHazard(v) end +end + +function warptorio.ResearchEffects.unlock_teleporters(tpt) + if (not istable(tpt)) then tpt = { tpt } end + for i, nm in pairs(tpt) do + local tpx = warptorio.platform.teleporters[nm] + local gps = storage.Teleporters[nm] + if (not gps) then + --game.print("New teleporter: " .. tostring(nm)) + gps = new(warptorio.TeleporterMeta, tpx) + end + gps:CheckTeleporterPairs(true) + end +end + +function warptorio.ResearchEffects.unlock_rails(tpt) + if (not istable(tpt)) then tpt = { tpt } end + for i, nm in pairs(tpt) do + local tpx = warptorio.platform.rails[nm] + local gps = storage.Rails[nm] + if (not gps) then + --game.print("New Rails: " .. tostring(nm)) + gps = new(warptorio.RailMeta, tpx) + end + gps:DoMakes() + end +end + +function warptorio.ResearchEffects.harvesters(hvt) + for i, nm in pairs(hvt) do + local tpx = warptorio.platform.harvesters[nm] + local gps = storage.Harvesters[nm] + if (not gps) then + gps = new(warptorio.HarvesterMeta, tpx) + end + gps:Upgrade() + end +end + +function warptorio.ResearchEffects.upgrade_energy(tgt) + if (tgt == true) then + for k, v in pairs(storage.Teleporters) do v:CheckTeleporterPairs(true) end + for k, v in pairs(storage.Harvesters) do v:CheckTeleporterPairs(true) end + else + for k, v in pairs(tgt) do if (storage.Teleporters[v]) then storage.Teleporters[v]:CheckTeleporterPairs(true) end end + end +end + +function warptorio.ResearchEffects.upgrade_logistics(tgt) + if (tgt == true) then + for k, v in pairs(storage.Teleporters) do v:CheckTeleporterPairs(true) end + for k, v in pairs(storage.Harvesters) do v:CheckTeleporterPairs(true) end + for k, v in pairs(storage.Rails) do v:DoMakes() end + else + for k, v in pairs(tgt) do if (storage.Teleporters[v]) then storage.Teleporters[v]:CheckTeleporterPairs(true) end end + end +end + +function warptorio.ResearchEffects.do_combinators() + for k, v in pairs(storage.Harvesters) do v:CheckCombo(true) end +end + +function warptorio.ResearchEffects.special(spt) + for k, v in pairs(spt) do warptorio.CheckPlatformSpecials(storage.floor[v]) end +end + +function warptorio.ResearchEffects.reactor(b, lv) + local m = storage.floor.main + players.playsound("warp_in", m.host) + for i = 1, 3, 1 do for x, ply in pairs(game.players) do ply.print { "warptorio_lore." .. lv .. "_" .. i } end end + + if (lv < 6) then storage.warp_auto_time = storage.warp_auto_time + 60 * 10 end + + if (lv >= 8) then warptorio.ResetHUD() end + + --warptorio.CheckPlatformSpecials(storage.floor.main) +end + +function warptorio.ResearchEffects.ability(tgt) + warptorio.ResetHUD() +end + +function warptorio.ResearchEffects.unlock_homeworld() + warptorio.ResetHUD() +end + +function warptorio.ResearchEffects.unlock_toolbar() + warptorio.ResetHUD() +end + +function warptorio.DoResearchEffects(fx, lv) + for k, v in pairs(fx) do + if (warptorio.ResearchEffects[k]) then warptorio.ResearchEffects[k](v, lv) end + end +end + +function warptorio.ResearchFinished(ev) + local rs = ev.research + --game.print("researched_finished: " .. rs.name) + local u = warptorio.GetPlatformResearch(rs.name) + if (u) then + local lv = warptorio.GetPlatformTechLevel(u.key) or 0 + --if(u.first_effect)then game.print("testing: " .. tostring(lv) .. " , " .. serpent.line(u)) end + + if (u.first_effect and (u.levels and (u.levels[0] and lv == 0 or lv == 1) or (u.level_range and lv == u.level_range[1]))) then + warptorio.DoResearchEffects(u.first_effect, lv) + --game.print("first effect") + end + if (u.effect) then warptorio.DoResearchEffects(u.effect, lv) end + if (u.lv_effect) then + local lvt = u.lv_effect[lv] + if (lvt) then warptorio.DoResearchEffects(lvt, lv) end + end + end + + warptorio.ConstructHazards() +end + +events.on_event(defines.events.on_research_finished, warptorio.ResearchFinished) + + +local platform = warptorio.platform + +--[[ Warp Teleporters ]] -- + +local TELL = {} +TELL.__index = TELL +warptorio.TeleporterMeta = TELL +function TELL.__init(self, tbl, bHarvester) + self.key = self.key or tbl.key + --self.maxloader=(tbl.logs and 1 or 0)+(tbl.dualloader and 1 or 0)+(tbl.triloader and 1 or 0) + --if(not tbl.prototype)then error(serpent.block(self)) end + self.offloader = (tbl.prototype and 1 or 0) + + self.points = self.points or { {}, {} } + self.chestcontents = self.chestcontents or { {}, {} } + self.loaders = self.loaders or { {}, {} } + self.pipes = self.pipes or { {}, {} } + self.chests = self.chests or { {}, {} } + if (not self.dir) then + self.dir = { {}, {} } + for i = 1, 6, 1 do + self.dir[1][i] = "input" + self.dir[2][i] = "output" + end + end + self.loaderFilter = self.loaderFilter or { {}, {} } + self.sprites = self.sprites or { {}, {} } + self.sprite_arrows = self.sprite_arrows or { nil, nil } + if (not bHarvester) then storage.Teleporters[self.key] = self end +end + +function TELL:Data() return warptorio.platform.teleporters[self.key] end + +function TELL:ValidA() return isvalid(self.points[1].ent) end + +function TELL:ValidB() return isvalid(self.points[2].ent) end + +function TELL:ConnectCircuit() + local p = self.points + if (self:ValidA() and self:ValidB()) then + local red1 = p[1].ent.get_wire_connector(defines.wire_connector_id.circuit_red, true) + local red2 = p[2].ent.get_wire_connector(defines.wire_connector_id.circuit_red, true) + red1.connect_to(red2) + local green1 = p[1].ent.get_wire_connector(defines.wire_connector_id.circuit_green, true) + local green2 = p[2].ent.get_wire_connector(defines.wire_connector_id.circuit_green, true) + green1.connect_to(green2) + end +end + +function TELL:CheckTeleporterPairs(bSound) -- Call updates and stuff. Automatically deals with logistics, upgrades and cleaning as-needed with good accuracy + local tps = self:Data() + if (tps.pair) then + for i, t in pairs(tps.pair) do + local pi = self.points[i] + self:MakePointTeleporter(tps, i, t, (t.gate and isvalid(pi.ent)) and pi.ent.position or nil) + end + end + local ca = cache.get_entity(self.points[1].ent) + local cb = cache.get_entity(self.points[2].ent) + if (ca and cb) then + ca.teleport_dest = cb.host + cb.teleport_dest = ca.host + else + if (ca) then ca.teleport_dest = nil end + if (cb) then cb.teleport_dest = nil end + end + if (tps.circuit) then self:ConnectCircuit() end +end + +--[[ Teleporter Logistics & Spawning Stuff ]] -- + +function TELL:DestroyPointTeleporter(i, rd) + local e = self.points[i].ent + if (isvalid(e)) then + self.points[i].energy = e.energy + entity.destroy(e, rd) + end + self:DestroyPointSprites(i) +end + +function TELL:DestroyPointSprites(i) + if (self.sprites and self.sprites[i]) then + for k, v in pairs(self.sprites[i]) do + if (v.valid) then + v.destroy() + self.sprites[i][k] = nil + end + end + end + if (self.sprite_arrows and self.sprite_arrows[i]) then + if (self.sprite_arrows[i] ~= nil) then + self.sprite_arrows[i].destroy() + self.sprite_arrows[i] = nil + end + end +end + +function TELL:CheckPointSprites(i) + local tps = self:Data() + local t = tps.pair[i] + if (warptorio.setting("hide_sprites")) then + self:DestroyPointSprites(i) + else + if (t.sprites) then self:MakePointSprites(tps, i, t.sprites) end + if (t.sprite_arrow) then self:MakePointArrow(tps, i, t.sprite_arrow) end + end +end + +function TELL:MakePointTeleporter(tps, i, t, pos) + local p = self.points[i] + local f = storage.floor[t.floor].host + local epos + if (t.prototype) then + local vproto = t.prototype + if (tps.energy) then vproto = vproto .. "-" .. warptorio.GetPlatformTechLevel(tps.energy) end + local e = p.ent + if (isvalid(e)) then + if (e.surface ~= f) then + self:DestroyPointTeleporter(i) + self:DestroyPointLogistics(i) + elseif (e.name ~= vproto) then + epos = e.position + self:DestroyPointTeleporter(i) + end + end + if (not isvalid(e)) then + local vepos = epos or (pos or t.position) + if (not vepos) then return end + local vpos = ((t.gate and not epos) and f.find_non_colliding_position(vproto, vepos, 0, 1, true) or vepos) + --error(serpent.line(vpos)) + local varea + if (not t.gate) then + varea = vector.square(vpos + vector(0.5, 0.5), vector(2, 2)) + vector.clean(f, varea) + end + e = entity.protect(entity.create(f, vproto, vpos), t.minable ~= nil and t.minable or false, + t.destructible ~= nil and t.destructible or false) + if (not t.gate) then vector.cleanplayers(f, varea) end + p.ent = e + end + if (p.energy) then + e.energy = e.energy + p.energy + p.energy = nil + end + if (t.sprites) then self:MakePointSprites(tps, i, t.sprites) end + if (t.sprite_arrow) then self:MakePointArrow(tps, i, t.sprite_arrow) end + end + if (epos or not t.gate) then self:CheckPointLogistics(i) end + + local ce = cache.force_entity(p.ent, "Teleporters", self.key, "points", i) +end + +warptorio.arrowSprite = { sprite = "utility/medium_gui_arrow", target_offset = { 0.75, -0.75 }, x_scale = 0.5, y_scale = 0.5 } + +function TELL:MakePointArrow(tps, i, arrow) + local spid = self.sprite_arrows[i] + if (spid and spid.valid) then return end + local tp = self.points[i].ent + local t = table.deepcopy(warptorio.arrowSprite) + t.surface = tp.surface + t.target = tp + t.only_in_alt_mode = true + t.render_layer = "higher-object-above" + t.orientation = (arrow == "down" and 0.5 or 0) + self.sprite_arrows[i] = rendering.draw_sprite(t) +end + +function TELL:MakePointSprites(tps, i, sprites) + for k, v in pairs(sprites) do + local spid = self.sprites[i][k] + if (not (spid and spid.valid)) then + local tp = self.points[i].ent + local t = table.deepcopy(v) + t.surface = tp.surface + t.target = tp + t.only_in_alt_mode = true + t.render_layer = "higher-object-under" + self.sprites[i][k] = rendering.draw_sprite(t) + end + end +end + +function TELL:GetLoaderDirection() + local tps = self:Data() + if (tps.dirsetting) then return warptorio.setting(tps.dirsetting) end + return (tps.staticdir and tps.staticdir or (tps.top and warptorio.setting("loader_top") or warptorio.setting("loader_bottom"))) or + "up" +end + +function TELL:DestroyPointLogistics(o) + if (self.chests) then + for k, v in pairs(self.chests[o]) do + self.chestcontents[o][k] = v.get_inventory(defines.inventory.chest).get_contents() + entity.destroy(v) + self.chests[o][k] = nil + end + end + for k, v in pairs(self.loaders[o]) do + if (v and isvalid(v)) then + self.loaderFilter[o][k] = {} + for i = 1, v.filter_slot_count, 1 do self.loaderFilter[o][k][i] = v.get_filter(i) end + entity.destroy(v) + end + self.loaders[o][k] = nil + end + for k, v in pairs(self.pipes[o]) do + entity.destroy(v) + self.pipes[o][k] = nil + end +end + +function TELL:RemakeChestPair(o, k) + local e = self.chests[o][k] + local ex = warptorio.GetChest(self.dir[o][k]) + if (e and e.name ~= ex) then + local v = entity.protect(entity.create(e.surface, ex, e.position), false, false) + entity.copy.chest(e, v) + entity.destroy(e) + self.chests[o][k] = v + if (self.dir[o][k] == "input") then entity.ChestRequestMode(v) end + cache.get_raise_type("types", v.type, v, "Teleporters", self.key, "chests", o, k) + end +end + +function TELL:SwapLoaderChests(id) + self:RemakeChestPair(1, id) + self:RemakeChestPair(2, id) +end + +function TELL:UpgradeChests() for i = 1, 6, 1 do self:SwapLoaderChests(i) end end + +function TELL:GetTeleporterSize() + local d = self:Data() + return warptorio.GetTeleporterSize(d.logs, d.dualloader, d.triloader) +end + +function TELL:GetLogisticsArea(o) return vector.square(o or self:Data().position, self:GetTeleporterSize()) end + +function TELL:MakePointLoader(tps, i, id, ido, pos, f, belt, lddir, chesty, belty, vexdir) + local offld = tps.pair[i].prototype and 1 or 0 + + local v = self.loaders[i][id] + if (isvalid(v) and v.name ~= belt) then v.destroy { raise_destroy = true } end + if (not isvalid(v)) then + local vpos = vector(pos) + vector((offld + ido) * vexdir, belty) + local varea = vector.square(vpos + vector(0, 0.5), vector(1, 1)) + vector.clean(f, varea) + v = entity.protect(entity.create(f, belt, vpos, lddir), false, false) + vector.cleanplayers(f, varea) + v.loader_type = self.dir[i][id] + self.loaders[i][id] = v + local inv = self.loaderFilter[i][id] + if (inv) then for invx, invy in pairs(inv) do v.set_filter(invx, invy) end end + end + cache.force_entity(v, "Teleporters", self.key, "loaders", i, id) + + local v = self.chests[i][id] + local chest = warptorio.GetChest(self.dir[i][id]) + if (isvalid(v) and v.name ~= chest) then + self.chestcontents[i][id] = v.get_inventory(defines.inventory.chest).get_contents() + v.destroy { raise_destroy = true } + end + if (not isvalid(v)) then + local vpos = vector(pos) + vector((offld + ido) * vexdir, chesty) + local varea = vector.square(vpos, vector(0.5, 0.5)) + vector.clean(f, varea) + v = entity.protect(entity.create(f, chest, vpos), false, false) + vector.cleanplayers(f, varea) + self.chests[i][id] = v + local inv = self.chestcontents[i][id] + if (inv) then + local cv = v.get_inventory(defines.inventory.chest) + for x, y in pairs(inv) do cv.insert { name = y.name, count = y.count } end + self.chestcontents[i][id] = nil + end + --if(v.type=="logistic-container")then entity.ChestRequestMode(r) end + end + cache.get_raise_type("types", v.type, v, "Teleporters", self.key, "chests", i, id) +end + +function TELL:MakePointLoaders(tps, i, id, pos, f, belt, lddir, chesty, belty) + if (not tps.oneside or tps.oneside == "right") then + self:MakePointLoader(tps, i, id, id, pos, f, belt, lddir, chesty, + belty, 1) + end + if (not tps.oneside or tps.oneside == "left") then + self:MakePointLoader(tps, i, id + 3, id, pos, f, belt, lddir, + chesty, belty, -1) + end +end + +function TELL:MakePointPipes(tps, i, id, pos, f, dist, vexdir, ido) -- TODO: Initial pipe dir & remember direction + local pipe = "warptorio-logistics-pipe" + local v = self.pipes[i][id] + local vpos = vector(pos) + vector(dist * vexdir, 2 - ido) + local pipedir = (vexdir == 1 and 3 or 6) + if (isvalid(v) and (v.surface ~= f or v.position.x ~= vpos.x or v.position.y ~= vpos.y)) then + pipedir = v.direction + entity.destroy(v) + end + if (not isvalid(v)) then + local varea = vector.square(vpos, vector(0.5, 0.5)) + vector.clean(f, varea) + v = entity.protect(entity.create(f, pipe, vpos, pipedir * 2), false, false) + vector.cleanplayers(f, varea) + self.pipes[i][id] = v + end + + cache.force_entity(v, "Teleporters", self.key, "pipes", i, id) +end + +function TELL:CheckEmptyPipes() + local ppr = {} + for a, b in pairs(self.pipes) do for k, v in pairs(b) do if (isvalid(v) and table_size(v.neighbours[1]) >= 1) then ppr[k] = true end end end + for a, b in pairs(self.pipes) do for k, v in pairs(b) do if (isvalid(v) and not ppr[k]) then v.clear_fluid_inside() end end end +end + +function TELL:CheckPointLogistics(i, vxpos) + local tps = self:Data() + local t = tps.pair[i] + if (not tps.logs and not tps.dualloader and not tps.triloader) then return end + local belt = warptorio.GetBelt() + local pos = vxpos or t.position + vector(0.5, 0.5) + if (t.gate and not vxpos) then + if (not isvalid(self.points[i].ent)) then return end + pos = vector(self.points[i].ent.position) + end + local f = storage.floor[t.floor].host + local offld = tps.pair[i].prototype and 1 or 0 + local lddir, chesty, belty + if (self:GetLoaderDirection() == "up") then + lddir = defines.direction.south + chesty = -1 + belty = 0 + else + lddir = defines.direction.north + chesty = 1 + belty = -1 + end + local ldl = 0 + local lvLogs = research.level("warptorio-logistics") + if (tps.logs and lvLogs > 0) then ldl = ldl + 1 end + if (tps.dualloader and research.has("warptorio-dualloader-1")) then ldl = ldl + 1 end + if (tps.triloader and research.has("warptorio-triloader")) then ldl = ldl + 1 end + local can = true + if (t.gate) then -- check if placement area is clear + local vsize = offld + ldl + (tps.dopipes and 1 or 0) + local varea = vector.square(pos, vector(vsize * 2, 3)) + -- if(f.count_entities_filtered{area=varea,collision_mask={"object-layer"}} >1)then + if (f.count_entities_filtered { area = varea, collision_mask = "object" } > 1) then + --f.create_entity { name = "flying-text", position = pos, text = "Logistics blocked - Needs more space", color = { r = 1, g = 0.5, b = 0.5 } } + game.print({ "warptorio.teleporter-blocked-error" }) + f.play_sound { path = "utility/cannot_build", position = pos } + can = false + end + end + if (can and ldl > 0) then + for id = 1, ldl, 1 do + self:MakePointLoaders(tps, i, id, pos, f, belt, lddir, chesty, belty) + end + end + if (can and tps.dopipes and lvLogs > 0) then + for id = 1, math.min(lvLogs, 3), 1 do -- pipes first, it removes the old ones + if (not tps.oneside or tps.oneside == "right") then + self:MakePointPipes(tps, i, id, pos, f, ldl + offld + 1, + 1, id) + end + if (not tps.oneside or tps.oneside == "left") then + self:MakePointPipes(tps, i, id + 3, pos, f, ldl + offld + + 1, -1, id) + end + end + end +end + +--[[ +function events.on_tick("logistics_teleporters",function(ev) for k,v in pairs(storage.Teleporters)do v:TickLogistics() end end end) + +function TELL:TickLogistics() + for k,v in pairs(self.chests[1])do if(isvalid(self.chests[2][k]))then + if(self.dir[1][k]=="input")then warptorio.BalanceLogistics(v,self.chests[2][k]) else warptorio.BalanceLogistics(self.chests[2][k],v) end + end end + for k,v in pairs(self.pipes[1])do if(isvalid(self.pipes[2][k]))then + warptorio.BalanceLogistics(v,self.pipes[2][k]) + end end +end]] diff --git a/control_main.lua b/control_main.lua index c6f1d41..14e3733 100644 --- a/control_main.lua +++ b/control_main.lua @@ -1,1068 +1,1412 @@ ---[[------------------------------------- - -Author: Pyro-Fire -https://mods.factorio.com/mod/warptorio2 - -Script: control.lua -Purpose: control stuff - - -Written using Microsoft Notepad. -IDE's are for children. - -How to notepad like a pro: -ctrl+f = find -ctrl+h = find & replace -ctrl+g = show/jump to line (turn off wordwrap n00b) - -Status bar wastes screen space, don't use it. - -Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. - - -]]--------------------------------------- - -local planets=lib.planets - ---[[ Warptorio Environment ]]-- - -warptorio=warptorio or {} -warptorio.Loaded=false - -require("control_main_helpers") - -warptorio.platform=require("control_platform_classic") -local platform=warptorio.platform - - -require("control_class_teleporter") -require("control_class_harvester") -require("control_class_rails") - -warptorio.chatcmd={} -function warptorio.chatcmd.kill(ev) - local ply=game.players[ev.player_index] local c=ply.character - if(c and c.valid)then c.die(c.force,c) end -end -commands.add_command("kill","Suicides the player",warptorio.chatcmd.kill) - - ---[[ Warptorio custom events ]]-- --- Hook in on_load with --- local eventdefs=remote.call("warptorio","get_events") --- script.on_event(eventdefs["on_warp"],func() end) - -events.register("on_warp") -- during Warpout() -events.register("on_post_warp") -- during Warpout() -events.register("warp_started") -- StartWarp() -events.register("warp_stopped") -- StopWarp() - -events.register("harvester_deploy") -- ? -events.register("harvester_recall") -- ? - -events.register("ability_used") -- ? - - - - ---[[ Warptorio Libraries ]]-- - - -warptorio.ChestBeltPairs={{"loader","wooden-chest"},{"fast-loader","iron-chest"},{"express-loader","steel-chest"}, - {"express-loader",function(dir) return (dir=="output" and warptorio.setting("loaderchest_provider") or warptorio.setting("loaderchest_requester")) end}, -} -warptorio.ChestBeltPairs[0]={"loader","wooden-chest"} -function warptorio.GetChest(dir) local lv=research.level("warptorio-logistics") local lvb=warptorio.ChestBeltPairs[lv] return (isstring(lvb[2]) and lvb[2] or lvb[2](dir)) end -function warptorio.GetBelt(dir) local lv=research.level("warptorio-logistics") local lvb=warptorio.ChestBeltPairs[lv] return (isstring(lvb[1]) and lvb[1] or lvb[1](dir)) end ---remotes.register("GetChest",warptorio.GetChest) ---remotes.register("GetBelt",warptorio.GetBelt) - - - ---[[ Warptorio Platform ]]-- - -function warptorio.GetPlatform() return warptorio.platform end -function warptorio.GetCurrentSurface() return global.floor.main.host end -function warptorio.GetMainSurface() return global.floor.main.host end -function warptorio.GetHomeSurface() return global.floor.home and global.floor.home.host or nil end -function warptorio.GetMainPlanet() return planets.GetBySurface(warptorio.GetMainSurface()) end -- planetorio -function warptorio.GetHomePlanet() return planets.GetBySurface(warptorio.GetHomeSurface()) end -- planetorio - -function warptorio.GetNamedSurfaces(tbl) local t={} for k,nm in pairs(tbl)do t[nm]=global.floor[nm].host end return t end -function warptorio.GetAllSurfaces() local t={} for nm,v in pairs(global.floor)do t[v.hostindex]=v.host end return t end -function warptorio.GetPlatformSurfaces() local t={} for nm,v in pairs(global.floor)do if(platform.floors[nm].empty==true)then t[v.hostindex]=v.host end end return t end - - -function warptorio.GetTeleporterSize(a,b,c,noproto) -- for clearing - local x=1 - if(a and research.has("warptorio-logistics-1"))then x=x+2 end - if(b and research.has("warptorio-dualloader-1"))then x=x+1 end - if(c and research.has("warptorio-triloader"))then x=x+1 end - return vector((x*2)+2,2) -end -function warptorio.GetTeleporterHazard(bMain,bFull) -- for hazard tiles - local x=0 - bFull=(bFull==nil and true or bFull) -- has the tech, or -1 - local lgHas=research.has("warptorio-logistics-1") - local dlHas=research.has("warptorio-dualloader-1") - local tlHas=research.has("warptorio-triloader") - local lgCan=research.can("warptorio-logistics-1") - local dlCan=research.can("warptorio-dualloader-1") - local tlCan=research.can("warptorio-triloader") - - if(lgCan or lgHas)then x=x+2 end - - if(bMain)then - if(tlHas and dlHas)then x=x+2 - elseif(tlHas or dlHas)then x=x+1 if(bFull and ( (not tlHas and tlCan) or (not dlHas and dlCan) ) )then x=x+1 end - elseif(bFull and (tlCan or dlCan))then x=x+1 - end - else - if(tlCan)then x=x+1 end - end - - - return vector((x*2)+2,2) -end - -warptorio.EmptyGenSettings={default_enable_all_autoplace_controls=false,width=32*12,height=32*12, - autoplace_settings={entity={treat_missing_as_default=false},tile={treat_missing_as_default=false},decorative={treat_missing_as_default=false}, }, starting_area="none",} - -function warptorio.MakePlatformFloor(vt) - local f=game.create_surface(vt.name,(vt.empty and warptorio.EmptyGenSettings or nil)) - if(vt.empty)then - f.solar_power_multiplier=settings.global.warptorio_solar_multiplier.value - f.daytime=0 - f.always_day=true - f.request_to_generate_chunks({0,0},16) - f.force_generate_chunk_requests() - f.destroy_decoratives({}) - for k,v in pairs(f.find_entities())do entity.destroy(v) end - local area=vector.area(vector(-32*8,-32*8),vector(32*8*2,32*8*2)) - vector.LayTiles("out-of-map",f,area) - end - local floor=cache.raise_surface(f) - if(vt.init)then lib.call(vt.init,floor) end - global.floor[vt.key]=floor - return floor -end - -function warptorio.GetPlatformFloor(vt) if(isstring(vt))then vt=warptorio.platform.floors[vt] end - local floor - if(vt.key=="main")then -- Special; nauvis / primary planet - floor=global.floor.main if(not floor)then floor={key=vt.key,host=game.surfaces.nauvis,hostindex=1} global.floor.main=floor if(vt.init)then lib.call(vt.init,floor) end end - elseif(vt.key=="home")then -- Special; homeworld - floor=global.floor.home if(not floor)then floor={key=vt.key,host=game.surfaces.nauvis,hostindex=1} global.floor.home=floor end - else - floor=global.floor[vt.key] if(not floor)then floor=warptorio.MakePlatformFloor(vt) end - floor.key=vt.key - end - return floor -end - -function warptorio.ConstructFloor(fn,bhzd) warptorio.ConstructPlatform(platform.floors[fn],bhzd) end -function warptorio.ConstructFloorHazard(fn) warptorio.ConstructHazard(platform.floors[fn]) end - -function warptorio.ConstructPlatformVoid(surf) - local vt=warptorio.platform.floors["main"] if(vt.tile)then lib.call(vt.tile,surf,true) end -end -function warptorio.ConstructPlatform(vt,bhzd) - if(isstring(vt))then vt=warptorio.platform.floors[vt] end - local floor=warptorio.GetPlatformFloor(vt) if(floor)then - if(vt.tile)then lib.call(vt.tile,floor.host) end - if(bhzd and vt.hazard)then lib.call(vt.hazard,floor.host) end -end end - -function warptorio.ConstructPlatforms(bhzd) - local platform=warptorio.GetPlatform() - for nm,vt in pairs(platform.floors)do warptorio.ConstructPlatform(vt,bhzd) end -end - -function warptorio.ConstructHazard(vt) - if(isstring(vt))then vt=warptorio.platform.floors[vt] end - local floor=warptorio.GetPlatformFloor(vt) - if(floor and vt.hazard)then lib.call(vt.hazard,floor.host) end -end - -function warptorio.ConstructHazards() - local platform=warptorio.GetPlatform() - for nm,vt in pairs(platform.floors)do warptorio.ConstructHazard(vt) end -end - -function warptorio.CheckFloorRadar(floor) if(research.has("warptorio-charting") and not isvalid(floor.radar))then - floor.radar=entity.protect(entity.create(floor.host,"warptorio-invisradar",vector(-1,-1)),false,false) -end end - - -function warptorio.CheckPlatformSpecials(self) - local platform=warptorio.platform - local vfloor=platform.floors[self.key] - if(not vfloor)then - game.print("no vfloor error: " .. serpent.line(self)) - end - local sp=vfloor.special if(not sp)then return end - if(not sp.upgrade)then if(not research.has(sp.tech) or isvalid(self.SpecialEnt))then return end elseif(research.level(sp.tech)<1)then return end - local protoname=sp.prototype - local inv={} - if(sp.upgrade)then protoname=protoname.."-"..research.level(sp.tech) - if(isvalid(self.SpecialEnt) and self.SpecialEnt.name==protoname)then return elseif(isvalid(self.SpecialEnt))then inv=warptorio.DestroyPlatformSpecial(self) end - end - - local f=self.host - local efply={} - local area=vector.square(vector(-0.5,-0.5),sp.size) - local eft=f.find_entities_filtered{area=area} - local rdr=false if(isvalid(self.radar))then rdr=true entity.destroy(self.radar) end - for k,v in pairs(eft)do if(isvalid(v))then if(v.type=="character")then table.insert(efply,v) elseif(v~=self.radar)then entity.destroy(v) end end end - - local e=entity.protect(entity.create(f,protoname,vector(-0.5,-0.5)),false,false) - self.SpecialEnt=e - if(inv)then for k,v in pairs(inv)do e.get_module_inventory().insert{name=k,count=v} end end -- beacon modules. Close enough. - warptorio.CheckFloorRadar(self) - vector.cleanplayers(f,area) - players.playsound("warp_in",f) -end - -function warptorio.DestroyPlatformSpecial(self) local inv - if(isvalid(self.SpecialEnt))then local x=self.SpecialEnt.get_module_inventory() if(x)then inv=x.get_contents() end entity.destroy(self.SpecialEnt) end - self.SpecialEnt=nil return inv - -end - -function warptorio.InitPlatform() - global.floor={} - - for nm,vt in pairs(warptorio.platform.floors)do - local floor=warptorio.GetPlatformFloor(vt) - if(floor)then - warptorio.ConstructPlatform(vt,true) - end - end -end - - - - - ---[[ Bootstrap Initialization and Migrations ]]-- - -events.on_init(function() - events.raise_migrate() - lib.planets.lua() - warptorio.ValidateWarpBlacklist() - --warptorio.HookNewGamePlus() -end) - - - - -function warptorio.ApplyMapSettings() - local gmp=game.map_settings - gmp.pollution.diffusion_ratio = 0.105 - gmp.pollution.pollution_factor = 0.0000001 - - gmp.pollution.min_to_diffuse=15 -- default 15 - gmp.pollution.ageing=1.0 -- 1.0 - gmp.pollution.expected_max_per_chunk=250 - gmp.pollution.min_to_show_per_chunk=50 - gmp.pollution.pollution_restored_per_tree_damage=9 - gmp.pollution.enemy_attack_pollution_consumption_modifier=1.0 - - gmp.enemy_evolution.destroy_factor=0.0002 -- default 0.002 - - gmp.unit_group.min_group_gathering_time = 600 - gmp.unit_group.max_group_gathering_time = 2 * 600 - gmp.unit_group.max_unit_group_size = 200 - gmp.unit_group.max_wait_time_for_late_members = 2 * 360 - gmp.unit_group.settler_group_min_size = 1 - gmp.unit_group.settler_group_max_size = 1 - - --gmp.enemy_expansion.max_expansion_cooldown = (gmp.enemy_expansion.min_expansion_cooldown*1.25) - - -end - -events.on_config(function(ev) if(warptorio.Loaded)then return end - lib.planets.lua() - cache.validate("combinators") - cache.validate("heat") - cache.validate("power") - cache.validate("loaderinput") - cache.validate("loaderoutput") - cache.validate("ldinputf") - cache.validate("ldoutputf") - - global.warpzone=global.warpzone or 0 - global.time_spent_start_tick=global.time_spent_start_tick or game.tick - global.time_passed=global.time_passed or 0 - - global.warp_charge_time=global.warp_charge_time or 10 - global.warp_charge_start_tick=global.warp_charge_start_tick or 0 - global.warp_charging=global.warp_charging or 0 - global.warp_timeleft=global.warp_timeleft or 60*10 - global.warp_auto_time = global.warp_auto_time or 60*settings.global["warptorio_autowarp_time"].value - global.warp_auto_end = global.warp_auto_end or 60*60*settings.global["warptorio_autowarp_time"].value - global.warp_last=global.warp_last or game.tick - global.abilities=global.abilities or {} - global.ability_drain=global.ability_drain or settings.global["warptorio_ability_drain"].value - - global.pollution_amount = global.pollution_amount or 1.1 - global.pollution_expansion = global.pollution_expansion or 1.1 - global.ability_uses=global.ability_uses or 0 - global.ability_next=global.ability_next or 0 - global.radar_uses=global.radar_uses or 0 - - warptorio.ApplyMapSettings() - - global.votewarp=global.votewarp or {} if(type(global.votewarp)~="table")then global.votewarp={} end - warptorio.CheckVotewarps() - - -- todo: global.warp_blacklist={} - warptorio.ValidateWarpBlacklist() - - --[[ more todo: - for k,v in pairs(gwarptorio.Harvesters)do v.position=warptorio.platform.harvester[k] end - for k,v in pairs(gwarptorio.Teleporters)do v.position=warptorio.Teleporters[k].position end - ]] - - global.Teleporters=global.Teleporters or {} - global.Research=global.Research or {} -- todo remove this - global.Turrets=global.Turrets or {} - global.Rails=global.Rails or {} - global.Harvesters=global.Harvesters or {} - - - if(not global.floor)then warptorio.InitPlatform() end - - - for k,v in pairs(global.Rails)do - v:MakeRails() - end - for k,v in pairs(global.Teleporters)do - v:CheckTeleporterPairs(true) - end - for k,v in pairs(global.Harvesters)do - local gdata=warptorio.platform.harvesters[v.key] - v.rank=warptorio.GetPlatformTechLevel(gdata.tech) - v:CheckTeleporterPairs(true) - v:Upgrade() - end - - for k,v in pairs(warptorio.settings)do v() end - - -- todo: warptorio.ApplyMapSettings() - for k,t in pairs(global.Harvesters)do - table.merge(t,table.deepcopy(warptorio.platform.harvesters[t.key])) - table.merge(t,table.deepcopy(warptorio.platform.HarvesterPointData)) - end - - warptorio.Loaded=true -end) - -events.on_load(function() - warptorio.HookNewGamePlus() - if(global.Teleporters)then for k,v in pairs(global.Teleporters)do setmetatable(v,warptorio.TeleporterMeta) end end - if(global.Harvesters)then for k,v in pairs(global.Harvesters)do setmetatable(v,warptorio.HarvesterMeta) end end - if(global.Rails)then for k,v in pairs(global.Rails)do setmetatable(v,warptorio.RailMeta) end end - --lib.planets.lua() -end) - - ---[[ Players Manager ]]-- - -function warptorio.CheckVotewarps() for k,v in pairs(global.votewarp)do if(isvalid(v) or not v.connected)then global.votewarp[k]=nil end end cache.updatemenu("hud","warpbtn") end - - -warptorio.teleDir={[0]={0,-1},[1]={1,-1},[2]={1,0},[3]={1,1},[4]={0,1},[5]={-1,1},[6]={-1,0},[7]={-1,-1}} -function warptorio.TeleportLogic(ply,e,tent) - local w=ply.walking_state - local ox=tent.position - local x=e.position - local mp=2 if(not ply.character)then mp=3 end - --game.print(serpent.line(ply.vehicle.name)) - if(ply.driving)then - local veh=ply.vehicle - if(veh.type=="spider-vehicle")then - local cp=ply.position local xd,yd=(x.x-cp.x),(x.y-cp.y) - local vpos=vector(ox.x+xd*3,ox.y+yd*3) - entity.safeteleport(ply,tent.surface,vpos) - local cn=veh.clone{position=ply.position,surface=ply.surface,force=ply.force} - veh.destroy() - ply.driving=cn - else - local cp=ply.position local xd,yd=(x.x-cp.x),(x.y-cp.y) entity.safeteleport(veh,tent.surface,vector(ox.x+xd*3,ox.y+yd*3)) - end - elseif(not w.walking)then - local cp=ply.position local xd,yd=(x.x-cp.x),(x.y-cp.y) entity.safeteleport(ply,tent.surface,vector(ox.x+xd*mp,ox.y+yd*mp)) - else - local td=warptorio.teleDir[w.direction] local tpe=ply entity.safeteleport(tpe,tent.surface,vector(ox.x+td[1]*mp,ox.y+td[2]*mp)) - end - players.playsound("teleport",e.surface,e.position) players.playsound("teleport",tent.surface,tent.position) -end - - -cache.player({ - raise=function(cp) local ply=cp.host - entity.safeteleport(ply,warptorio.GetMainSurface(),vector(0,-5)) - local hud=cache.force_menu("hud",ply) - end, - on_position=function(ply) - local cp=cache.force_player(ply) - if((cp.tprecent or 0)>game.tick)then return end - local f=ply.surface - local z=vector.square(ply.position,vector(0.8,0.8)) - if(ply.driving)then - local bbox=ply.vehicle.bounding_box - --game.print(serpent.line(bbox)) - bbox.left_top.x=bbox.left_top.x-0.8 - bbox.left_top.y=bbox.left_top.y-0.8 - bbox.right_bottom.x=bbox.right_bottom.x+0.8 - bbox.right_bottom.y=bbox.right_bottom.y+0.8 - z=bbox - end - - local ents=f.find_entities_filtered{area=z,type="accumulator"} --todo - for k,v in pairs(ents)do - local tpg=cache.get_entity(v) - if(tpg and isvalid(tpg.teleport_dest))then - cp.tprecent=game.tick+10 - local tgate=tpg.teleport_dest - warptorio.TeleportLogic(ply,v,tgate) - end - end - end, - on_create=function(ply) - local cp=cache.raise_player(ply) - end, - on_join=function(ply) - local menu=cache.force_menu("hud",ply) - entity.safeteleport(ply,warptorio.GetMainSurface(),{0,-5}) - end, - on_respawn=function(ply) - local cf=warptorio.GetMainSurface() local gp=ply - if(gp.surface~=cf)then local pos=cf.find_non_colliding_position("character",{0,-5},0,1,1) gp.teleport(pos,cf) end - end, - on_left=function(ply) - if(global.votewarp[ply.index])then - global.votewarp[ply.index]=nil - cache.updatemenu("hud","warpbtn") - end - end, - on_pre_removed=function(ply) - local cp=cache.get_player(ply) if(cp)then - cache.destroy_player(ply) - end - end, - on_capsule=function(ply,ev) - if(ev.item.name=="warptorio-townportal")then - local p=game.players[ev.player_index] - if(p and p.valid)then - players.playsound("teleport",p.surface,p.position) - entity.safeteleport(p,warptorio.GetMainSurface(),vector(0,-5)) - players.playsound("teleport",p.surface,p.position) - end - elseif(ev.item.name=="warptorio-homeportal" and warptorio.GetHomeSurface())then - local p=game.players[ev.player_index] - if(p and p.valid)then - players.playsound("teleport",p.surface,p.position) - entity.safeteleport(p,warptorio.GetHomeSurface(),vector(0,-5)) - players.playsound("teleport",p.surface,p.position) - end - end - - end, -}) - - - - - ---[[ Warptorio Cache Manager ]]-- - - - -- Pumps and resources cannot be cloned in warptorio -cache.type("offshore-pump",{ clone=function(e) e.destroy{raise_destroy=true} end, }) -cache.type("resource",{ clone=function(e) e.destroy{raise_destroy=true} end, }) - --- Simple globally balanced entities -cache.ent("warptorio-heatpipe",{ create=function(e) cache.insert("heat",e) end, destroy=function(e) cache.remove("heat",e) end }) -cache.ent("warptorio-reactor",{ create=function(e) cache.insert("heat",e) end, destroy=function(e) cache.remove("heat",e) end }) -cache.ent("warptorio-accumulator",{ create=function(e) cache.insert("power",e) end, destroy=function(e) cache.remove("power",e) end }) - -events.on_tick(1,0,"heattick",function(tick) entity.AutoBalanceHeat(cache.get("heat")) end) -events.on_tick(1,0,"powertick",function(tick) local t=cache.get("power") - local g,c=0,0 - for k,v in pairs(t)do if(isvalid(v))then g=g+v.energy c=c+v.electric_buffer_size end end - - local egdrain=global.ability_drain - local abc=0 - if(global.abilities.stabilizing)then - abc=abc+1 - end - if(global.abilities.accelerating)then - abc=abc+1 - end - if(global.abilities.scanning)then - abc=abc+1 - end - - if(abc>0)then - local gcost=c*egdrain*abc - if(g>=gcost)then - g=math.max(g-gcost,0) - global.ability_drain=math.min(egdrain+(0.00000002*abc),0.25) - else - global.abilities.stabilizing=false global.abilities.scanning=false global.abilities.accelerating=false - end - end - global.energycount=g global.energymax=c - for k,v in pairs(t)do if(v.valid)then v.energy=g*(v.electric_buffer_size/c) end end -end) - --- Warptorio Combinators -cache.ent("warptorio-combinator",{ - create=function(e,ev) cache.insert("combinators",e) end, - destroy=function(e,ev) cache.remove("combinators",e) end, - update=function(e,ev) local cbh=e.get_or_create_control_behavior() for k,v in pairs(ev.signals)do cbh.set_signal(k,v) end end, -}) -function warptorio.RefreshWarpCombinators() local sigs=warptorio.GetCombinatorSignals() cache.entcall("combinators","update",{signals=sigs}) end -function warptorio.GetCombinatorSignals() local tbl={} for k,v in pairs(warptorio.Signals)do tbl[k]={signal=v.signal,count=v.get()} end return tbl end -warptorio.Signals={} -- 18 max default -warptorio.Signals[1]={ signal={type="virtual",name="signal-W"},get=function() return (global.warp_charging>=1 and (global.warp_time_left or 10)/60 or (global.warp_charge_time or 10)) end} -warptorio.Signals[2]={ signal={type="virtual",name="signal-X"},get=function() return global.warp_charging or 0 end} -warptorio.Signals[3]={ signal={type="virtual",name="signal-A"},get=function() return global.warp_auto_end/60 end} -warptorio.Signals[4]={ signal={type="virtual",name="signal-L"},get=function() local hv=global.Harvesters.west return ((hv and hv.deployed) and 1 or 0) end} -warptorio.Signals[5]={ signal={type="virtual",name="signal-R"},get=function() local hv=global.Harvesters.east return ((hv and hv.deployed) and 1 or 0) end} -warptorio.Signals[6]={ signal={type="virtual",name="signal-P"},get=function() return global.time_passed end} - ---[[ Warptorio Gui ]]-- - - ---cache.updatemenu("hud","raise") -- to recreate the menu - -function warptorio.RaiseHUD(v) local m=cache.get_menu("hud",v) if(not m)then cache.raise_menu("hud",v) else cache.call_menu("raise",m) end end -function warptorio.ResetHUD(p) if(not p)then for k,v in pairs(game.players)do warptorio.RaiseHUD(v) end else warptorio.RaiseHUD(p) end end -function warptorio.PlayerCanStartWarp(ply) return true end - -function warptorio.ToolRecallHarvester(k,ply) if(not research.has("warptorio-harvester-"..k.."-1"))then return end - local cn=("warptorio-harvestpad-"..k.."-"..research.level("warptorio-harvester-"..k)) - if(not ply or (ply and not ply.get_main_inventory().get_contents()[cn]))then ply.get_main_inventory().insert{name=cn,count=1} players.playsound("warp_in",ply.surface,ply.position) end - local hv=global.Harvesters[k] if(hv and hv.deployed and isvalid(hv.b))then players.playsound("warp_in",hv.b.surface,hv.b.position) hv:Recall() hv:DestroyB() end -end -function warptorio.ToolRecallGate(ply) if(not research.has("warptorio-teleporter-portal"))then return end - local t=global.Teleporters.offworld if(t)then - if(t.b and t.b.valid)then players.playsound("warp_in",t.b.surface,t.b.position) t:DestroyLogsB() t:DestroyB() end - local inv=ply.get_main_inventory() - if(not inv.get_contents()["warptorio-teleporter-gate-0"])then inv.insert{name="warptorio-teleporter-gate-0",count=1} players.playsound("warp_in",ply.surface,ply.position) end - end -end - -cache.vgui("warptorio_toolbutton",{click=function(elm,ev) local menu=cache.get_menu("hud",elm.player_index) local b=menu.toolbar b.visible=not b.visible end}) -cache.vgui("warptorio_tool_hv_west",{click=function(elm,ev) warptorio.ToolRecallHarvester("west",game.players[elm.player_index]) end}) -cache.vgui("warptorio_tool_hv_east",{click=function(elm,ev) warptorio.ToolRecallHarvester("east",game.players[elm.player_index]) end}) -cache.vgui("warptorio_tool_planet_gate",{click=function(elm,ev) warptorio.ToolRecallGate(game.players[elm.player_index]) end}) - - -cache.vgui("warptorio_homeworld",{ - click=function(elm,ev) local menu=cache.get_menu("hud",elm.player_index) - if(menu.hometmr=1)then menu.charge_time.caption={"warptorio.warp-in",util.formattime(val or (global.warp_time_left or 0))} - elseif(menu.charge_time)then menu.charge_time.caption={"warptorio.charge_time",util.formattime((global.warp_charge_time or 0)*60)} - end - - menu.time_passed.caption={"warptorio.time_passed",util.formattime(global.time_passed or 0)} - if(warptorio.IsAutowarpEnabled())then menu.autowarp.caption={"warptorio.autowarp-in",util.formattime(global.warp_auto_end)} else menu.autowarp.caption="" end - - menu.hometmr=menu.hometmr or 0 - if(menu.homeworld)then - if(menu.hometmr>game.tick)then menu.homeworld.caption={"warptorio.confirm_homeworld",util.formattime(menu.hometmr-game.tick)} - else menu.homeworld.caption={"warptorio.button_homeworld"} - end - end - - if(menu.energybar)then - local cureng=global.energycount or 0 - local maxeng=math.max(global.energymax or 1,1) - local energydif=cureng-(menu.last_energy or 0) - menu.last_energy=cureng - - local egdrain=global.ability_drain*100*60 - local abc=0 - local r=menu.stabilizer - if(r)then if(global.abilities.stabilizing)then abc=abc+1 r.caption={"warptorio-stabilize-on","-"..math.roundx(egdrain,2).."%/sec"} else r.caption={"warptorio-stabilize"} end end - local r=menu.accelerator - if(r)then if(global.abilities.accelerating)then abc=abc+1 r.caption={"warptorio-accel-on","-"..math.roundx(egdrain,2).."%/sec"} else r.caption={"warptorio-accel"} end end - local r=menu.radar - if(r)then if(global.abilities.scanning)then abc=abc+1 r.caption={"warptorio-radar-on","-"..math.roundx(egdrain,2).."%/sec"} else r.caption={"warptorio-radar"} end end - - - menu.energybar_energy.caption=" "..string.energy_to_string(cureng) .. " " - menu.energybar_energymax.caption=" "..string.energy_to_string(maxeng) .. " " - - menu.energybar_energybal.caption=" ("..(energydif>=1 and "+" or (energydif>0 and "+-" or ""))..string.energy_to_string(energydif) .. "/sec) " - menu.energybar_energybal.style.font_color=(energydif>0 and {r=0,g=1,b=0} or (energydif<0 and {r=1,g=0,b=0} or {r=0.75,g=0.75,b=0.75})) - - menu.energybar.value=cureng/maxeng - - menu.energybar_energypct.caption=" "..math.roundx((cureng/maxeng)*100,2) .. "% " - - if(abc>0)then menu.energybar_energypctx.caption="-"..math.roundx(egdrain*abc,2).."%/sec" else menu.energybar_energypctx.caption="" end - - end - -end - - -function HUD.raise(menu,ev) local ply=menu.host - menu.frame=vgui.create(ply.gui.left,{name="warptorio_frame",type="flow",direction="vertical"}) - menu.frame.style.left_padding=4 - menu.row1=vgui.create(menu.frame,{name="warptorio_row1",type="flow",direction="horizontal"}) - menu.row2=vgui.create(menu.frame,{name="warptorio_row2",type="flow",direction="horizontal"}) - menu.row4=vgui.create(menu.frame,{name="warptorio_row4",type="flow",direction="horizontal"}) - menu.row3=vgui.create(menu.frame,{name="warptorio_row3",type="flow",direction="horizontal"}) - menu.row1.clear() - menu.row2.clear() - menu.row3.clear() - menu.row4.clear() - - menu.warpbtn=vgui.create(menu.row1,{name="warptorio_warpbutton",type="button",caption={"warptorio.button-warp","-"}}) - if(research.has("warptorio-toolbar"))then menu.toolbtn=vgui.create(menu.row1,{name="warptorio_toolbutton",type="button",caption={"warptorio.toolbutton","-"}}) end - if(research.level("warptorio-reactor")>=8)then - menu.warptgt=vgui.create(menu.row1,{name="warptorio_warptarget",type="drop-down"}) - HUD.rebuild_warptargets(menu) - HUD.warptarget(menu,{tgt=(sx==nil and "(Random)" or (sx=="home" and "(Homeworld)" or (sx=="(nauvis)" and "nauvis" or sx)))}) - end - - menu.time_passed=vgui.create(menu.row1,{name="warptorio_time_passed",type="label"}) - menu.charge_time=vgui.create(menu.row1,{name="warptorio_charge_time",type="label"}) - menu.warpzone=vgui.create(menu.row1,{name="warptorio_warpzone",type="label",caption="Warpzone: " .. global.warpzone or 0}) - menu.autowarp=vgui.create(menu.row1,{name="warptorio_autowarp",type="label"}) - - if(research.has("warptorio-homeworld"))then menu.homeworld=vgui.create(menu.row1,{name="warptorio_homeworld",type="button",caption={"warptorio.button_homeworld"}}) end - - - local hasabil=false - if(research.has("warptorio-stabilizer"))then hasabil=true menu.stabilizer=vgui.create(menu.row2,{name="warptorio_stabilizer",type="button",caption={"warptorio-stabilize","-"}}) end - if(research.has("warptorio-accelerator"))then hasabil=true menu.accelerator=vgui.create(menu.row2,{name="warptorio_accelerator",type="button",caption={"warptorio-accel","-"}}) end - if(research.has("warptorio-charting"))then hasabil=true menu.radar=vgui.create(menu.row2,{name="warptorio_radar",type="button",caption={"warptorio-radar","-"}}) end - if(hasabil)then - menu.last_energy=menu.last_energy or 100 - local energydif=1000-menu.last_energy - menu.energybar_label=vgui.create(menu.row4,{name="warptorio_energybar_label",type="label",caption={"warptorio.energybar","-"}}) - menu.energybar_energy=vgui.create(menu.row4,{name="warptorio_energybar_energy",type="label",caption=" 100kw "}) - menu.energybar_energy.style.font_color={r=0,g=1,b=0} - - menu.energybar_energydiv=vgui.create(menu.row4,{name="warptorio_energybar_energydiv",type="label",caption=" / "}) - - menu.energybar_energymax=vgui.create(menu.row4,{name="warptorio_energybar_energymax",type="label",caption=" 0kw "}) - menu.energybar_energymax.style.font_color={r=0.25,g=1,b=1} - - - menu.energybar_energybal=vgui.create(menu.row4,{name="warptorio_energybar_energybal",type="label",caption=" (+100.32MW/sec) "}) - menu.energybar_energybal.style.font_color=(energydif>0 and {r=0,g=1,b=0} or (energydif==0 and {r=1,g=1,b=0} or {r=1,g=0,b=0})) - - - menu.energybar_energydivb=vgui.create(menu.row4,{name="warptorio_energybar_energydivb",type="label",caption=" | "}) - - - menu.energybar=vgui.create(menu.row4,{name="warptorio_time_passed",type="progressbar",value=0.3}) - menu.energybar.style.natural_width=250 - menu.energybar.style.top_padding=7 - menu.energybar.style.bottom_padding=7 - - menu.energybar_energypcta=vgui.create(menu.row4,{name="warptorio_energybar_energypcta",type="label",caption=" | "}) - menu.energybar_energypct=vgui.create(menu.row4,{name="warptorio_energybar_energypct",type="label",caption="25%"}) - menu.energybar_energypct.style.font_color={r=1,g=1,b=1} - menu.energybar_energypctx=vgui.create(menu.row4,{name="warptorio_energybar_energypctx",type="label",caption="-3%/sec"}) - menu.energybar_energypctx.style.font_color={r=1,g=0,b=0} - - - - end - - if(research.has("warptorio-toolbar"))then - menu.toolbar=vgui.create(menu.row3,{name="warptorio_toolframe",type="flow",direction="horizontal",visible=false}) - menu.toolbar.clear() - menu.tool_harvester_west=vgui.create(menu.toolbar,{name="warptorio_tool_hv_west",type="sprite-button",sprite="entity/warptorio-harvestportal-1",tooltip={"warptorio.tool_hv_west","-"}}) - menu.tool_planet_gate=vgui.create(menu.toolbar,{name="warptorio_tool_planet_gate",type="sprite-button",sprite="item/warptorio-teleporter-gate-0",tooltip={"warptorio.tool_planet_gate","-"}}) - menu.tool_harvester_east=vgui.create(menu.toolbar,{name="warptorio_tool_hv_east",type="sprite-button",sprite="entity/warptorio-harvestportal-1",tooltip={"warptorio.tool_hv_east","-"}}) - end - - - HUD.clocktick(menu) - HUD.rebuild_warptargets(menu) - local sx=global.planet_target - -end - -function HUD.rebuild_warptargets(menu,ev) - if(menu.warptgt)then - local tgl={"(Random)"} - if(research.has("warptorio-homeworld"))then table.insert(tgl,"(Homeworld)") table.insert(tgl,"(Nauvis)") end - if(research.has("warptorio-charting"))then for k,v in pairs(lib.planets.GetTemplates())do table.insert(tgl,v.key) end end - menu.warptgt.items=tgl - HUD.warptarget(menu,{tgt=global.planet_target}) - end -end -function HUD.warptarget(menu,ev) local ply=menu.host if(not menu.warptgt or ply.index==ev.ply)then return end - local elm,items=menu.warptgt if(elm)then items=elm.items end if(not items)then return end - for idx,kv in pairs(items)do if(type(kv)=="string" and kv:lower()==ev.tgt)then elm.selected_index=idx end end -end - -function HUD.warpbtn(menu) - local r=menu.warpbtn - local ply=menu.host - if(global.warp_charging>=1)then r.caption={"warptorio.warping","-"} r.enabled=false - else local cx=table.Count(global.votewarp) local c=table.Count(game.connected_players) -- table.Count(game.non_afk_players) - if(c>1)then - local vcn=math.ceil(c*warptorio.setting("votewarp_multi")) - if(global.votewarp[ply.index] and cx0)then r.caption={"warptorio.button-votewarp-count",cx,vcn} - else r.caption={"warptorio.button-votewarp","-"} - end - else r.enabled=true r.caption={"warptorio.button-warp","-"} menu.warpzone.caption={"warptorio.warpzone_label",global.warpzone or 0} - end - end -end - -cache.menu("hud",HUD) - - - -cache.vgui("warptorio_warptarget",{ -selection_changed=function(elm,ev) local ply=game.players[elm.player_index] - local s=elm.items[elm.selected_index] if(not s)then return end local sx=s:lower() - local vt=(sx=="(random)" and nil or (sx=="(homeworld)" and "home" or (sx=="(nauvis)" and "nauvis" or sx))) - if(vt~=global.planet_target)then global.planet_target=vt game.print({"warptorio.player_set_warp_target",ply.name,s}) cache.updatemenu("hud","warptarget",{ply=elm.player_index,tgt=sx}) end -end, -}) - -function warptorio.StartWarp() - if(global.warp_charging<1)then - events.vraise("warp_started") - global.warp_charge_start_tick=game.tick - global.warp_charging=1 - players.playsound("reactor-stabilized") - cache.updatemenu("hud","warpbtn") - end -end -function warptorio.StopWarp() - if(global.warp_charging>0)then - events.vraise("warp_stopped") - global.warp_charging=0 - global.warp_charge_time=global.warp_time_left/60 - global.warp_charge_start_tick=0 - end -end -function warptorio.IsWarping() return global.warp_charging>0 end -cache.vgui("warptorio_warpbutton",{ -click=function(elm,ev) local ply=game.players[elm.player_index] local menu=cache.get_menu("hud",elm.player_index) - if(global.warp_charging<1)then local c=table.Count(game.connected_players) -- table.Count(game.non_afk_players) - if(c>1 and warptorio.setting("votewarp_multi")>0)then --votewarp - local vcn=math.ceil(c*warptorio.setting("votewarp_multi")) - global.votewarp[ply.index]=ply - local cx=table.Count(global.votewarp) - if(vcn<=1 or cx>=vcn)then - warptorio.StartWarp() - game.print(ply.name .. " started the warpout procedure.") - else - players.playsound("teleport") - game.print({"warptorio.player_want_vote_warp",ply.name,cx,vcn}) - cache.updatemenu("hud","warpbtn") - end - elseif(warptorio.PlayerCanStartWarp(ply))then - global.warp_charge_start_tick = game.tick - global.warp_charging = 1 - players.playsound("reactor-stabilized") - cache.updatemenu("hud","warpbtn") - else - ply.print("You must be on the same planet as the platform to warp") - end - end -end, -}) - -cache.vgui("warptorio_stabilizer",{ -click=function(elm,ev) local ply=game.players[elm.player_index] local menu=cache.get_menu("hud",elm.player_index) - global.abilities.stabilizing= not global.abilities.stabilizing -end, -}) -cache.vgui("warptorio_accelerator",{ -click=function(elm,ev) local ply=game.players[elm.player_index] local menu=cache.get_menu("hud",elm.player_index) - global.abilities.accelerating= not global.abilities.accelerating -end, -}) -cache.vgui("warptorio_radar",{ -click=function(elm,ev) local ply=game.players[elm.player_index] local menu=cache.get_menu("hud",elm.player_index) - global.abilities.scanning= not global.abilities.scanning -end, -}) - - - - ---[[ Warping stuff ]]-- - -function warptorio.ValidateWarpBlacklist() -end - -local staticBlacklist={"highlight-box","big_brother-blueprint-radar","osp_repair_radius"} -function warptorio.GetWarpBlacklist() - return staticBlacklist -end - --- OnEntCloned -events.on_event(defines.events.on_entity_cloned,function(ev) - if(warptorio.IsCloning)then table.insert(warptorio.Cloned_Entities,{source=ev.source,destination=ev.destination}) end - if(ev.source.type=="spider-vehicle")then - for k,v in pairs(game.players)do local inv=v.get_main_inventory() if(inv)then - for i=1,#inv,1 do local e=inv[i] if(e and e.valid_for_read and e.connected_entity==ev.source)then e.connected_entity=ev.destination end end - local e=v.cursor_stack if(e and e.valid_for_read and e.connected_entity==ev.source)then e.connected_entity=ev.destination end - if(v.driving and v.vehicle==ev.source)then - entity.safeteleport(v,ev.destination.surface,ev.destination.position) - v.driving=ev.destination - end - end end - end -end) - -function warptorio.CountPlatformEntities() return 5 end -- todo - -function warptorio.Warpout(key) - warptorio.IsWarping=true - for k,v in pairs(global.Harvesters)do if(v.deployed)then v:Recall(true) end end - - local cp=warptorio.GetMainPlanet() - local cf=warptorio.GetMainSurface() - warptorio.WarpPreBuildPlanet(key) - local f,w,frc=warptorio.WarpBuildPlanet(key) - warptorio.WarpPostBuildPlanet(w) - - global.floor.main.host=f - global.floor.main.hostindex=f.index - - warptorio.ConstructPlatform("main",true) - - events.vraise("on_warp",{newsurface=f,newplanet=w,oldsurface=cf,oldplanet=cp}) - if(cp and cp.on_warp)then lib.call(cp.on_warp,f,w,cf,cp) end - - warptorio.Warp(cf,f) - warptorio.WarpPost(cf,f) - - -- reset pollution & biters - game.forces["enemy"].evolution_factor=0 - global.pollution_amount=1.1 - global.pollution_expansion=1.1 - - -- warp sound - players.playsound("warp_in") - - - warptorio.WarpFinished() - events.vraise("on_post_warp",{newsurface=f,newplanet=w}) - if(w.postwarpout)then lib.call(w.postwarpout,{newsurface=f,newplanet=w}) end - warptorio.IsWarping=false -end - - -function warptorio.WarpPreBuildPlanet(key) - global.warp_charge=0 - global.warp_charging=0 - global.votewarp={} - global.warp_last=game.tick - - global.warpzone=global.warpzone+1 - - -- Warp chargetime cooldown math - local cot=warptorio.CountPlatformEntities() - - local sgZone=warptorio.setting("warpcharge_zone") - local sgZoneGain=warptorio.setting("warpcharge_zonegain") - local sgMax=warptorio.setting("warpcharge_max") - local sgFactor=warptorio.setting("warp_charge_factor") - local sgMul=warptorio.setting("warpcharge_multi") - - global.warp_charge_time=math.min(10+ (cot/sgFactor) + (global.warpzone*sgMul) + (sgZoneGain*(math.min(global.warpzone,sgZone)/sgZone)*60), 60*sgMax) - global.warp_time_left=60*global.warp_charge_time - - -- Autowarp timer math - local rta=research.level("warptorio-reactor") - global.warp_auto_time=60*warptorio.setting("autowarp_time")+60*10*rta - global.warp_auto_end=game.tick+ global.warp_auto_time*60 - - -- Abilities - --global.ability_uses=0 - --global.radar_uses=0 - --global.ability_next=game.tick+60*60*warptorio.setting("ability_warp") - - global.ability_drain=warptorio.setting("ability_drain") or 0.00001 - global.abilities={} - - -- Update guis - --if(research.has("warptorio-accelerator") or research.has("warptorio-charting") or research.has("warptorio-stabilizer"))then end --gui.uses() gui.cooldown() - --if(warptorio.IsAutowarpEnabled())then gui.autowarp() end - --gui.warpzone() - cache.updatemenu("hud","warpbtn") - - - -- packup old teleporter gate - --local tp=global.Teleporters.offworld if(tp and tp:ValidB())then tp:DestroyB() tp:DestroyLogsB() end - -- Recall harvester plates and players on them. - --for k,v in pairs(global.Harvesters)do v:Recall(true) end - -end - - -function warptorio.WarpBuildPlanet(key) - local nplanet - if(key)then - nplanet=remote.call("planetorio","FromTemplate","warpzone_"..global.warpzone,key) - else - local vplanet=warptorio.GetMainPlanet() - local lvl=research.level("warptorio-reactor") - if(lvl>=8)then local wx=global.planet_target - if(wx=="home" or wx=="nauvis")then if(research.has("warptorio-homeworld"))then local hf=(wx=="nauvis" and game.surfaces.nauvis or global.floor.home.host) - if(warptorio.GetMainSurface()~=hf and math.random(1,100)<=warptorio.setting("warpchance"))then local hp=remote.call("planetorio","GetBySurface",hf) or {name="Nauvis"} - game.print({"warptorio.successful_warp"}) game.print({"warptorio.home_sweet_home",hp.name}) - return hf,hp - end - end elseif(wx and math.random(1,100)<=warptorio.setting("warpchance"))then - nplanet=remote.call("planetorio","FromTemplate","warpzone_"..global.warpzone,wx) - if(nplanet)then game.print({"warptorio.successful_warp"}) end - end - end - if(not nplanet)then nplanet=remote.call("planetorio","SimplePlanetRoll","warpzone_"..global.warpzone,{zone=global.warpzone,prevplanet=vplanet}) end -- planetorio, modifiers={{"",stuff}}) - end - if(research.has("warptorio-charting") or not nplanet.planet.desc)then game.print(nplanet.planet.name) end - if(nplanet.planet.desc)then game.print(nplanet.planet.desc) end - return nplanet.surface,nplanet.planet,nplanet.force -end - - -function warptorio.WarpPostBuildPlanet(planet) - if(planet.warp_multiply)then - global.warp_charge_time=global.warp_charge_time*planet.warp_multiply - global.warp_time_left=global.warp_time_left*planet.warp_multiply - end - --gui.charge_time() -end - -function warptorio.Warp(cf,f) -- Find and clone entities to new surface - --cf.find_entities() - --cf.clone_entities{surface=f,entities=tbl} - - -- call to platform() - - - if(global.Teleporters.offworld)then global.Teleporters.offworld:DestroyPointTeleporter(2) end - - local etbl,tpply=warptorio.platform.GetWarpables(cf,f) --{},{} - for k,v in pairs(etbl)do if(not isvalid(v))then etbl[k]=nil end end - - local blacktbl={} - for k,v in pairs(etbl)do if(table.HasValue(warptorio.GetWarpBlacklist(),v.name))then table.insert(blacktbl,v) etbl[k]=nil end end - for k,v in pairs(etbl)do if(not v or not v.valid)then etbl[k]=nil end end - - -- find logistics networks and robots among entities to catch robots outside the platform - if(settings.global["warptorio_robot_warping"].value==true)then - local lgn={} for k,v in pairs(etbl)do if(v.type=="roboport")then local g=v.logistic_network if(g and g.valid)then table.insertExclusive(lgn,g) end end end - for k,v in pairs(lgn)do for i,e in pairs(v.robots)do table.insertExclusive(etbl,e) end end - end - - - -- do the cloning - warptorio.Cloned_Entities={} - warptorio.IsCloning=true - cf.clone_entities{entities=etbl,destination_offset={0,0},destination_surface=f} --,destination_force=game.forces.player} - warptorio.IsCloning=false - local new_ents=warptorio.Cloned_Entities - warptorio.Cloned_Entities=nil - - -- AAI Vehicles - if(remote.interfaces["aai-programmable-vehicles"])then local rmt="aai-programmable-vehicles" - for k,v in pairs(new_ents)do if(isvalid(v.source) and isvalid(v.destination))then - local sig=remote.call(rmt,"get_unit_by_entity",v.source) if(sig)then remote.call(rmt,"on_entity_deployed",{entity=v.destination,signals=sig.data}) end - end end - end - - --local clones={} for k,v in pairs(etbl)do if(v.valid)then table.insert(clones,v.clone{position=v.position,surface=f,force=v.force}) end end - - -- Recreate teleporter gate - --if(global.Teleporters.offworld)then global.Teleporters.offworld:CheckTeleporterPairs() end - - -- Clean inventories - for k,v in pairs(game.players)do if(v and v.valid)then local iv=v.get_main_inventory() if(iv)then for i,x in pairs(iv.get_contents())do - if(i:sub(1,25)=="warptorio-teleporter-gate")then iv.remove{name=i,count=x} end - if(i:sub(1,20)=="warptorio-harvestpad")then if(x>1)then iv.remove{name=i,count=(x-1)} end end - end end end end - - -- do the player teleport - for k,v in pairs(tpply)do v[1].teleport(f.find_non_colliding_position("character",{v[2][1],v[2][2]},0,1),f) end - - --// cleanup past entities - - for k,v in pairs(etbl)do if(v and v.valid)then v.destroy{raise_destroy=true} end end - for k,v in pairs(blacktbl)do if(v and v.valid)then v.destroy{raise_destroy=true} end end -end - -function warptorio.SurfaceIsWarpzone(f) local n=f.name - local hw=warptorio.GetHomeSurface() - local sf=(n:sub(1,9)=="warpsurf_") -- backwards compatability - local zf=(n:sub(1,9)=="warpzone_") - return (n~="nauvis" and (sf or zf) and f~=hw) -end - -function warptorio.WarpFinished() - local f=warptorio.GetMainSurface() - - --// delete abandoned surfaces - for k,v in pairs(game.surfaces)do - if( table_size(v.find_entities_filtered{type="character"})<1 and v~=f)then - --if(n=="nauvis" and not global.nauvis_is_clear)then global.nauvis_is_clear=true v.clear(true) else - if(warptorio.SurfaceIsWarpzone(v))then game.delete_surface(v) end - end - end - - --warptorio.CheckReactor() - -end - -function warptorio.WarpPost(cf,f) - -- Recreate teleporter gate - if(global.Teleporters.offworld)then global.Teleporters.offworld:CheckTeleporterPairs() end - - --// radar -- game.forces.player.chart(f,{lefttop={x=-256,y=-256},rightbottom={x=256,y=256}}) - - --// build void - --for k,v in pairs({"nw","ne","sw","se"})do local ug=research.level("turret-"..v) or -1 if(ug>=0)then vector.LayCircle("out-of-map",c,vector.circleEx(vector(cx[v].x+0.5,cx[v].y+0.5),math.floor(10+(ug*6)) )) end end - --vector.LayTiles("out-of-map",c,marea) - - if(cf and cf.valid)then warptorio.ConstructPlatformVoid(cf) end - - -end - - - - ---[[ Remotes ]]-- - -warptorio.remote={} - -require("control_main_remotes") - -remote.add_interface("warptorio",warptorio.remote) -remote.add_interface("warptorio2",warptorio.remote) - +--[[------------------------------------- + +Author: Pyro-Fire +https://mods.factorio.com/mod/warptorio2 + +Script: control.lua +Purpose: control stuff + + +Written using Microsoft Notepad. +IDE's are for children. + +How to notepad like a pro: +ctrl+f = find +ctrl+h = find & replace +ctrl+g = show/jump to line (turn off wordwrap n00b) + +Status bar wastes screen space, don't use it. + +Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. + + +]] --------------------------------------- + +local planets = lib.planets + +--[[ Warptorio Environment ]] -- + +warptorio = warptorio or {} +warptorio.Loaded = false + +require("control_main_helpers") + +warptorio.platform = require("control_platform_classic") +local platform = warptorio.platform + + +require("control_class_teleporter") +require("control_class_harvester") +require("control_class_rails") + + +warptorio.chatcmd = {} +function warptorio.chatcmd.kill(ev) + local ply = game.players[ev.player_index] + local c = ply.character + if (c and c.valid) then c.die(c.force, c) end +end + +commands.add_command("kill", "Suicides the player", warptorio.chatcmd.kill) + + +--[[ Warptorio custom events ]] -- +-- Hook in on_load with +-- local eventdefs=remote.call("warptorio","get_events") +-- script.on_event(eventdefs["on_warp"],func() end) + +events.register("on_warp") -- during Warpout() +events.register("on_post_warp") -- during Warpout() +events.register("warp_started") -- StartWarp() +events.register("warp_stopped") -- StopWarp() + +events.register("harvester_deploy") -- ? +events.register("harvester_recall") -- ? + +events.register("ability_used") -- ? + + +--[[ Warptorio Libraries ]] -- + +warptorio.ChestBeltPairs = { { "loader", "wooden-chest" }, { "fast-loader", "iron-chest" }, { "express-loader", "steel-chest" }, + { "express-loader", function(dir) return (dir == "output" and warptorio.setting("loaderchest_provider") or warptorio.setting("loaderchest_requester")) end }, +} +warptorio.ChestBeltPairs[0] = { "loader", "wooden-chest" } +function warptorio.GetChest(dir) + local lv = research.level("warptorio-logistics") + local lvb = warptorio.ChestBeltPairs[lv] + return (isstring(lvb[2]) and lvb[2] or lvb[2](dir)) +end + +function warptorio.GetBelt(dir) + local lv = research.level("warptorio-logistics") + local lvb = warptorio.ChestBeltPairs[lv] + return (isstring(lvb[1]) and lvb[1] or lvb[1](dir)) +end + +--remotes.register("GetChest",warptorio.GetChest) +--remotes.register("GetBelt",warptorio.GetBelt) + + + +--[[ Warptorio Platform ]] -- + +function warptorio.GetPlatform() return warptorio.platform end + +function warptorio.GetCurrentSurface() return storage.floor.main.host end + +function warptorio.GetMainSurface() return storage.floor.main.host end + +function warptorio.GetHomeSurface() return storage.floor.home and storage.floor.home.host or nil end + +function warptorio.GetMainPlanet() return planets.GetBySurface(warptorio.GetMainSurface()) end -- planetorio + +function warptorio.GetHomePlanet() return planets.GetBySurface(warptorio.GetHomeSurface()) end -- planetorio + +function warptorio.GetNamedSurfaces(tbl) + local t = {} + for k, nm in pairs(tbl) do t[nm] = storage.floor[nm].host end + return t +end + +function warptorio.GetAllSurfaces() + local t = {} + for nm, v in pairs(storage.floor) do t[v.hostindex] = v.host end + return t +end + +function warptorio.GetPlatformSurfaces() + local t = {} + for nm, v in pairs(storage.floor) do if (platform.floors[nm].empty == true) then t[v.hostindex] = v.host end end + return t +end + +function warptorio.GetTeleporterSize(a, b, c, noproto) -- for clearing + local x = 1 + if (a and research.has("warptorio-logistics-1")) then x = x + 2 end + if (b and research.has("warptorio-dualloader-1")) then x = x + 1 end + if (c and research.has("warptorio-triloader")) then x = x + 1 end + return vector((x * 2) + 2, 2) +end + +function warptorio.GetTeleporterHazard(bMain, bFull) -- for hazard tiles + local x = 0 + bFull = (bFull == nil and true or bFull) -- has the tech, or -1 + local lgHas = research.has("warptorio-logistics-1") + local dlHas = research.has("warptorio-dualloader-1") + local tlHas = research.has("warptorio-triloader") + local lgCan = research.can("warptorio-logistics-1") + local dlCan = research.can("warptorio-dualloader-1") + local tlCan = research.can("warptorio-triloader") + + if (lgCan or lgHas) then x = x + 2 end + + if (bMain) then + if (tlHas and dlHas) then + x = x + 2 + elseif (tlHas or dlHas) then + x = x + 1 + if (bFull and ((not tlHas and tlCan) or (not dlHas and dlCan))) then x = x + 1 end + elseif (bFull and (tlCan or dlCan)) then + x = x + 1 + end + else + if (tlCan) then x = x + 1 end + end + + + return vector((x * 2) + 2, 2) +end + +warptorio.EmptyGenSettings = { + default_enable_all_autoplace_controls = false, + width = 32 * 12, + height = 32 * 12, + autoplace_settings = { entity = { treat_missing_as_default = false }, tile = { treat_missing_as_default = false }, decorative = { treat_missing_as_default = false }, }, + starting_area = "none", +} + +function warptorio.MakePlatformFloor(vt) + local f = game.create_surface(vt.name, (vt.empty and warptorio.EmptyGenSettings or nil)) + if (vt.empty) then + f.solar_power_multiplier = settings.global.warptorio_solar_multiplier.value + f.daytime = 0 + f.always_day = true + f.request_to_generate_chunks({ 0, 0 }, 16) + f.force_generate_chunk_requests() + f.destroy_decoratives({}) + for k, v in pairs(f.find_entities()) do entity.destroy(v) end + local area = vector.area(vector(-32 * 8, -32 * 8), vector(32 * 8 * 2, 32 * 8 * 2)) + vector.LayTiles("out-of-map", f, area) + end + local floor = cache.raise_surface(f) + if (vt.init) then lib.call(vt.init, floor) end + storage.floor[vt.key] = floor + return floor +end + +function warptorio.GetPlatformFloor(vt) + if (isstring(vt)) then vt = warptorio.platform.floors[vt] end + local floor + if (vt.key == "main") then -- Special; nauvis / primary planet + floor = storage.floor.main + if (not floor) then + floor = { key = vt.key, host = game.surfaces.nauvis, hostindex = 1 } + storage.floor.main = floor + if (vt.init) then lib.call(vt.init, floor) end + end + elseif (vt.key == "home") then -- Special; homeworld + floor = storage.floor.home + if (not floor) then + floor = { key = vt.key, host = game.surfaces.nauvis, hostindex = 1 } + storage.floor.home = floor + end + else + floor = storage.floor[vt.key] + if (not floor) then floor = warptorio.MakePlatformFloor(vt) end + floor.key = vt.key + end + return floor +end + +function warptorio.ConstructFloor(fn, bhzd) warptorio.ConstructPlatform(platform.floors[fn], bhzd) end + +function warptorio.ConstructFloorHazard(fn) warptorio.ConstructHazard(platform.floors[fn]) end + +function warptorio.ConstructPlatformVoid(surf) + local vt = warptorio.platform.floors["main"] + if (vt.tile) then lib.call(vt.tile, surf, true) end +end + +function warptorio.ConstructPlatform(vt, bhzd) + if (isstring(vt)) then vt = warptorio.platform.floors[vt] end + local floor = warptorio.GetPlatformFloor(vt) + if (floor) then + if (vt.tile) then lib.call(vt.tile, floor.host) end + if (bhzd and vt.hazard) then lib.call(vt.hazard, floor.host) end + end +end + +function warptorio.ConstructPlatforms(bhzd) + local platform = warptorio.GetPlatform() + for nm, vt in pairs(platform.floors) do warptorio.ConstructPlatform(vt, bhzd) end +end + +function warptorio.ConstructHazard(vt) + if (isstring(vt)) then vt = warptorio.platform.floors[vt] end + local floor = warptorio.GetPlatformFloor(vt) + if (floor and vt.hazard) then lib.call(vt.hazard, floor.host) end +end + +function warptorio.ConstructHazards() + local platform = warptorio.GetPlatform() + for nm, vt in pairs(platform.floors) do warptorio.ConstructHazard(vt) end +end + +function warptorio.CheckFloorRadar(floor) + if (research.has("warptorio-charting") and not isvalid(floor.radar)) then + floor.radar = entity.protect(entity.create(floor.host, "warptorio-invisradar", vector(-1, -1)), false, false) + end +end + +function warptorio.CheckPlatformSpecials(self) + local platform = warptorio.platform + local vfloor = platform.floors[self.key] + if (not vfloor) then + game.print("no vfloor error: " .. serpent.line(self)) + end + local sp = vfloor.special + if (not sp) then return end + if (not sp.upgrade) then if (not research.has(sp.tech) or isvalid(self.SpecialEnt)) then return end elseif (research.level(sp.tech) < 1) then return end + local protoname = sp.prototype + local inv = {} + if (sp.upgrade) then + protoname = protoname .. "-" .. research.level(sp.tech) + if (isvalid(self.SpecialEnt) and self.SpecialEnt.name == protoname) then + return + elseif (isvalid(self.SpecialEnt)) then + inv = + warptorio.DestroyPlatformSpecial(self) + end + end + + local f = self.host + local efply = {} + local area = vector.square(vector(-0.5, -0.5), sp.size) + local eft = f.find_entities_filtered { area = area } + local rdr = false + if (isvalid(self.radar)) then + rdr = true + entity.destroy(self.radar) + end + for k, v in pairs(eft) do + if (isvalid(v)) then + if (v.type == "character") then + table.insert(efply, v) + elseif (v ~= self.radar) then + entity.destroy(v) + end + end + end + + local e = entity.protect(entity.create(f, protoname, vector(-0.5, -0.5)), false, false) + self.SpecialEnt = e + if (inv) then for k, v in pairs(inv) do e.get_module_inventory().insert { name = v.name, count = v.count } end end -- beacon modules. Close enough. + warptorio.CheckFloorRadar(self) + vector.cleanplayers(f, area) + players.playsound("warp_in", f) +end + +function warptorio.DestroyPlatformSpecial(self) + local inv + if (isvalid(self.SpecialEnt)) then + local x = self.SpecialEnt.get_module_inventory() + if (x) then inv = x.get_contents() end + entity.destroy(self.SpecialEnt) + end + self.SpecialEnt = nil + return inv +end + +function warptorio.InitPlatform() + storage.floor = {} + + for nm, vt in pairs(warptorio.platform.floors) do + local floor = warptorio.GetPlatformFloor(vt) + if (floor) then + warptorio.ConstructPlatform(vt, true) + end + end +end + +--[[ Bootstrap Initialization and Migrations ]] -- + +events.on_init(function() + events.raise_migrate() + lib.planets.lua() + warptorio.ValidateWarpBlacklist() + --warptorio.HookNewGamePlus() + + -- Custom Intro Message + remote.call("freeplay", "set_custom_intro_message", { "warptorio_lore.intro" }) + -- Disable Rocket Victory + if remote.interfaces.silo_script then + remote.call("silo_script", "set_no_victory", true) + end +end) + + +function warptorio.ApplyMapSettings() + local gmp = game.map_settings + gmp.pollution.diffusion_ratio = 0.105 + + gmp.pollution.min_to_diffuse = 15 -- default 15 + gmp.pollution.ageing = 1.0 -- 1.0 + gmp.pollution.expected_max_per_chunk = 250 + gmp.pollution.min_to_show_per_chunk = 50 + gmp.pollution.pollution_restored_per_tree_damage = 9 + gmp.pollution.enemy_attack_pollution_consumption_modifier = 1.0 + + gmp.enemy_evolution.pollution_factor = 0.0000001 + gmp.enemy_evolution.destroy_factor = 0.0002 -- default 0.002 + + gmp.unit_group.min_group_gathering_time = 600 + gmp.unit_group.max_group_gathering_time = 2 * 600 + gmp.unit_group.max_unit_group_size = 200 + gmp.unit_group.max_wait_time_for_late_members = 2 * 360 + gmp.enemy_expansion.settler_group_min_size = 1 + gmp.enemy_expansion.settler_group_max_size = 1 + + --gmp.enemy_expansion.max_expansion_cooldown = (gmp.enemy_expansion.min_expansion_cooldown*1.25) +end + +events.on_config(function(ev) + if (warptorio.Loaded) then return end + lib.planets.lua() + cache.validate("combinators") + cache.validate("heat") + cache.validate("power") + cache.validate("loaderinput") + cache.validate("loaderoutput") + cache.validate("ldinputf") + cache.validate("ldoutputf") + + storage.warpzone = storage.warpzone or 0 + storage.time_spent_start_tick = storage.time_spent_start_tick or game.tick + storage.time_passed = storage.time_passed or 0 + + storage.warp_charge_time = storage.warp_charge_time or 10 + storage.warp_charge_start_tick = storage.warp_charge_start_tick or 0 + storage.warp_charging = storage.warp_charging or 0 + storage.warp_timeleft = storage.warp_timeleft or 60 * 10 + storage.warp_auto_time = storage.warp_auto_time or 60 * settings.global["warptorio_autowarp_time"].value + storage.warp_auto_end = storage.warp_auto_end or 60 * 60 * settings.global["warptorio_autowarp_time"].value + storage.warp_last = storage.warp_last or game.tick + storage.abilities = storage.abilities or {} + storage.ability_drain = storage.ability_drain or settings.global["warptorio_ability_drain"].value + + storage.pollution_amount = storage.pollution_amount or 1.1 + storage.pollution_expansion = storage.pollution_expansion or 1.1 + storage.ability_uses = storage.ability_uses or 0 + storage.ability_next = storage.ability_next or 0 + storage.radar_uses = storage.radar_uses or 0 + + warptorio.ApplyMapSettings() + + storage.votewarp = storage.votewarp or {} + if (type(storage.votewarp) ~= "table") then storage.votewarp = {} end + warptorio.CheckVotewarps() + + -- todo: storage.warp_blacklist={} + warptorio.ValidateWarpBlacklist() + + --[[ more todo: + for k,v in pairs(gwarptorio.Harvesters)do v.position=warptorio.platform.harvester[k] end + for k,v in pairs(gwarptorio.Teleporters)do v.position=warptorio.Teleporters[k].position end + ]] + + storage.Teleporters = storage.Teleporters or {} + storage.Research = storage.Research or {} -- todo remove this + storage.Turrets = storage.Turrets or {} + storage.Rails = storage.Rails or {} + storage.Harvesters = storage.Harvesters or {} + + + if (not storage.floor) then warptorio.InitPlatform() end + + + for k, v in pairs(storage.Rails) do + v:MakeRails() + end + for k, v in pairs(storage.Teleporters) do + v:CheckTeleporterPairs(true) + end + for k, v in pairs(storage.Harvesters) do + local gdata = warptorio.platform.harvesters[v.key] + v.rank = warptorio.GetPlatformTechLevel(gdata.tech) + v:CheckTeleporterPairs(true) + v:Upgrade() + end + + for k, v in pairs(warptorio.settings) do v() end + + -- todo: warptorio.ApplyMapSettings() + for k, t in pairs(storage.Harvesters) do + table.merge(t, table.deepcopy(warptorio.platform.harvesters[t.key])) + table.merge(t, table.deepcopy(warptorio.platform.HarvesterPointData)) + end + + warptorio.Loaded = true +end) + +events.on_load(function() + warptorio.HookNewGamePlus() + if (storage.Teleporters) then for k, v in pairs(storage.Teleporters) do setmetatable(v, warptorio.TeleporterMeta) end end + if (storage.Harvesters) then for k, v in pairs(storage.Harvesters) do setmetatable(v, warptorio.HarvesterMeta) end end + if (storage.Rails) then for k, v in pairs(storage.Rails) do setmetatable(v, warptorio.RailMeta) end end + --lib.planets.lua() +end) + + +--[[ Players Manager ]] -- + +function warptorio.CheckVotewarps() + for k, v in pairs(storage.votewarp) do if (isvalid(v) or not v.connected) then storage.votewarp[k] = nil end end + cache.updatemenu("hud", "warpbtn") +end + +warptorio.teleDir = { + [0] = { 0, -1 }, + [1] = { 1, -1 }, + [2] = { 1, 0 }, + [3] = { 1, 1 }, + [4] = { 0, 1 }, + [5] = { -1, 1 }, + [6] = { -1, 0 }, + [7] = { -1, -1 } +} +function warptorio.TeleportLogic(ply, e, tent) + if ply.controller_type == defines.controllers.remote then return end + local w = ply.walking_state + local ox = tent.position + local x = e.position + local mp = 2 + if (not ply.character) then mp = 3 end + --game.print(serpent.line(ply.vehicle.name)) + if (ply.driving) then + local veh = ply.vehicle + if (veh.type == "spider-vehicle") then + --[[ local cp = ply.position + local xd, yd = (x.x - cp.x), (x.y - cp.y) + local vpos = vector(ox.x + xd * 3, ox.y + yd * 3) + entity.safeteleport(ply, tent.surface, vpos) + local cn = veh.clone { position = ply.position, surface = ply.surface, force = ply.force } + veh.destroy() + cn.set_driver(ply) + else]] -- + local cp = ply.position + local xd, yd = (x.x - cp.x), (x.y - cp.y) + entity.safeteleport(veh, tent.surface, vector(ox.x + xd, ox.y + yd)) + end + elseif (not w.walking) then + local cp = ply.position + local xd, yd = (x.x - cp.x), (x.y - cp.y) + entity.safeteleport(ply, tent.surface, vector(ox.x + xd * mp, ox.y + yd * mp)) + else + local cp = ply.position + local xd, yd = (x.x - cp.x), (x.y - cp.y) + entity.safeteleport(ply, tent.surface, vector(ox.x + xd * mp, ox.y + yd * mp)) + -- local td=warptorio.teleDir[w.direction] local tpe=ply entity.safeteleport(tpe,tent.surface,vector(ox.x+td[1]*mp,ox.y+td[2]*mp)) + end + players.playsound("teleport", e.surface, e.position) + players.playsound("teleport", tent.surface, tent.position) +end + +cache.player({ + raise = function(cp) + local ply = cp.host + entity.safeteleport(ply, warptorio.GetMainSurface(), vector(0, -5)) + local hud = cache.force_menu("hud", ply) + end, + on_position = function(ply) + local cp = cache.force_player(ply) + if ((cp.tprecent or 0) > game.tick) then return end + local f = ply.surface + local z = vector.square(ply.position, vector(0.8, 0.8)) + if (ply.driving) then + local bbox = ply.vehicle.bounding_box + --game.print(serpent.line(bbox)) + bbox.left_top.x = bbox.left_top.x - 0.8 + bbox.left_top.y = bbox.left_top.y - 0.8 + bbox.right_bottom.x = bbox.right_bottom.x + 0.8 + bbox.right_bottom.y = bbox.right_bottom.y + 0.8 + z = bbox + end + + local ents = f.find_entities_filtered { area = z, type = "accumulator" } --todo + for k, v in pairs(ents) do + local tpg = cache.get_entity(v) + if (tpg and isvalid(tpg.teleport_dest)) then + cp.tprecent = game.tick + 10 + local tgate = tpg.teleport_dest + warptorio.TeleportLogic(ply, v, tgate) + end + end + end, + on_create = function(ply) + local cp = cache.raise_player(ply) + end, + on_join = function(ply) + local menu = cache.force_menu("hud", ply) + entity.safeteleport(ply, warptorio.GetMainSurface(), { 0, -5 }) + end, + on_respawn = function(ply) + local cf = warptorio.GetMainSurface() + local gp = ply + if (gp.surface ~= cf) then + local pos = cf.find_non_colliding_position("character", { 0, -5 }, 0, 1, 1) + gp.teleport(pos, cf) + end + end, + on_left = function(ply) + if (storage.votewarp[ply.index]) then + storage.votewarp[ply.index] = nil + cache.updatemenu("hud", "warpbtn") + end + end, + on_pre_removed = function(ply) + local cp = cache.get_player(ply) + if (cp) then + cache.destroy_player(ply) + end + end, + on_capsule = function(ply, ev) + if (ev.item.name == "warptorio-townportal") then + local p = game.players[ev.player_index] + if (p and p.valid) then + players.playsound("teleport", p.surface, p.position) + entity.safeteleport(p, warptorio.GetMainSurface(), vector(0, -5)) + players.playsound("teleport", p.surface, p.position) + end + elseif (ev.item.name == "warptorio-homeportal" and warptorio.GetHomeSurface()) then + local p = game.players[ev.player_index] + if (p and p.valid) then + players.playsound("teleport", p.surface, p.position) + entity.safeteleport(p, warptorio.GetHomeSurface(), vector(0, -5)) + players.playsound("teleport", p.surface, p.position) + end + end + end, +}) + + + + + +--[[ Warptorio Cache Manager ]] -- + + +-- Pumps and resources cannot be cloned in warptorio +cache.type("offshore-pump", { clone = function(e) e.destroy { raise_destroy = true } end, }) +cache.type("resource", { clone = function(e) e.destroy { raise_destroy = true } end, }) + +-- Simple globally balanced entities +cache.ent("warptorio-heatpipe", + { create = function(e) cache.insert("heat", e) end, destroy = function(e) cache.remove("heat", e) end }) +cache.ent("warptorio-reactor", + { create = function(e) cache.insert("heat", e) end, destroy = function(e) cache.remove("heat", e) end }) +cache.ent("warptorio-accumulator", + { create = function(e) cache.insert("power", e) end, destroy = function(e) cache.remove("power", e) end }) + +events.on_tick(1, 0, "heattick", function(tick) entity.AutoBalanceHeat(cache.get("heat")) end) +events.on_tick(1, 0, "powertick", function(tick) + local t = cache.get("power") + local g, c = 0, 0 + for k, v in pairs(t) do + if (isvalid(v)) then + g = g + v.energy + c = c + v.electric_buffer_size + end + end + + local egdrain = storage.ability_drain + local abc = 0 + if (storage.abilities.stabilizing) then + abc = abc + 1 + end + if (storage.abilities.accelerating) then + abc = abc + 1 + end + if (storage.abilities.scanning) then + abc = abc + 1 + end + + if (abc > 0) then + local gcost = c * egdrain * abc + if (g >= gcost) then + g = math.max(g - gcost, 0) + storage.ability_drain = math.min(egdrain + (0.00000002 * abc), 0.25) + else + storage.abilities.stabilizing = false + storage.abilities.scanning = false + storage.abilities.accelerating = false + end + end + storage.energycount = g + storage.energymax = c + for k, v in pairs(t) do if (v.valid) then v.energy = g * (v.electric_buffer_size / c) end end +end) + +-- Warptorio Combinators +cache.ent("warptorio-combinator", { + create = function(e, ev) cache.insert("combinators", e) end, + destroy = function(e, ev) cache.remove("combinators", e) end, + update = function(e, ev) + local cbh = e.get_or_create_control_behavior() + for k, v in pairs(ev.signals) do cbh.set_signal(k, v) end + end, +}) +function warptorio.RefreshWarpCombinators() + local sigs = warptorio.GetCombinatorSignals() + cache.entcall("combinators", "update", { signals = sigs }) +end + +function warptorio.GetCombinatorSignals() + local tbl = {} + for k, v in pairs(warptorio.Signals) do tbl[k] = { signal = v.signal, count = v.get() } end + return tbl +end + +warptorio.Signals = {} -- 18 max default +warptorio.Signals[1] = { signal = { type = "virtual", name = "signal-W" }, get = function() return (storage.warp_charging >= 1 and (storage.warp_time_left or 10) / 60 or (storage.warp_charge_time or 10)) end } +warptorio.Signals[2] = { + signal = { type = "virtual", name = "signal-X" }, + get = function() + return storage.warp_charging or + 0 + end +} +warptorio.Signals[3] = { + signal = { type = "virtual", name = "signal-A" }, + get = function() + return storage.warp_auto_end / + 60 + end +} +warptorio.Signals[4] = { + signal = { type = "virtual", name = "signal-L" }, + get = function() + local hv = storage.Harvesters.west + return ((hv and hv.deployed) and 1 or 0) + end +} +warptorio.Signals[5] = { + signal = { type = "virtual", name = "signal-R" }, + get = function() + local hv = storage.Harvesters.east + return ((hv and hv.deployed) and 1 or 0) + end +} +warptorio.Signals[6] = { signal = { type = "virtual", name = "signal-P" }, get = function() return storage.time_passed end } + +--[[ Warptorio Gui ]] -- + + +--cache.updatemenu("hud","raise") -- to recreate the menu + +function warptorio.RaiseHUD(v) + local m = cache.get_menu("hud", v) + if (not m) then cache.raise_menu("hud", v) else cache.call_menu("raise", m) end +end + +function warptorio.ResetHUD(p) + if (not p) then + for k, v in pairs(game.players) do warptorio.RaiseHUD(v) end + else + warptorio.RaiseHUD(p) + end +end + +function warptorio.PlayerCanStartWarp(ply) return true end + +function warptorio.ToolRecallHarvester(k, ply) + if (not research.has("warptorio-harvester-" .. k .. "-1")) then return end + local cn = ("warptorio-harvestpad-" .. k .. "-" .. research.level("warptorio-harvester-" .. k)) + if (not ply or (ply and not ply.get_main_inventory().get_contents()[cn])) then + ply.get_main_inventory().insert { name = cn, count = 1 } + players.playsound("warp_in", ply.surface, ply.position) + end + local hv = storage.Harvesters[k] + if (hv and hv.deployed and isvalid(hv.b)) then + players.playsound("warp_in", hv.b.surface, hv.b.position) + hv:Recall() + hv:DestroyB() + end +end + +function warptorio.ToolRecallGate(ply) + if (not research.has("warptorio-teleporter-portal")) then return end + local t = storage.Teleporters.offworld + if (t) then + if (t.b and t.b.valid) then + players.playsound("warp_in", t.b.surface, t.b.position) + t:DestroyLogsB() + t:DestroyB() + end + local inv = ply.get_main_inventory() + if (not inv.get_contents()["warptorio-teleporter-gate-0"]) then + inv.insert { name = "warptorio-teleporter-gate-0", count = 1 } + players.playsound("warp_in", ply.surface, ply.position) + end + end +end + +cache.vgui("warptorio_toolbutton", + { + click = function(elm, ev) + local menu = cache.get_menu("hud", elm.player_index) + local b = menu.toolbar + b.visible = not b.visible + end + }) +cache.vgui("warptorio_tool_hv_west", + { click = function(elm, ev) warptorio.ToolRecallHarvester("west", game.players[elm.player_index]) end }) +cache.vgui("warptorio_tool_hv_east", + { click = function(elm, ev) warptorio.ToolRecallHarvester("east", game.players[elm.player_index]) end }) +cache.vgui("warptorio_tool_planet_gate", + { click = function(elm, ev) warptorio.ToolRecallGate(game.players[elm.player_index]) end }) + + +cache.vgui("warptorio_homeworld", { + click = function(elm, ev) + local menu = cache.get_menu("hud", elm.player_index) + if (menu.hometmr < game.tick) then + menu.hometmr = game.tick + (60 * 5) + cache.call_menu("clocktick", menu) + else + storage.homeworld = storage.warpzone + local f = storage.floor.main.host + storage.floor.home.host = f + storage.floor.home.hostindex = f.index + players.playsound("warp_in", storage.floor.home.host) + game.print({ "warptorio.homeworld-set" }) + menu.hometmr = 0 + cache.call_menu("clocktick", menu) + + --Warptorio Victory Screen + game.set_win_ending_info({ + title = "Victory!", + message = "Finally, You found your Home!", + final_message = "With best regards,\nWarptorio Team.", + }) + game.set_game_state({ + can_continue = true, + game_finished = true, + victorious_force = player.force, + player_won = true, + }) + end + end, +}) + +local HUD = {} +warptorio.HUD = HUD +function HUD.clocktick(menu) + local ply = menu.host + if (storage.warp_charging >= 1) then + menu.charge_time.caption = { "warptorio.warp-in", util.formattime(val or (storage.warp_time_left or 0)) } + elseif (menu.charge_time) then + menu.charge_time.caption = { "warptorio.charge_time", util.formattime((storage.warp_charge_time or 0) * 60) } + end + + menu.time_passed.caption = { "warptorio.time_passed", util.formattime(storage.time_passed or 0) } + if (warptorio.IsAutowarpEnabled()) then + menu.autowarp.caption = { "warptorio.autowarp-in", util.formattime(storage.warp_auto_end) } + else + menu.autowarp.caption = "" + end + + menu.hometmr = menu.hometmr or 0 + if (menu.homeworld) then + if (menu.hometmr > game.tick) then + menu.homeworld.caption = { "warptorio.confirm_homeworld", util.formattime(menu.hometmr - game.tick) } + else + menu.homeworld.caption = { "warptorio.button-homeworld" } + end + end + + if (menu.energybar) then + local cureng = storage.energycount or 0 + local maxeng = math.max(storage.energymax or 1, 1) + local energydif = cureng - (menu.last_energy or 0) + menu.last_energy = cureng + + local egdrain = storage.ability_drain * 100 * 60 + local abc = 0 + local r = menu.stabilizer + if (r) then + if (storage.abilities.stabilizing) then + abc = abc + 1 + r.caption = { "warptorio.stabilize-on", "-" .. math.roundx(egdrain, 2) .. "%/sec" } + else + r.caption = { "warptorio.stabilize" } + end + end + local r = menu.accelerator + if (r) then + if (storage.abilities.accelerating) then + abc = abc + 1 + r.caption = { "warptorio.accel-on", "-" .. math.roundx(egdrain, 2) .. "%/sec" } + else + r.caption = { "warptorio.accel" } + end + end + local r = menu.radar + if (r) then + if (storage.abilities.scanning) then + abc = abc + 1 + r.caption = { "warptorio.radar-on", "-" .. math.roundx(egdrain, 2) .. "%/sec" } + else + r.caption = { "warptorio.radar" } + end + end + menu.energybar_energy.caption = " " .. string.energy_to_string(cureng) .. " " + menu.energybar_energymax.caption = " " .. string.energy_to_string(maxeng) .. " " + menu.energybar_energybal.caption = " (" .. + (energydif >= 1 and "+" or (energydif > 0 and "+-" or "")) .. string.energy_to_string(energydif) .. "/sec) " + menu.energybar_energybal.style.font_color = (energydif > 0 and { r = 0, g = 1, b = 0 } or (energydif < 0 and { r = 1, g = 0, b = 0 } or { r = 0.75, g = 0.75, b = 0.75 })) + menu.energybar.value = cureng / maxeng + menu.energybar_energypct.caption = " " .. math.roundx((cureng / maxeng) * 100, 2) .. "% " + if (abc > 0) then + menu.energybar_energypctx.caption = "-" .. math.roundx(egdrain * abc, 2) .. "%/sec" + else + menu.energybar_energypctx.caption = "" + end + end +end + +function HUD.raise(menu, ev) + local ply = menu.host + menu.frame = vgui.create(ply.gui.left, { name = "warptorio_frame", type = "flow", direction = "vertical" }) + menu.frame.style.left_padding = 4 + menu.row1 = vgui.create(menu.frame, { name = "warptorio_row1", type = "flow", direction = "horizontal" }) + menu.row2 = vgui.create(menu.frame, { name = "warptorio_row2", type = "flow", direction = "horizontal" }) + menu.row4 = vgui.create(menu.frame, { name = "warptorio_row4", type = "flow", direction = "horizontal" }) + menu.row3 = vgui.create(menu.frame, { name = "warptorio_row3", type = "flow", direction = "horizontal" }) + menu.row1.clear() + menu.row2.clear() + menu.row3.clear() + menu.row4.clear() + + menu.warpbtn = vgui.create(menu.row1, + { name = "warptorio_warpbutton", type = "button", caption = { "warptorio.button-warp", "-" } }) + if (research.has("warptorio-toolbar")) then + menu.toolbtn = vgui.create(menu.row1, + { name = "warptorio_toolbutton", type = "button", caption = { "warptorio.toolbutton", "-" } }) + end + if (research.level("warptorio-reactor") >= 8) then + menu.warptgt = vgui.create(menu.row1, { name = "warptorio_warptarget", type = "drop-down" }) + HUD.rebuild_warptargets(menu) + HUD.warptarget(menu, + { tgt = (sx == nil and "(Random)" or (sx == "home" and "(Homeworld)" or (sx == "(nauvis)" and "nauvis" or sx))) }) + end + + menu.time_passed = vgui.create(menu.row1, { name = "warptorio_time_passed", type = "label" }) + menu.charge_time = vgui.create(menu.row1, { name = "warptorio_charge_time", type = "label" }) + menu.warpzone = vgui.create(menu.row1, + { name = "warptorio_warpzone", type = "label", caption = { "warptorio.warpzone", storage.warpzone or 0 } }) + menu.autowarp = vgui.create(menu.row1, { name = "warptorio_autowarp", type = "label" }) + + if (research.has("warptorio-homeworld")) then + menu.homeworld = vgui.create(menu.row1, + { name = "warptorio_homeworld", type = "button", caption = { "warptorio.button-homeworld" } }) + end + + + local hasabil = false + if (research.has("warptorio-stabilizer")) then + hasabil = true + menu.stabilizer = vgui.create(menu.row2, + { name = "warptorio_stabilizer", type = "button", caption = { "warptorio.stabilize", "-" } }) + end + if (research.has("warptorio-accelerator")) then + hasabil = true + menu.accelerator = vgui.create(menu.row2, + { name = "warptorio_accelerator", type = "button", caption = { "warptorio.accel", "-" } }) + end + if (research.has("warptorio-charting")) then + hasabil = true + menu.radar = vgui.create(menu.row2, + { name = "warptorio_radar", type = "button", caption = { "warptorio.radar", "-" } }) + end + if (hasabil) then + menu.last_energy = menu.last_energy or 100 + local energydif = 1000 - menu.last_energy + menu.energybar_label = vgui.create(menu.row4, + { name = "warptorio_energybar_label", type = "label", caption = { "warptorio.energybar", "-" } }) + menu.energybar_energy = vgui.create(menu.row4, { + name = "warptorio_energybar_energy", + type = "label", + caption = + " 100kw " + }) + menu.energybar_energy.style.font_color = { r = 0, g = 1, b = 0 } + + menu.energybar_energydiv = vgui.create(menu.row4, + { name = "warptorio_energybar_energydiv", type = "label", caption = " / " }) + + menu.energybar_energymax = vgui.create(menu.row4, + { name = "warptorio_energybar_energymax", type = "label", caption = " 0kw " }) + menu.energybar_energymax.style.font_color = { r = 0.25, g = 1, b = 1 } + + + menu.energybar_energybal = vgui.create(menu.row4, + { name = "warptorio_energybar_energybal", type = "label", caption = " (+100.32MW/sec) " }) + menu.energybar_energybal.style.font_color = (energydif > 0 and { r = 0, g = 1, b = 0 } or (energydif == 0 and { r = 1, g = 1, b = 0 } or { r = 1, g = 0, b = 0 })) + + + menu.energybar_energydivb = vgui.create(menu.row4, + { name = "warptorio_energybar_energydivb", type = "label", caption = " | " }) + + + menu.energybar = vgui.create(menu.row4, { name = "warptorio_time_passed", type = "progressbar", value = 0.3 }) + menu.energybar.style.natural_width = 250 + menu.energybar.style.top_padding = 7 + menu.energybar.style.bottom_padding = 7 + + menu.energybar_energypcta = vgui.create(menu.row4, + { name = "warptorio_energybar_energypcta", type = "label", caption = " | " }) + menu.energybar_energypct = vgui.create(menu.row4, + { name = "warptorio_energybar_energypct", type = "label", caption = "25%" }) + menu.energybar_energypct.style.font_color = { r = 1, g = 1, b = 1 } + menu.energybar_energypctx = vgui.create(menu.row4, + { name = "warptorio_energybar_energypctx", type = "label", caption = "-3%/sec" }) + menu.energybar_energypctx.style.font_color = { r = 1, g = 0, b = 0 } + end + + if (research.has("warptorio-toolbar")) then + menu.toolbar = vgui.create(menu.row3, + { name = "warptorio_toolframe", type = "flow", direction = "horizontal", visible = false }) + menu.toolbar.clear() + menu.tool_harvester_west = vgui.create(menu.toolbar, + { name = "warptorio_tool_hv_west", type = "sprite-button", sprite = "entity/warptorio-harvestportal-1", tooltip = { "warptorio.tool_hv_west", "-" } }) + menu.tool_planet_gate = vgui.create(menu.toolbar, + { name = "warptorio_tool_planet_gate", type = "sprite-button", sprite = "item/warptorio-teleporter-gate-0", tooltip = { "warptorio.tool_planet_gate", "-" } }) + menu.tool_harvester_east = vgui.create(menu.toolbar, + { name = "warptorio_tool_hv_east", type = "sprite-button", sprite = "entity/warptorio-harvestportal-1", tooltip = { "warptorio.tool_hv_east", "-" } }) + end + + HUD.clocktick(menu) + HUD.rebuild_warptargets(menu) + local sx = storage.planet_target +end + +function HUD.rebuild_warptargets(menu, ev) + if (menu.warptgt) then + local tgl = { "(Random)" } + if (research.has("warptorio-homeworld")) then + table.insert(tgl, "(Homeworld)") + table.insert(tgl, "(Nauvis)") + end + if (research.has("warptorio-charting")) then + for k, v in pairs(lib.planets.GetTemplates()) do + table.insert(tgl, v.key) + end + end + menu.warptgt.items = tgl + HUD.warptarget(menu, { tgt = storage.planet_target }) + end +end + +function HUD.warptarget(menu, ev) + local ply = menu.host + if (not menu.warptgt or ply.index == ev.ply) then return end + local elm, items = menu.warptgt + if (elm) then items = elm.items end + if (not items) then return end + for idx, kv in pairs(items) do if (type(kv) == "string" and kv:lower() == ev.tgt) then elm.selected_index = idx end end +end + +function HUD.warpbtn(menu) + local r = menu.warpbtn + local ply = menu.host + if (storage.warp_charging >= 1) then + r.caption = { "warptorio.warping", "-" } + r.enabled = false + else + local cx = table.Count(storage.votewarp) + local c = table.Count(game.connected_players) -- table.Count(game.non_afk_players) + if (c > 1) then + local vcn = math.ceil(c * warptorio.setting("votewarp_multi")) + if (storage.votewarp[ply.index] and cx < vcn) then r.enabled = false else r.enabled = true end + if (cx > 0) then + r.caption = { "warptorio.button-votewarp-count", cx, vcn } + else + r.caption = { "warptorio.button-votewarp", "-" } + end + else + r.enabled = true + r.caption = { "warptorio.button-warp", "-" } + menu.warpzone.caption = { "warptorio.warpzone_label", storage.warpzone or 0 } + end + end +end + +cache.menu("hud", HUD) + +cache.vgui("warptorio_warptarget", { + selection_changed = function(elm, ev) + local ply = game.players[elm.player_index] + local s = elm.items[elm.selected_index] + if (not s) then return end + local sx = s:lower() + local vt = (sx == "(random)" and nil or (sx == "(homeworld)" and "home" or (sx == "(nauvis)" and "nauvis" or sx))) + if (vt ~= storage.planet_target) then + storage.planet_target = vt + game.print({ "warptorio.player_set_warp_target", ply.name, s }) + cache.updatemenu("hud", "warptarget", { ply = elm.player_index, tgt = sx }) + end + end, +}) + +function warptorio.StartWarp() + if (storage.warp_charging < 1) then + events.vraise("warp_started") + storage.warp_charge_start_tick = game.tick + storage.warp_charging = 1 + players.playsound("reactor-stabilized") + cache.updatemenu("hud", "warpbtn") + end +end + +function warptorio.StopWarp() + if (storage.warp_charging > 0) then + events.vraise("warp_stopped") + storage.warp_charging = 0 + storage.warp_charge_time = storage.warp_time_left / 60 + storage.warp_charge_start_tick = 0 + end +end + +function warptorio.IsWarping() return storage.warp_charging > 0 end + +cache.vgui("warptorio_warpbutton", { + click = function(elm, ev) + local ply = game.players[elm.player_index] + local menu = cache.get_menu("hud", elm.player_index) + if (storage.warp_charging < 1) then + local c = table.Count(game.connected_players) -- table.Count(game.non_afk_players) + if (c > 1 and warptorio.setting("votewarp_multi") > 0) then --votewarp + local vcn = math.ceil(c * warptorio.setting("votewarp_multi")) + storage.votewarp[ply.index] = ply + local cx = table.Count(storage.votewarp) + if (vcn <= 1 or cx >= vcn) then + warptorio.StartWarp() + game.print({ "warptorio.player_started_warpout", ply.name }) + else + players.playsound("teleport") + game.print({ "warptorio.player_want_vote_warp", ply.name, cx, vcn }) + cache.updatemenu("hud", "warpbtn") + end + elseif (warptorio.PlayerCanStartWarp(ply)) then + storage.warp_charge_start_tick = game.tick + storage.warp_charging = 1 + players.playsound("reactor-stabilized") + cache.updatemenu("hud", "warpbtn") + else + ply.print({ "warptorio.same-planet-error" }) + end + end + end, +}) + +cache.vgui("warptorio_stabilizer", { + click = function(elm, ev) + local ply = game.players[elm.player_index] + local menu = cache.get_menu("hud", elm.player_index) + storage.abilities.stabilizing = not storage.abilities.stabilizing + end, +}) +cache.vgui("warptorio_accelerator", { + click = function(elm, ev) + local ply = game.players[elm.player_index] + local menu = cache.get_menu("hud", elm.player_index) + storage.abilities.accelerating = not storage.abilities.accelerating + end, +}) +cache.vgui("warptorio_radar", { + click = function(elm, ev) + local ply = game.players[elm.player_index] + local menu = cache.get_menu("hud", elm.player_index) + storage.abilities.scanning = not storage.abilities.scanning + end, +}) + +--[[ Warping stuff ]] -- + +function warptorio.ValidateWarpBlacklist() +end + +local staticBlacklist = { "highlight-box", "big_brother-blueprint-radar", "osp_repair_radius" } +function warptorio.GetWarpBlacklist() + return staticBlacklist +end + +-- OnEntCloned +events.on_event(defines.events.on_entity_cloned, function(ev) + if (warptorio.IsCloning) then + table.insert(warptorio.Cloned_Entities, { + source = ev.source, + destination = ev.destination + }) + end + if (ev.source.type == "spider-vehicle") then + for k, v in pairs(game.players) do + if (v.driving and v.vehicle == ev.source) then + entity.safeteleport(v, ev.destination.surface, ev.destination.position) + ev.destination.set_driver(v) + end + --[[ + local inv = v.get_main_inventory() + if (inv) then + for i = 1, #inv, 1 do + local e = inv[i] + if (e and e.valid_for_read and e.connected_entity == ev.source) then + e.connected_entity = ev.destination + end + end + local e = v.cursor_stack + if (e and e.valid_for_read and e.connected_entity == ev.source) then e.connected_entity = ev.destination end + end]] + end + end +end) + +function warptorio.CountPlatformEntities() return 5 end -- todo + +function warptorio.Warpout(key) + warptorio.IsWarping = true + for k, v in pairs(storage.Harvesters) do if (v.deployed) then v:Recall(true) end end + + local cp = warptorio.GetMainPlanet() + local cf = warptorio.GetMainSurface() + warptorio.WarpPreBuildPlanet(key) + local f, w, frc = warptorio.WarpBuildPlanet(key) + warptorio.WarpPostBuildPlanet(w) + + storage.floor.main.host = f + storage.floor.main.hostindex = f.index + + warptorio.ConstructPlatform("main", true) + + events.vraise("on_warp", { newsurface = f, newplanet = w, oldsurface = cf, oldplanet = cp }) + if (cp and cp.on_warp) then lib.call(cp.on_warp, f, w, cf, cp) end + + warptorio.Warp(cf, f) + warptorio.WarpPost(cf, f) + + -- reset pollution & biters + game.forces["enemy"].set_evolution_factor(0) + storage.pollution_amount = 1.1 + storage.pollution_expansion = 1.1 + + -- warp sound + players.playsound("warp_in") + + warptorio.WarpFinished() + events.vraise("on_post_warp", { newsurface = f, newplanet = w }) + if (w.postwarpout) then lib.call(w.postwarpout, { newsurface = f, newplanet = w }) end + warptorio.IsWarping = false +end + +function warptorio.WarpPreBuildPlanet(key) + storage.warp_charge = 0 + storage.warp_charging = 0 + storage.votewarp = {} + storage.warp_last = game.tick + + storage.warpzone = storage.warpzone + 1 + + -- Warp chargetime cooldown math + local cot = warptorio.CountPlatformEntities() + + local sgZone = warptorio.setting("warpcharge_zone") + local sgZoneGain = warptorio.setting("warpcharge_zonegain") + local sgMax = warptorio.setting("warpcharge_max") + local sgFactor = warptorio.setting("warp_charge_factor") + local sgMul = warptorio.setting("warpcharge_multi") + + storage.warp_charge_time = math.min( + 10 + (cot / sgFactor) + (storage.warpzone * sgMul) + + (sgZoneGain * (math.min(storage.warpzone, sgZone) / sgZone) * 60), + 60 * sgMax) + storage.warp_time_left = 60 * storage.warp_charge_time + + -- Autowarp timer math + local rta = research.level("warptorio-reactor") + storage.warp_auto_time = 60 * warptorio.setting("autowarp_time") + 60 * 10 * rta + storage.warp_auto_end = game.tick + storage.warp_auto_time * 60 + + -- Abilities + --storage.ability_uses=0 + --storage.radar_uses=0 + --storage.ability_next=game.tick+60*60*warptorio.setting("ability_warp") + + storage.ability_drain = warptorio.setting("ability_drain") or 0.00001 + storage.abilities = {} + + -- Update guis + --if(research.has("warptorio-accelerator") or research.has("warptorio-charting") or research.has("warptorio-stabilizer"))then end --gui.uses() gui.cooldown() + --if(warptorio.IsAutowarpEnabled())then gui.autowarp() end + --gui.warpzone() + cache.updatemenu("hud", "warpbtn") + + -- packup old teleporter gate + --local tp=storage.Teleporters.offworld if(tp and tp:ValidB())then tp:DestroyB() tp:DestroyLogsB() end + -- Recall harvester plates and players on them. + --for k,v in pairs(storage.Harvesters)do v:Recall(true) end +end + +function warptorio.WarpBuildPlanet(key) + local nplanet + if (key) then + nplanet = remote.call("planetorio", "FromTemplate", "warpzone_" .. storage.warpzone, key) + else + local vplanet = warptorio.GetMainPlanet() + local lvl = research.level("warptorio-reactor") + if (lvl >= 8) then + local wx = storage.planet_target + if (wx == "home" or wx == "nauvis") then + if (research.has("warptorio-homeworld")) then + local hf = (wx == "nauvis" and game.surfaces.nauvis or storage.floor.home.host) + if (warptorio.GetMainSurface() ~= hf and math.random(1, 100) <= warptorio.setting("warpchance")) then + local hp = remote.call("planetorio", "GetBySurface", hf) or { name = "Nauvis" } + game.print({ "warptorio.successful_warp" }) + game.print({ "warptorio.home_sweet_home", hp.name }) + return hf, hp + end + end + elseif (wx and math.random(1, 100) <= warptorio.setting("warpchance")) then + nplanet = remote.call("planetorio", "FromTemplate", "warpzone_" .. storage.warpzone, wx) + if (nplanet) then game.print({ "warptorio.successful_warp" }) end + end + end + if (not nplanet) then + nplanet = remote.call("planetorio", "SimplePlanetRoll", "warpzone_" .. storage.warpzone, + { zone = storage.warpzone, prevplanet = vplanet }) + end -- planetorio, modifiers={{"",stuff}}) + end + if (research.has("warptorio-charting") or not nplanet.planet.desc) then game.print(nplanet.planet.name) end + if (nplanet.planet.desc) then game.print(nplanet.planet.desc) end + return nplanet.surface, nplanet.planet, nplanet.force +end + +function warptorio.WarpPostBuildPlanet(planet) + if (planet.warp_multiply) then + storage.warp_charge_time = storage.warp_charge_time * planet.warp_multiply + storage.warp_time_left = storage.warp_time_left * planet.warp_multiply + end + --gui.charge_time() +end + +function warptorio.Warp(cf, f) -- Find and clone entities to new surface + --cf.find_entities() + --cf.clone_entities{surface=f,entities=tbl} + + -- call to platform() + + if (storage.Teleporters.offworld) then storage.Teleporters.offworld:DestroyPointTeleporter(2) end + + local etbl, tpply = warptorio.platform.GetWarpables(cf, f) --{},{} + for k, v in pairs(etbl) do if (not isvalid(v)) then etbl[k] = nil end end + + local blacktbl = {} + for k, v in pairs(etbl) do + if (table.HasValue(warptorio.GetWarpBlacklist(), v.name)) then + table.insert(blacktbl, v) + etbl[k] = nil + end + end + for k, v in pairs(etbl) do if (not v or not v.valid) then etbl[k] = nil end end + + -- find logistics networks and robots among entities to catch robots outside the platform + if (settings.global["warptorio_robot_warping"].value == true) then + local lgn = {} + for k, v in pairs(etbl) do + if (v.type == "roboport") then + local g = v.logistic_network + if (g and g.valid) then table.insertExclusive(lgn, g) end + end + end + for k, v in pairs(lgn) do for i, e in pairs(v.robots) do table.insertExclusive(etbl, e) end end + end + + -- do the cloning + warptorio.Cloned_Entities = {} + warptorio.IsCloning = true + cf.clone_entities { entities = etbl, destination_offset = { 0, 0 }, destination_surface = f } --,destination_force=game.forces.player} + warptorio.IsCloning = false + local new_ents = warptorio.Cloned_Entities + warptorio.Cloned_Entities = nil + + -- AAI Vehicles + if (remote.interfaces["aai-programmable-vehicles"]) then + local rmt = "aai-programmable-vehicles" + for k, v in pairs(new_ents) do + if (isvalid(v.source) and isvalid(v.destination)) then + local sig = remote.call(rmt, "get_unit_by_entity", v.source) + if (sig) then remote.call(rmt, "on_entity_deployed", { entity = v.destination, signals = sig.data }) end + end + end + end + + --local clones={} for k,v in pairs(etbl)do if(v.valid)then table.insert(clones,v.clone{position=v.position,surface=f,force=v.force}) end end + + -- Recreate teleporter gate + --if(storage.Teleporters.offworld)then storage.Teleporters.offworld:CheckTeleporterPairs() end + + -- Clean inventories + for k, v in pairs(game.players) do + if (v and v.valid) then + local iv = v.get_main_inventory() + if (iv) then + for i, x in pairs(iv.get_contents()) do + if (x.name:sub(1, 25) == "warptorio-teleporter-gate") then iv.remove { name = x.name, count = x.count } end + if (x.name:sub(1, 20) == "warptorio-harvestpad") then if (x.count > 1) then iv.remove { name = x.name, count = (x.count - 1) } end end + end + end + end + end + + -- do the player teleport + for k, v in pairs(tpply) do v[1].teleport(f.find_non_colliding_position("character", { v[2][1], v[2][2] }, 0, 1), f) end + + --// cleanup past entities + + for k, v in pairs(etbl) do if (v and v.valid) then v.destroy { raise_destroy = true } end end + for k, v in pairs(blacktbl) do if (v and v.valid) then v.destroy { raise_destroy = true } end end +end + +function warptorio.SurfaceIsWarpzone(f) + local n = f.name + local hw = warptorio.GetHomeSurface() + local sf = (n:sub(1, 9) == "warpsurf_") -- backwards compatability + local zf = (n:sub(1, 9) == "warpzone_") + return (n ~= "nauvis" and (sf or zf) and f ~= hw) +end + +function warptorio.WarpFinished() + local f = warptorio.GetMainSurface() + + --// delete abandoned surfaces + for k, v in pairs(game.surfaces) do + if (table_size(v.find_entities_filtered { type = "character" }) < 1 and v ~= f) then + --if(n=="nauvis" and not storage.nauvis_is_clear)then storage.nauvis_is_clear=true v.clear(true) else + if (warptorio.SurfaceIsWarpzone(v)) then game.delete_surface(v) end + end + end + + --warptorio.CheckReactor() +end + +function warptorio.WarpPost(cf, f) + -- Recreate teleporter gate + if (storage.Teleporters.offworld) then storage.Teleporters.offworld:CheckTeleporterPairs() end + + --// radar -- game.forces.player.chart(f,{lefttop={x=-256,y=-256},rightbottom={x=256,y=256}}) + + --// build void + --for k,v in pairs({"nw","ne","sw","se"})do local ug=research.level("turret-"..v) or -1 if(ug>=0)then vector.LayCircle("out-of-map",c,vector.circleEx(vector(cx[v].x+0.5,cx[v].y+0.5),math.floor(10+(ug*6)) )) end end + --vector.LayTiles("out-of-map",c,marea) + + if (cf and cf.valid) then warptorio.ConstructPlatformVoid(cf) end +end + +--[[ Remotes ]] -- + +warptorio.remote = {} + +require("control_main_remotes") + +remote.add_interface("warptorio", warptorio.remote) +remote.add_interface("warptorio2", warptorio.remote) diff --git a/control_main_helpers.lua b/control_main_helpers.lua index b6e634b..ee62cd8 100644 --- a/control_main_helpers.lua +++ b/control_main_helpers.lua @@ -1,826 +1,1075 @@ - ---[[ Todo list ]]-- - ---[[ -function warptorio.CountEntities() local c=0 for k,v in pairs(gwarptorio.floor)do if(v.surface and v.surface.valid and k~="main" and k~="home")then - c=c+table_size(v.surface.find_entities()) -end end return c end -- used in warpout - -function warptorio.BlueprintEntityIsBlacklisted(e) if(warptorio.EntityIsPlatform(e))then return true end return false end -function warptorio.on_player_setup_blueprint.generic(ev) - if(settings.global.warptorio_no_blueprint.value)then return end - local mp=ev.mapping if(not mp)then return end local bpe=mp.get() local ply=game.players[ev.player_index] - local cst=ply.blueprint_to_setup if(not cst or not cst.valid_for_read)then cst=ply.cursor_stack end if(not cst or not cst.valid_for_read)then return end - local ents=cst.get_blueprint_entities() - if(ents)then for k,v in pairs(ents)do if(warptorio.BlueprintEntityIsBlacklisted(bpe[v.entity_number]))then ents[k]=nil end end cst.set_blueprint_entities(ents) end -end - - -function warptorio.PlanetEntityIsPlatform(e) local r --=(e.name:sub(1,9)=="warptorio") if(r)then return true end - for k,v in pairs(gwarptorio.Rails)do if(table.HasValue(v.rails,e))then return true end end - for k,v in pairs{gwarptorio.Teleporters.offworld,gwarptorio.Teleporters.b1}do if(v:ManagesEntity(e))then return true end end -end -function warptorio.EntityIsPlatform(e) local r --=(e.name:sub(1,9)=="warptorio") if(r)then return true end - for k,v in pairs(gwarptorio.Rails)do if(v:ManagesEntity(e))then return true end end - for k,v in pairs(gwarptorio.Teleporters)do if(v:ManagesEntity(e))then return true end end - for k,v in pairs(gwarptorio.Harvesters)do if(v:ManagesEntity(e))then return true end end - for k,v in pairs(gwarptorio.floor)do if(v:ManagesEntity(e))then return true end end - return false -end -]] - ---[[ TODO - -function warptorio.MigrateTileFloor(floor,buildfunc) local f=floor.surface - vector.LayTiles("grass-1",f,vector.square(vector(-1,-1),vector(512,512))) - buildfunc() - local tcs={} - for k,v in pairs(f.find_tiles_filtered{name="grass-1"})do table.insert(tcs,{name="out-of-map",position=v.position}) end - f.set_tiles(tcs,true) -end -function warptorio.MigrateHarvesterFloor() - warptorio.BuildB3() - local rLogs=game.forces.player.technologies["warptorio-logistics-1"].researched - for k,v in pairs(global.warptorio.Harvesters)do local f,pos v:DestroyLogs() - if(v.deployed)then f,pos=v.b.surface,v.deploy_position v:Recall() end - v:DestroyA() v:DestroyB() v:Warpin() if(rLogs)then v:SpawnLogs() end v:Upgrade() - end -end -function warptorio.MigrateTiles() if(warptorio.tilesAreMigrated)then return end warptorio.tilesAreMigrated = true - local flv=gwarptorio.floor.b1 if(flv)then warptorio.MigrateTileFloor(flv,warptorio.BuildB1) end - local flv=gwarptorio.floor.b2 if(flv)then warptorio.MigrateTileFloor(flv,warptorio.BuildB2) end - local flv=gwarptorio.floor.b3 if(flv)then warptorio.MigrateTileFloor(flv,warptorio.MigrateHarvesterFloor) end - warptorio.ValidateCache() - warptorio.BuildPlatform() -end - - - -function warptorio.init.floors(bhzd) - if(not gwarptorio.floor)then gwarptorio.floor={} end - local m=gwarptorio.floor.main if(not m)then m=new(FLOOR,"main",8) m.surface=game.surfaces["nauvis"] end - local m=gwarptorio.floor.b1 if(not m)then m=new(FLOOR,"b1",16) m:MakeEmptySurface() end - local m=gwarptorio.floor.b2 if(not m)then m=new(FLOOR,"b2",17) m:MakeEmptySurface() end - local m=gwarptorio.floor.b3 if(not m)then m=new(FLOOR,"b3",17) m.ovalsize={x=19,y=17} m:MakeEmptySurface() end - warptorio.BuildPlatform(bhzd) - warptorio.BuildB1(bhzd) - warptorio.BuildB2(bhzd) - warptorio.BuildB3(bhzd) -end -function warptorio.RebuildFloors(bhzd) warptorio.init.floors(bhzd) end - - -function warptorio.BuildHazards() warptorio.BuildPlatformHazard() warptorio.BuildB1Hazard() warptorio.BuildB2Hazard() warptorio.BuildB3Hazard() end - - - -function warptorio.BuildPlatformHazard() - -end - -function warptorio.BuildPlatform(bhzd) - - if(bhzd~=true)then warptorio.BuildPlatformHazard() end - - players.playsound("warp_in",f) -end - - -function warptorio.CheckReactor() - local m=gwarptorio.floor.main - local rlv=research.level("warptorio-reactor") -- gwarptorio.Research["reactor"] or 0 - if(rlv>=6 and (not gwarptorio.warp_reactor or not gwarptorio.warp_reactor.valid))then - local f=m.surface - vector.clean(f,vector.square(vector(-0.5,-0.5),vector(5,5))) - local e=f.create_entity{name="warptorio-reactor",position={-1,-1},force=game.forces.player,player=game.players[1]} - vector.cleanplayers(f,vector.square(vector(-0.5,-0.5),vector(5,5))) - gwarptorio.warp_reactor=e - e.minable=false - end -end - - - - -]]-- - - - - ---[[ Settings ]]-- -function warptorio.setting(n) return settings.global["warptorio_"..n].value end - -warptorio.settings={} local setter=warptorio.settings - -function setter.warptorio_autowarp_disable() warptorio.ResetHUD() end -function setter.warptorio_autowarp_always() warptorio.ResetHUD() end -function setter.warptorio_water() warptorio.EarlyWater(settings.global["warptorio_water"].value) end -function setter.warptorio_carebear() warptorio.Carebear(settings.global["warptorio_carebear"].value) end -function setter.warptorio_solar_multiplier() warptorio.SolarMultiplier(settings.global["warptorio_solar_multiplier"].value) end -function setter.warptorio_loaderchest_provider() warptorio.LoaderChestChanged(true) end -function setter.warptorio_loaderchest_requester() warptorio.LoaderChestChanged(false) end -function setter.warptorio_loader_top() warptorio.LoaderSideChanged(true) end -function setter.warptorio_loader_bottom() warptorio.LoaderSideChanged(false) end -function setter.warptorio_combinator_offset() warptorio.CombinatorOffsetChanged() end -function setter.warptorio_hide_sprites() for k,v in pairs(global.Teleporters)do v:CheckPointSprites(1) v:CheckPointSprites(2) end end - - -function warptorio.CombinatorOffsetChanged() - for k,v in pairs(global.Harvesters)do v:DestroyCombos() v:CheckCombo() end -end -function warptorio.LoaderChestChanged(bprovider) -end -function warptorio.LoaderSideChanged(btop) - for k,v in pairs(global.Teleporters)do local g=v:Data().top if((btop and g) or (not btop and not g))then - v:DestroyPointLogistics(1) - v:DestroyPointLogistics(2) - v:CheckTeleporterPairs(true) - end end -end - -function warptorio.SolarMultiplier(x) - for k,v in pairs(warptorio.GetPlatformSurfaces())do v.solar_power_multiplier=x end -end - -warptorio.carebearItems={ -["stone"]=20,["coal"]=20,["iron-plate"]=20,["copper-plate"]=20,["electronic-circuit"]=10,["iron-gear-wheel"]=10, -["wooden-chest"]=4,["transport-belt"]=10,["underground-belt"]=2,["splitter"]=1, -["burner-mining-drill"]=2,["assembling-machine-1"]=2,["small-electric-pole"]=5,["steam-engine"]=1,["boiler"]=1, -["gun-turret"]=4,["uranium-rounds-magazine"]=50,["piercing-rounds-magazine"]=200,["firearm-magazine"]=400, -} -function warptorio.Carebear(b) if(b and not global.carebear)then global.carebear=true - local e=global.floor.main.host.create_entity{name="warptorio-carebear-chest",position={-1,-1},force=game.forces.player} - local inv=e.get_inventory(defines.inventory.chest) for k,v in pairs(warptorio.carebearItems)do inv.insert{name=k,count=v} end -end end - - -function warptorio.EarlyWater(b) if(b and not global.earlywater)then global.earlywater=true - game.forces.player.technologies["warptorio-boiler-water-1"].researched=true -end end - -function warptorio.OnModSettingChanged(ev) local p=ev.player_index local s=ev.setting local st=ev.setting_type - if(warptorio.settings[s])then warptorio.settings[s](ev) end -end script.on_event(defines.events.on_runtime_mod_setting_changed,warptorio.OnModSettingChanged) - - -function warptorio.IsAutowarpEnabled() return warptorio.setting("autowarp_disable")~=true and (not research.has("warptorio-reactor-6") or warptorio.setting("autowarp_always")) end - - -function warptorio.HookNewGamePlus() - if(remote.interfaces["newgameplus"])then if(not warptorio.newgameplus)then warptorio.newgameplus=true - local ngp=remote.call("newgameplus","get_on_technology_reset_event") if(ngp)then script.on_event(ngp,warptorio.OnPreNewGame) end - local ngp=remote.call("newgameplus","get_on_post_new_game_plus_event") if(ngp)then script.on_event(ngp,warptorio.OnPostNewGame) end - end end -end - - - ---[[ Loot Chest ]]-- - - -warptorio.LootItems={ -["roboport"]=4,["construction-robot"]=10,["logistic-robot"]=20, -["logistic-chest-passive-provider"]=10,["logistic-chest-requester"]=10,["logistic-chest-buffer"]=10, -["wooden-chest"]=20,["iron-chest"]=20,["steel-chest"]=20,["storage-tank"]=10, -["wood"]=100,["stone"]=100,["iron-plate"]=400,["iron-gear-wheel"]=300,["steel-plate"]=200,["copper-plate"]=300,["copper-cable"]=400, -["red-wire"]=100,["green-wire"]=100,["electronic-circuit"]=200,["advanced-circuit"]=100,["processing-unit"]=50, -["big-electric-pole"]=25,["medium-electric-pole"]=25,["small-electric-pole"]=25,["substation"]=15, -["landfill"]=100, -["pipe"]=200,["pipe-to-ground"]=50, -["express-transport-belt"]=100,["fast-transport-belt"]=200,["transport-belt"]=300, -["express-underground-belt"]=15,["fast-underground-belt"]=20,["underground-belt"]=25, -["accumulator"]=10,["steam-engine"]=10, -["nuclear-reactor"]=2,["heat-exchanger"]=10,["heat-pipe"]=25,["steam-turbine"]=10, -["chemical-plant"]=10,["assembling-machine-1"]=15,["assembling-machine-2"]=15,["assembling-machine-3"]=15, -["inserter"]=30,["fast-inserter"]=20,["stack-inserter"]=15, -["warptorio-atomic-bomb"]=1,["warptorio-warponium-fuel-cell"]=2,["warptorio-warponium-fuel"]=1, -["gun-turret"]=10,["uranium-rounds-magazine"]=100,["firearm-magazine"]=400,["piercing-rounds-magazine"]=200, -["atomic-bomb"]=2, -} - -function warptorio.GetPossibleLoot() local lt={} for k,v in pairs(warptorio.LootItems)do local r=game.forces.player.recipes[k] if(not r or (r and r.enabled==true))then lt[k]=v end end return lt end -function warptorio.LootTable(mn,mx,cDist,cStack) local lt=warptorio.GetPossibleLoot() local t,u,k,vDist,vStack={} for i=1,math.random(mn or 1,mx or 5),1 do - u,k=table.Random(lt) vDist,vStack=math.min((cDist or 850)/1700,1),math.random((cStack or 20),100)/100 t[k]=math.max(math.ceil(u*vDist*vStack),1) -end return t end -function warptorio.SpawnLootChest(f,pos,varg) pos=vector(pos) varg=varg or {} - local e=f.create_entity{name="warptorio-lootchest",position=pos,force=game.forces.player,raise_built=true} if(not isvalid(e))then return false end - local lt=warptorio.LootTable(varg.min or 1, varg.max or 5,varg.dist or vector.length(pos), varg.stack or 20) - local inv=e.get_inventory(defines.inventory.chest) for k,v in pairs(lt)do inv.insert{name=k,count=v} end - return e -end - -function warptorio.ChunkLootChest(ev) if(settings.global["warptorio_no_lootchest"].value==true or math.random(1,settings.global["warptorio_lootchest_chance"].value)>1)then return end - local f=ev.surface if(not (f.name=="nauvis" or f==warptorio.GetMainSurface()))then return end local a=ev.area - local x,y=math.random(a.left_top.x,a.right_bottom.x),math.random(a.left_top.y,a.right_bottom.y) - local dist=math.sqrt(math.abs(x^2)+math.abs(y^2)) - if(dist>=settings.global["warptorio_lootchest_distance"].value)then warptorio.SpawnLootChest(f,{x,y}) end -end events.on_event(defines.events.on_chunk_generated,warptorio.ChunkLootChest) - - - ---[[ Tick Functions ]]-- - - -function warptorio.ClockTick(tick) - local donewarp=false - if(global.warp_charging==1)then - global.warp_time_left=(60*global.warp_charge_time)-(tick-global.warp_charge_start_tick) - if(global.warp_time_left<=0)then warptorio.Warpout() donewarp=true end - end - global.time_passed=tick-global.warp_last - --gui.time_passed() - --gui.charge_time() - - if(not donewarp and warptorio.IsAutowarpEnabled())then - global.warp_auto_end=(60*global.warp_auto_time)-(tick-global.warp_last) - if(global.warp_auto_end<=0)then warptorio.Warpout() donewarp=true end - end - - cache.updatemenu("hud","clocktick") - --gui.autowarp() - --gui if(research.has("warptorio-charting") or research.has("warptorio-accelerator") or research.has("warptorio-stabilizer"))then warptorio.derma.cooldown() end - --gui if(global.homeworld)then warptorio.derma.homeworld() end - - warptorio.RefreshWarpCombinators() - - - --events.vraise("ticktime",{warp_left=global.warp_time_left,auto_left=warptorio.IsAutowarpEnabled() and global.warp_auto_end or false, donewarp=donewarp}) -end -events.on_tick(60,0,"clock",warptorio.ClockTick) - - -function warptorio.ChargeCountdownTick(tick) - if(global.warp_charging<1 and global.warp_charge_time>30)then - local r=(780)-(research.level("warptorio-reactor")*60) if(tick%r==0)then global.warp_charge_time=math.max(global.warp_charge_time-1,30) end -- 60t*13s=780t - end -end -events.on_tick(60,0,"charge_countdown",warptorio.ChargeCountdownTick) - -function warptorio.WarpAlarmTick(tick) - if((global.warp_charging==1 and global.warp_time_left<=3600) or (warptorio.IsAutowarpEnabled() and global.warp_auto_end<=3600))then players.playsound("warp_alarm") end -end -events.on_tick(120,1,"warpalarm",warptorio.WarpAlarmTick) - -function warptorio.PollutionTick(tick) if(tick%(warptorio.setting("pollution_tickrate")*60)~=0)then return end - local f=warptorio.GetMainSurface() if(not isvalid(f))then return end - local stb=global.abilities.stabilizing - local vpol=0 - if(warptorio.setting("pollution_disable")~=true)then - vpol=global.pollution_amount - global.pollution_amount=math.min( vpol+ (vpol^warptorio.setting("pollution_exponent"))*(stb and 0.05 or warptorio.setting("pollution_multiplier")), 1000000) - end - - for k,v in pairs(warptorio.GetPlatformSurfaces())do - vpol=vpol+v.get_total_pollution() - v.clear_pollution() - end - if(vpol>0)then - f.pollute({-1,-1},vpol*(stb and 0.05 or 1)) -- todo; pollute to teleporters and harvesters *0.125 - end - -end -events.on_tick(60,0,"pollution",warptorio.PollutionTick) - -events.on_tick(60,0,"radar_ability",function(tick) - local rdr=global.abilities.scanning if(not rdr)then return end - local rdrt=global.abilities.scantick or 0 - local rdrg=global.abilities.scanzone or 0 - rdrt=rdrt+1 global.abilities.scantick=rdrt if(rdrt<3+rdrg)then return end rdrt=0 global.abilities.scantick=0 - - - global.abilities.scanzone=rdrg+1 - local f=warptorio.GetMainSurface() - game.forces.player.chart(f,{lefttop={x=-64-32*rdrg,y=-64-32*rdrg},rightbottom={x=64+32*rdrg,y=64+32*rdrg}}) - players.playsound("reactor-stabilized", f) - -end) - - -function warptorio.BiterTick(tick) if(warptorio.setting("biter_wave_disable")==true or tick%(warptorio.setting("pollution_tickrate")*60)~=0)then return end - global.pollution_expansion = math.min( global.pollution_expansion * settings.global["warptorio_biter_expansion"].value, 60*60*settings.global["warptorio_biter_redux"].value ) - game.map_settings.enemy_expansion.min_expansion_cooldown = math.max((60*60*settings.global["warptorio_biter_min"].value)-global.pollution_expansion,60*60*1) - game.map_settings.enemy_expansion.max_expansion_cooldown = math.max( ((60*60*settings.global["warptorio_biter_max"].value)-global.pollution_expansion)+1,60*60*1) - --game.print("pol: " .. game.map_settings.enemy_expansion.min_expansion_cooldown) - local pt=(global.time_passed/60)/60 - if(pt>settings.global["warptorio_biter_wavestart"].value)then pt=pt-settings.global["warptorio_biter_wavestart"].value - local el=math.ceil(pt*settings.global["warptorio_biter_wavesize"].value) - local erng=math.ceil(pt*settings.global["warptorio_biter_waverng"].value) - local bmax=settings.global["warptorio_biter_wavesizemax"].value if(bmax>0)then el=math.min(el,bmax) end - if(math.random(1,math.max(math.min(settings.global["warptorio_biter_wavemax"].value-erng,settings.global["warptorio_biter_wavemin"].value),1))<=1)then - local f=global.floor.main.host - f.set_multi_command{command={type=defines.command.attack_area, destination={0,0},radius=128}, unit_count=el} - end - end -end -events.on_tick(60,0,"biters",warptorio.BiterTick) - - ---[[ --- Old ability buttons -wderma.stabilizer=derma.GuiControl("warptorio_stabilizer","button") -function wderma.stabilizer:get(p) return derma.control(derma.getrow(p,2),self.name,self.type) end -function wderma.stabilizer:update(p) local r=self:get(p) r.caption={"warptorio.button_stabilizer"} end -function wderma.stabilizer:click(p) - if(game.tick<(global.ability_next or 0) or not research.has("warptorio-stabilizer"))then return end - warptorio.IncrementAbility(settings.global["warptorio_ability_timegain"].value,settings.global["warptorio_ability_cooldown"].value) - warptorio.raise_event("ability_used",{player=p,ability="stabilizer",use_num=global.ability_uses}) - game.forces["enemy"].evolution_factor=0 - global.pollution_amount = 1.25 - global.pollution_expansion = 1.5 - local f=warptorio.GetMainSurface() - f.clear_pollution() - if(global.warp_reactor and isvalid(global.warp_reactor))then f.set_multi_command{command={type=defines.command.flee, from=global.warp_reactor}, unit_count=1000, unit_search_distance=500} end - players.playsound("reactor-stabilized", f) - game.print("Warp Reactor Stabilized") -end - -wderma.accelerator=derma.GuiControl("warptorio_accelerator","button") -function wderma.accelerator:get(p) return derma.control(derma.getrow(p,2),self.name,self.type) end -function wderma.accelerator:update(p) local r=self:get(p) r.caption={"warptorio.button_accelerator"} end -function wderma.accelerator:click(p) - if(game.tick<(gwarptorio.ability_next or 0) or gwarptorio.warp_charge_time<=10)then return end - warptorio.IncrementAbility(settings.global["warptorio_ability_timegain"].value,settings.global["warptorio_ability_cooldown"].value) - warptorio.raise_event("ability_used",{player=p,ability="accelerator",use_num=gwarptorio.ability_uses}) - - gwarptorio.warp_charge_time=math.max(math.ceil(gwarptorio.warp_charge_time^0.75),10) - if(gwarptorio.warp_charging~=1)then warptorio.derma.charge_time() end --,gwarptorio.warp_charge_time*60) end - - local f=warptorio.GetMainSurface() - players.playsound("reactor-stabilized", f) - game.print("Warp Reactor Accelerated") -end - -wderma.radar=derma.GuiControl("warptorio_radar","button") -function wderma.radar:get(p) return derma.control(derma.getrow(p,2),self.name,self.type) end -function wderma.radar:update(p) local r=self:get(p) r.caption={"warptorio.button_radar"} end -function wderma.radar:click(p) - if(game.tick<(gwarptorio.ability_next or 0))then return end - warptorio.IncrementAbility(settings.global["warptorio_ability_timegain"].value/1.25,settings.global["warptorio_ability_cooldown"].value*0.6) - --warptorio.derma.radar() - local n=gwarptorio.radar_uses+1 gwarptorio.radar_uses=n - warptorio.raise_event("ability_used",{player=p,ability="radar",use_num=gwarptorio.ability_uses,radar_num=n}) - - local f=warptorio.GetMainSurface() - game.forces.player.chart(f,{lefttop={x=-64-128*n,y=-64-128*n},rightbottom={x=64+128*n,y=64+128*n}}) - players.playsound("reactor-stabilized", f) - game.print("Warp Reactor Scanner Sweep") -end -]] - - ---[[ Class Cache ]]-- - - - - - - -local tpCache={} -function tpCache.raise(obj,cls,entkey,pth,vi) - obj.cls=cls - obj.entkey=entkey - obj.pth=pth - obj.vi=vi -end -function tpCache.unraise(obj,b_noraise) - local gv=global[obj.cls][obj.entkey] - --gv:DestroyPointTeleporter(obj.vi) -end -function tpCache.create(e,ev) - cache.insert("power",e) -end -function tpCache.clone(e,ev) - local obj=cache.get_entity(ev.source) - if(obj)then - local gv=global[obj.cls][obj.entkey] - gv:DestroyPointSprites(obj.vi) - local nv=cache.force_entity(e,obj.cls,obj.entkey,obj.pth,obj.vi) - cache.destroy_entity(obj,true) - gv[nv.pth][nv.vi].ent=e - gv:CheckPointSprites(nv.vi) - - local gvoe=gv[nv.pth][nv.vi==1 and 2 or 1].ent - local gvoc=cache.get_entity(gvoe) - if(gvoc)then gvoc.teleport_dest=e nv.teleport_dest=gvoe end - if(gv:Data().circuit)then gv:ConnectCircuit() end - end -end -function tpCache.destroy(e,ev) - cache.remove("power",e) - local obj=cache.get_entity(e) - if(obj)then - local gv=global[obj.cls][obj.entkey] - --gv:DestroyPointTeleporter(obj.vi) - --gv:DestroyPointLogistics(obj.vi) - cache.destroy(obj) - end -end - -local tpgateCache=table.deepcopy(tpCache) -function tpgateCache.built(e,ev) - local obj=cache.force_entity(e,"Teleporters","offworld","points",2) - - if(obj)then - local ef=e.surface - local t=global.Teleporters["offworld"] - local gv=global[obj.cls][obj.entkey] - if(gv:ValidB())then entity.destroy(gv.points[2].ent) game.print("Max 1 Planet Teleporter Gate allowed at a time - built") end - - --if(ef~=warptorio.GetMainSurface())then game.print("Teleporter Logistics only functions on the Planet") return end - --[[if(ef.count_entities_filtered{area=t:GetLogisticsArea(e.position),collision_mask={"object-layer"}} >1)then - game.print("Unable to place teleporter logistics, something is in the way!") - - gv[obj.pth][obj.vi].ent=e - gv:CheckTeleporterPairs() - return - end]] - local gve=gv[obj.pth][obj.vi] - gve.ent=e - gv:CheckPointLogistics(2,e.position) - if(gve.energy)then e.energy=gve.energy gve.energy=nil end - gv:CheckTeleporterPairs() - end -end -function tpgateCache.destroy(e,ev) - cache.remove("power",e) - local obj=cache.get_entity(e) - if(obj)then - local gv=global[obj.cls][obj.entkey] - --gv:DestroyPointTeleporter(obj.vi) - gv:DestroyPointLogistics(obj.vi) - cache.destroy(obj) - end -end - - - -local tpharvCache=table.deepcopy(tpCache) - -function tpharvCache.destroy(e,ev) - cache.remove("power",e) - local obj=cache.get_entity(e) - if(obj and not obj.dead)then obj.dead=true - local gv=global[obj.cls][obj.entkey] - cache.destroy(obj) - gv:Recall() - end -end -tpharvCache.died=tpharvCache.destroy - -function tpharvCache.mined(e,ev) - local obj=cache.get_entity(e) - if(obj)then - local gv=global[obj.cls][obj.entkey] - for x,y in pairs(ev.buffer.get_contents())do ev.buffer.remove({name=x,count=y}) end - local cn=(gv:Data().pad_prototype .."-"..research.level("warptorio-harvester-"..obj.entkey)) - if(not ply or (ply and not ply.get_main_inventory().get_contents()[cn]))then ev.buffer.insert{name=cn,count=1} end - local hv=global.Harvesters[obj.entkey] - if(not hv.deployed)then hv:Recall() else hv:CheckTeleporterPairs() end - end -end - ---[[ -function tpharvCache.clone(e,ev) - local obj=cache.get_entity(ev.source) - if(obj)then - local gv=global[obj.cls][obj.entkey] - gv:DestroyPointSprites(obj.vi) - local nv=cache.force_entity(e,obj.cls,obj.entkey,obj.pth,obj.vi) - cache.destroy_entity(obj,true) - gv[nv.pth][nv.vi].ent=e - gv:CheckPointSprites(nv.vi) - - local gvoe=gv[nv.pth][nv.vi==1 and 2 or 1].ent - local gvoc=cache.get_entity(gvoe) - if(gvoc)then gvoc.teleport_dest=e nv.teleport_dest=gvoe end - if(gv:Data().circuit)then gv:ConnectCircuit() end - end -end -]] - -function tpharvCache.clone(e,ev) - local obj=cache.get_entity(ev.source) - if(obj)then - local gv=global[obj.cls][obj.entkey] - gv:DestroyPointSprites(obj.vi) - local ovi=(obj.vi==1 and 2 or 1) - - local nv=cache.force_entity(e,obj.cls,obj.entkey,obj.pth,ovi) - --cache.destroy_entity(obj,true) - --gv:DestroyPointTeleporter(obj.vi) - gv[nv.pth][ovi].ent=e - e.energy=0 - - local gvoe=gv[nv.pth][obj.vi].ent - local gvoc=cache.get_entity(gvoe) - if(gvoc)then gvoc.teleport_dest=e nv.teleport_dest=gvoe end - --gv:CheckTeleporterPairs() - end -end - - -local tppadWestCache={} -function tppadWestCache.built(e,ev) - local f=e.surface if(f~=warptorio.GetMainSurface())then return end - local pos=e.position - entity.destroy(e) - local hv=global.Harvesters["west"] if(hv)then hv:Deploy(f,pos) end -end -local tppadEastCache={} -function tppadEastCache.built(e,ev) - local f=e.surface if(f~=warptorio.GetMainSurface())then return end - local pos=e.position - entity.destroy(e) - local hv=global.Harvesters["east"] if(hv)then hv:Deploy(f,pos) end -end - - -for k,v in pairs{"warptorio-harvestportal","warptorio-harvestpad-west","warptorio-harvestpad-east"}do - for i=0,8,1 do cache.ent(v.."-"..i,tpharvCache) end -end -for i=0,8,1 do cache.ent("warptorio-harvestpad-west-"..i,tppadWestCache) end -for i=0,8,1 do cache.ent("warptorio-harvestpad-east-"..i,tppadEastCache) end - - - -cache.ent("warptorio-teleporter",tpCache) -cache.ent("warptorio-teleporter-gate",tpgateCache) -cache.ent("warptorio-underground",tpCache) -for i=0,8,1 do - cache.ent("warptorio-teleporter-gate-"..i,tpgateCache) - cache.ent("warptorio-teleporter-"..i,tpCache) - cache.ent("warptorio-underground-"..i,tpCache) -end - - -local loaderCache={} -function loaderCache.raise(obj,cls,entkey,pth,vi,vid) - obj.cls=cls - obj.entkey=entkey - obj.pth=pth - obj.vi=vi - obj.vid=vid -end -function loaderCache.unraise(obj) - local gv=global[obj.cls][obj.entkey] - --gv[obj.pth][obj.vi][obj.vid]=nil -end -function loaderCache.clone(e,ev) - local obj=cache.get_entity(ev.source) - if(obj)then - local gv=global[obj.cls][obj.entkey] - local nv=cache.force_entity(e,obj.cls,obj.entkey,obj.pth,obj.vi,obj.vid) - cache.destroy_entity(obj,true) - gv[nv.pth][nv.vi][nv.vid]=e - end -end -function loaderCache.destroy(e,ev) - local obj=cache.get_entity(e) - if(obj)then cache.destroy(obj) end -end -function loaderCache.rotate(e,ev) - local obj=cache.get_entity(e) - if(obj)then - local gv=global[obj.cls][obj.entkey] - if(obj.cls=="Rails")then - gv.dir=e.loader_type - gv:Rotate() - else - gv.dir[obj.vi][obj.vid]=e.loader_type - gv.dir[(obj.vi==1 and 2 or 1)][obj.vid]=string.opposite_loader[e.loader_type] - local de=gv.loaders[(obj.vi==1 and 2 or 1)][obj.vid] - if(isvalid(de))then de.loader_type=string.opposite_loader[e.loader_type] end - if(gv.chests)then gv:SwapLoaderChests(obj.vid) end - end - end -end -cache.ent("loader",loaderCache) -cache.ent("fast-loader",loaderCache) -cache.ent("express-loader",loaderCache) - - -local pipeCache={} -function pipeCache.raise(obj,cls,key,pth,vi,vid) - obj.cls=cls - obj.entkey=key - obj.pth=pth - obj.vi=vi - obj.vid=vid -end -function pipeCache.unraise(obj) - local gv=global[obj.cls][obj.entkey] - --gv[obj.pth][vi][vid]=nil -end -function pipeCache.clone(e,ev) - local obj=cache.get_entity(ev.source) - if(obj)then - local gv=global[obj.cls][obj.entkey] - local nv=cache.force_entity(e,obj.cls,obj.entkey,obj.pth,obj.vi,obj.vid) - cache.destroy_entity(obj,true) - gv[nv.pth][nv.vi][nv.vid]=e - end -end -function pipeCache.destroy(e,ev) - local obj=cache.get_entity(e) - if(obj)then cache.destroy(obj) end -end - -cache.ent("warptorio-logistics-pipe",pipeCache) - - -local gpipeCache={} -- Global pipe cache to clean warppipes - -function gpipeCache.destroy(e,ev) - for k,v in pairs(global.Teleporters)do v:CheckEmptyPipes() end -end -cache.type("pipe",gpipeCache) -cache.type("pipe-to-ground",gpipeCache) - - -local chestCache={} -function chestCache.raise(obj,cls,key,pth,vi,vid) - obj.cls=cls - obj.entkey=key - obj.pth=pth - obj.vi=vi - obj.vid=vid -end -function chestCache.unraise(obj) - --local gv=global[obj.cls][obj.entkey] - --gv[obj.pth][vi][vid]=nil -end -function chestCache.clone(e,ev) - local obj=cache.get_type("types",ev.source.type,ev.source) - if(obj)then - local gv=global[obj.cls][obj.entkey] - local nv=cache.get_raise_type("types",e.type,e,obj.cls,obj.entkey,obj.pth,obj.vi,obj.vid) - gv[nv.pth][nv.vi][nv.vid]=e - --cache.destroy(obj,true) - end -end - -function chestCache.destroy(e,ev) - local obj=cache.get_entity(e) - if(obj)then cache.destroy(obj) end -end - -cache.type("container",chestCache) -cache.type("logistic-container",chestCache) - - -local comboCache={} -function comboCache.raise(obj,cls,key,pth,vi) - obj.cls=cls - obj.entkey=key - obj.pth=pth - obj.vi=vi -end -function comboCache.unraise(obj) - local gv=global[obj.cls][obj.entkey] - --gv[obj.pth][vi][vid]=nil -end -function comboCache.clone(e,ev) - local obj=cache.get_entity(ev.source) - if(obj)then - local gv=global[obj.cls][obj.entkey] - local nv=cache.force_entity(e,obj.cls,obj.entkey,obj.pth,obj.vi) - cache.destroy_entity(obj,true) - gv[nv.pth][nv.vi]=e - end -end -function comboCache.destroy(e,ev) - local obj=cache.get_entity(e) - if(obj)then - local gv=global[obj.cls][obj.entkey] - --gv[obj.vi][obj.vid]=nil - cache.destroy_entity(obj) - end -end - -cache.ent("warptorio-alt-combinator",comboCache) - - --- string.opposite_loader[e.loader_type] -local warploader={} - -function warploader.dofilters(e) - local tp=e.loader_type - local lanes={e.get_transport_line(1),e.get_transport_line(2)} - for k,v in pairs(global.warploaders.outputf)do for i=1,2,1 do table.RemoveByValue(v,lanes[i]) end end - if(tp~="output")then --if(tp=="input")then - for i=1,2,1 do table.RemoveByValue(global.warploaders.output,lanes[i]) end - for i=1,2,1 do table.insertExclusive(global.warploaders.input,lanes[i]) end - else --if(tp=="output")then - local ct=global.warploaders.outputf - local hf=false - for i=1,5,1 do local f=e.get_filter(i) if(f)then hf=true - ct[f]=ct[f] or {} for a=1,2,1 do table.insertExclusive(ct[f],lanes[a]) end - end end - if(hf)then - for i=1,2,1 do table.RemoveByValue(global.warploaders.output,lanes[i]) end - else - for a=1,2,1 do table.insertExclusive(global.warploaders.output,lanes[a]) end - end - for a=1,2,1 do table.RemoveByValue(global.warploaders.input,lanes[a]) end - end -end -function warploader.built(e,ev) - global.warploaders=global.warploaders or {} - global.warploaders.input=global.warploaders.input or {} - global.warploaders.output=global.warploaders.output or {} - global.warploaders.outputf=global.warploaders.outputf or {} - global.warploaders.outputf_next=global.warploaders.outputf_next or {} - - warploader.dofilters(e) -end -function warploader.rotate(e,ev) - warploader.dofilters(e) -end - -function warploader.destroy(e,ev) - local obj=cache.get_entity(e) if(obj)then cache.destroy(obj) end - local un=e.unit_number - local tp=e.loader_type - local wpg=global.warploaders - local lanes={e.get_transport_line(1),e.get_transport_line(2)} - if(tp=="output")then - local hf=false for i=1,5,1 do if(e.get_filter(i))then hf=true break end end - if(hf)then for k,v in pairs(wpg.outputf)do for i=1,2,1 do table.RemoveByValue(v,lanes[i]) end end else - for i=1,2,1 do table.RemoveByValue(wpg.output,lanes[i]) end - end - else - for i=1,2,1 do table.RemoveByValue(wpg.input,lanes[i]) end - end -end -function warploader.settings_pasted(e) warploader.dofilters(e) end -function warploader.gui_closed(e) warploader.dofilters(e) end - -cache.ent("warptorio-warploader",warploader) - - -function warptorio.InsertWarpLane(cv,item_name) if(cv.can_insert_at_back())then cv.insert_at_back({name=item_name,count=1}) return true end return false end -function warptorio.NextWarploader(tbl,key) local k,v=next(tbl,key) if(not k and not v)then return next(tbl,nil) end return k,v end - -function warptorio.DistributeLoaderLine(line) local inv=line.get_contents() - for item_name,item_count in pairs(inv)do if(warptorio.OutputWarpLoader(item_name,item_count))then line.remove_item{name=item_name,count=1} return true end end -end -function warptorio.OutputWarpLoader(cv,c) - local wpg=global.warploaders - - local ins=false - if(wpg.outputf[cv])then - local wpfnext=wpg.outputf_next[cv] - local coutf=wpg.outputf[cv] - for k,v in pairs(coutf)do local rk,rv=warptorio.NextWarploader(coutf,wpfnext) wpfnext=rk if(rv and warptorio.InsertWarpLane(rv,cv))then ins=true break end end - wpg.outputf_next[cv]=wpfnext - if(ins)then return true end - end - local wpnext=wpg.output_next - local cout=wpg.output - for k,v in pairs(cout)do local rk,rv=warptorio.NextWarploader(cout,wpnext) wpnext=rk if(rv and warptorio.InsertWarpLane(rv,cv))then ins=true break end end - wpg.output_next=wpnext - if(ins)then return true end - return false -end - -function warptorio.TickWarploaders() - local wpg=global.warploaders if(not wpg)then return end - local k,line=warptorio.NextWarploader(wpg.input,wpg.input_next) - wpg.input_next=k - if(not isvalid(line))then return end - warptorio.DistributeLoaderLine(line) -end - -function warptorio.TickLogistics() - for nm,tpt in pairs(global.Teleporters)do - if(tpt.pipes)then if(type(tpt.pipes)=="boolean")then error(serpent.block(tpt)) end for vi,ve in pairs(tpt.pipes[1])do if(isvalid(ve))then - local vo=tpt.pipes[2][vi] - if(isvalid(vo))then entity.BalanceFluidPair(ve,vo) end - end end end - if(tpt.chests)then for vi,ve in pairs(tpt.chests[1])do if(isvalid(ve))then - local vo=tpt.chests[2][vi] - if(isvalid(vo))then - local vdir=tpt.dir[1][vi] - if(vdir=="input")then entity.ShiftContainer(ve,vo) else entity.ShiftContainer(vo,ve) end - end - end end end - end - for nm,tpt in pairs(global.Harvesters)do - for vi,ve in pairs(tpt.pipes[1])do if(isvalid(ve))then - local vo=tpt.pipes[2][vi] - if(isvalid(vo))then entity.BalanceFluidPair(ve,vo) end - end end - for vi,ve in pairs(tpt.loaders[1])do if(isvalid(ve))then - local vo=tpt.loaders[2][vi] - if(isvalid(vo))then - local vdir=tpt.dir[1][vi] - if(vdir=="input")then entity.ShiftBelt(ve,vo) else entity.ShiftBelt(vo,ve) end - end - end end - end - entity.AutoBalancePower(cache.get("power")) - entity.AutoBalanceHeat(cache.get("heat")) - if(global.warploaders)then for i=1,math.min(table_size(global.warploaders.input),10),1 do warptorio.TickWarploaders() end end -end -events.on_tick(1,0,"TickLogs",warptorio.TickLogistics) - +--[[ Todo list ]] -- + +--[[ +function warptorio.CountEntities() local c=0 for k,v in pairs(gwarptorio.floor)do if(v.surface and v.surface.valid and k~="main" and k~="home")then + c=c+table_size(v.surface.find_entities()) +end end return c end -- used in warpout + +function warptorio.BlueprintEntityIsBlacklisted(e) if(warptorio.EntityIsPlatform(e))then return true end return false end +function warptorio.on_player_setup_blueprint.generic(ev) + if(settings.global.warptorio_no_blueprint.value)then return end + local mp=ev.mapping if(not mp)then return end local bpe=mp.get() local ply=game.players[ev.player_index] + local cst=ply.blueprint_to_setup if(not cst or not cst.valid_for_read)then cst=ply.cursor_stack end if(not cst or not cst.valid_for_read)then return end + local ents=cst.get_blueprint_entities() + if(ents)then for k,v in pairs(ents)do if(warptorio.BlueprintEntityIsBlacklisted(bpe[v.entity_number]))then ents[k]=nil end end cst.set_blueprint_entities(ents) end +end + + +function warptorio.PlanetEntityIsPlatform(e) local r --=(e.name:sub(1,9)=="warptorio") if(r)then return true end + for k,v in pairs(gwarptorio.Rails)do if(table.HasValue(v.rails,e))then return true end end + for k,v in pairs{gwarptorio.Teleporters.offworld,gwarptorio.Teleporters.b1}do if(v:ManagesEntity(e))then return true end end +end +function warptorio.EntityIsPlatform(e) local r --=(e.name:sub(1,9)=="warptorio") if(r)then return true end + for k,v in pairs(gwarptorio.Rails)do if(v:ManagesEntity(e))then return true end end + for k,v in pairs(gwarptorio.Teleporters)do if(v:ManagesEntity(e))then return true end end + for k,v in pairs(gwarptorio.Harvesters)do if(v:ManagesEntity(e))then return true end end + for k,v in pairs(gwarptorio.floor)do if(v:ManagesEntity(e))then return true end end + return false +end +]] + +--[[ TODO + +function warptorio.MigrateTileFloor(floor,buildfunc) local f=floor.surface + vector.LayTiles("grass-1",f,vector.square(vector(-1,-1),vector(512,512))) + buildfunc() + local tcs={} + for k,v in pairs(f.find_tiles_filtered{name="grass-1"})do table.insert(tcs,{name="out-of-map",position=v.position}) end + f.set_tiles(tcs,true) +end +function warptorio.MigrateHarvesterFloor() + warptorio.BuildB3() + local rLogs=game.forces.player.technologies["warptorio-logistics-1"].researched + for k,v in pairs(storage.warptorio.Harvesters)do local f,pos v:DestroyLogs() + if(v.deployed)then f,pos=v.b.surface,v.deploy_position v:Recall() end + v:DestroyA() v:DestroyB() v:Warpin() if(rLogs)then v:SpawnLogs() end v:Upgrade() + end +end +function warptorio.MigrateTiles() if(warptorio.tilesAreMigrated)then return end warptorio.tilesAreMigrated = true + local flv=gwarptorio.floor.b1 if(flv)then warptorio.MigrateTileFloor(flv,warptorio.BuildB1) end + local flv=gwarptorio.floor.b2 if(flv)then warptorio.MigrateTileFloor(flv,warptorio.BuildB2) end + local flv=gwarptorio.floor.b3 if(flv)then warptorio.MigrateTileFloor(flv,warptorio.MigrateHarvesterFloor) end + warptorio.ValidateCache() + warptorio.BuildPlatform() +end + + + +function warptorio.init.floors(bhzd) + if(not gwarptorio.floor)then gwarptorio.floor={} end + local m=gwarptorio.floor.main if(not m)then m=new(FLOOR,"main",8) m.surface=game.surfaces["nauvis"] end + local m=gwarptorio.floor.b1 if(not m)then m=new(FLOOR,"b1",16) m:MakeEmptySurface() end + local m=gwarptorio.floor.b2 if(not m)then m=new(FLOOR,"b2",17) m:MakeEmptySurface() end + local m=gwarptorio.floor.b3 if(not m)then m=new(FLOOR,"b3",17) m.ovalsize={x=19,y=17} m:MakeEmptySurface() end + warptorio.BuildPlatform(bhzd) + warptorio.BuildB1(bhzd) + warptorio.BuildB2(bhzd) + warptorio.BuildB3(bhzd) +end +function warptorio.RebuildFloors(bhzd) warptorio.init.floors(bhzd) end + + +function warptorio.BuildHazards() warptorio.BuildPlatformHazard() warptorio.BuildB1Hazard() warptorio.BuildB2Hazard() warptorio.BuildB3Hazard() end + + + +function warptorio.BuildPlatformHazard() + +end + +function warptorio.BuildPlatform(bhzd) + + if(bhzd~=true)then warptorio.BuildPlatformHazard() end + + players.playsound("warp_in",f) +end + + +function warptorio.CheckReactor() + local m=gwarptorio.floor.main + local rlv=research.level("warptorio-reactor") -- gwarptorio.Research["reactor"] or 0 + if(rlv>=6 and (not gwarptorio.warp_reactor or not gwarptorio.warp_reactor.valid))then + local f=m.surface + vector.clean(f,vector.square(vector(-0.5,-0.5),vector(5,5))) + local e=f.create_entity{name="warptorio-reactor",position={-1,-1},force=game.forces.player,player=game.players[1]} + vector.cleanplayers(f,vector.square(vector(-0.5,-0.5),vector(5,5))) + gwarptorio.warp_reactor=e + e.minable=false + end +end + + + + +]] -- + + + + +--[[ Settings ]] -- +function warptorio.setting(n) return settings.global["warptorio_" .. n].value end + +warptorio.settings = {} +local setter = warptorio.settings + +function setter.warptorio_autowarp_disable() warptorio.ResetHUD() end + +function setter.warptorio_autowarp_always() warptorio.ResetHUD() end + +function setter.warptorio_water() warptorio.EarlyWater(settings.global["warptorio_water"].value) end + +function setter.warptorio_carebear() warptorio.Carebear(settings.global["warptorio_carebear"].value) end + +function setter.warptorio_solar_multiplier() + warptorio.SolarMultiplier(settings.global["warptorio_solar_multiplier"] + .value) +end + +function setter.warptorio_loaderchest_provider() warptorio.LoaderChestChanged(true) end + +function setter.warptorio_loaderchest_requester() warptorio.LoaderChestChanged(false) end + +function setter.warptorio_loader_top() warptorio.LoaderSideChanged(true) end + +function setter.warptorio_loader_bottom() warptorio.LoaderSideChanged(false) end + +function setter.warptorio_combinator_offset() warptorio.CombinatorOffsetChanged() end + +function setter.warptorio_hide_sprites() + for k, v in pairs(storage.Teleporters) do + v:CheckPointSprites(1) + v:CheckPointSprites(2) + end +end + +function warptorio.CombinatorOffsetChanged() + for k, v in pairs(storage.Harvesters) do + v:DestroyCombos() + v:CheckCombo() + end +end + +function warptorio.LoaderChestChanged(bprovider) +end + +function warptorio.LoaderSideChanged(btop) + for k, v in pairs(storage.Teleporters) do + local g = v:Data().top + if ((btop and g) or (not btop and not g)) then + v:DestroyPointLogistics(1) + v:DestroyPointLogistics(2) + v:CheckTeleporterPairs(true) + end + end +end + +function warptorio.SolarMultiplier(x) + for k, v in pairs(warptorio.GetPlatformSurfaces()) do v.solar_power_multiplier = x end +end + +warptorio.carebearItems = { + ["stone"] = 20, + ["coal"] = 20, + ["iron-plate"] = 20, + ["copper-plate"] = 20, + ["electronic-circuit"] = 10, + ["iron-gear-wheel"] = 10, + ["wooden-chest"] = 4, + ["transport-belt"] = 10, + ["underground-belt"] = 2, + ["splitter"] = 1, + ["burner-mining-drill"] = 2, + ["assembling-machine-1"] = 2, + ["small-electric-pole"] = 5, + ["steam-engine"] = 1, + ["boiler"] = 1, + ["gun-turret"] = 4, + ["uranium-rounds-magazine"] = 50, + ["piercing-rounds-magazine"] = 200, + ["firearm-magazine"] = 400, +} +function warptorio.Carebear(b) + if (b and not storage.carebear) then + storage.carebear = true + local e = storage.floor.main.host.create_entity { name = "warptorio-carebear-chest", position = { -1, -1 }, force = game.forces.player } + local inv = e.get_inventory(defines.inventory.chest) + for k, v in pairs(warptorio.carebearItems) do inv.insert { name = k, count = v } end + end +end + +function warptorio.EarlyWater(b) + if (b and not storage.earlywater) then + storage.earlywater = true + game.forces.player.technologies["warptorio-boiler-water-1"].researched = true + end +end + +function warptorio.OnModSettingChanged(ev) + local p = ev.player_index + local s = ev.setting + local st = ev.setting_type + if (warptorio.settings[s]) then warptorio.settings[s](ev) end +end + +script.on_event(defines.events.on_runtime_mod_setting_changed, warptorio.OnModSettingChanged) + + +function warptorio.IsAutowarpEnabled() + return warptorio.setting("autowarp_disable") ~= true and + (not research.has("warptorio-reactor-6") or warptorio.setting("autowarp_always")) +end + +function warptorio.HookNewGamePlus() + if (remote.interfaces["newgameplus"]) then + if (not warptorio.newgameplus) then + warptorio.newgameplus = true + local ngp = remote.call("newgameplus", "get_on_technology_reset_event") + if (ngp) then script.on_event(ngp, warptorio.OnPreNewGame) end + local ngp = remote.call("newgameplus", "get_on_post_new_game_plus_event") + if (ngp) then script.on_event(ngp, warptorio.OnPostNewGame) end + end + end +end + +--[[ Loot Chest ]] -- + + +warptorio.LootItems = { + ["roboport"] = 4, + ["construction-robot"] = 10, + ["logistic-robot"] = 20, + ["passive-provider-chest"] = 10, + ["requester-chest"] = 10, + ["buffer-chest"] = 10, + ["wooden-chest"] = 20, + ["iron-chest"] = 20, + ["steel-chest"] = 20, + ["storage-tank"] = 10, + ["wood"] = 100, + ["stone"] = 100, + ["iron-plate"] = 400, + ["iron-gear-wheel"] = 300, + ["steel-plate"] = 200, + ["copper-plate"] = 300, + ["copper-cable"] = 400, + ["electronic-circuit"] = 200, + ["advanced-circuit"] = 100, + ["processing-unit"] = 50, + ["big-electric-pole"] = 25, + ["medium-electric-pole"] = 25, + ["small-electric-pole"] = 25, + ["substation"] = 15, + ["landfill"] = 100, + ["pipe"] = 200, + ["pipe-to-ground"] = 50, + ["express-transport-belt"] = 100, + ["fast-transport-belt"] = 200, + ["transport-belt"] = 300, + ["express-underground-belt"] = 15, + ["fast-underground-belt"] = 20, + ["underground-belt"] = 25, + ["accumulator"] = 10, + ["steam-engine"] = 10, + ["nuclear-reactor"] = 2, + ["heat-exchanger"] = 10, + ["heat-pipe"] = 25, + ["steam-turbine"] = 10, + ["chemical-plant"] = 10, + ["assembling-machine-1"] = 15, + ["assembling-machine-2"] = 15, + ["assembling-machine-3"] = 15, + ["inserter"] = 30, + ["fast-inserter"] = 20, + ["bulk-inserter"] = 15, + ["warptorio-atomic-bomb"] = 1, + ["warptorio-warponium-fuel-cell"] = 2, + ["warptorio-warponium-fuel"] = 1, + ["gun-turret"] = 10, + ["uranium-rounds-magazine"] = 100, + ["firearm-magazine"] = 400, + ["piercing-rounds-magazine"] = 200, + ["atomic-bomb"] = 2, +} + +function warptorio.GetPossibleLoot() + local lt = {} + for k, v in pairs(warptorio.LootItems) do + local r = game.forces.player.recipes[k] + if (not r or (r and r.enabled == true)) then lt[k] = v end + end + return lt +end + +function warptorio.LootTable(mn, mx, cDist, cStack) + local lt = warptorio.GetPossibleLoot() + local t, u, k, vDist, vStack = {} + for i = 1, math.random(mn or 1, mx or 5), 1 do + u, k = table.Random(lt) + vDist, vStack = math.min((cDist or 850) / 1700, 1), math.random((cStack or 20), 100) / 100 + t[k] = math.max(math.ceil(u * vDist * vStack), 1) + end + return t +end + +function warptorio.SpawnLootChest(f, pos, varg) + pos = vector(pos) + varg = varg or {} + local e = f.create_entity { name = "warptorio-lootchest", position = pos, force = game.forces.player, raise_built = true } + if (not isvalid(e)) then return false end + local lt = warptorio.LootTable(varg.min or 1, varg.max or 5, varg.dist or vector.length(pos), varg.stack or 20) + local inv = e.get_inventory(defines.inventory.chest) + for k, v in pairs(lt) do inv.insert { name = k, count = v } end + return e +end + +function warptorio.ChunkLootChest(ev) + if (settings.global["warptorio_no_lootchest"].value == true or math.random(1, settings.global["warptorio_lootchest_chance"].value) > 1) then return end + local f = ev.surface + if (not (f.name == "nauvis" or f == warptorio.GetMainSurface())) then return end + local a = ev.area + local x, y = math.random(a.left_top.x, a.right_bottom.x), math.random(a.left_top.y, a.right_bottom.y) + local dist = math.sqrt(math.abs(x ^ 2) + math.abs(y ^ 2)) + if (dist >= settings.global["warptorio_lootchest_distance"].value) then + warptorio.SpawnLootChest(f, { x, y }) + end +end + +events.on_event(defines.events.on_chunk_generated, warptorio.ChunkLootChest) + + + +--[[ Tick Functions ]] -- + + +function warptorio.ClockTick(tick) + local donewarp = false + if (storage.warp_charging == 1) then + storage.warp_time_left = (60 * storage.warp_charge_time) - (tick - storage.warp_charge_start_tick) + if (storage.warp_time_left <= 0) then + warptorio.Warpout() + donewarp = true + end + end + storage.time_passed = tick - storage.warp_last + --gui.time_passed() + --gui.charge_time() + + if (not donewarp and warptorio.IsAutowarpEnabled()) then + storage.warp_auto_end = (60 * storage.warp_auto_time) - (tick - storage.warp_last) + if (storage.warp_auto_end <= 0) then + warptorio.Warpout() + donewarp = true + end + end + + cache.updatemenu("hud", "clocktick") + --gui.autowarp() + --gui if(research.has("warptorio-charting") or research.has("warptorio-accelerator") or research.has("warptorio-stabilizer"))then warptorio.derma.cooldown() end + --gui if(storage.homeworld)then warptorio.derma.homeworld() end + + warptorio.RefreshWarpCombinators() + + + --events.vraise("ticktime",{warp_left=storage.warp_time_left,auto_left=warptorio.IsAutowarpEnabled() and storage.warp_auto_end or false, donewarp=donewarp}) +end + +events.on_tick(60, 0, "clock", warptorio.ClockTick) + + +function warptorio.ChargeCountdownTick(tick) + if (storage.warp_charging < 1 and storage.warp_charge_time > 30) then + local r = (780) - (research.level("warptorio-reactor") * 60) + if (tick % r == 0) then storage.warp_charge_time = math.max(storage.warp_charge_time - 1, 30) end -- 60t*13s=780t + end +end + +events.on_tick(60, 0, "charge_countdown", warptorio.ChargeCountdownTick) + +function warptorio.WarpAlarmTick(tick) + if ((storage.warp_charging == 1 and storage.warp_time_left <= 3600) or (warptorio.IsAutowarpEnabled() and storage.warp_auto_end <= 3600)) then + players.playsound("warp_alarm") + end +end + +events.on_tick(120, 1, "warpalarm", warptorio.WarpAlarmTick) + +function warptorio.PollutionTick(tick) + if (tick % (warptorio.setting("pollution_tickrate") * 60) ~= 0) then return end + local f = warptorio.GetMainSurface() + if (not isvalid(f)) then return end + local stb = storage.abilities.stabilizing + local vpol = 0 + if (warptorio.setting("pollution_disable") ~= true) then + vpol = storage.pollution_amount + storage.pollution_amount = math.min( + vpol + (vpol ^ warptorio.setting("pollution_exponent")) * + (stb and 0.05 or warptorio.setting("pollution_multiplier")), 1000000) + end + + for k, v in pairs(warptorio.GetPlatformSurfaces()) do + vpol = vpol + v.get_total_pollution() + v.clear_pollution() + end + if (vpol > 0) then + f.pollute({ -1, -1 }, vpol * (stb and 0.05 or 1)) -- todo; pollute to teleporters and harvesters *0.125 + end +end + +events.on_tick(60, 0, "pollution", warptorio.PollutionTick) + +events.on_tick(60, 0, "radar_ability", function(tick) + local rdr = storage.abilities.scanning + if (not rdr) then return end + local rdrt = storage.abilities.scantick or 0 + local rdrg = storage.abilities.scanzone or 0 + rdrt = rdrt + 1 + storage.abilities.scantick = rdrt + if (rdrt < 3 + rdrg) then return end + rdrt = 0 + storage.abilities.scantick = 0 + + + storage.abilities.scanzone = rdrg + 1 + local f = warptorio.GetMainSurface() + game.forces.player.chart(f, + { lefttop = { x = -64 - 32 * rdrg, y = -64 - 32 * rdrg }, rightbottom = { x = 64 + 32 * rdrg, y = 64 + 32 * rdrg } }) + players.playsound("reactor-stabilized", f) +end) + + +function warptorio.BiterTick(tick) + if (warptorio.setting("biter_wave_disable") == true or tick % (warptorio.setting("pollution_tickrate") * 60) ~= 0) then return end + storage.pollution_expansion = math.min( + storage.pollution_expansion * settings.global["warptorio_biter_expansion"].value, + 60 * 60 * settings.global["warptorio_biter_redux"].value) + game.map_settings.enemy_expansion.min_expansion_cooldown = math.max( + (60 * 60 * settings.global["warptorio_biter_min"].value) - storage.pollution_expansion, 60 * 60 * 1) + game.map_settings.enemy_expansion.max_expansion_cooldown = math.max( + ((60 * 60 * settings.global["warptorio_biter_max"].value) - storage.pollution_expansion) + 1, 60 * 60 * 1) + --game.print("pol: " .. game.map_settings.enemy_expansion.min_expansion_cooldown) + local pt = (storage.time_passed / 60) / 60 + if (pt > settings.global["warptorio_biter_wavestart"].value) then + pt = pt - settings.global["warptorio_biter_wavestart"].value + local el = math.ceil(pt * settings.global["warptorio_biter_wavesize"].value) + local erng = math.ceil(pt * settings.global["warptorio_biter_waverng"].value) + local bmax = settings.global["warptorio_biter_wavesizemax"].value + if (bmax > 0) then el = math.min(el, bmax) end + if (math.random(1, math.max(math.min(settings.global["warptorio_biter_wavemax"].value - erng, settings.global["warptorio_biter_wavemin"].value), 1)) <= 1) then + local f = storage.floor.main.host + f.set_multi_command { command = { type = defines.command.attack_area, destination = { 0, 0 }, radius = 128 }, unit_count = el } + end + end +end + +events.on_tick(60, 0, "biters", warptorio.BiterTick) + + +--[[ +-- Old ability buttons +wderma.stabilizer=derma.GuiControl("warptorio_stabilizer","button") +function wderma.stabilizer:get(p) return derma.control(derma.getrow(p,2),self.name,self.type) end +function wderma.stabilizer:update(p) local r=self:get(p) r.caption={"warptorio.button_stabilizer"} end +function wderma.stabilizer:click(p) + if(game.tick<(storage.ability_next or 0) or not research.has("warptorio-stabilizer"))then return end + warptorio.IncrementAbility(settings.global["warptorio_ability_timegain"].value,settings.global["warptorio_ability_cooldown"].value) + warptorio.raise_event("ability_used",{player=p,ability="stabilizer",use_num=storage.ability_uses}) + game.forces["enemy"].evolution_factor=0 + storage.pollution_amount = 1.25 + storage.pollution_expansion = 1.5 + local f=warptorio.GetMainSurface() + f.clear_pollution() + if(storage.warp_reactor and isvalid(storage.warp_reactor))then f.set_multi_command{command={type=defines.command.flee, from=storage.warp_reactor}, unit_count=1000, unit_search_distance=500} end + players.playsound("reactor-stabilized", f) + game.print("Warp Reactor Stabilized") +end + +wderma.accelerator=derma.GuiControl("warptorio_accelerator","button") +function wderma.accelerator:get(p) return derma.control(derma.getrow(p,2),self.name,self.type) end +function wderma.accelerator:update(p) local r=self:get(p) r.caption={"warptorio.button_accelerator"} end +function wderma.accelerator:click(p) + if(game.tick<(gwarptorio.ability_next or 0) or gwarptorio.warp_charge_time<=10)then return end + warptorio.IncrementAbility(settings.global["warptorio_ability_timegain"].value,settings.global["warptorio_ability_cooldown"].value) + warptorio.raise_event("ability_used",{player=p,ability="accelerator",use_num=gwarptorio.ability_uses}) + + gwarptorio.warp_charge_time=math.max(math.ceil(gwarptorio.warp_charge_time^0.75),10) + if(gwarptorio.warp_charging~=1)then warptorio.derma.charge_time() end --,gwarptorio.warp_charge_time*60) end + + local f=warptorio.GetMainSurface() + players.playsound("reactor-stabilized", f) + game.print("Warp Reactor Accelerated") +end + +wderma.radar=derma.GuiControl("warptorio_radar","button") +function wderma.radar:get(p) return derma.control(derma.getrow(p,2),self.name,self.type) end +function wderma.radar:update(p) local r=self:get(p) r.caption={"warptorio.button_radar"} end +function wderma.radar:click(p) + if(game.tick<(gwarptorio.ability_next or 0))then return end + warptorio.IncrementAbility(settings.global["warptorio_ability_timegain"].value/1.25,settings.global["warptorio_ability_cooldown"].value*0.6) + --warptorio.derma.radar() + local n=gwarptorio.radar_uses+1 gwarptorio.radar_uses=n + warptorio.raise_event("ability_used",{player=p,ability="radar",use_num=gwarptorio.ability_uses,radar_num=n}) + + local f=warptorio.GetMainSurface() + game.forces.player.chart(f,{lefttop={x=-64-128*n,y=-64-128*n},rightbottom={x=64+128*n,y=64+128*n}}) + players.playsound("reactor-stabilized", f) + game.print("Warp Reactor Scanner Sweep") +end +]] + + +--[[ Class Cache ]] -- + + +local tpCache = {} +function tpCache.raise(obj, cls, entkey, pth, vi) + obj.cls = cls + obj.entkey = entkey + obj.pth = pth + obj.vi = vi +end + +function tpCache.unraise(obj, b_noraise) + local gv = storage[obj.cls][obj.entkey] + --gv:DestroyPointTeleporter(obj.vi) +end + +function tpCache.create(e, ev) + cache.insert("power", e) +end + +function tpCache.clone(e, ev) + local obj = cache.get_entity(ev.source) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + gv:DestroyPointSprites(obj.vi) + local nv = cache.force_entity(e, obj.cls, obj.entkey, obj.pth, obj.vi) + cache.destroy_entity(obj, true) + gv[nv.pth][nv.vi].ent = e + gv:CheckPointSprites(nv.vi) + + local gvoe = gv[nv.pth][nv.vi == 1 and 2 or 1].ent + local gvoc = cache.get_entity(gvoe) + if (gvoc) then + gvoc.teleport_dest = e + nv.teleport_dest = gvoe + end + if (gv:Data().circuit) then gv:ConnectCircuit() end + end +end + +function tpCache.destroy(e, ev) + cache.remove("power", e) + local obj = cache.get_entity(e) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + --gv:DestroyPointTeleporter(obj.vi) + --gv:DestroyPointLogistics(obj.vi) + cache.destroy(obj) + end +end + +local tpgateCache = table.deepcopy(tpCache) +function tpgateCache.built(e, ev) + local obj = cache.force_entity(e, "Teleporters", "offworld", "points", 2) + + if (obj) then + local ef = e.surface + local t = storage.Teleporters["offworld"] + local gv = storage[obj.cls][obj.entkey] + if (gv:ValidB()) then + entity.destroy(gv.points[2].ent) + game.print({ "warptorio.max-one-teleporter-error" }) + end + + --if(ef~=warptorio.GetMainSurface())then game.print("Teleporter Logistics only functions on the Planet") return end + --[[if(ef.count_entities_filtered{area=t:GetLogisticsArea(e.position),collision_mask={"object-layer"}} >1)then + game.print("Unable to place teleporter logistics, something is in the way!") + + gv[obj.pth][obj.vi].ent=e + gv:CheckTeleporterPairs() + return + end]] + local gve = gv[obj.pth][obj.vi] + gve.ent = e + gv:CheckPointLogistics(2, e.position) + if (gve.energy) then + e.energy = gve.energy + gve.energy = nil + end + gv:CheckTeleporterPairs() + end +end + +function tpgateCache.destroy(e, ev) + cache.remove("power", e) + local obj = cache.get_entity(e) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + --gv:DestroyPointTeleporter(obj.vi) + gv:DestroyPointLogistics(obj.vi) + cache.destroy(obj) + end +end + +local tpharvCache = table.deepcopy(tpCache) + +function tpharvCache.destroy(e, ev) + cache.remove("power", e) + local obj = cache.get_entity(e) + if (obj and not obj.dead) then + obj.dead = true + local gv = storage[obj.cls][obj.entkey] + cache.destroy(obj) + gv:Recall() + end +end + +tpharvCache.died = tpharvCache.destroy + +function tpharvCache.mined(e, ev) + local obj = cache.get_entity(e) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + for x, y in pairs(ev.buffer.get_contents()) do ev.buffer.remove({ name = y.name, count = y.count }) end + local cn = (gv:Data().pad_prototype .. "-" .. research.level("warptorio-harvester-" .. obj.entkey)) + if (not ply or (ply and not ply.get_main_inventory().get_contents()[cn])) then ev.buffer.insert { name = cn, count = 1 } end + local hv = storage.Harvesters[obj.entkey] + if (not hv.deployed) then hv:Recall() else hv:CheckTeleporterPairs() end + end +end + +--[[ +function tpharvCache.clone(e,ev) + local obj=cache.get_entity(ev.source) + if(obj)then + local gv=storage[obj.cls][obj.entkey] + gv:DestroyPointSprites(obj.vi) + local nv=cache.force_entity(e,obj.cls,obj.entkey,obj.pth,obj.vi) + cache.destroy_entity(obj,true) + gv[nv.pth][nv.vi].ent=e + gv:CheckPointSprites(nv.vi) + + local gvoe=gv[nv.pth][nv.vi==1 and 2 or 1].ent + local gvoc=cache.get_entity(gvoe) + if(gvoc)then gvoc.teleport_dest=e nv.teleport_dest=gvoe end + if(gv:Data().circuit)then gv:ConnectCircuit() end + end +end +]] + +function tpharvCache.clone(e, ev) + local obj = cache.get_entity(ev.source) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + gv:DestroyPointSprites(obj.vi) + local ovi = (obj.vi == 1 and 2 or 1) + + local nv = cache.force_entity(e, obj.cls, obj.entkey, obj.pth, ovi) + --cache.destroy_entity(obj,true) + --gv:DestroyPointTeleporter(obj.vi) + gv[nv.pth][ovi].ent = e + e.energy = 0 + + local gvoe = gv[nv.pth][obj.vi].ent + local gvoc = cache.get_entity(gvoe) + if (gvoc) then + gvoc.teleport_dest = e + nv.teleport_dest = gvoe + end + --gv:CheckTeleporterPairs() + end +end + +local tppadWestCache = {} +function tppadWestCache.built(e, ev) + local f = e.surface + if (f ~= warptorio.GetMainSurface()) then return end + local pos = e.position + entity.destroy(e) + local hv = storage.Harvesters["west"] + if (hv) then hv:Deploy(f, pos) end +end + +local tppadEastCache = {} +function tppadEastCache.built(e, ev) + local f = e.surface + if (f ~= warptorio.GetMainSurface()) then return end + local pos = e.position + entity.destroy(e) + local hv = storage.Harvesters["east"] + if (hv) then hv:Deploy(f, pos) end +end + +for k, v in pairs { "warptorio-harvestportal", "warptorio-harvestpad-west", "warptorio-harvestpad-east" } do + for i = 0, 8, 1 do cache.ent(v .. "-" .. i, tpharvCache) end +end +for i = 0, 8, 1 do cache.ent("warptorio-harvestpad-west-" .. i, tppadWestCache) end +for i = 0, 8, 1 do cache.ent("warptorio-harvestpad-east-" .. i, tppadEastCache) end + + + +cache.ent("warptorio-teleporter", tpCache) +cache.ent("warptorio-teleporter-gate", tpgateCache) +cache.ent("warptorio-underground", tpCache) +for i = 0, 8, 1 do + cache.ent("warptorio-teleporter-gate-" .. i, tpgateCache) + cache.ent("warptorio-teleporter-" .. i, tpCache) + cache.ent("warptorio-underground-" .. i, tpCache) +end + + +local loaderCache = {} +function loaderCache.raise(obj, cls, entkey, pth, vi, vid) + obj.cls = cls + obj.entkey = entkey + obj.pth = pth + obj.vi = vi + obj.vid = vid +end + +function loaderCache.unraise(obj) + local gv = storage[obj.cls][obj.entkey] + --gv[obj.pth][obj.vi][obj.vid]=nil +end + +function loaderCache.clone(e, ev) + local obj = cache.get_entity(ev.source) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + local nv = cache.force_entity(e, obj.cls, obj.entkey, obj.pth, obj.vi, obj.vid) + cache.destroy_entity(obj, true) + gv[nv.pth][nv.vi][nv.vid] = e + end +end + +function loaderCache.destroy(e, ev) + local obj = cache.get_entity(e) + if (obj) then cache.destroy(obj) end +end + +function loaderCache.rotate(e, ev) + local obj = cache.get_entity(e) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + if (obj.cls == "Rails") then + gv.dir = e.loader_type + gv:Rotate() + else + gv.dir[obj.vi][obj.vid] = e.loader_type + gv.dir[(obj.vi == 1 and 2 or 1)][obj.vid] = string.opposite_loader[e.loader_type] + local de = gv.loaders[(obj.vi == 1 and 2 or 1)][obj.vid] + if (isvalid(de)) then de.loader_type = string.opposite_loader[e.loader_type] end + if (gv.chests) then gv:SwapLoaderChests(obj.vid) end + end + end +end + +cache.ent("loader", loaderCache) +cache.ent("fast-loader", loaderCache) +cache.ent("express-loader", loaderCache) + + +local pipeCache = {} +function pipeCache.raise(obj, cls, key, pth, vi, vid) + obj.cls = cls + obj.entkey = key + obj.pth = pth + obj.vi = vi + obj.vid = vid +end + +function pipeCache.unraise(obj) + local gv = storage[obj.cls][obj.entkey] + --gv[obj.pth][vi][vid]=nil +end + +function pipeCache.clone(e, ev) + local obj = cache.get_entity(ev.source) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + local nv = cache.force_entity(e, obj.cls, obj.entkey, obj.pth, obj.vi, obj.vid) + cache.destroy_entity(obj, true) + gv[nv.pth][nv.vi][nv.vid] = e + end +end + +function pipeCache.destroy(e, ev) + local obj = cache.get_entity(e) + if (obj) then cache.destroy(obj) end +end + +cache.ent("warptorio-logistics-pipe", pipeCache) + + +local gpipeCache = {} -- Global pipe cache to clean warppipes + +function gpipeCache.destroy(e, ev) + for k, v in pairs(storage.Teleporters) do v:CheckEmptyPipes() end +end + +cache.type("pipe", gpipeCache) +cache.type("pipe-to-ground", gpipeCache) + + +local chestCache = {} +function chestCache.raise(obj, cls, key, pth, vi, vid) + obj.cls = cls + obj.entkey = key + obj.pth = pth + obj.vi = vi + obj.vid = vid +end + +function chestCache.unraise(obj) + --local gv=storage[obj.cls][obj.entkey] + --gv[obj.pth][vi][vid]=nil +end + +function chestCache.clone(e, ev) + local obj = cache.get_type("types", ev.source.type, ev.source) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + local nv = cache.get_raise_type("types", e.type, e, obj.cls, obj.entkey, obj.pth, obj.vi, obj.vid) + gv[nv.pth][nv.vi][nv.vid] = e + --cache.destroy(obj,true) + end +end + +function chestCache.destroy(e, ev) + local obj = cache.get_entity(e) + if (obj) then cache.destroy(obj) end +end + +cache.type("container", chestCache) +cache.type("logistic-container", chestCache) + + +local comboCache = {} +function comboCache.raise(obj, cls, key, pth, vi) + obj.cls = cls + obj.entkey = key + obj.pth = pth + obj.vi = vi +end + +function comboCache.unraise(obj) + local gv = storage[obj.cls][obj.entkey] + --gv[obj.pth][vi][vid]=nil +end + +function comboCache.clone(e, ev) + local obj = cache.get_entity(ev.source) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + local nv = cache.force_entity(e, obj.cls, obj.entkey, obj.pth, obj.vi) + cache.destroy_entity(obj, true) + gv[nv.pth][nv.vi] = e + end +end + +function comboCache.destroy(e, ev) + local obj = cache.get_entity(e) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + --gv[obj.vi][obj.vid]=nil + cache.destroy_entity(obj) + end +end + +cache.ent("warptorio-alt-combinator", comboCache) + + +-- string.opposite_loader[e.loader_type] +local warploader = {} + +function warploader.dofilters(e) + local tp = e.loader_type + local lanes = { e.get_transport_line(1), e.get_transport_line(2) } + for k, v in pairs(storage.warploaders.outputf) do for i = 1, 2, 1 do table.RemoveByValue(v, lanes[i]) end end + if (tp ~= "output") then --if(tp=="input")then + for i = 1, 2, 1 do table.RemoveByValue(storage.warploaders.output, lanes[i]) end + for i = 1, 2, 1 do table.insertExclusive(storage.warploaders.input, lanes[i]) end + else --if(tp=="output")then + local ct = storage.warploaders.outputf + local hf = false + for i = 1, 5, 1 do + local f = e.get_filter(i) + if (f) then + hf = true + ct[f] = ct[f] or {} + for a = 1, 2, 1 do table.insertExclusive(ct[f], lanes[a]) end + end + end + if (hf) then + for i = 1, 2, 1 do table.RemoveByValue(storage.warploaders.output, lanes[i]) end + else + for a = 1, 2, 1 do table.insertExclusive(storage.warploaders.output, lanes[a]) end + end + for a = 1, 2, 1 do table.RemoveByValue(storage.warploaders.input, lanes[a]) end + end +end + +function warploader.built(e, ev) + storage.warploaders = storage.warploaders or {} + storage.warploaders.input = storage.warploaders.input or {} + storage.warploaders.output = storage.warploaders.output or {} + storage.warploaders.outputf = storage.warploaders.outputf or {} + storage.warploaders.outputf_next = storage.warploaders.outputf_next or {} + + warploader.dofilters(e) +end + +function warploader.rotate(e, ev) + warploader.dofilters(e) +end + +function warploader.destroy(e, ev) + local obj = cache.get_entity(e) + if (obj) then cache.destroy(obj) end + local un = e.unit_number + local tp = e.loader_type + local wpg = storage.warploaders + local lanes = { e.get_transport_line(1), e.get_transport_line(2) } + if (tp == "output") then + local hf = false + for i = 1, 5, 1 do + if (e.get_filter(i)) then + hf = true + break + end + end + if (hf) then + for k, v in pairs(wpg.outputf) do for i = 1, 2, 1 do table.RemoveByValue(v, lanes[i]) end end + else + for i = 1, 2, 1 do table.RemoveByValue(wpg.output, lanes[i]) end + end + else + for i = 1, 2, 1 do table.RemoveByValue(wpg.input, lanes[i]) end + end +end + +function warploader.settings_pasted(e) warploader.dofilters(e) end + +function warploader.gui_closed(e) warploader.dofilters(e) end + +cache.ent("warptorio-warploader", warploader) + +function warptorio.InsertWarpLane(cv, item_name) + if (cv.can_insert_at_back()) then + cv.insert_at_back({ name = item_name, count = 1 }) + return true + end + return false +end + +function warptorio.NextWarploader(tbl, key) + local k, v = next(tbl, key) + if (not k and not v) then + return next(tbl, nil) + end + return k, v +end + +function warptorio.DistributeLoaderLine(line) + local inv = line.get_contents() + for item_name, item_count in pairs(inv) do + if (warptorio.OutputWarpLoader(item_count.name, item_count.count)) then + line.remove_item { name = item_count.name, count = 1 } + return true + end + end +end + +function warptorio.OutputWarpLoader(cv, c) + local wpg = storage.warploaders + + local ins = false + if (wpg.outputf[cv]) then + local wpfnext = wpg.outputf_next[cv] + local coutf = wpg.outputf[cv] + for k, v in pairs(coutf) do + local rk, rv = warptorio.NextWarploader(coutf, wpfnext) + wpfnext = rk + if (rv and warptorio.InsertWarpLane(rv, cv)) then + ins = true + break + end + end + wpg.outputf_next[cv] = wpfnext + if (ins) then return true end + end + local wpnext = wpg.output_next + local cout = wpg.output + for k, v in pairs(cout) do + local rk, rv = warptorio.NextWarploader(cout, wpnext) + wpnext = rk + if (rv and warptorio.InsertWarpLane(rv, cv)) then + ins = true + break + end + end + wpg.output_next = wpnext + if (ins) then return true end + return false +end + +function warptorio.TickWarploaders() + local wpg = storage.warploaders + if (not wpg) then return end + local k, line = warptorio.NextWarploader(wpg.input, wpg.input_next) + wpg.input_next = k + if (not isvalid(line)) then return end + warptorio.DistributeLoaderLine(line) +end + +function warptorio.TickLogistics() + for nm, tpt in pairs(storage.Teleporters) do + if (tpt.pipes) then + if (type(tpt.pipes) == "boolean") then error(serpent.block(tpt)) end + for vi, ve in pairs(tpt.pipes[1]) do + if (isvalid(ve)) then + local vo = tpt.pipes[2][vi] + if (isvalid(vo)) then entity.BalanceFluidPair(ve, vo) end + end + end + end + if (tpt.chests) then + for vi, ve in pairs(tpt.chests[1]) do + if (isvalid(ve)) then + local vo = tpt.chests[2][vi] + if (isvalid(vo)) then + local vdir = tpt.dir[1][vi] + if (vdir == "input") then entity.ShiftContainer(ve, vo) else entity.ShiftContainer(vo, ve) end + end + end + end + end + end + for nm, tpt in pairs(storage.Harvesters) do + for vi, ve in pairs(tpt.pipes[1]) do + if (isvalid(ve)) then + local vo = tpt.pipes[2][vi] + if (isvalid(vo)) then entity.BalanceFluidPair(ve, vo) end + end + end + for vi, ve in pairs(tpt.loaders[1]) do + if (isvalid(ve)) then + local vo = tpt.loaders[2][vi] + if (isvalid(vo)) then + local vdir = tpt.dir[1][vi] + if (vdir == "input") then entity.ShiftBelt(ve, vo) else entity.ShiftBelt(vo, ve) end + end + end + end + end + entity.AutoBalancePower(cache.get("power")) + entity.AutoBalanceHeat(cache.get("heat")) + if (storage.warploaders) then + for i = 1, math.min(table_size(storage.warploaders.input), 10), 1 do + warptorio + .TickWarploaders() + end + end +end + +events.on_tick(1, 0, "TickLogs", warptorio.TickLogistics) diff --git a/control_main_remotes.lua b/control_main_remotes.lua index 6475e8f..088b587 100644 --- a/control_main_remotes.lua +++ b/control_main_remotes.lua @@ -1,144 +1,144 @@ - ---[[ Custom Events ]]-- - -function warptorio.remote.get_events() return events.vdefs end -- call (), returns {event_name=script_generated_event_name_int}. Used to get a copy of the entire table. -function warptorio.remote.get_event(n) return events.vdefs[n] end -- call (warptorio_event_name_string), returns a specific event. - - - ---------------------------------------------------------------------- ---[[ New Surfaces/Platform Interface ]]-- -warptorio.remote.GetMainSurface=warptorio.GetMainSurface -- call (), returns LuaSurface, -warptorio.remote.GetMainPlanet=warptorio.GetMainPlanet -- call (), returns planet_table. Same as doing remote.call("planetorio","GetPlanetBySurface",remote.call("warptorio","GetMainSurface")) -warptorio.remote.GetHomeSurface=warptorio.GetHomeSurface -- call (), returns LuaSurface, -warptorio.remote.GetHomePlanet=warptorio.GetHomePlanet -- call (), returns planet_table. Same as doing remote.call("planetorio","GetPlanetBySurface",remote.call("warptorio","GetHomeSurface")) -warptorio.remote.GetSurfaces=warptorio.GetAllSurfaces -- call (), returns {table_of_warptorio_surfaces}. This does not include surfaces that are marked for destroy, such as player being left behind on warp. -warptorio.remote.GetSurface=function(key) return (global.floor[key] and global.floor[key].host or nil) end -warptorio.remote.GetFloor=function(key) return global.floor[key] end -warptorio.remote.GetFloors=function() return global.floor end -warptorio.remote.GetNamedSurfaces=warptorio.GetNamedSurfaces -- call ({table_of_floor_names, e.g. "home","main","factory"}), returns {[name]=surface,...}. Used to get surfaces in bulk. - -warptorio.remote.RecallTeleporterGate=function() local t=global.Teleporters.offworld if(t and isvalid(t.b))then t:DestroyLogsB() t:DestroyB() end end -- call(). Used to destroy the teleporter gate. -warptorio.remote.RecallHarvester=function(side,bply) if(global.Harvesters[side])then global.Harvesters[side]:Recall(bply) end end -- call(string_side,bool_recallplayers). side must be "east" or "west". future values may include "nw","ne","sw","se" if i ever add those. - ---------------------------------------------------------------------- - ---[[ Warptorio Remote Interface - Mod Managed Tables ]]-- ---[[ -For dealing with blacklists and stuff, so if your mod is uninstalled i can remove it from the global table. - -old stuff first: -warptorio.remote.insert_warp_blacklist=warptorio.cmdinsertcloneblacklist -- call (mod_name,prototype_name), returns nil. Stops warptorio from cloning a specific prototype name when warping. -warptorio.remote.remove_warp_blacklist=warptorio.cmdremovecloneblacklist -- call (mod_name,prototype_name), returns nil. Stops warptorio from cloning a specific prototype name when warping. -warptorio.remote.is_warp_blacklisted=warptorio.cmdiscloneblacklisted -- call (mod_name,prototype_name), returns nil. Stops warptorio from cloning a specific prototype name when warping. -warptorio.remote.GetWarpBlacklist=warptorio.GetWarpBlacklist -- call (), returns: {warptorio_warp_blacklist}. Returns the full table of all blacklisted entities. - - -function warptorio.cmdinsertcloneblacklist(mn,e) if(not global.warp_blacklist[mn])then global.warp_blacklist[mn]={} end table.insertExclusive(global.warp_blacklist[mn],e) end -function warptorio.cmdremovecloneblacklist(mn,e) if(not global.warp_blacklist[mn])then global.warp_blacklist[mn]={} end table.RemoveByValue(global.warp_blacklist[mn],e) end -function warptorio.cmdiscloneblacklisted(mn,e) if(not global.warp_blacklist[mn])then return false end return table.HasValue(global.warp_blacklist[mn],e) end -]] - - -function warptorio.ValidateRemoteTable(x) local mt=global.modtbl if(not mt[x])then mt[x]={} end - for k,v in pairs(mt[x])do if(not game.active_mods[k])then mt[x][k]=nil end end -end -function warptorio.InsertModTable(x,y,z) if(y=="warptorio2")then return end local mt=global.modtbl if(not mt[x])then return false end mt[x][y]=mt[x][y] or {} - return table.insertExclusive(mt[x][y],z) -end -function warptorio.RemoveModTable(x,y,z) if(y=="warptorio2")then return end local mt=global.modtbl if(not mt[x])then return false end mt[x][y]=mt[x][y] or {} - return table.RemoveByValue(mt[x][y],z) -end - -warptorio.ModTables={} -function warptorio.GetModTable(x) - if(warptorio.ModTables[x])then return warptorio.ModTables[x] end - local mt=global.modtbl if(not mt[x])then return true end - local t={} for k,v in pairs(mt[x])do for y,z in pairs(v)do table.insertExclusive(t,z) end end - warptorio.ModTables[x]=t - return t -end - -events.on_config(function() - global.modtbl=global.modtbl or {} - warptorio.ValidateRemoteTable("harvester_blacklist") -- prevents certain entities from being affected by harvester deploy/recall cloning. - warptorio.ValidateRemoteTable("warp_blacklist") -- prevents certain entities from being affected by the big Warpout function / cloning. -end) - - -warptorio.remote.InsertModTable=warptorio.InsertModTable -- call ("table_name", "mod_name", (ANY) Value). Used to interface with numerous mod related tables. Returns false if bad table, true if the value already exists, and int on success -warptorio.remote.RemoveModTable=warptorio.RemoveModTable -- call ("table_name", "mod_name", (ANY) Value). Returns false/int depending on success - ---------------------------------------------------------------------- ---[[ Cheats ]]-- - -warptorio.remote.ResearchNauvis=function() for k,v in pairs(game.forces.player.technologies)do if(not v.name:match("warptorio"))then v.researched=true end end end -warptorio.remote.ResearchCheat=function() for k,v in pairs(game.forces.player.research_queue)do v.researched=true end end -warptorio.remote.cheat=function() for i,p in pairs(game.players)do for k,v in pairs(lootItems)do p.get_main_inventory().insert{name=k,count=v} end end end -- call (), returns: Nil. Gives all players all the items in the lootchest table. Useful for testing. -warptorio.remote.reveal=function(n) n=n or 10 local f=global.floor.main.host game.forces.player.chart(f,{lefttop={x=-64-128*n,y=-64-128*n},rightbottom={x=64+128*n,y=64+128*n}}) end -- call (reveal_scale), returns: nil. Cheat command to reveal the map - - ---------------------------------------------------------------------- ---[[ Warptorio Loot Chest stuff ]]-- -warptorio.remote.SpawnLootChest=warptorio.SpawnLootChest -- call (surface,position_table,varg_table={min=1,max=5,dist=dist_from_0_0,stack=stack_size_min_fraction}). returns entity. Creates and fills a loot chest on given surface at given position. varg is used to tweak potential stack sizes and number of items. -warptorio.remote.GetPossibleLoot=warptorio.GetPossibleLoot -- returns a table of potential items from the loot table, filtered by is-craftable. -warptorio.remote.LootTable=warptorio.LootTable -- call (min,max,dist,stack), returns {[item_name]=#count}. Used to get a rolled table of loot items. See varg_table on SpawnLootChest. - ---------------------------------------------------------------------- ---[[ Needs review, CallDerma is deprecated ]]-- -warptorio.remote.ResetGui=warptorio.ResetGui -- call (*optional LuaPlayer), returns nil, used to re-construct a player's, or all player's gui HUD. Used when unlocking research and fixing gui issues. -warptorio.remote.CallDerma=warptorio.CallDerma -- call (derma_name, *event_table), returns nil, specifically added for remotes. Used to refresh a specific internal gui control. - ---------------------------------------------------------------------- ---[[ Generic/backend stuff exposed for no good reason, if you actually need these let me know ]]-- -warptorio.remote.GetChest=warptorio.GetChest -- call ("input" or "output"), returns "chest-prototype-name" depending on level and settings value: loaderchest_provider / loaderchest_requester based on variable. -warptorio.remote.GetBelt=warptorio.GetBelt -- call (), returns loader type based on current logistics level - -warptorio.remote.PlanetEntityIsPlatform=warptorio.PlanetEntityIsPlatform -- call (entity), returns true if the entity is a warptorio entity (aka special chest or loader used by stairs or the rails). Used specifically to check for ents on the planet -warptorio.remote.EntityIsPlatform=warptorio.EntityIsPlatform -- call (entity), returns true. Same as PlanetEntityIsPlatform, except checks all teleporters on all surfaces and stuff. -warptorio.remote.BlueprintEntityIsBlacklisted=warptorio.BlueprintEntityIsBlacklisted -- call (entity), returns true/false whether the entity should not be added to blueprints. Currently identical to remote.call("warptorio","EntityIsPlatform",entity), but is not an alias. - -warptorio.remote.ResetPlatform=function() warptorio.BuildB1() warptorio.BuildB2() for k,v in pairs(global.Teleporters)do v:Warpin() end end -- Rebuild the platform?? - - ---------------------------------------------------------------------- ---[[ Warping related stuff ]]-- - -warptorio.remote.GetWarpzone=function() return global.warpzone end -- Returns the current warpzone -warptorio.remote.IsAutowarpEnabled=warptorio.IsAutowarpEnabled -- call (), returns: boolean_IsAutowarpEnabled. Does exactly what it says on the tin. If true, the autowarp timer is running. -warptorio.remote.Warpout=warptorio.Warpout -- call (*optional planet_name), returns: nil. The big warp function. Increments the warpzone and other stuff. -warptorio.remote.warp=warptorio.Warpout -- alias - -warptorio.remote.StartWarp=warptorio.StartWarp -- call() Forcibly start the warping countdown -warptorio.remote.StopWarp=warptorio.StopWarp -- call() Forcibly stop the warping countdown -warptorio.remote.IsWarping=warptorio.IsWarping -- call(), returns bool_IsWarping. - -function warptorio.remote.GetWarpTime() return (global.warp_charging>0 and global.warp_time_left/60 or global.warp_charge_time) end -function warptorio.remote.SetWarpTime(n) global.warp_charge_time=n end - ---[[ todo? -function warptorio.remote.GetAutowarpTimeLeft() end -function warptorio.remote.SetAutowarpTimeLeft(n) end -]] - ---------------------------------------------------------------------- ---[[ Backwards Compatability - DEPRECATED -function warptorio.cmdgetwarpevent() if(not warptorio.warpevent_name)then warptorio.warpevent_name = script.generate_event_name() end return warptorio.warpevent_name end -function warptorio.cmdgetpostwarpevent() if(not warptorio.warpevent_post_name)then warptorio.warpevent_post_name = script.generate_event_name() end return warptorio.warpevent_post_name end -function warptorio.cmdgettickevent() return warptorio.custom_events.ticktime end -function warptorio.cmdevent_harvester_deploy() return warptorio.custom_events.harvester_deploy end -function warptorio.cmdevent_harvester_recall() return warptorio.custom_events.harvester_recall end -function warptorio.cmdevent_warp_started() return warptorio.custom_events.warp_started end -function warptorio.cmdevent_warp_countdown() return warptorio.custom_events.warp_countdown end -function warptorio.cmdevent_autowarp_countdown() return warptorio.custom_events.autowarp_countdown end -function warptorio.cmdevent_ability_used() return warptorio.custom_events.ability_used end -function warptorio.cmdevent_autowarp_countdown() return warptorio.custom_events.autowarp_countdown end -warptorio.remote.event_ticktime=warptorio.cmdgettickevent -warptorio.remote.event_harvester_deploy=warptorio.cmdevent_harvester_deploy -warptorio.remote.event_harvester_recall=warptorio.cmdevent_harvester_recall -warptorio.remote.event_warp=warptorio.cmdgetwarpevent -warptorio.remote.event_post_warp=warptorio.cmdgetpostwarpevent -warptorio.remote.event_warp_started=warptorio.cmdevent_warp_started -warptorio.remote.warpevent=warptorio.cmdgetwarpevent -warptorio.remote.postwarpevent=warptorio.cmdgetpostwarpevent --_- ]]-- + +--[[ Custom Events ]]-- + +function warptorio.remote.get_events() return events.vdefs end -- call (), returns {event_name=script_generated_event_name_int}. Used to get a copy of the entire table. +function warptorio.remote.get_event(n) return events.vdefs[n] end -- call (warptorio_event_name_string), returns a specific event. + + + +--------------------------------------------------------------------- +--[[ New Surfaces/Platform Interface ]]-- +warptorio.remote.GetMainSurface=warptorio.GetMainSurface -- call (), returns LuaSurface, +warptorio.remote.GetMainPlanet=warptorio.GetMainPlanet -- call (), returns planet_table. Same as doing remote.call("planetorio","GetPlanetBySurface",remote.call("warptorio","GetMainSurface")) +warptorio.remote.GetHomeSurface=warptorio.GetHomeSurface -- call (), returns LuaSurface, +warptorio.remote.GetHomePlanet=warptorio.GetHomePlanet -- call (), returns planet_table. Same as doing remote.call("planetorio","GetPlanetBySurface",remote.call("warptorio","GetHomeSurface")) +warptorio.remote.GetSurfaces=warptorio.GetAllSurfaces -- call (), returns {table_of_warptorio_surfaces}. This does not include surfaces that are marked for destroy, such as player being left behind on warp. +warptorio.remote.GetSurface=function(key) return (storage.floor[key] and storage.floor[key].host or nil) end +warptorio.remote.GetFloor=function(key) return storage.floor[key] end +warptorio.remote.GetFloors=function() return storage.floor end +warptorio.remote.GetNamedSurfaces=warptorio.GetNamedSurfaces -- call ({table_of_floor_names, e.g. "home","main","factory"}), returns {[name]=surface,...}. Used to get surfaces in bulk. + +warptorio.remote.RecallTeleporterGate=function() local t=storage.Teleporters.offworld if(t and isvalid(t.b))then t:DestroyLogsB() t:DestroyB() end end -- call(). Used to destroy the teleporter gate. +warptorio.remote.RecallHarvester=function(side,bply) if(storage.Harvesters[side])then storage.Harvesters[side]:Recall(bply) end end -- call(string_side,bool_recallplayers). side must be "east" or "west". future values may include "nw","ne","sw","se" if i ever add those. + +--------------------------------------------------------------------- + +--[[ Warptorio Remote Interface - Mod Managed Tables ]]-- +--[[ +For dealing with blacklists and stuff, so if your mod is uninstalled i can remove it from the global table. + +old stuff first: +warptorio.remote.insert_warp_blacklist=warptorio.cmdinsertcloneblacklist -- call (mod_name,prototype_name), returns nil. Stops warptorio from cloning a specific prototype name when warping. +warptorio.remote.remove_warp_blacklist=warptorio.cmdremovecloneblacklist -- call (mod_name,prototype_name), returns nil. Stops warptorio from cloning a specific prototype name when warping. +warptorio.remote.is_warp_blacklisted=warptorio.cmdiscloneblacklisted -- call (mod_name,prototype_name), returns nil. Stops warptorio from cloning a specific prototype name when warping. +warptorio.remote.GetWarpBlacklist=warptorio.GetWarpBlacklist -- call (), returns: {warptorio_warp_blacklist}. Returns the full table of all blacklisted entities. + + +function warptorio.cmdinsertcloneblacklist(mn,e) if(not storage.warp_blacklist[mn])then storage.warp_blacklist[mn]={} end table.insertExclusive(storage.warp_blacklist[mn],e) end +function warptorio.cmdremovecloneblacklist(mn,e) if(not storage.warp_blacklist[mn])then storage.warp_blacklist[mn]={} end table.RemoveByValue(storage.warp_blacklist[mn],e) end +function warptorio.cmdiscloneblacklisted(mn,e) if(not storage.warp_blacklist[mn])then return false end return table.HasValue(storage.warp_blacklist[mn],e) end +]] + + +function warptorio.ValidateRemoteTable(x) local mt=storage.modtbl if(not mt[x])then mt[x]={} end + for k,v in pairs(mt[x])do if(not script.active_mods[k])then mt[x][k]=nil end end +end +function warptorio.InsertModTable(x,y,z) if(y=="warptorio2")then return end local mt=storage.modtbl if(not mt[x])then return false end mt[x][y]=mt[x][y] or {} + return table.insertExclusive(mt[x][y],z) +end +function warptorio.RemoveModTable(x,y,z) if(y=="warptorio2")then return end local mt=storage.modtbl if(not mt[x])then return false end mt[x][y]=mt[x][y] or {} + return table.RemoveByValue(mt[x][y],z) +end + +warptorio.ModTables={} +function warptorio.GetModTable(x) + if(warptorio.ModTables[x])then return warptorio.ModTables[x] end + local mt=storage.modtbl if(not mt[x])then return true end + local t={} for k,v in pairs(mt[x])do for y,z in pairs(v)do table.insertExclusive(t,z) end end + warptorio.ModTables[x]=t + return t +end + +events.on_config(function() + storage.modtbl=storage.modtbl or {} + warptorio.ValidateRemoteTable("harvester_blacklist") -- prevents certain entities from being affected by harvester deploy/recall cloning. + warptorio.ValidateRemoteTable("warp_blacklist") -- prevents certain entities from being affected by the big Warpout function / cloning. +end) + + +warptorio.remote.InsertModTable=warptorio.InsertModTable -- call ("table_name", "mod_name", (ANY) Value). Used to interface with numerous mod related tables. Returns false if bad table, true if the value already exists, and int on success +warptorio.remote.RemoveModTable=warptorio.RemoveModTable -- call ("table_name", "mod_name", (ANY) Value). Returns false/int depending on success + +--------------------------------------------------------------------- +--[[ Cheats ]]-- + +warptorio.remote.ResearchNauvis=function() for k,v in pairs(game.forces.player.technologies)do if(not v.name:match("warptorio"))then v.researched=true end end end +warptorio.remote.ResearchCheat=function() for k,v in pairs(game.forces.player.research_queue)do v.researched=true end end +warptorio.remote.cheat=function() for i,p in pairs(game.players)do for k,v in pairs(lootItems)do p.get_main_inventory().insert{name=k,count=v} end end end -- call (), returns: Nil. Gives all players all the items in the lootchest table. Useful for testing. +warptorio.remote.reveal=function(n) n=n or 10 local f=storage.floor.main.host game.forces.player.chart(f,{lefttop={x=-64-128*n,y=-64-128*n},rightbottom={x=64+128*n,y=64+128*n}}) end -- call (reveal_scale), returns: nil. Cheat command to reveal the map + + +--------------------------------------------------------------------- +--[[ Warptorio Loot Chest stuff ]]-- +warptorio.remote.SpawnLootChest=warptorio.SpawnLootChest -- call (surface,position_table,varg_table={min=1,max=5,dist=dist_from_0_0,stack=stack_size_min_fraction}). returns entity. Creates and fills a loot chest on given surface at given position. varg is used to tweak potential stack sizes and number of items. +warptorio.remote.GetPossibleLoot=warptorio.GetPossibleLoot -- returns a table of potential items from the loot table, filtered by is-craftable. +warptorio.remote.LootTable=warptorio.LootTable -- call (min,max,dist,stack), returns {[item_name]=#count}. Used to get a rolled table of loot items. See varg_table on SpawnLootChest. + +--------------------------------------------------------------------- +--[[ Needs review, CallDerma is deprecated ]]-- +warptorio.remote.ResetGui=warptorio.ResetGui -- call (*optional LuaPlayer), returns nil, used to re-construct a player's, or all player's gui HUD. Used when unlocking research and fixing gui issues. +warptorio.remote.CallDerma=warptorio.CallDerma -- call (derma_name, *event_table), returns nil, specifically added for remotes. Used to refresh a specific internal gui control. + +--------------------------------------------------------------------- +--[[ Generic/backend stuff exposed for no good reason, if you actually need these let me know ]]-- +warptorio.remote.GetChest=warptorio.GetChest -- call ("input" or "output"), returns "chest-prototype-name" depending on level and settings value: loaderchest_provider / loaderchest_requester based on variable. +warptorio.remote.GetBelt=warptorio.GetBelt -- call (), returns loader type based on current logistics level + +warptorio.remote.PlanetEntityIsPlatform=warptorio.PlanetEntityIsPlatform -- call (entity), returns true if the entity is a warptorio entity (aka special chest or loader used by stairs or the rails). Used specifically to check for ents on the planet +warptorio.remote.EntityIsPlatform=warptorio.EntityIsPlatform -- call (entity), returns true. Same as PlanetEntityIsPlatform, except checks all teleporters on all surfaces and stuff. +warptorio.remote.BlueprintEntityIsBlacklisted=warptorio.BlueprintEntityIsBlacklisted -- call (entity), returns true/false whether the entity should not be added to blueprints. Currently identical to remote.call("warptorio","EntityIsPlatform",entity), but is not an alias. + +warptorio.remote.ResetPlatform=function() warptorio.BuildB1() warptorio.BuildB2() for k,v in pairs(storage.Teleporters)do v:Warpin() end end -- Rebuild the platform?? + + +--------------------------------------------------------------------- +--[[ Warping related stuff ]]-- + +warptorio.remote.GetWarpzone=function() return storage.warpzone end -- Returns the current warpzone +warptorio.remote.IsAutowarpEnabled=warptorio.IsAutowarpEnabled -- call (), returns: boolean_IsAutowarpEnabled. Does exactly what it says on the tin. If true, the autowarp timer is running. +warptorio.remote.Warpout=warptorio.Warpout -- call (*optional planet_name), returns: nil. The big warp function. Increments the warpzone and other stuff. +warptorio.remote.warp=warptorio.Warpout -- alias + +warptorio.remote.StartWarp=warptorio.StartWarp -- call() Forcibly start the warping countdown +warptorio.remote.StopWarp=warptorio.StopWarp -- call() Forcibly stop the warping countdown +warptorio.remote.IsWarping=warptorio.IsWarping -- call(), returns bool_IsWarping. + +function warptorio.remote.GetWarpTime() return (storage.warp_charging>0 and storage.warp_time_left/60 or storage.warp_charge_time) end +function warptorio.remote.SetWarpTime(n) storage.warp_charge_time=n end + +--[[ todo? +function warptorio.remote.GetAutowarpTimeLeft() end +function warptorio.remote.SetAutowarpTimeLeft(n) end +]] + +--------------------------------------------------------------------- +--[[ Backwards Compatability - DEPRECATED +function warptorio.cmdgetwarpevent() if(not warptorio.warpevent_name)then warptorio.warpevent_name = script.generate_event_name() end return warptorio.warpevent_name end +function warptorio.cmdgetpostwarpevent() if(not warptorio.warpevent_post_name)then warptorio.warpevent_post_name = script.generate_event_name() end return warptorio.warpevent_post_name end +function warptorio.cmdgettickevent() return warptorio.custom_events.ticktime end +function warptorio.cmdevent_harvester_deploy() return warptorio.custom_events.harvester_deploy end +function warptorio.cmdevent_harvester_recall() return warptorio.custom_events.harvester_recall end +function warptorio.cmdevent_warp_started() return warptorio.custom_events.warp_started end +function warptorio.cmdevent_warp_countdown() return warptorio.custom_events.warp_countdown end +function warptorio.cmdevent_autowarp_countdown() return warptorio.custom_events.autowarp_countdown end +function warptorio.cmdevent_ability_used() return warptorio.custom_events.ability_used end +function warptorio.cmdevent_autowarp_countdown() return warptorio.custom_events.autowarp_countdown end +warptorio.remote.event_ticktime=warptorio.cmdgettickevent +warptorio.remote.event_harvester_deploy=warptorio.cmdevent_harvester_deploy +warptorio.remote.event_harvester_recall=warptorio.cmdevent_harvester_recall +warptorio.remote.event_warp=warptorio.cmdgetwarpevent +warptorio.remote.event_post_warp=warptorio.cmdgetpostwarpevent +warptorio.remote.event_warp_started=warptorio.cmdevent_warp_started +warptorio.remote.warpevent=warptorio.cmdgetwarpevent +warptorio.remote.postwarpevent=warptorio.cmdgetpostwarpevent +-_- ]]-- diff --git a/control_platform_classic.lua b/control_platform_classic.lua index f158395..4a20a8f 100644 --- a/control_platform_classic.lua +++ b/control_platform_classic.lua @@ -1,954 +1,954 @@ -local platform={} -platform.name="classic" - ---[[ Offsets and stuff ]]-- - -platform.railCorner={nw=vector(-35,-35),ne=vector(34,-35),sw=vector(-35,34),se=vector(34,34)} -platform.railOffset={nw=vector(0,0),ne=vector(-1,0),sw=vector(0,-1),se=vector(-1,-1)} --{nw=vector(-1,-1),ne=vector(0,-1),sw=vector(-1,0),se=vector(0,0)} -platform.railLoader={nw=vector.area(vector(2,0),vector(0,2)),sw=vector.area(vector(2,0),vector(0,-2)),ne=vector.area(vector(-2,0),vector(0,2)),se=vector.area(vector(-2,0),vector(0,-2))} - -platform.letterOpposite={n=defines.direction.south,s=defines.direction.north,e=defines.direction.west,w=defines.direction.east} -platform.railLoaderPos={ - nw={vector(2,0),vector(2,-1),vector(0,2),vector(-1,2)}, - sw={vector(2,0),vector(2,-1),vector(0,-2),vector(-1,-2)}, - ne={vector(-2,0),vector(-2,-1),vector(0,2),vector(-1,2)}, - se={vector(-2,0),vector(-2,-1),vector(0,-2),vector(-1,-2)}, -} - ---platform.corner={nw=vector(-52,-52),ne=vector(50,-52),sw=vector(-52,50),se=vector(50,50)} -- old -platform.corner={nw=vector(-51.5,-51.5),ne=vector(50.5,-51.5),sw=vector(-51.5,50.5),se=vector(50.5,50.5)} - -platform.side={north=vector(0,-52),south=vector(0,51),east=vector(51,0),west=vector(-52,0)} ---[[ -local cirMaxWidth=128+8 -local cirHeight=17 --64+4 --17 -- -local vz=cirMaxWidth ---local ez=m.harvestSize or 10 -- harvester size max 47 -local hvMax=47 -local vzx=vz/2 local hvx=hvMax/2 local hvy=hvMax/8 - -local westPos=warptorio.platform.harvester.west --vector(-(vzx+(hvx-hvy))+0.5,-0.5) -local eastPos=warptorio.platform.harvester.east --vector(vzx+(hvx-hvy),-0.5) -]] -local hvSize=(128+8)/2 -local hvMax=47 -platform.harvester={} -platform.harvester.east=vector(85.5,-0.5) --hvSize+((hvMax/2)-(hvMax/8)),-0.5) -- 85.625 -platform.harvester.west=vector(-86.5,-0.5) -- -(hvSize+((hvMax/2)-(hvMax/8)))+0.5,-0.5) -- -85.125 -- was -86 - - -platform.corn={} -platform.corn.nw={x=-52,y=-52} -platform.corn.ne={x=50,y=-52} -platform.corn.sw={x=-52,y=50} -platform.corn.se={x=50,y=50} -platform.corn.north=-52 -platform.corn.south=50 -platform.corn.east=50 -platform.corn.west=-51.5 - - - ---[[ Floors ]]-- - -platform.floors={} - - --- Todo: Make teleporters and specials automatically do hazard tiles - ---[[ Platform Technology Effects ]]-- - -platform.techs={} - --- General technologies - -platform.techs.boiler_station={tech="warptorio-boiler-station",effect={special={"boiler"}},} -platform.techs.reactor={tech="warptorio-reactor",level_range={1,8},effect={reactor=true,special={"main"}}, } - -platform.techs.tele_portal={tech="warptorio-teleporter-portal",effect={unlock_teleporters={"offworld"},},} -platform.techs.tele_energy={tech="warptorio-teleporter",level_range={1,5},effect={upgrade_energy={"offworld"},},} -platform.techs.energy={tech="warptorio-energy",level_range={1,5},effect={upgrade_energy=true},} -platform.techs.logistics={tech="warptorio-logistics",level_range={1,4},effect={upgrade_logistics=true},} -platform.techs.warp_beacon={tech="warptorio-beacon",level_range={1,10},effect={special={"factory"},},} - -platform.techs.dualloader={tech="warptorio-dualloader-1",effect={upgrade_logistics=true},} -platform.techs.triloader={tech="warptorio-triloader",effect={upgrade_logistics=true},} - -platform.techs.accelerator={tech="warptorio-accelerator",effect={ability="accelerator"},} -platform.techs.stabilizer={tech="warptorio-stabilizer",effect={ability="stabilizer"},} -platform.techs.charting={tech="warptorio-charting",effect={ability="charting",special={"factory","boiler"}},} - - -platform.techs.alt_combinator={tech="warptorio-alt-combinator",effect={do_combinators=true},} - -platform.techs.homeworld={tech="warptorio-homeworld",effect={unlock_homeworld=true},} - -platform.techs.toolbar={tech="warptorio-toolbar",effect={unlock_toolbar=true}} - - - - --- Platform Surface Techs -platform.techs.size={tech="warptorio-platform-size",effect={retile={"main"}}, -levels={ - [0]=8, - [1]=10+7-1, - [2]=18+7-1, - [3]=26+7-1, - [4]=40+7-1, - [5]=56+7-1+2, - [6]=74+7-1+2, - [7]=92+7-1+4, -}} - -platform.techs.railnw={tech="warptorio-rail-nw",effect={unlock_rails="nw"},} -platform.techs.railne={tech="warptorio-rail-ne",effect={unlock_rails="ne"},} -platform.techs.railsw={tech="warptorio-rail-sw",effect={unlock_rails="sw"},} -platform.techs.railse={tech="warptorio-rail-se",effect={unlock_rails="se"},} - -platform.techs.turret_nw={tech="warptorio-turret-nw",first_effect={unlock_teleporters={"main_tur_factory_nw"}},effect={retile={"main","factory"}},level_range={0,3},} -platform.techs.turret_ne={tech="warptorio-turret-ne",first_effect={unlock_teleporters={"main_tur_factory_ne"}},effect={retile={"main","factory"}},level_range={0,3},} -platform.techs.turret_sw={tech="warptorio-turret-sw",first_effect={unlock_teleporters={"main_tur_factory_sw"}},effect={retile={"main","factory"}},level_range={0,3},} -platform.techs.turret_se={tech="warptorio-turret-se",first_effect={unlock_teleporters={"main_tur_factory_se"}},effect={retile={"main","factory"}},level_range={0,3},} - - --- Factory Techs - -platform.techs.factory_n={tech="warptorio-factory-n",effect={retile={"factory"}},} -platform.techs.factory_s={tech="warptorio-factory-s",effect={retile={"factory"}},} -platform.techs.factory_e={tech="warptorio-factory-e",effect={retile={"factory"}},} -platform.techs.factory_w={tech="warptorio-factory-w",effect={retile={"factory"}},} -platform.techs.bridgesize={tech="warptorio-bridgesize",level_range={1,2},effect={retile={"factory"}},} - - -platform.techs.factorysize={tech="warptorio-factory",effect={retile={"factory"}}, -first_effect={rehazard={"main"},unlock_teleporters={"main_to_factory"},}, -levels={ - [0]=19-1, - [1]=23-1, - [2]=31-1, - [3]=39-1, - [4]=47-1, - [5]=55-1, - [6]=63-1, - [7]=71+2-1, -}, -} - - --- Boiler Techs - -platform.techs.boiler_water={tech="warptorio-boiler-water",level_range={1,3},effect={retile={"boiler"},},} - -platform.techs.boiler_n={tech="warptorio-boiler-n",effect={retile={"boiler"}},} -platform.techs.boiler_s={tech="warptorio-boiler-s",effect={retile={"boiler"}},} -platform.techs.boiler_e={tech="warptorio-boiler-e",effect={retile={"boiler"}},} -platform.techs.boiler_w={tech="warptorio-boiler-w",effect={retile={"boiler"}},} - - -platform.techs.boilersize={tech="warptorio-boiler", -first_effect={rehazard={"harvester"},unlock_teleporters={"harvester_to_boiler"}}, -effect={retile={"boiler"}}, -levels={ - [0]=18, - [1]=24, - [2]=32, - [3]=40, - [4]=48, - [5]=56, - [6]=64, - [7]=72, -}, -} - - -platform.techs.harvesterfloor={tech="warptorio-harvester-floor",effect={retile={"harvester"},unlock_teleporters={"factory_to_harvester"}}, -} -platform.techs.harvestersize={tech="warptorio-harvester-size",effect={retile={"harvester"},}, -- oval sizes -levels={ - [0]=vector(19,17), - [1]=vector(28,22), - [2]=vector(36,26), - [3]=vector(48,32), - [4]=vector(74,40), - [5]=vector(92,48), - [6]=vector(112,56), - [7]=vector(128+8,64), -}, -} -platform.techs.harvester_west={tech="warptorio-harvester-west",effect={harvesters={"west"}}, -levels={ - [1]=12, - [2]=20, - [3]=26, - [4]=32, - [5]=38, -}, -} -platform.techs.harvester_east={tech="warptorio-harvester-east",effect={harvesters={"east"}}, -levels={ - [1]=12, - [2]=20, - [3]=26, - [4]=32, - [5]=38, -}, -} - ---unused platform.techs.harvester_west_loader={tech="warptorio-harvester-west-loader",effect={harvesters={"west"}},} ---unused platform.techs.harvester_east_loader={tech="warptorio-harvester-east-loader",effect={harvesters={"east"}},} - - ---[[ Rails registers ]]-- - -platform.rails={} -local tpr={key="nw"} platform.rails[tpr.key]=tpr -tpr.railpos=platform.railCorner[tpr.key]+platform.railOffset[tpr.key] -tpr.chestpos=platform.railCorner[tpr.key] --+platform.railOffset[tpr.key] -tpr.floor="factory" -tpr.logs={false,true,true,false} - -local tpr={key="ne"} platform.rails[tpr.key]=tpr -tpr.railpos=platform.railCorner[tpr.key]+platform.railOffset[tpr.key] -tpr.chestpos=platform.railCorner[tpr.key] --+platform.railOffset[tpr.key] -tpr.floor="factory" -tpr.logs={false,false,true,true} - -local tpr={key="sw"} platform.rails[tpr.key]=tpr -tpr.railpos=platform.railCorner[tpr.key]+platform.railOffset[tpr.key] -tpr.chestpos=platform.railCorner[tpr.key] --+platform.railOffset[tpr.key] -tpr.floor="factory" -tpr.logs={true,true,false,false} - -local tpr={key="se"} platform.rails[tpr.key]=tpr -tpr.railpos=platform.railCorner[tpr.key]+platform.railOffset[tpr.key] -tpr.chestpos=platform.railCorner[tpr.key] --+platform.railOffset[tpr.key] -tpr.floor="factory" -tpr.logs={true,false,false,true} - - - - ---[[ Teleporter registers ]]-- - -platform.teleporters={} - ---[[ Offworld Teleporter ]]-- - --- Offworld is special and has some special handling on its pair, e.g. the second pair doesn't get hazards and can be spawned freely because you can pick it up. -local tps={key="offworld"} platform.teleporters[tps.key]=tps -tps.logs=true -- this teleporter gains loaders on the first logistics upgrade -tps.dopipes=true -- this teleporter should be given pipes -tps.dualloader=false -- this teleporter gets an extra loader on the dualloader upgrade -tps.triloader=true -- this teleporter gets an extra loader on the triloader upgrade -tps.top=false -- this teleporter is a "top loader" used to determine loader direction via settings. -tps.circuit=false -- Should be false if the teleporter pair isn't in the same position. -tps.staticdir=false -- "up" or "down" if the logistics cannot have their direction changed with setting -tps.oneside=false -- If this teleporter is onesided, "left" or "right" -tps.rotated=false -- If true, this has logistics on top and bottom instead of left and right -tps.logiport=false -- Set to true if this is logistics only. -tps.energy="tele_energy" -- platform tech name - -tps.pair={ - {floor="main",position=vector(-1,5), - prototype="warptorio-teleporter", - }, - {floor="main",position=vector(-1,8), - prototype="warptorio-teleporter-gate", - gate=true, -- Logistics spawning behaviour flag - minable=true, -- Flag to pickup - destructible=true, -- Can be destroyed - } -} - - ---[[ Main Factory Teleporter ]]-- - -local tps={key="main_to_factory"} platform.teleporters[tps.key]=tps -tps.logs=true -tps.dopipes=true -tps.dualloader=true -tps.triloader=true -tps.top=true -tps.circuit=true -tps.staticdir=false -tps.oneside=false -tps.rotated=false -tps.logiport=false -tps.energy="energy" - -tps.pair={ - {floor="main",position=vector(-1,-7), - prototype="warptorio-underground", - sprite_arrow="down", - sprites={ - {sprite="technology/automation",target_offset={0,-0.25},x_scale=0.5,y_scale=0.5,tint={r=1,g=0.7,b=0.4,a=1}}, - }, - }, - {floor="factory",position=vector(-1,-7), - prototype="warptorio-underground", - sprite_arrow="up", - sprites={ - {sprite="technology/concrete",target_offset={0,-0.25},x_scale=0.5,y_scale=0.5,tint={r=1,g=0.7,b=0.4,a=1}}, - }, - } -} - --- Main Turrets copy from Main Factory - -local kdir="nw" -local key="main_tur_factory_"..kdir -local tpv=table.deepcopy(tps) -tpv.dualloader=false -tpv.top=true -tpv.triloader=true -tpv.circuit=true -tpv.key=key platform.teleporters[key]=tpv -tpv.pair[1].position=platform.corner[kdir]-vector(0.5,0.5) -tpv.pair[2].position=platform.corner[kdir]-vector(0.5,0.5) -tpv.pair[1].sprites=nil -tpv.pair[2].sprites=nil - -local kdir="ne" -local key="main_tur_factory_"..kdir -local tpv=table.deepcopy(tps) -tpv.dualloader=false -tpv.top=true -tpv.triloader=true -tpv.circuit=true -tpv.key=key platform.teleporters[key]=tpv -tpv.pair[1].position=platform.corner[kdir]-vector(0.5,0.5) -tpv.pair[2].position=platform.corner[kdir]-vector(0.5,0.5) -tpv.pair[1].sprites=nil -tpv.pair[2].sprites=nil - -local kdir="sw" -local key="main_tur_factory_"..kdir -local tpv=table.deepcopy(tps) -tpv.dualloader=false -tpv.triloader=true -tpv.circuit=true -tpv.top=false -tpv.key=key platform.teleporters[key]=tpv -tpv.pair[1].position=platform.corner[kdir]-vector(0.5,0.5) -tpv.pair[2].position=platform.corner[kdir]-vector(0.5,0.5) -tpv.pair[1].sprites=nil -tpv.pair[2].sprites=nil - -local kdir="se" -local key="main_tur_factory_"..kdir -local tpv=table.deepcopy(tps) -tpv.dualloader=false -tpv.triloader=true -tpv.circuit=true -tpv.top=false -tpv.key=key platform.teleporters[key]=tpv -tpv.pair[1].position=platform.corner[kdir]-vector(0.5,0.5) -tpv.pair[2].position=platform.corner[kdir]-vector(0.5,0.5) -tpv.pair[1].sprites=nil -tpv.pair[2].sprites=nil - - ---[[ Factory to Harvester Teleporter ]]-- - -local tps={key="factory_to_harvester"} platform.teleporters[tps.key]=tps -tps.logs=true -tps.dopipes=true -tps.dualloader=true -tps.triloader=true -tps.top=false -tps.circuit=true -tps.staticdir=false -tps.oneside=false -tps.rotated=false -tps.logiport=false -tps.energy="energy" -tps.pair={ - {floor="factory",position=vector(-1,5), - prototype="warptorio-underground", - sprite_arrow="down", - sprites={ - {sprite="technology/tank",target_offset={0,-0.25},x_scale=0.5,y_scale=0.5,tint={r=1,g=0.7,b=0.4,a=1}}, - }, - }, - {floor="harvester",position=vector(-1,5), - prototype="warptorio-underground", - sprite_arrow="up", - sprites={ - {sprite="technology/automation",target_offset={0,-0.25},x_scale=0.5,y_scale=0.5,tint={r=1,g=0.7,b=0.4,a=1}}, - }, - } -} - - - ---[[ Harvester to Boiler Teleporter ]]-- - -local tps={key="harvester_to_boiler"} platform.teleporters[tps.key]=tps -tps.logs=true -tps.dopipes=true -tps.dualloader=true -tps.triloader=true -tps.top=true -tps.circuit=true -tps.staticdir=false -tps.oneside=false -tps.rotated=false -tps.logiport=false -tps.energy="energy" -tps.pair={ - {floor="harvester",position=vector(-1,-7), - prototype="warptorio-underground", - sprite_arrow="down", - sprites={ - {sprite="technology/fluid-handling",target_offset={0,-0.25},x_scale=0.5,y_scale=0.5,tint={r=1,g=0.7,b=0.4,a=1}} - }, - }, - {floor="boiler",position=vector(-1,-7), - prototype="warptorio-underground", - sprite_arrow="up", - sprites={ - - {sprite="technology/tank",target_offset={0,-0.25},x_scale=0.5,y_scale=0.5,tint={r=1,g=0.7,b=0.4,a=1}} - }, - } -} - - - - ---[[ Harvester registers ]]-- - -platform.HarvesterPointData={ - energy="energy", - pair={ - {floor="harvester",prototype="warptorio-harvestportal",minable=true,destructible=false}, - {floor="main",prototype="warptorio-harvestportal",minable=true,destructible=true,gate=true}, - }, -} - -platform.harvesters={} - -local hvs={key="west",position=platform.harvester.west} -hvs.energy="energy" -hvs.pad_prototype="warptorio-harvestpad-west" -hvs.prototype="warptorio-harvestportal" -hvs.tech="harvester_west" -- harvester size tech name, or.. -hvs.fixed_level=nil -- If this harvester is a fixed level -hvs.logs=true -hvs.dualloader=true -hvs.triloader=true -hvs.dopipes=true -hvs.pipes_pattern="east" --{east={{2},{2,-2},{2,-2}},} -hvs.logs_pattern="east" --{east={{0},{0,-1},{0,-1,1}},} -- Which side the logistics are on. Yes you can have on all 4 sides. -hvs.combinator_pattern="west" -- Which side the combinator is on. - -platform.harvesters.west=hvs - -local hvs={key="east",position=platform.harvester.east} -hvs.energy="energy" -hvs.pad_prototype="warptorio-harvestpad-east" -hvs.prototype="warptorio-harvestportal" -hvs.tech="harvester_east" -hvs.fixed_level=nil -hvs.logs=true -hvs.dualloader=true -hvs.triloader=true -hvs.dopipes=true -hvs.pipes_pattern="west" --{west={{2},{2,-2},{2,-2}},} -hvs.logs_pattern="west" --{west={{0},{0,-1},{0,-1,1}},} -- Which side the logistics are on. -hvs.combinator_pattern="east" -- Which side the combinator is on. No patterns, dont put logistics over it. - - -platform.harvesters.east=hvs - --- No gigas yet - - ---[[ Homeworld ]]-- - -local floor={key="home"} -- Special key doesnt need a name -floor.empty=false -floor.radar=false -floor.special=nil -floor.migrate_tile=nil -platform.floors.home=floor - - - ---[[ Main Floor (Planet Surface) ]]-- - -local floor={key="main"} -- Special key doesnt need a name -floor.empty=false -floor.radar=false -floor.special={tech="warptorio-reactor-6",prototype="warptorio-reactor",size=vector(4,4),destructible=true} --vector.clean(f,vector.square(vector(-0.5,-0.5),vector(5,5))) -floor.migrate_tile=nil -- A tile that will never appear during default tile & hazard placement, excluding harvesters (special handling on them). nil=no migration - - -function floor.get_sizes() local t={} - t.size=warptorio.GetPlatformTechAmount("size") -- research.level etc -return t end - - -function floor.tile(f,b_void) - local zt=floor.get_sizes() - local z=zt.size or 8 - - local tiler="warp-tile-concrete" if(b_void)then tiler="out-of-map" end - - local area=vector.square(vector(-0.5,-0.5),vector(z,z)) - vector.clearFiltered(f,area) - vector.LayTiles(tiler,f,area) - - local rSize=research.level("warptorio-platform-size") - local rLogs=research.level("warptorio-logistics") - local rFacSize=research.level("warptorio-factory") - local rTpGate=research.has("warptorio-teleporter-portal") - - for u,c in pairs(platform.corner)do - local lvc=research.level("warptorio-turret-"..u.."") - if(research.has("warptorio-turret-"..u.."-0"))then local rad=math.floor((10+lvc*6)) - for k,v in pairs(f.find_entities_filtered{type="character",force={game.forces.player,game.forces.enemy},invert=true,position=c,radius=rad/2})do entity.tryclean(v) end - vector.LayCircle(tiler,f,vector.circleEx(c,rad)) - end - end -end -function floor.hazard(f) - local zt=floor.get_sizes() - local z=zt.size or 8 - - local area=vector.square(vector(-0.5,-0.5),vector(z,z)) - vector.LayTiles("hazard-concrete-left",f,vector.square(vector(-1,-1),vector(4,4))) - - local rSize=research.level("warptorio-platform-size") - --local rLogs=research.level("warptorio-logistics") - local rFacSize=research.level("warptorio-factory") - local rFac=research.has("warptorio-factory-0") - local rTpGate=research.has("warptorio-teleporter-portal") - - if(rSize>0)then local ltm,ltp - ltm=warptorio.GetTeleporterHazard(true,rFac) - ltp=warptorio.GetTeleporterHazard(false,rTpGate) - vector.LayTiles("hazard-concrete-left",f,vector.square(platform.teleporters["main_to_factory"].pair[1].position,ltm)) - vector.LayTiles("hazard-concrete-left",f,vector.square(platform.teleporters["offworld"].pair[1].position,ltp)) - end - if(rSize>=6)then for k,v in pairs(platform.railCorner)do local o=platform.railOffset[k] vector.LayTiles("hazard-concrete-left",f,vector.square(v+o,vector(1,1))) end end -- trains - - for u,c in pairs(platform.corner)do - local lvc=research.level("warptorio-turret-"..u.."") - if(research.has("warptorio-turret-"..u.."-0"))then local rad=math.floor((10+lvc*6)) - vector.LayTiles("hazard-concrete-left",f,vector.square(c,warptorio.GetTeleporterHazard(false))) - end - end -end - -function floor.technology(f) -- Check/re-apply technology-effects - -end -platform.floors.main=floor - - ---[[ Factory Floor ]]-- - -local floor={key="factory",name="warptorio_factory"} -floor.empty=true -floor.radar=true -floor.special={tech="warptorio-beacon",upgrade=true,prototype="warptorio-beacon",size=vector(2,2)} -floor.migrate_tile="grass-1" -- A tile that will never appear during default tile & hazard placement, excluding harvesters (special handling on them). nil=no migration - -function floor.get_sizes() local t={} - t.size=warptorio.GetPlatformTechAmount("factorysize") -- research.level etc -return t end - -function floor.tile(f) - local zt=floor.get_sizes() - local z=zt.size - - local area=vector.square(vector(-0.5,-0.5),vector(z,z)) - local rFacSize=research.level("warptorio-factory") - local rBoiler=research.has("warptorio-boiler-1") - local rLogs=research.level("warptorio-logistics") - local rBridge=research.level("warptorio-bridgesize") - vector.LayTiles("warp-tile-concrete",f,area) - - local rc={} for k in pairs(platform.corner)do local rclv=research.level("warptorio-turret-"..k) if(rclv>0 or research.has("warptorio-turret-"..k.."-0"))then rc[k]=rclv end end - local zMainWidth=10+rBridge*2 - local zMainHeight=59+rBridge*2-2 - local zLeg=6+rBridge*4 - local whas=(rc.nw or rc.sw) local nhas=(rc.nw or rc.ne) local ehas=(rc.ne or rc.se) local shas=(rc.sw or rc.se) - if(nhas)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-0.5,platform.side.north.y/2),vector(zMainWidth,zMainHeight))) end - if(shas)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-0.5,platform.side.south.y/2-0.5),vector(zMainWidth,zMainHeight))) end - if(ehas)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.east.x/2-0.5,-0.5),vector(zMainHeight,zMainWidth))) end - if(whas)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.west.x/2,-0.5),vector(zMainHeight,zMainWidth))) end - if(nhas and rc.nw)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.west.x/2,platform.side.north.y),vector(zMainHeight,zLeg))) end - if(nhas and rc.ne)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.east.x/2,platform.side.north.y),vector(zMainHeight,zLeg))) end - if(shas and rc.sw)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.west.x/2,platform.side.south.y-0.5),vector(zMainHeight,zLeg))) end - if(shas and rc.se)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.east.x/2,platform.side.south.y-0.5),vector(zMainHeight,zLeg))) end - if(ehas and rc.ne)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.east.x-0.5,platform.side.north.y/2),vector(zLeg,zMainHeight))) end - if(ehas and rc.se)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.east.x-0.5,platform.side.south.y/2),vector(zLeg,zMainHeight))) end - if(whas and rc.nw)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.west.x,platform.side.north.y/2),vector(zLeg,zMainHeight))) end - if(whas and rc.sw)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.west.x,platform.side.south.y/2),vector(zLeg,zMainHeight))) end - - for k,c in pairs(platform.corner)do if(rc[k])then local zx=(10+rc[k]*6) - vector.LayTiles("warp-tile-concrete",f,vector.square(c,vector(zx,zx))) vector.LayTiles("hazard-concrete-left",f,vector.square(c,warptorio.GetTeleporterHazard(false))) - end end - - local zgWidth=128-16 - local zgHeight=96-12 - local zgLegHeight=17 - local zgLegWidth=10 - - if(research.has("warptorio-factory-n"))then - vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.north+vector(-1,-zgLegHeight-zgHeight/2-1),vector(zgWidth,zgHeight))) - vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.north+vector(9-1,-zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) - vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.north+vector(-9-1,-zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) - end if(research.has("warptorio-factory-s"))then - vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.south+vector(-1,zgLegHeight+zgHeight/2),vector(zgWidth,zgHeight))) - vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.south+vector(9-1,zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) - vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.south+vector(-9-1,zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) - end if(research.has("warptorio-factory-w"))then - vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.west+vector(-zgLegHeight-zgHeight/2-1,-1),vector(zgHeight,zgWidth))) - vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.west+vector(-zgLegHeight/2-1,9-1),vector(zgLegHeight,zgLegWidth))) - vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.west+vector(-zgLegHeight/2-1,-9-1),vector(zgLegHeight,zgLegWidth))) - end if(research.has("warptorio-factory-e"))then - vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.east+vector(zgLegHeight+zgHeight/2,-1),vector(zgHeight,zgWidth))) - vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.east+vector(zgLegHeight/2-1,9-1),vector(zgLegHeight,zgLegWidth))) - vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.east+vector(zgLegHeight/2-1,-9-1),vector(zgLegHeight,zgLegWidth))) - end - -end - -function floor.hazard(f) - local zt=floor.get_sizes() - local z=zt.size - local area=vector.square(vector(-0.5,-0.5),vector(z,z)) - local rFac=research.has("warptorio-factory-0") - local rFacSize=research.level("warptorio-factory") - local rBoiler=research.has("warptorio-boiler-1") - local rHarv=research.has("warptorio-harvester-floor") - local rLogs=research.level("warptorio-logistics") - local rBridge=research.level("warptorio-bridgesize") - - if(rFacSize>=7)then for k,rv in pairs(platform.railOffset)do local rc=platform.railCorner[k] -- trains - local rvx=platform.railLoader[k] - vector.LayTiles("hazard-concrete-left",f,vector.square(vector(rc.x,rc.y),vector(1,1))) - vector.LayTiles("hazard-concrete-left",f,vector.square(vector(rc.x+rvx[1][1],rc.y+rvx[1][2]),vector(1,1))) - vector.LayTiles("hazard-concrete-left",f,vector.square(vector(rc.x+rvx[2][1],rc.y+rvx[2][2]),vector(1,1))) - end end - - vector.LayTiles("hazard-concrete-left",f,vector.square(platform.teleporters["factory_to_harvester"].pair[1].position, -- factory to harvester - (warptorio.GetTeleporterHazard(true,rHarv)) - )) - - vector.LayTiles("hazard-concrete-left",f,vector.square(platform.teleporters["main_to_factory"].pair[1].position, -- planet to factory - (warptorio.GetTeleporterHazard(true,rFac) ) - )) - vector.LayTiles("hazard-concrete-left",f,vector.square(vector(-0.5,-0.5),vector(2,2))) -end - -function floor.technology(f) - -end -platform.floors.factory=floor - - - ---[[ Harvester Floor ]]-- - -local floor={key="harvester",name="warptorio_harvester"} -floor.empty=true -floor.radar=false -floor.special=nil -- no special for harvester -floor.migrate_tile="grass-1" -- A tile that will never appear during default tile & hazard placement, excluding harvesters (special handling on them). nil=no migration - - -function floor.BuildHarvestCorner(f,cz,k,v) -- for giga harvesters unused - if(research.has("warptorio-harvester-"..k.."-gate"))then - vector.LayTiles("warp-tile-concrete",f,vector.square(v/3*2,vector(cz*1.25,cz*1.25))) - vector.LayTiles("warptorio-red-concrete",f,vector.square(v/3*2,vector(cz,cz))) - vector.LayTiles("hazard-concrete-left",f,vector.square((v/3*2),vector(2,2))) - end -end - - -function floor.get_sizes() local t={} - t.size=16 -- research.level etc - t.ovalsize=warptorio.GetPlatformTechAmount("harvestersize") or vector(22,17) -return t end - -function floor.hazard(f) - local zt=floor.get_sizes() - local z=zt.size - - --local rLogs=research.level("warptorio-logistics") - local rBoiler=research.has("warptorio-boiler-0") - - local bpair=platform.teleporters["factory_to_harvester"].pair - local apair=platform.teleporters["harvester_to_boiler"].pair - vector.LayTiles("hazard-concrete-left",f,vector.square(apair[1].position,(warptorio.GetTeleporterHazard(true,rBoiler)) )) -- harvester to boiler - vector.LayTiles("hazard-concrete-left",f,vector.square(bpair[1].position,warptorio.GetTeleporterHazard(true))) -- factory to harvester - --vector.LayTiles("hazard-concrete-left",f,vector.square(vector(-1,-1),vector(2,2))) -- beacon -end - -function floor.tile(f) - local zt=floor.get_sizes() - local z=zt.size - - - local cirMaxWidth=128+8 - local cirHeight=17 --64+4 --17 -- - - local minCir=vector(22,17) - local maxCir=vector(128+8,64+4) - local ovSize=vector(vector.getx(zt.ovalsize),vector.gety(zt.ovalsize)) -- vector(cirWidth,cirHeight) - - vector.LayCircle("warp-tile-concrete",f,vector.oval(vector(-1,-1),ovSize)) - - ---[[ for 4 corners -- unfinished - - --local zx=(platform.side.east.x+platform.side.west.x)/3*2 - --vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.east.x/3*2,-1),vector(6,platform.side.south.y+3))) - --vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.west.x/3*2,-1),vector(6,platform.side.south.y+3))) - local cz=16 - for k,v in pairs(platform.corner)do warptorio.BuildHarvestCorner(cz,k,v) end -]] - - -end - -function floor.technology(f) - -end - -floor.BuildHarvester={} -floor.BuildHarvester.west=function(f) - local zt=floor.get_sizes() - local z=zt.size - - local lvWest=research.level("warptorio-harvester-west") - if(lvWest>0)then - local ez=warptorio.GetHarvesterLevelSizeNum(lvWest) - local vz=128+8 local hvMax=47 local vzx=vz/2 local hvx=hvMax/2 local hvy=hvMax/8 - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-1-vz/3,-1),vector(vz/2+(hvMax/2.5)-ez/2,4+((lvWest-1)*2 ))) ) -- west bridge - end -end -floor.BuildHarvester.east=function(f) - local zt=floor.get_sizes() - local z=zt.size - - - - local lvEast=research.level("warptorio-harvester-east") - if(lvEast>0)then - local ez=warptorio.GetHarvesterLevelSizeNum(lvEast) - local vz=128+8 local hvMax=47 local vzx=vz/2 local hvx=hvMax/2 local hvy=hvMax/8 - local vecSize=vector( (vz/2+(hvMax/2.5)-ez/2),4+((lvEast-1)*2)) - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-1+vz/3,-1), vecSize)) -- east bridge - end -end - -platform.floors.harvester=floor - - - - - - ---[[ Boiler Floor ]]-- - -local floor={key="boiler",name="warptorio_boiler"} -floor.empty=true -floor.radar=true -floor.special={tech="warptorio-boiler-station",prototype="warptorio-warpstation",size=vector(2,2)} -floor.migrate_tile="grass-1" -- A tile that will never appear during default tile & hazard placement, excluding harvesters (special handling on them). nil=no migration - -function floor.get_sizes() local t={} - t.size=warptorio.GetPlatformTechAmount("boilersize") or 17 -- research.level etc - --error(serpent.block(warptorio.platform.techs.boilersize)) -return t end - -function floor.hazard(f) - local zt=floor.get_sizes() - local z=zt.size - - local rBoiler=research.level("warptorio-boiler") - local rLogs=research.level("warptorio-logistics") - local rWater=research.level("warptorio-boiler-water") - - vector.LayTiles("hazard-concrete-left",f,vector.square(platform.teleporters["harvester_to_boiler"].pair[1].position,warptorio.GetTeleporterHazard(true) )) -- Boiler entry - --vector.LayTiles("hazard-concrete-left",f,vector.square(warptorio.Teleporters.b2.position,warptorio.GetTeleporterHazard(true))) -- next level - vector.LayTiles("hazard-concrete-left",f,vector.square(vector(-1,-1),vector(2,2))) -- beacon -end -function floor.tile(f) - local zt=floor.get_sizes() - local z=zt.size - - local rBoiler=research.level("warptorio-boiler") - local rLogs=research.level("warptorio-logistics") - local rWater=research.level("warptorio-boiler-water") - - local zf=z/3 - local zfx=math.floor(zf) + (zf%2==0 and 0 or 1) - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-0.5,-0.5),vector(zfx*2,(z*2)))) - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-0.5,-0.5),vector((z*2),zfx*2))) - - if(rWater>0)then - local zx=(rWater*2) - local vx=zfx+zx/2+1 - vector.LayTiles("deepwater",f,vector.square(vector(-0.5,-0.5)+vector(vx,vx),vector(zx,zx))) -- se - vector.LayTiles("deepwater",f,vector.square(vector(-0.5,-0.5)+vector(-vx,vx),vector(zx,zx))) -- sw - vector.LayTiles("deepwater",f,vector.square(vector(-0.5,-0.5)+vector(-vx,-vx),vector(zx,zx))) -- nw - vector.LayTiles("deepwater",f,vector.square(vector(-0.5,-0.5)+vector(vx,-vx),vector(zx,zx))) -- ne - end - local rgNorth=research.has("warptorio-boiler-n") - local rgSouth=research.has("warptorio-boiler-s") - local rgEast=research.has("warptorio-boiler-e") - local rgWest=research.has("warptorio-boiler-w") - - local zgWidth=96 - local zgHeight=64 - local zgLegHeight=12 - local zgLegWidth=10 - - if(rgNorth)then - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-1,-z-zgLegHeight-(zgHeight/2)-1),vector(zgWidth,zgHeight))) - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(9-1,-z-zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-9-1,-z-zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) - end if(rgSouth)then - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-1,z+zgLegHeight+(zgHeight/2)-1),vector(zgWidth,zgHeight))) - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(9-1,z+zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-9-1,z+zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) - end if(rgEast)then - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(z+zgLegHeight+(zgHeight/2)-1,-1),vector(zgHeight,zgWidth))) - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(z+zgLegHeight/2-1,9-1),vector(zgLegHeight,zgLegWidth))) - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(z+zgLegHeight/2-1,-9-1),vector(zgLegHeight,zgLegWidth))) - end if(rgWest)then - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-z-zgLegHeight-(zgHeight/2)-1,-1),vector(zgHeight,zgWidth))) - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-z-zgLegHeight/2-1,9-1),vector(zgLegHeight,zgLegWidth))) - vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-z-zgLegHeight/2-1,-9-1),vector(zgLegHeight,zgLegWidth))) - end - -end - - -function floor.technology(f) - -end -platform.floors.boiler=floor - - - - - ---[[ Empty surface cache ]]-- - -cache.surface("platform_factory",{ - raise=function(self) local f=self.host - - -- size=16 - end, -}) - -cache.surface("platform_harvester",{ - raise=function(self) local f=self.host - f.solar_power_multiplier=settings.global.warptorio_solar_multiplier.value - f.daytime=0 - f.always_day=true - f.request_to_generate_chunks({0,0},16) - f.force_generate_chunk_requests() - f.destroy_decoratives({}) - for k,v in pairs(f.find_entities())do entity.destroy(v) end - local area=vector.area(vector(-32*8,-32*8),vector(32*8*2,32*8*2)) - vector.LayTiles("out-of-map",f,area) - -- size=16 - end, -}) - -cache.surface("platform_boiler",{ - raise=function(self) local f=self.host - f.solar_power_multiplier=settings.global.warptorio_solar_multiplier.value - f.daytime=0 - f.always_day=true - f.request_to_generate_chunks({0,0},16) - f.force_generate_chunk_requests() - f.destroy_decoratives({}) - for k,v in pairs(f.find_entities())do entity.destroy(v) end - local area=vector.area(vector(-32*8,-32*8),vector(32*8*2,32*8*2)) - vector.LayTiles("out-of-map",f,area) - -- size=16 - end, -}) - - - ---[[ General Platform Stuff ]]-- - -function platform.PositionInPlatform(f,pos) local gf=global.floor - if(f==gf.factory.surface)then return true - elseif(f==gf.boiler.surface)then return true - elseif(f==gf.harvester.surface)then return true - end - -- Do overworld checks here - -end - -function platform.GetWarpables(c,cf) - -- warptorio.IsWarping=true - --local m=global.floor.main - --local c=m.host - local mt=platform.floors.main.get_sizes() - - local marea=vector.square(vector.pos({-0.5,-0.5}),vector(mt.size,mt.size)) - - -- find entities and players to copy/transfer to new surface - local tpply={} local cx=platform.corn - local etbl={} - for k,v in pairs(c.find_entities_filtered{type={"car","character","player"},invert=true,area=marea})do - local biterwarp=(warptorio.setting("biter_warping")==false) - if(v.type=="spider-vehicle")then - --local drv=v.get_driver() if(isvalid(drv))then drv.driving=nil v.set_driver(nil) end - table.insert(etbl,v) - elseif(v.type=="item-entity" or v.type=="character-corpse" or v.last_user or v.force.name=="player" or (biterwarp and v.force.name=="enemy"))then - table.insert(etbl,v) - end - end - - -- find players to teleport to new platform - for k,v in pairs(game.players)do if(not v.driving)then if(v.character==nil or (v.surface==c and vector.inarea(v.position,marea)))then - table.insert(tpply,{v,vector.pos(v.position)}) - end end end - - -- find cars to teleport to new platform - for k,v in pairs(c.find_entities_filtered{type={"car","tank"},area=marea})do if((v.surface==c and vector.inarea(v.position,marea)))then - table.insert(tpply,{v,vector.pos(v.position)}) - end end - - -- find entities/players on the corners - for k,v in pairs({"nw","ne","sw","se"})do local ugName="turret-"..v local rHas=research.has("warptorio-"..ugName.."-0") if(rHas)then local ug=research.level("warptorio-"..ugName) - local etc=cf.find_entities_filtered{position={cx[v].x+0.5,cx[v].y+0.5},radius=math.floor(10+ug*6)/2} for a,e in pairs(etc)do e.destroy() end -- clean new platform corner - - local etp=c.find_entities_filtered{type="character",position={cx[v].x+0.5,cx[v].y+0.5},radius=(10+(ug*6))/2} -- find corner players - for a,e in pairs(etp)do if(e.player and e.player.character~=nil and not e.driving)then table.insert(tpply,{e.player,{e.position.x,e.position.y}}) end end - - local etp=c.find_entities_filtered{type={"car","tank"},position={cx[v].x+0.5,cx[v].y+0.5},radius=(10+(ug*6))/2} -- find corner cars - for a,e in pairs(etp)do table.insert(tpply,{e,{e.position.x,e.position.y}}) end - - local et=c.find_entities_filtered{type={"car","character","tank"},invert=true,position={cx[v].x+0.5,cx[v].y+0.5},radius=math.floor((10+ug*6)/2)-(1e-6)} -- find corner ents - for k,v in pairs(et)do if(v.last_user or v.force.name=="player" or (biterwarp and v.force.name=="enemy"))then - table.insertExclusive(etbl,v) - end end - - end end - - return etbl,tpply -end - - - - - - -return platform - - +local platform={} +platform.name="classic" + +--[[ Offsets and stuff ]]-- + +platform.railCorner={nw=vector(-35,-35),ne=vector(34,-35),sw=vector(-35,34),se=vector(34,34)} +platform.railOffset={nw=vector(0,0),ne=vector(-1,0),sw=vector(0,-1),se=vector(-1,-1)} --{nw=vector(-1,-1),ne=vector(0,-1),sw=vector(-1,0),se=vector(0,0)} +platform.railLoader={nw=vector.area(vector(2,0),vector(0,2)),sw=vector.area(vector(2,0),vector(0,-2)),ne=vector.area(vector(-2,0),vector(0,2)),se=vector.area(vector(-2,0),vector(0,-2))} + +platform.letterOpposite={n=defines.direction.south,s=defines.direction.north,e=defines.direction.west,w=defines.direction.east} +platform.railLoaderPos={ + nw={vector(2,0),vector(2,-1),vector(0,2),vector(-1,2)}, + sw={vector(2,0),vector(2,-1),vector(0,-2),vector(-1,-2)}, + ne={vector(-2,0),vector(-2,-1),vector(0,2),vector(-1,2)}, + se={vector(-2,0),vector(-2,-1),vector(0,-2),vector(-1,-2)}, +} + +--platform.corner={nw=vector(-52,-52),ne=vector(50,-52),sw=vector(-52,50),se=vector(50,50)} -- old +platform.corner={nw=vector(-51.5,-51.5),ne=vector(50.5,-51.5),sw=vector(-51.5,50.5),se=vector(50.5,50.5)} + +platform.side={north=vector(0,-52),south=vector(0,51),east=vector(51,0),west=vector(-52,0)} +--[[ +local cirMaxWidth=128+8 +local cirHeight=17 --64+4 --17 -- +local vz=cirMaxWidth +--local ez=m.harvestSize or 10 -- harvester size max 47 +local hvMax=47 +local vzx=vz/2 local hvx=hvMax/2 local hvy=hvMax/8 + +local westPos=warptorio.platform.harvester.west --vector(-(vzx+(hvx-hvy))+0.5,-0.5) +local eastPos=warptorio.platform.harvester.east --vector(vzx+(hvx-hvy),-0.5) +]] +local hvSize=(128+8)/2 +local hvMax=47 +platform.harvester={} +platform.harvester.east=vector(85.5,-0.5) --hvSize+((hvMax/2)-(hvMax/8)),-0.5) -- 85.625 +platform.harvester.west=vector(-86.5,-0.5) -- -(hvSize+((hvMax/2)-(hvMax/8)))+0.5,-0.5) -- -85.125 -- was -86 + + +platform.corn={} +platform.corn.nw={x=-52,y=-52} +platform.corn.ne={x=50,y=-52} +platform.corn.sw={x=-52,y=50} +platform.corn.se={x=50,y=50} +platform.corn.north=-52 +platform.corn.south=50 +platform.corn.east=50 +platform.corn.west=-51.5 + + + +--[[ Floors ]]-- + +platform.floors={} + + +-- Todo: Make teleporters and specials automatically do hazard tiles + +--[[ Platform Technology Effects ]]-- + +platform.techs={} + +-- General technologies + +platform.techs.boiler_station={tech="warptorio-boiler-station",effect={special={"boiler"}},} +platform.techs.reactor={tech="warptorio-reactor",level_range={1,8},effect={reactor=true,special={"main"}}, } + +platform.techs.tele_portal={tech="warptorio-teleporter-portal",effect={unlock_teleporters={"offworld"},},} +platform.techs.tele_energy={tech="warptorio-teleporter",level_range={1,5},effect={upgrade_energy={"offworld"},},} +platform.techs.energy={tech="warptorio-energy",level_range={1,5},effect={upgrade_energy=true},} +platform.techs.logistics={tech="warptorio-logistics",level_range={1,4},effect={upgrade_logistics=true},} +platform.techs.warp_beacon={tech="warptorio-beacon",level_range={1,10},effect={special={"factory"},},} + +platform.techs.dualloader={tech="warptorio-dualloader-1",effect={upgrade_logistics=true},} +platform.techs.triloader={tech="warptorio-triloader",effect={upgrade_logistics=true},} + +platform.techs.accelerator={tech="warptorio-accelerator",effect={ability="accelerator"},} +platform.techs.stabilizer={tech="warptorio-stabilizer",effect={ability="stabilizer"},} +platform.techs.charting={tech="warptorio-charting",effect={ability="charting",special={"factory","boiler"}},} + + +platform.techs.alt_combinator={tech="warptorio-alt-combinator",effect={do_combinators=true},} + +platform.techs.homeworld={tech="warptorio-homeworld",effect={unlock_homeworld=true},} + +platform.techs.toolbar={tech="warptorio-toolbar",effect={unlock_toolbar=true}} + + + + +-- Platform Surface Techs +platform.techs.size={tech="warptorio-platform-size",effect={retile={"main"}}, +levels={ + [0]=8, + [1]=10+7-1, + [2]=18+7-1, + [3]=26+7-1, + [4]=40+7-1, + [5]=56+7-1+2, + [6]=74+7-1+2, + [7]=92+7-1+4, +}} + +platform.techs.railnw={tech="warptorio-rail-nw",effect={unlock_rails="nw"},} +platform.techs.railne={tech="warptorio-rail-ne",effect={unlock_rails="ne"},} +platform.techs.railsw={tech="warptorio-rail-sw",effect={unlock_rails="sw"},} +platform.techs.railse={tech="warptorio-rail-se",effect={unlock_rails="se"},} + +platform.techs.turret_nw={tech="warptorio-turret-nw",first_effect={unlock_teleporters={"main_tur_factory_nw"}},effect={retile={"main","factory"}},level_range={0,3},} +platform.techs.turret_ne={tech="warptorio-turret-ne",first_effect={unlock_teleporters={"main_tur_factory_ne"}},effect={retile={"main","factory"}},level_range={0,3},} +platform.techs.turret_sw={tech="warptorio-turret-sw",first_effect={unlock_teleporters={"main_tur_factory_sw"}},effect={retile={"main","factory"}},level_range={0,3},} +platform.techs.turret_se={tech="warptorio-turret-se",first_effect={unlock_teleporters={"main_tur_factory_se"}},effect={retile={"main","factory"}},level_range={0,3},} + + +-- Factory Techs + +platform.techs.factory_n={tech="warptorio-factory-n",effect={retile={"factory"}},} +platform.techs.factory_s={tech="warptorio-factory-s",effect={retile={"factory"}},} +platform.techs.factory_e={tech="warptorio-factory-e",effect={retile={"factory"}},} +platform.techs.factory_w={tech="warptorio-factory-w",effect={retile={"factory"}},} +platform.techs.bridgesize={tech="warptorio-bridgesize",level_range={1,2},effect={retile={"factory"}},} + + +platform.techs.factorysize={tech="warptorio-factory",effect={retile={"factory"}}, +first_effect={rehazard={"main"},unlock_teleporters={"main_to_factory"},}, +levels={ + [0]=19-1, + [1]=23-1, + [2]=31-1, + [3]=39-1, + [4]=47-1, + [5]=55-1, + [6]=63-1, + [7]=71+2-1, +}, +} + + +-- Boiler Techs + +platform.techs.boiler_water={tech="warptorio-boiler-water",level_range={1,3},effect={retile={"boiler"},},} + +platform.techs.boiler_n={tech="warptorio-boiler-n",effect={retile={"boiler"}},} +platform.techs.boiler_s={tech="warptorio-boiler-s",effect={retile={"boiler"}},} +platform.techs.boiler_e={tech="warptorio-boiler-e",effect={retile={"boiler"}},} +platform.techs.boiler_w={tech="warptorio-boiler-w",effect={retile={"boiler"}},} + + +platform.techs.boilersize={tech="warptorio-boiler", +first_effect={rehazard={"harvester"},unlock_teleporters={"harvester_to_boiler"}}, +effect={retile={"boiler"}}, +levels={ + [0]=18, + [1]=24, + [2]=32, + [3]=40, + [4]=48, + [5]=56, + [6]=64, + [7]=72, +}, +} + + +platform.techs.harvesterfloor={tech="warptorio-harvester-floor",effect={retile={"harvester"},unlock_teleporters={"factory_to_harvester"}}, +} +platform.techs.harvestersize={tech="warptorio-harvester-size",effect={retile={"harvester"},}, -- oval sizes +levels={ + [0]=vector(19,17), + [1]=vector(28,22), + [2]=vector(36,26), + [3]=vector(48,32), + [4]=vector(74,40), + [5]=vector(92,48), + [6]=vector(112,56), + [7]=vector(128+8,64), +}, +} +platform.techs.harvester_west={tech="warptorio-harvester-west",effect={harvesters={"west"}}, +levels={ + [1]=12, + [2]=20, + [3]=26, + [4]=32, + [5]=38, +}, +} +platform.techs.harvester_east={tech="warptorio-harvester-east",effect={harvesters={"east"}}, +levels={ + [1]=12, + [2]=20, + [3]=26, + [4]=32, + [5]=38, +}, +} + +--unused platform.techs.harvester_west_loader={tech="warptorio-harvester-west-loader",effect={harvesters={"west"}},} +--unused platform.techs.harvester_east_loader={tech="warptorio-harvester-east-loader",effect={harvesters={"east"}},} + + +--[[ Rails registers ]]-- + +platform.rails={} +local tpr={key="nw"} platform.rails[tpr.key]=tpr +tpr.railpos=platform.railCorner[tpr.key]+platform.railOffset[tpr.key] +tpr.chestpos=platform.railCorner[tpr.key] --+platform.railOffset[tpr.key] +tpr.floor="factory" +tpr.logs={false,true,true,false} + +local tpr={key="ne"} platform.rails[tpr.key]=tpr +tpr.railpos=platform.railCorner[tpr.key]+platform.railOffset[tpr.key] +tpr.chestpos=platform.railCorner[tpr.key] --+platform.railOffset[tpr.key] +tpr.floor="factory" +tpr.logs={false,false,true,true} + +local tpr={key="sw"} platform.rails[tpr.key]=tpr +tpr.railpos=platform.railCorner[tpr.key]+platform.railOffset[tpr.key] +tpr.chestpos=platform.railCorner[tpr.key] --+platform.railOffset[tpr.key] +tpr.floor="factory" +tpr.logs={true,true,false,false} + +local tpr={key="se"} platform.rails[tpr.key]=tpr +tpr.railpos=platform.railCorner[tpr.key]+platform.railOffset[tpr.key] +tpr.chestpos=platform.railCorner[tpr.key] --+platform.railOffset[tpr.key] +tpr.floor="factory" +tpr.logs={true,false,false,true} + + + + +--[[ Teleporter registers ]]-- + +platform.teleporters={} + +--[[ Offworld Teleporter ]]-- + +-- Offworld is special and has some special handling on its pair, e.g. the second pair doesn't get hazards and can be spawned freely because you can pick it up. +local tps={key="offworld"} platform.teleporters[tps.key]=tps +tps.logs=true -- this teleporter gains loaders on the first logistics upgrade +tps.dopipes=true -- this teleporter should be given pipes +tps.dualloader=false -- this teleporter gets an extra loader on the dualloader upgrade +tps.triloader=true -- this teleporter gets an extra loader on the triloader upgrade +tps.top=false -- this teleporter is a "top loader" used to determine loader direction via settings. +tps.circuit=false -- Should be false if the teleporter pair isn't in the same position. +tps.staticdir=false -- "up" or "down" if the logistics cannot have their direction changed with setting +tps.oneside=false -- If this teleporter is onesided, "left" or "right" +tps.rotated=false -- If true, this has logistics on top and bottom instead of left and right +tps.logiport=false -- Set to true if this is logistics only. +tps.energy="tele_energy" -- platform tech name + +tps.pair={ + {floor="main",position=vector(-1,5), + prototype="warptorio-teleporter", + }, + {floor="main",position=vector(-1,8), + prototype="warptorio-teleporter-gate", + gate=true, -- Logistics spawning behaviour flag + minable=true, -- Flag to pickup + destructible=true, -- Can be destroyed + } +} + + +--[[ Main Factory Teleporter ]]-- + +local tps={key="main_to_factory"} platform.teleporters[tps.key]=tps +tps.logs=true +tps.dopipes=true +tps.dualloader=true +tps.triloader=true +tps.top=true +tps.circuit=true +tps.staticdir=false +tps.oneside=false +tps.rotated=false +tps.logiport=false +tps.energy="energy" + +tps.pair={ + {floor="main",position=vector(-1,-7), + prototype="warptorio-underground", + sprite_arrow="down", + sprites={ + {sprite="technology/automation",target_offset={0,-0.25},x_scale=0.5,y_scale=0.5,tint={r=1,g=0.7,b=0.4,a=1}}, + }, + }, + {floor="factory",position=vector(-1,-7), + prototype="warptorio-underground", + sprite_arrow="up", + sprites={ + {sprite="technology/concrete",target_offset={0,-0.25},x_scale=0.5,y_scale=0.5,tint={r=1,g=0.7,b=0.4,a=1}}, + }, + } +} + +-- Main Turrets copy from Main Factory + +local kdir="nw" +local key="main_tur_factory_"..kdir +local tpv=table.deepcopy(tps) +tpv.dualloader=false +tpv.top=true +tpv.triloader=true +tpv.circuit=true +tpv.key=key platform.teleporters[key]=tpv +tpv.pair[1].position=platform.corner[kdir]-vector(0.5,0.5) +tpv.pair[2].position=platform.corner[kdir]-vector(0.5,0.5) +tpv.pair[1].sprites=nil +tpv.pair[2].sprites=nil + +local kdir="ne" +local key="main_tur_factory_"..kdir +local tpv=table.deepcopy(tps) +tpv.dualloader=false +tpv.top=true +tpv.triloader=true +tpv.circuit=true +tpv.key=key platform.teleporters[key]=tpv +tpv.pair[1].position=platform.corner[kdir]-vector(0.5,0.5) +tpv.pair[2].position=platform.corner[kdir]-vector(0.5,0.5) +tpv.pair[1].sprites=nil +tpv.pair[2].sprites=nil + +local kdir="sw" +local key="main_tur_factory_"..kdir +local tpv=table.deepcopy(tps) +tpv.dualloader=false +tpv.triloader=true +tpv.circuit=true +tpv.top=false +tpv.key=key platform.teleporters[key]=tpv +tpv.pair[1].position=platform.corner[kdir]-vector(0.5,0.5) +tpv.pair[2].position=platform.corner[kdir]-vector(0.5,0.5) +tpv.pair[1].sprites=nil +tpv.pair[2].sprites=nil + +local kdir="se" +local key="main_tur_factory_"..kdir +local tpv=table.deepcopy(tps) +tpv.dualloader=false +tpv.triloader=true +tpv.circuit=true +tpv.top=false +tpv.key=key platform.teleporters[key]=tpv +tpv.pair[1].position=platform.corner[kdir]-vector(0.5,0.5) +tpv.pair[2].position=platform.corner[kdir]-vector(0.5,0.5) +tpv.pair[1].sprites=nil +tpv.pair[2].sprites=nil + + +--[[ Factory to Harvester Teleporter ]]-- + +local tps={key="factory_to_harvester"} platform.teleporters[tps.key]=tps +tps.logs=true +tps.dopipes=true +tps.dualloader=true +tps.triloader=true +tps.top=false +tps.circuit=true +tps.staticdir=false +tps.oneside=false +tps.rotated=false +tps.logiport=false +tps.energy="energy" +tps.pair={ + {floor="factory",position=vector(-1,5), + prototype="warptorio-underground", + sprite_arrow="down", + sprites={ + {sprite="technology/tank",target_offset={0,-0.25},x_scale=0.5,y_scale=0.5,tint={r=1,g=0.7,b=0.4,a=1}}, + }, + }, + {floor="harvester",position=vector(-1,5), + prototype="warptorio-underground", + sprite_arrow="up", + sprites={ + {sprite="technology/automation",target_offset={0,-0.25},x_scale=0.5,y_scale=0.5,tint={r=1,g=0.7,b=0.4,a=1}}, + }, + } +} + + + +--[[ Harvester to Boiler Teleporter ]]-- + +local tps={key="harvester_to_boiler"} platform.teleporters[tps.key]=tps +tps.logs=true +tps.dopipes=true +tps.dualloader=true +tps.triloader=true +tps.top=true +tps.circuit=true +tps.staticdir=false +tps.oneside=false +tps.rotated=false +tps.logiport=false +tps.energy="energy" +tps.pair={ + {floor="harvester",position=vector(-1,-7), + prototype="warptorio-underground", + sprite_arrow="down", + sprites={ + {sprite="technology/fluid-handling",target_offset={0,-0.25},x_scale=0.5,y_scale=0.5,tint={r=1,g=0.7,b=0.4,a=1}} + }, + }, + {floor="boiler",position=vector(-1,-7), + prototype="warptorio-underground", + sprite_arrow="up", + sprites={ + + {sprite="technology/tank",target_offset={0,-0.25},x_scale=0.5,y_scale=0.5,tint={r=1,g=0.7,b=0.4,a=1}} + }, + } +} + + + + +--[[ Harvester registers ]]-- + +platform.HarvesterPointData={ + energy="energy", + pair={ + {floor="harvester",prototype="warptorio-harvestportal",minable=true,destructible=false}, + {floor="main",prototype="warptorio-harvestportal",minable=true,destructible=true,gate=true}, + }, +} + +platform.harvesters={} + +local hvs={key="west",position=platform.harvester.west} +hvs.energy="energy" +hvs.pad_prototype="warptorio-harvestpad-west" +hvs.prototype="warptorio-harvestportal" +hvs.tech="harvester_west" -- harvester size tech name, or.. +hvs.fixed_level=nil -- If this harvester is a fixed level +hvs.logs=true +hvs.dualloader=true +hvs.triloader=true +hvs.dopipes=true +hvs.pipes_pattern="east" --{east={{2},{2,-2},{2,-2}},} +hvs.logs_pattern="east" --{east={{0},{0,-1},{0,-1,1}},} -- Which side the logistics are on. Yes you can have on all 4 sides. +hvs.combinator_pattern="west" -- Which side the combinator is on. + +platform.harvesters.west=hvs + +local hvs={key="east",position=platform.harvester.east} +hvs.energy="energy" +hvs.pad_prototype="warptorio-harvestpad-east" +hvs.prototype="warptorio-harvestportal" +hvs.tech="harvester_east" +hvs.fixed_level=nil +hvs.logs=true +hvs.dualloader=true +hvs.triloader=true +hvs.dopipes=true +hvs.pipes_pattern="west" --{west={{2},{2,-2},{2,-2}},} +hvs.logs_pattern="west" --{west={{0},{0,-1},{0,-1,1}},} -- Which side the logistics are on. +hvs.combinator_pattern="east" -- Which side the combinator is on. No patterns, dont put logistics over it. + + +platform.harvesters.east=hvs + +-- No gigas yet + + +--[[ Homeworld ]]-- + +local floor={key="home"} -- Special key doesnt need a name +floor.empty=false +floor.radar=false +floor.special=nil +floor.migrate_tile=nil +platform.floors.home=floor + + + +--[[ Main Floor (Planet Surface) ]]-- + +local floor={key="main"} -- Special key doesnt need a name +floor.empty=false +floor.radar=false +floor.special={tech="warptorio-reactor-6",prototype="warptorio-reactor",size=vector(4,4),destructible=true} --vector.clean(f,vector.square(vector(-0.5,-0.5),vector(5,5))) +floor.migrate_tile=nil -- A tile that will never appear during default tile & hazard placement, excluding harvesters (special handling on them). nil=no migration + + +function floor.get_sizes() local t={} + t.size=warptorio.GetPlatformTechAmount("size") -- research.level etc +return t end + + +function floor.tile(f,b_void) + local zt=floor.get_sizes() + local z=zt.size or 8 + + local tiler="warp-tile-concrete" if(b_void)then tiler="out-of-map" end + + local area=vector.square(vector(-0.5,-0.5),vector(z,z)) + vector.clearFiltered(f,area) + vector.LayTiles(tiler,f,area) + + local rSize=research.level("warptorio-platform-size") + local rLogs=research.level("warptorio-logistics") + local rFacSize=research.level("warptorio-factory") + local rTpGate=research.has("warptorio-teleporter-portal") + + for u,c in pairs(platform.corner)do + local lvc=research.level("warptorio-turret-"..u.."") + if(research.has("warptorio-turret-"..u.."-0"))then local rad=math.floor((10+lvc*6)) + for k,v in pairs(f.find_entities_filtered{type="character",force={game.forces.player,game.forces.enemy},invert=true,position=c,radius=rad/2})do entity.tryclean(v) end + vector.LayCircle(tiler,f,vector.circleEx(c,rad)) + end + end +end +function floor.hazard(f) + local zt=floor.get_sizes() + local z=zt.size or 8 + + local area=vector.square(vector(-0.5,-0.5),vector(z,z)) + vector.LayTiles("hazard-concrete-left",f,vector.square(vector(-1,-1),vector(4,4))) + + local rSize=research.level("warptorio-platform-size") + --local rLogs=research.level("warptorio-logistics") + local rFacSize=research.level("warptorio-factory") + local rFac=research.has("warptorio-factory-0") + local rTpGate=research.has("warptorio-teleporter-portal") + + if(rSize>0)then local ltm,ltp + ltm=warptorio.GetTeleporterHazard(true,rFac) + ltp=warptorio.GetTeleporterHazard(false,rTpGate) + vector.LayTiles("hazard-concrete-left",f,vector.square(platform.teleporters["main_to_factory"].pair[1].position,ltm)) + vector.LayTiles("hazard-concrete-left",f,vector.square(platform.teleporters["offworld"].pair[1].position,ltp)) + end + if(rSize>=6)then for k,v in pairs(platform.railCorner)do local o=platform.railOffset[k] vector.LayTiles("hazard-concrete-left",f,vector.square(v+o,vector(1,1))) end end -- trains + + for u,c in pairs(platform.corner)do + local lvc=research.level("warptorio-turret-"..u.."") + if(research.has("warptorio-turret-"..u.."-0"))then local rad=math.floor((10+lvc*6)) + vector.LayTiles("hazard-concrete-left",f,vector.square(c,warptorio.GetTeleporterHazard(false))) + end + end +end + +function floor.technology(f) -- Check/re-apply technology-effects + +end +platform.floors.main=floor + + +--[[ Factory Floor ]]-- + +local floor={key="factory",name="warptorio_factory"} +floor.empty=true +floor.radar=true +floor.special={tech="warptorio-beacon",upgrade=true,prototype="warptorio-beacon",size=vector(2,2)} +floor.migrate_tile="grass-1" -- A tile that will never appear during default tile & hazard placement, excluding harvesters (special handling on them). nil=no migration + +function floor.get_sizes() local t={} + t.size=warptorio.GetPlatformTechAmount("factorysize") -- research.level etc +return t end + +function floor.tile(f) + local zt=floor.get_sizes() + local z=zt.size + + local area=vector.square(vector(-0.5,-0.5),vector(z,z)) + local rFacSize=research.level("warptorio-factory") + local rBoiler=research.has("warptorio-boiler-1") + local rLogs=research.level("warptorio-logistics") + local rBridge=research.level("warptorio-bridgesize") + vector.LayTiles("warp-tile-concrete",f,area) + + local rc={} for k in pairs(platform.corner)do local rclv=research.level("warptorio-turret-"..k) if(rclv>0 or research.has("warptorio-turret-"..k.."-0"))then rc[k]=rclv end end + local zMainWidth=10+rBridge*2 + local zMainHeight=59+rBridge*2-2 + local zLeg=6+rBridge*4 + local whas=(rc.nw or rc.sw) local nhas=(rc.nw or rc.ne) local ehas=(rc.ne or rc.se) local shas=(rc.sw or rc.se) + if(nhas)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-0.5,platform.side.north.y/2),vector(zMainWidth,zMainHeight))) end + if(shas)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-0.5,platform.side.south.y/2-0.5),vector(zMainWidth,zMainHeight))) end + if(ehas)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.east.x/2-0.5,-0.5),vector(zMainHeight,zMainWidth))) end + if(whas)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.west.x/2,-0.5),vector(zMainHeight,zMainWidth))) end + if(nhas and rc.nw)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.west.x/2,platform.side.north.y),vector(zMainHeight,zLeg))) end + if(nhas and rc.ne)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.east.x/2,platform.side.north.y),vector(zMainHeight,zLeg))) end + if(shas and rc.sw)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.west.x/2,platform.side.south.y-0.5),vector(zMainHeight,zLeg))) end + if(shas and rc.se)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.east.x/2,platform.side.south.y-0.5),vector(zMainHeight,zLeg))) end + if(ehas and rc.ne)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.east.x-0.5,platform.side.north.y/2),vector(zLeg,zMainHeight))) end + if(ehas and rc.se)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.east.x-0.5,platform.side.south.y/2),vector(zLeg,zMainHeight))) end + if(whas and rc.nw)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.west.x,platform.side.north.y/2),vector(zLeg,zMainHeight))) end + if(whas and rc.sw)then vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.west.x,platform.side.south.y/2),vector(zLeg,zMainHeight))) end + + for k,c in pairs(platform.corner)do if(rc[k])then local zx=(10+rc[k]*6) + vector.LayTiles("warp-tile-concrete",f,vector.square(c,vector(zx,zx))) vector.LayTiles("hazard-concrete-left",f,vector.square(c,warptorio.GetTeleporterHazard(false))) + end end + + local zgWidth=128-16 + local zgHeight=96-12 + local zgLegHeight=17 + local zgLegWidth=10 + + if(research.has("warptorio-factory-n"))then + vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.north+vector(-1,-zgLegHeight-zgHeight/2-1),vector(zgWidth,zgHeight))) + vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.north+vector(9-1,-zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) + vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.north+vector(-9-1,-zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) + end if(research.has("warptorio-factory-s"))then + vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.south+vector(-1,zgLegHeight+zgHeight/2),vector(zgWidth,zgHeight))) + vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.south+vector(9-1,zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) + vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.south+vector(-9-1,zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) + end if(research.has("warptorio-factory-w"))then + vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.west+vector(-zgLegHeight-zgHeight/2-1,-1),vector(zgHeight,zgWidth))) + vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.west+vector(-zgLegHeight/2-1,9-1),vector(zgLegHeight,zgLegWidth))) + vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.west+vector(-zgLegHeight/2-1,-9-1),vector(zgLegHeight,zgLegWidth))) + end if(research.has("warptorio-factory-e"))then + vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.east+vector(zgLegHeight+zgHeight/2,-1),vector(zgHeight,zgWidth))) + vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.east+vector(zgLegHeight/2-1,9-1),vector(zgLegHeight,zgLegWidth))) + vector.LayTiles("warp-tile-concrete",f,vector.square(platform.side.east+vector(zgLegHeight/2-1,-9-1),vector(zgLegHeight,zgLegWidth))) + end + +end + +function floor.hazard(f) + local zt=floor.get_sizes() + local z=zt.size + local area=vector.square(vector(-0.5,-0.5),vector(z,z)) + local rFac=research.has("warptorio-factory-0") + local rFacSize=research.level("warptorio-factory") + local rBoiler=research.has("warptorio-boiler-1") + local rHarv=research.has("warptorio-harvester-floor") + local rLogs=research.level("warptorio-logistics") + local rBridge=research.level("warptorio-bridgesize") + + if(rFacSize>=7)then for k,rv in pairs(platform.railOffset)do local rc=platform.railCorner[k] -- trains + local rvx=platform.railLoader[k] + vector.LayTiles("hazard-concrete-left",f,vector.square(vector(rc.x,rc.y),vector(1,1))) + vector.LayTiles("hazard-concrete-left",f,vector.square(vector(rc.x+rvx[1][1],rc.y+rvx[1][2]),vector(1,1))) + vector.LayTiles("hazard-concrete-left",f,vector.square(vector(rc.x+rvx[2][1],rc.y+rvx[2][2]),vector(1,1))) + end end + + vector.LayTiles("hazard-concrete-left",f,vector.square(platform.teleporters["factory_to_harvester"].pair[1].position, -- factory to harvester + (warptorio.GetTeleporterHazard(true,rHarv)) + )) + + vector.LayTiles("hazard-concrete-left",f,vector.square(platform.teleporters["main_to_factory"].pair[1].position, -- planet to factory + (warptorio.GetTeleporterHazard(true,rFac) ) + )) + vector.LayTiles("hazard-concrete-left",f,vector.square(vector(-0.5,-0.5),vector(2,2))) +end + +function floor.technology(f) + +end +platform.floors.factory=floor + + + +--[[ Harvester Floor ]]-- + +local floor={key="harvester",name="warptorio_harvester"} +floor.empty=true +floor.radar=false +floor.special=nil -- no special for harvester +floor.migrate_tile="grass-1" -- A tile that will never appear during default tile & hazard placement, excluding harvesters (special handling on them). nil=no migration + + +function floor.BuildHarvestCorner(f,cz,k,v) -- for giga harvesters unused + if(research.has("warptorio-harvester-"..k.."-gate"))then + vector.LayTiles("warp-tile-concrete",f,vector.square(v/3*2,vector(cz*1.25,cz*1.25))) + vector.LayTiles("warptorio-red-concrete",f,vector.square(v/3*2,vector(cz,cz))) + vector.LayTiles("hazard-concrete-left",f,vector.square((v/3*2),vector(2,2))) + end +end + + +function floor.get_sizes() local t={} + t.size=16 -- research.level etc + t.ovalsize=warptorio.GetPlatformTechAmount("harvestersize") or vector(22,17) +return t end + +function floor.hazard(f) + local zt=floor.get_sizes() + local z=zt.size + + --local rLogs=research.level("warptorio-logistics") + local rBoiler=research.has("warptorio-boiler-0") + + local bpair=platform.teleporters["factory_to_harvester"].pair + local apair=platform.teleporters["harvester_to_boiler"].pair + vector.LayTiles("hazard-concrete-left",f,vector.square(apair[1].position,(warptorio.GetTeleporterHazard(true,rBoiler)) )) -- harvester to boiler + vector.LayTiles("hazard-concrete-left",f,vector.square(bpair[1].position,warptorio.GetTeleporterHazard(true))) -- factory to harvester + --vector.LayTiles("hazard-concrete-left",f,vector.square(vector(-1,-1),vector(2,2))) -- beacon +end + +function floor.tile(f) + local zt=floor.get_sizes() + local z=zt.size + + + local cirMaxWidth=128+8 + local cirHeight=17 --64+4 --17 -- + + local minCir=vector(22,17) + local maxCir=vector(128+8,64+4) + local ovSize=vector(vector.getx(zt.ovalsize),vector.gety(zt.ovalsize)) -- vector(cirWidth,cirHeight) + + vector.LayCircle("warp-tile-concrete",f,vector.oval(vector(-1,-1),ovSize)) + + +--[[ for 4 corners -- unfinished + + --local zx=(platform.side.east.x+platform.side.west.x)/3*2 + --vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.east.x/3*2,-1),vector(6,platform.side.south.y+3))) + --vector.LayTiles("warp-tile-concrete",f,vector.square(vector(platform.side.west.x/3*2,-1),vector(6,platform.side.south.y+3))) + local cz=16 + for k,v in pairs(platform.corner)do warptorio.BuildHarvestCorner(cz,k,v) end +]] + + +end + +function floor.technology(f) + +end + +floor.BuildHarvester={} +floor.BuildHarvester.west=function(f) + local zt=floor.get_sizes() + local z=zt.size + + local lvWest=research.level("warptorio-harvester-west") + if(lvWest>0)then + local ez=warptorio.GetHarvesterLevelSizeNum(lvWest) + local vz=128+8 local hvMax=47 local vzx=vz/2 local hvx=hvMax/2 local hvy=hvMax/8 + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-1-vz/3,-1),vector(vz/2+(hvMax/2.5)-ez/2,4+((lvWest-1)*2 ))) ) -- west bridge + end +end +floor.BuildHarvester.east=function(f) + local zt=floor.get_sizes() + local z=zt.size + + + + local lvEast=research.level("warptorio-harvester-east") + if(lvEast>0)then + local ez=warptorio.GetHarvesterLevelSizeNum(lvEast) + local vz=128+8 local hvMax=47 local vzx=vz/2 local hvx=hvMax/2 local hvy=hvMax/8 + local vecSize=vector( (vz/2+(hvMax/2.5)-ez/2),4+((lvEast-1)*2)) + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-1+vz/3,-1), vecSize)) -- east bridge + end +end + +platform.floors.harvester=floor + + + + + + +--[[ Boiler Floor ]]-- + +local floor={key="boiler",name="warptorio_boiler"} +floor.empty=true +floor.radar=true +floor.special={tech="warptorio-boiler-station",prototype="warptorio-warpstation",size=vector(2,2)} +floor.migrate_tile="grass-1" -- A tile that will never appear during default tile & hazard placement, excluding harvesters (special handling on them). nil=no migration + +function floor.get_sizes() local t={} + t.size=warptorio.GetPlatformTechAmount("boilersize") or 17 -- research.level etc + --error(serpent.block(warptorio.platform.techs.boilersize)) +return t end + +function floor.hazard(f) + local zt=floor.get_sizes() + local z=zt.size + + local rBoiler=research.level("warptorio-boiler") + local rLogs=research.level("warptorio-logistics") + local rWater=research.level("warptorio-boiler-water") + + vector.LayTiles("hazard-concrete-left",f,vector.square(platform.teleporters["harvester_to_boiler"].pair[1].position,warptorio.GetTeleporterHazard(true) )) -- Boiler entry + --vector.LayTiles("hazard-concrete-left",f,vector.square(warptorio.Teleporters.b2.position,warptorio.GetTeleporterHazard(true))) -- next level + vector.LayTiles("hazard-concrete-left",f,vector.square(vector(-1,-1),vector(2,2))) -- beacon +end +function floor.tile(f) + local zt=floor.get_sizes() + local z=zt.size + + local rBoiler=research.level("warptorio-boiler") + local rLogs=research.level("warptorio-logistics") + local rWater=research.level("warptorio-boiler-water") + + local zf=z/3 + local zfx=math.floor(zf) + (zf%2==0 and 0 or 1) + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-0.5,-0.5),vector(zfx*2,(z*2)))) + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-0.5,-0.5),vector((z*2),zfx*2))) + + if(rWater>0)then + local zx=(rWater*2) + local vx=zfx+zx/2+1 + vector.LayTiles("deepwater",f,vector.square(vector(-0.5,-0.5)+vector(vx,vx),vector(zx,zx))) -- se + vector.LayTiles("deepwater",f,vector.square(vector(-0.5,-0.5)+vector(-vx,vx),vector(zx,zx))) -- sw + vector.LayTiles("deepwater",f,vector.square(vector(-0.5,-0.5)+vector(-vx,-vx),vector(zx,zx))) -- nw + vector.LayTiles("deepwater",f,vector.square(vector(-0.5,-0.5)+vector(vx,-vx),vector(zx,zx))) -- ne + end + local rgNorth=research.has("warptorio-boiler-n") + local rgSouth=research.has("warptorio-boiler-s") + local rgEast=research.has("warptorio-boiler-e") + local rgWest=research.has("warptorio-boiler-w") + + local zgWidth=96 + local zgHeight=64 + local zgLegHeight=12 + local zgLegWidth=10 + + if(rgNorth)then + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-1,-z-zgLegHeight-(zgHeight/2)-1),vector(zgWidth,zgHeight))) + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(9-1,-z-zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-9-1,-z-zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) + end if(rgSouth)then + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-1,z+zgLegHeight+(zgHeight/2)-1),vector(zgWidth,zgHeight))) + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(9-1,z+zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-9-1,z+zgLegHeight/2-1),vector(zgLegWidth,zgLegHeight))) + end if(rgEast)then + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(z+zgLegHeight+(zgHeight/2)-1,-1),vector(zgHeight,zgWidth))) + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(z+zgLegHeight/2-1,9-1),vector(zgLegHeight,zgLegWidth))) + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(z+zgLegHeight/2-1,-9-1),vector(zgLegHeight,zgLegWidth))) + end if(rgWest)then + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-z-zgLegHeight-(zgHeight/2)-1,-1),vector(zgHeight,zgWidth))) + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-z-zgLegHeight/2-1,9-1),vector(zgLegHeight,zgLegWidth))) + vector.LayTiles("warp-tile-concrete",f,vector.square(vector(-z-zgLegHeight/2-1,-9-1),vector(zgLegHeight,zgLegWidth))) + end + +end + + +function floor.technology(f) + +end +platform.floors.boiler=floor + + + + + +--[[ Empty surface cache ]]-- + +cache.surface("platform_factory",{ + raise=function(self) local f=self.host + + -- size=16 + end, +}) + +cache.surface("platform_harvester",{ + raise=function(self) local f=self.host + f.solar_power_multiplier=settings.global.warptorio_solar_multiplier.value + f.daytime=0 + f.always_day=true + f.request_to_generate_chunks({0,0},16) + f.force_generate_chunk_requests() + f.destroy_decoratives({}) + for k,v in pairs(f.find_entities())do entity.destroy(v) end + local area=vector.area(vector(-32*8,-32*8),vector(32*8*2,32*8*2)) + vector.LayTiles("out-of-map",f,area) + -- size=16 + end, +}) + +cache.surface("platform_boiler",{ + raise=function(self) local f=self.host + f.solar_power_multiplier=settings.global.warptorio_solar_multiplier.value + f.daytime=0 + f.always_day=true + f.request_to_generate_chunks({0,0},16) + f.force_generate_chunk_requests() + f.destroy_decoratives({}) + for k,v in pairs(f.find_entities())do entity.destroy(v) end + local area=vector.area(vector(-32*8,-32*8),vector(32*8*2,32*8*2)) + vector.LayTiles("out-of-map",f,area) + -- size=16 + end, +}) + + + +--[[ General Platform Stuff ]]-- + +function platform.PositionInPlatform(f,pos) local gf=storage.floor + if(f==gf.factory.surface)then return true + elseif(f==gf.boiler.surface)then return true + elseif(f==gf.harvester.surface)then return true + end + -- Do overworld checks here + +end + +function platform.GetWarpables(c,cf) + -- warptorio.IsWarping=true + --local m=storage.floor.main + --local c=m.host + local mt=platform.floors.main.get_sizes() + + local marea=vector.square(vector.pos({-0.5,-0.5}),vector(mt.size,mt.size)) + + -- find entities and players to copy/transfer to new surface + local tpply={} local cx=platform.corn + local etbl={} + for k,v in pairs(c.find_entities_filtered{type={"car","character","player"},invert=true,area=marea})do + local biterwarp=(warptorio.setting("biter_warping")==false) + if(v.type=="spider-vehicle")then + --local drv=v.get_driver() if(isvalid(drv))then drv.driving=nil v.set_driver(nil) end + table.insert(etbl,v) + elseif(v.type=="item-entity" or v.type=="character-corpse" or v.last_user or v.force.name=="player" or (biterwarp and v.force.name=="enemy"))then + table.insert(etbl,v) + end + end + + -- find players to teleport to new platform + for k,v in pairs(game.players)do if(not v.driving)then if(v.character==nil or (v.surface==c and vector.inarea(v.position,marea)))then + table.insert(tpply,{v,vector.pos(v.position)}) + end end end + + -- find cars to teleport to new platform + for k,v in pairs(c.find_entities_filtered{type={"car","tank"},area=marea})do if((v.surface==c and vector.inarea(v.position,marea)))then + table.insert(tpply,{v,vector.pos(v.position)}) + end end + + -- find entities/players on the corners + for k,v in pairs({"nw","ne","sw","se"})do local ugName="turret-"..v local rHas=research.has("warptorio-"..ugName.."-0") if(rHas)then local ug=research.level("warptorio-"..ugName) + local etc=cf.find_entities_filtered{position={cx[v].x+0.5,cx[v].y+0.5},radius=math.floor(10+ug*6)/2} for a,e in pairs(etc)do e.destroy() end -- clean new platform corner + + local etp=c.find_entities_filtered{type="character",position={cx[v].x+0.5,cx[v].y+0.5},radius=(10+(ug*6))/2} -- find corner players + for a,e in pairs(etp)do if(e.player and e.player.character~=nil and not e.driving)then table.insert(tpply,{e.player,{e.position.x,e.position.y}}) end end + + local etp=c.find_entities_filtered{type={"car","tank"},position={cx[v].x+0.5,cx[v].y+0.5},radius=(10+(ug*6))/2} -- find corner cars + for a,e in pairs(etp)do table.insert(tpply,{e,{e.position.x,e.position.y}}) end + + local et=c.find_entities_filtered{type={"car","character","tank"},invert=true,position={cx[v].x+0.5,cx[v].y+0.5},radius=math.floor((10+ug*6)/2)-(1e-6)} -- find corner ents + for k,v in pairs(et)do if(v.last_user or v.force.name=="player" or (biterwarp and v.force.name=="enemy"))then + table.insertExclusive(etbl,v) + end end + + end end + + return etbl,tpply +end + + + + + + +return platform + + diff --git a/data-updates.lua b/data-updates.lua index db12ae3..83d3891 100644 --- a/data-updates.lua +++ b/data-updates.lua @@ -73,7 +73,7 @@ local entIgnore={ "big-electric-pole", } - +--[[ local s="" for u,n in pairs(entTbl)do for k,v in pairs(data.raw[n])do @@ -90,4 +90,4 @@ for u,n in pairs(entTbl)do end end --error(s) - +]]-- diff --git a/data.lua b/data.lua index e94781d..e3d20ce 100644 --- a/data.lua +++ b/data.lua @@ -1,21 +1,21 @@ require("lib/lib") -local reqpth="prototypes/" +local reqpth = "prototypes/" --require("technology/warp-technology") require("sound/sound") -require(reqpth.."data_warptorio-heatpipe") -require(reqpth.."data_warptorio-warpport") -require(reqpth.."data_warptorio-logistics-pipe") -require(reqpth.."data_warptorio-warpstation") -require(reqpth.."data_warpnuke") -require(reqpth.."data_warptorio-warploader") -require(reqpth.."data_warptorio-townportal") -require(reqpth.."data_warptorio-combinator") -require(reqpth.."data_warptorio-warpspider") +require(reqpth .. "data_warptorio-heatpipe") +require(reqpth .. "data_warptorio-warpport") +require(reqpth .. "data_warptorio-logistics-pipe") +require(reqpth .. "data_warptorio-warpstation") +require(reqpth .. "data_warpnuke") +require(reqpth .. "data_warptorio-warploader") +require(reqpth .. "data_warptorio-townportal") +require(reqpth .. "data_warptorio-combinator") +require(reqpth .. "data_warptorio-warpspider") --require("data_nauvis_preset") --require("data_accumulators") -- This would be included here if it weren't for factorioextended ruining the accumulator tables >:| require("data_warptorio") -lib.lua() \ No newline at end of file +lib.lua() diff --git a/data_warptorio.lua b/data_warptorio.lua index 0f531c1..c79e0c0 100644 --- a/data_warptorio.lua +++ b/data_warptorio.lua @@ -1,769 +1,1452 @@ - -local function istable(t) return type(t)=="table" end -local function rgb(r,g,b,a) a=a or 255 return {r=r/255,g=g/255,b=b/255,a=a/255} end - -function table.deepmerge(s,t) for k,v in pairs(t)do if(istable(v) and s[k] and istable(s[k]))then table.deepmerge(s[k],v) else s[k]=v end end end -function table.merge(s,t) local x={} for k,v in pairs(s)do x[k]=v end for k,v in pairs(t)do x[k]=v end return x end -local function MakeDataCopy(a,b,x) local t=table.deepcopy(data.raw[a][b]) if(x)then table.deepmerge(t,x) end return t end -local function ExtendRecipeItem(t) - local r=table.deepcopy(data.raw.recipe["nuclear-reactor"]) - r.enabled=false r.name=t.name r.ingredients={{"steel-plate",1}} r.result=t.name - local i=table.deepcopy(data.raw.item["nuclear-reactor"]) - i.name=t.name i.place_result=t.name - data:extend{i,r} -end -local function ExtendRecipeItemFix(t) t.order=t.order or "warptorio" end -local function ExtendDataCopy(a,b,x,ri,tx) local t=MakeDataCopy(a,b,x) if(tx)then for k,v in pairs(tx)do if(v==false)then t[k]=nil else t[k]=v end end end if(ri)then ExtendRecipeItemFix(t) end data:extend{t} return t end - -local function ExtendCopyRecipe(src,name) - local r=table.deepcopy( data.raw.recipe[src] ) - r.enabled=false r.name=name r.ingredients={{"steel-plate",1}} r.result=name - local i=table.deepcopy( data.raw.recipe[src] ) - i.name=name i.place_result=name - data:extend{i,r} -end - -local techPacks={red="automation-science-pack",green="logistic-science-pack",blue="chemical-science-pack",black="military-science-pack", - purple="production-science-pack",yellow="utility-science-pack",white="space-science-pack"} - -local function SciencePacks(x) local t={} for k,v in pairs(x)do table.insert(t,{techPacks[k],v}) end return t end -local function ExtendTech(t,d,s) local x=table.merge(t,d) if(s)then x.unit.ingredients=SciencePacks(s) end data:extend{x} return x end - ---[[ -local t=ExtendDataCopy("electric-pole","small-electric-pole",{name="warptorio-electric-pole", - pictures={layers={[1]={tint={r=0.6,g=0.6,b=1,a=1},hr_version={tint={r=0.6,g=0.6,b=1,a=1}} }, }}, -},true) -]] - - --- -------- --- vonNeumann compatability. It's base game stuff anyway. Perhaps expand on this later - --- data.raw.lab["crash-site-lab-repaired"].minable={mining_time=3,result="crash-site-lab-repaired"} --- data.raw.container["crash-site-chest-1"].minable={mining_time=3,result="crash-site-chest-1"} --- data.raw.container["crash-site-chest-2"].minable={mining_time=3,result="crash-site-chest-2"} --- data.raw["assembling-machine"]["crash-site-assembling-machine-1-repaired"].minable={mining_time=3,result="crash-site-assembling-machine-1-repaired"} --- data.raw["assembling-machine"]["crash-site-assembling-machine-2-repaired"].minable={mining_time=3,result="crash-site-assembling-machine-2-repaired"} - - - - - - --- -------- --- Warp Tiles - --- purple tiles -local t=ExtendDataCopy("tile","tutorial-grid",{name="warp-tile-concrete",tint={r=0.6,g=0.6,b=0.7,a=1},layer=99,decorative_removal_probability=1,walking_speed_modifier=1.6,map_color={r=0.2,g=0.1,b=0.25,a=1}}) - --- orange tiles -local t=ExtendDataCopy("tile","tutorial-grid",{name="warptorio-red-concrete",tint={r=1,g=0.5,b=0,a=0.25},layer=67,decorative_removal_probability=1,walking_speed_modifier=1.5,map_color={r=0.2,g=0.1,b=0,a=1}}) - --- -------- --- Invisiradar -local rtint={r=0.4,g=0.4,b=1,a=1} -local rvtint={scale=1/3,shift={0.03125/3,-0.5/3},tint={r=1,g=1,b=1,a=0},hr_version={scale=0.5/3,tint={r=1,g=1,b=1,a=0},shift={0.03125/3,-0.5/3}}} -local r=ExtendDataCopy("radar","radar",{name="warptorio-invisradar", - icons={{icon="__base__/graphics/icons/radar.png",tint=rtint}},integration_patch=rvtint,pictures={layers={rvtint,rvtint}}, -},true,{energy_per_nearby_scan="10kJ",energy_per_sector="200kJ",energy_usage="1kW", icon=false, - max_distance_of_nearby_sector_revealed=5,max_distance_of_sector_revealed=18, - collision_box={{-1.2/3,-1.2/3},{1.2/3,1.2/3}},selection_box={{-1.5/3,-1.5/3},{1.5/3,1.5/3}}, -}) - - --- -------- --- Loot Chest - -local rtint={r=0.4,g=0.4,b=1,a=1} -local t=ExtendDataCopy("container","wooden-chest",{name="warptorio-lootchest",inventory_size=8, - icons={{icon="__base__/graphics/icons/wooden-chest.png",tint=rtint}}, - picture={layers={ [1]={tint=rtint,hr_version={tint=rtint}}, }}, -},true,{icon=false,minable={mining_time=0.1}}) - - --- -------- --- Carebear Chest - -local rtint=rgb(255,20,147) -local t=ExtendDataCopy("container","wooden-chest",{name="warptorio-carebear-chest",inventory_size=99, - icons={{icon="__base__/graphics/icons/wooden-chest.png",tint=rtint}}, - picture={layers={ [1]={tint=rtint,hr_version={tint=rtint}}, }}, -},true,{icon=false,minable={mining_time=10}}) - - - --- ---- --- Logistics - ---[[ -local rtint={r=0.5,g=0.5,b=1,a=1} -local rtintpic={tint=rtint,hr_version={tint=rtint}} -local rctint={r=0.39,g=0,b=0,a=1} -local rtintcov={layers={ [1]={tint=rctint,hr_version={tint=rctint}} }} -local t=ExtendDataCopy("pipe-to-ground","pipe-to-ground",{name="warptorio-logistics-pipe",fluid_box={base_area=5,pipe_connections={[2]={max_underground_distance=-1}}}, - pictures={ left=rtintpic, right=rtintpic,up=rtintpic,down=rtintpic }, - pipe_covers={ east={layers={ [1]={tint=rctint,hr_version={tint=rctint}} }}, north=rtintcov, south=rtintcov, west=rtintcov,} -},true) -]] - --- -------- --- Warp Reactor - --- Fuel -data:extend{{type="fuel-category", name="warp"}} - -ExtendDataCopy("item","uranium-fuel-cell",{name="warptorio-warponium-fuel-cell",fuel_category="warp",burnt_result="uranium-fuel-cell",fuel_value="32GJ",stack_size=50, - icon_size=64,icons={ {icon="__base__/graphics/icons/uranium-fuel-cell.png",tint={r=1,g=0.2,b=1,a=0.8}}, }, },false,{icon=false}) - -ExtendDataCopy("recipe","uranium-fuel-cell",{name="warptorio-warponium-fuel-cell",enabled=false,result="warptorio-warponium-fuel-cell",result_count=1},false, - {ingredients={{"uranium-fuel-cell",5}}, - icon_size=64,icons={ {icon="__base__/graphics/icons/uranium-fuel-cell.png",tint={r=1,g=0.2,b=1,a=0.8}}, }, -},false,{icon=false}) - -ExtendDataCopy("item","nuclear-fuel",{name="warptorio-warponium-fuel",fuel_category="chemical", - fuel_acceleration_multiplier=5,fuel_value="7GJ",stack_size=1,fuel_top_speed_multiplier=1.25, - icon_size=64,icons={ {icon="__base__/graphics/icons/nuclear-fuel.png",tint={r=1,g=0.2,b=1,a=0.8}}, }, -},false,{icon=false}) - -ExtendDataCopy("recipe","nuclear-fuel",{name="warptorio-warponium-fuel",enabled=false,result="warptorio-warponium-fuel",result_count=1},false, - {ingredients={{"warptorio-warponium-fuel-cell",1},{"nuclear-fuel",1}}, - icon=false,icon_size=64,icons={ {icon="__base__/graphics/icons/nuclear-fuel.png",tint={r=1,g=0.2,b=1,a=0.8}}, }, -}) - - --- The Reactor Itself -local t=ExtendDataCopy("reactor","nuclear-reactor",{name="warptorio-reactor",max_health=5000,neighbour_bonus=12,consumption="160MW", - energy_source={fuel_category="warp"},heat_buffer={specific_heat="1MJ",max_temperature=1000}, light={ intensity=10, size=9.9, shift={0.0,0.0}, color={r=1.0,g=0.0,b=0.0} }, - working_light_picture={ filename="__base__/graphics/entity/nuclear-reactor/reactor-lights-color.png", tint={r=1,g=0.4,b=0.4,a=1}, - hr_version={ filename="__base__/graphics/entity/nuclear-reactor/hr-reactor-lights-color.png", tint={r=1,g=0.4,b=0.4,a=1}, }, - }, - picture={layers={ - [1]={ tint={r=0.8,g=0.8,b=1,a=1}, hr_version={ tint={r=0.8,g=0.8,b=1,a=1}, }, }, - }}, -},true) - - - - --- ------------------------------------------------------------------------- --- Technologies - - --- ---- --- Warp Roboport - -local t={type="technology",upgrade=true,icon_size=128,effects={{recipe="warptorio-warpport",type="unlock-recipe"}},icons={ - {icon="__base__/graphics/entity/roboport/roboport-base.png",tint={r=0.3,g=0.3,b=1,a=1},scale=0.75,priority="low",}, -}, } -ExtendTech(t,{name="warptorio-warpport",unit={count=1000,time=5}, prerequisites={"warptorio-logistics-4","warptorio-reactor-8","space-science-pack"}}, {red=1,green=1,black=1,blue=1,purple=1,yellow=1,white=1}) - - --- ---- --- Warp Nuke - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/atomic-bomb.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-warpnuke",unit={count=1000,time=5},effects={{recipe="warptorio-atomic-bomb",type="unlock-recipe"}}, - prerequisites={"atomic-bomb","warptorio-reactor-8","space-science-pack"}}, {red=1,green=1,black=1,blue=1,purple=1,yellow=1,white=1}) - - --- ---- --- Warp Module - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/module.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-warpmodule",unit={count=3000,time=5}, prerequisites={"warptorio-reactor-8","space-science-pack","effectivity-module-3"}, - effects={{recipe="warptorio-warpmodule",type="unlock-recipe"}},}, {red=1,green=1,black=1,blue=1,purple=1,yellow=1,white=1}) - -data:extend{{type="module-category",name="warpivity"}} -local t={type="module",category="warpivity",name="warptorio-warpmodule",stack_size=50,subgroup="module",tier=4,localised_description={"item-description.warptorio-warpmodule"}, - limitation_message_key = "production-module-usable-only-on-intermediates", - effect={ consumption={bonus=0.6},pollution={bonus=0.05},productivity={bonus=0.1},speed={bonus=0.35} }, - icon_size=64,icons={ {icon="__base__/graphics/icons/speed-module-3.png",tint={r=0.2,g=0.2,b=1,a=1}} }, -} -data:extend{t} - -data:extend{{type="recipe",result="warptorio-warpmodule",name="warptorio-warpmodule",enabled=false,energy_required=60, - ingredients={{"speed-module-3",50},{"productivity-module-3",50},{"effectivity-module-3",50},{"advanced-circuit",200},{"processing-unit",200},{"low-density-structure",10}}, -}} - - --- ---- --- Warp Reactor - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/engine.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-reactor-1",unit={count=50,time=5}, prerequisites={}}, {red=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/electronics.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-reactor-2",unit={count=50,time=5}, prerequisites={"warptorio-reactor-1","logistic-science-pack"}}, {red=1,green=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/advanced-electronics.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-reactor-3",unit={count=50,time=5}, prerequisites={"warptorio-reactor-2","military-science-pack"}}, {red=1,green=2,black=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/advanced-electronics-2.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-reactor-4",unit={count=50,time=5}, prerequisites={"warptorio-reactor-3","rocketry"}}, {red=2,green=2,black=1,}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/explosives.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-reactor-5",unit={count=50,time=5}, prerequisites={"warptorio-reactor-4","chemical-science-pack"}}, {red=1,green=3,black=1,blue=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/atomic-bomb.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,} -}, localised_description={"technology-description.warptorio-reactor-6"} } -ExtendTech(t,{name="warptorio-reactor-6",unit={count=100,time=90}, effects={{recipe="warptorio-townportal",type="unlock-recipe"}},prerequisites={"warptorio-reactor-5","uranium-processing","robotics"}}, {red=5,black=5}) -- reactor module - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/kovarex-enrichment-process.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-reactor-7",unit={count=1000,time=30}, effects={{recipe="warptorio-heatpipe",type="unlock-recipe"},{recipe="warptorio-warponium-fuel-cell",type="unlock-recipe"}}, prerequisites={"nuclear-power","warptorio-reactor-6"}}, {red=1,green=1,black=1,blue=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__warptorio2__/graphics/technology/earth.png",tint={r=0.8,g=0.8,b=1,a=1},scale=0.5,shift={32,32},priority="high"} -}, localised_description={"technology-description.warptorio-reactor-8"} } -ExtendTech(t,{name="warptorio-reactor-8",unit={count=1000,time=30}, prerequisites={"warptorio-reactor-7","warptorio-charting","warptorio-accelerator","warptorio-stabilizer","warptorio-kovarex","rocket-control-unit"}}, {red=1,green=1,black=1,blue=1,purple=1,yellow=1}) -- steering - - - --- ---- --- Reactor Abilities - -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/battery.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-stabilizer",unit={count=400,time=30}, prerequisites={"warptorio-reactor-6","military-3","circuit-network"}}, {red=1,green=1,black=1,blue=1}) -- stabilizer - -local t={type="technology",upgrade=false,icon_size=128,icons={ {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,} }, } -t.icons={ {icon="__base__/graphics/technology/engine.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} } -ExtendTech(t,{name="warptorio-accelerator",unit={count=400,time=30}, prerequisites={"warptorio-reactor-6","military-3","circuit-network"}}, {red=1,green=1,black=1,blue=1}) -- accelerator - -local t={type="technology",upgrade=false,icon_size=128,icons={ {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,} }, } -t.icons={ {icon="__base__/graphics/technology/radar.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} } -ExtendTech(t,{name="warptorio-charting",unit={count=400,time=30}, prerequisites={"warptorio-reactor-6","military-3","circuit-network"}}, {red=1,green=1,black=1,blue=1}) -- charting - - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__warptorio2__/graphics/technology/earth.png",tint={r=0.8,g=0.8,b=1,a=1},priority="low"} -}, } -ExtendTech(t,{name="warptorio-homeworld",unit={count=5000,time=30}, effects={{recipe="warptorio-homeportal",type="unlock-recipe"}}, prerequisites={"warptorio-reactor-8","space-science-pack"}}, {red=1,green=1,black=1,blue=1,purple=1,yellow=1,white=1}) - - --- ---- --- Warponium Fuel - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/rocket-fuel.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,}, - }, - effects={{recipe="warptorio-warponium-fuel",type="unlock-recipe"}}, -} -ExtendTech(t,{name="warptorio-kovarex",unit={count=1000,time=15}, prerequisites={"warptorio-reactor-7","kovarex-enrichment-process"}}, {red=1,green=1,black=1,blue=1,purple=1}) -- Kovarex - - --- ---- --- Boiler Warp Substation - -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/electric-energy-distribution-1.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-boiler-station",unit={count=500,time=10}, prerequisites={"electric-energy-distribution-2","warptorio-boiler-0","production-science-pack"}}, {red=1,blue=1,green=1,purple=1}) - - --- ---- --- Warp Energy Pipe - -local rtint={tint={r=0.3,g=0.3,b=1,a=1},hr_version={tint={r=0.3,g=0.3,b=1,a=1}}} - ---[[ -local pipe_sprites={corner_left_down={{rtint},{rtint},{rtint},{rtint},{rtint}},corner_left_up={{rtint},{rtint},{rtint},{rtint},{rtint},{rtint}}, - corner_right_down={{rtint},{rtint},{rtint},{rtint},{rtint},{rtint}},corner_right_up={{rtint},{rtint},{rtint},{rtint},{rtint},{rtint}}, - cross={{rtint}},ending_down={{rtint}},ending_left={{rtint}},ending_right={{rtint}},ending_up={{rtint}},single={{rtint}}, - straight_horizontal={{rtint},{rtint},{rtint},{rtint},{rtint},{rtint}},straight_vertical={{rtint},{rtint},{rtint},{rtint},{rtint},{rtint}}, - t_down={{rtint}},t_left={{rtint}},t_right={{rtint}},t_up={{rtint}},} - -local t=ExtendDataCopy("heat-pipe","heat-pipe",{name="warptorio-heatpipe",connection_sprites=pipe_sprites,heat_glow_sprites=pipe_sprites, - max_temperature=5000, - max_transfer="5GW", - specific_heat="1MJ", - icon_size=64,icons={ {icon="__base__/graphics/icons/heat-pipe.png",tint={r=0.3,g=0.3,b=1,a=1},hr_version={tint={r=0.3,g=0.3,b=1,a=1}} } } -})]] - -local pipe_icon={ {icon="__base__/graphics/icons/heat-pipe.png",tint={r=0.3,g=0.3,b=1,a=1},hr_version={tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} } } -local t=ExtendDataCopy("recipe","heat-pipe",{name="warptorio-heatpipe",result="warptorio-heatpipe",ingredients={{"processing-unit",200},{"heat-pipe",50}}, enabled=false,energy_required=30, }) -local t=ExtendDataCopy("item","heat-pipe",{name="warptorio-heatpipe",place_result="warptorio-heatpipe", - icon_size=64,icons=pipe_icon, -}) - --- ---- --- Sandbox Boosts - -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/mining-productivity.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, - effects={ {type="mining-drill-productivity-bonus",modifier=0.1}}, } -ExtendTech(t,{name="warptorio-mining-prod-1",unit={count_formula="20*L",time=30},max_level=5}, {red=1}) -ExtendTech(t,{name="warptorio-mining-prod-6",unit={count_formula="(20*L)-50",time=30},max_level=10,prerequisites={"warptorio-mining-prod-1","logistic-science-pack"}}, {red=2,green=1}) -ExtendTech(t,{name="warptorio-mining-prod-11",unit={count_formula="(20*L)-100",time=30},max_level=15,prerequisites={"warptorio-mining-prod-6","chemical-science-pack"}}, {red=2,green=2,blue=1} ) -ExtendTech(t,{name="warptorio-mining-prod-16",unit={count_formula="(20*L)-150",time=30},max_level=20,prerequisites={"warptorio-mining-prod-11","production-science-pack"}}, {red=3,green=3,blue=1,purple=1} ) -ExtendTech(t,{name="warptorio-mining-prod-21",unit={count_formula="(20*L)-200",time=30},max_level=25,prerequisites={"warptorio-mining-prod-16","utility-science-pack"}}, {red=3,green=3,blue=2,purple=1,yellow=1} ) - -local t={type="technology",upgrade=true,icon_size=64,icons={ {icon="__base__/graphics/icons/steel-axe.png",tint={r=0.3,g=0.3,b=1,a=1},} }, - effects={ {type="character-mining-speed",modifier=0.5}}, } -ExtendTech(t,{name="warptorio-axe-speed-1",unit={count_formula="50*L",time=30},prerequisites={"steel-axe","warptorio-reactor-1"},max_level=2}, {red=1}) -ExtendTech(t,{name="warptorio-axe-speed-3",unit={count_formula="(50*L)",time=30},max_level=4,prerequisites={"warptorio-axe-speed-1","logistic-science-pack"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-axe-speed-5",unit={count_formula="(50*L)",time=30},max_level=6,prerequisites={"warptorio-axe-speed-3","chemical-science-pack"}}, {red=1,green=1,blue=1} ) -ExtendTech(t,{name="warptorio-axe-speed-7",unit={count_formula="(50*L)",time=30},max_level=8,prerequisites={"warptorio-axe-speed-5","production-science-pack"}}, {red=1,green=1,blue=1,purple=1} ) -ExtendTech(t,{name="warptorio-axe-speed-9",unit={count_formula="(50*L)",time=30},max_level=10,prerequisites={"warptorio-axe-speed-7","utility-science-pack"}}, {red=1,green=1,blue=1,purple=1,yellow=1} ) - -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/inserter-capacity.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, - effects={ {type="stack-inserter-capacity-bonus",modifier=1}, {type="inserter-stack-size-bonus",modifier=1},} } -ExtendTech(t,{name="warptorio-inserter-cap-1",unit={count=150,time=30},prerequisites={"warptorio-reactor-1","fast-inserter"},}, {red=1}) -ExtendTech(t,{name="warptorio-inserter-cap-2",unit={count=200,time=30},prerequisites={"warptorio-inserter-cap-1","logistic-science-pack"}}, {red=2,green=1}) -ExtendTech(t,{name="warptorio-inserter-cap-3",unit={count=250,time=30},prerequisites={"warptorio-inserter-cap-2","chemical-science-pack"}}, {red=3,green=2,blue=1} ) -ExtendTech(t,{name="warptorio-inserter-cap-4",unit={count=300,time=30},prerequisites={"warptorio-inserter-cap-3","production-science-pack"}}, {red=4,green=3,blue=2,purple=1} ) -ExtendTech(t,{name="warptorio-inserter-cap-5",unit={count=350,time=30},prerequisites={"warptorio-inserter-cap-4","utility-science-pack"}}, {red=5,green=4,blue=3,purple=2,yellow=1} ) - - -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/worker-robots-speed.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, - effects={ {type="worker-robot-speed",modifier=0.35},} } -ExtendTech(t,{name="warptorio-bot-speed-1",unit={count=120,time=30},prerequisites={"robotics","warptorio-reactor-2"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-bot-speed-2",unit={count=180,time=30},prerequisites={"warptorio-bot-speed-1","logistic-robotics"}}, {red=2,green=1}) -ExtendTech(t,{name="warptorio-bot-speed-3",unit={count=250,time=30},prerequisites={"warptorio-bot-speed-2","chemical-science-pack"}}, {red=3,green=2,blue=1} ) -ExtendTech(t,{name="warptorio-bot-speed-4",unit={count=300,time=30},prerequisites={"warptorio-bot-speed-3","production-science-pack"}}, {red=4,green=3,blue=2,purple=1} ) -ExtendTech(t,{name="warptorio-bot-speed-5",unit={count=350,time=30},prerequisites={"warptorio-bot-speed-4","utility-science-pack"}}, {red=5,green=4,blue=3,purple=2,yellow=1} ) - -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/worker-robots-storage.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, - effects={ {type="worker-robot-storage",modifier=1}, } } -ExtendTech(t,{name="warptorio-bot-cap-1",unit={count=120,time=30},prerequisites={"robotics","warptorio-reactor-2"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-bot-cap-2",unit={count=180,time=30},prerequisites={"warptorio-bot-cap-1","construction-robotics"}}, {red=2,green=1}) -ExtendTech(t,{name="warptorio-bot-cap-3",unit={count=250,time=30},prerequisites={"warptorio-bot-cap-2","chemical-science-pack"}}, {red=2,green=2,blue=1} ) -ExtendTech(t,{name="warptorio-bot-cap-4",unit={count=300,time=30},prerequisites={"warptorio-bot-cap-3","production-science-pack"}}, {red=3,green=3,blue=1,purple=1} ) -ExtendTech(t,{name="warptorio-bot-cap-5",unit={count=350,time=30},prerequisites={"warptorio-bot-cap-4","utility-science-pack"}}, {red=3,green=3,blue=2,purple=1,yellow=1} ) - - -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/physical-projectile-damage-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, - effects={ {type="turret-attack",modifier=0.15,turret_id="gun-turret"},{ammo_category="bullet",modifier=0.15,type="ammo-damage"},{ammo_category="shotgun-shell",modifier=0.2,type="ammo-damage"} } } -ExtendTech(t,{name="warptorio-physdmg-1",unit={count=250,time=30},prerequisites={"warptorio-reactor-1","physical-projectile-damage-1"}}, {red=1}) -ExtendTech(t,{name="warptorio-physdmg-2",unit={count=250,time=30},prerequisites={"warptorio-reactor-2","warptorio-physdmg-1","physical-projectile-damage-2"}}, {red=2,green=1} ) -ExtendTech(t,{name="warptorio-physdmg-3",unit={count=350,time=30},prerequisites={"warptorio-reactor-3","warptorio-physdmg-2","physical-projectile-damage-3"}}, {red=3,green=2,black=1} ) - -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/toolbelt.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, - effects={ {type="character-inventory-slots-bonus",modifier=10} }, } -ExtendTech(t,{name="warptorio-toolbelt-1",unit={count=70,time=30},prerequisites={"warptorio-reactor-1"}}, {red=1}) -ExtendTech(t,{name="warptorio-toolbelt-2",unit={count=120,time=30},prerequisites={"warptorio-toolbelt-1","toolbelt","logistic-science-pack"}}, {red=2,green=1}) -ExtendTech(t,{name="warptorio-toolbelt-3",unit={count=150,time=30},prerequisites={"warptorio-toolbelt-2","chemical-science-pack"}}, {red=2,green=2,blue=1} ) -ExtendTech(t,{name="warptorio-toolbelt-4",unit={count=180,time=30},prerequisites={"warptorio-toolbelt-3","production-science-pack"}}, {red=3,green=2,blue=2,purple=1} ) -ExtendTech(t,{name="warptorio-toolbelt-5",unit={count=200,time=30},prerequisites={"warptorio-toolbelt-4","utility-science-pack"}}, {red=4,green=3,blue=2,purple=2,yellow=1} ) - -local t={type="technology",upgrade=true,icons={ - {icon="__warptorio2__/graphics/technology/earth.png",tint={r=0.7,g=0.7,b=1,a=1},shift={0,0},scale=0.375,priority="medium",icon_size=128}, - {icon="__base__/graphics/icons/steel-axe.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_size=64,scale=0.5}, - }, - effects={ - {type="character-reach-distance",modifier=1}, - {type="character-build-distance",modifier=1}, - {type="character-item-drop-distance",modifier=1}, - {type="character-resource-reach-distance",modifier=1}, - }, -} -ExtendTech(t,{name="warptorio-reach-1",unit={count=50,time=30},prerequisites={"warptorio-reactor-1"}}, {red=1}) -ExtendTech(t,{name="warptorio-reach-2",unit={count=100,time=30},prerequisites={"warptorio-reach-1","logistic-science-pack"}}, {red=2,green=1}) -ExtendTech(t,{name="warptorio-reach-3",unit={count=150,time=30},prerequisites={"warptorio-reach-2","chemical-science-pack"}}, {red=2,green=2,blue=1} ) -ExtendTech(t,{name="warptorio-reach-4",unit={count=180,time=30},prerequisites={"warptorio-reach-3","production-science-pack"}}, {red=3,green=2,blue=2,purple=1} ) -ExtendTech(t,{name="warptorio-reach-5",unit={count=200,time=30},prerequisites={"warptorio-reach-4","utility-science-pack"}}, {red=4,green=3,blue=2,purple=2,yellow=1} ) - - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/exoskeleton-equipment.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, -}, effects={ - {type="character-running-speed",modifier=0.1}, -}, } -ExtendTech(t,{name="warptorio-striders-1",unit={count=150,time=20}, prerequisites={"warptorio-reactor-1"},upgrade=false}, {red=1}) -ExtendTech(t,{name="warptorio-striders-2",unit={count=300,time=20}, prerequisites={"warptorio-reactor-2","modular-armor","warptorio-striders-1"},upgrade=false}, {red=1,green=1}) - - - --- ---- --- Platform Size - -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/concrete.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, } -ExtendTech(t,{name="warptorio-platform-size-1", unit={count=70,time=20}, prerequisites={}}, {red=1} ) -ExtendTech(t,{name="warptorio-platform-size-2", unit={count=120,time=20}, prerequisites={"warptorio-platform-size-1","warptorio-reactor-1"}}, {red=1} ) -ExtendTech(t,{name="warptorio-platform-size-3", unit={count=150,time=40}, prerequisites={"warptorio-platform-size-2","logistic-science-pack"}}, {red=1,green=1} ) -ExtendTech(t,{name="warptorio-platform-size-4", unit={count=250,time=30}, prerequisites={"concrete","warptorio-platform-size-3"}}, {red=1,green=1} ) -ExtendTech(t,{name="warptorio-platform-size-5", unit={count=120,time=30}, prerequisites={"chemical-science-pack","warptorio-platform-size-4"}}, {red=2,green=2,blue=1} ) -ExtendTech(t,{name="warptorio-platform-size-6", unit={count=150,time=30}, prerequisites={"warptorio-platform-size-5","solar-energy","production-science-pack"}}, {red=2,green=2,blue=1,purple=1} ) -ExtendTech(t,{name="warptorio-platform-size-7", unit={count=150,time=30}, prerequisites={"warptorio-platform-size-6","utility-science-pack"}}, {red=2,green=2,blue=1,purple=1,yellow=1} ) - - --- ---- --- Train Stops - - -for v,w in pairs({nw={-38,-38},ne={38,-38},se={38,38},sw={-38,38}})do -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/railway.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/railway.png",tint={r=0.7,g=0.7,b=1,a=0.9},shift={w[1],w[2]},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, -}, } - -ExtendTech(t,{name="warptorio-rail-"..v, unit={count=500,time=40}, prerequisites={"railway","warptorio-platform-size-6","warptorio-factory-7"}}, {red=1,green=1,black=1,blue=1,purple=1,yellow=1} ) -end - - --- ---- --- Castle Ramps - - -for v,w in pairs({nw={-38,-38},ne={38,-38},se={38,38},sw={-38,38}})do -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/stone-wall.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/stone-wall.png",tint={r=0.7,g=0.7,b=1,a=0.9},shift={w[1],w[2]},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-turret-"..v.."-0",upgrade=false, unit={count=100,time=40}, prerequisites={"gate","warptorio-factory-0"}}, {red=1,green=1} ) -ExtendTech(t,{name="warptorio-turret-"..v.."-1", unit={count=150,time=40}, prerequisites={"warptorio-turret-"..v.."-0","military-science-pack",}}, {red=2,green=1,black=1,} ) -ExtendTech(t,{name="warptorio-turret-"..v.."-2", unit={count=200,time=30}, prerequisites={"warptorio-turret-"..v.."-1","chemical-science-pack"}}, {red=2,green=1,black=1,blue=1} ) -ExtendTech(t,{name="warptorio-turret-"..v.."-3", unit={count=300,time=40}, prerequisites={"warptorio-turret-"..v.."-2","production-science-pack"}}, {red=2,green=2,black=1,blue=1,purple=1} ) -end - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/stone-wall.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/stone-wall.png",tint={r=0.7,g=0.7,b=1,a=0.9},shift={38,38},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/stone-wall.png",tint={r=0.7,g=0.7,b=1,a=0.9},shift={-38,-38},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/stone-wall.png",tint={r=0.7,g=0.7,b=1,a=0.9},shift={-38,38},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/stone-wall.png",tint={r=0.7,g=0.7,b=1,a=0.9},shift={38,-38},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-bridgesize-1",unit={count=500,time=40},prerequisites={"warptorio-turret-nw-0","warptorio-turret-ne-0","warptorio-turret-se-0","warptorio-turret-sw-0"}, - unit={count=200,time=40}},{red=1,green=1,black=1}) -ExtendTech(t,{name="warptorio-bridgesize-2",unit={count=500,time=40},prerequisites={"warptorio-bridgesize-1","warptorio-turret-nw-1","warptorio-turret-ne-1","warptorio-turret-se-1","warptorio-turret-sw-1","low-density-structure"}, - unit={count=400,time=40}},{red=1,green=1,black=1,blue=1}) - --- ---- --- Factory Floor Upgrades - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/automation-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-factory-0",unit={count=80,time=20}, prerequisites={"automation","warptorio-platform-size-1"}, upgrade=false, - localised_name={"technology-name.warptorio-factory"}, - localised_description={"technology-description.warptorio-factory-floor"}, -},{red=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/automation-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-factory-1",unit={count=120,time=20}, prerequisites={"warptorio-factory-0","steel-processing"}}, {red=1}) -ExtendTech(t,{name="warptorio-factory-2",unit={count=150,time=15}, prerequisites={"electric-energy-distribution-1","advanced-material-processing","automation-2","warptorio-factory-1"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-factory-3",unit={count=180,time=20}, prerequisites={"warptorio-factory-2","sulfur-processing"}}, {red=2,green=2}) -ExtendTech(t,{name="warptorio-factory-4",unit={count=220,time=25}, prerequisites={"warptorio-factory-3","chemical-science-pack","modules"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-factory-5",unit={count=250,time=20}, prerequisites={"warptorio-factory-4","advanced-material-processing-2"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-factory-6",unit={count=300,time=20}, prerequisites={"warptorio-factory-5","automation-3"}}, {red=2,green=2,blue=1,purple=1}) -ExtendTech(t,{name="warptorio-factory-7",unit={count=350,time=20}, prerequisites={"warptorio-factory-6","utility-science-pack","effect-transmission"}}, {red=2,green=3,blue=1,purple=1,yellow=1}) - -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/automation-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={0,-32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-factory-n",unit={count=1000,time=30}, prerequisites={"warptorio-factory-7","space-science-pack","warptorio-bridgesize-2"}}, {red=3,green=2,blue=3,purple=2,yellow=1,white=1}) -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/automation-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={0,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-factory-s",unit={count=1000,time=30}, prerequisites={"warptorio-factory-7","space-science-pack","warptorio-bridgesize-2"}}, {red=3,green=2,blue=3,purple=2,yellow=1,white=1}) -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/automation-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,0},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-factory-e",unit={count=1000,time=30}, prerequisites={"warptorio-factory-7","space-science-pack","warptorio-bridgesize-2"}}, {red=3,green=2,blue=3,purple=2,yellow=1,white=1}) -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/automation-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={-32,0},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-factory-w",unit={count=1000,time=30}, prerequisites={"warptorio-factory-7","space-science-pack","warptorio-bridgesize-2"}}, {red=3,green=2,blue=3,purple=2,yellow=1,white=1}) - --- ---- --- Boiler Room Upgrades - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-boiler-0",unit={count=100,time=30}, prerequisites={"steel-processing","warptorio-harvester-floor"},upgrade=false, - localised_name={"technology-name.warptorio-boiler"}, - localised_description={"technology-description.warptorio-boiler-floor"}, -}, {red=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-boiler-1",unit={count=100,time=30}, prerequisites={"warptorio-boiler-0","fluid-handling"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-boiler-2",unit={count=200,time=30}, prerequisites={"warptorio-boiler-1","flammables"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-boiler-3",unit={count=300,time=30}, prerequisites={"warptorio-boiler-2","battery"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-boiler-4",unit={count=150,time=30}, prerequisites={"warptorio-boiler-3","chemical-science-pack"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-boiler-5",unit={count=200,time=30}, prerequisites={"warptorio-boiler-4","production-science-pack"}}, {red=2,green=2,blue=1,purple=1}) -ExtendTech(t,{name="warptorio-boiler-6",unit={count=300,time=30}, prerequisites={"warptorio-boiler-5","nuclear-fuel-reprocessing"}}, {red=2,green=2,blue=1,purple=1,}) -ExtendTech(t,{name="warptorio-boiler-7",unit={count=300,time=30}, prerequisites={"warptorio-boiler-6","utility-science-pack"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) - - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/oil-gathering.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-boiler-water-1",upgrade=true,unit={count=500,time=30}, prerequisites={"warptorio-boiler-3","landfill"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-boiler-water-2",upgrade=true,unit={count=500,time=30}, prerequisites={"warptorio-boiler-5","warptorio-boiler-water-1"}}, {red=2,green=2,blue=1,purple=1}) - -ExtendTech(t,{name="warptorio-boiler-water-3",upgrade=true,unit={count=2000,time=30}, prerequisites={"warptorio-boiler-water-2","space-science-pack"}}, {red=1,green=1,blue=1,purple=1,yellow=1,white=1}) - -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={0,-32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-boiler-n",unit={count=1000,time=30}, prerequisites={"warptorio-boiler-7","space-science-pack"}}, {red=3,green=2,blue=2,purple=2,yellow=1,white=1}) - -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={0,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-boiler-s",unit={count=1000,time=30}, prerequisites={"warptorio-boiler-7","space-science-pack"}}, {red=3,green=2,blue=2,purple=2,yellow=1,white=1}) -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,0},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-boiler-e",unit={count=1000,time=30}, prerequisites={"warptorio-boiler-7","space-science-pack"}}, {red=3,green=2,blue=2,purple=2,yellow=1,white=1}) -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={-32,0},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-boiler-w",unit={count=1000,time=30}, prerequisites={"warptorio-boiler-7","space-science-pack"}}, {red=3,green=2,blue=2,purple=2,yellow=1,white=1}) - - - - --- ---- --- Harvester Size - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/tank.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-harvester-floor",unit={count=100,time=30}, prerequisites={"fast-inserter","warptorio-factory-0"},upgrade=false}, {red=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/tank.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-harvester-size-1",unit={count=100,time=30}, prerequisites={"warptorio-harvester-floor","oil-processing"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-harvester-size-2",unit={count=150,time=30}, prerequisites={"warptorio-harvester-size-1","stack-inserter"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-harvester-size-3",unit={count=200,time=30}, prerequisites={"warptorio-harvester-size-2","mining-productivity-1"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-harvester-size-4",unit={count=250,time=30}, prerequisites={"warptorio-harvester-size-3","chemical-science-pack"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-harvester-size-5",unit={count=300,time=30}, prerequisites={"warptorio-harvester-size-4","production-science-pack","mining-productivity-2"}}, {red=2,green=2,blue=1,purple=1}) -ExtendTech(t,{name="warptorio-harvester-size-6",unit={count=350,time=30}, prerequisites={"warptorio-harvester-size-5","nuclear-fuel-reprocessing"}}, {red=2,green=2,blue=1,purple=1,}) -ExtendTech(t,{name="warptorio-harvester-size-7",unit={count=400,time=30}, prerequisites={"warptorio-harvester-size-6","utility-science-pack","mining-productivity-3"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) - - -for v,w in pairs({east={32,0},west={-32,0}})do local odr=(v=="east" and "a-b" or "a-a") -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/tank.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=1,g=0.7,b=0.4,a=0.9},shift={w[1],w[2]},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, -}, } ---ExtendTech(t,{name="warptorio-harvester-"..v.."-gate",upgrade=false, unit={count=150,time=25}, prerequisites={"warptorio-harvester-floor"}}, {red=1,green=1} ) - -ExtendTech(t,{name="warptorio-harvester-"..v.."-1", order=odr, unit={count=150,time=25}, prerequisites={"warptorio-harvester-floor"},localised_description={"technology-description.warptorio-harvester-"..v.."-gate"}}, {red=1,green=1,} ) -ExtendTech(t,{name="warptorio-harvester-"..v.."-2", order=odr, unit={count=200,time=25}, prerequisites={"warptorio-harvester-"..v.."-1","mining-productivity-1","military-science-pack"}}, {red=2,green=1,black=1} ) -ExtendTech(t,{name="warptorio-harvester-"..v.."-3", order=odr, unit={count=300,time=25}, prerequisites={"warptorio-harvester-"..v.."-2","mining-productivity-2"}}, {red=2,green=2,black=1,blue=1} ) -ExtendTech(t,{name="warptorio-harvester-"..v.."-4", order=odr, unit={count=400,time=25}, prerequisites={"warptorio-harvester-"..v.."-3","nuclear-fuel-reprocessing"}}, {red=2,green=2,black=1,blue=1,purple=1} ) -ExtendTech(t,{name="warptorio-harvester-"..v.."-5", order=odr, unit={count=500,time=25}, prerequisites={"warptorio-harvester-"..v.."-4","mining-productivity-3"}}, {red=2,green=2,black=1,blue=1,purple=1,yellow=1} ) -end - ---[[ todo -for v,w in pairs({nw={-38,-38},ne={38,-38},se={38,38},sw={-38,38}})do -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/tank.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=1,g=0.7,b=0.4,a=0.9},shift={w[1],w[2]},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-harvester-"..v.."",upgrade=false, unit={count=1000,time=40}, prerequisites={"warptorio-harvester-size-7","warptorio-reactor-8","space-science-pack"}}, {red=1,green=1,black=1,blue=1,purple=1,yellow=1,white=1} ) -end -]] - --- ---- --- Logistics - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/logistics-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - }, -} -ExtendTech(t,{name="warptorio-logistics-1", unit={count=100,time=20}, prerequisites={"logistics","warptorio-factory-0"},upgrade=false}, {red=1} ) -ExtendTech(t,{name="warptorio-logistics-2", unit={count=200,time=20}, prerequisites={"logistics-2","warptorio-logistics-1"}}, {red=2,green=1} ) -ExtendTech(t,{name="warptorio-logistics-3", unit={count=300,time=20}, prerequisites={"logistics-3","warptorio-logistics-2"}}, {red=2,green=2,blue=1,purple=1} ) -ExtendTech(t,{name="warptorio-logistics-4", unit={count=400,time=20}, prerequisites={"logistic-system","warptorio-logistics-3"}}, {red=2,green=2,blue=1,purple=1,yellow=1} ) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/logistics-1.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/logistics-2.png",tint={r=1,g=1,b=0.7,a=0.9},shift={24,24},scale=0.4,priority="medium",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/logistics-3.png",tint={r=1,g=1,b=0.7,a=0.9},shift={-24,24},scale=0.4,priority="medium",icon_mipmaps=4,icon_size=256,}, - }, -} -ExtendTech(t,{name="warptorio-dualloader-1", unit={count=1000,time=10}, prerequisites={"logistics-2","warptorio-logistics-1"}}, {red=1,green=1} ) ---ExtendTech(t,{name="warptorio-dualloader-2", unit={count=1000,time=15}, prerequisites={"logistics-2","warptorio-dualloader-1"}}, {red=2,green=1} ) ---ExtendTech(t,{name="warptorio-dualloader-3", unit={count=1000,time=20}, prerequisites={"logistics-3","warptorio-dualloader-2","production-science-pack"}}, {red=3,green=2,blue=1,purple=1} ) -t.upgrade=false - -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/logistics-1.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/logistics-1.png",tint={r=1,g=1,b=0.7,a=0.9},shift={-28,-12},scale=0.4,priority="medium",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/logistics-1.png",tint={r=1,g=1,b=0.7,a=0.9},shift={28,-12},scale=0.4,priority="medium",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/logistics-1.png",tint={r=1,g=1,b=0.7,a=0.9},shift={0,32},scale=0.4,priority="high",icon_mipmaps=4,icon_size=256,}, - }, -} -ExtendTech(t,{name="warptorio-triloader", unit={count=10000,time=10}, prerequisites={"warptorio-logistics-1"}}, {red=1} ) - - - --- ---- --- Warp Loader - -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/logistics-1.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__warptorio2__/graphics/technology/earth.png",tint={r=0.8,g=0.8,b=1,a=1},scale=1,shift={32,32},priority="high",} - }, effects={ {recipe="warptorio-warploader",type="unlock-recipe"} }, -} -ExtendTech(t,{name="warptorio-warploader", unit={count=10000,time=10}, prerequisites={"warptorio-armor","warptorio-warpmodule","warptorio-warpnuke","warptorio-warpport"}}, {red=1,green=1,blue=1,purple=1,yellow=1,white=1} ) - - - --- ---- --- Energy Upgrades - -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/electric-energy-acumulators.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, } -ExtendTech(t,{name="warptorio-energy-1",unit={count=30,time=20}, prerequisites={"warptorio-factory-0"},upgrade=false}, {red=1}) -ExtendTech(t,{name="warptorio-energy-2",unit={count=100,time=25}, prerequisites={"warptorio-energy-1","electric-energy-distribution-1"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-energy-3",unit={count=150,time=30}, prerequisites={"warptorio-energy-2","advanced-electronics"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-energy-4",unit={count=200,time=35}, prerequisites={"warptorio-energy-3","electric-energy-distribution-2","advanced-electronics-2"}}, {red=1,green=1,blue=1}) -ExtendTech(t,{name="warptorio-energy-5",unit={count=250,time=40}, prerequisites={"warptorio-energy-4","utility-science-pack","production-science-pack"}}, {red=1,green=1,blue=1,purple=1,yellow=1}) - --- ---- --- Teleporter - -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/research-speed.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, } -ExtendTech(t,{name="warptorio-teleporter-portal",unit={count=30,time=20}, prerequisites={"warptorio-factory-0","electronics",},upgrade=false}, {red=1}) -ExtendTech(t,{name="warptorio-teleporter-1",unit={count=30,time=20}, prerequisites={"warptorio-teleporter-portal","electric-energy-distribution-1"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-teleporter-2",unit={count=30,time=20}, prerequisites={"warptorio-teleporter-1","advanced-electronics"}}, {red=2,green=2,}) -ExtendTech(t,{name="warptorio-teleporter-3",unit={count=30,time=20}, prerequisites={"warptorio-teleporter-2","electric-energy-distribution-2","advanced-electronics-2"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-teleporter-4",unit={count=30,time=20}, prerequisites={"warptorio-teleporter-3","nuclear-power"}}, {red=2,green=2,blue=2,}) -ExtendTech(t,{name="warptorio-teleporter-5",unit={count=30,time=20}, prerequisites={"warptorio-teleporter-4","utility-science-pack","production-science-pack"}}, {red=2,green=3,blue=2,purple=1,yellow=1}) - - --- ---- --- Beacon - - -local t={type="technology",upgrade=true,icon_size=64,icons={ {icon="__base__/graphics/icons/beacon.png",tint={r=0.3,g=0.3,b=1,a=1}} }, } -ExtendTech(t,{name="warptorio-beacon-1",unit={count=300,time=20}, prerequisites={"modules","warptorio-factory-0"},upgrade=false}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-beacon-2",unit={count=500,time=20}, prerequisites={"warptorio-beacon-1","speed-module","productivity-module","effectivity-module"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-beacon-3",unit={count=300,time=20}, prerequisites={"warptorio-beacon-2","speed-module-2","productivity-module-2","effectivity-module-2"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-beacon-4",unit={count=500,time=20}, prerequisites={"warptorio-beacon-3","speed-module-3","productivity-module-3","effectivity-module-3"}}, {red=2,green=2,blue=1,purple=1}) -ExtendTech(t,{name="warptorio-beacon-5",unit={count="700",time=20}, prerequisites={"warptorio-beacon-4","utility-science-pack"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) -ExtendTech(t,{name="warptorio-beacon-6",unit={count="900",time=20}, prerequisites={"warptorio-beacon-5"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) -ExtendTech(t,{name="warptorio-beacon-7",unit={count="1200",time=20}, prerequisites={"warptorio-beacon-6"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) -ExtendTech(t,{name="warptorio-beacon-8",unit={count="1500",time=20}, prerequisites={"warptorio-beacon-7"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) -ExtendTech(t,{name="warptorio-beacon-9",unit={count="1000",time=20}, prerequisites={"warptorio-beacon-8","space-science-pack"}}, {red=3,green=3,blue=2,purple=1,yellow=1,white=1}) -ExtendTech(t,{name="warptorio-beacon-10",unit={count="2000",time=20}, prerequisites={"warptorio-beacon-9"}}, {red=3,green=3,blue=2,purple=2,yellow=2,white=1}) - ---[[ unused -local t={type="technology",upgrade=true,icon_size=64,icons={ {icon="__base__/graphics/icons/beacon.png",tint={r=0.3,g=0.3,b=1,a=1}} }, } -ExtendTech(t,{name="warptorio-beacon-1",unit={count=300,time=20}, prerequisites={"modules","warptorio-factory-0"},upgrade=false}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-beacon-2",unit={count=500,time=20}, prerequisites={"warptorio-beacon-1","speed-module","productivity-module","effectivity-module"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-beacon-3",unit={count=300,time=20}, prerequisites={"warptorio-beacon-2","speed-module-2","productivity-module-2","effectivity-module-2"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-beacon-4",unit={count=500,time=20}, prerequisites={"warptorio-beacon-3","speed-module-3","productivity-module-3","effectivity-module-3"}}, {red=2,green=2,blue=1,purple=1}) -ExtendTech(t,{name="warptorio-beacon-5",unit={count_formula="250+50*L",time=20},max_level=10, prerequisites={"warptorio-beacon-4","utility-science-pack"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) -ExtendTech(t,{name="warptorio-beacon-11",unit={count=5,time=1}, prerequisites={"warptorio-beacon-5"}}, {red=5,green=5,blue=5,purple=5,white=5}) -ExtendTech(t,{name="warptorio-beacon-12",unit={count=5,time=1}, prerequisites={"warptorio-beacon-11"}}, {red=2,green=5,blue=5,purple=5,white=5}) -]] - - --- ---- --- Warp Beacon - -local t=ExtendDataCopy("beacon","beacon",{name="warptorio-beacon-1",supply_area_distance=16,module_specification={module_slots=1}, - base_picture={ tint={r=0.5,g=0.7,b=1,a=1}, }, animation={ tint={r=1,g=0.2,b=0.2,a=1}, }, - allowed_effects={"consumption","speed","pollution","productivity"}, - distribution_effectivity=1, -},true) -for i=2,10,1 do local xt=table.deepcopy(t) xt.name="warptorio-beacon-"..i xt.supply_area_distance=math.min(16+8*i,64) xt.module_specification.module_slots=i data:extend{xt} end - - - --- ---- --- Radar - ---[[ -local t={type="technology",icon_size=128,icons={ {icon="__base__/graphics/technology/radar.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, } -ExtendTech(t,{name="warptorio-radar-1",unit={count=300,time=15},prerequisites={"radar","chemical-science-pack","optics"}}, {red=1,green=1}) -]] - - --- ---- --- Warp Armor -local t={type="technology",icon_size=128,icons={ {icon="__base__/graphics/technology/power-armor-mk2.png",tint={r=0.3,g=0.3,b=1,a=1},icon_size=256},},prerequisites={"power-armor-mk2","warptorio-reactor-8","space-science-pack",} } -ExtendTech(t,{name="warptorio-armor",unit={count=1000,time=60},effects={{recipe="warptorio-armor",type="unlock-recipe"}}},{red=4,green=4,blue=4,black=5,yellow=2,white=1}) - - -data:extend{{type="equipment-grid",name="warptorio-warparmor-grid",equipment_categories={"armor"},height=16,width=16}} -local t=ExtendDataCopy("armor","power-armor-mk2",{name="warptorio-armor",equipment_grid="warptorio-warparmor-grid", - icon_size=64,icons={{icon="__base__/graphics/icons/power-armor-mk2.png",tint={r=0.3,g=0.3,b=1,a=1},}},inventory_size_bonus=100},false) - -local t=ExtendDataCopy("recipe","power-armor-mk2",{name="warptorio-armor",enabled=false,ingredients={{"power-armor-mk2",5},{"power-armor",5},{"modular-armor",5},{"heavy-armor",5},{"light-armor",5}},result="warptorio-armor"}) - - - --- ---- --- Warp Combinators - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/circuit-network.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - --{icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, effects={ - {recipe="warptorio-combinator",type="unlock-recipe"}, -}, } -ExtendTech(t,{name="warptorio-combinator",unit={count=50,time=20}, prerequisites={"circuit-network","chemical-science-pack"}}, {red=1,green=1,blue=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/circuit-network.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/tank.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-alt-combinator",unit={count=50,time=20}, prerequisites={"circuit-network","production-science-pack","warptorio-harvester-east-1","warptorio-harvester-west-1"}}, {red=1,green=1,blue=1,purple=1}) - - - --- ---- --- Warp Toolbar - - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/toolbelt.png",tint={r=0.4,g=0.4,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__warptorio2__/graphics/technology/earth.png",tint={r=0.8,g=0.8,b=1,a=0.9},priority="medium",shift={32,32},scale=1}, -},} -ExtendTech(t,{name="warptorio-toolbar",unit={count=2000,time=20}, - prerequisites={"space-science-pack","warptorio-toolbelt-5","warptorio-reach-5","warptorio-harvester-east-5","warptorio-harvester-west-5","warptorio-teleporter-5","warptorio-striders-2"}, -}, - {red=1,green=1,blue=1,purple=1,black=1,yellow=1,white=1} -) - - - +local function istable(t) return type(t) == "table" end +local function rgb(r, g, b, a) + a = a or 255 + return { r = r / 255, g = g / 255, b = b / 255, a = a / 255 } +end + +function table.deepmerge(s, t) + for k, v in pairs(t) do + if (istable(v) and s[k] and istable(s[k])) then + table.deepmerge( + s[k], v) + else + s[k] = v + end + end +end + +function table.merge(s, t) + local x = {} + for k, v in pairs(s) do x[k] = v end + for k, v in pairs(t) do x[k] = v end + return x +end + +local function MakeDataCopy(a, b, x) + local t = table.deepcopy(data.raw[a][b]) + if (x) then table.deepmerge(t, x) end + return t +end +local function ExtendRecipeItem(t) + local r = table.deepcopy(data.raw.recipe["nuclear-reactor"]) + r.enabled = false + r.name = t.name + r.ingredients = { { type = "item", name = "steel-plate", amount = 1 } } + r.results = { { type = "item", name = t.name, amount = 1 } } + local i = table.deepcopy(data.raw.item["nuclear-reactor"]) + i.name = t.name + i.place_result = t.name + data:extend { i, r } +end +local function ExtendRecipeItemFix(t) t.order = t.order or "warptorio" end +local function ExtendDataCopy(a, b, x, ri, tx) + local t = MakeDataCopy(a, b, x) + if (tx) then for k, v in pairs(tx) do if (v == false) then t[k] = nil else t[k] = v end end end + if (ri) then ExtendRecipeItemFix(t) end + data:extend { t } + return t +end + +local function ExtendCopyRecipe(src, name) + local r = table.deepcopy(data.raw.recipe[src]) + r.enabled = false + r.name = name + r.ingredients = { { type = "item", name = "steel-plate", amount = 1 } } + r.results = { { type = "item", name = name, amount = 1 } } + local i = table.deepcopy(data.raw.recipe[src]) + i.name = name + i.place_result = name + data:extend { i, r } +end + +local techPacks = { + red = "automation-science-pack", + green = "logistic-science-pack", + blue = "chemical-science-pack", + black = "military-science-pack", + purple = "production-science-pack", + yellow = "utility-science-pack", + white = "space-science-pack" +} + +local function SciencePacks(x) + local t = {} + for k, v in pairs(x) do table.insert(t, { techPacks[k], v }) end + return t +end +local function ExtendTech(t, d, s) + local x = table.merge(t, d) + if (s) then x.unit.ingredients = SciencePacks(s) end + data:extend { x } + return x +end + +--[[ +local t=ExtendDataCopy("electric-pole","small-electric-pole",{name="warptorio-electric-pole", + pictures={layers={[1]={tint={r=0.6,g=0.6,b=1,a=1},hr_version={tint={r=0.6,g=0.6,b=1,a=1}} }, }}, +},true) +]] + + +-- -------- +-- vonNeumann compatability. It's base game stuff anyway. Perhaps expand on this later + +-- data.raw.lab["crash-site-lab-repaired"].minable={mining_time=3,result="crash-site-lab-repaired"} +-- data.raw.container["crash-site-chest-1"].minable={mining_time=3,result="crash-site-chest-1"} +-- data.raw.container["crash-site-chest-2"].minable={mining_time=3,result="crash-site-chest-2"} +-- data.raw["assembling-machine"]["crash-site-assembling-machine-1-repaired"].minable={mining_time=3,result="crash-site-assembling-machine-1-repaired"} +-- data.raw["assembling-machine"]["crash-site-assembling-machine-2-repaired"].minable={mining_time=3,result="crash-site-assembling-machine-2-repaired"} + + +-- -------- +-- Warp Tiles + +-- purple tiles +local t = ExtendDataCopy("tile", "tutorial-grid", + { name = "warp-tile-concrete", tint = { r = 0.6, g = 0.6, b = 0.7, a = 1 }, layer = 99, decorative_removal_probability = 1, walking_speed_modifier = 1.6, map_color = { r = 0.2, g = 0.1, b = 0.25, a = 1 } }) + +-- orange tiles +local t = ExtendDataCopy("tile", "tutorial-grid", + { name = "warptorio-red-concrete", tint = { r = 1, g = 0.5, b = 0, a = 0.25 }, layer = 67, decorative_removal_probability = 1, walking_speed_modifier = 1.5, map_color = { r = 0.2, g = 0.1, b = 0, a = 1 } }) + +-- -------- +-- Invisiradar +local rtint = { r = 0.4, g = 0.4, b = 1, a = 1 } +local rvtint = { scale = 0.5 / 3, tint = { r = 1, g = 1, b = 1, a = 0 }, shift = { 0.03125 / 3, -0.5 / 3 } } +local r = ExtendDataCopy("radar", "radar", { + name = "warptorio-invisradar", + icons = { { icon = "__base__/graphics/icons/radar.png", tint = rtint } }, + integration_patch = rvtint, + pictures = { layers = { rvtint, rvtint } }, +}, true, { + energy_source = { type = "void" }, + energy_per_nearby_scan = "10kJ", + energy_per_sector = "200kJ", + energy_usage = "1kW", + icon = false, + max_distance_of_nearby_sector_revealed = 5, + max_distance_of_sector_revealed = 18, + collision_box = { { -1.2 / 3, -1.2 / 3 }, { 1.2 / 3, 1.2 / 3 } }, + selection_box = { { -1.5 / 3, -1.5 / 3 }, { 1.5 / 3, 1.5 / 3 } }, +}) + + +-- -------- +-- Loot Chest + +local rtint = { r = 0.4, g = 0.4, b = 1, a = 1 } +local t = ExtendDataCopy("container", "wooden-chest", { + name = "warptorio-lootchest", + inventory_size = 8, + icons = { { icon = "__base__/graphics/icons/wooden-chest.png", tint = rtint } }, + picture = { layers = { [1] = { tint = rtint }, } }, +}, true, { icon = false, minable = { mining_time = 0.1 } }) + + +-- -------- +-- Carebear Chest + +local rtint = rgb(255, 20, 147) +local t = ExtendDataCopy("container", "wooden-chest", { + name = "warptorio-carebear-chest", + inventory_size = 99, + icons = { { icon = "__base__/graphics/icons/wooden-chest.png", tint = rtint } }, + picture = { layers = { [1] = { tint = rtint }, } }, +}, true, { icon = false, minable = { mining_time = 10 } }) + + +-- ---- +-- Logistics + +--[[ +local rtint={r=0.5,g=0.5,b=1,a=1} +local rtintpic={tint=rtint,hr_version={tint=rtint}} +local rctint={r=0.39,g=0,b=0,a=1} +local rtintcov={layers={ [1]={tint=rctint,hr_version={tint=rctint}} }} +local t=ExtendDataCopy("pipe-to-ground","pipe-to-ground",{name="warptorio-logistics-pipe",fluid_box={base_area=5,pipe_connections={[2]={max_underground_distance=-1}}}, + pictures={ left=rtintpic, right=rtintpic,up=rtintpic,down=rtintpic }, + pipe_covers={ east={layers={ [1]={tint=rctint,hr_version={tint=rctint}} }}, north=rtintcov, south=rtintcov, west=rtintcov,} +},true) +]] + +-- -------- +-- Warp Reactor + +-- Fuel +data:extend { { type = "fuel-category", name = "warp" } } + +ExtendDataCopy("item", "uranium-fuel-cell", + { + name = "warptorio-warponium-fuel-cell", + fuel_category = "warp", + burnt_result = "uranium-fuel-cell", + fuel_value = "32GJ", + stack_size = 50, + icon_size = 64, + icons = { { icon = "__base__/graphics/icons/uranium-fuel-cell.png", tint = { r = 1, g = 0.2, b = 1, a = 0.8 } }, }, + }, false, { icon = false }) + +ExtendDataCopy("recipe", "uranium-fuel-cell", + { name = "warptorio-warponium-fuel-cell", enabled = false, results = { { type = "item", name = "warptorio-warponium-fuel-cell", amount = 1 } } }, + false, + { + ingredients = { { type = "item", name = "uranium-fuel-cell", amount = 5 } }, + icon_size = 64, + icons = { { icon = "__base__/graphics/icons/uranium-fuel-cell.png", tint = { r = 1, g = 0.2, b = 1, a = 0.8 } }, }, + }, false, { icon = false }) + +ExtendDataCopy("item", "nuclear-fuel", { + name = "warptorio-warponium-fuel", + fuel_category = "chemical", + fuel_acceleration_multiplier = 5, + fuel_value = "7GJ", + stack_size = 1, + fuel_top_speed_multiplier = 1.25, + icon_size = 64, + icons = { { icon = "__base__/graphics/icons/nuclear-fuel.png", tint = { r = 1, g = 0.2, b = 1, a = 0.8 } }, }, +}, false, { icon = false }) + +ExtendDataCopy("recipe", "nuclear-fuel", + { name = "warptorio-warponium-fuel", enabled = false, results = { { type = "item", name = "warptorio-warponium-fuel", amount = 1 } } }, + false, + { + ingredients = { { type = "item", name = "warptorio-warponium-fuel-cell", amount = 1 }, { type = "item", name = "nuclear-fuel", amount = 1 } }, + icon = false, + icon_size = 64, + icons = { { icon = "__base__/graphics/icons/nuclear-fuel.png", tint = { r = 1, g = 0.2, b = 1, a = 0.8 } }, }, + }) + + +-- The Reactor Itself +local t = ExtendDataCopy("reactor", "nuclear-reactor", + { + name = "warptorio-reactor", + max_health = 5000, + neighbour_bonus = 12, + consumption = "160MW", + energy_source = { fuel_categories = { "warp" } }, + heat_buffer = { specific_heat = "1MJ", max_temperature = 1000 }, + light = { intensity = 10, size = 9.9, shift = { 0.0, 0.0 }, color = { r = 1.0, g = 0.0, b = 0.0 } }, + working_light_picture = { filename = "__base__/graphics/entity/nuclear-reactor/reactor-lights-color.png", tint = { r = 1, g = 0.4, b = 0.4, a = 1 }, + }, + picture = { + layers = { + [1] = { tint = { r = 0.8, g = 0.8, b = 1, a = 1 } }, + } + }, + }, true) + + +-- ------------------------------------------------------------------------- +-- Technologies + + +-- ---- +-- Warp Roboport + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + effects = { { recipe = "warptorio-warpport", type = "unlock-recipe" } }, + icons = { + { icon = "__base__/graphics/entity/roboport/roboport-base.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_size = 220, scale = 0.25 }, + }, +} +ExtendTech(t, + { name = "warptorio-warpport", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-logistics-4", "warptorio-reactor-8", "space-science-pack" } }, + { red = 1, green = 1, black = 1, blue = 1, purple = 1, yellow = 1, white = 1 }) + + +-- ---- +-- Warp Nuke + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/atomic-bomb.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { + name = "warptorio-warpnuke", + unit = { count = 1000, time = 5 }, + effects = { { recipe = "warptorio-atomic-bomb", type = "unlock-recipe" } }, + prerequisites = { "atomic-bomb", "warptorio-reactor-8", "space-science-pack" } + }, { red = 1, green = 1, black = 1, blue = 1, purple = 1, yellow = 1, white = 1 }) + + +-- ---- +-- Warp Module + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/module.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { + name = "warptorio-warpmodule", + unit = { count = 3000, time = 60 }, + prerequisites = { "warptorio-reactor-8", "space-science-pack", "efficiency-module-3" }, + effects = { { recipe = "warptorio-warpmodule", type = "unlock-recipe" } }, + }, { red = 1, green = 1, black = 1, blue = 1, purple = 1, yellow = 1, white = 1 }) + +data:extend { { type = "module-category", name = "warpivity" } } +local t = { + type = "module", + category = "warpivity", + name = "warptorio-warpmodule", + stack_size = 50, + subgroup = "module", + tier = 4, + localised_description = { "item-description.warptorio-warpmodule" }, + limitation_message_key = "production-module-usable-only-on-intermediates", + effect = { consumption = 0.6, pollution = 0.05, productivity = 0.1, speed = 0.35 }, + icon_size = 64, + icons = { { icon = "__base__/graphics/icons/speed-module-3.png", tint = { r = 0.2, g = 0.2, b = 1, a = 1 } } }, +} +data:extend { t } + +data:extend { { type = "recipe", results = { { type = "item", name = "warptorio-warpmodule", amount = 1 } }, name = "warptorio-warpmodule", enabled = false, energy_required = 60, + ingredients = { + { type = "item", name = "speed-module-3", amount = 50 }, + { type = "item", name = "productivity-module-3", amount = 50 }, + { type = "item", name = "efficiency-module-3", amount = 50 }, + { type = "item", name = "advanced-circuit", amount = 200 }, + { type = "item", name = "processing-unit", amount = 200 }, + { type = "item", name = "low-density-structure", amount = 10 } + }, +} } + + +-- ---- +-- Warp Reactor + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/engine.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, { name = "warptorio-reactor-1", unit = { count = 50, time = 5 }, prerequisites = {} }, { red = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/electronics.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { name = "warptorio-reactor-2", unit = { count = 75, time = 10 }, prerequisites = { "warptorio-reactor-1", "logistic-science-pack" } }, + { red = 1, green = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/advanced-circuit.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { name = "warptorio-reactor-3", unit = { count = 100, time = 15 }, prerequisites = { "warptorio-reactor-2", "military-science-pack" } }, + { red = 1, green = 2, black = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/processing-unit.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { name = "warptorio-reactor-4", unit = { count = 200, time = 20 }, prerequisites = { "warptorio-reactor-3", "rocketry" } }, + { red = 2, green = 2, black = 1, }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/explosives.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { name = "warptorio-reactor-5", unit = { count = 250, time = 25 }, prerequisites = { "warptorio-reactor-4", "chemical-science-pack" } }, + { red = 1, green = 3, black = 1, blue = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/atomic-bomb.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, } + }, + localised_description = { "technology-description.warptorio-reactor-6" } +} +ExtendTech(t, + { name = "warptorio-reactor-6", unit = { count = 300, time = 30 }, effects = { { recipe = "warptorio-townportal", type = "unlock-recipe" } }, prerequisites = { "warptorio-reactor-5", "uranium-processing", "robotics" } }, + { red = 5, black = 5 }) -- reactor module + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/kovarex-enrichment-process.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { name = "warptorio-reactor-7", unit = { count = 500, time = 40 }, effects = { { recipe = "warptorio-heatpipe", type = "unlock-recipe" }, { recipe = "warptorio-warponium-fuel-cell", type = "unlock-recipe" } }, prerequisites = { "nuclear-power", "warptorio-reactor-6" } }, + { red = 1, green = 1, black = 1, blue = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__warptorio2__/graphics/technology/earth.png", tint = { r = 0.8, g = 0.8, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high" } + }, + localised_description = { "technology-description.warptorio-reactor-8" } +} +ExtendTech(t, + { name = "warptorio-reactor-8", unit = { count = 1000, time = 60 }, prerequisites = { "warptorio-reactor-7", "warptorio-charting", "warptorio-accelerator", "warptorio-stabilizer", "warptorio-kovarex" } }, + { red = 1, green = 1, black = 1, blue = 1, purple = 1, yellow = 1 }) -- steering + + + +-- ---- +-- Reactor Abilities + +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/battery.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-stabilizer", unit = { count = 400, time = 30 }, prerequisites = { "warptorio-reactor-6", "military-3", "circuit-network" } }, + { red = 1, green = 1, black = 1, blue = 1 }) -- stabilizer + +local t = { type = "technology", upgrade = false, icon_size = 128, icons = { { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, } }, } +t.icons = { { icon = "__base__/graphics/technology/engine.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } } +ExtendTech(t, + { name = "warptorio-accelerator", unit = { count = 400, time = 30 }, prerequisites = { "warptorio-reactor-6", "military-3", "circuit-network" } }, + { red = 1, green = 1, black = 1, blue = 1 }) -- accelerator + +local t = { type = "technology", upgrade = false, icon_size = 128, icons = { { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, } }, } +t.icons = { { icon = "__base__/graphics/technology/radar.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } } +ExtendTech(t, + { name = "warptorio-charting", unit = { count = 400, time = 30 }, prerequisites = { "warptorio-reactor-6", "military-3", "circuit-network" } }, + { red = 1, green = 1, black = 1, blue = 1 }) -- charting + + +local t = { + type = "technology", + upgrade = true, + icons = { + { icon = "__warptorio2__/graphics/technology/earth.png", tint = { r = 0.8, g = 0.8, b = 1, a = 1 }, scale = 0.375, priority = "low", icon_size = 128 } + }, +} +ExtendTech(t, + { name = "warptorio-homeworld", unit = { count = 5000, time = 30 }, effects = { { recipe = "warptorio-homeportal", type = "unlock-recipe" } }, prerequisites = { "warptorio-reactor-8", "space-science-pack" } }, + { red = 1, green = 1, black = 1, blue = 1, purple = 1, yellow = 1, white = 1 }) + + +-- ---- +-- Warponium Fuel + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/rocket-fuel.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + }, + effects = { { recipe = "warptorio-warponium-fuel", type = "unlock-recipe" } }, +} +ExtendTech(t, + { name = "warptorio-kovarex", unit = { count = 1000, time = 15 }, prerequisites = { "warptorio-reactor-7", "kovarex-enrichment-process" } }, + { red = 1, green = 1, black = 1, blue = 1, purple = 1 }) -- Kovarex + + +-- ---- +-- Boiler Warp Substation + +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/electric-energy-distribution-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-boiler-station", unit = { count = 500, time = 10 }, prerequisites = { "electric-energy-distribution-2", "warptorio-boiler-0", "production-science-pack" } }, + { red = 1, blue = 1, green = 1, purple = 1 }) + + +-- ---- +-- Warp Energy Pipe + +local rtint = { tint = { r = 0.3, g = 0.3, b = 1, a = 1 } } + +--[[ +local pipe_sprites={corner_left_down={{rtint},{rtint},{rtint},{rtint},{rtint}},corner_left_up={{rtint},{rtint},{rtint},{rtint},{rtint},{rtint}}, + corner_right_down={{rtint},{rtint},{rtint},{rtint},{rtint},{rtint}},corner_right_up={{rtint},{rtint},{rtint},{rtint},{rtint},{rtint}}, + cross={{rtint}},ending_down={{rtint}},ending_left={{rtint}},ending_right={{rtint}},ending_up={{rtint}},single={{rtint}}, + straight_horizontal={{rtint},{rtint},{rtint},{rtint},{rtint},{rtint}},straight_vertical={{rtint},{rtint},{rtint},{rtint},{rtint},{rtint}}, + t_down={{rtint}},t_left={{rtint}},t_right={{rtint}},t_up={{rtint}},} + +local t=ExtendDataCopy("heat-pipe","heat-pipe",{name="warptorio-heatpipe",connection_sprites=pipe_sprites,heat_glow_sprites=pipe_sprites, + max_temperature=5000, + max_transfer="5GW", + specific_heat="1MJ", + icon_size=64,icons={ {icon="__base__/graphics/icons/heat-pipe.png",tint={r=0.3,g=0.3,b=1,a=1},hr_version={tint={r=0.3,g=0.3,b=1,a=1}} } } +})]] + +local pipe_icon = { { icon = "__base__/graphics/icons/heat-pipe.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 64 } } +local t = ExtendDataCopy("recipe", "heat-pipe", + { name = "warptorio-heatpipe", results = { { type = "item", name = "warptorio-heatpipe", amount = 1 } }, ingredients = { { type = "item", name = "processing-unit", amount = 200 }, { type = "item", name = "heat-pipe", amount = 50 } }, enabled = false, energy_required = 30, }) +local t = ExtendDataCopy("item", "heat-pipe", { + name = "warptorio-heatpipe", + place_result = "warptorio-heatpipe", + icon_size = 64, + icons = pipe_icon, +}) + +-- ---- +-- Sandbox Boosts + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { { icon = "__base__/graphics/technology/mining-productivity.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, + effects = { { type = "mining-drill-productivity-bonus", modifier = 0.1 } }, +} +ExtendTech(t, { name = "warptorio-mining-prod-1", unit = { count_formula = "20*L", time = 30 }, max_level = 5 }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-mining-prod-6", unit = { count_formula = "(20*L)+50", time = 40 }, max_level = 10, prerequisites = { "warptorio-mining-prod-1", "logistic-science-pack" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-mining-prod-11", unit = { count_formula = "(20*L)+100", time = 50 }, max_level = 15, prerequisites = { "warptorio-mining-prod-6", "chemical-science-pack" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-mining-prod-16", unit = { count_formula = "(20*L)+150", time = 60 }, max_level = 20, prerequisites = { "warptorio-mining-prod-11", "production-science-pack" } }, + { red = 3, green = 3, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-mining-prod-21", unit = { count_formula = "(20*L)+200", time = 60 }, max_level = 25, prerequisites = { "warptorio-mining-prod-16", "utility-science-pack" } }, + { red = 3, green = 3, blue = 2, purple = 1, yellow = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 64, + icons = { { icon = "__base__/graphics/technology/steel-axe.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, + effects = { { type = "character-mining-speed", modifier = 0.5 } }, +} +ExtendTech(t, + { name = "warptorio-axe-speed-1", unit = { count_formula = "50*L", time = 30 }, prerequisites = { "steel-axe", "warptorio-reactor-1" }, max_level = 2 }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-axe-speed-3", unit = { count_formula = "(50*L)+50", time = 30 }, max_level = 4, prerequisites = { "warptorio-axe-speed-1", "logistic-science-pack" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-axe-speed-5", unit = { count_formula = "(50*L)+100", time = 30 }, max_level = 6, prerequisites = { "warptorio-axe-speed-3", "chemical-science-pack" } }, + { red = 1, green = 1, blue = 1 }) +ExtendTech(t, + { name = "warptorio-axe-speed-7", unit = { count_formula = "(50*L)+150", time = 30 }, max_level = 8, prerequisites = { "warptorio-axe-speed-5", "production-science-pack" } }, + { red = 1, green = 1, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-axe-speed-9", unit = { count_formula = "(50*L)+200", time = 30 }, max_level = 10, prerequisites = { "warptorio-axe-speed-7", "utility-science-pack" } }, + { red = 1, green = 1, blue = 1, purple = 1, yellow = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { { icon = "__base__/graphics/technology/inserter-capacity.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, + effects = { { type = "bulk-inserter-capacity-bonus", modifier = 1 }, { type = "inserter-stack-size-bonus", modifier = 1 }, } +} +ExtendTech(t, + { name = "warptorio-inserter-cap-1", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-reactor-1", "fast-inserter" }, }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-inserter-cap-2", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-inserter-cap-1", "logistic-science-pack" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-inserter-cap-3", unit = { count = 250, time = 30 }, prerequisites = { "warptorio-inserter-cap-2", "chemical-science-pack" } }, + { red = 3, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-inserter-cap-4", unit = { count = 300, time = 30 }, prerequisites = { "warptorio-inserter-cap-3", "production-science-pack" } }, + { red = 4, green = 3, blue = 2, purple = 1 }) +ExtendTech(t, + { name = "warptorio-inserter-cap-5", unit = { count = 350, time = 30 }, prerequisites = { "warptorio-inserter-cap-4", "utility-science-pack" } }, + { red = 5, green = 4, blue = 3, purple = 2, yellow = 1 }) + + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { { icon = "__base__/graphics/technology/worker-robots-speed.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, + effects = { { type = "worker-robot-speed", modifier = 0.35 }, } +} +ExtendTech(t, + { name = "warptorio-bot-speed-1", unit = { count = 120, time = 30 }, prerequisites = { "robotics", "warptorio-reactor-2" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-bot-speed-2", unit = { count = 180, time = 30 }, prerequisites = { "warptorio-bot-speed-1", "logistic-robotics" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-bot-speed-3", unit = { count = 250, time = 30 }, prerequisites = { "warptorio-bot-speed-2", "chemical-science-pack" } }, + { red = 3, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-bot-speed-4", unit = { count = 300, time = 30 }, prerequisites = { "warptorio-bot-speed-3", "production-science-pack" } }, + { red = 4, green = 3, blue = 2, purple = 1 }) +ExtendTech(t, + { name = "warptorio-bot-speed-5", unit = { count = 350, time = 30 }, prerequisites = { "warptorio-bot-speed-4", "utility-science-pack" } }, + { red = 5, green = 4, blue = 3, purple = 2, yellow = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { { icon = "__base__/graphics/technology/worker-robots-storage.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, + effects = { { type = "worker-robot-storage", modifier = 1 }, } +} +ExtendTech(t, + { name = "warptorio-bot-cap-1", unit = { count = 120, time = 30 }, prerequisites = { "robotics", "warptorio-reactor-2" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-bot-cap-2", unit = { count = 180, time = 30 }, prerequisites = { "warptorio-bot-cap-1", "construction-robotics" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-bot-cap-3", unit = { count = 250, time = 30 }, prerequisites = { "warptorio-bot-cap-2", "chemical-science-pack" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-bot-cap-4", unit = { count = 300, time = 30 }, prerequisites = { "warptorio-bot-cap-3", "production-science-pack" } }, + { red = 3, green = 3, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-bot-cap-5", unit = { count = 350, time = 30 }, prerequisites = { "warptorio-bot-cap-4", "utility-science-pack" } }, + { red = 3, green = 3, blue = 2, purple = 1, yellow = 1 }) + + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { { icon = "__base__/graphics/technology/physical-projectile-damage-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, + effects = { { type = "turret-attack", modifier = 0.15, turret_id = "gun-turret" }, { ammo_category = "bullet", modifier = 0.15, type = "ammo-damage" }, { ammo_category = "shotgun-shell", modifier = 0.2, type = "ammo-damage" } } +} +ExtendTech(t, + { name = "warptorio-physdmg-1", unit = { count = 250, time = 30 }, prerequisites = { "warptorio-reactor-1", "physical-projectile-damage-1" } }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-physdmg-2", unit = { count = 250, time = 30 }, prerequisites = { "warptorio-reactor-2", "warptorio-physdmg-1", "physical-projectile-damage-2" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-physdmg-3", unit = { count = 350, time = 30 }, prerequisites = { "warptorio-reactor-3", "warptorio-physdmg-2", "physical-projectile-damage-3" } }, + { red = 3, green = 2, black = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { { icon = "__base__/graphics/technology/toolbelt.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, + effects = { { type = "character-inventory-slots-bonus", modifier = 10 } }, +} +ExtendTech(t, + { name = "warptorio-toolbelt-1", unit = { count = 70, time = 30 }, prerequisites = { "warptorio-reactor-1" } }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-toolbelt-2", unit = { count = 120, time = 30 }, prerequisites = { "warptorio-toolbelt-1", "toolbelt", "logistic-science-pack" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-toolbelt-3", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-toolbelt-2", "chemical-science-pack" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-toolbelt-4", unit = { count = 180, time = 30 }, prerequisites = { "warptorio-toolbelt-3", "production-science-pack" } }, + { red = 3, green = 2, blue = 2, purple = 1 }) +ExtendTech(t, + { name = "warptorio-toolbelt-5", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-toolbelt-4", "utility-science-pack" } }, + { red = 4, green = 3, blue = 2, purple = 2, yellow = 1 }) + +local t = { + type = "technology", + upgrade = true, + icons = { + { icon = "__warptorio2__/graphics/technology/earth.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, shift = { 0, 0 }, scale = 0.375, priority = "medium", icon_size = 128 }, + { icon = "__base__/graphics/technology/steel-axe.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_size = 256, scale = 0.125 }, + }, + effects = { + { type = "character-reach-distance", modifier = 1 }, + { type = "character-build-distance", modifier = 1 }, + { type = "character-item-drop-distance", modifier = 1 }, + { type = "character-resource-reach-distance", modifier = 1 }, + }, +} +ExtendTech(t, { name = "warptorio-reach-1", unit = { count = 50, time = 30 }, prerequisites = { "warptorio-reactor-1" } }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-reach-2", unit = { count = 100, time = 30 }, prerequisites = { "warptorio-reach-1", "logistic-science-pack" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-reach-3", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-reach-2", "chemical-science-pack" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-reach-4", unit = { count = 180, time = 30 }, prerequisites = { "warptorio-reach-3", "production-science-pack" } }, + { red = 3, green = 2, blue = 2, purple = 1 }) +ExtendTech(t, + { name = "warptorio-reach-5", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-reach-4", "utility-science-pack" } }, + { red = 4, green = 3, blue = 2, purple = 2, yellow = 1 }) + + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/exoskeleton-equipment.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + }, + effects = { + { type = "character-running-speed", modifier = 0.1 }, + }, +} +ExtendTech(t, + { name = "warptorio-striders-1", unit = { count = 150, time = 20 }, prerequisites = { "warptorio-reactor-1" }, upgrade = false }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-striders-2", unit = { count = 300, time = 20 }, prerequisites = { "warptorio-reactor-2", "modular-armor", "warptorio-striders-1" }, upgrade = false }, + { red = 1, green = 1 }) + + + +-- ---- +-- Platform Size + +local t = { type = "technology", upgrade = true, icon_size = 128, icons = { { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, } +ExtendTech(t, { name = "warptorio-platform-size-1", unit = { count = 70, time = 20 }, prerequisites = {} }, { red = 1 }) +ExtendTech(t, + { name = "warptorio-platform-size-2", unit = { count = 120, time = 20 }, prerequisites = { "warptorio-platform-size-1", "warptorio-reactor-1" } }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-platform-size-3", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-platform-size-2", "logistic-science-pack" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-platform-size-4", unit = { count = 200, time = 30 }, prerequisites = { "concrete", "warptorio-platform-size-3" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-platform-size-5", unit = { count = 120, time = 30 }, prerequisites = { "chemical-science-pack", "warptorio-platform-size-4" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-platform-size-6", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-platform-size-5", "solar-energy", "production-science-pack" } }, + { red = 2, green = 2, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-platform-size-7", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-platform-size-6", "utility-science-pack" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) + + +-- ---- +-- Train Stops + + +for v, w in pairs({ nw = { -38, -38 }, ne = { 38, -38 }, se = { 38, 38 }, sw = { -38, 38 } }) do + local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/railway.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "low", icon_mipmaps = 4, icon_size = 256, scale = 0.375 }, + { icon = "__base__/graphics/technology/railway.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, shift = { w[1], w[2] }, scale = 0.25, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + }, + } + + ExtendTech(t, + { name = "warptorio-rail-" .. v, unit = { count = 500, time = 30 }, prerequisites = { "railway", "warptorio-platform-size-6", "warptorio-factory-7" } }, + { red = 1, green = 1, black = 1, blue = 1, purple = 1, yellow = 1 }) +end + + +-- ---- +-- Castle Ramps + + +for v, w in pairs({ nw = { -38, -38 }, ne = { 38, -38 }, se = { 38, 38 }, sw = { -38, 38 } }) do + local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/stone-wall.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, scale = 0.4 }, + { icon = "__base__/graphics/technology/stone-wall.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, shift = { w[1], w[2] }, scale = 0.25, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + }, + } + ExtendTech(t, + { name = "warptorio-turret-" .. v .. "-0", upgrade = false, unit = { count = 100, time = 30 }, prerequisites = { "gate", "warptorio-factory-0" } }, + { red = 1, green = 1 }) + ExtendTech(t, + { name = "warptorio-turret-" .. v .. "-1", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-turret-" .. v .. "-0", "military-science-pack", } }, + { red = 2, green = 1, black = 1, }) + ExtendTech(t, + { name = "warptorio-turret-" .. v .. "-2", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-turret-" .. v .. "-1", "chemical-science-pack" } }, + { red = 2, green = 1, black = 1, blue = 1 }) + ExtendTech(t, + { name = "warptorio-turret-" .. v .. "-3", unit = { count = 300, time = 40 }, prerequisites = { "warptorio-turret-" .. v .. "-2", "production-science-pack" } }, + { red = 2, green = 2, black = 1, blue = 1, purple = 1 }) +end + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/stone-wall.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/stone-wall.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, shift = { 32, 32 }, scale = 0.25, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/stone-wall.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, shift = { -32, -32 }, scale = 0.25, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/stone-wall.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, shift = { -32, 32 }, scale = 0.25, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/stone-wall.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, shift = { 32, -32 }, scale = 0.25, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { + name = "warptorio-bridgesize-1", + unit = { count = 500, time = 40 }, + prerequisites = { "warptorio-turret-nw-0", "warptorio-turret-ne-0", "warptorio-turret-se-0", "warptorio-turret-sw-0" }, + unit = { count = 200, time = 40 } + }, { red = 1, green = 1, black = 1 }) +ExtendTech(t, + { + name = "warptorio-bridgesize-2", + unit = { count = 500, time = 40 }, + prerequisites = { "warptorio-bridgesize-1", "warptorio-turret-nw-1", "warptorio-turret-ne-1", "warptorio-turret-se-1", "warptorio-turret-sw-1", "low-density-structure" }, + unit = { count = 400, time = 40 } + }, { red = 1, green = 1, black = 1, blue = 1 }) + +-- ---- +-- Factory Floor Upgrades + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/automation-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { + name = "warptorio-factory-0", + unit = { count = 80, time = 20 }, + prerequisites = { "automation", "warptorio-platform-size-1" }, + upgrade = false, + localised_name = { "technology-name.warptorio-factory" }, + localised_description = { "technology-description.warptorio-factory-floor" }, + }, { red = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/automation-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 16, 16 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-factory-1", unit = { count = 120, time = 20 }, prerequisites = { "warptorio-factory-0", "steel-processing" } }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-factory-2", unit = { count = 150, time = 20 }, prerequisites = { "electric-energy-distribution-1", "advanced-material-processing", "automation-2", "warptorio-factory-1" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-factory-3", unit = { count = 180, time = 20 }, prerequisites = { "warptorio-factory-2", "sulfur-processing" } }, + { red = 2, green = 2 }) +ExtendTech(t, + { name = "warptorio-factory-4", unit = { count = 220, time = 20 }, prerequisites = { "warptorio-factory-3", "chemical-science-pack", "modules" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-factory-5", unit = { count = 250, time = 20 }, prerequisites = { "warptorio-factory-4", "advanced-material-processing-2" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-factory-6", unit = { count = 300, time = 20 }, prerequisites = { "warptorio-factory-5", "automation-3" } }, + { red = 2, green = 2, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-factory-7", unit = { count = 350, time = 20 }, prerequisites = { "warptorio-factory-6", "utility-science-pack", "effect-transmission" } }, + { red = 2, green = 3, blue = 1, purple = 1, yellow = 1 }) + +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/automation-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 0, -24 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-factory-n", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-factory-7", "space-science-pack", "warptorio-bridgesize-2" } }, + { red = 3, green = 2, blue = 3, purple = 2, yellow = 1, white = 1 }) +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/automation-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 0, 24 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-factory-s", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-factory-7", "space-science-pack", "warptorio-bridgesize-2" } }, + { red = 3, green = 2, blue = 3, purple = 2, yellow = 1, white = 1 }) +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/automation-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 24, 0 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-factory-e", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-factory-7", "space-science-pack", "warptorio-bridgesize-2" } }, + { red = 3, green = 2, blue = 3, purple = 2, yellow = 1, white = 1 }) +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/automation-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { -24, 0 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-factory-w", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-factory-7", "space-science-pack", "warptorio-bridgesize-2" } }, + { red = 3, green = 2, blue = 3, purple = 2, yellow = 1, white = 1 }) + +-- ---- +-- Boiler Room Upgrades + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { + name = "warptorio-boiler-0", + unit = { count = 100, time = 30 }, + prerequisites = { "steel-processing", "warptorio-harvester-floor" }, + upgrade = false, + localised_name = { "technology-name.warptorio-boiler" }, + localised_description = { "technology-description.warptorio-boiler-floor" }, + }, { red = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 16, 16 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-boiler-1", unit = { count = 100, time = 30 }, prerequisites = { "warptorio-boiler-0", "fluid-handling" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-boiler-2", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-boiler-1", "flammables" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-boiler-3", unit = { count = 300, time = 30 }, prerequisites = { "warptorio-boiler-2", "battery" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-boiler-4", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-boiler-3", "chemical-science-pack" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-boiler-5", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-boiler-4", "production-science-pack" } }, + { red = 2, green = 2, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-boiler-6", unit = { count = 300, time = 30 }, prerequisites = { "warptorio-boiler-5", "nuclear-fuel-reprocessing" } }, + { red = 2, green = 2, blue = 1, purple = 1, }) +ExtendTech(t, + { name = "warptorio-boiler-7", unit = { count = 300, time = 30 }, prerequisites = { "warptorio-boiler-6", "utility-science-pack" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) + + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/oil-gathering.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 16, 16 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-boiler-water-1", upgrade = true, unit = { count = 500, time = 30 }, prerequisites = { "warptorio-boiler-3", "landfill" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-boiler-water-2", upgrade = true, unit = { count = 1000, time = 40 }, prerequisites = { "warptorio-boiler-5", "warptorio-boiler-water-1" } }, + { red = 2, green = 2, blue = 1, purple = 1 }) + +ExtendTech(t, + { name = "warptorio-boiler-water-3", upgrade = true, unit = { count = 2000, time = 50 }, prerequisites = { "warptorio-boiler-water-2", "space-science-pack" } }, + { red = 1, green = 1, blue = 1, purple = 1, yellow = 1, white = 1 }) + +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 0, -24 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-boiler-n", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-boiler-7", "space-science-pack" } }, + { red = 3, green = 2, blue = 2, purple = 2, yellow = 1, white = 1 }) + +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 0, 24 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-boiler-s", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-boiler-7", "space-science-pack" } }, + { red = 3, green = 2, blue = 2, purple = 2, yellow = 1, white = 1 }) +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 24, 0 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-boiler-e", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-boiler-7", "space-science-pack" } }, + { red = 3, green = 2, blue = 2, purple = 2, yellow = 1, white = 1 }) +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { -24, 0 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-boiler-w", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-boiler-7", "space-science-pack" } }, + { red = 3, green = 2, blue = 2, purple = 2, yellow = 1, white = 1 }) + + + + +-- ---- +-- Harvester Size + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/tank.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { name = "warptorio-harvester-floor", unit = { count = 100, time = 30 }, prerequisites = { "fast-inserter", "warptorio-factory-0" }, upgrade = false }, + { red = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 256, + icons = { + { icon = "__base__/graphics/technology/tank.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, shift = { 16, 16 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-harvester-size-1", unit = { count = 100, time = 30 }, prerequisites = { "warptorio-harvester-floor", "oil-processing" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-harvester-size-2", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-harvester-size-1", "bulk-inserter" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-harvester-size-3", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-harvester-size-2", "mining-productivity-1" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-harvester-size-4", unit = { count = 250, time = 30 }, prerequisites = { "warptorio-harvester-size-3", "chemical-science-pack" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-harvester-size-5", unit = { count = 300, time = 30 }, prerequisites = { "warptorio-harvester-size-4", "production-science-pack", "mining-productivity-2" } }, + { red = 2, green = 2, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-harvester-size-6", unit = { count = 350, time = 30 }, prerequisites = { "warptorio-harvester-size-5", "nuclear-fuel-reprocessing" } }, + { red = 2, green = 2, blue = 1, purple = 1, }) +ExtendTech(t, + { name = "warptorio-harvester-size-7", unit = { count = 400, time = 30 }, prerequisites = { "warptorio-harvester-size-6", "utility-science-pack", "mining-productivity-3" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) + + +for v, w in pairs({ east = { 24, 0 }, west = { -24, 0 } }) do + local odr = (v == "east" and "a-b" or "a-a") + local t = { + type = "technology", + upgrade = true, + icon_size = 256, + icons = { + { icon = "__base__/graphics/technology/tank.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 1, g = 0.7, b = 0.4, a = 0.9 }, shift = { w[1], w[2] }, scale = 0.25, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + }, + } + --ExtendTech(t,{name="warptorio-harvester-"..v.."-gate",upgrade=false, unit={count=150,time=25}, prerequisites={"warptorio-harvester-floor"}}, {red=1,green=1} ) + + ExtendTech(t, + { name = "warptorio-harvester-" .. v .. "-1", order = odr, unit = { count = 150, time = 25 }, prerequisites = { "warptorio-harvester-floor" }, localised_description = { "technology-description.warptorio-harvester-" .. v .. "-gate" } }, + { red = 1, green = 1, }) + ExtendTech(t, + { name = "warptorio-harvester-" .. v .. "-2", order = odr, unit = { count = 200, time = 25 }, prerequisites = { "warptorio-harvester-" .. v .. "-1", "mining-productivity-1", "military-science-pack" } }, + { red = 2, green = 1, black = 1 }) + ExtendTech(t, + { name = "warptorio-harvester-" .. v .. "-3", order = odr, unit = { count = 300, time = 25 }, prerequisites = { "warptorio-harvester-" .. v .. "-2", "mining-productivity-2" } }, + { red = 2, green = 2, black = 1, blue = 1 }) + ExtendTech(t, + { name = "warptorio-harvester-" .. v .. "-4", order = odr, unit = { count = 400, time = 25 }, prerequisites = { "warptorio-harvester-" .. v .. "-3", "nuclear-fuel-reprocessing" } }, + { red = 2, green = 2, black = 1, blue = 1, purple = 1 }) + ExtendTech(t, + { name = "warptorio-harvester-" .. v .. "-5", order = odr, unit = { count = 500, time = 25 }, prerequisites = { "warptorio-harvester-" .. v .. "-4", "mining-productivity-3" } }, + { red = 2, green = 2, black = 1, blue = 1, purple = 1, yellow = 1 }) +end + +--[[ todo +for v,w in pairs({nw={-38,-38},ne={38,-38},se={38,38},sw={-38,38}})do +local t={type="technology",upgrade=true,icon_size=128,icons={ + {icon="__base__/graphics/technology/tank.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, + {icon="__base__/graphics/technology/concrete.png",tint={r=1,g=0.7,b=0.4,a=0.9},shift={w[1],w[2]},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, +}, } +ExtendTech(t,{name="warptorio-harvester-"..v.."",upgrade=false, unit={count=1000,time=40}, prerequisites={"warptorio-harvester-size-7","warptorio-reactor-8","space-science-pack"}}, {red=1,green=1,black=1,blue=1,purple=1,yellow=1,white=1} ) +end +]] + +-- ---- +-- Logistics + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/logistics-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-logistics-1", unit = { count = 100, time = 20 }, prerequisites = { "logistics", "warptorio-factory-0" }, upgrade = false }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-logistics-2", unit = { count = 200, time = 20 }, prerequisites = { "logistics-2", "warptorio-logistics-1" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-logistics-3", unit = { count = 300, time = 20 }, prerequisites = { "logistics-3", "warptorio-logistics-2" } }, + { red = 2, green = 2, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-logistics-4", unit = { count = 400, time = 20 }, prerequisites = { "logistic-system", "warptorio-logistics-3" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/logistics-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/logistics-2.png", tint = { r = 1, g = 1, b = 0.7, a = 0.9 }, shift = { -14, 12 }, scale = 0.2, priority = "medium", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/logistics-3.png", tint = { r = 1, g = 1, b = 0.7, a = 0.9 }, shift = { 14, 12 }, scale = 0.2, priority = "medium", icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-dualloader-1", unit = { count = 500, time = 20 }, prerequisites = { "logistics-2", "warptorio-logistics-1" } }, + { red = 1, green = 1 }) +--ExtendTech(t,{name="warptorio-dualloader-2", unit={count=1000,time=15}, prerequisites={"logistics-2","warptorio-dualloader-1"}}, {red=2,green=1} ) +--ExtendTech(t,{name="warptorio-dualloader-3", unit={count=1000,time=20}, prerequisites={"logistics-3","warptorio-dualloader-2","production-science-pack"}}, {red=3,green=2,blue=1,purple=1} ) +t.upgrade = false + +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/logistics-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/logistics-1.png", tint = { r = 1, g = 1, b = 0.7, a = 0.9 }, shift = { -16, -6 }, scale = 0.2, priority = "medium", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/logistics-2.png", tint = { r = 1, g = 1, b = 0.7, a = 0.9 }, shift = { 16, -6 }, scale = 0.2, priority = "medium", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/logistics-3.png", tint = { r = 1, g = 1, b = 0.7, a = 0.9 }, shift = { 0, 16 }, scale = 0.2, priority = "medium", icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-triloader", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-dualloader-1", "chemical-science-pack" } }, + { red = 1, green = 1, blue = 1 }) + + + +-- ---- +-- Warp Loader + +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/logistics-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__warptorio2__/graphics/technology/earth.png", tint = { r = 0.8, g = 0.8, b = 1, a = 1 }, scale = 1, shift = { 32, 32 }, priority = "high", icon_size = 128, scale = 0.5 } + }, + effects = { { recipe = "warptorio-warploader", type = "unlock-recipe" } }, +} +ExtendTech(t, + { name = "warptorio-warploader", unit = { count = 10000, time = 60 }, prerequisites = { "warptorio-armor", "warptorio-warpmodule", "warptorio-warpnuke", "warptorio-warpport" } }, + { red = 1, green = 1, blue = 1, purple = 1, yellow = 1, white = 1 }) + + + +-- ---- +-- Energy Upgrades + +local t = { type = "technology", upgrade = true, icon_size = 128, icons = { { icon = "__base__/graphics/technology/electric-energy-acumulators.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, } +ExtendTech(t, + { name = "warptorio-energy-1", unit = { count = 30, time = 20 }, prerequisites = { "warptorio-factory-0" }, upgrade = false }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-energy-2", unit = { count = 100, time = 25 }, prerequisites = { "warptorio-energy-1", "electric-energy-distribution-1" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-energy-3", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-energy-2", "advanced-circuit" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-energy-4", unit = { count = 200, time = 35 }, prerequisites = { "warptorio-energy-3", "electric-energy-distribution-2", "processing-unit" } }, + { red = 1, green = 1, blue = 1 }) +ExtendTech(t, + { name = "warptorio-energy-5", unit = { count = 250, time = 40 }, prerequisites = { "warptorio-energy-4", "utility-science-pack", "production-science-pack" } }, + { red = 1, green = 1, blue = 1, purple = 1, yellow = 1 }) + +-- ---- +-- Teleporter + +local t = { type = "technology", upgrade = true, icon_size = 128, icons = { { icon = "__base__/graphics/technology/research-speed.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, } +ExtendTech(t, + { name = "warptorio-teleporter-portal", unit = { count = 50, time = 20 }, prerequisites = { "warptorio-factory-0", "electronics", }, upgrade = false }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-teleporter-1", unit = { count = 100, time = 20 }, prerequisites = { "warptorio-teleporter-portal", "electric-energy-distribution-1" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-teleporter-2", unit = { count = 150, time = 20 }, prerequisites = { "warptorio-teleporter-1", "advanced-circuit" } }, + { red = 2, green = 2, }) +ExtendTech(t, + { name = "warptorio-teleporter-3", unit = { count = 200, time = 20 }, prerequisites = { "warptorio-teleporter-2", "electric-energy-distribution-2", "processing-unit" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-teleporter-4", unit = { count = 250, time = 20 }, prerequisites = { "warptorio-teleporter-3", "nuclear-power" } }, + { red = 2, green = 2, blue = 2, }) +ExtendTech(t, + { name = "warptorio-teleporter-5", unit = { count = 300, time = 20 }, prerequisites = { "warptorio-teleporter-4", "utility-science-pack", "production-science-pack" } }, + { red = 2, green = 3, blue = 2, purple = 1, yellow = 1 }) + + +-- ---- +-- Beacon + + +local t = { type = "technology", upgrade = true, icon_size = 64, icons = { { icon = "__base__/graphics/icons/beacon.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 } } }, } +ExtendTech(t, + { name = "warptorio-beacon-1", unit = { count = 300, time = 20 }, prerequisites = { "modules", "warptorio-factory-0" }, upgrade = false }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-2", unit = { count = 400, time = 20 }, prerequisites = { "warptorio-beacon-1", "speed-module", "productivity-module", "efficiency-module" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-3", unit = { count = 500, time = 20 }, prerequisites = { "warptorio-beacon-2", "speed-module-2", "productivity-module-2", "efficiency-module-2" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-4", unit = { count = 600, time = 20 }, prerequisites = { "warptorio-beacon-3", "speed-module-3", "productivity-module-3", "efficiency-module-3" } }, + { red = 2, green = 2, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-5", unit = { count = 700, time = 20 }, prerequisites = { "warptorio-beacon-4", "utility-science-pack" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-6", unit = { count = 800, time = 20 }, prerequisites = { "warptorio-beacon-5" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-7", unit = { count = 1000, time = 20 }, prerequisites = { "warptorio-beacon-6" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-8", unit = { count = 1200, time = 20 }, prerequisites = { "warptorio-beacon-7" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-9", unit = { count = 1500, time = 20 }, prerequisites = { "warptorio-beacon-8", "space-science-pack" } }, + { red = 3, green = 3, blue = 2, purple = 1, yellow = 1, white = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-10", unit = { count = 2000, time = 20 }, prerequisites = { "warptorio-beacon-9" } }, + { red = 3, green = 3, blue = 2, purple = 2, yellow = 2, white = 1 }) + +--[[ unused +local t={type="technology",upgrade=true,icon_size=64,icons={ {icon="__base__/graphics/icons/beacon.png",tint={r=0.3,g=0.3,b=1,a=1}} }, } +ExtendTech(t,{name="warptorio-beacon-1",unit={count=300,time=20}, prerequisites={"modules","warptorio-factory-0"},upgrade=false}, {red=1,green=1}) +ExtendTech(t,{name="warptorio-beacon-2",unit={count=500,time=20}, prerequisites={"warptorio-beacon-1","speed-module","productivity-module","efficiency-module"}}, {red=1,green=1}) +ExtendTech(t,{name="warptorio-beacon-3",unit={count=300,time=20}, prerequisites={"warptorio-beacon-2","speed-module-2","productivity-module-2","efficiency-module-2"}}, {red=2,green=2,blue=1}) +ExtendTech(t,{name="warptorio-beacon-4",unit={count=500,time=20}, prerequisites={"warptorio-beacon-3","speed-module-3","productivity-module-3","efficiency-module-3"}}, {red=2,green=2,blue=1,purple=1}) +ExtendTech(t,{name="warptorio-beacon-5",unit={count_formula="250+50*L",time=20},max_level=10, prerequisites={"warptorio-beacon-4","utility-science-pack"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) +ExtendTech(t,{name="warptorio-beacon-11",unit={count=5,time=1}, prerequisites={"warptorio-beacon-5"}}, {red=5,green=5,blue=5,purple=5,white=5}) +ExtendTech(t,{name="warptorio-beacon-12",unit={count=5,time=1}, prerequisites={"warptorio-beacon-11"}}, {red=2,green=5,blue=5,purple=5,white=5}) +]] + + +-- ---- +-- Warp Beacon + +local t = ExtendDataCopy("beacon", "beacon", { + name = "warptorio-beacon-1", + supply_area_distance = 16, + module_slots = 1, + base_picture = { tint = { r = 0.5, g = 0.7, b = 1, a = 1 }, }, + animation = { tint = { r = 1, g = 0.2, b = 0.2, a = 1 }, }, + allowed_effects = { "consumption", "speed", "pollution", "productivity" }, + distribution_effectivity = 1, +}, true) +for i = 2, 10, 1 do + local xt = table.deepcopy(t) + xt.name = "warptorio-beacon-" .. i + xt.supply_area_distance = math.min(16 + 8 * i, 64) + xt.module_slots = i + data:extend { xt } +end + +-- ---- +-- Radar + +--[[ +local t={type="technology",icon_size=128,icons={ {icon="__base__/graphics/technology/radar.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, } +ExtendTech(t,{name="warptorio-radar-1",unit={count=300,time=15},prerequisites={"radar","chemical-science-pack","optics"}}, {red=1,green=1}) +]] + + +-- ---- +-- Warp Armor +local t = { type = "technology", icon_size = 128, icons = { { icon = "__base__/graphics/technology/power-armor-mk2.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_size = 256 }, }, prerequisites = { "power-armor-mk2", "warptorio-reactor-8", "space-science-pack", } } +ExtendTech(t, + { name = "warptorio-armor", unit = { count = 1000, time = 60 }, effects = { { recipe = "warptorio-armor", type = "unlock-recipe" } } }, + { red = 4, green = 4, blue = 4, black = 5, yellow = 2, white = 1 }) + + +data:extend { { type = "equipment-grid", name = "warptorio-warparmor-grid", equipment_categories = { "armor" }, height = 16, width = 16 } } +local t = ExtendDataCopy("armor", "power-armor-mk2", { + name = "warptorio-armor", + equipment_grid = "warptorio-warparmor-grid", + icon_size = 64, + icons = { { icon = "__base__/graphics/icons/power-armor-mk2.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, } }, + inventory_size_bonus = 100 +}, false) + +local t = ExtendDataCopy("recipe", "power-armor-mk2", + { + name = "warptorio-armor", + enabled = false, + ingredients = { + { type = "item", name = "power-armor-mk2", amount = 1 }, + { type = "item", name = "power-armor", amount = 1 }, + { type = "item", name = "modular-armor", amount = 1 }, + { type = "item", name = "heavy-armor", amount = 1 }, + { type = "item", name = "light-armor", amount = 1 }, + { type = "item", name = "warptorio-warponium-fuel-cell", amount = 10 }, + }, + results = { + { type = "item", name = "warptorio-armor", amount = 1 } + } + }) + + + +-- ---- +-- Warp Combinators + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/circuit-network.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + --{icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, + }, + effects = { + { recipe = "warptorio-combinator", type = "unlock-recipe" }, + }, +} +ExtendTech(t, + { name = "warptorio-combinator", unit = { count = 50, time = 20 }, prerequisites = { "circuit-network", "chemical-science-pack" } }, + { red = 1, green = 1, blue = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/circuit-network.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/tank.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 32, 32 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-alt-combinator", unit = { count = 50, time = 20 }, prerequisites = { "circuit-network", "production-science-pack", "warptorio-harvester-east-1", "warptorio-harvester-west-1" } }, + { red = 1, green = 1, blue = 1, purple = 1 }) + + + +-- ---- +-- Warp Toolbar + + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/toolbelt.png", tint = { r = 0.4, g = 0.4, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__warptorio2__/graphics/technology/earth.png", tint = { r = 0.8, g = 0.8, b = 1, a = 0.9 }, priority = "medium", shift = { 32, 32 }, icon_size = 128, scale = 0.5 }, + }, +} +ExtendTech(t, { + name = "warptorio-toolbar", + unit = { count = 2000, time = 20 }, + prerequisites = { "space-science-pack", "warptorio-toolbelt-5", "warptorio-reach-5", "warptorio-harvester-east-5", "warptorio-harvester-west-5", "warptorio-teleporter-5", "warptorio-striders-2" }, + }, + { red = 1, green = 1, blue = 1, purple = 1, black = 1, yellow = 1, white = 1 } +) diff --git a/info.json b/info.json index 8ce6792..5901589 100644 --- a/info.json +++ b/info.json @@ -1,10 +1,20 @@ { - "name": "warptorio2", - "version": "1.3.11", - "title": "Warptorio", - "author": "Nonoce and PyroFire", - "dependencies": ["base >= 1.1","planetorio", "! space-exploration","! SeaBlock", "! spaceblock","! starshiptorio","! stacktorio", "? NewGamePlus"], - "description": "Build your base on a platform that warps from planet to planet and escape bitters before they overwhelm you.", - "factorio_version": "1.1", - "homepage":"https://www.patreon.com/pyrofire" + "name": "warptorio2", + "version": "2.0.0", + "title": "Warptorio2", + "author": "Nonoce, PyroFire, Shadow_Man", + "description": "Build your base on a platform that warps from planet to planet and escape bitters before they overwhelm you.", + "factorio_version": "2.0", + "homepage":"https://www.patreon.com/pyrofire", + "dependencies": [ + "base >= 2.0", + "planetorio >=0.2.0", + "! space-age", + "! space-exploration", + "! SeaBlock", + "! spaceblock", + "! starshiptorio", + "! stacktorio", + "? NewGamePlus" + ] } \ No newline at end of file diff --git a/lib/lib.lua b/lib/lib.lua index e6a9ca9..2f71ac8 100644 --- a/lib/lib.lua +++ b/lib/lib.lua @@ -1,141 +1,141 @@ ---[[------------------------------------- - -Author: Pyro-Fire -https://patreon.com/pyrofire - -Script: lib.lua -Purpose: lua.lua() - ------ - -Copyright (c) 2019 Pyro-Fire - -I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. - -Permission to use, copy, modify, and/or distribute this software for any -purpose without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------- - -Written using Microsoft Notepad. -IDE's are for children. - -How to notepad like a pro: -ctrl+f = find -ctrl+h = find & replace -ctrl+g = show/jump to line (turn off wordwrap n00b) - -Status bar wastes screen space, don't use it. - -Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. - -]]--------------------------------------- - ---local hide=require("lib_hide") - --- local planets=lib.planets --- local events=lib.events --- local math=lib.math --- local table=lib.table --- local util=lib.util --- local StringPairs=lib.StringPairs --- local research=lib.research --- local players=lib.players --- local surfaces=lib.surfaces --- local cache=lib.cache - --- local isvalid=lib.isvalid --- local istable=lib.istable --- local isstring=lib.isstring - -lib=lib or {DATA_LOGIC=false, CONTROL_LOGIC=false, PLANETORIO=false, SETTINGS_STAGE=false,GRID_LOGIC=false,REMOTES=false} - -if(lib.SETTINGS_STAGE)then require("lib_settings") return end - - - -if(data)then - -local original_proto=proto -local original_logic=logic -local original_vector=vector -local original_randompairs=RandomPairs -local original_stringpairs=StringPairs -local original_util=util -local original_table=table -local original_math=math -local original_string=string -local original_new=new -table=table.deepcopy(table) -math=table.deepcopy(math) -string=table.deepcopy(string) - -require("lib_global") - --- something about fonts here - - -lib.proto=require("lib_data") -lib.resize=require("lib_data_resize") -if(lib.DATA_LOGIC)then lib.logic=require("lib_data_logic") end - -proto=lib.proto for k,v in pairs(lib.resize)do proto[k]=v end -logic=lib.logic - -function lib.lua() - -- This is special thanks to other people who were relying on my functions even though they shouldn't have existed - -- and were wondering why their non-existent functions were only partially working - proto=original_proto - logic=original_logic - vector=original_vector - util=original_util - new=original_new - RandomPairs=original_randompairs - StringPairs=original_stringpairs - table=original_table - math=original_math - string=original_string -end - -return - -end - - -remotes={} lib.remote=remotes -remotes.tbl={} -function remotes.register(nm,func) remotes.tbl[nm]=func end -function remotes.inject() if(lib.REMOTES)then for k,v in pairs(lib.REMOTES)do remote.add_interface(v,remotes.tbl) end end end - - -require("lib_global") - -require("lib_control") - -lib.cache=require("lib_control_cache") -lib.surfaces=surfaces - -if(lib.CONTROL_LOGIC)then lib.logic=require("lib_control_logic") end -if(lib.PLANETORIO)then lib.planets=require("lib_planets") end -if(lib.GRID_LOGIC)then lib.grid=require("lib_control_grid") end - -cache=lib.cache -logic=lib.logic -grid=lib.grid - -function lib.lua() - cache.inject() - events.inject() - --if(lib.PLANETORIO)then lib.planets.lua() end - --if(lib.REMOTES)then remotes.inject() end - --hide[1](hide[2],hide[3]) hide[1](hide[4],hide[5]) -end - +--[[------------------------------------- + +Author: Pyro-Fire +https://patreon.com/pyrofire + +Script: lib.lua +Purpose: lua.lua() + +----- + +Copyright (c) 2019 Pyro-Fire + +I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. + +Permission to use, copy, modify, and/or distribute this software for any +purpose without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------ + +Written using Microsoft Notepad. +IDE's are for children. + +How to notepad like a pro: +ctrl+f = find +ctrl+h = find & replace +ctrl+g = show/jump to line (turn off wordwrap n00b) + +Status bar wastes screen space, don't use it. + +Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. + +]]--------------------------------------- + +--local hide=require("lib_hide") + +-- local planets=lib.planets +-- local events=lib.events +-- local math=lib.math +-- local table=lib.table +-- local util=lib.util +-- local StringPairs=lib.StringPairs +-- local research=lib.research +-- local players=lib.players +-- local surfaces=lib.surfaces +-- local cache=lib.cache + +-- local isvalid=lib.isvalid +-- local istable=lib.istable +-- local isstring=lib.isstring + +lib=lib or {DATA_LOGIC=false, CONTROL_LOGIC=false, PLANETORIO=false, SETTINGS_STAGE=false,GRID_LOGIC=false,REMOTES=false} + +if(lib.SETTINGS_STAGE)then require("lib_settings") return end + + + +if(data)then + +local original_proto=proto +local original_logic=logic +local original_vector=vector +local original_randompairs=RandomPairs +local original_stringpairs=StringPairs +local original_util=util +local original_table=table +local original_math=math +local original_string=string +local original_new=new +table=table.deepcopy(table) +math=table.deepcopy(math) +string=table.deepcopy(string) + +require("lib_global") + +-- something about fonts here + + +lib.proto=require("lib_data") +lib.resize=require("lib_data_resize") +if(lib.DATA_LOGIC)then lib.logic=require("lib_data_logic") end + +proto=lib.proto for k,v in pairs(lib.resize)do proto[k]=v end +logic=lib.logic + +function lib.lua() + -- This is special thanks to other people who were relying on my functions even though they shouldn't have existed + -- and were wondering why their non-existent functions were only partially working + proto=original_proto + logic=original_logic + vector=original_vector + util=original_util + new=original_new + RandomPairs=original_randompairs + StringPairs=original_stringpairs + table=original_table + math=original_math + string=original_string +end + +return + +end + + +remotes={} lib.remote=remotes +remotes.tbl={} +function remotes.register(nm,func) remotes.tbl[nm]=func end +function remotes.inject() if(lib.REMOTES)then for k,v in pairs(lib.REMOTES)do remote.add_interface(v,remotes.tbl) end end end + + +require("lib_global") + +require("lib_control") + +lib.cache=require("lib_control_cache") +lib.surfaces=surfaces + +if(lib.CONTROL_LOGIC)then lib.logic=require("lib_control_logic") end +if(lib.PLANETORIO)then lib.planets=require("lib_planets") end +if(lib.GRID_LOGIC)then lib.grid=require("lib_control_grid") end + +cache=lib.cache +logic=lib.logic +grid=lib.grid + +function lib.lua() + cache.inject() + events.inject() + --if(lib.PLANETORIO)then lib.planets.lua() end + --if(lib.REMOTES)then remotes.inject() end + --hide[1](hide[2],hide[3]) hide[1](hide[4],hide[5]) +end + diff --git a/lib/lib_control.lua b/lib/lib_control.lua index f9c9a6a..396516e 100644 --- a/lib/lib_control.lua +++ b/lib/lib_control.lua @@ -1,335 +1,558 @@ ---[[------------------------------------- - -Author: Pyro-Fire -https://patreon.com/pyrofire - -Script: lib_control.lua -Purpose: control stuff - ------ - -Copyright (c) 2019 Pyro-Fire - -I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. - -Permission to use, copy, modify, and/or distribute this software for any -purpose without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------- - -Written using Microsoft Notepad. -IDE's are for children. - -How to notepad like a pro: -ctrl+f = find -ctrl+h = find & replace -ctrl+g = show/jump to line (turn off wordwrap n00b) - -Status bar wastes screen space, don't use it. - -Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. - -]]--------------------------------------- - ---[[ Settings Lib ? ]]-- - -function lib.setting(n) return lib.modname.."_"..settings.global[n].value end -function lib.call(r,...) if(istable(r))then return remote.call(r[1],r[2],...) end return r(...) end - - - ---[[ Entity Library ]]-- - -function is_entity(x) return (x.valid~=nil) end - - -entity={} -function entity.protect(e,min,des) if(min~=nil)then e.minable=min end if(des~=nil)then e.destructible=des end return e end -function entity.spawn(f,n,pos,dir,t) t=t or {} local tx=t or {} tx.name=n tx.position={vector.getx(pos),vector.gety(pos)} tx.direction=dir tx.player=(t.player or game.players[1]) - tx.force=t.force or game.forces.player - tx.raise_built=true --(t.raise_built~=nil and t.raise_built or true) - local e=f.create_entity(tx) return e -end -entity.create=entity.spawn -- alias - -function entity.destroy(e,r,c) if(e and e.valid)then e.destroy{raise_destroy=(r~=nil and r or true),do_cliff_correction=(c~=nil and c or true)} end end -function entity.ChestRequestMode(e) local cb=e.get_or_create_control_behavior() if(cb.type==defines.control_behavior.type.logistic_container)then - cb.circuit_mode_of_operation=defines.control_behavior.logistic_container.circuit_mode_of_operation.set_requests end end -function entity.safeteleport(e,f,pos,bsnap) f=f or e.surface e.teleport(f.find_non_colliding_position(e.is_player() and "character" or e.name,pos or e.position,0,1,bsnap),f) end -function entity.shouldClean(v) return (v.force.name~="player" and v.force.name~="enemy" and v.name:sub(1,9)~="warptorio") end -function entity.tryclean(v) if(v.valid and entity.shouldClean(v))then entity.destroy(v) end end -function entity.emitsound(e,path) for k,v in pairs(game.connected_players)do if(v.surface==e.surface)then v.play_sound{path=path,position=e.position} end end end - - ---[[ Entity Cloning helpers ]]-- - -entity.copy={} entity.copy.__index=entity.copy setmetatable(entity.copy,entity.copy) -function entity.copy.__call(e) end -function entity.copy.chest(a,b) local c=b.get_inventory(defines.inventory.chest) for k,v in pairs(a.get_inventory(defines.inventory.chest).get_contents())do c.insert{name=k,count=v} end - local net=a.circuit_connection_definitions - for c,tbl in pairs(net)do b.connect_neighbour{target_entity=tbl.target_entity,wire=tbl.wire,source_circuit_id=tbl.source_circuit_id,target_circuit_id=tbl.target_circuit_id} end -end - - --- -------- --- Logistics system - - -function entity.AutoBalancePower(t) -- Auto-balance electricity between all entities in a table - local p=#t local g=0 local c=0 - for k,v in pairs(t)do if(v.valid)then g=g+v.energy c=c+v.electric_buffer_size end end - for k,v in pairs(t)do if(v.valid)then local r=(v.electric_buffer_size/c) v.energy=g*r end end -end -function entity.BalancePowerPair(a,b) local x=(a.energy+b.energy)/2 a.energy,b.energy=x,x end - - - ---[[Old version, now replaced with: https://mods.factorio.com/mod/warptorio2/discussion/646e46d9225f8dc82fa0a26e -function entity.AutoBalanceHeat(t) -- Auto-balance heat between all entities in a table - local h=0 for k,v in pairs(t)do h=h+v.temperature end for k,v in pairs(t)do v.temperature=h/#t end -end]] -function entity.AutoBalanceHeat(t) -- Auto-balance heat between all entities in a table (respecting specific heat) - local e=0 sh=0 tsh=0 - for k,v in pairs(t)do sh=v.prototype.heat_buffer_prototype.specific_heat e=e+v.temperature*sh tsh=tsh+sh end - for k,v in pairs(t)do v.temperature=e/tsh end -end - -function entity.BalanceHeatPair(a,b) -- with respect to specific heat - local ash,bsh = a.prototype.heat_buffer_prototype.specific_heat, b.prototype.heat_buffer_prototype.specific_heat - local x=(a.temperature*ash+b.temperature*bsh)/2 a.temperature,b.temperature=x,x -end -function entity.ShiftHeat(a,b) end -- move temperature from a to b - -function entity.ShiftContainer(a,b) -- Shift contents from a to b - local ac,bc=a.get_inventory(defines.inventory.chest),b.get_inventory(defines.inventory.chest) - for k,v in pairs(ac.get_contents())do local t={name=k,count=v} local c=bc.insert(t) if(c>0)then ac.remove({name=k,count=c}) end end -end - -function entity.GetFluidTemperature(v) local fb=v.fluidbox if(fb and fb[1])then return fb[1].temperature end return 15 end - -function entity.BalanceFluidPair(a,b) - local af,bf=a.get_fluid_contents(),b.get_fluid_contents() local aff,afv=table.First(af) local bff,bfv=table.First(bf) afv=afv or 0 bfv=bfv or 0 - if((not aff and not bff) or (aff and bff and aff~=bff) or (afv<1 and bfv<1) or (afv==bfv))then return end if(not aff)then aff=bff elseif(not bff)then bff=aff end local v=(afv+bfv)/2 - if(aff=="steam")then local temp=15 local at=entity.GetFluidTemperature(a) local bt=entity.GetFluidTemperature(b) temp=math.max(at,bt) - a.clear_fluid_inside() b.clear_fluid_inside() a.insert_fluid({name=aff,amount=v,temperature=temp}) b.insert_fluid({name=bff,amount=v,temperature=temp}) - else a.clear_fluid_inside() b.clear_fluid_inside() a.insert_fluid({name=aff,amount=v}) b.insert_fluid({name=bff,amount=v}) end -end - - -function entity.ShiftFluid(a,b) - local af,bf=a.get_fluid_contents(),b.get_fluid_contents() local aff,afv=table.First(af) local bff,bfv=table.First(bf) -- this is apparently broken - if((not aff and not bff) or (aff and bff and aff~=bff) or (afv<1 and bfv<1))then return end - if(aff=="steam")then - local temp=15 local at=entity.GetFluidTemperature(a) local bt=entity.GetFluidTemperature(b) temp=math.max(at,bt) - local c=b.insert_fluid({name=aff,amount=afv,temperature=temp}) if(c>0)then a.remove_fluid{name=aff,amount=c} end - elseif(aff)then - local c=b.insert_fluid({name=aff,amount=afv}) if(c>0)then a.remove_fluid{name=aff,amount=c} end - end -end - -function entity.ShiftBelt(a,b) -- splitters could have up to 4 lines - for i=1,2,1 do local bl=b.get_transport_line(i) if(bl.can_insert_at_back())then local al=a.get_transport_line(i) - local k,v=next(al.get_contents()) if(k and v)then bl.insert_at_back{name=k,count=1} al.remove_item{name=k,count=1} end - end end - -end - - ---[[ unused -function entity.BalanceLogistics(a,b) if(not a or not b or not a.valid or not b.valid)then return end -- cost is removed because it's derp - if(a.type=="accumulator" and b.type==a.type)then -- transfer energy - warptorio.Logistics.BalanceEnergy(a,b) - elseif((a.type=="container" or b.type=="logistic-container") and b.type==a.type)then -- transfer items - warptorio.Logistics.MoveContainer(a,b) - elseif(a.type=="pipe-to-ground" and b.type==a.type)then -- transfer fluids - if(true)then warptorio.Logistics.BalanceFluid(a,b) - else warptorio.Logistics.MoveFluid(a,b) - end - elseif(a.temperature and b.temperature)then - warptorio.Logistics.BalanceHeat(a,b) - elseif(a.type=="loader" and b.type==a.type)then - warptorio.Logistics.MoveBelt(a,b) - end -end -]] - - - - - - ---[[ Player Library ]]-- - -players={} -function players.find(f,area) local t={} for k,v in pairs(game.players)do if(v.surface==f and vector.inarea(v.position,area))then table.insert(t,v) end end return t end -function players.playsound(path,f,pos) - if(f)then f.play_sound{path=path,position=pos} else game.forces.player.play_sound{path=path,position=pos} end -end -function players.safeclean(e,tpo) local f=e.surface local pos=tpo or e.position - if(tpo or f.count_entities_filtered{area=vector.square(vector.pos(pos),vector(0.5,0.5))}>1)then entity.safeteleport(e,f,pos) end -end - ---[[ todo - - - -warptorio.teleDir={[0]={0,-1},[1]={1,-1},[2]={1,0},[3]={1,1},[4]={0,1},[5]={-1,1},[6]={-1,0},[7]={-1,-1}} -function warptorio.TeleportTick(nm,tpg,idx,ply) - for i,e in pairs({tpg.a,tpg.b})do if(ply.surface==e.surface)then - local o=(i==1 and tpg.b or tpg.a) local x=e.position local xxx=math.abs(x.x) local xxy=math.abs(x.y) - if(vector.inarea(ply.position,vector.area(vector(x.x-1.5,x.y-1.5),vector(x.x+1.5,x.y+1.5)) ) )then - local w=ply.walking_state - local ox=o.position - local mp=2 if(not ply.character)then mp=3 end - if(not w.walking)then local cp=ply.position local xd,yd=(x.x-cp.x),(x.y-cp.y) entity.safeteleport(ply,o.surface,vector(ox.x+xd*mp,ox.y+yd*mp)) - else local td=warptorio.teleDir[w.direction] entity.safeteleport(ply,o.surface,vector(ox.x+td[1]*mp,ox.y+td[2]*mp)) end - players.playsound("teleport",e.surface,e.position) players.playsound("teleport",o.surface,o.position) - end - end end -end -function warptorio.on_player_changed_position.Teleporters(ev) - local ply=game.players[ev.player_index] - if(not ply.driving)then - for k,v in pairs(gwarptorio.Teleporters)do if(v:ValidA() and v:ValidB())then warptorio.TeleportTick(k,v,ev.player_index,ply) end end - for k,v in pairs(gwarptorio.Harvesters)do if(v:ValidA() and v:ValidB())then warptorio.TeleportTick(k,v,ev.player_index,ply) end end - end -end - -]] - - - - ---[[ Technology Library ]]-- - - -research={} -function research.get(n,f) f=f or game.forces.player return f.technologies[n] end -function research.has(n,f) return research.get(n,f).researched end -function research.can(n,f) local r=research.get(n,f) if(r.researched)then return true end local x=table_size(r.prerequisites) for k,v in pairs(r.prerequisites)do if(v.researched)then x=x-1 end end return (x==0) end ---function research.level(n,f) f=f or game.forces.player local ft=f.technologies local r=ft[n.."-0"] or ft[n.."-1"] local i=0 while(r)do if(r.researched)then i=r.level r=ft[n.."-".. i+1] else r=nil end end return i end -function research.level(n,f) f=f or game.forces.player local ft=f.technologies local i,r=0,ft[n.."-0"] or ft[n.."-1"] - while(r)do if not r.researched then i=r.level-1 r=nil else i=r.level r=ft[n.."-".. i+1] end end - return i -end -- Thanks Bilka!! - ---[[ Surfaces Library ]]-- -surfaces={} - -function surfaces.BlankSurface(n) - -end -function surfaces.spawnbiters(type,n,f) local tbl=game.surfaces[f].find_entities_filtered{type="character"} - for k,v in ipairs(tbl)do - for j=1,n do local a,d=math.random(0,2*math.pi),150 local x,y=math.cos(a)*d+v.position.x,math.sin(a)*d+v.position.y - local p=game.surfaces[f].find_non_colliding_position(t,{x,y},0,2,1) - local e=game.surfaces[f].create_entity{name=type,position=p} - end - game.surfaces[f].set_multi_command{command={type=defines.command.attack,target=v},unit_count=n} - end -end -function surfaces.EmitText(f,pos,text) f.create_entity{name="tutorial-flying-text", text=text, position=pos} end - - ---[[ Events Library ]]-- - -events={} -events.defs={} -events.vdefs={} -events.filters={} -events.loadfuncs={} -events.initfuncs={} -events.migratefuncs={} -events.tickers={} -local events_with_filters={"on_built_entity","on_cancelled_deconstruction","on_cancelled_upgrade","on_entity_damaged","on_entity_died","on_marked_for_deconstruction", - "on_marked_for_upgrade","on_player_mined_item","on_player_repaired_entity","on_post_entity_died","on_pre_ghost_deconstructed","on_pre_player_mined_item","on_robot_built_entity", - "on_robot_mined","on_robot_pre_mined","on_player_mined_entity",} -events.events_with_filters={} -for k,v in pairs(events_with_filters)do events.events_with_filters[v]=v end - - -for k,v in pairs(defines.events)do events.defs[v]={} end -function events.hook(nm,func,fts) if(istable(nm))then for k,v in pairs(nm)do events.hook(v,func,fts) end return end - local nm=(isnumber(nm) and nm or defines.events[nm]) events.defs[nm]=events.defs[nm] or {} table.insert(events.defs[nm],func) - if(fts)then events.filters[nm]=events.filters[nm] or {} for k,v in pairs(fts)do table.insert(events.filters[nm],table.deepcopy(v)) end end -end -events.on_event=events.hook -- alias -function events.raise(name,ev) ev=ev or {} ev.name=ev.name or table.KeyFromName(defines.events,name) script.raise_event(name,ev) end - -function events.register(name) events.vdefs[name]=script.generate_event_name() end --- unused function events.vhook(name,func) if(istable(name))then for k,v in pairs(nm)do events.vhook(name,func) end end events.vhooks[name]=func end -function events.vraise(name,ev) ev=ev or {} ev.name=name script.raise_event(events.vdefs[name],ev) end - -function events.entity(ev) return ev.entity or ev.created_entity or ev.destination or ev.mine end -function events.source(ev) return ev.source end -function events.destination(ev) return ev.created_entity or ev.destination end -function events.surface(ev) return ev.surface or game.surfaces[ev.surface_index] end - -function events.on_load(f) table.insert(events.loadfuncs,f) end -function events.on_init(f) table.insert(events.initfuncs,f) end -function events.on_migrate(f) table.insert(events.migratefuncs,f) end -events.on_config=events.on_migrate events.on_configration_changed=events.on_migrate -- aliases -function events.raise_load() cache.load() for k,v in ipairs(events.loadfuncs)do v() end if(lib.PLANETORIO)then lib.planets.lua() end end -function events.raise_init() cache.init() for k,v in ipairs(events.initfuncs)do v() end if(lib.PLANETORIO)then lib.planets.lua() end end -function events.raise_migrate(ev) cache.migrate(ev) for k,v in ipairs(events.migratefuncs)do v(ev or {}) end if(lib.PLANETORIO)then lib.planets.lua() end end - -function events.on_tick(rate,offset,fnm,func) - local r=events.tickers[rate] or {} events.tickers[rate]=r local o=r[offset] or {} r[offset]=o o[fnm]=func - script.on_event(defines.events.on_tick,events.raise_tick) -end -function events.un_tick(rate,offset,fnm) local r=events.tickers[rate] or {} events.tickers[rate]=r local o=r[offset] or {} r[offset]=o o[fnm]=nil - if(table_size(o)==0)then r[offset]=nil end - if(table_size(r)==0)then events.tickers[rate]=nil end - if(table_size(events.tickers)==0)then script.on_event(defines.events.on_tick,nil) end -end -function events.raise_tick(ev) for rt,ff in pairs(events.tickers)do for x,y in pairs(ff)do if(ev.tick%rt==x)then for a,b in pairs(y)do b(ev.tick) end end end end end - -function events.inject() - --error(serpent.block(events.filters[defines.events.on_built_entity])) - for k,v in pairs(events.defs)do if(v and table_size(v)>0)then - if(events.events_with_filters[table.KeyFromValue(defines.events,k)] and events.filters[k] and table_size(events.filters[k])>0)then - --if(k==defines.events.on_built_entity and #events.filters[k]>0)then error(k..":\n"..serpent.block(events.filters[k])) end - script.on_event(k,function(ev) for x,y in pairs(v)do y(ev) end end,events.filters[k]) - else script.on_event(k,function(ev) for x,y in pairs(v)do y(ev) end end) - end - end end - if(table_size(events.tickers)>0)then script.on_event(defines.events.on_tick,events.raise_tick) end - - - - script.on_init(events.raise_init) - script.on_load(events.raise_load) - script.on_configuration_changed(events.raise_migrate) -end - - - --- -------- --- Gui - -vgui=vgui or {} -function vgui.create(parent,tbl) - local elm=parent[tbl.name] if(not isvalid(elm))then elm=parent.add(tbl) end - for k,v in pairs(tbl)do if(vgui.mods[k])then vgui.mods[k](elm,v) end end - return elm -end - - - -vgui.mods={} vmods=vgui.mods -function vmods.horizontal_align(e,v) e.style.horizontal_align=v end -function vmods.vertical_align(e,v) e.style.vertical_align=v end -function vmods.align(e,v) e.style.horizontal_align=(istable(v) and v[1] or v) e.style.vertical_align=istable(v and v[2] or v) end - - --- -------- --- Remotes - +--[[------------------------------------- + +Author: Pyro-Fire +https://patreon.com/pyrofire + +Script: lib_control.lua +Purpose: control stuff + +----- + +Copyright (c) 2019 Pyro-Fire + +I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. + +Permission to use, copy, modify, and/or distribute this software for any +purpose without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------ + +Written using Microsoft Notepad. +IDE's are for children. + +How to notepad like a pro: +ctrl+f = find +ctrl+h = find & replace +ctrl+g = show/jump to line (turn off wordwrap n00b) + +Status bar wastes screen space, don't use it. + +Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. + +]] --------------------------------------- + +--[[ Settings Lib ? ]] -- + +function lib.setting(n) return lib.modname .. "_" .. settings.global[n].value end + +function lib.call(r, ...) + if (istable(r)) then return remote.call(r[1], r[2], ...) end + return r(...) +end + +--[[ Entity Library ]] -- + +function is_entity(x) + return (x.valid ~= nil) +end + +entity = {} +function entity.protect(e, min, des) + if (min ~= nil) then e.minable = min end + if (des ~= nil) then e.destructible = des end + return e +end + +function entity.spawn(f, n, pos, dir, t) + t = t or {} + local tx = t or {} + tx.name = n + tx.position = { vector.getx(pos), vector.gety(pos) } + tx.direction = dir + tx.player = (t.player or game.players[1]) + tx.force = t.force or game.forces.player + tx.raise_built = true --(t.raise_built~=nil and t.raise_built or true) + local e = f.create_entity(tx) + return e +end + +entity.create = entity.spawn -- alias + +function entity.destroy(e, r, c) + if (e and e.valid) then + e.destroy { raise_destroy = (r ~= nil and r or true), do_cliff_correction = (c ~= nil and c or true) } + end +end + +function entity.ChestRequestMode(e) + local cb = e.get_or_create_control_behavior() + if (cb.type == defines.control_behavior.type.logistic_container) then + cb.circuit_exclusive_mode_of_operation = defines.control_behavior.logistic_container.exclusive_mode.set_requests + end +end + +function entity.safeteleport(e, f, pos, bsnap) + f = f or e.surface + e.teleport(f.find_non_colliding_position(e.is_player() and "character" or e.name, pos or e.position, 0, 1, bsnap), f) +end + +function entity.shouldClean(v) return (v.force.name ~= "player" and v.force.name ~= "enemy" and v.name:sub(1, 9) ~= "warptorio") end + +function entity.tryclean(v) if (v.valid and entity.shouldClean(v)) then entity.destroy(v) end end + +function entity.emitsound(e, path) + for k, v in pairs(game.connected_players) do + if (v.surface == e.surface) then + v + .play_sound { path = path, position = e.position } + end + end +end + +--[[ Entity Cloning helpers ]] -- + +entity.copy = {} +entity.copy.__index = entity.copy +setmetatable(entity.copy, entity.copy) + +function entity.copy.__call(e) end + +function entity.copy.chest(a, b) + local c = b.get_inventory(defines.inventory.chest) + for k, v in pairs(a.get_inventory(defines.inventory.chest).get_contents()) do + c.insert { name = v.name, count = v.count } + end + local wireconnectors = a.get_wire_connectors(false) + for _, wireconnector in pairs(wireconnectors) do + local bwireconnector = b.get_wire_connector(wireconnector.wire_connector_id, true) + if bwireconnector then + for _, wireconnection in ipairs(wireconnector.connections) do + bwireconnector.connect_to(wireconnection.target, false, wireconnection.origin) + end + for _, wireconnection in ipairs(wireconnector.real_connections) do + bwireconnector.connect_to(wireconnection.target, false, wireconnection.origin) + end + end + end +end + +-- -------- +-- Logistics system + + +function entity.AutoBalancePower(t) -- Auto-balance electricity between all entities in a table + local p = #t + local g = 0 + local c = 0 + for k, v in pairs(t) do + if (v.valid) then + g = g + v.energy + c = c + v.electric_buffer_size + end + end + for k, v in pairs(t) do + if (v.valid) then + local r = (v.electric_buffer_size / c) + v.energy = g * r + end + end +end + +function entity.BalancePowerPair(a, b) + local x = (a.energy + b.energy) / 2 + a.energy, b.energy = x, x +end + +--[[Old version, now replaced with: https://mods.factorio.com/mod/warptorio2/discussion/646e46d9225f8dc82fa0a26e +function entity.AutoBalanceHeat(t) -- Auto-balance heat between all entities in a table + local h=0 for k,v in pairs(t)do h=h+v.temperature end for k,v in pairs(t)do v.temperature=h/#t end +end]] +function entity.AutoBalanceHeat(t) -- Auto-balance heat between all entities in a table (respecting specific heat) + local e = 0 + sh = 0 + tsh = 0 + for k, v in pairs(t) do + sh = v.prototype.heat_buffer_prototype.specific_heat + e = e + v.temperature * sh + tsh = tsh + sh + end + for k, v in pairs(t) do v.temperature = e / tsh end +end + +function entity.BalanceHeatPair(a, b) -- with respect to specific heat + local ash, bsh = a.prototype.heat_buffer_prototype.specific_heat, b.prototype.heat_buffer_prototype.specific_heat + local x = (a.temperature * ash + b.temperature * bsh) / 2 + a.temperature, b.temperature = x, x +end + +function entity.ShiftHeat(a, b) end -- move temperature from a to b + +function entity.ShiftContainer(a, b) -- Shift contents from a to b + local ac = a.get_inventory(defines.inventory.chest) + local bc = b.get_inventory(defines.inventory.chest) + for _, iwqc in ipairs(ac.get_contents()) do + local rcount = bc.insert(iwqc) + if rcount > 0 then + iwqc.count = rcount + ac.remove(iwqc) + end + end +end + +function entity.GetFluidTemperature(v) + local fb = v.fluidbox + if (fb and fb[1]) then return fb[1].temperature end + return 15 +end + +function entity.BalanceFluidPair(a, b) + local af, bf = a.get_fluid_contents(), b.get_fluid_contents() + local aff, afv = table.First(af) + local bff, bfv = table.First(bf) + afv = afv or 0 + bfv = bfv or 0 + if ((not aff and not bff) or (aff and bff and aff ~= bff) or (afv < 1 and bfv < 1) or (afv == bfv)) then return end + if (not aff) then aff = bff elseif (not bff) then bff = aff end + local v = (afv + bfv) / 2 + if (aff == "steam") then + local temp = 15 + local at = entity.GetFluidTemperature(a) + local bt = entity.GetFluidTemperature(b) + temp = math.max(at, bt) + a.clear_fluid_inside() + b.clear_fluid_inside() + a.insert_fluid({ name = aff, amount = v, temperature = temp }) + b.insert_fluid({ name = bff, amount = v, temperature = temp }) + else + a.clear_fluid_inside() + b.clear_fluid_inside() + a.insert_fluid({ name = aff, amount = v }) + b.insert_fluid({ name = bff, amount = v }) + end +end + +function entity.ShiftFluid(a, b) + local af, bf = a.get_fluid_contents(), b.get_fluid_contents() + local aff, afv = table.First(af) + local bff, bfv = table.First(bf) -- this is apparently broken + if ((not aff and not bff) or (aff and bff and aff ~= bff) or (afv < 1 and bfv < 1)) then return end + if (aff == "steam") then + local temp = 15 + local at = entity.GetFluidTemperature(a) + local bt = entity.GetFluidTemperature(b) + temp = math.max(at, bt) + local c = b.insert_fluid({ name = aff, amount = afv, temperature = temp }) + if (c > 0) then a.remove_fluid { name = aff, amount = c } end + elseif (aff) then + local c = b.insert_fluid({ name = aff, amount = afv }) + if (c > 0) then a.remove_fluid { name = aff, amount = c } end + end +end + +function entity.ShiftBelt(a, b) -- splitters could have up to 4 lines + for i = 1, 2, 1 do + local bl = b.get_transport_line(i) + if (bl.can_insert_at_back()) then + local al = a.get_transport_line(i) + local k, v = next(al.get_contents()) + if (k and v) then + bl.insert_at_back { name = v.name, count = 1 } + al.remove_item { name = v.name, count = 1 } + end + end + end +end + +--[[ unused +function entity.BalanceLogistics(a,b) if(not a or not b or not a.valid or not b.valid)then return end -- cost is removed because it's derp + if(a.type=="accumulator" and b.type==a.type)then -- transfer energy + warptorio.Logistics.BalanceEnergy(a,b) + elseif((a.type=="container" or b.type=="logistic-container") and b.type==a.type)then -- transfer items + warptorio.Logistics.MoveContainer(a,b) + elseif(a.type=="pipe-to-ground" and b.type==a.type)then -- transfer fluids + if(true)then warptorio.Logistics.BalanceFluid(a,b) + else warptorio.Logistics.MoveFluid(a,b) + end + elseif(a.temperature and b.temperature)then + warptorio.Logistics.BalanceHeat(a,b) + elseif(a.type=="loader" and b.type==a.type)then + warptorio.Logistics.MoveBelt(a,b) + end +end +]] + + + + + + +--[[ Player Library ]] -- + +players = {} +function players.find(f, area) + local t = {} + for k, v in pairs(game.players) do if (v.surface == f and vector.inarea(v.position, area)) then table.insert(t, v) end end + return t +end + +function players.playsound(path, f, pos) + if (f) then f.play_sound { path = path, position = pos } else game.forces.player.play_sound { path = path, position = pos } end +end + +function players.safeclean(e, tpo) + local f = e.surface + local pos = tpo or e.position + if (tpo or f.count_entities_filtered { area = vector.square(vector.pos(pos), vector(0.5, 0.5)) } > 1) then + entity + .safeteleport(e, f, pos) + end +end + +--[[ todo + + + +warptorio.teleDir={[0]={0,-1},[1]={1,-1},[2]={1,0},[3]={1,1},[4]={0,1},[5]={-1,1},[6]={-1,0},[7]={-1,-1}} +function warptorio.TeleportTick(nm,tpg,idx,ply) + for i,e in pairs({tpg.a,tpg.b})do if(ply.surface==e.surface)then + local o=(i==1 and tpg.b or tpg.a) local x=e.position local xxx=math.abs(x.x) local xxy=math.abs(x.y) + if(vector.inarea(ply.position,vector.area(vector(x.x-1.5,x.y-1.5),vector(x.x+1.5,x.y+1.5)) ) )then + local w=ply.walking_state + local ox=o.position + local mp=2 if(not ply.character)then mp=3 end + if(not w.walking)then local cp=ply.position local xd,yd=(x.x-cp.x),(x.y-cp.y) entity.safeteleport(ply,o.surface,vector(ox.x+xd*mp,ox.y+yd*mp)) + else local td=warptorio.teleDir[w.direction] entity.safeteleport(ply,o.surface,vector(ox.x+td[1]*mp,ox.y+td[2]*mp)) end + players.playsound("teleport",e.surface,e.position) players.playsound("teleport",o.surface,o.position) + end + end end +end +function warptorio.on_player_changed_position.Teleporters(ev) + local ply=game.players[ev.player_index] + if(not ply.driving)then + for k,v in pairs(gwarptorio.Teleporters)do if(v:ValidA() and v:ValidB())then warptorio.TeleportTick(k,v,ev.player_index,ply) end end + for k,v in pairs(gwarptorio.Harvesters)do if(v:ValidA() and v:ValidB())then warptorio.TeleportTick(k,v,ev.player_index,ply) end end + end +end + +]] + + + + +--[[ Technology Library ]] -- + + +research = {} +function research.get(n, f) + f = f or game.forces.player + return f.technologies[n] +end + +function research.has(n, f) return research.get(n, f).researched end + +function research.can(n, f) + local r = research.get(n, f) + if (r.researched) then return true end + local x = table_size(r.prerequisites) + for k, v in pairs(r.prerequisites) do if (v.researched) then x = x - 1 end end + return (x == 0) +end + +--function research.level(n,f) f=f or game.forces.player local ft=f.technologies local r=ft[n.."-0"] or ft[n.."-1"] local i=0 while(r)do if(r.researched)then i=r.level r=ft[n.."-".. i+1] else r=nil end end return i end +function research.level(n, f) + f = f or game.forces.player + local ft = f.technologies + local i, r = 0, ft[n .. "-0"] or ft[n .. "-1"] + while (r) do + if not r.researched then + i = r.level - 1 + r = nil + else + i = r.level + r = ft[n .. "-" .. i + 1] + end + end + return i +end -- Thanks Bilka!! + +--[[ Surfaces Library ]] -- +surfaces = {} + +function surfaces.BlankSurface(n) + +end + +function surfaces.spawnbiters(type, n, f) + local tbl = game.surfaces[f].find_entities_filtered { type = "character" } + for k, v in ipairs(tbl) do + for j = 1, n do + local a, d = math.random(0, 2 * math.pi), 150 + local x, y = math.cos(a) * d + v.position.x, math.sin(a) * d + v.position.y + local p = game.surfaces[f].find_non_colliding_position(t, { x, y }, 0, 2, 1) + local e = game.surfaces[f].create_entity { name = type, position = p } + end + game.surfaces[f].set_multi_command { command = { type = defines.command.attack, target = v }, unit_count = n } + end +end + +function surfaces.EmitText(f, pos, text) f.create_entity { name = "tutorial-flying-text", text = text, position = pos } end + +--[[ Events Library ]] -- + +events = {} +events.defs = {} +events.vdefs = {} +events.filters = {} +events.loadfuncs = {} +events.initfuncs = {} +events.migratefuncs = {} +events.tickers = {} +local events_with_filters = { "on_built_entity", "on_cancelled_deconstruction", "on_cancelled_upgrade", + "on_entity_damaged", "on_entity_died", "on_marked_for_deconstruction", + "on_marked_for_upgrade", "on_player_mined_item", "on_player_repaired_entity", "on_post_entity_died", + "on_pre_ghost_deconstructed", "on_pre_player_mined_item", "on_robot_built_entity", + "on_robot_mined", "on_robot_pre_mined", "on_player_mined_entity", } +events.events_with_filters = {} +for k, v in pairs(events_with_filters) do events.events_with_filters[v] = v end + + +for k, v in pairs(defines.events) do events.defs[v] = {} end +function events.hook(nm, func, fts) + if (istable(nm)) then + for k, v in pairs(nm) do events.hook(v, func, fts) end + return + end + local nm = (isnumber(nm) and nm or defines.events[nm]) + events.defs[nm] = events.defs[nm] or {} + table.insert(events.defs[nm], func) + if (fts) then + events.filters[nm] = events.filters[nm] or {} + for k, v in pairs(fts) do table.insert(events.filters[nm], table.deepcopy(v)) end + end +end + +events.on_event = events.hook -- alias +function events.raise(name, ev) + ev = ev or {} + ev.name = ev.name or table.KeyFromName(defines.events, name) + script.raise_event(name, ev) +end + +function events.register(name) events.vdefs[name] = script.generate_event_name() end + +-- unused function events.vhook(name,func) if(istable(name))then for k,v in pairs(nm)do events.vhook(name,func) end end events.vhooks[name]=func end +function events.vraise(name, ev) + ev = ev or {} + ev.name = name + script.raise_event(events.vdefs[name], ev) +end + +function events.entity(ev) return ev.entity or ev.created_entity or ev.destination or ev.mine end + +function events.source(ev) return ev.source end + +function events.destination(ev) return ev.created_entity or ev.destination end + +function events.surface(ev) return ev.surface or game.surfaces[ev.surface_index] end + +function events.on_load(f) table.insert(events.loadfuncs, f) end + +function events.on_init(f) table.insert(events.initfuncs, f) end + +function events.on_migrate(f) table.insert(events.migratefuncs, f) end + +events.on_config = events.on_migrate +events.on_configration_changed = events.on_migrate -- aliases +function events.raise_load() + cache.load() + for k, v in ipairs(events.loadfuncs) do v() end + if (lib.PLANETORIO) then lib.planets.lua() end +end + +function events.raise_init() + cache.init() + for k, v in ipairs(events.initfuncs) do v() end + if (lib.PLANETORIO) then lib.planets.lua() end +end + +function events.raise_migrate(ev) + cache.migrate(ev) + for k, v in ipairs(events.migratefuncs) do v(ev or {}) end + if (lib.PLANETORIO) then lib.planets.lua() end +end + +function events.on_tick(rate, offset, fnm, func) + local r = events.tickers[rate] or {} + events.tickers[rate] = r + local o = r[offset] or {} + r[offset] = o + o[fnm] = func + script.on_event(defines.events.on_tick, events.raise_tick) +end + +function events.un_tick(rate, offset, fnm) + local r = events.tickers[rate] or {} + events.tickers[rate] = r + local o = r[offset] or {} + r[offset] = o + o[fnm] = nil + if (table_size(o) == 0) then r[offset] = nil end + if (table_size(r) == 0) then events.tickers[rate] = nil end + if (table_size(events.tickers) == 0) then script.on_event(defines.events.on_tick, nil) end +end + +function events.raise_tick(ev) + for rt, ff in pairs(events.tickers) do + for x, y in pairs(ff) do + if (ev.tick % rt == x) then + for a, b in pairs(y) do + b(ev.tick) + end + end + end + end +end + +function events.inject() + --error(serpent.block(events.filters[defines.events.on_built_entity])) + for k, v in pairs(events.defs) do + if (v and table_size(v) > 0) then + if (events.events_with_filters[table.KeyFromValue(defines.events, k)] and events.filters[k] and table_size(events.filters[k]) > 0) then + --if(k==defines.events.on_built_entity and #events.filters[k]>0)then error(k..":\n"..serpent.block(events.filters[k])) end + script.on_event(k, function(ev) for x, y in pairs(v) do y(ev) end end, events.filters[k]) + else + script.on_event(k, function(ev) for x, y in pairs(v) do y(ev) end end) + end + end + end + if (table_size(events.tickers) > 0) then script.on_event(defines.events.on_tick, events.raise_tick) end + + + + script.on_init(events.raise_init) + script.on_load(events.raise_load) + script.on_configuration_changed(events.raise_migrate) +end + +-- -------- +-- Gui + +vgui = vgui or {} +function vgui.create(parent, tbl) + local elm = parent[tbl.name] + if (not isvalid(elm)) then elm = parent.add(tbl) end + for k, v in pairs(tbl) do if (vgui.mods[k]) then vgui.mods[k](elm, v) end end + return elm +end + +vgui.mods = {} +vmods = vgui.mods +function vmods.horizontal_align(e, v) e.style.horizontal_align = v end + +function vmods.vertical_align(e, v) e.style.vertical_align = v end + +function vmods.align(e, v) + e.style.horizontal_align = (istable(v) and v[1] or v) + e.style.vertical_align = istable(v and v[2] or v) +end + +-- -------- +-- Remotes diff --git a/lib/lib_control_cache.lua b/lib/lib_control_cache.lua index d6b6a31..a29574e 100644 --- a/lib/lib_control_cache.lua +++ b/lib/lib_control_cache.lua @@ -1,663 +1,663 @@ ---[[------------------------------------- - -Author: Pyro-Fire -https://patreon.com/pyrofire - -Script: lib_control_cache.lua -Purpose: cache stuff with events - ------ - -Copyright (c) 2019 Pyro-Fire - -I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. - -Permission to use, copy, modify, and/or distribute this software for any -purpose without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------- - -Written using Microsoft Notepad. -IDE's are for children. - -How to notepad like a pro: -ctrl+f = find -ctrl+h = find & replace -ctrl+g = show/jump to line (turn off wordwrap n00b) - -Status bar wastes screen space, don't use it. - -Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. - -]]--------------------------------------- - - ---[[ Simple Cache & Events Manager ]]-- ---[[ Usage -cache.ent("assembling-machine-1",{built=function(ent) dostuff() end}) -cache.type("assembling-machine",{built=function(ent_with_type) dostuff() end}) - -Also has global table manager for arbitrary data on stuff. -Create/destroy manually though, still easier than writing a new handler every time. - -cache.vgui("hud_frame",{ click=function(elm,ev) - local menu=cache.get_menu("hud",ev.player_index) - cache.call_menu("clickyframe",menu,ev,...) - ..etc -end }) - -cache.menu("menu_name",{ create=function(menu,...) menu.frame=etc() end, destroy=function(menu,ev,...) forceclose() end, closed=function(menu,ev,...) onclosed() end }) -local menu=cache.raise_menu("hud",ply) -menu.frame=ply.gui.add("hud_frame",...) -... -local menu=cache.get_menu("menu_name",ply) -cache.call_menu("func_name",menu,data,...) -... -... -cache.destroy_menu(menu) -- force close menu - - -local vtbl=cache.raise_entity(entity) -... -cache.destroy_entity(vtbl) --- etc etc - - -]]-- - -local cache={} - - --- cache classes -cache.surfaces={} -cache.spatterns={} -cache.ents={} -cache.types={} -cache.patterns={} -cache.vguis={} -cache.gtypes={} -cache.gpatterns={} -cache.players={} -cache.forces={} -cache.fpatterns={} -cache.units={} -cache.utypes={} -cache.menus={} - --- translate named function tables -cache.primaries={ - ent="ents",type="types",pattern="patterns", - vgui="vguis",gpattern="gpatterns",gtype="gtype", - menu="menus", - player="players",force="forces", - surface="surfaces",spattern="spatterns", - unit="units",utype="utypes", -} --- grouped class types for event filters -cache.classes={ - ents={name="ents",type="types",ptrn="patterns"}, - vgui={name="vguis",type="gtypes",ptrn="gpatterns"}, - menus={name="menus"}, - players={single="players"}, - forces={name="forces",ptrn="fpatterns"}, - surfaces={name="surfaces",spattern="spatterns"}, -} - -for k,v in pairs(cache.primaries)do if(k~="player")then cache[k]=function(name,tbl) cache[v][name]=tbl end end end -function cache.player(tbl) cache.players=tbl end - - -cache.events={} -- Functions to distribute individual events among the caches in correct orders - -function cache.init() - global._lib=global._lib or {} - cache.migrate() -end - -function cache.migrate(ev) - if(global._libcache)then global._lib={cache=global._libcache} global._libcache=nil else global._lib=global._lib or {cache={}} end -- global._lib.cache - global._lib.cache=global._lib.cache or {} - for key,category in pairs(cache.primaries)do -- global._lib[raised_type] - global._lib[category]=global._lib[category] or {} - global._lib[category.."_idx"]=global._lib[category.."_idx"] or {} - end -end - - -function cache.load() -end - - -- helper functions for simple caching -function cache.insert(n,ent) global._lib.cache[n]=global._lib.cache[n] or {} table.insertExclusive(global._lib.cache[n],ent) end -function cache.validate(n) global._lib.cache[n]=global._lib.cache[n] or {} for k,v in pairs(global._lib.cache[n])do if(not isvalid(v))then global._lib.cache[n][k]=nil end end end -function cache.remove(n,ent) global._lib.cache[n]=global._lib.cache[n] or {} table.RemoveByValue(global._lib.cache[n],ent) end -function cache.get(n) if(isstring(n))then return global._lib.cache[n] or {} end end ---function cache.call(n,evn,ev,...) for k,v in pairs(cache.get(n))do ev.entity=v cache.call_ents(evn,ev,...) end end -- Call a simple event on all entities in a cache table. -function cache.entcall(n,evn,ev,...) for k,v in pairs(cache.get(n))do ev.entity=v cache.call_ents(evn,ev,...) end end -- Call a simple event on all entities in a cache table. -function cache.surfacecall(n,evn,ev,...) for k,v in pairs(cache.get(n))do ev.entity=v cache.call_surfaces(evn,ev,...) end end -- Call a simple event on all entities in a cache table. - - - - -function cache.call_ents(vn,ev,...) local ent=events.entity(ev) if(not isvalid(ent))then return end - local tx=cache.types[ent.type=="ghost" and ent.ghost_type or ent.type] if(tx and tx[vn])then tx[vn](ent,ev,...) end if(not isvalid(ent))then return end - local tx=cache.ents[ent.type=="ghost" and ent.ghost_name or ent.name] if(tx and tx[vn])then tx[vn](ent,ev,...) end if(not isvalid(ent))then return end - local tx for k,v in pairs(cache.patterns)do if((ent.type=="ghost" and ent.ghost_name or ent.name):find(k,1,true))then tx=v break end end if(tx and tx[vn])then tx[vn](ent,ev,...) end -end -function cache.call_vgui(vn,ev,...) local elm=ev.element if(not isvalid(elm))then return end - local tx=cache.vguis[elm.name] if(tx and tx[vn])then tx[vn](ev.element,ev,...) end - local tx=cache.gtypes[elm.type] if(tx and tx[vn])then tx[vn](ev.element,ev,...) end - local tx for k,v in pairs(cache.gpatterns)do if(elm.name:find(k,1,true))then tx=v break end end if(tx and tx[vn])then tx[vn](ev.element,ev,...) end -end -function cache.call_player(vn,ev,...) local tx=cache.players[vn] if(not tx)then return end - if(tx)then tx(game.players[ev.player_index],ev,...) end -end -function cache.call_force(vn,ev,...) local f=ev.force if(not f)then f=game.forces[ev.force_index] end if(not f)then f=game.forces[ev.force_name] end if(not isvalid(f))then return end - local tx=cache.forces[f.name] if(tx and tx[vn])then tx[vn](f,ev,...) end - local tx for k,v in pairs(cache.fpatterns)do if(f.name:find(k,1,true))then tx=v break end end if(tx and tx[vn])then tx[vn](f,ev,...) end -end - -function cache.call_surface(vn,ev,...) local f=ev.surface if(not f)then f=game.surfaces[ev.surface_index] end if(not isvalid(f))then return end - local tx=cache.surfaces[f.name] if(tx and tx[vn])then tx[vn](f,ev,...) end - local tx for k,v in pairs(cache.spatterns)do if(f.name:find(k,1,true))then tx=v break end end if(tx and tx[vn])then tx[vn](f,ev,...) end -end -function cache.call_menu(vn,menu,ev,...) - local tx=cache.menus[menu.name] if(tx and tx[vn])then tx[vn](menu,ev,...) end -end - -function cache.get_index(host,key) return host[key] end - --- Raise/destroy stuff to cache into global table. It gives us an internally managed cache table to shove data into e.g. creation/destruction of the base object. -function cache.raise_type(vtype,name,host,...) - local uid if(isnumber(host))then uid=host else local cx cx,uid=pcall(cache.get_index,host,"index") if(not cx)then cx,uid=pcall(cache.get_index,host,"unit_number") if(not cx)then uid=nil end end end - local hdx=uid - if(hdx)then local gc=global._lib[vtype.."_idx"][hdx] if(gc and name)then gc=gc[name] end if(gc)then return gc end end -- get existing hosted/index vtype - local c=cache[vtype] -- cache["ents"][name]. You can call these manually if you need to for ptrn, surfaces etc. - if(not c)then return end if(name)then c=c[name] if(not c)then return end end -- only menus and vguis typically use names. - local idx=#global._lib[vtype]+1 - local t={index=idx,name=name,type=vtype,host=host,hostindex=hdx} global._lib[vtype][idx]=t - if(hdx)then - if(name)then local gc=global._lib[vtype.."_idx"][hdx] or {} global._lib[vtype.."_idx"][hdx]=gc gc[t.name]=t - else global._lib[vtype.."_idx"][hdx]=t - end - end - if(c.raise)then c.raise(t,...) end - if(vtype=="ents")then if(c[host.name] and c[host.name].raise)then c[host.name].raise(t,...) end end - if(vtype=="types")then local htype=(host.is_player() and "player" or host.type) if(c[htype] and c[htype].raise)then c[htype].raise(t,...) end end - - return t -end -function cache.destroy_type(obj,...) local vtype=obj.type - local c=cache[vtype] if(not c)then return end if(obj.name)then c=c[obj.name] if(not c)then return end end - if(c.unraise)then c.unraise(obj,...) end - global._lib[vtype][obj.index]=nil - if(obj.hostindex)then global._lib[vtype.."_idx"][obj.hostindex]=nil end -end -function cache.get_type(vtype,name,host) local t=global._lib[vtype.."_idx"] - if(t)then - local uid if(isnumber(host))then uid=host else local cx cx,uid=pcall(cache.get_index,host,"index") if(not cx)then cx,uid=pcall(cache.get_index,host,"unit_number") if(not cx)then uid=nil end end end - if(uid)then t=t[uid] else t=nil end - end - if(t and name)then t=t[name] end - return t -end -function cache.get_raise_type(vtype,name,host,...) return cache.get_type(vtype,name,host) or cache.raise_type(vtype,name,host,...) end -function cache.get_types(vtype) local t=global._lib[vtype] return t end - -function cache.destroy(obj,...) return cache.destroy_type(obj,...) end -- This just destroys the cache object, not the actual in-game object. - - -function cache.raise_menu(name,ply,...) return cache.raise_type("menus",name,ply,...) end -function cache.force_menu(name,ply,...) return cache.get_raise_type("menus",name,ply,...) end -function cache.get_menu(name,ply) return cache.get_type("menus",name,ply) end -cache.destroy_menu=cache.destroy - -function cache.raise_vgui(name,menu,...) return cache.raise_type("vguis",name,menu,...) end -function cache.force_vgui(name,menu,...) return cache.get_raise_type("vguis",name,menu,...) end -function cache.get_vgui(name,menu) return cache.get_type("vguis",name,menu) end -cache.destroy_vgui=cache.destroy - -function cache.raise_player(ply,...) return cache.raise_type("players",nil,ply,...) end -function cache.force_player(ply,...) return cache.get_raise_type("players",nil,ply,...) end -function cache.get_player(ply) return cache.get_type("players",nil,ply) end -cache.destroy_player=cache.destroy - -function cache.raise_force(force,...) return cache.raise_type("forces",nil,force,...) end -function cache.force_force(force,...) return cache.get_raise_type("forces",nil,force,...) end -function cache.get_force(force) return cache.get_type("forces",nil,force) end -cache.destroy_force=cache.destroy - -function cache.raise_surface(surface,...) return cache.raise_type("surfaces",nil,surface,...) end -function cache.force_surface(surface,...) return cache.get_raise_type("surfaces",nil,surface,...) end -function cache.get_surface(surface) return cache.get_type("surfaces",nil,surface) end -cache.destroy_surface=cache.destroy - -function cache.raise_unit(unit,...) return cache.raise_type("units",nil,unit,...) end -function cache.force_unit(unit,...) return cache.get_raise_type("units",nil,unit,...) end -function cache.get_unit(unit) return cache.get_type("units",nil,unit) end -cache.destroy_unit=cache.destroy - -function cache.raise_entity(ent,...) return cache.raise_type("ents",nil,ent,...) end -function cache.force_entity(ent,...) return cache.get_raise_type("ents",nil,ent,...) end -function cache.get_entity(ent) return cache.get_type("ents",nil,ent) end -cache.destroy_entity=cache.destroy - - - -function cache.update(ent,vn,...) vn=vn or "update" - local tx=cache.types[ent.type] if(tx and tx[vn])then tx[vn](ent,...) end - local tx=cache.ents[ent.name] if(tx and tx[vn])then tx[vn](ent,...) end - local tx for k,v in pairs(cache.patterns)do if(ent.name:find(k,1,true))then tx=v break end end if(tx and tx[vn])then tx[vn](ent,...) end -end -function cache.updategui(elm,...) local vn="update" if(not isstring(elm))then elm=elm.name end - local tx=cache.vguis[elm.name] if(tx and tx[vn])then tx[vn](elm,...) end - local tx=cache.gtypes[elm.name] if(tx and tx[vn])then tx[vn](elm,...) end - local tx for k,v in pairs(cache.gpatterns)do if(elm.name:find(k,1,true))then tx=v break end end if(tx and tx[vn])then tx[vn](elm,...) end -end -function cache.updatemenu(mn,vn,ev,...) for i,ply in pairs(game.players)do - local menu=cache.get_menu(mn,ply) if(menu)then - cache.call_menu(vn,menu,ev,...) - end -end end - - - -function cache.inject_type(nm,evdata) - local funcs=cache.events[nm] - local defs=cache.events[nm.."_defs"] - local ccls=cache.classes[nm] - - - local ptrn=false - for evtype,vdefs in pairs(defs)do - if(ccls.name)then for tpnm,cls in pairs(cache[ccls.name])do if(cls[evtype])then - for _,def in pairs(vdefs)do evdata[def]=evdata[def] or {} table.insert(evdata[def],{nm=nm,tpnm=tpnm,evtype=evtype,ghost=cls.ghost,clsname=ccls.name,func=funcs[def]}) end - end end end - if(ccls.type)then for tpnm,cls in pairs(cache[ccls.type])do if(cls[evtype])then - for _,def in pairs(vdefs)do evdata[def]=evdata[def] or {} table.insert(evdata[def],{nm=nm,tpnm=tpnm,evtype=evtype,ghost=cls.ghost,clstype=ccls.type,func=funcs[def]}) end - end end end - if(ccls.ptrn)then for tpnm,cls in pairs(cache[ccls.ptrn])do if(cls[evtype])then ptrn=true - for _,def in pairs(vdefs)do evdata[def]=evdata[def] or {} table.insert(evdata[def],{nm=nm,tpnm=tpnm,evtype=evtype,ghost=cls.ghost,clsptrn=ccls.ptrn,func=funcs[def]}) end - end end end - if(ccls.single)then local cls=cache[ccls.single] if(cls[evtype])then - for _,def in pairs(vdefs)do evdata[def]=evdata[def] or {} table.insert(evdata[def],{nm=nm,tpnm=tpnm,evtype=evtype,ghost=cls.ghost,clssingle=ccls.single,func=funcs[def]}) end - end end - end - --if(nm=="players")then error(serpent.block(evdata)) end -end - - -function cache.inject() -- interface with events - local evdata={} for nm in pairs(cache.classes)do cache.inject_type(nm,evdata) end - --error(serpent.block(evdata)) - for def,tbl in pairs(evdata)do - local filters={} - local nmf,tpf,ptf,sgf - --if(events.events_with_filters[def])then - for i,vtbl in pairs(tbl)do - if(vtbl.clsptrn)then ptf=vtbl.func filters=nil - elseif(vtbl.clstype)then tpf=vtbl.func - if(filters)then table.insert(filters,{filter="type",type=vtbl.tpnm}) - if(vtbl.ghost)then table.insert(filters,{filter="ghost_type",type=vtbl.tpnm}) end - end - elseif(vtbl.clsname)then nmf=vtbl.func - if(filters)then table.insert(filters,{filter="name",name=vtbl.tpnm}) - if(vtbl.ghost)then table.insert(filters,{filter="ghost_name",name=vtbl.tpnm}) end - end - elseif(vtbl.clssingle)then sgf=vtbl.func filters=nil - end - end - --end - if(not events.events_with_filters[def])then filters=nil end - - if(nmf)then events.hook(defines.events[def],nmf,filters) end - if(tpf)then events.hook(defines.events[def],tpf,filters) end - if(ptf)then events.hook(defines.events[def],ptf,filters) end - if(sgf)then events.hook(defines.events[def],sgf,filters) end - end -end - ---[[ Unknowns -on_put_item -on_ai_command_completed - -on_difficulty_settings_changed -on_cutscene_waypout_reached - -on_console_command -on_console_chat - -on_chart_tag_added -on_chart_tag_modified -on_chart_tag_removed -- force events - -on_game_created_from_scenario - -on_robot_built_entity -on_robot_built_tile -on_robot_exploded_cliff -on_robot_mined -on_robot_mined_entity -on_robot_mined_tile -on_robot_pre_mined -on_rocket_launch_ordered -on_rocket_launched -on_runtime_mod_setting_changed -on_script_path_request_finished -- pathfinding -on_sector_scanned -- radar -on_string_translated - -on_train_changed_state -on_train_created -on_train_schedule_changed - -on_trigger_fired_artillery - -on_unit_added_to_group -on_unit_group_created -on_unit_removed_from_group -on_biter_base_built - - -on_market_item_purchased - - -]] - - -cache.events.forces={} -function cache.events.forces.on_research_finished(ev) cache.call_force("research_finished",ev) end -function cache.events.forces.on_research_started(ev) cache.call_force("research_started",ev) end -function cache.events.forces.on_technology_effects_reset(ev) cache.call_force("research_reset",ev) end -function cache.events.forces.on_chart_tag_added(ev) cache.call_force("tag_added",ev) end -function cache.events.forces.on_chart_tag_modified(ev) cache.call_force("tag_modified",ev) end -function cache.events.forces.on_chart_tag_removed(ev) cache.call_force("tag_removed",ev) end - -cache.events.forces_defs={ -- Things that specifically are called with a force. Player stuff can be hooked from players. - research_finished={"on_research_finished"}, - research_started={"on_research_started"}, - research_reset={"on_technology_effects_reset"}, -} - -cache.events.ents={} -function cache.events.ents.on_built_entity(ev) cache.call_ents("built",ev) cache.call_ents("create",ev) end -function cache.events.ents.script_raised_built(ev) cache.call_ents("create",ev) end -function cache.events.ents.on_entity_cloned(ev) cache.call_ents("clone",ev) cache.call_ents("create",ev) end -function cache.events.ents.on_robot_built_entity(ev) cache.call_ents("built",ev) cache.call_ents("create",ev) end -function cache.events.ents.script_raised_destroy(ev) cache.call_ents("destroy",ev) end -function cache.events.ents.on_entity_died(ev) cache.call_ents("died",ev) cache.call_ents("destroy",ev) end -function cache.events.ents.on_post_entity_died(ev) cache.call_ents("post_died",ev) end -function cache.events.ents.on_player_mined_entity(ev) cache.call_ents("mined",ev) cache.call_ents("destroy",ev) end -function cache.events.ents.on_robot_mined_entity(ev) cache.call_ents("mined",ev) cache.call_ents("destroy",ev) end -function cache.events.ents.on_player_rotated_entity(ev) cache.call_ents("rotate",ev) end -function cache.events.ents.on_entity_settings_pasted(ev) cache.call_ents("settings_pasted",ev) end -function cache.events.ents.on_pre_entity_settings_pasted(ev) cache.call_ents("pre_settings_pasted",ev) end -function cache.events.ents.on_cancelled_deconstruction(ev) cache.call_ents("cancel_deconstruct",ev) end -function cache.events.ents.on_cancelled_upgrade(ev) cache.call_ents("cancel_upgrade",ev) end -function cache.events.ents.on_marked_for_deconstruction(ev) cache.call_ents("deconstruct",ev) end -function cache.events.ents.on_marked_for_upgrade(ev) cache.call_ents("upgrade",ev) end -function cache.events.ents.on_pre_ghost_deconstructed(ev) cache.call_ents("deconstruct_ghost",ev) end -function cache.events.ents.on_post_entity_died(ev) cache.call_ents("post_died",ev) end -function cache.events.ents.on_mod_item_opened(ev) cache.call_ents("item_menu",ev) end -function cache.events.ents.on_entity_damaged(ev) cache.call_ents("damage",ev) end -function cache.events.ents.on_trigger_created_entity(ev) cache.call_ents("trigger",ev) end -function cache.events.ents.on_entity_spawned(ev) cache.call_ents("spawned",ev) end -function cache.events.ents.on_land_mine_armed(ev) cache.call_ents("mine_armed",ev) end -function cache.events.ents.on_gui_opened(ev) cache.call_ents("gui_opened",ev) end -function cache.events.ents.on_gui_closed(ev) cache.call_ents("gui_closed",ev) end -function cache.events.ents.on_pre_robot_exploded_cliff(ev) cache.call_ents("pre_robot_exploded_cliff",ev) end -function cache.events.ents.on_post_entity_died(ev) cache.call_ents("post_died",ev) end -function cache.events.ents.on_combat_robot_expired(ev) cache.call_ents("robot_expired",ev) end -function cache.events.ents.script_raised_revive(ev) cache.call_ents("create",ev) end -function cache.events.ents.on_entity_renamed(ev) cache.call_ents("rename",ev) end - -cache.events.ents_defs={ - built={"on_built_entity","on_robot_built_entity"}, - create={"on_built_entity","script_raised_built","on_entity_cloned","on_robot_built_entity","script_raised_revive"}, - mined={"on_player_mined_entity","on_robot_mined_entity"}, - rotate={"on_player_rotated_entity"}, - rename={"on_entity_renamed"}, - destroy={"on_player_mined_entity","on_robot_mined_entity","script_raised_destroy","on_entity_died"}, - - died={"on_entity_died"}, - post_died={"on_post_entity_died"}, - - settings_pasted={"on_entity_settings_pasted"}, - pre_settings_pasted={"on_pre_entity_settings_pasted"}, - cancel_deconstruct={"on_cancelled_deconstruction"}, - cancel_upgrade={"on_cancelled_upgrade"}, - deconstruct={"on_marked_for_deconstruction"}, - deconstruct_ghost={"on_pre_ghost_deconstructed"}, - - upgrade={"on_marked_for_upgrade"}, - - gui_opened={"on_gui_opened"}, - gui_closed={"on_gui_closed"}, - - item_menu={"on_mod_item_opened"}, --Called when the player uses the 'Open item GUI' control on an item defined with 'can_be_mod_opened' as true - damage={"on_entity_damaged"}, - trigger={"on_trigger_created_entity"}, - robot_expired={"on_combat_robot_expired"}, - - spawned={"on_entity_spawned"}, - mine_armed={"on_land_mine_armed"}, - - pre_robot_exploded_cliff={"on_pre_robot_exploded_cliff"}, - post_died={"on_post_entity_died"}, -} - - -cache.events.vgui={} -function cache.events.vgui.on_gui_opened(ev) cache.call_vgui("open_menu",ev) end -function cache.events.vgui.on_gui_closed(ev) cache.call_vgui("gui_closed",ev) cache.call_vgui("gui_closed",ev) end -function cache.events.vgui.on_gui_click(ev) cache.call_vgui("click",ev) end -function cache.events.vgui.on_gui_confirmed(ev) cache.call_vgui("confirm",ev) end -function cache.events.vgui.on_gui_text_changed(ev) cache.call_vgui("text_changed",ev) end -function cache.events.vgui.on_gui_selection_state_changed(ev) cache.call_vgui("selection_changed",ev) end -function cache.events.vgui.on_player_display_resolution_changed(ev) cache.call_vgui("on_resolution",ev) end -function cache.events.vgui.on_player_display_scale_changed(ev) cache.call_vgui("on_scale",ev) end -function cache.events.vgui.on_gui_checked_state_changed(ev) cache.call_vgui("on_checked",ev) end -function cache.events.vgui.on_gui_elem_changed(ev) cache.call_vgui("elem_changed",ev) end -function cache.events.vgui.on_gui_location_changed(ev) cache.call_vgui("location_changed",ev) end -function cache.events.vgui.on_gui_selected_tab_changed(ev) cache.call_vgui("tab_changed",ev) end -function cache.events.vgui.on_gui_switch_state_changed(ev) cache.call_vgui("on_switched",ev) end -function cache.events.vgui.on_gui_value_changed(ev) cache.call_vgui("value_changed",ev) end - -cache.events.vgui_defs={ - click={"on_gui_click"}, - open_menu={"on_gui_opened"}, - gui_closed={"on_gui_closed"}, - confirm={"on_gui_confirmed"}, - text_changed={"on_gui_text_changed"}, - selection_changed={"on_gui_selection_state_changed"}, - on_resolution={"on_player_display_resolution_changed"}, - on_scale={"on_player_display_scale_changed"}, - on_checked={"on_gui_checked_state_changed"}, - elem_changed={"on_gui_elem_changed"}, - location_changed={"on_gui_location_changed"}, - tab_changed={"on_gui_selected_tab_changed"}, - on_switched={"on_gui_switch_state_changed"}, - value_changed={"on_gui_value_changed"}, -} - - - -cache.events.surfaces={} -function cache.events.surfaces.on_surface_created(ev) cache.call_surface("create",ev) end -function cache.events.surfaces.on_pre_surface_deleted(ev) cache.call_surface("pre_deleted",ev) end -function cache.events.surfaces.on_pre_surface_cleared(ev) cache.call_surface("pre_cleared",ev) end -function cache.events.surfaces.on_surface_deleted(ev) cache.call_surface("on_deleted",ev) end -function cache.events.surfaces.on_surface_imported(ev) cache.call_surface("import",ev) end -function cache.events.surfaces.on_surface_renamed(ev) cache.call_surface("rename",ev) end -function cache.events.surfaces.on_chunk_generated(ev) cache.call_surface("chunk",ev) end -function cache.events.surfaces.on_chunk_deleted(ev) cache.call_surface("chunk_deleted",ev) end -function cache.events.surfaces.on_pre_chunk_deleted(ev) cache.call_surface("pre_chunk_deleted",ev) end -function cache.events.surfaces.on_chunk_charted(ev) cache.call_surface("chart",ev) end - -cache.events.surfaces_defs={ - create={"on_surface_created"}, - pre_deleted={"on_pre_surface_deleted"}, - pre_cleared={"on_pre_surface_cleared"}, - on_cleared={"on_surface_cleared"}, - on_deleted={"on_surface_deleted"}, - - import={"on_surface_imported"}, - rename={"on_surface_renamed"}, - chunk={"on_chunk_generated"}, - chunk_deleted={"on_chunk_deleted"}, - pre_chunk_deleted={"on_pre_chunk_deleted"}, - - chart={"on_chunk_charted"}, -} - -cache.events.players={} -function cache.events.players.on_player_toggled_alt_mode(ev) cache.call_player("on_alt",ev) end -function cache.events.players.on_player_toggled_map_editor(ev) cache.call_player("on_editor",ev) end -function cache.events.players.on_player_cheat_mode_enabled(ev) cache.call_player("on_cheat",ev) end -function cache.events.players.on_player_cheat_mode_disabled(ev) cache.call_player("on_uncheat",ev) end -function cache.events.players.on_player_driving_changed_state(ev) cache.call_player("on_driving",ev) end -function cache.events.players.on_pickup_item(ev) cache.call_player("on_pickup_item",ev) end -function cache.events.players.on_player_dropped_item(ev) cache.call_player("on_drop_item",ev) end -function cache.events.players.on_player_fast_transferred(ev) cache.call_player("on_fast_transfer",ev) end -function cache.events.players.on_player_gun_inventory_changed(ev) cache.call_player("on_gun_inv",ev) end -function cache.events.players.on_player_ammo_inventory_changed(ev) cache.call_player("on_ammo_changed",ev) end -function cache.events.players.on_player_armor_inventory_changed(ev) cache.call_player("on_armor_changed",ev) end -function cache.events.players.on_player_placed_equipment(ev) cache.call_player("on_equip",ev) end -function cache.events.players.on_player_removed_equipment(ev) cache.call_player("on_dequip",ev) end - -function cache.events.players.on_built_tile(ev) cache.call_player("on_built_tile",ev) end -function cache.events.players.on_built_entity(ev) cache.call_player("on_built",ev) end -function cache.events.players.on_player_changed_position(ev) cache.call_player("on_position",ev) end -function cache.events.players.on_player_changed_surface(ev) cache.call_player("on_surface",ev) end -function cache.events.players.on_character_corpse_expired(ev) cache.call_player("on_corpse_expired",ev) end -function cache.events.players.on_lua_shortcut(ev) cache.call_player("on_shortcut",ev) end -function cache.events.players.on_player_alt_selected_area(ev) cache.call_player("on_alt_select_area",ev) end -function cache.events.players.on_player_deconstructed_area(ev) cache.call_player("on_deconstruct_area",ev) end -function cache.events.players.on_player_selected_area(ev) cache.call_player("on_select_area",ev) end -function cache.events.players.on_player_configured_blueprint(ev) cache.call_player("on_blueprint",ev) end -function cache.events.players.on_player_setup_blueprint(ev) cache.call_player("on_setup_blueprint",ev) end -function cache.events.players.on_selected_entity_changed(ev) cache.call_player("on_selected_entity_changed",ev) end -function cache.events.players.on_player_respawned(ev) cache.call_player("on_respawn",ev) end -function cache.events.players.on_player_created(ev) cache.call_player("on_create",ev) end -function cache.events.players.on_player_joined_game(ev) cache.call_player("on_join",ev) end -function cache.events.players.on_player_banned(ev) cache.call_player("on_banned",ev) end -function cache.events.players.on_player_left_game(ev) cache.call_player("on_left",ev) end -function cache.events.players.on_player_removed(ev) cache.call_player("on_removed",ev) end -function cache.events.players.on_pre_player_left_game(ev) cache.call_player("on_pre_left",ev) end -function cache.events.players.on_pre_player_removed(ev) cache.call_player("on_pre_removed",ev) end -function cache.events.players.on_player_unbanned(ev) cache.call_player("on_unban",ev) end -function cache.events.players.on_player_unmuted(ev) cache.call_player("on_unmute",ev) end -function cache.events.players.on_player_demoted(ev) cache.call_player("on_demoted",ev) end -function cache.events.players.on_player_died(ev) cache.call_player("on_died",ev) end -function cache.events.players.on_pre_player_died(ev) cache.call_player("on_pre_died",ev) end -function cache.events.players.on_player_muted(ev) cache.call_player("on_muted",ev) end -function cache.events.players.on_player_promoted(ev) cache.call_player("on_promoted",ev) end -function cache.events.players.on_player_main_inventory_changed(ev) cache.call_player("on_inventory",ev) end -function cache.events.players.on_player_mined_entity(ev) cache.call_player("on_mined",ev) end -function cache.events.players.on_pre_player_mined_item(ev) cache.call_player("on_pre_mined_item",ev) end -function cache.events.players.on_player_mined_item(ev) cache.call_player("on_mined_item",ev) end -function cache.events.players.on_player_mined_tile(ev) cache.call_player("on_mined_tile",ev) end -function cache.events.players.on_player_cursor_stack_changed(ev) cache.call_player("on_cursor",ev) end -function cache.events.players.on_player_pipette(ev) cache.call_player("on_pipette",ev) end -function cache.events.players.on_player_cancelled_crafting(ev) cache.call_player("on_cancel_craft",ev) end -function cache.events.players.on_pre_player_crafted_item(ev) cache.call_player("on_pre_craft",ev) end -function cache.events.players.on_player_crafted_item(ev) cache.call_player("on_craft",ev) end -function cache.events.players.on_player_repaired_entity(ev) cache.call_player("on_repair",ev) end -function cache.events.players.on_player_rotated_entity(ev) cache.call_player("on_rotate",ev) end -function cache.events.players.on_player_trash_inventory_changed(ev) cache.call_player("on_trash_changed",ev) end -function cache.events.players.on_player_used_capsule(ev) cache.call_player("on_capsule",ev) end - - -cache.events.players_defs={ - - on_alt={"on_player_toggled_alt_mode"}, - on_editor={"on_player_toggled_map_editor"}, - - on_cheat={"on_player_cheat_mode_enabled"}, - on_uncheat={"on_player_cheat_mode_disabled"}, - - on_driving={"on_player_driving_changed_state"}, - - on_pickup_item={"on_picked_up_item"}, - on_drop_item={"on_player_dropped_item"}, - - on_fast_transfer={"on_player_fast_transferred"}, - on_gun_inv={"on_player_gun_inventory_changed"}, - on_ammo_changed={"on_player_ammo_inventory_changed"}, - on_armor_changed={"on_player_armor_inventory_changed"}, - on_equip={"on_player_placed_equipment"}, - on_dequip={"on_player_removed_equipment"}, - - on_built_tile={"on_player_built_tile"}, - on_built={"on_entity_built"}, - - on_position={"on_player_changed_position"}, - on_surface={"on_player_changed_surface"}, - - on_corpse_expired={"on_character_corpse_expired"}, - - on_shortcut={"on_lua_shortcut"}, - on_alt_select_area={"on_player_alt_selected_area"}, - on_deconstruct_area={"on_player_deconstructed_area"}, - on_select_area={"on_player_selected_area"}, - - - on_blueprint={"on_player_configured_blueprint"}, - on_setup_blueprint={"on_player_setup_blueprint"}, - - on_select={"on_selected_entity_changed"}, - - on_respawn={"on_player_respawned"}, - on_create={"on_player_created"}, - on_join={"on_player_joined_game"}, - - on_banned={"on_player_banned"}, - on_left={"on_player_left_game"}, - on_removed={"on_player_removed"}, - on_pre_left={"on_pre_player_left_game"}, - on_pre_removed={"on_pre_player_removed"}, - - on_unban={"on_player_unbanned"}, - on_unmute={"on_player_unmuted"}, - on_demote={"on_player_demoted"}, - - on_died={"on_player_died"}, - on_pre_died={"on_pre_player_died"}, - - on_muted={"on_player_muted"}, - on_promoted={"on_player_promoted"}, - - on_inventory={"on_player_main_inventory_changed"}, - on_mined={"on_player_mined_entity"}, - on_pre_mined_item={"on_pre_player_mined_item"}, - on_mined_item={"on_player_mined_item"}, - on_mined_tile={"on_player_mined_tile"}, - - on_cursor={"on_player_cursor_stack_changed"}, - on_pipette={"on_player_pipette"}, - - on_cancel_craft={"on_player_cancelled_crafting"}, - on_pre_craft={"on_pre_player_crafted_item"}, - on_craft={"on_player_crafted_item"}, - - on_repair={"on_player_repaired_entity"}, - on_rotate={"on_player_rotated_entity"}, - - on_trash_changed={"on_player_trash_inventory_changed"}, - - on_capsule={"on_player_used_capsule"}, - -} -cache.events.menus={} -cache.events.menus_defs={ -} - +--[[------------------------------------- + +Author: Pyro-Fire +https://patreon.com/pyrofire + +Script: lib_control_cache.lua +Purpose: cache stuff with events + +----- + +Copyright (c) 2019 Pyro-Fire + +I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. + +Permission to use, copy, modify, and/or distribute this software for any +purpose without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------ + +Written using Microsoft Notepad. +IDE's are for children. + +How to notepad like a pro: +ctrl+f = find +ctrl+h = find & replace +ctrl+g = show/jump to line (turn off wordwrap n00b) + +Status bar wastes screen space, don't use it. + +Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. + +]]--------------------------------------- + + +--[[ Simple Cache & Events Manager ]]-- +--[[ Usage +cache.ent("assembling-machine-1",{built=function(ent) dostuff() end}) +cache.type("assembling-machine",{built=function(ent_with_type) dostuff() end}) + +Also has global table manager for arbitrary data on stuff. +Create/destroy manually though, still easier than writing a new handler every time. + +cache.vgui("hud_frame",{ click=function(elm,ev) + local menu=cache.get_menu("hud",ev.player_index) + cache.call_menu("clickyframe",menu,ev,...) + ..etc +end }) + +cache.menu("menu_name",{ create=function(menu,...) menu.frame=etc() end, destroy=function(menu,ev,...) forceclose() end, closed=function(menu,ev,...) onclosed() end }) +local menu=cache.raise_menu("hud",ply) +menu.frame=ply.gui.add("hud_frame",...) +... +local menu=cache.get_menu("menu_name",ply) +cache.call_menu("func_name",menu,data,...) +... +... +cache.destroy_menu(menu) -- force close menu + + +local vtbl=cache.raise_entity(entity) +... +cache.destroy_entity(vtbl) +-- etc etc + + +]]-- + +local cache={} + + +-- cache classes +cache.surfaces={} +cache.spatterns={} +cache.ents={} +cache.types={} +cache.patterns={} +cache.vguis={} +cache.gtypes={} +cache.gpatterns={} +cache.players={} +cache.forces={} +cache.fpatterns={} +cache.units={} +cache.utypes={} +cache.menus={} + +-- translate named function tables +cache.primaries={ + ent="ents",type="types",pattern="patterns", + vgui="vguis",gpattern="gpatterns",gtype="gtype", + menu="menus", + player="players",force="forces", + surface="surfaces",spattern="spatterns", + unit="units",utype="utypes", +} +-- grouped class types for event filters +cache.classes={ + ents={name="ents",type="types",ptrn="patterns"}, + vgui={name="vguis",type="gtypes",ptrn="gpatterns"}, + menus={name="menus"}, + players={single="players"}, + forces={name="forces",ptrn="fpatterns"}, + surfaces={name="surfaces",spattern="spatterns"}, +} + +for k,v in pairs(cache.primaries)do if(k~="player")then cache[k]=function(name,tbl) cache[v][name]=tbl end end end +function cache.player(tbl) cache.players=tbl end + + +cache.events={} -- Functions to distribute individual events among the caches in correct orders + +function cache.init() + storage._lib=storage._lib or {} + cache.migrate() +end + +function cache.migrate(ev) + if(storage._libcache)then storage._lib={cache=storage._libcache} storage._libcache=nil else storage._lib=storage._lib or {cache={}} end -- storage._lib.cache + storage._lib.cache=storage._lib.cache or {} + for key,category in pairs(cache.primaries)do -- storage._lib[raised_type] + storage._lib[category]=storage._lib[category] or {} + storage._lib[category.."_idx"]=storage._lib[category.."_idx"] or {} + end +end + + +function cache.load() +end + + -- helper functions for simple caching +function cache.insert(n,ent) storage._lib.cache[n]=storage._lib.cache[n] or {} table.insertExclusive(storage._lib.cache[n],ent) end +function cache.validate(n) storage._lib.cache[n]=storage._lib.cache[n] or {} for k,v in pairs(storage._lib.cache[n])do if(not isvalid(v))then storage._lib.cache[n][k]=nil end end end +function cache.remove(n,ent) storage._lib.cache[n]=storage._lib.cache[n] or {} table.RemoveByValue(storage._lib.cache[n],ent) end +function cache.get(n) if(isstring(n))then return storage._lib.cache[n] or {} end end +--function cache.call(n,evn,ev,...) for k,v in pairs(cache.get(n))do ev.entity=v cache.call_ents(evn,ev,...) end end -- Call a simple event on all entities in a cache table. +function cache.entcall(n,evn,ev,...) for k,v in pairs(cache.get(n))do ev.entity=v cache.call_ents(evn,ev,...) end end -- Call a simple event on all entities in a cache table. +function cache.surfacecall(n,evn,ev,...) for k,v in pairs(cache.get(n))do ev.entity=v cache.call_surfaces(evn,ev,...) end end -- Call a simple event on all entities in a cache table. + + + + +function cache.call_ents(vn,ev,...) local ent=events.entity(ev) if(not isvalid(ent))then return end + local tx=cache.types[ent.type=="ghost" and ent.ghost_type or ent.type] if(tx and tx[vn])then tx[vn](ent,ev,...) end if(not isvalid(ent))then return end + local tx=cache.ents[ent.type=="ghost" and ent.ghost_name or ent.name] if(tx and tx[vn])then tx[vn](ent,ev,...) end if(not isvalid(ent))then return end + local tx for k,v in pairs(cache.patterns)do if((ent.type=="ghost" and ent.ghost_name or ent.name):find(k,1,true))then tx=v break end end if(tx and tx[vn])then tx[vn](ent,ev,...) end +end +function cache.call_vgui(vn,ev,...) local elm=ev.element if(not isvalid(elm))then return end + local tx=cache.vguis[elm.name] if(tx and tx[vn])then tx[vn](ev.element,ev,...) end + local tx=cache.gtypes[elm.type] if(tx and tx[vn])then tx[vn](ev.element,ev,...) end + local tx for k,v in pairs(cache.gpatterns)do if(elm.name:find(k,1,true))then tx=v break end end if(tx and tx[vn])then tx[vn](ev.element,ev,...) end +end +function cache.call_player(vn,ev,...) local tx=cache.players[vn] if(not tx)then return end + if(tx)then tx(game.players[ev.player_index],ev,...) end +end +function cache.call_force(vn,ev,...) local f=ev.force if(not f)then f=game.forces[ev.force_index] end if(not f)then f=game.forces[ev.force_name] end if(not isvalid(f))then return end + local tx=cache.forces[f.name] if(tx and tx[vn])then tx[vn](f,ev,...) end + local tx for k,v in pairs(cache.fpatterns)do if(f.name:find(k,1,true))then tx=v break end end if(tx and tx[vn])then tx[vn](f,ev,...) end +end + +function cache.call_surface(vn,ev,...) local f=ev.surface if(not f)then f=game.surfaces[ev.surface_index] end if(not isvalid(f))then return end + local tx=cache.surfaces[f.name] if(tx and tx[vn])then tx[vn](f,ev,...) end + local tx for k,v in pairs(cache.spatterns)do if(f.name:find(k,1,true))then tx=v break end end if(tx and tx[vn])then tx[vn](f,ev,...) end +end +function cache.call_menu(vn,menu,ev,...) + local tx=cache.menus[menu.name] if(tx and tx[vn])then tx[vn](menu,ev,...) end +end + +function cache.get_index(host,key) return host[key] end + +-- Raise/destroy stuff to cache into global table. It gives us an internally managed cache table to shove data into e.g. creation/destruction of the base object. +function cache.raise_type(vtype,name,host,...) + local uid if(isnumber(host))then uid=host else local cx cx,uid=pcall(cache.get_index,host,"index") if(not cx)then cx,uid=pcall(cache.get_index,host,"unit_number") if(not cx)then uid=nil end end end + local hdx=uid + if(hdx)then local gc=storage._lib[vtype.."_idx"][hdx] if(gc and name)then gc=gc[name] end if(gc)then return gc end end -- get existing hosted/index vtype + local c=cache[vtype] -- cache["ents"][name]. You can call these manually if you need to for ptrn, surfaces etc. + if(not c)then return end if(name)then c=c[name] if(not c)then return end end -- only menus and vguis typically use names. + local idx=#storage._lib[vtype]+1 + local t={index=idx,name=name,type=vtype,host=host,hostindex=hdx} storage._lib[vtype][idx]=t + if(hdx)then + if(name)then local gc=storage._lib[vtype.."_idx"][hdx] or {} storage._lib[vtype.."_idx"][hdx]=gc gc[t.name]=t + else storage._lib[vtype.."_idx"][hdx]=t + end + end + if(c.raise)then c.raise(t,...) end + if(vtype=="ents")then if(c[host.name] and c[host.name].raise)then c[host.name].raise(t,...) end end + if(vtype=="types")then local htype=(host.is_player() and "player" or host.type) if(c[htype] and c[htype].raise)then c[htype].raise(t,...) end end + + return t +end +function cache.destroy_type(obj,...) local vtype=obj.type + local c=cache[vtype] if(not c)then return end if(obj.name)then c=c[obj.name] if(not c)then return end end + if(c.unraise)then c.unraise(obj,...) end + storage._lib[vtype][obj.index]=nil + if(obj.hostindex)then storage._lib[vtype.."_idx"][obj.hostindex]=nil end +end +function cache.get_type(vtype,name,host) local t=storage._lib[vtype.."_idx"] + if(t)then + local uid if(isnumber(host))then uid=host else local cx cx,uid=pcall(cache.get_index,host,"index") if(not cx)then cx,uid=pcall(cache.get_index,host,"unit_number") if(not cx)then uid=nil end end end + if(uid)then t=t[uid] else t=nil end + end + if(t and name)then t=t[name] end + return t +end +function cache.get_raise_type(vtype,name,host,...) return cache.get_type(vtype,name,host) or cache.raise_type(vtype,name,host,...) end +function cache.get_types(vtype) local t=storage._lib[vtype] return t end + +function cache.destroy(obj,...) return cache.destroy_type(obj,...) end -- This just destroys the cache object, not the actual in-game object. + + +function cache.raise_menu(name,ply,...) return cache.raise_type("menus",name,ply,...) end +function cache.force_menu(name,ply,...) return cache.get_raise_type("menus",name,ply,...) end +function cache.get_menu(name,ply) return cache.get_type("menus",name,ply) end +cache.destroy_menu=cache.destroy + +function cache.raise_vgui(name,menu,...) return cache.raise_type("vguis",name,menu,...) end +function cache.force_vgui(name,menu,...) return cache.get_raise_type("vguis",name,menu,...) end +function cache.get_vgui(name,menu) return cache.get_type("vguis",name,menu) end +cache.destroy_vgui=cache.destroy + +function cache.raise_player(ply,...) return cache.raise_type("players",nil,ply,...) end +function cache.force_player(ply,...) return cache.get_raise_type("players",nil,ply,...) end +function cache.get_player(ply) return cache.get_type("players",nil,ply) end +cache.destroy_player=cache.destroy + +function cache.raise_force(force,...) return cache.raise_type("forces",nil,force,...) end +function cache.force_force(force,...) return cache.get_raise_type("forces",nil,force,...) end +function cache.get_force(force) return cache.get_type("forces",nil,force) end +cache.destroy_force=cache.destroy + +function cache.raise_surface(surface,...) return cache.raise_type("surfaces",nil,surface,...) end +function cache.force_surface(surface,...) return cache.get_raise_type("surfaces",nil,surface,...) end +function cache.get_surface(surface) return cache.get_type("surfaces",nil,surface) end +cache.destroy_surface=cache.destroy + +function cache.raise_unit(unit,...) return cache.raise_type("units",nil,unit,...) end +function cache.force_unit(unit,...) return cache.get_raise_type("units",nil,unit,...) end +function cache.get_unit(unit) return cache.get_type("units",nil,unit) end +cache.destroy_unit=cache.destroy + +function cache.raise_entity(ent,...) return cache.raise_type("ents",nil,ent,...) end +function cache.force_entity(ent,...) return cache.get_raise_type("ents",nil,ent,...) end +function cache.get_entity(ent) return cache.get_type("ents",nil,ent) end +cache.destroy_entity=cache.destroy + + + +function cache.update(ent,vn,...) vn=vn or "update" + local tx=cache.types[ent.type] if(tx and tx[vn])then tx[vn](ent,...) end + local tx=cache.ents[ent.name] if(tx and tx[vn])then tx[vn](ent,...) end + local tx for k,v in pairs(cache.patterns)do if(ent.name:find(k,1,true))then tx=v break end end if(tx and tx[vn])then tx[vn](ent,...) end +end +function cache.updategui(elm,...) local vn="update" if(not isstring(elm))then elm=elm.name end + local tx=cache.vguis[elm.name] if(tx and tx[vn])then tx[vn](elm,...) end + local tx=cache.gtypes[elm.name] if(tx and tx[vn])then tx[vn](elm,...) end + local tx for k,v in pairs(cache.gpatterns)do if(elm.name:find(k,1,true))then tx=v break end end if(tx and tx[vn])then tx[vn](elm,...) end +end +function cache.updatemenu(mn,vn,ev,...) for i,ply in pairs(game.players)do + local menu=cache.get_menu(mn,ply) if(menu)then + cache.call_menu(vn,menu,ev,...) + end +end end + + + +function cache.inject_type(nm,evdata) + local funcs=cache.events[nm] + local defs=cache.events[nm.."_defs"] + local ccls=cache.classes[nm] + + + local ptrn=false + for evtype,vdefs in pairs(defs)do + if(ccls.name)then for tpnm,cls in pairs(cache[ccls.name])do if(cls[evtype])then + for _,def in pairs(vdefs)do evdata[def]=evdata[def] or {} table.insert(evdata[def],{nm=nm,tpnm=tpnm,evtype=evtype,ghost=cls.ghost,clsname=ccls.name,func=funcs[def]}) end + end end end + if(ccls.type)then for tpnm,cls in pairs(cache[ccls.type])do if(cls[evtype])then + for _,def in pairs(vdefs)do evdata[def]=evdata[def] or {} table.insert(evdata[def],{nm=nm,tpnm=tpnm,evtype=evtype,ghost=cls.ghost,clstype=ccls.type,func=funcs[def]}) end + end end end + if(ccls.ptrn)then for tpnm,cls in pairs(cache[ccls.ptrn])do if(cls[evtype])then ptrn=true + for _,def in pairs(vdefs)do evdata[def]=evdata[def] or {} table.insert(evdata[def],{nm=nm,tpnm=tpnm,evtype=evtype,ghost=cls.ghost,clsptrn=ccls.ptrn,func=funcs[def]}) end + end end end + if(ccls.single)then local cls=cache[ccls.single] if(cls[evtype])then + for _,def in pairs(vdefs)do evdata[def]=evdata[def] or {} table.insert(evdata[def],{nm=nm,tpnm=tpnm,evtype=evtype,ghost=cls.ghost,clssingle=ccls.single,func=funcs[def]}) end + end end + end + --if(nm=="players")then error(serpent.block(evdata)) end +end + + +function cache.inject() -- interface with events + local evdata={} for nm in pairs(cache.classes)do cache.inject_type(nm,evdata) end + --error(serpent.block(evdata)) + for def,tbl in pairs(evdata)do + local filters={} + local nmf,tpf,ptf,sgf + --if(events.events_with_filters[def])then + for i,vtbl in pairs(tbl)do + if(vtbl.clsptrn)then ptf=vtbl.func filters=nil + elseif(vtbl.clstype)then tpf=vtbl.func + if(filters)then table.insert(filters,{filter="type",type=vtbl.tpnm}) + if(vtbl.ghost)then table.insert(filters,{filter="ghost_type",type=vtbl.tpnm}) end + end + elseif(vtbl.clsname)then nmf=vtbl.func + if(filters)then table.insert(filters,{filter="name",name=vtbl.tpnm}) + if(vtbl.ghost)then table.insert(filters,{filter="ghost_name",name=vtbl.tpnm}) end + end + elseif(vtbl.clssingle)then sgf=vtbl.func filters=nil + end + end + --end + if(not events.events_with_filters[def])then filters=nil end + + if(nmf)then events.hook(defines.events[def],nmf,filters) end + if(tpf)then events.hook(defines.events[def],tpf,filters) end + if(ptf)then events.hook(defines.events[def],ptf,filters) end + if(sgf)then events.hook(defines.events[def],sgf,filters) end + end +end + +--[[ Unknowns +on_put_item +on_ai_command_completed + +on_difficulty_settings_changed +on_cutscene_waypout_reached + +on_console_command +on_console_chat + +on_chart_tag_added +on_chart_tag_modified +on_chart_tag_removed -- force events + +on_game_created_from_scenario + +on_robot_built_entity +on_robot_built_tile +on_robot_exploded_cliff +on_robot_mined +on_robot_mined_entity +on_robot_mined_tile +on_robot_pre_mined +on_rocket_launch_ordered +on_rocket_launched +on_runtime_mod_setting_changed +on_script_path_request_finished -- pathfinding +on_sector_scanned -- radar +on_string_translated + +on_train_changed_state +on_train_created +on_train_schedule_changed + +on_trigger_fired_artillery + +on_unit_added_to_group +on_unit_group_created +on_unit_removed_from_group +on_biter_base_built + + +on_market_item_purchased + + +]] + + +cache.events.forces={} +function cache.events.forces.on_research_finished(ev) cache.call_force("research_finished",ev) end +function cache.events.forces.on_research_started(ev) cache.call_force("research_started",ev) end +function cache.events.forces.on_technology_effects_reset(ev) cache.call_force("research_reset",ev) end +function cache.events.forces.on_chart_tag_added(ev) cache.call_force("tag_added",ev) end +function cache.events.forces.on_chart_tag_modified(ev) cache.call_force("tag_modified",ev) end +function cache.events.forces.on_chart_tag_removed(ev) cache.call_force("tag_removed",ev) end + +cache.events.forces_defs={ -- Things that specifically are called with a force. Player stuff can be hooked from players. + research_finished={"on_research_finished"}, + research_started={"on_research_started"}, + research_reset={"on_technology_effects_reset"}, +} + +cache.events.ents={} +function cache.events.ents.on_built_entity(ev) cache.call_ents("built",ev) cache.call_ents("create",ev) end +function cache.events.ents.script_raised_built(ev) cache.call_ents("create",ev) end +function cache.events.ents.on_entity_cloned(ev) cache.call_ents("clone",ev) cache.call_ents("create",ev) end +function cache.events.ents.on_robot_built_entity(ev) cache.call_ents("built",ev) cache.call_ents("create",ev) end +function cache.events.ents.script_raised_destroy(ev) cache.call_ents("destroy",ev) end +function cache.events.ents.on_entity_died(ev) cache.call_ents("died",ev) cache.call_ents("destroy",ev) end +function cache.events.ents.on_post_entity_died(ev) cache.call_ents("post_died",ev) end +function cache.events.ents.on_player_mined_entity(ev) cache.call_ents("mined",ev) cache.call_ents("destroy",ev) end +function cache.events.ents.on_robot_mined_entity(ev) cache.call_ents("mined",ev) cache.call_ents("destroy",ev) end +function cache.events.ents.on_player_rotated_entity(ev) cache.call_ents("rotate",ev) end +function cache.events.ents.on_entity_settings_pasted(ev) cache.call_ents("settings_pasted",ev) end +function cache.events.ents.on_pre_entity_settings_pasted(ev) cache.call_ents("pre_settings_pasted",ev) end +function cache.events.ents.on_cancelled_deconstruction(ev) cache.call_ents("cancel_deconstruct",ev) end +function cache.events.ents.on_cancelled_upgrade(ev) cache.call_ents("cancel_upgrade",ev) end +function cache.events.ents.on_marked_for_deconstruction(ev) cache.call_ents("deconstruct",ev) end +function cache.events.ents.on_marked_for_upgrade(ev) cache.call_ents("upgrade",ev) end +function cache.events.ents.on_pre_ghost_deconstructed(ev) cache.call_ents("deconstruct_ghost",ev) end +function cache.events.ents.on_post_entity_died(ev) cache.call_ents("post_died",ev) end +function cache.events.ents.on_mod_item_opened(ev) cache.call_ents("item_menu",ev) end +function cache.events.ents.on_entity_damaged(ev) cache.call_ents("damage",ev) end +function cache.events.ents.on_trigger_created_entity(ev) cache.call_ents("trigger",ev) end +function cache.events.ents.on_entity_spawned(ev) cache.call_ents("spawned",ev) end +function cache.events.ents.on_land_mine_armed(ev) cache.call_ents("mine_armed",ev) end +function cache.events.ents.on_gui_opened(ev) cache.call_ents("gui_opened",ev) end +function cache.events.ents.on_gui_closed(ev) cache.call_ents("gui_closed",ev) end +function cache.events.ents.on_pre_robot_exploded_cliff(ev) cache.call_ents("pre_robot_exploded_cliff",ev) end +function cache.events.ents.on_post_entity_died(ev) cache.call_ents("post_died",ev) end +function cache.events.ents.on_combat_robot_expired(ev) cache.call_ents("robot_expired",ev) end +function cache.events.ents.script_raised_revive(ev) cache.call_ents("create",ev) end +function cache.events.ents.on_entity_renamed(ev) cache.call_ents("rename",ev) end + +cache.events.ents_defs={ + built={"on_built_entity","on_robot_built_entity"}, + create={"on_built_entity","script_raised_built","on_entity_cloned","on_robot_built_entity","script_raised_revive"}, + mined={"on_player_mined_entity","on_robot_mined_entity"}, + rotate={"on_player_rotated_entity"}, + rename={"on_entity_renamed"}, + destroy={"on_player_mined_entity","on_robot_mined_entity","script_raised_destroy","on_entity_died"}, + + died={"on_entity_died"}, + post_died={"on_post_entity_died"}, + + settings_pasted={"on_entity_settings_pasted"}, + pre_settings_pasted={"on_pre_entity_settings_pasted"}, + cancel_deconstruct={"on_cancelled_deconstruction"}, + cancel_upgrade={"on_cancelled_upgrade"}, + deconstruct={"on_marked_for_deconstruction"}, + deconstruct_ghost={"on_pre_ghost_deconstructed"}, + + upgrade={"on_marked_for_upgrade"}, + + gui_opened={"on_gui_opened"}, + gui_closed={"on_gui_closed"}, + + item_menu={"on_mod_item_opened"}, --Called when the player uses the 'Open item GUI' control on an item defined with 'can_be_mod_opened' as true + damage={"on_entity_damaged"}, + trigger={"on_trigger_created_entity"}, + robot_expired={"on_combat_robot_expired"}, + + spawned={"on_entity_spawned"}, + mine_armed={"on_land_mine_armed"}, + + pre_robot_exploded_cliff={"on_pre_robot_exploded_cliff"}, + post_died={"on_post_entity_died"}, +} + + +cache.events.vgui={} +function cache.events.vgui.on_gui_opened(ev) cache.call_vgui("open_menu",ev) end +function cache.events.vgui.on_gui_closed(ev) cache.call_vgui("gui_closed",ev) cache.call_vgui("gui_closed",ev) end +function cache.events.vgui.on_gui_click(ev) cache.call_vgui("click",ev) end +function cache.events.vgui.on_gui_confirmed(ev) cache.call_vgui("confirm",ev) end +function cache.events.vgui.on_gui_text_changed(ev) cache.call_vgui("text_changed",ev) end +function cache.events.vgui.on_gui_selection_state_changed(ev) cache.call_vgui("selection_changed",ev) end +function cache.events.vgui.on_player_display_resolution_changed(ev) cache.call_vgui("on_resolution",ev) end +function cache.events.vgui.on_player_display_scale_changed(ev) cache.call_vgui("on_scale",ev) end +function cache.events.vgui.on_gui_checked_state_changed(ev) cache.call_vgui("on_checked",ev) end +function cache.events.vgui.on_gui_elem_changed(ev) cache.call_vgui("elem_changed",ev) end +function cache.events.vgui.on_gui_location_changed(ev) cache.call_vgui("location_changed",ev) end +function cache.events.vgui.on_gui_selected_tab_changed(ev) cache.call_vgui("tab_changed",ev) end +function cache.events.vgui.on_gui_switch_state_changed(ev) cache.call_vgui("on_switched",ev) end +function cache.events.vgui.on_gui_value_changed(ev) cache.call_vgui("value_changed",ev) end + +cache.events.vgui_defs={ + click={"on_gui_click"}, + open_menu={"on_gui_opened"}, + gui_closed={"on_gui_closed"}, + confirm={"on_gui_confirmed"}, + text_changed={"on_gui_text_changed"}, + selection_changed={"on_gui_selection_state_changed"}, + on_resolution={"on_player_display_resolution_changed"}, + on_scale={"on_player_display_scale_changed"}, + on_checked={"on_gui_checked_state_changed"}, + elem_changed={"on_gui_elem_changed"}, + location_changed={"on_gui_location_changed"}, + tab_changed={"on_gui_selected_tab_changed"}, + on_switched={"on_gui_switch_state_changed"}, + value_changed={"on_gui_value_changed"}, +} + + + +cache.events.surfaces={} +function cache.events.surfaces.on_surface_created(ev) cache.call_surface("create",ev) end +function cache.events.surfaces.on_pre_surface_deleted(ev) cache.call_surface("pre_deleted",ev) end +function cache.events.surfaces.on_pre_surface_cleared(ev) cache.call_surface("pre_cleared",ev) end +function cache.events.surfaces.on_surface_deleted(ev) cache.call_surface("on_deleted",ev) end +function cache.events.surfaces.on_surface_imported(ev) cache.call_surface("import",ev) end +function cache.events.surfaces.on_surface_renamed(ev) cache.call_surface("rename",ev) end +function cache.events.surfaces.on_chunk_generated(ev) cache.call_surface("chunk",ev) end +function cache.events.surfaces.on_chunk_deleted(ev) cache.call_surface("chunk_deleted",ev) end +function cache.events.surfaces.on_pre_chunk_deleted(ev) cache.call_surface("pre_chunk_deleted",ev) end +function cache.events.surfaces.on_chunk_charted(ev) cache.call_surface("chart",ev) end + +cache.events.surfaces_defs={ + create={"on_surface_created"}, + pre_deleted={"on_pre_surface_deleted"}, + pre_cleared={"on_pre_surface_cleared"}, + on_cleared={"on_surface_cleared"}, + on_deleted={"on_surface_deleted"}, + + import={"on_surface_imported"}, + rename={"on_surface_renamed"}, + chunk={"on_chunk_generated"}, + chunk_deleted={"on_chunk_deleted"}, + pre_chunk_deleted={"on_pre_chunk_deleted"}, + + chart={"on_chunk_charted"}, +} + +cache.events.players={} +function cache.events.players.on_player_toggled_alt_mode(ev) cache.call_player("on_alt",ev) end +function cache.events.players.on_player_toggled_map_editor(ev) cache.call_player("on_editor",ev) end +function cache.events.players.on_player_cheat_mode_enabled(ev) cache.call_player("on_cheat",ev) end +function cache.events.players.on_player_cheat_mode_disabled(ev) cache.call_player("on_uncheat",ev) end +function cache.events.players.on_player_driving_changed_state(ev) cache.call_player("on_driving",ev) end +function cache.events.players.on_pickup_item(ev) cache.call_player("on_pickup_item",ev) end +function cache.events.players.on_player_dropped_item(ev) cache.call_player("on_drop_item",ev) end +function cache.events.players.on_player_fast_transferred(ev) cache.call_player("on_fast_transfer",ev) end +function cache.events.players.on_player_gun_inventory_changed(ev) cache.call_player("on_gun_inv",ev) end +function cache.events.players.on_player_ammo_inventory_changed(ev) cache.call_player("on_ammo_changed",ev) end +function cache.events.players.on_player_armor_inventory_changed(ev) cache.call_player("on_armor_changed",ev) end +function cache.events.players.on_player_placed_equipment(ev) cache.call_player("on_equip",ev) end +function cache.events.players.on_player_removed_equipment(ev) cache.call_player("on_dequip",ev) end + +function cache.events.players.on_built_tile(ev) cache.call_player("on_built_tile",ev) end +function cache.events.players.on_built_entity(ev) cache.call_player("on_built",ev) end +function cache.events.players.on_player_changed_position(ev) cache.call_player("on_position",ev) end +function cache.events.players.on_player_changed_surface(ev) cache.call_player("on_surface",ev) end +function cache.events.players.on_character_corpse_expired(ev) cache.call_player("on_corpse_expired",ev) end +function cache.events.players.on_lua_shortcut(ev) cache.call_player("on_shortcut",ev) end +function cache.events.players.on_player_alt_selected_area(ev) cache.call_player("on_alt_select_area",ev) end +function cache.events.players.on_player_deconstructed_area(ev) cache.call_player("on_deconstruct_area",ev) end +function cache.events.players.on_player_selected_area(ev) cache.call_player("on_select_area",ev) end +function cache.events.players.on_player_configured_blueprint(ev) cache.call_player("on_blueprint",ev) end +function cache.events.players.on_player_setup_blueprint(ev) cache.call_player("on_setup_blueprint",ev) end +function cache.events.players.on_selected_entity_changed(ev) cache.call_player("on_selected_entity_changed",ev) end +function cache.events.players.on_player_respawned(ev) cache.call_player("on_respawn",ev) end +function cache.events.players.on_player_created(ev) cache.call_player("on_create",ev) end +function cache.events.players.on_player_joined_game(ev) cache.call_player("on_join",ev) end +function cache.events.players.on_player_banned(ev) cache.call_player("on_banned",ev) end +function cache.events.players.on_player_left_game(ev) cache.call_player("on_left",ev) end +function cache.events.players.on_player_removed(ev) cache.call_player("on_removed",ev) end +function cache.events.players.on_pre_player_left_game(ev) cache.call_player("on_pre_left",ev) end +function cache.events.players.on_pre_player_removed(ev) cache.call_player("on_pre_removed",ev) end +function cache.events.players.on_player_unbanned(ev) cache.call_player("on_unban",ev) end +function cache.events.players.on_player_unmuted(ev) cache.call_player("on_unmute",ev) end +function cache.events.players.on_player_demoted(ev) cache.call_player("on_demoted",ev) end +function cache.events.players.on_player_died(ev) cache.call_player("on_died",ev) end +function cache.events.players.on_pre_player_died(ev) cache.call_player("on_pre_died",ev) end +function cache.events.players.on_player_muted(ev) cache.call_player("on_muted",ev) end +function cache.events.players.on_player_promoted(ev) cache.call_player("on_promoted",ev) end +function cache.events.players.on_player_main_inventory_changed(ev) cache.call_player("on_inventory",ev) end +function cache.events.players.on_player_mined_entity(ev) cache.call_player("on_mined",ev) end +function cache.events.players.on_pre_player_mined_item(ev) cache.call_player("on_pre_mined_item",ev) end +function cache.events.players.on_player_mined_item(ev) cache.call_player("on_mined_item",ev) end +function cache.events.players.on_player_mined_tile(ev) cache.call_player("on_mined_tile",ev) end +function cache.events.players.on_player_cursor_stack_changed(ev) cache.call_player("on_cursor",ev) end +function cache.events.players.on_player_pipette(ev) cache.call_player("on_pipette",ev) end +function cache.events.players.on_player_cancelled_crafting(ev) cache.call_player("on_cancel_craft",ev) end +function cache.events.players.on_pre_player_crafted_item(ev) cache.call_player("on_pre_craft",ev) end +function cache.events.players.on_player_crafted_item(ev) cache.call_player("on_craft",ev) end +function cache.events.players.on_player_repaired_entity(ev) cache.call_player("on_repair",ev) end +function cache.events.players.on_player_rotated_entity(ev) cache.call_player("on_rotate",ev) end +function cache.events.players.on_player_trash_inventory_changed(ev) cache.call_player("on_trash_changed",ev) end +function cache.events.players.on_player_used_capsule(ev) cache.call_player("on_capsule",ev) end + + +cache.events.players_defs={ + + on_alt={"on_player_toggled_alt_mode"}, + on_editor={"on_player_toggled_map_editor"}, + + on_cheat={"on_player_cheat_mode_enabled"}, + on_uncheat={"on_player_cheat_mode_disabled"}, + + on_driving={"on_player_driving_changed_state"}, + + on_pickup_item={"on_picked_up_item"}, + on_drop_item={"on_player_dropped_item"}, + + on_fast_transfer={"on_player_fast_transferred"}, + on_gun_inv={"on_player_gun_inventory_changed"}, + on_ammo_changed={"on_player_ammo_inventory_changed"}, + on_armor_changed={"on_player_armor_inventory_changed"}, + on_equip={"on_player_placed_equipment"}, + on_dequip={"on_player_removed_equipment"}, + + on_built_tile={"on_player_built_tile"}, + on_built={"on_entity_built"}, + + on_position={"on_player_changed_position"}, + on_surface={"on_player_changed_surface"}, + + on_corpse_expired={"on_character_corpse_expired"}, + + on_shortcut={"on_lua_shortcut"}, + on_alt_select_area={"on_player_alt_selected_area"}, + on_deconstruct_area={"on_player_deconstructed_area"}, + on_select_area={"on_player_selected_area"}, + + + on_blueprint={"on_player_configured_blueprint"}, + on_setup_blueprint={"on_player_setup_blueprint"}, + + on_select={"on_selected_entity_changed"}, + + on_respawn={"on_player_respawned"}, + on_create={"on_player_created"}, + on_join={"on_player_joined_game"}, + + on_banned={"on_player_banned"}, + on_left={"on_player_left_game"}, + on_removed={"on_player_removed"}, + on_pre_left={"on_pre_player_left_game"}, + on_pre_removed={"on_pre_player_removed"}, + + on_unban={"on_player_unbanned"}, + on_unmute={"on_player_unmuted"}, + on_demote={"on_player_demoted"}, + + on_died={"on_player_died"}, + on_pre_died={"on_pre_player_died"}, + + on_muted={"on_player_muted"}, + on_promoted={"on_player_promoted"}, + + on_inventory={"on_player_main_inventory_changed"}, + on_mined={"on_player_mined_entity"}, + on_pre_mined_item={"on_pre_player_mined_item"}, + on_mined_item={"on_player_mined_item"}, + on_mined_tile={"on_player_mined_tile"}, + + on_cursor={"on_player_cursor_stack_changed"}, + on_pipette={"on_player_pipette"}, + + on_cancel_craft={"on_player_cancelled_crafting"}, + on_pre_craft={"on_pre_player_crafted_item"}, + on_craft={"on_player_crafted_item"}, + + on_repair={"on_player_repaired_entity"}, + on_rotate={"on_player_rotated_entity"}, + + on_trash_changed={"on_player_trash_inventory_changed"}, + + on_capsule={"on_player_used_capsule"}, + +} +cache.events.menus={} +cache.events.menus_defs={ +} + return cache \ No newline at end of file diff --git a/lib/lib_control_grid.lua b/lib/lib_control_grid.lua index 3753d20..0c42c01 100644 --- a/lib/lib_control_grid.lua +++ b/lib/lib_control_grid.lua @@ -1,40 +1,40 @@ ---[[------------------------------------- - -Author: Pyro-Fire -https://patreon.com/pyrofire - -Script: lib_grid.lua -Purpose: grid manager stuff - ------ - -Copyright (c) 2019 Pyro-Fire - -I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. - -Permission to use, copy, modify, and/or distribute this software for any -purpose without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------- - -Written using Microsoft Notepad. -IDE's are for children. - -How to notepad like a pro: -ctrl+f = find -ctrl+h = find & replace -ctrl+g = show/jump to line (turn off wordwrap n00b) - -Status bar wastes screen space, don't use it. - -Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. - -]]--------------------------------------- +--[[------------------------------------- + +Author: Pyro-Fire +https://patreon.com/pyrofire + +Script: lib_grid.lua +Purpose: grid manager stuff + +----- + +Copyright (c) 2019 Pyro-Fire + +I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. + +Permission to use, copy, modify, and/or distribute this software for any +purpose without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------ + +Written using Microsoft Notepad. +IDE's are for children. + +How to notepad like a pro: +ctrl+f = find +ctrl+h = find & replace +ctrl+g = show/jump to line (turn off wordwrap n00b) + +Status bar wastes screen space, don't use it. + +Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. + +]]--------------------------------------- diff --git a/lib/lib_control_logic.lua b/lib/lib_control_logic.lua index 57f5c22..5219e20 100644 --- a/lib/lib_control_logic.lua +++ b/lib/lib_control_logic.lua @@ -1,55 +1,55 @@ ---[[------------------------------------- - -Author: Pyro-Fire -https://patreon.com/pyrofire - -Script: lib_control_logic.lua -Purpose: control stage logic - ------ - -Copyright (c) 2019 Pyro-Fire - -I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. - -Permission to use, copy, modify, and/or distribute this software for any -purpose without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------- - -Written using Microsoft Notepad. -IDE's are for children. - -How to notepad like a pro: -ctrl+f = find -ctrl+h = find & replace -ctrl+g = show/jump to line (turn off wordwrap n00b) - -Status bar wastes screen space, don't use it. - -Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. - -]]--------------------------------------- - - - ---[[ Unused - - -function warptorio.GetFastestLoader() -- currently unused - if(warptorio.FastestLoader)then return warptorio.FastestLoader end if(true)then return "express-loader" end - local ld={} local topspeed=game.entity_prototypes["express-loader"].belt_speed local top="express-loader" - for k,v in pairs(game.entity_prototypes)do if(v.type=="loader")then table.insert(ld,v) end end - for k,v in pairs(ld)do if(not v.name:match("warptorio") and not v.name:match("mini") and v.belt_speed>=topspeed)then topspeed=v.belt_speed top=v.name end end - warptorio.FastestLoader=top return top -end - +--[[------------------------------------- + +Author: Pyro-Fire +https://patreon.com/pyrofire + +Script: lib_control_logic.lua +Purpose: control stage logic + +----- + +Copyright (c) 2019 Pyro-Fire + +I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. + +Permission to use, copy, modify, and/or distribute this software for any +purpose without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------ + +Written using Microsoft Notepad. +IDE's are for children. + +How to notepad like a pro: +ctrl+f = find +ctrl+h = find & replace +ctrl+g = show/jump to line (turn off wordwrap n00b) + +Status bar wastes screen space, don't use it. + +Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. + +]]--------------------------------------- + + + +--[[ Unused + + +function warptorio.GetFastestLoader() -- currently unused + if(warptorio.FastestLoader)then return warptorio.FastestLoader end if(true)then return "express-loader" end + local ld={} local topspeed=game.entity_prototypes["express-loader"].belt_speed local top="express-loader" + for k,v in pairs(game.entity_prototypes)do if(v.type=="loader")then table.insert(ld,v) end end + for k,v in pairs(ld)do if(not v.name:match("warptorio") and not v.name:match("mini") and v.belt_speed>=topspeed)then topspeed=v.belt_speed top=v.name end end + warptorio.FastestLoader=top return top +end + ]] \ No newline at end of file diff --git a/lib/lib_data.lua b/lib/lib_data.lua index b2bce1b..a6a7fb3 100644 --- a/lib/lib_data.lua +++ b/lib/lib_data.lua @@ -1,219 +1,219 @@ ---[[------------------------------------- - -Author: Pyro-Fire -https://patreon.com/pyrofire - -Script: lib_data.lua -Purpose: data library - ------ - -Copyright (c) 2019 Pyro-Fire - -I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. - -Permission to use, copy, modify, and/or distribute this software for any -purpose without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------- - -Written using Microsoft Notepad. -IDE's are for children. - -How to notepad like a pro: -ctrl+f = find -ctrl+h = find & replace -ctrl+g = show/jump to line (turn off wordwrap n00b) - -Status bar wastes screen space, don't use it. - -Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. - -]]--------------------------------------- - ---[[ Prototype/data stage libraries ]]-- - -local proto={} - - - - ---[[ Prototyping Data Stuff ]]-- - - - --- All the different things an item can be --- See also data.raw["item-subgroup"][k].name - -proto.ItemGroups={"item","tool","gun","ammo","capsule","armor","repair-tool","car","module","locomotive","cargo-wagon","artillery-wagon","fluid-wagon","rail-planner","item-with-entity-data"} - --- All the different things an item can be place_result'd as -proto.PlacementGroups={ -"accumulator","ammo-turret","arithmetic-combinator","artillery-turret","artillery-wagon","assembling-machine", -"beacon","boiler", -"car","cargo-wagon","character","constant-combinator","container", -"decider-combinator", -"electric-energy-interface","electric-turret","electric-pole", -"fluid-turret","fluid-wagon","furnace", -"gate","generator", -"heat-pipe", -"inserter", -"lab","loader","logistic-container","logistic-robot", -"mining-drill", -"offshore-pump", -"pipe","pipe-to-ground","power-switch","programmable-speaker","pump", -"radar","reactor","roboport","rocket-silo", -"simple-entity","simple-entity-with-force","simple-entity-with-owner","solar-panel","splitter","storage-tank", -"train-stop","transport-belt", -"underground-belt", -"wall", -} - -function proto.Recache() proto._items=nil proto._placeables=nil proto._labpacks=nil proto._used=nil proto._furnacecat=nil end - -function proto.CacheItems() local t={} for k,v in pairs(proto.ItemGroups)do for x,y in pairs(data.raw[v])do t[y.name]=y end end proto._items=t return t end -function proto.Items(b) return (proto._items and (not b and proto._items or proto.CacheItems()) or proto.CacheItems()) end -function proto.RawItem(n,b) return proto.Items(b)[n] end - -function proto.CacheLabPacks() local tx={} for k,v in pairs(data.raw.lab)do local vin=v.inputs for i,e in pairs(vin)do tx[e]=e end end proto._labpacks=tx return tx end -function proto.GetLabPacks(b) return (proto._labpacks and (not b and proto._labpacks or proto.CacheLabPacks()) or proto.CacheLabPacks()) end -function proto.LabPack(n,b) return proto.GetLabPacks(b)[n] end - -function proto.CachePlaceables() local t={} for k,v in pairs(proto.PlacementGroups)do for x,y in pairs(data.raw[v])do t[y.name]=y end end proto._placeables=t return t end -function proto.Placeables(b) return (proto._placeables and (not b and proto._placeables or proto.CachePlaceables()) or proto.CachePlaceables()) end -function proto.RawPlaceable(n,b) return proto.Placeables(b)[n] end -- place_result_entity -proto.PlaceResultEntity=proto.RawPlaceable --alias - -function proto.CacheUsedRecipes() local t={} - for k,v in pairs(data.raw.technology)do local fx=proto.TechEffects(v) for i,rcp in pairs(fx.recipes)do t[rcp]=true end end - for k,v in pairs(data.raw.recipe)do if(proto.IsEnabled(v))then t[v.name]=true end end -proto._used=t return t end -function proto.UsedRecipes() return (proto._used and (not b and proto._used or proto.CacheUsedRecipes()) or proto.CacheUsedRecipes()) end -function proto.UsedRecipe(n,b) return proto.UsedRecipes(b)[n] end -function proto.CountUsedRecipes() return table_size(proto.UsedRecipes()) end -function proto.CountUnsedRecipes() return table_size(data.raw.recipe)-proto.CountUsedRecipes() end - -function proto.IsAutoplaceControl(t) local dra=data.raw["autoplace-control"] if(dra[t.name] or dra[t.type] or (t.autoplace and t.autoplace.control))then return true end return false end - -function proto.HasFluidbox(t) return t.fluid_box or t.fluid_boxes or t.input_fluid_box or t.output_fluid_box end - -function proto.CacheFurnaceCats() local t={} for k,v in pairs(data.raw.furnace)do for cc in pairs(proto.CraftingCategories(v))do t[cc]=cc end end proto._furnacecat=t return t end -function proto.FurnaceCats(b) return (proto._furnacecat and (not b and proto._furnacecat or proto.CacheFurnaceCats()) or proto.CacheFurnaceCats()) end -function proto.FurnaceCat(n,b) return proto.FurnaceCats(b)[n] end - -function proto.Name(t) return (isstring(t) and t or (t.name and t.name or (isstring(t[1]) and t[1] or false))) end - -function proto.Fluids() return data.raw.fluid end -function proto.Recipes() return data.raw.recipe end -function proto.Techs() return data.raw.technology end - -function proto.IsEnabled(v) local c=false - if(tostring(v.enabled)=="true")then c=true end - if(v.normal and tostring(v.normal.enabled)=="true")then c=true end - if(v.expensive and tostring(v.expensive.enabled)=="true")then c=true end - --if(v.enabled==nil and (not v.normal or v.normal and v.normal.enabled==nil) and (not v.expensive or v.expensive and v.expensive.enabled==nil))then return true end - return c -end -function proto.IsDisabled(v) local c=false - if(tostring(v.enabled)=="false")then c=true end - if(v.normal and tostring(v.normal.enabled)=="false")then c=true end - if(v.expensive and tostring(v.expensive.enabled)=="false")then c=true end - --if(v.enabled==nil and (not v.normal or v.normal and v.normal.enabled==nil) and (not v.expensive or v.expensive and v.expensive.enabled==nil))then return true end - return c -end - -proto.IsTechnologyEnabled=proto.IsEnabled -- alias - -function proto.IsHidden(v) - if(tostring(v.hidden)=="true")then return true end - if(v.normal and tostring(v.normal.hidden)=="true")then return true end - if(v.expensive and tostring(v.expensive.hidden)=="true")then return true end - return false -end - - - -proto.Difficulties={[0]="standard",[1]="normal",[2]="expensive"} -function proto.Normal(t) local v=t if(t.normal)then v=t.normal elseif(t.expensive)then v=t.expensive end return v end -function proto.FetchDifficultyLayer(tx,seek) - local t=tx if(t)then for k,v in pairs(seek)do if(t[v])then return t,0 end end end - local t=tx.normal if(t)then for k,v in pairs(seek)do if(t[v])then return t,1 end end end - local t=tx.expensive if(t)then for k,v in pairs(seek)do if(t[v])then return t,2 end end end -end - -function proto.Result(t) if(t[1] and t[2])then return {type="item",name=t[1],amount=t[2]} else return t end end -function proto.Results(tx) local t,dfc=proto.FetchDifficultyLayer(tx,{"result","results"}) if(t)then if(t.results)then rs=t.results else rs={{t.result,t.result_count or 1}} end end return rs,dfc end -function proto.Ingredient(t) return proto.Result(t) end -function proto.Ingredients(tx) local t,dfc=proto.FetchDifficultyLayer(tx,{"ingredients"}) return (t and t.ingredients),dfc end - --- Fetch the raw item/object/etc -function proto.CraftingObject(rs) local raw=proto.RawItem(rs.name) return raw or data.raw.fluid[rs.name] end -function proto.ResultObject(t) local rs=proto.Result(t) return proto.CraftingObject(rs) end -function proto.IngredientObject(t) local rs=proto.Ingredient(t) return proto.CraftingObject(rs) end - -function proto.TechBottles(tz) local t,dfc=proto.FetchDifficultyLayer(tz,{"unit"}) if(not t or not t.unit or not t.unit.ingredients)then return end - local tx={} for k,v in pairs(t.unit.ingredients)do local rs=proto.Ingredient(v) tx[rs.name]=rs.name end return tx -end -function proto.LoopTech(n,p) p=p or {} p[n]=true local r=data.raw.technology[n] for k,v in pairs(r.prerequisites or {})do if(not p[v])then proto.LoopTech(v,p) end end return p end -function proto.RecursiveTechBottles(g) local t={} for n in pairs(proto.LoopTech(g.name))do local c,u=data.raw.technology[n] u=proto.TechBottles(c) for k,v in pairs(u)do t[v]=true end end return t end - -function proto.TechEffects(g) local t={recipes={},items={},c=0} if(not g.effects)then return t end - for k,v in pairs(g.effects)do local x=v.type if(x=="unlock-recipe")then table.insert(t.recipes,v.recipe) t.c=t.c+1 elseif(x=="give-item")then table.insert(x.items,v.item) t.c=t.c+1 end end - return t -end - -function proto.CraftingCategories(t) if(isstring(t))then return {t} end return t end -function proto.FuelCategories(t) local x - if(t.fuel_category)then x={} table.insert(x,t.fuel_category) end - if(t.fuel_categories)then x=x or {} for k,v in pairs(t.fuel_categories)do table.insertExclusive(x,v) end end - return x -end - -function proto.MinableResults(tx) - return {} -end - -function proto.GetRawAutoplacers(raw,vfunc) local t={} -- data.raw.resource,data.raw.tree vfunc(v) return true_is_valid end - for n,rsc in pairs(raw)do if(rsc.minable and proto.IsAutoplaceControl(rsc) and (not vfunc or (vfunc and vfunc(rsc))) )then - local rs=proto.Results(rsc.minable) - if(rs)then for k,v in pairs(rs)do local rso=proto.ResultObject(v) - if(not t[rso.name])then t[rso.name]={type=(rso.type~="fluid" and "item" or "fluid"),name=rso.name,proto=rsc} end - end end - end end - return t -end -function proto.GetRawResources() return proto.GetRawAutoplacers(data.raw.resource) end -function proto.GetRawTrees() return proto.GetRawAutoplacers(data.raw.tree) end -function proto.GetRawRocks() return proto.GetRawAutoplacers(data.raw["simple-entity"],function(v) return v.count_as_rock_for_filtered_deconstruction end) end -function proto.GetRaw() local t={} for k,v in pairs({proto.GetRawResources(),proto.GetRawTrees(),proto.GetRawRocks()})do for i,e in pairs(v)do table.insertExclusive(t,e) end end return t end - - -function proto.Copy(a,b,x) local t=table.deepcopy(data.raw[a][b]) if(x)then table.deepmerge(t,x) end return t end - -function proto.ExtendBlankEntityItems(ent) - local rcp=proto.Copy("recipe","nuclear-reactor") - rcp.enabled=false rcp.name=ent.name rcp.ingredients={{"steel-plate",1}} rcp.result=ent.name - - local item=proto.Copy("item","nuclear-reactor") - item.name=ent.name item.place_result=ent.name - data:extend{rcp,item} -end - - -proto.VanillaPacks={red="automation-science-pack",green="logistic-science-pack",blue="chemical-science-pack",black="military-science-pack", - purple="production-science-pack",yellow="utility-science-pack",white="space-science-pack"} - -function proto.SciencePacks(x) local t={} for k,v in pairs(x)do table.insert(t,{proto.VanillaPacks[k],v}) end return t end -function proto.ExtendTech(t,d,s) local x=table.merge(t,d) if(s)then x.unit.ingredients=proto.SciencePacks(s) end data:extend{x} return x end - -function proto.Icons(p) if(p.icons)then return p.icons end if(p.icon)then return {{icon=p.icon,icon_size=p.icon_size}} end end - +--[[------------------------------------- + +Author: Pyro-Fire +https://patreon.com/pyrofire + +Script: lib_data.lua +Purpose: data library + +----- + +Copyright (c) 2019 Pyro-Fire + +I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. + +Permission to use, copy, modify, and/or distribute this software for any +purpose without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------ + +Written using Microsoft Notepad. +IDE's are for children. + +How to notepad like a pro: +ctrl+f = find +ctrl+h = find & replace +ctrl+g = show/jump to line (turn off wordwrap n00b) + +Status bar wastes screen space, don't use it. + +Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. + +]]--------------------------------------- + +--[[ Prototype/data stage libraries ]]-- + +local proto={} + + + + +--[[ Prototyping Data Stuff ]]-- + + + +-- All the different things an item can be +-- See also data.raw["item-subgroup"][k].name + +proto.ItemGroups={"item","tool","gun","ammo","capsule","armor","repair-tool","car","module","locomotive","cargo-wagon","artillery-wagon","fluid-wagon","rail-planner","item-with-entity-data"} + +-- All the different things an item can be place_result'd as +proto.PlacementGroups={ +"accumulator","ammo-turret","arithmetic-combinator","artillery-turret","artillery-wagon","assembling-machine", +"beacon","boiler", +"car","cargo-wagon","character","constant-combinator","container", +"decider-combinator", +"electric-energy-interface","electric-turret","electric-pole", +"fluid-turret","fluid-wagon","furnace", +"gate","generator", +"heat-pipe", +"inserter", +"lab","loader","logistic-container","logistic-robot", +"mining-drill", +"offshore-pump", +"pipe","pipe-to-ground","power-switch","programmable-speaker","pump", +"radar","reactor","roboport","rocket-silo", +"simple-entity","simple-entity-with-force","simple-entity-with-owner","solar-panel","splitter","storage-tank", +"train-stop","transport-belt", +"underground-belt", +"wall", +} + +function proto.Recache() proto._items=nil proto._placeables=nil proto._labpacks=nil proto._used=nil proto._furnacecat=nil end + +function proto.CacheItems() local t={} for k,v in pairs(proto.ItemGroups)do for x,y in pairs(data.raw[v])do t[y.name]=y end end proto._items=t return t end +function proto.Items(b) return (proto._items and (not b and proto._items or proto.CacheItems()) or proto.CacheItems()) end +function proto.RawItem(n,b) return proto.Items(b)[n] end + +function proto.CacheLabPacks() local tx={} for k,v in pairs(data.raw.lab)do local vin=v.inputs for i,e in pairs(vin)do tx[e]=e end end proto._labpacks=tx return tx end +function proto.GetLabPacks(b) return (proto._labpacks and (not b and proto._labpacks or proto.CacheLabPacks()) or proto.CacheLabPacks()) end +function proto.LabPack(n,b) return proto.GetLabPacks(b)[n] end + +function proto.CachePlaceables() local t={} for k,v in pairs(proto.PlacementGroups)do for x,y in pairs(data.raw[v])do t[y.name]=y end end proto._placeables=t return t end +function proto.Placeables(b) return (proto._placeables and (not b and proto._placeables or proto.CachePlaceables()) or proto.CachePlaceables()) end +function proto.RawPlaceable(n,b) return proto.Placeables(b)[n] end -- place_result_entity +proto.PlaceResultEntity=proto.RawPlaceable --alias + +function proto.CacheUsedRecipes() local t={} + for k,v in pairs(data.raw.technology)do local fx=proto.TechEffects(v) for i,rcp in pairs(fx.recipes)do t[rcp]=true end end + for k,v in pairs(data.raw.recipe)do if(proto.IsEnabled(v))then t[v.name]=true end end +proto._used=t return t end +function proto.UsedRecipes() return (proto._used and (not b and proto._used or proto.CacheUsedRecipes()) or proto.CacheUsedRecipes()) end +function proto.UsedRecipe(n,b) return proto.UsedRecipes(b)[n] end +function proto.CountUsedRecipes() return table_size(proto.UsedRecipes()) end +function proto.CountUnsedRecipes() return table_size(data.raw.recipe)-proto.CountUsedRecipes() end + +function proto.IsAutoplaceControl(t) local dra=data.raw["autoplace-control"] if(dra[t.name] or dra[t.type] or (t.autoplace and t.autoplace.control))then return true end return false end + +function proto.HasFluidbox(t) return t.fluid_box or t.fluid_boxes or t.input_fluid_box or t.output_fluid_box end + +function proto.CacheFurnaceCats() local t={} for k,v in pairs(data.raw.furnace)do for cc in pairs(proto.CraftingCategories(v))do t[cc]=cc end end proto._furnacecat=t return t end +function proto.FurnaceCats(b) return (proto._furnacecat and (not b and proto._furnacecat or proto.CacheFurnaceCats()) or proto.CacheFurnaceCats()) end +function proto.FurnaceCat(n,b) return proto.FurnaceCats(b)[n] end + +function proto.Name(t) return (isstring(t) and t or (t.name and t.name or (isstring(t[1]) and t[1] or false))) end + +function proto.Fluids() return data.raw.fluid end +function proto.Recipes() return data.raw.recipe end +function proto.Techs() return data.raw.technology end + +function proto.IsEnabled(v) local c=false + if(tostring(v.enabled)=="true")then c=true end + if(v.normal and tostring(v.normal.enabled)=="true")then c=true end + if(v.expensive and tostring(v.expensive.enabled)=="true")then c=true end + --if(v.enabled==nil and (not v.normal or v.normal and v.normal.enabled==nil) and (not v.expensive or v.expensive and v.expensive.enabled==nil))then return true end + return c +end +function proto.IsDisabled(v) local c=false + if(tostring(v.enabled)=="false")then c=true end + if(v.normal and tostring(v.normal.enabled)=="false")then c=true end + if(v.expensive and tostring(v.expensive.enabled)=="false")then c=true end + --if(v.enabled==nil and (not v.normal or v.normal and v.normal.enabled==nil) and (not v.expensive or v.expensive and v.expensive.enabled==nil))then return true end + return c +end + +proto.IsTechnologyEnabled=proto.IsEnabled -- alias + +function proto.IsHidden(v) + if(tostring(v.hidden)=="true")then return true end + if(v.normal and tostring(v.normal.hidden)=="true")then return true end + if(v.expensive and tostring(v.expensive.hidden)=="true")then return true end + return false +end + + + +proto.Difficulties={[0]="standard",[1]="normal",[2]="expensive"} +function proto.Normal(t) local v=t if(t.normal)then v=t.normal elseif(t.expensive)then v=t.expensive end return v end +function proto.FetchDifficultyLayer(tx,seek) + local t=tx if(t)then for k,v in pairs(seek)do if(t[v])then return t,0 end end end + local t=tx.normal if(t)then for k,v in pairs(seek)do if(t[v])then return t,1 end end end + local t=tx.expensive if(t)then for k,v in pairs(seek)do if(t[v])then return t,2 end end end +end + +function proto.Result(t) if(t[1] and t[2])then return {type="item",name=t[1],amount=t[2]} else return t end end +function proto.Results(tx) local t,dfc=proto.FetchDifficultyLayer(tx,{"result","results"}) if(t)then if(t.results)then rs=t.results else rs={{t.result,t.result_count or 1}} end end return rs,dfc end +function proto.Ingredient(t) return proto.Result(t) end +function proto.Ingredients(tx) local t,dfc=proto.FetchDifficultyLayer(tx,{"ingredients"}) return (t and t.ingredients),dfc end + +-- Fetch the raw item/object/etc +function proto.CraftingObject(rs) local raw=proto.RawItem(rs.name) return raw or data.raw.fluid[rs.name] end +function proto.ResultObject(t) local rs=proto.Result(t) return proto.CraftingObject(rs) end +function proto.IngredientObject(t) local rs=proto.Ingredient(t) return proto.CraftingObject(rs) end + +function proto.TechBottles(tz) local t,dfc=proto.FetchDifficultyLayer(tz,{"unit"}) if(not t or not t.unit or not t.unit.ingredients)then return end + local tx={} for k,v in pairs(t.unit.ingredients)do local rs=proto.Ingredient(v) tx[rs.name]=rs.name end return tx +end +function proto.LoopTech(n,p) p=p or {} p[n]=true local r=data.raw.technology[n] for k,v in pairs(r.prerequisites or {})do if(not p[v])then proto.LoopTech(v,p) end end return p end +function proto.RecursiveTechBottles(g) local t={} for n in pairs(proto.LoopTech(g.name))do local c,u=data.raw.technology[n] u=proto.TechBottles(c) for k,v in pairs(u)do t[v]=true end end return t end + +function proto.TechEffects(g) local t={recipes={},items={},c=0} if(not g.effects)then return t end + for k,v in pairs(g.effects)do local x=v.type if(x=="unlock-recipe")then table.insert(t.recipes,v.recipe) t.c=t.c+1 elseif(x=="give-item")then table.insert(x.items,v.item) t.c=t.c+1 end end + return t +end + +function proto.CraftingCategories(t) if(isstring(t))then return {t} end return t end +function proto.FuelCategories(t) local x + if(t.fuel_category)then x={} table.insert(x,t.fuel_category) end + if(t.fuel_categories)then x=x or {} for k,v in pairs(t.fuel_categories)do table.insertExclusive(x,v) end end + return x +end + +function proto.MinableResults(tx) + return {} +end + +function proto.GetRawAutoplacers(raw,vfunc) local t={} -- data.raw.resource,data.raw.tree vfunc(v) return true_is_valid end + for n,rsc in pairs(raw)do if(rsc.minable and proto.IsAutoplaceControl(rsc) and (not vfunc or (vfunc and vfunc(rsc))) )then + local rs=proto.Results(rsc.minable) + if(rs)then for k,v in pairs(rs)do local rso=proto.ResultObject(v) + if(not t[rso.name])then t[rso.name]={type=(rso.type~="fluid" and "item" or "fluid"),name=rso.name,proto=rsc} end + end end + end end + return t +end +function proto.GetRawResources() return proto.GetRawAutoplacers(data.raw.resource) end +function proto.GetRawTrees() return proto.GetRawAutoplacers(data.raw.tree) end +function proto.GetRawRocks() return proto.GetRawAutoplacers(data.raw["simple-entity"],function(v) return v.count_as_rock_for_filtered_deconstruction end) end +function proto.GetRaw() local t={} for k,v in pairs({proto.GetRawResources(),proto.GetRawTrees(),proto.GetRawRocks()})do for i,e in pairs(v)do table.insertExclusive(t,e) end end return t end + + +function proto.Copy(a,b,x) local t=table.deepcopy(data.raw[a][b]) if(x)then table.deepmerge(t,x) end return t end + +function proto.ExtendBlankEntityItems(ent) + local rcp=proto.Copy("recipe","nuclear-reactor") + rcp.enabled=false rcp.name=ent.name rcp.ingredients={{"steel-plate",1}} rcp.result=ent.name + + local item=proto.Copy("item","nuclear-reactor") + item.name=ent.name item.place_result=ent.name + data:extend{rcp,item} +end + + +proto.VanillaPacks={red="automation-science-pack",green="logistic-science-pack",blue="chemical-science-pack",black="military-science-pack", + purple="production-science-pack",yellow="utility-science-pack",white="space-science-pack"} + +function proto.SciencePacks(x) local t={} for k,v in pairs(x)do table.insert(t,{proto.VanillaPacks[k],v}) end return t end +function proto.ExtendTech(t,d,s) local x=table.merge(t,d) if(s)then x.unit.ingredients=proto.SciencePacks(s) end data:extend{x} return x end + +function proto.Icons(p) if(p.icons)then return p.icons end if(p.icon)then return {{icon=p.icon,icon_size=p.icon_size}} end end + return proto \ No newline at end of file diff --git a/lib/lib_data_logic.lua b/lib/lib_data_logic.lua index 90543ab..b3fb802 100644 --- a/lib/lib_data_logic.lua +++ b/lib/lib_data_logic.lua @@ -1,517 +1,517 @@ ---[[------------------------------------- - -Author: Pyro-Fire -https://patreon.com/pyrofire - -Script: lib_data_logic.lua -Purpose: data stage logic - ------ - -Copyright (c) 2019 Pyro-Fire - -I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. - -Permission to use, copy, modify, and/or distribute this software for any -purpose without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------- - -Written using Microsoft Notepad. -IDE's are for children. - -How to notepad like a pro: -ctrl+f = find -ctrl+h = find & replace -ctrl+g = show/jump to line (turn off wordwrap n00b) - -Status bar wastes screen space, don't use it. - -Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. - -]]--------------------------------------- - - - -local logic={} -logic.loading=true - -function logic.seed(s) - local n=tonumber(s) if(tostring(n)==s)then math.randomseed(n) return n end -- its just a number - n=0 for i=1,string.len(s),1 do n=n+string.byte(s:sub(i,i)) end - math.randomseed(n*24) for i=1,n,1 do local x=math.random() end - return n -end - --- The original hand & starting conditions of the logic system -logic.origin={} local origin=logic.origin - --- Prototype types with their logic functions -logic.ent={} - --- The items, fluids, recipes, ents and everything and stuff currently in our hand & their logical status -logic.hand={} local hand=logic.hand -hand.recipes={} -- recipes in crafting menu -hand.recipescan={} -- recipes that have their item and entity results pushed to hand -hand.reciperead={} -- recipes that have had ingredients read -hand.techs={} -- technologies that we are able to finish thanks to labs, bottles etc -hand.techscan={} -- technologies that have been scanned and effects pushed to hand (recipes etc) aka we have "researched" this technology. -hand.ents={} -- Entities that we can place in the world -hand.entscan={} -- "usable" entities - we can fuel/operate them because we have neccessary items e.g. pipes needed for machines with fluidboxes -hand.items={} -- accessible and craftable items -hand.itemscan={} -- Items that have already been scanned and have fully pushed all potential uses -hand.fluids={} - -hand.labpacks={} -- Science pack items (that are in hand) that we can put into a lab (if we have a labbable slot for it). -hand.labslots={} -- Labbable science packs. - --- Flags, e.g. has a power source, has power pole, has belts etc -hand.void=true -- void power -hand.power=false -hand.pole=false -hand.pipes=false -hand.pipe_to_ground=false -hand.belts=false -hand.underground_belts=false -hand.splitters=false -hand.inserters=false -hand.drill=false -hand.fluid_drill=false -- can be true for a drill accepting all fluids, or a table of drills with filtered fluidboxes -hand.rocket_silo=false -- Has a thing capable of launching items for rocket_launch_product - -hand.heat=0 -- max heat capacity - -hand.craft_cats={} -hand.burner_cats={} -- [cat]=n with n=burnt_inventory_size. Burnable Categories that we can burn, and their burnt inventory size. -hand.burnables={} -- Items that can be put in a burner -hand.resource_cats={} -hand.resource_scan={} -- Resources that have been scanned & added to our hand, e.g. iron-ore, but not uranium ore because it waits for sulfuric acid. [name]=0/1 automation -hand.fuel_types={} - -logic.ignored={} -logic.is_bobs=false -logic.spaceblock=false -function logic.bobs(b) if(b)then logic.is_bobs=b end return logic.is_bobs end -function logic.Ignore(rcpname) logic.ignored[rcpname]=true end -function logic.ShouldIgnore(rcpname,rcp) - if(rcp and rcp.subgroup)then - if(logic.spaceblock and rcp.subgroup:find("spaceblock"))then return true end - end - return rcpname:find("void") or rcpname:find("converter") or logic.ignored[rcpname] - --or (logic.bobs() and rcpname:find("alien")) -end -function logic.Ignoring(rcp) return logic.ShouldIgnore(rcp.name,rcp) end - -logic.seablock=false -logic.SeablockScience={ - ["angels-ore3"]="sb-angelsore3-tool", - ["basic-circuit-board"]="sb-basic-circuit-board-tool", - ["algae-green"]="sb-algae-green-tool", - ["sulfur"]="sb-sulfur-tool", - ["lab"]="sb-lab-tool", -} - --- Other initial conditions -function logic.Seablock() hand.pole=true hand.power=true hand.pipes=true hand.belts=true hand.inserters=true - -- And push some entities too? - logic.seablock=true - logic.bobs(true) - logic.PushItem(data.raw.item["stone-furnace"],0,true) -- inv furnace - logic.PushItem(data.raw.item["burner-ore-crusher"],0,true) - logic.PushItem(data.raw.item["iron-plate"],0,true) - logic.PushItem(data.raw.item["stone-brick"],0,true) - logic.PushItem(data.raw.item["landfill-sand-3"],0,true) - logic.PushItem(data.raw.item["small-electric-pole"],0,true) - logic.PushItem(data.raw.item["copper-pipe"],0,true) - logic.PushItem(data.raw.item["stone-pipe"],0,true) - logic.PushItem(data.raw.item["stone-pipe-to-ground"],0,true) - logic.PushItem(data.raw.item["wind-turbine-2"],0,true) - logic.PushItem(data.raw.item["iron-stick"],0,true) - logic.PushItem(data.raw.item["pipe"],0,true) - logic.PushItem(data.raw.item["basic-circuit-board"],0,true) - logic.PushItem(data.raw.item["electronic-circuit"],0,true) - logic.PushItem(data.raw.item["iron-gear-wheel"],0,true) - logic.PushItem(data.raw.item["small-lamp"],0,true) - logic.PushItem(data.raw.item["stone"],0,true) - logic.PushItem(data.raw.item["pipe-to-ground"],0,true) - --logic.PushItem(data.raw.tool["sb-angelsore3-tool"],0,true) -- because apparently this is a special item you can't actually obtain. why. - --logic.PushItem(data.raw.tool["sb-basic-circuit-board-tool"],0,true) -- because apparently this is a special item you can't actually obtain. why. - --logic.PushItem(data.raw.tool["sb-algae-green-tool"],0,true) -- because apparently this is a special item you can't actually obtain. why. - --logic.PushItem(data.raw.tool["sb-lab-tool"],0,true) -- because apparently this is a special item you can't actually obtain. why. - - - --logic.Ignore("offshore-pump") - --logic.Ignore("crystallizer") - --logic.Ignore("electrolyzer") -end - -function logic.HasMoreRecipes() for k,v in pairs(data.raw.recipe)do if(not hand.recipescan[k] and proto.UsedRecipe(k) and not logic.ShouldIgnore(k))then return true end end return false end - - - --- Easy check if Fluid (with temperatures) or Item is in our hand (by name) --- fluids may need a min/max... --- Todo push a temperature without a fluid --- It is possible fluid temperature may be removed in future https://forums.factorio.com/viewtopic.php?f=34&t=64499 ---function logic.CanFluid(fld,tmp) tmp=tmp or 15 local ft=hand.fluids[fld] if(ft)then for m in pairs(ft)do if(m>=tmp)then return true end end end return false end -function logic.CanFluid(d,n,x) n=n or 15 local ft=hand.fluids[d] if(ft)then if(not x)then for m in pairs(ft)do if(m>=n)then return true end end else - for m in pairs(ft)do - if(m==x or m==n or (m>n and mx)then a=true elseif(m=(fuel.default_temperature or fuel.min_working_temperature or 1) end -function logic.CanFuel.electric(fuel) return hand.power and hand.pole end -function logic.CanFuel.burner(fuel) - local fcats=proto.FuelCategories(fuel) if(not fcats)then return table_size(hand.burner_cats)>0 end - local c=false for k,v in pairs(fcats)do if(hand.burner_cats[v])then c=true break end end if(c)then logic.PushBurner(fuel) return true end -end - --- Fluidbox fueling - note of future temperature changes --- logic.CanFuelFluidbox(entity.input_fluid_box) -function logic.CanFuelFluidbox(fbox,min,max) - if(not hand.pipes)then return false end - local ft=fbox.filter min=(fbox.minimum_temperature or min) max=(fbox.maximum_temperature or max) - --if(not ft)then return logic.CanFluidTemperature(min) end - return logic.CanFluid(ft,min,max) -end -function logic.CanFuel.fluid(fuel) if(fuel.pipe_connections)then return logic.CanFuelFluidbox(fuel) else return logic.CanFuelFluidbox(fuel.fluid_box,nil,fuel.maximum_temperature) end end - - - -function logic.CanMineResource(c) - local cat=c.category or "basic-solid" - if(not hand.resource_cats[cat])then return false end -- can we mine it by hand or auto? - local min=c.minable if(not min)then error(cat .. " type resource without a .minable?\n" .. serpent.block(c)) end - if(min.required_fluid and ((not logic.Fluid(min.required_fluid)) or (istable(hand.fluid_drill) and not hand.fluid_drill[min.required_fluid])))then return false end -- do we have the fluids needed for the resource? - return hand.resource_cats[cat] -- return automation level -end - -function logic.ScanResource(c) -- Scans a resource and pushes results if we can mine it. Odds are this will be called without need for further handling. - local lvl=logic.CanMineResource(c) if(not lvl)then return false end - if((hand.resource_scan[proto.Name(c)] or -1)0)then for k,v in pairs(fx.recipes)do logic.PushRecipe(data.raw.recipe[v]) end end - hand.techscan[t.name]=true - return true -end -function logic.ScanTechnologies() for k in pairs(hand.techs)do local r=data.raw.technology[k] if(logic.CanResearchTechnology(r) and logic.CanRecursiveAffordTechnology(r))then logic.PushTechnology(r) logic.ScanTechnology(r) end end end - -function logic.CanAffordRecipe(c) local ing=proto.Ingredients(c) if(not ing)then return true end - local can=true for k,ig in pairs(ing)do local v=proto.Ingredient(ig) - if(v.type~="fluid")then if(not hand.items[v.name])then can=false break end elseif(not logic.CanFluid(v.name,v.temperature))then can=false break end - end return can -end - -function logic.CanCraftRecipe(c) return hand.craft_cats[c.category or "crafting"] end -- Return automation level. 0=handcraft. 1=automated. -function logic.ScanRecipe(c,bscan) if(hand.recipescan[c.name])then return true end - if(logic.ShouldIgnore(c.name))then hand.recipescan[c.name]=true return true end - for k,v in pairs(proto.Results(c))do local x=proto.Result(v) logic.PushResult(x,hand.craft_cats[v.category or "crafting"] or 0,bscan) end - hand.recipescan[c.name]=true - return true -end -function logic.ScanRecipes(bscan) for k,v in pairs(hand.recipes)do logic.ScanRecipe(v,bscan) end end - ---[[ Push Functions ]]-- --- Push stuff into the hand - -function logic.PushRecipe(c) local n=proto.Name(c) if(not hand.recipes[n])then hand.recipes[n]=c logic.HandChanged("recipe",c) end end -function logic.PushTechnology(c) local n=proto.Name(c) if(not hand.techs[n])then hand.techs[n]=c logic.HandChanged("technology",c) end end -function logic.PushEntity(c,s) local n=proto.Name(c) if(not hand.ents[n])then hand.ents[n]=c if(s)then logic.ScanEntity(c) end logic.HandChanged("entity",c) end end -function logic.PushFluid(c,m) m=m or 15 local n=proto.Name(c) hand.fluids[n]=hand.fluids[n] or {} hand.fluids[n][m]=c logic.HandChanged("fluid",c,m) end - - -function logic.PushCraftCat(v,n) if(not hand.craft_cats[v] or (n and hand.craft_cats[v]=tmp)then return true end end end return false end +function logic.CanFluid(d,n,x) n=n or 15 local ft=hand.fluids[d] if(ft)then if(not x)then for m in pairs(ft)do if(m>=n)then return true end end else + for m in pairs(ft)do + if(m==x or m==n or (m>n and mx)then a=true elseif(m=(fuel.default_temperature or fuel.min_working_temperature or 1) end +function logic.CanFuel.electric(fuel) return hand.power and hand.pole end +function logic.CanFuel.burner(fuel) + local fcats=proto.FuelCategories(fuel) if(not fcats)then return table_size(hand.burner_cats)>0 end + local c=false for k,v in pairs(fcats)do if(hand.burner_cats[v])then c=true break end end if(c)then logic.PushBurner(fuel) return true end +end + +-- Fluidbox fueling - note of future temperature changes +-- logic.CanFuelFluidbox(entity.input_fluid_box) +function logic.CanFuelFluidbox(fbox,min,max) + if(not hand.pipes)then return false end + local ft=fbox.filter min=(fbox.minimum_temperature or min) max=(fbox.maximum_temperature or max) + --if(not ft)then return logic.CanFluidTemperature(min) end + return logic.CanFluid(ft,min,max) +end +function logic.CanFuel.fluid(fuel) if(fuel.pipe_connections)then return logic.CanFuelFluidbox(fuel) else return logic.CanFuelFluidbox(fuel.fluid_box,nil,fuel.maximum_temperature) end end + + + +function logic.CanMineResource(c) + local cat=c.category or "basic-solid" + if(not hand.resource_cats[cat])then return false end -- can we mine it by hand or auto? + local min=c.minable if(not min)then error(cat .. " type resource without a .minable?\n" .. serpent.block(c)) end + if(min.required_fluid and ((not logic.Fluid(min.required_fluid)) or (istable(hand.fluid_drill) and not hand.fluid_drill[min.required_fluid])))then return false end -- do we have the fluids needed for the resource? + return hand.resource_cats[cat] -- return automation level +end + +function logic.ScanResource(c) -- Scans a resource and pushes results if we can mine it. Odds are this will be called without need for further handling. + local lvl=logic.CanMineResource(c) if(not lvl)then return false end + if((hand.resource_scan[proto.Name(c)] or -1)0)then for k,v in pairs(fx.recipes)do logic.PushRecipe(data.raw.recipe[v]) end end + hand.techscan[t.name]=true + return true +end +function logic.ScanTechnologies() for k in pairs(hand.techs)do local r=data.raw.technology[k] if(logic.CanResearchTechnology(r) and logic.CanRecursiveAffordTechnology(r))then logic.PushTechnology(r) logic.ScanTechnology(r) end end end + +function logic.CanAffordRecipe(c) local ing=proto.Ingredients(c) if(not ing)then return true end + local can=true for k,ig in pairs(ing)do local v=proto.Ingredient(ig) + if(v.type~="fluid")then if(not hand.items[v.name])then can=false break end elseif(not logic.CanFluid(v.name,v.temperature))then can=false break end + end return can +end + +function logic.CanCraftRecipe(c) return hand.craft_cats[c.category or "crafting"] end -- Return automation level. 0=handcraft. 1=automated. +function logic.ScanRecipe(c,bscan) if(hand.recipescan[c.name])then return true end + if(logic.ShouldIgnore(c.name))then hand.recipescan[c.name]=true return true end + for k,v in pairs(proto.Results(c))do local x=proto.Result(v) logic.PushResult(x,hand.craft_cats[v.category or "crafting"] or 0,bscan) end + hand.recipescan[c.name]=true + return true +end +function logic.ScanRecipes(bscan) for k,v in pairs(hand.recipes)do logic.ScanRecipe(v,bscan) end end + +--[[ Push Functions ]]-- +-- Push stuff into the hand + +function logic.PushRecipe(c) local n=proto.Name(c) if(not hand.recipes[n])then hand.recipes[n]=c logic.HandChanged("recipe",c) end end +function logic.PushTechnology(c) local n=proto.Name(c) if(not hand.techs[n])then hand.techs[n]=c logic.HandChanged("technology",c) end end +function logic.PushEntity(c,s) local n=proto.Name(c) if(not hand.ents[n])then hand.ents[n]=c if(s)then logic.ScanEntity(c) end logic.HandChanged("entity",c) end end +function logic.PushFluid(c,m) m=m or 15 local n=proto.Name(c) hand.fluids[n]=hand.fluids[n] or {} hand.fluids[n][m]=c logic.HandChanged("fluid",c,m) end + + +function logic.PushCraftCat(v,n) if(not hand.craft_cats[v] or (n and hand.craft_cats[v]0)then -- Do the fluidbox thing - local pipesizemin=math.max(goalsize,fbc.northern,fbc.southern,fbc.eastern,fbc.western) -- The minimum tile-size we can be due to fluidboxes - goalsize=pipesizemin - local pipesize=goalsize+1 -- the goal tile-size which we would use if we were resizing to the size of the bbox if it were 1 tile bigger in all directions - local pipescale=vector(pipesize,pipesize)/pipemax - local bbnewpipe=bbpipe*pipescale - local bbnew=bbsize*(goalsize/bbmax) - - proto.ShiftFluidboxCenters(pr,bbsize,fbc) -- Shift fluidboxes to center of new bbox - proto.SizeFluidboxesTo(pr,pipescale,fbc) -- Shift positions of fluidboxes - - --if(proto.dbg)then error("DEBUG: Size " .. goalsize .. ", bbmax: " .. pipemax .. ", scale: " .. goalsize/bbmax .. ", Pipescale: " .. serpent.block(pipescale) .. "\nData:\n"..serpent.block(pr).."\n---------------FB----------------\n"..serpent.block(fbc).."\n".."") end - - - - - - end - - proto.SizeTo(pr,goalsize/bbmax) - -end - - - +--[[------------------------------------- + +Author: Pyro-Fire +https://patreon.com/pyrofire + +Script: lib_data_resize.lua +Purpose: proto code for resizing stuff + +----- + +Copyright (c) 2019 Pyro-Fire + +I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. + +Permission to use, copy, modify, and/or distribute this software for any +purpose without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------ + +Written using Microsoft Notepad. +IDE's are for children. + +How to notepad like a pro: +ctrl+f = find +ctrl+h = find & replace +ctrl+g = show/jump to line (turn off wordwrap n00b) + +Status bar wastes screen space, don't use it. + +Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. + +]]--------------------------------------- + +-- Todo: resize equipments to 1x1 https://mods.factorio.com/mod/Super_Pinky_Man_SmallPortableEquipment + +local proto={} + + + + +proto.no_resize_types={"item","item-on-ground","item-entity","item-request-proxy","tile","resource","recipe", +"rail","locomotive","cargo-wagon","fluid-wagon","artillery-wagon","rail-chain-signal","rail-signal", +--"pipe","pipe-to-ground","infinity-pipe", +"underground-belt","transport-belt","splitter", +--"construction-robot","logistic-robot","combat-robot","electric-pole","rocket-silo","rocket-silo-rocket", +--"offshore-pump", +} + +function proto.ShouldResize(pr) if(table.HasValue(proto.no_resize_types,pr.type))then return false end return true end + + +--[[ Basic pictures and layers and offsets resizing and rescaling ]]-- + +proto.scale_keys={"alert_icon_scale"} -- Stuff that is a single number. todo. + + +proto.offset_keys={ + -- Table keys that are offsets +"north_position","south_position","east_position","west_position","red","green","alert_icon_shift", +-- Spider keys +--[[ +"light_positions", +]] +"ground_position", +"offset_deviation", +"mount_position", + +} +function proto.IsImageLayer(k,v) if(v.filenames)then for i,e in pairs(v.filenames)do if(e:find(".png"))then return true end end end return v.layers or (v.filename and v.filename:find(".png")) or k=="animation" end +function proto.IsOffsetLayer(k,v) return (istable(v) and isstring(k) and (k:find("offset") or table.HasValue(proto.offset_keys,k))) end +function proto.IsRailLayer(k,v) return istable(v) and (v.metals or v.backplates) end +function proto.LoopFindImageLayers(prototype,lz) if(not prototype)then return end for key,val in pairs(prototype)do if(istable(val) and key~="sound")then + if(proto.IsImageLayer(key,val))then if(val.layers)then for i,e in pairs(val.layers)do table.insert(lz.images,e) end else table.insert(lz.images,val) end + elseif(proto.IsOffsetLayer(key,val))then table.insert(lz.offsets,val) elseif(proto.IsRailLayer(key,val))then table.insert(lz.rails,val) else proto.LoopFindImageLayers(val,lz) + end +end end end +function proto.FindImageLayers(prototype) local imgz={images={},offsets={},rails={}} proto.LoopFindImageLayers(prototype,imgz) return imgz end +function proto.MergeImageTable(img,tbl) if(img.hr_version)then proto.MergeImageTable(img.hr_version,table.deepcopy(tbl)) end table.merge(img,table.deepcopy(tbl)) end +function proto.MultiplyOffsets(v,z) --if(v[1] and istable(v[1]) and not vector.is_zero(v[1]) and not vector.is_zero(v[2]))then + for a,b in pairs(v)do if(istable(b))then for c,d in pairs(b)do if(type(d)=="table")then error(serpent.block(v)) end v[a][c]=d*z end else v[a]=b*z end end --else vector.set(v,vector(v)*z) --v[1]=v[1]*z v[2]=v[2]*z +end --end +function proto.MultiplyImageSize(img,z) if(img.hr_version)then proto.MultiplyImageSize(img.hr_version,z) end + if(img.shift and istable(img.shift))then for i,e in pairs(img.shift)do if(istable(e))then for a,b in pairs(e)do e[a]=b*z end else img.shift[i]=e*z end end end + img.scale=(img.scale or 1)*z img.y_scale=(img.y_scale or 1)*z img.x_scale=(img.x_scale or 1)*z +end + +function proto.TintImages(pr,tint) local imgz=proto.FindImageLayers(pr) for k,v in pairs(imgz.images)do proto.MergeImageTable(v,{tint=table.deepcopy(tint)}) end end +function proto.MultiplyImages(pr,z) local imgz=proto.FindImageLayers(pr) + for k,v in pairs(imgz.images)do proto.MultiplyImageSize(v,z) end + for k,v in pairs(imgz.offsets)do proto.MultiplyOffsets(v,z) end +end + + + + +proto.bbox_keys={"collision_box","selection_box", -- Table keys that are bounding boxes + "drawing_box","window_bounding_box","horizontal_window_bounding_box","sticker_box","map_generator_bounding_box", +} +proto.ScalableBBoxes={"collision_box","selection_box"} -- Ordered pairs of bounding boxes we can make sized based calculations from +function proto.BBoxIsZero(bbox) if(bbox and bbox[1][1]==0 and bbox[1][2]==0 and bbox[2][1]==0 and bbox[2][2]==0)then return true end return false end +function proto.GetSizableBBox(pr) local b=pr[proto.ScalableBBoxes[1]] for i=2,#proto.ScalableBBoxes,1 do if(not b or proto.BBoxIsZero(b))then b=pr[proto.ScalableBBoxes[i]] else return b end end return b end +function proto.MultiplyBBox(b,z) if(not proto.BBoxIsZero(b))then b[1]=vector.raw(vector(b[1])*z) b[2]=vector.raw(vector(b[2])*z) end end +function proto.MultiplyBBoxes(t,z) for _,nm in pairs(proto.bbox_keys)do if(t[nm] and not proto.BBoxIsZero(t[nm]))then proto.MultiplyBBox(t[nm],z) end end end +function proto.AddBBox(b,f) b[1]=vector.raw(vector(b[1])-vector(f)) b[2]=vector.raw(vector(b[2])+vector(f)) end +function proto.AddBBoxes(t,f) for _,nm in pairs(proto.bbox_keys)do if(t[nm] and not proto.BBoxIsZero(t[nm]))then proto.AddBBox(t[nm],f) end end end +function proto.BBoxSize(b) return vector(b[2])-vector(b[1]) end +function proto.RecenterBBox(b) local len=proto.BBoxSize(b) b[2]=len/2 b[1]=-len/2 end + + +function proto.GetBBoxOrigin(bbox) -- This is to give us +0.5 origin if the bbox needs it, but i dont think this is needed idfk + local bbx=proto.BBoxSize(bbox) + local bv=vector(math.round(bbx.x),math.round(bbx.y)) + local forigin=vector(bv.x%2==0 and 0.5 or 0,bv.y%2==0 and 0.5 or 0) + return forigin +end + +function proto.SizeTo(pr,scale) -- Resizes something purely off a simple scale, this function simply does *scale + proto.MultiplyBBoxes(pr,scale) + proto.MultiplyImages(pr,scale) +end +function proto.SizeToTile(pr,tilesize) -- Resizes something to a tile size based off its scaleable bbox. This is a simple call function to do simple image/bbox/offset resizing. + local bbox=proto.GetSizableBBox(pr) if(not bbox or proto.BBoxIsZero(bbox))then return end + local bbx=proto.BBoxSize(bbox) + proto.SizeTo(pr,tilesize/math.max(bbx.x,bbx.y)) +end + + +--[[ Fluidbox Counter/Scanner ]]-- + + +proto.fluidbox_keys={"fluid_boxes","fluid_box","input_fluid_box","output_fluid_box"} + +function proto.ScanReadFluidbox(fbox,fb) + if(not fbox.pipe_connections)then for k,v in pairs(fbox)do if(istable(v) and v.pipe_connections)then proto.ScanReadFluidbox(v,fb) end end return end + for pipeid,pipe in pairs(fbox.pipe_connections)do + if(pipe.position or pipe.positions)then fb.c=fb.c+1 end + if(pipe.position)then + local maxdir,maxkey=vector.MaxDir(vector(pipe.position)) + fb[maxdir.."ern"]=fb[maxdir.."ern"]+1 + fb[maxdir.."single"]=fb[maxdir.."single"]+1 + local id=#fb[maxdir]+1 fb[maxdir][id]=pipe.position + elseif(pipe.positions)then + fb["north".."single"]=fb["north".."single"]+1 + for i=1,4,1 do local dir=string.compassnum[i] fb[dir.."ern"]=fb[dir.."ern"]+1 local id=#fb[dir]+1 fb[dir][id]=pipe.positions[i] end + end + end +end +function proto.ScanFluidboxCounts(pr) + local fbc={c=0, + north={},east={},south={},west={}, -- Table of fluidbox datas based on direction. Fluidboxes always default to north (y=-5) + northern=0,eastern=0,southern=0,western=0, -- Number of fluidboxes for each given direction total, for all pipe connections. + northsingle=0,eastsingle=0,southsingle=0,westsingle=0, -- Number of fluidboxes for each given direction counting by only a single orientation (north) + } + for _,fbn in pairs(proto.fluidbox_keys)do if(pr[fbn] and istable(pr[fbn]))then proto.ScanReadFluidbox(pr[fbn],fbc) end end + return fbc +end + +function proto.SizeFluidboxesTo(pr,vecscale,fbc) + fbc=fbc or proto.ScanFluidboxCounts(pr) + for dir in pairs(string.strcompass)do + for vi,fbox in pairs(fbc[dir])do + local vfb=vector.raw(vector.floorEx(vector(fbox)*vecscale,2,true)) + +--if(proto.dbg)then error("FBOX:"..serpent.block(fbox) .. " \n NEW FBOX: " .. serpent.block(vfb) .. " \n ORIGIN: " .. serpent.block(origin) .. " \n BBOX: " .. serpent.block(bbround) .. " \n VECSCALE: " .. serpent.block(vecscale)) end + + vector.set(fbox,vfb) + + end + end +end + +function proto.ShiftFluidboxCenters(pr,bbox,fbc) -- Shift fluidboxes more towards the center if they're off-center as a sum. + fbc=fbc or proto.ScanFluidboxCounts(pr) + local shifts={north=vector(),east=vector(),south=vector(),west=vector()} + for dir,vec in pairs(shifts)do + for ktd,pos in pairs(fbc[dir])do --if(proto.dbg and dir=="north")then error("northtest" .. serpent.block(pos)) end + shifts[dir]=shifts[dir]+vector(((dir=="north" or dir=="south") and vector.getx(pos) or 0),((dir=="east" or dir=="west") and vector.gety(pos) or 0)) + end + if(not vector.is_zero(shifts[dir]))then shifts[dir]=shifts[dir]/fbc[dir.."ern"] end + end +--if(proto.dbg)then error(serpent.block(shifts) .. ", " .. serpent.block(fbc)) end + + for dir,vec in pairs(shifts)do + for vi,fbox in pairs(fbc[dir])do local vfb=vector(fbox)-vec vector.set(fbox,vfb) end + end + +end + +function proto.AutoResize(pr,tilesize) + --if(table.HasValue(proto.no_resize_types,pr.type))then return end + local goalsize=tilesize + local bbox=proto.GetSizableBBox(pr) if(not bbox or proto.BBoxIsZero(bbox))then return end + local bbsize=vector.roundEx(proto.BBoxSize(bbox),2,true) + local bbpipe=bbsize+vector(1,1) -- The size the bbox would be if it were 1 tile bigger (fluidbox size = {-0.5,-0.5},{0.5,0.5} bigger than regular bbox.) + local bbmax=math.ceil(math.max(bbsize.x,bbsize.y)) + local pipemax=math.ceil(math.max(bbpipe.x,bbpipe.y)) + if(pr.type=="character" or pr.type=="character-corpse")then goalsize=0.75 end + local fbc=proto.ScanFluidboxCounts(pr) + + --if(pr.name=="furnace")then proto.dbg=true end + --if(pr.name=="boiler")then proto.dbg=true end + --if(pr.name=="pumpjack")then proto.dbg=true end + --if(pr.name=="offshore-pump")then proto.dbg=true end + --if(pr.name=="oil-refinery")then proto.dbg=true end + --if(pr.name=="chemical-plant")then proto.dbg=true end + --if(pr.name=="pump")then proto.dbg=true end + + + + if(fbc.c>0)then -- Do the fluidbox thing + local pipesizemin=math.max(goalsize,fbc.northern,fbc.southern,fbc.eastern,fbc.western) -- The minimum tile-size we can be due to fluidboxes + goalsize=pipesizemin + local pipesize=goalsize+1 -- the goal tile-size which we would use if we were resizing to the size of the bbox if it were 1 tile bigger in all directions + local pipescale=vector(pipesize,pipesize)/pipemax + local bbnewpipe=bbpipe*pipescale + local bbnew=bbsize*(goalsize/bbmax) + + proto.ShiftFluidboxCenters(pr,bbsize,fbc) -- Shift fluidboxes to center of new bbox + proto.SizeFluidboxesTo(pr,pipescale,fbc) -- Shift positions of fluidboxes + + --if(proto.dbg)then error("DEBUG: Size " .. goalsize .. ", bbmax: " .. pipemax .. ", scale: " .. goalsize/bbmax .. ", Pipescale: " .. serpent.block(pipescale) .. "\nData:\n"..serpent.block(pr).."\n---------------FB----------------\n"..serpent.block(fbc).."\n".."") end + + + + + + end + + proto.SizeTo(pr,goalsize/bbmax) + +end + + + return proto \ No newline at end of file diff --git a/lib/lib_global.lua b/lib/lib_global.lua index cb4f496..cded851 100644 --- a/lib/lib_global.lua +++ b/lib/lib_global.lua @@ -1,254 +1,254 @@ ---[[------------------------------------- - -Author: Pyro-Fire -https://patreon.com/pyrofire - -Script: lib_global.lua -Purpose: lib.lua() - ------ - -Copyright (c) 2019 Pyro-Fire - -I put a lot of work into these library files. Please retain the above text and this copyright disclaimer message in derivatives/forks. - -Permission to use, copy, modify, and/or distribute this software for any -purpose without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------- - -Written using Microsoft Notepad. -IDE's are for children. - -How to notepad like a pro: -ctrl+f = find -ctrl+h = find & replace -ctrl+g = show/jump to line (turn off wordwrap n00b) - -Status bar wastes screen space, don't use it. - -Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. - -]]--------------------------------------- - -util=require("util") - -function istable(v) return type(v)=="table" end -function isstring(v) return type(v)=="string" end -function isnumber(v) return type(v)=="number" end - -function isvalid(v) return v and v.valid end - - -function new(x,a,b,c,d,e,f,g) local t,v=setmetatable({},x),rawget(x,"__init") if(v)then v(t,a,b,c,d,e,f,g) end return t end - -local function toKeyValues(t) local r={} for k,v in pairs(t)do table.insert(r,{k=k,v=v}) end return r end -local function keyValuePairs(x) x.i=x.i+1 local kv=x.kv[x.i] if(not kv)then return end return kv.k,kv.v end -function RandomPairs(t,d) local rt=toKeyValues(t) for k,v in pairs(rt)do v.rand=math.random(1,1000000) end - if(d)then table.sort(rt,function(a,b) return a.rand>b.rand end) else table.sort(rt,function(a,b) return a.rand>b.rand end) end - return keyValuePairs, {i=0,kv=rt} -end -function StringPairs(t,d) local tbl=toKeyValues(t) if(d)then table.sort(tbl,function(a,b) return a.v>b.v end) else table.sort(tbl,function(a,b) return a.vb.k end) else table.sort(tbl,function(a,b) return a.k=0 and math.ceil(x*k)/k or math.floor(x*k)/k) end return math.round(x*k)/k end -- round to nearest fraction e.g. *2 = nearest 0.5. -function math.floorEx(x,k,b) if(b)then return (x>=0 and math.floor(x*k)/k or math.ceil(x*k)/k) end return math.floor(x*k)/k end -- round to nearest fraction e.g. *2 = nearest 0.5. -function math.radtodeg(x) return x*(180/math.pi) end -function math.nroot(r,n) return n^(1/r) end -function math.sign(v) return v>0 and 1 or (v<0 and -1 or 0) end -function math.signx(v) return v>=0 and 1 or (v<0 and -1 or 0) end -function math.wrap(a,b) local lg=1 local dif=a-b if(math.abs(dif)>lg/2)then return (lg-math.abs(dif))*(dif>0 and 1 or -1) else return dif end end -math.uint32=4294967295 - - - -string.energy_chars={{10^3,"k"},{10^6,"M"},{10^9,"G"},{10^12,"T"},{10^15,"P"},{10^18,"E"},{10^21,"Z"},{10^24,"Y"}} -function string.energy_to_string(e,f) - local exp,str=10^3,"k" - local ev=math.abs(e) - for k,v in ipairs(string.energy_chars)do if(ev>v[1])then exp=v[1] str=v[2] else break end end - return math.roundx(e/exp,f or 2) .. str .. "W" -end - ---[[ Vector Meta ]]-- - -vector={} local vectorMeta={__index=vector} setmetatable(vector,vectorMeta) -setmetatable(vectorMeta,{__index=function(t,k) if(k=="x")then return rawget(t,"k") or t[1] elseif(k=="y")then return rawget(t,"y") or t[2] end end}) -function vectorMeta:__call(x,y) if(type(x)=="table")then return vector(vector.getx(x),vector.gety(x)) else return setmetatable({[1]=x or 0,[2]=y or 0,x=x or 0,y=y or 0},vector) end end -function vectorMeta.__tostring(v) return "{"..vector.getx(v) .. ", " .. vector.gety(v) .."}" end -function vector.__add(x,y) return vector.add(x,y) end -function vector.__sub(x,y) return vector.sub(x,y) end -function vector.__mul(x,y) return vector.mul(x,y) end -function vector.__div(x,y) return vector.div(x,y) end -function vector.__pow(x,y) return vector.pow(x,y) end -function vector.__mod(x,y) return vector.mod(x,y) end -function vector.__eq(x,y) return vector.equal(x,y) end -function vector.__lt(x,y) return vector.getx(x)math.abs(vec.y))then - maxkey="x" - if(vec.x<0)then maxdir="west" else maxdir="east" end - else - maxkey="y" - if(vec.y<0)then maxdir="north" else maxdir="south" end - end - return maxdir,maxkey -end - -function vector.isinbbox(p,a,b) local x,y=(p.x or p[1]),(p.y or p[2]) return not ( (x<(a.x or a[1]) or y<(a.y or a[2])) or (x>(b.x or b[1]) or y>(b.y or b[2]) ) ) end - -function vector.inarea(v,a) local x,y=(v.x or v[1]),(v.y or v[2]) return not ( (x<(a[1].x or a[1][1]) or y<(a[1].y or a[1][2])) or (x>(a[2].x or a[2][1]) or y>(a[2].y or a[2][2]))) end -function vector.table(area) local t={} for x=area[1].x,area[2].x,1 do for y=area[1].y,area[2].y,1 do table.insert(t,vector(x,y)) end end return t end -function vector.circle(p,z) local t,c,d={},math.round(z/2) for x=p.x-c,p.x+c,1 do for y=p.y-c,p.y+c,1 do d=math.sqrt(((x-p.x)^2)+((y-p.y)^2)) if(d<=c)then table.insert(t,vector(x,y)) end end end return t end -function vector.circleEx(p,z) local t,c,d={},z/2 for x=p.x-c,p.x+c,1 do for y=p.y-c,p.y+c,1 do d=math.sqrt(((x-p.x)^2)+((y-p.y)^2)) if(db.rand end) else table.sort(rt,function(a,b) return a.rand>b.rand end) end + return keyValuePairs, {i=0,kv=rt} +end +function StringPairs(t,d) local tbl=toKeyValues(t) if(d)then table.sort(tbl,function(a,b) return a.v>b.v end) else table.sort(tbl,function(a,b) return a.vb.k end) else table.sort(tbl,function(a,b) return a.k=0 and math.ceil(x*k)/k or math.floor(x*k)/k) end return math.round(x*k)/k end -- round to nearest fraction e.g. *2 = nearest 0.5. +function math.floorEx(x,k,b) if(b)then return (x>=0 and math.floor(x*k)/k or math.ceil(x*k)/k) end return math.floor(x*k)/k end -- round to nearest fraction e.g. *2 = nearest 0.5. +function math.radtodeg(x) return x*(180/math.pi) end +function math.nroot(r,n) return n^(1/r) end +function math.sign(v) return v>0 and 1 or (v<0 and -1 or 0) end +function math.signx(v) return v>=0 and 1 or (v<0 and -1 or 0) end +function math.wrap(a,b) local lg=1 local dif=a-b if(math.abs(dif)>lg/2)then return (lg-math.abs(dif))*(dif>0 and 1 or -1) else return dif end end +math.uint32=4294967295 + + + +string.energy_chars={{10^3,"k"},{10^6,"M"},{10^9,"G"},{10^12,"T"},{10^15,"P"},{10^18,"E"},{10^21,"Z"},{10^24,"Y"}} +function string.energy_to_string(e,f) + local exp,str=10^3,"k" + local ev=math.abs(e) + for k,v in ipairs(string.energy_chars)do if(ev>v[1])then exp=v[1] str=v[2] else break end end + return math.roundx(e/exp,f or 2) .. str .. "W" +end + +--[[ Vector Meta ]]-- + +vector={} local vectorMeta={__index=vector} setmetatable(vector,vectorMeta) +setmetatable(vectorMeta,{__index=function(t,k) if(k=="x")then return rawget(t,"k") or t[1] elseif(k=="y")then return rawget(t,"y") or t[2] end end}) +function vectorMeta:__call(x,y) if(type(x)=="table")then return vector(vector.getx(x),vector.gety(x)) else return setmetatable({[1]=x or 0,[2]=y or 0,x=x or 0,y=y or 0},vector) end end +function vectorMeta.__tostring(v) return "{"..vector.getx(v) .. ", " .. vector.gety(v) .."}" end +function vector.__add(x,y) return vector.add(x,y) end +function vector.__sub(x,y) return vector.sub(x,y) end +function vector.__mul(x,y) return vector.mul(x,y) end +function vector.__div(x,y) return vector.div(x,y) end +function vector.__pow(x,y) return vector.pow(x,y) end +function vector.__mod(x,y) return vector.mod(x,y) end +function vector.__eq(x,y) return vector.equal(x,y) end +function vector.__lt(x,y) return vector.getx(x)math.abs(vec.y))then + maxkey="x" + if(vec.x<0)then maxdir="west" else maxdir="east" end + else + maxkey="y" + if(vec.y<0)then maxdir="north" else maxdir="south" end + end + return maxdir,maxkey +end + +function vector.isinbbox(p,a,b) local x,y=(p.x or p[1]),(p.y or p[2]) return not ( (x<(a.x or a[1]) or y<(a.y or a[2])) or (x>(b.x or b[1]) or y>(b.y or b[2]) ) ) end + +function vector.inarea(v,a) local x,y=(v.x or v[1]),(v.y or v[2]) return not ( (x<(a[1].x or a[1][1]) or y<(a[1].y or a[1][2])) or (x>(a[2].x or a[2][1]) or y>(a[2].y or a[2][2]))) end +function vector.table(area) local t={} for x=area[1].x,area[2].x,1 do for y=area[1].y,area[2].y,1 do table.insert(t,vector(x,y)) end end return t end +function vector.circle(p,z) local t,c,d={},math.round(z/2) for x=p.x-c,p.x+c,1 do for y=p.y-c,p.y+c,1 do d=math.sqrt(((x-p.x)^2)+((y-p.y)^2)) if(d<=c)then table.insert(t,vector(x,y)) end end end return t end +function vector.circleEx(p,z) local t,c,d={},z/2 for x=p.x-c,p.x+c,1 do for y=p.y-c,p.y+c,1 do d=math.sqrt(((x-p.x)^2)+((y-p.y)^2)) if(d Date: Mon, 12 May 2025 01:21:36 +0200 Subject: [PATCH 2/2] Update for Factorio 2.0 --- changelog.txt | 2004 +++++++++-------- control.lua | 60 +- control_class_harvester.lua | 713 +++--- control_class_rails.lua | 263 ++- control_class_teleporter.lua | 661 +++--- control_main.lua | 1625 +++++++------ control_main_helpers.lua | 1081 +++++---- control_main_remotes.lua | 38 +- control_platform_classic.lua | 4 +- data-updates.lua | 186 +- data.lua | 42 +- data_warptorio.lua | 1705 +++++++++----- graphics/victory.png | Bin 0 -> 414367 bytes info.json | 28 +- lib/lib_control.lua | 515 +++-- lib/lib_control_cache.lua | 38 +- lib/lib_planets.lua | 20 +- locale/en/config.cfg | 895 ++++---- prototypes-updates/data_accumulators.lua | 405 ++-- .../data_warptorio-harvester.lua | 220 +- prototypes/data_warpnuke.lua | 72 +- prototypes/data_warptorio-combinator.lua | 386 ++-- prototypes/data_warptorio-heatpipe.lua | 1278 +++-------- prototypes/data_warptorio-logistics-pipe.lua | 158 +- prototypes/data_warptorio-townportal.lua | 141 +- prototypes/data_warptorio-warploader.lua | 28 +- prototypes/data_warptorio-warpport.lua | 153 +- prototypes/data_warptorio-warpspider.lua | 160 +- prototypes/data_warptorio-warpstation.lua | 39 +- settings.lua | 620 +++-- sound/sound.lua | 67 +- 31 files changed, 7557 insertions(+), 6048 deletions(-) create mode 100644 graphics/victory.png diff --git a/changelog.txt b/changelog.txt index 8e3810a..bf8b6f3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,999 +1,1007 @@ ---------------------------------------------------------------------------------------------------- -Version: 1.3.11 -Date: 18.2.2024 - Changes: - - Added a mod setting to disable stair sprites. - - Changed default provider chest to passive provider by popular demand - - Slightly increased the chance for loot chests to spawn and added a setting for it - - Changed warp reactor specific heat from 10MJ to 1MJ to address heat distribution issues - - Updated heat related code to better respect specific heats (Thanks chingis_khagan!) - - ---------------------------------------------------------------------------------------------------- -Version: 1.3.10 -Date: 8.5.2023 - Changes: - - Fixed crash when setting warp target to homeworld or nauvis. - - Fixed the Charting ability where the button wasnt adding to the hud and wasnt spawning invisible radars on the factory and boiler floors when the research finishes. - - Fixed two Typ"};o's in the Warptorio Lore messages (Thanks Honktown!) - - Fixed Warp Armor and Warp Accumulator tech icons (Thanks Knofbath!) - - Removed incompatibility flag with Rampant because Rampant now has multi-surface compatibility. - - Removed placeable-by on warp pipes to prevent accidental placement of them. - - Buffed Warponium Fuel Cells, they are now more accurately 4x more powerful than a typical uranium fuel cell as originally intended (Thanks Knofbath!) - - Buffed Stabilizer ability and rephrased its description for clarity - - Updated to Factorio 1.1.80 - ---------------------------------------------------------------------------------------------------- -Version: 1.3.9 -Date: 5.7.2022 - Changes: - - Fixed a bug with warp pre-charge speed upgrades where upgrading made pre-charging slower - - Fixed the harvester loaders bug + migration with help from community (Thank you!) - ---------------------------------------------------------------------------------------------------- -Version: 1.3.8 -Date: 8.4.2022 - Changes: - - Typo - - ---------------------------------------------------------------------------------------------------- -Version: 1.3.7 -Date: 7.4.2022 - Changes: - - Lib bugfix related to cloning spider legs - - ---------------------------------------------------------------------------------------------------- -Version: 1.3.6 -Date: 7.3.2022 - Changes: - - Fixed green wire circuits not connecting between stairs + migration - - Fixed void tiles not being placed if the platform warps away without you - - Added fix for crashes related to warp loaders & filters with help from community (Thank you!) - - Teleporter gate now has flying text when logistics cannot be placed instead of a global message. - ---------------------------------------------------------------------------------------------------- -Version: 1.3.5 -Date: 13.3.2021 - Changes: - - Fixed multiplayer crash, missing nil check on updating ownership and connection of cloned spidertrons to the remotes in players inventories between warps. - - ---------------------------------------------------------------------------------------------------- -Version: 1.3.4 -Date: 30.12.2020 - Changes: - - Factorio 1.1.6 - - ---------------------------------------------------------------------------------------------------- -Version: 1.3.3 -Date: 3.12.2020 - Changes: - - Factorio 1.1 - ---------------------------------------------------------------------------------------------------- -Version: 1.3.2 -Date: 4.11.2020 - Changes: - - Spidertron can now travel through stairs (cloning method) - - Fixed decoupling of spidertron remotes when warping/cloning - - You now remain in your spidertron when warping. - ---------------------------------------------------------------------------------------------------- -Version: 1.3.1 -Date: 25.8.2020 - Changes: - - Basic fixes for warp loaders - - Fixed spidertron being lost between warps - - Fixed a crash when using steel loader chests - ---------------------------------------------------------------------------------------------------- -Version: 1.3.0 -Date: 8.8.2020 - Changes: - - Fixed rails not being affected by logistics upgrades - - Made hazard tiles accurate and fixed hazard clearing crash - - typo causing crash on warp - ---------------------------------------------------------------------------------------------------- -Version: 1.2.9 -Date: 2.8.2020 - Changes: - - Fixed invisible radars & homeworld/platform teleport capsules - - e (typo) - - v (typo) - - Buffed stabilizer to 5% of regular platform pollution - - Fixed ability drain % texts and added setting - - Turned on warp blacklists for harvesters (fixes some mod compatabilities) - - Factorio 0.18.40 - - ---------------------------------------------------------------------------------------------------- -Version: 1.2.8 -Date: 12.5.2020 - Changes: - - Fixed a few bugs - - ---------------------------------------------------------------------------------------------------- -Version: 1.2.7 -Date: 7.5.2020 - Changes: - - Warptorio Expansion Update - - Large changes to remote interfaces - - Moved planet rng settings to planetorio - - Fixed changing loader directions mid-game (top/bottom halves) - - Fixed a bunch of harvester bugs - ---------------------------------------------------------------------------------------------------- -Version: 1.2.6 -Date: 13.4.2020 - Changes: - - Factorio 0.18 - - Added /kill command to suicide (if you get stuck on ocean planet) - - Added biter warping difficulty setting - - Added Nauvis to warp target list - - Added warp pipes to the Harvesters - - Full rework of platform tileing/upgrading system enabling the creation of multiple platform layouts. - - Full rework of planets system, exported to standalone library mod Planetorio enabling other mod makers to create new planets and use the planets/surfaces system for their own mods. - - Reworked Abilities: All abilities now use platform electricity (kept in the stairs) to function. Abilities are toggleable and drain energy over time. The amount drained is the same for all abilities, and it increases the longer abilities remain active. The amount of energy drained, and energy drain growth is applied for all abilities active at once (1x for 1 ability active, 3x for 3 abilities active). Drain amounts are based on a % of the total electrical storage capacity. - - Added a Platform Energy bar to the HUD showing electricity balance to help with using the new ability mechanics. - - Reworked Stabilizer Ability: Platform pollution, and pollution growth reduced to 25% while active. - - Reworked Radar Ability: Scans an outer ring every few seconds while active (takes longer each successive scan) - - Fixed a bug with warpchance setting not applying to homeworld rolls - - Fixed a bug with pollution not being removed from harvester floor - - Broke warp loaders - - Broke the Accelerator ability (it does nothing for now) - - Broke the warptorio remote interface (affects cross mod compatabilities) - - Broke functionality related to changing loader directions (top/bottom halves) upon the settings being changed mid-game - - Broke "unstuck" on platform entities, e.g. you can become trapped in teleporters as you unlock them. - - Broke hazard tile accuracy - - Probably broke more things. - ---------------------------------------------------------------------------------------------------- -Version: 1.2.5 -Date: 13.11.2019 - Changes: - - Harvester deploy typo x2 (?) - - Harvesters now ignore planet-side logistics/construction robots when deployed - ---------------------------------------------------------------------------------------------------- -Version: 1.2.4 -Date: 13.11.2019 - Changes: - - Fixed a divide by zero error - - Harvester deploy typo (?) - - ---------------------------------------------------------------------------------------------------- -Version: 1.2.3 -Date: 13.11.2019 - Changes: - - Made "invisible" radars unminable - - Removed warpstation, warppipe and harvesters from circuit signals menu - - Added blacklists to harvesters - - Vehicles are now teleported between surfaces instead of cloned (AAI vehicles compatability). Not yet added to harvesters. - - Players are no longer teleported through platform teleporters if they are in a vehicle. - - Optimized teleporter code to save frames - - 10,000 Downloads Special: Compatibility with NewGamePlus courtesy of Bilka <3 - ---------------------------------------------------------------------------------------------------- -Version: 1.2.2 -Date: 31.10.2019 - Changes: - - Added ability_used and ticktime to remote events - - Added remote functions to recall the harvesters and teleporter gate - - Added robots outside of platform carry between warps difficulty setting (disabled by default). - - Fix for harvesters being permanently lost - - Added Home Portal item that teleports you to homeworld - - Buffed warp module productivity bonus for consistency - - Added new remotes for mod managed tables - - Warp pipes are now automatically emptied if neither side is connected to another pipe - - Added sprite overlays to stairs to reduce confusion on where it will send you (alt-mode only) - ---------------------------------------------------------------------------------------------------- -Version: 1.2.1 -Date: 10.10.2019 - Changes: - - Harvesters now prevent players getting stuck when being deployed. - - Another loot chest typo - ---------------------------------------------------------------------------------------------------- -Version: 1.2.0 -Date: 10.10.2019 - Changes: - - Typos with loot chests - - Fixed harvesters "moving" players when recalled on warp - - Attempted fixes of harvester deploy bug - ---------------------------------------------------------------------------------------------------- -Version: 1.1.9 -Date: 10.10.2019 - Changes: - - Fixed votewarp bug - - Updated logistics research descriptions - - Fixed warp pipe temperature bug - - Added SpawnLootChest to remote interface - - Added setting to turn on/off loot chests - - Fixed a crash related to clearing mod composite entities (eg. mini-loaders) - - Added some missing modifiers to the reach distance research - - Added Warp Striders research - - Made a few early researches require the reactor reassembly project - - Made a few other small research tweaks - - Added steel chest to Requester chest type settings - ---------------------------------------------------------------------------------------------------- -Version: 1.1.8 -Date: 2.10.2019 - Changes: - - Attempted fixes of sound stacking problem - - Fixed platform turret warping alignment x2 - ---------------------------------------------------------------------------------------------------- -Version: 1.1.7 -Date: 30.09.2019 - Changes: - - Reduced cost of Warponium Fuel Cells - - Fixed teleporter sounds - - Fixed warp beacon (?) - - Changed warp pipe pipette - - Fixed player leave/join affecting votewarp - - Increased default votewarp fraction to 0.51 and now rounds up. (2 players in MP requires both players to vote before warping) - - Fixed platform turret warping alignment issue - - Fixed factory floor early research tile alignment issue - - ---------------------------------------------------------------------------------------------------- -Version: 1.1.6 -Date: 30.09.2019 - Changes: - - Fixed nauvis map gen settings not applying to uncharted planets and added copy_nauvis planet modifier. - - Fixed hazard tile indicator accuracy for stairs - - Fixed a bug with harvester recall and overlapping belts/entities being destroyed - ---------------------------------------------------------------------------------------------------- -Version: 1.1.5 -Date: 30.09.2019 - Changes: - - Made rotation checks more efficient - - Fixed Warp Rail logistics not being removed from blueprints. - - Fixed blueprints created from hotbar not being affected by blueprint checks. - - Mod Compatability attempted AAI Vehicles fixes - - Added toolbar and relating research for easy harvester and mobile gate pickup by popular demand - ---------------------------------------------------------------------------------------------------- -Version: 1.1.4 -Date: 29.09.2019 - Changes: - - Added "P" Planet Clock timer to Warp Combinator - - Added separate setting to disable biter waves (previously disabled under base expansion rate tickbox) - - Fix for harvester migration issue x3 - - ---------------------------------------------------------------------------------------------------- -Version: 1.1.3 -Date: 29.09.2019 - Changes: - - Fixed red X's in power statistics - - Made factory beacon research a bit more expensive - - Nerfed platform solar power by popular demand and added a difficulty setting - - Fix for harvester migration issue x2 - ---------------------------------------------------------------------------------------------------- -Version: 1.1.2 -Date: 29.09.2019 - Changes: - - Fixed bug with abilities not resetting on warp - - Attempted more fixes of multiplayer votewarp - - Added some locale to Warp Reactor research level 6 and 8 - - Fixed planet target dropdown unlocking early. - - Fix of harvester loaders migration issue - - Picking up harvesters now prevents inventory duplicates - - Tweaked sorting of harvester items and research (left is now on the left) - - ---------------------------------------------------------------------------------------------------- -Version: 1.1.1 -Date: 29.09.2019 - Changes: - - Migration error x2 - ---------------------------------------------------------------------------------------------------- -Version: 1.1.0 -Date: 28.09.2019 - Changes: - - Migration error - ---------------------------------------------------------------------------------------------------- -Version: 1.0.9 -Date: 28.09.2019 - Changes: - - Attempted fix of loader and boiler floor access migration issues - ---------------------------------------------------------------------------------------------------- -Version: 1.0.8 -Date: 27.09.2019 - Changes: - - Cleaned entity spam from circuit signals menu - - Mod compatability with Spell Pack - - Fixed Warp Loaders (old saves may need to rotate them to refresh/update) - ---------------------------------------------------------------------------------------------------- -Version: 1.0.7 -Date: 26.09.2019 - Changes: - - Planet API bugfix - - Removed some debug code - - Fixed migration power bug - - Fixed Warp Combinator alignments and bug with offset setting not applying - - Fixed Harvester alignment bug + tile migration - - Fixed bug with Harvester Combinators not moving for size upgrades - ---------------------------------------------------------------------------------------------------- -Version: 1.0.6 -Date: 25.09.2019 - Changes: - - Removed unused hazard tiles - - Moved Harvester Floor between boiler and factory, and adjusted research to match. - - Fixed Warp Accumulator recipe and item - - Fixed "Invisible" Radar being hidden by factory beacon/boiler substation upgrades - - Fixed minor factory floor misalignments + tile migration - ---------------------------------------------------------------------------------------------------- -Version: 1.0.5 -Date: 22.09.2019 - Changes: - - Fixed crash related to new blueprints thing - - Added Warp Combinators and related research - - Added Harvester Combinators and related research - - Fixed factory giga floors alignments + tile migration - ---------------------------------------------------------------------------------------------------- -Version: 1.0.4 -Date: 22.09.2019 - Changes: - - Fixed bug with teleporter gate not receiving power upgrades if logistics is blocked when it's placed - - Planet teleporter gate must now be rebuilt for logistics and loader upgrades to apply (prevents problems related to clearing space) - - Added fix for loader filters being lost between logistics and loader upgrades - - Fixed bug with players being moved between warps - - Fixed clearing bug with platform turrets - - Platform Structures are now removed from blueprints. This is potentially conflicting so there is a setting to disable this. - - New warptorio event handling. See remote.get_events() and remote.get_event(name). - - ---------------------------------------------------------------------------------------------------- -Version: 1.0.3 -Date: 21.09.2019 - Changes: - - Added a bunch of remote api events for future implementation and slightly adjusted naming of existing ones. - - Fixed harvester logistics research crash - - Fixed boiler floor, water and giga alignment issues + tile migration. - - Mod Compatability bugfix for ModMash - - Fixed tile migrations clearing harvesters - - ---------------------------------------------------------------------------------------------------- -Version: 1.0.2 -Date: 18.09.2019 - Changes: - - Fixed west harvester bugs - - Fixed east harvester loaders research bug - - Fixed boiler giga floor bridge alignment bugs - - Fixed bug with level 0 (entry) platform turret research not placing tiles on planet - - Fixed bug with harvester logistics not clearing space for loaders correctly - - Fixed boiler water alignment bugs - - Added tile migration. Saves may take a while to load. - ---------------------------------------------------------------------------------------------------- -Version: 1.0.1 -Date: 17.09.2019 - Changes: - - Fixed beacon issues - - Fixed carebear chest - - Attempted fix of logistics research occasional crash - - New thumbnail.png - ---------------------------------------------------------------------------------------------------- -Version: 1.0.0 -Date: 15.09.2019 - Changes: - - Fixed clearing alignment bug of platform circles - - Added migration to recall harvesters aiming to fix loader and alignment issues - ---------------------------------------------------------------------------------------------------- -Version: 0.9.9 -Date: 15.09.2019 - Changes: - - Fixed issue with reactor upgrade destroying teleporter - - Fixed bug with planet teleporter gate not using energy upgrades - ---------------------------------------------------------------------------------------------------- -Version: 0.9.8 -Date: 15.09.2019 - Changes: - - Fixed sizing bug for platform circles - ---------------------------------------------------------------------------------------------------- -Version: 0.9.7 -Date: 15.09.2019 - Changes: - - Fixed typos with carebear chest - - Adjusted size of harvester platform borders - - Added (up to) 3 loaders to the harvester platforms which are always connected to harvester floor. - - Harvesters are now recalled when the interior portal is mined (if deployed) - ---------------------------------------------------------------------------------------------------- -Version: 0.9.6 -Date: 13.09.2019 - Changes: - - Fixed harvester pickup portal bug - - More typos - ---------------------------------------------------------------------------------------------------- -Version: 0.9.5 -Date: 12.09.2019 - Changes: - - More typos - - Attempted fix of harvester recall crash - ---------------------------------------------------------------------------------------------------- -Version: 0.9.4 -Date: 12.09.2019 - Changes: - - Fixed typos with pipe logistics and warpout - ---------------------------------------------------------------------------------------------------- -Version: 0.9.3 -Date: 12.09.2019 - Changes: - - More typos - - ---------------------------------------------------------------------------------------------------- -Version: 0.9.2 -Date: 11.09.2019 - Changes: - - Fix for pipe logistics issue - - More typo fixes - - ---------------------------------------------------------------------------------------------------- -Version: 0.9.1 -Date: 11.09.2019 - Changes: - - (Hopefully) fixed a crash relating to fluids - - Added fix for migration bug relating to power between floors - - ---------------------------------------------------------------------------------------------------- -Version: 0.9.0 -Date: 11.09.2019 - Changes: - - Harvester Platforms now spawn on top of resources instead of transferring them to the harvester floor - - Harvester Platforms will now recall players on them if they're deployed when warping. - - ---------------------------------------------------------------------------------------------------- -Version: 0.8.9 -Date: 11.09.2019 - Changes: - - Fixed typos breaking planet packs and alien biomes. - - Fixed typo with boiler research - - Fixed typo with autowarp timer - - Added a bunch of various functions to the remote interface. - - Attempted fixes to votewarp for multiplayer (untested) - - Fixed homeworld button - ---------------------------------------------------------------------------------------------------- -Version: 0.8.8 -Date: 10.09.2019 - Changes: - - Massive re-write and code cleanup - - Fixed bugs related to multiple planets (eg. homeworld plus platform) with special chunk generation functions interfering with eachother, particularly for multiplayer. - - Tri-loader now adds an extra belt pair to ALL stairs, making the central stairs have 6 belts instead of 4. - - New Harvester Floor below the boiler and a new relating gameplay mechanic. - - Made a bunch of things use locale for translation later - - Fixed the teleporter logistics blocked message on warp - - Moved first boiler room water research to blue science - - Fixed water placement bugs - - Made platform "turrets" research a bit cheaper, and moved the first level to green science. - - Broke Warp Loaders - - Slightly adjusted alignment of warp rails - - Made warp charge timer (entity counter thing) ignore surface/planet entities - - ---------------------------------------------------------------------------------------------------- -Version: 0.8.7 -Date: 26.08.2019 - Changes: - - Added sound to warp button and a message for multiplayer - - Fixed a bug with planet selector - ---------------------------------------------------------------------------------------------------- -Version: 0.8.6 -Date: 24.08.2019 - Changes: - - More pollution nerfs - - Added pollution exponent multiplier setting - - Added pollution tick rate setting - - ---------------------------------------------------------------------------------------------------- -Version: 0.8.5 -Date: 22.08.2019 - Changes: - - Teleporter hitbox adjustments - ---------------------------------------------------------------------------------------------------- -Version: 0.8.4 -Date: 22.08.2019 - Changes: - - Mod Compatability: Von Neumann Mod. Please use v0.0.3 that i have posted if you wish to play that mod with this one: https://github.com/abaines/Von-Neumann/issues/1 - ---------------------------------------------------------------------------------------------------- -Version: 0.8.3 -Date: 22.08.2019 - Changes: - - Leftover test code - - ---------------------------------------------------------------------------------------------------- -Version: 0.8.2 -Date: 22.08.2019 - Changes: - - Full mod compatability: Force Fields 2 - https://mods.factorio.com/mod/ForceFields2 - ---------------------------------------------------------------------------------------------------- -Version: 0.8.1 -Date: 22.08.2019 - Changes: - - Fixed a bug with the Stone planet - - Review for multiplayer planet selection drop-down bug - - Mod Compatability: Added remote interface for other mods to prevent certain entities from being cloned by name - ---------------------------------------------------------------------------------------------------- -Version: 0.8.0 -Date: 21.08.2019 - Changes: - - Fixed a bug with circuits and loader chests - ---------------------------------------------------------------------------------------------------- -Version: 0.7.9 -Date: 21.08.2019 - Changes: - - New Planet: Smog Planet - - New Planet: Mirror Planet - ---------------------------------------------------------------------------------------------------- -Version: 0.7.8 -Date: 21.08.2019 - Changes: - - Mod Compatability: Alien Biomes - bug fixing - - More pollution nerfs (reset settings in existing saves) - ---------------------------------------------------------------------------------------------------- -Version: 0.7.7 -Date: 20.08.2019 - Changes: - - Nerfed Pollution Factor - - Fixed a bug with autowarp on/off - - New Planet Expansion Pack: DangOreus Planet - ---------------------------------------------------------------------------------------------------- -Version: 0.7.6 -Date: 19.08.2019 - Changes: - - Waterless, Biter, and "Rest" Planets can no longer occur twice in a row respectively. - - Moved the first teleporter research into it's own research - - Mod Compatability: Big Brother radars - - Mod Compatability: Alien Biomes - Fixed a bug with water not spawning on planets - - Mod Compatability: Alien Biomes - Fixed a multiplayer desync issue - ---------------------------------------------------------------------------------------------------- -Version: 0.7.5 -Date: 17.08.2019 - Changes: - - Fixed a bug with the warp target dropdown in multiplayer - ---------------------------------------------------------------------------------------------------- -Version: 0.7.4 -Date: 17.08.2019 - Changes: - - Added more mod remote commands - - Added tile overrides to disable certain tiles unless otherwise enabled. - ---------------------------------------------------------------------------------------------------- -Version: 0.7.3 -Date: 17.08.2019 - Changes: - - migration issues - ---------------------------------------------------------------------------------------------------- -Version: 0.7.2 -Date: 17.08.2019 - Changes: - - More bug fix - ---------------------------------------------------------------------------------------------------- -Version: 0.7.1 -Date: 17.08.2019 - Changes: - - Progress on mod compatability Alien Biomes - ---------------------------------------------------------------------------------------------------- -Version: 0.7.0 -Date: 17.08.2019 - Changes: - - Fixed gui not updating on autowarp settings changes - - Added a fix to make spawn area resources spawn further away from the platform as it gets bigger (this apparently did nothing) - - ---------------------------------------------------------------------------------------------------- -Version: 0.6.9 -Date: 17.08.2019 - Changes: - - Mod setting for %chance of landing on selected planet - - Added Warp Portal item - ---------------------------------------------------------------------------------------------------- -Version: 0.6.8 -Date: 17.08.2019 - Changes: - - Fixed a bug with the warp charge timer - - Fixed a bug with the planets gui dropdown - - Fixed missing ocean planet description - - Planets API tweaks - - Fixed player corpse between warps - ---------------------------------------------------------------------------------------------------- -Version: 0.6.7 -Date: 15.08.2019 - Changes: - - Added fix for dropped items being lost on warp - - More 0.6.5 typos - ---------------------------------------------------------------------------------------------------- -Version: 0.6.6 -Date: 15.08.2019 - Changes: - - Added missing multiplier for original map settings starting_area and water - - 0.6.5 typo - ---------------------------------------------------------------------------------------------------- -Version: 0.6.5 -Date: 15.08.2019 - Changes: - - Fixed a big with picking up warp heatpipes - - Fixed a bug with the early boiler room water setting not working when starting a new map with it enabled (migration for this is done too) - - Added checks to ensure resource specific planets are not spawned if a mod is added that removes base game resources. - - Fixed a bug with modded ores not appearing on any planets - - Fixed interactions with Factorissimo2 - - More progress on Alien Biomes compatability (trees and such should spawn now). It should only spawn nauvis-like planets currently. - ---------------------------------------------------------------------------------------------------- -Version: 0.6.4 -Date: 12.08.2019 - Changes: - - Fixed typos in 0.6.3 - - ---------------------------------------------------------------------------------------------------- -Version: 0.6.3 -Date: 12.08.2019 - Changes: - - Temporarily disabled loader mod detection - - Re-wrote the planet generator with improved mod compatability and improved api - - Tweaked a bunch of planet generation settings - - Added Uncharted planet - ---------------------------------------------------------------------------------------------------- -Version: 0.6.2 -Date: 12.08.2019 - Changes: - - Added mod compatability: Mods that introduce new/faster loaders will replace the existing platform loaders at logistics level 4. Exception: miniloaders - - Prep for mod compatible planet generator update - ---------------------------------------------------------------------------------------------------- -Version: 0.6.1 -Date: 11.08.2019 - Changes: - - Fixed a crash related to Alien Biomes - ---------------------------------------------------------------------------------------------------- -Version: 0.6.0 -Date: 10.08.2019 - Changes: - - Bug Fix - - More progress on mod compatability: Alien Biomes - ---------------------------------------------------------------------------------------------------- -Version: 0.5.9 -Date: 10.08.2019 - Changes: - - Completed Mod Extendable Planets. - - Official Warptorio2 Planet Pack: https://mods.factorio.com/mod/warptorio_planet_pack - - Progress on mod compatability: Alien Biomes. - - Progress on mod compatability for modded ores - ---------------------------------------------------------------------------------------------------- -Version: 0.5.8 -Date: 10.08.2019 - Changes: - - Added Biter Waves, ensuring biter attacks always happen - - Added Biter Wave difficulty settings - - Added a tiny bit of pollution to everything (such as chests, inserters) - ---------------------------------------------------------------------------------------------------- -Version: 0.5.7 -Date: 10.08.2019 - Changes: - - Adjusted spawn settings of the Barren planet - - Added Rogue planet - ---------------------------------------------------------------------------------------------------- -Version: 0.5.6 -Date: 10.08.2019 - Changes: - - Added votewarp multiplier mod setting - ---------------------------------------------------------------------------------------------------- -Version: 0.5.5 -Date: 10.08.2019 - Changes: - - Added nauvis_override to the modded planet api - - Added votewarp for multiplayer (untested) - - Reversed direction of logistics on north half of platform. - - Added mod settings allowing you to set the direction of platform logistics (north and south halves) - - ---------------------------------------------------------------------------------------------------- -Version: 0.5.4 -Date: 10.08.2019 - Changes: - - Full factorissimo mod support - - Fixed a bug with the southeast and southwest warp rails - - Fixed a bug with corner stairs not benefiting from stairs energy research - - Known Issue: Multiplayer Desync related to cloning accumulators. This is a factorio bug: https://forums.factorio.com/viewtopic.php?f=7&t=74363 - ---------------------------------------------------------------------------------------------------- -Version: 0.5.3 -Date: 09.08.2019 - Changes: - - Minor bug fixing - - ---------------------------------------------------------------------------------------------------- -Version: 0.5.2 -Date: 09.08.2019 - Changes: - - Minor bug fix - ---------------------------------------------------------------------------------------------------- -Version: 0.5.1 -Date: 09.08.2019 - Changes: - - Minor bug fix - ---------------------------------------------------------------------------------------------------- -Version: 0.5.0 -Date: 09.08.2019 - Changes: - - Added expert difficulty mod setting: autowarp is always on - - Added more mod settings for pollution factor and biter expansion rates - - Small nerf to biter expansion rates - - Added auto warp time mod setting - - ---------------------------------------------------------------------------------------------------- -Version: 0.4.9 -Date: 09.08.2019 - Changes: - - More work on remote interface for other mods to expand the warptorio planets table. Please refer to FAQ. - - ---------------------------------------------------------------------------------------------------- -Version: 0.4.8 -Date: 09.08.2019 - Changes: - - Mod compatability with Dirt Path - - Added remote interface for other mods to expand the warptorio planets table - ---------------------------------------------------------------------------------------------------- -Version: 0.4.7 -Date: 09.08.2019 - Changes: - - Added mod settings weighted planet probability of occurrence - - Fixed a crash related to loot chests - ---------------------------------------------------------------------------------------------------- -Version: 0.4.6 -Date: 09.08.2019 - Changes: - - Added carebear difficulty mod setting: Early boiler room water - ---------------------------------------------------------------------------------------------------- -Version: 0.4.5 -Date: 08.08.2019 - Changes: - - Added carebear difficulty mod setting: spawns a loot chest of items you'll need to get you through the first few planets alive for those that need help. - - Reduced base autowarp timer to 20 mins to better match biter evolution in the early game. - ---------------------------------------------------------------------------------------------------- -Version: 0.4.4 -Date: 08.08.2019 - Changes: - - General code cleanup and organising - - Added mod setting to turn off autowarp earlier than reactor level 6. - - Added mod settings to change warp charge time calculations and ability cooldowns. - ---------------------------------------------------------------------------------------------------- -Version: 0.4.3 -Date: 06.08.2019 - Changes: - - Fixed mp issue - - Added more provider chest options - ---------------------------------------------------------------------------------------------------- -Version: 0.4.2 -Date: 06.08.2019 - Changes: - - Miniaturized the "invisible" radar. - - Added mod settings allowing selection of requester/provider chests used with teleporter and stairs loaders. - ---------------------------------------------------------------------------------------------------- -Version: 0.4.1 -Date: 06.08.2019 - Changes: - - Fixed a bug with warp rail loaders and chests not switching direction - ---------------------------------------------------------------------------------------------------- -Version: 0.4.0 -Date: 06.08.2019 - Changes: - - Reduced warp charge time growth - - Fixed a bunch of sizing and alignment issues - - Big code cleanup intended for improved mod compatability, performance and reliability. - - Reactor research tweaks - - Invisible radar to factory and boiler floors (requires charting). - - Fixed a multiplayer crash - ---------------------------------------------------------------------------------------------------- -Version: 0.3.9 -Date: 06.08.2019 - Changes: - - Fixed missing beacon levels - - Fixed some lag issues when staying on a planet for too long - ---------------------------------------------------------------------------------------------------- -Version: 0.3.8 -Date: 05.08.2019 - Changes: - - Added crash protection for mods that remove base game resources - ---------------------------------------------------------------------------------------------------- -Version: 0.3.7 -Date: 04.08.2019 - Changes: - - Fixed a bug with reactor removing itself between warps - - Fixed factory beacon placement issues - - Added changelog formatting for in-game viewing - ---------------------------------------------------------------------------------------------------- -Version: 0.3.6 -Date: 04.08.2019 - Changes: - - Slightly reduced final platform size upgrade - ---------------------------------------------------------------------------------------------------- -Version: 0.3.5 -Date: 04.08.2019 - Changes: - - More research tweaks - - Fixed a crash caused by even distribution mod - ---------------------------------------------------------------------------------------------------- -Version: 0.3.4 -Date: 2019.08.03 - Changes: - - Added homeworld - - Tweaked beacon research - ---------------------------------------------------------------------------------------------------- -Version: 0.3.3 -Date: 03.08.2019 - Changes: - - Pumps are now correctly removed from platform between warps - - Removed additional stairs belts, max is now 4. - - New space science: Warp Loaders. - ---------------------------------------------------------------------------------------------------- -Version: 0.3.2 -Date: 03.08.2019 - Changes: - - Fixed bug with giga boiler floors unlocking early - - Reduced cost of research - ---------------------------------------------------------------------------------------------------- -Version: 0.3.1 -Date: 01.08.2019 - Changes: - - Added caching for warp accumulators and heatpipes to save frames - - Added missing purple science packs to logistics research - - Fixed sizing and alignment of boiler giga floors - ---------------------------------------------------------------------------------------------------- -Version: 0.3.0 -Date: 01.08.2019 - Changes: - - Tweaked occurrence rate and zones of planets - - More pollution tweaks - - Tweaked axe speed, physical damage and warp beacon research - - Fixed random deaths when warping while you're standing on the edge of the platform - - Planets will now correctly copy settings from original map generation. - ---------------------------------------------------------------------------------------------------- -Version: 0.2.9 -Date: 31.07.2019 - Changes: - - Added Warp Accumulators - - Further tweaks to pollution settings - - Added alarm to auto-warp - - fixed logistics bots between warps - ---------------------------------------------------------------------------------------------------- -Version: 0.2.8 -Date: 30.07.2019 - Changes: - - Added some vanilla bullet damage upgrades - - Tweaked initial and stabilizer pollution settings - ---------------------------------------------------------------------------------------------------- -Version: 0.2.7 -Date: 29.07.2019 - Changes: - - Tweaked the Polluted planet - - Added Dwarf Planet - - Changed some planet descriptions - - Fixed a bug with logistics chests not functioning correctly between floors - ---------------------------------------------------------------------------------------------------- -Version: 0.2.6 -Date: 29.07.2019 - Changes: - - Reduced warp multipliers for end game planets - - Tweaked resource spawning on specialized planets and disabled spawn area resource removal - ---------------------------------------------------------------------------------------------------- -Version: 0.2.5 -Date: 27.07.2019 - Changes: - - Fixed a bug with placing the teleporter gate causes the platform teleporter chests to empty - - Slightly reduced warp robot speed bonus - - Fixed a bug with dual loader research not applying to boiler floor - ---------------------------------------------------------------------------------------------------- -Version: 0.2.4 -Date: 27.07.2019 - Changes: - - Fixed a bug with upgrading energy causing loss of logistics in boiler room. - - Made early game research slightly more expensive - ---------------------------------------------------------------------------------------------------- -Version: 0.2.3 -Date: 27.07.2019 - Changes: - - Mic Drop - ---------------------------------------------------------------------------------------------------- -Version: 0.2.2 -Date: 27.07.2019 - Changes: - - Major Branch split from warptorio_0.2.1. Credit to Nonoce https://mods.factorio.com/mod/warptorio - - Updated everything - - Fixed everything - - Finished everything - - Polished everything - - Added a whole bunch of new stuff +--------------------------------------------------------------------------------------------------- +Version: 2.0.0 +Date: 09.05.2025 + Major changes: + - Updated to Factorio 2.0 (thanks to Shadow_Man) + - Space Age is not supported. Elevated Rails and Quality is supported. + - New game recommended. No migration support for previous savegames. + Changes: + - Added custom Warptorio2 intro text and victory screen. + - Changed some technologies research cost to better match similar vanilla techs. + - Changed some recipes with non-stacking ingredients to have only 1 of these ingredients. + +--------------------------------------------------------------------------------------------------- +Version: 1.3.11 +Date: 18.2.2024 + Changes: + - Added a mod setting to disable stair sprites. + - Changed default provider chest to passive provider by popular demand + - Slightly increased the chance for loot chests to spawn and added a setting for it + - Changed warp reactor specific heat from 10MJ to 1MJ to address heat distribution issues + - Updated heat related code to better respect specific heats (Thanks chingis_khagan!) + +--------------------------------------------------------------------------------------------------- +Version: 1.3.10 +Date: 8.5.2023 + Changes: + - Fixed crash when setting warp target to homeworld or nauvis. + - Fixed the Charting ability where the button wasnt adding to the hud and wasnt spawning invisible radars on the factory and boiler floors when the research finishes. + - Fixed two Typ"};o's in the Warptorio Lore messages (Thanks Honktown!) + - Fixed Warp Armor and Warp Accumulator tech icons (Thanks Knofbath!) + - Removed incompatibility flag with Rampant because Rampant now has multi-surface compatibility. + - Removed placeable-by on warp pipes to prevent accidental placement of them. + - Buffed Warponium Fuel Cells, they are now more accurately 4x more powerful than a typical uranium fuel cell as originally intended (Thanks Knofbath!) + - Buffed Stabilizer ability and rephrased its description for clarity + - Updated to Factorio 1.1.80 + +--------------------------------------------------------------------------------------------------- +Version: 1.3.9 +Date: 5.7.2022 + Changes: + - Fixed a bug with warp pre-charge speed upgrades where upgrading made pre-charging slower + - Fixed the harvester loaders bug + migration with help from community (Thank you!) + +--------------------------------------------------------------------------------------------------- +Version: 1.3.8 +Date: 8.4.2022 + Changes: + - Typo + +--------------------------------------------------------------------------------------------------- +Version: 1.3.7 +Date: 7.4.2022 + Changes: + - Lib bugfix related to cloning spider legs + +--------------------------------------------------------------------------------------------------- +Version: 1.3.6 +Date: 7.3.2022 + Changes: + - Fixed green wire circuits not connecting between stairs + migration + - Fixed void tiles not being placed if the platform warps away without you + - Added fix for crashes related to warp loaders & filters with help from community (Thank you!) + - Teleporter gate now has flying text when logistics cannot be placed instead of a global message. + +--------------------------------------------------------------------------------------------------- +Version: 1.3.5 +Date: 13.3.2021 + Changes: + - Fixed multiplayer crash, missing nil check on updating ownership and connection of cloned spidertrons to the remotes in players inventories between warps. + +--------------------------------------------------------------------------------------------------- +Version: 1.3.4 +Date: 30.12.2020 + Changes: + - Factorio 1.1.6 + + +--------------------------------------------------------------------------------------------------- +Version: 1.3.3 +Date: 3.12.2020 + Changes: + - Factorio 1.1 + +--------------------------------------------------------------------------------------------------- +Version: 1.3.2 +Date: 4.11.2020 + Changes: + - Spidertron can now travel through stairs (cloning method) + - Fixed decoupling of spidertron remotes when warping/cloning + - You now remain in your spidertron when warping. + +--------------------------------------------------------------------------------------------------- +Version: 1.3.1 +Date: 25.8.2020 + Changes: + - Basic fixes for warp loaders + - Fixed spidertron being lost between warps + - Fixed a crash when using steel loader chests + +--------------------------------------------------------------------------------------------------- +Version: 1.3.0 +Date: 8.8.2020 + Changes: + - Fixed rails not being affected by logistics upgrades + - Made hazard tiles accurate and fixed hazard clearing crash + - typo causing crash on warp + +--------------------------------------------------------------------------------------------------- +Version: 1.2.9 +Date: 2.8.2020 + Changes: + - Fixed invisible radars & homeworld/platform teleport capsules + - e (typo) + - v (typo) + - Buffed stabilizer to 5% of regular platform pollution + - Fixed ability drain % texts and added setting + - Turned on warp blacklists for harvesters (fixes some mod compatabilities) + - Factorio 0.18.40 + + +--------------------------------------------------------------------------------------------------- +Version: 1.2.8 +Date: 12.5.2020 + Changes: + - Fixed a few bugs + + +--------------------------------------------------------------------------------------------------- +Version: 1.2.7 +Date: 7.5.2020 + Changes: + - Warptorio Expansion Update + - Large changes to remote interfaces + - Moved planet rng settings to planetorio + - Fixed changing loader directions mid-game (top/bottom halves) + - Fixed a bunch of harvester bugs + +--------------------------------------------------------------------------------------------------- +Version: 1.2.6 +Date: 13.4.2020 + Changes: + - Factorio 0.18 + - Added /kill command to suicide (if you get stuck on ocean planet) + - Added biter warping difficulty setting + - Added Nauvis to warp target list + - Added warp pipes to the Harvesters + - Full rework of platform tileing/upgrading system enabling the creation of multiple platform layouts. + - Full rework of planets system, exported to standalone library mod Planetorio enabling other mod makers to create new planets and use the planets/surfaces system for their own mods. + - Reworked Abilities: All abilities now use platform electricity (kept in the stairs) to function. Abilities are toggleable and drain energy over time. The amount drained is the same for all abilities, and it increases the longer abilities remain active. The amount of energy drained, and energy drain growth is applied for all abilities active at once (1x for 1 ability active, 3x for 3 abilities active). Drain amounts are based on a % of the total electrical storage capacity. + - Added a Platform Energy bar to the HUD showing electricity balance to help with using the new ability mechanics. + - Reworked Stabilizer Ability: Platform pollution, and pollution growth reduced to 25% while active. + - Reworked Radar Ability: Scans an outer ring every few seconds while active (takes longer each successive scan) + - Fixed a bug with warpchance setting not applying to homeworld rolls + - Fixed a bug with pollution not being removed from harvester floor + - Broke warp loaders + - Broke the Accelerator ability (it does nothing for now) + - Broke the warptorio remote interface (affects cross mod compatabilities) + - Broke functionality related to changing loader directions (top/bottom halves) upon the settings being changed mid-game + - Broke "unstuck" on platform entities, e.g. you can become trapped in teleporters as you unlock them. + - Broke hazard tile accuracy + - Probably broke more things. + +--------------------------------------------------------------------------------------------------- +Version: 1.2.5 +Date: 13.11.2019 + Changes: + - Harvester deploy typo x2 (?) + - Harvesters now ignore planet-side logistics/construction robots when deployed + +--------------------------------------------------------------------------------------------------- +Version: 1.2.4 +Date: 13.11.2019 + Changes: + - Fixed a divide by zero error + - Harvester deploy typo (?) + + +--------------------------------------------------------------------------------------------------- +Version: 1.2.3 +Date: 13.11.2019 + Changes: + - Made "invisible" radars unminable + - Removed warpstation, warppipe and harvesters from circuit signals menu + - Added blacklists to harvesters + - Vehicles are now teleported between surfaces instead of cloned (AAI vehicles compatability). Not yet added to harvesters. + - Players are no longer teleported through platform teleporters if they are in a vehicle. + - Optimized teleporter code to save frames + - 10,000 Downloads Special: Compatibility with NewGamePlus courtesy of Bilka <3 + +--------------------------------------------------------------------------------------------------- +Version: 1.2.2 +Date: 31.10.2019 + Changes: + - Added ability_used and ticktime to remote events + - Added remote functions to recall the harvesters and teleporter gate + - Added robots outside of platform carry between warps difficulty setting (disabled by default). + - Fix for harvesters being permanently lost + - Added Home Portal item that teleports you to homeworld + - Buffed warp module productivity bonus for consistency + - Added new remotes for mod managed tables + - Warp pipes are now automatically emptied if neither side is connected to another pipe + - Added sprite overlays to stairs to reduce confusion on where it will send you (alt-mode only) + +--------------------------------------------------------------------------------------------------- +Version: 1.2.1 +Date: 10.10.2019 + Changes: + - Harvesters now prevent players getting stuck when being deployed. + - Another loot chest typo + +--------------------------------------------------------------------------------------------------- +Version: 1.2.0 +Date: 10.10.2019 + Changes: + - Typos with loot chests + - Fixed harvesters "moving" players when recalled on warp + - Attempted fixes of harvester deploy bug + +--------------------------------------------------------------------------------------------------- +Version: 1.1.9 +Date: 10.10.2019 + Changes: + - Fixed votewarp bug + - Updated logistics research descriptions + - Fixed warp pipe temperature bug + - Added SpawnLootChest to remote interface + - Added setting to turn on/off loot chests + - Fixed a crash related to clearing mod composite entities (eg. mini-loaders) + - Added some missing modifiers to the reach distance research + - Added Warp Striders research + - Made a few early researches require the reactor reassembly project + - Made a few other small research tweaks + - Added steel chest to Requester chest type settings + +--------------------------------------------------------------------------------------------------- +Version: 1.1.8 +Date: 2.10.2019 + Changes: + - Attempted fixes of sound stacking problem + - Fixed platform turret warping alignment x2 + +--------------------------------------------------------------------------------------------------- +Version: 1.1.7 +Date: 30.09.2019 + Changes: + - Reduced cost of Warponium Fuel Cells + - Fixed teleporter sounds + - Fixed warp beacon (?) + - Changed warp pipe pipette + - Fixed player leave/join affecting votewarp + - Increased default votewarp fraction to 0.51 and now rounds up. (2 players in MP requires both players to vote before warping) + - Fixed platform turret warping alignment issue + - Fixed factory floor early research tile alignment issue + + +--------------------------------------------------------------------------------------------------- +Version: 1.1.6 +Date: 30.09.2019 + Changes: + - Fixed nauvis map gen settings not applying to uncharted planets and added copy_nauvis planet modifier. + - Fixed hazard tile indicator accuracy for stairs + - Fixed a bug with harvester recall and overlapping belts/entities being destroyed + +--------------------------------------------------------------------------------------------------- +Version: 1.1.5 +Date: 30.09.2019 + Changes: + - Made rotation checks more efficient + - Fixed Warp Rail logistics not being removed from blueprints. + - Fixed blueprints created from hotbar not being affected by blueprint checks. + - Mod Compatability attempted AAI Vehicles fixes + - Added toolbar and relating research for easy harvester and mobile gate pickup by popular demand + +--------------------------------------------------------------------------------------------------- +Version: 1.1.4 +Date: 29.09.2019 + Changes: + - Added "P" Planet Clock timer to Warp Combinator + - Added separate setting to disable biter waves (previously disabled under base expansion rate tickbox) + - Fix for harvester migration issue x3 + + +--------------------------------------------------------------------------------------------------- +Version: 1.1.3 +Date: 29.09.2019 + Changes: + - Fixed red X's in power statistics + - Made factory beacon research a bit more expensive + - Nerfed platform solar power by popular demand and added a difficulty setting + - Fix for harvester migration issue x2 + +--------------------------------------------------------------------------------------------------- +Version: 1.1.2 +Date: 29.09.2019 + Changes: + - Fixed bug with abilities not resetting on warp + - Attempted more fixes of multiplayer votewarp + - Added some locale to Warp Reactor research level 6 and 8 + - Fixed planet target dropdown unlocking early. + - Fix of harvester loaders migration issue + - Picking up harvesters now prevents inventory duplicates + - Tweaked sorting of harvester items and research (left is now on the left) + + +--------------------------------------------------------------------------------------------------- +Version: 1.1.1 +Date: 29.09.2019 + Changes: + - Migration error x2 + +--------------------------------------------------------------------------------------------------- +Version: 1.1.0 +Date: 28.09.2019 + Changes: + - Migration error + +--------------------------------------------------------------------------------------------------- +Version: 1.0.9 +Date: 28.09.2019 + Changes: + - Attempted fix of loader and boiler floor access migration issues + +--------------------------------------------------------------------------------------------------- +Version: 1.0.8 +Date: 27.09.2019 + Changes: + - Cleaned entity spam from circuit signals menu + - Mod compatability with Spell Pack + - Fixed Warp Loaders (old saves may need to rotate them to refresh/update) + +--------------------------------------------------------------------------------------------------- +Version: 1.0.7 +Date: 26.09.2019 + Changes: + - Planet API bugfix + - Removed some debug code + - Fixed migration power bug + - Fixed Warp Combinator alignments and bug with offset setting not applying + - Fixed Harvester alignment bug + tile migration + - Fixed bug with Harvester Combinators not moving for size upgrades + +--------------------------------------------------------------------------------------------------- +Version: 1.0.6 +Date: 25.09.2019 + Changes: + - Removed unused hazard tiles + - Moved Harvester Floor between boiler and factory, and adjusted research to match. + - Fixed Warp Accumulator recipe and item + - Fixed "Invisible" Radar being hidden by factory beacon/boiler substation upgrades + - Fixed minor factory floor misalignments + tile migration + +--------------------------------------------------------------------------------------------------- +Version: 1.0.5 +Date: 22.09.2019 + Changes: + - Fixed crash related to new blueprints thing + - Added Warp Combinators and related research + - Added Harvester Combinators and related research + - Fixed factory giga floors alignments + tile migration + +--------------------------------------------------------------------------------------------------- +Version: 1.0.4 +Date: 22.09.2019 + Changes: + - Fixed bug with teleporter gate not receiving power upgrades if logistics is blocked when it's placed + - Planet teleporter gate must now be rebuilt for logistics and loader upgrades to apply (prevents problems related to clearing space) + - Added fix for loader filters being lost between logistics and loader upgrades + - Fixed bug with players being moved between warps + - Fixed clearing bug with platform turrets + - Platform Structures are now removed from blueprints. This is potentially conflicting so there is a setting to disable this. + - New warptorio event handling. See remote.get_events() and remote.get_event(name). + + +--------------------------------------------------------------------------------------------------- +Version: 1.0.3 +Date: 21.09.2019 + Changes: + - Added a bunch of remote api events for future implementation and slightly adjusted naming of existing ones. + - Fixed harvester logistics research crash + - Fixed boiler floor, water and giga alignment issues + tile migration. + - Mod Compatability bugfix for ModMash + - Fixed tile migrations clearing harvesters + + +--------------------------------------------------------------------------------------------------- +Version: 1.0.2 +Date: 18.09.2019 + Changes: + - Fixed west harvester bugs + - Fixed east harvester loaders research bug + - Fixed boiler giga floor bridge alignment bugs + - Fixed bug with level 0 (entry) platform turret research not placing tiles on planet + - Fixed bug with harvester logistics not clearing space for loaders correctly + - Fixed boiler water alignment bugs + - Added tile migration. Saves may take a while to load. + +--------------------------------------------------------------------------------------------------- +Version: 1.0.1 +Date: 17.09.2019 + Changes: + - Fixed beacon issues + - Fixed carebear chest + - Attempted fix of logistics research occasional crash + - New thumbnail.png + +--------------------------------------------------------------------------------------------------- +Version: 1.0.0 +Date: 15.09.2019 + Changes: + - Fixed clearing alignment bug of platform circles + - Added migration to recall harvesters aiming to fix loader and alignment issues + +--------------------------------------------------------------------------------------------------- +Version: 0.9.9 +Date: 15.09.2019 + Changes: + - Fixed issue with reactor upgrade destroying teleporter + - Fixed bug with planet teleporter gate not using energy upgrades + +--------------------------------------------------------------------------------------------------- +Version: 0.9.8 +Date: 15.09.2019 + Changes: + - Fixed sizing bug for platform circles + +--------------------------------------------------------------------------------------------------- +Version: 0.9.7 +Date: 15.09.2019 + Changes: + - Fixed typos with carebear chest + - Adjusted size of harvester platform borders + - Added (up to) 3 loaders to the harvester platforms which are always connected to harvester floor. + - Harvesters are now recalled when the interior portal is mined (if deployed) + +--------------------------------------------------------------------------------------------------- +Version: 0.9.6 +Date: 13.09.2019 + Changes: + - Fixed harvester pickup portal bug + - More typos + +--------------------------------------------------------------------------------------------------- +Version: 0.9.5 +Date: 12.09.2019 + Changes: + - More typos + - Attempted fix of harvester recall crash + +--------------------------------------------------------------------------------------------------- +Version: 0.9.4 +Date: 12.09.2019 + Changes: + - Fixed typos with pipe logistics and warpout + +--------------------------------------------------------------------------------------------------- +Version: 0.9.3 +Date: 12.09.2019 + Changes: + - More typos + + +--------------------------------------------------------------------------------------------------- +Version: 0.9.2 +Date: 11.09.2019 + Changes: + - Fix for pipe logistics issue + - More typo fixes + + +--------------------------------------------------------------------------------------------------- +Version: 0.9.1 +Date: 11.09.2019 + Changes: + - (Hopefully) fixed a crash relating to fluids + - Added fix for migration bug relating to power between floors + + +--------------------------------------------------------------------------------------------------- +Version: 0.9.0 +Date: 11.09.2019 + Changes: + - Harvester Platforms now spawn on top of resources instead of transferring them to the harvester floor + - Harvester Platforms will now recall players on them if they're deployed when warping. + + +--------------------------------------------------------------------------------------------------- +Version: 0.8.9 +Date: 11.09.2019 + Changes: + - Fixed typos breaking planet packs and alien biomes. + - Fixed typo with boiler research + - Fixed typo with autowarp timer + - Added a bunch of various functions to the remote interface. + - Attempted fixes to votewarp for multiplayer (untested) + - Fixed homeworld button + +--------------------------------------------------------------------------------------------------- +Version: 0.8.8 +Date: 10.09.2019 + Changes: + - Massive re-write and code cleanup + - Fixed bugs related to multiple planets (eg. homeworld plus platform) with special chunk generation functions interfering with eachother, particularly for multiplayer. + - Tri-loader now adds an extra belt pair to ALL stairs, making the central stairs have 6 belts instead of 4. + - New Harvester Floor below the boiler and a new relating gameplay mechanic. + - Made a bunch of things use locale for translation later + - Fixed the teleporter logistics blocked message on warp + - Moved first boiler room water research to blue science + - Fixed water placement bugs + - Made platform "turrets" research a bit cheaper, and moved the first level to green science. + - Broke Warp Loaders + - Slightly adjusted alignment of warp rails + - Made warp charge timer (entity counter thing) ignore surface/planet entities + + +--------------------------------------------------------------------------------------------------- +Version: 0.8.7 +Date: 26.08.2019 + Changes: + - Added sound to warp button and a message for multiplayer + - Fixed a bug with planet selector + +--------------------------------------------------------------------------------------------------- +Version: 0.8.6 +Date: 24.08.2019 + Changes: + - More pollution nerfs + - Added pollution exponent multiplier setting + - Added pollution tick rate setting + + +--------------------------------------------------------------------------------------------------- +Version: 0.8.5 +Date: 22.08.2019 + Changes: + - Teleporter hitbox adjustments + +--------------------------------------------------------------------------------------------------- +Version: 0.8.4 +Date: 22.08.2019 + Changes: + - Mod Compatability: Von Neumann Mod. Please use v0.0.3 that i have posted if you wish to play that mod with this one: https://github.com/abaines/Von-Neumann/issues/1 + +--------------------------------------------------------------------------------------------------- +Version: 0.8.3 +Date: 22.08.2019 + Changes: + - Leftover test code + + +--------------------------------------------------------------------------------------------------- +Version: 0.8.2 +Date: 22.08.2019 + Changes: + - Full mod compatability: Force Fields 2 - https://mods.factorio.com/mod/ForceFields2 + +--------------------------------------------------------------------------------------------------- +Version: 0.8.1 +Date: 22.08.2019 + Changes: + - Fixed a bug with the Stone planet + - Review for multiplayer planet selection drop-down bug + - Mod Compatability: Added remote interface for other mods to prevent certain entities from being cloned by name + +--------------------------------------------------------------------------------------------------- +Version: 0.8.0 +Date: 21.08.2019 + Changes: + - Fixed a bug with circuits and loader chests + +--------------------------------------------------------------------------------------------------- +Version: 0.7.9 +Date: 21.08.2019 + Changes: + - New Planet: Smog Planet + - New Planet: Mirror Planet + +--------------------------------------------------------------------------------------------------- +Version: 0.7.8 +Date: 21.08.2019 + Changes: + - Mod Compatability: Alien Biomes - bug fixing + - More pollution nerfs (reset settings in existing saves) + +--------------------------------------------------------------------------------------------------- +Version: 0.7.7 +Date: 20.08.2019 + Changes: + - Nerfed Pollution Factor + - Fixed a bug with autowarp on/off + - New Planet Expansion Pack: DangOreus Planet + +--------------------------------------------------------------------------------------------------- +Version: 0.7.6 +Date: 19.08.2019 + Changes: + - Waterless, Biter, and "Rest" Planets can no longer occur twice in a row respectively. + - Moved the first teleporter research into it's own research + - Mod Compatability: Big Brother radars + - Mod Compatability: Alien Biomes - Fixed a bug with water not spawning on planets + - Mod Compatability: Alien Biomes - Fixed a multiplayer desync issue + +--------------------------------------------------------------------------------------------------- +Version: 0.7.5 +Date: 17.08.2019 + Changes: + - Fixed a bug with the warp target dropdown in multiplayer + +--------------------------------------------------------------------------------------------------- +Version: 0.7.4 +Date: 17.08.2019 + Changes: + - Added more mod remote commands + - Added tile overrides to disable certain tiles unless otherwise enabled. + +--------------------------------------------------------------------------------------------------- +Version: 0.7.3 +Date: 17.08.2019 + Changes: + - migration issues + +--------------------------------------------------------------------------------------------------- +Version: 0.7.2 +Date: 17.08.2019 + Changes: + - More bug fix + +--------------------------------------------------------------------------------------------------- +Version: 0.7.1 +Date: 17.08.2019 + Changes: + - Progress on mod compatability Alien Biomes + +--------------------------------------------------------------------------------------------------- +Version: 0.7.0 +Date: 17.08.2019 + Changes: + - Fixed gui not updating on autowarp settings changes + - Added a fix to make spawn area resources spawn further away from the platform as it gets bigger (this apparently did nothing) + + +--------------------------------------------------------------------------------------------------- +Version: 0.6.9 +Date: 17.08.2019 + Changes: + - Mod setting for %chance of landing on selected planet + - Added Warp Portal item + +--------------------------------------------------------------------------------------------------- +Version: 0.6.8 +Date: 17.08.2019 + Changes: + - Fixed a bug with the warp charge timer + - Fixed a bug with the planets gui dropdown + - Fixed missing ocean planet description + - Planets API tweaks + - Fixed player corpse between warps + +--------------------------------------------------------------------------------------------------- +Version: 0.6.7 +Date: 15.08.2019 + Changes: + - Added fix for dropped items being lost on warp + - More 0.6.5 typos + +--------------------------------------------------------------------------------------------------- +Version: 0.6.6 +Date: 15.08.2019 + Changes: + - Added missing multiplier for original map settings starting_area and water + - 0.6.5 typo + +--------------------------------------------------------------------------------------------------- +Version: 0.6.5 +Date: 15.08.2019 + Changes: + - Fixed a big with picking up warp heatpipes + - Fixed a bug with the early boiler room water setting not working when starting a new map with it enabled (migration for this is done too) + - Added checks to ensure resource specific planets are not spawned if a mod is added that removes base game resources. + - Fixed a bug with modded ores not appearing on any planets + - Fixed interactions with Factorissimo2 + - More progress on Alien Biomes compatability (trees and such should spawn now). It should only spawn nauvis-like planets currently. + +--------------------------------------------------------------------------------------------------- +Version: 0.6.4 +Date: 12.08.2019 + Changes: + - Fixed typos in 0.6.3 + + +--------------------------------------------------------------------------------------------------- +Version: 0.6.3 +Date: 12.08.2019 + Changes: + - Temporarily disabled loader mod detection + - Re-wrote the planet generator with improved mod compatability and improved api + - Tweaked a bunch of planet generation settings + - Added Uncharted planet + +--------------------------------------------------------------------------------------------------- +Version: 0.6.2 +Date: 12.08.2019 + Changes: + - Added mod compatability: Mods that introduce new/faster loaders will replace the existing platform loaders at logistics level 4. Exception: miniloaders + - Prep for mod compatible planet generator update + +--------------------------------------------------------------------------------------------------- +Version: 0.6.1 +Date: 11.08.2019 + Changes: + - Fixed a crash related to Alien Biomes + +--------------------------------------------------------------------------------------------------- +Version: 0.6.0 +Date: 10.08.2019 + Changes: + - Bug Fix + - More progress on mod compatability: Alien Biomes + +--------------------------------------------------------------------------------------------------- +Version: 0.5.9 +Date: 10.08.2019 + Changes: + - Completed Mod Extendable Planets. + - Official Warptorio2 Planet Pack: https://mods.factorio.com/mod/warptorio_planet_pack + - Progress on mod compatability: Alien Biomes. + - Progress on mod compatability for modded ores + +--------------------------------------------------------------------------------------------------- +Version: 0.5.8 +Date: 10.08.2019 + Changes: + - Added Biter Waves, ensuring biter attacks always happen + - Added Biter Wave difficulty settings + - Added a tiny bit of pollution to everything (such as chests, inserters) + +--------------------------------------------------------------------------------------------------- +Version: 0.5.7 +Date: 10.08.2019 + Changes: + - Adjusted spawn settings of the Barren planet + - Added Rogue planet + +--------------------------------------------------------------------------------------------------- +Version: 0.5.6 +Date: 10.08.2019 + Changes: + - Added votewarp multiplier mod setting + +--------------------------------------------------------------------------------------------------- +Version: 0.5.5 +Date: 10.08.2019 + Changes: + - Added nauvis_override to the modded planet api + - Added votewarp for multiplayer (untested) + - Reversed direction of logistics on north half of platform. + - Added mod settings allowing you to set the direction of platform logistics (north and south halves) + + +--------------------------------------------------------------------------------------------------- +Version: 0.5.4 +Date: 10.08.2019 + Changes: + - Full factorissimo mod support + - Fixed a bug with the southeast and southwest warp rails + - Fixed a bug with corner stairs not benefiting from stairs energy research + - Known Issue: Multiplayer Desync related to cloning accumulators. This is a factorio bug: https://forums.factorio.com/viewtopic.php?f=7&t=74363 + +--------------------------------------------------------------------------------------------------- +Version: 0.5.3 +Date: 09.08.2019 + Changes: + - Minor bug fixing + + +--------------------------------------------------------------------------------------------------- +Version: 0.5.2 +Date: 09.08.2019 + Changes: + - Minor bug fix + +--------------------------------------------------------------------------------------------------- +Version: 0.5.1 +Date: 09.08.2019 + Changes: + - Minor bug fix + +--------------------------------------------------------------------------------------------------- +Version: 0.5.0 +Date: 09.08.2019 + Changes: + - Added expert difficulty mod setting: autowarp is always on + - Added more mod settings for pollution factor and biter expansion rates + - Small nerf to biter expansion rates + - Added auto warp time mod setting + + +--------------------------------------------------------------------------------------------------- +Version: 0.4.9 +Date: 09.08.2019 + Changes: + - More work on remote interface for other mods to expand the warptorio planets table. Please refer to FAQ. + + +--------------------------------------------------------------------------------------------------- +Version: 0.4.8 +Date: 09.08.2019 + Changes: + - Mod compatability with Dirt Path + - Added remote interface for other mods to expand the warptorio planets table + +--------------------------------------------------------------------------------------------------- +Version: 0.4.7 +Date: 09.08.2019 + Changes: + - Added mod settings weighted planet probability of occurrence + - Fixed a crash related to loot chests + +--------------------------------------------------------------------------------------------------- +Version: 0.4.6 +Date: 09.08.2019 + Changes: + - Added carebear difficulty mod setting: Early boiler room water + +--------------------------------------------------------------------------------------------------- +Version: 0.4.5 +Date: 08.08.2019 + Changes: + - Added carebear difficulty mod setting: spawns a loot chest of items you'll need to get you through the first few planets alive for those that need help. + - Reduced base autowarp timer to 20 mins to better match biter evolution in the early game. + +--------------------------------------------------------------------------------------------------- +Version: 0.4.4 +Date: 08.08.2019 + Changes: + - General code cleanup and organising + - Added mod setting to turn off autowarp earlier than reactor level 6. + - Added mod settings to change warp charge time calculations and ability cooldowns. + +--------------------------------------------------------------------------------------------------- +Version: 0.4.3 +Date: 06.08.2019 + Changes: + - Fixed mp issue + - Added more provider chest options + +--------------------------------------------------------------------------------------------------- +Version: 0.4.2 +Date: 06.08.2019 + Changes: + - Miniaturized the "invisible" radar. + - Added mod settings allowing selection of requester/provider chests used with teleporter and stairs loaders. + +--------------------------------------------------------------------------------------------------- +Version: 0.4.1 +Date: 06.08.2019 + Changes: + - Fixed a bug with warp rail loaders and chests not switching direction + +--------------------------------------------------------------------------------------------------- +Version: 0.4.0 +Date: 06.08.2019 + Changes: + - Reduced warp charge time growth + - Fixed a bunch of sizing and alignment issues + - Big code cleanup intended for improved mod compatability, performance and reliability. + - Reactor research tweaks + - Invisible radar to factory and boiler floors (requires charting). + - Fixed a multiplayer crash + +--------------------------------------------------------------------------------------------------- +Version: 0.3.9 +Date: 06.08.2019 + Changes: + - Fixed missing beacon levels + - Fixed some lag issues when staying on a planet for too long + +--------------------------------------------------------------------------------------------------- +Version: 0.3.8 +Date: 05.08.2019 + Changes: + - Added crash protection for mods that remove base game resources + +--------------------------------------------------------------------------------------------------- +Version: 0.3.7 +Date: 04.08.2019 + Changes: + - Fixed a bug with reactor removing itself between warps + - Fixed factory beacon placement issues + - Added changelog formatting for in-game viewing + +--------------------------------------------------------------------------------------------------- +Version: 0.3.6 +Date: 04.08.2019 + Changes: + - Slightly reduced final platform size upgrade + +--------------------------------------------------------------------------------------------------- +Version: 0.3.5 +Date: 04.08.2019 + Changes: + - More research tweaks + - Fixed a crash caused by even distribution mod + +--------------------------------------------------------------------------------------------------- +Version: 0.3.4 +Date: 2019.08.03 + Changes: + - Added homeworld + - Tweaked beacon research + +--------------------------------------------------------------------------------------------------- +Version: 0.3.3 +Date: 03.08.2019 + Changes: + - Pumps are now correctly removed from platform between warps + - Removed additional stairs belts, max is now 4. + - New space science: Warp Loaders. + +--------------------------------------------------------------------------------------------------- +Version: 0.3.2 +Date: 03.08.2019 + Changes: + - Fixed bug with giga boiler floors unlocking early + - Reduced cost of research + +--------------------------------------------------------------------------------------------------- +Version: 0.3.1 +Date: 01.08.2019 + Changes: + - Added caching for warp accumulators and heatpipes to save frames + - Added missing purple science packs to logistics research + - Fixed sizing and alignment of boiler giga floors + +--------------------------------------------------------------------------------------------------- +Version: 0.3.0 +Date: 01.08.2019 + Changes: + - Tweaked occurrence rate and zones of planets + - More pollution tweaks + - Tweaked axe speed, physical damage and warp beacon research + - Fixed random deaths when warping while you're standing on the edge of the platform + - Planets will now correctly copy settings from original map generation. + +--------------------------------------------------------------------------------------------------- +Version: 0.2.9 +Date: 31.07.2019 + Changes: + - Added Warp Accumulators + - Further tweaks to pollution settings + - Added alarm to auto-warp + - fixed logistics bots between warps + +--------------------------------------------------------------------------------------------------- +Version: 0.2.8 +Date: 30.07.2019 + Changes: + - Added some vanilla bullet damage upgrades + - Tweaked initial and stabilizer pollution settings + +--------------------------------------------------------------------------------------------------- +Version: 0.2.7 +Date: 29.07.2019 + Changes: + - Tweaked the Polluted planet + - Added Dwarf Planet + - Changed some planet descriptions + - Fixed a bug with logistics chests not functioning correctly between floors + +--------------------------------------------------------------------------------------------------- +Version: 0.2.6 +Date: 29.07.2019 + Changes: + - Reduced warp multipliers for end game planets + - Tweaked resource spawning on specialized planets and disabled spawn area resource removal + +--------------------------------------------------------------------------------------------------- +Version: 0.2.5 +Date: 27.07.2019 + Changes: + - Fixed a bug with placing the teleporter gate causes the platform teleporter chests to empty + - Slightly reduced warp robot speed bonus + - Fixed a bug with dual loader research not applying to boiler floor + +--------------------------------------------------------------------------------------------------- +Version: 0.2.4 +Date: 27.07.2019 + Changes: + - Fixed a bug with upgrading energy causing loss of logistics in boiler room. + - Made early game research slightly more expensive + +--------------------------------------------------------------------------------------------------- +Version: 0.2.3 +Date: 27.07.2019 + Changes: + - Mic Drop + +--------------------------------------------------------------------------------------------------- +Version: 0.2.2 +Date: 27.07.2019 + Changes: + - Major Branch split from warptorio_0.2.1. Credit to Nonoce https://mods.factorio.com/mod/warptorio + - Updated everything + - Fixed everything + - Finished everything + - Polished everything + - Added a whole bunch of new stuff - Made sure that new stuff worked properly as ideally as possible. \ No newline at end of file diff --git a/control.lua b/control.lua index 54d8b9c..5d227f2 100644 --- a/control.lua +++ b/control.lua @@ -1,31 +1,29 @@ ---[[------------------------------------- - -Author: Pyro-Fire -https://mods.factorio.com/mod/warptorio2 - -Script: control.lua -Purpose: control stuff - - -Written using Microsoft Notepad. -IDE's are for children. - -How to notepad like a pro: -ctrl+f = find -ctrl+h = find & replace -ctrl+g = show/jump to line (turn off wordwrap n00b) - -Status bar wastes screen space, don't use it. - -Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. - -]]--------------------------------------- - ---[[ Environment ]]-- -lib={PLANETORIO=true,REMOTES=true} - -require("lib/lib") -require("control_main") -lib.lua() - - +--[[------------------------------------- + +Author: Pyro-Fire +https://mods.factorio.com/mod/warptorio2 + +Script: control.lua +Purpose: control stuff + + +Written using Microsoft Notepad. +IDE's are for children. + +How to notepad like a pro: +ctrl+f = find +ctrl+h = find & replace +ctrl+g = show/jump to line (turn off wordwrap n00b) + +Status bar wastes screen space, don't use it. + +Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. + +]] --------------------------------------- + +--[[ Environment ]] -- +lib = { PLANETORIO = true, REMOTES = true } + +require("lib/lib") +require("control_main") +lib.lua() diff --git a/control_class_harvester.lua b/control_class_harvester.lua index c453875..daa1f55 100644 --- a/control_class_harvester.lua +++ b/control_class_harvester.lua @@ -1,5 +1,3 @@ - - --[[ harvestpad item on upgrade @@ -14,415 +12,596 @@ harvestpad item on upgrade ]] ---[[ Harvesters ]]-- - -warptorio.HarvesterSizes={12,20,26,32,38,46} -function warptorio.GetHarvesterLevelSize(lv) local z=warptorio.HarvesterSizes[lv] return vector(z,z) end -function warptorio.GetHarvesterLevelSizeNum(lv) local z=warptorio.HarvesterSizes[lv] return z end - -local HARV={} HARV.__index=HARV warptorio.HarvesterMeta=HARV setmetatable(HARV,warptorio.TeleporterMeta) -function HARV.__init(self,tbl) - self.key=tbl.key - self.rank=1 - local t={} - table.merge(t,table.deepcopy(warptorio.platform.harvesters[self.key])) - table.merge(t,table.deepcopy(warptorio.platform.HarvesterPointData)) - self.gdata=t - warptorio.TeleporterMeta.__init(self,self) - self.position=tbl.position - - self.pipes=self.pipes or {{},{}} - self.loaders=self.loaders or {{},{}} - self.loaderFilter=self.loaderFilter or {{},{}} - self.combos=self.combos or {nil,nil} - if(not self.dir)then self.dir={{},{}} for i=1,6,1 do self.dir[1][i]="input" self.dir[2][i]="output" end end - - self.deployed=self.deployed or false - self.deploy_position=self.deploy_position or nil - self.gdata.pair[2].position=self.gdata.pair[2].position or self.deploy_position or self.position - self.gdata.pair[1].position=self.gdata.pair[1].position or self.position - self.chests=nil - - global.Harvesters[tbl.key]=self +--[[ Harvesters ]] -- + +warptorio.HarvesterSizes = { 12, 20, 26, 32, 38, 46 } +function warptorio.GetHarvesterLevelSize(lv) + local z = warptorio.HarvesterSizes[lv] + return vector(z, z) +end + +function warptorio.GetHarvesterLevelSizeNum(lv) + local z = warptorio.HarvesterSizes[lv] + return z +end + +local HARV = {} +HARV.__index = HARV +warptorio.HarvesterMeta = HARV +setmetatable(HARV, warptorio.TeleporterMeta) +function HARV.__init(self, tbl) + self.key = tbl.key + self.rank = 1 + local t = {} + table.merge(t, table.deepcopy(warptorio.platform.harvesters[self.key])) + table.merge(t, table.deepcopy(warptorio.platform.HarvesterPointData)) + self.gdata = t + warptorio.TeleporterMeta.__init(self, self) + self.position = tbl.position + + self.pipes = self.pipes or { {}, {} } + self.loaders = self.loaders or { {}, {} } + self.loaderFilter = self.loaderFilter or { {}, {} } + self.combos = self.combos or { nil, nil } + if (not self.dir) then + self.dir = { {}, {} } + for i = 1, 6, 1 do + self.dir[1][i] = "input" + self.dir[2][i] = "output" + end + end + + self.deployed = self.deployed or false + self.deploy_position = self.deploy_position or nil + self.gdata.pair[2].position = self.gdata.pair[2].position or self.deploy_position or self.position + self.gdata.pair[1].position = self.gdata.pair[1].position or self.position + self.chests = nil + + storage.Harvesters[tbl.key] = self end + function HARV:Data() return self.gdata end function HARV:GetSize(brank) - local tps=self:Data() - if(tps.fixed_level)then return warptorio.GetHarvesterLevelSizeNum(tps.fixed_level) end - local tcn=tps.tech - local lv=(brank and self.rank or warptorio.GetPlatformTechLevel(tcn)) + local tps = self:Data() + if (tps.fixed_level) then return warptorio.GetHarvesterLevelSizeNum(tps.fixed_level) end + local tcn = tps.tech + local lv = (brank and self.rank or warptorio.GetPlatformTechLevel(tcn)) return warptorio.GetHarvesterLevelSize(lv) end -function HARV:GetBaseArea(z,rank) z=z or self:GetSize(rank)-1 return vector.square(self.position,vector(z,z)) end -function HARV:GetDeployArea(z,rank) z=z or self:GetSize(rank)-2 return vector.square(vector.pos(self.deploy_position),vector(z,z)) end +function HARV:GetBaseArea(z, rank) + z = z or self:GetSize(rank) - 1 + return vector.square(self.position, vector(z, z)) +end + +function HARV:GetDeployArea(z, rank) + z = z or self:GetSize(rank) - 2 + return vector.square(vector.pos(self.deploy_position), vector(z, z)) +end function HARV:CheckTeleporterPairs(bSound) -- Call updates and stuff. Automatically deals with logistics, upgrades and cleaning as-needed with good accuracy - local tps=self:Data() - local wps=warptorio.platform.HarvesterPointData - self:MakePointTeleporter(wps,1,wps.pair[1],self.position) - if(self.deployed)then - self:MakePointTeleporter(wps,2,wps.pair[2],self.deploy_position) + local tps = self:Data() + local wps = warptorio.platform.HarvesterPointData + self:MakePointTeleporter(wps, 1, wps.pair[1], self.position) + if (self.deployed) then + self:MakePointTeleporter(wps, 2, wps.pair[2], self.deploy_position) end self:CheckPointLogistics(1) self:CheckPointLogistics(2) end function HARV:UpgradePlayerInventories() - for k,v in pairs(game.players)do if(v and v.valid)then local iv=v.get_main_inventory() if(iv)then for i,x in pairs(iv.get_contents())do - if(i:sub(1,20)=="warptorio-harvestpad" and i:sub(22,22+self.key:len())==self.key)then local lvx=tonumber(i:sub(-1,-1)) - if(lvx1)then iv.remove{name=i,count=(x-1)} end + for k, v in pairs(game.players) do + if (v and v.valid) then + local iv = v.get_main_inventory() + if (iv) then + for i, x in pairs(iv.get_contents()) do + if (x.name:sub(1, 20) == "warptorio-harvestpad" and x.name:sub(22, 22 + self.key:len()) == self.key) then + local lvx = tonumber(x.name:sub(-1, -1)) + if (lvx < lv) then + iv.remove { name = x.name, count = x.count } + iv.insert { name = cls, count = 1 } + elseif (x > 1) then + iv.remove { name = x.name, count = (x.count - 1) } + end + end + end + end end - end end end end + end end - -function HARV:MakePointTeleporter(tps,i,t,pos) - local p=self.points[i] - local f=global.floor[t.floor].host +function HARV:MakePointTeleporter(tps, i, t, pos) + local p = self.points[i] + local f = storage.floor[t.floor].host local epos - if(t.prototype)then - local vproto=t.prototype - if(tps.energy)then vproto=vproto.."-"..(warptorio.GetPlatformTechLevel(tps.energy)) end - local e=p.ent - if(isvalid(e))then - if(e.surface~=f)then self:DestroyPointTeleporter(i) self:DestroyPointLogistics(i) - elseif(e.name~=vproto)then epos=e.position self:DestroyPointTeleporter(i) + if (t.prototype) then + local vproto = t.prototype + if (tps.energy) then vproto = vproto .. "-" .. (warptorio.GetPlatformTechLevel(tps.energy)) end + local e = p.ent + if (isvalid(e)) then + if (e.surface ~= f) then + self:DestroyPointTeleporter(i) + self:DestroyPointLogistics(i) + elseif (e.name ~= vproto) then + epos = e.position + self:DestroyPointTeleporter(i) end end - if(not isvalid(e))then - local vepos=epos or (pos or t.position) - if(not vepos)then return end - local vpos=((t.gate and not epos) and f.find_non_colliding_position(vproto,vepos,0,1,1) or vepos) + if (not isvalid(e)) then + local vepos = epos or (pos or t.position) + if (not vepos) then return end + local vpos = ((t.gate and not epos) and f.find_non_colliding_position(vproto, vepos, 0, 1, 1) or vepos) local varea - if(not t.gate)then varea=vector.square(vpos,vector(2,2)) vector.clean(f,varea) end - e=entity.protect(entity.create(f,vproto,vpos),t.minable~=nil and t.minable or false,t.destructible~=nil and t.destructible or false) - if(not t.gate)then vector.cleanplayers(f,varea) end - p.ent=e + if (not t.gate) then + varea = vector.square(vpos, vector(2, 2)) + vector.clean(f, varea) + end + e = entity.protect(entity.create(f, vproto, vpos), t.minable ~= nil and t.minable or false, + t.destructible ~= nil and t.destructible or false) + if (not t.gate) then vector.cleanplayers(f, varea) end + p.ent = e end - if(p.energy)then e.energy=e.energy+p.energy p.energy=nil end - if(t.sprites)then self:MakePointSprites(tps,i,t.sprites) end - if(t.sprite_arrow)then self:MakePointArrow(tps,i,t.sprite_arrow) end + if (p.energy) then + e.energy = e.energy + p.energy + p.energy = nil + end + if (t.sprites) then self:MakePointSprites(tps, i, t.sprites) end + if (t.sprite_arrow) then self:MakePointArrow(tps, i, t.sprite_arrow) end end - if(epos or not t.gate)then self:CheckPointLogistics(i) end - - cache.force_entity(p.ent,"Harvesters",self.key,"points",i) + if (epos or not t.gate) then self:CheckPointLogistics(i) end + cache.force_entity(p.ent, "Harvesters", self.key, "points", i) end function HARV:RunUpgrade() - local tps=self:Data() - local vz=self:GetSize() - local lv=warptorio.GetPlatformTechLevel(tps.tech) + local tps = self:Data() + local vz = self:GetSize() + local lv = warptorio.GetPlatformTechLevel(tps.tech) - local f=global.floor[tps.pair[1].floor].host + local f = storage.floor[tps.pair[1].floor].host - local pos=tps.position - if(not self.deployed)then - local bh=warptorio.platform.floors.harvester.BuildHarvester -- bridges first - if(bh[self.key])then bh[self.key](f) end + local pos = tps.position + if (not self.deployed) then + local bh = warptorio.platform.floors.harvester.BuildHarvester -- bridges first + if (bh[self.key]) then bh[self.key](f) end - local lvm=math.max(lv*2,2) -- Makes buffer area around the harvesters - vector.LayTiles("warp-tile-concrete",f,vector.square(tps.position,vector(vz+lvm,vz+lvm))) - vector.LayTiles("warptorio-red-concrete",f,vector.square(tps.position,vector(vz-2,vz-2))) + local lvm = math.max(lv * 2, 2) -- Makes buffer area around the harvesters + vector.LayTiles("warp-tile-concrete", f, vector.square(tps.position, vector(vz + lvm, vz + lvm))) + vector.LayTiles("warptorio-red-concrete", f, vector.square(tps.position, vector(vz - 2, vz - 2))) self:CheckTeleporterPairs(true) end - if(research.has("warptorio-logistics-1"))then + if (research.has("warptorio-logistics-1")) then self:DestroyPointLogistics(1) self:CheckPointLogistics(1) - if(not self.deployed)then self:DestroyPointLogistics(2) self:CheckPointLogistics(2) end + if (not self.deployed) then + self:DestroyPointLogistics(2) + self:CheckPointLogistics(2) + end end self:DestroyCombos() self:CheckCombo() self:UpgradePlayerInventories() -- upgrade their harvestpads for this harvester (if needed) - self.rank=lv + self.rank = lv end +function HARV:Upgrade() + self.ReadyUpgrade = true + if (not self.deployed) then self:DoUpgrade() end +end -function HARV:Upgrade() self.ReadyUpgrade=true if(not self.deployed)then self:DoUpgrade() end end -function HARV:DoUpgrade() if(self.ReadyUpgrade)then self.ReadyUpgrade=false self:RunUpgrade() end end +function HARV:DoUpgrade() + if (self.ReadyUpgrade) then + self.ReadyUpgrade = false + self:RunUpgrade() + end +end + +--[[ Harvester Combinator ]] -- + +function HARV:ConnectCombo() + if (not self.deployed and self:ValidCombos()) then + local red1 = self.combos[1].get_wire_connector(defines.wire_connector_id.circuit_red, true) + local red2 = self.combos[2].get_wire_connector(defines.wire_connector_id.circuit_red, true) + red1.connect_to(red2) + local green1 = self.combos[1].get_wire_connector(defines.wire_connector_id.circuit_green, true) + local green2 = self.combos[2].get_wire_connector(defines.wire_connector_id.circuit_green, true) + green1.connect_to(green2) + -- self.combos[1].connect_neighbour({target_entity=self.combos[2],wire=defines.wire_type.red}) + -- self.combos[1].connect_neighbour({target_entity=self.combos[2],wire=defines.wire_type.green}) + end +end + +function HARV:ValidCombos() return isvalid(self.combos[1]) and isvalid(self.combos[2]) end +function HARV:CheckCombo() + if (research.has("warptorio-alt-combinator")) then + self:MakeComboA() + self:MakeComboB() + self:ConnectCombo() + end +end ---[[ Harvester Combinator ]]-- +function HARV:DestroyComboA() + if (isvalid(self.combos[1])) then entity.destroy(self.combos[1]) end + self.combos[1] = nil +end +function HARV:DestroyComboB() + if (isvalid(self.combos[2])) then entity.destroy(self.combos[2]) end + self.combos[2] = nil +end -function HARV:ConnectCombo() if(not self.deployed and self:ValidCombos())then - self.combos[1].connect_neighbour({target_entity=self.combos[2],wire=defines.wire_type.red}) self.combos[1].connect_neighbour({target_entity=self.combos[2],wire=defines.wire_type.green}) -end end -function HARV:ValidCombos() return isvalid(self.combos[1]) and isvalid(self.combos[2]) end -function HARV:CheckCombo() if(research.has("warptorio-alt-combinator"))then self:MakeComboA() self:MakeComboB() self:ConnectCombo() end end -function HARV:DestroyComboA() if(isvalid(self.combos[1]))then entity.destroy(self.combos[1]) end self.combos[1]=nil end -function HARV:DestroyComboB() if(isvalid(self.combos[2]))then entity.destroy(self.combos[2]) end self.combos[2]=nil end -function HARV:DestroyCombos() self:DestroyComboA() self:DestroyComboB() end - -function HARV:MakeComboA() local vx=self.points[1].ent - local cfg=settings.global.warptorio_combinator_offset.value local ofv if(cfg)then ofv=(self.key=="east" and 1 or 1.5) else ofv=0 end - local vpos=vector.pos(vx.position)+vector(self:GetSize().x/2*(self.key=="east" and 1 or -1)+ofv,0) - vector.clean(vx.surface,vector.square(vpos,vector(0.5,0.5))) - local e=entity.protect(entity.create(vx.surface,"warptorio-alt-combinator",vpos),false,false) - self.combos[1]=e - - cache.force_entity(e,"Harvesters",self.key,"combos",1) +function HARV:DestroyCombos() + self:DestroyComboA() + self:DestroyComboB() end -function HARV:MakeComboB() local vx=(isvalid(self.points[2].ent) and self.points[2].ent or self.points[1].ent) - local cfg=settings.global.warptorio_combinator_offset.value local ofv if(cfg)then ofv=(self.key=="east" and -2 or -1) else ofv=(self.key=="east" and -1 or 1) end - local vpos=vector.pos(vx.position)+vector(self:GetSize().x/2*(self.key=="east" and 1 or -1)+ofv,0) - vector.clean(vx.surface,vector.square(vpos,vector(0.5,0.5))) - local e=entity.protect(entity.create(vx.surface,"warptorio-alt-combinator",vpos),false,false) - self.combos[2]=e - - cache.force_entity(e,"Harvesters",self.key,"combos",2) + +function HARV:MakeComboA() + local vx = self.points[1].ent + local cfg = settings.global.warptorio_combinator_offset.value + local ofv + if (cfg) then ofv = (self.key == "east" and 1 or 1.5) else ofv = 0 end + local vpos = vector.pos(vx.position) + vector(self:GetSize().x / 2 * (self.key == "east" and 1 or -1) + ofv, 0) + vector.clean(vx.surface, vector.square(vpos, vector(0.5, 0.5))) + local e = entity.protect(entity.create(vx.surface, "warptorio-alt-combinator", vpos), false, false) + self.combos[1] = e + + cache.force_entity(e, "Harvesters", self.key, "combos", 1) end ---[[ Harvester Logistics ]]-- +function HARV:MakeComboB() + local vx = (isvalid(self.points[2].ent) and self.points[2].ent or self.points[1].ent) + local cfg = settings.global.warptorio_combinator_offset.value + local ofv + if (cfg) then ofv = (self.key == "east" and -2 or -1) else ofv = (self.key == "east" and -1 or 1) end + local vpos = vector.pos(vx.position) + vector(self:GetSize().x / 2 * (self.key == "east" and 1 or -1) + ofv, 0) + vector.clean(vx.surface, vector.square(vpos, vector(0.5, 0.5))) + local e = entity.protect(entity.create(vx.surface, "warptorio-alt-combinator", vpos), false, false) + self.combos[2] = e + + cache.force_entity(e, "Harvesters", self.key, "combos", 2) +end -function HARV:MakePointPipes(tps,i,id,pos,f,lddir,belty,vexdir) - local pipe="warptorio-logistics-pipe" - local v=self.pipes[i][id] - local vpos=vector(pos)+vector(vexdir)+vector(belty) - if(isvalid(v) and (v.surface~=f or v.position.x~=vpos.x or v.position.y~=vpos.y))then entity.destroy(v) end - if(not isvalid(v))then - local varea=vector.square(vpos,vector(0.5,0.5)) - vector.clean(f,varea) - v=entity.protect(entity.create(f,pipe,vpos,lddir),false,false) - self.pipes[i][id]=v +--[[ Harvester Logistics ]] -- + +function HARV:MakePointPipes(tps, i, id, pos, f, lddir, belty, vexdir) + local pipe = "warptorio-logistics-pipe" + local v = self.pipes[i][id] + local vpos = vector(pos) + vector(vexdir) + vector(belty) + if (isvalid(v) and (v.surface ~= f or v.position.x ~= vpos.x or v.position.y ~= vpos.y)) then entity.destroy(v) end + if (not isvalid(v)) then + local varea = vector.square(vpos, vector(0.5, 0.5)) + vector.clean(f, varea) + v = entity.protect(entity.create(f, pipe, vpos, lddir), false, false) + self.pipes[i][id] = v end - cache.force_entity(v,"Harvesters",self.key,"pipes",i,id) + cache.force_entity(v, "Harvesters", self.key, "pipes", i, id) end -function HARV:MakePointLoader(tps,i,id,pos,f,belt,lddir,belty,beltsquare,vexdir) - local v=self.loaders[i][id] - if(isvalid(v) and v.name~=belt)then v.destroy{raise_destroy=true} end - if(not isvalid(v))then - local vpos=vector(pos)+vector(vexdir)+vector(belty) - local varea=vector.square(vpos,beltsquare) - vector.clean(f,varea) - v=entity.protect(entity.create(f,belt,vpos,lddir),false,false) - v.loader_type=self.dir[i][id] - self.loaders[i][id]=v - local inv=self.loaderFilter[i][id] if(inv)then for invx,invy in pairs(inv)do v.set_filter(invx,invy) end end +function HARV:MakePointLoader(tps, i, id, pos, f, belt, lddir, belty, beltsquare, vexdir) + local v = self.loaders[i][id] + if (isvalid(v) and v.name ~= belt) then v.destroy { raise_destroy = true } end + if (not isvalid(v)) then + local vpos = vector(pos) + vector(vexdir) + vector(belty) + local varea = vector.square(vpos, beltsquare) + vector.clean(f, varea) + v = entity.protect(entity.create(f, belt, vpos, lddir), false, false) + v.loader_type = self.dir[i][id] + if v.loader_type == "output" then + v.loader_type = "input" + elseif v.loader_type == "input" then + v.loader_type = "output" + end + self.loaders[i][id] = v + local inv = self.loaderFilter[i][id] + if (inv) then for invx, invy in pairs(inv) do v.set_filter(invx, invy) end end end - cache.force_entity(v,"Harvesters",self.key,"loaders",i,id) - + cache.force_entity(v, "Harvesters", self.key, "loaders", i, id) end function HARV:CheckPointLogistics(i) - local tps=self:Data() - local t=tps.pair[i] - if(self.maxloader==0 or not tps.logs_pattern)then return end - local belt=warptorio.GetBelt() - local pos=tps.position - local f=global.floor.harvester.host - if(i==2 and self.deployed)then f=global.floor.main.host pos=self.deploy_position end - - local ldl=0 - local lvLogs=research.level("warptorio-logistics") - if(tps.logs and lvLogs>0)then ldl=ldl+1 end - if(tps.dualloader and research.has("warptorio-dualloader-1"))then ldl=ldl+1 end - if(tps.triloader and research.has("warptorio-triloader"))then ldl=ldl+1 end - if(ldl<=0)then return end - - local lddir=(i==2 and string.compassdef[tps.logs_pattern] or string.compassdef[string.compassopp[tps.logs_pattern]]) - local ldodir=(i==1 and string.compassdef[tps.logs_pattern] or string.compassdef[string.compassopp[tps.logs_pattern]]) - local vcomp=vector.compass[tps.logs_pattern] - --game.print(tps.logs_pattern .. " , lddir: " .. lddir) - local vdir=vcomp*(self:GetSize()/2) + vcomp*(i==2 and -1 or 1) + local tps = self:Data() + local t = tps.pair[i] + if (self.maxloader == 0 or not tps.logs_pattern) then return end + local belt = warptorio.GetBelt() + local pos = tps.position + local f = storage.floor.harvester.host + if (i == 2 and self.deployed) then + f = storage.floor.main.host + pos = self.deploy_position + end + + local ldl = 0 + local lvLogs = research.level("warptorio-logistics") + if (tps.logs and lvLogs > 0) then ldl = ldl + 1 end + if (tps.dualloader and research.has("warptorio-dualloader-1")) then ldl = ldl + 1 end + if (tps.triloader and research.has("warptorio-triloader")) then ldl = ldl + 1 end + if (ldl <= 0) then return end - local beltsquare=vector(1,0.5) - local pipe=vector(0,(id==1 and 2 or -2) ) - if(tps.logs_pattern=="north" or tps.logs_pattern=="south")then beltsquare=vector(0.5,1) end - for id=1,ldl do - local belty=vector( 0,(id%2==0 and 1 or 0)+(id%3==0 and -1 or 0) ) - self:MakePointLoader(tps,i,id,pos,f,belt,lddir,belty,beltsquare,vdir-vcomp*0.5) + local ldodir = (i == 2 and string.compassdef[tps.logs_pattern] or string.compassdef[string.compassopp[tps.logs_pattern]]) + local lddir = (i == 1 and string.compassdef[tps.logs_pattern] or string.compassdef[string.compassopp[tps.logs_pattern]]) + local vcomp = vector.compass[tps.logs_pattern] + --game.print(tps.logs_pattern .. " , lddir: " .. lddir) + local vdir = vcomp * (self:GetSize() / 2) + vcomp * (i == 2 and -1 or 1) + + local beltsquare = vector(1, 0.5) + local pipe = vector(0, (id == 1 and 2 or -2)) + if (tps.logs_pattern == "north" or tps.logs_pattern == "south") then beltsquare = vector(0.5, 1) end + for id = 1, ldl do + local belty = vector(0, (id % 2 == 0 and 1 or 0) + (id % 3 == 0 and -1 or 0)) + self:MakePointLoader(tps, i, id, pos, f, belt, lddir, belty, beltsquare, vdir - vcomp * 0.5) end - if(tps.dopipes and lvLogs>0)then - for id=1,math.min(lvLogs,2),1 do - local belty=vector( 0,(id==1 and 2 or -2) ) + (i==1 and vcomp*-1 or 0) - self:MakePointPipes(tps,i,id,pos,f,ldodir,belty,vdir) + if (tps.dopipes and lvLogs > 0) then + for id = 1, math.min(lvLogs, 2), 1 do + local belty = vector(0, (id == 1 and 2 or -2)) + (i == 1 and vcomp * -1 or 0) + self:MakePointPipes(tps, i, id, pos, f, lddir, belty, vdir) end end end - - ---[[ DEPLOY/RECALL ]]-- +--[[ DEPLOY/RECALL ]] -- --cleanlanding() function HARV:Recall(bply) -- recall after portal is mined - if(self.recalling)then return end self.recalling=true - local tps=self:Data() - if(not self.deployed)then self:DestroyPointTeleporter(1,false) self:CheckTeleporterPairs() + if (self.recalling) then return end + self.recalling = true + local tps = self:Data() + if (not self.deployed) then + self:DestroyPointTeleporter(1, false) + self:CheckTeleporterPairs() self:DoUpgrade() self:CheckCombo() self:ConnectCombo() - self.recalling=false + self.recalling = false return true end - local t=tps.pair[i] + local t = tps.pair[i] --self:CleanLanding() -- clean for loaders and combinators -- done automatically now --if(isvalid(self.points[2].ent))then self.points[2].ent.destroy() end --self.points[2].ent=nil - local f=global.floor.main.host - local ebs={} - for k,v in pairs(f.find_entities_filtered{type="character",invert=true,area=self:GetDeployArea(nil,true)})do - if(v.type~="resource" and v~=self.points[1].ent)then table.insert(ebs,v) end + local f = storage.floor.main.host + local ebs = {} + for k, v in pairs(f.find_entities_filtered { type = "character", invert = true, area = self:GetDeployArea(nil, true) }) do + if (v.type ~= "resource" and v ~= self.points[1].ent) then table.insert(ebs, v) end --v~=self.b and v~=self.a and (v.name=="warptorio-combinator" or v.name:sub(1,9)~="warptorio") )then table.insert(ebs,v) end end - local hf=global.floor.harvester.host - local harvArea=self:GetBaseArea(nil,true) + local hf = storage.floor.harvester.host + local harvArea = self:GetBaseArea(nil, true) - local tbs={} - local tcs={} for k,v in pairs(hf.find_tiles_filtered{area=harvArea})do - local vpos=vector.add(vector.sub(v.position,self.position),self.deploy_position) - table.insert(tcs,{name=v.name,position=vpos}) - table.insert(tbs,{name="warptorio-red-concrete",position=v.position}) + local tbs = {} + local tcs = {} + for k, v in pairs(hf.find_tiles_filtered { area = harvArea }) do + local vpos = vector.add(vector.sub(v.position, self.position), self.deploy_position) + table.insert(tcs, { name = v.name, position = vpos }) + table.insert(tbs, { name = "warptorio-red-concrete", position = v.position }) end - local dcs={} for k,v in pairs(hf.find_decoratives_filtered{area=self:GetBaseArea(nil,true)})do - local vpos=vector.add(vector.sub(v.position,self.position),self.deploy_position) - table.insert(dcs,{name=v.decorative.name,position=vpos,amount=v.amount}) + local dcs = {} + for k, v in pairs(hf.find_decoratives_filtered { area = self:GetBaseArea(nil, true) }) do + local vpos = vector.add(vector.sub(v.position, self.position), self.deploy_position) + table.insert(dcs, { name = v.decorative.name, position = vpos, amount = v.amount }) end - local ecs={} for k,v in pairs(hf.find_entities_filtered{area=harvArea,type="character",invert=true})do - if(v and v.valid and v~=self.points[1].ent and v~=self.points[2].ent and not entity.shouldClean(v) and not cache.get_entity(v) and v.type~="resource")then table.insert(ecs,v) end + local ecs = {} + for k, v in pairs(hf.find_entities_filtered { area = harvArea, type = "character", invert = true }) do + if (v and v.valid and v ~= self.points[1].ent and v ~= self.points[2].ent and not entity.shouldClean(v) and not cache.get_entity(v) and v.type ~= "resource") then + table.insert(ecs, v) + end end - local blacktbl={} - for k,v in pairs(ebs)do if(table.HasValue(warptorio.GetWarpBlacklist(),v.name))then table.insert(blacktbl,v) ebs[k]=nil end end - for k,v in pairs(ebs)do if(table.HasValue(warptorio.GetModTable("harvester_blacklist"),v.name))then table.insert(blacktbl,v) ebs[k]=nil end end + local blacktbl = {} + for k, v in pairs(ebs) do + if (table.HasValue(warptorio.GetWarpBlacklist(), v.name)) then + table.insert(blacktbl, v) + ebs[k] = nil + end + end + for k, v in pairs(ebs) do + if (table.HasValue(warptorio.GetModTable("harvester_blacklist"), v.name)) then + table.insert(blacktbl, v) + ebs[k] = nil + end + end - for k,v in pairs(ecs)do if(table.HasValue(warptorio.GetWarpBlacklist(),v.name))then table.insert(blacktbl,v) ecs[k]=nil end end - for k,v in pairs(ecs)do if(table.HasValue(warptorio.GetModTable("harvester_blacklist"),v.name))then table.insert(blacktbl,v) ecs[k]=nil end end + for k, v in pairs(ecs) do + if (table.HasValue(warptorio.GetWarpBlacklist(), v.name)) then + table.insert(blacktbl, v) + ecs[k] = nil + end + end + for k, v in pairs(ecs) do + if (table.HasValue(warptorio.GetModTable("harvester_blacklist"), v.name)) then + table.insert(blacktbl, v) + ecs[k] = nil + end + end - warptorio.Cloned_Entities={} warptorio.IsCloning=true - hf.clone_entities{entities=ecs,destination_surface=f,destination_offset=vector.add(vector.mul(self.position,-1),self.deploy_position),snap_to_grid=false} - local hfe=warptorio.Cloned_Entities warptorio.IsCloning=false warptorio.Cloned_Entities=nil + warptorio.Cloned_Entities = {} + warptorio.IsCloning = true + hf.clone_entities { entities = ecs, destination_surface = f, destination_offset = { self.deploy_position.x - self.position.x, self.deploy_position.y - self.position.y }, snap_to_grid = false } + local hfe = warptorio.Cloned_Entities + warptorio.IsCloning = false + warptorio.Cloned_Entities = nil - if(#ebs>0)then for i=#ebs,1,-1 do if(not ebs[i] or not ebs[i].valid)then table.remove(ebs,i) end end end -- bad ents in table ? + if (#ebs > 0) then for i = #ebs, 1, -1 do if (not ebs[i] or not ebs[i].valid) then table.remove(ebs, i) end end end -- bad ents in table ? - warptorio.Cloned_Entities={} warptorio.IsCloning=true - f.clone_entities{entities=ebs,destination_surface=hf,destination_offset=vector.add(vector.mul(self.deploy_position,-1),self.position),snap_to_grid=false} - local fe=warptorio.Cloned_Entities warptorio.IsCloning=false warptorio.Cloned_Entities=nil + warptorio.Cloned_Entities = {} + warptorio.IsCloning = true + f.clone_entities { entities = ebs, destination_surface = hf, destination_offset = { self.position.x - self.deploy_position.x, self.position.y - self.deploy_position.y }, snap_to_grid = false } + local fe = warptorio.Cloned_Entities + warptorio.IsCloning = false + warptorio.Cloned_Entities = nil - local hfm={} for k,v in pairs(hfe)do if(isvalid(v.source) and isvalid(v.destination) and table.HasValue(ecs,v.source))then table.insert(hfm,v.source) end end - local fm={} for k,v in pairs(fe)do if(isvalid(v.source) and isvalid(v.destination) and table.HasValue(ebs,v.source))then table.insert(fm,v.source) end end + local hfm = {} + for k, v in pairs(hfe) do + if (isvalid(v.source) and isvalid(v.destination) and table.HasValue(ecs, v.source)) then + table.insert(hfm, v.source) + end + end + local fm = {} + for k, v in pairs(fe) do + if (isvalid(v.source) and isvalid(v.destination) and table.HasValue(ebs, v.source)) then + table.insert(fm, v.source) + end + end - for k,v in pairs(fm)do entity.destroy(v) end - for k,v in pairs(hfm)do entity.destroy(v) end + for k, v in pairs(fm) do entity.destroy(v) end + for k, v in pairs(hfm) do entity.destroy(v) end - f.set_tiles(tcs,true) - f.create_decoratives{decoratives=dcs} + f.set_tiles(tcs, true) + f.create_decoratives { decoratives = dcs } - hf.destroy_decoratives{area=harvArea} + hf.destroy_decoratives { area = harvArea } - if(bply)then -- players now - local tpply={} - for k,v in pairs(game.players)do if(v.character==nil or (v.surface==f and vector.inarea(v.position,self:GetDeployArea(nil,true))) )then - table.insert(tpply,{v,vector.add(vector.add(vector.mul(self.deploy_position,-1),vector.pos(v.position)),self.position)}) - end end - for k,v in pairs(tpply)do v[1].teleport(f.find_non_colliding_position("character",{v[2][1],v[2][2]},0,1),hf) end + if (bply) then -- players now + local tpply = {} + for k, v in pairs(game.players) do + if (v.character == nil or (v.surface == f and vector.inarea(v.position, self:GetDeployArea(nil, true)))) then + table.insert(tpply, + { v, vector.add(vector.add(vector.mul(self.deploy_position, -1), vector.pos(v.position)), + self.position) }) + end + end + for k, v in pairs(tpply) do + v[1].teleport(f.find_non_colliding_position("character", { v[2][1], v[2][2] }, 0, 1), + hf) + end end --vector.LayTiles("warp-tile-concrete",hf,self:GetBaseArea(self:GetSize()+2)) --vector.LayTiles("warptorio-red-concrete",hf,self:GetBaseArea()) - hf.set_tiles(tbs,true) - self.deployed=false + hf.set_tiles(tbs, true) + self.deployed = false self:DestroyComboB() - self:DestroyPointTeleporter(1,false) self:DestroyPointTeleporter(2,false) + self:DestroyPointTeleporter(1, false) + self:DestroyPointTeleporter(2, false) self:CheckTeleporterPairs() self:DoUpgrade() self:CheckCombo() self:ConnectCombo() - self.recalling=false - + self.recalling = false end - - -function HARV:Deploy(surf,pos) -- deploy over a harvester platform - if(self.deployed)then return false end - local f=surf if(f~=warptorio.GetMainSurface())then game.print("Harvesters can only be placed on the planet") return false end +function HARV:Deploy(surf, pos) -- deploy over a harvester platform + if (self.deployed) then return false end + local f = surf + if (f ~= warptorio.GetMainSurface()) then + game.print({ "warptorio.harvester-placement-error" }) + return false + end --game.print("deployed at: " .. serpent.line(pos)) - self.deploy_position=vector.pos(pos) - local hf=global.floor.harvester.host + self.deploy_position = vector.pos(pos) + local hf = storage.floor.harvester.host - local ebs=hf.find_entities_filtered{type="character",invert=true,area=self:GetBaseArea()} + local ebs = hf.find_entities_filtered { type = "character", invert = true, area = self:GetBaseArea() } - local planetArea=self:GetDeployArea() + local planetArea = self:GetDeployArea() - local tcs={} for x=planetArea[1][1],planetArea[2][1] do for y=planetArea[1][2],planetArea[2][2]do local v=f.get_tile(x,y) - local vpos=vector.add(vector.sub(vector(x,y),self.deploy_position),self.position) - table.insert(tcs,{name=v.name,position=vpos}) - end end - local dcs={} for k,v in pairs(f.find_decoratives_filtered{area=self:GetDeployArea(self:GetSize()-3)})do - local vpos=vector.add(vector.sub(v.position,self.deploy_position),self.position) - table.insert(dcs,{name=v.decorative.name,position=vpos,amount=v.amount}) + local tcs = {} + for x = planetArea[1][1], planetArea[2][1] do + for y = planetArea[1][2], planetArea[2][2] do + local v = f.get_tile(x, y) + local vpos = vector.add(vector.sub(vector(x, y), self.deploy_position), self.position) + table.insert(tcs, { name = v.name, position = vpos }) + end + end + local dcs = {} + for k, v in pairs(f.find_decoratives_filtered { area = self:GetDeployArea(self:GetSize() - 3) }) do + local vpos = vector.add(vector.sub(v.position, self.deploy_position), self.position) + table.insert(dcs, { name = v.decorative.name, position = vpos, amount = v.amount }) + end + local ecs = {} + for k, v in pairs(f.find_entities_filtered { area = planetArea, type = { "construction-robot", "logistic-robot", "character" }, invert = true }) do + if (v.type ~= "resource" and v.name:sub(1, 9) ~= ("warptorio")) then + table.insert(ecs, v) + end end - local ecs={} for k,v in pairs(f.find_entities_filtered{area=planetArea,type={"construction-robot","logistic-robot","character"},invert=true})do if(v.type~="resource" and v.name:sub(1,9)~=("warptorio"))then table.insert(ecs,v) end end - - hf.set_tiles(tcs,true) - hf.create_decoratives{decoratives=dcs} - local ebsc=#ebs - local ecsc=#ecs + hf.set_tiles(tcs, true) + hf.create_decoratives { decoratives = dcs } + local ebsc = #ebs + local ecsc = #ecs - local blacktbl={} + local blacktbl = {} --for k,v in pairs(ebs)do if(isvalid(v))then if(table.HasValue(warptorio.GetWarpBlacklist(),v.name))then table.insert(blacktbl,v) ebs[k]=nil end end end --for k,v in pairs(ebs)do if(isvalid(v))then if(table.HasValue(warptorio.GetModTable("harvester_blacklist"),v.name))then table.insert(blacktbl,v) ebs[k]=nil end end end --for k,v in pairs(ecs)do if(isvalid(v))then if(table.HasValue(warptorio.GetWarpBlacklist(),v.name))then table.insert(blacktbl,v) ecs[k]=nil end end end --for k,v in pairs(ecs)do if(isvalid(v))then if(table.HasValue(warptorio.GetModTable("harvester_blacklist"),v.name))then table.insert(blacktbl,v) ecs[k]=nil end end end + if (ecsc > 0) then for i = ecsc, 1, -1 do if (not ecs[i] or not ecs[i].valid) then table.remove(ecs, i) end end end -- bad ents in table ? - if(ecsc>0)then for i=ecsc,1,-1 do if(not ecs[i] or not ecs[i].valid)then table.remove(ecs,i) end end end -- bad ents in table ? - - warptorio.Cloned_Entities={} warptorio.IsCloning=true - f.clone_entities{entities=ecs,destination_surface=hf,destination_offset=vector.mul(vector.sub(self.deploy_position,self.position),-1),snap_to_grid=false} - local fe=warptorio.Cloned_Entities warptorio.IsCloning=false warptorio.Cloned_Entities=nil - + warptorio.Cloned_Entities = {} + warptorio.IsCloning = true + -- f.clone_entities { entities = ecs, destination_surface = hf, destination_offset = vector.mul(vector.sub(self.position, self.deploy_position), -1), snap_to_grid = false } + f.clone_entities { entities = ecs, destination_surface = hf, destination_offset = { self.deploy_position.x - self.position.x, self.deploy_position.y - self.position.y }, snap_to_grid = false } + local fe = warptorio.Cloned_Entities + warptorio.IsCloning = false + warptorio.Cloned_Entities = nil - if(ebsc>0)then for i=ebsc,1,-1 do if(not ebs[i] or not ebs[i].valid)then table.remove(ebs,i) end end end -- bad ents in table ? + if (ebsc > 0) then for i = ebsc, 1, -1 do if (not ebs[i] or not ebs[i].valid) then table.remove(ebs, i) end end end -- bad ents in table ? - vector.LayTiles("warptorio-red-concrete",f,self:GetDeployArea()) + vector.LayTiles("warptorio-red-concrete", f, self:GetDeployArea()) -- this doesnt really work - warptorio.Cloned_Entities={} warptorio.IsCloning=true - hf.clone_entities{entities=ebs,destination_surface=f,destination_offset=vector.mul(vector.sub(self.position,self.deploy_position),-1),snap_to_grid=false} - local hfe=warptorio.Cloned_Entities warptorio.IsCloning=false warptorio.Cloned_Entities=nil - - local hfm={} for k,v in pairs(hfe)do if(isvalid(v.source) and isvalid(v.destination) and table.HasValue(ebs,v.source))then table.insert(hfm,v.source) end end - local fm={} for k,v in pairs(fe)do if(isvalid(v.source) and isvalid(v.destination) and table.HasValue(ecs,v.source))then table.insert(fm,v.source) end end + warptorio.Cloned_Entities = {} + warptorio.IsCloning = true + -- hf.clone_entities { entities = ebs, destination_surface = f, destination_offset = vector.mul(vector.sub(self.position, self.deploy_position), -1), snap_to_grid = false } + hf.clone_entities { entities = ebs, destination_surface = f, destination_offset = { self.deploy_position.x - self.position.x, self.deploy_position.y - self.position.y }, snap_to_grid = false } + local hfe = warptorio.Cloned_Entities + warptorio.IsCloning = false + warptorio.Cloned_Entities = nil + + local hfm = {} + for k, v in pairs(hfe) do + if (isvalid(v.source) and isvalid(v.destination) and table.HasValue(ebs, v.source)) then + table.insert(hfm, v.source) + end + end + local fm = {} + for k, v in pairs(fe) do + if (isvalid(v.source) and isvalid(v.destination) and table.HasValue(ecs, v.source)) then + table.insert(fm, v.source) + end + end - for k,v in pairs(fm)do if(isvalid(v) and v~=self.points[1].ent and v~=self.points[2].ent)then entity.destroy(v) end end - for k,v in pairs(hfm)do if(isvalid(v) and v~=self.points[1].ent and v~=self.points[2].ent)then entity.destroy(v) end end + for k, v in pairs(fm) do + if (isvalid(v) and v ~= self.points[1].ent and v ~= self.points[2].ent) then + entity.destroy(v) + end + end + for k, v in pairs(hfm) do + if (isvalid(v) and v ~= self.points[1].ent and v ~= self.points[2].ent) then + entity.destroy(v) + end + end - for k,v in pairs(blacktbl)do if(v and v.valid)then v.destroy{raise_destroy=true} end end -- cleanup past entities + for k, v in pairs(blacktbl) do if (v and v.valid) then v.destroy { raise_destroy = true } end end -- cleanup past entities - vector.clearplayers(f,planetArea) + vector.clearplayers(f, planetArea) - self.deployed=true + self.deployed = true -- game.print("deployed") self:CheckTeleporterPairs() end - - diff --git a/control_class_rails.lua b/control_class_rails.lua index 5690098..8ead5eb 100644 --- a/control_class_rails.lua +++ b/control_class_rails.lua @@ -1,110 +1,215 @@ - -local TRAIL={} TRAIL.__index=TRAIL warptorio.RailMeta=TRAIL -function TRAIL.__init(self,tbl) - self.key=self.key or tbl.key - self.chests={{}} - self.rails={} - self.loaders={{},{},{},{}} - self.chestcontents={} - self.dir="output" - global.Rails[self.key]=self +local TRAIL = {} +TRAIL.__index = TRAIL +warptorio.RailMeta = TRAIL +function TRAIL.__init(self, tbl) + self.key = self.key or tbl.key + self.chests = { {} } + self.rails = {} + self.loaders = { {}, {}, {}, {} } + self.chestcontents = {} + self.dir = "output" + storage.Rails[self.key] = self end -function TRAIL:Data() return warptorio.platform.rails[self.key] end +function TRAIL:Data() + return warptorio.platform.rails[self.key] +end function TRAIL:MakeRails() - local f=warptorio.GetMainSurface() - local tps=self:Data() - if(not isvalid(self.rails[1]) or not isvalid(self.rails[2]))then vector.clean(f,vector.square(tps.railpos,vector(1,1))) end - if(not isvalid(self.rails[1]))then self.rails[1]=entity.protect(entity.spawn(f,"straight-rail",tps.railpos,defines.direction.south),false,false) end - if(not isvalid(self.rails[2]))then self.rails[2]=entity.protect(entity.spawn(f,"straight-rail",tps.railpos,defines.direction.east),false,false) end + local f = warptorio.GetMainSurface() + local tps = self:Data() + if (not isvalid(self.rails[1]) or not isvalid(self.rails[2])) then + vector.clean(f, + vector.square(tps.railpos, vector(1, 1))) + end + if (not isvalid(self.rails[1])) then + self.rails[1] = entity.protect( + entity.spawn(f, "straight-rail", tps.railpos, defines.direction.south), false, false) + end + if (not isvalid(self.rails[2])) then + self.rails[2] = entity.protect( + entity.spawn(f, "straight-rail", tps.railpos, defines.direction.east), false, false) + end end function TRAIL:MakeChests() - local ccls=warptorio.GetChest(self.dir) - local tps=self:Data() - local f=global.floor[tps.floor].host - for i,px in pairs(vector.compasscorn)do - local v=self.chests[1][i] - if(isvalid(v) and v.name~=ccls)then self.chestcontents[i]=v.get_inventory(defines.inventory.chest).get_contents() v.destroy{raise_destroy=true} end - if(not isvalid(v))then - local vpos=tps.chestpos+px*0.5 - local varea=vector.square(vpos,vector(0.5,0.5)) - vector.clean(f,varea) - v=entity.protect(entity.create(f,ccls,vpos),false,false) - self.chests[1][i]=v - local inv=self.chestcontents[i] - if(inv)then local cv=v.get_inventory(defines.inventory.chest) for x,y in pairs(inv)do cv.insert{name=x,count=y} end self.chestcontents[i]=nil end + local ccls = warptorio.GetChest(self.dir) + local tps = self:Data() + local f = storage.floor[tps.floor].host + for i, px in pairs(vector.compasscorn) do + local v = self.chests[1][i] + if (isvalid(v) and v.name ~= ccls) then + self.chestcontents[i] = v.get_inventory(defines.inventory.chest).get_contents() + v.destroy { raise_destroy = true } end - cache.get_raise_type("types",v.type,v,"Rails",self.key,"chests",1,i) + if (not isvalid(v)) then + local vpos = tps.chestpos + px * 0.5 + local varea = vector.square(vpos, vector(0.5, 0.5)) + vector.clean(f, varea) + v = entity.protect(entity.create(f, ccls, vpos), false, false) + self.chests[1][i] = v + local inv = self.chestcontents[i] + if (inv) then + local cv = v.get_inventory(defines.inventory.chest) + for x, y in pairs(inv) do cv.insert { name = x, count = y } end + self.chestcontents[i] = nil + end + end + cache.get_raise_type("types", v.type, v, "Rails", self.key, "chests", 1, i) end end -function TRAIL:Rotate() self:MakeChests() for i,tbl in pairs(self.loaders)do for k,v in pairs(tbl)do v.loader_type=self.dir end end end - +function TRAIL:Rotate() + self:MakeChests() + for i, tbl in pairs(self.loaders) do + for k, v in pairs(tbl) do + v.loader_type = self.dir + end + end +end function TRAIL:MakeLoaders() - local tps=self:Data() - local f=global.floor[tps.floor].host - local bcls=warptorio.GetBelt(self.dir) - for i,b in pairs(tps.logs)do if(b)then - local cd=vector.compass[string.compass[i]]*2 - - for x=1,2,1 do - local v=self.loaders[i][x] - if(isvalid(v) and v.name~=bcls)then entity.destroy(v) end - if(not isvalid(v))then - local vang=(((i-1)*2)+4)%8 - local vpos=tps.chestpos+cd+vector.compassall[string.compassall[((vang+2)%8)+1]]*(x==1 and 0.5 or -0.5) - local varea=vector.square(vpos,vector((i==1 or i==3) and 0.5 or 1,(i==1 or i==3) and 1 or 0.5)) - vector.clean(f,varea) - v=entity.protect(entity.create(f,bcls,vpos,vang),false,false) - v.loader_type=self.dir - self.loaders[i][x]=v - end - cache.force_entity(v,"Rails",self.key,"loaders",i,x) + local tps = self:Data() + local f = storage.floor[tps.floor].host + local bcls = warptorio.GetBelt(self.dir) + for i, b in pairs(tps.logs) do + if (b) then + local cd = vector.compass[string.compass[i]] * 2 + for x = 1, 2, 1 do + local v = self.loaders[i][x] + if (isvalid(v) and v.name ~= bcls) then + entity.destroy(v) + end + if (not isvalid(v)) then + local vang = (((i - 1) * 2) + 4) % 8 + local vpos = tps.chestpos + cd + + vector.compassall[string.compassall[((vang + 2) % 8) + 1]] * (x == 1 and 0.5 or -0.5) + local varea = vector.square(vpos, vector((i == 1 or i == 3) and 0.5 or 1, (i == 1 or i == 3) and 1 or + 0.5)) + vector.clean(f, varea) + v = entity.protect(entity.create(f, bcls, vpos, (vang * 2 + 8) % 16), false, false) + v.loader_type = self.dir + self.loaders[i][x] = v + end + cache.force_entity(v, "Rails", self.key, "loaders", i, x) + end end - end end + end end - -function TRAIL:DoMakes() self:MakeRails() self:MakeChests() self:MakeLoaders() end +function TRAIL:DoMakes() + self:MakeRails() + self:MakeChests() + self:MakeLoaders() +end -- Warp Rail Logistics - -function TRAIL:SplitItem(u,n) local c=n local cx=0 local cinv={} local ui={name=k,count=n} - for k,v in pairs(self.chests[1])do local iv=v.get_inventory(defines.inventory.chest) if(iv.can_insert(u))then cinv[k]=iv end end local tcn=table_size(cinv) - for k,v in pairs(cinv)do if(c>0)then local w=v.insert{name=u,count=math.ceil(c/tcn)} cx=cx+w c=c-w tcn=tcn-1 end end +function TRAIL:SplitItem(u, n) + local c = n + local cx = 0 + local cinv = {} + local ui = { name = k, count = n } + for k, v in pairs(self.chests[1]) do + local iv = v.get_inventory(defines.inventory.chest) + if (iv.can_insert(u)) then + cinv[k] = iv + end + end + local tcn = table_size(cinv) + for k, v in pairs(cinv) do + if (c > 0) then + local w = v.insert { name = u, count = math.ceil(c / tcn) } + cx = cx + w + c = c - w + tcn = tcn - 1 + end + end return cx end -function TRAIL:UnloadLogistics(e) for _,r in pairs(e)do - local inv=r.get_inventory(defines.inventory.cargo_wagon) for k,v in pairs(inv.get_contents())do local ct=self:SplitItem(k,v) if(ct>0)then inv.remove({name=k,count=ct}) end end -end end +function TRAIL:UnloadLogistics(e) + for _, r in pairs(e) do + local inv = r.get_inventory(defines.inventory.cargo_wagon) + for k, v in pairs(inv.get_contents()) do + local ct = self:SplitItem(v.name, v.count) + if (ct > 0) then inv.remove({ name = v.name, count = ct }) end + end + end +end function TRAIL:LoadLogistics(e) - local inv={} for k,v in pairs(self.chests[1])do inv[k]=v.get_inventory(defines.inventory.chest) end - local ct={} for k,v in pairs(inv)do for a,b in pairs(v.get_contents())do ct[a]=(ct[a] or 0)+b end v.clear() end - for _,r in pairs(e)do local tr=r.get_inventory(defines.inventory.cargo_wagon) for k,v in pairs(ct)do ct[k]=v-(tr.insert{name=k,count=v}) end end - local ci for a,b in pairs(ct)do local g=b ci=#inv - for k,v in pairs(inv)do if(ci>0)then local gci=math.ceil(g/ci) if(gci>0)then local w=v.insert{name=a,count=math.ceil(g/ci)} ci=ci-1 g=g-w end end end + local inv = {} + for k, v in pairs(self.chests[1]) do inv[k] = v.get_inventory(defines.inventory.chest) end + local ct = {} + for k, v in pairs(inv) do + for a, b in pairs(v.get_contents()) do ct[a] = (ct[a] or 0) + b end + v.clear() + end + for _, r in pairs(e) do + local tr = r.get_inventory(defines.inventory.cargo_wagon) + for k, v in pairs(ct) do ct[k] = v - (tr.insert { name = k, count = v }) end + end + local ci + for a, b in pairs(ct) do + local g = b + ci = #inv + for k, v in pairs(inv) do + if (ci > 0) then + local gci = math.ceil(g / ci) + if (gci > 0) then + local w = v.insert { name = a, count = math.ceil(g / ci) } + ci = ci - 1 + g = g - w + end + end + end end end -function TRAIL:BalanceChests() local inv={} for k,v in pairs(self.chests[1])do if(isvalid(v))then inv[k]=v.get_inventory(defines.inventory.chest) end end if(table_size(inv)>0)then - local ct={} for k,v in pairs(inv)do for a,b in pairs(v.get_contents())do ct[a]=(ct[a] or 0)+b end v.clear() end - local ci for a,b in pairs(ct)do local g=b ci=table_size(inv) for k,v in pairs(inv)do - local gci=math.ceil(g/ci) if(gci>0)then local w=v.insert{name=a,count=math.ceil(g/ci)} ci=ci-1 g=g-w end - end end -end end - -function TRAIL:TickLogistics() local f=global.floor.main.host if(not f.valid)then return end local c=self:Data().railpos - local e=f.find_entities_filtered{name="cargo-wagon",area={{c.x-1,c.y-1},{c.x+1,c.y+1}} } - if(table_size(e)>0)then if(self.dir=="output")then self:UnloadLogistics(e) self:BalanceChests() else self:LoadLogistics(e) end else self:BalanceChests() end + +function TRAIL:BalanceChests() + local inv = {} + for k, v in pairs(self.chests[1]) do if (isvalid(v)) then inv[k] = v.get_inventory(defines.inventory.chest) end end + if (table_size(inv) > 0) then + local ct = {} + for k, v in pairs(inv) do + for a, b in pairs(v.get_contents()) do ct[b] = (ct[b] or 0) + b.count end + v.clear() + end + local ci + for a, b in pairs(ct) do + local g = b + ci = table_size(inv) + for k, v in pairs(inv) do + local gci = math.ceil(g / ci) + if (gci > 0) then + local w = v.insert { name = a.name, count = math.ceil(g / ci) } + ci = ci - 1 + g = g - w + end + end + end + end end +function TRAIL:TickLogistics() + local f = storage.floor.main.host + if (not f.valid) then return end + local c = self:Data().railpos + local e = f.find_entities_filtered { name = "cargo-wagon", area = { { c.x - 1, c.y - 1 }, { c.x + 1, c.y + 1 } } } + if (table_size(e) > 0) then + if (self.dir == "output") then + self:UnloadLogistics(e) + self:BalanceChests() + else + self:LoadLogistics(e) + end + else + self:BalanceChests() + end +end -events.on_tick(3,0,"TickRails",function(ev) for k,v in pairs(global.Rails)do v:TickLogistics() end end) +events.on_tick(3, 0, "TickRails", function(ev) for k, v in pairs(storage.Rails) do v:TickLogistics() end end) --[[ old stuff @@ -125,5 +230,3 @@ function warptorio.BuildRails() warptorio.BuildRailCorner("nw") warptorio.BuildR ]] - - diff --git a/control_class_teleporter.lua b/control_class_teleporter.lua index 9bf5d13..99b613e 100644 --- a/control_class_teleporter.lua +++ b/control_class_teleporter.lua @@ -1,21 +1,27 @@ - - -function warptorio.GetPlatformTechLevel(nm) local tc=warptorio.platform.techs[nm] if(not tc)then return false end - if(tc.level_range or tc.levels)then return research.level(tc.tech) else return research.has(tc.tech) end +function warptorio.GetPlatformTechLevel(nm) + local tc = warptorio.platform.techs[nm] + if (not tc) then return false end + if (tc.level_range or tc.levels) then return research.level(tc.tech) else return research.has(tc.tech) end end -function warptorio.GetPlatformTechAmount(nm) local tc=warptorio.platform.techs[nm] if(not tc)then return false end - local lv=warptorio.GetPlatformTechLevel(nm) or 0 - if(tc.levels)then return tc.levels[lv] end + +function warptorio.GetPlatformTechAmount(nm) + local tc = warptorio.platform.techs[nm] + if (not tc) then return false end + local lv = warptorio.GetPlatformTechLevel(nm) or 0 + if (tc.levels) then return tc.levels[lv] end end function warptorio.GetPlatformResearches() -- cache stuff - if(warptorio.PlatformResearches)then return warptorio.PlatformResearches end - warptorio.PlatformResearches={} - for vi,v in pairs(warptorio.platform.techs)do - v.key=v.key or vi - if(v.levels)then for k in pairs(v.levels)do warptorio.PlatformResearches[v.tech.."-"..k]=v end - elseif(v.level_range)then for i=v.level_range[1],v.level_range[2] do warptorio.PlatformResearches[v.tech.."-"..i]=v end - else warptorio.PlatformResearches[v.tech]=v + if (warptorio.PlatformResearches) then return warptorio.PlatformResearches end + warptorio.PlatformResearches = {} + for vi, v in pairs(warptorio.platform.techs) do + v.key = v.key or vi + if (v.levels) then + for k in pairs(v.levels) do warptorio.PlatformResearches[v.tech .. "-" .. k] = v end + elseif (v.level_range) then + for i = v.level_range[1], v.level_range[2] do warptorio.PlatformResearches[v.tech .. "-" .. i] = v end + else + warptorio.PlatformResearches[v.tech] = v end end return warptorio.PlatformResearches @@ -23,377 +29,515 @@ end function warptorio.GetPlatformResearch(nm) return warptorio.GetPlatformResearches()[nm] end -warptorio.ResearchEffects={} +warptorio.ResearchEffects = {} function warptorio.ResearchEffects.retile(floors) - for k,v in pairs(floors)do warptorio.ConstructFloor(v,true) end + for k, v in pairs(floors) do warptorio.ConstructFloor(v, true) end end + function warptorio.ResearchEffects.rehazard(floors) - for k,v in pairs(floors)do warptorio.ConstructFloorHazard(v) end + for k, v in pairs(floors) do warptorio.ConstructFloorHazard(v) end end -function warptorio.ResearchEffects.unlock_teleporters(tpt) if(not istable(tpt))then tpt={tpt} end - for i,nm in pairs(tpt)do - local tpx=warptorio.platform.teleporters[nm] - local gps=global.Teleporters[nm] - if(not gps)then + +function warptorio.ResearchEffects.unlock_teleporters(tpt) + if (not istable(tpt)) then tpt = { tpt } end + for i, nm in pairs(tpt) do + local tpx = warptorio.platform.teleporters[nm] + local gps = storage.Teleporters[nm] + if (not gps) then --game.print("New teleporter: " .. tostring(nm)) - gps=new(warptorio.TeleporterMeta,tpx) + gps = new(warptorio.TeleporterMeta, tpx) end gps:CheckTeleporterPairs(true) end end -function warptorio.ResearchEffects.unlock_rails(tpt) if(not istable(tpt))then tpt={tpt} end - for i,nm in pairs(tpt)do - local tpx=warptorio.platform.rails[nm] - local gps=global.Rails[nm] - if(not gps)then + +function warptorio.ResearchEffects.unlock_rails(tpt) + if (not istable(tpt)) then tpt = { tpt } end + for i, nm in pairs(tpt) do + local tpx = warptorio.platform.rails[nm] + local gps = storage.Rails[nm] + if (not gps) then --game.print("New Rails: " .. tostring(nm)) - gps=new(warptorio.RailMeta,tpx) + gps = new(warptorio.RailMeta, tpx) end gps:DoMakes() end end function warptorio.ResearchEffects.harvesters(hvt) - for i,nm in pairs(hvt)do - local tpx=warptorio.platform.harvesters[nm] - local gps=global.Harvesters[nm] - if(not gps)then - gps=new(warptorio.HarvesterMeta,tpx) + for i, nm in pairs(hvt) do + local tpx = warptorio.platform.harvesters[nm] + local gps = storage.Harvesters[nm] + if (not gps) then + gps = new(warptorio.HarvesterMeta, tpx) end gps:Upgrade() end end + function warptorio.ResearchEffects.upgrade_energy(tgt) - if(tgt==true)then - for k,v in pairs(global.Teleporters)do v:CheckTeleporterPairs(true) end - for k,v in pairs(global.Harvesters)do v:CheckTeleporterPairs(true) end + if (tgt == true) then + for k, v in pairs(storage.Teleporters) do v:CheckTeleporterPairs(true) end + for k, v in pairs(storage.Harvesters) do v:CheckTeleporterPairs(true) end else - for k,v in pairs(tgt)do if(global.Teleporters[v])then global.Teleporters[v]:CheckTeleporterPairs(true) end end + for k, v in pairs(tgt) do if (storage.Teleporters[v]) then storage.Teleporters[v]:CheckTeleporterPairs(true) end end end end + function warptorio.ResearchEffects.upgrade_logistics(tgt) - if(tgt==true)then - for k,v in pairs(global.Teleporters)do v:CheckTeleporterPairs(true) end - for k,v in pairs(global.Harvesters)do v:CheckTeleporterPairs(true) end - for k,v in pairs(global.Rails)do v:DoMakes() end + if (tgt == true) then + for k, v in pairs(storage.Teleporters) do v:CheckTeleporterPairs(true) end + for k, v in pairs(storage.Harvesters) do v:CheckTeleporterPairs(true) end + for k, v in pairs(storage.Rails) do v:DoMakes() end else - for k,v in pairs(tgt)do if(global.Teleporters[v])then global.Teleporters[v]:CheckTeleporterPairs(true) end end + for k, v in pairs(tgt) do if (storage.Teleporters[v]) then storage.Teleporters[v]:CheckTeleporterPairs(true) end end end end + function warptorio.ResearchEffects.do_combinators() - for k,v in pairs(global.Harvesters)do v:CheckCombo(true) end + for k, v in pairs(storage.Harvesters) do v:CheckCombo(true) end end + function warptorio.ResearchEffects.special(spt) - for k,v in pairs(spt)do warptorio.CheckPlatformSpecials(global.floor[v]) end + for k, v in pairs(spt) do warptorio.CheckPlatformSpecials(storage.floor[v]) end end -function warptorio.ResearchEffects.reactor(b,lv) - local m=global.floor.main players.playsound("warp_in",m.host) - for i=1,3,1 do for x,ply in pairs(game.players)do ply.print{"warptorio_lore."..lv .."_"..i} end end - if(lv<6)then global.warp_auto_time=global.warp_auto_time+60*10 end +function warptorio.ResearchEffects.reactor(b, lv) + local m = storage.floor.main + players.playsound("warp_in", m.host) + for i = 1, 3, 1 do for x, ply in pairs(game.players) do ply.print { "warptorio_lore." .. lv .. "_" .. i } end end - if(lv>=8)then warptorio.ResetHUD() end + if (lv < 6) then storage.warp_auto_time = storage.warp_auto_time + 60 * 10 end - --warptorio.CheckPlatformSpecials(global.floor.main) + if (lv >= 8) then warptorio.ResetHUD() end + + --warptorio.CheckPlatformSpecials(storage.floor.main) end + function warptorio.ResearchEffects.ability(tgt) warptorio.ResetHUD() end + function warptorio.ResearchEffects.unlock_homeworld() warptorio.ResetHUD() end + function warptorio.ResearchEffects.unlock_toolbar() warptorio.ResetHUD() end - -function warptorio.DoResearchEffects(fx,lv) - for k,v in pairs(fx)do - if(warptorio.ResearchEffects[k])then warptorio.ResearchEffects[k](v,lv) end +function warptorio.DoResearchEffects(fx, lv) + for k, v in pairs(fx) do + if (warptorio.ResearchEffects[k]) then warptorio.ResearchEffects[k](v, lv) end end end + function warptorio.ResearchFinished(ev) - local rs=ev.research + local rs = ev.research --game.print("researched_finished: " .. rs.name) - local u=warptorio.GetPlatformResearch(rs.name) - if(u)then - local lv=warptorio.GetPlatformTechLevel(u.key) or 0 + local u = warptorio.GetPlatformResearch(rs.name) + if (u) then + local lv = warptorio.GetPlatformTechLevel(u.key) or 0 --if(u.first_effect)then game.print("testing: " .. tostring(lv) .. " , " .. serpent.line(u)) end - if(u.first_effect and (u.levels and (u.levels[0] and lv==0 or lv==1) or (u.level_range and lv==u.level_range[1])) )then - warptorio.DoResearchEffects(u.first_effect,lv) + if (u.first_effect and (u.levels and (u.levels[0] and lv == 0 or lv == 1) or (u.level_range and lv == u.level_range[1]))) then + warptorio.DoResearchEffects(u.first_effect, lv) --game.print("first effect") end - if(u.effect)then warptorio.DoResearchEffects(u.effect,lv) end - if(u.lv_effect)then local lvt=u.lv_effect[lv] if(lvt)then warptorio.DoResearchEffects(lvt,lv) end end - + if (u.effect) then warptorio.DoResearchEffects(u.effect, lv) end + if (u.lv_effect) then + local lvt = u.lv_effect[lv] + if (lvt) then warptorio.DoResearchEffects(lvt, lv) end + end end warptorio.ConstructHazards() end +events.on_event(defines.events.on_research_finished, warptorio.ResearchFinished) -events.on_event(defines.events.on_research_finished,warptorio.ResearchFinished) +local platform = warptorio.platform -local platform=warptorio.platform +--[[ Warp Teleporters ]] -- ---[[ Warp Teleporters ]]-- - -local TELL={} TELL.__index=TELL warptorio.TeleporterMeta=TELL -function TELL.__init(self,tbl,bHarvester) - self.key=self.key or tbl.key +local TELL = {} +TELL.__index = TELL +warptorio.TeleporterMeta = TELL +function TELL.__init(self, tbl, bHarvester) + self.key = self.key or tbl.key --self.maxloader=(tbl.logs and 1 or 0)+(tbl.dualloader and 1 or 0)+(tbl.triloader and 1 or 0) --if(not tbl.prototype)then error(serpent.block(self)) end - self.offloader=(tbl.prototype and 1 or 0) - - self.points=self.points or {{},{}} - self.chestcontents=self.chestcontents or {{},{}} - self.loaders=self.loaders or {{},{}} - self.pipes=self.pipes or {{},{}} - self.chests=self.chests or {{},{}} - if(not self.dir)then self.dir={{},{}} for i=1,6,1 do self.dir[1][i]="input" self.dir[2][i]="output" end end - self.loaderFilter=self.loaderFilter or {{},{}} - self.sprites=self.sprites or {{},{}} - self.sprite_arrows=self.sprite_arrows or {nil,nil} - if(not bHarvester)then global.Teleporters[self.key]=self end + self.offloader = (tbl.prototype and 1 or 0) + + self.points = self.points or { {}, {} } + self.chestcontents = self.chestcontents or { {}, {} } + self.loaders = self.loaders or { {}, {} } + self.pipes = self.pipes or { {}, {} } + self.chests = self.chests or { {}, {} } + if (not self.dir) then + self.dir = { {}, {} } + for i = 1, 6, 1 do + self.dir[1][i] = "input" + self.dir[2][i] = "output" + end + end + self.loaderFilter = self.loaderFilter or { {}, {} } + self.sprites = self.sprites or { {}, {} } + self.sprite_arrows = self.sprite_arrows or { nil, nil } + if (not bHarvester) then storage.Teleporters[self.key] = self end end + function TELL:Data() return warptorio.platform.teleporters[self.key] end function TELL:ValidA() return isvalid(self.points[1].ent) end + function TELL:ValidB() return isvalid(self.points[2].ent) end -function TELL:ConnectCircuit() local p=self.points - if(self:ValidA() and self:ValidB())then - p[1].ent.connect_neighbour({target_entity=p[2].ent,wire=defines.wire_type.red}) - p[1].ent.connect_neighbour({target_entity=p[2].ent,wire=defines.wire_type.green}) +function TELL:ConnectCircuit() + local p = self.points + if (self:ValidA() and self:ValidB()) then + local red1 = p[1].ent.get_wire_connector(defines.wire_connector_id.circuit_red, true) + local red2 = p[2].ent.get_wire_connector(defines.wire_connector_id.circuit_red, true) + red1.connect_to(red2) + local green1 = p[1].ent.get_wire_connector(defines.wire_connector_id.circuit_green, true) + local green2 = p[2].ent.get_wire_connector(defines.wire_connector_id.circuit_green, true) + green1.connect_to(green2) end end function TELL:CheckTeleporterPairs(bSound) -- Call updates and stuff. Automatically deals with logistics, upgrades and cleaning as-needed with good accuracy - local tps=self:Data() - if(tps.pair)then for i,t in pairs(tps.pair)do local pi=self.points[i] self:MakePointTeleporter(tps,i,t,(t.gate and isvalid(pi.ent)) and pi.ent.position or nil) end end - local ca=cache.get_entity(self.points[1].ent) - local cb=cache.get_entity(self.points[2].ent) - if(ca and cb)then ca.teleport_dest=cb.host cb.teleport_dest=ca.host else if(ca)then ca.teleport_dest=nil end if(cb)then cb.teleport_dest=nil end end - if(tps.circuit)then self:ConnectCircuit() end + local tps = self:Data() + if (tps.pair) then + for i, t in pairs(tps.pair) do + local pi = self.points[i] + self:MakePointTeleporter(tps, i, t, (t.gate and isvalid(pi.ent)) and pi.ent.position or nil) + end + end + local ca = cache.get_entity(self.points[1].ent) + local cb = cache.get_entity(self.points[2].ent) + if (ca and cb) then + ca.teleport_dest = cb.host + cb.teleport_dest = ca.host + else + if (ca) then ca.teleport_dest = nil end + if (cb) then cb.teleport_dest = nil end + end + if (tps.circuit) then self:ConnectCircuit() end end +--[[ Teleporter Logistics & Spawning Stuff ]] -- - ---[[ Teleporter Logistics & Spawning Stuff ]]-- - - -function TELL:DestroyPointTeleporter(i,rd) - local e=self.points[i].ent if(isvalid(e))then self.points[i].energy=e.energy entity.destroy(e,rd) end +function TELL:DestroyPointTeleporter(i, rd) + local e = self.points[i].ent + if (isvalid(e)) then + self.points[i].energy = e.energy + entity.destroy(e, rd) + end self:DestroyPointSprites(i) end + function TELL:DestroyPointSprites(i) - if(self.sprites and self.sprites[i])then for k,v in pairs(self.sprites[i])do if(rendering.is_valid(v))then rendering.destroy(v) self.sprites[i][k]=nil end end end - if(self.sprite_arrows and self.sprite_arrows[i])then if(rendering.is_valid(self.sprite_arrows[i]))then rendering.destroy(self.sprite_arrows[i]) self.sprite_arrows[i]=nil end end + if (self.sprites and self.sprites[i]) then + for k, v in pairs(self.sprites[i]) do + if (v.valid) then + v.destroy() + self.sprites[i][k] = nil + end + end + end + if (self.sprite_arrows and self.sprite_arrows[i]) then + if (self.sprite_arrows[i] ~= nil) then + self.sprite_arrows[i].destroy() + self.sprite_arrows[i] = nil + end + end end + function TELL:CheckPointSprites(i) - local tps=self:Data() local t=tps.pair[i] - if(warptorio.setting("hide_sprites"))then self:DestroyPointSprites(i) else - if(t.sprites)then self:MakePointSprites(tps,i,t.sprites) end - if(t.sprite_arrow)then self:MakePointArrow(tps,i,t.sprite_arrow) end + local tps = self:Data() + local t = tps.pair[i] + if (warptorio.setting("hide_sprites")) then + self:DestroyPointSprites(i) + else + if (t.sprites) then self:MakePointSprites(tps, i, t.sprites) end + if (t.sprite_arrow) then self:MakePointArrow(tps, i, t.sprite_arrow) end end end -function TELL:MakePointTeleporter(tps,i,t,pos) - local p=self.points[i] - local f=global.floor[t.floor].host - +function TELL:MakePointTeleporter(tps, i, t, pos) + local p = self.points[i] + local f = storage.floor[t.floor].host local epos - if(t.prototype)then - local vproto=t.prototype - if(tps.energy)then vproto=vproto.."-"..warptorio.GetPlatformTechLevel(tps.energy) end - local e=p.ent - if(isvalid(e))then - if(e.surface~=f)then self:DestroyPointTeleporter(i) self:DestroyPointLogistics(i) - elseif(e.name~=vproto)then epos=e.position self:DestroyPointTeleporter(i) + if (t.prototype) then + local vproto = t.prototype + if (tps.energy) then vproto = vproto .. "-" .. warptorio.GetPlatformTechLevel(tps.energy) end + local e = p.ent + if (isvalid(e)) then + if (e.surface ~= f) then + self:DestroyPointTeleporter(i) + self:DestroyPointLogistics(i) + elseif (e.name ~= vproto) then + epos = e.position + self:DestroyPointTeleporter(i) end end - if(not isvalid(e))then - local vepos=epos or (pos or t.position) - if(not vepos)then return end - local vpos=((t.gate and not epos) and f.find_non_colliding_position(vproto,vepos,0,1,1) or vepos) + if (not isvalid(e)) then + local vepos = epos or (pos or t.position) + if (not vepos) then return end + local vpos = ((t.gate and not epos) and f.find_non_colliding_position(vproto, vepos, 0, 1, true) or vepos) --error(serpent.line(vpos)) local varea - if(not t.gate)then varea=vector.square(vpos+vector(0.5,0.5),vector(2,2)) vector.clean(f,varea) end - e=entity.protect(entity.create(f,vproto,vpos),t.minable~=nil and t.minable or false,t.destructible~=nil and t.destructible or false) - if(not t.gate)then vector.cleanplayers(f,varea) end - p.ent=e + if (not t.gate) then + varea = vector.square(vpos + vector(0.5, 0.5), vector(2, 2)) + vector.clean(f, varea) + end + e = entity.protect(entity.create(f, vproto, vpos), t.minable ~= nil and t.minable or false, + t.destructible ~= nil and t.destructible or false) + if (not t.gate) then vector.cleanplayers(f, varea) end + p.ent = e + end + if (p.energy) then + e.energy = e.energy + p.energy + p.energy = nil end - if(p.energy)then e.energy=e.energy+p.energy p.energy=nil end - if(t.sprites)then self:MakePointSprites(tps,i,t.sprites) end - if(t.sprite_arrow)then self:MakePointArrow(tps,i,t.sprite_arrow) end + if (t.sprites) then self:MakePointSprites(tps, i, t.sprites) end + if (t.sprite_arrow) then self:MakePointArrow(tps, i, t.sprite_arrow) end end - if(epos or not t.gate)then self:CheckPointLogistics(i) end - - local ce=cache.force_entity(p.ent,"Teleporters",self.key,"points",i) -end - - -warptorio.arrowSprite={sprite="utility/medium_gui_arrow",target_offset={0.75,-0.75},x_scale=0.4,y_scale=0.4} - -function TELL:MakePointArrow(tps,i,arrow) - local spid=self.sprite_arrows[i] - if(spid and rendering.is_valid(spid))then return end - local tp=self.points[i].ent - local t=table.deepcopy(warptorio.arrowSprite) - t.surface=tp.surface - t.target=tp - t.only_in_alt_mode=true - t.render_layer="higher-object-above" - t.orientation=(arrow=="down" and 0.5 or 0) - self.sprite_arrows[i]=rendering.draw_sprite(t) -end - -function TELL:MakePointSprites(tps,i,sprites) - for k,v in pairs(sprites)do - local spid=self.sprites[i][k] - if(not (spid and rendering.is_valid(spid)))then - local tp=self.points[i].ent - local t=table.deepcopy(v) - t.surface=tp.surface t.target=tp t.only_in_alt_mode=true t.render_layer="higher-object-under" - self.sprites[i][k]=rendering.draw_sprite(t) + if (epos or not t.gate) then self:CheckPointLogistics(i) end + + local ce = cache.force_entity(p.ent, "Teleporters", self.key, "points", i) +end + +warptorio.arrowSprite = { sprite = "utility/medium_gui_arrow", target_offset = { 0.75, -0.75 }, x_scale = 0.5, y_scale = 0.5 } + +function TELL:MakePointArrow(tps, i, arrow) + local spid = self.sprite_arrows[i] + if (spid and spid.valid) then return end + local tp = self.points[i].ent + local t = table.deepcopy(warptorio.arrowSprite) + t.surface = tp.surface + t.target = tp + t.only_in_alt_mode = true + t.render_layer = "higher-object-above" + t.orientation = (arrow == "down" and 0.5 or 0) + self.sprite_arrows[i] = rendering.draw_sprite(t) +end + +function TELL:MakePointSprites(tps, i, sprites) + for k, v in pairs(sprites) do + local spid = self.sprites[i][k] + if (not (spid and spid.valid)) then + local tp = self.points[i].ent + local t = table.deepcopy(v) + t.surface = tp.surface + t.target = tp + t.only_in_alt_mode = true + t.render_layer = "higher-object-under" + self.sprites[i][k] = rendering.draw_sprite(t) end end end - -function TELL:GetLoaderDirection() local tps=self:Data() - if(tps.dirsetting)then return warptorio.setting(tps.dirsetting) end - return (tps.staticdir and tps.staticdir or (tps.top and warptorio.setting("loader_top") or warptorio.setting("loader_bottom"))) or "up" +function TELL:GetLoaderDirection() + local tps = self:Data() + if (tps.dirsetting) then return warptorio.setting(tps.dirsetting) end + return (tps.staticdir and tps.staticdir or (tps.top and warptorio.setting("loader_top") or warptorio.setting("loader_bottom"))) or + "up" end function TELL:DestroyPointLogistics(o) - if(self.chests)then for k,v in pairs(self.chests[o])do self.chestcontents[o][k]=v.get_inventory(defines.inventory.chest).get_contents() entity.destroy(v) self.chests[o][k]=nil end end - for k,v in pairs(self.loaders[o])do if(v and isvalid(v))then - self.loaderFilter[o][k]={} for i=1,v.filter_slot_count,1 do self.loaderFilter[o][k][i]=v.get_filter(i) end entity.destroy(v) - end self.loaders[o][k]=nil end - for k,v in pairs(self.pipes[o])do entity.destroy(v) self.pipes[o][k]=nil end + if (self.chests) then + for k, v in pairs(self.chests[o]) do + self.chestcontents[o][k] = v.get_inventory(defines.inventory.chest).get_contents() + entity.destroy(v) + self.chests[o][k] = nil + end + end + for k, v in pairs(self.loaders[o]) do + if (v and isvalid(v)) then + self.loaderFilter[o][k] = {} + for i = 1, v.filter_slot_count, 1 do self.loaderFilter[o][k][i] = v.get_filter(i) end + entity.destroy(v) + end + self.loaders[o][k] = nil + end + for k, v in pairs(self.pipes[o]) do + entity.destroy(v) + self.pipes[o][k] = nil + end end -function TELL:RemakeChestPair(o,k) local e=self.chests[o][k] local ex=warptorio.GetChest(self.dir[o][k]) - if(e and e.name~=ex)then - local v=entity.protect(entity.create(e.surface,ex,e.position),false,false) entity.copy.chest(e,v) - entity.destroy(e) self.chests[o][k]=v if(self.dir[o][k]=="input")then entity.ChestRequestMode(v) end - cache.get_raise_type("types",v.type,v,"Teleporters",self.key,"chests",o,k) +function TELL:RemakeChestPair(o, k) + local e = self.chests[o][k] + local ex = warptorio.GetChest(self.dir[o][k]) + if (e and e.name ~= ex) then + local v = entity.protect(entity.create(e.surface, ex, e.position), false, false) + entity.copy.chest(e, v) + entity.destroy(e) + self.chests[o][k] = v + if (self.dir[o][k] == "input") then entity.ChestRequestMode(v) end + cache.get_raise_type("types", v.type, v, "Teleporters", self.key, "chests", o, k) end end -function TELL:SwapLoaderChests(id) self:RemakeChestPair(1,id) self:RemakeChestPair(2,id) end -function TELL:UpgradeChests() for i=1,6,1 do self:SwapLoaderChests(i) end end -function TELL:GetTeleporterSize() local d=self:Data() return warptorio.GetTeleporterSize(d.logs,d.dualloader,d.triloader) end -function TELL:GetLogisticsArea(o) return vector.square(o or self:Data().position,self:GetTeleporterSize()) end +function TELL:SwapLoaderChests(id) + self:RemakeChestPair(1, id) + self:RemakeChestPair(2, id) +end +function TELL:UpgradeChests() for i = 1, 6, 1 do self:SwapLoaderChests(i) end end +function TELL:GetTeleporterSize() + local d = self:Data() + return warptorio.GetTeleporterSize(d.logs, d.dualloader, d.triloader) +end +function TELL:GetLogisticsArea(o) return vector.square(o or self:Data().position, self:GetTeleporterSize()) end -function TELL:MakePointLoader(tps,i,id,ido,pos,f,belt,lddir,chesty,belty,vexdir) - local offld=tps.pair[i].prototype and 1 or 0 +function TELL:MakePointLoader(tps, i, id, ido, pos, f, belt, lddir, chesty, belty, vexdir) + local offld = tps.pair[i].prototype and 1 or 0 - local v=self.loaders[i][id] - if(isvalid(v) and v.name~=belt)then v.destroy{raise_destroy=true} end - if(not isvalid(v))then - local vpos=vector(pos)+vector((offld+ido)*vexdir,belty) - local varea=vector.square(vpos+vector(0,0.5),vector(1,1)) - vector.clean(f,varea) - v=entity.protect(entity.create(f,belt,vpos,lddir),false,false) - vector.cleanplayers(f,varea) - v.loader_type=self.dir[i][id] - self.loaders[i][id]=v - local inv=self.loaderFilter[i][id] if(inv)then for invx,invy in pairs(inv)do v.set_filter(invx,invy) end end + local v = self.loaders[i][id] + if (isvalid(v) and v.name ~= belt) then v.destroy { raise_destroy = true } end + if (not isvalid(v)) then + local vpos = vector(pos) + vector((offld + ido) * vexdir, belty) + local varea = vector.square(vpos + vector(0, 0.5), vector(1, 1)) + vector.clean(f, varea) + v = entity.protect(entity.create(f, belt, vpos, lddir), false, false) + vector.cleanplayers(f, varea) + v.loader_type = self.dir[i][id] + self.loaders[i][id] = v + local inv = self.loaderFilter[i][id] + if (inv) then for invx, invy in pairs(inv) do v.set_filter(invx, invy) end end end - cache.force_entity(v,"Teleporters",self.key,"loaders",i,id) + cache.force_entity(v, "Teleporters", self.key, "loaders", i, id) - local v=self.chests[i][id] - local chest=warptorio.GetChest(self.dir[i][id]) - if(isvalid(v) and v.name~=chest)then self.chestcontents[i][id]=v.get_inventory(defines.inventory.chest).get_contents() v.destroy{raise_destroy=true} end - if(not isvalid(v))then - local vpos=vector(pos)+vector((offld+ido)*vexdir,chesty) - local varea=vector.square(vpos,vector(0.5,0.5)) - vector.clean(f,varea) - v=entity.protect(entity.create(f,chest,vpos),false,false) - vector.cleanplayers(f,varea) - self.chests[i][id]=v - local inv=self.chestcontents[i][id] - if(inv)then local cv=v.get_inventory(defines.inventory.chest) for x,y in pairs(inv)do cv.insert{name=x,count=y} end self.chestcontents[i][id]=nil end - --if(v.type=="logistic-container")then entity.ChestRequestMode(r) end + local v = self.chests[i][id] + local chest = warptorio.GetChest(self.dir[i][id]) + if (isvalid(v) and v.name ~= chest) then + self.chestcontents[i][id] = v.get_inventory(defines.inventory.chest).get_contents() + v.destroy { raise_destroy = true } end - cache.get_raise_type("types",v.type,v,"Teleporters",self.key,"chests",i,id) - - + if (not isvalid(v)) then + local vpos = vector(pos) + vector((offld + ido) * vexdir, chesty) + local varea = vector.square(vpos, vector(0.5, 0.5)) + vector.clean(f, varea) + v = entity.protect(entity.create(f, chest, vpos), false, false) + vector.cleanplayers(f, varea) + self.chests[i][id] = v + local inv = self.chestcontents[i][id] + if (inv) then + local cv = v.get_inventory(defines.inventory.chest) + for x, y in pairs(inv) do cv.insert { name = y.name, count = y.count } end + self.chestcontents[i][id] = nil + end + --if(v.type=="logistic-container")then entity.ChestRequestMode(r) end + end + cache.get_raise_type("types", v.type, v, "Teleporters", self.key, "chests", i, id) end -function TELL:MakePointLoaders(tps,i,id,pos,f,belt,lddir,chesty,belty) - if(not tps.oneside or tps.oneside=="right")then self:MakePointLoader(tps,i,id,id,pos,f,belt,lddir,chesty,belty,1) end - if(not tps.oneside or tps.oneside=="left")then self:MakePointLoader(tps,i,id+3,id,pos,f,belt,lddir,chesty,belty,-1) end + +function TELL:MakePointLoaders(tps, i, id, pos, f, belt, lddir, chesty, belty) + if (not tps.oneside or tps.oneside == "right") then + self:MakePointLoader(tps, i, id, id, pos, f, belt, lddir, chesty, + belty, 1) + end + if (not tps.oneside or tps.oneside == "left") then + self:MakePointLoader(tps, i, id + 3, id, pos, f, belt, lddir, + chesty, belty, -1) + end end -function TELL:MakePointPipes(tps,i,id,pos,f,dist,vexdir,ido) -- TODO: Initial pipe dir & remember direction - local pipe="warptorio-logistics-pipe" - local v=self.pipes[i][id] - local vpos=vector(pos)+vector(dist*vexdir,2-ido) - local pipedir=(vexdir==1 and 2 or 6) - if(isvalid(v) and (v.surface~=f or v.position.x~=vpos.x or v.position.y~=vpos.y))then pipedir=v.direction entity.destroy(v) end - if(not isvalid(v))then - local varea=vector.square(vpos,vector(0.5,0.5)) - vector.clean(f,varea) - v=entity.protect(entity.create(f,pipe,vpos,pipedir),false,false) - vector.cleanplayers(f,varea) - self.pipes[i][id]=v + +function TELL:MakePointPipes(tps, i, id, pos, f, dist, vexdir, ido) -- TODO: Initial pipe dir & remember direction + local pipe = "warptorio-logistics-pipe" + local v = self.pipes[i][id] + local vpos = vector(pos) + vector(dist * vexdir, 2 - ido) + local pipedir = (vexdir == 1 and 3 or 6) + if (isvalid(v) and (v.surface ~= f or v.position.x ~= vpos.x or v.position.y ~= vpos.y)) then + pipedir = v.direction + entity.destroy(v) + end + if (not isvalid(v)) then + local varea = vector.square(vpos, vector(0.5, 0.5)) + vector.clean(f, varea) + v = entity.protect(entity.create(f, pipe, vpos, pipedir * 2), false, false) + vector.cleanplayers(f, varea) + self.pipes[i][id] = v end - cache.force_entity(v,"Teleporters",self.key,"pipes",i,id) + cache.force_entity(v, "Teleporters", self.key, "pipes", i, id) end + function TELL:CheckEmptyPipes() - local ppr={} for a,b in pairs(self.pipes)do for k,v in pairs(b)do if(isvalid(v) and table_size(v.neighbours[1])>=1)then ppr[k]=true end end end - for a,b in pairs(self.pipes)do for k,v in pairs(b)do if(isvalid(v) and not ppr[k])then v.clear_fluid_inside() end end end -end - -function TELL:CheckPointLogistics(i,vxpos) - local tps=self:Data() - local t=tps.pair[i] - if(not tps.logs and not tps.dualloader and not tps.triloader)then return end - local belt=warptorio.GetBelt() - local pos=vxpos or t.position+vector(0.5,0.5) - if(t.gate and not vxpos)then if(not isvalid(self.points[i].ent))then return end pos=vector(self.points[i].ent.position) end - local f=global.floor[t.floor].host - local offld=tps.pair[i].prototype and 1 or 0 - local lddir,chesty,belty - if(self:GetLoaderDirection()=="up")then lddir=defines.direction.north chesty=-1 belty=0 else lddir=defines.direction.south chesty=1 belty=-1 end - local ldl=0 - local lvLogs=research.level("warptorio-logistics") - if(tps.logs and lvLogs>0)then ldl=ldl+1 end - if(tps.dualloader and research.has("warptorio-dualloader-1"))then ldl=ldl+1 end - if(tps.triloader and research.has("warptorio-triloader"))then ldl=ldl+1 end - local can=true - if(t.gate)then -- check if placement area is clear - local vsize=offld+ldl+(tps.dopipes and 1 or 0) - local varea=vector.square(pos,vector(vsize*2,3)) - if(f.count_entities_filtered{area=varea,collision_mask={"object-layer"}} >1)then - f.create_entity{name="flying-text", position=pos, text="Logistics blocked - Needs more space", color={r=1,g=0.5,b=0.5}} - f.play_sound{path="utility/cannot_build",position=pos} - --game.print("Planet Teleporter Gate Logistics were blocked by nearby obstructions") - can=false + local ppr = {} + for a, b in pairs(self.pipes) do for k, v in pairs(b) do if (isvalid(v) and table_size(v.neighbours[1]) >= 1) then ppr[k] = true end end end + for a, b in pairs(self.pipes) do for k, v in pairs(b) do if (isvalid(v) and not ppr[k]) then v.clear_fluid_inside() end end end +end + +function TELL:CheckPointLogistics(i, vxpos) + local tps = self:Data() + local t = tps.pair[i] + if (not tps.logs and not tps.dualloader and not tps.triloader) then return end + local belt = warptorio.GetBelt() + local pos = vxpos or t.position + vector(0.5, 0.5) + if (t.gate and not vxpos) then + if (not isvalid(self.points[i].ent)) then return end + pos = vector(self.points[i].ent.position) + end + local f = storage.floor[t.floor].host + local offld = tps.pair[i].prototype and 1 or 0 + local lddir, chesty, belty + if (self:GetLoaderDirection() == "up") then + lddir = defines.direction.south + chesty = -1 + belty = 0 + else + lddir = defines.direction.north + chesty = 1 + belty = -1 + end + local ldl = 0 + local lvLogs = research.level("warptorio-logistics") + if (tps.logs and lvLogs > 0) then ldl = ldl + 1 end + if (tps.dualloader and research.has("warptorio-dualloader-1")) then ldl = ldl + 1 end + if (tps.triloader and research.has("warptorio-triloader")) then ldl = ldl + 1 end + local can = true + if (t.gate) then -- check if placement area is clear + local vsize = offld + ldl + (tps.dopipes and 1 or 0) + local varea = vector.square(pos, vector(vsize * 2, 3)) + -- if(f.count_entities_filtered{area=varea,collision_mask={"object-layer"}} >1)then + if (f.count_entities_filtered { area = varea, collision_mask = "object" } > 1) then + --f.create_entity { name = "flying-text", position = pos, text = "Logistics blocked - Needs more space", color = { r = 1, g = 0.5, b = 0.5 } } + game.print({ "warptorio.teleporter-blocked-error" }) + f.play_sound { path = "utility/cannot_build", position = pos } + can = false + end + end + if (can and ldl > 0) then + for id = 1, ldl, 1 do + self:MakePointLoaders(tps, i, id, pos, f, belt, lddir, chesty, belty) + end + end + if (can and tps.dopipes and lvLogs > 0) then + for id = 1, math.min(lvLogs, 3), 1 do -- pipes first, it removes the old ones + if (not tps.oneside or tps.oneside == "right") then + self:MakePointPipes(tps, i, id, pos, f, ldl + offld + 1, + 1, id) + end + if (not tps.oneside or tps.oneside == "left") then + self:MakePointPipes(tps, i, id + 3, pos, f, ldl + offld + + 1, -1, id) + end end end - if(can and ldl>0)then for id=1,ldl,1 do - self:MakePointLoaders(tps,i,id,pos,f,belt,lddir,chesty,belty) - end end - if(can and tps.dopipes and lvLogs>0)then for id=1,math.min(lvLogs,3),1 do -- pipes first, it removes the old ones - if(not tps.oneside or tps.oneside=="right")then self:MakePointPipes(tps,i,id,pos,f,ldl+offld+1,1,id) end - if(not tps.oneside or tps.oneside=="left")then self:MakePointPipes(tps,i,id+3,pos,f,ldl+offld+1,-1,id) end - end end end --[[ -function events.on_tick("logistics_teleporters",function(ev) for k,v in pairs(global.Teleporters)do v:TickLogistics() end end end) +function events.on_tick("logistics_teleporters",function(ev) for k,v in pairs(storage.Teleporters)do v:TickLogistics() end end end) -function TELL:TickLogistics() +function TELL:TickLogistics() for k,v in pairs(self.chests[1])do if(isvalid(self.chests[2][k]))then if(self.dir[1][k]=="input")then warptorio.BalanceLogistics(v,self.chests[2][k]) else warptorio.BalanceLogistics(self.chests[2][k],v) end end end @@ -401,4 +545,3 @@ function TELL:TickLogistics() warptorio.BalanceLogistics(v,self.pipes[2][k]) end end end]] - diff --git a/control_main.lua b/control_main.lua index c6f1d41..e5997e3 100644 --- a/control_main.lua +++ b/control_main.lua @@ -20,269 +20,348 @@ Status bar wastes screen space, don't use it. Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. -]]--------------------------------------- +]] --------------------------------------- -local planets=lib.planets +local planets = lib.planets ---[[ Warptorio Environment ]]-- +--[[ Warptorio Environment ]] -- -warptorio=warptorio or {} -warptorio.Loaded=false +warptorio = warptorio or {} +warptorio.Loaded = false require("control_main_helpers") -warptorio.platform=require("control_platform_classic") -local platform=warptorio.platform +warptorio.platform = require("control_platform_classic") +local platform = warptorio.platform require("control_class_teleporter") require("control_class_harvester") require("control_class_rails") -warptorio.chatcmd={} + +warptorio.chatcmd = {} function warptorio.chatcmd.kill(ev) - local ply=game.players[ev.player_index] local c=ply.character - if(c and c.valid)then c.die(c.force,c) end + local ply = game.players[ev.player_index] + local c = ply.character + if (c and c.valid) then c.die(c.force, c) end end -commands.add_command("kill","Suicides the player",warptorio.chatcmd.kill) + +commands.add_command("kill", "Suicides the player", warptorio.chatcmd.kill) ---[[ Warptorio custom events ]]-- +--[[ Warptorio custom events ]] -- -- Hook in on_load with -- local eventdefs=remote.call("warptorio","get_events") -- script.on_event(eventdefs["on_warp"],func() end) -events.register("on_warp") -- during Warpout() -events.register("on_post_warp") -- during Warpout() -events.register("warp_started") -- StartWarp() -events.register("warp_stopped") -- StopWarp() +events.register("on_warp") -- during Warpout() +events.register("on_post_warp") -- during Warpout() +events.register("warp_started") -- StartWarp() +events.register("warp_stopped") -- StopWarp() events.register("harvester_deploy") -- ? events.register("harvester_recall") -- ? -events.register("ability_used") -- ? - +events.register("ability_used") -- ? +--[[ Warptorio Libraries ]] -- ---[[ Warptorio Libraries ]]-- +warptorio.ChestBeltPairs = { { "loader", "wooden-chest" }, { "fast-loader", "iron-chest" }, { "express-loader", "steel-chest" }, + { "express-loader", function(dir) return (dir == "output" and warptorio.setting("loaderchest_provider") or warptorio.setting("loaderchest_requester")) end }, +} +warptorio.ChestBeltPairs[0] = { "loader", "wooden-chest" } +function warptorio.GetChest(dir) + local lv = research.level("warptorio-logistics") + local lvb = warptorio.ChestBeltPairs[lv] + return (isstring(lvb[2]) and lvb[2] or lvb[2](dir)) +end +function warptorio.GetBelt(dir) + local lv = research.level("warptorio-logistics") + local lvb = warptorio.ChestBeltPairs[lv] + return (isstring(lvb[1]) and lvb[1] or lvb[1](dir)) +end -warptorio.ChestBeltPairs={{"loader","wooden-chest"},{"fast-loader","iron-chest"},{"express-loader","steel-chest"}, - {"express-loader",function(dir) return (dir=="output" and warptorio.setting("loaderchest_provider") or warptorio.setting("loaderchest_requester")) end}, -} -warptorio.ChestBeltPairs[0]={"loader","wooden-chest"} -function warptorio.GetChest(dir) local lv=research.level("warptorio-logistics") local lvb=warptorio.ChestBeltPairs[lv] return (isstring(lvb[2]) and lvb[2] or lvb[2](dir)) end -function warptorio.GetBelt(dir) local lv=research.level("warptorio-logistics") local lvb=warptorio.ChestBeltPairs[lv] return (isstring(lvb[1]) and lvb[1] or lvb[1](dir)) end --remotes.register("GetChest",warptorio.GetChest) --remotes.register("GetBelt",warptorio.GetBelt) ---[[ Warptorio Platform ]]-- +--[[ Warptorio Platform ]] -- function warptorio.GetPlatform() return warptorio.platform end -function warptorio.GetCurrentSurface() return global.floor.main.host end -function warptorio.GetMainSurface() return global.floor.main.host end -function warptorio.GetHomeSurface() return global.floor.home and global.floor.home.host or nil end + +function warptorio.GetCurrentSurface() return storage.floor.main.host end + +function warptorio.GetMainSurface() return storage.floor.main.host end + +function warptorio.GetHomeSurface() return storage.floor.home and storage.floor.home.host or nil end + function warptorio.GetMainPlanet() return planets.GetBySurface(warptorio.GetMainSurface()) end -- planetorio + function warptorio.GetHomePlanet() return planets.GetBySurface(warptorio.GetHomeSurface()) end -- planetorio -function warptorio.GetNamedSurfaces(tbl) local t={} for k,nm in pairs(tbl)do t[nm]=global.floor[nm].host end return t end -function warptorio.GetAllSurfaces() local t={} for nm,v in pairs(global.floor)do t[v.hostindex]=v.host end return t end -function warptorio.GetPlatformSurfaces() local t={} for nm,v in pairs(global.floor)do if(platform.floors[nm].empty==true)then t[v.hostindex]=v.host end end return t end +function warptorio.GetNamedSurfaces(tbl) + local t = {} + for k, nm in pairs(tbl) do t[nm] = storage.floor[nm].host end + return t +end + +function warptorio.GetAllSurfaces() + local t = {} + for nm, v in pairs(storage.floor) do t[v.hostindex] = v.host end + return t +end +function warptorio.GetPlatformSurfaces() + local t = {} + for nm, v in pairs(storage.floor) do if (platform.floors[nm].empty == true) then t[v.hostindex] = v.host end end + return t +end -function warptorio.GetTeleporterSize(a,b,c,noproto) -- for clearing - local x=1 - if(a and research.has("warptorio-logistics-1"))then x=x+2 end - if(b and research.has("warptorio-dualloader-1"))then x=x+1 end - if(c and research.has("warptorio-triloader"))then x=x+1 end - return vector((x*2)+2,2) +function warptorio.GetTeleporterSize(a, b, c, noproto) -- for clearing + local x = 1 + if (a and research.has("warptorio-logistics-1")) then x = x + 2 end + if (b and research.has("warptorio-dualloader-1")) then x = x + 1 end + if (c and research.has("warptorio-triloader")) then x = x + 1 end + return vector((x * 2) + 2, 2) end -function warptorio.GetTeleporterHazard(bMain,bFull) -- for hazard tiles - local x=0 - bFull=(bFull==nil and true or bFull) -- has the tech, or -1 - local lgHas=research.has("warptorio-logistics-1") - local dlHas=research.has("warptorio-dualloader-1") - local tlHas=research.has("warptorio-triloader") - local lgCan=research.can("warptorio-logistics-1") - local dlCan=research.can("warptorio-dualloader-1") - local tlCan=research.can("warptorio-triloader") - - if(lgCan or lgHas)then x=x+2 end - - if(bMain)then - if(tlHas and dlHas)then x=x+2 - elseif(tlHas or dlHas)then x=x+1 if(bFull and ( (not tlHas and tlCan) or (not dlHas and dlCan) ) )then x=x+1 end - elseif(bFull and (tlCan or dlCan))then x=x+1 + +function warptorio.GetTeleporterHazard(bMain, bFull) -- for hazard tiles + local x = 0 + bFull = (bFull == nil and true or bFull) -- has the tech, or -1 + local lgHas = research.has("warptorio-logistics-1") + local dlHas = research.has("warptorio-dualloader-1") + local tlHas = research.has("warptorio-triloader") + local lgCan = research.can("warptorio-logistics-1") + local dlCan = research.can("warptorio-dualloader-1") + local tlCan = research.can("warptorio-triloader") + + if (lgCan or lgHas) then x = x + 2 end + + if (bMain) then + if (tlHas and dlHas) then + x = x + 2 + elseif (tlHas or dlHas) then + x = x + 1 + if (bFull and ((not tlHas and tlCan) or (not dlHas and dlCan))) then x = x + 1 end + elseif (bFull and (tlCan or dlCan)) then + x = x + 1 end else - if(tlCan)then x=x+1 end + if (tlCan) then x = x + 1 end end - return vector((x*2)+2,2) + return vector((x * 2) + 2, 2) end -warptorio.EmptyGenSettings={default_enable_all_autoplace_controls=false,width=32*12,height=32*12, - autoplace_settings={entity={treat_missing_as_default=false},tile={treat_missing_as_default=false},decorative={treat_missing_as_default=false}, }, starting_area="none",} +warptorio.EmptyGenSettings = { + default_enable_all_autoplace_controls = false, + width = 32 * 12, + height = 32 * 12, + autoplace_settings = { entity = { treat_missing_as_default = false }, tile = { treat_missing_as_default = false }, decorative = { treat_missing_as_default = false }, }, + starting_area = "none", +} function warptorio.MakePlatformFloor(vt) - local f=game.create_surface(vt.name,(vt.empty and warptorio.EmptyGenSettings or nil)) - if(vt.empty)then - f.solar_power_multiplier=settings.global.warptorio_solar_multiplier.value - f.daytime=0 - f.always_day=true - f.request_to_generate_chunks({0,0},16) + local f = game.create_surface(vt.name, (vt.empty and warptorio.EmptyGenSettings or nil)) + if (vt.empty) then + f.solar_power_multiplier = settings.global.warptorio_solar_multiplier.value + f.daytime = 0 + f.always_day = true + f.request_to_generate_chunks({ 0, 0 }, 16) f.force_generate_chunk_requests() f.destroy_decoratives({}) - for k,v in pairs(f.find_entities())do entity.destroy(v) end - local area=vector.area(vector(-32*8,-32*8),vector(32*8*2,32*8*2)) - vector.LayTiles("out-of-map",f,area) + for k, v in pairs(f.find_entities()) do entity.destroy(v) end + local area = vector.area(vector(-32 * 8, -32 * 8), vector(32 * 8 * 2, 32 * 8 * 2)) + vector.LayTiles("out-of-map", f, area) end - local floor=cache.raise_surface(f) - if(vt.init)then lib.call(vt.init,floor) end - global.floor[vt.key]=floor + local floor = cache.raise_surface(f) + if (vt.init) then lib.call(vt.init, floor) end + storage.floor[vt.key] = floor return floor end -function warptorio.GetPlatformFloor(vt) if(isstring(vt))then vt=warptorio.platform.floors[vt] end +function warptorio.GetPlatformFloor(vt) + if (isstring(vt)) then vt = warptorio.platform.floors[vt] end local floor - if(vt.key=="main")then -- Special; nauvis / primary planet - floor=global.floor.main if(not floor)then floor={key=vt.key,host=game.surfaces.nauvis,hostindex=1} global.floor.main=floor if(vt.init)then lib.call(vt.init,floor) end end - elseif(vt.key=="home")then -- Special; homeworld - floor=global.floor.home if(not floor)then floor={key=vt.key,host=game.surfaces.nauvis,hostindex=1} global.floor.home=floor end + if (vt.key == "main") then -- Special; nauvis / primary planet + floor = storage.floor.main + if (not floor) then + floor = { key = vt.key, host = game.surfaces.nauvis, hostindex = 1 } + storage.floor.main = floor + if (vt.init) then lib.call(vt.init, floor) end + end + elseif (vt.key == "home") then -- Special; homeworld + floor = storage.floor.home + if (not floor) then + floor = { key = vt.key, host = game.surfaces.nauvis, hostindex = 1 } + storage.floor.home = floor + end else - floor=global.floor[vt.key] if(not floor)then floor=warptorio.MakePlatformFloor(vt) end - floor.key=vt.key + floor = storage.floor[vt.key] + if (not floor) then floor = warptorio.MakePlatformFloor(vt) end + floor.key = vt.key end return floor end -function warptorio.ConstructFloor(fn,bhzd) warptorio.ConstructPlatform(platform.floors[fn],bhzd) end +function warptorio.ConstructFloor(fn, bhzd) warptorio.ConstructPlatform(platform.floors[fn], bhzd) end + function warptorio.ConstructFloorHazard(fn) warptorio.ConstructHazard(platform.floors[fn]) end function warptorio.ConstructPlatformVoid(surf) - local vt=warptorio.platform.floors["main"] if(vt.tile)then lib.call(vt.tile,surf,true) end + local vt = warptorio.platform.floors["main"] + if (vt.tile) then lib.call(vt.tile, surf, true) end +end + +function warptorio.ConstructPlatform(vt, bhzd) + if (isstring(vt)) then vt = warptorio.platform.floors[vt] end + local floor = warptorio.GetPlatformFloor(vt) + if (floor) then + if (vt.tile) then lib.call(vt.tile, floor.host) end + if (bhzd and vt.hazard) then lib.call(vt.hazard, floor.host) end + end end -function warptorio.ConstructPlatform(vt,bhzd) - if(isstring(vt))then vt=warptorio.platform.floors[vt] end - local floor=warptorio.GetPlatformFloor(vt) if(floor)then - if(vt.tile)then lib.call(vt.tile,floor.host) end - if(bhzd and vt.hazard)then lib.call(vt.hazard,floor.host) end -end end function warptorio.ConstructPlatforms(bhzd) - local platform=warptorio.GetPlatform() - for nm,vt in pairs(platform.floors)do warptorio.ConstructPlatform(vt,bhzd) end + local platform = warptorio.GetPlatform() + for nm, vt in pairs(platform.floors) do warptorio.ConstructPlatform(vt, bhzd) end end function warptorio.ConstructHazard(vt) - if(isstring(vt))then vt=warptorio.platform.floors[vt] end - local floor=warptorio.GetPlatformFloor(vt) - if(floor and vt.hazard)then lib.call(vt.hazard,floor.host) end + if (isstring(vt)) then vt = warptorio.platform.floors[vt] end + local floor = warptorio.GetPlatformFloor(vt) + if (floor and vt.hazard) then lib.call(vt.hazard, floor.host) end end function warptorio.ConstructHazards() - local platform=warptorio.GetPlatform() - for nm,vt in pairs(platform.floors)do warptorio.ConstructHazard(vt) end + local platform = warptorio.GetPlatform() + for nm, vt in pairs(platform.floors) do warptorio.ConstructHazard(vt) end end -function warptorio.CheckFloorRadar(floor) if(research.has("warptorio-charting") and not isvalid(floor.radar))then - floor.radar=entity.protect(entity.create(floor.host,"warptorio-invisradar",vector(-1,-1)),false,false) -end end - +function warptorio.CheckFloorRadar(floor) + if (research.has("warptorio-charting") and not isvalid(floor.radar)) then + floor.radar = entity.protect(entity.create(floor.host, "warptorio-invisradar", vector(-1, -1)), false, false) + end +end function warptorio.CheckPlatformSpecials(self) - local platform=warptorio.platform - local vfloor=platform.floors[self.key] - if(not vfloor)then + local platform = warptorio.platform + local vfloor = platform.floors[self.key] + if (not vfloor) then game.print("no vfloor error: " .. serpent.line(self)) end - local sp=vfloor.special if(not sp)then return end - if(not sp.upgrade)then if(not research.has(sp.tech) or isvalid(self.SpecialEnt))then return end elseif(research.level(sp.tech)<1)then return end - local protoname=sp.prototype - local inv={} - if(sp.upgrade)then protoname=protoname.."-"..research.level(sp.tech) - if(isvalid(self.SpecialEnt) and self.SpecialEnt.name==protoname)then return elseif(isvalid(self.SpecialEnt))then inv=warptorio.DestroyPlatformSpecial(self) end + local sp = vfloor.special + if (not sp) then return end + if (not sp.upgrade) then if (not research.has(sp.tech) or isvalid(self.SpecialEnt)) then return end elseif (research.level(sp.tech) < 1) then return end + local protoname = sp.prototype + local inv = {} + if (sp.upgrade) then + protoname = protoname .. "-" .. research.level(sp.tech) + if (isvalid(self.SpecialEnt) and self.SpecialEnt.name == protoname) then + return + elseif (isvalid(self.SpecialEnt)) then + inv = + warptorio.DestroyPlatformSpecial(self) + end end - local f=self.host - local efply={} - local area=vector.square(vector(-0.5,-0.5),sp.size) - local eft=f.find_entities_filtered{area=area} - local rdr=false if(isvalid(self.radar))then rdr=true entity.destroy(self.radar) end - for k,v in pairs(eft)do if(isvalid(v))then if(v.type=="character")then table.insert(efply,v) elseif(v~=self.radar)then entity.destroy(v) end end end + local f = self.host + local efply = {} + local area = vector.square(vector(-0.5, -0.5), sp.size) + local eft = f.find_entities_filtered { area = area } + local rdr = false + if (isvalid(self.radar)) then + rdr = true + entity.destroy(self.radar) + end + for k, v in pairs(eft) do + if (isvalid(v)) then + if (v.type == "character") then + table.insert(efply, v) + elseif (v ~= self.radar) then + entity.destroy(v) + end + end + end - local e=entity.protect(entity.create(f,protoname,vector(-0.5,-0.5)),false,false) - self.SpecialEnt=e - if(inv)then for k,v in pairs(inv)do e.get_module_inventory().insert{name=k,count=v} end end -- beacon modules. Close enough. + local e = entity.protect(entity.create(f, protoname, vector(-0.5, -0.5)), false, false) + self.SpecialEnt = e + if (inv) then for k, v in pairs(inv) do e.get_module_inventory().insert { name = v.name, count = v.count } end end -- beacon modules. Close enough. warptorio.CheckFloorRadar(self) - vector.cleanplayers(f,area) - players.playsound("warp_in",f) + vector.cleanplayers(f, area) + players.playsound("warp_in", f) end -function warptorio.DestroyPlatformSpecial(self) local inv - if(isvalid(self.SpecialEnt))then local x=self.SpecialEnt.get_module_inventory() if(x)then inv=x.get_contents() end entity.destroy(self.SpecialEnt) end - self.SpecialEnt=nil return inv - +function warptorio.DestroyPlatformSpecial(self) + local inv + if (isvalid(self.SpecialEnt)) then + local x = self.SpecialEnt.get_module_inventory() + if (x) then inv = x.get_contents() end + entity.destroy(self.SpecialEnt) + end + self.SpecialEnt = nil + return inv end function warptorio.InitPlatform() - global.floor={} + storage.floor = {} - for nm,vt in pairs(warptorio.platform.floors)do - local floor=warptorio.GetPlatformFloor(vt) - if(floor)then - warptorio.ConstructPlatform(vt,true) + for nm, vt in pairs(warptorio.platform.floors) do + local floor = warptorio.GetPlatformFloor(vt) + if (floor) then + warptorio.ConstructPlatform(vt, true) end end end - - - - ---[[ Bootstrap Initialization and Migrations ]]-- +--[[ Bootstrap Initialization and Migrations ]] -- events.on_init(function() events.raise_migrate() lib.planets.lua() warptorio.ValidateWarpBlacklist() --warptorio.HookNewGamePlus() -end) - + -- Custom Intro Message + remote.call("freeplay", "set_custom_intro_message", { "warptorio.intro" }) + -- Disable Rocket Victory + if remote.interfaces.silo_script then + remote.call("silo_script", "set_no_victory", true) + end +end) function warptorio.ApplyMapSettings() - local gmp=game.map_settings + local gmp = game.map_settings gmp.pollution.diffusion_ratio = 0.105 - gmp.pollution.pollution_factor = 0.0000001 - gmp.pollution.min_to_diffuse=15 -- default 15 - gmp.pollution.ageing=1.0 -- 1.0 - gmp.pollution.expected_max_per_chunk=250 - gmp.pollution.min_to_show_per_chunk=50 - gmp.pollution.pollution_restored_per_tree_damage=9 - gmp.pollution.enemy_attack_pollution_consumption_modifier=1.0 + gmp.pollution.min_to_diffuse = 15 -- default 15 + gmp.pollution.ageing = 1.0 -- 1.0 + gmp.pollution.expected_max_per_chunk = 250 + gmp.pollution.min_to_show_per_chunk = 50 + gmp.pollution.pollution_restored_per_tree_damage = 9 + gmp.pollution.enemy_attack_pollution_consumption_modifier = 1.0 - gmp.enemy_evolution.destroy_factor=0.0002 -- default 0.002 + gmp.enemy_evolution.pollution_factor = 0.0000001 + gmp.enemy_evolution.destroy_factor = 0.0002 -- default 0.002 gmp.unit_group.min_group_gathering_time = 600 gmp.unit_group.max_group_gathering_time = 2 * 600 gmp.unit_group.max_unit_group_size = 200 gmp.unit_group.max_wait_time_for_late_members = 2 * 360 - gmp.unit_group.settler_group_min_size = 1 - gmp.unit_group.settler_group_max_size = 1 + gmp.enemy_expansion.settler_group_min_size = 1 + gmp.enemy_expansion.settler_group_max_size = 1 --gmp.enemy_expansion.max_expansion_cooldown = (gmp.enemy_expansion.min_expansion_cooldown*1.25) - - end -events.on_config(function(ev) if(warptorio.Loaded)then return end +events.on_config(function(ev) + if (warptorio.Loaded) then return end lib.planets.lua() cache.validate("combinators") cache.validate("heat") @@ -292,32 +371,33 @@ events.on_config(function(ev) if(warptorio.Loaded)then return end cache.validate("ldinputf") cache.validate("ldoutputf") - global.warpzone=global.warpzone or 0 - global.time_spent_start_tick=global.time_spent_start_tick or game.tick - global.time_passed=global.time_passed or 0 - - global.warp_charge_time=global.warp_charge_time or 10 - global.warp_charge_start_tick=global.warp_charge_start_tick or 0 - global.warp_charging=global.warp_charging or 0 - global.warp_timeleft=global.warp_timeleft or 60*10 - global.warp_auto_time = global.warp_auto_time or 60*settings.global["warptorio_autowarp_time"].value - global.warp_auto_end = global.warp_auto_end or 60*60*settings.global["warptorio_autowarp_time"].value - global.warp_last=global.warp_last or game.tick - global.abilities=global.abilities or {} - global.ability_drain=global.ability_drain or settings.global["warptorio_ability_drain"].value - - global.pollution_amount = global.pollution_amount or 1.1 - global.pollution_expansion = global.pollution_expansion or 1.1 - global.ability_uses=global.ability_uses or 0 - global.ability_next=global.ability_next or 0 - global.radar_uses=global.radar_uses or 0 + storage.warpzone = storage.warpzone or 0 + storage.time_spent_start_tick = storage.time_spent_start_tick or game.tick + storage.time_passed = storage.time_passed or 0 + + storage.warp_charge_time = storage.warp_charge_time or 10 + storage.warp_charge_start_tick = storage.warp_charge_start_tick or 0 + storage.warp_charging = storage.warp_charging or 0 + storage.warp_timeleft = storage.warp_timeleft or 60 * 10 + storage.warp_auto_time = storage.warp_auto_time or 60 * settings.global["warptorio_autowarp_time"].value + storage.warp_auto_end = storage.warp_auto_end or 60 * 60 * settings.global["warptorio_autowarp_time"].value + storage.warp_last = storage.warp_last or game.tick + storage.abilities = storage.abilities or {} + storage.ability_drain = storage.ability_drain or settings.global["warptorio_ability_drain"].value + + storage.pollution_amount = storage.pollution_amount or 1.1 + storage.pollution_expansion = storage.pollution_expansion or 1.1 + storage.ability_uses = storage.ability_uses or 0 + storage.ability_next = storage.ability_next or 0 + storage.radar_uses = storage.radar_uses or 0 warptorio.ApplyMapSettings() - global.votewarp=global.votewarp or {} if(type(global.votewarp)~="table")then global.votewarp={} end + storage.votewarp = storage.votewarp or {} + if (type(storage.votewarp) ~= "table") then storage.votewarp = {} end warptorio.CheckVotewarps() - -- todo: global.warp_blacklist={} + -- todo: storage.warp_blacklist={} warptorio.ValidateWarpBlacklist() --[[ more todo: @@ -325,151 +405,177 @@ events.on_config(function(ev) if(warptorio.Loaded)then return end for k,v in pairs(gwarptorio.Teleporters)do v.position=warptorio.Teleporters[k].position end ]] - global.Teleporters=global.Teleporters or {} - global.Research=global.Research or {} -- todo remove this - global.Turrets=global.Turrets or {} - global.Rails=global.Rails or {} - global.Harvesters=global.Harvesters or {} + storage.Teleporters = storage.Teleporters or {} + storage.Research = storage.Research or {} -- todo remove this + storage.Turrets = storage.Turrets or {} + storage.Rails = storage.Rails or {} + storage.Harvesters = storage.Harvesters or {} - if(not global.floor)then warptorio.InitPlatform() end + if (not storage.floor) then warptorio.InitPlatform() end - for k,v in pairs(global.Rails)do + for k, v in pairs(storage.Rails) do v:MakeRails() end - for k,v in pairs(global.Teleporters)do + for k, v in pairs(storage.Teleporters) do v:CheckTeleporterPairs(true) end - for k,v in pairs(global.Harvesters)do - local gdata=warptorio.platform.harvesters[v.key] - v.rank=warptorio.GetPlatformTechLevel(gdata.tech) + for k, v in pairs(storage.Harvesters) do + local gdata = warptorio.platform.harvesters[v.key] + v.rank = warptorio.GetPlatformTechLevel(gdata.tech) v:CheckTeleporterPairs(true) v:Upgrade() end - for k,v in pairs(warptorio.settings)do v() end + for k, v in pairs(warptorio.settings) do v() end -- todo: warptorio.ApplyMapSettings() - for k,t in pairs(global.Harvesters)do - table.merge(t,table.deepcopy(warptorio.platform.harvesters[t.key])) - table.merge(t,table.deepcopy(warptorio.platform.HarvesterPointData)) + for k, t in pairs(storage.Harvesters) do + table.merge(t, table.deepcopy(warptorio.platform.harvesters[t.key])) + table.merge(t, table.deepcopy(warptorio.platform.HarvesterPointData)) end - warptorio.Loaded=true + warptorio.Loaded = true end) events.on_load(function() warptorio.HookNewGamePlus() - if(global.Teleporters)then for k,v in pairs(global.Teleporters)do setmetatable(v,warptorio.TeleporterMeta) end end - if(global.Harvesters)then for k,v in pairs(global.Harvesters)do setmetatable(v,warptorio.HarvesterMeta) end end - if(global.Rails)then for k,v in pairs(global.Rails)do setmetatable(v,warptorio.RailMeta) end end + if (storage.Teleporters) then for k, v in pairs(storage.Teleporters) do setmetatable(v, warptorio.TeleporterMeta) end end + if (storage.Harvesters) then for k, v in pairs(storage.Harvesters) do setmetatable(v, warptorio.HarvesterMeta) end end + if (storage.Rails) then for k, v in pairs(storage.Rails) do setmetatable(v, warptorio.RailMeta) end end --lib.planets.lua() end) ---[[ Players Manager ]]-- - -function warptorio.CheckVotewarps() for k,v in pairs(global.votewarp)do if(isvalid(v) or not v.connected)then global.votewarp[k]=nil end end cache.updatemenu("hud","warpbtn") end +--[[ Players Manager ]] -- +function warptorio.CheckVotewarps() + for k, v in pairs(storage.votewarp) do if (isvalid(v) or not v.connected) then storage.votewarp[k] = nil end end + cache.updatemenu("hud", "warpbtn") +end -warptorio.teleDir={[0]={0,-1},[1]={1,-1},[2]={1,0},[3]={1,1},[4]={0,1},[5]={-1,1},[6]={-1,0},[7]={-1,-1}} -function warptorio.TeleportLogic(ply,e,tent) - local w=ply.walking_state - local ox=tent.position - local x=e.position - local mp=2 if(not ply.character)then mp=3 end +warptorio.teleDir = { + [0] = { 0, -1 }, + [1] = { 1, -1 }, + [2] = { 1, 0 }, + [3] = { 1, 1 }, + [4] = { 0, 1 }, + [5] = { -1, 1 }, + [6] = { -1, 0 }, + [7] = { -1, -1 } +} +function warptorio.TeleportLogic(ply, e, tent) + if ply.controller_type == defines.controllers.remote then return end + local w = ply.walking_state + local ox = tent.position + local x = e.position + local mp = 2 + if (not ply.character) then mp = 3 end --game.print(serpent.line(ply.vehicle.name)) - if(ply.driving)then - local veh=ply.vehicle - if(veh.type=="spider-vehicle")then - local cp=ply.position local xd,yd=(x.x-cp.x),(x.y-cp.y) - local vpos=vector(ox.x+xd*3,ox.y+yd*3) - entity.safeteleport(ply,tent.surface,vpos) - local cn=veh.clone{position=ply.position,surface=ply.surface,force=ply.force} + if (ply.driving) then + local veh = ply.vehicle + if (veh.type == "spider-vehicle") then + --[[ local cp = ply.position + local xd, yd = (x.x - cp.x), (x.y - cp.y) + local vpos = vector(ox.x + xd * 3, ox.y + yd * 3) + entity.safeteleport(ply, tent.surface, vpos) + local cn = veh.clone { position = ply.position, surface = ply.surface, force = ply.force } veh.destroy() - ply.driving=cn - else - local cp=ply.position local xd,yd=(x.x-cp.x),(x.y-cp.y) entity.safeteleport(veh,tent.surface,vector(ox.x+xd*3,ox.y+yd*3)) + cn.set_driver(ply) + else]] -- + local cp = ply.position + local xd, yd = (x.x - cp.x), (x.y - cp.y) + entity.safeteleport(veh, tent.surface, vector(ox.x + xd, ox.y + yd)) end - elseif(not w.walking)then - local cp=ply.position local xd,yd=(x.x-cp.x),(x.y-cp.y) entity.safeteleport(ply,tent.surface,vector(ox.x+xd*mp,ox.y+yd*mp)) + elseif (not w.walking) then + local cp = ply.position + local xd, yd = (x.x - cp.x), (x.y - cp.y) + entity.safeteleport(ply, tent.surface, vector(ox.x + xd * mp, ox.y + yd * mp)) else - local td=warptorio.teleDir[w.direction] local tpe=ply entity.safeteleport(tpe,tent.surface,vector(ox.x+td[1]*mp,ox.y+td[2]*mp)) + local cp = ply.position + local xd, yd = (x.x - cp.x), (x.y - cp.y) + entity.safeteleport(ply, tent.surface, vector(ox.x + xd * mp, ox.y + yd * mp)) + -- local td=warptorio.teleDir[w.direction] local tpe=ply entity.safeteleport(tpe,tent.surface,vector(ox.x+td[1]*mp,ox.y+td[2]*mp)) end - players.playsound("teleport",e.surface,e.position) players.playsound("teleport",tent.surface,tent.position) + players.playsound("teleport", e.surface, e.position) + players.playsound("teleport", tent.surface, tent.position) end - cache.player({ - raise=function(cp) local ply=cp.host - entity.safeteleport(ply,warptorio.GetMainSurface(),vector(0,-5)) - local hud=cache.force_menu("hud",ply) + raise = function(cp) + local ply = cp.host + entity.safeteleport(ply, warptorio.GetMainSurface(), vector(0, -5)) + local hud = cache.force_menu("hud", ply) end, - on_position=function(ply) - local cp=cache.force_player(ply) - if((cp.tprecent or 0)>game.tick)then return end - local f=ply.surface - local z=vector.square(ply.position,vector(0.8,0.8)) - if(ply.driving)then - local bbox=ply.vehicle.bounding_box + on_position = function(ply) + local cp = cache.force_player(ply) + if ((cp.tprecent or 0) > game.tick) then return end + local f = ply.surface + local z = vector.square(ply.position, vector(0.8, 0.8)) + if (ply.driving) then + local bbox = ply.vehicle.bounding_box --game.print(serpent.line(bbox)) - bbox.left_top.x=bbox.left_top.x-0.8 - bbox.left_top.y=bbox.left_top.y-0.8 - bbox.right_bottom.x=bbox.right_bottom.x+0.8 - bbox.right_bottom.y=bbox.right_bottom.y+0.8 - z=bbox + bbox.left_top.x = bbox.left_top.x - 0.8 + bbox.left_top.y = bbox.left_top.y - 0.8 + bbox.right_bottom.x = bbox.right_bottom.x + 0.8 + bbox.right_bottom.y = bbox.right_bottom.y + 0.8 + z = bbox end - local ents=f.find_entities_filtered{area=z,type="accumulator"} --todo - for k,v in pairs(ents)do - local tpg=cache.get_entity(v) - if(tpg and isvalid(tpg.teleport_dest))then - cp.tprecent=game.tick+10 - local tgate=tpg.teleport_dest - warptorio.TeleportLogic(ply,v,tgate) + local ents = f.find_entities_filtered { area = z, type = "accumulator" } --todo + for k, v in pairs(ents) do + local tpg = cache.get_entity(v) + if (tpg and isvalid(tpg.teleport_dest)) then + cp.tprecent = game.tick + 10 + local tgate = tpg.teleport_dest + warptorio.TeleportLogic(ply, v, tgate) end end end, - on_create=function(ply) - local cp=cache.raise_player(ply) + on_create = function(ply) + local cp = cache.raise_player(ply) end, - on_join=function(ply) - local menu=cache.force_menu("hud",ply) - entity.safeteleport(ply,warptorio.GetMainSurface(),{0,-5}) + on_join = function(ply) + local menu = cache.force_menu("hud", ply) + entity.safeteleport(ply, warptorio.GetMainSurface(), { 0, -5 }) end, - on_respawn=function(ply) - local cf=warptorio.GetMainSurface() local gp=ply - if(gp.surface~=cf)then local pos=cf.find_non_colliding_position("character",{0,-5},0,1,1) gp.teleport(pos,cf) end + on_respawn = function(ply) + local cf = warptorio.GetMainSurface() + local gp = ply + if (gp.surface ~= cf) then + local pos = cf.find_non_colliding_position("character", { 0, -5 }, 0, 1, 1) + gp.teleport(pos, cf) + end end, - on_left=function(ply) - if(global.votewarp[ply.index])then - global.votewarp[ply.index]=nil - cache.updatemenu("hud","warpbtn") + on_left = function(ply) + if (storage.votewarp[ply.index]) then + storage.votewarp[ply.index] = nil + cache.updatemenu("hud", "warpbtn") end end, - on_pre_removed=function(ply) - local cp=cache.get_player(ply) if(cp)then + on_pre_removed = function(ply) + local cp = cache.get_player(ply) + if (cp) then cache.destroy_player(ply) end end, - on_capsule=function(ply,ev) - if(ev.item.name=="warptorio-townportal")then - local p=game.players[ev.player_index] - if(p and p.valid)then - players.playsound("teleport",p.surface,p.position) - entity.safeteleport(p,warptorio.GetMainSurface(),vector(0,-5)) - players.playsound("teleport",p.surface,p.position) + on_capsule = function(ply, ev) + if (ev.item.name == "warptorio-townportal") then + local p = game.players[ev.player_index] + if (p and p.valid) then + players.playsound("teleport", p.surface, p.position) + entity.safeteleport(p, warptorio.GetMainSurface(), vector(0, -5)) + players.playsound("teleport", p.surface, p.position) end - elseif(ev.item.name=="warptorio-homeportal" and warptorio.GetHomeSurface())then - local p=game.players[ev.player_index] - if(p and p.valid)then - players.playsound("teleport",p.surface,p.position) - entity.safeteleport(p,warptorio.GetHomeSurface(),vector(0,-5)) - players.playsound("teleport",p.surface,p.position) + elseif (ev.item.name == "warptorio-homeportal" and warptorio.GetHomeSurface()) then + local p = game.players[ev.player_index] + if (p and p.valid) then + players.playsound("teleport", p.surface, p.position) + entity.safeteleport(p, warptorio.GetHomeSurface(), vector(0, -5)) + players.playsound("teleport", p.surface, p.position) end end - end, }) @@ -477,571 +583,818 @@ cache.player({ ---[[ Warptorio Cache Manager ]]-- +--[[ Warptorio Cache Manager ]] -- - -- Pumps and resources cannot be cloned in warptorio -cache.type("offshore-pump",{ clone=function(e) e.destroy{raise_destroy=true} end, }) -cache.type("resource",{ clone=function(e) e.destroy{raise_destroy=true} end, }) +-- Pumps and resources cannot be cloned in warptorio +cache.type("offshore-pump", { clone = function(e) e.destroy { raise_destroy = true } end, }) +cache.type("resource", { clone = function(e) e.destroy { raise_destroy = true } end, }) -- Simple globally balanced entities -cache.ent("warptorio-heatpipe",{ create=function(e) cache.insert("heat",e) end, destroy=function(e) cache.remove("heat",e) end }) -cache.ent("warptorio-reactor",{ create=function(e) cache.insert("heat",e) end, destroy=function(e) cache.remove("heat",e) end }) -cache.ent("warptorio-accumulator",{ create=function(e) cache.insert("power",e) end, destroy=function(e) cache.remove("power",e) end }) - -events.on_tick(1,0,"heattick",function(tick) entity.AutoBalanceHeat(cache.get("heat")) end) -events.on_tick(1,0,"powertick",function(tick) local t=cache.get("power") - local g,c=0,0 - for k,v in pairs(t)do if(isvalid(v))then g=g+v.energy c=c+v.electric_buffer_size end end - - local egdrain=global.ability_drain - local abc=0 - if(global.abilities.stabilizing)then - abc=abc+1 +cache.ent("warptorio-heatpipe", + { create = function(e) cache.insert("heat", e) end, destroy = function(e) cache.remove("heat", e) end }) +cache.ent("warptorio-reactor", + { create = function(e) cache.insert("heat", e) end, destroy = function(e) cache.remove("heat", e) end }) +cache.ent("warptorio-accumulator", + { create = function(e) cache.insert("power", e) end, destroy = function(e) cache.remove("power", e) end }) + +events.on_tick(1, 0, "heattick", function(tick) entity.AutoBalanceHeat(cache.get("heat")) end) +events.on_tick(1, 0, "powertick", function(tick) + local t = cache.get("power") + local g, c = 0, 0 + for k, v in pairs(t) do + if (isvalid(v)) then + g = g + v.energy + c = c + v.electric_buffer_size + end end - if(global.abilities.accelerating)then - abc=abc+1 + + local egdrain = storage.ability_drain + local abc = 0 + if (storage.abilities.stabilizing) then + abc = abc + 1 end - if(global.abilities.scanning)then - abc=abc+1 + if (storage.abilities.accelerating) then + abc = abc + 1 + end + if (storage.abilities.scanning) then + abc = abc + 1 end - if(abc>0)then - local gcost=c*egdrain*abc - if(g>=gcost)then - g=math.max(g-gcost,0) - global.ability_drain=math.min(egdrain+(0.00000002*abc),0.25) + if (abc > 0) then + local gcost = c * egdrain * abc + if (g >= gcost) then + g = math.max(g - gcost, 0) + storage.ability_drain = math.min(egdrain + (0.00000002 * abc), 0.25) else - global.abilities.stabilizing=false global.abilities.scanning=false global.abilities.accelerating=false + storage.abilities.stabilizing = false + storage.abilities.scanning = false + storage.abilities.accelerating = false end end - global.energycount=g global.energymax=c - for k,v in pairs(t)do if(v.valid)then v.energy=g*(v.electric_buffer_size/c) end end + storage.energycount = g + storage.energymax = c + for k, v in pairs(t) do if (v.valid) then v.energy = g * (v.electric_buffer_size / c) end end end) -- Warptorio Combinators -cache.ent("warptorio-combinator",{ - create=function(e,ev) cache.insert("combinators",e) end, - destroy=function(e,ev) cache.remove("combinators",e) end, - update=function(e,ev) local cbh=e.get_or_create_control_behavior() for k,v in pairs(ev.signals)do cbh.set_signal(k,v) end end, +cache.ent("warptorio-combinator", { + create = function(e, ev) cache.insert("combinators", e) end, + destroy = function(e, ev) cache.remove("combinators", e) end, + update = function(e, ev) + local cbh = e.get_or_create_control_behavior() + for k, v in pairs(ev.signals) do cbh.set_signal(k, v) end + end, }) -function warptorio.RefreshWarpCombinators() local sigs=warptorio.GetCombinatorSignals() cache.entcall("combinators","update",{signals=sigs}) end -function warptorio.GetCombinatorSignals() local tbl={} for k,v in pairs(warptorio.Signals)do tbl[k]={signal=v.signal,count=v.get()} end return tbl end -warptorio.Signals={} -- 18 max default -warptorio.Signals[1]={ signal={type="virtual",name="signal-W"},get=function() return (global.warp_charging>=1 and (global.warp_time_left or 10)/60 or (global.warp_charge_time or 10)) end} -warptorio.Signals[2]={ signal={type="virtual",name="signal-X"},get=function() return global.warp_charging or 0 end} -warptorio.Signals[3]={ signal={type="virtual",name="signal-A"},get=function() return global.warp_auto_end/60 end} -warptorio.Signals[4]={ signal={type="virtual",name="signal-L"},get=function() local hv=global.Harvesters.west return ((hv and hv.deployed) and 1 or 0) end} -warptorio.Signals[5]={ signal={type="virtual",name="signal-R"},get=function() local hv=global.Harvesters.east return ((hv and hv.deployed) and 1 or 0) end} -warptorio.Signals[6]={ signal={type="virtual",name="signal-P"},get=function() return global.time_passed end} +function warptorio.RefreshWarpCombinators() + local sigs = warptorio.GetCombinatorSignals() + cache.entcall("combinators", "update", { signals = sigs }) +end + +function warptorio.GetCombinatorSignals() + local tbl = {} + for k, v in pairs(warptorio.Signals) do tbl[k] = { signal = v.signal, count = v.get() } end + return tbl +end + +warptorio.Signals = {} -- 18 max default +warptorio.Signals[1] = { signal = { type = "virtual", name = "signal-W" }, get = function() return (storage.warp_charging >= 1 and (storage.warp_time_left or 10) / 60 or (storage.warp_charge_time or 10)) end } +warptorio.Signals[2] = { + signal = { type = "virtual", name = "signal-X" }, + get = function() + return storage.warp_charging or + 0 + end +} +warptorio.Signals[3] = { + signal = { type = "virtual", name = "signal-A" }, + get = function() + return storage.warp_auto_end / + 60 + end +} +warptorio.Signals[4] = { + signal = { type = "virtual", name = "signal-L" }, + get = function() + local hv = storage.Harvesters.west + return ((hv and hv.deployed) and 1 or 0) + end +} +warptorio.Signals[5] = { + signal = { type = "virtual", name = "signal-R" }, + get = function() + local hv = storage.Harvesters.east + return ((hv and hv.deployed) and 1 or 0) + end +} +warptorio.Signals[6] = { signal = { type = "virtual", name = "signal-P" }, get = function() return storage.time_passed end } ---[[ Warptorio Gui ]]-- +--[[ Warptorio Gui ]] -- --cache.updatemenu("hud","raise") -- to recreate the menu -function warptorio.RaiseHUD(v) local m=cache.get_menu("hud",v) if(not m)then cache.raise_menu("hud",v) else cache.call_menu("raise",m) end end -function warptorio.ResetHUD(p) if(not p)then for k,v in pairs(game.players)do warptorio.RaiseHUD(v) end else warptorio.RaiseHUD(p) end end -function warptorio.PlayerCanStartWarp(ply) return true end +function warptorio.RaiseHUD(v) + local m = cache.get_menu("hud", v) + if (not m) then cache.raise_menu("hud", v) else cache.call_menu("raise", m) end +end -function warptorio.ToolRecallHarvester(k,ply) if(not research.has("warptorio-harvester-"..k.."-1"))then return end - local cn=("warptorio-harvestpad-"..k.."-"..research.level("warptorio-harvester-"..k)) - if(not ply or (ply and not ply.get_main_inventory().get_contents()[cn]))then ply.get_main_inventory().insert{name=cn,count=1} players.playsound("warp_in",ply.surface,ply.position) end - local hv=global.Harvesters[k] if(hv and hv.deployed and isvalid(hv.b))then players.playsound("warp_in",hv.b.surface,hv.b.position) hv:Recall() hv:DestroyB() end +function warptorio.ResetHUD(p) + if (not p) then + for k, v in pairs(game.players) do warptorio.RaiseHUD(v) end + else + warptorio.RaiseHUD(p) + end end -function warptorio.ToolRecallGate(ply) if(not research.has("warptorio-teleporter-portal"))then return end - local t=global.Teleporters.offworld if(t)then - if(t.b and t.b.valid)then players.playsound("warp_in",t.b.surface,t.b.position) t:DestroyLogsB() t:DestroyB() end - local inv=ply.get_main_inventory() - if(not inv.get_contents()["warptorio-teleporter-gate-0"])then inv.insert{name="warptorio-teleporter-gate-0",count=1} players.playsound("warp_in",ply.surface,ply.position) end + +function warptorio.PlayerCanStartWarp(ply) return true end + +function warptorio.ToolRecallHarvester(k, ply) + if (not research.has("warptorio-harvester-" .. k .. "-1")) then return end + local cn = ("warptorio-harvestpad-" .. k .. "-" .. research.level("warptorio-harvester-" .. k)) + if (not ply or (ply and not ply.get_main_inventory().get_contents()[cn])) then + ply.get_main_inventory().insert { name = cn, count = 1 } + players.playsound("warp_in", ply.surface, ply.position) + end + local hv = storage.Harvesters[k] + if (hv and hv.deployed and isvalid(hv.b)) then + players.playsound("warp_in", hv.b.surface, hv.b.position) + hv:Recall() + hv:DestroyB() end end -cache.vgui("warptorio_toolbutton",{click=function(elm,ev) local menu=cache.get_menu("hud",elm.player_index) local b=menu.toolbar b.visible=not b.visible end}) -cache.vgui("warptorio_tool_hv_west",{click=function(elm,ev) warptorio.ToolRecallHarvester("west",game.players[elm.player_index]) end}) -cache.vgui("warptorio_tool_hv_east",{click=function(elm,ev) warptorio.ToolRecallHarvester("east",game.players[elm.player_index]) end}) -cache.vgui("warptorio_tool_planet_gate",{click=function(elm,ev) warptorio.ToolRecallGate(game.players[elm.player_index]) end}) +function warptorio.ToolRecallGate(ply) + if (not research.has("warptorio-teleporter-portal")) then return end + local t = storage.Teleporters.offworld + if (t) then + if (t.b and t.b.valid) then + players.playsound("warp_in", t.b.surface, t.b.position) + t:DestroyLogsB() + t:DestroyB() + end + local inv = ply.get_main_inventory() + if (not inv.get_contents()["warptorio-teleporter-gate-0"]) then + inv.insert { name = "warptorio-teleporter-gate-0", count = 1 } + players.playsound("warp_in", ply.surface, ply.position) + end + end +end +function HomeSweetHome() + --Warptorio Victory Screen + game.set_win_ending_info({ + title = { "warptorio.victory-title" }, + message = { "warptorio.victory-text" }, + final_message = { "warptorio.victoty-text2" }, + image_path = "__warptorio2__/graphics/victory.png" + }) + game.set_game_state({ + can_continue = true, + game_finished = true, + player_won = true, + }) +end -cache.vgui("warptorio_homeworld",{ - click=function(elm,ev) local menu=cache.get_menu("hud",elm.player_index) - if(menu.hometmr=1)then menu.charge_time.caption={"warptorio.warp-in",util.formattime(val or (global.warp_time_left or 0))} - elseif(menu.charge_time)then menu.charge_time.caption={"warptorio.charge_time",util.formattime((global.warp_charge_time or 0)*60)} +local HUD = {} +warptorio.HUD = HUD +function HUD.clocktick(menu) + local ply = menu.host + if (storage.warp_charging >= 1) then + menu.charge_time.caption = { "warptorio.warp-in", util.formattime(val or (storage.warp_time_left or 0)) } + elseif (menu.charge_time) then + menu.charge_time.caption = { "warptorio.charge_time", util.formattime((storage.warp_charge_time or 0) * 60) } end - menu.time_passed.caption={"warptorio.time_passed",util.formattime(global.time_passed or 0)} - if(warptorio.IsAutowarpEnabled())then menu.autowarp.caption={"warptorio.autowarp-in",util.formattime(global.warp_auto_end)} else menu.autowarp.caption="" end + menu.time_passed.caption = { "warptorio.time_passed", util.formattime(storage.time_passed or 0) } + if (warptorio.IsAutowarpEnabled()) then + menu.autowarp.caption = { "warptorio.autowarp-in", util.formattime(storage.warp_auto_end) } + else + menu.autowarp.caption = "" + end - menu.hometmr=menu.hometmr or 0 - if(menu.homeworld)then - if(menu.hometmr>game.tick)then menu.homeworld.caption={"warptorio.confirm_homeworld",util.formattime(menu.hometmr-game.tick)} - else menu.homeworld.caption={"warptorio.button_homeworld"} + menu.hometmr = menu.hometmr or 0 + if (menu.homeworld) then + if (menu.hometmr > game.tick) then + menu.homeworld.caption = { "warptorio.confirm_homeworld", util.formattime(menu.hometmr - game.tick) } + else + menu.homeworld.caption = { "warptorio.button-homeworld" } end end - if(menu.energybar)then - local cureng=global.energycount or 0 - local maxeng=math.max(global.energymax or 1,1) - local energydif=cureng-(menu.last_energy or 0) - menu.last_energy=cureng - - local egdrain=global.ability_drain*100*60 - local abc=0 - local r=menu.stabilizer - if(r)then if(global.abilities.stabilizing)then abc=abc+1 r.caption={"warptorio-stabilize-on","-"..math.roundx(egdrain,2).."%/sec"} else r.caption={"warptorio-stabilize"} end end - local r=menu.accelerator - if(r)then if(global.abilities.accelerating)then abc=abc+1 r.caption={"warptorio-accel-on","-"..math.roundx(egdrain,2).."%/sec"} else r.caption={"warptorio-accel"} end end - local r=menu.radar - if(r)then if(global.abilities.scanning)then abc=abc+1 r.caption={"warptorio-radar-on","-"..math.roundx(egdrain,2).."%/sec"} else r.caption={"warptorio-radar"} end end - - - menu.energybar_energy.caption=" "..string.energy_to_string(cureng) .. " " - menu.energybar_energymax.caption=" "..string.energy_to_string(maxeng) .. " " - - menu.energybar_energybal.caption=" ("..(energydif>=1 and "+" or (energydif>0 and "+-" or ""))..string.energy_to_string(energydif) .. "/sec) " - menu.energybar_energybal.style.font_color=(energydif>0 and {r=0,g=1,b=0} or (energydif<0 and {r=1,g=0,b=0} or {r=0.75,g=0.75,b=0.75})) - - menu.energybar.value=cureng/maxeng - - menu.energybar_energypct.caption=" "..math.roundx((cureng/maxeng)*100,2) .. "% " - - if(abc>0)then menu.energybar_energypctx.caption="-"..math.roundx(egdrain*abc,2).."%/sec" else menu.energybar_energypctx.caption="" end - + if (menu.energybar) then + local cureng = storage.energycount or 0 + local maxeng = math.max(storage.energymax or 1, 1) + local energydif = cureng - (menu.last_energy or 0) + menu.last_energy = cureng + + local egdrain = storage.ability_drain * 100 * 60 + local abc = 0 + local r = menu.stabilizer + if (r) then + if (storage.abilities.stabilizing) then + abc = abc + 1 + r.caption = { "warptorio.stabilize-on", "-" .. math.roundx(egdrain, 2) .. "%/sec" } + else + r.caption = { "warptorio.stabilize" } + end + end + local r = menu.accelerator + if (r) then + if (storage.abilities.accelerating) then + abc = abc + 1 + r.caption = { "warptorio.accel-on", "-" .. math.roundx(egdrain, 2) .. "%/sec" } + else + r.caption = { "warptorio.accel" } + end + end + local r = menu.radar + if (r) then + if (storage.abilities.scanning) then + abc = abc + 1 + r.caption = { "warptorio.radar-on", "-" .. math.roundx(egdrain, 2) .. "%/sec" } + else + r.caption = { "warptorio.radar" } + end + end + menu.energybar_energy.caption = " " .. string.energy_to_string(cureng) .. " " + menu.energybar_energymax.caption = " " .. string.energy_to_string(maxeng) .. " " + menu.energybar_energybal.caption = " (" .. + (energydif >= 1 and "+" or (energydif > 0 and "+-" or "")) .. string.energy_to_string(energydif) .. "/sec) " + menu.energybar_energybal.style.font_color = (energydif > 0 and { r = 0, g = 1, b = 0 } or (energydif < 0 and { r = 1, g = 0, b = 0 } or { r = 0.75, g = 0.75, b = 0.75 })) + menu.energybar.value = cureng / maxeng + menu.energybar_energypct.caption = " " .. math.roundx((cureng / maxeng) * 100, 2) .. "% " + if (abc > 0) then + menu.energybar_energypctx.caption = "-" .. math.roundx(egdrain * abc, 2) .. "%/sec" + else + menu.energybar_energypctx.caption = "" + end end - end - -function HUD.raise(menu,ev) local ply=menu.host - menu.frame=vgui.create(ply.gui.left,{name="warptorio_frame",type="flow",direction="vertical"}) - menu.frame.style.left_padding=4 - menu.row1=vgui.create(menu.frame,{name="warptorio_row1",type="flow",direction="horizontal"}) - menu.row2=vgui.create(menu.frame,{name="warptorio_row2",type="flow",direction="horizontal"}) - menu.row4=vgui.create(menu.frame,{name="warptorio_row4",type="flow",direction="horizontal"}) - menu.row3=vgui.create(menu.frame,{name="warptorio_row3",type="flow",direction="horizontal"}) +function HUD.raise(menu, ev) + local ply = menu.host + menu.frame = vgui.create(ply.gui.left, { name = "warptorio_frame", type = "flow", direction = "vertical" }) + menu.frame.style.left_padding = 4 + menu.row1 = vgui.create(menu.frame, { name = "warptorio_row1", type = "flow", direction = "horizontal" }) + menu.row2 = vgui.create(menu.frame, { name = "warptorio_row2", type = "flow", direction = "horizontal" }) + menu.row4 = vgui.create(menu.frame, { name = "warptorio_row4", type = "flow", direction = "horizontal" }) + menu.row3 = vgui.create(menu.frame, { name = "warptorio_row3", type = "flow", direction = "horizontal" }) menu.row1.clear() menu.row2.clear() menu.row3.clear() menu.row4.clear() - menu.warpbtn=vgui.create(menu.row1,{name="warptorio_warpbutton",type="button",caption={"warptorio.button-warp","-"}}) - if(research.has("warptorio-toolbar"))then menu.toolbtn=vgui.create(menu.row1,{name="warptorio_toolbutton",type="button",caption={"warptorio.toolbutton","-"}}) end - if(research.level("warptorio-reactor")>=8)then - menu.warptgt=vgui.create(menu.row1,{name="warptorio_warptarget",type="drop-down"}) + menu.warpbtn = vgui.create(menu.row1, + { name = "warptorio_warpbutton", type = "button", caption = { "warptorio.button-warp", "-" } }) + if (research.has("warptorio-toolbar")) then + menu.toolbtn = vgui.create(menu.row1, + { name = "warptorio_toolbutton", type = "button", caption = { "warptorio.toolbutton", "-" } }) + end + if (research.level("warptorio-reactor") >= 8) then + menu.warptgt = vgui.create(menu.row1, { name = "warptorio_warptarget", type = "drop-down" }) HUD.rebuild_warptargets(menu) - HUD.warptarget(menu,{tgt=(sx==nil and "(Random)" or (sx=="home" and "(Homeworld)" or (sx=="(nauvis)" and "nauvis" or sx)))}) + HUD.warptarget(menu, + { tgt = (sx == nil and "(Random)" or (sx == "home" and "(Homeworld)" or (sx == "(nauvis)" and "nauvis" or sx))) }) end - menu.time_passed=vgui.create(menu.row1,{name="warptorio_time_passed",type="label"}) - menu.charge_time=vgui.create(menu.row1,{name="warptorio_charge_time",type="label"}) - menu.warpzone=vgui.create(menu.row1,{name="warptorio_warpzone",type="label",caption="Warpzone: " .. global.warpzone or 0}) - menu.autowarp=vgui.create(menu.row1,{name="warptorio_autowarp",type="label"}) - - if(research.has("warptorio-homeworld"))then menu.homeworld=vgui.create(menu.row1,{name="warptorio_homeworld",type="button",caption={"warptorio.button_homeworld"}}) end - - - local hasabil=false - if(research.has("warptorio-stabilizer"))then hasabil=true menu.stabilizer=vgui.create(menu.row2,{name="warptorio_stabilizer",type="button",caption={"warptorio-stabilize","-"}}) end - if(research.has("warptorio-accelerator"))then hasabil=true menu.accelerator=vgui.create(menu.row2,{name="warptorio_accelerator",type="button",caption={"warptorio-accel","-"}}) end - if(research.has("warptorio-charting"))then hasabil=true menu.radar=vgui.create(menu.row2,{name="warptorio_radar",type="button",caption={"warptorio-radar","-"}}) end - if(hasabil)then - menu.last_energy=menu.last_energy or 100 - local energydif=1000-menu.last_energy - menu.energybar_label=vgui.create(menu.row4,{name="warptorio_energybar_label",type="label",caption={"warptorio.energybar","-"}}) - menu.energybar_energy=vgui.create(menu.row4,{name="warptorio_energybar_energy",type="label",caption=" 100kw "}) - menu.energybar_energy.style.font_color={r=0,g=1,b=0} - - menu.energybar_energydiv=vgui.create(menu.row4,{name="warptorio_energybar_energydiv",type="label",caption=" / "}) - - menu.energybar_energymax=vgui.create(menu.row4,{name="warptorio_energybar_energymax",type="label",caption=" 0kw "}) - menu.energybar_energymax.style.font_color={r=0.25,g=1,b=1} - - - menu.energybar_energybal=vgui.create(menu.row4,{name="warptorio_energybar_energybal",type="label",caption=" (+100.32MW/sec) "}) - menu.energybar_energybal.style.font_color=(energydif>0 and {r=0,g=1,b=0} or (energydif==0 and {r=1,g=1,b=0} or {r=1,g=0,b=0})) - - - menu.energybar_energydivb=vgui.create(menu.row4,{name="warptorio_energybar_energydivb",type="label",caption=" | "}) - - - menu.energybar=vgui.create(menu.row4,{name="warptorio_time_passed",type="progressbar",value=0.3}) - menu.energybar.style.natural_width=250 - menu.energybar.style.top_padding=7 - menu.energybar.style.bottom_padding=7 - - menu.energybar_energypcta=vgui.create(menu.row4,{name="warptorio_energybar_energypcta",type="label",caption=" | "}) - menu.energybar_energypct=vgui.create(menu.row4,{name="warptorio_energybar_energypct",type="label",caption="25%"}) - menu.energybar_energypct.style.font_color={r=1,g=1,b=1} - menu.energybar_energypctx=vgui.create(menu.row4,{name="warptorio_energybar_energypctx",type="label",caption="-3%/sec"}) - menu.energybar_energypctx.style.font_color={r=1,g=0,b=0} + menu.time_passed = vgui.create(menu.row1, { name = "warptorio_time_passed", type = "label" }) + menu.charge_time = vgui.create(menu.row1, { name = "warptorio_charge_time", type = "label" }) + menu.warpzone = vgui.create(menu.row1, + { name = "warptorio_warpzone", type = "label", caption = { "warptorio.warpzone", storage.warpzone or 0 } }) + menu.autowarp = vgui.create(menu.row1, { name = "warptorio_autowarp", type = "label" }) + if (research.has("warptorio-homeworld")) then + menu.homeworld = vgui.create(menu.row1, + { name = "warptorio_homeworld", type = "button", caption = { "warptorio.button-homeworld" } }) + end + local hasabil = false + if (research.has("warptorio-stabilizer")) then + hasabil = true + menu.stabilizer = vgui.create(menu.row2, + { name = "warptorio_stabilizer", type = "button", caption = { "warptorio.stabilize", "-" } }) + end + if (research.has("warptorio-accelerator")) then + hasabil = true + menu.accelerator = vgui.create(menu.row2, + { name = "warptorio_accelerator", type = "button", caption = { "warptorio.accel", "-" } }) + end + if (research.has("warptorio-charting")) then + hasabil = true + menu.radar = vgui.create(menu.row2, + { name = "warptorio_radar", type = "button", caption = { "warptorio.radar", "-" } }) + end + if (hasabil) then + menu.last_energy = menu.last_energy or 100 + local energydif = 1000 - menu.last_energy + menu.energybar_label = vgui.create(menu.row4, + { name = "warptorio_energybar_label", type = "label", caption = { "warptorio.energybar", "-" } }) + menu.energybar_energy = vgui.create(menu.row4, { + name = "warptorio_energybar_energy", + type = "label", + caption = + " 100kw " + }) + menu.energybar_energy.style.font_color = { r = 0, g = 1, b = 0 } + + menu.energybar_energydiv = vgui.create(menu.row4, + { name = "warptorio_energybar_energydiv", type = "label", caption = " / " }) + + menu.energybar_energymax = vgui.create(menu.row4, + { name = "warptorio_energybar_energymax", type = "label", caption = " 0kw " }) + menu.energybar_energymax.style.font_color = { r = 0.25, g = 1, b = 1 } + + + menu.energybar_energybal = vgui.create(menu.row4, + { name = "warptorio_energybar_energybal", type = "label", caption = " (+100.32MW/sec) " }) + menu.energybar_energybal.style.font_color = (energydif > 0 and { r = 0, g = 1, b = 0 } or (energydif == 0 and { r = 1, g = 1, b = 0 } or { r = 1, g = 0, b = 0 })) + + + menu.energybar_energydivb = vgui.create(menu.row4, + { name = "warptorio_energybar_energydivb", type = "label", caption = " | " }) + + + menu.energybar = vgui.create(menu.row4, { name = "warptorio_time_passed", type = "progressbar", value = 0.3 }) + menu.energybar.style.natural_width = 250 + menu.energybar.style.top_padding = 7 + menu.energybar.style.bottom_padding = 7 + + menu.energybar_energypcta = vgui.create(menu.row4, + { name = "warptorio_energybar_energypcta", type = "label", caption = " | " }) + menu.energybar_energypct = vgui.create(menu.row4, + { name = "warptorio_energybar_energypct", type = "label", caption = "25%" }) + menu.energybar_energypct.style.font_color = { r = 1, g = 1, b = 1 } + menu.energybar_energypctx = vgui.create(menu.row4, + { name = "warptorio_energybar_energypctx", type = "label", caption = "-3%/sec" }) + menu.energybar_energypctx.style.font_color = { r = 1, g = 0, b = 0 } end - if(research.has("warptorio-toolbar"))then - menu.toolbar=vgui.create(menu.row3,{name="warptorio_toolframe",type="flow",direction="horizontal",visible=false}) + if (research.has("warptorio-toolbar")) then + menu.toolbar = vgui.create(menu.row3, + { name = "warptorio_toolframe", type = "flow", direction = "horizontal", visible = false }) menu.toolbar.clear() - menu.tool_harvester_west=vgui.create(menu.toolbar,{name="warptorio_tool_hv_west",type="sprite-button",sprite="entity/warptorio-harvestportal-1",tooltip={"warptorio.tool_hv_west","-"}}) - menu.tool_planet_gate=vgui.create(menu.toolbar,{name="warptorio_tool_planet_gate",type="sprite-button",sprite="item/warptorio-teleporter-gate-0",tooltip={"warptorio.tool_planet_gate","-"}}) - menu.tool_harvester_east=vgui.create(menu.toolbar,{name="warptorio_tool_hv_east",type="sprite-button",sprite="entity/warptorio-harvestportal-1",tooltip={"warptorio.tool_hv_east","-"}}) + menu.tool_harvester_west = vgui.create(menu.toolbar, + { name = "warptorio_tool_hv_west", type = "sprite-button", sprite = "entity/warptorio-harvestportal-1", tooltip = { "warptorio.tool_hv_west", "-" } }) + menu.tool_planet_gate = vgui.create(menu.toolbar, + { name = "warptorio_tool_planet_gate", type = "sprite-button", sprite = "item/warptorio-teleporter-gate-0", tooltip = { "warptorio.tool_planet_gate", "-" } }) + menu.tool_harvester_east = vgui.create(menu.toolbar, + { name = "warptorio_tool_hv_east", type = "sprite-button", sprite = "entity/warptorio-harvestportal-1", tooltip = { "warptorio.tool_hv_east", "-" } }) end - HUD.clocktick(menu) HUD.rebuild_warptargets(menu) - local sx=global.planet_target - + local sx = storage.planet_target end -function HUD.rebuild_warptargets(menu,ev) - if(menu.warptgt)then - local tgl={"(Random)"} - if(research.has("warptorio-homeworld"))then table.insert(tgl,"(Homeworld)") table.insert(tgl,"(Nauvis)") end - if(research.has("warptorio-charting"))then for k,v in pairs(lib.planets.GetTemplates())do table.insert(tgl,v.key) end end - menu.warptgt.items=tgl - HUD.warptarget(menu,{tgt=global.planet_target}) +function HUD.rebuild_warptargets(menu, ev) + if (menu.warptgt) then + local tgl = { "(Random)" } + if (research.has("warptorio-homeworld")) then + table.insert(tgl, "(Homeworld)") + table.insert(tgl, "(Nauvis)") + end + if (research.has("warptorio-charting")) then + for k, v in pairs(lib.planets.GetTemplates()) do + table.insert(tgl, v.key) + end + end + menu.warptgt.items = tgl + HUD.warptarget(menu, { tgt = storage.planet_target }) end end -function HUD.warptarget(menu,ev) local ply=menu.host if(not menu.warptgt or ply.index==ev.ply)then return end - local elm,items=menu.warptgt if(elm)then items=elm.items end if(not items)then return end - for idx,kv in pairs(items)do if(type(kv)=="string" and kv:lower()==ev.tgt)then elm.selected_index=idx end end + +function HUD.warptarget(menu, ev) + local ply = menu.host + if (not menu.warptgt or ply.index == ev.ply) then return end + local elm, items = menu.warptgt + if (elm) then items = elm.items end + if (not items) then return end + for idx, kv in pairs(items) do if (type(kv) == "string" and kv:lower() == ev.tgt) then elm.selected_index = idx end end end function HUD.warpbtn(menu) - local r=menu.warpbtn - local ply=menu.host - if(global.warp_charging>=1)then r.caption={"warptorio.warping","-"} r.enabled=false - else local cx=table.Count(global.votewarp) local c=table.Count(game.connected_players) -- table.Count(game.non_afk_players) - if(c>1)then - local vcn=math.ceil(c*warptorio.setting("votewarp_multi")) - if(global.votewarp[ply.index] and cx0)then r.caption={"warptorio.button-votewarp-count",cx,vcn} - else r.caption={"warptorio.button-votewarp","-"} + local r = menu.warpbtn + local ply = menu.host + if (storage.warp_charging >= 1) then + r.caption = { "warptorio.warping", "-" } + r.enabled = false + else + local cx = table.Count(storage.votewarp) + local c = table.Count(game.connected_players) -- table.Count(game.non_afk_players) + if (c > 1) then + local vcn = math.ceil(c * warptorio.setting("votewarp_multi")) + if (storage.votewarp[ply.index] and cx < vcn) then r.enabled = false else r.enabled = true end + if (cx > 0) then + r.caption = { "warptorio.button-votewarp-count", cx, vcn } + else + r.caption = { "warptorio.button-votewarp", "-" } end - else r.enabled=true r.caption={"warptorio.button-warp","-"} menu.warpzone.caption={"warptorio.warpzone_label",global.warpzone or 0} + else + r.enabled = true + r.caption = { "warptorio.button-warp", "-" } + menu.warpzone.caption = { "warptorio.warpzone_label", storage.warpzone or 0 } end end end -cache.menu("hud",HUD) - - - -cache.vgui("warptorio_warptarget",{ -selection_changed=function(elm,ev) local ply=game.players[elm.player_index] - local s=elm.items[elm.selected_index] if(not s)then return end local sx=s:lower() - local vt=(sx=="(random)" and nil or (sx=="(homeworld)" and "home" or (sx=="(nauvis)" and "nauvis" or sx))) - if(vt~=global.planet_target)then global.planet_target=vt game.print({"warptorio.player_set_warp_target",ply.name,s}) cache.updatemenu("hud","warptarget",{ply=elm.player_index,tgt=sx}) end -end, +cache.menu("hud", HUD) + +cache.vgui("warptorio_warptarget", { + selection_changed = function(elm, ev) + local ply = game.players[elm.player_index] + local s = elm.items[elm.selected_index] + if (not s) then return end + local sx = s:lower() + local vt = (sx == "(random)" and nil or (sx == "(homeworld)" and "home" or (sx == "(nauvis)" and "nauvis" or sx))) + if (vt ~= storage.planet_target) then + storage.planet_target = vt + game.print({ "warptorio.player_set_warp_target", ply.name, s }) + cache.updatemenu("hud", "warptarget", { ply = elm.player_index, tgt = sx }) + end + end, }) function warptorio.StartWarp() - if(global.warp_charging<1)then + if (storage.warp_charging < 1) then events.vraise("warp_started") - global.warp_charge_start_tick=game.tick - global.warp_charging=1 + storage.warp_charge_start_tick = game.tick + storage.warp_charging = 1 players.playsound("reactor-stabilized") - cache.updatemenu("hud","warpbtn") + cache.updatemenu("hud", "warpbtn") end end + function warptorio.StopWarp() - if(global.warp_charging>0)then + if (storage.warp_charging > 0) then events.vraise("warp_stopped") - global.warp_charging=0 - global.warp_charge_time=global.warp_time_left/60 - global.warp_charge_start_tick=0 + storage.warp_charging = 0 + storage.warp_charge_time = storage.warp_time_left / 60 + storage.warp_charge_start_tick = 0 end end -function warptorio.IsWarping() return global.warp_charging>0 end -cache.vgui("warptorio_warpbutton",{ -click=function(elm,ev) local ply=game.players[elm.player_index] local menu=cache.get_menu("hud",elm.player_index) - if(global.warp_charging<1)then local c=table.Count(game.connected_players) -- table.Count(game.non_afk_players) - if(c>1 and warptorio.setting("votewarp_multi")>0)then --votewarp - local vcn=math.ceil(c*warptorio.setting("votewarp_multi")) - global.votewarp[ply.index]=ply - local cx=table.Count(global.votewarp) - if(vcn<=1 or cx>=vcn)then - warptorio.StartWarp() - game.print(ply.name .. " started the warpout procedure.") + +function warptorio.IsWarping() return storage.warp_charging > 0 end + +cache.vgui("warptorio_warpbutton", { + click = function(elm, ev) + local ply = game.players[elm.player_index] + local menu = cache.get_menu("hud", elm.player_index) + if (storage.warp_charging < 1) then + local c = table.Count(game.connected_players) -- table.Count(game.non_afk_players) + if (c > 1 and warptorio.setting("votewarp_multi") > 0) then --votewarp + local vcn = math.ceil(c * warptorio.setting("votewarp_multi")) + storage.votewarp[ply.index] = ply + local cx = table.Count(storage.votewarp) + if (vcn <= 1 or cx >= vcn) then + warptorio.StartWarp() + game.print({ "warptorio.player_started_warpout", ply.name }) + else + players.playsound("teleport") + game.print({ "warptorio.player_want_vote_warp", ply.name, cx, vcn }) + cache.updatemenu("hud", "warpbtn") + end + elseif (warptorio.PlayerCanStartWarp(ply)) then + storage.warp_charge_start_tick = game.tick + storage.warp_charging = 1 + players.playsound("reactor-stabilized") + cache.updatemenu("hud", "warpbtn") else - players.playsound("teleport") - game.print({"warptorio.player_want_vote_warp",ply.name,cx,vcn}) - cache.updatemenu("hud","warpbtn") + ply.print({ "warptorio.same-planet-error" }) end - elseif(warptorio.PlayerCanStartWarp(ply))then - global.warp_charge_start_tick = game.tick - global.warp_charging = 1 - players.playsound("reactor-stabilized") - cache.updatemenu("hud","warpbtn") - else - ply.print("You must be on the same planet as the platform to warp") end - end -end, + end, }) -cache.vgui("warptorio_stabilizer",{ -click=function(elm,ev) local ply=game.players[elm.player_index] local menu=cache.get_menu("hud",elm.player_index) - global.abilities.stabilizing= not global.abilities.stabilizing -end, +cache.vgui("warptorio_stabilizer", { + click = function(elm, ev) + local ply = game.players[elm.player_index] + local menu = cache.get_menu("hud", elm.player_index) + storage.abilities.stabilizing = not storage.abilities.stabilizing + end, }) -cache.vgui("warptorio_accelerator",{ -click=function(elm,ev) local ply=game.players[elm.player_index] local menu=cache.get_menu("hud",elm.player_index) - global.abilities.accelerating= not global.abilities.accelerating -end, +cache.vgui("warptorio_accelerator", { + click = function(elm, ev) + local ply = game.players[elm.player_index] + local menu = cache.get_menu("hud", elm.player_index) + storage.abilities.accelerating = not storage.abilities.accelerating + end, }) -cache.vgui("warptorio_radar",{ -click=function(elm,ev) local ply=game.players[elm.player_index] local menu=cache.get_menu("hud",elm.player_index) - global.abilities.scanning= not global.abilities.scanning -end, +cache.vgui("warptorio_radar", { + click = function(elm, ev) + local ply = game.players[elm.player_index] + local menu = cache.get_menu("hud", elm.player_index) + storage.abilities.scanning = not storage.abilities.scanning + end, }) - - - ---[[ Warping stuff ]]-- +--[[ Warping stuff ]] -- function warptorio.ValidateWarpBlacklist() end -local staticBlacklist={"highlight-box","big_brother-blueprint-radar","osp_repair_radius"} +local staticBlacklist = { "highlight-box", "big_brother-blueprint-radar", "osp_repair_radius" } function warptorio.GetWarpBlacklist() return staticBlacklist end -- OnEntCloned -events.on_event(defines.events.on_entity_cloned,function(ev) - if(warptorio.IsCloning)then table.insert(warptorio.Cloned_Entities,{source=ev.source,destination=ev.destination}) end - if(ev.source.type=="spider-vehicle")then - for k,v in pairs(game.players)do local inv=v.get_main_inventory() if(inv)then - for i=1,#inv,1 do local e=inv[i] if(e and e.valid_for_read and e.connected_entity==ev.source)then e.connected_entity=ev.destination end end - local e=v.cursor_stack if(e and e.valid_for_read and e.connected_entity==ev.source)then e.connected_entity=ev.destination end - if(v.driving and v.vehicle==ev.source)then - entity.safeteleport(v,ev.destination.surface,ev.destination.position) - v.driving=ev.destination +events.on_event(defines.events.on_entity_cloned, function(ev) + if (warptorio.IsCloning) then + table.insert(warptorio.Cloned_Entities, { + source = ev.source, + destination = ev.destination + }) + end + if (ev.source.type == "spider-vehicle") then + for k, v in pairs(game.players) do + if (v.driving and v.vehicle == ev.source) then + entity.safeteleport(v, ev.destination.surface, ev.destination.position) + ev.destination.set_driver(v) end - end end + --[[ + local inv = v.get_main_inventory() + if (inv) then + for i = 1, #inv, 1 do + local e = inv[i] + if (e and e.valid_for_read and e.connected_entity == ev.source) then + e.connected_entity = ev.destination + end + end + local e = v.cursor_stack + if (e and e.valid_for_read and e.connected_entity == ev.source) then e.connected_entity = ev.destination end + end]] + end end end) function warptorio.CountPlatformEntities() return 5 end -- todo function warptorio.Warpout(key) - warptorio.IsWarping=true - for k,v in pairs(global.Harvesters)do if(v.deployed)then v:Recall(true) end end + warptorio.IsWarping = true + for k, v in pairs(storage.Harvesters) do if (v.deployed) then v:Recall(true) end end - local cp=warptorio.GetMainPlanet() - local cf=warptorio.GetMainSurface() + local cp = warptorio.GetMainPlanet() + local cf = warptorio.GetMainSurface() warptorio.WarpPreBuildPlanet(key) - local f,w,frc=warptorio.WarpBuildPlanet(key) + local f, w, frc = warptorio.WarpBuildPlanet(key) warptorio.WarpPostBuildPlanet(w) - global.floor.main.host=f - global.floor.main.hostindex=f.index + storage.floor.main.host = f + storage.floor.main.hostindex = f.index - warptorio.ConstructPlatform("main",true) + warptorio.ConstructPlatform("main", true) - events.vraise("on_warp",{newsurface=f,newplanet=w,oldsurface=cf,oldplanet=cp}) - if(cp and cp.on_warp)then lib.call(cp.on_warp,f,w,cf,cp) end + events.vraise("on_warp", { newsurface = f, newplanet = w, oldsurface = cf, oldplanet = cp }) + if (cp and cp.on_warp) then lib.call(cp.on_warp, f, w, cf, cp) end - warptorio.Warp(cf,f) - warptorio.WarpPost(cf,f) + warptorio.Warp(cf, f) + warptorio.WarpPost(cf, f) -- reset pollution & biters - game.forces["enemy"].evolution_factor=0 - global.pollution_amount=1.1 - global.pollution_expansion=1.1 + game.forces["enemy"].set_evolution_factor(0) + storage.pollution_amount = 1.1 + storage.pollution_expansion = 1.1 -- warp sound players.playsound("warp_in") - warptorio.WarpFinished() - events.vraise("on_post_warp",{newsurface=f,newplanet=w}) - if(w.postwarpout)then lib.call(w.postwarpout,{newsurface=f,newplanet=w}) end - warptorio.IsWarping=false + events.vraise("on_post_warp", { newsurface = f, newplanet = w }) + if (w.postwarpout) then lib.call(w.postwarpout, { newsurface = f, newplanet = w }) end + warptorio.IsWarping = false end - function warptorio.WarpPreBuildPlanet(key) - global.warp_charge=0 - global.warp_charging=0 - global.votewarp={} - global.warp_last=game.tick + storage.warp_charge = 0 + storage.warp_charging = 0 + storage.votewarp = {} + storage.warp_last = game.tick - global.warpzone=global.warpzone+1 + storage.warpzone = storage.warpzone + 1 -- Warp chargetime cooldown math - local cot=warptorio.CountPlatformEntities() + local cot = warptorio.CountPlatformEntities() - local sgZone=warptorio.setting("warpcharge_zone") - local sgZoneGain=warptorio.setting("warpcharge_zonegain") - local sgMax=warptorio.setting("warpcharge_max") - local sgFactor=warptorio.setting("warp_charge_factor") - local sgMul=warptorio.setting("warpcharge_multi") + local sgZone = warptorio.setting("warpcharge_zone") + local sgZoneGain = warptorio.setting("warpcharge_zonegain") + local sgMax = warptorio.setting("warpcharge_max") + local sgFactor = warptorio.setting("warp_charge_factor") + local sgMul = warptorio.setting("warpcharge_multi") - global.warp_charge_time=math.min(10+ (cot/sgFactor) + (global.warpzone*sgMul) + (sgZoneGain*(math.min(global.warpzone,sgZone)/sgZone)*60), 60*sgMax) - global.warp_time_left=60*global.warp_charge_time + storage.warp_charge_time = math.min( + 10 + (cot / sgFactor) + (storage.warpzone * sgMul) + + (sgZoneGain * (math.min(storage.warpzone, sgZone) / sgZone) * 60), + 60 * sgMax) + storage.warp_time_left = 60 * storage.warp_charge_time -- Autowarp timer math - local rta=research.level("warptorio-reactor") - global.warp_auto_time=60*warptorio.setting("autowarp_time")+60*10*rta - global.warp_auto_end=game.tick+ global.warp_auto_time*60 + local rta = research.level("warptorio-reactor") + storage.warp_auto_time = 60 * warptorio.setting("autowarp_time") + 60 * 10 * rta + storage.warp_auto_end = game.tick + storage.warp_auto_time * 60 -- Abilities - --global.ability_uses=0 - --global.radar_uses=0 - --global.ability_next=game.tick+60*60*warptorio.setting("ability_warp") + --storage.ability_uses=0 + --storage.radar_uses=0 + --storage.ability_next=game.tick+60*60*warptorio.setting("ability_warp") - global.ability_drain=warptorio.setting("ability_drain") or 0.00001 - global.abilities={} + storage.ability_drain = warptorio.setting("ability_drain") or 0.00001 + storage.abilities = {} -- Update guis --if(research.has("warptorio-accelerator") or research.has("warptorio-charting") or research.has("warptorio-stabilizer"))then end --gui.uses() gui.cooldown() --if(warptorio.IsAutowarpEnabled())then gui.autowarp() end --gui.warpzone() - cache.updatemenu("hud","warpbtn") - + cache.updatemenu("hud", "warpbtn") -- packup old teleporter gate - --local tp=global.Teleporters.offworld if(tp and tp:ValidB())then tp:DestroyB() tp:DestroyLogsB() end + --local tp=storage.Teleporters.offworld if(tp and tp:ValidB())then tp:DestroyB() tp:DestroyLogsB() end -- Recall harvester plates and players on them. - --for k,v in pairs(global.Harvesters)do v:Recall(true) end - + --for k,v in pairs(storage.Harvesters)do v:Recall(true) end end - function warptorio.WarpBuildPlanet(key) local nplanet - if(key)then - nplanet=remote.call("planetorio","FromTemplate","warpzone_"..global.warpzone,key) + if (key) then + nplanet = remote.call("planetorio", "FromTemplate", "warpzone_" .. storage.warpzone, key) else - local vplanet=warptorio.GetMainPlanet() - local lvl=research.level("warptorio-reactor") - if(lvl>=8)then local wx=global.planet_target - if(wx=="home" or wx=="nauvis")then if(research.has("warptorio-homeworld"))then local hf=(wx=="nauvis" and game.surfaces.nauvis or global.floor.home.host) - if(warptorio.GetMainSurface()~=hf and math.random(1,100)<=warptorio.setting("warpchance"))then local hp=remote.call("planetorio","GetBySurface",hf) or {name="Nauvis"} - game.print({"warptorio.successful_warp"}) game.print({"warptorio.home_sweet_home",hp.name}) - return hf,hp + local vplanet = warptorio.GetMainPlanet() + local lvl = research.level("warptorio-reactor") + if (lvl >= 8) then + local wx = storage.planet_target + if (wx == "home" or wx == "nauvis") then + if (research.has("warptorio-homeworld")) then + local hf = (wx == "nauvis" and game.surfaces.nauvis or storage.floor.home.host) + if (warptorio.GetMainSurface() ~= hf and math.random(1, 100) <= warptorio.setting("warpchance")) then + local hp = remote.call("planetorio", "GetBySurface", hf) or { name = "Nauvis" } + game.print({ "warptorio.successful_warp" }) + game.print({ "warptorio.home_sweet_home", hp.name }) + return hf, hp + end end - end elseif(wx and math.random(1,100)<=warptorio.setting("warpchance"))then - nplanet=remote.call("planetorio","FromTemplate","warpzone_"..global.warpzone,wx) - if(nplanet)then game.print({"warptorio.successful_warp"}) end + elseif (wx and math.random(1, 100) <= warptorio.setting("warpchance")) then + nplanet = remote.call("planetorio", "FromTemplate", "warpzone_" .. storage.warpzone, wx) + if (nplanet) then game.print({ "warptorio.successful_warp" }) end end end - if(not nplanet)then nplanet=remote.call("planetorio","SimplePlanetRoll","warpzone_"..global.warpzone,{zone=global.warpzone,prevplanet=vplanet}) end -- planetorio, modifiers={{"",stuff}}) + if (not nplanet) then + nplanet = remote.call("planetorio", "SimplePlanetRoll", "warpzone_" .. storage.warpzone, + { zone = storage.warpzone, prevplanet = vplanet }) + end -- planetorio, modifiers={{"",stuff}}) end - if(research.has("warptorio-charting") or not nplanet.planet.desc)then game.print(nplanet.planet.name) end - if(nplanet.planet.desc)then game.print(nplanet.planet.desc) end - return nplanet.surface,nplanet.planet,nplanet.force + if (research.has("warptorio-charting") or not nplanet.planet.desc) then game.print(nplanet.planet.name) end + if (nplanet.planet.desc) then game.print(nplanet.planet.desc) end + return nplanet.surface, nplanet.planet, nplanet.force end - function warptorio.WarpPostBuildPlanet(planet) - if(planet.warp_multiply)then - global.warp_charge_time=global.warp_charge_time*planet.warp_multiply - global.warp_time_left=global.warp_time_left*planet.warp_multiply + if (planet.warp_multiply) then + storage.warp_charge_time = storage.warp_charge_time * planet.warp_multiply + storage.warp_time_left = storage.warp_time_left * planet.warp_multiply end --gui.charge_time() end -function warptorio.Warp(cf,f) -- Find and clone entities to new surface +function warptorio.Warp(cf, f) -- Find and clone entities to new surface --cf.find_entities() --cf.clone_entities{surface=f,entities=tbl} -- call to platform() + if (storage.Teleporters.offworld) then storage.Teleporters.offworld:DestroyPointTeleporter(2) end - if(global.Teleporters.offworld)then global.Teleporters.offworld:DestroyPointTeleporter(2) end + local etbl, tpply = warptorio.platform.GetWarpables(cf, f) --{},{} + for k, v in pairs(etbl) do if (not isvalid(v)) then etbl[k] = nil end end - local etbl,tpply=warptorio.platform.GetWarpables(cf,f) --{},{} - for k,v in pairs(etbl)do if(not isvalid(v))then etbl[k]=nil end end - - local blacktbl={} - for k,v in pairs(etbl)do if(table.HasValue(warptorio.GetWarpBlacklist(),v.name))then table.insert(blacktbl,v) etbl[k]=nil end end - for k,v in pairs(etbl)do if(not v or not v.valid)then etbl[k]=nil end end + local blacktbl = {} + for k, v in pairs(etbl) do + if (table.HasValue(warptorio.GetWarpBlacklist(), v.name)) then + table.insert(blacktbl, v) + etbl[k] = nil + end + end + for k, v in pairs(etbl) do if (not v or not v.valid) then etbl[k] = nil end end -- find logistics networks and robots among entities to catch robots outside the platform - if(settings.global["warptorio_robot_warping"].value==true)then - local lgn={} for k,v in pairs(etbl)do if(v.type=="roboport")then local g=v.logistic_network if(g and g.valid)then table.insertExclusive(lgn,g) end end end - for k,v in pairs(lgn)do for i,e in pairs(v.robots)do table.insertExclusive(etbl,e) end end + if (settings.global["warptorio_robot_warping"].value == true) then + local lgn = {} + for k, v in pairs(etbl) do + if (v.type == "roboport") then + local g = v.logistic_network + if (g and g.valid) then table.insertExclusive(lgn, g) end + end + end + for k, v in pairs(lgn) do for i, e in pairs(v.robots) do table.insertExclusive(etbl, e) end end end - -- do the cloning - warptorio.Cloned_Entities={} - warptorio.IsCloning=true - cf.clone_entities{entities=etbl,destination_offset={0,0},destination_surface=f} --,destination_force=game.forces.player} - warptorio.IsCloning=false - local new_ents=warptorio.Cloned_Entities - warptorio.Cloned_Entities=nil + warptorio.Cloned_Entities = {} + warptorio.IsCloning = true + cf.clone_entities { entities = etbl, destination_offset = { 0, 0 }, destination_surface = f } --,destination_force=game.forces.player} + warptorio.IsCloning = false + local new_ents = warptorio.Cloned_Entities + warptorio.Cloned_Entities = nil -- AAI Vehicles - if(remote.interfaces["aai-programmable-vehicles"])then local rmt="aai-programmable-vehicles" - for k,v in pairs(new_ents)do if(isvalid(v.source) and isvalid(v.destination))then - local sig=remote.call(rmt,"get_unit_by_entity",v.source) if(sig)then remote.call(rmt,"on_entity_deployed",{entity=v.destination,signals=sig.data}) end - end end + if (remote.interfaces["aai-programmable-vehicles"]) then + local rmt = "aai-programmable-vehicles" + for k, v in pairs(new_ents) do + if (isvalid(v.source) and isvalid(v.destination)) then + local sig = remote.call(rmt, "get_unit_by_entity", v.source) + if (sig) then remote.call(rmt, "on_entity_deployed", { entity = v.destination, signals = sig.data }) end + end + end end --local clones={} for k,v in pairs(etbl)do if(v.valid)then table.insert(clones,v.clone{position=v.position,surface=f,force=v.force}) end end -- Recreate teleporter gate - --if(global.Teleporters.offworld)then global.Teleporters.offworld:CheckTeleporterPairs() end + --if(storage.Teleporters.offworld)then storage.Teleporters.offworld:CheckTeleporterPairs() end -- Clean inventories - for k,v in pairs(game.players)do if(v and v.valid)then local iv=v.get_main_inventory() if(iv)then for i,x in pairs(iv.get_contents())do - if(i:sub(1,25)=="warptorio-teleporter-gate")then iv.remove{name=i,count=x} end - if(i:sub(1,20)=="warptorio-harvestpad")then if(x>1)then iv.remove{name=i,count=(x-1)} end end - end end end end + for k, v in pairs(game.players) do + if (v and v.valid) then + local iv = v.get_main_inventory() + if (iv) then + for i, x in pairs(iv.get_contents()) do + if (x.name:sub(1, 25) == "warptorio-teleporter-gate") then iv.remove { name = x.name, count = x.count } end + if (x.name:sub(1, 20) == "warptorio-harvestpad") then if (x.count > 1) then iv.remove { name = x.name, count = (x.count - 1) } end end + end + end + end + end -- do the player teleport - for k,v in pairs(tpply)do v[1].teleport(f.find_non_colliding_position("character",{v[2][1],v[2][2]},0,1),f) end + for k, v in pairs(tpply) do v[1].teleport(f.find_non_colliding_position("character", { v[2][1], v[2][2] }, 0, 1), f) end --// cleanup past entities - - for k,v in pairs(etbl)do if(v and v.valid)then v.destroy{raise_destroy=true} end end - for k,v in pairs(blacktbl)do if(v and v.valid)then v.destroy{raise_destroy=true} end end + + for k, v in pairs(etbl) do if (v and v.valid) then v.destroy { raise_destroy = true } end end + for k, v in pairs(blacktbl) do if (v and v.valid) then v.destroy { raise_destroy = true } end end end -function warptorio.SurfaceIsWarpzone(f) local n=f.name - local hw=warptorio.GetHomeSurface() - local sf=(n:sub(1,9)=="warpsurf_") -- backwards compatability - local zf=(n:sub(1,9)=="warpzone_") - return (n~="nauvis" and (sf or zf) and f~=hw) +function warptorio.SurfaceIsWarpzone(f) + local n = f.name + local hw = warptorio.GetHomeSurface() + local sf = (n:sub(1, 9) == "warpsurf_") -- backwards compatability + local zf = (n:sub(1, 9) == "warpzone_") + return (n ~= "nauvis" and (sf or zf) and f ~= hw) end function warptorio.WarpFinished() - local f=warptorio.GetMainSurface() + local f = warptorio.GetMainSurface() --// delete abandoned surfaces - for k,v in pairs(game.surfaces)do - if( table_size(v.find_entities_filtered{type="character"})<1 and v~=f)then - --if(n=="nauvis" and not global.nauvis_is_clear)then global.nauvis_is_clear=true v.clear(true) else - if(warptorio.SurfaceIsWarpzone(v))then game.delete_surface(v) end + for k, v in pairs(game.surfaces) do + if (table_size(v.find_entities_filtered { type = "character" }) < 1 and v ~= f) then + --if(n=="nauvis" and not storage.nauvis_is_clear)then storage.nauvis_is_clear=true v.clear(true) else + if (warptorio.SurfaceIsWarpzone(v)) then game.delete_surface(v) end end end --warptorio.CheckReactor() - end -function warptorio.WarpPost(cf,f) +function warptorio.WarpPost(cf, f) -- Recreate teleporter gate - if(global.Teleporters.offworld)then global.Teleporters.offworld:CheckTeleporterPairs() end + if (storage.Teleporters.offworld) then storage.Teleporters.offworld:CheckTeleporterPairs() end --// radar -- game.forces.player.chart(f,{lefttop={x=-256,y=-256},rightbottom={x=256,y=256}}) @@ -1049,20 +1402,14 @@ function warptorio.WarpPost(cf,f) --for k,v in pairs({"nw","ne","sw","se"})do local ug=research.level("turret-"..v) or -1 if(ug>=0)then vector.LayCircle("out-of-map",c,vector.circleEx(vector(cx[v].x+0.5,cx[v].y+0.5),math.floor(10+(ug*6)) )) end end --vector.LayTiles("out-of-map",c,marea) - if(cf and cf.valid)then warptorio.ConstructPlatformVoid(cf) end - - + if (cf and cf.valid) then warptorio.ConstructPlatformVoid(cf) end end +--[[ Remotes ]] -- - - ---[[ Remotes ]]-- - -warptorio.remote={} +warptorio.remote = {} require("control_main_remotes") -remote.add_interface("warptorio",warptorio.remote) -remote.add_interface("warptorio2",warptorio.remote) - +remote.add_interface("warptorio", warptorio.remote) +remote.add_interface("warptorio2", warptorio.remote) diff --git a/control_main_helpers.lua b/control_main_helpers.lua index b6e634b..406220b 100644 --- a/control_main_helpers.lua +++ b/control_main_helpers.lua @@ -1,5 +1,4 @@ - ---[[ Todo list ]]-- +--[[ Todo list ]] -- --[[ function warptorio.CountEntities() local c=0 for k,v in pairs(gwarptorio.floor)do if(v.surface and v.surface.valid and k~="main" and k~="home")then @@ -41,7 +40,7 @@ end function warptorio.MigrateHarvesterFloor() warptorio.BuildB3() local rLogs=game.forces.player.technologies["warptorio-logistics-1"].researched - for k,v in pairs(global.warptorio.Harvesters)do local f,pos v:DestroyLogs() + for k,v in pairs(storage.warptorio.Harvesters)do local f,pos v:DestroyLogs() if(v.deployed)then f,pos=v.b.surface,v.deploy_position v:Recall() end v:DestroyA() v:DestroyB() v:Warpin() if(rLogs)then v:SpawnLogs() end v:Upgrade() end @@ -102,217 +101,367 @@ end -]]-- +]] -- ---[[ Settings ]]-- -function warptorio.setting(n) return settings.global["warptorio_"..n].value end +--[[ Settings ]] -- +function warptorio.setting(n) return settings.global["warptorio_" .. n].value end -warptorio.settings={} local setter=warptorio.settings +warptorio.settings = {} +local setter = warptorio.settings function setter.warptorio_autowarp_disable() warptorio.ResetHUD() end + function setter.warptorio_autowarp_always() warptorio.ResetHUD() end + function setter.warptorio_water() warptorio.EarlyWater(settings.global["warptorio_water"].value) end + function setter.warptorio_carebear() warptorio.Carebear(settings.global["warptorio_carebear"].value) end -function setter.warptorio_solar_multiplier() warptorio.SolarMultiplier(settings.global["warptorio_solar_multiplier"].value) end + +function setter.warptorio_solar_multiplier() + warptorio.SolarMultiplier(settings.global["warptorio_solar_multiplier"] + .value) +end + function setter.warptorio_loaderchest_provider() warptorio.LoaderChestChanged(true) end + function setter.warptorio_loaderchest_requester() warptorio.LoaderChestChanged(false) end + function setter.warptorio_loader_top() warptorio.LoaderSideChanged(true) end + function setter.warptorio_loader_bottom() warptorio.LoaderSideChanged(false) end + function setter.warptorio_combinator_offset() warptorio.CombinatorOffsetChanged() end -function setter.warptorio_hide_sprites() for k,v in pairs(global.Teleporters)do v:CheckPointSprites(1) v:CheckPointSprites(2) end end +function setter.warptorio_hide_sprites() + for k, v in pairs(storage.Teleporters) do + v:CheckPointSprites(1) + v:CheckPointSprites(2) + end +end function warptorio.CombinatorOffsetChanged() - for k,v in pairs(global.Harvesters)do v:DestroyCombos() v:CheckCombo() end + for k, v in pairs(storage.Harvesters) do + v:DestroyCombos() + v:CheckCombo() + end end + function warptorio.LoaderChestChanged(bprovider) end + function warptorio.LoaderSideChanged(btop) - for k,v in pairs(global.Teleporters)do local g=v:Data().top if((btop and g) or (not btop and not g))then - v:DestroyPointLogistics(1) - v:DestroyPointLogistics(2) - v:CheckTeleporterPairs(true) - end end + for k, v in pairs(storage.Teleporters) do + local g = v:Data().top + if ((btop and g) or (not btop and not g)) then + v:DestroyPointLogistics(1) + v:DestroyPointLogistics(2) + v:CheckTeleporterPairs(true) + end + end end function warptorio.SolarMultiplier(x) - for k,v in pairs(warptorio.GetPlatformSurfaces())do v.solar_power_multiplier=x end -end - -warptorio.carebearItems={ -["stone"]=20,["coal"]=20,["iron-plate"]=20,["copper-plate"]=20,["electronic-circuit"]=10,["iron-gear-wheel"]=10, -["wooden-chest"]=4,["transport-belt"]=10,["underground-belt"]=2,["splitter"]=1, -["burner-mining-drill"]=2,["assembling-machine-1"]=2,["small-electric-pole"]=5,["steam-engine"]=1,["boiler"]=1, -["gun-turret"]=4,["uranium-rounds-magazine"]=50,["piercing-rounds-magazine"]=200,["firearm-magazine"]=400, + for k, v in pairs(warptorio.GetPlatformSurfaces()) do v.solar_power_multiplier = x end +end + +warptorio.carebearItems = { + ["stone"] = 20, + ["coal"] = 20, + ["iron-plate"] = 20, + ["copper-plate"] = 20, + ["electronic-circuit"] = 10, + ["iron-gear-wheel"] = 10, + ["wooden-chest"] = 4, + ["transport-belt"] = 10, + ["underground-belt"] = 2, + ["splitter"] = 1, + ["burner-mining-drill"] = 2, + ["assembling-machine-1"] = 2, + ["small-electric-pole"] = 5, + ["steam-engine"] = 1, + ["boiler"] = 1, + ["gun-turret"] = 4, + ["uranium-rounds-magazine"] = 50, + ["piercing-rounds-magazine"] = 200, + ["firearm-magazine"] = 400, } -function warptorio.Carebear(b) if(b and not global.carebear)then global.carebear=true - local e=global.floor.main.host.create_entity{name="warptorio-carebear-chest",position={-1,-1},force=game.forces.player} - local inv=e.get_inventory(defines.inventory.chest) for k,v in pairs(warptorio.carebearItems)do inv.insert{name=k,count=v} end -end end - +function warptorio.Carebear(b) + if (b and not storage.carebear) then + storage.carebear = true + local e = storage.floor.main.host.create_entity { name = "warptorio-carebear-chest", position = { -1, -1 }, force = game.forces.player } + local inv = e.get_inventory(defines.inventory.chest) + for k, v in pairs(warptorio.carebearItems) do inv.insert { name = k, count = v } end + end +end -function warptorio.EarlyWater(b) if(b and not global.earlywater)then global.earlywater=true - game.forces.player.technologies["warptorio-boiler-water-1"].researched=true -end end +function warptorio.EarlyWater(b) + if (b and not storage.earlywater) then + storage.earlywater = true + game.forces.player.technologies["warptorio-boiler-water-1"].researched = true + end +end -function warptorio.OnModSettingChanged(ev) local p=ev.player_index local s=ev.setting local st=ev.setting_type - if(warptorio.settings[s])then warptorio.settings[s](ev) end -end script.on_event(defines.events.on_runtime_mod_setting_changed,warptorio.OnModSettingChanged) +function warptorio.OnModSettingChanged(ev) + local p = ev.player_index + local s = ev.setting + local st = ev.setting_type + if (warptorio.settings[s]) then warptorio.settings[s](ev) end +end +script.on_event(defines.events.on_runtime_mod_setting_changed, warptorio.OnModSettingChanged) -function warptorio.IsAutowarpEnabled() return warptorio.setting("autowarp_disable")~=true and (not research.has("warptorio-reactor-6") or warptorio.setting("autowarp_always")) end +function warptorio.IsAutowarpEnabled() + return warptorio.setting("autowarp_disable") ~= true and + (not research.has("warptorio-reactor-6") or warptorio.setting("autowarp_always")) +end function warptorio.HookNewGamePlus() - if(remote.interfaces["newgameplus"])then if(not warptorio.newgameplus)then warptorio.newgameplus=true - local ngp=remote.call("newgameplus","get_on_technology_reset_event") if(ngp)then script.on_event(ngp,warptorio.OnPreNewGame) end - local ngp=remote.call("newgameplus","get_on_post_new_game_plus_event") if(ngp)then script.on_event(ngp,warptorio.OnPostNewGame) end - end end -end - - - ---[[ Loot Chest ]]-- - - -warptorio.LootItems={ -["roboport"]=4,["construction-robot"]=10,["logistic-robot"]=20, -["logistic-chest-passive-provider"]=10,["logistic-chest-requester"]=10,["logistic-chest-buffer"]=10, -["wooden-chest"]=20,["iron-chest"]=20,["steel-chest"]=20,["storage-tank"]=10, -["wood"]=100,["stone"]=100,["iron-plate"]=400,["iron-gear-wheel"]=300,["steel-plate"]=200,["copper-plate"]=300,["copper-cable"]=400, -["red-wire"]=100,["green-wire"]=100,["electronic-circuit"]=200,["advanced-circuit"]=100,["processing-unit"]=50, -["big-electric-pole"]=25,["medium-electric-pole"]=25,["small-electric-pole"]=25,["substation"]=15, -["landfill"]=100, -["pipe"]=200,["pipe-to-ground"]=50, -["express-transport-belt"]=100,["fast-transport-belt"]=200,["transport-belt"]=300, -["express-underground-belt"]=15,["fast-underground-belt"]=20,["underground-belt"]=25, -["accumulator"]=10,["steam-engine"]=10, -["nuclear-reactor"]=2,["heat-exchanger"]=10,["heat-pipe"]=25,["steam-turbine"]=10, -["chemical-plant"]=10,["assembling-machine-1"]=15,["assembling-machine-2"]=15,["assembling-machine-3"]=15, -["inserter"]=30,["fast-inserter"]=20,["stack-inserter"]=15, -["warptorio-atomic-bomb"]=1,["warptorio-warponium-fuel-cell"]=2,["warptorio-warponium-fuel"]=1, -["gun-turret"]=10,["uranium-rounds-magazine"]=100,["firearm-magazine"]=400,["piercing-rounds-magazine"]=200, -["atomic-bomb"]=2, + if (remote.interfaces["newgameplus"]) then + if (not warptorio.newgameplus) then + warptorio.newgameplus = true + local ngp = remote.call("newgameplus", "get_on_technology_reset_event") + if (ngp) then script.on_event(ngp, warptorio.OnPreNewGame) end + local ngp = remote.call("newgameplus", "get_on_post_new_game_plus_event") + if (ngp) then script.on_event(ngp, warptorio.OnPostNewGame) end + end + end +end + +--[[ Loot Chest ]] -- + + +warptorio.LootItems = { + ["roboport"] = 4, + ["construction-robot"] = 10, + ["logistic-robot"] = 20, + ["passive-provider-chest"] = 10, + ["requester-chest"] = 10, + ["buffer-chest"] = 10, + ["wooden-chest"] = 20, + ["iron-chest"] = 20, + ["steel-chest"] = 20, + ["storage-tank"] = 10, + ["wood"] = 100, + ["stone"] = 100, + ["iron-plate"] = 400, + ["iron-gear-wheel"] = 300, + ["steel-plate"] = 200, + ["copper-plate"] = 300, + ["copper-cable"] = 400, + ["electronic-circuit"] = 200, + ["advanced-circuit"] = 100, + ["processing-unit"] = 50, + ["big-electric-pole"] = 25, + ["medium-electric-pole"] = 25, + ["small-electric-pole"] = 25, + ["substation"] = 15, + ["landfill"] = 100, + ["pipe"] = 200, + ["pipe-to-ground"] = 50, + ["express-transport-belt"] = 100, + ["fast-transport-belt"] = 200, + ["transport-belt"] = 300, + ["express-underground-belt"] = 15, + ["fast-underground-belt"] = 20, + ["underground-belt"] = 25, + ["accumulator"] = 10, + ["steam-engine"] = 10, + ["nuclear-reactor"] = 2, + ["heat-exchanger"] = 10, + ["heat-pipe"] = 25, + ["steam-turbine"] = 10, + ["chemical-plant"] = 10, + ["assembling-machine-1"] = 15, + ["assembling-machine-2"] = 15, + ["assembling-machine-3"] = 15, + ["inserter"] = 30, + ["fast-inserter"] = 20, + ["bulk-inserter"] = 15, + ["warptorio-atomic-bomb"] = 1, + ["warptorio-warponium-fuel-cell"] = 2, + ["warptorio-warponium-fuel"] = 1, + ["gun-turret"] = 10, + ["uranium-rounds-magazine"] = 100, + ["firearm-magazine"] = 400, + ["piercing-rounds-magazine"] = 200, + ["atomic-bomb"] = 2, } -function warptorio.GetPossibleLoot() local lt={} for k,v in pairs(warptorio.LootItems)do local r=game.forces.player.recipes[k] if(not r or (r and r.enabled==true))then lt[k]=v end end return lt end -function warptorio.LootTable(mn,mx,cDist,cStack) local lt=warptorio.GetPossibleLoot() local t,u,k,vDist,vStack={} for i=1,math.random(mn or 1,mx or 5),1 do - u,k=table.Random(lt) vDist,vStack=math.min((cDist or 850)/1700,1),math.random((cStack or 20),100)/100 t[k]=math.max(math.ceil(u*vDist*vStack),1) -end return t end -function warptorio.SpawnLootChest(f,pos,varg) pos=vector(pos) varg=varg or {} - local e=f.create_entity{name="warptorio-lootchest",position=pos,force=game.forces.player,raise_built=true} if(not isvalid(e))then return false end - local lt=warptorio.LootTable(varg.min or 1, varg.max or 5,varg.dist or vector.length(pos), varg.stack or 20) - local inv=e.get_inventory(defines.inventory.chest) for k,v in pairs(lt)do inv.insert{name=k,count=v} end +function warptorio.GetPossibleLoot() + local lt = {} + for k, v in pairs(warptorio.LootItems) do + local r = game.forces.player.recipes[k] + if (not r or (r and r.enabled == true)) then lt[k] = v end + end + return lt +end + +function warptorio.LootTable(mn, mx, cDist, cStack) + local lt = warptorio.GetPossibleLoot() + local t, u, k, vDist, vStack = {} + for i = 1, math.random(mn or 1, mx or 5), 1 do + u, k = table.Random(lt) + vDist, vStack = math.min((cDist or 850) / 1700, 1), math.random((cStack or 20), 100) / 100 + t[k] = math.max(math.ceil(u * vDist * vStack), 1) + end + return t +end + +function warptorio.SpawnLootChest(f, pos, varg) + pos = vector(pos) + varg = varg or {} + local e = f.create_entity { name = "warptorio-lootchest", position = pos, force = game.forces.player, raise_built = true } + if (not isvalid(e)) then return false end + local lt = warptorio.LootTable(varg.min or 1, varg.max or 5, varg.dist or vector.length(pos), varg.stack or 20) + local inv = e.get_inventory(defines.inventory.chest) + for k, v in pairs(lt) do inv.insert { name = k, count = v } end return e end -function warptorio.ChunkLootChest(ev) if(settings.global["warptorio_no_lootchest"].value==true or math.random(1,settings.global["warptorio_lootchest_chance"].value)>1)then return end - local f=ev.surface if(not (f.name=="nauvis" or f==warptorio.GetMainSurface()))then return end local a=ev.area - local x,y=math.random(a.left_top.x,a.right_bottom.x),math.random(a.left_top.y,a.right_bottom.y) - local dist=math.sqrt(math.abs(x^2)+math.abs(y^2)) - if(dist>=settings.global["warptorio_lootchest_distance"].value)then warptorio.SpawnLootChest(f,{x,y}) end -end events.on_event(defines.events.on_chunk_generated,warptorio.ChunkLootChest) +function warptorio.ChunkLootChest(ev) + if (settings.global["warptorio_no_lootchest"].value == true or math.random(1, settings.global["warptorio_lootchest_chance"].value) > 1) then return end + local f = ev.surface + if (not (f.name == "nauvis" or f == warptorio.GetMainSurface())) then return end + local a = ev.area + local x, y = math.random(a.left_top.x, a.right_bottom.x), math.random(a.left_top.y, a.right_bottom.y) + local dist = math.sqrt(math.abs(x ^ 2) + math.abs(y ^ 2)) + if (dist >= settings.global["warptorio_lootchest_distance"].value) then + warptorio.SpawnLootChest(f, { x, y }) + end +end + +events.on_event(defines.events.on_chunk_generated, warptorio.ChunkLootChest) ---[[ Tick Functions ]]-- +--[[ Tick Functions ]] -- function warptorio.ClockTick(tick) - local donewarp=false - if(global.warp_charging==1)then - global.warp_time_left=(60*global.warp_charge_time)-(tick-global.warp_charge_start_tick) - if(global.warp_time_left<=0)then warptorio.Warpout() donewarp=true end + local donewarp = false + if (storage.warp_charging == 1) then + storage.warp_time_left = (60 * storage.warp_charge_time) - (tick - storage.warp_charge_start_tick) + if (storage.warp_time_left <= 0) then + warptorio.Warpout() + donewarp = true + end end - global.time_passed=tick-global.warp_last + storage.time_passed = tick - storage.warp_last --gui.time_passed() --gui.charge_time() - if(not donewarp and warptorio.IsAutowarpEnabled())then - global.warp_auto_end=(60*global.warp_auto_time)-(tick-global.warp_last) - if(global.warp_auto_end<=0)then warptorio.Warpout() donewarp=true end + if (not donewarp and warptorio.IsAutowarpEnabled()) then + storage.warp_auto_end = (60 * storage.warp_auto_time) - (tick - storage.warp_last) + if (storage.warp_auto_end <= 0) then + warptorio.Warpout() + donewarp = true + end end - cache.updatemenu("hud","clocktick") + cache.updatemenu("hud", "clocktick") --gui.autowarp() --gui if(research.has("warptorio-charting") or research.has("warptorio-accelerator") or research.has("warptorio-stabilizer"))then warptorio.derma.cooldown() end - --gui if(global.homeworld)then warptorio.derma.homeworld() end + --gui if(storage.homeworld)then warptorio.derma.homeworld() end warptorio.RefreshWarpCombinators() - --events.vraise("ticktime",{warp_left=global.warp_time_left,auto_left=warptorio.IsAutowarpEnabled() and global.warp_auto_end or false, donewarp=donewarp}) + --events.vraise("ticktime",{warp_left=storage.warp_time_left,auto_left=warptorio.IsAutowarpEnabled() and storage.warp_auto_end or false, donewarp=donewarp}) end -events.on_tick(60,0,"clock",warptorio.ClockTick) + +events.on_tick(60, 0, "clock", warptorio.ClockTick) function warptorio.ChargeCountdownTick(tick) - if(global.warp_charging<1 and global.warp_charge_time>30)then - local r=(780)-(research.level("warptorio-reactor")*60) if(tick%r==0)then global.warp_charge_time=math.max(global.warp_charge_time-1,30) end -- 60t*13s=780t + if (storage.warp_charging < 1 and storage.warp_charge_time > 30) then + local r = (780) - (research.level("warptorio-reactor") * 60) + if (tick % r == 0) then storage.warp_charge_time = math.max(storage.warp_charge_time - 1, 30) end -- 60t*13s=780t end end -events.on_tick(60,0,"charge_countdown",warptorio.ChargeCountdownTick) + +events.on_tick(60, 0, "charge_countdown", warptorio.ChargeCountdownTick) function warptorio.WarpAlarmTick(tick) - if((global.warp_charging==1 and global.warp_time_left<=3600) or (warptorio.IsAutowarpEnabled() and global.warp_auto_end<=3600))then players.playsound("warp_alarm") end + if ((storage.warp_charging == 1 and storage.warp_time_left <= 3600) or (warptorio.IsAutowarpEnabled() and storage.warp_auto_end <= 3600)) then + players.playsound("warp_alarm") + end end -events.on_tick(120,1,"warpalarm",warptorio.WarpAlarmTick) -function warptorio.PollutionTick(tick) if(tick%(warptorio.setting("pollution_tickrate")*60)~=0)then return end - local f=warptorio.GetMainSurface() if(not isvalid(f))then return end - local stb=global.abilities.stabilizing - local vpol=0 - if(warptorio.setting("pollution_disable")~=true)then - vpol=global.pollution_amount - global.pollution_amount=math.min( vpol+ (vpol^warptorio.setting("pollution_exponent"))*(stb and 0.05 or warptorio.setting("pollution_multiplier")), 1000000) +events.on_tick(120, 1, "warpalarm", warptorio.WarpAlarmTick) + +function warptorio.PollutionTick(tick) + if (tick % (warptorio.setting("pollution_tickrate") * 60) ~= 0) then return end + local f = warptorio.GetMainSurface() + if (not isvalid(f)) then return end + local stb = storage.abilities.stabilizing + local vpol = 0 + if (warptorio.setting("pollution_disable") ~= true) then + vpol = storage.pollution_amount + storage.pollution_amount = math.min( + vpol + (vpol ^ warptorio.setting("pollution_exponent")) * + (stb and 0.05 or warptorio.setting("pollution_multiplier")), 1000000) end - for k,v in pairs(warptorio.GetPlatformSurfaces())do - vpol=vpol+v.get_total_pollution() + for k, v in pairs(warptorio.GetPlatformSurfaces()) do + vpol = vpol + v.get_total_pollution() v.clear_pollution() end - if(vpol>0)then - f.pollute({-1,-1},vpol*(stb and 0.05 or 1)) -- todo; pollute to teleporters and harvesters *0.125 + if (vpol > 0) then + f.pollute({ -1, -1 }, vpol * (stb and 0.05 or 1)) -- todo; pollute to teleporters and harvesters *0.125 end - end -events.on_tick(60,0,"pollution",warptorio.PollutionTick) -events.on_tick(60,0,"radar_ability",function(tick) - local rdr=global.abilities.scanning if(not rdr)then return end - local rdrt=global.abilities.scantick or 0 - local rdrg=global.abilities.scanzone or 0 - rdrt=rdrt+1 global.abilities.scantick=rdrt if(rdrt<3+rdrg)then return end rdrt=0 global.abilities.scantick=0 +events.on_tick(60, 0, "pollution", warptorio.PollutionTick) +events.on_tick(60, 0, "radar_ability", function(tick) + local rdr = storage.abilities.scanning + if (not rdr) then return end + local rdrt = storage.abilities.scantick or 0 + local rdrg = storage.abilities.scanzone or 0 + rdrt = rdrt + 1 + storage.abilities.scantick = rdrt + if (rdrt < 3 + rdrg) then return end + rdrt = 0 + storage.abilities.scantick = 0 - global.abilities.scanzone=rdrg+1 - local f=warptorio.GetMainSurface() - game.forces.player.chart(f,{lefttop={x=-64-32*rdrg,y=-64-32*rdrg},rightbottom={x=64+32*rdrg,y=64+32*rdrg}}) - players.playsound("reactor-stabilized", f) + storage.abilities.scanzone = rdrg + 1 + local f = warptorio.GetMainSurface() + game.forces.player.chart(f, + { lefttop = { x = -64 - 32 * rdrg, y = -64 - 32 * rdrg }, rightbottom = { x = 64 + 32 * rdrg, y = 64 + 32 * rdrg } }) + players.playsound("reactor-stabilized", f) end) -function warptorio.BiterTick(tick) if(warptorio.setting("biter_wave_disable")==true or tick%(warptorio.setting("pollution_tickrate")*60)~=0)then return end - global.pollution_expansion = math.min( global.pollution_expansion * settings.global["warptorio_biter_expansion"].value, 60*60*settings.global["warptorio_biter_redux"].value ) - game.map_settings.enemy_expansion.min_expansion_cooldown = math.max((60*60*settings.global["warptorio_biter_min"].value)-global.pollution_expansion,60*60*1) - game.map_settings.enemy_expansion.max_expansion_cooldown = math.max( ((60*60*settings.global["warptorio_biter_max"].value)-global.pollution_expansion)+1,60*60*1) - --game.print("pol: " .. game.map_settings.enemy_expansion.min_expansion_cooldown) - local pt=(global.time_passed/60)/60 - if(pt>settings.global["warptorio_biter_wavestart"].value)then pt=pt-settings.global["warptorio_biter_wavestart"].value - local el=math.ceil(pt*settings.global["warptorio_biter_wavesize"].value) - local erng=math.ceil(pt*settings.global["warptorio_biter_waverng"].value) - local bmax=settings.global["warptorio_biter_wavesizemax"].value if(bmax>0)then el=math.min(el,bmax) end - if(math.random(1,math.max(math.min(settings.global["warptorio_biter_wavemax"].value-erng,settings.global["warptorio_biter_wavemin"].value),1))<=1)then - local f=global.floor.main.host - f.set_multi_command{command={type=defines.command.attack_area, destination={0,0},radius=128}, unit_count=el} - end +function warptorio.BiterTick(tick) + if (warptorio.setting("biter_wave_disable") == true or tick % (warptorio.setting("pollution_tickrate") * 60) ~= 0) then return end + storage.pollution_expansion = math.min( + storage.pollution_expansion * settings.global["warptorio_biter_expansion"].value, + 60 * 60 * settings.global["warptorio_biter_redux"].value) + game.map_settings.enemy_expansion.min_expansion_cooldown = math.max( + (60 * 60 * settings.global["warptorio_biter_min"].value) - storage.pollution_expansion, 60 * 60 * 1) + game.map_settings.enemy_expansion.max_expansion_cooldown = math.max( + ((60 * 60 * settings.global["warptorio_biter_max"].value) - storage.pollution_expansion) + 1, 60 * 60 * 1) + --game.print("pol: " .. game.map_settings.enemy_expansion.min_expansion_cooldown) + local pt = (storage.time_passed / 60) / 60 + if (pt > settings.global["warptorio_biter_wavestart"].value) then + pt = pt - settings.global["warptorio_biter_wavestart"].value + local el = math.ceil(pt * settings.global["warptorio_biter_wavesize"].value) + local erng = math.ceil(pt * settings.global["warptorio_biter_waverng"].value) + local bmax = settings.global["warptorio_biter_wavesizemax"].value + if (bmax > 0) then el = math.min(el, bmax) end + if (math.random(1, math.max(math.min(settings.global["warptorio_biter_wavemax"].value - erng, settings.global["warptorio_biter_wavemin"].value), 1)) <= 1) then + local f = storage.floor.main.host + f.set_multi_command { command = { type = defines.command.attack_area, destination = { 0, 0 }, radius = 128 }, unit_count = el } end + end end -events.on_tick(60,0,"biters",warptorio.BiterTick) + +events.on_tick(60, 0, "biters", warptorio.BiterTick) --[[ @@ -321,15 +470,15 @@ wderma.stabilizer=derma.GuiControl("warptorio_stabilizer","button") function wderma.stabilizer:get(p) return derma.control(derma.getrow(p,2),self.name,self.type) end function wderma.stabilizer:update(p) local r=self:get(p) r.caption={"warptorio.button_stabilizer"} end function wderma.stabilizer:click(p) - if(game.tick<(global.ability_next or 0) or not research.has("warptorio-stabilizer"))then return end + if(game.tick<(storage.ability_next or 0) or not research.has("warptorio-stabilizer"))then return end warptorio.IncrementAbility(settings.global["warptorio_ability_timegain"].value,settings.global["warptorio_ability_cooldown"].value) - warptorio.raise_event("ability_used",{player=p,ability="stabilizer",use_num=global.ability_uses}) + warptorio.raise_event("ability_used",{player=p,ability="stabilizer",use_num=storage.ability_uses}) game.forces["enemy"].evolution_factor=0 - global.pollution_amount = 1.25 - global.pollution_expansion = 1.5 + storage.pollution_amount = 1.25 + storage.pollution_expansion = 1.5 local f=warptorio.GetMainSurface() f.clear_pollution() - if(global.warp_reactor and isvalid(global.warp_reactor))then f.set_multi_command{command={type=defines.command.flee, from=global.warp_reactor}, unit_count=1000, unit_search_distance=500} end + if(storage.warp_reactor and isvalid(storage.warp_reactor))then f.set_multi_command{command={type=defines.command.flee, from=storage.warp_reactor}, unit_count=1000, unit_search_distance=500} end players.playsound("reactor-stabilized", f) game.print("Warp Reactor Stabilized") end @@ -368,63 +517,69 @@ end ]] ---[[ Class Cache ]]-- - - - +--[[ Class Cache ]] -- - -local tpCache={} -function tpCache.raise(obj,cls,entkey,pth,vi) - obj.cls=cls - obj.entkey=entkey - obj.pth=pth - obj.vi=vi +local tpCache = {} +function tpCache.raise(obj, cls, entkey, pth, vi) + obj.cls = cls + obj.entkey = entkey + obj.pth = pth + obj.vi = vi end -function tpCache.unraise(obj,b_noraise) - local gv=global[obj.cls][obj.entkey] + +function tpCache.unraise(obj, b_noraise) + local gv = storage[obj.cls][obj.entkey] --gv:DestroyPointTeleporter(obj.vi) end -function tpCache.create(e,ev) - cache.insert("power",e) + +function tpCache.create(e, ev) + cache.insert("power", e) end -function tpCache.clone(e,ev) - local obj=cache.get_entity(ev.source) - if(obj)then - local gv=global[obj.cls][obj.entkey] + +function tpCache.clone(e, ev) + local obj = cache.get_entity(ev.source) + if (obj) then + local gv = storage[obj.cls][obj.entkey] gv:DestroyPointSprites(obj.vi) - local nv=cache.force_entity(e,obj.cls,obj.entkey,obj.pth,obj.vi) - cache.destroy_entity(obj,true) - gv[nv.pth][nv.vi].ent=e + local nv = cache.force_entity(e, obj.cls, obj.entkey, obj.pth, obj.vi) + cache.destroy_entity(obj, true) + gv[nv.pth][nv.vi].ent = e gv:CheckPointSprites(nv.vi) - local gvoe=gv[nv.pth][nv.vi==1 and 2 or 1].ent - local gvoc=cache.get_entity(gvoe) - if(gvoc)then gvoc.teleport_dest=e nv.teleport_dest=gvoe end - if(gv:Data().circuit)then gv:ConnectCircuit() end + local gvoe = gv[nv.pth][nv.vi == 1 and 2 or 1].ent + local gvoc = cache.get_entity(gvoe) + if (gvoc) then + gvoc.teleport_dest = e + nv.teleport_dest = gvoe + end + if (gv:Data().circuit) then gv:ConnectCircuit() end end end -function tpCache.destroy(e,ev) - cache.remove("power",e) - local obj=cache.get_entity(e) - if(obj)then - local gv=global[obj.cls][obj.entkey] + +function tpCache.destroy(e, ev) + cache.remove("power", e) + local obj = cache.get_entity(e) + if (obj) then + local gv = storage[obj.cls][obj.entkey] --gv:DestroyPointTeleporter(obj.vi) --gv:DestroyPointLogistics(obj.vi) cache.destroy(obj) end end -local tpgateCache=table.deepcopy(tpCache) -function tpgateCache.built(e,ev) - local obj=cache.force_entity(e,"Teleporters","offworld","points",2) +local tpgateCache = table.deepcopy(tpCache) +function tpgateCache.built(e, ev) + local obj = cache.force_entity(e, "Teleporters", "offworld", "points", 2) - if(obj)then - local ef=e.surface - local t=global.Teleporters["offworld"] - local gv=global[obj.cls][obj.entkey] - if(gv:ValidB())then entity.destroy(gv.points[2].ent) game.print("Max 1 Planet Teleporter Gate allowed at a time - built") end + if (obj) then + local ef = e.surface + local t = storage.Teleporters["offworld"] + local gv = storage[obj.cls][obj.entkey] + if (gv:ValidB()) then + entity.destroy(gv.points[2].ent) + game.print({ "warptorio.max-one-teleporter-error" }) + end --if(ef~=warptorio.GetMainSurface())then game.print("Teleporter Logistics only functions on the Planet") return end --[[if(ef.count_entities_filtered{area=t:GetLogisticsArea(e.position),collision_mask={"object-layer"}} >1)then @@ -434,48 +589,52 @@ function tpgateCache.built(e,ev) gv:CheckTeleporterPairs() return end]] - local gve=gv[obj.pth][obj.vi] - gve.ent=e - gv:CheckPointLogistics(2,e.position) - if(gve.energy)then e.energy=gve.energy gve.energy=nil end + local gve = gv[obj.pth][obj.vi] + gve.ent = e + gv:CheckPointLogistics(2, e.position) + if (gve.energy) then + e.energy = gve.energy + gve.energy = nil + end gv:CheckTeleporterPairs() end end -function tpgateCache.destroy(e,ev) - cache.remove("power",e) - local obj=cache.get_entity(e) - if(obj)then - local gv=global[obj.cls][obj.entkey] + +function tpgateCache.destroy(e, ev) + cache.remove("power", e) + local obj = cache.get_entity(e) + if (obj) then + local gv = storage[obj.cls][obj.entkey] --gv:DestroyPointTeleporter(obj.vi) gv:DestroyPointLogistics(obj.vi) cache.destroy(obj) end end +local tpharvCache = table.deepcopy(tpCache) - -local tpharvCache=table.deepcopy(tpCache) - -function tpharvCache.destroy(e,ev) - cache.remove("power",e) - local obj=cache.get_entity(e) - if(obj and not obj.dead)then obj.dead=true - local gv=global[obj.cls][obj.entkey] +function tpharvCache.destroy(e, ev) + cache.remove("power", e) + local obj = cache.get_entity(e) + if (obj and not obj.dead) then + obj.dead = true + local gv = storage[obj.cls][obj.entkey] cache.destroy(obj) gv:Recall() end end -tpharvCache.died=tpharvCache.destroy -function tpharvCache.mined(e,ev) - local obj=cache.get_entity(e) - if(obj)then - local gv=global[obj.cls][obj.entkey] - for x,y in pairs(ev.buffer.get_contents())do ev.buffer.remove({name=x,count=y}) end - local cn=(gv:Data().pad_prototype .."-"..research.level("warptorio-harvester-"..obj.entkey)) - if(not ply or (ply and not ply.get_main_inventory().get_contents()[cn]))then ev.buffer.insert{name=cn,count=1} end - local hv=global.Harvesters[obj.entkey] - if(not hv.deployed)then hv:Recall() else hv:CheckTeleporterPairs() end +tpharvCache.died = tpharvCache.destroy + +function tpharvCache.mined(e, ev) + local obj = cache.get_entity(e) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + for x, y in pairs(ev.buffer.get_contents()) do ev.buffer.remove({ name = y.name, count = y.count }) end + local cn = (gv:Data().pad_prototype .. "-" .. research.level("warptorio-harvester-" .. obj.entkey)) + if (not ply or (ply and not ply.get_main_inventory().get_contents()[cn])) then ev.buffer.insert { name = cn, count = 1 } end + local hv = storage.Harvesters[obj.entkey] + if (not hv.deployed) then hv:Recall() else hv:CheckTeleporterPairs() end end end @@ -483,7 +642,7 @@ end function tpharvCache.clone(e,ev) local obj=cache.get_entity(ev.source) if(obj)then - local gv=global[obj.cls][obj.entkey] + local gv=storage[obj.cls][obj.entkey] gv:DestroyPointSprites(obj.vi) local nv=cache.force_entity(e,obj.cls,obj.entkey,obj.pth,obj.vi) cache.destroy_entity(obj,true) @@ -498,329 +657,419 @@ function tpharvCache.clone(e,ev) end ]] -function tpharvCache.clone(e,ev) - local obj=cache.get_entity(ev.source) - if(obj)then - local gv=global[obj.cls][obj.entkey] +function tpharvCache.clone(e, ev) + local obj = cache.get_entity(ev.source) + if (obj) then + local gv = storage[obj.cls][obj.entkey] gv:DestroyPointSprites(obj.vi) - local ovi=(obj.vi==1 and 2 or 1) + local ovi = (obj.vi == 1 and 2 or 1) - local nv=cache.force_entity(e,obj.cls,obj.entkey,obj.pth,ovi) + local nv = cache.force_entity(e, obj.cls, obj.entkey, obj.pth, ovi) --cache.destroy_entity(obj,true) --gv:DestroyPointTeleporter(obj.vi) - gv[nv.pth][ovi].ent=e - e.energy=0 - - local gvoe=gv[nv.pth][obj.vi].ent - local gvoc=cache.get_entity(gvoe) - if(gvoc)then gvoc.teleport_dest=e nv.teleport_dest=gvoe end + gv[nv.pth][ovi].ent = e + e.energy = 0 + + local gvoe = gv[nv.pth][obj.vi].ent + local gvoc = cache.get_entity(gvoe) + if (gvoc) then + gvoc.teleport_dest = e + nv.teleport_dest = gvoe + end --gv:CheckTeleporterPairs() end end - -local tppadWestCache={} -function tppadWestCache.built(e,ev) - local f=e.surface if(f~=warptorio.GetMainSurface())then return end - local pos=e.position +local tppadWestCache = {} +function tppadWestCache.built(e, ev) + local f = e.surface + if (f ~= warptorio.GetMainSurface()) then return end + local pos = e.position entity.destroy(e) - local hv=global.Harvesters["west"] if(hv)then hv:Deploy(f,pos) end + local hv = storage.Harvesters["west"] + if (hv) then hv:Deploy(f, pos) end end -local tppadEastCache={} -function tppadEastCache.built(e,ev) - local f=e.surface if(f~=warptorio.GetMainSurface())then return end - local pos=e.position + +local tppadEastCache = {} +function tppadEastCache.built(e, ev) + local f = e.surface + if (f ~= warptorio.GetMainSurface()) then return end + local pos = e.position entity.destroy(e) - local hv=global.Harvesters["east"] if(hv)then hv:Deploy(f,pos) end + local hv = storage.Harvesters["east"] + if (hv) then hv:Deploy(f, pos) end end - -for k,v in pairs{"warptorio-harvestportal","warptorio-harvestpad-west","warptorio-harvestpad-east"}do - for i=0,8,1 do cache.ent(v.."-"..i,tpharvCache) end +for k, v in pairs { "warptorio-harvestportal", "warptorio-harvestpad-west", "warptorio-harvestpad-east" } do + for i = 0, 8, 1 do cache.ent(v .. "-" .. i, tpharvCache) end end -for i=0,8,1 do cache.ent("warptorio-harvestpad-west-"..i,tppadWestCache) end -for i=0,8,1 do cache.ent("warptorio-harvestpad-east-"..i,tppadEastCache) end +for i = 0, 8, 1 do cache.ent("warptorio-harvestpad-west-" .. i, tppadWestCache) end +for i = 0, 8, 1 do cache.ent("warptorio-harvestpad-east-" .. i, tppadEastCache) end -cache.ent("warptorio-teleporter",tpCache) -cache.ent("warptorio-teleporter-gate",tpgateCache) -cache.ent("warptorio-underground",tpCache) -for i=0,8,1 do - cache.ent("warptorio-teleporter-gate-"..i,tpgateCache) - cache.ent("warptorio-teleporter-"..i,tpCache) - cache.ent("warptorio-underground-"..i,tpCache) +cache.ent("warptorio-teleporter", tpCache) +cache.ent("warptorio-teleporter-gate", tpgateCache) +cache.ent("warptorio-underground", tpCache) +for i = 0, 8, 1 do + cache.ent("warptorio-teleporter-gate-" .. i, tpgateCache) + cache.ent("warptorio-teleporter-" .. i, tpCache) + cache.ent("warptorio-underground-" .. i, tpCache) end -local loaderCache={} -function loaderCache.raise(obj,cls,entkey,pth,vi,vid) - obj.cls=cls - obj.entkey=entkey - obj.pth=pth - obj.vi=vi - obj.vid=vid +local loaderCache = {} +function loaderCache.raise(obj, cls, entkey, pth, vi, vid) + obj.cls = cls + obj.entkey = entkey + obj.pth = pth + obj.vi = vi + obj.vid = vid end + function loaderCache.unraise(obj) - local gv=global[obj.cls][obj.entkey] + local gv = storage[obj.cls][obj.entkey] --gv[obj.pth][obj.vi][obj.vid]=nil end -function loaderCache.clone(e,ev) - local obj=cache.get_entity(ev.source) - if(obj)then - local gv=global[obj.cls][obj.entkey] - local nv=cache.force_entity(e,obj.cls,obj.entkey,obj.pth,obj.vi,obj.vid) - cache.destroy_entity(obj,true) - gv[nv.pth][nv.vi][nv.vid]=e + +function loaderCache.clone(e, ev) + local obj = cache.get_entity(ev.source) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + local nv = cache.force_entity(e, obj.cls, obj.entkey, obj.pth, obj.vi, obj.vid) + cache.destroy_entity(obj, true) + gv[nv.pth][nv.vi][nv.vid] = e end end -function loaderCache.destroy(e,ev) - local obj=cache.get_entity(e) - if(obj)then cache.destroy(obj) end + +function loaderCache.destroy(e, ev) + local obj = cache.get_entity(e) + if (obj) then cache.destroy(obj) end end -function loaderCache.rotate(e,ev) - local obj=cache.get_entity(e) - if(obj)then - local gv=global[obj.cls][obj.entkey] - if(obj.cls=="Rails")then - gv.dir=e.loader_type + +function loaderCache.rotate(e, ev) + local obj = cache.get_entity(e) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + if (obj.cls == "Rails") then + gv.dir = e.loader_type gv:Rotate() else - gv.dir[obj.vi][obj.vid]=e.loader_type - gv.dir[(obj.vi==1 and 2 or 1)][obj.vid]=string.opposite_loader[e.loader_type] - local de=gv.loaders[(obj.vi==1 and 2 or 1)][obj.vid] - if(isvalid(de))then de.loader_type=string.opposite_loader[e.loader_type] end - if(gv.chests)then gv:SwapLoaderChests(obj.vid) end + gv.dir[obj.vi][obj.vid] = e.loader_type + gv.dir[(obj.vi == 1 and 2 or 1)][obj.vid] = string.opposite_loader[e.loader_type] + local de = gv.loaders[(obj.vi == 1 and 2 or 1)][obj.vid] + if (isvalid(de)) then de.loader_type = string.opposite_loader[e.loader_type] end + if (gv.chests) then gv:SwapLoaderChests(obj.vid) end end end end -cache.ent("loader",loaderCache) -cache.ent("fast-loader",loaderCache) -cache.ent("express-loader",loaderCache) + +cache.ent("loader", loaderCache) +cache.ent("fast-loader", loaderCache) +cache.ent("express-loader", loaderCache) -local pipeCache={} -function pipeCache.raise(obj,cls,key,pth,vi,vid) - obj.cls=cls - obj.entkey=key - obj.pth=pth - obj.vi=vi - obj.vid=vid +local pipeCache = {} +function pipeCache.raise(obj, cls, key, pth, vi, vid) + obj.cls = cls + obj.entkey = key + obj.pth = pth + obj.vi = vi + obj.vid = vid end + function pipeCache.unraise(obj) - local gv=global[obj.cls][obj.entkey] + local gv = storage[obj.cls][obj.entkey] --gv[obj.pth][vi][vid]=nil end -function pipeCache.clone(e,ev) - local obj=cache.get_entity(ev.source) - if(obj)then - local gv=global[obj.cls][obj.entkey] - local nv=cache.force_entity(e,obj.cls,obj.entkey,obj.pth,obj.vi,obj.vid) - cache.destroy_entity(obj,true) - gv[nv.pth][nv.vi][nv.vid]=e + +function pipeCache.clone(e, ev) + local obj = cache.get_entity(ev.source) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + local nv = cache.force_entity(e, obj.cls, obj.entkey, obj.pth, obj.vi, obj.vid) + cache.destroy_entity(obj, true) + gv[nv.pth][nv.vi][nv.vid] = e end end -function pipeCache.destroy(e,ev) - local obj=cache.get_entity(e) - if(obj)then cache.destroy(obj) end + +function pipeCache.destroy(e, ev) + local obj = cache.get_entity(e) + if (obj) then cache.destroy(obj) end end -cache.ent("warptorio-logistics-pipe",pipeCache) +cache.ent("warptorio-logistics-pipe", pipeCache) -local gpipeCache={} -- Global pipe cache to clean warppipes +local gpipeCache = {} -- Global pipe cache to clean warppipes -function gpipeCache.destroy(e,ev) - for k,v in pairs(global.Teleporters)do v:CheckEmptyPipes() end +function gpipeCache.destroy(e, ev) + for k, v in pairs(storage.Teleporters) do v:CheckEmptyPipes() end end -cache.type("pipe",gpipeCache) -cache.type("pipe-to-ground",gpipeCache) + +cache.type("pipe", gpipeCache) +cache.type("pipe-to-ground", gpipeCache) -local chestCache={} -function chestCache.raise(obj,cls,key,pth,vi,vid) - obj.cls=cls - obj.entkey=key - obj.pth=pth - obj.vi=vi - obj.vid=vid +local chestCache = {} +function chestCache.raise(obj, cls, key, pth, vi, vid) + obj.cls = cls + obj.entkey = key + obj.pth = pth + obj.vi = vi + obj.vid = vid end + function chestCache.unraise(obj) - --local gv=global[obj.cls][obj.entkey] + --local gv=storage[obj.cls][obj.entkey] --gv[obj.pth][vi][vid]=nil end -function chestCache.clone(e,ev) - local obj=cache.get_type("types",ev.source.type,ev.source) - if(obj)then - local gv=global[obj.cls][obj.entkey] - local nv=cache.get_raise_type("types",e.type,e,obj.cls,obj.entkey,obj.pth,obj.vi,obj.vid) - gv[nv.pth][nv.vi][nv.vid]=e + +function chestCache.clone(e, ev) + local obj = cache.get_type("types", ev.source.type, ev.source) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + local nv = cache.get_raise_type("types", e.type, e, obj.cls, obj.entkey, obj.pth, obj.vi, obj.vid) + gv[nv.pth][nv.vi][nv.vid] = e --cache.destroy(obj,true) end end -function chestCache.destroy(e,ev) - local obj=cache.get_entity(e) - if(obj)then cache.destroy(obj) end +function chestCache.destroy(e, ev) + local obj = cache.get_entity(e) + if (obj) then cache.destroy(obj) end end -cache.type("container",chestCache) -cache.type("logistic-container",chestCache) +cache.type("container", chestCache) +cache.type("logistic-container", chestCache) -local comboCache={} -function comboCache.raise(obj,cls,key,pth,vi) - obj.cls=cls - obj.entkey=key - obj.pth=pth - obj.vi=vi +local comboCache = {} +function comboCache.raise(obj, cls, key, pth, vi) + obj.cls = cls + obj.entkey = key + obj.pth = pth + obj.vi = vi end + function comboCache.unraise(obj) - local gv=global[obj.cls][obj.entkey] + local gv = storage[obj.cls][obj.entkey] --gv[obj.pth][vi][vid]=nil end -function comboCache.clone(e,ev) - local obj=cache.get_entity(ev.source) - if(obj)then - local gv=global[obj.cls][obj.entkey] - local nv=cache.force_entity(e,obj.cls,obj.entkey,obj.pth,obj.vi) - cache.destroy_entity(obj,true) - gv[nv.pth][nv.vi]=e + +function comboCache.clone(e, ev) + local obj = cache.get_entity(ev.source) + if (obj) then + local gv = storage[obj.cls][obj.entkey] + local nv = cache.force_entity(e, obj.cls, obj.entkey, obj.pth, obj.vi) + cache.destroy_entity(obj, true) + gv[nv.pth][nv.vi] = e end end -function comboCache.destroy(e,ev) - local obj=cache.get_entity(e) - if(obj)then - local gv=global[obj.cls][obj.entkey] + +function comboCache.destroy(e, ev) + local obj = cache.get_entity(e) + if (obj) then + local gv = storage[obj.cls][obj.entkey] --gv[obj.vi][obj.vid]=nil cache.destroy_entity(obj) end end -cache.ent("warptorio-alt-combinator",comboCache) +cache.ent("warptorio-alt-combinator", comboCache) -- string.opposite_loader[e.loader_type] -local warploader={} +local warploader = {} function warploader.dofilters(e) - local tp=e.loader_type - local lanes={e.get_transport_line(1),e.get_transport_line(2)} - for k,v in pairs(global.warploaders.outputf)do for i=1,2,1 do table.RemoveByValue(v,lanes[i]) end end - if(tp~="output")then --if(tp=="input")then - for i=1,2,1 do table.RemoveByValue(global.warploaders.output,lanes[i]) end - for i=1,2,1 do table.insertExclusive(global.warploaders.input,lanes[i]) end + local tp = e.loader_type + local lanes = { e.get_transport_line(1), e.get_transport_line(2) } + for k, v in pairs(storage.warploaders.outputf) do for i = 1, 2, 1 do table.RemoveByValue(v, lanes[i]) end end + if (tp ~= "output") then --if(tp=="input")then + for i = 1, 2, 1 do table.RemoveByValue(storage.warploaders.output, lanes[i]) end + for i = 1, 2, 1 do table.insertExclusive(storage.warploaders.input, lanes[i]) end else --if(tp=="output")then - local ct=global.warploaders.outputf - local hf=false - for i=1,5,1 do local f=e.get_filter(i) if(f)then hf=true - ct[f]=ct[f] or {} for a=1,2,1 do table.insertExclusive(ct[f],lanes[a]) end - end end - if(hf)then - for i=1,2,1 do table.RemoveByValue(global.warploaders.output,lanes[i]) end + local ct = storage.warploaders.outputf + local hf = false + for i = 1, 5, 1 do + local f = e.get_filter(i) + if (f) then + hf = true + ct[f] = ct[f] or {} + for a = 1, 2, 1 do table.insertExclusive(ct[f], lanes[a]) end + end + end + if (hf) then + for i = 1, 2, 1 do table.RemoveByValue(storage.warploaders.output, lanes[i]) end else - for a=1,2,1 do table.insertExclusive(global.warploaders.output,lanes[a]) end + for a = 1, 2, 1 do table.insertExclusive(storage.warploaders.output, lanes[a]) end end - for a=1,2,1 do table.RemoveByValue(global.warploaders.input,lanes[a]) end + for a = 1, 2, 1 do table.RemoveByValue(storage.warploaders.input, lanes[a]) end end end -function warploader.built(e,ev) - global.warploaders=global.warploaders or {} - global.warploaders.input=global.warploaders.input or {} - global.warploaders.output=global.warploaders.output or {} - global.warploaders.outputf=global.warploaders.outputf or {} - global.warploaders.outputf_next=global.warploaders.outputf_next or {} + +function warploader.built(e, ev) + storage.warploaders = storage.warploaders or {} + storage.warploaders.input = storage.warploaders.input or {} + storage.warploaders.output = storage.warploaders.output or {} + storage.warploaders.outputf = storage.warploaders.outputf or {} + storage.warploaders.outputf_next = storage.warploaders.outputf_next or {} warploader.dofilters(e) end -function warploader.rotate(e,ev) + +function warploader.rotate(e, ev) warploader.dofilters(e) end -function warploader.destroy(e,ev) - local obj=cache.get_entity(e) if(obj)then cache.destroy(obj) end - local un=e.unit_number - local tp=e.loader_type - local wpg=global.warploaders - local lanes={e.get_transport_line(1),e.get_transport_line(2)} - if(tp=="output")then - local hf=false for i=1,5,1 do if(e.get_filter(i))then hf=true break end end - if(hf)then for k,v in pairs(wpg.outputf)do for i=1,2,1 do table.RemoveByValue(v,lanes[i]) end end else - for i=1,2,1 do table.RemoveByValue(wpg.output,lanes[i]) end +function warploader.destroy(e, ev) + local obj = cache.get_entity(e) + if (obj) then cache.destroy(obj) end + local un = e.unit_number + local tp = e.loader_type + local wpg = storage.warploaders + local lanes = { e.get_transport_line(1), e.get_transport_line(2) } + if (tp == "output") then + local hf = false + for i = 1, 5, 1 do + if (e.get_filter(i)) then + hf = true + break + end + end + if (hf) then + for k, v in pairs(wpg.outputf) do for i = 1, 2, 1 do table.RemoveByValue(v, lanes[i]) end end + else + for i = 1, 2, 1 do table.RemoveByValue(wpg.output, lanes[i]) end end else - for i=1,2,1 do table.RemoveByValue(wpg.input,lanes[i]) end + for i = 1, 2, 1 do table.RemoveByValue(wpg.input, lanes[i]) end end end + function warploader.settings_pasted(e) warploader.dofilters(e) end + function warploader.gui_closed(e) warploader.dofilters(e) end -cache.ent("warptorio-warploader",warploader) +cache.ent("warptorio-warploader", warploader) +function warptorio.InsertWarpLane(cv, item_name) + if (cv.can_insert_at_back()) then + cv.insert_at_back({ name = item_name, count = 1 }) + return true + end + return false +end -function warptorio.InsertWarpLane(cv,item_name) if(cv.can_insert_at_back())then cv.insert_at_back({name=item_name,count=1}) return true end return false end -function warptorio.NextWarploader(tbl,key) local k,v=next(tbl,key) if(not k and not v)then return next(tbl,nil) end return k,v end +function warptorio.NextWarploader(tbl, key) + local k, v = next(tbl, key) + if (not k and not v) then + return next(tbl, nil) + end + return k, v +end -function warptorio.DistributeLoaderLine(line) local inv=line.get_contents() - for item_name,item_count in pairs(inv)do if(warptorio.OutputWarpLoader(item_name,item_count))then line.remove_item{name=item_name,count=1} return true end end +function warptorio.DistributeLoaderLine(line) + local inv = line.get_contents() + for item_name, item_count in pairs(inv) do + if (warptorio.OutputWarpLoader(item_count.name, item_count.count)) then + line.remove_item { name = item_count.name, count = 1 } + return true + end + end end -function warptorio.OutputWarpLoader(cv,c) - local wpg=global.warploaders - local ins=false - if(wpg.outputf[cv])then - local wpfnext=wpg.outputf_next[cv] - local coutf=wpg.outputf[cv] - for k,v in pairs(coutf)do local rk,rv=warptorio.NextWarploader(coutf,wpfnext) wpfnext=rk if(rv and warptorio.InsertWarpLane(rv,cv))then ins=true break end end - wpg.outputf_next[cv]=wpfnext - if(ins)then return true end +function warptorio.OutputWarpLoader(cv, c) + local wpg = storage.warploaders + + local ins = false + if (wpg.outputf[cv]) then + local wpfnext = wpg.outputf_next[cv] + local coutf = wpg.outputf[cv] + for k, v in pairs(coutf) do + local rk, rv = warptorio.NextWarploader(coutf, wpfnext) + wpfnext = rk + if (rv and warptorio.InsertWarpLane(rv, cv)) then + ins = true + break + end + end + wpg.outputf_next[cv] = wpfnext + if (ins) then return true end + end + local wpnext = wpg.output_next + local cout = wpg.output + for k, v in pairs(cout) do + local rk, rv = warptorio.NextWarploader(cout, wpnext) + wpnext = rk + if (rv and warptorio.InsertWarpLane(rv, cv)) then + ins = true + break + end end - local wpnext=wpg.output_next - local cout=wpg.output - for k,v in pairs(cout)do local rk,rv=warptorio.NextWarploader(cout,wpnext) wpnext=rk if(rv and warptorio.InsertWarpLane(rv,cv))then ins=true break end end - wpg.output_next=wpnext - if(ins)then return true end + wpg.output_next = wpnext + if (ins) then return true end return false end function warptorio.TickWarploaders() - local wpg=global.warploaders if(not wpg)then return end - local k,line=warptorio.NextWarploader(wpg.input,wpg.input_next) - wpg.input_next=k - if(not isvalid(line))then return end + local wpg = storage.warploaders + if (not wpg) then return end + local k, line = warptorio.NextWarploader(wpg.input, wpg.input_next) + wpg.input_next = k + if (not isvalid(line)) then return end warptorio.DistributeLoaderLine(line) end function warptorio.TickLogistics() - for nm,tpt in pairs(global.Teleporters)do - if(tpt.pipes)then if(type(tpt.pipes)=="boolean")then error(serpent.block(tpt)) end for vi,ve in pairs(tpt.pipes[1])do if(isvalid(ve))then - local vo=tpt.pipes[2][vi] - if(isvalid(vo))then entity.BalanceFluidPair(ve,vo) end - end end end - if(tpt.chests)then for vi,ve in pairs(tpt.chests[1])do if(isvalid(ve))then - local vo=tpt.chests[2][vi] - if(isvalid(vo))then - local vdir=tpt.dir[1][vi] - if(vdir=="input")then entity.ShiftContainer(ve,vo) else entity.ShiftContainer(vo,ve) end + for nm, tpt in pairs(storage.Teleporters) do + if (tpt.pipes) then + if (type(tpt.pipes) == "boolean") then error(serpent.block(tpt)) end + for vi, ve in pairs(tpt.pipes[1]) do + if (isvalid(ve)) then + local vo = tpt.pipes[2][vi] + if (isvalid(vo)) then entity.BalanceFluidPair(ve, vo) end + end end - end end end - end - for nm,tpt in pairs(global.Harvesters)do - for vi,ve in pairs(tpt.pipes[1])do if(isvalid(ve))then - local vo=tpt.pipes[2][vi] - if(isvalid(vo))then entity.BalanceFluidPair(ve,vo) end - end end - for vi,ve in pairs(tpt.loaders[1])do if(isvalid(ve))then - local vo=tpt.loaders[2][vi] - if(isvalid(vo))then - local vdir=tpt.dir[1][vi] - if(vdir=="input")then entity.ShiftBelt(ve,vo) else entity.ShiftBelt(vo,ve) end + end + if (tpt.chests) then + for vi, ve in pairs(tpt.chests[1]) do + if (isvalid(ve)) then + local vo = tpt.chests[2][vi] + if (isvalid(vo)) then + local vdir = tpt.dir[1][vi] + if (vdir == "input") then entity.ShiftContainer(ve, vo) else entity.ShiftContainer(vo, ve) end + end + end end - end end + end + end + for nm, tpt in pairs(storage.Harvesters) do + for vi, ve in pairs(tpt.pipes[1]) do + if (isvalid(ve)) then + local vo = tpt.pipes[2][vi] + if (isvalid(vo)) then entity.BalanceFluidPair(ve, vo) end + end + end + for vi, ve in pairs(tpt.loaders[1]) do + if (isvalid(ve)) then + local vo = tpt.loaders[2][vi] + if (isvalid(vo)) then + local vdir = tpt.dir[1][vi] + if (vdir == "input") then entity.ShiftBelt(ve, vo) else entity.ShiftBelt(vo, ve) end + end + end + end end entity.AutoBalancePower(cache.get("power")) entity.AutoBalanceHeat(cache.get("heat")) - if(global.warploaders)then for i=1,math.min(table_size(global.warploaders.input),10),1 do warptorio.TickWarploaders() end end + if (storage.warploaders) then + for i = 1, math.min(table_size(storage.warploaders.input), 10), 1 do + warptorio + .TickWarploaders() + end + end end -events.on_tick(1,0,"TickLogs",warptorio.TickLogistics) +events.on_tick(1, 0, "TickLogs", warptorio.TickLogistics) diff --git a/control_main_remotes.lua b/control_main_remotes.lua index 6475e8f..60cbe68 100644 --- a/control_main_remotes.lua +++ b/control_main_remotes.lua @@ -13,13 +13,13 @@ warptorio.remote.GetMainPlanet=warptorio.GetMainPlanet -- call (), returns plane warptorio.remote.GetHomeSurface=warptorio.GetHomeSurface -- call (), returns LuaSurface, warptorio.remote.GetHomePlanet=warptorio.GetHomePlanet -- call (), returns planet_table. Same as doing remote.call("planetorio","GetPlanetBySurface",remote.call("warptorio","GetHomeSurface")) warptorio.remote.GetSurfaces=warptorio.GetAllSurfaces -- call (), returns {table_of_warptorio_surfaces}. This does not include surfaces that are marked for destroy, such as player being left behind on warp. -warptorio.remote.GetSurface=function(key) return (global.floor[key] and global.floor[key].host or nil) end -warptorio.remote.GetFloor=function(key) return global.floor[key] end -warptorio.remote.GetFloors=function() return global.floor end +warptorio.remote.GetSurface=function(key) return (storage.floor[key] and storage.floor[key].host or nil) end +warptorio.remote.GetFloor=function(key) return storage.floor[key] end +warptorio.remote.GetFloors=function() return storage.floor end warptorio.remote.GetNamedSurfaces=warptorio.GetNamedSurfaces -- call ({table_of_floor_names, e.g. "home","main","factory"}), returns {[name]=surface,...}. Used to get surfaces in bulk. -warptorio.remote.RecallTeleporterGate=function() local t=global.Teleporters.offworld if(t and isvalid(t.b))then t:DestroyLogsB() t:DestroyB() end end -- call(). Used to destroy the teleporter gate. -warptorio.remote.RecallHarvester=function(side,bply) if(global.Harvesters[side])then global.Harvesters[side]:Recall(bply) end end -- call(string_side,bool_recallplayers). side must be "east" or "west". future values may include "nw","ne","sw","se" if i ever add those. +warptorio.remote.RecallTeleporterGate=function() local t=storage.Teleporters.offworld if(t and isvalid(t.b))then t:DestroyLogsB() t:DestroyB() end end -- call(). Used to destroy the teleporter gate. +warptorio.remote.RecallHarvester=function(side,bply) if(storage.Harvesters[side])then storage.Harvesters[side]:Recall(bply) end end -- call(string_side,bool_recallplayers). side must be "east" or "west". future values may include "nw","ne","sw","se" if i ever add those. --------------------------------------------------------------------- @@ -34,33 +34,33 @@ warptorio.remote.is_warp_blacklisted=warptorio.cmdiscloneblacklisted -- call (mo warptorio.remote.GetWarpBlacklist=warptorio.GetWarpBlacklist -- call (), returns: {warptorio_warp_blacklist}. Returns the full table of all blacklisted entities. -function warptorio.cmdinsertcloneblacklist(mn,e) if(not global.warp_blacklist[mn])then global.warp_blacklist[mn]={} end table.insertExclusive(global.warp_blacklist[mn],e) end -function warptorio.cmdremovecloneblacklist(mn,e) if(not global.warp_blacklist[mn])then global.warp_blacklist[mn]={} end table.RemoveByValue(global.warp_blacklist[mn],e) end -function warptorio.cmdiscloneblacklisted(mn,e) if(not global.warp_blacklist[mn])then return false end return table.HasValue(global.warp_blacklist[mn],e) end +function warptorio.cmdinsertcloneblacklist(mn,e) if(not storage.warp_blacklist[mn])then storage.warp_blacklist[mn]={} end table.insertExclusive(storage.warp_blacklist[mn],e) end +function warptorio.cmdremovecloneblacklist(mn,e) if(not storage.warp_blacklist[mn])then storage.warp_blacklist[mn]={} end table.RemoveByValue(storage.warp_blacklist[mn],e) end +function warptorio.cmdiscloneblacklisted(mn,e) if(not storage.warp_blacklist[mn])then return false end return table.HasValue(storage.warp_blacklist[mn],e) end ]] -function warptorio.ValidateRemoteTable(x) local mt=global.modtbl if(not mt[x])then mt[x]={} end - for k,v in pairs(mt[x])do if(not game.active_mods[k])then mt[x][k]=nil end end +function warptorio.ValidateRemoteTable(x) local mt=storage.modtbl if(not mt[x])then mt[x]={} end + for k,v in pairs(mt[x])do if(not script.active_mods[k])then mt[x][k]=nil end end end -function warptorio.InsertModTable(x,y,z) if(y=="warptorio2")then return end local mt=global.modtbl if(not mt[x])then return false end mt[x][y]=mt[x][y] or {} +function warptorio.InsertModTable(x,y,z) if(y=="warptorio2")then return end local mt=storage.modtbl if(not mt[x])then return false end mt[x][y]=mt[x][y] or {} return table.insertExclusive(mt[x][y],z) end -function warptorio.RemoveModTable(x,y,z) if(y=="warptorio2")then return end local mt=global.modtbl if(not mt[x])then return false end mt[x][y]=mt[x][y] or {} +function warptorio.RemoveModTable(x,y,z) if(y=="warptorio2")then return end local mt=storage.modtbl if(not mt[x])then return false end mt[x][y]=mt[x][y] or {} return table.RemoveByValue(mt[x][y],z) end warptorio.ModTables={} function warptorio.GetModTable(x) if(warptorio.ModTables[x])then return warptorio.ModTables[x] end - local mt=global.modtbl if(not mt[x])then return true end + local mt=storage.modtbl if(not mt[x])then return true end local t={} for k,v in pairs(mt[x])do for y,z in pairs(v)do table.insertExclusive(t,z) end end warptorio.ModTables[x]=t return t end events.on_config(function() - global.modtbl=global.modtbl or {} + storage.modtbl=storage.modtbl or {} warptorio.ValidateRemoteTable("harvester_blacklist") -- prevents certain entities from being affected by harvester deploy/recall cloning. warptorio.ValidateRemoteTable("warp_blacklist") -- prevents certain entities from being affected by the big Warpout function / cloning. end) @@ -75,7 +75,7 @@ warptorio.remote.RemoveModTable=warptorio.RemoveModTable -- call ("table_name", warptorio.remote.ResearchNauvis=function() for k,v in pairs(game.forces.player.technologies)do if(not v.name:match("warptorio"))then v.researched=true end end end warptorio.remote.ResearchCheat=function() for k,v in pairs(game.forces.player.research_queue)do v.researched=true end end warptorio.remote.cheat=function() for i,p in pairs(game.players)do for k,v in pairs(lootItems)do p.get_main_inventory().insert{name=k,count=v} end end end -- call (), returns: Nil. Gives all players all the items in the lootchest table. Useful for testing. -warptorio.remote.reveal=function(n) n=n or 10 local f=global.floor.main.host game.forces.player.chart(f,{lefttop={x=-64-128*n,y=-64-128*n},rightbottom={x=64+128*n,y=64+128*n}}) end -- call (reveal_scale), returns: nil. Cheat command to reveal the map +warptorio.remote.reveal=function(n) n=n or 10 local f=storage.floor.main.host game.forces.player.chart(f,{lefttop={x=-64-128*n,y=-64-128*n},rightbottom={x=64+128*n,y=64+128*n}}) end -- call (reveal_scale), returns: nil. Cheat command to reveal the map --------------------------------------------------------------------- @@ -98,13 +98,13 @@ warptorio.remote.PlanetEntityIsPlatform=warptorio.PlanetEntityIsPlatform -- call warptorio.remote.EntityIsPlatform=warptorio.EntityIsPlatform -- call (entity), returns true. Same as PlanetEntityIsPlatform, except checks all teleporters on all surfaces and stuff. warptorio.remote.BlueprintEntityIsBlacklisted=warptorio.BlueprintEntityIsBlacklisted -- call (entity), returns true/false whether the entity should not be added to blueprints. Currently identical to remote.call("warptorio","EntityIsPlatform",entity), but is not an alias. -warptorio.remote.ResetPlatform=function() warptorio.BuildB1() warptorio.BuildB2() for k,v in pairs(global.Teleporters)do v:Warpin() end end -- Rebuild the platform?? +warptorio.remote.ResetPlatform=function() warptorio.BuildB1() warptorio.BuildB2() for k,v in pairs(storage.Teleporters)do v:Warpin() end end -- Rebuild the platform?? --------------------------------------------------------------------- --[[ Warping related stuff ]]-- -warptorio.remote.GetWarpzone=function() return global.warpzone end -- Returns the current warpzone +warptorio.remote.GetWarpzone=function() return storage.warpzone end -- Returns the current warpzone warptorio.remote.IsAutowarpEnabled=warptorio.IsAutowarpEnabled -- call (), returns: boolean_IsAutowarpEnabled. Does exactly what it says on the tin. If true, the autowarp timer is running. warptorio.remote.Warpout=warptorio.Warpout -- call (*optional planet_name), returns: nil. The big warp function. Increments the warpzone and other stuff. warptorio.remote.warp=warptorio.Warpout -- alias @@ -113,8 +113,8 @@ warptorio.remote.StartWarp=warptorio.StartWarp -- call() Forcibly start the warp warptorio.remote.StopWarp=warptorio.StopWarp -- call() Forcibly stop the warping countdown warptorio.remote.IsWarping=warptorio.IsWarping -- call(), returns bool_IsWarping. -function warptorio.remote.GetWarpTime() return (global.warp_charging>0 and global.warp_time_left/60 or global.warp_charge_time) end -function warptorio.remote.SetWarpTime(n) global.warp_charge_time=n end +function warptorio.remote.GetWarpTime() return (storage.warp_charging>0 and storage.warp_time_left/60 or storage.warp_charge_time) end +function warptorio.remote.SetWarpTime(n) storage.warp_charge_time=n end --[[ todo? function warptorio.remote.GetAutowarpTimeLeft() end diff --git a/control_platform_classic.lua b/control_platform_classic.lua index f158395..ea5e863 100644 --- a/control_platform_classic.lua +++ b/control_platform_classic.lua @@ -884,7 +884,7 @@ cache.surface("platform_boiler",{ --[[ General Platform Stuff ]]-- -function platform.PositionInPlatform(f,pos) local gf=global.floor +function platform.PositionInPlatform(f,pos) local gf=storage.floor if(f==gf.factory.surface)then return true elseif(f==gf.boiler.surface)then return true elseif(f==gf.harvester.surface)then return true @@ -895,7 +895,7 @@ end function platform.GetWarpables(c,cf) -- warptorio.IsWarping=true - --local m=global.floor.main + --local m=storage.floor.main --local c=m.host local mt=platform.floors.main.get_sizes() diff --git a/data-updates.lua b/data-updates.lua index db12ae3..2fd749e 100644 --- a/data-updates.lua +++ b/data-updates.lua @@ -1,93 +1,93 @@ ---[[ - -Add research for mod loaders - -]] - - - ---[[ - -Add emissions to all entities - -]] - -local reqpth="prototypes-updates/" -require(reqpth.."data_accumulators") -- include accumulator data AFTER factorioextended ruins the data.raw.accumulator tables, so that it doesn't break our mcnuggets. -require(reqpth.."data_warptorio-harvester") -- include accumulator data AFTER factorioextended ruins the data.raw.accumulator tables, so that it doesn't break our mcnuggets. - - -local entTbl={ -"accumulator", -"ammo-turret", -"arithmetic-combinator", -"artillery-turret", ---"artillery-wagon", -"assembling-machine", -"beacon", -"boiler", ---"car", ---"cargo-wagon", ---"character", -"constant-combinator", -"container", -"decider-combinator", ---"electric-energy-interface", -"electric-turret", -"fluid-turret", ---"fluid-wagon", -"furnace", -"gate", -"generator", -"heat-pipe", -"inserter", -"lab", -"loader", ---"locomotive", -"logistic-container", -"logistic-robot", -"mining-drill", ---"pipe", ---"pipe-to-ground", -"power-switch", -"programmable-speaker", ---"pump", -"radar", -"reactor", -"roboport", -"rocket-silo", ---"simple-entity", ---"simple-entity-with-force", ---"simple-entity-with-owner", -"solar-panel", -"splitter", -"storage-tank", ---"train-stop", -"transport-belt", -"underground-belt", -"wall", -} - - -local entIgnore={ -"big-electric-pole", -} - - -local s="" -for u,n in pairs(entTbl)do - for k,v in pairs(data.raw[n])do - if(v.name~="big-electric-pole" and not v.emissions_per_second and not v.emissions_per_tick)then - s=s .. "Added: " .. v.name - v.emissions_per_second=0.000005 - if(not v.energy_source)then v.energy_source={type="void",drain="100kW"} end - if(v.energy_source and (not v.energy_source.emissions_per_minute or v.energy_source.emissions_per_minute==0))then - s = s .. " & emissions" - v.energy_source.emissions_per_minute=0.0005 - end - s=s .. "\n" - end - end -end ---error(s) - +--[[ + +Add research for mod loaders + +]] + + + +--[[ + +Add emissions to all entities + +]] + +local reqpth="prototypes-updates/" +require(reqpth.."data_accumulators") -- include accumulator data AFTER factorioextended ruins the data.raw.accumulator tables, so that it doesn't break our mcnuggets. +require(reqpth.."data_warptorio-harvester") -- include accumulator data AFTER factorioextended ruins the data.raw.accumulator tables, so that it doesn't break our mcnuggets. + + +local entTbl={ +"accumulator", +"ammo-turret", +"arithmetic-combinator", +"artillery-turret", +--"artillery-wagon", +"assembling-machine", +"beacon", +"boiler", +--"car", +--"cargo-wagon", +--"character", +"constant-combinator", +"container", +"decider-combinator", +--"electric-energy-interface", +"electric-turret", +"fluid-turret", +--"fluid-wagon", +"furnace", +"gate", +"generator", +"heat-pipe", +"inserter", +"lab", +"loader", +--"locomotive", +"logistic-container", +"logistic-robot", +"mining-drill", +--"pipe", +--"pipe-to-ground", +"power-switch", +"programmable-speaker", +--"pump", +"radar", +"reactor", +"roboport", +"rocket-silo", +--"simple-entity", +--"simple-entity-with-force", +--"simple-entity-with-owner", +"solar-panel", +"splitter", +"storage-tank", +--"train-stop", +"transport-belt", +"underground-belt", +"wall", +} + + +local entIgnore={ +"big-electric-pole", +} + +--[[ +local s="" +for u,n in pairs(entTbl)do + for k,v in pairs(data.raw[n])do + if(v.name~="big-electric-pole" and not v.emissions_per_second and not v.emissions_per_tick)then + s=s .. "Added: " .. v.name + v.emissions_per_second=0.000005 + if(not v.energy_source)then v.energy_source={type="void",drain="100kW"} end + if(v.energy_source and (not v.energy_source.emissions_per_minute or v.energy_source.emissions_per_minute==0))then + s = s .. " & emissions" + v.energy_source.emissions_per_minute=0.0005 + end + s=s .. "\n" + end + end +end +--error(s) +]]-- diff --git a/data.lua b/data.lua index e94781d..41017bb 100644 --- a/data.lua +++ b/data.lua @@ -1,21 +1,21 @@ -require("lib/lib") - -local reqpth="prototypes/" ---require("technology/warp-technology") -require("sound/sound") -require(reqpth.."data_warptorio-heatpipe") -require(reqpth.."data_warptorio-warpport") -require(reqpth.."data_warptorio-logistics-pipe") -require(reqpth.."data_warptorio-warpstation") -require(reqpth.."data_warpnuke") -require(reqpth.."data_warptorio-warploader") -require(reqpth.."data_warptorio-townportal") -require(reqpth.."data_warptorio-combinator") -require(reqpth.."data_warptorio-warpspider") ---require("data_nauvis_preset") ---require("data_accumulators") -- This would be included here if it weren't for factorioextended ruining the accumulator tables >:| - - -require("data_warptorio") - -lib.lua() \ No newline at end of file +require("lib/lib") + +local reqpth = "prototypes/" +--require("technology/warp-technology") +require("sound/sound") +require(reqpth .. "data_warptorio-heatpipe") +require(reqpth .. "data_warptorio-warpport") +require(reqpth .. "data_warptorio-logistics-pipe") +require(reqpth .. "data_warptorio-warpstation") +require(reqpth .. "data_warpnuke") +require(reqpth .. "data_warptorio-warploader") +require(reqpth .. "data_warptorio-townportal") +require(reqpth .. "data_warptorio-combinator") +require(reqpth .. "data_warptorio-warpspider") +--require("data_nauvis_preset") +--require("data_accumulators") -- This would be included here if it weren't for factorioextended ruining the accumulator tables >:| + + +require("data_warptorio") + +lib.lua() diff --git a/data_warptorio.lua b/data_warptorio.lua index 0f531c1..5101acd 100644 --- a/data_warptorio.lua +++ b/data_warptorio.lua @@ -1,33 +1,85 @@ +local function istable(t) return type(t) == "table" end +local function rgb(r, g, b, a) + a = a or 255 + return { r = r / 255, g = g / 255, b = b / 255, a = a / 255 } +end + +function table.deepmerge(s, t) + for k, v in pairs(t) do + if (istable(v) and s[k] and istable(s[k])) then + table.deepmerge( + s[k], v) + else + s[k] = v + end + end +end -local function istable(t) return type(t)=="table" end -local function rgb(r,g,b,a) a=a or 255 return {r=r/255,g=g/255,b=b/255,a=a/255} end +function table.merge(s, t) + local x = {} + for k, v in pairs(s) do x[k] = v end + for k, v in pairs(t) do x[k] = v end + return x +end -function table.deepmerge(s,t) for k,v in pairs(t)do if(istable(v) and s[k] and istable(s[k]))then table.deepmerge(s[k],v) else s[k]=v end end end -function table.merge(s,t) local x={} for k,v in pairs(s)do x[k]=v end for k,v in pairs(t)do x[k]=v end return x end -local function MakeDataCopy(a,b,x) local t=table.deepcopy(data.raw[a][b]) if(x)then table.deepmerge(t,x) end return t end +local function MakeDataCopy(a, b, x) + local t = table.deepcopy(data.raw[a][b]) + if (x) then table.deepmerge(t, x) end + return t +end local function ExtendRecipeItem(t) - local r=table.deepcopy(data.raw.recipe["nuclear-reactor"]) - r.enabled=false r.name=t.name r.ingredients={{"steel-plate",1}} r.result=t.name - local i=table.deepcopy(data.raw.item["nuclear-reactor"]) - i.name=t.name i.place_result=t.name - data:extend{i,r} + local r = table.deepcopy(data.raw.recipe["nuclear-reactor"]) + r.enabled = false + r.name = t.name + r.ingredients = { { type = "item", name = "steel-plate", amount = 1 } } + r.results = { { type = "item", name = t.name, amount = 1 } } + local i = table.deepcopy(data.raw.item["nuclear-reactor"]) + i.name = t.name + i.place_result = t.name + data:extend { i, r } +end +local function ExtendRecipeItemFix(t) t.order = t.order or "warptorio" end +local function ExtendDataCopy(a, b, x, ri, tx) + local t = MakeDataCopy(a, b, x) + if (tx) then for k, v in pairs(tx) do if (v == false) then t[k] = nil else t[k] = v end end end + if (ri) then ExtendRecipeItemFix(t) end + data:extend { t } + return t end -local function ExtendRecipeItemFix(t) t.order=t.order or "warptorio" end -local function ExtendDataCopy(a,b,x,ri,tx) local t=MakeDataCopy(a,b,x) if(tx)then for k,v in pairs(tx)do if(v==false)then t[k]=nil else t[k]=v end end end if(ri)then ExtendRecipeItemFix(t) end data:extend{t} return t end - -local function ExtendCopyRecipe(src,name) - local r=table.deepcopy( data.raw.recipe[src] ) - r.enabled=false r.name=name r.ingredients={{"steel-plate",1}} r.result=name - local i=table.deepcopy( data.raw.recipe[src] ) - i.name=name i.place_result=name - data:extend{i,r} + +local function ExtendCopyRecipe(src, name) + local r = table.deepcopy(data.raw.recipe[src]) + r.enabled = false + r.name = name + r.ingredients = { { type = "item", name = "steel-plate", amount = 1 } } + r.results = { { type = "item", name = name, amount = 1 } } + local i = table.deepcopy(data.raw.recipe[src]) + i.name = name + i.place_result = name + data:extend { i, r } end -local techPacks={red="automation-science-pack",green="logistic-science-pack",blue="chemical-science-pack",black="military-science-pack", - purple="production-science-pack",yellow="utility-science-pack",white="space-science-pack"} +local techPacks = { + red = "automation-science-pack", + green = "logistic-science-pack", + blue = "chemical-science-pack", + black = "military-science-pack", + purple = "production-science-pack", + yellow = "utility-science-pack", + white = "space-science-pack" +} -local function SciencePacks(x) local t={} for k,v in pairs(x)do table.insert(t,{techPacks[k],v}) end return t end -local function ExtendTech(t,d,s) local x=table.merge(t,d) if(s)then x.unit.ingredients=SciencePacks(s) end data:extend{x} return x end +local function SciencePacks(x) + local t = {} + for k, v in pairs(x) do table.insert(t, { techPacks[k], v }) end + return t +end +local function ExtendTech(t, d, s) + local x = table.merge(t, d) + if (s) then x.unit.ingredients = SciencePacks(s) end + data:extend { x } + return x +end --[[ local t=ExtendDataCopy("electric-pole","small-electric-pole",{name="warptorio-electric-pole", @@ -46,50 +98,61 @@ local t=ExtendDataCopy("electric-pole","small-electric-pole",{name="warptorio-el -- data.raw["assembling-machine"]["crash-site-assembling-machine-2-repaired"].minable={mining_time=3,result="crash-site-assembling-machine-2-repaired"} - - - - -- -------- -- Warp Tiles -- purple tiles -local t=ExtendDataCopy("tile","tutorial-grid",{name="warp-tile-concrete",tint={r=0.6,g=0.6,b=0.7,a=1},layer=99,decorative_removal_probability=1,walking_speed_modifier=1.6,map_color={r=0.2,g=0.1,b=0.25,a=1}}) +local t = ExtendDataCopy("tile", "tutorial-grid", + { name = "warp-tile-concrete", tint = { r = 0.6, g = 0.6, b = 0.7, a = 1 }, layer = 99, decorative_removal_probability = 1, walking_speed_modifier = 1.6, map_color = { r = 0.2, g = 0.1, b = 0.25, a = 1 } }) -- orange tiles -local t=ExtendDataCopy("tile","tutorial-grid",{name="warptorio-red-concrete",tint={r=1,g=0.5,b=0,a=0.25},layer=67,decorative_removal_probability=1,walking_speed_modifier=1.5,map_color={r=0.2,g=0.1,b=0,a=1}}) +local t = ExtendDataCopy("tile", "tutorial-grid", + { name = "warptorio-red-concrete", tint = { r = 1, g = 0.5, b = 0, a = 0.25 }, layer = 67, decorative_removal_probability = 1, walking_speed_modifier = 1.5, map_color = { r = 0.2, g = 0.1, b = 0, a = 1 } }) -- -------- -- Invisiradar -local rtint={r=0.4,g=0.4,b=1,a=1} -local rvtint={scale=1/3,shift={0.03125/3,-0.5/3},tint={r=1,g=1,b=1,a=0},hr_version={scale=0.5/3,tint={r=1,g=1,b=1,a=0},shift={0.03125/3,-0.5/3}}} -local r=ExtendDataCopy("radar","radar",{name="warptorio-invisradar", - icons={{icon="__base__/graphics/icons/radar.png",tint=rtint}},integration_patch=rvtint,pictures={layers={rvtint,rvtint}}, -},true,{energy_per_nearby_scan="10kJ",energy_per_sector="200kJ",energy_usage="1kW", icon=false, - max_distance_of_nearby_sector_revealed=5,max_distance_of_sector_revealed=18, - collision_box={{-1.2/3,-1.2/3},{1.2/3,1.2/3}},selection_box={{-1.5/3,-1.5/3},{1.5/3,1.5/3}}, +local rtint = { r = 0.4, g = 0.4, b = 1, a = 1 } +local rvtint = { scale = 0.5 / 3, tint = { r = 1, g = 1, b = 1, a = 0 }, shift = { 0.03125 / 3, -0.5 / 3 } } +local r = ExtendDataCopy("radar", "radar", { + name = "warptorio-invisradar", + icons = { { icon = "__base__/graphics/icons/radar.png", tint = rtint } }, + integration_patch = rvtint, + pictures = { layers = { rvtint, rvtint } }, +}, true, { + energy_source = { type = "void" }, + energy_per_nearby_scan = "10kJ", + energy_per_sector = "200kJ", + energy_usage = "1kW", + icon = false, + max_distance_of_nearby_sector_revealed = 5, + max_distance_of_sector_revealed = 18, + collision_box = { { -1.2 / 3, -1.2 / 3 }, { 1.2 / 3, 1.2 / 3 } }, + selection_box = { { -1.5 / 3, -1.5 / 3 }, { 1.5 / 3, 1.5 / 3 } }, }) -- -------- -- Loot Chest -local rtint={r=0.4,g=0.4,b=1,a=1} -local t=ExtendDataCopy("container","wooden-chest",{name="warptorio-lootchest",inventory_size=8, - icons={{icon="__base__/graphics/icons/wooden-chest.png",tint=rtint}}, - picture={layers={ [1]={tint=rtint,hr_version={tint=rtint}}, }}, -},true,{icon=false,minable={mining_time=0.1}}) +local rtint = { r = 0.4, g = 0.4, b = 1, a = 1 } +local t = ExtendDataCopy("container", "wooden-chest", { + name = "warptorio-lootchest", + inventory_size = 8, + icons = { { icon = "__base__/graphics/icons/wooden-chest.png", tint = rtint } }, + picture = { layers = { [1] = { tint = rtint }, } }, +}, true, { icon = false, minable = { mining_time = 0.1 } }) -- -------- -- Carebear Chest -local rtint=rgb(255,20,147) -local t=ExtendDataCopy("container","wooden-chest",{name="warptorio-carebear-chest",inventory_size=99, - icons={{icon="__base__/graphics/icons/wooden-chest.png",tint=rtint}}, - picture={layers={ [1]={tint=rtint,hr_version={tint=rtint}}, }}, -},true,{icon=false,minable={mining_time=10}}) - +local rtint = rgb(255, 20, 147) +local t = ExtendDataCopy("container", "wooden-chest", { + name = "warptorio-carebear-chest", + inventory_size = 99, + icons = { { icon = "__base__/graphics/icons/wooden-chest.png", tint = rtint } }, + picture = { layers = { [1] = { tint = rtint }, } }, +}, true, { icon = false, minable = { mining_time = 10 } }) -- ---- @@ -110,39 +173,68 @@ local t=ExtendDataCopy("pipe-to-ground","pipe-to-ground",{name="warptorio-logist -- Warp Reactor -- Fuel -data:extend{{type="fuel-category", name="warp"}} - -ExtendDataCopy("item","uranium-fuel-cell",{name="warptorio-warponium-fuel-cell",fuel_category="warp",burnt_result="uranium-fuel-cell",fuel_value="32GJ",stack_size=50, - icon_size=64,icons={ {icon="__base__/graphics/icons/uranium-fuel-cell.png",tint={r=1,g=0.2,b=1,a=0.8}}, }, },false,{icon=false}) - -ExtendDataCopy("recipe","uranium-fuel-cell",{name="warptorio-warponium-fuel-cell",enabled=false,result="warptorio-warponium-fuel-cell",result_count=1},false, - {ingredients={{"uranium-fuel-cell",5}}, - icon_size=64,icons={ {icon="__base__/graphics/icons/uranium-fuel-cell.png",tint={r=1,g=0.2,b=1,a=0.8}}, }, -},false,{icon=false}) - -ExtendDataCopy("item","nuclear-fuel",{name="warptorio-warponium-fuel",fuel_category="chemical", - fuel_acceleration_multiplier=5,fuel_value="7GJ",stack_size=1,fuel_top_speed_multiplier=1.25, - icon_size=64,icons={ {icon="__base__/graphics/icons/nuclear-fuel.png",tint={r=1,g=0.2,b=1,a=0.8}}, }, -},false,{icon=false}) - -ExtendDataCopy("recipe","nuclear-fuel",{name="warptorio-warponium-fuel",enabled=false,result="warptorio-warponium-fuel",result_count=1},false, - {ingredients={{"warptorio-warponium-fuel-cell",1},{"nuclear-fuel",1}}, - icon=false,icon_size=64,icons={ {icon="__base__/graphics/icons/nuclear-fuel.png",tint={r=1,g=0.2,b=1,a=0.8}}, }, -}) +data:extend { { type = "fuel-category", name = "warp" } } + +ExtendDataCopy("item", "uranium-fuel-cell", + { + name = "warptorio-warponium-fuel-cell", + fuel_category = "warp", + burnt_result = "uranium-fuel-cell", + fuel_value = "32GJ", + stack_size = 50, + icon_size = 64, + icons = { { icon = "__base__/graphics/icons/uranium-fuel-cell.png", tint = { r = 1, g = 0.2, b = 1, a = 0.8 } }, }, + }, false, { icon = false }) + +ExtendDataCopy("recipe", "uranium-fuel-cell", + { name = "warptorio-warponium-fuel-cell", enabled = false, results = { { type = "item", name = "warptorio-warponium-fuel-cell", amount = 1 } } }, + false, + { + ingredients = { { type = "item", name = "uranium-fuel-cell", amount = 5 } }, + icon_size = 64, + icons = { { icon = "__base__/graphics/icons/uranium-fuel-cell.png", tint = { r = 1, g = 0.2, b = 1, a = 0.8 } }, }, + }, false, { icon = false }) + +ExtendDataCopy("item", "nuclear-fuel", { + name = "warptorio-warponium-fuel", + fuel_category = "chemical", + fuel_acceleration_multiplier = 5, + fuel_value = "7GJ", + stack_size = 1, + fuel_top_speed_multiplier = 1.25, + icon_size = 64, + icons = { { icon = "__base__/graphics/icons/nuclear-fuel.png", tint = { r = 1, g = 0.2, b = 1, a = 0.8 } }, }, +}, false, { icon = false }) + +ExtendDataCopy("recipe", "nuclear-fuel", + { name = "warptorio-warponium-fuel", enabled = false, results = { { type = "item", name = "warptorio-warponium-fuel", amount = 1 } } }, + false, + { + ingredients = { { type = "item", name = "warptorio-warponium-fuel-cell", amount = 1 }, { type = "item", name = "nuclear-fuel", amount = 1 } }, + icon = false, + icon_size = 64, + icons = { { icon = "__base__/graphics/icons/nuclear-fuel.png", tint = { r = 1, g = 0.2, b = 1, a = 0.8 } }, }, + }) -- The Reactor Itself -local t=ExtendDataCopy("reactor","nuclear-reactor",{name="warptorio-reactor",max_health=5000,neighbour_bonus=12,consumption="160MW", - energy_source={fuel_category="warp"},heat_buffer={specific_heat="1MJ",max_temperature=1000}, light={ intensity=10, size=9.9, shift={0.0,0.0}, color={r=1.0,g=0.0,b=0.0} }, - working_light_picture={ filename="__base__/graphics/entity/nuclear-reactor/reactor-lights-color.png", tint={r=1,g=0.4,b=0.4,a=1}, - hr_version={ filename="__base__/graphics/entity/nuclear-reactor/hr-reactor-lights-color.png", tint={r=1,g=0.4,b=0.4,a=1}, }, - }, - picture={layers={ - [1]={ tint={r=0.8,g=0.8,b=1,a=1}, hr_version={ tint={r=0.8,g=0.8,b=1,a=1}, }, }, - }}, -},true) - - +local t = ExtendDataCopy("reactor", "nuclear-reactor", + { + name = "warptorio-reactor", + max_health = 5000, + neighbour_bonus = 12, + consumption = "160MW", + energy_source = { fuel_categories = { "warp" } }, + heat_buffer = { specific_heat = "1MJ", max_temperature = 1000 }, + light = { intensity = 10, size = 9.9, shift = { 0.0, 0.0 }, color = { r = 1.0, g = 0.0, b = 0.0 } }, + working_light_picture = { filename = "__base__/graphics/entity/nuclear-reactor/reactor-lights-color.png", tint = { r = 1, g = 0.4, b = 0.4, a = 1 }, + }, + picture = { + layers = { + [1] = { tint = { r = 0.8, g = 0.8, b = 1, a = 1 } }, + } + }, + }, true) -- ------------------------------------------------------------------------- @@ -152,146 +244,275 @@ local t=ExtendDataCopy("reactor","nuclear-reactor",{name="warptorio-reactor",max -- ---- -- Warp Roboport -local t={type="technology",upgrade=true,icon_size=128,effects={{recipe="warptorio-warpport",type="unlock-recipe"}},icons={ - {icon="__base__/graphics/entity/roboport/roboport-base.png",tint={r=0.3,g=0.3,b=1,a=1},scale=0.75,priority="low",}, -}, } -ExtendTech(t,{name="warptorio-warpport",unit={count=1000,time=5}, prerequisites={"warptorio-logistics-4","warptorio-reactor-8","space-science-pack"}}, {red=1,green=1,black=1,blue=1,purple=1,yellow=1,white=1}) +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + effects = { { recipe = "warptorio-warpport", type = "unlock-recipe" } }, + icons = { + { icon = "__base__/graphics/entity/roboport/roboport-base.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_size = 220, scale = 0.25 }, + }, +} +ExtendTech(t, + { name = "warptorio-warpport", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-logistics-4", "warptorio-reactor-8", "space-science-pack" } }, + { red = 1, green = 1, black = 1, blue = 1, purple = 1, yellow = 1, white = 1 }) -- ---- -- Warp Nuke -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/atomic-bomb.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-warpnuke",unit={count=1000,time=5},effects={{recipe="warptorio-atomic-bomb",type="unlock-recipe"}}, - prerequisites={"atomic-bomb","warptorio-reactor-8","space-science-pack"}}, {red=1,green=1,black=1,blue=1,purple=1,yellow=1,white=1}) +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/atomic-bomb.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { + name = "warptorio-warpnuke", + unit = { count = 1000, time = 5 }, + effects = { { recipe = "warptorio-atomic-bomb", type = "unlock-recipe" } }, + prerequisites = { "atomic-bomb", "warptorio-reactor-8", "space-science-pack" } + }, { red = 1, green = 1, black = 1, blue = 1, purple = 1, yellow = 1, white = 1 }) -- ---- -- Warp Module -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/module.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-warpmodule",unit={count=3000,time=5}, prerequisites={"warptorio-reactor-8","space-science-pack","effectivity-module-3"}, - effects={{recipe="warptorio-warpmodule",type="unlock-recipe"}},}, {red=1,green=1,black=1,blue=1,purple=1,yellow=1,white=1}) - -data:extend{{type="module-category",name="warpivity"}} -local t={type="module",category="warpivity",name="warptorio-warpmodule",stack_size=50,subgroup="module",tier=4,localised_description={"item-description.warptorio-warpmodule"}, +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/module.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { + name = "warptorio-warpmodule", + unit = { count = 3000, time = 60 }, + prerequisites = { "warptorio-reactor-8", "space-science-pack", "efficiency-module-3" }, + effects = { { recipe = "warptorio-warpmodule", type = "unlock-recipe" } }, + }, { red = 1, green = 1, black = 1, blue = 1, purple = 1, yellow = 1, white = 1 }) + +data:extend { { type = "module-category", name = "warpivity" } } +local t = { + type = "module", + category = "warpivity", + name = "warptorio-warpmodule", + stack_size = 50, + subgroup = "module", + tier = 4, + localised_description = { "item-description.warptorio-warpmodule" }, limitation_message_key = "production-module-usable-only-on-intermediates", - effect={ consumption={bonus=0.6},pollution={bonus=0.05},productivity={bonus=0.1},speed={bonus=0.35} }, - icon_size=64,icons={ {icon="__base__/graphics/icons/speed-module-3.png",tint={r=0.2,g=0.2,b=1,a=1}} }, + effect = { consumption = 0.6, pollution = 0.05, productivity = 0.1, speed = 0.35 }, + icon_size = 64, + icons = { { icon = "__base__/graphics/icons/speed-module-3.png", tint = { r = 0.2, g = 0.2, b = 1, a = 1 } } }, } -data:extend{t} - -data:extend{{type="recipe",result="warptorio-warpmodule",name="warptorio-warpmodule",enabled=false,energy_required=60, - ingredients={{"speed-module-3",50},{"productivity-module-3",50},{"effectivity-module-3",50},{"advanced-circuit",200},{"processing-unit",200},{"low-density-structure",10}}, -}} +data:extend { t } + +data:extend { { type = "recipe", results = { { type = "item", name = "warptorio-warpmodule", amount = 1 } }, name = "warptorio-warpmodule", enabled = false, energy_required = 60, + ingredients = { + { type = "item", name = "speed-module-3", amount = 50 }, + { type = "item", name = "productivity-module-3", amount = 50 }, + { type = "item", name = "efficiency-module-3", amount = 50 }, + { type = "item", name = "advanced-circuit", amount = 200 }, + { type = "item", name = "processing-unit", amount = 200 }, + { type = "item", name = "low-density-structure", amount = 10 } + }, +} } -- ---- -- Warp Reactor -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/engine.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-reactor-1",unit={count=50,time=5}, prerequisites={}}, {red=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/electronics.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-reactor-2",unit={count=50,time=5}, prerequisites={"warptorio-reactor-1","logistic-science-pack"}}, {red=1,green=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/advanced-electronics.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-reactor-3",unit={count=50,time=5}, prerequisites={"warptorio-reactor-2","military-science-pack"}}, {red=1,green=2,black=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/advanced-electronics-2.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-reactor-4",unit={count=50,time=5}, prerequisites={"warptorio-reactor-3","rocketry"}}, {red=2,green=2,black=1,}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/explosives.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-reactor-5",unit={count=50,time=5}, prerequisites={"warptorio-reactor-4","chemical-science-pack"}}, {red=1,green=3,black=1,blue=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/atomic-bomb.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,} -}, localised_description={"technology-description.warptorio-reactor-6"} } -ExtendTech(t,{name="warptorio-reactor-6",unit={count=100,time=90}, effects={{recipe="warptorio-townportal",type="unlock-recipe"}},prerequisites={"warptorio-reactor-5","uranium-processing","robotics"}}, {red=5,black=5}) -- reactor module - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/kovarex-enrichment-process.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-reactor-7",unit={count=1000,time=30}, effects={{recipe="warptorio-heatpipe",type="unlock-recipe"},{recipe="warptorio-warponium-fuel-cell",type="unlock-recipe"}}, prerequisites={"nuclear-power","warptorio-reactor-6"}}, {red=1,green=1,black=1,blue=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__warptorio2__/graphics/technology/earth.png",tint={r=0.8,g=0.8,b=1,a=1},scale=0.5,shift={32,32},priority="high"} -}, localised_description={"technology-description.warptorio-reactor-8"} } -ExtendTech(t,{name="warptorio-reactor-8",unit={count=1000,time=30}, prerequisites={"warptorio-reactor-7","warptorio-charting","warptorio-accelerator","warptorio-stabilizer","warptorio-kovarex","rocket-control-unit"}}, {red=1,green=1,black=1,blue=1,purple=1,yellow=1}) -- steering +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/engine.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, { name = "warptorio-reactor-1", unit = { count = 50, time = 5 }, prerequisites = {} }, { red = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/electronics.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { name = "warptorio-reactor-2", unit = { count = 75, time = 10 }, prerequisites = { "warptorio-reactor-1", "logistic-science-pack" } }, + { red = 1, green = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/advanced-circuit.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { name = "warptorio-reactor-3", unit = { count = 100, time = 15 }, prerequisites = { "warptorio-reactor-2", "military-science-pack" } }, + { red = 1, green = 2, black = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/processing-unit.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { name = "warptorio-reactor-4", unit = { count = 200, time = 20 }, prerequisites = { "warptorio-reactor-3", "rocketry" } }, + { red = 2, green = 2, black = 1, }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/explosives.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { name = "warptorio-reactor-5", unit = { count = 250, time = 25 }, prerequisites = { "warptorio-reactor-4", "chemical-science-pack" } }, + { red = 1, green = 3, black = 1, blue = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/atomic-bomb.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, } + }, + localised_description = { "technology-description.warptorio-reactor-6" } +} +ExtendTech(t, + { name = "warptorio-reactor-6", unit = { count = 300, time = 30 }, effects = { { recipe = "warptorio-townportal", type = "unlock-recipe" } }, prerequisites = { "warptorio-reactor-5", "uranium-processing", "robotics" } }, + { red = 5, black = 5 }) -- reactor module + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/kovarex-enrichment-process.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { name = "warptorio-reactor-7", unit = { count = 500, time = 40 }, effects = { { recipe = "warptorio-heatpipe", type = "unlock-recipe" }, { recipe = "warptorio-warponium-fuel-cell", type = "unlock-recipe" } }, prerequisites = { "nuclear-power", "warptorio-reactor-6" } }, + { red = 1, green = 1, black = 1, blue = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__warptorio2__/graphics/technology/earth.png", tint = { r = 0.8, g = 0.8, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high" } + }, + localised_description = { "technology-description.warptorio-reactor-8" } +} +ExtendTech(t, + { name = "warptorio-reactor-8", unit = { count = 1000, time = 60 }, prerequisites = { "warptorio-reactor-7", "warptorio-charting", "warptorio-accelerator", "warptorio-stabilizer", "warptorio-kovarex" } }, + { red = 1, green = 1, black = 1, blue = 1, purple = 1, yellow = 1 }) -- steering -- ---- -- Reactor Abilities -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/battery.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-stabilizer",unit={count=400,time=30}, prerequisites={"warptorio-reactor-6","military-3","circuit-network"}}, {red=1,green=1,black=1,blue=1}) -- stabilizer - -local t={type="technology",upgrade=false,icon_size=128,icons={ {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,} }, } -t.icons={ {icon="__base__/graphics/technology/engine.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} } -ExtendTech(t,{name="warptorio-accelerator",unit={count=400,time=30}, prerequisites={"warptorio-reactor-6","military-3","circuit-network"}}, {red=1,green=1,black=1,blue=1}) -- accelerator - -local t={type="technology",upgrade=false,icon_size=128,icons={ {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,} }, } -t.icons={ {icon="__base__/graphics/technology/radar.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} } -ExtendTech(t,{name="warptorio-charting",unit={count=400,time=30}, prerequisites={"warptorio-reactor-6","military-3","circuit-network"}}, {red=1,green=1,black=1,blue=1}) -- charting - - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__warptorio2__/graphics/technology/earth.png",tint={r=0.8,g=0.8,b=1,a=1},priority="low"} -}, } -ExtendTech(t,{name="warptorio-homeworld",unit={count=5000,time=30}, effects={{recipe="warptorio-homeportal",type="unlock-recipe"}}, prerequisites={"warptorio-reactor-8","space-science-pack"}}, {red=1,green=1,black=1,blue=1,purple=1,yellow=1,white=1}) +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/battery.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-stabilizer", unit = { count = 400, time = 30 }, prerequisites = { "warptorio-reactor-6", "military-3", "circuit-network" } }, + { red = 1, green = 1, black = 1, blue = 1 }) -- stabilizer + +local t = { type = "technology", upgrade = false, icon_size = 128, icons = { { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, } }, } +t.icons = { { icon = "__base__/graphics/technology/engine.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } } +ExtendTech(t, + { name = "warptorio-accelerator", unit = { count = 400, time = 30 }, prerequisites = { "warptorio-reactor-6", "military-3", "circuit-network" } }, + { red = 1, green = 1, black = 1, blue = 1 }) -- accelerator + +local t = { type = "technology", upgrade = false, icon_size = 128, icons = { { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, } }, } +t.icons = { { icon = "__base__/graphics/technology/radar.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } } +ExtendTech(t, + { name = "warptorio-charting", unit = { count = 400, time = 30 }, prerequisites = { "warptorio-reactor-6", "military-3", "circuit-network" } }, + { red = 1, green = 1, black = 1, blue = 1 }) -- charting + + +local t = { + type = "technology", + upgrade = true, + icons = { + { icon = "__warptorio2__/graphics/technology/earth.png", tint = { r = 0.8, g = 0.8, b = 1, a = 1 }, scale = 0.375, priority = "low", icon_size = 128 } + }, +} +ExtendTech(t, + { name = "warptorio-homeworld", unit = { count = 5000, time = 30 }, effects = { { recipe = "warptorio-homeportal", type = "unlock-recipe" } }, prerequisites = { "warptorio-reactor-8", "space-science-pack" } }, + { red = 1, green = 1, black = 1, blue = 1, purple = 1, yellow = 1, white = 1 }) -- ---- -- Warponium Fuel -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/nuclear-power.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/rocket-fuel.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,}, +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/nuclear-power.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/rocket-fuel.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, }, }, - effects={{recipe="warptorio-warponium-fuel",type="unlock-recipe"}}, + effects = { { recipe = "warptorio-warponium-fuel", type = "unlock-recipe" } }, } -ExtendTech(t,{name="warptorio-kovarex",unit={count=1000,time=15}, prerequisites={"warptorio-reactor-7","kovarex-enrichment-process"}}, {red=1,green=1,black=1,blue=1,purple=1}) -- Kovarex +ExtendTech(t, + { name = "warptorio-kovarex", unit = { count = 1000, time = 15 }, prerequisites = { "warptorio-reactor-7", "kovarex-enrichment-process" } }, + { red = 1, green = 1, black = 1, blue = 1, purple = 1 }) -- Kovarex -- ---- -- Boiler Warp Substation -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/electric-energy-distribution-1.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.7,g=0.7,b=1,a=1},scale=0.5,shift={32,32},priority="high",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-boiler-station",unit={count=500,time=10}, prerequisites={"electric-energy-distribution-2","warptorio-boiler-0","production-science-pack"}}, {red=1,blue=1,green=1,purple=1}) +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/electric-energy-distribution-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, scale = 0.25, shift = { 16, 16 }, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-boiler-station", unit = { count = 500, time = 10 }, prerequisites = { "electric-energy-distribution-2", "warptorio-boiler-0", "production-science-pack" } }, + { red = 1, blue = 1, green = 1, purple = 1 }) -- ---- -- Warp Energy Pipe -local rtint={tint={r=0.3,g=0.3,b=1,a=1},hr_version={tint={r=0.3,g=0.3,b=1,a=1}}} +local rtint = { tint = { r = 0.3, g = 0.3, b = 1, a = 1 } } --[[ local pipe_sprites={corner_left_down={{rtint},{rtint},{rtint},{rtint},{rtint}},corner_left_up={{rtint},{rtint},{rtint},{rtint},{rtint},{rtint}}, @@ -307,123 +528,268 @@ local t=ExtendDataCopy("heat-pipe","heat-pipe",{name="warptorio-heatpipe",connec icon_size=64,icons={ {icon="__base__/graphics/icons/heat-pipe.png",tint={r=0.3,g=0.3,b=1,a=1},hr_version={tint={r=0.3,g=0.3,b=1,a=1}} } } })]] -local pipe_icon={ {icon="__base__/graphics/icons/heat-pipe.png",tint={r=0.3,g=0.3,b=1,a=1},hr_version={tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} } } -local t=ExtendDataCopy("recipe","heat-pipe",{name="warptorio-heatpipe",result="warptorio-heatpipe",ingredients={{"processing-unit",200},{"heat-pipe",50}}, enabled=false,energy_required=30, }) -local t=ExtendDataCopy("item","heat-pipe",{name="warptorio-heatpipe",place_result="warptorio-heatpipe", - icon_size=64,icons=pipe_icon, +local pipe_icon = { { icon = "__base__/graphics/icons/heat-pipe.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 64 } } +local t = ExtendDataCopy("recipe", "heat-pipe", + { name = "warptorio-heatpipe", results = { { type = "item", name = "warptorio-heatpipe", amount = 1 } }, ingredients = { { type = "item", name = "processing-unit", amount = 200 }, { type = "item", name = "heat-pipe", amount = 50 } }, enabled = false, energy_required = 30, }) +local t = ExtendDataCopy("item", "heat-pipe", { + name = "warptorio-heatpipe", + place_result = "warptorio-heatpipe", + icon_size = 64, + icons = pipe_icon, }) -- ---- -- Sandbox Boosts -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/mining-productivity.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, - effects={ {type="mining-drill-productivity-bonus",modifier=0.1}}, } -ExtendTech(t,{name="warptorio-mining-prod-1",unit={count_formula="20*L",time=30},max_level=5}, {red=1}) -ExtendTech(t,{name="warptorio-mining-prod-6",unit={count_formula="(20*L)-50",time=30},max_level=10,prerequisites={"warptorio-mining-prod-1","logistic-science-pack"}}, {red=2,green=1}) -ExtendTech(t,{name="warptorio-mining-prod-11",unit={count_formula="(20*L)-100",time=30},max_level=15,prerequisites={"warptorio-mining-prod-6","chemical-science-pack"}}, {red=2,green=2,blue=1} ) -ExtendTech(t,{name="warptorio-mining-prod-16",unit={count_formula="(20*L)-150",time=30},max_level=20,prerequisites={"warptorio-mining-prod-11","production-science-pack"}}, {red=3,green=3,blue=1,purple=1} ) -ExtendTech(t,{name="warptorio-mining-prod-21",unit={count_formula="(20*L)-200",time=30},max_level=25,prerequisites={"warptorio-mining-prod-16","utility-science-pack"}}, {red=3,green=3,blue=2,purple=1,yellow=1} ) - -local t={type="technology",upgrade=true,icon_size=64,icons={ {icon="__base__/graphics/icons/steel-axe.png",tint={r=0.3,g=0.3,b=1,a=1},} }, - effects={ {type="character-mining-speed",modifier=0.5}}, } -ExtendTech(t,{name="warptorio-axe-speed-1",unit={count_formula="50*L",time=30},prerequisites={"steel-axe","warptorio-reactor-1"},max_level=2}, {red=1}) -ExtendTech(t,{name="warptorio-axe-speed-3",unit={count_formula="(50*L)",time=30},max_level=4,prerequisites={"warptorio-axe-speed-1","logistic-science-pack"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-axe-speed-5",unit={count_formula="(50*L)",time=30},max_level=6,prerequisites={"warptorio-axe-speed-3","chemical-science-pack"}}, {red=1,green=1,blue=1} ) -ExtendTech(t,{name="warptorio-axe-speed-7",unit={count_formula="(50*L)",time=30},max_level=8,prerequisites={"warptorio-axe-speed-5","production-science-pack"}}, {red=1,green=1,blue=1,purple=1} ) -ExtendTech(t,{name="warptorio-axe-speed-9",unit={count_formula="(50*L)",time=30},max_level=10,prerequisites={"warptorio-axe-speed-7","utility-science-pack"}}, {red=1,green=1,blue=1,purple=1,yellow=1} ) - -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/inserter-capacity.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, - effects={ {type="stack-inserter-capacity-bonus",modifier=1}, {type="inserter-stack-size-bonus",modifier=1},} } -ExtendTech(t,{name="warptorio-inserter-cap-1",unit={count=150,time=30},prerequisites={"warptorio-reactor-1","fast-inserter"},}, {red=1}) -ExtendTech(t,{name="warptorio-inserter-cap-2",unit={count=200,time=30},prerequisites={"warptorio-inserter-cap-1","logistic-science-pack"}}, {red=2,green=1}) -ExtendTech(t,{name="warptorio-inserter-cap-3",unit={count=250,time=30},prerequisites={"warptorio-inserter-cap-2","chemical-science-pack"}}, {red=3,green=2,blue=1} ) -ExtendTech(t,{name="warptorio-inserter-cap-4",unit={count=300,time=30},prerequisites={"warptorio-inserter-cap-3","production-science-pack"}}, {red=4,green=3,blue=2,purple=1} ) -ExtendTech(t,{name="warptorio-inserter-cap-5",unit={count=350,time=30},prerequisites={"warptorio-inserter-cap-4","utility-science-pack"}}, {red=5,green=4,blue=3,purple=2,yellow=1} ) - - -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/worker-robots-speed.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, - effects={ {type="worker-robot-speed",modifier=0.35},} } -ExtendTech(t,{name="warptorio-bot-speed-1",unit={count=120,time=30},prerequisites={"robotics","warptorio-reactor-2"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-bot-speed-2",unit={count=180,time=30},prerequisites={"warptorio-bot-speed-1","logistic-robotics"}}, {red=2,green=1}) -ExtendTech(t,{name="warptorio-bot-speed-3",unit={count=250,time=30},prerequisites={"warptorio-bot-speed-2","chemical-science-pack"}}, {red=3,green=2,blue=1} ) -ExtendTech(t,{name="warptorio-bot-speed-4",unit={count=300,time=30},prerequisites={"warptorio-bot-speed-3","production-science-pack"}}, {red=4,green=3,blue=2,purple=1} ) -ExtendTech(t,{name="warptorio-bot-speed-5",unit={count=350,time=30},prerequisites={"warptorio-bot-speed-4","utility-science-pack"}}, {red=5,green=4,blue=3,purple=2,yellow=1} ) - -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/worker-robots-storage.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, - effects={ {type="worker-robot-storage",modifier=1}, } } -ExtendTech(t,{name="warptorio-bot-cap-1",unit={count=120,time=30},prerequisites={"robotics","warptorio-reactor-2"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-bot-cap-2",unit={count=180,time=30},prerequisites={"warptorio-bot-cap-1","construction-robotics"}}, {red=2,green=1}) -ExtendTech(t,{name="warptorio-bot-cap-3",unit={count=250,time=30},prerequisites={"warptorio-bot-cap-2","chemical-science-pack"}}, {red=2,green=2,blue=1} ) -ExtendTech(t,{name="warptorio-bot-cap-4",unit={count=300,time=30},prerequisites={"warptorio-bot-cap-3","production-science-pack"}}, {red=3,green=3,blue=1,purple=1} ) -ExtendTech(t,{name="warptorio-bot-cap-5",unit={count=350,time=30},prerequisites={"warptorio-bot-cap-4","utility-science-pack"}}, {red=3,green=3,blue=2,purple=1,yellow=1} ) - - -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/physical-projectile-damage-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, - effects={ {type="turret-attack",modifier=0.15,turret_id="gun-turret"},{ammo_category="bullet",modifier=0.15,type="ammo-damage"},{ammo_category="shotgun-shell",modifier=0.2,type="ammo-damage"} } } -ExtendTech(t,{name="warptorio-physdmg-1",unit={count=250,time=30},prerequisites={"warptorio-reactor-1","physical-projectile-damage-1"}}, {red=1}) -ExtendTech(t,{name="warptorio-physdmg-2",unit={count=250,time=30},prerequisites={"warptorio-reactor-2","warptorio-physdmg-1","physical-projectile-damage-2"}}, {red=2,green=1} ) -ExtendTech(t,{name="warptorio-physdmg-3",unit={count=350,time=30},prerequisites={"warptorio-reactor-3","warptorio-physdmg-2","physical-projectile-damage-3"}}, {red=3,green=2,black=1} ) - -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/toolbelt.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, - effects={ {type="character-inventory-slots-bonus",modifier=10} }, } -ExtendTech(t,{name="warptorio-toolbelt-1",unit={count=70,time=30},prerequisites={"warptorio-reactor-1"}}, {red=1}) -ExtendTech(t,{name="warptorio-toolbelt-2",unit={count=120,time=30},prerequisites={"warptorio-toolbelt-1","toolbelt","logistic-science-pack"}}, {red=2,green=1}) -ExtendTech(t,{name="warptorio-toolbelt-3",unit={count=150,time=30},prerequisites={"warptorio-toolbelt-2","chemical-science-pack"}}, {red=2,green=2,blue=1} ) -ExtendTech(t,{name="warptorio-toolbelt-4",unit={count=180,time=30},prerequisites={"warptorio-toolbelt-3","production-science-pack"}}, {red=3,green=2,blue=2,purple=1} ) -ExtendTech(t,{name="warptorio-toolbelt-5",unit={count=200,time=30},prerequisites={"warptorio-toolbelt-4","utility-science-pack"}}, {red=4,green=3,blue=2,purple=2,yellow=1} ) - -local t={type="technology",upgrade=true,icons={ - {icon="__warptorio2__/graphics/technology/earth.png",tint={r=0.7,g=0.7,b=1,a=1},shift={0,0},scale=0.375,priority="medium",icon_size=128}, - {icon="__base__/graphics/icons/steel-axe.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_size=64,scale=0.5}, - }, - effects={ - {type="character-reach-distance",modifier=1}, - {type="character-build-distance",modifier=1}, - {type="character-item-drop-distance",modifier=1}, - {type="character-resource-reach-distance",modifier=1}, - }, -} -ExtendTech(t,{name="warptorio-reach-1",unit={count=50,time=30},prerequisites={"warptorio-reactor-1"}}, {red=1}) -ExtendTech(t,{name="warptorio-reach-2",unit={count=100,time=30},prerequisites={"warptorio-reach-1","logistic-science-pack"}}, {red=2,green=1}) -ExtendTech(t,{name="warptorio-reach-3",unit={count=150,time=30},prerequisites={"warptorio-reach-2","chemical-science-pack"}}, {red=2,green=2,blue=1} ) -ExtendTech(t,{name="warptorio-reach-4",unit={count=180,time=30},prerequisites={"warptorio-reach-3","production-science-pack"}}, {red=3,green=2,blue=2,purple=1} ) -ExtendTech(t,{name="warptorio-reach-5",unit={count=200,time=30},prerequisites={"warptorio-reach-4","utility-science-pack"}}, {red=4,green=3,blue=2,purple=2,yellow=1} ) - - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/exoskeleton-equipment.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, -}, effects={ - {type="character-running-speed",modifier=0.1}, -}, } -ExtendTech(t,{name="warptorio-striders-1",unit={count=150,time=20}, prerequisites={"warptorio-reactor-1"},upgrade=false}, {red=1}) -ExtendTech(t,{name="warptorio-striders-2",unit={count=300,time=20}, prerequisites={"warptorio-reactor-2","modular-armor","warptorio-striders-1"},upgrade=false}, {red=1,green=1}) +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { { icon = "__base__/graphics/technology/mining-productivity.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, + effects = { { type = "mining-drill-productivity-bonus", modifier = 0.1 } }, +} +ExtendTech(t, { name = "warptorio-mining-prod-1", unit = { count_formula = "20*L", time = 30 }, max_level = 5 }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-mining-prod-6", unit = { count_formula = "(20*L)+50", time = 40 }, max_level = 10, prerequisites = { "warptorio-mining-prod-1", "logistic-science-pack" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-mining-prod-11", unit = { count_formula = "(20*L)+100", time = 50 }, max_level = 15, prerequisites = { "warptorio-mining-prod-6", "chemical-science-pack" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-mining-prod-16", unit = { count_formula = "(20*L)+150", time = 60 }, max_level = 20, prerequisites = { "warptorio-mining-prod-11", "production-science-pack" } }, + { red = 3, green = 3, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-mining-prod-21", unit = { count_formula = "(20*L)+200", time = 60 }, max_level = 25, prerequisites = { "warptorio-mining-prod-16", "utility-science-pack" } }, + { red = 3, green = 3, blue = 2, purple = 1, yellow = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 64, + icons = { { icon = "__base__/graphics/technology/steel-axe.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, + effects = { { type = "character-mining-speed", modifier = 0.5 } }, +} +ExtendTech(t, + { name = "warptorio-axe-speed-1", unit = { count_formula = "50*L", time = 30 }, prerequisites = { "steel-axe", "warptorio-reactor-1" }, max_level = 2 }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-axe-speed-3", unit = { count_formula = "(50*L)+50", time = 30 }, max_level = 4, prerequisites = { "warptorio-axe-speed-1", "logistic-science-pack" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-axe-speed-5", unit = { count_formula = "(50*L)+100", time = 30 }, max_level = 6, prerequisites = { "warptorio-axe-speed-3", "chemical-science-pack" } }, + { red = 1, green = 1, blue = 1 }) +ExtendTech(t, + { name = "warptorio-axe-speed-7", unit = { count_formula = "(50*L)+150", time = 30 }, max_level = 8, prerequisites = { "warptorio-axe-speed-5", "production-science-pack" } }, + { red = 1, green = 1, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-axe-speed-9", unit = { count_formula = "(50*L)+200", time = 30 }, max_level = 10, prerequisites = { "warptorio-axe-speed-7", "utility-science-pack" } }, + { red = 1, green = 1, blue = 1, purple = 1, yellow = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { { icon = "__base__/graphics/technology/inserter-capacity.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, + effects = { { type = "bulk-inserter-capacity-bonus", modifier = 1 }, { type = "inserter-stack-size-bonus", modifier = 1 }, } +} +ExtendTech(t, + { name = "warptorio-inserter-cap-1", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-reactor-1", "fast-inserter" }, }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-inserter-cap-2", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-inserter-cap-1", "logistic-science-pack" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-inserter-cap-3", unit = { count = 250, time = 30 }, prerequisites = { "warptorio-inserter-cap-2", "chemical-science-pack" } }, + { red = 3, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-inserter-cap-4", unit = { count = 300, time = 30 }, prerequisites = { "warptorio-inserter-cap-3", "production-science-pack" } }, + { red = 4, green = 3, blue = 2, purple = 1 }) +ExtendTech(t, + { name = "warptorio-inserter-cap-5", unit = { count = 350, time = 30 }, prerequisites = { "warptorio-inserter-cap-4", "utility-science-pack" } }, + { red = 5, green = 4, blue = 3, purple = 2, yellow = 1 }) + + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { { icon = "__base__/graphics/technology/worker-robots-speed.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, + effects = { { type = "worker-robot-speed", modifier = 0.35 }, } +} +ExtendTech(t, + { name = "warptorio-bot-speed-1", unit = { count = 120, time = 30 }, prerequisites = { "robotics", "warptorio-reactor-2" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-bot-speed-2", unit = { count = 180, time = 30 }, prerequisites = { "warptorio-bot-speed-1", "logistic-robotics" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-bot-speed-3", unit = { count = 250, time = 30 }, prerequisites = { "warptorio-bot-speed-2", "chemical-science-pack" } }, + { red = 3, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-bot-speed-4", unit = { count = 300, time = 30 }, prerequisites = { "warptorio-bot-speed-3", "production-science-pack" } }, + { red = 4, green = 3, blue = 2, purple = 1 }) +ExtendTech(t, + { name = "warptorio-bot-speed-5", unit = { count = 350, time = 30 }, prerequisites = { "warptorio-bot-speed-4", "utility-science-pack" } }, + { red = 5, green = 4, blue = 3, purple = 2, yellow = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { { icon = "__base__/graphics/technology/worker-robots-storage.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, + effects = { { type = "worker-robot-storage", modifier = 1 }, } +} +ExtendTech(t, + { name = "warptorio-bot-cap-1", unit = { count = 120, time = 30 }, prerequisites = { "robotics", "warptorio-reactor-2" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-bot-cap-2", unit = { count = 180, time = 30 }, prerequisites = { "warptorio-bot-cap-1", "construction-robotics" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-bot-cap-3", unit = { count = 250, time = 30 }, prerequisites = { "warptorio-bot-cap-2", "chemical-science-pack" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-bot-cap-4", unit = { count = 300, time = 30 }, prerequisites = { "warptorio-bot-cap-3", "production-science-pack" } }, + { red = 3, green = 3, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-bot-cap-5", unit = { count = 350, time = 30 }, prerequisites = { "warptorio-bot-cap-4", "utility-science-pack" } }, + { red = 3, green = 3, blue = 2, purple = 1, yellow = 1 }) + + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { { icon = "__base__/graphics/technology/physical-projectile-damage-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, + effects = { { type = "turret-attack", modifier = 0.15, turret_id = "gun-turret" }, { ammo_category = "bullet", modifier = 0.15, type = "ammo-damage" }, { ammo_category = "shotgun-shell", modifier = 0.2, type = "ammo-damage" } } +} +ExtendTech(t, + { name = "warptorio-physdmg-1", unit = { count = 250, time = 30 }, prerequisites = { "warptorio-reactor-1", "physical-projectile-damage-1" } }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-physdmg-2", unit = { count = 250, time = 30 }, prerequisites = { "warptorio-reactor-2", "warptorio-physdmg-1", "physical-projectile-damage-2" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-physdmg-3", unit = { count = 350, time = 30 }, prerequisites = { "warptorio-reactor-3", "warptorio-physdmg-2", "physical-projectile-damage-3" } }, + { red = 3, green = 2, black = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { { icon = "__base__/graphics/technology/toolbelt.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, + effects = { { type = "character-inventory-slots-bonus", modifier = 10 } }, +} +ExtendTech(t, + { name = "warptorio-toolbelt-1", unit = { count = 70, time = 30 }, prerequisites = { "warptorio-reactor-1" } }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-toolbelt-2", unit = { count = 120, time = 30 }, prerequisites = { "warptorio-toolbelt-1", "toolbelt", "logistic-science-pack" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-toolbelt-3", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-toolbelt-2", "chemical-science-pack" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-toolbelt-4", unit = { count = 180, time = 30 }, prerequisites = { "warptorio-toolbelt-3", "production-science-pack" } }, + { red = 3, green = 2, blue = 2, purple = 1 }) +ExtendTech(t, + { name = "warptorio-toolbelt-5", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-toolbelt-4", "utility-science-pack" } }, + { red = 4, green = 3, blue = 2, purple = 2, yellow = 1 }) + +local t = { + type = "technology", + upgrade = true, + icons = { + { icon = "__warptorio2__/graphics/technology/earth.png", tint = { r = 0.7, g = 0.7, b = 1, a = 1 }, shift = { 0, 0 }, scale = 0.375, priority = "medium", icon_size = 128 }, + { icon = "__base__/graphics/technology/steel-axe.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_size = 256, scale = 0.125 }, + }, + effects = { + { type = "character-reach-distance", modifier = 1 }, + { type = "character-build-distance", modifier = 1 }, + { type = "character-item-drop-distance", modifier = 1 }, + { type = "character-resource-reach-distance", modifier = 1 }, + }, +} +ExtendTech(t, { name = "warptorio-reach-1", unit = { count = 50, time = 30 }, prerequisites = { "warptorio-reactor-1" } }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-reach-2", unit = { count = 100, time = 30 }, prerequisites = { "warptorio-reach-1", "logistic-science-pack" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-reach-3", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-reach-2", "chemical-science-pack" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-reach-4", unit = { count = 180, time = 30 }, prerequisites = { "warptorio-reach-3", "production-science-pack" } }, + { red = 3, green = 2, blue = 2, purple = 1 }) +ExtendTech(t, + { name = "warptorio-reach-5", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-reach-4", "utility-science-pack" } }, + { red = 4, green = 3, blue = 2, purple = 2, yellow = 1 }) + + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/exoskeleton-equipment.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + }, + effects = { + { type = "character-running-speed", modifier = 0.1 }, + }, +} +ExtendTech(t, + { name = "warptorio-striders-1", unit = { count = 150, time = 20 }, prerequisites = { "warptorio-reactor-1" }, upgrade = false }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-striders-2", unit = { count = 300, time = 20 }, prerequisites = { "warptorio-reactor-2", "modular-armor", "warptorio-striders-1" }, upgrade = false }, + { red = 1, green = 1 }) -- ---- -- Platform Size -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/concrete.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, } -ExtendTech(t,{name="warptorio-platform-size-1", unit={count=70,time=20}, prerequisites={}}, {red=1} ) -ExtendTech(t,{name="warptorio-platform-size-2", unit={count=120,time=20}, prerequisites={"warptorio-platform-size-1","warptorio-reactor-1"}}, {red=1} ) -ExtendTech(t,{name="warptorio-platform-size-3", unit={count=150,time=40}, prerequisites={"warptorio-platform-size-2","logistic-science-pack"}}, {red=1,green=1} ) -ExtendTech(t,{name="warptorio-platform-size-4", unit={count=250,time=30}, prerequisites={"concrete","warptorio-platform-size-3"}}, {red=1,green=1} ) -ExtendTech(t,{name="warptorio-platform-size-5", unit={count=120,time=30}, prerequisites={"chemical-science-pack","warptorio-platform-size-4"}}, {red=2,green=2,blue=1} ) -ExtendTech(t,{name="warptorio-platform-size-6", unit={count=150,time=30}, prerequisites={"warptorio-platform-size-5","solar-energy","production-science-pack"}}, {red=2,green=2,blue=1,purple=1} ) -ExtendTech(t,{name="warptorio-platform-size-7", unit={count=150,time=30}, prerequisites={"warptorio-platform-size-6","utility-science-pack"}}, {red=2,green=2,blue=1,purple=1,yellow=1} ) +local t = { type = "technology", upgrade = true, icon_size = 128, icons = { { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, } +ExtendTech(t, { name = "warptorio-platform-size-1", unit = { count = 70, time = 20 }, prerequisites = {} }, { red = 1 }) +ExtendTech(t, + { name = "warptorio-platform-size-2", unit = { count = 120, time = 20 }, prerequisites = { "warptorio-platform-size-1", "warptorio-reactor-1" } }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-platform-size-3", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-platform-size-2", "logistic-science-pack" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-platform-size-4", unit = { count = 200, time = 30 }, prerequisites = { "concrete", "warptorio-platform-size-3" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-platform-size-5", unit = { count = 120, time = 30 }, prerequisites = { "chemical-science-pack", "warptorio-platform-size-4" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-platform-size-6", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-platform-size-5", "solar-energy", "production-science-pack" } }, + { red = 2, green = 2, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-platform-size-7", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-platform-size-6", "utility-science-pack" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) -- ---- -- Train Stops -for v,w in pairs({nw={-38,-38},ne={38,-38},se={38,38},sw={-38,38}})do -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/railway.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/railway.png",tint={r=0.7,g=0.7,b=1,a=0.9},shift={w[1],w[2]},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, -}, } - -ExtendTech(t,{name="warptorio-rail-"..v, unit={count=500,time=40}, prerequisites={"railway","warptorio-platform-size-6","warptorio-factory-7"}}, {red=1,green=1,black=1,blue=1,purple=1,yellow=1} ) +for v, w in pairs({ nw = { -38, -38 }, ne = { 38, -38 }, se = { 38, 38 }, sw = { -38, 38 } }) do + local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/railway.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "low", icon_mipmaps = 4, icon_size = 256, scale = 0.375 }, + { icon = "__base__/graphics/technology/railway.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, shift = { w[1], w[2] }, scale = 0.25, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + }, + } + + ExtendTech(t, + { name = "warptorio-rail-" .. v, unit = { count = 500, time = 30 }, prerequisites = { "railway", "warptorio-platform-size-6", "warptorio-factory-7" } }, + { red = 1, green = 1, black = 1, blue = 1, purple = 1, yellow = 1 }) end @@ -431,127 +797,280 @@ end -- Castle Ramps -for v,w in pairs({nw={-38,-38},ne={38,-38},se={38,38},sw={-38,38}})do -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/stone-wall.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/stone-wall.png",tint={r=0.7,g=0.7,b=1,a=0.9},shift={w[1],w[2]},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-turret-"..v.."-0",upgrade=false, unit={count=100,time=40}, prerequisites={"gate","warptorio-factory-0"}}, {red=1,green=1} ) -ExtendTech(t,{name="warptorio-turret-"..v.."-1", unit={count=150,time=40}, prerequisites={"warptorio-turret-"..v.."-0","military-science-pack",}}, {red=2,green=1,black=1,} ) -ExtendTech(t,{name="warptorio-turret-"..v.."-2", unit={count=200,time=30}, prerequisites={"warptorio-turret-"..v.."-1","chemical-science-pack"}}, {red=2,green=1,black=1,blue=1} ) -ExtendTech(t,{name="warptorio-turret-"..v.."-3", unit={count=300,time=40}, prerequisites={"warptorio-turret-"..v.."-2","production-science-pack"}}, {red=2,green=2,black=1,blue=1,purple=1} ) +for v, w in pairs({ nw = { -38, -38 }, ne = { 38, -38 }, se = { 38, 38 }, sw = { -38, 38 } }) do + local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/stone-wall.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, scale = 0.4 }, + { icon = "__base__/graphics/technology/stone-wall.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, shift = { w[1], w[2] }, scale = 0.25, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + }, + } + ExtendTech(t, + { name = "warptorio-turret-" .. v .. "-0", upgrade = false, unit = { count = 100, time = 30 }, prerequisites = { "gate", "warptorio-factory-0" } }, + { red = 1, green = 1 }) + ExtendTech(t, + { name = "warptorio-turret-" .. v .. "-1", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-turret-" .. v .. "-0", "military-science-pack", } }, + { red = 2, green = 1, black = 1, }) + ExtendTech(t, + { name = "warptorio-turret-" .. v .. "-2", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-turret-" .. v .. "-1", "chemical-science-pack" } }, + { red = 2, green = 1, black = 1, blue = 1 }) + ExtendTech(t, + { name = "warptorio-turret-" .. v .. "-3", unit = { count = 300, time = 40 }, prerequisites = { "warptorio-turret-" .. v .. "-2", "production-science-pack" } }, + { red = 2, green = 2, black = 1, blue = 1, purple = 1 }) end -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/stone-wall.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/stone-wall.png",tint={r=0.7,g=0.7,b=1,a=0.9},shift={38,38},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/stone-wall.png",tint={r=0.7,g=0.7,b=1,a=0.9},shift={-38,-38},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/stone-wall.png",tint={r=0.7,g=0.7,b=1,a=0.9},shift={-38,38},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/stone-wall.png",tint={r=0.7,g=0.7,b=1,a=0.9},shift={38,-38},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-bridgesize-1",unit={count=500,time=40},prerequisites={"warptorio-turret-nw-0","warptorio-turret-ne-0","warptorio-turret-se-0","warptorio-turret-sw-0"}, - unit={count=200,time=40}},{red=1,green=1,black=1}) -ExtendTech(t,{name="warptorio-bridgesize-2",unit={count=500,time=40},prerequisites={"warptorio-bridgesize-1","warptorio-turret-nw-1","warptorio-turret-ne-1","warptorio-turret-se-1","warptorio-turret-sw-1","low-density-structure"}, - unit={count=400,time=40}},{red=1,green=1,black=1,blue=1}) +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/stone-wall.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/stone-wall.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, shift = { 32, 32 }, scale = 0.25, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/stone-wall.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, shift = { -32, -32 }, scale = 0.25, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/stone-wall.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, shift = { -32, 32 }, scale = 0.25, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/stone-wall.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, shift = { 32, -32 }, scale = 0.25, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { + name = "warptorio-bridgesize-1", + unit = { count = 500, time = 40 }, + prerequisites = { "warptorio-turret-nw-0", "warptorio-turret-ne-0", "warptorio-turret-se-0", "warptorio-turret-sw-0" }, + unit = { count = 200, time = 40 } + }, { red = 1, green = 1, black = 1 }) +ExtendTech(t, + { + name = "warptorio-bridgesize-2", + unit = { count = 500, time = 40 }, + prerequisites = { "warptorio-bridgesize-1", "warptorio-turret-nw-1", "warptorio-turret-ne-1", "warptorio-turret-se-1", "warptorio-turret-sw-1", "low-density-structure" }, + unit = { count = 400, time = 40 } + }, { red = 1, green = 1, black = 1, blue = 1 }) -- ---- -- Factory Floor Upgrades -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/automation-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-factory-0",unit={count=80,time=20}, prerequisites={"automation","warptorio-platform-size-1"}, upgrade=false, - localised_name={"technology-name.warptorio-factory"}, - localised_description={"technology-description.warptorio-factory-floor"}, -},{red=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/automation-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-factory-1",unit={count=120,time=20}, prerequisites={"warptorio-factory-0","steel-processing"}}, {red=1}) -ExtendTech(t,{name="warptorio-factory-2",unit={count=150,time=15}, prerequisites={"electric-energy-distribution-1","advanced-material-processing","automation-2","warptorio-factory-1"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-factory-3",unit={count=180,time=20}, prerequisites={"warptorio-factory-2","sulfur-processing"}}, {red=2,green=2}) -ExtendTech(t,{name="warptorio-factory-4",unit={count=220,time=25}, prerequisites={"warptorio-factory-3","chemical-science-pack","modules"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-factory-5",unit={count=250,time=20}, prerequisites={"warptorio-factory-4","advanced-material-processing-2"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-factory-6",unit={count=300,time=20}, prerequisites={"warptorio-factory-5","automation-3"}}, {red=2,green=2,blue=1,purple=1}) -ExtendTech(t,{name="warptorio-factory-7",unit={count=350,time=20}, prerequisites={"warptorio-factory-6","utility-science-pack","effect-transmission"}}, {red=2,green=3,blue=1,purple=1,yellow=1}) - -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/automation-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={0,-32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-factory-n",unit={count=1000,time=30}, prerequisites={"warptorio-factory-7","space-science-pack","warptorio-bridgesize-2"}}, {red=3,green=2,blue=3,purple=2,yellow=1,white=1}) -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/automation-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={0,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-factory-s",unit={count=1000,time=30}, prerequisites={"warptorio-factory-7","space-science-pack","warptorio-bridgesize-2"}}, {red=3,green=2,blue=3,purple=2,yellow=1,white=1}) -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/automation-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,0},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-factory-e",unit={count=1000,time=30}, prerequisites={"warptorio-factory-7","space-science-pack","warptorio-bridgesize-2"}}, {red=3,green=2,blue=3,purple=2,yellow=1,white=1}) -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/automation-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={-32,0},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-factory-w",unit={count=1000,time=30}, prerequisites={"warptorio-factory-7","space-science-pack","warptorio-bridgesize-2"}}, {red=3,green=2,blue=3,purple=2,yellow=1,white=1}) +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/automation-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { + name = "warptorio-factory-0", + unit = { count = 80, time = 20 }, + prerequisites = { "automation", "warptorio-platform-size-1" }, + upgrade = false, + localised_name = { "technology-name.warptorio-factory" }, + localised_description = { "technology-description.warptorio-factory-floor" }, + }, { red = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/automation-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 16, 16 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-factory-1", unit = { count = 120, time = 20 }, prerequisites = { "warptorio-factory-0", "steel-processing" } }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-factory-2", unit = { count = 150, time = 20 }, prerequisites = { "electric-energy-distribution-1", "advanced-material-processing", "automation-2", "warptorio-factory-1" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-factory-3", unit = { count = 180, time = 20 }, prerequisites = { "warptorio-factory-2", "sulfur-processing" } }, + { red = 2, green = 2 }) +ExtendTech(t, + { name = "warptorio-factory-4", unit = { count = 220, time = 20 }, prerequisites = { "warptorio-factory-3", "chemical-science-pack", "modules" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-factory-5", unit = { count = 250, time = 20 }, prerequisites = { "warptorio-factory-4", "advanced-material-processing-2" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-factory-6", unit = { count = 300, time = 20 }, prerequisites = { "warptorio-factory-5", "automation-3" } }, + { red = 2, green = 2, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-factory-7", unit = { count = 350, time = 20 }, prerequisites = { "warptorio-factory-6", "utility-science-pack", "effect-transmission" } }, + { red = 2, green = 3, blue = 1, purple = 1, yellow = 1 }) + +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/automation-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 0, -24 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-factory-n", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-factory-7", "space-science-pack", "warptorio-bridgesize-2" } }, + { red = 3, green = 2, blue = 3, purple = 2, yellow = 1, white = 1 }) +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/automation-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 0, 24 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-factory-s", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-factory-7", "space-science-pack", "warptorio-bridgesize-2" } }, + { red = 3, green = 2, blue = 3, purple = 2, yellow = 1, white = 1 }) +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/automation-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 24, 0 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-factory-e", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-factory-7", "space-science-pack", "warptorio-bridgesize-2" } }, + { red = 3, green = 2, blue = 3, purple = 2, yellow = 1, white = 1 }) +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/automation-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { -24, 0 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-factory-w", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-factory-7", "space-science-pack", "warptorio-bridgesize-2" } }, + { red = 3, green = 2, blue = 3, purple = 2, yellow = 1, white = 1 }) -- ---- -- Boiler Room Upgrades -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-boiler-0",unit={count=100,time=30}, prerequisites={"steel-processing","warptorio-harvester-floor"},upgrade=false, - localised_name={"technology-name.warptorio-boiler"}, - localised_description={"technology-description.warptorio-boiler-floor"}, -}, {red=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-boiler-1",unit={count=100,time=30}, prerequisites={"warptorio-boiler-0","fluid-handling"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-boiler-2",unit={count=200,time=30}, prerequisites={"warptorio-boiler-1","flammables"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-boiler-3",unit={count=300,time=30}, prerequisites={"warptorio-boiler-2","battery"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-boiler-4",unit={count=150,time=30}, prerequisites={"warptorio-boiler-3","chemical-science-pack"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-boiler-5",unit={count=200,time=30}, prerequisites={"warptorio-boiler-4","production-science-pack"}}, {red=2,green=2,blue=1,purple=1}) -ExtendTech(t,{name="warptorio-boiler-6",unit={count=300,time=30}, prerequisites={"warptorio-boiler-5","nuclear-fuel-reprocessing"}}, {red=2,green=2,blue=1,purple=1,}) -ExtendTech(t,{name="warptorio-boiler-7",unit={count=300,time=30}, prerequisites={"warptorio-boiler-6","utility-science-pack"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) - - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/oil-gathering.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-boiler-water-1",upgrade=true,unit={count=500,time=30}, prerequisites={"warptorio-boiler-3","landfill"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-boiler-water-2",upgrade=true,unit={count=500,time=30}, prerequisites={"warptorio-boiler-5","warptorio-boiler-water-1"}}, {red=2,green=2,blue=1,purple=1}) - -ExtendTech(t,{name="warptorio-boiler-water-3",upgrade=true,unit={count=2000,time=30}, prerequisites={"warptorio-boiler-water-2","space-science-pack"}}, {red=1,green=1,blue=1,purple=1,yellow=1,white=1}) - -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={0,-32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-boiler-n",unit={count=1000,time=30}, prerequisites={"warptorio-boiler-7","space-science-pack"}}, {red=3,green=2,blue=2,purple=2,yellow=1,white=1}) - -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={0,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-boiler-s",unit={count=1000,time=30}, prerequisites={"warptorio-boiler-7","space-science-pack"}}, {red=3,green=2,blue=2,purple=2,yellow=1,white=1}) -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,0},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-boiler-e",unit={count=1000,time=30}, prerequisites={"warptorio-boiler-7","space-science-pack"}}, {red=3,green=2,blue=2,purple=2,yellow=1,white=1}) -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/fluid-handling.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={-32,0},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-boiler-w",unit={count=1000,time=30}, prerequisites={"warptorio-boiler-7","space-science-pack"}}, {red=3,green=2,blue=2,purple=2,yellow=1,white=1}) +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { + name = "warptorio-boiler-0", + unit = { count = 100, time = 30 }, + prerequisites = { "steel-processing", "warptorio-harvester-floor" }, + upgrade = false, + localised_name = { "technology-name.warptorio-boiler" }, + localised_description = { "technology-description.warptorio-boiler-floor" }, + }, { red = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 16, 16 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-boiler-1", unit = { count = 100, time = 30 }, prerequisites = { "warptorio-boiler-0", "fluid-handling" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-boiler-2", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-boiler-1", "flammables" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-boiler-3", unit = { count = 300, time = 30 }, prerequisites = { "warptorio-boiler-2", "battery" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-boiler-4", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-boiler-3", "chemical-science-pack" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-boiler-5", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-boiler-4", "production-science-pack" } }, + { red = 2, green = 2, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-boiler-6", unit = { count = 300, time = 30 }, prerequisites = { "warptorio-boiler-5", "nuclear-fuel-reprocessing" } }, + { red = 2, green = 2, blue = 1, purple = 1, }) +ExtendTech(t, + { name = "warptorio-boiler-7", unit = { count = 300, time = 30 }, prerequisites = { "warptorio-boiler-6", "utility-science-pack" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) + + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/oil-gathering.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 16, 16 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-boiler-water-1", upgrade = true, unit = { count = 500, time = 30 }, prerequisites = { "warptorio-boiler-3", "landfill" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-boiler-water-2", upgrade = true, unit = { count = 1000, time = 40 }, prerequisites = { "warptorio-boiler-5", "warptorio-boiler-water-1" } }, + { red = 2, green = 2, blue = 1, purple = 1 }) + +ExtendTech(t, + { name = "warptorio-boiler-water-3", upgrade = true, unit = { count = 2000, time = 50 }, prerequisites = { "warptorio-boiler-water-2", "space-science-pack" } }, + { red = 1, green = 1, blue = 1, purple = 1, yellow = 1, white = 1 }) + +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 0, -24 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-boiler-n", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-boiler-7", "space-science-pack" } }, + { red = 3, green = 2, blue = 2, purple = 2, yellow = 1, white = 1 }) + +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 0, 24 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-boiler-s", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-boiler-7", "space-science-pack" } }, + { red = 3, green = 2, blue = 2, purple = 2, yellow = 1, white = 1 }) +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 24, 0 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-boiler-e", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-boiler-7", "space-science-pack" } }, + { red = 3, green = 2, blue = 2, purple = 2, yellow = 1, white = 1 }) +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/fluid-handling.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { -24, 0 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-boiler-w", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-boiler-7", "space-science-pack" } }, + { red = 3, green = 2, blue = 2, purple = 2, yellow = 1, white = 1 }) @@ -559,36 +1078,78 @@ ExtendTech(t,{name="warptorio-boiler-w",unit={count=1000,time=30}, prerequisites -- ---- -- Harvester Size -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/tank.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} -}, } -ExtendTech(t,{name="warptorio-harvester-floor",unit={count=100,time=30}, prerequisites={"fast-inserter","warptorio-factory-0"},upgrade=false}, {red=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/tank.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-harvester-size-1",unit={count=100,time=30}, prerequisites={"warptorio-harvester-floor","oil-processing"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-harvester-size-2",unit={count=150,time=30}, prerequisites={"warptorio-harvester-size-1","stack-inserter"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-harvester-size-3",unit={count=200,time=30}, prerequisites={"warptorio-harvester-size-2","mining-productivity-1"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-harvester-size-4",unit={count=250,time=30}, prerequisites={"warptorio-harvester-size-3","chemical-science-pack"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-harvester-size-5",unit={count=300,time=30}, prerequisites={"warptorio-harvester-size-4","production-science-pack","mining-productivity-2"}}, {red=2,green=2,blue=1,purple=1}) -ExtendTech(t,{name="warptorio-harvester-size-6",unit={count=350,time=30}, prerequisites={"warptorio-harvester-size-5","nuclear-fuel-reprocessing"}}, {red=2,green=2,blue=1,purple=1,}) -ExtendTech(t,{name="warptorio-harvester-size-7",unit={count=400,time=30}, prerequisites={"warptorio-harvester-size-6","utility-science-pack","mining-productivity-3"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) - - -for v,w in pairs({east={32,0},west={-32,0}})do local odr=(v=="east" and "a-b" or "a-a") -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/tank.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/concrete.png",tint={r=1,g=0.7,b=0.4,a=0.9},shift={w[1],w[2]},scale=0.45,priority="high",icon_mipmaps=4,icon_size=256,}, -}, } ---ExtendTech(t,{name="warptorio-harvester-"..v.."-gate",upgrade=false, unit={count=150,time=25}, prerequisites={"warptorio-harvester-floor"}}, {red=1,green=1} ) - -ExtendTech(t,{name="warptorio-harvester-"..v.."-1", order=odr, unit={count=150,time=25}, prerequisites={"warptorio-harvester-floor"},localised_description={"technology-description.warptorio-harvester-"..v.."-gate"}}, {red=1,green=1,} ) -ExtendTech(t,{name="warptorio-harvester-"..v.."-2", order=odr, unit={count=200,time=25}, prerequisites={"warptorio-harvester-"..v.."-1","mining-productivity-1","military-science-pack"}}, {red=2,green=1,black=1} ) -ExtendTech(t,{name="warptorio-harvester-"..v.."-3", order=odr, unit={count=300,time=25}, prerequisites={"warptorio-harvester-"..v.."-2","mining-productivity-2"}}, {red=2,green=2,black=1,blue=1} ) -ExtendTech(t,{name="warptorio-harvester-"..v.."-4", order=odr, unit={count=400,time=25}, prerequisites={"warptorio-harvester-"..v.."-3","nuclear-fuel-reprocessing"}}, {red=2,green=2,black=1,blue=1,purple=1} ) -ExtendTech(t,{name="warptorio-harvester-"..v.."-5", order=odr, unit={count=500,time=25}, prerequisites={"warptorio-harvester-"..v.."-4","mining-productivity-3"}}, {red=2,green=2,black=1,blue=1,purple=1,yellow=1} ) +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/tank.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } + }, +} +ExtendTech(t, + { name = "warptorio-harvester-floor", unit = { count = 100, time = 30 }, prerequisites = { "fast-inserter", "warptorio-factory-0" }, upgrade = false }, + { red = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 256, + icons = { + { icon = "__base__/graphics/technology/tank.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, shift = { 16, 16 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-harvester-size-1", unit = { count = 100, time = 30 }, prerequisites = { "warptorio-harvester-floor", "oil-processing" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-harvester-size-2", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-harvester-size-1", "bulk-inserter" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-harvester-size-3", unit = { count = 200, time = 30 }, prerequisites = { "warptorio-harvester-size-2", "mining-productivity-1" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-harvester-size-4", unit = { count = 250, time = 30 }, prerequisites = { "warptorio-harvester-size-3", "chemical-science-pack" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-harvester-size-5", unit = { count = 300, time = 30 }, prerequisites = { "warptorio-harvester-size-4", "production-science-pack", "mining-productivity-2" } }, + { red = 2, green = 2, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-harvester-size-6", unit = { count = 350, time = 30 }, prerequisites = { "warptorio-harvester-size-5", "nuclear-fuel-reprocessing" } }, + { red = 2, green = 2, blue = 1, purple = 1, }) +ExtendTech(t, + { name = "warptorio-harvester-size-7", unit = { count = 400, time = 30 }, prerequisites = { "warptorio-harvester-size-6", "utility-science-pack", "mining-productivity-3" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) + + +for v, w in pairs({ east = { 24, 0 }, west = { -24, 0 } }) do + local odr = (v == "east" and "a-b" or "a-a") + local t = { + type = "technology", + upgrade = true, + icon_size = 256, + icons = { + { icon = "__base__/graphics/technology/tank.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/concrete.png", tint = { r = 1, g = 0.7, b = 0.4, a = 0.9 }, shift = { w[1], w[2] }, scale = 0.25, priority = "high", icon_mipmaps = 4, icon_size = 256, }, + }, + } + --ExtendTech(t,{name="warptorio-harvester-"..v.."-gate",upgrade=false, unit={count=150,time=25}, prerequisites={"warptorio-harvester-floor"}}, {red=1,green=1} ) + + ExtendTech(t, + { name = "warptorio-harvester-" .. v .. "-1", order = odr, unit = { count = 150, time = 25 }, prerequisites = { "warptorio-harvester-floor" }, localised_description = { "technology-description.warptorio-harvester-" .. v .. "-gate" } }, + { red = 1, green = 1, }) + ExtendTech(t, + { name = "warptorio-harvester-" .. v .. "-2", order = odr, unit = { count = 200, time = 25 }, prerequisites = { "warptorio-harvester-" .. v .. "-1", "mining-productivity-1", "military-science-pack" } }, + { red = 2, green = 1, black = 1 }) + ExtendTech(t, + { name = "warptorio-harvester-" .. v .. "-3", order = odr, unit = { count = 300, time = 25 }, prerequisites = { "warptorio-harvester-" .. v .. "-2", "mining-productivity-2" } }, + { red = 2, green = 2, black = 1, blue = 1 }) + ExtendTech(t, + { name = "warptorio-harvester-" .. v .. "-4", order = odr, unit = { count = 400, time = 25 }, prerequisites = { "warptorio-harvester-" .. v .. "-3", "nuclear-fuel-reprocessing" } }, + { red = 2, green = 2, black = 1, blue = 1, purple = 1 }) + ExtendTech(t, + { name = "warptorio-harvester-" .. v .. "-5", order = odr, unit = { count = 500, time = 25 }, prerequisites = { "warptorio-harvester-" .. v .. "-4", "mining-productivity-3" } }, + { red = 2, green = 2, black = 1, blue = 1, purple = 1, yellow = 1 }) end --[[ todo @@ -604,93 +1165,166 @@ end -- ---- -- Logistics -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/logistics-1.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/logistics-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, }, } -ExtendTech(t,{name="warptorio-logistics-1", unit={count=100,time=20}, prerequisites={"logistics","warptorio-factory-0"},upgrade=false}, {red=1} ) -ExtendTech(t,{name="warptorio-logistics-2", unit={count=200,time=20}, prerequisites={"logistics-2","warptorio-logistics-1"}}, {red=2,green=1} ) -ExtendTech(t,{name="warptorio-logistics-3", unit={count=300,time=20}, prerequisites={"logistics-3","warptorio-logistics-2"}}, {red=2,green=2,blue=1,purple=1} ) -ExtendTech(t,{name="warptorio-logistics-4", unit={count=400,time=20}, prerequisites={"logistic-system","warptorio-logistics-3"}}, {red=2,green=2,blue=1,purple=1,yellow=1} ) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/logistics-1.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/logistics-2.png",tint={r=1,g=1,b=0.7,a=0.9},shift={24,24},scale=0.4,priority="medium",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/logistics-3.png",tint={r=1,g=1,b=0.7,a=0.9},shift={-24,24},scale=0.4,priority="medium",icon_mipmaps=4,icon_size=256,}, +ExtendTech(t, + { name = "warptorio-logistics-1", unit = { count = 100, time = 20 }, prerequisites = { "logistics", "warptorio-factory-0" }, upgrade = false }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-logistics-2", unit = { count = 200, time = 20 }, prerequisites = { "logistics-2", "warptorio-logistics-1" } }, + { red = 2, green = 1 }) +ExtendTech(t, + { name = "warptorio-logistics-3", unit = { count = 300, time = 20 }, prerequisites = { "logistics-3", "warptorio-logistics-2" } }, + { red = 2, green = 2, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-logistics-4", unit = { count = 400, time = 20 }, prerequisites = { "logistic-system", "warptorio-logistics-3" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/logistics-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/logistics-2.png", tint = { r = 1, g = 1, b = 0.7, a = 0.9 }, shift = { -14, 12 }, scale = 0.2, priority = "medium", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/logistics-3.png", tint = { r = 1, g = 1, b = 0.7, a = 0.9 }, shift = { 14, 12 }, scale = 0.2, priority = "medium", icon_mipmaps = 4, icon_size = 256, }, }, } -ExtendTech(t,{name="warptorio-dualloader-1", unit={count=1000,time=10}, prerequisites={"logistics-2","warptorio-logistics-1"}}, {red=1,green=1} ) +ExtendTech(t, + { name = "warptorio-dualloader-1", unit = { count = 500, time = 20 }, prerequisites = { "logistics-2", "warptorio-logistics-1" } }, + { red = 1, green = 1 }) --ExtendTech(t,{name="warptorio-dualloader-2", unit={count=1000,time=15}, prerequisites={"logistics-2","warptorio-dualloader-1"}}, {red=2,green=1} ) --ExtendTech(t,{name="warptorio-dualloader-3", unit={count=1000,time=20}, prerequisites={"logistics-3","warptorio-dualloader-2","production-science-pack"}}, {red=3,green=2,blue=1,purple=1} ) -t.upgrade=false - -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/logistics-1.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/logistics-1.png",tint={r=1,g=1,b=0.7,a=0.9},shift={-28,-12},scale=0.4,priority="medium",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/logistics-1.png",tint={r=1,g=1,b=0.7,a=0.9},shift={28,-12},scale=0.4,priority="medium",icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/logistics-1.png",tint={r=1,g=1,b=0.7,a=0.9},shift={0,32},scale=0.4,priority="high",icon_mipmaps=4,icon_size=256,}, +t.upgrade = false + +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/logistics-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/logistics-1.png", tint = { r = 1, g = 1, b = 0.7, a = 0.9 }, shift = { -16, -6 }, scale = 0.2, priority = "medium", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/logistics-2.png", tint = { r = 1, g = 1, b = 0.7, a = 0.9 }, shift = { 16, -6 }, scale = 0.2, priority = "medium", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/logistics-3.png", tint = { r = 1, g = 1, b = 0.7, a = 0.9 }, shift = { 0, 16 }, scale = 0.2, priority = "medium", icon_mipmaps = 4, icon_size = 256, }, }, } -ExtendTech(t,{name="warptorio-triloader", unit={count=10000,time=10}, prerequisites={"warptorio-logistics-1"}}, {red=1} ) +ExtendTech(t, + { name = "warptorio-triloader", unit = { count = 1000, time = 30 }, prerequisites = { "warptorio-dualloader-1", "chemical-science-pack" } }, + { red = 1, green = 1, blue = 1 }) -- ---- -- Warp Loader -local t={type="technology",upgrade=false,icon_size=128,icons={ - {icon="__base__/graphics/technology/logistics-1.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_mipmaps=4,icon_size=256,}, - {icon="__warptorio2__/graphics/technology/earth.png",tint={r=0.8,g=0.8,b=1,a=1},scale=1,shift={32,32},priority="high",} - }, effects={ {recipe="warptorio-warploader",type="unlock-recipe"} }, +local t = { + type = "technology", + upgrade = false, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/logistics-1.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_mipmaps = 4, icon_size = 256, }, + { icon = "__warptorio2__/graphics/technology/earth.png", tint = { r = 0.8, g = 0.8, b = 1, a = 1 }, scale = 1, shift = { 32, 32 }, priority = "high", icon_size = 128, scale = 0.5 } + }, + effects = { { recipe = "warptorio-warploader", type = "unlock-recipe" } }, } -ExtendTech(t,{name="warptorio-warploader", unit={count=10000,time=10}, prerequisites={"warptorio-armor","warptorio-warpmodule","warptorio-warpnuke","warptorio-warpport"}}, {red=1,green=1,blue=1,purple=1,yellow=1,white=1} ) +ExtendTech(t, + { name = "warptorio-warploader", unit = { count = 10000, time = 60 }, prerequisites = { "warptorio-armor", "warptorio-warpmodule", "warptorio-warpnuke", "warptorio-warpport" } }, + { red = 1, green = 1, blue = 1, purple = 1, yellow = 1, white = 1 }) -- ---- -- Energy Upgrades -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/electric-energy-acumulators.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, } -ExtendTech(t,{name="warptorio-energy-1",unit={count=30,time=20}, prerequisites={"warptorio-factory-0"},upgrade=false}, {red=1}) -ExtendTech(t,{name="warptorio-energy-2",unit={count=100,time=25}, prerequisites={"warptorio-energy-1","electric-energy-distribution-1"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-energy-3",unit={count=150,time=30}, prerequisites={"warptorio-energy-2","advanced-electronics"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-energy-4",unit={count=200,time=35}, prerequisites={"warptorio-energy-3","electric-energy-distribution-2","advanced-electronics-2"}}, {red=1,green=1,blue=1}) -ExtendTech(t,{name="warptorio-energy-5",unit={count=250,time=40}, prerequisites={"warptorio-energy-4","utility-science-pack","production-science-pack"}}, {red=1,green=1,blue=1,purple=1,yellow=1}) +local t = { type = "technology", upgrade = true, icon_size = 128, icons = { { icon = "__base__/graphics/technology/electric-energy-acumulators.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, } +ExtendTech(t, + { name = "warptorio-energy-1", unit = { count = 30, time = 20 }, prerequisites = { "warptorio-factory-0" }, upgrade = false }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-energy-2", unit = { count = 100, time = 25 }, prerequisites = { "warptorio-energy-1", "electric-energy-distribution-1" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-energy-3", unit = { count = 150, time = 30 }, prerequisites = { "warptorio-energy-2", "advanced-circuit" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-energy-4", unit = { count = 200, time = 35 }, prerequisites = { "warptorio-energy-3", "electric-energy-distribution-2", "processing-unit" } }, + { red = 1, green = 1, blue = 1 }) +ExtendTech(t, + { name = "warptorio-energy-5", unit = { count = 250, time = 40 }, prerequisites = { "warptorio-energy-4", "utility-science-pack", "production-science-pack" } }, + { red = 1, green = 1, blue = 1, purple = 1, yellow = 1 }) -- ---- -- Teleporter -local t={type="technology",upgrade=true,icon_size=128,icons={ {icon="__base__/graphics/technology/research-speed.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,} }, } -ExtendTech(t,{name="warptorio-teleporter-portal",unit={count=30,time=20}, prerequisites={"warptorio-factory-0","electronics",},upgrade=false}, {red=1}) -ExtendTech(t,{name="warptorio-teleporter-1",unit={count=30,time=20}, prerequisites={"warptorio-teleporter-portal","electric-energy-distribution-1"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-teleporter-2",unit={count=30,time=20}, prerequisites={"warptorio-teleporter-1","advanced-electronics"}}, {red=2,green=2,}) -ExtendTech(t,{name="warptorio-teleporter-3",unit={count=30,time=20}, prerequisites={"warptorio-teleporter-2","electric-energy-distribution-2","advanced-electronics-2"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-teleporter-4",unit={count=30,time=20}, prerequisites={"warptorio-teleporter-3","nuclear-power"}}, {red=2,green=2,blue=2,}) -ExtendTech(t,{name="warptorio-teleporter-5",unit={count=30,time=20}, prerequisites={"warptorio-teleporter-4","utility-science-pack","production-science-pack"}}, {red=2,green=3,blue=2,purple=1,yellow=1}) +local t = { type = "technology", upgrade = true, icon_size = 128, icons = { { icon = "__base__/graphics/technology/research-speed.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, } }, } +ExtendTech(t, + { name = "warptorio-teleporter-portal", unit = { count = 50, time = 20 }, prerequisites = { "warptorio-factory-0", "electronics", }, upgrade = false }, + { red = 1 }) +ExtendTech(t, + { name = "warptorio-teleporter-1", unit = { count = 100, time = 20 }, prerequisites = { "warptorio-teleporter-portal", "electric-energy-distribution-1" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-teleporter-2", unit = { count = 150, time = 20 }, prerequisites = { "warptorio-teleporter-1", "advanced-circuit" } }, + { red = 2, green = 2, }) +ExtendTech(t, + { name = "warptorio-teleporter-3", unit = { count = 200, time = 20 }, prerequisites = { "warptorio-teleporter-2", "electric-energy-distribution-2", "processing-unit" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-teleporter-4", unit = { count = 250, time = 20 }, prerequisites = { "warptorio-teleporter-3", "nuclear-power" } }, + { red = 2, green = 2, blue = 2, }) +ExtendTech(t, + { name = "warptorio-teleporter-5", unit = { count = 300, time = 20 }, prerequisites = { "warptorio-teleporter-4", "utility-science-pack", "production-science-pack" } }, + { red = 2, green = 3, blue = 2, purple = 1, yellow = 1 }) -- ---- -- Beacon -local t={type="technology",upgrade=true,icon_size=64,icons={ {icon="__base__/graphics/icons/beacon.png",tint={r=0.3,g=0.3,b=1,a=1}} }, } -ExtendTech(t,{name="warptorio-beacon-1",unit={count=300,time=20}, prerequisites={"modules","warptorio-factory-0"},upgrade=false}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-beacon-2",unit={count=500,time=20}, prerequisites={"warptorio-beacon-1","speed-module","productivity-module","effectivity-module"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-beacon-3",unit={count=300,time=20}, prerequisites={"warptorio-beacon-2","speed-module-2","productivity-module-2","effectivity-module-2"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-beacon-4",unit={count=500,time=20}, prerequisites={"warptorio-beacon-3","speed-module-3","productivity-module-3","effectivity-module-3"}}, {red=2,green=2,blue=1,purple=1}) -ExtendTech(t,{name="warptorio-beacon-5",unit={count="700",time=20}, prerequisites={"warptorio-beacon-4","utility-science-pack"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) -ExtendTech(t,{name="warptorio-beacon-6",unit={count="900",time=20}, prerequisites={"warptorio-beacon-5"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) -ExtendTech(t,{name="warptorio-beacon-7",unit={count="1200",time=20}, prerequisites={"warptorio-beacon-6"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) -ExtendTech(t,{name="warptorio-beacon-8",unit={count="1500",time=20}, prerequisites={"warptorio-beacon-7"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) -ExtendTech(t,{name="warptorio-beacon-9",unit={count="1000",time=20}, prerequisites={"warptorio-beacon-8","space-science-pack"}}, {red=3,green=3,blue=2,purple=1,yellow=1,white=1}) -ExtendTech(t,{name="warptorio-beacon-10",unit={count="2000",time=20}, prerequisites={"warptorio-beacon-9"}}, {red=3,green=3,blue=2,purple=2,yellow=2,white=1}) +local t = { type = "technology", upgrade = true, icon_size = 64, icons = { { icon = "__base__/graphics/icons/beacon.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 } } }, } +ExtendTech(t, + { name = "warptorio-beacon-1", unit = { count = 300, time = 20 }, prerequisites = { "modules", "warptorio-factory-0" }, upgrade = false }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-2", unit = { count = 400, time = 20 }, prerequisites = { "warptorio-beacon-1", "speed-module", "productivity-module", "efficiency-module" } }, + { red = 1, green = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-3", unit = { count = 500, time = 20 }, prerequisites = { "warptorio-beacon-2", "speed-module-2", "productivity-module-2", "efficiency-module-2" } }, + { red = 2, green = 2, blue = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-4", unit = { count = 600, time = 20 }, prerequisites = { "warptorio-beacon-3", "speed-module-3", "productivity-module-3", "efficiency-module-3" } }, + { red = 2, green = 2, blue = 1, purple = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-5", unit = { count = 700, time = 20 }, prerequisites = { "warptorio-beacon-4", "utility-science-pack" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-6", unit = { count = 800, time = 20 }, prerequisites = { "warptorio-beacon-5" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-7", unit = { count = 1000, time = 20 }, prerequisites = { "warptorio-beacon-6" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-8", unit = { count = 1200, time = 20 }, prerequisites = { "warptorio-beacon-7" } }, + { red = 2, green = 2, blue = 1, purple = 1, yellow = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-9", unit = { count = 1500, time = 20 }, prerequisites = { "warptorio-beacon-8", "space-science-pack" } }, + { red = 3, green = 3, blue = 2, purple = 1, yellow = 1, white = 1 }) +ExtendTech(t, + { name = "warptorio-beacon-10", unit = { count = 2000, time = 20 }, prerequisites = { "warptorio-beacon-9" } }, + { red = 3, green = 3, blue = 2, purple = 2, yellow = 2, white = 1 }) --[[ unused local t={type="technology",upgrade=true,icon_size=64,icons={ {icon="__base__/graphics/icons/beacon.png",tint={r=0.3,g=0.3,b=1,a=1}} }, } ExtendTech(t,{name="warptorio-beacon-1",unit={count=300,time=20}, prerequisites={"modules","warptorio-factory-0"},upgrade=false}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-beacon-2",unit={count=500,time=20}, prerequisites={"warptorio-beacon-1","speed-module","productivity-module","effectivity-module"}}, {red=1,green=1}) -ExtendTech(t,{name="warptorio-beacon-3",unit={count=300,time=20}, prerequisites={"warptorio-beacon-2","speed-module-2","productivity-module-2","effectivity-module-2"}}, {red=2,green=2,blue=1}) -ExtendTech(t,{name="warptorio-beacon-4",unit={count=500,time=20}, prerequisites={"warptorio-beacon-3","speed-module-3","productivity-module-3","effectivity-module-3"}}, {red=2,green=2,blue=1,purple=1}) +ExtendTech(t,{name="warptorio-beacon-2",unit={count=500,time=20}, prerequisites={"warptorio-beacon-1","speed-module","productivity-module","efficiency-module"}}, {red=1,green=1}) +ExtendTech(t,{name="warptorio-beacon-3",unit={count=300,time=20}, prerequisites={"warptorio-beacon-2","speed-module-2","productivity-module-2","efficiency-module-2"}}, {red=2,green=2,blue=1}) +ExtendTech(t,{name="warptorio-beacon-4",unit={count=500,time=20}, prerequisites={"warptorio-beacon-3","speed-module-3","productivity-module-3","efficiency-module-3"}}, {red=2,green=2,blue=1,purple=1}) ExtendTech(t,{name="warptorio-beacon-5",unit={count_formula="250+50*L",time=20},max_level=10, prerequisites={"warptorio-beacon-4","utility-science-pack"}}, {red=2,green=2,blue=1,purple=1,yellow=1}) ExtendTech(t,{name="warptorio-beacon-11",unit={count=5,time=1}, prerequisites={"warptorio-beacon-5"}}, {red=5,green=5,blue=5,purple=5,white=5}) ExtendTech(t,{name="warptorio-beacon-12",unit={count=5,time=1}, prerequisites={"warptorio-beacon-11"}}, {red=2,green=5,blue=5,purple=5,white=5}) @@ -700,14 +1334,22 @@ ExtendTech(t,{name="warptorio-beacon-12",unit={count=5,time=1}, prerequisites={" -- ---- -- Warp Beacon -local t=ExtendDataCopy("beacon","beacon",{name="warptorio-beacon-1",supply_area_distance=16,module_specification={module_slots=1}, - base_picture={ tint={r=0.5,g=0.7,b=1,a=1}, }, animation={ tint={r=1,g=0.2,b=0.2,a=1}, }, - allowed_effects={"consumption","speed","pollution","productivity"}, - distribution_effectivity=1, -},true) -for i=2,10,1 do local xt=table.deepcopy(t) xt.name="warptorio-beacon-"..i xt.supply_area_distance=math.min(16+8*i,64) xt.module_specification.module_slots=i data:extend{xt} end - - +local t = ExtendDataCopy("beacon", "beacon", { + name = "warptorio-beacon-1", + supply_area_distance = 16, + module_slots = 1, + base_picture = { tint = { r = 0.5, g = 0.7, b = 1, a = 1 }, }, + animation = { tint = { r = 1, g = 0.2, b = 0.2, a = 1 }, }, + allowed_effects = { "consumption", "speed", "pollution", "productivity" }, + distribution_effectivity = 1, +}, true) +for i = 2, 10, 1 do + local xt = table.deepcopy(t) + xt.name = "warptorio-beacon-" .. i + xt.supply_area_distance = math.min(16 + 8 * i, 64) + xt.module_slots = i + data:extend { xt } +end -- ---- -- Radar @@ -720,34 +1362,71 @@ ExtendTech(t,{name="warptorio-radar-1",unit={count=300,time=15},prerequisites={" -- ---- -- Warp Armor -local t={type="technology",icon_size=128,icons={ {icon="__base__/graphics/technology/power-armor-mk2.png",tint={r=0.3,g=0.3,b=1,a=1},icon_size=256},},prerequisites={"power-armor-mk2","warptorio-reactor-8","space-science-pack",} } -ExtendTech(t,{name="warptorio-armor",unit={count=1000,time=60},effects={{recipe="warptorio-armor",type="unlock-recipe"}}},{red=4,green=4,blue=4,black=5,yellow=2,white=1}) - - -data:extend{{type="equipment-grid",name="warptorio-warparmor-grid",equipment_categories={"armor"},height=16,width=16}} -local t=ExtendDataCopy("armor","power-armor-mk2",{name="warptorio-armor",equipment_grid="warptorio-warparmor-grid", - icon_size=64,icons={{icon="__base__/graphics/icons/power-armor-mk2.png",tint={r=0.3,g=0.3,b=1,a=1},}},inventory_size_bonus=100},false) - -local t=ExtendDataCopy("recipe","power-armor-mk2",{name="warptorio-armor",enabled=false,ingredients={{"power-armor-mk2",5},{"power-armor",5},{"modular-armor",5},{"heavy-armor",5},{"light-armor",5}},result="warptorio-armor"}) +local t = { type = "technology", icon_size = 128, icons = { { icon = "__base__/graphics/technology/power-armor-mk2.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_size = 256 }, }, prerequisites = { "power-armor-mk2", "warptorio-reactor-8", "space-science-pack", } } +ExtendTech(t, + { name = "warptorio-armor", unit = { count = 1000, time = 60 }, effects = { { recipe = "warptorio-armor", type = "unlock-recipe" } } }, + { red = 4, green = 4, blue = 4, black = 5, yellow = 2, white = 1 }) + + +data:extend { { type = "equipment-grid", name = "warptorio-warparmor-grid", equipment_categories = { "armor" }, height = 16, width = 16 } } +local t = ExtendDataCopy("armor", "power-armor-mk2", { + name = "warptorio-armor", + equipment_grid = "warptorio-warparmor-grid", + icon_size = 64, + icons = { { icon = "__base__/graphics/icons/power-armor-mk2.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, } }, + inventory_size_bonus = 100 +}, false) + +local t = ExtendDataCopy("recipe", "power-armor-mk2", + { + name = "warptorio-armor", + enabled = false, + ingredients = { + { type = "item", name = "power-armor-mk2", amount = 1 }, + { type = "item", name = "power-armor", amount = 1 }, + { type = "item", name = "modular-armor", amount = 1 }, + { type = "item", name = "heavy-armor", amount = 1 }, + { type = "item", name = "light-armor", amount = 1 }, + { type = "item", name = "warptorio-warponium-fuel-cell", amount = 10 }, + }, + results = { + { type = "item", name = "warptorio-armor", amount = 1 } + } + }) -- ---- -- Warp Combinators -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/circuit-network.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - --{icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, effects={ - {recipe="warptorio-combinator",type="unlock-recipe"}, -}, } -ExtendTech(t,{name="warptorio-combinator",unit={count=50,time=20}, prerequisites={"circuit-network","chemical-science-pack"}}, {red=1,green=1,blue=1}) - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/circuit-network.png",tint={r=0.3,g=0.3,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__base__/graphics/technology/tank.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-alt-combinator",unit={count=50,time=20}, prerequisites={"circuit-network","production-science-pack","warptorio-harvester-east-1","warptorio-harvester-west-1"}}, {red=1,green=1,blue=1,purple=1}) +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/circuit-network.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + --{icon="__base__/graphics/technology/concrete.png",tint={r=0.7,g=0.7,b=1,a=0.9},priority="medium",shift={32,32},scale=0.5,icon_mipmaps=4,icon_size=256,}, + }, + effects = { + { recipe = "warptorio-combinator", type = "unlock-recipe" }, + }, +} +ExtendTech(t, + { name = "warptorio-combinator", unit = { count = 50, time = 20 }, prerequisites = { "circuit-network", "chemical-science-pack" } }, + { red = 1, green = 1, blue = 1 }) + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/circuit-network.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__base__/graphics/technology/tank.png", tint = { r = 0.7, g = 0.7, b = 1, a = 0.9 }, priority = "medium", shift = { 32, 32 }, scale = 0.25, icon_mipmaps = 4, icon_size = 256, }, + }, +} +ExtendTech(t, + { name = "warptorio-alt-combinator", unit = { count = 50, time = 20 }, prerequisites = { "circuit-network", "production-science-pack", "warptorio-harvester-east-1", "warptorio-harvester-west-1" } }, + { red = 1, green = 1, blue = 1, purple = 1 }) @@ -755,15 +1434,19 @@ ExtendTech(t,{name="warptorio-alt-combinator",unit={count=50,time=20}, prerequis -- Warp Toolbar -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/toolbelt.png",tint={r=0.4,g=0.4,b=1,a=1},icon_mipmaps=4,icon_size=256,}, - {icon="__warptorio2__/graphics/technology/earth.png",tint={r=0.8,g=0.8,b=1,a=0.9},priority="medium",shift={32,32},scale=1}, -},} -ExtendTech(t,{name="warptorio-toolbar",unit={count=2000,time=20}, - prerequisites={"space-science-pack","warptorio-toolbelt-5","warptorio-reach-5","warptorio-harvester-east-5","warptorio-harvester-west-5","warptorio-teleporter-5","warptorio-striders-2"}, -}, - {red=1,green=1,blue=1,purple=1,black=1,yellow=1,white=1} +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/toolbelt.png", tint = { r = 0.4, g = 0.4, b = 1, a = 1 }, icon_mipmaps = 4, icon_size = 256, }, + { icon = "__warptorio2__/graphics/technology/earth.png", tint = { r = 0.8, g = 0.8, b = 1, a = 0.9 }, priority = "medium", shift = { 32, 32 }, icon_size = 128, scale = 0.5 }, + }, +} +ExtendTech(t, { + name = "warptorio-toolbar", + unit = { count = 2000, time = 20 }, + prerequisites = { "space-science-pack", "warptorio-toolbelt-5", "warptorio-reach-5", "warptorio-harvester-east-5", "warptorio-harvester-west-5", "warptorio-teleporter-5", "warptorio-striders-2" }, + }, + { red = 1, green = 1, blue = 1, purple = 1, black = 1, yellow = 1, white = 1 } ) - - - diff --git a/graphics/victory.png b/graphics/victory.png new file mode 100644 index 0000000000000000000000000000000000000000..4baccbbad2a60537610c036d4c49e54516dad43e GIT binary patch literal 414367 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 G7_sz~BAO_ntg{@Ab=95asONsm;xYAH4U`2Oq7M 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%0D(v#k!Q~H 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%0DBYf>JAtMgC3 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

yS2x|wVmV)}+MtLy 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 z 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 literal 0 HcmV?d00001 diff --git a/info.json b/info.json index 8ce6792..ff2f686 100644 --- a/info.json +++ b/info.json @@ -1,10 +1,20 @@ -{ - "name": "warptorio2", - "version": "1.3.11", - "title": "Warptorio", - "author": "Nonoce and PyroFire", - "dependencies": ["base >= 1.1","planetorio", "! space-exploration","! SeaBlock", "! spaceblock","! starshiptorio","! stacktorio", "? NewGamePlus"], - "description": "Build your base on a platform that warps from planet to planet and escape bitters before they overwhelm you.", - "factorio_version": "1.1", - "homepage":"https://www.patreon.com/pyrofire" +{ + "name": "warptorio2", + "version": "2.0.0", + "title": "Warptorio2", + "author": "Nonoce, PyroFire, Shadow_Man", + "description": "Build your base on a platform that warps from planet to planet and escape bitters before they overwhelm you.", + "factorio_version": "2.0", + "homepage":"https://www.patreon.com/pyrofire", + "dependencies": [ + "base >= 2.0", + "planetorio >=0.2.0", + "! space-age", + "! space-exploration", + "! SeaBlock", + "! spaceblock", + "! starshiptorio", + "! stacktorio", + "? NewGamePlus" + ] } \ No newline at end of file diff --git a/lib/lib_control.lua b/lib/lib_control.lua index f9c9a6a..dfc40d3 100644 --- a/lib/lib_control.lua +++ b/lib/lib_control.lua @@ -37,111 +37,229 @@ Status bar wastes screen space, don't use it. Use https://tools.stefankueng.com/grepWin.html to mass search, find and replace many files in bulk. -]]--------------------------------------- +]] --------------------------------------- ---[[ Settings Lib ? ]]-- +--[[ Settings Lib ? ]] -- -function lib.setting(n) return lib.modname.."_"..settings.global[n].value end -function lib.call(r,...) if(istable(r))then return remote.call(r[1],r[2],...) end return r(...) end +function lib.setting(n) return lib.modname .. "_" .. settings.global[n].value end +function lib.call(r, ...) + if (istable(r)) then return remote.call(r[1], r[2], ...) end + return r(...) +end + +--[[ Entity Library ]] -- +function is_entity(x) + return (x.valid ~= nil) +end ---[[ Entity Library ]]-- +entity = {} +function entity.protect(e, min, des) + if (min ~= nil) then e.minable = min end + if (des ~= nil) then e.destructible = des end + return e +end -function is_entity(x) return (x.valid~=nil) end +function entity.spawn(f, n, pos, dir, t) + t = t or {} + local tx = t or {} + tx.name = n + tx.position = { vector.getx(pos), vector.gety(pos) } + tx.direction = dir + tx.player = (t.player or game.players[1]) + tx.force = t.force or game.forces.player + tx.raise_built = true --(t.raise_built~=nil and t.raise_built or true) + local e = f.create_entity(tx) + return e +end +entity.create = entity.spawn -- alias -entity={} -function entity.protect(e,min,des) if(min~=nil)then e.minable=min end if(des~=nil)then e.destructible=des end return e end -function entity.spawn(f,n,pos,dir,t) t=t or {} local tx=t or {} tx.name=n tx.position={vector.getx(pos),vector.gety(pos)} tx.direction=dir tx.player=(t.player or game.players[1]) - tx.force=t.force or game.forces.player - tx.raise_built=true --(t.raise_built~=nil and t.raise_built or true) - local e=f.create_entity(tx) return e +function entity.destroy(e, r, c) + if (e and e.valid) then + e.destroy { raise_destroy = (r ~= nil and r or true), do_cliff_correction = (c ~= nil and c or true) } + end end -entity.create=entity.spawn -- alias -function entity.destroy(e,r,c) if(e and e.valid)then e.destroy{raise_destroy=(r~=nil and r or true),do_cliff_correction=(c~=nil and c or true)} end end -function entity.ChestRequestMode(e) local cb=e.get_or_create_control_behavior() if(cb.type==defines.control_behavior.type.logistic_container)then - cb.circuit_mode_of_operation=defines.control_behavior.logistic_container.circuit_mode_of_operation.set_requests end end -function entity.safeteleport(e,f,pos,bsnap) f=f or e.surface e.teleport(f.find_non_colliding_position(e.is_player() and "character" or e.name,pos or e.position,0,1,bsnap),f) end -function entity.shouldClean(v) return (v.force.name~="player" and v.force.name~="enemy" and v.name:sub(1,9)~="warptorio") end -function entity.tryclean(v) if(v.valid and entity.shouldClean(v))then entity.destroy(v) end end -function entity.emitsound(e,path) for k,v in pairs(game.connected_players)do if(v.surface==e.surface)then v.play_sound{path=path,position=e.position} end end end +function entity.ChestRequestMode(e) + local cb = e.get_or_create_control_behavior() + if (cb.type == defines.control_behavior.type.logistic_container) then + cb.circuit_exclusive_mode_of_operation = defines.control_behavior.logistic_container.exclusive_mode.set_requests + end +end +function entity.safeteleport(e, f, pos, bsnap) + f = f or e.surface + e.teleport(f.find_non_colliding_position(e.is_player() and "character" or e.name, pos or e.position, 0, 1, bsnap), f) +end ---[[ Entity Cloning helpers ]]-- +function entity.shouldClean(v) return (v.force.name ~= "player" and v.force.name ~= "enemy" and v.name:sub(1, 9) ~= "warptorio") end -entity.copy={} entity.copy.__index=entity.copy setmetatable(entity.copy,entity.copy) -function entity.copy.__call(e) end -function entity.copy.chest(a,b) local c=b.get_inventory(defines.inventory.chest) for k,v in pairs(a.get_inventory(defines.inventory.chest).get_contents())do c.insert{name=k,count=v} end - local net=a.circuit_connection_definitions - for c,tbl in pairs(net)do b.connect_neighbour{target_entity=tbl.target_entity,wire=tbl.wire,source_circuit_id=tbl.source_circuit_id,target_circuit_id=tbl.target_circuit_id} end +function entity.tryclean(v) if (v.valid and entity.shouldClean(v)) then entity.destroy(v) end end + +function entity.emitsound(e, path) + for k, v in pairs(game.connected_players) do + if (v.surface == e.surface) then + v + .play_sound { path = path, position = e.position } + end + end end +--[[ Entity Cloning helpers ]] -- + +entity.copy = {} +entity.copy.__index = entity.copy +setmetatable(entity.copy, entity.copy) + +function entity.copy.__call(e) end + +function entity.copy.chest(a, b) + local c = b.get_inventory(defines.inventory.chest) + for k, v in pairs(a.get_inventory(defines.inventory.chest).get_contents()) do + c.insert { name = v.name, count = v.count } + end + local wireconnectors = a.get_wire_connectors(false) + for _, wireconnector in pairs(wireconnectors) do + local bwireconnector = b.get_wire_connector(wireconnector.wire_connector_id, true) + if bwireconnector then + for _, wireconnection in ipairs(wireconnector.connections) do + bwireconnector.connect_to(wireconnection.target, false, wireconnection.origin) + end + for _, wireconnection in ipairs(wireconnector.real_connections) do + bwireconnector.connect_to(wireconnection.target, false, wireconnection.origin) + end + end + end +end -- -------- -- Logistics system function entity.AutoBalancePower(t) -- Auto-balance electricity between all entities in a table - local p=#t local g=0 local c=0 - for k,v in pairs(t)do if(v.valid)then g=g+v.energy c=c+v.electric_buffer_size end end - for k,v in pairs(t)do if(v.valid)then local r=(v.electric_buffer_size/c) v.energy=g*r end end + local p = #t + local g = 0 + local c = 0 + for k, v in pairs(t) do + if (v.valid) then + g = g + v.energy + c = c + v.electric_buffer_size + end + end + for k, v in pairs(t) do + if (v.valid) then + local r = (v.electric_buffer_size / c) + v.energy = g * r + end + end end -function entity.BalancePowerPair(a,b) local x=(a.energy+b.energy)/2 a.energy,b.energy=x,x end - +function entity.BalancePowerPair(a, b) + local x = (a.energy + b.energy) / 2 + a.energy, b.energy = x, x +end --[[Old version, now replaced with: https://mods.factorio.com/mod/warptorio2/discussion/646e46d9225f8dc82fa0a26e function entity.AutoBalanceHeat(t) -- Auto-balance heat between all entities in a table local h=0 for k,v in pairs(t)do h=h+v.temperature end for k,v in pairs(t)do v.temperature=h/#t end end]] function entity.AutoBalanceHeat(t) -- Auto-balance heat between all entities in a table (respecting specific heat) - local e=0 sh=0 tsh=0 - for k,v in pairs(t)do sh=v.prototype.heat_buffer_prototype.specific_heat e=e+v.temperature*sh tsh=tsh+sh end - for k,v in pairs(t)do v.temperature=e/tsh end -end - -function entity.BalanceHeatPair(a,b) -- with respect to specific heat - local ash,bsh = a.prototype.heat_buffer_prototype.specific_heat, b.prototype.heat_buffer_prototype.specific_heat - local x=(a.temperature*ash+b.temperature*bsh)/2 a.temperature,b.temperature=x,x + local e = 0 + sh = 0 + tsh = 0 + for k, v in pairs(t) do + sh = v.prototype.heat_buffer_prototype.specific_heat + e = e + v.temperature * sh + tsh = tsh + sh + end + for k, v in pairs(t) do v.temperature = e / tsh end end -function entity.ShiftHeat(a,b) end -- move temperature from a to b -function entity.ShiftContainer(a,b) -- Shift contents from a to b - local ac,bc=a.get_inventory(defines.inventory.chest),b.get_inventory(defines.inventory.chest) - for k,v in pairs(ac.get_contents())do local t={name=k,count=v} local c=bc.insert(t) if(c>0)then ac.remove({name=k,count=c}) end end +function entity.BalanceHeatPair(a, b) -- with respect to specific heat + local ash, bsh = a.prototype.heat_buffer_prototype.specific_heat, b.prototype.heat_buffer_prototype.specific_heat + local x = (a.temperature * ash + b.temperature * bsh) / 2 + a.temperature, b.temperature = x, x end -function entity.GetFluidTemperature(v) local fb=v.fluidbox if(fb and fb[1])then return fb[1].temperature end return 15 end +function entity.ShiftHeat(a, b) end -- move temperature from a to b -function entity.BalanceFluidPair(a,b) - local af,bf=a.get_fluid_contents(),b.get_fluid_contents() local aff,afv=table.First(af) local bff,bfv=table.First(bf) afv=afv or 0 bfv=bfv or 0 - if((not aff and not bff) or (aff and bff and aff~=bff) or (afv<1 and bfv<1) or (afv==bfv))then return end if(not aff)then aff=bff elseif(not bff)then bff=aff end local v=(afv+bfv)/2 - if(aff=="steam")then local temp=15 local at=entity.GetFluidTemperature(a) local bt=entity.GetFluidTemperature(b) temp=math.max(at,bt) - a.clear_fluid_inside() b.clear_fluid_inside() a.insert_fluid({name=aff,amount=v,temperature=temp}) b.insert_fluid({name=bff,amount=v,temperature=temp}) - else a.clear_fluid_inside() b.clear_fluid_inside() a.insert_fluid({name=aff,amount=v}) b.insert_fluid({name=bff,amount=v}) end +function entity.ShiftContainer(a, b) -- Shift contents from a to b + local ac = a.get_inventory(defines.inventory.chest) + local bc = b.get_inventory(defines.inventory.chest) + for _, iwqc in ipairs(ac.get_contents()) do + local rcount = bc.insert(iwqc) + if rcount > 0 then + iwqc.count = rcount + ac.remove(iwqc) + end + end end +function entity.GetFluidTemperature(v) + local fb = v.fluidbox + if (fb and fb[1]) then return fb[1].temperature end + return 15 +end -function entity.ShiftFluid(a,b) - local af,bf=a.get_fluid_contents(),b.get_fluid_contents() local aff,afv=table.First(af) local bff,bfv=table.First(bf) -- this is apparently broken - if((not aff and not bff) or (aff and bff and aff~=bff) or (afv<1 and bfv<1))then return end - if(aff=="steam")then - local temp=15 local at=entity.GetFluidTemperature(a) local bt=entity.GetFluidTemperature(b) temp=math.max(at,bt) - local c=b.insert_fluid({name=aff,amount=afv,temperature=temp}) if(c>0)then a.remove_fluid{name=aff,amount=c} end - elseif(aff)then - local c=b.insert_fluid({name=aff,amount=afv}) if(c>0)then a.remove_fluid{name=aff,amount=c} end +function entity.BalanceFluidPair(a, b) + local af, bf = a.get_fluid_contents(), b.get_fluid_contents() + local aff, afv = table.First(af) + local bff, bfv = table.First(bf) + afv = afv or 0 + bfv = bfv or 0 + if ((not aff and not bff) or (aff and bff and aff ~= bff) or (afv < 1 and bfv < 1) or (afv == bfv)) then return end + if (not aff) then aff = bff elseif (not bff) then bff = aff end + local v = (afv + bfv) / 2 + if (aff == "steam") then + local temp = 15 + local at = entity.GetFluidTemperature(a) + local bt = entity.GetFluidTemperature(b) + temp = math.max(at, bt) + a.clear_fluid_inside() + b.clear_fluid_inside() + a.insert_fluid({ name = aff, amount = v, temperature = temp }) + b.insert_fluid({ name = bff, amount = v, temperature = temp }) + else + a.clear_fluid_inside() + b.clear_fluid_inside() + a.insert_fluid({ name = aff, amount = v }) + b.insert_fluid({ name = bff, amount = v }) end end -function entity.ShiftBelt(a,b) -- splitters could have up to 4 lines - for i=1,2,1 do local bl=b.get_transport_line(i) if(bl.can_insert_at_back())then local al=a.get_transport_line(i) - local k,v=next(al.get_contents()) if(k and v)then bl.insert_at_back{name=k,count=1} al.remove_item{name=k,count=1} end - end end - +function entity.ShiftFluid(a, b) + local af, bf = a.get_fluid_contents(), b.get_fluid_contents() + local aff, afv = table.First(af) + local bff, bfv = table.First(bf) -- this is apparently broken + if ((not aff and not bff) or (aff and bff and aff ~= bff) or (afv < 1 and bfv < 1)) then return end + if (aff == "steam") then + local temp = 15 + local at = entity.GetFluidTemperature(a) + local bt = entity.GetFluidTemperature(b) + temp = math.max(at, bt) + local c = b.insert_fluid({ name = aff, amount = afv, temperature = temp }) + if (c > 0) then a.remove_fluid { name = aff, amount = c } end + elseif (aff) then + local c = b.insert_fluid({ name = aff, amount = afv }) + if (c > 0) then a.remove_fluid { name = aff, amount = c } end + end end +function entity.ShiftBelt(a, b) -- splitters could have up to 4 lines + for i = 1, 2, 1 do + local bl = b.get_transport_line(i) + if (bl.can_insert_at_back()) then + local al = a.get_transport_line(i) + local k, v = next(al.get_contents()) + if (k and v) then + bl.insert_at_back { name = v.name, count = 1 } + al.remove_item { name = v.name, count = 1 } + end + end + end +end --[[ unused function entity.BalanceLogistics(a,b) if(not a or not b or not a.valid or not b.valid)then return end -- cost is removed because it's derp @@ -166,15 +284,26 @@ end ---[[ Player Library ]]-- +--[[ Player Library ]] -- + +players = {} +function players.find(f, area) + local t = {} + for k, v in pairs(game.players) do if (v.surface == f and vector.inarea(v.position, area)) then table.insert(t, v) end end + return t +end -players={} -function players.find(f,area) local t={} for k,v in pairs(game.players)do if(v.surface==f and vector.inarea(v.position,area))then table.insert(t,v) end end return t end -function players.playsound(path,f,pos) - if(f)then f.play_sound{path=path,position=pos} else game.forces.player.play_sound{path=path,position=pos} end +function players.playsound(path, f, pos) + if (f) then f.play_sound { path = path, position = pos } else game.forces.player.play_sound { path = path, position = pos } end end -function players.safeclean(e,tpo) local f=e.surface local pos=tpo or e.position - if(tpo or f.count_entities_filtered{area=vector.square(vector.pos(pos),vector(0.5,0.5))}>1)then entity.safeteleport(e,f,pos) end + +function players.safeclean(e, tpo) + local f = e.surface + local pos = tpo or e.position + if (tpo or f.count_entities_filtered { area = vector.square(vector.pos(pos), vector(0.5, 0.5)) } > 1) then + entity + .safeteleport(e, f, pos) + end end --[[ todo @@ -208,100 +337,193 @@ end ---[[ Technology Library ]]-- +--[[ Technology Library ]] -- + +research = {} +function research.get(n, f) + f = f or game.forces.player + return f.technologies[n] +end + +function research.has(n, f) return research.get(n, f).researched end + +function research.can(n, f) + local r = research.get(n, f) + if (r.researched) then return true end + local x = table_size(r.prerequisites) + for k, v in pairs(r.prerequisites) do if (v.researched) then x = x - 1 end end + return (x == 0) +end -research={} -function research.get(n,f) f=f or game.forces.player return f.technologies[n] end -function research.has(n,f) return research.get(n,f).researched end -function research.can(n,f) local r=research.get(n,f) if(r.researched)then return true end local x=table_size(r.prerequisites) for k,v in pairs(r.prerequisites)do if(v.researched)then x=x-1 end end return (x==0) end --function research.level(n,f) f=f or game.forces.player local ft=f.technologies local r=ft[n.."-0"] or ft[n.."-1"] local i=0 while(r)do if(r.researched)then i=r.level r=ft[n.."-".. i+1] else r=nil end end return i end -function research.level(n,f) f=f or game.forces.player local ft=f.technologies local i,r=0,ft[n.."-0"] or ft[n.."-1"] - while(r)do if not r.researched then i=r.level-1 r=nil else i=r.level r=ft[n.."-".. i+1] end end +function research.level(n, f) + f = f or game.forces.player + local ft = f.technologies + local i, r = 0, ft[n .. "-0"] or ft[n .. "-1"] + while (r) do + if not r.researched then + i = r.level - 1 + r = nil + else + i = r.level + r = ft[n .. "-" .. i + 1] + end + end return i -end -- Thanks Bilka!! +end -- Thanks Bilka!! ---[[ Surfaces Library ]]-- -surfaces={} +--[[ Surfaces Library ]] -- +surfaces = {} function surfaces.BlankSurface(n) end -function surfaces.spawnbiters(type,n,f) local tbl=game.surfaces[f].find_entities_filtered{type="character"} - for k,v in ipairs(tbl)do - for j=1,n do local a,d=math.random(0,2*math.pi),150 local x,y=math.cos(a)*d+v.position.x,math.sin(a)*d+v.position.y - local p=game.surfaces[f].find_non_colliding_position(t,{x,y},0,2,1) - local e=game.surfaces[f].create_entity{name=type,position=p} + +function surfaces.spawnbiters(type, n, f) + local tbl = game.surfaces[f].find_entities_filtered { type = "character" } + for k, v in ipairs(tbl) do + for j = 1, n do + local a, d = math.random(0, 2 * math.pi), 150 + local x, y = math.cos(a) * d + v.position.x, math.sin(a) * d + v.position.y + local p = game.surfaces[f].find_non_colliding_position(t, { x, y }, 0, 2, 1) + local e = game.surfaces[f].create_entity { name = type, position = p } end - game.surfaces[f].set_multi_command{command={type=defines.command.attack,target=v},unit_count=n} + game.surfaces[f].set_multi_command { command = { type = defines.command.attack, target = v }, unit_count = n } end end -function surfaces.EmitText(f,pos,text) f.create_entity{name="tutorial-flying-text", text=text, position=pos} end - - ---[[ Events Library ]]-- - -events={} -events.defs={} -events.vdefs={} -events.filters={} -events.loadfuncs={} -events.initfuncs={} -events.migratefuncs={} -events.tickers={} -local events_with_filters={"on_built_entity","on_cancelled_deconstruction","on_cancelled_upgrade","on_entity_damaged","on_entity_died","on_marked_for_deconstruction", - "on_marked_for_upgrade","on_player_mined_item","on_player_repaired_entity","on_post_entity_died","on_pre_ghost_deconstructed","on_pre_player_mined_item","on_robot_built_entity", - "on_robot_mined","on_robot_pre_mined","on_player_mined_entity",} -events.events_with_filters={} -for k,v in pairs(events_with_filters)do events.events_with_filters[v]=v end +function surfaces.EmitText(f, pos, text) f.create_entity { name = "tutorial-flying-text", text = text, position = pos } end + +--[[ Events Library ]] -- + +events = {} +events.defs = {} +events.vdefs = {} +events.filters = {} +events.loadfuncs = {} +events.initfuncs = {} +events.migratefuncs = {} +events.tickers = {} +local events_with_filters = { "on_built_entity", "on_cancelled_deconstruction", "on_cancelled_upgrade", + "on_entity_damaged", "on_entity_died", "on_marked_for_deconstruction", + "on_marked_for_upgrade", "on_player_mined_item", "on_player_repaired_entity", "on_post_entity_died", + "on_pre_ghost_deconstructed", "on_pre_player_mined_item", "on_robot_built_entity", + "on_robot_mined", "on_robot_pre_mined", "on_player_mined_entity", } +events.events_with_filters = {} +for k, v in pairs(events_with_filters) do events.events_with_filters[v] = v end + + +for k, v in pairs(defines.events) do events.defs[v] = {} end +function events.hook(nm, func, fts) + if (istable(nm)) then + for k, v in pairs(nm) do events.hook(v, func, fts) end + return + end + local nm = (isnumber(nm) and nm or defines.events[nm]) + events.defs[nm] = events.defs[nm] or {} + table.insert(events.defs[nm], func) + if (fts) then + events.filters[nm] = events.filters[nm] or {} + for k, v in pairs(fts) do table.insert(events.filters[nm], table.deepcopy(v)) end + end +end -for k,v in pairs(defines.events)do events.defs[v]={} end -function events.hook(nm,func,fts) if(istable(nm))then for k,v in pairs(nm)do events.hook(v,func,fts) end return end - local nm=(isnumber(nm) and nm or defines.events[nm]) events.defs[nm]=events.defs[nm] or {} table.insert(events.defs[nm],func) - if(fts)then events.filters[nm]=events.filters[nm] or {} for k,v in pairs(fts)do table.insert(events.filters[nm],table.deepcopy(v)) end end +events.on_event = events.hook -- alias +function events.raise(name, ev) + ev = ev or {} + ev.name = ev.name or table.KeyFromName(defines.events, name) + script.raise_event(name, ev) end -events.on_event=events.hook -- alias -function events.raise(name,ev) ev=ev or {} ev.name=ev.name or table.KeyFromName(defines.events,name) script.raise_event(name,ev) end -function events.register(name) events.vdefs[name]=script.generate_event_name() end +function events.register(name) events.vdefs[name] = script.generate_event_name() end + -- unused function events.vhook(name,func) if(istable(name))then for k,v in pairs(nm)do events.vhook(name,func) end end events.vhooks[name]=func end -function events.vraise(name,ev) ev=ev or {} ev.name=name script.raise_event(events.vdefs[name],ev) end +function events.vraise(name, ev) + ev = ev or {} + ev.name = name + script.raise_event(events.vdefs[name], ev) +end function events.entity(ev) return ev.entity or ev.created_entity or ev.destination or ev.mine end + function events.source(ev) return ev.source end + function events.destination(ev) return ev.created_entity or ev.destination end + function events.surface(ev) return ev.surface or game.surfaces[ev.surface_index] end -function events.on_load(f) table.insert(events.loadfuncs,f) end -function events.on_init(f) table.insert(events.initfuncs,f) end -function events.on_migrate(f) table.insert(events.migratefuncs,f) end -events.on_config=events.on_migrate events.on_configration_changed=events.on_migrate -- aliases -function events.raise_load() cache.load() for k,v in ipairs(events.loadfuncs)do v() end if(lib.PLANETORIO)then lib.planets.lua() end end -function events.raise_init() cache.init() for k,v in ipairs(events.initfuncs)do v() end if(lib.PLANETORIO)then lib.planets.lua() end end -function events.raise_migrate(ev) cache.migrate(ev) for k,v in ipairs(events.migratefuncs)do v(ev or {}) end if(lib.PLANETORIO)then lib.planets.lua() end end +function events.on_load(f) table.insert(events.loadfuncs, f) end -function events.on_tick(rate,offset,fnm,func) - local r=events.tickers[rate] or {} events.tickers[rate]=r local o=r[offset] or {} r[offset]=o o[fnm]=func - script.on_event(defines.events.on_tick,events.raise_tick) +function events.on_init(f) table.insert(events.initfuncs, f) end + +function events.on_migrate(f) table.insert(events.migratefuncs, f) end + +events.on_config = events.on_migrate +events.on_configration_changed = events.on_migrate -- aliases +function events.raise_load() + cache.load() + for k, v in ipairs(events.loadfuncs) do v() end + if (lib.PLANETORIO) then lib.planets.lua() end +end + +function events.raise_init() + cache.init() + for k, v in ipairs(events.initfuncs) do v() end + if (lib.PLANETORIO) then lib.planets.lua() end +end + +function events.raise_migrate(ev) + cache.migrate(ev) + for k, v in ipairs(events.migratefuncs) do v(ev or {}) end + if (lib.PLANETORIO) then lib.planets.lua() end +end + +function events.on_tick(rate, offset, fnm, func) + local r = events.tickers[rate] or {} + events.tickers[rate] = r + local o = r[offset] or {} + r[offset] = o + o[fnm] = func + script.on_event(defines.events.on_tick, events.raise_tick) +end + +function events.un_tick(rate, offset, fnm) + local r = events.tickers[rate] or {} + events.tickers[rate] = r + local o = r[offset] or {} + r[offset] = o + o[fnm] = nil + if (table_size(o) == 0) then r[offset] = nil end + if (table_size(r) == 0) then events.tickers[rate] = nil end + if (table_size(events.tickers) == 0) then script.on_event(defines.events.on_tick, nil) end end -function events.un_tick(rate,offset,fnm) local r=events.tickers[rate] or {} events.tickers[rate]=r local o=r[offset] or {} r[offset]=o o[fnm]=nil - if(table_size(o)==0)then r[offset]=nil end - if(table_size(r)==0)then events.tickers[rate]=nil end - if(table_size(events.tickers)==0)then script.on_event(defines.events.on_tick,nil) end + +function events.raise_tick(ev) + for rt, ff in pairs(events.tickers) do + for x, y in pairs(ff) do + if (ev.tick % rt == x) then + for a, b in pairs(y) do + b(ev.tick) + end + end + end + end end -function events.raise_tick(ev) for rt,ff in pairs(events.tickers)do for x,y in pairs(ff)do if(ev.tick%rt==x)then for a,b in pairs(y)do b(ev.tick) end end end end end function events.inject() --error(serpent.block(events.filters[defines.events.on_built_entity])) - for k,v in pairs(events.defs)do if(v and table_size(v)>0)then - if(events.events_with_filters[table.KeyFromValue(defines.events,k)] and events.filters[k] and table_size(events.filters[k])>0)then - --if(k==defines.events.on_built_entity and #events.filters[k]>0)then error(k..":\n"..serpent.block(events.filters[k])) end - script.on_event(k,function(ev) for x,y in pairs(v)do y(ev) end end,events.filters[k]) - else script.on_event(k,function(ev) for x,y in pairs(v)do y(ev) end end) + for k, v in pairs(events.defs) do + if (v and table_size(v) > 0) then + if (events.events_with_filters[table.KeyFromValue(defines.events, k)] and events.filters[k] and table_size(events.filters[k]) > 0) then + --if(k==defines.events.on_built_entity and #events.filters[k]>0)then error(k..":\n"..serpent.block(events.filters[k])) end + script.on_event(k, function(ev) for x, y in pairs(v) do y(ev) end end, events.filters[k]) + else + script.on_event(k, function(ev) for x, y in pairs(v) do y(ev) end end) + end end - end end - if(table_size(events.tickers)>0)then script.on_event(defines.events.on_tick,events.raise_tick) end + end + if (table_size(events.tickers) > 0) then script.on_event(defines.events.on_tick, events.raise_tick) end @@ -310,26 +532,27 @@ function events.inject() script.on_configuration_changed(events.raise_migrate) end - - -- -------- -- Gui -vgui=vgui or {} -function vgui.create(parent,tbl) - local elm=parent[tbl.name] if(not isvalid(elm))then elm=parent.add(tbl) end - for k,v in pairs(tbl)do if(vgui.mods[k])then vgui.mods[k](elm,v) end end +vgui = vgui or {} +function vgui.create(parent, tbl) + local elm = parent[tbl.name] + if (not isvalid(elm)) then elm = parent.add(tbl) end + for k, v in pairs(tbl) do if (vgui.mods[k]) then vgui.mods[k](elm, v) end end return elm end +vgui.mods = {} +vmods = vgui.mods +function vmods.horizontal_align(e, v) e.style.horizontal_align = v end +function vmods.vertical_align(e, v) e.style.vertical_align = v end -vgui.mods={} vmods=vgui.mods -function vmods.horizontal_align(e,v) e.style.horizontal_align=v end -function vmods.vertical_align(e,v) e.style.vertical_align=v end -function vmods.align(e,v) e.style.horizontal_align=(istable(v) and v[1] or v) e.style.vertical_align=istable(v and v[2] or v) end - +function vmods.align(e, v) + e.style.horizontal_align = (istable(v) and v[1] or v) + e.style.vertical_align = istable(v and v[2] or v) +end -- -------- -- Remotes - diff --git a/lib/lib_control_cache.lua b/lib/lib_control_cache.lua index d6b6a31..d24e3c6 100644 --- a/lib/lib_control_cache.lua +++ b/lib/lib_control_cache.lua @@ -118,16 +118,16 @@ function cache.player(tbl) cache.players=tbl end cache.events={} -- Functions to distribute individual events among the caches in correct orders function cache.init() - global._lib=global._lib or {} + storage._lib=storage._lib or {} cache.migrate() end function cache.migrate(ev) - if(global._libcache)then global._lib={cache=global._libcache} global._libcache=nil else global._lib=global._lib or {cache={}} end -- global._lib.cache - global._lib.cache=global._lib.cache or {} - for key,category in pairs(cache.primaries)do -- global._lib[raised_type] - global._lib[category]=global._lib[category] or {} - global._lib[category.."_idx"]=global._lib[category.."_idx"] or {} + if(storage._libcache)then storage._lib={cache=storage._libcache} storage._libcache=nil else storage._lib=storage._lib or {cache={}} end -- storage._lib.cache + storage._lib.cache=storage._lib.cache or {} + for key,category in pairs(cache.primaries)do -- storage._lib[raised_type] + storage._lib[category]=storage._lib[category] or {} + storage._lib[category.."_idx"]=storage._lib[category.."_idx"] or {} end end @@ -136,10 +136,10 @@ function cache.load() end -- helper functions for simple caching -function cache.insert(n,ent) global._lib.cache[n]=global._lib.cache[n] or {} table.insertExclusive(global._lib.cache[n],ent) end -function cache.validate(n) global._lib.cache[n]=global._lib.cache[n] or {} for k,v in pairs(global._lib.cache[n])do if(not isvalid(v))then global._lib.cache[n][k]=nil end end end -function cache.remove(n,ent) global._lib.cache[n]=global._lib.cache[n] or {} table.RemoveByValue(global._lib.cache[n],ent) end -function cache.get(n) if(isstring(n))then return global._lib.cache[n] or {} end end +function cache.insert(n,ent) storage._lib.cache[n]=storage._lib.cache[n] or {} table.insertExclusive(storage._lib.cache[n],ent) end +function cache.validate(n) storage._lib.cache[n]=storage._lib.cache[n] or {} for k,v in pairs(storage._lib.cache[n])do if(not isvalid(v))then storage._lib.cache[n][k]=nil end end end +function cache.remove(n,ent) storage._lib.cache[n]=storage._lib.cache[n] or {} table.RemoveByValue(storage._lib.cache[n],ent) end +function cache.get(n) if(isstring(n))then return storage._lib.cache[n] or {} end end --function cache.call(n,evn,ev,...) for k,v in pairs(cache.get(n))do ev.entity=v cache.call_ents(evn,ev,...) end end -- Call a simple event on all entities in a cache table. function cache.entcall(n,evn,ev,...) for k,v in pairs(cache.get(n))do ev.entity=v cache.call_ents(evn,ev,...) end end -- Call a simple event on all entities in a cache table. function cache.surfacecall(n,evn,ev,...) for k,v in pairs(cache.get(n))do ev.entity=v cache.call_surfaces(evn,ev,...) end end -- Call a simple event on all entities in a cache table. @@ -179,14 +179,14 @@ function cache.get_index(host,key) return host[key] end function cache.raise_type(vtype,name,host,...) local uid if(isnumber(host))then uid=host else local cx cx,uid=pcall(cache.get_index,host,"index") if(not cx)then cx,uid=pcall(cache.get_index,host,"unit_number") if(not cx)then uid=nil end end end local hdx=uid - if(hdx)then local gc=global._lib[vtype.."_idx"][hdx] if(gc and name)then gc=gc[name] end if(gc)then return gc end end -- get existing hosted/index vtype + if(hdx)then local gc=storage._lib[vtype.."_idx"][hdx] if(gc and name)then gc=gc[name] end if(gc)then return gc end end -- get existing hosted/index vtype local c=cache[vtype] -- cache["ents"][name]. You can call these manually if you need to for ptrn, surfaces etc. if(not c)then return end if(name)then c=c[name] if(not c)then return end end -- only menus and vguis typically use names. - local idx=#global._lib[vtype]+1 - local t={index=idx,name=name,type=vtype,host=host,hostindex=hdx} global._lib[vtype][idx]=t + local idx=#storage._lib[vtype]+1 + local t={index=idx,name=name,type=vtype,host=host,hostindex=hdx} storage._lib[vtype][idx]=t if(hdx)then - if(name)then local gc=global._lib[vtype.."_idx"][hdx] or {} global._lib[vtype.."_idx"][hdx]=gc gc[t.name]=t - else global._lib[vtype.."_idx"][hdx]=t + if(name)then local gc=storage._lib[vtype.."_idx"][hdx] or {} storage._lib[vtype.."_idx"][hdx]=gc gc[t.name]=t + else storage._lib[vtype.."_idx"][hdx]=t end end if(c.raise)then c.raise(t,...) end @@ -198,10 +198,10 @@ end function cache.destroy_type(obj,...) local vtype=obj.type local c=cache[vtype] if(not c)then return end if(obj.name)then c=c[obj.name] if(not c)then return end end if(c.unraise)then c.unraise(obj,...) end - global._lib[vtype][obj.index]=nil - if(obj.hostindex)then global._lib[vtype.."_idx"][obj.hostindex]=nil end + storage._lib[vtype][obj.index]=nil + if(obj.hostindex)then storage._lib[vtype.."_idx"][obj.hostindex]=nil end end -function cache.get_type(vtype,name,host) local t=global._lib[vtype.."_idx"] +function cache.get_type(vtype,name,host) local t=storage._lib[vtype.."_idx"] if(t)then local uid if(isnumber(host))then uid=host else local cx cx,uid=pcall(cache.get_index,host,"index") if(not cx)then cx,uid=pcall(cache.get_index,host,"unit_number") if(not cx)then uid=nil end end end if(uid)then t=t[uid] else t=nil end @@ -210,7 +210,7 @@ function cache.get_type(vtype,name,host) local t=global._lib[vtype.."_idx"] return t end function cache.get_raise_type(vtype,name,host,...) return cache.get_type(vtype,name,host) or cache.raise_type(vtype,name,host,...) end -function cache.get_types(vtype) local t=global._lib[vtype] return t end +function cache.get_types(vtype) local t=storage._lib[vtype] return t end function cache.destroy(obj,...) return cache.destroy_type(obj,...) end -- This just destroys the cache object, not the actual in-game object. diff --git a/lib/lib_planets.lua b/lib/lib_planets.lua index 8f291f6..0ee3f93 100644 --- a/lib/lib_planets.lua +++ b/lib/lib_planets.lua @@ -60,33 +60,33 @@ function planets.on_template_updated(f) table.insert(planets.templateupfuncs,f) function planets.on_template_removed(f) table.insert(planets.templatermvfuncs,f) end -- Internal function to raise the template events table -function planets.raise_template_removed(ev) for i,f in pairs(planets.templatermvfuncs)do f(ev) end global._planetorio.template[ev.template.key]=nil end -function planets.raise_template_event(ev) global._planetorio.template[ev.template.key]=ev.template for i,f in pairs(planets.templatefuncs)do f(ev) end end -function planets.raise_template_updated_event(ev) table.merge(global._planetorio.template[ev.template.key],ev.template) for i,f in pairs(planets.templateupfuncs)do f(ev) end end +function planets.raise_template_removed(ev) for i,f in pairs(planets.templatermvfuncs)do f(ev) end storage._planetorio.template[ev.template.key]=nil end +function planets.raise_template_event(ev) storage._planetorio.template[ev.template.key]=ev.template for i,f in pairs(planets.templatefuncs)do f(ev) end end +function planets.raise_template_updated_event(ev) table.merge(storage._planetorio.template[ev.template.key],ev.template) for i,f in pairs(planets.templateupfuncs)do f(ev) end end function planets.GetTemplates() -- returns internal copy of synced templates - return global._planetorio.template + return storage._planetorio.template end function planets.GetTemplate(key) -- returns internal synced copy of a template - return global._planetorio.template[key] + return storage._planetorio.template[key] end function planets.GetBySurface(f) return remote.call("planetorio","GetBySurface",f) end function planets.lua() local pevents=remote.call("planetorio","GetEvents") - global._planetorio=global._planetorio or {} + storage._planetorio=storage._planetorio or {} script.on_event(pevents.on_new_template,planets.raise_template_event) script.on_event(pevents.on_template_updated,planets.raise_template_updated_event) script.on_event(pevents.on_template_removed,planets.raise_template_removed) local cur_data=remote.call("planetorio","GetTemplates") - global._planetorio.template=global._planetorio.template or {} - for key,val in pairs(global._planetorio.template)do - if(not cur_data[key])then planets.raise_template_removed({template=val}) global._planetorio.template[key]=nil end + storage._planetorio.template=storage._planetorio.template or {} + for key,val in pairs(storage._planetorio.template)do + if(not cur_data[key])then planets.raise_template_removed({template=val}) storage._planetorio.template[key]=nil end end - table.merge(global._planetorio,{template=cur_data}) + table.merge(storage._planetorio,{template=cur_data}) for k,v in pairs(cur_data)do planets.raise_template_event({template=v}) end end diff --git a/locale/en/config.cfg b/locale/en/config.cfg index dc3ba0c..2d6ca32 100644 --- a/locale/en/config.cfg +++ b/locale/en/config.cfg @@ -1,453 +1,442 @@ - - - -warptorio-stabilize=Stabilizer -warptorio-stabilize-on=Stabilizing.. __1__ -warptorio-radar=Radar -warptorio-radar-on=Scanning.. __1__ -warptorio-accel=Accelerater -warptorio-accel-on=Accelerating.. __1__ -warptorio-warp=Warp ! - -[tooltip-category] -shot=Shot - -[warptorio] -energybar=Energy: -button-votewarp=Votewarp ! -button-warp=Warp ! -button_homeworld=Settle ! -button_stabilizer=Stabilizer -button_radar=Radar -button_accelerator=Accelerate -ability_ready=Ability Ready ! -ability_uses=Uses: __1__ -ability_cooldown=Cooldown: __1__ -time_passed=Planet Clock: __1__ -charge_time=Warp Charge: __1__ -warpzone=Warpzone: __1__ -autowarp-in=Autowarping In: __1__ -warp-in=Warping In: __1__ -confirm_homeworld=Confirm? __1__ -warping=Warping... -button-votewarp-count=Votewarp ! __1__/__2__ -tool_hv_east=Right Harvester -tool_hv_west=Left Harvester -tool_planet_gate=Mobile Gate -toolbutton=Tools -home_sweet_home=__1__. Home sweet home -successful_warp=-Successful Warp- -player_want_vote_warp=__1__ wants to Warp. __2__ / __3__ votes -player_set_warp_target=__1__ set a course for: __2__ -warpzone_label=Warpzone: __1__ - -[mod-name] -warptorio2=Warptorio2 - -[mod-description] -warptorio2=Build your base on a platform that warps from planet to planet and escape biters before they overwhelm you. - -[mod-setting-tooltip] -warptorio_pollution_exponent=Small changes can have a large effect. pollution = pollution + pollution ^ X - -[mod-setting-name] -warptorio_no_lootchest=Difficulty: Disable loot chests from spawning -warptorio_lootchest_chance=Difficulty: 1 in X chance for a lootchest to spawn -warptorio_lootchest_distance=Difficulty: Minimum distance from the platform that a lootchest can spawn -warptorio_robot_warping=Difficulty: All platform-roboports deployed robots outside the platform are carried between warps. -warptorio_biter_warping=Difficulty: Disable biters on the platform being carried between warps - -warptorio_no_blueprint=Warptorio: Disable removing platform entities from blueprints in case of conflicts. -warptorio_loader_top=Platform Logstics: Loader Belt Direction (North Half) -warptorio_loader_bottom=Platform Logistics: Loader Belt Direction (South Half) -warptorio_loaderchest_provider=Platform Logistics: Loader-Chest Provider chest type -warptorio_loaderchest_requester=Platform Logistics: Loader-Chest Requester chest type -warptorio_hide_sprites=Platform Logistics: Hide stair sprites - -warptorio_combinator_offset=Harvesters: Combinators are offset from the edge of the harvesters by 1 tile. -warptorio_solar_multiplier=Difficulty: Solar Multiplier for solar panels placed on underground platform floors. - -warptorio_warpchance=Difficulty: Percentage chance to land on selected planet. -warptorio_votewarp_multi=Multiplayer: Fraction of players needed to votewarp before warping, between 0 and 1. - -warptorio_pollution_tickrate=Difficulty: Pollution Tick Rate, in seconds. -warptorio_pollution_exponent=Difficulty: Pollution generated by the platform is exponentiated by this amount every 2 seconds. -warptorio_pollution_multiplier=Difficulty: Pollution exponent result is multiplied by this amount each time it is applied. - -warptorio_science_output_multiplier=Warptorio difficulty science pack multiplier - -warptorio_pollution_disable=Difficulty: Disable Warp Platform based pollution. Factory pollution remains as normal. -warptorio_biter_expansion=Difficulty: Biter base expansion rate time reduction multiplier -warptorio_biter_min=Difficulty: Biter base expansion rate base min. time, in minutes -warptorio_biter_max=Difficulty: Biter base expansion rate base max. time, in minutes -warptorio_biter_redux=Difficulty: Biter base expansion rate maximum time reduction, in minutes -warptorio_biter_wavemin=Difficulty: Biter Waves min chance (1 in X per second) -warptorio_biter_wavemax=Difficulty: Biter waves max chance (1 in X per second) -warptorio_biter_waverng=Difficulty: Biter Waves wave-chance reduction (-X in 1 per minute) until minimum chance. -warptorio_biter_wavesize=Difficulty: Biter Waves pack size increase per minute, in number of biters -warptorio_biter_wavesizemax=Difficulty: Biter Waves pack size maximum, in number of biters. 0=infinite -warptorio_biter_wavestart=Difficulty: Biter Waves delay after warp before attacks start happening, in minutes - -warptorio_autowarp_always=Difficulty: Autowarp is always enabled. -warptorio_autowarp_time=Difficulty: Base autowarp timer, in minutes - -warptorio_autowarp_disable=Difficulty: Disable Autowarp -warptorio_warpcharge_max=Warp Charge: Max charge time possible, in minutes -warptorio_warpcharge_zonegain=Warp Charge: Max linear time increase from warp zones, in minutes -warptorio_warpcharge_zone=Warp Charge: Warp Zone # at which max linear zone time is reached -warptorio_warpcharge_multi=Warp Charge: Warp zone multiplier added to charge time -warptorio_warp_charge_factor=Warp Charge: For every X entities on platform and all floors, add 1 minute to charge time. - -warptorio_ability_warp=Abilities: Initial cooldown after warping, in minutes -warptorio_ability_cooldown=Abilities: Base cooldown time, in minutes. -warptorio_ability_timegain=Abilities: Cooldown time added due to number of ability uses, in minutes. -warptorio_ability_drain=Abilities: Starting amount of ability energy drain in % multiplier per tick (60tick=1sec) - -warptorio_carebear=Difficulty: It is dangerous to go it alone, take this. (Carebear Starter/Helper Chest) -warptorio_water=Difficulty: Early boiler room water. -warptorio_biter_disable=Difficulty: Disable biter base expansion rate modifiers -warptorio_biter_wave_disable=Difficulty: Disable biter waves - -warptorio_planet_normal=Planet Weighted Probability: Normal -warptorio_planet_uncharted=Planet Weighted Probability: Uncharted -warptorio_planet_average=Planet Weighted Probability: Average -warptorio_planet_res=Planet Weighted Probability: Resource Specific -warptorio_planet_dwarf=Planet Weighted Probability: Dwarf -warptorio_planet_jungle=Planet Weighted Probability: Jungle -warptorio_planet_barren=Planet Weighted Probability: Barren -warptorio_planet_ocean=Planet Weighted Probability: Ocean -warptorio_planet_rich=Planet Weighted Probability: Rich -warptorio_planet_midnight=Planet Weighted Probability: Midnight -warptorio_planet_polluted=Planet Weighted Probability: Polluted -warptorio_planet_biter=Planet Weighted Probability: Biter -warptorio_planet_rogue=Planet Weighted Probability: Rogue -warptorio_planet_void=Planet Weighted Probability: Void - - -[entity-name] -warptorio-warploader=Warp Loader -warptorio-warpstation=Warpstation -warptorio-reactor=Warp Reactor -warptorio-heatpipe=Warp Reactor Heatpipe -warptorio-logistics-pipe=Warp Pipe -warptorio-lootchest=Warptorio Loot Chest -warptorio-warpport=Warpport -warptorio-accumulator=Warp Accumulator -warptorio-teleporter-0=Planet Teleporter -warptorio-teleporter-1=Planet Teleporter -warptorio-teleporter-2=Planet Teleporter -warptorio-teleporter-3=Planet Teleporter -warptorio-teleporter-4=Planet Teleporter -warptorio-teleporter-5=Planet Teleporter -warptorio-teleporter-gate-0=Planet Teleporter Mobile Gate -warptorio-teleporter-gate-1=Planet Teleporter Mobile Gate -warptorio-teleporter-gate-2=Planet Teleporter Mobile Gate -warptorio-teleporter-gate-3=Planet Teleporter Mobile Gate -warptorio-teleporter-gate-4=Planet Teleporter Mobile Gate -warptorio-teleporter-gate-5=Planet Teleporter Mobile Gate -warptorio-underground-0=Platform Stairs -warptorio-underground-1=Platform Stairs -warptorio-underground-2=Platform Stairs -warptorio-underground-3=Platform Stairs -warptorio-underground-4=Platform Stairs -warptorio-underground-5=Platform Stairs -warptorio-beacon-1=Warp Beacon -warptorio-beacon-2=Warp Beacon -warptorio-beacon-3=Warp Beacon -warptorio-beacon-4=Warp Beacon -warptorio-beacon-5=Warp Beacon -warptorio-beacon-6=Warp Beacon -warptorio-beacon-7=Warp Beacon -warptorio-beacon-8=Warp Beacon -warptorio-beacon-9=Warp Beacon -warptorio-beacon-10=Warp Beacon -warptorio-beacon-11=Warp Beacon -warptorio-beacon-12=Warp Beacon -warptorio-beacon-13=Warp Beacon -warptorio-beacon-14=Warp Beacon -warptorio-beacon-15=Warp Beacon -warptorio-beacon-16=Warp Beacon -warptorio-beacon-17=Warp Beacon -warptorio-beacon-18=Warp Beacon -warptorio-beacon-19=Warp Beacon -warptorio-beacon-20=Warp Beacon -warptorio-invisradar=Warptorio "Invisible" Radar -warptorio-carebear-chest=Carebear Chest - -warptorio-harvestpad-east-1=Right Harvester Platform Lv1 -warptorio-harvestpad-west-1=Left Harvester Platform Lv1 -warptorio-harvestpad-east-2=Right Harvester Platform Lv2 -warptorio-harvestpad-west-2=Left Harvester Platform Lv2 -warptorio-harvestpad-east-3=Right Harvester Platform Lv3 -warptorio-harvestpad-west-3=Left Harvester Platform Lv3 -warptorio-harvestpad-east-4=Right Harvester Platform Lv4 -warptorio-harvestpad-west-4=Left Harvester Platform Lv4 -warptorio-harvestpad-east-5=Right Harvester Platform Lv5 -warptorio-harvestpad-west-5=Left Harvester Platform Lv5 - -warptorio-harvestportal-0=Harvester Teleporter -warptorio-harvestportal-1=Harvester Teleporter -warptorio-harvestportal-2=Harvester Teleporter -warptorio-harvestportal-3=Harvester Teleporter -warptorio-harvestportal-4=Harvester Teleporter -warptorio-harvestportal-5=Harvester Teleporter - -warptorio-combinator=Warptorio Combinator -warptorio-alt-combinator=Warp Harvester Circuit Connector - -warptorio-warpspider=Warp Strider - -[entity-description] -warptorio-warploader=Distributes items between all other warploaders according to filters. -warptorio-reactor=The warp reactor is a failed experiment. It's power output is weak and it seems to be pulling itself into an interdimentional rift more than it can draw energy from it. It's unstable too and will destroy the planet it's on if left unmanaged, so try to build a rocket and get away ! -warptorio-heatpipe=Balances heat between ALL Warp Heatpipes and the Warp Reactor -warptorio-warponium-fuel-cell=The only fuel that can power the Warp Reactor -warptorio-carebear-chest=It is dangerous to go it alone, take this. - -[item-name] -warptorio-reactor-fuel-cell=Warp Reactor Fuel Cell -warptorio-heatpipe=Warp Reactor Heatpipe -warptorio-armor=Warp Armor -warptorio-teleporter-gate-0=Planet Teleporter Mobile Gate -warptorio-teleporter-gate-1=Planet Teleporter Mobile Gate -warptorio-teleporter-gate-2=Planet Teleporter Mobile Gate -warptorio-teleporter-gate-3=Planet Teleporter Mobile Gate -warptorio-teleporter-gate-4=Planet Teleporter Mobile Gate -warptorio-teleporter-gate-5=Planet Teleporter Mobile Gate -warptorio-warponium-fuel=Warponium Fuel -warptorio-warponium-fuel-cell=Warponium Fuel Cell -warptorio-warpmodule=Warp Module -warptorio-atomic-bomb=Warp Nuke -warptorio-warpport=Warpport -warptorio-accumulator=Warp Accumulator -warptorio-warploader=Warp Loader -warptorio-townportal=Warp Platform Portal -warptorio-homeportal=Warp Homeworld Portal -warptorio-combinator=Warptorio Combinator -warptorio-alt-combinator=Warp Harvester Circuit Connector - -warptorio-spidertron-rocket-launcher-1=WarpStrider Rocket Launcher 1 -warptorio-spidertron-rocket-launcher-2=WarpStrider Rocket Launcher 2 -warptorio-spidertron-rocket-launcher-3=WarpStrider Rocket Launcher 3 -warptorio-spidertron-rocket-launcher-4=WarpStrider Rocket Launcher 4 -warptorio-spidertron-rocket-launcher-5=WarpStrider Rocket Launcher 5 -warptorio-spidertron-rocket-launcher-6=WarpStrider Rocket Launcher 6 -warptorio-spidertron-rocket-launcher-7=WarpStrider Rocket Launcher 7 -warptorio-spidertron-rocket-launcher-8=WarpStrider Rocket Launcher 8 - -warptorio-spidertron-shotgun-1=WarpStrider Shotgun -warptorio-spidertron-shotgun-2=WarpStrider Shotgun -warptorio-spidertron-flamethrower-1=WarpStrider Flamethrower -warptorio-spidertron-flamethrower-2=WarpStrider Flamethrower -warptorio-spidertron-machine-gun-1=WarpStrider Submachine Gun -warptorio-spidertron-machine-gun-2=WarpStrider Submachine Gun - - -[modifier-description] -character-reach-distance=Character Reach Distance +__1__ -character-build-distance=Character Build Distance +__1__ -character-item-drop-distance=Character Item-Drop Distance +__1__ -character-resource-reach-distance=Character Resource Reach Distance +__1__ -character-running-speed=Character Movement Speed +__1__ - - -[item-description] -warptorio-warpmodule=Contains a micro warp reactor that distorts spacetime providing the combined bonuses of speed, efficiency and productivity modules. -warptorio-atomic-bomb=Destabilizes surrounding warpspace at a specific frequency that only effects the targeted materials. -warptorio-warploader=Distributes items between all other warploaders according to filters. -warptorio-townportal=Teleport to the platform upon use. -warptorio-homeportal=Teleport to the homeworld upon use. -warptorio-combinator=W-Warp Countdown, X-Warp Is Active, A-Autowarp Timer, L-West Harvester is deployed, R-East Harvester is deployed, P-Planet Clock. - -[technology-name] -warptorio-striders=Warp Striders -warptorio-mining-prod=Warp Mining Production -warptorio-axe-speed=Warp Axe Speed -warptorio-inserter-cap=Warp Inserters Pocket Dimension -warptorio-bot-speed=Warp Robot Engine -warptorio-bot-cap=Warp Robot Pocket Dimension -warptorio-toolbelt=Warp Pocket Dimension -warptorio-warpport=Warpport -warptorio-warpmodule=Warp Modules -warptorio-reach=Warp Reach -warptorio-warpnuke=Warp Nuke -warptorio-physdmg=Warp Projectile Rounds -warptorio-accumulator=Warp Accumulator -warptorio-warploader=Warp Loader -warptorio-homeworld=Warptorio Homeworld -warptorio-teleporter-portal=Warptorio Teleporter Gate -warptorio-toolbar=Warptorio Toolbar - -warptorio-platform-size=Warp Platform Upgrade -warptorio-rail-nw=Warp Rail North West -warptorio-rail-ne=Warp Rail North East -warptorio-rail-sw=Warp Rail South West -warptorio-rail-se=Warp Rail South East - -warptorio-turret-nw=Warp Platform Turret North West -warptorio-turret-ne=Warp Platform Turret North East -warptorio-turret-sw=Warp Platform Turret South West -warptorio-turret-se=Warp Platform Turret South East - -warptorio-bridgesize=Warp Factory Bridge Size - -warptorio-factory=Warp Factory Floor -warptorio-factory-n=Warp Factory Giga Floor North -warptorio-factory-s=Warp Factory Giga Floor South -warptorio-factory-e=Warp Factory Giga Floor East -warptorio-factory-w=Warp Factory Giga Floor West - -warptorio-boiler=Warp Boiler Floor -warptorio-boiler-water=Warp Boiler Floor Water -warptorio-boiler-n=Warp Boiler Giga Floor North -warptorio-boiler-s=Warp Boiler Giga Floor South -warptorio-boiler-e=Warp Boiler Giga Floor East -warptorio-boiler-w=Warp Boiler Giga Floor West - -warptorio-boiler-station=Warp Boiler Substation - -warptorio-logistics=Warp Platform Logistics -warptorio-dualloader=Warp Platform Logistics Dual Loader -warptorio-triloader=Warp Platform Logistics Tri Loader - -warptorio-energy=Warp Platform Stairs Energy Upgrade - -warptorio-teleporter=Warp Planet Teleporter Energy Upgrade - -warptorio-beacon=Warp Factory Beacon - -warptorio-armor=Warp Armor - -warptorio-charting=Warp Reactor Charting -warptorio-stabilizer=Warp Reactor Stabilizers -warptorio-accelerator=Warp Reactor Accelerator - -warptorio-reactor=Warp Reactor Re-Assembly Project -warptorio-kovarex=Warponium Fuel - -warptorio-harvester-floor=Warp Harvester Floor -warptorio-harvester-size=Warp Harvester Floor Size -warptorio-harvester-east-gate=Warp Harvester East Platform -warptorio-harvester-west-gate=Warp Harvester West Platform - -warptorio-harvester-east=Warp Harvester East Platform Size -warptorio-harvester-west=Warp Harvester West Platform Size - -warptorio-combinator=Warp Combinators -warptorio-alt-combinator=Warp Harvester Circuit Connections - -warptorio-warpspider=Warp Strider - -[technology-description] -warptorio-mining-prod=Warp technology allows us to almost duplicate resources as we collect them -warptorio-axe-speed=Improved warping of planetary structures into your inventory -warptorio-bot-speed=Allows robots to warp impercetibively short distances, slightly increasing their speed. -warptorio-reach=The Warp Reactor incident imbued you with a supernatural ability to create localized warps, improving your reach distance. -warptorio-physdmg=Warp technology allows minor improvements to our weaponry and defense network. -warptorio-accumulator=These accumulators balance power between the warp platform and ALL warp accumulators, allowing increased energy throughput between the platform floors. -warptorio-teleporter-portal=Unlock the Warp Platform Planetary Teleporter -warptorio-toolbar=Mastery of your innate control over warpspace giving you the ability to recall harvesters and teleporter gates remotely. -warptorio-striders=The Warp Reactor incident imbued you with a supernatural ability to create localized warps, improving your movement speed. - -warptorio-rail-nw=Warp Rails detect trains passing over them, and warp their contents to and from chests on the Warp Factory Floor -warptorio-rail-ne=Warp Rails detect trains passing over them, and warp their contents to and from chests on the Warp Factory Floor -warptorio-rail-sw=Warp Rails detect trains passing over them, and warp their contents to and from chests on the Warp Factory Floor -warptorio-rail-se=Warp Rails detect trains passing over them, and warp their contents to and from chests on the Warp Factory Floor - -warptorio-turret-nw=Warp in a small castle turret to the North West connected through the Warp Factory Floor -warptorio-turret-sw=Warp in a small castle turret to the South West connected through the Warp Factory Floor -warptorio-turret-ne=Warp in a small castle turret to the North East connected through the Warp Factory Floor -warptorio-turret-se=Warp in a small castle turret to the South East connected through the Warp Factory Floor - -warptorio-bridgesize=Increase the size of Warp Factory Bridges - -warptorio-factory-floor=Unlocks the Warp Factory Floor. -warptorio-factory=Increase the size of the Warp Factory Floor. -warptorio-factory-n=Unlock a giant Factory Floor platform to the North -warptorio-factory-s=Unlock a giant Factory Floor platform to the South -warptorio-factory-e=Unlock a giant Factory Floor platform to the East -warptorio-factory-w=Unlock a giant Factory Floor platform to the West - -warptorio-boiler-floor=Unlocks the Warp Boiler Floor -warptorio-boiler=Increase the size of the Warp Boiler Floor. -warptorio-boiler-water=Warp a small amount of water from the planet to the Boiler Floor -warptorio-boiler-n=Unlock a giant Boiler Floor platform to the North -warptorio-boiler-s=Unlock a giant Boiler Floor platform to the South -warptorio-boiler-e=Unlock a giant Boiler Floor platform to the East -warptorio-boiler-w=Unlock a giant Boiler Floor platform to the West - -warptorio-logistics=Adds an extra pipe and upgrades the belt speed and chest size of all Platform Logistics. -warptorio-dualloader=Adds an additional belt to the central Platform Stairs and the Harvesters. -warptorio-triloader=Adds an additional belt to all teleporters, stairs and harvesters - -warptorio-energy=Increase energy flow rate and capacity of Platform Stairs. -warptorio-teleporter=Increase energy flow rate and capacity of the Planet Teleporter. -warptorio-beacon=Unlock a Warp Beacon on the Factory Floor. Each level adds an additional module slot. -warptorio-boiler-station=Unlock a Warpstation on the Boiler Floor, providing a large coverage of power. - -warptorio-armor=Perfection of the defensive applications of the Warp Reactor and its technologies. -warptorio-warpport=Perfection of the robotics applications of the Warp Reactor and its technologies. -warptorio-kovarex=Perfection of the energy applications of the Warp Reactor and its technologies. -warptorio-warpmodule=Perfection of the productivity applications of the Warp Reactor and its technologies. -warptorio-warpnuke=Perfection of the offensive applications of the Warp Reactor and its technologies. - -warptorio-warploader=Perfection of the logistics applications of the Warp Reactor and its technologies. -warptorio-warpspider=Perfection of the vehicular applications of the Warp Reactor and its technologies. - -warptorio-homeworld=Allows you to settle a planet. - -warptorio-charting=Unlock the Reactor Ability to scan and reveal surrounding areas. Charting also adds an invisible radar to the Factory and Boiler floors if you have their center buildings. -warptorio-stabilizer=Unlock the Reactor Ability to stabilize the platform minimizing pollution emissions and pollution growth. -warptorio-accelerator=Unlock the Reactor Ability to pre-charge the Warp function allowing for faster warp-outs. -warptorio-reactor=Research, construct and repair the components neccessary to rebuild the Warp Reactor and perfect its functionality to return home. Each level adds 10 minutes to the Auto-Warp Timer, Warp Pre-Charge ticks 1 sec faster, and may have other effects. - -warptorio-reactor-6=Research, construct and repair the components neccessary to rebuild the Warp Reactor and perfect its functionality to return home. Each level adds 10 minutes to the Auto-Warp Timer, Warp Pre-Charge ticks 1 sec faster, and may have other effects. This level spawns the physical Warp Reactor and disables the Autowarp Timer. -warptorio-reactor-8=Research, construct and repair the components neccessary to rebuild the Warp Reactor and perfect its functionality to return home. Each level adds 10 minutes to the Auto-Warp Timer, Warp Pre-Charge ticks 1 sec faster, and may have other effects. This level allows you to steer the warp reactor. The chance of landing on the targeted planet is 30%. - - -warptorio-harvester-floor=Warp Harvester Floor -warptorio-harvester-size=Warp Harvester Floor Size -warptorio-harvester-east-gate=Unlock the Eastern (Right) Harvest Platform, which is a portable deployable platform that you can build on. -warptorio-harvester-west-gate=Unlock the Western (Left) Harvest Platform, which is a portable deployable platform that you can build on. - -warptorio-harvester-east=Warp Harvester East Platform Size -warptorio-harvester-west=Warp Harvester West Platform Size - -warptorio-combinator=These combinators give a readout of platform information such as timers and warp status. Useful for advanced automation. -warptorio-alt-combinator=This adds static combinators to the Harvester platforms that automatically connect when harvesters are recalled. Useful for advanced automation. - - -[warptorio_lore] -1_1=You first awoke with slight headache on this platform, and the only thing you feel sure of is that you need to rebuild your experiment to escape this dangerous world and return home. -1_2=You cobble together some wires, switches and dials and attach it to the platform. -1_3=Although you are unsure if you managed to achieve anything, you at least feel a bit more in control. - -2_1=The memories of what happened begin to return to you. You were working on an experimental reactor that could distort and displace time and space. -2_2=You recall your early experiments and proceed to replicate them with the crude resources you've found on your journey so far. -2_3=The progress you feel you've made fills you with determination. - -3_1=Ah yes, the experiment went bad! The Warp Reactor ruptured and tore a rift in localized warpspace fabric casting you and the warp platform into an alternate relative dimension in space. -3_2=You hastily assemble the warp reactor control panel from memory, but then stop when you realize you need the reactor core before they can function. -3_3=The feeling like you know what you need to do fills you with determination, if only you had the resources to do it. - -4_1=Before the accident, you remember feeling excited about the endless applications of mastering the control of warpspace and became careless. -4_2=You have finished building the reactor warpdis and rift core, but you are not going to make the same mistakes twice. -4_3=Holding the pulsating warpdis in your hands fills you with determination. - -5_1=You think you know why your experiment went wrong, the warpdis must be unstable unless maintained by perfectly reversing the polarity inversely squared to the rift core's inter-subdimensional artron energy matrix. -5_2=You ready the warpdis to rip the perfected materials you need directly out of warpspace. -5_3=It's a risky strategy, but you believe this is your only chance to escape these savage alien infested worlds and get back to civilization. - -6_1=A loud clash of energy ripples over your warp platform as the reactor shifts into existence, and you know this technology will uplift your civilization beyond their imagination. -6_2=You decide to continue your experiments with the warp reactor while you warp through world after world in search of home, if only you knew how to steer this boat. -6_3=The Warp Reactor finally now in place fills you with determination. - -7_1=You have developed a way to build a miniaturized warpdis connected to your reactors rift core, allowing the transfer of heat energy through warpspace -7_2=You believe this may be further refined into a way to rip chemical artron energy fuel cells out of warpspace through a perfect quasi-misalignment of the warpdis polarity. -7_3=This newfound flexible control over warpspace and time fills you with determination. - -8_1=You have almost lost track of how many worlds you have visited while adrift between dimensions, but you have discovered a way to measure the dimensional relativity of the artron energy signature emitted by the reactors rift core. -8_2=As a result, you are able to chart a map of where you have been, and what might lay ahead. But be wary, the Warp Reactor may not always agree with you, just like the day that started this all. -8_3=Your homeworld in your sights fills you with determination, and you marvel at the fruits of your final warpspace experiments. - - +[mod-name] +warptorio2=Warptorio2 + +[mod-description] +warptorio2=Build your base on a platform that warps from planet to planet and escape biters before they overwhelm you. Restore the Warp Reactor and find your Home. + +[warptorio] +stabilize=Stabilizer +stabilize-on=Stabilizing.. __1__ +radar=Radar +radar-on=Scanning.. __1__ +accel=Accelerator +accel-on=Accelerating.. __1__ +energybar=Energy: +button-warp=Warp ! +button-votewarp=Votewarp ! +button-votewarp-count=Votewarp ! __1__/__2__ +button-homeworld=Settle ! +ability_ready=Ability Ready ! +ability_uses=Uses: __1__ +ability_cooldown=Cooldown: __1__ +time_passed=Planet Clock: __1__ +charge_time=Warp Charge: __1__ +warpzone=Warpzone: __1__ +autowarp-in=Autowarping In: __1__ +warp-in=Warping In: __1__ +warping=Warping... +tool_hv_east=Right Harvester Platform +tool_hv_west=Left Harvester Platform +tool_planet_gate=Mobile Gate +toolbutton=Tools +confirm_homeworld=Confirm? __1__ +home_sweet_home=__1__. Home Sweet Home. +successful_warp=-= Successful Warp =- +player_want_vote_warp=__1__ wants to Warp. __2__ / __3__ votes +player_set_warp_target=__1__ set a course for: __2__ +player_started_warpout=__1__ started the warpout procedure. +warpzone_label=Warpzone: __1__ +harvester-placement-error=Harvesters can only be placed on the planet +homeworld-set=Homeworld Set. +same-planet-error=You must be on the same planet as the platform to warp. +max-one-teleporter-error=Max 1 Planet Teleporter Gate allowed at a time - built +teleporter-blocked-error=Planet Teleporter Gate Logistics blocked - Needs more space +intro=You woke up in an unfamiliar world, in the wreckage of your platform ship. You need to get back before you get lost.\nRestore the Warp Reactor and find your Home. +victory-title=Victory! +victory-text=After a long journey, many planets visited, technology developed, and countless trials, you have finally found a world you can call Home. +victoty-text2=With best regards,\nWarptorio2 Team. + +[tooltip-category] +shot=Shot + +[mod-setting-tooltip] +warptorio_pollution_exponent=Small changes can have a large effect. (pollution = pollution + pollution ^ X) + +[mod-setting-name] +warptorio_no_lootchest=Difficulty: Disable loot chests from spawning +warptorio_lootchest_chance=Difficulty: 1 in X chance for a lootchest to spawn +warptorio_lootchest_distance=Difficulty: Minimum distance from the platform that a lootchest can spawn +warptorio_robot_warping=Difficulty: All platform-roboports deployed robots outside the platform are carried between warps. +warptorio_biter_warping=Difficulty: Disable biters on the platform being carried between warps + +warptorio_no_blueprint=Warptorio: Disable removing platform entities from blueprints in case of conflicts. +warptorio_loader_top=Platform Logstics: Loader Belt Direction (North Half) +warptorio_loader_bottom=Platform Logistics: Loader Belt Direction (South Half) +warptorio_loaderchest_provider=Platform Logistics: Loader-Chest Provider chest type +warptorio_loaderchest_requester=Platform Logistics: Loader-Chest Requester chest type +warptorio_hide_sprites=Platform Logistics: Hide stair sprites + +warptorio_combinator_offset=Harvesters: Combinators are offset from the edge of the harvesters by 1 tile. +warptorio_solar_multiplier=Difficulty: Solar Multiplier for solar panels placed on underground platform floors. + +warptorio_warpchance=Difficulty: Percentage chance to land on selected planet. +warptorio_votewarp_multi=Multiplayer: Fraction of players needed to votewarp before warping, between 0 and 1. + +warptorio_pollution_tickrate=Difficulty: Pollution Tick Rate, in seconds. +warptorio_pollution_exponent=Difficulty: Pollution generated by the platform is exponentiated by this amount every 2 seconds. +warptorio_pollution_multiplier=Difficulty: Pollution exponent result is multiplied by this amount each time it is applied. + +warptorio_science_output_multiplier=Warptorio difficulty science pack multiplier + +warptorio_pollution_disable=Difficulty: Disable Warp Platform based pollution. Factory pollution remains as normal. +warptorio_biter_expansion=Difficulty: Biter base expansion rate time reduction multiplier +warptorio_biter_min=Difficulty: Biter base expansion rate base min. time, in minutes +warptorio_biter_max=Difficulty: Biter base expansion rate base max. time, in minutes +warptorio_biter_redux=Difficulty: Biter base expansion rate maximum time reduction, in minutes +warptorio_biter_wavemin=Difficulty: Biter Waves min chance (1 in X per second) +warptorio_biter_wavemax=Difficulty: Biter waves max chance (1 in X per second) +warptorio_biter_waverng=Difficulty: Biter Waves wave-chance reduction (-X in 1 per minute) until minimum chance. +warptorio_biter_wavesize=Difficulty: Biter Waves pack size increase per minute, in number of biters +warptorio_biter_wavesizemax=Difficulty: Biter Waves pack size maximum, in number of biters. 0=infinite +warptorio_biter_wavestart=Difficulty: Biter Waves delay after warp before attacks start happening, in minutes + +warptorio_autowarp_always=Difficulty: Autowarp is always enabled. +warptorio_autowarp_time=Difficulty: Base autowarp timer, in minutes + +warptorio_autowarp_disable=Difficulty: Disable Autowarp +warptorio_warpcharge_max=Warp Charge: Max charge time possible, in minutes +warptorio_warpcharge_zonegain=Warp Charge: Max linear time increase from warp zones, in minutes +warptorio_warpcharge_zone=Warp Charge: Warp Zone # at which max linear zone time is reached +warptorio_warpcharge_multi=Warp Charge: Warp zone multiplier added to charge time +warptorio_warp_charge_factor=Warp Charge: For every X entities on platform and all floors, add 1 minute to charge time. + +warptorio_ability_warp=Abilities: Initial cooldown after warping, in minutes +warptorio_ability_cooldown=Abilities: Base cooldown time, in minutes. +warptorio_ability_timegain=Abilities: Cooldown time added due to number of ability uses, in minutes. +warptorio_ability_drain=Abilities: Starting amount of ability energy drain in % multiplier per tick (60tick=1sec) + +warptorio_carebear=Difficulty: It is dangerous to go it alone, take this. (Carebear Starter/Helper Chest) +warptorio_water=Difficulty: Early boiler room water. +warptorio_biter_disable=Difficulty: Disable biter base expansion rate modifiers +warptorio_biter_wave_disable=Difficulty: Disable biter waves + +[entity-name] +warptorio-warploader=Warp Loader +warptorio-warpstation=Warpstation +warptorio-reactor=Warp Reactor +warptorio-heatpipe=Warp Reactor Heatpipe +warptorio-logistics-pipe=Warp Pipe +warptorio-lootchest=Warptorio Loot Chest +warptorio-warpport=Warpport +warptorio-accumulator=Warp Accumulator +warptorio-teleporter-0=Planet Teleporter +warptorio-teleporter-1=Planet Teleporter +warptorio-teleporter-2=Planet Teleporter +warptorio-teleporter-3=Planet Teleporter +warptorio-teleporter-4=Planet Teleporter +warptorio-teleporter-5=Planet Teleporter +warptorio-teleporter-gate-0=Planet Teleporter Mobile Gate +warptorio-teleporter-gate-1=Planet Teleporter Mobile Gate +warptorio-teleporter-gate-2=Planet Teleporter Mobile Gate +warptorio-teleporter-gate-3=Planet Teleporter Mobile Gate +warptorio-teleporter-gate-4=Planet Teleporter Mobile Gate +warptorio-teleporter-gate-5=Planet Teleporter Mobile Gate +warptorio-underground-0=Platform Stairs +warptorio-underground-1=Platform Stairs +warptorio-underground-2=Platform Stairs +warptorio-underground-3=Platform Stairs +warptorio-underground-4=Platform Stairs +warptorio-underground-5=Platform Stairs +warptorio-beacon-1=Warp Beacon +warptorio-beacon-2=Warp Beacon +warptorio-beacon-3=Warp Beacon +warptorio-beacon-4=Warp Beacon +warptorio-beacon-5=Warp Beacon +warptorio-beacon-6=Warp Beacon +warptorio-beacon-7=Warp Beacon +warptorio-beacon-8=Warp Beacon +warptorio-beacon-9=Warp Beacon +warptorio-beacon-10=Warp Beacon +warptorio-beacon-11=Warp Beacon +warptorio-beacon-12=Warp Beacon +warptorio-beacon-13=Warp Beacon +warptorio-beacon-14=Warp Beacon +warptorio-beacon-15=Warp Beacon +warptorio-beacon-16=Warp Beacon +warptorio-beacon-17=Warp Beacon +warptorio-beacon-18=Warp Beacon +warptorio-beacon-19=Warp Beacon +warptorio-beacon-20=Warp Beacon +warptorio-invisradar=Warptorio "Invisible" Radar +warptorio-carebear-chest=Carebear Chest + +warptorio-harvestpad-east-1=Right Harvester Platform Lv1 +warptorio-harvestpad-west-1=Left Harvester Platform Lv1 +warptorio-harvestpad-east-2=Right Harvester Platform Lv2 +warptorio-harvestpad-west-2=Left Harvester Platform Lv2 +warptorio-harvestpad-east-3=Right Harvester Platform Lv3 +warptorio-harvestpad-west-3=Left Harvester Platform Lv3 +warptorio-harvestpad-east-4=Right Harvester Platform Lv4 +warptorio-harvestpad-west-4=Left Harvester Platform Lv4 +warptorio-harvestpad-east-5=Right Harvester Platform Lv5 +warptorio-harvestpad-west-5=Left Harvester Platform Lv5 +warptorio-harvestpad-tag-1=Space for Harvester Platform Lv1 +warptorio-harvestpad-tag-2=Space for Harvester Platform Lv2 +warptorio-harvestpad-tag-3=Space for Harvester Platform Lv3 +warptorio-harvestpad-tag-4=Space for Harvester Platform Lv4 +warptorio-harvestpad-tag-5=Space for Harvester Platform Lv5 + +warptorio-harvestportal-0=Harvester Teleporter +warptorio-harvestportal-1=Harvester Teleporter +warptorio-harvestportal-2=Harvester Teleporter +warptorio-harvestportal-3=Harvester Teleporter +warptorio-harvestportal-4=Harvester Teleporter +warptorio-harvestportal-5=Harvester Teleporter + +warptorio-combinator=Warptorio Combinator +warptorio-alt-combinator=Warp Harvester Circuit Connector + +warptorio-warpspider=Warp Strider + +[entity-description] +warptorio-warploader=Distributes items between all other warploaders according to filters. +warptorio-reactor=The warp reactor is a failed experiment. It's power output is weak and it seems to be pulling itself into an interdimentional rift more than it can draw energy from it. It's unstable too and will destroy the planet it's on if left unmanaged, so try to build a rocket and get away ! +warptorio-heatpipe=Balances heat between ALL Warp Heatpipes and the Warp Reactor +warptorio-warponium-fuel-cell=The only fuel that can power the Warp Reactor +warptorio-carebear-chest=It is dangerous to go it alone, take this. + +[item-name] +warptorio-reactor-fuel-cell=Warp Reactor Fuel Cell +warptorio-heatpipe=Warp Reactor Heatpipe +warptorio-armor=Warp Armor +warptorio-teleporter-gate-0=Planet Teleporter Mobile Gate +warptorio-teleporter-gate-1=Planet Teleporter Mobile Gate +warptorio-teleporter-gate-2=Planet Teleporter Mobile Gate +warptorio-teleporter-gate-3=Planet Teleporter Mobile Gate +warptorio-teleporter-gate-4=Planet Teleporter Mobile Gate +warptorio-teleporter-gate-5=Planet Teleporter Mobile Gate +warptorio-warponium-fuel=Warponium Fuel +warptorio-warponium-fuel-cell=Warponium Fuel Cell +warptorio-warpmodule=Warp Module +warptorio-atomic-bomb=Warp Nuke +warptorio-warpport=Warpport +warptorio-accumulator=Warp Accumulator +warptorio-warploader=Warp Loader +warptorio-townportal=Warp Platform Portal +warptorio-homeportal=Warp Homeworld Portal +warptorio-combinator=Warptorio Combinator +warptorio-alt-combinator=Warp Harvester Circuit Connector + +warptorio-spidertron-rocket-launcher-1=WarpStrider Rocket Launcher 1 +warptorio-spidertron-rocket-launcher-2=WarpStrider Rocket Launcher 2 +warptorio-spidertron-rocket-launcher-3=WarpStrider Rocket Launcher 3 +warptorio-spidertron-rocket-launcher-4=WarpStrider Rocket Launcher 4 +warptorio-spidertron-rocket-launcher-5=WarpStrider Rocket Launcher 5 +warptorio-spidertron-rocket-launcher-6=WarpStrider Rocket Launcher 6 +warptorio-spidertron-rocket-launcher-7=WarpStrider Rocket Launcher 7 +warptorio-spidertron-rocket-launcher-8=WarpStrider Rocket Launcher 8 + +warptorio-spidertron-shotgun-1=WarpStrider Shotgun +warptorio-spidertron-shotgun-2=WarpStrider Shotgun +warptorio-spidertron-flamethrower-1=WarpStrider Flamethrower +warptorio-spidertron-flamethrower-2=WarpStrider Flamethrower +warptorio-spidertron-machine-gun-1=WarpStrider Submachine Gun +warptorio-spidertron-machine-gun-2=WarpStrider Submachine Gun + +[modifier-description] +character-reach-distance=Character Reach Distance +__1__ +character-build-distance=Character Build Distance +__1__ +character-item-drop-distance=Character Item-Drop Distance +__1__ +character-resource-reach-distance=Character Resource Reach Distance +__1__ +character-running-speed=Character Movement Speed +__1__ + +[item-description] +warptorio-warpmodule=Contains a micro warp reactor that distorts spacetime providing the combined bonuses of speed, efficiency and productivity modules. +warptorio-atomic-bomb=Destabilizes surrounding warpspace at a specific frequency that only effects the targeted materials. +warptorio-warploader=Distributes items between all other warploaders according to filters. +warptorio-townportal=Teleport to the platform upon use. +warptorio-homeportal=Teleport to the homeworld upon use. +warptorio-combinator=W-Warp Countdown, X-Warp Is Active, A-Autowarp Timer, L-West Harvester is deployed, R-East Harvester is deployed, P-Planet Clock. + +[technology-name] +warptorio-striders=Warp Striders +warptorio-mining-prod=Warp Mining Production +warptorio-axe-speed=Warp Axe Speed +warptorio-inserter-cap=Warp Inserters Pocket Dimension +warptorio-bot-speed=Warp Robot Engine +warptorio-bot-cap=Warp Robot Pocket Dimension +warptorio-toolbelt=Warp Pocket Dimension +warptorio-warpport=Warpport +warptorio-warpmodule=Warp Modules +warptorio-reach=Warp Reach +warptorio-warpnuke=Warp Nuke +warptorio-physdmg=Warp Projectile Rounds +warptorio-accumulator=Warp Accumulator +warptorio-warploader=Warp Loader +warptorio-homeworld=Warptorio Homeworld +warptorio-teleporter-portal=Warptorio Teleporter Gate +warptorio-toolbar=Warptorio Toolbar + +warptorio-platform-size=Warp Platform Upgrade +warptorio-rail-nw=Warp Rail North West +warptorio-rail-ne=Warp Rail North East +warptorio-rail-sw=Warp Rail South West +warptorio-rail-se=Warp Rail South East + +warptorio-turret-nw=Warp Platform Turret North West +warptorio-turret-ne=Warp Platform Turret North East +warptorio-turret-sw=Warp Platform Turret South West +warptorio-turret-se=Warp Platform Turret South East + +warptorio-bridgesize=Warp Factory Bridge Size + +warptorio-factory=Warp Factory Floor +warptorio-factory-n=Warp Factory Giga Floor North +warptorio-factory-s=Warp Factory Giga Floor South +warptorio-factory-e=Warp Factory Giga Floor East +warptorio-factory-w=Warp Factory Giga Floor West + +warptorio-boiler=Warp Boiler Floor +warptorio-boiler-water=Warp Boiler Floor Water +warptorio-boiler-n=Warp Boiler Giga Floor North +warptorio-boiler-s=Warp Boiler Giga Floor South +warptorio-boiler-e=Warp Boiler Giga Floor East +warptorio-boiler-w=Warp Boiler Giga Floor West + +warptorio-boiler-station=Warp Boiler Substation + +warptorio-logistics=Warp Platform Logistics +warptorio-dualloader=Warp Platform Logistics Dual Loader +warptorio-triloader=Warp Platform Logistics Tri Loader + +warptorio-energy=Warp Platform Stairs Energy Upgrade + +warptorio-teleporter=Warp Planet Teleporter Energy Upgrade + +warptorio-beacon=Warp Factory Beacon + +warptorio-armor=Warp Armor + +warptorio-charting=Warp Reactor Charting +warptorio-stabilizer=Warp Reactor Stabilizers +warptorio-accelerator=Warp Reactor Accelerator + +warptorio-reactor=Warp Reactor Re-Assembly Project +warptorio-kovarex=Warponium Fuel + +warptorio-harvester-floor=Warp Harvester Floor +warptorio-harvester-size=Warp Harvester Floor Size +warptorio-harvester-east-gate=Warp Harvester East Platform +warptorio-harvester-west-gate=Warp Harvester West Platform + +warptorio-harvester-east=Warp Harvester East Platform Size +warptorio-harvester-west=Warp Harvester West Platform Size + +warptorio-combinator=Warp Combinators +warptorio-alt-combinator=Warp Harvester Circuit Connections + +warptorio-warpspider=Warp Strider + +[technology-description] +warptorio-mining-prod=Warp technology allows us to almost duplicate resources as we collect them +warptorio-axe-speed=Improved warping of planetary structures into your inventory +warptorio-bot-speed=Allows robots to warp impercetibively short distances, slightly increasing their speed. +warptorio-reach=The Warp Reactor incident imbued you with a supernatural ability to create localized warps, improving your reach distance. +warptorio-physdmg=Warp technology allows minor improvements to our weaponry and defense network. +warptorio-accumulator=These accumulators balance power between the warp platform and ALL warp accumulators, allowing increased energy throughput between the platform floors. +warptorio-teleporter-portal=Unlock the Warp Platform Planetary Teleporter +warptorio-toolbar=Mastery of your innate control over warpspace giving you the ability to recall harvesters and teleporter gates remotely. +warptorio-striders=The Warp Reactor incident imbued you with a supernatural ability to create localized warps, improving your movement speed. + +warptorio-rail-nw=Warp Rails detect trains passing over them, and warp their contents to and from chests on the Warp Factory Floor +warptorio-rail-ne=Warp Rails detect trains passing over them, and warp their contents to and from chests on the Warp Factory Floor +warptorio-rail-sw=Warp Rails detect trains passing over them, and warp their contents to and from chests on the Warp Factory Floor +warptorio-rail-se=Warp Rails detect trains passing over them, and warp their contents to and from chests on the Warp Factory Floor + +warptorio-turret-nw=Warp in a small castle turret to the North West connected through the Warp Factory Floor +warptorio-turret-sw=Warp in a small castle turret to the South West connected through the Warp Factory Floor +warptorio-turret-ne=Warp in a small castle turret to the North East connected through the Warp Factory Floor +warptorio-turret-se=Warp in a small castle turret to the South East connected through the Warp Factory Floor + +warptorio-bridgesize=Increase the size of Warp Factory Bridges + +warptorio-factory-floor=Unlocks the Warp Factory Floor. +warptorio-factory=Increase the size of the Warp Factory Floor. +warptorio-factory-n=Unlock a giant Factory Floor platform to the North +warptorio-factory-s=Unlock a giant Factory Floor platform to the South +warptorio-factory-e=Unlock a giant Factory Floor platform to the East +warptorio-factory-w=Unlock a giant Factory Floor platform to the West + +warptorio-boiler-floor=Unlocks the Warp Boiler Floor +warptorio-boiler=Increase the size of the Warp Boiler Floor. +warptorio-boiler-water=Warp a small amount of water from the planet to the Boiler Floor +warptorio-boiler-n=Unlock a giant Boiler Floor platform to the North +warptorio-boiler-s=Unlock a giant Boiler Floor platform to the South +warptorio-boiler-e=Unlock a giant Boiler Floor platform to the East +warptorio-boiler-w=Unlock a giant Boiler Floor platform to the West + +warptorio-logistics=Adds an extra pipe and upgrades the belt speed and chest size of all Platform Logistics. +warptorio-dualloader=Adds an additional belt to the central Platform Stairs and the Harvesters. +warptorio-triloader=Adds an additional belt to all teleporters, stairs and harvesters + +warptorio-energy=Increase energy flow rate and capacity of Platform Stairs. +warptorio-teleporter=Increase energy flow rate and capacity of the Planet Teleporter. +warptorio-beacon=Unlock a Warp Beacon on the Factory Floor. Each level adds an additional module slot. +warptorio-boiler-station=Unlock a Warpstation on the Boiler Floor, providing a large coverage of power. + +warptorio-armor=Perfection of the defensive applications of the Warp Reactor and its technologies. +warptorio-warpport=Perfection of the robotics applications of the Warp Reactor and its technologies. +warptorio-kovarex=Perfection of the energy applications of the Warp Reactor and its technologies. +warptorio-warpmodule=Perfection of the productivity applications of the Warp Reactor and its technologies. +warptorio-warpnuke=Perfection of the offensive applications of the Warp Reactor and its technologies. + +warptorio-warploader=Perfection of the logistics applications of the Warp Reactor and its technologies. +warptorio-warpspider=Perfection of the vehicular applications of the Warp Reactor and its technologies. + +warptorio-homeworld=Allows you to settle a planet. + +warptorio-charting=Unlock the Reactor Ability to scan and reveal surrounding areas. Charting also adds an invisible radar to the Factory and Boiler floors if you have their center buildings. +warptorio-stabilizer=Unlock the Reactor Ability to stabilize the platform minimizing pollution emissions and pollution growth. +warptorio-accelerator=Unlock the Reactor Ability to pre-charge the Warp function allowing for faster warp-outs. +warptorio-reactor=Research, construct and repair the components neccessary to rebuild the Warp Reactor and perfect its functionality to return home. Each level adds 10 minutes to the Auto-Warp Timer, Warp Pre-Charge ticks 1 sec faster, and may have other effects. + +warptorio-reactor-6=Research, construct and repair the components neccessary to rebuild the Warp Reactor and perfect its functionality to return home. Each level adds 10 minutes to the Auto-Warp Timer, Warp Pre-Charge ticks 1 sec faster, and may have other effects. This level spawns the physical Warp Reactor and disables the Autowarp Timer. +warptorio-reactor-8=Research, construct and repair the components neccessary to rebuild the Warp Reactor and perfect its functionality to return home. Each level adds 10 minutes to the Auto-Warp Timer, Warp Pre-Charge ticks 1 sec faster, and may have other effects. This level allows you to steer the warp reactor. The chance of landing on the targeted planet is 30%. + + +warptorio-harvester-floor=Warp Harvester Floor +warptorio-harvester-size=Warp Harvester Floor Size +warptorio-harvester-east-gate=Unlock the Eastern (Right) Harvest Platform, which is a portable deployable platform that you can build on. +warptorio-harvester-west-gate=Unlock the Western (Left) Harvest Platform, which is a portable deployable platform that you can build on. + +warptorio-harvester-east=Warp Harvester East Platform Size +warptorio-harvester-west=Warp Harvester West Platform Size + +warptorio-combinator=These combinators give a readout of platform information such as timers and warp status. Useful for advanced automation. +warptorio-alt-combinator=This adds static combinators to the Harvester platforms that automatically connect when harvesters are recalled. Useful for advanced automation. + +[fuel-category-name] +warp=Warponium fuel + +[warptorio_lore] +1_1=You first awoke with slight headache on this platform, and the only thing you feel sure of is that you need to rebuild your experiment to escape this dangerous world and return home. +1_2=You cobble together some wires, switches and dials and attach it to the platform. +1_3=Although you are unsure if you managed to achieve anything, you at least feel a bit more in control. + +2_1=The memories of what happened begin to return to you. You were working on an experimental reactor that could distort and displace time and space. +2_2=You recall your early experiments and proceed to replicate them with the crude resources you've found on your journey so far. +2_3=The progress you feel you've made fills you with determination. + +3_1=Ah yes, the experiment went bad! The Warp Reactor ruptured and tore a rift in localized warpspace fabric casting you and the warp platform into an alternate relative dimension in space. +3_2=You hastily assemble the warp reactor control panel from memory, but then stop when you realize you need the reactor core before they can function. +3_3=The feeling like you know what you need to do fills you with determination, if only you had the resources to do it. + +4_1=Before the accident, you remember feeling excited about the endless applications of mastering the control of warpspace and became careless. +4_2=You have finished building the reactor warpdis and rift core, but you are not going to make the same mistakes twice. +4_3=Holding the pulsating warpdis in your hands fills you with determination. + +5_1=You think you know why your experiment went wrong, the warpdis must be unstable unless maintained by perfectly reversing the polarity inversely squared to the rift core's inter-subdimensional artron energy matrix. +5_2=You ready the warpdis to rip the perfected materials you need directly out of warpspace. +5_3=It's a risky strategy, but you believe this is your only chance to escape these savage alien infested worlds and get back to civilization. + +6_1=A loud clash of energy ripples over your warp platform as the reactor shifts into existence, and you know this technology will uplift your civilization beyond their imagination. +6_2=You decide to continue your experiments with the warp reactor while you warp through world after world in search of home, if only you knew how to steer this boat. +6_3=The Warp Reactor finally now in place fills you with determination. + +7_1=You have developed a way to build a miniaturized warpdis connected to your reactors rift core, allowing the transfer of heat energy through warpspace +7_2=You believe this may be further refined into a way to rip chemical artron energy fuel cells out of warpspace through a perfect quasi-misalignment of the warpdis polarity. +7_3=This newfound flexible control over warpspace and time fills you with determination. + +8_1=You have almost lost track of how many worlds you have visited while adrift between dimensions, but you have discovered a way to measure the dimensional relativity of the artron energy signature emitted by the reactors rift core. +8_2=As a result, you are able to chart a map of where you have been, and what might lay ahead. But be wary, the Warp Reactor may not always agree with you, just like the day that started this all. +8_3=Your homeworld in your sights fills you with determination, and you marvel at the fruits of your final warpspace experiments. diff --git a/prototypes-updates/data_accumulators.lua b/prototypes-updates/data_accumulators.lua index d59f4f8..15ecccf 100644 --- a/prototypes-updates/data_accumulators.lua +++ b/prototypes-updates/data_accumulators.lua @@ -1,25 +1,74 @@ -local function istable(t) return type(t)=="table" end -local function rgb(r,g,b,a) a=a or 255 return {r=r/255,g=g/255,b=b/255,a=a/255} end +local function istable(t) return type(t) == "table" end +local function rgb(r, g, b, a) + a = a or 255 + return { r = r / 255, g = g / 255, b = b / 255, a = a / 255 } +end + +function table.deepmerge(s, t) + for k, v in pairs(t) do + if (istable(v) and s[k] and istable(s[k])) then + table.deepmerge( + s[k], v) + else + s[k] = v + end + end +end -function table.deepmerge(s,t) for k,v in pairs(t)do if(istable(v) and s[k] and istable(s[k]))then table.deepmerge(s[k],v) else s[k]=v end end end -function table.merge(s,t) local x={} for k,v in pairs(s)do x[k]=v end for k,v in pairs(t)do x[k]=v end return x end -local function MakeDataCopy(a,b,x) local t=table.deepcopy(data.raw[a][b]) if(x)then table.deepmerge(t,x) end return t end +function table.merge(s, t) + local x = {} + for k, v in pairs(s) do x[k] = v end + for k, v in pairs(t) do x[k] = v end + return x +end + +local function MakeDataCopy(a, b, x) + local t = table.deepcopy(data.raw[a][b]) + if (x) then table.deepmerge(t, x) end + return t +end local function ExtendRecipeItem(t) - local r=table.deepcopy(data.raw.recipe["nuclear-reactor"]) - r.enabled=false r.name=t.name r.ingredients={{"steel-plate",1}} r.result=t.name - local i=table.deepcopy(data.raw.item["nuclear-reactor"]) - i.name=t.name i.place_result=t.name - data:extend{i,r} + local r = table.deepcopy(data.raw.recipe["nuclear-reactor"]) + r.enabled = false + r.name = t.name + r.ingredients = { { type = "item", name = "steel-plate", amount = 1 } } + r.results = { { type = "item", name = t.name, amount = 1 } } + local i = table.deepcopy(data.raw.item["nuclear-reactor"]) + i.name = t.name + i.place_result = t.name + data:extend { i, r } +end +local function ExtendRecipeItemFix(t) t.order = t.order or "warptorio" end +local function ExtendDataCopy(a, b, x, ri, tx) + local t = MakeDataCopy(a, b, x) + if (tx) then for k, v in pairs(tx) do if (v == false) then t[k] = nil else t[k] = v end end end + if (ri) then ExtendRecipeItemFix(t) end + data:extend { t } + return t end -local function ExtendRecipeItemFix(t) t.order=t.order or "warptorio" end -local function ExtendDataCopy(a,b,x,ri,tx) local t=MakeDataCopy(a,b,x) if(tx)then for k,v in pairs(tx)do if(v==false)then t[k]=nil else t[k]=v end end end if(ri)then ExtendRecipeItemFix(t) end data:extend{t} return t end -local techPacks={red="automation-science-pack",green="logistic-science-pack",blue="chemical-science-pack",black="military-science-pack", - purple="production-science-pack",yellow="utility-science-pack",white="space-science-pack"} +local techPacks = { + red = "automation-science-pack", + green = "logistic-science-pack", + blue = "chemical-science-pack", + black = "military-science-pack", + purple = "production-science-pack", + yellow = "utility-science-pack", + white = "space-science-pack" +} -local function SciencePacks(x) local t={} for k,v in pairs(x)do table.insert(t,{techPacks[k],v}) end return t end -local function ExtendTech(t,d,s) local x=table.merge(t,d) if(s)then x.unit.ingredients=SciencePacks(s) end data:extend{x} return x end +local function SciencePacks(x) + local t = {} + for k, v in pairs(x) do table.insert(t, { techPacks[k], v }) end + return t +end +local function ExtendTech(t, d, s) + local x = table.merge(t, d) + if (s) then x.unit.ingredients = SciencePacks(s) end + data:extend { x } + return x +end -- -------- @@ -27,149 +76,225 @@ local function ExtendTech(t,d,s) local x=table.merge(t,d) if(s)then x.unit.ingre -- -- Most other teleporters are based off this one - - -local t={ - name="warptorio-teleporter-0", - type="accumulator", - max_health=500, - energy_source={type="electric",usage_priority="tertiary",buffer_capacity="2MJ",input_flow_limit="200kW",output_flow_limit="200kW"}, - icon_size=64, - icons={{icon="__base__/graphics/icons/lab.png",tint={r=0.6,g=0.6,b=1,a=0.6}}}, - - collision_box={{-1.01/0.9,-1.01/0.9}, {1.01/0.9,1.01/0.9}}, selection_box={{-1.5/0.9,-1.5/0.9}, {1.5/0.9,1.5/0.9}}, - charge_cooldown=30, charge_light={intensity=0.3,size=7,color={r=1.0,g=1.0,b=1.0}}, - discharge_cooldown=60, discharge_light={intensity=0.7,size=7,color={r=1.0,g=1.0,b=1.0}}, - circuit_wire_connection_point=circuit_connector_definitions["accumulator"].points, - circuit_connector_sprites=circuit_connector_definitions["accumulator"].sprites, - circuit_wire_max_distance=default_circuit_wire_max_distance, - default_output_signal={type="virtual", name="signal-A"}, - vehicle_impact_sound={ filename="__base__/sound/car-metal-impact.ogg", volume=0.65 }, - repair_sound = {filename = "__base__/sound/manual-repair-simple.ogg"}, - maximum_wire_distance=7.5, - supply_area_distance=2.5, +local t = { + name = "warptorio-teleporter-0", + type = "accumulator", + max_health = 500, + energy_source = { type = "electric", usage_priority = "tertiary", buffer_capacity = "2MJ", input_flow_limit = "200kW", output_flow_limit = "200kW" }, + icon_size = 64, + icons = { { icon = "__base__/graphics/icons/lab.png", tint = { r = 0.6, g = 0.6, b = 1, a = 0.6 } } }, + + collision_box = { { -1.01 / 0.9, -1.01 / 0.9 }, { 1.01 / 0.9, 1.01 / 0.9 } }, + selection_box = { { -1.5 / 0.9, -1.5 / 0.9 }, { 1.5 / 0.9, 1.5 / 0.9 } }, + circuit_wire_connection_point = circuit_connector_definitions["accumulator"].points, + circuit_connector_sprites = circuit_connector_definitions["accumulator"].sprites, + circuit_wire_max_distance = default_circuit_wire_max_distance, + default_output_signal = { type = "virtual", name = "signal-A" }, + vehicle_impact_sound = { filename = "__base__/sound/car-metal-impact.ogg", volume = 0.65 }, + repair_sound = { filename = "__base__/sound/manual-repair-simple.ogg" }, + maximum_wire_distance = 7.5, + supply_area_distance = 2.5, --minable={mining_time=10,result="warptorio-teleporter-0"}, - - picture={ layers={ - [1]={ filename="__base__/graphics/entity/lab/lab.png", tint={r=0.6,g=0.6,b=1,a=0.6}, - width=98, height=87, frame_count=33, animation_speed=1/3, line_length=11, shift=util.by_pixel(0,1.5), scale=0.9, - hr_version={ filename="__base__/graphics/entity/lab/hr-lab.png", scale=0.45, tint={r=0.6,g=0.6,b=1,a=0.6}, - width=194, height=174, frame_count=33,animation_speed=1/3, line_length=11, shift=util.by_pixel(0, 1.5), - }, - }, - [2]={ filename="__base__/graphics/entity/lab/lab-shadow.png", draw_as_shadow=true, scale=0.9, - width=122, height=68, frame_count=1, line_length=1, repeat_count=33, animation_speed=1/3, shift=util.by_pixel(13,11), - hr_version ={filename="__base__/graphics/entity/lab/hr-lab-shadow.png", draw_as_shadow=true, scale=0.45, - width=242, height=136, frame_count=1, line_length=1, repeat_count=33, animation_speed=1/3, shift=util.by_pixel(13, 11), - }, - }, - [3]={ filename="__base__/graphics/entity/lab/lab-integration.png", scale=0.9, - width=122, height=81, frame_count=1, line_length=1, repeat_count=33, animation_speed=1/3, shift=util.by_pixel(0, 15.5), - hr_version={ filename="__base__/graphics/entity/lab/hr-lab-integration.png", scale=0.45, - width=242, height=162, frame_count=1, line_length=1, repeat_count=33, animation_speed=1/3, shift=util.by_pixel(0, 15.5), - }, + chargable_graphics = + { + charge_cooldown = 30, + charge_light = { intensity = 0.3, size = 7, color = { r = 1.0, g = 1.0, b = 1.0 } }, + discharge_cooldown = 60, + discharge_light = { intensity = 0.7, size = 7, color = { r = 1.0, g = 1.0, b = 1.0 } }, + picture = { + layers = { + [1] = { + filename = "__base__/graphics/entity/lab/lab.png", + scale = 0.45, + tint = { r = 0.6, g = 0.6, b = 1, a = 0.6 }, + width = 194, + height = 174, + frame_count = 33, + repeat_count = 33, + animation_speed = 1 / 3, + line_length = 11, + shift = util.by_pixel(0, 1.5), + }, + [2] = { + filename = "__base__/graphics/entity/lab/lab-shadow.png", + draw_as_shadow = true, + scale = 0.45, + width = 242, + height = 136, + --frame_count = 1, + --line_length = 1, + --animation_speed = 1 / 3, + shift = util.by_pixel(13, 11), + }, + [3] = { + filename = "__base__/graphics/entity/lab/lab-integration.png", + scale = 0.45, + width = 242, + height = 162, + frame_count = 1, + line_length = 1, + repeat_count = 33, + animation_speed = 1 / 3, + shift = util.by_pixel(0, 15.5), + }, + } }, - }}, + }, } ExtendRecipeItemFix(t) -data:extend{t} - - -local t=ExtendDataCopy("accumulator","warptorio-teleporter-0",{name="warptorio-teleporter-1",energy_source={buffer_capacity="4MJ",input_flow_limit="2MW",output_flow_limit="2MW"}},true) -local t=ExtendDataCopy("accumulator","warptorio-teleporter-0",{name="warptorio-teleporter-2",energy_source={buffer_capacity="8MJ",input_flow_limit="20MW",output_flow_limit="20MW"}},true) -local t=ExtendDataCopy("accumulator","warptorio-teleporter-0",{name="warptorio-teleporter-3",energy_source={buffer_capacity="16MJ",input_flow_limit="200MW",output_flow_limit="200MW"}},true) -local t=ExtendDataCopy("accumulator","warptorio-teleporter-0",{name="warptorio-teleporter-4",energy_source={buffer_capacity="32MJ",input_flow_limit="2000MW",output_flow_limit="2000MW"}},true) -local t=ExtendDataCopy("accumulator","warptorio-teleporter-0",{name="warptorio-teleporter-5",energy_source={buffer_capacity="64MJ",input_flow_limit="20000MW",output_flow_limit="20000MW"}},true) +data:extend { t } + + +local t = ExtendDataCopy("accumulator", "warptorio-teleporter-0", + { name = "warptorio-teleporter-1", energy_source = { buffer_capacity = "4MJ", input_flow_limit = "2MW", output_flow_limit = "2MW" } }, + true) +local t = ExtendDataCopy("accumulator", "warptorio-teleporter-0", + { name = "warptorio-teleporter-2", energy_source = { buffer_capacity = "8MJ", input_flow_limit = "20MW", output_flow_limit = "20MW" } }, + true) +local t = ExtendDataCopy("accumulator", "warptorio-teleporter-0", + { name = "warptorio-teleporter-3", energy_source = { buffer_capacity = "16MJ", input_flow_limit = "200MW", output_flow_limit = "200MW" } }, + true) +local t = ExtendDataCopy("accumulator", "warptorio-teleporter-0", + { name = "warptorio-teleporter-4", energy_source = { buffer_capacity = "32MJ", input_flow_limit = "2000MW", output_flow_limit = "2000MW" } }, + true) +local t = ExtendDataCopy("accumulator", "warptorio-teleporter-0", + { name = "warptorio-teleporter-5", energy_source = { buffer_capacity = "64MJ", input_flow_limit = "20000MW", output_flow_limit = "20000MW" } }, + true) -- -------- -- Teleporter Gate -local t=ExtendDataCopy("accumulator","warptorio-teleporter-0",{name="warptorio-teleporter-gate-0",minable={mining_time=2,result="warptorio-teleporter-gate-0"}, - picture={layers={[1]={ tint={r=1,g=0.8,b=0.8,a=0.6}, hr_version={tint={r=1,g=0.8,b=0.8,a=0.6}}, } }}, }) -local t=ExtendDataCopy("recipe","lab",{name="warptorio-teleporter-gate-0",enabled=false}) -local t=ExtendDataCopy("item","lab",{name="warptorio-teleporter-gate-0",place_result="warptorio-teleporter-gate-0", - icons={{ icon="__base__/graphics/icons/lab.png", tint={r=1,g=0.6,b=0.6,a=0.6}, }}, }) +local t = ExtendDataCopy("accumulator", "warptorio-teleporter-0", + { + name = "warptorio-teleporter-gate-0", + minable = { mining_time = 2, result = "warptorio-teleporter-gate-0" }, + chargable_graphics = { picture = { layers = { { tint = { r = 1, g = 0.8, b = 0.8, a = 0.6 } } }, } } + }) +local t = ExtendDataCopy("recipe", "lab", { name = "warptorio-teleporter-gate-0", enabled = false }) +local t = ExtendDataCopy("item", "lab", { + name = "warptorio-teleporter-gate-0", + place_result = "warptorio-teleporter-gate-0", + icons = { { icon = "__base__/graphics/icons/lab.png", tint = { r = 1, g = 0.6, b = 0.6, a = 0.6 }, icon_size = 64 } }, +}) -local t=ExtendDataCopy("accumulator","warptorio-teleporter-gate-0",{name="warptorio-teleporter-gate-1",energy_source={buffer_capacity="4MJ",input_flow_limit="2MW",output_flow_limit="2MW"}},true) -local t=ExtendDataCopy("accumulator","warptorio-teleporter-gate-0",{name="warptorio-teleporter-gate-2",energy_source={buffer_capacity="8MJ",input_flow_limit="20MW",output_flow_limit="20MW"}},true) -local t=ExtendDataCopy("accumulator","warptorio-teleporter-gate-0",{name="warptorio-teleporter-gate-3",energy_source={buffer_capacity="16MJ",input_flow_limit="200MW",output_flow_limit="200MW"}},true) -local t=ExtendDataCopy("accumulator","warptorio-teleporter-gate-0",{name="warptorio-teleporter-gate-4",energy_source={buffer_capacity="32MJ",input_flow_limit="2GW",output_flow_limit="2GW"}},true) -local t=ExtendDataCopy("accumulator","warptorio-teleporter-gate-0",{name="warptorio-teleporter-gate-5",energy_source={buffer_capacity="64MJ",input_flow_limit="20GW",output_flow_limit="20GW"}},true) +local t = ExtendDataCopy("accumulator", "warptorio-teleporter-gate-0", + { name = "warptorio-teleporter-gate-1", energy_source = { buffer_capacity = "4MJ", input_flow_limit = "2MW", output_flow_limit = "2MW" } }, + true) +local t = ExtendDataCopy("accumulator", "warptorio-teleporter-gate-0", + { name = "warptorio-teleporter-gate-2", energy_source = { buffer_capacity = "8MJ", input_flow_limit = "20MW", output_flow_limit = "20MW" } }, + true) +local t = ExtendDataCopy("accumulator", "warptorio-teleporter-gate-0", + { name = "warptorio-teleporter-gate-3", energy_source = { buffer_capacity = "16MJ", input_flow_limit = "200MW", output_flow_limit = "200MW" } }, + true) +local t = ExtendDataCopy("accumulator", "warptorio-teleporter-gate-0", + { name = "warptorio-teleporter-gate-4", energy_source = { buffer_capacity = "32MJ", input_flow_limit = "2GW", output_flow_limit = "2GW" } }, + true) +local t = ExtendDataCopy("accumulator", "warptorio-teleporter-gate-0", + { name = "warptorio-teleporter-gate-5", energy_source = { buffer_capacity = "64MJ", input_flow_limit = "20GW", output_flow_limit = "20GW" } }, + true) -- ---- -- Stairways -local t=ExtendDataCopy("accumulator","warptorio-teleporter-0",{name="warptorio-underground-0",energy_source={buffer_capacity="2MJ",input_flow_limit="5MW",output_flow_limit="5MW"},},true,{ - picture={layers={ - [1]={ tint={r=0.8,g=0.8,b=1,a=1}, scale=0.9, - filename="__base__/graphics/entity/electric-furnace/electric-furnace-base.png", priority="high", width=129, height=100, frame_count=1, shift={0.421875/2, 0}, - hr_version={ filename="__base__/graphics/entity/electric-furnace/hr-electric-furnace.png", tint={r=0.8,g=0.8,b=1,a=1}, - scale=0.45, priority="high", width=239, height=219, frame_count=1, shift=util.by_pixel(0.75, 5.75), +local t = ExtendDataCopy("accumulator", "warptorio-teleporter-0", + { name = "warptorio-underground-0", energy_source = { buffer_capacity = "2MJ", input_flow_limit = "5MW", output_flow_limit = "5MW" }, }, + true, { + chargable_graphics = + { + picture = { + layers = { + [1] = { + filename = "__base__/graphics/entity/electric-furnace/electric-furnace.png", + tint = { r = 0.8, g = 0.8, b = 1, a = 1 }, + scale = 0.45, + priority = "high", + width = 239, + height = 219, + frame_count = 1, + shift = util.by_pixel(0.75, 5.75), + }, + [2] = { + filename = "__base__/graphics/entity/electric-furnace/electric-furnace-shadow.png", + draw_as_shadow = true, + priority = "high", + width = 227, + height = 171, + frame_count = 1, + draw_as_shadow = true, + shift = util.by_pixel(11.25, 7.75), + scale = 0.45, + }, + } }, }, - [2]={ - filename="__base__/graphics/entity/electric-furnace/electric-furnace-shadow.png", draw_as_shadow=true, scale=0.9, - priority="high", width=129, height=100, frame_count=1, shift={0.421875,0}, - hr_version={ filename="__base__/graphics/entity/electric-furnace/hr-electric-furnace-shadow.png", - priority="high", width=227, height=171, frame_count=1, draw_as_shadow=true, shift=util.by_pixel(11.25, 7.75), scale=0.45, - }, - }, - }}, - icon_size=32, - icons={{icon="__base__/graphics/icons/electric-furnace.png",tint={r=0.8,g=0.8,b=1,a=1}}}, - icon=false, -}) - -local t=ExtendDataCopy("accumulator","warptorio-underground-0",{name="warptorio-underground-1",energy_source={buffer_capacity="10MJ",input_flow_limit="500MW",output_flow_limit="500MW"},},true) -local t=ExtendDataCopy("accumulator","warptorio-underground-0",{name="warptorio-underground-2",energy_source={buffer_capacity="50MJ",input_flow_limit="1GW",output_flow_limit="1GW"},},true) -local t=ExtendDataCopy("accumulator","warptorio-underground-0",{name="warptorio-underground-3",energy_source={buffer_capacity="100MJ",input_flow_limit="2GW",output_flow_limit="2GW"},},true) -local t=ExtendDataCopy("accumulator","warptorio-underground-0",{name="warptorio-underground-4",energy_source={buffer_capacity="500MJ",input_flow_limit="5GW",output_flow_limit="5GW"},},true) -local t=ExtendDataCopy("accumulator","warptorio-underground-0",{name="warptorio-underground-5",energy_source={buffer_capacity="1GJ",input_flow_limit="20GW",output_flow_limit="20GW"},},true) - - + icon_size = 32, + icons = { { icon = "__base__/graphics/icons/electric-furnace.png", tint = { r = 0.8, g = 0.8, b = 1, a = 1 } } }, + icon = false, + }) + +local t = ExtendDataCopy("accumulator", "warptorio-underground-0", + { name = "warptorio-underground-1", energy_source = { buffer_capacity = "10MJ", input_flow_limit = "500MW", output_flow_limit = "500MW" }, }, + true) +local t = ExtendDataCopy("accumulator", "warptorio-underground-0", + { name = "warptorio-underground-2", energy_source = { buffer_capacity = "50MJ", input_flow_limit = "1GW", output_flow_limit = "1GW" }, }, + true) +local t = ExtendDataCopy("accumulator", "warptorio-underground-0", + { name = "warptorio-underground-3", energy_source = { buffer_capacity = "100MJ", input_flow_limit = "2GW", output_flow_limit = "2GW" }, }, + true) +local t = ExtendDataCopy("accumulator", "warptorio-underground-0", + { name = "warptorio-underground-4", energy_source = { buffer_capacity = "500MJ", input_flow_limit = "5GW", output_flow_limit = "5GW" }, }, + true) +local t = ExtendDataCopy("accumulator", "warptorio-underground-0", + { name = "warptorio-underground-5", energy_source = { buffer_capacity = "1GJ", input_flow_limit = "20GW", output_flow_limit = "20GW" }, }, + true) -- Do icon based stairs - - - - -- ---- -- Warp Accumulator -local rtint={r=0.4,g=0.4,b=1,a=1} -local t=ExtendDataCopy("accumulator","accumulator",{name="warptorio-accumulator", - energy_source={ type="electric", usage_priority="tertiary", emissions_per_minute=5, - input_flow_limit="5GW", output_flow_limit="5GW", buffer_capacity="1GJ", +local rtint = { r = 0.4, g = 0.4, b = 1, a = 1 } +local t = ExtendDataCopy("accumulator", "accumulator", { + name = "warptorio-accumulator", + energy_source = { + type = "electric", + usage_priority = "tertiary", + emissions_per_minute = { pollution = 5 }, + input_flow_limit = "5GW", + output_flow_limit = "5GW", + buffer_capacity = "1GJ", }, - picture={layers={ {tint=rtint,hr_version={tint=rtint},} }}, - minable={mining_time=2,result="warptorio-accumulator"}, - - icons={{icon="__base__/graphics/icons/accumulator.png",tint=rtint,icon_size=64,}}, -},false,{icon=false}) -local name="warptorio-accumulator" -local item=table.deepcopy( data.raw.item.accumulator ) -item.name=name item.place_result=name -item.icons={{icon="__base__/graphics/icons/accumulator.png",tint=rtint}} -item.icon=nil -local recipe=table.deepcopy( data.raw.recipe["accumulator"] ) -recipe.enabled=false recipe.name=name recipe.result=name -recipe.ingredients={{"accumulator",10},{"solar-panel",10},{"advanced-circuit",20},{"processing-unit",50},{"battery",50},{"nuclear-reactor",1}} -data:extend{item,recipe} - -local t={type="technology",upgrade=true,icon_size=128,icons={ - {icon="__base__/graphics/technology/electric-energy-acumulators.png",tint={r=0.3,g=0.3,b=1,a=1},priority="low",icon_size=256,}, -}, } -ExtendTech(t,{name="warptorio-accumulator",unit={count=1000,time=5},effects={{recipe="warptorio-accumulator",type="unlock-recipe"}}, - prerequisites={"warptorio-energy-4","warptorio-teleporter-4","production-science-pack"}}, {red=1,green=1,blue=1,purple=1}) - - - - - - - - - - - + picture = { layers = { { tint = rtint, } } }, + minable = { mining_time = 2, result = "warptorio-accumulator" }, + + icons = { { icon = "__base__/graphics/icons/accumulator.png", tint = rtint, icon_size = 64, } }, +}, false, { icon = false }) +local name = "warptorio-accumulator" +local item = table.deepcopy(data.raw.item.accumulator) +item.name = name +item.place_result = name +item.icons = { { icon = "__base__/graphics/icons/accumulator.png", tint = rtint } } +item.icon = nil +local recipe = table.deepcopy(data.raw.recipe["accumulator"]) +recipe.enabled = false +recipe.name = name +recipe.results = { { type = "item", name = name, amount = 1 } } +recipe.ingredients = { { type = "item", name = "accumulator", amount = 10 }, { type = "item", name = "solar-panel", amount = 10 }, { type = "item", name = "advanced-circuit", amount = 20 }, { type = "item", name = "processing-unit", amount = 50 }, { type = "item", name = "battery", amount = 50 }, { type = "item", name = "nuclear-reactor", amount = 1 } } +data:extend { item, recipe } + +local t = { + type = "technology", + upgrade = true, + icon_size = 128, + icons = { + { icon = "__base__/graphics/technology/electric-energy-acumulators.png", tint = { r = 0.3, g = 0.3, b = 1, a = 1 }, priority = "low", icon_size = 256, }, + }, +} +ExtendTech(t, + { + name = "warptorio-accumulator", + unit = { count = 1000, time = 30 }, + effects = { { recipe = "warptorio-accumulator", type = "unlock-recipe" } }, + prerequisites = { "warptorio-energy-4", "warptorio-teleporter-4", "production-science-pack" } + }, + { red = 1, green = 1, blue = 1, purple = 1 }) diff --git a/prototypes-updates/data_warptorio-harvester.lua b/prototypes-updates/data_warptorio-harvester.lua index 44272aa..1302405 100644 --- a/prototypes-updates/data_warptorio-harvester.lua +++ b/prototypes-updates/data_warptorio-harvester.lua @@ -1,43 +1,103 @@ -local function istable(t) return type(t)=="table" end -local function rgb(r,g,b,a) a=a or 255 return {r=r/255,g=g/255,b=b/255,a=a/255} end +local function istable(t) return type(t) == "table" end +local function rgb(r, g, b, a) + a = a or 255 + return { r = r / 255, g = g / 255, b = b / 255, a = a / 255 } +end -function table.deepmerge(s,t) for k,v in pairs(t)do if(istable(v) and s[k] and istable(s[k]))then table.deepmerge(s[k],v) else s[k]=v end end end -function table.merge(s,t) local x={} for k,v in pairs(s)do x[k]=v end for k,v in pairs(t)do x[k]=v end return x end -local function MakeDataCopy(a,b,x) local t=table.deepcopy(data.raw[a][b]) if(x)then table.deepmerge(t,x) end return t end +function table.deepmerge(s, t) + for k, v in pairs(t) do + if (istable(v) and s[k] and istable(s[k])) then + table.deepmerge( + s[k], v) + else + s[k] = v + end + end +end -local function ExtendRecipeItem(t) - local r=table.deepcopy(data.raw.recipe["nuclear-reactor"]) - r.enabled=false r.name=t.name r.ingredients={{"steel-plate",1}} r.result=t.name - local i=table.deepcopy(data.raw.item["nuclear-reactor"]) - i.name=t.name i.place_result=t.name - i.flags={"hidden"} - data:extend{i,r} +function table.merge(s, t) + local x = {} + for k, v in pairs(s) do x[k] = v end + for k, v in pairs(t) do x[k] = v end + return x +end + +local function MakeDataCopy(a, b, x) + local t = table.deepcopy(data.raw[a][b]) + if (x) then table.deepmerge(t, x) end + return t end -local function ExtendDataCopy(a,b,x,ri,tx) local t=MakeDataCopy(a,b,x) if(tx)then for k,v in pairs(tx)do if(v==false)then t[k]=nil else t[k]=v end end end - if(ri)then ExtendRecipeItem(t) elseif(ri==false)then t.order=t.order or "warptorio" end - data:extend{t} return t +local function ExtendRecipeItem(t) + local r = table.deepcopy(data.raw.recipe["nuclear-reactor"]) + r.enabled = false + r.name = t.name + r.ingredients = { { type = "item", name = "steel-plate", amount = 1 } } + r.results = { { type = "item", name = t.name, amount = 1 } } + local i = table.deepcopy(data.raw.item["nuclear-reactor"]) + i.name = t.name + i.place_result = t.name + i.hidden = true + data:extend { i, r } end +local function ExtendDataCopy(a, b, x, ri, tx) + local t = MakeDataCopy(a, b, x) + if (tx) then for k, v in pairs(tx) do if (v == false) then t[k] = nil else t[k] = v end end end + if (ri) then ExtendRecipeItem(t) elseif (ri == false) then t.order = t.order or "warptorio" end + data:extend { t } + return t +end -local techPacks={red="automation-science-pack",green="logistic-science-pack",blue="chemical-science-pack",black="military-science-pack", - purple="production-science-pack",yellow="utility-science-pack",white="space-science-pack"} -local function SciencePacks(x) local t={} for k,v in pairs(x)do table.insert(t,{techPacks[k],v}) end return t end -local function ExtendTech(t,d,s) local x=table.merge(t,d) if(s)then x.unit.ingredients=SciencePacks(s) end data:extend{x} return x end +local techPacks = { + red = "automation-science-pack", + green = "logistic-science-pack", + blue = "chemical-science-pack", + black = "military-science-pack", + purple = "production-science-pack", + yellow = "utility-science-pack", + white = "space-science-pack" +} + +local function SciencePacks(x) + local t = {} + for k, v in pairs(x) do table.insert(t, { techPacks[k], v }) end + return t +end +local function ExtendTech(t, d, s) + local x = table.merge(t, d) + if (s) then x.unit.ingredients = SciencePacks(s) end + data:extend { x } + return x +end --for k,v in pairs{"nw","sw","se","ne","west","east"}do -local t=ExtendDataCopy("accumulator","warptorio-teleporter-0",{name="warptorio-harvestportal-0", - minable={mining_time=5,result="warptorio-harvestportal-1"},energy_source={buffer_capacity="5MJ",input_flow_limit="500kW",output_flow_limit="500kW"}},false) - -local t=ExtendDataCopy("accumulator","warptorio-teleporter-0",{name="warptorio-harvestportal-1", - minable={mining_time=5,result="warptorio-harvestportal-1"},energy_source={buffer_capacity="10MJ",input_flow_limit="500MW",output_flow_limit="500MW"}},true) -local t=ExtendDataCopy("accumulator","warptorio-harvestportal-1",{name="warptorio-harvestportal-2",energy_source={buffer_capacity="50MJ",input_flow_limit="1GW",output_flow_limit="1GW"}},false) -local t=ExtendDataCopy("accumulator","warptorio-harvestportal-1",{name="warptorio-harvestportal-3",energy_source={buffer_capacity="100MJ",input_flow_limit="2GW",output_flow_limit="2GW"}},false) -local t=ExtendDataCopy("accumulator","warptorio-harvestportal-1",{name="warptorio-harvestportal-4",energy_source={buffer_capacity="500MJ",input_flow_limit="5GW",output_flow_limit="5GW"}},false) -local t=ExtendDataCopy("accumulator","warptorio-harvestportal-1",{name="warptorio-harvestportal-5",energy_source={buffer_capacity="1GJ",input_flow_limit="20GW",output_flow_limit="20GW"}},false) +local t = ExtendDataCopy("accumulator", "warptorio-teleporter-0", { + name = "warptorio-harvestportal-0", + minable = { mining_time = 5, result = "warptorio-harvestportal-1" }, + energy_source = { buffer_capacity = "5MJ", input_flow_limit = "500kW", output_flow_limit = "500kW" } +}, false) + +local t = ExtendDataCopy("accumulator", "warptorio-teleporter-0", { + name = "warptorio-harvestportal-1", + minable = { mining_time = 5, result = "warptorio-harvestportal-1" }, + energy_source = { buffer_capacity = "10MJ", input_flow_limit = "500MW", output_flow_limit = "500MW" } +}, true) +local t = ExtendDataCopy("accumulator", "warptorio-harvestportal-1", + { name = "warptorio-harvestportal-2", energy_source = { buffer_capacity = "50MJ", input_flow_limit = "1GW", output_flow_limit = "1GW" } }, + false) +local t = ExtendDataCopy("accumulator", "warptorio-harvestportal-1", + { name = "warptorio-harvestportal-3", energy_source = { buffer_capacity = "100MJ", input_flow_limit = "2GW", output_flow_limit = "2GW" } }, + false) +local t = ExtendDataCopy("accumulator", "warptorio-harvestportal-1", + { name = "warptorio-harvestportal-4", energy_source = { buffer_capacity = "500MJ", input_flow_limit = "5GW", output_flow_limit = "5GW" } }, + false) +local t = ExtendDataCopy("accumulator", "warptorio-harvestportal-1", + { name = "warptorio-harvestportal-5", energy_source = { buffer_capacity = "1GJ", input_flow_limit = "20GW", output_flow_limit = "20GW" } }, + false) --end @@ -50,10 +110,10 @@ local F = "__warptorio2__"; require("circuit-connector-sprites") local function cwc0() - return {shadow = {red = {0,0},green = {0,0}}, wire = {red = {0,0},green = {0,0}}} + return { shadow = { red = { 0, 0 }, green = { 0, 0 } }, wire = { red = { 0, 0 }, green = { 0, 0 } } } end local function cc0() - return get_circuit_connector_sprites({0,0},nil,1) + return get_circuit_connector_sprites({ 0, 0 }, nil, 1) end local function blank() return { @@ -72,38 +132,46 @@ local function ablank() frame_count = 1, } end -local rtint={r=0.6,g=0.6,b=0.8,a=1} +local rtint = { r = 0.6, g = 0.6, b = 0.8, a = 1 } -local function makePortal(suffix, visible, sprite,size,vorder,btag) +local function makePortal(suffix, visible, sprite, size, vorder, btag) local name = "warptorio-harvestpad-" .. suffix - local localised_name = {"entity-name.warptorio-harvestpad-" .. suffix} + local localised_name = { "entity-name.warptorio-harvestpad-" .. suffix } local result_name = "warptorio-harvestpad-" .. suffix local item_flags - if visible then item_flags = {} else item_flags = {"hidden"} end + local shift_side + if suffix:sub(1, 4) == "west" then + shift_side = 1 + else + shift_side = -1 + end + if visible then item_flags = {} else item_flags = { "hidden" } end return { { type = "storage-tank", name = name, localised_name = localised_name, - icons = {{icon="__base__/graphics/icons/lab.png",tint=rtint,}}, + icons = { { icon = "__base__/graphics/icons/lab.png", tint = rtint, } }, icon_size = 64, - flags = {"player-creation"}, - minable = {mining_time = 5, result = result_name, count = 1}, + flags = { "player-creation" }, + minable = { mining_time = 5, result = result_name, count = 1 }, max_health = 2000, corpse = "big-remnants", - collision_box = {{-size, -size}, {size, size}}, - selection_box = {{-size, -size}, {size, size}}, - collision_mask={"item-layer","object-layer","water-tile"}, + collision_box = { { -size, -size }, { size, size } }, + selection_box = { { -size, -size }, { size, size } }, + collision_mask = { layers = { item = true, object = true, water_tile = true } }, vehicle_impact_sound = { filename = "__base__/sound/car-stone-impact.ogg", volume = 1.0 }, pictures = { picture = { sheet = { - filename = sprite, tint={r=1,g=1,b=1,a=0.3}, + filename = sprite, + tint = { r = 1, g = 1, b = 1, a = 0.3 }, frames = 1, width = 32, - height = 32,scale=size*2, - shift = {0, 0}, + height = 32, + scale = size * 2, + shift = { 0, 0 }, }, }, fluid_background = blank(), @@ -111,8 +179,9 @@ local function makePortal(suffix, visible, sprite,size,vorder,btag) flow_sprite = blank(), gas_flow = ablank(), }, - window_bounding_box = {{0,0},{0,0}}, + window_bounding_box = { { 0, 0 }, { 0, 0 } }, fluid_box = { + volume = 100, base_area = 1, pipe_covers = pipecoverspictures(), pipe_connections = {}, @@ -121,14 +190,14 @@ local function makePortal(suffix, visible, sprite,size,vorder,btag) circuit_wire_connection_points = circuit_connector_definitions["storage-tank"].points, circuit_connector_sprites = circuit_connector_definitions["storage-tank"].sprites, circuit_wire_max_distance = 0, - map_color = {r = 0.8, g = 0.7, b = 0.55}, + map_color = { r = 0.8, g = 0.7, b = 0.55 }, }, { - flags={"hidden"}, + flags = { "hidden" }, type = (btag and "item-with-tags" or "item"), name = name, localised_name = localised_name, - icons = {{icon="__base__/graphics/icons/lab.png",tint=rtint,}}, + icons = { { icon = "__base__/graphics/icons/lab.png", tint = rtint, }, { icon = "__base__/graphics/icons/fast-underground-belt.png", scale = 0.3, shift = { shift_side * 8, 0 } } }, icon_size = 64, flags = item_flags, subgroup = "storage", @@ -139,39 +208,32 @@ local function makePortal(suffix, visible, sprite,size,vorder,btag) }; end -data:extend(makePortal("nw",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(20-1)/2,"a-c")) -data:extend(makePortal("sw",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(20-1)/2,"a-f")) -data:extend(makePortal("ne",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(20-1)/2,"a-d")) -data:extend(makePortal("se",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(20-1)/2,"a-e")) - - - -data:extend(makePortal("west-1",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(12-1)/2,"a-a1")) -data:extend(makePortal("west-2",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(20-1)/2,"a-a2")) -data:extend(makePortal("west-3",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(26-1)/2,"a-a3")) -data:extend(makePortal("west-4",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(32-1)/2,"a-a4")) -data:extend(makePortal("west-5",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(38-1)/2,"a-a5")) -data:extend(makePortal("west-6",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(46-1)/2,"a-a6")) - -data:extend(makePortal("east-1",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(12-1)/2,"a-b1")) -data:extend(makePortal("east-2",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(20-1)/2,"a-b2")) -data:extend(makePortal("east-3",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(26-1)/2,"a-b3")) -data:extend(makePortal("east-4",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(32-1)/2,"a-b4")) -data:extend(makePortal("east-5",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(38-1)/2,"a-b5")) -data:extend(makePortal("east-6",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(46-1)/2,"a-b6")) - -data:extend(makePortal("tag-1",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(12-1)/2,"a-c1",true)) -data:extend(makePortal("tag-2",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(20-1)/2,"a-c2",true)) -data:extend(makePortal("tag-3",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(26-1)/2,"a-c3",true)) -data:extend(makePortal("tag-4",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(32-1)/2,"a-c4",true)) -data:extend(makePortal("tag-5",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(38-1)/2,"a-c5",true)) -data:extend(makePortal("tag-6",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(46-1)/2,"a-c6",true)) +--data:extend(makePortal("nw",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(20-1)/2,"a-c")) +--data:extend(makePortal("sw",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(20-1)/2,"a-f")) +--data:extend(makePortal("ne",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(20-1)/2,"a-d")) +--data:extend(makePortal("se",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",(20-1)/2,"a-e")) + +data:extend(makePortal("west-1", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (12 - 1) / 2, "a-a1")) +data:extend(makePortal("west-2", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (20 - 1) / 2, "a-a2")) +data:extend(makePortal("west-3", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (26 - 1) / 2, "a-a3")) +data:extend(makePortal("west-4", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (32 - 1) / 2, "a-a4")) +data:extend(makePortal("west-5", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (38 - 1) / 2, "a-a5")) +--data:extend(makePortal("west-6", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (46 - 1) / 2, "a-a6")) + +data:extend(makePortal("east-1", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (12 - 1) / 2, "a-b1")) +data:extend(makePortal("east-2", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (20 - 1) / 2, "a-b2")) +data:extend(makePortal("east-3", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (26 - 1) / 2, "a-b3")) +data:extend(makePortal("east-4", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (32 - 1) / 2, "a-b4")) +data:extend(makePortal("east-5", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (38 - 1) / 2, "a-b5")) +--data:extend(makePortal("east-6", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (46 - 1) / 2, "a-b6")) + +data:extend(makePortal("tag-1", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (12 - 1) / 2, "a-c1", true)) +data:extend(makePortal("tag-2", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (20 - 1) / 2, "a-c2", true)) +data:extend(makePortal("tag-3", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (26 - 1) / 2, "a-c3", true)) +data:extend(makePortal("tag-4", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (32 - 1) / 2, "a-c4", true)) +data:extend(makePortal("tag-5", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (38 - 1) / 2, "a-c5", true)) +--data:extend(makePortal("tag-6", true, "__base__/graphics/terrain/lab-tiles/lab-dark-2.png", (46 - 1) / 2, "a-c6", true)) --data:extend(makePortal("giga-west",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",16.5)) --data:extend(makePortal("giga-east",true,"__base__/graphics/terrain/lab-tiles/lab-dark-2.png",16.5)) - - - - - diff --git a/prototypes/data_warpnuke.lua b/prototypes/data_warpnuke.lua index c35a95c..0f51ee2 100644 --- a/prototypes/data_warpnuke.lua +++ b/prototypes/data_warpnuke.lua @@ -10,10 +10,12 @@ data:extend{ enabled = false, energy_required = 50, ingredients = { - {"atomic-bomb",1},{"warptorio-warponium-fuel-cell",1},{"warptorio-warponium-fuel",1} + {type="item", name="atomic-bomb", amount=1}, + {type="item", name="warptorio-warponium-fuel-cell", amount=1}, + {type="item", name="warptorio-warponium-fuel", amount=1} }, name = "warptorio-atomic-bomb", - result = "warptorio-atomic-bomb", + results = {{type="item", name="warptorio-atomic-bomb", amount=1}}, type = "recipe" }, @@ -43,7 +45,8 @@ data:extend{ order = "d[rocket-launcher]-c[atomic-bomb]", stack_size = 10, subgroup = "ammo", - type = "ammo" + type = "ammo", + ammo_category = "rocket" }, @@ -168,15 +171,15 @@ data:extend{ }, animation = { tint=rtint, filename = "__base__/graphics/entity/rocket/rocket.png", - frame_count = 8, - height = 35, - line_length = 8, + frame_count = 1, + height = 60, + line_length = 1, priority = "high", shift = { 0, 0 }, - width = 9 + width = 20 }, flags = { "not-on-map" @@ -186,17 +189,6 @@ data:extend{ size = 15 }, name = "warptorio-atomic-rocket", - shadow = { - filename = "__base__/graphics/entity/rocket/rocket-shadow.png", - frame_count = 1, - height = 24, - priority = "high", - shift = { - 0, - 0 - }, - width = 7 - }, smoke = { { deviation = { @@ -276,56 +268,30 @@ animations = { animation_speed = 0.5, filename = "__base__/graphics/entity/explosion/explosion-1.png", frame_count = 17, - height = 22, - hr_version = {tint=rtint, - animation_speed = 0.5, - filename = "__base__/graphics/entity/explosion/hr-explosion-1.png", - frame_count = 17, - height = 42, - line_length = 6, - priority = "high", - scale = 0.5, - shift = { - 0.140625, - 0.1875 - }, - width = 48 - }, + height = 42, line_length = 6, priority = "high", + scale = 0.5, shift = { - 0.15625, + 0.140625, 0.1875 }, - width = 26 + width = 48 }, {tint=rtint, animation_speed = 0.5, filename = "__base__/graphics/entity/explosion/explosion-3.png", frame_count = 17, - height = 46, - hr_version = {tint=rtint, - animation_speed = 0.5, - filename = "__base__/graphics/entity/explosion/hr-explosion-3.png", - frame_count = 17, - height = 88, - line_length = 6, - priority = "high", - scale = 0.5, - shift = { - -0.03125, - 0.046875 - }, - width = 102 - }, + height = 88, line_length = 6, priority = "high", + scale = 0.5, shift = { -0.03125, - 0.0625 + 0.046875 }, - width = 52 - } + width = 102 + }, }, diff --git a/prototypes/data_warptorio-combinator.lua b/prototypes/data_warptorio-combinator.lua index 71dc28b..d7130b5 100644 --- a/prototypes/data_warptorio-combinator.lua +++ b/prototypes/data_warptorio-combinator.lua @@ -1,245 +1,173 @@ -local rtint={r=0.5,g=0.5,b=1,a=1} +local rtint = { r = 0.5, g = 0.5, b = 1, a = 1 } ---[[ Combinator Sprites ]]-- +--[[ Combinator Sprites ]] -- - sprites = { - east = { - layers = { - { tint=rtint, - filename = "__base__/graphics/entity/combinator/constant-combinator.png", - frame_count = 1, - height = 52, - hr_version = { tint=rtint, - filename = "__base__/graphics/entity/combinator/hr-constant-combinator.png", - frame_count = 1, - height = 102, - priority = "high", - scale = 0.5, - shift = { - 0, - 0.15625 - }, - width = 114, - x = 114 - }, - priority = "high", - scale = 1, - shift = { - 0, - 0.15625 - }, - width = 58, - x = 58 - }, - { - draw_as_shadow = true, - filename = "__base__/graphics/entity/combinator/constant-combinator-shadow.png", - frame_count = 1, - height = 34, - hr_version = { - draw_as_shadow = true, - filename = "__base__/graphics/entity/combinator/hr-constant-combinator-shadow.png", - frame_count = 1, - height = 66, - priority = "high", - scale = 0.5, - shift = { - 0.265625, - 0.171875 - }, - width = 98, - x = 98 - }, - priority = "high", - scale = 1, - shift = { - 0.28125, - 0.1875 - }, - width = 50, - x = 50 - } - } +sprites = { + east = { + layers = { + { + tint = rtint, + filename = "__base__/graphics/entity/combinator/constant-combinator.png", + frame_count = 1, + height = 102, + priority = "high", + scale = 0.5, + shift = { + 0, + 0.15625 }, - north = { - layers = { - { tint=rtint, - filename = "__base__/graphics/entity/combinator/constant-combinator.png", - frame_count = 1, - height = 52, - hr_version = { tint=rtint, - filename = "__base__/graphics/entity/combinator/hr-constant-combinator.png", - frame_count = 1, - height = 102, - priority = "high", - scale = 0.5, - shift = nil, - width = 114, - x = 0 - }, - priority = "high", - scale = 1, - shift = nil, - width = 58, - x = 0 - }, - { - draw_as_shadow = true, - filename = "__base__/graphics/entity/combinator/constant-combinator-shadow.png", - frame_count = 1, - height = 34, - hr_version = { - draw_as_shadow = true, - filename = "__base__/graphics/entity/combinator/hr-constant-combinator-shadow.png", - frame_count = 1, - height = 66, - priority = "high", - scale = 0.5, - shift = nil, - width = 98, - x = 0 - }, - priority = "high", - scale = 1, - shift = nil, - width = 50, - x = 0 - } - } + width = 114, + x = 114 + }, + { + draw_as_shadow = true, + filename = "__base__/graphics/entity/combinator/constant-combinator-shadow.png", + frame_count = 1, + height = 66, + priority = "high", + scale = 0.5, + shift = { + 0.265625, + 0.171875 }, - south = { - layers = { - { tint=rtint, - filename = "__base__/graphics/entity/combinator/constant-combinator.png", - frame_count = 1, - height = 52, - hr_version = { tint=rtint, - filename = "__base__/graphics/entity/combinator/hr-constant-combinator.png", - frame_count = 1, - height = 102, - priority = "high", - scale = 0.5, - shift = nil, - width = 114, - x = 228 - }, - priority = "high", - scale = 1, - shift = nil, - width = 58, - x = 116 - }, - { - draw_as_shadow = true, - filename = "__base__/graphics/entity/combinator/constant-combinator-shadow.png", - frame_count = 1, - height = 34, - hr_version = { - draw_as_shadow = true, - filename = "__base__/graphics/entity/combinator/hr-constant-combinator-shadow.png", - frame_count = 1, - height = 66, - priority = "high", - scale = 0.5, - shift = nil, - width = 98, - x = 196 - }, - priority = "high", - scale = 1, - shift = nil, - width = 50, - x = 100 - } - } - }, - west = { - layers = { - { tint=rtint, - filename = "__base__/graphics/entity/combinator/constant-combinator.png", - frame_count = 1, - height = 52, - hr_version = { tint=rtint, - filename = "__base__/graphics/entity/combinator/hr-constant-combinator.png", - frame_count = 1, - height = 102, - priority = "high", - scale = 0.5, - shift = nil, - width = 114, - x = 342 - }, - priority = "high", - scale = 1, - shift = nil, - width = 58, - x = 174 - }, - { - draw_as_shadow = true, - filename = "__base__/graphics/entity/combinator/constant-combinator-shadow.png", - frame_count = 1, - height = 34, - hr_version = { - draw_as_shadow = true, - filename = "__base__/graphics/entity/combinator/hr-constant-combinator-shadow.png", - frame_count = 1, - height = 66, - priority = "high", - scale = 0.5, - shift = nil, - width = 98, - x = 294 - }, - priority = "high", - scale = 1, - shift = nil, - width = 50, - x = 150 - } - } - } + width = 98, + x = 98 + }, + } + }, + north = { + layers = { + { + tint = rtint, + filename = "__base__/graphics/entity/combinator/constant-combinator.png", + frame_count = 1, + height = 102, + priority = "high", + scale = 0.5, + shift = nil, + width = 114, + x = 0 + }, + { + draw_as_shadow = true, + filename = "__base__/graphics/entity/combinator/constant-combinator-shadow.png", + frame_count = 1, + height = 66, + priority = "high", + scale = 0.5, + shift = nil, + width = 98, + x = 0 + }, + } + }, + south = { + layers = { + { + tint = rtint, + filename = "__base__/graphics/entity/combinator/constant-combinator.png", + frame_count = 1, + height = 102, + priority = "high", + scale = 0.5, + shift = nil, + width = 114, + x = 228 + }, + { + draw_as_shadow = true, + filename = "__base__/graphics/entity/combinator/constant-combinator-shadow.png", + frame_count = 1, + height = 66, + priority = "high", + scale = 0.5, + shift = nil, + width = 98, + x = 196 + }, + } + }, + west = { + layers = { + { + tint = rtint, + filename = "__base__/graphics/entity/combinator/constant-combinator.png", + frame_count = 1, + height = 102, + priority = "high", + scale = 0.5, + shift = nil, + width = 114, + x = 342 + }, + { + draw_as_shadow = true, + filename = "__base__/graphics/entity/combinator/constant-combinator-shadow.png", + frame_count = 1, + height = 66, + priority = "high", + scale = 0.5, + shift = nil, + width = 98, + x = 294 } + } + } +} ---[[ Registers ]]-- +--[[ Registers ]] -- -local name="warptorio-combinator" -local entity = table.deepcopy( data.raw["constant-combinator"]["constant-combinator"] ) +local name = "warptorio-combinator" +local entity = table.deepcopy(data.raw["constant-combinator"]["constant-combinator"]) entity.name = name -entity.enabled=false +entity.enabled = false entity.minable.result = name -entity.order="z" -entity.icons={{icon="__base__/graphics/icons/constant-combinator.png",tint=rtint}} -entity.icon=nil -entity.sprites=sprites -local item=table.deepcopy( data.raw.item["constant-combinator"] ) -item.name=name item.place_result=name -item.icons={{icon="__base__/graphics/icons/constant-combinator.png",tint=rtint}} -item.icon=nil -local recipe=table.deepcopy( data.raw.recipe["constant-combinator"] ) -recipe.enabled=false recipe.name=name recipe.result=name -recipe.ingredients={{"constant-combinator",10},{"arithmetic-combinator",10},{"decider-combinator",10},{"red-wire",50},{"green-wire",50},{"programmable-speaker",10},{"small-lamp",10},{"advanced-circuit",20},{"power-switch",1}} +entity.order = "z" +entity.icons = { { icon = "__base__/graphics/icons/constant-combinator.png", tint = rtint } } +entity.icon = nil +entity.sprites = sprites +local item = table.deepcopy(data.raw.item["constant-combinator"]) +item.name = name +item.place_result = name +item.icons = { { icon = "__base__/graphics/icons/constant-combinator.png", tint = rtint } } +item.icon = nil +local recipe = table.deepcopy(data.raw.recipe["constant-combinator"]) +recipe.enabled = false +recipe.name = name +recipe.results = { { type = "item", name = name, amount = 1 } } +recipe.ingredients = { + { type = "item", name = "constant-combinator", amount = 10 }, + { type = "item", name = "arithmetic-combinator", amount = 10 }, + { type = "item", name = "decider-combinator", amount = 10 }, + { type = "item", name = "programmable-speaker", amount = 10 }, + { type = "item", name = "small-lamp", amount = 10 }, + { type = "item", name = "advanced-circuit", amount = 10 }, + { type = "item", name = "power-switch", amount = 10 } +} -data:extend({entity,item,recipe}) +data:extend({ entity, item, recipe }) -local name="warptorio-alt-combinator" -local entity = table.deepcopy( data.raw["constant-combinator"]["constant-combinator"] ) +local name = "warptorio-alt-combinator" +local entity = table.deepcopy(data.raw["constant-combinator"]["constant-combinator"]) entity.name = name -entity.enabled=false -entity.minable=nil --.result = name -entity.order="z" -entity.icons={{icon="__base__/graphics/icons/constant-combinator.png",tint=rtint}} -entity.icon=nil -entity.sprites=sprites -local item=table.deepcopy( data.raw.item["constant-combinator"] ) -item.name=name item.place_result=name -item.icons={{icon="__base__/graphics/icons/constant-combinator.png",tint=rtint}} -item.icon=nil -local recipe=table.deepcopy( data.raw.recipe["constant-combinator"] ) -recipe.enabled=false recipe.name=name recipe.result=name -recipe.ingredients={{"steel-plate",1}} +entity.enabled = false +entity.minable = nil --.result = name +entity.order = "z" +entity.icons = { { icon = "__base__/graphics/icons/constant-combinator.png", tint = rtint } } +entity.icon = nil +entity.sprites = sprites +local item = table.deepcopy(data.raw.item["constant-combinator"]) +item.name = name +item.place_result = name +item.icons = { { icon = "__base__/graphics/icons/constant-combinator.png", tint = rtint } } +item.icon = nil +local recipe = table.deepcopy(data.raw.recipe["constant-combinator"]) +recipe.enabled = false +recipe.name = name +recipe.results = { { type = "item", name = name, amount = 1 } } +recipe.ingredients = { { type = "item", name = "steel-plate", amount = 1 } } -data:extend({entity}) --,item,recipe}) +data:extend({ entity }) --,item,recipe}) diff --git a/prototypes/data_warptorio-heatpipe.lua b/prototypes/data_warptorio-heatpipe.lua index 1f97cec..86bd41f 100644 --- a/prototypes/data_warptorio-heatpipe.lua +++ b/prototypes/data_warptorio-heatpipe.lua @@ -16,631 +16,355 @@ data:extend{ corner_left_down = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-down-left-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-down-left-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-down-left-2.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-down-left-2.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-down-left-3.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-down-left-3.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-down-left-4.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-down-left-4.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-down-left-5.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-down-left-5.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-down-left-6.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-down-left-6.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, corner_left_up = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-up-left-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-up-left-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-up-left-2.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-up-left-2.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-up-left-3.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-up-left-3.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-up-left-4.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-up-left-4.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-up-left-5.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-up-left-5.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-up-left-6.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-up-left-6.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, corner_right_down = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-down-right-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-down-right-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-down-right-2.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-down-right-2.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-down-right-3.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-down-right-3.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-down-right-4.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-down-right-4.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-down-right-5.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-down-right-5.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-down-right-6.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-down-right-6.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, corner_right_up = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-up-right-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-up-right-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-up-right-2.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-up-right-2.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-up-right-3.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-up-right-3.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-up-right-4.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-up-right-4.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-up-right-5.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-up-right-5.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-corner-up-right-6.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-corner-up-right-6.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, cross = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-t-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-t-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, ending_down = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-ending-down-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-ending-down-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, ending_left = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-ending-left-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-ending-left-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, ending_right = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-ending-right-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-ending-right-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, ending_up = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-ending-up-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-ending-up-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, single = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-straight-vertical-single.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-straight-vertical-single.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, straight_horizontal = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-straight-horizontal-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-straight-horizontal-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-straight-horizontal-2.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-straight-horizontal-2.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-straight-horizontal-3.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-straight-horizontal-3.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-straight-horizontal-4.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-straight-horizontal-4.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-straight-horizontal-5.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-straight-horizontal-5.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-straight-horizontal-6.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-straight-horizontal-6.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, straight_vertical = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-straight-vertical-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-straight-vertical-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-straight-vertical-2.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-straight-vertical-2.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-straight-vertical-3.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-straight-vertical-3.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-straight-vertical-4.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-straight-vertical-4.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-straight-vertical-5.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-straight-vertical-5.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-straight-vertical-6.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-straight-vertical-6.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, t_down = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-t-down-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-t-down-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, t_left = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-t-left-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-t-left-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, t_right = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-t-right-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-t-right-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, t_up = { { filename = "__base__/graphics/entity/heat-pipe/heat-pipe-t-up-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heat-pipe-t-up-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } } }, @@ -699,396 +423,222 @@ data:extend{ corner_left_down = { { filename = "__base__/graphics/entity/heat-pipe/heated-corner-down-left-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-down-left-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-down-left-2.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-down-left-2.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-down-left-3.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-down-left-3.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-down-left-4.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-down-left-4.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-down-left-5.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-down-left-5.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-down-left-6.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-down-left-6.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, corner_left_up = { { filename = "__base__/graphics/entity/heat-pipe/heated-corner-up-left-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-up-left-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-up-left-2.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-up-left-2.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-up-left-3.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-up-left-3.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-up-left-4.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-up-left-4.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-up-left-5.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-up-left-5.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-up-left-6.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-up-left-6.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, corner_right_down = { { filename = "__base__/graphics/entity/heat-pipe/heated-corner-down-right-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-down-right-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-down-right-2.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-down-right-2.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-down-right-3.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-down-right-3.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-down-right-4.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-down-right-4.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-down-right-5.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-down-right-5.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-down-right-6.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-down-right-6.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, corner_right_up = { { filename = "__base__/graphics/entity/heat-pipe/heated-corner-up-right-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-up-right-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-up-right-2.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-up-right-2.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-up-right-3.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-up-right-3.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-up-right-4.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-up-right-4.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-up-right-5.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-up-right-5.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-corner-up-right-6.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-corner-up-right-6.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, cross = { { filename = "__base__/graphics/entity/heat-pipe/heated-t-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-t-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, ending_down = { { filename = "__base__/graphics/entity/heat-pipe/heated-ending-down-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-ending-down-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, ending_left = { { filename = "__base__/graphics/entity/heat-pipe/heated-ending-left-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-ending-left-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, ending_right = { { filename = "__base__/graphics/entity/heat-pipe/heated-ending-right-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-ending-right-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, ending_up = { { filename = "__base__/graphics/entity/heat-pipe/heated-ending-up-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-ending-up-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, single = { @@ -1100,232 +650,136 @@ data:extend{ straight_horizontal = { { filename = "__base__/graphics/entity/heat-pipe/heated-straight-horizontal-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-straight-horizontal-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-straight-horizontal-2.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-straight-horizontal-2.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-straight-horizontal-3.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-straight-horizontal-3.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-straight-horizontal-4.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-straight-horizontal-4.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-straight-horizontal-5.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-straight-horizontal-5.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-straight-horizontal-6.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-straight-horizontal-6.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, straight_vertical = { { filename = "__base__/graphics/entity/heat-pipe/heated-straight-vertical-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-straight-vertical-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-straight-vertical-2.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-straight-vertical-2.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-straight-vertical-3.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-straight-vertical-3.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-straight-vertical-4.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-straight-vertical-4.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-straight-vertical-5.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-straight-vertical-5.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 }, { filename = "__base__/graphics/entity/heat-pipe/heated-straight-vertical-6.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-straight-vertical-6.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, t_down = { { filename = "__base__/graphics/entity/heat-pipe/heated-t-down-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-t-down-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, t_left = { { filename = "__base__/graphics/entity/heat-pipe/heated-t-left-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-t-left-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, t_right = { { filename = "__base__/graphics/entity/heat-pipe/heated-t-right-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-t-right-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } }, t_up = { { filename = "__base__/graphics/entity/heat-pipe/heated-t-up-1.png", - tint=heatpipe_tint, height= 32, - hr_version = { - filename = "__base__/graphics/entity/heat-pipe/hr-heated-t-up-1.png", - tint=heatpipe_tint, height= 64, - priority = "extra-high", - scale = 0.5, - width = 64 - }, - priority = "extra-high", - width = 32 + tint=heatpipe_tint, height= 64, + priority = "extra-high", + scale = 0.5, + width = 64 } } }, --icon = "__base__/graphics/icons/heat-pipe.png", --icon_size = 64, - icon_size=64,icons={{icon="__base__/graphics/icons/heat-pipe.png",tint={r=0.2,g=0.2,b=1,a=0.8},hr_version={tint={r=0.2,g=0.2,b=1,a=0.8}} }}, + icon_size=64,icons={{icon="__base__/graphics/icons/heat-pipe.png",tint={r=0.2,g=0.2,b=1,a=0.8}}}, max_health = 200, minable = { mining_time = 0.1, - result = "warptorio-heatpipe" + result = "warptorio-heatpipe", }, minimum_glow_temperature = 350, name = "warptorio-heatpipe", diff --git a/prototypes/data_warptorio-logistics-pipe.lua b/prototypes/data_warptorio-logistics-pipe.lua index 2ae8fd7..8e2cad8 100644 --- a/prototypes/data_warptorio-logistics-pipe.lua +++ b/prototypes/data_warptorio-logistics-pipe.lua @@ -34,15 +34,17 @@ data:extend{ "player-creation" }, fluid_box = { + volume = 100, base_area = 5, - pipe_connections = { - { - position = { - 0, - -1 - } - } - }, + pipe_connections = + { + { direction = defines.direction.north, position = {0, 0} }, + { + connection_type = "underground", + direction = defines.direction.south, + position = {0, 0} + } + }, pipe_covers = { @@ -50,31 +52,18 @@ data:extend{ layers = { { tint=rctint, filename = "__base__/graphics/entity/pipe-covers/pipe-cover-east.png", - height = 64, - hr_version = { tint=rctint, - filename = "__base__/graphics/entity/pipe-covers/hr-pipe-cover-east.png", - height = 128, - priority = "extra-high", - scale = 0.5, - width = 128 - }, + height = 128, priority = "extra-high", - width = 64 + scale = 0.5, + width = 128 }, { draw_as_shadow = true, filename = "__base__/graphics/entity/pipe-covers/pipe-cover-east-shadow.png", - height = 64, - hr_version = { - draw_as_shadow = true, - filename = "__base__/graphics/entity/pipe-covers/hr-pipe-cover-east-shadow.png", - height = 128, - priority = "extra-high", - scale = 0.5, - width = 128 - }, + height = 128, priority = "extra-high", - width = 64 + scale = 0.5, + width = 128 } } }, @@ -82,31 +71,18 @@ data:extend{ layers = { { tint=rctint, filename = "__base__/graphics/entity/pipe-covers/pipe-cover-north.png", - height = 64, - hr_version = { tint=rctint, - filename = "__base__/graphics/entity/pipe-covers/hr-pipe-cover-north.png", - height = 128, - priority = "extra-high", - scale = 0.5, - width = 128 - }, + height = 128, priority = "extra-high", - width = 64 + scale = 0.5, + width = 128 }, { draw_as_shadow = true, filename = "__base__/graphics/entity/pipe-covers/pipe-cover-north-shadow.png", - height = 64, - hr_version = { - draw_as_shadow = true, - filename = "__base__/graphics/entity/pipe-covers/hr-pipe-cover-north-shadow.png", - height = 128, - priority = "extra-high", - scale = 0.5, - width = 128 - }, + height = 128, priority = "extra-high", - width = 64 + scale = 0.5, + width = 128 } } }, @@ -114,31 +90,18 @@ data:extend{ layers = { { tint=rctint, filename = "__base__/graphics/entity/pipe-covers/pipe-cover-south.png", - height = 64, - hr_version = { tint=rctint, - filename = "__base__/graphics/entity/pipe-covers/hr-pipe-cover-south.png", - height = 128, - priority = "extra-high", - scale = 0.5, - width = 128 - }, + height = 128, priority = "extra-high", - width = 64 + scale = 0.5, + width = 128 }, { draw_as_shadow = true, filename = "__base__/graphics/entity/pipe-covers/pipe-cover-south-shadow.png", - height = 64, - hr_version = { - draw_as_shadow = true, - filename = "__base__/graphics/entity/pipe-covers/hr-pipe-cover-south-shadow.png", - height = 128, - priority = "extra-high", - scale = 0.5, - width = 128 - }, + height = 128, priority = "extra-high", - width = 64 + scale = 0.5, + width = 128 } } }, @@ -146,31 +109,18 @@ data:extend{ layers = { { tint=rctint, filename = "__base__/graphics/entity/pipe-covers/pipe-cover-west.png", - height = 64, - hr_version = { tint=rctint, - filename = "__base__/graphics/entity/pipe-covers/hr-pipe-cover-west.png", - height = 128, - priority = "extra-high", - scale = 0.5, - width = 128 - }, + height = 128, priority = "extra-high", - width = 64 + scale = 0.5, + width = 128 }, { draw_as_shadow = true, filename = "__base__/graphics/entity/pipe-covers/pipe-cover-west-shadow.png", - height = 64, - hr_version = { - draw_as_shadow = true, - filename = "__base__/graphics/entity/pipe-covers/hr-pipe-cover-west-shadow.png", - height = 128, - priority = "extra-high", - scale = 0.5, - width = 128 - }, + height = 128, priority = "extra-high", - width = 64 + scale = 0.5, + width = 128 } } } @@ -186,57 +136,33 @@ data:extend{ order = "a[pipe]-b[pipe-to-ground]", name = "warptorio-logistics-pipe", pictures = { - down = { tint=rctint, - filename = "__base__/graphics/entity/pipe-to-ground/pipe-to-ground-down.png", - height = 64, - hr_version = { tint=rtint, - filename = "__base__/graphics/entity/pipe-to-ground/hr-pipe-to-ground-down.png", + south = { tint=rtint, + filename = "__base__/graphics/entity/pipe-to-ground/pipe-to-ground-down.png", height = 128, priority = "extra-high", scale = 0.5, width = 128 - }, - priority = "high", - width = 64 }, - left = { tint=rctint, - filename = "__base__/graphics/entity/pipe-to-ground/pipe-to-ground-left.png", - height = 64, - hr_version = { tint=rtint, - filename = "__base__/graphics/entity/pipe-to-ground/hr-pipe-to-ground-left.png", + west = { tint=rtint, + filename = "__base__/graphics/entity/pipe-to-ground/pipe-to-ground-left.png", height = 128, priority = "extra-high", scale = 0.5, width = 128 - }, - priority = "high", - width = 64 }, - right = { tint=rctint, - filename = "__base__/graphics/entity/pipe-to-ground/pipe-to-ground-right.png", - height = 64, - hr_version = { tint=rtint, - filename = "__base__/graphics/entity/pipe-to-ground/hr-pipe-to-ground-right.png", + east = { tint=rtint, + filename = "__base__/graphics/entity/pipe-to-ground/pipe-to-ground-right.png", height = 128, priority = "extra-high", scale = 0.5, width = 128 - }, - priority = "high", - width = 64 }, - up = { tint=rctint, - filename = "__base__/graphics/entity/pipe-to-ground/pipe-to-ground-up.png", - height = 64, - hr_version = { tint=rtint, - filename = "__base__/graphics/entity/pipe-to-ground/hr-pipe-to-ground-up.png", + north = { tint=rtint, + filename = "__base__/graphics/entity/pipe-to-ground/pipe-to-ground-up.png", height = 128, priority = "extra-high", scale = 0.5, width = 128 - }, - priority = "high", - width = 64 } }, resistances = { diff --git a/prototypes/data_warptorio-townportal.lua b/prototypes/data_warptorio-townportal.lua index 807a2da..270f535 100644 --- a/prototypes/data_warptorio-townportal.lua +++ b/prototypes/data_warptorio-townportal.lua @@ -1,95 +1,66 @@ -local rtint={r=0.4,g=0.4,b=1,a=1} - -local rsc=1.5 - -data:extend{ - -{ - capsule_action = { - attack_parameters={type="stream",range=0,cooldown=10,ammo_category="capsule", - ammo_type={action={action_deliver={target_effects={damage={amount=-10,type="physical"},type="damage"},type="instant"},type="direct"},category="capsule",target_type="position"}, - }, - type = "use-on-self", - uses_stack=true, +local rtint = { r = 0.4, g = 0.4, b = 1, a = 1 } +local rsc = 1.5 + +data:extend { + { + capsule_action = { + attack_parameters = { type = "stream", range = 0, cooldown = 10, ammo_category = "capsule", + ammo_type = { action = { action_deliver = { target_effects = { damage = { amount = -10, type = "physical" }, type = "damage" }, type = "instant" }, type = "direct" }, category = "capsule", target_type = "position" }, + }, + type = "use-on-self", + uses_stack = true, + }, + icons = { { icon = "__warptorio2__/graphics/technology/earth.png", icon_size = 128, scale = 1 } }, + icon_size = 128, + name = "warptorio-townportal", + order = "zz", + stack_size = 5, + subgroup = "capsule", + type = "capsule" }, - icons = {{icon="__warptorio2__/graphics/technology/earth.png",scale=1}}, - icon_size = 128, - name = "warptorio-townportal", - order = "zz", - stack_size = 5, - subgroup = "capsule", - type = "capsule" -}, - - -{ - enabled = false, - ingredients = { - { - "advanced-circuit", - 10 - }, - { - "grenade", - 10 - }, - { - "radar", - 10 - }, + { + enabled = false, + ingredients = { + { type = "item", name = "advanced-circuit", amount = 10 }, + { type = "item", name = "grenade", amount = 10 }, + { type = "item", name = "radar", amount = 10 } + }, + name = "warptorio-townportal", + results = { { type = "item", name = "warptorio-townportal", amount = 1 } }, + type = "recipe" }, - name = "warptorio-townportal", - result = "warptorio-townportal", - type = "recipe" -}, - - } - - - - -data:extend{ - -{ - capsule_action = { - attack_parameters={type="stream",range=0,cooldown=10,ammo_category="capsule", - ammo_type={action={action_deliver={target_effects={damage={amount=-10,type="physical"},type="damage"},type="instant"},type="direct"},category="capsule",target_type="position"}, - }, - type = "use-on-self", - uses_stack=true, +data:extend { + { + capsule_action = { + attack_parameters = { type = "stream", range = 0, cooldown = 10, ammo_category = "capsule", + ammo_type = { action = { action_deliver = { target_effects = { damage = { amount = -10, type = "physical" }, type = "damage" }, type = "instant" }, type = "direct" }, category = "capsule", target_type = "position" }, + }, + type = "use-on-self", + uses_stack = true, + }, + icons = { { icon = "__warptorio2__/graphics/technology/earth.png", icon_size = 128, scale = 1, tint = rtint } }, + icon_size = 128, + name = "warptorio-homeportal", + order = "zz", + stack_size = 5, + subgroup = "capsule", + type = "capsule" }, - icons = {{icon="__warptorio2__/graphics/technology/earth.png",scale=1,tint=rtint}}, - icon_size = 128, - name = "warptorio-homeportal", - order = "zz", - stack_size = 5, - subgroup = "capsule", - type = "capsule" -}, -{ - enabled = false, - ingredients = { - { - "advanced-circuit", - 10 - }, - { - "grenade", - 10 - }, - { - "radar", - 10 - }, + { + enabled = false, + ingredients = { + { type = "item", name = "advanced-circuit", amount = 10 }, + { type = "item", name = "grenade", amount = 10 }, + { type = "item", name = "radar", amount = 10 } + }, + name = "warptorio-homeportal", + results = { { type = "item", name = "warptorio-homeportal", amount = 1 } }, + type = "recipe" }, - name = "warptorio-homeportal", - result = "warptorio-homeportal", - type = "recipe" -}, -} \ No newline at end of file +} diff --git a/prototypes/data_warptorio-warploader.lua b/prototypes/data_warptorio-warploader.lua index 1333cf9..23c7d68 100644 --- a/prototypes/data_warptorio-warploader.lua +++ b/prototypes/data_warptorio-warploader.lua @@ -9,8 +9,14 @@ data:extend{ }, { name="warptorio-warploader", type="recipe",category="crafting-with-fluid",enabled=false,energy_required=2, - ingredients={ {"iron-gear-wheel",400},{"express-underground-belt",50},{"express-transport-belt",100},{"express-splitter",50},{amount=200,name="lubricant",type="fluid"} }, - result="warptorio-warploader",result_count=1, + ingredients={ + {type="item", name="iron-gear-wheel", amount=400}, + {type="item", name="express-underground-belt", amount=50}, + {type="item", name="express-transport-belt", amount=100}, + {type="item", name="express-splitter", amount=50}, + {amount=200,name="lubricant",type="fluid"} + }, + results={{type="item", name="warptorio-warploader", amount=1}} }, @@ -23,18 +29,10 @@ data:extend{ direction_count = 20, filename = "__base__/graphics/entity/express-transport-belt/express-transport-belt.png", frame_count = 32, - height = 64, - hr_version = { tint=rtint, - direction_count = 20, - filename = "__base__/graphics/entity/express-transport-belt/hr-express-transport-belt.png", - frame_count = 32, - height = 128, - priority = "extra-high", - scale = 0.5, - width = 128 - }, + height = 128, priority = "extra-high", - width = 64 + scale = 0.5, + width = 128 }, east_index = 1, east_to_north_index = 5, @@ -72,8 +70,8 @@ data:extend{ filter_count = 5, flags = { "placeable-neutral", - "player-creation", - "fast-replaceable-no-build-while-moving" + "player-creation"--, +-- "fast-replaceable-no-build-while-moving" }, icons = {{icon="__base__/graphics/icons/express-loader.png",tint=rtint}}, icon_size = 32, diff --git a/prototypes/data_warptorio-warpport.lua b/prototypes/data_warptorio-warpport.lua index 9891903..9b8c71c 100644 --- a/prototypes/data_warptorio-warpport.lua +++ b/prototypes/data_warptorio-warpport.lua @@ -17,25 +17,16 @@ data:extend{ enabled = false, energy_required = 5, ingredients = { - { - "steel-plate", - 45 - }, - { - "iron-gear-wheel", - 45 - }, - { - "advanced-circuit", - 100 - }, - {"processing-unit",100}, - {"flying-robot-frame",100}, - {"roboport",10}, - {"warptorio-warponium-fuel",1} + {type="item", name="steel-plate", amount=45}, + {type="item", name="iron-gear-wheel", amount=45}, + {type="item", name="advanced-circuit", amount=100}, + {type="item", name="processing-unit", amount=100}, + {type="item", name="flying-robot-frame", amount=100}, + {type="item", name="roboport", amount=10}, + {type="item", name="warptorio-warponium-fuel", amount=1} }, name = "warptorio-warpport", - result = "warptorio-warpport", + results = {{type="item", name="warptorio-warpport", amount=1}}, type = "recipe" }, @@ -43,142 +34,78 @@ data:extend{ { base = { layers = { - { tint=rtint, scale = 1/2, + { tint=rtint, filename = "__base__/graphics/entity/roboport/roboport-base.png", - height = 135, - hr_version = { tint=rtint, - filename = "__base__/graphics/entity/roboport/hr-roboport-base.png", - height = 277, - scale = 0.5/2, - shift = { - 0.0625/2, - 0.2421875/2 - }, - width = 228 - }, + height = 277, + scale = 0.5/2, shift = { - 0.5/2, - 0.25/2 + 0.0625/2, + 0.2421875/2 }, - width = 143 + width = 228 }, { - draw_as_shadow = true, scale = 1/2, + draw_as_shadow = true, filename = "__base__/graphics/entity/roboport/roboport-shadow.png", - height = 101, - hr_version = { - draw_as_shadow = true, - filename = "__base__/graphics/entity/roboport/hr-roboport-shadow.png", - height = 201, - scale = 0.5/2, - shift = { - 0.890625/2, - 0.6015625/2 - }, - width = 294 - }, + height = 201, + scale = 0.5/2, shift = { 0.890625/2, 0.6015625/2 }, - width = 147 + width = 294 } } }, base_animation = { tint=rtint, - animation_speed = 0.5, scale = 1/2, + animation_speed = 0.5, filename = "__base__/graphics/entity/roboport/roboport-base-animation.png", frame_count = 8, - height = 31, - hr_version = { tint=rtint, - animation_speed = 0.5, - filename = "__base__/graphics/entity/roboport/hr-roboport-base-animation.png", - frame_count = 8, - height = 59, - priority = "medium", - scale = 0.5/2, - shift = { - -0.5546875/2, - -1.9140625/2 - }, - width = 83 - }, + height = 59, priority = "medium", + scale = 0.5/2, shift = { - -0.53149999999999995/2, - -1.9375/2 + -0.5546875/2, + -1.9140625/2 }, - width = 42 + width = 83 }, - base_patch = { tint=rtint, scale = 1/2, + base_patch = { tint=rtint, filename = "__base__/graphics/entity/roboport/roboport-base-patch.png", frame_count = 1, - height = 50, - hr_version = { tint=rtint, - filename = "__base__/graphics/entity/roboport/hr-roboport-base-patch.png", - frame_count = 1, - height = 100, - priority = "medium", - scale = 0.5/2, - shift = { - 0.046875/2, - 0.15625/2 - }, - width = 138 - }, + height = 100, priority = "medium", + scale = 0.5/2, shift = { - 0.03125/2, - 0.203125/2 + 0.046875/2, + 0.15625/2 }, - width = 69 + width = 138 }, door_animation_down = { tint=rtint, filename = "__base__/graphics/entity/roboport/roboport-door-down.png", frame_count = 16, - height = 22, - hr_version = { tint=rtint, - filename = "__base__/graphics/entity/roboport/hr-roboport-door-down.png", - frame_count = 16, - height = 41, - priority = "medium", - scale = 0.5/2, - shift = { - -0.0078125/2, - -0.3046875/2 - }, - width = 97/2 - }, + height = 41, priority = "medium", + scale = 0.5/2, shift = { - 0.015625, - -0.234375 + -0.0078125/2, + -0.3046875/2 }, - width = 52 + width = 97/2 }, door_animation_up = { tint=rtint, filename = "__base__/graphics/entity/roboport/roboport-door-up.png", frame_count = 16, - height = 20, - hr_version = { tint=rtint, - filename = "__base__/graphics/entity/roboport/hr-roboport-door-up.png", - frame_count = 16, - height = 38, - priority = "medium", - scale = 0.5/2, - shift = { - -0.0078125/2, - -0.921875/2 - }, - width = 97 - }, + height = 38, priority = "medium", + scale = 0.5/2, shift = { - 0.015625/2, - -0.890625/2 + -0.0078125/2, + -0.921875/2 }, - width = 52 + width = 97 }, charging_offsets = { diff --git a/prototypes/data_warptorio-warpspider.lua b/prototypes/data_warptorio-warpspider.lua index 9ea7e5b..af2ea2d 100644 --- a/prototypes/data_warptorio-warpspider.lua +++ b/prototypes/data_warptorio-warpspider.lua @@ -1,48 +1,54 @@ -local spider={} -spider.tint={r=0.4,g=0.4,b=1,a=0.7} -spider.name="warptorio-warpspider" -spider.size=0.5 - -spider.item=table.deepcopy(data.raw["item-with-entity-data"].spidertron) -spider.item.name=spider.name -spider.item.icons={{icon=spider.item.icon,icon_size=spider.item.icon_size,tint=spider.tint}} -spider.item.place_result=spider.name -spider.item.icon=nil - -spider.recipe=table.deepcopy(data.raw.recipe.spidertron) -spider.recipe.name=spider.name -spider.recipe.result=spider.name -spider.recipe.icons=spider.item.icons -spider.recipe["recipe-category"]="crafting" -- Hand-craft only does not exist - -spider.recipe.ingredients={{"spidertron",8},{"power-armor-mk2",8},{"fusion-reactor-equipment",8},{"raw-fish",9},{"satellite",8},{"artillery-turret",8},{"rocket-silo",1}} - - -spider.tech=table.deepcopy(data.raw["technology"].spidertron) -spider.tech.name=spider.name -spider.tech.effects={{type="unlock-recipe",recipe="warptorio-warpspider"}} -spider.tech.prerequisites={"spidertron","space-science-pack","warptorio-reactor-8","artillery"} -spider.tech.icons={{icon=spider.tech.icon,icon_size=spider.tech.icon_size,tint=spider.tint}} -spider.tech.icon=nil -spider.tech.localised_description={"technology-description.warptorio-warpspider"} - -spider.vehicle_grid=table.deepcopy(data.raw["equipment-grid"]["spidertron-equipment-grid"]) -spider.vehicle_grid.name="warptorio-warpspider-equipment-grid" -spider.vehicle_grid.height=10 --6 -spider.vehicle_grid.width=12 --10 - -spider.vehicle=table.deepcopy(data.raw["spider-vehicle"].spidertron) -spider.vehicle.name=spider.name -spider.vehicle.equipment_grid="warptorio-warpspider-equipment-grid" -spider.vehicle.icons={{icon=spider.vehicle.icon,icon_size=spider.vehicle.icon_size,tint=spider.tint}} -spider.vehicle.icon=nil - -spider.vehicle.max_health=9001 --3000 -spider.vehicle.height=spider.vehicle.height*spider.size --12 -spider.vehicle.minable.result=spider.name -spider.vehicle.inventory_size=200 -spider.vehicle.torso_rotation_speed = 0.01 --0.005 -spider.vehicle.movement_energy_consumption="250kW" +local spider = {} +spider.tint = { r = 0.4, g = 0.4, b = 1, a = 0.7 } +spider.name = "warptorio-warpspider" +spider.size = 0.65 + +spider.item = table.deepcopy(data.raw["item-with-entity-data"].spidertron) +spider.item.name = spider.name +spider.item.icons = { { icon = spider.item.icon, icon_size = spider.item.icon_size, tint = spider.tint } } +spider.item.place_result = spider.name +spider.item.icon = nil + +spider.recipe = table.deepcopy(data.raw.recipe.spidertron) +spider.recipe.name = spider.name +spider.recipe.results = { { type = "item", name = spider.name, amount = 1 } } +spider.recipe.icons = spider.item.icons + +spider.recipe.ingredients = { + { type = "item", name = "spidertron", amount = 1 }, + { type = "item", name = "power-armor-mk2", amount = 1 }, + { type = "item", name = "fission-reactor-equipment", amount = 8 }, + { type = "item", name = "raw-fish", amount = 8 }, + { type = "item", name = "satellite", amount = 1 }, + { type = "item", name = "artillery-turret", amount = 8 }, + { type = "item", name = "rocket-silo", amount = 1 } +} + +spider.tech = table.deepcopy(data.raw["technology"].spidertron) +spider.tech.name = spider.name +spider.tech.effects = { { type = "unlock-recipe", recipe = "warptorio-warpspider" } } +spider.tech.prerequisites = { "spidertron", "space-science-pack", "warptorio-reactor-8", "artillery" } +spider.tech.icons = { { icon = spider.tech.icon, icon_size = spider.tech.icon_size, tint = spider.tint } } +spider.tech.icon = nil +spider.tech.localised_description = { "technology-description.warptorio-warpspider" } + +spider.vehicle_grid = table.deepcopy(data.raw["equipment-grid"]["spidertron-equipment-grid"]) +spider.vehicle_grid.name = "warptorio-warpspider-equipment-grid" +spider.vehicle_grid.height = 10 --6 +spider.vehicle_grid.width = 12 --10 + +spider.vehicle = table.deepcopy(data.raw["spider-vehicle"].spidertron) +spider.vehicle.name = spider.name +spider.vehicle.equipment_grid = "warptorio-warpspider-equipment-grid" +spider.vehicle.icons = { { icon = spider.vehicle.icon, icon_size = spider.vehicle.icon_size, tint = spider.tint } } +spider.vehicle.icon = nil + +spider.vehicle.max_health = 9000 --3000 +spider.vehicle.height = spider.vehicle.height * spider.size --12 +spider.vehicle.minable.result = spider.name +spider.vehicle.inventory_size = 200 +spider.vehicle.torso_rotation_speed = 0.01 --0.005 +spider.vehicle.movement_energy_consumption = "250kW" spider.vehicle.chain_shooting_cooldown_modifier = 0.35 --0.5 --[[spider.vehicle.guns = { @@ -53,31 +59,35 @@ spider.vehicle.chain_shooting_cooldown_modifier = 0.35 --0.5 }, ]] -spider.legs={} -for i=1,8,1 do - local leg=table.deepcopy(data.raw["spider-leg"]["spidertron-leg-"..i]) - proto.TintImages(leg,spider.tint) - proto.SizeTo(leg,spider.size) - leg.name="warptorio-"..leg.name - leg.part_length=leg.part_length*spider.size - leg.movement_acceleration = leg.movement_acceleration/(spider.size/1.5) --0.3 --0.03 - leg.movement_based_position_selection_distance= leg.movement_based_position_selection_distance*spider.size*1.5 -- 12 --4 - leg.initial_movement_speed = leg.initial_movement_speed/(spider.size/1.5) --0.6 --0.06 - spider.legs[i]=leg +spider.legs = {} +for i = 1, 8, 1 do + local leg = table.deepcopy(data.raw["spider-leg"]["spidertron-leg-" .. i]) + proto.TintImages(leg, spider.tint) + proto.SizeTo(leg, spider.size) + --leg.type = "spider-leg" + leg.name = "warptorio-" .. leg.name + leg.knee_height = leg.knee_height * spider.size + leg.movement_acceleration = leg.movement_acceleration / (spider.size / 1.5) + leg.movement_based_position_selection_distance = leg.movement_based_position_selection_distance * spider.size * 1.5 + leg.initial_movement_speed = leg.initial_movement_speed / (spider.size / 1.5) + --if leg.collision_mask == nil then + --leg.collision_mask = { layers = { item = true, meltable = true, object = true, player = true, water_tile = true, is_object = true, is_lower_object = true } } end + --if leg.collision_mask.layers == nil then leg.collision_mask.layers = { object = true } end + spider.legs[i] = leg end -spider.vehicle.guns={} -spider.guns={} -for i=1,4,1 do - for x=1,2,1 do - local w=table.deepcopy(data.raw.gun["spidertron-rocket-launcher-"..i]) - w.name="warptorio-spidertron-rocket-launcher-"..(i*2)-2+x - w.attack_parameters.cooldown=45 --60 - w.attack_parameters.range=45 --60 - w.localised_name={"item-name."..w.name} - table.insert(spider.guns,w) - table.insert(spider.vehicle.guns,w.name) - data:extend{w} +spider.vehicle.guns = {} +spider.guns = {} +for i = 1, 4, 1 do + for x = 1, 2, 1 do + local w = table.deepcopy(data.raw.gun["spidertron-rocket-launcher-" .. i]) + w.name = "warptorio-spidertron-rocket-launcher-" .. (i * 2) - 2 + x + w.attack_parameters.cooldown = 45 --60 + w.attack_parameters.range = 45 --60 + w.localised_name = { "item-name." .. w.name } + table.insert(spider.guns, w) + table.insert(spider.vehicle.guns, w.name) + data:extend { w } end end @@ -114,15 +124,15 @@ for i=1,2,1 do local w=table.deepcopy(spider.smg) w.name=w.name.."-"..i data:ext ]] -for k,v in pairs(spider.vehicle.spider_engine.legs)do - v.leg="warptorio-"..v.leg +for k, v in pairs(spider.vehicle.spider_engine.legs) do + v.leg = "warptorio-" .. v.leg end -proto.SizeTo(spider.vehicle,spider.size) -proto.TintImages(spider.vehicle,spider.tint) -spider.vehicle.selection_box={{-1,-1},{1,1}} +proto.SizeTo(spider.vehicle, spider.size) +proto.TintImages(spider.vehicle, spider.tint) +spider.vehicle.selection_box = { { -spider.size, -spider.size }, { spider.size, spider.size } } data:extend(spider.guns) data:extend(spider.legs) -data:extend{spider.recipe,spider.item,spider.tech,spider.vehicle_grid,spider.vehicle} +data:extend { spider.recipe, spider.item, spider.tech, spider.vehicle_grid, spider.vehicle } ---error(serpent.block(spider.vehicle)) \ No newline at end of file +--error(serpent.block(spider.vehicle)) diff --git a/prototypes/data_warptorio-warpstation.lua b/prototypes/data_warptorio-warpstation.lua index 918e061..f392ebe 100644 --- a/prototypes/data_warptorio-warpstation.lua +++ b/prototypes/data_warptorio-warpstation.lua @@ -178,53 +178,30 @@ data:extend{ name = "warptorio-warpstation", pictures = { layers = { - { tint=rtint, scale=rsc, + { tint=rtint, direction_count = 4, filename = "__base__/graphics/entity/substation/substation.png", - height = 136, - hr_version = { tint=rtint, - direction_count = 4, - filename = "__base__/graphics/entity/substation/hr-substation.png", - height = 270, - priority = "high", - scale = 0.5*rsc, - shift = { - 0, - -0.96875*rsc - }, - width = 138 - }, + height = 270, priority = "high", + scale = 0.5*rsc, shift = { 0, -0.96875*rsc }, - width = 70 + width = 138 }, - { tint=rtint, scale=rsc, + { tint=rtint, direction_count = 4, draw_as_shadow = true, filename = "__base__/graphics/entity/substation/substation-shadow.png", - height = 52, - hr_version = { tint=rtint, - direction_count = 4, - draw_as_shadow = true, - filename = "__base__/graphics/entity/substation/hr-substation-shadow.png", - height = 104, - priority = "high", - scale = 0.5*rsc, - shift = { - 1.9375*rsc, - 0.3125*rsc - }, - width = 370 - }, + height = 104, priority = "high", + scale = 0.5*rsc, shift = { 1.9375*rsc, 0.3125*rsc }, - width = 186 + width = 370 } } }, diff --git a/settings.lua b/settings.lua index 2397f68..ee2e850 100644 --- a/settings.lua +++ b/settings.lua @@ -1,193 +1,427 @@ -data:extend( -{ - - {type="double-setting",name="warptorio_votewarp_multi",order="11b", - setting_type="runtime-global",default_value=0.51, - minimum_value=0,maximum_value=1}, - - {type="bool-setting",name="warptorio_no_blueprint",order="1a", - setting_type="runtime-global",default_value=false,}, - - - - {type="bool-setting",name="warptorio_combinator_offset",order="1e", - setting_type="runtime-global",default_value=false,}, - - {type="bool-setting",name="warptorio_hide_sprites",order="1h", - setting_type="runtime-global",default_value=false,}, - - {type="string-setting",name="warptorio_loader_top",order="aaaa", - setting_type="runtime-global",default_value="up", - allowed_values={"up","down"}}, - - {type="string-setting",name="warptorio_loader_bottom",order="aaab", - setting_type="runtime-global",default_value="down", - allowed_values={"up","down"}}, - - {type="string-setting", name="warptorio_loaderchest_provider",order="aaac", - setting_type="runtime-global", default_value="logistic-chest-passive-provider", - allowed_values={"logistic-chest-active-provider","logistic-chest-buffer","logistic-chest-passive-provider","logistic-chest-storage","steel-chest"}, - }, - - {type="string-setting",name="warptorio_loaderchest_requester",order="aaad", - setting_type="runtime-global",default_value="logistic-chest-requester", - allowed_values={"logistic-chest-requester","logistic-chest-buffer","steel-chest"}, - }, - - {type="bool-setting",name="warptorio_carebear",order="aab2a", - setting_type="runtime-global",default_value=false}, - - {type="int-setting",name="warptorio_warpchance",order="aab3a", - setting_type="runtime-global",default_value=30, - minimum_value=1,maximum_value=100}, - - {type="double-setting",name="warptorio_solar_multiplier",order="aab4a", - setting_type="runtime-global",default_value=0.5, - minimum_value=0,maximum_value=10}, - - {type="bool-setting",name="warptorio_no_lootchest",order="aab4c", - setting_type="runtime-global",default_value=false,}, - - {type="int-setting",name="warptorio_lootchest_chance",order="aab4e", - setting_type="runtime-global",default_value=150,}, - - {type="int-setting",name="warptorio_lootchest_distance",order="aab4g", - setting_type="runtime-global",default_value=196,}, - - - {type="bool-setting",name="warptorio_autowarp_always",order="aaba", - setting_type="runtime-global",default_value=false,}, - - {type="bool-setting",name="warptorio_autowarp_disable",order="aabb", - setting_type="runtime-global",default_value=false,}, - - {type="double-setting",name="warptorio_autowarp_time",order="aabc", - setting_type="runtime-global",default_value=20, - minimum_value=10}, - - - - {type="bool-setting",name="warptorio_water",order="aad", - setting_type="runtime-global",default_value=false}, - - {type="bool-setting",name="warptorio_robot_warping",order="aae", - setting_type="runtime-global",default_value=false}, - - {type="bool-setting",name="warptorio_biter_warping",order="aaf", - setting_type="runtime-global",default_value=false}, - - {type = "bool-setting", name = "warptorio_pollution_disable",order="abaa", - setting_type = "runtime-global",default_value =false}, - - {type = "int-setting", name = "warptorio_pollution_tickrate",order="abab", - setting_type = "runtime-global",default_value = 3, - minimum_value=1,maximum_value=30}, - - {type = "double-setting", name = "warptorio_pollution_exponent",order="abba", - setting_type = "runtime-global",default_value = 0.225, - minimum_value = 0.01,maximum_value = 0.4}, - - - {type = "double-setting", name = "warptorio_pollution_multiplier",order="abbb", - setting_type = "runtime-global",default_value = 0.75, - minimum_value = 0.1,maximum_value = 4}, - - - {type = "bool-setting", name = "warptorio_biter_disable",order="abc", - setting_type = "runtime-global",default_value =false}, - - {type = "double-setting", name = "warptorio_biter_expansion",order="adab", - setting_type = "runtime-global",default_value = 1.009, - minimum_value = 1.0001,maximum_value = 2}, - - {type = "double-setting", name = "warptorio_biter_redux",order="adb", - setting_type = "runtime-global",default_value = 1, - minimum_value = 0}, - - {type = "double-setting", name = "warptorio_biter_min",order="adc", - setting_type = "runtime-global",default_value = 5, - minimum_value = 3}, - - {type = "double-setting", name = "warptorio_biter_max",order="add", - setting_type = "runtime-global",default_value = 15, - minimum_value = 3}, - - - {type = "bool-setting", name = "warptorio_biter_wave_disable",order="aea1a", - setting_type = "runtime-global",default_value =false}, - - {type = "double-setting", name = "warptorio_biter_wavestart",order="aea1b", - setting_type = "runtime-global",default_value = 5, - minimum_value = 1,maximum_value=10}, - - {type = "double-setting", name = "warptorio_biter_wavemin",order="aea2", - setting_type = "runtime-global",default_value = 700, - minimum_value = 10}, - - {type = "double-setting", name = "warptorio_biter_wavemax",order="aeb", - setting_type = "runtime-global",default_value = 7000, - minimum_value = 10,}, - - {type = "int-setting", name = "warptorio_biter_waverng",order="aec", - setting_type = "runtime-global",default_value = 10, - minimum_value = 1}, - - {type = "int-setting", name = "warptorio_biter_wavesize",order="aed", - setting_type = "runtime-global",default_value = 1, - minimum_value = 1}, - - {type = "int-setting", name = "warptorio_biter_wavesizemax",order="aee", - setting_type = "runtime-global",default_value = 500, - minimum_value = 0}, - - - - {type="int-setting",name="warptorio_warpcharge_max",order="ca", - setting_type="runtime-global",default_value=15, - minimum_value=5,maximum_value=1000}, - - {type="int-setting",name="warptorio_warpcharge_zone",order="cb", - setting_type="runtime-global",default_value=70, - minimum_value=5,maximum_value=1000}, - - {type="int-setting",name="warptorio_warpcharge_zonegain",order="cc", - setting_type="runtime-global",default_value=8, - minimum_value=5,maximum_value=1000}, - - - {type="int-setting",name="warptorio_warp_charge_factor",order="cd", - setting_type="runtime-global",default_value=70, - minimum_value=1}, - - {type="double-setting",name="warptorio_warpcharge_multi",order="ce", - setting_type="runtime-global",default_value=0.5}, - - - {type="double-setting",name="warptorio_ability_cooldown",order="daa", - setting_type="runtime-global",default_value=5, - minimum_value=1,maximum_value=30}, - - {type="double-setting",name="warptorio_ability_drain",order="dab", - setting_type="runtime-global",default_value=0.00001, - minimum_value=0.000000001,maximum_value=0.01}, - - {type="double-setting",name="warptorio_ability_timegain",order="db", - setting_type="runtime-global",default_value=2.5, - minimum_value=1,maximum_value=30}, - - {type="double-setting",name="warptorio_ability_warp",order="dc", - setting_type="runtime-global",default_value=2, - minimum_value=1,maximum_value=30}, - - - - --[[ used in nauvis preset -- unused -- {type="int-setting",name="warptorio_nauvis_override",order="e1aa", - setting_type="startup",default_value=12, - minimum_value=1},]] - - - --[[ {type="int-setting",name="warptorio_planet_void",order="em", - setting_type="startup",default_value=1, - minimum_value=0}, ]] - -}) \ No newline at end of file +data:extend( + { + { + type = "double-setting", + name = "warptorio_votewarp_multi", + order = "11b", + setting_type = "runtime-global", + default_value = 0.51, + minimum_value = 0, + maximum_value = 1 + }, + + { + type = "bool-setting", + name = "warptorio_no_blueprint", + order = "1a", + setting_type = "runtime-global", + default_value = false, + }, + + { + type = "bool-setting", + name = "warptorio_combinator_offset", + order = "1e", + setting_type = "runtime-global", + default_value = false, + }, + + { + type = "bool-setting", + name = "warptorio_hide_sprites", + order = "1h", + setting_type = "runtime-global", + default_value = false, + }, + + { + type = "string-setting", + name = "warptorio_loader_top", + order = "aaaa", + setting_type = "runtime-global", + default_value = "up", + allowed_values = { "up", "down" } + }, + + { + type = "string-setting", + name = "warptorio_loader_bottom", + order = "aaab", + setting_type = "runtime-global", + default_value = "down", + allowed_values = { "up", "down" } + }, + + { + type = "string-setting", + name = "warptorio_loaderchest_provider", + order = "aaac", + setting_type = "runtime-global", + default_value = "passive-provider-chest", + allowed_values = { "active-provider-chest", "buffer-chest", "passive-provider-chest", "storage-chest", "steel-chest" }, + }, + + { + type = "string-setting", + name = "warptorio_loaderchest_requester", + order = "aaad", + setting_type = "runtime-global", + default_value = "requester-chest", + allowed_values = { "requester-chest", "buffer-chest", "steel-chest" }, + }, + + { + type = "bool-setting", + name = "warptorio_carebear", + order = "aab2a", + setting_type = "runtime-global", + default_value = false + }, + + { + type = "int-setting", + name = "warptorio_warpchance", + order = "aab3a", + setting_type = "runtime-global", + default_value = 30, + minimum_value = 1, + maximum_value = 100 + }, + + { + type = "double-setting", + name = "warptorio_solar_multiplier", + order = "aab4a", + setting_type = "runtime-global", + default_value = 0.5, + minimum_value = 0, + maximum_value = 10 + }, + + { + type = "bool-setting", + name = "warptorio_no_lootchest", + order = "aab4c", + setting_type = "runtime-global", + default_value = false, + }, + + { + type = "int-setting", + name = "warptorio_lootchest_chance", + order = "aab4e", + setting_type = "runtime-global", + default_value = 150, + }, + + { + type = "int-setting", + name = "warptorio_lootchest_distance", + order = "aab4g", + setting_type = "runtime-global", + default_value = 196, + }, + + { + type = "bool-setting", + name = "warptorio_autowarp_always", + order = "aaba", + setting_type = "runtime-global", + default_value = false, + }, + + { + type = "bool-setting", + name = "warptorio_autowarp_disable", + order = "aabb", + setting_type = "runtime-global", + default_value = false, + }, + + { + type = "double-setting", + name = "warptorio_autowarp_time", + order = "aabc", + setting_type = "runtime-global", + default_value = 20, + minimum_value = 10 + }, + + + + { + type = "bool-setting", + name = "warptorio_water", + order = "aad", + setting_type = "runtime-global", + default_value = false + }, + + { + type = "bool-setting", + name = "warptorio_robot_warping", + order = "aae", + setting_type = "runtime-global", + default_value = false + }, + + { + type = "bool-setting", + name = "warptorio_biter_warping", + order = "aaf", + setting_type = "runtime-global", + default_value = false + }, + + { + type = "bool-setting", + name = "warptorio_pollution_disable", + order = "abaa", + setting_type = "runtime-global", + default_value = false + }, + + { + type = "int-setting", + name = "warptorio_pollution_tickrate", + order = "abab", + setting_type = "runtime-global", + default_value = 3, + minimum_value = 1, + maximum_value = 30 + }, + + { + type = "double-setting", + name = "warptorio_pollution_exponent", + order = "abba", + setting_type = "runtime-global", + default_value = 0.225, + minimum_value = 0.01, + maximum_value = 0.4 + }, + + + { + type = "double-setting", + name = "warptorio_pollution_multiplier", + order = "abbb", + setting_type = "runtime-global", + default_value = 0.75, + minimum_value = 0.1, + maximum_value = 4 + }, + + + { + type = "bool-setting", + name = "warptorio_biter_disable", + order = "abc", + setting_type = "runtime-global", + default_value = false + }, + + { + type = "double-setting", + name = "warptorio_biter_expansion", + order = "adab", + setting_type = "runtime-global", + default_value = 1.009, + minimum_value = 1.0001, + maximum_value = 2 + }, + + { + type = "double-setting", + name = "warptorio_biter_redux", + order = "adb", + setting_type = "runtime-global", + default_value = 1, + minimum_value = 0 + }, + + { + type = "double-setting", + name = "warptorio_biter_min", + order = "adc", + setting_type = "runtime-global", + default_value = 5, + minimum_value = 3 + }, + + { + type = "double-setting", + name = "warptorio_biter_max", + order = "add", + setting_type = "runtime-global", + default_value = 15, + minimum_value = 3 + }, + + + { + type = "bool-setting", + name = "warptorio_biter_wave_disable", + order = "aea1a", + setting_type = "runtime-global", + default_value = false + }, + + { + type = "double-setting", + name = "warptorio_biter_wavestart", + order = "aea1b", + setting_type = "runtime-global", + default_value = 5, + minimum_value = 1, + maximum_value = 10 + }, + + { + type = "double-setting", + name = "warptorio_biter_wavemin", + order = "aea2", + setting_type = "runtime-global", + default_value = 700, + minimum_value = 10 + }, + + { + type = "double-setting", + name = "warptorio_biter_wavemax", + order = "aeb", + setting_type = "runtime-global", + default_value = 7000, + minimum_value = 10, + }, + + { + type = "int-setting", + name = "warptorio_biter_waverng", + order = "aec", + setting_type = "runtime-global", + default_value = 10, + minimum_value = 1 + }, + + { + type = "int-setting", + name = "warptorio_biter_wavesize", + order = "aed", + setting_type = "runtime-global", + default_value = 1, + minimum_value = 1 + }, + + { + type = "int-setting", + name = "warptorio_biter_wavesizemax", + order = "aee", + setting_type = "runtime-global", + default_value = 500, + minimum_value = 0 + }, + + + + { + type = "int-setting", + name = "warptorio_warpcharge_max", + order = "ca", + setting_type = "runtime-global", + default_value = 15, + minimum_value = 5, + maximum_value = 1000 + }, + + { + type = "int-setting", + name = "warptorio_warpcharge_zone", + order = "cb", + setting_type = "runtime-global", + default_value = 70, + minimum_value = 5, + maximum_value = 1000 + }, + + { + type = "int-setting", + name = "warptorio_warpcharge_zonegain", + order = "cc", + setting_type = "runtime-global", + default_value = 8, + minimum_value = 5, + maximum_value = 1000 + }, + + + { + type = "int-setting", + name = "warptorio_warp_charge_factor", + order = "cd", + setting_type = "runtime-global", + default_value = 70, + minimum_value = 1 + }, + + { + type = "double-setting", + name = "warptorio_warpcharge_multi", + order = "ce", + setting_type = "runtime-global", + default_value = 0.5 + }, + + + { + type = "double-setting", + name = "warptorio_ability_cooldown", + order = "daa", + setting_type = "runtime-global", + default_value = 5, + minimum_value = 1, + maximum_value = 30 + }, + + { + type = "double-setting", + name = "warptorio_ability_drain", + order = "dab", + setting_type = "runtime-global", + default_value = 0.00001, + minimum_value = 0.000000001, + maximum_value = 0.01 + }, + + { + type = "double-setting", + name = "warptorio_ability_timegain", + order = "db", + setting_type = "runtime-global", + default_value = 2.5, + minimum_value = 1, + maximum_value = 30 + }, + + { + type = "double-setting", + name = "warptorio_ability_warp", + order = "dc", + setting_type = "runtime-global", + default_value = 2, + minimum_value = 1, + maximum_value = 30 + }, + + + + --[[ used in nauvis preset -- unused -- {type="int-setting",name="warptorio_nauvis_override",order="e1aa", + setting_type="startup",default_value=12, + minimum_value=1},]] + + + --[[ {type="int-setting",name="warptorio_planet_void",order="em", + setting_type="startup",default_value=1, + minimum_value=0}, ]] + + }) diff --git a/sound/sound.lua b/sound/sound.lua index 85e7a2d..aac482a 100644 --- a/sound/sound.lua +++ b/sound/sound.lua @@ -1,35 +1,34 @@ - ---sounds -data:extend( -{ - { - type = "sound", - name = "warp_alarm", - filename = "__base__/sound/programmable-speaker/alarm-2.ogg" - }, - { - type = "sound", - name = "warp_in", - filename = "__base__/sound/fight/old/huge-explosion.ogg" - }, - { - type = "sound", - name = "warp_out", - filename = "__base__/sound/fight/electric-beam.ogg" - }, - { - type = "sound", - name = "reactor-stabilized", - filename = "__warptorio2__/sound/reactor_stabilized.ogg" - }, - { - type = "sound", - name = "teleport", - filename = "__warptorio2__/sound/teleport.ogg" - }, - { - type = "sound", - name = "stairs", - filename = "__base__/sound/inserter-long-handed.ogg" - }, +--sounds +data:extend( +{ + { + type = "sound", + name = "warp_alarm", + filename = "__base__/sound/programmable-speaker/alarm-2.ogg" + }, + { + type = "sound", + name = "warp_in", + filename = "__base__/sound/fight/old/huge-explosion.ogg" + }, + { + type = "sound", + name = "warp_out", + filename = "__base__/sound/fight/electric-beam.ogg" + }, + { + type = "sound", + name = "reactor-stabilized", + filename = "__warptorio2__/sound/reactor_stabilized.ogg" + }, + { + type = "sound", + name = "teleport", + filename = "__warptorio2__/sound/teleport.ogg" + }, + { + type = "sound", + name = "stairs", + filename = "__base__/sound/inserter-long-handed.ogg" + }, }) \ No newline at end of file