-- IndustrialTest -- Copyright (C) 2023 mrkubax10 -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . local S=minetest.get_translator("industrialtest") industrialtest.Reactor=table.copy(industrialtest.ActivatedElectricMachine) industrialtest.internal.unpackTableInto(industrialtest.Reactor,{ name="industrialtest:nuclear_reactor", description=S("Nuclear Reactor"), tiles={ "industrialtest_machine_block.png^industrialtest_nuclear_reactor_top.png", "industrialtest_machine_block.png", "industrialtest_machine_block.png", "industrialtest_machine_block.png", "industrialtest_machine_block.png", "industrialtest_machine_block.png^industrialtest_nuclear_reactor_front.png" }, sounds="metal", requiresWrench=true, facedir=true, storageLists={ "charged", "fuel" }, powerLists={ { list="charged", direction="o" } }, active={ tiles={ "industrialtest_machine_block.png^industrialtest_nuclear_reactor_top.png", "industrialtest_machine_block.png", "industrialtest_machine_block.png", "industrialtest_machine_block.png", "industrialtest_machine_block.png", "industrialtest_machine_block.png^industrialtest_nuclear_reactor_front_active.png" }, lightSource=2 }, capacity=industrialtest.api.evPowerFlow, flow=industrialtest.api.evPowerFlow, hasPowerOutput=true, ioConfig="oooooo" }) function industrialtest.Reactor.onConstruct(self,pos) local meta=minetest.get_meta(pos) local inv=meta:get_inventory() inv:set_size("fuel",4) inv:set_size("charged",1) meta:set_int("heat",0) meta:set_int("size",6) meta:set_int("enabled",0) meta:set_int("stateChanged",0) industrialtest.ActivatedElectricMachine.onConstruct(self,pos) end function industrialtest.Reactor.onDestruct(self,pos) local meta=minetest.get_meta(pos) local chambers=minetest.deserialize(meta:get_string("chambers")) or {} for _,chamber in ipairs(chambers) do minetest.remove_node(chamber) minetest.add_item(chamber,"industrialtest:nuclear_reactor_chamber") end industrialtest.ActivatedElectricMachine.onDestruct(self,pos) end function industrialtest.Reactor.getFormspec(self,pos) local parentFormspec=industrialtest.ActivatedElectricMachine.getFormspec(self,pos) local meta=minetest.get_meta(pos) local charged=meta:get_int("industrialtest.powerAmount")/meta:get_int("industrialtest.powerCapacity") local size=math.floor(meta:get_int("size")/3) local switchText=(meta:get_int("enabled")==0 and S("Start") or S("Stop")) local formspec={ "list[context;fuel;1,1;"..size..","..size.."]", industrialtest.internal.getItemSlotBg(1,1,size,size), "list[context;charged;7,2.8;1,1]", industrialtest.internal.getItemSlotBg(7.7,2.8,1,1), "button[7.7,1;1,0.8;toggle;"..minetest.formspec_escape(switchText).."]", self.createPowerIndicatorWidget(charged,9,1), "listring[context;fuel]" } return parentFormspec..table.concat(formspec,"") end function industrialtest.Reactor.allowMetadataInventoryMove(self,pos,fromList,fromIndex,toList,toIndex,count) local meta=minetest.get_meta(pos) local inv=meta:get_inventory() local movedItemStack=inv:get_stack(fromList,fromIndex) local def=movedItemStack:get_definition() if toList=="fuel" and (not def or not def.groups._industrialtest_placedInNuclearReactor) then return 0 end return industrialtest.ActivatedElectricMachine.allowMetadataInventoryMove(self,pos,fromList,fromIndex,toList,toIndex,count) end function industrialtest.Reactor.allowMetadataInventoryPut(self,pos,listname,index,stack,player) local def=stack:get_definition() if listname=="fuel" and (not def or not def.groups._industrialtest_placedInNuclearReactor) then return 0 end return industrialtest.ActivatedElectricMachine.allowMetadataInventoryPut(self,pos,listname,index,stack,player) end function industrialtest.Reactor.onMetadataInventoryMove(self,pos,fromList,fromIndex,toList,toIndex,count) industrialtest.ActivatedElectricMachine.onMetadataInventoryMove(self,pos,fromList,fromIndex,toList,toIndex,count) self.synchronizeChambers(pos) end function industrialtest.Reactor.onMetadataInventoryPut(self,pos,listname,index,stack,player) industrialtest.ActivatedElectricMachine.allowMetadataInventoryPut(self,pos,listname,index,stack,player) self.synchronizeChambers(pos) end function industrialtest.Reactor.onMetadataInventoryTake(self,pos,listname,index,stack) industrialtest.ActivatedElectricMachine.onMetadataInventoryTake(self,pos,listname,index,stack) self.synchronizeChambers(pos) end function industrialtest.Reactor.onReceiveFields(self,pos,formname,fields) if not fields.toggle then return end local meta=minetest.get_meta(pos) if not self.hasFuel(pos) and meta:get_int("enabled")==0 then return end if meta:get_int("enabled")==0 then meta:set_int("enabled",1) else meta:set_int("enabled",0) self:updateFormspec(pos) self.synchronizeChambers(pos) end meta:set_int("stateChanged",1) self:triggerIfNeeded(pos) end function industrialtest.Reactor.shouldActivate(self,pos) local meta=minetest.get_meta(pos) if meta:get_int("stateChanged")==0 then return false end return meta:get_int("enabled")>0 and self.hasFuel(pos) end function industrialtest.Reactor.shouldDeactivate(self,pos) local meta=minetest.get_meta(pos) return meta:get_int("enabled")==0 or not self.hasFuel(pos) end function industrialtest.Reactor.afterActivation(self,pos) local meta=minetest.get_meta(pos) meta:set_int("stateChanged",0) self.synchronizeChambers(pos) end function industrialtest.Reactor.afterDeactivation(self,pos) local meta=minetest.get_meta(pos) meta:set_int("enabled",0) self:updateFormspec(pos) self.synchronizeChambers(pos) end function industrialtest.Reactor.activeUpdate(self,pos,elapsed,meta,inv) local size=math.floor(meta:get_int("size")/3) local fuelList=inv:get_list("fuel") local shouldRerunTimer=meta:get_int("enabled")>0 local shouldUpdateFormspec=false local maxCluster=self.findMaxFuelCluster(size,fuelList) for _,stack in ipairs(maxCluster) do local index=stack.y*size+stack.x local usedStack,_=self.useFuel(fuelList[index],5) inv:set_stack("fuel",index,usedStack) end local generatedPowerAmount=math.pow(3,#maxCluster) if industrialtest.api.addPower(meta,generatedPowerAmount)>0 then shouldUpdateFormspec=true end local heat=meta:get_int("heat")+#maxCluster local coolant=self.findCoolant(fuelList) if coolant>0 then local coolantStack,used=self.useFuel(fuelList[coolant],#maxCluster*50) heat=math.max(0,heat-used) inv:set_stack("fuel",coolant,coolantStack) end if heat>200 then minetest.remove_node(pos) industrialtest.internal.explode(pos,#maxCluster*4) return false end meta:set_int("heat",heat) self.synchronizeChambers(pos) return shouldUpdateFormspec end function industrialtest.Reactor.changeSize(self,pos,diff) local meta=minetest.get_meta(pos) local inv=meta:get_inventory() local size=meta:get_int("size")+diff local actualSize=math.floor(size/3) meta:set_int("size",size) inv:set_size("fuel",actualSize*actualSize) self:updateFormspec(pos) end function industrialtest.Reactor.synchronizeToChamber(self,pos) local meta=minetest.get_meta(pos) local inv=meta:get_inventory() local fuelList=inv:get_list("fuel") local chargedList=inv:get_list("charged") local reactorPos=minetest.deserialize(meta:get_string("reactor")) local reactorMeta=minetest.get_meta(reactorPos) local reactorInv=reactorMeta:get_inventory() reactorInv:set_list("fuel",fuelList) reactorInv:set_list("charged",chargedList) self.synchronizeChambers(reactorPos) end function industrialtest.Reactor.hasFuel(pos) local meta=minetest.get_meta(pos) local inv=meta:get_inventory() local fuelList=inv:get_list("fuel") for _,stack in ipairs(fuelList) do if stack:get_name()=="industrialtest:uranium_cell" then return true end end return false end function industrialtest.Reactor.findMaxFuelCluster(size,fuelList) local maxCluster={} for y=1,size do for x=1,size do local iy=y-1 local stack=fuelList[iy*size+x] local def=minetest.registered_tools[stack:get_name()] if def and def.groups._industrialtest_nuclearReactorFuel then local cluster={ [1]={ x=x, y=iy } } if x>1 and fuelList[iy*size+x-1]:get_name()==stack:get_name() then table.insert(cluster,{ x=x-1, y=iy }) end if x1 and fuelList[(iy-1)*size+x]:get_name()==stack:get_name() then table.insert(cluster,{ x=x, y=iy-1 }) end if y1 and y>1 and fuelList[(iy-1)*size+x-1]:get_name()==stack:get_name() then table.insert(cluster,{ x=x-1, y=iy-1 }) end if x1 and fuelList[(iy-1)*size+x+1]:get_name()==stack:get_name() then table.insert(cluster,{ x=x+1, y=iy-1 }) end if x>1 and y#maxCluster then maxCluster=cluster end end end end return maxCluster end function industrialtest.Reactor.findCoolant(fuelList) for i=1,#fuelList do local stack=fuelList[i] local def=minetest.registered_tools[stack:get_name()] if def and def.groups._industrialtest_nuclearReactorCoolant then return i end end return 0 end function industrialtest.Reactor.useFuel(stack,use) local used=math.min(65535-stack:get_wear(),use) if used