z_mirror/MouseOverConstruction

git clone https://git.raiguard.me/z_mirror/MouseOverConstruction

Caleb HeuerMicro2af5331

trunk
4.0 KiB145 linesraw
1--- @param box1 BoundingBox
2--- @param box2 BoundingBox
3local function bounding_boxes_equal(box1, box2)
4  return box1.left_top.x == box2.left_top.x
5    and box1.left_top.y == box2.left_top.y
6    and box1.right_bottom.x == box2.right_bottom.x
7    and box1.right_bottom.y == box2.right_bottom.y
8end
9
10--- @param entity LuaEntity
11--- @return string
12local function get_useful_type(entity)
13  if entity.type == "entity-ghost" then
14    return entity.ghost_type
15  end
16  return entity.type
17end
18
19--- @class common
20local common = {}
21
22--- Builds an entity over the top of an existing entity.
23--- @param player LuaPlayer
24--- @param entity LuaEntity
25--- @param new_prototype LuaEntityPrototype
26--- @param new_quality LuaQualityPrototype
27--- @return LuaEntity?
28function common.build(player, entity, new_prototype, new_quality)
29  local item, consume_count = common.get_item(player, new_prototype, new_quality)
30  if not item then
31    return nil
32  end
33
34  local bounding_box = entity.bounding_box
35  local surface = entity.surface
36  local position = entity.position
37  local direction = entity.direction
38  local quality = entity.quality
39  local force = entity.force
40
41  local new_entity = surface.create_entity({
42    name = new_prototype.name,
43    position = position,
44    direction = direction,
45    quality = new_quality,
46    force = force,
47    fast_replace = true,
48    player = player,
49    character = player.character,
50    raise_built = true,
51    create_build_effect_smoke = true,
52    spawn_decorations = true,
53    move_stuck_players = true,
54    item = item,
55    register_plant = true,
56    mirror = entity.mirroring,
57    -- Undergound belt
58    type = get_useful_type(entity) == "underground-belt" and entity.belt_to_ground_type or nil,
59  })
60  if not new_entity or not new_entity.valid then
61    -- Some mods will immediately replace the entity with a different one. Let's see if we can detect this.
62    for _, replaced_entity in
63      pairs(surface.find_entities_filtered({
64        direction = direction,
65        position = position,
66        quality = quality.name,
67        force = force,
68      }))
69    do
70      if
71        replaced_entity.type ~= "entity-ghost"
72        and replaced_entity.type ~= "tile-ghost"
73        and bounding_boxes_equal(replaced_entity.bounding_box, bounding_box)
74      then
75        new_entity = replaced_entity
76        break
77      else
78        return
79      end
80    end
81  end
82
83  if not new_entity or not new_entity.valid then
84    return
85  end
86
87  item.count = item.count - consume_count
88
89  local stats = force.get_entity_build_count_statistics(surface)
90  stats.on_flow(new_entity, 1)
91
92  player.play_sound({
93    path = "entity-build/" .. new_entity.name,
94    position = new_entity.position,
95  })
96
97  return new_entity
98end
99
100--- @param player LuaPlayer
101--- @param entity LuaEntity
102--- @param new_prototype LuaEntityPrototype
103--- @return boolean
104function common.check_can_place_entity(player, entity, new_prototype)
105  if
106    not player.can_place_entity({
107      name = new_prototype.name,
108      position = entity.position,
109      direction = entity.direction,
110    })
111  then
112    storage.recheck_on_move[player.index] = true
113    return false
114  end
115  return true
116end
117
118--- Returns the first LuaItemStack that can build the given entity and quality.
119--- @param player LuaPlayer
120--- @param prototype LuaEntityPrototype
121--- @param quality LuaQualityPrototype
122--- @return LuaItemStack?, uint?
123function common.get_item(player, prototype, quality)
124  local cursor_stack = player.cursor_stack
125  local inventory = player.get_main_inventory()
126  for _, item_to_place in pairs(prototype.items_to_place_this or {}) do
127    if
128      cursor_stack
129      and cursor_stack.valid_for_read
130      and cursor_stack.name == item_to_place.name
131      and cursor_stack.quality == quality
132      and cursor_stack.count >= item_to_place.count
133    then
134      return cursor_stack, item_to_place.count
135    end
136    if inventory then
137      local item = inventory.find_item_stack({ name = item_to_place.name, quality = quality.name })
138      if item and item.count >= item_to_place.count then
139        return item, item_to_place.count
140      end
141    end
142  end
143end
144
145return common