Skip to content

Commit

Permalink
Merge pull request #158 from esoviscode/attack-rework
Browse files Browse the repository at this point in the history
Attack mode only during attack event
  • Loading branch information
gitesthuman authored Mar 16, 2023
2 parents db3cea8 + e92d972 commit beb393d
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 88 deletions.
2 changes: 1 addition & 1 deletion dnd-bot/dnd_bot/dc/cogs/command_shutdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ async def shutdown(self, interaction):
print("\nDeleting old images...")
tmp_img_path = 'dnd_bot/assets/tmp/game_images'
for filename in os.listdir(tmp_img_path):
if filename.startswith('pov'):
if filename.startswith('pov') or filename.startswith('map'):
os.remove('%s/%s' % (tmp_img_path, filename))

await self.bot.close()
Expand Down
23 changes: 16 additions & 7 deletions dnd-bot/dnd_bot/dc/ui/views/view_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ async def send_view(user):
view_to_show = player_current_view(game_token, user.discord_id)

player = game.get_player_by_id_user(user.discord_id)
player_view = get_player_view(Multiverse.get_game(game_token), player)
player_view = get_player_view(Multiverse.get_game(game_token), player, player.attack_mode)
turn_view_embed = await MessageTemplates.creature_turn_embed(game_token, user.discord_id,
recent_action=recent_action_message)
await Messager.edit_last_user_message(user.discord_id, embeds=[turn_view_embed] + player_current_embeds,
Expand All @@ -61,14 +61,18 @@ async def send_view(user):
await asyncio.gather(*tasks)
await q.join()

async def cancel(self, interaction: nextcord.Interaction):
async def cancel(self, interaction: nextcord.Interaction, files=None):
"""button for moving back to main menu"""

turn_view_embed = await MessageTemplates.creature_turn_embed(self.token, interaction.user.id)

self.game.players_views[self.user_discord_id] = (ViewMain, [])
await Messager.edit_last_user_message(user_id=interaction.user.id, embed=turn_view_embed,
view=ViewMain(self.token, interaction.user.id))
if files:
await Messager.edit_last_user_message(user_id=interaction.user.id, embed=turn_view_embed,
view=ViewMain(self.token, interaction.user.id), files=files)
else:
await Messager.edit_last_user_message(user_id=interaction.user.id, embed=turn_view_embed,
view=ViewMain(self.token, interaction.user.id))

async def character_view_options(self, interaction: nextcord.Interaction):
"""shared handler for character view"""
Expand Down Expand Up @@ -131,15 +135,18 @@ class ViewMain(ViewGame):
async def attack(self, button: nextcord.ui.Button, interaction: nextcord.Interaction):
"""button for opening attack menu"""
game = Multiverse.get_game(self.token)
player = game.get_player_by_id_user(interaction.user.id)
player.attack_mode = True

# TODO adding enemies in players range to the list
enemies = game.get_attackable_enemies_for_player(game.get_player_by_id_user(interaction.user.id))
enemies = game.get_attackable_enemies_for_player(player)

turn_view_embed = await MessageTemplates.creature_turn_embed(self.token, interaction.user.id)
self.game.players_views[self.user_discord_id] = (ViewAttack, [])
await Messager.edit_last_user_message(user_id=interaction.user.id,
embeds=[turn_view_embed],
view=ViewAttack(self.token, self.user_discord_id))
view=ViewAttack(self.token, self.user_discord_id),
files=[get_player_view(game, player, True)])

@nextcord.ui.button(label='Move', style=nextcord.ButtonStyle.blurple)
async def move(self, button: nextcord.ui.Button, interaction: nextcord.Interaction):
Expand Down Expand Up @@ -285,7 +292,9 @@ async def attack_button(self, interaction: nextcord.Interaction):
interaction.user.id, self.token, interaction)

async def cancel(self, interaction: nextcord.Interaction):
await super().cancel(interaction)
player = self.game.get_player_by_id_user(interaction.user.id)
player.attack_mode = False
await super().cancel(interaction, [get_player_view(self.game, player)])

@staticmethod
async def attack(target_id, id_user, token, interaction: nextcord.Interaction):
Expand Down
42 changes: 1 addition & 41 deletions dnd-bot/dnd_bot/logic/prototype/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,47 +126,7 @@ def get_attackable_enemies_for_player(self, player):
if weapon is None:
return result

def find_position_to_check(x_src=0, y_src=0, x_dest=1, y_dest=1):
result = []

def find_positions(x1, y1, x2, y2, dx, dy, decide):
pk = 2 * dy - dx
for i in range(0, dx + 1):
if decide == 0:
result.append((x1, y1))
else:
result.append((y1, x1))

if x1 < x2:
x1 = x1 + 1
else:
x1 = x1 - 1
if pk < 0:

if decide == 0:
pk = pk + 2 * dy
else:
pk = pk + 2 * dy
else:
if y1 < y2:
y1 = y1 + 1
else:
y1 = y1 - 1

pk = pk + 2 * dy - 2 * dx

dx = abs(x_dest - x_src)
dy = abs(y_dest - y_src)

# If slope is less than one
if dx > dy:
find_positions(x_src, y_src, x_dest, y_dest, dx, dy, 0)
# if slope is greater than or equal to 1
else:
find_positions(y_src, x_src, y_dest, x_dest, dy, dx, 1)

return result[1:-1]

from dnd_bot.logic.utils.utils import find_position_to_check
attack_range = min(weapon.use_range, player.perception)
for creature in creatures:
if not isinstance(creature, Player):
Expand Down
1 change: 1 addition & 0 deletions dnd-bot/dnd_bot/logic/prototype/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def __init__(self, entity_id=0, x=0, y=0, name: str = 'Player',
self.character_class = character_class
self.equipment = equipment
self.active = False
self.attack_mode = False

def get_sprite_path_by_color(self, color: str):
import os
Expand Down
159 changes: 120 additions & 39 deletions dnd-bot/dnd_bot/logic/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,48 @@ def belongs_to_circle(x, y):
return points


def find_position_to_check(x_src=0, y_src=0, x_dest=1, y_dest=1):
result = []

def find_positions(x1, y1, x2, y2, dx, dy, decide):
pk = 2 * dy - dx
for i in range(0, dx + 1):
if decide == 0:
result.append((x1, y1))
else:
result.append((y1, x1))

if x1 < x2:
x1 = x1 + 1
else:
x1 = x1 - 1
if pk < 0:

if decide == 0:
pk = pk + 2 * dy
else:
pk = pk + 2 * dy
else:
if y1 < y2:
y1 = y1 + 1
else:
y1 = y1 - 1

pk = pk + 2 * dy - 2 * dx

dx = abs(x_dest - x_src)
dy = abs(y_dest - y_src)

# If slope is less than one
if dx > dy:
find_positions(x_src, y_src, x_dest, y_dest, dx, dy, 0)
# if slope is greater than or equal to 1
else:
find_positions(y_src, x_src, y_dest, x_dest, dy, dx, 1)

return result[1:-1]


def paste_image(src: np.ndarray, dest: np.ndarray, x_offset: int, y_offset: int):
"""
pastes src on dest with x,y offsets
Expand Down Expand Up @@ -83,11 +125,12 @@ def get_game_view(game: Game) -> str:
return file_name


def get_player_view(game: Game, player: Player):
def get_player_view(game: Game, player: Player, attack_mode=False):
"""
generates image and returns its path
:param game: game object
:param player: player
:param attack_mode: if to paste grid, coords, and attackable tiles
:return filename: path to game view image with player's POV
"""
player_view = copy.deepcopy(game.sprite)
Expand All @@ -97,11 +140,11 @@ def get_player_view(game: Game, player: Player):
entities = [e for e in sum(game.entities, []) if e and e.fragile
and (e.x - player.x, e.y - player.y) in points_in_range]

for entity in entities:
sprite = copy.deepcopy(entity.sprite)
sprite = rotate_image_to_direction(sprite, entity.look_direction)

paste_image(sprite, player_view, entity.x * Mv.square_size, entity.y * Mv.square_size)
# for entity in entities:
# sprite = copy.deepcopy(entity.sprite)
# sprite = rotate_image_to_direction(sprite, entity.look_direction)
#
# paste_image(sprite, player_view, entity.x * Mv.square_size, entity.y * Mv.square_size)

# cropping image
from_y = max(0, player.y - Mv.view_range)
Expand All @@ -122,39 +165,77 @@ def get_player_view(game: Game, player: Player):
player_view = cv.bitwise_and(player_view, player_view, mask=mask)

# pasting coordinates and grid
number_width = 10
number_height = 13
number_space = 1
width = to_x - from_x + 1
height = to_y - from_y + 1

def length(num):
return len(str(num)) * number_width + (len(str(num)) + 1) * number_space

padding_top = 10 + number_height
padding_left = 10 + length(height)
square = 50
line_color = (110, 110, 110)

coords = np.zeros((player_view.shape[0] + padding_top, player_view.shape[1] + padding_left, player_view.shape[2]),
player_view.dtype)
lines = coords.copy()
coords[padding_top:, padding_left:, :] = player_view[:, :, :]

for i in range(width + 1):
cv.line(lines, (padding_left + i * square - 1, padding_top), (padding_left + i * square - 1, coords.shape[0]),
line_color, 1)
cv.putText(img=coords, text=str(from_x + i),
org=(padding_left + i * square + (square - length(from_x + i)) // 2, padding_top - 6),
fontFace=cv.FONT_HERSHEY_TRIPLEX, fontScale=0.55, color=(200, 200, 200), thickness=1)
for i in range(height + 1):
cv.line(lines, (padding_left, padding_top + i * square - 1), (coords.shape[1], padding_top + i * square - 1),
line_color, 1)
cv.putText(img=coords, text=str(from_y + i),
org=(padding_left - length(from_y + i) - 5, padding_top + ((i + 1) * square - 19)),
fontFace=cv.FONT_HERSHEY_TRIPLEX, fontScale=0.55, color=(200, 200, 200), thickness=1)

player_view = cv.addWeighted(lines, .6, coords, 1.0, 0)
if attack_mode:
attackable = []
attack_range = min(player.equipment.right_hand.use_range, player.perception)
from dnd_bot.logic.prototype.creature import Creature
for p in generate_circle_points(attack_range, attack_range):
x = player.x + p[0]
y = player.y + p[1]
if x < 0 or x >= game.world_width or y < 0 or y >= game.world_height:
continue
if (not game.entities[y][x]) or \
(isinstance(game.entities[y][x], Creature) and not isinstance(game.entities[y][x], Player)):
path = find_position_to_check(player.x, player.y, player.x + p[0], player.y + p[1])
add = True
for pos in path:
if game.entities[pos[1]][pos[0]]:
add = False
break
if add:
attackable.append((x, y))

number_width = 10
number_height = 13
number_space = 1
width = to_x - from_x + 1
height = to_y - from_y + 1

def length(num):
return len(str(num)) * number_width + (len(str(num)) + 1) * number_space

padding_top = 10 + number_height
padding_left = 10 + length(height)
square = 50
line_color = (110, 110, 110)
attack_color = (0, 0, 50)

coords = np.zeros((player_view.shape[0] + padding_top, player_view.shape[1] + padding_left, player_view.shape[2]),
player_view.dtype)
lines = coords.copy()
tiles = coords.copy()
coords[padding_top:, padding_left:, :] = player_view[:, :, :]

for p in attackable:
cv.rectangle(tiles, (padding_left + (p[0] - from_x) * square, padding_top + (p[1] - from_y) * square),
(padding_left + (p[0] - from_x + 1) * square - 1,
padding_top + (p[1] - from_y + 1) * square - 1), attack_color, -1)

for i in range(width + 1):
cv.line(lines, (padding_left + i * square - 1, padding_top),
(padding_left + i * square - 1, coords.shape[0]), line_color, 1)
cv.putText(img=coords, text=str(from_x + i),
org=(padding_left + i * square + (square - length(from_x + i)) // 2, padding_top - 6),
fontFace=cv.FONT_HERSHEY_TRIPLEX, fontScale=0.55, color=(200, 200, 200), thickness=1)
for i in range(height + 1):
cv.line(lines, (padding_left, padding_top + i * square - 1),
(coords.shape[1], padding_top + i * square - 1), line_color, 1)
cv.putText(img=coords, text=str(from_y + i),
org=(padding_left - length(from_y + i) - 5, padding_top + ((i + 1) * square - 19)),
fontFace=cv.FONT_HERSHEY_TRIPLEX, fontScale=0.55, color=(200, 200, 200), thickness=1)

player_view = cv.addWeighted(tiles, .4, coords, 1.0, 0)
player_view = cv.addWeighted(lines, .6, player_view, 1.0, 0)

for entity in entities:
sprite = copy.deepcopy(entity.sprite)
sprite = rotate_image_to_direction(sprite, entity.look_direction)

if attack_mode:
paste_image(sprite, player_view, padding_left + (entity.x - from_x) * Mv.square_size,
padding_top + (entity.y - from_y) * Mv.square_size)
else:
paste_image(sprite, player_view, (entity.x - from_x) * Mv.square_size, (entity.y - from_y) * Mv.square_size)

# saving view
file_name = "%s/game_images/pov%s_%s.png" % (TMP_IMAGES_PATH, game.token, player.discord_identity)
Expand Down

0 comments on commit beb393d

Please sign in to comment.