概要
今回は以前作成したRPG風テキストゲームにストーリー性を追加したものになります。
しらかみゅさん(@shiracamus)が僕の書いたコードを、大幅にクラスやインスタンスの概念などを改良したものから、さらに私がストーリーを軽く肉付けしたものになります。
ストーリー自体は王道…、というかベタなものです。
コード内容
duel_braver.py
import time
import sys
import random
import keyboard
from typing import Callable
class Point:
"""ヒットポイント、マジックポイントなどいろいろステータス"""
def __init__(self,point: int) -> None:
self._remain: int = point
self._max: int = point
def __str__(self) -> str:
"""表示文字列を返す"""
return str(self._remain)
def use(self, point:int) -> bool:
"""point分使えるならTrueを返す、ポイント不足ならFalseを返す"""
if self._remain < point:
return False
self.damage(point)
return True
def damage(self, point:int) -> None:
"""ダメージ分がHPから引かれる"""
self._remain -= point
def charge(self, point:int) -> None:
"""HP回復"""
self._remain=min(self._remain+point,self._max)
def is_full(self) -> bool:
"""HP上限突破を防ぐ"""
return self._remain == self._max
def is_empty(self) -> bool:
"""残りが0以下なら値を返す"""
return self._remain <= 0
class Power:
"""武器攻撃力のクラス"""
def __init__(self, minimum: int, maximum: int) -> None:
self._points: range = range(minimum, maximum + 1)
def use(self) -> int:
"""力を使う、ポイントを返す"""
return random.choice(self._points)
class Magic:
"""魔法攻撃のクラス"""
def __init__(self, name: str, point: int, power: Power) -> None:
self._name: str = name # プレイヤー名
self._point: int = point # 魔法を使用するのに必要なポイント
self._power: Power = power #攻撃
def __str__(self) -> str:
"""表示文字列を返す"""
return self._name
def use(self, mp: Point) -> int:
"""mpを消費して魔法を使う。攻撃ポイントを返す"""
if mp.use(self._point):
return self._power.use()
else:
return 0 # mp不足
class HealthPosion:
"""回復薬"""
def __init__(self,remain = 1,point = 100):
self._remain = remain
self._point = point
def remain(self):
return self._remain
def use(self,hp: Point):
"""ポーションがあるならhpを回復してTrueを返す、ないならFalseを返す"""
if self._remain <= 0:
return False
self._remain -= 1
hp.charge(self._point)
return True
class UpperPosion(HealthPosion):
def __init__(self,remain = 1,point = 200):
self._remain = remain
self._point = point
def remain(self):
return self._remain
def use(self,hp: Point):
"""ポーションがあるならhpを回復してTrueを返す、ないならFalseを返す"""
if self._remain <= 0:
return False
self._remain -= 1
hp.charge(self._point)
return True
class Character:
"""プレイヤーと敵モンスターのデータの源!"""
def __init__(self,name: str,health_point: int, magic_point: int,weapon:Power,shield:Power)->None:
"""キャラクターの雛型"""
self._name: str = name
self._hp:Point = Point(health_point)
self._mp:Point = Point(magic_point)
self._weapon:Power = weapon
self._shield:Power = shield
def __str__(self)->str:
"""表示文字列を返す"""
return str(self._name)
def _message(self,text: str,wait: int=1)->None:
"""キャラクタのメッセージ出力"""
print(f"{self}:{text}")
time.sleep(wait)
def status(self)->str:
"""ステータスを返す"""
return f"{self}のHP:{self._hp},MP:{self._mp}"
def defense(self,point: int)->int:
"""攻撃を防御する"""
return self._damage(point//2-self._shield.use()//4)
def _damage(self,point)->int:
"""ダメージ処理"""
self._hp.damage(point)
self._message(f"{point}のダメージ")
return point
def is_dead(self)->bool:
"""死亡していたらTrueを返す"""
return self._hp.is_empty()
class Weapon(Power):
def __init__(self,name,minimum,maximum):
self._name=name
super().__init__(minimum,maximum)
def __str__(self):
"""表示文字列を返す(武器名)"""
return self._name
#プレイヤーのクラス
class Player(Character):
def __init__(self,name: str,weapon)->None:
super().__init__(name,300,30,Power(0,0),Power(40,45))
self._weapon:Weapon=weapon
self._message(f'{weapon}で行く!')
self._is_guard: bool=False
self._health_posion: HealthPosion=HealthPosion(5)
self._upper_posion:UpperPosion=UpperPosion(2)
self._COMMANDS: dict[str,Callable[[Character],bool]]={
'a':self._use_weapon,
'm':self._use_magic,
's':self._use_strong_magic,
'g':self._guard,
'd':self._heal,
'h':self._upper_heal,
}
def status(self)->str:
return f"{super().status()},回復薬:{self._health_posion.remain()},回復薬(上):{self._upper_posion.remain()}"
#防御
def defense(self,point: int)->int:
"""防御する"""
if self._is_guard:
self._is_guard = False
if random.random() >= 0.1:
self._message("攻撃を弾いた!")
return 0
return super().defense(point)
def attack(self,monster: Character)->None:
"""攻撃する"""
print("-------------------------")
print("|a:攻撃 |m:攻撃魔法 |")
print("|g:防御 |s:強力攻撃魔法|")
print("|d:回復薬|h:回復薬(上)|")
print("-------------------------")
while((command := input("選択>>>"))not in self._COMMANDS or not self._COMMANDS[command](monster)):
pass
def _use_weapon(self,monster: Character)->bool:
"""武器を使って攻撃する"""
self._message(f"「このォ!」")
monster.defense(self._weapon.use())
return True
def _use_magic(self,monster: Character,magic: Magic = Magic("サンダーシュート",5,Power(125,130)))->bool:
"""魔法を使って攻撃する"""
point = magic.use(self._mp)
if point == 0:
self._message(f"「MPが足りない!」")
return False # 再入力
self._message(f"「{magic}!」", 0)
monster.defense(point)
return True
def _use_strong_magic(self,monster:Character, magic:Magic = Magic("フレイムバースト", 10, Power(145, 150))) -> bool:
"""強力魔法を使って攻撃する"""
return self._use_magic(monster, magic)
def _guard(self,monster) -> bool:
"""盾を使って防御する"""
self._is_guard = True
self._message(f"「盾で防ぐぞ!」")
return True
def _heal(self,monster:Character) -> bool:
"""生命力を回復する"""
if self._hp.is_full():
self._message(f"「今はいらないな」")
return False #再入力
if self._health_posion.use(self._hp):
self._message(f"「力がみなぎって来たぞ!」\nライフが回復した!")
return True
else:
self._message(f"「回復薬が無い!」")
return False #再入力
def _upper_heal(self,monster:Character) -> bool:
if self._hp.is_full():
self._message(f"「今は使わなくていいな」")
return False
if self._upper_posion.use(self._hp):
self._message(f"「うおおおぉっ!!」")
return True
else:
self._message(f"「まずい! 切れたか!」")
return False
#モンスターのクラス
class Monster(Character):
def __init__(self, name: str, hp: int, mp: int, ap: Power, sp: int, magic: Magic) -> None:
super().__init__(name, hp, mp, ap, Power(sp, sp))
self._magic: Magic = magic
def attack(self, player: Character) -> None:
if random.random() > 0.3:
point = self._weapon.use()
self._message(f"「喰らえ!」", 0)
else:
point = self._magic.use(self._mp)
if point == 0:
self._message("「MPが足りない!」")
return
self._message(f"「{self._magic}!」", 0)
if player.defense(point) == 0:
self._message("「やるな」")
else:
self._message("「馬鹿め!」")
#モンスターの一覧
MONSTERS = (
Monster("スカルヘッド",250,50,Power(50,60),20,
Magic("スカルヘッドバット",5,Power(50,60))),
Monster("ゴーストナイト",300,70,Power(75,85),20,
Magic("ダークスラッシュ",5,Power(100,105))),
Monster("デスマシーン",310,75,Power(80,85),25,
Magic("デスクラッシュ",5,Power(105,110))),
Monster("ギルドラゴン",320,80,Power(85,95),25,
Magic("バーンフレイム",5,Power(110,115))),
Monster("ダークウィザー",350,90,Power(105,115),25,
Magic("キルストーム",5,Power(120,125))),
Monster("ネビュラシーザー",500,100,Power(130,135),30,
Magic("ヘル・デストロイ",5,Power(170,175))),
)
WEAPONS = {
"m": Weapon("マスターブレード",120,130),
"b": Weapon("ビッグソード",100,110),
"s": Weapon("スマートダガー",80,90)
}
class Old_Man(Character):
def __init__(self, name: str)->None:
self._name=name
def go_fight(self)->None:
self._message(f"「{name}よ、戦うのじゃ」")
def help_me(self)->None:
self._message(f"「大変だ! ワシ達の村に魔物が襲ってきた!\n 済まない、どうか助けてくれないか?」")
def question(self) -> None:
print()
print("-------------------------")
print("|yキー:はい,nキー:いいえ|")
print("-------------------------")
print()
say=input('どうしますか?>>>')
if say == 'y':
self._message(f'「おお、やってくれるか。名前は何という?」')
elif say == 'n':
self._message(f"「そうか。仕方あるまい。\n なら今の状況を受け入れるか」")
game_over()
else:
self._message(f'「何をぐずぐずしている」')
def show_title() -> None:
"""タイトル表示"""
print("*************")
print("*DUEL BLAVER*")
print("*************")
def go() -> Old_Man:
old_man=Old_Man("長老ソル")
old_man.go_fight()
def tell() -> Old_Man:
old_man=Old_Man("長老ソル")
old_man.question()
def entry_player() -> Player:
global name
"""プレイヤー登場"""
tell()
name = input("名前を入力してください>>>")
print()
weapon = select_weapon()
print()
go()
return Player(name,weapon)
def select_weapon() -> Weapon:
print("----------------------------------------")
print("|m:マスターブレード(入門者向け) |")
print("|b:ビッグソード (プレイ済みの方向け)|")
print("|s:スマートダガー (熟練者向け) |")
print("----------------------------------------")
while(selection := input("武器を選択してください>>>")) not in WEAPONS:
pass
weapon = WEAPONS[selection]
return weapon
def opening() -> None:
show_title()
time.sleep(1)
print("一匹の魔物が王国を攻撃しようとしているぞ!")
print("果たして止める事は出来るのか!?")
time.sleep(2)
old_man=Old_Man("長老ソル")
old_man.help_me()
time.sleep(1)
def ending() -> None:
print("モンスターを倒した!\n")
print(f"化け物は{name}の手で倒された。")
print(f"この国にも平和が戻った。\nありがとう、{name}。")
time.sleep(1)
print("************")
print("*GAME CLEAR*")
print("************")
def appear_monster() -> Monster:
"""モンスター出現"""
monster = random.choice(MONSTERS)
print(f"{monster}出現!")
return monster
def game_over():
print("一匹の魔物の手によってこの国は滅び、\n次第にそこは魔物の巣窟と化し、魔界帝国が誕生した。\n")
time.sleep(2)
print("***********")
print("*GAME OVER*")
print("***********")
sys.exit()
def main() -> None:
"""主なゲームの流れ一式"""
print();opening()
player = entry_player()
print()
monster = appear_monster()
time.sleep(1)
while True:
print()
print(player.status());print(monster.status())
time.sleep(2)
print(f"\n***{player}のターン!***")
player.attack(monster)
if monster.is_dead():
ending()
return
print(f"\n***{monster}のターン!***")
monster.attack(player)
if player.is_dead():
print(f"{player}は敗れた・・・\n")
game_over()
return
if __name__ == "__main__":
main()
感想
まだ長老のセリフ云々は改良出来ると思うので、今後もいろいろ手を加えていきたいです。
可能であれば、モンスターと連戦できるように改良もしたいところ。