import google.generativeai as genai from google.api_core import retry import os import pathlib import textwrap import json GOOGLE_API_KEY = os.environ['GOOGLE_API_KEY'] genai.configure(api_key=GOOGLE_API_KEY) model = genai.GenerativeModel(model_name='models/gemini-1.5-pro-latest') def generate_story(available_items): response = model.generate_content(f""" You are game master in a roguelike game. You should help me create an consise objective for the player to fulfill in the current level. Our protagonist, A girl with a red hood is wandering inside a dungeon. You are ONLY allowed to only use the following elements and not modify either the map or the enemies: {available_items} Example of possible Objectives: Example 1 : Defeat N monster $monster_name and then report it to npc :$npc_name Example 2 : Loot two treasure chest then defeat the boss $boss_name to exit. A object of type NPC can be talked to but can't move and can't be fought, an ennemy type object can be fought but not talked to. A boss can be fought but not talked to To escape, the player will have to pass by the portal. """, request_options={'retry': retry.Retry()}) story = response.text return story def place_objects(available_items,story,myMap): prompt = f""" Please return JSON describing the objective of this level, the objects that should be placed as well as all enemies/npcs that shall be placed: {{"objective": str, "objects":list[OBJECT], "enemies":list[ENEMIES], "boss":list[BOSS],"npcs": list[NPC]}} In all of the following example, placement is the id of the room to place the object in. # The Objects that should be placed in the treasure chests OBJECT = {{"name": str, "description": str,"placement": int, "strength": str, "speed": str}} # The infos necessary about the enemies ENEMIES = {{"name": str, "placement": int}} # The NPC that should be added to the map NPC = {{"name": str, "persona": str, "placement": int}} # The Boss monster of this level. BOSS = {{"name": str, "placement": int}} For objects, the name key represents the name of the object inside the treasure chest when placement is requiered, it is the id of the room on the map. All fields are not necessarily required; if null, don't add it. it should make sense with the crafted story. Items can only be weapons or objects that can be useful for a special quest. "strength" and "speed" should only be declared for weapons and can only range between 0 and 1. 0 being a rusty sword and 1 being the best sword in the game. Important: Only return a single piece of valid JSON text. Here is the map: {myMap} X: is the starting position of the player ?: represent and interesting room where it could be interesting to place an object numbers represent the index of the room and the objective of this level: {story} The objective MUST be feasible, otherwise the player will be stuck. REMEMBER, You are ONLY allowed to only use the following elements and not modify either the map or the enemies: {available_items} """ print(prompt) response = model.generate_content( prompt, generation_config={'response_mime_type':'application/json'} ) try: map_placements=json.dumps(json.loads(response.text), indent=4) except: map_placements="error" return map_placements def get_items_string_representation(items_list): result = "" for item in items_list: item_str = "Name: " + item["name"] + ", Type: " + item["type"] + ", Description: " + item["description"] + "\n" result += item_str return result def generate_map_markdown(rooms, room_of_interest,index_exit): import numpy as np # Define the room structure with walls and markers def create_room(room_char, index): index_str = f"{index}".zfill(2) # Zero pad index to 2 digits if needed if index_str[0] !="0": first_number=index_str[0] else: first_number=" " return [ f"╔═{room_char}═╗", f"║ {first_number}{index_str[1]}║", f"╚═══╝" ] # Extract rooms and rooms of interest rooms = [eval(room) for room in rooms] rooms_of_interest = [eval(room) for room in room_of_interest] # Determine grid size min_x = min(room[0] for room in rooms) max_x = max(room[0] for room in rooms) min_y = min(room[1] for room in rooms) max_y = max(room[1] for room in rooms) # Create grid with empty spaces represented by a room-like structure map_height = (max_y - min_y + 1) * 3 map_width = (max_x - min_x + 1) * 5 grid = np.full((map_height, map_width), " ") # Populate grid with rooms and their characteristics for i, room in enumerate(rooms): x, y = room x_offset = (x - min_x) * 5 y_offset = (max_y - y) * 3 if room == (0, 0): room_char = "X" elif room in rooms_of_interest: room_char = "P" if i == index_exit else "?" else: room_char = " " room_structure = create_room(room_char, i) for j, row in enumerate(room_structure): grid[y_offset + j, x_offset:x_offset + 5] = list(row) # Convert grid to a string format suitable for display markdown_map = "\n".join("".join(row) for row in grid) # Return the map wrapped in triple backticks for proper display in markdown return f"```\n{markdown_map}\n```"