Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attack mode only during attack event #158

Merged
merged 3 commits into from
Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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