help with making a harvester

Place to get help with not working mods / modding interface.
McSpiffy
Long Handed Inserter
Long Handed Inserter
Posts: 51
Joined: Mon May 05, 2014 9:17 pm
Contact:

help with making a harvester

Post by McSpiffy »

Hi I am new to modding and would like some help. So the idea is to recreate the harvester from C&C Red Alert. Now I have been working at this for a few days and have been able to rip the images from red alert , resize them, get the harvester to work like a car with the proper hit boxes, and set up a recipe for it. Now can anyone inform me on how to get it to mine and deposit the ore it mines into its "trunk". Also I'm Rly kind of clueless when it comes to making a control or migration file so I can't seem to get it to work in previous saves.
Last edited by McSpiffy on Thu May 08, 2014 8:35 pm, edited 4 times in total.
User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: help with making a harvester

Post by FreeER »

First, a migration file should not be necessary for adding a new mod (they are used when updating mods so that the saved data/prototypes are in the state expected by the new version when it start running, for instance if you'd had the harvester be a type 'container' or type 'train' in the old save and then changed it to type 'car' or if you were saving data in the glob table and then changed the format of it, though this mod shouldn't actually need to store any data :)).
Second, you will need to use the control.lua for this :)

Now, to get it to mine you'll need to know it's position and then check if any ore is under/nearby it, and if so decrement the ore's amount and insert that ore into the harvesters inventory.

a control.lua like so should work, should be enough comments for you to understand how it's working, if you want any clarification be sure to ask!

Code: Select all

require "defines" -- has a bunch of defined constants for events and inventory, etc. the file itself is data\core\lualib\defines.lua

game.onevent(defines.event.ontick, function() --tell game we want to do stuff every tick (60 times per second)
  if game.tick % 60 == 0 then -- do this only once per second, you can decrease 60 if needed...but it'd probably be better to increase the amount of ore being removed
    if game.player.vehicle and game.player.vehicle.name == "harvester" then -- if the player is in a vehicle and it is a harvester
      local ore = game.findentitiesfiltered{type = "resource", area={{game.player.vehicle.position.x - 10, game.player.vehicle.position.y -10}, {game.player.vehicle.position.x - 10, game.player.vehicle.position.y -10}} -- get a table of the ore within a (square) radius of 10 around the harvester, thankfully that was fairly easy, change the '10' to any value you think is appropriate, the 'type = "resource"' might allow it to 'mine' trees as well...if so and you didn't want that you'd need to have multiple tables and instead search using 'name = "name_of_ores"'
      local oreAmount = 1 -- amount of ore to mine from each resource spot
      for _, ore in ipairs(ore) do -- loop through those ores
        if game.player.vehicle.caninsert{name = ore.name, count = oreAmount} -- if the harvester is not full
          if ore.amount >= oreAmount then -- if there is more than enough ore
            ore.amount = ore.amount - oreAmount -- decrement the ore by oreAmount
            game.player.vehicle.insert{name = ore.name, count = oreAmount} -- and insert it into the harvester
          else -- if the amount of ore left is not greater than or equal to what we want to remove, just remove all of it (without the else, it'd leave any spots less than oreAmount...which would be somewhat annoying lol)
            game.player.vehicle.insert{name = ore.name, count = ore.amount} -- insert first so that we don't need a local variable to store the amount
            ore.amount = 0 -- then just set ore amount to 0 instead doing ore.amount = ore.amount - ore.amount (cause that looks silly :))
          end
        end
      end
    end
  end
end) -- end anonymous function and onevent/ontick call
McSpiffy
Long Handed Inserter
Long Handed Inserter
Posts: 51
Joined: Mon May 05, 2014 9:17 pm
Contact:

Re: help with making a harvester

Post by McSpiffy »

Ok so I got the control script to run in the game but it still wont mine. I had edit a few syntax errors to get it to work. But I don't know how to get it to mine.
I uploaded my wip so maybe you could take a look at it.

Do I have to define the ore types in line 8 where it says "for _, ore in ipairs(ore) do"?
also i have mining animations for the harvester is there any way to incorporate them while the harvester in mining?
Last edited by McSpiffy on Thu May 08, 2014 5:51 pm, edited 1 time in total.
User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: help with making a harvester

Post by FreeER »

McSpiffy wrote:the first was missing a "}" at the end of line 6 i guess
yep, definitely needs a '}' at the end of line 6 and there is a missing "then" for line 9 (the caninsert if statement)...it shows as line 10 because it finishes 9 still expecting a "then" and doesn't find one on line 10.

That's what I get for writing it in the forum comment box instead of notepad++ or vim (which have nice syntax highlighting). Sorry. That should be it though :)
McSpiffy
Long Handed Inserter
Long Handed Inserter
Posts: 51
Joined: Mon May 05, 2014 9:17 pm
Contact:

Re: help with making a harvester

Post by McSpiffy »

By the way thank you so much for the help this is the first time I'm using Lua.
User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: help with making a harvester

Post by FreeER »

McSpiffy wrote:By the way thank you so much for the help this is the first time I'm using Lua.
No problem, it's something I absolutely love to do :D

ok, found the problem...and also found another one caused by fixing it :lol:
the problem is (other than the syntax) that in the ore = findentitiesfiltered, area parameters I passed {{x - 10,y-10}, {x - 10,y-10}} instead of {{x - 10, y - 10}, {x + 10,y + 10}}, so it searches a very very small area instead of the square I'd intended.. (that is why I usually define a function called getBoundingBox(position, radius) return {{position.x - radius,position.y-radius}, {position.x + radius,position.y + radius}} end and use it instead with getBoundingBox(game.player.vehicle.position, 10)...) I noticed by using game.player.print(serpent.block(ore)) to see what the findentitiesfiltered function was returning...which was an empty table lol

Now the next problem is that type=resource also matches oil but 'crude-oil' is not an item and so it crashes on insert... sigh, I think it'd be easiest to fix that is in the loop by checking if the name==oil (and you could of course use extra checks for trees if they happen too, I went ahead and showed how to handle that since there are multiple trees but all of their names end with "tree")

new, working code :)

Code: Select all

require "defines" -- has a bunch of defined constants for events and inventory, etc. the file itself is data\core\lualib\defines.lua

game.onevent(defines.events.ontick, function() --tell game we want to do stuff every tick (60 times per second)
  if game.tick % 60 == 0 then -- do this only once per second, you can decrease 60 if needed...but it'd probably be better to increase the amount of ore being removed
    if game.player.vehicle and game.player.vehicle.name == "harvester" then -- if the player is in a vehicle and it is a harvester
      local ore = game.findentitiesfiltered{type = "resource", area=getBoundingBox(game.player.vehicle.position, 3)} -- get a table of the ore within a (square) radius of 10 around the harvester, thankfully that was fairly easy, change the '10' to any value you think is appropriate, the 'type = "resource"' might allow it to 'mine' trees as well...if so and you didn't want that you'd need to have multiple tables and instead search using 'name = "name_of_ores"'
      local oreAmount = 1 -- amount of ore to mine from each resource spot
      for _, ore in pairs(ore) do -- loop through those ores
        if ore.name ~= "crude-oil" and ore.name:sub(-4) ~= "tree" then
          if game.player.vehicle.caninsert{name = ore.name, count = oreAmount} then -- if the ore's name is not crude-oil and it's last 4 characters are not "tree"
            if ore.amount >= oreAmount then -- if there is more than enough ore
              ore.amount = ore.amount - oreAmount -- decrement the ore by oreAmount
              game.player.vehicle.insert{name = ore.name, count = oreAmount} -- and insert it into the harvester
            else -- if the amount of ore left is not greater than or equal to what we want to remove, just remove all of it (without the else, it'd leave any spots less than oreAmount...which would be somewhat annoying lol)
              game.player.vehicle.insert{name = ore.name, count = ore.amount} -- insert first so that we don't need a local variable to store the amount
              ore.amount = 0 -- then just set ore amount to 0 instead doing ore.amount = ore.amount - ore.amount (cause that looks silly :))
            end
          end
        end
      end
    end
  end
end) -- end anonymous function and onevent/ontick calls

function getBoundingBox(position, radius)
  return {{position.x - radius, position.y-radius}, {position.x + radius, position.y + radius}}
end
Note, it's fairly slow to mine right now, but that can be changed by increasing the oreAmount from 1 to, idk, say 10.
edit: also note that I changed the boundingbox from a radius of 10 to a radius of 3 (when calling the function)...10 was really far to big :lol:
McSpiffy
Long Handed Inserter
Long Handed Inserter
Posts: 51
Joined: Mon May 05, 2014 9:17 pm
Contact:

Re: help with making a harvester

Post by McSpiffy »

thanks so much it works :D Now question is there anyway to add a mining animation for each direction the the harvester stops in kind of like how the mining drill entity has animations for north, south, east, and west but have n,ne,nw,e,se,s,and south west?
User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: help with making a harvester

Post by FreeER »

McSpiffy wrote:add a mining animation
hm...not that I know of, but I don't usually do much with animations so it's possible that someone who has used those more than I have would know a way :)

sorry I can't help you any more with that part...
McSpiffy
Long Handed Inserter
Long Handed Inserter
Posts: 51
Joined: Mon May 05, 2014 9:17 pm
Contact:

Re: help with making a harvester

Post by McSpiffy »

That's fine, you did more then I ever hoped! Now its time to work on the Refinery building to dump all the ore I collect into it ^0^ I might need help with that later 2. But for now I will post this mod as 0.0.2 for any one who wants to try it^0^
McSpiffy
Long Handed Inserter
Long Handed Inserter
Posts: 51
Joined: Mon May 05, 2014 9:17 pm
Contact:

Re: help with making a harvester

Post by McSpiffy »

Any idea on how to get it to work in previous saves? example: like in campaign?
User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: help with making a harvester

Post by FreeER »

McSpiffy wrote:like in campaign?
The campaigns actually disable everything they don't want you to have (probably to avoid overwhelming new people when they first play)...You'd have to modify the campaign files (or copy them to your mod and then change them, but then you'd start them by using play->custom scenario I believe), see: data\base\campaigns\beta\level-01\control.lua, line 8-80...of course you'd have to modify ALL of the campaigns to include your prototypes (or give access to all prototypes by removing line 9 I think).

Any previous freeplay saves should work without anything needing to be done however.
McSpiffy
Long Handed Inserter
Long Handed Inserter
Posts: 51
Joined: Mon May 05, 2014 9:17 pm
Contact:

Re: help with making a harvester

Post by McSpiffy »

Ok kool thx again!
McSpiffy
Long Handed Inserter
Long Handed Inserter
Posts: 51
Joined: Mon May 05, 2014 9:17 pm
Contact:

Re: help with making a harvester

Post by McSpiffy »

hey so i figured out the the burner slot is game.player.vehicle.getinventory(1).insert({name="coal", count="1"}) by inserting coal
so i think if i can figure out how to write code to check and see if game.player.vehicle.getinventory(1)is less then 64 to then check and see if I have coal in the harvester's inventory and if so give the burner in increments of 1 until the burners slot =64. So am i on the right track with this?
User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: help with making a harvester

Post by FreeER »

Definitely on the right track :) check out the wiki Lua/Inventory and see if one of those would be helpful with getting the 'count' of "coal" inside the inventory :) (and more generally Lua/Objects for other other entities).
McSpiffy wrote:give the burner in increments of 1
You could give it simply by 64-amount_in_burner, which would fill it up, but either would work :)

You could also do it while mining instead of checking the main inventory, so it only gets refueled automatically when mining coal and low on fuel, otherwise (not mining coal or not low on fuel) the player has to fill it. Not sure which is preferable but I thought I'd mention it :)
McSpiffy
Long Handed Inserter
Long Handed Inserter
Posts: 51
Joined: Mon May 05, 2014 9:17 pm
Contact:

Re: help with making a harvester

Post by McSpiffy »

Kool I'll try to dig into to it some more to see what i can achieve^0^
McSpiffy
Long Handed Inserter
Long Handed Inserter
Posts: 51
Joined: Mon May 05, 2014 9:17 pm
Contact:

Re: help with making a harvester

Post by McSpiffy »

How is this so far?

Code: Select all

game.player.vehicle.getinventory(1).insert({name="coal", count="1"})
game.onevent(defines.events.ontick, function() 
  if game.tick % 60 == 0 then
	if game.player.vehicle and game.player.vehicle.name == "harvester" then
		if game.player.vehicle.getitemcount(1) <= 20, then
		 if game.player.vehicle.getitemcount(2).ore.coal >0, then
		 game.player.vehicle.getitemcount(2).remove({name="coal", count="1"}) then
		 game.player.vehicle.getitemcount(1).insert({name="coal", count="1"})
User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: help with making a harvester

Post by FreeER »

McSpiffy wrote:game.player.vehicle.getinventory(1).insert({name="coal", count="1"})
Not entirely sure if you actually want to insert coal on this first line... especially since it is outside of the if statement checking if the player is in a vehicle or not (note: if the player is not in a vehicle game.player.vehicle is equal to (aka returns) 'nil' and trying to use a 'nil' value, by saying .getinventory(1) for instance, will cause an immediate error in game :))

to prevent having to type game.player.vehicle.getinventory(x) a lot you can store them to local variables like so:

Code: Select all

-- possible code above
local burner = game.player.vehicle.getinventory(1)
local trunk = game.player.vehicle.getinventory(2)
-- other possible code
if burner.getitemcount("coal") <= 20 then 
  -- code
end

-- without using the variable you'd need:
if game.player.vehicle.getinventory(1).getitemcount("coal") <= 20 then
  -- this if statement is what is actually being called/used when you use the variable
  -- but it's much shorter to use the variable, especially if you'd otherwise be typing that several times :)
end
local just means that once they are 'out of scope' (in this case once the end of the "harvester" if statement is reached) that the rest of your code (which right now is mostly just ending if statements and the onevent call) can not access them (aka, Factorio is not wasting memory by keeping that data when it is not going to be used), mainly it's considered good practice to use local variables unless you know you need them elsewhere.

You might have noticed I used getitemcount("coal") and not getitemcount(1)... it's the item name that you pass to getitemcount not the inventory id, and you actually need to get the inventory before calling getitemcount (the exception is that if you just call game.player.vehicle.getitemcount() it will automatically use the default inventory). Also, something that can be useful (especially to shorten finding coal since the burner can have nothing other than fuel) is that if you do not pass an item name to getitemcount() it will return the count of ALL items in that inventory.

So, a working (and ever so slightly shorter version) of what you posted is:

Code: Select all

-- game.player.vehicle.getinventory(1).insert({name="coal", count="1"}) -- commented this line out since I'm not certain why it's here to be honest...

game.onevent(defines.events.ontick, function()
  if game.tick % 60 == 0 then
   if game.player.vehicle and game.player.vehicle.name == "harvester" then
     local burner = game.player.vehicle.getinventory(1)
     local main = game.player.vehicle.getinventory(2)
     -- notice that I combined these since you won't do anything if only one is true
     if burner.getitemcount() <= 20 and main.getitemcount("coal") > 0  then
       main.remove({name="coal", count="1"})
       burner.insert({name="coal", count="1"})
McSpiffy
Long Handed Inserter
Long Handed Inserter
Posts: 51
Joined: Mon May 05, 2014 9:17 pm
Contact:

Re: help with making a harvester

Post by McSpiffy »

lol this is where i was at when i read you'r post >.<

Code: Select all

game.onevent(defines.events.ontick, function() --t
  if game.tick % 60 == 0 then
      if game.player.vehicle and game.player.vehicle.name == "harvester" then
		local burnerCoal = game.player.vehicle.getitemcount(1) 
		  if bunerCoal (<20,) then
			if game.player.vehicle.getitemcount(2) (name"coal" >0) then
				game.player.vehicle.getitemcount(2).remove({name="coal", count="1"})
				game.player.vehicle.getitemcount(1).insert({name="coal", count="1"})
			else
McSpiffy
Long Handed Inserter
Long Handed Inserter
Posts: 51
Joined: Mon May 05, 2014 9:17 pm
Contact:

Re: help with making a harvester

Post by McSpiffy »

hey do you know if there is a way to set the harvester's sprite sheet to a variable so I could switch out the sprite sheet when its mining? maybe something along the lines of

Code: Select all

harvSprite = harvAnimation
	harvAnimation = "__harvester-mod__/graphics/entity/harvester/drive_harv-sheet.png",
		if game.player.vehicle == "harvester" then
			local ore = game.findentitiesfiltered{type = "resource", area=getBoundingBox(game.player.vehicle.position, 2)}
				if game.player.vehicle.caninsert{name = ore.name, count = oreAmount} then
				 harvAnimation = "__harvester-mod__/graphics/entity/harvester/mining_harv-sheet.png"
User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: help with making a harvester

Post by FreeER »

you can set the prototype of the sprite to be a variable in the data files...but once it's loaded you can not switch between them (you have very limited access to prototypes through control.lua) so no you can not do that at this time, as far as I am aware.

Remember, this game is 'relatively' new so some things haven't been fully worked out yet (or done at all). You can make an interface request for the devs and other modders to see (try to be somewhat specific for how you think the best/easiest way might be to do what you want but also state the primary goal, animating sprites from control.lua for example, as generally as possible so others can easily offer alternative solutions :)), and realize that it may take quite some time to get done (the devs are focusing on certain things right now :))
Post Reply

Return to “Modding help”