1extends Control
2
3export var show_blueprint = false
4export var campaign_map = true
5export var take_enemy_hq = true
6export var control_all_towers = false
7export var multiplayer_map = false
8
9var terrain
10var underground
11var units
12var map_layer_back
13var map_layer_front
14var action_layer
15var bag
16var random_tile
17
18var mouse_dragging = false
19var pos
20var game_size
21var scale
22var root
23var camera
24var theme
25
26var shake_timer = Timer.new()
27var shakes = 0
28export var shakes_max = 5
29export var shake_time = 0.25
30export var shake_boundary = 5
31var shake_initial_position
32
33var current_player = 0
34
35const GEN_GRASS = 6
36const GEN_FLOWERS = 3
37const GEN_STONES = 6
38const GEN_SNOW_PARTICLES = 5
39
40var map_file = load('res://scripts/services/map_file_handler.gd').new()
41var campaign
42var used_tiles_list = []
43
44var tileset
45var map_movable = preload('res://terrain/tilesets/summer_movable.xscn')
46var map_non_movable = preload('res://terrain/tilesets/summer_non_movable.xscn')
47var wave = preload('res://terrain/wave.xscn')
48var underground_rock = preload('res://terrain/underground.xscn')
49
50var map_city_small = [
51    preload('res://terrain/city/summer/city_small_1.xscn'),
52    preload('res://terrain/city/summer/city_small_2.xscn'),
53    preload('res://terrain/city/summer/city_small_3.xscn'),
54    preload('res://terrain/city/summer/city_small_4.xscn'),
55    preload('res://terrain/city/summer/city_small_5.xscn'),
56    preload('res://terrain/city/summer/city_small_6.xscn')
57    ]
58var map_city_big = [
59    preload('res://terrain/city/summer/city_big_1.xscn'),
60    preload('res://terrain/city/summer/city_big_2.xscn'),
61    preload('res://terrain/city/summer/city_big_3.xscn'),
62    preload('res://terrain/city/summer/city_big_4.xscn')
63    ]
64var map_statue = preload('res://terrain/city/summer/city_statue.xscn')
65var map_buildings = [
66    preload('res://buildings/bunker_blue.xscn'),
67    preload('res://buildings/bunker_red.xscn'),
68    preload('res://buildings/barrack.xscn'),
69    preload('res://buildings/factory.xscn'),
70    preload('res://buildings/airport.xscn'),
71    preload('res://buildings/tower.xscn'),
72    preload('res://buildings/fence.xscn')
73]
74
75var map_units = [
76    preload('res://units/soldier_blue.xscn'),
77    preload('res://units/tank_blue.xscn'),
78    preload('res://units/helicopter_blue.xscn'),
79    preload('res://units/soldier_red.xscn'),
80    preload('res://units/tank_red.xscn'),
81    preload('res://units/helicopter_red.xscn')
82]
83
84var map_civilians = [
85    preload('res://units/civilians/old_woman.tscn'),
86    preload('res://units/civilians/protest_guy.tscn'),
87    preload('res://units/civilians/protest_guy2.tscn'),
88    preload('res://units/civilians/refugee.tscn'),
89    preload('res://units/civilians/refugee2.tscn')
90]
91
92var waypoint = preload('res://maps/waypoint.tscn')
93
94var is_dead = false
95
96var should_do_awesome_explosions = false
97var awesome_explosions_interval = 10
98var awesome_explosions_interval_counter = 0
99
100
101func do_awesome_cinematic_pan():
102    self.set_map_pos_global(Vector2(self.sX - 1, self.sY))
103
104func do_awesome_random_explosions():
105    if not self.should_do_awesome_explosions:
106        return
107    var root_tree = self.root.get_tree()
108    var all_units = root_tree.get_nodes_in_group("units")
109    if all_units.size() == 0:
110        return
111    randomize()
112    var unit = all_units[randi() % all_units.size()]
113    if unit.die:
114        return
115    var stats = unit.get_stats()
116    stats.life -= 5
117    unit.set_stats(stats)
118    if stats.life < 0:
119        var field = self.root.bag.abstract_map.get_field(unit.get_pos_map())
120        self.root.bag.controllers.action_controller.play_destroy(field)
121        self.root.bag.controllers.action_controller.destroy_unit(field)
122        self.root.bag.controllers.action_controller.collateral_damage(unit.get_pos_map())
123    else:
124        unit.show_explosion()
125
126func move_to(target):
127    if not mouse_dragging:
128        self.camera.target = target;
129
130func set_map_pos_global(position):
131    self.camera.set_pos(position)
132
133func set_map_pos(position):
134    self.game_size = self.root.get_size()
135    position = self.terrain.map_to_world(position*Vector2(-1,-1)) + Vector2(self.game_size.x/(2*self.scale.x), self.game_size.y/(2*self.scale.y))
136    self.set_map_pos_global(position)
137
138func move_to_map(target):
139    self.camera.move_to_map(target)
140
141func generate_map():
142    var temp = null
143    var temp2 = null
144    var terrain_under_building = null
145    var cells_to_change = []
146    var cell
147    randomize()
148    self.used_tiles_list = []
149
150    #map elements count
151    var city_small_elements_count = map_city_small.size()
152    var city_big_elements_count = map_city_big.size()
153    var neigbours = 0
154
155    for x in range(self.bag.abstract_map.MAP_MAX_X):
156        for y in range(self.bag.abstract_map.MAP_MAX_Y):
157
158            var terrain_cell = terrain.get_cell(x, y)
159            # underground
160            if terrain_cell > -1:
161                self.generate_underground(x, y)
162            else:
163                self.generate_wave(x, y)
164                continue
165
166            self.used_tiles_list.append(Vector2(x, y))
167
168            if terrain_cell == self.tileset.TERRAIN_PLAIN or terrain_cell == self.tileset.TERRAIN_DIRT:
169                # bridges
170                neigbours = count_neighbours_in_binary(x, y, [-1])
171
172                if neigbours == 10:
173                    cells_to_change.append({x=x, y=y, type=55})
174                    temp = null
175                elif neigbours == 20:
176                    cells_to_change.append({x=x, y=y, type=56})
177                    temp = null
178                elif not terrain_cell == self.tileset.TERRAIN_DIRT:
179                    # plain
180                    cells_to_change.append({x=x, y=y, type=1})
181                    # grass, flowers, log
182                    if ( randi() % 10 ) <= GEN_GRASS:
183                        temp = map_movable.instance()
184                        temp.set_frame(randi()%3)
185                    if ( randi() % 10 ) <= GEN_FLOWERS:
186                        temp2 = map_movable.instance()
187                        temp2.set_frame(8 + (randi()%8))
188                else:
189                    # dirt
190                    cells_to_change.append({x=x, y=y, type=0})
191                    if ( randi() % 10 ) <= GEN_STONES:
192                        temp = map_movable.instance()
193                        temp.set_frame(16 + (randi()%8))
194            if temp:
195                temp.set_pos(terrain.map_to_world(Vector2(x, y)))
196                map_layer_back.add_child(temp)
197                temp = null
198            if temp2:
199                temp2.set_pos(terrain.map_to_world(Vector2(x, y)))
200                map_layer_back.add_child(temp2)
201                temp2 = null
202
203            # forest
204            if terrain_cell == self.tileset.TERRAIN_FOREST:
205                temp = map_non_movable.instance()
206                temp.set_frame(randi()%10)
207                cells_to_change.append({x=x, y=y, type=1})
208
209            # mountains
210            if terrain_cell == self.tileset.TERRAIN_MOUNTAINS:
211                temp = map_non_movable.instance()
212                temp.set_frame(11 + (randi()%2))
213                if randi()%10 < GEN_SNOW_PARTICLES :
214                    temp.particle_enabled = true;
215                cells_to_change.append({x=x, y=y, type=1})
216
217            # city
218            if terrain_cell == self.tileset.TERRAIN_CITY || terrain_cell == self.tileset.TERRAIN_CITY_DESTROYED:
219                # have road near or have less than 5 neighbours
220                if count_neighbours(x,y,[self.tileset.TERRAIN_ROAD,self.tileset.TERRAIN_DIRT_ROAD, self.tileset.TERRAIN_BRIDGE, self.tileset.TERRAIN_RIVER]) > 0 or count_neighbours(x,y,[self.tileset.TERRAIN_CITY]) < 5:
221                    temp = map_city_small[randi() % city_small_elements_count].instance()
222                else:
223                    # no roads and not alone
224                    temp = map_city_big[randi() % city_big_elements_count].instance()
225                if terrain_cell == self.tileset.TERRAIN_CITY_DESTROYED:
226                    temp.set_damage()
227                terrain_under_building = 9
228
229            # special buildings
230            if terrain_cell == self.tileset.TERRAIN_STATUE:
231                temp = map_statue.instance()
232                terrain_under_building = 9
233
234            if terrain_cell == self.tileset.TERRAIN_SPAWN:
235                cells_to_change.append({x=x, y=y, type=13})
236
237            # concrete
238            if terrain_cell == self.tileset.TERRAIN_CONCRETE:
239                if randi() % 10 > 5:
240                    random_tile = 3
241                else:
242                    random_tile = 4
243                cells_to_change.append({x=x, y=y, type=random_tile})
244
245            # military buildings
246
247            if terrain_cell == self.tileset.TERRAIN_HQ_BLUE: # HQ blue
248                temp = map_buildings[0].instance()
249                terrain_under_building = 11
250            if terrain_cell == self.tileset.TERRAIN_HQ_RED: # HQ red
251                temp = map_buildings[1].instance()
252                terrain_under_building = 12
253            if terrain_cell == self.tileset.TERRAIN_BARRACKS_FREE: # barrack
254                temp = map_buildings[2].instance()
255                terrain_under_building = 10
256            if terrain_cell == self.tileset.TERRAIN_FACTORY_FREE: # factory
257                temp = map_buildings[3].instance()
258                terrain_under_building = 10
259            if terrain_cell == self.tileset.TERRAIN_AIRPORT_FREE: # airport
260                temp = map_buildings[4].instance()
261                terrain_under_building = 10
262            if terrain_cell == self.tileset.TERRAIN_TOWER_FREE: # tower
263                temp = map_buildings[5].instance()
264                terrain_under_building = 10
265            if terrain_cell == self.tileset.TERRAIN_BARRACKS_RED: # barrack
266                temp = map_buildings[2].instance()
267                temp.player = 1
268                terrain_under_building = 12
269            if terrain_cell == self.tileset.TERRAIN_FACTORY_RED: # factory
270                temp = map_buildings[3].instance()
271                temp.player = 1
272                terrain_under_building = 12
273            if terrain_cell == self.tileset.TERRAIN_AIRPORT_RED: # airport
274                temp = map_buildings[4].instance()
275                temp.player = 1
276                terrain_under_building = 12
277            if terrain_cell == self.tileset.TERRAIN_TOWER_RED: # tower
278                temp = map_buildings[5].instance()
279                temp.player = 1
280                terrain_under_building = 12
281            if terrain_cell == self.tileset.TERRAIN_BARRACKS_BLUE: # barrack
282                temp = map_buildings[2].instance()
283                temp.player = 0
284                terrain_under_building = 11
285            if terrain_cell == self.tileset.TERRAIN_FACTORY_BLUE: # factory
286                temp = map_buildings[3].instance()
287                temp.player = 0
288                terrain_under_building = 11
289            if terrain_cell == self.tileset.TERRAIN_AIRPORT_BLUE: # airport
290                temp = map_buildings[4].instance()
291                temp.player = 0
292                terrain_under_building = 11
293            if terrain_cell == self.tileset.TERRAIN_TOWER_BLUE: # tower
294                temp = map_buildings[5].instance()
295                temp.player = 0
296                terrain_under_building = 11
297            if terrain_cell == self.tileset.TERRAIN_FENCE: # fence
298                temp = map_buildings[6].instance()
299                terrain_under_building = 10
300
301            if temp:
302                self.attach_object(Vector2(x,y), temp)
303
304                if temp.group == 'building':
305                    temp.claim(temp.player, 0)
306                temp = 1
307                if terrain_under_building == null:
308                    if count_neighbours(x,y,[0]) >= count_neighbours(x,y,[1]):
309                        temp = 0
310                    else:
311                        temp = 1
312                else:
313                    temp = terrain_under_building
314
315                cells_to_change.append({x=x, y=y, type=temp})
316                temp = null
317
318            # roads
319            if terrain_cell == self.tileset.TERRAIN_ROAD: # city road
320                cells_to_change.append({x=x, y=y, type=self.build_sprite_path(x, y, [self.tileset.TERRAIN_ROAD, self.tileset.TERRAIN_BRIDGE])})
321            if terrain_cell == self.tileset.TERRAIN_DIRT_ROAD: # dirt road
322                cells_to_change.append({x=x, y=y ,type=self.build_sprite_path(x ,y, [self.tileset.TERRAIN_DIRT_ROAD, self.tileset.TERRAIN_BRIDGE])})
323            if terrain_cell == self.tileset.TERRAIN_RIVER: # river
324                cells_to_change.append({x=x, y=y, type=self.build_sprite_path(x, y, [self.tileset.TERRAIN_RIVER, self.tileset.TERRAIN_BRIDGE])})
325            if terrain_cell == self.tileset.TERRAIN_BRIDGE: # bridge
326                cells_to_change.append({x=x, y=y, type=self.build_sprite_path(x, y, [self.tileset.TERRAIN_BRIDGE, self.tileset.TERRAIN_RIVER])})
327
328            if units.get_cell(x,y) > -1:
329                self.spawn_unit(x,y,units.get_cell(x,y))
330
331            terrain_under_building = null
332
333    for cell in cells_to_change:
334        if(cell.type > -1):
335            terrain.set_cell(cell.x,cell.y,cell.type)
336    self.connect_fences()
337    units.hide()
338
339    self.bag.fog_controller.clear_fog()
340    return
341
342func attach_object(position, object):
343    object.set_pos(terrain.map_to_world(position))
344    map_layer_front.add_child(object)
345    self.find_spawn_for_building(position.x, position.y, object)
346
347func connect_fences():
348    for fence in get_tree().get_nodes_in_group("terrain_fence"):
349        fence.connect_with_neighbours()
350
351func count_neighbours(x, y, type):
352    var counted = 0
353    var tiles = 1
354
355    for cx in range(x-tiles, x+tiles+1):
356        for cy in range(y-tiles, y+tiles+1):
357            for t in type:
358                if terrain.get_cell(cx,cy) == t:
359                    counted = counted + 1
360
361    return counted
362
363func count_neighbours_in_binary(x, y, type):
364    var counted = 0
365
366    if terrain.get_cell(x, y-1) in type:
367        counted += 2
368    if terrain.get_cell(x+1, y) in type:
369        counted += 4
370    if terrain.get_cell(x, y+1) in type:
371        counted += 8
372    if terrain.get_cell(x-1, y) in type:
373        counted += 16
374
375    return counted
376
377func find_spawn_for_building(x, y, building):
378    if building.group != "building":
379        return
380    if building.can_spawn == false:
381        return
382
383    var acceptable_tiles = [
384        self.tileset.TERRAIN_PLAIN,
385        self.tileset.TERRAIN_DIRT,
386        self.tileset.TERRAIN_CONCRETE,
387        self.tileset.TERRAIN_ROAD,
388        self.tileset.TERRAIN_DIRT_ROAD,
389        self.tileset.TERRAIN_RIVER,
390        self.tileset.TERRAIN_BRIDGE,
391        self.tileset.TERRAIN_SPAWN,
392    ]
393
394    self.look_for_spawn(x, y, 1, 0, building)
395    self.look_for_spawn(x, y, 0, 1, building)
396    self.look_for_spawn(x, y, -1, 0, building)
397    self.look_for_spawn(x, y, 0, -1, building)
398
399    var current_spawn = terrain.get_cell(building.spawn_point.x, building.spawn_point.y)
400    for acceptable_tile in acceptable_tiles:
401        if current_spawn == acceptable_tile:
402            return
403
404    self.look_for_spawn(x, y, 1, 0, building, acceptable_tiles)
405    self.look_for_spawn(x, y, 0, 1, building, acceptable_tiles)
406    self.look_for_spawn(x, y, -1, 0, building, acceptable_tiles)
407    self.look_for_spawn(x, y, 0, -1, building, acceptable_tiles)
408
409
410func look_for_spawn(x, y, offset_x, offset_y, building, acceptable_tiles = null):
411    var cell = terrain.get_cell(x + offset_x, y + offset_y)
412    if acceptable_tiles == null:
413        acceptable_tiles = [self.tileset.TERRAIN_SPAWN]
414    for acceptable_tile in acceptable_tiles:
415        if cell == acceptable_tile:
416            building.spawn_point_position = Vector2(offset_x, offset_y)
417            building.spawn_point = Vector2(x + offset_x, y + offset_y)
418
419func build_sprite_path(x, y, type):
420    var neighbours
421
422    # big bridge
423    if type[0] == self.tileset.TERRAIN_ROAD or type[0] == self.tileset.TERRAIN_DIRT_ROAD:
424        neighbours = count_neighbours_in_binary(x, y, [-1])
425        if neighbours == 10:
426            return 55
427        if neighbours == 20:
428            return 56
429
430    # river bridge
431    if type[0] == self.tileset.TERRAIN_BRIDGE:
432        neighbours = count_neighbours_in_binary(x, y, [self.tileset.TERRAIN_RIVER])
433        if neighbours == 10:
434            return 31
435        if neighbours == 20:
436            return 30
437
438    neighbours = count_neighbours_in_binary(x, y, type)
439
440    # road
441    if type[0] == self.tileset.TERRAIN_ROAD:
442        if neighbours in [10,2,8]:
443            return 19
444        if neighbours in [20,16,4]:
445            return 20
446        if neighbours == 24:
447            return 21
448        if neighbours == 12:
449            return 22
450        if neighbours == 18:
451            return 23
452        if neighbours == 6:
453            return 24
454        if neighbours == 26:
455            return 25
456        if neighbours == 28:
457            return 26
458        if neighbours == 14:
459            return 27
460        if neighbours == 22:
461            return 28
462        if neighbours == 30:
463            return 29
464
465    # coutry road
466    if type[0] == self.tileset.TERRAIN_DIRT_ROAD:
467        if neighbours in [10,2,8]:
468            return 36
469        if neighbours in [20,16,4]:
470            return 37
471        if neighbours == 24:
472            return 38
473        if neighbours == 12:
474            return 39
475        if neighbours == 18:
476            return 40
477        if neighbours == 6:
478            return 41
479        if neighbours == 26:
480            return 42
481        if neighbours == 28:
482            return 43
483        if neighbours == 14:
484            return 44
485        if neighbours == 22:
486            return 45
487        if neighbours == 30:
488            return 46
489
490    # road mix
491    if type[0] == 16:
492        if neighbours == 2:
493            return 32
494        if neighbours == 16:
495            return 33
496        if neighbours == 8:
497            return 34
498        if neighbours == 4:
499            return 35
500
501    # river
502    if type[0] == self.tileset.TERRAIN_RIVER:
503        if neighbours in [10,2,8]:
504            if randi() % 4 > 2:
505                return 47
506            else:
507                return 53
508        if neighbours in [20,16,4]:
509            if randi() % 4 > 2:
510                return 48
511            else:
512                return 54
513        if neighbours == 24:
514            return 49
515        if neighbours == 12:
516            return 50
517        if neighbours == 18:
518            return 51
519        if neighbours == 6:
520            return 52
521
522    # nothing to change
523    return false
524
525func spawn_unit(x, y, type):
526    var temp
527    var new_x
528    var new_y
529    var MOVE_OFFSET = 32
530    var MAX_CIVILIANS_ON_TILE = 6
531
532    if type == 6:
533        for civil in range(MAX_CIVILIANS_ON_TILE):
534            temp = map_civilians[randi() % map_civilians.size()].instance()
535            new_x = (randi() % MOVE_OFFSET) - (MOVE_OFFSET/2)
536            new_y = (randi() % MOVE_OFFSET) - (MOVE_OFFSET/2)
537            temp.set_pos(terrain.map_to_world(Vector2(x,y)) + Vector2(new_x, new_y))
538            map_layer_front.add_child(temp)
539    else:
540        temp = map_units[type].instance()
541        temp.set_pos(terrain.map_to_world(Vector2(x,y)))
542        temp.position_on_map = Vector2(x,y)
543        map_layer_front.add_child(temp)
544    return temp
545
546func generate_underground(x, y):
547    var temp = null
548    var neighbours = count_neighbours_in_binary(x, y, [-1])
549
550    temp = underground_rock.instance()
551    temp.set_frame(0)
552    if neighbours in [10]:
553        temp.set_frame(1)
554    if neighbours in [20]:
555        temp.set_frame(2)
556    temp.set_pos(terrain.map_to_world(Vector2(x+1,y+1)))
557    underground.add_child(temp)
558    temp = null
559
560func generate_wave(x, y):
561    var generate = false
562    var temp = null
563    var waves_range = 4
564
565    for cx in range(x-waves_range, x+waves_range+1):
566        for cy in range(y-waves_range, y+waves_range+1):
567            if terrain.get_cell(cx, cy) > -1:
568                generate = true
569
570    if generate:
571        temp = wave.instance()
572        temp.set_pos(terrain.map_to_world(Vector2(x+1,y+1)))
573        underground.add_child(temp)
574        temp = null
575        return true
576
577    return false
578
579func set_default_zoom():
580    self.scale = (Vector2(2, 2))
581
582func get_map_data_as_array():
583    var temp_data = []
584    var temp_terrain = -1
585    var temp_unit = -1
586
587    for x in range(self.bag.abstract_map.MAP_MAX_X):
588        for y in range(self.bag.abstract_map.MAP_MAX_Y):
589            if terrain.get_cell(x, y) > -1:
590                temp_terrain = terrain.get_cell(x, y)
591
592            if units.get_cell(x, y) > -1:
593                temp_unit = units.get_cell(x, y)
594
595            if temp_terrain > -1 or temp_unit > -1:
596                temp_data.append({
597                    x=x,y=y,
598                    terrain=temp_terrain,
599                    unit=temp_unit
600                })
601
602            temp_terrain = -1
603            temp_unit = -1
604
605    return temp_data
606
607func save_map(file_name):
608    var temp_data = {
609        'tiles' : self.get_map_data_as_array(),
610        'theme' : self.theme
611    }
612
613    file_name = str(file_name)
614
615    if self.check_file_name(file_name):
616        self.store_map_in_binary_file(file_name, temp_data)
617        self.store_map_in_plain_file(file_name, temp_data)
618        return true
619    else:
620        return false
621
622func store_map_in_binary_file(file_name, data):
623    var file_path = "user://" + file_name + ".map"
624    map_file.write(file_path, data)
625    if file_name != "restore_map":
626        self.root.bag.map_list.store_map(file_name)
627        self.root.bag.controllers.menu_controller.update_custom_maps_count_label()
628
629func store_map_in_plain_file(file_name, data):
630    var file_path = "user://" + file_name + ".gd"
631    map_file.write_as_plain_file(file_path, data)
632
633func check_file_name(name):
634    # we need to check here for unusual charracters
635    # and trim spaces, convert to lower case etc
636    # allowed: [a-z] and "-"
637    # and can not name 'settings' !!!
638    if name == "" || name == "settings":
639        return false
640
641    var validator = RegEx.new()
642    validator.compile("^([a-zA-Z0-9-_]*)$")
643    validator.find(name)
644    var matches = validator.get_captures()
645
646    if matches[1] != name:
647        return false
648
649    return true
650
651func load_map(file_name, is_remote = false, switch_tileset=true):
652    if self.map_file.load_data_from_file(file_name, is_remote):
653        if switch_tileset:
654            self.switch_to_tileset(self.map_file.get_theme())
655        self.fill_map_from_data_array(self.map_file.get_tiles())
656        self.theme = self.map_file.get_theme()
657        # TODO [waypoints] - add building waypoints
658        return true
659    return false
660
661func load_campaign_map(file_name):
662    var campaign_map = self.campaign.get_map_data(file_name)
663    self.fill_map_from_data_array(campaign_map.map_data)
664
665func fill_map_from_data_array(data):
666    var cell
667    self.init_nodes()
668    if not self.show_blueprint:
669        underground.clear()
670    terrain.clear()
671    units.clear()
672    for cell in data:
673        if cell.terrain > -1:
674            terrain.set_cell(cell.x, cell.y, cell.terrain)
675
676        if cell.unit > -1:
677            units.set_cell(cell.x, cell.y, cell.unit)
678    units.raise()
679
680func fill(width, height):
681    var offset_x = 0
682    var offset_y = 0
683
684    terrain.clear()
685    units.clear()
686    offset_x = (self.bag.abstract_map.MAP_MAX_X * 0.5) - (width * 0.5)
687    offset_y = (self.bag.abstract_map.MAP_MAX_Y * 0.5) - (height * 0.5)
688
689    for x in range(width):
690        for y in range(height):
691            terrain.set_cell(x+offset_x, y+offset_y, 0)
692
693func clear_layer(layer):
694    if layer == 0:
695        self.units.clear()
696        self.terrain.clear()
697    if layer == 1:
698        self.units.clear()
699
700func init_background():
701    for x in range(self.bag.abstract_map.MAP_MAX_X):
702        for y in range(self.bag.abstract_map.MAP_MAX_Y):
703            self.underground.set_cell(x,y,3)
704
705func init_nodes():
706    self.underground = self.get_node("underground")
707    self.terrain = self.get_node("terrain")
708    self.units = terrain.get_node("units")
709    self.map_layer_back = terrain.get_node("back")
710    self.map_layer_front = terrain.get_node("front")
711    self.action_layer = terrain.get_node("actions")
712
713func _ready():
714    root = get_node("/root/game")
715    self.init_nodes()
716    self.bag = self.root.bag
717    self.bag.fog_controller.init_node(self, terrain)
718    self.camera = self.bag.camera
719    self.tileset = self.bag.map_tiles
720
721    if root:
722        scale = self.camera.get_scale()
723    else:
724        self.set_default_zoom()
725    pos = terrain.get_pos()
726
727    self.shake_timer.set_wait_time(shake_time / shakes_max)
728    self.shake_timer.set_one_shot(true)
729    self.shake_timer.set_autostart(false)
730    self.shake_timer.connect('timeout', self, 'do_single_shake')
731    self.add_child(shake_timer)
732
733    # where the magic happens
734    if show_blueprint:
735        self.init_background()
736    else:
737        self.generate_map()
738
739    set_process_input(true)
740
741func shake_camera():
742    if root.settings['shake_enabled'] and not mouse_dragging:
743        self.shakes = 0
744        shake_initial_position = terrain.get_pos()
745        self.do_single_shake()
746
747func do_single_shake():
748    var target
749    if shakes < shakes_max:
750        var direction_x = randf()
751        var direction_y = randf()
752        var distance_x = randi() % shake_boundary
753        var distance_y = randi() % shake_boundary
754        if direction_x <= 0.5:
755            distance_x = -distance_x
756        if direction_y <= 0.5:
757            distance_y = -distance_y
758
759        pos = Vector2(shake_initial_position) + Vector2(distance_x, distance_y)
760        target = pos
761        underground.set_pos(pos)
762        terrain.set_pos(pos)
763        self.shakes += 1
764        self.shake_timer.start()
765    else:
766        pos = shake_initial_position
767        target = pos
768        self.underground.set_pos(shake_initial_position)
769        self.terrain.set_pos(shake_initial_position)
770
771func switch_to_tileset(tileset):
772    self.get_node('terrain').set_tileset(self.bag.tileset_handler.available_tilesets[tileset])
773    self.map_movable = self.bag.tileset_handler.available_objects[tileset]['movable']
774    self.map_non_movable = self.bag.tileset_handler.available_objects[tileset]['non-movable']
775    self.map_city_small = self.bag.tileset_handler.available_city[tileset]['small']
776    self.map_city_big = self.bag.tileset_handler.available_city[tileset]['large']
777    self.map_statue = self.bag.tileset_handler.available_city[tileset]['statue']
778
779func _init_bag(bag):
780    self.bag = bag
781    self.campaign = bag.campaign
782
783