Skip to content

Commit

Permalink
Merge pull request #89 from neph1/update-v0.33.0
Browse files Browse the repository at this point in the history
Update v0.33.0
  • Loading branch information
neph1 authored Aug 1, 2024
2 parents 6c8a354 + 58445de commit f48995c
Show file tree
Hide file tree
Showing 14 changed files with 352 additions and 15 deletions.
2 changes: 1 addition & 1 deletion llm_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ CHARACTER_TEMPLATE: '{"name":"", "description": "50 words", "appearance": "25 wo
FOLLOW_TEMPLATE: '{{"response":"yes or no", "reason":"50 words"}}'
ITEM_TYPES: ["Weapon", "Wearable", "Health", "Money", "Trash", "Food", "Drink", "Key"]
PRE_PROMPT: 'You are a creative game keeper for a role playing game (RPG). You craft detailed worlds and interesting characters with unique and deep personalities for the player to interact with. Do not acknowledge the task or speak directly to the user, just perform it.'
BASE_PROMPT: '<context>{context}</context>\n[USER_START]Rewrite [{input_text}] in your own words using the information found inside the <context> tags to create a background for your text. Use about {max_words} words.'
BASE_PROMPT: '<context>{context}</context>\n[USER_START] Rewrite [{input_text}] in your own words. The information inside the <context> tags should be used to ensure it fits the story. Use about {max_words} words.'
DIALOGUE_PROMPT: '<context>{context}</context>\nThe following is a conversation between {character1} and {character2}; {character2}s sentiment towards {character1}: {sentiment}. Write a single response as {character2} in third person pov, using {character2} description and other information found inside the <context> tags. If {character2} has a quest active, they will discuss it based on its status. Respond in JSON using this template: """{dialogue_template}""". [USER_START]Continue the following conversation as {character2}: {previous_conversation}'
COMBAT_PROMPT: '<context>{context}</context>\nThe following is a combat scene between {attackers} and {defenders} in {location}. [USER_START] Describe the following combat result in about 150 words in vivid language, using the characters weapons and their health status: 1.0 is highest, 0.0 is lowest. Combat Result: {input_text}'
PRE_JSON_PROMPT: 'Below is an instruction that describes a task, paired with an input that provides further context. Write a response in valid JSON format that appropriately completes the request.'
Expand Down
5 changes: 5 additions & 0 deletions stories/anything/story.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from tale import parse_utils
from tale.driver import Driver
from tale.json_story import JsonStory
from tale.magic import MagicType
from tale.main import run_from_cmdline
from tale.player import Player, PlayerConnection
from tale.charbuilder import PlayerNaming
Expand All @@ -33,6 +34,10 @@ def init_player(self, player: Player) -> None:
player.stats.set_weapon_skill(weapon_type=WeaponType.ONE_HANDED, value=random.randint(10, 30))
player.stats.set_weapon_skill(weapon_type=WeaponType.TWO_HANDED, value=random.randint(10, 30))
player.stats.set_weapon_skill(weapon_type=WeaponType.UNARMED, value=random.randint(20, 30))
player.stats.magic_skills[MagicType.HEAL] = 30
player.stats.magic_skills[MagicType.BOLT] = 30
player.stats.magic_skills[MagicType.DRAIN] = 30
player.stats.magic_skills[MagicType.REJUVENATE] = 30
pass

def create_account_dialog(self, playerconnection: PlayerConnection, playernaming: PlayerNaming) -> Generator:
Expand Down
5 changes: 5 additions & 0 deletions stories/dungeon/story.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from tale.dungeon.dungeon_generator import ItemPopulator, Layout, LayoutGenerator, MobPopulator
from tale.items.basic import Money
from tale.json_story import JsonStory
from tale.magic import MagicType
from tale.main import run_from_cmdline
from tale.npc_defs import RoamingMob
from tale.player import Player, PlayerConnection
Expand Down Expand Up @@ -44,6 +45,10 @@ def init_player(self, player: Player) -> None:
player.stats.set_weapon_skill(weapon_type=WeaponType.ONE_HANDED, value=random.randint(10, 30))
player.stats.set_weapon_skill(weapon_type=WeaponType.TWO_HANDED, value=random.randint(10, 30))
player.stats.set_weapon_skill(weapon_type=WeaponType.UNARMED, value=random.randint(20, 30))
player.stats.magic_skills[MagicType.HEAL] = 30
player.stats.magic_skills[MagicType.BOLT] = 30
player.stats.magic_skills[MagicType.DRAIN] = 30
player.stats.magic_skills[MagicType.REJUVENATE] = 30
pass

def create_account_dialog(self, playerconnection: PlayerConnection, playernaming: PlayerNaming) -> Generator:
Expand Down
3 changes: 3 additions & 0 deletions stories/prancingllama/story.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

import tale
from tale.base import Location
from tale.cmds import spells
from tale.driver import Driver
from tale.llm.llm_ext import DynamicStory
from tale.magic import MagicType
from tale.main import run_from_cmdline
from tale.player import Player, PlayerConnection
from tale.charbuilder import PlayerNaming
Expand Down Expand Up @@ -55,6 +57,7 @@ def init_player(self, player: Player) -> None:
player.stats.set_weapon_skill(weapon_type=WeaponType.ONE_HANDED, value=25)
player.stats.set_weapon_skill(weapon_type=WeaponType.TWO_HANDED, value=15)
player.stats.set_weapon_skill(weapon_type=WeaponType.UNARMED, value=35)
player.stats.magic_skills[MagicType.HEAL] = 50

def create_account_dialog(self, playerconnection: PlayerConnection, playernaming: PlayerNaming) -> Generator:
"""
Expand Down
4 changes: 1 addition & 3 deletions stories/prancingllama/zones/prancingllama.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import random

from tale.base import Location, Item, Exit, Door, Key, Living, ParseResult, Weapon
from tale.base import Location, Item, Exit, Weapon
from tale.errors import StoryCompleted
from tale.items.basic import Note
from tale.lang import capital
from tale.player import Player
from tale.util import Context, call_periodically
from tale.verbdefs import AGGRESSIVE_VERBS
from tale.verbdefs import VERBS
Expand Down
3 changes: 3 additions & 0 deletions tale/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,11 @@ def _create_database(self) -> None:
strength integer NOT NULL,
dexterity integer NOT NULL,
weapon_skills varchar NOT NULL,
magic_skills varchar NOT NULL,
combat_points integer NOT NULL,
max_combat_points integer NOT NULL,
magic_points integer NOT NULL,
max_magic_points integer NOT NULL,
FOREIGN KEY(account) REFERENCES Account(id)
);
""")
Expand Down
12 changes: 12 additions & 0 deletions tale/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@

from tale.coord import Coord
from tale.llm.contexts.CombatContext import CombatContext
from tale.magic import MagicSkill, MagicType

from . import lang
from . import mud_context
Expand Down Expand Up @@ -975,8 +976,11 @@ def __init__(self) -> None:
self.dexterity = 3
self.unarmed_attack = Weapon(UnarmedAttack.FISTS.name, weapon_type=WeaponType.UNARMED)
self.weapon_skills = {} # type: Dict[WeaponType, int] # weapon type -> skill level
self.magic_skills = {} # type: Dict[MagicType, MagicSkill]
self.combat_points = 0 # combat points
self.max_combat_points = 5 # max combat points
self.max_magic_points = 5 # max magic points
self.magic_points = 0 # magic points

def __repr__(self):
return "<Stats: %s>" % self.__dict__
Expand Down Expand Up @@ -1025,6 +1029,14 @@ def replenish_combat_points(self, amount: int = None) -> None:
if self.combat_points > self.max_combat_points:
self.combat_points = self.max_combat_points

def replenish_magic_points(self, amount: int = None) -> None:
if amount:
self.magic_points += amount
else:
self.magic_points = self.max_magic_points
if self.magic_points > self.max_magic_points:
self.magic_points = self.max_magic_points

class Living(MudObject):
"""
A living entity in the mud world (also known as an NPC).
Expand Down
141 changes: 141 additions & 0 deletions tale/cmds/spells.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@

import random
from typing import Optional
from tale import base, util, cmds
from tale import magic
from tale.cmds import cmd
from tale.errors import ActionRefused, ParseError
from tale.magic import MagicType, MagicSkill, Spell
from tale.player import Player


@cmd("heal")
def do_heal(player: Player, parsed: base.ParseResult, ctx: util.Context) -> None:
""" Heal someone or something """

skillValue = player.stats.magic_skills.get(MagicType.HEAL, None)
if not skillValue:
raise ActionRefused("You don't know how to heal")
spell = magic.spells[MagicType.HEAL] # type: Spell

num_args = len(parsed.args)

level = player.stats.level
if num_args == 2:
level = int(parsed.args[1])

if not spell.check_cost(player.stats.magic_points, level):
raise ActionRefused("You don't have enough magic points")

if num_args < 1:
raise ParseError("You need to specify who or what to heal")
try:
entity = str(parsed.args[0])
except ValueError as x:
raise ActionRefused(str(x))

result = player.location.search_living(entity) # type: Optional[base.Living]
if not result or not isinstance(result, base.Living):
raise ActionRefused("Can't heal that")


player.stats.magic_points -= spell.base_cost * level

if random.randint(1, 100) > skillValue:
player.tell("Your healing spell fizzles out", evoke=True, short_len=True)
return

result.stats.replenish_hp(5 * level)
player.tell("You cast a healing spell that heals %s for %d hit points" % (result.name, 5 * level), evoke=True)
player.tell_others("%s casts a healing spell that heals %s" % (player.name, result.name), evoke=True)


@cmd("bolt")
def do_bolt(player: Player, parsed: base.ParseResult, ctx: util.Context) -> None:
""" Cast a bolt of energy """

skillValue = player.stats.magic_skills.get(MagicType.BOLT, None)
if not skillValue:
raise ActionRefused("You don't know how to cast a bolt")

spell = magic.spells[MagicType.BOLT] # type: Spell

num_args = len(parsed.args)

level = player.stats.level
if num_args == 2:
level = int(parsed.args[1])

if not spell.check_cost(player.stats.magic_points, level):
raise ActionRefused("You don't have enough magic points")

if num_args < 1:
raise ParseError("You need to specify who or what to attack")

try:
entity = str(parsed.args[0])
except ValueError as x:
raise ActionRefused(str(x))

result = player.location.search_living(entity) # type: Optional[base.Living]
if not result or not isinstance(result, base.Living):
raise ActionRefused("Can't attack that")

player.stats.magic_points -= spell.base_cost * level

if random.randint(1, 100) > skillValue:
player.tell("Your bolt spell fizzles out", evoke=True, short_len=True)
return

hp = random.randint(1, level)
result.stats.hp -= hp
player.tell("You cast an energy bolt that hits %s for %d damage" % (result.name, hp), evoke=True)
player.tell_others("%s casts an energy bolt that hits %s for %d damage" % (player.name, result.name, hp), evoke=True)

@cmd("drain")
def do_drain(player: Player, parsed: base.ParseResult, ctx: util.Context) -> None:
""" Drain energy from someone or something """

skillValue = player.stats.magic_skills.get(MagicType.DRAIN, None)
if not skillValue:
raise ActionRefused("You don't know how to drain")

spell = magic.spells[MagicType.DRAIN] # type: Spell

num_args = len(parsed.args)

level = player.stats.level
if num_args == 2:
level = int(parsed.args[1])

if not spell.check_cost(player.stats.magic_points, level):
raise ActionRefused("You don't have enough magic points")

if num_args < 1:
raise ParseError("You need to specify who or what to drain")

try:
entity = str(parsed.args[0])
except ValueError as x:
raise ActionRefused(str(x))

result = player.location.search_living(entity) # type: Optional[base.Living]
if not result or not isinstance(result, base.Living):
raise ActionRefused("Can't drain that")

player.stats.magic_points -= spell.base_cost * level

if random.randint(1, 100) > skillValue:
player.tell("Your drain spell fizzles out", evoke=True, short_len=True)
return

points = random.randint(1, level)
result.stats.combat_points -= points
result.stats.magic_points -= points

player.stats.magic_points += points

player.tell("You cast a 'drain' spell that drains %s of %d combat and magic points" % (result.name, points), evoke=True)
player.tell_others("%s casts a 'drain' spell that drains energy from %s" % (player.name, result.name), evoke=True)


5 changes: 3 additions & 2 deletions tale/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -961,8 +961,9 @@ def build_location(self, targetLocation: base.Location, zone: Zone, player: play
def do_on_player_death(self, player: player.Player) -> None:
pass

@util.call_periodically(10)
@util.call_periodically(20)
def replenish(self):
for player in self.all_players.values():
player.player.stats.replenish_hp(1)
player.player.stats.replenish_combat_points(1)
player.player.stats.replenish_combat_points(1)
player.player.stats.replenish_magic_points(1)
2 changes: 0 additions & 2 deletions tale/items/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,6 @@ def init(self) -> None:
def consume(self, actor: 'Living'):
if self not in actor.inventory:
raise ActionRefused("You don't have that.")
actor.stats.hp += self.affect_thirst
actor.tell("You drink the %s." % (self.title), evoke=True, short_len=True)
actor.tell_others("{Actor} drinks the %s." % (self.title))
self.destroy(util.Context.from_global())
Expand All @@ -243,7 +242,6 @@ def init(self) -> None:
def consume(self, actor: 'Living'):
if self not in actor.inventory:
raise ActionRefused("You don't have that.")
actor.stats.hp += self.affect_fullness
actor.tell("You eat the %s." % (self.title), evoke=True, short_len=True)
actor.tell_others("{Actor} eats the %s." % (self.title))
self.destroy(util.Context.from_global())
Expand Down
32 changes: 32 additions & 0 deletions tale/magic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from abc import ABC
from enum import Enum


class MagicType(Enum):
HEAL = 1
BOLT = 2
DRAIN = 3
REJUVENATE = 4



class Spell(ABC):
def __init__(self, name: str, base_cost: int, base_value: int = 1, max_level: int = -1):
self.name = name
self.base_value = base_value
self.base_cost = base_cost
self.max_level = max_level

def check_cost(self, magic_points: int, level: int) -> bool:
return magic_points >= self.base_cost * level

spells = {
MagicType.HEAL: Spell('heal', base_cost=2, base_value=5),
MagicType.BOLT: Spell('bolt', base_cost=3, base_value=5),
MagicType.DRAIN: Spell('drain', base_cost=3, base_value=5)
}

class MagicSkill:
def __init__(self, spell: Spell, skill: int = 0):
self.spell = spell
self.skill = skill
5 changes: 1 addition & 4 deletions tale/npc_defs.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,9 @@ def do_idle_action(self, ctx: Context) -> None:
if player_in_location and self.aggressive and not self.attacking:
for liv in self.location.livings:
if isinstance(liv, Player):
self.do_attack(liv)
self.start_attack(defender=liv)
elif player_in_location or self.location.get_wiretap() or self.get_wiretap():
self.idle_action()

def do_attack(self, target: Living) -> None:
self.start_attack(defender=target)

class RoamingMob(StationaryMob):

Expand Down
14 changes: 11 additions & 3 deletions tale/parse_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from tale.item_spawner import ItemSpawner
from tale.items.basic import Boxlike, Drink, Food, Health, Money, Note
from tale.llm.LivingNpc import LivingNpc
from tale.magic import MagicType
from tale.npc_defs import StationaryMob, StationaryNpc
from tale.races import BodyType, UnarmedAttack
from tale.mob_spawner import MobSpawner
Expand Down Expand Up @@ -160,7 +161,7 @@ def load_npcs(json_npcs: list, locations = {}) -> dict:
npcs[name] = new_npc
return npcs

def load_npc(npc: dict, name: str = None, npc_type: str = 'Mob'):
def load_npc(npc: dict, name: str = None, npc_type: str = 'Mob', roaming = False):
race = None
if npc.get('stats', None):
race = npc['stats'].get('race', None)
Expand Down Expand Up @@ -641,7 +642,8 @@ def save_stats(stats: Stats) -> dict:
json_stats['hp'] = stats.hp
json_stats['max_hp'] = stats.max_hp
json_stats['level'] = stats.level
json_stats['weapon_skills'] = save_weaponskills(stats.weapon_skills)
json_stats['weapon_skills'] = skills_dict_to_json(stats.weapon_skills)
json_stats['magic_skills'] = skills_dict_to_json(stats.magic_skills)
json_stats['gender'] = stats.gender = 'n'
json_stats['alignment'] = stats.alignment
json_stats['weight'] = stats.weight
Expand Down Expand Up @@ -679,6 +681,12 @@ def load_stats(json_stats: dict) -> Stats:
for skill in json_skills.keys():
int_skill = int(skill)
stats.weapon_skills[WeaponType(int_skill)] = json_skills[skill]
if json_stats.get('magic_skills'):
json_skills = json_stats['magic_skills']
stats.magic_skills = {}
for skill in json_skills.keys():
int_skill = int(skill)
stats.magic_skills[MagicType(int_skill)] = json_skills[skill]
return stats

def save_items(items: List[Item]) -> dict:
Expand Down Expand Up @@ -715,7 +723,7 @@ def save_locations(locations: List[Location]) -> dict:
json_locations.append(json_location)
return json_locations

def save_weaponskills(weaponskills: dict) -> dict:
def skills_dict_to_json(weaponskills: dict) -> dict:
json_skills = {}
for skill in weaponskills.keys():
json_skills[skill.value] = weaponskills[skill]
Expand Down
Loading

0 comments on commit f48995c

Please sign in to comment.