def get_spawn_spaces(center, r, walking): # X range v1_min, v1_max = max(0, center[0] - r), min(game_vars.world_dim()[0] - 1, center[0] + r) # When calculating max, add 1 so that if we have only air but # there is a solid block just outside our range, we can still spawn # Y range v2_min, v2_max = max(0, center[1] - r), min(game_vars.world_dim()[1] - 1, center[1] + r + 1) air = {} # For all ranges, use max + 1 to be inclusive for v1 in range(v1_min, v1_max + 1): air_count = -1 v2 = 0 for v2 in reversed(range(v2_min, v2_max + 1)): block = game_vars.get_block_at(*(v1, v2) if walking else (v2, v1)) if block != AIR: if air_count > 0: # Coords of ground = current (solid) + 1 + air count update_dict(v1, v2 + 1 + air_count, air_count, air) air_count = 0 elif air_count != -1: air_count += 1 if air_count > 0: # Coord of ground = current (air) + air count update_dict(v1, v2 + air_count, air_count, air) return air
def spawn(self): spawn = game_vars.world.spawn self.set_pos((spawn[0] * BLOCK_W, spawn[1] * BLOCK_W)) for x in range(spawn[0], ceil(spawn[0] + self.dim[0])): for y in range(spawn[1], ceil(spawn[1] + self.dim[1])): if game_vars.get_block_at(x, y) not in game_vars.non_solid: self.break_block(x, y)
def right_click(self): pos = pg.mouse.get_pos() global_pos = game_vars.global_mouse_pos() if not self.inventory.right_click(pos): block_x, block_y = game_vars.get_topleft( *[p // BLOCK_W for p in global_pos]) tile = game_vars.tiles[game_vars.get_block_at(block_x, block_y)] # First attempt to activate the tile # Make sure we didn't click the same block more than once if tile.clickable and self.placement_range.collidepoint(*global_pos) and \ (not tile.has_ui or self.active_ui is None or self.active_ui.block_pos != [block_x, block_y]): if tile.activate((block_x, block_y)): return # Then try to drop the cursor item if self.inventory.selected_item.is_item: # Check if we dropped an item drop = self.inventory.drop_item() if drop is not None: # This determines if we clicked to the left or right of the player left = global_pos[0] < self.rect.centerx game_vars.drop_item(drop, left) # If there is no cursor item, use the current hotbar item else: item = self.inventory.get_current_item() if item.is_item: item_obj = game_vars.items[item.item_id] if item_obj.right_click and (self.first_swing or item_obj.auto_use): self.first_swing = False # Use item item_obj.on_right_click() self.item_used = item_obj self.use_time = item_obj.use_time
def on_right_click(self): item = game_vars.player_inventory().get_current_item() if item.item_id != i.MAGIC_WAND: return entities = game_vars.handler.entities # Check if we clicked on a mage pos = game_vars.global_mouse_pos(blocks=False) for key, entity in entities.items(): if isinstance(entity, Mobs.Mage) and entity.rect.collidepoint(pos): print("Selected mage") item.data = key.to_bytes(2, byteorder) entity.target = (-1, -1) return # Get the clicked on tile pos = game_vars.get_topleft(*game_vars.global_mouse_pos(blocks=True)) tile_id = game_vars.get_block_at(*pos) # Check if we clicked on a pedestal if item.data and tile_id == t.PEDESTAL: key = int.from_bytes(item.data[:2], byteorder) if isinstance(entities.get(key), Mobs.Mage): print("Bound mage") entities[key].set_target(pos) entities[key].set_pos(pos[0] * BLOCK_W, (pos[1] - entities[key].dim[1]) * BLOCK_W) item.data = None # Check if we clicked on a portal elif tile_id == t.PORTAL: game_vars.tiles[t.PORTAL].summon(pos)
def get_spawn_spaces_with_hole(center, r_inner, r_outer, walking): # X range v1_min, v1_max = max(0, center[0] - r_outer), min(game_vars.world_dim()[0], center[0] + r_outer) # Y bounds v2_min1, v2_max1 = max(0, center[1] - r_outer), max(0, center[1] - r_inner) v2_min2 = min(game_vars.world_dim()[1], center[1] + r_inner) v2_max2 = min(game_vars.world_dim()[1], center[1] + r_outer) v2_range_full = (range(v2_min1, v2_max2)) v2_range_parts = (range(v2_min1, v2_max1), range(v2_min2, v2_max2)) air = {} def add_val(v1_, v2_, val): if v1_ not in air.keys(): air[v1_] = {} air[v1_][v2_] = val for v1 in range(v1_min, v1_max): for v2_range in v2_range_full if abs(v1 - center[1]) <= r_inner else \ v2_range_parts: air_count = 0 hit_block = False v2 = 0 for v2 in v2_range: block = game_vars.get_block_at(*(v1, v2) if walking else (v2, v1)) if block != AIR: hit_block = True if air_count > 0: add_val(v1, v2 - air_count, air_count) air_count = 0 elif hit_block: air_count += 1 if air_count > 0: add_val(v1, v2 - air_count, air_count) return air
def on_left_click(self): pos = game_vars.get_topleft(*game_vars.global_mouse_pos(blocks=True)) item_id = game_vars.get_block_at(*pos) if item_id == t.PORTAL: data = game_vars.get_block_data(pos) if data: # TODO: ingame message system print("Magic Stored:", int.from_bytes(data, byteorder))
def get_space(self, x, y): tile_id = game_vars.get_block_at(x, y) if tile_id == t.PEDESTAL: data = game_vars.get_block_data((x, y)) if data and len(data) > 2: item = game_vars.items[int.from_bytes(data[:2], byteorder)] if isinstance(item, ItemTypes.MagicContainer): current_amnt = int.from_bytes(data[3:item.int_bytes + 3], byteorder) return item.capacity - current_amnt return 0
def ai(self): self.time -= game_vars.dt # Check if we are standing on the ground if self.collisions[1] == 1: too_far = self.bound and not self.drag and abs( self.rect.centerx - self.target[0] * BLOCK_W) >= self.MAX_DX # Check if we are ready to start/stop moving if self.time <= 0 or too_far: # We were stopped if self.drag: if self.bound: self.a[0] = math.copysign( self.stats.get_stat("acceleration"), self.target[0] * BLOCK_W - self.rect.centerx) else: self.a[0] = self.stats.get_stat( "acceleration") * random_sign() self.drag = False max_t = self.MAX_DX / self.stats.get_stat("max_speedx") self.time = uniform(max_t / 3, max_t * .9) # We were moving else: self.a[0] = 0 self.drag = True self.time = uniform(1, 3) # Check if we need to jump if self.collisions[0] != 0: self.v[1] = -self.stats.get_stat("jump_speed") self.time = uniform(1, 3) # Increment magic self.magic = min(self.capacity, self.magic + self.production * game_vars.dt) if self.magic >= 5 and self.bound and self.transfer_cooldown <= 0: x, y = game_vars.get_topleft(*self.target) tile_id = game_vars.get_block_at(x, y) if tile_id != tiles.PEDESTAL: self.target = (-1, -1) else: tile = game_vars.tiles[tile_id] transfer = min(self.production, self.magic, tile.get_space(x, y)) if transfer > 0: game_vars.shoot_projectile( self.P1(transfer, self.rect.center, (x, y))) self.transfer_cooldown = 1 elif self.transfer_cooldown > 0: self.transfer_cooldown -= game_vars.dt
def move(self): if super().move(): return True x, y = game_vars.get_topleft(*self.target) tile_id = game_vars.get_block_at(x, y) if tile_id != tiles.PEDESTAL: return True else: tile = game_vars.tiles[tile_id] rect = pg.Rect((x * BLOCK_W, y * BLOCK_W), [i * BLOCK_W for i in tile.dim]) if abs(self.rect.centerx - rect.centerx) < self.HIT_RAD and abs( self.rect.centery - rect.centery) < self.HIT_RAD: tile.add_magic(x, y, self.magic) return True return False
def break_block(self, block_x, block_y): # Make sure we aren't hitting air block_x, block_y = game_vars.get_topleft(block_x, block_y) block = game_vars.get_block_at(block_x, block_y) if block == AIR: return tile = game_vars.tiles[block] # Make sure this block does not have a ui open if self.active_ui is not None and self.active_ui.block_pos == [ block_x, block_y ]: return False # Make sure the block is in range and check if we destroyed the block power = self.stats.get_stat("power") block_rect = Rect(block_x * BLOCK_W, block_y * BLOCK_W, BLOCK_W * tile.dim[0], BLOCK_W * tile.dim[1]) if self.placement_range.collidepoint(*block_rect.center) and tile.hit( block_x, block_y, power): return game_vars.break_block(block_x, block_y) return False
def tick(self, dt): self.time = (self.time + dt) % c.SEC_PER_DAY # Run auto save self.next_save -= game_vars.dt if self.next_save <= 0: self.save_progress = self.save_world(self.save_progress) if self.save_progress >= 1: self.save_progress = 0 self.next_save = 30 game_vars.player.write() # Update minimap pos = game_vars.player_pos(True) left, top = max(int(pos[0] - 10), 0), max(int(pos[1] - 10), 0) # Go through every row, column pair where the color is black section = pg.surfarray.pixels2d(self.map)[left:math.ceil(pos[0] + 10), top:math.ceil(pos[1] + 10)] for x, y in zip(*np.where(section == 0)): map_color = game_vars.tiles[game_vars.get_block_at( left + x, top + y)].map_color section[x][y] = self.map.map_rgb(map_color) del section self.manager.tick(dt)